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 | |
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>
-rw-r--r-- | drivers/usb/core/hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 102 | ||||
-rw-r--r-- | include/linux/usb.h | 22 |
3 files changed, 123 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 | |||
diff --git a/include/linux/usb.h b/include/linux/usb.h index 98e0338664fb..0873c6219efc 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
@@ -1000,11 +1000,26 @@ struct usb_iso_packet_descriptor { | |||
1000 | 1000 | ||
1001 | struct urb; | 1001 | struct urb; |
1002 | 1002 | ||
1003 | struct usb_anchor { | ||
1004 | struct list_head urb_list; | ||
1005 | wait_queue_head_t wait; | ||
1006 | spinlock_t lock; | ||
1007 | }; | ||
1008 | |||
1009 | static inline void init_usb_anchor(struct usb_anchor *anchor) | ||
1010 | { | ||
1011 | INIT_LIST_HEAD(&anchor->urb_list); | ||
1012 | init_waitqueue_head(&anchor->wait); | ||
1013 | spin_lock_init(&anchor->lock); | ||
1014 | } | ||
1015 | |||
1003 | typedef void (*usb_complete_t)(struct urb *); | 1016 | typedef void (*usb_complete_t)(struct urb *); |
1004 | 1017 | ||
1005 | /** | 1018 | /** |
1006 | * struct urb - USB Request Block | 1019 | * struct urb - USB Request Block |
1007 | * @urb_list: For use by current owner of the URB. | 1020 | * @urb_list: For use by current owner of the URB. |
1021 | * @anchor_list: membership in the list of an anchor | ||
1022 | * @anchor: to anchor URBs to a common mooring | ||
1008 | * @pipe: Holds endpoint number, direction, type, and more. | 1023 | * @pipe: Holds endpoint number, direction, type, and more. |
1009 | * Create these values with the eight macros available; | 1024 | * Create these values with the eight macros available; |
1010 | * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" | 1025 | * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" |
@@ -1177,6 +1192,8 @@ struct urb | |||
1177 | /* public: documented fields in the urb that can be used by drivers */ | 1192 | /* public: documented fields in the urb that can be used by drivers */ |
1178 | struct list_head urb_list; /* list head for use by the urb's | 1193 | struct list_head urb_list; /* list head for use by the urb's |
1179 | * current owner */ | 1194 | * current owner */ |
1195 | struct list_head anchor_list; /* the URB may be anchored by the driver */ | ||
1196 | struct usb_anchor *anchor; | ||
1180 | struct usb_device *dev; /* (in) pointer to associated device */ | 1197 | struct usb_device *dev; /* (in) pointer to associated device */ |
1181 | unsigned int pipe; /* (in) pipe information */ | 1198 | unsigned int pipe; /* (in) pipe information */ |
1182 | int status; /* (return) non-ISO status */ | 1199 | int status; /* (return) non-ISO status */ |
@@ -1312,6 +1329,11 @@ extern struct urb *usb_get_urb(struct urb *urb); | |||
1312 | extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags); | 1329 | extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags); |
1313 | extern int usb_unlink_urb(struct urb *urb); | 1330 | extern int usb_unlink_urb(struct urb *urb); |
1314 | extern void usb_kill_urb(struct urb *urb); | 1331 | extern void usb_kill_urb(struct urb *urb); |
1332 | extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); | ||
1333 | extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); | ||
1334 | extern void usb_unanchor_urb(struct urb *urb); | ||
1335 | extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, | ||
1336 | unsigned int timeout); | ||
1315 | 1337 | ||
1316 | void *usb_buffer_alloc (struct usb_device *dev, size_t size, | 1338 | void *usb_buffer_alloc (struct usb_device *dev, size_t size, |
1317 | gfp_t mem_flags, dma_addr_t *dma); | 1339 | gfp_t mem_flags, dma_addr_t *dma); |