diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-09-10 11:33:05 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 17:55:26 -0400 |
commit | 95cf82f99cfbd697c15572c444bd4f54f19745b0 (patch) | |
tree | 87d0bd6c842922231f5177522b6635532416d206 /drivers/usb/core | |
parent | 5ad4f71e2f19a06f738463da1f09ea7fda3a3db2 (diff) |
USB: break apart flush_endpoint and disable_endpoint
This patch (as988) breaks usb_hcd_endpoint_disable() apart into two
routines. The first, usb_hcd_flush_endpoint() does the -ESHUTDOWN
unlinking of all URBs in the endpoint's queue and waits for them to
complete. The second, usb_hcd_disable_endpoint() -- renamed for
better grammatical style -- merely calls the HCD's endpoint_disable
method. The changeover is easy because the routine currently has only
one caller.
This separation of function will be exploited in the following patch:
When a device is suspended, the core will be able to cancel all
outstanding URBs for that device while leaving the HCD's
endpoint-related data structures intact for later.
As an added benefit, HCDs no longer need to check for existing URBs in
their endpoint_disable methods. It is now guaranteed that there will
be none.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/hcd.c | 48 | ||||
-rw-r--r-- | drivers/usb/core/hcd.h | 4 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 3 |
3 files changed, 32 insertions, 23 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1c5e5d35e08d..e5874e8b8cbc 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1289,24 +1289,22 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); | |||
1289 | 1289 | ||
1290 | /*-------------------------------------------------------------------------*/ | 1290 | /*-------------------------------------------------------------------------*/ |
1291 | 1291 | ||
1292 | /* disables the endpoint: cancels any pending urbs, then synchronizes with | 1292 | /* Cancel all URBs pending on this endpoint and wait for the endpoint's |
1293 | * the hcd to make sure all endpoint state is gone from hardware, and then | 1293 | * queue to drain completely. The caller must first insure that no more |
1294 | * waits until the endpoint's queue is completely drained. use for | 1294 | * URBs can be submitted for this endpoint. |
1295 | * set_configuration, set_interface, driver removal, physical disconnect. | ||
1296 | * | ||
1297 | * example: a qh stored in ep->hcpriv, holding state related to endpoint | ||
1298 | * type, maxpacket size, toggle, halt status, and scheduling. | ||
1299 | */ | 1295 | */ |
1300 | void usb_hcd_endpoint_disable (struct usb_device *udev, | 1296 | void usb_hcd_flush_endpoint(struct usb_device *udev, |
1301 | struct usb_host_endpoint *ep) | 1297 | struct usb_host_endpoint *ep) |
1302 | { | 1298 | { |
1303 | struct usb_hcd *hcd; | 1299 | struct usb_hcd *hcd; |
1304 | struct urb *urb; | 1300 | struct urb *urb; |
1305 | 1301 | ||
1302 | if (!ep) | ||
1303 | return; | ||
1306 | might_sleep(); | 1304 | might_sleep(); |
1307 | hcd = bus_to_hcd(udev->bus); | 1305 | hcd = bus_to_hcd(udev->bus); |
1308 | 1306 | ||
1309 | /* ep is already gone from udev->ep_{in,out}[]; no more submits */ | 1307 | /* No more submits can occur */ |
1310 | rescan: | 1308 | rescan: |
1311 | spin_lock_irq(&hcd_urb_list_lock); | 1309 | spin_lock_irq(&hcd_urb_list_lock); |
1312 | list_for_each_entry (urb, &ep->urb_list, urb_list) { | 1310 | list_for_each_entry (urb, &ep->urb_list, urb_list) { |
@@ -1345,18 +1343,7 @@ rescan: | |||
1345 | } | 1343 | } |
1346 | spin_unlock_irq(&hcd_urb_list_lock); | 1344 | spin_unlock_irq(&hcd_urb_list_lock); |
1347 | 1345 | ||
1348 | /* synchronize with the hardware, so old configuration state | 1346 | /* Wait until the endpoint queue is completely empty */ |
1349 | * clears out immediately (and will be freed). | ||
1350 | */ | ||
1351 | if (hcd->driver->endpoint_disable) | ||
1352 | hcd->driver->endpoint_disable (hcd, ep); | ||
1353 | |||
1354 | /* Wait until the endpoint queue is completely empty. Most HCDs | ||
1355 | * will have done this already in their endpoint_disable method, | ||
1356 | * but some might not. And there could be root-hub control URBs | ||
1357 | * still pending since they aren't affected by the HCDs' | ||
1358 | * endpoint_disable methods. | ||
1359 | */ | ||
1360 | while (!list_empty (&ep->urb_list)) { | 1347 | while (!list_empty (&ep->urb_list)) { |
1361 | spin_lock_irq(&hcd_urb_list_lock); | 1348 | spin_lock_irq(&hcd_urb_list_lock); |
1362 | 1349 | ||
@@ -1376,6 +1363,25 @@ rescan: | |||
1376 | } | 1363 | } |
1377 | } | 1364 | } |
1378 | 1365 | ||
1366 | /* Disables the endpoint: synchronizes with the hcd to make sure all | ||
1367 | * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must | ||
1368 | * have been called previously. Use for set_configuration, set_interface, | ||
1369 | * driver removal, physical disconnect. | ||
1370 | * | ||
1371 | * example: a qh stored in ep->hcpriv, holding state related to endpoint | ||
1372 | * type, maxpacket size, toggle, halt status, and scheduling. | ||
1373 | */ | ||
1374 | void usb_hcd_disable_endpoint(struct usb_device *udev, | ||
1375 | struct usb_host_endpoint *ep) | ||
1376 | { | ||
1377 | struct usb_hcd *hcd; | ||
1378 | |||
1379 | might_sleep(); | ||
1380 | hcd = bus_to_hcd(udev->bus); | ||
1381 | if (hcd->driver->endpoint_disable) | ||
1382 | hcd->driver->endpoint_disable(hcd, ep); | ||
1383 | } | ||
1384 | |||
1379 | /*-------------------------------------------------------------------------*/ | 1385 | /*-------------------------------------------------------------------------*/ |
1380 | 1386 | ||
1381 | /* called in any context */ | 1387 | /* called in any context */ |
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 0fc7b95259f5..1396141274f1 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h | |||
@@ -219,7 +219,9 @@ extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); | |||
219 | extern int usb_hcd_unlink_urb (struct urb *urb, int status); | 219 | extern int usb_hcd_unlink_urb (struct urb *urb, int status); |
220 | extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, | 220 | extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, |
221 | int status); | 221 | int status); |
222 | extern void usb_hcd_endpoint_disable (struct usb_device *udev, | 222 | extern void usb_hcd_flush_endpoint(struct usb_device *udev, |
223 | struct usb_host_endpoint *ep); | ||
224 | extern void usb_hcd_disable_endpoint(struct usb_device *udev, | ||
223 | struct usb_host_endpoint *ep); | 225 | struct usb_host_endpoint *ep); |
224 | extern int usb_hcd_get_frame_number (struct usb_device *udev); | 226 | extern int usb_hcd_get_frame_number (struct usb_device *udev); |
225 | 227 | ||
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index d638375e22e7..98fcddba6908 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -1017,7 +1017,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) | |||
1017 | } | 1017 | } |
1018 | if (ep) { | 1018 | if (ep) { |
1019 | ep->enabled = 0; | 1019 | ep->enabled = 0; |
1020 | usb_hcd_endpoint_disable(dev, ep); | 1020 | usb_hcd_flush_endpoint(dev, ep); |
1021 | usb_hcd_disable_endpoint(dev, ep); | ||
1021 | } | 1022 | } |
1022 | } | 1023 | } |
1023 | 1024 | ||