1 /* Pci/pcmcia code for wavelan.c */ 2 3 #include "u.h" 4 #include "../port/lib.h" 5 #include "mem.h" 6 #include "dat.h" 7 #include "fns.h" 8 #include "io.h" 9 #include "../port/error.h" 10 #include "../port/netif.h" 11 #include "etherif.h" 12 13 #include "wavelan.h" 14 15 static int 16 wavelanpcmciareset(Ether *ether) 17 { 18 int i; 19 char *p; 20 Ctlr *ctlr; 21 22 if((ctlr = malloc(sizeof(Ctlr))) == nil) 23 return -1; 24 25 ilock(ctlr); 26 ctlr->ctlrno = ether->ctlrno; 27 28 if (ether->port==0) 29 ether->port=WDfltIOB; 30 ctlr->iob = ether->port; 31 32 if (ether->irq==0) 33 ether->irq=WDfltIRQ; 34 35 if (ioalloc(ether->port,WIOLen,0,"wavelan")<0){ 36 // print("#l%d: port 0x%lx in use\n", 37 // ether->ctlrno, ether->port); 38 goto abort1; 39 } 40 41 /* 42 * If id= is specified, card must match. Otherwise try generic. 43 */ 44 ctlr->slot = -1; 45 for(i=0; i<ether->nopt; i++){ 46 if(cistrncmp(ether->opt[i], "id=", 3) == 0){ 47 if((ctlr->slot = pcmspecial(ðer->opt[i][3], ether)) < 0) 48 goto abort; 49 break; 50 } 51 } 52 if(ctlr->slot == -1){ 53 for (i=0; wavenames[i]; i++) 54 if((ctlr->slot = pcmspecial(wavenames[i], ether))>=0) 55 break; 56 if(!wavenames[i]){ 57 DEBUG("no wavelan found\n"); 58 goto abort; 59 } 60 } 61 62 // DEBUG("#l%d: port=0x%lx irq=%ld\n", 63 // ether->ctlrno, ether->port, ether->irq); 64 65 if(wavelanreset(ether, ctlr) < 0){ 66 abort: 67 iofree(ether->port); 68 abort1: 69 iunlock(ctlr); 70 free(ctlr); 71 ether->ctlr = nil; 72 return -1; 73 } 74 75 for(i = 0; i < ether->nopt; i++){ 76 if(p = strchr(ether->opt[i], '=')) 77 *p = ' '; 78 w_option(ctlr, ether->opt[i], strlen(ether->opt[i])); 79 } 80 81 iunlock(ctlr); 82 return 0; 83 } 84 85 static struct { 86 int vid; 87 int did; 88 } wavelanpci[] = { 89 0x1260, 0x3873, /* Intersil Prism2.5 */ 90 0x1737, 0x0019, /* Linksys WPC-11 untested */ 91 }; 92 93 static Ctlr *ctlrhead, *ctlrtail; 94 95 static void 96 wavelanpciscan(void) 97 { 98 int i; 99 void *mem; 100 Pcidev *p; 101 Ctlr *ctlr; 102 103 p = nil; 104 while(p = pcimatch(p, 0, 0)){ 105 for(i=0; i<nelem(wavelanpci); i++) 106 if(p->vid == wavelanpci[i].vid && p->did == wavelanpci[i].did) 107 break; 108 if(i==nelem(wavelanpci)) 109 continue; 110 111 /* 112 * On the Prism, bar[0] is the memory-mapped register address (4KB), 113 */ 114 if(p->mem[0].size != 4096){ 115 print("wavelanpci: %.4ux %.4ux: unlikely mmio size\n", p->vid, p->did); 116 continue; 117 } 118 119 ctlr = malloc(sizeof(Ctlr)); 120 ctlr->pcidev = p; 121 mem = vmap(p->mem[0].bar&~0xF, p->mem[0].size); 122 if(mem == nil){ 123 print("wavelanpci: %.4ux %.4ux: vmap 0x%.8lux %d failed\n", p->vid, p->did, p->mem[0].bar&~0xF, p->mem[0].size); 124 free(ctlr); 125 continue; 126 } 127 ctlr->mmb = mem; 128 if(ctlrhead != nil) 129 ctlrtail->next = ctlr; 130 else 131 ctlrhead = ctlr; 132 ctlrtail = ctlr; 133 pcisetbme(p); 134 } 135 } 136 137 static int 138 wavelanpcireset(Ether *ether) 139 { 140 int i; 141 char *p; 142 Ctlr *ctlr; 143 144 if(ctlrhead == nil) 145 wavelanpciscan(); 146 147 /* 148 * Allow plan9.ini to set vid, did? 149 */ 150 for(ctlr=ctlrhead; ctlr!=nil; ctlr=ctlr->next) 151 if(ctlr->active == 0) 152 break; 153 if(ctlr == nil) 154 return -1; 155 156 ctlr->active = 1; 157 ilock(ctlr); 158 ether->irq = ctlr->pcidev->intl; 159 ether->tbdf = ctlr->pcidev->tbdf; 160 161 /* 162 * Really hard reset. 163 */ 164 csr_outs(ctlr, WR_PciCor, 0x0080); 165 delay(250); 166 csr_outs(ctlr, WR_PciCor, 0x0000); 167 delay(500); 168 for(i=0; i<2*10; i++){ 169 if(!(csr_ins(ctlr, WR_Cmd)&WCmdBusy)) 170 break; 171 delay(100); 172 } 173 if(i >= 2*10) 174 print("wavelan pci %.4ux %.4ux: reset timeout %.4ux\n", 175 ctlr->pcidev->vid, ctlr->pcidev->did, csr_ins(ctlr, WR_Cmd)); 176 177 if(wavelanreset(ether, ctlr) < 0){ 178 iunlock(ctlr); 179 ether->ctlr = nil; 180 return -1; 181 } 182 183 for(i = 0; i < ether->nopt; i++){ 184 if(p = strchr(ether->opt[i], '=')) 185 *p = ' '; 186 w_option(ctlr, ether->opt[i], strlen(ether->opt[i])); 187 } 188 iunlock(ctlr); 189 return 0; 190 } 191 192 void 193 etherwavelanlink(void) 194 { 195 addethercard("wavelan", wavelanpcmciareset); 196 addethercard("wavelanpci", wavelanpcireset); 197 } 198