From a2c9d9009ff5692dbb517df97f328fd67940830a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 15 Jul 2009 16:40:52 -0700 Subject: [PATCH] Backport USB stuff to allow ar9170 on 2.6.27 Only compile tested. Signed-off-by: Luis R. Rodriguez --- compat/compat-2.6.29.c | 143 +++++++++++++++++++++++++++++++++++++++++ compat/compat-2.6.29.h | 8 +++ config.mk | 7 +- 3 files changed, 152 insertions(+), 6 deletions(-) diff --git a/compat/compat-2.6.29.c b/compat/compat-2.6.29.c index e0f1e302cf12..8c66d5237ea7 100644 --- a/compat/compat-2.6.29.c +++ b/compat/compat-2.6.29.c @@ -12,7 +12,150 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) +#include + /* 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) */ diff --git a/compat/compat-2.6.29.h b/compat/compat-2.6.29.h index f4086e92e6a9..ce2cfc6ffda2 100644 --- a/compat/compat-2.6.29.h +++ b/compat/compat-2.6.29.h @@ -8,6 +8,14 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) #include +#include + +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 diff --git a/config.mk b/config.mk index 0dc2fe9ff8b0..4e1c1a36168c 100644 --- 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 -- 2.30.2