summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2010-04-06 23:14:43 +0000
committerthompsa <thompsa@FreeBSD.org>2010-04-06 23:14:43 +0000
commit21bcf3828e198d7703a323f7b2eb17562938a9e5 (patch)
tree379d2e61e7cfdc4d6520abf93a4231262a318fb5 /sys
parentcd725da6e94b75152954f72050b78fe3399ac441 (diff)
downloadFreeBSD-src-21bcf3828e198d7703a323f7b2eb17562938a9e5.zip
FreeBSD-src-21bcf3828e198d7703a323f7b2eb17562938a9e5.tar.gz
MFC r203134
Add run(4), a driver for Ralink RT2700U/RT2800U/RT3000U USB 802.11agn devices. This driver was written for OpenBSD by Damien Bergamini and ported over by Akinori Furukoshi.
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files1
-rw-r--r--sys/contrib/dev/run/LICENSE39
-rw-r--r--sys/contrib/dev/run/run-rt2870bin0 -> 8192 bytes
-rw-r--r--sys/dev/usb/usbdevs209
-rw-r--r--sys/dev/usb/wlan/if_run.c4143
-rw-r--r--sys/dev/usb/wlan/if_runreg.h1130
-rw-r--r--sys/dev/usb/wlan/if_runvar.h222
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/modules/runfw/Makefile8
-rw-r--r--sys/modules/usb/Makefile2
-rw-r--r--sys/modules/usb/run/Makefile36
11 files changed, 5789 insertions, 2 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 86e9d47..0761487 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1717,6 +1717,7 @@ dev/usb/net/uhso.c optional uhso
# USB WLAN drivers
#
dev/usb/wlan/if_rum.c optional rum
+dev/usb/wlan/if_run.c optional run
dev/usb/wlan/if_uath.c optional uath
dev/usb/wlan/if_upgt.c optional upgt
dev/usb/wlan/if_ural.c optional ural
diff --git a/sys/contrib/dev/run/LICENSE b/sys/contrib/dev/run/LICENSE
new file mode 100644
index 0000000..39e3c52
--- /dev/null
+++ b/sys/contrib/dev/run/LICENSE
@@ -0,0 +1,39 @@
+Copyright (c) 2007, Ralink Technology Corporation
+All rights reserved.
+
+Redistribution. Redistribution and use in binary form, without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions must reproduce the above copyright notice and the
+ following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+* Neither the name of Ralink Technology Corporation nor the names of its
+ suppliers may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+* No reverse engineering, decompilation, or disassembly of this software
+ is permitted.
+
+Limited patent license. Ralink Technology Corporation grants a world-wide,
+royalty-free, non-exclusive license under patents it now or hereafter
+owns or controls to make, have made, use, import, offer to sell and
+sell ("Utilize") this software, but solely to the extent that any
+such patent is necessary to Utilize the software alone, or in
+combination with an operating system licensed under an approved Open
+Source license as listed by the Open Source Initiative at
+http://opensource.org/licenses. The patent license shall not apply to
+any other combinations which include this software. No hardware per
+se is licensed hereunder.
+
+DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/sys/contrib/dev/run/run-rt2870 b/sys/contrib/dev/run/run-rt2870
new file mode 100644
index 0000000..06ca5e1
--- /dev/null
+++ b/sys/contrib/dev/run/run-rt2870
Binary files differ
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 53d676d..e18f7be 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -524,6 +524,7 @@ vendor ELCON 0x0db7 ELCON Systemtechnik
vendor NETAC 0x0dd8 Netac
vendor SITECOMEU 0x0df6 Sitecom Europe
vendor MOBILEACTION 0x0df7 Mobile Action
+vendor AMIGO 0x0e0b Amigo Technology
vendor SPEEDDRAGON 0x0e55 Speed Dragon Multimedia
vendor HAWKING 0x0e66 Hawking
vendor FOSSIL 0x0e67 Fossil, Inc
@@ -589,12 +590,14 @@ vendor NETGEAR3 0x1385 Netgear
vendor BALTECH 0x13ad Baltech
vendor CISCOLINKSYS 0x13b1 Cisco-Linksys
vendor SHARK 0x13d2 Shark
+vendor AZUREWAVE 0x13d3 AsureWave
vendor EMTEC 0x13fe Emtec
vendor NOVATEL 0x1410 Novatel Wireless
vendor MERLIN 0x1416 Merlin
vendor WISTRONNEWEB 0x1435 Wistron NeWeb
vendor RADIOSHACK 0x1453 Radio Shack
vendor HUAWEI3COM 0x1472 Huawei-3Com
+vendor ABOCOM2 0x1482 AboCom Systems
vendor SILICOM 0x1485 Silicom
vendor RALINK 0x148f Ralink Technology
vendor IMAGINATION 0x149a Imagination Technologies
@@ -610,6 +613,7 @@ vendor OQO 0x1557 OQO
vendor UMEDIA 0x157e U-MEDIA Communications
vendor FIBERLINE 0x1582 Fiberline
vendor SPARKLAN 0x15a9 SparkLAN
+vendor AMIT2 0x15c5 AMIT
vendor SOHOWARE 0x15e8 SOHOware
vendor UMAX 0x1606 UMAX Data Systems
vendor INSIDEOUT 0x1608 Inside Out Networks
@@ -617,6 +621,7 @@ vendor AMOI 0x1614 Amoi Electronics
vendor GOODWAY 0x1631 Good Way Technology
vendor ENTREGA 0x1645 Entrega
vendor ACTIONTEC 0x1668 Actiontec Electronics
+vendor CISCOLINKSYS2 0x167b Cisco-Linksys
vendor ATHEROS 0x168c Atheros Communications
vendor GIGASET 0x1690 Gigaset
vendor GLOBALSUN 0x16ab Global Sun Technology
@@ -626,6 +631,8 @@ vendor CMOTECH 0x16d8 C-motech
vendor AXESSTEL 0x1726 Axesstel Co., Ltd.
vendor LINKSYS4 0x1737 Linksys
vendor SENAO 0x1740 Senao
+vendor ASUS2 0x1761 ASUS
+vendor SWEEX2 0x177f Sweex
vendor METAGEEK 0x1781 MetaGeek
vendor AMIT 0x18c5 AMIT
vendor QCOM 0x18e8 Qcom
@@ -637,11 +644,15 @@ vendor TCTMOBILE 0x1bbb TCT Mobile
vendor TELIT 0x1bc7 Telit
vendor MPMAN 0x1cae MpMan
vendor DRESDENELEKTRONIK 0x1cf1 dresden elektronik
+vendor PEGATRON 0x1d4d Pegatron
vendor QISDA 0x1da5 Qisda
vendor ALINK 0x1e0e Alink
+vendor AIRTIES 0x1eda AirTies
vendor DLINK 0x2001 D-Link
vendor PLANEX2 0x2019 Planex Communications
vendor TLAYTECH 0x20b9 Tlay Tech
+vendor ENCORE 0x203d Encore
+vendor PARA 0x20b8 PARA Industrial
vendor ERICSSON 0x2282 Ericsson
vendor MOTOROLA2 0x22b8 Motorola
vendor TRIPPLITE 0x2478 Tripp-Lite
@@ -667,6 +678,7 @@ vendor ZINWELL 0x5a57 Zinwell
vendor SITECOM 0x6189 Sitecom
vendor ARKMICRO 0x6547 Arkmicro Technologies Inc.
vendor 3COM2 0x6891 3Com
+vendor EDIMAX 0x7392 Edimax
vendor INTEL 0x8086 Intel
vendor INTEL2 0x8087 Intel
vendor SITECOM2 0x9016 Sitecom
@@ -701,6 +713,12 @@ product 3COMUSR USR56K 0x3021 U.S. Robotics 56000 Voice FaxModem Pro
/* AboCom products */
product ABOCOM XX1 0x110c XX1
product ABOCOM XX2 0x200c XX2
+product ABOCOM RT2770 0x2770 RT2770
+product ABOCOM RT2870 0x2870 RT2870
+product ABOCOM RT3070 0x3070 RT3070
+product ABOCOM RT3071 0x3071 RT3071
+product ABOCOM RT3072 0x3072 RT3072
+product ABOCOM2 RT2870_1 0x3c09 RT2870
product ABOCOM URE450 0x4000 URE450 Ethernet Adapter
product ABOCOM UFE1000 0x4002 UFE1000 Fast Ethernet Adapter
product ABOCOM DSB650TX_PNA 0x4003 1/10/100 Ethernet Adapter
@@ -731,6 +749,17 @@ product ACCTON SMCWUSBTG2_NF 0x4507 SMCWUSBT-G2 (no firmware)
product ACCTON SMCWUSBTG2 0x4508 SMCWUSBT-G2
product ACCTON PRISM_GT 0x4521 PrismGT USB 2.0 WLAN
product ACCTON SS1001 0x5046 SpeedStream Ethernet Adapter
+product ACCTON RT2870_2 0x6618 RT2870
+product ACCTON RT3070 0x7511 RT3070
+product ACCTON RT2770 0x7512 RT2770
+product ACCTON RT2870_3 0x7522 RT2870
+product ACCTON RT2870_5 0x8522 RT2870
+product ACCTON RT3070_4 0xa512 RT3070
+product ACCTON RT2870_4 0xa618 RT2870
+product ACCTON RT3070_1 0xa701 RT3070
+product ACCTON RT3070_2 0xa702 RT3070
+product ACCTON RT2870_1 0xb522 RT2870
+product ACCTON RT3070_3 0xc522 RT3070
product ACCTON ZD1211B 0xe501 ZD1211B
/* Aceeca products */
@@ -833,6 +862,9 @@ product AIRPLUS MCD650 0x3198 MCD650 modem
/* AirPrime products */
product AIRPRIME PC5220 0x0112 CDMA Wireless PC Card
+/* AirTies products */
+product AIRTIES RT3070 0x2310 RT3070
+
/* AKS products */
product AKS USBHASP 0x0001 USB-HASP 0.06
@@ -872,8 +904,20 @@ product APC UPS 0x0002 Uninterruptible Power Supply
product AMBIT WLAN 0x0302 WLAN
product AMBIT NTL_250 0x6098 NTL 250 cable modem
+/* American Power Conversion products */
+product APC UPS 0x0002 Uninterruptible Power Supply
+
+/* Amigo Technology products */
+product AMIGO RT2870_1 0x9031 RT2870
+product AMIGO RT2870_2 0x9041 RT2870
+
/* AMIT products */
product AMIT CGWLUSB2GO 0x0002 CG-WLUSB2GO
+product AMIT CGWLUSB2GNR 0x0008 CG-WLUSB2GNR
+product AMIT RT2870_1 0x0012 RT2870
+
+/* AMIT(2) products */
+product AMIT2 RT2870 0x0008 RT2870
/* Anchor products */
product ANCHOR EZUSB 0x2131 EZUSB
@@ -933,6 +977,7 @@ product ASIX AX88772 0x7720 AX88772
product ASIX AX88772A 0x772a AX88772A USB 2.0 10/100 Ethernet
/* ASUS products */
+product ASUS2 USBN11 0x0b05 USB-N11
product ASUS WL167G 0x1707 WL-167g Wireless Adapter
product ASUS WL159G 0x170c WL-159g
product ASUS A9T_WIFI 0x171b A9T wireless
@@ -940,6 +985,12 @@ product ASUS P5B_WIFI 0x171d P5B wireless
product ASUS RT2573_1 0x1723 RT2573
product ASUS RT2573_2 0x1724 RT2573
product ASUS LCM 0x1726 LCM display
+product ASUS RT2870_1 0x1731 RT2870
+product ASUS RT2870_2 0x1732 RT2870
+product ASUS RT2870_3 0x1742 RT2870
+product ASUS RT2870_4 0x1760 RT2870
+product ASUS RT2870_5 0x1761 RT2870
+product ASUS RT3070 0x1784 RT3070
product ASUS P535 0x420f ASUS P535 PDA
product ASUS GMSC 0x422f ASUS Generic Mass Storage
product ASUS RT2570 0x1706 RT2500USB Wireless Adapter
@@ -976,6 +1027,13 @@ product AVISION 1200U 0x0268 1200U scanner
/* Axesstel products */
product AXESSTEL DATAMODEM 0x1000 Data Modem
+/* AsureWave products */
+product AZUREWAVE RT2870_1 0x3247 RT2870
+product AZUREWAVE RT2870_2 0x3262 RT2870
+product AZUREWAVE RT3070_1 0x3273 RT3070
+product AZUREWAVE RT3070_2 0x3284 RT3070
+product AZUREWAVE RT3070_3 0x3305 RT3070
+
/* Baltech products */
product BALTECH CARDREADER 0x9999 Card reader
@@ -1006,8 +1064,13 @@ product BELKIN F5D7050A 0x705a F5D7050A Wireless Adapter
/* Also sold as 'Ativa 802.11g wireless card' */
product BELKIN F5D7050_V4000 0x705c F5D7050 v4000 Wireless Adapter
product BELKIN F5D7050E 0x705e F5D7050E Wireless Adapter
+product BELKIN RT2870_1 0x8053 RT2870
+product BELKIN RT2870_2 0x805c RT2870
+product BELKIN F5D8053V3 0x815c F5D8053 v3
+product BELKIN F5D8055 0x825a F5D8055
product BELKIN F5D9050V3 0x905b F5D9050 ver 3 Wireless Adapter
product BELKIN2 F5U002 0x0002 F5U002 Parallel printer
+product BELKIN F6D4050V1 0x935a F6D4050 v1
/* Billionton products */
product BILLIONTON USB100 0x0986 USB100N 10/100 FastEthernet
@@ -1084,6 +1147,7 @@ product CISCOLINKSYS HU200TS 0x001a HU200TS Wireless Adapter
product CISCOLINKSYS WUSB54GC 0x0020 WUSB54GC
product CISCOLINKSYS WUSB54GR 0x0023 WUSB54GR
product CISCOLINKSYS WUSBF54G 0x0024 WUSBF54G
+product CISCOLINKSYS2 RT3070 0x4001 RT3070
/* CMOTECH products */
product CMOTECH CNU510 0x5141 CDMA Technologies USB modem
@@ -1110,6 +1174,15 @@ product CONCEPTRONIC AR5523_2 0x7811 AR5523
product CONCEPTRONIC AR5523_2_NF 0x7812 AR5523 (no firmware)
product CONCEPTRONIC2 C54RU 0x3c02 C54RU WLAN
product CONCEPTRONIC2 C54RU2 0x3c22 C54RU
+product CONCEPTRONIC2 VIGORN61 0x3c25 VIGORN61
+product CONCEPTRONIC2 RT2870_1 0x3c06 RT2870
+product CONCEPTRONIC2 RT2870_2 0x3c07 RT2870
+product CONCEPTRONIC2 RT2870_7 0x3c09 RT2870
+product CONCEPTRONIC2 RT2870_8 0x3c12 RT2870
+product CONCEPTRONIC2 RT2870_3 0x3c23 RT2870
+product CONCEPTRONIC2 RT2870_4 0x3c25 RT2870
+product CONCEPTRONIC2 RT2870_5 0x3c27 RT2870
+product CONCEPTRONIC2 RT2870_6 0x3c28 RT2870
/* Connectix products */
product CONNECTIX QUICKCAM 0x0001 QuickCam
@@ -1124,6 +1197,12 @@ product COREGA FETHER_USB2_TX 0x0017 FEther USB2-TX
product COREGA WLUSB_11_KEY 0x001a ULUSB-11 Key
product COREGA CGWLUSB2GL 0x002d CG-WLUSB2GL
product COREGA CGWLUSB2GPX 0x002e CG-WLUSB2GPX
+product COREGA RT2870_1 0x002f RT2870
+product COREGA RT2870_2 0x003c RT2870
+product COREGA RT2870_3 0x003f RT2870
+product COREGA RT3070 0x0041 RT3070
+product COREGA CGWLUSB300GNM 0x0042 CG-WLUSB300GNM
+
product COREGA WLUSB_11_STICK 0x7613 WLAN USB Stick 11
product COREGA FETHER_USB_TXC 0x9601 FEther USB-TXC
@@ -1152,6 +1231,7 @@ product CYBERPOWER 1500CAVRLCD 0x0501 1500CAVRLCD
/* CyberTAN Technology products */
product CYBERTAN TG54USB 0x1666 TG54USB
+product CYBERTAN RT2870 0x1828 RT2870
/* Cypress Semiconductor products */
product CYPRESS MOUSE 0x0001 mouse
@@ -1229,6 +1309,8 @@ product DLINK DWLAG122 0x3a04 DWL-AG122
product DLINK DWLAG122_NF 0x3a05 DWL-AG122 (no firmware)
product DLINK DWLG122 0x3c00 DWL-G122 b1 Wireless Adapter
product DLINK DUBE100B1 0x3c05 DUB-E100 rev B1
+product DLINK RT2870 0x3c09 RT2870
+product DLINK RT3072 0x3c0a RT3072
product DLINK DSB650C 0x4000 10Mbps Ethernet
product DLINK DSB650TX1 0x4001 10/100 Ethernet
product DLINK DSB650TX 0x4002 10/100 Ethernet
@@ -1241,7 +1323,15 @@ product DLINK2 DWA120 0x3a0e DWA-120
product DLINK2 DWLG122C1 0x3c03 DWL-G122 c1
product DLINK2 WUA1340 0x3c04 WUA-1340
product DLINK2 DWA111 0x3c06 DWA-111
+product DLINK2 RT2870_1 0x3c09 RT2870
product DLINK2 DWA110 0x3c07 DWA-110
+product DLINK2 RT3072 0x3c0a RT3072
+product DLINK2 RT3070_1 0x3c0d RT3070
+product DLINK2 RT3070_2 0x3c0e RT3070
+product DLINK2 RT3070_3 0x3c0f RT3070
+product DLINK2 RT2870_2 0x3c11 RT2870
+product DLINK2 DWA130 0x3c13 DWA-130
+product DLINK2 RT3070_4 0x3c15 RT3070
product DLINK3 DWM652 0x3e04 DWM-652
/* DMI products */
@@ -1257,6 +1347,12 @@ product DRESDENELEKTRONIK WIRELESSHANDHELDTERMINAL 0x0004 Wireless Handheld Ter
/* Dynastream Innovations */
product DYNASTREAM ANTDEVBOARD 0x1003 ANT dev board
+/* Edimax products */
+product EDIMAX EW7318USG 0x7318 USB Wireless dongle
+product EDIMAX RT2870_1 0x7711 RT2870
+product EDIMAX EW7717 0x7717 EW-7717
+product EDIMAX EW7718 0x7718 EW-7718
+
/* Eicon Networks */
product EICON DIVA852 0x4905 Diva 852 ISDN TA
@@ -1285,6 +1381,11 @@ product ELSA USB2ETHERNET 0x3000 Microlink USB2Ethernet
/* EMS products */
product EMS DUAL_SHOOTER 0x0003 PSX gun controller converter
+/* Encore products */
+product ENCORE RT3070_1 0x1480 RT3070
+product ENCORE RT3070_2 0x14a1 RT3070
+product ENCORE RT3070_3 0x14a9 RT3070
+
/* Entrega products */
product ENTREGA 1S 0x0001 1S serial
product ENTREGA 2S 0x0002 2S serial
@@ -1429,6 +1530,11 @@ product GIGASET SMCWUSBTG_NF 0x0711 SMCWUSBT-G (no firmware)
product GIGASET AR5523 0x0712 AR5523
product GIGASET AR5523_NF 0x0713 AR5523 (no firmware)
product GIGASET RT2573 0x0722 RT2573
+product GIGASET RT3070_1 0x0740 RT3070
+product GIGASET RT3070_2 0x0744 RT3070
+product GIGABYTE RT2870_1 0x800b RT2870
+product GIGABYTE GNWB31N 0x800c GN-WB31N
+product GIGABYTE GNWB32L 0x800d GN-WB32L
/* Global Sun Technology product */
product GLOBALSUN AR5523_1 0x7801 AR5523
@@ -1464,6 +1570,7 @@ product GUILLEMOT DALEADER 0xa300 DA Leader
product GUILLEMOT HWGUSB254 0xe000 HWGUSB2-54 WLAN
product GUILLEMOT HWGUSB254LB 0xe010 HWGUSB2-54-LB
product GUILLEMOT HWGUSB254V2AP 0xe020 HWGUSB2-54V2-AP
+product GUILLEMOT HWNU300 0xe030 HWNU-300
/* Hagiwara products */
product HAGIWARA FGSM 0x0002 FlashGate SmartMedia Card Reader
@@ -1482,6 +1589,10 @@ product HANDSPRING TREO600 0x0300 Handspring Treo 600
product HAUPPAUGE WINTV_USB_FM 0x4d12 WinTV USB FM
/* Hawking Technologies products */
+product HAWKING RT2870_1 0x0001 RT2870
+product HAWKING RT2870_2 0x0003 RT2870
+product HAWKING HWUN2 0x0009 HWUN2
+product HAWKING RT3070 0x000b RT3070
product HAWKING UF100 0x400c 10/100 USB Ethernet
/* Hitachi, Ltd. products */
@@ -1528,6 +1639,7 @@ product HP 2215 0x1016 iPAQ 22xx/Jornada 548
product HP 568J 0x1116 Jornada 568
product HP 930C 0x1204 DeskJet 930c
product HP P2000U 0x1801 Inkjet P-2000U
+product HP HS2300 0x1e1d HS2300 HSDPA (aka MC8775)
product HP 640C 0x2004 DeskJet 640c
product HP 4670V 0x3005 ScanJet 4670v
product HP P1100 0x3102 Photosmart P1100
@@ -1655,6 +1767,10 @@ product IODATA USBETTXS 0x0913 USB ETTX
product IODATA USBWNB11A 0x0919 USB WN-B11
product IODATA USBWNB11 0x0922 USB Airport WN-B11
product IODATA ETGUS2 0x0930 ETG-US2
+product IODATA RT3072_1 0x0944 RT3072
+product IODATA RT3072_2 0x0945 RT3072
+product IODATA RT3072_3 0x0947 RT3072
+product IODATA RT3072_4 0x0948 RT3072
product IODATA USBRSAQ 0x0a03 Serial USB-RSAQ1
product IODATA2 USB2SC 0x0a09 USB2.0-SCSI Bridge USB2-SC
@@ -1779,7 +1895,11 @@ product LINKSYS2 WUSB11 0x2219 WUSB11 Wireless Adapter
product LINKSYS2 USB200M 0x2226 USB 2.0 10/100 Ethernet
product LINKSYS3 WUSB11v28 0x2233 WUSB11 v2.8 Wireless Adapter
product LINKSYS4 USB1000 0x0039 USB1000
+product LINKSYS4 WUSB100 0x0070 WUSB100
+product LINKSYS4 WUSB600N 0x0071 WUSB600N
product LINKSYS4 WUSB54GCV2 0x0073 WUSB54GC v2
+product LINKSYS4 WUSB54GCV3 0x0077 WUSB54GC v3
+product LINKSYS4 WUSB600NV2 0x0079 WUSB600N v2
/* Logitech products */
product LOGITECH M2452 0x0203 M2452 keyboard
@@ -1809,6 +1929,9 @@ product LOGITECH QUICKCAMPRO2 0xd001 QuickCam Pro
/* Logitec Corp. products */
product LOGITEC LDR_H443SU2 0x0033 DVD Multi-plus unit LDR-H443SU2
product LOGITEC LDR_H443U2 0x00b3 DVD Multi-plus unit LDR-H443U2
+product LOGITEC RT2870_1 0x0162 RT2870
+product LOGITEC RT2870_2 0x0163 RT2870
+product LOGITEC RT2870_3 0x0164 RT2870
/* Lucent products */
product LUCENT EVALKIT 0x1001 USS-720 evaluation kit
@@ -1846,7 +1969,10 @@ product MELCO PCOPRS1 0x00b3 PC-OP-RS1 RemoteStation
product MELCO SG54HP 0x00d8 WLI-U2-SG54HP
product MELCO G54HP 0x00d9 WLI-U2-G54HP
product MELCO KG54L 0x00da WLI-U2-KG54L
+product MELCO WLIUCG300N 0x00e8 WLI-UC-G300N
product MELCO SG54HG 0x00f4 WLI-U2-SG54HG
+product MELCO WLIUCAG300N 0x012e WLI-UC-AG300N
+product MELCO WLIUCGN 0x015d WLI-UC-GN
/* Merlin products */
product MERLIN V620 0x1110 Merlin V620
@@ -1864,15 +1990,25 @@ product MGE UPS2 0xffff MGE UPS SYSTEMS PROTECTIONCENTER 2
/* Micro Star International products */
product MSI BT_DONGLE 0x1967 Bluetooth USB dongle
+product MSI RT3070_1 0x3820 RT3070
+product MSI RT3070_2 0x3821 RT3070
+product MSI RT3070_3 0x3870 RT3070
product MSI UB11B 0x6823 UB11B
product MSI RT2570 0x6861 RT2570
product MSI RT2570_2 0x6865 RT2570
product MSI RT2570_3 0x6869 RT2570
product MSI RT2573_1 0x6874 RT2573
product MSI RT2573_2 0x6877 RT2573
+product MSI RT3070_4 0x6899 RT3070
+product MSI RT3070_5 0x821a RT3070
+product MSI RT3070_6 0x870a RT3070
+product MSI RT3070_7 0x899a RT3070
product MSI RT2573_3 0xa861 RT2573
product MSI RT2573_4 0xa874 RT2573
+/* Microdia products */
+product MICRODIA TWINKLECAM 0x600d TwinkleCam USB camera
+
/* Microsoft products */
product MICROSOFT SIDEPREC 0x0008 SideWinder Precision Pro
product MICROSOFT INTELLIMOUSE 0x0009 IntelliMouse
@@ -2021,8 +2157,12 @@ product NIKON D300 0x041a Digital Camera D300
product NOVATECH NV902 0x9020 NovaTech NV-902W
product NOVATECH RT2573 0x9021 RT2573
+/* Nokia products */
+product NOKIA N958GB 0x0070 Nokia N95 8GBc
+
/* Novatel Wireless products */
product NOVATEL V640 0x1100 Merlin V620
+product NOVATEL CDMA_MODEM 0x1110 Novatel Wireless Merlin CDMA
product NOVATEL V620 0x1110 Merlin V620
product NOVATEL V740 0x1120 Merlin V740
product NOVATEL V720 0x1130 Merlin V720
@@ -2034,6 +2174,7 @@ product NOVATEL X950D 0x1450 Merlin X950D
product NOVATEL ES620 0x2100 Expedite ES620
product NOVATEL E725 0x2120 Expedite E725
product NOVATEL ES620_2 0x2130 Expedite ES620
+product NOVATEL ES620 0x2100 ES620 CDMA
product NOVATEL U720 0x2110 Merlin U720
product NOVATEL EU730 0x2400 Expedite EU730
product NOVATEL EU740 0x2410 Expedite EU740
@@ -2140,6 +2281,14 @@ product PANASONIC KXLCB20AN 0x0d0a CD-R Drive KXL-CB20AN
product PANASONIC KXLCB35AN 0x0d0e DVD-ROM & CD-R/RW
product PANASONIC SDCAAE 0x1b00 MultiMediaCard
+/* PARA Industrial products */
+product PARA RT3070 0x8888 RT3070
+
+/* Pegatron products */
+product PEGATRON RT2870 0x0002 RT2870
+product PEGATRON RT3070 0x000c RT3070
+product PEGATRON RT3070_2 0x000e RT3070
+
/* Peracom products */
product PERACOM SERIAL1 0x0001 Serial
product PERACOM ENET 0x0002 Ethernet
@@ -2157,6 +2306,7 @@ product PHILIPS SPE3030CC 0x083a USB 2.0 External Disk
product PHILIPS SNU5600 0x1236 SNU5600
product PHILIPS UM10016 0x1552 ISP 1581 Hi-Speed USB MPEG2 Encoder Reference Kit
product PHILIPS DIVAUSB 0x1801 DIVA USB mp3 player
+product PHILIPS RT2870 0x200f RT2870
/* Philips Semiconductor products */
product PHILIPSSEMI HUB1122 0x1122 HUB
@@ -2172,11 +2322,15 @@ product PLANEX GW_US11H 0x14ea GW-US11H WLAN
product PLANEX2 GW_US11S 0x3220 GW-US11S WLAN
product PLANEX2 GW_US54GXS 0x5303 GW-US54GXS WLAN
product PLANEX2 GWUS54HP 0xab01 GW-US54HP
+product PLANEX2 GWUS300MINIS 0xab24 GW-US300MiniS
+product PLANEX2 RT3070 0xab25 RT3070
product PLANEX2 GWUS54MINI2 0xab50 GW-US54Mini2
product PLANEX2 GWUS54SG 0xc002 GW-US54SG
product PLANEX2 GWUS54GZL 0xc007 GW-US54GZL
product PLANEX2 GWUS54GD 0xed01 GW-US54GD
product PLANEX2 GWUSMM 0xed02 GW-USMM
+product PLANEX2 RT2870 0xed06 RT2870
+product PLANEX2 GWUSMICRON 0xed14 GW-USMicroN
product PLANEX3 GWUS54GZ 0xab10 GW-US54GZ
product PLANEX3 GU1000T 0xab11 GU-1000T
product PLANEX3 GWUS54MINI 0xab13 GW-US54Mini
@@ -2234,6 +2388,7 @@ product PUTERCOM UPA100 0x047e USB-1284 BRIDGE
product QCOM RT2573 0x6196 RT2573
product QCOM RT2573_2 0x6229 RT2573
product QCOM RT2573_3 0x6238 RT2573
+product QCOM RT2870 0x6259 RT2870
/* Qisda products */
product QISDA H21_1 0x4512 3G modem
@@ -2320,6 +2475,8 @@ product QUALCOMMINC E2002 0x2002 3G modem
product QUALCOMMINC E2003 0x2003 3G modem
/* Quanta products */
+/* Quanta products */
+product QUANTA RT3070 0x0304 RT3070
product QUANTA Q101 0xea02 HSDPA modem
product QUANTA Q111 0xea03 HSDPA modem
product QUANTA GLX 0xea04 HSDPA modem
@@ -2340,9 +2497,16 @@ product RAINBOW IKEY2000 0x1200 i-Key 2000
/* Ralink Technology products */
product RALINK RT2570 0x1706 RT2500USB Wireless Adapter
+product RALINK RT2070 0x2070 RT2070
product RALINK RT2570_2 0x2570 RT2500USB Wireless Adapter
product RALINK RT2573 0x2573 RT2501USB Wireless Adapter
product RALINK RT2671 0x2671 RT2601USB Wireless Adapter
+product RALINK RT2770 0x2770 RT2770
+product RALINK RT2870 0x2870 RT2870
+product RALINK RT3070 0x3070 RT3070
+product RALINK RT3071 0x3071 RT3071
+product RALINK RT3072 0x3072 RT3072
+product RALINK RT3572 0x3572 RT3572
product RALINK RT2570_3 0x9020 RT2500USB Wireless Adapter
product RALINK RT2573_2 0x9021 RT2501USB Wireless Adapter
@@ -2383,6 +2547,7 @@ product SAGEM XG76NA 0x0062 XG-76NA
product SAMSUNG ML6060 0x3008 ML-6060 laser printer
product SAMSUNG YP_U2 0x5050 YP-U2 MP3 Player
product SAMSUNG I500 0x6601 I500 Palm USB Phone
+product SAMSUNG2 RT2870_1 0x2018 RT2870
/* Samsung Techwin products */
product SAMSUNG_TECHWIN DIGIMAX_410 0x000a Digimax 410
@@ -2406,7 +2571,18 @@ product SCANLOGIC SL11R 0x0002 SL11R IDE Adapter
product SCANLOGIC 336CX 0x0300 Phantom 336CX - C3 scanner
/* Senao products */
+product SENAO RT2870_3 0x0605 RT2870
+product SENAO RT2870_4 0x0615 RT2870
product SENAO NUB8301 0x2000 NUB-8301
+product SENAO RT2870_1 0x9701 RT2870
+product SENAO RT2870_2 0x9702 RT2870
+product SENAO RT3070 0x9703 RT3070
+product SENAO RT3071 0x9705 RT3071
+product SENAO RT3072_1 0x9706 RT3072
+product SENAO RT3072_2 0x9707 RT3072
+product SENAO RT3072_3 0x9708 RT3072
+product SENAO RT3072_4 0x9709 RT3072
+product SENAO RT3072_5 0x9801 RT3072
/* ShanTou products */
product SHANTOU ST268 0x0268 ST268
@@ -2453,7 +2629,9 @@ product SIEMENS3 X75 0x0004 X75
product SIERRA EM5625 0x0017 EM5625
product SIERRA MC5720_2 0x0018 MC5720
product SIERRA MC5725 0x0020 MC5725
+product SIERRA AIRCARD580 0x0112 Sierra Wireless AirCard 580
product SIERRA AIRCARD595 0x0019 Sierra Wireless AirCard 595
+product SIERRA AC595U 0x0120 Sierra Wireless AirCard 595U
product SIERRA AC597E 0x0021 Sierra Wireless AirCard 597E
product SIERRA EM5725 0x0022 EM5725
product SIERRA C597 0x0023 Sierra Wireless Compass 597
@@ -2553,8 +2731,24 @@ product SITECOM SERIAL 0x2068 USB to serial cable (v2)
product SITECOM2 WL022 0x182d WL-022
/* Sitecom Europe products */
+product SITECOMEU RT2870_1 0x0017 RT2870
product SITECOMEU WL168V1 0x000d WL-168 v1
product SITECOMEU WL168V4 0x0028 WL-168 v4
+product SITECOMEU RT2870_2 0x002b RT2870
+product SITECOMEU RT2870_3 0x002c RT2870
+product SITECOMEU RT2870_4 0x002d RT2870
+product SITECOMEU RT2770 0x0039 RT2770
+product SITECOMEU RT3070_2 0x003b RT3070
+product SITECOMEU RT3070_3 0x003c RT3070
+product SITECOMEU RT3070_4 0x003d RT3070
+product SITECOMEU RT3070 0x003e RT3070
+product SITECOMEU WL608 0x003f WL-608
+product SITECOMEU RT3072_1 0x0041 RT3072
+product SITECOMEU RT3072_2 0x0042 RT3072
+product SITECOMEU RT3072_3 0x0047 RT3072
+product SITECOMEU RT3072_4 0x0048 RT3072
+product SITECOMEU RT3072_5 0x004a RT3072
+product SITECOMEU RT3072_6 0x004d RT3072
product SITECOMEU LN028 0x061c LN-028
product SITECOMEU WL113 0x9071 WL-113
product SITECOMEU ZD1211B 0x9075 ZD1211B
@@ -2612,7 +2806,9 @@ product SOURCENEXT KEIKAI8 0x039f KeikaiDenwa 8
product SOURCENEXT KEIKAI8_CHG 0x012e KeikaiDenwa 8 with charger
/* SparkLAN products */
-product SPARKLAN RT2573 0x0004 RT2573
+product SPARKLAN RT2573 0x0004 RT2573
+product SPARKLAN RT2870_1 0x0006 RT2870
+product SPARKLAN RT3070 0x0010 RT3070
/* Sphairon Access Systems GmbH products */
product SPHAIRON UB801R 0x0110 UB801R
@@ -2682,6 +2878,8 @@ product SURECOM RT2573 0x31f3 RT2573
/* Sweex products */
product SWEEX ZD1211 0x1809 ZD1211
+product SWEEX2 LW303 0x0302 LW303
+product SWEEX2 LW313 0x0313 LW313
/* System TALKS, Inc. */
product SYSTEMTALKS SGCX2UL 0x1920 SGC-X2UL
@@ -2775,6 +2973,7 @@ product UMEDIA TEW444UBEU_NF 0x3007 TEW-444UB EU (no firmware)
product UMEDIA TEW429UB_A 0x300a TEW-429UB_A
product UMEDIA TEW429UB 0x300b TEW-429UB
product UMEDIA TEW429UBC1 0x300d TEW-429UB C1
+product UMEDIA RT2870_1 0x300e RT2870
product UMEDIA ALL0298V2 0x3204 ALL0298 v2
product UMEDIA AR5523_2 0x3205 AR5523
product UMEDIA AR5523_2_NF 0x3206 AR5523 (no firmware)
@@ -2884,9 +3083,16 @@ product ZCOM AR5523 0x0012 AR5523
product ZCOM AR5523_NF 0x0013 AR5523 driver (no firmware)
product ZCOM XM142 0x0015 XM-142
product ZCOM ZD1211B 0x001a ZD1211B
+product ZCOM RT2870_1 0x0022 RT2870
+product ZCOM RT2870_2 0x0025 RT2870
/* Zinwell products */
product ZINWELL RT2570 0x0260 RT2570
+product ZINWELL RT2870_1 0x0280 RT2870
+product ZINWELL RT2870_2 0x0282 RT2870
+product ZINWELL RT3072_1 0x0283 RT3072
+product ZINWELL RT3072_2 0x0284 RT3072
+product ZINWELL RT3070 0x5257 RT3070
/* Zoom Telephonics, Inc. products */
product ZOOM 2986L 0x9700 2986L Fax modem
@@ -2907,3 +3113,4 @@ product ZYXEL AG225H 0x3409 AG-225H
product ZYXEL M202 0x340a M-202
product ZYXEL G220V2 0x340f G-220 v2
product ZYXEL G202 0x3410 G-202
+product ZYXEL RT2870_1 0x3416 RT2870
diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c
new file mode 100644
index 0000000..92acd47
--- /dev/null
+++ b/sys/dev/usb/wlan/if_run.c
@@ -0,0 +1,4143 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 2008,2009 Damien Bergamini <damien.bergamini@free.fr>
+ * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* release date Jan. 09, 2010 */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * Ralink Technology RT2700U/RT2800U/RT3000U chipset driver.
+ * http://www.ralinktech.com/
+ */
+
+#include <sys/param.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/linker.h>
+#include <sys/firmware.h>
+#include <sys/kdb.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_amrr.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include "usbdevs.h"
+
+#define USB_DEBUG_VAR run_debug
+#include <dev/usb/usb_debug.h>
+
+#include "if_runreg.h" /* shared with ral(4) */
+#include "if_runvar.h"
+
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+
+#if USB_DEBUG
+#define RUN_DEBUG
+#endif
+
+#ifdef RUN_DEBUG
+int run_debug = 0;
+SYSCTL_NODE(_hw_usb, OID_AUTO, run, CTLFLAG_RW, 0, "USB run");
+SYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0,
+ "run debug level");
+#endif
+
+#define IEEE80211_HAS_ADDR4(wh) \
+ (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
+
+static const struct usb_device_id run_devs[] = {
+ { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2770) },
+ { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2870) },
+ { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT3070) },
+ { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT3071) },
+ { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT3072) },
+ { USB_VP(USB_VENDOR_ABOCOM2, USB_PRODUCT_ABOCOM2_RT2870_1) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2770) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_1) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_2) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_3) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_4) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT2870_5) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_1) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_2) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_3) },
+ { USB_VP(USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_RT3070_4) },
+ { USB_VP(USB_VENDOR_AIRTIES, USB_PRODUCT_AIRTIES_RT3070) },
+ { USB_VP(USB_VENDOR_AMIGO, USB_PRODUCT_AMIGO_RT2870_1) },
+ { USB_VP(USB_VENDOR_AMIGO, USB_PRODUCT_AMIGO_RT2870_2) },
+ { USB_VP(USB_VENDOR_AMIT, USB_PRODUCT_AMIT_CGWLUSB2GNR) },
+ { USB_VP(USB_VENDOR_AMIT, USB_PRODUCT_AMIT_RT2870_1) },
+ { USB_VP(USB_VENDOR_AMIT2, USB_PRODUCT_AMIT2_RT2870) },
+ { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_1) },
+ { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_2) },
+ { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_3) },
+ { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_4) },
+ { USB_VP(USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RT2870_5) },
+ { USB_VP(USB_VENDOR_ASUS2, USB_PRODUCT_ASUS2_USBN11) },
+ { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT2870_1) },
+ { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT2870_2) },
+ { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT3070_1) },
+ { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT3070_2) },
+ { USB_VP(USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_RT3070_3) },
+ { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D8053V3) },
+ { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D8055) },
+ { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6D4050V1) },
+ { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RT2870_1) },
+ { USB_VP(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RT2870_2) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_1) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_2) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_3) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_4) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_5) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_6) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_7) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_RT2870_8) },
+ { USB_VP(USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_VIGORN61) },
+ { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB300GNM) },
+ { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT2870_1) },
+ { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT2870_2) },
+ { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT2870_3) },
+ { USB_VP(USB_VENDOR_COREGA, USB_PRODUCT_COREGA_RT3070) },
+ { USB_VP(USB_VENDOR_CYBERTAN, USB_PRODUCT_CYBERTAN_RT2870) },
+ { USB_VP(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RT2870) },
+ { USB_VP(USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RT3072) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA130) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT2870_1) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT2870_2) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_1) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_2) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_3) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3070_4) },
+ { USB_VP(USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_RT3072) },
+ { USB_VP(USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_EW7717) },
+ { USB_VP(USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_EW7718) },
+ { USB_VP(USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_RT2870_1) },
+ { USB_VP(USB_VENDOR_ENCORE, USB_PRODUCT_ENCORE_RT3070_1) },
+ { USB_VP(USB_VENDOR_ENCORE, USB_PRODUCT_ENCORE_RT3070_2) },
+ { USB_VP(USB_VENDOR_ENCORE, USB_PRODUCT_ENCORE_RT3070_3) },
+ { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWB31N) },
+ { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWB32L) },
+ { USB_VP(USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_RT2870_1) },
+ { USB_VP(USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_RT3070_1) },
+ { USB_VP(USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_RT3070_2) },
+ { USB_VP(USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWNU300) },
+ { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_HWUN2) },
+ { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RT2870_1) },
+ { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RT2870_2) },
+ { USB_VP(USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_RT3070) },
+ { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_1) },
+ { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_2) },
+ { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_3) },
+ { USB_VP(USB_VENDOR_IODATA, USB_PRODUCT_IODATA_RT3072_4) },
+ { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB100) },
+ { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB54GCV3) },
+ { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB600N) },
+ { USB_VP(USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_WUSB600NV2) },
+ { USB_VP(USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_RT2870_1) },
+ { USB_VP(USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_RT2870_2) },
+ { USB_VP(USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_RT2870_3) },
+ { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_WLIUCAG300N) },
+ { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_WLIUCG300N) },
+ { USB_VP(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_WLIUCGN) },
+ { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_1) },
+ { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_2) },
+ { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_3) },
+ { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_4) },
+ { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_5) },
+ { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_6) },
+ { USB_VP(USB_VENDOR_MSI, USB_PRODUCT_MSI_RT3070_7) },
+ { USB_VP(USB_VENDOR_PARA, USB_PRODUCT_PARA_RT3070) },
+ { USB_VP(USB_VENDOR_PEGATRON, USB_PRODUCT_PEGATRON_RT2870) },
+ { USB_VP(USB_VENDOR_PEGATRON, USB_PRODUCT_PEGATRON_RT3070) },
+ { USB_VP(USB_VENDOR_PEGATRON, USB_PRODUCT_PEGATRON_RT3070_2) },
+ { USB_VP(USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_RT2870) },
+ { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS300MINIS) },
+ { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUSMICRON) },
+ { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RT2870) },
+ { USB_VP(USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_RT3070) },
+ { USB_VP(USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2870) },
+ { USB_VP(USB_VENDOR_QUANTA, USB_PRODUCT_QUANTA_RT3070) },
+ { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2070) },
+ { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2770) },
+ { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2870) },
+ { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3070) },
+ { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3071) },
+ { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3072) },
+ { USB_VP(USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT3572) },
+ { USB_VP(USB_VENDOR_SAMSUNG2, USB_PRODUCT_SAMSUNG2_RT2870_1) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_1) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_2) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_3) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT2870_4) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3070) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3071) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_1) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_2) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_3) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_4) },
+ { USB_VP(USB_VENDOR_SENAO, USB_PRODUCT_SENAO_RT3072_5) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2770) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_1) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_2) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_3) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT2870_4) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070_2) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070_3) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3070_4) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_1) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_2) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_3) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_4) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_5) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_RT3072_6) },
+ { USB_VP(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL608) },
+ { USB_VP(USB_VENDOR_SPARKLAN, USB_PRODUCT_SPARKLAN_RT2870_1) },
+ { USB_VP(USB_VENDOR_SPARKLAN, USB_PRODUCT_SPARKLAN_RT3070) },
+ { USB_VP(USB_VENDOR_SWEEX2, USB_PRODUCT_SWEEX2_LW303) },
+ { USB_VP(USB_VENDOR_SWEEX2, USB_PRODUCT_SWEEX2_LW313) },
+ { USB_VP(USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_RT2870_1) },
+ { USB_VP(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_RT2870_1) },
+ { USB_VP(USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_RT2870_2) },
+ { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT2870_1) },
+ { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT2870_2) },
+ { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT3070) },
+ { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT3072_1) },
+ { USB_VP(USB_VENDOR_ZINWELL, USB_PRODUCT_ZINWELL_RT3072_2) },
+ { USB_VP(USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_RT2870_1) },
+};
+
+MODULE_DEPEND(run, wlan, 1, 1, 1);
+MODULE_DEPEND(run, wlan_amrr, 1, 1, 1);
+MODULE_DEPEND(run, usb, 1, 1, 1);
+MODULE_DEPEND(run, firmware, 1, 1, 1);
+
+static device_probe_t run_match;
+static device_attach_t run_attach;
+static device_detach_t run_detach;
+
+static usb_callback_t run_bulk_rx_callback;
+static usb_callback_t run_bulk_tx_callback0;
+static usb_callback_t run_bulk_tx_callback1;
+static usb_callback_t run_bulk_tx_callback2;
+static usb_callback_t run_bulk_tx_callback3;
+static usb_callback_t run_bulk_tx_callback4;
+static usb_callback_t run_bulk_tx_callback5;
+
+static void run_bulk_tx_callbackN(struct usb_xfer *xfer,
+ usb_error_t error, unsigned int index);
+static struct ieee80211vap *run_vap_create(struct ieee80211com *,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t
+ mac[IEEE80211_ADDR_LEN]);
+static void run_vap_delete(struct ieee80211vap *);
+static void run_setup_tx_list(struct run_softc *,
+ struct run_endpoint_queue *);
+static void run_unsetup_tx_list(struct run_softc *,
+ struct run_endpoint_queue *);
+static int run_load_microcode(struct run_softc *);
+static int run_reset(struct run_softc *);
+static usb_error_t run_do_request(struct run_softc *,
+ struct usb_device_request *, void *);
+static int run_read(struct run_softc *, uint16_t, uint32_t *);
+static int run_read_region_1(struct run_softc *, uint16_t, uint8_t *, int);
+static int run_write_2(struct run_softc *, uint16_t, uint16_t);
+static int run_write(struct run_softc *, uint16_t, uint32_t);
+static int run_write_region_1(struct run_softc *, uint16_t,
+ const uint8_t *, int);
+static int run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
+static int run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
+static int run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
+static int run_rt2870_rf_write(struct run_softc *, uint8_t, uint32_t);
+static int run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
+static int run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
+static int run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
+static int run_bbp_write(struct run_softc *, uint8_t, uint8_t);
+static int run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
+static const char *run_get_rf(int);
+static int run_read_eeprom(struct run_softc *);
+static struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
+ const uint8_t mac[IEEE80211_ADDR_LEN]);
+static int run_media_change(struct ifnet *);
+static int run_newstate(struct ieee80211vap *, enum ieee80211_state, int);
+static int run_wme_update(struct ieee80211com *);
+static void run_wme_update_cb(void *, int);
+static void run_key_update_begin(struct ieee80211vap *);
+static void run_key_update_end(struct ieee80211vap *);
+static int run_key_set(struct ieee80211vap *, const struct ieee80211_key *,
+ const uint8_t mac[IEEE80211_ADDR_LEN]);
+static int run_key_delete(struct ieee80211vap *,
+ const struct ieee80211_key *);
+static void run_amrr_start(struct run_softc *, struct ieee80211_node *);
+static void run_amrr_to(void *);
+static void run_amrr_cb(void *, int);
+static void run_iter_func(void *, struct ieee80211_node *);
+static void run_newassoc(struct ieee80211_node *, int);
+static void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t);
+static void run_tx_free(struct run_endpoint_queue *pq,
+ struct run_tx_data *, int);
+static void run_set_tx_desc(struct run_softc *, struct run_tx_data *,
+ uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
+static int run_tx(struct run_softc *, struct mbuf *,
+ struct ieee80211_node *);
+static int run_tx_mgt(struct run_softc *, struct mbuf *,
+ struct ieee80211_node *);
+static int run_sendprot(struct run_softc *, const struct mbuf *,
+ struct ieee80211_node *, int, int);
+static int run_tx_param(struct run_softc *, struct mbuf *,
+ struct ieee80211_node *,
+ const struct ieee80211_bpf_params *);
+static int run_raw_xmit(struct ieee80211_node *, struct mbuf *,
+ const struct ieee80211_bpf_params *);
+static void run_start(struct ifnet *);
+static int run_ioctl(struct ifnet *, u_long, caddr_t);
+static void run_select_chan_group(struct run_softc *, int);
+static void run_set_rx_antenna(struct run_softc *, int);
+static void run_rt2870_set_chan(struct run_softc *, u_int);
+static void run_rt3070_set_chan(struct run_softc *, u_int);
+static int run_set_chan(struct run_softc *, struct ieee80211_channel *);
+static void run_set_channel(struct ieee80211com *);
+static void run_scan_start(struct ieee80211com *);
+static void run_scan_end(struct ieee80211com *);
+static uint8_t run_rate2mcs(uint8_t);
+static void run_update_beacon(struct ieee80211vap *, int);
+static void run_update_beacon_locked(struct ieee80211vap *, int);
+static void run_updateprot(struct ieee80211com *);
+static void run_usb_timeout_cb(void *, int);
+static void run_reset_livelock(struct run_softc *);
+static void run_enable_tsf_sync(struct run_softc *);
+static void run_enable_mrr(struct run_softc *);
+static void run_set_txpreamble(struct run_softc *);
+static void run_set_basicrates(struct run_softc *);
+static void run_set_leds(struct run_softc *, uint16_t);
+static void run_set_bssid(struct run_softc *, const uint8_t *);
+static void run_set_macaddr(struct run_softc *, const uint8_t *);
+static void run_updateslot(struct ifnet *);
+static int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
+static void run_update_promisc_locked(struct ifnet *);
+static void run_update_promisc(struct ifnet *);
+static int run_bbp_init(struct run_softc *);
+static int run_rt3070_rf_init(struct run_softc *);
+static int run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
+ uint8_t *);
+static int run_txrx_enable(struct run_softc *);
+static void run_init(void *);
+static void run_init_locked(struct run_softc *);
+static void run_stop(void *);
+static void run_delay(struct run_softc *, unsigned int);
+
+static const struct {
+ uint32_t reg;
+ uint32_t val;
+} rt2870_def_mac[] = {
+ RT2870_DEF_MAC
+};
+
+static const struct {
+ uint8_t reg;
+ uint8_t val;
+} rt2860_def_bbp[] = {
+ RT2860_DEF_BBP
+};
+
+static const struct rfprog {
+ uint8_t chan;
+ uint32_t r1, r2, r3, r4;
+} rt2860_rf2850[] = {
+ RT2860_RF2850
+};
+
+struct {
+ uint8_t n, r, k;
+} run_rf3020_freqs[] = {
+ RT3070_RF3020
+};
+
+static const struct {
+ uint8_t reg;
+ uint8_t val;
+} rt3070_def_rf[] = {
+ RT3070_DEF_RF
+};
+
+static const struct usb_config run_config[RUN_N_XFER] = {
+ [RUN_BULK_TX_BE] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .ep_index = 0,
+ .direction = UE_DIR_OUT,
+ .bufsize = RUN_MAX_TXSZ,
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .callback = run_bulk_tx_callback0,
+ .timeout = 5000, /* ms */
+ },
+ [RUN_BULK_TX_BK] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_OUT,
+ .ep_index = 1,
+ .bufsize = RUN_MAX_TXSZ,
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .callback = run_bulk_tx_callback1,
+ .timeout = 5000, /* ms */
+ },
+ [RUN_BULK_TX_VI] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_OUT,
+ .ep_index = 2,
+ .bufsize = RUN_MAX_TXSZ,
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .callback = run_bulk_tx_callback2,
+ .timeout = 5000, /* ms */
+ },
+ [RUN_BULK_TX_VO] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_OUT,
+ .ep_index = 3,
+ .bufsize = RUN_MAX_TXSZ,
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .callback = run_bulk_tx_callback3,
+ .timeout = 5000, /* ms */
+ },
+ [RUN_BULK_TX_HCCA] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_OUT,
+ .ep_index = 4,
+ .bufsize = RUN_MAX_TXSZ,
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
+ .callback = run_bulk_tx_callback4,
+ .timeout = 5000, /* ms */
+ },
+ [RUN_BULK_TX_PRIO] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_OUT,
+ .ep_index = 5,
+ .bufsize = RUN_MAX_TXSZ,
+ .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,},
+ .callback = run_bulk_tx_callback5,
+ .timeout = 5000, /* ms */
+ },
+ [RUN_BULK_RX] = {
+ .type = UE_BULK,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_IN,
+ .bufsize = RUN_MAX_RXSZ,
+ .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+ .callback = run_bulk_rx_callback,
+ }
+};
+
+int
+run_match(device_t self)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(self);
+
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return (ENXIO);
+ if (uaa->info.bConfigIndex != 0)
+ return (ENXIO);
+ if (uaa->info.bIfaceIndex != RT2860_IFACE_INDEX)
+ return (ENXIO);
+
+ return (usbd_lookup_id_by_uaa(run_devs, sizeof(run_devs), uaa));
+}
+
+static int
+run_attach(device_t self)
+{
+ struct run_softc *sc = device_get_softc(self);
+ struct usb_attach_arg *uaa = device_get_ivars(self);
+ struct ieee80211com *ic;
+ struct ifnet *ifp;
+ int i, ntries, error;
+ uint8_t iface_index, bands;
+
+ device_set_usb_desc(self);
+ sc->sc_udev = uaa->device;
+ sc->sc_dev = self;
+
+ mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev),
+ MTX_NETWORK_LOCK, MTX_DEF);
+
+ iface_index = RT2860_IFACE_INDEX;
+ /* Rx transfer has own lock */
+ error = usbd_transfer_setup(uaa->device, &iface_index,
+ sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx);
+ if (error) {
+ device_printf(self, "could not allocate USB Tx transfers, "
+ "err=%s\n", usbd_errstr(error));
+ goto detach;
+ }
+
+ RUN_LOCK(sc);
+
+ /* wait for the chip to settle */
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (run_read(sc, RT2860_ASIC_VER_ID, &sc->mac_rev) != 0){
+ RUN_UNLOCK(sc);
+ goto detach;
+ }
+ if (sc->mac_rev != 0 && sc->mac_rev != 0xffffffff)
+ break;
+ run_delay(sc, 10);
+ }
+ if (ntries == 100) {
+ printf("%s: timeout waiting for NIC to initialize\n",
+ device_get_nameunit(sc->sc_dev));
+ RUN_UNLOCK(sc);
+ goto detach;
+ }
+
+ /* retrieve RF rev. no and various other things from EEPROM */
+ run_read_eeprom(sc);
+
+ printf("%s: MAC/BBP RT%04X (rev 0x%04X), RF %s (MIMO %dT%dR), "
+ "address %s\n", device_get_nameunit(sc->sc_dev), sc->mac_rev >> 16,
+ sc->mac_rev & 0xffff, run_get_rf(sc->rf_rev), sc->ntxchains,
+ sc->nrxchains, ether_sprintf(sc->sc_bssid));
+
+ if ((error = run_load_microcode(sc)) != 0) {
+ printf("%s: could not load 8051 microcode\n",
+ device_get_nameunit(sc->sc_dev));
+ RUN_UNLOCK(sc);
+ goto detach;
+ }
+
+ RUN_UNLOCK(sc);
+
+ ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
+ if(ifp == NULL){
+ printf("%s: can not if_alloc()\n",
+ device_get_nameunit(sc->sc_dev));
+ goto detach;
+ }
+ ic = ifp->if_l2com;
+
+ ifp->if_softc = sc;
+ if_initname(ifp, "run", device_get_unit(sc->sc_dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_init = run_init;
+ ifp->if_ioctl = run_ioctl;
+ ifp->if_start = run_start;
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ic->ic_ifp = ifp;
+ ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
+ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
+#if 0
+ ic->ic_state = IEEE80211_S_INIT;
+#endif
+ /* set device capabilities */
+ ic->ic_caps =
+ IEEE80211_C_STA | /* station mode supported */
+ IEEE80211_C_MONITOR | /* monitor mode supported */
+ IEEE80211_C_IBSS |
+ IEEE80211_C_HOSTAP |
+ IEEE80211_C_SHPREAMBLE | /* short preamble supported */
+ IEEE80211_C_SHSLOT | /* short slot time supported */
+ IEEE80211_C_WME | /* WME */
+ IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */
+
+ ic->ic_cryptocaps =
+ IEEE80211_CRYPTO_WEP |
+ IEEE80211_CRYPTO_AES_CCM |
+ IEEE80211_CRYPTO_TKIPMIC |
+ IEEE80211_CRYPTO_TKIP;
+
+ ic->ic_flags |= IEEE80211_F_DATAPAD;
+ ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
+
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ ieee80211_init_channels(ic, NULL, &bands);
+
+ /*
+ * Do this by own because h/w supports
+ * more channels than ieee80211_init_channels()
+ */
+ if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850) {
+ /* set supported .11a rates */
+ for (i = 14; i < nitems(rt2860_rf2850); i++) {
+ uint8_t chan = rt2860_rf2850[i].chan;
+ ic->ic_channels[ic->ic_nchans].ic_freq =
+ ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A);
+ ic->ic_channels[ic->ic_nchans].ic_ieee = chan;
+ ic->ic_channels[ic->ic_nchans].ic_flags = IEEE80211_CHAN_A;
+ ic->ic_channels[ic->ic_nchans].ic_extieee = 0;
+ ic->ic_nchans++;
+ }
+ }
+
+ ieee80211_ifattach(ic, sc->sc_bssid);
+
+ ic->ic_scan_start = run_scan_start;
+ ic->ic_scan_end = run_scan_end;
+ ic->ic_set_channel = run_set_channel;
+ ic->ic_node_alloc = run_node_alloc;
+ ic->ic_newassoc = run_newassoc;
+ //ic->ic_updateslot = run_updateslot;
+ ic->ic_wme.wme_update = run_wme_update;
+ ic->ic_raw_xmit = run_raw_xmit;
+ ic->ic_update_promisc = run_update_promisc;
+
+ ic->ic_vap_create = run_vap_create;
+ ic->ic_vap_delete = run_vap_delete;
+
+ ieee80211_radiotap_attach(ic,
+ &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
+ RUN_TX_RADIOTAP_PRESENT,
+ &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
+ RUN_RX_RADIOTAP_PRESENT);
+
+ if (bootverbose)
+ ieee80211_announce(ic);
+
+ return 0;
+
+detach:
+ run_detach(self);
+ return(ENXIO);
+}
+
+static int
+run_detach(device_t self)
+{
+ struct run_softc *sc = device_get_softc(self);
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic;
+ int i;
+
+ /* stop all USB transfers */
+ usbd_transfer_unsetup(sc->sc_xfer, RUN_N_XFER);
+
+ RUN_LOCK(sc);
+ /* free TX list, if any */
+ for (i = 0; i != RUN_EP_QUEUES; i++)
+ run_unsetup_tx_list(sc, &sc->sc_epq[i]);
+ RUN_UNLOCK(sc);
+
+ if (ifp) {
+ ic = ifp->if_l2com;
+ ieee80211_ifdetach(ic);
+ if_free(ifp);
+ }
+
+ mtx_destroy(&sc->sc_mtx);
+
+ return (0);
+}
+
+static struct ieee80211vap *
+run_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+ struct run_vap *rvp;
+ struct ieee80211vap *vap;
+
+ if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
+ return NULL;
+ sc->sc_rvp = rvp = (struct run_vap *) malloc(sizeof(struct run_vap),
+ M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (rvp == NULL)
+ return NULL;
+ vap = &rvp->vap;
+ /* enable s/w bmiss handling for sta mode */
+ ieee80211_vap_setup(ic, vap, name, unit, opmode,
+ flags | IEEE80211_CLONE_NOBEACONS, bssid, mac);
+
+ vap->iv_key_update_begin = run_key_update_begin;
+ vap->iv_key_update_end = run_key_update_end;
+ vap->iv_key_delete = run_key_delete;
+ vap->iv_key_set = run_key_set;
+ vap->iv_update_beacon = run_update_beacon;
+
+ /* override state transition machine */
+ rvp->newstate = vap->iv_newstate;
+ vap->iv_newstate = run_newstate;
+
+ TASK_INIT(&rvp->amrr_task, 0, run_amrr_cb, rvp);
+ TASK_INIT(&sc->wme_task, 0, run_wme_update_cb, ic);
+ TASK_INIT(&sc->usb_timeout_task, 0, run_usb_timeout_cb, sc);
+ callout_init((struct callout *)&rvp->amrr_ch, 1);
+ ieee80211_amrr_init(&rvp->amrr, vap,
+ IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
+ IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
+ 1000 /* 1 sec */);
+
+ /* complete setup */
+ ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status);
+ ic->ic_opmode = opmode;
+ return vap;
+}
+
+static void
+run_vap_delete(struct ieee80211vap *vap)
+{
+ struct run_vap *rvp = RUN_VAP(vap);
+ struct ifnet *ifp;
+ struct ieee80211com *ic;
+ struct run_softc *sc;
+
+ if(vap == NULL)
+ return;
+
+ ic = vap->iv_ic;
+ ifp = ic->ic_ifp;
+
+ sc = ifp->if_softc;
+
+ if (ifp && ifp->if_flags & IFF_UP){
+ RUN_LOCK(sc);
+ run_stop(sc);
+ RUN_UNLOCK(sc);
+ }
+
+ ieee80211_amrr_cleanup(&rvp->amrr);
+ ieee80211_vap_detach(vap);
+ free(rvp, M_80211_VAP);
+ sc->sc_rvp = NULL;
+}
+
+static void
+run_setup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
+{
+ struct run_tx_data *data;
+
+ memset(pq, 0, sizeof(*pq));
+
+ STAILQ_INIT(&pq->tx_qh);
+ STAILQ_INIT(&pq->tx_fh);
+
+ for (data = &pq->tx_data[0];
+ data < &pq->tx_data[RUN_TX_RING_COUNT]; data++) {
+ data->sc = sc;
+ STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
+ }
+ pq->tx_nfree = RUN_TX_RING_COUNT;
+}
+
+static void
+run_unsetup_tx_list(struct run_softc *sc, struct run_endpoint_queue *pq)
+{
+ struct run_tx_data *data;
+
+ /* make sure any subsequent use of the queues will fail */
+ pq->tx_nfree = 0;
+ STAILQ_INIT(&pq->tx_fh);
+ STAILQ_INIT(&pq->tx_qh);
+
+ /* free up all node references and mbufs */
+ for (data = &pq->tx_data[0];
+ data < &pq->tx_data[RUN_TX_RING_COUNT]; data++){
+ if (data->m != NULL) {
+ m_freem(data->m);
+ data->m = NULL;
+ }
+ if (data->ni != NULL) {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ }
+ }
+}
+
+int
+run_load_microcode(struct run_softc *sc)
+{
+ usb_device_request_t req;
+ const u_char *base;
+ uint32_t tmp;
+ int ntries, error;
+ const uint64_t *temp;
+ uint64_t bytes;
+
+ if((sc->fwp = firmware_get("runfw")) == NULL){
+ printf("%s: failed loadfirmware of file %s (error %d)\n",
+ device_get_nameunit(sc->sc_dev), "runfw", ENOENT);
+ return ENOENT;
+ }
+
+ if (sc->fwp->datasize != 8192) {
+ printf("%s: invalid firmware size (should be 8KB)\n",
+ device_get_nameunit(sc->sc_dev));
+ return EINVAL;
+ }
+
+ /*
+ * RT3071/RT3072 use a different firmware
+ * run-rt2870 (8KB) contains both,
+ * first half (4KB) is for rt2870,
+ * last half is for rt3071.
+ */
+ base = sc->fwp->data;
+ if ((sc->mac_rev >> 16) != 0x2860 &&
+ (sc->mac_rev >> 16) != 0x2872 &&
+ (sc->mac_rev >> 16) != 0x3070 &&
+ (sc->mac_rev >> 16) != 0x3572){
+ base += 4096;
+ printf("%s: You are using firmware RT3071.\n",
+ device_get_nameunit(sc->sc_dev));
+ } else
+ printf("%s: You are using firmware RT2870.\n",
+ device_get_nameunit(sc->sc_dev));
+
+ /* cheap sanity check */
+ temp = sc->fwp->data;
+ bytes = *temp;
+ if(bytes != be64toh(0xffffff0210280210))
+ return EINVAL;
+
+ run_read(sc, RT2860_ASIC_VER_ID, &tmp);
+ /* write microcode image */
+ run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
+ run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
+ run_write(sc, RT2860_H2M_MAILBOX_STATUS, 0xffffffff);
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = RT2870_RESET;
+ USETW(req.wValue, 8);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ if ((error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL)) != 0)
+ return error;
+
+ run_delay(sc, 10);
+
+ run_write(sc, RT2860_H2M_MAILBOX, 0);
+ if ((error = run_mcu_cmd(sc, RT2860_MCU_CMD_BOOT, 0)) != 0)
+ return error;
+
+ /* wait until microcontroller is ready */
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if ((error = run_read(sc, RT2860_SYS_CTRL, &tmp)) != 0)
+ return error;
+ if (tmp & RT2860_MCU_READY)
+ break;
+ run_delay(sc, 10);
+ }
+ if (ntries == 1000) {
+ printf("%s: timeout waiting for MCU to initialize\n",
+ device_get_nameunit(sc->sc_dev));
+ return ETIMEDOUT;
+ }
+ DPRINTF("microcode successfully loaded after %d tries\n", ntries);
+
+ return 0;
+}
+
+int
+run_reset(struct run_softc *sc)
+{
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = RT2870_RESET;
+ USETW(req.wValue, 1);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ return usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL);
+}
+
+static usb_error_t
+run_do_request(struct run_softc *sc,
+ struct usb_device_request *req, void *data)
+{
+ usb_error_t err;
+ int ntries = 10;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ while (ntries--) {
+ err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
+ req, data, 0, NULL, 250 /* ms */);
+ if (err == 0)
+ break;
+ DPRINTFN(1, "Control request failed, %s (retrying)\n",
+ usbd_errstr(err));
+ run_delay(sc, 10);
+ }
+ return (err);
+}
+
+static int
+run_read(struct run_softc *sc, uint16_t reg, uint32_t *val)
+{
+ uint32_t tmp;
+ int error;
+
+ error = run_read_region_1(sc, reg, (uint8_t *)&tmp, sizeof tmp);
+ if (error == 0)
+ *val = le32toh(tmp);
+ else
+ *val = 0xffffffff;
+ return error;
+}
+
+static int
+run_read_region_1(struct run_softc *sc, uint16_t reg, uint8_t *buf, int len)
+{
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = RT2870_READ_REGION_1;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, reg);
+ USETW(req.wLength, len);
+
+ return run_do_request(sc, &req, buf);
+}
+
+static int
+run_write_2(struct run_softc *sc, uint16_t reg, uint16_t val)
+{
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = RT2870_WRITE_2;
+ USETW(req.wValue, val);
+ USETW(req.wIndex, reg);
+ USETW(req.wLength, 0);
+
+ return run_do_request(sc, &req, NULL);
+}
+
+static int
+run_write(struct run_softc *sc, uint16_t reg, uint32_t val)
+{
+ int error;
+
+ if ((error = run_write_2(sc, reg, val & 0xffff)) == 0)
+ error = run_write_2(sc, reg + 2, val >> 16);
+ return error;
+}
+
+static int
+run_write_region_1(struct run_softc *sc, uint16_t reg, const uint8_t *buf,
+ int len)
+{
+#if 1
+ int i, error = 0;
+ /*
+ * NB: the WRITE_REGION_1 command is not stable on RT2860.
+ * We thus issue multiple WRITE_2 commands instead.
+ */
+ KASSERT((len & 1) == 0, ("run_write_region_1: Data too long.\n"));
+ for (i = 0; i < len && error == 0; i += 2)
+ error = run_write_2(sc, reg + i, buf[i] | buf[i + 1] << 8);
+ return error;
+#else
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = RT2870_WRITE_REGION_1;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, reg);
+ USETW(req.wLength, len);
+ return run_do_request(sc, &req, buf);
+#endif
+}
+
+static int
+run_set_region_4(struct run_softc *sc, uint16_t reg, uint32_t val, int len)
+{
+ int i, error = 0;
+
+ KASSERT((len & 3) == 0, ("run_set_region_4: Invalid data length.\n"));
+ for (i = 0; i < len && error == 0; i += 4)
+ error = run_write(sc, reg + i, val);
+ return error;
+}
+
+/* Read 16-bit from eFUSE ROM (RT3070 only.) */
+static int
+run_efuse_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
+{
+ uint32_t tmp;
+ uint16_t reg;
+ int error, ntries;
+
+ if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
+ return error;
+
+ addr *= 2;
+ /*-
+ * Read one 16-byte block into registers EFUSE_DATA[0-3]:
+ * DATA0: F E D C
+ * DATA1: B A 9 8
+ * DATA2: 7 6 5 4
+ * DATA3: 3 2 1 0
+ */
+ tmp &= ~(RT3070_EFSROM_MODE_MASK | RT3070_EFSROM_AIN_MASK);
+ tmp |= (addr & ~0xf) << RT3070_EFSROM_AIN_SHIFT | RT3070_EFSROM_KICK;
+ run_write(sc, RT3070_EFUSE_CTRL, tmp);
+ for (ntries = 0; ntries < 100; ntries++) {
+ if ((error = run_read(sc, RT3070_EFUSE_CTRL, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT3070_EFSROM_KICK))
+ break;
+ run_delay(sc, 2);
+ }
+ if (ntries == 100)
+ return ETIMEDOUT;
+
+ if ((tmp & RT3070_EFUSE_AOUT_MASK) == RT3070_EFUSE_AOUT_MASK) {
+ *val = 0xffff; /* address not found */
+ return 0;
+ }
+ /* determine to which 32-bit register our 16-bit word belongs */
+ reg = RT3070_EFUSE_DATA3 - (addr & 0xc);
+ if ((error = run_read(sc, reg, &tmp)) != 0)
+ return error;
+
+ *val = (addr & 2) ? tmp >> 16 : tmp & 0xffff;
+ return 0;
+}
+
+static int
+run_eeprom_read_2(struct run_softc *sc, uint16_t addr, uint16_t *val)
+{
+ usb_device_request_t req;
+ uint16_t tmp;
+ int error;
+
+ addr *= 2;
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = RT2870_EEPROM_READ;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, addr);
+ USETW(req.wLength, sizeof tmp);
+
+ error = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &tmp);
+ if (error == 0)
+ *val = le16toh(tmp);
+ else
+ *val = 0xffff;
+ return error;
+}
+
+static __inline int
+run_srom_read(struct run_softc *sc, uint16_t addr, uint16_t *val)
+{
+ /* either eFUSE ROM or EEPROM */
+ return sc->sc_srom_read(sc, addr, val);
+}
+
+static int
+run_rt2870_rf_write(struct run_softc *sc, uint8_t reg, uint32_t val)
+{
+ uint32_t tmp;
+ int error, ntries;
+
+ for (ntries = 0; ntries < 10; ntries++) {
+ if ((error = run_read(sc, RT2860_RF_CSR_CFG0, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT2860_RF_REG_CTRL))
+ break;
+ }
+ if (ntries == 10)
+ return ETIMEDOUT;
+
+ /* RF registers are 24-bit on the RT2860 */
+ tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT |
+ (val & 0x3fffff) << 2 | (reg & 3);
+ return run_write(sc, RT2860_RF_CSR_CFG0, tmp);
+}
+
+static int
+run_rt3070_rf_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
+{
+ uint32_t tmp;
+ int error, ntries;
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT3070_RF_KICK))
+ break;
+ }
+ if (ntries == 100)
+ return ETIMEDOUT;
+
+ tmp = RT3070_RF_KICK | reg << 8;
+ if ((error = run_write(sc, RT3070_RF_CSR_CFG, tmp)) != 0)
+ return error;
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT3070_RF_KICK))
+ break;
+ }
+ if (ntries == 100)
+ return ETIMEDOUT;
+
+ *val = tmp & 0xff;
+ return 0;
+}
+
+static int
+run_rt3070_rf_write(struct run_softc *sc, uint8_t reg, uint8_t val)
+{
+ uint32_t tmp;
+ int error, ntries;
+
+ for (ntries = 0; ntries < 10; ntries++) {
+ if ((error = run_read(sc, RT3070_RF_CSR_CFG, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT3070_RF_KICK))
+ break;
+ }
+ if (ntries == 10)
+ return ETIMEDOUT;
+
+ tmp = RT3070_RF_WRITE | RT3070_RF_KICK | reg << 8 | val;
+ return run_write(sc, RT3070_RF_CSR_CFG, tmp);
+}
+
+static int
+run_bbp_read(struct run_softc *sc, uint8_t reg, uint8_t *val)
+{
+ uint32_t tmp;
+ int ntries, error;
+
+ for (ntries = 0; ntries < 10; ntries++) {
+ if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT2860_BBP_CSR_KICK))
+ break;
+ }
+ if (ntries == 10)
+ return ETIMEDOUT;
+
+ tmp = RT2860_BBP_CSR_READ | RT2860_BBP_CSR_KICK | reg << 8;
+ if ((error = run_write(sc, RT2860_BBP_CSR_CFG, tmp)) != 0)
+ return error;
+
+ for (ntries = 0; ntries < 10; ntries++) {
+ if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT2860_BBP_CSR_KICK))
+ break;
+ }
+ if (ntries == 10)
+ return ETIMEDOUT;
+
+ *val = tmp & 0xff;
+ return 0;
+}
+
+static int
+run_bbp_write(struct run_softc *sc, uint8_t reg, uint8_t val)
+{
+ uint32_t tmp;
+ int ntries, error;
+
+ for (ntries = 0; ntries < 10; ntries++) {
+ if ((error = run_read(sc, RT2860_BBP_CSR_CFG, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT2860_BBP_CSR_KICK))
+ break;
+ }
+ if (ntries == 10)
+ return ETIMEDOUT;
+
+ tmp = RT2860_BBP_CSR_KICK | reg << 8 | val;
+ return run_write(sc, RT2860_BBP_CSR_CFG, tmp);
+}
+
+/*
+ * Send a command to the 8051 microcontroller unit.
+ */
+static int
+run_mcu_cmd(struct run_softc *sc, uint8_t cmd, uint16_t arg)
+{
+ uint32_t tmp;
+ int error, ntries;
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if ((error = run_read(sc, RT2860_H2M_MAILBOX, &tmp)) != 0)
+ return error;
+ if (!(tmp & RT2860_H2M_BUSY))
+ break;
+ }
+ if (ntries == 100)
+ return ETIMEDOUT;
+
+ tmp = RT2860_H2M_BUSY | RT2860_TOKEN_NO_INTR << 16 | arg;
+ if ((error = run_write(sc, RT2860_H2M_MAILBOX, tmp)) == 0)
+ error = run_write(sc, RT2860_HOST_CMD, cmd);
+ return error;
+}
+
+/*
+ * Add `delta' (signed) to each 4-bit sub-word of a 32-bit word.
+ * Used to adjust per-rate Tx power registers.
+ */
+static __inline uint32_t
+b4inc(uint32_t b32, int8_t delta)
+{
+ int8_t i, b4;
+
+ for (i = 0; i < 8; i++) {
+ b4 = b32 & 0xf;
+ b4 += delta;
+ if (b4 < 0)
+ b4 = 0;
+ else if (b4 > 0xf)
+ b4 = 0xf;
+ b32 = b32 >> 4 | b4 << 28;
+ }
+ return b32;
+}
+
+static const char *
+run_get_rf(int rev)
+{
+ switch (rev) {
+ case RT2860_RF_2820: return "RT2820";
+ case RT2860_RF_2850: return "RT2850";
+ case RT2860_RF_2720: return "RT2720";
+ case RT2860_RF_2750: return "RT2750";
+ case RT3070_RF_3020: return "RT3020";
+ case RT3070_RF_2020: return "RT2020";
+ case RT3070_RF_3021: return "RT3021";
+ case RT3070_RF_3022: return "RT3022";
+ case RT3070_RF_3052: return "RT3052";
+ }
+ return "unknown";
+}
+
+int
+run_read_eeprom(struct run_softc *sc)
+{
+ int8_t delta_2ghz, delta_5ghz;
+ uint32_t tmp;
+ uint16_t val;
+ int ridx, ant, i;
+
+ /* check whether the ROM is eFUSE ROM or EEPROM */
+ sc->sc_srom_read = run_eeprom_read_2;
+ if ((sc->mac_rev & 0xfff00000) >= 0x30700000) {
+ run_read(sc, RT3070_EFUSE_CTRL, &tmp);
+ DPRINTF("EFUSE_CTRL=0x%08x\n", tmp);
+ if (tmp & RT3070_SEL_EFUSE)
+ sc->sc_srom_read = run_efuse_read_2;
+ }
+
+ /* read ROM version */
+ run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
+ DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
+
+ /* read MAC address */
+ run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
+ sc->sc_bssid[0] = val & 0xff;
+ sc->sc_bssid[1] = val >> 8;
+ run_srom_read(sc, RT2860_EEPROM_MAC23, &val);
+ sc->sc_bssid[2] = val & 0xff;
+ sc->sc_bssid[3] = val >> 8;
+ run_srom_read(sc, RT2860_EEPROM_MAC45, &val);
+ sc->sc_bssid[4] = val & 0xff;
+ sc->sc_bssid[5] = val >> 8;
+
+ /* read default BBP settings */
+ for (i = 0; i < 8; i++) {
+ run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
+ sc->bbp[i].val = val & 0xff;
+ sc->bbp[i].reg = val >> 8;
+ DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, sc->bbp[i].val);
+ }
+
+ /* read RF frequency offset from EEPROM */
+ run_srom_read(sc, RT2860_EEPROM_FREQ_LEDS, &val);
+ sc->freq = ((val & 0xff) != 0xff) ? val & 0xff : 0;
+ DPRINTF("EEPROM freq offset %d\n", sc->freq & 0xff);
+
+ if ((sc->leds = val >> 8) != 0xff) {
+ /* read LEDs operating mode */
+ run_srom_read(sc, RT2860_EEPROM_LED1, &sc->led[0]);
+ run_srom_read(sc, RT2860_EEPROM_LED2, &sc->led[1]);
+ run_srom_read(sc, RT2860_EEPROM_LED3, &sc->led[2]);
+ } else {
+ /* broken EEPROM, use default settings */
+ sc->leds = 0x01;
+ sc->led[0] = 0x5555;
+ sc->led[1] = 0x2221;
+ sc->led[2] = 0x5627; /* differs from RT2860 */
+ }
+ DPRINTF("EEPROM LED mode=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
+ sc->leds, sc->led[0], sc->led[1], sc->led[2]);
+
+ /* read RF information */
+ run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
+ if (val == 0xffff) {
+ DPRINTF("invalid EEPROM antenna info, using default\n");
+ if ((sc->mac_rev >> 16) >= 0x3070) {
+ /* default to RF3020 1T1R */
+ sc->rf_rev = RT3070_RF_3020;
+ sc->ntxchains = 1;
+ sc->nrxchains = 1;
+ } else {
+ /* default to RF2820 1T2R */
+ sc->rf_rev = RT2860_RF_2820;
+ sc->ntxchains = 1;
+ sc->nrxchains = 2;
+ }
+ } else {
+ sc->rf_rev = (val >> 8) & 0xf;
+ sc->ntxchains = (val >> 4) & 0xf;
+ sc->nrxchains = val & 0xf;
+ }
+ DPRINTF("EEPROM RF rev=0x%02x chains=%dT%dR\n",
+ sc->rf_rev, sc->ntxchains, sc->nrxchains);
+
+ /* check if RF supports automatic Tx access gain control */
+ run_srom_read(sc, RT2860_EEPROM_CONFIG, &val);
+ DPRINTF("EEPROM CFG 0x%04x\n", val);
+ if ((val & 0xff) != 0xff) {
+ sc->ext_5ghz_lna = (val >> 3) & 1;
+ sc->ext_2ghz_lna = (val >> 2) & 1;
+ sc->calib_2ghz = sc->calib_5ghz = (val >> 1) & 1;
+ }
+
+ /* read power settings for 2GHz channels */
+ for (i = 0; i < 14; i += 2) {
+ run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE1 + i / 2, &val);
+ sc->txpow1[i + 0] = (int8_t)(val & 0xff);
+ sc->txpow1[i + 1] = (int8_t)(val >> 8);
+
+ run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
+ sc->txpow2[i + 0] = (int8_t)(val & 0xff);
+ sc->txpow2[i + 1] = (int8_t)(val >> 8);
+ }
+ /* fix broken Tx power entries */
+ for (i = 0; i < 14; i++) {
+ if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
+ sc->txpow1[i] = 5;
+ if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
+ sc->txpow2[i] = 5;
+ DPRINTF("chan %d: power1=%d, power2=%d\n",
+ rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
+ }
+ /* read power settings for 5GHz channels */
+ for (i = 0; i < 36; i += 2) {
+ run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE1 + i / 2, &val);
+ sc->txpow1[i + 14] = (int8_t)(val & 0xff);
+ sc->txpow1[i + 15] = (int8_t)(val >> 8);
+
+ run_srom_read(sc, RT2860_EEPROM_PWR5GHZ_BASE2 + i / 2, &val);
+ sc->txpow2[i + 14] = (int8_t)(val & 0xff);
+ sc->txpow2[i + 15] = (int8_t)(val >> 8);
+ }
+ /* fix broken Tx power entries */
+ for (i = 0; i < 36; i++) {
+ if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
+ sc->txpow1[14 + i] = 5;
+ if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
+ sc->txpow2[14 + i] = 5;
+ DPRINTF("chan %d: power1=%d, power2=%d\n",
+ rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
+ sc->txpow2[14 + i]);
+ }
+
+ /* read Tx power compensation for each Tx rate */
+ run_srom_read(sc, RT2860_EEPROM_DELTAPWR, &val);
+ delta_2ghz = delta_5ghz = 0;
+ if ((val & 0xff) != 0xff && (val & 0x80)) {
+ delta_2ghz = val & 0xf;
+ if (!(val & 0x40)) /* negative number */
+ delta_2ghz = -delta_2ghz;
+ }
+ val >>= 8;
+ if ((val & 0xff) != 0xff && (val & 0x80)) {
+ delta_5ghz = val & 0xf;
+ if (!(val & 0x40)) /* negative number */
+ delta_5ghz = -delta_5ghz;
+ }
+ DPRINTF("power compensation=%d (2GHz), %d (5GHz)\n",
+ delta_2ghz, delta_5ghz);
+
+ for (ridx = 0; ridx < 5; ridx++) {
+ uint32_t reg;
+
+ run_srom_read(sc, RT2860_EEPROM_RPWR + ridx, &val);
+ reg = (uint32_t)val << 16;
+ run_srom_read(sc, RT2860_EEPROM_RPWR + ridx + 1, &val);
+ reg |= val;
+
+ sc->txpow20mhz[ridx] = reg;
+ sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz);
+ sc->txpow40mhz_5ghz[ridx] = b4inc(reg, delta_5ghz);
+
+ DPRINTF("ridx %d: power 20MHz=0x%08x, 40MHz/2GHz=0x%08x, "
+ "40MHz/5GHz=0x%08x\n", ridx, sc->txpow20mhz[ridx],
+ sc->txpow40mhz_2ghz[ridx], sc->txpow40mhz_5ghz[ridx]);
+ }
+
+ /* read RSSI offsets and LNA gains from EEPROM */
+ run_srom_read(sc, RT2860_EEPROM_RSSI1_2GHZ, &val);
+ sc->rssi_2ghz[0] = val & 0xff; /* Ant A */
+ sc->rssi_2ghz[1] = val >> 8; /* Ant B */
+ run_srom_read(sc, RT2860_EEPROM_RSSI2_2GHZ, &val);
+ sc->rssi_2ghz[2] = val & 0xff; /* Ant C */
+ sc->lna[2] = val >> 8; /* channel group 2 */
+
+ run_srom_read(sc, RT2860_EEPROM_RSSI1_5GHZ, &val);
+ sc->rssi_5ghz[0] = val & 0xff; /* Ant A */
+ sc->rssi_5ghz[1] = val >> 8; /* Ant B */
+ run_srom_read(sc, RT2860_EEPROM_RSSI2_5GHZ, &val);
+ sc->rssi_5ghz[2] = val & 0xff; /* Ant C */
+ sc->lna[3] = val >> 8; /* channel group 3 */
+
+ run_srom_read(sc, RT2860_EEPROM_LNA, &val);
+ sc->lna[0] = val & 0xff; /* channel group 0 */
+ sc->lna[1] = val >> 8; /* channel group 1 */
+
+ /* fix broken 5GHz LNA entries */
+ if (sc->lna[2] == 0 || sc->lna[2] == 0xff) {
+ DPRINTF("invalid LNA for channel group %d\n", 2);
+ sc->lna[2] = sc->lna[1];
+ }
+ if (sc->lna[3] == 0 || sc->lna[3] == 0xff) {
+ DPRINTF("invalid LNA for channel group %d\n", 3);
+ sc->lna[3] = sc->lna[1];
+ }
+
+ /* fix broken RSSI offset entries */
+ for (ant = 0; ant < 3; ant++) {
+ if (sc->rssi_2ghz[ant] < -10 || sc->rssi_2ghz[ant] > 10) {
+ DPRINTF("invalid RSSI%d offset: %d (2GHz)\n",
+ ant + 1, sc->rssi_2ghz[ant]);
+ sc->rssi_2ghz[ant] = 0;
+ }
+ if (sc->rssi_5ghz[ant] < -10 || sc->rssi_5ghz[ant] > 10) {
+ DPRINTF("invalid RSSI%d offset: %d (5GHz)\n",
+ ant + 1, sc->rssi_5ghz[ant]);
+ sc->rssi_5ghz[ant] = 0;
+ }
+ }
+ return 0;
+}
+
+struct ieee80211_node *
+run_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO);
+}
+
+static int
+run_media_change(struct ifnet *ifp)
+{
+ const struct ieee80211_txparam *tp;
+ struct run_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211vap *vap = &sc->sc_rvp->vap;
+ uint8_t rate, ridx;
+ int error;
+
+ RUN_LOCK(sc);
+
+ error = ieee80211_media_change(ifp);
+ if (error != ENETRESET)
+ RUN_UNLOCK(sc);
+ return error;
+
+ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
+ if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
+ rate = ic->ic_sup_rates[ic->ic_curmode].
+ rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
+ for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
+ if (rt2860_rates[ridx].rate == rate)
+ break;
+ sc->fixed_ridx = ridx;
+ }
+
+ if ((ifp->if_flags & IFF_UP) &&
+ (ifp->if_drv_flags & IFF_DRV_RUNNING)){
+ run_init_locked(sc);
+ }
+
+ RUN_UNLOCK(sc);
+
+ return 0;
+}
+
+static int
+run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+ const struct ieee80211_txparam *tp;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+ struct run_vap *rvp = RUN_VAP(vap);
+ enum ieee80211_state ostate;
+ struct ieee80211_node *ni;
+ uint32_t tmp;
+ uint8_t wcid;
+
+ ostate = vap->iv_state;
+ DPRINTF("%s -> %s\n",
+ ieee80211_state_name[ostate],
+ ieee80211_state_name[nstate]);
+
+ IEEE80211_UNLOCK(ic);
+ RUN_LOCK(sc);
+
+ sc->sc_rvp->amrr_run = RUN_AMRR_OFF;
+ usb_callout_stop(&rvp->amrr_ch);
+
+ if (ostate == IEEE80211_S_RUN) {
+ /* turn link LED off */
+ run_set_leds(sc, RT2860_LED_RADIO);
+ }
+
+ switch (nstate) {
+ case IEEE80211_S_INIT:
+ if (ostate == IEEE80211_S_RUN) {
+ /* abort TSF synchronization */
+ run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
+ run_write(sc, RT2860_BCN_TIME_CFG,
+ tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
+ RT2860_TBTT_TIMER_EN));
+ }
+ break;
+
+ case IEEE80211_S_RUN:
+ ni = vap->iv_bss;
+
+ if (vap->iv_opmode != IEEE80211_M_MONITOR) {
+ run_updateslot(ic->ic_ifp);
+ run_enable_mrr(sc);
+ run_set_txpreamble(sc);
+ run_set_basicrates(sc);
+ IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid);
+ run_set_bssid(sc, ni->ni_bssid);
+ }
+
+ if (vap->iv_opmode == IEEE80211_M_STA) {
+ /* add BSS entry to the WCID table */
+ wcid = RUN_AID2WCID(ni->ni_associd);
+ run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
+ ni->ni_macaddr, IEEE80211_ADDR_LEN);
+ }
+
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
+ vap->iv_opmode == IEEE80211_M_IBSS)
+ run_update_beacon_locked(vap, 0);
+
+ if (vap->iv_opmode != IEEE80211_M_MONITOR) {
+ run_enable_tsf_sync(sc);
+ } /* else tsf */
+
+ /* enable automatic rate adaptation */
+ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
+ if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
+ run_amrr_start(sc, ni);
+
+ /* turn link LED on */
+ run_set_leds(sc, RT2860_LED_RADIO |
+ (IEEE80211_IS_CHAN_2GHZ(vap->iv_bss->ni_chan) ?
+ RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ));
+
+ break;
+ default:
+ DPRINTFN(6, "undefined case\n");
+ break;
+ }
+
+ RUN_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+
+ return(rvp->newstate(vap, nstate, arg));
+}
+
+/* another taskqueue, so usbd_do_request() can go sleep */
+static int
+run_wme_update(struct ieee80211com *ic)
+{
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+
+ ieee80211_runtask(ic, &sc->wme_task);
+
+ /* return whatever, upper layer desn't care anyway */
+ return 0;
+}
+
+/* ARGSUSED */
+static void
+run_wme_update_cb(void *arg, int pending)
+{
+ struct ieee80211com *ic = arg;
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+ struct ieee80211_wme_state *wmesp = &ic->ic_wme;
+ int aci, error = 0;
+
+ RUN_LOCK(sc);
+
+ /* update MAC TX configuration registers */
+ for (aci = 0; aci < WME_NUM_AC; aci++) {
+ error = run_write(sc, RT2860_EDCA_AC_CFG(aci),
+ wmesp->wme_params[aci].wmep_logcwmax << 16 |
+ wmesp->wme_params[aci].wmep_logcwmin << 12 |
+ wmesp->wme_params[aci].wmep_aifsn << 8 |
+ wmesp->wme_params[aci].wmep_txopLimit);
+ if(error) goto err;
+ }
+
+ /* update SCH/DMA registers too */
+ error = run_write(sc, RT2860_WMM_AIFSN_CFG,
+ wmesp->wme_params[WME_AC_VO].wmep_aifsn << 12 |
+ wmesp->wme_params[WME_AC_VI].wmep_aifsn << 8 |
+ wmesp->wme_params[WME_AC_BK].wmep_aifsn << 4 |
+ wmesp->wme_params[WME_AC_BE].wmep_aifsn);
+ if(error) goto err;
+ error = run_write(sc, RT2860_WMM_CWMIN_CFG,
+ wmesp->wme_params[WME_AC_VO].wmep_logcwmin << 12 |
+ wmesp->wme_params[WME_AC_VI].wmep_logcwmin << 8 |
+ wmesp->wme_params[WME_AC_BK].wmep_logcwmin << 4 |
+ wmesp->wme_params[WME_AC_BE].wmep_logcwmin);
+ if(error) goto err;
+ error = run_write(sc, RT2860_WMM_CWMAX_CFG,
+ wmesp->wme_params[WME_AC_VO].wmep_logcwmax << 12 |
+ wmesp->wme_params[WME_AC_VI].wmep_logcwmax << 8 |
+ wmesp->wme_params[WME_AC_BK].wmep_logcwmax << 4 |
+ wmesp->wme_params[WME_AC_BE].wmep_logcwmax);
+ if(error) goto err;
+ error = run_write(sc, RT2860_WMM_TXOP0_CFG,
+ wmesp->wme_params[WME_AC_BK].wmep_txopLimit << 16 |
+ wmesp->wme_params[WME_AC_BE].wmep_txopLimit);
+ if(error) goto err;
+ error = run_write(sc, RT2860_WMM_TXOP1_CFG,
+ wmesp->wme_params[WME_AC_VO].wmep_txopLimit << 16 |
+ wmesp->wme_params[WME_AC_VI].wmep_txopLimit);
+
+err:
+ if(error)
+ DPRINTF("WME update failed\n");
+
+ RUN_UNLOCK(sc);
+ return;
+}
+
+static void
+run_key_update_begin(struct ieee80211vap *vap)
+{
+ /*
+ * Because run_key_delete() needs special attention
+ * on lock related operation, lock handling is being done
+ * differently in run_key_set and _delete.
+ *
+ * So, we don't use key_update_begin and _end.
+ */
+}
+
+static void
+run_key_update_end(struct ieee80211vap *vap)
+{
+ /* null */
+}
+
+/*
+ * return 0 on error
+ */
+static int
+run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
+ const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct run_softc *sc = ifp->if_softc;
+ struct ieee80211_node *ni;
+ uint32_t attr;
+ uint16_t base, associd;
+ uint8_t mode, wcid, txmic, rxmic, iv[8];
+ int error = 0;
+
+ RUN_LOCK(sc);
+
+ if(vap->iv_opmode == IEEE80211_M_HOSTAP){
+ ni = ieee80211_find_vap_node(&ic->ic_sta, vap, mac);
+ associd = (ni != NULL) ? ni->ni_associd : 0;
+ if(ni != NULL)
+ ieee80211_free_node(ni);
+ txmic = 24;
+ rxmic = 16;
+ } else {
+ ni = vap->iv_bss;
+ associd = (ni != NULL) ? ni->ni_associd : 0;
+ txmic = 16;
+ rxmic = 24;
+ }
+
+ /* map net80211 cipher to RT2860 security mode */
+ switch (k->wk_cipher->ic_cipher) {
+ case IEEE80211_CIPHER_WEP:
+ if(k->wk_keylen < 8)
+ mode = RT2860_MODE_WEP40;
+ else
+ mode = RT2860_MODE_WEP104;
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ mode = RT2860_MODE_TKIP;
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ mode = RT2860_MODE_AES_CCMP;
+ break;
+ default:
+ DPRINTF("undefined case\n");
+ goto fail;
+ }
+
+ DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s\n",
+ associd, k->wk_keyix, mode,
+ (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise");
+
+ if (k->wk_flags & IEEE80211_KEY_GROUP) {
+ wcid = 0; /* NB: update WCID0 for group keys */
+ base = RT2860_SKEY(0, k->wk_keyix);
+ } else {
+ wcid = RUN_AID2WCID(associd);
+ base = RT2860_PKEY(wcid);
+ }
+
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
+ if(run_write_region_1(sc, base, k->wk_key, 16))
+ goto fail;
+ if(run_write_region_1(sc, base + 16, &k->wk_key[txmic], 8)) /* wk_txmic */
+ goto fail;
+ if(run_write_region_1(sc, base + 24, &k->wk_key[rxmic], 8)) /* wk_rxmic */
+ goto fail;
+ } else {
+ /* roundup len to 16-bit: XXX fix write_region_1() instead */
+ if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1))
+ goto fail;
+ }
+
+ if (!(k->wk_flags & IEEE80211_KEY_GROUP) ||
+ (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) {
+ /* set initial packet number in IV+EIV */
+ if (k->wk_cipher == IEEE80211_CIPHER_WEP){
+ memset(iv, 0, sizeof iv);
+ iv[3] = sc->sc_rvp->vap.iv_def_txkey << 6;
+ } else {
+ if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) {
+ iv[0] = k->wk_keytsc >> 8;
+ iv[1] = (iv[0] | 0x20) & 0x7f;
+ iv[2] = k->wk_keytsc;
+ } else /* CCMP */ {
+ iv[0] = k->wk_keytsc;
+ iv[1] = k->wk_keytsc >> 8;
+ iv[2] = 0;
+ }
+ iv[3] = k->wk_keyix << 6 | IEEE80211_WEP_EXTIV;
+ iv[4] = k->wk_keytsc >> 16;
+ iv[5] = k->wk_keytsc >> 24;
+ iv[6] = k->wk_keytsc >> 32;
+ iv[7] = k->wk_keytsc >> 40;
+ }
+ if(run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8))
+ goto fail;
+ }
+
+ if (k->wk_flags & IEEE80211_KEY_GROUP) {
+ /* install group key */
+ if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
+ goto fail;
+ attr &= ~(0xf << (k->wk_keyix * 4));
+ attr |= mode << (k->wk_keyix * 4);
+ if(run_write(sc, RT2860_SKEY_MODE_0_7, attr))
+ goto fail;
+ } else {
+ /* install pairwise key */
+ if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
+ goto fail;
+ attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN;
+ if(run_write(sc, RT2860_WCID_ATTR(wcid), attr))
+ goto fail;
+ }
+
+ /* TODO create a pass-thru key entry? */
+
+fail:
+ RUN_UNLOCK(sc);
+ return (error? 0 : 1);
+}
+
+/*
+ * return 0 on error
+ */
+static int
+run_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+ struct ieee80211_node *ni = vap->iv_bss;
+ struct ieee80211_node_table *nt = &ic->ic_sta;
+ uint32_t attr;
+ uint8_t wcid;
+ int error = 0;
+ uint8_t nislocked, cislocked;
+
+ if((nislocked = IEEE80211_NODE_IS_LOCKED(nt)))
+ IEEE80211_NODE_UNLOCK(nt);
+ if((cislocked = mtx_owned(&ic->ic_comlock.mtx)))
+ IEEE80211_UNLOCK(ic);
+ RUN_LOCK(sc);
+
+ if (k->wk_flags & IEEE80211_KEY_GROUP) {
+ /* remove group key */
+ if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr))
+ goto fail;
+ attr &= ~(0xf << (k->wk_keyix * 4));
+ if(run_write(sc, RT2860_SKEY_MODE_0_7, attr))
+ goto fail;
+ } else {
+ /* remove pairwise key */
+ wcid = RUN_AID2WCID((ni != NULL) ? ni->ni_associd : 0);
+ if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr))
+ goto fail;
+ attr &= ~0xf;
+ if(run_write(sc, RT2860_WCID_ATTR(wcid), attr))
+ goto fail;
+ }
+
+fail:
+ RUN_UNLOCK(sc);
+ if(cislocked)
+ IEEE80211_LOCK(ic);
+ if(nislocked)
+ IEEE80211_NODE_LOCK(nt);
+
+ return (error? 0 : 1);
+}
+
+static void
+run_amrr_start(struct run_softc *sc, struct ieee80211_node *ni)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct run_vap *rvp = RUN_VAP(vap);
+ uint32_t sta[3];
+ uint8_t wcid;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ /* read statistic counters (clear on read) and update AMRR state */
+ run_read_region_1(sc, RT2860_TX_STA_CNT0,
+ (uint8_t *)sta, sizeof sta);
+
+ wcid = RUN_AID2WCID(ni == NULL ? 0 : ni->ni_associd);
+ ieee80211_amrr_node_init(&rvp->amrr, &rvp->amn[wcid], ni);
+
+ /* start at lowest available bit-rate, AMRR will raise */
+ ni->ni_txrate = 2;
+
+ /* start calibration timer */
+ rvp->amrr_run = RUN_AMRR_ON;
+ usb_callout_reset(&rvp->amrr_ch, hz, run_amrr_to, rvp);
+}
+
+static void
+run_amrr_to(void *arg)
+{
+ struct run_vap *rvp = arg;
+
+ /* do it in a process context, so it can go sleep */
+ ieee80211_runtask(rvp->vap.iv_ic, &rvp->amrr_task);
+ /* next timeout will be rescheduled in the callback task */
+}
+
+/* ARGSUSED */
+static void
+run_amrr_cb(void *arg, int pending)
+{
+ struct run_vap *rvp = arg;
+ struct ieee80211vap *vap = &rvp->vap;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ run_iter_func(rvp, vap->iv_bss);
+ else {
+ /*
+ * run_reset_livelock() doesn't do anything with AMRR,
+ * but Ralink wants us to call it every 1 sec. So, we
+ * piggyback here rather than creating another callout.
+ * Livelock may occur only in HOSTAP or IBSS mode
+ * (when h/w is sending beacons).
+ */
+ RUN_LOCK(sc);
+ run_reset_livelock(sc);
+ RUN_UNLOCK(sc);
+ ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, rvp);
+ }
+
+ if(rvp->amrr_run == RUN_AMRR_ON)
+ usb_callout_reset(&rvp->amrr_ch, hz, run_amrr_to, rvp);
+}
+
+
+static void
+run_iter_func(void *arg, struct ieee80211_node *ni)
+{
+ struct run_vap *rvp = arg;
+ struct ieee80211com *ic = rvp->vap.iv_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct run_softc *sc = ifp->if_softc;
+ struct ieee80211_node_table *nt = &ic->ic_sta;
+ struct ieee80211_amrr_node *amn = &rvp->amn[0]; /* make compiler happy */
+ uint32_t sta[3], stat;
+ int error;
+ uint8_t wcid, mcs, pid;
+
+ if(ic->ic_opmode != IEEE80211_M_STA)
+ IEEE80211_NODE_ITERATE_UNLOCK(nt);
+
+ RUN_LOCK(sc);
+
+ if(ic->ic_opmode != IEEE80211_M_STA){
+ /* drain Tx status FIFO (maxsize = 16) */
+ run_read(sc, RT2860_TX_STAT_FIFO, &stat);
+ while (stat & RT2860_TXQ_VLD) {
+ DPRINTFN(4, "tx stat 0x%08x\n", stat);
+
+ wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
+
+ /* if no ACK was requested, no feedback is available */
+ if (!(stat & RT2860_TXQ_ACKREQ) || wcid == 0xff)
+ continue;
+
+ /* update per-STA AMRR stats */
+ amn = &rvp->amn[wcid];
+ amn->amn_txcnt++;
+ if (stat & RT2860_TXQ_OK) {
+ amn->amn_success++;
+ /*
+ * Check if there were retries, ie if the Tx
+ * success rate is different from the requested
+ * rate. Note that it works only because we do
+ * not allow rate fallback from OFDM to CCK.
+ */
+ mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
+ pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
+ if (mcs + 1 != pid)
+ amn->amn_retrycnt++;
+ } else {
+ amn->amn_retrycnt++;
+ ifp->if_oerrors++;
+ }
+ run_read_region_1(sc, RT2860_TX_STAT_FIFO,
+ (uint8_t *)&stat, sizeof stat);
+ }
+ DPRINTFN(3, "retrycnt=%d txcnt=%d success=%d\n",
+ amn->amn_retrycnt, amn->amn_txcnt, amn->amn_success);
+ } else {
+ /* read statistic counters (clear on read) and update AMRR state */
+ error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
+ sizeof sta);
+ if (error != 0)
+ goto skip;
+
+ DPRINTFN(3, "retrycnt=%d txcnt=%d failcnt=%d\n",
+ le32toh(sta[1]) >> 16, le32toh(sta[1]) & 0xffff,
+ le32toh(sta[0]) & 0xffff);
+
+ wcid = RUN_AID2WCID(ni == NULL ? 0 : ni->ni_associd);
+ amn = &rvp->amn[wcid];
+
+ /* count failed TX as errors */
+ ifp->if_oerrors += le32toh(sta[0]) & 0xffff;
+
+ amn->amn_retrycnt =
+ (le32toh(sta[0]) & 0xffff) + /* failed TX count */
+ (le32toh(sta[1]) >> 16); /* TX retransmission count */
+
+ amn->amn_txcnt =
+ amn->amn_retrycnt +
+ (le32toh(sta[1]) & 0xffff); /* successful TX count */
+
+ amn->amn_success =
+ (le32toh(sta[1]) >> 16) +
+ (le32toh(sta[1]) & 0xffff);
+ }
+
+ ieee80211_amrr_choose(ni, amn);
+
+skip:;
+ RUN_UNLOCK(sc);
+
+ if(ic->ic_opmode != IEEE80211_M_STA)
+ IEEE80211_NODE_ITERATE_LOCK(nt);
+}
+
+static void
+run_newassoc(struct ieee80211_node *ni, int isnew)
+{
+ struct run_node *rn = (void *)ni;
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ uint8_t rate;
+ int ridx, i, j;
+
+ DPRINTF("new assoc isnew=%d addr=%s\n",
+ isnew, ether_sprintf(ni->ni_macaddr));
+
+ for (i = 0; i < rs->rs_nrates; i++) {
+ rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
+ /* convert 802.11 rate to hardware rate index */
+ for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
+ if (rt2860_rates[ridx].rate == rate)
+ break;
+ rn->ridx[i] = ridx;
+ /* determine rate of control response frames */
+ for (j = i; j >= 0; j--) {
+ if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
+ rt2860_rates[rn->ridx[i]].phy ==
+ rt2860_rates[rn->ridx[j]].phy)
+ break;
+ }
+ if (j >= 0) {
+ rn->ctl_ridx[i] = rn->ridx[j];
+ } else {
+ /* no basic rate found, use mandatory one */
+ rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
+ }
+ DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n",
+ rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
+ }
+}
+
+/*
+ * Return the Rx chain with the highest RSSI for a given frame.
+ */
+static __inline uint8_t
+run_maxrssi_chain(struct run_softc *sc, const struct rt2860_rxwi *rxwi)
+{
+ uint8_t rxchain = 0;
+
+ if (sc->nrxchains > 1) {
+ if (rxwi->rssi[1] > rxwi->rssi[rxchain])
+ rxchain = 1;
+ if (sc->nrxchains > 2)
+ if (rxwi->rssi[2] > rxwi->rssi[rxchain])
+ rxchain = 2;
+ }
+ return rxchain;
+}
+
+static void
+run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211vap *vap = &sc->sc_rvp->vap;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
+ struct rt2870_rxd *rxd;
+ struct rt2860_rxwi *rxwi;
+ uint32_t flags;
+ uint16_t len, phy;
+ uint8_t ant, rssi;
+ int8_t nf;
+
+ rxwi = mtod(m, struct rt2860_rxwi *);
+ len = le16toh(rxwi->len) & 0xfff;
+ if (__predict_false(len > dmalen)) {
+ m_freem(m);
+ ifp->if_ierrors++;
+ DPRINTF("bad RXWI length %u > %u\n", len, dmalen);
+ return;
+ }
+ /* Rx descriptor is located at the end */
+ rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
+ flags = le32toh(rxd->flags);
+
+ if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
+ m_freem(m);
+ ifp->if_ierrors++;
+ DPRINTF("%s error.\n", (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
+ return;
+ }
+
+ m->m_data += sizeof(struct rt2860_rxwi);
+ m->m_pkthdr.len = m->m_len -= sizeof(struct rt2860_rxwi);
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP){
+ wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+ m->m_flags |= M_WEP;
+ }
+
+ if (flags & RT2860_RX_L2PAD){
+ DPRINTFN(8, "received RT2860_RX_L2PAD frame\n");
+ len += 2;
+ }
+
+ if (__predict_false(flags & RT2860_RX_MICERR)) {
+ /* report MIC failures to net80211 for TKIP */
+ ieee80211_notify_michael_failure(vap, wh, rxwi->keyidx);
+ m_freem(m);
+ ifp->if_ierrors++;
+ DPRINTF("MIC error. Someone is lying.\n");
+ return;
+ }
+
+ ant = run_maxrssi_chain(sc, rxwi);
+ rssi = rxwi->rssi[ant];
+ nf = run_rssi2dbm(sc, rssi, ant);
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+
+ ni = ieee80211_find_rxnode(ic,
+ mtod(m, struct ieee80211_frame_min *));
+ if (ni != NULL) {
+ (void)ieee80211_input(ni, m, rssi, nf);
+ ieee80211_free_node(ni);
+ } else {
+ (void)ieee80211_input_all(ic, m, rssi, nf);
+ }
+
+ if(__predict_false(ieee80211_radiotap_active(ic))){
+ struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
+
+ tap->wr_flags = 0;
+ tap->wr_chan_freq = htole16(ic->ic_bsschan->ic_freq);
+ tap->wr_chan_flags = htole16(ic->ic_bsschan->ic_flags);
+ tap->wr_antsignal = rssi;
+ tap->wr_antenna = ant;
+ tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant);
+ tap->wr_rate = 2; /* in case it can't be found below */
+ phy = le16toh(rxwi->phy);
+ switch (phy & RT2860_PHY_MODE) {
+ case RT2860_PHY_CCK:
+ switch ((phy & RT2860_PHY_MCS) & ~RT2860_PHY_SHPRE) {
+ case 0: tap->wr_rate = 2; break;
+ case 1: tap->wr_rate = 4; break;
+ case 2: tap->wr_rate = 11; break;
+ case 3: tap->wr_rate = 22; break;
+ }
+ if (phy & RT2860_PHY_SHPRE)
+ tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+ break;
+ case RT2860_PHY_OFDM:
+ switch (phy & RT2860_PHY_MCS) {
+ case 0: tap->wr_rate = 12; break;
+ case 1: tap->wr_rate = 18; break;
+ case 2: tap->wr_rate = 24; break;
+ case 3: tap->wr_rate = 36; break;
+ case 4: tap->wr_rate = 48; break;
+ case 5: tap->wr_rate = 72; break;
+ case 6: tap->wr_rate = 96; break;
+ case 7: tap->wr_rate = 108; break;
+ }
+ break;
+ }
+ }
+}
+
+static void
+run_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct run_softc *sc = usbd_xfer_softc(xfer);
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m = NULL;
+ struct mbuf *m0;
+ uint32_t dmalen;
+ int xferlen;
+
+ usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+
+ DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
+
+ if (xferlen < sizeof (uint32_t) +
+ sizeof (struct rt2860_rxwi) + sizeof (struct rt2870_rxd)) {
+ DPRINTF("xfer too short %d\n", xferlen);
+ goto tr_setup;
+ }
+
+ m = sc->rx_m;
+ sc->rx_m = NULL;
+
+ /* FALLTHROUGH */
+ case USB_ST_SETUP:
+tr_setup:
+ if (sc->rx_m == NULL) {
+ sc->rx_m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
+ MJUMPAGESIZE /* xfer can be bigger than MCLBYTES */);
+ }
+ if (sc->rx_m == NULL) {
+ DPRINTF("could not allocate mbuf - idle with stall\n");
+ ifp->if_ierrors++;
+ usbd_xfer_set_stall(xfer);
+ usbd_xfer_set_frames(xfer, 0);
+ } else {
+ /*
+ * Directly loading a mbuf cluster into DMA to
+ * save some data copying. This works because
+ * there is only one cluster.
+ */
+ usbd_xfer_set_frame_data(xfer, 0,
+ mtod(sc->rx_m, caddr_t), RUN_MAX_RXSZ);
+ usbd_xfer_set_frames(xfer, 1);
+ }
+ usbd_transfer_submit(xfer);
+ break;
+
+ default: /* Error */
+ if (error != USB_ERR_CANCELLED) {
+ /* try to clear stall first */
+ usbd_xfer_set_stall(xfer);
+
+ if (error == USB_ERR_TIMEOUT)
+ device_printf(sc->sc_dev, "device timeout\n");
+
+ ifp->if_ierrors++;
+
+ goto tr_setup;
+ }
+ if(sc->rx_m != NULL){
+ m_freem(sc->rx_m);
+ sc->rx_m = NULL;
+ }
+ break;
+ }
+
+ if (m == NULL)
+ return;
+
+ /* inputting all the frames must be last */
+
+ RUN_UNLOCK(sc);
+
+ m->m_pkthdr.len = m->m_len = xferlen;
+
+ /* HW can aggregate multiple 802.11 frames in a single USB xfer */
+ for(;;) {
+ dmalen = le32toh(*mtod(m, uint32_t *)) & 0xffff;
+
+ if ((dmalen == 0) || ((dmalen & 3) != 0)) {
+ DPRINTF("bad DMA length %u\n", dmalen);
+ break;
+ }
+ if ((dmalen + 8) > xferlen) {
+ DPRINTF("bad DMA length %u > %d\n",
+ dmalen + 8, xferlen);
+ break;
+ }
+
+ /* If it is the last one or a single frame, we won't copy. */
+ if((xferlen -= dmalen + 8) <= 8){
+ /* trim 32-bit DMA-len header */
+ m->m_data += 4;
+ m->m_pkthdr.len = m->m_len -= 4;
+ run_rx_frame(sc, m, dmalen);
+ break;
+ }
+
+ /* copy aggregated frames to another mbuf */
+ m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (__predict_false(m0 == NULL)) {
+ DPRINTF("could not allocate mbuf\n");
+ ifp->if_ierrors++;
+ break;
+ }
+ m_copydata(m, 4 /* skip 32-bit DMA-len header */,
+ dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
+ m0->m_pkthdr.len = m0->m_len =
+ dmalen + sizeof(struct rt2870_rxd);
+ run_rx_frame(sc, m0, dmalen);
+
+ /* update data ptr */
+ m->m_data += dmalen + 8;
+ m->m_pkthdr.len = m->m_len -= dmalen + 8;
+ }
+
+ RUN_LOCK(sc);
+}
+
+static void
+run_tx_free(struct run_endpoint_queue *pq,
+ struct run_tx_data *data, int txerr)
+{
+ if (data->m != NULL) {
+ if (data->m->m_flags & M_TXCB)
+ ieee80211_process_callback(data->ni, data->m,
+ txerr ? ETIMEDOUT : 0);
+ m_freem(data->m);
+ data->m = NULL;
+
+ if(data->ni == NULL) {
+ DPRINTF("no node\n");
+ } else {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ }
+ }
+
+ STAILQ_INSERT_TAIL(&pq->tx_fh, data, next);
+ pq->tx_nfree++;
+}
+
+static void
+run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int index)
+{
+ struct run_softc *sc = usbd_xfer_softc(xfer);
+ struct ifnet *ifp = sc->sc_ifp;
+ struct run_tx_data *data;
+ struct ieee80211vap *vap = NULL;
+ struct usb_page_cache *pc;
+ struct run_endpoint_queue *pq = &sc->sc_epq[index];
+ struct mbuf *m;
+ usb_frlength_t size;
+ unsigned int len;
+ int actlen;
+ int sumlen;
+
+ usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)){
+ case USB_ST_TRANSFERRED:
+ DPRINTFN(11, "transfer complete: %d "
+ "bytes @ index %d\n", actlen, index);
+
+ data = usbd_xfer_get_priv(xfer);
+
+ run_tx_free(pq, data, 0);
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ usbd_xfer_set_priv(xfer, NULL);
+
+ ifp->if_opackets++;
+
+ /* FALLTHROUGH */
+ case USB_ST_SETUP:
+tr_setup:
+ data = STAILQ_FIRST(&pq->tx_qh);
+ if(data == NULL)
+ break;
+
+ STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
+
+ m = data->m;
+ if (m->m_pkthdr.len > RUN_MAX_TXSZ) {
+ DPRINTF("data overflow, %u bytes\n",
+ m->m_pkthdr.len);
+
+ ifp->if_oerrors++;
+
+ run_tx_free(pq, data, 1);
+
+ goto tr_setup;
+ }
+
+ pc = usbd_xfer_get_frame(xfer, 0);
+ size = sizeof(data->desc);
+ usbd_copy_in(pc, 0, &data->desc, size);
+ usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
+
+ vap = data->ni->ni_vap;
+ if (ieee80211_radiotap_active_vap(vap)) {
+ struct run_tx_radiotap_header *tap = &sc->sc_txtap;
+
+ tap->wt_flags = 0;
+ tap->wt_rate = rt2860_rates[data->ridx].rate;
+ tap->wt_chan_freq = htole16(vap->iv_bss->ni_chan->ic_freq);
+ tap->wt_chan_flags = htole16(vap->iv_bss->ni_chan->ic_flags);
+ tap->wt_hwqueue = index;
+ if (data->mcs & RT2860_PHY_SHPRE)
+ tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ ieee80211_radiotap_tx(vap, m);
+ }
+
+ /* align end on a 4-bytes boundary */
+ len = (size + m->m_pkthdr.len + 3) & ~3;
+
+ DPRINTFN(11, "sending frame len=%u xferlen=%u @ index %d\n",
+ m->m_pkthdr.len, len, index);
+
+ usbd_xfer_set_frame_len(xfer, 0, len);
+ usbd_xfer_set_priv(xfer, data);
+
+ usbd_transfer_submit(xfer);
+
+ RUN_UNLOCK(sc);
+ run_start(ifp);
+ RUN_LOCK(sc);
+
+ break;
+
+ default:
+ DPRINTF("USB transfer error, %s\n",
+ usbd_errstr(error));
+
+ data = usbd_xfer_get_priv(xfer);
+
+ ifp->if_oerrors++;
+
+ if (data != NULL) {
+ run_tx_free(pq, data, error);
+ usbd_xfer_set_priv(xfer, NULL);
+ }
+
+ if (error != USB_ERR_CANCELLED) {
+ if (error == USB_ERR_TIMEOUT) {
+ device_printf(sc->sc_dev, "device timeout\n");
+ ieee80211_runtask(ifp->if_l2com, &sc->usb_timeout_task);
+ }
+
+ /*
+ * Try to clear stall first, also if other
+ * errors occur, hence clearing stall
+ * introduces a 50 ms delay:
+ */
+ usbd_xfer_set_stall(xfer);
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
+run_bulk_tx_callback0(struct usb_xfer *xfer, usb_error_t error)
+{
+ run_bulk_tx_callbackN(xfer, error, 0);
+}
+
+static void
+run_bulk_tx_callback1(struct usb_xfer *xfer, usb_error_t error)
+{
+ run_bulk_tx_callbackN(xfer, error, 1);
+}
+
+static void
+run_bulk_tx_callback2(struct usb_xfer *xfer, usb_error_t error)
+{
+ run_bulk_tx_callbackN(xfer, error, 2);
+}
+
+static void
+run_bulk_tx_callback3(struct usb_xfer *xfer, usb_error_t error)
+{
+ run_bulk_tx_callbackN(xfer, error, 3);
+}
+
+static void
+run_bulk_tx_callback4(struct usb_xfer *xfer, usb_error_t error)
+{
+ run_bulk_tx_callbackN(xfer, error, 4);
+}
+
+static void
+run_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error)
+{
+ run_bulk_tx_callbackN(xfer, error, 5);
+}
+
+static void
+run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data,
+ uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags,
+ uint8_t type, uint8_t pad)
+{
+ struct mbuf *m = data->m;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211vap *vap = &sc->sc_rvp->vap;
+ struct ieee80211_frame *wh;
+ struct rt2870_txd *txd;
+ struct rt2860_txwi *txwi;
+ int xferlen;
+ uint8_t mcs;
+ uint8_t ridx = data->ridx;
+
+ /* get MCS code from rate index */
+ data->mcs = mcs = rt2860_rates[ridx].mcs;
+
+ xferlen = sizeof(*txwi) + m->m_pkthdr.len;
+
+ /* roundup to 32-bit alignment */
+ xferlen = (xferlen + 3) & ~3;
+
+ txd = (struct rt2870_txd *)&data->desc;
+ txd->flags = dflags;
+ txd->len = htole16(xferlen);
+
+ /* setup TX Wireless Information */
+ txwi = (struct rt2860_txwi *)(txd + 1);
+ txwi->flags = wflags;
+ txwi->xflags = xflags;
+ txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ?
+ RUN_AID2WCID(data->ni->ni_associd) : 0xff;
+ txwi->len = htole16(m->m_pkthdr.len - pad);
+ if (rt2860_rates[ridx].phy == IEEE80211_T_DS) {
+ txwi->phy = htole16(RT2860_PHY_CCK);
+ if (ridx != RT2860_RIDX_CCK1 &&
+ (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+ mcs |= RT2860_PHY_SHPRE;
+ } else
+ txwi->phy = htole16(RT2860_PHY_OFDM);
+ txwi->phy |= htole16(mcs);
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ /* check if RTS/CTS or CTS-to-self protection is required */
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
+ ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+ rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
+ txwi->txop = RT2860_TX_TXOP_HT | opflags;
+ else
+ txwi->txop = RT2860_TX_TXOP_BACKOFF | opflags;
+}
+
+/* This function must be called locked */
+static int
+run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211vap *vap = &sc->sc_rvp->vap;
+ struct ieee80211_frame *wh;
+ const struct ieee80211_txparam *tp;
+ struct run_tx_data *data;
+ uint16_t qos;
+ uint16_t dur;
+ uint8_t type;
+ uint8_t tid;
+ uint8_t qid;
+ uint8_t qflags;
+ uint8_t pad;
+ uint8_t xflags = 0;
+ int hasqos;
+ int ridx;
+ int ctl_ridx;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+ /*
+ * There are 7 bulk endpoints: 1 for RX
+ * and 6 for TX (4 EDCAs + HCCA + Prio).
+ * Update 03-14-2009: some devices like the Planex GW-US300MiniS
+ * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
+ */
+ if ((hasqos = IEEE80211_QOS_HAS_SEQ(wh))) {
+ uint8_t *frm;
+
+ if(IEEE80211_HAS_ADDR4(wh))
+ frm = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
+ else
+ frm =((struct ieee80211_qosframe *)wh)->i_qos;
+
+ qos = le16toh(*(const uint16_t *)frm);
+ tid = qos & IEEE80211_QOS_TID;
+ qid = TID_TO_WME_AC(tid);
+ pad = 2;
+ } else {
+ qos = 0;
+ tid = 0;
+ qid = WME_AC_BE;
+ pad = 0;
+ }
+ qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA;
+
+ DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n",
+ qos, qid, tid, qflags);
+
+ tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
+
+ /* pickup a rate index */
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
+ type != IEEE80211_FC0_TYPE_DATA) {
+ ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
+ RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
+ ctl_ridx = rt2860_rates[ridx].ctl_ridx;
+ } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
+ ridx = sc->fixed_ridx;
+ ctl_ridx = rt2860_rates[ridx].ctl_ridx;
+ } else {
+ for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++){
+ if (rt2860_rates[ridx].rate == ni->ni_txrate)
+ break;
+ }
+ ctl_ridx = rt2860_rates[ridx].ctl_ridx;
+ }
+
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) !=
+ IEEE80211_QOS_ACKPOLICY_NOACK)) {
+ xflags |= RT2860_TX_ACK;
+ if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+ dur = rt2860_rates[ridx].sp_ack_dur;
+ else
+ dur = rt2860_rates[ridx].lp_ack_dur;
+ *(uint16_t *)wh->i_dur = htole16(dur + sc->sifs);
+ }
+
+ /* reserve slots for mgmt packets, just in case */
+ if (sc->sc_epq[qid].tx_nfree < 3) {
+ DPRINTFN(10, "tx ring %d is full\n", qid);
+ return (-1);
+ }
+
+ data = STAILQ_FIRST(&sc->sc_epq[qid].tx_fh);
+ STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next);
+ sc->sc_epq[qid].tx_nfree--;
+
+ data->m = m;
+ data->ni = ni;
+ data->ridx = ridx;
+
+ run_set_tx_desc(sc, data, 0, xflags, 0, qflags, type, pad);
+
+ STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next);
+
+ usbd_transfer_start(sc->sc_xfer[qid]);
+
+ DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", m->m_pkthdr.len +
+ (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)),
+ rt2860_rates[ridx].rate, qid);
+
+ return (0);
+}
+
+static int
+run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+{
+ const struct ieee80211_txparam *tp;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct run_tx_data *data;
+ struct ieee80211_frame *wh;
+ int ridx;
+ uint16_t dur;
+ uint8_t type;
+ uint8_t xflags = 0;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
+
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ xflags |= RT2860_TX_ACK;
+
+ dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate,
+ ic->ic_flags & IEEE80211_F_SHPREAMBLE);
+ *(uint16_t *)wh->i_dur = htole16(dur);
+
+ /* tell hardware to add timestamp for probe responses */
+ if ((wh->i_fc[0] &
+ (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
+ (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
+ xflags |= RT2860_TX_TS;
+ }
+
+ if (sc->sc_epq[0].tx_nfree == 0) {
+ /* let caller free mbuf */
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ return (EIO);
+ }
+ data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
+ STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
+ sc->sc_epq[0].tx_nfree--;
+
+ data->m = m;
+ data->ni = ni;
+ for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
+ if (rt2860_rates[ridx].rate == tp->mgmtrate)
+ break;
+ data->ridx = ridx;
+
+ run_set_tx_desc(sc, data, 0, xflags, 0, RT2860_TX_QSEL_MGMT,
+ wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, 0);
+
+ DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
+ (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)),
+ tp->mgmtrate);
+
+ STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
+
+ usbd_transfer_start(sc->sc_xfer[0]);
+
+ return (0);
+}
+
+static int
+run_sendprot(struct run_softc *sc,
+ const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_frame *wh;
+ struct run_tx_data *data;
+ struct mbuf *mprot;
+ int ridx;
+ int protrate;
+ int ackrate;
+ int pktlen;
+ int isshort;
+ uint16_t dur;
+ uint8_t type;
+ uint8_t wflags;
+ uint8_t txflags = 0;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
+ ("protection %d", prot));
+
+ wh = mtod(m, struct ieee80211_frame *);
+ pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+ protrate = ieee80211_ctl_rate(ic->ic_rt, rate);
+ ackrate = ieee80211_ack_rate(ic->ic_rt, rate);
+
+ isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
+ dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort);
+ + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
+ wflags = RT2860_TX_FRAG;
+
+ /* check that there are free slots before allocating the mbuf */
+ if (sc->sc_epq[0].tx_nfree == 0) {
+ /* let caller free mbuf */
+ sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ return (ENOBUFS);
+ }
+
+ if (prot == IEEE80211_PROT_RTSCTS) {
+ /* NB: CTS is the same size as an ACK */
+ dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
+ txflags |= RT2860_TX_ACK;
+ mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
+ } else {
+ mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
+ }
+ if (mprot == NULL) {
+ sc->sc_ifp->if_oerrors++;
+ DPRINTF("could not allocate mbuf\n");
+ return (ENOBUFS);
+ }
+
+ data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
+ STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
+ sc->sc_epq[0].tx_nfree--;
+
+ data->m = mprot;
+ data->ni = ieee80211_ref_node(ni);
+
+ for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
+ if (rt2860_rates[ridx].rate == protrate)
+ break;
+ data->ridx = ridx;
+
+ run_set_tx_desc(sc, data, wflags, txflags, 0,
+ RT2860_TX_QSEL_EDCA, type, 0);
+
+ DPRINTFN(1, "sending prot len=%u rate=%u\n",
+ m->m_pkthdr.len, rate);
+
+ STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
+
+ usbd_transfer_start(sc->sc_xfer[0]);
+
+ return (0);
+}
+
+static int
+run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_frame *wh;
+ struct run_tx_data *data;
+ uint8_t type;
+ uint8_t opflags;
+ uint8_t txflags;
+ int ridx;
+ int rate;
+ int error;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ KASSERT(params != NULL, ("no raw xmit params"));
+
+ wh = mtod(m, struct ieee80211_frame *);
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+ rate = params->ibp_rate0;
+ if (!ieee80211_isratevalid(ic->ic_rt, rate)) {
+ /* let caller free mbuf */
+ return (EINVAL);
+ }
+
+ opflags = 0;
+ txflags = 0;
+ if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0)
+ txflags |= RT2860_TX_ACK;
+ if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) {
+ error = run_sendprot(sc, m, ni,
+ params->ibp_flags & IEEE80211_BPF_RTS ?
+ IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY,
+ rate);
+ if (error) {
+ /* let caller free mbuf */
+ return (error);
+ }
+ opflags |= /*XXX RT2573_TX_LONG_RETRY |*/ RT2860_TX_TXOP_SIFS;
+ }
+
+ if (sc->sc_epq[0].tx_nfree == 0) {
+ /* let caller free mbuf */
+ sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ DPRINTF("sending raw frame, but tx ring is full\n");
+ return (EIO);
+ }
+ data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh);
+ STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next);
+ sc->sc_epq[0].tx_nfree--;
+
+ data->m = m;
+ data->ni = ni;
+ for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
+ if (rt2860_rates[ridx].rate == rate)
+ break;
+ data->ridx = ridx;
+
+ run_set_tx_desc(sc, data, 0, txflags, opflags,
+ RT2860_TX_QSEL_EDCA, type, 0);
+
+ DPRINTFN(10, "sending raw frame len=%u rate=%u\n",
+ m->m_pkthdr.len, rate);
+
+ STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
+
+ usbd_transfer_start(sc->sc_xfer[0]);
+
+ return (0);
+}
+
+static int
+run_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ifnet *ifp = ni->ni_ic->ic_ifp;
+ struct run_softc *sc = ifp->if_softc;
+ int error;
+
+ RUN_LOCK(sc);
+
+ /* prevent management frames from being sent if we're not ready */
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ if (params == NULL) {
+ /* tx mgt packet */
+ if ((error = run_tx_mgt(sc, m, ni)) != 0){
+ ifp->if_oerrors++;
+ DPRINTF("mgt tx failed\n");
+ goto bad;
+ }
+ } else {
+ /* tx raw packet with param */
+ if ((error = run_tx_param(sc, m, ni, params)) != 0){
+ ifp->if_oerrors++;
+ DPRINTF("tx with param failed\n");
+ goto bad;
+ }
+ }
+
+ ifp->if_opackets++;
+
+ RUN_UNLOCK(sc);
+
+ return (0);
+
+bad:
+ RUN_UNLOCK(sc);
+ if(m != NULL)
+ m_freem(m);
+ ieee80211_free_node(ni);
+
+ return (error);
+}
+
+static void
+run_start(struct ifnet *ifp)
+{
+ struct run_softc *sc = ifp->if_softc;
+ struct ieee80211_node *ni;
+ struct mbuf *m;
+
+ RUN_LOCK(sc);
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ RUN_UNLOCK(sc);
+ return;
+ }
+
+ for (;;) {
+ /* send data frames */
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+
+ ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ if (run_tx(sc, m, ni) != 0) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
+ }
+
+ RUN_UNLOCK(sc);
+}
+
+static int
+run_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct run_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ifreq *ifr = (struct ifreq *) data;
+ int error = 0, startall = 0;
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ RUN_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){
+ run_init_locked(sc);
+ startall = 1;
+ } else
+ run_update_promisc_locked(ifp);
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ run_stop(sc);
+ }
+ RUN_UNLOCK(sc);
+ if(startall)
+ ieee80211_start_all(ic);
+ break;
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
+ break;
+ case SIOCGIFADDR:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
+
+static void
+run_select_chan_group(struct run_softc *sc, int group)
+{
+ uint32_t tmp;
+
+ run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
+ run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
+ run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
+ run_bbp_write(sc, 86, 0x00);
+
+ if (group == 0) {
+ if (sc->ext_2ghz_lna) {
+ run_bbp_write(sc, 82, 0x62);
+ run_bbp_write(sc, 75, 0x46);
+ } else {
+ run_bbp_write(sc, 82, 0x84);
+ run_bbp_write(sc, 75, 0x50);
+ }
+ } else {
+ if (sc->ext_5ghz_lna) {
+ run_bbp_write(sc, 82, 0xf2);
+ run_bbp_write(sc, 75, 0x46);
+ } else {
+ run_bbp_write(sc, 82, 0xf2);
+ run_bbp_write(sc, 75, 0x50);
+ }
+ }
+
+ run_read(sc, RT2860_TX_BAND_CFG, &tmp);
+ tmp &= ~(RT2860_5G_BAND_SEL_N | RT2860_5G_BAND_SEL_P);
+ tmp |= (group == 0) ? RT2860_5G_BAND_SEL_N : RT2860_5G_BAND_SEL_P;
+ run_write(sc, RT2860_TX_BAND_CFG, tmp);
+
+ /* enable appropriate Power Amplifiers and Low Noise Amplifiers */
+ tmp = RT2860_RFTR_EN | RT2860_TRSW_EN;
+ if (group == 0) { /* 2GHz */
+ tmp |= RT2860_PA_PE_G0_EN | RT2860_LNA_PE_G0_EN;
+ if (sc->ntxchains > 1)
+ tmp |= RT2860_PA_PE_G1_EN;
+ if (sc->nrxchains > 1)
+ tmp |= RT2860_LNA_PE_G1_EN;
+ } else { /* 5GHz */
+ tmp |= RT2860_PA_PE_A0_EN | RT2860_LNA_PE_A0_EN;
+ if (sc->ntxchains > 1)
+ tmp |= RT2860_PA_PE_A1_EN;
+ if (sc->nrxchains > 1)
+ tmp |= RT2860_LNA_PE_A1_EN;
+ }
+ run_write(sc, RT2860_TX_PIN_CFG, tmp);
+
+ /* set initial AGC value */
+ if (group == 0)
+ run_bbp_write(sc, 66, 0x2e + sc->lna[0]);
+ else
+ run_bbp_write(sc, 66, 0x32 + (sc->lna[group] * 5) / 3);
+}
+
+static void
+run_rt2870_set_chan(struct run_softc *sc, uint32_t chan)
+{
+ const struct rfprog *rfprog = rt2860_rf2850;
+ uint32_t r2, r3, r4;
+ int8_t txpow1, txpow2;
+ int i;
+
+ /* find the settings for this channel (we know it exists) */
+ for (i = 0; rfprog[i].chan != chan; i++);
+
+ r2 = rfprog[i].r2;
+ if (sc->ntxchains == 1)
+ r2 |= 1 << 12; /* 1T: disable Tx chain 2 */
+ if (sc->nrxchains == 1)
+ r2 |= 1 << 15 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */
+ else if (sc->nrxchains == 2)
+ r2 |= 1 << 4; /* 2R: disable Rx chain 3 */
+
+ /* use Tx power values from EEPROM */
+ txpow1 = sc->txpow1[i];
+ txpow2 = sc->txpow2[i];
+ if (chan > 14) {
+ if (txpow1 >= 0)
+ txpow1 = txpow1 << 1;
+ else
+ txpow1 = (7 + txpow1) << 1 | 1;
+ if (txpow2 >= 0)
+ txpow2 = txpow2 << 1;
+ else
+ txpow2 = (7 + txpow2) << 1 | 1;
+ }
+ r3 = rfprog[i].r3 | txpow1 << 7;
+ r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4;
+
+ run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
+ run_rt2870_rf_write(sc, RT2860_RF2, r2);
+ run_rt2870_rf_write(sc, RT2860_RF3, r3);
+ run_rt2870_rf_write(sc, RT2860_RF4, r4);
+
+ run_delay(sc, 10);
+
+ run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
+ run_rt2870_rf_write(sc, RT2860_RF2, r2);
+ run_rt2870_rf_write(sc, RT2860_RF3, r3 | 1);
+ run_rt2870_rf_write(sc, RT2860_RF4, r4);
+
+ run_delay(sc, 10);
+
+ run_rt2870_rf_write(sc, RT2860_RF1, rfprog[i].r1);
+ run_rt2870_rf_write(sc, RT2860_RF2, r2);
+ run_rt2870_rf_write(sc, RT2860_RF3, r3);
+ run_rt2870_rf_write(sc, RT2860_RF4, r4);
+}
+
+static void
+run_rt3070_set_chan(struct run_softc *sc, uint32_t chan)
+{
+ int8_t txpow1, txpow2;
+ uint8_t rf;
+
+ /* RT3070 is 2GHz only */
+ KASSERT(chan >= 1 && chan <= 14, ("wrong channel selected\n"));
+
+ /* use Tx power values from EEPROM */
+ txpow1 = sc->txpow1[chan - 1];
+ txpow2 = sc->txpow2[chan - 1];
+
+ run_rt3070_rf_write(sc, 2, run_rf3020_freqs[chan - 1].n);
+ run_rt3070_rf_write(sc, 3, run_rf3020_freqs[chan - 1].k);
+ run_rt3070_rf_read(sc, 6, &rf);
+ rf = (rf & ~0x03) | run_rf3020_freqs[chan - 1].r;
+ run_rt3070_rf_write(sc, 6, rf);
+
+ /* set Tx0 power */
+ run_rt3070_rf_read(sc, 12, &rf);
+ rf = (rf & ~0x1f) | txpow1;
+ run_rt3070_rf_write(sc, 12, rf);
+
+ /* set Tx1 power */
+ run_rt3070_rf_read(sc, 13, &rf);
+ rf = (rf & ~0x1f) | txpow2;
+ run_rt3070_rf_write(sc, 13, rf);
+
+ run_rt3070_rf_read(sc, 1, &rf);
+ rf &= ~0xfc;
+ if (sc->ntxchains == 1)
+ rf |= 1 << 7 | 1 << 5; /* 1T: disable Tx chains 2 & 3 */
+ else if (sc->ntxchains == 2)
+ rf |= 1 << 7; /* 2T: disable Tx chain 3 */
+ if (sc->nrxchains == 1)
+ rf |= 1 << 6 | 1 << 4; /* 1R: disable Rx chains 2 & 3 */
+ else if (sc->nrxchains == 2)
+ rf |= 1 << 6; /* 2R: disable Rx chain 3 */
+ run_rt3070_rf_write(sc, 1, rf);
+
+ /* set RF offset */
+ run_rt3070_rf_read(sc, 23, &rf);
+ rf = (rf & ~0x7f) | sc->freq;
+ run_rt3070_rf_write(sc, 23, rf);
+
+ /* program RF filter */
+ run_rt3070_rf_write(sc, 24, sc->rf24_20mhz);
+ run_rt3070_rf_write(sc, 31, sc->rf24_20mhz);
+
+ /* enable RF tuning */
+ run_rt3070_rf_read(sc, 7, &rf);
+ run_rt3070_rf_write(sc, 7, rf | 0x01);
+}
+
+static void
+run_set_rx_antenna(struct run_softc *sc, int aux)
+{
+ uint32_t tmp;
+
+ if (aux) {
+ run_read(sc, RT2860_PCI_EECTRL, &tmp);
+ run_write(sc, RT2860_PCI_EECTRL, tmp & ~RT2860_C);
+ run_read(sc, RT2860_GPIO_CTRL, &tmp);
+ run_write(sc, RT2860_GPIO_CTRL, (tmp & ~0x0808) | 0x08);
+ } else {
+ run_read(sc, RT2860_PCI_EECTRL, &tmp);
+ run_write(sc, RT2860_PCI_EECTRL, tmp | RT2860_C);
+ run_read(sc, RT2860_GPIO_CTRL, &tmp);
+ run_write(sc, RT2860_GPIO_CTRL, tmp & ~0x0808);
+ }
+}
+
+static int
+run_set_chan(struct run_softc *sc, struct ieee80211_channel *c)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint32_t chan, group;
+
+ chan = ieee80211_chan2ieee(ic, c);
+ if (chan == 0 || chan == IEEE80211_CHAN_ANY)
+ return EINVAL;
+
+ if ((sc->mac_rev >> 16) >= 0x3070)
+ run_rt3070_set_chan(sc, chan);
+ else
+ run_rt2870_set_chan(sc, chan);
+
+ /* 802.11a uses a 16 microseconds short interframe space */
+ sc->sifs = IEEE80211_IS_CHAN_5GHZ(c) ? 16 : 10;
+
+ /* determine channel group */
+ if (chan <= 14)
+ group = 0;
+ else if (chan <= 64)
+ group = 1;
+ else if (chan <= 128)
+ group = 2;
+ else
+ group = 3;
+
+ /* XXX necessary only when group has changed! */
+ run_select_chan_group(sc, group);
+
+ run_delay(sc, 10);
+
+ return 0;
+}
+
+static void
+run_set_channel(struct ieee80211com *ic)
+{
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+
+ RUN_LOCK(sc);
+ run_set_chan(sc, ic->ic_curchan);
+ RUN_UNLOCK(sc);
+
+ return;
+}
+
+static void
+run_scan_start(struct ieee80211com *ic)
+{
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+ uint32_t tmp;
+
+ RUN_LOCK(sc);
+
+ /* abort TSF synchronization */
+ run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
+ run_write(sc, RT2860_BCN_TIME_CFG,
+ tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
+ RT2860_TBTT_TIMER_EN));
+ run_set_bssid(sc, sc->sc_ifp->if_broadcastaddr);
+
+ RUN_UNLOCK(sc);
+
+ return;
+}
+
+static void
+run_scan_end(struct ieee80211com *ic)
+{
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+
+ RUN_LOCK(sc);
+
+ run_enable_tsf_sync(sc);
+ /* XXX keep local copy */
+ run_set_bssid(sc, sc->sc_bssid);
+
+ RUN_UNLOCK(sc);
+
+ return;
+}
+
+static uint8_t
+run_rate2mcs(uint8_t rate)
+{
+ switch (rate) {
+ /* CCK rates */
+ case 2: return 0;
+ case 4: return 1;
+ case 11: return 2;
+ case 22: return 3;
+ /* OFDM rates */
+ case 12: return 0;
+ case 18: return 1;
+ case 24: return 2;
+ case 36: return 3;
+ case 48: return 4;
+ case 72: return 5;
+ case 96: return 6;
+ case 108: return 7;
+ }
+ return 0; /* shouldn't get here */
+}
+
+static void
+run_update_beacon_locked(struct ieee80211vap *vap, int item)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+ struct rt2860_txwi txwi;
+ struct mbuf *m;
+ int rate;
+
+ if ((m = ieee80211_beacon_alloc(vap->iv_bss, &RUN_VAP(vap)->bo)) == NULL)
+ return;
+
+ memset(&txwi, 0, sizeof txwi);
+ txwi.wcid = 0xff;
+ txwi.len = htole16(m->m_pkthdr.len);
+ /* send beacons at the lowest available rate */
+ rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 12 : 2;
+ txwi.phy = htole16(run_rate2mcs(rate));
+ if (rate == 12)
+ txwi.phy |= htole16(RT2860_PHY_OFDM);
+ txwi.txop = RT2860_TX_TXOP_HT;
+ txwi.flags = RT2860_TX_TS;
+
+ run_write_region_1(sc, RT2860_BCN_BASE(0),
+ (u_int8_t *)&txwi, sizeof txwi);
+ run_write_region_1(sc, RT2860_BCN_BASE(0) + sizeof txwi,
+ mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); /* roundup len */
+
+ m_freem(m);
+
+ return;
+}
+
+static void
+run_update_beacon(struct ieee80211vap *vap, int item)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+
+ IEEE80211_UNLOCK(ic);
+ RUN_LOCK(sc);
+ run_update_beacon_locked(vap, item);
+ RUN_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+
+ return;
+}
+
+static void
+run_updateprot(struct ieee80211com *ic)
+{
+ struct run_softc *sc = ic->ic_ifp->if_softc;
+ uint32_t tmp;
+
+ tmp = RT2860_RTSTH_EN | RT2860_PROT_NAV_SHORT | RT2860_TXOP_ALLOW_ALL;
+ /* setup protection frame rate (MCS code) */
+ tmp |= (ic->ic_curmode == IEEE80211_MODE_11A) ?
+ rt2860_rates[RT2860_RIDX_OFDM6].mcs :
+ rt2860_rates[RT2860_RIDX_CCK11].mcs;
+
+ /* CCK frames don't require protection */
+ run_write(sc, RT2860_CCK_PROT_CFG, tmp);
+ if (ic->ic_flags & IEEE80211_F_USEPROT) {
+ if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
+ tmp |= RT2860_PROT_CTRL_RTS_CTS;
+ else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
+ tmp |= RT2860_PROT_CTRL_CTS;
+ }
+ run_write(sc, RT2860_OFDM_PROT_CFG, tmp);
+}
+
+static void
+run_usb_timeout_cb(void *arg, int pending)
+{
+ struct run_softc *sc = arg;
+ struct ieee80211vap *vap = &sc->sc_rvp->vap;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ if(vap->iv_state == IEEE80211_S_RUN &&
+ vap->iv_opmode != IEEE80211_M_STA)
+ run_reset_livelock(sc);
+ else if(vap->iv_state == IEEE80211_S_SCAN){
+ DPRINTF("timeout caused by scan\n");
+ /* cancel bgscan */
+ ieee80211_cancel_scan(vap);
+ } else
+ DPRINTF("timeout by unknown cause\n");
+}
+
+static void
+run_reset_livelock(struct run_softc *sc)
+{
+ uint32_t tmp;
+
+ /*
+ * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
+ * can run into a livelock and start sending CTS-to-self frames like
+ * crazy if protection is enabled. Reset MAC/BBP for a while
+ */
+ run_read(sc, RT2860_DEBUG, &tmp);
+ if((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))){
+ DPRINTF("CTS-to-self livelock detected\n");
+ run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
+ run_delay(sc, 1);
+ run_write(sc, RT2860_MAC_SYS_CTRL,
+ RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
+ }
+}
+
+static void
+run_update_promisc_locked(struct ifnet *ifp)
+{
+ struct run_softc *sc = ifp->if_softc;
+ uint32_t tmp;
+
+ run_read(sc, RT2860_RX_FILTR_CFG, &tmp);
+
+ tmp |= RT2860_DROP_UC_NOME;
+ if (ifp->if_flags & IFF_PROMISC)
+ tmp &= ~RT2860_DROP_UC_NOME;
+
+ run_write(sc, RT2860_RX_FILTR_CFG, tmp);
+
+ DPRINTF("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
+ "entering" : "leaving");
+}
+
+static void
+run_update_promisc(struct ifnet *ifp)
+{
+ struct run_softc *sc = ifp->if_softc;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ return;
+
+ RUN_LOCK(sc);
+ run_update_promisc_locked(ifp);
+ RUN_UNLOCK(sc);
+}
+
+static void
+run_enable_tsf_sync(struct run_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ uint32_t tmp;
+
+ run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
+ tmp &= ~0x1fffff;
+ tmp |= vap->iv_bss->ni_intval * 16;
+ tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN;
+
+ if (vap->iv_opmode == IEEE80211_M_STA) {
+ /*
+ * Local TSF is always updated with remote TSF on beacon
+ * reception.
+ */
+ tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT;
+ } else if (vap->iv_opmode == IEEE80211_M_IBSS) {
+ tmp |= RT2860_BCN_TX_EN;
+ /*
+ * Local TSF is updated with remote TSF on beacon reception
+ * only if the remote TSF is greater than local TSF.
+ */
+ tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT;
+ } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+ tmp |= RT2860_BCN_TX_EN;
+ /* SYNC with nobody */
+ tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT;
+ } else
+ DPRINTF("Enabling TSF failed. undefined opmode\n");
+
+ run_write(sc, RT2860_BCN_TIME_CFG, tmp);
+}
+
+static void
+run_enable_mrr(struct run_softc *sc)
+{
+#define CCK(mcs) (mcs)
+#define OFDM(mcs) (1 << 3 | (mcs))
+ run_write(sc, RT2860_LG_FBK_CFG0,
+ OFDM(6) << 28 | /* 54->48 */
+ OFDM(5) << 24 | /* 48->36 */
+ OFDM(4) << 20 | /* 36->24 */
+ OFDM(3) << 16 | /* 24->18 */
+ OFDM(2) << 12 | /* 18->12 */
+ OFDM(1) << 8 | /* 12-> 9 */
+ OFDM(0) << 4 | /* 9-> 6 */
+ OFDM(0)); /* 6-> 6 */
+
+ run_write(sc, RT2860_LG_FBK_CFG1,
+ CCK(2) << 12 | /* 11->5.5 */
+ CCK(1) << 8 | /* 5.5-> 2 */
+ CCK(0) << 4 | /* 2-> 1 */
+ CCK(0)); /* 1-> 1 */
+#undef OFDM
+#undef CCK
+}
+
+static void
+run_set_txpreamble(struct run_softc *sc)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint32_t tmp;
+
+ run_read(sc, RT2860_AUTO_RSP_CFG, &tmp);
+ if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+ tmp |= RT2860_CCK_SHORT_EN;
+ else
+ tmp &= ~RT2860_CCK_SHORT_EN;
+ run_write(sc, RT2860_AUTO_RSP_CFG, tmp);
+}
+
+static void
+run_set_basicrates(struct run_softc *sc)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+
+ /* set basic rates mask */
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x003);
+ else if (ic->ic_curmode == IEEE80211_MODE_11A)
+ run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x150);
+ else /* 11g */
+ run_write(sc, RT2860_LEGACY_BASIC_RATE, 0x15f);
+}
+
+static void
+run_set_leds(struct run_softc *sc, uint16_t which)
+{
+ (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LEDS,
+ which | (sc->leds & 0x7f));
+}
+
+static void
+run_set_bssid(struct run_softc *sc, const uint8_t *bssid)
+{
+ run_write(sc, RT2860_MAC_BSSID_DW0,
+ bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24);
+ run_write(sc, RT2860_MAC_BSSID_DW1,
+ bssid[4] | bssid[5] << 8);
+}
+
+static void
+run_set_macaddr(struct run_softc *sc, const uint8_t *addr)
+{
+ run_write(sc, RT2860_MAC_ADDR_DW0,
+ addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
+ run_write(sc, RT2860_MAC_ADDR_DW1,
+ addr[4] | addr[5] << 8 | 0xff << 16);
+}
+
+/* ARGSUSED */
+static void
+run_updateslot(struct ifnet *ifp)
+{
+ struct run_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint32_t tmp;
+
+ run_read(sc, RT2860_BKOFF_SLOT_CFG, &tmp);
+ tmp &= ~0xff;
+ tmp |= (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
+ run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp);
+}
+
+static int8_t
+run_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211_channel *c = ic->ic_curchan;
+ int delta;
+
+ if (IEEE80211_IS_CHAN_5GHZ(c)) {
+ uint32_t chan = ieee80211_chan2ieee(ic, c);
+ delta = sc->rssi_5ghz[rxchain];
+
+ /* determine channel group */
+ if (chan <= 64)
+ delta -= sc->lna[1];
+ else if (chan <= 128)
+ delta -= sc->lna[2];
+ else
+ delta -= sc->lna[3];
+ } else
+ delta = sc->rssi_2ghz[rxchain] - sc->lna[0];
+
+ return -12 - delta - rssi;
+}
+
+static int
+run_bbp_init(struct run_softc *sc)
+{
+ int i, error, ntries;
+ uint8_t bbp0;
+
+ /* wait for BBP to wake up */
+ for (ntries = 0; ntries < 20; ntries++) {
+ if ((error = run_bbp_read(sc, 0, &bbp0)) != 0)
+ return error;
+ if (bbp0 != 0 && bbp0 != 0xff)
+ break;
+ }
+ if (ntries == 20)
+ return ETIMEDOUT;
+
+ /* initialize BBP registers to default values */
+ for (i = 0; i < nitems(rt2860_def_bbp); i++) {
+ run_bbp_write(sc, rt2860_def_bbp[i].reg,
+ rt2860_def_bbp[i].val);
+ }
+
+ /* fix BBP84 for RT2860E */
+ if ((sc->mac_rev >> 16) == 0x2860 && (sc->mac_rev & 0xffff) != 0x0101)
+ run_bbp_write(sc, 84, 0x19);
+
+ if ((sc->mac_rev >> 16) >= 0x3070) {
+ run_bbp_write(sc, 79, 0x13);
+ run_bbp_write(sc, 80, 0x05);
+ run_bbp_write(sc, 81, 0x33);
+ /* XXX RT3090 needs more */
+ } else if (sc->mac_rev == 0x28600100) {
+ run_bbp_write(sc, 69, 0x16);
+ run_bbp_write(sc, 73, 0x12);
+ }
+ return 0;
+}
+
+static int
+run_rt3070_rf_init(struct run_softc *sc)
+{
+ uint32_t tmp;
+ uint8_t rf, bbp4;
+ int i;
+
+ run_rt3070_rf_read(sc, 30, &rf);
+ /* toggle RF R30 bit 7 */
+ run_rt3070_rf_write(sc, 30, rf | 0x80);
+ run_delay(sc, 10);
+ run_rt3070_rf_write(sc, 30, rf & ~0x80);
+
+ /* initialize RF registers to default value */
+ for (i = 0; i < nitems(rt3070_def_rf); i++) {
+ run_rt3070_rf_write(sc, rt3070_def_rf[i].reg,
+ rt3070_def_rf[i].val);
+ }
+ if ((sc->mac_rev >> 16) == 0x3070) {
+ /* change voltage from 1.2V to 1.35V for RT3070 */
+ run_read(sc, RT3070_LDO_CFG0, &tmp);
+ tmp = (tmp & ~0x0f000000) | 0x0d000000;
+ run_write(sc, RT3070_LDO_CFG0, tmp);
+
+ } else if ((sc->mac_rev >> 16) == 0x3071) {
+ run_rt3070_rf_read(sc, 6, &rf);
+ run_rt3070_rf_write(sc, 6, rf | 0x40);
+ run_rt3070_rf_write(sc, 31, 0x14);
+
+ run_read(sc, RT3070_LDO_CFG0, &tmp);
+ tmp &= ~0x1f000000;
+ if ((sc->mac_rev & 0xffff) < 0x0211)
+ tmp |= 0x0d000000;
+ else
+ tmp |= 0x01000000;
+ run_write(sc, RT3070_LDO_CFG0, tmp);
+
+ /* patch LNA_PE_G1 */
+ run_read(sc, RT3070_GPIO_SWITCH, &tmp);
+ run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20);
+ } else if((sc->mac_rev >> 16) == 0x3572){
+ if ((sc->mac_rev & 0xffff) < 0x0211){
+ run_read(sc, RT3070_LDO_CFG0, &tmp);
+ tmp = (tmp & ~0x0f000000) | 0x0d000000;
+ run_write(sc, RT3070_LDO_CFG0, tmp);
+ } else {
+ run_read(sc, RT3070_LDO_CFG0, &tmp);
+ tmp = (tmp & ~0x1f000000) | 0x0d000000;
+ run_write(sc, RT3070_LDO_CFG0, tmp);
+
+ run_delay(sc, 1); /* wait for 1msec */
+
+ tmp = (tmp & ~0x1f000000) | 0x01000000;
+ run_write(sc, RT3070_LDO_CFG0, tmp);
+ }
+ }
+
+ /* select 20MHz bandwidth */
+ run_rt3070_rf_read(sc, 31, &rf);
+ run_rt3070_rf_write(sc, 31, rf & ~0x20);
+
+ /* calibrate filter for 20MHz bandwidth */
+ sc->rf24_20mhz = 0x1f; /* default value */
+ run_rt3070_filter_calib(sc, 0x07, 0x16, &sc->rf24_20mhz);
+
+ /* select 40MHz bandwidth */
+ run_bbp_read(sc, 4, &bbp4);
+ run_bbp_write(sc, 4, (bbp4 & ~0x08) | 0x10);
+
+ /* calibrate filter for 40MHz bandwidth */
+ sc->rf24_40mhz = 0x2f; /* default value */
+ run_rt3070_filter_calib(sc, 0x27, 0x19, &sc->rf24_40mhz);
+
+ /* go back to 20MHz bandwidth */
+ run_bbp_read(sc, 4, &bbp4);
+ run_bbp_write(sc, 4, bbp4 & ~0x18);
+
+ if ((sc->mac_rev & 0xffff) < 0x0211)
+ run_rt3070_rf_write(sc, 27, 0x03);
+
+ run_read(sc, RT3070_OPT_14, &tmp);
+ run_write(sc, RT3070_OPT_14, tmp | 1);
+
+ if ((sc->mac_rev >> 16) == 0x3071) {
+ run_rt3070_rf_read(sc, 1, &rf);
+ rf &= ~(RT3070_RX0_PD | RT3070_TX0_PD);
+ rf |= RT3070_RF_BLOCK | RT3070_RX1_PD | RT3070_TX1_PD;
+ run_rt3070_rf_write(sc, 1, rf);
+
+ run_rt3070_rf_read(sc, 15, &rf);
+ run_rt3070_rf_write(sc, 15, rf & ~RT3070_TX_LO2);
+
+ run_rt3070_rf_read(sc, 17, &rf);
+ rf &= ~RT3070_TX_LO1;
+ if ((sc->mac_rev & 0xffff) >= 0x0211 && !sc->ext_2ghz_lna)
+ rf |= 0x20; /* fix for long range Rx issue */
+ run_rt3070_rf_write(sc, 17, rf);
+
+ run_rt3070_rf_read(sc, 20, &rf);
+ run_rt3070_rf_write(sc, 20, rf & ~RT3070_RX_LO1);
+
+ run_rt3070_rf_read(sc, 21, &rf);
+ run_rt3070_rf_write(sc, 21, rf & ~RT3070_RX_LO2);
+
+ run_rt3070_rf_read(sc, 27, &rf);
+ rf &= ~0x77;
+ if ((sc->mac_rev & 0xffff) < 0x0211)
+ rf |= 0x03;
+ run_rt3070_rf_write(sc, 27, rf);
+ }
+ return 0;
+}
+
+static int
+run_rt3070_filter_calib(struct run_softc *sc, uint8_t init, uint8_t target,
+ uint8_t *val)
+{
+ uint8_t rf22, rf24;
+ uint8_t bbp55_pb, bbp55_sb, delta;
+ int ntries;
+
+ /* program filter */
+ rf24 = init; /* initial filter value */
+ run_rt3070_rf_write(sc, 24, rf24);
+
+ /* enable baseband loopback mode */
+ run_rt3070_rf_read(sc, 22, &rf22);
+ run_rt3070_rf_write(sc, 22, rf22 | 0x01);
+
+ /* set power and frequency of passband test tone */
+ run_bbp_write(sc, 24, 0x00);
+ for (ntries = 0; ntries < 100; ntries++) {
+ /* transmit test tone */
+ run_bbp_write(sc, 25, 0x90);
+ run_delay(sc, 10);
+ /* read received power */
+ run_bbp_read(sc, 55, &bbp55_pb);
+ if (bbp55_pb != 0)
+ break;
+ }
+ if (ntries == 100)
+ return ETIMEDOUT;
+
+ /* set power and frequency of stopband test tone */
+ run_bbp_write(sc, 24, 0x06);
+ for (ntries = 0; ntries < 100; ntries++) {
+ /* transmit test tone */
+ run_bbp_write(sc, 25, 0x90);
+ run_delay(sc, 10);
+ /* read received power */
+ run_bbp_read(sc, 55, &bbp55_sb);
+
+ delta = bbp55_pb - bbp55_sb;
+ if (delta > target)
+ break;
+
+ /* reprogram filter */
+ rf24++;
+ run_rt3070_rf_write(sc, 24, rf24);
+ }
+ if (ntries < 100) {
+ if (rf24 != init)
+ rf24--; /* backtrack */
+ *val = rf24;
+ run_rt3070_rf_write(sc, 24, rf24);
+ }
+
+ /* restore initial state */
+ run_bbp_write(sc, 24, 0x00);
+
+ /* disable baseband loopback mode */
+ run_rt3070_rf_read(sc, 22, &rf22);
+ run_rt3070_rf_write(sc, 22, rf22 & ~0x01);
+
+ return 0;
+}
+
+static int
+run_txrx_enable(struct run_softc *sc)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint32_t tmp;
+ int error, ntries;
+
+ run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_TX_EN);
+ for (ntries = 0; ntries < 200; ntries++) {
+ if ((error = run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp)) != 0)
+ return error;
+ if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
+ break;
+ run_delay(sc, 50);
+ }
+ if (ntries == 200)
+ return ETIMEDOUT;
+
+ run_delay(sc, 50);
+
+ tmp |= RT2860_RX_DMA_EN | RT2860_TX_DMA_EN | RT2860_TX_WB_DDONE;
+ run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
+
+ /* enable Rx bulk aggregation (set timeout and limit) */
+ tmp = RT2860_USB_TX_EN | RT2860_USB_RX_EN | RT2860_USB_RX_AGG_EN |
+ RT2860_USB_RX_AGG_TO(128) | RT2860_USB_RX_AGG_LMT(2);
+ run_write(sc, RT2860_USB_DMA_CFG, tmp);
+
+ /* set Rx filter */
+ tmp = RT2860_DROP_CRC_ERR | RT2860_DROP_PHY_ERR;
+ if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+ tmp |= RT2860_DROP_UC_NOME | RT2860_DROP_DUPL |
+ RT2860_DROP_CTS | RT2860_DROP_BA | RT2860_DROP_ACK |
+ RT2860_DROP_VER_ERR | RT2860_DROP_CTRL_RSV |
+ RT2860_DROP_CFACK | RT2860_DROP_CFEND;
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ tmp |= RT2860_DROP_RTS | RT2860_DROP_PSPOLL;
+ }
+ run_write(sc, RT2860_RX_FILTR_CFG, tmp);
+
+ run_write(sc, RT2860_MAC_SYS_CTRL,
+ RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
+
+ return 0;
+}
+
+static void
+run_init_locked(struct run_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211vap *vap = &sc->sc_rvp->vap;
+ uint32_t tmp;
+ uint8_t bbp1, bbp3;
+ int i;
+ int ridx;
+ int ntries;
+
+ run_stop(sc);
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (run_read(sc, RT2860_ASIC_VER_ID, &tmp) != 0)
+ goto fail;
+ if (tmp != 0 && tmp != 0xffffffff)
+ break;
+ run_delay(sc, 10);
+ }
+ if (ntries == 100)
+ goto fail;
+
+ for (i = 0; i != RUN_EP_QUEUES; i++)
+ run_setup_tx_list(sc, &sc->sc_epq[i]);
+
+ run_set_macaddr(sc, IF_LLADDR(ifp));
+
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (run_read(sc, RT2860_WPDMA_GLO_CFG, &tmp) != 0)
+ goto fail;
+ if ((tmp & (RT2860_TX_DMA_BUSY | RT2860_RX_DMA_BUSY)) == 0)
+ break;
+ run_delay(sc, 10);
+ }
+ if (ntries == 100) {
+ printf("%s: timeout waiting for DMA engine\n",
+ device_get_nameunit(sc->sc_dev));
+ goto fail;
+ }
+ tmp &= 0xff0;
+ tmp |= RT2860_TX_WB_DDONE;
+ run_write(sc, RT2860_WPDMA_GLO_CFG, tmp);
+
+ /* turn off PME_OEN to solve high-current issue */
+ run_read(sc, RT2860_SYS_CTRL, &tmp);
+ run_write(sc, RT2860_SYS_CTRL, tmp & ~RT2860_PME_OEN);
+
+ run_write(sc, RT2860_MAC_SYS_CTRL,
+ RT2860_BBP_HRST | RT2860_MAC_SRST);
+ run_write(sc, RT2860_USB_DMA_CFG, 0);
+
+ if (run_reset(sc) != 0) {
+ printf("%s: could not reset chipset\n",
+ device_get_nameunit(sc->sc_dev));
+ goto fail;
+ }
+
+ run_write(sc, RT2860_MAC_SYS_CTRL, 0);
+
+ /* init Tx power for all Tx rates (from EEPROM) */
+ for (ridx = 0; ridx < 5; ridx++) {
+ if (sc->txpow20mhz[ridx] == 0xffffffff)
+ continue;
+ run_write(sc, RT2860_TX_PWR_CFG(ridx), sc->txpow20mhz[ridx]);
+ }
+
+ for (i = 0; i < nitems(rt2870_def_mac); i++)
+ run_write(sc, rt2870_def_mac[i].reg, rt2870_def_mac[i].val);
+ run_write(sc, RT2860_WMM_AIFSN_CFG, 0x00002273);
+ run_write(sc, RT2860_WMM_CWMIN_CFG, 0x00002344);
+ run_write(sc, RT2860_WMM_CWMAX_CFG, 0x000034aa);
+
+ if ((sc->mac_rev >> 16) >= 0x3070) {
+ /* set delay of PA_PE assertion to 1us (unit of 0.25us) */
+ run_write(sc, RT2860_TX_SW_CFG0,
+ 4 << RT2860_DLY_PAPE_EN_SHIFT);
+ run_write(sc, RT2860_TX_SW_CFG1, 0);
+ run_write(sc, RT2860_TX_SW_CFG2, 0x1f);
+ }
+
+ /* wait while MAC is busy */
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (run_read(sc, RT2860_MAC_STATUS_REG, &tmp) != 0)
+ goto fail;
+ if (!(tmp & (RT2860_RX_STATUS_BUSY | RT2860_TX_STATUS_BUSY)))
+ break;
+ run_delay(sc, 10);
+ }
+ if (ntries == 100)
+ goto fail;
+
+ /* clear Host to MCU mailbox */
+ run_write(sc, RT2860_H2M_BBPAGENT, 0);
+ run_write(sc, RT2860_H2M_MAILBOX, 0);
+ run_delay(sc, 10);
+
+ if (run_bbp_init(sc) != 0) {
+ printf("%s: could not initialize BBP\n",
+ device_get_nameunit(sc->sc_dev));
+ goto fail;
+ }
+
+ /* abort TSF synchronization */
+ run_read(sc, RT2860_BCN_TIME_CFG, &tmp);
+ tmp &= ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN |
+ RT2860_TBTT_TIMER_EN);
+ run_write(sc, RT2860_BCN_TIME_CFG, tmp);
+
+ /* clear RX WCID search table */
+ run_set_region_4(sc, RT2860_WCID_ENTRY(0), 0, 512);
+ /* clear WCID attribute table */
+ run_set_region_4(sc, RT2860_WCID_ATTR(0), 0, 8 * 32);
+ /* clear shared key table */
+ run_set_region_4(sc, RT2860_SKEY(0, 0), 0, 8 * 32);
+ /* clear shared key mode */
+ run_set_region_4(sc, RT2860_SKEY_MODE_0_7, 0, 4);
+
+ run_read(sc, RT2860_US_CYC_CNT, &tmp);
+ tmp = (tmp & ~0xff) | 0x1e;
+ run_write(sc, RT2860_US_CYC_CNT, tmp);
+
+ if ((sc->mac_rev >> 16) == 0x2860 && (sc->mac_rev & 0xffff) != 0x0101)
+ run_write(sc, RT2860_TXOP_CTRL_CFG, 0x0000583f);
+
+ run_write(sc, RT2860_WMM_TXOP0_CFG, 0);
+ run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96);
+
+ /* write vendor-specific BBP values (from EEPROM) */
+ for (i = 0; i < 8; i++) {
+ if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff)
+ continue;
+ run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val);
+ }
+
+ /* select Main antenna for 1T1R devices */
+ if (sc->rf_rev == RT3070_RF_3020)
+ run_set_rx_antenna(sc, 0);
+
+ /* send LEDs operating mode to microcontroller */
+ (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED1, sc->led[0]);
+ (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED2, sc->led[1]);
+ (void)run_mcu_cmd(sc, RT2860_MCU_CMD_LED3, sc->led[2]);
+
+ /* disable non-existing Rx chains */
+ run_bbp_read(sc, 3, &bbp3);
+ bbp3 &= ~(1 << 3 | 1 << 4);
+ if (sc->nrxchains == 2)
+ bbp3 |= 1 << 3;
+ else if (sc->nrxchains == 3)
+ bbp3 |= 1 << 4;
+ run_bbp_write(sc, 3, bbp3);
+
+ /* disable non-existing Tx chains */
+ run_bbp_read(sc, 1, &bbp1);
+ if (sc->ntxchains == 1)
+ bbp1 &= ~(1 << 3 | 1 << 4);
+ run_bbp_write(sc, 1, bbp1);
+
+ if ((sc->mac_rev >> 16) >= 0x3070)
+ run_rt3070_rf_init(sc);
+
+ /* select default channel */
+ vap->iv_bss->ni_chan = ic->ic_curchan; /* ic_bsschan?? */
+ run_set_chan(sc, ic->ic_curchan);
+
+ /* setup initial protection mode */
+ run_updateprot(ic);
+
+ /* turn radio LED on */
+ run_set_leds(sc, RT2860_LED_RADIO);
+
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+
+ for(i = 0; i != RUN_N_XFER; i++)
+ usbd_xfer_set_stall(sc->sc_xfer[i]);
+
+ usbd_transfer_start(sc->sc_xfer[RUN_BULK_RX]);
+
+ if (run_txrx_enable(sc) != 0)
+ goto fail;
+
+ return;
+
+fail:
+ run_stop(sc);
+}
+
+static void
+run_init(void *arg)
+{
+ struct run_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ RUN_LOCK(sc);
+ run_init_locked(sc);
+ RUN_UNLOCK(sc);
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ieee80211_start_all(ic);
+}
+
+static void
+run_stop(void *arg)
+{
+ struct run_softc *sc = (struct run_softc *)arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint32_t tmp;
+ int i;
+ int ntries;
+
+ RUN_LOCK_ASSERT(sc, MA_OWNED);
+
+ if (ic->ic_flags & IEEE80211_F_SCAN)
+ ieee80211_cancel_scan(&sc->sc_rvp->vap);
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ run_set_leds(sc, 0); /* turn all LEDs off */
+
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+ sc->sc_rvp->amrr_run = RUN_AMRR_OFF;
+
+ RUN_UNLOCK(sc);
+
+ /* drain them all */
+ usb_callout_drain(&sc->sc_rvp->amrr_ch);
+ ieee80211_draintask(ic, &sc->sc_rvp->amrr_task);
+ ieee80211_draintask(ic, &sc->wme_task);
+ for(i = 0; i < RUN_N_XFER; i++)
+ usbd_transfer_drain(sc->sc_xfer[i]);
+ ieee80211_draintask(ic, &sc->usb_timeout_task);
+
+ RUN_LOCK(sc);
+
+ if(sc->rx_m != NULL){
+ m_free(sc->rx_m);
+ sc->rx_m = NULL;
+ }
+
+ /* disable Tx/Rx */
+ run_read(sc, RT2860_MAC_SYS_CTRL, &tmp);
+ tmp &= ~(RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
+ run_write(sc, RT2860_MAC_SYS_CTRL, tmp);
+
+ /* wait for pending Tx to complete */
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (run_read(sc, RT2860_TXRXQ_PCNT, &tmp) != 0){
+ DPRINTF("Cannot read Tx queue count\n");
+ break;
+ }
+ if ((tmp & RT2860_TX2Q_PCNT_MASK) == 0){
+ DPRINTF("All Tx cleared\n");
+ break;
+ }
+ run_delay(sc, 10);
+ }
+ if(ntries >= 100)
+ DPRINTF("There are still pending Tx\n");
+ run_delay(sc, 10);
+ run_write(sc, RT2860_USB_DMA_CFG, 0);
+
+ run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_BBP_HRST | RT2860_MAC_SRST);
+ run_write(sc, RT2860_MAC_SYS_CTRL, 0);
+
+ for (i = 0; i != RUN_EP_QUEUES; i++)
+ run_unsetup_tx_list(sc, &sc->sc_epq[i]);
+
+ return;
+}
+
+static void
+run_delay(struct run_softc *sc, unsigned int ms)
+{
+ usb_pause_mtx(mtx_owned(&sc->sc_mtx) ?
+ &sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
+}
+
+static device_method_t run_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, run_match),
+ DEVMETHOD(device_attach, run_attach),
+ DEVMETHOD(device_detach, run_detach),
+
+ { 0, 0 }
+};
+
+static driver_t run_driver = {
+ "run",
+ run_methods,
+ sizeof(struct run_softc)
+};
+
+static devclass_t run_devclass;
+
+DRIVER_MODULE(run, uhub, run_driver, run_devclass, NULL, 0);
diff --git a/sys/dev/usb/wlan/if_runreg.h b/sys/dev/usb/wlan/if_runreg.h
new file mode 100644
index 0000000..f630fb1
--- /dev/null
+++ b/sys/dev/usb/wlan/if_runreg.h
@@ -0,0 +1,1130 @@
+/* $OpenBSD: rt2860reg.h,v 1.19 2009/05/18 19:25:07 damien Exp $ */
+
+/*-
+ * Copyright (c) 2007
+ * Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_RUNREG_H_
+#define _IF_RUNREG_H_
+
+/* PCI registers */
+#define RT2860_PCI_CFG 0x0000
+#define RT2860_PCI_EECTRL 0x0004
+#define RT2860_PCI_MCUCTRL 0x0008
+#define RT2860_PCI_SYSCTRL 0x000c
+#define RT2860_PCIE_JTAG 0x0010
+
+#define RT2860_CONFIG_NO 1
+#define RT2860_IFACE_INDEX 0
+
+#define RT3070_OPT_14 0x0114
+
+/* SCH/DMA registers */
+#define RT2860_INT_STATUS 0x0200
+#define RT2860_INT_MASK 0x0204
+#define RT2860_WPDMA_GLO_CFG 0x0208
+#define RT2860_WPDMA_RST_IDX 0x020c
+#define RT2860_DELAY_INT_CFG 0x0210
+#define RT2860_WMM_AIFSN_CFG 0x0214
+#define RT2860_WMM_CWMIN_CFG 0x0218
+#define RT2860_WMM_CWMAX_CFG 0x021c
+#define RT2860_WMM_TXOP0_CFG 0x0220
+#define RT2860_WMM_TXOP1_CFG 0x0224
+#define RT2860_GPIO_CTRL 0x0228
+#define RT2860_MCU_CMD_REG 0x022c
+#define RT2860_TX_BASE_PTR(qid) (0x0230 + (qid) * 16)
+#define RT2860_TX_MAX_CNT(qid) (0x0234 + (qid) * 16)
+#define RT2860_TX_CTX_IDX(qid) (0x0238 + (qid) * 16)
+#define RT2860_TX_DTX_IDX(qid) (0x023c + (qid) * 16)
+#define RT2860_RX_BASE_PTR 0x0290
+#define RT2860_RX_MAX_CNT 0x0294
+#define RT2860_RX_CALC_IDX 0x0298
+#define RT2860_FS_DRX_IDX 0x029c
+#define RT2860_USB_DMA_CFG 0x02a0 /* RT2870 only */
+#define RT2860_US_CYC_CNT 0x02a4
+
+/* PBF registers */
+#define RT2860_SYS_CTRL 0x0400
+#define RT2860_HOST_CMD 0x0404
+#define RT2860_PBF_CFG 0x0408
+#define RT2860_MAX_PCNT 0x040c
+#define RT2860_BUF_CTRL 0x0410
+#define RT2860_MCU_INT_STA 0x0414
+#define RT2860_MCU_INT_ENA 0x0418
+#define RT2860_TXQ_IO(qid) (0x041c + (qid) * 4)
+#define RT2860_RX0Q_IO 0x0424
+#define RT2860_BCN_OFFSET0 0x042c
+#define RT2860_BCN_OFFSET1 0x0430
+#define RT2860_TXRXQ_STA 0x0434
+#define RT2860_TXRXQ_PCNT 0x0438
+#define RT2860_PBF_DBG 0x043c
+#define RT2860_CAP_CTRL 0x0440
+
+/* RT3070 registers */
+#define RT3070_RF_CSR_CFG 0x0500
+#define RT3070_EFUSE_CTRL 0x0580
+#define RT3070_EFUSE_DATA0 0x0590
+#define RT3070_EFUSE_DATA1 0x0594
+#define RT3070_EFUSE_DATA2 0x0598
+#define RT3070_EFUSE_DATA3 0x059c
+#define RT3070_LDO_CFG0 0x05d4
+#define RT3070_GPIO_SWITCH 0x05dc
+
+/* MAC registers */
+#define RT2860_ASIC_VER_ID 0x1000
+#define RT2860_MAC_SYS_CTRL 0x1004
+#define RT2860_MAC_ADDR_DW0 0x1008
+#define RT2860_MAC_ADDR_DW1 0x100c
+#define RT2860_MAC_BSSID_DW0 0x1010
+#define RT2860_MAC_BSSID_DW1 0x1014
+#define RT2860_MAX_LEN_CFG 0x1018
+#define RT2860_BBP_CSR_CFG 0x101c
+#define RT2860_RF_CSR_CFG0 0x1020
+#define RT2860_RF_CSR_CFG1 0x1024
+#define RT2860_RF_CSR_CFG2 0x1028
+#define RT2860_LED_CFG 0x102c
+
+/* undocumented registers */
+#define RT2860_DEBUG 0x10f4
+
+/* MAC Timing control registers */
+#define RT2860_XIFS_TIME_CFG 0x1100
+#define RT2860_BKOFF_SLOT_CFG 0x1104
+#define RT2860_NAV_TIME_CFG 0x1108
+#define RT2860_CH_TIME_CFG 0x110c
+#define RT2860_PBF_LIFE_TIMER 0x1110
+#define RT2860_BCN_TIME_CFG 0x1114
+#define RT2860_TBTT_SYNC_CFG 0x1118
+#define RT2860_TSF_TIMER_DW0 0x111c
+#define RT2860_TSF_TIMER_DW1 0x1120
+#define RT2860_TBTT_TIMER 0x1124
+#define RT2860_INT_TIMER_CFG 0x1128
+#define RT2860_INT_TIMER_EN 0x112c
+#define RT2860_CH_IDLE_TIME 0x1130
+
+/* MAC Power Save configuration registers */
+#define RT2860_MAC_STATUS_REG 0x1200
+#define RT2860_PWR_PIN_CFG 0x1204
+#define RT2860_AUTO_WAKEUP_CFG 0x1208
+
+/* MAC TX configuration registers */
+#define RT2860_EDCA_AC_CFG(aci) (0x1300 + (aci) * 4)
+#define RT2860_EDCA_TID_AC_MAP 0x1310
+#define RT2860_TX_PWR_CFG(ridx) (0x1314 + (ridx) * 4)
+#define RT2860_TX_PIN_CFG 0x1328
+#define RT2860_TX_BAND_CFG 0x132c
+#define RT2860_TX_SW_CFG0 0x1330
+#define RT2860_TX_SW_CFG1 0x1334
+#define RT2860_TX_SW_CFG2 0x1338
+#define RT2860_TXOP_THRES_CFG 0x133c
+#define RT2860_TXOP_CTRL_CFG 0x1340
+#define RT2860_TX_RTS_CFG 0x1344
+#define RT2860_TX_TIMEOUT_CFG 0x1348
+#define RT2860_TX_RTY_CFG 0x134c
+#define RT2860_TX_LINK_CFG 0x1350
+#define RT2860_HT_FBK_CFG0 0x1354
+#define RT2860_HT_FBK_CFG1 0x1358
+#define RT2860_LG_FBK_CFG0 0x135c
+#define RT2860_LG_FBK_CFG1 0x1360
+#define RT2860_CCK_PROT_CFG 0x1364
+#define RT2860_OFDM_PROT_CFG 0x1368
+#define RT2860_MM20_PROT_CFG 0x136c
+#define RT2860_MM40_PROT_CFG 0x1370
+#define RT2860_GF20_PROT_CFG 0x1374
+#define RT2860_GF40_PROT_CFG 0x1378
+#define RT2860_EXP_CTS_TIME 0x137c
+#define RT2860_EXP_ACK_TIME 0x1380
+
+/* MAC RX configuration registers */
+#define RT2860_RX_FILTR_CFG 0x1400
+#define RT2860_AUTO_RSP_CFG 0x1404
+#define RT2860_LEGACY_BASIC_RATE 0x1408
+#define RT2860_HT_BASIC_RATE 0x140c
+#define RT2860_HT_CTRL_CFG 0x1410
+#define RT2860_SIFS_COST_CFG 0x1414
+#define RT2860_RX_PARSER_CFG 0x1418
+
+/* MAC Security configuration registers */
+#define RT2860_TX_SEC_CNT0 0x1500
+#define RT2860_RX_SEC_CNT0 0x1504
+#define RT2860_CCMP_FC_MUTE 0x1508
+
+/* MAC HCCA/PSMP configuration registers */
+#define RT2860_TXOP_HLDR_ADDR0 0x1600
+#define RT2860_TXOP_HLDR_ADDR1 0x1604
+#define RT2860_TXOP_HLDR_ET 0x1608
+#define RT2860_QOS_CFPOLL_RA_DW0 0x160c
+#define RT2860_QOS_CFPOLL_A1_DW1 0x1610
+#define RT2860_QOS_CFPOLL_QC 0x1614
+
+/* MAC Statistics Counters */
+#define RT2860_RX_STA_CNT0 0x1700
+#define RT2860_RX_STA_CNT1 0x1704
+#define RT2860_RX_STA_CNT2 0x1708
+#define RT2860_TX_STA_CNT0 0x170c
+#define RT2860_TX_STA_CNT1 0x1710
+#define RT2860_TX_STA_CNT2 0x1714
+#define RT2860_TX_STAT_FIFO 0x1718
+
+/* RX WCID search table */
+#define RT2860_WCID_ENTRY(wcid) (0x1800 + (wcid) * 8)
+
+#define RT2860_FW_BASE 0x2000
+#define RT2870_FW_BASE 0x3000
+
+/* Pair-wise key table */
+#define RT2860_PKEY(wcid) (0x4000 + (wcid) * 32)
+
+/* IV/EIV table */
+#define RT2860_IVEIV(wcid) (0x6000 + (wcid) * 8)
+
+/* WCID attribute table */
+#define RT2860_WCID_ATTR(wcid) (0x6800 + (wcid) * 4)
+
+/* Shared Key Table */
+#define RT2860_SKEY(vap, kidx) (0x6c00 + (vap) * 128 + (kidx) * 32)
+
+/* Shared Key Mode */
+#define RT2860_SKEY_MODE_0_7 0x7000
+#define RT2860_SKEY_MODE_8_15 0x7004
+#define RT2860_SKEY_MODE_16_23 0x7008
+#define RT2860_SKEY_MODE_24_31 0x700c
+
+/* Shared Memory between MCU and host */
+#define RT2860_H2M_MAILBOX 0x7010
+#define RT2860_H2M_MAILBOX_CID 0x7014
+#define RT2860_H2M_MAILBOX_STATUS 0x701c
+#define RT2860_H2M_BBPAGENT 0x7028
+#define RT2860_BCN_BASE(vap) (0x7800 + (vap) * 512)
+
+
+/* possible flags for register RT2860_PCI_EECTRL */
+#define RT2860_C (1 << 0)
+#define RT2860_S (1 << 1)
+#define RT2860_D (1 << 2)
+#define RT2860_SHIFT_D 2
+#define RT2860_Q (1 << 3)
+#define RT2860_SHIFT_Q 3
+
+/* possible flags for registers INT_STATUS/INT_MASK */
+#define RT2860_TX_COHERENT (1 << 17)
+#define RT2860_RX_COHERENT (1 << 16)
+#define RT2860_MAC_INT_4 (1 << 15)
+#define RT2860_MAC_INT_3 (1 << 14)
+#define RT2860_MAC_INT_2 (1 << 13)
+#define RT2860_MAC_INT_1 (1 << 12)
+#define RT2860_MAC_INT_0 (1 << 11)
+#define RT2860_TX_RX_COHERENT (1 << 10)
+#define RT2860_MCU_CMD_INT (1 << 9)
+#define RT2860_TX_DONE_INT5 (1 << 8)
+#define RT2860_TX_DONE_INT4 (1 << 7)
+#define RT2860_TX_DONE_INT3 (1 << 6)
+#define RT2860_TX_DONE_INT2 (1 << 5)
+#define RT2860_TX_DONE_INT1 (1 << 4)
+#define RT2860_TX_DONE_INT0 (1 << 3)
+#define RT2860_RX_DONE_INT (1 << 2)
+#define RT2860_TX_DLY_INT (1 << 1)
+#define RT2860_RX_DLY_INT (1 << 0)
+
+/* possible flags for register WPDMA_GLO_CFG */
+#define RT2860_HDR_SEG_LEN_SHIFT 8
+#define RT2860_BIG_ENDIAN (1 << 7)
+#define RT2860_TX_WB_DDONE (1 << 6)
+#define RT2860_WPDMA_BT_SIZE_SHIFT 4
+#define RT2860_WPDMA_BT_SIZE16 0
+#define RT2860_WPDMA_BT_SIZE32 1
+#define RT2860_WPDMA_BT_SIZE64 2
+#define RT2860_WPDMA_BT_SIZE128 3
+#define RT2860_RX_DMA_BUSY (1 << 3)
+#define RT2860_RX_DMA_EN (1 << 2)
+#define RT2860_TX_DMA_BUSY (1 << 1)
+#define RT2860_TX_DMA_EN (1 << 0)
+
+/* possible flags for register DELAY_INT_CFG */
+#define RT2860_TXDLY_INT_EN (1 << 31)
+#define RT2860_TXMAX_PINT_SHIFT 24
+#define RT2860_TXMAX_PTIME_SHIFT 16
+#define RT2860_RXDLY_INT_EN (1 << 15)
+#define RT2860_RXMAX_PINT_SHIFT 8
+#define RT2860_RXMAX_PTIME_SHIFT 0
+
+/* possible flags for register GPIO_CTRL */
+#define RT2860_GPIO_D_SHIFT 8
+#define RT2860_GPIO_O_SHIFT 0
+
+/* possible flags for register USB_DMA_CFG */
+#define RT2860_USB_TX_BUSY (1 << 31)
+#define RT2860_USB_RX_BUSY (1 << 30)
+#define RT2860_USB_EPOUT_VLD_SHIFT 24
+#define RT2860_USB_TX_EN (1 << 23)
+#define RT2860_USB_RX_EN (1 << 22)
+#define RT2860_USB_RX_AGG_EN (1 << 21)
+#define RT2860_USB_TXOP_HALT (1 << 20)
+#define RT2860_USB_TX_CLEAR (1 << 19)
+#define RT2860_USB_PHY_WD_EN (1 << 16)
+#define RT2860_USB_PHY_MAN_RST (1 << 15)
+#define RT2860_USB_RX_AGG_LMT(x) ((x) << 8) /* in unit of 1KB */
+#define RT2860_USB_RX_AGG_TO(x) ((x) & 0xff) /* in unit of 33ns */
+
+/* possible flags for register US_CYC_CNT */
+#define RT2860_TEST_EN (1 << 24)
+#define RT2860_TEST_SEL_SHIFT 16
+#define RT2860_BT_MODE_EN (1 << 8)
+#define RT2860_US_CYC_CNT_SHIFT 0
+
+/* possible flags for register SYS_CTRL */
+#define RT2860_HST_PM_SEL (1 << 16)
+#define RT2860_CAP_MODE (1 << 14)
+#define RT2860_PME_OEN (1 << 13)
+#define RT2860_CLKSELECT (1 << 12)
+#define RT2860_PBF_CLK_EN (1 << 11)
+#define RT2860_MAC_CLK_EN (1 << 10)
+#define RT2860_DMA_CLK_EN (1 << 9)
+#define RT2860_MCU_READY (1 << 7)
+#define RT2860_ASY_RESET (1 << 4)
+#define RT2860_PBF_RESET (1 << 3)
+#define RT2860_MAC_RESET (1 << 2)
+#define RT2860_DMA_RESET (1 << 1)
+#define RT2860_MCU_RESET (1 << 0)
+
+/* possible values for register HOST_CMD */
+#define RT2860_MCU_CMD_SLEEP 0x30
+#define RT2860_MCU_CMD_WAKEUP 0x31
+#define RT2860_MCU_CMD_LEDS 0x50
+#define RT2860_MCU_CMD_LED_RSSI 0x51
+#define RT2860_MCU_CMD_LED1 0x52
+#define RT2860_MCU_CMD_LED2 0x53
+#define RT2860_MCU_CMD_LED3 0x54
+#define RT2860_MCU_CMD_BOOT 0x72
+#define RT2860_MCU_CMD_BBP 0x80
+#define RT2860_MCU_CMD_PSLEVEL 0x83
+
+/* possible flags for register PBF_CFG */
+#define RT2860_TX1Q_NUM_SHIFT 21
+#define RT2860_TX2Q_NUM_SHIFT 16
+#define RT2860_NULL0_MODE (1 << 15)
+#define RT2860_NULL1_MODE (1 << 14)
+#define RT2860_RX_DROP_MODE (1 << 13)
+#define RT2860_TX0Q_MANUAL (1 << 12)
+#define RT2860_TX1Q_MANUAL (1 << 11)
+#define RT2860_TX2Q_MANUAL (1 << 10)
+#define RT2860_RX0Q_MANUAL (1 << 9)
+#define RT2860_HCCA_EN (1 << 8)
+#define RT2860_TX0Q_EN (1 << 4)
+#define RT2860_TX1Q_EN (1 << 3)
+#define RT2860_TX2Q_EN (1 << 2)
+#define RT2860_RX0Q_EN (1 << 1)
+
+/* possible flags for register BUF_CTRL */
+#define RT2860_WRITE_TXQ(qid) (1 << (11 - (qid)))
+#define RT2860_NULL0_KICK (1 << 7)
+#define RT2860_NULL1_KICK (1 << 6)
+#define RT2860_BUF_RESET (1 << 5)
+#define RT2860_READ_TXQ(qid) (1 << (3 - (qid))
+#define RT2860_READ_RX0Q (1 << 0)
+
+/* possible flags for registers MCU_INT_STA/MCU_INT_ENA */
+#define RT2860_MCU_MAC_INT_8 (1 << 24)
+#define RT2860_MCU_MAC_INT_7 (1 << 23)
+#define RT2860_MCU_MAC_INT_6 (1 << 22)
+#define RT2860_MCU_MAC_INT_4 (1 << 20)
+#define RT2860_MCU_MAC_INT_3 (1 << 19)
+#define RT2860_MCU_MAC_INT_2 (1 << 18)
+#define RT2860_MCU_MAC_INT_1 (1 << 17)
+#define RT2860_MCU_MAC_INT_0 (1 << 16)
+#define RT2860_DTX0_INT (1 << 11)
+#define RT2860_DTX1_INT (1 << 10)
+#define RT2860_DTX2_INT (1 << 9)
+#define RT2860_DRX0_INT (1 << 8)
+#define RT2860_HCMD_INT (1 << 7)
+#define RT2860_N0TX_INT (1 << 6)
+#define RT2860_N1TX_INT (1 << 5)
+#define RT2860_BCNTX_INT (1 << 4)
+#define RT2860_MTX0_INT (1 << 3)
+#define RT2860_MTX1_INT (1 << 2)
+#define RT2860_MTX2_INT (1 << 1)
+#define RT2860_MRX0_INT (1 << 0)
+
+/* possible flags for register TXRXQ_PCNT */
+#define RT2860_RX0Q_PCNT_MASK 0xff000000
+#define RT2860_TX2Q_PCNT_MASK 0x00ff0000
+#define RT2860_TX1Q_PCNT_MASK 0x0000ff00
+#define RT2860_TX0Q_PCNT_MASK 0x000000ff
+
+/* possible flags for register CAP_CTRL */
+#define RT2860_CAP_ADC_FEQ (1 << 31)
+#define RT2860_CAP_START (1 << 30)
+#define RT2860_MAN_TRIG (1 << 29)
+#define RT2860_TRIG_OFFSET_SHIFT 16
+#define RT2860_START_ADDR_SHIFT 0
+
+/* possible flags for register RF_CSR_CFG */
+#define RT3070_RF_KICK (1 << 17)
+#define RT3070_RF_WRITE (1 << 16)
+
+/* possible flags for register EFUSE_CTRL */
+#define RT3070_SEL_EFUSE (1 << 31)
+#define RT3070_EFSROM_KICK (1 << 30)
+#define RT3070_EFSROM_AIN_MASK 0x03ff0000
+#define RT3070_EFSROM_AIN_SHIFT 16
+#define RT3070_EFSROM_MODE_MASK 0x000000c0
+#define RT3070_EFUSE_AOUT_MASK 0x0000003f
+
+/* possible flags for register MAC_SYS_CTRL */
+#define RT2860_RX_TS_EN (1 << 7)
+#define RT2860_WLAN_HALT_EN (1 << 6)
+#define RT2860_PBF_LOOP_EN (1 << 5)
+#define RT2860_CONT_TX_TEST (1 << 4)
+#define RT2860_MAC_RX_EN (1 << 3)
+#define RT2860_MAC_TX_EN (1 << 2)
+#define RT2860_BBP_HRST (1 << 1)
+#define RT2860_MAC_SRST (1 << 0)
+
+/* possible flags for register MAC_BSSID_DW1 */
+#define RT2860_MULTI_BCN_NUM_SHIFT 18
+#define RT2860_MULTI_BSSID_MODE_SHIFT 16
+
+/* possible flags for register MAX_LEN_CFG */
+#define RT2860_MIN_MPDU_LEN_SHIFT 16
+#define RT2860_MAX_PSDU_LEN_SHIFT 12
+#define RT2860_MAX_PSDU_LEN8K 0
+#define RT2860_MAX_PSDU_LEN16K 1
+#define RT2860_MAX_PSDU_LEN32K 2
+#define RT2860_MAX_PSDU_LEN64K 3
+#define RT2860_MAX_MPDU_LEN_SHIFT 0
+
+/* possible flags for registers BBP_CSR_CFG/H2M_BBPAGENT */
+#define RT2860_BBP_RW_PARALLEL (1 << 19)
+#define RT2860_BBP_PAR_DUR_112_5 (1 << 18)
+#define RT2860_BBP_CSR_KICK (1 << 17)
+#define RT2860_BBP_CSR_READ (1 << 16)
+#define RT2860_BBP_ADDR_SHIFT 8
+#define RT2860_BBP_DATA_SHIFT 0
+
+/* possible flags for register RF_CSR_CFG0 */
+#define RT2860_RF_REG_CTRL (1 << 31)
+#define RT2860_RF_LE_SEL1 (1 << 30)
+#define RT2860_RF_LE_STBY (1 << 29)
+#define RT2860_RF_REG_WIDTH_SHIFT 24
+#define RT2860_RF_REG_0_SHIFT 0
+
+/* possible flags for register RF_CSR_CFG1 */
+#define RT2860_RF_DUR_5 (1 << 24)
+#define RT2860_RF_REG_1_SHIFT 0
+
+/* possible flags for register LED_CFG */
+#define RT2860_LED_POL (1 << 30)
+#define RT2860_Y_LED_MODE_SHIFT 28
+#define RT2860_G_LED_MODE_SHIFT 26
+#define RT2860_R_LED_MODE_SHIFT 24
+#define RT2860_LED_MODE_OFF 0
+#define RT2860_LED_MODE_BLINK_TX 1
+#define RT2860_LED_MODE_SLOW_BLINK 2
+#define RT2860_LED_MODE_ON 3
+#define RT2860_SLOW_BLK_TIME_SHIFT 16
+#define RT2860_LED_OFF_TIME_SHIFT 8
+#define RT2860_LED_ON_TIME_SHIFT 0
+
+/* possible flags for register XIFS_TIME_CFG */
+#define RT2860_BB_RXEND_EN (1 << 29)
+#define RT2860_EIFS_TIME_SHIFT 20
+#define RT2860_OFDM_XIFS_TIME_SHIFT 16
+#define RT2860_OFDM_SIFS_TIME_SHIFT 8
+#define RT2860_CCK_SIFS_TIME_SHIFT 0
+
+/* possible flags for register BKOFF_SLOT_CFG */
+#define RT2860_CC_DELAY_TIME_SHIFT 8
+#define RT2860_SLOT_TIME 0
+
+/* possible flags for register NAV_TIME_CFG */
+#define RT2860_NAV_UPD (1 << 31)
+#define RT2860_NAV_UPD_VAL_SHIFT 16
+#define RT2860_NAV_CLR_EN (1 << 15)
+#define RT2860_NAV_TIMER_SHIFT 0
+
+/* possible flags for register CH_TIME_CFG */
+#define RT2860_EIFS_AS_CH_BUSY (1 << 4)
+#define RT2860_NAV_AS_CH_BUSY (1 << 3)
+#define RT2860_RX_AS_CH_BUSY (1 << 2)
+#define RT2860_TX_AS_CH_BUSY (1 << 1)
+#define RT2860_CH_STA_TIMER_EN (1 << 0)
+
+/* possible values for register BCN_TIME_CFG */
+#define RT2860_TSF_INS_COMP_SHIFT 24
+#define RT2860_BCN_TX_EN (1 << 20)
+#define RT2860_TBTT_TIMER_EN (1 << 19)
+#define RT2860_TSF_SYNC_MODE_SHIFT 17
+#define RT2860_TSF_SYNC_MODE_DIS 0
+#define RT2860_TSF_SYNC_MODE_STA 1
+#define RT2860_TSF_SYNC_MODE_IBSS 2
+#define RT2860_TSF_SYNC_MODE_HOSTAP 3
+#define RT2860_TSF_TIMER_EN (1 << 16)
+#define RT2860_BCN_INTVAL_SHIFT 0
+
+/* possible flags for register TBTT_SYNC_CFG */
+#define RT2860_BCN_CWMIN_SHIFT 20
+#define RT2860_BCN_AIFSN_SHIFT 16
+#define RT2860_BCN_EXP_WIN_SHIFT 8
+#define RT2860_TBTT_ADJUST_SHIFT 0
+
+/* possible flags for register INT_TIMER_CFG */
+#define RT2860_GP_TIMER_SHIFT 16
+#define RT2860_PRE_TBTT_TIMER_SHIFT 0
+
+/* possible flags for register INT_TIMER_EN */
+#define RT2860_GP_TIMER_EN (1 << 1)
+#define RT2860_PRE_TBTT_INT_EN (1 << 0)
+
+/* possible flags for register MAC_STATUS_REG */
+#define RT2860_RX_STATUS_BUSY (1 << 1)
+#define RT2860_TX_STATUS_BUSY (1 << 0)
+
+/* possible flags for register PWR_PIN_CFG */
+#define RT2860_IO_ADDA_PD (1 << 3)
+#define RT2860_IO_PLL_PD (1 << 2)
+#define RT2860_IO_RA_PE (1 << 1)
+#define RT2860_IO_RF_PE (1 << 0)
+
+/* possible flags for register AUTO_WAKEUP_CFG */
+#define RT2860_AUTO_WAKEUP_EN (1 << 15)
+#define RT2860_SLEEP_TBTT_NUM_SHIFT 8
+#define RT2860_WAKEUP_LEAD_TIME_SHIFT 0
+
+/* possible flags for register TX_PIN_CFG */
+#define RT2860_TRSW_POL (1 << 19)
+#define RT2860_TRSW_EN (1 << 18)
+#define RT2860_RFTR_POL (1 << 17)
+#define RT2860_RFTR_EN (1 << 16)
+#define RT2860_LNA_PE_G1_POL (1 << 15)
+#define RT2860_LNA_PE_A1_POL (1 << 14)
+#define RT2860_LNA_PE_G0_POL (1 << 13)
+#define RT2860_LNA_PE_A0_POL (1 << 12)
+#define RT2860_LNA_PE_G1_EN (1 << 11)
+#define RT2860_LNA_PE_A1_EN (1 << 10)
+#define RT2860_LNA_PE_G0_EN (1 << 9)
+#define RT2860_LNA_PE_A0_EN (1 << 8)
+#define RT2860_PA_PE_G1_POL (1 << 7)
+#define RT2860_PA_PE_A1_POL (1 << 6)
+#define RT2860_PA_PE_G0_POL (1 << 5)
+#define RT2860_PA_PE_A0_POL (1 << 4)
+#define RT2860_PA_PE_G1_EN (1 << 3)
+#define RT2860_PA_PE_A1_EN (1 << 2)
+#define RT2860_PA_PE_G0_EN (1 << 1)
+#define RT2860_PA_PE_A0_EN (1 << 0)
+
+/* possible flags for register TX_BAND_CFG */
+#define RT2860_5G_BAND_SEL_N (1 << 2)
+#define RT2860_5G_BAND_SEL_P (1 << 1)
+#define RT2860_TX_BAND_SEL (1 << 0)
+
+/* possible flags for register TX_SW_CFG0 */
+#define RT2860_DLY_RFTR_EN_SHIFT 24
+#define RT2860_DLY_TRSW_EN_SHIFT 16
+#define RT2860_DLY_PAPE_EN_SHIFT 8
+#define RT2860_DLY_TXPE_EN_SHIFT 0
+
+/* possible flags for register TX_SW_CFG1 */
+#define RT2860_DLY_RFTR_DIS_SHIFT 16
+#define RT2860_DLY_TRSW_DIS_SHIFT 8
+#define RT2860_DLY_PAPE_DIS SHIFT 0
+
+/* possible flags for register TX_SW_CFG2 */
+#define RT2860_DLY_LNA_EN_SHIFT 24
+#define RT2860_DLY_LNA_DIS_SHIFT 16
+#define RT2860_DLY_DAC_EN_SHIFT 8
+#define RT2860_DLY_DAC_DIS_SHIFT 0
+
+/* possible flags for register TXOP_THRES_CFG */
+#define RT2860_TXOP_REM_THRES_SHIFT 24
+#define RT2860_CF_END_THRES_SHIFT 16
+#define RT2860_RDG_IN_THRES 8
+#define RT2860_RDG_OUT_THRES 0
+
+/* possible flags for register TXOP_CTRL_CFG */
+#define RT2860_EXT_CW_MIN_SHIFT 16
+#define RT2860_EXT_CCA_DLY_SHIFT 8
+#define RT2860_EXT_CCA_EN (1 << 7)
+#define RT2860_LSIG_TXOP_EN (1 << 6)
+#define RT2860_TXOP_TRUN_EN_MIMOPS (1 << 4)
+#define RT2860_TXOP_TRUN_EN_TXOP (1 << 3)
+#define RT2860_TXOP_TRUN_EN_RATE (1 << 2)
+#define RT2860_TXOP_TRUN_EN_AC (1 << 1)
+#define RT2860_TXOP_TRUN_EN_TIMEOUT (1 << 0)
+
+/* possible flags for register TX_RTS_CFG */
+#define RT2860_RTS_FBK_EN (1 << 24)
+#define RT2860_RTS_THRES_SHIFT 8
+#define RT2860_RTS_RTY_LIMIT_SHIFT 0
+
+/* possible flags for register TX_TIMEOUT_CFG */
+#define RT2860_TXOP_TIMEOUT_SHIFT 16
+#define RT2860_RX_ACK_TIMEOUT_SHIFT 8
+#define RT2860_MPDU_LIFE_TIME_SHIFT 4
+
+/* possible flags for register TX_RTY_CFG */
+#define RT2860_TX_AUTOFB_EN (1 << 30)
+#define RT2860_AGG_RTY_MODE_TIMER (1 << 29)
+#define RT2860_NAG_RTY_MODE_TIMER (1 << 28)
+#define RT2860_LONG_RTY_THRES_SHIFT 16
+#define RT2860_LONG_RTY_LIMIT_SHIFT 8
+#define RT2860_SHORT_RTY_LIMIT_SHIFT 0
+
+/* possible flags for register TX_LINK_CFG */
+#define RT2860_REMOTE_MFS_SHIFT 24
+#define RT2860_REMOTE_MFB_SHIFT 16
+#define RT2860_TX_CFACK_EN (1 << 12)
+#define RT2860_TX_RDG_EN (1 << 11)
+#define RT2860_TX_MRQ_EN (1 << 10)
+#define RT2860_REMOTE_UMFS_EN (1 << 9)
+#define RT2860_TX_MFB_EN (1 << 8)
+#define RT2860_REMOTE_MFB_LT_SHIFT 0
+
+/* possible flags for registers *_PROT_CFG */
+#define RT2860_RTSTH_EN (1 << 26)
+#define RT2860_TXOP_ALLOW_GF40 (1 << 25)
+#define RT2860_TXOP_ALLOW_GF20 (1 << 24)
+#define RT2860_TXOP_ALLOW_MM40 (1 << 23)
+#define RT2860_TXOP_ALLOW_MM20 (1 << 22)
+#define RT2860_TXOP_ALLOW_OFDM (1 << 21)
+#define RT2860_TXOP_ALLOW_CCK (1 << 20)
+#define RT2860_TXOP_ALLOW_ALL (0x3f << 20)
+#define RT2860_PROT_NAV_SHORT (1 << 18)
+#define RT2860_PROT_NAV_LONG (2 << 18)
+#define RT2860_PROT_CTRL_RTS_CTS (1 << 16)
+#define RT2860_PROT_CTRL_CTS (2 << 16)
+
+/* possible flags for registers EXP_{CTS,ACK}_TIME */
+#define RT2860_EXP_OFDM_TIME_SHIFT 16
+#define RT2860_EXP_CCK_TIME_SHIFT 0
+
+/* possible flags for register RX_FILTR_CFG */
+#define RT2860_DROP_CTRL_RSV (1 << 16)
+#define RT2860_DROP_BAR (1 << 15)
+#define RT2860_DROP_BA (1 << 14)
+#define RT2860_DROP_PSPOLL (1 << 13)
+#define RT2860_DROP_RTS (1 << 12)
+#define RT2860_DROP_CTS (1 << 11)
+#define RT2860_DROP_ACK (1 << 10)
+#define RT2860_DROP_CFEND (1 << 9)
+#define RT2860_DROP_CFACK (1 << 8)
+#define RT2860_DROP_DUPL (1 << 7)
+#define RT2860_DROP_BC (1 << 6)
+#define RT2860_DROP_MC (1 << 5)
+#define RT2860_DROP_VER_ERR (1 << 4)
+#define RT2860_DROP_NOT_MYBSS (1 << 3)
+#define RT2860_DROP_UC_NOME (1 << 2)
+#define RT2860_DROP_PHY_ERR (1 << 1)
+#define RT2860_DROP_CRC_ERR (1 << 0)
+
+/* possible flags for register AUTO_RSP_CFG */
+#define RT2860_CTRL_PWR_BIT (1 << 7)
+#define RT2860_BAC_ACK_POLICY (1 << 6)
+#define RT2860_CCK_SHORT_EN (1 << 4)
+#define RT2860_CTS_40M_REF_EN (1 << 3)
+#define RT2860_CTS_40M_MODE_EN (1 << 2)
+#define RT2860_BAC_ACKPOLICY_EN (1 << 1)
+#define RT2860_AUTO_RSP_EN (1 << 0)
+
+/* possible flags for register SIFS_COST_CFG */
+#define RT2860_OFDM_SIFS_COST_SHIFT 8
+#define RT2860_CCK_SIFS_COST_SHIFT 0
+
+/* possible flags for register TXOP_HLDR_ET */
+#define RT2860_TXOP_ETM1_EN (1 << 25)
+#define RT2860_TXOP_ETM0_EN (1 << 24)
+#define RT2860_TXOP_ETM_THRES_SHIFT 16
+#define RT2860_TXOP_ETO_EN (1 << 8)
+#define RT2860_TXOP_ETO_THRES_SHIFT 1
+#define RT2860_PER_RX_RST_EN (1 << 0)
+
+/* possible flags for register TX_STAT_FIFO */
+#define RT2860_TXQ_MCS_SHIFT 16
+#define RT2860_TXQ_WCID_SHIFT 8
+#define RT2860_TXQ_ACKREQ (1 << 7)
+#define RT2860_TXQ_AGG (1 << 6)
+#define RT2860_TXQ_OK (1 << 5)
+#define RT2860_TXQ_PID_SHIFT 1
+#define RT2860_TXQ_VLD (1 << 0)
+
+/* possible flags for register WCID_ATTR */
+#define RT2860_MODE_NOSEC 0
+#define RT2860_MODE_WEP40 1
+#define RT2860_MODE_WEP104 2
+#define RT2860_MODE_TKIP 3
+#define RT2860_MODE_AES_CCMP 4
+#define RT2860_MODE_CKIP40 5
+#define RT2860_MODE_CKIP104 6
+#define RT2860_MODE_CKIP128 7
+#define RT2860_RX_PKEY_EN (1 << 0)
+
+/* possible flags for register H2M_MAILBOX */
+#define RT2860_H2M_BUSY (1 << 24)
+#define RT2860_TOKEN_NO_INTR 0xff
+
+
+/* possible flags for MCU command RT2860_MCU_CMD_LEDS */
+#define RT2860_LED_RADIO (1 << 13)
+#define RT2860_LED_LINK_2GHZ (1 << 14)
+#define RT2860_LED_LINK_5GHZ (1 << 15)
+
+
+/* possible flags for RT3020 RF register 1 */
+#define RT3070_RF_BLOCK (1 << 0)
+#define RT3070_RX0_PD (1 << 2)
+#define RT3070_TX0_PD (1 << 3)
+#define RT3070_RX1_PD (1 << 4)
+#define RT3070_TX1_PD (1 << 5)
+
+/* possible flags for RT3020 RF register 15 */
+#define RT3070_TX_LO2 (1 << 3)
+
+/* possible flags for RT3020 RF register 17 */
+#define RT3070_TX_LO1 (1 << 3)
+
+/* possible flags for RT3020 RF register 20 */
+#define RT3070_RX_LO1 (1 << 3)
+
+/* possible flags for RT3020 RF register 21 */
+#define RT3070_RX_LO2 (1 << 3)
+
+
+/* RT2860 TX descriptor */
+struct rt2860_txd {
+ uint32_t sdp0; /* Segment Data Pointer 0 */
+ uint16_t sdl1; /* Segment Data Length 1 */
+#define RT2860_TX_BURST (1 << 15)
+#define RT2860_TX_LS1 (1 << 14) /* SDP1 is the last segment */
+
+ uint16_t sdl0; /* Segment Data Length 0 */
+#define RT2860_TX_DDONE (1 << 15)
+#define RT2860_TX_LS0 (1 << 14) /* SDP0 is the last segment */
+
+ uint32_t sdp1; /* Segment Data Pointer 1 */
+ uint8_t reserved[3];
+ uint8_t flags;
+#define RT2860_TX_QSEL_SHIFT 1
+#define RT2860_TX_QSEL_MGMT (0 << 1)
+#define RT2860_TX_QSEL_HCCA (1 << 1)
+#define RT2860_TX_QSEL_EDCA (2 << 1)
+#define RT2860_TX_WIV (1 << 0)
+} __packed;
+
+/* RT2870 TX descriptor */
+struct rt2870_txd {
+ uint16_t len;
+ uint8_t pad;
+ uint8_t flags;
+} __packed;
+
+/* TX Wireless Information */
+struct rt2860_txwi {
+ uint8_t flags;
+#define RT2860_TX_MPDU_DSITY_SHIFT 5
+#define RT2860_TX_AMPDU (1 << 4)
+#define RT2860_TX_TS (1 << 3)
+#define RT2860_TX_CFACK (1 << 2)
+#define RT2860_TX_MMPS (1 << 1)
+#define RT2860_TX_FRAG (1 << 0)
+
+ uint8_t txop;
+#define RT2860_TX_TXOP_HT 0
+#define RT2860_TX_TXOP_PIFS 1
+#define RT2860_TX_TXOP_SIFS 2
+#define RT2860_TX_TXOP_BACKOFF 3
+
+ uint16_t phy;
+#define RT2860_PHY_MODE 0xc000
+#define RT2860_PHY_CCK (0 << 14)
+#define RT2860_PHY_OFDM (1 << 14)
+#define RT2860_PHY_HT (2 << 14)
+#define RT2860_PHY_HT_GF (3 << 14)
+#define RT2860_PHY_SGI (1 << 8)
+#define RT2860_PHY_BW40 (1 << 7)
+#define RT2860_PHY_MCS 0x7f
+#define RT2860_PHY_SHPRE (1 << 3)
+
+ uint8_t xflags;
+#define RT2860_TX_BAWINSIZE_SHIFT 2
+#define RT2860_TX_NSEQ (1 << 1)
+#define RT2860_TX_ACK (1 << 0)
+
+ uint8_t wcid; /* Wireless Client ID */
+ uint16_t len;
+#define RT2860_TX_PID_SHIFT 12
+
+ uint32_t iv;
+ uint32_t eiv;
+} __packed;
+
+/* RT2860 RX descriptor */
+struct rt2860_rxd {
+ uint32_t sdp0;
+ uint16_t sdl1; /* unused */
+ uint16_t sdl0;
+#define RT2860_RX_DDONE (1 << 15)
+#define RT2860_RX_LS0 (1 << 14)
+
+ uint32_t sdp1; /* unused */
+ uint32_t flags;
+#define RT2860_RX_DEC (1 << 16)
+#define RT2860_RX_AMPDU (1 << 15)
+#define RT2860_RX_L2PAD (1 << 14)
+#define RT2860_RX_RSSI (1 << 13)
+#define RT2860_RX_HTC (1 << 12)
+#define RT2860_RX_AMSDU (1 << 11)
+#define RT2860_RX_MICERR (1 << 10)
+#define RT2860_RX_ICVERR (1 << 9)
+#define RT2860_RX_CRCERR (1 << 8)
+#define RT2860_RX_MYBSS (1 << 7)
+#define RT2860_RX_BC (1 << 6)
+#define RT2860_RX_MC (1 << 5)
+#define RT2860_RX_UC2ME (1 << 4)
+#define RT2860_RX_FRAG (1 << 3)
+#define RT2860_RX_NULL (1 << 2)
+#define RT2860_RX_DATA (1 << 1)
+#define RT2860_RX_BA (1 << 0)
+} __packed;
+
+/* RT2870 RX descriptor */
+struct rt2870_rxd {
+ /* single 32-bit field */
+ uint32_t flags;
+} __packed;
+
+/* RX Wireless Information */
+struct rt2860_rxwi {
+ uint8_t wcid;
+ uint8_t keyidx;
+#define RT2860_RX_UDF_SHIFT 5
+#define RT2860_RX_BSS_IDX_SHIFT 2
+
+ uint16_t len;
+#define RT2860_RX_TID_SHIFT 12
+
+ uint16_t seq;
+ uint16_t phy;
+ uint8_t rssi[3];
+ uint8_t reserved1;
+ uint8_t snr[2];
+ uint16_t reserved2;
+} __packed;
+
+
+/* first DMA segment contains TXWI + 802.11 header + 32-bit padding */
+#define RT2860_TXWI_DMASZ \
+ (sizeof (struct rt2860_txwi) + \
+ sizeof (struct ieee80211_htframe) + \
+ sizeof (uint16_t))
+
+#define RT2860_RF1 0
+#define RT2860_RF2 2
+#define RT2860_RF3 1
+#define RT2860_RF4 3
+
+#define RT2860_RF_2820 1 /* 2T3R */
+#define RT2860_RF_2850 2 /* dual-band 2T3R */
+#define RT2860_RF_2720 3 /* 1T2R */
+#define RT2860_RF_2750 4 /* dual-band 1T2R */
+#define RT3070_RF_3020 5 /* 1T1R */
+#define RT3070_RF_2020 6 /* b/g */
+#define RT3070_RF_3021 7 /* 1T2R */
+#define RT3070_RF_3022 8 /* 2T2R */
+#define RT3070_RF_3052 9 /* dual-band 2T2R */
+
+/* USB commands for RT2870 only */
+#define RT2870_RESET 1
+#define RT2870_WRITE_2 2
+#define RT2870_WRITE_REGION_1 6
+#define RT2870_READ_REGION_1 7
+#define RT2870_EEPROM_READ 9
+
+#define RT2860_EEPROM_DELAY 1 /* minimum hold time (microsecond) */
+
+#define RT2860_EEPROM_VERSION 0x01
+#define RT2860_EEPROM_MAC01 0x02
+#define RT2860_EEPROM_MAC23 0x03
+#define RT2860_EEPROM_MAC45 0x04
+#define RT2860_EEPROM_PCIE_PSLEVEL 0x11
+#define RT2860_EEPROM_REV 0x12
+#define RT2860_EEPROM_ANTENNA 0x1a
+#define RT2860_EEPROM_CONFIG 0x1b
+#define RT2860_EEPROM_COUNTRY 0x1c
+#define RT2860_EEPROM_FREQ_LEDS 0x1d
+#define RT2860_EEPROM_LED1 0x1e
+#define RT2860_EEPROM_LED2 0x1f
+#define RT2860_EEPROM_LED3 0x20
+#define RT2860_EEPROM_LNA 0x22
+#define RT2860_EEPROM_RSSI1_2GHZ 0x23
+#define RT2860_EEPROM_RSSI2_2GHZ 0x24
+#define RT2860_EEPROM_RSSI1_5GHZ 0x25
+#define RT2860_EEPROM_RSSI2_5GHZ 0x26
+#define RT2860_EEPROM_DELTAPWR 0x28
+#define RT2860_EEPROM_PWR2GHZ_BASE1 0x29
+#define RT2860_EEPROM_PWR2GHZ_BASE2 0x30
+#define RT2860_EEPROM_TSSI1_2GHZ 0x37
+#define RT2860_EEPROM_TSSI2_2GHZ 0x38
+#define RT2860_EEPROM_TSSI3_2GHZ 0x39
+#define RT2860_EEPROM_TSSI4_2GHZ 0x3a
+#define RT2860_EEPROM_TSSI5_2GHZ 0x3b
+#define RT2860_EEPROM_PWR5GHZ_BASE1 0x3c
+#define RT2860_EEPROM_PWR5GHZ_BASE2 0x53
+#define RT2860_EEPROM_TSSI1_5GHZ 0x6a
+#define RT2860_EEPROM_TSSI2_5GHZ 0x6b
+#define RT2860_EEPROM_TSSI3_5GHZ 0x6c
+#define RT2860_EEPROM_TSSI4_5GHZ 0x6d
+#define RT2860_EEPROM_TSSI5_5GHZ 0x6e
+#define RT2860_EEPROM_RPWR 0x6f
+#define RT2860_EEPROM_BBP_BASE 0x78
+
+#define RT2860_RIDX_CCK1 0
+#define RT2860_RIDX_CCK11 3
+#define RT2860_RIDX_OFDM6 4
+#define RT2860_RIDX_MAX 11
+static const struct rt2860_rate {
+ uint8_t rate;
+ uint8_t mcs;
+ enum ieee80211_phytype phy;
+ uint8_t ctl_ridx;
+ uint16_t sp_ack_dur;
+ uint16_t lp_ack_dur;
+} rt2860_rates[] = {
+ { 2, 0, IEEE80211_T_DS, 0, 304, 304 },
+ { 4, 1, IEEE80211_T_DS, 1, 248, 152 },
+ { 11, 2, IEEE80211_T_DS, 2, 213, 117 },
+ { 22, 3, IEEE80211_T_DS, 3, 203, 107 },
+ { 12, 0, IEEE80211_T_OFDM, 4, 50, 50 },
+ { 18, 1, IEEE80211_T_OFDM, 4, 42, 42 },
+ { 24, 2, IEEE80211_T_OFDM, 6, 38, 38 },
+ { 36, 3, IEEE80211_T_OFDM, 6, 34, 34 },
+ { 48, 4, IEEE80211_T_OFDM, 8, 34, 34 },
+ { 72, 5, IEEE80211_T_OFDM, 8, 30, 30 },
+ { 96, 6, IEEE80211_T_OFDM, 8, 30, 30 },
+ { 108, 7, IEEE80211_T_OFDM, 8, 30, 30 }
+};
+
+/*
+ * Control and status registers access macros.
+ */
+#define RAL_READ(sc, reg) \
+ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
+
+#define RAL_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+
+#define RAL_BARRIER_WRITE(sc) \
+ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, 0x1800, \
+ BUS_SPACE_BARRIER_WRITE)
+
+#define RAL_BARRIER_READ_WRITE(sc) \
+ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, 0x1800, \
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+#define RAL_WRITE_REGION_1(sc, offset, datap, count) \
+ bus_space_write_region_1((sc)->sc_st, (sc)->sc_sh, (offset), \
+ (datap), (count))
+
+#define RAL_SET_REGION_4(sc, offset, val, count) \
+ bus_space_set_region_4((sc)->sc_st, (sc)->sc_sh, (offset), \
+ (val), (count))
+
+/*
+ * EEPROM access macro.
+ */
+#define RT2860_EEPROM_CTL(sc, val) do { \
+ RAL_WRITE((sc), RT2860_PCI_EECTRL, (val)); \
+ RAL_BARRIER_READ_WRITE((sc)); \
+ DELAY(RT2860_EEPROM_DELAY); \
+} while (/* CONSTCOND */0)
+
+/*
+ * Default values for MAC registers; values taken from the reference driver.
+ */
+#define RT2860_DEF_MAC \
+ { RT2860_BCN_OFFSET0, 0xf8f0e8e0 }, \
+ { RT2860_LEGACY_BASIC_RATE, 0x0000013f }, \
+ { RT2860_HT_BASIC_RATE, 0x00008003 }, \
+ { RT2860_MAC_SYS_CTRL, 0x00000000 }, \
+ { RT2860_BKOFF_SLOT_CFG, 0x00000209 }, \
+ { RT2860_TX_SW_CFG0, 0x00000000 }, \
+ { RT2860_TX_SW_CFG1, 0x00080606 }, \
+ { RT2860_TX_LINK_CFG, 0x00001020 }, \
+ { RT2860_TX_TIMEOUT_CFG, 0x000a2090 }, \
+ { RT2860_LED_CFG, 0x7f031e46 }, \
+ { RT2860_WMM_AIFSN_CFG, 0x00002273 }, \
+ { RT2860_WMM_CWMIN_CFG, 0x00002344 }, \
+ { RT2860_WMM_CWMAX_CFG, 0x000034aa }, \
+ { RT2860_MAX_PCNT, 0x1f3fbf9f }, \
+ { RT2860_TX_RTY_CFG, 0x47d01f0f }, \
+ { RT2860_AUTO_RSP_CFG, 0x00000013 }, \
+ { RT2860_CCK_PROT_CFG, 0x05740003 }, \
+ { RT2860_OFDM_PROT_CFG, 0x05740003 }, \
+ { RT2860_GF20_PROT_CFG, 0x01744004 }, \
+ { RT2860_GF40_PROT_CFG, 0x03f44084 }, \
+ { RT2860_MM20_PROT_CFG, 0x01744004 }, \
+ { RT2860_MM40_PROT_CFG, 0x03f54084 }, \
+ { RT2860_TXOP_CTRL_CFG, 0x0000583f }, \
+ { RT2860_TXOP_HLDR_ET, 0x00000002 }, \
+ { RT2860_TX_RTS_CFG, 0x00092b20 }, \
+ { RT2860_EXP_ACK_TIME, 0x002400ca }, \
+ { RT2860_XIFS_TIME_CFG, 0x33a41010 }, \
+ { RT2860_PWR_PIN_CFG, 0x00000003 }
+
+/* XXX only a few registers differ from above, try to merge? */
+#define RT2870_DEF_MAC \
+ { RT2860_BCN_OFFSET0, 0xf8f0e8e0 }, \
+ { RT2860_LEGACY_BASIC_RATE, 0x0000013f }, \
+ { RT2860_HT_BASIC_RATE, 0x00008003 }, \
+ { RT2860_MAC_SYS_CTRL, 0x00000000 }, \
+ { RT2860_BKOFF_SLOT_CFG, 0x00000209 }, \
+ { RT2860_TX_SW_CFG0, 0x00000000 }, \
+ { RT2860_TX_SW_CFG1, 0x00080606 }, \
+ { RT2860_TX_LINK_CFG, 0x00001020 }, \
+ { RT2860_TX_TIMEOUT_CFG, 0x000a2090 }, \
+ { RT2860_LED_CFG, 0x7f031e46 }, \
+ { RT2860_WMM_AIFSN_CFG, 0x00002273 }, \
+ { RT2860_WMM_CWMIN_CFG, 0x00002344 }, \
+ { RT2860_WMM_CWMAX_CFG, 0x000034aa }, \
+ { RT2860_MAX_PCNT, 0x1f3fbf9f }, \
+ { RT2860_TX_RTY_CFG, 0x47d01f0f }, \
+ { RT2860_AUTO_RSP_CFG, 0x00000013 }, \
+ { RT2860_CCK_PROT_CFG, 0x05740003 }, \
+ { RT2860_OFDM_PROT_CFG, 0x05740003 }, \
+ { RT2860_PBF_CFG, 0x00f40006 }, \
+ { RT2860_WPDMA_GLO_CFG, 0x00000030 }, \
+ { RT2860_GF20_PROT_CFG, 0x01744004 }, \
+ { RT2860_GF40_PROT_CFG, 0x03f44084 }, \
+ { RT2860_MM20_PROT_CFG, 0x01744004 }, \
+ { RT2860_MM40_PROT_CFG, 0x03f44084 }, \
+ { RT2860_TXOP_CTRL_CFG, 0x0000583f }, \
+ { RT2860_TXOP_HLDR_ET, 0x00000002 }, \
+ { RT2860_TX_RTS_CFG, 0x00092b20 }, \
+ { RT2860_EXP_ACK_TIME, 0x002400ca }, \
+ { RT2860_XIFS_TIME_CFG, 0x33a41010 }, \
+ { RT2860_PWR_PIN_CFG, 0x00000003 }
+
+/*
+ * Default values for BBP registers; values taken from the reference driver.
+ */
+#define RT2860_DEF_BBP \
+ { 65, 0x2c }, \
+ { 66, 0x38 }, \
+ { 69, 0x12 }, \
+ { 70, 0x0a }, \
+ { 73, 0x10 }, \
+ { 81, 0x37 }, \
+ { 82, 0x62 }, \
+ { 83, 0x6a }, \
+ { 84, 0x99 }, \
+ { 86, 0x00 }, \
+ { 91, 0x04 }, \
+ { 92, 0x00 }, \
+ { 103, 0x00 }, \
+ { 105, 0x05 }
+
+/*
+ * Default settings for RF registers; values derived from the reference driver.
+ */
+#define RT2860_RF2850 \
+ { 1, 0x100bb3, 0x1301e1, 0x05a014, 0x001402 }, \
+ { 2, 0x100bb3, 0x1301e1, 0x05a014, 0x001407 }, \
+ { 3, 0x100bb3, 0x1301e2, 0x05a014, 0x001402 }, \
+ { 4, 0x100bb3, 0x1301e2, 0x05a014, 0x001407 }, \
+ { 5, 0x100bb3, 0x1301e3, 0x05a014, 0x001402 }, \
+ { 6, 0x100bb3, 0x1301e3, 0x05a014, 0x001407 }, \
+ { 7, 0x100bb3, 0x1301e4, 0x05a014, 0x001402 }, \
+ { 8, 0x100bb3, 0x1301e4, 0x05a014, 0x001407 }, \
+ { 9, 0x100bb3, 0x1301e5, 0x05a014, 0x001402 }, \
+ { 10, 0x100bb3, 0x1301e5, 0x05a014, 0x001407 }, \
+ { 11, 0x100bb3, 0x1301e6, 0x05a014, 0x001402 }, \
+ { 12, 0x100bb3, 0x1301e6, 0x05a014, 0x001407 }, \
+ { 13, 0x100bb3, 0x1301e7, 0x05a014, 0x001402 }, \
+ { 14, 0x100bb3, 0x1301e8, 0x05a014, 0x001404 }, \
+ { 36, 0x100bb3, 0x130266, 0x056014, 0x001408 }, \
+ { 38, 0x100bb3, 0x130267, 0x056014, 0x001404 }, \
+ { 40, 0x100bb2, 0x1301a0, 0x056014, 0x001400 }, \
+ { 44, 0x100bb2, 0x1301a0, 0x056014, 0x001408 }, \
+ { 46, 0x100bb2, 0x1301a1, 0x056014, 0x001402 }, \
+ { 48, 0x100bb2, 0x1301a1, 0x056014, 0x001406 }, \
+ { 52, 0x100bb2, 0x1301a2, 0x056014, 0x001404 }, \
+ { 54, 0x100bb2, 0x1301a2, 0x056014, 0x001408 }, \
+ { 56, 0x100bb2, 0x1301a3, 0x056014, 0x001402 }, \
+ { 60, 0x100bb2, 0x1301a4, 0x056014, 0x001400 }, \
+ { 62, 0x100bb2, 0x1301a4, 0x056014, 0x001404 }, \
+ { 64, 0x100bb2, 0x1301a4, 0x056014, 0x001408 }, \
+ { 100, 0x100bb2, 0x1301ac, 0x05e014, 0x001400 }, \
+ { 102, 0x100bb2, 0x1701ac, 0x15e014, 0x001404 }, \
+ { 104, 0x100bb2, 0x1701ac, 0x15e014, 0x001408 }, \
+ { 108, 0x100bb3, 0x17028c, 0x15e014, 0x001404 }, \
+ { 110, 0x100bb3, 0x13028d, 0x05e014, 0x001400 }, \
+ { 112, 0x100bb3, 0x13028d, 0x05e014, 0x001406 }, \
+ { 116, 0x100bb3, 0x13028e, 0x05e014, 0x001408 }, \
+ { 118, 0x100bb3, 0x13028f, 0x05e014, 0x001404 }, \
+ { 120, 0x100bb1, 0x1300e0, 0x05e014, 0x001400 }, \
+ { 124, 0x100bb1, 0x1300e0, 0x05e014, 0x001404 }, \
+ { 126, 0x100bb1, 0x1300e0, 0x05e014, 0x001406 }, \
+ { 128, 0x100bb1, 0x1300e0, 0x05e014, 0x001408 }, \
+ { 132, 0x100bb1, 0x1300e1, 0x05e014, 0x001402 }, \
+ { 134, 0x100bb1, 0x1300e1, 0x05e014, 0x001404 }, \
+ { 136, 0x100bb1, 0x1300e1, 0x05e014, 0x001406 }, \
+ { 140, 0x100bb1, 0x1300e2, 0x05e014, 0x001400 }, \
+ { 149, 0x100bb1, 0x1300e2, 0x05e014, 0x001409 }, \
+ { 151, 0x100bb1, 0x1300e3, 0x05e014, 0x001401 }, \
+ { 153, 0x100bb1, 0x1300e3, 0x05e014, 0x001403 }, \
+ { 157, 0x100bb1, 0x1300e3, 0x05e014, 0x001407 }, \
+ { 159, 0x100bb1, 0x1300e3, 0x05e014, 0x001409 }, \
+ { 161, 0x100bb1, 0x1300e4, 0x05e014, 0x001401 }, \
+ { 165, 0x100bb1, 0x1300e4, 0x05e014, 0x001405 }
+
+#define RT3070_RF3020 \
+ { 241, 2, 2 }, \
+ { 241, 2, 7 }, \
+ { 242, 2, 2 }, \
+ { 242, 2, 7 }, \
+ { 243, 2, 2 }, \
+ { 243, 2, 7 }, \
+ { 244, 2, 2 }, \
+ { 244, 2, 7 }, \
+ { 245, 2, 2 }, \
+ { 245, 2, 7 }, \
+ { 246, 2, 2 }, \
+ { 246, 2, 7 }, \
+ { 247, 2, 2 }, \
+ { 248, 2, 4 }
+
+#define RT3070_DEF_RF \
+ { 4, 0x40 }, \
+ { 5, 0x03 }, \
+ { 6, 0x02 }, \
+ { 7, 0x70 }, \
+ { 9, 0x0f }, \
+ { 10, 0x41 }, \
+ { 11, 0x21 }, \
+ { 12, 0x7b }, \
+ { 14, 0x90 }, \
+ { 15, 0x58 }, \
+ { 16, 0xb3 }, \
+ { 17, 0x92 }, \
+ { 18, 0x2c }, \
+ { 19, 0x02 }, \
+ { 20, 0xba }, \
+ { 21, 0xdb }, \
+ { 24, 0x16 }, \
+ { 25, 0x01 }, \
+ { 29, 0x1f }
+
+#endif /* _IF_RUNREG_H_ */
diff --git a/sys/dev/usb/wlan/if_runvar.h b/sys/dev/usb/wlan/if_runvar.h
new file mode 100644
index 0000000..a8795a9
--- /dev/null
+++ b/sys/dev/usb/wlan/if_runvar.h
@@ -0,0 +1,222 @@
+/* $OpenBSD: if_runvar.h,v 1.3 2009/03/26 20:17:27 damien Exp $ */
+
+/*-
+ * Copyright (c) 2008,2009 Damien Bergamini <damien.bergamini@free.fr>
+ * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_RUNVAR_H_
+#define _IF_RUNVAR_H_
+
+#define RUN_MAX_RXSZ \
+ MIN(4096, MJUMPAGESIZE)
+#if 0
+ (sizeof (uint32_t) + \
+ sizeof (struct rt2860_rxwi) + \
+ sizeof (uint16_t) + \
+ MCLBYTES + \
+ sizeof (struct rt2870_rxd))
+#endif
+/* NB: "11" is the maximum number of padding bytes needed for Tx */
+#define RUN_MAX_TXSZ \
+ (sizeof (struct rt2870_txd) + \
+ sizeof (struct rt2860_rxwi) + \
+ MCLBYTES + 11)
+
+#define RUN_TX_TIMEOUT 5000 /* ms */
+
+/* Tx ring count was 8/endpoint, now 32 for all 4 (or 6) endpoints. */
+#define RUN_TX_RING_COUNT 32
+#define RUN_RX_RING_COUNT 1
+
+#define RT2870_WCID_MAX 253
+#define RUN_AID2WCID(aid) ((aid) & 0xff)
+
+struct run_rx_radiotap_header {
+ struct ieee80211_radiotap_header wr_ihdr;
+ uint8_t wr_flags;
+ uint8_t wr_rate;
+ uint16_t wr_chan_freq;
+ uint16_t wr_chan_flags;
+ uint8_t wr_dbm_antsignal;
+ uint8_t wr_antenna;
+ uint8_t wr_antsignal;
+} __packed;
+
+#define RUN_RX_RADIOTAP_PRESENT \
+ (1 << IEEE80211_RADIOTAP_FLAGS | \
+ 1 << IEEE80211_RADIOTAP_RATE | \
+ 1 << IEEE80211_RADIOTAP_CHANNEL | \
+ 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL | \
+ 1 << IEEE80211_RADIOTAP_ANTENNA | \
+ 1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)
+
+struct run_tx_radiotap_header {
+ struct ieee80211_radiotap_header wt_ihdr;
+ uint8_t wt_flags;
+ uint8_t wt_rate;
+ uint16_t wt_chan_freq;
+ uint16_t wt_chan_flags;
+ uint8_t wt_hwqueue;
+} __packed;
+
+#define IEEE80211_RADIOTAP_HWQUEUE 15
+
+#define RUN_TX_RADIOTAP_PRESENT \
+ (1 << IEEE80211_RADIOTAP_FLAGS | \
+ 1 << IEEE80211_RADIOTAP_RATE | \
+ 1 << IEEE80211_RADIOTAP_CHANNEL | \
+ 1 << IEEE80211_RADIOTAP_HWQUEUE)
+
+struct run_softc;
+
+struct run_tx_data {
+ STAILQ_ENTRY(run_tx_data) next;
+ struct run_softc *sc;
+ struct mbuf *m;
+ struct ieee80211_node *ni;
+ uint32_t align[0]; /* dummy field */
+ uint8_t desc[sizeof(struct rt2870_txd) +
+ sizeof(struct rt2860_txwi)];
+ int ridx;
+ uint8_t mcs;
+};
+STAILQ_HEAD(run_tx_data_head, run_tx_data);
+
+struct run_node {
+ struct ieee80211_node ni;
+ uint8_t ridx[IEEE80211_RATE_MAXSIZE];
+ uint8_t ctl_ridx[IEEE80211_RATE_MAXSIZE];
+};
+
+struct run_vap {
+ struct ieee80211vap vap;
+ struct ieee80211_beacon_offsets bo;
+ struct ieee80211_amrr amrr;
+ struct ieee80211_amrr_node amn[RT2870_WCID_MAX + 1];
+ struct usb_callout amrr_ch;
+ struct task amrr_task;
+ uint8_t amrr_run;
+#define RUN_AMRR_ON 1
+#define RUN_AMRR_OFF 0
+
+ int (*newstate)(struct ieee80211vap *,
+ enum ieee80211_state, int);
+};
+#define RUN_VAP(vap) ((struct run_vap *)(vap))
+
+/*
+ * There are 7 bulk endpoints: 1 for RX
+ * and 6 for TX (4 EDCAs + HCCA + Prio).
+ * Update 03-14-2009: some devices like the Planex GW-US300MiniS
+ * seem to have only 4 TX bulk endpoints (Fukaumi Naoki).
+ */
+enum {
+ RUN_BULK_TX_BE, /* = WME_AC_BE */
+ RUN_BULK_TX_BK, /* = WME_AC_BK */
+ RUN_BULK_TX_VI, /* = WME_AC_VI */
+ RUN_BULK_TX_VO, /* = WME_AC_VO */
+ RUN_BULK_TX_HCCA,
+ RUN_BULK_TX_PRIO,
+ RUN_BULK_RX,
+ RUN_N_XFER,
+};
+
+#define RUN_EP_QUEUES RUN_BULK_RX
+
+struct run_endpoint_queue {
+ struct run_tx_data tx_data[RUN_TX_RING_COUNT];
+ struct run_tx_data_head tx_qh;
+ struct run_tx_data_head tx_fh;
+ uint32_t tx_nfree;
+};
+
+struct run_softc {
+ device_t sc_dev;
+ struct usb_device *sc_udev;
+ struct ifnet *sc_ifp;
+ struct run_vap *sc_rvp;
+
+ int (*sc_srom_read)(struct run_softc *,
+ uint16_t, uint16_t *);
+
+ const struct firmware *fwp;
+
+ uint32_t mac_rev;
+ uint8_t rf_rev;
+ uint8_t freq;
+ uint8_t ntxchains;
+ uint8_t nrxchains;
+ int fixed_ridx;
+
+ uint8_t rf24_20mhz;
+ uint8_t rf24_40mhz;
+ uint8_t ext_2ghz_lna;
+ uint8_t ext_5ghz_lna;
+ uint8_t calib_2ghz;
+ uint8_t calib_5ghz;
+ int8_t txpow1[50];
+ int8_t txpow2[50];
+ int8_t rssi_2ghz[3];
+ int8_t rssi_5ghz[3];
+ uint8_t lna[4];
+
+ struct {
+ uint8_t reg;
+ uint8_t val;
+ } bbp[8];
+ uint8_t leds;
+ uint16_t led[3];
+ uint32_t txpow20mhz[5];
+ uint32_t txpow40mhz_2ghz[5];
+ uint32_t txpow40mhz_5ghz[5];
+
+ uint8_t sc_bssid[6];
+
+ struct mtx sc_mtx;
+
+ struct run_endpoint_queue sc_epq[RUN_EP_QUEUES];
+
+ struct task wme_task;
+ struct task usb_timeout_task;
+
+ struct usb_xfer *sc_xfer[RUN_N_XFER];
+
+ struct mbuf *rx_m;
+
+ int sifs;
+
+ union {
+ struct run_rx_radiotap_header th;
+ uint8_t pad[64];
+ } sc_rxtapu;
+#define sc_rxtap sc_rxtapu.th
+ int sc_rxtap_len;
+
+ union {
+ struct run_tx_radiotap_header th;
+ uint8_t pad[64];
+ } sc_txtapu;
+#define sc_txtap sc_txtapu.th
+ int sc_txtap_len;
+};
+
+#define RUN_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define RUN_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define RUN_LOCK_ASSERT(sc, t) mtx_assert(&(sc)->sc_mtx, t)
+
+#endif /* _IF_RUNVAR_H_ */
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index cad745d..aebdcea 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -238,6 +238,7 @@ SUBDIR= ${_3dfx} \
re \
reiserfs \
rl \
+ runfw \
${_s3} \
${_safe} \
${_sbni} \
diff --git a/sys/modules/runfw/Makefile b/sys/modules/runfw/Makefile
new file mode 100644
index 0000000..ded0408
--- /dev/null
+++ b/sys/modules/runfw/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../contrib/dev/run
+
+KMOD= runfw
+FIRMWS= run-rt2870:runfw:1
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/usb/Makefile b/sys/modules/usb/Makefile
index 09ad669..7f43e2b 100644
--- a/sys/modules/usb/Makefile
+++ b/sys/modules/usb/Makefile
@@ -27,7 +27,7 @@
SUBDIR = usb
SUBDIR += ehci musb ohci uhci uss820dci ${_at91dci} ${_atmegadci}
-SUBDIR += rum uath upgt ural zyd ${_urtw}
+SUBDIR += rum run uath upgt ural zyd ${_urtw}
SUBDIR += atp uhid ukbd ums udbp ufm
SUBDIR += ucom u3g uark ubsa ubser uchcom ucycom ufoma uftdi ugensa uipaq ulpt \
umct umodem umoscom uplcom uslcom uvisor uvscom
diff --git a/sys/modules/usb/run/Makefile b/sys/modules/usb/run/Makefile
new file mode 100644
index 0000000..5acada4
--- /dev/null
+++ b/sys/modules/usb/run/Makefile
@@ -0,0 +1,36 @@
+#
+# $FreeBSD$
+#
+# Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+S= ${.CURDIR}/../../..
+
+.PATH: $S/dev/usb/wlan
+
+KMOD= if_run
+SRCS= opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h usbdevs.h \
+ if_run.c
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud