1 /* $NetBSD: if_ne_pcmcia.c,v 1.5 1997/11/02 00:27:21 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Marc Horowitz. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/select.h> 35 #include <sys/device.h> 36 #include <sys/socket.h> 37 38 #include <net/if_types.h> 39 #include <net/if.h> 40 #include <net/if_media.h> 41 #include <net/if_ether.h> 42 43 #include <machine/bus.h> 44 #include <machine/intr.h> 45 46 #include <dev/pcmcia/pcmciareg.h> 47 #include <dev/pcmcia/pcmciavar.h> 48 49 #include <dev/ic/dp8390reg.h> 50 #include <dev/ic/dp8390var.h> 51 52 #include <dev/ic/ne2000reg.h> 53 #include <dev/ic/ne2000var.h> 54 55 #ifdef __BROKEN_INDIRECT_CONFIG 56 int ne_pcmcia_match __P((struct device *, void *, void *)); 57 #else 58 int ne_pcmcia_match __P((struct device *, struct cfdata *, void *)); 59 #endif 60 void ne_pcmcia_attach __P((struct device *, struct device *, void *)); 61 62 int ne_pcmcia_enable __P((struct dp8390_softc *)); 63 void ne_pcmcia_disable __P((struct dp8390_softc *)); 64 65 struct ne_pcmcia_softc { 66 struct ne2000_softc sc_ne2000; /* real "ne2000" softc */ 67 68 /* PCMCIA-specific goo */ 69 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o information */ 70 int sc_asic_io_window; /* i/o window for ASIC */ 71 int sc_nic_io_window; /* i/o window for NIC */ 72 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 73 void *sc_ih; /* interrupt handle */ 74 }; 75 76 struct cfattach ne_pcmcia_ca = { 77 sizeof(struct ne_pcmcia_softc), ne_pcmcia_match, ne_pcmcia_attach 78 }; 79 80 struct ne2000dev { 81 char *name; 82 int32_t manufacturer; 83 int32_t product; 84 char *cis1_info0; 85 char *cis1_info1; 86 int function; 87 int enet_maddr; 88 unsigned char enet_vendor[3]; 89 } ne2000devs[] = { 90 { "PreMax PE-200", 91 0xffff, 0xffff, "PMX ", "PE-200", 0, 92 0x07f0, { 0x00, 0x20, 0xe0 } }, 93 { "National Semiconductor InfoMover", 94 0x00a4, 0x0002, NULL, NULL, 0, 95 0x0ff0, { 0x08, 0x00, 0x5a } }, 96 { "DEC DEPCM-BA", 97 0x0000, 0x0000, "DIGITAL", "DEPCM-XX", 0, 98 0x0ff0, { 0x00, 0x00, 0xe8 } }, 99 /* this card might need pcic_alloc_iobase < 0x400, and/or 100 CIRRUS_PD672X on TI TravelMate 5000 needs it: */ 101 { "Linksys EthernetCard", 102 0x0149, 0x0265, "LINKSYS", "E-CARD", 103 0, -1, { 0x00, 0x80, 0xc8 } }, 104 { "Planet SmartCOM 2000", 105 /* This card doesn't have manufacturer and product id in CIS. */ 106 PCMCIA_MANUFACTURER_INVALID, PCMCIA_PRODUCT_INVALID, 107 "PCMCIA", "UE2212", 0, 108 0xff0, { 0x00, 0x00, 0xe8 } }, 109 #if 0 110 /* the rest of these are stolen from the linux pcnet pcmcia device 111 driver. Since I don't know the manfid or cis info strings for 112 any of them, they're not compiled in until I do. */ 113 114 { "Accton EN2212", 115 0x0000, 0x0000, NULL, NULL, 0, 116 0x0ff0, { 0x00, 0x00, 0xe8 } }, 117 { "Allied Telesis LA-PCM", 118 0x0000, 0x0000, NULL, NULL, 0, 119 0x0ff0, { 0x00, 0x00, 0xf4 } }, 120 { "APEX MultiCard", 121 0x0000, 0x0000, NULL, NULL, 0, 122 0x03f4, { 0x00, 0x20, 0xe5 } }, 123 { "ASANTE FriendlyNet", 124 0x0000, 0x0000, NULL, NULL, 0, 125 0x4910, { 0x00, 0x00, 0x94 } }, 126 { "Danpex EN-6200P2", 127 0x0000, 0x0000, NULL, NULL, 0, 128 0x0110, { 0x00, 0x40, 0xc7 } }, 129 { "DataTrek NetCard", 130 0x0000, 0x0000, NULL, NULL, 0, 131 0x0ff0, { 0x00, 0x20, 0xe8 } }, 132 { "Dayna CommuniCard E", 133 0x0000, 0x0000, NULL, NULL, 0, 134 0x0110, { 0x00, 0x80, 0x19 } }, 135 { "D-Link DE-650", 136 0x0000, 0x0000, NULL, NULL, 0, 137 0x0040, { 0x00, 0x80, 0xc8 } }, 138 { "EP-210 Ethernet", 139 0x0000, 0x0000, NULL, NULL, 0, 140 0x0110, { 0x00, 0x40, 0x33 } }, 141 { "Epson EEN10B", 142 0x0000, 0x0000, NULL, NULL, 0, 143 0x0ff0, { 0x00, 0x00, 0x48 } }, 144 { "ELECOM Laneed LD-CDWA", 145 0x0000, 0x0000, NULL, NULL, 0, 146 0x00b8, { 0x08, 0x00, 0x42 } }, 147 { "Grey Cell GCS2220", 148 0x0000, 0x0000, NULL, NULL, 0, 149 0x0000, { 0x00, 0x47, 0x43 } }, 150 { "Hypertec Ethernet", 151 0x0000, 0x0000, NULL, NULL, 0, 152 0x01c0, { 0x00, 0x40, 0x4c } }, 153 { "IBM CCAE", 154 0x0000, 0x0000, NULL, NULL, 0, 155 0x0ff0, { 0x08, 0x00, 0x5a } }, 156 { "IBM CCAE", 157 0x0000, 0x0000, NULL, NULL, 0, 158 0x0ff0, { 0x00, 0x04, 0xac } }, 159 { "IBM CCAE", 160 0x0000, 0x0000, NULL, NULL, 0, 161 0x0ff0, { 0x00, 0x06, 0x29 } }, 162 { "IBM FME", 163 0x0000, 0x0000, NULL, NULL, 0, 164 0x0374, { 0x00, 0x04, 0xac } }, 165 { "IBM FME", 166 0x0000, 0x0000, NULL, NULL, 0, 167 0x0374, { 0x08, 0x00, 0x5a } }, 168 { "I-O DATA PCLA/T", 169 0x0000, 0x0000, NULL, NULL, 0, 170 0x0ff0, { 0x00, 0xa0, 0xb0 } }, 171 { "Katron PE-520", 172 0x0000, 0x0000, NULL, NULL, 0, 173 0x0110, { 0x00, 0x40, 0xf6 } }, 174 { "Kingston KNE-PCM/x", 175 0x0000, 0x0000, NULL, NULL, 0, 176 0x0ff0, { 0x00, 0xc0, 0xf0 } }, 177 { "Kingston KNE-PCM/x", 178 0x0000, 0x0000, NULL, NULL, 0, 179 0x0ff0, { 0xe2, 0x0c, 0x0f } }, 180 { "Kingston KNE-PC2", 181 0x0000, 0x0000, NULL, NULL, 0, 182 0x0180, { 0x00, 0xc0, 0xf0 } }, 183 { "Longshine LCS-8534", 184 0x0000, 0x0000, NULL, NULL, 0, 185 0x0000, { 0x08, 0x00, 0x00 } }, 186 { "Maxtech PCN2000", 187 0x0000, 0x0000, NULL, NULL, 0, 188 0x5000, { 0x00, 0x00, 0xe8 } }, 189 { "NDC Instant-Link", 190 0x0000, 0x0000, NULL, NULL, 0, 191 0x003a, { 0x00, 0x80, 0xc6 } }, 192 { "NE2000 Compatible", 193 0x0000, 0x0000, NULL, NULL, 0, 194 0x0ff0, { 0x00, 0xa0, 0x0c } }, 195 { "Network General Sniffer", 196 0x0000, 0x0000, NULL, NULL, 0, 197 0x0ff0, { 0x00, 0x00, 0x65 } }, 198 { "Panasonic VEL211", 199 0x0000, 0x0000, NULL, NULL, 0, 200 0x0ff0, { 0x00, 0x80, 0x45 } }, 201 { "RPTI EP400", 202 0x0000, 0x0000, NULL, NULL, 0, 203 0x0110, { 0x00, 0x40, 0x95 } }, 204 { "SCM Ethernet", 205 0x0000, 0x0000, NULL, NULL, 0, 206 0x0ff0, { 0x00, 0x20, 0xcb } }, 207 { "Socket EA", 208 0x0000, 0x0000, NULL, NULL, 0, 209 0x4000, { 0x00, 0xc0, 0x1b } }, 210 { "Volktek NPL-402CT", 211 0x0000, 0x0000, NULL, NULL, 0, 212 0x0060, { 0x00, 0x40, 0x05 } }, 213 #endif 214 }; 215 216 #define NE2000_NDEVS (sizeof(ne2000devs) / sizeof(ne2000devs[0])) 217 218 #define ne2000_match(card, fct, n) \ 219 ((((((card)->manufacturer != PCMCIA_MANUFACTURER_INVALID) && \ 220 ((card)->manufacturer == ne2000devs[(n)].manufacturer) && \ 221 ((card)->product != PCMCIA_PRODUCT_INVALID) && \ 222 ((card)->product == ne2000devs[(n)].product)) || \ 223 ((ne2000devs[(n)].cis1_info0) && (ne2000devs[(n)].cis1_info1) && \ 224 (strcmp((card)->cis1_info[0], ne2000devs[(n)].cis1_info0) == 0) && \ 225 (strcmp((card)->cis1_info[1], ne2000devs[(n)].cis1_info1) == 0))) && \ 226 ((fct) == ne2000devs[(n)].function))? \ 227 &ne2000devs[(n)]:NULL) 228 229 int 230 ne_pcmcia_match(parent, match, aux) 231 struct device *parent; 232 #ifdef __BROKEN_INDIRECT_CONFIG 233 void *match; 234 #else 235 struct cfdata *cf; 236 #endif 237 void *aux; 238 { 239 struct pcmcia_attach_args *pa = aux; 240 int i; 241 242 for (i = 0; i < NE2000_NDEVS; i++) { 243 if (ne2000_match(pa->card, pa->pf->number, i)) 244 return (1); 245 } 246 247 return (0); 248 } 249 250 void 251 ne_pcmcia_attach(parent, self, aux) 252 struct device *parent, *self; 253 void *aux; 254 { 255 struct ne_pcmcia_softc *psc = (void *) self; 256 struct ne2000_softc *nsc = &psc->sc_ne2000; 257 struct dp8390_softc *dsc = &nsc->sc_dp8390; 258 struct pcmcia_attach_args *pa = aux; 259 struct pcmcia_config_entry *cfe; 260 struct ne2000dev *ne_dev; 261 struct pcmcia_mem_handle pcmh; 262 bus_addr_t offset; 263 int i, j, mwindow; 264 u_int8_t myea[6], *enaddr = NULL; 265 266 psc->sc_pf = pa->pf; 267 cfe = pa->pf->cfe_head.sqh_first; 268 269 #if 0 270 /* 271 * Some ne2000 driver's claim to have memory; others don't. 272 * Since I don't care, I don't check. 273 */ 274 275 if (cfe->num_memspace != 1) { 276 printf(": unexpected number of memory spaces " 277 " %d should be 1\n", cfe->num_memspace); 278 return; 279 } 280 #endif 281 282 if (cfe->num_iospace == 1) { 283 if (cfe->iospace[0].length != NE2000_NPORTS) { 284 printf(": unexpected I/O space configuration\n"); 285 return; 286 } 287 } else if (cfe->num_iospace == 2) { 288 /* 289 * Some cards report a separate space for NIC and ASIC. 290 * This make some sense, but we must allocate a single 291 * NE2000_NPORTS-sized chunk, due to brain damaged 292 * address decoders on some of these cards. 293 */ 294 if ((cfe->iospace[0].length + cfe->iospace[1].length) != 295 NE2000_NPORTS) { 296 printf(": unexpected I/O space configuration\n"); 297 return; 298 } 299 } else { 300 printf(": unexpected number of i/o spaces %d" 301 " should be 1 or 2\n", cfe->num_iospace); 302 } 303 304 if (pcmcia_io_alloc(pa->pf, 0, NE2000_NPORTS, NE2000_NPORTS, 305 &psc->sc_pcioh)) { 306 printf(": can't alloc i/o space\n"); 307 return; 308 } 309 310 dsc->sc_regt = psc->sc_pcioh.iot; 311 dsc->sc_regh = psc->sc_pcioh.ioh; 312 313 nsc->sc_asict = psc->sc_pcioh.iot; 314 if (bus_space_subregion(dsc->sc_regt, dsc->sc_regh, 315 NE2000_ASIC_OFFSET, NE2000_ASIC_NPORTS, 316 &nsc->sc_asich)) { 317 printf(": can't get subregion for asic\n"); 318 return; 319 } 320 321 /* Set up power management hooks. */ 322 dsc->sc_enable = ne_pcmcia_enable; 323 dsc->sc_disable = ne_pcmcia_disable; 324 325 /* Enable the card. */ 326 pcmcia_function_init(pa->pf, cfe); 327 if (pcmcia_function_enable(pa->pf)) { 328 printf(": function enable failed\n"); 329 return; 330 } 331 332 /* some cards claim to be io16, but they're lying. */ 333 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO8, 334 NE2000_NIC_OFFSET, NE2000_NIC_NPORTS, 335 &psc->sc_pcioh, &psc->sc_nic_io_window)) { 336 printf(": can't map NIC i/o space\n"); 337 return; 338 } 339 340 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO16, 341 NE2000_ASIC_OFFSET, NE2000_ASIC_NPORTS, 342 &psc->sc_pcioh, &psc->sc_asic_io_window)) { 343 printf(": can't map ASIC i/o space\n"); 344 return; 345 } 346 347 printf("\n"); 348 349 /* 350 * Read the station address from the board. 351 */ 352 for (i = 0; i < NE2000_NDEVS; i++) { 353 if ((ne_dev = ne2000_match(pa->card, pa->pf->number, i)) 354 != NULL) { 355 if (ne_dev->enet_maddr >= 0) { 356 if (pcmcia_mem_alloc(pa->pf, 357 ETHER_ADDR_LEN * 2, &pcmh)) { 358 printf("%s: can't alloc mem for" 359 " enet addr\n", 360 dsc->sc_dev.dv_xname); 361 return; 362 } 363 if (pcmcia_mem_map(pa->pf, PCMCIA_MEM_ATTR, 364 ne_dev->enet_maddr, ETHER_ADDR_LEN * 2, 365 &pcmh, &offset, &mwindow)) { 366 printf("%s: can't map mem for" 367 " enet addr\n", 368 dsc->sc_dev.dv_xname); 369 return; 370 } 371 for (j = 0; j < ETHER_ADDR_LEN; j++) 372 myea[j] = bus_space_read_1(pcmh.memt, 373 pcmh.memh, offset + (j * 2)); 374 pcmcia_mem_unmap(pa->pf, mwindow); 375 pcmcia_mem_free(pa->pf, &pcmh); 376 enaddr = myea; 377 } 378 break; 379 } 380 } 381 382 if (enaddr != NULL) { 383 /* 384 * Make sure this is what we expect. 385 */ 386 if (enaddr[0] != ne_dev->enet_vendor[0] || 387 enaddr[1] != ne_dev->enet_vendor[1] || 388 enaddr[2] != ne_dev->enet_vendor[2]) { 389 printf("\n%s: enet addr has incorrect vendor code\n", 390 dsc->sc_dev.dv_xname); 391 printf("%s: (%02x:%02x:%02x should be " 392 "%02x:%02x:%02x)\n", dsc->sc_dev.dv_xname, 393 enaddr[0], enaddr[1], enaddr[2], 394 ne_dev->enet_vendor[0], 395 ne_dev->enet_vendor[1], 396 ne_dev->enet_vendor[2]); 397 return; 398 } 399 } 400 401 printf("%s: %s Ethernet\n", dsc->sc_dev.dv_xname, ne_dev->name); 402 403 ne2000_attach(nsc, enaddr); 404 405 pcmcia_function_disable(pa->pf); 406 } 407 408 int 409 ne_pcmcia_enable(dsc) 410 struct dp8390_softc *dsc; 411 { 412 struct ne_pcmcia_softc *psc = (struct ne_pcmcia_softc *)dsc; 413 414 /* set up the interrupt */ 415 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, dp8390_intr, 416 dsc); 417 if (psc->sc_ih == NULL) { 418 printf("%s: couldn't establish interrupt\n", 419 dsc->sc_dev.dv_xname); 420 return (1); 421 } 422 423 return (pcmcia_function_enable(psc->sc_pf)); 424 } 425 426 void 427 ne_pcmcia_disable(dsc) 428 struct dp8390_softc *dsc; 429 { 430 struct ne_pcmcia_softc *psc = (struct ne_pcmcia_softc *)dsc; 431 432 pcmcia_function_disable(psc->sc_pf); 433 434 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 435 } 436