diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/etherwavelan.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/etherwavelan.c')
-rwxr-xr-x | sys/src/9/pc/etherwavelan.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/sys/src/9/pc/etherwavelan.c b/sys/src/9/pc/etherwavelan.c new file mode 100755 index 000000000..e76905b52 --- /dev/null +++ b/sys/src/9/pc/etherwavelan.c @@ -0,0 +1,197 @@ +/* Pci/pcmcia code for wavelan.c */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "../port/netif.h" +#include "etherif.h" + +#include "wavelan.h" + +static int +wavelanpcmciareset(Ether *ether) +{ + int i; + char *p; + Ctlr *ctlr; + + if((ctlr = malloc(sizeof(Ctlr))) == nil) + return -1; + + ilock(ctlr); + ctlr->ctlrno = ether->ctlrno; + + if (ether->port==0) + ether->port=WDfltIOB; + ctlr->iob = ether->port; + + if (ether->irq==0) + ether->irq=WDfltIRQ; + + if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){ + // print("#l%d: port 0x%lx in use\n", + // ether->ctlrno, ether->port); + goto abort1; + } + + /* + * If id= is specified, card must match. Otherwise try generic. + */ + ctlr->slot = -1; + for(i=0; i<ether->nopt; i++){ + if(cistrncmp(ether->opt[i], "id=", 3) == 0){ + if((ctlr->slot = pcmspecial(ðer->opt[i][3], ether)) < 0) + goto abort; + break; + } + } + if(ctlr->slot == -1){ + for (i=0; wavenames[i]; i++) + if((ctlr->slot = pcmspecial(wavenames[i], ether))>=0) + break; + if(!wavenames[i]){ + DEBUG("no wavelan found\n"); + goto abort; + } + } + + // DEBUG("#l%d: port=0x%lx irq=%ld\n", + // ether->ctlrno, ether->port, ether->irq); + + if(wavelanreset(ether, ctlr) < 0){ + abort: + iofree(ether->port); + abort1: + iunlock(ctlr); + free(ctlr); + ether->ctlr = nil; + return -1; + } + + for(i = 0; i < ether->nopt; i++){ + if(p = strchr(ether->opt[i], '=')) + *p = ' '; + w_option(ctlr, ether->opt[i], strlen(ether->opt[i])); + } + + iunlock(ctlr); + return 0; +} + +static struct { + int vid; + int did; +} wavelanpci[] = { + 0x1260, 0x3873, /* Intersil Prism2.5 */ + 0x1737, 0x0019, /* Linksys WPC-11 untested */ +}; + +static Ctlr *ctlrhead, *ctlrtail; + +static void +wavelanpciscan(void) +{ + int i; + void *mem; + Pcidev *p; + Ctlr *ctlr; + + p = nil; + while(p = pcimatch(p, 0, 0)){ + for(i=0; i<nelem(wavelanpci); i++) + if(p->vid == wavelanpci[i].vid && p->did == wavelanpci[i].did) + break; + if(i==nelem(wavelanpci)) + continue; + + /* + * On the Prism, bar[0] is the memory-mapped register address (4KB), + */ + if(p->mem[0].size != 4096){ + print("wavelanpci: %.4ux %.4ux: unlikely mmio size\n", p->vid, p->did); + continue; + } + + ctlr = malloc(sizeof(Ctlr)); + ctlr->pcidev = p; + mem = vmap(p->mem[0].bar&~0xF, p->mem[0].size); + if(mem == nil){ + print("wavelanpci: %.4ux %.4ux: vmap 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size); + free(ctlr); + continue; + } + ctlr->mmb = mem; + if(ctlrhead != nil) + ctlrtail->next = ctlr; + else + ctlrhead = ctlr; + ctlrtail = ctlr; + pcisetbme(p); + } +} + +static int +wavelanpcireset(Ether *ether) +{ + int i; + char *p; + Ctlr *ctlr; + + if(ctlrhead == nil) + wavelanpciscan(); + + /* + * Allow plan9.ini to set vid, did? + */ + for(ctlr=ctlrhead; ctlr!=nil; ctlr=ctlr->next) + if(ctlr->active == 0) + break; + if(ctlr == nil) + return -1; + + ctlr->active = 1; + ilock(ctlr); + ether->irq = ctlr->pcidev->intl; + ether->tbdf = ctlr->pcidev->tbdf; + + /* + * Really hard reset. + */ + csr_outs(ctlr, WR_PciCor, 0x0080); + delay(250); + csr_outs(ctlr, WR_PciCor, 0x0000); + delay(500); + for(i=0; i<2*10; i++){ + if(!(csr_ins(ctlr, WR_Cmd)&WCmdBusy)) + break; + delay(100); + } + if(i >= 2*10) + print("wavelan pci %.4ux %.4ux: reset timeout %.4ux\n", + ctlr->pcidev->vid, ctlr->pcidev->did, csr_ins(ctlr, WR_Cmd)); + + if(wavelanreset(ether, ctlr) < 0){ + iunlock(ctlr); + ether->ctlr = nil; + return -1; + } + + for(i = 0; i < ether->nopt; i++){ + if(p = strchr(ether->opt[i], '=')) + *p = ' '; + w_option(ctlr, ether->opt[i], strlen(ether->opt[i])); + } + iunlock(ctlr); + return 0; +} + +void +etherwavelanlink(void) +{ + addethercard("wavelan", wavelanpcmciareset); + addethercard("wavelanpci", wavelanpcireset); +} |