LCOV - code coverage report
Current view: top level - dev/usb - if_bwfm_usb.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 389 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13