1 /*
2 * Copyright 2010 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
atu_usb_request(struct atu_softc * sc,uint8_t type,uint8_t request,uint16_t value,uint16_t index,uint16_t length,uint8_t * data)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
atu_get_mib(struct atu_softc * sc,uint8_t type,uint8_t size,uint8_t index,uint8_t * buf)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
atu_get_cmd_status(struct atu_softc * sc,uint8_t cmd,uint8_t * status)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
atu_get_dfu_state(struct atu_softc * sc)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
atu_get_opmode(struct atu_softc * sc,uint8_t * mode)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
atu_get_config(struct atu_softc * sc)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
atu_wait_completion(struct atu_softc * sc,uint8_t cmd,uint8_t * status)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
atu_send_command(struct atu_softc * sc,uint8_t * command,int size)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
atu_send_mib(struct atu_softc * sc,uint8_t type,uint8_t size,uint8_t index,void * data)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
atu_switch_radio(struct atu_softc * sc,boolean_t on)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
atu_config(struct atu_softc * sc)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
atu_start_scan(struct atu_softc * sc)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
atu_join(struct atu_softc * sc,struct ieee80211_node * node)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
atu_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)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
atu_open_pipes(struct atu_softc * sc)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
atu_close_pipes(struct atu_softc * sc)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
atu_rxeof(usb_pipe_handle_t pipe,usb_bulk_req_t * req)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
atu_txeof(usb_pipe_handle_t pipe,usb_bulk_req_t * req)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
atu_rx_trigger(struct atu_softc * sc)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
atu_tx_trigger(struct atu_softc * sc,mblk_t * mp)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
atu_init_rx_queue(struct atu_softc * sc)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
atu_init_tx_queue(struct atu_softc * sc)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
atu_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)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
atu_stop(struct atu_softc * sc)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
atu_init(struct atu_softc * sc)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
atu_watchdog(void * arg)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
atu_dfu_stage1(void * arg)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
atu_dfu_stage2(void * arg)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
atu_load_microcode(struct atu_softc * sc,boolean_t attach)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
atu_disconnect(dev_info_t * dip)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
atu_reconnect(dev_info_t * dip)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
atu_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
atu_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
_info(struct modinfo * modinfop)1387 _info(struct modinfo *modinfop)
1388 {
1389 return (mod_info(&modlinkage, modinfop));
1390 }
1391
1392 int
_init(void)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
_fini(void)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
atu_m_start(void * arg)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
atu_m_stop(void * arg)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
atu_m_unicst(void * arg,const uint8_t * macaddr)1460 atu_m_unicst(void *arg, const uint8_t *macaddr)
1461 {
1462 return (ENOTSUP);
1463 }
1464
1465 /*ARGSUSED*/
1466 static int
atu_m_multicst(void * arg,boolean_t add,const uint8_t * mca)1467 atu_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1468 {
1469 return (ENOTSUP);
1470 }
1471
1472 /*ARGSUSED*/
1473 static int
atu_m_promisc(void * arg,boolean_t on)1474 atu_m_promisc(void *arg, boolean_t on)
1475 {
1476 return (0);
1477 }
1478
1479 static int
atu_m_setprop(void * arg,const char * name,mac_prop_id_t id,uint_t len,const void * buf)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 int
atu_m_getprop(void * arg,const char * name,mac_prop_id_t id,uint_t length,void * buf)1515 atu_m_getprop(void *arg, const char *name, mac_prop_id_t id,
1516 uint_t length, void *buf)
1517 {
1518 struct atu_softc *sc = (struct atu_softc *)arg;
1519 struct ieee80211com *ic = &sc->sc_ic;
1520
1521 return (ieee80211_getprop(ic, name, id, length, buf));
1522 }
1523
1524 static void
atu_m_propinfo(void * arg,const char * name,mac_prop_id_t id,mac_prop_info_handle_t mph)1525 atu_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
1526 mac_prop_info_handle_t mph)
1527 {
1528 struct atu_softc *sc = (struct atu_softc *)arg;
1529 struct ieee80211com *ic = &sc->sc_ic;
1530
1531 ieee80211_propinfo(ic, name, id, mph);
1532 }
1533
1534 static void
atu_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)1535 atu_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
1536 {
1537 struct atu_softc *sc = (struct atu_softc *)arg;
1538 struct ieee80211com *ic = &sc->sc_ic;
1539 int err;
1540
1541 err = ieee80211_ioctl(ic, wq, mp);
1542 if (err != ENETRESET || ic->ic_des_esslen == 0)
1543 return;
1544
1545 ATU_LOCK(sc);
1546 if (ATU_RUNNING(sc)) {
1547 if (sc->sc_scan_timer != 0) {
1548 ATU_UNLOCK(sc);
1549 (void) untimeout(sc->sc_scan_timer);
1550 ATU_LOCK(sc);
1551 sc->sc_scan_timer = 0;
1552 }
1553 err = atu_init(sc);
1554
1555 ATU_UNLOCK(sc);
1556 if (err)
1557 return;
1558 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1559 ATU_LOCK(sc);
1560 }
1561
1562 ATU_UNLOCK(sc);
1563 }
1564
1565 static mblk_t *
atu_m_tx(void * arg,mblk_t * mp)1566 atu_m_tx(void *arg, mblk_t *mp)
1567 {
1568 struct atu_softc *sc = (struct atu_softc *)arg;
1569 struct ieee80211com *ic = &sc->sc_ic;
1570 mblk_t *next;
1571
1572 if (ic->ic_state != IEEE80211_S_RUN) {
1573 freemsgchain(mp);
1574 return (NULL);
1575 }
1576
1577 while (mp != NULL) {
1578 next = mp->b_next;
1579 mp->b_next = NULL;
1580 if (atu_send(ic, mp, IEEE80211_FC0_TYPE_DATA) == ENOMEM) {
1581 mutex_enter(&sc->sc_txlock);
1582 sc->sc_need_sched = 1;
1583 mutex_exit(&sc->sc_txlock);
1584
1585 mp->b_next = next;
1586 return (mp);
1587 }
1588 mp = next;
1589 }
1590
1591 return (mp);
1592 }
1593
1594 static int
atu_m_stat(void * arg,uint_t stat,uint64_t * val)1595 atu_m_stat(void *arg, uint_t stat, uint64_t *val)
1596 {
1597 struct atu_softc *sc = (struct atu_softc *)arg;
1598 ieee80211com_t *ic = &sc->sc_ic;
1599 ieee80211_node_t *in;
1600
1601 ATU_LOCK(sc);
1602 switch (stat) {
1603 case MAC_STAT_IFSPEED:
1604 in = ic->ic_bss;
1605 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
1606 IEEE80211_RATE(in->in_txrate) :
1607 ic->ic_fixed_rate) / 2 * 1000000;
1608 break;
1609 case MAC_STAT_NOXMTBUF:
1610 *val = sc->sc_tx_nobuf;
1611 break;
1612 case MAC_STAT_NORCVBUF:
1613 *val = sc->sc_rx_nobuf;
1614 break;
1615 case MAC_STAT_IERRORS:
1616 *val = sc->sc_rx_err;
1617 break;
1618 case MAC_STAT_RBYTES:
1619 *val = ic->ic_stats.is_rx_bytes;
1620 break;
1621 case MAC_STAT_IPACKETS:
1622 *val = ic->ic_stats.is_rx_frags;
1623 break;
1624 case MAC_STAT_OBYTES:
1625 *val = ic->ic_stats.is_tx_bytes;
1626 break;
1627 case MAC_STAT_OPACKETS:
1628 *val = ic->ic_stats.is_tx_frags;
1629 break;
1630 case MAC_STAT_OERRORS:
1631 *val = ic->ic_stats.is_tx_failed;
1632 break;
1633 case WIFI_STAT_TX_FRAGS:
1634 case WIFI_STAT_MCAST_TX:
1635 case WIFI_STAT_TX_FAILED:
1636 case WIFI_STAT_TX_RETRANS:
1637 case WIFI_STAT_TX_RERETRANS:
1638 case WIFI_STAT_RTS_SUCCESS:
1639 case WIFI_STAT_RTS_FAILURE:
1640 case WIFI_STAT_ACK_FAILURE:
1641 case WIFI_STAT_RX_FRAGS:
1642 case WIFI_STAT_MCAST_RX:
1643 case WIFI_STAT_FCS_ERRORS:
1644 case WIFI_STAT_WEP_ERRORS:
1645 case WIFI_STAT_RX_DUPS:
1646 ATU_UNLOCK(sc);
1647 return (ieee80211_stat(ic, stat, val));
1648 default:
1649 ATU_UNLOCK(sc);
1650 return (ENOTSUP);
1651 }
1652
1653 ATU_UNLOCK(sc);
1654 return (0);
1655 }
1656
1657 static mac_callbacks_t atu_m_callbacks = {
1658 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
1659 atu_m_stat,
1660 atu_m_start,
1661 atu_m_stop,
1662 atu_m_promisc,
1663 atu_m_multicst,
1664 atu_m_unicst,
1665 atu_m_tx,
1666 NULL,
1667 atu_m_ioctl,
1668 NULL,
1669 NULL,
1670 NULL,
1671 atu_m_setprop,
1672 atu_m_getprop,
1673 atu_m_propinfo
1674 };
1675