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