#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h"#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 */enum{ /* * registers indices */ Rid= 0x0, /* identification and revision */ Ris= 0x1, /* interface status */ Rpc= 0x2, /* power control */ Foutena= (1<<7), /* output enable */ Fautopower= (1<<5), /* automatic power switching */ Fcardena= (1<<4), /* PC card enable */ Rigc= 0x3, /* interrupt and general control */ Fiocard= (1<<5), /* I/O card (vs memory) */ Fnotreset= (1<<6), /* reset if not set */ FSMIena= (1<<4), /* enable change interrupt on SMI */ Rcsc= 0x4, /* card status change */ Rcscic= 0x5, /* card status change interrupt config */ Fchangeena= (1<<3), /* card changed */ Fbwarnena= (1<<1), /* card battery warning */ Fbdeadena= (1<<0), /* card battery dead */ Rwe= 0x6, /* address window enable */ Fmem16= (1<<5), /* use A23-A12 to decode address */ Rio= 0x7, /* I/O control */ Fwidth16= (1<<0), /* 16 bit data width */ Fiocs16= (1<<1), /* IOCS16 determines data width */ Fzerows= (1<<2), /* zero wait state */ Ftiming= (1<<3), /* timing register to use */ Riobtm0lo= 0x8, /* I/O address 0 start low byte */ Riobtm0hi= 0x9, /* I/O address 0 start high byte */ Riotop0lo= 0xa, /* I/O address 0 stop low byte */ Riotop0hi= 0xb, /* I/O address 0 stop high byte */ Riobtm1lo= 0xc, /* I/O address 1 start low byte */ Riobtm1hi= 0xd, /* I/O address 1 start high byte */ Riotop1lo= 0xe, /* I/O address 1 stop low byte */ Riotop1hi= 0xf, /* I/O address 1 stop high byte */ Rmap= 0x10, /* map 0 */ /* * CL-PD67xx extension registers */ Rmisc1= 0x16, /* misc control 1 */ F5Vdetect= (1<<0), Fvcc3V= (1<<1), Fpmint= (1<<2), Fpsirq= (1<<3), Fspeaker= (1<<4), Finpack= (1<<7), Rfifo= 0x17, /* fifo control */ Fflush= (1<<7), /* flush fifo */ Rmisc2= 0x1E, /* misc control 2 */ Flowpow= (1<<1), /* low power mode */ Rchipinfo= 0x1F, /* chip information */ Ratactl= 0x26, /* ATA control */ /* * offsets into the system memory address maps */ Mbtmlo= 0x0, /* System mem addr mapping start low byte */ Mbtmhi= 0x1, /* System mem addr mapping start high byte */ F16bit= (1<<7), /* 16-bit wide data path */ Mtoplo= 0x2, /* System mem addr mapping stop low byte */ Mtophi= 0x3, /* System mem addr mapping stop high byte */ Ftimer1= (1<<6), /* timer set 1 */ Mofflo= 0x4, /* Card memory offset address low byte */ 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. */ Rconfig= 0, Creset= (1<<7), /* reset device */ Clevel= (1<<6), /* level sensitive interrupt line */ Maxctab= 8, /* maximum configuration table entries */}; static int pcmcia_pcmspecial(char *, ISAConf *);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{ Ti82365, Tpd6710, Tpd6720, Tvg46x,};struct I82365{ int type; int dev; int nslot; int xreg; /* index register address */ int dreg; /* data register address */ int irq;};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 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*); voiddevi82365link(void){ static int already; if(already) return; already = 1; if (_pcmspecial) return; _pcmspecial = pcmcia_pcmspecial; _pcmspecialclose = pcmcia_pcmspecialclose;} /* * reading and writing card registers */static ucharrdreg(Slot *pp, int index){ outb(pp->cp->xreg, pp->base + index); return inb(pp->cp->dreg);}static voidwrreg(Slot *pp, int index, uchar val){ outb(pp->cp->xreg, pp->base + index); outb(pp->cp->dreg, val);} /* * get info about card */static voidslotinfo(Slot *pp){ uchar isr; isr = rdreg(pp, Ris); pp->occupied = (isr & (3<<2)) == (3<<2); pp->powered = isr & (1<<6); pp->battery = (isr & 3) == 3; pp->wrprot = isr & (1<<4); pp->busy = isr & (1<<5);} static intvcode(int volt){ switch(volt){ case 5: return 1; case 12: return 2; default: return 0; }} /* * enable the slot card */static voidslotena(Slot *pp){ if(pp->enabled) return; /* power up and unreset, wait's are empirical (???) */ wrreg(pp, Rpc, Fautopower|Foutena|Fcardena); delay(300); wrreg(pp, Rigc, 0); delay(100); wrreg(pp, Rigc, Fnotreset); delay(500); /* get configuration */ slotinfo(pp); if(pp->occupied){ cisread(pp); pp->enabled = 1; } else wrreg(pp, Rpc, Fautopower);} /* * disable the slot card */static voidslotdis(Slot *pp){ wrreg(pp, Rpc, 0); /* turn off card power */ wrreg(pp, Rwe, 0); /* no windows */ pp->enabled = 0;} /* * status change interrupt */static voidi82365intr(Ureg *, void *){ uchar csc, was; Slot *pp; if(slot == 0) return; for(pp = slot; pp < lastslot; pp++){ csc = rdreg(pp, Rcsc); was = pp->occupied; slotinfo(pp); if(csc & (1<<3) && was != pp->occupied){ if(!pp->occupied) slotdis(pp); } }} enum{ Mshift= 12, Mgran= (1<<Mshift), /* granularity of maps */ Mmask= ~(Mgran-1), /* mask for address bits important to the chip */}; /* * get a map for pc card region, return corrected len */PCMmap*pcmmap(int slotno, ulong offset, int len, int attr){ Slot *pp; uchar we, bit; PCMmap *m, *nm; int i; ulong e; pp = slot + slotno; lock(&pp->mlock); /* convert offset to granularity */ if(len <= 0) len = 1; e = ROUND(offset+len, Mgran); offset &= Mmask; len = e - offset; /* look for a map that covers the right area */ we = rdreg(pp, Rwe); bit = 1; nm = 0; for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){ if((we & bit)) if(m->attr == attr) if(offset >= m->ca && e <= m->cea){ m->ref++; unlock(&pp->mlock); return m; } bit <<= 1; if(nm == 0 && m->ref == 0) nm = m; } m = nm; if(m == 0){ unlock(&pp->mlock); return 0; } /* if isa space isn't big enough, free it and get more */ if(m->len < len){ if(m->isa){ umbfree(m->isa, m->len); m->len = 0; } m->isa = PADDR(umbmalloc(0, len, Mgran)); if(m->isa == 0){ print("pcmmap %d: out of isa space\n", len); unlock(&pp->mlock); return 0; } m->len = len; } /* set up new map */ m->ca = offset; m->cea = m->ca + m->len; m->attr = attr; i = m-pp->mmap; bit = 1<<i; wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */ wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift); wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit); wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift); wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8))); offset -= m->isa; offset &= (1<<25)-1; offset >>= Mshift; wrreg(pp, MAP(i, Mofflo), offset); wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0)); wrreg(pp, Rwe, we | bit); /* enable map */ m->ref = 1; unlock(&pp->mlock); return m;} voidpcmunmap(int slotno, PCMmap* m){ Slot *pp; pp = slot + slotno; lock(&pp->mlock); m->ref--; unlock(&pp->mlock);} static voidincrefp(Slot *pp){ lock(pp); if(pp->ref++ == 0) slotena(pp); unlock(pp);} static voiddecrefp(Slot *pp){ lock(pp); if(pp->ref-- == 1) slotdis(pp); unlock(pp);} /* * look for a card whose version contains 'idstr' */static intpcmcia_pcmspecial(char *idstr, ISAConf *isa){ Slot *pp; extern char *strstr(char*, char*); int enabled; i82365reset(); for(pp = slot; pp < lastslot; pp++){ if(pp->special) continue; /* already taken */ enabled = 0; /* make sure we don't power on cards when we already know what's * in them. We'll reread every two minutes if necessary */ if (pp->verstr[0] == '\0') { increfp(pp); enabled++; } if(pp->occupied) { if(strstr(pp->verstr, idstr)) { if (!enabled) increfp(pp); if(isa == 0 || pcmio(pp->slotno, isa) == 0){ pp->special = 1; return pp->slotno; } } } else pp->special = 1; if (enabled) decrefp(pp); } return -1;} static voidpcmcia_pcmspecialclose(int slotno){ Slot *pp; print("pcmspecialclose called\n"); if(slotno >= nslot) panic("pcmspecialclose"); pp = slot + slotno; pp->special = 0;Lines 1–500 of 1205. Load more
#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "error.h" #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 */ enum { /* * registers indices */ Rid= 0x0, /* identification and revision */ Ris= 0x1, /* interface status */ Rpc= 0x2, /* power control */ Foutena= (1<<7), /* output enable */ Fautopower= (1<<5), /* automatic power switching */ Fcardena= (1<<4), /* PC card enable */ Rigc= 0x3, /* interrupt and general control */ Fiocard= (1<<5), /* I/O card (vs memory) */ Fnotreset= (1<<6), /* reset if not set */ FSMIena= (1<<4), /* enable change interrupt on SMI */ Rcsc= 0x4, /* card status change */ Rcscic= 0x5, /* card status change interrupt config */ Fchangeena= (1<<3), /* card changed */ Fbwarnena= (1<<1), /* card battery warning */ Fbdeadena= (1<<0), /* card battery dead */ Rwe= 0x6, /* address window enable */ Fmem16= (1<<5), /* use A23-A12 to decode address */ Rio= 0x7, /* I/O control */ Fwidth16= (1<<0), /* 16 bit data width */ Fiocs16= (1<<1), /* IOCS16 determines data width */ Fzerows= (1<<2), /* zero wait state */ Ftiming= (1<<3), /* timing register to use */ Riobtm0lo= 0x8, /* I/O address 0 start low byte */ Riobtm0hi= 0x9, /* I/O address 0 start high byte */ Riotop0lo= 0xa, /* I/O address 0 stop low byte */ Riotop0hi= 0xb, /* I/O address 0 stop high byte */ Riobtm1lo= 0xc, /* I/O address 1 start low byte */ Riobtm1hi= 0xd, /* I/O address 1 start high byte */ Riotop1lo= 0xe, /* I/O address 1 stop low byte */ Riotop1hi= 0xf, /* I/O address 1 stop high byte */ Rmap= 0x10, /* map 0 */ /* * CL-PD67xx extension registers */ Rmisc1= 0x16, /* misc control 1 */ F5Vdetect= (1<<0), Fvcc3V= (1<<1), Fpmint= (1<<2), Fpsirq= (1<<3), Fspeaker= (1<<4), Finpack= (1<<7), Rfifo= 0x17, /* fifo control */ Fflush= (1<<7), /* flush fifo */ Rmisc2= 0x1E, /* misc control 2 */ Flowpow= (1<<1), /* low power mode */ Rchipinfo= 0x1F, /* chip information */ Ratactl= 0x26, /* ATA control */ /* * offsets into the system memory address maps */ Mbtmlo= 0x0, /* System mem addr mapping start low byte */ Mbtmhi= 0x1, /* System mem addr mapping start high byte */ F16bit= (1<<7), /* 16-bit wide data path */ Mtoplo= 0x2, /* System mem addr mapping stop low byte */ Mtophi= 0x3, /* System mem addr mapping stop high byte */ Ftimer1= (1<<6), /* timer set 1 */ Mofflo= 0x4, /* Card memory offset address low byte */ 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. */ Rconfig= 0, Creset= (1<<7), /* reset device */ Clevel= (1<<6), /* level sensitive interrupt line */ Maxctab= 8, /* maximum configuration table entries */ }; static int pcmcia_pcmspecial(char *, ISAConf *); 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 { Ti82365, Tpd6710, Tpd6720, Tvg46x, }; struct I82365 { int type; int dev; int nslot; int xreg; /* index register address */ int dreg; /* data register address */ int irq; }; 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 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*); void devi82365link(void) { static int already; if(already) return; already = 1; if (_pcmspecial) return; _pcmspecial = pcmcia_pcmspecial; _pcmspecialclose = pcmcia_pcmspecialclose; } /* * reading and writing card registers */ static uchar rdreg(Slot *pp, int index) { outb(pp->cp->xreg, pp->base + index); return inb(pp->cp->dreg); } static void wrreg(Slot *pp, int index, uchar val) { outb(pp->cp->xreg, pp->base + index); outb(pp->cp->dreg, val); } /* * get info about card */ static void slotinfo(Slot *pp) { uchar isr; isr = rdreg(pp, Ris); pp->occupied = (isr & (3<<2)) == (3<<2); pp->powered = isr & (1<<6); pp->battery = (isr & 3) == 3; pp->wrprot = isr & (1<<4); pp->busy = isr & (1<<5); } static int vcode(int volt) { switch(volt){ case 5: return 1; case 12: return 2; default: return 0; } } /* * enable the slot card */ static void slotena(Slot *pp) { if(pp->enabled) return; /* power up and unreset, wait's are empirical (???) */ wrreg(pp, Rpc, Fautopower|Foutena|Fcardena); delay(300); wrreg(pp, Rigc, 0); delay(100); wrreg(pp, Rigc, Fnotreset); delay(500); /* get configuration */ slotinfo(pp); if(pp->occupied){ cisread(pp); pp->enabled = 1; } else wrreg(pp, Rpc, Fautopower); } /* * disable the slot card */ static void slotdis(Slot *pp) { wrreg(pp, Rpc, 0); /* turn off card power */ wrreg(pp, Rwe, 0); /* no windows */ pp->enabled = 0; } /* * status change interrupt */ static void i82365intr(Ureg *, void *) { uchar csc, was; Slot *pp; if(slot == 0) return; for(pp = slot; pp < lastslot; pp++){ csc = rdreg(pp, Rcsc); was = pp->occupied; slotinfo(pp); if(csc & (1<<3) && was != pp->occupied){ if(!pp->occupied) slotdis(pp); } } } enum { Mshift= 12, Mgran= (1<<Mshift), /* granularity of maps */ Mmask= ~(Mgran-1), /* mask for address bits important to the chip */ }; /* * get a map for pc card region, return corrected len */ PCMmap* pcmmap(int slotno, ulong offset, int len, int attr) { Slot *pp; uchar we, bit; PCMmap *m, *nm; int i; ulong e; pp = slot + slotno; lock(&pp->mlock); /* convert offset to granularity */ if(len <= 0) len = 1; e = ROUND(offset+len, Mgran); offset &= Mmask; len = e - offset; /* look for a map that covers the right area */ we = rdreg(pp, Rwe); bit = 1; nm = 0; for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){ if((we & bit)) if(m->attr == attr) if(offset >= m->ca && e <= m->cea){ m->ref++; unlock(&pp->mlock); return m; } bit <<= 1; if(nm == 0 && m->ref == 0) nm = m; } m = nm; if(m == 0){ unlock(&pp->mlock); return 0; } /* if isa space isn't big enough, free it and get more */ if(m->len < len){ if(m->isa){ umbfree(m->isa, m->len); m->len = 0; } m->isa = PADDR(umbmalloc(0, len, Mgran)); if(m->isa == 0){ print("pcmmap %d: out of isa space\n", len); unlock(&pp->mlock); return 0; } m->len = len; } /* set up new map */ m->ca = offset; m->cea = m->ca + m->len; m->attr = attr; i = m-pp->mmap; bit = 1<<i; wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */ wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift); wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit); wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift); wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8))); offset -= m->isa; offset &= (1<<25)-1; offset >>= Mshift; wrreg(pp, MAP(i, Mofflo), offset); wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0)); wrreg(pp, Rwe, we | bit); /* enable map */ m->ref = 1; unlock(&pp->mlock); return m; } void pcmunmap(int slotno, PCMmap* m) { Slot *pp; pp = slot + slotno; lock(&pp->mlock); m->ref--; unlock(&pp->mlock); } static void increfp(Slot *pp) { lock(pp); if(pp->ref++ == 0) slotena(pp); unlock(pp); } static void decrefp(Slot *pp) { lock(pp); if(pp->ref-- == 1) slotdis(pp); unlock(pp); } /* * look for a card whose version contains 'idstr' */ static int pcmcia_pcmspecial(char *idstr, ISAConf *isa) { Slot *pp; extern char *strstr(char*, char*); int enabled; i82365reset(); for(pp = slot; pp < lastslot; pp++){ if(pp->special) continue; /* already taken */ enabled = 0; /* make sure we don't power on cards when we already know what's * in them. We'll reread every two minutes if necessary */ if (pp->verstr[0] == '\0') { increfp(pp); enabled++; } if(pp->occupied) { if(strstr(pp->verstr, idstr)) { if (!enabled) increfp(pp); if(isa == 0 || pcmio(pp->slotno, isa) == 0){ pp->special = 1; return pp->slotno; } } } else pp->special = 1; if (enabled) decrefp(pp); } return -1; } static void pcmcia_pcmspecialclose(int slotno) { Slot *pp; print("pcmspecialclose called\n"); if(slotno >= nslot) panic("pcmspecialclose"); pp = slot + slotno; pp->special = 0;