1 /* $OpenBSD: if_wi_pcmcia.c,v 1.77 2024/05/26 08:46:28 jsg 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/device.h>
50
51 #include <net/if.h>
52 #include <net/if_media.h>
53
54 #include <netinet/in.h>
55 #include <netinet/if_ether.h>
56
57 #include <net80211/ieee80211_var.h>
58 #include <net80211/ieee80211_ioctl.h>
59
60 #include <machine/bus.h>
61
62 #include <dev/pcmcia/pcmciavar.h>
63 #include <dev/pcmcia/pcmciadevs.h>
64
65 #include <dev/ic/if_wireg.h>
66 #include <dev/ic/if_wi_ieee.h>
67 #include <dev/ic/if_wivar.h>
68
69 int wi_pcmcia_match(struct device *, void *, void *);
70 void wi_pcmcia_attach(struct device *, struct device *, void *);
71 int wi_pcmcia_detach(struct device *, int);
72 int wi_pcmcia_activate(struct device *, int);
73 void wi_pcmcia_wakeup(struct wi_softc *);
74
75 struct wi_pcmcia_softc {
76 struct wi_softc sc_wi;
77
78 struct pcmcia_io_handle sc_pcioh;
79 int sc_io_window;
80 struct pcmcia_function *sc_pf;
81 };
82
83 const struct cfattach wi_pcmcia_ca = {
84 sizeof (struct wi_pcmcia_softc), wi_pcmcia_match, wi_pcmcia_attach,
85 wi_pcmcia_detach, wi_pcmcia_activate
86 };
87
88 static const struct wi_pcmcia_product {
89 u_int16_t pp_vendor;
90 u_int16_t pp_product;
91 const char *pp_cisinfo[4];
92 } wi_pcmcia_products[] = {
93 { PCMCIA_VENDOR_LUCENT,
94 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
95 PCMCIA_CIS_LUCENT_WAVELAN_IEEE
96 },
97 { PCMCIA_VENDOR_3COM,
98 PCMCIA_PRODUCT_3COM_3CRWE737A,
99 PCMCIA_CIS_3COM_3CRWE737A
100 },
101 { PCMCIA_VENDOR_3COM,
102 PCMCIA_PRODUCT_3COM_3CRWE777A,
103 PCMCIA_CIS_3COM_3CRWE777A
104 },
105 { PCMCIA_VENDOR_COREGA,
106 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCC_11,
107 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCC_11
108 },
109 { PCMCIA_VENDOR_COREGA,
110 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCA_11,
111 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCA_11
112 },
113 { PCMCIA_VENDOR_COREGA,
114 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCB_11,
115 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCB_11
116 },
117 { PCMCIA_VENDOR_COREGA,
118 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCL_11,
119 PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCL_11
120 },
121 { PCMCIA_VENDOR_COREGA,
122 PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_WLCFL_11,
123 PCMCIA_CIS_COREGA_WIRELESS_LAN_WLCFL_11
124 },
125 { PCMCIA_VENDOR_INTEL,
126 PCMCIA_PRODUCT_INTEL_PRO_WLAN_2011,
127 PCMCIA_CIS_INTEL_PRO_WLAN_2011
128 },
129 { PCMCIA_VENDOR_INTERSIL,
130 PCMCIA_PRODUCT_INTERSIL_PRISM2,
131 PCMCIA_CIS_INTERSIL_PRISM2
132 },
133 { PCMCIA_VENDOR_SAMSUNG,
134 PCMCIA_PRODUCT_SAMSUNG_SWL_2000N,
135 PCMCIA_CIS_SAMSUNG_SWL_2000N
136 },
137 { PCMCIA_VENDOR_LINKSYS2,
138 PCMCIA_PRODUCT_LINKSYS2_IWN,
139 PCMCIA_CIS_LINKSYS2_IWN
140 },
141 { PCMCIA_VENDOR_LINKSYS2,
142 PCMCIA_PRODUCT_LINKSYS2_IWN2,
143 PCMCIA_CIS_LINKSYS2_IWN2
144 },
145 { PCMCIA_VENDOR_LINKSYS2,
146 PCMCIA_PRODUCT_LINKSYS2_WCF11,
147 PCMCIA_CIS_LINKSYS2_WCF11
148 },
149 { PCMCIA_VENDOR_LUCENT,
150 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
151 PCMCIA_CIS_SMC_2632W
152 },
153 { PCMCIA_VENDOR_LUCENT,
154 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
155 PCMCIA_CIS_NANOSPEED_PRISM2
156 },
157 { PCMCIA_VENDOR_ELSA,
158 PCMCIA_PRODUCT_ELSA_XI300_IEEE,
159 PCMCIA_CIS_ELSA_XI300_IEEE
160 },
161 { PCMCIA_VENDOR_ELSA,
162 PCMCIA_PRODUCT_ELSA_XI325_IEEE,
163 PCMCIA_CIS_ELSA_XI325_IEEE
164 },
165 { PCMCIA_VENDOR_ELSA,
166 PCMCIA_PRODUCT_ELSA_WNB11CFZ,
167 PCMCIA_CIS_ELSA_WNB11CFZ
168 },
169 { PCMCIA_VENDOR_COMPAQ,
170 PCMCIA_PRODUCT_COMPAQ_NC5004,
171 PCMCIA_CIS_COMPAQ_NC5004
172 },
173 { PCMCIA_VENDOR_CONTEC,
174 PCMCIA_PRODUCT_CONTEC_FX_DS110_PCC,
175 PCMCIA_CIS_CONTEC_FX_DS110_PCC
176 },
177 { PCMCIA_VENDOR_TDK,
178 PCMCIA_PRODUCT_TDK_LAK_CD011WL,
179 PCMCIA_CIS_TDK_LAK_CD011WL
180 },
181 { PCMCIA_VENDOR_LUCENT,
182 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
183 PCMCIA_CIS_NEC_CMZ_RT_WP
184 },
185 { PCMCIA_VENDOR_LUCENT,
186 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
187 PCMCIA_CIS_NTT_ME_WLAN
188 },
189 { PCMCIA_VENDOR_ADDTRON,
190 PCMCIA_PRODUCT_ADDTRON_AWP100,
191 PCMCIA_CIS_ADDTRON_AWP100
192 },
193 { PCMCIA_VENDOR_LUCENT,
194 PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
195 PCMCIA_CIS_CABLETRON_ROAMABOUT
196 },
197 { PCMCIA_VENDOR_IODATA2,
198 PCMCIA_PRODUCT_IODATA2_WCF12,
199 PCMCIA_CIS_IODATA2_WCF12
200 },
201 { PCMCIA_VENDOR_IODATA2,
202 PCMCIA_PRODUCT_IODATA2_WNB11PCM,
203 PCMCIA_CIS_IODATA2_WNB11PCM
204 },
205 { PCMCIA_VENDOR_GEMTEK,
206 PCMCIA_PRODUCT_GEMTEK_WLAN,
207 PCMCIA_CIS_GEMTEK_WLAN
208 },
209 { PCMCIA_VENDOR_ELSA,
210 PCMCIA_PRODUCT_ELSA_XI800_IEEE,
211 PCMCIA_CIS_ELSA_XI800_IEEE
212 },
213 { PCMCIA_VENDOR_BUFFALO,
214 PCMCIA_PRODUCT_BUFFALO_WLI_PCM_S11,
215 PCMCIA_CIS_BUFFALO_WLI_PCM_S11
216 },
217 { PCMCIA_VENDOR_BUFFALO,
218 PCMCIA_PRODUCT_BUFFALO_WLI_CF_S11G,
219 PCMCIA_CIS_BUFFALO_WLI_CF_S11G
220 },
221 { PCMCIA_VENDOR_EMTAC,
222 PCMCIA_PRODUCT_EMTAC_WLAN,
223 PCMCIA_CIS_EMTAC_WLAN
224 },
225 { PCMCIA_VENDOR_SIMPLETECH,
226 PCMCIA_PRODUCT_SIMPLETECH_SPECTRUM24_ALT,
227 PCMCIA_CIS_SIMPLETECH_SPECTRUM24_ALT
228 },
229 { PCMCIA_VENDOR_ERICSSON,
230 PCMCIA_PRODUCT_ERICSSON_WIRELESSLAN,
231 PCMCIA_CIS_ERICSSON_WIRELESSLAN
232 },
233 { PCMCIA_VENDOR_PROXIM,
234 PCMCIA_PRODUCT_PROXIM_RANGELANDS_8430,
235 PCMCIA_CIS_PROXIM_RANGELANDS_8430
236 },
237 { PCMCIA_VENDOR_ACTIONTEC,
238 PCMCIA_PRODUCT_ACTIONTEC_HWC01170,
239 PCMCIA_CIS_ACTIONTEC_HWC01170
240 },
241 { PCMCIA_VENDOR_NOKIA,
242 PCMCIA_PRODUCT_NOKIA_C020_WLAN,
243 PCMCIA_CIS_NOKIA_C020_WLAN
244 },
245 { PCMCIA_VENDOR_NOKIA,
246 PCMCIA_PRODUCT_NOKIA_C110_WLAN,
247 PCMCIA_CIS_NOKIA_C110_WLAN
248 },
249 { PCMCIA_VENDOR_NETGEAR2,
250 PCMCIA_PRODUCT_NETGEAR2_MA401RA,
251 PCMCIA_CIS_NETGEAR2_MA401RA
252 },
253 { PCMCIA_VENDOR_NETGEAR2,
254 PCMCIA_PRODUCT_NETGEAR2_DWL650,
255 PCMCIA_CIS_NETGEAR2_DWL650
256 },
257 { PCMCIA_VENDOR_AIRVAST,
258 PCMCIA_PRODUCT_AIRVAST_WN_100,
259 PCMCIA_CIS_AIRVAST_WN_100
260 },
261 { PCMCIA_VENDOR_SIEMENS,
262 PCMCIA_PRODUCT_SIEMENS_SS1021,
263 PCMCIA_CIS_SIEMENS_SS1021
264 },
265 { PCMCIA_VENDOR_PROXIM,
266 PCMCIA_PRODUCT_PROXIM_HARMONY_80211B,
267 PCMCIA_CIS_PROXIM_HARMONY_80211B
268 },
269 { PCMCIA_VENDOR_MICROSOFT,
270 PCMCIA_PRODUCT_MICROSOFT_MN520,
271 PCMCIA_CIS_MICROSOFT_MN520
272 },
273 { PCMCIA_VENDOR_ADAPTEC2,
274 PCMCIA_PRODUCT_ADAPTEC2_AWN8030,
275 PCMCIA_CIS_ADAPTEC2_AWN8030
276 },
277 { PCMCIA_VENDOR_ASUS,
278 PCMCIA_PRODUCT_ASUS_WL_100,
279 PCMCIA_CIS_ASUS_WL_100
280 },
281 { PCMCIA_VENDOR_SENAO,
282 PCMCIA_PRODUCT_SENAO_EL2511CD2EM,
283 PCMCIA_CIS_SENAO_EL2511CD2EM
284 },
285 { PCMCIA_VENDOR_ARTEM,
286 PCMCIA_PRODUCT_ARTEM_ONAIR,
287 PCMCIA_CIS_ARTEM_ONAIR
288 },
289 { PCMCIA_VENDOR_PLANEX,
290 PCMCIA_PRODUCT_PLANEX_GWNS11H,
291 PCMCIA_CIS_PLANEX_GWNS11H
292 },
293 { PCMCIA_VENDOR_SYMBOL,
294 PCMCIA_PRODUCT_SYMBOL_LA4100,
295 PCMCIA_CIS_SYMBOL_LA4100
296 },
297 { PCMCIA_VENDOR_BAY,
298 PCMCIA_PRODUCT_BAY_EMOBILITY_11B,
299 PCMCIA_CIS_BAY_EMOBILITY_11B
300 },
301 { PCMCIA_VENDOR_GREYCELL,
302 PCMCIA_PRODUCT_GREYCELL_DWL650H,
303 PCMCIA_CIS_GREYCELL_DWL650H
304 },
305 { PCMCIA_VENDOR_FUJITSU,
306 PCMCIA_PRODUCT_FUJITSU_WL110,
307 PCMCIA_CIS_FUJITSU_WL110
308 },
309 { PCMCIA_VENDOR_ALLIEDTELESIS,
310 PCMCIA_PRODUCT_ALLIEDTELESIS_WR211PCM,
311 PCMCIA_CIS_ALLIEDTELESIS_WR211PCM
312 },
313 { PCMCIA_VENDOR_HWN,
314 PCMCIA_PRODUCT_HWN_AIRWAY80211,
315 PCMCIA_CIS_HWN_AIRWAY80211
316 },
317 { PCMCIA_VENDOR_SOCKET,
318 PCMCIA_PRODUCT_SOCKET_LP_WLAN_CF,
319 PCMCIA_CIS_SOCKET_LP_WLAN_CF
320 }
321 };
322
323 static const struct wi_pcmcia_product *wi_lookup(struct pcmcia_attach_args *pa);
324
325 const struct wi_pcmcia_product *
wi_lookup(struct pcmcia_attach_args * pa)326 wi_lookup(struct pcmcia_attach_args *pa)
327 {
328 const struct wi_pcmcia_product *pp;
329 const struct wi_pcmcia_product *epp = wi_pcmcia_products +
330 sizeof(wi_pcmcia_products) / sizeof(wi_pcmcia_products[0]);
331
332 /*
333 * Several PRISM II-based cards use the Lucent WaveLAN vendor
334 * and product IDs so we match by CIS information first.
335 */
336 for (pp = wi_pcmcia_products; pp < epp; pp++) {
337 if (pa->card->cis1_info[0] != NULL &&
338 pp->pp_cisinfo[0] != NULL &&
339 strcmp(pa->card->cis1_info[0], pp->pp_cisinfo[0]) == 0 &&
340 pa->card->cis1_info[1] != NULL &&
341 pp->pp_cisinfo[1] != NULL &&
342 strcmp(pa->card->cis1_info[1], pp->pp_cisinfo[1]) == 0)
343 return (pp);
344 }
345
346 /* Match by vendor/product ID. */
347 for (pp = wi_pcmcia_products; pp < epp; pp++) {
348 if (pa->manufacturer != PCMCIA_VENDOR_INVALID &&
349 pa->manufacturer == pp->pp_vendor &&
350 pa->product != PCMCIA_PRODUCT_INVALID &&
351 pa->product == pp->pp_product)
352 return (pp);
353 }
354
355 return (NULL);
356 }
357
358 int
wi_pcmcia_match(struct device * parent,void * match,void * aux)359 wi_pcmcia_match(struct device *parent, void *match, void *aux)
360 {
361 struct pcmcia_attach_args *pa = aux;
362
363 if (wi_lookup(pa) != NULL)
364 return (1);
365 return (0);
366 }
367
368 void
wi_pcmcia_attach(struct device * parent,struct device * self,void * aux)369 wi_pcmcia_attach(struct device *parent, struct device *self, void *aux)
370 {
371 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)self;
372 struct wi_softc *sc = &psc->sc_wi;
373 struct pcmcia_attach_args *pa = aux;
374 struct pcmcia_function *pf = pa->pf;
375 struct pcmcia_config_entry *cfe = SIMPLEQ_FIRST(&pf->cfe_head);
376 const char *intrstr;
377 int state = 0;
378
379 psc->sc_pf = pf;
380
381 /* Enable the card. */
382 pcmcia_function_init(pf, cfe);
383 if (pcmcia_function_enable(pf)) {
384 printf(": function enable failed\n");
385 goto bad;
386 }
387 state++;
388
389 if (pcmcia_io_alloc(pf, 0, WI_IOSIZ, WI_IOSIZ, &psc->sc_pcioh)) {
390 printf(": can't alloc i/o space\n");
391 goto bad;
392 }
393 state++;
394
395 if (pcmcia_io_map(pf, PCMCIA_WIDTH_IO16, 0, WI_IOSIZ,
396 &psc->sc_pcioh, &psc->sc_io_window)) {
397 printf(": can't map i/o space\n");
398 goto bad;
399 }
400 state++;
401
402 printf(" port 0x%lx/%lu", psc->sc_pcioh.addr,
403 (u_long)psc->sc_pcioh.size);
404
405 sc->wi_ltag = sc->wi_btag = psc->sc_pcioh.iot;
406 sc->wi_lhandle = sc->wi_bhandle = psc->sc_pcioh.ioh;
407 sc->wi_cor_offset = WI_COR_OFFSET;
408 sc->wi_flags |= WI_FLAGS_BUS_PCMCIA;
409
410 /* Make sure interrupts are disabled. */
411 CSR_WRITE_2(sc, WI_INT_EN, 0);
412 CSR_WRITE_2(sc, WI_EVENT_ACK, 0xffff);
413
414 /* Establish the interrupt. */
415 sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, wi_intr, psc,
416 sc->sc_dev.dv_xname);
417 if (sc->sc_ih == NULL) {
418 printf("%s: can't establish interrupt\n",
419 sc->sc_dev.dv_xname);
420 goto bad;
421 }
422
423 intrstr = pcmcia_intr_string(psc->sc_pf, sc->sc_ih);
424 printf("%s%s\n", *intrstr ? ", " : "", intrstr);
425 if (wi_attach(sc, &wi_func_io) == 0)
426 return;
427
428 /* wi_attach() failed, do some cleanup */
429 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
430 sc->sc_ih = NULL;
431
432 bad:
433 if (state > 2)
434 pcmcia_io_unmap(pf, psc->sc_io_window);
435 if (state > 1)
436 pcmcia_io_free(pf, &psc->sc_pcioh);
437 if (state > 0)
438 pcmcia_function_disable(pf);
439 }
440
441 int
wi_pcmcia_detach(struct device * dev,int flags)442 wi_pcmcia_detach(struct device *dev, int flags)
443 {
444 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev;
445 struct wi_softc *sc = &psc->sc_wi;
446 struct ifnet *ifp = &sc->sc_ic.ic_if;
447
448 if (!(sc->wi_flags & WI_FLAGS_ATTACHED))
449 return (0);
450
451 wi_detach(sc);
452
453 sc->wi_flags = 0;
454
455 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
456 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
457
458 ether_ifdetach(ifp);
459 if_detach(ifp);
460
461 return (0);
462 }
463
464 int
wi_pcmcia_activate(struct device * dev,int act)465 wi_pcmcia_activate(struct device *dev, int act)
466 {
467 struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev;
468 struct wi_softc *sc = &psc->sc_wi;
469 struct ifnet *ifp = &sc->sc_ic.ic_if;
470
471 switch (act) {
472 case DVACT_SUSPEND:
473 ifp->if_timer = 0;
474 if (ifp->if_flags & IFF_RUNNING)
475 wi_stop(sc);
476 sc->wi_flags &= ~WI_FLAGS_INITIALIZED;
477 if (sc->sc_ih != NULL)
478 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
479 sc->sc_ih = NULL;
480 pcmcia_function_disable(psc->sc_pf);
481 break;
482 case DVACT_RESUME:
483 pcmcia_function_enable(psc->sc_pf);
484 sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
485 wi_intr, sc, sc->sc_dev.dv_xname);
486 break;
487 case DVACT_WAKEUP:
488 wi_pcmcia_wakeup(sc);
489 break;
490 case DVACT_DEACTIVATE:
491 if (sc->sc_ih != NULL)
492 pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
493 sc->sc_ih = NULL;
494 pcmcia_function_disable(psc->sc_pf);
495 break;
496 }
497 return (0);
498 }
499
500 void
wi_pcmcia_wakeup(struct wi_softc * sc)501 wi_pcmcia_wakeup(struct wi_softc *sc)
502 {
503 int s;
504
505 s = splnet();
506 while (sc->wi_flags & WI_FLAGS_BUSY)
507 tsleep_nsec(&sc->wi_flags, 0, "wipwr", INFSLP);
508 sc->wi_flags |= WI_FLAGS_BUSY;
509
510 wi_cor_reset(sc);
511 wi_init(sc);
512
513 sc->wi_flags &= ~WI_FLAGS_BUSY;
514 wakeup(&sc->wi_flags);
515 splx(s);
516 }
517