📄 devpccard.c
字号:
baddr = upaalloc(size, size); baddrva = vmap(baddr, size); pcicfgw32(cb->pci, PciBAR0, baddr); cb->regs = (ulong *)baddrva; } else cb->regs = (ulong *)vmap(baddr, 4096); cb->state = SlotEmpty; /* Don't really know what to do with this... */ i82365probe(cb, LegacyAddr, LegacyAddr + 1); print("#Y%ld: %s, %.8ulX intl %d\n", cb - cbslots, variant[i].name, baddr, pci->intl); } if (nslots == 0){ iofree(LegacyAddr); return; } _pcmspecial = pccard_pcmspecial; _pcmspecialclose = pccard_pcmspecialclose; for (i = 0; i != nslots; i++) { Cardbus *cb = &cbslots[i]; if ((cb->regs[SocketState] & SE_CCD) == 0) engine(cb, CardDetected); } delay(500); /* Allow time for power up */ for (i = 0; i != nslots; i++) { Cardbus *cb = &cbslots[i]; if (cb->regs[SocketState] & SE_POWER) engine(cb, CardPowered); /* Ack and enable interrupts on all events */ //cb->regs[SocketEvent] = cb->regs[SocketEvent]; cb->regs[SocketMask] |= 0xF; wrreg(cb, Rcscic, 0xC); }}static intpowerup(Cardbus *cb){ ulong state; ushort bcr; state = cb->regs[SocketState]; if (state & SS_PC16) { if(DEBUG) print("#Y%ld: Probed a PC16 card, powering up card\n", cb - cbslots); cb->type = PC16; memset(&cb->linfo, 0, sizeof(Pcminfo)); /* power up and unreset, wait's are empirical (???) */ wrreg(cb, Rpc, Fautopower|Foutena|Fcardena); delay(300); wrreg(cb, Rigc, 0); delay(100); wrreg(cb, Rigc, Fnotreset); delay(500);// return 1; } if (state & SS_CCD) return 0; if (state & SS_NOTCARD) { print("#Y%ld: No card inserted\n", cb - cbslots); return 0; } if ((state & SS_3V) == 0 && (state & SS_5V) == 0) { print("#Y%ld: Unsupported voltage, powering down card!\n", cb - cbslots); cb->regs[SocketControl] = 0; return 0; } if(DEBUG) print("#Y%ld: card %spowered at %d volt\n", cb - cbslots, (state & SS_POWER)? "": "not ", (state & SS_3V)? 3: (state & SS_5V)? 5: -1); /* Power up the card * and make sure the secondary bus is not in reset. */ cb->regs[SocketControl] = (state & SS_5V)? SC_5V: SC_3V; delay(50); bcr = pcicfgr16(cb->pci, PciBCR); bcr &= ~0x40; pcicfgw16(cb->pci, PciBCR, bcr); delay(100); if (state & SS_PC16) cb->type = PC16; else cb->type = PC32; return 1;}static voidpowerdown(Cardbus *cb){ ushort bcr; if (cb->type == PC16) { wrreg(cb, Rpc, 0); /* turn off card power */ wrreg(cb, Rwe, 0); /* no windows */ cb->type = -1; return; } bcr = pcicfgr16(cb->pci, PciBCR); bcr |= 0x40; pcicfgw16(cb->pci, PciBCR, bcr); cb->regs[SocketControl] = 0; cb->type = -1;}static voidconfigure(Cardbus *cb){ int i, r; ulong size, bar; Pcidev *pci; ulong membase, iobase, memlen, iolen, rombase, romlen; if(DEBUG) print("configuring slot %ld (%s)\n", cb - cbslots, states[cb->state]); if (cb->state == SlotConfigured) return; engine(cb, CardConfigured); delay(50); /* Emperically established */ if (cb->type == PC16) { i82365configure(cb); return; } /* Scan the CardBus for new PCI devices */ pciscan(pcicfgr8(cb->pci, PciSBN), &cb->pci->bridge); /* * size the devices on the bus, reserve a minimum for devices arriving later, * allow for ROM space, allocate space, and set the cardbus mapping registers */ pcibussize(cb->pci->bridge, &memlen, &iolen); /* TO DO: need initial alignments */ romlen = 0; for(pci = cb->pci->bridge; pci != nil; pci = pci->list){ size = pcibarsize(pci, PciEBAR0); if(size > 0){ pci->rom.bar = -1; pci->rom.size = size; romlen += size; } } if(iolen < 512) iolen = 512; iobase = ioreserve(~0, iolen, 0, "cardbus"); pcicfgw32(cb->pci, PciCBIBR0, iobase); pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1); pcicfgw32(cb->pci, PciCBIBR1, 0); pcicfgw32(cb->pci, PciCBILR1, 0); rombase = memlen; memlen += romlen; if(memlen < 1*1024*1024) memlen = 1*1024*1024; membase = upaalloc(memlen, 4*1024*1024); /* TO DO: better alignment */ pcicfgw32(cb->pci, PciCBMBR0, membase); pcicfgw32(cb->pci, PciCBMLR0, membase + memlen-1); pcicfgw32(cb->pci, PciCBMBR1, 0); pcicfgw32(cb->pci, PciCBMLR1, 0);// pcibussize(cb->pci->bridge, &membase, &iobase); /* now assign them */ rombase += membase; for(pci = cb->pci->bridge; pci != nil; pci = pci->list){ r = pcicfgr16(pci, PciPCR); r &= ~(PciPCR_IO|PciPCR_MEM); pcicfgw16(pci, PciPCR, r); /* * Treat the found device as an ordinary PCI card. * It seems that the CIS is not always present in * CardBus cards. * XXX, need to support multifunction cards */ for(i = 0; i < Nbars; i++) { if(pci->mem[i].size == 0) continue; bar = pci->mem[i].bar; if(bar & 1) bar += iobase; else bar += membase; pci->mem[i].bar = bar; pcicfgw32(pci, PciBAR0 + 4*i, bar); if((bar & 1) == 0){ print("%T mem[%d] %8.8lux %d\n", pci->tbdf, i, bar, pci->mem[i].size); if(bar & 0x80){ /* TO DO: enable prefetch */ ; } } } if((size = pcibarsize(pci, PciEBAR0)) > 0) { /* TO DO: can this be done by pci.c? */ pci->rom.bar = rombase; pci->rom.size = size; rombase += size; pcicfgw32(pci, PciEBAR0, pci->rom.bar); } /* Set the basic PCI registers for the device */ pci->pcr = pcicfgr16(pci, PciPCR); pci->pcr |= PciPCR_IO|PciPCR_MEM|PciPCR_Master; pci->cls = 8; pci->ltr = 64; pcicfgw16(pci, PciPCR, pci->pcr); pcicfgw8(pci, PciCLS, pci->cls); pcicfgw8(pci, PciLTR, pci->ltr); if (pcicfgr8(pci, PciINTP)) { pci->intl = pcicfgr8(cb->pci, PciINTL); pcicfgw8(pci, PciINTL, pci->intl); /* Route interrupts to INTA#/B# */ pcicfgw16(cb->pci, PciBCR, pcicfgr16(cb->pci, PciBCR) & ~(1 << 7)); } }}static voidunconfigure(Cardbus *cb){ Pcidev *pci; int i, ioindex, memindex, r; if (cb->type == PC16) { print("#Y%d: Don't know how to unconfigure a PC16 card\n", (int)(cb - cbslots)); memset(&cb->linfo, 0, sizeof(Pcminfo)); return; } pci = cb->pci->bridge; if (pci == nil) return; /* Not configured */ cb->pci->bridge = nil; memindex = ioindex = 0; while (pci) { Pcidev *_pci; for (i = 0; i != Nbars; i++) { if (pci->mem[i].size == 0) continue; if (pci->mem[i].bar & 1) { iofree(pci->mem[i].bar & ~1); pcicfgw16(cb->pci, PciCBIBR0 + ioindex * 8, (ushort)-1); pcicfgw16(cb->pci, PciCBILR0 + ioindex * 8, 0); ioindex++; continue; } upafree(pci->mem[i].bar & ~0xF, pci->mem[i].size); pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1); pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0); r = pcicfgr16(cb->pci, PciBCR); r &= ~(1 << (8 + memindex)); pcicfgw16(cb->pci, PciBCR, r); memindex++; } if (pci->rom.bar && memindex < 2) { upafree(pci->rom.bar & ~0xF, pci->rom.size); pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1); pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0); memindex++; } _pci = pci->list; free(_pci); pci = _pci; }}static voidi82365configure(Cardbus *cb){ int this; Cisdat cis; PCMmap *m; uchar type, link; /* * Read all tuples in attribute space. */ m = isamap(cb, 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 0x15: tvers1(cb, &cis, type); break; case 0x1A: tcfig(cb, &cis, type); break; case 0x1B: tentry(cb, &cis, type); break; } if(link == 0xFF) break; cis.cispos = this + (2+link); } isaunmap(m);}/* * look for a card whose version contains 'idstr' */static intpccard_pcmspecial(char *idstr, ISAConf *isa){ int i, irq; PCMconftab *ct, *et; Pcminfo *pi; Cardbus *cb; uchar x, we, *p; cb = nil; for (i = 0; i != nslots; i++) { cb = &cbslots[i]; lock(cb); if (cb->state == SlotConfigured && cb->type == PC16 && !cb->special && strstr(cb->linfo.verstr, idstr)) break; unlock(cb); } if (i == nslots) { //if(DEBUG) // print("#Y: %s not found\n", idstr); return -1; } pi = &cb->linfo; /* * 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. */ irq = isa->irq; if(irq == 2) irq = 9; et = &pi->ctab[pi->nctab]; ct = nil; for(i = 0; i < isa->nopt; i++){ int index; char *cp; if(strncmp(isa->opt[i], "index=", 6)) continue; index = strtol(&isa->opt[i][6], &cp, 0); if(cp == &isa->opt[i][6] || index >= pi->nctab) { unlock(cb); print("#Y%d: Cannot find index %d in conf table\n", (int)(cb - cbslots), index); return -1; } ct = &pi->ctab[index]; } if(ct == nil){ PCMconftab *t; /* assume default is right */ if(pi->defctab) ct = pi->defctab; else ct = pi->ctab; /* try for best match */ if(ct->nio == 0 || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){ for(t = pi->ctab; t < et; t++) if(t->nio && t->io[0].start == isa->port && ((1<<irq) & t->irqs)){ ct = t; break; } } if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){ for(t = pi->ctab; t < et; t++) if(t->nio && ((1<<irq) & t->irqs)){ ct = t; break; } } if(ct->nio == 0){ for(t = pi->ctab; t < et; t++) if(t->nio){ ct = t; break; } } } if(ct == et || ct->nio == 0) { unlock(cb); print("#Y%d: No configuration?\n", (int)(cb - cbslots)); return -1; } if(isa->port == 0 && ct->io[0].start == 0) { unlock(cb); print("#Y%d: No part or start address\n", (int)(cb - cbslots)); return -1; } cb->special = 1; /* taken */ /* route interrupts */ isa->irq = irq; wrreg(cb, Rigc, irq | Fnotreset | Fiocard); /* set power and enable device */ x = vcode(ct->vpp1); wrreg(cb, Rpc, x|Fautopower|Foutena|Fcardena); /* 16-bit data path */ if(ct->bit16) x = Ftiming|Fiocs16|Fwidth16; else x = Ftiming; if(ct->nio == 2 && ct->io[1].start) x |= x<<4; wrreg(cb, Rio, x); /* * 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(cb, Rwe); wrreg(cb, Riobtm0lo, isa->port); wrreg(cb, Riobtm0hi, isa->port>>8); i = isa->port+ct->io[0].len-1; wrreg(cb, Riotop0lo, i); wrreg(cb, Riotop0hi, i>>8); we |= 1<<6; if(ct->nio == 2 && ct->io[1].start){ wrreg(cb, Riobtm1lo, ct->io[1].start); wrreg(cb, Riobtm1hi, ct->io[1].start>>8); i = ct->io[1].start+ct->io[1].len-1; wrreg(cb, Riotop1lo, i); wrreg(cb, Riotop1hi, i>>8); we |= 1<<7; } wrreg(cb, Rwe, we); /* only touch Rconfig if it is present */ if(pi->conf_present & (1<<Rconfig)){ PCMmap *m; /* Reset adapter */ m = isamap(cb, pi->conf_addr + Rconfig, 1, 1); p = KADDR(m->isa + pi->conf_addr + Rconfig - m->ca); /* set configuration and interrupt type */ x = ct->index; if(ct->irqtype & 0x20) x |= Clevel; *p = x; delay(5); isaunmap(m); } pi->port = isa->port; pi->irq = isa->irq; unlock(cb); print("#Y%ld: %s irq %d, port %lX\n", cb - cbslots, pi->verstr, isa->irq, isa->port); return (int)(cb - cbslots);}static voidpccard_pcmspecialclose(int slotno){ Cardbus *cb = &cbslots[slotno]; wrreg(cb, Rwe, 0); /* no windows */ cb->special = 0;}static Chan*pccardattach(char *spec){ if (!managerstarted) { managerstarted = 1; kproc("cardbus", processevents, nil); } return devattach('Y', spec);}enum{ Qdir, Qctl, Nents = 1,};#define SLOTNO(c) ((ulong)((c->qid.path>>8)&0xff))#define TYPE(c) ((ulong)(c->qid.path&0xff))#define QID(s,t) (((s)<<8)|(t))static intpccardgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp){ int slotno; Qid qid; long len; int entry; if(i == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#Y", 0, eve, 0555, dp); return 1; } len = 0; if(i >= Nents * nslots) return -1; slotno = i / Nents; entry = i % Nents; if (entry == 0) { qid.path = QID(slotno, Qctl); snprint(up->genbuf, sizeof up->genbuf, "cb%dctl", slotno); } else { /* Entries for memory regions. I'll implement them when needed. (pb) */ } qid.vers = 0; qid.type = QTFILE; devdir(c, qid, up->genbuf, len, eve, 0660, dp); return 1;}static Walkqid*pccardwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, pccardgen);}static intpccardstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, pccardgen);}static voidincrefp(Cardbus *cb){ lock(&cb->refslock); cb->refs++; unlock(&cb->refslock);}static voiddecrefp(Cardbus *cb){ lock(&cb->refslock); cb->refs--; unlock(&cb->refslock);}static Chan*pccardopen(Chan *c, int omode){ if (c->qid.type & QTDIR){ if(omode != OREAD) error(Eperm); } else increfp(&cbslots[SLOTNO(c)]); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;}static voidpccardclose(Chan *c){ if(c->flag & COPEN) if((c->qid.type & QTDIR) == 0) decrefp(&cbslots[SLOTNO(c)]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -