Merge branch 'master' of github.com:davem330/net
[linux-2.6.git] / drivers / net / wireless / rt2x00 / rt2800usb.c
index 61852c5..f156579 100644 (file)
@@ -50,6 +50,112 @@ module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
 /*
+ * Queue handlers.
+ */
+static void rt2800usb_start_queue(struct data_queue *queue)
+{
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+       u32 reg;
+
+       switch (queue->qid) {
+       case QID_RX:
+               rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+               rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+               rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+               break;
+       case QID_BEACON:
+               rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+               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);
+               rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+               break;
+       default:
+               break;
+       }
+}
+
+static void rt2800usb_stop_queue(struct data_queue *queue)
+{
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+       u32 reg;
+
+       switch (queue->qid) {
+       case QID_RX:
+               rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+               rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+               rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+               break;
+       case QID_BEACON:
+               rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+               rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+               rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+               rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+               rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * test if there is an entry in any TX queue for which DMA is done
+ * but the TX status has not been returned yet
+ */
+static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)
+{
+       struct data_queue *queue;
+
+       tx_queue_for_each(rt2x00dev, queue) {
+               if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) !=
+                   rt2x00queue_get_entry(queue, Q_INDEX_DONE))
+                       return true;
+       }
+       return false;
+}
+
+static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
+                                                int urb_status, u32 tx_status)
+{
+       if (urb_status) {
+               WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status);
+               return false;
+       }
+
+       /* try to read all TX_STA_FIFO entries before scheduling txdone_work */
+       if (rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID)) {
+               if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status)) {
+                       WARNING(rt2x00dev, "TX status FIFO overrun, "
+                               "drop tx status report.\n");
+                       queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+               } else
+                       return true;
+       } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
+               queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+       } else if (rt2800usb_txstatus_pending(rt2x00dev)) {
+               mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2));
+       }
+
+       return false;
+}
+
+static void rt2800usb_tx_dma_done(struct queue_entry *entry)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+       rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
+                                     rt2800usb_tx_sta_fifo_read_completed);
+}
+
+static void rt2800usb_tx_sta_fifo_timeout(unsigned long data)
+{
+       struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
+
+       rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
+                                     rt2800usb_tx_sta_fifo_read_completed);
+}
+
+/*
  * Firmware functions
  */
 static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -80,11 +186,11 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
        /*
         * Write firmware to device.
         */
-       rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
-                                  data + offset, length);
+       rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+                                     data + offset, length);
 
-       rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
-       rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+       rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+       rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
 
        /*
         * Send firmware request to device to load firmware,
@@ -99,7 +205,7 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
        }
 
        msleep(10);
-       rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+       rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 
        return 0;
 }
@@ -107,17 +213,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
 /*
  * Device state switch handlers.
  */
-static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
-                               enum dev_state state)
-{
-       u32 reg;
-
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
-                          (state == STATE_RADIO_RX_ON));
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-}
-
 static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -128,22 +223,22 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
        if (rt2800_wait_csr_ready(rt2x00dev))
                return -EBUSY;
 
-       rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
-       rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
+       rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+       rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
 
-       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+       rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
 
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+       rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+       rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 
-       rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
+       rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
 
        rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
                                    USB_MODE_RESET, REGISTER_TIMEOUT);
 
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+       rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
 
        return 0;
 }
@@ -155,7 +250,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
        if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev)))
                return -EIO;
 
-       rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
+       rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, &reg);
        rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
        rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
        rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
@@ -168,7 +263,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
                            / 1024) - 3);
        rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_EN, 1);
        rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
-       rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg);
+       rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg);
 
        return rt2800_enable_radio(rt2x00dev);
 }
@@ -214,14 +309,8 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
                rt2800usb_disable_radio(rt2x00dev);
                rt2800usb_set_state(rt2x00dev, STATE_SLEEP);
                break;
-       case STATE_RADIO_RX_ON:
-       case STATE_RADIO_RX_OFF:
-               rt2800usb_toggle_rx(rt2x00dev, state);
-               break;
        case STATE_RADIO_IRQ_ON:
