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