1 /* $NetBSD: if_mbe_pcmcia.c,v 1.38 2005/12/11 12:23:23 christos 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.38 2005/12/11 12:23:23 christos 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(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 }, 101 102 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CF010, 103 PCMCIA_CIS_TDK_LAK_CF010 }, 104 -1 }, 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 }, 115 116 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA501, 117 PCMCIA_CIS_FUJITSU_LA501 }, 118 -1 }, 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 }, 127 128 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J182A, 129 PCMCIA_CIS_FUJITSU_FMV_J182A }, 130 0x1cc }, 131 132 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_ITCFJ182A, 133 PCMCIA_CIS_FUJITSU_ITCFJ182A }, 134 0x1cc }, 135 136 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA10S, 137 PCMCIA_CIS_FUJITSU_LA10S }, 138 -1 }, 139 140 { { PCMCIA_VENDOR_RATOC, PCMCIA_PRODUCT_RATOC_REX_R280, 141 PCMCIA_CIS_RATOC_REX_R280 }, 142 0x1fc }, 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(parent, match, aux) 149 struct device *parent; 150 struct cfdata *match; 151 void *aux; 152 { 153 struct pcmcia_attach_args *pa = aux; 154 155 if (pcmcia_product_lookup(pa, mbe_pcmcia_products, mbe_pcmcia_nproducts, 156 sizeof(mbe_pcmcia_products[0]), NULL)) 157 return (1); 158 return (0); 159 } 160 161 int 162 mbe_pcmcia_validate_config(cfe) 163 struct pcmcia_config_entry *cfe; 164 { 165 if (cfe->iftype != PCMCIA_IFTYPE_IO || 166 cfe->num_iospace < 1) 167 return (EINVAL); 168 return (0); 169 } 170 171 void 172 mbe_pcmcia_attach(parent, self, aux) 173 struct device *parent, *self; 174 void *aux; 175 { 176 struct mbe_pcmcia_softc *psc = (void *)self; 177 struct mb86960_softc *sc = &psc->sc_mb86960; 178 struct pcmcia_attach_args *pa = aux; 179 struct pcmcia_config_entry *cfe; 180 struct mbe_pcmcia_get_enaddr_args pgea; 181 const struct mbe_pcmcia_product *mpp; 182 int error; 183 184 psc->sc_pf = pa->pf; 185 186 error = pcmcia_function_configure(pa->pf, mbe_pcmcia_validate_config); 187 if (error) { 188 aprint_error("%s: configure failed, error=%d\n", self->dv_xname, 189 error); 190 return; 191 } 192 193 cfe = pa->pf->cfe; 194 sc->sc_bst = cfe->iospace[0].handle.iot; 195 sc->sc_bsh = cfe->iospace[0].handle.ioh; 196 197 mpp = pcmcia_product_lookup(pa, mbe_pcmcia_products, 198 mbe_pcmcia_nproducts, sizeof(mbe_pcmcia_products[0]), NULL); 199 if (!mpp) 200 panic("mbe_pcmcia_attach: impossible"); 201 202 /* Read station address from io/mem or CIS. */ 203 if (mpp->mpp_enet_maddr >= 0) { 204 pgea.maddr = mpp->mpp_enet_maddr; 205 if (mbe_pcmcia_get_enaddr_from_mem(psc, &pgea) != 0) { 206 printf("%s: couldn't get ethernet address " 207 "from memory\n", self->dv_xname); 208 goto fail; 209 } 210 } else if (mpp->mpp_flags & MBH10302) { 211 bus_space_write_1(sc->sc_bst, sc->sc_bsh, FE_MBH0 , 212 FE_MBH0_MASK | FE_MBH0_INTR_ENABLE); 213 if (mbe_pcmcia_get_enaddr_from_io(psc, &pgea) != 0) { 214 printf("%s: couldn't get ethernet address from i/o\n", 215 self->dv_xname); 216 goto fail; 217 } 218 } else { 219 if (pa->pf->pf_funce_lan_nidlen != ETHER_ADDR_LEN) { 220 printf("%s: couldn't get ethernet address from CIS\n", 221 self->dv_xname); 222 goto fail; 223 } 224 memcpy(pgea.enaddr, pa->pf->pf_funce_lan_nid, ETHER_ADDR_LEN); 225 } 226 227 /* Perform generic initialization. */ 228 if (mpp->mpp_flags & MBH10302) 229 sc->sc_flags |= FE_FLAGS_MB86960; 230 231 sc->sc_enable = mbe_pcmcia_enable; 232 sc->sc_disable = mbe_pcmcia_disable; 233 234 error = mbe_pcmcia_enable(sc); 235 if (error) 236 goto fail; 237 238 mb86960_attach(sc, pgea.enaddr); 239 mb86960_config(sc, NULL, 0, 0); 240 241 mbe_pcmcia_disable(sc); 242 psc->sc_state = MBE_PCMCIA_ATTACHED; 243 return; 244 245 fail: 246 pcmcia_function_unconfigure(pa->pf); 247 } 248 249 int 250 mbe_pcmcia_detach(self, flags) 251 struct device *self; 252 int flags; 253 { 254 struct mbe_pcmcia_softc *psc = (void *)self; 255 int error; 256 257 if (psc->sc_state != MBE_PCMCIA_ATTACHED) 258 return (0); 259 260 error = mb86960_detach(&psc->sc_mb86960); 261 if (error) 262 return (error); 263 264 pcmcia_function_unconfigure(psc->sc_pf); 265 266 return (0); 267 } 268 269 int 270 mbe_pcmcia_enable(sc) 271 struct mb86960_softc *sc; 272 { 273 struct mbe_pcmcia_softc *psc = (void *)sc; 274 int error; 275 276 /* Establish the interrupt handler. */ 277 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, mb86960_intr, 278 sc); 279 if (!psc->sc_ih) 280 return (EIO); 281 282 error = pcmcia_function_enable(psc->sc_pf); 283 if (error) { 284 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 285 psc->sc_ih = 0; 286 } 287 288 return (error); 289 } 290 291 void 292 mbe_pcmcia_disable(sc) 293 struct mb86960_softc *sc; 294 { 295 struct mbe_pcmcia_softc *psc = (void *)sc; 296 297 pcmcia_function_disable(psc->sc_pf); 298 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 299 psc->sc_ih = 0; 300 } 301 302 int 303 mbe_pcmcia_get_enaddr_from_io(psc, ea) 304 struct mbe_pcmcia_softc *psc; 305 struct mbe_pcmcia_get_enaddr_args *ea; 306 { 307 struct mb86960_softc *sc = &psc->sc_mb86960; 308 int i; 309 310 for (i = 0; i < ETHER_ADDR_LEN; i++) 311 ea->enaddr[i] = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 312 FE_MBH_ENADDR + i); 313 return (0); 314 } 315 316 int 317 mbe_pcmcia_get_enaddr_from_mem(psc, ea) 318 struct mbe_pcmcia_softc *psc; 319 struct mbe_pcmcia_get_enaddr_args *ea; 320 { 321 struct mb86960_softc *sc = &psc->sc_mb86960; 322 struct pcmcia_mem_handle pcmh; 323 bus_size_t offset; 324 int i, mwindow, rv = 1; 325 326 if (ea->maddr < 0) 327 goto bad_memaddr; 328 329 if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) { 330 printf("%s: can't alloc mem for enet addr\n", 331 sc->sc_dev.dv_xname); 332 goto memalloc_failed; 333 } 334 335 if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, ea->maddr, 336 ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) { 337 printf("%s: can't map mem for enet addr\n", 338 sc->sc_dev.dv_xname); 339 goto memmap_failed; 340 } 341 342 for (i = 0; i < ETHER_ADDR_LEN; i++) 343 ea->enaddr[i] = bus_space_read_1(pcmh.memt, pcmh.memh, 344 offset + (i * 2)); 345 346 rv = 0; 347 pcmcia_mem_unmap(psc->sc_pf, mwindow); 348 memmap_failed: 349 pcmcia_mem_free(psc->sc_pf, &pcmh); 350 memalloc_failed: 351 bad_memaddr: 352 353 return (rv); 354 } 355