2009-04-26 15:47:48 +02:00
/*
2009-11-08 16:39:55 +01:00
Copyright ( C ) 2009 Ivo van Doorn < IvDoorn @ gmail . com >
Copyright ( C ) 2009 Mattias Nissler < mattias . nissler @ gmx . de >
Copyright ( C ) 2009 Felix Fietkau < nbd @ openwrt . org >
Copyright ( C ) 2009 Xose Vazquez Perez < xose . vazquez @ gmail . com >
Copyright ( C ) 2009 Axel Kollhofer < rain_maker @ root - forum . org >
2009-04-26 15:47:48 +02:00
< http : //rt2x00.serialmonkey.com>
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the
Free Software Foundation , Inc . ,
59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
/*
Module : rt2800usb
Abstract : rt2800usb device specific routines .
Supported chipsets : RT2800U .
*/
# include <linux/crc-ccitt.h>
# include <linux/delay.h>
# include <linux/etherdevice.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/usb.h>
# include "rt2x00.h"
# include "rt2x00usb.h"
2009-11-04 18:35:32 +01:00
# include "rt2800lib.h"
2009-11-04 18:35:54 +01:00
# include "rt2800.h"
2009-04-26 15:47:48 +02:00
# include "rt2800usb.h"
/*
* Allow hardware encryption to be disabled .
*/
static int modparam_nohwcrypt = 1 ;
module_param_named ( nohwcrypt , modparam_nohwcrypt , bool , S_IRUGO ) ;
MODULE_PARM_DESC ( nohwcrypt , " Disable hardware encryption. " ) ;
/*
* Firmware functions
*/
static char * rt2800usb_get_firmware_name ( struct rt2x00_dev * rt2x00dev )
{
return FIRMWARE_RT2870 ;
}
static bool rt2800usb_check_crc ( const u8 * data , const size_t len )
{
u16 fw_crc ;
u16 crc ;
/*
* The last 2 bytes in the firmware array are the crc checksum itself ,
* this means that we should never pass those 2 bytes to the crc
* algorithm .
*/
fw_crc = ( data [ len - 2 ] < < 8 | data [ len - 1 ] ) ;
/*
* Use the crc ccitt algorithm .
* This will return the same value as the legacy driver which
* used bit ordering reversion on the both the firmware bytes
* before input input as well as on the final output .
* Obviously using crc ccitt directly is much more efficient .
*/
crc = crc_ccitt ( ~ 0 , data , len - 2 ) ;
/*
* There is a small difference between the crc - itu - t + bitrev and
* the crc - ccitt crc calculation . In the latter method the 2 bytes
* will be swapped , use swab16 to convert the crc to the correct
* value .
*/
crc = swab16 ( crc ) ;
return fw_crc = = crc ;
}
static int rt2800usb_check_firmware ( struct rt2x00_dev * rt2x00dev ,
const u8 * data , const size_t len )
{
u16 chipset = ( rt2x00_rev ( & rt2x00dev - > chip ) > > 16 ) & 0xffff ;
size_t offset = 0 ;
/*
* Firmware files :
* There are 2 variations of the rt2870 firmware .
* a ) size : 4 kb
* b ) size : 8 kb
* Note that ( b ) contains 2 seperate firmware blobs of 4 k
* within the file . The first blob is the same firmware as ( a ) ,
* but the second blob is for the additional chipsets .
*/
if ( len ! = 4096 & & len ! = 8192 )
return FW_BAD_LENGTH ;
/*
* Check if we need the upper 4 kb firmware data or not .
*/
if ( ( len = = 4096 ) & &
( chipset ! = 0x2860 ) & &
( chipset ! = 0x2872 ) & &
( chipset ! = 0x3070 ) )
return FW_BAD_VERSION ;
/*
* 8 kb firmware files must be checked as if it were
* 2 seperate firmware files .
*/
while ( offset < len ) {
if ( ! rt2800usb_check_crc ( data + offset , 4096 ) )
return FW_BAD_CRC ;
offset + = 4096 ;
}
return FW_OK ;
}
static int rt2800usb_load_firmware ( struct rt2x00_dev * rt2x00dev ,
const u8 * data , const size_t len )
{
unsigned int i ;
int status ;
u32 reg ;
u32 offset ;
u32 length ;
u16 chipset = ( rt2x00_rev ( & rt2x00dev - > chip ) > > 16 ) & 0xffff ;
/*
* Check which section of the firmware we need .
*/
2009-04-28 20:14:58 +02:00
if ( ( chipset = = 0x2860 ) | |
( chipset = = 0x2872 ) | |
( chipset = = 0x3070 ) ) {
2009-04-26 15:47:48 +02:00
offset = 0 ;
length = 4096 ;
} else {
offset = 4096 ;
length = 4096 ;
}
/*
* Wait for stable hardware .
*/
for ( i = 0 ; i < REGISTER_BUSY_COUNT ; i + + ) {
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , MAC_CSR0 , & reg ) ;
2009-04-26 15:47:48 +02:00
if ( reg & & reg ! = ~ 0 )
break ;
msleep ( 1 ) ;
}
if ( i = = REGISTER_BUSY_COUNT ) {
ERROR ( rt2x00dev , " Unstable hardware. \n " ) ;
return - EBUSY ;
}
/*
* Write firmware to device .
*/
rt2x00usb_vendor_request_large_buff ( rt2x00dev , USB_MULTI_WRITE ,
USB_VENDOR_REQUEST_OUT ,
FIRMWARE_IMAGE_BASE ,
data + offset , length ,
REGISTER_TIMEOUT32 ( length ) ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , H2M_MAILBOX_CID , ~ 0 ) ;
rt2800_register_write ( rt2x00dev , H2M_MAILBOX_STATUS , ~ 0 ) ;
2009-04-26 15:47:48 +02:00
/*
* Send firmware request to device to load firmware ,
* we need to specify a long timeout time .
*/
status = rt2x00usb_vendor_request_sw ( rt2x00dev , USB_DEVICE_MODE ,
0 , USB_MODE_FIRMWARE ,
REGISTER_TIMEOUT_FIRMWARE ) ;
if ( status < 0 ) {
ERROR ( rt2x00dev , " Failed to write Firmware to device. \n " ) ;
return status ;
}
2009-04-28 20:14:58 +02:00
msleep ( 10 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , H2M_MAILBOX_CSR , 0 ) ;
2009-04-28 20:14:58 +02:00
/*
* Send signal to firmware during boot time .
*/
2009-11-04 18:34:32 +01:00
rt2800_mcu_request ( rt2x00dev , MCU_BOOT_SIGNAL , 0xff , 0 , 0 ) ;
2009-04-28 20:14:58 +02:00
if ( ( chipset = = 0x3070 ) | |
( chipset = = 0x3071 ) | |
( chipset = = 0x3572 ) ) {
udelay ( 200 ) ;
2009-11-04 18:34:32 +01:00
rt2800_mcu_request ( rt2x00dev , MCU_CURRENT , 0 , 0 , 0 ) ;
2009-04-28 20:14:58 +02:00
udelay ( 10 ) ;
}
2009-04-26 15:47:48 +02:00
/*
* Wait for device to stabilize .
*/
for ( i = 0 ; i < REGISTER_BUSY_COUNT ; i + + ) {
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , PBF_SYS_CTRL , & reg ) ;
2009-04-26 15:47:48 +02:00
if ( rt2x00_get_field32 ( reg , PBF_SYS_CTRL_READY ) )
break ;
msleep ( 1 ) ;
}
if ( i = = REGISTER_BUSY_COUNT ) {
ERROR ( rt2x00dev , " PBF system register not ready. \n " ) ;
return - EBUSY ;
}
/*
* Initialize firmware .
*/
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , H2M_BBP_AGENT , 0 ) ;
rt2800_register_write ( rt2x00dev , H2M_MAILBOX_CSR , 0 ) ;
2009-04-26 15:47:48 +02:00
msleep ( 1 ) ;
return 0 ;
}
/*
* Device state switch handlers .
*/
static void rt2800usb_toggle_rx ( struct rt2x00_dev * rt2x00dev ,
enum dev_state state )
{
u32 reg ;
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , MAC_SYS_CTRL , & reg ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , MAC_SYS_CTRL_ENABLE_RX ,
( state = = STATE_RADIO_RX_ON ) | |
( state = = STATE_RADIO_RX_ON_LINK ) ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , MAC_SYS_CTRL , reg ) ;
2009-04-26 15:47:48 +02:00
}
static int rt2800usb_wait_wpdma_ready ( struct rt2x00_dev * rt2x00dev )
{
unsigned int i ;
u32 reg ;
for ( i = 0 ; i < REGISTER_BUSY_COUNT ; i + + ) {
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , WPDMA_GLO_CFG , & reg ) ;
2009-04-26 15:47:48 +02:00
if ( ! rt2x00_get_field32 ( reg , WPDMA_GLO_CFG_TX_DMA_BUSY ) & &
! rt2x00_get_field32 ( reg , WPDMA_GLO_CFG_RX_DMA_BUSY ) )
return 0 ;
msleep ( 1 ) ;
}
ERROR ( rt2x00dev , " WPDMA TX/RX busy, aborting. \n " ) ;
return - EACCES ;
}
static int rt2800usb_enable_radio ( struct rt2x00_dev * rt2x00dev )
{
u32 reg ;
u16 word ;
/*
* Initialize all registers .
*/
if ( unlikely ( rt2800usb_wait_wpdma_ready ( rt2x00dev ) | |
2009-11-04 18:36:57 +01:00
rt2800_init_registers ( rt2x00dev ) | |
rt2800_init_bbp ( rt2x00dev ) | |
rt2800_init_rfcsr ( rt2x00dev ) ) )
2009-04-26 15:47:48 +02:00
return - EIO ;
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , MAC_SYS_CTRL , & reg ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , MAC_SYS_CTRL_ENABLE_TX , 1 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , MAC_SYS_CTRL , reg ) ;
2009-04-26 15:47:48 +02:00
udelay ( 50 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , WPDMA_GLO_CFG , & reg ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , WPDMA_GLO_CFG_TX_WRITEBACK_DONE , 1 ) ;
rt2x00_set_field32 ( & reg , WPDMA_GLO_CFG_ENABLE_RX_DMA , 1 ) ;
rt2x00_set_field32 ( & reg , WPDMA_GLO_CFG_ENABLE_TX_DMA , 1 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , WPDMA_GLO_CFG , reg ) ;
2009-04-26 15:47:48 +02:00
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , USB_DMA_CFG , & reg ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , USB_DMA_CFG_PHY_CLEAR , 0 ) ;
/* Don't use bulk in aggregation when working with USB 1.1 */
rt2x00_set_field32 ( & reg , USB_DMA_CFG_RX_BULK_AGG_EN ,
( rt2x00dev - > rx - > usb_maxpacket = = 512 ) ) ;
rt2x00_set_field32 ( & reg , USB_DMA_CFG_RX_BULK_AGG_TIMEOUT , 128 ) ;
2009-04-28 20:14:58 +02:00
/*
* Total room for RX frames in kilobytes , PBF might still exceed
* this limit so reduce the number to prevent errors .
*/
rt2x00_set_field32 ( & reg , USB_DMA_CFG_RX_BULK_AGG_LIMIT ,
( ( RX_ENTRIES * DATA_FRAME_SIZE ) / 1024 ) - 3 ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , USB_DMA_CFG_RX_BULK_EN , 1 ) ;
rt2x00_set_field32 ( & reg , USB_DMA_CFG_TX_BULK_EN , 1 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , USB_DMA_CFG , reg ) ;
2009-04-26 15:47:48 +02:00
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , MAC_SYS_CTRL , & reg ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , MAC_SYS_CTRL_ENABLE_TX , 1 ) ;
rt2x00_set_field32 ( & reg , MAC_SYS_CTRL_ENABLE_RX , 1 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , MAC_SYS_CTRL , reg ) ;
2009-04-26 15:47:48 +02:00
/*
* Initialize LED control
*/
rt2x00_eeprom_read ( rt2x00dev , EEPROM_LED1 , & word ) ;
2009-11-04 18:34:32 +01:00
rt2800_mcu_request ( rt2x00dev , MCU_LED_1 , 0xff ,
2009-04-26 15:47:48 +02:00
word & 0xff , ( word > > 8 ) & 0xff ) ;
rt2x00_eeprom_read ( rt2x00dev , EEPROM_LED2 , & word ) ;
2009-11-04 18:34:32 +01:00
rt2800_mcu_request ( rt2x00dev , MCU_LED_2 , 0xff ,
2009-04-26 15:47:48 +02:00
word & 0xff , ( word > > 8 ) & 0xff ) ;
rt2x00_eeprom_read ( rt2x00dev , EEPROM_LED3 , & word ) ;
2009-11-04 18:34:32 +01:00
rt2800_mcu_request ( rt2x00dev , MCU_LED_3 , 0xff ,
2009-04-26 15:47:48 +02:00
word & 0xff , ( word > > 8 ) & 0xff ) ;
return 0 ;
}
static void rt2800usb_disable_radio ( struct rt2x00_dev * rt2x00dev )
{
u32 reg ;
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , WPDMA_GLO_CFG , & reg ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , WPDMA_GLO_CFG_ENABLE_TX_DMA , 0 ) ;
rt2x00_set_field32 ( & reg , WPDMA_GLO_CFG_ENABLE_RX_DMA , 0 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , WPDMA_GLO_CFG , reg ) ;
2009-04-26 15:47:48 +02:00
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , MAC_SYS_CTRL , 0 ) ;
rt2800_register_write ( rt2x00dev , PWR_PIN_CFG , 0 ) ;
rt2800_register_write ( rt2x00dev , TX_PIN_CFG , 0 ) ;
2009-04-26 15:47:48 +02:00
/* Wait for DMA, ignore error */
rt2800usb_wait_wpdma_ready ( rt2x00dev ) ;
rt2x00usb_disable_radio ( rt2x00dev ) ;
}
static int rt2800usb_set_state ( struct rt2x00_dev * rt2x00dev ,
enum dev_state state )
{
if ( state = = STATE_AWAKE )
2009-11-04 18:34:32 +01:00
rt2800_mcu_request ( rt2x00dev , MCU_WAKEUP , 0xff , 0 , 0 ) ;
2009-04-26 15:47:48 +02:00
else
2009-11-04 18:34:32 +01:00
rt2800_mcu_request ( rt2x00dev , MCU_SLEEP , 0xff , 0 , 2 ) ;
2009-04-26 15:47:48 +02:00
return 0 ;
}
static int rt2800usb_set_device_state ( struct rt2x00_dev * rt2x00dev ,
enum dev_state state )
{
int retval = 0 ;
switch ( state ) {
case STATE_RADIO_ON :
/*
* Before the radio can be enabled , the device first has
* to be woken up . After that it needs a bit of time
2009-07-17 21:39:19 +02:00
* to be fully awake and then the radio can be enabled .
2009-04-26 15:47:48 +02:00
*/
rt2800usb_set_state ( rt2x00dev , STATE_AWAKE ) ;
msleep ( 1 ) ;
retval = rt2800usb_enable_radio ( rt2x00dev ) ;
break ;
case STATE_RADIO_OFF :
/*
2009-07-17 21:39:19 +02:00
* After the radio has been disabled , the device should
2009-04-26 15:47:48 +02:00
* be put to sleep for powersaving .
*/
rt2800usb_disable_radio ( rt2x00dev ) ;
rt2800usb_set_state ( rt2x00dev , STATE_SLEEP ) ;
break ;
case STATE_RADIO_RX_ON :
case STATE_RADIO_RX_ON_LINK :
case STATE_RADIO_RX_OFF :
case STATE_RADIO_RX_OFF_LINK :
rt2800usb_toggle_rx ( rt2x00dev , state ) ;
break ;
case STATE_RADIO_IRQ_ON :
case STATE_RADIO_IRQ_OFF :
/* No support, but no error either */
break ;
case STATE_DEEP_SLEEP :
case STATE_SLEEP :
case STATE_STANDBY :
case STATE_AWAKE :
retval = rt2800usb_set_state ( rt2x00dev , state ) ;
break ;
default :
retval = - ENOTSUPP ;
break ;
}
if ( unlikely ( retval ) )
ERROR ( rt2x00dev , " Device failed to enter state %d (%d). \n " ,
state , retval ) ;
return retval ;
}
/*
* TX descriptor initialization
*/
static void rt2800usb_write_tx_desc ( struct rt2x00_dev * rt2x00dev ,
struct sk_buff * skb ,
struct txentry_desc * txdesc )
{
struct skb_frame_desc * skbdesc = get_skb_frame_desc ( skb ) ;
__le32 * txi = skbdesc - > desc ;
__le32 * txwi = & txi [ TXINFO_DESC_SIZE / sizeof ( __le32 ) ] ;
u32 word ;
/*
* Initialize TX Info descriptor
*/
rt2x00_desc_read ( txwi , 0 , & word ) ;
rt2x00_set_field32 ( & word , TXWI_W0_FRAG ,
test_bit ( ENTRY_TXD_MORE_FRAG , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXWI_W0_MIMO_PS , 0 ) ;
rt2x00_set_field32 ( & word , TXWI_W0_CF_ACK , 0 ) ;
rt2x00_set_field32 ( & word , TXWI_W0_TS ,
test_bit ( ENTRY_TXD_REQ_TIMESTAMP , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXWI_W0_AMPDU ,
test_bit ( ENTRY_TXD_HT_AMPDU , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXWI_W0_MPDU_DENSITY , txdesc - > mpdu_density ) ;
rt2x00_set_field32 ( & word , TXWI_W0_TX_OP , txdesc - > ifs ) ;
rt2x00_set_field32 ( & word , TXWI_W0_MCS , txdesc - > mcs ) ;
rt2x00_set_field32 ( & word , TXWI_W0_BW ,
test_bit ( ENTRY_TXD_HT_BW_40 , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXWI_W0_SHORT_GI ,
test_bit ( ENTRY_TXD_HT_SHORT_GI , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXWI_W0_STBC , txdesc - > stbc ) ;
rt2x00_set_field32 ( & word , TXWI_W0_PHYMODE , txdesc - > rate_mode ) ;
rt2x00_desc_write ( txwi , 0 , word ) ;
rt2x00_desc_read ( txwi , 1 , & word ) ;
rt2x00_set_field32 ( & word , TXWI_W1_ACK ,
test_bit ( ENTRY_TXD_ACK , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXWI_W1_NSEQ ,
test_bit ( ENTRY_TXD_GENERATE_SEQ , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXWI_W1_BW_WIN_SIZE , txdesc - > ba_size ) ;
rt2x00_set_field32 ( & word , TXWI_W1_WIRELESS_CLI_ID ,
test_bit ( ENTRY_TXD_ENCRYPT , & txdesc - > flags ) ?
2009-10-15 21:17:09 +02:00
txdesc - > key_idx : 0xff ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & word , TXWI_W1_MPDU_TOTAL_BYTE_COUNT ,
skb - > len - txdesc - > l2pad ) ;
rt2x00_set_field32 ( & word , TXWI_W1_PACKETID ,
2009-08-17 18:55:15 +02:00
skbdesc - > entry - > queue - > qid + 1 ) ;
2009-04-26 15:47:48 +02:00
rt2x00_desc_write ( txwi , 1 , word ) ;
/*
* Always write 0 to IV / EIV fields , hardware will insert the IV
* from the IVEIV register when TXINFO_W0_WIV is set to 0.
* When TXINFO_W0_WIV is set to 1 it will use the IV data
* from the descriptor . The TXWI_W1_WIRELESS_CLI_ID indicates which
* crypto entry in the registers should be used to encrypt the frame .
*/
_rt2x00_desc_write ( txwi , 2 , 0 /* skbdesc->iv[0] */ ) ;
_rt2x00_desc_write ( txwi , 3 , 0 /* skbdesc->iv[1] */ ) ;
/*
* Initialize TX descriptor
*/
rt2x00_desc_read ( txi , 0 , & word ) ;
rt2x00_set_field32 ( & word , TXINFO_W0_USB_DMA_TX_PKT_LEN ,
skb - > len + TXWI_DESC_SIZE ) ;
rt2x00_set_field32 ( & word , TXINFO_W0_WIV ,
! test_bit ( ENTRY_TXD_ENCRYPT_IV , & txdesc - > flags ) ) ;
rt2x00_set_field32 ( & word , TXINFO_W0_QSEL , 2 ) ;
rt2x00_set_field32 ( & word , TXINFO_W0_SW_USE_LAST_ROUND , 0 ) ;
rt2x00_set_field32 ( & word , TXINFO_W0_USB_DMA_NEXT_VALID , 0 ) ;
rt2x00_set_field32 ( & word , TXINFO_W0_USB_DMA_TX_BURST ,
test_bit ( ENTRY_TXD_BURST , & txdesc - > flags ) ) ;
rt2x00_desc_write ( txi , 0 , word ) ;
}
/*
* TX data initialization
*/
static void rt2800usb_write_beacon ( struct queue_entry * entry )
{
struct rt2x00_dev * rt2x00dev = entry - > queue - > rt2x00dev ;
struct skb_frame_desc * skbdesc = get_skb_frame_desc ( entry - > skb ) ;
unsigned int beacon_base ;
u32 reg ;
/*
* Add the descriptor in front of the skb .
*/
skb_push ( entry - > skb , entry - > queue - > desc_size ) ;
memcpy ( entry - > skb - > data , skbdesc - > desc , skbdesc - > desc_len ) ;
skbdesc - > desc = entry - > skb - > data ;
/*
* Disable beaconing while we are reloading the beacon data ,
* otherwise we might be sending out invalid data .
*/
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , BCN_TIME_CFG , & reg ) ;
2009-04-26 15:47:48 +02:00
rt2x00_set_field32 ( & reg , BCN_TIME_CFG_BEACON_GEN , 0 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , BCN_TIME_CFG , reg ) ;
2009-04-26 15:47:48 +02:00
/*
* Write entire beacon with descriptor to register .
*/
beacon_base = HW_BEACON_OFFSET ( entry - > entry_idx ) ;
rt2x00usb_vendor_request_large_buff ( rt2x00dev , USB_MULTI_WRITE ,
USB_VENDOR_REQUEST_OUT , beacon_base ,
entry - > skb - > data , entry - > skb - > len ,
REGISTER_TIMEOUT32 ( entry - > skb - > len ) ) ;
/*
* Clean up the beacon skb .
*/
dev_kfree_skb ( entry - > skb ) ;
entry - > skb = NULL ;
}
static int rt2800usb_get_tx_data_len ( struct queue_entry * entry )
{
int length ;
/*
* The length _must_ include 4 bytes padding ,
* it should always be multiple of 4 ,
* but it must _not_ be a multiple of the USB packet size .
*/
length = roundup ( entry - > skb - > len + 4 , 4 ) ;
length + = ( 4 * ! ( length % entry - > queue - > usb_maxpacket ) ) ;
return length ;
}
static void rt2800usb_kick_tx_queue ( struct rt2x00_dev * rt2x00dev ,
const enum data_queue_qid queue )
{
u32 reg ;
if ( queue ! = QID_BEACON ) {
rt2x00usb_kick_tx_queue ( rt2x00dev , queue ) ;
return ;
}
2009-11-04 18:33:05 +01:00
rt2800_register_read ( rt2x00dev , BCN_TIME_CFG , & reg ) ;
2009-04-26 15:47:48 +02:00
if ( ! rt2x00_get_field32 ( reg , BCN_TIME_CFG_BEACON_GEN ) ) {
rt2x00_set_field32 ( & reg , BCN_TIME_CFG_TSF_TICKING , 1 ) ;
rt2x00_set_field32 ( & reg , BCN_TIME_CFG_TBTT_ENABLE , 1 ) ;
rt2x00_set_field32 ( & reg , BCN_TIME_CFG_BEACON_GEN , 1 ) ;
2009-11-04 18:33:05 +01:00
rt2800_register_write ( rt2x00dev , BCN_TIME_CFG , reg ) ;
2009-04-26 15:47:48 +02:00
}
}
/*
* RX control handlers
*/
static void rt2800usb_fill_rxdone ( struct queue_entry * entry ,
struct rxdone_entry_desc * rxdesc )
{
struct rt2x00_dev * rt2x00dev = entry - > queue - > rt2x00dev ;
struct skb_frame_desc * skbdesc = get_skb_frame_desc ( entry - > skb ) ;
__le32 * rxd = ( __le32 * ) entry - > skb - > data ;
__le32 * rxwi ;
u32 rxd0 ;
u32 rxwi0 ;
u32 rxwi1 ;
u32 rxwi2 ;
u32 rxwi3 ;
/*
* Copy descriptor to the skbdesc - > desc buffer , making it safe from
* moving of frame data in rt2x00usb .
*/
memcpy ( skbdesc - > desc , rxd , skbdesc - > desc_len ) ;
rxd = ( __le32 * ) skbdesc - > desc ;
2009-11-04 18:35:47 +01:00
rxwi = & rxd [ RXINFO_DESC_SIZE / sizeof ( __le32 ) ] ;
2009-04-26 15:47:48 +02:00
/*
* It is now safe to read the descriptor on all architectures .
*/
rt2x00_desc_read ( rxd , 0 , & rxd0 ) ;
rt2x00_desc_read ( rxwi , 0 , & rxwi0 ) ;
rt2x00_desc_read ( rxwi , 1 , & rxwi1 ) ;
rt2x00_desc_read ( rxwi , 2 , & rxwi2 ) ;
rt2x00_desc_read ( rxwi , 3 , & rxwi3 ) ;
2009-11-08 14:39:40 +01:00
if ( rt2x00_get_field32 ( rxd0 , RXINFO_W0_CRC_ERROR ) )
2009-04-26 15:47:48 +02:00
rxdesc - > flags | = RX_FLAG_FAILED_FCS_CRC ;
if ( test_bit ( CONFIG_SUPPORT_HW_CRYPTO , & rt2x00dev - > flags ) ) {
rxdesc - > cipher = rt2x00_get_field32 ( rxwi0 , RXWI_W0_UDF ) ;
rxdesc - > cipher_status =
2009-11-08 14:39:40 +01:00
rt2x00_get_field32 ( rxd0 , RXINFO_W0_CIPHER_ERROR ) ;
2009-04-26 15:47:48 +02:00
}
2009-11-08 14:39:40 +01:00
if ( rt2x00_get_field32 ( rxd0 , RXINFO_W0_DECRYPTED ) ) {
2009-04-26 15:47:48 +02:00
/*
* Hardware has stripped IV / EIV data from 802.11 frame during
* decryption . Unfortunately the descriptor doesn ' t contain
* any fields with the EIV / IV data either , so they can ' t
* be restored by rt2x00lib .
*/
rxdesc - > flags | = RX_FLAG_IV_STRIPPED ;
if ( rxdesc - > cipher_status = = RX_CRYPTO_SUCCESS )
rxdesc - > flags | = RX_FLAG_DECRYPTED ;
else if ( rxdesc - > cipher_status = = RX_CRYPTO_FAIL_MIC )
rxdesc - > flags | = RX_FLAG_MMIC_ERROR ;
}
2009-11-08 14:39:40 +01:00
if ( rt2x00_get_field32 ( rxd0 , RXINFO_W0_MY_BSS ) )
2009-04-26 15:47:48 +02:00
rxdesc - > dev_flags | = RXDONE_MY_BSS ;
2009-11-08 14:39:40 +01:00
if ( rt2x00_get_field32 ( rxd0 , RXINFO_W0_L2PAD ) ) {
2009-04-26 15:47:48 +02:00
rxdesc - > dev_flags | = RXDONE_L2PAD ;
2009-08-17 18:54:50 +02:00
skbdesc - > flags | = SKBDESC_L2_PADDED ;
}
2009-04-26 15:47:48 +02:00
if ( rt2x00_get_field32 ( rxwi1 , RXWI_W1_SHORT_GI ) )
rxdesc - > flags | = RX_FLAG_SHORT_GI ;
if ( rt2x00_get_field32 ( rxwi1 , RXWI_W1_BW ) )
rxdesc - > flags | = RX_FLAG_40MHZ ;
/*
* Detect RX rate , always use MCS as signal type .
*/
rxdesc - > dev_flags | = RXDONE_SIGNAL_MCS ;
rxdesc - > rate_mode = rt2x00_get_field32 ( rxwi1 , RXWI_W1_PHYMODE ) ;
rxdesc - > signal = rt2x00_get_field32 ( rxwi1 , RXWI_W1_MCS ) ;
/*
* Mask of 0x8 bit to remove the short preamble flag .
*/
if ( rxdesc - > rate_mode = = RATE_MODE_CCK )
rxdesc - > signal & = ~ 0x8 ;
rxdesc - > rssi =
( rt2x00_get_field32 ( rxwi2 , RXWI_W2_RSSI0 ) +
rt2x00_get_field32 ( rxwi2 , RXWI_W2_RSSI1 ) ) / 2 ;
rxdesc - > noise =
( rt2x00_get_field32 ( rxwi3 , RXWI_W3_SNR0 ) +
rt2x00_get_field32 ( rxwi3 , RXWI_W3_SNR1 ) ) / 2 ;
rxdesc - > size = rt2x00_get_field32 ( rxwi0 , RXWI_W0_MPDU_TOTAL_BYTE_COUNT ) ;
/*
* Remove RXWI descriptor from start of buffer .
*/
skb_pull ( entry - > skb , skbdesc - > desc_len ) ;
skb_trim ( entry - > skb , rxdesc - > size ) ;
}
/*
* Device probe functions .
*/
2009-11-08 14:38:54 +01:00
static int rt2800usb_validate_eeprom ( struct rt2x00_dev * rt2x00dev )
{
2009-11-08 14:39:55 +01:00
if ( rt2800_efuse_detect ( rt2x00dev ) )
rt2800_read_eeprom_efuse ( rt2x00dev ) ;
else
rt2x00usb_eeprom_read ( rt2x00dev , rt2x00dev - > eeprom ,
EEPROM_SIZE ) ;
2009-11-08 14:38:54 +01:00
return rt2800_validate_eeprom ( rt2x00dev ) ;
}
2009-11-04 18:34:53 +01:00
static const struct rt2800_ops rt2800usb_rt2800_ops = {
. register_read = rt2x00usb_register_read ,
2009-11-14 20:20:36 +01:00
. register_read_lock = rt2x00usb_register_read_lock ,
2009-11-04 18:34:53 +01:00
. register_write = rt2x00usb_register_write ,
. register_write_lock = rt2x00usb_register_write_lock ,
. register_multiread = rt2x00usb_register_multiread ,
. register_multiwrite = rt2x00usb_register_multiwrite ,
. regbusy_read = rt2x00usb_regbusy_read ,
} ;
2009-04-26 15:47:48 +02:00
static int rt2800usb_probe_hw ( struct rt2x00_dev * rt2x00dev )
{
int retval ;
2009-11-04 18:34:53 +01:00
rt2x00dev - > priv = ( void * ) & rt2800usb_rt2800_ops ;
2009-04-26 15:47:48 +02:00
/*
* Allocate eeprom data .
*/
retval = rt2800usb_validate_eeprom ( rt2x00dev ) ;
if ( retval )
return retval ;
2009-11-08 14:39:01 +01:00
retval = rt2800_init_eeprom ( rt2x00dev ) ;
2009-04-26 15:47:48 +02:00
if ( retval )
return retval ;
/*
* Initialize hw specifications .
*/
2009-11-08 14:39:32 +01:00
retval = rt2800_probe_hw_mode ( rt2x00dev ) ;
2009-04-26 15:47:48 +02:00
if ( retval )
return retval ;
2009-08-08 23:55:55 +02:00
/*
* This device has multiple filters for control frames
* and has a separate filter for PS Poll frames .
*/
__set_bit ( DRIVER_SUPPORT_CONTROL_FILTERS , & rt2x00dev - > flags ) ;
__set_bit ( DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL , & rt2x00dev - > flags ) ;
2009-04-26 15:47:48 +02:00
/*
* This device requires firmware .
*/
__set_bit ( DRIVER_REQUIRE_FIRMWARE , & rt2x00dev - > flags ) ;
__set_bit ( DRIVER_REQUIRE_L2PAD , & rt2x00dev - > flags ) ;
if ( ! modparam_nohwcrypt )
__set_bit ( CONFIG_SUPPORT_HW_CRYPTO , & rt2x00dev - > flags ) ;
/*
* Set the rssi offset .
*/
rt2x00dev - > rssi_offset = DEFAULT_RSSI_OFFSET ;
return 0 ;
}
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
. probe_hw = rt2800usb_probe_hw ,
. get_firmware_name = rt2800usb_get_firmware_name ,
. check_firmware = rt2800usb_check_firmware ,
. load_firmware = rt2800usb_load_firmware ,
. initialize = rt2x00usb_initialize ,
. uninitialize = rt2x00usb_uninitialize ,
. clear_entry = rt2x00usb_clear_entry ,
. set_device_state = rt2800usb_set_device_state ,
2009-11-04 18:36:40 +01:00
. rfkill_poll = rt2800_rfkill_poll ,
. link_stats = rt2800_link_stats ,
. reset_tuner = rt2800_reset_tuner ,
. link_tuner = rt2800_link_tuner ,
2009-04-26 15:47:48 +02:00
. write_tx_desc = rt2800usb_write_tx_desc ,
. write_tx_data = rt2x00usb_write_tx_data ,
. write_beacon = rt2800usb_write_beacon ,
. get_tx_data_len = rt2800usb_get_tx_data_len ,
. kick_tx_queue = rt2800usb_kick_tx_queue ,
. kill_tx_queue = rt2x00usb_kill_tx_queue ,
. fill_rxdone = rt2800usb_fill_rxdone ,
2009-11-04 18:36:40 +01:00
. config_shared_key = rt2800_config_shared_key ,
. config_pairwise_key = rt2800_config_pairwise_key ,
. config_filter = rt2800_config_filter ,
. config_intf = rt2800_config_intf ,
. config_erp = rt2800_config_erp ,
. config_ant = rt2800_config_ant ,
. config = rt2800_config ,
2009-04-26 15:47:48 +02:00
} ;
static const struct data_queue_desc rt2800usb_queue_rx = {
. entry_num = RX_ENTRIES ,
. data_size = AGGREGATION_SIZE ,
2009-11-04 18:35:47 +01:00
. desc_size = RXINFO_DESC_SIZE + RXWI_DESC_SIZE ,
2009-04-26 15:47:48 +02:00
. priv_size = sizeof ( struct queue_entry_priv_usb ) ,
} ;
static const struct data_queue_desc rt2800usb_queue_tx = {
. entry_num = TX_ENTRIES ,
. data_size = AGGREGATION_SIZE ,
. desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE ,
. priv_size = sizeof ( struct queue_entry_priv_usb ) ,
} ;
static const struct data_queue_desc rt2800usb_queue_bcn = {
. entry_num = 8 * BEACON_ENTRIES ,
. data_size = MGMT_FRAME_SIZE ,
. desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE ,
. priv_size = sizeof ( struct queue_entry_priv_usb ) ,
} ;
static const struct rt2x00_ops rt2800usb_ops = {
. name = KBUILD_MODNAME ,
. max_sta_intf = 1 ,
. max_ap_intf = 8 ,
. eeprom_size = EEPROM_SIZE ,
. rf_size = RF_SIZE ,
. tx_queues = NUM_TX_QUEUES ,
. rx = & rt2800usb_queue_rx ,
. tx = & rt2800usb_queue_tx ,
. bcn = & rt2800usb_queue_bcn ,
. lib = & rt2800usb_rt2x00_ops ,
2009-11-04 18:37:05 +01:00
. hw = & rt2800_mac80211_ops ,
2009-04-26 15:47:48 +02:00
# ifdef CONFIG_RT2X00_LIB_DEBUGFS
2009-11-04 18:36:40 +01:00
. debugfs = & rt2800_rt2x00debug ,
2009-04-26 15:47:48 +02:00
# endif /* CONFIG_RT2X00_LIB_DEBUGFS */
} ;
/*
* rt2800usb module information .
*/
static struct usb_device_id rt2800usb_device_table [ ] = {
/* Abocom */
{ USB_DEVICE ( 0x07b8 , 0x2870 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07b8 , 0x2770 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07b8 , 0x3070 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07b8 , 0x3071 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07b8 , 0x3072 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1482 , 0x3c09 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* AirTies */
{ USB_DEVICE ( 0x1eda , 0x2310 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Amigo */
{ USB_DEVICE ( 0x0e0b , 0x9031 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0e0b , 0x9041 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Amit */
{ USB_DEVICE ( 0x15c5 , 0x0008 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* ASUS */
{ USB_DEVICE ( 0x0b05 , 0x1731 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0b05 , 0x1732 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0b05 , 0x1742 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0b05 , 0x1760 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0b05 , 0x1761 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* AzureWave */
{ USB_DEVICE ( 0x13d3 , 0x3247 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x13d3 , 0x3262 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x13d3 , 0x3273 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x13d3 , 0x3284 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Belkin */
{ USB_DEVICE ( 0x050d , 0x8053 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x050d , 0x805c ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x050d , 0x815c ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-19 07:26:04 +02:00
{ USB_DEVICE ( 0x050d , 0x825a ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* Buffalo */
{ USB_DEVICE ( 0x0411 , 0x00e8 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0411 , 0x012e ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Conceptronic */
{ USB_DEVICE ( 0x14b2 , 0x3c06 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c07 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c08 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c09 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c11 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c12 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c23 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c25 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c27 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x14b2 , 0x3c28 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Corega */
{ USB_DEVICE ( 0x07aa , 0x002f ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07aa , 0x003c ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07aa , 0x003f ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x18c5 , 0x0008 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x18c5 , 0x0012 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* D-Link */
{ USB_DEVICE ( 0x07d1 , 0x3c09 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07d1 , 0x3c0a ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07d1 , 0x3c0b ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-22 21:33:21 +02:00
{ USB_DEVICE ( 0x07d1 , 0x3c0d ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07d1 , 0x3c0e ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07d1 , 0x3c0f ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
{ USB_DEVICE ( 0x07d1 , 0x3c11 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x07d1 , 0x3c13 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Edimax */
{ USB_DEVICE ( 0x7392 , 0x7711 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x7392 , 0x7717 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x7392 , 0x7718 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-22 21:33:21 +02:00
/* Encore */
{ USB_DEVICE ( 0x203d , 0x1480 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* EnGenius */
{ USB_DEVICE ( 0 X1740 , 0x9701 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1740 , 0x9702 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1740 , 0x9703 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1740 , 0x9705 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1740 , 0x9706 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1740 , 0x9801 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Gemtek */
{ USB_DEVICE ( 0x15a9 , 0x0010 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Gigabyte */
{ USB_DEVICE ( 0x1044 , 0x800b ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1044 , 0x800c ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1044 , 0x800d ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Hawking */
{ USB_DEVICE ( 0x0e66 , 0x0001 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0e66 , 0x0003 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0e66 , 0x0009 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0e66 , 0x000b ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-22 21:33:21 +02:00
/* I-O DATA */
{ USB_DEVICE ( 0x04bb , 0x0945 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* LevelOne */
{ USB_DEVICE ( 0x1740 , 0x0605 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1740 , 0x0615 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Linksys */
{ USB_DEVICE ( 0x1737 , 0x0070 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1737 , 0x0071 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-27 23:58:31 +02:00
{ USB_DEVICE ( 0x1737 , 0x0077 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* Logitec */
{ USB_DEVICE ( 0x0789 , 0x0162 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0789 , 0x0163 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0789 , 0x0164 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Motorola */
{ USB_DEVICE ( 0x100d , 0x9031 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x100d , 0x9032 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Ovislink */
{ USB_DEVICE ( 0x1b75 , 0x3072 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Pegatron */
{ USB_DEVICE ( 0x1d4d , 0x0002 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x1d4d , 0x000c ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-22 21:33:21 +02:00
{ USB_DEVICE ( 0x1d4d , 0x000e ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* Philips */
{ USB_DEVICE ( 0x0471 , 0x200f ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Planex */
{ USB_DEVICE ( 0x2019 , 0xed06 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x2019 , 0xab24 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x2019 , 0xab25 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Qcom */
{ USB_DEVICE ( 0x18e8 , 0x6259 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Quanta */
{ USB_DEVICE ( 0x1a32 , 0x0304 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Ralink */
2009-05-22 21:33:21 +02:00
{ USB_DEVICE ( 0x0db0 , 0x3820 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
{ USB_DEVICE ( 0x0db0 , 0x6899 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x148f , 0x2070 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x148f , 0x2770 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x148f , 0x2870 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x148f , 0x3070 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x148f , 0x3071 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x148f , 0x3072 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x148f , 0x3572 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Samsung */
{ USB_DEVICE ( 0x04e8 , 0x2018 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Siemens */
{ USB_DEVICE ( 0x129b , 0x1828 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Sitecom */
{ USB_DEVICE ( 0x0df6 , 0x0017 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x002b ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x002c ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x002d ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x0039 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x003b ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x003c ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x003d ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x003e ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x003f ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0df6 , 0x0040 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-22 21:33:21 +02:00
{ USB_DEVICE ( 0x0df6 , 0x0042 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* SMC */
{ USB_DEVICE ( 0x083a , 0x6618 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0x7511 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0x7512 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0x7522 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0x8522 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0xa512 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0xa618 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0xb522 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x083a , 0xc522 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Sparklan */
{ USB_DEVICE ( 0x15a9 , 0x0006 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-21 19:16:14 +02:00
/* Sweex */
{ USB_DEVICE ( 0x177f , 0x0153 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x177f , 0x0302 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x177f , 0x0313 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* U-Media*/
{ USB_DEVICE ( 0x157e , 0x300e ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* ZCOM */
{ USB_DEVICE ( 0x0cde , 0x0022 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0cde , 0x0025 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
/* Zinwell */
{ USB_DEVICE ( 0x5a57 , 0x0280 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x5a57 , 0x0282 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-05-22 21:33:21 +02:00
{ USB_DEVICE ( 0x5a57 , 0x0283 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x5a57 , 0x5257 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
2009-04-26 15:47:48 +02:00
/* Zyxel */
{ USB_DEVICE ( 0x0586 , 0x3416 ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ USB_DEVICE ( 0x0586 , 0x341a ) , USB_DEVICE_DATA ( & rt2800usb_ops ) } ,
{ 0 , }
} ;
MODULE_AUTHOR ( DRV_PROJECT ) ;
MODULE_VERSION ( DRV_VERSION ) ;
MODULE_DESCRIPTION ( " Ralink RT2800 USB Wireless LAN driver. " ) ;
MODULE_SUPPORTED_DEVICE ( " Ralink RT2870 USB chipset based cards " ) ;
MODULE_DEVICE_TABLE ( usb , rt2800usb_device_table ) ;
MODULE_FIRMWARE ( FIRMWARE_RT2870 ) ;
MODULE_LICENSE ( " GPL " ) ;
static struct usb_driver rt2800usb_driver = {
. name = KBUILD_MODNAME ,
. id_table = rt2800usb_device_table ,
. probe = rt2x00usb_probe ,
. disconnect = rt2x00usb_disconnect ,
. suspend = rt2x00usb_suspend ,
. resume = rt2x00usb_resume ,
} ;
static int __init rt2800usb_init ( void )
{
return usb_register ( & rt2800usb_driver ) ;
}
static void __exit rt2800usb_exit ( void )
{
usb_deregister ( & rt2800usb_driver ) ;
}
module_init ( rt2800usb_init ) ;
module_exit ( rt2800usb_exit ) ;