xref: /openbsd-src/sys/dev/usb/if_bwfm_usb.c (revision aa997e528a848ca5596493c2a801bdd6fb26ae61)
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