1 #include <u.h>
2 #include <libc.h>
3
4 enum
5 {
6 Linktarget = 0x13,
7 Funcid = 0x21,
8 End = 0xff,
9 };
10
11 int fd;
12 int pos;
13
14 void tdevice(int, int);
15 void tlonglnkmfc(int, int);
16 void tfuncid(int, int);
17 void tcfig(int, int);
18 void tentry(int, int);
19 void tvers1(int, int);
20
21 void (*parse[256])(int, int) =
22 {
23 [1] tdevice,
24 [6] tlonglnkmfc,
25 [0x15] tvers1,
26 [0x17] tdevice,
27 [0x1A] tcfig,
28 [0x1B] tentry,
29 [Funcid] tfuncid,
30 };
31
32 int hex;
33
34 void
fatal(char * fmt,...)35 fatal(char *fmt, ...)
36 {
37 va_list arg;
38 char buf[512];
39
40 va_start(arg, fmt);
41 vseprint(buf, buf+sizeof(buf), fmt, arg);
42 va_end(arg);
43 fprint(2, "pcmcia: %s\n", buf);
44 exits(buf);
45 }
46
47 int
readc(void * x)48 readc(void *x)
49 {
50 int rv;
51
52 seek(fd, 2*pos, 0);
53 pos++;
54 rv = read(fd, x, 1);
55 if(hex)
56 print("%2.2ux ", *(uchar*)x);
57 return rv;
58 }
59
60 int
tuple(int next,int expect)61 tuple(int next, int expect)
62 {
63 uchar link;
64 uchar type;
65
66 pos = next;
67 if(readc(&type) != 1)
68 return -1;
69 if(type == 0xff)
70 return -1;
71 print("type %.2uX\n", type & 0xff);
72
73 if(expect && expect != type){
74 print("expected %.2uX found %.2uX\n",
75 expect, type);
76 return -1;
77 }
78
79 if(readc(&link) != 1)
80 return -1;
81 if(parse[type])
82 (*parse[type])(type, link);
83 if(link == 0xff)
84 next = -1;
85 else
86 next = next+2+link;
87 return next;
88 }
89
90 void
main(int argc,char * argv[])91 main(int argc, char *argv[])
92 {
93 char *file;
94 int next;
95
96 ARGBEGIN{
97 case 'x':
98 hex = 1;
99 }ARGEND;
100
101 if(argc == 0)
102 file = "#y/pcm0attr";
103 else
104 file = argv[0];
105
106 fd = open(file, OREAD);
107 if(fd < 0)
108 fatal("opening %s: %r", file);
109
110 for(next = 0; next >= 0;)
111 next = tuple(next, 0);
112 }
113
114 ulong speedtab[16] =
115 {
116 [1] 250,
117 [2] 200,
118 [3] 150,
119 [4] 100,
120 };
121
122 ulong mantissa[16] =
123 {
124 [1] 10,
125 [2] 12,
126 [3] 13,
127 [4] 15,
128 [5] 20,
129 [6] 25,
130 [7] 30,
131 [8] 35,
132 [9] 40,
133 [0xa] 45,
134 [0xb] 50,
135 [0xc] 55,
136 [0xd] 60,
137 [0xe] 70,
138 [0xf] 80,
139 };
140
141 ulong exponent[8] =
142 {
143 [0] 1,
144 [1] 10,
145 [2] 100,
146 [3] 1000,
147 [4] 10000,
148 [5] 100000,
149 [6] 1000000,
150 [7] 10000000,
151 };
152
153 char *typetab[256] =
154 {
155 [1] "Masked ROM",
156 [2] "PROM",
157 [3] "EPROM",
158 [4] "EEPROM",
159 [5] "FLASH",
160 [6] "SRAM",
161 [7] "DRAM",
162 [0xD] "IO+MEM",
163 };
164
165 ulong
getlong(int size)166 getlong(int size)
167 {
168 uchar c;
169 int i;
170 ulong x;
171
172 x = 0;
173 for(i = 0; i < size; i++){
174 if(readc(&c) != 1)
175 break;
176 x |= c<<(i*8);
177 }
178 return x;
179 }
180
181 void
tdevice(int ttype,int len)182 tdevice(int ttype, int len)
183 {
184 uchar id;
185 uchar type;
186 uchar speed, aespeed;
187 uchar size;
188 ulong bytes, ns;
189 char *tname, *ttname;
190
191 while(len > 0){
192 if(readc(&id) != 1)
193 return;
194 len--;
195 if(id == End)
196 return;
197
198 /* PRISM cards have a device tuple with id = size = 0. */
199 if(id == 0x00){
200 if(readc(&size) != 1)
201 return;
202 len--;
203 continue;
204 }
205
206 speed = id & 0x7;
207 if(speed == 0x7){
208 if(readc(&speed) != 1)
209 return;
210 len--;
211 if(speed & 0x80){
212 if(readc(&aespeed) != 1)
213 return;
214 ns = 0;
215 } else
216 ns = (mantissa[(speed>>3)&0xf]*exponent[speed&7])/10;
217 } else
218 ns = speedtab[speed];
219
220 type = id>>4;
221 if(type == 0xE){
222 if(readc(&type) != 1)
223 return;
224 len--;
225 }
226 tname = typetab[type];
227 if(tname == 0)
228 tname = "unknown";
229
230 if(readc(&size) != 1)
231 return;
232 len--;
233 bytes = ((size>>3)+1) * 512 * (1<<(2*(size&0x7)));
234
235 if(ttype == 1)
236 ttname = "device";
237 else
238 ttname = "attr device";
239 print("%s %ld bytes of %ldns %s\n", ttname, bytes, ns, tname);
240 }
241 }
242
243 void
tlonglnkmfc(int,int)244 tlonglnkmfc(int, int)
245 {
246 int i, opos;
247 uchar nfn, space, expect;
248 int addr;
249
250 readc(&nfn);
251 for(i = 0; i < nfn; i++){
252 readc(&space);
253 addr = getlong(4);
254 opos = pos;
255 expect = Linktarget;
256 while(addr > 0){
257 addr = tuple(addr, expect);
258 expect = 0;
259 }
260 pos = opos;
261 }
262 }
263
264 static char *funcids[] = {
265 "MULTI",
266 "MEMORY",
267 "SERIAL",
268 "PARALLEL",
269 "FIXED",
270 "VIDEO",
271 "NETWORK",
272 "AIMS",
273 "SCSI",
274 };
275
276 void
tfuncid(int,int)277 tfuncid(int, int)
278 {
279 uchar func;
280
281 readc(&func);
282 print("Function %s\n",
283 (func >= nelem(funcids))? "unknown function": funcids[func]);
284 }
285
286 void
tvers1(int ttype,int len)287 tvers1(int ttype, int len)
288 {
289 uchar c, major, minor;
290 int i;
291 char string[512];
292
293 USED(ttype);
294 if(readc(&major) != 1)
295 return;
296 len--;
297 if(readc(&minor) != 1)
298 return;
299 len--;
300 print("version %d.%d\n", major, minor);
301 while(len > 0){
302 for(i = 0; len > 0 && i < sizeof(string); i++){
303 if(readc(&string[i]) != 1)
304 return;
305 len--;
306 c = string[i];
307 if(c == 0)
308 break;
309 if(c == 0xff){
310 if(i != 0){
311 string[i] = 0;
312 print("\t%s<missing null>\n", string);
313 }
314 return;
315 }
316 }
317 string[i] = 0;
318 print("\t%s\n", string);
319 }
320 }
321
322 void
tcfig(int ttype,int len)323 tcfig(int ttype, int len)
324 {
325 uchar size, rasize, rmsize;
326 uchar last;
327 ulong caddr;
328 ulong cregs;
329 int i;
330
331 USED(ttype, len);
332 if(readc(&size) != 1)
333 return;
334 rasize = (size&0x3) + 1;
335 rmsize = ((size>>2)&0xf) + 1;
336 if(readc(&last) != 1)
337 return;
338 caddr = getlong(rasize);
339 cregs = getlong(rmsize);
340
341 print("configuration registers at");
342 for(i = 0; i < 16; i++)
343 if((1<<i) & cregs)
344 print(" (%d)0x%lux", i, caddr + i*2);
345 print("\n");
346 }
347
348 char *intrname[16] =
349 {
350 [0] "memory",
351 [1] "I/O",
352 [4] "Custom 0",
353 [5] "Custom 1",
354 [6] "Custom 2",
355 [7] "Custom 3",
356 };
357
358 ulong vexp[8] =
359 {
360 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
361 };
362 ulong vmant[16] =
363 {
364 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
365 };
366
367 void
volt(char * name)368 volt(char *name)
369 {
370 uchar c;
371 ulong microv;
372 ulong exp;
373
374 if(readc(&c) != 1)
375 return;
376 exp = vexp[c&0x7];
377 microv = vmant[(c>>3)&0xf]*exp;
378 while(c & 0x80){
379 if(readc(&c) != 1)
380 return;
381 switch(c){
382 case 0x7d:
383 break; /* high impedence when sleeping */
384 case 0x7e:
385 case 0x7f:
386 microv = 0; /* no connection */
387 break;
388 default:
389 exp /= 10;
390 microv += exp*(c&0x7f);
391 }
392 }
393 print(" V%s %lduV", name, microv);
394 }
395
396 void
amps(char * name)397 amps(char *name)
398 {
399 uchar c;
400 ulong amps;
401
402 if(readc(&c) != 1)
403 return;
404 amps = vexp[c&0x7]*vmant[(c>>3)&0xf];
405 while(c & 0x80){
406 if(readc(&c) != 1)
407 return;
408 if(c == 0x7d || c == 0x7e || c == 0x7f)
409 amps = 0;
410 }
411 if(amps >= 1000000)
412 print(" I%s %ldmA", name, amps/100000);
413 else if(amps >= 1000)
414 print(" I%s %lduA", name, amps/100);
415 else
416 print(" I%s %ldnA", name, amps*10);
417 }
418
419 void
power(char * name)420 power(char *name)
421 {
422 uchar feature;
423
424 print("\t%s: ", name);
425 if(readc(&feature) != 1)
426 return;
427 if(feature & 1)
428 volt("nominal");
429 if(feature & 2)
430 volt("min");
431 if(feature & 4)
432 volt("max");
433 if(feature & 8)
434 amps("static");
435 if(feature & 0x10)
436 amps("avg");
437 if(feature & 0x20)
438 amps("peak");
439 if(feature & 0x40)
440 amps("powerdown");
441 print("\n");
442 }
443
444 void
ttiming(char * name,int scale)445 ttiming(char *name, int scale)
446 {
447 uchar unscaled;
448 ulong scaled;
449
450 if(readc(&unscaled) != 1)
451 return;
452 scaled = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
453 scaled = scaled * vexp[scale];
454 print("\t%s %ldns\n", name, scaled);
455 }
456
457 void
timing(void)458 timing(void)
459 {
460 uchar c, i;
461
462 if(readc(&c) != 1)
463 return;
464 i = c&0x3;
465 if(i != 3)
466 ttiming("max wait", i);
467 i = (c>>2)&0x7;
468 if(i != 7)
469 ttiming("max ready/busy wait", i);
470 i = (c>>5)&0x7;
471 if(i != 7)
472 ttiming("reserved wait", i);
473 }
474
475 void
range(int asize,int lsize)476 range(int asize, int lsize)
477 {
478 ulong address, len;
479
480 address = getlong(asize);
481 len = getlong(lsize);
482 print("\t\t%lux - %lux\n", address, address+len);
483 }
484
485 char *ioaccess[4] =
486 {
487 " no access",
488 " 8bit access only",
489 " 8bit or 16bit access",
490 " selectable 8bit or 8&16bit access",
491 };
492
493 int
iospace(uchar c)494 iospace(uchar c)
495 {
496 int i;
497
498 print("\tIO space %d address lines%s\n", c&0x1f, ioaccess[(c>>5)&3]);
499 if((c & 0x80) == 0)
500 return -1;
501
502 if(readc(&c) != 1)
503 return -1;
504
505 for(i = (c&0xf)+1; i; i--)
506 range((c>>4)&0x3, (c>>6)&0x3);
507 return 0;
508 }
509
510 void
iospaces(void)511 iospaces(void)
512 {
513 uchar c;
514
515 if(readc(&c) != 1)
516 return;
517 iospace(c);
518 }
519
520 void
irq(void)521 irq(void)
522 {
523 uchar c;
524 uchar irq1, irq2;
525 ushort i, irqs;
526
527 if(readc(&c) != 1)
528 return;
529 if(c & 0x10){
530 if(readc(&irq1) != 1)
531 return;
532 if(readc(&irq2) != 1)
533 return;
534 irqs = irq1|(irq2<<8);
535 } else
536 irqs = 1<<(c&0xf);
537 print("\tinterrupts%s%s%s", (c&0x20)?":level":"", (c&0x40)?":pulse":"",
538 (c&0x80)?":shared":"");
539 for(i = 0; i < 16; i++)
540 if(irqs & (1<<i))
541 print(", %d", i);
542 print("\n");
543 }
544
545 void
memspace(int asize,int lsize,int host)546 memspace(int asize, int lsize, int host)
547 {
548 ulong haddress, address, len;
549
550 len = getlong(lsize)*256;
551 address = getlong(asize)*256;
552 if(host){
553 haddress = getlong(asize)*256;
554 print("\tmemory address range 0x%lux - 0x%lux hostaddr 0x%lux\n",
555 address, address+len, haddress);
556 } else
557 print("\tmemory address range 0x%lux - 0x%lux\n", address, address+len);
558 }
559
560 void
misc(void)561 misc(void)
562 {
563 }
564
565 void
tentry(int ttype,int len)566 tentry(int ttype, int len)
567 {
568 uchar c, i, feature;
569 char *tname;
570 char buf[16];
571
572 USED(ttype, len);
573 if(readc(&c) != 1)
574 return;
575 print("configuration %d%s\n", c&0x3f, (c&0x40)?" (default)":"");
576 if(c & 0x80){
577 if(readc(&i) != 1)
578 return;
579 tname = intrname[i & 0xf];
580 if(tname == 0){
581 tname = buf;
582 sprint(buf, "type %d", i & 0xf);
583 }
584 print("\t%s device, %s%s%s%s\n", tname,
585 (i&0x10)?" Battery status active":"",
586 (i&0x20)?" Write Protect active":"",
587 (i&0x40)?" Ready/Busy active":"",
588 (i&0x80)?" Memory Wait required":"");
589 }
590 if(readc(&feature) != 1)
591 return;
592 switch(feature&0x3){
593 case 1:
594 power("Vcc");
595 break;
596 case 2:
597 power("Vcc");
598 power("Vpp");
599 break;
600 case 3:
601 power("Vcc");
602 power("Vpp1");
603 power("Vpp2");
604 break;
605 }
606 if(feature&0x4)
607 timing();
608 if(feature&0x8)
609 iospaces();
610 if(feature&0x10)
611 irq();
612 switch((feature>>5)&0x3){
613 case 1:
614 memspace(0, 2, 0);
615 break;
616 case 2:
617 memspace(2, 2, 0);
618 break;
619 case 3:
620 if(readc(&c) != 1)
621 return;
622 for(i = 0; i <= (c&0x7); i++)
623 memspace((c>>5)&0x3, (c>>3)&0x3, c&0x80);
624 break;
625 }
626 if(feature&0x80)
627 misc();
628 }
629