if_ep_pcmcia.c revision 1.11
1/* $OpenBSD: if_ep_pcmcia.c,v 1.11 1998/09/19 10:08:06 maja 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#include <machine/intr.h> 109 110#include <dev/ic/elink3var.h> 111#include <dev/ic/elink3reg.h> 112 113#include <dev/pcmcia/pcmciareg.h> 114#include <dev/pcmcia/pcmciavar.h> 115#include <dev/pcmcia/pcmciadevs.h> 116 117int ep_pcmcia_match __P((struct device *, void *, void *)); 118void ep_pcmcia_attach __P((struct device *, struct device *, void *)); 119 120int ep_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *)); 121int ep_pcmcia_enable __P((struct ep_softc *)); 122void ep_pcmcia_disable __P((struct ep_softc *)); 123 124int ep_pcmcia_enable1 __P((struct ep_softc *)); 125void ep_pcmcia_disable1 __P((struct ep_softc *)); 126 127struct ep_pcmcia_softc { 128 struct ep_softc sc_ep; /* real "ep" softc */ 129 130 /* PCMCIA-specific goo */ 131 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 132 int sc_io_window; /* our i/o window */ 133 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 134}; 135 136struct cfattach ep_pcmcia_ca = { 137 sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach 138}; 139 140struct ep_pcmcia_product { 141 u_int32_t epp_product; /* PCMCIA product ID */ 142 u_short epp_chipset; /* 3Com chipset used */ 143 int epp_flags; /* initial softc flags */ 144 int epp_expfunc; /* expected function */ 145 const char *epp_name; /* device name */ 146} ep_pcmcia_products[] = { 147 { PCMCIA_PRODUCT_3COM_3C562, EP_CHIPSET_3C509, 148 0, 0, 149 PCMCIA_STR_3COM_3C562 }, 150 { PCMCIA_PRODUCT_3COM_3C589, EP_CHIPSET_3C509, 151 0, 0, 152 PCMCIA_STR_3COM_3C589 }, 153 154 { PCMCIA_PRODUCT_3COM_3C574, EP_CHIPSET_BOOMERANG, 155 EP_FLAGS_MII, 0, 156 PCMCIA_STR_3COM_3C574 }, 157 158 { 0, 0, 159 0, 0, 160 NULL }, 161}; 162 163struct ep_pcmcia_product *ep_pcmcia_lookup __P((struct pcmcia_attach_args *)); 164 165struct ep_pcmcia_product * 166ep_pcmcia_lookup(pa) 167 struct pcmcia_attach_args *pa; 168{ 169 struct ep_pcmcia_product *epp; 170 171 for (epp = ep_pcmcia_products; epp->epp_name != NULL; epp++) 172 if (pa->product == epp->epp_product && 173 pa->pf->number == epp->epp_expfunc) 174 return (epp); 175 176 return (NULL); 177} 178 179int 180ep_pcmcia_match(parent, match, aux) 181 struct device *parent; 182 void *match, *aux; 183{ 184 struct pcmcia_attach_args *pa = aux; 185 186 if (pa->manufacturer != PCMCIA_VENDOR_3COM) 187 return (0); 188 189 if (ep_pcmcia_lookup(pa) != NULL) 190 return (1); 191 192 return (0); 193} 194 195int 196ep_pcmcia_enable(sc) 197 struct ep_softc *sc; 198{ 199 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 200 struct pcmcia_function *pf = psc->sc_pf; 201 202 /* establish the interrupt. */ 203 sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr, sc); 204 if (sc->sc_ih == NULL) { 205 printf("%s: couldn't establish interrupt\n", 206 sc->sc_dev.dv_xname); 207 return (1); 208 } 209 210 return (ep_pcmcia_enable1(sc)); 211} 212 213int 214ep_pcmcia_enable1(sc) 215 struct ep_softc *sc; 216{ 217 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 218 struct pcmcia_function *pf = psc->sc_pf; 219 int ret; 220 221 if ((ret = pcmcia_function_enable(pf))) 222 return (ret); 223 224 if (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) { 225 int reg; 226 227 /* turn off the serial-disable bit */ 228 229 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); 230 if (reg & 0x08) { 231 reg &= ~0x08; 232 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); 233 } 234 235 } 236 237 return (ret); 238} 239 240void 241ep_pcmcia_disable(sc) 242 struct ep_softc *sc; 243{ 244 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 245 246 ep_pcmcia_disable1(sc); 247 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 248} 249 250void 251ep_pcmcia_disable1(sc) 252 struct ep_softc *sc; 253{ 254 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 255 256 pcmcia_function_disable(psc->sc_pf); 257} 258 259void 260ep_pcmcia_attach(parent, self, aux) 261 struct device *parent, *self; 262 void *aux; 263{ 264 struct ep_pcmcia_softc *psc = (void *) self; 265 struct ep_softc *sc = &psc->sc_ep; 266 struct pcmcia_attach_args *pa = aux; 267 struct pcmcia_config_entry *cfe; 268 struct ep_pcmcia_product *epp; 269 u_int8_t myla[ETHER_ADDR_LEN]; 270 u_int8_t *enaddr = NULL; 271 int i; 272 273 psc->sc_pf = pa->pf; 274 cfe = pa->pf->cfe_head.sqh_first; 275 276 /* Enable the card. */ 277 pcmcia_function_init(pa->pf, cfe); 278 if (ep_pcmcia_enable1(sc)) 279 printf(": function enable failed\n"); 280 281#ifdef notyet 282 sc->enabled = 1; 283#endif 284 285 if (cfe->num_memspace != 0) 286 printf(": unexpected number of memory spaces %d should be 0\n", 287 cfe->num_memspace); 288 289 if (cfe->num_iospace != 1) 290 printf(": unexpected number of I/O spaces %d should be 1\n", 291 cfe->num_iospace); 292 293 if (pa->product == PCMCIA_PRODUCT_3COM_3C562) { 294 bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize); 295 296 for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) { 297 /* 298 * the 3c562 can only use 0x??00-0x??7f 299 * according to the Linux driver 300 */ 301 if (i & 0x80) 302 continue; 303 if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length, 304 0, &psc->sc_pcioh) == 0) 305 break; 306 } 307 if (i >= maxaddr) { 308 printf(": can't allocate i/o space\n"); 309 return; 310 } 311 } else { 312 if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, 313 cfe->iospace[0].length, &psc->sc_pcioh)) 314 printf(": can't allocate i/o space\n"); 315 } 316 317 sc->sc_iot = psc->sc_pcioh.iot; 318 sc->sc_ioh = psc->sc_pcioh.ioh; 319 320 if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? 321 PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length, 322 &psc->sc_pcioh, &psc->sc_io_window)) { 323 printf(": can't map i/o space\n"); 324 return; 325 } 326 327 switch (pa->product) { 328 case PCMCIA_PRODUCT_3COM_3C562: 329 /* 330 * 3c562a-c use this; 3c562d does it in the regular way. 331 * we might want to check the revision and produce a warning 332 * in the future. 333 */ 334 /* FALLTHROUGH */ 335 case PCMCIA_PRODUCT_3COM_3C574: 336 /* 337 * Apparently, some 3c574s do it this way, as well. 338 */ 339 if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla)) 340 enaddr = myla; 341 break; 342 } 343 344 sc->bustype = EP_BUS_PCMCIA; 345 346 epp = ep_pcmcia_lookup(pa); 347 if (epp == NULL) 348 panic("ep_pcmcia_attach: impossible"); 349 350 printf(": %s,", epp->epp_name); 351 352#ifdef notyet 353 sc->enable = ep_pcmcia_enable; 354 sc->disable = ep_pcmcia_disable; 355#endif 356 357 epconfig(sc, epp->epp_chipset, enaddr); 358 359 /* establish the interrupt. */ 360 sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr, sc); 361 if (sc->sc_ih == NULL) 362 printf("%s: couldn't establish interrupt\n", 363 sc->sc_dev.dv_xname); 364 365#ifdef notyet 366 sc->enabled = 0; 367 368 ep_pcmcia_disable1(sc); 369#endif 370} 371 372int 373ep_pcmcia_get_enaddr(tuple, arg) 374 struct pcmcia_tuple *tuple; 375 void *arg; 376{ 377 u_int8_t *myla = arg; 378 int i; 379 380 /* this is 3c562a-c magic */ 381 if (tuple->code == 0x88) { 382 if (tuple->length < ETHER_ADDR_LEN) 383 return (0); 384 385 for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 386 myla[i] = pcmcia_tuple_read_1(tuple, i + 1); 387 myla[i + 1] = pcmcia_tuple_read_1(tuple, i); 388 } 389 390 return (1); 391 } 392 return (0); 393} 394