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