-       case STATE_RADIO_IRQ_ON_ISR:
        case STATE_RADIO_IRQ_OFF:
-       case STATE_RADIO_IRQ_OFF_ISR:
                /* No support, but no error either */
                break;
        case STATE_DEEP_SLEEP:
@@ -250,12 +339,12 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
        unsigned int i;
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+       rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
        if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) {
                WARNING(rt2x00dev, "TX HW queue 0 timed out,"
-                       " invoke forced kick");
+                       " invoke forced kick\n");
 
-               rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012);
+               rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40012);
 
                for (i = 0; i < 10; i++) {
                        udelay(10);
@@ -263,15 +352,15 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
                                break;
                }
 
-               rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+               rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006);
        }
 
-       rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+       rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
        if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) {
                WARNING(rt2x00dev, "TX HW queue 1 timed out,"
-                       " invoke forced kick");
+                       " invoke forced kick\n");
 
-               rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
+               rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
 
                for (i = 0; i < 10; i++) {
                        udelay(10);
@@ -279,7 +368,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
                                break;
                }
 
-               rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+               rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006);
        }
 
        rt2x00usb_watchdog(rt2x00dev);
@@ -307,8 +396,14 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
         * Initialize TXINFO descriptor
         */
        rt2x00_desc_read(txi, 0, &word);
+
+       /*
+        * The size of TXINFO_W0_USB_DMA_TX_PKT_LEN is
+        * TXWI + 802.11 header + L2 pad + payload + pad,
+        * so need to decrease size of TXINFO and USB end pad.
+        */
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
-                          entry->skb->len - TXINFO_DESC_SIZE);
+                          entry->skb->len - TXINFO_DESC_SIZE - 4);
        rt2x00_set_field32(&word, TXINFO_W0_WIV,
                           !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
        rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
@@ -326,27 +421,132 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
        skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
 }
 
+static void rt2800usb_write_tx_data(struct queue_entry *entry,
+                                       struct txentry_desc *txdesc)
+{
+       unsigned int len;
+       int err;
+
+       rt2800_write_tx_data(entry, txdesc);
+
+       /*
+        * pad(1~3 bytes) is added after each 802.11 payload.
+        * USB end pad(4 bytes) is added at each USB bulk out packet end.
+        * TX frame format is :
+        * | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad |
+        *                 |<------------- tx_pkt_len ------------->|
+        */
+       len = roundup(entry->skb->len, 4) + 4;
+       err = skb_padto(entry->skb, len);
+       if (unlikely(err)) {
+               WARNING(entry->queue->rt2x00dev, "TX SKB padding error, out of memory\n");
+               return;
+       }
+
+       entry->skb->len = len;
+}
+
 /*
  * TX data initialization
  */
 static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
 {
-       int length;
+       return entry->skb->len;
+}
+
+/*
+ * TX control handlers
+ */
+static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
+{
+       __le32 *txwi;
+       u32 word;
+       int wcid, ack, pid;
+       int tx_wcid, tx_ack, tx_pid;
+
+       if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+           !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) {
+               WARNING(entry->queue->rt2x00dev,
+                       "Data pending for entry %u in queue %u\n",
+                       entry->entry_idx, entry->queue->qid);
+               cond_resched();
+               return false;
+       }
+
+       wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+       ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
+       pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+
+       /*
+        * This frames has returned with an IO error,
+        * so the status report is not intended for this
+        * frame.
+        */
+       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) {
+               rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+               return false;
+       }
 
        /*
-        * 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.
+        * Validate if this TX status report is intended for
+        * this entry by comparing the WCID/ACK/PID fields.
         */
-       length = roundup(entry->skb->len + 4, 4);
-       length += (4 * !(length % entry->queue->usb_maxpacket));
+       txwi = rt2800usb_get_txwi(entry);
+
+       rt2x00_desc_read(txwi, 1, &word);
+       tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+       tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
+       tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
+
+       if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) {
+               WARNING(entry->queue->rt2x00dev,
+                       "TX status report missed for queue %d entry %d\n",
+               entry->queue->qid, entry->entry_idx);
+               rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+               return false;
+       }
 
