if_rum.c revision 207077
1107120Sjulian/* $FreeBSD: head/sys/dev/usb/wlan/if_rum.c 207077 2010-04-22 21:31:34Z thompsa $ */ 2107120Sjulian 3139823Simp/*- 4139823Simp * Copyright (c) 2005-2007 Damien Bergamini <damien.bergamini@free.fr> 5139823Simp * Copyright (c) 2006 Niall O'Higgins <niallo@openbsd.org> 6107120Sjulian * Copyright (c) 2007-2008 Hans Petter Selasky <hselasky@FreeBSD.org> 7107120Sjulian * 8107120Sjulian * Permission to use, copy, modify, and distribute this software for any 9107120Sjulian * purpose with or without fee is hereby granted, provided that the above 10107120Sjulian * copyright notice and this permission notice appear in all copies. 11107120Sjulian * 12107120Sjulian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13107120Sjulian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14107120Sjulian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15107120Sjulian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16107120Sjulian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17107120Sjulian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18107120Sjulian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19107120Sjulian */ 20107120Sjulian 21107120Sjulian#include <sys/cdefs.h> 22107120Sjulian__FBSDID("$FreeBSD: head/sys/dev/usb/wlan/if_rum.c 207077 2010-04-22 21:31:34Z thompsa $"); 23107120Sjulian 24107120Sjulian/*- 25107120Sjulian * Ralink Technology RT2501USB/RT2601USB chipset driver 26107120Sjulian * http://www.ralinktech.com.tw/ 27107120Sjulian */ 28107120Sjulian 29107120Sjulian#include <sys/param.h> 30121054Semax#include <sys/sockio.h> 31107120Sjulian#include <sys/sysctl.h> 32107120Sjulian#include <sys/lock.h> 33107120Sjulian#include <sys/mutex.h> 34107120Sjulian#include <sys/mbuf.h> 35107120Sjulian#include <sys/kernel.h> 36121054Semax#include <sys/socket.h> 37107120Sjulian#include <sys/systm.h> 38107120Sjulian#include <sys/malloc.h> 39107120Sjulian#include <sys/module.h> 40107120Sjulian#include <sys/bus.h> 41107120Sjulian#include <sys/endian.h> 42107120Sjulian#include <sys/kdb.h> 43107120Sjulian 44107120Sjulian#include <machine/bus.h> 45107120Sjulian#include <machine/resource.h> 46107120Sjulian#include <sys/rman.h> 47107120Sjulian 48107120Sjulian#include <net/bpf.h> 49107120Sjulian#include <net/if.h> 50107120Sjulian#include <net/if_arp.h> 51107120Sjulian#include <net/ethernet.h> 52107120Sjulian#include <net/if_dl.h> 53107120Sjulian#include <net/if_media.h> 54107120Sjulian#include <net/if_types.h> 55128688Semax 56128688Semax#ifdef INET 57128688Semax#include <netinet/in.h> 58128688Semax#include <netinet/in_systm.h> 59128688Semax#include <netinet/in_var.h> 60107120Sjulian#include <netinet/if_ether.h> 61107120Sjulian#include <netinet/ip.h> 62107120Sjulian#endif 63107120Sjulian 64107120Sjulian#include <net80211/ieee80211_var.h> 65107120Sjulian#include <net80211/ieee80211_regdomain.h> 66107120Sjulian#include <net80211/ieee80211_radiotap.h> 67107120Sjulian#include <net80211/ieee80211_ratectl.h> 68107120Sjulian 69107120Sjulian#include <dev/usb/usb.h> 70107120Sjulian#include <dev/usb/usbdi.h> 71107120Sjulian#include "usbdevs.h" 72107120Sjulian 73107120Sjulian#define USB_DEBUG_VAR rum_debug 74107120Sjulian#include <dev/usb/usb_debug.h> 75107120Sjulian 76107120Sjulian#include <dev/usb/wlan/if_rumreg.h> 77107120Sjulian#include <dev/usb/wlan/if_rumvar.h> 78107120Sjulian#include <dev/usb/wlan/if_rumfw.h> 79107120Sjulian 80107120Sjulian#ifdef USB_DEBUG 81107120Sjulianstatic int rum_debug = 0; 82107120Sjulian 83129823SjulianSYSCTL_NODE(_hw_usb, OID_AUTO, rum, CTLFLAG_RW, 0, "USB rum"); 84129823SjulianSYSCTL_INT(_hw_usb_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0, 85129823Sjulian "Debug level"); 86129823Sjulian#endif 87129823Sjulian 88129823Sjulianstatic const struct usb_device_id rum_devs[] = { 89129823Sjulian#define RUM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 90129823Sjulian RUM_DEV(ABOCOM, HWU54DM), 91129823Sjulian RUM_DEV(ABOCOM, RT2573_2), 92107120Sjulian RUM_DEV(ABOCOM, RT2573_3), 93107120Sjulian RUM_DEV(ABOCOM, RT2573_4), 94107120Sjulian RUM_DEV(ABOCOM, WUG2700), 95107120Sjulian RUM_DEV(AMIT, CGWLUSB2GO), 96107120Sjulian RUM_DEV(ASUS, RT2573_1), 97107120Sjulian RUM_DEV(ASUS, RT2573_2), 98107120Sjulian RUM_DEV(BELKIN, F5D7050A), 99107120Sjulian RUM_DEV(BELKIN, F5D9050V3), 100107120Sjulian RUM_DEV(CISCOLINKSYS, WUSB54GC), 101107120Sjulian RUM_DEV(CISCOLINKSYS, WUSB54GR), 102107120Sjulian RUM_DEV(CONCEPTRONIC2, C54RU2), 103107120Sjulian RUM_DEV(COREGA, CGWLUSB2GL), 104107120Sjulian RUM_DEV(COREGA, CGWLUSB2GPX), 105107120Sjulian RUM_DEV(DICKSMITH, CWD854F), 106181093Semax RUM_DEV(DICKSMITH, RT2573), 107181093Semax RUM_DEV(EDIMAX, EW7318USG), 108107120Sjulian RUM_DEV(DLINK2, DWLG122C1), 109107120Sjulian RUM_DEV(DLINK2, WUA1340), 110107120Sjulian RUM_DEV(DLINK2, DWA111), 111107120Sjulian RUM_DEV(DLINK2, DWA110), 112107120Sjulian RUM_DEV(GIGABYTE, GNWB01GS), 113217320Smdf RUM_DEV(GIGABYTE, GNWI05GS), 114107120Sjulian RUM_DEV(GIGASET, RT2573), 115107120Sjulian RUM_DEV(GOODWAY, RT2573), 116107120Sjulian RUM_DEV(GUILLEMOT, HWGUSB254LB), 117217320Smdf RUM_DEV(GUILLEMOT, HWGUSB254V2AP), 118107120Sjulian RUM_DEV(HUAWEI3COM, WUB320G), 119107120Sjulian RUM_DEV(MELCO, G54HP), 120107120Sjulian RUM_DEV(MELCO, SG54HP), 121217320Smdf RUM_DEV(MSI, RT2573_1), 122107120Sjulian RUM_DEV(MSI, RT2573_2), 123107120Sjulian RUM_DEV(MSI, RT2573_3), 124107120Sjulian RUM_DEV(MSI, RT2573_4), 125217320Smdf RUM_DEV(NOVATECH, RT2573), 126107120Sjulian RUM_DEV(PLANEX2, GWUS54HP), 127107120Sjulian RUM_DEV(PLANEX2, GWUS54MINI2), 128107120Sjulian RUM_DEV(PLANEX2, GWUSMM), 129107120Sjulian RUM_DEV(QCOM, RT2573), 130107120Sjulian RUM_DEV(QCOM, RT2573_2), 131107120Sjulian RUM_DEV(QCOM, RT2573_3), 132181093Semax RUM_DEV(RALINK, RT2573), 133181093Semax RUM_DEV(RALINK, RT2573_2), 134107120Sjulian RUM_DEV(RALINK, RT2671), 135107120Sjulian RUM_DEV(SITECOMEU, WL113R2), 136107120Sjulian RUM_DEV(SITECOMEU, WL172), 137181093Semax RUM_DEV(SPARKLAN, RT2573), 138181093Semax RUM_DEV(SURECOM, RT2573), 139107120Sjulian#undef RUM_DEV 140107120Sjulian}; 141107120Sjulian 142181093SemaxMODULE_DEPEND(rum, wlan, 1, 1, 1); 143181093SemaxMODULE_DEPEND(rum, usb, 1, 1, 1); 144107120Sjulian 145107120Sjulianstatic device_probe_t rum_match; 146107120Sjulianstatic device_attach_t rum_attach; 147181093Semaxstatic device_detach_t rum_detach; 148181093Semax 149107120Sjulianstatic usb_callback_t rum_bulk_read_callback; 150107120Sjulianstatic usb_callback_t rum_bulk_write_callback; 151107120Sjulian 152107120Sjulianstatic usb_error_t rum_do_request(struct rum_softc *sc, 153107120Sjulian struct usb_device_request *req, void *data); 154107120Sjulianstatic struct ieee80211vap *rum_vap_create(struct ieee80211com *, 155107120Sjulian const char name[IFNAMSIZ], int unit, int opmode, 156161623Semax int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], 157107120Sjulian const uint8_t mac[IEEE80211_ADDR_LEN]); 158161623Semaxstatic void rum_vap_delete(struct ieee80211vap *); 159107120Sjulianstatic void rum_tx_free(struct rum_tx_data *, int); 160161623Semaxstatic void rum_setup_tx_list(struct rum_softc *); 161107120Sjulianstatic void rum_unsetup_tx_list(struct rum_softc *); 162107120Sjulianstatic int rum_newstate(struct ieee80211vap *, 163161623Semax enum ieee80211_state, int); 164107120Sjulianstatic void rum_setup_tx_desc(struct rum_softc *, 165161623Semax struct rum_tx_desc *, uint32_t, uint16_t, int, 166107120Sjulian int); 167161623Semaxstatic int rum_tx_mgt(struct rum_softc *, struct mbuf *, 168107120Sjulian struct ieee80211_node *); 169107120Sjulianstatic int rum_tx_raw(struct rum_softc *, struct mbuf *, 170161623Semax struct ieee80211_node *, 171107120Sjulian const struct ieee80211_bpf_params *); 172161623Semaxstatic int rum_tx_data(struct rum_softc *, struct mbuf *, 173107120Sjulian struct ieee80211_node *); 174107120Sjulianstatic void rum_start(struct ifnet *); 175161623Semaxstatic int rum_ioctl(struct ifnet *, u_long, caddr_t); 176107120Sjulianstatic void rum_eeprom_read(struct rum_softc *, uint16_t, void *, 177107120Sjulian int); 178107120Sjulianstatic uint32_t rum_read(struct rum_softc *, uint16_t); 179107120Sjulianstatic void rum_read_multi(struct rum_softc *, uint16_t, void *, 180107120Sjulian int); 181107120Sjulianstatic usb_error_t rum_write(struct rum_softc *, uint16_t, uint32_t); 182107120Sjulianstatic usb_error_t rum_write_multi(struct rum_softc *, uint16_t, void *, 183107120Sjulian size_t); 184107120Sjulianstatic void rum_bbp_write(struct rum_softc *, uint8_t, uint8_t); 185107120Sjulianstatic uint8_t rum_bbp_read(struct rum_softc *, uint8_t); 186107120Sjulianstatic void rum_rf_write(struct rum_softc *, uint8_t, uint32_t); 187107120Sjulianstatic void rum_select_antenna(struct rum_softc *); 188107120Sjulianstatic void rum_enable_mrr(struct rum_softc *); 189107120Sjulianstatic void rum_set_txpreamble(struct rum_softc *); 190107120Sjulianstatic void rum_set_basicrates(struct rum_softc *); 191107120Sjulianstatic void rum_select_band(struct rum_softc *, 192107120Sjulian struct ieee80211_channel *); 193107120Sjulianstatic void rum_set_chan(struct rum_softc *, 194107120Sjulian struct ieee80211_channel *); 195107120Sjulianstatic void rum_enable_tsf_sync(struct rum_softc *); 196107120Sjulianstatic void rum_enable_tsf(struct rum_softc *); 197107120Sjulianstatic void rum_update_slot(struct ifnet *); 198107120Sjulianstatic void rum_set_bssid(struct rum_softc *, const uint8_t *); 199107120Sjulianstatic void rum_set_macaddr(struct rum_softc *, const uint8_t *); 200107120Sjulianstatic void rum_update_promisc(struct ifnet *); 201107120Sjulianstatic void rum_setpromisc(struct rum_softc *); 202107120Sjulianstatic const char *rum_get_rf(int); 203107120Sjulianstatic void rum_read_eeprom(struct rum_softc *); 204107120Sjulianstatic int rum_bbp_init(struct rum_softc *); 205107120Sjulianstatic void rum_init_locked(struct rum_softc *); 206107120Sjulianstatic void rum_init(void *); 207107120Sjulianstatic void rum_stop(struct rum_softc *); 208107120Sjulianstatic void rum_load_microcode(struct rum_softc *, const uint8_t *, 209107120Sjulian size_t); 210107120Sjulianstatic int rum_prepare_beacon(struct rum_softc *, 211107120Sjulian struct ieee80211vap *); 212114878Sjulianstatic int rum_raw_xmit(struct ieee80211_node *, struct mbuf *, 213114878Sjulian const struct ieee80211_bpf_params *); 214114878Sjulianstatic void rum_scan_start(struct ieee80211com *); 215114878Sjulianstatic void rum_scan_end(struct ieee80211com *); 216114878Sjulianstatic void rum_set_channel(struct ieee80211com *); 217114878Sjulianstatic int rum_get_rssi(struct rum_softc *, uint8_t); 218107120Sjulianstatic void rum_ratectl_start(struct rum_softc *, 219107120Sjulian struct ieee80211_node *); 220107120Sjulianstatic void rum_ratectl_timeout(void *); 221107120Sjulianstatic void rum_ratectl_task(void *, int); 222107120Sjulianstatic int rum_pause(struct rum_softc *, int); 223107120Sjulian 224107120Sjulianstatic const struct { 225107120Sjulian uint32_t reg; 226107120Sjulian uint32_t val; 227107120Sjulian} rum_def_mac[] = { 228107120Sjulian { RT2573_TXRX_CSR0, 0x025fb032 }, 229107120Sjulian { RT2573_TXRX_CSR1, 0x9eaa9eaf }, 230107120Sjulian { RT2573_TXRX_CSR2, 0x8a8b8c8d }, 231107120Sjulian { RT2573_TXRX_CSR3, 0x00858687 }, 232107120Sjulian { RT2573_TXRX_CSR7, 0x2e31353b }, 233107120Sjulian { RT2573_TXRX_CSR8, 0x2a2a2a2c }, 234107120Sjulian { RT2573_TXRX_CSR15, 0x0000000f }, 235107120Sjulian { RT2573_MAC_CSR6, 0x00000fff }, 236107120Sjulian { RT2573_MAC_CSR8, 0x016c030a }, 237107120Sjulian { RT2573_MAC_CSR10, 0x00000718 }, 238107120Sjulian { RT2573_MAC_CSR12, 0x00000004 }, 239107120Sjulian { RT2573_MAC_CSR13, 0x00007f00 }, 240107120Sjulian { RT2573_SEC_CSR0, 0x00000000 }, 241107120Sjulian { RT2573_SEC_CSR1, 0x00000000 }, 242107120Sjulian { RT2573_SEC_CSR5, 0x00000000 }, 243107120Sjulian { RT2573_PHY_CSR1, 0x000023b0 }, 244107120Sjulian { RT2573_PHY_CSR5, 0x00040a06 }, 245107120Sjulian { RT2573_PHY_CSR6, 0x00080606 }, 246107120Sjulian { RT2573_PHY_CSR7, 0x00000408 }, 247107120Sjulian { RT2573_AIFSN_CSR, 0x00002273 }, 248107120Sjulian { RT2573_CWMIN_CSR, 0x00002344 }, 249107120Sjulian { RT2573_CWMAX_CSR, 0x000034aa } 250107120Sjulian}; 251107120Sjulian 252107120Sjulianstatic const struct { 253107120Sjulian uint8_t reg; 254107120Sjulian uint8_t val; 255107120Sjulian} rum_def_bbp[] = { 256107120Sjulian { 3, 0x80 }, 257107120Sjulian { 15, 0x30 }, 258123812Salfred { 17, 0x20 }, 259107120Sjulian { 21, 0xc8 }, 260107120Sjulian { 22, 0x38 }, 261107120Sjulian { 23, 0x06 }, 262107120Sjulian { 24, 0xfe }, 263107120Sjulian { 25, 0x0a }, 264107120Sjulian { 26, 0x0d }, 265107120Sjulian { 32, 0x0b }, 266107120Sjulian { 34, 0x12 }, 267107120Sjulian { 37, 0x07 }, 268107120Sjulian { 39, 0xf8 }, 269107120Sjulian { 41, 0x60 }, 270107120Sjulian { 53, 0x10 }, 271107120Sjulian { 54, 0x18 }, 272107120Sjulian { 60, 0x10 }, 273107120Sjulian { 61, 0x04 }, 274107120Sjulian { 62, 0x04 }, 275107120Sjulian { 75, 0xfe }, 276107120Sjulian { 86, 0xfe }, 277107120Sjulian { 88, 0xfe }, 278107120Sjulian { 90, 0x0f }, 279107120Sjulian { 99, 0x00 }, 280107120Sjulian { 102, 0x16 }, 281107120Sjulian { 107, 0x04 } 282107120Sjulian}; 283107120Sjulian 284107120Sjulianstatic const struct rfprog { 285107120Sjulian uint8_t chan; 286107120Sjulian uint32_t r1, r2, r3, r4; 287107120Sjulian} rum_rf5226[] = { 288107120Sjulian { 1, 0x00b03, 0x001e1, 0x1a014, 0x30282 }, 289107120Sjulian { 2, 0x00b03, 0x001e1, 0x1a014, 0x30287 }, 290107120Sjulian { 3, 0x00b03, 0x001e2, 0x1a014, 0x30282 }, 291107120Sjulian { 4, 0x00b03, 0x001e2, 0x1a014, 0x30287 }, 292107120Sjulian { 5, 0x00b03, 0x001e3, 0x1a014, 0x30282 }, 293107120Sjulian { 6, 0x00b03, 0x001e3, 0x1a014, 0x30287 }, 294107120Sjulian { 7, 0x00b03, 0x001e4, 0x1a014, 0x30282 }, 295107120Sjulian { 8, 0x00b03, 0x001e4, 0x1a014, 0x30287 }, 296107120Sjulian { 9, 0x00b03, 0x001e5, 0x1a014, 0x30282 }, 297107120Sjulian { 10, 0x00b03, 0x001e5, 0x1a014, 0x30287 }, 298107120Sjulian { 11, 0x00b03, 0x001e6, 0x1a014, 0x30282 }, 299107120Sjulian { 12, 0x00b03, 0x001e6, 0x1a014, 0x30287 }, 300107120Sjulian { 13, 0x00b03, 0x001e7, 0x1a014, 0x30282 }, 301107120Sjulian { 14, 0x00b03, 0x001e8, 0x1a014, 0x30284 }, 302107120Sjulian 303107120Sjulian { 34, 0x00b03, 0x20266, 0x36014, 0x30282 }, 304107120Sjulian { 38, 0x00b03, 0x20267, 0x36014, 0x30284 }, 305107120Sjulian { 42, 0x00b03, 0x20268, 0x36014, 0x30286 }, 306107120Sjulian { 46, 0x00b03, 0x20269, 0x36014, 0x30288 }, 307107120Sjulian 308107120Sjulian { 36, 0x00b03, 0x00266, 0x26014, 0x30288 }, 309107120Sjulian { 40, 0x00b03, 0x00268, 0x26014, 0x30280 }, 310107120Sjulian { 44, 0x00b03, 0x00269, 0x26014, 0x30282 }, 311107120Sjulian { 48, 0x00b03, 0x0026a, 0x26014, 0x30284 }, 312107120Sjulian { 52, 0x00b03, 0x0026b, 0x26014, 0x30286 }, 313107120Sjulian { 56, 0x00b03, 0x0026c, 0x26014, 0x30288 }, 314107120Sjulian { 60, 0x00b03, 0x0026e, 0x26014, 0x30280 }, 315114878Sjulian { 64, 0x00b03, 0x0026f, 0x26014, 0x30282 }, 316107120Sjulian 317107120Sjulian { 100, 0x00b03, 0x0028a, 0x2e014, 0x30280 }, 318107120Sjulian { 104, 0x00b03, 0x0028b, 0x2e014, 0x30282 }, 319107120Sjulian { 108, 0x00b03, 0x0028c, 0x2e014, 0x30284 }, 320107120Sjulian { 112, 0x00b03, 0x0028d, 0x2e014, 0x30286 }, 321107120Sjulian { 116, 0x00b03, 0x0028e, 0x2e014, 0x30288 }, 322107120Sjulian { 120, 0x00b03, 0x002a0, 0x2e014, 0x30280 }, 323107120Sjulian { 124, 0x00b03, 0x002a1, 0x2e014, 0x30282 }, 324107120Sjulian { 128, 0x00b03, 0x002a2, 0x2e014, 0x30284 }, 325107120Sjulian { 132, 0x00b03, 0x002a3, 0x2e014, 0x30286 }, 326107120Sjulian { 136, 0x00b03, 0x002a4, 0x2e014, 0x30288 }, 327107120Sjulian { 140, 0x00b03, 0x002a6, 0x2e014, 0x30280 }, 328107120Sjulian 329107120Sjulian { 149, 0x00b03, 0x002a8, 0x2e014, 0x30287 }, 330107120Sjulian { 153, 0x00b03, 0x002a9, 0x2e014, 0x30289 }, 331107120Sjulian { 157, 0x00b03, 0x002ab, 0x2e014, 0x30281 }, 332107120Sjulian { 161, 0x00b03, 0x002ac, 0x2e014, 0x30283 }, 333107120Sjulian { 165, 0x00b03, 0x002ad, 0x2e014, 0x30285 } 334107120Sjulian}, rum_rf5225[] = { 335107120Sjulian { 1, 0x00b33, 0x011e1, 0x1a014, 0x30282 }, 336107120Sjulian { 2, 0x00b33, 0x011e1, 0x1a014, 0x30287 }, 337107120Sjulian { 3, 0x00b33, 0x011e2, 0x1a014, 0x30282 }, 338107120Sjulian { 4, 0x00b33, 0x011e2, 0x1a014, 0x30287 }, 339107120Sjulian { 5, 0x00b33, 0x011e3, 0x1a014, 0x30282 }, 340107120Sjulian { 6, 0x00b33, 0x011e3, 0x1a014, 0x30287 }, 341107120Sjulian { 7, 0x00b33, 0x011e4, 0x1a014, 0x30282 }, 342107120Sjulian { 8, 0x00b33, 0x011e4, 0x1a014, 0x30287 }, 343107120Sjulian { 9, 0x00b33, 0x011e5, 0x1a014, 0x30282 }, 344107120Sjulian { 10, 0x00b33, 0x011e5, 0x1a014, 0x30287 }, 345107120Sjulian { 11, 0x00b33, 0x011e6, 0x1a014, 0x30282 }, 346107120Sjulian { 12, 0x00b33, 0x011e6, 0x1a014, 0x30287 }, 347107120Sjulian { 13, 0x00b33, 0x011e7, 0x1a014, 0x30282 }, 348114878Sjulian { 14, 0x00b33, 0x011e8, 0x1a014, 0x30284 }, 349107120Sjulian 350107120Sjulian { 34, 0x00b33, 0x01266, 0x26014, 0x30282 }, 351107120Sjulian { 38, 0x00b33, 0x01267, 0x26014, 0x30284 }, 352107120Sjulian { 42, 0x00b33, 0x01268, 0x26014, 0x30286 }, 353107120Sjulian { 46, 0x00b33, 0x01269, 0x26014, 0x30288 }, 354107120Sjulian 355107120Sjulian { 36, 0x00b33, 0x01266, 0x26014, 0x30288 }, 356107120Sjulian { 40, 0x00b33, 0x01268, 0x26014, 0x30280 }, 357107120Sjulian { 44, 0x00b33, 0x01269, 0x26014, 0x30282 }, 358107120Sjulian { 48, 0x00b33, 0x0126a, 0x26014, 0x30284 }, 359107120Sjulian { 52, 0x00b33, 0x0126b, 0x26014, 0x30286 }, 360107120Sjulian { 56, 0x00b33, 0x0126c, 0x26014, 0x30288 }, 361107120Sjulian { 60, 0x00b33, 0x0126e, 0x26014, 0x30280 }, 362107120Sjulian { 64, 0x00b33, 0x0126f, 0x26014, 0x30282 }, 363107120Sjulian 364107120Sjulian { 100, 0x00b33, 0x0128a, 0x2e014, 0x30280 }, 365107120Sjulian { 104, 0x00b33, 0x0128b, 0x2e014, 0x30282 }, 366107120Sjulian { 108, 0x00b33, 0x0128c, 0x2e014, 0x30284 }, 367107120Sjulian { 112, 0x00b33, 0x0128d, 0x2e014, 0x30286 }, 368107120Sjulian { 116, 0x00b33, 0x0128e, 0x2e014, 0x30288 }, 369107120Sjulian { 120, 0x00b33, 0x012a0, 0x2e014, 0x30280 }, 370107120Sjulian { 124, 0x00b33, 0x012a1, 0x2e014, 0x30282 }, 371107120Sjulian { 128, 0x00b33, 0x012a2, 0x2e014, 0x30284 }, 372107120Sjulian { 132, 0x00b33, 0x012a3, 0x2e014, 0x30286 }, 373107120Sjulian { 136, 0x00b33, 0x012a4, 0x2e014, 0x30288 }, 374107120Sjulian { 140, 0x00b33, 0x012a6, 0x2e014, 0x30280 }, 375107120Sjulian 376107120Sjulian { 149, 0x00b33, 0x012a8, 0x2e014, 0x30287 }, 377107120Sjulian { 153, 0x00b33, 0x012a9, 0x2e014, 0x30289 }, 378107120Sjulian { 157, 0x00b33, 0x012ab, 0x2e014, 0x30281 }, 379107120Sjulian { 161, 0x00b33, 0x012ac, 0x2e014, 0x30283 }, 380107120Sjulian { 165, 0x00b33, 0x012ad, 0x2e014, 0x30285 } 381114878Sjulian}; 382107120Sjulian 383107120Sjulianstatic const struct usb_config rum_config[RUM_N_TRANSFER] = { 384107120Sjulian [RUM_BULK_WR] = { 385107120Sjulian .type = UE_BULK, 386107120Sjulian .endpoint = UE_ADDR_ANY, 387107120Sjulian .direction = UE_DIR_OUT, 388107120Sjulian .bufsize = (MCLBYTES + RT2573_TX_DESC_SIZE + 8), 389107120Sjulian .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 390107120Sjulian .callback = rum_bulk_write_callback, 391107120Sjulian .timeout = 5000, /* ms */ 392107120Sjulian }, 393107120Sjulian [RUM_BULK_RD] = { 394107120Sjulian .type = UE_BULK, 395161623Semax .endpoint = UE_ADDR_ANY, 396107120Sjulian .direction = UE_DIR_IN, 397107120Sjulian .bufsize = (MCLBYTES + RT2573_RX_DESC_SIZE), 398107120Sjulian .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 399107120Sjulian .callback = rum_bulk_read_callback, 400107120Sjulian }, 401107120Sjulian}; 402107120Sjulian 403107120Sjulianstatic int 404107120Sjulianrum_match(device_t self) 405107120Sjulian{ 406114878Sjulian struct usb_attach_arg *uaa = device_get_ivars(self); 407114878Sjulian 408107120Sjulian if (uaa->usb_mode != USB_MODE_HOST) 409107120Sjulian return (ENXIO); 410114878Sjulian if (uaa->info.bConfigIndex != 0) 411114878Sjulian return (ENXIO); 412107120Sjulian if (uaa->info.bIfaceIndex != RT2573_IFACE_INDEX) 413114878Sjulian return (ENXIO); 414107120Sjulian 415107120Sjulian return (usbd_lookup_id_by_uaa(rum_devs, sizeof(rum_devs), uaa)); 416107120Sjulian} 417107120Sjulian 418107120Sjulianstatic int 419107120Sjulianrum_attach(device_t self) 420107120Sjulian{ 421107120Sjulian struct usb_attach_arg *uaa = device_get_ivars(self); 422107120Sjulian struct rum_softc *sc = device_get_softc(self); 423107120Sjulian struct ieee80211com *ic; 424107120Sjulian struct ifnet *ifp; 425107120Sjulian uint8_t iface_index, bands; 426107120Sjulian uint32_t tmp; 427107120Sjulian int error, ntries; 428107120Sjulian 429107120Sjulian device_set_usb_desc(self); 430114878Sjulian sc->sc_udev = uaa->device; 431114878Sjulian sc->sc_dev = self; 432107120Sjulian 433107120Sjulian mtx_init(&sc->sc_mtx, device_get_nameunit(self), 434107120Sjulian MTX_NETWORK_LOCK, MTX_DEF); 435107120Sjulian 436107120Sjulian iface_index = RT2573_IFACE_INDEX; 437107120Sjulian error = usbd_transfer_setup(uaa->device, &iface_index, 438107120Sjulian sc->sc_xfer, rum_config, RUM_N_TRANSFER, sc, &sc->sc_mtx); 439107120Sjulian if (error) { 440114878Sjulian device_printf(self, "could not allocate USB transfers, " 441114878Sjulian "err=%s\n", usbd_errstr(error)); 442107120Sjulian goto detach; 443107120Sjulian } 444107120Sjulian 445107120Sjulian RUM_LOCK(sc); 446107120Sjulian /* retrieve RT2573 rev. no */ 447107120Sjulian for (ntries = 0; ntries < 100; ntries++) { 448107120Sjulian if ((tmp = rum_read(sc, RT2573_MAC_CSR0)) != 0) 449107120Sjulian break; 450107120Sjulian if (rum_pause(sc, hz / 100)) 451107120Sjulian break; 452107120Sjulian } 453107120Sjulian if (ntries == 100) { 454107120Sjulian device_printf(sc->sc_dev, "timeout waiting for chip to settle\n"); 455107120Sjulian RUM_UNLOCK(sc); 456107120Sjulian goto detach; 457107120Sjulian } 458107120Sjulian 459107120Sjulian /* retrieve MAC address and various other things from EEPROM */ 460107120Sjulian rum_read_eeprom(sc); 461107120Sjulian 462107120Sjulian device_printf(sc->sc_dev, "MAC/BBP RT2573 (rev 0x%05x), RF %s\n", 463107120Sjulian tmp, rum_get_rf(sc->rf_rev)); 464107120Sjulian 465107120Sjulian rum_load_microcode(sc, rt2573_ucode, sizeof(rt2573_ucode)); 466107120Sjulian RUM_UNLOCK(sc); 467107120Sjulian 468107120Sjulian ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); 469107120Sjulian if (ifp == NULL) { 470107120Sjulian device_printf(sc->sc_dev, "can not if_alloc()\n"); 471107120Sjulian goto detach; 472107120Sjulian } 473107120Sjulian ic = ifp->if_l2com; 474107120Sjulian 475107120Sjulian ifp->if_softc = sc; 476107120Sjulian if_initname(ifp, "rum", device_get_unit(sc->sc_dev)); 477107120Sjulian ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 478107120Sjulian ifp->if_init = rum_init; 479107120Sjulian ifp->if_ioctl = rum_ioctl; 480107120Sjulian ifp->if_start = rum_start; 481114878Sjulian IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 482107120Sjulian ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 483107120Sjulian IFQ_SET_READY(&ifp->if_snd); 484107120Sjulian 485107120Sjulian ic->ic_ifp = ifp; 486107120Sjulian ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 487107120Sjulian 488107120Sjulian /* set device capabilities */ 489107120Sjulian ic->ic_caps = 490107120Sjulian IEEE80211_C_STA /* station mode supported */ 491107120Sjulian | IEEE80211_C_IBSS /* IBSS mode supported */ 492161623Semax | IEEE80211_C_MONITOR /* monitor mode supported */ 493107120Sjulian | IEEE80211_C_HOSTAP /* HostAp mode supported */ 494107120Sjulian | IEEE80211_C_TXPMGT /* tx power management */ 495107120Sjulian | IEEE80211_C_SHPREAMBLE /* short preamble supported */ 496107120Sjulian | IEEE80211_C_SHSLOT /* short slot time supported */ 497107120Sjulian | IEEE80211_C_BGSCAN /* bg scanning supported */ 498107120Sjulian | IEEE80211_C_WPA /* 802.11i */ 499107120Sjulian ; 500107120Sjulian 501107120Sjulian bands = 0; 502114878Sjulian setbit(&bands, IEEE80211_MODE_11B); 503114878Sjulian setbit(&bands, IEEE80211_MODE_11G); 504107120Sjulian if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) 505107120Sjulian setbit(&bands, IEEE80211_MODE_11A); 506114878Sjulian ieee80211_init_channels(ic, NULL, &bands); 507114878Sjulian 508107120Sjulian ieee80211_ifattach(ic, sc->sc_bssid); 509114878Sjulian ic->ic_update_promisc = rum_update_promisc; 510107120Sjulian ic->ic_raw_xmit = rum_raw_xmit; 511107120Sjulian ic->ic_scan_start = rum_scan_start; 512107120Sjulian ic->ic_scan_end = rum_scan_end; 513107120Sjulian ic->ic_set_channel = rum_set_channel; 514107120Sjulian 515107120Sjulian ic->ic_vap_create = rum_vap_create; 516107120Sjulian ic->ic_vap_delete = rum_vap_delete; 517107120Sjulian 518107120Sjulian ieee80211_radiotap_attach(ic, 519107120Sjulian &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), 520107120Sjulian RT2573_TX_RADIOTAP_PRESENT, 521107120Sjulian &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), 522107120Sjulian RT2573_RX_RADIOTAP_PRESENT); 523107120Sjulian 524107120Sjulian if (bootverbose) 525114878Sjulian ieee80211_announce(ic); 526114878Sjulian 527107120Sjulian return (0); 528107120Sjulian 529107120Sjuliandetach: 530107120Sjulian rum_detach(self); 531107120Sjulian return (ENXIO); /* failure */ 532107120Sjulian} 533107120Sjulian 534107120Sjulianstatic int 535107120Sjulianrum_detach(device_t self) 536107120Sjulian{ 537107120Sjulian struct rum_softc *sc = device_get_softc(self); 538107120Sjulian struct ifnet *ifp = sc->sc_ifp; 539107120Sjulian struct ieee80211com *ic; 540107120Sjulian 541107120Sjulian /* stop all USB transfers */ 542107120Sjulian usbd_transfer_unsetup(sc->sc_xfer, RUM_N_TRANSFER); 543107120Sjulian 544107120Sjulian /* free TX list, if any */ 545107120Sjulian RUM_LOCK(sc); 546114878Sjulian rum_unsetup_tx_list(sc); 547107120Sjulian RUM_UNLOCK(sc); 548107120Sjulian 549107120Sjulian if (ifp) { 550107120Sjulian ic = ifp->if_l2com; 551107120Sjulian ieee80211_ifdetach(ic); 552107120Sjulian if_free(ifp); 553107120Sjulian } 554107120Sjulian mtx_destroy(&sc->sc_mtx); 555107120Sjulian 556107120Sjulian return (0); 557107120Sjulian} 558107120Sjulian 559161623Semaxstatic usb_error_t 560107120Sjulianrum_do_request(struct rum_softc *sc, 561107120Sjulian struct usb_device_request *req, void *data) 562107120Sjulian{ 563107120Sjulian usb_error_t err; 564107120Sjulian int ntries = 10; 565107120Sjulian 566107120Sjulian while (ntries--) { 567107120Sjulian err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, 568107120Sjulian req, data, 0, NULL, 250 /* ms */); 569107120Sjulian if (err == 0) 570107120Sjulian break; 571107120Sjulian 572107120Sjulian DPRINTFN(1, "Control request failed, %s (retrying)\n", 573107120Sjulian usbd_errstr(err)); 574107120Sjulian if (rum_pause(sc, hz / 100)) 575107120Sjulian break; 576107120Sjulian } 577107120Sjulian return (err); 578107120Sjulian} 579107120Sjulian 580107120Sjulianstatic struct ieee80211vap * 581114878Sjulianrum_vap_create(struct ieee80211com *ic, 582114878Sjulian const char name[IFNAMSIZ], int unit, int opmode, int flags, 583107120Sjulian const uint8_t bssid[IEEE80211_ADDR_LEN], 584107120Sjulian const uint8_t mac[IEEE80211_ADDR_LEN]) 585107120Sjulian{ 586107120Sjulian struct rum_softc *sc = ic->ic_ifp->if_softc; 587107120Sjulian struct rum_vap *rvp; 588107120Sjulian struct ieee80211vap *vap; 589107120Sjulian 590107120Sjulian if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ 591107120Sjulian return NULL; 592107120Sjulian rvp = (struct rum_vap *) malloc(sizeof(struct rum_vap), 593107120Sjulian M_80211_VAP, M_NOWAIT | M_ZERO); 594107120Sjulian if (rvp == NULL) 595107120Sjulian return NULL; 596107120Sjulian vap = &rvp->vap; 597107120Sjulian /* enable s/w bmiss handling for sta mode */ 598107120Sjulian ieee80211_vap_setup(ic, vap, name, unit, opmode, 599107120Sjulian flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); 600107120Sjulian 601107120Sjulian /* override state transition machine */ 602107120Sjulian rvp->newstate = vap->iv_newstate; 603107120Sjulian vap->iv_newstate = rum_newstate; 604107120Sjulian 605107120Sjulian usb_callout_init_mtx(&rvp->ratectl_ch, &sc->sc_mtx, 0); 606107120Sjulian TASK_INIT(&rvp->ratectl_task, 0, rum_ratectl_task, rvp); 607107120Sjulian ieee80211_ratectl_init(vap); 608107120Sjulian ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); 609107120Sjulian /* complete setup */ 610107120Sjulian ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); 611107120Sjulian ic->ic_opmode = opmode; 612107120Sjulian return vap; 613107120Sjulian} 614114878Sjulian 615107120Sjulianstatic void 616107120Sjulianrum_vap_delete(struct ieee80211vap *vap) 617107120Sjulian{ 618107120Sjulian struct rum_vap *rvp = RUM_VAP(vap); 619107120Sjulian struct ieee80211com *ic = vap->iv_ic; 620107120Sjulian 621107120Sjulian usb_callout_drain(&rvp->ratectl_ch); 622107120Sjulian ieee80211_draintask(ic, &rvp->ratectl_task); 623107120Sjulian ieee80211_ratectl_deinit(vap); 624107120Sjulian ieee80211_vap_detach(vap); 625107120Sjulian free(rvp, M_80211_VAP); 626107120Sjulian} 627107120Sjulian 628107120Sjulianstatic void 629107120Sjulianrum_tx_free(struct rum_tx_data *data, int txerr) 630107120Sjulian{ 631107120Sjulian struct rum_softc *sc = data->sc; 632107120Sjulian 633107120Sjulian if (data->m != NULL) { 634107120Sjulian if (data->m->m_flags & M_TXCB) 635107120Sjulian ieee80211_process_callback(data->ni, data->m, 636107120Sjulian txerr ? ETIMEDOUT : 0); 637107120Sjulian m_freem(data->m); 638107120Sjulian data->m = NULL; 639107120Sjulian 640107120Sjulian ieee80211_free_node(data->ni); 641107120Sjulian data->ni = NULL; 642107120Sjulian } 643107120Sjulian STAILQ_INSERT_TAIL(&sc->tx_free, data, next); 644107120Sjulian sc->tx_nfree++; 645107120Sjulian} 646107120Sjulian 647107120Sjulianstatic void 648107120Sjulianrum_setup_tx_list(struct rum_softc *sc) 649107120Sjulian{ 650107120Sjulian struct rum_tx_data *data; 651107120Sjulian int i; 652107120Sjulian 653107120Sjulian sc->tx_nfree = 0; 654107120Sjulian STAILQ_INIT(&sc->tx_q); 655107120Sjulian STAILQ_INIT(&sc->tx_free); 656107120Sjulian 657107120Sjulian for (i = 0; i < RUM_TX_LIST_COUNT; i++) { 658107120Sjulian data = &sc->tx_data[i]; 659114878Sjulian 660114878Sjulian data->sc = sc; 661107120Sjulian STAILQ_INSERT_TAIL(&sc->tx_free, data, next); 662107120Sjulian sc->tx_nfree++; 663107120Sjulian } 664107120Sjulian} 665107120Sjulian 666107120Sjulianstatic void 667107120Sjulianrum_unsetup_tx_list(struct rum_softc *sc) 668107120Sjulian{ 669107120Sjulian struct rum_tx_data *data; 670161623Semax int i; 671107120Sjulian 672107120Sjulian /* make sure any subsequent use of the queues will fail */ 673107120Sjulian sc->tx_nfree = 0; 674107120Sjulian STAILQ_INIT(&sc->tx_q); 675107120Sjulian STAILQ_INIT(&sc->tx_free); 676107120Sjulian 677107120Sjulian /* free up all node references and mbufs */ 678107120Sjulian for (i = 0; i < RUM_TX_LIST_COUNT; i++) { 679107120Sjulian data = &sc->tx_data[i]; 680114878Sjulian 681114878Sjulian if (data->m != NULL) { 682107120Sjulian m_freem(data->m); 683107120Sjulian data->m = NULL; 684107120Sjulian } 685107120Sjulian if (data->ni != NULL) { 686107120Sjulian ieee80211_free_node(data->ni); 687107120Sjulian data->ni = NULL; 688107120Sjulian } 689107120Sjulian } 690107120Sjulian} 691107120Sjulian 692107120Sjulianstatic int 693107120Sjulianrum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 694107120Sjulian{ 695107120Sjulian struct rum_vap *rvp = RUM_VAP(vap); 696114878Sjulian struct ieee80211com *ic = vap->iv_ic; 697107120Sjulian struct rum_softc *sc = ic->ic_ifp->if_softc; 698107120Sjulian const struct ieee80211_txparam *tp; 699107120Sjulian enum ieee80211_state ostate; 700107120Sjulian struct ieee80211_node *ni; 701107120Sjulian uint32_t tmp; 702107120Sjulian 703107120Sjulian ostate = vap->iv_state; 704107120Sjulian DPRINTF("%s -> %s\n", 705107120Sjulian ieee80211_state_name[ostate], 706107120Sjulian ieee80211_state_name[nstate]); 707107120Sjulian 708107120Sjulian IEEE80211_UNLOCK(ic); 709107120Sjulian RUM_LOCK(sc); 710107120Sjulian usb_callout_stop(&rvp->ratectl_ch); 711107120Sjulian 712107120Sjulian switch (nstate) { 713107120Sjulian case IEEE80211_S_INIT: 714107120Sjulian if (ostate == IEEE80211_S_RUN) { 715114878Sjulian /* abort TSF synchronization */ 716114878Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR9); 717107120Sjulian rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); 718107120Sjulian } 719107120Sjulian break; 720107120Sjulian 721107120Sjulian case IEEE80211_S_RUN: 722107120Sjulian ni = vap->iv_bss; 723107120Sjulian 724107120Sjulian if (vap->iv_opmode != IEEE80211_M_MONITOR) { 725107120Sjulian rum_update_slot(ic->ic_ifp); 726107120Sjulian rum_enable_mrr(sc); 727107120Sjulian rum_set_txpreamble(sc); 728107120Sjulian rum_set_basicrates(sc); 729107120Sjulian IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); 730107120Sjulian rum_set_bssid(sc, sc->sc_bssid); 731107120Sjulian } 732107120Sjulian 733107120Sjulian if (vap->iv_opmode == IEEE80211_M_HOSTAP || 734107120Sjulian vap->iv_opmode == IEEE80211_M_IBSS) 735107120Sjulian rum_prepare_beacon(sc, vap); 736107120Sjulian 737107120Sjulian if (vap->iv_opmode != IEEE80211_M_MONITOR) 738107120Sjulian rum_enable_tsf_sync(sc); 739107120Sjulian else 740107120Sjulian rum_enable_tsf(sc); 741107120Sjulian 742107120Sjulian /* enable automatic rate adaptation */ 743107120Sjulian tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 744107120Sjulian if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 745107120Sjulian rum_ratectl_start(sc, ni); 746107120Sjulian break; 747107120Sjulian default: 748107120Sjulian break; 749107120Sjulian } 750107120Sjulian RUM_UNLOCK(sc); 751107120Sjulian IEEE80211_LOCK(ic); 752107120Sjulian return (rvp->newstate(vap, nstate, arg)); 753107120Sjulian} 754107120Sjulian 755107120Sjulianstatic void 756107120Sjulianrum_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 757107120Sjulian{ 758107120Sjulian struct rum_softc *sc = usbd_xfer_softc(xfer); 759107120Sjulian struct ifnet *ifp = sc->sc_ifp; 760107120Sjulian struct ieee80211vap *vap; 761107120Sjulian struct rum_tx_data *data; 762107120Sjulian struct mbuf *m; 763107120Sjulian struct usb_page_cache *pc; 764107120Sjulian unsigned int len; 765107120Sjulian int actlen, sumlen; 766107120Sjulian 767107120Sjulian usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 768107120Sjulian 769107120Sjulian switch (USB_GET_STATE(xfer)) { 770107120Sjulian case USB_ST_TRANSFERRED: 771107120Sjulian DPRINTFN(11, "transfer complete, %d bytes\n", actlen); 772107120Sjulian 773107120Sjulian /* free resources */ 774107120Sjulian data = usbd_xfer_get_priv(xfer); 775107120Sjulian rum_tx_free(data, 0); 776114878Sjulian usbd_xfer_set_priv(xfer, NULL); 777107120Sjulian 778107120Sjulian ifp->if_opackets++; 779107120Sjulian ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 780107120Sjulian 781107120Sjulian /* FALLTHROUGH */ 782107120Sjulian case USB_ST_SETUP: 783107120Sjuliantr_setup: 784107120Sjulian data = STAILQ_FIRST(&sc->tx_q); 785107120Sjulian if (data) { 786107120Sjulian STAILQ_REMOVE_HEAD(&sc->tx_q, next); 787161623Semax m = data->m; 788107120Sjulian 789107120Sjulian if (m->m_pkthdr.len > (MCLBYTES + RT2573_TX_DESC_SIZE)) { 790107120Sjulian DPRINTFN(0, "data overflow, %u bytes\n", 791107120Sjulian m->m_pkthdr.len); 792107120Sjulian m->m_pkthdr.len = (MCLBYTES + RT2573_TX_DESC_SIZE); 793107120Sjulian } 794107120Sjulian pc = usbd_xfer_get_frame(xfer, 0); 795107120Sjulian usbd_copy_in(pc, 0, &data->desc, RT2573_TX_DESC_SIZE); 796107120Sjulian usbd_m_copy_in(pc, RT2573_TX_DESC_SIZE, m, 0, 797107120Sjulian m->m_pkthdr.len); 798114878Sjulian 799114878Sjulian vap = data->ni->ni_vap; 800107120Sjulian if (ieee80211_radiotap_active_vap(vap)) { 801107120Sjulian struct rum_tx_radiotap_header *tap = &sc->sc_txtap; 802114878Sjulian 803114878Sjulian tap->wt_flags = 0; 804107120Sjulian tap->wt_rate = data->rate; 805114878Sjulian tap->wt_antenna = sc->tx_ant; 806107120Sjulian 807107120Sjulian ieee80211_radiotap_tx(vap, m); 808107120Sjulian } 809107120Sjulian 810107120Sjulian /* align end on a 4-bytes boundary */ 811107120Sjulian len = (RT2573_TX_DESC_SIZE + m->m_pkthdr.len + 3) & ~3; 812107120Sjulian if ((len % 64) == 0) 813107120Sjulian len += 4; 814107120Sjulian 815107120Sjulian DPRINTFN(11, "sending frame len=%u xferlen=%u\n", 816107120Sjulian m->m_pkthdr.len, len); 817107120Sjulian 818107120Sjulian usbd_xfer_set_frame_len(xfer, 0, len); 819107120Sjulian usbd_xfer_set_priv(xfer, data); 820107120Sjulian 821107120Sjulian usbd_transfer_submit(xfer); 822114878Sjulian } 823114878Sjulian RUM_UNLOCK(sc); 824107120Sjulian rum_start(ifp); 825107120Sjulian RUM_LOCK(sc); 826107120Sjulian break; 827107120Sjulian 828107120Sjulian default: /* Error */ 829107120Sjulian DPRINTFN(11, "transfer error, %s\n", 830107120Sjulian usbd_errstr(error)); 831107120Sjulian 832107120Sjulian ifp->if_oerrors++; 833107120Sjulian data = usbd_xfer_get_priv(xfer); 834107120Sjulian if (data != NULL) { 835107120Sjulian rum_tx_free(data, error); 836107120Sjulian usbd_xfer_set_priv(xfer, NULL); 837107120Sjulian } 838107120Sjulian 839107120Sjulian if (error != USB_ERR_CANCELLED) { 840107120Sjulian if (error == USB_ERR_TIMEOUT) 841107120Sjulian device_printf(sc->sc_dev, "device timeout\n"); 842107120Sjulian 843107120Sjulian /* 844107120Sjulian * Try to clear stall first, also if other 845107120Sjulian * errors occur, hence clearing stall 846107120Sjulian * introduces a 50 ms delay: 847107120Sjulian */ 848107120Sjulian usbd_xfer_set_stall(xfer); 849107120Sjulian goto tr_setup; 850107120Sjulian } 851107120Sjulian break; 852107120Sjulian } 853107120Sjulian} 854107120Sjulian 855107120Sjulianstatic void 856114878Sjulianrum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 857107120Sjulian{ 858107120Sjulian struct rum_softc *sc = usbd_xfer_softc(xfer); 859107120Sjulian struct ifnet *ifp = sc->sc_ifp; 860107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 861107120Sjulian struct ieee80211_node *ni; 862107120Sjulian struct mbuf *m = NULL; 863107120Sjulian struct usb_page_cache *pc; 864107120Sjulian uint32_t flags; 865107120Sjulian uint8_t rssi = 0; 866107120Sjulian int len; 867107120Sjulian 868107120Sjulian usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 869107120Sjulian 870107120Sjulian switch (USB_GET_STATE(xfer)) { 871114878Sjulian case USB_ST_TRANSFERRED: 872107120Sjulian 873107120Sjulian DPRINTFN(15, "rx done, actlen=%d\n", len); 874107120Sjulian 875107120Sjulian if (len < RT2573_RX_DESC_SIZE + IEEE80211_MIN_LEN) { 876107120Sjulian DPRINTF("%s: xfer too short %d\n", 877107120Sjulian device_get_nameunit(sc->sc_dev), len); 878107120Sjulian ifp->if_ierrors++; 879107120Sjulian goto tr_setup; 880107120Sjulian } 881107120Sjulian 882161623Semax len -= RT2573_RX_DESC_SIZE; 883107120Sjulian pc = usbd_xfer_get_frame(xfer, 0); 884107120Sjulian usbd_copy_out(pc, 0, &sc->sc_rx_desc, RT2573_RX_DESC_SIZE); 885107120Sjulian 886107120Sjulian rssi = rum_get_rssi(sc, sc->sc_rx_desc.rssi); 887107120Sjulian flags = le32toh(sc->sc_rx_desc.flags); 888107120Sjulian if (flags & RT2573_RX_CRC_ERROR) { 889107120Sjulian /* 890107120Sjulian * This should not happen since we did not 891107120Sjulian * request to receive those frames when we 892107120Sjulian * filled RUM_TXRX_CSR2: 893114878Sjulian */ 894114878Sjulian DPRINTFN(5, "PHY or CRC error\n"); 895107120Sjulian ifp->if_ierrors++; 896107120Sjulian goto tr_setup; 897114878Sjulian } 898114878Sjulian 899107120Sjulian m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 900114878Sjulian if (m == NULL) { 901107120Sjulian DPRINTF("could not allocate mbuf\n"); 902107120Sjulian ifp->if_ierrors++; 903107120Sjulian goto tr_setup; 904107120Sjulian } 905107120Sjulian usbd_copy_out(pc, RT2573_RX_DESC_SIZE, 906107120Sjulian mtod(m, uint8_t *), len); 907107120Sjulian 908107120Sjulian /* finalize mbuf */ 909107120Sjulian m->m_pkthdr.rcvif = ifp; 910107120Sjulian m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; 911107120Sjulian 912107120Sjulian if (ieee80211_radiotap_active(ic)) { 913107120Sjulian struct rum_rx_radiotap_header *tap = &sc->sc_rxtap; 914107120Sjulian 915107120Sjulian /* XXX read tsf */ 916107120Sjulian tap->wr_flags = 0; 917114878Sjulian tap->wr_rate = ieee80211_plcp2rate(sc->sc_rx_desc.rate, 918114878Sjulian (flags & RT2573_RX_OFDM) ? 919107120Sjulian IEEE80211_T_OFDM : IEEE80211_T_CCK); 920107120Sjulian tap->wr_antsignal = RT2573_NOISE_FLOOR + rssi; 921107120Sjulian tap->wr_antnoise = RT2573_NOISE_FLOOR; 922107120Sjulian tap->wr_antenna = sc->rx_ant; 923107120Sjulian } 924107120Sjulian /* FALLTHROUGH */ 925107120Sjulian case USB_ST_SETUP: 926107120Sjuliantr_setup: 927107120Sjulian usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 928107120Sjulian usbd_transfer_submit(xfer); 929107120Sjulian 930107120Sjulian /* 931107120Sjulian * At the end of a USB callback it is always safe to unlock 932107120Sjulian * the private mutex of a device! That is why we do the 933107120Sjulian * "ieee80211_input" here, and not some lines up! 934107120Sjulian */ 935107120Sjulian RUM_UNLOCK(sc); 936107120Sjulian if (m) { 937114878Sjulian ni = ieee80211_find_rxnode(ic, 938114878Sjulian mtod(m, struct ieee80211_frame_min *)); 939114878Sjulian if (ni != NULL) { 940114878Sjulian (void) ieee80211_input(ni, m, rssi, 941107120Sjulian RT2573_NOISE_FLOOR); 942114878Sjulian ieee80211_free_node(ni); 943107120Sjulian } else 944114878Sjulian (void) ieee80211_input_all(ic, m, rssi, 945114878Sjulian RT2573_NOISE_FLOOR); 946107120Sjulian } 947114878Sjulian if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 && 948114878Sjulian !IFQ_IS_EMPTY(&ifp->if_snd)) 949114878Sjulian rum_start(ifp); 950114878Sjulian RUM_LOCK(sc); 951114878Sjulian return; 952107120Sjulian 953107120Sjulian default: /* Error */ 954107120Sjulian if (error != USB_ERR_CANCELLED) { 955114878Sjulian /* try to clear stall first */ 956107120Sjulian usbd_xfer_set_stall(xfer); 957107120Sjulian goto tr_setup; 958107120Sjulian } 959107120Sjulian return; 960107120Sjulian } 961107120Sjulian} 962107120Sjulian 963107120Sjulianstatic uint8_t 964107120Sjulianrum_plcp_signal(int rate) 965107120Sjulian{ 966161623Semax switch (rate) { 967107120Sjulian /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 968107120Sjulian case 12: return 0xb; 969107120Sjulian case 18: return 0xf; 970107120Sjulian case 24: return 0xa; 971107120Sjulian case 36: return 0xe; 972107120Sjulian case 48: return 0x9; 973107120Sjulian case 72: return 0xd; 974107120Sjulian case 96: return 0x8; 975107120Sjulian case 108: return 0xc; 976107120Sjulian 977114878Sjulian /* CCK rates (NB: not IEEE std, device-specific) */ 978114878Sjulian case 2: return 0x0; 979107120Sjulian case 4: return 0x1; 980107120Sjulian case 11: return 0x2; 981107120Sjulian case 22: return 0x3; 982107120Sjulian } 983107120Sjulian return 0xff; /* XXX unsupported/unknown rate */ 984107120Sjulian} 985107120Sjulian 986114878Sjulianstatic void 987114878Sjulianrum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, 988107120Sjulian uint32_t flags, uint16_t xflags, int len, int rate) 989114878Sjulian{ 990107120Sjulian struct ifnet *ifp = sc->sc_ifp; 991107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 992107120Sjulian uint16_t plcp_length; 993107120Sjulian int remainder; 994107120Sjulian 995107120Sjulian desc->flags = htole32(flags); 996107120Sjulian desc->flags |= htole32(RT2573_TX_VALID); 997107120Sjulian desc->flags |= htole32(len << 16); 998107120Sjulian 999107120Sjulian desc->xflags = htole16(xflags); 1000107120Sjulian 1001107120Sjulian desc->wme = htole16(RT2573_QID(0) | RT2573_AIFSN(2) | 1002107120Sjulian RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); 1003107120Sjulian 1004107120Sjulian /* setup PLCP fields */ 1005107120Sjulian desc->plcp_signal = rum_plcp_signal(rate); 1006107120Sjulian desc->plcp_service = 4; 1007107120Sjulian 1008107120Sjulian len += IEEE80211_CRC_LEN; 1009107120Sjulian if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { 1010107120Sjulian desc->flags |= htole32(RT2573_TX_OFDM); 1011107120Sjulian 1012114878Sjulian plcp_length = len & 0xfff; 1013107120Sjulian desc->plcp_length_hi = plcp_length >> 6; 1014107120Sjulian desc->plcp_length_lo = plcp_length & 0x3f; 1015107120Sjulian } else { 1016107120Sjulian plcp_length = (16 * len + rate - 1) / rate; 1017107120Sjulian if (rate == 22) { 1018107120Sjulian remainder = (16 * len) % 22; 1019107120Sjulian if (remainder != 0 && remainder < 7) 1020107120Sjulian desc->plcp_service |= RT2573_PLCP_LENGEXT; 1021107120Sjulian } 1022107120Sjulian desc->plcp_length_hi = plcp_length >> 8; 1023161623Semax desc->plcp_length_lo = plcp_length & 0xff; 1024107120Sjulian 1025107120Sjulian if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 1026107120Sjulian desc->plcp_signal |= 0x08; 1027107120Sjulian } 1028107120Sjulian} 1029107120Sjulian 1030107120Sjulianstatic int 1031107120Sjulianrum_sendprot(struct rum_softc *sc, 1032107120Sjulian const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) 1033107120Sjulian{ 1034114878Sjulian struct ieee80211com *ic = ni->ni_ic; 1035114878Sjulian const struct ieee80211_frame *wh; 1036107120Sjulian struct rum_tx_data *data; 1037107120Sjulian struct mbuf *mprot; 1038114878Sjulian int protrate, ackrate, pktlen, flags, isshort; 1039114878Sjulian uint16_t dur; 1040107120Sjulian 1041114878Sjulian RUM_LOCK_ASSERT(sc, MA_OWNED); 1042107120Sjulian KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY, 1043107120Sjulian ("protection %d", prot)); 1044107120Sjulian 1045107120Sjulian wh = mtod(m, const struct ieee80211_frame *); 1046107120Sjulian pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 1047107120Sjulian 1048107120Sjulian protrate = ieee80211_ctl_rate(ic->ic_rt, rate); 1049107120Sjulian ackrate = ieee80211_ack_rate(ic->ic_rt, rate); 1050107120Sjulian 1051107120Sjulian isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; 1052107120Sjulian dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort); 1053107120Sjulian + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1054107120Sjulian flags = RT2573_TX_MORE_FRAG; 1055107120Sjulian if (prot == IEEE80211_PROT_RTSCTS) { 1056107120Sjulian /* NB: CTS is the same size as an ACK */ 1057107120Sjulian dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 1058107120Sjulian flags |= RT2573_TX_NEED_ACK; 1059107120Sjulian mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 1060107120Sjulian } else { 1061107120Sjulian mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); 1062107120Sjulian } 1063107120Sjulian if (mprot == NULL) { 1064107120Sjulian /* XXX stat + msg */ 1065107120Sjulian return (ENOBUFS); 1066107120Sjulian } 1067107120Sjulian data = STAILQ_FIRST(&sc->tx_free); 1068114878Sjulian STAILQ_REMOVE_HEAD(&sc->tx_free, next); 1069107120Sjulian sc->tx_nfree--; 1070107120Sjulian 1071107120Sjulian data->m = mprot; 1072107120Sjulian data->ni = ieee80211_ref_node(ni); 1073107120Sjulian data->rate = protrate; 1074107120Sjulian rum_setup_tx_desc(sc, &data->desc, flags, 0, mprot->m_pkthdr.len, protrate); 1075107120Sjulian 1076107120Sjulian STAILQ_INSERT_TAIL(&sc->tx_q, data, next); 1077107120Sjulian usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); 1078107120Sjulian 1079161623Semax return 0; 1080107120Sjulian} 1081107120Sjulian 1082107120Sjulianstatic int 1083107120Sjulianrum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) 1084107120Sjulian{ 1085107120Sjulian struct ieee80211vap *vap = ni->ni_vap; 1086107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1087107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1088107120Sjulian struct rum_tx_data *data; 1089107120Sjulian struct ieee80211_frame *wh; 1090114878Sjulian const struct ieee80211_txparam *tp; 1091114878Sjulian struct ieee80211_key *k; 1092107120Sjulian uint32_t flags = 0; 1093107120Sjulian uint16_t dur; 1094114878Sjulian 1095114878Sjulian RUM_LOCK_ASSERT(sc, MA_OWNED); 1096107120Sjulian 1097114878Sjulian data = STAILQ_FIRST(&sc->tx_free); 1098107120Sjulian STAILQ_REMOVE_HEAD(&sc->tx_free, next); 1099107120Sjulian sc->tx_nfree--; 1100107120Sjulian 1101107120Sjulian wh = mtod(m0, struct ieee80211_frame *); 1102107120Sjulian if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1103107120Sjulian k = ieee80211_crypto_encap(ni, m0); 1104107120Sjulian if (k == NULL) { 1105107120Sjulian m_freem(m0); 1106107120Sjulian return ENOBUFS; 1107107120Sjulian } 1108107120Sjulian wh = mtod(m0, struct ieee80211_frame *); 1109107120Sjulian } 1110107120Sjulian 1111107120Sjulian tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1112107120Sjulian 1113107120Sjulian if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1114114878Sjulian flags |= RT2573_TX_NEED_ACK; 1115114878Sjulian 1116107120Sjulian dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate, 1117107120Sjulian ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1118107120Sjulian *(uint16_t *)wh->i_dur = htole16(dur); 1119107120Sjulian 1120107120Sjulian /* tell hardware to add timestamp for probe responses */ 1121107120Sjulian if ((wh->i_fc[0] & 1122107120Sjulian (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == 1123107120Sjulian (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 1124107120Sjulian flags |= RT2573_TX_TIMESTAMP; 1125107120Sjulian } 1126107120Sjulian 1127107120Sjulian data->m = m0; 1128107120Sjulian data->ni = ni; 1129107120Sjulian data->rate = tp->mgmtrate; 1130107120Sjulian 1131107120Sjulian rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, tp->mgmtrate); 1132107120Sjulian 1133107120Sjulian DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", 1134107120Sjulian m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, tp->mgmtrate); 1135107120Sjulian 1136107120Sjulian STAILQ_INSERT_TAIL(&sc->tx_q, data, next); 1137107120Sjulian usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); 1138107120Sjulian 1139107120Sjulian return (0); 1140107120Sjulian} 1141107120Sjulian 1142114878Sjulianstatic int 1143107120Sjulianrum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, 1144107120Sjulian const struct ieee80211_bpf_params *params) 1145107120Sjulian{ 1146107120Sjulian struct ieee80211com *ic = ni->ni_ic; 1147107120Sjulian struct rum_tx_data *data; 1148107120Sjulian uint32_t flags; 1149107120Sjulian int rate, error; 1150107120Sjulian 1151107120Sjulian RUM_LOCK_ASSERT(sc, MA_OWNED); 1152107120Sjulian KASSERT(params != NULL, ("no raw xmit params")); 1153107120Sjulian 1154107120Sjulian rate = params->ibp_rate0; 1155107120Sjulian if (!ieee80211_isratevalid(ic->ic_rt, rate)) { 1156107120Sjulian m_freem(m0); 1157107120Sjulian return EINVAL; 1158107120Sjulian } 1159107120Sjulian flags = 0; 1160107120Sjulian if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) 1161107120Sjulian flags |= RT2573_TX_NEED_ACK; 1162107120Sjulian if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { 1163107120Sjulian error = rum_sendprot(sc, m0, ni, 1164107120Sjulian params->ibp_flags & IEEE80211_BPF_RTS ? 1165107120Sjulian IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, 1166107120Sjulian rate); 1167107120Sjulian if (error || sc->tx_nfree == 0) { 1168107120Sjulian m_freem(m0); 1169107120Sjulian return ENOBUFS; 1170107120Sjulian } 1171107120Sjulian flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; 1172107120Sjulian } 1173107120Sjulian 1174107120Sjulian data = STAILQ_FIRST(&sc->tx_free); 1175123812Salfred STAILQ_REMOVE_HEAD(&sc->tx_free, next); 1176107120Sjulian sc->tx_nfree--; 1177107120Sjulian 1178107120Sjulian data->m = m0; 1179107120Sjulian data->ni = ni; 1180107120Sjulian data->rate = rate; 1181107120Sjulian 1182107120Sjulian /* XXX need to setup descriptor ourself */ 1183107120Sjulian rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); 1184107120Sjulian 1185107120Sjulian DPRINTFN(10, "sending raw frame len=%u rate=%u\n", 1186107120Sjulian m0->m_pkthdr.len, rate); 1187107120Sjulian 1188107120Sjulian STAILQ_INSERT_TAIL(&sc->tx_q, data, next); 1189107120Sjulian usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); 1190107120Sjulian 1191107120Sjulian return 0; 1192107120Sjulian} 1193107120Sjulian 1194107120Sjulianstatic int 1195107120Sjulianrum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) 1196107120Sjulian{ 1197107120Sjulian struct ieee80211vap *vap = ni->ni_vap; 1198107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1199107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1200107120Sjulian struct rum_tx_data *data; 1201107120Sjulian struct ieee80211_frame *wh; 1202107120Sjulian const struct ieee80211_txparam *tp; 1203107120Sjulian struct ieee80211_key *k; 1204107120Sjulian uint32_t flags = 0; 1205107120Sjulian uint16_t dur; 1206107120Sjulian int error, rate; 1207107120Sjulian 1208107120Sjulian RUM_LOCK_ASSERT(sc, MA_OWNED); 1209107120Sjulian 1210123812Salfred wh = mtod(m0, struct ieee80211_frame *); 1211107120Sjulian 1212107120Sjulian tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; 1213107120Sjulian if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 1214107120Sjulian rate = tp->mcastrate; 1215107120Sjulian else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 1216107120Sjulian rate = tp->ucastrate; 1217107120Sjulian else 1218107120Sjulian rate = ni->ni_txrate; 1219107120Sjulian 1220107120Sjulian if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 1221107120Sjulian k = ieee80211_crypto_encap(ni, m0); 1222107120Sjulian if (k == NULL) { 1223107120Sjulian m_freem(m0); 1224107120Sjulian return ENOBUFS; 1225107120Sjulian } 1226107120Sjulian 1227107120Sjulian /* packet header may have moved, reset our local pointer */ 1228107120Sjulian wh = mtod(m0, struct ieee80211_frame *); 1229107120Sjulian } 1230107120Sjulian 1231107120Sjulian if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1232107120Sjulian int prot = IEEE80211_PROT_NONE; 1233107120Sjulian if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) 1234107120Sjulian prot = IEEE80211_PROT_RTSCTS; 1235107120Sjulian else if ((ic->ic_flags & IEEE80211_F_USEPROT) && 1236107120Sjulian ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) 1237107120Sjulian prot = ic->ic_protmode; 1238107120Sjulian if (prot != IEEE80211_PROT_NONE) { 1239107120Sjulian error = rum_sendprot(sc, m0, ni, prot, rate); 1240107120Sjulian if (error || sc->tx_nfree == 0) { 1241107120Sjulian m_freem(m0); 1242107120Sjulian return ENOBUFS; 1243107120Sjulian } 1244107120Sjulian flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS; 1245107120Sjulian } 1246123812Salfred } 1247107120Sjulian 1248107120Sjulian data = STAILQ_FIRST(&sc->tx_free); 1249107120Sjulian STAILQ_REMOVE_HEAD(&sc->tx_free, next); 1250107120Sjulian sc->tx_nfree--; 1251107120Sjulian 1252107120Sjulian data->m = m0; 1253107120Sjulian data->ni = ni; 1254107120Sjulian data->rate = rate; 1255107120Sjulian 1256107120Sjulian if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1257107120Sjulian flags |= RT2573_TX_NEED_ACK; 1258107120Sjulian flags |= RT2573_TX_MORE_FRAG; 1259107120Sjulian 1260107120Sjulian dur = ieee80211_ack_duration(ic->ic_rt, rate, 1261107120Sjulian ic->ic_flags & IEEE80211_F_SHPREAMBLE); 1262107120Sjulian *(uint16_t *)wh->i_dur = htole16(dur); 1263107120Sjulian } 1264107120Sjulian 1265107120Sjulian rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); 1266107120Sjulian 1267107120Sjulian DPRINTFN(10, "sending frame len=%d rate=%d\n", 1268107120Sjulian m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate); 1269107120Sjulian 1270107120Sjulian STAILQ_INSERT_TAIL(&sc->tx_q, data, next); 1271107120Sjulian usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); 1272107120Sjulian 1273107120Sjulian return 0; 1274107120Sjulian} 1275107120Sjulian 1276107120Sjulianstatic void 1277107120Sjulianrum_start(struct ifnet *ifp) 1278107120Sjulian{ 1279107120Sjulian struct rum_softc *sc = ifp->if_softc; 1280123812Salfred struct ieee80211_node *ni; 1281107120Sjulian struct mbuf *m; 1282107120Sjulian 1283107120Sjulian RUM_LOCK(sc); 1284107120Sjulian if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1285107120Sjulian RUM_UNLOCK(sc); 1286107120Sjulian return; 1287107120Sjulian } 1288107120Sjulian for (;;) { 1289107120Sjulian IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1290107120Sjulian if (m == NULL) 1291107120Sjulian break; 1292107120Sjulian if (sc->tx_nfree < RUM_TX_MINFREE) { 1293107120Sjulian IFQ_DRV_PREPEND(&ifp->if_snd, m); 1294107120Sjulian ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1295107120Sjulian break; 1296107120Sjulian } 1297107120Sjulian ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; 1298107120Sjulian if (rum_tx_data(sc, m, ni) != 0) { 1299107120Sjulian ieee80211_free_node(ni); 1300107120Sjulian ifp->if_oerrors++; 1301107120Sjulian break; 1302107120Sjulian } 1303107120Sjulian } 1304107120Sjulian RUM_UNLOCK(sc); 1305107120Sjulian} 1306107120Sjulian 1307107120Sjulianstatic int 1308107120Sjulianrum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1309107120Sjulian{ 1310107120Sjulian struct rum_softc *sc = ifp->if_softc; 1311107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1312107120Sjulian struct ifreq *ifr = (struct ifreq *) data; 1313123812Salfred int error = 0, startall = 0; 1314107120Sjulian 1315107120Sjulian switch (cmd) { 1316107120Sjulian case SIOCSIFFLAGS: 1317107120Sjulian RUM_LOCK(sc); 1318107120Sjulian if (ifp->if_flags & IFF_UP) { 1319107120Sjulian if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1320107120Sjulian rum_init_locked(sc); 1321107120Sjulian startall = 1; 1322107120Sjulian } else 1323107120Sjulian rum_setpromisc(sc); 1324107120Sjulian } else { 1325107120Sjulian if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1326107120Sjulian rum_stop(sc); 1327107120Sjulian } 1328107120Sjulian RUM_UNLOCK(sc); 1329107120Sjulian if (startall) 1330107120Sjulian ieee80211_start_all(ic); 1331107120Sjulian break; 1332107120Sjulian case SIOCGIFMEDIA: 1333107120Sjulian error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); 1334107120Sjulian break; 1335107120Sjulian case SIOCGIFADDR: 1336107120Sjulian error = ether_ioctl(ifp, cmd, data); 1337107120Sjulian break; 1338107120Sjulian default: 1339107120Sjulian error = EINVAL; 1340107120Sjulian break; 1341107120Sjulian } 1342107120Sjulian return error; 1343107120Sjulian} 1344107120Sjulian 1345107120Sjulianstatic void 1346107120Sjulianrum_eeprom_read(struct rum_softc *sc, uint16_t addr, void *buf, int len) 1347107120Sjulian{ 1348107120Sjulian struct usb_device_request req; 1349107120Sjulian usb_error_t error; 1350107120Sjulian 1351107120Sjulian req.bmRequestType = UT_READ_VENDOR_DEVICE; 1352107120Sjulian req.bRequest = RT2573_READ_EEPROM; 1353107120Sjulian USETW(req.wValue, 0); 1354107120Sjulian USETW(req.wIndex, addr); 1355107120Sjulian USETW(req.wLength, len); 1356107120Sjulian 1357107120Sjulian error = rum_do_request(sc, &req, buf); 1358107120Sjulian if (error != 0) { 1359107120Sjulian device_printf(sc->sc_dev, "could not read EEPROM: %s\n", 1360107120Sjulian usbd_errstr(error)); 1361107120Sjulian } 1362107120Sjulian} 1363107120Sjulian 1364107120Sjulianstatic uint32_t 1365107120Sjulianrum_read(struct rum_softc *sc, uint16_t reg) 1366107120Sjulian{ 1367107120Sjulian uint32_t val; 1368107120Sjulian 1369107120Sjulian rum_read_multi(sc, reg, &val, sizeof val); 1370107120Sjulian 1371107120Sjulian return le32toh(val); 1372107120Sjulian} 1373107120Sjulian 1374107120Sjulianstatic void 1375107120Sjulianrum_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, int len) 1376107120Sjulian{ 1377107120Sjulian struct usb_device_request req; 1378107120Sjulian usb_error_t error; 1379107120Sjulian 1380107120Sjulian req.bmRequestType = UT_READ_VENDOR_DEVICE; 1381107120Sjulian req.bRequest = RT2573_READ_MULTI_MAC; 1382107120Sjulian USETW(req.wValue, 0); 1383107120Sjulian USETW(req.wIndex, reg); 1384107120Sjulian USETW(req.wLength, len); 1385114878Sjulian 1386107120Sjulian error = rum_do_request(sc, &req, buf); 1387107120Sjulian if (error != 0) { 1388107120Sjulian device_printf(sc->sc_dev, 1389107120Sjulian "could not multi read MAC register: %s\n", 1390107120Sjulian usbd_errstr(error)); 1391107120Sjulian } 1392121054Semax} 1393114878Sjulian 1394114878Sjulianstatic usb_error_t 1395114878Sjulianrum_write(struct rum_softc *sc, uint16_t reg, uint32_t val) 1396107120Sjulian{ 1397107120Sjulian uint32_t tmp = htole32(val); 1398114878Sjulian 1399114878Sjulian return (rum_write_multi(sc, reg, &tmp, sizeof tmp)); 1400107120Sjulian} 1401114878Sjulian 1402107120Sjulianstatic usb_error_t 1403107120Sjulianrum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len) 1404107120Sjulian{ 1405107120Sjulian struct usb_device_request req; 1406107120Sjulian usb_error_t error; 1407107120Sjulian 1408107120Sjulian req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 1409107120Sjulian req.bRequest = RT2573_WRITE_MULTI_MAC; 1410107120Sjulian USETW(req.wValue, 0); 1411107120Sjulian USETW(req.wIndex, reg); 1412107120Sjulian USETW(req.wLength, len); 1413107120Sjulian 1414114878Sjulian error = rum_do_request(sc, &req, buf); 1415107120Sjulian if (error != 0) { 1416107120Sjulian device_printf(sc->sc_dev, 1417107120Sjulian "could not multi write MAC register: %s\n", 1418107120Sjulian usbd_errstr(error)); 1419107120Sjulian } 1420107120Sjulian return (error); 1421107120Sjulian} 1422107120Sjulian 1423107120Sjulianstatic void 1424107120Sjulianrum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) 1425107120Sjulian{ 1426107120Sjulian uint32_t tmp; 1427107120Sjulian int ntries; 1428107120Sjulian 1429114878Sjulian DPRINTFN(2, "reg=0x%08x\n", reg); 1430107120Sjulian 1431107120Sjulian for (ntries = 0; ntries < 100; ntries++) { 1432107120Sjulian if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) 1433107120Sjulian break; 1434107120Sjulian if (rum_pause(sc, hz / 100)) 1435107120Sjulian break; 1436107120Sjulian } 1437107120Sjulian if (ntries == 100) { 1438107120Sjulian device_printf(sc->sc_dev, "could not write to BBP\n"); 1439107120Sjulian return; 1440107120Sjulian } 1441107120Sjulian 1442107120Sjulian tmp = RT2573_BBP_BUSY | (reg & 0x7f) << 8 | val; 1443107120Sjulian rum_write(sc, RT2573_PHY_CSR3, tmp); 1444107120Sjulian} 1445107120Sjulian 1446107120Sjulianstatic uint8_t 1447107120Sjulianrum_bbp_read(struct rum_softc *sc, uint8_t reg) 1448107120Sjulian{ 1449107120Sjulian uint32_t val; 1450107120Sjulian int ntries; 1451107120Sjulian 1452107120Sjulian DPRINTFN(2, "reg=0x%08x\n", reg); 1453114878Sjulian 1454107120Sjulian for (ntries = 0; ntries < 100; ntries++) { 1455107120Sjulian if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) 1456107120Sjulian break; 1457107120Sjulian if (rum_pause(sc, hz / 100)) 1458107120Sjulian break; 1459107120Sjulian } 1460107120Sjulian if (ntries == 100) { 1461107120Sjulian device_printf(sc->sc_dev, "could not read BBP\n"); 1462114878Sjulian return 0; 1463107120Sjulian } 1464114878Sjulian 1465114878Sjulian val = RT2573_BBP_BUSY | RT2573_BBP_READ | reg << 8; 1466107120Sjulian rum_write(sc, RT2573_PHY_CSR3, val); 1467107120Sjulian 1468107120Sjulian for (ntries = 0; ntries < 100; ntries++) { 1469107120Sjulian val = rum_read(sc, RT2573_PHY_CSR3); 1470107120Sjulian if (!(val & RT2573_BBP_BUSY)) 1471107120Sjulian return val & 0xff; 1472107120Sjulian if (rum_pause(sc, hz / 100)) 1473107120Sjulian break; 1474107120Sjulian } 1475107120Sjulian 1476107120Sjulian device_printf(sc->sc_dev, "could not read BBP\n"); 1477107120Sjulian return 0; 1478107120Sjulian} 1479107120Sjulian 1480107120Sjulianstatic void 1481107120Sjulianrum_rf_write(struct rum_softc *sc, uint8_t reg, uint32_t val) 1482107120Sjulian{ 1483107120Sjulian uint32_t tmp; 1484107120Sjulian int ntries; 1485107120Sjulian 1486107120Sjulian for (ntries = 0; ntries < 100; ntries++) { 1487107120Sjulian if (!(rum_read(sc, RT2573_PHY_CSR4) & RT2573_RF_BUSY)) 1488107120Sjulian break; 1489107120Sjulian if (rum_pause(sc, hz / 100)) 1490107120Sjulian break; 1491107120Sjulian } 1492107120Sjulian if (ntries == 100) { 1493107120Sjulian device_printf(sc->sc_dev, "could not write to RF\n"); 1494107120Sjulian return; 1495107120Sjulian } 1496107120Sjulian 1497107120Sjulian tmp = RT2573_RF_BUSY | RT2573_RF_20BIT | (val & 0xfffff) << 2 | 1498107120Sjulian (reg & 3); 1499107120Sjulian rum_write(sc, RT2573_PHY_CSR4, tmp); 1500107120Sjulian 1501107120Sjulian /* remember last written value in sc */ 1502107120Sjulian sc->rf_regs[reg] = val; 1503107120Sjulian 1504107120Sjulian DPRINTFN(15, "RF R[%u] <- 0x%05x\n", reg & 3, val & 0xfffff); 1505107120Sjulian} 1506107120Sjulian 1507107120Sjulianstatic void 1508107120Sjulianrum_select_antenna(struct rum_softc *sc) 1509107120Sjulian{ 1510107120Sjulian uint8_t bbp4, bbp77; 1511107120Sjulian uint32_t tmp; 1512107120Sjulian 1513107120Sjulian bbp4 = rum_bbp_read(sc, 4); 1514107120Sjulian bbp77 = rum_bbp_read(sc, 77); 1515107120Sjulian 1516107120Sjulian /* TBD */ 1517107120Sjulian 1518107120Sjulian /* make sure Rx is disabled before switching antenna */ 1519107120Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR0); 1520107120Sjulian rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); 1521107120Sjulian 1522107120Sjulian rum_bbp_write(sc, 4, bbp4); 1523107120Sjulian rum_bbp_write(sc, 77, bbp77); 1524107120Sjulian 1525107120Sjulian rum_write(sc, RT2573_TXRX_CSR0, tmp); 1526107120Sjulian} 1527107120Sjulian 1528107120Sjulian/* 1529107120Sjulian * Enable multi-rate retries for frames sent at OFDM rates. 1530111119Simp * In 802.11b/g mode, allow fallback to CCK rates. 1531107120Sjulian */ 1532107120Sjulianstatic void 1533107120Sjulianrum_enable_mrr(struct rum_softc *sc) 1534107120Sjulian{ 1535107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1536107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1537107120Sjulian uint32_t tmp; 1538114878Sjulian 1539107120Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR4); 1540107120Sjulian 1541107120Sjulian tmp &= ~RT2573_MRR_CCK_FALLBACK; 1542107120Sjulian if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) 1543107120Sjulian tmp |= RT2573_MRR_CCK_FALLBACK; 1544107120Sjulian tmp |= RT2573_MRR_ENABLED; 1545107120Sjulian 1546107120Sjulian rum_write(sc, RT2573_TXRX_CSR4, tmp); 1547107120Sjulian} 1548107120Sjulian 1549107120Sjulianstatic void 1550107120Sjulianrum_set_txpreamble(struct rum_softc *sc) 1551107120Sjulian{ 1552107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1553107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1554107120Sjulian uint32_t tmp; 1555107120Sjulian 1556107120Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR4); 1557107120Sjulian 1558107120Sjulian tmp &= ~RT2573_SHORT_PREAMBLE; 1559107120Sjulian if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 1560107120Sjulian tmp |= RT2573_SHORT_PREAMBLE; 1561107120Sjulian 1562114878Sjulian rum_write(sc, RT2573_TXRX_CSR4, tmp); 1563114878Sjulian} 1564107120Sjulian 1565107120Sjulianstatic void 1566184205Sdesrum_set_basicrates(struct rum_softc *sc) 1567107120Sjulian{ 1568114878Sjulian struct ifnet *ifp = sc->sc_ifp; 1569114878Sjulian struct ieee80211com *ic = ifp->if_l2com; 1570107120Sjulian 1571114878Sjulian /* update basic rate set */ 1572107120Sjulian if (ic->ic_curmode == IEEE80211_MODE_11B) { 1573107120Sjulian /* 11b basic rates: 1, 2Mbps */ 1574107120Sjulian rum_write(sc, RT2573_TXRX_CSR5, 0x3); 1575107120Sjulian } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) { 1576107120Sjulian /* 11a basic rates: 6, 12, 24Mbps */ 1577114878Sjulian rum_write(sc, RT2573_TXRX_CSR5, 0x150); 1578107120Sjulian } else { 1579107120Sjulian /* 11b/g basic rates: 1, 2, 5.5, 11Mbps */ 1580107120Sjulian rum_write(sc, RT2573_TXRX_CSR5, 0xf); 1581114878Sjulian } 1582114878Sjulian} 1583107120Sjulian 1584107120Sjulian/* 1585107120Sjulian * Reprogram MAC/BBP to switch to a new band. Values taken from the reference 1586107120Sjulian * driver. 1587107120Sjulian */ 1588107120Sjulianstatic void 1589107120Sjulianrum_select_band(struct rum_softc *sc, struct ieee80211_channel *c) 1590107120Sjulian{ 1591107120Sjulian uint8_t bbp17, bbp35, bbp96, bbp97, bbp98, bbp104; 1592107120Sjulian uint32_t tmp; 1593107120Sjulian 1594107120Sjulian /* update all BBP registers that depend on the band */ 1595107120Sjulian bbp17 = 0x20; bbp96 = 0x48; bbp104 = 0x2c; 1596107120Sjulian bbp35 = 0x50; bbp97 = 0x48; bbp98 = 0x48; 1597107120Sjulian if (IEEE80211_IS_CHAN_5GHZ(c)) { 1598107120Sjulian bbp17 += 0x08; bbp96 += 0x10; bbp104 += 0x0c; 1599107120Sjulian bbp35 += 0x10; bbp97 += 0x10; bbp98 += 0x10; 1600107120Sjulian } 1601107120Sjulian if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) || 1602107120Sjulian (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) { 1603107120Sjulian bbp17 += 0x10; bbp96 += 0x10; bbp104 += 0x10; 1604107120Sjulian } 1605107120Sjulian 1606161623Semax sc->bbp17 = bbp17; 1607107120Sjulian rum_bbp_write(sc, 17, bbp17); 1608107120Sjulian rum_bbp_write(sc, 96, bbp96); 1609107120Sjulian rum_bbp_write(sc, 104, bbp104); 1610107120Sjulian 1611107120Sjulian if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) || 1612107120Sjulian (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) { 1613107120Sjulian rum_bbp_write(sc, 75, 0x80); 1614107120Sjulian rum_bbp_write(sc, 86, 0x80); 1615107120Sjulian rum_bbp_write(sc, 88, 0x80); 1616107120Sjulian } 1617107120Sjulian 1618107120Sjulian rum_bbp_write(sc, 35, bbp35); 1619107120Sjulian rum_bbp_write(sc, 97, bbp97); 1620107120Sjulian rum_bbp_write(sc, 98, bbp98); 1621107120Sjulian 1622107120Sjulian tmp = rum_read(sc, RT2573_PHY_CSR0); 1623161623Semax tmp &= ~(RT2573_PA_PE_2GHZ | RT2573_PA_PE_5GHZ); 1624107120Sjulian if (IEEE80211_IS_CHAN_2GHZ(c)) 1625107120Sjulian tmp |= RT2573_PA_PE_2GHZ; 1626107120Sjulian else 1627161623Semax tmp |= RT2573_PA_PE_5GHZ; 1628107120Sjulian rum_write(sc, RT2573_PHY_CSR0, tmp); 1629107120Sjulian} 1630107120Sjulian 1631161623Semaxstatic void 1632107120Sjulianrum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) 1633107120Sjulian{ 1634107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1635161623Semax struct ieee80211com *ic = ifp->if_l2com; 1636107120Sjulian const struct rfprog *rfprog; 1637107120Sjulian uint8_t bbp3, bbp94 = RT2573_BBPR94_DEFAULT; 1638107120Sjulian int8_t power; 1639161623Semax int i, chan; 1640107120Sjulian 1641107120Sjulian chan = ieee80211_chan2ieee(ic, c); 1642107120Sjulian if (chan == 0 || chan == IEEE80211_CHAN_ANY) 1643161623Semax return; 1644107120Sjulian 1645107120Sjulian /* select the appropriate RF settings based on what EEPROM says */ 1646107120Sjulian rfprog = (sc->rf_rev == RT2573_RF_5225 || 1647161623Semax sc->rf_rev == RT2573_RF_2527) ? rum_rf5225 : rum_rf5226; 1648107120Sjulian 1649107120Sjulian /* find the settings for this channel (we know it exists) */ 1650107120Sjulian for (i = 0; rfprog[i].chan != chan; i++); 1651161623Semax 1652107120Sjulian power = sc->txpow[i]; 1653107120Sjulian if (power < 0) { 1654107120Sjulian bbp94 += power; 1655161623Semax power = 0; 1656107120Sjulian } else if (power > 31) { 1657107120Sjulian bbp94 += power - 31; 1658107120Sjulian power = 31; 1659107120Sjulian } 1660107120Sjulian 1661107120Sjulian /* 1662107120Sjulian * If we are switching from the 2GHz band to the 5GHz band or 1663107120Sjulian * vice-versa, BBP registers need to be reprogrammed. 1664107120Sjulian */ 1665107120Sjulian if (c->ic_flags != ic->ic_curchan->ic_flags) { 1666107120Sjulian rum_select_band(sc, c); 1667107120Sjulian rum_select_antenna(sc); 1668107120Sjulian } 1669107120Sjulian ic->ic_curchan = c; 1670107120Sjulian 1671107120Sjulian rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); 1672107120Sjulian rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); 1673107120Sjulian rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7); 1674107120Sjulian rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); 1675107120Sjulian 1676107120Sjulian rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); 1677107120Sjulian rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); 1678107120Sjulian rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7 | 1); 1679107120Sjulian rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); 1680107120Sjulian 1681107120Sjulian rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); 1682107120Sjulian rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); 1683107120Sjulian rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7); 1684107120Sjulian rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); 1685107120Sjulian 1686107120Sjulian rum_pause(sc, hz / 100); 1687107120Sjulian 1688107120Sjulian /* enable smart mode for MIMO-capable RFs */ 1689107120Sjulian bbp3 = rum_bbp_read(sc, 3); 1690107120Sjulian 1691107120Sjulian bbp3 &= ~RT2573_SMART_MODE; 1692107120Sjulian if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_2527) 1693107120Sjulian bbp3 |= RT2573_SMART_MODE; 1694107120Sjulian 1695107120Sjulian rum_bbp_write(sc, 3, bbp3); 1696107120Sjulian 1697107120Sjulian if (bbp94 != RT2573_BBPR94_DEFAULT) 1698107120Sjulian rum_bbp_write(sc, 94, bbp94); 1699107120Sjulian 1700107120Sjulian /* give the chip some extra time to do the switchover */ 1701107120Sjulian rum_pause(sc, hz / 100); 1702107120Sjulian} 1703107120Sjulian 1704107120Sjulian/* 1705107120Sjulian * Enable TSF synchronization and tell h/w to start sending beacons for IBSS 1706107120Sjulian * and HostAP operating modes. 1707107120Sjulian */ 1708107120Sjulianstatic void 1709107120Sjulianrum_enable_tsf_sync(struct rum_softc *sc) 1710107120Sjulian{ 1711107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1712107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1713107120Sjulian struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); 1714107120Sjulian uint32_t tmp; 1715107120Sjulian 1716107120Sjulian if (vap->iv_opmode != IEEE80211_M_STA) { 1717107120Sjulian /* 1718107120Sjulian * Change default 16ms TBTT adjustment to 8ms. 1719107120Sjulian * Must be done before enabling beacon generation. 1720107120Sjulian */ 1721107120Sjulian rum_write(sc, RT2573_TXRX_CSR10, 1 << 12 | 8); 1722107120Sjulian } 1723107120Sjulian 1724107120Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000; 1725107120Sjulian 1726107120Sjulian /* set beacon interval (in 1/16ms unit) */ 1727107120Sjulian tmp |= vap->iv_bss->ni_intval * 16; 1728107120Sjulian 1729107120Sjulian tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT; 1730107120Sjulian if (vap->iv_opmode == IEEE80211_M_STA) 1731107120Sjulian tmp |= RT2573_TSF_MODE(1); 1732107120Sjulian else 1733107120Sjulian tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON; 1734107120Sjulian 1735107120Sjulian rum_write(sc, RT2573_TXRX_CSR9, tmp); 1736107120Sjulian} 1737107120Sjulian 1738107120Sjulianstatic void 1739107120Sjulianrum_enable_tsf(struct rum_softc *sc) 1740107120Sjulian{ 1741107120Sjulian rum_write(sc, RT2573_TXRX_CSR9, 1742107120Sjulian (rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000) | 1743107120Sjulian RT2573_TSF_TICKING | RT2573_TSF_MODE(2)); 1744107120Sjulian} 1745114878Sjulian 1746107120Sjulianstatic void 1747107120Sjulianrum_update_slot(struct ifnet *ifp) 1748107120Sjulian{ 1749107120Sjulian struct rum_softc *sc = ifp->if_softc; 1750107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1751107120Sjulian uint8_t slottime; 1752107120Sjulian uint32_t tmp; 1753107120Sjulian 1754107120Sjulian slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 1755114878Sjulian 1756107120Sjulian tmp = rum_read(sc, RT2573_MAC_CSR9); 1757114878Sjulian tmp = (tmp & ~0xff) | slottime; 1758107120Sjulian rum_write(sc, RT2573_MAC_CSR9, tmp); 1759107120Sjulian 1760107120Sjulian DPRINTF("setting slot time to %uus\n", slottime); 1761107120Sjulian} 1762107120Sjulian 1763107120Sjulianstatic void 1764107120Sjulianrum_set_bssid(struct rum_softc *sc, const uint8_t *bssid) 1765107120Sjulian{ 1766107120Sjulian uint32_t tmp; 1767107120Sjulian 1768107120Sjulian tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 1769114878Sjulian rum_write(sc, RT2573_MAC_CSR4, tmp); 1770107120Sjulian 1771107120Sjulian tmp = bssid[4] | bssid[5] << 8 | RT2573_ONE_BSSID << 16; 1772107120Sjulian rum_write(sc, RT2573_MAC_CSR5, tmp); 1773107120Sjulian} 1774114878Sjulian 1775107120Sjulianstatic void 1776107120Sjulianrum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) 1777107120Sjulian{ 1778107120Sjulian uint32_t tmp; 1779107120Sjulian 1780107120Sjulian tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 1781114878Sjulian rum_write(sc, RT2573_MAC_CSR2, tmp); 1782107120Sjulian 1783107120Sjulian tmp = addr[4] | addr[5] << 8 | 0xff << 16; 1784107120Sjulian rum_write(sc, RT2573_MAC_CSR3, tmp); 1785107120Sjulian} 1786107120Sjulian 1787107120Sjulianstatic void 1788107120Sjulianrum_setpromisc(struct rum_softc *sc) 1789107120Sjulian{ 1790107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1791184205Sdes uint32_t tmp; 1792107120Sjulian 1793107120Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR0); 1794107120Sjulian 1795107120Sjulian tmp &= ~RT2573_DROP_NOT_TO_ME; 1796107120Sjulian if (!(ifp->if_flags & IFF_PROMISC)) 1797107120Sjulian tmp |= RT2573_DROP_NOT_TO_ME; 1798107120Sjulian 1799107120Sjulian rum_write(sc, RT2573_TXRX_CSR0, tmp); 1800107120Sjulian 1801107120Sjulian DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ? 1802107120Sjulian "entering" : "leaving"); 1803107120Sjulian} 1804107120Sjulian 1805107120Sjulianstatic void 1806107120Sjulianrum_update_promisc(struct ifnet *ifp) 1807107120Sjulian{ 1808107120Sjulian struct rum_softc *sc = ifp->if_softc; 1809107120Sjulian 1810107120Sjulian if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1811107120Sjulian return; 1812107120Sjulian 1813107120Sjulian RUM_LOCK(sc); 1814107120Sjulian rum_setpromisc(sc); 1815107120Sjulian RUM_UNLOCK(sc); 1816107120Sjulian} 1817107120Sjulian 1818107120Sjulianstatic const char * 1819107120Sjulianrum_get_rf(int rev) 1820107120Sjulian{ 1821107120Sjulian switch (rev) { 1822107120Sjulian case RT2573_RF_2527: return "RT2527 (MIMO XR)"; 1823107120Sjulian case RT2573_RF_2528: return "RT2528"; 1824107120Sjulian case RT2573_RF_5225: return "RT5225 (MIMO XR)"; 1825107120Sjulian case RT2573_RF_5226: return "RT5226"; 1826107120Sjulian default: return "unknown"; 1827107120Sjulian } 1828107120Sjulian} 1829107120Sjulian 1830107120Sjulianstatic void 1831107120Sjulianrum_read_eeprom(struct rum_softc *sc) 1832107120Sjulian{ 1833107120Sjulian uint16_t val; 1834107120Sjulian#ifdef RUM_DEBUG 1835107120Sjulian int i; 1836107120Sjulian#endif 1837107120Sjulian 1838107120Sjulian /* read MAC address */ 1839107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_ADDRESS, sc->sc_bssid, 6); 1840107120Sjulian 1841107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_ANTENNA, &val, 2); 1842107120Sjulian val = le16toh(val); 1843107120Sjulian sc->rf_rev = (val >> 11) & 0x1f; 1844107120Sjulian sc->hw_radio = (val >> 10) & 0x1; 1845107120Sjulian sc->rx_ant = (val >> 4) & 0x3; 1846107120Sjulian sc->tx_ant = (val >> 2) & 0x3; 1847107120Sjulian sc->nb_ant = val & 0x3; 1848107120Sjulian 1849107120Sjulian DPRINTF("RF revision=%d\n", sc->rf_rev); 1850107120Sjulian 1851107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_CONFIG2, &val, 2); 1852107120Sjulian val = le16toh(val); 1853107120Sjulian sc->ext_5ghz_lna = (val >> 6) & 0x1; 1854107120Sjulian sc->ext_2ghz_lna = (val >> 4) & 0x1; 1855107120Sjulian 1856107120Sjulian DPRINTF("External 2GHz LNA=%d\nExternal 5GHz LNA=%d\n", 1857107120Sjulian sc->ext_2ghz_lna, sc->ext_5ghz_lna); 1858107120Sjulian 1859107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_RSSI_2GHZ_OFFSET, &val, 2); 1860107120Sjulian val = le16toh(val); 1861107120Sjulian if ((val & 0xff) != 0xff) 1862107120Sjulian sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */ 1863107120Sjulian 1864107120Sjulian /* Only [-10, 10] is valid */ 1865107120Sjulian if (sc->rssi_2ghz_corr < -10 || sc->rssi_2ghz_corr > 10) 1866107120Sjulian sc->rssi_2ghz_corr = 0; 1867107120Sjulian 1868107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET, &val, 2); 1869157366Srwatson val = le16toh(val); 1870107120Sjulian if ((val & 0xff) != 0xff) 1871107120Sjulian sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */ 1872107120Sjulian 1873107120Sjulian /* Only [-10, 10] is valid */ 1874160549Srwatson if (sc->rssi_5ghz_corr < -10 || sc->rssi_5ghz_corr > 10) 1875107120Sjulian sc->rssi_5ghz_corr = 0; 1876107120Sjulian 1877160549Srwatson if (sc->ext_2ghz_lna) 1878160549Srwatson sc->rssi_2ghz_corr -= 14; 1879160549Srwatson if (sc->ext_5ghz_lna) 1880160549Srwatson sc->rssi_5ghz_corr -= 14; 1881160549Srwatson 1882160549Srwatson DPRINTF("RSSI 2GHz corr=%d\nRSSI 5GHz corr=%d\n", 1883160549Srwatson sc->rssi_2ghz_corr, sc->rssi_5ghz_corr); 1884107120Sjulian 1885107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_FREQ_OFFSET, &val, 2); 1886107120Sjulian val = le16toh(val); 1887107120Sjulian if ((val & 0xff) != 0xff) 1888107120Sjulian sc->rffreq = val & 0xff; 1889107120Sjulian 1890107120Sjulian DPRINTF("RF freq=%d\n", sc->rffreq); 1891107120Sjulian 1892107120Sjulian /* read Tx power for all a/b/g channels */ 1893107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_TXPOWER, sc->txpow, 14); 1894107120Sjulian /* XXX default Tx power for 802.11a channels */ 1895107120Sjulian memset(sc->txpow + 14, 24, sizeof (sc->txpow) - 14); 1896107120Sjulian#ifdef RUM_DEBUG 1897107120Sjulian for (i = 0; i < 14; i++) 1898107120Sjulian DPRINTF("Channel=%d Tx power=%d\n", i + 1, sc->txpow[i]); 1899107120Sjulian#endif 1900107120Sjulian 1901107120Sjulian /* read default values for BBP registers */ 1902107120Sjulian rum_eeprom_read(sc, RT2573_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16); 1903107120Sjulian#ifdef RUM_DEBUG 1904107120Sjulian for (i = 0; i < 14; i++) { 1905114878Sjulian if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff) 1906107120Sjulian continue; 1907107120Sjulian DPRINTF("BBP R%d=%02x\n", sc->bbp_prom[i].reg, 1908107120Sjulian sc->bbp_prom[i].val); 1909107120Sjulian } 1910107120Sjulian#endif 1911107120Sjulian} 1912107120Sjulian 1913107120Sjulianstatic int 1914107120Sjulianrum_bbp_init(struct rum_softc *sc) 1915107120Sjulian{ 1916107120Sjulian#define N(a) (sizeof (a) / sizeof ((a)[0])) 1917107120Sjulian int i, ntries; 1918107120Sjulian 1919107120Sjulian /* wait for BBP to be ready */ 1920107120Sjulian for (ntries = 0; ntries < 100; ntries++) { 1921107120Sjulian const uint8_t val = rum_bbp_read(sc, 0); 1922107120Sjulian if (val != 0 && val != 0xff) 1923107120Sjulian break; 1924107120Sjulian if (rum_pause(sc, hz / 100)) 1925107120Sjulian break; 1926107120Sjulian } 1927107120Sjulian if (ntries == 100) { 1928107120Sjulian device_printf(sc->sc_dev, "timeout waiting for BBP\n"); 1929107120Sjulian return EIO; 1930107120Sjulian } 1931107120Sjulian 1932107120Sjulian /* initialize BBP registers to default values */ 1933184205Sdes for (i = 0; i < N(rum_def_bbp); i++) 1934107120Sjulian rum_bbp_write(sc, rum_def_bbp[i].reg, rum_def_bbp[i].val); 1935107120Sjulian 1936107120Sjulian /* write vendor-specific BBP values (from EEPROM) */ 1937107120Sjulian for (i = 0; i < 16; i++) { 1938107120Sjulian if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff) 1939107120Sjulian continue; 1940107120Sjulian rum_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 1941107120Sjulian } 1942107120Sjulian 1943107120Sjulian return 0; 1944107120Sjulian#undef N 1945107120Sjulian} 1946107120Sjulian 1947107120Sjulianstatic void 1948107120Sjulianrum_init_locked(struct rum_softc *sc) 1949107120Sjulian{ 1950107120Sjulian#define N(a) (sizeof (a) / sizeof ((a)[0])) 1951107120Sjulian struct ifnet *ifp = sc->sc_ifp; 1952107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 1953107120Sjulian uint32_t tmp; 1954107120Sjulian usb_error_t error; 1955107120Sjulian int i, ntries; 1956107120Sjulian 1957107120Sjulian RUM_LOCK_ASSERT(sc, MA_OWNED); 1958107120Sjulian 1959107120Sjulian rum_stop(sc); 1960107120Sjulian 1961107120Sjulian /* initialize MAC registers to default values */ 1962114878Sjulian for (i = 0; i < N(rum_def_mac); i++) 1963114878Sjulian rum_write(sc, rum_def_mac[i].reg, rum_def_mac[i].val); 1964114878Sjulian 1965114878Sjulian /* set host ready */ 1966114878Sjulian rum_write(sc, RT2573_MAC_CSR1, 3); 1967114878Sjulian rum_write(sc, RT2573_MAC_CSR1, 0); 1968114878Sjulian 1969114878Sjulian /* wait for BBP/RF to wakeup */ 1970114878Sjulian for (ntries = 0; ntries < 100; ntries++) { 1971114878Sjulian if (rum_read(sc, RT2573_MAC_CSR12) & 8) 1972114878Sjulian break; 1973114878Sjulian rum_write(sc, RT2573_MAC_CSR12, 4); /* force wakeup */ 1974114878Sjulian if (rum_pause(sc, hz / 100)) 1975114878Sjulian break; 1976114878Sjulian } 1977114878Sjulian if (ntries == 100) { 1978114878Sjulian device_printf(sc->sc_dev, 1979114878Sjulian "timeout waiting for BBP/RF to wakeup\n"); 1980114878Sjulian goto fail; 1981114878Sjulian } 1982114878Sjulian 1983170035Srwatson if ((error = rum_bbp_init(sc)) != 0) 1984114878Sjulian goto fail; 1985114878Sjulian 1986167907Smaxim /* select default channel */ 1987114878Sjulian rum_select_band(sc, ic->ic_curchan); 1988114878Sjulian rum_select_antenna(sc); 1989114878Sjulian rum_set_chan(sc, ic->ic_curchan); 1990114878Sjulian 1991114878Sjulian /* clear STA registers */ 1992114878Sjulian rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); 1993114878Sjulian 1994114878Sjulian rum_set_macaddr(sc, IF_LLADDR(ifp)); 1995114878Sjulian 1996114878Sjulian /* initialize ASIC */ 1997114878Sjulian rum_write(sc, RT2573_MAC_CSR1, 4); 1998114878Sjulian 1999114878Sjulian /* 2000114878Sjulian * Allocate Tx and Rx xfer queues. 2001114878Sjulian */ 2002107120Sjulian rum_setup_tx_list(sc); 2003107120Sjulian 2004114878Sjulian /* update Rx filter */ 2005114878Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR0) & 0xffff; 2006114878Sjulian 2007107120Sjulian tmp |= RT2573_DROP_PHY_ERROR | RT2573_DROP_CRC_ERROR; 2008107120Sjulian if (ic->ic_opmode != IEEE80211_M_MONITOR) { 2009107120Sjulian tmp |= RT2573_DROP_CTL | RT2573_DROP_VER_ERROR | 2010107120Sjulian RT2573_DROP_ACKCTS; 2011107120Sjulian if (ic->ic_opmode != IEEE80211_M_HOSTAP) 2012107120Sjulian tmp |= RT2573_DROP_TODS; 2013107120Sjulian if (!(ifp->if_flags & IFF_PROMISC)) 2014107120Sjulian tmp |= RT2573_DROP_NOT_TO_ME; 2015107120Sjulian } 2016107120Sjulian rum_write(sc, RT2573_TXRX_CSR0, tmp); 2017107120Sjulian 2018107120Sjulian ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2019107120Sjulian ifp->if_drv_flags |= IFF_DRV_RUNNING; 2020107120Sjulian usbd_xfer_set_stall(sc->sc_xfer[RUM_BULK_WR]); 2021107120Sjulian usbd_transfer_start(sc->sc_xfer[RUM_BULK_RD]); 2022107120Sjulian return; 2023107120Sjulian 2024107120Sjulianfail: rum_stop(sc); 2025107120Sjulian#undef N 2026107120Sjulian} 2027107120Sjulian 2028107120Sjulianstatic void 2029107120Sjulianrum_init(void *priv) 2030107120Sjulian{ 2031107120Sjulian struct rum_softc *sc = priv; 2032107120Sjulian struct ifnet *ifp = sc->sc_ifp; 2033107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 2034107120Sjulian 2035107120Sjulian RUM_LOCK(sc); 2036107120Sjulian rum_init_locked(sc); 2037107120Sjulian RUM_UNLOCK(sc); 2038107120Sjulian 2039107120Sjulian if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2040107120Sjulian ieee80211_start_all(ic); /* start all vap's */ 2041107120Sjulian} 2042107120Sjulian 2043107120Sjulianstatic void 2044107120Sjulianrum_stop(struct rum_softc *sc) 2045107120Sjulian{ 2046107120Sjulian struct ifnet *ifp = sc->sc_ifp; 2047107120Sjulian uint32_t tmp; 2048107120Sjulian 2049107120Sjulian RUM_LOCK_ASSERT(sc, MA_OWNED); 2050107120Sjulian 2051107120Sjulian ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2052107120Sjulian 2053107120Sjulian RUM_UNLOCK(sc); 2054107120Sjulian 2055107120Sjulian /* 2056107120Sjulian * Drain the USB transfers, if not already drained: 2057107120Sjulian */ 2058107120Sjulian usbd_transfer_drain(sc->sc_xfer[RUM_BULK_WR]); 2059107120Sjulian usbd_transfer_drain(sc->sc_xfer[RUM_BULK_RD]); 2060107120Sjulian 2061107120Sjulian RUM_LOCK(sc); 2062107120Sjulian 2063107120Sjulian rum_unsetup_tx_list(sc); 2064107120Sjulian 2065107120Sjulian /* disable Rx */ 2066107120Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR0); 2067107120Sjulian rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); 2068107120Sjulian 2069107120Sjulian /* reset ASIC */ 2070107120Sjulian rum_write(sc, RT2573_MAC_CSR1, 3); 2071107120Sjulian rum_write(sc, RT2573_MAC_CSR1, 0); 2072107120Sjulian} 2073107120Sjulian 2074107120Sjulianstatic void 2075107120Sjulianrum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size) 2076107120Sjulian{ 2077107120Sjulian struct usb_device_request req; 2078107120Sjulian uint16_t reg = RT2573_MCU_CODE_BASE; 2079107120Sjulian usb_error_t err; 2080107120Sjulian 2081107120Sjulian /* copy firmware image into NIC */ 2082107120Sjulian for (; size >= 4; reg += 4, ucode += 4, size -= 4) { 2083107120Sjulian err = rum_write(sc, reg, UGETDW(ucode)); 2084107120Sjulian if (err) { 2085107120Sjulian /* firmware already loaded ? */ 2086107120Sjulian device_printf(sc->sc_dev, "Firmware load " 2087107120Sjulian "failure! (ignored)\n"); 2088107120Sjulian break; 2089107120Sjulian } 2090107120Sjulian } 2091107120Sjulian 2092107120Sjulian req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 2093107120Sjulian req.bRequest = RT2573_MCU_CNTL; 2094107120Sjulian USETW(req.wValue, RT2573_MCU_RUN); 2095107120Sjulian USETW(req.wIndex, 0); 2096107120Sjulian USETW(req.wLength, 0); 2097107120Sjulian 2098107120Sjulian err = rum_do_request(sc, &req, NULL); 2099107120Sjulian if (err != 0) { 2100107120Sjulian device_printf(sc->sc_dev, "could not run firmware: %s\n", 2101107120Sjulian usbd_errstr(err)); 2102107120Sjulian } 2103107120Sjulian 2104107120Sjulian /* give the chip some time to boot */ 2105107120Sjulian rum_pause(sc, hz / 8); 2106107120Sjulian} 2107114878Sjulian 2108114878Sjulianstatic int 2109114878Sjulianrum_prepare_beacon(struct rum_softc *sc, struct ieee80211vap *vap) 2110114878Sjulian{ 2111114878Sjulian struct ieee80211com *ic = vap->iv_ic; 2112114878Sjulian const struct ieee80211_txparam *tp; 2113114878Sjulian struct rum_tx_desc desc; 2114114878Sjulian struct mbuf *m0; 2115107120Sjulian 2116107120Sjulian m0 = ieee80211_beacon_alloc(vap->iv_bss, &RUM_VAP(vap)->bo); 2117107120Sjulian if (m0 == NULL) { 2118107120Sjulian return ENOBUFS; 2119107120Sjulian } 2120107120Sjulian 2121107120Sjulian tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; 2122107120Sjulian rum_setup_tx_desc(sc, &desc, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ, 2123107120Sjulian m0->m_pkthdr.len, tp->mgmtrate); 2124107120Sjulian 2125107120Sjulian /* copy the first 24 bytes of Tx descriptor into NIC memory */ 2126107120Sjulian rum_write_multi(sc, RT2573_HW_BEACON_BASE0, (uint8_t *)&desc, 24); 2127107120Sjulian 2128107120Sjulian /* copy beacon header and payload into NIC memory */ 2129107120Sjulian rum_write_multi(sc, RT2573_HW_BEACON_BASE0 + 24, mtod(m0, uint8_t *), 2130107120Sjulian m0->m_pkthdr.len); 2131107120Sjulian 2132107120Sjulian m_freem(m0); 2133107120Sjulian 2134107120Sjulian return 0; 2135107120Sjulian} 2136107120Sjulian 2137107120Sjulianstatic int 2138107120Sjulianrum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2139107120Sjulian const struct ieee80211_bpf_params *params) 2140107120Sjulian{ 2141107120Sjulian struct ifnet *ifp = ni->ni_ic->ic_ifp; 2142107120Sjulian struct rum_softc *sc = ifp->if_softc; 2143107120Sjulian 2144107120Sjulian RUM_LOCK(sc); 2145107120Sjulian /* prevent management frames from being sent if we're not ready */ 2146107120Sjulian if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2147107120Sjulian RUM_UNLOCK(sc); 2148107120Sjulian m_freem(m); 2149107120Sjulian ieee80211_free_node(ni); 2150107120Sjulian return ENETDOWN; 2151107120Sjulian } 2152107120Sjulian if (sc->tx_nfree < RUM_TX_MINFREE) { 2153107120Sjulian ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2154107120Sjulian RUM_UNLOCK(sc); 2155114878Sjulian m_freem(m); 2156114878Sjulian ieee80211_free_node(ni); 2157114878Sjulian return EIO; 2158114878Sjulian } 2159107120Sjulian 2160107120Sjulian ifp->if_opackets++; 2161107120Sjulian 2162107120Sjulian if (params == NULL) { 2163107120Sjulian /* 2164107120Sjulian * Legacy path; interpret frame contents to decide 2165107120Sjulian * precisely how to send the frame. 2166107120Sjulian */ 2167107120Sjulian if (rum_tx_mgt(sc, m, ni) != 0) 2168107120Sjulian goto bad; 2169107120Sjulian } else { 2170107120Sjulian /* 2171107120Sjulian * Caller supplied explicit parameters to use in 2172107120Sjulian * sending the frame. 2173107120Sjulian */ 2174107120Sjulian if (rum_tx_raw(sc, m, ni, params) != 0) 2175107120Sjulian goto bad; 2176107120Sjulian } 2177107120Sjulian RUM_UNLOCK(sc); 2178107120Sjulian 2179107120Sjulian return 0; 2180107120Sjulianbad: 2181107120Sjulian ifp->if_oerrors++; 2182107120Sjulian RUM_UNLOCK(sc); 2183107120Sjulian ieee80211_free_node(ni); 2184107120Sjulian return EIO; 2185107120Sjulian} 2186107120Sjulian 2187107120Sjulianstatic void 2188107120Sjulianrum_ratectl_start(struct rum_softc *sc, struct ieee80211_node *ni) 2189107120Sjulian{ 2190107120Sjulian struct ieee80211vap *vap = ni->ni_vap; 2191107120Sjulian struct rum_vap *rvp = RUM_VAP(vap); 2192107120Sjulian 2193107120Sjulian /* clear statistic registers (STA_CSR0 to STA_CSR5) */ 2194107120Sjulian rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); 2195107120Sjulian 2196107120Sjulian ieee80211_ratectl_node_init(ni); 2197107120Sjulian 2198107120Sjulian usb_callout_reset(&rvp->ratectl_ch, hz, rum_ratectl_timeout, rvp); 2199107120Sjulian} 2200107120Sjulian 2201107120Sjulianstatic void 2202107120Sjulianrum_ratectl_timeout(void *arg) 2203107120Sjulian{ 2204107120Sjulian struct rum_vap *rvp = arg; 2205107120Sjulian struct ieee80211vap *vap = &rvp->vap; 2206107120Sjulian struct ieee80211com *ic = vap->iv_ic; 2207107120Sjulian 2208107120Sjulian ieee80211_runtask(ic, &rvp->ratectl_task); 2209107120Sjulian} 2210107120Sjulian 2211107120Sjulianstatic void 2212107120Sjulianrum_ratectl_task(void *arg, int pending) 2213107120Sjulian{ 2214107120Sjulian struct rum_vap *rvp = arg; 2215107120Sjulian struct ieee80211vap *vap = &rvp->vap; 2216107120Sjulian struct ieee80211com *ic = vap->iv_ic; 2217107120Sjulian struct ifnet *ifp = ic->ic_ifp; 2218107120Sjulian struct rum_softc *sc = ifp->if_softc; 2219107120Sjulian struct ieee80211_node *ni = vap->iv_bss; 2220107120Sjulian int ok, fail; 2221107120Sjulian int sum, retrycnt; 2222107120Sjulian 2223107120Sjulian RUM_LOCK(sc); 2224107120Sjulian /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ 2225107120Sjulian rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof(sc->sta)); 2226107120Sjulian 2227107120Sjulian ok = (le32toh(sc->sta[4]) >> 16) + /* TX ok w/o retry */ 2228107120Sjulian (le32toh(sc->sta[5]) & 0xffff); /* TX ok w/ retry */ 2229107120Sjulian fail = (le32toh(sc->sta[5]) >> 16); /* TX retry-fail count */ 2230114878Sjulian sum = ok+fail; 2231114878Sjulian retrycnt = (le32toh(sc->sta[5]) & 0xffff) + fail; 2232114878Sjulian 2233114878Sjulian ieee80211_ratectl_tx_update(vap, ni, &sum, &ok, &retrycnt); 2234114878Sjulian (void) ieee80211_ratectl_rate(ni, NULL, 0); 2235107120Sjulian 2236107120Sjulian ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ 2237173231Semax 2238173231Semax usb_callout_reset(&rvp->ratectl_ch, hz, rum_ratectl_timeout, rvp); 2239173231Semax RUM_UNLOCK(sc); 2240173231Semax} 2241107120Sjulian 2242107120Sjulianstatic void 2243107120Sjulianrum_scan_start(struct ieee80211com *ic) 2244107120Sjulian{ 2245107120Sjulian struct ifnet *ifp = ic->ic_ifp; 2246107120Sjulian struct rum_softc *sc = ifp->if_softc; 2247107120Sjulian uint32_t tmp; 2248107120Sjulian 2249107120Sjulian RUM_LOCK(sc); 2250107120Sjulian /* abort TSF synchronization */ 2251107120Sjulian tmp = rum_read(sc, RT2573_TXRX_CSR9); 2252107120Sjulian rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); 2253107120Sjulian rum_set_bssid(sc, ifp->if_broadcastaddr); 2254107120Sjulian RUM_UNLOCK(sc); 2255107120Sjulian 2256107120Sjulian} 2257107120Sjulian 2258107120Sjulianstatic void 2259107120Sjulianrum_scan_end(struct ieee80211com *ic) 2260107120Sjulian{ 2261107120Sjulian struct rum_softc *sc = ic->ic_ifp->if_softc; 2262107120Sjulian 2263107120Sjulian RUM_LOCK(sc); 2264107120Sjulian rum_enable_tsf_sync(sc); 2265107120Sjulian rum_set_bssid(sc, sc->sc_bssid); 2266107120Sjulian RUM_UNLOCK(sc); 2267107120Sjulian 2268107120Sjulian} 2269107120Sjulian 2270107120Sjulianstatic void 2271107120Sjulianrum_set_channel(struct ieee80211com *ic) 2272107120Sjulian{ 2273107120Sjulian struct rum_softc *sc = ic->ic_ifp->if_softc; 2274107120Sjulian 2275107120Sjulian RUM_LOCK(sc); 2276107120Sjulian rum_set_chan(sc, ic->ic_curchan); 2277107120Sjulian RUM_UNLOCK(sc); 2278107120Sjulian} 2279107120Sjulian 2280107120Sjulianstatic int 2281107120Sjulianrum_get_rssi(struct rum_softc *sc, uint8_t raw) 2282157370Srwatson{ 2283107120Sjulian struct ifnet *ifp = sc->sc_ifp; 2284107120Sjulian struct ieee80211com *ic = ifp->if_l2com; 2285107120Sjulian int lna, agc, rssi; 2286107120Sjulian 2287157370Srwatson lna = (raw >> 5) & 0x3; 2288157370Srwatson agc = raw & 0x1f; 2289107120Sjulian 2290157370Srwatson if (lna == 0) { 2291107120Sjulian /* 2292114878Sjulian * No RSSI mapping 2293107120Sjulian * 2294107120Sjulian * NB: Since RSSI is relative to noise floor, -1 is 2295107120Sjulian * adequate for caller to know error happened. 2296107120Sjulian */ 2297107120Sjulian return -1; 2298107120Sjulian } 2299107120Sjulian 2300107120Sjulian rssi = (2 * agc) - RT2573_NOISE_FLOOR; 2301107120Sjulian 2302107120Sjulian if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { 2303107120Sjulian rssi += sc->rssi_2ghz_corr; 2304107120Sjulian 2305107120Sjulian if (lna == 1) 2306114878Sjulian rssi -= 64; 2307107120Sjulian else if (lna == 2) 2308107120Sjulian rssi -= 74; 2309107120Sjulian else if (lna == 3) 2310107120Sjulian rssi -= 90; 2311107120Sjulian } else { 2312107120Sjulian rssi += sc->rssi_5ghz_corr; 2313184205Sdes 2314107120Sjulian if (!sc->ext_5ghz_lna && lna != 1) 2315114878Sjulian rssi += 4; 2316114878Sjulian 2317107120Sjulian if (lna == 1) 2318107120Sjulian rssi -= 64; 2319107120Sjulian else if (lna == 2) 2320107120Sjulian rssi -= 86; 2321107120Sjulian else if (lna == 3) 2322107120Sjulian rssi -= 100; 2323107120Sjulian } 2324107120Sjulian return rssi; 2325107120Sjulian} 2326107120Sjulian 2327107120Sjulianstatic int 2328107120Sjulianrum_pause(struct rum_softc *sc, int timeout) 2329107120Sjulian{ 2330107120Sjulian 2331107120Sjulian usb_pause_mtx(&sc->sc_mtx, timeout); 2332107120Sjulian return (0); 2333107120Sjulian} 2334107120Sjulian 2335107120Sjulianstatic device_method_t rum_methods[] = { 2336107120Sjulian /* Device interface */ 2337107120Sjulian DEVMETHOD(device_probe, rum_match), 2338107120Sjulian DEVMETHOD(device_attach, rum_attach), 2339107120Sjulian DEVMETHOD(device_detach, rum_detach), 2340107120Sjulian 2341107120Sjulian { 0, 0 } 2342107120Sjulian}; 2343107120Sjulian 2344107120Sjulianstatic driver_t rum_driver = { 2345107120Sjulian .name = "rum", 2346107120Sjulian .methods = rum_methods, 2347107120Sjulian .size = sizeof(struct rum_softc), 2348107120Sjulian}; 2349107120Sjulian 2350107120Sjulianstatic devclass_t rum_devclass; 2351107120Sjulian 2352107120SjulianDRIVER_MODULE(rum, uhub, rum_driver, rum_devclass, NULL, 0); 2353107120Sjulian