compat: backport some usb urb functions
authorHauke Mehrtens <hauke@hauke-m.de>
Sun, 19 Sep 2010 17:42:09 +0000 (10:42 -0700)
committerLuis R. Rodriguez <lrodriguez@atheros.com>
Mon, 20 Sep 2010 15:14:59 +0000 (08:14 -0700)
These functions have to be backported, because they were thread-unsafe.
This is commit b3e670443b7fb8a2d29831b62b44a039c283e351 in mainline kernel.

CC: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
compat/Makefile
compat/compat-2.6.28.c
compat/compat-2.6.36.c [new file with mode: 0644]
include/linux/compat-2.6.28.h
include/linux/compat-2.6.36.h

index b067be2..1f053f2 100644 (file)
@@ -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
index bfb645a..c11ba40 100644 (file)
@@ -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 (file)
index 0000000..bd9335d
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010    Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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 <linux/compat.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
+
+#include <linux/usb.h>
+
+#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) */
index 649fbbc..1de39ad 100644 (file)
@@ -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
index 5b48215..2df34d6 100644 (file)
@@ -5,6 +5,8 @@
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36))
 
+#include <linux/usb.h>
+
 #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 */