diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/port/cis.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/port/cis.c')
-rwxr-xr-x | sys/src/9/port/cis.c | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/sys/src/9/port/cis.c b/sys/src/9/port/cis.c new file mode 100755 index 000000000..368eb6d68 --- /dev/null +++ b/sys/src/9/port/cis.c @@ -0,0 +1,539 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" + +enum{ + Linktarget = 0x13, +}; + +/* + * read and crack the card information structure enough to set + * important parameters like power + */ +/* cis memory walking */ +typedef struct Cisdat { + uchar *cisbase; + int cispos; + int cisskip; + int cislen; +} Cisdat; + +static void tcfig(PCMslot*, Cisdat*, int); +static void tentry(PCMslot*, Cisdat*, int); +static void tvers1(PCMslot*, Cisdat*, int); +static void tlonglnkmfc(PCMslot*, Cisdat*, int); + +static int +readc(Cisdat *cis, uchar *x) +{ + if(cis->cispos >= cis->cislen) + return 0; + *x = cis->cisbase[cis->cisskip*cis->cispos]; + cis->cispos++; + return 1; +} + +static int +xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr) +{ + PCMmap *m; + Cisdat cis; + int i, l; + uchar *p; + uchar type, link, n, c; + int this, subtype; + + m = pcmmap(slotno, 0, 0, attr); + if(m == 0) + return -1; + + cis.cisbase = KADDR(m->isa); + cis.cispos = 0; + cis.cisskip = attr ? 2 : 1; + cis.cislen = m->len; + + /* loop through all the tuples */ + for(i = 0; i < 1000; i++){ + this = cis.cispos; + if(readc(&cis, &type) != 1) + break; + if(type == 0xFF) + break; + if(readc(&cis, &link) != 1) + break; + if(link == 0xFF) + break; + + n = link; + if(link > 1 && subtuple != -1){ + if(readc(&cis, &c) != 1) + break; + subtype = c; + n--; + }else + subtype = -1; + + if(type == tuple && subtype == subtuple){ + p = v; + for(l=0; l<nv && l<n; l++) + if(readc(&cis, p++) != 1) + break; + pcmunmap(slotno, m); + return nv; + } + cis.cispos = this + (2+link); + } + pcmunmap(slotno, m); + return -1; +} + +int +pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv) +{ + int n; + + /* try attribute space, then memory */ + if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0) + return n; + return xcistuple(slotno, tuple, subtuple, v, nv, 0); +} + +void +pcmcisread(PCMslot *pp) +{ + int this; + Cisdat cis; + PCMmap *m; + uchar type, link; + + memset(pp->ctab, 0, sizeof(pp->ctab)); + pp->ncfg = 0; + memset(pp->cfg, 0, sizeof(pp->cfg)); + pp->configed = 0; + pp->nctab = 0; + pp->verstr[0] = 0; + + /* + * Read all tuples in attribute space. + */ + m = pcmmap(pp->slotno, 0, 0, 1); + if(m == 0) + return; + + cis.cisbase = KADDR(m->isa); + cis.cispos = 0; + cis.cisskip = 2; + cis.cislen = m->len; + + /* loop through all the tuples */ + for(;;){ + this = cis.cispos; + if(readc(&cis, &type) != 1) + break; + if(type == 0xFF) + break; + if(readc(&cis, &link) != 1) + break; + + switch(type){ + default: + break; + case 6: + tlonglnkmfc(pp, &cis, type); + break; + case 0x15: + tvers1(pp, &cis, type); + break; + case 0x1A: + tcfig(pp, &cis, type); + break; + case 0x1B: + tentry(pp, &cis, type); + break; + } + + if(link == 0xFF) + break; + cis.cispos = this + (2+link); + } + pcmunmap(pp->slotno, m); +} + +static ulong +getlong(Cisdat *cis, int size) +{ + uchar c; + int i; + ulong x; + + x = 0; + for(i = 0; i < size; i++){ + if(readc(cis, &c) != 1) + break; + x |= c<<(i*8); + } + return x; +} + +static void +tcfig(PCMslot *pp, Cisdat *cis, int ) +{ + uchar size, rasize, rmsize; + uchar last; + + if(readc(cis, &size) != 1) + return; + rasize = (size&0x3) + 1; + rmsize = ((size>>2)&0xf) + 1; + if(readc(cis, &last) != 1) + return; + + if(pp->ncfg >= 8){ + print("tcfig: too many configuration registers\n"); + return; + } + + pp->cfg[pp->ncfg].caddr = getlong(cis, rasize); + pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize); + pp->ncfg++; +} + +static ulong vexp[8] = +{ + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 +}; +static ulong vmant[16] = +{ + 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90, +}; + +static ulong +microvolt(Cisdat *cis) +{ + uchar c; + ulong microvolts; + ulong exp; + + if(readc(cis, &c) != 1) + return 0; + exp = vexp[c&0x7]; + microvolts = vmant[(c>>3)&0xf]*exp; + while(c & 0x80){ + if(readc(cis, &c) != 1) + return 0; + switch(c){ + case 0x7d: + break; /* high impedence when sleeping */ + case 0x7e: + case 0x7f: + microvolts = 0; /* no connection */ + break; + default: + exp /= 10; + microvolts += exp*(c&0x7f); + } + } + return microvolts; +} + +static ulong +nanoamps(Cisdat *cis) +{ + uchar c; + ulong nanoamps; + + if(readc(cis, &c) != 1) + return 0; + nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf]; + while(c & 0x80){ + if(readc(cis, &c) != 1) + return 0; + if(c == 0x7d || c == 0x7e || c == 0x7f) + nanoamps = 0; + } + return nanoamps; +} + +/* + * only nominal voltage (feature 1) is important for config, + * other features must read card to stay in sync. + */ +static ulong +power(Cisdat *cis) +{ + uchar feature; + ulong mv; + + mv = 0; + if(readc(cis, &feature) != 1) + return 0; + if(feature & 1) + mv = microvolt(cis); + if(feature & 2) + microvolt(cis); + if(feature & 4) + microvolt(cis); + if(feature & 8) + nanoamps(cis); + if(feature & 0x10) + nanoamps(cis); + if(feature & 0x20) + nanoamps(cis); + if(feature & 0x40) + nanoamps(cis); + return mv/1000000; +} + +static ulong mantissa[16] = +{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; + +static ulong exponent[8] = +{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; + +static ulong +ttiming(Cisdat *cis, int scale) +{ + uchar unscaled; + ulong nanosecs; + + if(readc(cis, &unscaled) != 1) + return 0; + nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10; + nanosecs = nanosecs * vexp[scale]; + return nanosecs; +} + +static void +timing(Cisdat *cis, PCMconftab *ct) +{ + uchar c, i; + + if(readc(cis, &c) != 1) + return; + i = c&0x3; + if(i != 3) + ct->maxwait = ttiming(cis, i); /* max wait */ + i = (c>>2)&0x7; + if(i != 7) + ct->readywait = ttiming(cis, i); /* max ready/busy wait */ + i = (c>>5)&0x7; + if(i != 7) + ct->otherwait = ttiming(cis, i); /* reserved wait */ +} + +static void +iospaces(Cisdat *cis, PCMconftab *ct) +{ + uchar c; + int i, nio; + + ct->nio = 0; + if(readc(cis, &c) != 1) + return; + + ct->bit16 = ((c>>5)&3) >= 2; + if(!(c & 0x80)){ + ct->io[0].start = 0; + ct->io[0].len = 1<<(c&0x1f); + ct->nio = 1; + return; + } + + if(readc(cis, &c) != 1) + return; + + /* + * For each of the range descriptions read the + * start address and the length (value is length-1). + */ + nio = (c&0xf)+1; + for(i = 0; i < nio; i++){ + ct->io[i].start = getlong(cis, (c>>4)&0x3); + ct->io[i].len = getlong(cis, (c>>6)&0x3)+1; + } + ct->nio = nio; +} + +static void +irq(Cisdat *cis, PCMconftab *ct) +{ + uchar c; + + if(readc(cis, &c) != 1) + return; + ct->irqtype = c & 0xe0; + if(c & 0x10) + ct->irqs = getlong(cis, 2); + else + ct->irqs = 1<<(c&0xf); + ct->irqs &= 0xDEB8; /* levels available to card */ +} + +static void +memspace(Cisdat *cis, int asize, int lsize, int host) +{ + ulong haddress, address, len; + + len = getlong(cis, lsize)*256; + address = getlong(cis, asize)*256; + USED(len, address); + if(host){ + haddress = getlong(cis, asize)*256; + USED(haddress); + } +} + +static void +tentry(PCMslot *pp, Cisdat *cis, int ) +{ + uchar c, i, feature; + PCMconftab *ct; + + if(pp->nctab >= nelem(pp->ctab)) + return; + if(readc(cis, &c) != 1) + return; + ct = &pp->ctab[pp->nctab++]; + + /* copy from last default config */ + if(pp->def) + *ct = *pp->def; + + ct->index = c & 0x3f; + + /* is this the new default? */ + if(c & 0x40) + pp->def = ct; + + /* memory wait specified? */ + if(c & 0x80){ + if(readc(cis, &i) != 1) + return; + if(i&0x80) + ct->memwait = 1; + } + + if(readc(cis, &feature) != 1) + return; + switch(feature&0x3){ + case 1: + ct->vpp1 = ct->vpp2 = power(cis); + break; + case 2: + power(cis); + ct->vpp1 = ct->vpp2 = power(cis); + break; + case 3: + power(cis); + ct->vpp1 = power(cis); + ct->vpp2 = power(cis); + break; + default: + break; + } + if(feature&0x4) + timing(cis, ct); + if(feature&0x8) + iospaces(cis, ct); + if(feature&0x10) + irq(cis, ct); + switch((feature>>5)&0x3){ + case 1: + memspace(cis, 0, 2, 0); + break; + case 2: + memspace(cis, 2, 2, 0); + break; + case 3: + if(readc(cis, &c) != 1) + return; + for(i = 0; i <= (c&0x7); i++) + memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80); + break; + } + pp->configed++; +} + +static void +tvers1(PCMslot *pp, Cisdat *cis, int ) +{ + uchar c, major, minor, last; + int i; + + if(readc(cis, &major) != 1) + return; + if(readc(cis, &minor) != 1) + return; + last = 0; + for(i = 0; i < sizeof(pp->verstr)-1; i++){ + if(readc(cis, &c) != 1) + return; + if(c == 0) + c = ';'; + if(c == '\n') + c = ';'; + if(c == 0xff) + break; + if(c == ';' && last == ';') + continue; + pp->verstr[i] = c; + last = c; + } + pp->verstr[i] = 0; +} + +static void +tlonglnkmfc(PCMslot *pp, Cisdat *cis, int) +{ + int i, npos, opos; + uchar nfn, space, expect, type, this, link; + + readc(cis, &nfn); + for(i = 0; i < nfn; i++){ + readc(cis, &space); + npos = getlong(cis, 4); + opos = cis->cispos; + cis->cispos = npos; + expect = Linktarget; + + while(1){ + this = cis->cispos; + if(readc(cis, &type) != 1) + break; + if(type == 0xFF) + break; + if(readc(cis, &link) != 1) + break; + + if(expect && expect != type){ + print("tlonglnkmfc: expected %X found %X\n", + expect, type); + break; + } + expect = 0; + + switch(type){ + default: + break; + case 0x15: + tvers1(pp, cis, type); + break; + case 0x1A: + tcfig(pp, cis, type); + break; + case 0x1B: + tentry(pp, cis, type); + break; + } + + if(link == 0xFF) + break; + cis->cispos = this + (2+link); + } + cis->cispos = opos; + } +} |