ref: 052abe1cc8dd6403f4983b1b587f14d3eed1fe8c
dir: /sys/src/cmd/aux/pcmcia.c/
#include <u.h> #include <libc.h> enum { Linktarget = 0x13, Funcid = 0x21, End = 0xff, }; int fd; int pos; void tdevice(int, int); void tlonglnkmfc(int, int); void tfuncid(int, int); void tcfig(int, int); void tentry(int, int); void tvers1(int, int); void (*parse[256])(int, int) = { [1] tdevice, [6] tlonglnkmfc, [0x15] tvers1, [0x17] tdevice, [0x1A] tcfig, [0x1B] tentry, [Funcid] tfuncid, }; 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, int expect) { uchar link; uchar type; pos = next; if(readc(&type) != 1) return -1; if(type == 0xff) return -1; print("type %.2uX\n", type & 0xff); if(expect && expect != type){ print("expected %.2uX found %.2uX\n", expect, type); 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, 0); } 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; /* PRISM cards have a device tuple with id = size = 0. */ if(id == 0x00){ if(readc(&size) != 1) return; len--; continue; } speed = id & 0x7; if(speed == 0x7){ 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 tlonglnkmfc(int, int) { int i, opos; uchar nfn, space, expect; int addr; readc(&nfn); for(i = 0; i < nfn; i++){ readc(&space); addr = getlong(4); opos = pos; expect = Linktarget; while(addr > 0){ addr = tuple(addr, expect); expect = 0; } pos = opos; } } static char *funcids[] = { "MULTI", "MEMORY", "SERIAL", "PARALLEL", "FIXED", "VIDEO", "NETWORK", "AIMS", "SCSI", }; void tfuncid(int, int) { uchar func; readc(&func); print("Function %s\n", (func >= nelem(funcids))? "unknown function": funcids[func]); } 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<missing null>\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<<i) & cregs) print(" (%d)0x%lux", i, caddr + i*2); print("\n"); } char *intrname[16] = { [0] "memory", [1] "I/O", [4] "Custom 0", [5] "Custom 1", [6] "Custom 2", [7] "Custom 3", }; ulong vexp[8] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; ulong vmant[16] = { 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90, }; void volt(char *name) { uchar c; ulong microv; ulong exp; if(readc(&c) != 1) return; exp = vexp[c&0x7]; microv = vmant[(c>>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<<i)) print(", %d", i); print("\n"); } void memspace(int asize, int lsize, int host) { ulong haddress, address, len; len = getlong(lsize)*256; address = getlong(asize)*256; if(host){ haddress = getlong(asize)*256; print("\tmemory address range 0x%lux - 0x%lux hostaddr 0x%lux\n", address, address+len, haddress); } else print("\tmemory address range 0x%lux - 0x%lux\n", address, address+len); } void misc(void) { } void tentry(int ttype, int len) { uchar c, i, feature; char *tname; char buf[16]; USED(ttype, len); if(readc(&c) != 1) return; print("configuration %d%s\n", c&0x3f, (c&0x40)?" (default)":""); if(c & 0x80){ if(readc(&i) != 1) return; tname = intrname[i & 0xf]; if(tname == 0){ tname = buf; sprint(buf, "type %d", i & 0xf); } print("\t%s device, %s%s%s%s\n", tname, (i&0x10)?" Battery status active":"", (i&0x20)?" Write Protect active":"", (i&0x40)?" Ready/Busy active":"", (i&0x80)?" Memory Wait required":""); } if(readc(&feature) != 1) return; switch(feature&0x3){ case 1: power("Vcc"); break; case 2: power("Vcc"); power("Vpp"); break; case 3: power("Vcc"); power("Vpp1"); power("Vpp2"); break; } if(feature&0x4) timing(); if(feature&0x8) iospaces(); if(feature&0x10) irq(); switch((feature>>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(); }