mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 02:34:01 +08:00
[PATCH] usbcore: port reset for composite devices
This patch (as699) adds usb_reset_composite_device(), a routine for sending a USB port reset to a device with multiple interfaces owned by different drivers. Drivers are notified about impending and completed resets through two new methods in the usb_driver structure. The patch modifieds the usbfs ioctl code to make it use the new routine instead of usb_reset_device(). Follow-up patches will modify the hub, usb-storage, and usbhid drivers so they can utilize this new API. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
efcaa20525
commit
79efa097e7
@ -823,8 +823,7 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)
|
||||
|
||||
static int proc_resetdevice(struct dev_state *ps)
|
||||
{
|
||||
return usb_reset_device(ps->dev);
|
||||
|
||||
return usb_reset_composite_device(ps->dev, NULL);
|
||||
}
|
||||
|
||||
static int proc_setintf(struct dev_state *ps, void __user *arg)
|
||||
|
@ -3007,9 +3007,9 @@ static int config_descriptors_changed(struct usb_device *udev)
|
||||
* usb_reset_device - perform a USB port reset to reinitialize a device
|
||||
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
|
||||
*
|
||||
* WARNING - don't reset any device unless drivers for all of its
|
||||
* interfaces are expecting that reset! Maybe some driver->reset()
|
||||
* method should eventually help ensure sufficient cooperation.
|
||||
* WARNING - don't use this routine to reset a composite device
|
||||
* (one with multiple interfaces owned by separate drivers)!
|
||||
* Use usb_reset_composite_device() instead.
|
||||
*
|
||||
* Do a port reset, reassign the device's address, and establish its
|
||||
* former operating configuration. If the reset fails, or the device's
|
||||
@ -3125,3 +3125,81 @@ re_enumerate:
|
||||
hub_port_logical_disconnect(parent_hub, port1);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_reset_composite_device - warn interface drivers and perform a USB port reset
|
||||
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
|
||||
* @iface: interface bound to the driver making the request (optional)
|
||||
*
|
||||
* Warns all drivers bound to registered interfaces (using their pre_reset
|
||||
* method), performs the port reset, and then lets the drivers know that
|
||||
* the reset is over (using their post_reset method).
|
||||
*
|
||||
* Return value is the same as for usb_reset_device().
|
||||
*
|
||||
* The caller must own the device lock. For example, it's safe to use
|
||||
* this from a driver probe() routine after downloading new firmware.
|
||||
* For calls that might not occur during probe(), drivers should lock
|
||||
* the device using usb_lock_device_for_reset().
|
||||
*
|
||||
* The interface locks are acquired during the pre_reset stage and released
|
||||
* during the post_reset stage. However if iface is not NULL and is
|
||||
* currently being probed, we assume that the caller already owns its
|
||||
* lock.
|
||||
*/
|
||||
int usb_reset_composite_device(struct usb_device *udev,
|
||||
struct usb_interface *iface)
|
||||
{
|
||||
int ret;
|
||||
struct usb_host_config *config = udev->actconfig;
|
||||
|
||||
if (udev->state == USB_STATE_NOTATTACHED ||
|
||||
udev->state == USB_STATE_SUSPENDED) {
|
||||
dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
|
||||
udev->state);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iface && iface->condition != USB_INTERFACE_BINDING)
|
||||
iface = NULL;
|
||||
|
||||
if (config) {
|
||||
int i;
|
||||
struct usb_interface *cintf;
|
||||
struct usb_driver *drv;
|
||||
|
||||
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||||
cintf = config->interface[i];
|
||||
if (cintf != iface)
|
||||
down(&cintf->dev.sem);
|
||||
if (device_is_registered(&cintf->dev) &&
|
||||
cintf->dev.driver) {
|
||||
drv = to_usb_driver(cintf->dev.driver);
|
||||
if (drv->pre_reset)
|
||||
(drv->pre_reset)(cintf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = usb_reset_device(udev);
|
||||
|
||||
if (config) {
|
||||
int i;
|
||||
struct usb_interface *cintf;
|
||||
struct usb_driver *drv;
|
||||
|
||||
for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
|
||||
cintf = config->interface[i];
|
||||
if (device_is_registered(&cintf->dev) &&
|
||||
cintf->dev.driver) {
|
||||
drv = to_usb_driver(cintf->dev.driver);
|
||||
if (drv->post_reset)
|
||||
(drv->post_reset)(cintf);
|
||||
}
|
||||
if (cintf != iface)
|
||||
up(&cintf->dev.sem);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1207,6 +1207,7 @@ EXPORT_SYMBOL(usb_ifnum_to_if);
|
||||
EXPORT_SYMBOL(usb_altnum_to_altsetting);
|
||||
|
||||
EXPORT_SYMBOL(usb_reset_device);
|
||||
EXPORT_SYMBOL(usb_reset_composite_device);
|
||||
|
||||
EXPORT_SYMBOL(__usb_get_extra_descriptor);
|
||||
|
||||
|
@ -386,6 +386,8 @@ extern int usb_lock_device_for_reset(struct usb_device *udev,
|
||||
|
||||
/* USB port reset for device reinitialization */
|
||||
extern int usb_reset_device(struct usb_device *dev);
|
||||
extern int usb_reset_composite_device(struct usb_device *dev,
|
||||
struct usb_interface *iface);
|
||||
|
||||
extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
|
||||
|
||||
@ -554,6 +556,10 @@ struct usb_dynids {
|
||||
* do (or don't) show up otherwise in the filesystem.
|
||||
* @suspend: Called when the device is going to be suspended by the system.
|
||||
* @resume: Called when the device is being resumed by the system.
|
||||
* @pre_reset: Called by usb_reset_composite_device() when the device
|
||||
* is about to be reset.
|
||||
* @post_reset: Called by usb_reset_composite_device() after the device
|
||||
* has been reset.
|
||||
* @id_table: USB drivers use ID table to support hotplugging.
|
||||
* Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
|
||||
* or your driver's probe function will never get called.
|
||||
@ -592,6 +598,9 @@ struct usb_driver {
|
||||
int (*suspend) (struct usb_interface *intf, pm_message_t message);
|
||||
int (*resume) (struct usb_interface *intf);
|
||||
|
||||
void (*pre_reset) (struct usb_interface *intf);
|
||||
void (*post_reset) (struct usb_interface *intf);
|
||||
|
||||
const struct usb_device_id *id_table;
|
||||
|
||||
struct usb_dynids dynids;
|
||||
|
Loading…
Reference in New Issue
Block a user