-       return length;
+       return true;
+}
+
+static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
+{
+       struct data_queue *queue;
+       struct queue_entry *entry;
+       u32 reg;
+       u8 qid;
+
+       while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
+
+               /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus
+                * qid is guaranteed to be one of the TX QIDs
+                */
+               qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
+               queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
+               if (unlikely(!queue)) {
+                       WARNING(rt2x00dev, "Got TX status for an unavailable "
+                                          "queue %u, dropping\n", qid);
+                       continue;
+               }
+
+               /*
+                * Inside each queue, we process each entry in a chronological
+                * order. We first check that the queue is not empty.
+                */
+               entry = NULL;
+               while (!rt2x00queue_empty(queue)) {
+                       entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+                       if (rt2800usb_txdone_entry_check(entry, reg))
+                               break;
+                       entry = NULL;
+               }
+
+               if (entry)
+                       rt2800_txdone_entry(entry, reg,
+                                           rt2800usb_get_txwi(entry));
+       }
 }
 
-/*
- * TX control handlers
- */
 static void rt2800usb_work_txdone(struct work_struct *work)
 {
        struct rt2x00_dev *rt2x00dev =
@@ -354,7 +554,7 @@ static void rt2800usb_work_txdone(struct work_struct *work)
        struct data_queue *queue;
        struct queue_entry *entry;
 
-       rt2800_txdone(rt2x00dev);
+       rt2800usb_txdone(rt2x00dev);
 
        /*
         * Process any trailing TX status reports for IO failures,
@@ -368,20 +568,25 @@ static void rt2800usb_work_txdone(struct work_struct *work)
                        entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 
                        if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
-                           !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+                           !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
                                break;
 
-                       rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+                       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+                               rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+                       else if (rt2x00queue_status_timeout(entry))
+                               rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+                       else
+                               break;
                }
        }
-}
 
-static void rt2800usb_kill_tx_queue(struct data_queue *queue)
-{
-       if (queue->qid == QID_BEACON)
-               rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0);
-
-       rt2x00usb_kill_tx_queue(queue);
+       /*
+        * The hw may delay sending the packet after DMA complete
+        * if the medium is busy, thus the TX_STA_FIFO entry is
+        * also delayed -> use a timer to retrieve it.
+        */
+       if (rt2800usb_txstatus_pending(rt2x00dev))
+               mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2));
 }
 
 /*
@@ -439,6 +644,12 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
                 */
                rxdesc->flags |= RX_FLAG_IV_STRIPPED;
 
+               /*
+                * The hardware has already checked the Michael Mic and has
+                * stripped it from the frame. Signal this to mac80211.
+                */
+               rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
                if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
                        rxdesc->flags |= RX_FLAG_DECRYPTED;
                else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
@@ -502,18 +713,24 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
         * 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);
+       __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
+       __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags);
 
        /*
         * This device requires firmware.
         */
-       __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
-       __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
+       __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
+       __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags);
        if (!modparam_nohwcrypt)
