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

Reply via email to