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 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 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 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 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 * 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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