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