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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
5ad4f71e2f
commit
95cf82f99c
@@ -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:
|
|||||||
}
|
}
|
||||||
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:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user