aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2007-05-25 07:40:56 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:29:51 -0400
commit51a2f077c44e559841b09de6da605b4d3ae40dad (patch)
tree2d4d0064994de2223abac57f7242579649717ae6 /drivers
parentffcdc18d64d73ecce49c182f969977ae88ff4384 (diff)
USB: introduce usb_anchor
- introduction of usb_anchor and its methods Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/hcd.c2
-rw-r--r--drivers/usb/core/urb.c102
2 files changed, 101 insertions, 3 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index c5a2f83991dc..87d6edf11f92 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1410,6 +1410,8 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
1410 } 1410 }
1411 1411
1412 usbmon_urb_complete (&hcd->self, urb); 1412 usbmon_urb_complete (&hcd->self, urb);
1413 usb_unanchor_urb(urb);
1414
1413 /* pass ownership to the completion handler */ 1415 /* pass ownership to the completion handler */
1414 urb->complete (urb); 1416 urb->complete (urb);
1415 atomic_dec (&urb->use_count); 1417 atomic_dec (&urb->use_count);
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 94ea9727ff55..ac4273dddf34 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -4,6 +4,7 @@
4#include <linux/slab.h> 4#include <linux/slab.h>
5#include <linux/init.h> 5#include <linux/init.h>
6#include <linux/usb.h> 6#include <linux/usb.h>
7#include <linux/wait.h>
7#include "hcd.h" 8#include "hcd.h"
8 9
9#define to_urb(d) container_of(d, struct urb, kref) 10#define to_urb(d) container_of(d, struct urb, kref)
@@ -11,6 +12,7 @@
11static void urb_destroy(struct kref *kref) 12static void urb_destroy(struct kref *kref)
12{ 13{
13 struct urb *urb = to_urb(kref); 14 struct urb *urb = to_urb(kref);
15
14 kfree(urb); 16 kfree(urb);
15} 17}
16 18
@@ -34,6 +36,7 @@ void usb_init_urb(struct urb *urb)
34 memset(urb, 0, sizeof(*urb)); 36 memset(urb, 0, sizeof(*urb));
35 kref_init(&urb->kref); 37 kref_init(&urb->kref);
36 spin_lock_init(&urb->lock); 38 spin_lock_init(&urb->lock);
39 INIT_LIST_HEAD(&urb->anchor_list);
37 } 40 }
38} 41}
39 42
@@ -100,8 +103,60 @@ struct urb * usb_get_urb(struct urb *urb)
100 kref_get(&urb->kref); 103 kref_get(&urb->kref);
101 return urb; 104 return urb;
102} 105}
103 106
104 107/**
108 * usb_anchor_urb - anchors an URB while it is processed
109 * @urb: pointer to the urb to anchor
110 * @anchor: pointer to the anchor
111 *
112 * This can be called to have access to URBs which are to be executed
113 * without bothering to track them
114 */
115void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
116{
117 unsigned long flags;
118
119 spin_lock_irqsave(&anchor->lock, flags);
120 usb_get_urb(urb);
121 list_add_tail(&urb->anchor_list, &anchor->urb_list);
122 urb->anchor = anchor;
123 spin_unlock_irqrestore(&anchor->lock, flags);
124}
125EXPORT_SYMBOL_GPL(usb_anchor_urb);
126
127/**
128 * usb_unanchor_urb - unanchors an URB
129 * @urb: pointer to the urb to anchor
130 *
131 * Call this to stop the system keeping track of this URB
132 */
133void usb_unanchor_urb(struct urb *urb)
134{
135 unsigned long flags;
136 struct usb_anchor *anchor;
137
138 if (!urb)
139 return;
140
141 anchor = urb->anchor;
142 if (!anchor)
143 return;
144
145 spin_lock_irqsave(&anchor->lock, flags);
146 if (unlikely(anchor != urb->anchor)) {
147 /* we've lost the race to another thread */
148 spin_unlock_irqrestore(&anchor->lock, flags);
149 return;
150 }
151 urb->anchor = NULL;
152 list_del(&urb->anchor_list);
153 spin_unlock_irqrestore(&anchor->lock, flags);
154 usb_put_urb(urb);
155 if (list_empty(&anchor->urb_list))
156 wake_up(&anchor->wait);
157}
158EXPORT_SYMBOL_GPL(usb_unanchor_urb);
159
105/*-------------------------------------------------------------------*/ 160/*-------------------------------------------------------------------*/
106 161
107/** 162/**
@@ -478,6 +533,48 @@ void usb_kill_urb(struct urb *urb)
478 spin_unlock_irq(&urb->lock); 533 spin_unlock_irq(&urb->lock);
479} 534}
480 535
536/**
537 * usb_kill_anchored_urbs - cancel transfer requests en masse
538 * @anchor: anchor the requests are bound to
539 *
540 * this allows all outstanding URBs to be killed starting
541 * from the back of the queue
542 */
543void usb_kill_anchored_urbs(struct usb_anchor *anchor)
544{
545 struct urb *victim;
546
547 spin_lock_irq(&anchor->lock);
548 while (!list_empty(&anchor->urb_list)) {
549 victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list);
550 /* we must make sure the URB isn't freed before we kill it*/
551 usb_get_urb(victim);
552 spin_unlock_irq(&anchor->lock);
553 /* this will unanchor the URB */
554 usb_kill_urb(victim);
555 usb_put_urb(victim);
556 spin_lock_irq(&anchor->lock);
557 }
558 spin_unlock_irq(&anchor->lock);
559}
560EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
561
562/**
563 * usb_wait_anchor_empty_timeout - wait for an anchor to be unused
564 * @anchor: the anchor you want to become unused
565 * @timeout: how long you are willing to wait in milliseconds
566 *
567 * Call this is you want to be sure all an anchor's
568 * URBs have finished
569 */
570int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
571 unsigned int timeout)
572{
573 return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list),
574 msecs_to_jiffies(timeout));
575}
576EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
577
481EXPORT_SYMBOL(usb_init_urb); 578EXPORT_SYMBOL(usb_init_urb);
482EXPORT_SYMBOL(usb_alloc_urb); 579EXPORT_SYMBOL(usb_alloc_urb);
483EXPORT_SYMBOL(usb_free_urb); 580EXPORT_SYMBOL(usb_free_urb);
@@ -485,4 +582,3 @@ EXPORT_SYMBOL(usb_get_urb);
485EXPORT_SYMBOL(usb_submit_urb); 582EXPORT_SYMBOL(usb_submit_urb);
486EXPORT_SYMBOL(usb_unlink_urb); 583EXPORT_SYMBOL(usb_unlink_urb);
487EXPORT_SYMBOL(usb_kill_urb); 584EXPORT_SYMBOL(usb_kill_urb);
488