rt2x00: Simplify TXD handling of beacons.
[safe/jmp/linux-2.6] / drivers / net / wireless / rt2x00 / rt2x00usb.c
index 933e6cc..a4f0551 100644 (file)
@@ -1,5 +1,5 @@
 /*
-       Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+       Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
        <http://rt2x00.serialmonkey.com>
 
        This program is free software; you can redistribute it and/or modify
@@ -47,6 +47,8 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
            (requesttype == USB_VENDOR_REQUEST_IN) ?
            usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
 
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return -ENODEV;
 
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
                status = usb_control_msg(usb_dev, pipe, request, requesttype,
@@ -60,8 +62,10 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
                 * -ENODEV: Device has disappeared, no point continuing.
                 * All other errors: Try again.
                 */
-               else if (status == -ENODEV)
+               else if (status == -ENODEV) {
+                       clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
                        break;
+               }
        }
 
        ERROR(rt2x00dev,
@@ -79,7 +83,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
 {
        int status;
 
-       BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex));
+       BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex));
 
        /*
         * Check for Cache availability.
@@ -110,13 +114,13 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
 {
        int status;
 
-       mutex_lock(&rt2x00dev->usb_cache_mutex);
+       mutex_lock(&rt2x00dev->csr_mutex);
 
        status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
                                                requesttype, offset, buffer,
                                                buffer_length, timeout);
 
-       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+       mutex_unlock(&rt2x00dev->csr_mutex);
 
        return status;
 }
@@ -124,7 +128,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
 
 int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
                                        const u8 request, const u8 requesttype,
-                                       const u16 offset, void *buffer,
+                                       const u16 offset, const void *buffer,
                                        const u16 buffer_length,
                                        const int timeout)
 {
@@ -132,9 +136,9 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
        unsigned char *tb;
        u16 off, len, bsize;
 
-       mutex_lock(&rt2x00dev->usb_cache_mutex);
+       mutex_lock(&rt2x00dev->csr_mutex);
 
-       tb  = buffer;
+       tb  = (char *)buffer;
        off = offset;
        len = buffer_length;
        while (len && !status) {
@@ -148,12 +152,37 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
                off += bsize;
        }
 
-       mutex_unlock(&rt2x00dev->usb_cache_mutex);
+       mutex_unlock(&rt2x00dev->csr_mutex);
 
        return status;
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
 
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+                          const unsigned int offset,
+                          const struct rt2x00_field32 field,
+                          u32 *reg)
+{
+       unsigned int i;
+
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return -ENODEV;
+
+       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+               rt2x00usb_register_read_lock(rt2x00dev, offset, reg);
+               if (!rt2x00_get_field32(*reg, field))
+                       return 1;
+               udelay(REGISTER_BUSY_DELAY);
+       }
+
+       ERROR(rt2x00dev, "Indirect register access failed: "
+             "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+       *reg = ~0;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
+
 /*
  * TX data handlers.
  */
@@ -163,16 +192,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct txdone_entry_desc txdesc;
 
-       if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
            !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
        /*
-        * Remove the descriptor data from the buffer.
-        */
-       skb_pull(entry->skb, entry->queue->desc_size);
-
-       /*
         * Obtain the status about this packet.
         * Note that when the status is 0 it does not mean the
         * frame was send out correctly. It only means the frame
@@ -181,6 +205,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
         * (Only indirectly by looking at the failed TX counters
         * in the register).
         */
+       txdesc.flags = 0;
        if (!urb->status)
                __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
        else
@@ -190,12 +215,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        rt2x00lib_txdone(entry, &txdesc);
 }
 
