1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 2007 by Lukas Turek <turek@ksvi.mff.cuni.cz>
8 * Copyright (c) 2007 by Jiri Svoboda <jirik.svoboda@seznam.cz>
9 * Copyright (c) 2007 by Martin Krulis <martin.krulis@matfyz.cz>
10 * Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr>
11 * Copyright (c) 2006 by Florian Stoehr <ich@florian-stoehr.de>
12 *
13 * Permission to use, copy, modify, and distribute this software for any
14 * purpose with or without fee is hereby granted, provided that the above
15 * copyright notice and this permission notice appear in all copies.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
20 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
23 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 *
25 */
26
27 /*
28 * ZD1211 wLAN driver
29 * USB communication
30 *
31 * Manage USB communication with the ZD-based device.
32 */
33
34 #include <sys/byteorder.h>
35 #include <sys/stream.h>
36 #include <sys/strsun.h>
37 #include <sys/mac_provider.h>
38
39 #include "zyd.h"
40 #include "zyd_reg.h"
41
42 static int zyd_usb_disconnect(dev_info_t *dip);
43 static int zyd_usb_reconnect(dev_info_t *dip);
44 static zyd_res zyd_usb_data_in_start_request(struct zyd_usb *uc);
45
46 static zyd_usb_info_t usb_ids[] = {
47 {0x53, 0x5301, ZYD_ZD1211B},
48 {0x105, 0x145f, ZYD_ZD1211},
49 {0x411, 0xda, ZYD_ZD1211B},
50 {0x471, 0x1236, ZYD_ZD1211B},
51 {0x471, 0x1237, ZYD_ZD1211B},
52 {0x50d, 0x705c, ZYD_ZD1211B},
53 {0x586, 0x3401, ZYD_ZD1211},
54 {0x586, 0x3402, ZYD_ZD1211},
55 {0x586, 0x3407, ZYD_ZD1211},
56 {0x586, 0x3409, ZYD_ZD1211},
57 {0x586, 0x3410, ZYD_ZD1211B},
58 {0x586, 0x3412, ZYD_ZD1211B},
59 {0x586, 0x3413, ZYD_ZD1211B},
60 {0x586, 0x340a, ZYD_ZD1211B},
61 {0x586, 0x340f, ZYD_ZD1211B},
62 {0x79b, 0x4a, ZYD_ZD1211},
63 {0x79b, 0x62, ZYD_ZD1211B},
64 {0x7b8, 0x6001, ZYD_ZD1211},
65 {0x83a, 0x4505, ZYD_ZD1211B},
66 {0xace, 0x1211, ZYD_ZD1211},
67 {0xace, 0x1215, ZYD_ZD1211B},
68 {0xb05, 0x170c, ZYD_ZD1211},
69 {0xb05, 0x171b, ZYD_ZD1211B},
70 {0xb3b, 0x1630, ZYD_ZD1211},
71 {0xb3b, 0x5630, ZYD_ZD1211},
72 {0xbaf, 0x121, ZYD_ZD1211B},
73 {0xcde, 0x1a, ZYD_ZD1211B},
74 {0xdf6, 0x9071, ZYD_ZD1211},
75 {0xdf6, 0x9075, ZYD_ZD1211},
76 {0x126f, 0xa006, ZYD_ZD1211},
77 {0x129b, 0x1666, ZYD_ZD1211},
78 {0x129b, 0x1667, ZYD_ZD1211B},
79 {0x13b1, 0x1e, ZYD_ZD1211},
80 {0x13b1, 0x24, ZYD_ZD1211B},
81 {0x1435, 0x711, ZYD_ZD1211},
82 {0x14ea, 0xab13, ZYD_ZD1211},
83 {0x157e, 0x300b, ZYD_ZD1211},
84 {0x157e, 0x300d, ZYD_ZD1211B},
85 {0x157e, 0x3204, ZYD_ZD1211},
86 {0x1582, 0x6003, ZYD_ZD1211B},
87 {0x1740, 0x2000, ZYD_ZD1211},
88 {0x2019, 0x5303, ZYD_ZD1211B},
89 {0x6891, 0xa727, ZYD_ZD1211}
90 };
91
92 /*
93 * Get mac rev for usb vendor/product id.
94 */
95 zyd_mac_rev_t
zyd_usb_mac_rev(uint16_t vendor,uint16_t product)96 zyd_usb_mac_rev(uint16_t vendor, uint16_t product)
97 {
98 int i;
99
100 ZYD_DEBUG((ZYD_DBG_USB, "matching device usb%x,%x\n", vendor, product));
101 for (i = 0; i < sizeof (usb_ids) / sizeof (zyd_usb_info_t); i++) {
102 if (vendor == usb_ids[i].vendor_id &&
103 product == usb_ids[i].product_id)
104 return (usb_ids[i].mac_rev);
105 }
106
107 ZYD_DEBUG((ZYD_DBG_USB, "assuming ZD1211B\n"));
108 return (ZYD_ZD1211B);
109 }
110
111 /*
112 * Vendor-specific write to the default control pipe.
113 */
114 static zyd_res
zyd_usb_ctrl_send(struct zyd_usb * uc,uint8_t request,uint16_t value,uint8_t * data,uint16_t len)115 zyd_usb_ctrl_send(struct zyd_usb *uc, uint8_t request, uint16_t value,
116 uint8_t *data, uint16_t len)
117 {
118 int err;
119 int retry = 0;
120 mblk_t *msg;
121 usb_ctrl_setup_t setup;
122
123 /* Always clean structures before use */
124 bzero(&setup, sizeof (setup));
125 setup.bmRequestType =
126 USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV;
127 setup.bRequest = request;
128 setup.wValue = value;
129 setup.wIndex = 0;
130 setup.wLength = len;
131 setup.attrs = USB_ATTRS_NONE;
132
133 if ((msg = allocb(len, BPRI_HI)) == NULL)
134 return (ZYD_FAILURE);
135
136 bcopy(data, msg->b_wptr, len);
137 msg->b_wptr += len;
138
139 while ((err = usb_pipe_ctrl_xfer_wait(uc->cdata->dev_default_ph,
140 &setup, &msg, NULL, NULL, 0)) != USB_SUCCESS) {
141 if (retry++ > 3)
142 break;
143 }
144
145 freemsg(msg);
146
147 if (err != USB_SUCCESS) {
148 ZYD_DEBUG((ZYD_DBG_USB,
149 "control pipe send failure (%d)\n", err));
150 return (ZYD_FAILURE);
151 }
152
153 return (ZYD_SUCCESS);
154 }
155
156 /*
157 * Vendor-specific read from the default control pipe.
158 */
159 static zyd_res
zyd_usb_ctrl_recv(struct zyd_usb * uc,uint8_t request,uint16_t value,uint8_t * data,uint16_t len)160 zyd_usb_ctrl_recv(struct zyd_usb *uc, uint8_t request, uint16_t value,
161 uint8_t *data, uint16_t len)
162 {
163 int err;
164 mblk_t *msg, *tmp_msg;
165 usb_ctrl_setup_t setup;
166 size_t msg_len;
167
168 ASSERT(data != NULL);
169
170 bzero(&setup, sizeof (setup));
171 setup.bmRequestType =
172 USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST;
173 setup.bRequest = request;
174 setup.wValue = value;
175 setup.wIndex = 0;
176 setup.wLength = len;
177 setup.attrs = USB_ATTRS_NONE;
178
179 /* Pointer msg must be either set to NULL or point to a valid mblk! */
180 msg = NULL;
181 err = usb_pipe_ctrl_xfer_wait(uc->cdata->dev_default_ph,
182 &setup, &msg, NULL, NULL, 0);
183
184 if (err != USB_SUCCESS) {
185 ZYD_WARN("control pipe receive failure (%d)\n", err);
186 return (ZYD_FAILURE);
187 }
188
189 msg_len = msgsize(msg);
190
191 if (msg_len != len) {
192 ZYD_WARN("control pipe failure: "
193 "received %d bytes, %d expected\n", (int)msg_len, len);
194 return (ZYD_FAILURE);
195 }
196
197 if (msg->b_cont != NULL) {
198 /* Fragmented message, concatenate */
199 tmp_msg = msgpullup(msg, -1);
200 freemsg(msg);
201 msg = tmp_msg;
202 }
203
204 /*
205 * Now we can be sure the message is in a single block
206 * so we can copy it.
207 */
208 bcopy(msg->b_rptr, data, len);
209 freemsg(msg);
210
211 return (ZYD_SUCCESS);
212 }
213
214 /*
215 * Load firmware into the chip.
216 */
217 zyd_res
zyd_usb_loadfirmware(struct zyd_usb * uc,uint8_t * fw,size_t size)218 zyd_usb_loadfirmware(struct zyd_usb *uc, uint8_t *fw, size_t size)
219 {
220 uint16_t addr;
221 uint8_t stat;
222
223 ZYD_DEBUG((ZYD_DBG_FW, "firmware size: %lu\n", size));
224
225 addr = ZYD_FIRMWARE_START_ADDR;
226 while (size > 0) {
227 const uint16_t mlen = (uint16_t)min(size, 4096);
228
229 if (zyd_usb_ctrl_send(uc, ZYD_DOWNLOADREQ, addr, fw, mlen)
230 != USB_SUCCESS)
231 return (ZYD_FAILURE);
232
233 addr += mlen / 2;
234 fw += mlen;
235 size -= mlen;
236 }
237
238 /* check whether the upload succeeded */
239 if (zyd_usb_ctrl_recv(uc, ZYD_DOWNLOADSTS, 0, &stat, sizeof (stat))
240 != ZYD_SUCCESS)
241 return (ZYD_FAILURE);
242
243 return ((stat & 0x80) ? ZYD_FAILURE : ZYD_SUCCESS);
244 }
245
246 /*
247 * Return a specific alt_if from the device descriptor tree.
248 */
249 static usb_alt_if_data_t *
usb_lookup_alt_if(usb_client_dev_data_t * cdd,uint_t config,uint_t interface,uint_t alt)250 usb_lookup_alt_if(usb_client_dev_data_t *cdd, uint_t config,
251 uint_t interface, uint_t alt)
252 {
253 usb_cfg_data_t *dcfg;
254 usb_if_data_t *cfgif;
255 usb_alt_if_data_t *ifalt;
256
257 /*
258 * Assume everything is in the tree for now,
259 * (USB_PARSE_LVL_ALL)
260 * so we can directly index the array.
261 */
262
263 /* Descend to configuration, configs are 1-based */
264 if (config < 1 || config > cdd->dev_n_cfg)
265 return (NULL);
266 dcfg = &cdd->dev_cfg[config - 1];
267
268 /* Descend to interface */
269 if (interface > dcfg->cfg_n_if - 1)
270 return (NULL);
271 cfgif = &dcfg->cfg_if[interface];
272
273 /* Descend to alt */
274 if (alt > cfgif->if_n_alt - 1)
275 return (NULL);
276 ifalt = &cfgif->if_alt[alt];
277
278 return (ifalt);
279 }
280
281 /*
282 * Print all endpoints of an alt_if.
283 */
284 static void
usb_list_all_endpoints(usb_alt_if_data_t * ifalt)285 usb_list_all_endpoints(usb_alt_if_data_t *ifalt)
286 {
287 usb_ep_data_t *ep_data;
288 usb_ep_descr_t *ep_descr;
289 int i;
290
291 for (i = 0; i < ifalt->altif_n_ep; i++) {
292 ep_data = &ifalt->altif_ep[i];
293 ep_descr = &ep_data->ep_descr;
294 cmn_err(CE_NOTE, "EP: %u\n", ep_descr->bEndpointAddress);
295 }
296 }
297
298 /*
299 * For the given alt_if, find an endpoint with the given
300 * address and direction.
301 *
302 * ep_direction USB_EP_DIR_IN or USB_EP_DIR_OUT
303 */
304 static usb_ep_data_t *
usb_find_endpoint(usb_alt_if_data_t * alt_if,uint_t ep_address,uint_t ep_direction)305 usb_find_endpoint(usb_alt_if_data_t *alt_if,
306 uint_t ep_address, uint_t ep_direction)
307 {
308 usb_ep_data_t *ep_data;
309 usb_ep_descr_t *ep_descr;
310 uint_t ep_addr, ep_dir;
311 int i;
312
313 for (i = 0; i < alt_if->altif_n_ep; i++) {
314 ep_data = &alt_if->altif_ep[i];
315 ep_descr = &ep_data->ep_descr;
316 ep_addr = ep_descr->bEndpointAddress & USB_EP_NUM_MASK;
317 ep_dir = ep_descr->bEndpointAddress & USB_EP_DIR_MASK;
318
319 if (ep_addr == ep_address && ep_dir == ep_direction) {
320 return (ep_data);
321 }
322 }
323
324 ZYD_WARN("no endpoint with addr %u, dir %u\n", ep_address,
325 ep_direction);
326 return (NULL);
327 }
328
329 enum zyd_usb_use_attr
330 {
331 ZYD_USB_USE_ATTR = 1,
332 ZYD_USB_NO_ATTR = 0
333 };
334
335 /*
336 * Open a pipe to a given endpoint address/direction in the given
337 * alt_if. Furthemore, if use_attr == ZYD_USB_USE_ATTR,
338 * check whether the endpoint's transfer type is attr.
339 */
340 static zyd_res
zyd_usb_open_pipe(struct zyd_usb * uc,usb_alt_if_data_t * alt_if,uint_t ep_address,uint_t ep_direction,uint_t attr,enum zyd_usb_use_attr use_attr,usb_pipe_handle_t * pipe,usb_ep_data_t * endpoint)341 zyd_usb_open_pipe(struct zyd_usb *uc,
342 usb_alt_if_data_t *alt_if,
343 uint_t ep_address,
344 uint_t ep_direction,
345 uint_t attr,
346 enum zyd_usb_use_attr use_attr,
347 usb_pipe_handle_t *pipe, usb_ep_data_t *endpoint)
348 {
349 usb_pipe_policy_t pipe_policy;
350
351 *endpoint = *usb_find_endpoint(alt_if, ep_address, ep_direction);
352
353 if ((use_attr == ZYD_USB_USE_ATTR) &&
354 (endpoint->ep_descr.bmAttributes & USB_EP_ATTR_MASK) != attr) {
355
356 ZYD_WARN("endpoint %u/%s is not of type %s\n", ep_address,
357 (ep_direction == USB_EP_DIR_IN) ? "IN" : "OUT",
358 (attr == USB_EP_ATTR_BULK) ? "bulk" : "intr");
359 return (ZYD_FAILURE);
360 }
361
362 bzero(&pipe_policy, sizeof (usb_pipe_policy_t));
363 pipe_policy.pp_max_async_reqs = ZYD_USB_REQ_COUNT;
364
365 if (usb_pipe_open(uc->dip, &endpoint->ep_descr,
366 &pipe_policy, USB_FLAGS_SLEEP, pipe) != USB_SUCCESS) {
367 ZYD_WARN("failed to open pipe %u\n", ep_address);
368 return (ZYD_FAILURE);
369 }
370
371 return (ZYD_SUCCESS);
372 }
373
374 /*
375 * Open communication pipes.
376 *
377 * The following pipes are used by the ZD1211:
378 *
379 * 1/OUT BULK
380 * 2/IN BULK
381 * 3/IN INTR
382 * 4/OUT BULK or INTR
383 */
384 zyd_res
zyd_usb_open_pipes(struct zyd_usb * uc)385 zyd_usb_open_pipes(struct zyd_usb *uc)
386 {
387 usb_alt_if_data_t *alt_if;
388
389 ZYD_DEBUG((ZYD_DBG_USB, "opening pipes\n"));
390
391 alt_if = usb_lookup_alt_if(uc->cdata, ZYD_USB_CONFIG_NUMBER,
392 ZYD_USB_IFACE_INDEX, ZYD_USB_ALT_IF_INDEX);
393
394 if (alt_if == NULL) {
395 ZYD_WARN("alt_if not found\n");
396 return (ZYD_FAILURE);
397 }
398
399 #ifdef DEBUG
400 if (zyd_dbg_flags & ZYD_DBG_USB)
401 usb_list_all_endpoints(alt_if);
402 #endif
403
404 if (zyd_usb_open_pipe(uc, alt_if, 1, USB_EP_DIR_OUT, USB_EP_ATTR_BULK,
405 ZYD_USB_USE_ATTR, &uc->pipe_data_out, &uc->ep_data_out) !=
406 ZYD_SUCCESS) {
407 ZYD_WARN("failed to open data OUT pipe\n");
408 goto fail;
409 }
410
411 if (zyd_usb_open_pipe(uc, alt_if, 2, USB_EP_DIR_IN, USB_EP_ATTR_BULK,
412 ZYD_USB_USE_ATTR, &uc->pipe_data_in, &uc->ep_data_in) !=
413 ZYD_SUCCESS) {
414 ZYD_WARN("failed to open data IN pipe\n");
415 goto fail;
416 }
417
418 if (zyd_usb_open_pipe(uc, alt_if, 3, USB_EP_DIR_IN, USB_EP_ATTR_INTR,
419 ZYD_USB_USE_ATTR, &uc->pipe_cmd_in, &uc->ep_cmd_in) !=
420 ZYD_SUCCESS) {
421 ZYD_WARN("failed to open command IN pipe\n");
422 goto fail;
423 }
424
425 /*
426 * Pipe 4/OUT is either a bulk or interrupt pipe.
427 */
428 if (zyd_usb_open_pipe(uc, alt_if, 4, USB_EP_DIR_OUT, 0,
429 ZYD_USB_NO_ATTR, &uc->pipe_cmd_out, &uc->ep_cmd_out) !=
430 ZYD_SUCCESS) {
431 ZYD_WARN("failed to open command OUT pipe\n");
432 goto fail;
433 }
434
435 return (ZYD_SUCCESS);
436
437 fail:
438 zyd_usb_close_pipes(uc);
439 return (ZYD_FAILURE);
440 }
441
442 /*
443 * Close communication pipes.
444 */
445 void
zyd_usb_close_pipes(struct zyd_usb * uc)446 zyd_usb_close_pipes(struct zyd_usb *uc)
447 {
448 ZYD_DEBUG((ZYD_DBG_USB, "closing pipes\n"));
449
450 if (uc->pipe_data_out != NULL) {
451 usb_pipe_close(uc->dip, uc->pipe_data_out, USB_FLAGS_SLEEP,
452 NULL, NULL);
453 uc->pipe_data_out = NULL;
454 }
455
456 if (uc->pipe_data_in != NULL) {
457 usb_pipe_close(uc->dip, uc->pipe_data_in, USB_FLAGS_SLEEP,
458 NULL, NULL);
459 uc->pipe_data_in = NULL;
460 }
461
462 if (uc->pipe_cmd_in != NULL) {
463 usb_pipe_close(uc->dip, uc->pipe_cmd_in, USB_FLAGS_SLEEP,
464 NULL, NULL);
465 uc->pipe_cmd_in = NULL;
466 }
467
468 if (uc->pipe_cmd_out != NULL) {
469 usb_pipe_close(uc->dip, uc->pipe_cmd_out, USB_FLAGS_SLEEP,
470 NULL, NULL);
471 uc->pipe_cmd_out = NULL;
472 }
473 }
474
475 /*
476 * Send a sequence of bytes to a bulk pipe.
477 *
478 * uc pointer to usb module state
479 * data pointer to a buffer of bytes
480 * len size of the buffer (bytes)
481 */
482 /*ARGSUSED*/
483 static void
zyd_data_out_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)484 zyd_data_out_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
485 {
486 struct zyd_softc *sc = (struct zyd_softc *)req->bulk_client_private;
487 struct ieee80211com *ic = &sc->ic;
488 boolean_t resched;
489
490 if (req->bulk_completion_reason != USB_CR_OK)
491 ZYD_DEBUG((ZYD_DBG_USB, "data OUT exception\n"));
492
493 (void) zyd_serial_enter(sc, ZYD_NO_SIG);
494 if (sc->tx_queued > 0)
495 sc->tx_queued--;
496 else
497 ZYD_DEBUG((ZYD_DBG_TX, "tx queue underrun\n"));
498
499 if (sc->resched && (sc->tx_queued < ZYD_TX_LIST_COUNT)) {
500 resched = sc->resched;
501 sc->resched = B_FALSE;
502 }
503 zyd_serial_exit(sc);
504
505 if (resched)
506 mac_tx_update(ic->ic_mach);
507
508 usb_free_bulk_req(req);
509 }
510
511 /*
512 * Called when the transfer from zyd_usb_bulk_pipe_send() terminates
513 * or an exception occurs on the pipe.
514 */
515 /*ARGSUSED*/
516 static void
zyd_bulk_pipe_cb(usb_pipe_handle_t pipe,struct usb_bulk_req * req)517 zyd_bulk_pipe_cb(usb_pipe_handle_t pipe, struct usb_bulk_req *req)
518 {
519 struct zyd_cb_lock *lock;
520 lock = (struct zyd_cb_lock *)req->bulk_client_private;
521
522 /* Just signal that something happened */
523 zyd_cb_lock_signal(lock);
524 }
525
526 static zyd_res
zyd_usb_bulk_pipe_send(struct zyd_usb * uc,usb_pipe_handle_t pipe,const void * data,size_t len)527 zyd_usb_bulk_pipe_send(struct zyd_usb *uc,
528 usb_pipe_handle_t pipe, const void *data, size_t len)
529 {
530 usb_bulk_req_t *send_req;
531 mblk_t *mblk;
532 int res;
533 struct zyd_cb_lock lock;
534
535 send_req = usb_alloc_bulk_req(uc->dip, len, USB_FLAGS_SLEEP);
536 if (send_req == NULL) {
537 ZYD_WARN("failed to allocate bulk request\n");
538 return (ZYD_FAILURE);
539 }
540 send_req->bulk_len = (uint_t)len;
541 send_req->bulk_client_private = (usb_opaque_t)&lock;
542 send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
543 send_req->bulk_timeout = 5;
544 send_req->bulk_cb = zyd_bulk_pipe_cb;
545 send_req->bulk_exc_cb = zyd_bulk_pipe_cb;
546
547 mblk = send_req->bulk_data;
548 bcopy(data, mblk->b_wptr, len);
549 mblk->b_wptr += len;
550
551 zyd_cb_lock_init(&lock);
552
553 res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_NOSLEEP);
554 if (res != USB_SUCCESS) {
555 ZYD_DEBUG((ZYD_DBG_USB,
556 "failed writing to bulk OUT pipe (%d)\n", res));
557 usb_free_bulk_req(send_req);
558 zyd_cb_lock_destroy(&lock);
559 return (ZYD_FAILURE);
560 }
561
562 if (zyd_cb_lock_wait(&lock, 1000000) != ZYD_SUCCESS) {
563 ZYD_WARN("timeout - pipe reset\n");
564 usb_pipe_reset(uc->dip, pipe, USB_FLAGS_SLEEP, NULL, 0);
565 (void) zyd_cb_lock_wait(&lock, -1);
566 res = ZYD_FAILURE;
567 } else {
568 res = (send_req->bulk_completion_reason == USB_CR_OK) ?
569 ZYD_SUCCESS : ZYD_FAILURE;
570 }
571
572 usb_free_bulk_req(send_req);
573 zyd_cb_lock_destroy(&lock);
574 return (res);
575 }
576
577 /*
578 * Called when the transfer from zyd_usb_intr_pipe_send() terminates
579 * or an exception occurs on the pipe.
580 */
581 /*ARGSUSED*/
582 static void
zyd_intr_pipe_cb(usb_pipe_handle_t pipe,struct usb_intr_req * req)583 zyd_intr_pipe_cb(usb_pipe_handle_t pipe, struct usb_intr_req *req)
584 {
585 struct zyd_cb_lock *lock;
586 lock = (struct zyd_cb_lock *)req->intr_client_private;
587
588 /* Just signal that something happened */
589 zyd_cb_lock_signal(lock);
590 }
591
592 /*
593 * Send a sequence of bytes to an interrupt pipe.
594 *
595 * uc pointer to usb module state
596 * data pointer to a buffer of bytes
597 * len size of the buffer (bytes)
598 */
599 static zyd_res
zyd_usb_intr_pipe_send(struct zyd_usb * uc,usb_pipe_handle_t pipe,const void * data,size_t len)600 zyd_usb_intr_pipe_send(struct zyd_usb *uc,
601 usb_pipe_handle_t pipe, const void *data, size_t len)
602 {
603 usb_intr_req_t *send_req;
604 mblk_t *mblk;
605 int res;
606 struct zyd_cb_lock lock;
607
608 send_req = usb_alloc_intr_req(uc->dip, len, USB_FLAGS_SLEEP);
609 if (send_req == NULL) {
610 ZYD_WARN("failed to allocate interupt request\n");
611 return (ZYD_FAILURE);
612 }
613 send_req->intr_len = (uint_t)len;
614 send_req->intr_client_private = (usb_opaque_t)&lock;
615 send_req->intr_attributes = USB_ATTRS_AUTOCLEARING;
616 send_req->intr_timeout = 5;
617 send_req->intr_cb = zyd_intr_pipe_cb;
618 send_req->intr_exc_cb = zyd_intr_pipe_cb;
619
620 mblk = send_req->intr_data;
621 bcopy(data, mblk->b_wptr, len);
622 mblk->b_wptr += len;
623
624 zyd_cb_lock_init(&lock);
625
626 res = usb_pipe_intr_xfer(pipe, send_req, 0);
627 if (res != USB_SUCCESS) {
628 ZYD_DEBUG((ZYD_DBG_USB,
629 "failed writing to intr/out pipe (%d)\n", res));
630 usb_free_intr_req(send_req);
631 zyd_cb_lock_destroy(&lock);
632 return (ZYD_FAILURE);
633 }
634
635 if (zyd_cb_lock_wait(&lock, 1000000) != ZYD_SUCCESS) {
636 ZYD_WARN("timeout - pipe reset\n");
637 usb_pipe_reset(uc->dip, pipe, USB_FLAGS_SLEEP, NULL, 0);
638 (void) zyd_cb_lock_wait(&lock, -1);
639 res = ZYD_FAILURE;
640 } else {
641 res = (send_req->intr_completion_reason == USB_CR_OK) ?
642 ZYD_SUCCESS : ZYD_FAILURE;
643 }
644
645 usb_free_intr_req(send_req);
646 zyd_cb_lock_destroy(&lock);
647 return (res);
648 }
649
650 /*
651 * Send a sequence of bytes to the cmd_out pipe. (in a single USB transfer)
652 *
653 * uc pointer to usb module state
654 * data pointer to a buffer of bytes
655 * len size of the buffer (bytes)
656 */
657 static zyd_res
zyd_usb_cmd_pipe_send(struct zyd_usb * uc,const void * data,size_t len)658 zyd_usb_cmd_pipe_send(struct zyd_usb *uc, const void *data, size_t len)
659 {
660 zyd_res res;
661 uint8_t type;
662
663 /* Determine the type of cmd_out */
664 type = uc->ep_cmd_out.ep_descr.bmAttributes & USB_EP_ATTR_MASK;
665 if (type == USB_EP_ATTR_BULK)
666 res = zyd_usb_bulk_pipe_send(uc, uc->pipe_cmd_out, data, len);
667 else
668 res = zyd_usb_intr_pipe_send(uc, uc->pipe_cmd_out, data, len);
669
670 return (res);
671 }
672
673
674 /*
675 * Format and send a command to the cmd_out pipe.
676 *
677 * uc pointer to usb module state
678 * code ZD command code (16-bit)
679 * data raw buffer containing command data
680 * len size of the data buffer (bytes)
681 */
682 zyd_res
zyd_usb_cmd_send(struct zyd_usb * uc,uint16_t code,const void * data,size_t len)683 zyd_usb_cmd_send(struct zyd_usb *uc,
684 uint16_t code, const void *data, size_t len)
685 {
686 zyd_res res;
687 struct zyd_cmd cmd;
688
689 cmd.cmd_code = LE_16(code);
690 bcopy(data, cmd.data, len);
691
692 res = zyd_usb_cmd_pipe_send(uc, &cmd, sizeof (uint16_t) + len);
693 if (res != ZYD_SUCCESS) {
694 ZYD_DEBUG((ZYD_DBG_USB, "failed writing command (%d)\n", res));
695 return (ZYD_FAILURE);
696 }
697
698 return (ZYD_SUCCESS);
699 }
700
701 /*
702 * Issue an ioread request.
703 *
704 * Issues a ZD ioread command (with a vector of addresses passed in raw
705 * form as in_data) and blocks until the response is received
706 * and filled into the response buffer.
707 *
708 * uc pointer to usb module state
709 * in_data pointer to request data
710 * in_len request data size (bytes)
711 * out_data pointer to response buffer
712 * out_len response buffer size (bytes)
713 */
714 zyd_res
zyd_usb_ioread_req(struct zyd_usb * uc,const void * in_data,size_t in_len,void * out_data,size_t out_len)715 zyd_usb_ioread_req(struct zyd_usb *uc,
716 const void *in_data, size_t in_len, void *out_data, size_t out_len)
717 {
718 zyd_res res;
719 int cnt;
720
721 /* Initialise io_read structure */
722 uc->io_read.done = B_FALSE;
723 uc->io_read.buffer = out_data;
724 uc->io_read.buf_len = (int)out_len;
725
726 uc->io_read.pending = B_TRUE;
727
728 res = zyd_usb_cmd_send(uc, ZYD_CMD_IORD, in_data, in_len);
729 if (res != ZYD_SUCCESS) {
730 ZYD_DEBUG((ZYD_DBG_USB, "IO read request: pipe failure(%d)\n"));
731 return (ZYD_FAILURE);
732 }
733
734 cnt = 0;
735 while (uc->io_read.done != B_TRUE && cnt < 500) {
736 delay(drv_usectohz(10 * 1000));
737 ++cnt;
738 }
739
740 if (uc->io_read.done != B_TRUE) {
741 ZYD_WARN("I/O read request: timeout\n");
742 return (ZYD_FAILURE);
743 }
744
745 if (uc->io_read.exc != B_FALSE) {
746 ZYD_DEBUG((ZYD_DBG_USB, "I/O read request: exception\n"));
747 return (ZYD_FAILURE);
748 }
749
750 return (ZYD_SUCCESS);
751 }
752
753
754 /*
755 * Called when data arrives from the cmd_in pipe.
756 */
757 /*ARGSUSED*/
758 static void
zyd_cmd_in_cb(usb_pipe_handle_t pipe,usb_intr_req_t * req)759 zyd_cmd_in_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
760 {
761 struct zyd_usb *uc;
762 struct zyd_ioread *rdp;
763 mblk_t *mblk, *tmp_blk;
764 unsigned char *data;
765 size_t len;
766 uint16_t code;
767
768 uc = (struct zyd_usb *)req->intr_client_private;
769 ASSERT(uc != NULL);
770 rdp = &uc->io_read;
771 mblk = req->intr_data;
772
773 if (mblk->b_cont != NULL) {
774 /* Fragmented message, concatenate */
775 tmp_blk = msgpullup(mblk, -1);
776 data = tmp_blk->b_rptr;
777 len = MBLKL(tmp_blk);
778 } else {
779 /* Non-fragmented message, use directly */
780 tmp_blk = NULL;
781 data = mblk->b_rptr;
782 len = MBLKL(mblk);
783 }
784
785 code = LE_16(*(uint16_t *)(uintptr_t)data);
786 if (code != ZYD_RESPONSE_IOREAD) {
787 /* Other response types not handled yet */
788 usb_free_intr_req(req);
789 return;
790 }
791
792 if (rdp->pending != B_TRUE) {
793 ZYD_WARN("no ioread pending\n");
794 usb_free_intr_req(req);
795 return;
796 }
797 rdp->pending = B_FALSE;
798
799 /* Now move on to the data part */
800 data += sizeof (uint16_t);
801 len -= sizeof (uint16_t);
802 if (rdp->buf_len > len) {
803 ZYD_WARN("too few bytes received\n");
804 }
805
806 bcopy(data, rdp->buffer, rdp->buf_len);
807
808 if (tmp_blk != NULL)
809 freemsg(tmp_blk);
810
811 rdp->exc = B_FALSE;
812 rdp->done = B_TRUE;
813 usb_free_intr_req(req);
814 }
815
816 /*
817 * Called when an exception occurs on the cmd_in pipe.
818 */
819 /*ARGSUSED*/
820 static void
zyd_cmd_in_exc_cb(usb_pipe_handle_t pipe,usb_intr_req_t * req)821 zyd_cmd_in_exc_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
822 {
823 struct zyd_usb *uc;
824 struct zyd_ioread *rdp;
825
826 ZYD_DEBUG((ZYD_DBG_USB, "command IN exception\n"));
827
828 uc = (struct zyd_usb *)req->intr_client_private;
829 ASSERT(uc != NULL);
830 rdp = &uc->io_read;
831
832 if (rdp->pending == B_TRUE) {
833 rdp->exc = B_TRUE;
834 rdp->done = B_TRUE;
835 }
836 usb_free_intr_req(req);
837 }
838
839 /*
840 * Start interrupt polling on the cmd_in pipe.
841 */
842 zyd_res
zyd_usb_cmd_in_start_polling(struct zyd_usb * uc)843 zyd_usb_cmd_in_start_polling(struct zyd_usb *uc)
844 {
845 usb_intr_req_t *intr_req;
846 int res;
847
848 intr_req = usb_alloc_intr_req(uc->dip, 0, USB_FLAGS_SLEEP);
849 if (intr_req == NULL) {
850 ZYD_WARN("failed to allocate interrupt request\n");
851 return (ZYD_FAILURE);
852 }
853
854 intr_req->intr_attributes = USB_ATTRS_SHORT_XFER_OK;
855 intr_req->intr_len = uc->ep_cmd_in.ep_descr.wMaxPacketSize;
856 intr_req->intr_cb = zyd_cmd_in_cb;
857 intr_req->intr_exc_cb = zyd_cmd_in_exc_cb;
858 intr_req->intr_client_private = (usb_opaque_t)uc;
859
860 res = usb_pipe_intr_xfer(uc->pipe_cmd_in, intr_req, USB_FLAGS_NOSLEEP);
861 if (res != USB_SUCCESS) {
862 ZYD_WARN("failed starting command IN polling: pipe failure\n");
863 usb_free_intr_req(intr_req);
864 return (ZYD_FAILURE);
865 }
866
867 return (ZYD_SUCCESS);
868 }
869
870 /*
871 * Stop interrupt polling on the cmd_in pipe.
872 */
873 void
zyd_usb_cmd_in_stop_polling(struct zyd_usb * uc)874 zyd_usb_cmd_in_stop_polling(struct zyd_usb *uc)
875 {
876 ZYD_DEBUG((ZYD_DBG_USB, "stopping command IN polling\n"));
877
878 usb_pipe_stop_intr_polling(uc->pipe_cmd_in, USB_FLAGS_SLEEP);
879 }
880
881 /*
882 * Called when data arrives on the data_in pipe.
883 */
884 /*ARGSUSED*/
885 static void
zyd_data_in_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)886 zyd_data_in_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
887 {
888 struct zyd_softc *sc;
889 struct zyd_usb *uc;
890 mblk_t *mblk, *tmp_blk;
891 struct zyd_rx_desc *desc;
892 unsigned char *data;
893 size_t len;
894
895 uc = (struct zyd_usb *)req->bulk_client_private;
896 ASSERT(uc != NULL);
897 sc = ZYD_USB_TO_SOFTC(uc);
898 ASSERT(sc != NULL);
899 mblk = req->bulk_data;
900
901 /* Fragmented STREAMS message? */
902 if (mblk->b_cont != NULL) {
903 /* Fragmented, concatenate it into a single block */
904 tmp_blk = msgpullup(mblk, -1);
905 if (tmp_blk == NULL) {
906 ZYD_WARN("failed to concatenate fragments\n");
907 goto error;
908 }
909 data = tmp_blk->b_rptr;
910 len = MBLKL(tmp_blk);
911 } else {
912 /* Not fragmented, use directly */
913 tmp_blk = NULL;
914 data = mblk->b_rptr;
915 len = MBLKL(mblk);
916 }
917
918 if (len < 2) {
919 ZYD_WARN("received usb transfer too short\n");
920 goto error;
921 }
922
923 /*
924 * If this is a composite packet, the last two bytes contain
925 * two special signature bytes.
926 */
927 desc = (struct zyd_rx_desc *)(data + len) - 1;
928 /* multi-frame transfer */
929 if (LE_16(desc->tag) == ZYD_TAG_MULTIFRAME) {
930 const uint8_t *p = data, *end = data + len;
931 int i;
932
933 ZYD_DEBUG((ZYD_DBG_RX, "composite packet\n"));
934
935 for (i = 0; i < ZYD_MAX_RXFRAMECNT; i++) {
936 const uint16_t len16 = LE_16(desc->len[i]);
937 if (len16 == 0 || p + len16 > end)
938 break;
939 zyd_receive(ZYD_USB_TO_SOFTC(uc), p, len16);
940 /* next frame is aligned on a 32-bit boundary */
941 p += (len16 + 3) & ~3;
942 }
943 } else {
944 /* single-frame transfer */
945 zyd_receive(ZYD_USB_TO_SOFTC(uc), data, MBLKL(mblk));
946 }
947
948 error:
949 if (tmp_blk != NULL)
950 freemsg(tmp_blk);
951
952 usb_free_bulk_req(req);
953
954 if (!sc->running)
955 return;
956
957 if (zyd_usb_data_in_start_request(uc) != ZYD_SUCCESS) {
958 ZYD_WARN("error restarting data_in transfer\n");
959 }
960 }
961
962 /*
963 * Called when an exception occurs on the data_in pipe.
964 */
965 /*ARGSUSED*/
966 static void
zyd_data_in_exc_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)967 zyd_data_in_exc_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
968 {
969 struct zyd_usb *uc;
970
971 ZYD_DEBUG((ZYD_DBG_USB, "data IN exception\n"));
972
973 uc = (struct zyd_usb *)req->bulk_client_private;
974 ASSERT(uc != NULL);
975
976 usb_free_bulk_req(req);
977 }
978
979 /*
980 * Start a receive request on the data_in pipe.
981 */
982 static zyd_res
zyd_usb_data_in_start_request(struct zyd_usb * uc)983 zyd_usb_data_in_start_request(struct zyd_usb *uc)
984 {
985 usb_bulk_req_t *req;
986 int res;
987
988 req = usb_alloc_bulk_req(uc->dip, ZYD_RX_BUF_SIZE, USB_FLAGS_SLEEP);
989 if (req == NULL) {
990 ZYD_WARN("failed to allocate bulk IN request\n");
991 return (ZYD_FAILURE);
992 }
993
994 req->bulk_len = (uint_t)ZYD_RX_BUF_SIZE;
995 req->bulk_timeout = 0;
996 req->bulk_client_private = (usb_opaque_t)uc;
997 req->bulk_attributes =
998 USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
999 req->bulk_cb = zyd_data_in_cb;
1000 req->bulk_exc_cb = zyd_data_in_exc_cb;
1001
1002 res = usb_pipe_bulk_xfer(uc->pipe_data_in, req, USB_FLAGS_NOSLEEP);
1003 if (res != USB_SUCCESS) {
1004 ZYD_WARN("error starting receive request on data_in pipe\n");
1005 usb_free_bulk_req(req);
1006 return (ZYD_FAILURE);
1007 }
1008
1009 return (ZYD_SUCCESS);
1010 }
1011
1012
1013 /*
1014 * Start receiving packets on the data_in pipe.
1015 */
1016 zyd_res
zyd_usb_data_in_enable(struct zyd_usb * uc)1017 zyd_usb_data_in_enable(struct zyd_usb *uc)
1018 {
1019 for (int i = 0; i < ZYD_RX_LIST_COUNT; i++) {
1020 if (zyd_usb_data_in_start_request(uc) != ZYD_SUCCESS) {
1021 ZYD_WARN("failed to start data IN requests\n");
1022 return (ZYD_FAILURE);
1023 }
1024 }
1025 return (ZYD_SUCCESS);
1026 }
1027
1028 /*
1029 * Stop receiving packets on the data_in pipe.
1030 */
1031 void
zyd_usb_data_in_disable(struct zyd_usb * uc)1032 zyd_usb_data_in_disable(struct zyd_usb *uc)
1033 {
1034 usb_pipe_reset(uc->dip, uc->pipe_data_in, USB_FLAGS_SLEEP,
1035 NULL, NULL);
1036 }
1037
1038 /*
1039 * Send a packet to data_out.
1040 *
1041 * A packet consists of a zyd_tx_header + the IEEE802.11 frame.
1042 */
1043 zyd_res
zyd_usb_send_packet(struct zyd_usb * uc,mblk_t * mp)1044 zyd_usb_send_packet(struct zyd_usb *uc, mblk_t *mp)
1045 {
1046 usb_bulk_req_t *send_req;
1047 int res;
1048
1049 send_req = usb_alloc_bulk_req(uc->dip, 0, USB_FLAGS_SLEEP);
1050 if (send_req == NULL) {
1051 ZYD_WARN("failed to allocate bulk request\n");
1052 return (ZYD_FAILURE);
1053 }
1054
1055 send_req->bulk_len = msgdsize(mp);
1056 send_req->bulk_data = mp;
1057 send_req->bulk_timeout = 5;
1058 send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1059 send_req->bulk_client_private = (usb_opaque_t)ZYD_USB_TO_SOFTC(uc);
1060 send_req->bulk_cb = zyd_data_out_cb;
1061 send_req->bulk_exc_cb = zyd_data_out_cb;
1062 send_req->bulk_completion_reason = 0;
1063 send_req->bulk_cb_flags = 0;
1064
1065 res = usb_pipe_bulk_xfer(uc->pipe_data_out, send_req, 0);
1066 if (res != USB_SUCCESS) {
1067 ZYD_DEBUG((ZYD_DBG_USB,
1068 "failed writing to bulk/out pipe (%d)\n", res));
1069 usb_free_bulk_req(send_req);
1070 return (USB_FAILURE);
1071 }
1072
1073 return (USB_SUCCESS);
1074 }
1075
1076 /*
1077 * Initialize USB device communication and USB module state.
1078 *
1079 * uc pointer to usb module state
1080 * dip pointer to device info structure
1081 */
1082 zyd_res
zyd_usb_init(struct zyd_softc * sc)1083 zyd_usb_init(struct zyd_softc *sc)
1084 {
1085 struct zyd_usb *uc = &sc->usb;
1086 dev_info_t *dip = sc->dip;
1087 int ures;
1088
1089 uc->dip = dip;
1090
1091 ures = usb_client_attach(uc->dip, USBDRV_VERSION, 0);
1092 if (ures != USB_SUCCESS) {
1093 ZYD_WARN("usb_client_attach failed, error code: %d\n", ures);
1094 return (ZYD_FAILURE);
1095 }
1096
1097 /*
1098 * LVL_ALL is needed for later endpoint scanning,
1099 * and the tree must not be freed before that.
1100 */
1101 ures = usb_get_dev_data(uc->dip, &uc->cdata, USB_PARSE_LVL_ALL, 0);
1102 if (ures != USB_SUCCESS) {
1103 ZYD_WARN("usb_get_dev_data failed, error code: %d\n", ures);
1104 ASSERT(uc->cdata == NULL);
1105 goto fail;
1106 }
1107
1108 ures = usb_reset_device(uc->dip, USB_RESET_LVL_DEFAULT);
1109 if (ures != USB_SUCCESS) {
1110 ZYD_WARN("usb_reset_device failed, error code: %d\n", ures);
1111 goto fail;
1112 }
1113
1114 uc->connected = B_TRUE;
1115
1116 ures = usb_register_hotplug_cbs(dip, zyd_usb_disconnect,
1117 zyd_usb_reconnect);
1118 if (ures != USB_SUCCESS) {
1119 ZYD_WARN("usb_register_hotplug_cbs failed, error code: %d\n",
1120 ures);
1121 goto fail;
1122 }
1123
1124 return (ZYD_SUCCESS);
1125 fail:
1126 usb_client_detach(uc->dip, uc->cdata);
1127 uc->cdata = NULL;
1128 return (ZYD_FAILURE);
1129 }
1130
1131 /*
1132 * Deinitialize USB device communication.
1133 */
1134 void
zyd_usb_deinit(struct zyd_softc * sc)1135 zyd_usb_deinit(struct zyd_softc *sc)
1136 {
1137 struct zyd_usb *uc = &sc->usb;
1138
1139 usb_unregister_hotplug_cbs(sc->dip);
1140
1141 usb_client_detach(uc->dip, uc->cdata);
1142 uc->cdata = NULL;
1143 uc->connected = B_FALSE;
1144 }
1145
1146 /*
1147 * Device connected
1148 */
1149 static int
zyd_usb_reconnect(dev_info_t * dip)1150 zyd_usb_reconnect(dev_info_t *dip)
1151 {
1152 struct zyd_softc *sc;
1153 struct zyd_usb *uc;
1154
1155 sc = ddi_get_soft_state(zyd_ssp, ddi_get_instance(dip));
1156 ASSERT(sc != NULL);
1157 uc = &sc->usb;
1158 ASSERT(!uc->connected);
1159
1160 if (sc->suspended)
1161 ZYD_DEBUG((ZYD_DBG_RESUME | ZYD_DBG_USB,
1162 "reconnect before resume\n"));
1163
1164 /* check device changes after disconnect */
1165 if (usb_check_same_device(sc->dip, NULL, USB_LOG_L2, -1,
1166 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
1167 ZYD_DEBUG((ZYD_DBG_USB, "different device connected\n"));
1168 return (DDI_FAILURE);
1169 }
1170
1171 (void) zyd_serial_enter(sc, ZYD_NO_SIG);
1172 if (zyd_hw_init(sc) != ZYD_SUCCESS) {
1173 ZYD_WARN("failed to reinit hardware\n");
1174 zyd_serial_exit(sc);
1175 return (DDI_FAILURE);
1176 }
1177 if (sc->running) {
1178 if (zyd_hw_start(sc) != ZYD_SUCCESS) {
1179 ZYD_WARN("failed to restart hardware\n");
1180 zyd_serial_exit(sc);
1181 goto fail;
1182 }
1183 }
1184 zyd_serial_exit(sc);
1185
1186 uc->connected = B_TRUE;
1187
1188 return (DDI_SUCCESS);
1189 fail:
1190 usb_client_detach(uc->dip, uc->cdata);
1191 uc->cdata = NULL;
1192 return (DDI_FAILURE);
1193 }
1194
1195 static int
zyd_usb_disconnect(dev_info_t * dip)1196 zyd_usb_disconnect(dev_info_t *dip)
1197 {
1198 struct zyd_softc *sc;
1199 struct zyd_usb *uc;
1200
1201 sc = ddi_get_soft_state(zyd_ssp, ddi_get_instance(dip));
1202 ASSERT(sc != NULL);
1203 uc = &sc->usb;
1204
1205 if (!uc->connected) {
1206 ZYD_DEBUG((ZYD_DBG_USB, "different device disconnected\n"));
1207 return (DDI_FAILURE);
1208 }
1209 uc->connected = B_FALSE;
1210
1211 if (sc->suspended) {
1212 ZYD_DEBUG((ZYD_DBG_USB, "disconnect after suspend\n"));
1213 return (DDI_SUCCESS);
1214 }
1215 ieee80211_new_state(&sc->ic, IEEE80211_S_INIT, -1);
1216
1217 (void) zyd_serial_enter(sc, ZYD_NO_SIG);
1218 zyd_hw_stop(sc);
1219 zyd_hw_deinit(sc);
1220 zyd_serial_exit(sc);
1221
1222 return (DDI_SUCCESS);
1223 }
1224
1225 int
zyd_suspend(struct zyd_softc * sc)1226 zyd_suspend(struct zyd_softc *sc)
1227 {
1228 struct zyd_usb *uc = &sc->usb;
1229
1230 if (!uc->connected) {
1231 ZYD_DEBUG((ZYD_DBG_USB | ZYD_DBG_RESUME,
1232 "suspend after disconnect\n"));
1233 sc->suspended = B_TRUE;
1234 return (DDI_SUCCESS);
1235 }
1236 ZYD_DEBUG((ZYD_DBG_RESUME, "suspend\n"));
1237
1238 sc->suspended = B_TRUE;
1239 ieee80211_new_state(&sc->ic, IEEE80211_S_INIT, -1);
1240
1241 (void) zyd_serial_enter(sc, ZYD_NO_SIG);
1242 zyd_hw_stop(sc);
1243 zyd_hw_deinit(sc);
1244 zyd_serial_exit(sc);
1245
1246 ZYD_DEBUG((ZYD_DBG_RESUME, "suspend complete\n"));
1247 return (DDI_SUCCESS);
1248 }
1249
1250 int
zyd_resume(struct zyd_softc * sc)1251 zyd_resume(struct zyd_softc *sc)
1252 {
1253 struct zyd_usb *uc = &sc->usb;
1254
1255 if (!uc->connected) {
1256 ZYD_DEBUG((ZYD_DBG_USB | ZYD_DBG_RESUME,
1257 "resume after disconnect\n"));
1258 sc->suspended = B_FALSE;
1259 return (DDI_SUCCESS);
1260 }
1261 ZYD_DEBUG((ZYD_DBG_RESUME, "resume\n"));
1262
1263 /* check device changes after disconnect */
1264 if (usb_check_same_device(sc->dip, NULL, USB_LOG_L2, -1,
1265 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
1266 ZYD_WARN("different device connected to same port\n");
1267 sc->suspended = B_FALSE;
1268 uc->connected = B_FALSE;
1269 return (DDI_SUCCESS);
1270 }
1271
1272 (void) zyd_serial_enter(sc, ZYD_NO_SIG);
1273 if (zyd_hw_init(sc) != ZYD_SUCCESS) {
1274 ZYD_WARN("failed to reinit hardware\n");
1275 zyd_serial_exit(sc);
1276 return (DDI_FAILURE);
1277 }
1278 if (sc->running) {
1279 if (zyd_hw_start(sc) != ZYD_SUCCESS) {
1280 ZYD_WARN("failed to restart hardware\n");
1281 zyd_serial_exit(sc);
1282 return (DDI_FAILURE);
1283 }
1284 }
1285 zyd_serial_exit(sc);
1286
1287 sc->suspended = B_FALSE;
1288
1289 ZYD_DEBUG((ZYD_DBG_RESUME, "resume complete\n"));
1290 return (DDI_SUCCESS);
1291 }
1292