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/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel