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