#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h" /* * MPC821/3 PCMCIA driver (prototype) * * unlike the i82365 adapter, there isn't an offset register: * card addresses are simply the lower order 26 bits of the host address. * * to do: * split allocation of memory/attrib (all 26 bits valid) and io space (typically 10 or 12 bits) * correct config * interrupts and i/o space access * DMA? * power control */ enum{ Maxctlr= 1, Maxslot= 2, Slotashift= 16, /* pipr */ Cbvs1= 1<<15, Cbvs2= 1<<14, Cbwp= 1<<13, Cbcd2= 1<<12, Cbcd1= 1<<11, Cbbvd2= 1<<10, Cbbvd1= 1<<9, Cbrdy= 1<<8, /* pscr and per */ Cbvs1_c= 1<<15, Cbvs2_c= 1<<14, Cbwp_c= 1<<13, Cbcd2_c= 1<<12, Cbcd1_c= 1<<11, Cbbvd2_c= 1<<10, Cbbvd1_c= 1<<9, Cbrdy_l= 1<<7, Cbrdy_h= 1<<6, Cbrdy_r= 1<<5, Cbrdy_f= 1<<4, /* pgcr[n] */ Cbdreq_int= 0<<14, Cbdreq_iois16= 2<<14, Cbdreq_spkr= 3<<14, Cboe= 1<<7, Cbreset= 1<<6, /* porN */ Rport8= 0<<6, Rport16= 1<<6, Rmtype= 7<<3, /* memory type field */ Rmem= 0<<3, /* common memory space */ Rattrib= 2<<3, /* attribute space */ Rio= 3<<3, Rdma= 4<<3, /* normal DMA */ Rdmalx= 5<<3, /* DMA, last transaction */ RA22_23= 6<<3, /* ``drive A22 and A23 signals on CE2 and CE1'' */ RslotB= 1<<2, /* select slot B (always, on MPC823) */ Rwp= 1<<1, /* write protect */ Rvalid= 1<<0, /* region valid */ Nmap= 8, /* 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 */ Rccsr= 2, Ciack = (1<<0), Cipend = (1<<1), Cpwrdown= (1<<2), Caudioen= (1<<3), Ciois8= (1<<5), Cchgena= (1<<6), Cchange= (1<<7), Rpin= 4, /* pin replacement register */ Rscpr= 6, /* socket and copy register */ Riob0= 10, Riob1= 12, Riob2= 14, Riob3= 16, Riolim= 18, Maxctab= 8, /* maximum configuration table entries */ MaxCIS = 8192, /* maximum CIS size in bytes */ Mgran = 8192, /* maximum size of reads and writes */ Statusbounce=20, /* msec debounce time */}; typedef struct Ctlr Ctlr; /* a controller (there's only one) */struct Ctlr{ int dev; int nslot; /* memory maps */ Lock mlock; /* lock down the maps */ PCMmap mmap[Nmap]; /* maps */ /* IO port allocation */ ulong nextport;};static Ctlr controller[Maxctlr]; static PCMslot *slot;static PCMslot *lastslot;static int nslot; static Map pcmmapv[Nmap+1];static RMap pcmmaps = {"PCMCIA mappings"}; static void pcmciaintr(Ureg*, void*);static void pcmciareset(void);static int pcmio(int, ISAConf*);static long pcmread(int, int, void*, long, ulong);static long pcmwrite(int, int, void*, long, ulong);static void slotdis(PCMslot*); static ulong pcmmalloc(ulong, long);static void pcmfree(ulong, long);static void pcmciaproc(void*); static void pcmciadump(PCMslot*); /* * get info about card */static voidslotinfo(PCMslot *pp){ ulong pipr; pipr = (m->iomem->pipr >> pp->slotshift) & 0xFF00;print("pipr=%8.8lux/%lux\n", m->iomem->pipr, pipr); pp->v3_3 = (pipr&Cbvs1)!=0; pp->voltage = (((pipr & Cbvs2)!=0)<<1) | ((pipr & Cbvs1)!=0); pp->occupied = (pipr&(Cbcd1|Cbcd2))==0; pp->powered = pcmpowered(pp->slotno); pp->battery = (pipr & (Cbbvd1|Cbbvd2))>>9; pp->wrprot = (pipr&Cbwp)!=0; pp->busy = (pipr&Cbrdy)==0;} static voidpcmdelay(int ms){ if(up == nil) delay(ms); else tsleep(&up->sleep, return0, nil, ms);} /* * enable the slot card */static voidslotena(PCMslot *pp){ IMM *io; if(pp->enabled) return; m->iomem->pgcr[pp->slotno] &= ~Cboe; pcmpower(pp->slotno, 1); eieio(); pcmdelay(300); io = m->iomem; io->pgcr[pp->slotno] |= Cbreset; /* active high */ eieio(); pcmdelay(100); io->pgcr[pp->slotno] &= ~Cbreset; eieio(); pcmdelay(500); /* ludicrous delay */ /* get configuration */ slotinfo(pp); if(pp->occupied){ if(pp->cisread == 0){ pcmcisread(pp); pp->cisread = 1; } pp->enabled = 1; } else{ print("empty slot\n"); slotdis(pp); }} /* * disable the slot card */static voidslotdis(PCMslot *pp){ int i; Ctlr *ctlr; PCMmap *pm; iprint("slotdis %d\n", pp->slotno); pcmpower(pp->slotno, 0); m->iomem->pgcr[pp->slotno] |= Cboe; ctlr = pp->ctlr; for(i = 0; i < nelem(ctlr->mmap); i++){ pm = &ctlr->mmap[i]; if(m->iomem->pcmr[i].option & Rvalid && pm->slotno == pp->slotno) pcmunmap(pp->slotno, pm); } pp->enabled = 0; pp->cisread = 0;} static voidpcmciardy(Ureg *ur, void *a){ PCMslot *pp; ulong w; pp = a; w = (m->iomem->pipr >> pp->slotshift) & 0xFF00; if(pp->occupied && (w & Cbrdy) == 0){ /* interrupt */print("PCM.%dI#%lux|", pp->slotno, w); if(pp->intr.f != nil) pp->intr.f(ur, pp->intr.arg); }} voidpcmintrenable(int slotno, void (*f)(Ureg*, void*), void *arg){ PCMslot *pp; IMM *io; char name[KNAMELEN]; if(slotno < 0 || slotno >= nslot) panic("pcmintrenable"); snprint(name, sizeof(name), "pcmcia.irq%d", slotno); io = ioplock(); pp = slot+slotno; pp->intr.f = f; pp->intr.arg = arg; intrenable(PCMCIAio, pcmciardy, pp, BUSUNKNOWN, name); io->per |= Cbrdy_l; /* assumes used for irq, not rdy; assumes level interrupt always right */ iopunlock();} voidpcmintrdisable(int slotno, void (*f)(Ureg*, void*), void *arg){ PCMslot *pp; IMM *io; char name[KNAMELEN]; if(slotno < 0 || slotno >= nslot) panic("pcmintrdisable"); snprint(name, sizeof(name), "pcmcia.irq%d", slotno); io = ioplock(); pp = slot+slotno; if(pp->intr.f == f && pp->intr.arg == arg){ pp->intr.f = nil; pp->intr.arg = nil; intrdisable(PCMCIAio, pcmciardy, pp, BUSUNKNOWN, name); io->per &= ~Cbrdy_l; } iopunlock();} /* * status change interrupt * * this wakes a monitoring process to read the CIS, * rather than holding other interrupts out here. */ static Rendez pcmstate; static intstatechanged(void *a){ PCMslot *pp; int in; pp = a; in = (m->iomem->pipr & (Cbcd1|Cbcd2))==0; return in != pp->occupied;} static voidpcmciaintr(Ureg*, void*){ ulong events; if(slot == 0) return; events = m->iomem->pscr & (Cbvs1_c|Cbvs2_c|Cbwp_c|Cbcd2_c|Cbcd1_c|Cbbvd2_c|Cbbvd1_c); eieio(); m->iomem->pscr = events; /* TO DO: other slot */iprint("PCM: #%lux|", events);iprint("pipr=#%lux|", m->iomem->pipr & 0xFF00); wakeup(&pcmstate);} static voidpcmciaproc(void*){ ulong csc; PCMslot *pp; int was; for(;;){ sleep(&pcmstate, statechanged, slot+1); tsleep(&up->sleep, return0, nil, Statusbounce); /* * voltage change 1,2 * write protect change * card detect 1,2 * battery voltage 1 change (or SPKR-bar) * battery voltage 2 change (or STSCHG-bar) * card B rdy / IRQ-bar low * card B rdy / IRQ-bar high * card B rdy / IRQ-bar rising edge * card B rdy / IRQ-bar falling edge * * TO DO: currently only handle card-present changes */ for(pp = slot; pp < lastslot; pp++){ if(pp->memlen == 0) continue; csc = (m->iomem->pipr>>pp->slotshift) & (Cbcd1|Cbcd2); was = pp->occupied; slotinfo(pp); if(csc == 0 && was != pp->occupied){ if(!pp->occupied){ slotdis(pp); if(pp->special && pp->notify.f != nil) pp->notify.f(pp->notify.arg, 1); } } } }} static uchar greycode[] = { 0, 1, 3, 2, 6, 7, 5, 4, 014, 015, 017, 016, 012, 013, 011, 010, 030, 031, 033, 032, 036, 037, 035, 034, 024, 025, 027}; /* * get a map for pc card region, return corrected len */PCMmap*pcmmap(int slotno, ulong offset, int len, int attr){ Ctlr *ctlr; PCMslot *pp; PCMmap *pm, *nm; IMM *io; int i; ulong e, bsize, code, opt; if(0) print("pcmmap: %d #%lux %d #%x\n", slotno, offset, len, attr); pp = slot + slotno; if(!pp->occupied) return nil; if(attr == 1){ /* account for ../port/cis.c's conventions */ attr = Rattrib; if(len <= 0) len = MaxCIS*2; /* TO DO */ } ctlr = pp->ctlr; /* convert offset to granularity */ if(len <= 0) len = 1; e = offset+len; for(i=0;; i++){ if(i >= nelem(greycode)) return nil; bsize = 1<<i; offset &= ~(bsize-1); if(e <= offset+bsize) break; } code = greycode[i]; if(0) print("i=%d bsize=%lud code=0%luo\n", i, bsize, code); e = offset+bsize; len = bsize; lock(&ctlr->mlock); /* look for an existing map that covers the right area */ io = m->iomem; nm = nil; for(i=0; i<Nmap; i++){ pm = &ctlr->mmap[i]; if(io->pcmr[i].option & Rvalid && pm->slotno == slotno && pm->attr == attr && offset >= pm->ca && e <= pm->cea){ pm->ref++; unlock(&ctlr->mlock); return pm; } if(nm == 0 && pm->ref == 0) nm = pm; } pm = nm; if(pm == nil){ unlock(&ctlr->mlock); return nil; } /* set up new map */ pm->isa = pcmmalloc(offset, len); if(pm->isa == 0){ /* address not available: in use, or too much to map */ unlock(&ctlr->mlock); return 0; } if(0) print("mx=%d isa=#%lux\n", (int)(pm - ctlr->mmap), pm->isa); pm->len = len; pm->ca = offset; pm->cea = pm->ca + pm->len; pm->attr = attr; i = pm - ctlr->mmap; io->pcmr[i].option &= ~Rvalid; /* disable map before changing it */ io->pcmr[i].base = pm->isa; opt = attr; opt |= code<<27; if((attr&Rmtype) == Rio){ opt |= 4<<12; /* PSST */ opt |= 8<<7; /* PSL */ opt |= 2<<16; /* PSHT */ }else{ opt |= 6<<12; /* PSST */ opt |= 24<<7; /* PSL */ opt |= 8<<16; /* PSHT */ } if((attr & Rport16) == 0) opt |= Rport8; if(slotno == 1) opt |= RslotB; io->pcmr[i].option = opt | Rvalid; pm->slotno = slotno; pm->ref = 1; unlock(&ctlr->mlock); return pm;} static voidpcmiomap(PCMslot *pp, PCMconftab *ct, int i){ int n, attr; Ctlr *ctlr; if(0) print("pcm iomap #%lux %lud\n", ct->io[i].start, ct->io[i].len); if(ct->io[i].len <= 0) return; if(ct->io[i].start == 0){ n = 1<<ct->nlines; ctlr = pp->ctlr; lock(&ctlr->mlock); if(ctlr->nextport == 0) ctlr->nextport = 0xF000; ctlr->nextport = (ctlr->nextport + n - 1) & ~(n-1); ct->io[i].start = ctlr->nextport; ct->io[i].len = n; ctlr->nextport += n; unlock(&ctlr->mlock); } attr = Rio; if(ct->bit16) attr |= Rport16; ct->io[i].map = pcmmap(pp->slotno, ct->io[i].start, ct->io[i].len, attr);} Lines 1–500 of 1076. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" /* * MPC821/3 PCMCIA driver (prototype) * * unlike the i82365 adapter, there isn't an offset register: * card addresses are simply the lower order 26 bits of the host address. * * to do: * split allocation of memory/attrib (all 26 bits valid) and io space (typically 10 or 12 bits) * correct config * interrupts and i/o space access * DMA? * power control */ enum { Maxctlr= 1, Maxslot= 2, Slotashift= 16, /* pipr */ Cbvs1= 1<<15, Cbvs2= 1<<14, Cbwp= 1<<13, Cbcd2= 1<<12, Cbcd1= 1<<11, Cbbvd2= 1<<10, Cbbvd1= 1<<9, Cbrdy= 1<<8, /* pscr and per */ Cbvs1_c= 1<<15, Cbvs2_c= 1<<14, Cbwp_c= 1<<13, Cbcd2_c= 1<<12, Cbcd1_c= 1<<11, Cbbvd2_c= 1<<10, Cbbvd1_c= 1<<9, Cbrdy_l= 1<<7, Cbrdy_h= 1<<6, Cbrdy_r= 1<<5, Cbrdy_f= 1<<4, /* pgcr[n] */ Cbdreq_int= 0<<14, Cbdreq_iois16= 2<<14, Cbdreq_spkr= 3<<14, Cboe= 1<<7, Cbreset= 1<<6, /* porN */ Rport8= 0<<6, Rport16= 1<<6, Rmtype= 7<<3, /* memory type field */ Rmem= 0<<3, /* common memory space */ Rattrib= 2<<3, /* attribute space */ Rio= 3<<3, Rdma= 4<<3, /* normal DMA */ Rdmalx= 5<<3, /* DMA, last transaction */ RA22_23= 6<<3, /* ``drive A22 and A23 signals on CE2 and CE1'' */ RslotB= 1<<2, /* select slot B (always, on MPC823) */ Rwp= 1<<1, /* write protect */ Rvalid= 1<<0, /* region valid */ Nmap= 8, /* 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 */ Rccsr= 2, Ciack = (1<<0), Cipend = (1<<1), Cpwrdown= (1<<2), Caudioen= (1<<3), Ciois8= (1<<5), Cchgena= (1<<6), Cchange= (1<<7), Rpin= 4, /* pin replacement register */ Rscpr= 6, /* socket and copy register */ Riob0= 10, Riob1= 12, Riob2= 14, Riob3= 16, Riolim= 18, Maxctab= 8, /* maximum configuration table entries */ MaxCIS = 8192, /* maximum CIS size in bytes */ Mgran = 8192, /* maximum size of reads and writes */ Statusbounce=20, /* msec debounce time */ }; typedef struct Ctlr Ctlr; /* a controller (there's only one) */ struct Ctlr { int dev; int nslot; /* memory maps */ Lock mlock; /* lock down the maps */ PCMmap mmap[Nmap]; /* maps */ /* IO port allocation */ ulong nextport; }; static Ctlr controller[Maxctlr]; static PCMslot *slot; static PCMslot *lastslot; static int nslot; static Map pcmmapv[Nmap+1]; static RMap pcmmaps = {"PCMCIA mappings"}; static void pcmciaintr(Ureg*, void*); static void pcmciareset(void); static int pcmio(int, ISAConf*); static long pcmread(int, int, void*, long, ulong); static long pcmwrite(int, int, void*, long, ulong); static void slotdis(PCMslot*); static ulong pcmmalloc(ulong, long); static void pcmfree(ulong, long); static void pcmciaproc(void*); static void pcmciadump(PCMslot*); /* * get info about card */ static void slotinfo(PCMslot *pp) { ulong pipr; pipr = (m->iomem->pipr >> pp->slotshift) & 0xFF00; print("pipr=%8.8lux/%lux\n", m->iomem->pipr, pipr); pp->v3_3 = (pipr&Cbvs1)!=0; pp->voltage = (((pipr & Cbvs2)!=0)<<1) | ((pipr & Cbvs1)!=0); pp->occupied = (pipr&(Cbcd1|Cbcd2))==0; pp->powered = pcmpowered(pp->slotno); pp->battery = (pipr & (Cbbvd1|Cbbvd2))>>9; pp->wrprot = (pipr&Cbwp)!=0; pp->busy = (pipr&Cbrdy)==0; } static void pcmdelay(int ms) { if(up == nil) delay(ms); else tsleep(&up->sleep, return0, nil, ms); } /* * enable the slot card */ static void slotena(PCMslot *pp) { IMM *io; if(pp->enabled) return; m->iomem->pgcr[pp->slotno] &= ~Cboe; pcmpower(pp->slotno, 1); eieio(); pcmdelay(300); io = m->iomem; io->pgcr[pp->slotno] |= Cbreset; /* active high */ eieio(); pcmdelay(100); io->pgcr[pp->slotno] &= ~Cbreset; eieio(); pcmdelay(500); /* ludicrous delay */ /* get configuration */ slotinfo(pp); if(pp->occupied){ if(pp->cisread == 0){ pcmcisread(pp); pp->cisread = 1; } pp->enabled = 1; } else{ print("empty slot\n"); slotdis(pp); } } /* * disable the slot card */ static void slotdis(PCMslot *pp) { int i; Ctlr *ctlr; PCMmap *pm; iprint("slotdis %d\n", pp->slotno); pcmpower(pp->slotno, 0); m->iomem->pgcr[pp->slotno] |= Cboe; ctlr = pp->ctlr; for(i = 0; i < nelem(ctlr->mmap); i++){ pm = &ctlr->mmap[i]; if(m->iomem->pcmr[i].option & Rvalid && pm->slotno == pp->slotno) pcmunmap(pp->slotno, pm); } pp->enabled = 0; pp->cisread = 0; } static void pcmciardy(Ureg *ur, void *a) { PCMslot *pp; ulong w; pp = a; w = (m->iomem->pipr >> pp->slotshift) & 0xFF00; if(pp->occupied && (w & Cbrdy) == 0){ /* interrupt */ print("PCM.%dI#%lux|", pp->slotno, w); if(pp->intr.f != nil) pp->intr.f(ur, pp->intr.arg); } } void pcmintrenable(int slotno, void (*f)(Ureg*, void*), void *arg) { PCMslot *pp; IMM *io; char name[KNAMELEN]; if(slotno < 0 || slotno >= nslot) panic("pcmintrenable"); snprint(name, sizeof(name), "pcmcia.irq%d", slotno); io = ioplock(); pp = slot+slotno; pp->intr.f = f; pp->intr.arg = arg; intrenable(PCMCIAio, pcmciardy, pp, BUSUNKNOWN, name); io->per |= Cbrdy_l; /* assumes used for irq, not rdy; assumes level interrupt always right */ iopunlock(); } void pcmintrdisable(int slotno, void (*f)(Ureg*, void*), void *arg) { PCMslot *pp; IMM *io; char name[KNAMELEN]; if(slotno < 0 || slotno >= nslot) panic("pcmintrdisable"); snprint(name, sizeof(name), "pcmcia.irq%d", slotno); io = ioplock(); pp = slot+slotno; if(pp->intr.f == f && pp->intr.arg == arg){ pp->intr.f = nil; pp->intr.arg = nil; intrdisable(PCMCIAio, pcmciardy, pp, BUSUNKNOWN, name); io->per &= ~Cbrdy_l; } iopunlock(); } /* * status change interrupt * * this wakes a monitoring process to read the CIS, * rather than holding other interrupts out here. */ static Rendez pcmstate; static int statechanged(void *a) { PCMslot *pp; int in; pp = a; in = (m->iomem->pipr & (Cbcd1|Cbcd2))==0; return in != pp->occupied; } static void pcmciaintr(Ureg*, void*) { ulong events; if(slot == 0) return; events = m->iomem->pscr & (Cbvs1_c|Cbvs2_c|Cbwp_c|Cbcd2_c|Cbcd1_c|Cbbvd2_c|Cbbvd1_c); eieio(); m->iomem->pscr = events; /* TO DO: other slot */ iprint("PCM: #%lux|", events); iprint("pipr=#%lux|", m->iomem->pipr & 0xFF00); wakeup(&pcmstate); } static void pcmciaproc(void*) { ulong csc; PCMslot *pp; int was; for(;;){ sleep(&pcmstate, statechanged, slot+1); tsleep(&up->sleep, return0, nil, Statusbounce); /* * voltage change 1,2 * write protect change * card detect 1,2 * battery voltage 1 change (or SPKR-bar) * battery voltage 2 change (or STSCHG-bar) * card B rdy / IRQ-bar low * card B rdy / IRQ-bar high * card B rdy / IRQ-bar rising edge * card B rdy / IRQ-bar falling edge * * TO DO: currently only handle card-present changes */ for(pp = slot; pp < lastslot; pp++){ if(pp->memlen == 0) continue; csc = (m->iomem->pipr>>pp->slotshift) & (Cbcd1|Cbcd2); was = pp->occupied; slotinfo(pp); if(csc == 0 && was != pp->occupied){ if(!pp->occupied){ slotdis(pp); if(pp->special && pp->notify.f != nil) pp->notify.f(pp->notify.arg, 1); } } } } } static uchar greycode[] = { 0, 1, 3, 2, 6, 7, 5, 4, 014, 015, 017, 016, 012, 013, 011, 010, 030, 031, 033, 032, 036, 037, 035, 034, 024, 025, 027 }; /* * get a map for pc card region, return corrected len */ PCMmap* pcmmap(int slotno, ulong offset, int len, int attr) { Ctlr *ctlr; PCMslot *pp; PCMmap *pm, *nm; IMM *io; int i; ulong e, bsize, code, opt; if(0) print("pcmmap: %d #%lux %d #%x\n", slotno, offset, len, attr); pp = slot + slotno; if(!pp->occupied) return nil; if(attr == 1){ /* account for ../port/cis.c's conventions */ attr = Rattrib; if(len <= 0) len = MaxCIS*2; /* TO DO */ } ctlr = pp->ctlr; /* convert offset to granularity */ if(len <= 0) len = 1; e = offset+len; for(i=0;; i++){ if(i >= nelem(greycode)) return nil; bsize = 1<<i; offset &= ~(bsize-1); if(e <= offset+bsize) break; } code = greycode[i]; if(0) print("i=%d bsize=%lud code=0%luo\n", i, bsize, code); e = offset+bsize; len = bsize; lock(&ctlr->mlock); /* look for an existing map that covers the right area */ io = m->iomem; nm = nil; for(i=0; i<Nmap; i++){ pm = &ctlr->mmap[i]; if(io->pcmr[i].option & Rvalid && pm->slotno == slotno && pm->attr == attr && offset >= pm->ca && e <= pm->cea){ pm->ref++; unlock(&ctlr->mlock); return pm; } if(nm == 0 && pm->ref == 0) nm = pm; } pm = nm; if(pm == nil){ unlock(&ctlr->mlock); return nil; } /* set up new map */ pm->isa = pcmmalloc(offset, len); if(pm->isa == 0){ /* address not available: in use, or too much to map */ unlock(&ctlr->mlock); return 0; } if(0) print("mx=%d isa=#%lux\n", (int)(pm - ctlr->mmap), pm->isa); pm->len = len; pm->ca = offset; pm->cea = pm->ca + pm->len; pm->attr = attr; i = pm - ctlr->mmap; io->pcmr[i].option &= ~Rvalid; /* disable map before changing it */ io->pcmr[i].base = pm->isa; opt = attr; opt |= code<<27; if((attr&Rmtype) == Rio){ opt |= 4<<12; /* PSST */ opt |= 8<<7; /* PSL */ opt |= 2<<16; /* PSHT */ }else{ opt |= 6<<12; /* PSST */ opt |= 24<<7; /* PSL */ opt |= 8<<16; /* PSHT */ } if((attr & Rport16) == 0) opt |= Rport8; if(slotno == 1) opt |= RslotB; io->pcmr[i].option = opt | Rvalid; pm->slotno = slotno; pm->ref = 1; unlock(&ctlr->mlock); return pm; } static void pcmiomap(PCMslot *pp, PCMconftab *ct, int i) { int n, attr; Ctlr *ctlr; if(0) print("pcm iomap #%lux %lud\n", ct->io[i].start, ct->io[i].len); if(ct->io[i].len <= 0) return; if(ct->io[i].start == 0){ n = 1<<ct->nlines; ctlr = pp->ctlr; lock(&ctlr->mlock); if(ctlr->nextport == 0) ctlr->nextport = 0xF000; ctlr->nextport = (ctlr->nextport + n - 1) & ~(n-1); ct->io[i].start = ctlr->nextport; ct->io[i].len = n; ctlr->nextport += n; unlock(&ctlr->mlock); } attr = Rio; if(ct->bit16) attr |= Rport16; ct->io[i].map = pcmmap(pp->slotno, ct->io[i].start, ct->io[i].len, attr); }