summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-09-10 11:33:05 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 14:55:26 -0700
commit95cf82f99cfbd697c15572c444bd4f54f19745b0 (patch)
tree87d0bd6c842922231f5177522b6635532416d206 /drivers/usb
parent5ad4f71e2f19a06f738463da1f09ea7fda3a3db2 (diff)
downloadlinux-95cf82f99cfbd697c15572c444bd4f54f19745b0.tar.bz2
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')
-rw-r--r--drivers/usb/core/hcd.c48
-rw-r--r--drivers/usb/core/hcd.h4
-rw-r--r--drivers/usb/core/message.c3
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);
/*-------------------------------------------------------------------------*/
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example: a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely. The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
*/
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
+ if (!ep)
+ return;
might_sleep();
hcd = bus_to_hcd(udev->bus);
- /* ep is already gone from udev->ep_{in,out}[]; no more submits */
+ /* No more submits can occur */
rescan:
spin_lock_irq(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
@@ -1345,18 +1343,7 @@ rescan:
}
spin_unlock_irq(&hcd_urb_list_lock);
- /* synchronize with the hardware, so old configuration state
- * clears out immediately (and will be freed).
- */
- if (hcd->driver->endpoint_disable)
- hcd->driver->endpoint_disable (hcd, ep);
-
- /* Wait until the endpoint queue is completely empty. Most HCDs
- * will have done this already in their endpoint_disable method,
- * but some might not. And there could be root-hub control URBs
- * still pending since they aren't affected by the HCDs'
- * endpoint_disable methods.
- */
+ /* Wait until the endpoint queue is completely empty */
while (!list_empty (&ep->urb_list)) {
spin_lock_irq(&hcd_urb_list_lock);
@@ -1376,6 +1363,25 @@ rescan:
}
}
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
+ * have been called previously. Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example: a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd;
+
+ might_sleep();
+ hcd = bus_to_hcd(udev->bus);
+ if (hcd->driver->endpoint_disable)
+ hcd->driver->endpoint_disable(hcd, ep);
+}
+
/*-------------------------------------------------------------------------*/
/* 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);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
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)
}
if (ep) {
ep->enabled = 0;
- usb_hcd_endpoint_disable(dev, ep);
+ usb_hcd_flush_endpoint(dev, ep);
+ usb_hcd_disable_endpoint(dev, ep);
}
}