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

          Line data    Source code
       1             : /*      $OpenBSD: if_rsu.c,v 1.43 2018/04/26 12:50:07 pirofti Exp $     */
       2             : 
       3             : /*-
       4             :  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
       5             :  *
       6             :  * Permission to use, copy, modify, and 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             : /*
      20             :  * Driver for Realtek RTL8188SU/RTL8191SU/RTL8192SU.
      21             :  */
      22             : 
      23             : #include "bpfilter.h"
      24             : 
      25             : #include <sys/param.h>
      26             : #include <sys/sockio.h>
      27             : #include <sys/mbuf.h>
      28             : #include <sys/kernel.h>
      29             : #include <sys/socket.h>
      30             : #include <sys/systm.h>
      31             : #include <sys/timeout.h>
      32             : #include <sys/conf.h>
      33             : #include <sys/device.h>
      34             : #include <sys/endian.h>
      35             : 
      36             : #include <machine/intr.h>
      37             : 
      38             : #if NBPFILTER > 0
      39             : #include <net/bpf.h>
      40             : #endif
      41             : #include <net/if.h>
      42             : #include <net/if_dl.h>
      43             : #include <net/if_media.h>
      44             : 
      45             : #include <netinet/in.h>
      46             : #include <netinet/if_ether.h>
      47             : 
      48             : #include <net80211/ieee80211_var.h>
      49             : #include <net80211/ieee80211_radiotap.h>
      50             : 
      51             : #include <dev/usb/usb.h>
      52             : #include <dev/usb/usbdi.h>
      53             : #include <dev/usb/usbdi_util.h>
      54             : #include <dev/usb/usbdevs.h>
      55             : 
      56             : #include <dev/usb/if_rsureg.h>
      57             : 
      58             : #ifdef RSU_DEBUG
      59             : #define DPRINTF(x)      do { if (rsu_debug) printf x; } while (0)
      60             : #define DPRINTFN(n, x)  do { if (rsu_debug >= (n)) printf x; } while (0)
      61             : int rsu_debug = 4;
      62             : #else
      63             : #define DPRINTF(x)
      64             : #define DPRINTFN(n, x)
      65             : #endif
      66             : 
      67             : /*
      68             :  * NB: When updating this list of devices, beware to also update the list
      69             :  * of devices that have HT support disabled below, if applicable.
      70             :  */
      71             : static const struct usb_devno rsu_devs[] = {
      72             :         { USB_VENDOR_ACCTON,            USB_PRODUCT_ACCTON_RTL8192SU },
      73             :         { USB_VENDOR_ASUS,              USB_PRODUCT_ASUS_USBN10 },
      74             :         { USB_VENDOR_ASUS,              USB_PRODUCT_ASUS_RTL8192SU_1 },
      75             :         { USB_VENDOR_AZUREWAVE,         USB_PRODUCT_AZUREWAVE_RTL8192SU_1 },
      76             :         { USB_VENDOR_AZUREWAVE,         USB_PRODUCT_AZUREWAVE_RTL8192SU_2 },
      77             :         { USB_VENDOR_AZUREWAVE,         USB_PRODUCT_AZUREWAVE_RTL8192SU_3 },
      78             :         { USB_VENDOR_AZUREWAVE,         USB_PRODUCT_AZUREWAVE_RTL8192SU_4 },
      79             :         { USB_VENDOR_AZUREWAVE,         USB_PRODUCT_AZUREWAVE_RTL8192SU_5 },
      80             :         { USB_VENDOR_BELKIN,            USB_PRODUCT_BELKIN_RTL8192SU_1 },
      81             :         { USB_VENDOR_BELKIN,            USB_PRODUCT_BELKIN_RTL8192SU_2 },
      82             :         { USB_VENDOR_BELKIN,            USB_PRODUCT_BELKIN_RTL8192SU_3 },
      83             :         { USB_VENDOR_CONCEPTRONIC2,     USB_PRODUCT_CONCEPTRONIC2_RTL8192SU_1 },
      84             :         { USB_VENDOR_CONCEPTRONIC2,     USB_PRODUCT_CONCEPTRONIC2_RTL8192SU_2 },
      85             :         { USB_VENDOR_CONCEPTRONIC2,     USB_PRODUCT_CONCEPTRONIC2_RTL8192SU_3 },
      86             :         { USB_VENDOR_COREGA,            USB_PRODUCT_COREGA_RTL8192SU },
      87             :         { USB_VENDOR_DLINK2,            USB_PRODUCT_DLINK2_DWA131A1 },
      88             :         { USB_VENDOR_DLINK2,            USB_PRODUCT_DLINK2_RTL8192SU_1 },
      89             :         { USB_VENDOR_DLINK2,            USB_PRODUCT_DLINK2_RTL8192SU_2 },
      90             :         { USB_VENDOR_EDIMAX,            USB_PRODUCT_EDIMAX_RTL8192SU_1 },
      91             :         { USB_VENDOR_EDIMAX,            USB_PRODUCT_EDIMAX_RTL8192SU_2 },
      92             :         { USB_VENDOR_EDIMAX,            USB_PRODUCT_EDIMAX_RTL8192SU_3 },
      93             :         { USB_VENDOR_GUILLEMOT,         USB_PRODUCT_GUILLEMOT_HWGUN54 },
      94             :         { USB_VENDOR_GUILLEMOT,         USB_PRODUCT_GUILLEMOT_HWNUM300 },
      95             :         { USB_VENDOR_HAWKING,           USB_PRODUCT_HAWKING_RTL8192SU_1 },
      96             :         { USB_VENDOR_HAWKING,           USB_PRODUCT_HAWKING_RTL8192SU_2 },
      97             :         { USB_VENDOR_PLANEX2,           USB_PRODUCT_PLANEX2_GWUSNANO },
      98             :         { USB_VENDOR_REALTEK,           USB_PRODUCT_REALTEK_RTL8171 },
      99             :         { USB_VENDOR_REALTEK,           USB_PRODUCT_REALTEK_RTL8172 },
     100             :         { USB_VENDOR_REALTEK,           USB_PRODUCT_REALTEK_RTL8173 },
     101             :         { USB_VENDOR_REALTEK,           USB_PRODUCT_REALTEK_RTL8174 },
     102             :         { USB_VENDOR_REALTEK,           USB_PRODUCT_REALTEK_RTL8192SU },
     103             :         { USB_VENDOR_REALTEK,           USB_PRODUCT_REALTEK_RTL8712 },
     104             :         { USB_VENDOR_REALTEK,           USB_PRODUCT_REALTEK_RTL8713 },
     105             :         { USB_VENDOR_SENAO,             USB_PRODUCT_SENAO_RTL8192SU_1 },
     106             :         { USB_VENDOR_SENAO,             USB_PRODUCT_SENAO_RTL8192SU_2 },
     107             :         { USB_VENDOR_SITECOMEU,         USB_PRODUCT_SITECOMEU_WL349V1 },
     108             :         { USB_VENDOR_SITECOMEU,         USB_PRODUCT_SITECOMEU_WL353 },
     109             :         { USB_VENDOR_SWEEX2,            USB_PRODUCT_SWEEX2_LW154 }
     110             : };
     111             : 
     112             : /* List of devices that have HT support disabled. */
     113             : static const struct usb_devno rsu_devs_noht[] = {
     114             :         { USB_VENDOR_ASUS,              USB_PRODUCT_ASUS_RTL8192SU_1 },
     115             :         { USB_VENDOR_AZUREWAVE,         USB_PRODUCT_AZUREWAVE_RTL8192SU_4 }
     116             : };
     117             : 
     118             : int             rsu_match(struct device *, void *, void *);
     119             : void            rsu_attach(struct device *, struct device *, void *);
     120             : int             rsu_detach(struct device *, int);
     121             : int             rsu_open_pipes(struct rsu_softc *);
     122             : void            rsu_close_pipes(struct rsu_softc *);
     123             : int             rsu_alloc_rx_list(struct rsu_softc *);
     124             : void            rsu_free_rx_list(struct rsu_softc *);
     125             : int             rsu_alloc_tx_list(struct rsu_softc *);
     126             : void            rsu_free_tx_list(struct rsu_softc *);
     127             : void            rsu_task(void *);
     128             : void            rsu_do_async(struct rsu_softc *,
     129             :                     void (*)(struct rsu_softc *, void *), void *, int);
     130             : void            rsu_wait_async(struct rsu_softc *);
     131             : int             rsu_write_region_1(struct rsu_softc *, uint16_t, uint8_t *,
     132             :                     int);
     133             : void            rsu_write_1(struct rsu_softc *, uint16_t, uint8_t);
     134             : void            rsu_write_2(struct rsu_softc *, uint16_t, uint16_t);
     135             : void            rsu_write_4(struct rsu_softc *, uint16_t, uint32_t);
     136             : int             rsu_read_region_1(struct rsu_softc *, uint16_t, uint8_t *,
     137             :                     int);
     138             : uint8_t         rsu_read_1(struct rsu_softc *, uint16_t);
     139             : uint16_t        rsu_read_2(struct rsu_softc *, uint16_t);
     140             : uint32_t        rsu_read_4(struct rsu_softc *, uint16_t);
     141             : int             rsu_fw_iocmd(struct rsu_softc *, uint32_t);
     142             : uint8_t         rsu_efuse_read_1(struct rsu_softc *, uint16_t);
     143             : int             rsu_read_rom(struct rsu_softc *);
     144             : int             rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int);
     145             : int             rsu_media_change(struct ifnet *);
     146             : void            rsu_calib_to(void *);
     147             : void            rsu_calib_cb(struct rsu_softc *, void *);
     148             : int             rsu_newstate(struct ieee80211com *, enum ieee80211_state, int);
     149             : void            rsu_newstate_cb(struct rsu_softc *, void *);
     150             : int             rsu_set_key(struct ieee80211com *, struct ieee80211_node *,
     151             :                     struct ieee80211_key *);
     152             : void            rsu_set_key_cb(struct rsu_softc *, void *);
     153             : void            rsu_delete_key(struct ieee80211com *, struct ieee80211_node *,
     154             :                     struct ieee80211_key *);
     155             : void            rsu_delete_key_cb(struct rsu_softc *, void *);
     156             : int             rsu_site_survey(struct rsu_softc *);
     157             : int             rsu_join_bss(struct rsu_softc *, struct ieee80211_node *);
     158             : int             rsu_disconnect(struct rsu_softc *);
     159             : void            rsu_event_survey(struct rsu_softc *, uint8_t *, int);
     160             : void            rsu_event_join_bss(struct rsu_softc *, uint8_t *, int);
     161             : void            rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int);
     162             : void            rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int);
     163             : int8_t          rsu_get_rssi(struct rsu_softc *, int, void *);
     164             : void            rsu_rx_frame(struct rsu_softc *, uint8_t *, int);
     165             : void            rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int);
     166             : void            rsu_rxeof(struct usbd_xfer *, void *, usbd_status);
     167             : void            rsu_txeof(struct usbd_xfer *, void *, usbd_status);
     168             : int             rsu_tx(struct rsu_softc *, struct mbuf *,
     169             :                     struct ieee80211_node *);
     170             : int             rsu_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
     171             :                     int, int, int);
     172             : void            rsu_start(struct ifnet *);
     173             : void            rsu_watchdog(struct ifnet *);
     174             : int             rsu_ioctl(struct ifnet *, u_long, caddr_t);
     175             : void            rsu_power_on_acut(struct rsu_softc *);
     176             : void            rsu_power_on_bcut(struct rsu_softc *);
     177             : void            rsu_power_off(struct rsu_softc *);
     178             : int             rsu_fw_loadsection(struct rsu_softc *, uint8_t *, int);
     179             : int             rsu_load_firmware(struct rsu_softc *);
     180             : int             rsu_init(struct ifnet *);
     181             : void            rsu_stop(struct ifnet *);
     182             : 
     183             : struct cfdriver rsu_cd = {
     184             :         NULL, "rsu", DV_IFNET
     185             : };
     186             : 
     187             : const struct cfattach rsu_ca = {
     188             :         sizeof(struct rsu_softc), rsu_match, rsu_attach, rsu_detach,
     189             : };
     190             : 
     191             : int
     192           0 : rsu_match(struct device *parent, void *match, void *aux)
     193             : {
     194           0 :         struct usb_attach_arg *uaa = aux;
     195             : 
     196           0 :         if (uaa->iface == NULL || uaa->configno != 1)
     197           0 :                 return (UMATCH_NONE);
     198             : 
     199           0 :         return ((usb_lookup(rsu_devs, uaa->vendor, uaa->product) != NULL) ?
     200             :             UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
     201           0 : }
     202             : 
     203             : void
     204           0 : rsu_attach(struct device *parent, struct device *self, void *aux)
     205             : {
     206           0 :         struct rsu_softc *sc = (struct rsu_softc *)self;
     207           0 :         struct usb_attach_arg *uaa = aux;
     208           0 :         struct ieee80211com *ic = &sc->sc_ic;
     209           0 :         struct ifnet *ifp = &ic->ic_if;
     210             :         int i, error;
     211             : 
     212           0 :         sc->sc_udev = uaa->device;
     213           0 :         sc->sc_iface = uaa->iface;
     214             : 
     215           0 :         usb_init_task(&sc->sc_task, rsu_task, sc, USB_TASK_TYPE_GENERIC);
     216           0 :         timeout_set(&sc->calib_to, rsu_calib_to, sc);
     217             : 
     218             :         /* Read chip revision. */
     219           0 :         sc->cut = MS(rsu_read_4(sc, R92S_PMC_FSM), R92S_PMC_FSM_CUT);
     220           0 :         if (sc->cut != 3)
     221           0 :                 sc->cut = (sc->cut >> 1) + 1;
     222             : 
     223           0 :         error = rsu_read_rom(sc);
     224           0 :         if (error != 0) {
     225           0 :                 printf("%s: could not read ROM\n", sc->sc_dev.dv_xname);
     226           0 :                 return;
     227             :         }
     228           0 :         IEEE80211_ADDR_COPY(ic->ic_myaddr, &sc->rom[0x12]);
     229             : 
     230           0 :         printf("%s: MAC/BB RTL8712 cut %d, address %s\n",
     231           0 :             sc->sc_dev.dv_xname, sc->cut, ether_sprintf(ic->ic_myaddr));
     232             : 
     233           0 :         if (rsu_open_pipes(sc) != 0)
     234           0 :                 return;
     235             : 
     236           0 :         ic->ic_phytype = IEEE80211_T_OFDM;   /* Not only, but not used. */
     237           0 :         ic->ic_opmode = IEEE80211_M_STA;     /* Default to BSS mode. */
     238           0 :         ic->ic_state = IEEE80211_S_INIT;
     239             : 
     240             :         /* Set device capabilities. */
     241           0 :         ic->ic_caps =
     242             :             IEEE80211_C_SCANALL |       /* Hardware scan. */
     243             :             IEEE80211_C_SHPREAMBLE |    /* Short preamble supported. */
     244             :             IEEE80211_C_SHSLOT |        /* Short slot time supported. */
     245             :             IEEE80211_C_WEP |           /* WEP. */
     246             :             IEEE80211_C_RSN;            /* WPA/RSN. */
     247             :         /* Check if HT support is present. */
     248           0 :         if (usb_lookup(rsu_devs_noht, uaa->vendor, uaa->product) == NULL) {
     249             : #ifdef notyet
     250             :                 /* Set HT capabilities. */
     251             :                 ic->ic_htcaps =
     252             :                     IEEE80211_HTCAP_CBW20_40 |
     253             :                     IEEE80211_HTCAP_DSSSCCK40;
     254             :                 /* Set supported HT rates. */
     255             :                 for (i = 0; i < 2; i++)
     256             :                         ic->ic_sup_mcs[i] = 0xff;
     257             : #endif
     258             :         }
     259             : 
     260             :         /* Set supported .11b and .11g rates. */
     261           0 :         ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
     262           0 :         ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
     263             : 
     264             :         /* Set supported .11b and .11g channels (1 through 14). */
     265           0 :         for (i = 1; i <= 14; i++) {
     266           0 :                 ic->ic_channels[i].ic_freq =
     267           0 :                     ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
     268           0 :                 ic->ic_channels[i].ic_flags =
     269             :                     IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
     270             :                     IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
     271             :         }
     272             : 
     273           0 :         ifp->if_softc = sc;
     274           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     275           0 :         ifp->if_ioctl = rsu_ioctl;
     276           0 :         ifp->if_start = rsu_start;
     277           0 :         ifp->if_watchdog = rsu_watchdog;
     278           0 :         memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
     279             : 
     280           0 :         if_attach(ifp);
     281           0 :         ieee80211_ifattach(ifp);
     282             : #ifdef notyet
     283             :         ic->ic_set_key = rsu_set_key;
     284             :         ic->ic_delete_key = rsu_delete_key;
     285             : #endif
     286             :         /* Override state transition machine. */
     287           0 :         sc->sc_newstate = ic->ic_newstate;
     288           0 :         ic->ic_newstate = rsu_newstate;
     289           0 :         ic->ic_send_mgmt = rsu_send_mgmt;
     290           0 :         ieee80211_media_init(ifp, rsu_media_change, ieee80211_media_status);
     291             : 
     292             : #if NBPFILTER > 0
     293           0 :         bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
     294             :             sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
     295             : 
     296           0 :         sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
     297           0 :         sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
     298           0 :         sc->sc_rxtap.wr_ihdr.it_present = htole32(RSU_RX_RADIOTAP_PRESENT);
     299             : 
     300           0 :         sc->sc_txtap_len = sizeof(sc->sc_txtapu);
     301           0 :         sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
     302           0 :         sc->sc_txtap.wt_ihdr.it_present = htole32(RSU_TX_RADIOTAP_PRESENT);
     303             : #endif
     304           0 : }
     305             : 
     306             : int
     307           0 : rsu_detach(struct device *self, int flags)
     308             : {
     309           0 :         struct rsu_softc *sc = (struct rsu_softc *)self;
     310           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
     311             :         int s;
     312             : 
     313           0 :         s = splusb();
     314             : 
     315           0 :         if (timeout_initialized(&sc->calib_to))
     316           0 :                 timeout_del(&sc->calib_to);
     317             : 
     318             :         /* Wait for all async commands to complete. */
     319           0 :         usb_rem_wait_task(sc->sc_udev, &sc->sc_task);
     320             : 
     321           0 :         usbd_ref_wait(sc->sc_udev);
     322             : 
     323           0 :         if (ifp->if_softc != NULL) {
     324           0 :                 ieee80211_ifdetach(ifp);
     325           0 :                 if_detach(ifp);
     326           0 :         }
     327             : 
     328             :         /* Abort and close Tx/Rx pipes. */
     329           0 :         rsu_close_pipes(sc);
     330             : 
     331             :         /* Free Tx/Rx buffers. */
     332           0 :         rsu_free_tx_list(sc);
     333           0 :         rsu_free_rx_list(sc);
     334           0 :         splx(s);
     335             : 
     336           0 :         return (0);
     337             : }
     338             : 
     339             : int
     340           0 : rsu_open_pipes(struct rsu_softc *sc)
     341             : {
     342             :         usb_interface_descriptor_t *id;
     343             :         int i, error;
     344             : 
     345             :         /*
     346             :          * Determine the number of Tx/Rx endpoints (there are chips with
     347             :          * 4, 6 or 11 endpoints).
     348             :          */
     349           0 :         id = usbd_get_interface_descriptor(sc->sc_iface);
     350           0 :         sc->npipes = id->bNumEndpoints;
     351           0 :         if (sc->npipes == 4)
     352           0 :                 sc->qid2idx = rsu_qid2idx_4ep;
     353           0 :         else if (sc->npipes == 6)
     354           0 :                 sc->qid2idx = rsu_qid2idx_6ep;
     355             :         else    /* Assume npipes==11; will fail below otherwise. */
     356           0 :                 sc->qid2idx = rsu_qid2idx_11ep;
     357             :         DPRINTF(("%d endpoints configuration\n", sc->npipes));
     358             : 
     359             :         /* Open all pipes. */
     360           0 :         for (i = 0; i < MIN(sc->npipes, nitems(r92s_epaddr)); i++) {
     361           0 :                 error = usbd_open_pipe(sc->sc_iface, r92s_epaddr[i], 0,
     362           0 :                     &sc->pipe[i]);
     363           0 :                 if (error != 0) {
     364           0 :                         printf("%s: could not open bulk pipe 0x%02x\n",
     365           0 :                             sc->sc_dev.dv_xname, r92s_epaddr[i]);
     366           0 :                         break;
     367             :                 }
     368             :         }
     369           0 :         if (error != 0)
     370           0 :                 rsu_close_pipes(sc);
     371           0 :         return (error);
     372             : }
     373             : 
     374             : void
     375           0 : rsu_close_pipes(struct rsu_softc *sc)
     376             : {
     377             :         int i;
     378             : 
     379             :         /* Close all pipes. */
     380           0 :         for (i = 0; i < sc->npipes; i++) {
     381           0 :                 if (sc->pipe[i] == NULL)
     382             :                         continue;
     383           0 :                 usbd_abort_pipe(sc->pipe[i]);
     384           0 :                 usbd_close_pipe(sc->pipe[i]);
     385           0 :         }
     386           0 : }
     387             : 
     388             : int
     389           0 : rsu_alloc_rx_list(struct rsu_softc *sc)
     390             : {
     391             :         struct rsu_rx_data *data;
     392             :         int i, error = 0;
     393             : 
     394           0 :         for (i = 0; i < RSU_RX_LIST_COUNT; i++) {
     395           0 :                 data = &sc->rx_data[i];
     396             : 
     397           0 :                 data->sc = sc;       /* Backpointer for callbacks. */
     398             : 
     399           0 :                 data->xfer = usbd_alloc_xfer(sc->sc_udev);
     400           0 :                 if (data->xfer == NULL) {
     401           0 :                         printf("%s: could not allocate xfer\n",
     402           0 :                             sc->sc_dev.dv_xname);
     403             :                         error = ENOMEM;
     404           0 :                         break;
     405             :                 }
     406           0 :                 data->buf = usbd_alloc_buffer(data->xfer, RSU_RXBUFSZ);
     407           0 :                 if (data->buf == NULL) {
     408           0 :                         printf("%s: could not allocate xfer buffer\n",
     409           0 :                             sc->sc_dev.dv_xname);
     410             :                         error = ENOMEM;
     411           0 :                         break;
     412             :                 }
     413             :         }
     414           0 :         if (error != 0)
     415           0 :                 rsu_free_rx_list(sc);
     416           0 :         return (error);
     417             : }
     418             : 
     419             : void
     420           0 : rsu_free_rx_list(struct rsu_softc *sc)
     421             : {
     422             :         int i;
     423             : 
     424             :         /* NB: Caller must abort pipe first. */
     425           0 :         for (i = 0; i < RSU_RX_LIST_COUNT; i++) {
     426           0 :                 if (sc->rx_data[i].xfer != NULL)
     427           0 :                         usbd_free_xfer(sc->rx_data[i].xfer);
     428           0 :                 sc->rx_data[i].xfer = NULL;
     429             :         }
     430           0 : }
     431             : 
     432             : int
     433           0 : rsu_alloc_tx_list(struct rsu_softc *sc)
     434             : {
     435             :         struct rsu_tx_data *data;
     436             :         int i, error = 0;
     437             : 
     438           0 :         TAILQ_INIT(&sc->tx_free_list);
     439           0 :         for (i = 0; i < RSU_TX_LIST_COUNT; i++) {
     440           0 :                 data = &sc->tx_data[i];
     441             : 
     442           0 :                 data->sc = sc;       /* Backpointer for callbacks. */
     443             : 
     444           0 :                 data->xfer = usbd_alloc_xfer(sc->sc_udev);
     445           0 :                 if (data->xfer == NULL) {
     446           0 :                         printf("%s: could not allocate xfer\n",
     447           0 :                             sc->sc_dev.dv_xname);
     448             :                         error = ENOMEM;
     449           0 :                         break;
     450             :                 }
     451           0 :                 data->buf = usbd_alloc_buffer(data->xfer, RSU_TXBUFSZ);
     452           0 :                 if (data->buf == NULL) {
     453           0 :                         printf("%s: could not allocate xfer buffer\n",
     454           0 :                             sc->sc_dev.dv_xname);
     455             :                         error = ENOMEM;
     456           0 :                         break;
     457             :                 }
     458             :                 /* Append this Tx buffer to our free list. */
     459           0 :                 TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
     460             :         }
     461           0 :         if (error != 0)
     462           0 :                 rsu_free_tx_list(sc);
     463           0 :         return (error);
     464             : }
     465             : 
     466             : void
     467           0 : rsu_free_tx_list(struct rsu_softc *sc)
     468             : {
     469             :         int i;
     470             : 
     471             :         /* NB: Caller must abort pipe first. */
     472           0 :         for (i = 0; i < RSU_TX_LIST_COUNT; i++) {
     473           0 :                 if (sc->tx_data[i].xfer != NULL)
     474           0 :                         usbd_free_xfer(sc->tx_data[i].xfer);
     475           0 :                 sc->tx_data[i].xfer = NULL;
     476             :         }
     477           0 : }
     478             : 
     479             : void
     480           0 : rsu_task(void *arg)
     481             : {
     482           0 :         struct rsu_softc *sc = arg;
     483           0 :         struct rsu_host_cmd_ring *ring = &sc->cmdq;
     484             :         struct rsu_host_cmd *cmd;
     485             :         int s;
     486             : 
     487             :         /* Process host commands. */
     488           0 :         s = splusb();
     489           0 :         while (ring->next != ring->cur) {
     490           0 :                 cmd = &ring->cmd[ring->next];
     491           0 :                 splx(s);
     492             :                 /* Invoke callback. */
     493           0 :                 cmd->cb(sc, cmd->data);
     494           0 :                 s = splusb();
     495           0 :                 ring->queued--;
     496           0 :                 ring->next = (ring->next + 1) % RSU_HOST_CMD_RING_COUNT;
     497             :         }
     498           0 :         splx(s);
     499           0 : }
     500             : 
     501             : void
     502           0 : rsu_do_async(struct rsu_softc *sc,
     503             :     void (*cb)(struct rsu_softc *, void *), void *arg, int len)
     504             : {
     505           0 :         struct rsu_host_cmd_ring *ring = &sc->cmdq;
     506             :         struct rsu_host_cmd *cmd;
     507             :         int s;
     508             : 
     509           0 :         s = splusb();
     510           0 :         cmd = &ring->cmd[ring->cur];
     511           0 :         cmd->cb = cb;
     512           0 :         KASSERT(len <= sizeof(cmd->data));
     513           0 :         memcpy(cmd->data, arg, len);
     514           0 :         ring->cur = (ring->cur + 1) % RSU_HOST_CMD_RING_COUNT;
     515             : 
     516             :         /* If there is no pending command already, schedule a task. */
     517           0 :         if (++ring->queued == 1)
     518           0 :                 usb_add_task(sc->sc_udev, &sc->sc_task);
     519           0 :         splx(s);
     520           0 : }
     521             : 
     522             : void
     523           0 : rsu_wait_async(struct rsu_softc *sc)
     524             : {
     525             :         /* Wait for all queued asynchronous commands to complete. */
     526           0 :         usb_wait_task(sc->sc_udev, &sc->sc_task);
     527           0 : }
     528             : 
     529             : int
     530           0 : rsu_write_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf,
     531             :     int len)
     532             : {
     533           0 :         usb_device_request_t req;
     534             : 
     535           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     536           0 :         req.bRequest = R92S_REQ_REGS;
     537           0 :         USETW(req.wValue, addr);
     538           0 :         USETW(req.wIndex, 0);
     539           0 :         USETW(req.wLength, len);
     540           0 :         return (usbd_do_request(sc->sc_udev, &req, buf));
     541           0 : }
     542             : 
     543             : void
     544           0 : rsu_write_1(struct rsu_softc *sc, uint16_t addr, uint8_t val)
     545             : {
     546           0 :         rsu_write_region_1(sc, addr, &val, 1);
     547           0 : }
     548             : 
     549             : void
     550           0 : rsu_write_2(struct rsu_softc *sc, uint16_t addr, uint16_t val)
     551             : {
     552           0 :         val = htole16(val);
     553           0 :         rsu_write_region_1(sc, addr, (uint8_t *)&val, 2);
     554           0 : }
     555             : 
     556             : void
     557           0 : rsu_write_4(struct rsu_softc *sc, uint16_t addr, uint32_t val)
     558             : {
     559           0 :         val = htole32(val);
     560           0 :         rsu_write_region_1(sc, addr, (uint8_t *)&val, 4);
     561           0 : }
     562             : 
     563             : int
     564           0 : rsu_read_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf,
     565             :     int len)
     566             : {
     567           0 :         usb_device_request_t req;
     568             : 
     569           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     570           0 :         req.bRequest = R92S_REQ_REGS;
     571           0 :         USETW(req.wValue, addr);
     572           0 :         USETW(req.wIndex, 0);
     573           0 :         USETW(req.wLength, len);
     574           0 :         return (usbd_do_request(sc->sc_udev, &req, buf));
     575           0 : }
     576             : 
     577             : uint8_t
     578           0 : rsu_read_1(struct rsu_softc *sc, uint16_t addr)
     579             : {
     580           0 :         uint8_t val;
     581             : 
     582           0 :         if (rsu_read_region_1(sc, addr, &val, 1) != 0)
     583           0 :                 return (0xff);
     584           0 :         return (val);
     585           0 : }
     586             : 
     587             : uint16_t
     588           0 : rsu_read_2(struct rsu_softc *sc, uint16_t addr)
     589             : {
     590           0 :         uint16_t val;
     591             : 
     592           0 :         if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0)
     593           0 :                 return (0xffff);
     594           0 :         return (letoh16(val));
     595           0 : }
     596             : 
     597             : uint32_t
     598           0 : rsu_read_4(struct rsu_softc *sc, uint16_t addr)
     599             : {
     600           0 :         uint32_t val;
     601             : 
     602           0 :         if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0)
     603           0 :                 return (0xffffffff);
     604           0 :         return (letoh32(val));
     605           0 : }
     606             : 
     607             : int
     608           0 : rsu_fw_iocmd(struct rsu_softc *sc, uint32_t iocmd)
     609             : {
     610             :         int ntries;
     611             : 
     612           0 :         rsu_write_4(sc, R92S_IOCMD_CTRL, iocmd);
     613           0 :         DELAY(100);
     614           0 :         for (ntries = 0; ntries < 50; ntries++) {
     615           0 :                 if (rsu_read_4(sc, R92S_IOCMD_CTRL) == 0)
     616           0 :                         return (0);
     617           0 :                 DELAY(10);
     618             :         }
     619           0 :         return (ETIMEDOUT);
     620           0 : }
     621             : 
     622             : uint8_t
     623           0 : rsu_efuse_read_1(struct rsu_softc *sc, uint16_t addr)
     624             : {
     625             :         uint32_t reg;
     626             :         int ntries;
     627             : 
     628           0 :         reg = rsu_read_4(sc, R92S_EFUSE_CTRL);
     629           0 :         reg = RW(reg, R92S_EFUSE_CTRL_ADDR, addr);
     630           0 :         reg &= ~R92S_EFUSE_CTRL_VALID;
     631           0 :         rsu_write_4(sc, R92S_EFUSE_CTRL, reg);
     632             :         /* Wait for read operation to complete. */
     633           0 :         for (ntries = 0; ntries < 100; ntries++) {
     634           0 :                 reg = rsu_read_4(sc, R92S_EFUSE_CTRL);
     635           0 :                 if (reg & R92S_EFUSE_CTRL_VALID)
     636           0 :                         return (MS(reg, R92S_EFUSE_CTRL_DATA));
     637           0 :                 DELAY(5);
     638             :         }
     639           0 :         printf("%s: could not read efuse byte at address 0x%x\n",
     640           0 :             sc->sc_dev.dv_xname, addr);
     641           0 :         return (0xff);
     642           0 : }
     643             : 
     644             : int
     645           0 : rsu_read_rom(struct rsu_softc *sc)
     646             : {
     647           0 :         uint8_t *rom = sc->rom;
     648             :         uint16_t addr = 0;
     649             :         uint32_t reg;
     650             :         uint8_t off, msk;
     651             :         int i;
     652             : 
     653             :         /* Make sure that ROM type is eFuse and that autoload succeeded. */
     654           0 :         reg = rsu_read_1(sc, R92S_EE_9346CR);
     655           0 :         if ((reg & (R92S_9356SEL | R92S_EEPROM_EN)) != R92S_EEPROM_EN)
     656           0 :                 return (EIO);
     657             : 
     658             :         /* Turn on 2.5V to prevent eFuse leakage. */
     659           0 :         reg = rsu_read_1(sc, R92S_EFUSE_TEST + 3);
     660           0 :         rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg | 0x80);
     661           0 :         DELAY(1000);
     662           0 :         rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg & ~0x80);
     663             : 
     664             :         /* Read full ROM image. */
     665           0 :         memset(&sc->rom, 0xff, sizeof(sc->rom));
     666           0 :         while (addr < 512) {
     667           0 :                 reg = rsu_efuse_read_1(sc, addr);
     668           0 :                 if (reg == 0xff)
     669             :                         break;
     670           0 :                 addr++;
     671           0 :                 off = reg >> 4;
     672           0 :                 msk = reg & 0xf;
     673           0 :                 for (i = 0; i < 4; i++) {
     674           0 :                         if (msk & (1 << i))
     675             :                                 continue;
     676           0 :                         rom[off * 8 + i * 2 + 0] =
     677           0 :                             rsu_efuse_read_1(sc, addr);
     678           0 :                         addr++;
     679           0 :                         rom[off * 8 + i * 2 + 1] =
     680           0 :                             rsu_efuse_read_1(sc, addr);
     681           0 :                         addr++;
     682           0 :                 }
     683             :         }
     684             : #ifdef RSU_DEBUG
     685             :         if (rsu_debug >= 5) {
     686             :                 /* Dump ROM content. */
     687             :                 printf("\n");
     688             :                 for (i = 0; i < sizeof(sc->rom); i++)
     689             :                         printf("%02x:", rom[i]);
     690             :                 printf("\n");
     691             :         }
     692             : #endif
     693           0 :         return (0);
     694           0 : }
     695             : 
     696             : int
     697           0 : rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len)
     698             : {
     699             :         struct rsu_tx_data *data;
     700             :         struct r92s_tx_desc *txd;
     701             :         struct r92s_fw_cmd_hdr *cmd;
     702             :         struct usbd_pipe *pipe;
     703             :         int cmdsz, xferlen;
     704             : 
     705           0 :         data = sc->fwcmd_data;
     706             : 
     707             :         /* Round-up command length to a multiple of 8 bytes. */
     708           0 :         cmdsz = (len + 7) & ~7;
     709             : 
     710           0 :         xferlen = sizeof(*txd) + sizeof(*cmd) + cmdsz;
     711           0 :         KASSERT(xferlen <= RSU_TXBUFSZ);
     712           0 :         memset(data->buf, 0, xferlen);
     713             : 
     714             :         /* Setup Tx descriptor. */
     715           0 :         txd = (struct r92s_tx_desc *)data->buf;
     716           0 :         txd->txdw0 = htole32(
     717             :             SM(R92S_TXDW0_OFFSET, sizeof(*txd)) |
     718             :             SM(R92S_TXDW0_PKTLEN, sizeof(*cmd) + cmdsz) |
     719             :             R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG);
     720           0 :         txd->txdw1 = htole32(SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_H2C));
     721             : 
     722             :         /* Setup command header. */
     723           0 :         cmd = (struct r92s_fw_cmd_hdr *)&txd[1];
     724           0 :         cmd->len = htole16(cmdsz);
     725           0 :         cmd->code = code;
     726           0 :         cmd->seq = sc->cmd_seq;
     727           0 :         sc->cmd_seq = (sc->cmd_seq + 1) & 0x7f;
     728             : 
     729             :         /* Copy command payload. */
     730           0 :         memcpy(&cmd[1], buf, len);
     731             : 
     732             :         DPRINTFN(2, ("Tx cmd code=%d len=%d\n", code, cmdsz));
     733           0 :         pipe = sc->pipe[sc->qid2idx[RSU_QID_H2C]];
     734           0 :         usbd_setup_xfer(data->xfer, pipe, NULL, data->buf, xferlen,
     735             :             USBD_SHORT_XFER_OK | USBD_NO_COPY | USBD_SYNCHRONOUS,
     736             :             RSU_CMD_TIMEOUT, NULL);
     737           0 :         return (usbd_transfer(data->xfer));
     738             : }
     739             : 
     740             : int
     741           0 : rsu_media_change(struct ifnet *ifp)
     742             : {
     743             :         int error;
     744             : 
     745           0 :         error = ieee80211_media_change(ifp);
     746           0 :         if (error != ENETRESET)
     747           0 :                 return (error);
     748             : 
     749           0 :         if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
     750             :             (IFF_UP | IFF_RUNNING)) {
     751           0 :                 rsu_stop(ifp);
     752           0 :                 rsu_init(ifp);
     753           0 :         }
     754           0 :         return (0);
     755           0 : }
     756             : 
     757             : void
     758           0 : rsu_calib_to(void *arg)
     759             : {
     760           0 :         struct rsu_softc *sc = arg;
     761             : 
     762           0 :         if (usbd_is_dying(sc->sc_udev))
     763           0 :                 return;
     764             : 
     765           0 :         usbd_ref_incr(sc->sc_udev);
     766             : 
     767             :         /* Do it in a process context. */
     768           0 :         rsu_do_async(sc, rsu_calib_cb, NULL, 0);
     769             : 
     770           0 :         usbd_ref_decr(sc->sc_udev);
     771           0 : }
     772             : 
     773             : /* ARGSUSED */
     774             : void
     775           0 : rsu_calib_cb(struct rsu_softc *sc, void *arg)
     776             : {
     777             :         uint32_t reg;
     778             : 
     779             : #ifdef notyet
     780             :         /* Read WPS PBC status. */
     781             :         rsu_write_1(sc, R92S_MAC_PINMUX_CTRL,
     782             :             R92S_GPIOMUX_EN | SM(R92S_GPIOSEL_GPIO, R92S_GPIOSEL_GPIO_JTAG));
     783             :         rsu_write_1(sc, R92S_GPIO_IO_SEL,
     784             :             rsu_read_1(sc, R92S_GPIO_IO_SEL) & ~R92S_GPIO_WPS);
     785             :         reg = rsu_read_1(sc, R92S_GPIO_CTRL);
     786             :         if (reg != 0xff && (reg & R92S_GPIO_WPS))
     787             :                 DPRINTF(("WPS PBC is pushed\n"));
     788             : #endif
     789             :         /* Read current signal level. */
     790           0 :         if (rsu_fw_iocmd(sc, 0xf4000001) == 0) {
     791           0 :                 reg = rsu_read_4(sc, R92S_IOCMD_DATA);
     792             :                 DPRINTFN(8, ("RSSI=%d%%\n", reg >> 4));
     793           0 :         }
     794             : 
     795           0 :         if (!usbd_is_dying(sc->sc_udev))
     796           0 :                 timeout_add_sec(&sc->calib_to, 2);
     797           0 : }
     798             : 
     799             : int
     800           0 : rsu_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
     801             : {
     802           0 :         struct rsu_softc *sc = ic->ic_softc;
     803           0 :         struct rsu_cmd_newstate cmd;
     804             : 
     805             :         /* Do it in a process context. */
     806           0 :         cmd.state = nstate;
     807           0 :         cmd.arg = arg;
     808           0 :         rsu_do_async(sc, rsu_newstate_cb, &cmd, sizeof(cmd));
     809           0 :         return (0);
     810           0 : }
     811             : 
     812             : void
     813           0 : rsu_newstate_cb(struct rsu_softc *sc, void *arg)
     814             : {
     815           0 :         struct rsu_cmd_newstate *cmd = arg;
     816           0 :         struct ieee80211com *ic = &sc->sc_ic;
     817           0 :         struct ifnet *ifp = &ic->ic_if;
     818             :         enum ieee80211_state ostate;
     819             :         int error, s;
     820             : 
     821           0 :         s = splnet();
     822           0 :         ostate = ic->ic_state;
     823             : 
     824           0 :         if (ostate == IEEE80211_S_RUN) {
     825             :                 /* Stop calibration. */
     826           0 :                 timeout_del(&sc->calib_to);
     827             :                 /* Disassociate from our current BSS. */
     828           0 :                 (void)rsu_disconnect(sc);
     829           0 :         }
     830           0 :         switch (cmd->state) {
     831             :         case IEEE80211_S_INIT:
     832             :                 break;
     833             :         case IEEE80211_S_SCAN:
     834           0 :                 error = rsu_site_survey(sc);
     835           0 :                 if (error != 0) {
     836           0 :                         printf("%s: could not send site survey command\n",
     837           0 :                             sc->sc_dev.dv_xname);
     838           0 :                 }
     839           0 :                 if (ifp->if_flags & IFF_DEBUG)
     840           0 :                         printf("%s: %s -> %s\n", ifp->if_xname,
     841           0 :                             ieee80211_state_name[ic->ic_state],
     842           0 :                             ieee80211_state_name[cmd->state]);
     843           0 :                 ic->ic_state = cmd->state;
     844           0 :                 splx(s);
     845           0 :                 return;
     846             :         case IEEE80211_S_AUTH:
     847           0 :                 ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE;
     848           0 :                 error = rsu_join_bss(sc, ic->ic_bss);
     849           0 :                 if (error != 0) {
     850           0 :                         printf("%s: could not send join command\n",
     851           0 :                             sc->sc_dev.dv_xname);
     852           0 :                         ieee80211_begin_scan(&ic->ic_if);
     853           0 :                         splx(s);
     854           0 :                         return;
     855             :                 }
     856           0 :                 if (ifp->if_flags & IFF_DEBUG)
     857           0 :                         printf("%s: %s -> %s\n", ifp->if_xname,
     858           0 :                             ieee80211_state_name[ic->ic_state],
     859           0 :                             ieee80211_state_name[cmd->state]);
     860           0 :                 ic->ic_state = cmd->state;
     861           0 :                 if (ic->ic_flags & IEEE80211_F_RSNON)
     862           0 :                         ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_PTKSTART;
     863           0 :                 splx(s);
     864           0 :                 return;
     865             :         case IEEE80211_S_ASSOC:
     866             :                 /* No-op for this driver. See rsu_event_join_bss(). */
     867           0 :                 if (ifp->if_flags & IFF_DEBUG)
     868           0 :                         printf("%s: %s -> %s\n", ifp->if_xname,
     869           0 :                             ieee80211_state_name[ic->ic_state],
     870           0 :                             ieee80211_state_name[cmd->state]);
     871           0 :                 ic->ic_state = cmd->state;
     872           0 :                 splx(s);
     873           0 :                 return;
     874             :         case IEEE80211_S_RUN:
     875             :                 /* Indicate highest supported rate. */
     876           0 :                 ic->ic_bss->ni_txrate = ic->ic_bss->ni_rates.rs_nrates - 1;
     877             : 
     878             :                 /* Start periodic calibration. */
     879           0 :                 if (!usbd_is_dying(sc->sc_udev))
     880           0 :                         timeout_add_sec(&sc->calib_to, 2);
     881             :                 break;
     882             :         }
     883           0 :         (void)sc->sc_newstate(ic, cmd->state, cmd->arg);
     884           0 :         splx(s);
     885           0 : }
     886             : 
     887             : int
     888           0 : rsu_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
     889             :     struct ieee80211_key *k)
     890             : {
     891           0 :         struct rsu_softc *sc = ic->ic_softc;
     892           0 :         struct rsu_cmd_key cmd;
     893             : 
     894             :         /* Defer setting of WEP keys until interface is brought up. */
     895           0 :         if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
     896             :             (IFF_UP | IFF_RUNNING))
     897           0 :                 return (0);
     898             : 
     899             :         /* Do it in a process context. */
     900           0 :         cmd.key = *k;
     901           0 :         rsu_do_async(sc, rsu_set_key_cb, &cmd, sizeof(cmd));
     902           0 :         return (0);
     903           0 : }
     904             : 
     905             : void
     906           0 : rsu_set_key_cb(struct rsu_softc *sc, void *arg)
     907             : {
     908           0 :         struct rsu_cmd_key *cmd = arg;
     909           0 :         struct ieee80211_key *k = &cmd->key;
     910           0 :         struct r92s_fw_cmd_set_key key;
     911             : 
     912           0 :         memset(&key, 0, sizeof(key));
     913             :         /* Map net80211 cipher to HW crypto algorithm. */
     914           0 :         switch (k->k_cipher) {
     915             :         case IEEE80211_CIPHER_WEP40:
     916           0 :                 key.algo = R92S_KEY_ALGO_WEP40;
     917           0 :                 break;
     918             :         case IEEE80211_CIPHER_WEP104:
     919           0 :                 key.algo = R92S_KEY_ALGO_WEP104;
     920           0 :                 break;
     921             :         case IEEE80211_CIPHER_TKIP:
     922           0 :                 key.algo = R92S_KEY_ALGO_TKIP;
     923           0 :                 break;
     924             :         case IEEE80211_CIPHER_CCMP:
     925           0 :                 key.algo = R92S_KEY_ALGO_AES;
     926           0 :                 break;
     927             :         default:
     928           0 :                 return;
     929             :         }
     930           0 :         key.id = k->k_id;
     931           0 :         key.grpkey = (k->k_flags & IEEE80211_KEY_GROUP) != 0;
     932           0 :         memcpy(key.key, k->k_key, MIN(k->k_len, sizeof(key.key)));
     933           0 :         (void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
     934           0 : }
     935             : 
     936             : /* ARGSUSED */
     937             : void
     938           0 : rsu_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
     939             :     struct ieee80211_key *k)
     940             : {
     941           0 :         struct rsu_softc *sc = ic->ic_softc;
     942           0 :         struct rsu_cmd_key cmd;
     943             : 
     944           0 :         if (!(ic->ic_if.if_flags & IFF_RUNNING) ||
     945           0 :             ic->ic_state != IEEE80211_S_RUN)
     946           0 :                 return; /* Nothing to do. */
     947             : 
     948             :         /* Do it in a process context. */
     949           0 :         cmd.key = *k;
     950           0 :         rsu_do_async(sc, rsu_delete_key_cb, &cmd, sizeof(cmd));
     951           0 : }
     952             : 
     953             : void
     954           0 : rsu_delete_key_cb(struct rsu_softc *sc, void *arg)
     955             : {
     956           0 :         struct rsu_cmd_key *cmd = arg;
     957           0 :         struct ieee80211_key *k = &cmd->key;
     958           0 :         struct r92s_fw_cmd_set_key key;
     959             : 
     960           0 :         memset(&key, 0, sizeof(key));
     961           0 :         key.id = k->k_id;
     962           0 :         (void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
     963           0 : }
     964             : 
     965             : int
     966           0 : rsu_site_survey(struct rsu_softc *sc)
     967             : {
     968           0 :         struct ieee80211com *ic = &sc->sc_ic;
     969           0 :         struct r92s_fw_cmd_sitesurvey cmd;
     970             : 
     971           0 :         memset(&cmd, 0, sizeof(cmd));
     972           0 :         if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->scan_pass == 1)
     973           0 :                 cmd.active = htole32(1);
     974           0 :         cmd.limit = htole32(48);
     975           0 :         if (sc->scan_pass == 1) {
     976             :                 /* Do a directed scan for second pass. */
     977           0 :                 cmd.ssidlen = htole32(ic->ic_des_esslen);
     978           0 :                 memcpy(cmd.ssid, ic->ic_des_essid, ic->ic_des_esslen);
     979           0 :         }
     980             :         DPRINTF(("sending site survey command, pass=%d\n", sc->scan_pass));
     981           0 :         return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd)));
     982           0 : }
     983             : 
     984             : int
     985           0 : rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
     986             : {
     987           0 :         struct ieee80211com *ic = &sc->sc_ic;
     988             :         struct ndis_wlan_bssid_ex *bss;
     989             :         struct ndis_802_11_fixed_ies *fixed;
     990           0 :         struct r92s_fw_cmd_auth auth;
     991           0 :         uint8_t buf[sizeof(*bss) + 128], *frm;
     992           0 :         uint8_t opmode;
     993             :         int error;
     994             : 
     995             :         /* Let the FW decide the opmode based on the capinfo field. */
     996           0 :         opmode = NDIS802_11AUTOUNKNOWN;
     997             :         DPRINTF(("setting operating mode to %d\n", opmode));
     998           0 :         error = rsu_fw_cmd(sc, R92S_CMD_SET_OPMODE, &opmode, sizeof(opmode));
     999           0 :         if (error != 0)
    1000           0 :                 return (error);
    1001             : 
    1002           0 :         memset(&auth, 0, sizeof(auth));
    1003           0 :         if (ic->ic_flags & IEEE80211_F_RSNON) {
    1004           0 :                 auth.mode = R92S_AUTHMODE_WPA;
    1005           0 :                 auth.dot1x = ieee80211_is_8021x_akm(ni->ni_rsnakms);
    1006           0 :         } else
    1007           0 :                 auth.mode = R92S_AUTHMODE_OPEN;
    1008             :         DPRINTF(("setting auth mode to %d\n", auth.mode));
    1009           0 :         error = rsu_fw_cmd(sc, R92S_CMD_SET_AUTH, &auth, sizeof(auth));
    1010           0 :         if (error != 0)
    1011           0 :                 return (error);
    1012             : 
    1013           0 :         memset(buf, 0, sizeof(buf));
    1014           0 :         bss = (struct ndis_wlan_bssid_ex *)buf;
    1015           0 :         IEEE80211_ADDR_COPY(bss->macaddr, ni->ni_bssid);
    1016           0 :         bss->ssid.ssidlen = htole32(ni->ni_esslen);
    1017           0 :         memcpy(bss->ssid.ssid, ni->ni_essid, ni->ni_esslen);
    1018           0 :         if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON))
    1019           0 :                 bss->privacy = htole32(1);
    1020           0 :         bss->rssi = htole32(ni->ni_rssi);
    1021           0 :         if (ic->ic_curmode == IEEE80211_MODE_11B)
    1022           0 :                 bss->networktype = htole32(NDIS802_11DS);
    1023             :         else
    1024           0 :                 bss->networktype = htole32(NDIS802_11OFDM24);
    1025           0 :         bss->config.len = htole32(sizeof(bss->config));
    1026           0 :         bss->config.bintval = htole32(ni->ni_intval);
    1027           0 :         bss->config.dsconfig = htole32(ieee80211_chan2ieee(ic, ni->ni_chan));
    1028           0 :         bss->inframode = htole32(NDIS802_11INFRASTRUCTURE);
    1029           0 :         memcpy(bss->supprates, ni->ni_rates.rs_rates,
    1030             :             ni->ni_rates.rs_nrates);
    1031             :         /* Write the fixed fields of the beacon frame. */
    1032           0 :         fixed = (struct ndis_802_11_fixed_ies *)&bss[1];
    1033           0 :         memcpy(&fixed->tstamp, ni->ni_tstamp, 8);
    1034           0 :         fixed->bintval = htole16(ni->ni_intval);
    1035           0 :         fixed->capabilities = htole16(ni->ni_capinfo);
    1036             :         /* Write IEs to be included in the association request. */
    1037           0 :         frm = (uint8_t *)&fixed[1];
    1038           0 :         if ((ic->ic_flags & IEEE80211_F_RSNON) &&
    1039           0 :             (ni->ni_rsnprotos & IEEE80211_PROTO_RSN))
    1040           0 :                 frm = ieee80211_add_rsn(frm, ic, ni);
    1041           0 :         if (ni->ni_flags & IEEE80211_NODE_QOS)
    1042           0 :                 frm = ieee80211_add_qos_capability(frm, ic);
    1043           0 :         if (ni->ni_flags & IEEE80211_NODE_HT)
    1044           0 :                 frm = ieee80211_add_htcaps(frm, ic);
    1045           0 :         if ((ic->ic_flags & IEEE80211_F_RSNON) &&
    1046           0 :             (ni->ni_rsnprotos & IEEE80211_PROTO_WPA))
    1047           0 :                 frm = ieee80211_add_wpa(frm, ic, ni);
    1048           0 :         bss->ieslen = htole32(frm - (uint8_t *)fixed);
    1049           0 :         bss->len = htole32(((frm - buf) + 3) & ~3);
    1050             :         DPRINTF(("sending join bss command to %s chan %d\n",
    1051             :             ether_sprintf(bss->macaddr), letoh32(bss->config.dsconfig)));
    1052           0 :         return (rsu_fw_cmd(sc, R92S_CMD_JOIN_BSS, buf, sizeof(buf)));
    1053           0 : }
    1054             : 
    1055             : int
    1056           0 : rsu_disconnect(struct rsu_softc *sc)
    1057             : {
    1058           0 :         uint32_t zero = 0;      /* :-) */
    1059             : 
    1060             :         /* Disassociate from our current BSS. */
    1061             :         DPRINTF(("sending disconnect command\n"));
    1062           0 :         return (rsu_fw_cmd(sc, R92S_CMD_DISCONNECT, &zero, sizeof(zero)));
    1063           0 : }
    1064             : 
    1065             : void
    1066           0 : rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
    1067             : {
    1068           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1069           0 :         struct ifnet *ifp = &ic->ic_if;
    1070           0 :         struct ieee80211_rxinfo rxi;
    1071             :         struct ieee80211_node *ni;
    1072             :         struct ieee80211_frame *wh;
    1073             :         struct ndis_wlan_bssid_ex *bss;
    1074             :         struct mbuf *m;
    1075             :         uint32_t pktlen, ieslen;
    1076             : 
    1077           0 :         if (__predict_false(len < sizeof(*bss)))
    1078           0 :                 return;
    1079           0 :         bss = (struct ndis_wlan_bssid_ex *)buf;
    1080           0 :         ieslen = letoh32(bss->ieslen);
    1081           0 :         if (ieslen > len - sizeof(*bss))
    1082           0 :                 return;
    1083             : 
    1084             :         DPRINTFN(2, ("found BSS %s: len=%d chan=%d inframode=%d "
    1085             :             "networktype=%d privacy=%d\n",
    1086             :             ether_sprintf(bss->macaddr), letoh32(bss->len),
    1087             :             letoh32(bss->config.dsconfig), letoh32(bss->inframode),
    1088             :             letoh32(bss->networktype), letoh32(bss->privacy)));
    1089             : 
    1090             :         /* Build a fake beacon frame to let net80211 do all the parsing. */
    1091           0 :         pktlen = sizeof(*wh) + ieslen;
    1092           0 :         if (__predict_false(pktlen > MCLBYTES))
    1093           0 :                 return;
    1094           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
    1095           0 :         if (__predict_false(m == NULL))
    1096           0 :                 return;
    1097           0 :         if (pktlen > MHLEN) {
    1098           0 :                 MCLGET(m, M_DONTWAIT);
    1099           0 :                 if (!(m->m_flags & M_EXT)) {
    1100           0 :                         m_free(m);
    1101           0 :                         return;
    1102             :                 }
    1103             :         }
    1104           0 :         wh = mtod(m, struct ieee80211_frame *);
    1105           0 :         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
    1106             :             IEEE80211_FC0_SUBTYPE_BEACON;
    1107           0 :         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
    1108           0 :         *(uint16_t *)wh->i_dur = 0;
    1109           0 :         IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
    1110           0 :         IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr);
    1111           0 :         IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr);
    1112           0 :         *(uint16_t *)wh->i_seq = 0;
    1113           0 :         memcpy(&wh[1], (uint8_t *)&bss[1], ieslen);
    1114             : 
    1115             :         /* Finalize mbuf. */
    1116           0 :         m->m_pkthdr.len = m->m_len = pktlen;
    1117             : 
    1118           0 :         ni = ieee80211_find_rxnode(ic, wh);
    1119           0 :         rxi.rxi_flags = 0;
    1120           0 :         rxi.rxi_rssi = letoh32(bss->rssi);
    1121           0 :         rxi.rxi_tstamp = 0;
    1122           0 :         ieee80211_input(ifp, m, ni, &rxi);
    1123             :         /* Node is no longer needed. */
    1124           0 :         ieee80211_release_node(ic, ni);
    1125           0 : }
    1126             : 
    1127             : void
    1128           0 : rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len)
    1129             : {
    1130           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1131           0 :         struct ieee80211_node *ni = ic->ic_bss;
    1132             :         struct r92s_event_join_bss *rsp;
    1133             :         int res;
    1134             : 
    1135           0 :         if (__predict_false(len < sizeof(*rsp)))
    1136           0 :                 return;
    1137           0 :         rsp = (struct r92s_event_join_bss *)buf;
    1138           0 :         res = (int)letoh32(rsp->join_res);
    1139             : 
    1140             :         DPRINTF(("Rx join BSS event len=%d res=%d\n", len, res));
    1141           0 :         if (res <= 0) {
    1142           0 :                 ic->ic_stats.is_rx_auth_fail++;
    1143           0 :                 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    1144           0 :                 return;
    1145             :         }
    1146             :         DPRINTF(("associated with %s associd=%d\n",
    1147             :             ether_sprintf(rsp->bss.macaddr), letoh32(rsp->associd)));
    1148             : 
    1149           0 :         ni->ni_associd = letoh32(rsp->associd) | 0xc000;
    1150           0 :         if (ic->ic_flags & IEEE80211_F_WEPON)
    1151           0 :                 ni->ni_flags |= IEEE80211_NODE_TXRXPROT;
    1152             : 
    1153             :         /* Force an ASSOC->RUN transition. AUTH->RUN is invalid. */
    1154           0 :         ic->ic_state = IEEE80211_S_ASSOC;
    1155           0 :         ieee80211_new_state(ic, IEEE80211_S_RUN,
    1156             :             IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
    1157           0 : }
    1158             : 
    1159             : void
    1160           0 : rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len)
    1161             : {
    1162           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1163           0 :         struct ifnet *ifp = &ic->ic_if;
    1164             : 
    1165             :         DPRINTFN(4, ("Rx event code=%d len=%d\n", code, len));
    1166           0 :         switch (code) {
    1167             :         case R92S_EVT_SURVEY:
    1168           0 :                 if (ic->ic_state == IEEE80211_S_SCAN)
    1169           0 :                         rsu_event_survey(sc, buf, len);
    1170             :                 break;
    1171             :         case R92S_EVT_SURVEY_DONE:
    1172             :                 DPRINTF(("site survey pass %d done, found %d BSS\n",
    1173             :                     sc->scan_pass, letoh32(*(uint32_t *)buf)));
    1174           0 :                 if (ic->ic_state != IEEE80211_S_SCAN)
    1175             :                         break;  /* Ignore if not scanning. */
    1176           0 :                 if (sc->scan_pass == 0 && ic->ic_des_esslen != 0) {
    1177             :                         /* Schedule a directed scan for hidden APs. */
    1178           0 :                         sc->scan_pass = 1;
    1179           0 :                         ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    1180           0 :                         break;
    1181             :                 }
    1182           0 :                 ieee80211_end_scan(ifp);
    1183           0 :                 sc->scan_pass = 0;
    1184           0 :                 break;
    1185             :         case R92S_EVT_JOIN_BSS:
    1186           0 :                 if (ic->ic_state == IEEE80211_S_AUTH)
    1187           0 :                         rsu_event_join_bss(sc, buf, len);
    1188             :                 break;
    1189             :         case R92S_EVT_DEL_STA:
    1190             :                 DPRINTF(("disassociated from %s\n", ether_sprintf(buf)));
    1191           0 :                 if (ic->ic_state == IEEE80211_S_RUN &&
    1192           0 :                     IEEE80211_ADDR_EQ(ic->ic_bss->ni_bssid, buf))
    1193           0 :                         ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    1194             :                 break;
    1195             :         case R92S_EVT_WPS_PBC:
    1196             :                 DPRINTF(("WPS PBC pushed.\n"));
    1197             :                 break;
    1198             :         case R92S_EVT_FWDBG:
    1199           0 :                 if (ifp->if_flags & IFF_DEBUG) {
    1200           0 :                         buf[60] = '\0';
    1201           0 :                         printf("FWDBG: %s\n", (char *)buf);
    1202           0 :                 }
    1203             :                 break;
    1204             :         }
    1205           0 : }
    1206             : 
    1207             : void
    1208           0 : rsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len)
    1209             : {
    1210             :         struct r92s_fw_cmd_hdr *cmd;
    1211             :         int cmdsz;
    1212             : 
    1213             :         DPRINTFN(6, ("Rx events len=%d\n", len));
    1214             : 
    1215             :         /* Skip Rx status. */
    1216           0 :         buf += sizeof(struct r92s_rx_stat);
    1217           0 :         len -= sizeof(struct r92s_rx_stat);
    1218             : 
    1219             :         /* Process all events. */
    1220           0 :         for (;;) {
    1221             :                 /* Check that command header fits. */
    1222           0 :                 if (__predict_false(len < sizeof(*cmd)))
    1223             :                         break;
    1224           0 :                 cmd = (struct r92s_fw_cmd_hdr *)buf;
    1225             :                 /* Check that command payload fits. */
    1226           0 :                 cmdsz = letoh16(cmd->len);
    1227           0 :                 if (__predict_false(len < sizeof(*cmd) + cmdsz))
    1228             :                         break;
    1229           0 :                 if (cmdsz > len)
    1230             :                         break;
    1231             : 
    1232             :                 /* Process firmware event. */
    1233           0 :                 rsu_rx_event(sc, cmd->code, (uint8_t *)&cmd[1], cmdsz);
    1234             : 
    1235           0 :                 if (!(cmd->seq & R92S_FW_CMD_MORE))
    1236             :                         break;
    1237           0 :                 buf += sizeof(*cmd) + cmdsz;
    1238           0 :                 len -= sizeof(*cmd) + cmdsz;
    1239             :         }
    1240           0 : }
    1241             : 
    1242             : int8_t
    1243           0 : rsu_get_rssi(struct rsu_softc *sc, int rate, void *physt)
    1244             : {
    1245             :         static const int8_t cckoff[] = { 14, -2, -20, -40 };
    1246             :         struct r92s_rx_phystat *phy;
    1247             :         struct r92s_rx_cck *cck;
    1248             :         uint8_t rpt;
    1249             :         int8_t rssi;
    1250             : 
    1251           0 :         if (rate <= 3) {
    1252           0 :                 cck = (struct r92s_rx_cck *)physt;
    1253           0 :                 rpt = (cck->agc_rpt >> 6) & 0x3;
    1254           0 :                 rssi = cck->agc_rpt & 0x3e;
    1255           0 :                 rssi = cckoff[rpt] - rssi;
    1256           0 :         } else {        /* OFDM/HT. */
    1257           0 :                 phy = (struct r92s_rx_phystat *)physt;
    1258           0 :                 rssi = ((letoh32(phy->phydw1) >> 1) & 0x7f) - 106;
    1259             :         }
    1260           0 :         return (rssi);
    1261             : }
    1262             : 
    1263             : void
    1264           0 : rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen)
    1265             : {
    1266           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1267           0 :         struct ifnet *ifp = &ic->ic_if;
    1268           0 :         struct ieee80211_rxinfo rxi;
    1269             :         struct ieee80211_frame *wh;
    1270             :         struct ieee80211_node *ni;
    1271             :         struct r92s_rx_stat *stat;
    1272             :         uint32_t rxdw0, rxdw3;
    1273             :         struct mbuf *m;
    1274             :         uint8_t rate;
    1275             :         int8_t rssi = 0;
    1276             :         int s, infosz;
    1277             : 
    1278           0 :         stat = (struct r92s_rx_stat *)buf;
    1279           0 :         rxdw0 = letoh32(stat->rxdw0);
    1280           0 :         rxdw3 = letoh32(stat->rxdw3);
    1281             : 
    1282           0 :         if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) {
    1283           0 :                 ifp->if_ierrors++;
    1284           0 :                 return;
    1285             :         }
    1286           0 :         if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) {
    1287           0 :                 ifp->if_ierrors++;
    1288           0 :                 return;
    1289             :         }
    1290             : 
    1291           0 :         rate = MS(rxdw3, R92S_RXDW3_RATE);
    1292           0 :         infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
    1293             : 
    1294             :         /* Get RSSI from PHY status descriptor if present. */
    1295           0 :         if (infosz != 0)
    1296           0 :                 rssi = rsu_get_rssi(sc, rate, &stat[1]);
    1297             : 
    1298             :         DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d rssi=%d\n",
    1299             :             pktlen, rate, infosz, rssi));
    1300             : 
    1301           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
    1302           0 :         if (__predict_false(m == NULL)) {
    1303           0 :                 ifp->if_ierrors++;
    1304           0 :                 return;
    1305             :         }
    1306           0 :         if (pktlen > MHLEN) {
    1307           0 :                 MCLGET(m, M_DONTWAIT);
    1308           0 :                 if (__predict_false(!(m->m_flags & M_EXT))) {
    1309           0 :                         ifp->if_ierrors++;
    1310           0 :                         m_freem(m);
    1311           0 :                         return;
    1312             :                 }
    1313             :         }
    1314             :         /* Finalize mbuf. */
    1315             :         /* Hardware does Rx TCP checksum offload. */
    1316           0 :         if (rxdw3 & R92S_RXDW3_TCPCHKVALID) {
    1317           0 :                 if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT))
    1318           0 :                         m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
    1319             :                 else
    1320           0 :                         m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_BAD;
    1321             :         }
    1322           0 :         wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz);
    1323           0 :         memcpy(mtod(m, uint8_t *), wh, pktlen);
    1324           0 :         m->m_pkthdr.len = m->m_len = pktlen;
    1325             : 
    1326           0 :         s = splnet();
    1327             : #if NBPFILTER > 0
    1328           0 :         if (__predict_false(sc->sc_drvbpf != NULL)) {
    1329           0 :                 struct rsu_rx_radiotap_header *tap = &sc->sc_rxtap;
    1330           0 :                 struct mbuf mb;
    1331             : 
    1332           0 :                 tap->wr_flags = 0;
    1333             :                 /* Map HW rate index to 802.11 rate. */
    1334           0 :                 tap->wr_flags = 2;
    1335           0 :                 if (!(rxdw3 & R92S_RXDW3_HTC)) {
    1336           0 :                         switch (rate) {
    1337             :                         /* CCK. */
    1338           0 :                         case  0: tap->wr_rate =   2; break;
    1339           0 :                         case  1: tap->wr_rate =   4; break;
    1340           0 :                         case  2: tap->wr_rate =  11; break;
    1341           0 :                         case  3: tap->wr_rate =  22; break;
    1342             :                         /* OFDM. */
    1343           0 :                         case  4: tap->wr_rate =  12; break;
    1344           0 :                         case  5: tap->wr_rate =  18; break;
    1345           0 :                         case  6: tap->wr_rate =  24; break;
    1346           0 :                         case  7: tap->wr_rate =  36; break;
    1347           0 :                         case  8: tap->wr_rate =  48; break;
    1348           0 :                         case  9: tap->wr_rate =  72; break;
    1349           0 :                         case 10: tap->wr_rate =  96; break;
    1350           0 :                         case 11: tap->wr_rate = 108; break;
    1351             :                         }
    1352           0 :                 } else if (rate >= 12) {     /* MCS0~15. */
    1353             :                         /* Bit 7 set means HT MCS instead of rate. */
    1354           0 :                         tap->wr_rate = 0x80 | (rate - 12);
    1355           0 :                 }
    1356           0 :                 tap->wr_dbm_antsignal = rssi;
    1357           0 :                 tap->wr_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
    1358           0 :                 tap->wr_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
    1359             : 
    1360           0 :                 mb.m_data = (caddr_t)tap;
    1361           0 :                 mb.m_len = sc->sc_rxtap_len;
    1362           0 :                 mb.m_next = m;
    1363           0 :                 mb.m_nextpkt = NULL;
    1364           0 :                 mb.m_type = 0;
    1365           0 :                 mb.m_flags = 0;
    1366           0 :                 bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
    1367           0 :         }
    1368             : #endif
    1369             : 
    1370           0 :         ni = ieee80211_find_rxnode(ic, wh);
    1371           0 :         rxi.rxi_flags = 0;
    1372           0 :         rxi.rxi_rssi = rssi;
    1373           0 :         rxi.rxi_tstamp = 0;     /* Unused. */
    1374           0 :         ieee80211_input(ifp, m, ni, &rxi);
    1375             :         /* Node is no longer needed. */
    1376           0 :         ieee80211_release_node(ic, ni);
    1377           0 :         splx(s);
    1378           0 : }
    1379             : 
    1380             : void
    1381           0 : rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len)
    1382             : {
    1383             :         struct r92s_rx_stat *stat;
    1384             :         uint32_t rxdw0;
    1385             :         int totlen, pktlen, infosz, npkts;
    1386             : 
    1387             :         /* Get the number of encapsulated frames. */
    1388           0 :         stat = (struct r92s_rx_stat *)buf;
    1389           0 :         npkts = MS(letoh32(stat->rxdw2), R92S_RXDW2_PKTCNT);
    1390             :         DPRINTFN(6, ("Rx %d frames in one chunk\n", npkts));
    1391             : 
    1392             :         /* Process all of them. */
    1393           0 :         while (npkts-- > 0) {
    1394           0 :                 if (__predict_false(len < sizeof(*stat)))
    1395             :                         break;
    1396           0 :                 stat = (struct r92s_rx_stat *)buf;
    1397           0 :                 rxdw0 = letoh32(stat->rxdw0);
    1398             : 
    1399           0 :                 pktlen = MS(rxdw0, R92S_RXDW0_PKTLEN);
    1400           0 :                 if (__predict_false(pktlen == 0))
    1401             :                         break;
    1402             : 
    1403           0 :                 infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
    1404             : 
    1405             :                 /* Make sure everything fits in xfer. */
    1406           0 :                 totlen = sizeof(*stat) + infosz + pktlen;
    1407           0 :                 if (__predict_false(totlen > len))
    1408             :                         break;
    1409             : 
    1410             :                 /* Process 802.11 frame. */
    1411           0 :                 rsu_rx_frame(sc, buf, pktlen);
    1412             : 
    1413             :                 /* Next chunk is 128-byte aligned. */
    1414           0 :                 totlen = (totlen + 127) & ~127;
    1415           0 :                 buf += totlen;
    1416           0 :                 len -= totlen;
    1417             :         }
    1418           0 : }
    1419             : 
    1420             : void
    1421           0 : rsu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
    1422             : {
    1423           0 :         struct rsu_rx_data *data = priv;
    1424           0 :         struct rsu_softc *sc = data->sc;
    1425             :         struct r92s_rx_stat *stat;
    1426           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
    1427           0 :         int len;
    1428             : 
    1429           0 :         if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
    1430             :                 DPRINTF(("RX status=%d\n", status));
    1431           0 :                 if (status == USBD_STALLED)
    1432           0 :                         usbd_clear_endpoint_stall_async(data->pipe);
    1433           0 :                 if (status != USBD_CANCELLED)
    1434             :                         goto resubmit;
    1435           0 :                 return;
    1436             :         }
    1437           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
    1438             : 
    1439           0 :         if (__predict_false(len < sizeof(*stat))) {
    1440             :                 DPRINTF(("xfer too short %d\n", len));
    1441           0 :                 ifp->if_ierrors++;
    1442           0 :                 goto resubmit;
    1443             :         }
    1444           0 :         if (len > RSU_RXBUFSZ) {
    1445             :                 DPRINTF(("xfer too large %d\n", len));
    1446           0 :                 ifp->if_ierrors++;
    1447           0 :                 goto resubmit;
    1448             :         }
    1449             :                 
    1450             :         /* Determine if it is a firmware C2H event or an 802.11 frame. */
    1451           0 :         stat = (struct r92s_rx_stat *)data->buf;
    1452           0 :         if ((letoh32(stat->rxdw1) & 0x1ff) == 0x1ff)
    1453           0 :                 rsu_rx_multi_event(sc, data->buf, len);
    1454             :         else
    1455           0 :                 rsu_rx_multi_frame(sc, data->buf, len);
    1456             : 
    1457             :  resubmit:
    1458             :         /* Setup a new transfer. */
    1459           0 :         usbd_setup_xfer(xfer, data->pipe, data, data->buf, RSU_RXBUFSZ,
    1460             :             USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, rsu_rxeof);
    1461           0 :         (void)usbd_transfer(xfer);
    1462           0 : }
    1463             : 
    1464             : void
    1465           0 : rsu_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
    1466             : {
    1467           0 :         struct rsu_tx_data *data = priv;
    1468           0 :         struct rsu_softc *sc = data->sc;
    1469           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
    1470             :         int s;
    1471             : 
    1472           0 :         s = splnet();
    1473             :         /* Put this Tx buffer back to our free list. */
    1474           0 :         TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
    1475             : 
    1476           0 :         if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
    1477             :                 DPRINTF(("TX status=%d\n", status));
    1478           0 :                 if (status == USBD_STALLED)
    1479           0 :                         usbd_clear_endpoint_stall_async(data->pipe);
    1480           0 :                 ifp->if_oerrors++;
    1481           0 :                 splx(s);
    1482           0 :                 return;
    1483             :         }
    1484           0 :         sc->sc_tx_timer = 0;
    1485             : 
    1486             :         /* We just released a Tx buffer, notify Tx. */
    1487           0 :         if (ifq_is_oactive(&ifp->if_snd)) {
    1488           0 :                 ifq_clr_oactive(&ifp->if_snd);
    1489           0 :                 rsu_start(ifp);
    1490           0 :         }
    1491           0 :         splx(s);
    1492           0 : }
    1493             : 
    1494             : int
    1495           0 : rsu_tx(struct rsu_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
    1496             : {
    1497           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1498             :         struct ieee80211_frame *wh;
    1499             :         struct ieee80211_key *k = NULL;
    1500             :         struct rsu_tx_data *data;
    1501             :         struct r92s_tx_desc *txd;
    1502             :         struct usbd_pipe *pipe;
    1503             :         uint16_t qos;
    1504             :         uint8_t type, qid, tid = 0;
    1505             :         int hasqos, xferlen, error;
    1506             : 
    1507           0 :         wh = mtod(m, struct ieee80211_frame *);
    1508           0 :         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
    1509             : 
    1510           0 :         if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
    1511           0 :                 k = ieee80211_get_txkey(ic, wh, ni);
    1512           0 :                 if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
    1513           0 :                         return (ENOBUFS);
    1514           0 :                 wh = mtod(m, struct ieee80211_frame *);
    1515           0 :         }
    1516           0 :         if ((hasqos = ieee80211_has_qos(wh))) {
    1517           0 :                 qos = ieee80211_get_qos(wh);
    1518           0 :                 tid = qos & IEEE80211_QOS_TID;
    1519           0 :                 qid = rsu_ac2qid[ieee80211_up_to_ac(ic, tid)];
    1520           0 :         } else
    1521             :                 qid = RSU_QID_BE;
    1522             : 
    1523             :         /* Get the USB pipe to use for this queue id. */
    1524           0 :         pipe = sc->pipe[sc->qid2idx[qid]];
    1525             : 
    1526             :         /* Grab a Tx buffer from our free list. */
    1527           0 :         data = TAILQ_FIRST(&sc->tx_free_list);
    1528           0 :         TAILQ_REMOVE(&sc->tx_free_list, data, next);
    1529             : 
    1530             :         /* Fill Tx descriptor. */
    1531           0 :         txd = (struct r92s_tx_desc *)data->buf;
    1532           0 :         memset(txd, 0, sizeof(*txd));
    1533             : 
    1534           0 :         txd->txdw0 |= htole32(
    1535             :             SM(R92S_TXDW0_PKTLEN, m->m_pkthdr.len) |
    1536             :             SM(R92S_TXDW0_OFFSET, sizeof(*txd)) |
    1537             :             R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG);
    1538             : 
    1539           0 :         txd->txdw1 |= htole32(
    1540             :             SM(R92S_TXDW1_MACID, R92S_MACID_BSS) |
    1541             :             SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_BE));
    1542           0 :         if (!hasqos)
    1543           0 :                 txd->txdw1 |= htole32(R92S_TXDW1_NONQOS);
    1544             : #ifdef notyet
    1545             :         if (k != NULL) {
    1546             :                 switch (k->k_cipher) {
    1547             :                 case IEEE80211_CIPHER_WEP40:
    1548             :                 case IEEE80211_CIPHER_WEP104:
    1549             :                         cipher = R92S_TXDW1_CIPHER_WEP;
    1550             :                         break;
    1551             :                 case IEEE80211_CIPHER_TKIP:
    1552             :                         cipher = R92S_TXDW1_CIPHER_TKIP;
    1553             :                         break;
    1554             :                 case IEEE80211_CIPHER_CCMP:
    1555             :                         cipher = R92S_TXDW1_CIPHER_AES;
    1556             :                         break;
    1557             :                 default:
    1558             :                         cipher = R92S_TXDW1_CIPHER_NONE;
    1559             :                 }
    1560             :                 txd->txdw1 |= htole32(
    1561             :                     SM(R92S_TXDW1_CIPHER, cipher) |
    1562             :                     SM(R92S_TXDW1_KEYIDX, k->k_id));
    1563             :         }
    1564             : #endif
    1565           0 :         txd->txdw2 |= htole32(R92S_TXDW2_BK);
    1566           0 :         if (IEEE80211_IS_MULTICAST(wh->i_addr1))
    1567           0 :                 txd->txdw2 |= htole32(R92S_TXDW2_BMCAST);
    1568             :         /*
    1569             :          * Firmware will use and increment the sequence number for the
    1570             :          * specified TID.
    1571             :          */
    1572           0 :         txd->txdw3 |= htole32(SM(R92S_TXDW3_SEQ, tid));
    1573             : 
    1574             : #if NBPFILTER > 0
    1575           0 :         if (__predict_false(sc->sc_drvbpf != NULL)) {
    1576           0 :                 struct rsu_tx_radiotap_header *tap = &sc->sc_txtap;
    1577           0 :                 struct mbuf mb;
    1578             : 
    1579           0 :                 tap->wt_flags = 0;
    1580           0 :                 tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
    1581           0 :                 tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
    1582             : 
    1583           0 :                 mb.m_data = (caddr_t)tap;
    1584           0 :                 mb.m_len = sc->sc_txtap_len;
    1585           0 :                 mb.m_next = m;
    1586           0 :                 mb.m_nextpkt = NULL;
    1587           0 :                 mb.m_type = 0;
    1588           0 :                 mb.m_flags = 0;
    1589           0 :                 bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
    1590           0 :         }
    1591             : #endif
    1592             : 
    1593           0 :         xferlen = sizeof(*txd) + m->m_pkthdr.len;
    1594           0 :         m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]);
    1595           0 :         m_freem(m);
    1596             : 
    1597           0 :         data->pipe = pipe;
    1598           0 :         usbd_setup_xfer(data->xfer, pipe, data, data->buf, xferlen,
    1599             :             USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RSU_TX_TIMEOUT,
    1600             :             rsu_txeof);
    1601           0 :         error = usbd_transfer(data->xfer);
    1602           0 :         if (__predict_false(error != USBD_IN_PROGRESS && error != 0)) {
    1603             :                 /* Put this Tx buffer back to our free list. */
    1604           0 :                 TAILQ_INSERT_TAIL(&sc->tx_free_list, data, next);
    1605           0 :                 return (error);
    1606             :         }
    1607           0 :         ieee80211_release_node(ic, ni);
    1608           0 :         return (0);
    1609           0 : }
    1610             : 
    1611             : /* ARGSUSED */
    1612             : int
    1613           0 : rsu_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, int type,
    1614             :     int arg1, int arg2)
    1615             : {
    1616           0 :         return (EOPNOTSUPP);
    1617             : }
    1618             : 
    1619             : void
    1620           0 : rsu_start(struct ifnet *ifp)
    1621             : {
    1622           0 :         struct rsu_softc *sc = ifp->if_softc;
    1623           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1624           0 :         struct ieee80211_node *ni;
    1625             :         struct mbuf *m;
    1626             : 
    1627           0 :         if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
    1628           0 :                 return;
    1629             : 
    1630           0 :         for (;;) {
    1631           0 :                 if (TAILQ_EMPTY(&sc->tx_free_list)) {
    1632           0 :                         ifq_set_oactive(&ifp->if_snd);
    1633           0 :                         break;
    1634             :                 }
    1635           0 :                 if (ic->ic_state != IEEE80211_S_RUN)
    1636             :                         break;
    1637             : 
    1638             :                 /* Encapsulate and send data frames. */
    1639           0 :                 IFQ_DEQUEUE(&ifp->if_snd, m);
    1640           0 :                 if (m == NULL)
    1641             :                         break;
    1642             : #if NBPFILTER > 0
    1643           0 :                 if (ifp->if_bpf != NULL)
    1644           0 :                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
    1645             : #endif
    1646           0 :                 if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
    1647           0 :                         continue;
    1648             : 
    1649             : #if NBPFILTER > 0
    1650           0 :                 if (ic->ic_rawbpf != NULL)
    1651           0 :                         bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
    1652             : #endif
    1653           0 :                 if (rsu_tx(sc, m, ni) != 0) {
    1654           0 :                         ieee80211_release_node(ic, ni);
    1655           0 :                         ifp->if_oerrors++;
    1656           0 :                         continue;
    1657             :                 }
    1658             : 
    1659           0 :                 sc->sc_tx_timer = 5;
    1660           0 :                 ifp->if_timer = 1;
    1661             :         }
    1662           0 : }
    1663             : 
    1664             : void
    1665           0 : rsu_watchdog(struct ifnet *ifp)
    1666             : {
    1667           0 :         struct rsu_softc *sc = ifp->if_softc;
    1668             : 
    1669           0 :         ifp->if_timer = 0;
    1670             : 
    1671           0 :         if (sc->sc_tx_timer > 0) {
    1672           0 :                 if (--sc->sc_tx_timer == 0) {
    1673           0 :                         printf("%s: device timeout\n", sc->sc_dev.dv_xname);
    1674             :                         /* rsu_init(ifp); XXX needs a process context! */
    1675           0 :                         ifp->if_oerrors++;
    1676           0 :                         return;
    1677             :                 }
    1678           0 :                 ifp->if_timer = 1;
    1679           0 :         }
    1680           0 :         ieee80211_watchdog(ifp);
    1681           0 : }
    1682             : 
    1683             : int
    1684           0 : rsu_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    1685             : {
    1686           0 :         struct rsu_softc *sc = ifp->if_softc;
    1687             :         int s, error = 0;
    1688             : 
    1689           0 :         if (usbd_is_dying(sc->sc_udev))
    1690           0 :                 return ENXIO;
    1691             : 
    1692           0 :         usbd_ref_incr(sc->sc_udev);
    1693             : 
    1694           0 :         s = splnet();
    1695             : 
    1696           0 :         switch (cmd) {
    1697             :         case SIOCSIFADDR:
    1698           0 :                 ifp->if_flags |= IFF_UP;
    1699             :                 /* FALLTHROUGH */
    1700             :         case SIOCSIFFLAGS:
    1701           0 :                 if (ifp->if_flags & IFF_UP) {
    1702           0 :                         if (!(ifp->if_flags & IFF_RUNNING))
    1703           0 :                                 rsu_init(ifp);
    1704             :                 } else {
    1705           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1706           0 :                                 rsu_stop(ifp);
    1707             :                 }
    1708             :                 break;
    1709             :         default:
    1710           0 :                 error = ieee80211_ioctl(ifp, cmd, data);
    1711           0 :         }
    1712             : 
    1713           0 :         if (error == ENETRESET) {
    1714           0 :                 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
    1715             :                     (IFF_UP | IFF_RUNNING)) {
    1716           0 :                         rsu_stop(ifp);
    1717           0 :                         rsu_init(ifp);
    1718           0 :                 }
    1719             :                 error = 0;
    1720           0 :         }
    1721           0 :         splx(s);
    1722             : 
    1723           0 :         usbd_ref_decr(sc->sc_udev);
    1724             : 
    1725           0 :         return (error);
    1726           0 : }
    1727             : 
    1728             : /*
    1729             :  * Power on sequence for A-cut adapters.
    1730             :  */
    1731             : void
    1732           0 : rsu_power_on_acut(struct rsu_softc *sc)
    1733             : {
    1734             :         uint32_t reg;
    1735             : 
    1736           0 :         rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53);
    1737           0 :         rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57);
    1738             : 
    1739             :         /* Enable AFE macro block's bandgap and Mbias. */
    1740           0 :         rsu_write_1(sc, R92S_AFE_MISC,
    1741           0 :             rsu_read_1(sc, R92S_AFE_MISC) |
    1742           0 :             R92S_AFE_MISC_BGEN | R92S_AFE_MISC_MBEN);
    1743             :         /* Enable LDOA15 block. */
    1744           0 :         rsu_write_1(sc, R92S_LDOA15_CTRL,
    1745           0 :             rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN);
    1746             : 
    1747           0 :         rsu_write_1(sc, R92S_SPS1_CTRL,
    1748           0 :             rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_LDEN);
    1749           0 :         usbd_delay_ms(sc->sc_udev, 2);
    1750             :         /* Enable switch regulator block. */
    1751           0 :         rsu_write_1(sc, R92S_SPS1_CTRL,
    1752           0 :             rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_SWEN);
    1753             : 
    1754           0 :         rsu_write_4(sc, R92S_SPS1_CTRL, 0x00a7b267);
    1755             : 
    1756           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
    1757           0 :             rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08);
    1758             : 
    1759           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
    1760           0 :             rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20);
    1761             : 
    1762           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
    1763           0 :             rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x90);
    1764             : 
    1765             :         /* Enable AFE clock. */
    1766           0 :         rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1,
    1767           0 :             rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04);
    1768             :         /* Enable AFE PLL macro block. */
    1769           0 :         rsu_write_1(sc, R92S_AFE_PLL_CTRL,
    1770           0 :             rsu_read_1(sc, R92S_AFE_PLL_CTRL) | 0x11);
    1771             :         /* Attach AFE PLL to MACTOP/BB. */
    1772           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL,
    1773           0 :             rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11);
    1774             : 
    1775             :         /* Switch to 40MHz clock instead of 80MHz. */
    1776           0 :         rsu_write_2(sc, R92S_SYS_CLKR,
    1777           0 :             rsu_read_2(sc, R92S_SYS_CLKR) & ~R92S_SYS_CLKSEL);
    1778             : 
    1779             :         /* Enable MAC clock. */
    1780           0 :         rsu_write_2(sc, R92S_SYS_CLKR,
    1781           0 :             rsu_read_2(sc, R92S_SYS_CLKR) |
    1782           0 :             R92S_MAC_CLK_EN | R92S_SYS_CLK_EN);
    1783             : 
    1784           0 :         rsu_write_1(sc, R92S_PMC_FSM, 0x02);
    1785             : 
    1786             :         /* Enable digital core and IOREG R/W. */
    1787           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
    1788           0 :             rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08);
    1789             : 
    1790           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
    1791           0 :             rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80);
    1792             : 
    1793             :         /* Switch the control path to firmware. */
    1794           0 :         reg = rsu_read_2(sc, R92S_SYS_CLKR);
    1795           0 :         reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL;
    1796           0 :         rsu_write_2(sc, R92S_SYS_CLKR, reg);
    1797             : 
    1798           0 :         rsu_write_2(sc, R92S_CR, 0x37fc);
    1799             : 
    1800             :         /* Fix USB RX FIFO issue. */
    1801           0 :         rsu_write_1(sc, 0xfe5c,
    1802           0 :             rsu_read_1(sc, 0xfe5c) | 0x80);
    1803           0 :         rsu_write_1(sc, 0x00ab,
    1804           0 :             rsu_read_1(sc, 0x00ab) | 0xc0);
    1805             : 
    1806           0 :         rsu_write_1(sc, R92S_SYS_CLKR,
    1807           0 :             rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL);
    1808           0 : }
    1809             : 
    1810             : /*
    1811             :  * Power on sequence for B-cut and C-cut adapters.
    1812             :  */
    1813             : void
    1814           0 : rsu_power_on_bcut(struct rsu_softc *sc)
    1815             : {
    1816             :         uint32_t reg;
    1817             :         int ntries;
    1818             : 
    1819             :         /* Prevent eFuse leakage. */
    1820           0 :         rsu_write_1(sc, 0x37, 0xb0);
    1821           0 :         usbd_delay_ms(sc->sc_udev, 10);
    1822           0 :         rsu_write_1(sc, 0x37, 0x30);
    1823             : 
    1824             :         /* Switch the control path to hardware. */
    1825           0 :         reg = rsu_read_2(sc, R92S_SYS_CLKR);
    1826           0 :         if (reg & R92S_FWHW_SEL) {
    1827           0 :                 rsu_write_2(sc, R92S_SYS_CLKR,
    1828           0 :                     reg & ~(R92S_SWHW_SEL | R92S_FWHW_SEL));
    1829           0 :         }
    1830           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
    1831           0 :             rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) & ~0x8c);
    1832           0 :         DELAY(1000);
    1833             : 
    1834           0 :         rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53);
    1835           0 :         rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57);
    1836             : 
    1837           0 :         reg = rsu_read_1(sc, R92S_AFE_MISC);
    1838           0 :         rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN);
    1839           0 :         rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN |
    1840           0 :             R92S_AFE_MISC_MBEN | R92S_AFE_MISC_I32_EN);
    1841             : 
    1842             :         /* Enable PLL. */
    1843           0 :         rsu_write_1(sc, R92S_LDOA15_CTRL,
    1844           0 :             rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN);
    1845             : 
    1846           0 :         rsu_write_1(sc, R92S_LDOV12D_CTRL,
    1847           0 :             rsu_read_1(sc, R92S_LDOV12D_CTRL) | R92S_LDV12_EN);
    1848             : 
    1849           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
    1850           0 :             rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08);
    1851             : 
    1852           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
    1853           0 :             rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20);
    1854             : 
    1855             :         /* Support 64KB IMEM. */
    1856           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
    1857           0 :             rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x97);
    1858             : 
    1859             :         /* Enable AFE clock. */
    1860           0 :         rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1,
    1861           0 :             rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04);
    1862             :         /* Enable AFE PLL macro block. */
    1863           0 :         reg = rsu_read_1(sc, R92S_AFE_PLL_CTRL);
    1864           0 :         rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11);
    1865           0 :         DELAY(500);
    1866           0 :         rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x51);
    1867           0 :         DELAY(500);
    1868           0 :         rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11);
    1869           0 :         DELAY(500);
    1870             : 
    1871             :         /* Attach AFE PLL to MACTOP/BB. */
    1872           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL,
    1873           0 :             rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11);
    1874             : 
    1875             :         /* Switch to 40MHz clock. */
    1876           0 :         rsu_write_1(sc, R92S_SYS_CLKR, 0x00);
    1877             :         /* Disable CPU clock and 80MHz SSC. */
    1878           0 :         rsu_write_1(sc, R92S_SYS_CLKR,
    1879           0 :             rsu_read_1(sc, R92S_SYS_CLKR) | 0xa0);
    1880             :         /* Enable MAC clock. */
    1881           0 :         rsu_write_2(sc, R92S_SYS_CLKR,
    1882           0 :             rsu_read_2(sc, R92S_SYS_CLKR) |
    1883           0 :             R92S_MAC_CLK_EN | R92S_SYS_CLK_EN);
    1884             : 
    1885           0 :         rsu_write_1(sc, R92S_PMC_FSM, 0x02);
    1886             : 
    1887             :         /* Enable digital core and IOREG R/W. */
    1888           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
    1889           0 :             rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08);
    1890             : 
    1891           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
    1892           0 :             rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80);
    1893             : 
    1894             :         /* Switch the control path to firmware. */
    1895           0 :         reg = rsu_read_2(sc, R92S_SYS_CLKR);
    1896           0 :         reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL;
    1897           0 :         rsu_write_2(sc, R92S_SYS_CLKR, reg);
    1898             : 
    1899           0 :         rsu_write_2(sc, R92S_CR, 0x37fc);
    1900             : 
    1901             :         /* Fix USB RX FIFO issue. */
    1902           0 :         rsu_write_1(sc, 0xfe5c,
    1903           0 :             rsu_read_1(sc, 0xfe5c) | 0x80);
    1904             : 
    1905           0 :         rsu_write_1(sc, R92S_SYS_CLKR,
    1906           0 :             rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL);
    1907             : 
    1908           0 :         rsu_write_1(sc, 0xfe1c, 0x80);
    1909             : 
    1910             :         /* Make sure TxDMA is ready to download firmware. */
    1911           0 :         for (ntries = 0; ntries < 20; ntries++) {
    1912           0 :                 reg = rsu_read_1(sc, R92S_TCR);
    1913           0 :                 if ((reg & (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT)) ==
    1914             :                     (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT))
    1915             :                         break;
    1916           0 :                 DELAY(5);
    1917             :         }
    1918           0 :         if (ntries == 20) {
    1919             :                 /* Reset TxDMA. */
    1920           0 :                 reg = rsu_read_1(sc, R92S_CR);
    1921           0 :                 rsu_write_1(sc, R92S_CR, reg & ~R92S_CR_TXDMA_EN);
    1922           0 :                 DELAY(2);
    1923           0 :                 rsu_write_1(sc, R92S_CR, reg | R92S_CR_TXDMA_EN);
    1924           0 :         }
    1925           0 : }
    1926             : 
    1927             : void
    1928           0 : rsu_power_off(struct rsu_softc *sc)
    1929             : {
    1930             :         /* Turn RF off. */
    1931           0 :         rsu_write_1(sc, R92S_RF_CTRL, 0x00);
    1932           0 :         usbd_delay_ms(sc->sc_udev, 5);
    1933             : 
    1934             :         /* Turn MAC off. */
    1935             :         /* Switch control path. */
    1936           0 :         rsu_write_1(sc, R92S_SYS_CLKR + 1, 0x38);
    1937             :         /* Reset MACTOP. */
    1938           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x70);
    1939           0 :         rsu_write_1(sc, R92S_PMC_FSM, 0x06);
    1940           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL + 0, 0xf9);
    1941           0 :         rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 0xe8);
    1942             : 
    1943             :         /* Disable AFE PLL. */
    1944           0 :         rsu_write_1(sc, R92S_AFE_PLL_CTRL, 0x00);
    1945             :         /* Disable A15V. */
    1946           0 :         rsu_write_1(sc, R92S_LDOA15_CTRL, 0x54);
    1947             :         /* Disable eFuse 1.2V. */
    1948           0 :         rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x50);
    1949           0 :         rsu_write_1(sc, R92S_LDOV12D_CTRL, 0x24);
    1950             :         /* Enable AFE macro block's bandgap and Mbias. */
    1951           0 :         rsu_write_1(sc, R92S_AFE_MISC, 0x30);
    1952             :         /* Disable 1.6V LDO. */
    1953           0 :         rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x56);
    1954           0 :         rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x43);
    1955           0 : }
    1956             : 
    1957             : int
    1958           0 : rsu_fw_loadsection(struct rsu_softc *sc, uint8_t *buf, int len)
    1959             : {
    1960             :         struct rsu_tx_data *data;
    1961             :         struct r92s_tx_desc *txd;
    1962             :         struct usbd_pipe *pipe;
    1963             :         int mlen, error;
    1964             : 
    1965           0 :         data = sc->fwcmd_data;
    1966           0 :         pipe = sc->pipe[sc->qid2idx[RSU_QID_VO]];
    1967           0 :         txd = (struct r92s_tx_desc *)data->buf;
    1968           0 :         while (len > 0) {
    1969           0 :                 memset(txd, 0, sizeof(*txd));
    1970           0 :                 if (len <= RSU_TXBUFSZ - sizeof(*txd)) {
    1971             :                         /* Last chunk. */
    1972           0 :                         txd->txdw0 |= htole32(R92S_TXDW0_LINIP);
    1973             :                         mlen = len;
    1974           0 :                 } else
    1975             :                         mlen = RSU_TXBUFSZ - sizeof(*txd);
    1976           0 :                 txd->txdw0 |= htole32(SM(R92S_TXDW0_PKTLEN, mlen));
    1977           0 :                 memcpy(&txd[1], buf, mlen);
    1978             : 
    1979           0 :                 usbd_setup_xfer(data->xfer, pipe, NULL, data->buf,
    1980           0 :                     sizeof(*txd) + mlen,
    1981             :                     USBD_SHORT_XFER_OK | USBD_NO_COPY | USBD_SYNCHRONOUS,
    1982             :                     RSU_TX_TIMEOUT, NULL);
    1983           0 :                 error = usbd_transfer(data->xfer);
    1984           0 :                 if (error != 0)
    1985           0 :                         return (error);
    1986           0 :                 buf += mlen;
    1987           0 :                 len -= mlen;
    1988             :         }
    1989           0 :         return (0);
    1990           0 : }
    1991             : 
    1992             : int
    1993           0 : rsu_load_firmware(struct rsu_softc *sc)
    1994             : {
    1995           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1996             :         struct r92s_fw_hdr *hdr;
    1997             :         struct r92s_fw_priv *dmem;
    1998             :         uint8_t *imem, *emem;
    1999             :         int imemsz, ememsz;
    2000           0 :         u_char *fw;
    2001           0 :         size_t size;
    2002             :         uint32_t reg;
    2003             :         int ntries, error;
    2004             : 
    2005             :         /* Read firmware image from the filesystem. */
    2006           0 :         if ((error = loadfirmware("rsu-rtl8712fw", &fw, &size)) != 0) {
    2007           0 :                 printf("%s: failed loadfirmware of file %s (error %d)\n",
    2008           0 :                     sc->sc_dev.dv_xname, "rsu-rtl8712fw", error);
    2009           0 :                 return (error);
    2010             :         }
    2011           0 :         if (size < sizeof(*hdr)) {
    2012           0 :                 printf("%s: firmware too short\n", sc->sc_dev.dv_xname);
    2013             :                 error = EINVAL;
    2014           0 :                 goto fail;
    2015             :         }
    2016           0 :         hdr = (struct r92s_fw_hdr *)fw;
    2017           0 :         if (hdr->signature != htole16(0x8712) &&
    2018           0 :             hdr->signature != htole16(0x8192)) {
    2019           0 :                 printf("%s: invalid firmware signature 0x%x\n",
    2020           0 :                     sc->sc_dev.dv_xname, letoh16(hdr->signature));
    2021             :                 error = EINVAL;
    2022           0 :                 goto fail;
    2023             :         }
    2024             :         DPRINTF(("FW V%d %02x-%02x %02x:%02x\n", letoh16(hdr->version),
    2025             :             hdr->month, hdr->day, hdr->hour, hdr->minute));
    2026             : 
    2027             :         /* Make sure that driver and firmware are in sync. */
    2028           0 :         if (hdr->privsz != htole32(sizeof(*dmem))) {
    2029           0 :                 printf("%s: unsupported firmware image\n",
    2030           0 :                     sc->sc_dev.dv_xname);
    2031             :                 error = EINVAL;
    2032           0 :                 goto fail;
    2033             :         }
    2034             :         /* Get FW sections sizes. */
    2035           0 :         imemsz = letoh32(hdr->imemsz);
    2036           0 :         ememsz = letoh32(hdr->sramsz);
    2037             :         /* Check that all FW sections fit in image. */
    2038           0 :         if (size < sizeof(*hdr) + imemsz + ememsz) {
    2039           0 :                 printf("%s: firmware too short\n", sc->sc_dev.dv_xname);
    2040             :                 error = EINVAL;
    2041           0 :                 goto fail;
    2042             :         }
    2043           0 :         imem = (uint8_t *)&hdr[1];
    2044           0 :         emem = imem + imemsz;
    2045             : 
    2046             :         /* Load IMEM section. */
    2047           0 :         error = rsu_fw_loadsection(sc, imem, imemsz);
    2048           0 :         if (error != 0) {
    2049           0 :                 printf("%s: could not load firmware section %s\n",
    2050           0 :                     sc->sc_dev.dv_xname, "IMEM");
    2051           0 :                 goto fail;
    2052             :         }
    2053             :         /* Wait for load to complete. */
    2054           0 :         for (ntries = 0; ntries < 10; ntries++) {
    2055           0 :                 reg = rsu_read_2(sc, R92S_TCR);
    2056           0 :                 if (reg & R92S_TCR_IMEM_CODE_DONE)
    2057             :                         break;
    2058           0 :                 DELAY(10);
    2059             :         }
    2060           0 :         if (ntries == 10 || !(reg & R92S_TCR_IMEM_CHK_RPT)) {
    2061           0 :                 printf("%s: timeout waiting for %s transfer\n",
    2062           0 :                     sc->sc_dev.dv_xname, "IMEM");
    2063             :                 error = ETIMEDOUT;
    2064           0 :                 goto fail;
    2065             :         }
    2066             : 
    2067             :         /* Load EMEM section. */
    2068           0 :         error = rsu_fw_loadsection(sc, emem, ememsz);
    2069           0 :         if (error != 0) {
    2070           0 :                 printf("%s: could not load firmware section %s\n",
    2071           0 :                     sc->sc_dev.dv_xname, "EMEM");
    2072           0 :                 goto fail;
    2073             :         }
    2074             :         /* Wait for load to complete. */
    2075           0 :         for (ntries = 0; ntries < 10; ntries++) {
    2076           0 :                 reg = rsu_read_2(sc, R92S_TCR);
    2077           0 :                 if (reg & R92S_TCR_EMEM_CODE_DONE)
    2078             :                         break;
    2079           0 :                 DELAY(10);
    2080             :         }
    2081           0 :         if (ntries == 10 || !(reg & R92S_TCR_EMEM_CHK_RPT)) {
    2082           0 :                 printf("%s: timeout waiting for %s transfer\n",
    2083           0 :                     sc->sc_dev.dv_xname, "EMEM");
    2084             :                 error = ETIMEDOUT;
    2085           0 :                 goto fail;
    2086             :         }
    2087             : 
    2088             :         /* Enable CPU. */
    2089           0 :         rsu_write_1(sc, R92S_SYS_CLKR,
    2090           0 :             rsu_read_1(sc, R92S_SYS_CLKR) | R92S_SYS_CPU_CLKSEL);
    2091           0 :         if (!(rsu_read_1(sc, R92S_SYS_CLKR) & R92S_SYS_CPU_CLKSEL)) {
    2092           0 :                 printf("%s: could not enable system clock\n",
    2093           0 :                     sc->sc_dev.dv_xname);
    2094             :                 error = EIO;
    2095           0 :                 goto fail;
    2096             :         }
    2097           0 :         rsu_write_2(sc, R92S_SYS_FUNC_EN,
    2098           0 :             rsu_read_2(sc, R92S_SYS_FUNC_EN) | R92S_FEN_CPUEN);
    2099           0 :         if (!(rsu_read_2(sc, R92S_SYS_FUNC_EN) & R92S_FEN_CPUEN)) {
    2100           0 :                 printf("%s: could not enable microcontroller\n",
    2101           0 :                     sc->sc_dev.dv_xname);
    2102             :                 error = EIO;
    2103           0 :                 goto fail;
    2104             :         }
    2105             :         /* Wait for CPU to initialize. */
    2106           0 :         for (ntries = 0; ntries < 100; ntries++) {
    2107           0 :                 if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_IMEM_RDY)
    2108             :                         break;
    2109           0 :                 DELAY(1000);
    2110             :         }
    2111           0 :         if (ntries == 100) {
    2112           0 :                 printf("%s: timeout waiting for microcontroller\n",
    2113           0 :                     sc->sc_dev.dv_xname);
    2114             :                 error = ETIMEDOUT;
    2115           0 :                 goto fail;
    2116             :         }
    2117             : 
    2118             :         /* Update DMEM section before loading. */
    2119           0 :         dmem = &hdr->priv;
    2120           0 :         memset(dmem, 0, sizeof(*dmem));
    2121           0 :         dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172;
    2122           0 :         dmem->nendpoints = sc->npipes;
    2123           0 :         dmem->rf_config = 0x12;      /* 1T2R */
    2124           0 :         dmem->vcs_type = R92S_VCS_TYPE_AUTO;
    2125           0 :         dmem->vcs_mode = R92S_VCS_MODE_RTS_CTS;
    2126           0 :         dmem->bw40_en = (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) != 0;
    2127           0 :         dmem->turbo_mode = 1;
    2128             :         /* Load DMEM section. */
    2129           0 :         error = rsu_fw_loadsection(sc, (uint8_t *)dmem, sizeof(*dmem));
    2130           0 :         if (error != 0) {
    2131           0 :                 printf("%s: could not load firmware section %s\n",
    2132           0 :                     sc->sc_dev.dv_xname, "DMEM");
    2133           0 :                 goto fail;
    2134             :         }
    2135             :         /* Wait for load to complete. */
    2136           0 :         for (ntries = 0; ntries < 100; ntries++) {
    2137           0 :                 if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_DMEM_CODE_DONE)
    2138             :                         break;
    2139           0 :                 DELAY(1000);
    2140             :         }
    2141           0 :         if (ntries == 100) {
    2142           0 :                 printf("%s: timeout waiting for %s transfer\n",
    2143           0 :                     sc->sc_dev.dv_xname, "DMEM");
    2144             :                 error = ETIMEDOUT;
    2145           0 :                 goto fail;
    2146             :         }
    2147             :         /* Wait for firmware readiness. */
    2148           0 :         for (ntries = 0; ntries < 60; ntries++) {
    2149           0 :                 if (!(rsu_read_2(sc, R92S_TCR) & R92S_TCR_FWRDY))
    2150             :                         break;
    2151           0 :                 DELAY(1000);
    2152             :         }
    2153           0 :         if (ntries == 60) {
    2154           0 :                 printf("%s: timeout waiting for firmware readiness\n",
    2155           0 :                     sc->sc_dev.dv_xname);
    2156             :                 error = ETIMEDOUT;
    2157           0 :                 goto fail;
    2158             :         }
    2159             :  fail:
    2160           0 :         free(fw, M_DEVBUF, size);
    2161           0 :         return (error);
    2162           0 : }
    2163             : 
    2164             : int
    2165           0 : rsu_init(struct ifnet *ifp)
    2166             : {
    2167           0 :         struct rsu_softc *sc = ifp->if_softc;
    2168           0 :         struct ieee80211com *ic = &sc->sc_ic;
    2169           0 :         struct r92s_set_pwr_mode cmd;
    2170             :         struct rsu_rx_data *data;
    2171             :         int i, error;
    2172             : 
    2173             :         /* Init host async commands ring. */
    2174           0 :         sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
    2175             : 
    2176             :         /* Allocate Tx/Rx buffers. */
    2177           0 :         error = rsu_alloc_rx_list(sc);
    2178           0 :         if (error != 0) {
    2179           0 :                 printf("%s: could not allocate Rx buffers\n",
    2180           0 :                     sc->sc_dev.dv_xname);
    2181           0 :                 goto fail;
    2182             :         }
    2183           0 :         error = rsu_alloc_tx_list(sc);
    2184           0 :         if (error != 0) {
    2185           0 :                 printf("%s: could not allocate Tx buffers\n",
    2186           0 :                     sc->sc_dev.dv_xname);
    2187           0 :                 goto fail;
    2188             :         }
    2189             :         /* Reserve one Tx buffer for firmware commands. */
    2190           0 :         sc->fwcmd_data = TAILQ_FIRST(&sc->tx_free_list);
    2191           0 :         TAILQ_REMOVE(&sc->tx_free_list, sc->fwcmd_data, next);
    2192             : 
    2193             :         /* Power on adapter. */
    2194           0 :         if (sc->cut == 1)
    2195           0 :                 rsu_power_on_acut(sc);
    2196             :         else
    2197           0 :                 rsu_power_on_bcut(sc);
    2198             :         /* Load firmware. */
    2199           0 :         error = rsu_load_firmware(sc);
    2200           0 :         if (error != 0)
    2201             :                 goto fail;
    2202             : 
    2203             :         /* Enable Rx TCP checksum offload. */
    2204           0 :         rsu_write_4(sc, R92S_RCR,
    2205           0 :             rsu_read_4(sc, R92S_RCR) | 0x04000000);
    2206             :         /* Append PHY status. */
    2207           0 :         rsu_write_4(sc, R92S_RCR,
    2208           0 :             rsu_read_4(sc, R92S_RCR) | 0x02000000);
    2209             : 
    2210           0 :         rsu_write_4(sc, R92S_CR,
    2211           0 :             rsu_read_4(sc, R92S_CR) & ~0xff000000);
    2212             : 
    2213             :         /* Use 128 bytes pages. */
    2214           0 :         rsu_write_1(sc, 0x00b5,
    2215           0 :             rsu_read_1(sc, 0x00b5) | 0x01);
    2216             :         /* Enable USB Rx aggregation. */
    2217           0 :         rsu_write_1(sc, 0x00bd,
    2218           0 :             rsu_read_1(sc, 0x00bd) | 0x80);
    2219             :         /* Set USB Rx aggregation threshold. */
    2220           0 :         rsu_write_1(sc, 0x00d9, 0x01);
    2221             :         /* Set USB Rx aggregation timeout (1.7ms/4). */
    2222           0 :         rsu_write_1(sc, 0xfe5b, 0x04);
    2223             :         /* Fix USB Rx FIFO issue. */
    2224           0 :         rsu_write_1(sc, 0xfe5c,
    2225           0 :             rsu_read_1(sc, 0xfe5c) | 0x80);
    2226             : 
    2227             :         /* Set MAC address. */
    2228           0 :         IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
    2229           0 :         rsu_write_region_1(sc, R92S_MACID, ic->ic_myaddr, IEEE80211_ADDR_LEN);               
    2230             : 
    2231             :         /* Queue Rx xfers (XXX C2H pipe for 11-pipe configurations?) */
    2232           0 :         for (i = 0; i < RSU_RX_LIST_COUNT; i++) {
    2233           0 :                 data = &sc->rx_data[i];
    2234             : 
    2235           0 :                 data->pipe = sc->pipe[sc->qid2idx[RSU_QID_RXOFF]];
    2236           0 :                 usbd_setup_xfer(data->xfer, data->pipe, data, data->buf,
    2237             :                     RSU_RXBUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
    2238             :                     USBD_NO_TIMEOUT, rsu_rxeof);
    2239           0 :                 error = usbd_transfer(data->xfer);
    2240           0 :                 if (error != 0 && error != USBD_IN_PROGRESS)
    2241             :                         goto fail;
    2242             :         }
    2243             : 
    2244             :         /* NB: it really takes that long for firmware to boot. */
    2245           0 :         usbd_delay_ms(sc->sc_udev, 1500);
    2246             : 
    2247             :         DPRINTF(("setting MAC address to %s\n", ether_sprintf(ic->ic_myaddr)));
    2248           0 :         error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, ic->ic_myaddr,
    2249             :             IEEE80211_ADDR_LEN);
    2250           0 :         if (error != 0) {
    2251           0 :                 printf("%s: could not set MAC address\n", sc->sc_dev.dv_xname);
    2252           0 :                 goto fail;
    2253             :         }
    2254             : 
    2255           0 :         rsu_write_1(sc, R92S_USB_HRPWM,
    2256             :             R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON);
    2257             : 
    2258           0 :         memset(&cmd, 0, sizeof(cmd));
    2259           0 :         cmd.mode = R92S_PS_MODE_ACTIVE;
    2260             :         DPRINTF(("setting ps mode to %d\n", cmd.mode));
    2261           0 :         error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd));
    2262           0 :         if (error != 0) {
    2263           0 :                 printf("%s: could not set PS mode\n", sc->sc_dev.dv_xname);
    2264           0 :                 goto fail;
    2265             :         }
    2266             : 
    2267           0 :         if (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) {
    2268             :                 /* Enable 40MHz mode. */
    2269           0 :                 error = rsu_fw_iocmd(sc,
    2270             :                     SM(R92S_IOCMD_CLASS, 0xf4) |
    2271             :                     SM(R92S_IOCMD_INDEX, 0x00) |
    2272             :                     SM(R92S_IOCMD_VALUE, 0x0007));
    2273           0 :                 if (error != 0) {
    2274           0 :                         printf("%s: could not enable 40MHz mode\n",
    2275           0 :                             sc->sc_dev.dv_xname);
    2276           0 :                         goto fail;
    2277             :                 }
    2278             :         }
    2279             : 
    2280             :         /* Set default channel. */
    2281           0 :         ic->ic_bss->ni_chan = ic->ic_ibss_chan;
    2282             : 
    2283             :         /* We're ready to go. */
    2284           0 :         ifp->if_flags |= IFF_RUNNING;
    2285           0 :         ifq_clr_oactive(&ifp->if_snd);
    2286             : 
    2287             : #ifdef notyet
    2288             :         if (ic->ic_flags & IEEE80211_F_WEPON) {
    2289             :                 /* Install WEP keys. */
    2290             :                 for (i = 0; i < IEEE80211_WEP_NKID; i++)
    2291             :                         rsu_set_key(ic, NULL, &ic->ic_nw_keys[i]);
    2292             :                 rsu_wait_async(sc);
    2293             :         }
    2294             : #endif
    2295             : 
    2296           0 :         sc->scan_pass = 0;
    2297           0 :         ieee80211_begin_scan(ifp);
    2298           0 :         return (0);
    2299             :  fail:
    2300           0 :         rsu_stop(ifp);
    2301           0 :         return (error);
    2302           0 : }
    2303             : 
    2304             : void
    2305           0 : rsu_stop(struct ifnet *ifp)
    2306             : {
    2307           0 :         struct rsu_softc *sc = ifp->if_softc;
    2308           0 :         struct ieee80211com *ic = &sc->sc_ic;
    2309             :         int i, s;
    2310             : 
    2311           0 :         sc->sc_tx_timer = 0;
    2312           0 :         ifp->if_timer = 0;
    2313           0 :         ifp->if_flags &= ~IFF_RUNNING;
    2314           0 :         ifq_clr_oactive(&ifp->if_snd);
    2315             : 
    2316           0 :         s = splusb();
    2317           0 :         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
    2318             :         /* Wait for all async commands to complete. */
    2319           0 :         rsu_wait_async(sc);
    2320           0 :         splx(s);
    2321             : 
    2322           0 :         timeout_del(&sc->calib_to);
    2323             : 
    2324             :         /* Power off adapter. */
    2325           0 :         rsu_power_off(sc);
    2326             : 
    2327             :         /* Abort Tx/Rx. */
    2328           0 :         for (i = 0; i < sc->npipes; i++)
    2329           0 :                 usbd_abort_pipe(sc->pipe[i]);
    2330             : 
    2331             :         /* Free Tx/Rx buffers. */
    2332           0 :         rsu_free_tx_list(sc);
    2333           0 :         rsu_free_rx_list(sc);
    2334           0 : }

Generated by: LCOV version 1.13