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