-int rt2x00usb_write_tx_data(struct queue_entry *entry)
+int rt2x00usb_write_tx_data(struct queue_entry *entry,
+                           struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
-       struct skb_frame_desc *skbdesc;
        u32 length;
 
        /*
@@ -205,24 +230,23 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
        memset(entry->skb->data, 0, entry->queue->desc_size);
 
        /*
-        * Fill in skb descriptor
-        */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       skbdesc->desc = entry->skb->data;
-       skbdesc->desc_len = entry->queue->desc_size;
-
-       /*
         * USB devices cannot blindly pass the skb->len as the
         * length of the data to usb_fill_bulk_urb. Pass the skb
         * to the driver to determine what the length should be.
         */
-       length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+       length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
        usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-                         usb_sndbulkpipe(usb_dev, 1),
+                         usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
                          entry->skb->data, length,
                          rt2x00usb_interrupt_txdone, entry);
 
+       /*
+        * Make sure the skb->data pointer points to the frame, not the
+        * descriptor.
+        */
+       skb_pull(entry->skb, entry->queue->desc_size);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
@@ -231,7 +255,7 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
 {
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 
-       if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+       if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
                usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
 }
 
@@ -272,6 +296,41 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
 
+void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
+                            const enum data_queue_qid qid)
+{
+       struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
+       struct queue_entry_priv_usb *entry_priv;
+       struct queue_entry_priv_usb_bcn *bcn_priv;
+       unsigned int i;
+       bool kill_guard;
+
+       /*
+        * When killing the beacon queue, we must also kill
+        * the beacon guard byte.
+        */
+       kill_guard =
+           (qid == QID_BEACON) &&
+           (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags));
+
+       /*
+        * Cancel all entries.
+        */
+       for (i = 0; i < queue->limit; i++) {
+               entry_priv = queue->entries[i].priv_data;
+               usb_kill_urb(entry_priv->urb);
+
+               /*
+                * Kill guardian urb (if required by driver).
+                */
+               if (kill_guard) {
+                       bcn_priv = queue->entries[i].priv_data;
+                       usb_kill_urb(bcn_priv->guardian_urb);
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
+
 /*
  * RX data handlers.
  */
@@ -282,7 +341,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        u8 rxd[32];
 
-       if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
            !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
@@ -292,7 +351,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
         * a problem.
         */
        if (urb->actual_length < entry->queue->desc_size || urb->status) {
-               __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+               set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
                usb_submit_urb(urb, GFP_ATOMIC);
                return;
        }
@@ -314,63 +373,110 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
  */
 void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
-       struct queue_entry_priv_usb *entry_priv;
-       struct queue_entry_priv_usb_bcn *bcn_priv;
-       struct data_queue *queue;
-       unsigned int i;
-
        rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
                                    REGISTER_TIMEOUT);
 
        /*
-        * Cancel all queues.
+        * The USB version of kill_tx_queue also works
+        * on the RX queue.
         */
-       queue_for_each(rt2x00dev, queue) {
-               for (i = 0; i < queue->limit; i++) {
-                       entry_priv = queue->entries[i].priv_data;
-                       usb_kill_urb(entry_priv->urb);
-               }
-       }
-
-       /*
-        * Kill guardian urb (if required by driver).
-        */
-       if (!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
-               return;
-
-       for (i = 0; i < rt2x00dev->bcn->limit; i++) {
-               bcn_priv = rt2x00dev->bcn->entries[i].priv_data;
-               if (bcn_priv->guardian_urb)
-                       usb_kill_urb(bcn_priv->guardian_urb);
-       }
+       rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_RX);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
 
 /*
  * Device initialization handlers.
  */
-void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
-                           struct queue_entry *entry)
+void rt2x00usb_clear_entry(struct queue_entry *entry)
 {
-       struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+       struct usb_device *usb_dev =
+           to_usb_device_intf(entry->queue->rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+       int pipe;
 
-       usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-                         usb_rcvbulkpipe(usb_dev, 1),
-                         entry->skb->data, entry->skb->len,
-                         rt2x00usb_interrupt_rxdone, entry);
+       if (entry->queue->qid == QID_RX) {
+               pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
+               usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
+                               entry->skb->data, entry->skb->len,
+                               rt2x00usb_interrupt_rxdone, entry);
+
+               set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+               usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+       } else {
+               entry->flags = 0;
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
+
+static void rt2x00usb_assign_endpoint(struct data_queue *queue,
+                                     struct usb_endpoint_descriptor *ep_desc)
+{
+       struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
+       int pipe;
 
-       __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-       usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+       queue->usb_endpoint = usb_endpoint_num(ep_desc);
+
+       if (queue->qid == QID_RX) {
+               pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
+               queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
+       } else {
+               pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
+               queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
+       }
+
+       if (!queue->usb_maxpacket)
+               queue->usb_maxpacket = 1;
 }
-EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
 
-void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
-                           struct queue_entry *entry)
+static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
 {
-       entry->flags = 0;
+       struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
+       struct usb_host_interface *intf_desc = intf->cur_altsetting;
+       struct usb_endpoint_descriptor *ep_desc;
+       struct data_queue *queue = rt2x00dev->tx;
+       struct usb_endpoint_descriptor *tx_ep_desc = NULL;
+       unsigned int i;
+
+       /*
+        * Walk through all available endpoints to search for "bulk in"
+        * and "bulk out" endpoints. When we find such endpoints collect
+        * the information we need from the descriptor and assign it
+        * to the queue.
+        */
+       for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+               ep_desc = &intf_desc->endpoint[i].desc;
+
+               if (usb_endpoint_is_bulk_in(ep_desc)) {
+                       rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
+               } else if (usb_endpoint_is_bulk_out(ep_desc) &&
+                          (queue != queue_end(rt2x00dev))) {
+                       rt2x00usb_assign_endpoint(queue, ep_desc);
+                       queue = queue_next(queue);
+
+                       tx_ep_desc = ep_desc;
+               }
+       }
+
+       /*
+        * At least 1 endpoint for RX and 1 endpoint for TX must be available.
+        */
+       if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
+               ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
+               return -EPIPE;
+       }
+
+       /*
+        * It might be possible not all queues have a dedicated endpoint.
+        * Loop through all TX queues and copy the endpoint information
+        * which we have gathered from already assigned endpoints.
+        */
+       txall_queue_for_each(rt2x00dev, queue) {
+               if (!queue->usb_endpoint)
+                       rt2x00usb_assign_endpoint(queue, tx_ep_desc);
+       }
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry);
 
 static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
                               struct data_queue *queue)
