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