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