1 /* $NetBSD: if_mbe_pcmcia.c,v 1.26 2002/06/01 23:51:01 lukem 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/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: if_mbe_pcmcia.c,v 1.26 2002/06/01 23:51:01 lukem Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/socket.h> 46 47 #include <net/if.h> 48 #include <net/if_ether.h> 49 #include <net/if_media.h> 50 51 #include <machine/intr.h> 52 #include <machine/bus.h> 53 54 #include <dev/ic/mb86960reg.h> 55 #include <dev/ic/mb86960var.h> 56 57 #include <dev/pcmcia/pcmciareg.h> 58 #include <dev/pcmcia/pcmciavar.h> 59 #include <dev/pcmcia/pcmciadevs.h> 60 61 int mbe_pcmcia_match __P((struct device *, struct cfdata *, void *)); 62 void mbe_pcmcia_attach __P((struct device *, struct device *, void *)); 63 int mbe_pcmcia_detach __P((struct device *, int)); 64 65 static const struct mbe_pcmcia_product 66 *mbe_pcmcia_lookup __P((struct pcmcia_attach_args *pa)); 67 68 struct mbe_pcmcia_softc { 69 struct mb86960_softc sc_mb86960; /* real "mb" softc */ 70 71 /* PCMCIA-specific goo. */ 72 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 73 int sc_io_window; /* our i/o window */ 74 void *sc_ih; /* interrupt cookie */ 75 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 76 }; 77 78 struct cfattach mbe_pcmcia_ca = { 79 sizeof(struct mbe_pcmcia_softc), mbe_pcmcia_match, mbe_pcmcia_attach, 80 mbe_pcmcia_detach, mb86960_activate 81 }; 82 83 int mbe_pcmcia_enable __P((struct mb86960_softc *)); 84 void mbe_pcmcia_disable __P((struct mb86960_softc *)); 85 86 struct mbe_pcmcia_get_enaddr_args { 87 u_int8_t enaddr[ETHER_ADDR_LEN]; 88 int maddr; 89 }; 90 int mbe_pcmcia_get_enaddr_from_cis __P((struct pcmcia_tuple *, void *)); 91 int mbe_pcmcia_get_enaddr_from_mem __P((struct mbe_pcmcia_softc *, 92 struct mbe_pcmcia_get_enaddr_args *)); 93 int mbe_pcmcia_get_enaddr_from_io __P((struct mbe_pcmcia_softc *, 94 struct mbe_pcmcia_get_enaddr_args *)); 95 96 static const struct mbe_pcmcia_product { 97 const char *mpp_name; /* product name */ 98 u_int32_t mpp_vendor; /* vendor ID */ 99 u_int32_t mpp_product; /* product ID */ 100 const char *mpp_cisinfo[4]; /* CIS information */ 101 u_int32_t mpp_ioalign; /* required alignment */ 102 int mpp_enet_maddr; 103 int flags; 104 #define MBH10302 0x0001 /* FUJITSU MBH10302 */ 105 } mbe_pcmcia_products[] = { 106 { PCMCIA_STR_TDK_LAK_CD021BX, PCMCIA_VENDOR_TDK, 107 PCMCIA_PRODUCT_TDK_LAK_CD021BX, PCMCIA_CIS_TDK_LAK_CD021BX, 108 0, -1 }, 109 110 { PCMCIA_STR_TDK_LAK_CF010, PCMCIA_VENDOR_TDK, 111 PCMCIA_PRODUCT_TDK_LAK_CF010, PCMCIA_CIS_TDK_LAK_CF010, 112 0, -1 }, 113 114 #if 0 /* XXX 86960-based? */ 115 { PCMCIA_STR_TDK_LAK_DFL9610, PCMCIA_VENDOR_TDK, 116 PCMCIA_PRODUCT_TDK_LAK_DFL9610, PCMCIA_CIS_TDK_DFL9610, 117 0, -1, MBH10302 /* XXX */ }, 118 #endif 119 120 { PCMCIA_STR_CONTEC_CNETPC, PCMCIA_VENDOR_CONTEC, 121 PCMCIA_PRODUCT_CONTEC_CNETPC, PCMCIA_CIS_CONTEC_CNETPC, 122 0, -1 }, 123 124 { PCMCIA_STR_FUJITSU_LA501, PCMCIA_VENDOR_FUJITSU, 125 PCMCIA_PRODUCT_FUJITSU_LA501, PCMCIA_CIS_FUJITSU_LA501, 126 0x20, -1 }, 127 128 { PCMCIA_STR_FUJITSU_FMV_J181, PCMCIA_VENDOR_FUJITSU, 129 PCMCIA_PRODUCT_FUJITSU_FMV_J181, PCMCIA_CIS_FUJITSU_FMV_J181, 130 0x20, -1, MBH10302 }, 131 132 { PCMCIA_STR_FUJITSU_FMV_J182, PCMCIA_VENDOR_FUJITSU, 133 PCMCIA_PRODUCT_FUJITSU_FMV_J182, PCMCIA_CIS_FUJITSU_FMV_J182, 134 0, 0xf2c }, 135 136 { PCMCIA_STR_FUJITSU_FMV_J182A, PCMCIA_VENDOR_FUJITSU, 137 PCMCIA_PRODUCT_FUJITSU_FMV_J182A, PCMCIA_CIS_FUJITSU_FMV_J182A, 138 0, 0x1cc }, 139 140 { PCMCIA_STR_FUJITSU_ITCFJ182A, PCMCIA_VENDOR_FUJITSU, 141 PCMCIA_PRODUCT_FUJITSU_ITCFJ182A, PCMCIA_CIS_FUJITSU_ITCFJ182A, 142 0, 0x1cc }, 143 144 { PCMCIA_STR_FUJITSU_LA10S, PCMCIA_VENDOR_FUJITSU, 145 PCMCIA_PRODUCT_FUJITSU_LA10S, PCMCIA_CIS_FUJITSU_LA10S, 146 0, -1 }, 147 148 { PCMCIA_STR_RATOC_REX_R280, PCMCIA_VENDOR_RATOC, 149 PCMCIA_PRODUCT_RATOC_REX_R280, PCMCIA_CIS_RATOC_REX_R280, 150 0, 0x1fc }, 151 152 { NULL, 0, 153 0, { NULL, NULL, NULL, NULL }, 154 0, 0 } 155 }; 156 157 static const struct mbe_pcmcia_product * 158 mbe_pcmcia_lookup(pa) 159 struct pcmcia_attach_args *pa; 160 { 161 const struct mbe_pcmcia_product *mpp; 162 163 for (mpp = mbe_pcmcia_products; mpp->mpp_name != NULL; mpp++) { 164 /* match by CIS information */ 165 if (pa->card->cis1_info[0] != NULL && 166 mpp->mpp_cisinfo[0] != NULL && 167 strcmp(pa->card->cis1_info[0], mpp->mpp_cisinfo[0]) == 0 && 168 pa->card->cis1_info[1] != NULL && 169 mpp->mpp_cisinfo[1] != NULL && 170 strcmp(pa->card->cis1_info[1], mpp->mpp_cisinfo[1]) == 0 && 171 (mpp->mpp_cisinfo[2] == NULL || 172 strcmp(pa->card->cis1_info[2], mpp->mpp_cisinfo[2]) == 0)) 173 return (mpp); 174 175 /* match by vendor/product id */ 176 if (pa->manufacturer != PCMCIA_VENDOR_INVALID && 177 pa->manufacturer == mpp->mpp_vendor && 178 pa->product != PCMCIA_PRODUCT_INVALID && 179 pa->product == mpp->mpp_product) 180 return (mpp); 181 } 182 183 return (NULL); 184 } 185 186 int 187 mbe_pcmcia_match(parent, match, aux) 188 struct device *parent; 189 struct cfdata *match; 190 void *aux; 191 { 192 struct pcmcia_attach_args *pa = aux; 193 194 if (mbe_pcmcia_lookup(pa) != NULL) 195 return (1); 196 return (0); 197 } 198 199 void 200 mbe_pcmcia_attach(parent, self, aux) 201 struct device *parent, *self; 202 void *aux; 203 { 204 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)self; 205 struct mb86960_softc *sc = &psc->sc_mb86960; 206 struct pcmcia_attach_args *pa = aux; 207 struct pcmcia_config_entry *cfe; 208 struct mbe_pcmcia_get_enaddr_args pgea; 209 const struct mbe_pcmcia_product *mpp; 210 int rv; 211 212 mpp = mbe_pcmcia_lookup(pa); 213 if (mpp == NULL) { 214 printf("\n"); 215 panic("mbe_pcmcia_attach: impossible"); 216 } 217 218 psc->sc_pf = pa->pf; 219 cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); 220 221 /* Enable the card. */ 222 pcmcia_function_init(pa->pf, cfe); 223 if (pcmcia_function_enable(pa->pf)) { 224 printf(": function enable failed\n"); 225 goto enable_failed; 226 } 227 228 /* Allocate and map i/o space for the card. */ 229 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, 230 cfe->iospace[0].length, 231 mpp->mpp_ioalign ? mpp->mpp_ioalign : cfe->iospace[0].length, 232 &psc->sc_pcioh)) { 233 printf(": can't allocate i/o space\n"); 234 goto ioalloc_failed; 235 } 236 237 sc->sc_bst = psc->sc_pcioh.iot; 238 sc->sc_bsh = psc->sc_pcioh.ioh; 239 240 sc->sc_enable = mbe_pcmcia_enable; 241 sc->sc_disable = mbe_pcmcia_disable; 242 243 /* 244 * Don't bother checking flags; the back-end sets the chip 245 * into 16-bit mode. 246 */ 247 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO16, 0, 248 mpp->mpp_ioalign ? mpp->mpp_ioalign : cfe->iospace[0].length, 249 &psc->sc_pcioh, &psc->sc_io_window)) { 250 printf(": can't map i/o space\n"); 251 goto iomap_failed; 252 } 253 254 printf(": %s\n", mpp->mpp_name); 255 256 /* Read station address from io/mem or CIS. */ 257 if (mpp->mpp_enet_maddr >= 0) { 258 pgea.maddr = mpp->mpp_enet_maddr; 259 if (mbe_pcmcia_get_enaddr_from_mem(psc, &pgea) != 0) { 260 printf("%s: Couldn't get ethernet address " 261 "from mem\n", sc->sc_dev.dv_xname); 262 goto no_enaddr; 263 } 264 } else if ((mpp->flags & MBH10302) != 0) { 265 bus_space_write_1(sc->sc_bst, sc->sc_bsh, FE_MBH0 , 266 FE_MBH0_MASK | FE_MBH0_INTR_ENABLE); 267 if (mbe_pcmcia_get_enaddr_from_io(psc, &pgea) != 0) { 268 printf("%s: Couldn't get ethernet address " 269 "from io\n", sc->sc_dev.dv_xname); 270 goto no_enaddr; 271 } 272 } else { 273 rv = pcmcia_scan_cis(parent, 274 mbe_pcmcia_get_enaddr_from_cis, &pgea); 275 if (rv == -1) { 276 printf("%s: Couldn't read CIS to get ethernet " 277 "address\n", sc->sc_dev.dv_xname); 278 goto no_enaddr; 279 } else if (rv == 0) { 280 printf("%s: Couldn't get ethernet address " 281 "from CIS\n", sc->sc_dev.dv_xname); 282 goto no_enaddr; 283 } 284 #ifdef DIAGNOSTIC 285 if (rv != 1) { 286 printf("%s: pcmcia_scan_cis returns %d\n", 287 sc->sc_dev.dv_xname, rv); 288 panic("mbe_pcmcia_attach"); 289 } 290 printf("%s: Ethernet address from CIS: %s\n", 291 sc->sc_dev.dv_xname, ether_sprintf(pgea.enaddr)); 292 #endif 293 } 294 295 /* Perform generic initialization. */ 296 if ((mpp->flags & MBH10302) != 0) 297 mb86960_attach(sc, MB86960_TYPE_86960, pgea.enaddr); 298 else 299 mb86960_attach(sc, MB86960_TYPE_86965, pgea.enaddr); 300 301 mb86960_config(sc, NULL, 0, 0); 302 303 pcmcia_function_disable(pa->pf); 304 return; 305 306 no_enaddr: 307 /* Unmap our i/o window. */ 308 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 309 310 iomap_failed: 311 /* Free our i/o space. */ 312 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 313 314 ioalloc_failed: 315 pcmcia_function_disable(pa->pf); 316 317 enable_failed: 318 psc->sc_io_window = -1; 319 } 320 321 int 322 mbe_pcmcia_detach(self, flags) 323 struct device *self; 324 int flags; 325 { 326 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)self; 327 int error; 328 329 if (psc->sc_io_window == -1) 330 /* Nothing to detach. */ 331 return (0); 332 333 error = mb86960_detach(&psc->sc_mb86960); 334 if (error != 0) 335 return (error); 336 337 /* Unmap our i/o window. */ 338 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 339 340 /* Free our i/o space. */ 341 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 342 343 return (0); 344 } 345 346 int 347 mbe_pcmcia_enable(sc) 348 struct mb86960_softc *sc; 349 { 350 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 351 352 /* Establish the interrupt handler. */ 353 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, mb86960_intr, 354 sc); 355 if (psc->sc_ih == NULL) { 356 printf("%s: couldn't establish interrupt handler\n", 357 sc->sc_dev.dv_xname); 358 return (1); 359 } 360 361 if (pcmcia_function_enable(psc->sc_pf)) { 362 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 363 return (1); 364 } 365 366 return (0); 367 } 368 369 void 370 mbe_pcmcia_disable(sc) 371 struct mb86960_softc *sc; 372 { 373 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 374 375 pcmcia_function_disable(psc->sc_pf); 376 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 377 } 378 379 int 380 mbe_pcmcia_get_enaddr_from_cis(tuple, arg) 381 struct pcmcia_tuple *tuple; 382 void *arg; 383 { 384 struct mbe_pcmcia_get_enaddr_args *p = arg; 385 int i; 386 387 if (tuple->code == PCMCIA_CISTPL_FUNCE) { 388 if (tuple->length < 2) /* sub code and ether addr length */ 389 return (0); 390 391 if ((pcmcia_tuple_read_1(tuple, 0) != 392 PCMCIA_TPLFE_TYPE_LAN_NID) || 393 (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)) 394 return (0); 395 396 for (i = 0; i < ETHER_ADDR_LEN; i++) 397 p->enaddr[i] = pcmcia_tuple_read_1(tuple, i + 2); 398 return (1); 399 } 400 return (0); 401 } 402 403 int 404 mbe_pcmcia_get_enaddr_from_io(psc, ea) 405 struct mbe_pcmcia_softc *psc; 406 struct mbe_pcmcia_get_enaddr_args *ea; 407 { 408 int i; 409 410 for (i = 0; i < ETHER_ADDR_LEN; i++) 411 ea->enaddr[i] = bus_space_read_1(psc->sc_pcioh.iot, 412 psc->sc_pcioh.ioh, FE_MBH_ENADDR + i); 413 414 if (ea->enaddr == NULL) 415 return (1); 416 return (0); 417 } 418 419 int 420 mbe_pcmcia_get_enaddr_from_mem(psc, ea) 421 struct mbe_pcmcia_softc *psc; 422 struct mbe_pcmcia_get_enaddr_args *ea; 423 { 424 struct mb86960_softc *sc = &psc->sc_mb86960; 425 struct pcmcia_mem_handle pcmh; 426 bus_size_t offset; 427 int i, mwindow, rv = 1; 428 429 if (ea->maddr < 0) 430 goto bad_memaddr; 431 432 if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) { 433 printf("%s: can't alloc mem for enet addr\n", 434 sc->sc_dev.dv_xname); 435 goto memalloc_failed; 436 } 437 438 if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, ea->maddr, 439 ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) { 440 printf("%s: can't map mem for enet addr\n", 441 sc->sc_dev.dv_xname); 442 goto memmap_failed; 443 } 444 445 for (i = 0; i < ETHER_ADDR_LEN; i++) 446 ea->enaddr[i] = bus_space_read_1(pcmh.memt, pcmh.memh, 447 offset + (i * 2)); 448 449 rv = 0; 450 pcmcia_mem_unmap(psc->sc_pf, mwindow); 451 memmap_failed: 452 pcmcia_mem_free(psc->sc_pf, &pcmh); 453 memalloc_failed: 454 bad_memaddr: 455 456 return (rv); 457 } 458