1*31d98677SRui Paulo /* $OpenBSD: if_rsu.c,v 1.17 2013/04/15 09:23:01 mglocker Exp $ */ 2*31d98677SRui Paulo 3*31d98677SRui Paulo /*- 4*31d98677SRui Paulo * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5*31d98677SRui Paulo * 6*31d98677SRui Paulo * Permission to use, copy, modify, and distribute this software for any 7*31d98677SRui Paulo * purpose with or without fee is hereby granted, provided that the above 8*31d98677SRui Paulo * copyright notice and this permission notice appear in all copies. 9*31d98677SRui Paulo * 10*31d98677SRui Paulo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*31d98677SRui Paulo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*31d98677SRui Paulo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*31d98677SRui Paulo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*31d98677SRui Paulo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*31d98677SRui Paulo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*31d98677SRui Paulo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*31d98677SRui Paulo */ 18*31d98677SRui Paulo #include <sys/cdefs.h> 19*31d98677SRui Paulo __FBSDID("$FreeBSD$"); 20*31d98677SRui Paulo 21*31d98677SRui Paulo /* 22*31d98677SRui Paulo * Driver for Realtek RTL8188SU/RTL8191SU/RTL8192SU. 23*31d98677SRui Paulo * 24*31d98677SRui Paulo * TODO: 25*31d98677SRui Paulo * o 11n support 26*31d98677SRui Paulo * o h/w crypto 27*31d98677SRui Paulo * o hostap / ibss / mesh 28*31d98677SRui Paulo */ 29*31d98677SRui Paulo #include <sys/param.h> 30*31d98677SRui Paulo #include <sys/endian.h> 31*31d98677SRui Paulo #include <sys/sockio.h> 32*31d98677SRui Paulo #include <sys/mbuf.h> 33*31d98677SRui Paulo #include <sys/kernel.h> 34*31d98677SRui Paulo #include <sys/socket.h> 35*31d98677SRui Paulo #include <sys/systm.h> 36*31d98677SRui Paulo #include <sys/conf.h> 37*31d98677SRui Paulo #include <sys/bus.h> 38*31d98677SRui Paulo #include <sys/rman.h> 39*31d98677SRui Paulo #include <sys/firmware.h> 40*31d98677SRui Paulo #include <sys/module.h> 41*31d98677SRui Paulo 42*31d98677SRui Paulo #include <machine/bus.h> 43*31d98677SRui Paulo #include <machine/resource.h> 44*31d98677SRui Paulo 45*31d98677SRui Paulo #include <net/bpf.h> 46*31d98677SRui Paulo #include <net/if.h> 47*31d98677SRui Paulo #include <net/if_arp.h> 48*31d98677SRui Paulo #include <net/if_dl.h> 49*31d98677SRui Paulo #include <net/if_media.h> 50*31d98677SRui Paulo #include <net/if_types.h> 51*31d98677SRui Paulo 52*31d98677SRui Paulo #include <netinet/in.h> 53*31d98677SRui Paulo #include <netinet/in_systm.h> 54*31d98677SRui Paulo #include <netinet/in_var.h> 55*31d98677SRui Paulo #include <netinet/if_ether.h> 56*31d98677SRui Paulo #include <netinet/ip.h> 57*31d98677SRui Paulo 58*31d98677SRui Paulo #include <net80211/ieee80211_var.h> 59*31d98677SRui Paulo #include <net80211/ieee80211_regdomain.h> 60*31d98677SRui Paulo #include <net80211/ieee80211_radiotap.h> 61*31d98677SRui Paulo 62*31d98677SRui Paulo #include <dev/usb/usb.h> 63*31d98677SRui Paulo #include <dev/usb/usbdi.h> 64*31d98677SRui Paulo #include "usbdevs.h" 65*31d98677SRui Paulo 66*31d98677SRui Paulo #define USB_DEBUG_VAR rsu_debug 67*31d98677SRui Paulo #include <dev/usb/usb_debug.h> 68*31d98677SRui Paulo 69*31d98677SRui Paulo #include <dev/usb/wlan/if_rsureg.h> 70*31d98677SRui Paulo 71*31d98677SRui Paulo #ifdef USB_DEBUG 72*31d98677SRui Paulo static int rsu_debug = 0; 73*31d98677SRui Paulo SYSCTL_NODE(_hw_usb, OID_AUTO, rsu, CTLFLAG_RW, 0, "USB rsu"); 74*31d98677SRui Paulo SYSCTL_INT(_hw_usb_rsu, OID_AUTO, debug, CTLFLAG_RW, &rsu_debug, 0, 75*31d98677SRui Paulo "Debug level"); 76*31d98677SRui Paulo #endif 77*31d98677SRui Paulo 78*31d98677SRui Paulo static const STRUCT_USB_HOST_ID rsu_devs[] = { 79*31d98677SRui Paulo #define RSU_HT_NOT_SUPPORTED 0 80*31d98677SRui Paulo #define RSU_HT_SUPPORTED 1 81*31d98677SRui Paulo #define RSU_DEV_HT(v,p) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, \ 82*31d98677SRui Paulo RSU_HT_SUPPORTED) } 83*31d98677SRui Paulo #define RSU_DEV(v,p) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, \ 84*31d98677SRui Paulo RSU_HT_NOT_SUPPORTED) } 85*31d98677SRui Paulo RSU_DEV(ASUS, RTL8192SU), 86*31d98677SRui Paulo RSU_DEV(AZUREWAVE, RTL8192SU_4), 87*31d98677SRui Paulo RSU_DEV_HT(ACCTON, RTL8192SU), 88*31d98677SRui Paulo RSU_DEV_HT(ASUS, USBN10), 89*31d98677SRui Paulo RSU_DEV_HT(AZUREWAVE, RTL8192SU_1), 90*31d98677SRui Paulo RSU_DEV_HT(AZUREWAVE, RTL8192SU_2), 91*31d98677SRui Paulo RSU_DEV_HT(AZUREWAVE, RTL8192SU_3), 92*31d98677SRui Paulo RSU_DEV_HT(AZUREWAVE, RTL8192SU_5), 93*31d98677SRui Paulo RSU_DEV_HT(BELKIN, RTL8192SU_1), 94*31d98677SRui Paulo RSU_DEV_HT(BELKIN, RTL8192SU_2), 95*31d98677SRui Paulo RSU_DEV_HT(BELKIN, RTL8192SU_3), 96*31d98677SRui Paulo RSU_DEV_HT(CONCEPTRONIC2, RTL8192SU_1), 97*31d98677SRui Paulo RSU_DEV_HT(CONCEPTRONIC2, RTL8192SU_2), 98*31d98677SRui Paulo RSU_DEV_HT(CONCEPTRONIC2, RTL8192SU_3), 99*31d98677SRui Paulo RSU_DEV_HT(COREGA, RTL8192SU), 100*31d98677SRui Paulo RSU_DEV_HT(DLINK2, DWA131A1), 101*31d98677SRui Paulo RSU_DEV_HT(DLINK2, RTL8192SU_1), 102*31d98677SRui Paulo RSU_DEV_HT(DLINK2, RTL8192SU_2), 103*31d98677SRui Paulo RSU_DEV_HT(EDIMAX, RTL8192SU_1), 104*31d98677SRui Paulo RSU_DEV_HT(EDIMAX, RTL8192SU_2), 105*31d98677SRui Paulo RSU_DEV_HT(EDIMAX, RTL8192SU_3), 106*31d98677SRui Paulo RSU_DEV_HT(GUILLEMOT, HWGUN54), 107*31d98677SRui Paulo RSU_DEV_HT(GUILLEMOT, HWNUM300), 108*31d98677SRui Paulo RSU_DEV_HT(HAWKING, RTL8192SU_1), 109*31d98677SRui Paulo RSU_DEV_HT(HAWKING, RTL8192SU_2), 110*31d98677SRui Paulo RSU_DEV_HT(PLANEX2, GWUSNANO), 111*31d98677SRui Paulo RSU_DEV_HT(REALTEK, RTL8171), 112*31d98677SRui Paulo RSU_DEV_HT(REALTEK, RTL8172), 113*31d98677SRui Paulo RSU_DEV_HT(REALTEK, RTL8173), 114*31d98677SRui Paulo RSU_DEV_HT(REALTEK, RTL8174), 115*31d98677SRui Paulo RSU_DEV_HT(REALTEK, RTL8192SU), 116*31d98677SRui Paulo RSU_DEV_HT(REALTEK, RTL8712), 117*31d98677SRui Paulo RSU_DEV_HT(REALTEK, RTL8713), 118*31d98677SRui Paulo RSU_DEV_HT(SENAO, RTL8192SU_1), 119*31d98677SRui Paulo RSU_DEV_HT(SENAO, RTL8192SU_2), 120*31d98677SRui Paulo RSU_DEV_HT(SITECOMEU, WL349V1), 121*31d98677SRui Paulo RSU_DEV_HT(SITECOMEU, WL353), 122*31d98677SRui Paulo RSU_DEV_HT(SWEEX2, LW154), 123*31d98677SRui Paulo #undef RSU_DEV_HT 124*31d98677SRui Paulo #undef RSU_DEV 125*31d98677SRui Paulo }; 126*31d98677SRui Paulo 127*31d98677SRui Paulo static device_probe_t rsu_match; 128*31d98677SRui Paulo static device_attach_t rsu_attach; 129*31d98677SRui Paulo static device_detach_t rsu_detach; 130*31d98677SRui Paulo static usb_callback_t rsu_bulk_tx_callback; 131*31d98677SRui Paulo static usb_callback_t rsu_bulk_rx_callback; 132*31d98677SRui Paulo static usb_error_t rsu_do_request(struct rsu_softc *, 133*31d98677SRui Paulo struct usb_device_request *, void *); 134*31d98677SRui Paulo static struct ieee80211vap * 135*31d98677SRui Paulo rsu_vap_create(struct ieee80211com *, const char name[], 136*31d98677SRui Paulo int, enum ieee80211_opmode, int, const uint8_t bssid[], 137*31d98677SRui Paulo const uint8_t mac[]); 138*31d98677SRui Paulo static void rsu_vap_delete(struct ieee80211vap *); 139*31d98677SRui Paulo static void rsu_scan_start(struct ieee80211com *); 140*31d98677SRui Paulo static void rsu_scan_end(struct ieee80211com *); 141*31d98677SRui Paulo static void rsu_set_channel(struct ieee80211com *); 142*31d98677SRui Paulo static void rsu_update_mcast(struct ifnet *); 143*31d98677SRui Paulo static int rsu_alloc_rx_list(struct rsu_softc *); 144*31d98677SRui Paulo static void rsu_free_rx_list(struct rsu_softc *); 145*31d98677SRui Paulo static int rsu_alloc_tx_list(struct rsu_softc *); 146*31d98677SRui Paulo static void rsu_free_tx_list(struct rsu_softc *); 147*31d98677SRui Paulo static void rsu_free_list(struct rsu_softc *, struct rsu_data [], int); 148*31d98677SRui Paulo static struct rsu_data *_rsu_getbuf(struct rsu_softc *); 149*31d98677SRui Paulo static struct rsu_data *rsu_getbuf(struct rsu_softc *); 150*31d98677SRui Paulo static int rsu_write_region_1(struct rsu_softc *, uint16_t, uint8_t *, 151*31d98677SRui Paulo int); 152*31d98677SRui Paulo static void rsu_write_1(struct rsu_softc *, uint16_t, uint8_t); 153*31d98677SRui Paulo static void rsu_write_2(struct rsu_softc *, uint16_t, uint16_t); 154*31d98677SRui Paulo static void rsu_write_4(struct rsu_softc *, uint16_t, uint32_t); 155*31d98677SRui Paulo static int rsu_read_region_1(struct rsu_softc *, uint16_t, uint8_t *, 156*31d98677SRui Paulo int); 157*31d98677SRui Paulo static uint8_t rsu_read_1(struct rsu_softc *, uint16_t); 158*31d98677SRui Paulo static uint16_t rsu_read_2(struct rsu_softc *, uint16_t); 159*31d98677SRui Paulo static uint32_t rsu_read_4(struct rsu_softc *, uint16_t); 160*31d98677SRui Paulo static int rsu_fw_iocmd(struct rsu_softc *, uint32_t); 161*31d98677SRui Paulo static uint8_t rsu_efuse_read_1(struct rsu_softc *, uint16_t); 162*31d98677SRui Paulo static int rsu_read_rom(struct rsu_softc *); 163*31d98677SRui Paulo static int rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int); 164*31d98677SRui Paulo static void rsu_calib_task(void *, int); 165*31d98677SRui Paulo static int rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int); 166*31d98677SRui Paulo #ifdef notyet 167*31d98677SRui Paulo static void rsu_set_key(struct rsu_softc *, const struct ieee80211_key *); 168*31d98677SRui Paulo static void rsu_delete_key(struct rsu_softc *, const struct ieee80211_key *); 169*31d98677SRui Paulo #endif 170*31d98677SRui Paulo static int rsu_site_survey(struct rsu_softc *, struct ieee80211vap *); 171*31d98677SRui Paulo static int rsu_join_bss(struct rsu_softc *, struct ieee80211_node *); 172*31d98677SRui Paulo static int rsu_disconnect(struct rsu_softc *); 173*31d98677SRui Paulo static void rsu_event_survey(struct rsu_softc *, uint8_t *, int); 174*31d98677SRui Paulo static void rsu_event_join_bss(struct rsu_softc *, uint8_t *, int); 175*31d98677SRui Paulo static void rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int); 176*31d98677SRui Paulo static void rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int); 177*31d98677SRui Paulo static int8_t rsu_get_rssi(struct rsu_softc *, int, void *); 178*31d98677SRui Paulo static struct mbuf * 179*31d98677SRui Paulo rsu_rx_frame(struct rsu_softc *, uint8_t *, int, int *); 180*31d98677SRui Paulo static struct mbuf * 181*31d98677SRui Paulo rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int, int *); 182*31d98677SRui Paulo static struct mbuf * 183*31d98677SRui Paulo rsu_rxeof(struct usb_xfer *, struct rsu_data *, int *); 184*31d98677SRui Paulo static void rsu_txeof(struct usb_xfer *, struct rsu_data *); 185*31d98677SRui Paulo static int rsu_raw_xmit(struct ieee80211_node *, struct mbuf *, 186*31d98677SRui Paulo const struct ieee80211_bpf_params *); 187*31d98677SRui Paulo static void rsu_init(void *); 188*31d98677SRui Paulo static void rsu_init_locked(struct rsu_softc *); 189*31d98677SRui Paulo static void rsu_watchdog(void *); 190*31d98677SRui Paulo static int rsu_tx_start(struct rsu_softc *, struct ieee80211_node *, 191*31d98677SRui Paulo struct mbuf *, struct rsu_data *); 192*31d98677SRui Paulo static void rsu_start(struct ifnet *); 193*31d98677SRui Paulo static void rsu_start_locked(struct ifnet *); 194*31d98677SRui Paulo static int rsu_ioctl(struct ifnet *, u_long, caddr_t); 195*31d98677SRui Paulo static void rsu_stop(struct ifnet *, int); 196*31d98677SRui Paulo static void rsu_stop_locked(struct ifnet *, int); 197*31d98677SRui Paulo 198*31d98677SRui Paulo static device_method_t rsu_methods[] = { 199*31d98677SRui Paulo DEVMETHOD(device_probe, rsu_match), 200*31d98677SRui Paulo DEVMETHOD(device_attach, rsu_attach), 201*31d98677SRui Paulo DEVMETHOD(device_detach, rsu_detach), 202*31d98677SRui Paulo 203*31d98677SRui Paulo DEVMETHOD_END 204*31d98677SRui Paulo }; 205*31d98677SRui Paulo 206*31d98677SRui Paulo static driver_t rsu_driver = { 207*31d98677SRui Paulo .name = "rsu", 208*31d98677SRui Paulo .methods = rsu_methods, 209*31d98677SRui Paulo .size = sizeof(struct rsu_softc) 210*31d98677SRui Paulo }; 211*31d98677SRui Paulo 212*31d98677SRui Paulo static devclass_t rsu_devclass; 213*31d98677SRui Paulo 214*31d98677SRui Paulo DRIVER_MODULE(rsu, uhub, rsu_driver, rsu_devclass, NULL, 0); 215*31d98677SRui Paulo MODULE_DEPEND(rsu, wlan, 1, 1, 1); 216*31d98677SRui Paulo MODULE_DEPEND(rsu, usb, 1, 1, 1); 217*31d98677SRui Paulo MODULE_DEPEND(rsu, firmware, 1, 1, 1); 218*31d98677SRui Paulo MODULE_VERSION(rsu, 1); 219*31d98677SRui Paulo 220*31d98677SRui Paulo static const struct usb_config rsu_config[RSU_N_TRANSFER] = { 221*31d98677SRui Paulo [RSU_BULK_RX] = { 222*31d98677SRui Paulo .type = UE_BULK, 223*31d98677SRui Paulo .endpoint = UE_ADDR_ANY, 224*31d98677SRui Paulo .direction = UE_DIR_IN, 225*31d98677SRui Paulo .bufsize = RSU_RXBUFSZ, 226*31d98677SRui Paulo .flags = { 227*31d98677SRui Paulo .pipe_bof = 1, 228*31d98677SRui Paulo .short_xfer_ok = 1 229*31d98677SRui Paulo }, 230*31d98677SRui Paulo .callback = rsu_bulk_rx_callback 231*31d98677SRui Paulo }, 232*31d98677SRui Paulo [RSU_BULK_TX_BE] = { 233*31d98677SRui Paulo .type = UE_BULK, 234*31d98677SRui Paulo .endpoint = 0x06, 235*31d98677SRui Paulo .direction = UE_DIR_OUT, 236*31d98677SRui Paulo .bufsize = RSU_TXBUFSZ, 237*31d98677SRui Paulo .flags = { 238*31d98677SRui Paulo .ext_buffer = 1, 239*31d98677SRui Paulo .pipe_bof = 1, 240*31d98677SRui Paulo .force_short_xfer = 1 241*31d98677SRui Paulo }, 242*31d98677SRui Paulo .callback = rsu_bulk_tx_callback, 243*31d98677SRui Paulo .timeout = RSU_TX_TIMEOUT 244*31d98677SRui Paulo }, 245*31d98677SRui Paulo [RSU_BULK_TX_BK] = { 246*31d98677SRui Paulo .type = UE_BULK, 247*31d98677SRui Paulo .endpoint = 0x06, 248*31d98677SRui Paulo .direction = UE_DIR_OUT, 249*31d98677SRui Paulo .bufsize = RSU_TXBUFSZ, 250*31d98677SRui Paulo .flags = { 251*31d98677SRui Paulo .ext_buffer = 1, 252*31d98677SRui Paulo .pipe_bof = 1, 253*31d98677SRui Paulo .force_short_xfer = 1 254*31d98677SRui Paulo }, 255*31d98677SRui Paulo .callback = rsu_bulk_tx_callback, 256*31d98677SRui Paulo .timeout = RSU_TX_TIMEOUT 257*31d98677SRui Paulo }, 258*31d98677SRui Paulo [RSU_BULK_TX_VI] = { 259*31d98677SRui Paulo .type = UE_BULK, 260*31d98677SRui Paulo .endpoint = 0x04, 261*31d98677SRui Paulo .direction = UE_DIR_OUT, 262*31d98677SRui Paulo .bufsize = RSU_TXBUFSZ, 263*31d98677SRui Paulo .flags = { 264*31d98677SRui Paulo .ext_buffer = 1, 265*31d98677SRui Paulo .pipe_bof = 1, 266*31d98677SRui Paulo .force_short_xfer = 1 267*31d98677SRui Paulo }, 268*31d98677SRui Paulo .callback = rsu_bulk_tx_callback, 269*31d98677SRui Paulo .timeout = RSU_TX_TIMEOUT 270*31d98677SRui Paulo }, 271*31d98677SRui Paulo [RSU_BULK_TX_VO] = { 272*31d98677SRui Paulo .type = UE_BULK, 273*31d98677SRui Paulo .endpoint = 0x04, 274*31d98677SRui Paulo .direction = UE_DIR_OUT, 275*31d98677SRui Paulo .bufsize = RSU_TXBUFSZ, 276*31d98677SRui Paulo .flags = { 277*31d98677SRui Paulo .ext_buffer = 1, 278*31d98677SRui Paulo .pipe_bof = 1, 279*31d98677SRui Paulo .force_short_xfer = 1 280*31d98677SRui Paulo }, 281*31d98677SRui Paulo .callback = rsu_bulk_tx_callback, 282*31d98677SRui Paulo .timeout = RSU_TX_TIMEOUT 283*31d98677SRui Paulo }, 284*31d98677SRui Paulo }; 285*31d98677SRui Paulo 286*31d98677SRui Paulo static int 287*31d98677SRui Paulo rsu_match(device_t self) 288*31d98677SRui Paulo { 289*31d98677SRui Paulo struct usb_attach_arg *uaa = device_get_ivars(self); 290*31d98677SRui Paulo 291*31d98677SRui Paulo if (uaa->usb_mode != USB_MODE_HOST || 292*31d98677SRui Paulo uaa->info.bIfaceIndex != 0 || 293*31d98677SRui Paulo uaa->info.bConfigIndex != 0) 294*31d98677SRui Paulo return (ENXIO); 295*31d98677SRui Paulo 296*31d98677SRui Paulo return (usbd_lookup_id_by_uaa(rsu_devs, sizeof(rsu_devs), uaa)); 297*31d98677SRui Paulo } 298*31d98677SRui Paulo 299*31d98677SRui Paulo static int 300*31d98677SRui Paulo rsu_attach(device_t self) 301*31d98677SRui Paulo { 302*31d98677SRui Paulo struct usb_attach_arg *uaa = device_get_ivars(self); 303*31d98677SRui Paulo struct rsu_softc *sc = device_get_softc(self); 304*31d98677SRui Paulo struct ifnet *ifp; 305*31d98677SRui Paulo struct ieee80211com *ic; 306*31d98677SRui Paulo int error; 307*31d98677SRui Paulo uint8_t iface_index, bands; 308*31d98677SRui Paulo 309*31d98677SRui Paulo device_set_usb_desc(self); 310*31d98677SRui Paulo sc->sc_udev = uaa->device; 311*31d98677SRui Paulo sc->sc_dev = self; 312*31d98677SRui Paulo 313*31d98677SRui Paulo mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, 314*31d98677SRui Paulo MTX_DEF); 315*31d98677SRui Paulo TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0, 316*31d98677SRui Paulo rsu_calib_task, sc); 317*31d98677SRui Paulo callout_init(&sc->sc_watchdog_ch, 0); 318*31d98677SRui Paulo 319*31d98677SRui Paulo iface_index = 0; 320*31d98677SRui Paulo error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, 321*31d98677SRui Paulo rsu_config, RSU_N_TRANSFER, sc, &sc->sc_mtx); 322*31d98677SRui Paulo if (error) { 323*31d98677SRui Paulo device_printf(sc->sc_dev, 324*31d98677SRui Paulo "could not allocate USB transfers, err=%s\n", 325*31d98677SRui Paulo usbd_errstr(error)); 326*31d98677SRui Paulo goto detach; 327*31d98677SRui Paulo } 328*31d98677SRui Paulo RSU_LOCK(sc); 329*31d98677SRui Paulo /* Read chip revision. */ 330*31d98677SRui Paulo sc->cut = MS(rsu_read_4(sc, R92S_PMC_FSM), R92S_PMC_FSM_CUT); 331*31d98677SRui Paulo if (sc->cut != 3) 332*31d98677SRui Paulo sc->cut = (sc->cut >> 1) + 1; 333*31d98677SRui Paulo error = rsu_read_rom(sc); 334*31d98677SRui Paulo if (error != 0) { 335*31d98677SRui Paulo device_printf(self, "could not read ROM\n"); 336*31d98677SRui Paulo goto detach; 337*31d98677SRui Paulo } 338*31d98677SRui Paulo RSU_UNLOCK(sc); 339*31d98677SRui Paulo IEEE80211_ADDR_COPY(sc->sc_bssid, &sc->rom[0x12]); 340*31d98677SRui Paulo device_printf(self, "MAC/BB RTL8712 cut %d\n", sc->cut); 341*31d98677SRui Paulo ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 342*31d98677SRui Paulo if (ifp == NULL) { 343*31d98677SRui Paulo device_printf(self, "cannot allocate interface\n"); 344*31d98677SRui Paulo goto detach; 345*31d98677SRui Paulo } 346*31d98677SRui Paulo ic = ifp->if_l2com; 347*31d98677SRui Paulo ifp->if_softc = sc; 348*31d98677SRui Paulo if_initname(ifp, "rsu", device_get_unit(self)); 349*31d98677SRui Paulo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 350*31d98677SRui Paulo ifp->if_init = rsu_init; 351*31d98677SRui Paulo ifp->if_ioctl = rsu_ioctl; 352*31d98677SRui Paulo ifp->if_start = rsu_start; 353*31d98677SRui Paulo IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 354*31d98677SRui Paulo ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 355*31d98677SRui Paulo IFQ_SET_READY(&ifp->if_snd); 356*31d98677SRui Paulo ifp->if_capabilities |= IFCAP_RXCSUM; 357*31d98677SRui Paulo ifp->if_capenable |= IFCAP_RXCSUM; 358*31d98677SRui Paulo ifp->if_hwassist = CSUM_TCP; 359*31d98677SRui Paulo 360*31d98677SRui Paulo ic->ic_ifp = ifp; 361*31d98677SRui Paulo ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */ 362*31d98677SRui Paulo ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */ 363*31d98677SRui Paulo 364*31d98677SRui Paulo /* Set device capabilities. */ 365*31d98677SRui Paulo ic->ic_caps = 366*31d98677SRui Paulo IEEE80211_C_STA | /* station mode */ 367*31d98677SRui Paulo IEEE80211_C_BGSCAN | /* Background scan. */ 368*31d98677SRui Paulo IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */ 369*31d98677SRui Paulo IEEE80211_C_SHSLOT | /* Short slot time supported. */ 370*31d98677SRui Paulo IEEE80211_C_WPA; /* WPA/RSN. */ 371*31d98677SRui Paulo 372*31d98677SRui Paulo #if 0 373*31d98677SRui Paulo /* Check if HT support is present. */ 374*31d98677SRui Paulo if (usb_lookup(rsu_devs_noht, uaa->vendor, uaa->product) == NULL) { 375*31d98677SRui Paulo /* Set HT capabilities. */ 376*31d98677SRui Paulo ic->ic_htcaps = 377*31d98677SRui Paulo IEEE80211_HTCAP_CBW20_40 | 378*31d98677SRui Paulo IEEE80211_HTCAP_DSSSCCK40; 379*31d98677SRui Paulo /* Set supported HT rates. */ 380*31d98677SRui Paulo for (i = 0; i < 2; i++) 381*31d98677SRui Paulo ic->ic_sup_mcs[i] = 0xff; 382*31d98677SRui Paulo } 383*31d98677SRui Paulo #endif 384*31d98677SRui Paulo 385*31d98677SRui Paulo /* Set supported .11b and .11g rates. */ 386*31d98677SRui Paulo bands = 0; 387*31d98677SRui Paulo setbit(&bands, IEEE80211_MODE_11B); 388*31d98677SRui Paulo setbit(&bands, IEEE80211_MODE_11G); 389*31d98677SRui Paulo ieee80211_init_channels(ic, NULL, &bands); 390*31d98677SRui Paulo 391*31d98677SRui Paulo ieee80211_ifattach(ic, sc->sc_bssid); 392*31d98677SRui Paulo ic->ic_raw_xmit = rsu_raw_xmit; 393*31d98677SRui Paulo ic->ic_scan_start = rsu_scan_start; 394*31d98677SRui Paulo ic->ic_scan_end = rsu_scan_end; 395*31d98677SRui Paulo ic->ic_set_channel = rsu_set_channel; 396*31d98677SRui Paulo ic->ic_vap_create = rsu_vap_create; 397*31d98677SRui Paulo ic->ic_vap_delete = rsu_vap_delete; 398*31d98677SRui Paulo ic->ic_update_mcast = rsu_update_mcast; 399*31d98677SRui Paulo 400*31d98677SRui Paulo ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, 401*31d98677SRui Paulo sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT, 402*31d98677SRui Paulo &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 403*31d98677SRui Paulo RSU_RX_RADIOTAP_PRESENT); 404*31d98677SRui Paulo 405*31d98677SRui Paulo if (bootverbose) 406*31d98677SRui Paulo ieee80211_announce(ic); 407*31d98677SRui Paulo 408*31d98677SRui Paulo return (0); 409*31d98677SRui Paulo 410*31d98677SRui Paulo detach: 411*31d98677SRui Paulo rsu_detach(self); 412*31d98677SRui Paulo return (ENXIO); 413*31d98677SRui Paulo } 414*31d98677SRui Paulo 415*31d98677SRui Paulo static int 416*31d98677SRui Paulo rsu_detach(device_t self) 417*31d98677SRui Paulo { 418*31d98677SRui Paulo struct rsu_softc *sc = device_get_softc(self); 419*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 420*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 421*31d98677SRui Paulo 422*31d98677SRui Paulo if (!device_is_attached(self)) 423*31d98677SRui Paulo return (0); 424*31d98677SRui Paulo rsu_stop(ifp, 1); 425*31d98677SRui Paulo usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER); 426*31d98677SRui Paulo ieee80211_ifdetach(ic); 427*31d98677SRui Paulo 428*31d98677SRui Paulo callout_drain(&sc->sc_watchdog_ch); 429*31d98677SRui Paulo taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); 430*31d98677SRui Paulo 431*31d98677SRui Paulo /* Free Tx/Rx buffers. */ 432*31d98677SRui Paulo rsu_free_tx_list(sc); 433*31d98677SRui Paulo rsu_free_rx_list(sc); 434*31d98677SRui Paulo 435*31d98677SRui Paulo if_free(ifp); 436*31d98677SRui Paulo mtx_destroy(&sc->sc_mtx); 437*31d98677SRui Paulo 438*31d98677SRui Paulo return (0); 439*31d98677SRui Paulo } 440*31d98677SRui Paulo 441*31d98677SRui Paulo static usb_error_t 442*31d98677SRui Paulo rsu_do_request(struct rsu_softc *sc, struct usb_device_request *req, 443*31d98677SRui Paulo void *data) 444*31d98677SRui Paulo { 445*31d98677SRui Paulo usb_error_t err; 446*31d98677SRui Paulo int ntries = 10; 447*31d98677SRui Paulo 448*31d98677SRui Paulo RSU_ASSERT_LOCKED(sc); 449*31d98677SRui Paulo 450*31d98677SRui Paulo while (ntries--) { 451*31d98677SRui Paulo err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 452*31d98677SRui Paulo req, data, 0, NULL, 250 /* ms */); 453*31d98677SRui Paulo if (err == 0 || !device_is_attached(sc->sc_dev)) 454*31d98677SRui Paulo break; 455*31d98677SRui Paulo DPRINTFN(1, "Control request failed, %s (retrying)\n", 456*31d98677SRui Paulo usbd_errstr(err)); 457*31d98677SRui Paulo usb_pause_mtx(&sc->sc_mtx, hz / 100); 458*31d98677SRui Paulo } 459*31d98677SRui Paulo 460*31d98677SRui Paulo return (err); 461*31d98677SRui Paulo } 462*31d98677SRui Paulo 463*31d98677SRui Paulo static struct ieee80211vap * 464*31d98677SRui Paulo rsu_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 465*31d98677SRui Paulo enum ieee80211_opmode opmode, int flags, 466*31d98677SRui Paulo const uint8_t bssid[IEEE80211_ADDR_LEN], 467*31d98677SRui Paulo const uint8_t mac[IEEE80211_ADDR_LEN]) 468*31d98677SRui Paulo { 469*31d98677SRui Paulo struct rsu_vap *uvp; 470*31d98677SRui Paulo struct ieee80211vap *vap; 471*31d98677SRui Paulo 472*31d98677SRui Paulo if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 473*31d98677SRui Paulo return (NULL); 474*31d98677SRui Paulo 475*31d98677SRui Paulo uvp = (struct rsu_vap *) malloc(sizeof(struct rsu_vap), 476*31d98677SRui Paulo M_80211_VAP, M_NOWAIT | M_ZERO); 477*31d98677SRui Paulo if (uvp == NULL) 478*31d98677SRui Paulo return (NULL); 479*31d98677SRui Paulo vap = &uvp->vap; 480*31d98677SRui Paulo ieee80211_vap_setup(ic, vap, name, unit, opmode, 481*31d98677SRui Paulo flags, bssid, mac); 482*31d98677SRui Paulo 483*31d98677SRui Paulo /* override state transition machine */ 484*31d98677SRui Paulo uvp->newstate = vap->iv_newstate; 485*31d98677SRui Paulo vap->iv_newstate = rsu_newstate; 486*31d98677SRui Paulo 487*31d98677SRui Paulo /* complete setup */ 488*31d98677SRui Paulo ieee80211_vap_attach(vap, ieee80211_media_change, 489*31d98677SRui Paulo ieee80211_media_status); 490*31d98677SRui Paulo ic->ic_opmode = opmode; 491*31d98677SRui Paulo 492*31d98677SRui Paulo return (vap); 493*31d98677SRui Paulo } 494*31d98677SRui Paulo 495*31d98677SRui Paulo static void 496*31d98677SRui Paulo rsu_vap_delete(struct ieee80211vap *vap) 497*31d98677SRui Paulo { 498*31d98677SRui Paulo struct rsu_vap *uvp = RSU_VAP(vap); 499*31d98677SRui Paulo 500*31d98677SRui Paulo ieee80211_vap_detach(vap); 501*31d98677SRui Paulo free(uvp, M_80211_VAP); 502*31d98677SRui Paulo } 503*31d98677SRui Paulo 504*31d98677SRui Paulo static void 505*31d98677SRui Paulo rsu_scan_start(struct ieee80211com *ic) 506*31d98677SRui Paulo { 507*31d98677SRui Paulo int error; 508*31d98677SRui Paulo struct ifnet *ifp = ic->ic_ifp; 509*31d98677SRui Paulo struct rsu_softc *sc = ifp->if_softc; 510*31d98677SRui Paulo 511*31d98677SRui Paulo /* Scanning is done by the firmware. */ 512*31d98677SRui Paulo RSU_LOCK(sc); 513*31d98677SRui Paulo error = rsu_site_survey(sc, TAILQ_FIRST(&ic->ic_vaps)); 514*31d98677SRui Paulo RSU_UNLOCK(sc); 515*31d98677SRui Paulo if (error != 0) 516*31d98677SRui Paulo device_printf(sc->sc_dev, 517*31d98677SRui Paulo "could not send site survey command\n"); 518*31d98677SRui Paulo } 519*31d98677SRui Paulo 520*31d98677SRui Paulo static void 521*31d98677SRui Paulo rsu_scan_end(struct ieee80211com *ic) 522*31d98677SRui Paulo { 523*31d98677SRui Paulo /* Nothing to do here. */ 524*31d98677SRui Paulo } 525*31d98677SRui Paulo 526*31d98677SRui Paulo static void 527*31d98677SRui Paulo rsu_set_channel(struct ieee80211com *ic __unused) 528*31d98677SRui Paulo { 529*31d98677SRui Paulo /* We are unable to switch channels, yet. */ 530*31d98677SRui Paulo } 531*31d98677SRui Paulo 532*31d98677SRui Paulo static void 533*31d98677SRui Paulo rsu_update_mcast(struct ifnet *ifp) 534*31d98677SRui Paulo { 535*31d98677SRui Paulo /* XXX do nothing? */ 536*31d98677SRui Paulo } 537*31d98677SRui Paulo 538*31d98677SRui Paulo static int 539*31d98677SRui Paulo rsu_alloc_list(struct rsu_softc *sc, struct rsu_data data[], 540*31d98677SRui Paulo int ndata, int maxsz) 541*31d98677SRui Paulo { 542*31d98677SRui Paulo int i, error; 543*31d98677SRui Paulo 544*31d98677SRui Paulo for (i = 0; i < ndata; i++) { 545*31d98677SRui Paulo struct rsu_data *dp = &data[i]; 546*31d98677SRui Paulo dp->sc = sc; 547*31d98677SRui Paulo dp->m = NULL; 548*31d98677SRui Paulo dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); 549*31d98677SRui Paulo if (dp->buf == NULL) { 550*31d98677SRui Paulo device_printf(sc->sc_dev, 551*31d98677SRui Paulo "could not allocate buffer\n"); 552*31d98677SRui Paulo error = ENOMEM; 553*31d98677SRui Paulo goto fail; 554*31d98677SRui Paulo } 555*31d98677SRui Paulo dp->ni = NULL; 556*31d98677SRui Paulo } 557*31d98677SRui Paulo 558*31d98677SRui Paulo return (0); 559*31d98677SRui Paulo fail: 560*31d98677SRui Paulo rsu_free_list(sc, data, ndata); 561*31d98677SRui Paulo return (error); 562*31d98677SRui Paulo } 563*31d98677SRui Paulo 564*31d98677SRui Paulo static int 565*31d98677SRui Paulo rsu_alloc_rx_list(struct rsu_softc *sc) 566*31d98677SRui Paulo { 567*31d98677SRui Paulo int error, i; 568*31d98677SRui Paulo 569*31d98677SRui Paulo error = rsu_alloc_list(sc, sc->sc_rx, RSU_RX_LIST_COUNT, 570*31d98677SRui Paulo RSU_RXBUFSZ); 571*31d98677SRui Paulo if (error != 0) 572*31d98677SRui Paulo return (error); 573*31d98677SRui Paulo 574*31d98677SRui Paulo STAILQ_INIT(&sc->sc_rx_active); 575*31d98677SRui Paulo STAILQ_INIT(&sc->sc_rx_inactive); 576*31d98677SRui Paulo 577*31d98677SRui Paulo for (i = 0; i < RSU_RX_LIST_COUNT; i++) 578*31d98677SRui Paulo STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next); 579*31d98677SRui Paulo 580*31d98677SRui Paulo return (0); 581*31d98677SRui Paulo } 582*31d98677SRui Paulo 583*31d98677SRui Paulo static int 584*31d98677SRui Paulo rsu_alloc_tx_list(struct rsu_softc *sc) 585*31d98677SRui Paulo { 586*31d98677SRui Paulo int error, i; 587*31d98677SRui Paulo 588*31d98677SRui Paulo error = rsu_alloc_list(sc, sc->sc_tx, RSU_TX_LIST_COUNT, 589*31d98677SRui Paulo RSU_TXBUFSZ); 590*31d98677SRui Paulo if (error != 0) 591*31d98677SRui Paulo return (error); 592*31d98677SRui Paulo 593*31d98677SRui Paulo STAILQ_INIT(&sc->sc_tx_active); 594*31d98677SRui Paulo STAILQ_INIT(&sc->sc_tx_inactive); 595*31d98677SRui Paulo STAILQ_INIT(&sc->sc_tx_pending); 596*31d98677SRui Paulo 597*31d98677SRui Paulo for (i = 0; i < RSU_TX_LIST_COUNT; i++) { 598*31d98677SRui Paulo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next); 599*31d98677SRui Paulo } 600*31d98677SRui Paulo 601*31d98677SRui Paulo return (0); 602*31d98677SRui Paulo } 603*31d98677SRui Paulo 604*31d98677SRui Paulo static void 605*31d98677SRui Paulo rsu_free_tx_list(struct rsu_softc *sc) 606*31d98677SRui Paulo { 607*31d98677SRui Paulo rsu_free_list(sc, sc->sc_tx, RSU_TX_LIST_COUNT); 608*31d98677SRui Paulo } 609*31d98677SRui Paulo 610*31d98677SRui Paulo static void 611*31d98677SRui Paulo rsu_free_rx_list(struct rsu_softc *sc) 612*31d98677SRui Paulo { 613*31d98677SRui Paulo rsu_free_list(sc, sc->sc_rx, RSU_RX_LIST_COUNT); 614*31d98677SRui Paulo } 615*31d98677SRui Paulo 616*31d98677SRui Paulo static void 617*31d98677SRui Paulo rsu_free_list(struct rsu_softc *sc, struct rsu_data data[], int ndata) 618*31d98677SRui Paulo { 619*31d98677SRui Paulo int i; 620*31d98677SRui Paulo 621*31d98677SRui Paulo for (i = 0; i < ndata; i++) { 622*31d98677SRui Paulo struct rsu_data *dp = &data[i]; 623*31d98677SRui Paulo 624*31d98677SRui Paulo if (dp->buf != NULL) { 625*31d98677SRui Paulo free(dp->buf, M_USBDEV); 626*31d98677SRui Paulo dp->buf = NULL; 627*31d98677SRui Paulo } 628*31d98677SRui Paulo if (dp->ni != NULL) { 629*31d98677SRui Paulo ieee80211_free_node(dp->ni); 630*31d98677SRui Paulo dp->ni = NULL; 631*31d98677SRui Paulo } 632*31d98677SRui Paulo } 633*31d98677SRui Paulo } 634*31d98677SRui Paulo 635*31d98677SRui Paulo static struct rsu_data * 636*31d98677SRui Paulo _rsu_getbuf(struct rsu_softc *sc) 637*31d98677SRui Paulo { 638*31d98677SRui Paulo struct rsu_data *bf; 639*31d98677SRui Paulo 640*31d98677SRui Paulo bf = STAILQ_FIRST(&sc->sc_tx_inactive); 641*31d98677SRui Paulo if (bf != NULL) 642*31d98677SRui Paulo STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); 643*31d98677SRui Paulo else 644*31d98677SRui Paulo bf = NULL; 645*31d98677SRui Paulo if (bf == NULL) 646*31d98677SRui Paulo DPRINTF("out of xmit buffers\n"); 647*31d98677SRui Paulo return (bf); 648*31d98677SRui Paulo } 649*31d98677SRui Paulo 650*31d98677SRui Paulo static struct rsu_data * 651*31d98677SRui Paulo rsu_getbuf(struct rsu_softc *sc) 652*31d98677SRui Paulo { 653*31d98677SRui Paulo struct rsu_data *bf; 654*31d98677SRui Paulo 655*31d98677SRui Paulo RSU_ASSERT_LOCKED(sc); 656*31d98677SRui Paulo 657*31d98677SRui Paulo bf = _rsu_getbuf(sc); 658*31d98677SRui Paulo if (bf == NULL) { 659*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 660*31d98677SRui Paulo DPRINTF("stop queue\n"); 661*31d98677SRui Paulo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 662*31d98677SRui Paulo } 663*31d98677SRui Paulo return (bf); 664*31d98677SRui Paulo } 665*31d98677SRui Paulo 666*31d98677SRui Paulo static int 667*31d98677SRui Paulo rsu_write_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf, 668*31d98677SRui Paulo int len) 669*31d98677SRui Paulo { 670*31d98677SRui Paulo usb_device_request_t req; 671*31d98677SRui Paulo 672*31d98677SRui Paulo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 673*31d98677SRui Paulo req.bRequest = R92S_REQ_REGS; 674*31d98677SRui Paulo USETW(req.wValue, addr); 675*31d98677SRui Paulo USETW(req.wIndex, 0); 676*31d98677SRui Paulo USETW(req.wLength, len); 677*31d98677SRui Paulo 678*31d98677SRui Paulo return (rsu_do_request(sc, &req, buf)); 679*31d98677SRui Paulo } 680*31d98677SRui Paulo 681*31d98677SRui Paulo static void 682*31d98677SRui Paulo rsu_write_1(struct rsu_softc *sc, uint16_t addr, uint8_t val) 683*31d98677SRui Paulo { 684*31d98677SRui Paulo rsu_write_region_1(sc, addr, &val, 1); 685*31d98677SRui Paulo } 686*31d98677SRui Paulo 687*31d98677SRui Paulo static void 688*31d98677SRui Paulo rsu_write_2(struct rsu_softc *sc, uint16_t addr, uint16_t val) 689*31d98677SRui Paulo { 690*31d98677SRui Paulo val = htole16(val); 691*31d98677SRui Paulo rsu_write_region_1(sc, addr, (uint8_t *)&val, 2); 692*31d98677SRui Paulo } 693*31d98677SRui Paulo 694*31d98677SRui Paulo static void 695*31d98677SRui Paulo rsu_write_4(struct rsu_softc *sc, uint16_t addr, uint32_t val) 696*31d98677SRui Paulo { 697*31d98677SRui Paulo val = htole32(val); 698*31d98677SRui Paulo rsu_write_region_1(sc, addr, (uint8_t *)&val, 4); 699*31d98677SRui Paulo } 700*31d98677SRui Paulo 701*31d98677SRui Paulo static int 702*31d98677SRui Paulo rsu_read_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf, 703*31d98677SRui Paulo int len) 704*31d98677SRui Paulo { 705*31d98677SRui Paulo usb_device_request_t req; 706*31d98677SRui Paulo 707*31d98677SRui Paulo req.bmRequestType = UT_READ_VENDOR_DEVICE; 708*31d98677SRui Paulo req.bRequest = R92S_REQ_REGS; 709*31d98677SRui Paulo USETW(req.wValue, addr); 710*31d98677SRui Paulo USETW(req.wIndex, 0); 711*31d98677SRui Paulo USETW(req.wLength, len); 712*31d98677SRui Paulo 713*31d98677SRui Paulo return (rsu_do_request(sc, &req, buf)); 714*31d98677SRui Paulo } 715*31d98677SRui Paulo 716*31d98677SRui Paulo static uint8_t 717*31d98677SRui Paulo rsu_read_1(struct rsu_softc *sc, uint16_t addr) 718*31d98677SRui Paulo { 719*31d98677SRui Paulo uint8_t val; 720*31d98677SRui Paulo 721*31d98677SRui Paulo if (rsu_read_region_1(sc, addr, &val, 1) != 0) 722*31d98677SRui Paulo return (0xff); 723*31d98677SRui Paulo return (val); 724*31d98677SRui Paulo } 725*31d98677SRui Paulo 726*31d98677SRui Paulo static uint16_t 727*31d98677SRui Paulo rsu_read_2(struct rsu_softc *sc, uint16_t addr) 728*31d98677SRui Paulo { 729*31d98677SRui Paulo uint16_t val; 730*31d98677SRui Paulo 731*31d98677SRui Paulo if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) 732*31d98677SRui Paulo return (0xffff); 733*31d98677SRui Paulo return (le16toh(val)); 734*31d98677SRui Paulo } 735*31d98677SRui Paulo 736*31d98677SRui Paulo static uint32_t 737*31d98677SRui Paulo rsu_read_4(struct rsu_softc *sc, uint16_t addr) 738*31d98677SRui Paulo { 739*31d98677SRui Paulo uint32_t val; 740*31d98677SRui Paulo 741*31d98677SRui Paulo if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) 742*31d98677SRui Paulo return (0xffffffff); 743*31d98677SRui Paulo return (le32toh(val)); 744*31d98677SRui Paulo } 745*31d98677SRui Paulo 746*31d98677SRui Paulo static int 747*31d98677SRui Paulo rsu_fw_iocmd(struct rsu_softc *sc, uint32_t iocmd) 748*31d98677SRui Paulo { 749*31d98677SRui Paulo int ntries; 750*31d98677SRui Paulo 751*31d98677SRui Paulo rsu_write_4(sc, R92S_IOCMD_CTRL, iocmd); 752*31d98677SRui Paulo DELAY(100); 753*31d98677SRui Paulo for (ntries = 0; ntries < 50; ntries++) { 754*31d98677SRui Paulo if (rsu_read_4(sc, R92S_IOCMD_CTRL) == 0) 755*31d98677SRui Paulo return (0); 756*31d98677SRui Paulo DELAY(10); 757*31d98677SRui Paulo } 758*31d98677SRui Paulo return (ETIMEDOUT); 759*31d98677SRui Paulo } 760*31d98677SRui Paulo 761*31d98677SRui Paulo static uint8_t 762*31d98677SRui Paulo rsu_efuse_read_1(struct rsu_softc *sc, uint16_t addr) 763*31d98677SRui Paulo { 764*31d98677SRui Paulo uint32_t reg; 765*31d98677SRui Paulo int ntries; 766*31d98677SRui Paulo 767*31d98677SRui Paulo reg = rsu_read_4(sc, R92S_EFUSE_CTRL); 768*31d98677SRui Paulo reg = RW(reg, R92S_EFUSE_CTRL_ADDR, addr); 769*31d98677SRui Paulo reg &= ~R92S_EFUSE_CTRL_VALID; 770*31d98677SRui Paulo rsu_write_4(sc, R92S_EFUSE_CTRL, reg); 771*31d98677SRui Paulo /* Wait for read operation to complete. */ 772*31d98677SRui Paulo for (ntries = 0; ntries < 100; ntries++) { 773*31d98677SRui Paulo reg = rsu_read_4(sc, R92S_EFUSE_CTRL); 774*31d98677SRui Paulo if (reg & R92S_EFUSE_CTRL_VALID) 775*31d98677SRui Paulo return (MS(reg, R92S_EFUSE_CTRL_DATA)); 776*31d98677SRui Paulo DELAY(5); 777*31d98677SRui Paulo } 778*31d98677SRui Paulo device_printf(sc->sc_dev, 779*31d98677SRui Paulo "could not read efuse byte at address 0x%x\n", addr); 780*31d98677SRui Paulo return (0xff); 781*31d98677SRui Paulo } 782*31d98677SRui Paulo 783*31d98677SRui Paulo static int 784*31d98677SRui Paulo rsu_read_rom(struct rsu_softc *sc) 785*31d98677SRui Paulo { 786*31d98677SRui Paulo uint8_t *rom = sc->rom; 787*31d98677SRui Paulo uint16_t addr = 0; 788*31d98677SRui Paulo uint32_t reg; 789*31d98677SRui Paulo uint8_t off, msk; 790*31d98677SRui Paulo int i; 791*31d98677SRui Paulo 792*31d98677SRui Paulo /* Make sure that ROM type is eFuse and that autoload succeeded. */ 793*31d98677SRui Paulo reg = rsu_read_1(sc, R92S_EE_9346CR); 794*31d98677SRui Paulo if ((reg & (R92S_9356SEL | R92S_EEPROM_EN)) != R92S_EEPROM_EN) 795*31d98677SRui Paulo return (EIO); 796*31d98677SRui Paulo 797*31d98677SRui Paulo /* Turn on 2.5V to prevent eFuse leakage. */ 798*31d98677SRui Paulo reg = rsu_read_1(sc, R92S_EFUSE_TEST + 3); 799*31d98677SRui Paulo rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg | 0x80); 800*31d98677SRui Paulo DELAY(1000); 801*31d98677SRui Paulo rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg & ~0x80); 802*31d98677SRui Paulo 803*31d98677SRui Paulo /* Read full ROM image. */ 804*31d98677SRui Paulo memset(&sc->rom, 0xff, sizeof(sc->rom)); 805*31d98677SRui Paulo while (addr < 512) { 806*31d98677SRui Paulo reg = rsu_efuse_read_1(sc, addr); 807*31d98677SRui Paulo if (reg == 0xff) 808*31d98677SRui Paulo break; 809*31d98677SRui Paulo addr++; 810*31d98677SRui Paulo off = reg >> 4; 811*31d98677SRui Paulo msk = reg & 0xf; 812*31d98677SRui Paulo for (i = 0; i < 4; i++) { 813*31d98677SRui Paulo if (msk & (1 << i)) 814*31d98677SRui Paulo continue; 815*31d98677SRui Paulo rom[off * 8 + i * 2 + 0] = 816*31d98677SRui Paulo rsu_efuse_read_1(sc, addr); 817*31d98677SRui Paulo addr++; 818*31d98677SRui Paulo rom[off * 8 + i * 2 + 1] = 819*31d98677SRui Paulo rsu_efuse_read_1(sc, addr); 820*31d98677SRui Paulo addr++; 821*31d98677SRui Paulo } 822*31d98677SRui Paulo } 823*31d98677SRui Paulo #ifdef USB_DEBUG 824*31d98677SRui Paulo if (rsu_debug >= 5) { 825*31d98677SRui Paulo /* Dump ROM content. */ 826*31d98677SRui Paulo printf("\n"); 827*31d98677SRui Paulo for (i = 0; i < sizeof(sc->rom); i++) 828*31d98677SRui Paulo printf("%02x:", rom[i]); 829*31d98677SRui Paulo printf("\n"); 830*31d98677SRui Paulo } 831*31d98677SRui Paulo #endif 832*31d98677SRui Paulo return (0); 833*31d98677SRui Paulo } 834*31d98677SRui Paulo 835*31d98677SRui Paulo static int 836*31d98677SRui Paulo rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len) 837*31d98677SRui Paulo { 838*31d98677SRui Paulo struct rsu_data *data; 839*31d98677SRui Paulo struct r92s_tx_desc *txd; 840*31d98677SRui Paulo struct r92s_fw_cmd_hdr *cmd; 841*31d98677SRui Paulo int cmdsz, xferlen; 842*31d98677SRui Paulo 843*31d98677SRui Paulo data = rsu_getbuf(sc); 844*31d98677SRui Paulo if (data == NULL) 845*31d98677SRui Paulo return (ENOMEM); 846*31d98677SRui Paulo 847*31d98677SRui Paulo /* Round-up command length to a multiple of 8 bytes. */ 848*31d98677SRui Paulo cmdsz = (len + 7) & ~7; 849*31d98677SRui Paulo 850*31d98677SRui Paulo xferlen = sizeof(*txd) + sizeof(*cmd) + cmdsz; 851*31d98677SRui Paulo KASSERT(xferlen <= RSU_TXBUFSZ, ("%s: invalid length", __func__)); 852*31d98677SRui Paulo memset(data->buf, 0, xferlen); 853*31d98677SRui Paulo 854*31d98677SRui Paulo /* Setup Tx descriptor. */ 855*31d98677SRui Paulo txd = (struct r92s_tx_desc *)data->buf; 856*31d98677SRui Paulo txd->txdw0 = htole32( 857*31d98677SRui Paulo SM(R92S_TXDW0_OFFSET, sizeof(*txd)) | 858*31d98677SRui Paulo SM(R92S_TXDW0_PKTLEN, sizeof(*cmd) + cmdsz) | 859*31d98677SRui Paulo R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG); 860*31d98677SRui Paulo txd->txdw1 = htole32(SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_H2C)); 861*31d98677SRui Paulo 862*31d98677SRui Paulo /* Setup command header. */ 863*31d98677SRui Paulo cmd = (struct r92s_fw_cmd_hdr *)&txd[1]; 864*31d98677SRui Paulo cmd->len = htole16(cmdsz); 865*31d98677SRui Paulo cmd->code = code; 866*31d98677SRui Paulo cmd->seq = sc->cmd_seq; 867*31d98677SRui Paulo sc->cmd_seq = (sc->cmd_seq + 1) & 0x7f; 868*31d98677SRui Paulo 869*31d98677SRui Paulo /* Copy command payload. */ 870*31d98677SRui Paulo memcpy(&cmd[1], buf, len); 871*31d98677SRui Paulo 872*31d98677SRui Paulo DPRINTFN(2, "Tx cmd code=0x%x len=0x%x\n", code, cmdsz); 873*31d98677SRui Paulo data->buflen = xferlen; 874*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); 875*31d98677SRui Paulo usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]); 876*31d98677SRui Paulo 877*31d98677SRui Paulo return (0); 878*31d98677SRui Paulo } 879*31d98677SRui Paulo 880*31d98677SRui Paulo /* ARGSUSED */ 881*31d98677SRui Paulo static void 882*31d98677SRui Paulo rsu_calib_task(void *arg, int pending __unused) 883*31d98677SRui Paulo { 884*31d98677SRui Paulo struct rsu_softc *sc = arg; 885*31d98677SRui Paulo uint32_t reg; 886*31d98677SRui Paulo 887*31d98677SRui Paulo DPRINTFN(6, "running calibration task\n"); 888*31d98677SRui Paulo RSU_LOCK(sc); 889*31d98677SRui Paulo #ifdef notyet 890*31d98677SRui Paulo /* Read WPS PBC status. */ 891*31d98677SRui Paulo rsu_write_1(sc, R92S_MAC_PINMUX_CTRL, 892*31d98677SRui Paulo R92S_GPIOMUX_EN | SM(R92S_GPIOSEL_GPIO, R92S_GPIOSEL_GPIO_JTAG)); 893*31d98677SRui Paulo rsu_write_1(sc, R92S_GPIO_IO_SEL, 894*31d98677SRui Paulo rsu_read_1(sc, R92S_GPIO_IO_SEL) & ~R92S_GPIO_WPS); 895*31d98677SRui Paulo reg = rsu_read_1(sc, R92S_GPIO_CTRL); 896*31d98677SRui Paulo if (reg != 0xff && (reg & R92S_GPIO_WPS)) 897*31d98677SRui Paulo DPRINTF(("WPS PBC is pushed\n")); 898*31d98677SRui Paulo #endif 899*31d98677SRui Paulo /* Read current signal level. */ 900*31d98677SRui Paulo if (rsu_fw_iocmd(sc, 0xf4000001) == 0) { 901*31d98677SRui Paulo reg = rsu_read_4(sc, R92S_IOCMD_DATA); 902*31d98677SRui Paulo DPRINTFN(8, "RSSI=%d%%\n", reg >> 4); 903*31d98677SRui Paulo } 904*31d98677SRui Paulo if (sc->sc_calibrating) { 905*31d98677SRui Paulo RSU_UNLOCK(sc); 906*31d98677SRui Paulo taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task, 907*31d98677SRui Paulo hz * 2); 908*31d98677SRui Paulo } else 909*31d98677SRui Paulo RSU_UNLOCK(sc); 910*31d98677SRui Paulo } 911*31d98677SRui Paulo 912*31d98677SRui Paulo static int 913*31d98677SRui Paulo rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 914*31d98677SRui Paulo { 915*31d98677SRui Paulo struct rsu_vap *uvp = RSU_VAP(vap); 916*31d98677SRui Paulo struct ieee80211com *ic = vap->iv_ic; 917*31d98677SRui Paulo struct rsu_softc *sc = ic->ic_ifp->if_softc; 918*31d98677SRui Paulo struct ieee80211_node *ni; 919*31d98677SRui Paulo struct ieee80211_rateset *rs; 920*31d98677SRui Paulo enum ieee80211_state ostate; 921*31d98677SRui Paulo int error, startcal = 0; 922*31d98677SRui Paulo 923*31d98677SRui Paulo ostate = vap->iv_state; 924*31d98677SRui Paulo DPRINTF("%s -> %s\n", ieee80211_state_name[ostate], 925*31d98677SRui Paulo ieee80211_state_name[nstate]); 926*31d98677SRui Paulo 927*31d98677SRui Paulo IEEE80211_UNLOCK(ic); 928*31d98677SRui Paulo if (ostate == IEEE80211_S_RUN) { 929*31d98677SRui Paulo RSU_LOCK(sc); 930*31d98677SRui Paulo /* Stop calibration. */ 931*31d98677SRui Paulo sc->sc_calibrating = 0; 932*31d98677SRui Paulo RSU_UNLOCK(sc); 933*31d98677SRui Paulo taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task); 934*31d98677SRui Paulo /* Disassociate from our current BSS. */ 935*31d98677SRui Paulo RSU_LOCK(sc); 936*31d98677SRui Paulo rsu_disconnect(sc); 937*31d98677SRui Paulo } else 938*31d98677SRui Paulo RSU_LOCK(sc); 939*31d98677SRui Paulo switch (nstate) { 940*31d98677SRui Paulo case IEEE80211_S_INIT: 941*31d98677SRui Paulo break; 942*31d98677SRui Paulo case IEEE80211_S_AUTH: 943*31d98677SRui Paulo ni = ieee80211_ref_node(vap->iv_bss); 944*31d98677SRui Paulo error = rsu_join_bss(sc, ni); 945*31d98677SRui Paulo ieee80211_free_node(ni); 946*31d98677SRui Paulo if (error != 0) { 947*31d98677SRui Paulo device_printf(sc->sc_dev, 948*31d98677SRui Paulo "could not send join command\n"); 949*31d98677SRui Paulo } 950*31d98677SRui Paulo break; 951*31d98677SRui Paulo case IEEE80211_S_RUN: 952*31d98677SRui Paulo ni = ieee80211_ref_node(vap->iv_bss); 953*31d98677SRui Paulo rs = &ni->ni_rates; 954*31d98677SRui Paulo /* Indicate highest supported rate. */ 955*31d98677SRui Paulo ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; 956*31d98677SRui Paulo ieee80211_free_node(ni); 957*31d98677SRui Paulo startcal = 1; 958*31d98677SRui Paulo break; 959*31d98677SRui Paulo default: 960*31d98677SRui Paulo break; 961*31d98677SRui Paulo } 962*31d98677SRui Paulo sc->sc_calibrating = 1; 963*31d98677SRui Paulo RSU_UNLOCK(sc); 964*31d98677SRui Paulo IEEE80211_LOCK(ic); 965*31d98677SRui Paulo /* Start periodic calibration. */ 966*31d98677SRui Paulo taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task, hz * 2); 967*31d98677SRui Paulo 968*31d98677SRui Paulo return (uvp->newstate(vap, nstate, arg)); 969*31d98677SRui Paulo } 970*31d98677SRui Paulo 971*31d98677SRui Paulo #ifdef notyet 972*31d98677SRui Paulo static void 973*31d98677SRui Paulo rsu_set_key(struct rsu_softc *sc, const struct ieee80211_key *k) 974*31d98677SRui Paulo { 975*31d98677SRui Paulo struct r92s_fw_cmd_set_key key; 976*31d98677SRui Paulo 977*31d98677SRui Paulo memset(&key, 0, sizeof(key)); 978*31d98677SRui Paulo /* Map net80211 cipher to HW crypto algorithm. */ 979*31d98677SRui Paulo switch (k->wk_cipher->ic_cipher) { 980*31d98677SRui Paulo case IEEE80211_CIPHER_WEP: 981*31d98677SRui Paulo if (k->wk_keylen < 8) 982*31d98677SRui Paulo key.algo = R92S_KEY_ALGO_WEP40; 983*31d98677SRui Paulo else 984*31d98677SRui Paulo key.algo = R92S_KEY_ALGO_WEP104; 985*31d98677SRui Paulo break; 986*31d98677SRui Paulo case IEEE80211_CIPHER_TKIP: 987*31d98677SRui Paulo key.algo = R92S_KEY_ALGO_TKIP; 988*31d98677SRui Paulo break; 989*31d98677SRui Paulo case IEEE80211_CIPHER_AES_CCM: 990*31d98677SRui Paulo key.algo = R92S_KEY_ALGO_AES; 991*31d98677SRui Paulo break; 992*31d98677SRui Paulo default: 993*31d98677SRui Paulo return; 994*31d98677SRui Paulo } 995*31d98677SRui Paulo key.id = k->wk_keyix; 996*31d98677SRui Paulo key.grpkey = (k->wk_flags & IEEE80211_KEY_GROUP) != 0; 997*31d98677SRui Paulo memcpy(key.key, k->wk_key, MIN(k->wk_keylen, sizeof(key.key))); 998*31d98677SRui Paulo (void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key)); 999*31d98677SRui Paulo } 1000*31d98677SRui Paulo 1001*31d98677SRui Paulo static void 1002*31d98677SRui Paulo rsu_delete_key(struct rsu_softc *sc, const struct ieee80211_key *k) 1003*31d98677SRui Paulo { 1004*31d98677SRui Paulo struct r92s_fw_cmd_set_key key; 1005*31d98677SRui Paulo 1006*31d98677SRui Paulo memset(&key, 0, sizeof(key)); 1007*31d98677SRui Paulo key.id = k->wk_keyix; 1008*31d98677SRui Paulo (void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key)); 1009*31d98677SRui Paulo } 1010*31d98677SRui Paulo #endif 1011*31d98677SRui Paulo 1012*31d98677SRui Paulo static int 1013*31d98677SRui Paulo rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap) 1014*31d98677SRui Paulo { 1015*31d98677SRui Paulo struct r92s_fw_cmd_sitesurvey cmd; 1016*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1017*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1018*31d98677SRui Paulo 1019*31d98677SRui Paulo memset(&cmd, 0, sizeof(cmd)); 1020*31d98677SRui Paulo if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->scan_pass == 1) 1021*31d98677SRui Paulo cmd.active = htole32(1); 1022*31d98677SRui Paulo cmd.limit = htole32(48); 1023*31d98677SRui Paulo if (sc->scan_pass == 1 && vap->iv_des_nssid > 0) { 1024*31d98677SRui Paulo /* Do a directed scan for second pass. */ 1025*31d98677SRui Paulo cmd.ssidlen = htole32(vap->iv_des_ssid[0].len); 1026*31d98677SRui Paulo memcpy(cmd.ssid, vap->iv_des_ssid[0].ssid, 1027*31d98677SRui Paulo vap->iv_des_ssid[0].len); 1028*31d98677SRui Paulo 1029*31d98677SRui Paulo } 1030*31d98677SRui Paulo DPRINTF("sending site survey command, pass=%d\n", sc->scan_pass); 1031*31d98677SRui Paulo return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd))); 1032*31d98677SRui Paulo } 1033*31d98677SRui Paulo 1034*31d98677SRui Paulo static int 1035*31d98677SRui Paulo rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) 1036*31d98677SRui Paulo { 1037*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1038*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1039*31d98677SRui Paulo struct ieee80211vap *vap = ni->ni_vap; 1040*31d98677SRui Paulo struct ndis_wlan_bssid_ex *bss; 1041*31d98677SRui Paulo struct ndis_802_11_fixed_ies *fixed; 1042*31d98677SRui Paulo struct r92s_fw_cmd_auth auth; 1043*31d98677SRui Paulo uint8_t buf[sizeof(*bss) + 128], *frm; 1044*31d98677SRui Paulo uint8_t opmode; 1045*31d98677SRui Paulo int error; 1046*31d98677SRui Paulo 1047*31d98677SRui Paulo /* Let the FW decide the opmode based on the capinfo field. */ 1048*31d98677SRui Paulo opmode = NDIS802_11AUTOUNKNOWN; 1049*31d98677SRui Paulo DPRINTF("setting operating mode to %d\n", opmode); 1050*31d98677SRui Paulo error = rsu_fw_cmd(sc, R92S_CMD_SET_OPMODE, &opmode, sizeof(opmode)); 1051*31d98677SRui Paulo if (error != 0) 1052*31d98677SRui Paulo return (error); 1053*31d98677SRui Paulo 1054*31d98677SRui Paulo memset(&auth, 0, sizeof(auth)); 1055*31d98677SRui Paulo if (vap->iv_flags & IEEE80211_F_WPA) { 1056*31d98677SRui Paulo auth.mode = R92S_AUTHMODE_WPA; 1057*31d98677SRui Paulo auth.dot1x = ni->ni_authmode == IEEE80211_AUTH_8021X; 1058*31d98677SRui Paulo } else 1059*31d98677SRui Paulo auth.mode = R92S_AUTHMODE_OPEN; 1060*31d98677SRui Paulo DPRINTF("setting auth mode to %d\n", auth.mode); 1061*31d98677SRui Paulo error = rsu_fw_cmd(sc, R92S_CMD_SET_AUTH, &auth, sizeof(auth)); 1062*31d98677SRui Paulo if (error != 0) 1063*31d98677SRui Paulo return (error); 1064*31d98677SRui Paulo 1065*31d98677SRui Paulo memset(buf, 0, sizeof(buf)); 1066*31d98677SRui Paulo bss = (struct ndis_wlan_bssid_ex *)buf; 1067*31d98677SRui Paulo IEEE80211_ADDR_COPY(bss->macaddr, ni->ni_bssid); 1068*31d98677SRui Paulo bss->ssid.ssidlen = htole32(ni->ni_esslen); 1069*31d98677SRui Paulo memcpy(bss->ssid.ssid, ni->ni_essid, ni->ni_esslen); 1070*31d98677SRui Paulo if (vap->iv_flags & (IEEE80211_F_PRIVACY | IEEE80211_F_WPA)) 1071*31d98677SRui Paulo bss->privacy = htole32(1); 1072*31d98677SRui Paulo bss->rssi = htole32(ni->ni_avgrssi); 1073*31d98677SRui Paulo if (ic->ic_curmode == IEEE80211_MODE_11B) 1074*31d98677SRui Paulo bss->networktype = htole32(NDIS802_11DS); 1075*31d98677SRui Paulo else 1076*31d98677SRui Paulo bss->networktype = htole32(NDIS802_11OFDM24); 1077*31d98677SRui Paulo bss->config.len = htole32(sizeof(bss->config)); 1078*31d98677SRui Paulo bss->config.bintval = htole32(ni->ni_intval); 1079*31d98677SRui Paulo bss->config.dsconfig = htole32(ieee80211_chan2ieee(ic, ni->ni_chan)); 1080*31d98677SRui Paulo bss->inframode = htole32(NDIS802_11INFRASTRUCTURE); 1081*31d98677SRui Paulo memcpy(bss->supprates, ni->ni_rates.rs_rates, 1082*31d98677SRui Paulo ni->ni_rates.rs_nrates); 1083*31d98677SRui Paulo /* Write the fixed fields of the beacon frame. */ 1084*31d98677SRui Paulo fixed = (struct ndis_802_11_fixed_ies *)&bss[1]; 1085*31d98677SRui Paulo memcpy(&fixed->tstamp, ni->ni_tstamp.data, 8); 1086*31d98677SRui Paulo fixed->bintval = htole16(ni->ni_intval); 1087*31d98677SRui Paulo fixed->capabilities = htole16(ni->ni_capinfo); 1088*31d98677SRui Paulo /* Write IEs to be included in the association request. */ 1089*31d98677SRui Paulo frm = (uint8_t *)&fixed[1]; 1090*31d98677SRui Paulo frm = ieee80211_add_rsn(frm, vap); 1091*31d98677SRui Paulo frm = ieee80211_add_wpa(frm, vap); 1092*31d98677SRui Paulo frm = ieee80211_add_qos(frm, ni); 1093*31d98677SRui Paulo if (ni->ni_flags & IEEE80211_NODE_HT) 1094*31d98677SRui Paulo frm = ieee80211_add_htcap(frm, ni); 1095*31d98677SRui Paulo bss->ieslen = htole32(frm - (uint8_t *)fixed); 1096*31d98677SRui Paulo bss->len = htole32(((frm - buf) + 3) & ~3); 1097*31d98677SRui Paulo DPRINTF("sending join bss command to %s chan %d\n", 1098*31d98677SRui Paulo ether_sprintf(bss->macaddr), le32toh(bss->config.dsconfig)); 1099*31d98677SRui Paulo return (rsu_fw_cmd(sc, R92S_CMD_JOIN_BSS, buf, sizeof(buf))); 1100*31d98677SRui Paulo } 1101*31d98677SRui Paulo 1102*31d98677SRui Paulo static int 1103*31d98677SRui Paulo rsu_disconnect(struct rsu_softc *sc) 1104*31d98677SRui Paulo { 1105*31d98677SRui Paulo uint32_t zero = 0; /* :-) */ 1106*31d98677SRui Paulo 1107*31d98677SRui Paulo /* Disassociate from our current BSS. */ 1108*31d98677SRui Paulo DPRINTF("sending disconnect command\n"); 1109*31d98677SRui Paulo return (rsu_fw_cmd(sc, R92S_CMD_DISCONNECT, &zero, sizeof(zero))); 1110*31d98677SRui Paulo } 1111*31d98677SRui Paulo 1112*31d98677SRui Paulo static void 1113*31d98677SRui Paulo rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) 1114*31d98677SRui Paulo { 1115*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1116*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1117*31d98677SRui Paulo struct ieee80211_frame *wh; 1118*31d98677SRui Paulo struct ieee80211_channel *c; 1119*31d98677SRui Paulo struct ndis_wlan_bssid_ex *bss; 1120*31d98677SRui Paulo struct mbuf *m; 1121*31d98677SRui Paulo int pktlen; 1122*31d98677SRui Paulo 1123*31d98677SRui Paulo if (__predict_false(len < sizeof(*bss))) 1124*31d98677SRui Paulo return; 1125*31d98677SRui Paulo bss = (struct ndis_wlan_bssid_ex *)buf; 1126*31d98677SRui Paulo if (__predict_false(len < sizeof(*bss) + le32toh(bss->ieslen))) 1127*31d98677SRui Paulo return; 1128*31d98677SRui Paulo 1129*31d98677SRui Paulo DPRINTFN(2, "found BSS %s: len=%d chan=%d inframode=%d " 1130*31d98677SRui Paulo "networktype=%d privacy=%d\n", 1131*31d98677SRui Paulo ether_sprintf(bss->macaddr), le32toh(bss->len), 1132*31d98677SRui Paulo le32toh(bss->config.dsconfig), le32toh(bss->inframode), 1133*31d98677SRui Paulo le32toh(bss->networktype), le32toh(bss->privacy)); 1134*31d98677SRui Paulo 1135*31d98677SRui Paulo /* Build a fake beacon frame to let net80211 do all the parsing. */ 1136*31d98677SRui Paulo pktlen = sizeof(*wh) + le32toh(bss->ieslen); 1137*31d98677SRui Paulo if (__predict_false(pktlen > MCLBYTES)) 1138*31d98677SRui Paulo return; 1139*31d98677SRui Paulo MGETHDR(m, M_DONTWAIT, MT_DATA); 1140*31d98677SRui Paulo if (__predict_false(m == NULL)) 1141*31d98677SRui Paulo return; 1142*31d98677SRui Paulo if (pktlen > MHLEN) { 1143*31d98677SRui Paulo MCLGET(m, M_DONTWAIT); 1144*31d98677SRui Paulo if (!(m->m_flags & M_EXT)) { 1145*31d98677SRui Paulo m_free(m); 1146*31d98677SRui Paulo return; 1147*31d98677SRui Paulo } 1148*31d98677SRui Paulo } 1149*31d98677SRui Paulo wh = mtod(m, struct ieee80211_frame *); 1150*31d98677SRui Paulo wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 1151*31d98677SRui Paulo IEEE80211_FC0_SUBTYPE_BEACON; 1152*31d98677SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1153*31d98677SRui Paulo *(uint16_t *)wh->i_dur = 0; 1154*31d98677SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 1155*31d98677SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr); 1156*31d98677SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr); 1157*31d98677SRui Paulo *(uint16_t *)wh->i_seq = 0; 1158*31d98677SRui Paulo memcpy(&wh[1], (uint8_t *)&bss[1], le32toh(bss->ieslen)); 1159*31d98677SRui Paulo 1160*31d98677SRui Paulo /* Finalize mbuf. */ 1161*31d98677SRui Paulo m->m_pkthdr.len = m->m_len = pktlen; 1162*31d98677SRui Paulo m->m_pkthdr.rcvif = ifp; 1163*31d98677SRui Paulo /* Fix the channel. */ 1164*31d98677SRui Paulo c = ieee80211_find_channel_byieee(ic, 1165*31d98677SRui Paulo le32toh(bss->config.dsconfig), 1166*31d98677SRui Paulo IEEE80211_CHAN_G); 1167*31d98677SRui Paulo if (c) { 1168*31d98677SRui Paulo ic->ic_curchan = c; 1169*31d98677SRui Paulo ieee80211_radiotap_chan_change(ic); 1170*31d98677SRui Paulo } 1171*31d98677SRui Paulo /* XXX avoid a LOR */ 1172*31d98677SRui Paulo RSU_UNLOCK(sc); 1173*31d98677SRui Paulo ieee80211_input_all(ic, m, le32toh(bss->rssi), 0); 1174*31d98677SRui Paulo RSU_LOCK(sc); 1175*31d98677SRui Paulo } 1176*31d98677SRui Paulo 1177*31d98677SRui Paulo static void 1178*31d98677SRui Paulo rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len) 1179*31d98677SRui Paulo { 1180*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1181*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1182*31d98677SRui Paulo struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1183*31d98677SRui Paulo struct ieee80211_node *ni = vap->iv_bss; 1184*31d98677SRui Paulo struct r92s_event_join_bss *rsp; 1185*31d98677SRui Paulo int res; 1186*31d98677SRui Paulo 1187*31d98677SRui Paulo if (__predict_false(len < sizeof(*rsp))) 1188*31d98677SRui Paulo return; 1189*31d98677SRui Paulo rsp = (struct r92s_event_join_bss *)buf; 1190*31d98677SRui Paulo res = (int)le32toh(rsp->join_res); 1191*31d98677SRui Paulo 1192*31d98677SRui Paulo DPRINTF("Rx join BSS event len=%d res=%d\n", len, res); 1193*31d98677SRui Paulo if (res <= 0) { 1194*31d98677SRui Paulo RSU_UNLOCK(sc); 1195*31d98677SRui Paulo ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); 1196*31d98677SRui Paulo RSU_LOCK(sc); 1197*31d98677SRui Paulo return; 1198*31d98677SRui Paulo } 1199*31d98677SRui Paulo DPRINTF("associated with %s associd=%d\n", 1200*31d98677SRui Paulo ether_sprintf(rsp->bss.macaddr), le32toh(rsp->associd)); 1201*31d98677SRui Paulo ni->ni_associd = le32toh(rsp->associd) | 0xc000; 1202*31d98677SRui Paulo RSU_UNLOCK(sc); 1203*31d98677SRui Paulo ieee80211_new_state(vap, IEEE80211_S_RUN, 1204*31d98677SRui Paulo IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 1205*31d98677SRui Paulo RSU_LOCK(sc); 1206*31d98677SRui Paulo } 1207*31d98677SRui Paulo 1208*31d98677SRui Paulo static void 1209*31d98677SRui Paulo rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) 1210*31d98677SRui Paulo { 1211*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1212*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1213*31d98677SRui Paulo struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1214*31d98677SRui Paulo 1215*31d98677SRui Paulo DPRINTFN(4, "Rx event code=%d len=%d\n", code, len); 1216*31d98677SRui Paulo switch (code) { 1217*31d98677SRui Paulo case R92S_EVT_SURVEY: 1218*31d98677SRui Paulo if (vap->iv_state == IEEE80211_S_SCAN) 1219*31d98677SRui Paulo rsu_event_survey(sc, buf, len); 1220*31d98677SRui Paulo break; 1221*31d98677SRui Paulo case R92S_EVT_SURVEY_DONE: 1222*31d98677SRui Paulo DPRINTF("site survey pass %d done, found %d BSS\n", 1223*31d98677SRui Paulo sc->scan_pass, le32toh(*(uint32_t *)buf)); 1224*31d98677SRui Paulo if (vap->iv_state != IEEE80211_S_SCAN) 1225*31d98677SRui Paulo break; /* Ignore if not scanning. */ 1226*31d98677SRui Paulo if (sc->scan_pass == 0 && vap->iv_des_nssid != 0) { 1227*31d98677SRui Paulo /* Schedule a directed scan for hidden APs. */ 1228*31d98677SRui Paulo sc->scan_pass = 1; 1229*31d98677SRui Paulo RSU_UNLOCK(sc); 1230*31d98677SRui Paulo ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); 1231*31d98677SRui Paulo RSU_LOCK(sc); 1232*31d98677SRui Paulo break; 1233*31d98677SRui Paulo } 1234*31d98677SRui Paulo sc->scan_pass = 0; 1235*31d98677SRui Paulo break; 1236*31d98677SRui Paulo case R92S_EVT_JOIN_BSS: 1237*31d98677SRui Paulo if (vap->iv_state == IEEE80211_S_AUTH) 1238*31d98677SRui Paulo rsu_event_join_bss(sc, buf, len); 1239*31d98677SRui Paulo break; 1240*31d98677SRui Paulo case R92S_EVT_DEL_STA: 1241*31d98677SRui Paulo DPRINTF("disassociated from %s\n", ether_sprintf(buf)); 1242*31d98677SRui Paulo if (vap->iv_state == IEEE80211_S_RUN && 1243*31d98677SRui Paulo IEEE80211_ADDR_EQ(vap->iv_bss->ni_bssid, buf)) { 1244*31d98677SRui Paulo RSU_UNLOCK(sc); 1245*31d98677SRui Paulo ieee80211_new_state(vap, IEEE80211_S_SCAN, -1); 1246*31d98677SRui Paulo RSU_LOCK(sc); 1247*31d98677SRui Paulo } 1248*31d98677SRui Paulo break; 1249*31d98677SRui Paulo case R92S_EVT_WPS_PBC: 1250*31d98677SRui Paulo DPRINTF("WPS PBC pushed.\n"); 1251*31d98677SRui Paulo break; 1252*31d98677SRui Paulo case R92S_EVT_FWDBG: 1253*31d98677SRui Paulo if (ifp->if_flags & IFF_DEBUG) { 1254*31d98677SRui Paulo buf[60] = '\0'; 1255*31d98677SRui Paulo printf("FWDBG: %s\n", (char *)buf); 1256*31d98677SRui Paulo } 1257*31d98677SRui Paulo break; 1258*31d98677SRui Paulo } 1259*31d98677SRui Paulo } 1260*31d98677SRui Paulo 1261*31d98677SRui Paulo static void 1262*31d98677SRui Paulo rsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len) 1263*31d98677SRui Paulo { 1264*31d98677SRui Paulo struct r92s_fw_cmd_hdr *cmd; 1265*31d98677SRui Paulo int cmdsz; 1266*31d98677SRui Paulo 1267*31d98677SRui Paulo DPRINTFN(6, "Rx events len=%d\n", len); 1268*31d98677SRui Paulo 1269*31d98677SRui Paulo /* Skip Rx status. */ 1270*31d98677SRui Paulo buf += sizeof(struct r92s_rx_stat); 1271*31d98677SRui Paulo len -= sizeof(struct r92s_rx_stat); 1272*31d98677SRui Paulo 1273*31d98677SRui Paulo /* Process all events. */ 1274*31d98677SRui Paulo for (;;) { 1275*31d98677SRui Paulo /* Check that command header fits. */ 1276*31d98677SRui Paulo if (__predict_false(len < sizeof(*cmd))) 1277*31d98677SRui Paulo break; 1278*31d98677SRui Paulo cmd = (struct r92s_fw_cmd_hdr *)buf; 1279*31d98677SRui Paulo /* Check that command payload fits. */ 1280*31d98677SRui Paulo cmdsz = le16toh(cmd->len); 1281*31d98677SRui Paulo if (__predict_false(len < sizeof(*cmd) + cmdsz)) 1282*31d98677SRui Paulo break; 1283*31d98677SRui Paulo 1284*31d98677SRui Paulo /* Process firmware event. */ 1285*31d98677SRui Paulo rsu_rx_event(sc, cmd->code, (uint8_t *)&cmd[1], cmdsz); 1286*31d98677SRui Paulo 1287*31d98677SRui Paulo if (!(cmd->seq & R92S_FW_CMD_MORE)) 1288*31d98677SRui Paulo break; 1289*31d98677SRui Paulo buf += sizeof(*cmd) + cmdsz; 1290*31d98677SRui Paulo len -= sizeof(*cmd) + cmdsz; 1291*31d98677SRui Paulo } 1292*31d98677SRui Paulo } 1293*31d98677SRui Paulo 1294*31d98677SRui Paulo static int8_t 1295*31d98677SRui Paulo rsu_get_rssi(struct rsu_softc *sc, int rate, void *physt) 1296*31d98677SRui Paulo { 1297*31d98677SRui Paulo static const int8_t cckoff[] = { 14, -2, -20, -40 }; 1298*31d98677SRui Paulo struct r92s_rx_phystat *phy; 1299*31d98677SRui Paulo struct r92s_rx_cck *cck; 1300*31d98677SRui Paulo uint8_t rpt; 1301*31d98677SRui Paulo int8_t rssi; 1302*31d98677SRui Paulo 1303*31d98677SRui Paulo if (rate <= 3) { 1304*31d98677SRui Paulo cck = (struct r92s_rx_cck *)physt; 1305*31d98677SRui Paulo rpt = (cck->agc_rpt >> 6) & 0x3; 1306*31d98677SRui Paulo rssi = cck->agc_rpt & 0x3e; 1307*31d98677SRui Paulo rssi = cckoff[rpt] - rssi; 1308*31d98677SRui Paulo } else { /* OFDM/HT. */ 1309*31d98677SRui Paulo phy = (struct r92s_rx_phystat *)physt; 1310*31d98677SRui Paulo rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 106; 1311*31d98677SRui Paulo } 1312*31d98677SRui Paulo return (rssi); 1313*31d98677SRui Paulo } 1314*31d98677SRui Paulo 1315*31d98677SRui Paulo static struct mbuf * 1316*31d98677SRui Paulo rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi) 1317*31d98677SRui Paulo { 1318*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1319*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1320*31d98677SRui Paulo struct ieee80211_frame *wh; 1321*31d98677SRui Paulo struct r92s_rx_stat *stat; 1322*31d98677SRui Paulo uint32_t rxdw0, rxdw3; 1323*31d98677SRui Paulo struct mbuf *m; 1324*31d98677SRui Paulo uint8_t rate; 1325*31d98677SRui Paulo int infosz; 1326*31d98677SRui Paulo 1327*31d98677SRui Paulo stat = (struct r92s_rx_stat *)buf; 1328*31d98677SRui Paulo rxdw0 = le32toh(stat->rxdw0); 1329*31d98677SRui Paulo rxdw3 = le32toh(stat->rxdw3); 1330*31d98677SRui Paulo 1331*31d98677SRui Paulo if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) { 1332*31d98677SRui Paulo ifp->if_ierrors++; 1333*31d98677SRui Paulo return NULL; 1334*31d98677SRui Paulo } 1335*31d98677SRui Paulo if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) { 1336*31d98677SRui Paulo ifp->if_ierrors++; 1337*31d98677SRui Paulo return NULL; 1338*31d98677SRui Paulo } 1339*31d98677SRui Paulo 1340*31d98677SRui Paulo rate = MS(rxdw3, R92S_RXDW3_RATE); 1341*31d98677SRui Paulo infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8; 1342*31d98677SRui Paulo 1343*31d98677SRui Paulo /* Get RSSI from PHY status descriptor if present. */ 1344*31d98677SRui Paulo if (infosz != 0) 1345*31d98677SRui Paulo *rssi = rsu_get_rssi(sc, rate, &stat[1]); 1346*31d98677SRui Paulo else 1347*31d98677SRui Paulo *rssi = 0; 1348*31d98677SRui Paulo 1349*31d98677SRui Paulo DPRINTFN(5, "Rx frame len=%d rate=%d infosz=%d rssi=%d\n", 1350*31d98677SRui Paulo pktlen, rate, infosz, *rssi); 1351*31d98677SRui Paulo 1352*31d98677SRui Paulo MGETHDR(m, M_DONTWAIT, MT_DATA); 1353*31d98677SRui Paulo if (__predict_false(m == NULL)) { 1354*31d98677SRui Paulo ifp->if_ierrors++; 1355*31d98677SRui Paulo return NULL; 1356*31d98677SRui Paulo } 1357*31d98677SRui Paulo if (pktlen > MHLEN) { 1358*31d98677SRui Paulo MCLGET(m, M_DONTWAIT); 1359*31d98677SRui Paulo if (__predict_false(!(m->m_flags & M_EXT))) { 1360*31d98677SRui Paulo ifp->if_ierrors++; 1361*31d98677SRui Paulo m_freem(m); 1362*31d98677SRui Paulo return NULL; 1363*31d98677SRui Paulo } 1364*31d98677SRui Paulo } 1365*31d98677SRui Paulo /* Finalize mbuf. */ 1366*31d98677SRui Paulo m->m_pkthdr.rcvif = ifp; 1367*31d98677SRui Paulo /* Hardware does Rx TCP checksum offload. */ 1368*31d98677SRui Paulo if (rxdw3 & R92S_RXDW3_TCPCHKVALID) { 1369*31d98677SRui Paulo if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT)) 1370*31d98677SRui Paulo m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; 1371*31d98677SRui Paulo } 1372*31d98677SRui Paulo wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); 1373*31d98677SRui Paulo memcpy(mtod(m, uint8_t *), wh, pktlen); 1374*31d98677SRui Paulo m->m_pkthdr.len = m->m_len = pktlen; 1375*31d98677SRui Paulo 1376*31d98677SRui Paulo if (ieee80211_radiotap_active(ic)) { 1377*31d98677SRui Paulo struct rsu_rx_radiotap_header *tap = &sc->sc_rxtap; 1378*31d98677SRui Paulo 1379*31d98677SRui Paulo /* Map HW rate index to 802.11 rate. */ 1380*31d98677SRui Paulo tap->wr_flags = 2; 1381*31d98677SRui Paulo if (!(rxdw3 & R92S_RXDW3_HTC)) { 1382*31d98677SRui Paulo switch (rate) { 1383*31d98677SRui Paulo /* CCK. */ 1384*31d98677SRui Paulo case 0: tap->wr_rate = 2; break; 1385*31d98677SRui Paulo case 1: tap->wr_rate = 4; break; 1386*31d98677SRui Paulo case 2: tap->wr_rate = 11; break; 1387*31d98677SRui Paulo case 3: tap->wr_rate = 22; break; 1388*31d98677SRui Paulo /* OFDM. */ 1389*31d98677SRui Paulo case 4: tap->wr_rate = 12; break; 1390*31d98677SRui Paulo case 5: tap->wr_rate = 18; break; 1391*31d98677SRui Paulo case 6: tap->wr_rate = 24; break; 1392*31d98677SRui Paulo case 7: tap->wr_rate = 36; break; 1393*31d98677SRui Paulo case 8: tap->wr_rate = 48; break; 1394*31d98677SRui Paulo case 9: tap->wr_rate = 72; break; 1395*31d98677SRui Paulo case 10: tap->wr_rate = 96; break; 1396*31d98677SRui Paulo case 11: tap->wr_rate = 108; break; 1397*31d98677SRui Paulo } 1398*31d98677SRui Paulo } else if (rate >= 12) { /* MCS0~15. */ 1399*31d98677SRui Paulo /* Bit 7 set means HT MCS instead of rate. */ 1400*31d98677SRui Paulo tap->wr_rate = 0x80 | (rate - 12); 1401*31d98677SRui Paulo } 1402*31d98677SRui Paulo tap->wr_dbm_antsignal = *rssi; 1403*31d98677SRui Paulo tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 1404*31d98677SRui Paulo tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 1405*31d98677SRui Paulo } 1406*31d98677SRui Paulo 1407*31d98677SRui Paulo return (m); 1408*31d98677SRui Paulo } 1409*31d98677SRui Paulo 1410*31d98677SRui Paulo static struct mbuf * 1411*31d98677SRui Paulo rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len, int *rssi) 1412*31d98677SRui Paulo { 1413*31d98677SRui Paulo struct r92s_rx_stat *stat; 1414*31d98677SRui Paulo uint32_t rxdw0; 1415*31d98677SRui Paulo int totlen, pktlen, infosz, npkts; 1416*31d98677SRui Paulo struct mbuf *m, *m0 = NULL, *prevm = NULL; 1417*31d98677SRui Paulo 1418*31d98677SRui Paulo /* Get the number of encapsulated frames. */ 1419*31d98677SRui Paulo stat = (struct r92s_rx_stat *)buf; 1420*31d98677SRui Paulo npkts = MS(le32toh(stat->rxdw2), R92S_RXDW2_PKTCNT); 1421*31d98677SRui Paulo DPRINTFN(6, "Rx %d frames in one chunk\n", npkts); 1422*31d98677SRui Paulo 1423*31d98677SRui Paulo /* Process all of them. */ 1424*31d98677SRui Paulo while (npkts-- > 0) { 1425*31d98677SRui Paulo if (__predict_false(len < sizeof(*stat))) 1426*31d98677SRui Paulo break; 1427*31d98677SRui Paulo stat = (struct r92s_rx_stat *)buf; 1428*31d98677SRui Paulo rxdw0 = le32toh(stat->rxdw0); 1429*31d98677SRui Paulo 1430*31d98677SRui Paulo pktlen = MS(rxdw0, R92S_RXDW0_PKTLEN); 1431*31d98677SRui Paulo if (__predict_false(pktlen == 0)) 1432*31d98677SRui Paulo break; 1433*31d98677SRui Paulo 1434*31d98677SRui Paulo infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8; 1435*31d98677SRui Paulo 1436*31d98677SRui Paulo /* Make sure everything fits in xfer. */ 1437*31d98677SRui Paulo totlen = sizeof(*stat) + infosz + pktlen; 1438*31d98677SRui Paulo if (__predict_false(totlen > len)) 1439*31d98677SRui Paulo break; 1440*31d98677SRui Paulo 1441*31d98677SRui Paulo /* Process 802.11 frame. */ 1442*31d98677SRui Paulo m = rsu_rx_frame(sc, buf, pktlen, rssi); 1443*31d98677SRui Paulo if (m0 == NULL) 1444*31d98677SRui Paulo m0 = m; 1445*31d98677SRui Paulo if (prevm == NULL) 1446*31d98677SRui Paulo prevm = m; 1447*31d98677SRui Paulo else { 1448*31d98677SRui Paulo prevm->m_next = m; 1449*31d98677SRui Paulo prevm = m; 1450*31d98677SRui Paulo } 1451*31d98677SRui Paulo /* Next chunk is 128-byte aligned. */ 1452*31d98677SRui Paulo totlen = (totlen + 127) & ~127; 1453*31d98677SRui Paulo buf += totlen; 1454*31d98677SRui Paulo len -= totlen; 1455*31d98677SRui Paulo } 1456*31d98677SRui Paulo 1457*31d98677SRui Paulo return (m0); 1458*31d98677SRui Paulo } 1459*31d98677SRui Paulo 1460*31d98677SRui Paulo static struct mbuf * 1461*31d98677SRui Paulo rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi) 1462*31d98677SRui Paulo { 1463*31d98677SRui Paulo struct rsu_softc *sc = data->sc; 1464*31d98677SRui Paulo struct r92s_rx_stat *stat; 1465*31d98677SRui Paulo int len; 1466*31d98677SRui Paulo 1467*31d98677SRui Paulo usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 1468*31d98677SRui Paulo 1469*31d98677SRui Paulo if (__predict_false(len < sizeof(*stat))) { 1470*31d98677SRui Paulo DPRINTF("xfer too short %d\n", len); 1471*31d98677SRui Paulo sc->sc_ifp->if_ierrors++; 1472*31d98677SRui Paulo return (NULL); 1473*31d98677SRui Paulo } 1474*31d98677SRui Paulo /* Determine if it is a firmware C2H event or an 802.11 frame. */ 1475*31d98677SRui Paulo stat = (struct r92s_rx_stat *)data->buf; 1476*31d98677SRui Paulo if ((le32toh(stat->rxdw1) & 0x1ff) == 0x1ff) { 1477*31d98677SRui Paulo rsu_rx_multi_event(sc, data->buf, len); 1478*31d98677SRui Paulo /* No packets to process. */ 1479*31d98677SRui Paulo return (NULL); 1480*31d98677SRui Paulo } else 1481*31d98677SRui Paulo return (rsu_rx_multi_frame(sc, data->buf, len, rssi)); 1482*31d98677SRui Paulo } 1483*31d98677SRui Paulo 1484*31d98677SRui Paulo static void 1485*31d98677SRui Paulo rsu_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 1486*31d98677SRui Paulo { 1487*31d98677SRui Paulo struct rsu_softc *sc = usbd_xfer_softc(xfer); 1488*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1489*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1490*31d98677SRui Paulo struct ieee80211_frame *wh; 1491*31d98677SRui Paulo struct ieee80211_node *ni; 1492*31d98677SRui Paulo struct mbuf *m = NULL, *next; 1493*31d98677SRui Paulo struct rsu_data *data; 1494*31d98677SRui Paulo int rssi = 1; 1495*31d98677SRui Paulo 1496*31d98677SRui Paulo RSU_ASSERT_LOCKED(sc); 1497*31d98677SRui Paulo 1498*31d98677SRui Paulo switch (USB_GET_STATE(xfer)) { 1499*31d98677SRui Paulo case USB_ST_TRANSFERRED: 1500*31d98677SRui Paulo data = STAILQ_FIRST(&sc->sc_rx_active); 1501*31d98677SRui Paulo if (data == NULL) 1502*31d98677SRui Paulo goto tr_setup; 1503*31d98677SRui Paulo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 1504*31d98677SRui Paulo m = rsu_rxeof(xfer, data, &rssi); 1505*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 1506*31d98677SRui Paulo /* FALLTHROUGH */ 1507*31d98677SRui Paulo case USB_ST_SETUP: 1508*31d98677SRui Paulo tr_setup: 1509*31d98677SRui Paulo data = STAILQ_FIRST(&sc->sc_rx_inactive); 1510*31d98677SRui Paulo if (data == NULL) { 1511*31d98677SRui Paulo KASSERT(m == NULL, ("mbuf isn't NULL")); 1512*31d98677SRui Paulo return; 1513*31d98677SRui Paulo } 1514*31d98677SRui Paulo STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next); 1515*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next); 1516*31d98677SRui Paulo usbd_xfer_set_frame_data(xfer, 0, data->buf, 1517*31d98677SRui Paulo usbd_xfer_max_len(xfer)); 1518*31d98677SRui Paulo usbd_transfer_submit(xfer); 1519*31d98677SRui Paulo /* 1520*31d98677SRui Paulo * To avoid LOR we should unlock our private mutex here to call 1521*31d98677SRui Paulo * ieee80211_input() because here is at the end of a USB 1522*31d98677SRui Paulo * callback and safe to unlock. 1523*31d98677SRui Paulo */ 1524*31d98677SRui Paulo RSU_UNLOCK(sc); 1525*31d98677SRui Paulo while (m != NULL) { 1526*31d98677SRui Paulo next = m->m_next; 1527*31d98677SRui Paulo m->m_next = NULL; 1528*31d98677SRui Paulo wh = mtod(m, struct ieee80211_frame *); 1529*31d98677SRui Paulo ni = ieee80211_find_rxnode(ic, 1530*31d98677SRui Paulo (struct ieee80211_frame_min *)wh); 1531*31d98677SRui Paulo if (ni != NULL) { 1532*31d98677SRui Paulo (void)ieee80211_input(ni, m, rssi, 0); 1533*31d98677SRui Paulo ieee80211_free_node(ni); 1534*31d98677SRui Paulo } else 1535*31d98677SRui Paulo (void)ieee80211_input_all(ic, m, rssi, 0); 1536*31d98677SRui Paulo m = next; 1537*31d98677SRui Paulo } 1538*31d98677SRui Paulo RSU_LOCK(sc); 1539*31d98677SRui Paulo break; 1540*31d98677SRui Paulo default: 1541*31d98677SRui Paulo /* needs it to the inactive queue due to a error. */ 1542*31d98677SRui Paulo data = STAILQ_FIRST(&sc->sc_rx_active); 1543*31d98677SRui Paulo if (data != NULL) { 1544*31d98677SRui Paulo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 1545*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 1546*31d98677SRui Paulo } 1547*31d98677SRui Paulo if (error != USB_ERR_CANCELLED) { 1548*31d98677SRui Paulo usbd_xfer_set_stall(xfer); 1549*31d98677SRui Paulo ifp->if_ierrors++; 1550*31d98677SRui Paulo goto tr_setup; 1551*31d98677SRui Paulo } 1552*31d98677SRui Paulo break; 1553*31d98677SRui Paulo } 1554*31d98677SRui Paulo 1555*31d98677SRui Paulo } 1556*31d98677SRui Paulo 1557*31d98677SRui Paulo 1558*31d98677SRui Paulo static void 1559*31d98677SRui Paulo rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data) 1560*31d98677SRui Paulo { 1561*31d98677SRui Paulo struct rsu_softc *sc = usbd_xfer_softc(xfer); 1562*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1563*31d98677SRui Paulo struct mbuf *m; 1564*31d98677SRui Paulo 1565*31d98677SRui Paulo RSU_ASSERT_LOCKED(sc); 1566*31d98677SRui Paulo 1567*31d98677SRui Paulo /* 1568*31d98677SRui Paulo * Do any tx complete callback. Note this must be done before releasing 1569*31d98677SRui Paulo * the node reference. 1570*31d98677SRui Paulo */ 1571*31d98677SRui Paulo if (data->m) { 1572*31d98677SRui Paulo m = data->m; 1573*31d98677SRui Paulo if (m->m_flags & M_TXCB) { 1574*31d98677SRui Paulo /* XXX status? */ 1575*31d98677SRui Paulo ieee80211_process_callback(data->ni, m, 0); 1576*31d98677SRui Paulo } 1577*31d98677SRui Paulo m_freem(m); 1578*31d98677SRui Paulo data->m = NULL; 1579*31d98677SRui Paulo } 1580*31d98677SRui Paulo if (data->ni) { 1581*31d98677SRui Paulo ieee80211_free_node(data->ni); 1582*31d98677SRui Paulo data->ni = NULL; 1583*31d98677SRui Paulo } 1584*31d98677SRui Paulo sc->sc_tx_timer = 0; 1585*31d98677SRui Paulo ifp->if_opackets++; 1586*31d98677SRui Paulo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1587*31d98677SRui Paulo } 1588*31d98677SRui Paulo 1589*31d98677SRui Paulo static void 1590*31d98677SRui Paulo rsu_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) 1591*31d98677SRui Paulo { 1592*31d98677SRui Paulo struct rsu_softc *sc = usbd_xfer_softc(xfer); 1593*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1594*31d98677SRui Paulo struct rsu_data *data; 1595*31d98677SRui Paulo 1596*31d98677SRui Paulo RSU_ASSERT_LOCKED(sc); 1597*31d98677SRui Paulo 1598*31d98677SRui Paulo switch (USB_GET_STATE(xfer)) { 1599*31d98677SRui Paulo case USB_ST_TRANSFERRED: 1600*31d98677SRui Paulo data = STAILQ_FIRST(&sc->sc_tx_active); 1601*31d98677SRui Paulo if (data == NULL) 1602*31d98677SRui Paulo goto tr_setup; 1603*31d98677SRui Paulo DPRINTF("transfer done %p\n", data); 1604*31d98677SRui Paulo STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); 1605*31d98677SRui Paulo rsu_txeof(xfer, data); 1606*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); 1607*31d98677SRui Paulo /* FALLTHROUGH */ 1608*31d98677SRui Paulo case USB_ST_SETUP: 1609*31d98677SRui Paulo tr_setup: 1610*31d98677SRui Paulo data = STAILQ_FIRST(&sc->sc_tx_pending); 1611*31d98677SRui Paulo if (data == NULL) { 1612*31d98677SRui Paulo DPRINTF("empty pending queue sc %p\n", sc); 1613*31d98677SRui Paulo return; 1614*31d98677SRui Paulo } 1615*31d98677SRui Paulo STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); 1616*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); 1617*31d98677SRui Paulo usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); 1618*31d98677SRui Paulo DPRINTF("submitting transfer %p\n", data); 1619*31d98677SRui Paulo usbd_transfer_submit(xfer); 1620*31d98677SRui Paulo rsu_start_locked(ifp); 1621*31d98677SRui Paulo break; 1622*31d98677SRui Paulo default: 1623*31d98677SRui Paulo data = STAILQ_FIRST(&sc->sc_tx_active); 1624*31d98677SRui Paulo if (data == NULL) 1625*31d98677SRui Paulo goto tr_setup; 1626*31d98677SRui Paulo if (data->ni != NULL) { 1627*31d98677SRui Paulo ieee80211_free_node(data->ni); 1628*31d98677SRui Paulo data->ni = NULL; 1629*31d98677SRui Paulo ifp->if_oerrors++; 1630*31d98677SRui Paulo } 1631*31d98677SRui Paulo if (error != USB_ERR_CANCELLED) { 1632*31d98677SRui Paulo usbd_xfer_set_stall(xfer); 1633*31d98677SRui Paulo goto tr_setup; 1634*31d98677SRui Paulo } 1635*31d98677SRui Paulo break; 1636*31d98677SRui Paulo } 1637*31d98677SRui Paulo } 1638*31d98677SRui Paulo 1639*31d98677SRui Paulo static int 1640*31d98677SRui Paulo rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, 1641*31d98677SRui Paulo struct mbuf *m0, struct rsu_data *data) 1642*31d98677SRui Paulo { 1643*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1644*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1645*31d98677SRui Paulo struct ieee80211vap *vap = ni->ni_vap; 1646*31d98677SRui Paulo struct ieee80211_frame *wh; 1647*31d98677SRui Paulo struct ieee80211_key *k = NULL; 1648*31d98677SRui Paulo struct r92s_tx_desc *txd; 1649*31d98677SRui Paulo struct usb_xfer *xfer; 1650*31d98677SRui Paulo uint8_t type, tid = 0; 1651*31d98677SRui Paulo int hasqos, xferlen; 1652*31d98677SRui Paulo struct usb_xfer *rsu_pipes[4] = { 1653*31d98677SRui Paulo sc->sc_xfer[RSU_BULK_TX_BE], 1654*31d98677SRui Paulo sc->sc_xfer[RSU_BULK_TX_BK], 1655*31d98677SRui Paulo sc->sc_xfer[RSU_BULK_TX_VI], 1656*31d98677SRui Paulo sc->sc_xfer[RSU_BULK_TX_VO] 1657*31d98677SRui Paulo }; 1658*31d98677SRui Paulo 1659*31d98677SRui Paulo RSU_ASSERT_LOCKED(sc); 1660*31d98677SRui Paulo 1661*31d98677SRui Paulo wh = mtod(m0, struct ieee80211_frame *); 1662*31d98677SRui Paulo type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 1663*31d98677SRui Paulo 1664*31d98677SRui Paulo if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1665*31d98677SRui Paulo k = ieee80211_crypto_encap(ni, m0); 1666*31d98677SRui Paulo if (k == NULL) { 1667*31d98677SRui Paulo device_printf(sc->sc_dev, 1668*31d98677SRui Paulo "ieee80211_crypto_encap returns NULL.\n"); 1669*31d98677SRui Paulo /* XXX we don't expect the fragmented frames */ 1670*31d98677SRui Paulo m_freem(m0); 1671*31d98677SRui Paulo return (ENOBUFS); 1672*31d98677SRui Paulo } 1673*31d98677SRui Paulo wh = mtod(m0, struct ieee80211_frame *); 1674*31d98677SRui Paulo } 1675*31d98677SRui Paulo switch (type) { 1676*31d98677SRui Paulo case IEEE80211_FC0_TYPE_CTL: 1677*31d98677SRui Paulo case IEEE80211_FC0_TYPE_MGT: 1678*31d98677SRui Paulo xfer = sc->sc_xfer[RSU_BULK_TX_VO]; 1679*31d98677SRui Paulo break; 1680*31d98677SRui Paulo default: 1681*31d98677SRui Paulo KASSERT(M_WME_GETAC(m0) < 4, 1682*31d98677SRui Paulo ("unsupported WME pipe %d", M_WME_GETAC(m0))); 1683*31d98677SRui Paulo xfer = rsu_pipes[M_WME_GETAC(m0)]; 1684*31d98677SRui Paulo break; 1685*31d98677SRui Paulo } 1686*31d98677SRui Paulo hasqos = 0; 1687*31d98677SRui Paulo 1688*31d98677SRui Paulo /* Fill Tx descriptor. */ 1689*31d98677SRui Paulo txd = (struct r92s_tx_desc *)data->buf; 1690*31d98677SRui Paulo memset(txd, 0, sizeof(*txd)); 1691*31d98677SRui Paulo 1692*31d98677SRui Paulo txd->txdw0 |= htole32( 1693*31d98677SRui Paulo SM(R92S_TXDW0_PKTLEN, m0->m_pkthdr.len) | 1694*31d98677SRui Paulo SM(R92S_TXDW0_OFFSET, sizeof(*txd)) | 1695*31d98677SRui Paulo R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG); 1696*31d98677SRui Paulo 1697*31d98677SRui Paulo txd->txdw1 |= htole32( 1698*31d98677SRui Paulo SM(R92S_TXDW1_MACID, R92S_MACID_BSS) | 1699*31d98677SRui Paulo SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_BE)); 1700*31d98677SRui Paulo if (!hasqos) 1701*31d98677SRui Paulo txd->txdw1 |= htole32(R92S_TXDW1_NONQOS); 1702*31d98677SRui Paulo #ifdef notyet 1703*31d98677SRui Paulo if (k != NULL) { 1704*31d98677SRui Paulo switch (k->wk_cipher->ic_cipher) { 1705*31d98677SRui Paulo case IEEE80211_CIPHER_WEP: 1706*31d98677SRui Paulo cipher = R92S_TXDW1_CIPHER_WEP; 1707*31d98677SRui Paulo break; 1708*31d98677SRui Paulo case IEEE80211_CIPHER_TKIP: 1709*31d98677SRui Paulo cipher = R92S_TXDW1_CIPHER_TKIP; 1710*31d98677SRui Paulo break; 1711*31d98677SRui Paulo case IEEE80211_CIPHER_AES_CCM: 1712*31d98677SRui Paulo cipher = R92S_TXDW1_CIPHER_AES; 1713*31d98677SRui Paulo break; 1714*31d98677SRui Paulo default: 1715*31d98677SRui Paulo cipher = R92S_TXDW1_CIPHER_NONE; 1716*31d98677SRui Paulo } 1717*31d98677SRui Paulo txd->txdw1 |= htole32( 1718*31d98677SRui Paulo SM(R92S_TXDW1_CIPHER, cipher) | 1719*31d98677SRui Paulo SM(R92S_TXDW1_KEYIDX, k->k_id)); 1720*31d98677SRui Paulo } 1721*31d98677SRui Paulo #endif 1722*31d98677SRui Paulo txd->txdw2 |= htole32(R92S_TXDW2_BK); 1723*31d98677SRui Paulo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 1724*31d98677SRui Paulo txd->txdw2 |= htole32(R92S_TXDW2_BMCAST); 1725*31d98677SRui Paulo /* 1726*31d98677SRui Paulo * Firmware will use and increment the sequence number for the 1727*31d98677SRui Paulo * specified TID. 1728*31d98677SRui Paulo */ 1729*31d98677SRui Paulo txd->txdw3 |= htole32(SM(R92S_TXDW3_SEQ, tid)); 1730*31d98677SRui Paulo 1731*31d98677SRui Paulo if (ieee80211_radiotap_active_vap(vap)) { 1732*31d98677SRui Paulo struct rsu_tx_radiotap_header *tap = &sc->sc_txtap; 1733*31d98677SRui Paulo 1734*31d98677SRui Paulo tap->wt_flags = 0; 1735*31d98677SRui Paulo tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 1736*31d98677SRui Paulo tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 1737*31d98677SRui Paulo ieee80211_radiotap_tx(vap, m0); 1738*31d98677SRui Paulo } 1739*31d98677SRui Paulo xferlen = sizeof(*txd) + m0->m_pkthdr.len; 1740*31d98677SRui Paulo m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&txd[1]); 1741*31d98677SRui Paulo 1742*31d98677SRui Paulo data->buflen = xferlen; 1743*31d98677SRui Paulo data->ni = ni; 1744*31d98677SRui Paulo data->m = m0; 1745*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); 1746*31d98677SRui Paulo usbd_transfer_start(xfer); 1747*31d98677SRui Paulo 1748*31d98677SRui Paulo return (0); 1749*31d98677SRui Paulo } 1750*31d98677SRui Paulo 1751*31d98677SRui Paulo static void 1752*31d98677SRui Paulo rsu_start(struct ifnet *ifp) 1753*31d98677SRui Paulo { 1754*31d98677SRui Paulo struct rsu_softc *sc = ifp->if_softc; 1755*31d98677SRui Paulo 1756*31d98677SRui Paulo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1757*31d98677SRui Paulo return; 1758*31d98677SRui Paulo 1759*31d98677SRui Paulo RSU_LOCK(sc); 1760*31d98677SRui Paulo rsu_start_locked(ifp); 1761*31d98677SRui Paulo RSU_UNLOCK(sc); 1762*31d98677SRui Paulo } 1763*31d98677SRui Paulo 1764*31d98677SRui Paulo static void 1765*31d98677SRui Paulo rsu_start_locked(struct ifnet *ifp) 1766*31d98677SRui Paulo { 1767*31d98677SRui Paulo struct rsu_softc *sc = ifp->if_softc; 1768*31d98677SRui Paulo struct ieee80211_node *ni; 1769*31d98677SRui Paulo struct mbuf *m; 1770*31d98677SRui Paulo struct rsu_data *bf; 1771*31d98677SRui Paulo 1772*31d98677SRui Paulo RSU_ASSERT_LOCKED(sc); 1773*31d98677SRui Paulo 1774*31d98677SRui Paulo for (;;) { 1775*31d98677SRui Paulo IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1776*31d98677SRui Paulo if (m == NULL) 1777*31d98677SRui Paulo break; 1778*31d98677SRui Paulo bf = rsu_getbuf(sc); 1779*31d98677SRui Paulo if (bf == NULL) { 1780*31d98677SRui Paulo IFQ_DRV_PREPEND(&ifp->if_snd, m); 1781*31d98677SRui Paulo break; 1782*31d98677SRui Paulo } 1783*31d98677SRui Paulo ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 1784*31d98677SRui Paulo m->m_pkthdr.rcvif = NULL; 1785*31d98677SRui Paulo 1786*31d98677SRui Paulo if (rsu_tx_start(sc, ni, m, bf) != 0) { 1787*31d98677SRui Paulo ifp->if_oerrors++; 1788*31d98677SRui Paulo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 1789*31d98677SRui Paulo ieee80211_free_node(ni); 1790*31d98677SRui Paulo break; 1791*31d98677SRui Paulo } 1792*31d98677SRui Paulo sc->sc_tx_timer = 5; 1793*31d98677SRui Paulo callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc); 1794*31d98677SRui Paulo } 1795*31d98677SRui Paulo } 1796*31d98677SRui Paulo 1797*31d98677SRui Paulo static void 1798*31d98677SRui Paulo rsu_watchdog(void *arg) 1799*31d98677SRui Paulo { 1800*31d98677SRui Paulo struct rsu_softc *sc = arg; 1801*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 1802*31d98677SRui Paulo 1803*31d98677SRui Paulo if (sc->sc_tx_timer > 0) { 1804*31d98677SRui Paulo if (--sc->sc_tx_timer == 0) { 1805*31d98677SRui Paulo device_printf(sc->sc_dev, "device timeout\n"); 1806*31d98677SRui Paulo /* rsu_init(ifp); XXX needs a process context! */ 1807*31d98677SRui Paulo ifp->if_oerrors++; 1808*31d98677SRui Paulo return; 1809*31d98677SRui Paulo } 1810*31d98677SRui Paulo callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc); 1811*31d98677SRui Paulo } 1812*31d98677SRui Paulo } 1813*31d98677SRui Paulo 1814*31d98677SRui Paulo static int 1815*31d98677SRui Paulo rsu_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1816*31d98677SRui Paulo { 1817*31d98677SRui Paulo struct ieee80211com *ic = ifp->if_l2com; 1818*31d98677SRui Paulo struct ifreq *ifr = (struct ifreq *) data; 1819*31d98677SRui Paulo int error = 0, startall = 0; 1820*31d98677SRui Paulo 1821*31d98677SRui Paulo switch (cmd) { 1822*31d98677SRui Paulo case SIOCSIFFLAGS: 1823*31d98677SRui Paulo if (ifp->if_flags & IFF_UP) { 1824*31d98677SRui Paulo if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1825*31d98677SRui Paulo rsu_init(ifp->if_softc); 1826*31d98677SRui Paulo startall = 1; 1827*31d98677SRui Paulo } 1828*31d98677SRui Paulo } else { 1829*31d98677SRui Paulo if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1830*31d98677SRui Paulo rsu_stop(ifp, 1); 1831*31d98677SRui Paulo } 1832*31d98677SRui Paulo if (startall) 1833*31d98677SRui Paulo ieee80211_start_all(ic); 1834*31d98677SRui Paulo break; 1835*31d98677SRui Paulo case SIOCGIFMEDIA: 1836*31d98677SRui Paulo error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 1837*31d98677SRui Paulo break; 1838*31d98677SRui Paulo case SIOCGIFADDR: 1839*31d98677SRui Paulo error = ether_ioctl(ifp, cmd, data); 1840*31d98677SRui Paulo break; 1841*31d98677SRui Paulo default: 1842*31d98677SRui Paulo error = EINVAL; 1843*31d98677SRui Paulo break; 1844*31d98677SRui Paulo } 1845*31d98677SRui Paulo 1846*31d98677SRui Paulo return (error); 1847*31d98677SRui Paulo } 1848*31d98677SRui Paulo 1849*31d98677SRui Paulo /* 1850*31d98677SRui Paulo * Power on sequence for A-cut adapters. 1851*31d98677SRui Paulo */ 1852*31d98677SRui Paulo static void 1853*31d98677SRui Paulo rsu_power_on_acut(struct rsu_softc *sc) 1854*31d98677SRui Paulo { 1855*31d98677SRui Paulo uint32_t reg; 1856*31d98677SRui Paulo 1857*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53); 1858*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57); 1859*31d98677SRui Paulo 1860*31d98677SRui Paulo /* Enable AFE macro block's bandgap and Mbias. */ 1861*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_MISC, 1862*31d98677SRui Paulo rsu_read_1(sc, R92S_AFE_MISC) | 1863*31d98677SRui Paulo R92S_AFE_MISC_BGEN | R92S_AFE_MISC_MBEN); 1864*31d98677SRui Paulo /* Enable LDOA15 block. */ 1865*31d98677SRui Paulo rsu_write_1(sc, R92S_LDOA15_CTRL, 1866*31d98677SRui Paulo rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN); 1867*31d98677SRui Paulo 1868*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS1_CTRL, 1869*31d98677SRui Paulo rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_LDEN); 1870*31d98677SRui Paulo usb_pause_mtx(&sc->sc_mtx, 2 * hz); 1871*31d98677SRui Paulo /* Enable switch regulator block. */ 1872*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS1_CTRL, 1873*31d98677SRui Paulo rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_SWEN); 1874*31d98677SRui Paulo 1875*31d98677SRui Paulo rsu_write_4(sc, R92S_SPS1_CTRL, 0x00a7b267); 1876*31d98677SRui Paulo 1877*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 1878*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08); 1879*31d98677SRui Paulo 1880*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 1881*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20); 1882*31d98677SRui Paulo 1883*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 1884*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x90); 1885*31d98677SRui Paulo 1886*31d98677SRui Paulo /* Enable AFE clock. */ 1887*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1, 1888*31d98677SRui Paulo rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04); 1889*31d98677SRui Paulo /* Enable AFE PLL macro block. */ 1890*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_PLL_CTRL, 1891*31d98677SRui Paulo rsu_read_1(sc, R92S_AFE_PLL_CTRL) | 0x11); 1892*31d98677SRui Paulo /* Attach AFE PLL to MACTOP/BB. */ 1893*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL, 1894*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11); 1895*31d98677SRui Paulo 1896*31d98677SRui Paulo /* Switch to 40MHz clock instead of 80MHz. */ 1897*31d98677SRui Paulo rsu_write_2(sc, R92S_SYS_CLKR, 1898*31d98677SRui Paulo rsu_read_2(sc, R92S_SYS_CLKR) & ~R92S_SYS_CLKSEL); 1899*31d98677SRui Paulo 1900*31d98677SRui Paulo /* Enable MAC clock. */ 1901*31d98677SRui Paulo rsu_write_2(sc, R92S_SYS_CLKR, 1902*31d98677SRui Paulo rsu_read_2(sc, R92S_SYS_CLKR) | 1903*31d98677SRui Paulo R92S_MAC_CLK_EN | R92S_SYS_CLK_EN); 1904*31d98677SRui Paulo 1905*31d98677SRui Paulo rsu_write_1(sc, R92S_PMC_FSM, 0x02); 1906*31d98677SRui Paulo 1907*31d98677SRui Paulo /* Enable digital core and IOREG R/W. */ 1908*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 1909*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08); 1910*31d98677SRui Paulo 1911*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 1912*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80); 1913*31d98677SRui Paulo 1914*31d98677SRui Paulo /* Switch the control path to firmware. */ 1915*31d98677SRui Paulo reg = rsu_read_2(sc, R92S_SYS_CLKR); 1916*31d98677SRui Paulo reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL; 1917*31d98677SRui Paulo rsu_write_2(sc, R92S_SYS_CLKR, reg); 1918*31d98677SRui Paulo 1919*31d98677SRui Paulo rsu_write_2(sc, R92S_CR, 0x37fc); 1920*31d98677SRui Paulo 1921*31d98677SRui Paulo /* Fix USB RX FIFO issue. */ 1922*31d98677SRui Paulo rsu_write_1(sc, 0xfe5c, 1923*31d98677SRui Paulo rsu_read_1(sc, 0xfe5c) | 0x80); 1924*31d98677SRui Paulo rsu_write_1(sc, 0x00ab, 1925*31d98677SRui Paulo rsu_read_1(sc, 0x00ab) | 0xc0); 1926*31d98677SRui Paulo 1927*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_CLKR, 1928*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL); 1929*31d98677SRui Paulo } 1930*31d98677SRui Paulo 1931*31d98677SRui Paulo /* 1932*31d98677SRui Paulo * Power on sequence for B-cut and C-cut adapters. 1933*31d98677SRui Paulo */ 1934*31d98677SRui Paulo static void 1935*31d98677SRui Paulo rsu_power_on_bcut(struct rsu_softc *sc) 1936*31d98677SRui Paulo { 1937*31d98677SRui Paulo uint32_t reg; 1938*31d98677SRui Paulo int ntries; 1939*31d98677SRui Paulo 1940*31d98677SRui Paulo /* Prevent eFuse leakage. */ 1941*31d98677SRui Paulo rsu_write_1(sc, 0x37, 0xb0); 1942*31d98677SRui Paulo usb_pause_mtx(&sc->sc_mtx, 10); 1943*31d98677SRui Paulo rsu_write_1(sc, 0x37, 0x30); 1944*31d98677SRui Paulo 1945*31d98677SRui Paulo /* Switch the control path to hardware. */ 1946*31d98677SRui Paulo reg = rsu_read_2(sc, R92S_SYS_CLKR); 1947*31d98677SRui Paulo if (reg & R92S_FWHW_SEL) { 1948*31d98677SRui Paulo rsu_write_2(sc, R92S_SYS_CLKR, 1949*31d98677SRui Paulo reg & ~(R92S_SWHW_SEL | R92S_FWHW_SEL)); 1950*31d98677SRui Paulo } 1951*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 1952*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) & ~0x8c); 1953*31d98677SRui Paulo DELAY(1000); 1954*31d98677SRui Paulo 1955*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53); 1956*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57); 1957*31d98677SRui Paulo 1958*31d98677SRui Paulo reg = rsu_read_1(sc, R92S_AFE_MISC); 1959*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN); 1960*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN | 1961*31d98677SRui Paulo R92S_AFE_MISC_MBEN | R92S_AFE_MISC_I32_EN); 1962*31d98677SRui Paulo 1963*31d98677SRui Paulo /* Enable PLL. */ 1964*31d98677SRui Paulo rsu_write_1(sc, R92S_LDOA15_CTRL, 1965*31d98677SRui Paulo rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN); 1966*31d98677SRui Paulo 1967*31d98677SRui Paulo rsu_write_1(sc, R92S_LDOV12D_CTRL, 1968*31d98677SRui Paulo rsu_read_1(sc, R92S_LDOV12D_CTRL) | R92S_LDV12_EN); 1969*31d98677SRui Paulo 1970*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 1971*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08); 1972*31d98677SRui Paulo 1973*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 1974*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20); 1975*31d98677SRui Paulo 1976*31d98677SRui Paulo /* Support 64KB IMEM. */ 1977*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 1978*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x97); 1979*31d98677SRui Paulo 1980*31d98677SRui Paulo /* Enable AFE clock. */ 1981*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1, 1982*31d98677SRui Paulo rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04); 1983*31d98677SRui Paulo /* Enable AFE PLL macro block. */ 1984*31d98677SRui Paulo reg = rsu_read_1(sc, R92S_AFE_PLL_CTRL); 1985*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11); 1986*31d98677SRui Paulo DELAY(500); 1987*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x51); 1988*31d98677SRui Paulo DELAY(500); 1989*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11); 1990*31d98677SRui Paulo DELAY(500); 1991*31d98677SRui Paulo 1992*31d98677SRui Paulo /* Attach AFE PLL to MACTOP/BB. */ 1993*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL, 1994*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11); 1995*31d98677SRui Paulo 1996*31d98677SRui Paulo /* Switch to 40MHz clock. */ 1997*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_CLKR, 0x00); 1998*31d98677SRui Paulo /* Disable CPU clock and 80MHz SSC. */ 1999*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_CLKR, 2000*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_CLKR) | 0xa0); 2001*31d98677SRui Paulo /* Enable MAC clock. */ 2002*31d98677SRui Paulo rsu_write_2(sc, R92S_SYS_CLKR, 2003*31d98677SRui Paulo rsu_read_2(sc, R92S_SYS_CLKR) | 2004*31d98677SRui Paulo R92S_MAC_CLK_EN | R92S_SYS_CLK_EN); 2005*31d98677SRui Paulo 2006*31d98677SRui Paulo rsu_write_1(sc, R92S_PMC_FSM, 0x02); 2007*31d98677SRui Paulo 2008*31d98677SRui Paulo /* Enable digital core and IOREG R/W. */ 2009*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 2010*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08); 2011*31d98677SRui Paulo 2012*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 2013*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80); 2014*31d98677SRui Paulo 2015*31d98677SRui Paulo /* Switch the control path to firmware. */ 2016*31d98677SRui Paulo reg = rsu_read_2(sc, R92S_SYS_CLKR); 2017*31d98677SRui Paulo reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL; 2018*31d98677SRui Paulo rsu_write_2(sc, R92S_SYS_CLKR, reg); 2019*31d98677SRui Paulo 2020*31d98677SRui Paulo rsu_write_2(sc, R92S_CR, 0x37fc); 2021*31d98677SRui Paulo 2022*31d98677SRui Paulo /* Fix USB RX FIFO issue. */ 2023*31d98677SRui Paulo rsu_write_1(sc, 0xfe5c, 2024*31d98677SRui Paulo rsu_read_1(sc, 0xfe5c) | 0x80); 2025*31d98677SRui Paulo 2026*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_CLKR, 2027*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL); 2028*31d98677SRui Paulo 2029*31d98677SRui Paulo rsu_write_1(sc, 0xfe1c, 0x80); 2030*31d98677SRui Paulo 2031*31d98677SRui Paulo /* Make sure TxDMA is ready to download firmware. */ 2032*31d98677SRui Paulo for (ntries = 0; ntries < 20; ntries++) { 2033*31d98677SRui Paulo reg = rsu_read_1(sc, R92S_TCR); 2034*31d98677SRui Paulo if ((reg & (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT)) == 2035*31d98677SRui Paulo (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT)) 2036*31d98677SRui Paulo break; 2037*31d98677SRui Paulo DELAY(5); 2038*31d98677SRui Paulo } 2039*31d98677SRui Paulo if (ntries == 20) { 2040*31d98677SRui Paulo DPRINTF("TxDMA is not ready\n"); 2041*31d98677SRui Paulo /* Reset TxDMA. */ 2042*31d98677SRui Paulo reg = rsu_read_1(sc, R92S_CR); 2043*31d98677SRui Paulo rsu_write_1(sc, R92S_CR, reg & ~R92S_CR_TXDMA_EN); 2044*31d98677SRui Paulo DELAY(2); 2045*31d98677SRui Paulo rsu_write_1(sc, R92S_CR, reg | R92S_CR_TXDMA_EN); 2046*31d98677SRui Paulo } 2047*31d98677SRui Paulo } 2048*31d98677SRui Paulo 2049*31d98677SRui Paulo static void 2050*31d98677SRui Paulo rsu_power_off(struct rsu_softc *sc) 2051*31d98677SRui Paulo { 2052*31d98677SRui Paulo /* Turn RF off. */ 2053*31d98677SRui Paulo rsu_write_1(sc, R92S_RF_CTRL, 0x00); 2054*31d98677SRui Paulo usb_pause_mtx(&sc->sc_mtx, 5); 2055*31d98677SRui Paulo 2056*31d98677SRui Paulo /* Turn MAC off. */ 2057*31d98677SRui Paulo /* Switch control path. */ 2058*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_CLKR + 1, 0x38); 2059*31d98677SRui Paulo /* Reset MACTOP. */ 2060*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x70); 2061*31d98677SRui Paulo rsu_write_1(sc, R92S_PMC_FSM, 0x06); 2062*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL + 0, 0xf9); 2063*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 0xe8); 2064*31d98677SRui Paulo 2065*31d98677SRui Paulo /* Disable AFE PLL. */ 2066*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_PLL_CTRL, 0x00); 2067*31d98677SRui Paulo /* Disable A15V. */ 2068*31d98677SRui Paulo rsu_write_1(sc, R92S_LDOA15_CTRL, 0x54); 2069*31d98677SRui Paulo /* Disable eFuse 1.2V. */ 2070*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x50); 2071*31d98677SRui Paulo rsu_write_1(sc, R92S_LDOV12D_CTRL, 0x24); 2072*31d98677SRui Paulo /* Enable AFE macro block's bandgap and Mbias. */ 2073*31d98677SRui Paulo rsu_write_1(sc, R92S_AFE_MISC, 0x30); 2074*31d98677SRui Paulo /* Disable 1.6V LDO. */ 2075*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x56); 2076*31d98677SRui Paulo rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x43); 2077*31d98677SRui Paulo } 2078*31d98677SRui Paulo 2079*31d98677SRui Paulo static int 2080*31d98677SRui Paulo rsu_fw_loadsection(struct rsu_softc *sc, uint8_t *buf, int len) 2081*31d98677SRui Paulo { 2082*31d98677SRui Paulo struct rsu_data *data; 2083*31d98677SRui Paulo struct r92s_tx_desc *txd; 2084*31d98677SRui Paulo int mlen; 2085*31d98677SRui Paulo 2086*31d98677SRui Paulo while (len > 0) { 2087*31d98677SRui Paulo data = rsu_getbuf(sc); 2088*31d98677SRui Paulo if (data == NULL) 2089*31d98677SRui Paulo return (ENOMEM); 2090*31d98677SRui Paulo txd = (struct r92s_tx_desc *)data->buf; 2091*31d98677SRui Paulo memset(txd, 0, sizeof(*txd)); 2092*31d98677SRui Paulo if (len <= RSU_TXBUFSZ - sizeof(*txd)) { 2093*31d98677SRui Paulo /* Last chunk. */ 2094*31d98677SRui Paulo txd->txdw0 |= htole32(R92S_TXDW0_LINIP); 2095*31d98677SRui Paulo mlen = len; 2096*31d98677SRui Paulo } else 2097*31d98677SRui Paulo mlen = RSU_TXBUFSZ - sizeof(*txd); 2098*31d98677SRui Paulo txd->txdw0 |= htole32(SM(R92S_TXDW0_PKTLEN, mlen)); 2099*31d98677SRui Paulo memcpy(&txd[1], buf, mlen); 2100*31d98677SRui Paulo data->buflen = sizeof(*txd) + mlen; 2101*31d98677SRui Paulo DPRINTF("starting transfer %p\n", data); 2102*31d98677SRui Paulo STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); 2103*31d98677SRui Paulo buf += mlen; 2104*31d98677SRui Paulo len -= mlen; 2105*31d98677SRui Paulo } 2106*31d98677SRui Paulo usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]); 2107*31d98677SRui Paulo 2108*31d98677SRui Paulo return (0); 2109*31d98677SRui Paulo } 2110*31d98677SRui Paulo 2111*31d98677SRui Paulo static int 2112*31d98677SRui Paulo rsu_load_firmware(struct rsu_softc *sc) 2113*31d98677SRui Paulo { 2114*31d98677SRui Paulo struct r92s_fw_hdr *hdr; 2115*31d98677SRui Paulo struct r92s_fw_priv *dmem; 2116*31d98677SRui Paulo uint8_t *imem, *emem; 2117*31d98677SRui Paulo int imemsz, ememsz; 2118*31d98677SRui Paulo const struct firmware *fw; 2119*31d98677SRui Paulo size_t size; 2120*31d98677SRui Paulo uint32_t reg; 2121*31d98677SRui Paulo int ntries, error; 2122*31d98677SRui Paulo 2123*31d98677SRui Paulo RSU_UNLOCK(sc); 2124*31d98677SRui Paulo /* Read firmware image from the filesystem. */ 2125*31d98677SRui Paulo if ((fw = firmware_get("rsu-rtl8712fw")) == NULL) { 2126*31d98677SRui Paulo device_printf(sc->sc_dev, 2127*31d98677SRui Paulo "%s: failed load firmware of file rsu-rtl8712fw\n", 2128*31d98677SRui Paulo __func__); 2129*31d98677SRui Paulo RSU_LOCK(sc); 2130*31d98677SRui Paulo return (ENXIO); 2131*31d98677SRui Paulo } 2132*31d98677SRui Paulo RSU_LOCK(sc); 2133*31d98677SRui Paulo size = fw->datasize; 2134*31d98677SRui Paulo if (size < sizeof(*hdr)) { 2135*31d98677SRui Paulo device_printf(sc->sc_dev, "firmware too short\n"); 2136*31d98677SRui Paulo error = EINVAL; 2137*31d98677SRui Paulo goto fail; 2138*31d98677SRui Paulo } 2139*31d98677SRui Paulo hdr = (struct r92s_fw_hdr *)fw->data; 2140*31d98677SRui Paulo if (hdr->signature != htole16(0x8712) && 2141*31d98677SRui Paulo hdr->signature != htole16(0x8192)) { 2142*31d98677SRui Paulo device_printf(sc->sc_dev, 2143*31d98677SRui Paulo "invalid firmware signature 0x%x\n", 2144*31d98677SRui Paulo le16toh(hdr->signature)); 2145*31d98677SRui Paulo error = EINVAL; 2146*31d98677SRui Paulo goto fail; 2147*31d98677SRui Paulo } 2148*31d98677SRui Paulo DPRINTF("FW V%d %02x-%02x %02x:%02x\n", le16toh(hdr->version), 2149*31d98677SRui Paulo hdr->month, hdr->day, hdr->hour, hdr->minute); 2150*31d98677SRui Paulo 2151*31d98677SRui Paulo /* Make sure that driver and firmware are in sync. */ 2152*31d98677SRui Paulo if (hdr->privsz != htole32(sizeof(*dmem))) { 2153*31d98677SRui Paulo device_printf(sc->sc_dev, "unsupported firmware image\n"); 2154*31d98677SRui Paulo error = EINVAL; 2155*31d98677SRui Paulo goto fail; 2156*31d98677SRui Paulo } 2157*31d98677SRui Paulo /* Get FW sections sizes. */ 2158*31d98677SRui Paulo imemsz = le32toh(hdr->imemsz); 2159*31d98677SRui Paulo ememsz = le32toh(hdr->sramsz); 2160*31d98677SRui Paulo /* Check that all FW sections fit in image. */ 2161*31d98677SRui Paulo if (size < sizeof(*hdr) + imemsz + ememsz) { 2162*31d98677SRui Paulo device_printf(sc->sc_dev, "firmware too short\n"); 2163*31d98677SRui Paulo error = EINVAL; 2164*31d98677SRui Paulo goto fail; 2165*31d98677SRui Paulo } 2166*31d98677SRui Paulo imem = (uint8_t *)&hdr[1]; 2167*31d98677SRui Paulo emem = imem + imemsz; 2168*31d98677SRui Paulo 2169*31d98677SRui Paulo /* Load IMEM section. */ 2170*31d98677SRui Paulo error = rsu_fw_loadsection(sc, imem, imemsz); 2171*31d98677SRui Paulo if (error != 0) { 2172*31d98677SRui Paulo device_printf(sc->sc_dev, 2173*31d98677SRui Paulo "could not load firmware section %s\n", "IMEM"); 2174*31d98677SRui Paulo goto fail; 2175*31d98677SRui Paulo } 2176*31d98677SRui Paulo /* Wait for load to complete. */ 2177*31d98677SRui Paulo for (ntries = 0; ntries < 10; ntries++) { 2178*31d98677SRui Paulo usb_pause_mtx(&sc->sc_mtx, 10); 2179*31d98677SRui Paulo reg = rsu_read_2(sc, R92S_TCR); 2180*31d98677SRui Paulo if (reg & R92S_TCR_IMEM_CODE_DONE) 2181*31d98677SRui Paulo break; 2182*31d98677SRui Paulo } 2183*31d98677SRui Paulo if (ntries == 10 || !(reg & R92S_TCR_IMEM_CHK_RPT)) { 2184*31d98677SRui Paulo device_printf(sc->sc_dev, "timeout waiting for %s transfer\n", 2185*31d98677SRui Paulo "IMEM"); 2186*31d98677SRui Paulo error = ETIMEDOUT; 2187*31d98677SRui Paulo goto fail; 2188*31d98677SRui Paulo } 2189*31d98677SRui Paulo 2190*31d98677SRui Paulo /* Load EMEM section. */ 2191*31d98677SRui Paulo error = rsu_fw_loadsection(sc, emem, ememsz); 2192*31d98677SRui Paulo if (error != 0) { 2193*31d98677SRui Paulo device_printf(sc->sc_dev, 2194*31d98677SRui Paulo "could not load firmware section %s\n", "EMEM"); 2195*31d98677SRui Paulo goto fail; 2196*31d98677SRui Paulo } 2197*31d98677SRui Paulo /* Wait for load to complete. */ 2198*31d98677SRui Paulo for (ntries = 0; ntries < 10; ntries++) { 2199*31d98677SRui Paulo usb_pause_mtx(&sc->sc_mtx, 10); 2200*31d98677SRui Paulo reg = rsu_read_2(sc, R92S_TCR); 2201*31d98677SRui Paulo if (reg & R92S_TCR_EMEM_CODE_DONE) 2202*31d98677SRui Paulo break; 2203*31d98677SRui Paulo } 2204*31d98677SRui Paulo if (ntries == 10 || !(reg & R92S_TCR_EMEM_CHK_RPT)) { 2205*31d98677SRui Paulo device_printf(sc->sc_dev, "timeout waiting for %s transfer\n", 2206*31d98677SRui Paulo "EMEM"); 2207*31d98677SRui Paulo error = ETIMEDOUT; 2208*31d98677SRui Paulo goto fail; 2209*31d98677SRui Paulo } 2210*31d98677SRui Paulo 2211*31d98677SRui Paulo /* Enable CPU. */ 2212*31d98677SRui Paulo rsu_write_1(sc, R92S_SYS_CLKR, 2213*31d98677SRui Paulo rsu_read_1(sc, R92S_SYS_CLKR) | R92S_SYS_CPU_CLKSEL); 2214*31d98677SRui Paulo if (!(rsu_read_1(sc, R92S_SYS_CLKR) & R92S_SYS_CPU_CLKSEL)) { 2215*31d98677SRui Paulo device_printf(sc->sc_dev, "could not enable system clock\n"); 2216*31d98677SRui Paulo error = EIO; 2217*31d98677SRui Paulo goto fail; 2218*31d98677SRui Paulo } 2219*31d98677SRui Paulo rsu_write_2(sc, R92S_SYS_FUNC_EN, 2220*31d98677SRui Paulo rsu_read_2(sc, R92S_SYS_FUNC_EN) | R92S_FEN_CPUEN); 2221*31d98677SRui Paulo if (!(rsu_read_2(sc, R92S_SYS_FUNC_EN) & R92S_FEN_CPUEN)) { 2222*31d98677SRui Paulo device_printf(sc->sc_dev, 2223*31d98677SRui Paulo "could not enable microcontroller\n"); 2224*31d98677SRui Paulo error = EIO; 2225*31d98677SRui Paulo goto fail; 2226*31d98677SRui Paulo } 2227*31d98677SRui Paulo /* Wait for CPU to initialize. */ 2228*31d98677SRui Paulo for (ntries = 0; ntries < 100; ntries++) { 2229*31d98677SRui Paulo if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_IMEM_RDY) 2230*31d98677SRui Paulo break; 2231*31d98677SRui Paulo DELAY(1000); 2232*31d98677SRui Paulo } 2233*31d98677SRui Paulo if (ntries == 100) { 2234*31d98677SRui Paulo device_printf(sc->sc_dev, 2235*31d98677SRui Paulo "timeout waiting for microcontroller\n"); 2236*31d98677SRui Paulo error = ETIMEDOUT; 2237*31d98677SRui Paulo goto fail; 2238*31d98677SRui Paulo } 2239*31d98677SRui Paulo 2240*31d98677SRui Paulo /* Update DMEM section before loading. */ 2241*31d98677SRui Paulo dmem = &hdr->priv; 2242*31d98677SRui Paulo memset(dmem, 0, sizeof(*dmem)); 2243*31d98677SRui Paulo dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172; 2244*31d98677SRui Paulo dmem->nendpoints = sc->npipes; 2245*31d98677SRui Paulo dmem->rf_config = 0x12; /* 1T2R */ 2246*31d98677SRui Paulo dmem->vcs_type = R92S_VCS_TYPE_AUTO; 2247*31d98677SRui Paulo dmem->vcs_mode = R92S_VCS_MODE_RTS_CTS; 2248*31d98677SRui Paulo #ifdef notyet 2249*31d98677SRui Paulo dmem->bw40_en = (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) != 0; 2250*31d98677SRui Paulo #endif 2251*31d98677SRui Paulo dmem->turbo_mode = 1; 2252*31d98677SRui Paulo /* Load DMEM section. */ 2253*31d98677SRui Paulo error = rsu_fw_loadsection(sc, (uint8_t *)dmem, sizeof(*dmem)); 2254*31d98677SRui Paulo if (error != 0) { 2255*31d98677SRui Paulo device_printf(sc->sc_dev, 2256*31d98677SRui Paulo "could not load firmware section %s\n", "DMEM"); 2257*31d98677SRui Paulo goto fail; 2258*31d98677SRui Paulo } 2259*31d98677SRui Paulo /* Wait for load to complete. */ 2260*31d98677SRui Paulo for (ntries = 0; ntries < 100; ntries++) { 2261*31d98677SRui Paulo if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_DMEM_CODE_DONE) 2262*31d98677SRui Paulo break; 2263*31d98677SRui Paulo DELAY(1000); 2264*31d98677SRui Paulo } 2265*31d98677SRui Paulo if (ntries == 100) { 2266*31d98677SRui Paulo device_printf(sc->sc_dev, "timeout waiting for %s transfer\n", 2267*31d98677SRui Paulo "DMEM"); 2268*31d98677SRui Paulo error = ETIMEDOUT; 2269*31d98677SRui Paulo goto fail; 2270*31d98677SRui Paulo } 2271*31d98677SRui Paulo /* Wait for firmware readiness. */ 2272*31d98677SRui Paulo for (ntries = 0; ntries < 60; ntries++) { 2273*31d98677SRui Paulo if (!(rsu_read_2(sc, R92S_TCR) & R92S_TCR_FWRDY)) 2274*31d98677SRui Paulo break; 2275*31d98677SRui Paulo DELAY(1000); 2276*31d98677SRui Paulo } 2277*31d98677SRui Paulo if (ntries == 60) { 2278*31d98677SRui Paulo device_printf(sc->sc_dev, 2279*31d98677SRui Paulo "timeout waiting for firmware readiness\n"); 2280*31d98677SRui Paulo error = ETIMEDOUT; 2281*31d98677SRui Paulo goto fail; 2282*31d98677SRui Paulo } 2283*31d98677SRui Paulo fail: 2284*31d98677SRui Paulo firmware_put(fw, FIRMWARE_UNLOAD); 2285*31d98677SRui Paulo return (error); 2286*31d98677SRui Paulo } 2287*31d98677SRui Paulo 2288*31d98677SRui Paulo 2289*31d98677SRui Paulo static int 2290*31d98677SRui Paulo rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2291*31d98677SRui Paulo const struct ieee80211_bpf_params *params) 2292*31d98677SRui Paulo { 2293*31d98677SRui Paulo struct ieee80211com *ic = ni->ni_ic; 2294*31d98677SRui Paulo struct ifnet *ifp = ic->ic_ifp; 2295*31d98677SRui Paulo struct rsu_softc *sc = ifp->if_softc; 2296*31d98677SRui Paulo struct rsu_data *bf; 2297*31d98677SRui Paulo 2298*31d98677SRui Paulo /* prevent management frames from being sent if we're not ready */ 2299*31d98677SRui Paulo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2300*31d98677SRui Paulo m_freem(m); 2301*31d98677SRui Paulo ieee80211_free_node(ni); 2302*31d98677SRui Paulo return (ENETDOWN); 2303*31d98677SRui Paulo } 2304*31d98677SRui Paulo RSU_LOCK(sc); 2305*31d98677SRui Paulo bf = rsu_getbuf(sc); 2306*31d98677SRui Paulo if (bf == NULL) { 2307*31d98677SRui Paulo ieee80211_free_node(ni); 2308*31d98677SRui Paulo m_freem(m); 2309*31d98677SRui Paulo RSU_UNLOCK(sc); 2310*31d98677SRui Paulo return (ENOBUFS); 2311*31d98677SRui Paulo } 2312*31d98677SRui Paulo ifp->if_opackets++; 2313*31d98677SRui Paulo if (rsu_tx_start(sc, ni, m, bf) != 0) { 2314*31d98677SRui Paulo ieee80211_free_node(ni); 2315*31d98677SRui Paulo ifp->if_oerrors++; 2316*31d98677SRui Paulo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 2317*31d98677SRui Paulo RSU_UNLOCK(sc); 2318*31d98677SRui Paulo return (EIO); 2319*31d98677SRui Paulo } 2320*31d98677SRui Paulo RSU_UNLOCK(sc); 2321*31d98677SRui Paulo sc->sc_tx_timer = 5; 2322*31d98677SRui Paulo 2323*31d98677SRui Paulo return (0); 2324*31d98677SRui Paulo } 2325*31d98677SRui Paulo 2326*31d98677SRui Paulo static void 2327*31d98677SRui Paulo rsu_init(void *arg) 2328*31d98677SRui Paulo { 2329*31d98677SRui Paulo struct rsu_softc *sc = arg; 2330*31d98677SRui Paulo 2331*31d98677SRui Paulo RSU_LOCK(sc); 2332*31d98677SRui Paulo rsu_init_locked(arg); 2333*31d98677SRui Paulo RSU_UNLOCK(sc); 2334*31d98677SRui Paulo } 2335*31d98677SRui Paulo 2336*31d98677SRui Paulo static void 2337*31d98677SRui Paulo rsu_init_locked(struct rsu_softc *sc) 2338*31d98677SRui Paulo { 2339*31d98677SRui Paulo struct ifnet *ifp = sc->sc_ifp; 2340*31d98677SRui Paulo struct r92s_set_pwr_mode cmd; 2341*31d98677SRui Paulo int error; 2342*31d98677SRui Paulo 2343*31d98677SRui Paulo /* Init host async commands ring. */ 2344*31d98677SRui Paulo sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0; 2345*31d98677SRui Paulo 2346*31d98677SRui Paulo /* Allocate Tx/Rx buffers. */ 2347*31d98677SRui Paulo error = rsu_alloc_rx_list(sc); 2348*31d98677SRui Paulo if (error != 0) { 2349*31d98677SRui Paulo device_printf(sc->sc_dev, "could not allocate Rx buffers\n"); 2350*31d98677SRui Paulo return; 2351*31d98677SRui Paulo } 2352*31d98677SRui Paulo error = rsu_alloc_tx_list(sc); 2353*31d98677SRui Paulo if (error != 0) { 2354*31d98677SRui Paulo device_printf(sc->sc_dev, "could not allocate Tx buffers\n"); 2355*31d98677SRui Paulo rsu_free_rx_list(sc); 2356*31d98677SRui Paulo return; 2357*31d98677SRui Paulo } 2358*31d98677SRui Paulo /* Power on adapter. */ 2359*31d98677SRui Paulo if (sc->cut == 1) 2360*31d98677SRui Paulo rsu_power_on_acut(sc); 2361*31d98677SRui Paulo else 2362*31d98677SRui Paulo rsu_power_on_bcut(sc); 2363*31d98677SRui Paulo /* Load firmware. */ 2364*31d98677SRui Paulo error = rsu_load_firmware(sc); 2365*31d98677SRui Paulo if (error != 0) 2366*31d98677SRui Paulo goto fail; 2367*31d98677SRui Paulo 2368*31d98677SRui Paulo /* Enable Rx TCP checksum offload. */ 2369*31d98677SRui Paulo rsu_write_4(sc, R92S_RCR, 2370*31d98677SRui Paulo rsu_read_4(sc, R92S_RCR) | 0x04000000); 2371*31d98677SRui Paulo /* Append PHY status. */ 2372*31d98677SRui Paulo rsu_write_4(sc, R92S_RCR, 2373*31d98677SRui Paulo rsu_read_4(sc, R92S_RCR) | 0x02000000); 2374*31d98677SRui Paulo 2375*31d98677SRui Paulo rsu_write_4(sc, R92S_CR, 2376*31d98677SRui Paulo rsu_read_4(sc, R92S_CR) & ~0xff000000); 2377*31d98677SRui Paulo 2378*31d98677SRui Paulo /* Use 128 bytes pages. */ 2379*31d98677SRui Paulo rsu_write_1(sc, 0x00b5, 2380*31d98677SRui Paulo rsu_read_1(sc, 0x00b5) | 0x01); 2381*31d98677SRui Paulo /* Enable USB Rx aggregation. */ 2382*31d98677SRui Paulo rsu_write_1(sc, 0x00bd, 2383*31d98677SRui Paulo rsu_read_1(sc, 0x00bd) | 0x80); 2384*31d98677SRui Paulo /* Set USB Rx aggregation threshold. */ 2385*31d98677SRui Paulo rsu_write_1(sc, 0x00d9, 0x01); 2386*31d98677SRui Paulo /* Set USB Rx aggregation timeout (1.7ms/4). */ 2387*31d98677SRui Paulo rsu_write_1(sc, 0xfe5b, 0x04); 2388*31d98677SRui Paulo /* Fix USB Rx FIFO issue. */ 2389*31d98677SRui Paulo rsu_write_1(sc, 0xfe5c, 2390*31d98677SRui Paulo rsu_read_1(sc, 0xfe5c) | 0x80); 2391*31d98677SRui Paulo 2392*31d98677SRui Paulo /* Set MAC address. */ 2393*31d98677SRui Paulo rsu_write_region_1(sc, R92S_MACID, IF_LLADDR(ifp), 2394*31d98677SRui Paulo IEEE80211_ADDR_LEN); 2395*31d98677SRui Paulo 2396*31d98677SRui Paulo /* NB: it really takes that long for firmware to boot. */ 2397*31d98677SRui Paulo usb_pause_mtx(&sc->sc_mtx, 1500); 2398*31d98677SRui Paulo 2399*31d98677SRui Paulo DPRINTF("setting MAC address to %s\n", ether_sprintf(IF_LLADDR(ifp))); 2400*31d98677SRui Paulo error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, IF_LLADDR(ifp), 2401*31d98677SRui Paulo IEEE80211_ADDR_LEN); 2402*31d98677SRui Paulo if (error != 0) { 2403*31d98677SRui Paulo device_printf(sc->sc_dev, "could not set MAC address\n"); 2404*31d98677SRui Paulo goto fail; 2405*31d98677SRui Paulo } 2406*31d98677SRui Paulo 2407*31d98677SRui Paulo rsu_write_1(sc, R92S_USB_HRPWM, 2408*31d98677SRui Paulo R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON); 2409*31d98677SRui Paulo 2410*31d98677SRui Paulo memset(&cmd, 0, sizeof(cmd)); 2411*31d98677SRui Paulo cmd.mode = R92S_PS_MODE_ACTIVE; 2412*31d98677SRui Paulo DPRINTF("setting ps mode to %d\n", cmd.mode); 2413*31d98677SRui Paulo error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd)); 2414*31d98677SRui Paulo if (error != 0) { 2415*31d98677SRui Paulo device_printf(sc->sc_dev, "could not set PS mode\n"); 2416*31d98677SRui Paulo goto fail; 2417*31d98677SRui Paulo } 2418*31d98677SRui Paulo 2419*31d98677SRui Paulo #if 0 2420*31d98677SRui Paulo if (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) { 2421*31d98677SRui Paulo /* Enable 40MHz mode. */ 2422*31d98677SRui Paulo error = rsu_fw_iocmd(sc, 2423*31d98677SRui Paulo SM(R92S_IOCMD_CLASS, 0xf4) | 2424*31d98677SRui Paulo SM(R92S_IOCMD_INDEX, 0x00) | 2425*31d98677SRui Paulo SM(R92S_IOCMD_VALUE, 0x0007)); 2426*31d98677SRui Paulo if (error != 0) { 2427*31d98677SRui Paulo device_printf(sc->sc_dev, 2428*31d98677SRui Paulo "could not enable 40MHz mode\n"); 2429*31d98677SRui Paulo goto fail; 2430*31d98677SRui Paulo } 2431*31d98677SRui Paulo } 2432*31d98677SRui Paulo 2433*31d98677SRui Paulo /* Set default channel. */ 2434*31d98677SRui Paulo ic->ic_bss->ni_chan = ic->ic_ibss_chan; 2435*31d98677SRui Paulo #endif 2436*31d98677SRui Paulo sc->scan_pass = 0; 2437*31d98677SRui Paulo usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]); 2438*31d98677SRui Paulo 2439*31d98677SRui Paulo /* We're ready to go. */ 2440*31d98677SRui Paulo ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2441*31d98677SRui Paulo ifp->if_drv_flags |= IFF_DRV_RUNNING; 2442*31d98677SRui Paulo 2443*31d98677SRui Paulo callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc); 2444*31d98677SRui Paulo 2445*31d98677SRui Paulo return; 2446*31d98677SRui Paulo fail: 2447*31d98677SRui Paulo rsu_free_rx_list(sc); 2448*31d98677SRui Paulo rsu_free_tx_list(sc); 2449*31d98677SRui Paulo return; 2450*31d98677SRui Paulo } 2451*31d98677SRui Paulo 2452*31d98677SRui Paulo static void 2453*31d98677SRui Paulo rsu_stop(struct ifnet *ifp, int disable) 2454*31d98677SRui Paulo { 2455*31d98677SRui Paulo struct rsu_softc *sc = ifp->if_softc; 2456*31d98677SRui Paulo 2457*31d98677SRui Paulo RSU_LOCK(sc); 2458*31d98677SRui Paulo rsu_stop_locked(ifp, disable); 2459*31d98677SRui Paulo RSU_UNLOCK(sc); 2460*31d98677SRui Paulo } 2461*31d98677SRui Paulo 2462*31d98677SRui Paulo static void 2463*31d98677SRui Paulo rsu_stop_locked(struct ifnet *ifp, int disable __unused) 2464*31d98677SRui Paulo { 2465*31d98677SRui Paulo struct rsu_softc *sc = ifp->if_softc; 2466*31d98677SRui Paulo int i; 2467*31d98677SRui Paulo 2468*31d98677SRui Paulo ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2469*31d98677SRui Paulo callout_stop(&sc->sc_watchdog_ch); 2470*31d98677SRui Paulo sc->sc_calibrating = 0; 2471*31d98677SRui Paulo taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL); 2472*31d98677SRui Paulo 2473*31d98677SRui Paulo /* Power off adapter. */ 2474*31d98677SRui Paulo rsu_power_off(sc); 2475*31d98677SRui Paulo 2476*31d98677SRui Paulo for (i = 0; i < RSU_N_TRANSFER; i++) 2477*31d98677SRui Paulo usbd_transfer_stop(sc->sc_xfer[i]); 2478*31d98677SRui Paulo } 2479*31d98677SRui Paulo 2480