if_urtwn.c revision 292080
1251538Srpaulo/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 2251538Srpaulo 3251538Srpaulo/*- 4251538Srpaulo * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5264912Skevlo * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 6251538Srpaulo * 7251538Srpaulo * Permission to use, copy, modify, and distribute this software for any 8251538Srpaulo * purpose with or without fee is hereby granted, provided that the above 9251538Srpaulo * copyright notice and this permission notice appear in all copies. 10251538Srpaulo * 11251538Srpaulo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12251538Srpaulo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13251538Srpaulo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14251538Srpaulo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15251538Srpaulo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16251538Srpaulo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17251538Srpaulo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18251538Srpaulo */ 19251538Srpaulo 20251538Srpaulo#include <sys/cdefs.h> 21251538Srpaulo__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_urtwn.c 292080 2015-12-11 05:28:00Z imp $"); 22251538Srpaulo 23251538Srpaulo/* 24264912Skevlo * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU. 25251538Srpaulo */ 26251538Srpaulo 27288353Sadrian#include "opt_wlan.h" 28288353Sadrian 29251538Srpaulo#include <sys/param.h> 30251538Srpaulo#include <sys/sockio.h> 31251538Srpaulo#include <sys/sysctl.h> 32251538Srpaulo#include <sys/lock.h> 33251538Srpaulo#include <sys/mutex.h> 34291902Skevlo#include <sys/condvar.h> 35251538Srpaulo#include <sys/mbuf.h> 36251538Srpaulo#include <sys/kernel.h> 37251538Srpaulo#include <sys/socket.h> 38251538Srpaulo#include <sys/systm.h> 39251538Srpaulo#include <sys/malloc.h> 40251538Srpaulo#include <sys/module.h> 41251538Srpaulo#include <sys/bus.h> 42251538Srpaulo#include <sys/endian.h> 43251538Srpaulo#include <sys/linker.h> 44251538Srpaulo#include <sys/firmware.h> 45251538Srpaulo#include <sys/kdb.h> 46251538Srpaulo 47251538Srpaulo#include <machine/bus.h> 48251538Srpaulo#include <machine/resource.h> 49251538Srpaulo#include <sys/rman.h> 50251538Srpaulo 51251538Srpaulo#include <net/bpf.h> 52251538Srpaulo#include <net/if.h> 53257176Sglebius#include <net/if_var.h> 54251538Srpaulo#include <net/if_arp.h> 55251538Srpaulo#include <net/ethernet.h> 56251538Srpaulo#include <net/if_dl.h> 57251538Srpaulo#include <net/if_media.h> 58251538Srpaulo#include <net/if_types.h> 59251538Srpaulo 60251538Srpaulo#include <netinet/in.h> 61251538Srpaulo#include <netinet/in_systm.h> 62251538Srpaulo#include <netinet/in_var.h> 63251538Srpaulo#include <netinet/if_ether.h> 64251538Srpaulo#include <netinet/ip.h> 65251538Srpaulo 66251538Srpaulo#include <net80211/ieee80211_var.h> 67288088Sadrian#include <net80211/ieee80211_input.h> 68251538Srpaulo#include <net80211/ieee80211_regdomain.h> 69251538Srpaulo#include <net80211/ieee80211_radiotap.h> 70251538Srpaulo#include <net80211/ieee80211_ratectl.h> 71251538Srpaulo 72251538Srpaulo#include <dev/usb/usb.h> 73251538Srpaulo#include <dev/usb/usbdi.h> 74291902Skevlo#include <dev/usb/usb_device.h> 75251538Srpaulo#include "usbdevs.h" 76251538Srpaulo 77251538Srpaulo#define USB_DEBUG_VAR urtwn_debug 78251538Srpaulo#include <dev/usb/usb_debug.h> 79251538Srpaulo 80251538Srpaulo#include <dev/usb/wlan/if_urtwnreg.h> 81289167Sadrian#include <dev/usb/wlan/if_urtwnvar.h> 82251538Srpaulo 83251538Srpaulo#ifdef USB_DEBUG 84251538Srpaulostatic int urtwn_debug = 0; 85251538Srpaulo 86251538SrpauloSYSCTL_NODE(_hw_usb, OID_AUTO, urtwn, CTLFLAG_RW, 0, "USB urtwn"); 87276701ShselaskySYSCTL_INT(_hw_usb_urtwn, OID_AUTO, debug, CTLFLAG_RWTUN, &urtwn_debug, 0, 88251538Srpaulo "Debug level"); 89251538Srpaulo#endif 90251538Srpaulo 91288088Sadrian#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) 92251538Srpaulo 93251538Srpaulo/* various supported device vendors/products */ 94251596Srpaulostatic const STRUCT_USB_HOST_ID urtwn_devs[] = { 95251538Srpaulo#define URTWN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 96264912Skevlo#define URTWN_RTL8188E_DEV(v,p) \ 97264912Skevlo { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTWN_RTL8188E) } 98264912Skevlo#define URTWN_RTL8188E 1 99251538Srpaulo URTWN_DEV(ABOCOM, RTL8188CU_1), 100251538Srpaulo URTWN_DEV(ABOCOM, RTL8188CU_2), 101251538Srpaulo URTWN_DEV(ABOCOM, RTL8192CU), 102251538Srpaulo URTWN_DEV(ASUS, RTL8192CU), 103266721Skevlo URTWN_DEV(ASUS, USBN10NANO), 104251538Srpaulo URTWN_DEV(AZUREWAVE, RTL8188CE_1), 105251538Srpaulo URTWN_DEV(AZUREWAVE, RTL8188CE_2), 106251538Srpaulo URTWN_DEV(AZUREWAVE, RTL8188CU), 107251538Srpaulo URTWN_DEV(BELKIN, F7D2102), 108251538Srpaulo URTWN_DEV(BELKIN, RTL8188CU), 109251538Srpaulo URTWN_DEV(BELKIN, RTL8192CU), 110251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_1), 111251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_2), 112251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_3), 113251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_4), 114251538Srpaulo URTWN_DEV(CHICONY, RTL8188CUS_5), 115251538Srpaulo URTWN_DEV(COREGA, RTL8192CU), 116251538Srpaulo URTWN_DEV(DLINK, RTL8188CU), 117251538Srpaulo URTWN_DEV(DLINK, RTL8192CU_1), 118251538Srpaulo URTWN_DEV(DLINK, RTL8192CU_2), 119251538Srpaulo URTWN_DEV(DLINK, RTL8192CU_3), 120252196Skevlo URTWN_DEV(DLINK, DWA131B), 121251538Srpaulo URTWN_DEV(EDIMAX, EW7811UN), 122251538Srpaulo URTWN_DEV(EDIMAX, RTL8192CU), 123251538Srpaulo URTWN_DEV(FEIXUN, RTL8188CU), 124251538Srpaulo URTWN_DEV(FEIXUN, RTL8192CU), 125251538Srpaulo URTWN_DEV(GUILLEMOT, HWNUP150), 126251538Srpaulo URTWN_DEV(HAWKING, RTL8192CU), 127251538Srpaulo URTWN_DEV(HP3, RTL8188CU), 128251538Srpaulo URTWN_DEV(NETGEAR, WNA1000M), 129251538Srpaulo URTWN_DEV(NETGEAR, RTL8192CU), 130251538Srpaulo URTWN_DEV(NETGEAR4, RTL8188CU), 131251538Srpaulo URTWN_DEV(NOVATECH, RTL8188CU), 132251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_1), 133251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_2), 134251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_3), 135251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CU_4), 136251538Srpaulo URTWN_DEV(PLANEX2, RTL8188CUS), 137251538Srpaulo URTWN_DEV(PLANEX2, RTL8192CU), 138251538Srpaulo URTWN_DEV(REALTEK, RTL8188CE_0), 139251538Srpaulo URTWN_DEV(REALTEK, RTL8188CE_1), 140251538Srpaulo URTWN_DEV(REALTEK, RTL8188CTV), 141251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_0), 142251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_1), 143251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_2), 144282119Skevlo URTWN_DEV(REALTEK, RTL8188CU_3), 145251538Srpaulo URTWN_DEV(REALTEK, RTL8188CU_COMBO), 146251538Srpaulo URTWN_DEV(REALTEK, RTL8188CUS), 147251538Srpaulo URTWN_DEV(REALTEK, RTL8188RU_1), 148251538Srpaulo URTWN_DEV(REALTEK, RTL8188RU_2), 149272410Shselasky URTWN_DEV(REALTEK, RTL8188RU_3), 150251538Srpaulo URTWN_DEV(REALTEK, RTL8191CU), 151251538Srpaulo URTWN_DEV(REALTEK, RTL8192CE), 152251538Srpaulo URTWN_DEV(REALTEK, RTL8192CU), 153251538Srpaulo URTWN_DEV(SITECOMEU, RTL8188CU_1), 154251538Srpaulo URTWN_DEV(SITECOMEU, RTL8188CU_2), 155251538Srpaulo URTWN_DEV(SITECOMEU, RTL8192CU), 156251538Srpaulo URTWN_DEV(TRENDNET, RTL8188CU), 157251538Srpaulo URTWN_DEV(TRENDNET, RTL8192CU), 158251538Srpaulo URTWN_DEV(ZYXEL, RTL8192CU), 159264912Skevlo /* URTWN_RTL8188E */ 160273589Skevlo URTWN_RTL8188E_DEV(DLINK, DWA123D1), 161270191Skevlo URTWN_RTL8188E_DEV(DLINK, DWA125D1), 162273589Skevlo URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M), 163264912Skevlo URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV), 164264912Skevlo URTWN_RTL8188E_DEV(REALTEK, RTL8188EU), 165264912Skevlo#undef URTWN_RTL8188E_DEV 166251538Srpaulo#undef URTWN_DEV 167251538Srpaulo}; 168251538Srpaulo 169251538Srpaulostatic device_probe_t urtwn_match; 170251538Srpaulostatic device_attach_t urtwn_attach; 171251538Srpaulostatic device_detach_t urtwn_detach; 172251538Srpaulo 173251538Srpaulostatic usb_callback_t urtwn_bulk_tx_callback; 174251538Srpaulostatic usb_callback_t urtwn_bulk_rx_callback; 175251538Srpaulo 176288353Sadrianstatic void urtwn_drain_mbufq(struct urtwn_softc *sc); 177287197Sglebiusstatic usb_error_t urtwn_do_request(struct urtwn_softc *, 178287197Sglebius struct usb_device_request *, void *); 179251538Srpaulostatic struct ieee80211vap *urtwn_vap_create(struct ieee80211com *, 180251538Srpaulo const char [IFNAMSIZ], int, enum ieee80211_opmode, int, 181251538Srpaulo const uint8_t [IEEE80211_ADDR_LEN], 182251538Srpaulo const uint8_t [IEEE80211_ADDR_LEN]); 183251538Srpaulostatic void urtwn_vap_delete(struct ieee80211vap *); 184281069Srpaulostatic struct mbuf * urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int, 185251538Srpaulo int *); 186281069Srpaulostatic struct mbuf * urtwn_rxeof(struct usb_xfer *, struct urtwn_data *, 187251538Srpaulo int *, int8_t *); 188289891Savosstatic void urtwn_txeof(struct urtwn_softc *, struct urtwn_data *, 189289891Savos int); 190281069Srpaulostatic int urtwn_alloc_list(struct urtwn_softc *, 191251538Srpaulo struct urtwn_data[], int, int); 192251538Srpaulostatic int urtwn_alloc_rx_list(struct urtwn_softc *); 193251538Srpaulostatic int urtwn_alloc_tx_list(struct urtwn_softc *); 194251538Srpaulostatic void urtwn_free_list(struct urtwn_softc *, 195251538Srpaulo struct urtwn_data data[], int); 196289066Skevlostatic void urtwn_free_rx_list(struct urtwn_softc *); 197289066Skevlostatic void urtwn_free_tx_list(struct urtwn_softc *); 198251538Srpaulostatic struct urtwn_data * _urtwn_getbuf(struct urtwn_softc *); 199251538Srpaulostatic struct urtwn_data * urtwn_getbuf(struct urtwn_softc *); 200291698Savosstatic usb_error_t urtwn_write_region_1(struct urtwn_softc *, uint16_t, 201251538Srpaulo uint8_t *, int); 202291698Savosstatic usb_error_t urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t); 203291698Savosstatic usb_error_t urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t); 204291698Savosstatic usb_error_t urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t); 205291698Savosstatic usb_error_t urtwn_read_region_1(struct urtwn_softc *, uint16_t, 206251538Srpaulo uint8_t *, int); 207251538Srpaulostatic uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t); 208251538Srpaulostatic uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t); 209251538Srpaulostatic uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t); 210281069Srpaulostatic int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, 211251538Srpaulo const void *, int); 212264912Skevlostatic void urtwn_r92c_rf_write(struct urtwn_softc *, int, 213264912Skevlo uint8_t, uint32_t); 214281069Srpaulostatic void urtwn_r88e_rf_write(struct urtwn_softc *, int, 215264912Skevlo uint8_t, uint32_t); 216251538Srpaulostatic uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t); 217281069Srpaulostatic int urtwn_llt_write(struct urtwn_softc *, uint32_t, 218251538Srpaulo uint32_t); 219291264Savosstatic int urtwn_efuse_read_next(struct urtwn_softc *, uint8_t *); 220291264Savosstatic int urtwn_efuse_read_data(struct urtwn_softc *, uint8_t *, 221291264Savos uint8_t, uint8_t); 222291264Savos#ifdef URTWN_DEBUG 223291264Savosstatic void urtwn_dump_rom_contents(struct urtwn_softc *, 224291264Savos uint8_t *, uint16_t); 225291264Savos#endif 226291264Savosstatic int urtwn_efuse_read(struct urtwn_softc *, uint8_t *, 227291264Savos uint16_t); 228291698Savosstatic int urtwn_efuse_switch_power(struct urtwn_softc *); 229251538Srpaulostatic int urtwn_read_chipid(struct urtwn_softc *); 230291264Savosstatic int urtwn_read_rom(struct urtwn_softc *); 231291264Savosstatic int urtwn_r88e_read_rom(struct urtwn_softc *); 232251538Srpaulostatic int urtwn_ra_init(struct urtwn_softc *); 233290631Savosstatic void urtwn_init_beacon(struct urtwn_softc *, 234290631Savos struct urtwn_vap *); 235290631Savosstatic int urtwn_setup_beacon(struct urtwn_softc *, 236290631Savos struct ieee80211_node *); 237290631Savosstatic void urtwn_update_beacon(struct ieee80211vap *, int); 238290631Savosstatic int urtwn_tx_beacon(struct urtwn_softc *sc, 239290631Savos struct urtwn_vap *); 240290651Savosstatic void urtwn_tsf_task_adhoc(void *, int); 241290631Savosstatic void urtwn_tsf_sync_enable(struct urtwn_softc *, 242290631Savos struct ieee80211vap *); 243251538Srpaulostatic void urtwn_set_led(struct urtwn_softc *, int, int); 244289811Savosstatic void urtwn_set_mode(struct urtwn_softc *, uint8_t); 245290651Savosstatic void urtwn_ibss_recv_mgmt(struct ieee80211_node *, 246290651Savos struct mbuf *, int, 247290651Savos const struct ieee80211_rx_stats *, int, int); 248281069Srpaulostatic int urtwn_newstate(struct ieee80211vap *, 249251538Srpaulo enum ieee80211_state, int); 250251538Srpaulostatic void urtwn_watchdog(void *); 251251538Srpaulostatic void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); 252251538Srpaulostatic int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); 253264912Skevlostatic int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); 254290630Savosstatic int urtwn_tx_data(struct urtwn_softc *, 255251538Srpaulo struct ieee80211_node *, struct mbuf *, 256251538Srpaulo struct urtwn_data *); 257290630Savosstatic void urtwn_tx_start(struct urtwn_softc *, struct mbuf *, 258290630Savos uint8_t, struct urtwn_data *); 259287197Sglebiusstatic int urtwn_transmit(struct ieee80211com *, struct mbuf *); 260287197Sglebiusstatic void urtwn_start(struct urtwn_softc *); 261287197Sglebiusstatic void urtwn_parent(struct ieee80211com *); 262264912Skevlostatic int urtwn_r92c_power_on(struct urtwn_softc *); 263264912Skevlostatic int urtwn_r88e_power_on(struct urtwn_softc *); 264251538Srpaulostatic int urtwn_llt_init(struct urtwn_softc *); 265251538Srpaulostatic void urtwn_fw_reset(struct urtwn_softc *); 266264912Skevlostatic void urtwn_r88e_fw_reset(struct urtwn_softc *); 267281069Srpaulostatic int urtwn_fw_loadpage(struct urtwn_softc *, int, 268251538Srpaulo const uint8_t *, int); 269251538Srpaulostatic int urtwn_load_firmware(struct urtwn_softc *); 270291902Skevlostatic int urtwn_dma_init(struct urtwn_softc *); 271291698Savosstatic int urtwn_mac_init(struct urtwn_softc *); 272251538Srpaulostatic void urtwn_bb_init(struct urtwn_softc *); 273251538Srpaulostatic void urtwn_rf_init(struct urtwn_softc *); 274251538Srpaulostatic void urtwn_cam_init(struct urtwn_softc *); 275251538Srpaulostatic void urtwn_pa_bias_init(struct urtwn_softc *); 276251538Srpaulostatic void urtwn_rxfilter_init(struct urtwn_softc *); 277251538Srpaulostatic void urtwn_edca_init(struct urtwn_softc *); 278281069Srpaulostatic void urtwn_write_txpower(struct urtwn_softc *, int, 279251538Srpaulo uint16_t[]); 280251538Srpaulostatic void urtwn_get_txpower(struct urtwn_softc *, int, 281281069Srpaulo struct ieee80211_channel *, 282251538Srpaulo struct ieee80211_channel *, uint16_t[]); 283264912Skevlostatic void urtwn_r88e_get_txpower(struct urtwn_softc *, int, 284281069Srpaulo struct ieee80211_channel *, 285264912Skevlo struct ieee80211_channel *, uint16_t[]); 286251538Srpaulostatic void urtwn_set_txpower(struct urtwn_softc *, 287281069Srpaulo struct ieee80211_channel *, 288251538Srpaulo struct ieee80211_channel *); 289290048Savosstatic void urtwn_set_rx_bssid_all(struct urtwn_softc *, int); 290290048Savosstatic void urtwn_set_gain(struct urtwn_softc *, uint8_t); 291251538Srpaulostatic void urtwn_scan_start(struct ieee80211com *); 292251538Srpaulostatic void urtwn_scan_end(struct ieee80211com *); 293251538Srpaulostatic void urtwn_set_channel(struct ieee80211com *); 294292014Savosstatic int urtwn_wme_update(struct ieee80211com *); 295290564Savosstatic void urtwn_set_promisc(struct urtwn_softc *); 296290564Savosstatic void urtwn_update_promisc(struct ieee80211com *); 297289066Skevlostatic void urtwn_update_mcast(struct ieee80211com *); 298251538Srpaulostatic void urtwn_set_chan(struct urtwn_softc *, 299281069Srpaulo struct ieee80211_channel *, 300251538Srpaulo struct ieee80211_channel *); 301251538Srpaulostatic void urtwn_iq_calib(struct urtwn_softc *); 302251538Srpaulostatic void urtwn_lc_calib(struct urtwn_softc *); 303291698Savosstatic int urtwn_init(struct urtwn_softc *); 304287197Sglebiusstatic void urtwn_stop(struct urtwn_softc *); 305251538Srpaulostatic void urtwn_abort_xfers(struct urtwn_softc *); 306251538Srpaulostatic int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, 307251538Srpaulo const struct ieee80211_bpf_params *); 308266472Shselaskystatic void urtwn_ms_delay(struct urtwn_softc *); 309251538Srpaulo 310251538Srpaulo/* Aliases. */ 311251538Srpaulo#define urtwn_bb_write urtwn_write_4 312251538Srpaulo#define urtwn_bb_read urtwn_read_4 313251538Srpaulo 314251538Srpaulostatic const struct usb_config urtwn_config[URTWN_N_TRANSFER] = { 315251538Srpaulo [URTWN_BULK_RX] = { 316251538Srpaulo .type = UE_BULK, 317251538Srpaulo .endpoint = UE_ADDR_ANY, 318251538Srpaulo .direction = UE_DIR_IN, 319251538Srpaulo .bufsize = URTWN_RXBUFSZ, 320251538Srpaulo .flags = { 321251538Srpaulo .pipe_bof = 1, 322251538Srpaulo .short_xfer_ok = 1 323251538Srpaulo }, 324251538Srpaulo .callback = urtwn_bulk_rx_callback, 325251538Srpaulo }, 326251538Srpaulo [URTWN_BULK_TX_BE] = { 327251538Srpaulo .type = UE_BULK, 328251538Srpaulo .endpoint = 0x03, 329251538Srpaulo .direction = UE_DIR_OUT, 330251538Srpaulo .bufsize = URTWN_TXBUFSZ, 331251538Srpaulo .flags = { 332251538Srpaulo .ext_buffer = 1, 333251538Srpaulo .pipe_bof = 1, 334251538Srpaulo .force_short_xfer = 1 335251538Srpaulo }, 336251538Srpaulo .callback = urtwn_bulk_tx_callback, 337251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 338251538Srpaulo }, 339251538Srpaulo [URTWN_BULK_TX_BK] = { 340251538Srpaulo .type = UE_BULK, 341251538Srpaulo .endpoint = 0x03, 342251538Srpaulo .direction = UE_DIR_OUT, 343251538Srpaulo .bufsize = URTWN_TXBUFSZ, 344251538Srpaulo .flags = { 345251538Srpaulo .ext_buffer = 1, 346251538Srpaulo .pipe_bof = 1, 347251538Srpaulo .force_short_xfer = 1, 348251538Srpaulo }, 349251538Srpaulo .callback = urtwn_bulk_tx_callback, 350251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 351251538Srpaulo }, 352251538Srpaulo [URTWN_BULK_TX_VI] = { 353251538Srpaulo .type = UE_BULK, 354251538Srpaulo .endpoint = 0x02, 355251538Srpaulo .direction = UE_DIR_OUT, 356251538Srpaulo .bufsize = URTWN_TXBUFSZ, 357251538Srpaulo .flags = { 358251538Srpaulo .ext_buffer = 1, 359251538Srpaulo .pipe_bof = 1, 360251538Srpaulo .force_short_xfer = 1 361251538Srpaulo }, 362251538Srpaulo .callback = urtwn_bulk_tx_callback, 363251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 364251538Srpaulo }, 365251538Srpaulo [URTWN_BULK_TX_VO] = { 366251538Srpaulo .type = UE_BULK, 367251538Srpaulo .endpoint = 0x02, 368251538Srpaulo .direction = UE_DIR_OUT, 369251538Srpaulo .bufsize = URTWN_TXBUFSZ, 370251538Srpaulo .flags = { 371251538Srpaulo .ext_buffer = 1, 372251538Srpaulo .pipe_bof = 1, 373251538Srpaulo .force_short_xfer = 1 374251538Srpaulo }, 375251538Srpaulo .callback = urtwn_bulk_tx_callback, 376251538Srpaulo .timeout = URTWN_TX_TIMEOUT, /* ms */ 377251538Srpaulo }, 378251538Srpaulo}; 379251538Srpaulo 380292014Savosstatic const struct wme_to_queue { 381292014Savos uint16_t reg; 382292014Savos uint8_t qid; 383292014Savos} wme2queue[WME_NUM_AC] = { 384292014Savos { R92C_EDCA_BE_PARAM, URTWN_BULK_TX_BE}, 385292014Savos { R92C_EDCA_BK_PARAM, URTWN_BULK_TX_BK}, 386292014Savos { R92C_EDCA_VI_PARAM, URTWN_BULK_TX_VI}, 387292014Savos { R92C_EDCA_VO_PARAM, URTWN_BULK_TX_VO} 388292014Savos}; 389292014Savos 390251538Srpaulostatic int 391251538Srpaulourtwn_match(device_t self) 392251538Srpaulo{ 393251538Srpaulo struct usb_attach_arg *uaa = device_get_ivars(self); 394251538Srpaulo 395251538Srpaulo if (uaa->usb_mode != USB_MODE_HOST) 396251538Srpaulo return (ENXIO); 397251538Srpaulo if (uaa->info.bConfigIndex != URTWN_CONFIG_INDEX) 398251538Srpaulo return (ENXIO); 399251538Srpaulo if (uaa->info.bIfaceIndex != URTWN_IFACE_INDEX) 400251538Srpaulo return (ENXIO); 401251538Srpaulo 402251538Srpaulo return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa)); 403251538Srpaulo} 404251538Srpaulo 405251538Srpaulostatic int 406251538Srpaulourtwn_attach(device_t self) 407251538Srpaulo{ 408251538Srpaulo struct usb_attach_arg *uaa = device_get_ivars(self); 409251538Srpaulo struct urtwn_softc *sc = device_get_softc(self); 410287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 411291902Skevlo uint8_t bands; 412251538Srpaulo int error; 413251538Srpaulo 414251538Srpaulo device_set_usb_desc(self); 415251538Srpaulo sc->sc_udev = uaa->device; 416251538Srpaulo sc->sc_dev = self; 417264912Skevlo if (USB_GET_DRIVER_INFO(uaa) == URTWN_RTL8188E) 418264912Skevlo sc->chip |= URTWN_CHIP_88E; 419251538Srpaulo 420251538Srpaulo mtx_init(&sc->sc_mtx, device_get_nameunit(self), 421251538Srpaulo MTX_NETWORK_LOCK, MTX_DEF); 422251538Srpaulo callout_init(&sc->sc_watchdog_ch, 0); 423287197Sglebius mbufq_init(&sc->sc_snd, ifqmaxlen); 424251538Srpaulo 425291902Skevlo sc->sc_iface_index = URTWN_IFACE_INDEX; 426291902Skevlo error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index, 427291902Skevlo sc->sc_xfer, urtwn_config, URTWN_N_TRANSFER, sc, &sc->sc_mtx); 428251538Srpaulo if (error) { 429251538Srpaulo device_printf(self, "could not allocate USB transfers, " 430251538Srpaulo "err=%s\n", usbd_errstr(error)); 431251538Srpaulo goto detach; 432251538Srpaulo } 433251538Srpaulo 434251538Srpaulo URTWN_LOCK(sc); 435251538Srpaulo 436251538Srpaulo error = urtwn_read_chipid(sc); 437251538Srpaulo if (error) { 438251538Srpaulo device_printf(sc->sc_dev, "unsupported test chip\n"); 439251538Srpaulo URTWN_UNLOCK(sc); 440251538Srpaulo goto detach; 441251538Srpaulo } 442251538Srpaulo 443251538Srpaulo /* Determine number of Tx/Rx chains. */ 444251538Srpaulo if (sc->chip & URTWN_CHIP_92C) { 445251538Srpaulo sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2; 446251538Srpaulo sc->nrxchains = 2; 447251538Srpaulo } else { 448251538Srpaulo sc->ntxchains = 1; 449251538Srpaulo sc->nrxchains = 1; 450251538Srpaulo } 451251538Srpaulo 452264912Skevlo if (sc->chip & URTWN_CHIP_88E) 453291264Savos error = urtwn_r88e_read_rom(sc); 454264912Skevlo else 455291264Savos error = urtwn_read_rom(sc); 456291264Savos if (error != 0) { 457291264Savos device_printf(sc->sc_dev, "%s: cannot read rom, error %d\n", 458291264Savos __func__, error); 459291264Savos URTWN_UNLOCK(sc); 460291264Savos goto detach; 461291264Savos } 462264912Skevlo 463251538Srpaulo device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n", 464251538Srpaulo (sc->chip & URTWN_CHIP_92C) ? "8192CU" : 465264912Skevlo (sc->chip & URTWN_CHIP_88E) ? "8188EU" : 466251538Srpaulo (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : 467251538Srpaulo (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : 468251538Srpaulo "8188CUS", sc->ntxchains, sc->nrxchains); 469251538Srpaulo 470251538Srpaulo URTWN_UNLOCK(sc); 471251538Srpaulo 472283537Sglebius ic->ic_softc = sc; 473283527Sglebius ic->ic_name = device_get_nameunit(self); 474251538Srpaulo ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 475251538Srpaulo ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 476251538Srpaulo 477251538Srpaulo /* set device capabilities */ 478251538Srpaulo ic->ic_caps = 479251538Srpaulo IEEE80211_C_STA /* station mode */ 480251538Srpaulo | IEEE80211_C_MONITOR /* monitor mode */ 481290651Savos | IEEE80211_C_IBSS /* adhoc mode */ 482290631Savos | IEEE80211_C_HOSTAP /* hostap mode */ 483251538Srpaulo | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 484251538Srpaulo | IEEE80211_C_SHSLOT /* short slot time supported */ 485251538Srpaulo | IEEE80211_C_BGSCAN /* capable of bg scanning */ 486251538Srpaulo | IEEE80211_C_WPA /* 802.11i */ 487292014Savos | IEEE80211_C_WME /* 802.11e */ 488251538Srpaulo ; 489251538Srpaulo 490251538Srpaulo bands = 0; 491251538Srpaulo setbit(&bands, IEEE80211_MODE_11B); 492251538Srpaulo setbit(&bands, IEEE80211_MODE_11G); 493251538Srpaulo ieee80211_init_channels(ic, NULL, &bands); 494251538Srpaulo 495287197Sglebius ieee80211_ifattach(ic); 496251538Srpaulo ic->ic_raw_xmit = urtwn_raw_xmit; 497251538Srpaulo ic->ic_scan_start = urtwn_scan_start; 498251538Srpaulo ic->ic_scan_end = urtwn_scan_end; 499251538Srpaulo ic->ic_set_channel = urtwn_set_channel; 500287197Sglebius ic->ic_transmit = urtwn_transmit; 501287197Sglebius ic->ic_parent = urtwn_parent; 502251538Srpaulo ic->ic_vap_create = urtwn_vap_create; 503251538Srpaulo ic->ic_vap_delete = urtwn_vap_delete; 504292014Savos ic->ic_wme.wme_update = urtwn_wme_update; 505290564Savos ic->ic_update_promisc = urtwn_update_promisc; 506251538Srpaulo ic->ic_update_mcast = urtwn_update_mcast; 507251538Srpaulo 508281069Srpaulo ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, 509251538Srpaulo sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT, 510251538Srpaulo &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 511251538Srpaulo URTWN_RX_RADIOTAP_PRESENT); 512251538Srpaulo 513251538Srpaulo if (bootverbose) 514251538Srpaulo ieee80211_announce(ic); 515251538Srpaulo 516251538Srpaulo return (0); 517251538Srpaulo 518251538Srpaulodetach: 519251538Srpaulo urtwn_detach(self); 520251538Srpaulo return (ENXIO); /* failure */ 521251538Srpaulo} 522251538Srpaulo 523251538Srpaulostatic int 524251538Srpaulourtwn_detach(device_t self) 525251538Srpaulo{ 526251538Srpaulo struct urtwn_softc *sc = device_get_softc(self); 527287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 528263153Skevlo unsigned int x; 529281069Srpaulo 530263153Skevlo /* Prevent further ioctls. */ 531263153Skevlo URTWN_LOCK(sc); 532263153Skevlo sc->sc_flags |= URTWN_DETACHED; 533263153Skevlo URTWN_UNLOCK(sc); 534251538Srpaulo 535291698Savos urtwn_stop(sc); 536291698Savos 537251538Srpaulo callout_drain(&sc->sc_watchdog_ch); 538251538Srpaulo 539288353Sadrian /* stop all USB transfers */ 540288353Sadrian usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); 541288353Sadrian 542263153Skevlo /* Prevent further allocations from RX/TX data lists. */ 543263153Skevlo URTWN_LOCK(sc); 544263153Skevlo STAILQ_INIT(&sc->sc_tx_active); 545263153Skevlo STAILQ_INIT(&sc->sc_tx_inactive); 546263153Skevlo STAILQ_INIT(&sc->sc_tx_pending); 547263153Skevlo 548263153Skevlo STAILQ_INIT(&sc->sc_rx_active); 549263153Skevlo STAILQ_INIT(&sc->sc_rx_inactive); 550263153Skevlo URTWN_UNLOCK(sc); 551263153Skevlo 552263153Skevlo /* drain USB transfers */ 553263153Skevlo for (x = 0; x != URTWN_N_TRANSFER; x++) 554263153Skevlo usbd_transfer_drain(sc->sc_xfer[x]); 555263153Skevlo 556263153Skevlo /* Free data buffers. */ 557263153Skevlo URTWN_LOCK(sc); 558263153Skevlo urtwn_free_tx_list(sc); 559263153Skevlo urtwn_free_rx_list(sc); 560263153Skevlo URTWN_UNLOCK(sc); 561263153Skevlo 562251538Srpaulo ieee80211_ifdetach(ic); 563251538Srpaulo mtx_destroy(&sc->sc_mtx); 564251538Srpaulo 565251538Srpaulo return (0); 566251538Srpaulo} 567251538Srpaulo 568251538Srpaulostatic void 569289066Skevlourtwn_drain_mbufq(struct urtwn_softc *sc) 570251538Srpaulo{ 571289066Skevlo struct mbuf *m; 572289066Skevlo struct ieee80211_node *ni; 573289066Skevlo URTWN_ASSERT_LOCKED(sc); 574289066Skevlo while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 575289066Skevlo ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 576289066Skevlo m->m_pkthdr.rcvif = NULL; 577289066Skevlo ieee80211_free_node(ni); 578289066Skevlo m_freem(m); 579251538Srpaulo } 580251538Srpaulo} 581251538Srpaulo 582251538Srpaulostatic usb_error_t 583251538Srpaulourtwn_do_request(struct urtwn_softc *sc, struct usb_device_request *req, 584251538Srpaulo void *data) 585251538Srpaulo{ 586251538Srpaulo usb_error_t err; 587251538Srpaulo int ntries = 10; 588251538Srpaulo 589251538Srpaulo URTWN_ASSERT_LOCKED(sc); 590251538Srpaulo 591251538Srpaulo while (ntries--) { 592251538Srpaulo err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 593251538Srpaulo req, data, 0, NULL, 250 /* ms */); 594251538Srpaulo if (err == 0) 595251538Srpaulo break; 596251538Srpaulo 597251538Srpaulo DPRINTFN(1, "Control request failed, %s (retrying)\n", 598251538Srpaulo usbd_errstr(err)); 599251538Srpaulo usb_pause_mtx(&sc->sc_mtx, hz / 100); 600251538Srpaulo } 601251538Srpaulo return (err); 602251538Srpaulo} 603251538Srpaulo 604251538Srpaulostatic struct ieee80211vap * 605251538Srpaulourtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, 606251538Srpaulo enum ieee80211_opmode opmode, int flags, 607251538Srpaulo const uint8_t bssid[IEEE80211_ADDR_LEN], 608251538Srpaulo const uint8_t mac[IEEE80211_ADDR_LEN]) 609251538Srpaulo{ 610290631Savos struct urtwn_softc *sc = ic->ic_softc; 611251538Srpaulo struct urtwn_vap *uvp; 612251538Srpaulo struct ieee80211vap *vap; 613251538Srpaulo 614251538Srpaulo if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 615251538Srpaulo return (NULL); 616251538Srpaulo 617287197Sglebius uvp = malloc(sizeof(struct urtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); 618251538Srpaulo vap = &uvp->vap; 619251538Srpaulo /* enable s/w bmiss handling for sta mode */ 620251538Srpaulo 621281069Srpaulo if (ieee80211_vap_setup(ic, vap, name, unit, opmode, 622287197Sglebius flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { 623257743Shselasky /* out of memory */ 624257743Shselasky free(uvp, M_80211_VAP); 625257743Shselasky return (NULL); 626257743Shselasky } 627257743Shselasky 628290651Savos if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_IBSS) 629290631Savos urtwn_init_beacon(sc, uvp); 630290631Savos 631251538Srpaulo /* override state transition machine */ 632251538Srpaulo uvp->newstate = vap->iv_newstate; 633251538Srpaulo vap->iv_newstate = urtwn_newstate; 634290631Savos vap->iv_update_beacon = urtwn_update_beacon; 635290651Savos if (opmode == IEEE80211_M_IBSS) { 636290651Savos uvp->recv_mgmt = vap->iv_recv_mgmt; 637290651Savos vap->iv_recv_mgmt = urtwn_ibss_recv_mgmt; 638290651Savos TASK_INIT(&uvp->tsf_task_adhoc, 0, urtwn_tsf_task_adhoc, vap); 639290651Savos } 640251538Srpaulo 641251538Srpaulo /* complete setup */ 642251538Srpaulo ieee80211_vap_attach(vap, ieee80211_media_change, 643287197Sglebius ieee80211_media_status, mac); 644251538Srpaulo ic->ic_opmode = opmode; 645251538Srpaulo return (vap); 646251538Srpaulo} 647251538Srpaulo 648251538Srpaulostatic void 649251538Srpaulourtwn_vap_delete(struct ieee80211vap *vap) 650251538Srpaulo{ 651290651Savos struct ieee80211com *ic = vap->iv_ic; 652251538Srpaulo struct urtwn_vap *uvp = URTWN_VAP(vap); 653251538Srpaulo 654290651Savos if (uvp->bcn_mbuf != NULL) 655290651Savos m_freem(uvp->bcn_mbuf); 656290651Savos if (vap->iv_opmode == IEEE80211_M_IBSS) 657290651Savos ieee80211_draintask(ic, &uvp->tsf_task_adhoc); 658251538Srpaulo ieee80211_vap_detach(vap); 659251538Srpaulo free(uvp, M_80211_VAP); 660251538Srpaulo} 661251538Srpaulo 662251538Srpaulostatic struct mbuf * 663251538Srpaulourtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen, int *rssi_p) 664251538Srpaulo{ 665287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 666251538Srpaulo struct ieee80211_frame *wh; 667251538Srpaulo struct mbuf *m; 668251538Srpaulo struct r92c_rx_stat *stat; 669251538Srpaulo uint32_t rxdw0, rxdw3; 670251538Srpaulo uint8_t rate; 671251538Srpaulo int8_t rssi = 0; 672251538Srpaulo int infosz; 673251538Srpaulo 674251538Srpaulo /* 675251538Srpaulo * don't pass packets to the ieee80211 framework if the driver isn't 676251538Srpaulo * RUNNING. 677251538Srpaulo */ 678287197Sglebius if (!(sc->sc_flags & URTWN_RUNNING)) 679251538Srpaulo return (NULL); 680251538Srpaulo 681251538Srpaulo stat = (struct r92c_rx_stat *)buf; 682251538Srpaulo rxdw0 = le32toh(stat->rxdw0); 683251538Srpaulo rxdw3 = le32toh(stat->rxdw3); 684251538Srpaulo 685251538Srpaulo if (rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR)) { 686251538Srpaulo /* 687251538Srpaulo * This should not happen since we setup our Rx filter 688251538Srpaulo * to not receive these frames. 689251538Srpaulo */ 690287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 691251538Srpaulo return (NULL); 692251538Srpaulo } 693290022Savos if (pktlen < sizeof(struct ieee80211_frame_ack) || 694290022Savos pktlen > MCLBYTES) { 695287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 696271303Skevlo return (NULL); 697271303Skevlo } 698251538Srpaulo 699251538Srpaulo rate = MS(rxdw3, R92C_RXDW3_RATE); 700251538Srpaulo infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; 701251538Srpaulo 702251538Srpaulo /* Get RSSI from PHY status descriptor if present. */ 703251538Srpaulo if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { 704281069Srpaulo if (sc->chip & URTWN_CHIP_88E) 705264912Skevlo rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]); 706264912Skevlo else 707264912Skevlo rssi = urtwn_get_rssi(sc, rate, &stat[1]); 708251538Srpaulo /* Update our average RSSI. */ 709251538Srpaulo urtwn_update_avgrssi(sc, rate, rssi); 710251538Srpaulo } 711251538Srpaulo 712260463Skevlo m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 713251538Srpaulo if (m == NULL) { 714251538Srpaulo device_printf(sc->sc_dev, "could not create RX mbuf\n"); 715251538Srpaulo return (NULL); 716251538Srpaulo } 717251538Srpaulo 718251538Srpaulo /* Finalize mbuf. */ 719251538Srpaulo wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz); 720251538Srpaulo memcpy(mtod(m, uint8_t *), wh, pktlen); 721251538Srpaulo m->m_pkthdr.len = m->m_len = pktlen; 722251538Srpaulo 723251538Srpaulo if (ieee80211_radiotap_active(ic)) { 724251538Srpaulo struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap; 725251538Srpaulo 726251538Srpaulo tap->wr_flags = 0; 727251538Srpaulo /* Map HW rate index to 802.11 rate. */ 728251538Srpaulo if (!(rxdw3 & R92C_RXDW3_HT)) { 729289758Savos tap->wr_rate = ridx2rate[rate]; 730251538Srpaulo } else if (rate >= 12) { /* MCS0~15. */ 731251538Srpaulo /* Bit 7 set means HT MCS instead of rate. */ 732251538Srpaulo tap->wr_rate = 0x80 | (rate - 12); 733251538Srpaulo } 734251538Srpaulo tap->wr_dbm_antsignal = rssi; 735289816Savos tap->wr_dbm_antnoise = URTWN_NOISE_FLOOR; 736251538Srpaulo tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); 737251538Srpaulo tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 738251538Srpaulo } 739251538Srpaulo 740251538Srpaulo *rssi_p = rssi; 741251538Srpaulo 742251538Srpaulo return (m); 743251538Srpaulo} 744251538Srpaulo 745251538Srpaulostatic struct mbuf * 746251538Srpaulourtwn_rxeof(struct usb_xfer *xfer, struct urtwn_data *data, int *rssi, 747251538Srpaulo int8_t *nf) 748251538Srpaulo{ 749251538Srpaulo struct urtwn_softc *sc = data->sc; 750287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 751251538Srpaulo struct r92c_rx_stat *stat; 752251538Srpaulo struct mbuf *m, *m0 = NULL, *prevm = NULL; 753251538Srpaulo uint32_t rxdw0; 754251538Srpaulo uint8_t *buf; 755251538Srpaulo int len, totlen, pktlen, infosz, npkts; 756251538Srpaulo 757251538Srpaulo usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 758251538Srpaulo 759251538Srpaulo if (len < sizeof(*stat)) { 760287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 761251538Srpaulo return (NULL); 762251538Srpaulo } 763251538Srpaulo 764251538Srpaulo buf = data->buf; 765251538Srpaulo /* Get the number of encapsulated frames. */ 766251538Srpaulo stat = (struct r92c_rx_stat *)buf; 767251538Srpaulo npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); 768251538Srpaulo DPRINTFN(6, "Rx %d frames in one chunk\n", npkts); 769251538Srpaulo 770251538Srpaulo /* Process all of them. */ 771251538Srpaulo while (npkts-- > 0) { 772251538Srpaulo if (len < sizeof(*stat)) 773251538Srpaulo break; 774251538Srpaulo stat = (struct r92c_rx_stat *)buf; 775251538Srpaulo rxdw0 = le32toh(stat->rxdw0); 776251538Srpaulo 777251538Srpaulo pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); 778251538Srpaulo if (pktlen == 0) 779251538Srpaulo break; 780251538Srpaulo 781251538Srpaulo infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; 782251538Srpaulo 783251538Srpaulo /* Make sure everything fits in xfer. */ 784251538Srpaulo totlen = sizeof(*stat) + infosz + pktlen; 785251538Srpaulo if (totlen > len) 786251538Srpaulo break; 787251538Srpaulo 788251538Srpaulo m = urtwn_rx_frame(sc, buf, pktlen, rssi); 789251538Srpaulo if (m0 == NULL) 790251538Srpaulo m0 = m; 791251538Srpaulo if (prevm == NULL) 792251538Srpaulo prevm = m; 793251538Srpaulo else { 794251538Srpaulo prevm->m_next = m; 795251538Srpaulo prevm = m; 796251538Srpaulo } 797251538Srpaulo 798251538Srpaulo /* Next chunk is 128-byte aligned. */ 799251538Srpaulo totlen = (totlen + 127) & ~127; 800251538Srpaulo buf += totlen; 801251538Srpaulo len -= totlen; 802251538Srpaulo } 803251538Srpaulo 804251538Srpaulo return (m0); 805251538Srpaulo} 806251538Srpaulo 807251538Srpaulostatic void 808251538Srpaulourtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) 809251538Srpaulo{ 810251538Srpaulo struct urtwn_softc *sc = usbd_xfer_softc(xfer); 811287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 812290022Savos struct ieee80211_frame_min *wh; 813251538Srpaulo struct ieee80211_node *ni; 814251538Srpaulo struct mbuf *m = NULL, *next; 815251538Srpaulo struct urtwn_data *data; 816251538Srpaulo int8_t nf; 817251538Srpaulo int rssi = 1; 818251538Srpaulo 819251538Srpaulo URTWN_ASSERT_LOCKED(sc); 820251538Srpaulo 821251538Srpaulo switch (USB_GET_STATE(xfer)) { 822251538Srpaulo case USB_ST_TRANSFERRED: 823251538Srpaulo data = STAILQ_FIRST(&sc->sc_rx_active); 824251538Srpaulo if (data == NULL) 825251538Srpaulo goto tr_setup; 826251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 827251538Srpaulo m = urtwn_rxeof(xfer, data, &rssi, &nf); 828251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 829251538Srpaulo /* FALLTHROUGH */ 830251538Srpaulo case USB_ST_SETUP: 831251538Srpaulotr_setup: 832251538Srpaulo data = STAILQ_FIRST(&sc->sc_rx_inactive); 833251538Srpaulo if (data == NULL) { 834251538Srpaulo KASSERT(m == NULL, ("mbuf isn't NULL")); 835251538Srpaulo return; 836251538Srpaulo } 837251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next); 838251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next); 839251538Srpaulo usbd_xfer_set_frame_data(xfer, 0, data->buf, 840251538Srpaulo usbd_xfer_max_len(xfer)); 841251538Srpaulo usbd_transfer_submit(xfer); 842251538Srpaulo 843251538Srpaulo /* 844251538Srpaulo * To avoid LOR we should unlock our private mutex here to call 845251538Srpaulo * ieee80211_input() because here is at the end of a USB 846251538Srpaulo * callback and safe to unlock. 847251538Srpaulo */ 848251538Srpaulo URTWN_UNLOCK(sc); 849251538Srpaulo while (m != NULL) { 850251538Srpaulo next = m->m_next; 851251538Srpaulo m->m_next = NULL; 852290022Savos wh = mtod(m, struct ieee80211_frame_min *); 853290022Savos if (m->m_len >= sizeof(*wh)) 854290022Savos ni = ieee80211_find_rxnode(ic, wh); 855290022Savos else 856290022Savos ni = NULL; 857251538Srpaulo nf = URTWN_NOISE_FLOOR; 858251538Srpaulo if (ni != NULL) { 859289799Savos (void)ieee80211_input(ni, m, rssi - nf, nf); 860251538Srpaulo ieee80211_free_node(ni); 861289799Savos } else { 862289799Savos (void)ieee80211_input_all(ic, m, rssi - nf, 863289799Savos nf); 864289799Savos } 865251538Srpaulo m = next; 866251538Srpaulo } 867251538Srpaulo URTWN_LOCK(sc); 868251538Srpaulo break; 869251538Srpaulo default: 870251538Srpaulo /* needs it to the inactive queue due to a error. */ 871251538Srpaulo data = STAILQ_FIRST(&sc->sc_rx_active); 872251538Srpaulo if (data != NULL) { 873251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); 874251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); 875251538Srpaulo } 876251538Srpaulo if (error != USB_ERR_CANCELLED) { 877251538Srpaulo usbd_xfer_set_stall(xfer); 878287197Sglebius counter_u64_add(ic->ic_ierrors, 1); 879251538Srpaulo goto tr_setup; 880251538Srpaulo } 881251538Srpaulo break; 882251538Srpaulo } 883251538Srpaulo} 884251538Srpaulo 885251538Srpaulostatic void 886289891Savosurtwn_txeof(struct urtwn_softc *sc, struct urtwn_data *data, int status) 887251538Srpaulo{ 888251538Srpaulo 889251538Srpaulo URTWN_ASSERT_LOCKED(sc); 890289891Savos 891290631Savos if (data->ni != NULL) /* not a beacon frame */ 892290631Savos ieee80211_tx_complete(data->ni, data->m, status); 893289891Savos 894287197Sglebius data->ni = NULL; 895287197Sglebius data->m = NULL; 896289891Savos 897251538Srpaulo sc->sc_txtimer = 0; 898289891Savos 899289891Savos STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); 900251538Srpaulo} 901251538Srpaulo 902289066Skevlostatic int 903289066Skevlourtwn_alloc_list(struct urtwn_softc *sc, struct urtwn_data data[], 904289066Skevlo int ndata, int maxsz) 905289066Skevlo{ 906289066Skevlo int i, error; 907289066Skevlo 908289066Skevlo for (i = 0; i < ndata; i++) { 909289066Skevlo struct urtwn_data *dp = &data[i]; 910289066Skevlo dp->sc = sc; 911289066Skevlo dp->m = NULL; 912289066Skevlo dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); 913289066Skevlo if (dp->buf == NULL) { 914289066Skevlo device_printf(sc->sc_dev, 915289066Skevlo "could not allocate buffer\n"); 916289066Skevlo error = ENOMEM; 917289066Skevlo goto fail; 918289066Skevlo } 919289066Skevlo dp->ni = NULL; 920289066Skevlo } 921289066Skevlo 922289066Skevlo return (0); 923289066Skevlofail: 924289066Skevlo urtwn_free_list(sc, data, ndata); 925289066Skevlo return (error); 926289066Skevlo} 927289066Skevlo 928289066Skevlostatic int 929289066Skevlourtwn_alloc_rx_list(struct urtwn_softc *sc) 930289066Skevlo{ 931289066Skevlo int error, i; 932289066Skevlo 933289066Skevlo error = urtwn_alloc_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT, 934289066Skevlo URTWN_RXBUFSZ); 935289066Skevlo if (error != 0) 936289066Skevlo return (error); 937289066Skevlo 938289066Skevlo STAILQ_INIT(&sc->sc_rx_active); 939289066Skevlo STAILQ_INIT(&sc->sc_rx_inactive); 940289066Skevlo 941289066Skevlo for (i = 0; i < URTWN_RX_LIST_COUNT; i++) 942289066Skevlo STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next); 943289066Skevlo 944289066Skevlo return (0); 945289066Skevlo} 946289066Skevlo 947289066Skevlostatic int 948289066Skevlourtwn_alloc_tx_list(struct urtwn_softc *sc) 949289066Skevlo{ 950289066Skevlo int error, i; 951289066Skevlo 952289066Skevlo error = urtwn_alloc_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT, 953289066Skevlo URTWN_TXBUFSZ); 954289066Skevlo if (error != 0) 955289066Skevlo return (error); 956289066Skevlo 957289066Skevlo STAILQ_INIT(&sc->sc_tx_active); 958289066Skevlo STAILQ_INIT(&sc->sc_tx_inactive); 959289066Skevlo STAILQ_INIT(&sc->sc_tx_pending); 960289066Skevlo 961289066Skevlo for (i = 0; i < URTWN_TX_LIST_COUNT; i++) 962289066Skevlo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next); 963289066Skevlo 964289066Skevlo return (0); 965289066Skevlo} 966289066Skevlo 967251538Srpaulostatic void 968289066Skevlourtwn_free_list(struct urtwn_softc *sc, struct urtwn_data data[], int ndata) 969289066Skevlo{ 970289066Skevlo int i; 971289066Skevlo 972289066Skevlo for (i = 0; i < ndata; i++) { 973289066Skevlo struct urtwn_data *dp = &data[i]; 974289066Skevlo 975289066Skevlo if (dp->buf != NULL) { 976289066Skevlo free(dp->buf, M_USBDEV); 977289066Skevlo dp->buf = NULL; 978289066Skevlo } 979289066Skevlo if (dp->ni != NULL) { 980289066Skevlo ieee80211_free_node(dp->ni); 981289066Skevlo dp->ni = NULL; 982289066Skevlo } 983289066Skevlo } 984289066Skevlo} 985289066Skevlo 986289066Skevlostatic void 987289066Skevlourtwn_free_rx_list(struct urtwn_softc *sc) 988289066Skevlo{ 989289066Skevlo urtwn_free_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT); 990289066Skevlo} 991289066Skevlo 992289066Skevlostatic void 993289066Skevlourtwn_free_tx_list(struct urtwn_softc *sc) 994289066Skevlo{ 995289066Skevlo urtwn_free_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT); 996289066Skevlo} 997289066Skevlo 998289066Skevlostatic void 999251538Srpaulourtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) 1000251538Srpaulo{ 1001251538Srpaulo struct urtwn_softc *sc = usbd_xfer_softc(xfer); 1002251538Srpaulo struct urtwn_data *data; 1003251538Srpaulo 1004251538Srpaulo URTWN_ASSERT_LOCKED(sc); 1005251538Srpaulo 1006251538Srpaulo switch (USB_GET_STATE(xfer)){ 1007251538Srpaulo case USB_ST_TRANSFERRED: 1008251538Srpaulo data = STAILQ_FIRST(&sc->sc_tx_active); 1009251538Srpaulo if (data == NULL) 1010251538Srpaulo goto tr_setup; 1011251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); 1012289891Savos urtwn_txeof(sc, data, 0); 1013251538Srpaulo /* FALLTHROUGH */ 1014251538Srpaulo case USB_ST_SETUP: 1015251538Srpaulotr_setup: 1016251538Srpaulo data = STAILQ_FIRST(&sc->sc_tx_pending); 1017251538Srpaulo if (data == NULL) { 1018251538Srpaulo DPRINTF("%s: empty pending queue\n", __func__); 1019288353Sadrian goto finish; 1020251538Srpaulo } 1021251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); 1022251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); 1023251538Srpaulo usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); 1024251538Srpaulo usbd_transfer_submit(xfer); 1025251538Srpaulo break; 1026251538Srpaulo default: 1027251538Srpaulo data = STAILQ_FIRST(&sc->sc_tx_active); 1028251538Srpaulo if (data == NULL) 1029251538Srpaulo goto tr_setup; 1030289891Savos STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); 1031289891Savos urtwn_txeof(sc, data, 1); 1032251538Srpaulo if (error != USB_ERR_CANCELLED) { 1033251538Srpaulo usbd_xfer_set_stall(xfer); 1034251538Srpaulo goto tr_setup; 1035251538Srpaulo } 1036251538Srpaulo break; 1037251538Srpaulo } 1038288353Sadrianfinish: 1039288353Sadrian /* Kick-start more transmit */ 1040288353Sadrian urtwn_start(sc); 1041251538Srpaulo} 1042251538Srpaulo 1043251538Srpaulostatic struct urtwn_data * 1044251538Srpaulo_urtwn_getbuf(struct urtwn_softc *sc) 1045251538Srpaulo{ 1046251538Srpaulo struct urtwn_data *bf; 1047251538Srpaulo 1048251538Srpaulo bf = STAILQ_FIRST(&sc->sc_tx_inactive); 1049251538Srpaulo if (bf != NULL) 1050251538Srpaulo STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); 1051251538Srpaulo else 1052251538Srpaulo DPRINTF("%s: %s\n", __func__, "out of xmit buffers"); 1053251538Srpaulo return (bf); 1054251538Srpaulo} 1055251538Srpaulo 1056251538Srpaulostatic struct urtwn_data * 1057251538Srpaulourtwn_getbuf(struct urtwn_softc *sc) 1058251538Srpaulo{ 1059251538Srpaulo struct urtwn_data *bf; 1060251538Srpaulo 1061251538Srpaulo URTWN_ASSERT_LOCKED(sc); 1062251538Srpaulo 1063251538Srpaulo bf = _urtwn_getbuf(sc); 1064287197Sglebius if (bf == NULL) 1065251538Srpaulo DPRINTF("%s: stop queue\n", __func__); 1066251538Srpaulo return (bf); 1067251538Srpaulo} 1068251538Srpaulo 1069291698Savosstatic usb_error_t 1070251538Srpaulourtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, 1071251538Srpaulo int len) 1072251538Srpaulo{ 1073251538Srpaulo usb_device_request_t req; 1074251538Srpaulo 1075251538Srpaulo req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1076251538Srpaulo req.bRequest = R92C_REQ_REGS; 1077251538Srpaulo USETW(req.wValue, addr); 1078251538Srpaulo USETW(req.wIndex, 0); 1079251538Srpaulo USETW(req.wLength, len); 1080251538Srpaulo return (urtwn_do_request(sc, &req, buf)); 1081251538Srpaulo} 1082251538Srpaulo 1083291698Savosstatic usb_error_t 1084251538Srpaulourtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val) 1085251538Srpaulo{ 1086291698Savos return (urtwn_write_region_1(sc, addr, &val, sizeof(val))); 1087251538Srpaulo} 1088251538Srpaulo 1089291698Savosstatic usb_error_t 1090251538Srpaulourtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val) 1091251538Srpaulo{ 1092251538Srpaulo val = htole16(val); 1093291698Savos return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); 1094251538Srpaulo} 1095251538Srpaulo 1096291698Savosstatic usb_error_t 1097251538Srpaulourtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val) 1098251538Srpaulo{ 1099251538Srpaulo val = htole32(val); 1100291698Savos return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); 1101251538Srpaulo} 1102251538Srpaulo 1103291698Savosstatic usb_error_t 1104251538Srpaulourtwn_read_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, 1105251538Srpaulo int len) 1106251538Srpaulo{ 1107251538Srpaulo usb_device_request_t req; 1108251538Srpaulo 1109251538Srpaulo req.bmRequestType = UT_READ_VENDOR_DEVICE; 1110251538Srpaulo req.bRequest = R92C_REQ_REGS; 1111251538Srpaulo USETW(req.wValue, addr); 1112251538Srpaulo USETW(req.wIndex, 0); 1113251538Srpaulo USETW(req.wLength, len); 1114251538Srpaulo return (urtwn_do_request(sc, &req, buf)); 1115251538Srpaulo} 1116251538Srpaulo 1117251538Srpaulostatic uint8_t 1118251538Srpaulourtwn_read_1(struct urtwn_softc *sc, uint16_t addr) 1119251538Srpaulo{ 1120251538Srpaulo uint8_t val; 1121251538Srpaulo 1122251538Srpaulo if (urtwn_read_region_1(sc, addr, &val, 1) != 0) 1123251538Srpaulo return (0xff); 1124251538Srpaulo return (val); 1125251538Srpaulo} 1126251538Srpaulo 1127251538Srpaulostatic uint16_t 1128251538Srpaulourtwn_read_2(struct urtwn_softc *sc, uint16_t addr) 1129251538Srpaulo{ 1130251538Srpaulo uint16_t val; 1131251538Srpaulo 1132251538Srpaulo if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) 1133251538Srpaulo return (0xffff); 1134251538Srpaulo return (le16toh(val)); 1135251538Srpaulo} 1136251538Srpaulo 1137251538Srpaulostatic uint32_t 1138251538Srpaulourtwn_read_4(struct urtwn_softc *sc, uint16_t addr) 1139251538Srpaulo{ 1140251538Srpaulo uint32_t val; 1141251538Srpaulo 1142251538Srpaulo if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) 1143251538Srpaulo return (0xffffffff); 1144251538Srpaulo return (le32toh(val)); 1145251538Srpaulo} 1146251538Srpaulo 1147251538Srpaulostatic int 1148251538Srpaulourtwn_fw_cmd(struct urtwn_softc *sc, uint8_t id, const void *buf, int len) 1149251538Srpaulo{ 1150251538Srpaulo struct r92c_fw_cmd cmd; 1151291698Savos usb_error_t error; 1152251538Srpaulo int ntries; 1153251538Srpaulo 1154251538Srpaulo /* Wait for current FW box to be empty. */ 1155251538Srpaulo for (ntries = 0; ntries < 100; ntries++) { 1156251538Srpaulo if (!(urtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) 1157251538Srpaulo break; 1158266472Shselasky urtwn_ms_delay(sc); 1159251538Srpaulo } 1160251538Srpaulo if (ntries == 100) { 1161251538Srpaulo device_printf(sc->sc_dev, 1162251538Srpaulo "could not send firmware command\n"); 1163251538Srpaulo return (ETIMEDOUT); 1164251538Srpaulo } 1165251538Srpaulo memset(&cmd, 0, sizeof(cmd)); 1166251538Srpaulo cmd.id = id; 1167251538Srpaulo if (len > 3) 1168251538Srpaulo cmd.id |= R92C_CMD_FLAG_EXT; 1169251538Srpaulo KASSERT(len <= sizeof(cmd.msg), ("urtwn_fw_cmd\n")); 1170251538Srpaulo memcpy(cmd.msg, buf, len); 1171251538Srpaulo 1172251538Srpaulo /* Write the first word last since that will trigger the FW. */ 1173291698Savos error = urtwn_write_region_1(sc, R92C_HMEBOX_EXT(sc->fwcur), 1174251538Srpaulo (uint8_t *)&cmd + 4, 2); 1175291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1176291698Savos return (EIO); 1177291698Savos error = urtwn_write_region_1(sc, R92C_HMEBOX(sc->fwcur), 1178251538Srpaulo (uint8_t *)&cmd + 0, 4); 1179291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1180291698Savos return (EIO); 1181251538Srpaulo 1182251538Srpaulo sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; 1183251538Srpaulo return (0); 1184251538Srpaulo} 1185251538Srpaulo 1186264912Skevlostatic __inline void 1187251538Srpaulourtwn_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, uint32_t val) 1188251538Srpaulo{ 1189264912Skevlo 1190264912Skevlo sc->sc_rf_write(sc, chain, addr, val); 1191264912Skevlo} 1192264912Skevlo 1193264912Skevlostatic void 1194264912Skevlourtwn_r92c_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, 1195264912Skevlo uint32_t val) 1196264912Skevlo{ 1197251538Srpaulo urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), 1198251538Srpaulo SM(R92C_LSSI_PARAM_ADDR, addr) | 1199251538Srpaulo SM(R92C_LSSI_PARAM_DATA, val)); 1200251538Srpaulo} 1201251538Srpaulo 1202264912Skevlostatic void 1203264912Skevlourtwn_r88e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, 1204264912Skevlouint32_t val) 1205264912Skevlo{ 1206264912Skevlo urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), 1207264912Skevlo SM(R88E_LSSI_PARAM_ADDR, addr) | 1208264912Skevlo SM(R92C_LSSI_PARAM_DATA, val)); 1209264912Skevlo} 1210264912Skevlo 1211251538Srpaulostatic uint32_t 1212251538Srpaulourtwn_rf_read(struct urtwn_softc *sc, int chain, uint8_t addr) 1213251538Srpaulo{ 1214251538Srpaulo uint32_t reg[R92C_MAX_CHAINS], val; 1215251538Srpaulo 1216251538Srpaulo reg[0] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); 1217251538Srpaulo if (chain != 0) 1218251538Srpaulo reg[chain] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); 1219251538Srpaulo 1220251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), 1221251538Srpaulo reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); 1222266472Shselasky urtwn_ms_delay(sc); 1223251538Srpaulo 1224251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), 1225251538Srpaulo RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | 1226251538Srpaulo R92C_HSSI_PARAM2_READ_EDGE); 1227266472Shselasky urtwn_ms_delay(sc); 1228251538Srpaulo 1229251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), 1230251538Srpaulo reg[0] | R92C_HSSI_PARAM2_READ_EDGE); 1231266472Shselasky urtwn_ms_delay(sc); 1232251538Srpaulo 1233251538Srpaulo if (urtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) 1234251538Srpaulo val = urtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); 1235251538Srpaulo else 1236251538Srpaulo val = urtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); 1237251538Srpaulo return (MS(val, R92C_LSSI_READBACK_DATA)); 1238251538Srpaulo} 1239251538Srpaulo 1240251538Srpaulostatic int 1241251538Srpaulourtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data) 1242251538Srpaulo{ 1243291698Savos usb_error_t error; 1244251538Srpaulo int ntries; 1245251538Srpaulo 1246291698Savos error = urtwn_write_4(sc, R92C_LLT_INIT, 1247251538Srpaulo SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | 1248251538Srpaulo SM(R92C_LLT_INIT_ADDR, addr) | 1249251538Srpaulo SM(R92C_LLT_INIT_DATA, data)); 1250291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1251291698Savos return (EIO); 1252251538Srpaulo /* Wait for write operation to complete. */ 1253251538Srpaulo for (ntries = 0; ntries < 20; ntries++) { 1254251538Srpaulo if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == 1255251538Srpaulo R92C_LLT_INIT_OP_NO_ACTIVE) 1256251538Srpaulo return (0); 1257266472Shselasky urtwn_ms_delay(sc); 1258251538Srpaulo } 1259251538Srpaulo return (ETIMEDOUT); 1260251538Srpaulo} 1261251538Srpaulo 1262291264Savosstatic int 1263291264Savosurtwn_efuse_read_next(struct urtwn_softc *sc, uint8_t *val) 1264251538Srpaulo{ 1265251538Srpaulo uint32_t reg; 1266291698Savos usb_error_t error; 1267251538Srpaulo int ntries; 1268251538Srpaulo 1269291264Savos if (sc->last_rom_addr >= URTWN_EFUSE_MAX_LEN) 1270291264Savos return (EFAULT); 1271291264Savos 1272251538Srpaulo reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); 1273291264Savos reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->last_rom_addr); 1274251538Srpaulo reg &= ~R92C_EFUSE_CTRL_VALID; 1275291264Savos 1276291698Savos error = urtwn_write_4(sc, R92C_EFUSE_CTRL, reg); 1277291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1278291698Savos return (EIO); 1279251538Srpaulo /* Wait for read operation to complete. */ 1280251538Srpaulo for (ntries = 0; ntries < 100; ntries++) { 1281251538Srpaulo reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); 1282251538Srpaulo if (reg & R92C_EFUSE_CTRL_VALID) 1283291264Savos break; 1284266472Shselasky urtwn_ms_delay(sc); 1285251538Srpaulo } 1286291264Savos if (ntries == 100) { 1287291264Savos device_printf(sc->sc_dev, 1288291264Savos "could not read efuse byte at address 0x%x\n", 1289291264Savos sc->last_rom_addr); 1290291264Savos return (ETIMEDOUT); 1291291264Savos } 1292291264Savos 1293291264Savos *val = MS(reg, R92C_EFUSE_CTRL_DATA); 1294291264Savos sc->last_rom_addr++; 1295291264Savos 1296291264Savos return (0); 1297251538Srpaulo} 1298251538Srpaulo 1299291264Savosstatic int 1300291264Savosurtwn_efuse_read_data(struct urtwn_softc *sc, uint8_t *rom, uint8_t off, 1301291264Savos uint8_t msk) 1302291264Savos{ 1303291264Savos uint8_t reg; 1304291264Savos int i, error; 1305291264Savos 1306291264Savos for (i = 0; i < 4; i++) { 1307291264Savos if (msk & (1 << i)) 1308291264Savos continue; 1309291264Savos error = urtwn_efuse_read_next(sc, ®); 1310291264Savos if (error != 0) 1311291264Savos return (error); 1312291264Savos DPRINTF("rom[0x%03X] == 0x%02X\n", off * 8 + i * 2, reg); 1313291264Savos rom[off * 8 + i * 2 + 0] = reg; 1314291264Savos 1315291264Savos error = urtwn_efuse_read_next(sc, ®); 1316291264Savos if (error != 0) 1317291264Savos return (error); 1318291264Savos DPRINTF("rom[0x%03X] == 0x%02X\n", off * 8 + i * 2 + 1, reg); 1319291264Savos rom[off * 8 + i * 2 + 1] = reg; 1320291264Savos } 1321291264Savos 1322291264Savos return (0); 1323291264Savos} 1324291264Savos 1325291264Savos#ifdef URTWN_DEBUG 1326251538Srpaulostatic void 1327291264Savosurtwn_dump_rom_contents(struct urtwn_softc *sc, uint8_t *rom, uint16_t size) 1328251538Srpaulo{ 1329251538Srpaulo int i; 1330251538Srpaulo 1331291264Savos /* Dump ROM contents. */ 1332291264Savos device_printf(sc->sc_dev, "%s:", __func__); 1333291264Savos for (i = 0; i < size; i++) { 1334291264Savos if (i % 32 == 0) 1335291264Savos printf("\n%03X: ", i); 1336291264Savos else if (i % 4 == 0) 1337291264Savos printf(" "); 1338291264Savos 1339291264Savos printf("%02X", rom[i]); 1340291264Savos } 1341291264Savos printf("\n"); 1342291264Savos} 1343291264Savos#endif 1344291264Savos 1345291264Savosstatic int 1346291264Savosurtwn_efuse_read(struct urtwn_softc *sc, uint8_t *rom, uint16_t size) 1347291264Savos{ 1348291264Savos#define URTWN_CHK(res) do { \ 1349291264Savos if ((error = res) != 0) \ 1350291264Savos goto end; \ 1351291264Savos} while(0) 1352291264Savos uint8_t msk, off, reg; 1353291264Savos int error; 1354291264Savos 1355291698Savos URTWN_CHK(urtwn_efuse_switch_power(sc)); 1356264912Skevlo 1357291264Savos /* Read full ROM image. */ 1358291264Savos sc->last_rom_addr = 0; 1359291264Savos memset(rom, 0xff, size); 1360291264Savos 1361291264Savos URTWN_CHK(urtwn_efuse_read_next(sc, ®)); 1362291264Savos while (reg != 0xff) { 1363291264Savos /* check for extended header */ 1364291264Savos if ((sc->chip & URTWN_CHIP_88E) && (reg & 0x1f) == 0x0f) { 1365291264Savos off = reg >> 5; 1366291264Savos URTWN_CHK(urtwn_efuse_read_next(sc, ®)); 1367291264Savos 1368291264Savos if ((reg & 0x0f) != 0x0f) 1369291264Savos off = ((reg & 0xf0) >> 1) | off; 1370291264Savos else 1371291264Savos continue; 1372291264Savos } else 1373291264Savos off = reg >> 4; 1374251538Srpaulo msk = reg & 0xf; 1375291264Savos 1376291264Savos URTWN_CHK(urtwn_efuse_read_data(sc, rom, off, msk)); 1377291264Savos URTWN_CHK(urtwn_efuse_read_next(sc, ®)); 1378251538Srpaulo } 1379291264Savos 1380291264Savosend: 1381291264Savos 1382251538Srpaulo#ifdef URTWN_DEBUG 1383291264Savos if (urtwn_debug >= 2) 1384291264Savos urtwn_dump_rom_contents(sc, rom, size); 1385251538Srpaulo#endif 1386291264Savos 1387282623Skevlo urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF); 1388291264Savos 1389291264Savos if (error != 0) { 1390291264Savos device_printf(sc->sc_dev, "%s: error while reading ROM\n", 1391291264Savos __func__); 1392291264Savos } 1393291264Savos 1394291264Savos return (error); 1395291264Savos#undef URTWN_CHK 1396282623Skevlo} 1397281592Skevlo 1398291698Savosstatic int 1399264912Skevlourtwn_efuse_switch_power(struct urtwn_softc *sc) 1400264912Skevlo{ 1401291698Savos usb_error_t error; 1402264912Skevlo uint32_t reg; 1403251538Srpaulo 1404291698Savos error = urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON); 1405291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1406291698Savos return (EIO); 1407281918Skevlo 1408264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL); 1409264912Skevlo if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) { 1410291698Savos error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL, 1411264912Skevlo reg | R92C_SYS_ISO_CTRL_PWC_EV12V); 1412291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1413291698Savos return (EIO); 1414264912Skevlo } 1415264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); 1416264912Skevlo if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { 1417291698Savos error = urtwn_write_2(sc, R92C_SYS_FUNC_EN, 1418264912Skevlo reg | R92C_SYS_FUNC_EN_ELDR); 1419291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1420291698Savos return (EIO); 1421264912Skevlo } 1422264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_CLKR); 1423264912Skevlo if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != 1424264912Skevlo (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { 1425291698Savos error = urtwn_write_2(sc, R92C_SYS_CLKR, 1426264912Skevlo reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); 1427291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 1428291698Savos return (EIO); 1429264912Skevlo } 1430291698Savos 1431291698Savos return (0); 1432264912Skevlo} 1433264912Skevlo 1434251538Srpaulostatic int 1435251538Srpaulourtwn_read_chipid(struct urtwn_softc *sc) 1436251538Srpaulo{ 1437251538Srpaulo uint32_t reg; 1438251538Srpaulo 1439264912Skevlo if (sc->chip & URTWN_CHIP_88E) 1440264912Skevlo return (0); 1441264912Skevlo 1442251538Srpaulo reg = urtwn_read_4(sc, R92C_SYS_CFG); 1443251538Srpaulo if (reg & R92C_SYS_CFG_TRP_VAUX_EN) 1444251538Srpaulo return (EIO); 1445251538Srpaulo 1446251538Srpaulo if (reg & R92C_SYS_CFG_TYPE_92C) { 1447251538Srpaulo sc->chip |= URTWN_CHIP_92C; 1448251538Srpaulo /* Check if it is a castrated 8192C. */ 1449251538Srpaulo if (MS(urtwn_read_4(sc, R92C_HPON_FSM), 1450251538Srpaulo R92C_HPON_FSM_CHIP_BONDING_ID) == 1451251538Srpaulo R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) 1452251538Srpaulo sc->chip |= URTWN_CHIP_92C_1T2R; 1453251538Srpaulo } 1454251538Srpaulo if (reg & R92C_SYS_CFG_VENDOR_UMC) { 1455251538Srpaulo sc->chip |= URTWN_CHIP_UMC; 1456251538Srpaulo if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) 1457251538Srpaulo sc->chip |= URTWN_CHIP_UMC_A_CUT; 1458251538Srpaulo } 1459251538Srpaulo return (0); 1460251538Srpaulo} 1461251538Srpaulo 1462291264Savosstatic int 1463251538Srpaulourtwn_read_rom(struct urtwn_softc *sc) 1464251538Srpaulo{ 1465291264Savos struct r92c_rom *rom = &sc->rom.r92c_rom; 1466291264Savos int error; 1467251538Srpaulo 1468251538Srpaulo /* Read full ROM image. */ 1469291264Savos error = urtwn_efuse_read(sc, (uint8_t *)rom, sizeof(*rom)); 1470291264Savos if (error != 0) 1471291264Savos return (error); 1472251538Srpaulo 1473251538Srpaulo /* XXX Weird but this is what the vendor driver does. */ 1474291264Savos sc->last_rom_addr = 0x1fa; 1475291264Savos error = urtwn_efuse_read_next(sc, &sc->pa_setting); 1476291264Savos if (error != 0) 1477291264Savos return (error); 1478251538Srpaulo DPRINTF("PA setting=0x%x\n", sc->pa_setting); 1479251538Srpaulo 1480251538Srpaulo sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); 1481251538Srpaulo 1482251538Srpaulo sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); 1483251538Srpaulo DPRINTF("regulatory type=%d\n", sc->regulatory); 1484287197Sglebius IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); 1485251538Srpaulo 1486264912Skevlo sc->sc_rf_write = urtwn_r92c_rf_write; 1487264912Skevlo sc->sc_power_on = urtwn_r92c_power_on; 1488291264Savos 1489291264Savos return (0); 1490251538Srpaulo} 1491251538Srpaulo 1492291264Savosstatic int 1493264912Skevlourtwn_r88e_read_rom(struct urtwn_softc *sc) 1494264912Skevlo{ 1495291264Savos uint8_t *rom = sc->rom.r88e_rom; 1496291264Savos uint16_t addr; 1497291264Savos int error, i; 1498264912Skevlo 1499291264Savos error = urtwn_efuse_read(sc, rom, sizeof(sc->rom.r88e_rom)); 1500291264Savos if (error != 0) 1501291264Savos return (error); 1502264912Skevlo 1503264912Skevlo addr = 0x10; 1504264912Skevlo for (i = 0; i < 6; i++) 1505291264Savos sc->cck_tx_pwr[i] = rom[addr++]; 1506264912Skevlo for (i = 0; i < 5; i++) 1507291264Savos sc->ht40_tx_pwr[i] = rom[addr++]; 1508291264Savos sc->bw20_tx_pwr_diff = (rom[addr] & 0xf0) >> 4; 1509264912Skevlo if (sc->bw20_tx_pwr_diff & 0x08) 1510264912Skevlo sc->bw20_tx_pwr_diff |= 0xf0; 1511291264Savos sc->ofdm_tx_pwr_diff = (rom[addr] & 0xf); 1512264912Skevlo if (sc->ofdm_tx_pwr_diff & 0x08) 1513264912Skevlo sc->ofdm_tx_pwr_diff |= 0xf0; 1514291264Savos sc->regulatory = MS(rom[0xc1], R92C_ROM_RF1_REGULATORY); 1515291264Savos IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, &rom[0xd7]); 1516264912Skevlo 1517264912Skevlo sc->sc_rf_write = urtwn_r88e_rf_write; 1518264912Skevlo sc->sc_power_on = urtwn_r88e_power_on; 1519291264Savos 1520291264Savos return (0); 1521264912Skevlo} 1522264912Skevlo 1523251538Srpaulo/* 1524251538Srpaulo * Initialize rate adaptation in firmware. 1525251538Srpaulo */ 1526251538Srpaulostatic int 1527251538Srpaulourtwn_ra_init(struct urtwn_softc *sc) 1528251538Srpaulo{ 1529287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 1530251538Srpaulo struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1531251538Srpaulo struct ieee80211_node *ni; 1532251538Srpaulo struct ieee80211_rateset *rs; 1533251538Srpaulo struct r92c_fw_cmd_macid_cfg cmd; 1534251538Srpaulo uint32_t rates, basicrates; 1535251538Srpaulo uint8_t mode; 1536251538Srpaulo int maxrate, maxbasicrate, error, i, j; 1537251538Srpaulo 1538251538Srpaulo ni = ieee80211_ref_node(vap->iv_bss); 1539251538Srpaulo rs = &ni->ni_rates; 1540251538Srpaulo 1541251538Srpaulo /* Get normal and basic rates mask. */ 1542251538Srpaulo rates = basicrates = 0; 1543251538Srpaulo maxrate = maxbasicrate = 0; 1544251538Srpaulo for (i = 0; i < rs->rs_nrates; i++) { 1545251538Srpaulo /* Convert 802.11 rate to HW rate index. */ 1546289758Savos for (j = 0; j < nitems(ridx2rate); j++) 1547289758Savos if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == 1548289758Savos ridx2rate[j]) 1549251538Srpaulo break; 1550289758Savos if (j == nitems(ridx2rate)) /* Unknown rate, skip. */ 1551251538Srpaulo continue; 1552251538Srpaulo rates |= 1 << j; 1553251538Srpaulo if (j > maxrate) 1554251538Srpaulo maxrate = j; 1555251538Srpaulo if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) { 1556251538Srpaulo basicrates |= 1 << j; 1557251538Srpaulo if (j > maxbasicrate) 1558251538Srpaulo maxbasicrate = j; 1559251538Srpaulo } 1560251538Srpaulo } 1561251538Srpaulo if (ic->ic_curmode == IEEE80211_MODE_11B) 1562251538Srpaulo mode = R92C_RAID_11B; 1563251538Srpaulo else 1564251538Srpaulo mode = R92C_RAID_11BG; 1565251538Srpaulo DPRINTF("mode=0x%x rates=0x%08x, basicrates=0x%08x\n", 1566251538Srpaulo mode, rates, basicrates); 1567251538Srpaulo 1568251538Srpaulo /* Set rates mask for group addressed frames. */ 1569251538Srpaulo cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID; 1570251538Srpaulo cmd.mask = htole32(mode << 28 | basicrates); 1571251538Srpaulo error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); 1572251538Srpaulo if (error != 0) { 1573252401Srpaulo ieee80211_free_node(ni); 1574251538Srpaulo device_printf(sc->sc_dev, 1575251538Srpaulo "could not add broadcast station\n"); 1576251538Srpaulo return (error); 1577251538Srpaulo } 1578251538Srpaulo /* Set initial MRR rate. */ 1579251538Srpaulo DPRINTF("maxbasicrate=%d\n", maxbasicrate); 1580251538Srpaulo urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BC), 1581251538Srpaulo maxbasicrate); 1582251538Srpaulo 1583251538Srpaulo /* Set rates mask for unicast frames. */ 1584251538Srpaulo cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID; 1585251538Srpaulo cmd.mask = htole32(mode << 28 | rates); 1586251538Srpaulo error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); 1587251538Srpaulo if (error != 0) { 1588252401Srpaulo ieee80211_free_node(ni); 1589251538Srpaulo device_printf(sc->sc_dev, "could not add BSS station\n"); 1590251538Srpaulo return (error); 1591251538Srpaulo } 1592251538Srpaulo /* Set initial MRR rate. */ 1593251538Srpaulo DPRINTF("maxrate=%d\n", maxrate); 1594251538Srpaulo urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS), 1595251538Srpaulo maxrate); 1596251538Srpaulo 1597251538Srpaulo /* Indicate highest supported rate. */ 1598252403Srpaulo ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; 1599252401Srpaulo ieee80211_free_node(ni); 1600252401Srpaulo 1601251538Srpaulo return (0); 1602251538Srpaulo} 1603251538Srpaulo 1604290439Savosstatic void 1605290631Savosurtwn_init_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) 1606251538Srpaulo{ 1607290631Savos struct r92c_tx_desc *txd = &uvp->bcn_desc; 1608290631Savos 1609290631Savos txd->txdw0 = htole32( 1610290631Savos SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | R92C_TXDW0_BMCAST | 1611290631Savos R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); 1612290631Savos txd->txdw1 = htole32( 1613290631Savos SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) | 1614290631Savos SM(R92C_TXDW1_RAID, R92C_RAID_11B)); 1615290631Savos 1616291858Savos if (sc->chip & URTWN_CHIP_88E) { 1617290631Savos txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, URTWN_MACID_BC)); 1618291858Savos txd->txdseq |= htole16(R88E_TXDSEQ_HWSEQ_EN); 1619291858Savos } else { 1620290631Savos txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC)); 1621291858Savos txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); 1622291858Savos } 1623290631Savos 1624290631Savos txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); 1625290631Savos txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, URTWN_RIDX_CCK1)); 1626251538Srpaulo} 1627251538Srpaulo 1628290631Savosstatic int 1629290631Savosurtwn_setup_beacon(struct urtwn_softc *sc, struct ieee80211_node *ni) 1630290631Savos{ 1631290631Savos struct ieee80211vap *vap = ni->ni_vap; 1632290631Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1633290631Savos struct mbuf *m; 1634290631Savos int error; 1635290631Savos 1636290631Savos URTWN_ASSERT_LOCKED(sc); 1637290631Savos 1638290631Savos if (ni->ni_chan == IEEE80211_CHAN_ANYC) 1639290631Savos return (EINVAL); 1640290631Savos 1641290631Savos m = ieee80211_beacon_alloc(ni); 1642290631Savos if (m == NULL) { 1643290631Savos device_printf(sc->sc_dev, 1644290631Savos "%s: could not allocate beacon frame\n", __func__); 1645290631Savos return (ENOMEM); 1646290631Savos } 1647290631Savos 1648290631Savos if (uvp->bcn_mbuf != NULL) 1649290631Savos m_freem(uvp->bcn_mbuf); 1650290631Savos 1651290631Savos uvp->bcn_mbuf = m; 1652290631Savos 1653290631Savos if ((error = urtwn_tx_beacon(sc, uvp)) != 0) 1654290631Savos return (error); 1655290631Savos 1656290631Savos /* XXX bcnq stuck workaround */ 1657290631Savos if ((error = urtwn_tx_beacon(sc, uvp)) != 0) 1658290631Savos return (error); 1659290631Savos 1660290631Savos return (0); 1661290631Savos} 1662290631Savos 1663251538Srpaulostatic void 1664290631Savosurtwn_update_beacon(struct ieee80211vap *vap, int item) 1665290631Savos{ 1666290631Savos struct urtwn_softc *sc = vap->iv_ic->ic_softc; 1667290631Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1668290631Savos struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 1669290631Savos struct ieee80211_node *ni = vap->iv_bss; 1670290631Savos int mcast = 0; 1671290631Savos 1672290631Savos URTWN_LOCK(sc); 1673290631Savos if (uvp->bcn_mbuf == NULL) { 1674290631Savos uvp->bcn_mbuf = ieee80211_beacon_alloc(ni); 1675290631Savos if (uvp->bcn_mbuf == NULL) { 1676290631Savos device_printf(sc->sc_dev, 1677290631Savos "%s: could not allocate beacon frame\n", __func__); 1678290631Savos URTWN_UNLOCK(sc); 1679290631Savos return; 1680290631Savos } 1681290631Savos } 1682290631Savos URTWN_UNLOCK(sc); 1683290631Savos 1684290631Savos if (item == IEEE80211_BEACON_TIM) 1685290631Savos mcast = 1; /* XXX */ 1686290631Savos 1687290631Savos setbit(bo->bo_flags, item); 1688290631Savos ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast); 1689290631Savos 1690290631Savos URTWN_LOCK(sc); 1691290631Savos urtwn_tx_beacon(sc, uvp); 1692290631Savos URTWN_UNLOCK(sc); 1693290631Savos} 1694290631Savos 1695290631Savos/* 1696290631Savos * Push a beacon frame into the chip. Beacon will 1697290631Savos * be repeated by the chip every R92C_BCN_INTERVAL. 1698290631Savos */ 1699290631Savosstatic int 1700290631Savosurtwn_tx_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) 1701290631Savos{ 1702290631Savos struct r92c_tx_desc *desc = &uvp->bcn_desc; 1703290631Savos struct urtwn_data *bf; 1704290631Savos 1705290631Savos URTWN_ASSERT_LOCKED(sc); 1706290631Savos 1707290631Savos bf = urtwn_getbuf(sc); 1708290631Savos if (bf == NULL) 1709290631Savos return (ENOMEM); 1710290631Savos 1711290631Savos memcpy(bf->buf, desc, sizeof(*desc)); 1712290631Savos urtwn_tx_start(sc, uvp->bcn_mbuf, IEEE80211_FC0_TYPE_MGT, bf); 1713290631Savos 1714290631Savos sc->sc_txtimer = 5; 1715290631Savos callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 1716290631Savos 1717290631Savos return (0); 1718290631Savos} 1719290631Savos 1720290631Savosstatic void 1721290651Savosurtwn_tsf_task_adhoc(void *arg, int pending) 1722290651Savos{ 1723290651Savos struct ieee80211vap *vap = arg; 1724290651Savos struct urtwn_softc *sc = vap->iv_ic->ic_softc; 1725290651Savos struct ieee80211_node *ni; 1726290651Savos uint32_t reg; 1727290651Savos 1728290651Savos URTWN_LOCK(sc); 1729290651Savos ni = ieee80211_ref_node(vap->iv_bss); 1730290651Savos reg = urtwn_read_1(sc, R92C_BCN_CTRL); 1731290651Savos 1732290651Savos /* Accept beacons with the same BSSID. */ 1733290651Savos urtwn_set_rx_bssid_all(sc, 0); 1734290651Savos 1735290651Savos /* Enable synchronization. */ 1736290651Savos reg &= ~R92C_BCN_CTRL_DIS_TSF_UDT0; 1737290651Savos urtwn_write_1(sc, R92C_BCN_CTRL, reg); 1738290651Savos 1739290651Savos /* Synchronize. */ 1740290651Savos usb_pause_mtx(&sc->sc_mtx, hz * ni->ni_intval * 5 / 1000); 1741290651Savos 1742290651Savos /* Disable synchronization. */ 1743290651Savos reg |= R92C_BCN_CTRL_DIS_TSF_UDT0; 1744290651Savos urtwn_write_1(sc, R92C_BCN_CTRL, reg); 1745290651Savos 1746290651Savos /* Remove beacon filter. */ 1747290651Savos urtwn_set_rx_bssid_all(sc, 1); 1748290651Savos 1749290651Savos /* Enable beaconing. */ 1750290651Savos urtwn_write_1(sc, R92C_MBID_NUM, 1751290651Savos urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0); 1752290651Savos reg |= R92C_BCN_CTRL_EN_BCN; 1753290651Savos 1754290651Savos urtwn_write_1(sc, R92C_BCN_CTRL, reg); 1755290651Savos ieee80211_free_node(ni); 1756290651Savos URTWN_UNLOCK(sc); 1757290651Savos} 1758290651Savos 1759290651Savosstatic void 1760290631Savosurtwn_tsf_sync_enable(struct urtwn_softc *sc, struct ieee80211vap *vap) 1761290631Savos{ 1762290651Savos struct ieee80211com *ic = &sc->sc_ic; 1763290651Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1764290651Savos 1765290631Savos /* Reset TSF. */ 1766290631Savos urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); 1767290631Savos 1768290631Savos switch (vap->iv_opmode) { 1769290631Savos case IEEE80211_M_STA: 1770290631Savos /* Enable TSF synchronization. */ 1771290631Savos urtwn_write_1(sc, R92C_BCN_CTRL, 1772290631Savos urtwn_read_1(sc, R92C_BCN_CTRL) & 1773290631Savos ~R92C_BCN_CTRL_DIS_TSF_UDT0); 1774290631Savos break; 1775290651Savos case IEEE80211_M_IBSS: 1776290651Savos ieee80211_runtask(ic, &uvp->tsf_task_adhoc); 1777290651Savos break; 1778290631Savos case IEEE80211_M_HOSTAP: 1779290631Savos /* Enable beaconing. */ 1780290631Savos urtwn_write_1(sc, R92C_MBID_NUM, 1781290631Savos urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0); 1782290631Savos urtwn_write_1(sc, R92C_BCN_CTRL, 1783290631Savos urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); 1784290631Savos break; 1785290631Savos default: 1786290631Savos device_printf(sc->sc_dev, "undefined opmode %d\n", 1787290631Savos vap->iv_opmode); 1788290631Savos return; 1789290631Savos } 1790290631Savos} 1791290631Savos 1792290631Savosstatic void 1793251538Srpaulourtwn_set_led(struct urtwn_softc *sc, int led, int on) 1794251538Srpaulo{ 1795251538Srpaulo uint8_t reg; 1796281069Srpaulo 1797251538Srpaulo if (led == URTWN_LED_LINK) { 1798264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 1799264912Skevlo reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0xf0; 1800264912Skevlo urtwn_write_1(sc, R92C_LEDCFG2, reg | 0x60); 1801264912Skevlo if (!on) { 1802264912Skevlo reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0x90; 1803264912Skevlo urtwn_write_1(sc, R92C_LEDCFG2, 1804264912Skevlo reg | R92C_LEDCFG0_DIS); 1805264912Skevlo urtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 1806264912Skevlo urtwn_read_1(sc, R92C_MAC_PINMUX_CFG) & 1807264912Skevlo 0xfe); 1808264912Skevlo } 1809264912Skevlo } else { 1810264912Skevlo reg = urtwn_read_1(sc, R92C_LEDCFG0) & 0x70; 1811264912Skevlo if (!on) 1812264912Skevlo reg |= R92C_LEDCFG0_DIS; 1813264912Skevlo urtwn_write_1(sc, R92C_LEDCFG0, reg); 1814264912Skevlo } 1815264912Skevlo sc->ledlink = on; /* Save LED state. */ 1816251538Srpaulo } 1817251538Srpaulo} 1818251538Srpaulo 1819289811Savosstatic void 1820289811Savosurtwn_set_mode(struct urtwn_softc *sc, uint8_t mode) 1821289811Savos{ 1822289811Savos uint8_t reg; 1823289811Savos 1824289811Savos reg = urtwn_read_1(sc, R92C_MSR); 1825289811Savos reg = (reg & ~R92C_MSR_MASK) | mode; 1826289811Savos urtwn_write_1(sc, R92C_MSR, reg); 1827289811Savos} 1828289811Savos 1829290651Savosstatic void 1830290651Savosurtwn_ibss_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, 1831290651Savos const struct ieee80211_rx_stats *rxs, 1832290651Savos int rssi, int nf) 1833290651Savos{ 1834290651Savos struct ieee80211vap *vap = ni->ni_vap; 1835290651Savos struct urtwn_softc *sc = vap->iv_ic->ic_softc; 1836290651Savos struct urtwn_vap *uvp = URTWN_VAP(vap); 1837290651Savos uint64_t ni_tstamp, curr_tstamp; 1838290651Savos 1839290651Savos uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); 1840290651Savos 1841290651Savos if (vap->iv_state == IEEE80211_S_RUN && 1842290651Savos (subtype == IEEE80211_FC0_SUBTYPE_BEACON || 1843290651Savos subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { 1844290651Savos ni_tstamp = le64toh(ni->ni_tstamp.tsf); 1845290651Savos#ifdef D3831 1846290651Savos URTWN_LOCK(sc); 1847290651Savos urtwn_get_tsf(sc, &curr_tstamp); 1848290651Savos URTWN_UNLOCK(sc); 1849290651Savos curr_tstamp = le64toh(curr_tstamp); 1850290651Savos 1851290651Savos if (ni_tstamp >= curr_tstamp) 1852290651Savos (void) ieee80211_ibss_merge(ni); 1853290651Savos#else 1854290651Savos (void) sc; 1855290651Savos (void) curr_tstamp; 1856290651Savos#endif 1857290651Savos } 1858290651Savos} 1859290651Savos 1860251538Srpaulostatic int 1861251538Srpaulourtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1862251538Srpaulo{ 1863251538Srpaulo struct urtwn_vap *uvp = URTWN_VAP(vap); 1864251538Srpaulo struct ieee80211com *ic = vap->iv_ic; 1865286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 1866251538Srpaulo struct ieee80211_node *ni; 1867251538Srpaulo enum ieee80211_state ostate; 1868290631Savos uint32_t reg; 1869290631Savos uint8_t mode; 1870290631Savos int error = 0; 1871251538Srpaulo 1872251538Srpaulo ostate = vap->iv_state; 1873251538Srpaulo DPRINTF("%s -> %s\n", ieee80211_state_name[ostate], 1874251538Srpaulo ieee80211_state_name[nstate]); 1875251538Srpaulo 1876251538Srpaulo IEEE80211_UNLOCK(ic); 1877251538Srpaulo URTWN_LOCK(sc); 1878251538Srpaulo callout_stop(&sc->sc_watchdog_ch); 1879251538Srpaulo 1880251538Srpaulo if (ostate == IEEE80211_S_RUN) { 1881251538Srpaulo /* Turn link LED off. */ 1882251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 0); 1883251538Srpaulo 1884251538Srpaulo /* Set media status to 'No Link'. */ 1885289811Savos urtwn_set_mode(sc, R92C_MSR_NOLINK); 1886251538Srpaulo 1887251538Srpaulo /* Stop Rx of data frames. */ 1888251538Srpaulo urtwn_write_2(sc, R92C_RXFLTMAP2, 0); 1889251538Srpaulo 1890251538Srpaulo /* Disable TSF synchronization. */ 1891251538Srpaulo urtwn_write_1(sc, R92C_BCN_CTRL, 1892290631Savos (urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN) | 1893251538Srpaulo R92C_BCN_CTRL_DIS_TSF_UDT0); 1894251538Srpaulo 1895290631Savos /* Disable beaconing. */ 1896290631Savos urtwn_write_1(sc, R92C_MBID_NUM, 1897290631Savos urtwn_read_1(sc, R92C_MBID_NUM) & ~R92C_MBID_TXBCN_RPT0); 1898290631Savos 1899290631Savos /* Reset TSF. */ 1900290631Savos urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); 1901290631Savos 1902251538Srpaulo /* Reset EDCA parameters. */ 1903251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); 1904251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); 1905251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320); 1906251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444); 1907251538Srpaulo } 1908251538Srpaulo 1909251538Srpaulo switch (nstate) { 1910251538Srpaulo case IEEE80211_S_INIT: 1911251538Srpaulo /* Turn link LED off. */ 1912251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 0); 1913251538Srpaulo break; 1914251538Srpaulo case IEEE80211_S_SCAN: 1915251538Srpaulo /* Pause AC Tx queues. */ 1916251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 1917251538Srpaulo urtwn_read_1(sc, R92C_TXPAUSE) | 0x0f); 1918251538Srpaulo break; 1919251538Srpaulo case IEEE80211_S_AUTH: 1920251538Srpaulo urtwn_set_chan(sc, ic->ic_curchan, NULL); 1921251538Srpaulo break; 1922251538Srpaulo case IEEE80211_S_RUN: 1923251538Srpaulo if (vap->iv_opmode == IEEE80211_M_MONITOR) { 1924251538Srpaulo /* Turn link LED on. */ 1925251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 1); 1926251538Srpaulo break; 1927251538Srpaulo } 1928251538Srpaulo 1929251538Srpaulo ni = ieee80211_ref_node(vap->iv_bss); 1930290631Savos 1931290631Savos if (ic->ic_bsschan == IEEE80211_CHAN_ANYC || 1932290631Savos ni->ni_chan == IEEE80211_CHAN_ANYC) { 1933290631Savos device_printf(sc->sc_dev, 1934290631Savos "%s: could not move to RUN state\n", __func__); 1935290631Savos error = EINVAL; 1936290631Savos goto end_run; 1937290631Savos } 1938290631Savos 1939290631Savos switch (vap->iv_opmode) { 1940290631Savos case IEEE80211_M_STA: 1941290631Savos mode = R92C_MSR_INFRA; 1942290631Savos break; 1943290651Savos case IEEE80211_M_IBSS: 1944290651Savos mode = R92C_MSR_ADHOC; 1945290651Savos break; 1946290631Savos case IEEE80211_M_HOSTAP: 1947290631Savos mode = R92C_MSR_AP; 1948290631Savos break; 1949290631Savos default: 1950290631Savos device_printf(sc->sc_dev, "undefined opmode %d\n", 1951290631Savos vap->iv_opmode); 1952290631Savos error = EINVAL; 1953290631Savos goto end_run; 1954290631Savos } 1955290631Savos 1956251538Srpaulo /* Set media status to 'Associated'. */ 1957290631Savos urtwn_set_mode(sc, mode); 1958251538Srpaulo 1959251538Srpaulo /* Set BSSID. */ 1960251538Srpaulo urtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0])); 1961251538Srpaulo urtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4])); 1962251538Srpaulo 1963251538Srpaulo if (ic->ic_curmode == IEEE80211_MODE_11B) 1964251538Srpaulo urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0); 1965251538Srpaulo else /* 802.11b/g */ 1966251538Srpaulo urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3); 1967251538Srpaulo 1968251538Srpaulo /* Enable Rx of data frames. */ 1969251538Srpaulo urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); 1970251538Srpaulo 1971251538Srpaulo /* Flush all AC queues. */ 1972251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 0); 1973251538Srpaulo 1974251538Srpaulo /* Set beacon interval. */ 1975251538Srpaulo urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval); 1976251538Srpaulo 1977251538Srpaulo /* Allow Rx from our BSSID only. */ 1978290564Savos if (ic->ic_promisc == 0) { 1979290631Savos reg = urtwn_read_4(sc, R92C_RCR); 1980290631Savos 1981290631Savos if (vap->iv_opmode != IEEE80211_M_HOSTAP) 1982290631Savos reg |= R92C_RCR_CBSSID_DATA; 1983290651Savos if (vap->iv_opmode != IEEE80211_M_IBSS) 1984290651Savos reg |= R92C_RCR_CBSSID_BCN; 1985290631Savos 1986290631Savos urtwn_write_4(sc, R92C_RCR, reg); 1987290564Savos } 1988251538Srpaulo 1989290651Savos if (vap->iv_opmode == IEEE80211_M_HOSTAP || 1990290651Savos vap->iv_opmode == IEEE80211_M_IBSS) { 1991290631Savos error = urtwn_setup_beacon(sc, ni); 1992290631Savos if (error != 0) { 1993290631Savos device_printf(sc->sc_dev, 1994290631Savos "unable to push beacon into the chip, " 1995290631Savos "error %d\n", error); 1996290631Savos goto end_run; 1997290631Savos } 1998290631Savos } 1999290631Savos 2000251538Srpaulo /* Enable TSF synchronization. */ 2001290631Savos urtwn_tsf_sync_enable(sc, vap); 2002251538Srpaulo 2003251538Srpaulo urtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); 2004251538Srpaulo urtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); 2005251538Srpaulo urtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10); 2006251538Srpaulo urtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10); 2007251538Srpaulo urtwn_write_1(sc, R92C_R2T_SIFS + 1, 10); 2008251538Srpaulo urtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); 2009251538Srpaulo 2010251538Srpaulo /* Intialize rate adaptation. */ 2011264912Skevlo if (sc->chip & URTWN_CHIP_88E) 2012264912Skevlo ni->ni_txrate = 2013264912Skevlo ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates-1]; 2014281069Srpaulo else 2015264912Skevlo urtwn_ra_init(sc); 2016251538Srpaulo /* Turn link LED on. */ 2017251538Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, 1); 2018251538Srpaulo 2019251538Srpaulo sc->avg_pwdb = -1; /* Reset average RSSI. */ 2020251538Srpaulo /* Reset temperature calibration state machine. */ 2021251538Srpaulo sc->thcal_state = 0; 2022251538Srpaulo sc->thcal_lctemp = 0; 2023290631Savos 2024290631Savosend_run: 2025251538Srpaulo ieee80211_free_node(ni); 2026251538Srpaulo break; 2027251538Srpaulo default: 2028251538Srpaulo break; 2029251538Srpaulo } 2030290631Savos 2031251538Srpaulo URTWN_UNLOCK(sc); 2032251538Srpaulo IEEE80211_LOCK(ic); 2033290631Savos return (error != 0 ? error : uvp->newstate(vap, nstate, arg)); 2034251538Srpaulo} 2035251538Srpaulo 2036251538Srpaulostatic void 2037251538Srpaulourtwn_watchdog(void *arg) 2038251538Srpaulo{ 2039251538Srpaulo struct urtwn_softc *sc = arg; 2040251538Srpaulo 2041251538Srpaulo if (sc->sc_txtimer > 0) { 2042251538Srpaulo if (--sc->sc_txtimer == 0) { 2043251538Srpaulo device_printf(sc->sc_dev, "device timeout\n"); 2044287197Sglebius counter_u64_add(sc->sc_ic.ic_oerrors, 1); 2045251538Srpaulo return; 2046251538Srpaulo } 2047251538Srpaulo callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 2048251538Srpaulo } 2049251538Srpaulo} 2050251538Srpaulo 2051251538Srpaulostatic void 2052251538Srpaulourtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi) 2053251538Srpaulo{ 2054251538Srpaulo int pwdb; 2055251538Srpaulo 2056251538Srpaulo /* Convert antenna signal to percentage. */ 2057251538Srpaulo if (rssi <= -100 || rssi >= 20) 2058251538Srpaulo pwdb = 0; 2059251538Srpaulo else if (rssi >= 0) 2060251538Srpaulo pwdb = 100; 2061251538Srpaulo else 2062251538Srpaulo pwdb = 100 + rssi; 2063264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 2064289758Savos if (rate <= URTWN_RIDX_CCK11) { 2065264912Skevlo /* CCK gain is smaller than OFDM/MCS gain. */ 2066264912Skevlo pwdb += 6; 2067264912Skevlo if (pwdb > 100) 2068264912Skevlo pwdb = 100; 2069264912Skevlo if (pwdb <= 14) 2070264912Skevlo pwdb -= 4; 2071264912Skevlo else if (pwdb <= 26) 2072264912Skevlo pwdb -= 8; 2073264912Skevlo else if (pwdb <= 34) 2074264912Skevlo pwdb -= 6; 2075264912Skevlo else if (pwdb <= 42) 2076264912Skevlo pwdb -= 2; 2077264912Skevlo } 2078251538Srpaulo } 2079251538Srpaulo if (sc->avg_pwdb == -1) /* Init. */ 2080251538Srpaulo sc->avg_pwdb = pwdb; 2081251538Srpaulo else if (sc->avg_pwdb < pwdb) 2082251538Srpaulo sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1; 2083251538Srpaulo else 2084251538Srpaulo sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20); 2085251538Srpaulo DPRINTFN(4, "PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb); 2086251538Srpaulo} 2087251538Srpaulo 2088251538Srpaulostatic int8_t 2089251538Srpaulourtwn_get_rssi(struct urtwn_softc *sc, int rate, void *physt) 2090251538Srpaulo{ 2091251538Srpaulo static const int8_t cckoff[] = { 16, -12, -26, -46 }; 2092251538Srpaulo struct r92c_rx_phystat *phy; 2093251538Srpaulo struct r92c_rx_cck *cck; 2094251538Srpaulo uint8_t rpt; 2095251538Srpaulo int8_t rssi; 2096251538Srpaulo 2097289758Savos if (rate <= URTWN_RIDX_CCK11) { 2098251538Srpaulo cck = (struct r92c_rx_cck *)physt; 2099251538Srpaulo if (sc->sc_flags & URTWN_FLAG_CCK_HIPWR) { 2100251538Srpaulo rpt = (cck->agc_rpt >> 5) & 0x3; 2101251538Srpaulo rssi = (cck->agc_rpt & 0x1f) << 1; 2102251538Srpaulo } else { 2103251538Srpaulo rpt = (cck->agc_rpt >> 6) & 0x3; 2104251538Srpaulo rssi = cck->agc_rpt & 0x3e; 2105251538Srpaulo } 2106251538Srpaulo rssi = cckoff[rpt] - rssi; 2107251538Srpaulo } else { /* OFDM/HT. */ 2108251538Srpaulo phy = (struct r92c_rx_phystat *)physt; 2109251538Srpaulo rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; 2110251538Srpaulo } 2111251538Srpaulo return (rssi); 2112251538Srpaulo} 2113251538Srpaulo 2114264912Skevlostatic int8_t 2115264912Skevlourtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt) 2116264912Skevlo{ 2117264912Skevlo struct r92c_rx_phystat *phy; 2118264912Skevlo struct r88e_rx_cck *cck; 2119264912Skevlo uint8_t cck_agc_rpt, lna_idx, vga_idx; 2120264912Skevlo int8_t rssi; 2121264912Skevlo 2122264972Skevlo rssi = 0; 2123289758Savos if (rate <= URTWN_RIDX_CCK11) { 2124264912Skevlo cck = (struct r88e_rx_cck *)physt; 2125264912Skevlo cck_agc_rpt = cck->agc_rpt; 2126264912Skevlo lna_idx = (cck_agc_rpt & 0xe0) >> 5; 2127281069Srpaulo vga_idx = cck_agc_rpt & 0x1f; 2128264912Skevlo switch (lna_idx) { 2129264912Skevlo case 7: 2130264912Skevlo if (vga_idx <= 27) 2131264912Skevlo rssi = -100 + 2* (27 - vga_idx); 2132264912Skevlo else 2133264912Skevlo rssi = -100; 2134264912Skevlo break; 2135264912Skevlo case 6: 2136264912Skevlo rssi = -48 + 2 * (2 - vga_idx); 2137264912Skevlo break; 2138264912Skevlo case 5: 2139264912Skevlo rssi = -42 + 2 * (7 - vga_idx); 2140264912Skevlo break; 2141264912Skevlo case 4: 2142264912Skevlo rssi = -36 + 2 * (7 - vga_idx); 2143264912Skevlo break; 2144264912Skevlo case 3: 2145264912Skevlo rssi = -24 + 2 * (7 - vga_idx); 2146264912Skevlo break; 2147264912Skevlo case 2: 2148264912Skevlo rssi = -12 + 2 * (5 - vga_idx); 2149264912Skevlo break; 2150264912Skevlo case 1: 2151264912Skevlo rssi = 8 - (2 * vga_idx); 2152264912Skevlo break; 2153264912Skevlo case 0: 2154264912Skevlo rssi = 14 - (2 * vga_idx); 2155264912Skevlo break; 2156264912Skevlo } 2157264912Skevlo rssi += 6; 2158264912Skevlo } else { /* OFDM/HT. */ 2159264912Skevlo phy = (struct r92c_rx_phystat *)physt; 2160264912Skevlo rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; 2161264912Skevlo } 2162264912Skevlo return (rssi); 2163264912Skevlo} 2164264912Skevlo 2165251538Srpaulostatic int 2166290630Savosurtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni, 2167290630Savos struct mbuf *m, struct urtwn_data *data) 2168251538Srpaulo{ 2169251538Srpaulo struct ieee80211_frame *wh; 2170290630Savos struct ieee80211_key *k = NULL; 2171287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 2172251538Srpaulo struct ieee80211vap *vap = ni->ni_vap; 2173251538Srpaulo struct r92c_tx_desc *txd; 2174292014Savos uint8_t macid, raid, ridx, subtype, type, tid, qsel; 2175292014Savos int hasqos, ismcast; 2176251538Srpaulo 2177251538Srpaulo URTWN_ASSERT_LOCKED(sc); 2178251538Srpaulo 2179251538Srpaulo /* 2180251538Srpaulo * Software crypto. 2181251538Srpaulo */ 2182290630Savos wh = mtod(m, struct ieee80211_frame *); 2183264912Skevlo type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 2184290630Savos subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 2185292014Savos hasqos = IEEE80211_QOS_HAS_SEQ(wh); 2186290630Savos ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 2187264912Skevlo 2188292014Savos /* Select TX ring for this frame. */ 2189292014Savos if (hasqos) { 2190292014Savos tid = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; 2191292014Savos tid &= IEEE80211_QOS_TID; 2192292014Savos } else 2193292014Savos tid = 0; 2194292014Savos 2195260444Skevlo if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2196290630Savos k = ieee80211_crypto_encap(ni, m); 2197251538Srpaulo if (k == NULL) { 2198251538Srpaulo device_printf(sc->sc_dev, 2199251538Srpaulo "ieee80211_crypto_encap returns NULL.\n"); 2200251538Srpaulo return (ENOBUFS); 2201251538Srpaulo } 2202251538Srpaulo 2203251538Srpaulo /* in case packet header moved, reset pointer */ 2204290630Savos wh = mtod(m, struct ieee80211_frame *); 2205251538Srpaulo } 2206281069Srpaulo 2207251538Srpaulo /* Fill Tx descriptor. */ 2208251538Srpaulo txd = (struct r92c_tx_desc *)data->buf; 2209251538Srpaulo memset(txd, 0, sizeof(*txd)); 2210251538Srpaulo 2211251538Srpaulo txd->txdw0 |= htole32( 2212251538Srpaulo SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | 2213251538Srpaulo R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); 2214290630Savos if (ismcast) 2215251538Srpaulo txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); 2216290630Savos 2217290630Savos raid = R92C_RAID_11B; /* by default */ 2218290630Savos ridx = URTWN_RIDX_CCK1; 2219290630Savos if (!ismcast) { 2220290630Savos macid = URTWN_MACID_BSS; 2221290630Savos 2222290630Savos if (type == IEEE80211_FC0_TYPE_DATA) { 2223292014Savos qsel = tid % URTWN_MAX_TID; 2224290630Savos 2225290630Savos if (!(m->m_flags & M_EAPOL)) { 2226290630Savos if (ic->ic_curmode != IEEE80211_MODE_11B) { 2227290630Savos raid = R92C_RAID_11BG; 2228290630Savos ridx = URTWN_RIDX_OFDM54; 2229290630Savos } else 2230290630Savos ridx = URTWN_RIDX_CCK11; 2231251538Srpaulo } 2232290630Savos 2233290630Savos if (sc->chip & URTWN_CHIP_88E) 2234290630Savos txd->txdw2 |= htole32(R88E_TXDW2_AGGBK); 2235290630Savos else 2236290630Savos txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); 2237290630Savos 2238290630Savos if (ic->ic_flags & IEEE80211_F_USEPROT) { 2239290630Savos switch (ic->ic_protmode) { 2240290630Savos case IEEE80211_PROT_CTSONLY: 2241290630Savos txd->txdw4 |= htole32( 2242290630Savos R92C_TXDW4_CTS2SELF | 2243290630Savos R92C_TXDW4_HWRTSEN); 2244290630Savos break; 2245290630Savos case IEEE80211_PROT_RTSCTS: 2246290630Savos txd->txdw4 |= htole32( 2247290630Savos R92C_TXDW4_RTSEN | 2248290630Savos R92C_TXDW4_HWRTSEN); 2249290630Savos break; 2250290630Savos default: 2251290630Savos break; 2252290630Savos } 2253290630Savos } 2254290630Savos txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, 2255290630Savos URTWN_RIDX_OFDM24)); 2256290630Savos txd->txdw5 |= htole32(0x0001ff00); 2257290630Savos } else /* IEEE80211_FC0_TYPE_MGT */ 2258290630Savos qsel = R92C_TXDW1_QSEL_MGNT; 2259251538Srpaulo } else { 2260290630Savos macid = URTWN_MACID_BC; 2261290630Savos qsel = R92C_TXDW1_QSEL_MGNT; 2262290630Savos } 2263251538Srpaulo 2264290630Savos txd->txdw1 |= htole32( 2265290630Savos SM(R92C_TXDW1_QSEL, qsel) | 2266290630Savos SM(R92C_TXDW1_RAID, raid)); 2267290630Savos 2268290630Savos if (sc->chip & URTWN_CHIP_88E) 2269290630Savos txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid)); 2270290630Savos else 2271290630Savos txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid)); 2272290630Savos 2273290630Savos txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); 2274291858Savos /* Force this rate if needed. */ 2275291858Savos if (ismcast || type != IEEE80211_FC0_TYPE_DATA || 2276291858Savos (m->m_flags & M_EAPOL)) 2277251538Srpaulo txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); 2278251538Srpaulo 2279292014Savos if (!hasqos) { 2280251538Srpaulo /* Use HW sequence numbering for non-QoS frames. */ 2281291858Savos if (sc->chip & URTWN_CHIP_88E) 2282291858Savos txd->txdseq = htole16(R88E_TXDSEQ_HWSEQ_EN); 2283291858Savos else 2284291858Savos txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); 2285290630Savos } else { 2286290630Savos /* Set sequence number. */ 2287290630Savos txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); 2288290630Savos } 2289251538Srpaulo 2290251538Srpaulo if (ieee80211_radiotap_active_vap(vap)) { 2291251538Srpaulo struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap; 2292251538Srpaulo 2293251538Srpaulo tap->wt_flags = 0; 2294251538Srpaulo tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); 2295251538Srpaulo tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); 2296290630Savos if (k != NULL) 2297290630Savos tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 2298290630Savos ieee80211_radiotap_tx(vap, m); 2299251538Srpaulo } 2300251538Srpaulo 2301290630Savos data->ni = ni; 2302251538Srpaulo 2303290630Savos urtwn_tx_start(sc, m, type, data); 2304290630Savos 2305290630Savos return (0); 2306290630Savos} 2307290630Savos 2308290630Savosstatic void 2309290630Savosurtwn_tx_start(struct urtwn_softc *sc, struct mbuf *m, uint8_t type, 2310290630Savos struct urtwn_data *data) 2311290630Savos{ 2312290630Savos struct usb_xfer *xfer; 2313290630Savos struct r92c_tx_desc *txd; 2314290630Savos uint16_t ac, sum; 2315290630Savos int i, xferlen; 2316290630Savos 2317290630Savos URTWN_ASSERT_LOCKED(sc); 2318290630Savos 2319290630Savos ac = M_WME_GETAC(m); 2320290630Savos 2321290630Savos switch (type) { 2322290630Savos case IEEE80211_FC0_TYPE_CTL: 2323290630Savos case IEEE80211_FC0_TYPE_MGT: 2324290630Savos xfer = sc->sc_xfer[URTWN_BULK_TX_VO]; 2325290630Savos break; 2326290630Savos default: 2327292014Savos xfer = sc->sc_xfer[wme2queue[ac].qid]; 2328290630Savos break; 2329290630Savos } 2330290630Savos 2331290630Savos txd = (struct r92c_tx_desc *)data->buf; 2332290630Savos txd->txdw0 |= htole32(SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len)); 2333290630Savos 2334290630Savos /* Compute Tx descriptor checksum. */ 2335290630Savos sum = 0; 2336290630Savos for (i = 0; i < sizeof(*txd) / 2; i++) 2337290630Savos sum ^= ((uint16_t *)txd)[i]; 2338290630Savos txd->txdsum = sum; /* NB: already little endian. */ 2339290630Savos 2340290630Savos xferlen = sizeof(*txd) + m->m_pkthdr.len; 2341290630Savos m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]); 2342290630Savos 2343251538Srpaulo data->buflen = xferlen; 2344290630Savos data->m = m; 2345251538Srpaulo 2346251538Srpaulo STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); 2347251538Srpaulo usbd_transfer_start(xfer); 2348251538Srpaulo} 2349251538Srpaulo 2350287197Sglebiusstatic int 2351287197Sglebiusurtwn_transmit(struct ieee80211com *ic, struct mbuf *m) 2352251538Srpaulo{ 2353287197Sglebius struct urtwn_softc *sc = ic->ic_softc; 2354287197Sglebius int error; 2355261863Srpaulo 2356261863Srpaulo URTWN_LOCK(sc); 2357287197Sglebius if ((sc->sc_flags & URTWN_RUNNING) == 0) { 2358287197Sglebius URTWN_UNLOCK(sc); 2359287197Sglebius return (ENXIO); 2360287197Sglebius } 2361287197Sglebius error = mbufq_enqueue(&sc->sc_snd, m); 2362287197Sglebius if (error) { 2363287197Sglebius URTWN_UNLOCK(sc); 2364287197Sglebius return (error); 2365287197Sglebius } 2366287197Sglebius urtwn_start(sc); 2367261863Srpaulo URTWN_UNLOCK(sc); 2368287197Sglebius 2369287197Sglebius return (0); 2370261863Srpaulo} 2371261863Srpaulo 2372261863Srpaulostatic void 2373287197Sglebiusurtwn_start(struct urtwn_softc *sc) 2374261863Srpaulo{ 2375251538Srpaulo struct ieee80211_node *ni; 2376251538Srpaulo struct mbuf *m; 2377251538Srpaulo struct urtwn_data *bf; 2378251538Srpaulo 2379261863Srpaulo URTWN_ASSERT_LOCKED(sc); 2380287197Sglebius while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 2381251538Srpaulo bf = urtwn_getbuf(sc); 2382251538Srpaulo if (bf == NULL) { 2383287197Sglebius mbufq_prepend(&sc->sc_snd, m); 2384251538Srpaulo break; 2385251538Srpaulo } 2386251538Srpaulo ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 2387251538Srpaulo m->m_pkthdr.rcvif = NULL; 2388290630Savos if (urtwn_tx_data(sc, ni, m, bf) != 0) { 2389287197Sglebius if_inc_counter(ni->ni_vap->iv_ifp, 2390287197Sglebius IFCOUNTER_OERRORS, 1); 2391251538Srpaulo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 2392288353Sadrian m_freem(m); 2393251538Srpaulo ieee80211_free_node(ni); 2394251538Srpaulo break; 2395251538Srpaulo } 2396251538Srpaulo sc->sc_txtimer = 5; 2397251538Srpaulo callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 2398251538Srpaulo } 2399251538Srpaulo} 2400251538Srpaulo 2401287197Sglebiusstatic void 2402287197Sglebiusurtwn_parent(struct ieee80211com *ic) 2403251538Srpaulo{ 2404286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 2405251538Srpaulo 2406263153Skevlo URTWN_LOCK(sc); 2407287197Sglebius if (sc->sc_flags & URTWN_DETACHED) { 2408287197Sglebius URTWN_UNLOCK(sc); 2409287197Sglebius return; 2410287197Sglebius } 2411291698Savos URTWN_UNLOCK(sc); 2412291698Savos 2413287197Sglebius if (ic->ic_nrunning > 0) { 2414291698Savos if (urtwn_init(sc) != 0) { 2415291698Savos struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 2416291698Savos if (vap != NULL) 2417291698Savos ieee80211_stop(vap); 2418291698Savos } else 2419291698Savos ieee80211_start_all(ic); 2420291698Savos } else 2421287197Sglebius urtwn_stop(sc); 2422251538Srpaulo} 2423251538Srpaulo 2424264912Skevlostatic __inline int 2425251538Srpaulourtwn_power_on(struct urtwn_softc *sc) 2426251538Srpaulo{ 2427264912Skevlo 2428264912Skevlo return sc->sc_power_on(sc); 2429264912Skevlo} 2430264912Skevlo 2431264912Skevlostatic int 2432264912Skevlourtwn_r92c_power_on(struct urtwn_softc *sc) 2433264912Skevlo{ 2434251538Srpaulo uint32_t reg; 2435291698Savos usb_error_t error; 2436251538Srpaulo int ntries; 2437251538Srpaulo 2438251538Srpaulo /* Wait for autoload done bit. */ 2439251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2440251538Srpaulo if (urtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) 2441251538Srpaulo break; 2442266472Shselasky urtwn_ms_delay(sc); 2443251538Srpaulo } 2444251538Srpaulo if (ntries == 1000) { 2445251538Srpaulo device_printf(sc->sc_dev, 2446251538Srpaulo "timeout waiting for chip autoload\n"); 2447251538Srpaulo return (ETIMEDOUT); 2448251538Srpaulo } 2449251538Srpaulo 2450251538Srpaulo /* Unlock ISO/CLK/Power control register. */ 2451291698Savos error = urtwn_write_1(sc, R92C_RSV_CTRL, 0); 2452291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2453291698Savos return (EIO); 2454251538Srpaulo /* Move SPS into PWM mode. */ 2455291698Savos error = urtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); 2456291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2457291698Savos return (EIO); 2458266472Shselasky urtwn_ms_delay(sc); 2459251538Srpaulo 2460251538Srpaulo reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL); 2461251538Srpaulo if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) { 2462291698Savos error = urtwn_write_1(sc, R92C_LDOV12D_CTRL, 2463251538Srpaulo reg | R92C_LDOV12D_CTRL_LDV12_EN); 2464291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2465291698Savos return (EIO); 2466266472Shselasky urtwn_ms_delay(sc); 2467291698Savos error = urtwn_write_1(sc, R92C_SYS_ISO_CTRL, 2468251538Srpaulo urtwn_read_1(sc, R92C_SYS_ISO_CTRL) & 2469251538Srpaulo ~R92C_SYS_ISO_CTRL_MD2PP); 2470291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2471291698Savos return (EIO); 2472251538Srpaulo } 2473251538Srpaulo 2474251538Srpaulo /* Auto enable WLAN. */ 2475291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2476251538Srpaulo urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); 2477291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2478291698Savos return (EIO); 2479251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2480262822Skevlo if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & 2481262822Skevlo R92C_APS_FSMCO_APFM_ONMAC)) 2482251538Srpaulo break; 2483266472Shselasky urtwn_ms_delay(sc); 2484251538Srpaulo } 2485251538Srpaulo if (ntries == 1000) { 2486251538Srpaulo device_printf(sc->sc_dev, 2487251538Srpaulo "timeout waiting for MAC auto ON\n"); 2488251538Srpaulo return (ETIMEDOUT); 2489251538Srpaulo } 2490251538Srpaulo 2491251538Srpaulo /* Enable radio, GPIO and LED functions. */ 2492291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2493251538Srpaulo R92C_APS_FSMCO_AFSM_HSUS | 2494251538Srpaulo R92C_APS_FSMCO_PDN_EN | 2495251538Srpaulo R92C_APS_FSMCO_PFM_ALDN); 2496291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2497291698Savos return (EIO); 2498251538Srpaulo /* Release RF digital isolation. */ 2499291698Savos error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL, 2500251538Srpaulo urtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR); 2501291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2502291698Savos return (EIO); 2503251538Srpaulo 2504251538Srpaulo /* Initialize MAC. */ 2505291698Savos error = urtwn_write_1(sc, R92C_APSD_CTRL, 2506251538Srpaulo urtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF); 2507291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2508291698Savos return (EIO); 2509251538Srpaulo for (ntries = 0; ntries < 200; ntries++) { 2510251538Srpaulo if (!(urtwn_read_1(sc, R92C_APSD_CTRL) & 2511251538Srpaulo R92C_APSD_CTRL_OFF_STATUS)) 2512251538Srpaulo break; 2513266472Shselasky urtwn_ms_delay(sc); 2514251538Srpaulo } 2515251538Srpaulo if (ntries == 200) { 2516251538Srpaulo device_printf(sc->sc_dev, 2517251538Srpaulo "timeout waiting for MAC initialization\n"); 2518251538Srpaulo return (ETIMEDOUT); 2519251538Srpaulo } 2520251538Srpaulo 2521251538Srpaulo /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ 2522251538Srpaulo reg = urtwn_read_2(sc, R92C_CR); 2523251538Srpaulo reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | 2524251538Srpaulo R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | 2525251538Srpaulo R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | 2526251538Srpaulo R92C_CR_ENSEC; 2527291698Savos error = urtwn_write_2(sc, R92C_CR, reg); 2528291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2529291698Savos return (EIO); 2530251538Srpaulo 2531291698Savos error = urtwn_write_1(sc, 0xfe10, 0x19); 2532291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2533291698Savos return (EIO); 2534251538Srpaulo return (0); 2535251538Srpaulo} 2536251538Srpaulo 2537251538Srpaulostatic int 2538264912Skevlourtwn_r88e_power_on(struct urtwn_softc *sc) 2539264912Skevlo{ 2540264912Skevlo uint32_t reg; 2541291698Savos usb_error_t error; 2542264912Skevlo int ntries; 2543264912Skevlo 2544264912Skevlo /* Wait for power ready bit. */ 2545264912Skevlo for (ntries = 0; ntries < 5000; ntries++) { 2546281918Skevlo if (urtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) 2547264912Skevlo break; 2548266472Shselasky urtwn_ms_delay(sc); 2549264912Skevlo } 2550264912Skevlo if (ntries == 5000) { 2551264912Skevlo device_printf(sc->sc_dev, 2552264912Skevlo "timeout waiting for chip power up\n"); 2553264912Skevlo return (ETIMEDOUT); 2554264912Skevlo } 2555264912Skevlo 2556264912Skevlo /* Reset BB. */ 2557291698Savos error = urtwn_write_1(sc, R92C_SYS_FUNC_EN, 2558264912Skevlo urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | 2559264912Skevlo R92C_SYS_FUNC_EN_BB_GLB_RST)); 2560291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2561291698Savos return (EIO); 2562264912Skevlo 2563291698Savos error = urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2, 2564281918Skevlo urtwn_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80); 2565291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2566291698Savos return (EIO); 2567264912Skevlo 2568264912Skevlo /* Disable HWPDN. */ 2569291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2570281918Skevlo urtwn_read_2(sc, R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN); 2571291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2572291698Savos return (EIO); 2573264912Skevlo 2574264912Skevlo /* Disable WL suspend. */ 2575291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2576281918Skevlo urtwn_read_2(sc, R92C_APS_FSMCO) & 2577281918Skevlo ~(R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE)); 2578291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2579291698Savos return (EIO); 2580264912Skevlo 2581291698Savos error = urtwn_write_2(sc, R92C_APS_FSMCO, 2582281918Skevlo urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); 2583291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2584291698Savos return (EIO); 2585264912Skevlo for (ntries = 0; ntries < 5000; ntries++) { 2586281918Skevlo if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & 2587281918Skevlo R92C_APS_FSMCO_APFM_ONMAC)) 2588264912Skevlo break; 2589266472Shselasky urtwn_ms_delay(sc); 2590264912Skevlo } 2591264912Skevlo if (ntries == 5000) 2592264912Skevlo return (ETIMEDOUT); 2593264912Skevlo 2594264912Skevlo /* Enable LDO normal mode. */ 2595291698Savos error = urtwn_write_1(sc, R92C_LPLDO_CTRL, 2596281918Skevlo urtwn_read_1(sc, R92C_LPLDO_CTRL) & ~0x10); 2597291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2598291698Savos return (EIO); 2599264912Skevlo 2600264912Skevlo /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ 2601291698Savos error = urtwn_write_2(sc, R92C_CR, 0); 2602291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2603291698Savos return (EIO); 2604264912Skevlo reg = urtwn_read_2(sc, R92C_CR); 2605264912Skevlo reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | 2606264912Skevlo R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | 2607264912Skevlo R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC | R92C_CR_CALTMR_EN; 2608291698Savos error = urtwn_write_2(sc, R92C_CR, reg); 2609291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2610291698Savos return (EIO); 2611264912Skevlo 2612264912Skevlo return (0); 2613264912Skevlo} 2614264912Skevlo 2615264912Skevlostatic int 2616251538Srpaulourtwn_llt_init(struct urtwn_softc *sc) 2617251538Srpaulo{ 2618264912Skevlo int i, error, page_count, pktbuf_count; 2619251538Srpaulo 2620264912Skevlo page_count = (sc->chip & URTWN_CHIP_88E) ? 2621264912Skevlo R88E_TX_PAGE_COUNT : R92C_TX_PAGE_COUNT; 2622264912Skevlo pktbuf_count = (sc->chip & URTWN_CHIP_88E) ? 2623264912Skevlo R88E_TXPKTBUF_COUNT : R92C_TXPKTBUF_COUNT; 2624264912Skevlo 2625264912Skevlo /* Reserve pages [0; page_count]. */ 2626264912Skevlo for (i = 0; i < page_count; i++) { 2627251538Srpaulo if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) 2628251538Srpaulo return (error); 2629251538Srpaulo } 2630251538Srpaulo /* NB: 0xff indicates end-of-list. */ 2631251538Srpaulo if ((error = urtwn_llt_write(sc, i, 0xff)) != 0) 2632251538Srpaulo return (error); 2633251538Srpaulo /* 2634264912Skevlo * Use pages [page_count + 1; pktbuf_count - 1] 2635251538Srpaulo * as ring buffer. 2636251538Srpaulo */ 2637264912Skevlo for (++i; i < pktbuf_count - 1; i++) { 2638251538Srpaulo if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) 2639251538Srpaulo return (error); 2640251538Srpaulo } 2641251538Srpaulo /* Make the last page point to the beginning of the ring buffer. */ 2642264912Skevlo error = urtwn_llt_write(sc, i, page_count + 1); 2643251538Srpaulo return (error); 2644251538Srpaulo} 2645251538Srpaulo 2646251538Srpaulostatic void 2647251538Srpaulourtwn_fw_reset(struct urtwn_softc *sc) 2648251538Srpaulo{ 2649251538Srpaulo uint16_t reg; 2650251538Srpaulo int ntries; 2651251538Srpaulo 2652251538Srpaulo /* Tell 8051 to reset itself. */ 2653251538Srpaulo urtwn_write_1(sc, R92C_HMETFR + 3, 0x20); 2654251538Srpaulo 2655251538Srpaulo /* Wait until 8051 resets by itself. */ 2656251538Srpaulo for (ntries = 0; ntries < 100; ntries++) { 2657251538Srpaulo reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); 2658251538Srpaulo if (!(reg & R92C_SYS_FUNC_EN_CPUEN)) 2659251538Srpaulo return; 2660266472Shselasky urtwn_ms_delay(sc); 2661251538Srpaulo } 2662251538Srpaulo /* Force 8051 reset. */ 2663251538Srpaulo urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); 2664251538Srpaulo} 2665251538Srpaulo 2666264912Skevlostatic void 2667264912Skevlourtwn_r88e_fw_reset(struct urtwn_softc *sc) 2668264912Skevlo{ 2669264912Skevlo uint16_t reg; 2670264912Skevlo 2671264912Skevlo reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); 2672264912Skevlo urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); 2673264912Skevlo urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN); 2674264912Skevlo} 2675264912Skevlo 2676251538Srpaulostatic int 2677251538Srpaulourtwn_fw_loadpage(struct urtwn_softc *sc, int page, const uint8_t *buf, int len) 2678251538Srpaulo{ 2679251538Srpaulo uint32_t reg; 2680291698Savos usb_error_t error = USB_ERR_NORMAL_COMPLETION; 2681291698Savos int off, mlen; 2682251538Srpaulo 2683251538Srpaulo reg = urtwn_read_4(sc, R92C_MCUFWDL); 2684251538Srpaulo reg = RW(reg, R92C_MCUFWDL_PAGE, page); 2685251538Srpaulo urtwn_write_4(sc, R92C_MCUFWDL, reg); 2686251538Srpaulo 2687251538Srpaulo off = R92C_FW_START_ADDR; 2688251538Srpaulo while (len > 0) { 2689251538Srpaulo if (len > 196) 2690251538Srpaulo mlen = 196; 2691251538Srpaulo else if (len > 4) 2692251538Srpaulo mlen = 4; 2693251538Srpaulo else 2694251538Srpaulo mlen = 1; 2695251538Srpaulo /* XXX fix this deconst */ 2696281069Srpaulo error = urtwn_write_region_1(sc, off, 2697251538Srpaulo __DECONST(uint8_t *, buf), mlen); 2698291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2699251538Srpaulo break; 2700251538Srpaulo off += mlen; 2701251538Srpaulo buf += mlen; 2702251538Srpaulo len -= mlen; 2703251538Srpaulo } 2704251538Srpaulo return (error); 2705251538Srpaulo} 2706251538Srpaulo 2707251538Srpaulostatic int 2708251538Srpaulourtwn_load_firmware(struct urtwn_softc *sc) 2709251538Srpaulo{ 2710251538Srpaulo const struct firmware *fw; 2711251538Srpaulo const struct r92c_fw_hdr *hdr; 2712251538Srpaulo const char *imagename; 2713251538Srpaulo const u_char *ptr; 2714251538Srpaulo size_t len; 2715251538Srpaulo uint32_t reg; 2716251538Srpaulo int mlen, ntries, page, error; 2717251538Srpaulo 2718264864Skevlo URTWN_UNLOCK(sc); 2719251538Srpaulo /* Read firmware image from the filesystem. */ 2720264912Skevlo if (sc->chip & URTWN_CHIP_88E) 2721264912Skevlo imagename = "urtwn-rtl8188eufw"; 2722264912Skevlo else if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == 2723264912Skevlo URTWN_CHIP_UMC_A_CUT) 2724251538Srpaulo imagename = "urtwn-rtl8192cfwU"; 2725251538Srpaulo else 2726251538Srpaulo imagename = "urtwn-rtl8192cfwT"; 2727251538Srpaulo 2728251538Srpaulo fw = firmware_get(imagename); 2729264864Skevlo URTWN_LOCK(sc); 2730251538Srpaulo if (fw == NULL) { 2731251538Srpaulo device_printf(sc->sc_dev, 2732251538Srpaulo "failed loadfirmware of file %s\n", imagename); 2733251538Srpaulo return (ENOENT); 2734251538Srpaulo } 2735251538Srpaulo 2736251538Srpaulo len = fw->datasize; 2737251538Srpaulo 2738251538Srpaulo if (len < sizeof(*hdr)) { 2739251538Srpaulo device_printf(sc->sc_dev, "firmware too short\n"); 2740251538Srpaulo error = EINVAL; 2741251538Srpaulo goto fail; 2742251538Srpaulo } 2743251538Srpaulo ptr = fw->data; 2744251538Srpaulo hdr = (const struct r92c_fw_hdr *)ptr; 2745251538Srpaulo /* Check if there is a valid FW header and skip it. */ 2746251538Srpaulo if ((le16toh(hdr->signature) >> 4) == 0x88c || 2747264912Skevlo (le16toh(hdr->signature) >> 4) == 0x88e || 2748251538Srpaulo (le16toh(hdr->signature) >> 4) == 0x92c) { 2749251538Srpaulo DPRINTF("FW V%d.%d %02d-%02d %02d:%02d\n", 2750251538Srpaulo le16toh(hdr->version), le16toh(hdr->subversion), 2751251538Srpaulo hdr->month, hdr->date, hdr->hour, hdr->minute); 2752251538Srpaulo ptr += sizeof(*hdr); 2753251538Srpaulo len -= sizeof(*hdr); 2754251538Srpaulo } 2755251538Srpaulo 2756264912Skevlo if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) { 2757264912Skevlo if (sc->chip & URTWN_CHIP_88E) 2758264912Skevlo urtwn_r88e_fw_reset(sc); 2759264912Skevlo else 2760264912Skevlo urtwn_fw_reset(sc); 2761251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL, 0); 2762251538Srpaulo } 2763264912Skevlo 2764268487Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 2765268487Skevlo urtwn_write_2(sc, R92C_SYS_FUNC_EN, 2766268487Skevlo urtwn_read_2(sc, R92C_SYS_FUNC_EN) | 2767268487Skevlo R92C_SYS_FUNC_EN_CPUEN); 2768268487Skevlo } 2769251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL, 2770251538Srpaulo urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN); 2771251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL + 2, 2772251538Srpaulo urtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08); 2773251538Srpaulo 2774263154Skevlo /* Reset the FWDL checksum. */ 2775263154Skevlo urtwn_write_1(sc, R92C_MCUFWDL, 2776263154Skevlo urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT); 2777263154Skevlo 2778251538Srpaulo for (page = 0; len > 0; page++) { 2779251538Srpaulo mlen = min(len, R92C_FW_PAGE_SIZE); 2780251538Srpaulo error = urtwn_fw_loadpage(sc, page, ptr, mlen); 2781251538Srpaulo if (error != 0) { 2782251538Srpaulo device_printf(sc->sc_dev, 2783251538Srpaulo "could not load firmware page\n"); 2784251538Srpaulo goto fail; 2785251538Srpaulo } 2786251538Srpaulo ptr += mlen; 2787251538Srpaulo len -= mlen; 2788251538Srpaulo } 2789251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL, 2790251538Srpaulo urtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN); 2791251538Srpaulo urtwn_write_1(sc, R92C_MCUFWDL + 1, 0); 2792251538Srpaulo 2793251538Srpaulo /* Wait for checksum report. */ 2794251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2795251538Srpaulo if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) 2796251538Srpaulo break; 2797266472Shselasky urtwn_ms_delay(sc); 2798251538Srpaulo } 2799251538Srpaulo if (ntries == 1000) { 2800251538Srpaulo device_printf(sc->sc_dev, 2801251538Srpaulo "timeout waiting for checksum report\n"); 2802251538Srpaulo error = ETIMEDOUT; 2803251538Srpaulo goto fail; 2804251538Srpaulo } 2805251538Srpaulo 2806251538Srpaulo reg = urtwn_read_4(sc, R92C_MCUFWDL); 2807251538Srpaulo reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY; 2808251538Srpaulo urtwn_write_4(sc, R92C_MCUFWDL, reg); 2809264912Skevlo if (sc->chip & URTWN_CHIP_88E) 2810264912Skevlo urtwn_r88e_fw_reset(sc); 2811251538Srpaulo /* Wait for firmware readiness. */ 2812251538Srpaulo for (ntries = 0; ntries < 1000; ntries++) { 2813251538Srpaulo if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) 2814251538Srpaulo break; 2815266472Shselasky urtwn_ms_delay(sc); 2816251538Srpaulo } 2817251538Srpaulo if (ntries == 1000) { 2818251538Srpaulo device_printf(sc->sc_dev, 2819251538Srpaulo "timeout waiting for firmware readiness\n"); 2820251538Srpaulo error = ETIMEDOUT; 2821251538Srpaulo goto fail; 2822251538Srpaulo } 2823251538Srpaulofail: 2824251538Srpaulo firmware_put(fw, FIRMWARE_UNLOAD); 2825251538Srpaulo return (error); 2826251538Srpaulo} 2827251538Srpaulo 2828291902Skevlostatic int 2829251538Srpaulourtwn_dma_init(struct urtwn_softc *sc) 2830251538Srpaulo{ 2831291902Skevlo struct usb_endpoint *ep, *ep_end; 2832291698Savos usb_error_t usb_err; 2833291902Skevlo uint32_t reg; 2834291902Skevlo int hashq, hasnq, haslq, nqueues, ntx; 2835291902Skevlo int error, pagecount, npubqpages, nqpages, nrempages, tx_boundary; 2836281069Srpaulo 2837291695Savos /* Initialize LLT table. */ 2838291695Savos error = urtwn_llt_init(sc); 2839291695Savos if (error != 0) 2840291695Savos return (error); 2841291695Savos 2842291902Skevlo /* Determine the number of bulk-out pipes. */ 2843291902Skevlo ntx = 0; 2844291902Skevlo ep = sc->sc_udev->endpoints; 2845291902Skevlo ep_end = sc->sc_udev->endpoints + sc->sc_udev->endpoints_max; 2846291902Skevlo for (; ep != ep_end; ep++) { 2847291902Skevlo if ((ep->edesc == NULL) || 2848291902Skevlo (ep->iface_index != sc->sc_iface_index)) 2849291902Skevlo continue; 2850291902Skevlo if (UE_GET_DIR(ep->edesc->bEndpointAddress) == UE_DIR_OUT) 2851291902Skevlo ntx++; 2852291902Skevlo } 2853291902Skevlo if (ntx == 0) { 2854291902Skevlo device_printf(sc->sc_dev, 2855291902Skevlo "%d: invalid number of Tx bulk pipes\n", ntx); 2856291698Savos return (EIO); 2857291902Skevlo } 2858291695Savos 2859251538Srpaulo /* Get Tx queues to USB endpoints mapping. */ 2860291902Skevlo hashq = hasnq = haslq = nqueues = 0; 2861291902Skevlo switch (ntx) { 2862291902Skevlo case 1: hashq = 1; break; 2863291902Skevlo case 2: hashq = hasnq = 1; break; 2864291902Skevlo case 3: case 4: hashq = hasnq = haslq = 1; break; 2865291902Skevlo } 2866251538Srpaulo nqueues = hashq + hasnq + haslq; 2867251538Srpaulo if (nqueues == 0) 2868251538Srpaulo return (EIO); 2869251538Srpaulo 2870291902Skevlo npubqpages = nqpages = nrempages = pagecount = 0; 2871291902Skevlo if (sc->chip & URTWN_CHIP_88E) 2872291902Skevlo tx_boundary = R88E_TX_PAGE_BOUNDARY; 2873291902Skevlo else { 2874291902Skevlo pagecount = R92C_TX_PAGE_COUNT; 2875291902Skevlo npubqpages = R92C_PUBQ_NPAGES; 2876291902Skevlo tx_boundary = R92C_TX_PAGE_BOUNDARY; 2877291902Skevlo } 2878291902Skevlo 2879251538Srpaulo /* Set number of pages for normal priority queue. */ 2880291902Skevlo if (sc->chip & URTWN_CHIP_88E) { 2881291902Skevlo usb_err = urtwn_write_2(sc, R92C_RQPN_NPQ, 0xd); 2882291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2883291902Skevlo return (EIO); 2884291902Skevlo usb_err = urtwn_write_4(sc, R92C_RQPN, 0x808e000d); 2885291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2886291902Skevlo return (EIO); 2887291902Skevlo } else { 2888291902Skevlo /* Get the number of pages for each queue. */ 2889291902Skevlo nqpages = (pagecount - npubqpages) / nqueues; 2890291902Skevlo /* 2891291902Skevlo * The remaining pages are assigned to the high priority 2892291902Skevlo * queue. 2893291902Skevlo */ 2894291902Skevlo nrempages = (pagecount - npubqpages) % nqueues; 2895291902Skevlo usb_err = urtwn_write_1(sc, R92C_RQPN_NPQ, hasnq ? nqpages : 0); 2896291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2897291902Skevlo return (EIO); 2898291902Skevlo usb_err = urtwn_write_4(sc, R92C_RQPN, 2899291902Skevlo /* Set number of pages for public queue. */ 2900291902Skevlo SM(R92C_RQPN_PUBQ, npubqpages) | 2901291902Skevlo /* Set number of pages for high priority queue. */ 2902291902Skevlo SM(R92C_RQPN_HPQ, hashq ? nqpages + nrempages : 0) | 2903291902Skevlo /* Set number of pages for low priority queue. */ 2904291902Skevlo SM(R92C_RQPN_LPQ, haslq ? nqpages : 0) | 2905291902Skevlo /* Load values. */ 2906291902Skevlo R92C_RQPN_LD); 2907291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2908291902Skevlo return (EIO); 2909291902Skevlo } 2910251538Srpaulo 2911291902Skevlo usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, tx_boundary); 2912291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2913291698Savos return (EIO); 2914291902Skevlo usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, tx_boundary); 2915291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2916291698Savos return (EIO); 2917291902Skevlo usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, tx_boundary); 2918291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2919291698Savos return (EIO); 2920291902Skevlo usb_err = urtwn_write_1(sc, R92C_TRXFF_BNDY, tx_boundary); 2921291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2922291698Savos return (EIO); 2923291902Skevlo usb_err = urtwn_write_1(sc, R92C_TDECTRL + 1, tx_boundary); 2924291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2925291698Savos return (EIO); 2926251538Srpaulo 2927251538Srpaulo /* Set queue to USB pipe mapping. */ 2928251538Srpaulo reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL); 2929251538Srpaulo reg &= ~R92C_TRXDMA_CTRL_QMAP_M; 2930251538Srpaulo if (nqueues == 1) { 2931251538Srpaulo if (hashq) 2932251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_HQ; 2933251538Srpaulo else if (hasnq) 2934251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_NQ; 2935251538Srpaulo else 2936251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_LQ; 2937251538Srpaulo } else if (nqueues == 2) { 2938292056Skevlo /* 2939292056Skevlo * All 2-endpoints configs have high and normal 2940292056Skevlo * priority queues. 2941292056Skevlo */ 2942292056Skevlo reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ; 2943251538Srpaulo } else 2944251538Srpaulo reg |= R92C_TRXDMA_CTRL_QMAP_3EP; 2945291902Skevlo usb_err = urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); 2946291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2947291698Savos return (EIO); 2948251538Srpaulo 2949251538Srpaulo /* Set Tx/Rx transfer page boundary. */ 2950291902Skevlo usb_err = urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 2951291902Skevlo (sc->chip & URTWN_CHIP_88E) ? 0x23ff : 0x27ff); 2952291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2953291698Savos return (EIO); 2954251538Srpaulo 2955291902Skevlo /* Set Tx/Rx transfer page size. */ 2956291902Skevlo usb_err = urtwn_write_1(sc, R92C_PBP, 2957291902Skevlo SM(R92C_PBP_PSRX, R92C_PBP_128) | 2958291902Skevlo SM(R92C_PBP_PSTX, R92C_PBP_128)); 2959291902Skevlo if (usb_err != USB_ERR_NORMAL_COMPLETION) 2960264912Skevlo return (EIO); 2961264912Skevlo 2962264912Skevlo return (0); 2963264912Skevlo} 2964264912Skevlo 2965291698Savosstatic int 2966251538Srpaulourtwn_mac_init(struct urtwn_softc *sc) 2967251538Srpaulo{ 2968291698Savos usb_error_t error; 2969251538Srpaulo int i; 2970251538Srpaulo 2971251538Srpaulo /* Write MAC initialization values. */ 2972264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 2973264912Skevlo for (i = 0; i < nitems(rtl8188eu_mac); i++) { 2974291698Savos error = urtwn_write_1(sc, rtl8188eu_mac[i].reg, 2975264912Skevlo rtl8188eu_mac[i].val); 2976291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2977291698Savos return (EIO); 2978264912Skevlo } 2979264912Skevlo urtwn_write_1(sc, R92C_MAX_AGGR_NUM, 0x07); 2980264912Skevlo } else { 2981264912Skevlo for (i = 0; i < nitems(rtl8192cu_mac); i++) 2982291698Savos error = urtwn_write_1(sc, rtl8192cu_mac[i].reg, 2983264912Skevlo rtl8192cu_mac[i].val); 2984291698Savos if (error != USB_ERR_NORMAL_COMPLETION) 2985291698Savos return (EIO); 2986264912Skevlo } 2987291698Savos 2988291698Savos return (0); 2989251538Srpaulo} 2990251538Srpaulo 2991251538Srpaulostatic void 2992251538Srpaulourtwn_bb_init(struct urtwn_softc *sc) 2993251538Srpaulo{ 2994251538Srpaulo const struct urtwn_bb_prog *prog; 2995251538Srpaulo uint32_t reg; 2996264912Skevlo uint8_t crystalcap; 2997251538Srpaulo int i; 2998251538Srpaulo 2999251538Srpaulo /* Enable BB and RF. */ 3000251538Srpaulo urtwn_write_2(sc, R92C_SYS_FUNC_EN, 3001251538Srpaulo urtwn_read_2(sc, R92C_SYS_FUNC_EN) | 3002251538Srpaulo R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | 3003251538Srpaulo R92C_SYS_FUNC_EN_DIO_RF); 3004251538Srpaulo 3005264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) 3006264912Skevlo urtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); 3007251538Srpaulo 3008251538Srpaulo urtwn_write_1(sc, R92C_RF_CTRL, 3009251538Srpaulo R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); 3010251538Srpaulo urtwn_write_1(sc, R92C_SYS_FUNC_EN, 3011251538Srpaulo R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | 3012251538Srpaulo R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); 3013251538Srpaulo 3014264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 3015264912Skevlo urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); 3016264912Skevlo urtwn_write_1(sc, 0x15, 0xe9); 3017264912Skevlo urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); 3018264912Skevlo } 3019251538Srpaulo 3020251538Srpaulo /* Select BB programming based on board type. */ 3021264912Skevlo if (sc->chip & URTWN_CHIP_88E) 3022264912Skevlo prog = &rtl8188eu_bb_prog; 3023264912Skevlo else if (!(sc->chip & URTWN_CHIP_92C)) { 3024251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_MINICARD) 3025251538Srpaulo prog = &rtl8188ce_bb_prog; 3026251538Srpaulo else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) 3027251538Srpaulo prog = &rtl8188ru_bb_prog; 3028251538Srpaulo else 3029251538Srpaulo prog = &rtl8188cu_bb_prog; 3030251538Srpaulo } else { 3031251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_MINICARD) 3032251538Srpaulo prog = &rtl8192ce_bb_prog; 3033251538Srpaulo else 3034251538Srpaulo prog = &rtl8192cu_bb_prog; 3035251538Srpaulo } 3036251538Srpaulo /* Write BB initialization values. */ 3037251538Srpaulo for (i = 0; i < prog->count; i++) { 3038251538Srpaulo urtwn_bb_write(sc, prog->regs[i], prog->vals[i]); 3039266472Shselasky urtwn_ms_delay(sc); 3040251538Srpaulo } 3041251538Srpaulo 3042251538Srpaulo if (sc->chip & URTWN_CHIP_92C_1T2R) { 3043251538Srpaulo /* 8192C 1T only configuration. */ 3044251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_TXINFO); 3045251538Srpaulo reg = (reg & ~0x00000003) | 0x2; 3046251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg); 3047251538Srpaulo 3048251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA1_TXINFO); 3049251538Srpaulo reg = (reg & ~0x00300033) | 0x00200022; 3050251538Srpaulo urtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg); 3051251538Srpaulo 3052251538Srpaulo reg = urtwn_bb_read(sc, R92C_CCK0_AFESETTING); 3053251538Srpaulo reg = (reg & ~0xff000000) | 0x45 << 24; 3054251538Srpaulo urtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg); 3055251538Srpaulo 3056251538Srpaulo reg = urtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); 3057251538Srpaulo reg = (reg & ~0x000000ff) | 0x23; 3058251538Srpaulo urtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg); 3059251538Srpaulo 3060251538Srpaulo reg = urtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1); 3061251538Srpaulo reg = (reg & ~0x00000030) | 1 << 4; 3062251538Srpaulo urtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg); 3063251538Srpaulo 3064251538Srpaulo reg = urtwn_bb_read(sc, 0xe74); 3065251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3066251538Srpaulo urtwn_bb_write(sc, 0xe74, reg); 3067251538Srpaulo reg = urtwn_bb_read(sc, 0xe78); 3068251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3069251538Srpaulo urtwn_bb_write(sc, 0xe78, reg); 3070251538Srpaulo reg = urtwn_bb_read(sc, 0xe7c); 3071251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3072251538Srpaulo urtwn_bb_write(sc, 0xe7c, reg); 3073251538Srpaulo reg = urtwn_bb_read(sc, 0xe80); 3074251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3075251538Srpaulo urtwn_bb_write(sc, 0xe80, reg); 3076251538Srpaulo reg = urtwn_bb_read(sc, 0xe88); 3077251538Srpaulo reg = (reg & ~0x0c000000) | 2 << 26; 3078251538Srpaulo urtwn_bb_write(sc, 0xe88, reg); 3079251538Srpaulo } 3080251538Srpaulo 3081251538Srpaulo /* Write AGC values. */ 3082251538Srpaulo for (i = 0; i < prog->agccount; i++) { 3083251538Srpaulo urtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, 3084251538Srpaulo prog->agcvals[i]); 3085266472Shselasky urtwn_ms_delay(sc); 3086251538Srpaulo } 3087251538Srpaulo 3088264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 3089264912Skevlo urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422); 3090266472Shselasky urtwn_ms_delay(sc); 3091264912Skevlo urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420); 3092266472Shselasky urtwn_ms_delay(sc); 3093264912Skevlo 3094291264Savos crystalcap = sc->rom.r88e_rom[0xb9]; 3095264912Skevlo if (crystalcap == 0xff) 3096264912Skevlo crystalcap = 0x20; 3097264912Skevlo crystalcap &= 0x3f; 3098264912Skevlo reg = urtwn_bb_read(sc, R92C_AFE_XTAL_CTRL); 3099264912Skevlo urtwn_bb_write(sc, R92C_AFE_XTAL_CTRL, 3100264912Skevlo RW(reg, R92C_AFE_XTAL_CTRL_ADDR, 3101264912Skevlo crystalcap | crystalcap << 6)); 3102264912Skevlo } else { 3103264912Skevlo if (urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & 3104264912Skevlo R92C_HSSI_PARAM2_CCK_HIPWR) 3105264912Skevlo sc->sc_flags |= URTWN_FLAG_CCK_HIPWR; 3106264912Skevlo } 3107251538Srpaulo} 3108251538Srpaulo 3109289066Skevlostatic void 3110251538Srpaulourtwn_rf_init(struct urtwn_softc *sc) 3111251538Srpaulo{ 3112251538Srpaulo const struct urtwn_rf_prog *prog; 3113251538Srpaulo uint32_t reg, type; 3114251538Srpaulo int i, j, idx, off; 3115251538Srpaulo 3116251538Srpaulo /* Select RF programming based on board type. */ 3117264912Skevlo if (sc->chip & URTWN_CHIP_88E) 3118264912Skevlo prog = rtl8188eu_rf_prog; 3119264912Skevlo else if (!(sc->chip & URTWN_CHIP_92C)) { 3120251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_MINICARD) 3121251538Srpaulo prog = rtl8188ce_rf_prog; 3122251538Srpaulo else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) 3123251538Srpaulo prog = rtl8188ru_rf_prog; 3124251538Srpaulo else 3125251538Srpaulo prog = rtl8188cu_rf_prog; 3126251538Srpaulo } else 3127251538Srpaulo prog = rtl8192ce_rf_prog; 3128251538Srpaulo 3129251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3130251538Srpaulo /* Save RF_ENV control type. */ 3131251538Srpaulo idx = i / 2; 3132251538Srpaulo off = (i % 2) * 16; 3133251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); 3134251538Srpaulo type = (reg >> off) & 0x10; 3135251538Srpaulo 3136251538Srpaulo /* Set RF_ENV enable. */ 3137251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); 3138251538Srpaulo reg |= 0x100000; 3139251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); 3140266472Shselasky urtwn_ms_delay(sc); 3141251538Srpaulo /* Set RF_ENV output high. */ 3142251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); 3143251538Srpaulo reg |= 0x10; 3144251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); 3145266472Shselasky urtwn_ms_delay(sc); 3146251538Srpaulo /* Set address and data lengths of RF registers. */ 3147251538Srpaulo reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); 3148251538Srpaulo reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH; 3149251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); 3150266472Shselasky urtwn_ms_delay(sc); 3151251538Srpaulo reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); 3152251538Srpaulo reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH; 3153251538Srpaulo urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); 3154266472Shselasky urtwn_ms_delay(sc); 3155251538Srpaulo 3156251538Srpaulo /* Write RF initialization values for this chain. */ 3157251538Srpaulo for (j = 0; j < prog[i].count; j++) { 3158251538Srpaulo if (prog[i].regs[j] >= 0xf9 && 3159251538Srpaulo prog[i].regs[j] <= 0xfe) { 3160251538Srpaulo /* 3161251538Srpaulo * These are fake RF registers offsets that 3162251538Srpaulo * indicate a delay is required. 3163251538Srpaulo */ 3164266472Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 20); /* 50ms */ 3165251538Srpaulo continue; 3166251538Srpaulo } 3167251538Srpaulo urtwn_rf_write(sc, i, prog[i].regs[j], 3168251538Srpaulo prog[i].vals[j]); 3169266472Shselasky urtwn_ms_delay(sc); 3170251538Srpaulo } 3171251538Srpaulo 3172251538Srpaulo /* Restore RF_ENV control type. */ 3173251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); 3174251538Srpaulo reg &= ~(0x10 << off) | (type << off); 3175251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg); 3176251538Srpaulo 3177251538Srpaulo /* Cache RF register CHNLBW. */ 3178251538Srpaulo sc->rf_chnlbw[i] = urtwn_rf_read(sc, i, R92C_RF_CHNLBW); 3179251538Srpaulo } 3180251538Srpaulo 3181251538Srpaulo if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == 3182251538Srpaulo URTWN_CHIP_UMC_A_CUT) { 3183251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); 3184251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00); 3185251538Srpaulo } 3186251538Srpaulo} 3187251538Srpaulo 3188251538Srpaulostatic void 3189251538Srpaulourtwn_cam_init(struct urtwn_softc *sc) 3190251538Srpaulo{ 3191251538Srpaulo /* Invalidate all CAM entries. */ 3192251538Srpaulo urtwn_write_4(sc, R92C_CAMCMD, 3193251538Srpaulo R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); 3194251538Srpaulo} 3195251538Srpaulo 3196251538Srpaulostatic void 3197251538Srpaulourtwn_pa_bias_init(struct urtwn_softc *sc) 3198251538Srpaulo{ 3199251538Srpaulo uint8_t reg; 3200251538Srpaulo int i; 3201251538Srpaulo 3202251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3203251538Srpaulo if (sc->pa_setting & (1 << i)) 3204251538Srpaulo continue; 3205251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406); 3206251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406); 3207251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406); 3208251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406); 3209251538Srpaulo } 3210251538Srpaulo if (!(sc->pa_setting & 0x10)) { 3211251538Srpaulo reg = urtwn_read_1(sc, 0x16); 3212251538Srpaulo reg = (reg & ~0xf0) | 0x90; 3213251538Srpaulo urtwn_write_1(sc, 0x16, reg); 3214251538Srpaulo } 3215251538Srpaulo} 3216251538Srpaulo 3217251538Srpaulostatic void 3218251538Srpaulourtwn_rxfilter_init(struct urtwn_softc *sc) 3219251538Srpaulo{ 3220290564Savos struct ieee80211com *ic = &sc->sc_ic; 3221290564Savos struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3222290564Savos uint32_t rcr; 3223290564Savos uint16_t filter; 3224290564Savos 3225290564Savos URTWN_ASSERT_LOCKED(sc); 3226290564Savos 3227251538Srpaulo /* Accept all multicast frames. */ 3228251538Srpaulo urtwn_write_4(sc, R92C_MAR + 0, 0xffffffff); 3229251538Srpaulo urtwn_write_4(sc, R92C_MAR + 4, 0xffffffff); 3230290564Savos 3231290564Savos /* Filter for management frames. */ 3232290564Savos filter = 0x7f3f; 3233290631Savos switch (vap->iv_opmode) { 3234290631Savos case IEEE80211_M_STA: 3235290564Savos filter &= ~( 3236290564Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | 3237290564Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | 3238290564Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); 3239290631Savos break; 3240290631Savos case IEEE80211_M_HOSTAP: 3241290631Savos filter &= ~( 3242290631Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | 3243290631Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP) | 3244290631Savos R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_BEACON)); 3245290631Savos break; 3246290631Savos case IEEE80211_M_MONITOR: 3247290651Savos case IEEE80211_M_IBSS: 3248290631Savos break; 3249290631Savos default: 3250290631Savos device_printf(sc->sc_dev, "%s: undefined opmode %d\n", 3251290631Savos __func__, vap->iv_opmode); 3252290631Savos break; 3253290564Savos } 3254290564Savos urtwn_write_2(sc, R92C_RXFLTMAP0, filter); 3255290564Savos 3256251538Srpaulo /* Reject all control frames. */ 3257251538Srpaulo urtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); 3258290564Savos 3259290564Savos /* Reject all data frames. */ 3260290564Savos urtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); 3261290564Savos 3262290564Savos rcr = R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | 3263290564Savos R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | 3264290564Savos R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; 3265290564Savos 3266290564Savos if (vap->iv_opmode == IEEE80211_M_MONITOR) { 3267290564Savos /* Accept all frames. */ 3268290564Savos rcr |= R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | 3269290564Savos R92C_RCR_AAP; 3270290564Savos } 3271290564Savos 3272290564Savos /* Set Rx filter. */ 3273290564Savos urtwn_write_4(sc, R92C_RCR, rcr); 3274290564Savos 3275290564Savos if (ic->ic_promisc != 0) { 3276290564Savos /* Update Rx filter. */ 3277290564Savos urtwn_set_promisc(sc); 3278290564Savos } 3279251538Srpaulo} 3280251538Srpaulo 3281251538Srpaulostatic void 3282251538Srpaulourtwn_edca_init(struct urtwn_softc *sc) 3283251538Srpaulo{ 3284251538Srpaulo urtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a); 3285251538Srpaulo urtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a); 3286251538Srpaulo urtwn_write_2(sc, R92C_SIFS_CCK, 0x100a); 3287251538Srpaulo urtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a); 3288251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); 3289251538Srpaulo urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); 3290251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324); 3291251538Srpaulo urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226); 3292251538Srpaulo} 3293251538Srpaulo 3294289066Skevlostatic void 3295251538Srpaulourtwn_write_txpower(struct urtwn_softc *sc, int chain, 3296251538Srpaulo uint16_t power[URTWN_RIDX_COUNT]) 3297251538Srpaulo{ 3298251538Srpaulo uint32_t reg; 3299251538Srpaulo 3300251538Srpaulo /* Write per-CCK rate Tx power. */ 3301251538Srpaulo if (chain == 0) { 3302251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); 3303251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]); 3304251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); 3305251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); 3306251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]); 3307251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]); 3308251538Srpaulo reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]); 3309251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); 3310251538Srpaulo } else { 3311251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); 3312251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]); 3313251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]); 3314251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]); 3315251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); 3316251538Srpaulo reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); 3317251538Srpaulo reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]); 3318251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); 3319251538Srpaulo } 3320251538Srpaulo /* Write per-OFDM rate Tx power. */ 3321251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), 3322251538Srpaulo SM(R92C_TXAGC_RATE06, power[ 4]) | 3323251538Srpaulo SM(R92C_TXAGC_RATE09, power[ 5]) | 3324251538Srpaulo SM(R92C_TXAGC_RATE12, power[ 6]) | 3325251538Srpaulo SM(R92C_TXAGC_RATE18, power[ 7])); 3326251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), 3327251538Srpaulo SM(R92C_TXAGC_RATE24, power[ 8]) | 3328251538Srpaulo SM(R92C_TXAGC_RATE36, power[ 9]) | 3329251538Srpaulo SM(R92C_TXAGC_RATE48, power[10]) | 3330251538Srpaulo SM(R92C_TXAGC_RATE54, power[11])); 3331251538Srpaulo /* Write per-MCS Tx power. */ 3332251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), 3333251538Srpaulo SM(R92C_TXAGC_MCS00, power[12]) | 3334251538Srpaulo SM(R92C_TXAGC_MCS01, power[13]) | 3335251538Srpaulo SM(R92C_TXAGC_MCS02, power[14]) | 3336251538Srpaulo SM(R92C_TXAGC_MCS03, power[15])); 3337251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), 3338251538Srpaulo SM(R92C_TXAGC_MCS04, power[16]) | 3339251538Srpaulo SM(R92C_TXAGC_MCS05, power[17]) | 3340251538Srpaulo SM(R92C_TXAGC_MCS06, power[18]) | 3341251538Srpaulo SM(R92C_TXAGC_MCS07, power[19])); 3342251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), 3343251538Srpaulo SM(R92C_TXAGC_MCS08, power[20]) | 3344261506Skevlo SM(R92C_TXAGC_MCS09, power[21]) | 3345251538Srpaulo SM(R92C_TXAGC_MCS10, power[22]) | 3346251538Srpaulo SM(R92C_TXAGC_MCS11, power[23])); 3347251538Srpaulo urtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), 3348251538Srpaulo SM(R92C_TXAGC_MCS12, power[24]) | 3349251538Srpaulo SM(R92C_TXAGC_MCS13, power[25]) | 3350251538Srpaulo SM(R92C_TXAGC_MCS14, power[26]) | 3351251538Srpaulo SM(R92C_TXAGC_MCS15, power[27])); 3352251538Srpaulo} 3353251538Srpaulo 3354289066Skevlostatic void 3355251538Srpaulourtwn_get_txpower(struct urtwn_softc *sc, int chain, 3356251538Srpaulo struct ieee80211_channel *c, struct ieee80211_channel *extc, 3357251538Srpaulo uint16_t power[URTWN_RIDX_COUNT]) 3358251538Srpaulo{ 3359287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3360291264Savos struct r92c_rom *rom = &sc->rom.r92c_rom; 3361251538Srpaulo uint16_t cckpow, ofdmpow, htpow, diff, max; 3362251538Srpaulo const struct urtwn_txpwr *base; 3363251538Srpaulo int ridx, chan, group; 3364251538Srpaulo 3365251538Srpaulo /* Determine channel group. */ 3366251538Srpaulo chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ 3367251538Srpaulo if (chan <= 3) 3368251538Srpaulo group = 0; 3369251538Srpaulo else if (chan <= 9) 3370251538Srpaulo group = 1; 3371251538Srpaulo else 3372251538Srpaulo group = 2; 3373251538Srpaulo 3374251538Srpaulo /* Get original Tx power based on board type and RF chain. */ 3375251538Srpaulo if (!(sc->chip & URTWN_CHIP_92C)) { 3376251538Srpaulo if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) 3377251538Srpaulo base = &rtl8188ru_txagc[chain]; 3378251538Srpaulo else 3379251538Srpaulo base = &rtl8192cu_txagc[chain]; 3380251538Srpaulo } else 3381251538Srpaulo base = &rtl8192cu_txagc[chain]; 3382251538Srpaulo 3383251538Srpaulo memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0])); 3384251538Srpaulo if (sc->regulatory == 0) { 3385289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) 3386251538Srpaulo power[ridx] = base->pwr[0][ridx]; 3387251538Srpaulo } 3388289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) { 3389251538Srpaulo if (sc->regulatory == 3) { 3390251538Srpaulo power[ridx] = base->pwr[0][ridx]; 3391251538Srpaulo /* Apply vendor limits. */ 3392251538Srpaulo if (extc != NULL) 3393251538Srpaulo max = rom->ht40_max_pwr[group]; 3394251538Srpaulo else 3395251538Srpaulo max = rom->ht20_max_pwr[group]; 3396251538Srpaulo max = (max >> (chain * 4)) & 0xf; 3397251538Srpaulo if (power[ridx] > max) 3398251538Srpaulo power[ridx] = max; 3399251538Srpaulo } else if (sc->regulatory == 1) { 3400251538Srpaulo if (extc == NULL) 3401251538Srpaulo power[ridx] = base->pwr[group][ridx]; 3402251538Srpaulo } else if (sc->regulatory != 2) 3403251538Srpaulo power[ridx] = base->pwr[0][ridx]; 3404251538Srpaulo } 3405251538Srpaulo 3406251538Srpaulo /* Compute per-CCK rate Tx power. */ 3407251538Srpaulo cckpow = rom->cck_tx_pwr[chain][group]; 3408289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) { 3409251538Srpaulo power[ridx] += cckpow; 3410251538Srpaulo if (power[ridx] > R92C_MAX_TX_PWR) 3411251538Srpaulo power[ridx] = R92C_MAX_TX_PWR; 3412251538Srpaulo } 3413251538Srpaulo 3414251538Srpaulo htpow = rom->ht40_1s_tx_pwr[chain][group]; 3415251538Srpaulo if (sc->ntxchains > 1) { 3416251538Srpaulo /* Apply reduction for 2 spatial streams. */ 3417251538Srpaulo diff = rom->ht40_2s_tx_pwr_diff[group]; 3418251538Srpaulo diff = (diff >> (chain * 4)) & 0xf; 3419251538Srpaulo htpow = (htpow > diff) ? htpow - diff : 0; 3420251538Srpaulo } 3421251538Srpaulo 3422251538Srpaulo /* Compute per-OFDM rate Tx power. */ 3423251538Srpaulo diff = rom->ofdm_tx_pwr_diff[group]; 3424251538Srpaulo diff = (diff >> (chain * 4)) & 0xf; 3425251538Srpaulo ofdmpow = htpow + diff; /* HT->OFDM correction. */ 3426289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) { 3427251538Srpaulo power[ridx] += ofdmpow; 3428251538Srpaulo if (power[ridx] > R92C_MAX_TX_PWR) 3429251538Srpaulo power[ridx] = R92C_MAX_TX_PWR; 3430251538Srpaulo } 3431251538Srpaulo 3432251538Srpaulo /* Compute per-MCS Tx power. */ 3433251538Srpaulo if (extc == NULL) { 3434251538Srpaulo diff = rom->ht20_tx_pwr_diff[group]; 3435251538Srpaulo diff = (diff >> (chain * 4)) & 0xf; 3436251538Srpaulo htpow += diff; /* HT40->HT20 correction. */ 3437251538Srpaulo } 3438251538Srpaulo for (ridx = 12; ridx <= 27; ridx++) { 3439251538Srpaulo power[ridx] += htpow; 3440251538Srpaulo if (power[ridx] > R92C_MAX_TX_PWR) 3441251538Srpaulo power[ridx] = R92C_MAX_TX_PWR; 3442251538Srpaulo } 3443251538Srpaulo#ifdef URTWN_DEBUG 3444251538Srpaulo if (urtwn_debug >= 4) { 3445251538Srpaulo /* Dump per-rate Tx power values. */ 3446251538Srpaulo printf("Tx power for chain %d:\n", chain); 3447289758Savos for (ridx = URTWN_RIDX_CCK1; ridx < URTWN_RIDX_COUNT; ridx++) 3448251538Srpaulo printf("Rate %d = %u\n", ridx, power[ridx]); 3449251538Srpaulo } 3450251538Srpaulo#endif 3451251538Srpaulo} 3452251538Srpaulo 3453289066Skevlostatic void 3454264912Skevlourtwn_r88e_get_txpower(struct urtwn_softc *sc, int chain, 3455264912Skevlo struct ieee80211_channel *c, struct ieee80211_channel *extc, 3456264912Skevlo uint16_t power[URTWN_RIDX_COUNT]) 3457264912Skevlo{ 3458287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3459264912Skevlo uint16_t cckpow, ofdmpow, bw20pow, htpow; 3460264912Skevlo const struct urtwn_r88e_txpwr *base; 3461264912Skevlo int ridx, chan, group; 3462264912Skevlo 3463264912Skevlo /* Determine channel group. */ 3464264912Skevlo chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ 3465264912Skevlo if (chan <= 2) 3466264912Skevlo group = 0; 3467264912Skevlo else if (chan <= 5) 3468264912Skevlo group = 1; 3469264912Skevlo else if (chan <= 8) 3470264912Skevlo group = 2; 3471264912Skevlo else if (chan <= 11) 3472264912Skevlo group = 3; 3473264912Skevlo else if (chan <= 13) 3474264912Skevlo group = 4; 3475264912Skevlo else 3476264912Skevlo group = 5; 3477264912Skevlo 3478264912Skevlo /* Get original Tx power based on board type and RF chain. */ 3479264912Skevlo base = &rtl8188eu_txagc[chain]; 3480264912Skevlo 3481264912Skevlo memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0])); 3482264912Skevlo if (sc->regulatory == 0) { 3483289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) 3484264912Skevlo power[ridx] = base->pwr[0][ridx]; 3485264912Skevlo } 3486289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) { 3487264912Skevlo if (sc->regulatory == 3) 3488264912Skevlo power[ridx] = base->pwr[0][ridx]; 3489264912Skevlo else if (sc->regulatory == 1) { 3490264912Skevlo if (extc == NULL) 3491264912Skevlo power[ridx] = base->pwr[group][ridx]; 3492264912Skevlo } else if (sc->regulatory != 2) 3493264912Skevlo power[ridx] = base->pwr[0][ridx]; 3494264912Skevlo } 3495264912Skevlo 3496264912Skevlo /* Compute per-CCK rate Tx power. */ 3497264912Skevlo cckpow = sc->cck_tx_pwr[group]; 3498289758Savos for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) { 3499264912Skevlo power[ridx] += cckpow; 3500264912Skevlo if (power[ridx] > R92C_MAX_TX_PWR) 3501264912Skevlo power[ridx] = R92C_MAX_TX_PWR; 3502264912Skevlo } 3503264912Skevlo 3504264912Skevlo htpow = sc->ht40_tx_pwr[group]; 3505264912Skevlo 3506264912Skevlo /* Compute per-OFDM rate Tx power. */ 3507264912Skevlo ofdmpow = htpow + sc->ofdm_tx_pwr_diff; 3508289758Savos for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) { 3509264912Skevlo power[ridx] += ofdmpow; 3510264912Skevlo if (power[ridx] > R92C_MAX_TX_PWR) 3511264912Skevlo power[ridx] = R92C_MAX_TX_PWR; 3512264912Skevlo } 3513264912Skevlo 3514264912Skevlo bw20pow = htpow + sc->bw20_tx_pwr_diff; 3515264912Skevlo for (ridx = 12; ridx <= 27; ridx++) { 3516264912Skevlo power[ridx] += bw20pow; 3517264912Skevlo if (power[ridx] > R92C_MAX_TX_PWR) 3518264912Skevlo power[ridx] = R92C_MAX_TX_PWR; 3519264912Skevlo } 3520264912Skevlo} 3521264912Skevlo 3522289066Skevlostatic void 3523251538Srpaulourtwn_set_txpower(struct urtwn_softc *sc, struct ieee80211_channel *c, 3524251538Srpaulo struct ieee80211_channel *extc) 3525251538Srpaulo{ 3526251538Srpaulo uint16_t power[URTWN_RIDX_COUNT]; 3527251538Srpaulo int i; 3528251538Srpaulo 3529251538Srpaulo for (i = 0; i < sc->ntxchains; i++) { 3530251538Srpaulo /* Compute per-rate Tx power values. */ 3531264912Skevlo if (sc->chip & URTWN_CHIP_88E) 3532264912Skevlo urtwn_r88e_get_txpower(sc, i, c, extc, power); 3533264912Skevlo else 3534264912Skevlo urtwn_get_txpower(sc, i, c, extc, power); 3535251538Srpaulo /* Write per-rate Tx power values to hardware. */ 3536251538Srpaulo urtwn_write_txpower(sc, i, power); 3537251538Srpaulo } 3538251538Srpaulo} 3539251538Srpaulo 3540251538Srpaulostatic void 3541290048Savosurtwn_set_rx_bssid_all(struct urtwn_softc *sc, int enable) 3542290048Savos{ 3543290048Savos uint32_t reg; 3544290048Savos 3545290048Savos reg = urtwn_read_4(sc, R92C_RCR); 3546290048Savos if (enable) 3547290048Savos reg &= ~R92C_RCR_CBSSID_BCN; 3548290048Savos else 3549290048Savos reg |= R92C_RCR_CBSSID_BCN; 3550290048Savos urtwn_write_4(sc, R92C_RCR, reg); 3551290048Savos} 3552290048Savos 3553290048Savosstatic void 3554290048Savosurtwn_set_gain(struct urtwn_softc *sc, uint8_t gain) 3555290048Savos{ 3556290048Savos uint32_t reg; 3557290048Savos 3558290048Savos reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); 3559290048Savos reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); 3560290048Savos urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); 3561290048Savos 3562290048Savos if (!(sc->chip & URTWN_CHIP_88E)) { 3563290048Savos reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); 3564290048Savos reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); 3565290048Savos urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); 3566290048Savos } 3567290048Savos} 3568290048Savos 3569290048Savosstatic void 3570251538Srpaulourtwn_scan_start(struct ieee80211com *ic) 3571251538Srpaulo{ 3572290048Savos struct urtwn_softc *sc = ic->ic_softc; 3573290048Savos 3574290048Savos URTWN_LOCK(sc); 3575290048Savos /* Receive beacons / probe responses from any BSSID. */ 3576290651Savos if (ic->ic_opmode != IEEE80211_M_IBSS) 3577290651Savos urtwn_set_rx_bssid_all(sc, 1); 3578290651Savos 3579290048Savos /* Set gain for scanning. */ 3580290048Savos urtwn_set_gain(sc, 0x20); 3581290048Savos URTWN_UNLOCK(sc); 3582251538Srpaulo} 3583251538Srpaulo 3584251538Srpaulostatic void 3585251538Srpaulourtwn_scan_end(struct ieee80211com *ic) 3586251538Srpaulo{ 3587290048Savos struct urtwn_softc *sc = ic->ic_softc; 3588290048Savos 3589290048Savos URTWN_LOCK(sc); 3590290048Savos /* Restore limitations. */ 3591290651Savos if (ic->ic_promisc == 0 && ic->ic_opmode != IEEE80211_M_IBSS) 3592290564Savos urtwn_set_rx_bssid_all(sc, 0); 3593290651Savos 3594290048Savos /* Set gain under link. */ 3595290048Savos urtwn_set_gain(sc, 0x32); 3596290048Savos URTWN_UNLOCK(sc); 3597251538Srpaulo} 3598251538Srpaulo 3599251538Srpaulostatic void 3600251538Srpaulourtwn_set_channel(struct ieee80211com *ic) 3601251538Srpaulo{ 3602286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 3603281070Srpaulo struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3604251538Srpaulo 3605251538Srpaulo URTWN_LOCK(sc); 3606281070Srpaulo if (vap->iv_state == IEEE80211_S_SCAN) { 3607281070Srpaulo /* Make link LED blink during scan. */ 3608281070Srpaulo urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink); 3609281070Srpaulo } 3610251538Srpaulo urtwn_set_chan(sc, ic->ic_curchan, NULL); 3611251538Srpaulo URTWN_UNLOCK(sc); 3612251538Srpaulo} 3613251538Srpaulo 3614292014Savosstatic int 3615292014Savosurtwn_wme_update(struct ieee80211com *ic) 3616292014Savos{ 3617292014Savos const struct wmeParams *wmep = 3618292014Savos ic->ic_wme.wme_chanParams.cap_wmeParams; 3619292014Savos struct urtwn_softc *sc = ic->ic_softc; 3620292014Savos uint8_t aifs, acm, slottime; 3621292014Savos int ac; 3622292014Savos 3623292014Savos acm = 0; 3624292014Savos slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 3625292014Savos IEEE80211_DUR_SHSLOT : IEEE80211_DUR_SLOT; 3626292014Savos 3627292014Savos URTWN_LOCK(sc); 3628292014Savos for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { 3629292014Savos /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ 3630292014Savos aifs = wmep[ac].wmep_aifsn * slottime + IEEE80211_DUR_SIFS; 3631292014Savos urtwn_write_4(sc, wme2queue[ac].reg, 3632292014Savos SM(R92C_EDCA_PARAM_TXOP, wmep[ac].wmep_txopLimit) | 3633292014Savos SM(R92C_EDCA_PARAM_ECWMIN, wmep[ac].wmep_logcwmin) | 3634292014Savos SM(R92C_EDCA_PARAM_ECWMAX, wmep[ac].wmep_logcwmax) | 3635292014Savos SM(R92C_EDCA_PARAM_AIFS, aifs)); 3636292014Savos if (ac != WME_AC_BE) 3637292014Savos acm |= wmep[ac].wmep_acm << ac; 3638292014Savos } 3639292014Savos 3640292014Savos if (acm != 0) 3641292014Savos acm |= R92C_ACMHWCTRL_EN; 3642292014Savos urtwn_write_1(sc, R92C_ACMHWCTRL, 3643292014Savos (urtwn_read_1(sc, R92C_ACMHWCTRL) & ~R92C_ACMHWCTRL_ACM_MASK) | 3644292014Savos acm); 3645292014Savos 3646292014Savos URTWN_UNLOCK(sc); 3647292014Savos 3648292014Savos return 0; 3649292014Savos} 3650292014Savos 3651251538Srpaulostatic void 3652290564Savosurtwn_set_promisc(struct urtwn_softc *sc) 3653290564Savos{ 3654290564Savos struct ieee80211com *ic = &sc->sc_ic; 3655290564Savos struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3656290564Savos uint32_t rcr, mask1, mask2; 3657290564Savos 3658290564Savos URTWN_ASSERT_LOCKED(sc); 3659290564Savos 3660290564Savos if (vap->iv_opmode == IEEE80211_M_MONITOR) 3661290564Savos return; 3662290564Savos 3663290564Savos mask1 = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; 3664290564Savos mask2 = R92C_RCR_APM; 3665290564Savos 3666290564Savos if (vap->iv_state == IEEE80211_S_RUN) { 3667290564Savos switch (vap->iv_opmode) { 3668290564Savos case IEEE80211_M_STA: 3669290631Savos mask2 |= R92C_RCR_CBSSID_DATA; 3670290631Savos /* FALLTHROUGH */ 3671290631Savos case IEEE80211_M_HOSTAP: 3672290631Savos mask2 |= R92C_RCR_CBSSID_BCN; 3673290564Savos break; 3674290651Savos case IEEE80211_M_IBSS: 3675290651Savos mask2 |= R92C_RCR_CBSSID_DATA; 3676290651Savos break; 3677290564Savos default: 3678290564Savos device_printf(sc->sc_dev, "%s: undefined opmode %d\n", 3679290564Savos __func__, vap->iv_opmode); 3680290564Savos return; 3681290564Savos } 3682290564Savos } 3683290564Savos 3684290564Savos rcr = urtwn_read_4(sc, R92C_RCR); 3685290564Savos if (ic->ic_promisc == 0) 3686290564Savos rcr = (rcr & ~mask1) | mask2; 3687290564Savos else 3688290564Savos rcr = (rcr & ~mask2) | mask1; 3689290564Savos urtwn_write_4(sc, R92C_RCR, rcr); 3690290564Savos} 3691290564Savos 3692290564Savosstatic void 3693290564Savosurtwn_update_promisc(struct ieee80211com *ic) 3694290564Savos{ 3695290564Savos struct urtwn_softc *sc = ic->ic_softc; 3696290564Savos 3697290564Savos URTWN_LOCK(sc); 3698290564Savos if (sc->sc_flags & URTWN_RUNNING) 3699290564Savos urtwn_set_promisc(sc); 3700290564Savos URTWN_UNLOCK(sc); 3701290564Savos} 3702290564Savos 3703290564Savosstatic void 3704283540Sglebiusurtwn_update_mcast(struct ieee80211com *ic) 3705251538Srpaulo{ 3706251538Srpaulo /* XXX do nothing? */ 3707251538Srpaulo} 3708251538Srpaulo 3709251538Srpaulostatic void 3710251538Srpaulourtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c, 3711251538Srpaulo struct ieee80211_channel *extc) 3712251538Srpaulo{ 3713287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3714251538Srpaulo uint32_t reg; 3715251538Srpaulo u_int chan; 3716251538Srpaulo int i; 3717251538Srpaulo 3718251538Srpaulo chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ 3719251538Srpaulo if (chan == 0 || chan == IEEE80211_CHAN_ANY) { 3720251538Srpaulo device_printf(sc->sc_dev, 3721251538Srpaulo "%s: invalid channel %x\n", __func__, chan); 3722251538Srpaulo return; 3723251538Srpaulo } 3724251538Srpaulo 3725251538Srpaulo /* Set Tx power for this new channel. */ 3726251538Srpaulo urtwn_set_txpower(sc, c, extc); 3727251538Srpaulo 3728251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3729251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_CHNLBW, 3730251538Srpaulo RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); 3731251538Srpaulo } 3732251538Srpaulo#ifndef IEEE80211_NO_HT 3733251538Srpaulo if (extc != NULL) { 3734251538Srpaulo /* Is secondary channel below or above primary? */ 3735251538Srpaulo int prichlo = c->ic_freq < extc->ic_freq; 3736251538Srpaulo 3737251538Srpaulo urtwn_write_1(sc, R92C_BWOPMODE, 3738251538Srpaulo urtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ); 3739251538Srpaulo 3740251538Srpaulo reg = urtwn_read_1(sc, R92C_RRSR + 2); 3741251538Srpaulo reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5; 3742251538Srpaulo urtwn_write_1(sc, R92C_RRSR + 2, reg); 3743251538Srpaulo 3744251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFMOD, 3745251538Srpaulo urtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ); 3746251538Srpaulo urtwn_bb_write(sc, R92C_FPGA1_RFMOD, 3747251538Srpaulo urtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ); 3748251538Srpaulo 3749251538Srpaulo /* Set CCK side band. */ 3750251538Srpaulo reg = urtwn_bb_read(sc, R92C_CCK0_SYSTEM); 3751251538Srpaulo reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4; 3752251538Srpaulo urtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg); 3753251538Srpaulo 3754251538Srpaulo reg = urtwn_bb_read(sc, R92C_OFDM1_LSTF); 3755251538Srpaulo reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10; 3756251538Srpaulo urtwn_bb_write(sc, R92C_OFDM1_LSTF, reg); 3757251538Srpaulo 3758251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, 3759251538Srpaulo urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) & 3760251538Srpaulo ~R92C_FPGA0_ANAPARAM2_CBW20); 3761251538Srpaulo 3762251538Srpaulo reg = urtwn_bb_read(sc, 0x818); 3763251538Srpaulo reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26; 3764251538Srpaulo urtwn_bb_write(sc, 0x818, reg); 3765251538Srpaulo 3766251538Srpaulo /* Select 40MHz bandwidth. */ 3767251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, 3768251538Srpaulo (sc->rf_chnlbw[0] & ~0xfff) | chan); 3769251538Srpaulo } else 3770251538Srpaulo#endif 3771251538Srpaulo { 3772251538Srpaulo urtwn_write_1(sc, R92C_BWOPMODE, 3773251538Srpaulo urtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ); 3774251538Srpaulo 3775251538Srpaulo urtwn_bb_write(sc, R92C_FPGA0_RFMOD, 3776251538Srpaulo urtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ); 3777251538Srpaulo urtwn_bb_write(sc, R92C_FPGA1_RFMOD, 3778251538Srpaulo urtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ); 3779251538Srpaulo 3780264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 3781264912Skevlo urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, 3782264912Skevlo urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) | 3783264912Skevlo R92C_FPGA0_ANAPARAM2_CBW20); 3784264912Skevlo } 3785281069Srpaulo 3786251538Srpaulo /* Select 20MHz bandwidth. */ 3787251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, 3788281069Srpaulo (sc->rf_chnlbw[0] & ~0xfff) | chan | 3789264912Skevlo ((sc->chip & URTWN_CHIP_88E) ? R88E_RF_CHNLBW_BW20 : 3790264912Skevlo R92C_RF_CHNLBW_BW20)); 3791251538Srpaulo } 3792251538Srpaulo} 3793251538Srpaulo 3794251538Srpaulostatic void 3795251538Srpaulourtwn_iq_calib(struct urtwn_softc *sc) 3796251538Srpaulo{ 3797251538Srpaulo /* TODO */ 3798251538Srpaulo} 3799251538Srpaulo 3800251538Srpaulostatic void 3801251538Srpaulourtwn_lc_calib(struct urtwn_softc *sc) 3802251538Srpaulo{ 3803251538Srpaulo uint32_t rf_ac[2]; 3804251538Srpaulo uint8_t txmode; 3805251538Srpaulo int i; 3806251538Srpaulo 3807251538Srpaulo txmode = urtwn_read_1(sc, R92C_OFDM1_LSTF + 3); 3808251538Srpaulo if ((txmode & 0x70) != 0) { 3809251538Srpaulo /* Disable all continuous Tx. */ 3810251538Srpaulo urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70); 3811251538Srpaulo 3812251538Srpaulo /* Set RF mode to standby mode. */ 3813251538Srpaulo for (i = 0; i < sc->nrxchains; i++) { 3814251538Srpaulo rf_ac[i] = urtwn_rf_read(sc, i, R92C_RF_AC); 3815251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_AC, 3816251538Srpaulo RW(rf_ac[i], R92C_RF_AC_MODE, 3817251538Srpaulo R92C_RF_AC_MODE_STANDBY)); 3818251538Srpaulo } 3819251538Srpaulo } else { 3820251538Srpaulo /* Block all Tx queues. */ 3821251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 0xff); 3822251538Srpaulo } 3823251538Srpaulo /* Start calibration. */ 3824251538Srpaulo urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, 3825251538Srpaulo urtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART); 3826251538Srpaulo 3827251538Srpaulo /* Give calibration the time to complete. */ 3828266472Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 10); /* 100ms */ 3829251538Srpaulo 3830251538Srpaulo /* Restore configuration. */ 3831251538Srpaulo if ((txmode & 0x70) != 0) { 3832251538Srpaulo /* Restore Tx mode. */ 3833251538Srpaulo urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode); 3834251538Srpaulo /* Restore RF mode. */ 3835251538Srpaulo for (i = 0; i < sc->nrxchains; i++) 3836251538Srpaulo urtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); 3837251538Srpaulo } else { 3838251538Srpaulo /* Unblock all Tx queues. */ 3839251538Srpaulo urtwn_write_1(sc, R92C_TXPAUSE, 0x00); 3840251538Srpaulo } 3841251538Srpaulo} 3842251538Srpaulo 3843291698Savosstatic int 3844287197Sglebiusurtwn_init(struct urtwn_softc *sc) 3845251538Srpaulo{ 3846287197Sglebius struct ieee80211com *ic = &sc->sc_ic; 3847287197Sglebius struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 3848287197Sglebius uint8_t macaddr[IEEE80211_ADDR_LEN]; 3849251538Srpaulo uint32_t reg; 3850291698Savos usb_error_t usb_err = USB_ERR_NORMAL_COMPLETION; 3851251538Srpaulo int error; 3852251538Srpaulo 3853291698Savos URTWN_LOCK(sc); 3854291698Savos if (sc->sc_flags & URTWN_RUNNING) { 3855291698Savos URTWN_UNLOCK(sc); 3856291698Savos return (0); 3857291698Savos } 3858264864Skevlo 3859251538Srpaulo /* Init firmware commands ring. */ 3860251538Srpaulo sc->fwcur = 0; 3861251538Srpaulo 3862251538Srpaulo /* Allocate Tx/Rx buffers. */ 3863251538Srpaulo error = urtwn_alloc_rx_list(sc); 3864251538Srpaulo if (error != 0) 3865251538Srpaulo goto fail; 3866281069Srpaulo 3867251538Srpaulo error = urtwn_alloc_tx_list(sc); 3868251538Srpaulo if (error != 0) 3869251538Srpaulo goto fail; 3870251538Srpaulo 3871251538Srpaulo /* Power on adapter. */ 3872251538Srpaulo error = urtwn_power_on(sc); 3873251538Srpaulo if (error != 0) 3874251538Srpaulo goto fail; 3875251538Srpaulo 3876251538Srpaulo /* Initialize DMA. */ 3877251538Srpaulo error = urtwn_dma_init(sc); 3878251538Srpaulo if (error != 0) 3879251538Srpaulo goto fail; 3880251538Srpaulo 3881251538Srpaulo /* Set info size in Rx descriptors (in 64-bit words). */ 3882251538Srpaulo urtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4); 3883251538Srpaulo 3884251538Srpaulo /* Init interrupts. */ 3885264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 3886291698Savos usb_err = urtwn_write_4(sc, R88E_HISR, 0xffffffff); 3887291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 3888291698Savos goto fail; 3889291698Savos usb_err = urtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | R88E_HIMR_CPWM2 | 3890264912Skevlo R88E_HIMR_TBDER | R88E_HIMR_PSTIMEOUT); 3891291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 3892291698Savos goto fail; 3893291698Savos usb_err = urtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW | 3894264912Skevlo R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | R88E_HIMRE_TXERR); 3895291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 3896291698Savos goto fail; 3897291698Savos usb_err = urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, 3898264912Skevlo urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | 3899264912Skevlo R92C_USB_SPECIAL_OPTION_INT_BULK_SEL); 3900291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 3901291698Savos goto fail; 3902264912Skevlo } else { 3903291698Savos usb_err = urtwn_write_4(sc, R92C_HISR, 0xffffffff); 3904291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 3905291698Savos goto fail; 3906291698Savos usb_err = urtwn_write_4(sc, R92C_HIMR, 0xffffffff); 3907291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 3908291698Savos goto fail; 3909264912Skevlo } 3910251538Srpaulo 3911251538Srpaulo /* Set MAC address. */ 3912287197Sglebius IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); 3913291698Savos usb_err = urtwn_write_region_1(sc, R92C_MACID, macaddr, IEEE80211_ADDR_LEN); 3914291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 3915291698Savos goto fail; 3916251538Srpaulo 3917251538Srpaulo /* Set initial network type. */ 3918289811Savos urtwn_set_mode(sc, R92C_MSR_INFRA); 3919251538Srpaulo 3920290564Savos /* Initialize Rx filter. */ 3921251538Srpaulo urtwn_rxfilter_init(sc); 3922251538Srpaulo 3923282623Skevlo /* Set response rate. */ 3924251538Srpaulo reg = urtwn_read_4(sc, R92C_RRSR); 3925251538Srpaulo reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_CCK_ONLY_1M); 3926251538Srpaulo urtwn_write_4(sc, R92C_RRSR, reg); 3927251538Srpaulo 3928251538Srpaulo /* Set short/long retry limits. */ 3929251538Srpaulo urtwn_write_2(sc, R92C_RL, 3930251538Srpaulo SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30)); 3931251538Srpaulo 3932251538Srpaulo /* Initialize EDCA parameters. */ 3933251538Srpaulo urtwn_edca_init(sc); 3934251538Srpaulo 3935251538Srpaulo /* Setup rate fallback. */ 3936264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 3937264912Skevlo urtwn_write_4(sc, R92C_DARFRC + 0, 0x00000000); 3938264912Skevlo urtwn_write_4(sc, R92C_DARFRC + 4, 0x10080404); 3939264912Skevlo urtwn_write_4(sc, R92C_RARFRC + 0, 0x04030201); 3940264912Skevlo urtwn_write_4(sc, R92C_RARFRC + 4, 0x08070605); 3941264912Skevlo } 3942251538Srpaulo 3943251538Srpaulo urtwn_write_1(sc, R92C_FWHW_TXQ_CTRL, 3944251538Srpaulo urtwn_read_1(sc, R92C_FWHW_TXQ_CTRL) | 3945251538Srpaulo R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); 3946251538Srpaulo /* Set ACK timeout. */ 3947251538Srpaulo urtwn_write_1(sc, R92C_ACKTO, 0x40); 3948251538Srpaulo 3949251538Srpaulo /* Setup USB aggregation. */ 3950251538Srpaulo reg = urtwn_read_4(sc, R92C_TDECTRL); 3951251538Srpaulo reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, 6); 3952251538Srpaulo urtwn_write_4(sc, R92C_TDECTRL, reg); 3953251538Srpaulo urtwn_write_1(sc, R92C_TRXDMA_CTRL, 3954251538Srpaulo urtwn_read_1(sc, R92C_TRXDMA_CTRL) | 3955251538Srpaulo R92C_TRXDMA_CTRL_RXDMA_AGG_EN); 3956251538Srpaulo urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48); 3957264912Skevlo if (sc->chip & URTWN_CHIP_88E) 3958264912Skevlo urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4); 3959282266Skevlo else { 3960264912Skevlo urtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4); 3961282266Skevlo urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, 3962282266Skevlo urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | 3963282266Skevlo R92C_USB_SPECIAL_OPTION_AGG_EN); 3964282266Skevlo urtwn_write_1(sc, R92C_USB_AGG_TH, 8); 3965282266Skevlo urtwn_write_1(sc, R92C_USB_AGG_TO, 6); 3966282266Skevlo } 3967251538Srpaulo 3968251538Srpaulo /* Initialize beacon parameters. */ 3969264912Skevlo urtwn_write_2(sc, R92C_BCN_CTRL, 0x1010); 3970251538Srpaulo urtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); 3971251538Srpaulo urtwn_write_1(sc, R92C_DRVERLYINT, 0x05); 3972251538Srpaulo urtwn_write_1(sc, R92C_BCNDMATIM, 0x02); 3973251538Srpaulo urtwn_write_2(sc, R92C_BCNTCFG, 0x660f); 3974251538Srpaulo 3975264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 3976264912Skevlo /* Setup AMPDU aggregation. */ 3977264912Skevlo urtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ 3978264912Skevlo urtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); 3979264912Skevlo urtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0708); 3980251538Srpaulo 3981264912Skevlo urtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff); 3982264912Skevlo } 3983251538Srpaulo 3984251538Srpaulo /* Load 8051 microcode. */ 3985251538Srpaulo error = urtwn_load_firmware(sc); 3986251538Srpaulo if (error != 0) 3987251538Srpaulo goto fail; 3988251538Srpaulo 3989251538Srpaulo /* Initialize MAC/BB/RF blocks. */ 3990291698Savos error = urtwn_mac_init(sc); 3991291698Savos if (error != 0) { 3992291698Savos device_printf(sc->sc_dev, 3993291698Savos "%s: error while initializing MAC block\n", __func__); 3994291698Savos goto fail; 3995291698Savos } 3996251538Srpaulo urtwn_bb_init(sc); 3997251538Srpaulo urtwn_rf_init(sc); 3998251538Srpaulo 3999290564Savos /* Reinitialize Rx filter (D3845 is not committed yet). */ 4000290564Savos urtwn_rxfilter_init(sc); 4001290564Savos 4002264912Skevlo if (sc->chip & URTWN_CHIP_88E) { 4003264912Skevlo urtwn_write_2(sc, R92C_CR, 4004264912Skevlo urtwn_read_2(sc, R92C_CR) | R92C_CR_MACTXEN | 4005264912Skevlo R92C_CR_MACRXEN); 4006264912Skevlo } 4007264912Skevlo 4008251538Srpaulo /* Turn CCK and OFDM blocks on. */ 4009251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD); 4010251538Srpaulo reg |= R92C_RFMOD_CCK_EN; 4011291698Savos usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); 4012291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4013291698Savos goto fail; 4014251538Srpaulo reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD); 4015251538Srpaulo reg |= R92C_RFMOD_OFDM_EN; 4016291698Savos usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); 4017291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4018291698Savos goto fail; 4019251538Srpaulo 4020251538Srpaulo /* Clear per-station keys table. */ 4021251538Srpaulo urtwn_cam_init(sc); 4022251538Srpaulo 4023251538Srpaulo /* Enable hardware sequence numbering. */ 4024251538Srpaulo urtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff); 4025251538Srpaulo 4026251538Srpaulo /* Perform LO and IQ calibrations. */ 4027251538Srpaulo urtwn_iq_calib(sc); 4028251538Srpaulo /* Perform LC calibration. */ 4029251538Srpaulo urtwn_lc_calib(sc); 4030251538Srpaulo 4031251538Srpaulo /* Fix USB interference issue. */ 4032264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) { 4033264912Skevlo urtwn_write_1(sc, 0xfe40, 0xe0); 4034264912Skevlo urtwn_write_1(sc, 0xfe41, 0x8d); 4035264912Skevlo urtwn_write_1(sc, 0xfe42, 0x80); 4036251538Srpaulo 4037264912Skevlo urtwn_pa_bias_init(sc); 4038264912Skevlo } 4039251538Srpaulo 4040251538Srpaulo /* Initialize GPIO setting. */ 4041251538Srpaulo urtwn_write_1(sc, R92C_GPIO_MUXCFG, 4042251538Srpaulo urtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT); 4043251538Srpaulo 4044251538Srpaulo /* Fix for lower temperature. */ 4045264912Skevlo if (!(sc->chip & URTWN_CHIP_88E)) 4046264912Skevlo urtwn_write_1(sc, 0x15, 0xe9); 4047251538Srpaulo 4048251538Srpaulo usbd_transfer_start(sc->sc_xfer[URTWN_BULK_RX]); 4049251538Srpaulo 4050287197Sglebius sc->sc_flags |= URTWN_RUNNING; 4051251538Srpaulo 4052251538Srpaulo callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 4053251538Srpaulofail: 4054291698Savos if (usb_err != USB_ERR_NORMAL_COMPLETION) 4055291698Savos error = EIO; 4056291698Savos 4057291698Savos URTWN_UNLOCK(sc); 4058291698Savos 4059291698Savos return (error); 4060251538Srpaulo} 4061251538Srpaulo 4062251538Srpaulostatic void 4063287197Sglebiusurtwn_stop(struct urtwn_softc *sc) 4064251538Srpaulo{ 4065251538Srpaulo 4066291698Savos URTWN_LOCK(sc); 4067291698Savos if (!(sc->sc_flags & URTWN_RUNNING)) { 4068291698Savos URTWN_UNLOCK(sc); 4069291698Savos return; 4070291698Savos } 4071291698Savos 4072287197Sglebius sc->sc_flags &= ~URTWN_RUNNING; 4073251538Srpaulo callout_stop(&sc->sc_watchdog_ch); 4074251538Srpaulo urtwn_abort_xfers(sc); 4075288353Sadrian 4076288353Sadrian urtwn_drain_mbufq(sc); 4077291698Savos URTWN_UNLOCK(sc); 4078251538Srpaulo} 4079251538Srpaulo 4080251538Srpaulostatic void 4081251538Srpaulourtwn_abort_xfers(struct urtwn_softc *sc) 4082251538Srpaulo{ 4083251538Srpaulo int i; 4084251538Srpaulo 4085251538Srpaulo URTWN_ASSERT_LOCKED(sc); 4086251538Srpaulo 4087251538Srpaulo /* abort any pending transfers */ 4088251538Srpaulo for (i = 0; i < URTWN_N_TRANSFER; i++) 4089251538Srpaulo usbd_transfer_stop(sc->sc_xfer[i]); 4090251538Srpaulo} 4091251538Srpaulo 4092251538Srpaulostatic int 4093251538Srpaulourtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 4094251538Srpaulo const struct ieee80211_bpf_params *params) 4095251538Srpaulo{ 4096251538Srpaulo struct ieee80211com *ic = ni->ni_ic; 4097286949Sadrian struct urtwn_softc *sc = ic->ic_softc; 4098251538Srpaulo struct urtwn_data *bf; 4099290630Savos int error; 4100251538Srpaulo 4101251538Srpaulo /* prevent management frames from being sent if we're not ready */ 4102290630Savos URTWN_LOCK(sc); 4103287197Sglebius if (!(sc->sc_flags & URTWN_RUNNING)) { 4104290630Savos error = ENETDOWN; 4105290630Savos goto end; 4106251538Srpaulo } 4107290630Savos 4108251538Srpaulo bf = urtwn_getbuf(sc); 4109251538Srpaulo if (bf == NULL) { 4110290630Savos error = ENOBUFS; 4111290630Savos goto end; 4112251538Srpaulo } 4113251538Srpaulo 4114290630Savos if ((error = urtwn_tx_data(sc, ni, m, bf)) != 0) { 4115251538Srpaulo STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); 4116290630Savos goto end; 4117251538Srpaulo } 4118290630Savos 4119288353Sadrian sc->sc_txtimer = 5; 4120290630Savos callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); 4121290630Savos 4122290630Savosend: 4123290630Savos if (error != 0) 4124290630Savos m_freem(m); 4125290630Savos 4126251538Srpaulo URTWN_UNLOCK(sc); 4127251538Srpaulo 4128290630Savos return (error); 4129251538Srpaulo} 4130251538Srpaulo 4131266472Shselaskystatic void 4132266472Shselaskyurtwn_ms_delay(struct urtwn_softc *sc) 4133266472Shselasky{ 4134266472Shselasky usb_pause_mtx(&sc->sc_mtx, hz / 1000); 4135266472Shselasky} 4136266472Shselasky 4137251538Srpaulostatic device_method_t urtwn_methods[] = { 4138251538Srpaulo /* Device interface */ 4139251538Srpaulo DEVMETHOD(device_probe, urtwn_match), 4140251538Srpaulo DEVMETHOD(device_attach, urtwn_attach), 4141251538Srpaulo DEVMETHOD(device_detach, urtwn_detach), 4142251538Srpaulo 4143264912Skevlo DEVMETHOD_END 4144251538Srpaulo}; 4145251538Srpaulo 4146251538Srpaulostatic driver_t urtwn_driver = { 4147251538Srpaulo "urtwn", 4148251538Srpaulo urtwn_methods, 4149251538Srpaulo sizeof(struct urtwn_softc) 4150251538Srpaulo}; 4151251538Srpaulo 4152251538Srpaulostatic devclass_t urtwn_devclass; 4153251538Srpaulo 4154251538SrpauloDRIVER_MODULE(urtwn, uhub, urtwn_driver, urtwn_devclass, NULL, NULL); 4155251538SrpauloMODULE_DEPEND(urtwn, usb, 1, 1, 1); 4156251538SrpauloMODULE_DEPEND(urtwn, wlan, 1, 1, 1); 4157251538SrpauloMODULE_DEPEND(urtwn, firmware, 1, 1, 1); 4158251538SrpauloMODULE_VERSION(urtwn, 1); 4159292080SimpUSB_PNP_HOST_INFO(urtwn_devs); 4160