xref: /openbsd/sys/dev/pcmcia/if_wi_pcmcia.c (revision fd84ef7e)
1 /* $OpenBSD: if_wi_pcmcia.c,v 1.15 2001/12/05 21:04:11 mickey Exp $ */
2 /* $NetBSD: if_wi_pcmcia.c,v 1.14 2001/11/26 04:34:56 ichiro Exp $ */
3 
4 /*
5  * Copyright (c) 1997, 1998, 1999
6  *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by Bill Paul.
19  * 4. Neither the name of the author nor the names of any co-contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  *	From: if_wi.c,v 1.7 1999/07/04 14:40:22 wpaul Exp $
36  */
37 
38 /*
39  * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for OpenBSD.
40  *
41  * Originally written by Bill Paul <wpaul@ctr.columbia.edu>
42  * Electrical Engineering Department
43  * Columbia University, New York City
44  */
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/timeout.h>
49 #include <sys/socket.h>
50 #include <sys/device.h>
51 
52 #include <net/if.h>
53 #include <net/if_dl.h>
54 #include <net/if_media.h>
55 
56 #ifdef INET
57 #include <netinet/in.h>
58 #include <netinet/if_ether.h>
59 #endif
60 
61 #include <net/if_ieee80211.h>
62 
63 #include <machine/bus.h>
64 
65 #include <dev/pcmcia/pcmciareg.h>
66 #include <dev/pcmcia/pcmciavar.h>
67 #include <dev/pcmcia/pcmciadevs.h>
68 
69 #include <dev/ic/if_wireg.h>
70 #include <dev/ic/if_wi_ieee.h>
71 #include <dev/ic/if_wivar.h>
72 
73 int	wi_pcmcia_match		__P((struct device *, void *, void *));
74 void	wi_pcmcia_attach	__P((struct device *, struct device *, void *));
75 int	wi_pcmcia_detach	__P((struct device *, int));
76 int	wi_pcmcia_activate	__P((struct device *, enum devact));
77 void	wi_pcmcia_attach	__P((struct device *, struct device *, void *));
78 
79 int	wi_intr			__P((void *));
80 int	wi_attach		__P((struct wi_softc *, int));
81 void	wi_init			__P((void *));
82 void	wi_stop			__P((struct wi_softc *));
83 
84 struct wi_pcmcia_softc {
85 	struct wi_softc sc_wi;
86 
87 	struct pcmcia_io_handle	sc_pcioh;
88 	int			sc_io_window;
89 	struct pcmcia_function	*sc_pf;
90 };
91 
92 struct cfattach wi_pcmcia_ca = {
93 	sizeof (struct wi_pcmcia_softc), wi_pcmcia_match, wi_pcmcia_attach,
94 	wi_pcmcia_detach, wi_pcmcia_activate
95 };
96 
97 static const struct wi_pcmcia_product {
98 	u_int16_t	pp_vendor;
99 	u_int16_t	pp_product;
100 	const char	*pp_cisinfo[4];
101 	const char	*pp_name;
102 } wi_pcmcia_products[] = {
103 	{ PCMCIA_VENDOR_LUCENT,
104 	  PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
105 	  PCMCIA_CIS_LUCENT_WAVELAN_IEEE,
106 	  "WaveLAN/IEEE"
107 	},
108 	{ PCMCIA_VENDOR_3COM,
109 	  PCMCIA_PRODUCT_3COM_3CRWE737A,
110 	  PCMCIA_CIS_3COM_3CRWE737A,
111 	  "3Com AirConnect Wireless LAN"
112 	},
113 	{ PCMCIA_VENDOR_COREGA,
114 	  PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCC_11,
115 	  PCMCIA_CIS_COREGA_WIRELESS_LAN_PCC_11,
116 	  "Corega Wireless LAN PCC-11"
117 	},
118 	{ PCMCIA_VENDOR_COREGA,
119 	  PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCA_11,
120 	  PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCA_11,
121 	  "Corega Wireless LAN PCCA-11",
122 	},
123 	{ PCMCIA_VENDOR_COREGA,
124 	  PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCB_11,
125 	  PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCB_11,
126 	  "Corega Wireless LAN PCCB-11",
127 	},
128 	{ PCMCIA_VENDOR_INTEL,
129 	  PCMCIA_PRODUCT_INTEL_PRO_WLAN_2011,
130 	  PCMCIA_CIS_INTEL_PRO_WLAN_2011,
131 	  "Intel PRO/Wireless 2011",
132 	},
133 	{ PCMCIA_VENDOR_INTERSIL,
134 	  PCMCIA_PRODUCT_INTERSIL_PRISM2,
135 	  PCMCIA_CIS_INTERSIL_PRISM2,
136 	  "Intersil Prism II",
137 	},
138 	{ PCMCIA_VENDOR_SAMSUNG,
139 	  PCMCIA_PRODUCT_SAMSUNG_SWL_2000N,
140 	  PCMCIA_CIS_SAMSUNG_SWL_2000N,
141 	  "Samsung MagicLAN SWL-2000N",
142 	},
143 	{ PCMCIA_VENDOR_LINKSYS2,
144 	  PCMCIA_PRODUCT_LINKSYS2_IWN,
145 	  PCMCIA_CIS_LINKSYS2_IWN,
146 	  "Linksys Instant Wireless Network",
147 	},
148 	{ PCMCIA_VENDOR_LUCENT,
149 	  PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
150 	  PCMCIA_CIS_SMC_2632W,
151 	  "SMC 2632 EZ Connect Wireless PC Card",
152 	},
153 	{ PCMCIA_VENDOR_LUCENT,
154 	  PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
155 	  PCMCIA_CIS_NANOSPEED_PRISM2,
156 	  "NANOSPEED ROOT-RZ2000 WLAN Card",
157 	},
158 	{ PCMCIA_VENDOR_ELSA,
159 	  PCMCIA_PRODUCT_ELSA_XI300_IEEE,
160 	  PCMCIA_CIS_ELSA_XI300_IEEE,
161 	  "XI300 Wireless LAN",
162 	},
163 	{ PCMCIA_VENDOR_COMPAQ,
164 	  PCMCIA_PRODUCT_COMPAQ_NC5004,
165 	  PCMCIA_CIS_COMPAQ_NC5004,
166 	  "Compaq Agency NC5004 Wireless Card",
167 	},
168 	{ PCMCIA_VENDOR_CONTEC,
169 	  PCMCIA_PRODUCT_CONTEC_FX_DS110_PCC,
170 	  PCMCIA_CIS_CONTEC_FX_DS110_PCC,
171 	  "Contec FLEXLAN/FX-DS110-PCC",
172 	},
173 	{ PCMCIA_VENDOR_TDK,
174 	  PCMCIA_PRODUCT_TDK_LAK_CD011WL,
175 	  PCMCIA_CIS_TDK_LAK_CD011WL,
176 	  "TDK LAK-CD011WL",
177 	},
178 	{ PCMCIA_VENDOR_LUCENT,
179 	  PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
180 	  PCMCIA_CIS_NEC_CMZ_RT_WP,
181 	  "NEC Wireless Card CMZ-RT-WP",
182 	},
183 	{ PCMCIA_VENDOR_LUCENT,
184 	  PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
185 	  PCMCIA_CIS_NTT_ME_WLAN,
186 	  "NTT-ME 11Mbps Wireless LAN PC Card",
187 	},
188 	{ PCMCIA_VENDOR_ADDTRON,
189 	  PCMCIA_PRODUCT_ADDTRON_AWP100,
190 	  PCMCIA_CIS_ADDTRON_AWP100,
191 	  "Addtron AWP-100",
192 	},
193 	{ PCMCIA_VENDOR_LUCENT,
194 	  PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
195 	  PCMCIA_CIS_CABLETRON_ROAMABOUT,
196 	  "Cabletron RoamAbout",
197 	},
198 	{ PCMCIA_VENDOR_IODATA2,
199 	  PCMCIA_PRODUCT_IODATA2_WNB11PCM,
200 	  PCMCIA_CIS_IODATA2_WNB11PCM,
201 	  "I-O DATA WN-B11/PCM",
202 	},
203 	{ PCMCIA_VENDOR_GEMTEK,
204 	  PCMCIA_PRODUCT_GEMTEK_WLAN,
205 	  PCMCIA_CIS_GEMTEK_WLAN,
206 	  "GEMTEK Prism2_5 WaveLAN Card"
207 	},
208 	{ PCMCIA_VENDOR_ELSA,
209 	  PCMCIA_PRODUCT_ELSA_XI800_IEEE,
210 	  PCMCIA_CIS_ELSA_XI800_IEEE,
211 	  "ELSA XI800 CF Wireless LAN"
212 	},
213 	{ PCMCIA_VENDOR_BUFFALO,
214 	  PCMCIA_PRODUCT_BUFFALO_WLI_PCM_S11,
215 	  PCMCIA_CIS_BUFFALO_WLI_PCM_S11,
216 	  "BUFFALO AirStation 11Mbps WLAN"
217 	},
218 	{ PCMCIA_VENDOR_BUFFALO,
219 	  PCMCIA_PRODUCT_BUFFALO_WLI_CF_S11G,
220 	  PCMCIA_CIS_BUFFALO_WLI_CF_S11G,
221 	  "BUFFALO AirStation 11Mbps CF WLAN"
222 	},
223 	{ PCMCIA_VENDOR_EMTAC,
224 	  PCMCIA_PRODUCT_EMTAC_WLAN,
225 	  PCMCIA_CIS_EMTAC_WLAN,
226 	  "EMTAC A2424i 11Mbps WLAN Card"
227 	},
228 	{ PCMCIA_VENDOR_SIMPLETECH,
229 	  PCMCIA_PRODUCT_SIMPLETECH_SPECTRUM24_ALT,
230 	  PCMCIA_CIS_SIMPLETECH_SPECTRUM24_ALT,
231 	  "LA4111 Spectrum24 WLAN PC Card"
232 	},
233 	{ 0,
234 	  0,
235 	  { NULL, NULL, NULL, NULL },
236 	  NULL,
237 	}
238 };
239 
240 static const struct wi_pcmcia_product *wi_lookup __P((struct pcmcia_attach_args *pa));
241 
242 const struct wi_pcmcia_product *
243 wi_lookup(pa)
244 	struct pcmcia_attach_args *pa;
245 {
246 	const struct wi_pcmcia_product *pp;
247 
248 	/*
249 	 * Several PRISM II-based cards use the Lucent WaveLAN vendor
250 	 * and product IDs so we match by CIS information first.
251 	 */
252 	for (pp = wi_pcmcia_products; pp->pp_name != NULL; pp++) {
253 		if (pa->card->cis1_info[0] != NULL &&
254 		    pp->pp_cisinfo[0] != NULL &&
255 		    strcmp(pa->card->cis1_info[0], pp->pp_cisinfo[0]) == 0 &&
256 		    pa->card->cis1_info[1] != NULL &&
257 		    pp->pp_cisinfo[1] != NULL &&
258 		    strcmp(pa->card->cis1_info[1], pp->pp_cisinfo[1]) == 0)
259 			return (pp);
260 	}
261 
262 	/* Match by vendor/product ID. */
263 	for (pp = wi_pcmcia_products; pp->pp_name != NULL; pp++) {
264 		if (pa->manufacturer != PCMCIA_VENDOR_INVALID &&
265 		    pa->manufacturer == pp->pp_vendor &&
266 		    pa->product != PCMCIA_PRODUCT_INVALID &&
267 		    pa->product == pp->pp_product)
268 			return (pp);
269 	}
270 
271 	return (NULL);
272 }
273 
274 int
275 wi_pcmcia_match(parent, match, aux)
276 	struct device *parent;
277 	void *match, *aux;
278 {
279 	struct pcmcia_attach_args *pa = aux;
280 
281 	if (wi_lookup(pa) != NULL)
282 		return (1);
283 	return (0);
284 }
285 
286 void
287 wi_pcmcia_attach(parent, self, aux)
288 	struct device *parent, *self;
289 	void *aux;
290 {
291 	struct wi_pcmcia_softc	*psc = (struct wi_pcmcia_softc *)self;
292 	struct wi_softc		*sc = &psc->sc_wi;
293 	struct pcmcia_attach_args *pa = aux;
294 	struct pcmcia_function	*pf = pa->pf;
295 	struct pcmcia_config_entry *cfe = pf->cfe_head.sqh_first;
296 	int			state = 0;
297 
298 	psc->sc_pf = pf;
299 
300 	/* Enable the card. */
301 	pcmcia_function_init(pf, cfe);
302 	if (pcmcia_function_enable(pf)) {
303 		printf(": function enable failed\n");
304 		goto bad;
305 	}
306 	state++;
307 
308 	if (pcmcia_io_alloc(pf, 0, WI_IOSIZ, WI_IOSIZ, &psc->sc_pcioh)) {
309 		printf(": can't alloc i/o space\n");
310 		goto bad;
311 	}
312 	state++;
313 
314 	if (pcmcia_io_map(pf, PCMCIA_WIDTH_IO16, 0, WI_IOSIZ,
315 	    &psc->sc_pcioh, &psc->sc_io_window)) {
316 		printf(": can't map io space\n");
317 		goto bad;
318 	}
319 	state++;
320 
321 	sc->wi_btag = psc->sc_pcioh.iot;
322 	sc->wi_bhandle = psc->sc_pcioh.ioh;
323 
324 	/* Make sure interrupts are disabled. */
325 	CSR_WRITE_2(sc, WI_INT_EN, 0);
326 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xffff);
327 
328 	/* Establish the interrupt. */
329 	sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, wi_intr, psc, "");
330 	if (sc->sc_ih == NULL) {
331 		printf("%s: couldn't establish interrupt\n",
332 		    sc->sc_dev.dv_xname);
333 		goto bad;
334 	}
335 
336 	wi_attach(sc, 0);
337 	return;
338 
339 bad:
340 	if (state > 2)
341 		pcmcia_io_unmap(pf, psc->sc_io_window);
342 	if (state > 1)
343 		pcmcia_io_free(pf, &psc->sc_pcioh);
344 	if (state > 0)
345 		pcmcia_function_disable(pf);
346 }
347 
348 int
349 wi_pcmcia_detach(dev, flags)
350 	struct device *dev;
351 	int flags;
352 {
353 	struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev;
354 	struct wi_softc *sc = &psc->sc_wi;
355 	struct ifnet *ifp = &sc->arpcom.ac_if;
356 
357 	pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
358 	pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
359 
360 	ether_ifdetach(ifp);
361 	if_detach(ifp);
362 
363 	return (0);
364 }
365 
366 int
367 wi_pcmcia_activate(dev, act)
368 	struct device *dev;
369 	enum devact act;
370 {
371 	struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev;
372 	struct wi_softc *sc = &psc->sc_wi;
373 	struct ifnet *ifp = &sc->arpcom.ac_if;
374 	int s;
375 
376 	s = splnet();
377 	switch (act) {
378 	case DVACT_ACTIVATE:
379 		pcmcia_function_enable(psc->sc_pf);
380 		sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
381 		    wi_intr, sc, sc->sc_dev.dv_xname);
382 		wi_init(sc);
383 		break;
384 
385 	case DVACT_DEACTIVATE:
386 		ifp->if_timer = 0;
387 		if (ifp->if_flags & IFF_RUNNING)
388 			wi_stop(sc);
389 		pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
390 		pcmcia_function_disable(psc->sc_pf);
391 		break;
392 	}
393 	splx(s);
394 	return (0);
395 }
396