xref: /illumos-gate/usr/src/uts/common/io/atu/atu.c (revision 9f758caf94c37c3ad28c48cfe503f9fc830a66d5)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2003, 2004
8  *	Daan Vreeken <Danovitsch@Vitsch.net>.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by Daan Vreeken.
21  * 4. Neither the name of the author nor the names of any co-contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY Daan Vreeken AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL Daan Vreeken OR THE VOICES IN HIS HEAD
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35  * THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Atmel AT76c503 / AT76c503a / AT76c505 / AT76c505a  USB WLAN driver
40  *
41  * Originally written by Daan Vreeken <Danovitsch @ Vitsch . net>
42  *  http://vitsch.net/bsd/atuwi
43  *
44  * Contributed to by :
45  *  Chris Whitehouse, Alistair Phillips, Peter Pilka, Martijn van Buul,
46  *  Suihong Liang, Arjan van Leeuwen, Stuart Walsh
47  *
48  * Ported to OpenBSD by Theo de Raadt and David Gwynne.
49  */
50 
51 #include <sys/strsubr.h>
52 #include <sys/strsun.h>
53 #include <sys/mac_provider.h>
54 #include <sys/mac_wifi.h>
55 #include <sys/net80211.h>
56 #define	USBDRV_MAJOR_VER	2
57 #define	USBDRV_MINOR_VER	0
58 #include <sys/usb/usba.h>
59 #include <sys/usb/usba/usba_types.h>
60 
61 #include "fw/atmel_rfmd.hex"
62 #include "fw/atmel_rfmd2958.hex"
63 #include "fw/atmel_rfmd2958-smc.hex"
64 #include "fw/atmel_intersil.hex"
65 #include "fw/atmel_at76c505_rfmd.hex"
66 #include "fw/atmel_at76c503_rfmd_acc.hex"
67 #include "fw/atmel_at76c503_i3863.hex"
68 #include "atu.h"
69 
70 static void *atu_soft_state_p;
71 static mac_callbacks_t	atu_m_callbacks;
72 static const struct ieee80211_rateset atu_rateset = {4, {2, 4, 11, 22}};
73 
74 static int
75 atu_usb_request(struct atu_softc *sc, uint8_t type,
76     uint8_t request, uint16_t value, uint16_t index, uint16_t length,
77     uint8_t *data)
78 {
79 	usb_ctrl_setup_t	req;
80 	usb_cb_flags_t		cf;
81 	usb_cr_t		cr;
82 	mblk_t			*mp = NULL;
83 	int			uret = USB_SUCCESS;
84 
85 	bzero(&req, sizeof (req));
86 	req.bmRequestType = type;
87 	req.bRequest = request;
88 	req.wValue = value;
89 	req.wIndex = index;
90 	req.wLength = length;
91 	req.attrs = USB_ATTRS_NONE;
92 
93 	if (type & USB_DEV_REQ_DEV_TO_HOST) {
94 		req.attrs = USB_ATTRS_AUTOCLEARING;
95 		uret = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph,
96 		    &req, &mp, &cr, &cf, 0);
97 		if (mp == NULL)
98 			return (EIO);
99 
100 		if (uret == USB_SUCCESS)
101 			bcopy(mp->b_rptr, data, length);
102 	} else {
103 		if ((mp = allocb(length, BPRI_HI)) == NULL)
104 			return (ENOMEM);
105 
106 		bcopy(data, mp->b_wptr, length);
107 		mp->b_wptr += length;
108 		uret = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph,
109 		    &req, &mp, &cr, &cf, 0);
110 	}
111 
112 	if (mp)
113 		freemsg(mp);
114 
115 	return (uret == USB_SUCCESS ? 0 : EIO);
116 }
117 
118 static int
119 atu_get_mib(struct atu_softc *sc, uint8_t type, uint8_t size,
120     uint8_t index, uint8_t *buf)
121 {
122 	return atu_usb_request(sc, ATU_VENDOR_IF_IN, 0x033,
123 	    type << 8, index, size, buf);
124 }
125 
126 static int
127 atu_get_cmd_status(struct atu_softc *sc, uint8_t cmd, uint8_t *status)
128 {
129 	/*
130 	 * all other drivers (including Windoze) request 40 bytes of status
131 	 * and get a short-xfer of just 6 bytes. we can save 34 bytes of
132 	 * buffer if we just request those 6 bytes in the first place :)
133 	 */
134 	return atu_usb_request(sc, ATU_VENDOR_IF_IN, 0x22, cmd,
135 	    0x0000, 6, status);
136 }
137 
138 static uint8_t
139 atu_get_dfu_state(struct atu_softc *sc)
140 {
141 	uint8_t	state;
142 
143 	if (atu_usb_request(sc, DFU_GETSTATE, 0, 0, 1, &state))
144 		return (DFUState_DFUError);
145 	return (state);
146 }
147 
148 static int
149 atu_get_opmode(struct atu_softc *sc, uint8_t *mode)
150 {
151 	return atu_usb_request(sc, ATU_VENDOR_IF_IN, 0x33, 0x0001,
152 	    0x0000, 1, mode);
153 }
154 
155 static int
156 atu_get_config(struct atu_softc *sc)
157 {
158 	struct ieee80211com	*ic = &sc->sc_ic;
159 	struct atu_rfmd_conf	rfmd_conf;
160 	struct atu_intersil_conf intersil_conf;
161 	int			err;
162 
163 	switch (sc->sc_radio) {
164 	case RadioRFMD:
165 	case RadioRFMD2958:
166 	case RadioRFMD2958_SMC:
167 	case AT76C503_RFMD_ACC:
168 	case AT76C505_RFMD:
169 		err = atu_usb_request(sc, ATU_VENDOR_IF_IN, 0x33, 0x0a02,
170 		    0x0000, sizeof (rfmd_conf), (uint8_t *)&rfmd_conf);
171 		if (err) {
172 			cmn_err(CE_WARN, "%s: get RFMD config failed\n",
173 			    sc->sc_name);
174 			return (err);
175 		}
176 		bcopy(rfmd_conf.MACAddr, ic->ic_macaddr, IEEE80211_ADDR_LEN);
177 		break;
178 
179 	case RadioIntersil:
180 	case AT76C503_i3863:
181 		err = atu_usb_request(sc, ATU_VENDOR_IF_IN, 0x33, 0x0902,
182 		    0x0000, sizeof (intersil_conf), (uint8_t *)&intersil_conf);
183 		if (err) {
184 			cmn_err(CE_WARN, "%s: get Intersil config failed\n",
185 			    sc->sc_name);
186 			return (err);
187 		}
188 		bcopy(intersil_conf.MACAddr, ic->ic_macaddr,
189 		    IEEE80211_ADDR_LEN);
190 		break;
191 	}
192 
193 	return (0);
194 }
195 
196 static int
197 atu_wait_completion(struct atu_softc *sc, uint8_t cmd, uint8_t *status)
198 {
199 	uint8_t	statusreq[6];
200 	int	idle_count = 0, err;
201 
202 	while ((err = atu_get_cmd_status(sc, cmd, statusreq)) == 0) {
203 
204 		if ((statusreq[5] != STATUS_IN_PROGRESS) &&
205 		    (statusreq[5] != STATUS_IDLE)) {
206 			if (status != NULL)
207 				*status = statusreq[5];
208 			return (0);
209 		} else if (idle_count++ > 60) {
210 			cmn_err(CE_WARN, "%s: command (0x%02x) timeout\n",
211 			    sc->sc_name, cmd);
212 			return (ETIME);
213 		}
214 
215 		drv_usecwait(10 * 1000);
216 	}
217 
218 	return (err);
219 }
220 
221 static int
222 atu_send_command(struct atu_softc *sc, uint8_t *command, int size)
223 {
224 	return atu_usb_request(sc, ATU_VENDOR_DEV_OUT, 0x0e, 0x0000,
225 	    0x0000, size, command);
226 }
227 
228 static int
229 atu_send_mib(struct atu_softc *sc, uint8_t type, uint8_t size,
230     uint8_t index, void *data)
231 {
232 	struct atu_cmd_set_mib	request;
233 	int err;
234 
235 	bzero(&request, sizeof (request));
236 	request.AtCmd = CMD_SET_MIB;
237 	request.AtSize = size + 4;
238 	request.MIBType = type;
239 	request.MIBSize = size;
240 	request.MIBIndex = index;
241 	request.MIBReserved = 0;
242 
243 	/*
244 	 * For 1 and 2 byte requests we assume a direct value,
245 	 * everything bigger than 2 bytes we assume a pointer to the data
246 	 */
247 	switch (size) {
248 	case 0:
249 		break;
250 	case 1:
251 		request.data[0] = (long)data & 0x000000ff;
252 		break;
253 	case 2:
254 		request.data[0] = (long)data & 0x000000ff;
255 		request.data[1] = (long)data >> 8;
256 		break;
257 	default:
258 		bcopy(data, request.data, size);
259 		break;
260 	}
261 
262 	err = atu_usb_request(sc, ATU_VENDOR_DEV_OUT, 0x0e, 0x0000,
263 	    0x0000, size+8, (uint8_t *)&request);
264 	if (err)
265 		return (err);
266 
267 	return (atu_wait_completion(sc, CMD_SET_MIB, NULL));
268 }
269 
270 static int
271 atu_switch_radio(struct atu_softc *sc, boolean_t on)
272 {
273 	struct atu_cmd	radio;
274 	boolean_t	ostate;
275 	int		err;
276 
277 	/* Intersil doesn't seem to support radio switch */
278 	if (sc->sc_radio == RadioIntersil)
279 		return (0);
280 
281 	ostate = ATU_RADIO_ON(sc) ? B_TRUE : B_FALSE;
282 	if (on != ostate) {
283 		bzero(&radio, sizeof (radio));
284 		radio.Cmd = on ? CMD_RADIO_ON : CMD_RADIO_OFF;
285 
286 		err = atu_send_command(sc, (uint8_t *)&radio,
287 		    sizeof (radio));
288 		if (err)
289 			return (err);
290 
291 		err = atu_wait_completion(sc, radio.Cmd, NULL);
292 		if (err)
293 			return (err);
294 
295 		if (on)
296 			sc->sc_flags |= ATU_FLAG_RADIO_ON;
297 		else
298 			sc->sc_flags &= ~ATU_FLAG_RADIO_ON;
299 	}
300 
301 	return (0);
302 }
303 
304 static int
305 atu_config(struct atu_softc *sc)
306 {
307 	struct ieee80211com		*ic = &sc->sc_ic;
308 	struct ieee80211_key		*k;
309 	struct atu_cmd_card_config	cmd;
310 	uint8_t				rates[4] = {0x82, 0x84, 0x8B, 0x96};
311 	int				err, i;
312 
313 	err = atu_send_mib(sc, MIB_MAC_ADDR_STA, ic->ic_macaddr);
314 	if (err) {
315 		cmn_err(CE_WARN, "%s: setting MAC address failed\n",
316 		    sc->sc_name);
317 		return (err);
318 	}
319 
320 	bzero(&cmd, sizeof (cmd));
321 	cmd.Cmd = CMD_STARTUP;
322 	cmd.Reserved = 0;
323 	cmd.Size = sizeof (cmd) - 4;
324 	cmd.Channel = ATU_DEF_CHAN;
325 	cmd.ShortRetryLimit = 7;
326 	cmd.RTS_Threshold = 2347;
327 	cmd.FragThreshold = 2346;
328 	cmd.PromiscuousMode = 1;
329 	cmd.AutoRateFallback = 1;
330 	bcopy(rates, cmd.BasicRateSet, 4);
331 
332 	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
333 		k = ic->ic_nw_keys + ic->ic_def_txkey;
334 		switch (k->wk_keylen) {
335 		case 5:
336 			cmd.EncryptionType = ATU_ENC_WEP40;
337 			break;
338 		case 13:
339 			cmd.EncryptionType = ATU_ENC_WEP104;
340 			break;
341 		default:
342 			cmn_err(CE_WARN, "%s: key invalid (%d bytes)\n",
343 			    sc->sc_name, k->wk_keylen);
344 			goto nowep;
345 		}
346 		cmd.PrivacyInvoked = 1;
347 		cmd.ExcludeUnencrypted = 1;
348 		cmd.WEP_DefaultKeyID = ic->ic_def_txkey;
349 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
350 			k = ic->ic_nw_keys + i;
351 			if (k->wk_keylen == 0)
352 				continue;
353 			bcopy(k->wk_key, cmd.WEP_DefaultKey + i, k->wk_keylen);
354 		}
355 	} else {
356 nowep:
357 		cmd.EncryptionType = ATU_ENC_NONE;
358 	}
359 
360 	bcopy(ic->ic_des_essid, cmd.SSID, ic->ic_des_esslen);
361 	cmd.SSID_Len = ic->ic_des_esslen;
362 	cmd.BeaconPeriod = 100;
363 
364 	err = atu_send_command(sc, (uint8_t *)&cmd, sizeof (cmd));
365 	if (err)
366 		return (err);
367 	err = atu_wait_completion(sc, CMD_STARTUP, NULL);
368 	if (err)
369 		return (err);
370 
371 	err = atu_switch_radio(sc, B_TRUE);
372 	if (err)
373 		return (err);
374 
375 	err = atu_send_mib(sc, MIB_MAC_MGMT_POWER_MODE,
376 	    (void *)ATU_POWER_ACTIVE);
377 	if (err)
378 		return (err);
379 
380 	return (0);
381 }
382 
383 static int
384 atu_start_scan(struct atu_softc *sc)
385 {
386 	struct ieee80211com	*ic = &sc->sc_ic;
387 	struct atu_cmd_do_scan	scan;
388 	int			err;
389 
390 	if (!ATU_RUNNING(sc))
391 		return (EIO);
392 
393 	bzero(&scan, sizeof (scan));
394 	scan.Cmd = CMD_START_SCAN;
395 	scan.Reserved = 0;
396 	scan.Size = sizeof (scan) - 4;
397 	(void) memset(scan.BSSID, 0xff, sizeof (scan.BSSID));
398 	bcopy(ic->ic_des_essid, scan.SSID, ic->ic_des_esslen);
399 	scan.SSID_Len = ic->ic_des_esslen;
400 	scan.ScanType = ATU_SCAN_ACTIVE;
401 	scan.Channel = ieee80211_chan2ieee(ic, ic->ic_curchan);
402 	scan.ProbeDelay = 0;
403 	scan.MinChannelTime = 20;
404 	scan.MaxChannelTime = 40;
405 	scan.InternationalScan = 0;
406 
407 	err = atu_send_command(sc, (uint8_t *)&scan, sizeof (scan));
408 	if (err) {
409 		cmn_err(CE_WARN, "%s: SCAN command failed\n",
410 		    sc->sc_name);
411 		return (err);
412 	}
413 
414 	err = atu_wait_completion(sc, CMD_START_SCAN, NULL);
415 	if (err) {
416 		cmn_err(CE_WARN, "%s: SCAN completion failed\n",
417 		    sc->sc_name);
418 		return (err);
419 	}
420 
421 	return (0);
422 }
423 
424 static int
425 atu_join(struct atu_softc *sc, struct ieee80211_node *node)
426 {
427 	struct atu_cmd_join	join;
428 	uint8_t			status;
429 	int			err;
430 
431 	bzero(&join, sizeof (join));
432 	join.Cmd = CMD_JOIN;
433 	join.Reserved = 0x00;
434 	join.Size = sizeof (join) - 4;
435 	bcopy(node->in_bssid, join.bssid, IEEE80211_ADDR_LEN);
436 	bcopy(node->in_essid, join.essid, node->in_esslen);
437 	join.essid_size = node->in_esslen;
438 
439 	if (node->in_capinfo & IEEE80211_CAPINFO_IBSS)
440 		join.bss_type = ATU_MODE_IBSS;
441 	else
442 		join.bss_type = ATU_MODE_STA;
443 
444 	join.channel = ieee80211_chan2ieee(&sc->sc_ic, node->in_chan);
445 	join.timeout = ATU_JOIN_TIMEOUT;
446 	join.reserved = 0x00;
447 
448 	err = atu_send_command(sc, (uint8_t *)&join, sizeof (join));
449 	if (err) {
450 		cmn_err(CE_WARN, "%s: JOIN command failed\n",
451 		    sc->sc_name);
452 		return (err);
453 	}
454 	err = atu_wait_completion(sc, CMD_JOIN, &status);
455 	if (err)
456 		return (err);
457 
458 	if (status != STATUS_COMPLETE) {
459 		cmn_err(CE_WARN, "%s: incorrect JOIN state (0x%02x)\n",
460 		    sc->sc_name, status);
461 		return (EIO);
462 	}
463 
464 	return (0);
465 }
466 
467 static int
468 atu_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
469 {
470 	struct atu_softc	*sc = (struct atu_softc *)ic;
471 	enum ieee80211_state	ostate = ic->ic_state;
472 	int			err = 0;
473 
474 	ATU_LOCK(sc);
475 
476 	if (sc->sc_scan_timer != 0) {
477 		ATU_UNLOCK(sc);
478 		(void) untimeout(sc->sc_scan_timer);
479 		ATU_LOCK(sc);
480 		sc->sc_scan_timer = 0;
481 	}
482 	ostate = ic->ic_state;
483 
484 	switch (nstate) {
485 	case IEEE80211_S_SCAN:
486 		switch (ostate) {
487 			case IEEE80211_S_SCAN:
488 			case IEEE80211_S_AUTH:
489 			case IEEE80211_S_ASSOC:
490 			case IEEE80211_S_RUN:
491 				ATU_UNLOCK(sc);
492 				sc->sc_newstate(ic, nstate, arg);
493 				ATU_LOCK(sc);
494 				if ((err = atu_start_scan(sc)) != 0) {
495 					ATU_UNLOCK(sc);
496 					ieee80211_cancel_scan(ic);
497 					return (err);
498 				}
499 				sc->sc_scan_timer = timeout(
500 				    (void (*) (void*))ieee80211_next_scan,
501 				    (void *)&sc->sc_ic, 0);
502 
503 				ATU_UNLOCK(sc);
504 				return (err);
505 			default:
506 				break;
507 		}
508 		break;
509 
510 	case IEEE80211_S_AUTH:
511 		switch (ostate) {
512 		case IEEE80211_S_INIT:
513 		case IEEE80211_S_SCAN:
514 			err = atu_join(sc, ic->ic_bss);
515 			if (err) {
516 				ATU_UNLOCK(sc);
517 				return (err);
518 			}
519 			break;
520 		default:
521 			break;
522 		}
523 	default:
524 		break;
525 	}
526 
527 	ATU_UNLOCK(sc);
528 	err = sc->sc_newstate(ic, nstate, arg);
529 
530 	return (err);
531 }
532 
533 static int
534 atu_open_pipes(struct atu_softc *sc)
535 {
536 	usb_ep_data_t		*ep;
537 	usb_pipe_policy_t	policy = {0};
538 	int			uret;
539 
540 	ep = usb_lookup_ep_data(sc->sc_dip, sc->sc_udev, 0, 0, 0,
541 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
542 	policy.pp_max_async_reqs = ATU_TX_LIST_CNT;
543 
544 	uret = usb_pipe_open(sc->sc_dip, &ep->ep_descr, &policy,
545 	    USB_FLAGS_SLEEP, &sc->sc_tx_pipe);
546 	if (uret != USB_SUCCESS)
547 		goto fail;
548 
549 	ep = usb_lookup_ep_data(sc->sc_dip, sc->sc_udev, 0, 0, 0,
550 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
551 	policy.pp_max_async_reqs = ATU_RX_LIST_CNT + 32;
552 
553 	uret = usb_pipe_open(sc->sc_dip, &ep->ep_descr, &policy,
554 	    USB_FLAGS_SLEEP, &sc->sc_rx_pipe);
555 	if (uret != USB_SUCCESS)
556 		goto fail;
557 
558 	return (0);
559 fail:
560 	if (sc->sc_rx_pipe != NULL) {
561 		usb_pipe_close(sc->sc_dip, sc->sc_rx_pipe,
562 		    USB_FLAGS_SLEEP, NULL, 0);
563 		sc->sc_rx_pipe = NULL;
564 	}
565 
566 	if (sc->sc_tx_pipe != NULL) {
567 		usb_pipe_close(sc->sc_dip, sc->sc_tx_pipe,
568 		    USB_FLAGS_SLEEP, NULL, 0);
569 		sc->sc_tx_pipe = NULL;
570 	}
571 
572 	return (EIO);
573 }
574 
575 static void
576 atu_close_pipes(struct atu_softc *sc)
577 {
578 	usb_flags_t flags = USB_FLAGS_SLEEP;
579 
580 	if (sc->sc_rx_pipe != NULL) {
581 		usb_pipe_reset(sc->sc_dip, sc->sc_rx_pipe, flags, NULL, 0);
582 		usb_pipe_close(sc->sc_dip, sc->sc_rx_pipe, flags, NULL, 0);
583 		sc->sc_rx_pipe = NULL;
584 	}
585 
586 	if (sc->sc_tx_pipe != NULL) {
587 		usb_pipe_reset(sc->sc_dip, sc->sc_tx_pipe, flags, NULL, 0);
588 		usb_pipe_close(sc->sc_dip, sc->sc_tx_pipe, flags, NULL, 0);
589 		sc->sc_tx_pipe = NULL;
590 	}
591 }
592 
593 static int atu_rx_trigger(struct atu_softc *sc);
594 
595 /*ARGSUSED*/
596 static void
597 atu_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
598 {
599 	struct atu_softc *sc = (struct atu_softc *)req->bulk_client_private;
600 	struct ieee80211com	*ic = &sc->sc_ic;
601 	struct ieee80211_node	*ni;
602 	struct atu_rx_hdr	*h;
603 	struct ieee80211_frame	*wh;
604 	mblk_t			*mp = req->bulk_data;
605 	int			len, pktlen;
606 
607 	req->bulk_data = NULL;
608 	if (req->bulk_completion_reason != USB_CR_OK) {
609 		sc->sc_rx_err++;
610 		goto fail;
611 	}
612 
613 	len = msgdsize(mp);
614 	if (len < ATU_RX_HDRLEN + ATU_MIN_FRAMELEN) {
615 		cmn_err(CE_CONT, "%s: fragment (%d bytes)\n",
616 		    sc->sc_name, len);
617 		sc->sc_rx_err++;
618 		goto fail;
619 	}
620 
621 	h = (struct atu_rx_hdr *)mp->b_rptr;
622 	pktlen = h->length - 4;
623 	if (pktlen + ATU_RX_HDRLEN + 4 != len) {
624 		cmn_err(CE_CONT, "%s: jumbo (%d bytes -> %d bytes)\n",
625 		    sc->sc_name, len, pktlen);
626 		sc->sc_rx_err++;
627 		goto fail;
628 	}
629 
630 	mp->b_rptr += ATU_RX_HDRLEN;
631 	mp->b_wptr = mp->b_rptr + pktlen;
632 	wh = (struct ieee80211_frame *)mp->b_rptr;
633 
634 	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
635 		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
636 
637 	ni = ieee80211_find_rxnode(ic, wh);
638 	(void) ieee80211_input(ic, mp, ni, h->rssi, h->rx_time);
639 	ieee80211_free_node(ni);
640 done:
641 	usb_free_bulk_req(req);
642 
643 	mutex_enter(&sc->sc_rxlock);
644 	sc->rx_queued--;
645 	mutex_exit(&sc->sc_rxlock);
646 
647 	if (ATU_RUNNING(sc))
648 		(void) atu_rx_trigger(sc);
649 	return;
650 fail:
651 	freemsg(mp);
652 	goto done;
653 }
654 
655 /*ARGSUSED*/
656 static void
657 atu_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
658 {
659 	struct atu_softc *sc = (struct atu_softc *)req->bulk_client_private;
660 	struct ieee80211com	*ic = &sc->sc_ic;
661 
662 	if (req->bulk_completion_reason != USB_CR_OK)
663 		ic->ic_stats.is_tx_failed++;
664 	usb_free_bulk_req(req);
665 
666 	mutex_enter(&sc->sc_txlock);
667 	sc->tx_queued--;
668 
669 	if (sc->sc_need_sched) {
670 		sc->sc_need_sched = 0;
671 		mac_tx_update(ic->ic_mach);
672 	}
673 
674 	mutex_exit(&sc->sc_txlock);
675 }
676 
677 static int
678 atu_rx_trigger(struct atu_softc *sc)
679 {
680 	usb_bulk_req_t *req;
681 	int uret;
682 
683 	req = usb_alloc_bulk_req(sc->sc_dip, ATU_RX_BUFSZ, USB_FLAGS_SLEEP);
684 	if (req == NULL)
685 		return (ENOMEM);
686 
687 	req->bulk_len		= ATU_RX_BUFSZ;
688 	req->bulk_client_private = (usb_opaque_t)sc;
689 	req->bulk_timeout	= 0;
690 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
691 	req->bulk_cb		= atu_rxeof;
692 	req->bulk_exc_cb	= atu_rxeof;
693 	req->bulk_completion_reason = 0;
694 	req->bulk_cb_flags	= 0;
695 
696 	uret = usb_pipe_bulk_xfer(sc->sc_rx_pipe, req, 0);
697 	if (uret != USB_SUCCESS) {
698 		usb_free_bulk_req(req);
699 		return (EIO);
700 	}
701 
702 	mutex_enter(&sc->sc_rxlock);
703 	sc->rx_queued++;
704 	mutex_exit(&sc->sc_rxlock);
705 
706 	return (0);
707 }
708 
709 static int
710 atu_tx_trigger(struct atu_softc *sc, mblk_t *mp)
711 {
712 	usb_bulk_req_t *req;
713 	int uret;
714 
715 	req = usb_alloc_bulk_req(sc->sc_dip, 0, USB_FLAGS_SLEEP);
716 	if (req == NULL)
717 		return (EIO);
718 
719 	req->bulk_len		= msgdsize(mp);
720 	req->bulk_data		= mp;
721 	req->bulk_client_private = (usb_opaque_t)sc;
722 	req->bulk_timeout	= 10;
723 	req->bulk_attributes	= USB_ATTRS_AUTOCLEARING;
724 	req->bulk_cb		= atu_txeof;
725 	req->bulk_exc_cb	= atu_txeof;
726 	req->bulk_completion_reason = 0;
727 	req->bulk_cb_flags	= 0;
728 
729 	uret = usb_pipe_bulk_xfer(sc->sc_tx_pipe, req, 0);
730 	if (uret != USB_SUCCESS) {
731 		req->bulk_data = NULL;
732 		usb_free_bulk_req(req);
733 		return (EIO);
734 	}
735 
736 	mutex_enter(&sc->sc_txlock);
737 	sc->tx_queued++;
738 	mutex_exit(&sc->sc_txlock);
739 
740 	return (0);
741 }
742 
743 static int
744 atu_init_rx_queue(struct atu_softc *sc)
745 {
746 	int err, i;
747 
748 	mutex_enter(&sc->sc_rxlock);
749 	sc->rx_queued = 0;
750 	mutex_exit(&sc->sc_rxlock);
751 
752 	for (i = 0; i < ATU_RX_LIST_CNT; i++) {
753 		err = atu_rx_trigger(sc);
754 		if (err)
755 			return (err);
756 	}
757 
758 	return (0);
759 }
760 
761 static void
762 atu_init_tx_queue(struct atu_softc *sc)
763 {
764 	mutex_enter(&sc->sc_txlock);
765 	sc->tx_queued = 0;
766 	mutex_exit(&sc->sc_txlock);
767 }
768 
769 static int
770 atu_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
771 {
772 	struct atu_softc	*sc = (struct atu_softc *)ic;
773 	struct ieee80211_node	*ni = NULL;
774 	struct atu_tx_hdr	*desc;
775 	struct ieee80211_frame	*wh;
776 	mblk_t			*m;
777 	int pktlen = msgdsize(mp), err = 0;
778 
779 	mutex_enter(&sc->sc_txlock);
780 	if (sc->tx_queued > ATU_TX_LIST_CNT) {
781 		sc->sc_tx_nobuf++;
782 		mutex_exit(&sc->sc_txlock);
783 		err = ENOMEM;
784 		goto fail;
785 	}
786 	mutex_exit(&sc->sc_txlock);
787 
788 	m = allocb(ATU_TX_BUFSZ, BPRI_MED);
789 	if (m == NULL) {
790 		sc->sc_tx_nobuf++;
791 		err = ENOMEM;
792 		goto fail;
793 	}
794 	/* reserve tx header space */
795 	m->b_rptr += ATU_TX_HDRLEN;
796 	m->b_wptr += ATU_TX_HDRLEN;
797 
798 	/* copy and (implicitly) free old data */
799 	mcopymsg(mp, m->b_wptr);
800 	m->b_wptr += pktlen;
801 	wh = (struct ieee80211_frame *)m->b_rptr;
802 
803 	ni = ieee80211_find_txnode(ic, wh->i_addr1);
804 	if (ni == NULL) {
805 		ic->ic_stats.is_tx_failed++;
806 		freemsg(m);
807 		err = ENXIO;
808 		goto fail;
809 	}
810 
811 	if (type == IEEE80211_FC0_TYPE_DATA)
812 		(void) ieee80211_encap(ic, m, ni);
813 
814 	/* full WEP in device, prune WEP fields (IV, KID) */
815 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
816 		(void) memmove(m->b_rptr + IEEE80211_WEP_IVLEN
817 		    + IEEE80211_WEP_KIDLEN, m->b_rptr,
818 		    sizeof (struct ieee80211_frame));
819 		m->b_rptr += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
820 	}
821 	pktlen = msgdsize(m);
822 	m->b_rptr -= ATU_TX_HDRLEN;
823 
824 	/* setup tx header */
825 	desc = (struct atu_tx_hdr *)m->b_rptr;
826 	bzero(desc, ATU_TX_HDRLEN);
827 	desc->length = (uint16_t)pktlen;
828 	desc->tx_rate = ATU_DEF_TX_RATE;
829 
830 	err = atu_tx_trigger(sc, m);
831 	if (!err) {
832 		ic->ic_stats.is_tx_frags++;
833 		ic->ic_stats.is_tx_bytes += pktlen;
834 	} else {
835 		ic->ic_stats.is_tx_failed++;
836 		freemsg(m);
837 	}
838 fail:
839 	if (ni != NULL)
840 		ieee80211_free_node(ni);
841 
842 	return (err);
843 }
844 
845 static int
846 atu_stop(struct atu_softc *sc)
847 {
848 	sc->sc_flags &= ~ATU_FLAG_RUNNING;
849 	atu_close_pipes(sc);
850 
851 	return (atu_switch_radio(sc, B_FALSE));
852 }
853 
854 static int
855 atu_init(struct atu_softc *sc)
856 {
857 	int err;
858 
859 	err = atu_stop(sc);
860 	if (err)
861 		return (err);
862 
863 	err = atu_open_pipes(sc);
864 	if (err)
865 		goto fail;
866 
867 	err = atu_config(sc);
868 	if (err) {
869 		cmn_err(CE_WARN, "%s: startup config failed\n",
870 		    sc->sc_name);
871 		goto fail;
872 	}
873 
874 	atu_init_tx_queue(sc);
875 
876 	err = atu_init_rx_queue(sc);
877 	if (err) {
878 		cmn_err(CE_WARN, "%s: rx queue init failed\n", sc->sc_name);
879 		goto fail;
880 	}
881 
882 	sc->sc_flags |= ATU_FLAG_RUNNING;
883 
884 	return (0);
885 fail:
886 	(void) atu_stop(sc);
887 	return (err);
888 }
889 
890 static void
891 atu_watchdog(void *arg)
892 {
893 	struct atu_softc *sc = arg;
894 	struct ieee80211com *ic = &sc->sc_ic;
895 
896 	ieee80211_stop_watchdog(ic);
897 
898 	ATU_LOCK(sc);
899 	if (!ATU_RUNNING(sc)) {
900 		ATU_UNLOCK(sc);
901 		return;
902 	}
903 
904 	ATU_UNLOCK(sc);
905 	switch (ic->ic_state) {
906 		case IEEE80211_S_AUTH:
907 		case IEEE80211_S_ASSOC:
908 			if (ic->ic_bss->in_fails > 0)
909 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
910 			else
911 				ieee80211_watchdog(ic);
912 			break;
913 	}
914 }
915 
916 static int
917 atu_dfu_stage1(void *arg)
918 {
919 	struct atu_softc *sc = arg;
920 	uint8_t	state, *ptr = NULL, status[6];
921 	int block_size, bytes_left = 0, block = 0, err, i, count = 0;
922 
923 	/*
924 	 * Uploading firmware is done with the DFU (Device Firmware Upgrade)
925 	 * interface. See "Universal Serial Bus - Device Class Specification
926 	 * for Device Firmware Upgrade" pdf for details of the protocol.
927 	 * Maybe this could be moved to a separate 'firmware driver' once more
928 	 * device drivers need it... For now we'll just do it here.
929 	 *
930 	 * Just for your information, the Atmel's DFU descriptor looks like
931 	 * this:
932 	 *
933 	 * 07		size
934 	 * 21		type
935 	 * 01		capabilities : only firmware download, *need* reset
936 	 *		  after download
937 	 * 13 05	detach timeout : max 1299ms between DFU_DETACH and
938 	 *		  reset
939 	 * 00 04	max bytes of firmware per transaction : 1024
940 	 */
941 	for (i = 0; i < sizeof (atu_fw_table) / sizeof (atu_fw_table[0]); i++)
942 		if (sc->sc_radio == atu_fw_table[i].atur_type) {
943 			ptr = atu_fw_table[i].atur_int;
944 			bytes_left = atu_fw_table[i].atur_int_size;
945 		}
946 
947 	state = atu_get_dfu_state(sc);
948 	while (block >= 0 && state > 0) {
949 		switch (state) {
950 		case DFUState_DnLoadSync:
951 			/* get DFU status */
952 			err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0, 6,
953 			    status);
954 			if (err) {
955 				cmn_err(CE_WARN, "%s: DFU get status failed\n",
956 				    sc->sc_name);
957 				return (err);
958 			}
959 			/* success means state => DnLoadIdle */
960 			state = DFUState_DnLoadIdle;
961 			continue;
962 
963 		case DFUState_DFUIdle:
964 		case DFUState_DnLoadIdle:
965 			if (bytes_left >= DFU_MaxBlockSize)
966 				block_size = DFU_MaxBlockSize;
967 			else
968 				block_size = bytes_left;
969 
970 			err = atu_usb_request(sc, DFU_DNLOAD, block++, 0,
971 			    block_size, ptr);
972 			if (err) {
973 				cmn_err(CE_WARN, "%s: DFU download failed\n",
974 				    sc->sc_name);
975 				return (err);
976 			}
977 
978 			ptr += block_size;
979 			bytes_left -= block_size;
980 			if (block_size == 0)
981 				block = -1;
982 			break;
983 
984 		case DFUState_DFUError:
985 			cmn_err(CE_WARN, "%s: DFU state error\n", sc->sc_name);
986 			return (EIO);
987 
988 		default:
989 			drv_usecwait(10*1000);
990 			if (++count > 100) {
991 				cmn_err(CE_WARN, "%s: DFU timeout\n",
992 				    sc->sc_name);
993 				return (ETIME);
994 			}
995 			break;
996 		}
997 
998 		state = atu_get_dfu_state(sc);
999 	}
1000 	if (state != DFUState_ManifestSync)
1001 		cmn_err(CE_WARN, "%s: DFU state (%d) != ManifestSync\n",
1002 		    sc->sc_name, state);
1003 
1004 	err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0, 6, status);
1005 	if (err) {
1006 		cmn_err(CE_WARN, "%s: DFU get status failed\n",
1007 		    sc->sc_name);
1008 		return (err);
1009 	}
1010 
1011 	err = atu_usb_request(sc, DFU_REMAP, 0, 0, 0, NULL);
1012 	if (err && !(sc->sc_quirk & ATU_QUIRK_NO_REMAP)) {
1013 		cmn_err(CE_WARN, "%s: DFU remap failed\n", sc->sc_name);
1014 		return (err);
1015 	}
1016 
1017 	/*
1018 	 * after a lot of trying and measuring I found out the device needs
1019 	 * about 56 miliseconds after sending the remap command before
1020 	 * it's ready to communicate again. So we'll wait just a little bit
1021 	 * longer than that to be sure...
1022 	 */
1023 	drv_usecwait((56+100)*1000);
1024 
1025 	return (0);
1026 }
1027 
1028 static int
1029 atu_dfu_stage2(void *arg)
1030 {
1031 	struct atu_softc *sc = arg;
1032 	uint8_t	*ptr = NULL;
1033 	int block_size, bytes_left = 0, block = 0, err, i;
1034 
1035 	for (i = 0; i < sizeof (atu_fw_table) / sizeof (atu_fw_table[0]); i++)
1036 		if (sc->sc_radio == atu_fw_table[i].atur_type) {
1037 			ptr = atu_fw_table[i].atur_ext;
1038 			bytes_left = atu_fw_table[i].atur_ext_size;
1039 		}
1040 
1041 	while (bytes_left) {
1042 		if (bytes_left > 1024)
1043 			block_size = 1024;
1044 		else
1045 			block_size = bytes_left;
1046 
1047 		err = atu_usb_request(sc, ATU_VENDOR_DEV_OUT, 0x0e,
1048 		    0x0802, block, block_size, ptr);
1049 		if (err) {
1050 			cmn_err(CE_WARN, "%s: stage2 firmware load failed\n",
1051 			    sc->sc_name);
1052 			return (err);
1053 		}
1054 
1055 		ptr += block_size;
1056 		block++;
1057 		bytes_left -= block_size;
1058 	}
1059 
1060 	err = atu_usb_request(sc, ATU_VENDOR_DEV_OUT, 0x0e, 0x0802,
1061 	    block, 0, NULL);
1062 	if (err) {
1063 		cmn_err(CE_WARN, "%s: zero-length block load failed\n",
1064 		    sc->sc_name);
1065 		return (err);
1066 	}
1067 
1068 	/*
1069 	 * The SMC2662w V.4 seems to require some time to do its thing with
1070 	 * the stage2 firmware... 20 ms isn't enough, but 21 ms works 100
1071 	 * times out of 100 tries. We'll wait a bit longer just to be sure
1072 	 */
1073 	if (sc->sc_quirk & ATU_QUIRK_FW_DELAY)
1074 		drv_usecwait((21 + 100) * 1000);
1075 
1076 	return (0);
1077 }
1078 
1079 static int
1080 atu_load_microcode(struct atu_softc *sc, boolean_t attach)
1081 {
1082 	usb_dev_reset_lvl_t	reset;
1083 	uint8_t			mode, chan;
1084 	int			err;
1085 
1086 	reset = attach ? USB_RESET_LVL_REATTACH : USB_RESET_LVL_DEFAULT;
1087 
1088 	err = atu_get_opmode(sc, &mode);
1089 	if (!err) {
1090 		if (mode == ATU_DEV_READY)
1091 			return (0);
1092 		/*
1093 		 * Opmode of SMC2662 V.4 does not change after stage2
1094 		 * firmware download. If succeeded reading the channel
1095 		 * number, stage2 firmware is already running.
1096 		 */
1097 		if (sc->sc_radio != RadioIntersil &&
1098 		    atu_get_mib(sc, MIB_PHY_CHANNEL, &chan) == 0)
1099 			return (0);
1100 
1101 		if (mode == ATU_DEV_STAGE2)
1102 stage2:
1103 			return (atu_dfu_stage2(sc));
1104 	}
1105 
1106 	err = atu_dfu_stage1(sc);
1107 	if (err)
1108 		return (err);
1109 
1110 	if (usb_reset_device(sc->sc_dip, reset) != USB_SUCCESS)
1111 		return (EIO);
1112 
1113 	if (attach)
1114 		return (EAGAIN);
1115 	else
1116 		goto stage2;
1117 }
1118 
1119 static int
1120 atu_disconnect(dev_info_t *dip)
1121 {
1122 	struct atu_softc *sc;
1123 	struct ieee80211com *ic;
1124 
1125 	sc = ddi_get_soft_state(atu_soft_state_p, ddi_get_instance(dip));
1126 	ic = &sc->sc_ic;
1127 
1128 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1129 	ieee80211_stop_watchdog(ic);
1130 
1131 	ATU_LOCK(sc);
1132 	if (sc->sc_scan_timer != 0) {
1133 		ATU_UNLOCK(sc);
1134 		(void) untimeout(sc->sc_scan_timer);
1135 		ATU_LOCK(sc);
1136 		sc->sc_scan_timer = 0;
1137 	}
1138 
1139 	sc->sc_flags &= ~(ATU_FLAG_RUNNING | ATU_FLAG_RADIO_ON);
1140 	atu_close_pipes(sc);
1141 
1142 	ATU_UNLOCK(sc);
1143 	return (0);
1144 }
1145 
1146 static int
1147 atu_reconnect(dev_info_t *dip)
1148 {
1149 	struct atu_softc *sc;
1150 	int err;
1151 
1152 	sc = ddi_get_soft_state(atu_soft_state_p, ddi_get_instance(dip));
1153 	if (usb_check_same_device(sc->sc_dip, NULL, USB_LOG_L2, -1,
1154 	    USB_CHK_BASIC, NULL) != USB_SUCCESS)
1155 		return (DDI_FAILURE);
1156 
1157 	ATU_LOCK(sc);
1158 	err = atu_load_microcode(sc, B_FALSE);
1159 	if (!err)
1160 		err = atu_init(sc);
1161 
1162 	ATU_UNLOCK(sc);
1163 	return (err ? DDI_FAILURE : DDI_SUCCESS);
1164 }
1165 
1166 static int
1167 atu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1168 {
1169 	struct atu_softc	*sc;
1170 	struct ieee80211com	*ic;
1171 	mac_register_t		*macp;
1172 	wifi_data_t		wd = {0};
1173 	int			instance, i, err;
1174 
1175 	switch (cmd) {
1176 	case DDI_ATTACH:
1177 		break;
1178 	case DDI_RESUME:
1179 		sc = ddi_get_soft_state(atu_soft_state_p,
1180 		    ddi_get_instance(dip));
1181 		if (usb_check_same_device(sc->sc_dip, NULL, USB_LOG_L2, -1,
1182 		    USB_CHK_BASIC, NULL) != USB_SUCCESS)
1183 			return (DDI_SUCCESS);
1184 
1185 		if (atu_load_microcode(sc, B_FALSE) == 0)
1186 			(void) atu_init(sc);
1187 
1188 		return (DDI_SUCCESS);
1189 	default:
1190 		return (DDI_FAILURE);
1191 	}
1192 
1193 	instance = ddi_get_instance(dip);
1194 	if (ddi_soft_state_zalloc(atu_soft_state_p, instance) != DDI_SUCCESS)
1195 		return (DDI_FAILURE);
1196 
1197 	sc = ddi_get_soft_state(atu_soft_state_p, instance);
1198 	ic = &sc->sc_ic;
1199 	sc->sc_dip = dip;
1200 
1201 	(void) snprintf(sc->sc_name, sizeof (sc->sc_name), "%s%d",
1202 	    "atu", instance);
1203 
1204 	err = usb_client_attach(dip, USBDRV_VERSION, 0);
1205 	if (err != USB_SUCCESS)
1206 		goto fail1;
1207 
1208 	err = usb_get_dev_data(dip, &sc->sc_udev, USB_PARSE_LVL_ALL, 0);
1209 	if (err != USB_SUCCESS) {
1210 		sc->sc_udev = NULL;
1211 		goto fail2;
1212 	}
1213 
1214 	for (i = 0; i < sizeof (atu_dev_table)/sizeof (atu_dev_table[0]); i++) {
1215 		struct atu_dev_type *t = &atu_dev_table[i];
1216 		if (sc->sc_udev->dev_descr->idVendor == t->atu_vid &&
1217 		    sc->sc_udev->dev_descr->idProduct == t->atu_pid) {
1218 			sc->sc_radio = t->atu_radio;
1219 			sc->sc_quirk = t->atu_quirk;
1220 		}
1221 	}
1222 
1223 	err = atu_load_microcode(sc, B_TRUE);
1224 	if (err == EAGAIN) {
1225 		sc->sc_flags |= ATU_FLAG_REATTACH;	/* reattaching */
1226 		return (DDI_SUCCESS);
1227 	} else if (err) {
1228 		goto fail2;
1229 	}
1230 	sc->sc_flags &= ~ATU_FLAG_REATTACH;
1231 
1232 	/* read device config & MAC address */
1233 	err = atu_get_config(sc);
1234 	if (err) {
1235 		cmn_err(CE_WARN, "%s: read device config failed\n",
1236 		    sc->sc_name);
1237 		goto fail2;
1238 	}
1239 
1240 	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
1241 	mutex_init(&sc->sc_txlock, NULL, MUTEX_DRIVER, NULL);
1242 	mutex_init(&sc->sc_rxlock, NULL, MUTEX_DRIVER, NULL);
1243 
1244 	ic->ic_phytype = IEEE80211_T_DS;
1245 	ic->ic_opmode = IEEE80211_M_STA;
1246 	ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_WEP;
1247 	ic->ic_sup_rates[IEEE80211_MODE_11B] = atu_rateset;
1248 	ic->ic_maxrssi = atu_fw_table[sc->sc_radio].max_rssi;
1249 	ic->ic_state = IEEE80211_S_INIT;
1250 	for (i = 1; i <= 14; i++) {
1251 		ic->ic_sup_channels[i].ich_freq =
1252 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
1253 		ic->ic_sup_channels[i].ich_flags =
1254 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ |
1255 		    IEEE80211_CHAN_PASSIVE;
1256 	}
1257 	ic->ic_xmit = atu_send;
1258 	ieee80211_attach(ic);
1259 
1260 	sc->sc_newstate = ic->ic_newstate;
1261 	ic->ic_newstate = atu_newstate;
1262 	ic->ic_watchdog = atu_watchdog;
1263 	ieee80211_media_init(ic);
1264 
1265 	ic->ic_def_txkey = 0;
1266 	wd.wd_opmode = ic->ic_opmode;
1267 	wd.wd_secalloc = WIFI_SEC_NONE;
1268 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
1269 
1270 	macp = mac_alloc(MAC_VERSION);
1271 	if (macp == NULL)
1272 		goto fail3;
1273 
1274 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
1275 	macp->m_driver		= sc;
1276 	macp->m_dip		= dip;
1277 	macp->m_src_addr	= ic->ic_macaddr;
1278 	macp->m_callbacks	= &atu_m_callbacks;
1279 	macp->m_min_sdu		= 0;
1280 	macp->m_max_sdu		= IEEE80211_MTU;
1281 	macp->m_pdata		= &wd;
1282 	macp->m_pdata_size	= sizeof (wd);
1283 
1284 	err = mac_register(macp, &ic->ic_mach);
1285 	mac_free(macp);
1286 	if (err)
1287 		goto fail3;
1288 
1289 	err = usb_register_hotplug_cbs(sc->sc_dip, atu_disconnect,
1290 	    atu_reconnect);
1291 	if (err != USB_SUCCESS)
1292 		goto fail4;
1293 
1294 	err = ddi_create_minor_node(dip, sc->sc_name, S_IFCHR,
1295 	    instance + 1, DDI_NT_NET_WIFI, 0);
1296 	if (err != DDI_SUCCESS)
1297 		cmn_err(CE_WARN, "%s: minor node creation failed\n",
1298 		    sc->sc_name);
1299 
1300 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
1301 	return (DDI_SUCCESS);
1302 
1303 fail4:
1304 	(void) mac_unregister(ic->ic_mach);
1305 fail3:
1306 	mutex_destroy(&sc->sc_genlock);
1307 	mutex_destroy(&sc->sc_rxlock);
1308 	mutex_destroy(&sc->sc_txlock);
1309 fail2:
1310 	usb_client_detach(sc->sc_dip, sc->sc_udev);
1311 fail1:
1312 	ddi_soft_state_free(atu_soft_state_p, instance);
1313 
1314 	return (DDI_FAILURE);
1315 }
1316 
1317 static int
1318 atu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1319 {
1320 	struct atu_softc *sc;
1321 	int err;
1322 
1323 	sc = ddi_get_soft_state(atu_soft_state_p, ddi_get_instance(dip));
1324 
1325 	switch (cmd) {
1326 	case DDI_DETACH:
1327 		break;
1328 	case DDI_SUSPEND:
1329 		ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
1330 		ieee80211_stop_watchdog(&sc->sc_ic);
1331 
1332 		ATU_LOCK(sc);
1333 		if (sc->sc_scan_timer != 0) {
1334 			ATU_UNLOCK(sc);
1335 			(void) untimeout(sc->sc_scan_timer);
1336 			ATU_LOCK(sc);
1337 			sc->sc_scan_timer = 0;
1338 		}
1339 		(void) atu_stop(sc);
1340 
1341 		ATU_UNLOCK(sc);
1342 		return (DDI_SUCCESS);
1343 	default:
1344 		return (DDI_FAILURE);
1345 	}
1346 
1347 	if (!ATU_REATTACH(sc)) {
1348 		err = mac_disable(sc->sc_ic.ic_mach);
1349 		if (err)
1350 			return (DDI_FAILURE);
1351 
1352 		(void) atu_stop(sc);
1353 
1354 		usb_unregister_hotplug_cbs(dip);
1355 		(void) mac_unregister(sc->sc_ic.ic_mach);
1356 		ieee80211_detach(&sc->sc_ic);
1357 
1358 		mutex_destroy(&sc->sc_genlock);
1359 		mutex_destroy(&sc->sc_txlock);
1360 		mutex_destroy(&sc->sc_rxlock);
1361 
1362 		ddi_remove_minor_node(dip, NULL);
1363 	}
1364 
1365 	usb_client_detach(dip, sc->sc_udev);
1366 	ddi_soft_state_free(atu_soft_state_p, ddi_get_instance(dip));
1367 
1368 	return (DDI_SUCCESS);
1369 }
1370 
1371 DDI_DEFINE_STREAM_OPS(atu_dev_ops, nulldev, nulldev, atu_attach,
1372     atu_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
1373 
1374 static struct modldrv atu_modldrv = {
1375 	&mod_driverops,
1376 	"atu driver v1.1",
1377 	&atu_dev_ops
1378 };
1379 
1380 static struct modlinkage modlinkage = {
1381 	MODREV_1,
1382 	(void *)&atu_modldrv,
1383 	NULL
1384 };
1385 
1386 int
1387 _info(struct modinfo *modinfop)
1388 {
1389 	return (mod_info(&modlinkage, modinfop));
1390 }
1391 
1392 int
1393 _init(void)
1394 {
1395 	int status;
1396 
1397 	status = ddi_soft_state_init(&atu_soft_state_p,
1398 	    sizeof (struct atu_softc), 1);
1399 	if (status != 0)
1400 		return (status);
1401 
1402 	mac_init_ops(&atu_dev_ops, "atu");
1403 	status = mod_install(&modlinkage);
1404 	if (status != 0) {
1405 		mac_fini_ops(&atu_dev_ops);
1406 		ddi_soft_state_fini(&atu_soft_state_p);
1407 	}
1408 	return (status);
1409 }
1410 
1411 int
1412 _fini(void)
1413 {
1414 	int status;
1415 
1416 	status = mod_remove(&modlinkage);
1417 	if (status == 0) {
1418 		mac_fini_ops(&atu_dev_ops);
1419 		ddi_soft_state_fini(&atu_soft_state_p);
1420 	}
1421 	return (status);
1422 }
1423 
1424 static int
1425 atu_m_start(void *arg)
1426 {
1427 	struct atu_softc *sc = (struct atu_softc *)arg;
1428 	int err;
1429 
1430 	ATU_LOCK(sc);
1431 	err = atu_init(sc);
1432 
1433 	ATU_UNLOCK(sc);
1434 	return (err);
1435 }
1436 
1437 static void
1438 atu_m_stop(void *arg)
1439 {
1440 	struct atu_softc *sc = (struct atu_softc *)arg;
1441 	struct ieee80211com *ic = &sc->sc_ic;
1442 
1443 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1444 	ieee80211_stop_watchdog(ic);
1445 
1446 	ATU_LOCK(sc);
1447 	if (sc->sc_scan_timer != 0) {
1448 		ATU_UNLOCK(sc);
1449 		(void) untimeout(sc->sc_scan_timer);
1450 		ATU_LOCK(sc);
1451 		sc->sc_scan_timer = 0;
1452 	}
1453 	(void) atu_stop(sc);
1454 
1455 	ATU_UNLOCK(sc);
1456 }
1457 
1458 /*ARGSUSED*/
1459 static int
1460 atu_m_unicst(void *arg, const uint8_t *macaddr)
1461 {
1462 	return (ENOTSUP);
1463 }
1464 
1465 /*ARGSUSED*/
1466 static int
1467 atu_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1468 {
1469 	return (ENOTSUP);
1470 }
1471 
1472 /*ARGSUSED*/
1473 static int
1474 atu_m_promisc(void *arg, boolean_t on)
1475 {
1476 	return (0);
1477 }
1478 
1479 static int
1480 atu_m_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t len,
1481     const void *buf)
1482 {
1483 	struct atu_softc *sc = (struct atu_softc *)arg;
1484 	struct ieee80211com *ic = &sc->sc_ic;
1485 	int err;
1486 
1487 	err = ieee80211_setprop(ic, name, id, len, buf);
1488 	if (err != ENETRESET)
1489 		return (err);
1490 	if (ic->ic_des_esslen == 0)
1491 		return (0);
1492 
1493 	ATU_LOCK(sc);
1494 	if (ATU_RUNNING(sc)) {
1495 		if (sc->sc_scan_timer != 0) {
1496 			ATU_UNLOCK(sc);
1497 			(void) untimeout(sc->sc_scan_timer);
1498 			ATU_LOCK(sc);
1499 			sc->sc_scan_timer = 0;
1500 		}
1501 		err = atu_init(sc);
1502 
1503 		ATU_UNLOCK(sc);
1504 		if (err)
1505 			return (err);
1506 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1507 		ATU_LOCK(sc);
1508 	}
1509 
1510 	ATU_UNLOCK(sc);
1511 	return (0);
1512 }
1513 
1514 static void
1515 atu_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
1516 {
1517 	struct atu_softc *sc = (struct atu_softc *)arg;
1518 	struct ieee80211com *ic = &sc->sc_ic;
1519 	int err;
1520 
1521 	err = ieee80211_ioctl(ic, wq, mp);
1522 	if (err != ENETRESET || ic->ic_des_esslen == 0)
1523 		return;
1524 
1525 	ATU_LOCK(sc);
1526 	if (ATU_RUNNING(sc)) {
1527 		if (sc->sc_scan_timer != 0) {
1528 			ATU_UNLOCK(sc);
1529 			(void) untimeout(sc->sc_scan_timer);
1530 			ATU_LOCK(sc);
1531 			sc->sc_scan_timer = 0;
1532 		}
1533 		err = atu_init(sc);
1534 
1535 		ATU_UNLOCK(sc);
1536 		if (err)
1537 			return;
1538 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1539 		ATU_LOCK(sc);
1540 	}
1541 
1542 	ATU_UNLOCK(sc);
1543 }
1544 
1545 static mblk_t *
1546 atu_m_tx(void *arg, mblk_t *mp)
1547 {
1548 	struct atu_softc *sc = (struct atu_softc *)arg;
1549 	struct ieee80211com *ic = &sc->sc_ic;
1550 	mblk_t *next;
1551 
1552 	if (ic->ic_state != IEEE80211_S_RUN) {
1553 		freemsgchain(mp);
1554 		return (NULL);
1555 	}
1556 
1557 	while (mp != NULL) {
1558 		next = mp->b_next;
1559 		mp->b_next = NULL;
1560 		if (atu_send(ic, mp, IEEE80211_FC0_TYPE_DATA) == ENOMEM) {
1561 			mutex_enter(&sc->sc_txlock);
1562 			sc->sc_need_sched = 1;
1563 			mutex_exit(&sc->sc_txlock);
1564 
1565 			mp->b_next = next;
1566 			return (mp);
1567 		}
1568 		mp = next;
1569 	}
1570 
1571 	return (mp);
1572 }
1573 
1574 static int
1575 atu_m_stat(void *arg, uint_t stat, uint64_t *val)
1576 {
1577 	struct atu_softc	*sc  = (struct atu_softc *)arg;
1578 	ieee80211com_t		*ic = &sc->sc_ic;
1579 	ieee80211_node_t	*in;
1580 
1581 	ATU_LOCK(sc);
1582 	switch (stat) {
1583 	case MAC_STAT_IFSPEED:
1584 		in = ic->ic_bss;
1585 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
1586 		    IEEE80211_RATE(in->in_txrate) :
1587 		    ic->ic_fixed_rate) / 2 * 1000000;
1588 		break;
1589 	case MAC_STAT_NOXMTBUF:
1590 		*val = sc->sc_tx_nobuf;
1591 		break;
1592 	case MAC_STAT_NORCVBUF:
1593 		*val = sc->sc_rx_nobuf;
1594 		break;
1595 	case MAC_STAT_IERRORS:
1596 		*val = sc->sc_rx_err;
1597 		break;
1598 	case MAC_STAT_RBYTES:
1599 		*val = ic->ic_stats.is_rx_bytes;
1600 		break;
1601 	case MAC_STAT_IPACKETS:
1602 		*val = ic->ic_stats.is_rx_frags;
1603 		break;
1604 	case MAC_STAT_OBYTES:
1605 		*val = ic->ic_stats.is_tx_bytes;
1606 		break;
1607 	case MAC_STAT_OPACKETS:
1608 		*val = ic->ic_stats.is_tx_frags;
1609 		break;
1610 	case MAC_STAT_OERRORS:
1611 		*val = ic->ic_stats.is_tx_failed;
1612 		break;
1613 	case WIFI_STAT_TX_FRAGS:
1614 	case WIFI_STAT_MCAST_TX:
1615 	case WIFI_STAT_TX_FAILED:
1616 	case WIFI_STAT_TX_RETRANS:
1617 	case WIFI_STAT_TX_RERETRANS:
1618 	case WIFI_STAT_RTS_SUCCESS:
1619 	case WIFI_STAT_RTS_FAILURE:
1620 	case WIFI_STAT_ACK_FAILURE:
1621 	case WIFI_STAT_RX_FRAGS:
1622 	case WIFI_STAT_MCAST_RX:
1623 	case WIFI_STAT_FCS_ERRORS:
1624 	case WIFI_STAT_WEP_ERRORS:
1625 	case WIFI_STAT_RX_DUPS:
1626 		ATU_UNLOCK(sc);
1627 		return (ieee80211_stat(ic, stat, val));
1628 	default:
1629 		ATU_UNLOCK(sc);
1630 		return (ENOTSUP);
1631 	}
1632 
1633 	ATU_UNLOCK(sc);
1634 	return (0);
1635 }
1636 
1637 static mac_callbacks_t atu_m_callbacks = {
1638 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
1639 	atu_m_stat,
1640 	atu_m_start,
1641 	atu_m_stop,
1642 	atu_m_promisc,
1643 	atu_m_multicst,
1644 	atu_m_unicst,
1645 	atu_m_tx,
1646 	atu_m_ioctl,
1647 	NULL,
1648 	NULL,
1649 	NULL,
1650 	atu_m_setprop,
1651 	ieee80211_getprop
1652 };
1653