xref: /plan9/sys/src/cmd/aux/vga/db.c (revision b0dcc5a8c7c5c46439edae0dfc71a5fd27bb2a41)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ndb.h>
5 
6 #include "pci.h"
7 #include "vga.h"
8 
9 static Ndb*
dbopen(char * dbname)10 dbopen(char* dbname)
11 {
12 	Ndb *db;
13 
14 	if((db = ndbopen(dbname)) == 0)
15 		error("dbopen: %s: %r\n", dbname);
16 	return db;
17 }
18 
19 static void
addattr(Attr ** app,Ndbtuple * t)20 addattr(Attr** app, Ndbtuple* t)
21 {
22 	Attr *attr, *l;
23 
24 	attr = alloc(sizeof(Attr));
25 	attr->attr = alloc(strlen(t->attr)+1);
26 	strcpy(attr->attr, t->attr);
27 	attr->val = alloc(strlen(t->val)+1);
28 	strcpy(attr->val, t->val);
29 
30 	for(l = *app; l; l = l->next)
31 		app = &l->next;
32 	*app = attr;
33 }
34 
35 char*
dbattr(Attr * ap,char * attr)36 dbattr(Attr* ap, char* attr)
37 {
38 	while(ap){
39 		if(strcmp(ap->attr, attr) == 0)
40 			return ap->val;
41 		ap = ap->next;
42 	}
43 
44 	return 0;
45 }
46 
47 static Ctlr*
addctlr(Vga * vga,char * val)48 addctlr(Vga* vga, char* val)
49 {
50 	Ctlr **ctlr;
51 	char name[Namelen+1], *p;
52 	int i;
53 
54 	/*
55 	 * A controller name may have an extension on the end
56 	 * following a '-' which can be used as a speed grade or
57 	 * subtype.  Do the match without the extension.
58 	 * The linked copy of the controller struct gets the
59 	 * full name with extension.
60 	 */
61 	strncpy(name, val, Namelen);
62 	name[Namelen] = 0;
63 	if(p = strchr(name, '-'))
64 		*p = 0;
65 
66 	for(i = 0; ctlrs[i]; i++){
67 		if(strcmp(ctlrs[i]->name, name))
68 			continue;
69 		for(ctlr = &vga->link; *ctlr; ctlr = &((*ctlr)->link))
70 			;
71 		*ctlr = alloc(sizeof(Ctlr));
72 		**ctlr = *ctlrs[i];
73 		strncpy((*ctlr)->name, val, Namelen);
74 		return *ctlr;
75 	}
76 
77 	fprint(2, "dbctlr: unknown controller \"%s\" ctlr\n", val);
78 	return 0;
79 }
80 
81 int
dbbios(Vga * vga,Ndbtuple * tuple)82 dbbios(Vga *vga, Ndbtuple *tuple)
83 {
84 	char *bios, *p, *string;
85 	int len;
86 	long offset, offset1;
87 	Ndbtuple *t;
88 
89 	for(t = tuple->entry; t; t = t->entry){
90 		if((offset = strtol(t->attr, 0, 0)) == 0)
91 			continue;
92 
93 		string = t->val;
94 		len = strlen(string);
95 
96 		if(p = strchr(t->attr, '-')) {
97 			if((offset1 = strtol(p+1, 0, 0)) < offset+len)
98 				continue;
99 		} else
100 			offset1 = offset+len;
101 
102 		if(vga->offset) {
103 			if(offset > vga->offset || vga->offset+len > offset1)
104 				continue;
105 			offset = vga->offset;
106 			offset1 = offset+len;
107 		}
108 
109 		for(; offset+len<=offset1; offset++) {
110 			if(vga->bios)
111 				bios = vga->bios;
112 			else
113 				bios = readbios(len, offset);
114 			if(strncmp(bios, string, len) == 0){
115 				if(vga->bios == 0){
116 					vga->bios = alloc(len+1);
117 					strncpy(vga->bios, bios, len);
118 				}
119 				addattr(&vga->attr, t);
120 				return 1;
121 			}
122 		}
123 	}
124 	return 0;
125 }
126 
127 int
dbpci(Vga * vga,Ndbtuple * tuple)128 dbpci(Vga *vga, Ndbtuple *tuple)
129 {
130 	int did, vid;
131 	Ndbtuple *t, *td;
132 	Pcidev *pci;
133 
134 	for(t = tuple->entry; t; t = t->entry){
135 		if(strcmp(t->attr, "vid") != 0 || (vid=atoi(t->val)) == 0)
136 			continue;
137 		for(td = t->line; td != t; td = td->line){
138 			if(strcmp(td->attr, "did") != 0)
139 				continue;
140 			if(strcmp(td->val, "*") == 0)
141 				did = 0;
142 			else if((did=atoi(td->val)) == 0)
143 				continue;
144 			for(pci=nil; pci=pcimatch(pci, vid, did);)
145 				if((pci->ccru>>8) == 3)
146 					break;
147 			if(pci == nil)
148 				continue;
149 			vga->pci = pci;
150 			addattr(&vga->attr, t);
151 			addattr(&vga->attr, td);
152 			return 1;
153 		}
154 	}
155 	return 0;
156 }
157 
158 static void
save(Vga * vga,Ndbtuple * tuple)159 save(Vga *vga, Ndbtuple *tuple)
160 {
161 	Ctlr *c;
162 	Ndbtuple *t;
163 
164 	for(t = tuple->entry; t; t = t->entry){
165 		if(strcmp(t->attr, "ctlr") == 0){
166 			vga->ctlr = addctlr(vga, t->val);
167 			if(strcmp(t->val, "vesa") == 0)
168 				vga->vesa = vga->ctlr;
169 		}else if(strcmp(t->attr, "ramdac") == 0)
170 			vga->ramdac = addctlr(vga, t->val);
171 		else if(strcmp(t->attr, "clock") == 0)
172 			vga->clock = addctlr(vga, t->val);
173 		else if(strcmp(t->attr, "hwgc") == 0)
174 			vga->hwgc = addctlr(vga, t->val);
175 		else if(strcmp(t->attr, "link") == 0){
176 			c = addctlr(vga, t->val);
177 			if(strcmp(t->val, "vesa") == 0)
178 				vga->vesa = c;
179 		}else if(strcmp(t->attr, "linear") == 0)
180 			vga->linear = strtol(t->val, 0, 0);
181 		else if(strcmp(t->attr, "membw") == 0)
182 			vga->membw = strtol(t->val, 0, 0)*1000000;
183 		else if(strcmp(t->attr, "vid")==0 || strcmp(t->attr, "did")==0)
184 			{}
185 		else if(strtol(t->attr, 0, 0) == 0)
186 			addattr(&vga->attr, t);
187 	}
188 }
189 
190 int
dbctlr(char * name,Vga * vga)191 dbctlr(char* name, Vga* vga)
192 {
193 	Ndb *db;
194 	Ndbs s;
195 	Ndbtuple *tuple;
196 	Ndbtuple *pcituple;
197 
198 	db = dbopen(name);
199 
200 	/*
201 	 * Search vgadb for a matching BIOS string or PCI id.
202 	 * If we have both, the BIOS string wins.
203 	 */
204 	pcituple = nil;
205 	for(tuple = ndbsearch(db, &s, "ctlr", ""); tuple; tuple = ndbsnext(&s, "ctlr", "")){
206 		if(!pcituple && dbpci(vga, tuple))
207 			pcituple = tuple;
208 		if(dbbios(vga, tuple)){
209 			save(vga, tuple);
210 			if(pcituple && pcituple != tuple)
211 				ndbfree(pcituple);
212 			ndbfree(tuple);
213 			ndbclose(db);
214 			return 1;
215 		}
216 		if(tuple != pcituple)
217 			ndbfree(tuple);
218 	}
219 
220 	if(pcituple){
221 		save(vga, pcituple);
222 		ndbfree(pcituple);
223 	}
224 	ndbclose(db);
225 	if(pcituple)
226 		return 1;
227 	return 0;
228 }
229 
230 static int
dbmonitor(Ndb * db,Mode * mode,char * type,char * size)231 dbmonitor(Ndb* db, Mode* mode, char* type, char* size)
232 {
233 	Ndbs s;
234 	Ndbtuple *t, *tuple;
235 	char *p, attr[Namelen+1], val[Namelen+1], buf[2*Namelen+1];
236 	int clock, x, i;
237 
238 	/*
239 	 * Clock rate hack.
240 	 * If the size is 'XxYxZ@NMHz' then override the database entry's
241 	 * 'clock=' with 'N*1000000'.
242 	 */
243 	clock = 0;
244 	strcpy(buf, size);
245 	if(p = strchr(buf, '@')){
246 		*p++ = 0;
247 		if((clock = strtol(p, &p, 0)) && strcmp(p, "MHz") == 0)
248 			clock *= 1000000;
249 	}
250 
251 	memset(mode, 0, sizeof(Mode));
252 
253 	if((p = strchr(buf, 'x')) && (p = strchr(p+1, 'x'))){
254 		*p++ = 0;
255 		mode->z = atoi(p);
256 	}
257 
258 	strcpy(attr, type);
259 	strcpy(val, buf);
260 
261 	if(p = ndbgetvalue(db, &s, attr, "", "videobw", nil)){
262 		mode->videobw = atol(p)*1000000UL;
263 		free(p);
264 	}
265 
266 	if(mode->x == 0 && ((mode->x = strtol(val, &p, 0)) == 0 || *p++ != 'x'))
267 		return 0;
268 	if(mode->y == 0 && (mode->y = strtol(p, &p, 0)) == 0)
269 		return 0;
270 	i = 0;
271 buggery:
272 	if((tuple = ndbsearch(db, &s, attr, val)) == 0)
273 		return 0;
274 
275 	for(t = tuple->entry; t; t = t->entry){
276 		if(strcmp(t->attr, "clock") == 0 && mode->frequency == 0)
277 			mode->frequency = strtod(t->val, 0)*1000000;
278 		else if(strcmp(t->attr, "defaultclock") == 0 && mode->deffrequency == 0)
279 			mode->deffrequency = strtod(t->val, 0)*1000000;
280 		else if(strcmp(t->attr, "ht") == 0 && mode->ht == 0)
281 			mode->ht = strtol(t->val, 0, 0);
282 		else if(strcmp(t->attr, "shb") == 0 && mode->shb == 0)
283 			mode->shb = strtol(t->val, 0, 0);
284 		else if(strcmp(t->attr, "ehb") == 0 && mode->ehb == 0)
285 			mode->ehb = strtol(t->val, 0, 0);
286 		else if(strcmp(t->attr, "shs") == 0 && mode->shs == 0)
287 			mode->shs = strtol(t->val, 0, 0);
288 		else if(strcmp(t->attr, "ehs") == 0 && mode->ehs == 0)
289 			mode->ehs = strtol(t->val, 0, 0);
290 		else if(strcmp(t->attr, "vt") == 0 && mode->vt == 0)
291 			mode->vt = strtol(t->val, 0, 0);
292 		else if(strcmp(t->attr, "vrs") == 0 && mode->vrs == 0)
293 			mode->vrs = strtol(t->val, 0, 0);
294 		else if(strcmp(t->attr, "vre") == 0 && mode->vre == 0)
295 			mode->vre = strtol(t->val, 0, 0);
296 		else if(strcmp(t->attr, "hsync") == 0)
297 			mode->hsync = *t->val;
298 		else if(strcmp(t->attr, "vsync") == 0)
299 			mode->vsync = *t->val;
300 		else if(strcmp(t->attr, "interlace") == 0)
301 			mode->interlace = *t->val;
302 		else if(strcmp(t->attr, "include") == 0 /*&& strcmp(t->val, val) != 0*/){
303 			strcpy(attr, t->attr);
304 			strcpy(val, t->val);
305 			ndbfree(tuple);
306 			if(i++ > 5)
307 				error("dbmonitor: implausible include depth at %s=%s\n", attr, val);
308 			goto buggery;
309 		}
310 		else if(strcmp(t->attr, "include") == 0){
311 			print("warning: bailed out of infinite loop in attr %s=%s\n", attr, val);
312 		}
313 		else
314 			addattr(&mode->attr, t);
315 	}
316 	ndbfree(tuple);
317 
318 	if((x = strtol(size, &p, 0)) == 0 || x != mode->x || *p++ != 'x')
319 		return 0;
320 	if((x = strtol(p, &p, 0)) == 0 || x != mode->y || *p++ != 'x')
321 		return 0;
322 	if((x = strtol(p, &p, 0)) == 0 || x != mode->z)
323 		return 0;
324 
325 	if(clock)
326 		mode->frequency = clock;
327 
328 	return 1;
329 }
330 
331 Mode*
dbmode(char * name,char * type,char * size)332 dbmode(char* name, char* type, char* size)
333 {
334 	Ndb *db;
335 	Ndbs s;
336 	Ndbtuple *t, *tuple;
337 	Mode *mode;
338 	char attr[Namelen+1];
339 	ulong videobw;
340 
341 	db = dbopen(name);
342 	mode = alloc(sizeof(Mode));
343 	strcpy(attr, type);
344 
345 	videobw = 0;
346 	/*
347 	 * Look for the attr=size entry.
348 	 */
349 	if(dbmonitor(db, mode, attr, size)){
350 		strcpy(mode->type, type);
351 		strcpy(mode->size, size);
352 		ndbclose(db);
353 		return mode;
354 	}
355 
356 	if(mode->videobw && videobw == 0)	/* we at least found that; save it away */
357 		videobw = mode->videobw;
358 
359 	/*
360 	 * Not found. Look for an attr="" entry and then
361 	 * for an alias=attr within.
362 	 */
363 buggery:
364 	for(tuple = ndbsearch(db, &s, attr, ""); tuple; tuple = ndbsnext(&s, attr, "")){
365 		for(t = tuple->entry; t; t = t->entry){
366 			if(strcmp(t->attr, "alias"))
367 				continue;
368 			strcpy(attr, t->val);
369 			if(dbmonitor(db, mode, attr, size)){
370 				strcpy(mode->type, type);
371 				strcpy(mode->size, size);
372 				ndbfree(tuple);
373 				ndbclose(db);
374 				if(videobw)
375 					mode->videobw = videobw;
376 				return mode;
377 			}
378 
379 			/*
380 			 * Found an alias but no match for size,
381 			 * restart looking for attr="" with the
382 			 * new attr.
383 			 */
384 			ndbfree(tuple);
385 			goto buggery;
386 		}
387 		ndbfree(tuple);
388 	}
389 
390 	free(mode);
391 	ndbclose(db);
392 	return 0;
393 }
394 
395 void
dbdumpmode(Mode * mode)396 dbdumpmode(Mode* mode)
397 {
398 	Attr *attr;
399 
400 	Bprint(&stdout, "dbdumpmode\n");
401 
402 	Bprint(&stdout, "type=%s, size=%s\n", mode->type, mode->size);
403 	Bprint(&stdout, "frequency=%d\n", mode->frequency);
404 	Bprint(&stdout, "x=%d (0x%X), y=%d (0x%X), z=%d (0x%X)\n",
405 		mode->x, mode->x, mode->y,  mode->y, mode->z, mode->z);
406 	Bprint(&stdout, "ht=%d (0x%X), shb=%d (0x%X), ehb=%d (0x%X)\n",
407 		mode->ht, mode->ht, mode->shb, mode->shb, mode->ehb, mode->ehb);
408 	Bprint(&stdout, "shs=%d (0x%X), ehs=%d (0x%X)\n",
409 		mode->shs, mode->shs, mode->ehs, mode->ehs);
410 	Bprint(&stdout, "vt=%d (0x%X), vrs=%d (0x%X), vre=%d (0x%X)\n",
411 		mode->vt, mode->vt, mode->vrs, mode->vrs, mode->vre, mode->vre);
412 	Bprint(&stdout, "hsync=%d, vsync=%d, interlace=%d\n",
413 		mode->hsync, mode->vsync, mode->interlace);
414 
415 	for(attr = mode->attr; attr; attr = attr->next)
416 		Bprint(&stdout, "mode->attr: %s=%s\n", attr->attr, attr->val);
417 }
418