-               __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
-       __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
-       __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
+               __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+       __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
+       __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
+       __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
+       __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
+
+       setup_timer(&rt2x00dev->txstatus_timer,
+                   rt2800usb_tx_sta_fifo_timeout,
+                   (unsigned long) rt2x00dev);
 
        /*
         * Set the rssi offset.
@@ -543,12 +760,17 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
        .get_stats              = rt2x00mac_get_stats,
        .get_tkip_seq           = rt2800_get_tkip_seq,
        .set_rts_threshold      = rt2800_set_rts_threshold,
+       .sta_add                = rt2x00mac_sta_add,
+       .sta_remove             = rt2x00mac_sta_remove,
        .bss_info_changed       = rt2x00mac_bss_info_changed,
        .conf_tx                = rt2800_conf_tx,
        .get_tsf                = rt2800_get_tsf,
        .rfkill_poll            = rt2x00mac_rfkill_poll,
        .ampdu_action           = rt2800_ampdu_action,
        .flush                  = rt2x00mac_flush,
+       .get_survey             = rt2800_get_survey,
+       .get_ringparam          = rt2x00mac_get_ringparam,
+       .tx_frames_pending      = rt2x00mac_tx_frames_pending,
 };
 
 static const struct rt2800_ops rt2800usb_rt2800_ops = {
@@ -577,13 +799,18 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .link_stats             = rt2800_link_stats,
        .reset_tuner            = rt2800_reset_tuner,
        .link_tuner             = rt2800_link_tuner,
+       .gain_calibration       = rt2800_gain_calibration,
        .watchdog               = rt2800usb_watchdog,
+       .start_queue            = rt2800usb_start_queue,
+       .kick_queue             = rt2x00usb_kick_queue,
+       .stop_queue             = rt2800usb_stop_queue,
+       .flush_queue            = rt2x00usb_flush_queue,
+       .tx_dma_done            = rt2800usb_tx_dma_done,
        .write_tx_desc          = rt2800usb_write_tx_desc,
-       .write_tx_data          = rt2800_write_tx_data,
+       .write_tx_data          = rt2800usb_write_tx_data,
        .write_beacon           = rt2800_write_beacon,
+       .clear_beacon           = rt2800_clear_beacon,
        .get_tx_data_len        = rt2800usb_get_tx_data_len,
-       .kick_tx_queue          = rt2x00usb_kick_tx_queue,
-       .kill_tx_queue          = rt2800usb_kill_tx_queue,
        .fill_rxdone            = rt2800usb_fill_rxdone,
        .config_shared_key      = rt2800_config_shared_key,
        .config_pairwise_key    = rt2800_config_pairwise_key,
@@ -592,6 +819,8 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .config_erp             = rt2800_config_erp,
        .config_ant             = rt2800_config_ant,
        .config                 = rt2800_config,
+       .sta_add                = rt2800_sta_add,
+       .sta_remove             = rt2800_sta_remove,
 };
 
 static const struct data_queue_desc rt2800usb_queue_rx = {
@@ -639,304 +868,344 @@ static const struct rt2x00_ops rt2800usb_ops = {
  */
 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(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07b8, 0x2870) },
+       { USB_DEVICE(0x07b8, 0x2770) },
+       { USB_DEVICE(0x07b8, 0x3070) },
+       { USB_DEVICE(0x07b8, 0x3071) },
+       { USB_DEVICE(0x07b8, 0x3072) },
+       { USB_DEVICE(0x1482, 0x3c09) },
+       /* AirTies */
+       { USB_DEVICE(0x1eda, 0x2012) },
+       { USB_DEVICE(0x1eda, 0x2310) },
        /* Allwin */
-       { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x8516, 0x2070) },
+       { USB_DEVICE(0x8516, 0x2770) },
+       { USB_DEVICE(0x8516, 0x2870) },
+       { USB_DEVICE(0x8516, 0x3070) },
+       { USB_DEVICE(0x8516, 0x3071) },
+       { USB_DEVICE(0x8516, 0x3072) },
+       /* Alpha Networks */
+       { USB_DEVICE(0x14b2, 0x3c06) },
+       { USB_DEVICE(0x14b2, 0x3c07) },
+       { USB_DEVICE(0x14b2, 0x3c09) },
+       { USB_DEVICE(0x14b2, 0x3c12) },
+       { USB_DEVICE(0x14b2, 0x3c23) },
+       { USB_DEVICE(0x14b2, 0x3c25) },
+       { USB_DEVICE(0x14b2, 0x3c27) },
+       { USB_DEVICE(0x14b2, 0x3c28) },
+       { USB_DEVICE(0x14b2, 0x3c2c) },
        /* Amit */
-       { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x15c5, 0x0008) },
        /* Askey */
-       { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1690, 0x0740) },
        /* 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, 0x1731) },
+       { USB_DEVICE(0x0b05, 0x1732) },
+       { USB_DEVICE(0x0b05, 0x1742) },
+       { USB_DEVICE(0x0b05, 0x1784) },
+       { USB_DEVICE(0x1761, 0x0b05) },
        /* AzureWave */
