1 /* $NetBSD: if_mbe_pcmcia.c,v 1.42 2007/10/19 12:01:04 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000, 2004 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.42 2007/10/19 12:01:04 ad 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 <sys/intr.h> 52 #include <sys/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(struct device *, struct cfdata *, void *); 62 int mbe_pcmcia_validate_config(struct pcmcia_config_entry *); 63 void mbe_pcmcia_attach(struct device *, struct device *, void *); 64 int mbe_pcmcia_detach(struct device *, int); 65 66 struct mbe_pcmcia_softc { 67 struct mb86960_softc sc_mb86960; /* real "mb" softc */ 68 69 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 70 void *sc_ih; /* interrupt cookie */ 71 72 int sc_state; 73 #define MBE_PCMCIA_ATTACHED 3 74 }; 75 76 CFATTACH_DECL(mbe_pcmcia, sizeof(struct mbe_pcmcia_softc), 77 mbe_pcmcia_match, mbe_pcmcia_attach, mbe_pcmcia_detach, mb86960_activate); 78 79 int mbe_pcmcia_enable(struct mb86960_softc *); 80 void mbe_pcmcia_disable(struct mb86960_softc *); 81 82 struct mbe_pcmcia_get_enaddr_args { 83 u_int8_t enaddr[ETHER_ADDR_LEN]; 84 int maddr; 85 }; 86 int mbe_pcmcia_get_enaddr_from_cis(struct pcmcia_tuple *, void *); 87 int mbe_pcmcia_get_enaddr_from_mem(struct mbe_pcmcia_softc *, 88 struct mbe_pcmcia_get_enaddr_args *); 89 int mbe_pcmcia_get_enaddr_from_io(struct mbe_pcmcia_softc *, 90 struct mbe_pcmcia_get_enaddr_args *); 91 92 static const struct mbe_pcmcia_product { 93 struct pcmcia_product mpp_product; 94 int mpp_enet_maddr; 95 int mpp_flags; 96 #define MBH10302 0x0001 /* FUJITSU MBH10302 */ 97 } mbe_pcmcia_products[] = { 98 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CD021BX, 99 PCMCIA_CIS_TDK_LAK_CD021BX }, 100 -1, 0 }, 101 102 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CF010, 103 PCMCIA_CIS_TDK_LAK_CF010 }, 104 -1, 0 }, 105 106 #if 0 /* XXX 86960-based? */ 107 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_DFL9610, 108 PCMCIA_CIS_TDK_DFL9610 }, 109 -1, MBH10302 /* XXX */ }, 110 #endif 111 112 { { PCMCIA_VENDOR_CONTEC, PCMCIA_PRODUCT_CONTEC_CNETPC, 113 PCMCIA_CIS_CONTEC_CNETPC }, 114 -1, 0 }, 115 116 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA501, 117 PCMCIA_CIS_FUJITSU_LA501 }, 118 -1, 0 }, 119 120 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J181, 121 PCMCIA_CIS_FUJITSU_FMV_J181 }, 122 -1, MBH10302 }, 123 124 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J182, 125 PCMCIA_CIS_FUJITSU_FMV_J182 }, 126 0xf2c, 0 }, 127 128 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J182A, 129 PCMCIA_CIS_FUJITSU_FMV_J182A }, 130 0x1cc, 0 }, 131 132 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_ITCFJ182A, 133 PCMCIA_CIS_FUJITSU_ITCFJ182A }, 134 0x1cc, 0 }, 135 136 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA10S, 137 PCMCIA_CIS_FUJITSU_LA10S }, 138 -1, 0 }, 139 140 { { PCMCIA_VENDOR_RATOC, PCMCIA_PRODUCT_RATOC_REX_R280, 141 PCMCIA_CIS_RATOC_REX_R280 }, 142 0x1fc, 0 }, 143 }; 144 static const size_t mbe_pcmcia_nproducts = 145 sizeof(mbe_pcmcia_products) / sizeof(mbe_pcmcia_products[0]); 146 147 int 148 mbe_pcmcia_match(struct device *parent, struct cfdata *match, 149 void *aux) 150 { 151 struct pcmcia_attach_args *pa = aux; 152 153 if (pcmcia_product_lookup(pa, mbe_pcmcia_products, mbe_pcmcia_nproducts, 154 sizeof(mbe_pcmcia_products[0]), NULL)) 155 return (1); 156 return (0); 157 } 158 159 int 160 mbe_pcmcia_validate_config(cfe) 161 struct pcmcia_config_entry *cfe; 162 { 163 if (cfe->iftype != PCMCIA_IFTYPE_IO || 164 cfe->num_iospace < 1) 165 return (EINVAL); 166 return (0); 167 } 168 169 void 170 mbe_pcmcia_attach(struct device *parent, struct device *self, 171 void *aux) 172 { 173 struct mbe_pcmcia_softc *psc = (void *)self; 174 struct mb86960_softc *sc = &psc->sc_mb86960; 175 struct pcmcia_attach_args *pa = aux; 176 struct pcmcia_config_entry *cfe; 177 struct mbe_pcmcia_get_enaddr_args pgea; 178 const struct mbe_pcmcia_product *mpp; 179 int error; 180 181 psc->sc_pf = pa->pf; 182 183 error = pcmcia_function_configure(pa->pf, mbe_pcmcia_validate_config); 184 if (error) { 185 aprint_error("%s: configure failed, error=%d\n", self->dv_xname, 186 error); 187 return; 188 } 189 190 cfe = pa->pf->cfe; 191 sc->sc_bst = cfe->iospace[0].handle.iot; 192 sc->sc_bsh = cfe->iospace[0].handle.ioh; 193 194 mpp = pcmcia_product_lookup(pa, mbe_pcmcia_products, 195 mbe_pcmcia_nproducts, sizeof(mbe_pcmcia_products[0]), NULL); 196 if (!mpp) 197 panic("mbe_pcmcia_attach: impossible"); 198 199 /* Read station address from io/mem or CIS. */ 200 if (mpp->mpp_enet_maddr >= 0) { 201 pgea.maddr = mpp->mpp_enet_maddr; 202 if (mbe_pcmcia_get_enaddr_from_mem(psc, &pgea) != 0) { 203 printf("%s: couldn't get ethernet address " 204 "from memory\n", self->dv_xname); 205 goto fail; 206 } 207 } else if (mpp->mpp_flags & MBH10302) { 208 bus_space_write_1(sc->sc_bst, sc->sc_bsh, FE_MBH0 , 209 FE_MBH0_MASK | FE_MBH0_INTR_ENABLE); 210 if (mbe_pcmcia_get_enaddr_from_io(psc, &pgea) != 0) { 211 printf("%s: couldn't get ethernet address from i/o\n", 212 self->dv_xname); 213 goto fail; 214 } 215 } else { 216 if (pa->pf->pf_funce_lan_nidlen != ETHER_ADDR_LEN) { 217 printf("%s: couldn't get ethernet address from CIS\n", 218 self->dv_xname); 219 goto fail; 220 } 221 memcpy(pgea.enaddr, pa->pf->pf_funce_lan_nid, ETHER_ADDR_LEN); 222 } 223 224 /* Perform generic initialization. */ 225 if (mpp->mpp_flags & MBH10302) 226 sc->sc_flags |= FE_FLAGS_MB86960; 227 228 sc->sc_enable = mbe_pcmcia_enable; 229 sc->sc_disable = mbe_pcmcia_disable; 230 231 error = mbe_pcmcia_enable(sc); 232 if (error) 233 goto fail; 234 235 mb86960_attach(sc, pgea.enaddr); 236 mb86960_config(sc, NULL, 0, 0); 237 238 mbe_pcmcia_disable(sc); 239 psc->sc_state = MBE_PCMCIA_ATTACHED; 240 return; 241 242 fail: 243 pcmcia_function_unconfigure(pa->pf); 244 } 245 246 int 247 mbe_pcmcia_detach(struct device *self, int flags) 248 { 249 struct mbe_pcmcia_softc *psc = (void *)self; 250 int error; 251 252 if (psc->sc_state != MBE_PCMCIA_ATTACHED) 253 return (0); 254 255 error = mb86960_detach(&psc->sc_mb86960); 256 if (error) 257 return (error); 258 259 pcmcia_function_unconfigure(psc->sc_pf); 260 261 return (0); 262 } 263 264 int 265 mbe_pcmcia_enable(sc) 266 struct mb86960_softc *sc; 267 { 268 struct mbe_pcmcia_softc *psc = (void *)sc; 269 int error; 270 271 /* Establish the interrupt handler. */ 272 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, mb86960_intr, 273 sc); 274 if (!psc->sc_ih) 275 return (EIO); 276 277 error = pcmcia_function_enable(psc->sc_pf); 278 if (error) { 279 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 280 psc->sc_ih = 0; 281 } 282 283 return (error); 284 } 285 286 void 287 mbe_pcmcia_disable(sc) 288 struct mb86960_softc *sc; 289 { 290 struct mbe_pcmcia_softc *psc = (void *)sc; 291 292 pcmcia_function_disable(psc->sc_pf); 293 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 294 psc->sc_ih = 0; 295 } 296 297 int 298 mbe_pcmcia_get_enaddr_from_io(psc, ea) 299 struct mbe_pcmcia_softc *psc; 300 struct mbe_pcmcia_get_enaddr_args *ea; 301 { 302 struct mb86960_softc *sc = &psc->sc_mb86960; 303 int i; 304 305 for (i = 0; i < ETHER_ADDR_LEN; i++) 306 ea->enaddr[i] = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 307 FE_MBH_ENADDR + i); 308 return (0); 309 } 310 311 int 312 mbe_pcmcia_get_enaddr_from_mem(psc, ea) 313 struct mbe_pcmcia_softc *psc; 314 struct mbe_pcmcia_get_enaddr_args *ea; 315 { 316 struct mb86960_softc *sc = &psc->sc_mb86960; 317 struct pcmcia_mem_handle pcmh; 318 bus_size_t offset; 319 int i, mwindow, rv = 1; 320 321 if (ea->maddr < 0) 322 goto bad_memaddr; 323 324 if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) { 325 printf("%s: can't alloc mem for enet addr\n", 326 sc->sc_dev.dv_xname); 327 goto memalloc_failed; 328 } 329 330 if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, ea->maddr, 331 ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) { 332 printf("%s: can't map mem for enet addr\n", 333 sc->sc_dev.dv_xname); 334 goto memmap_failed; 335 } 336 337 for (i = 0; i < ETHER_ADDR_LEN; i++) 338 ea->enaddr[i] = bus_space_read_1(pcmh.memt, pcmh.memh, 339 offset + (i * 2)); 340 341 rv = 0; 342 pcmcia_mem_unmap(psc->sc_pf, mwindow); 343 memmap_failed: 344 pcmcia_mem_free(psc->sc_pf, &pcmh); 345 memalloc_failed: 346 bad_memaddr: 347 348 return (rv); 349 } 350