diff options
Diffstat (limited to 'os/boot/pc/devi82365.c')
| -rw-r--r-- | os/boot/pc/devi82365.c | 629 |
1 files changed, 83 insertions, 546 deletions
diff --git a/os/boot/pc/devi82365.c b/os/boot/pc/devi82365.c index a4e09d2d..456d911d 100644 --- a/os/boot/pc/devi82365.c +++ b/os/boot/pc/devi82365.c @@ -7,15 +7,7 @@ #include "io.h" /* - * Support for up to 4 Slot card slots. Generalizing above that is hard - * since addressing is not obvious. - presotto - * - * WARNING: This has never been tried with more than one card slot. - */ - -/* - * Intel 82365SL PCIC controller for the PCMCIA or - * Cirrus Logic PD6710/PD6720 which is mostly register compatible + * Intel 82365SL PCIC controller and compatibles. */ enum { @@ -84,10 +76,6 @@ enum Moffhi= 0x5, /* Card memory offset address high byte */ Fregactive= (1<<6), /* attribute memory */ - Mbits= 13, /* msb of Mchunk */ - Mchunk= 1<<Mbits, /* logical mapping granularity */ - Nmap= 4, /* max number of maps to use */ - /* * configuration registers - they start at an offset in attribute * memory found in the CIS. @@ -95,8 +83,12 @@ enum Rconfig= 0, Creset= (1<<7), /* reset device */ Clevel= (1<<6), /* level sensitive interrupt line */ - - Maxctab= 8, /* maximum configuration table entries */ + Cirq= (1<<2), /* IRQ enable */ + Cdecode= (1<<1), /* address decode */ + Cfunc= (1<<0), /* function enable */ + Riobase0= 5, + Riobase1= 6, + Riosize= 9, }; static int pcmcia_pcmspecial(char *, ISAConf *); @@ -105,9 +97,7 @@ static void pcmcia_pcmspecialclose(int); #define MAP(x,o) (Rmap + (x)*0x8 + o) typedef struct I82365 I82365; -typedef struct Slot Slot; -typedef struct Conftab Conftab; -typedef struct Cisdat Cisdat; + /* a controller */ enum { @@ -127,96 +117,29 @@ struct I82365 }; static I82365 *controller[4]; static int ncontroller; - -/* configuration table entry */ -struct Conftab -{ - int index; - ushort irqs; /* legal irqs */ - uchar irqtype; - uchar bit16; /* true for 16 bit access */ - struct { - ulong start; - ulong len; - } io[16]; - int nio; - uchar vpp1; - uchar vpp2; - uchar memwait; - ulong maxwait; - ulong readywait; - ulong otherwait; -}; - -/* cis memory walking */ -struct Cisdat -{ - uchar *cisbase; - int cispos; - int cisskip; - int cislen; -}; - -/* a card slot */ -struct Slot -{ - Lock; - int ref; - - I82365 *cp; /* controller for this slot */ - long memlen; /* memory length */ - uchar base; /* index register base */ - uchar slotno; /* slot number */ - - /* status */ - uchar special; /* in use for a special device */ - uchar already; /* already inited */ - uchar occupied; - uchar battery; - uchar wrprot; - uchar powered; - uchar configed; - uchar enabled; - uchar busy; - - /* cis info */ - char verstr[512]; /* version string */ - uchar cpresent; /* config registers present */ - ulong caddr; /* relative address of config registers */ - int nctab; /* number of config table entries */ - Conftab ctab[Maxctab]; - Conftab *def; /* default conftab */ - - /* for walking through cis */ - Cisdat; - - /* memory maps */ - Lock mlock; /* lock down the maps */ - int time; - PCMmap mmap[Nmap]; /* maps, last is always for the kernel */ -}; -static Slot *slot; -static Slot *lastslot; +static PCMslot *slot; +static PCMslot *lastslot; static nslot; -static void cisread(Slot*); static void i82365intr(Ureg*, void*); static void i82365reset(void); static int pcmio(int, ISAConf*); -static long pcmread(int, int, void*, long, vlong); -static long pcmwrite(int, int, void*, long, vlong); -static void i82365dump(Slot*); +static void i82365dump(PCMslot*); void devi82365link(void) { static int already; + char *p; if(already) return; already = 1; + if((p=getconf("pcmcia0")) && strncmp(p, "disabled", 8)==0) + return; + if (_pcmspecial) return; @@ -228,23 +151,23 @@ devi82365link(void) * reading and writing card registers */ static uchar -rdreg(Slot *pp, int index) +rdreg(PCMslot *pp, int index) { - outb(pp->cp->xreg, pp->base + index); - return inb(pp->cp->dreg); + outb(((I82365*)pp->cp)->xreg, pp->base + index); + return inb(((I82365*)pp->cp)->dreg); } static void -wrreg(Slot *pp, int index, uchar val) +wrreg(PCMslot *pp, int index, uchar val) { - outb(pp->cp->xreg, pp->base + index); - outb(pp->cp->dreg, val); + outb(((I82365*)pp->cp)->xreg, pp->base + index); + outb(((I82365*)pp->cp)->dreg, val); } /* * get info about card */ static void -slotinfo(Slot *pp) +slotinfo(PCMslot *pp) { uchar isr; @@ -254,6 +177,7 @@ slotinfo(Slot *pp) pp->battery = (isr & 3) == 3; pp->wrprot = isr & (1<<4); pp->busy = isr & (1<<5); + //pp->msec = TK2MS(MACHP(0)->ticks); } static int @@ -273,7 +197,7 @@ vcode(int volt) * enable the slot card */ static void -slotena(Slot *pp) +slotena(PCMslot *pp) { if(pp->enabled) return; @@ -289,7 +213,7 @@ slotena(Slot *pp) /* get configuration */ slotinfo(pp); if(pp->occupied){ - cisread(pp); + pcmcisread(pp); pp->enabled = 1; } else wrreg(pp, Rpc, Fautopower); @@ -299,7 +223,7 @@ slotena(Slot *pp) * disable the slot card */ static void -slotdis(Slot *pp) +slotdis(PCMslot *pp) { wrreg(pp, Rpc, 0); /* turn off card power */ wrreg(pp, Rwe, 0); /* no windows */ @@ -313,7 +237,7 @@ static void i82365intr(Ureg *, void *) { uchar csc, was; - Slot *pp; + PCMslot *pp; if(slot == 0) return; @@ -342,7 +266,7 @@ enum PCMmap* pcmmap(int slotno, ulong offset, int len, int attr) { - Slot *pp; + PCMslot *pp; uchar we, bit; PCMmap *m, *nm; int i; @@ -362,7 +286,7 @@ pcmmap(int slotno, ulong offset, int len, int attr) we = rdreg(pp, Rwe); bit = 1; nm = 0; - for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){ + for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){ if((we & bit)) if(m->attr == attr) if(offset >= m->ca && e <= m->cea){ @@ -422,7 +346,7 @@ pcmmap(int slotno, ulong offset, int len, int attr) void pcmunmap(int slotno, PCMmap* m) { - Slot *pp; + PCMslot *pp; pp = slot + slotno; lock(&pp->mlock); @@ -431,7 +355,7 @@ pcmunmap(int slotno, PCMmap* m) } static void -increfp(Slot *pp) +increfp(PCMslot *pp) { lock(pp); if(pp->ref++ == 0) @@ -440,7 +364,7 @@ increfp(Slot *pp) } static void -decrefp(Slot *pp) +decrefp(PCMslot *pp) { lock(pp); if(pp->ref-- == 1) @@ -454,7 +378,7 @@ decrefp(Slot *pp) static int pcmcia_pcmspecial(char *idstr, ISAConf *isa) { - Slot *pp; + PCMslot *pp; extern char *strstr(char*, char*); int enabled; @@ -472,9 +396,11 @@ pcmcia_pcmspecial(char *idstr, ISAConf *isa) } if(pp->occupied) { - if(strstr(pp->verstr, idstr)) { - if (!enabled) + if(strstr(pp->verstr, idstr)){ + if (!enabled){ + enabled = 1; increfp(pp); + } if(isa == 0 || pcmio(pp->slotno, isa) == 0){ pp->special = 1; return pp->slotno; @@ -491,7 +417,7 @@ pcmcia_pcmspecial(char *idstr, ISAConf *isa) static void pcmcia_pcmspecialclose(int slotno) { - Slot *pp; + PCMslot *pp; print("pcmspecialclose called\n"); if(slotno >= nslot) @@ -520,7 +446,9 @@ i82365probe(int x, int d, int dev) outb(x, Rid + (dev<<7)); id = inb(d); if((id & 0xf0) != 0x80) - return 0; /* not this family */ + return 0; /* not a memory & I/O card */ + if((id & 0x0f) == 0x00) + return 0; /* no revision number, not possible */ cp = xalloc(sizeof(I82365)); cp->xreg = x; @@ -556,18 +484,22 @@ i82365probe(int x, int d, int dev) break; } + /* if it's not a Cirrus, it could be a Vadem... */ if(cp->type == Ti82365){ + /* unlock the Vadem extended regs */ outb(x, 0x0E + (dev<<7)); outb(x, 0x37 + (dev<<7)); + + /* make the id register show the Vadem id */ outb(x, 0x3A + (dev<<7)); c = inb(d); outb(d, c|0xC0); outb(x, Rid + (dev<<7)); c = inb(d); - if(c != id && !(c & 0x08)) - print("#y%d: id %uX changed to %uX\n", ncontroller, id, c); if(c & 0x08) cp->type = Tvg46x; + + /* go back to Intel compatible id */ outb(x, 0x3A + (dev<<7)); c = inb(d); outb(d, c & ~0xC0); @@ -592,7 +524,7 @@ i82365probe(int x, int d, int dev) } static void -i82365dump(Slot *pp) +i82365dump(PCMslot *pp) { int i; @@ -615,7 +547,7 @@ i82365reset(void) static int already; int i, j; I82365 *cp; - Slot *pp; + PCMslot *pp; if(already) return; @@ -630,9 +562,8 @@ i82365reset(void) for(i = 0; i < ncontroller; i++) nslot += controller[i]->nslot; - slot = xalloc(nslot * sizeof(Slot)); + slot = xalloc(nslot * sizeof(PCMslot)); - /* if the card is there turn on 5V power to keep its battery alive */ lastslot = slot; for(i = 0; i < ncontroller; i++){ cp = controller[i]; @@ -644,6 +575,8 @@ i82365reset(void) pp->memlen = 64*MB; pp->base = (cp->dev<<7) | (j<<6); pp->cp = cp; + pp->msec = ~0; + pp->verstr[0] = 0; slotdis(pp); /* interrupt on status change */ @@ -657,15 +590,15 @@ i82365reset(void) } /* - * configure the Slot for IO. We assume very heavily that we can read + * configure the PCMslot for IO. We assume very heavily that we can read * configuration info from the CIS. If not, we won't set up correctly. */ static int pcmio(int slotno, ISAConf *isa) { uchar we, x, *p; - Slot *pp; - Conftab *ct, *et, *t; + PCMslot *pp; + PCMconftab *ct, *et, *t; PCMmap *m; int i, index, irq; char *cp; @@ -692,6 +625,7 @@ pcmio(int slotno, ISAConf *isa) return -1; ct = &pp->ctab[index]; } + if(ct == 0){ /* assume default is right */ @@ -749,7 +683,10 @@ pcmio(int slotno, ISAConf *isa) x |= x<<4; wrreg(pp, Rio, x); - /* enable io port map 0 */ + /* + * enable io port map 0 + * the 'top' register value includes the last valid address + */ if(isa->port == 0) isa->port = ct->io[0].start; we = rdreg(pp, Rwe); @@ -759,7 +696,7 @@ pcmio(int slotno, ISAConf *isa) wrreg(pp, Riotop0lo, i); wrreg(pp, Riotop0hi, i>>8); we |= 1<<6; - if(ct->nio == 2 && ct->io[1].start){ + if(ct->nio >= 2 && ct->io[1].start){ wrreg(pp, Riobtm1lo, ct->io[1].start); wrreg(pp, Riobtm1hi, ct->io[1].start>>8); i = ct->io[1].start+ct->io[1].len-1; @@ -770,436 +707,36 @@ pcmio(int slotno, ISAConf *isa) wrreg(pp, Rwe, we); /* only touch Rconfig if it is present */ - if(pp->cpresent & (1<<Rconfig)){ + m = pcmmap(slotno, pp->cfg[0].caddr + Rconfig, 0x20, 1); + p = KADDR(m->isa + pp->cfg[0].caddr - m->ca); + if(pp->cfg[0].cpresent & (1<<Rconfig)){ /* Reset adapter */ - m = pcmmap(slotno, pp->caddr + Rconfig, 1, 1); - p = KADDR(m->isa + pp->caddr + Rconfig - m->ca); - /* set configuration and interrupt type */ + /* set configuration and interrupt type. + * if level is possible on the card, use it. + */ x = ct->index; - if((ct->irqtype & 0x20) && ((ct->irqtype & 0x40)==0 || isa->irq>7)) + if(ct->irqtype & 0x20) x |= Clevel; - *p = x; - delay(5); - - pcmunmap(slotno, m); - } - return 0; -} - -/* - * read and crack the card information structure enough to set - * important parameters like power - */ -static void tcfig(Slot*, Cisdat*, int); -static void tentry(Slot*, Cisdat*, int); -static void tvers1(Slot*, Cisdat*, int); - -struct { - int n; - void (*parse)(Slot*, Cisdat*, int); -} cistab[] = { - 0x15, tvers1, - 0x1A, tcfig, - 0x1B, tentry, -}; - -static int -readc(Cisdat *pp, uchar *x) -{ - if(pp->cispos >= pp->cislen) - return 0; - *x = pp->cisbase[pp->cisskip*pp->cispos]; - pp->cispos++; - return 1; -} - -static int -xcistuple(int slotno, int tuple, void *v, int nv, int attr) -{ - PCMmap *m; - Cisdat cis; - int i, l; - uchar *p; - uchar type, link; - int this; - - m = pcmmap(slotno, 0, 0, attr); - if(m == 0) { -if(debug) print("could not map\n"); - return -1; - } - - cis.cisbase = KADDR(m->isa); - cis.cispos = 0; - cis.cisskip = attr ? 2 : 1; - cis.cislen = Mchunk; - -if(debug) print("cis %d %d #%lux srch %x...", attr, cis.cisskip, cis.cisbase, tuple); - /* loop through all the tuples */ - for(i = 0; i < 1000; i++){ - this = cis.cispos; - if(readc(&cis, &type) != 1) - break; -if(debug) print("%2ux...", type); - if(type == 0xFF) - break; - if(readc(&cis, &link) != 1) - break; - if(link == 0xFF) - break; - if(type == tuple) { - p = v; - for(l=0; l<nv && l<link; l++) - if(readc(&cis, p++) != 1) - break; - pcmunmap(slotno, m); -if(debug) print("pcm find %2.2ux %d %d\n", type, link, l); - return l; - } - cis.cispos = this + (2+link); - } - pcmunmap(slotno, m); - return -1; -} - -int -pcmcistuple(int slotno, int tuple, void *v, int nv) -{ - int n; - - /* try attribute space, then memory */ - if((n = xcistuple(slotno, tuple, v, nv, 1)) >= 0) - return n; - return xcistuple(slotno, tuple, v, nv, 0); -} - -static void -cisread(Slot *pp) -{ - uchar v[256]; - int i, nv; - Cisdat cis; - - memset(pp->ctab, 0, sizeof(pp->ctab)); - pp->caddr = 0; - pp->cpresent = 0; - pp->configed = 0; - pp->nctab = 0; - - for(i = 0; i < nelem(cistab); i++) { - if((nv = pcmcistuple(pp->slotno, cistab[i].n, v, sizeof(v))) >= 0) { - cis.cisbase = v; - cis.cispos = 0; - cis.cisskip = 1; - cis.cislen = nv; - - (*cistab[i].parse)(pp, &cis, cistab[i].n); - } - } -} - -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(Slot *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; - pp->caddr = getlong(cis, rasize); - pp->cpresent = getlong(cis, rmsize); -} - -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 is important for config - */ -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, Conftab *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, Conftab *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; - - 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, Conftab *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(Slot *pp, Cisdat *cis, int ) -{ - uchar c, i, feature; - Conftab *ct; - - if(pp->nctab >= Maxctab) - 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; + /* enable the device, enable address decode and + * irq enable. + */ + x |= Cfunc|Cdecode|Cirq; - /* memory wait specified? */ - if(c & 0x80){ - if(readc(cis, &i) != 1) - return; - if(i&0x80) - ct->memwait = 1; + p[0] = x; + //delay(5); + microdelay(40); } - 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; + if(pp->cfg[0].cpresent & (1<<Riobase0)){ + /* set up the iobase 0 */ + p[Riobase0 << 1] = isa->port; + p[Riobase1 << 1] = isa->port >> 8; } - pp->configed++; -} -static void -tvers1(Slot *pp, Cisdat *cis, int ) -{ - uchar c, major, minor; - int i; - - if(readc(cis, &major) != 1) - return; - if(readc(cis, &minor) != 1) - return; - for(i = 0; i < sizeof(pp->verstr)-1; i++){ - if(readc(cis, &c) != 1) - return; - if(c == 0) - c = '\n'; - if(c == 0xff) - break; - pp->verstr[i] = c; - } - pp->verstr[i] = 0; + if(pp->cfg[0].cpresent & (1<<Riosize)) + p[Riosize << 1] = ct->io[0].len; + pcmunmap(slotno, m); + return 0; } |