-       { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3247) },
+       { USB_DEVICE(0x13d3, 0x3273) },
+       { USB_DEVICE(0x13d3, 0x3305) },
+       { USB_DEVICE(0x13d3, 0x3307) },
+       { USB_DEVICE(0x13d3, 0x3321) },
        /* 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) },
+       { USB_DEVICE(0x050d, 0x8053) },
+       { USB_DEVICE(0x050d, 0x805c) },
+       { USB_DEVICE(0x050d, 0x815c) },
+       { USB_DEVICE(0x050d, 0x825b) },
+       { USB_DEVICE(0x050d, 0x935a) },
+       { USB_DEVICE(0x050d, 0x935b) },
        /* Buffalo */
-       { USB_DEVICE(0x0411, 0x00e8), 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, 0x3c09), 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) },
+       { USB_DEVICE(0x0411, 0x00e8) },
+       { USB_DEVICE(0x0411, 0x016f) },
+       { USB_DEVICE(0x0411, 0x01a2) },
        /* 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(0x07aa, 0x002f) },
+       { USB_DEVICE(0x07aa, 0x003c) },
+       { USB_DEVICE(0x07aa, 0x003f) },
+       { USB_DEVICE(0x18c5, 0x0012) },
        /* D-Link */
-       { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c09) },
+       { USB_DEVICE(0x07d1, 0x3c0a) },
+       { USB_DEVICE(0x07d1, 0x3c0d) },
+       { USB_DEVICE(0x07d1, 0x3c0e) },
+       { USB_DEVICE(0x07d1, 0x3c0f) },
+       { USB_DEVICE(0x07d1, 0x3c11) },
+       { USB_DEVICE(0x07d1, 0x3c16) },
+       /* Draytek */
+       { USB_DEVICE(0x07fa, 0x7712) },
+       /* DVICO */
+       { USB_DEVICE(0x0fe9, 0xb307) },
        /* Edimax */
-       { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x7392, 0x7711) },
+       { USB_DEVICE(0x7392, 0x7717) },
+       { USB_DEVICE(0x7392, 0x7718) },
+       /* Encore */
+       { USB_DEVICE(0x203d, 0x1480) },
+       { USB_DEVICE(0x203d, 0x14a9) },
        /* EnGenius */
-       { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9701) },
+       { USB_DEVICE(0x1740, 0x9702) },
+       { USB_DEVICE(0x1740, 0x9703) },
+       { USB_DEVICE(0x1740, 0x9705) },
+       { USB_DEVICE(0x1740, 0x9706) },
+       { USB_DEVICE(0x1740, 0x9707) },
+       { USB_DEVICE(0x1740, 0x9708) },
+       { USB_DEVICE(0x1740, 0x9709) },
+       /* Gemtek */
+       { USB_DEVICE(0x15a9, 0x0012) },
        /* Gigabyte */
-       { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1044, 0x800b) },
+       { USB_DEVICE(0x1044, 0x800d) },
        /* 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) },
-       { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0e66, 0x0001) },
+       { USB_DEVICE(0x0e66, 0x0003) },
+       { USB_DEVICE(0x0e66, 0x0009) },
+       { USB_DEVICE(0x0e66, 0x000b) },
+       { USB_DEVICE(0x0e66, 0x0013) },
+       { USB_DEVICE(0x0e66, 0x0017) },
+       { USB_DEVICE(0x0e66, 0x0018) },
+       /* I-O DATA */
+       { USB_DEVICE(0x04bb, 0x0945) },
+       { USB_DEVICE(0x04bb, 0x0947) },
+       { USB_DEVICE(0x04bb, 0x0948) },
        /* Linksys */
-       { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13b1, 0x0031) },
+       { USB_DEVICE(0x1737, 0x0070) },
+       { USB_DEVICE(0x1737, 0x0071) },
        /* 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) },
+       { USB_DEVICE(0x0789, 0x0162) },
+       { USB_DEVICE(0x0789, 0x0163) },
+       { USB_DEVICE(0x0789, 0x0164) },
+       { USB_DEVICE(0x0789, 0x0166) },
        /* Motorola */
-       { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x100d, 0x9031) },
        /* MSI */
