xref: /netbsd-src/sys/dev/usb/if_bwfm_usb.c (revision c38e7cc395b1472a774ff828e46123de44c628e9)
1 /* $NetBSD: if_bwfm_usb.c,v 1.4 2018/01/21 13:57:11 skrll 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/param.h>
21 #include <sys/systm.h>
22 #include <sys/buf.h>
23 #include <sys/kernel.h>
24 #include <sys/malloc.h>
25 #include <sys/device.h>
26 #include <sys/queue.h>
27 #include <sys/socket.h>
28 #include <sys/mutex.h>
29 #include <sys/workqueue.h>
30 #include <sys/pcq.h>
31 
32 #include <net/bpf.h>
33 #include <net/if.h>
34 #include <net/if_dl.h>
35 #include <net/if_media.h>
36 #include <net/if_ether.h>
37 
38 #include <netinet/in.h>
39 
40 #include <net80211/ieee80211_var.h>
41 
42 #include <dev/firmload.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)	device_xname((sc)->sc_sc.sc_dev)
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 	kmutex_t		 sc_rx_lock;
185 	kmutex_t		 sc_tx_lock;
186 };
187 
188 int		 bwfm_usb_match(device_t, cfdata_t, void *);
189 void		 bwfm_usb_attachhook(device_t);
190 void		 bwfm_usb_attach(device_t, device_t, void *);
191 int		 bwfm_usb_detach(device_t, int);
192 
193 int		 bwfm_usb_dl_cmd(struct bwfm_usb_softc *, uint8_t, void *, int);
194 int		 bwfm_usb_load_microcode(struct bwfm_usb_softc *, const u_char *,
195 		     size_t);
196 
197 int		 bwfm_usb_alloc_rx_list(struct bwfm_usb_softc *);
198 void		 bwfm_usb_free_rx_list(struct bwfm_usb_softc *);
199 int		 bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *);
200 void		 bwfm_usb_free_tx_list(struct bwfm_usb_softc *);
201 
202 int		 bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *);
203 int		 bwfm_usb_txctl(struct bwfm_softc *, char *, size_t);
204 int		 bwfm_usb_rxctl(struct bwfm_softc *, char *, size_t *);
205 
206 void		 bwfm_usb_rxeof(struct usbd_xfer *, void *, usbd_status);
207 void		 bwfm_usb_txeof(struct usbd_xfer *, void *, usbd_status);
208 
209 struct bwfm_bus_ops bwfm_usb_bus_ops = {
210 	.bs_init = NULL,
211 	.bs_stop = NULL,
212 	.bs_txdata = bwfm_usb_txdata,
213 	.bs_txctl = bwfm_usb_txctl,
214 	.bs_rxctl = bwfm_usb_rxctl,
215 };
216 
217 CFATTACH_DECL_NEW(bwfm_usb, sizeof(struct bwfm_usb_softc),
218     bwfm_usb_match, bwfm_usb_attach, bwfm_usb_detach, NULL);
219 
220 int
221 bwfm_usb_match(device_t parent, cfdata_t match, void *aux)
222 {
223 	struct usb_attach_arg *uaa = aux;
224 
225 	return (usb_lookup(bwfm_usbdevs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ?
226 	    UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE;
227 }
228 
229 void
230 bwfm_usb_attach(device_t parent, device_t self, void *aux)
231 {
232 	struct bwfm_usb_softc *sc = device_private(self);
233 	struct usb_attach_arg *uaa = aux;
234 	usb_device_descriptor_t *dd;
235 	usb_interface_descriptor_t *id;
236 	usb_endpoint_descriptor_t *ed;
237 	char *devinfop;
238 	int i;
239 
240 	sc->sc_sc.sc_dev = self;
241 	sc->sc_udev = uaa->uaa_device;
242 	mutex_init(&sc->sc_rx_lock, MUTEX_DEFAULT, IPL_NET);
243 	mutex_init(&sc->sc_tx_lock, MUTEX_DEFAULT, IPL_NET);
244 
245 	aprint_naive("\n");
246 
247 	devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
248 	aprint_normal(": %s\n", devinfop);
249 	usbd_devinfo_free(devinfop);
250 
251 	if (usbd_set_config_no(sc->sc_udev, 1, 1) != 0) {
252 		aprint_error_dev(self, "failed to set configuration\n");
253 		return;
254 	}
255 	if (usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface) != 0) {
256 		aprint_error_dev(self, "failed to get interface handle\n");
257 		return;
258 	}
259 
260 	sc->sc_ifaceno = 0;
261 	sc->sc_vendor = uaa->uaa_vendor;
262 	sc->sc_product = uaa->uaa_product;
263 	sc->sc_sc.sc_bus_ops = &bwfm_usb_bus_ops;
264 	sc->sc_sc.sc_proto_ops = &bwfm_proto_bcdc_ops;
265 
266 	/* Check number of configurations. */
267 	dd = usbd_get_device_descriptor(sc->sc_udev);
268 	if (dd->bNumConfigurations != 1) {
269 		printf("%s: number of configurations not supported\n",
270 		    DEVNAME(sc));
271 		return;
272 	}
273 
274 	/* Get endpoints. */
275 	id = usbd_get_interface_descriptor(sc->sc_iface);
276 
277 	sc->sc_rx_no = sc->sc_tx_no = -1;
278 	for (i = 0; i < id->bNumEndpoints; i++) {
279 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
280 		if (ed == NULL) {
281 			printf("%s: no endpoint descriptor for iface %d\n",
282 			    DEVNAME(sc), i);
283 			return;
284 		}
285 
286 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
287 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
288 		    sc->sc_rx_no == -1)
289 			sc->sc_rx_no = ed->bEndpointAddress;
290 		else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
291 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
292 		    sc->sc_tx_no == -1)
293 			sc->sc_tx_no = ed->bEndpointAddress;
294 	}
295 	if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) {
296 		printf("%s: missing endpoint\n", DEVNAME(sc));
297 		return;
298 	}
299 
300 	config_mountroot(self, bwfm_usb_attachhook);
301 }
302 
303 void
304 bwfm_usb_attachhook(device_t self)
305 {
306 	struct bwfm_usb_softc *sc = device_private(self);
307 	struct bwfm_usb_rx_data *data;
308 	const char *name = NULL;
309 	struct bootrom_id brom;
310 	firmware_handle_t fwh;
311 	usbd_status error;
312 	u_char *ucode;
313 	size_t size;
314 	int i;
315 
316 	/* Read chip id and chip rev to check the firmware. */
317 	memset(&brom, 0, sizeof(brom));
318 	bwfm_usb_dl_cmd(sc, DL_GETVER, &brom, sizeof(brom));
319 	sc->sc_chip = le32toh(brom.chip);
320 	sc->sc_chiprev = le32toh(brom.chiprev);
321 
322 	/* Setup data pipes */
323 	error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE,
324 	    &sc->sc_rx_pipeh);
325 	if (error != 0) {
326 		printf("%s: could not open rx pipe: %s\n",
327 		    DEVNAME(sc), usbd_errstr(error));
328 		return;
329 	}
330 	error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE,
331 	    &sc->sc_tx_pipeh);
332 	if (error != 0) {
333 		printf("%s: could not open tx pipe: %s\n",
334 		    DEVNAME(sc), usbd_errstr(error));
335 		return;
336 	}
337 
338 	/* Firmware not yet loaded? */
339 	if (sc->sc_chip != BRCMF_POSTBOOT_ID) {
340 		switch (sc->sc_chip)
341 		{
342 		case BRCM_CC_43143_CHIP_ID:
343 			name = "brcmfmac43143.bin";
344 			break;
345 		case BRCM_CC_43235_CHIP_ID:
346 		case BRCM_CC_43236_CHIP_ID:
347 		case BRCM_CC_43238_CHIP_ID:
348 			if (sc->sc_chiprev == 3)
349 				name = "brcmfmac43236b.bin";
350 			break;
351 		case BRCM_CC_43242_CHIP_ID:
352 			name = "brcmfmac43242a.bin";
353 			break;
354 		case BRCM_CC_43566_CHIP_ID:
355 		case BRCM_CC_43569_CHIP_ID:
356 			name = "brcmfmac43569.bin";
357 			break;
358 		default:
359 			break;
360 		}
361 
362 		if (name == NULL) {
363 			printf("%s: unknown firmware\n", DEVNAME(sc));
364 			return;
365 		}
366 
367 		if (firmware_open("if_bwfm", name, &fwh) != 0) {
368 			printf("%s: failed firmware_open of file %s\n",
369 			    DEVNAME(sc), name);
370 			return;
371 		}
372 		size = firmware_get_size(fwh);
373 		ucode = firmware_malloc(size);
374 		if (ucode == NULL) {
375 			printf("%s: failed to allocate firmware memory\n",
376 			    DEVNAME(sc));
377 			firmware_close(fwh);
378 			return;
379 		}
380 		error = firmware_read(fwh, 0, ucode, size);
381 		firmware_close(fwh);
382 		if (error != 0) {
383 			printf("%s: failed to read firmware (error %d)\n",
384 			    DEVNAME(sc), error);
385 			firmware_free(ucode, size);
386 			return;
387 		}
388 
389 		if (bwfm_usb_load_microcode(sc, ucode, size) != 0) {
390 			printf("%s: could not load microcode\n",
391 			    DEVNAME(sc));
392 			return;
393 		}
394 
395 		firmware_free(ucode, size);
396 
397 		for (i = 0; i < 10; i++) {
398 			delay(100 * 1000);
399 			memset(&brom, 0, sizeof(brom));
400 			bwfm_usb_dl_cmd(sc, DL_GETVER, &brom, sizeof(brom));
401 			if (le32toh(brom.chip) == BRCMF_POSTBOOT_ID)
402 				break;
403 		}
404 
405 		if (le32toh(brom.chip) != BRCMF_POSTBOOT_ID) {
406 			printf("%s: firmware did not start up\n",
407 			    DEVNAME(sc));
408 			return;
409 		}
410 
411 		sc->sc_chip = le32toh(brom.chip);
412 		sc->sc_chiprev = le32toh(brom.chiprev);
413 		printf("%s: firmware loaded\n", DEVNAME(sc));
414 	}
415 
416 	bwfm_usb_dl_cmd(sc, DL_RESETCFG, &brom, sizeof(brom));
417 
418 	if (bwfm_usb_alloc_rx_list(sc) || bwfm_usb_alloc_tx_list(sc)) {
419 		printf("%s: cannot allocate rx/tx lists\n", DEVNAME(sc));
420 		return;
421 	}
422 
423 	bwfm_attach(&sc->sc_sc);
424 
425 	for (i = 0; i < BWFM_RX_LIST_COUNT; i++) {
426 		data = &sc->sc_rx_data[i];
427 
428 		usbd_setup_xfer(data->xfer, data, data->buf,
429 		    BWFM_RXBUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT,
430 		    bwfm_usb_rxeof);
431 		error = usbd_transfer(data->xfer);
432 		if (error != 0 && error != USBD_IN_PROGRESS)
433 			printf("%s: could not set up new transfer: %s\n",
434 			    DEVNAME(sc), usbd_errstr(error));
435 	}
436 }
437 
438 void
439 bwfm_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
440 {
441 	struct bwfm_usb_rx_data *data = priv;
442 	struct bwfm_usb_softc *sc = data->sc;
443 	struct bwfm_proto_bcdc_hdr *hdr;
444 	usbd_status error;
445 	uint32_t len, off;
446 
447 	DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__,
448 	    usbd_errstr(status)));
449 
450 	if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
451 		usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh);
452 		if (status != USBD_CANCELLED)
453 			goto resubmit;
454 		return;
455 	}
456 	usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
457 
458 	off = 0;
459 	hdr = (void *)data->buf;
460 	if (len < sizeof(*hdr))
461 		goto resubmit;
462 	len -= sizeof(*hdr);
463 	off += sizeof(*hdr);
464 	if (len < hdr->data_offset << 2)
465 		goto resubmit;
466 	len -= hdr->data_offset << 2;
467 	off += hdr->data_offset << 2;
468 
469 	mutex_enter(&sc->sc_rx_lock);
470 	bwfm_rx(&sc->sc_sc, &data->buf[off], len);
471 	mutex_exit(&sc->sc_rx_lock);
472 
473 resubmit:
474 	usbd_setup_xfer(data->xfer, data, data->buf,
475 	    BWFM_RXBUFSZ, USBD_SHORT_XFER_OK, 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
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 		if (usbd_create_xfer(sc->sc_rx_pipeh, BWFM_RXBUFSZ,
495 		    0, 0, &data->xfer) != 0) {
496 			printf("%s: could not create xfer\n",
497 			    DEVNAME(sc));
498 			error = ENOMEM;
499 			break;
500 		}
501 		data->buf = usbd_get_buffer(data->xfer);
502 	}
503 	if (error != 0)
504 		bwfm_usb_free_rx_list(sc);
505 	return (error);
506 }
507 
508 void
509 bwfm_usb_free_rx_list(struct bwfm_usb_softc *sc)
510 {
511 	int i;
512 
513 	/* NB: Caller must abort pipe first. */
514 	for (i = 0; i < BWFM_RX_LIST_COUNT; i++) {
515 		if (sc->sc_rx_data[i].xfer != NULL)
516 			usbd_destroy_xfer(sc->sc_rx_data[i].xfer);
517 		sc->sc_rx_data[i].xfer = NULL;
518 	}
519 }
520 
521 int
522 bwfm_usb_alloc_tx_list(struct bwfm_usb_softc *sc)
523 {
524 	struct bwfm_usb_tx_data *data;
525 	int i, error = 0;
526 
527 	TAILQ_INIT(&sc->sc_tx_free_list);
528 	for (i = 0; i < BWFM_TX_LIST_COUNT; i++) {
529 		data = &sc->sc_tx_data[i];
530 
531 		data->sc = sc; /* Backpointer for callbacks. */
532 
533 		if (usbd_create_xfer(sc->sc_tx_pipeh, BWFM_TXBUFSZ,
534 		    USBD_FORCE_SHORT_XFER, 0, &data->xfer) != 0) {
535 			printf("%s: could not create xfer\n",
536 			    DEVNAME(sc));
537 			error = ENOMEM;
538 			break;
539 		}
540 		data->buf = usbd_get_buffer(data->xfer);
541 
542 		/* Append this Tx buffer to our free list. */
543 		TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next);
544 	}
545 	if (error != 0)
546 		bwfm_usb_free_tx_list(sc);
547 	return (error);
548 }
549 
550 void
551 bwfm_usb_free_tx_list(struct bwfm_usb_softc *sc)
552 {
553 	int i;
554 
555 	/* NB: Caller must abort pipe first. */
556 	for (i = 0; i < BWFM_TX_LIST_COUNT; i++) {
557 		if (sc->sc_tx_data[i].xfer != NULL)
558 			usbd_destroy_xfer(sc->sc_tx_data[i].xfer);
559 		sc->sc_tx_data[i].xfer = NULL;
560 	}
561 }
562 
563 void
564 bwfm_usb_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
565 {
566 	struct bwfm_usb_tx_data *data = priv;
567 	struct bwfm_usb_softc *sc = data->sc;
568 	struct ifnet *ifp = sc->sc_sc.sc_ic.ic_ifp;
569 	int s;
570 
571 	DPRINTFN(2, ("%s: %s status %s\n", DEVNAME(sc), __func__,
572 	    usbd_errstr(status)));
573 
574 	m_freem(data->mbuf);
575 	data->mbuf = NULL;
576 
577 	mutex_enter(&sc->sc_tx_lock);
578 	/* Put this Tx buffer back to our free list. */
579 	TAILQ_INSERT_TAIL(&sc->sc_tx_free_list, data, next);
580 	mutex_exit(&sc->sc_tx_lock);
581 
582 	s = splnet();
583 
584 	if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
585 		if (status == USBD_CANCELLED)
586 			usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh);
587 		ifp->if_oerrors++;
588 		splx(s);
589 		return;
590 	}
591 
592 	ifp->if_opackets++;
593 
594 	/* We just released a Tx buffer, notify Tx. */
595 	if ((ifp->if_flags & IFF_OACTIVE) != 0) {
596 		ifp->if_flags &= ~IFF_OACTIVE;
597 		if_schedule_deferred_start(ifp);
598 	}
599 	splx(s);
600 }
601 
602 int
603 bwfm_usb_detach(device_t self, int flags)
604 {
605 	struct bwfm_usb_softc *sc = device_private(self);
606 
607 	bwfm_detach(&sc->sc_sc, flags);
608 
609 	if (sc->sc_rx_pipeh != NULL) {
610 		usbd_abort_pipe(sc->sc_rx_pipeh);
611 		usbd_close_pipe(sc->sc_rx_pipeh);
612 	}
613 	if (sc->sc_tx_pipeh != NULL) {
614 		usbd_abort_pipe(sc->sc_tx_pipeh);
615 		usbd_close_pipe(sc->sc_tx_pipeh);
616 	}
617 
618 	bwfm_usb_free_rx_list(sc);
619 	bwfm_usb_free_tx_list(sc);
620 
621 	mutex_destroy(&sc->sc_rx_lock);
622 	mutex_destroy(&sc->sc_tx_lock);
623 
624 	return 0;
625 }
626 
627 int
628 bwfm_usb_dl_cmd(struct bwfm_usb_softc *sc, uByte cmd, void *buf, int len)
629 {
630 	usb_device_request_t req;
631 	usbd_status error;
632 
633 	req.bmRequestType = UT_READ_VENDOR_INTERFACE;
634 	req.bRequest = cmd;
635 
636 	USETW(req.wValue, 0);
637 	USETW(req.wIndex, sc->sc_ifaceno);
638 	USETW(req.wLength, len);
639 
640 	error = usbd_do_request(sc->sc_udev, &req, buf);
641 	if (error != 0) {
642 		printf("%s: could not read register: %s\n",
643 		    DEVNAME(sc), usbd_errstr(error));
644 	}
645 	return error;
646 }
647 
648 int
649 bwfm_usb_load_microcode(struct bwfm_usb_softc *sc, const u_char *ucode, size_t size)
650 {
651 	const struct trx_header *trx = (const struct trx_header *)ucode;
652 	struct rdl_state state;
653 	uint32_t rdlstate, rdlbytes, sent = 0, sendlen = 0;
654 	struct usbd_xfer *xfer;
655 	usbd_status error;
656 	char *buf;
657 
658 	if (le32toh(trx->magic) != TRX_MAGIC ||
659 	    (le32toh(trx->flag_version) & TRX_UNCOMP_IMAGE) == 0) {
660 		printf("%s: invalid firmware\n", DEVNAME(sc));
661 		return 1;
662 	}
663 
664 	bwfm_usb_dl_cmd(sc, DL_START, &state, sizeof(state));
665 	rdlstate = le32toh(state.state);
666 	rdlbytes = le32toh(state.bytes);
667 
668 	if (rdlstate != DL_WAITING) {
669 		printf("%s: cannot start fw download\n", DEVNAME(sc));
670 		return 1;
671 	}
672 
673 	error = usbd_create_xfer(sc->sc_tx_pipeh, TRX_RDL_CHUNK,
674 	    0, 0, &xfer);
675 	if (error != 0) {
676 		printf("%s: cannot create xfer\n", DEVNAME(sc));
677 		goto err;
678 	}
679 
680 	buf = usbd_get_buffer(xfer);
681 
682 	while (rdlbytes != size) {
683 		sendlen = MIN(size - sent, TRX_RDL_CHUNK);
684 		memcpy(buf, ucode + sent, sendlen);
685 
686 		usbd_setup_xfer(xfer, NULL, buf, sendlen,
687 		    USBD_SYNCHRONOUS, USBD_NO_TIMEOUT, NULL);
688 		error = usbd_transfer(xfer);
689 		if (error != 0 && error != USBD_IN_PROGRESS) {
690 			printf("%s: transfer error\n", DEVNAME(sc));
691 			goto err;
692 		}
693 		sent += sendlen;
694 
695 		bwfm_usb_dl_cmd(sc, DL_GETSTATE, &state, sizeof(state));
696 		rdlstate = le32toh(state.state);
697 		rdlbytes = le32toh(state.bytes);
698 
699 		if (rdlbytes != sent) {
700 			printf("%s: device reported different size\n",
701 			    DEVNAME(sc));
702 			goto err;
703 		}
704 
705 		if (rdlstate == DL_BAD_HDR || rdlstate == DL_BAD_CRC) {
706 			printf("%s: device reported bad hdr/crc\n",
707 			    DEVNAME(sc));
708 			goto err;
709 		}
710 	}
711 
712 	bwfm_usb_dl_cmd(sc, DL_GETSTATE, &state, sizeof(state));
713 	rdlstate = le32toh(state.state);
714 	rdlbytes = le32toh(state.bytes);
715 
716 	if (rdlstate != DL_RUNNABLE) {
717 		printf("%s: dongle not runnable\n", DEVNAME(sc));
718 		goto err;
719 	}
720 
721 	bwfm_usb_dl_cmd(sc, DL_GO, &state, sizeof(state));
722 
723 	usbd_destroy_xfer(xfer);
724 
725 	return 0;
726 err:
727 	if (sc->sc_tx_pipeh != NULL) {
728 		usbd_abort_pipe(sc->sc_tx_pipeh);
729 		usbd_close_pipe(sc->sc_tx_pipeh);
730 		sc->sc_tx_pipeh = NULL;
731 	}
732 	if (xfer != NULL)
733 		usbd_destroy_xfer(xfer);
734 	return 1;
735 }
736 
737 int
738 bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf *m)
739 {
740 	struct bwfm_usb_softc *sc = (void *)bwfm;
741 	struct bwfm_proto_bcdc_hdr *hdr;
742 	struct bwfm_usb_tx_data *data;
743 	struct ether_header *eh;
744 	uint32_t len = 0;
745 	int error, ac;
746 
747 	DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__));
748 
749 	mutex_enter(&sc->sc_tx_lock);
750 
751 	if (TAILQ_EMPTY(&sc->sc_tx_free_list)) {
752 		mutex_exit(&sc->sc_tx_lock);
753 		return ENOBUFS;
754 	}
755 
756 	/* No QoS for EAPOL frames. */
757 	eh = mtod(m, struct ether_header *);
758 	ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ?
759 	    M_WME_GETAC(m) : WME_AC_BE;
760 
761 	/* Grab a Tx buffer from our free list. */
762 	data = TAILQ_FIRST(&sc->sc_tx_free_list);
763 	TAILQ_REMOVE(&sc->sc_tx_free_list, data, next);
764 
765 	mutex_exit(&sc->sc_tx_lock);
766 
767 	hdr = (void *)&data->buf[len];
768 	hdr->data_offset = 0;
769 	hdr->priority = ac;
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, &data->buf[len]);
775 	len += m->m_pkthdr.len;
776 
777 	data->mbuf = m;
778 
779 	usbd_setup_xfer(data->xfer, data, data->buf,
780 	    len, USBD_FORCE_SHORT_XFER, 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
790 bwfm_usb_txctl(struct bwfm_softc *bwfm, char *buf, size_t len)
791 {
792 	struct bwfm_usb_softc *sc = (void *)bwfm;
793 	usb_device_request_t req;
794 	usbd_status error;
795 	int ret = 1;
796 
797 	DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__));
798 
799 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
800 	req.bRequest = 0;
801 
802 	USETW(req.wValue, 0);
803 	USETW(req.wIndex, sc->sc_ifaceno);
804 	USETW(req.wLength, len);
805 
806 	error = usbd_do_request(sc->sc_udev, &req, buf);
807 	if (error != 0) {
808 		printf("%s: could not read ctl packet: %s\n",
809 		    DEVNAME(sc), usbd_errstr(error));
810 		goto err;
811 	}
812 
813 	ret = 0;
814 err:
815 	return ret;
816 }
817 
818 int
819 bwfm_usb_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *len)
820 {
821 	struct bwfm_usb_softc *sc = (void *)bwfm;
822 	usb_device_request_t req;
823 	usbd_status error;
824 	uint32_t len32;
825 	int ret = 1;
826 
827 	DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__));
828 
829 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
830 	req.bRequest = 1;
831 
832 	USETW(req.wValue, 0);
833 	USETW(req.wIndex, sc->sc_ifaceno);
834 	USETW(req.wLength, *len);
835 
836 	error = usbd_do_request_flags(sc->sc_udev, &req, buf, 0,
837 	    &len32, USBD_DEFAULT_TIMEOUT);
838 	if (error != 0) {
839 		printf("%s: could not read ctl packet: %s\n",
840 		    DEVNAME(sc), usbd_errstr(error));
841 		goto err;
842 	}
843 
844 	if (len32 > *len) {
845 		printf("%s: broken length\n", DEVNAME(sc));
846 		goto err;
847 	}
848 
849 	*len = len32;
850 	ret = 0;
851 err:
852 	return ret;
853 }
854