Backport USB stuff to allow ar9170 on 2.6.27
authorLuis R. Rodriguez <lrodriguez@atheros.com>
Wed, 15 Jul 2009 23:40:52 +0000 (16:40 -0700)
committerLuis R. Rodriguez <lrodriguez@atheros.com>
Wed, 15 Jul 2009 23:40:52 +0000 (16:40 -0700)
Only compile tested.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
compat/compat-2.6.29.c
compat/compat-2.6.29.h
config.mk

index e0f1e302cf124e490e4ec19424f213c38ab525a0..8c66d5237ea7dc2e2e337b69cb196e9655f17d01 100644 (file)
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
 
+#include <linux/usb.h>
+
 /* 2.6.29 compat code goes here */
 
+/*
+ * Compat-wireless notes for USB backport stuff:
+ *
+ * urb->reject exists on 2.6.27, the poison/unpoison helpers
+ * did not though. The anchor poison does not exist so we cannot use them.
+ *
+ * USB anchor poising seems to exist to prevent future driver sumbissions
+ * of usb_anchor_urb() to an anchor marked as poisoned. For older kernels
+ * we cannot use that, so new usb_anchor_urb()s will be anchored. The down
+ * side to this should be submission of URBs will continue being anchored
+ * on an anchor instead of having them being rejected immediately when the
+ * driver realized we needed to stop. For ar9170 we poison URBs upon the
+ * ar9170 mac80211 stop callback(), don't think this should be so bad.
+ * It mean there is period of time in older kernels for which we continue
+ * to anchor new URBs to a known stopped anchor. We have two anchors
+ * (TX, and RX)
+ */
+
+/**
+ * usb_poison_anchored_urbs - cease all traffic from an anchor
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be poisoned starting
+ * from the back of the queue. Newly added URBs will also be
+ * poisoned
+ *
+ * This routine should not be called by a driver after its disconnect
+ * method has returned.
+ */
+void usb_poison_anchored_urbs(struct usb_anchor *anchor)
+{
+       struct urb *victim;
+
+       spin_lock_irq(&anchor->lock);
+       // anchor->poisoned = 1; /* XXX: Cannot backport */
+       while (!list_empty(&anchor->urb_list)) {
+               victim = list_entry(anchor->urb_list.prev, struct urb,
+                                   anchor_list);
+               /* we must make sure the URB isn't freed before we kill it*/
+               usb_get_urb(victim);
+               spin_unlock_irq(&anchor->lock);
+               /* this will unanchor the URB */
+               usb_poison_urb(victim);
+               usb_put_urb(victim);
+               spin_lock_irq(&anchor->lock);
+       }
+       spin_unlock_irq(&anchor->lock);
+}
+EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
+
+/**
+ * usb_unpoison_anchored_urbs - let an anchor be used successfully again
+ * @anchor: anchor the requests are bound to
+ *
+ * Reverses the effect of usb_poison_anchored_urbs
+ * the anchor can be used normally after it returns
+ */
+void usb_unpoison_anchored_urbs(struct usb_anchor *anchor)
+{
+       unsigned long flags;
+       struct urb *lazarus;
+
+       spin_lock_irqsave(&anchor->lock, flags);
+       list_for_each_entry(lazarus, &anchor->urb_list, anchor_list) {
+               usb_unpoison_urb(lazarus);
+       }
+       //anchor->poisoned = 0; /* XXX: cannot backport */
+       spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);
+
+/**
+ * usb_get_from_anchor - get an anchor's oldest urb
+ * @anchor: the anchor whose urb you want
+ *
+ * this will take the oldest urb from an anchor,
+ * unanchor and return it
+ */
+struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
+{
+       struct urb *victim;
+       unsigned long flags;
+
+       spin_lock_irqsave(&anchor->lock, flags);
+       if (!list_empty(&anchor->urb_list)) {
+               victim = list_entry(anchor->urb_list.next, struct urb,
+                                   anchor_list);
+               usb_get_urb(victim);
+               spin_unlock_irqrestore(&anchor->lock, flags);
+               usb_unanchor_urb(victim);
+       } else {
+               spin_unlock_irqrestore(&anchor->lock, flags);
+               victim = NULL;
+       }
+
+       return victim;
+}
+
+EXPORT_SYMBOL_GPL(usb_get_from_anchor);
+
+/**
+ * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs
+ * @anchor: the anchor whose urbs you want to unanchor
+ *
+ * use this to get rid of all an anchor's urbs
+ */
+void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
+{
+       struct urb *victim;
+       unsigned long flags;
+
+       spin_lock_irqsave(&anchor->lock, flags);
+       while (!list_empty(&anchor->urb_list)) {
+               victim = list_entry(anchor->urb_list.prev, struct urb,
+                                   anchor_list);
+               usb_get_urb(victim);
+               spin_unlock_irqrestore(&anchor->lock, flags);
+               /* this may free the URB */
+               usb_unanchor_urb(victim);
+               usb_put_urb(victim);
+               spin_lock_irqsave(&anchor->lock, flags);
+       }
+       spin_unlock_irqrestore(&anchor->lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs);
+
+/**
+ * usb_anchor_empty - is an anchor empty
+ * @anchor: the anchor you want to query
+ *
+ * returns 1 if the anchor has no urbs associated with it
+ */
+int usb_anchor_empty(struct usb_anchor *anchor)
+{
+       return list_empty(&anchor->urb_list);
+}
+
+EXPORT_SYMBOL_GPL(usb_anchor_empty);
+
+
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) */
 
index f4086e92e6a9d6b6eda2d3c9641b010413745ffa..ce2cfc6ffda2d2048f49fcc6286ad7502f685c5e 100644 (file)
@@ -8,6 +8,14 @@
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
 
 #include <linux/skbuff.h>
+#include <linux/usb.h>
+
+extern void usb_poison_anchored_urbs(struct usb_anchor *anchor);
+extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor);
+
+extern struct urb *usb_get_from_anchor(struct usb_anchor *anchor);
+extern void usb_scuttle_anchored_urbs(struct usb_anchor *anchor);
+extern int usb_anchor_empty(struct usb_anchor *anchor);
 
 /**
  *     skb_queue_is_first - check if skb is the first entry in the queue
index 0dc2fe9ff8b08723bf1ca522901e3c89433fe76d..4e1c1a36168c74696df26813e089013c5d260f81 100644 (file)
--- a/config.mk
+++ b/config.mk
@@ -273,12 +273,7 @@ CONFIG_RTL8187=m
 
 CONFIG_AT76C50X_USB=m
 
-# Activate AR9170 support only on kernel >= 2.6.29.
-# You need to backport:
-# * usb_get_from_anchor()
-# * usb_poison_anchored_urbs()
-# * usb_unpoison_anchored_urbs()
-ifeq ($(shell test $(KERNEL_SUBLEVEL) -ge 29 && echo yes),yes)
+ifeq ($(shell test $(KERNEL_SUBLEVEL) -ge 27 && echo yes),yes)
 CONFIG_AR9170_USB=m
 CONFIG_AR9170_LEDS=y
 endif