plan9fox/sys/src/cmd/aux/pcmcia.c
2011-03-30 19:35:09 +03:00

629 lines
9 KiB
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();
}