static int usb_generic_driver_data;
-/* needs to be called with BKL held */
+/* called from driver core with usb_bus_type.subsys writelock */
int usb_probe_interface(struct device *dev)
{
struct usb_interface * intf = to_usb_interface(dev);
if (!driver->probe)
return error;
+ /* driver claim() doesn't yet affect dev->driver... */
+ if (intf->driver)
+ return error;
+
id = usb_match_id (intf, driver->id_table);
if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
- down (&driver->serialize);
error = driver->probe (intf, id);
- up (&driver->serialize);
}
if (!error)
intf->driver = driver;
return error;
}
+/* called from driver core with usb_bus_type.subsys writelock */
int usb_unbind_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
- struct usb_driver *driver = to_usb_driver(dev->driver);
-
- down(&driver->serialize);
+ struct usb_driver *driver = intf->driver;
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
- if (intf->driver && intf->driver->disconnect)
- intf->driver->disconnect(intf);
+ if (driver && driver->disconnect)
+ driver->disconnect(intf);
- /* force a release and re-initialize the interface */
- usb_driver_release_interface(driver, intf);
-
- up(&driver->serialize);
+ /* reset other interface state */
+ usb_set_interface(interface_to_usbdev(intf),
+ intf->altsetting[0].desc.bInterfaceNumber,
+ 0);
+ usb_set_intfdata(intf, NULL);
+ intf->driver = NULL;
return 0;
}
new_driver->driver.probe = usb_probe_interface;
new_driver->driver.remove = usb_unbind_interface;
- init_MUTEX(&new_driver->serialize);
-
retval = driver_register(&new_driver->driver);
if (!retval) {
/**
* usb_deregister - unregister a USB driver
* @driver: USB operations of the driver to unregister
- * Context: !in_interrupt (), must be called with BKL held
+ * Context: must be able to sleep
*
* Unlinks the specified driver from the internal USB driver list.
*
* Few drivers should need to use this routine, since the most natural
* way to bind to an interface is to return the private data from
* the driver's probe() method.
+ *
+ * Callers must own the driver model's usb bus writelock. So driver
+ * probe() entries don't need extra locking, but other call contexts
+ * may need to explicitly claim that lock.
*/
int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
{
if (!iface || !driver)
return -EINVAL;
- /* this is mainly to lock against usbfs */
- lock_kernel();
- if (iface->driver) {
- unlock_kernel();
- err ("%s driver booted %s off interface %p",
- driver->name, iface->driver->name, iface);
+ if (iface->driver)
return -EBUSY;
- } else {
- dbg("%s driver claimed interface %p", driver->name, iface);
- }
+ /* FIXME should device_bind_driver() */
iface->driver = driver;
usb_set_intfdata(iface, priv);
- unlock_kernel();
return 0;
}
* usually won't need to call this.
*
* This call is synchronous, and may not be used in an interrupt context.
+ * Callers must own the driver model's usb bus writelock. So driver
+ * disconnect() entries don't need extra locking, but other call contexts
+ * may need to explicitly claim that lock.
*/
void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
{
/* this should never happen, don't release something that's not ours */
- if (iface->driver && iface->driver != driver)
+ if (!iface || !iface->driver || iface->driver != driver)
return;
+ if (iface->dev.driver) {
+ /* FIXME should be the ONLY case here */
+ device_release_driver(&iface->dev);
+ return;
+ }
+
usb_set_interface(interface_to_usbdev(iface),
iface->altsetting[0].desc.bInterfaceNumber,
0);