aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-08-21 12:08:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:58:55 -0400
commit088dc270e1da03744d977cbd9edd4311af142348 (patch)
tree92ccfd907137f2135857bea8a43981b040028d37 /drivers/usb
parent3a3416b12f1fbd607bc137a57c924a628aa5485c (diff)
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/message.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 49cfd7928a1..333b22c68aa 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1493,6 +1493,65 @@ free_interfaces:
1493 return 0; 1493 return 0;
1494} 1494}
1495 1495
1496struct set_config_request {
1497 struct usb_device *udev;
1498 int config;
1499 struct work_struct work;
1500};
1501
1502/* Worker routine for usb_driver_set_configuration() */
1503static void driver_set_config_work(void *_req)
1504{
1505 struct set_config_request *req = _req;
1506
1507 usb_lock_device(req->udev);
1508 usb_set_configuration(req->udev, req->config);
1509 usb_unlock_device(req->udev);
1510 usb_put_dev(req->udev);
1511 kfree(req);
1512}
1513
1514/**
1515 * usb_driver_set_configuration - Provide a way for drivers to change device configurations
1516 * @udev: the device whose configuration is being updated
1517 * @config: the configuration being chosen.
1518 * Context: In process context, must be able to sleep
1519 *
1520 * Device interface drivers are not allowed to change device configurations.
1521 * This is because changing configurations will destroy the interface the
1522 * driver is bound to and create new ones; it would be like a floppy-disk
1523 * driver telling the computer to replace the floppy-disk drive with a
1524 * tape drive!
1525 *
1526 * Still, in certain specialized circumstances the need may arise. This
1527 * routine gets around the normal restrictions by using a work thread to
1528 * submit the change-config request.
1529 *
1530 * Returns 0 if the request was succesfully queued, error code otherwise.
1531 * The caller has no way to know whether the queued request will eventually
1532 * succeed.
1533 */
1534int usb_driver_set_configuration(struct usb_device *udev, int config)
1535{
1536 struct set_config_request *req;
1537
1538 req = kmalloc(sizeof(*req), GFP_KERNEL);
1539 if (!req)
1540 return -ENOMEM;
1541 req->udev = udev;
1542 req->config = config;
1543 INIT_WORK(&req->work, driver_set_config_work, req);
1544
1545 usb_get_dev(udev);
1546 if (!schedule_work(&req->work)) {
1547 usb_put_dev(udev);
1548 kfree(req);
1549 return -EINVAL;
1550 }
1551 return 0;
1552}
1553EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
1554
1496// synchronous request completion model 1555// synchronous request completion model
1497EXPORT_SYMBOL(usb_control_msg); 1556EXPORT_SYMBOL(usb_control_msg);
1498EXPORT_SYMBOL(usb_bulk_msg); 1557EXPORT_SYMBOL(usb_bulk_msg);