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