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