1 /* $OpenBSD: if_bwfm_usb.c,v 1.11 2018/02/11 05:13:07 patrick Exp $ */ 2 /* 3 * Copyright (c) 2010-2016 Broadcom Corporation 4 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "bpfilter.h" 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/buf.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/device.h> 27 #include <sys/queue.h> 28 #include <sys/socket.h> 29 30 #if NBPFILTER > 0 31 #include <net/bpf.h> 32 #endif 33 #include <net/if.h> 34 #include <net/if_dl.h> 35 #include <net/if_media.h> 36 37 #include <netinet/in.h> 38 #include <netinet/if_ether.h> 39 40 #include <net80211/ieee80211_var.h> 41 42 #include <machine/bus.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) ((sc)->sc_sc.sc_dev.dv_xname) 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 185 int bwfm_usb_match(struct device *, void *, void *); 186 void bwfm_usb_attachhook(struct device *); 187 void bwfm_usb_attach(struct device *, struct device *, void *); 188 int bwfm_usb_detach(struct device *, int); 189 190 int bwfm_usb_dl_cmd(struct bwfm_usb_softc *, uint8_t, void *, int); 191 int bwfm_usb_load_microcode(struct bwfm_usb_softc *, const u_char *, 192 size_t); 193 194 int bwfm_usb_alloc_rx_list(struct bwfm_usb_softc *); 195 void bwfm_usb_free_rx_list(struct bwfm_usb_softc *); 196 int bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *); 197 void bwfm_usb_free_tx_list(struct bwfm_usb_softc *); 198 199 int bwfm_usb_txcheck(struct bwfm_softc *); 200 int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *); 201 int bwfm_usb_txctl(struct bwfm_softc *, char *, size_t); 202 int bwfm_usb_rxctl(struct bwfm_softc *, char *, size_t *); 203 204 struct mbuf * bwfm_usb_newbuf(void); 205 void bwfm_usb_rxeof(struct usbd_xfer *, void *, usbd_status); 206 void bwfm_usb_txeof(struct usbd_xfer *, void *, usbd_status); 207 208 struct bwfm_bus_ops bwfm_usb_bus_ops = { 209 .bs_init = NULL, 210 .bs_stop = NULL, 211 .bs_txcheck = bwfm_usb_txcheck, 212 .bs_txdata = bwfm_usb_txdata, 213 .bs_txctl = bwfm_usb_txctl, 214 .bs_rxctl = bwfm_usb_rxctl, 215 }; 216 217 struct cfattach bwfm_usb_ca = { 218 sizeof(struct bwfm_usb_softc), 219 bwfm_usb_match, 220 bwfm_usb_attach, 221 bwfm_usb_detach, 222 }; 223 224 int 225 bwfm_usb_match(struct device *parent, void *match, void *aux) 226 { 227 struct usb_attach_arg *uaa = aux; 228 229 if (uaa->iface == NULL || uaa->configno != 1) 230 return UMATCH_NONE; 231 232 return (usb_lookup(bwfm_usbdevs, uaa->vendor, uaa->product) != NULL) ? 233 UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE; 234 } 235 236 void 237 bwfm_usb_attach(struct device *parent, struct device *self, void *aux) 238 { 239 struct bwfm_usb_softc *sc = (struct bwfm_usb_softc *)self; 240 struct usb_attach_arg *uaa = aux; 241 usb_device_descriptor_t *dd; 242 usb_interface_descriptor_t *id; 243 usb_endpoint_descriptor_t *ed; 244 int i; 245 246 sc->sc_udev = uaa->device; 247 sc->sc_iface = uaa->iface; 248 sc->sc_ifaceno = uaa->ifaceno; 249 sc->sc_vendor = uaa->vendor; 250 sc->sc_product = uaa->product; 251 sc->sc_sc.sc_bus_ops = &bwfm_usb_bus_ops; 252 sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops; 253 254 /* Check number of configurations. */ 255 dd = usbd_get_device_descriptor(sc->sc_udev); 256 if (dd->bNumConfigurations != 1) { 257 printf("%s: number of configurations not supported\n", 258 DEVNAME(sc)); 259 return; 260 } 261 262 /* Get endpoints. */ 263 id = usbd_get_interface_descriptor(sc->sc_iface); 264 265 sc->sc_rx_no = sc->sc_tx_no = -1; 266 for (i = 0; i < id->bNumEndpoints; i++) { 267 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 268 if (ed == NULL) { 269 printf("%s: no endpoint descriptor for iface %d\n", 270 DEVNAME(sc), i); 271 return; 272 } 273 274 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 275 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && 276 sc->sc_rx_no == -1) 277 sc->sc_rx_no = ed->bEndpointAddress; 278 else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 279 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK && 280 sc->sc_tx_no == -1) 281 sc->sc_tx_no = ed->bEndpointAddress; 282 } 283 if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) { 284 printf("%s: missing endpoint\n", DEVNAME(sc)); 285 return; 286 } 287 288 config_mountroot(self, bwfm_usb_attachhook); 289 } 290 291 void 292 bwfm_usb_attachhook(struct device *self) 293 { 294 struct bwfm_usb_softc *sc = (struct bwfm_usb_softc *)self; 295 struct bwfm_usb_rx_data *data; 296 const char *name = NULL; 297 struct bootrom_id brom; 298 usbd_status error; 299 u_char *ucode; 300 size_t size; 301 int i; 302 303 /* Read chip id and chip rev to check the firmware. */ 304 memset(&brom, 0, sizeof(brom)); 305 bwfm_usb_dl_cmd(sc, DL_GETVER, &brom, sizeof(brom)); 306 sc->sc_chip = letoh32(brom.chip); 307 sc->sc_chiprev = letoh32(brom.chiprev); 308 309 /* Setup data pipes */ 310 error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE, 311 &sc->sc_rx_pipeh); 312 if (error != 0) { 313 printf("%s: could not open rx pipe: %s\n", 314 DEVNAME(sc), usbd_errstr(error)); 315 return; 316 } 317 error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE, 318 &sc->sc_tx_pipeh); 319 if (error != 0) { 320 printf("%s: could not open tx pipe: %s\n", 321 DEVNAME(sc), usbd_errstr(error)); 322 return; 323 } 324 325 /* Firmware not yet loaded? */ 326 if (sc->sc_chip != BRCMF_POSTBOOT_ID) { 327 switch (sc->sc_chip) 328 { 329 case BRCM_CC_43143_CHIP_ID: 330 name = "brcmfmac43143.bin"; 331 break; 332 case BRCM_CC_43235_CHIP_ID: 333 case BRCM_CC_43236_CHIP_ID: 334 case BRCM_CC_43238_CHIP_ID: 335 if (sc->sc_chiprev == 3) 336 name = "brcmfmac43236b.bin"; 337 break; 338 case BRCM_CC_43242_CHIP_ID: 339 name = "brcmfmac43242a.bin"; 340 break; 341 case BRCM_CC_43566_CHIP_ID: 342 case BRCM_CC_43569_CHIP_ID: 343 name = "brcmfmac43569.bin"; 344 break; 345 default: 346 break; 347 } 348 349 if (name == NULL) { 350 printf("%s: unknown firmware\n", DEVNAME(sc)); 351 return; 352 } 353 354 if (loadfirmware(name, &ucode, &size) != 0) { 355 printf("%s: failed loadfirmware of file %s\n", 356 DEVNAME(sc), name); 357 return; 358 } 359 360 if (bwfm_usb_load_microcode(sc, ucode, size) != 0) { 361 printf("%s: could not load microcode\n", 362 DEVNAME(sc)); 363 free(ucode, M_DEVBUF, size); 364 return; 365 } 366 367 free(ucode, M_DEVBUF, size); 368 369 for (i = 0; i < 10; i++) { 370 delay(100 * 1000); 371 memset(&brom, 0, sizeof(brom)); 372 bwfm_usb_dl_cmd(sc, DL_GETVER, &brom, sizeof(brom)); 373 if (letoh32(brom.chip) == BRCMF_POSTBOOT_ID) 374 break; 375 } 376 377 if (letoh32(brom.chip) != BRCMF_POSTBOOT_ID) { 378 printf("%s: firmware did not start up\n", 379 DEVNAME(sc)); 380 return; 381 } 382 383 sc->sc_chip = letoh32(brom.chip); 384 sc->sc_chiprev = letoh32(brom.chiprev); 385 } 386 387 bwfm_usb_dl_cmd(sc, DL_RESETCFG, &brom, sizeof(brom)); 388 389 if (bwfm_usb_alloc_rx_list(sc) || bwfm_usb_alloc_tx_list(sc)) { 390 printf("%s: cannot allocate rx/tx lists\n", DEVNAME(sc)); 391 return; 392 } 393 394 for (i = 0; i < BWFM_RX_LIST_COUNT; i++) { 395 data = &sc->sc_rx_data[i]; 396 397 usbd_setup_xfer(data->xfer, sc->sc_rx_pipeh, data, data->buf, 398 BWFM_RXBUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, 399 bwfm_usb_rxeof); 400 error = usbd_transfer(data->xfer); 401 if (error != 0 && error != USBD_IN_PROGRESS) 402 printf("%s: could not set up new transfer: %s\n", 403 DEVNAME(sc), usbd_errstr(error)); 404 } 405 406 bwfm_attach(&sc->sc_sc); 407 } 408 409 struct mbuf * 410 bwfm_usb_newbuf(void) 411 { 412 struct mbuf *m; 413 414 MGETHDR(m, M_DONTWAIT, MT_DATA); 415 if (m == NULL) 416 return (NULL); 417 418 MCLGET(m, M_DONTWAIT); 419 if (!(m->m_flags & M_EXT)) { 420 m_freem(m); 421 return (NULL); 422 } 423 424 m->m_len = m->m_pkthdr.len = MCLBYTES; 425 426 return (m); 427 } 428 429 void 430 bwfm_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 431 { 432 struct bwfm_usb_rx_data *data = priv; 433 struct bwfm_usb_softc *sc = data->sc; 434 usbd_status error; 435 struct mbuf *m; 436 uint32_t len; 437 438 DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__, 439 usbd_errstr(status))); 440 441 if (usbd_is_dying(sc->sc_udev)) 442 return; 443 444 if (__predict_false(status != USBD_NORMAL_COMPLETION)) { 445 usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh); 446 if (status != USBD_CANCELLED) 447 goto resubmit; 448 return; 449 } 450 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 451 452 m = bwfm_usb_newbuf(); 453 if (m == NULL) 454 goto resubmit; 455 456 memcpy(mtod(m, char *), data->buf, len); 457 m->m_len = m->m_pkthdr.len = len; 458 sc->sc_sc.sc_proto_ops->proto_rx(&sc->sc_sc, m); 459 460 resubmit: 461 usbd_setup_xfer(data->xfer, sc->sc_rx_pipeh, data, data->buf, 462 BWFM_RXBUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, 463 bwfm_usb_rxeof); 464 error = usbd_transfer(data->xfer); 465 if (error != 0 && error != USBD_IN_PROGRESS) 466 printf("%s: could not set up new transfer: %s\n", 467 DEVNAME(sc), usbd_errstr(error)); 468 } 469 470 int 471 bwfm_usb_alloc_rx_list(struct bwfm_usb_softc *sc) 472 { 473 struct bwfm_usb_rx_data *data; 474 int i, error = 0; 475 476 for (i = 0; i < BWFM_RX_LIST_COUNT; i++) { 477 data = &sc->sc_rx_data[i]; 478 479 data->sc = sc; /* Backpointer for callbacks. */ 480 481 data->xfer = usbd_alloc_xfer(sc->sc_udev); 482 if (data->xfer == NULL) { 483 printf("%s: could not allocate xfer\n", 484 DEVNAME(sc)); 485 error = ENOMEM; 486 break; 487 } 488 data->buf = usbd_alloc_buffer(data->xfer, BWFM_RXBUFSZ); 489 if (data->buf == NULL) { 490 printf("%s: could not allocate xfer buffer\n", 491 DEVNAME(sc)); 492 error = ENOMEM; 493 break; 494 } 495 } 496 if (error != 0) 497 bwfm_usb_free_rx_list(sc); 498 return (error); 499 } 500 501 void 502 bwfm_usb_free_rx_list(struct bwfm_usb_softc *sc) 503 { 504 int i; 505 506 /* NB: Caller must abort pipe first. */ 507 for (i = 0; i < BWFM_RX_LIST_COUNT; i++) { 508 if (sc->sc_rx_data[i].xfer != NULL) 509 usbd_free_xfer(sc->sc_rx_data[i].xfer); 510 sc->sc_rx_data[i].xfer = NULL; 511 } 512 } 513 514 int 515 bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *sc) 516 { 517 struct bwfm_usb_tx_data *data; 518 int i, error = 0; 519 520 TAILQ_INIT(&sc->sc_tx_free_list); 521 for (i = 0; i < BWFM_TX_LIST_COUNT; i++) { 522 data = &sc->sc_tx_data[i]; 523 524 data->sc = sc; /* Backpointer for callbacks. */ 525 526 data->xfer = usbd_alloc_xfer(sc->sc_udev); 527 if (data->xfer == NULL) { 528 printf("%s: could not allocate xfer\n", 529 DEVNAME(sc)); 530 error = ENOMEM; 531 break; 532 } 533 data->buf = usbd_alloc_buffer(data->xfer, BWFM_TXBUFSZ); 534 if (data->buf == NULL) { 535 printf("%s: could not allocate xfer buffer\n", 536 DEVNAME(sc)); 537 error = ENOMEM; 538 break; 539 } 540 /* Append this Tx buffer to our free list. */ 541 TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next); 542 } 543 if (error != 0) 544 bwfm_usb_free_tx_list(sc); 545 return (error); 546 } 547 548 void 549 bwfm_usb_free_tx_list(struct bwfm_usb_softc *sc) 550 { 551 int i; 552 553 /* NB: Caller must abort pipe first. */ 554 for (i = 0; i < BWFM_TX_LIST_COUNT; i++) { 555 if (sc->sc_tx_data[i].xfer != NULL) 556 usbd_free_xfer(sc->sc_tx_data[i].xfer); 557 sc->sc_tx_data[i].xfer = NULL; 558 } 559 } 560 561 void 562 bwfm_usb_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 563 { 564 struct bwfm_usb_tx_data *data = priv; 565 struct bwfm_usb_softc *sc = data->sc; 566 struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; 567 int s; 568 569 DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__, 570 usbd_errstr(status))); 571 572 if (usbd_is_dying(sc->sc_udev)) 573 return; 574 575 s = splnet(); 576 /* Put this Tx buffer back to our free list. */ 577 TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next); 578 579 if (__predict_false(status != USBD_NORMAL_COMPLETION)) { 580 if (status == USBD_CANCELLED) 581 usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh); 582 ifp->if_oerrors++; 583 splx(s); 584 return; 585 } 586 587 m_freem(data->mbuf); 588 data->mbuf = NULL; 589 590 /* We just released a Tx buffer, notify Tx. */ 591 if (ifq_is_oactive(&ifp->if_snd)) { 592 ifq_restart(&ifp->if_snd); 593 } 594 splx(s); 595 } 596 597 int 598 bwfm_usb_detach(struct device *self, int flags) 599 { 600 struct bwfm_usb_softc *sc = (struct bwfm_usb_softc *)self; 601 602 bwfm_detach(&sc->sc_sc, flags); 603 604 if (sc->sc_rx_pipeh != NULL) { 605 usbd_abort_pipe(sc->sc_rx_pipeh); 606 usbd_close_pipe(sc->sc_rx_pipeh); 607 } 608 if (sc->sc_tx_pipeh != NULL) { 609 usbd_abort_pipe(sc->sc_tx_pipeh); 610 usbd_close_pipe(sc->sc_tx_pipeh); 611 } 612 613 bwfm_usb_free_rx_list(sc); 614 bwfm_usb_free_tx_list(sc); 615 616 return 0; 617 } 618 619 int 620 bwfm_usb_dl_cmd(struct bwfm_usb_softc *sc, uByte cmd, void *buf, int len) 621 { 622 usb_device_request_t req; 623 usbd_status error; 624 625 req.bmRequestType = UT_READ_VENDOR_INTERFACE; 626 req.bRequest = cmd; 627 628 USETW(req.wValue, 0); 629 USETW(req.wIndex, sc->sc_ifaceno); 630 USETW(req.wLength, len); 631 632 error = usbd_do_request(sc->sc_udev, &req, buf); 633 if (error != 0) { 634 printf("%s: could not read register: %s\n", 635 DEVNAME(sc), usbd_errstr(error)); 636 } 637 return error; 638 } 639 640 int 641 bwfm_usb_load_microcode(struct bwfm_usb_softc *sc, const u_char *ucode, size_t size) 642 { 643 struct trx_header *trx = (struct trx_header *)ucode; 644 struct rdl_state state; 645 uint32_t rdlstate, rdlbytes, sent = 0, sendlen = 0; 646 struct usbd_xfer *xfer; 647 usbd_status error; 648 char *buf; 649 650 if (letoh32(trx->magic) != TRX_MAGIC || 651 (letoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) == 0) { 652 printf("%s: invalid firmware\n", DEVNAME(sc)); 653 return 1; 654 } 655 656 bwfm_usb_dl_cmd(sc, DL_START, &state, sizeof(state)); 657 rdlstate = letoh32(state.state); 658 rdlbytes = letoh32(state.bytes); 659 660 if (rdlstate != DL_WAITING) { 661 printf("%s: cannot start fw download\n", DEVNAME(sc)); 662 return 1; 663 } 664 665 xfer = usbd_alloc_xfer(sc->sc_udev); 666 if (xfer == NULL) { 667 printf("%s: cannot alloc xfer\n", DEVNAME(sc)); 668 goto err; 669 } 670 671 buf = usbd_alloc_buffer(xfer, TRX_RDL_CHUNK); 672 if (buf == NULL) { 673 printf("%s: cannot alloc buf\n", DEVNAME(sc)); 674 goto err; 675 } 676 677 while (rdlbytes != size) { 678 sendlen = MIN(size - sent, TRX_RDL_CHUNK); 679 memcpy(buf, ucode + sent, sendlen); 680 681 usbd_setup_xfer(xfer, sc->sc_tx_pipeh, NULL, buf, sendlen, 682 USBD_SYNCHRONOUS | USBD_NO_COPY, USBD_NO_TIMEOUT, NULL); 683 error = usbd_transfer(xfer); 684 if (error != 0 && error != USBD_IN_PROGRESS) { 685 printf("%s: transfer error\n", DEVNAME(sc)); 686 goto err; 687 } 688 sent += sendlen; 689 690 bwfm_usb_dl_cmd(sc, DL_GETSTATE, &state, sizeof(state)); 691 rdlstate = letoh32(state.state); 692 rdlbytes = letoh32(state.bytes); 693 694 if (rdlbytes != sent) { 695 printf("%s: device reported different size\n", 696 DEVNAME(sc)); 697 goto err; 698 } 699 700 if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) { 701 printf("%s: device reported bad hdr/crc\n", 702 DEVNAME(sc)); 703 goto err; 704 } 705 } 706 707 bwfm_usb_dl_cmd(sc, DL_GETSTATE, &state, sizeof(state)); 708 rdlstate = letoh32(state.state); 709 rdlbytes = letoh32(state.bytes); 710 711 if (rdlstate != DL_RUNNABLE) { 712 printf("%s: dongle not runnable\n", DEVNAME(sc)); 713 goto err; 714 } 715 716 bwfm_usb_dl_cmd(sc, DL_GO, &state, sizeof(state)); 717 718 return 0; 719 err: 720 if (sc->sc_tx_pipeh != NULL) { 721 usbd_abort_pipe(sc->sc_tx_pipeh); 722 usbd_close_pipe(sc->sc_tx_pipeh); 723 sc->sc_tx_pipeh = NULL; 724 } 725 if (xfer != NULL) 726 usbd_free_xfer(xfer); 727 return 1; 728 } 729 730 int 731 bwfm_usb_txcheck(struct bwfm_softc *bwfm) 732 { 733 struct bwfm_usb_softc *sc = (void *)bwfm; 734 735 if (TAILQ_EMPTY(&sc->sc_tx_free_list)) 736 return ENOBUFS; 737 738 return 0; 739 } 740 741 int 742 bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf *m) 743 { 744 struct bwfm_usb_softc *sc = (void *)bwfm; 745 struct bwfm_proto_bcdc_hdr *hdr; 746 struct bwfm_usb_tx_data *data; 747 uint32_t len = 0; 748 int error; 749 750 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 751 752 if (TAILQ_EMPTY(&sc->sc_tx_free_list)) 753 return ENOBUFS; 754 755 /* Grab a Tx buffer from our free list. */ 756 data = TAILQ_FIRST(&sc->sc_tx_free_list); 757 TAILQ_REMOVE(&sc->sc_tx_free_list, data, next); 758 759 hdr = (void *)&data->buf[len]; 760 hdr->data_offset = 0; 761 hdr->priority = ieee80211_classify(&sc->sc_sc.sc_ic, m); 762 hdr->flags = BWFM_BCDC_FLAG_VER(BWFM_BCDC_FLAG_PROTO_VER); 763 hdr->flags2 = 0; 764 len += sizeof(*hdr); 765 766 m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&data->buf[len]); 767 len += m->m_pkthdr.len; 768 769 data->mbuf = m; 770 771 usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, 772 len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, USBD_NO_TIMEOUT, 773 bwfm_usb_txeof); 774 error = usbd_transfer(data->xfer); 775 if (error != 0 && error != USBD_IN_PROGRESS) 776 printf("%s: could not set up new transfer: %s\n", 777 DEVNAME(sc), usbd_errstr(error)); 778 return 0; 779 } 780 781 int 782 bwfm_usb_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) 783 { 784 struct bwfm_usb_softc *sc = (void *)bwfm; 785 usb_device_request_t req; 786 usbd_status error; 787 int ret = 1; 788 789 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 790 791 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 792 req.bRequest = 0; 793 794 USETW(req.wValue, 0); 795 USETW(req.wIndex, sc->sc_ifaceno); 796 USETW(req.wLength, len); 797 798 error = usbd_do_request(sc->sc_udev, &req, buf); 799 if (error != 0) { 800 printf("%s: could not read ctl packet: %s\n", 801 DEVNAME(sc), usbd_errstr(error)); 802 goto err; 803 } 804 805 ret = 0; 806 err: 807 return ret; 808 } 809 810 int 811 bwfm_usb_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *len) 812 { 813 struct bwfm_usb_softc *sc = (void *)bwfm; 814 usb_device_request_t req; 815 usbd_status error; 816 uint32_t len32; 817 int ret = 1; 818 819 DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); 820 821 req.bmRequestType = UT_READ_CLASS_INTERFACE; 822 req.bRequest = 1; 823 824 USETW(req.wValue, 0); 825 USETW(req.wIndex, sc->sc_ifaceno); 826 USETW(req.wLength, *len); 827 828 error = usbd_do_request_flags(sc->sc_udev, &req, buf, 0, 829 &len32, USBD_DEFAULT_TIMEOUT); 830 if (error != 0) { 831 printf("%s: could not read ctl packet: %s\n", 832 DEVNAME(sc), usbd_errstr(error)); 833 goto err; 834 } 835 836 if (len32 > *len) { 837 printf("%s: broken length\n", DEVNAME(sc)); 838 goto err; 839 } 840 841 *len = len32; 842 ret = 0; 843 err: 844 return ret; 845 } 846