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