-       { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3820) },
+       { USB_DEVICE(0x0db0, 0x3821) },
+       { USB_DEVICE(0x0db0, 0x3822) },
+       { USB_DEVICE(0x0db0, 0x3870) },
+       { USB_DEVICE(0x0db0, 0x3871) },
+       { USB_DEVICE(0x0db0, 0x6899) },
+       { USB_DEVICE(0x0db0, 0x821a) },
+       { USB_DEVICE(0x0db0, 0x822a) },
+       { USB_DEVICE(0x0db0, 0x822b) },
+       { USB_DEVICE(0x0db0, 0x822c) },
+       { USB_DEVICE(0x0db0, 0x870a) },
+       { USB_DEVICE(0x0db0, 0x871a) },
+       { USB_DEVICE(0x0db0, 0x871b) },
+       { USB_DEVICE(0x0db0, 0x871c) },
+       { USB_DEVICE(0x0db0, 0x899a) },
+       /* Para */
+       { USB_DEVICE(0x20b8, 0x8888) },
+       /* Pegatron */
+       { USB_DEVICE(0x1d4d, 0x000c) },
+       { USB_DEVICE(0x1d4d, 0x000e) },
+       { USB_DEVICE(0x1d4d, 0x0011) },
        /* Philips */
-       { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0471, 0x200f) },
        /* Planex */
-       { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x2019, 0xab25) },
+       { USB_DEVICE(0x2019, 0xed06) },
+       /* Quanta */
+       { USB_DEVICE(0x1a32, 0x0304) },
        /* Ralink */
-       { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x148f, 0x2070) },
+       { USB_DEVICE(0x148f, 0x2770) },
+       { USB_DEVICE(0x148f, 0x2870) },
+       { USB_DEVICE(0x148f, 0x3070) },
+       { USB_DEVICE(0x148f, 0x3071) },
+       { USB_DEVICE(0x148f, 0x3072) },
        /* Samsung */
-       { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04e8, 0x2018) },
        /* Siemens */
-       { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x129b, 0x1828) },
        /* 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, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0017) },
+       { USB_DEVICE(0x0df6, 0x002b) },
+       { USB_DEVICE(0x0df6, 0x002c) },
+       { USB_DEVICE(0x0df6, 0x002d) },
+       { USB_DEVICE(0x0df6, 0x0039) },
+       { USB_DEVICE(0x0df6, 0x003b) },
+       { USB_DEVICE(0x0df6, 0x003d) },
+       { USB_DEVICE(0x0df6, 0x003e) },
+       { USB_DEVICE(0x0df6, 0x003f) },
+       { USB_DEVICE(0x0df6, 0x0040) },
+       { USB_DEVICE(0x0df6, 0x0042) },
+       { USB_DEVICE(0x0df6, 0x0047) },
+       { USB_DEVICE(0x0df6, 0x0048) },
+       { USB_DEVICE(0x0df6, 0x0051) },
+       { USB_DEVICE(0x0df6, 0x005f) },
+       { USB_DEVICE(0x0df6, 0x0060) },
        /* SMC */
-       { USB_DEVICE(0x083a, 0x6618), 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, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0x6618) },
+       { USB_DEVICE(0x083a, 0x7511) },
+       { USB_DEVICE(0x083a, 0x7512) },
+       { USB_DEVICE(0x083a, 0x7522) },
+       { USB_DEVICE(0x083a, 0x8522) },
+       { USB_DEVICE(0x083a, 0xa618) },
+       { USB_DEVICE(0x083a, 0xa701) },
+       { USB_DEVICE(0x083a, 0xa702) },
+       { USB_DEVICE(0x083a, 0xa703) },
+       { USB_DEVICE(0x083a, 0xb522) },
        /* Sparklan */
-       { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x15a9, 0x0006) },
        /* Sweex */
-       { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* U-Media*/
-       { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x177f, 0x0302) },
+       /* U-Media */
+       { USB_DEVICE(0x157e, 0x300e) },
+       { USB_DEVICE(0x157e, 0x3013) },
        /* ZCOM */
-       { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0cde, 0x0022) },
+       { USB_DEVICE(0x0cde, 0x0025) },
        /* Zinwell */
