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