From 56e3de9c7a56c018fa440a90341163b089a7ca5d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 19 Sep 2010 10:42:09 -0700 Subject: [PATCH] compat: backport some usb urb functions These functions have to be backported, because they were thread-unsafe. This is commit b3e670443b7fb8a2d29831b62b44a039c283e351 in mainline kernel. CC: Christian Lamparter Signed-off-by: Hauke Mehrtens --- compat/Makefile | 1 + compat/compat-2.6.28.c | 56 ------------------- compat/compat-2.6.36.c | 100 ++++++++++++++++++++++++++++++++++ include/linux/compat-2.6.28.h | 2 - include/linux/compat-2.6.36.h | 12 ++++ 5 files changed, 113 insertions(+), 58 deletions(-) create mode 100644 compat/compat-2.6.36.c diff --git a/compat/Makefile b/compat/Makefile index b067be272335..1f053f2cb42c 100644 --- a/compat/Makefile +++ b/compat/Makefile @@ -27,4 +27,5 @@ compat-$(CONFIG_COMPAT_KERNEL_31) += compat-2.6.31.o compat-$(CONFIG_COMPAT_KERNEL_32) += compat-2.6.32.o compat-$(CONFIG_COMPAT_KERNEL_33) += compat-2.6.33.o compat-$(CONFIG_COMPAT_KERNEL_35) += compat-2.6.35.o +compat-$(CONFIG_COMPAT_KERNEL_36) += compat-2.6.36.o compat-$(CONFIG_COMPAT_KERNEL_37) += compat-2.6.37.o diff --git a/compat/compat-2.6.28.c b/compat/compat-2.6.28.c index bfb645a8099d..c11ba409b5b3 100644 --- a/compat/compat-2.6.28.c +++ b/compat/compat-2.6.28.c @@ -224,62 +224,6 @@ void usb_poison_anchored_urbs(struct usb_anchor *anchor) EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs); #endif -/** - * 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 diff --git a/compat/compat-2.6.36.c b/compat/compat-2.6.36.c new file mode 100644 index 000000000000..bd9335d673a9 --- /dev/null +++ b/compat/compat-2.6.36.c @@ -0,0 +1,100 @@ +/* + * Copyright 2010 Hauke Mehrtens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Compatibility file for Linux wireless for kernels 2.6.36. + */ + +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + +#include + +#ifdef CONFIG_COMPAT_USB_URB_THREAD_FIX +/* Callers must hold anchor->lock */ +static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor) +{ + urb->anchor = NULL; + list_del(&urb->anchor_list); + usb_put_urb(urb); + if (list_empty(&anchor->urb_list)) + wake_up(&anchor->wait); +} + +/** + * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse + * @anchor: anchor the requests are bound to + * + * this allows all outstanding URBs to be unlinked starting + * from the back of the queue. This function is asynchronous. + * The unlinking is just tiggered. It may happen after this + * function has returned. + * + * This routine should not be called by a driver after its disconnect + * method has returned. + */ +void compat_usb_unlink_anchored_urbs(struct usb_anchor *anchor) +{ + struct urb *victim; + + while ((victim = usb_get_from_anchor(anchor)) != NULL) { + usb_unlink_urb(victim); + usb_put_urb(victim); + } +} +EXPORT_SYMBOL_GPL(compat_usb_unlink_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 *compat_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); + __usb_unanchor_urb(victim, anchor); + } else { + victim = NULL; + } + spin_unlock_irqrestore(&anchor->lock, flags); + + return victim; +} +EXPORT_SYMBOL_GPL(compat_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 compat_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_unanchor_urb(victim, anchor); + } + spin_unlock_irqrestore(&anchor->lock, flags); +} +EXPORT_SYMBOL_GPL(compat_usb_scuttle_anchored_urbs); +#endif /* CONFIG_COMPAT_USB_URB_THREAD_FIX */ + +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) */ diff --git a/include/linux/compat-2.6.28.h b/include/linux/compat-2.6.28.h index 649fbbc3183c..1de39ad31ac8 100644 --- a/include/linux/compat-2.6.28.h +++ b/include/linux/compat-2.6.28.h @@ -62,8 +62,6 @@ extern void usb_unpoison_urb(struct urb *urb); extern void usb_poison_anchored_urbs(struct usb_anchor *anchor); #endif -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); #endif /* CONFIG_USB */ #endif diff --git a/include/linux/compat-2.6.36.h b/include/linux/compat-2.6.36.h index 5b48215cbd4e..2df34d637188 100644 --- a/include/linux/compat-2.6.36.h +++ b/include/linux/compat-2.6.36.h @@ -5,6 +5,8 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) +#include + #define kparam_block_sysfs_write(a) #define kparam_unblock_sysfs_write(a) @@ -15,6 +17,16 @@ struct va_format { #define device_rename(dev, new_name) device_rename(dev, (char *)new_name) +#ifdef CONFIG_COMPAT_USB_URB_THREAD_FIX +#define usb_scuttle_anchored_urbs(anchor) compat_usb_scuttle_anchored_urbs(anchor) +#define usb_get_from_anchor(anchor) compat_usb_get_from_anchor(anchor) +#define usb_unlink_anchored_urbs(anchor) compat_usb_unlink_anchored_urbs(anchor) + +extern void compat_usb_unlink_anchored_urbs(struct usb_anchor *anchor); +extern struct urb *compat_usb_get_from_anchor(struct usb_anchor *anchor); +extern void compat_usb_scuttle_anchored_urbs(struct usb_anchor *anchor); +#endif + #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) */ #endif /* LINUX_26_36_COMPAT_H */ -- 2.30.2