1 /* $OpenBSD: if_ep_pcmcia.c,v 1.30 2003/07/08 20:17:05 mickey Exp $ */ 2 /* $NetBSD: if_ep_pcmcia.c,v 1.16 1998/08/17 23:20:40 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by Marc Horowitz. 55 * 4. The name of the author may not be used to endorse or promote products 56 * derived from this software without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 59 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 61 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 62 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 63 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 64 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 65 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 66 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 67 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 */ 69 70 #include "bpfilter.h" 71 72 #include <sys/param.h> 73 #include <sys/systm.h> 74 #include <sys/mbuf.h> 75 #include <sys/socket.h> 76 #include <sys/ioctl.h> 77 #include <sys/errno.h> 78 #include <sys/syslog.h> 79 #include <sys/select.h> 80 #include <sys/device.h> 81 82 #include <net/if.h> 83 #include <net/if_dl.h> 84 #include <net/if_types.h> 85 #include <net/netisr.h> 86 #include <net/if_media.h> 87 88 #ifdef INET 89 #include <netinet/in.h> 90 #include <netinet/in_systm.h> 91 #include <netinet/in_var.h> 92 #include <netinet/ip.h> 93 #include <netinet/if_ether.h> 94 #endif 95 96 #ifdef NS 97 #include <netns/ns.h> 98 #include <netns/ns_if.h> 99 #endif 100 101 #if NBPFILTER > 0 102 #include <net/bpf.h> 103 #include <net/bpfdesc.h> 104 #endif 105 106 #include <machine/cpu.h> 107 #include <machine/bus.h> 108 109 #include <dev/mii/mii.h> 110 #include <dev/mii/miivar.h> 111 112 #include <dev/ic/elink3var.h> 113 #include <dev/ic/elink3reg.h> 114 115 #include <dev/pcmcia/pcmciareg.h> 116 #include <dev/pcmcia/pcmciavar.h> 117 #include <dev/pcmcia/pcmciadevs.h> 118 119 int ep_pcmcia_match(struct device *, void *, void *); 120 void ep_pcmcia_attach(struct device *, struct device *, void *); 121 int ep_pcmcia_detach(struct device *, int); 122 int ep_pcmcia_activate(struct device *, enum devact); 123 124 int ep_pcmcia_get_enaddr(struct pcmcia_tuple *, void *); 125 int ep_pcmcia_enable(struct ep_softc *); 126 void ep_pcmcia_disable(struct ep_softc *); 127 128 int ep_pcmcia_enable1(struct ep_softc *); 129 void ep_pcmcia_disable1(struct ep_softc *); 130 131 struct ep_pcmcia_softc { 132 struct ep_softc sc_ep; /* real "ep" softc */ 133 134 /* PCMCIA-specific goo */ 135 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 136 int sc_io_window; /* our i/o window */ 137 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 138 }; 139 140 struct cfattach ep_pcmcia_ca = { 141 sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach, 142 ep_pcmcia_detach, ep_pcmcia_activate 143 }; 144 145 struct ep_pcmcia_product { 146 u_int16_t epp_product; /* PCMCIA product ID */ 147 u_short epp_chipset; /* 3Com chipset used */ 148 int epp_flags; /* initial softc flags */ 149 int epp_expfunc; /* expected function */ 150 } ep_pcmcia_prod[] = { 151 { PCMCIA_PRODUCT_3COM_3C562, EP_CHIPSET_3C509, 152 0, 0 }, 153 154 { PCMCIA_PRODUCT_3COM_3C589, EP_CHIPSET_3C509, 155 0, 0 }, 156 157 { PCMCIA_PRODUCT_3COM_3CXEM556, EP_CHIPSET_3C509, 158 0, 0 }, 159 160 { PCMCIA_PRODUCT_3COM_3CXEM556B,EP_CHIPSET_3C509, 161 0, 0 }, 162 163 { PCMCIA_PRODUCT_3COM_3C1, EP_CHIPSET_3C509, 164 0, 0 }, 165 166 { PCMCIA_PRODUCT_3COM_3CCFEM556BI, EP_CHIPSET_ROADRUNNER, 167 EP_FLAGS_MII, 0 }, 168 169 { PCMCIA_PRODUCT_3COM_3C574, EP_CHIPSET_ROADRUNNER, 170 EP_FLAGS_MII, 0 } 171 }; 172 173 struct ep_pcmcia_product *ep_pcmcia_lookup(struct pcmcia_attach_args *); 174 175 struct ep_pcmcia_product * 176 ep_pcmcia_lookup(pa) 177 struct pcmcia_attach_args *pa; 178 { 179 int i; 180 181 for (i = 0; i < sizeof(ep_pcmcia_prod)/sizeof(ep_pcmcia_prod[0]); i++) 182 if (pa->product == ep_pcmcia_prod[i].epp_product && 183 pa->pf->number == ep_pcmcia_prod[i].epp_expfunc) 184 return &ep_pcmcia_prod[i]; 185 186 return (NULL); 187 } 188 189 int 190 ep_pcmcia_match(parent, match, aux) 191 struct device *parent; 192 void *match, *aux; 193 { 194 struct pcmcia_attach_args *pa = aux; 195 196 if (pa->manufacturer != PCMCIA_VENDOR_3COM) 197 return (0); 198 199 if (ep_pcmcia_lookup(pa) != NULL) 200 return (1); 201 202 return (0); 203 } 204 205 int 206 ep_pcmcia_enable(sc) 207 struct ep_softc *sc; 208 { 209 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 210 struct pcmcia_function *pf = psc->sc_pf; 211 212 /* establish the interrupt. */ 213 sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr, 214 sc, sc->sc_dev.dv_xname); 215 if (sc->sc_ih == NULL) { 216 printf("%s: couldn't establish interrupt\n", 217 sc->sc_dev.dv_xname); 218 return (1); 219 } 220 221 return (ep_pcmcia_enable1(sc)); 222 } 223 224 int 225 ep_pcmcia_enable1(sc) 226 struct ep_softc *sc; 227 { 228 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 229 struct pcmcia_function *pf = psc->sc_pf; 230 int ret; 231 232 if ((ret = pcmcia_function_enable(pf))) 233 return (ret); 234 235 if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) || 236 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) || 237 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556B)) { 238 int reg; 239 240 /* turn off the serial-disable bit */ 241 242 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); 243 if (reg & 0x08) { 244 reg &= ~0x08; 245 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); 246 } 247 248 } 249 250 return (ret); 251 } 252 253 void 254 ep_pcmcia_disable(sc) 255 struct ep_softc *sc; 256 { 257 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 258 259 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 260 ep_pcmcia_disable1(sc); 261 } 262 263 void 264 ep_pcmcia_disable1(sc) 265 struct ep_softc *sc; 266 { 267 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 268 269 pcmcia_function_disable(psc->sc_pf); 270 } 271 272 void 273 ep_pcmcia_attach(parent, self, aux) 274 struct device *parent, *self; 275 void *aux; 276 { 277 struct ep_pcmcia_softc *psc = (void *) self; 278 struct ep_softc *sc = &psc->sc_ep; 279 struct pcmcia_attach_args *pa = aux; 280 struct pcmcia_config_entry *cfe; 281 struct ep_pcmcia_product *epp; 282 u_int8_t myla[ETHER_ADDR_LEN]; 283 u_int8_t *enaddr = NULL; 284 int i; 285 286 psc->sc_pf = pa->pf; 287 cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); 288 289 /* Enable the card. */ 290 pcmcia_function_init(pa->pf, cfe); 291 if (ep_pcmcia_enable1(sc)) 292 printf(": function enable failed\n"); 293 294 #ifdef notyet 295 sc->enabled = 1; 296 #endif 297 298 if (cfe->num_memspace != 0) 299 printf(": unexpected number of memory spaces %d should be 0\n", 300 cfe->num_memspace); 301 302 if (cfe->num_iospace != 1) 303 printf(": unexpected number of I/O spaces %d should be 1\n", 304 cfe->num_iospace); 305 306 if (pa->product == PCMCIA_PRODUCT_3COM_3C562) { 307 bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize); 308 309 for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) { 310 /* 311 * the 3c562 can only use 0x??00-0x??7f 312 * according to the Linux driver 313 */ 314 if (i & 0x80) 315 continue; 316 if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length, 317 cfe->iospace[0].length, &psc->sc_pcioh) == 0) 318 break; 319 } 320 if (i >= maxaddr) { 321 printf(": can't allocate i/o space\n"); 322 return; 323 } 324 } else { 325 if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, 326 cfe->iospace[0].length, &psc->sc_pcioh)) 327 printf(": can't allocate i/o space\n"); 328 } 329 330 sc->sc_iot = psc->sc_pcioh.iot; 331 sc->sc_ioh = psc->sc_pcioh.ioh; 332 333 if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? 334 PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length, 335 &psc->sc_pcioh, &psc->sc_io_window)) { 336 printf(": can't map i/o space\n"); 337 return; 338 } 339 340 printf(" port 0x%lx/%d", psc->sc_pcioh.addr, psc->sc_pcioh.size); 341 342 switch (pa->product) { 343 case PCMCIA_PRODUCT_3COM_3C562: 344 /* 345 * 3c562a-c use this; 3c562d does it in the regular way. 346 * we might want to check the revision and produce a warning 347 * in the future. 348 */ 349 /* FALLTHROUGH */ 350 case PCMCIA_PRODUCT_3COM_3C574: 351 case PCMCIA_PRODUCT_3COM_3CCFEM556BI: 352 /* 353 * Apparently, some 3c574s do it this way, as well. 354 */ 355 if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla)) 356 enaddr = myla; 357 break; 358 } 359 360 sc->bustype = EP_BUS_PCMCIA; 361 362 epp = ep_pcmcia_lookup(pa); 363 if (epp == NULL) 364 panic("ep_pcmcia_attach: impossible"); 365 366 sc->ep_flags = epp->epp_flags; 367 368 #ifdef notyet 369 sc->enable = ep_pcmcia_enable; 370 sc->disable = ep_pcmcia_disable; 371 #endif 372 373 /* establish the interrupt. */ 374 sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr, 375 sc, ""); 376 if (sc->sc_ih == NULL) 377 printf(", couldn't establish interrupt"); 378 379 printf(":"); 380 381 epconfig(sc, epp->epp_chipset, enaddr); 382 383 #ifdef notyet 384 sc->enabled = 0; 385 386 ep_pcmcia_disable1(sc); 387 #endif 388 } 389 390 int 391 ep_pcmcia_detach(dev, flags) 392 struct device *dev; 393 int flags; 394 { 395 int rv; 396 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *)dev; 397 398 if ((rv = ep_detach(dev)) != 0) 399 return (rv); 400 401 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 402 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 403 404 return (0); 405 } 406 407 int 408 ep_pcmcia_activate(dev, act) 409 struct device *dev; 410 enum devact act; 411 { 412 struct ep_pcmcia_softc *sc = (struct ep_pcmcia_softc *)dev; 413 struct ep_softc *esc = &sc->sc_ep; 414 struct ifnet *ifp = &esc->sc_arpcom.ac_if; 415 int s; 416 417 s = splnet(); 418 switch (act) { 419 case DVACT_ACTIVATE: 420 pcmcia_function_enable(sc->sc_pf); 421 sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, 422 epintr, sc, esc->sc_dev.dv_xname); 423 epinit(esc); 424 break; 425 426 case DVACT_DEACTIVATE: 427 ifp->if_timer = 0; 428 if (ifp->if_flags & IFF_RUNNING) 429 epstop(esc); 430 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih); 431 pcmcia_function_disable(sc->sc_pf); 432 break; 433 } 434 splx(s); 435 return (0); 436 } 437 438 int 439 ep_pcmcia_get_enaddr(tuple, arg) 440 struct pcmcia_tuple *tuple; 441 void *arg; 442 { 443 u_int8_t *myla = arg; 444 int i; 445 446 /* this is 3c562a-c magic */ 447 if (tuple->code == 0x88) { 448 if (tuple->length < ETHER_ADDR_LEN) 449 return (0); 450 451 for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 452 myla[i] = pcmcia_tuple_read_1(tuple, i + 1); 453 myla[i + 1] = pcmcia_tuple_read_1(tuple, i); 454 } 455 456 return (1); 457 } 458 return (0); 459 } 460