1 /* $NetBSD: if_bwfm_usb.c,v 1.4 2018/01/21 13:57:11 skrll Exp $ */ 2 /* $OpenBSD: if_bwfm_usb.c,v 1.2 2017/10/15 14:55:13 patrick Exp $ */ 3 /* 4 * Copyright (c) 2010-2016 Broadcom Corporation 5 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/buf.h> 23 #include <sys/kernel.h> 24 #include <sys/malloc.h> 25 #include <sys/device.h> 26 #include <sys/queue.h> 27 #include <sys/socket.h> 28 #include <sys/mutex.h> 29 #include <sys/workqueue.h> 30 #include <sys/pcq.h> 31 32 #include <net/bpf.h> 33 #include <net/if.h> 34 #include <net/if_dl.h> 35 #include <net/if_media.h> 36 #include <net/if_ether.h> 37 38 #include <netinet/in.h> 39 40 #include <net80211/ieee80211_var.h> 41 42 #include <dev/firmload.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/usbdivar.h> 48 #include <dev/usb/usbdevs.h> 49 50 #include <dev/ic/bwfmvar.h> 51 #include <dev/ic/bwfmreg.h> 52 53 /* 54 * Various supported device vendors/products. 55 */ 56 static const struct usb_devno bwfm_usbdevs[] = { 57 { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM43143 }, 58 { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM43236 }, 59 { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM43242 }, 60 { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM43569 }, 61 { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCMFW }, 62 }; 63 64 #ifdef BWFM_DEBUG 65 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 66 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 67 static int bwfm_debug = 2; 68 #else 69 #define DPRINTF(x) do { ; } while (0) 70 #define DPRINTFN(n, x) do { ; } while (0) 71 #endif 72 73 #define DEVNAME(sc) device_xname((sc)->sc_sc.sc_dev) 74 75 #define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle 76 * has boot up 77 */ 78 79 #define TRX_MAGIC 0x30524448 /* "HDR0" */ 80 #define TRX_MAX_OFFSET 3 /* Max number of file offsets */ 81 #define TRX_UNCOMP_IMAGE 0x20 /* Trx holds uncompressed img */ 82 #define TRX_RDL_CHUNK 1500 /* size of each dl transfer */ 83 #define TRX_OFFSETS_DLFWLEN_IDX 0 84 85 /* Control messages: bRequest values */ 86 #define DL_GETSTATE 0 /* returns the rdl_state_t struct */ 87 #define DL_CHECK_CRC 1 /* currently unused */ 88 #define DL_GO 2 /* execute downloaded image */ 89 #define DL_START 3 /* initialize dl state */ 90 #define DL_REBOOT 4 /* reboot the device in 2 seconds */ 91 #define DL_GETVER 5 /* returns the bootrom_id_t struct */ 92 #define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset 93 * event to occur in 2 seconds. It is the 94 * responsibility of the downloaded code to 95 * clear this event 96 */ 97 #define DL_EXEC 7 /* jump to a supplied address */ 98 #define DL_RESETCFG 8 /* To support single enum on dongle 99 * - Not used by bootloader 100 */ 101 #define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup 102 * if resp unavailable 103 */ 104 105 /* states */ 106 #define DL_WAITING 0 /* waiting to rx first pkt */ 107 #define DL_READY 1 /* hdr was good, waiting for more of the 108 * compressed image 109 */ 110 #define DL_BAD_HDR 2 /* hdr was corrupted */ 111 #define DL_BAD_CRC 3 /* compressed image was corrupted */ 112 #define DL_RUNNABLE 4 /* download was successful,waiting for go cmd */ 113 #define DL_START_FAIL 5 /* failed to initialize correctly */ 114 #define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM 115 * value 116 */ 117 #define DL_IMAGE_TOOBIG 7 /* firmware image too big */ 118 119 120 struct trx_header { 121 uint32_t magic; /* "HDR0" */ 122 uint32_t len; /* Length of file including header */ 123 uint32_t crc32; /* CRC from flag_version to end of file */ 124 uint32_t flag_version; /* 0:15 flags, 16:31 version */ 125 uint32_t offsets[TRX_MAX_OFFSET];/* Offsets of partitions from start of 126 * header 127 */ 128 }; 129 130 struct rdl_state { 131 uint32_t state; 132 uint32_t bytes; 133 }; 134 135 struct bootrom_id { 136 uint32_t chip; /* Chip id */ 137 uint32_t chiprev; /* Chip rev */ 138 uint32_t ramsize; /* Size of RAM */ 139 uint32_t remapbase; /* Current remap base address */ 140 uint32_t boardtype; /* Type of board */ 141 uint32_t boardrev; /* Board revision */ 142 }; 143 144 struct bwfm_usb_rx_data { 145 struct bwfm_usb_softc *sc; 146 struct usbd_xfer *xfer; 147 uint8_t *buf; 148 }; 149 150 struct bwfm_usb_tx_data { 151 struct bwfm_usb_softc *sc; 152 struct usbd_xfer *xfer; 153 uint8_t *buf; 154 struct mbuf *mbuf; 155 TAILQ_ENTRY(bwfm_usb_tx_data) next; 156 }; 157 158 #define BWFM_RX_LIST_COUNT 50 159 #define BWFM_TX_LIST_COUNT 50 160 #define BWFM_RXBUFSZ 1600 161 #define BWFM_TXBUFSZ 1600 162 struct bwfm_usb_softc { 163 struct bwfm_softc sc_sc; 164 struct usbd_device *sc_udev; 165 struct usbd_interface *sc_iface; 166 uint8_t sc_ifaceno; 167 168 uint16_t sc_vendor; 169 uint16_t sc_product; 170 171 uint32_t sc_chip; 172 uint32_t sc_chiprev; 173 174 int sc_rx_no; 175 int sc_tx_no; 176 177 struct usbd_pipe *sc_rx_pipeh; 178 struct usbd_pipe *sc_tx_pipeh; 179 180 struct bwfm_usb_rx_data sc_rx_data[BWFM_RX_LIST_COUNT]; 181 struct bwfm_usb_tx_data sc_tx_data[BWFM_TX_LIST_COUNT]; 182 TAILQ_HEAD(, bwfm_usb_tx_data) sc_tx_free_list; 183 184 kmutex_t sc_rx_lock; 185 kmutex_t sc_tx_lock; 186 }; 187 188 int bwfm_usb_match(device_t, cfdata_t, void *); 189 void bwfm_usb_attachhook(device_t); 190 void bwfm_usb_attach(device_t, device_t, void *); 191 int bwfm_usb_detach(device_t, int); 192 193 int bwfm_usb_dl_cmd(struct bwfm_usb_softc *, uint8_t, void *, int); 194 int bwfm_usb_load_microcode(struct bwfm_usb_softc *, const u_char *, 195 size_t); 196 197 int bwfm_usb_alloc_rx_list(struct bwfm_usb_softc *); 198 void bwfm_usb_free_rx_list(struct bwfm_usb_softc *); 199 int bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *); 200 void bwfm_usb_free_tx_list(struct bwfm_usb_softc *); 201 202 int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *); 203 int bwfm_usb_txctl(struct bwfm_softc *, char *, size_t); 204 int bwfm_usb_rxctl(struct bwfm_softc *, char *, size_t *); 205 206 void bwfm_usb_rxeof(struct usbd_xfer *, void *, usbd_status); 207 void bwfm_usb_txeof(struct usbd_xfer *, void *, usbd_status); 208 209 struct bwfm_bus_ops bwfm_usb_bus_ops = { 210 .bs_init = NULL, 211 .bs_stop = NULL, 212 .bs_txdata = bwfm_usb_txdata, 213 .bs_txctl = bwfm_usb_txctl, 214 .bs_rxctl = bwfm_usb_rxctl, 215 }; 216 217 CFATTACH_DECL_NEW(bwfm_usb, sizeof(struct bwfm_usb_softc), 218 bwfm_usb_match, bwfm_usb_attach, bwfm_usb_detach, NULL); 219 220 int 221 bwfm_usb_match(device_t parent, cfdata_t match, void *aux) 222 { 223 struct usb_attach_arg *uaa = aux; 224 225 return (usb_lookup(bwfm_usbdevs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ? 226 UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE; 227 } 228 229 void 230 bwfm_usb_attach(device_t parent, device_t self, void *aux) 231 { 232 struct bwfm_usb_softc *sc = device_private(self); 233 struct usb_attach_arg *uaa = aux; 234 usb_device_descriptor_t *dd; 235 usb_interface_descriptor_t *id; 236 usb_endpoint_descriptor_t *ed; 237 char *devinfop; 238 int i; 239 240 sc->sc_sc.sc_dev = self; 241 sc->sc_udev = uaa->uaa_device; 242 mutex_init(&sc->sc_rx_lock, MUTEX_DEFAULT, IPL_NET); 243 mutex_init(&sc->sc_tx_lock, MUTEX_DEFAULT, IPL_NET); 244 245 aprint_naive("\n"); 246 247 devinfop = usbd_devinfo_alloc(sc->sc_udev, 0); 248 aprint_normal(": %s\n", devinfop); 249 usbd_devinfo_free(devinfop); 250 251 if (usbd_set_config_no(sc->sc_udev, 1, 1) != 0) { 252 aprint_error_dev(self, "failed to set configuration\n"); 253 return; 254 } 255 if (usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface) != 0) { 256 aprint_error_dev(self, "failed to get interface handle\n"); 257 return; 258 } 259 260 sc->sc_ifaceno = 0; 261 sc->sc_vendor = uaa->uaa_vendor; 262 sc->sc_product = uaa->uaa_product; 263 sc->sc_sc.sc_bus_ops = &bwfm_usb_bus_ops; 264 sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; 265 266 /* Check number of configurations. */ 267 dd = usbd_get_device_descriptor(sc->sc_udev); 268 if (dd->bNumConfigurations != 1) { 269 printf("%s: number of configurations not supported\n", 270 DEVNAME(sc)); 271 return; 272 } 273 274 /* Get endpoints. */ 275 id = usbd_get_interface_descriptor(sc->sc_iface); 276 277 sc->sc_rx_no = sc->sc_tx_no = -1; 278 for (i = 0; i < id->bNumEndpoints; i++) { 279 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 280 if (ed == NULL) { 281 printf("%s: no endpoint descriptor for iface %d\n", 282 DEVNAME(sc), i); 283 return; 284 } 285 286 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 287 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && 288 sc->sc_rx_no == -1) 289 sc->sc_rx_no = ed->bEndpointAddress; 290 else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 291 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && 292 sc->sc_tx_no == -1) 293 sc->sc_tx_no = ed->bEndpointAddress; 294 } 295 if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) { 296 printf("%s: missing endpoint\n", DEVNAME(sc)); 297 return; 298 } 299 300 config_mountroot(self, bwfm_usb_attachhook); 301 } 302 303 void 304 bwfm_usb_attachhook(device_t self) 305 { 306 struct bwfm_usb_softc *sc = device_private(self); 307 struct bwfm_usb_rx_data *data; 308 const char *name = NULL; 309 struct bootrom_id brom; 310 firmware_handle_t fwh; 311 usbd_status error; 312 u_char *ucode; 313 size_t size; 314 int i; 315 316 /* Read chip id and chip rev to check the firmware. */ 317 memset(&brom, 0, sizeof(brom)); 318 bwfm_usb_dl_cmd(sc, DL_GETVER, &brom, sizeof(brom)); 319 sc->sc_chip = le32toh(brom.chip); 320 sc->sc_chiprev = le32toh(brom.chiprev); 321 322 /* Setup data pipes */ 323 error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE, 324 &sc->sc_rx_pipeh); 325 if (error != 0) { 326 printf("%s: could not open rx pipe: %s\n", 327 DEVNAME(sc), usbd_errstr(error)); 328 return; 329 } 330 error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE, 331 &sc->sc_tx_pipeh); 332 if (error != 0) { 333 printf("%s: could not open tx pipe: %s\n", 334 DEVNAME(sc), usbd_errstr(error)); 335 return; 336 } 337 338 /* Firmware not yet loaded? */ 339 if (sc->sc_chip != BRCMF_POSTBOOT_ID) { 340 switch (sc->sc_chip) 341 { 342 case BRCM_CC_43143_CHIP_ID: 343 name = "brcmfmac43143.bin"; 344 break; 345 case BRCM_CC_43235_CHIP_ID: 346 case BRCM_CC_43236_CHIP_ID: 347 case BRCM_CC_43238_CHIP_ID: 348 if (sc->sc_chiprev == 3) 349 name = "brcmfmac43236b.bin"; 350 break; 351 case BRCM_CC_43242_CHIP_ID: 352 name = "brcmfmac43242a.bin"; 353 break; 354 case BRCM_CC_43566_CHIP_ID: 355 case BRCM_CC_43569_CHIP_ID: 356 name = "brcmfmac43569.bin"; 357 break; 358 default: 359 break; 360 } 361 362 if (name == NULL) { 363 printf("%s: unknown firmware\n", DEVNAME(sc)); 364 return; 365 } 366 367 if (firmware_open("if_bwfm", name, &fwh) != 0) { 368 printf("%s: failed firmware_open of file %s\n", 369 DEVNAME(sc), name); 370 return; 371 } 372 size = firmware_get_size(fwh); 373 ucode = firmware_malloc(size); 374 if (ucode == NULL) { 375 printf("%s: failed to allocate firmware memory\n", 376 DEVNAME(sc)); 377 firmware_close(fwh); 378 return; 379 } 380 error = firmware_read(fwh, 0, ucode, size); 381 firmware_close(fwh); 382 if (error != 0) { 383 printf("%s: failed to read firmware (error %d)\n", 384 DEVNAME(sc), error); 385 firmware_free(ucode, size); 386 return; 387 } 388 389 if (bwfm_usb_load_microcode(sc, ucode, size) != 0) { 390 printf("%s: could not load microcode\n", 391 DEVNAME(sc)); 392 return; 393 } 394 395 firmware_free(ucode, size); 396 397 for (i = 0; i < 10; i++) { 398 delay(100 * 1000); 399 memset(&brom, 0, sizeof(brom)); 400 bwfm_usb_dl_cmd(sc, DL_GETVER, &brom, sizeof(brom)); 401 if (le32toh(brom.chip) == BRCMF_POSTBOOT_ID) 402 break; 403 } 404 405 if (le32toh(brom.chip) != BRCMF_POSTBOOT_ID) { 406 printf("%s: firmware did not start up\n", 407 DEVNAME(sc)); 408 return; 409 } 410 411 sc->sc_chip = le32toh(brom.chip); 412 sc->sc_chiprev = le32toh(brom.chiprev); 413 printf("%s: firmware loaded\n", DEVNAME(sc)); 414 } 415 416 bwfm_usb_dl_cmd(sc, DL_RESETCFG, &brom, sizeof(brom)); 417 418 if (bwfm_usb_alloc_rx_list(sc) || bwfm_usb_alloc_tx_list(sc)) { 419 printf("%s: cannot allocate rx/tx lists\n", DEVNAME(sc)); 420 return; 421 } 422 423 bwfm_attach(&sc->sc_sc); 424 425 for (i = 0; i < BWFM_RX_LIST_COUNT; i++) { 426 data = &sc->sc_rx_data[i]; 427 428 usbd_setup_xfer(data->xfer, data, data->buf, 429 BWFM_RXBUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, 430 bwfm_usb_rxeof); 431 error = usbd_transfer(data->xfer); 432 if (error != 0 && error != USBD_IN_PROGRESS) 433 printf("%s: could not set up new transfer: %s\n", 434 DEVNAME(sc), usbd_errstr(error)); 435 } 436 } 437 438 void 439 bwfm_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 440 { 441 struct bwfm_usb_rx_data *data = priv; 442 struct bwfm_usb_softc *sc = data->sc; 443 struct bwfm_proto_bcdc_hdr *hdr; 444 usbd_status error; 445 uint32_t len, off; 446 447 DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__, 448 usbd_errstr(status))); 449 450 if (__predict_false(status != USBD_NORMAL_COMPLETION)) { 451 usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh); 452 if (status != USBD_CANCELLED) 453 goto resubmit; 454 return; 455 } 456 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 457 458 off = 0; 459 hdr = (void *)data->buf; 460 if (len < sizeof(*hdr)) 461 goto resubmit; 462 len -= sizeof(*hdr); 463 off += sizeof(*hdr); 464 if (len < hdr->data_offset << 2) 465 goto resubmit; 466 len -= hdr->data_offset << 2; 467 off += hdr->data_offset << 2; 468 469 mutex_enter(&sc->sc_rx_lock); 470 bwfm_rx(&sc->sc_sc, &data->buf[off], len); 471 mutex_exit(&sc->sc_rx_lock); 472 473 resubmit: 474 usbd_setup_xfer(data->xfer, data, data->buf, 475 BWFM_RXBUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, 476 bwfm_usb_rxeof); 477 error = usbd_transfer(data->xfer); 478 if (error != 0 && error != USBD_IN_PROGRESS) 479 printf("%s: could not set up new transfer: %s\n", 480 DEVNAME(sc), usbd_errstr(error)); 481 } 482 483 int 484 bwfm_usb_alloc_rx_list(struct bwfm_usb_softc *sc) 485 { 486 struct bwfm_usb_rx_data *data; 487 int i, error = 0; 488 489 for (i = 0; i < BWFM_RX_LIST_COUNT; i++) { 490 data = &sc->sc_rx_data[i]; 491 492 data->sc = sc; /* Backpointer for callbacks. */ 493 494 if (usbd_create_xfer(sc->sc_rx_pipeh, BWFM_RXBUFSZ, 495 0, 0, &data->xfer) != 0) { 496 printf("%s: could not create xfer\n", 497 DEVNAME(sc)); 498 error = ENOMEM; 499 break; 500 } 501 data->buf = usbd_get_buffer(data->xfer); 502 } 503 if (error != 0) 504 bwfm_usb_free_rx_list(sc); 505 return (error); 506 } 507 508 void 509 bwfm_usb_free_rx_list(struct bwfm_usb_softc *sc) 510 { 511 int i; 512 513 /* NB: Caller must abort pipe first. */ 514 for (i = 0; i < BWFM_RX_LIST_COUNT; i++) { 515 if (sc->sc_rx_data[i].xfer != NULL) 516 usbd_destroy_xfer(sc->sc_rx_data[i].xfer); 517 sc->sc_rx_data[i].xfer = NULL; 518 } 519 } 520 521 int 522 bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *sc) 523 { 524 struct bwfm_usb_tx_data *data; 525 int i, error = 0; 526 527 TAILQ_INIT(&sc->sc_tx_free_list); 528 for (i = 0; i < BWFM_TX_LIST_COUNT; i++) { 529 data = &sc->sc_tx_data[i]; 530 531 data->sc = sc; /* Backpointer for callbacks. */ 532 533 if (usbd_create_xfer(sc->sc_tx_pipeh, BWFM_TXBUFSZ, 534 USBD_FORCE_SHORT_XFER, 0, &data->xfer) != 0) { 535 printf("%s: could not create xfer\n", 536 DEVNAME(sc)); 537 error = ENOMEM; 538 break; 539 } 540 data->buf = usbd_get_buffer(data->xfer); 541 542 /* Append this Tx buffer to our free list. */ 543 TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next); 544 } 545 if (error != 0) 546 bwfm_usb_free_tx_list(sc); 547 return (error); 548 } 549 550 void 551 bwfm_usb_free_tx_list(struct bwfm_usb_softc *sc) 552 { 553 int i; 554 555 /* NB: Caller must abort pipe first. */ 556 for (i = 0; i < BWFM_TX_LIST_COUNT; i++) { 557 if (sc->sc_tx_data[i].xfer != NULL) 558 usbd_destroy_xfer(sc->sc_tx_data[i].xfer); 559 sc->sc_tx_data[i].xfer = NULL; 560 } 561 } 562 563 void 564 bwfm_usb_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 565 { 566 struct bwfm_usb_tx_data *data = priv; 567 struct bwfm_usb_softc *sc = data->sc; 568 struct ifnet *ifp = sc->sc_sc.sc_ic.ic_ifp; 569 int s; 570 571 DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__, 572 usbd_errstr(status))); 573 574 m_freem(data->mbuf); 575 data->mbuf = NULL; 576 577 mutex_enter(&sc->sc_tx_lock); 578 /* Put this Tx buffer back to our free list. */ 579 TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next); 580 mutex_exit(&sc->sc_tx_lock); 581 582 s = splnet(); 583 584 if (__predict_false(status != USBD_NORMAL_COMPLETION)) { 585 if (status == USBD_CANCELLED) 586 usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh); 587 ifp->if_oerrors++; 588 splx(s); 589 return; 590 } 591 592 ifp->if_opackets++; 593 594 /* We just released a Tx buffer, notify Tx. */ 595 if ((ifp->if_flags & IFF_OACTIVE) != 0) { 596 ifp->if_flags &= ~IFF_OACTIVE; 597 if_schedule_deferred_start(ifp); 598 } 599 splx(s); 600 } 601 602 int 603 bwfm_usb_detach(device_t self, int flags) 604 { 605 struct bwfm_usb_softc *sc = device_private(self); 606 607 bwfm_detach(&sc->sc_sc, flags); 608 609 if (sc->sc_rx_pipeh != NULL) { 610 usbd_abort_pipe(sc->sc_rx_pipeh); 611 usbd_close_pipe(sc->sc_rx_pipeh); 612 } 613 if (sc->sc_tx_pipeh != NULL) { 614 usbd_abort_pipe(sc->sc_tx_pipeh); 615 usbd_close_pipe(sc->sc_tx_pipeh); 616 } 617 618 bwfm_usb_free_rx_list(sc); 619 bwfm_usb_free_tx_list(sc); 620 621 mutex_destroy(&sc->sc_rx_lock); 622 mutex_destroy(&sc->sc_tx_lock); 623 624 return 0; 625 } 626 627 int 628 bwfm_usb_dl_cmd(struct bwfm_usb_softc *sc, uByte cmd, void *buf, int len) 629 { 630 usb_device_request_t req; 631 usbd_status error; 632 633 req.bmRequestType = UT_READ_VENDOR_INTERFACE; 634 req.bRequest = cmd; 635 636 USETW(req.wValue, 0); 637 USETW(req.wIndex, sc->sc_ifaceno); 638 USETW(req.wLength, len); 639 640 error = usbd_do_request(sc->sc_udev, &req, buf); 641 if (error != 0) { 642 printf("%s: could not read register: %s\n", 643 DEVNAME(sc), usbd_errstr(error)); 644 } 645 return error; 646 } 647 648 int 649 bwfm_usb_load_microcode(struct bwfm_usb_softc *sc, const u_char *ucode, size_t size) 650 { 651 const struct trx_header *trx = (const struct trx_header *)ucode; 652 struct rdl_state state; 653 uint32_t rdlstate, rdlbytes, sent = 0, sendlen = 0; 654 struct usbd_xfer *xfer; 655 usbd_status error; 656 char *buf; 657 658 if (le32toh(trx->magic) != TRX_MAGIC || 659 (le32toh(trx->flag_version) & TRX_UNCOMP_IMAGE) == 0) { 660 printf("%s: invalid firmware\n", DEVNAME(sc)); 661 return 1; 662 } 663 664 bwfm_usb_dl_cmd(sc, DL_START, &state, sizeof(state)); 665 rdlstate = le32toh(state.state); 666 rdlbytes = le32toh(state.bytes); 667 668 if (rdlstate != DL_WAITING) { 669 printf("%s: cannot start fw download\n", DEVNAME(sc)); 670 return 1; 671 } 672 673 error = usbd_create_xfer(sc->sc_tx_pipeh, TRX_RDL_CHUNK, 674 0, 0, &xfer); 675 if (error != 0) { 676 printf("%s: cannot create xfer\n", DEVNAME(sc)); 677 goto err; 678 } 679 680 buf = usbd_get_buffer(xfer); 681 682 while (rdlbytes != size) { 683 sendlen = MIN(size - sent, TRX_RDL_CHUNK); 684 memcpy(buf, ucode + sent, sendlen); 685 686 usbd_setup_xfer(xfer, NULL, buf, sendlen, 687 USBD_SYNCHRONOUS, USBD_NO_TIMEOUT, NULL); 688 error = usbd_transfer(xfer); 689 if (error != 0 && error != USBD_IN_PROGRESS) { 690 printf("%s: transfer error\n", DEVNAME(sc)); 691 goto err; 692 } 693 sent += sendlen; 694 695 bwfm_usb_dl_cmd(sc, DL_GETSTATE, &state, sizeof(state)); 696 rdlstate = le32toh(state.state); 697 rdlbytes = le32toh(state.bytes); 698 699 if (rdlbytes != sent) { 700 printf("%s: device reported different size\n", 701 DEVNAME(sc)); 702 goto err; 703 } 704 705 if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) { 706 printf("%s: device reported bad hdr/crc\n", 707 DEVNAME(sc)); 708 goto err; 709 } 710 } 711 712 bwfm_usb_dl_cmd(sc, DL_GETSTATE, &state, sizeof(state)); 713 rdlstate = le32toh(state.state); 714 rdlbytes = le32toh(state.bytes); 715 716 if (rdlstate != DL_RUNNABLE) { 717 printf("%s: dongle not runnable\n", DEVNAME(sc)); 718 goto err; 719 } 720 721 bwfm_usb_dl_cmd(sc, DL_GO, &state, sizeof(state)); 722 723 usbd_destroy_xfer(xfer); 724 725 return 0; 726 err: 727 if (sc->sc_tx_pipeh != NULL) { 728 usbd_abort_pipe(sc->sc_tx_pipeh); 729 usbd_close_pipe(sc->sc_tx_pipeh); 730 sc->sc_tx_pipeh = NULL; 731 } 732 if (xfer != NULL) 733 usbd_destroy_xfer(xfer); 734 return 1; 735 } 736 737 int 738 bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 739 { 740 struct bwfm_usb_softc *sc = (void *)bwfm; 741 struct bwfm_proto_bcdc_hdr *hdr; 742 struct bwfm_usb_tx_data *data; 743 struct ether_header *eh; 744 uint32_t len = 0; 745 int error, ac; 746 747 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 748 749 mutex_enter(&sc->sc_tx_lock); 750 751 if (TAILQ_EMPTY(&sc->sc_tx_free_list)) { 752 mutex_exit(&sc->sc_tx_lock); 753 return ENOBUFS; 754 } 755 756 /* No QoS for EAPOL frames. */ 757 eh = mtod(m, struct ether_header *); 758 ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ? 759 M_WME_GETAC(m) : WME_AC_BE; 760 761 /* Grab a Tx buffer from our free list. */ 762 data = TAILQ_FIRST(&sc->sc_tx_free_list); 763 TAILQ_REMOVE(&sc->sc_tx_free_list, data, next); 764 765 mutex_exit(&sc->sc_tx_lock); 766 767 hdr = (void *)&data->buf[len]; 768 hdr->data_offset = 0; 769 hdr->priority = ac; 770 hdr->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER); 771 hdr->flags2 = 0; 772 len += sizeof(*hdr); 773 774 m_copydata(m, 0, m->m_pkthdr.len, &data->buf[len]); 775 len += m->m_pkthdr.len; 776 777 data->mbuf = m; 778 779 usbd_setup_xfer(data->xfer, data, data->buf, 780 len, USBD_FORCE_SHORT_XFER, USBD_NO_TIMEOUT, 781 bwfm_usb_txeof); 782 error = usbd_transfer(data->xfer); 783 if (error != 0 && error != USBD_IN_PROGRESS) 784 printf("%s: could not set up new transfer: %s\n", 785 DEVNAME(sc), usbd_errstr(error)); 786 return 0; 787 } 788 789 int 790 bwfm_usb_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) 791 { 792 struct bwfm_usb_softc *sc = (void *)bwfm; 793 usb_device_request_t req; 794 usbd_status error; 795 int ret = 1; 796 797 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 798 799 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 800 req.bRequest = 0; 801 802 USETW(req.wValue, 0); 803 USETW(req.wIndex, sc->sc_ifaceno); 804 USETW(req.wLength, len); 805 806 error = usbd_do_request(sc->sc_udev, &req, buf); 807 if (error != 0) { 808 printf("%s: could not read ctl packet: %s\n", 809 DEVNAME(sc), usbd_errstr(error)); 810 goto err; 811 } 812 813 ret = 0; 814 err: 815 return ret; 816 } 817 818 int 819 bwfm_usb_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *len) 820 { 821 struct bwfm_usb_softc *sc = (void *)bwfm; 822 usb_device_request_t req; 823 usbd_status error; 824 uint32_t len32; 825 int ret = 1; 826 827 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 828 829 req.bmRequestType = UT_READ_CLASS_INTERFACE; 830 req.bRequest = 1; 831 832 USETW(req.wValue, 0); 833 USETW(req.wIndex, sc->sc_ifaceno); 834 USETW(req.wLength, *len); 835 836 error = usbd_do_request_flags(sc->sc_udev, &req, buf, 0, 837 &len32, USBD_DEFAULT_TIMEOUT); 838 if (error != 0) { 839 printf("%s: could not read ctl packet: %s\n", 840 DEVNAME(sc), usbd_errstr(error)); 841 goto err; 842 } 843 844 if (len32 > *len) { 845 printf("%s: broken length\n", DEVNAME(sc)); 846 goto err; 847 } 848 849 *len = len32; 850 ret = 0; 851 err: 852 return ret; 853 } 854