ref: d0ab3a0dd8f6355b3603d0fb04043a9ae867639b
dir: /appl/cmd/auxi/pcmcia.b/
implement Pcmcia;
#
# Copyright © 1995-2001 Lucent Technologies Inc. All rights reserved.
# Revisions Copyright © 2001-2003 Vita Nuova Holdings Limited. All rights reserved.
#
include "sys.m";
sys: Sys;
print, fprint: import sys;
include "draw.m";
Pcmcia: module
{
init: fn(nil: ref Draw->Context, nil: list of string);
};
End: con 16rFF;
fd: ref Sys->FD;
stderr: ref Sys->FD;
pos := 0;
hex := 0;
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
stderr = sys->fildes(2);
if(args != nil)
args = tl args;
if(args != nil && hd args == "-x"){
hex = 1;
args = tl args;
}
file := "#y/pcm0attr";
if(args != nil)
file = hd args;
fd = sys->open(file, Sys->OREAD);
if(fd == nil)
fatal(sys->sprint("can't open %s: %r", file));
for(next := 0; next >= 0;)
next = dtuple(next);
}
fatal(s: string)
{
fprint(stderr, "pcmcia: %s\n", s);
raise "fail:error";
}
readc(): int
{
x := array[1] of byte;
sys->seek(fd, big(2*pos), 0);
pos++;
rv := sys->read(fd, x, 1);
if(rv != 1){
if(rv < 0)
sys->print("readc err: %r\n");
return -1;
}
v := int x[0];
if(hex)
print("%2.2ux ", v);
return v;
}
dtuple(next: int): int
{
pos = next;
if((ttype := readc()) < 0)
return -1;
if(ttype == End)
return -1;
if((link := readc()) < 0)
return -1;
case ttype {
* => print("unknown tuple type #%2.2ux\n", ttype);
16r01 => tdevice(ttype, link);
16r15 => tvers1(ttype, link);
16r17 => tdevice(ttype, link);
16r1A => tcfig(ttype, link);
16r1B => tentry(ttype, link);
}
if(link == End)
next = -1;
else
next = next+2+link;
return next;
}
speedtab := array[16] of {
0 => 0,
1 => 250,
2 => 200,
3 => 150,
4 => 100,
};
mantissa := array[16] of {
1 => 10,
2 => 12,
3 => 13,
4 => 15,
5 => 20,
6 => 25,
7 => 30,
8 => 35,
9 => 40,
10=> 45,
11=> 50,
12=> 55,
13=> 60,
14=> 70,
15=> 80,
};
exponent := array[] of {
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
};
typetab := array [256] of {
1=> "Masked ROM",
2=> "PROM",
3=> "EPROM",
4=> "EEPROM",
5=> "FLASH",
6=> "SRAM",
7=> "DRAM",
16rD=> "IO+MEM",
* => "Unknown",
};
getlong(size: int): int
{
x := 0;
for(i := 0; i < size; i++){
if((c := readc()) < 0)
break;
x |= c<<(i*8);
}
return x;
}
tdevice(dtype: int, tlen: int)
{
while(tlen > 0){
if((id := readc()) < 0)
return;
tlen--;
if(id == End)
return;
speed := id & 16r7;
ns := 0;
if(speed == 16r7){
if((speed = readc()) < 0)
return;
tlen--;
if(speed & 16r80){
if((aespeed := readc()) < 0)
return;
ns = 0;
} else
ns = (mantissa[(speed>>3)&16rF]*exponent[speed&7])/10;
} else
ns = speedtab[speed];
ttype := id>>4;
if(ttype == 16rE){
if((ttype = readc()) < 0)
return;
tlen--;
}
tname := typetab[ttype];
if(tname == nil)
tname = "unknown";
if((size := readc()) < 0)
return;
tlen--;
bytes := ((size>>3)+1) * 512 * (1<<(2*(size&16r7)));
ttname := "attr device";
if(dtype == 1)
ttname = "device";
print("%s %d bytes of %dns %s\n", ttname, bytes, ns, tname);
}
}
tvers1(nil: int, tlen: int)
{
if((major := readc()) < 0)
return;
tlen--;
if((minor := readc()) < 0)
return;
tlen--;
print("version %d.%d\n", major, minor);
while(tlen > 0){
s := "";
while(tlen > 0){
if((c := readc()) < 0)
return;
tlen--;
if(c == 0)
break;
if(c == End){
if(s != "")
print("\t%s<missing null>\n", s);
return;
}
s[len s] = c;
}
print("\t%s\n", s);
}
}
tcfig(nil: int, nil: int)
{
if((size := readc()) < 0)
return;
rasize := (size&16r3) + 1;
rmsize := ((size>>2)&16rf) + 1;
if((last := readc()) < 0)
return;
caddr := getlong(rasize);
cregs := getlong(rmsize);
print("configuration registers at");
for(i := 0; i < 16; i++)
if((1<<i) & cregs)
print(" (%d) #%ux", i, caddr + i*2);
print("\n");
}
intrname := array[16] of {
0 => "memory",
1 => "I/O",
4 => "Custom 0",
5 => "Custom 1",
6 => "Custom 2",
7 => "Custom 3",
* => "unknown"
};
vexp := array[8] of {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
};
vmant := array[16] of {
10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
};
volt(name: string)
{
if((c := readc()) < 0)
return;
exp := vexp[c&16r7];
microv := vmant[(c>>3)&16rf]*exp;
while(c & 16r80){
if((c = readc()) < 0)
return;
case c {
16r7d =>
break; # high impedence when sleeping
16r7e or 16r7f =>
microv = 0; # no connection
* =>
exp /= 10;
microv += exp*(c&16r7f);
}
}
print(" V%s %duV", name, microv);
}
amps(name: string)
{
if((c := readc()) < 0)
return;
amps := vexp[c&16r7]*vmant[(c>>3)&16rf];
while(c & 16r80){
if((c = readc()) < 0)
return;
if(c == 16r7d || c == 16r7e || c == 16r7f)
amps = 0;
}
if(amps >= 1000000)
print(" I%s %dmA", name, amps/100000);
else if(amps >= 1000)
print(" I%s %duA", name, amps/100);
else
print(" I%s %dnA", name, amps*10);
}
power(name: string)
{
print("\t%s: ", name);
if((feature := readc()) < 0)
return;
if(feature & 1)
volt("nominal");
if(feature & 2)
volt("min");
if(feature & 4)
volt("max");
if(feature & 8)
amps("static");
if(feature & 16r10)
amps("avg");
if(feature & 16r20)
amps("peak");
if(feature & 16r40)
amps("powerdown");
print("\n");
}
ttiming(name: string, scale: int)
{
if((unscaled := readc()) < 0)
return;
scaled := (mantissa[(unscaled>>3)&16rf]*exponent[unscaled&7])/10;
scaled = scaled * vexp[scale];
print("\t%s %dns\n", name, scaled);
}
timing()
{
if((c := readc()) < 0)
return;
i := c&16r3;
if(i != 3)
ttiming("max wait", i);
i = (c>>2)&16r7;
if(i != 7)
ttiming("max ready/busy wait", i);
i = (c>>5)&16r7;
if(i != 7)
ttiming("reserved wait", i);
}
range(asize: int, lsize: int)
{
address := getlong(asize);
alen := getlong(lsize);
print("\t\t%ux - %ux\n", address, address+alen);
}
ioaccess := array[] of {
0 => " no access",
1 => " 8bit access only",
2 => " 8bit or 16bit access",
3 => " selectable 8bit or 8&16bit access",
};
iospace(c: int): int
{
print("\tIO space %d address lines%s\n", c&16r1f, ioaccess[(c>>5)&3]);
if((c & 16r80) == 0)
return -1;
if((c = readc()) < 0)
return -1;
for(i := (c&16rf)+1; i; i--)
range((c>>4)&16r3, (c>>6)&16r3);
return 0;
}
iospaces()
{
if((c := readc()) < 0)
return;
iospace(c);
}
irq()
{
if((c := readc()) < 0)
return;
irqs: int;
if(c & 16r10){
if((irq1 := readc()) < 0)
return;
if((irq2 := readc()) < 0)
return;
irqs = irq1|(irq2<<8);
} else
irqs = 1<<(c&16rf);
level := "";
if(c & 16r20)
level = " level";
pulse := "";
if(c & 16r40)
pulse = " pulse";
shared := "";
if(c & 16r80)
shared = " shared";
print("\tinterrupts%s%s%s", level, pulse, shared);
for(i := 0; i < 16; i++)
if(irqs & (1<<i))
print(", %d", i);
print("\n");
}
memspace(asize: int, lsize: int, host: int)
{
alen := getlong(lsize)*256;
address := getlong(asize)*256;
if(host){
haddress := getlong(asize)*256;
print("\tmemory address range #%ux - #%ux hostaddr #%ux\n",
address, address+alen, haddress);
} else
print("\tmemory address range #%ux - #%ux\n", address, address+alen);
}
misc()
{
}
tentry(nil: int, nil: int)
{
if((c := readc()) < 0)
return;
def := "";
if(c & 16r40)
def = " (default)";
print("configuration %d%s\n", c&16r3f, def);
if(c & 16r80){
if((i := readc()) < 0)
return;
tname := intrname[i & 16rf];
if(tname == "")
tname = sys->sprint("type %d", i & 16rf);
attrib := "";
if(i & 16r10)
attrib += " Battery status active";
if(i & 16r20)
attrib += " Write Protect active";
if(i & 16r40)
attrib += " Ready/Busy active";
if(i & 16r80)
attrib += " Memory Wait required";
print("\t%s device, %s\n", tname, attrib);
}
if((feature := readc()) < 0)
return;
case feature&16r3 {
1 =>
power("Vcc");
2 =>
power("Vcc");
power("Vpp");
3 =>
power("Vcc");
power("Vpp1");
power("Vpp2");
}
if(feature&16r4)
timing();
if(feature&16r8)
iospaces();
if(feature&16r10)
irq();
case (feature>>5)&16r3 {
1 =>
memspace(0, 2, 0);
2 =>
memspace(2, 2, 0);
3 =>
if((c = readc()) < 0)
return;
for(i := 0; i <= (c&16r7); i++)
memspace((c>>5)&16r3, (c>>3)&16r3, c&16r80);
break;
}
if(feature&16r80)
misc();
}