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