aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-hcd.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-08-08 11:48:02 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:55:10 -0400
commite9df41c5c5899259541dc928872cad4d07b82076 (patch)
tree12bb0917eeecbe62b2b5d3dc576806c7f2728550 /drivers/usb/host/ohci-hcd.c
parentb0e396e3097ce4914c643bc3f0c2fe0098f551eb (diff)
USB: make HCDs responsible for managing endpoint queues
This patch (as954) implements a suggestion of David Brownell's. Now the host controller drivers are responsible for linking and unlinking URBs to/from their endpoint queues. This eliminates the possiblity of strange situations where usbcore thinks an URB is linked but the HCD thinks it isn't. It also means HCDs no longer have to check for URBs being dequeued before they were fully enqueued. In addition to the core changes, this requires changing every host controller driver and the root-hub URB handler. For the most part the required changes are fairly small; drivers have to call usb_hcd_link_urb_to_ep() in their urb_enqueue method, usb_hcd_check_unlink_urb() in their urb_dequeue method, and usb_hcd_unlink_urb_from_ep() before giving URBs back. A few HCDs make matters more complicated by the way they split up the flow of control. In addition some method interfaces get changed. The endpoint argument for urb_enqueue is now redundant so it is removed. The unlink status is required by usb_hcd_check_unlink_urb(), so it has been added to urb_dequeue. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: David Brownell <david-b@pacbell.net> CC: Olav Kongas <ok@artecdesign.ee> CC: Tony Olech <tony.olech@elandigitalsystems.com> CC: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r--drivers/usb/host/ohci-hcd.c32
1 files changed, 14 insertions, 18 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index d673cb9c36b1..6b06ab69938f 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -117,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
117 */ 117 */
118static int ohci_urb_enqueue ( 118static int ohci_urb_enqueue (
119 struct usb_hcd *hcd, 119 struct usb_hcd *hcd,
120 struct usb_host_endpoint *ep,
121 struct urb *urb, 120 struct urb *urb,
122 gfp_t mem_flags 121 gfp_t mem_flags
123) { 122) {
@@ -134,7 +133,7 @@ static int ohci_urb_enqueue (
134#endif 133#endif
135 134
136 /* every endpoint has a ed, locate and maybe (re)initialize it */ 135 /* every endpoint has a ed, locate and maybe (re)initialize it */
137 if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) 136 if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
138 return -ENOMEM; 137 return -ENOMEM;
139 138
140 /* for the private part of the URB we need the number of TDs (size) */ 139 /* for the private part of the URB we need the number of TDs (size) */
@@ -199,22 +198,17 @@ static int ohci_urb_enqueue (
199 retval = -ENODEV; 198 retval = -ENODEV;
200 goto fail; 199 goto fail;
201 } 200 }
202 201 retval = usb_hcd_link_urb_to_ep(hcd, urb);
203 /* in case of unlink-during-submit */ 202 if (retval)
204 spin_lock (&urb->lock);
205 if (urb->status != -EINPROGRESS) {
206 spin_unlock (&urb->lock);
207 urb->hcpriv = urb_priv;
208 finish_urb (ohci, urb);
209 retval = 0;
210 goto fail; 203 goto fail;
211 }
212 204
213 /* schedule the ed if needed */ 205 /* schedule the ed if needed */
214 if (ed->state == ED_IDLE) { 206 if (ed->state == ED_IDLE) {
215 retval = ed_schedule (ohci, ed); 207 retval = ed_schedule (ohci, ed);
216 if (retval < 0) 208 if (retval < 0) {
217 goto fail0; 209 usb_hcd_unlink_urb_from_ep(hcd, urb);
210 goto fail;
211 }
218 if (ed->type == PIPE_ISOCHRONOUS) { 212 if (ed->type == PIPE_ISOCHRONOUS) {
219 u16 frame = ohci_frame_no(ohci); 213 u16 frame = ohci_frame_no(ohci);
220 214
@@ -238,8 +232,6 @@ static int ohci_urb_enqueue (
238 urb->hcpriv = urb_priv; 232 urb->hcpriv = urb_priv;
239 td_submit_urb (ohci, urb); 233 td_submit_urb (ohci, urb);
240 234
241fail0:
242 spin_unlock (&urb->lock);
243fail: 235fail:
244 if (retval) 236 if (retval)
245 urb_free_priv (ohci, urb_priv); 237 urb_free_priv (ohci, urb_priv);
@@ -253,17 +245,21 @@ fail:
253 * asynchronously, and we might be dealing with an urb that's 245 * asynchronously, and we might be dealing with an urb that's
254 * partially transferred, or an ED with other urbs being unlinked. 246 * partially transferred, or an ED with other urbs being unlinked.
255 */ 247 */
256static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) 248static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
257{ 249{
258 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 250 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
259 unsigned long flags; 251 unsigned long flags;
252 int rc;
260 253
261#ifdef OHCI_VERBOSE_DEBUG 254#ifdef OHCI_VERBOSE_DEBUG
262 urb_print (urb, "UNLINK", 1); 255 urb_print (urb, "UNLINK", 1);
263#endif 256#endif
264 257
265 spin_lock_irqsave (&ohci->lock, flags); 258 spin_lock_irqsave (&ohci->lock, flags);
266 if (HC_IS_RUNNING(hcd->state)) { 259 rc = usb_hcd_check_unlink_urb(hcd, urb, status);
260 if (rc) {
261 ; /* Do nothing */
262 } else if (HC_IS_RUNNING(hcd->state)) {
267 urb_priv_t *urb_priv; 263 urb_priv_t *urb_priv;
268 264
269 /* Unless an IRQ completed the unlink while it was being 265 /* Unless an IRQ completed the unlink while it was being
@@ -284,7 +280,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
284 finish_urb (ohci, urb); 280 finish_urb (ohci, urb);
285 } 281 }
286 spin_unlock_irqrestore (&ohci->lock, flags); 282 spin_unlock_irqrestore (&ohci->lock, flags);
287 return 0; 283 return rc;
288} 284}
289 285
290/*-------------------------------------------------------------------------*/ 286/*-------------------------------------------------------------------------*/