ref: 4d7c195804991b9c762f9a859679282c7014bbbb
dir: /sys/src/9/port/cis.c/
#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; } }