1 /* $NetBSD: if_ep_pcmcia.c,v 1.7 1998/03/31 08:13:34 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 "bpfilter.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/mbuf.h> 37 #include <sys/socket.h> 38 #include <sys/ioctl.h> 39 #include <sys/errno.h> 40 #include <sys/syslog.h> 41 #include <sys/select.h> 42 #include <sys/device.h> 43 44 #include <net/if.h> 45 #include <net/if_dl.h> 46 #include <net/if_ether.h> 47 #include <net/if_media.h> 48 49 #ifdef INET 50 #include <netinet/in.h> 51 #include <netinet/in_systm.h> 52 #include <netinet/in_var.h> 53 #include <netinet/ip.h> 54 #include <netinet/if_inarp.h> 55 #endif 56 57 #ifdef NS 58 #include <netns/ns.h> 59 #include <netns/ns_if.h> 60 #endif 61 62 #if NBPFILTER > 0 63 #include <net/bpf.h> 64 #include <net/bpfdesc.h> 65 #endif 66 67 #include <machine/cpu.h> 68 #include <machine/bus.h> 69 #include <machine/intr.h> 70 71 #include <dev/ic/elink3var.h> 72 #include <dev/ic/elink3reg.h> 73 74 #include <dev/pcmcia/pcmciareg.h> 75 #include <dev/pcmcia/pcmciavar.h> 76 77 #define PCMCIA_MANUFACTURER_3COM 0x101 78 #define PCMCIA_PRODUCT_3COM_3C562 0x562 79 #define PCMCIA_PRODUCT_3COM_3C589 0x589 80 81 #ifdef __BROKEN_INDIRECT_CONFIG 82 int ep_pcmcia_match __P((struct device *, void *, void *)); 83 #else 84 int ep_pcmcia_match __P((struct device *, struct cfdata *, void *)); 85 #endif 86 void ep_pcmcia_attach __P((struct device *, struct device *, void *)); 87 88 int ep_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *)); 89 int ep_pcmcia_enable __P((struct ep_softc *)); 90 void ep_pcmcia_disable __P((struct ep_softc *)); 91 92 int ep_pcmcia_enable1 __P((struct ep_softc *)); 93 void ep_pcmcia_disable1 __P((struct ep_softc *)); 94 95 struct ep_pcmcia_softc { 96 struct ep_softc sc_ep; /* real "ep" softc */ 97 98 /* PCMCIA-specific goo */ 99 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 100 int sc_io_window; /* our i/o window */ 101 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 102 }; 103 104 struct cfattach ep_pcmcia_ca = { 105 sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach 106 }; 107 108 int 109 ep_pcmcia_match(parent, match, aux) 110 struct device *parent; 111 #ifdef __BROKEN_INDIRECT_CONFIG 112 void *match; 113 #else 114 struct cfdata *match; 115 #endif 116 void *aux; 117 { 118 struct pcmcia_attach_args *pa = aux; 119 120 if (pa->manufacturer == PCMCIA_MANUFACTURER_3COM) { 121 switch (pa->product) { 122 case PCMCIA_PRODUCT_3COM_3C562: 123 case PCMCIA_PRODUCT_3COM_3C589: 124 if (pa->pf->number == 0) 125 return (1); 126 } 127 } 128 129 return (0); 130 } 131 132 int 133 ep_pcmcia_enable(sc) 134 struct ep_softc *sc; 135 { 136 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 137 struct pcmcia_function *pf = psc->sc_pf; 138 139 /* establish the interrupt. */ 140 sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr, sc); 141 if (sc->sc_ih == NULL) { 142 printf("%s: couldn't establish interrupt\n", 143 sc->sc_dev.dv_xname); 144 return (1); 145 } 146 147 return (ep_pcmcia_enable1(sc)); 148 } 149 150 int 151 ep_pcmcia_enable1(sc) 152 struct ep_softc *sc; 153 { 154 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 155 struct pcmcia_function *pf = psc->sc_pf; 156 int ret; 157 158 if ((ret = pcmcia_function_enable(pf))) 159 return (ret); 160 161 if (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) { 162 int reg; 163 164 /* turn off the serial-disable bit */ 165 166 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); 167 if (reg & 0x08) { 168 reg &= ~0x08; 169 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); 170 } 171 172 } 173 174 return (ret); 175 } 176 177 void 178 ep_pcmcia_disable(sc) 179 struct ep_softc *sc; 180 { 181 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 182 183 ep_pcmcia_disable1(sc); 184 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 185 } 186 187 void 188 ep_pcmcia_disable1(sc) 189 struct ep_softc *sc; 190 { 191 struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; 192 193 pcmcia_function_disable(psc->sc_pf); 194 } 195 196 void 197 ep_pcmcia_attach(parent, self, aux) 198 struct device *parent, *self; 199 void *aux; 200 { 201 struct ep_pcmcia_softc *psc = (void *) self; 202 struct ep_softc *sc = &psc->sc_ep; 203 struct pcmcia_attach_args *pa = aux; 204 struct pcmcia_config_entry *cfe; 205 int i; 206 u_int8_t myla[ETHER_ADDR_LEN]; 207 u_int8_t *enaddr; 208 char *model; 209 210 psc->sc_pf = pa->pf; 211 cfe = pa->pf->cfe_head.sqh_first; 212 213 /* Enable the card. */ 214 pcmcia_function_init(pa->pf, cfe); 215 if (ep_pcmcia_enable1(sc)) 216 printf(": function enable failed\n"); 217 218 sc->enabled = 1; 219 220 if (cfe->num_memspace != 0) 221 printf(": unexpected number of memory spaces %d should be 0\n", 222 cfe->num_memspace); 223 224 if (cfe->num_iospace != 1) 225 printf(": unexpected number of I/O spaces %d should be 1\n", 226 cfe->num_iospace); 227 228 if (pa->product == PCMCIA_PRODUCT_3COM_3C562) { 229 bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize); 230 231 for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) { 232 /* 233 * the 3c562 can only use 0x??00-0x??7f 234 * according to the Linux driver 235 */ 236 if (i & 0x80) 237 continue; 238 if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length, 239 0, &psc->sc_pcioh) == 0) 240 break; 241 } 242 if (i >= maxaddr) { 243 printf(": can't allocate i/o space\n"); 244 return; 245 } 246 } else { 247 if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, 248 cfe->iospace[0].length, &psc->sc_pcioh)) 249 printf(": can't allocate i/o space\n"); 250 } 251 252 sc->sc_iot = psc->sc_pcioh.iot; 253 sc->sc_ioh = psc->sc_pcioh.ioh; 254 255 if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? 256 PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length, 257 &psc->sc_pcioh, &psc->sc_io_window)) { 258 printf(": can't map i/o space\n"); 259 return; 260 } 261 if (pa->product == PCMCIA_PRODUCT_3COM_3C562) { 262 /* 263 * 3c562a-c use this; 3c562d does it in the regular way. 264 * we might want to check the revision and produce a warning 265 * in the future. 266 */ 267 if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla) != 1) 268 enaddr = NULL; 269 else 270 enaddr = myla; 271 } else { 272 enaddr = NULL; 273 } 274 275 sc->bustype = EP_BUS_PCMCIA; 276 277 switch (pa->product) { 278 case PCMCIA_PRODUCT_3COM_3C589: 279 model = "3Com 3C589 Ethernet"; 280 break; 281 case PCMCIA_PRODUCT_3COM_3C562: 282 model = "3Com 3C562 Ethernet"; 283 break; 284 default: 285 model = "3Com Ethernet, model unknown"; 286 break; 287 } 288 289 printf(": %s\n", model); 290 291 sc->enable = ep_pcmcia_enable; 292 sc->disable = ep_pcmcia_disable; 293 294 epconfig(sc, EP_CHIPSET_3C509, enaddr); 295 296 sc->enabled = 0; 297 298 ep_pcmcia_disable1(sc); 299 } 300 301 int 302 ep_pcmcia_get_enaddr(tuple, arg) 303 struct pcmcia_tuple *tuple; 304 void *arg; 305 { 306 u_int8_t *myla = arg; 307 int i; 308 309 /* this is 3c562a-c magic */ 310 if (tuple->code == 0x88) { 311 if (tuple->length < ETHER_ADDR_LEN) 312 return (0); 313 314 for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 315 myla[i] = pcmcia_tuple_read_1(tuple, i + 1); 316 myla[i + 1] = pcmcia_tuple_read_1(tuple, i); 317 } 318 319 return (1); 320 } 321 return (0); 322 } 323