1 /* $OpenBSD: if_wi_usb.c,v 1.4 2003/11/09 20:54:19 drahn Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Dale Rahn. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * Effort sponsored in part by the Defense Advanced Research Projects 27 * Agency (DARPA) and Air Force Research Laboratory, Air Force 28 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 29 */ 30 #include "bpfilter.h" 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/sockio.h> 35 #include <sys/mbuf.h> 36 #include <sys/malloc.h> 37 #include <sys/kernel.h> 38 #include <sys/proc.h> 39 #include <sys/socket.h> 40 #include <sys/device.h> 41 #include <sys/kthread.h> 42 43 #include <net/if.h> 44 #include <net/if_dl.h> 45 #include <net/if_media.h> 46 #include <net/if_types.h> 47 48 #ifdef INET 49 #include <netinet/in.h> 50 #include <netinet/in_systm.h> 51 #include <netinet/in_var.h> 52 #include <netinet/ip.h> 53 #include <netinet/if_ether.h> 54 #endif 55 56 #include <dev/usb/usb.h> 57 #include <dev/usb/usbdi.h> 58 #include <dev/usb/usbdi_util.h> 59 #include <dev/usb/usbdevs.h> 60 61 #define ROUNDUP64(x) (((x)+63) & ~63) 62 63 #include <net/if_ieee80211.h> 64 65 #if NBPFILTER > 0 66 #include <net/bpf.h> 67 #endif 68 69 #include <machine/bus.h> 70 71 #include <dev/rndvar.h> 72 73 #include <dev/ic/if_wireg.h> 74 #include <dev/ic/if_wi_ieee.h> 75 #include <dev/ic/if_wivar.h> 76 77 #include <wi_usb.h> 78 #include <dev/usb/if_wi_usb.h> 79 80 int wi_usb_do_transmit_sync(struct wi_usb_softc *wsc, struct wi_usb_chain *c, 81 void *ident); 82 void wi_usb_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, 83 usbd_status status); 84 void wi_usb_txeof_frm(usbd_xfer_handle xfer, usbd_private_handle priv, 85 usbd_status status); 86 void wi_usb_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, 87 usbd_status status); 88 void wi_usb_intr(usbd_xfer_handle xfer, usbd_private_handle priv, 89 usbd_status status); 90 void wi_usb_stop(struct wi_usb_softc *usc); 91 int wi_usb_tx_list_init(struct wi_usb_softc *usc); 92 int wi_usb_rx_list_init(struct wi_usb_softc *usc); 93 int wi_usb_open_pipes(struct wi_usb_softc *usc); 94 void wi_usb_cmdresp(struct wi_usb_chain *c); 95 void wi_usb_rridresp(struct wi_usb_chain *c); 96 void wi_usb_wridresp(struct wi_usb_chain *c); 97 void wi_usb_infofrm(struct wi_usb_chain *c, int len); 98 int wi_send_packet(struct wi_usb_softc *sc, int id); 99 void wi_usb_rxfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len); 100 void wi_usb_txfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len); 101 void wi_usb_start_thread(void *); 102 103 int wi_usb_tx_lock_try(struct wi_usb_softc *sc); 104 void wi_usb_tx_lock(struct wi_usb_softc *usc); 105 void wi_usb_tx_unlock(struct wi_usb_softc *usc); 106 void wi_usb_ctl_lock(struct wi_usb_softc *usc); 107 void wi_usb_ctl_unlock(struct wi_usb_softc *usc); 108 109 void wi_dump_data(void *buffer, int len); 110 111 void wi_usb_thread(void *arg); 112 113 #ifdef WI_USB_DEBUG 114 #define DPRINTF(x) if (wi_usbdebug) logprintf x 115 #define DPRINTFN(n,x) if (wi_usbdebug >= (n)) logprintf x 116 int wi_usbdebug = 1; 117 #else 118 #define DPRINTF(x) 119 #define DPRINTFN(n,x) 120 #endif 121 122 struct wi_usb_thread_info { 123 int status; 124 int dying; 125 int idle; 126 }; 127 128 /* thread status flags */ 129 #define WI_START 0x01 130 #define WI_DYING 0x02 131 #define WI_INQUIRE 0x04 132 #define WI_WATCHDOG 0x08 133 134 135 struct wi_usb_softc { 136 struct wi_softc sc_wi; 137 #define wi_usb_dev sc_wi.sc_dev 138 139 usb_callout_t wi_usb_stat_ch; 140 141 usbd_device_handle wi_usb_udev; 142 usbd_interface_handle wi_usb_iface; 143 u_int16_t wi_usb_vendor; 144 u_int16_t wi_usb_product; 145 int wi_usb_ed[WI_USB_ENDPT_MAX]; 146 usbd_pipe_handle wi_usb_ep[WI_USB_ENDPT_MAX]; 147 148 struct wi_usb_chain wi_usb_tx_chain[WI_USB_TX_LIST_CNT]; 149 struct wi_usb_chain wi_usb_rx_chain[WI_USB_RX_LIST_CNT]; 150 151 int wi_usb_refcnt; 152 char wi_usb_dying; 153 char wi_usb_attached; 154 int wi_usb_intr_errs; 155 struct timeval wi_usb_rx_notice; 156 157 int wi_usb_pollpending; 158 159 wi_usb_usbin wi_usb_ibuf; 160 int wi_usb_tx_prod; 161 int wi_usb_tx_cons; 162 int wi_usb_tx_cnt; 163 int wi_usb_rx_prod; 164 165 struct wi_ltv_gen *ridltv; 166 int ridresperr; 167 168 int cmdresp; 169 int cmdresperr; 170 int txresp; 171 int txresperr; 172 173 /* nummem (tx/mgmt) */ 174 int wi_usb_nummem; 175 #define MAX_WI_NMEM 3 176 void *wi_usb_txmem[MAX_WI_NMEM]; 177 int wi_usb_txmemsize[MAX_WI_NMEM]; 178 void *wi_usb_rxmem; 179 int wi_usb_rxmemsize; 180 181 void *wi_info; 182 void *wi_rxframe; 183 184 /* prevent multpile outstanding USB requests */ 185 int wi_lock; 186 int wi_lockwait; 187 188 /* prevent multiple command requests */ 189 int wi_ctllock; 190 int wi_ctllockwait; 191 struct proc *wi_curproc; 192 193 /* kthread */ 194 struct wi_usb_thread_info *wi_thread_info; 195 int wi_resetonce; 196 }; 197 198 struct wi_funcs wi_func_usb = { 199 wi_cmd_usb, 200 wi_read_record_usb, 201 wi_write_record_usb, 202 wi_alloc_nicmem_usb, 203 wi_read_data_usb, 204 wi_write_data_usb, 205 wi_get_fid_usb, 206 wi_init_usb, 207 208 wi_start_usb, 209 wi_ioctl_usb, 210 wi_watchdog_usb, 211 wi_inquire_usb, 212 }; 213 214 /* 215 * Various supported device vendors/products. 216 */ 217 const struct wi_usb_type { 218 struct usb_devno wi_usb_device; 219 u_int16_t wi_usb_flags; 220 /* XXX */ 221 } wi_usb_devs[] = { 222 {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_MA111NA }, 0 } 223 }; 224 #define wi_usb_lookup(v, p) ((struct wi_usb_type *)usb_lookup(wi_usb_devs, v, p)) 225 226 USB_DECLARE_DRIVER(wi_usb); 227 228 USB_MATCH(wi_usb) 229 { 230 USB_MATCH_START(wi_usb, uaa); 231 232 if (uaa->iface != NULL) 233 return (UMATCH_NONE); 234 235 return (wi_usb_lookup(uaa->vendor, uaa->product) != NULL ? 236 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 237 } 238 239 240 /* 241 * Attach the interface. Allocate softc structures, do ifmedia 242 * setup and ethernet/BPF attach. 243 */ 244 USB_ATTACH(wi_usb) 245 { 246 USB_ATTACH_START(wi_usb, sc, uaa); 247 char devinfo[1024]; 248 /* int s; */ 249 usbd_device_handle dev = uaa->device; 250 usbd_interface_handle iface; 251 usbd_status err; 252 usb_interface_descriptor_t *id; 253 usb_endpoint_descriptor_t *ed; 254 int i; 255 256 DPRINTFN(5,(" : wi_usb_attach: sc=%p", sc)); 257 258 err = usbd_set_config_no(dev, WI_USB_CONFIG_NO, 1); 259 if (err) { 260 printf("%s: setting config no failed\n", 261 USBDEVNAME(sc->wi_usb_dev)); 262 USB_ATTACH_ERROR_RETURN; 263 } 264 265 usbd_devinfo(dev, 0, devinfo, sizeof devinfo); 266 USB_ATTACH_SETUP; 267 printf("%s: %s\n", USBDEVNAME(sc->wi_usb_dev), devinfo); 268 269 /* XXX - any tasks? */ 270 271 err = usbd_device2interface_handle(dev, WI_USB_IFACE_IDX, &iface); 272 if (err) { 273 printf("%s: getting interface handle failed\n", 274 USBDEVNAME(sc->wi_usb_dev)); 275 USB_ATTACH_ERROR_RETURN; 276 } 277 278 /* XXX - flags? */ 279 280 sc->wi_usb_udev = dev; 281 sc->wi_usb_iface = iface; 282 sc->wi_usb_product = uaa->product; 283 sc->wi_usb_vendor = uaa->vendor; 284 285 sc->sc_wi.wi_usb_cdata = sc; 286 sc->sc_wi.wi_flags |= WI_FLAGS_BUS_USB; 287 288 sc->wi_lock = 0; 289 sc->wi_lockwait = 0; 290 sc->wi_resetonce = 0; 291 292 id = usbd_get_interface_descriptor(iface); 293 294 /* Find endpoints. */ 295 for (i = 0; i < id->bNumEndpoints; i++) { 296 ed = usbd_interface2endpoint_descriptor(iface, i); 297 if (ed == NULL) { 298 printf("%s: couldn't get endpoint descriptor %d\n", 299 USBDEVNAME(sc->wi_usb_dev), i); 300 USB_ATTACH_ERROR_RETURN; 301 } 302 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 303 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 304 sc->wi_usb_ed[WI_USB_ENDPT_RX] = ed->bEndpointAddress; 305 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 306 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 307 sc->wi_usb_ed[WI_USB_ENDPT_TX] = ed->bEndpointAddress; 308 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 309 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 310 sc->wi_usb_ed[WI_USB_ENDPT_INTR] = ed->bEndpointAddress; 311 } 312 } 313 314 sc->wi_usb_nummem = 0; 315 316 /* attach wi device */ 317 318 if (wi_usb_rx_list_init(sc)) { 319 printf("%s: rx list init failed\n", 320 USBDEVNAME(sc->wi_usb_dev)); 321 USB_ATTACH_ERROR_RETURN; 322 } 323 if (wi_usb_tx_list_init(sc)) { 324 printf("%s: tx list init failed\n", 325 USBDEVNAME(sc->wi_usb_dev)); 326 USB_ATTACH_ERROR_RETURN; 327 } 328 329 if (wi_usb_open_pipes(sc)){ 330 printf("%s: open pipes failed\n", 331 USBDEVNAME(sc->wi_usb_dev)); 332 USB_ATTACH_ERROR_RETURN; 333 } 334 335 sc->wi_usb_attached = 1; 336 337 if (cold) 338 kthread_create_deferred(wi_usb_start_thread, sc); 339 else 340 wi_usb_start_thread(sc); 341 342 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->wi_usb_udev, 343 USBDEV(sc->wi_usb_dev)); 344 345 346 USB_ATTACH_SUCCESS_RETURN; 347 } 348 349 USB_DETACH(wi_usb) 350 { 351 USB_DETACH_START(wi_usb, sc); 352 struct ifnet *ifp = WI_GET_IFP(sc); 353 struct wi_softc *wsc = &sc->sc_wi; 354 int s; 355 356 sc->wi_usb_dying = 1; 357 if (sc->wi_thread_info != NULL) { 358 sc->wi_thread_info->dying = 1; 359 360 sc->wi_thread_info->status |= WI_DYING; 361 if (sc->wi_thread_info->idle) 362 wakeup (sc->wi_thread_info); 363 } 364 365 if (!sc->wi_usb_attached) { 366 /* Detached before attach finished, so just bail out. */ 367 return (0); 368 } 369 /* tasks? */ 370 371 s = splusb(); 372 /* detatch wi */ 373 374 if (!(wsc->wi_flags & WI_FLAGS_ATTACHED)) { 375 printf("%s: already detached\n", USBDEVNAME(sc->wi_usb_dev)); 376 splx(s); 377 return (0); 378 } 379 380 wi_detach(&sc->sc_wi); 381 382 wsc->wi_flags = 0; 383 384 ether_ifdetach(ifp); 385 if_detach(ifp); 386 387 sc->wi_usb_attached = 0; 388 389 if (--sc->wi_usb_refcnt >= 0) { 390 /* Wait for processes to go away. */ 391 usb_detach_wait(USBDEV(sc->wi_usb_dev)); 392 } 393 394 while (sc->wi_usb_nummem) { 395 sc->wi_usb_nummem--; 396 if (sc->wi_usb_txmem[sc->wi_usb_nummem] != NULL) 397 free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_DEVBUF); 398 sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL; 399 } 400 401 if (sc->wi_usb_ep[WI_USB_ENDPT_INTR] != NULL); 402 usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]); 403 if (sc->wi_usb_ep[WI_USB_ENDPT_TX] != NULL); 404 usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]); 405 if (sc->wi_usb_ep[WI_USB_ENDPT_RX] != NULL); 406 usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]); 407 408 splx(s); 409 410 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->wi_usb_udev, 411 USBDEV(sc->wi_usb_dev)); 412 return (0); 413 } 414 415 int 416 wi_send_packet(struct wi_usb_softc *sc, int id) 417 { 418 struct wi_usb_chain *c; 419 struct wi_frame *wibuf; 420 int total_len, rnd_len; 421 int err; 422 423 c = &sc->wi_usb_tx_chain[0]; 424 425 DPRINTFN(10,("%s: %s: id=%x\n", 426 USBDEVNAME(sc->wi_usb_dev), __func__, id)); 427 428 /* assemble packet from write_data buffer */ 429 if (id == 0 || id == 1) { 430 /* tx_lock acquired before wi_start() */ 431 wibuf = sc->wi_usb_txmem[id]; 432 433 total_len = sizeof (struct wi_frame) + 434 letoh16(wibuf->wi_dat_len); 435 rnd_len = ROUNDUP64(total_len); 436 if ((total_len > sc->wi_usb_txmemsize[id]) || 437 (rnd_len > WI_USB_BUFSZ )){ 438 printf("invalid packet len: %x memsz %x max %x\n", 439 total_len, sc->wi_usb_txmemsize[id], WI_USB_BUFSZ); 440 total_len = sc->wi_usb_txmemsize[id]; 441 442 err = EIO; 443 goto err_ret; 444 } 445 446 sc->txresp = WI_CMD_TX; 447 sc->txresperr = 0; 448 449 bcopy(wibuf, c->wi_usb_buf, total_len); 450 451 bzero(((char *)c->wi_usb_buf)+total_len, 452 rnd_len - total_len); 453 454 /* zero old packet for next TX */ 455 bzero(wibuf, total_len); 456 457 total_len = rnd_len; 458 459 DPRINTFN(5,("%s: %s: id=%x len=%x\n", 460 USBDEVNAME(sc->wi_usb_dev), __func__, id, total_len)); 461 462 usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX], 463 c, c->wi_usb_buf, rnd_len, 464 USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 465 WI_USB_TX_TIMEOUT, wi_usb_txeof_frm); 466 467 err = usbd_transfer(c->wi_usb_xfer); 468 if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) { 469 printf("%s: wi_usb_send error=%s\n", 470 USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err)); 471 /* Stop the interface from process context. */ 472 wi_usb_stop(sc); 473 err = EIO; 474 } else { 475 err = 0; 476 } 477 478 DPRINTFN(5,("%s: %s: exit err=%x\n", 479 USBDEVNAME(sc->wi_usb_dev), __func__, err)); 480 err_ret: 481 return err; 482 } 483 printf("%s:%s: invalid packet id sent %x\n", 484 USBDEVNAME(sc->wi_usb_dev), __func__, id); 485 return 0; 486 } 487 488 int 489 wi_cmd_usb(struct wi_softc *wsc, int cmd, int val0, int val1, int val2) 490 { 491 struct wi_usb_chain *c; 492 struct wi_usb_softc *sc = wsc->wi_usb_cdata; 493 struct wi_cmdreq *pcmd; 494 int total_len, rnd_len; 495 int err; 496 497 DPRINTFN(5,("%s: %s: enter cmd=%x %x %x %x\n", 498 USBDEVNAME(sc->wi_usb_dev), __func__, cmd, val0, val1, val2)); 499 500 if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_TX) { 501 return wi_send_packet(sc, val0); 502 } 503 504 505 if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_INI) { 506 /* free alloc_nicmem regions */ 507 while (sc->wi_usb_nummem) { 508 sc->wi_usb_nummem--; 509 free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_DEVBUF); 510 sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL; 511 } 512 513 #if 0 514 /* if this is the first time, init, otherwise do not?? */ 515 if (sc->wi_resetonce) { 516 return 0; 517 } else 518 sc->wi_resetonce = 1; 519 #endif 520 } 521 522 wi_usb_ctl_lock(sc); 523 524 wi_usb_tx_lock(sc); 525 526 c = &sc->wi_usb_tx_chain[0]; 527 pcmd = c->wi_usb_buf; 528 529 530 total_len = sizeof (struct wi_cmdreq); 531 rnd_len = ROUNDUP64(total_len); 532 if (rnd_len > WI_USB_BUFSZ) { 533 printf("read_record buf size err %x %x\n", 534 rnd_len, WI_USB_BUFSZ); 535 err = EIO; 536 goto err_ret; 537 } 538 539 sc->cmdresp = cmd; 540 sc->cmdresperr = 0; 541 542 pcmd->type = htole16(WI_USB_CMDREQ); 543 pcmd->cmd = htole16(cmd); 544 pcmd->param0 = htole16(val0); 545 pcmd->param1 = htole16(val1); 546 pcmd->param2 = htole16(val2); 547 548 bzero(((char*)pcmd)+total_len, rnd_len - total_len); 549 550 total_len = rnd_len; 551 552 usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX], 553 c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 554 WI_USB_TX_TIMEOUT, wi_usb_txeof); 555 556 err = wi_usb_do_transmit_sync(sc, c, &sc->cmdresperr); 557 558 if (err == 0) 559 err = sc->cmdresperr; 560 561 sc->cmdresperr = 0; 562 563 err_ret: 564 wi_usb_tx_unlock(sc); 565 566 wi_usb_ctl_unlock(sc); 567 568 DPRINTFN(5,("%s: %s: exit err=%x\n", 569 USBDEVNAME(sc->wi_usb_dev), __func__, err)); 570 return err; 571 } 572 573 574 int 575 wi_read_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv) 576 { 577 struct wi_usb_chain *c; 578 struct wi_usb_softc *sc = wsc->wi_usb_cdata; 579 struct wi_rridreq *prid; 580 int total_len, rnd_len; 581 int err; 582 struct wi_ltv_gen *oltv, p2ltv; 583 584 DPRINTFN(5,("%s: %s: enter rid=%x\n", 585 USBDEVNAME(sc->wi_usb_dev), __func__, ltv->wi_type)); 586 587 /* Do we need to deal with these here, as in _io version? 588 * WI_RID_ENCRYPTION -> WI_RID_P2_ENCRYPTION 589 * WI_RID_TX_CRYPT_KEY -> WI_RID_P2_TX_CRYPT_KEY 590 */ 591 if (wsc->sc_firmware_type != WI_LUCENT) { 592 oltv = ltv; 593 switch (ltv->wi_type) { 594 case WI_RID_ENCRYPTION: 595 p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 596 p2ltv.wi_len = 2; 597 ltv = &p2ltv; 598 break; 599 case WI_RID_TX_CRYPT_KEY: 600 if (ltv->wi_val > WI_NLTV_KEYS) 601 return (EINVAL); 602 p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 603 p2ltv.wi_len = 2; 604 ltv = &p2ltv; 605 break; 606 } 607 } 608 609 wi_usb_tx_lock(sc); 610 611 c = &sc->wi_usb_tx_chain[0]; 612 prid = c->wi_usb_buf; 613 614 total_len = sizeof(struct wi_rridreq); 615 rnd_len = ROUNDUP64(total_len); 616 617 if (rnd_len > WI_USB_BUFSZ) { 618 printf("read_record buf size err %x %x\n", 619 rnd_len, WI_USB_BUFSZ); 620 return EIO; 621 } 622 623 sc->ridltv = ltv; 624 sc->ridresperr = 0; 625 626 prid->type = htole16(WI_USB_RRIDREQ); 627 prid->frmlen = htole16(2); /* variable size? */ 628 prid->rid = htole16(ltv->wi_type); 629 630 bzero(((char*)prid)+total_len, rnd_len - total_len); 631 632 usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX], 633 c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 634 WI_USB_TX_TIMEOUT, wi_usb_txeof); 635 636 DPRINTFN(10,("%s: %s: total_len=%x, wilen %d\n", 637 USBDEVNAME(sc->wi_usb_dev), __func__, total_len, ltv->wi_len)); 638 639 err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr); 640 641 /* Do we need to deal with these here, as in _io version? 642 * 643 * WI_RID_TX_RATE 644 * WI_RID_CUR_TX_RATE 645 * WI_RID_ENCRYPTION 646 * WI_RID_TX_CRYPT_KEY 647 * WI_RID_CNFAUTHMODE 648 */ 649 if (ltv->wi_type == WI_RID_PORTTYPE && wsc->wi_ptype == WI_PORTTYPE_IBSS 650 && ltv->wi_val == wsc->wi_ibss_port) { 651 /* 652 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS. 653 * Since Lucent uses port type 1 for BSS *and* IBSS we 654 * have to rely on wi_ptype to distinguish this for us. 655 */ 656 ltv->wi_val = htole16(WI_PORTTYPE_IBSS); 657 } else if (wsc->sc_firmware_type != WI_LUCENT) { 658 int v; 659 660 switch (oltv->wi_type) { 661 case WI_RID_TX_RATE: 662 case WI_RID_CUR_TX_RATE: 663 switch (letoh16(ltv->wi_val)) { 664 case 1: v = 1; break; 665 case 2: v = 2; break; 666 case 3: v = 6; break; 667 case 4: v = 5; break; 668 case 7: v = 7; break; 669 case 8: v = 11; break; 670 case 15: v = 3; break; 671 default: v = 0x100 + letoh16(ltv->wi_val); break; 672 } 673 oltv->wi_val = htole16(v); 674 break; 675 case WI_RID_ENCRYPTION: 676 oltv->wi_len = 2; 677 if (ltv->wi_val & htole16(0x01)) 678 oltv->wi_val = htole16(1); 679 else 680 oltv->wi_val = htole16(0); 681 break; 682 case WI_RID_TX_CRYPT_KEY: 683 case WI_RID_CNFAUTHMODE: 684 oltv->wi_len = 2; 685 oltv->wi_val = ltv->wi_val; 686 break; 687 } 688 } 689 690 if (err == 0) 691 err = sc->ridresperr; 692 693 sc->ridresperr = 0; 694 695 wi_usb_tx_unlock(sc); 696 697 DPRINTFN(5,("%s: %s: exit err=%x\n", 698 USBDEVNAME(sc->wi_usb_dev), __func__, err)); 699 return err; 700 } 701 702 int 703 wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv) 704 { 705 struct wi_usb_chain *c; 706 struct wi_usb_softc *sc = wsc->wi_usb_cdata; 707 struct wi_wridreq *prid; 708 int total_len, rnd_len; 709 int err; 710 struct wi_ltv_gen p2ltv; 711 u_int16_t val = 0; 712 int i; 713 714 DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n", 715 USBDEVNAME(sc->wi_usb_dev), __func__, ltv->wi_type, ltv->wi_len, 716 (ltv->wi_len-1)*2 )); 717 718 /* Do we need to deal with these here, as in _io version? 719 * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE 720 * RID_TX_RATE munging 721 * RID_ENCRYPTION 722 * WI_RID_TX_CRYPT_KEY 723 * WI_RID_DEFLT_CRYPT_KEYS 724 */ 725 if (ltv->wi_type == WI_RID_PORTTYPE && 726 letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) { 727 /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */ 728 p2ltv.wi_type = WI_RID_PORTTYPE; 729 p2ltv.wi_len = 2; 730 p2ltv.wi_val = wsc->wi_ibss_port; 731 ltv = &p2ltv; 732 } else if (wsc->sc_firmware_type != WI_LUCENT) { 733 int v; 734 735 switch (ltv->wi_type) { 736 case WI_RID_TX_RATE: 737 p2ltv.wi_type = WI_RID_TX_RATE; 738 p2ltv.wi_len = 2; 739 switch (letoh16(ltv->wi_val)) { 740 case 1: v = 1; break; 741 case 2: v = 2; break; 742 case 3: v = 15; break; 743 case 5: v = 4; break; 744 case 6: v = 3; break; 745 case 7: v = 7; break; 746 case 11: v = 8; break; 747 default: return EINVAL; 748 } 749 p2ltv.wi_val = htole16(v); 750 ltv = &p2ltv; 751 break; 752 case WI_RID_ENCRYPTION: 753 p2ltv.wi_type = WI_RID_P2_ENCRYPTION; 754 p2ltv.wi_len = 2; 755 if (ltv->wi_val & htole16(0x01)) { 756 val = PRIVACY_INVOKED; 757 /* 758 * If using shared key WEP we must set the 759 * EXCLUDE_UNENCRYPTED bit. Symbol cards 760 * need this bit set even when not using 761 * shared key. We can't just test for 762 * IEEE80211_AUTH_SHARED since Symbol cards 763 * have 2 shared key modes. 764 */ 765 if (wsc->wi_authtype != IEEE80211_AUTH_OPEN || 766 wsc->sc_firmware_type == WI_SYMBOL) 767 val |= EXCLUDE_UNENCRYPTED; 768 769 switch (wsc->wi_crypto_algorithm) { 770 case WI_CRYPTO_FIRMWARE_WEP: 771 /* 772 * TX encryption is broken in 773 * Host AP mode. 774 */ 775 if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP) 776 val |= HOST_ENCRYPT; 777 break; 778 case WI_CRYPTO_SOFTWARE_WEP: 779 val |= HOST_ENCRYPT|HOST_DECRYPT; 780 break; 781 } 782 p2ltv.wi_val = htole16(val); 783 } else 784 p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT); 785 ltv = &p2ltv; 786 break; 787 case WI_RID_TX_CRYPT_KEY: 788 if (ltv->wi_val > WI_NLTV_KEYS) 789 return (EINVAL); 790 p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; 791 p2ltv.wi_len = 2; 792 p2ltv.wi_val = ltv->wi_val; 793 ltv = &p2ltv; 794 break; 795 case WI_RID_DEFLT_CRYPT_KEYS: { 796 int error; 797 int keylen; 798 struct wi_ltv_str ws; 799 struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv; 800 keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen; 801 802 for (i = 0; i < 4; i++) { 803 bzero(&ws, sizeof(ws)); 804 ws.wi_len = (keylen > 5) ? 8 : 4; 805 ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; 806 bcopy(&wk->wi_keys[i].wi_keydat, 807 ws.wi_str, keylen); 808 error = wi_write_record_usb(wsc, 809 (struct wi_ltv_gen *)&ws); 810 if (error) 811 return (error); 812 } 813 } 814 return (0); 815 } 816 } 817 818 wi_usb_tx_lock(sc); 819 820 c = &sc->wi_usb_tx_chain[0]; 821 822 prid = c->wi_usb_buf; 823 824 total_len = sizeof(prid->type) + sizeof(prid->frmlen) + 825 sizeof(prid->rid) + (ltv->wi_len-1)*2; 826 rnd_len = ROUNDUP64(total_len); 827 if (rnd_len > WI_USB_BUFSZ) { 828 printf("write_record buf size err %x %x\n", 829 rnd_len, WI_USB_BUFSZ); 830 return EIO; 831 } 832 833 prid->type = htole16(WI_USB_WRIDREQ); 834 prid->frmlen = htole16(ltv->wi_len); 835 prid->rid = htole16(ltv->wi_type); 836 if (ltv->wi_len > 1) 837 bcopy((u_int8_t *)<v->wi_val, (u_int8_t *)&prid->data[0], 838 (ltv->wi_len-1)*2); 839 840 bzero(((char*)prid)+total_len, rnd_len - total_len); 841 842 usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX], 843 c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 844 WI_USB_TX_TIMEOUT, wi_usb_txeof); 845 846 err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr); 847 848 if (err == 0) 849 err = sc->ridresperr; 850 851 sc->ridresperr = 0; 852 853 wi_usb_tx_unlock(sc); 854 855 DPRINTFN(5,("%s: %s: exit err=%x\n", 856 USBDEVNAME(sc->wi_usb_dev), __func__, err)); 857 return err; 858 } 859 860 /* 861 * This is an ugly compat portion to emulate the I/O which writes 862 * a packet or management information 863 * The data is copied into local memory for the requested 864 * 'id' then on the wi_cmd WI_CMD_TX, the id argument 865 * will identify which buffer to use 866 */ 867 int 868 wi_alloc_nicmem_usb(struct wi_softc *wsc, int len, int *id) 869 { 870 int nmem; 871 struct wi_usb_softc *sc = wsc->wi_usb_cdata; 872 873 DPRINTFN(10,("%s: %s: enter len=%x\n", 874 USBDEVNAME(sc->wi_usb_dev), __func__, len)); 875 876 /* 877 * NOTE THIS IS A USB DEVICE WHICH WILL LIKELY HAVE MANY 878 * CONNECTS/DISCONNECTS, FREE THIS MEMORY XXX XXX XXX !!! !!! 879 */ 880 nmem = sc->wi_usb_nummem++; 881 882 if (nmem >= MAX_WI_NMEM) { 883 sc->wi_usb_nummem--; 884 return ENOMEM; 885 } 886 887 sc->wi_usb_txmem[nmem] = malloc(len, M_DEVBUF, M_WAITOK); 888 if (sc->wi_usb_txmem[nmem] == NULL) { 889 sc->wi_usb_nummem--; 890 return ENOMEM; 891 } 892 sc->wi_usb_txmemsize[nmem] = len; 893 894 *id = nmem; 895 return 0; 896 } 897 898 /* 899 * this is crazy, we skip the first 16 bits of the buf so that it 900 * can be used as the 'type' of the usb transfer. 901 */ 902 903 904 int 905 wi_write_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len) 906 { 907 u_int8_t *ptr; 908 struct wi_usb_softc *sc = wsc->wi_usb_cdata; 909 910 DPRINTFN(10,("%s: %s: id %x off %x len %d\n", 911 USBDEVNAME(sc->wi_usb_dev), __func__, id, off, len)); 912 913 if (id < 0 && id >= sc->wi_usb_nummem) 914 return EIO; 915 916 ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off; 917 918 if (len + off > sc->wi_usb_txmemsize[id]) 919 return EIO; 920 DPRINTFN(10,("%s: %s: completed \n", 921 USBDEVNAME(sc->wi_usb_dev), __func__)); 922 923 bcopy(buf, ptr, len); 924 return 0; 925 } 926 927 /* 928 * On the prism I/O, this read_data points to the hardware buffer 929 * which contains the 930 */ 931 int 932 wi_read_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len) 933 { 934 u_int8_t *ptr; 935 struct wi_usb_softc *sc = wsc->wi_usb_cdata; 936 937 DPRINTFN(10,("%s: %s: id %x off %x len %d\n", 938 USBDEVNAME(sc->wi_usb_dev), __func__, id, off, len)); 939 940 if (id == 0x1001 && sc->wi_info != NULL) 941 ptr = (u_int8_t *)sc->wi_info + off; 942 else if (id == 0x1000 && sc->wi_rxframe != NULL) 943 ptr = (u_int8_t *)sc->wi_rxframe + off; 944 else if (id >= 0 && id < sc->wi_usb_nummem) { 945 946 if (sc->wi_usb_txmem[id] == NULL) 947 return EIO; 948 if (len + off > sc->wi_usb_txmemsize[id]) 949 return EIO; 950 951 ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off; 952 } else 953 return EIO; 954 955 if (id < sc->wi_usb_nummem) { 956 ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off; 957 958 if (len + off > sc->wi_usb_txmemsize[id]) 959 return EIO; 960 } 961 962 bcopy(ptr, buf, len); 963 return 0; 964 } 965 966 void 967 wi_usb_stop(struct wi_usb_softc *sc) 968 { 969 DPRINTFN(1,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev),__func__)); 970 /* XXX */ 971 972 /* Stop transfers */ 973 } 974 975 int 976 wi_usb_do_transmit_sync(struct wi_usb_softc *sc, struct wi_usb_chain *c, 977 void *ident) 978 { 979 usbd_status err; 980 981 DPRINTFN(10,("%s: %s:\n", 982 USBDEVNAME(sc->wi_usb_dev), __func__)); 983 984 sc->wi_usb_refcnt++; 985 err = usbd_transfer(c->wi_usb_xfer); 986 if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) { 987 printf("%s: wi_usb_send error=%s\n", 988 USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err)); 989 /* Stop the interface from process context. */ 990 wi_usb_stop(sc); 991 err = EIO; 992 goto done; 993 } 994 err = tsleep(ident, PRIBIO, "wiTXsync", hz*1); 995 if (err) { 996 DPRINTFN(1,("%s: %s: err %x\n", 997 USBDEVNAME(sc->wi_usb_dev), __func__, err)); 998 err = ETIMEDOUT; 999 } 1000 done: 1001 if (--sc->wi_usb_refcnt < 0) 1002 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1003 return err; 1004 } 1005 1006 1007 /* 1008 * A command/rrid/wrid was sent to the chip. It's safe for us to clean up 1009 * the list buffers. 1010 */ 1011 1012 void 1013 wi_usb_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, 1014 usbd_status status) 1015 { 1016 struct wi_usb_chain *c = priv; 1017 struct wi_usb_softc *sc = c->wi_usb_sc; 1018 1019 int s; 1020 1021 if (sc->wi_usb_dying) 1022 return; 1023 1024 s = splnet(); 1025 1026 DPRINTFN(10,("%s: %s: enter status=%d\n", USBDEVNAME(sc->wi_usb_dev), 1027 __func__, status)); 1028 1029 if (status != USBD_NORMAL_COMPLETION) { 1030 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 1031 splx(s); 1032 return; 1033 } 1034 printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->wi_usb_dev), 1035 usbd_errstr(status)); 1036 if (status == USBD_STALLED) { 1037 sc->wi_usb_refcnt++; 1038 usbd_clear_endpoint_stall( 1039 sc->wi_usb_ep[WI_USB_ENDPT_TX]); 1040 if (--sc->wi_usb_refcnt < 0) 1041 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1042 } 1043 splx(s); 1044 return; 1045 } 1046 1047 splx(s); 1048 } 1049 1050 /* 1051 * A packet was sent to the chip. It's safe for us to clean up 1052 * the list buffers. 1053 */ 1054 1055 void 1056 wi_usb_txeof_frm(usbd_xfer_handle xfer, usbd_private_handle priv, 1057 usbd_status status) 1058 { 1059 struct wi_usb_chain *c = priv; 1060 struct wi_usb_softc *sc = c->wi_usb_sc; 1061 struct wi_softc *wsc = &sc->sc_wi; 1062 struct ifnet *ifp = &wsc->sc_arpcom.ac_if; 1063 1064 int s; 1065 int err = 0; 1066 1067 if (sc->wi_usb_dying) 1068 return; 1069 1070 s = splnet(); 1071 1072 DPRINTFN(10,("%s: %s: enter status=%d\n", USBDEVNAME(sc->wi_usb_dev), 1073 __func__, status)); 1074 1075 if (status != USBD_NORMAL_COMPLETION) { 1076 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 1077 splx(s); 1078 return; 1079 } 1080 printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->wi_usb_dev), 1081 usbd_errstr(status)); 1082 if (status == USBD_STALLED) { 1083 sc->wi_usb_refcnt++; 1084 usbd_clear_endpoint_stall( 1085 sc->wi_usb_ep[WI_USB_ENDPT_TX]); 1086 if (--sc->wi_usb_refcnt < 0) 1087 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1088 } 1089 splx(s); 1090 return; 1091 } 1092 1093 if (status) 1094 err = WI_EV_TX_EXC; 1095 1096 wi_txeof(wsc, err); 1097 1098 wi_usb_tx_unlock(sc); 1099 1100 if (!IFQ_IS_EMPTY(&ifp->if_snd)) 1101 wi_start_usb(ifp); 1102 1103 splx(s); 1104 } 1105 1106 int 1107 wi_usb_rx_list_init(struct wi_usb_softc *sc) 1108 { 1109 struct wi_usb_chain *c; 1110 int i; 1111 1112 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1113 1114 for (i = 0; i < WI_USB_RX_LIST_CNT; i++) { 1115 c = &sc->wi_usb_rx_chain[i]; 1116 c->wi_usb_sc = sc; 1117 c->wi_usb_idx = i; 1118 if (c->wi_usb_xfer != NULL) { 1119 printf("UGH RX\n"); 1120 } 1121 if (c->wi_usb_xfer == NULL) { 1122 c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev); 1123 if (c->wi_usb_xfer == NULL) 1124 return (ENOBUFS); 1125 c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer, 1126 WI_USB_BUFSZ); 1127 if (c->wi_usb_buf == NULL) 1128 return (ENOBUFS); /* XXX free xfer */ 1129 } 1130 } 1131 1132 return (0); 1133 } 1134 1135 int 1136 wi_usb_tx_list_init(struct wi_usb_softc *sc) 1137 { 1138 struct wi_usb_chain *c; 1139 int i; 1140 1141 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1142 1143 for (i = 0; i < WI_USB_TX_LIST_CNT; i++) { 1144 c = &sc->wi_usb_tx_chain[i]; 1145 c->wi_usb_sc = sc; 1146 c->wi_usb_idx = i; 1147 c->wi_usb_mbuf = NULL; 1148 if (c->wi_usb_xfer != NULL) { 1149 printf("UGH TX\n"); 1150 } 1151 if (c->wi_usb_xfer == NULL) { 1152 c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev); 1153 if (c->wi_usb_xfer == NULL) 1154 return (ENOBUFS); 1155 c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer, 1156 WI_USB_BUFSZ); 1157 if (c->wi_usb_buf == NULL) 1158 return (ENOBUFS); 1159 } 1160 } 1161 1162 return (0); 1163 } 1164 1165 int 1166 wi_usb_open_pipes(struct wi_usb_softc *sc) 1167 { 1168 usbd_status err; 1169 int error = 0; 1170 struct wi_usb_chain *c; 1171 int i; 1172 1173 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev),__func__)); 1174 1175 sc->wi_usb_refcnt++; 1176 1177 /* Open RX and TX pipes. */ 1178 err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_RX], 1179 USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_RX]); 1180 if (err) { 1181 printf("%s: open rx pipe failed: %s\n", 1182 USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err)); 1183 error = EIO; 1184 goto done; 1185 } 1186 1187 err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_TX], 1188 USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_TX]); 1189 if (err) { 1190 printf("%s: open tx pipe failed: %s\n", 1191 USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err)); 1192 error = EIO; 1193 goto done; 1194 } 1195 1196 /* is this used? */ 1197 err = usbd_open_pipe_intr(sc->wi_usb_iface, 1198 sc->wi_usb_ed[WI_USB_ENDPT_INTR], USBD_EXCLUSIVE_USE, 1199 &sc->wi_usb_ep[WI_USB_ENDPT_INTR], sc, &sc->wi_usb_ibuf, 1200 WI_USB_INTR_PKTLEN, wi_usb_intr, WI_USB_INTR_INTERVAL); 1201 if (err) { 1202 printf("%s: open intr pipe failed: %s\n", 1203 USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err)); 1204 error = EIO; 1205 goto done; 1206 } 1207 1208 /* Start up the receive pipe. */ 1209 for (i = 0; i < WI_USB_RX_LIST_CNT; i++) { 1210 c = &sc->wi_usb_rx_chain[i]; 1211 usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX], 1212 c, c->wi_usb_buf, WI_USB_BUFSZ, 1213 USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, 1214 wi_usb_rxeof); 1215 DPRINTFN(10,("%s: %s: start read\n", USBDEVNAME(sc->wi_usb_dev), 1216 __func__)); 1217 usbd_transfer(c->wi_usb_xfer); 1218 } 1219 1220 done: 1221 if (--sc->wi_usb_refcnt < 0) 1222 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1223 1224 return (error); 1225 } 1226 1227 /* 1228 * This is a bit of a kludge, however wi_rxeof and wi_update_stats 1229 * call wi_get_fid to determine where the data associated with 1230 * the transaction is located, the returned id is then used to 1231 * wi_read_data the information out. 1232 * 1233 * This code returns which 'fid' should be used. The results are only valid 1234 * during a wi_usb_rxeof because the data is received packet is 'held' 1235 * an a variable for reading by wi_read_data_usb for that period. 1236 * 1237 * for magic numbers this uses 0x1000, 0x1001 for rx/info 1238 */ 1239 1240 int 1241 wi_get_fid_usb(struct wi_softc *sc, int fid) 1242 { 1243 switch (fid) { 1244 case WI_RX_FID: 1245 return 0x1000; 1246 case WI_INFO_FID: 1247 return 0x1001; 1248 default: 1249 return 0x1111; 1250 } 1251 1252 } 1253 1254 int 1255 wi_usb_activate(device_ptr_t self, enum devact act) 1256 { 1257 struct wi_usb_softc *sc = (struct wi_usb_softc *)self; 1258 1259 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1260 1261 switch (act) { 1262 case DVACT_ACTIVATE: 1263 return (EOPNOTSUPP); 1264 break; 1265 1266 case DVACT_DEACTIVATE: 1267 if_deactivate(&sc->sc_wi.wi_ec.ec_if); 1268 sc->wi_usb_dying = 1; 1269 sc->wi_thread_info->dying = 1; 1270 break; 1271 } 1272 return (0); 1273 } 1274 1275 #if 0 1276 void 1277 wi_dump_data(void *buffer, int len) 1278 { 1279 int i; 1280 for (i = 0; i < len; i++) { 1281 if (((i) % 16) == 0) 1282 printf("\n %02x:", i); 1283 printf(" %02x", 1284 ((uint8_t *)(buffer))[i]); 1285 1286 } 1287 printf("\n"); 1288 1289 } 1290 #endif 1291 1292 /* 1293 * A frame has been received. 1294 */ 1295 void 1296 wi_usb_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) 1297 { 1298 struct wi_usb_chain *c = priv; 1299 struct wi_usb_softc *sc = c->wi_usb_sc; 1300 wi_usb_usbin *uin; 1301 int total_len = 0; 1302 u_int16_t rtype; 1303 1304 if (sc->wi_usb_dying) 1305 return; 1306 1307 DPRINTFN(10,("%s: %s: enter status=%d\n", USBDEVNAME(sc->wi_usb_dev), 1308 __func__, status)); 1309 1310 1311 if (status != USBD_NORMAL_COMPLETION) { 1312 if (status == USBD_NOT_STARTED || status == USBD_IOERROR 1313 || status == USBD_CANCELLED) { 1314 printf("%s: %u usb errors on rx: %s\n", 1315 USBDEVNAME(sc->wi_usb_dev), 1, 1316 /* sc->wi_usb_rx_errs, */ 1317 usbd_errstr(status)); 1318 return; 1319 } 1320 #if 0 1321 sc->wi_usb_rx_errs++; 1322 if (usbd_ratecheck(&sc->wi_usb_rx_notice)) { 1323 printf("%s: %u usb errors on rx: %s\n", 1324 USBDEVNAME(sc->wi_usb_dev), sc->wi_usb_rx_errs, 1325 usbd_errstr(status)); 1326 sc->wi_usb_rx_errs = 0; 1327 } 1328 #endif 1329 if (status == USBD_STALLED) { 1330 sc->wi_usb_refcnt++; 1331 usbd_clear_endpoint_stall( 1332 sc->wi_usb_ep[WI_USB_ENDPT_RX]); 1333 if (--sc->wi_usb_refcnt < 0) 1334 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1335 } 1336 goto done; 1337 } 1338 1339 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); 1340 1341 if (total_len < 6) /* short XXX */ 1342 goto done; 1343 1344 uin = (wi_usb_usbin *)(c->wi_usb_buf); 1345 1346 rtype = letoh16(uin->type); 1347 1348 1349 #if 0 1350 wi_dump_data(c->wi_usb_buf, total_len); 1351 #endif 1352 1353 if (WI_USB_ISRXFRM(rtype)) { 1354 wi_usb_rxfrm(sc, uin, total_len); 1355 goto done; 1356 } 1357 if (WI_USB_ISTXFRM(rtype)) { 1358 DPRINTFN(2,("%s: %s: txfrm type %x\n", 1359 USBDEVNAME(sc->wi_usb_dev), __func__, rtype)); 1360 wi_usb_txfrm(sc, uin, total_len); 1361 goto done; 1362 } 1363 1364 switch (rtype) { 1365 case WI_USB_INFOFRM: 1366 /* info packet, INFO_FID hmm */ 1367 DPRINTFN(10,("%s: %s: infofrm type %x\n", 1368 USBDEVNAME(sc->wi_usb_dev), __func__, rtype)); 1369 wi_usb_infofrm(c, total_len); 1370 break; 1371 case WI_USB_CMDRESP: 1372 wi_usb_cmdresp(c); 1373 break; 1374 case WI_USB_WRIDRESP: 1375 wi_usb_wridresp(c); 1376 break; 1377 case WI_USB_RRIDRESP: 1378 wi_usb_rridresp(c); 1379 break; 1380 case WI_USB_WMEMRESP: 1381 /* Not currently used */ 1382 DPRINTFN(2,("%s: %s: wmemresp type %x\n", 1383 USBDEVNAME(sc->wi_usb_dev), __func__, rtype)); 1384 break; 1385 case WI_USB_RMEMRESP: 1386 /* Not currently used */ 1387 DPRINTFN(2,("%s: %s: rmemresp type %x\n", 1388 USBDEVNAME(sc->wi_usb_dev), __func__, rtype)); 1389 break; 1390 case WI_USB_BUFAVAIL: 1391 printf("wi_usb: received USB_BUFAVAIL packet\n"); /* XXX */ 1392 break; 1393 case WI_USB_ERROR: 1394 printf("wi_usb: received USB_ERROR packet\n"); /* XXX */ 1395 break; 1396 default: 1397 #if 0 1398 printf("wi_usb: received Unknown packet 0x%x len %x\n", 1399 rtype, total_len); 1400 wi_dump_data(c->wi_usb_buf, total_len); 1401 #endif 1402 } 1403 1404 done: 1405 /* Setup new transfer. */ 1406 usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX], 1407 c, c->wi_usb_buf, WI_USB_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, 1408 USBD_NO_TIMEOUT, wi_usb_rxeof); 1409 sc->wi_usb_refcnt++; 1410 usbd_transfer(c->wi_usb_xfer); 1411 if (--sc->wi_usb_refcnt < 0) 1412 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1413 1414 DPRINTFN(10,("%s: %s: start rx\n", USBDEVNAME(sc->wi_usb_dev), 1415 __func__)); 1416 } 1417 1418 void 1419 wi_usb_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) 1420 { 1421 struct wi_usb_softc *sc = priv; 1422 1423 DPRINTFN(2,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1424 1425 if (sc->wi_usb_dying) 1426 return; 1427 1428 if (status != USBD_NORMAL_COMPLETION) { 1429 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 1430 return; 1431 1432 if (status == USBD_STALLED) { 1433 sc->wi_usb_refcnt++; 1434 usbd_clear_endpoint_stall( 1435 sc->wi_usb_ep[WI_USB_ENDPT_RX]); 1436 if (--sc->wi_usb_refcnt < 0) 1437 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1438 } 1439 return; 1440 } 1441 /* XXX oerrors or collisions? */ 1442 } 1443 void 1444 wi_usb_cmdresp(struct wi_usb_chain *c) 1445 { 1446 struct wi_cmdresp *presp = (struct wi_cmdresp *)(c->wi_usb_buf); 1447 u_int16_t status = letoh16(presp->status); 1448 struct wi_usb_softc *sc = c->wi_usb_sc; 1449 uint16_t type; 1450 uint16_t cmdresperr; 1451 1452 type = htole16(presp->type); 1453 cmdresperr = letoh16(presp->resp0); 1454 DPRINTFN(10,("%s: %s: enter rid=%x status %x %x %x\n", 1455 USBDEVNAME(sc->wi_usb_dev), __func__, type, status, sc->cmdresp, 1456 cmdresperr)); 1457 1458 if (sc->cmdresp != status) { 1459 DPRINTFN(1,("%s:cmd ty %x st %x cmd %x failed %x\n", 1460 USBDEVNAME(sc->wi_usb_dev), 1461 type, status, sc->cmdresp, cmdresperr)); 1462 return; 1463 } 1464 1465 if ((cmdresperr != 0) && ((sc->cmdresp == WI_CMD_INQUIRE) || 1466 (sc->cmdresp == WI_CMD_DISABLE)) ) { 1467 /* 1468 * For some reason MA111 does not like info frame requests, 1469 * or some DISABLES 1470 * It responds to the request with the info 1471 * but it claims the request failed 1472 * reset the error code. 1473 */ 1474 cmdresperr = 0; 1475 } 1476 1477 if (cmdresperr != 0) { 1478 DPRINTFN(1,("%s:cmd ty %x st %x cmd %x failed %x\n", 1479 USBDEVNAME(sc->wi_usb_dev), 1480 type, status, sc->cmdresp, cmdresperr)); 1481 } 1482 1483 sc->cmdresperr = cmdresperr; 1484 1485 sc->cmdresp = 0; /* good value for idle == INI ?? XXX */ 1486 1487 wakeup(&sc->cmdresperr); 1488 } 1489 void 1490 wi_usb_rridresp(struct wi_usb_chain *c) 1491 { 1492 struct wi_rridresp *presp = (struct wi_rridresp *)(c->wi_usb_buf); 1493 u_int16_t frmlen = letoh16(presp->frmlen); 1494 struct wi_usb_softc *sc = c->wi_usb_sc; 1495 struct wi_ltv_gen *ltv; 1496 uint16_t rid; 1497 1498 rid = letoh16(presp->rid); 1499 ltv = sc->ridltv; 1500 1501 if (ltv == 0) { 1502 DPRINTFN(5,("%s: %s: enter ltv = 0 rid=%x len %d\n", 1503 USBDEVNAME(sc->wi_usb_dev), __func__, rid, 1504 frmlen)); 1505 return; 1506 } 1507 1508 DPRINTFN(5,("%s: %s: enter rid=%x expecting %x len %d exptlen %d\n", 1509 USBDEVNAME(sc->wi_usb_dev), __func__, rid, ltv->wi_type, 1510 frmlen, ltv->wi_len)); 1511 1512 rid = letoh16(presp->rid); 1513 1514 if (rid != ltv->wi_type) { 1515 sc->ridresperr = EIO; 1516 return; 1517 } 1518 1519 /* XXX */ 1520 if (rid == WI_RID_DATA_RATES) 1521 frmlen = 2; 1522 1523 if (frmlen > ltv->wi_len) { 1524 sc->ridresperr = ENOSPC; 1525 sc->ridltv = 0; 1526 wakeup(&sc->ridresperr); 1527 return; 1528 } 1529 1530 ltv->wi_len = frmlen; 1531 1532 DPRINTFN(10,("%s: %s: copying %x frmlen %d s %x d %x\n", 1533 USBDEVNAME(sc->wi_usb_dev), __func__, (ltv->wi_len-1)*2, 1534 frmlen)); 1535 1536 if (ltv->wi_len > 1) 1537 bcopy(&presp->data[0], (u_int8_t *)<v->wi_val, 1538 (ltv->wi_len-1)*2); 1539 1540 sc->ridresperr = 0; 1541 sc->ridltv = 0; 1542 wakeup(&sc->ridresperr); 1543 1544 } 1545 1546 void 1547 wi_usb_wridresp(struct wi_usb_chain *c) 1548 { 1549 struct wi_wridresp *presp = (struct wi_wridresp *)(c->wi_usb_buf); 1550 struct wi_usb_softc *sc = c->wi_usb_sc; 1551 uint16_t status; 1552 1553 status = letoh16(presp->status); 1554 1555 DPRINTFN(10,("%s: %s: enter status=%x\n", 1556 USBDEVNAME(sc->wi_usb_dev), __func__, status)); 1557 1558 sc->ridresperr = status; 1559 sc->ridltv = 0; 1560 wakeup(&sc->ridresperr); 1561 } 1562 1563 void 1564 wi_usb_infofrm(struct wi_usb_chain *c, int len) 1565 { 1566 struct wi_usb_softc *sc = c->wi_usb_sc; 1567 1568 DPRINTFN(10,("%s: %s: enter\n", 1569 USBDEVNAME(sc->wi_usb_dev), __func__)); 1570 1571 sc->wi_info = ((char *)c->wi_usb_buf) + 2; 1572 wi_update_stats(&sc->sc_wi); 1573 sc->wi_info = NULL; 1574 } 1575 1576 void 1577 wi_usb_txfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len) 1578 { 1579 u_int16_t status; 1580 int s; 1581 struct wi_softc *wsc = &sc->sc_wi; 1582 struct ifnet *ifp = &wsc->sc_arpcom.ac_if; 1583 1584 s = splnet(); 1585 status = letoh16(uin->type); /* XXX -- type == status */ 1586 1587 1588 DPRINTFN(2,("%s: %s: enter status=%d\n", 1589 USBDEVNAME(sc->wi_usb_dev), __func__, status)); 1590 1591 if (sc->txresp == WI_CMD_TX) { 1592 sc->txresperr=status; 1593 sc->txresp = 0; 1594 wakeup(&sc->txresperr); 1595 } else { 1596 if (status != 0) /* XXX */ 1597 wi_watchdog_usb(ifp); 1598 DPRINTFN(1,("%s: %s: txresp not expected status=%d \n", 1599 USBDEVNAME(sc->wi_usb_dev), __func__, status)); 1600 } 1601 1602 splx(s); 1603 } 1604 void 1605 wi_usb_rxfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len) 1606 { 1607 int s; 1608 1609 DPRINTFN(5,("%s: %s: enter len=%d\n", 1610 USBDEVNAME(sc->wi_usb_dev), __func__, total_len)); 1611 1612 s = splnet(); 1613 1614 sc->wi_rxframe = (void *)uin; 1615 1616 wi_rxeof(&sc->sc_wi); 1617 1618 sc->wi_rxframe = NULL; 1619 1620 splx(s); 1621 1622 } 1623 1624 1625 void 1626 wi_usb_start_thread(void *arg) 1627 { 1628 struct wi_usb_softc *sc = arg; 1629 kthread_create (wi_usb_thread, arg, NULL, USBDEVNAME(sc->wi_usb_dev)); 1630 } 1631 1632 void 1633 wi_start_usb(struct ifnet *ifp) 1634 { 1635 struct wi_softc *wsc; 1636 struct wi_usb_softc *sc; 1637 int s; 1638 1639 wsc = ifp->if_softc; 1640 sc = wsc->wi_usb_cdata; 1641 1642 s = splimp(); 1643 1644 DPRINTFN(5,("%s: %s:\n", 1645 USBDEVNAME(sc->wi_usb_dev), __func__)); 1646 1647 if (wi_usb_tx_lock_try(sc)) { 1648 /* lock acquired do start now */ 1649 wi_func_io.f_start(ifp); 1650 } else { 1651 sc->wi_thread_info->status |= WI_START; 1652 if (sc->wi_thread_info->idle) 1653 wakeup (sc->wi_thread_info); 1654 } 1655 1656 splx(s); 1657 } 1658 1659 /* 1660 * inquire is called from interrupt context (timeout) 1661 * It is not possible to sleep in interrupt context so it is necessary 1662 * to signal the kernel thread to perform the action. 1663 */ 1664 void 1665 wi_init_usb(struct wi_softc *wsc) 1666 { 1667 DPRINTFN(5,("%s: %s:\n", WI_PRT_ARG(wsc), __func__)); 1668 1669 wi_usb_ctl_lock(wsc->wi_usb_cdata); 1670 wi_func_io.f_init(wsc); 1671 wi_usb_ctl_unlock(wsc->wi_usb_cdata); 1672 } 1673 1674 1675 /* 1676 * inquire is called from interrupt context (timeout) 1677 * It is not possible to sleep in interrupt context so it is necessary 1678 * to signal the kernel thread to perform the action. 1679 */ 1680 void 1681 wi_inquire_usb(void *xsc) 1682 { 1683 struct wi_softc *wsc = xsc; 1684 struct wi_usb_softc *sc = wsc->wi_usb_cdata; 1685 int s; 1686 1687 1688 s = splimp(); 1689 1690 DPRINTFN(2,("%s: %s:\n", 1691 USBDEVNAME(sc->wi_usb_dev), __func__)); 1692 1693 sc->wi_thread_info->status |= WI_INQUIRE; 1694 1695 if (sc->wi_thread_info->idle) 1696 wakeup (sc->wi_thread_info); 1697 splx(s); 1698 } 1699 1700 /* 1701 * Watchdog is normally called from interrupt context (timeout) 1702 * It is not possible to sleep in interrupt context so it is necessary 1703 * to signal the kernel thread to perform the action. 1704 */ 1705 void 1706 wi_watchdog_usb(struct ifnet *ifp) 1707 { 1708 struct wi_softc *wsc; 1709 struct wi_usb_softc *sc; 1710 int s; 1711 1712 wsc = ifp->if_softc; 1713 sc = wsc->wi_usb_cdata; 1714 1715 s = splimp(); 1716 1717 DPRINTFN(5,("%s: %s: ifp %x\n", 1718 USBDEVNAME(sc->wi_usb_dev), __func__, ifp)); 1719 1720 sc->wi_thread_info->status |= WI_WATCHDOG; 1721 1722 if (sc->wi_thread_info->idle) 1723 wakeup (sc->wi_thread_info); 1724 splx(s); 1725 } 1726 1727 /* 1728 * ioctl will always be called from a user context, 1729 * therefore is is possible to sleep in the calling context 1730 * acquire the lock and call the real ioctl fucntion directly 1731 */ 1732 int 1733 wi_ioctl_usb(struct ifnet *ifp, u_long command, caddr_t data) 1734 { 1735 struct wi_softc *wsc; 1736 int err; 1737 1738 wsc = ifp->if_softc; 1739 1740 wi_usb_ctl_lock(wsc->wi_usb_cdata); 1741 err = wi_func_io.f_ioctl(ifp, command, data); 1742 wi_usb_ctl_unlock(wsc->wi_usb_cdata); 1743 return err; 1744 } 1745 1746 void 1747 wi_usb_thread(void *arg) 1748 { 1749 struct wi_usb_softc *sc = arg; 1750 struct wi_usb_thread_info *wi_thread_info; 1751 int s; 1752 1753 wi_thread_info = malloc(sizeof(*wi_thread_info), M_DEVBUF, M_WAITOK); 1754 1755 /* 1756 * is there a remote possibility that the device could 1757 * be removed before the kernel thread starts up? 1758 */ 1759 1760 sc->wi_usb_refcnt++; 1761 1762 sc->wi_thread_info = wi_thread_info; 1763 wi_thread_info->dying = 0; 1764 wi_thread_info->status = 0; 1765 1766 wi_usb_ctl_lock(sc); 1767 1768 wi_attach(&sc->sc_wi, &wi_func_usb); 1769 1770 wi_usb_ctl_unlock(sc); 1771 1772 for(;;) { 1773 if (wi_thread_info->dying) { 1774 if (--sc->wi_usb_refcnt < 0) 1775 usb_detach_wakeup(USBDEV(sc->wi_usb_dev)); 1776 kthread_exit(0); 1777 } 1778 1779 DPRINTFN(5,("%s: %s: dying %x status %x\n", 1780 USBDEVNAME(sc->wi_usb_dev), __func__, 1781 wi_thread_info->dying, wi_thread_info->status)); 1782 1783 wi_usb_ctl_lock(sc); 1784 1785 DPRINTFN(5,("%s: %s: starting %x\n", 1786 USBDEVNAME(sc->wi_usb_dev), __func__, 1787 wi_thread_info->status)); 1788 1789 s = splusb(); 1790 if (wi_thread_info->status & WI_START) { 1791 wi_thread_info->status &= ~WI_START; 1792 wi_usb_tx_lock(sc); 1793 wi_func_io.f_start(&sc->sc_wi.sc_arpcom.ac_if); 1794 /* 1795 * tx_unlock is explictly missing here 1796 * is is done in txeof_frm 1797 */ 1798 } else if (wi_thread_info->status & WI_INQUIRE) { 1799 wi_thread_info->status &= ~WI_INQUIRE; 1800 wi_func_io.f_inquire(&sc->sc_wi); 1801 } else if (wi_thread_info->status & WI_WATCHDOG) { 1802 wi_thread_info->status &= ~WI_WATCHDOG; 1803 wi_func_io.f_watchdog( &sc->sc_wi.sc_arpcom.ac_if); 1804 } 1805 splx(s); 1806 1807 DPRINTFN(5,("%s: %s: ending %x\n", 1808 USBDEVNAME(sc->wi_usb_dev), __func__, 1809 wi_thread_info->status)); 1810 wi_usb_ctl_unlock(sc); 1811 1812 if (wi_thread_info->status == 0) { 1813 s = splimp(); 1814 wi_thread_info->idle = 1; 1815 tsleep(wi_thread_info, PRIBIO, "wiIDL", 0); 1816 wi_thread_info->idle = 0; 1817 splx(s); 1818 } 1819 } 1820 } 1821 1822 int 1823 wi_usb_tx_lock_try(struct wi_usb_softc *sc) 1824 { 1825 int s; 1826 1827 s = splimp(); /* right priority? */ 1828 1829 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1830 1831 if (sc->wi_lock != 0) { 1832 return 0; /* failed to aquire lock */ 1833 } 1834 1835 sc->wi_lock = 1; 1836 1837 splx(s); 1838 1839 return 1; 1840 } 1841 void 1842 wi_usb_tx_lock(struct wi_usb_softc *sc) 1843 { 1844 int s; 1845 1846 s = splimp(); /* right priority? */ 1847 1848 again: 1849 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1850 1851 if (sc->wi_lock != 0) { 1852 sc->wi_lockwait++; 1853 DPRINTFN(10,("%s: %s: busy %d\n", USBDEVNAME(sc->wi_usb_dev), 1854 __func__, sc->wi_lockwait )); 1855 tsleep(&sc->wi_lock, PRIBIO, "witxl", 0); 1856 } 1857 1858 if (sc->wi_lock != 0) 1859 goto again; 1860 sc->wi_lock = 1; 1861 1862 splx(s); 1863 1864 return; 1865 1866 } 1867 1868 void 1869 wi_usb_tx_unlock(struct wi_usb_softc *sc) 1870 { 1871 int s; 1872 s = splimp(); /* right priority? */ 1873 1874 sc->wi_lock = 0; 1875 1876 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1877 1878 if (sc->wi_lockwait) { 1879 DPRINTFN(10,("%s: %s: waking\n", 1880 USBDEVNAME(sc->wi_usb_dev), __func__)); 1881 sc->wi_lockwait = 0; 1882 wakeup(&sc->wi_lock); 1883 } 1884 1885 splx(s); 1886 } 1887 1888 void 1889 wi_usb_ctl_lock(struct wi_usb_softc *sc) 1890 { 1891 int s; 1892 1893 s = splimp(); /* right priority? */ 1894 1895 again: 1896 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), 1897 __func__)); 1898 1899 if (sc->wi_ctllock != 0) { 1900 if (curproc == sc->wi_curproc) { 1901 /* allow recursion */ 1902 sc->wi_ctllock++; 1903 splx(s); 1904 return; 1905 } 1906 sc->wi_ctllockwait++; 1907 DPRINTFN(10,("%s: %s: busy %d\n", USBDEVNAME(sc->wi_usb_dev), 1908 __func__, sc->wi_ctllockwait )); 1909 tsleep(&sc->wi_ctllock, PRIBIO, "wiusbthr", 0); 1910 } 1911 1912 if (sc->wi_ctllock != 0) 1913 goto again; 1914 sc->wi_ctllock++; 1915 sc->wi_curproc = curproc; 1916 1917 splx(s); 1918 1919 return; 1920 1921 } 1922 1923 void 1924 wi_usb_ctl_unlock(struct wi_usb_softc *sc) 1925 { 1926 int s; 1927 1928 s = splimp(); /* right priority? */ 1929 1930 sc->wi_ctllock--; 1931 1932 DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__)); 1933 1934 if (sc->wi_ctllock == 0 && sc->wi_ctllockwait) { 1935 DPRINTFN(10,("%s: %s: waking\n", 1936 USBDEVNAME(sc->wi_usb_dev), __func__)); 1937 sc->wi_ctllockwait = 0; 1938 sc->wi_curproc = 0; 1939 wakeup(&sc->wi_ctllock); 1940 } 1941 1942 splx(s); 1943 } 1944