xref: /openbsd/sys/dev/pcmcia/if_wi_pcmcia.c (revision 8b4b0e59)
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