usbcore: help drivers to change device configs
It's generally a bad idea for USB interface drivers to try to change a device's configuration, and usbcore doesn't provide any way for them to do it. However in a few exceptional circumstances it can make sense. This patch (as767) adds a roundabout mechanism to help drivers that may need it. 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
3a3416b12f
commit
088dc270e1
@@ -1493,6 +1493,65 @@ free_interfaces:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct set_config_request {
|
||||||
|
struct usb_device *udev;
|
||||||
|
int config;
|
||||||
|
struct work_struct work;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Worker routine for usb_driver_set_configuration() */
|
||||||
|
static void driver_set_config_work(void *_req)
|
||||||
|
{
|
||||||
|
struct set_config_request *req = _req;
|
||||||
|
|
||||||
|
usb_lock_device(req->udev);
|
||||||
|
usb_set_configuration(req->udev, req->config);
|
||||||
|
usb_unlock_device(req->udev);
|
||||||
|
usb_put_dev(req->udev);
|
||||||
|
kfree(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usb_driver_set_configuration - Provide a way for drivers to change device configurations
|
||||||
|
* @udev: the device whose configuration is being updated
|
||||||
|
* @config: the configuration being chosen.
|
||||||
|
* Context: In process context, must be able to sleep
|
||||||
|
*
|
||||||
|
* Device interface drivers are not allowed to change device configurations.
|
||||||
|
* This is because changing configurations will destroy the interface the
|
||||||
|
* driver is bound to and create new ones; it would be like a floppy-disk
|
||||||
|
* driver telling the computer to replace the floppy-disk drive with a
|
||||||
|
* tape drive!
|
||||||
|
*
|
||||||
|
* Still, in certain specialized circumstances the need may arise. This
|
||||||
|
* routine gets around the normal restrictions by using a work thread to
|
||||||
|
* submit the change-config request.
|
||||||
|
*
|
||||||
|
* Returns 0 if the request was succesfully queued, error code otherwise.
|
||||||
|
* The caller has no way to know whether the queued request will eventually
|
||||||
|
* succeed.
|
||||||
|
*/
|
||||||
|
int usb_driver_set_configuration(struct usb_device *udev, int config)
|
||||||
|
{
|
||||||
|
struct set_config_request *req;
|
||||||
|
|
||||||
|
req = kmalloc(sizeof(*req), GFP_KERNEL);
|
||||||
|
if (!req)
|
||||||
|
return -ENOMEM;
|
||||||
|
req->udev = udev;
|
||||||
|
req->config = config;
|
||||||
|
INIT_WORK(&req->work, driver_set_config_work, req);
|
||||||
|
|
||||||
|
usb_get_dev(udev);
|
||||||
|
if (!schedule_work(&req->work)) {
|
||||||
|
usb_put_dev(udev);
|
||||||
|
kfree(req);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
|
||||||
|
|
||||||
// synchronous request completion model
|
// synchronous request completion model
|
||||||
EXPORT_SYMBOL(usb_control_msg);
|
EXPORT_SYMBOL(usb_control_msg);
|
||||||
EXPORT_SYMBOL(usb_bulk_msg);
|
EXPORT_SYMBOL(usb_bulk_msg);
|
||||||
|
@@ -1099,6 +1099,9 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe);
|
|||||||
extern int usb_reset_configuration(struct usb_device *dev);
|
extern int usb_reset_configuration(struct usb_device *dev);
|
||||||
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
|
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
|
||||||
|
|
||||||
|
/* this request isn't really synchronous, but it belongs with the others */
|
||||||
|
extern int usb_driver_set_configuration(struct usb_device *udev, int config);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timeouts, in milliseconds, used for sending/receiving control messages
|
* timeouts, in milliseconds, used for sending/receiving control messages
|
||||||
* they typically complete within a few frames (msec) after they're issued
|
* they typically complete within a few frames (msec) after they're issued
|
||||||
|
Reference in New Issue
Block a user