@@ -443,6 +549,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
        int status;
 
        /*
+        * Find endpoints for each queue
+        */
+       status = rt2x00usb_find_endpoints(rt2x00dev);
+       if (status)
+               goto exit;
+
+       /*
         * Allocate DMA
         */
        queue_for_each(rt2x00dev, queue) {
@@ -532,12 +645,8 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
        rt2x00dev->dev = &usb_intf->dev;
        rt2x00dev->ops = ops;
        rt2x00dev->hw = hw;
-       mutex_init(&rt2x00dev->usb_cache_mutex);
 
-       rt2x00dev->usb_maxpacket =
-           usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
-       if (!rt2x00dev->usb_maxpacket)
-               rt2x00dev->usb_maxpacket = 1;
+       rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
 
        retval = rt2x00usb_alloc_reg(rt2x00dev);
        if (retval)
@@ -595,8 +704,6 @@ int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state)
        if (retval)
                return retval;
 
-       rt2x00usb_free_reg(rt2x00dev);
-
        /*
         * Decrease usbdev refcount.
         */
@@ -610,24 +717,10 @@ int rt2x00usb_resume(struct usb_interface *usb_intf)
 {
        struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       int retval;
 
        usb_get_dev(interface_to_usbdev(usb_intf));
 
-       retval = rt2x00usb_alloc_reg(rt2x00dev);
-       if (retval)
-               return retval;
-
-       retval = rt2x00lib_resume(rt2x00dev);
-       if (retval)
-               goto exit_free_reg;
-
-       return 0;
-
-exit_free_reg:
-       rt2x00usb_free_reg(rt2x00dev);
-
-       return retval;
+       return rt2x00lib_resume(rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_resume);
 #endif /* CONFIG_PM */