Commit 95cf82f9 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 5ad4f71e
...@@ -1289,24 +1289,22 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb); ...@@ -1289,24 +1289,22 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* disables the endpoint: cancels any pending urbs, then synchronizes with /* Cancel all URBs pending on this endpoint and wait for the endpoint's
* the hcd to make sure all endpoint state is gone from hardware, and then * queue to drain completely. The caller must first insure that no more
* waits until the endpoint's queue is completely drained. use for * URBs can be submitted for this endpoint.
* 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_endpoint_disable (struct usb_device *udev, void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep) struct usb_host_endpoint *ep)
{ {
struct usb_hcd *hcd; struct usb_hcd *hcd;
struct urb *urb; struct urb *urb;
if (!ep)
return;
might_sleep(); might_sleep();
hcd = bus_to_hcd(udev->bus); hcd = bus_to_hcd(udev->bus);
/* ep is already gone from udev->ep_{in,out}[]; no more submits */ /* No more submits can occur */
rescan: rescan:
spin_lock_irq(&hcd_urb_list_lock); spin_lock_irq(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) { list_for_each_entry (urb, &ep->urb_list, urb_list) {
...@@ -1345,18 +1343,7 @@ rescan: ...@@ -1345,18 +1343,7 @@ rescan:
} }
spin_unlock_irq(&hcd_urb_list_lock); spin_unlock_irq(&hcd_urb_list_lock);
/* synchronize with the hardware, so old configuration state /* Wait until the endpoint queue is completely empty */
* 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.
*/
while (!list_empty (&ep->urb_list)) { while (!list_empty (&ep->urb_list)) {
spin_lock_irq(&hcd_urb_list_lock); spin_lock_irq(&hcd_urb_list_lock);
...@@ -1376,6 +1363,25 @@ rescan: ...@@ -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 */ /* called in any context */
......
...@@ -219,7 +219,9 @@ extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags); ...@@ -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 int usb_hcd_unlink_urb (struct urb *urb, int status);
extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
int status); 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); struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev); extern int usb_hcd_get_frame_number (struct usb_device *udev);
......
...@@ -1017,7 +1017,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ...@@ -1017,7 +1017,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
} }
if (ep) { if (ep) {
ep->enabled = 0; ep->enabled = 0;
usb_hcd_endpoint_disable(dev, ep); usb_hcd_flush_endpoint(dev, ep);
usb_hcd_disable_endpoint(dev, ep);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment