On Fri, 11 May 2007, Alan Stern wrote: > Maybe they don't bother to do so; I'm not familiar with those drivers. So > all right, I'll write the routine for you.
And here you go. Better check with Greg to see if there's any objection to exporting driver_probe_device() from the driver core. I haven't tested this, but it compiles. Alan Stern Index: usb-2.6/drivers/base/base.h =================================================================== --- usb-2.6.orig/drivers/base/base.h +++ usb-2.6/drivers/base/base.h @@ -25,7 +25,6 @@ extern int bus_add_driver(struct device_ extern void bus_remove_driver(struct device_driver *); extern void driver_detach(struct device_driver * drv); -extern int driver_probe_device(struct device_driver *, struct device *); extern void sysdev_shutdown(void); extern int sysdev_suspend(pm_message_t state); Index: usb-2.6/drivers/base/dd.c =================================================================== --- usb-2.6.orig/drivers/base/dd.c +++ usb-2.6/drivers/base/dd.c @@ -200,6 +200,7 @@ int driver_probe_device(struct device_dr done: return ret; } +EXPORT_SYMBOL_GPL(driver_probe_device); static int __device_attach(struct device_driver * drv, void * data) { Index: usb-2.6/drivers/usb/core/message.c =================================================================== --- usb-2.6.orig/drivers/usb/core/message.c +++ usb-2.6/drivers/usb/core/message.c @@ -1634,6 +1634,73 @@ int usb_driver_set_configuration(struct } EXPORT_SYMBOL_GPL(usb_driver_set_configuration); +struct rebind_interface_request { + struct usb_device *udev; + struct usb_interface *intf; + struct device_driver *driver; + struct work_struct work; +}; + +/* Worker routine for usb_rebind_interface() */ +static void rebind_interface_work(struct work_struct *work) +{ + struct rebind_interface_request *req = + container_of(work, struct rebind_interface_request, work); + struct device *dev = &req->intf->dev; + + if (req->udev->state == USB_STATE_NOTATTACHED) + goto done; + + usb_lock_device(req->udev); + down(&dev->sem); + if (device_is_registered(dev) && dev->driver == req->driver) { + device_release_driver(dev); + driver_probe_device(req->driver, dev); + } + up(&dev->sem); + usb_unlock_device(req->udev); + done: + put_driver(req->driver); + usb_put_intf(req->intf); + usb_put_dev(req->udev); + kfree(req); +} + +/** + * usb_rebind_interface - Unbind a driver from and then rebind it to an interface + * @intf: the interface whose driver should be unbound and rebound + * Context: In process context, must be able to sleep + * + * If a device interface driver finds itself in a deep hole with no way to + * get out (for example, if its post_reset() method is unable to restore + * the device's state because the driver doesn't know what that state + * should be), it can call this routine. The driver will be unbound and + * then rebound, giving it a fresh start at managing the interface. + * + * The unbind and rebind calls are made from a workqueue, so that the driver's + * disconnect() method can run without fear of deadlock. + * + * 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_rebind_interface(struct usb_interface *intf) +{ + struct rebind_interface_request *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + req->udev = usb_get_dev(interface_to_usbdev(intf)); + req->intf = usb_get_intf(intf); + req->driver = get_driver(intf->dev.driver); + INIT_WORK(&req->work, rebind_interface_work); + + schedule_work(&req->work); + return 0; +} +EXPORT_SYMBOL_GPL(usb_rebind_interface); + // synchronous request completion model EXPORT_SYMBOL(usb_control_msg); EXPORT_SYMBOL(usb_bulk_msg); Index: usb-2.6/include/linux/device.h =================================================================== --- usb-2.6.orig/include/linux/device.h +++ usb-2.6/include/linux/device.h @@ -530,6 +530,7 @@ extern void device_release_driver(struct extern int __must_check device_attach(struct device * dev); extern int __must_check driver_attach(struct device_driver *drv); extern int __must_check device_reprobe(struct device *dev); +extern int driver_probe_device(struct device_driver *, struct device *); /* * Easy functions for dynamically creating devices on the fly Index: usb-2.6/include/linux/usb.h =================================================================== --- usb-2.6.orig/include/linux/usb.h +++ usb-2.6/include/linux/usb.h @@ -1322,8 +1322,9 @@ extern int usb_clear_halt(struct usb_dev extern int usb_reset_configuration(struct usb_device *dev); 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 */ +/* these requests aren't really synchronous, but they belong with the others */ extern int usb_driver_set_configuration(struct usb_device *udev, int config); +extern int usb_rebind_interface(struct usb_interface *intf); /* * timeouts, in milliseconds, used for sending/receiving control messages ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel