#include #include enum { End = 0xff, }; int fd; int pos; void tdevice(int, int); void tcfig(int, int); void tentry(int, int); void tvers1(int, int); void (*parse[256])(int, int) = { [1] tdevice, [0x15] tvers1, [0x17] tdevice, [0x1A] tcfig, [0x1B] tentry, }; int hex; void fatal(char *fmt, ...) { va_list arg; char buf[512]; va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); fprint(2, "pcmcia: %s\n", buf); exits(buf); } int readc(void *x) { int rv; seek(fd, 2*pos, 0); pos++; rv = read(fd, x, 1); if(hex) print("%2.2ux ", *(uchar*)x); return rv; } int tuple(int next) { uchar link; uchar type; pos = next; if(readc(&type) != 1) return -1; if(type == 0xff) return -1; if(readc(&link) != 1) return -1; if(parse[type]) (*parse[type])(type, link); if(link == 0xff) next = -1; else next = next+2+link; return next; } void main(int argc, char *argv[]) { char *file; int next; ARGBEGIN{ case 'x': hex = 1; }ARGEND; if(argc == 0) file = "#y/pcm0attr"; else file = argv[0]; fd = open(file, OREAD); if(fd < 0) fatal("opening %s: %r", file); for(next = 0; next >= 0;) next = tuple(next); } ulong speedtab[16] = { [1] 250, [2] 200, [3] 150, [4] 100, }; ulong mantissa[16] = { [1] 10, [2] 12, [3] 13, [4] 15, [5] 20, [6] 25, [7] 30, [8] 35, [9] 40, [0xa] 45, [0xb] 50, [0xc] 55, [0xd] 60, [0xe] 70, [0xf] 80, }; ulong exponent[8] = { [0] 1, [1] 10, [2] 100, [3] 1000, [4] 10000, [5] 100000, [6] 1000000, [7] 10000000, }; char *typetab[256] = { [1] "Masked ROM", [2] "PROM", [3] "EPROM", [4] "EEPROM", [5] "FLASH", [6] "SRAM", [7] "DRAM", [0xD] "IO+MEM", }; ulong getlong(int size) { uchar c; int i; ulong x; x = 0; for(i = 0; i < size; i++){ if(readc(&c) != 1) break; x |= c<<(i*8); } return x; } void tdevice(int ttype, int len) { uchar id; uchar type; uchar speed, aespeed; uchar size; ulong bytes, ns; char *tname, *ttname; while(len > 0){ if(readc(&id) != 1) return; len--; if(id == End) return; speed = id & 0x7; if(speed == 0xE){ if(readc(&speed) != 1) return; len--; if(speed & 0x80){ if(readc(&aespeed) != 1) return; ns = 0; } else ns = (mantissa[(speed>>3)&0xf]*exponent[speed&7])/10; } else ns = speedtab[speed]; type = id>>4; if(type == 0xE){ if(readc(&type) != 1) return; len--; } tname = typetab[type]; if(tname == 0) tname = "unknown"; if(readc(&size) != 1) return; len--; bytes = ((size>>3)+1) * 512 * (1<<(2*(size&0x7))); if(ttype == 1) ttname = "device"; else ttname = "attr device"; print("%s %ld bytes of %ldns %s\n", ttname, bytes, ns, tname); } } void tvers1(int ttype, int len) { uchar c, major, minor; int i; char string[512]; USED(ttype); if(readc(&major) != 1) return; len--; if(readc(&minor) != 1) return; len--; print("version %d.%d\n", major, minor); while(len > 0){ for(i = 0; len > 0 && i < sizeof(string); i++){ if(readc(&string[i]) != 1) return; len--; c = string[i]; if(c == 0) break; if(c == 0xff){ if(i != 0){ string[i] = 0; print("\t%s\n", string); } return; } } string[i] = 0; print("\t%s\n", string); } } void tcfig(int ttype, int len) { uchar size, rasize, rmsize; uchar last; ulong caddr; ulong cregs; int i; USED(ttype, len); if(readc(&size) != 1) return; rasize = (size&0x3) + 1; rmsize = ((size>>2)&0xf) + 1; if(readc(&last) != 1) return; caddr = getlong(rasize); cregs = getlong(rmsize); print("configuration registers at"); for(i = 0; i < 16; i++) if((1<>3)&0xf]*exp; while(c & 0x80){ if(readc(&c) != 1) return; switch(c){ case 0x7d: break; /* high impedence when sleeping */ case 0x7e: case 0x7f: microv = 0; /* no connection */ break; default: exp /= 10; microv += exp*(c&0x7f); } } print(" V%s %lduV", name, microv); } void amps(char *name) { uchar c; ulong amps; if(readc(&c) != 1) return; amps = vexp[c&0x7]*vmant[(c>>3)&0xf]; while(c & 0x80){ if(readc(&c) != 1) return; if(c == 0x7d || c == 0x7e || c == 0x7f) amps = 0; } if(amps >= 1000000) print(" I%s %ldmA", name, amps/100000); else if(amps >= 1000) print(" I%s %lduA", name, amps/100); else print(" I%s %ldnA", name, amps*10); } void power(char *name) { uchar feature; print("\t%s: ", name); if(readc(&feature) != 1) return; if(feature & 1) volt("nominal"); if(feature & 2) volt("min"); if(feature & 4) volt("max"); if(feature & 8) amps("static"); if(feature & 0x10) amps("avg"); if(feature & 0x20) amps("peak"); if(feature & 0x40) amps("powerdown"); print("\n"); } void ttiming(char *name, int scale) { uchar unscaled; ulong scaled; if(readc(&unscaled) != 1) return; scaled = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10; scaled = scaled * vexp[scale]; print("\t%s %ldns\n", name, scaled); } void timing(void) { uchar c, i; if(readc(&c) != 1) return; i = c&0x3; if(i != 3) ttiming("max wait", i); i = (c>>2)&0x7; if(i != 7) ttiming("max ready/busy wait", i); i = (c>>5)&0x7; if(i != 7) ttiming("reserved wait", i); } void range(int asize, int lsize) { ulong address, len; address = getlong(asize); len = getlong(lsize); print("\t\t%lux - %lux\n", address, address+len); } char *ioaccess[4] = { " no access", " 8bit access only", " 8bit or 16bit access", " selectable 8bit or 8&16bit access", }; int iospace(uchar c) { int i; print("\tIO space %d address lines%s\n", c&0x1f, ioaccess[(c>>5)&3]); if((c & 0x80) == 0) return -1; if(readc(&c) != 1) return -1; for(i = (c&0xf)+1; i; i--) range((c>>4)&0x3, (c>>6)&0x3); return 0; } void iospaces(void) { uchar c; if(readc(&c) != 1) return; iospace(c); } void irq(void) { uchar c; uchar irq1, irq2; ushort i, irqs; if(readc(&c) != 1) return; if(c & 0x10){ if(readc(&irq1) != 1) return; if(readc(&irq2) != 1) return; irqs = irq1|(irq2<<8); } else irqs = 1<<(c&0xf); print("\tinterrupts%s%s%s", (c&0x20)?":level":"", (c&0x40)?":pulse":"", (c&0x80)?":shared":""); for(i = 0; i < 16; i++) if(irqs & (1<>5)&0x3){ case 1: memspace(0, 2, 0); break; case 2: memspace(2, 2, 0); break; case 3: if(readc(&c) != 1) return; for(i = 0; i <= (c&0x7); i++) memspace((c>>5)&0x3, (c>>3)&0x3, c&0x80); break; } if(feature&0x80) misc(); }