diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index ee6f1abdf0aa158f50341d0f588b915a93d43605..8a39c3b52803789555ec73c58bee1995e12ab071 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -80,7 +80,7 @@ static struct device_driver usb_generic_driver = { 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); @@ -93,12 +93,14 @@ int usb_probe_interface(struct device *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; @@ -106,23 +108,24 @@ int usb_probe_interface(struct device *dev) 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; } @@ -152,8 +155,6 @@ int usb_register(struct usb_driver *new_driver) 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) { @@ -170,7 +171,7 @@ int usb_register(struct usb_driver *new_driver) /** * 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. * @@ -264,26 +265,22 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) * 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; } @@ -323,13 +320,22 @@ int usb_interface_claimed(struct usb_interface *iface) * 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); diff --git a/include/linux/usb.h b/include/linux/usb.h index 41c2ca3dc629792681cc9afbee554229aa699695..5e49f861230d745f16216e7f64b9a8d064896883 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -414,9 +414,6 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set * or your driver's probe function will never get called. * @driver: the driver model core driver structure. - * @serialize: a semaphore used to serialize access to this driver. Used - * in the probe and disconnect functions. Only the USB core should use - * this lock. * * USB drivers must provide a name, probe() and disconnect() methods, * and an id_table. Other driver fields are optional. @@ -451,8 +448,6 @@ struct usb_driver { const struct usb_device_id *id_table; struct device_driver driver; - - struct semaphore serialize; }; #define to_usb_driver(d) container_of(d, struct usb_driver, driver)