1/* $NetBSD: if_mbe_pcmcia.c,v 1.45 2008/04/28 20:23:56 martin 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: if_mbe_pcmcia.c,v 1.45 2008/04/28 20:23:56 martin Exp $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/device.h> 38#include <sys/socket.h> 39 40#include <net/if.h> 41#include <net/if_ether.h> 42#include <net/if_media.h> 43 44#include <sys/intr.h> 45#include <sys/bus.h> 46 47#include <dev/ic/mb86960reg.h> 48#include <dev/ic/mb86960var.h> 49 50#include <dev/pcmcia/pcmciareg.h> 51#include <dev/pcmcia/pcmciavar.h> 52#include <dev/pcmcia/pcmciadevs.h> 53 54int mbe_pcmcia_match(device_t, cfdata_t, void *); 55int mbe_pcmcia_validate_config(struct pcmcia_config_entry *); 56void mbe_pcmcia_attach(device_t, device_t, void *); 57int mbe_pcmcia_detach(device_t, int); 58 59struct mbe_pcmcia_softc { 60 struct mb86960_softc sc_mb86960; /* real "mb" softc */ 61 62 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 63 void *sc_ih; /* interrupt cookie */ 64 65 int sc_state; 66#define MBE_PCMCIA_ATTACHED 3 67}; 68 69CFATTACH_DECL_NEW(mbe_pcmcia, sizeof(struct mbe_pcmcia_softc), 70 mbe_pcmcia_match, mbe_pcmcia_attach, mbe_pcmcia_detach, mb86960_activate); 71 72int mbe_pcmcia_enable(struct mb86960_softc *); 73void mbe_pcmcia_disable(struct mb86960_softc *); 74 75struct mbe_pcmcia_get_enaddr_args { 76 uint8_t enaddr[ETHER_ADDR_LEN]; 77 int maddr; 78}; 79int mbe_pcmcia_get_enaddr_from_cis(struct pcmcia_tuple *, void *); 80int mbe_pcmcia_get_enaddr_from_mem(struct mbe_pcmcia_softc *, 81 struct mbe_pcmcia_get_enaddr_args *); 82int mbe_pcmcia_get_enaddr_from_io(struct mbe_pcmcia_softc *, 83 struct mbe_pcmcia_get_enaddr_args *); 84 85static const struct mbe_pcmcia_product { 86 struct pcmcia_product mpp_product; 87 int mpp_enet_maddr; 88 int mpp_flags; 89#define MBH10302 0x0001 /* FUJITSU MBH10302 */ 90} mbe_pcmcia_products[] = { 91 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CD021BX, 92 PCMCIA_CIS_TDK_LAK_CD021BX }, 93 -1, 0 }, 94 95 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CF010, 96 PCMCIA_CIS_TDK_LAK_CF010 }, 97 -1, 0 }, 98 99#if 0 /* XXX 86960-based? */ 100 { { PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_DFL9610, 101 PCMCIA_CIS_TDK_DFL9610 }, 102 -1, MBH10302 /* XXX */ }, 103#endif 104 105 { { PCMCIA_VENDOR_CONTEC, PCMCIA_PRODUCT_CONTEC_CNETPC, 106 PCMCIA_CIS_CONTEC_CNETPC }, 107 -1, 0 }, 108 109 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA501, 110 PCMCIA_CIS_FUJITSU_LA501 }, 111 -1, 0 }, 112 113 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J181, 114 PCMCIA_CIS_FUJITSU_FMV_J181 }, 115 -1, MBH10302 }, 116 117 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J182, 118 PCMCIA_CIS_FUJITSU_FMV_J182 }, 119 0xf2c, 0 }, 120 121 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_FMV_J182A, 122 PCMCIA_CIS_FUJITSU_FMV_J182A }, 123 0x1cc, 0 }, 124 125 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_ITCFJ182A, 126 PCMCIA_CIS_FUJITSU_ITCFJ182A }, 127 0x1cc, 0 }, 128 129 { { PCMCIA_VENDOR_FUJITSU, PCMCIA_PRODUCT_FUJITSU_LA10S, 130 PCMCIA_CIS_FUJITSU_LA10S }, 131 -1, 0 }, 132 133 { { PCMCIA_VENDOR_RATOC, PCMCIA_PRODUCT_RATOC_REX_R280, 134 PCMCIA_CIS_RATOC_REX_R280 }, 135 0x1fc, 0 }, 136}; 137static const size_t mbe_pcmcia_nproducts = __arraycount(mbe_pcmcia_products); 138 139int 140mbe_pcmcia_match(device_t parent, cfdata_t cf, void *aux) 141{ 142 struct pcmcia_attach_args *pa = aux; 143 144 if (pcmcia_product_lookup(pa, mbe_pcmcia_products, mbe_pcmcia_nproducts, 145 sizeof(mbe_pcmcia_products[0]), NULL)) 146 return 1; 147 return 0; 148} 149 150int 151mbe_pcmcia_validate_config(struct pcmcia_config_entry *cfe) 152{ 153 154 if (cfe->iftype != PCMCIA_IFTYPE_IO || 155 cfe->num_iospace < 1) 156 return EINVAL; 157 return 0; 158} 159 160void 161mbe_pcmcia_attach(device_t parent, device_t self, void *aux) 162{ 163 struct mbe_pcmcia_softc *psc = device_private(self); 164 struct mb86960_softc *sc = &psc->sc_mb86960; 165 struct pcmcia_attach_args *pa = aux; 166 struct pcmcia_config_entry *cfe; 167 struct mbe_pcmcia_get_enaddr_args pgea; 168 const struct mbe_pcmcia_product *mpp; 169 int error; 170 171 sc->sc_dev = self; 172 psc->sc_pf = pa->pf; 173 174 error = pcmcia_function_configure(pa->pf, mbe_pcmcia_validate_config); 175 if (error) { 176 aprint_error_dev(self, "configure failed, error=%d\n", 177 error); 178 return; 179 } 180 181 cfe = pa->pf->cfe; 182 sc->sc_bst = cfe->iospace[0].handle.iot; 183 sc->sc_bsh = cfe->iospace[0].handle.ioh; 184 185 mpp = pcmcia_product_lookup(pa, mbe_pcmcia_products, 186 mbe_pcmcia_nproducts, sizeof(mbe_pcmcia_products[0]), NULL); 187 if (!mpp) 188 panic("%s: impossible", __func__); 189 190 /* Read station address from io/mem or CIS. */ 191 if (mpp->mpp_enet_maddr >= 0) { 192 pgea.maddr = mpp->mpp_enet_maddr; 193 if (mbe_pcmcia_get_enaddr_from_mem(psc, &pgea) != 0) { 194 aprint_error_dev(self, "couldn't get ethernet address " 195 "from memory\n"); 196 goto fail; 197 } 198 } else if (mpp->mpp_flags & MBH10302) { 199 bus_space_write_1(sc->sc_bst, sc->sc_bsh, FE_MBH0 , 200 FE_MBH0_MASK | FE_MBH0_INTR_ENABLE); 201 if (mbe_pcmcia_get_enaddr_from_io(psc, &pgea) != 0) { 202 aprint_error_dev(self, 203 "couldn't get ethernet address from i/o\n"); 204 goto fail; 205 } 206 } else { 207 if (pa->pf->pf_funce_lan_nidlen != ETHER_ADDR_LEN) { 208 aprint_error_dev(self, 209 "couldn't get ethernet address from CIS\n"); 210 goto fail; 211 } 212 memcpy(pgea.enaddr, pa->pf->pf_funce_lan_nid, ETHER_ADDR_LEN); 213 } 214 215 /* Perform generic initialization. */ 216 if (mpp->mpp_flags & MBH10302) 217 sc->sc_flags |= FE_FLAGS_MB86960; 218 219 sc->sc_enable = mbe_pcmcia_enable; 220 sc->sc_disable = mbe_pcmcia_disable; 221 222 error = mbe_pcmcia_enable(sc); 223 if (error) 224 goto fail; 225 226 mb86960_attach(sc, pgea.enaddr); 227 mb86960_config(sc, NULL, 0, 0); 228 229 mbe_pcmcia_disable(sc); 230 psc->sc_state = MBE_PCMCIA_ATTACHED; 231 return; 232 233fail: 234 pcmcia_function_unconfigure(pa->pf); 235} 236 237int 238mbe_pcmcia_detach(device_t self, int flags) 239{ 240 struct mbe_pcmcia_softc *psc = device_private(self); 241 int error; 242 243 if (psc->sc_state != MBE_PCMCIA_ATTACHED) 244 return 0; 245 246 error = mb86960_detach(&psc->sc_mb86960); 247 if (error) 248 return error; 249 250 pcmcia_function_unconfigure(psc->sc_pf); 251 252 return 0; 253} 254 255int 256mbe_pcmcia_enable(struct mb86960_softc *sc) 257{ 258 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 259 int error; 260 261 /* Establish the interrupt handler. */ 262 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, mb86960_intr, 263 sc); 264 if (!psc->sc_ih) 265 return EIO; 266 267 error = pcmcia_function_enable(psc->sc_pf); 268 if (error) { 269 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 270 psc->sc_ih = 0; 271 } 272 273 return error; 274} 275 276void 277mbe_pcmcia_disable(struct mb86960_softc *sc) 278{ 279 struct mbe_pcmcia_softc *psc = (struct mbe_pcmcia_softc *)sc; 280 281 pcmcia_function_disable(psc->sc_pf); 282 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 283 psc->sc_ih = 0; 284} 285 286int 287mbe_pcmcia_get_enaddr_from_io(struct mbe_pcmcia_softc *psc, 288 struct mbe_pcmcia_get_enaddr_args *ea) 289{ 290 struct mb86960_softc *sc = &psc->sc_mb86960; 291 int i; 292 293 for (i = 0; i < ETHER_ADDR_LEN; i++) 294 ea->enaddr[i] = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 295 FE_MBH_ENADDR + i); 296 return 0; 297} 298 299int 300mbe_pcmcia_get_enaddr_from_mem(struct mbe_pcmcia_softc *psc, 301 struct mbe_pcmcia_get_enaddr_args *ea) 302{ 303 struct mb86960_softc *sc = &psc->sc_mb86960; 304 struct pcmcia_mem_handle pcmh; 305 bus_size_t offset; 306 int i, mwindow, rv = 1; 307 308 if (ea->maddr < 0) 309 goto bad_memaddr; 310 311 if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) { 312 aprint_error_dev(sc->sc_dev, "can't alloc mem for enet addr\n"); 313 goto memalloc_failed; 314 } 315 316 if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, ea->maddr, 317 ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) { 318 aprint_error_dev(sc->sc_dev, "can't map mem for enet addr\n"); 319 goto memmap_failed; 320 } 321 322 for (i = 0; i < ETHER_ADDR_LEN; i++) 323 ea->enaddr[i] = bus_space_read_1(pcmh.memt, pcmh.memh, 324 offset + (i * 2)); 325 326 rv = 0; 327 pcmcia_mem_unmap(psc->sc_pf, mwindow); 328memmap_failed: 329 pcmcia_mem_free(psc->sc_pf, &pcmh); 330memalloc_failed: 331bad_memaddr: 332 333 return rv; 334} 335