1 /* $NetBSD: if_mbe_pcmcia.c,v 1.20 2000/05/15 08:08:12 enami Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Enami Tsugutomo. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/device.h> 42 #include <sys/socket.h> 43 44 #include <net/if.h> 45 #include <net/if_ether.h> 46 #include <net/if_media.h> 47 48 #include <machine/intr.h> 49 #include <machine/bus.h> 50 51 #include <dev/ic/mb86960reg.h> 52 #include <dev/ic/mb86960var.h> 53 54 #include <dev/pcmcia/pcmciareg.h> 55 #include <dev/pcmcia/pcmciavar.h> 56 #include <dev/pcmcia/pcmciadevs.h> 57 58 int mbe_pcmcia_match __P((struct device *, struct cfdata *, void *)); 59 void mbe_pcmcia_attach __P((struct device *, struct device *, void *)); 60 int mbe_pcmcia_detach __P((struct device *, int)); 61 62 struct mbe_pcmcia_softc { 63 struct mb86960_softc sc_mb86960; /* real "mb" softc */ 64 65 /* PCMCIA-specific goo. */ 66 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 67 int sc_io_window; /* our i/o window */ 68 void *sc_ih; /* interrupt cookie */ 69 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 70 }; 71 72 struct cfattach mbe_pcmcia_ca = { 73 sizeof(struct mbe_pcmcia_softc), mbe_pcmcia_match, mbe_pcmcia_attach, 74 mbe_pcmcia_detach, mb86960_activate 75 }; 76 77 int mbe_pcmcia_enable __P((struct mb86960_softc *)); 78 void mbe_pcmcia_disable __P((struct mb86960_softc *)); 79 80 struct mbe_pcmcia_get_enaddr_args { 81 u_int8_t enaddr[ETHER_ADDR_LEN]; 82 int maddr; 83 }; 84 int mbe_pcmcia_get_enaddr_from_cis __P((struct pcmcia_tuple *, void *)); 85 int mbe_pcmcia_get_enaddr_from_mem __P((struct mbe_pcmcia_softc *, 86 struct mbe_pcmcia_get_enaddr_args *)); 87 88 const struct mbe_pcmcia_product { 89 struct pcmcia_product mpp_product; 90 u_int32_t mpp_ioalign; /* required alignment */ 91 int mpp_enet_maddr; 92 } mbe_pcmcia_products[] = { 93 { { PCMCIA_STR_TDK_LAK_CD021BX, PCMCIA_VENDOR_TDK, 94 PCMCIA_PRODUCT_TDK_LAK_CD021BX, 0 }, 95 0, -1 }, 96 97 { { PCMCIA_STR_TDK_LAK_CF010, PCMCIA_VENDOR_TDK, 98 PCMCIA_PRODUCT_TDK_LAK_CF010, 0 }, 99 0, -1 }, 100 101 #if 0 /* XXX 86960-based? */ 102 { { PCMCIA_STR_TDK_LAK_DFL9610, PCMCIA_VENDOR_TDK, 103 PCMCIA_PRODUCT_TDK_LAK_DFL9610, 1 }, 104 0, -1 }, 105 #endif 106 107 { { PCMCIA_STR_CONTEC_CNETPC, PCMCIA_VENDOR_CONTEC, 108 PCMCIA_PRODUCT_CONTEC_CNETPC, 0 }, 109 0, -1 }, 110 111 { { PCMCIA_STR_FUJITSU_LA501, PCMCIA_VENDOR_FUJITSU, 112 PCMCIA_PRODUCT_FUJITSU_LA501, 0 }, 113 0x20, -1 }, 114 115 { { PCMCIA_STR_FUJITSU_LA10S, PCMCIA_VENDOR_FUJITSU, 116 PCMCIA_PRODUCT_FUJITSU_LA10S, 0 }, 117 0, -1 }, 118 119 { { PCMCIA_STR_RATOC_REX_R280, PCMCIA_VENDOR_RATOC, 120 PCMCIA_PRODUCT_RATOC_REX_R280, 0 }, 121 0, 0x1fc }, 122 123 { { NULL } } 124 }; 125 126 int 127 mbe_pcmcia_match(parent, match, aux) 128 struct device *parent; 129 struct cfdata *match; 130 void *aux; 131 { 132 struct pcmcia_attach_args *pa = aux; 133 134 if (pcmcia_product_lookup(pa, 135 (const struct pcmcia_product *)mbe_pcmcia_products, 136 sizeof mbe_pcmcia_products[0], NULL) != NULL) 137 return (1); 138 139 return (0); 140 } 141 142 void 143 mbe_pcmcia_attach(parent, self, aux) 144 struct device *parent, *self; 145 void *aux; 146 { 147 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)self; 148 struct mb86960_softc *sc = &psc->sc_mb86960; 149 struct pcmcia_attach_args *pa = aux; 150 struct pcmcia_config_entry *cfe; 151 struct mbe_pcmcia_get_enaddr_args pgea; 152 const struct mbe_pcmcia_product *mpp; 153 int rv; 154 155 mpp = (const struct mbe_pcmcia_product *)pcmcia_product_lookup(pa, 156 (const struct pcmcia_product *)mbe_pcmcia_products, 157 sizeof mbe_pcmcia_products[0], NULL); 158 if (mpp == NULL) { 159 printf("\n"); 160 panic("mbe_pcmcia_attach: impossible"); 161 } 162 163 psc->sc_pf = pa->pf; 164 cfe = pa->pf->cfe_head.sqh_first; 165 166 /* Enable the card. */ 167 pcmcia_function_init(pa->pf, cfe); 168 if (pcmcia_function_enable(pa->pf)) { 169 printf(": function enable failed\n"); 170 goto enable_failed; 171 } 172 173 /* Allocate and map i/o space for the card. */ 174 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, 175 cfe->iospace[0].length, 176 mpp->mpp_ioalign ? mpp->mpp_ioalign : cfe->iospace[0].length, 177 &psc->sc_pcioh)) { 178 printf(": can't allocate i/o space\n"); 179 goto ioalloc_failed; 180 } 181 182 sc->sc_bst = psc->sc_pcioh.iot; 183 sc->sc_bsh = psc->sc_pcioh.ioh; 184 185 sc->sc_enable = mbe_pcmcia_enable; 186 sc->sc_disable = mbe_pcmcia_disable; 187 188 /* 189 * Don't bother checking flags; the back-end sets the chip 190 * into 16-bit mode. 191 */ 192 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO16, 0, cfe->iospace[0].length, 193 &psc->sc_pcioh, &psc->sc_io_window)) { 194 printf(": can't map i/o space\n"); 195 goto iomap_failed; 196 } 197 198 printf(": %s\n", mpp->mpp_product.pp_name); 199 200 /* Read station address from mem or CIS. */ 201 if (mpp->mpp_enet_maddr >= 0) { 202 pgea.maddr = mpp->mpp_enet_maddr; 203 if (mbe_pcmcia_get_enaddr_from_mem(psc, &pgea) != 0) { 204 printf("%s: Couldn't get ethernet address " 205 "from mem\n", sc->sc_dev.dv_xname); 206 goto no_enaddr; 207 } 208 } else { 209 rv = pcmcia_scan_cis(parent, 210 mbe_pcmcia_get_enaddr_from_cis, &pgea); 211 if (rv == -1) { 212 printf("%s: Couldn't read CIS to get ethernet " 213 "address\n", sc->sc_dev.dv_xname); 214 goto no_enaddr; 215 } else if (rv == 0) { 216 printf("%s: Couldn't get ethernet address " 217 "from CIS\n", sc->sc_dev.dv_xname); 218 goto no_enaddr; 219 } 220 #ifdef DIAGNOSTIC 221 if (rv != 1) { 222 printf("%s: pcmcia_scan_cis returns %d\n", 223 sc->sc_dev.dv_xname, rv); 224 panic("mbe_pcmcia_attach"); 225 } 226 printf("%s: Ethernet address from CIS: %s\n", 227 sc->sc_dev.dv_xname, ether_sprintf(pgea.enaddr)); 228 #endif 229 } 230 231 /* Perform generic initialization. */ 232 mb86960_attach(sc, MB86960_TYPE_86965, pgea.enaddr); 233 234 mb86960_config(sc, NULL, 0, 0); 235 236 pcmcia_function_disable(pa->pf); 237 return; 238 239 no_enaddr: 240 /* Unmap our i/o window. */ 241 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 242 243 iomap_failed: 244 /* Free our i/o space. */ 245 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 246 247 ioalloc_failed: 248 pcmcia_function_disable(pa->pf); 249 250 enable_failed: 251 psc->sc_io_window = -1; 252 } 253 254 int 255 mbe_pcmcia_detach(self, flags) 256 struct device *self; 257 int flags; 258 { 259 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)self; 260 int error; 261 262 if (psc->sc_io_window == -1) 263 /* Nothing to detach. */ 264 return (0); 265 266 error = mb86960_detach(&psc->sc_mb86960); 267 if (error != 0) 268 return (error); 269 270 /* Unmap our i/o window. */ 271 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 272 273 /* Free our i/o space. */ 274 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 275 276 return (0); 277 } 278 279 int 280 mbe_pcmcia_enable(sc) 281 struct mb86960_softc *sc; 282 { 283 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 284 285 /* Establish the interrupt handler. */ 286 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, mb86960_intr, 287 sc); 288 if (psc->sc_ih == NULL) { 289 printf("%s: couldn't establish interrupt handler\n", 290 sc->sc_dev.dv_xname); 291 return (1); 292 } 293 294 if (pcmcia_function_enable(psc->sc_pf)) { 295 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 296 return (1); 297 } 298 299 return (0); 300 } 301 302 void 303 mbe_pcmcia_disable(sc) 304 struct mb86960_softc *sc; 305 { 306 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 307 308 pcmcia_function_disable(psc->sc_pf); 309 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 310 } 311 312 int 313 mbe_pcmcia_get_enaddr_from_cis(tuple, arg) 314 struct pcmcia_tuple *tuple; 315 void *arg; 316 { 317 struct mbe_pcmcia_get_enaddr_args *p = arg; 318 int i; 319 320 if (tuple->code == PCMCIA_CISTPL_FUNCE) { 321 if (tuple->length < 2) /* sub code and ether addr length */ 322 return (0); 323 324 if ((pcmcia_tuple_read_1(tuple, 0) != 325 PCMCIA_TPLFE_TYPE_LAN_NID) || 326 (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)) 327 return (0); 328 329 for (i = 0; i < ETHER_ADDR_LEN; i++) 330 p->enaddr[i] = pcmcia_tuple_read_1(tuple, i + 2); 331 return (1); 332 } 333 return (0); 334 } 335 336 int 337 mbe_pcmcia_get_enaddr_from_mem(psc, ea) 338 struct mbe_pcmcia_softc *psc; 339 struct mbe_pcmcia_get_enaddr_args *ea; 340 { 341 struct mb86960_softc *sc = &psc->sc_mb86960; 342 struct pcmcia_mem_handle pcmh; 343 bus_addr_t offset; 344 int i, mwindow, rv = 1; 345 346 if (ea->maddr < 0) 347 goto bad_memaddr; 348 349 if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) { 350 printf("%s: can't alloc mem for enet addr\n", 351 sc->sc_dev.dv_xname); 352 goto memalloc_failed; 353 } 354 355 if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, ea->maddr, 356 ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) { 357 printf("%s: can't map mem for enet addr\n", 358 sc->sc_dev.dv_xname); 359 goto memmap_failed; 360 } 361 362 for (i = 0; i < ETHER_ADDR_LEN; i++) 363 ea->enaddr[i] = bus_space_read_1(pcmh.memt, pcmh.memh, 364 offset + (i * 2)); 365 366 rv = 0; 367 pcmcia_mem_unmap(psc->sc_pf, mwindow); 368 memmap_failed: 369 pcmcia_mem_free(psc->sc_pf, &pcmh); 370 memalloc_failed: 371 bad_memaddr: 372 373 return (rv); 374 } 375