1/* $NetBSD: if_cs_pcmcia.c,v 1.18 2009/05/12 14:42:18 cegger Exp $ */ 2 3/*- 4 * Copyright (c)2001 YAMAMOTO Takashi, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: if_cs_pcmcia.c,v 1.18 2009/05/12 14:42:18 cegger Exp $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/device.h> 35#include <sys/socket.h> 36#include <sys/queue.h> 37 38#include <sys/rnd.h> 39 40#include <net/if.h> 41#include <net/if_ether.h> 42#include <net/if_media.h> 43 44#include <sys/bus.h> 45#include <sys/intr.h> 46 47#include <dev/pcmcia/pcmciareg.h> 48#include <dev/pcmcia/pcmciavar.h> 49#include <dev/pcmcia/pcmciadevs.h> 50 51#include <dev/ic/cs89x0reg.h> 52#include <dev/ic/cs89x0var.h> 53 54struct cs_pcmcia_softc; 55 56static int cs_pcmcia_match(device_t, cfdata_t, void *); 57static int cs_pcmcia_validate_config(struct pcmcia_config_entry *); 58static void cs_pcmcia_attach(device_t, device_t, void *); 59static int cs_pcmcia_detach(device_t, int); 60static int cs_pcmcia_enable(struct cs_softc *); 61static void cs_pcmcia_disable(struct cs_softc *); 62 63struct cs_pcmcia_softc { 64 struct cs_softc sc_cs; /* real "cs" softc */ 65 66 struct pcmcia_function *sc_pf; 67 68 int sc_state; 69#define CS_PCMCIA_ATTACHED 3 70}; 71 72CFATTACH_DECL(cs_pcmcia, sizeof(struct cs_pcmcia_softc), 73 cs_pcmcia_match, cs_pcmcia_attach, cs_pcmcia_detach, cs_activate); 74 75static int 76cs_pcmcia_match(device_t parent, cfdata_t match, 77 void *aux) 78{ 79 struct pcmcia_attach_args *pa = aux; 80 81 if (pa->manufacturer == PCMCIA_VENDOR_IBM && 82 pa->product == PCMCIA_PRODUCT_IBM_ETHERJET) 83 return (1); 84 return (0); 85} 86 87static int 88cs_pcmcia_validate_config(struct pcmcia_config_entry *cfe) 89{ 90 if (cfe->iftype != PCMCIA_IFTYPE_IO || 91 cfe->num_memspace != 0 || 92 cfe->num_iospace != 1 || 93 cfe->iospace[0].length < CS8900_IOSIZE) 94 return (EINVAL); 95 return (0); 96} 97 98static void 99cs_pcmcia_attach(device_t parent, device_t self, void *aux) 100{ 101 struct cs_pcmcia_softc *psc = (void *)self; 102 struct cs_softc *sc = (void *)&psc->sc_cs; 103 struct pcmcia_attach_args *pa = aux; 104 struct pcmcia_config_entry *cfe; 105 struct pcmcia_function *pf; 106 int error; 107 108 pf = psc->sc_pf = pa->pf; 109 110 error = pcmcia_function_configure(pa->pf, cs_pcmcia_validate_config); 111 if (error) { 112 aprint_error_dev(self, "configure failed, error=%d\n", 113 error); 114 return; 115 } 116 117 cfe = pf->cfe; 118 sc->sc_iot = cfe->iospace[0].handle.iot; 119 sc->sc_ioh = cfe->iospace[0].handle.ioh; 120 sc->sc_irq = -1; 121#define CS_PCMCIA_HACK_FOR_CARDBUS 122#ifdef CS_PCMCIA_HACK_FOR_CARDBUS 123 /* 124 * XXX is there a generic way to know if it's a cardbus or not? 125 */ 126 sc->sc_cfgflags |= CFGFLG_CARDBUS_HACK; 127#endif 128 129 error = cs_pcmcia_enable(sc); 130 if (error) 131 goto fail; 132 133 sc->sc_enable = cs_pcmcia_enable; 134 sc->sc_disable = cs_pcmcia_disable; 135 136 /* chip attach */ 137 error = cs_attach(sc, 0, 0, 0, 0); 138 if (error) 139 goto fail2; 140 141 cs_pcmcia_disable(sc); 142 psc->sc_state = CS_PCMCIA_ATTACHED; 143 return; 144 145fail2: 146 cs_pcmcia_disable(sc); 147fail: 148 pcmcia_function_unconfigure(pf); 149} 150 151static int 152cs_pcmcia_detach(device_t self, int flags) 153{ 154 struct cs_pcmcia_softc *psc = (void *)self; 155 struct cs_softc *sc = &psc->sc_cs; 156 int error; 157 158 if (psc->sc_state != CS_PCMCIA_ATTACHED) 159 return (0); 160 161 error = cs_detach(sc); 162 if (error) 163 return (error); 164 165 pcmcia_function_unconfigure(psc->sc_pf); 166 167 return (0); 168} 169 170static int 171cs_pcmcia_enable(struct cs_softc *sc) 172{ 173 struct cs_pcmcia_softc *psc = (void *)sc; 174 int error; 175 176 sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, cs_intr, sc); 177 if (!sc->sc_ih) 178 return (EIO); 179 180 error = pcmcia_function_enable(psc->sc_pf); 181 if (error) { 182 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 183 sc->sc_ih = 0; 184 } 185 186 return (error); 187} 188 189static void 190cs_pcmcia_disable(struct cs_softc *sc) 191{ 192 struct cs_pcmcia_softc *psc = (void *)sc; 193 194 pcmcia_function_disable(psc->sc_pf); 195 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); 196 sc->sc_ih = 0; 197} 198