-       { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x5a57, 0x0280) },
+       { USB_DEVICE(0x5a57, 0x0282) },
+       { USB_DEVICE(0x5a57, 0x0283) },
+       { USB_DEVICE(0x5a57, 0x5257) },
        /* Zyxel */
-       { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
-#ifdef CONFIG_RT2800USB_RT30XX
-       /* Abocom */
-       { 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) },
-       /* AirTies */
-       { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Allwin */
-       { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* ASUS */
-       { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* AzureWave */
-       { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Conceptronic */
-       { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Corega */
-       { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* D-Link */
-       { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { 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) },
-       { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Draytek */
-       { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Edimax */
-       { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Encore */
-       { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* EnGenius */
-       { 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, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Gigabyte */
-       { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* I-O DATA */
-       { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Logitec */
-       { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* MSI */
-       { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Para */
-       { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Pegatron */
-       { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Planex */
-       { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Quanta */
-       { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Ralink */
-       { USB_DEVICE(0x148f, 0x2070), 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) },
-       /* Sitecom */
-       { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* SMC */
-       { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Zinwell */
-       { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
-#endif
+       { USB_DEVICE(0x0586, 0x3416) },
+       { USB_DEVICE(0x0586, 0x3418) },
+       { USB_DEVICE(0x0586, 0x341e) },
+       { USB_DEVICE(0x0586, 0x343e) },
 #ifdef CONFIG_RT2800USB_RT33XX
+       /* Belkin */
+       { USB_DEVICE(0x050d, 0x945b) },
        /* Ralink */
-       { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x148f, 0x3370) },
+       { USB_DEVICE(0x148f, 0x8070) },
        /* Sitecom */
-       { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0050) },
 #endif
 #ifdef CONFIG_RT2800USB_RT35XX
        /* Allwin */
-       { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x8516, 0x3572) },
        /* Askey */
-       { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1690, 0x0744) },
        /* Cisco */
-       { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x167b, 0x4001) },
        /* EnGenius */
-       { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9801) },
        /* I-O DATA */
-       { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04bb, 0x0944) },
+       /* Linksys */
+       { USB_DEVICE(0x13b1, 0x002f) },
+       { USB_DEVICE(0x1737, 0x0079) },
        /* Ralink */
-       { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x148f, 0x3572) },
        /* Sitecom */
-       { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0041) },
+       { USB_DEVICE(0x0df6, 0x0062) },
+       /* Toshiba */
+       { USB_DEVICE(0x0930, 0x0a07) },
        /* Zinwell */
-       { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x5a57, 0x0284) },
+#endif
+#ifdef CONFIG_RT2800USB_RT53XX
+       /* Azurewave */
+       { USB_DEVICE(0x13d3, 0x3329) },
+       { USB_DEVICE(0x13d3, 0x3365) },
+       /* Ralink */
+       { USB_DEVICE(0x148f, 0x5370) },
+       { USB_DEVICE(0x148f, 0x5372) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
        /*
         * Unclear what kind of devices these are (they aren't supported by the
         * vendor linux driver).
         */
+       /* Abocom */
+       { USB_DEVICE(0x07b8, 0x3073) },
+       { USB_DEVICE(0x07b8, 0x3074) },
+       /* Alpha Networks */
+       { USB_DEVICE(0x14b2, 0x3c08) },
+       { USB_DEVICE(0x14b2, 0x3c11) },
        /* Amigo */
-       { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0e0b, 0x9031) },
+       { USB_DEVICE(0x0e0b, 0x9041) },
        /* ASUS */
-       { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0b05, 0x166a) },
+       { USB_DEVICE(0x0b05, 0x1760) },
+       { USB_DEVICE(0x0b05, 0x1761) },
+       { USB_DEVICE(0x0b05, 0x1790) },
+       { USB_DEVICE(0x0b05, 0x179d) },
        /* AzureWave */
-       { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x13d3, 0x3322), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3262) },
+       { USB_DEVICE(0x13d3, 0x3284) },
+       { USB_DEVICE(0x13d3, 0x3322) },
        /* Belkin */
-       { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x050d, 0x1003) },
+       { USB_DEVICE(0x050d, 0x825a) },
        /* Buffalo */
-       { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Conceptronic */
-       { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0411, 0x012e) },
+       { USB_DEVICE(0x0411, 0x0148) },
+       { USB_DEVICE(0x0411, 0x0150) },
+       { USB_DEVICE(0x0411, 0x015d) },
        /* Corega */
-       { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07aa, 0x0041) },
+       { USB_DEVICE(0x07aa, 0x0042) },
+       { USB_DEVICE(0x18c5, 0x0008) },
        /* D-Link */
-       { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c0b) },
+       { USB_DEVICE(0x07d1, 0x3c13) },
+       { USB_DEVICE(0x07d1, 0x3c15) },
+       { USB_DEVICE(0x07d1, 0x3c17) },
+       { USB_DEVICE(0x2001, 0x3c17) },
+       /* Edimax */
+       { USB_DEVICE(0x7392, 0x4085) },
+       { USB_DEVICE(0x7392, 0x7722) },
        /* Encore */
-       { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x203d, 0x14a1) },
        /* Gemtek */
-       { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x15a9, 0x0010) },
        /* Gigabyte */
-       { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1044, 0x800c) },
+       /* Huawei */
+       { USB_DEVICE(0x148f, 0xf101) },
+       /* I-O DATA */
+       { USB_DEVICE(0x04bb, 0x094b) },
        /* LevelOne */
-       { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x0605) },
+       { USB_DEVICE(0x1740, 0x0615) },
        /* Linksys */
-       { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1737, 0x0077) },
+       { USB_DEVICE(0x1737, 0x0078) },
+       /* Logitec */
+       { USB_DEVICE(0x0789, 0x0168) },
+       { USB_DEVICE(0x0789, 0x0169) },
        /* Motorola */
