diff options
author | Oliver Neukum <oneukum@suse.de> | 2007-05-25 07:40:56 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 19:29:51 -0400 |
commit | 51a2f077c44e559841b09de6da605b4d3ae40dad (patch) | |
tree | 2d4d0064994de2223abac57f7242579649717ae6 /drivers | |
parent | ffcdc18d64d73ecce49c182f969977ae88ff4384 (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.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 102 |
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 @@ | |||
11 | static void urb_destroy(struct kref *kref) | 12 | static 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 | */ | ||
115 | void 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 | } | ||
125 | EXPORT_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 | */ | ||
133 | void 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 | } | ||
158 | EXPORT_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 | */ | ||
543 | void 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 | } | ||
560 | EXPORT_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 | */ | ||
570 | int 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 | } | ||
576 | EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); | ||
577 | |||
481 | EXPORT_SYMBOL(usb_init_urb); | 578 | EXPORT_SYMBOL(usb_init_urb); |
482 | EXPORT_SYMBOL(usb_alloc_urb); | 579 | EXPORT_SYMBOL(usb_alloc_urb); |
483 | EXPORT_SYMBOL(usb_free_urb); | 580 | EXPORT_SYMBOL(usb_free_urb); |
@@ -485,4 +582,3 @@ EXPORT_SYMBOL(usb_get_urb); | |||
485 | EXPORT_SYMBOL(usb_submit_urb); | 582 | EXPORT_SYMBOL(usb_submit_urb); |
486 | EXPORT_SYMBOL(usb_unlink_urb); | 583 | EXPORT_SYMBOL(usb_unlink_urb); |
487 | EXPORT_SYMBOL(usb_kill_urb); | 584 | EXPORT_SYMBOL(usb_kill_urb); |
488 | |||