xref: /inferno-os/os/boot/pc/cis.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "error.h"
7 #include "io.h"
8 
9 enum{
10 	Linktarget = 0x13,
11 };
12 
13 /*
14  *  read and crack the card information structure enough to set
15  *  important parameters like power
16  */
17 /* cis memory walking */
18 typedef struct Cisdat {
19 	uchar	*cisbase;
20 	int	cispos;
21 	int	cisskip;
22 	int	cislen;
23 } Cisdat;
24 
25 static void	tcfig(PCMslot*, Cisdat*, int);
26 static void	tentry(PCMslot*, Cisdat*, int);
27 static void	tvers1(PCMslot*, Cisdat*, int);
28 static void	tlonglnkmfc(PCMslot*, Cisdat*, int);
29 
30 static int
31 readc(Cisdat *cis, uchar *x)
32 {
33 	if(cis->cispos >= cis->cislen)
34 		return 0;
35 	*x = cis->cisbase[cis->cisskip*cis->cispos];
36 	cis->cispos++;
37 	return 1;
38 }
39 
40 static int
41 xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
42 {
43 	PCMmap *m;
44 	Cisdat cis;
45 	int i, l;
46 	uchar *p;
47 	uchar type, link, n, c;
48 	int this, subtype;
49 
50 	m = pcmmap(slotno, 0, 0, attr);
51 	if(m == 0)
52 		return -1;
53 
54 	cis.cisbase = KADDR(m->isa);
55 	cis.cispos = 0;
56 	cis.cisskip = attr ? 2 : 1;
57 	cis.cislen = m->len;
58 
59 	/* loop through all the tuples */
60 	for(i = 0; i < 1000; i++){
61 		this = cis.cispos;
62 		if(readc(&cis, &type) != 1)
63 			break;
64 		if(type == 0xFF)
65 			break;
66 		if(readc(&cis, &link) != 1)
67 			break;
68 		if(link == 0xFF)
69 			break;
70 
71 		n = link;
72 		if(link > 1 && subtuple != -1){
73 			if(readc(&cis, &c) != 1)
74 				break;
75 			subtype = c;
76 			n--;
77 		}else
78 			subtype = -1;
79 
80 		if(type == tuple && subtype == subtuple){
81 			p = v;
82 			for(l=0; l<nv && l<n; l++)
83 				if(readc(&cis, p++) != 1)
84 					break;
85 			pcmunmap(slotno, m);
86 			return nv;
87 		}
88 		cis.cispos = this + (2+link);
89 	}
90 	pcmunmap(slotno, m);
91 	return -1;
92 }
93 
94 int
95 pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
96 {
97 	int n;
98 
99 	/* try attribute space, then memory */
100 	if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
101 		return n;
102 	return xcistuple(slotno, tuple, subtuple, v, nv, 0);
103 }
104 
105 void
106 pcmcisread(PCMslot *pp)
107 {
108 	int this;
109 	Cisdat cis;
110 	PCMmap *m;
111 	uchar type, link;
112 
113 	memset(pp->ctab, 0, sizeof(pp->ctab));
114 	pp->ncfg = 0;
115 	memset(pp->cfg, 0, sizeof(pp->cfg));
116 	pp->configed = 0;
117 	pp->nctab = 0;
118 	pp->verstr[0] = 0;
119 
120 	/*
121 	 * Read all tuples in attribute space.
122 	 */
123 	m = pcmmap(pp->slotno, 0, 0, 1);
124 	if(m == 0)
125 		return;
126 
127 	cis.cisbase = KADDR(m->isa);
128 	cis.cispos = 0;
129 	cis.cisskip = 2;
130 	cis.cislen = m->len;
131 
132 	/* loop through all the tuples */
133 	for(;;){
134 		this = cis.cispos;
135 		if(readc(&cis, &type) != 1)
136 			break;
137 		if(type == 0xFF)
138 			break;
139 		if(readc(&cis, &link) != 1)
140 			break;
141 
142 		switch(type){
143 		default:
144 			break;
145 		case 6:
146 			tlonglnkmfc(pp, &cis, type);
147 			break;
148 		case 0x15:
149 			tvers1(pp, &cis, type);
150 			break;
151 		case 0x1A:
152 			tcfig(pp, &cis, type);
153 			break;
154 		case 0x1B:
155 			tentry(pp, &cis, type);
156 			break;
157 		}
158 
159 		if(link == 0xFF)
160 			break;
161 		cis.cispos = this + (2+link);
162 	}
163 	pcmunmap(pp->slotno, m);
164 }
165 
166 static ulong
167 getlong(Cisdat *cis, int size)
168 {
169 	uchar c;
170 	int i;
171 	ulong x;
172 
173 	x = 0;
174 	for(i = 0; i < size; i++){
175 		if(readc(cis, &c) != 1)
176 			break;
177 		x |= c<<(i*8);
178 	}
179 	return x;
180 }
181 
182 static void
183 tcfig(PCMslot *pp, Cisdat *cis, int )
184 {
185 	uchar size, rasize, rmsize;
186 	uchar last;
187 
188 	if(readc(cis, &size) != 1)
189 		return;
190 	rasize = (size&0x3) + 1;
191 	rmsize = ((size>>2)&0xf) + 1;
192 	if(readc(cis, &last) != 1)
193 		return;
194 
195 	if(pp->ncfg >= 8){
196 		print("tcfig: too many configuration registers\n");
197 		return;
198 	}
199 
200 	pp->cfg[pp->ncfg].caddr = getlong(cis, rasize);
201 	pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize);
202 	pp->ncfg++;
203 }
204 
205 static ulong vexp[8] =
206 {
207 	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
208 };
209 static ulong vmant[16] =
210 {
211 	10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
212 };
213 
214 static ulong
215 microvolt(Cisdat *cis)
216 {
217 	uchar c;
218 	ulong microvolts;
219 	ulong exp;
220 
221 	if(readc(cis, &c) != 1)
222 		return 0;
223 	exp = vexp[c&0x7];
224 	microvolts = vmant[(c>>3)&0xf]*exp;
225 	while(c & 0x80){
226 		if(readc(cis, &c) != 1)
227 			return 0;
228 		switch(c){
229 		case 0x7d:
230 			break;		/* high impedence when sleeping */
231 		case 0x7e:
232 		case 0x7f:
233 			microvolts = 0;	/* no connection */
234 			break;
235 		default:
236 			exp /= 10;
237 			microvolts += exp*(c&0x7f);
238 		}
239 	}
240 	return microvolts;
241 }
242 
243 static ulong
244 nanoamps(Cisdat *cis)
245 {
246 	uchar c;
247 	ulong nanoamps;
248 
249 	if(readc(cis, &c) != 1)
250 		return 0;
251 	nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
252 	while(c & 0x80){
253 		if(readc(cis, &c) != 1)
254 			return 0;
255 		if(c == 0x7d || c == 0x7e || c == 0x7f)
256 			nanoamps = 0;
257 	}
258 	return nanoamps;
259 }
260 
261 /*
262  * only nominal voltage (feature 1) is important for config,
263  * other features must read card to stay in sync.
264  */
265 static ulong
266 power(Cisdat *cis)
267 {
268 	uchar feature;
269 	ulong mv;
270 
271 	mv = 0;
272 	if(readc(cis, &feature) != 1)
273 		return 0;
274 	if(feature & 1)
275 		mv = microvolt(cis);
276 	if(feature & 2)
277 		microvolt(cis);
278 	if(feature & 4)
279 		microvolt(cis);
280 	if(feature & 8)
281 		nanoamps(cis);
282 	if(feature & 0x10)
283 		nanoamps(cis);
284 	if(feature & 0x20)
285 		nanoamps(cis);
286 	if(feature & 0x40)
287 		nanoamps(cis);
288 	return mv/1000000;
289 }
290 
291 static ulong mantissa[16] =
292 { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };
293 
294 static ulong exponent[8] =
295 { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };
296 
297 static ulong
298 ttiming(Cisdat *cis, int scale)
299 {
300 	uchar unscaled;
301 	ulong nanosecs;
302 
303 	if(readc(cis, &unscaled) != 1)
304 		return 0;
305 	nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
306 	nanosecs = nanosecs * vexp[scale];
307 	return nanosecs;
308 }
309 
310 static void
311 timing(Cisdat *cis, PCMconftab *ct)
312 {
313 	uchar c, i;
314 
315 	if(readc(cis, &c) != 1)
316 		return;
317 	i = c&0x3;
318 	if(i != 3)
319 		ct->maxwait = ttiming(cis, i);		/* max wait */
320 	i = (c>>2)&0x7;
321 	if(i != 7)
322 		ct->readywait = ttiming(cis, i);		/* max ready/busy wait */
323 	i = (c>>5)&0x7;
324 	if(i != 7)
325 		ct->otherwait = ttiming(cis, i);		/* reserved wait */
326 }
327 
328 static void
329 iospaces(Cisdat *cis, PCMconftab *ct)
330 {
331 	uchar c;
332 	int i, nio;
333 
334 	ct->nio = 0;
335 	if(readc(cis, &c) != 1)
336 		return;
337 
338 	ct->bit16 = ((c>>5)&3) >= 2;
339 	if(!(c & 0x80)){
340 		ct->io[0].start = 0;
341 		ct->io[0].len = 1<<(c&0x1f);
342 		ct->nio = 1;
343 		return;
344 	}
345 
346 	if(readc(cis, &c) != 1)
347 		return;
348 
349 	/*
350 	 * For each of the range descriptions read the
351 	 * start address and the length (value is length-1).
352 	 */
353 	nio = (c&0xf)+1;
354 	for(i = 0; i < nio; i++){
355 		ct->io[i].start = getlong(cis, (c>>4)&0x3);
356 		ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
357 	}
358 	ct->nio = nio;
359 }
360 
361 static void
362 irq(Cisdat *cis, PCMconftab *ct)
363 {
364 	uchar c;
365 
366 	if(readc(cis, &c) != 1)
367 		return;
368 	ct->irqtype = c & 0xe0;
369 	if(c & 0x10)
370 		ct->irqs = getlong(cis, 2);
371 	else
372 		ct->irqs = 1<<(c&0xf);
373 	ct->irqs &= 0xDEB8;		/* levels available to card */
374 }
375 
376 static void
377 memspace(Cisdat *cis, int asize, int lsize, int host)
378 {
379 	ulong haddress, address, len;
380 
381 	len = getlong(cis, lsize)*256;
382 	address = getlong(cis, asize)*256;
383 	USED(len, address);
384 	if(host){
385 		haddress = getlong(cis, asize)*256;
386 		USED(haddress);
387 	}
388 }
389 
390 static void
391 tentry(PCMslot *pp, Cisdat *cis, int )
392 {
393 	uchar c, i, feature;
394 	PCMconftab *ct;
395 
396 	if(pp->nctab >= nelem(pp->ctab))
397 		return;
398 	if(readc(cis, &c) != 1)
399 		return;
400 	ct = &pp->ctab[pp->nctab++];
401 
402 	/* copy from last default config */
403 	if(pp->def)
404 		*ct = *pp->def;
405 
406 	ct->index = c & 0x3f;
407 
408 	/* is this the new default? */
409 	if(c & 0x40)
410 		pp->def = ct;
411 
412 	/* memory wait specified? */
413 	if(c & 0x80){
414 		if(readc(cis, &i) != 1)
415 			return;
416 		if(i&0x80)
417 			ct->memwait = 1;
418 	}
419 
420 	if(readc(cis, &feature) != 1)
421 		return;
422 	switch(feature&0x3){
423 	case 1:
424 		ct->vpp1 = ct->vpp2 = power(cis);
425 		break;
426 	case 2:
427 		power(cis);
428 		ct->vpp1 = ct->vpp2 = power(cis);
429 		break;
430 	case 3:
431 		power(cis);
432 		ct->vpp1 = power(cis);
433 		ct->vpp2 = power(cis);
434 		break;
435 	default:
436 		break;
437 	}
438 	if(feature&0x4)
439 		timing(cis, ct);
440 	if(feature&0x8)
441 		iospaces(cis, ct);
442 	if(feature&0x10)
443 		irq(cis, ct);
444 	switch((feature>>5)&0x3){
445 	case 1:
446 		memspace(cis, 0, 2, 0);
447 		break;
448 	case 2:
449 		memspace(cis, 2, 2, 0);
450 		break;
451 	case 3:
452 		if(readc(cis, &c) != 1)
453 			return;
454 		for(i = 0; i <= (c&0x7); i++)
455 			memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
456 		break;
457 	}
458 	pp->configed++;
459 }
460 
461 static void
462 tvers1(PCMslot *pp, Cisdat *cis, int )
463 {
464 	uchar c, major, minor, last;
465 	int  i;
466 
467 	if(readc(cis, &major) != 1)
468 		return;
469 	if(readc(cis, &minor) != 1)
470 		return;
471 	last = 0;
472 	for(i = 0; i < sizeof(pp->verstr)-1; i++){
473 		if(readc(cis, &c) != 1)
474 			return;
475 		if(c == 0)
476 			c = ';';
477 		if(c == '\n')
478 			c = ';';
479 		if(c == 0xff)
480 			break;
481 		if(c == ';' && last == ';')
482 			continue;
483 		pp->verstr[i] = c;
484 		last = c;
485 	}
486 	pp->verstr[i] = 0;
487 }
488 
489 static void
490 tlonglnkmfc(PCMslot *pp, Cisdat *cis, int)
491 {
492 	int i, npos, opos;
493 	uchar nfn, space, expect, type, this, link;
494 
495 	readc(cis, &nfn);
496 	for(i = 0; i < nfn; i++){
497 		readc(cis, &space);
498 		npos        = getlong(cis, 4);
499 		opos        = cis->cispos;
500 		cis->cispos = npos;
501 		expect      = Linktarget;
502 
503 		while(1){
504 			this = cis->cispos;
505 			if(readc(cis, &type) != 1)
506 				break;
507 			if(type == 0xFF)
508 				break;
509 			if(readc(cis, &link) != 1)
510 				break;
511 
512 			if(expect && expect != type){
513 				print("tlonglnkmfc: expected %X found %X\n",
514 					expect, type);
515 				break;
516 			}
517 			expect = 0;
518 
519 			switch(type){
520 			default:
521 				break;
522 			case 0x15:
523 				tvers1(pp, cis, type);
524 				break;
525 			case 0x1A:
526 				tcfig(pp, cis, type);
527 				break;
528 			case 0x1B:
529 				tentry(pp, cis, type);
530 				break;
531 			}
532 
533 			if(link == 0xFF)
534 				break;
535 			cis->cispos = this + (2+link);
536 		}
537 		cis->cispos = opos;
538 	}
539 }
540