-       { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x100d, 0x9032) },
        /* Ovislink */
-       { USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1b75, 0x3071) },
+       { USB_DEVICE(0x1b75, 0x3072) },
        /* Pegatron */
-       { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x05a6, 0x0101) },
+       { USB_DEVICE(0x1d4d, 0x0002) },
+       { USB_DEVICE(0x1d4d, 0x0010) },
        /* Planex */
-       { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x2019, 0x5201) },
+       { USB_DEVICE(0x2019, 0xab24) },
        /* Qcom */
-       { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x18e8, 0x6259) },
+       /* RadioShack */
+       { USB_DEVICE(0x08b9, 0x1197) },
+       /* Sitecom */
+       { USB_DEVICE(0x0df6, 0x003c) },
+       { USB_DEVICE(0x0df6, 0x004a) },
+       { USB_DEVICE(0x0df6, 0x004d) },
+       { USB_DEVICE(0x0df6, 0x0053) },
        /* SMC */
-       { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xf511), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa512) },
+       { USB_DEVICE(0x083a, 0xc522) },
+       { USB_DEVICE(0x083a, 0xd522) },
+       { USB_DEVICE(0x083a, 0xf511) },
        /* Sweex */
-       { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x177f, 0x0153) },
+       { USB_DEVICE(0x177f, 0x0313) },
        /* Zyxel */
-       { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0586, 0x341a) },
 #endif
        { 0, }
 };
@@ -949,10 +1218,16 @@ MODULE_DEVICE_TABLE(usb, rt2800usb_device_table);
 MODULE_FIRMWARE(FIRMWARE_RT2870);
 MODULE_LICENSE("GPL");
 
+static int rt2800usb_probe(struct usb_interface *usb_intf,
+                          const struct usb_device_id *id)
+{
+       return rt2x00usb_probe(usb_intf, &rt2800usb_ops);
+}
+
 static struct usb_driver rt2800usb_driver = {
        .name           = KBUILD_MODNAME,
        .id_table       = rt2800usb_device_table,
-       .probe          = rt2x00usb_probe,
+       .probe          = rt2800usb_probe,
        .disconnect     = rt2x00usb_disconnect,
        .suspend        = rt2x00usb_suspend,
        .resume         = rt2x00usb_resume,