1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/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
readc(Cisdat * cis,uchar * x)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
xcistuple(int slotno,int tuple,int subtuple,void * v,int nv,int attr)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
pcmcistuple(int slotno,int tuple,int subtuple,void * v,int nv)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
pcmcisread(PCMslot * pp)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
getlong(Cisdat * cis,int size)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
tcfig(PCMslot * pp,Cisdat * cis,int)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
microvolt(Cisdat * cis)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
nanoamps(Cisdat * cis)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
power(Cisdat * cis)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
ttiming(Cisdat * cis,int scale)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
timing(Cisdat * cis,PCMconftab * ct)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
iospaces(Cisdat * cis,PCMconftab * ct)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
irq(Cisdat * cis,PCMconftab * ct)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
memspace(Cisdat * cis,int asize,int lsize,int host)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
tentry(PCMslot * pp,Cisdat * cis,int)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
tvers1(PCMslot * pp,Cisdat * cis,int)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
tlonglnkmfc(PCMslot * pp,Cisdat * cis,int)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