aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/base/bus.c15
-rw-r--r--drivers/base/dd.c15
2 files changed, 28 insertions, 2 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index fa601b085eb..e3f915a2489 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -152,7 +152,11 @@ static ssize_t driver_unbind(struct device_driver *drv,
dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
if (dev && dev->driver == drv) {
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
device_release_driver(dev);
+ if (dev->parent)
+ up(&dev->parent->sem);
err = count;
}
put_device(dev);
@@ -175,9 +179,13 @@ static ssize_t driver_bind(struct device_driver *drv,
dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
if (dev && dev->driver == NULL) {
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
down(&dev->sem);
err = driver_probe_device(drv, dev);
up(&dev->sem);
+ if (dev->parent)
+ up(&dev->parent->sem);
}
put_device(dev);
put_bus(bus);
@@ -484,8 +492,13 @@ void bus_remove_driver(struct device_driver * drv)
/* Helper for bus_rescan_devices's iter */
static int bus_rescan_devices_helper(struct device *dev, void *data)
{
- if (!dev->driver)
+ if (!dev->driver) {
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
device_attach(dev);
+ if (dev->parent)
+ up(&dev->parent->sem);
+ }
return 0;
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 3b419c9a1e7..2b905016664 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -65,7 +65,8 @@ void device_bind_driver(struct device * dev)
* This function returns 1 if a match is found, an error if one
* occurs (that is not -ENODEV or -ENXIO), and 0 otherwise.
*
- * This function must be called with @dev->sem held.
+ * This function must be called with @dev->sem held. When called
+ * for a USB interface, @dev->parent->sem must be held as well.
*/
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
@@ -123,6 +124,8 @@ static int __device_attach(struct device_driver * drv, void * data)
*
* Returns 1 if the device was bound to a driver;
* 0 if no matching device was found; error code otherwise.
+ *
+ * When called for a USB interface, @dev->parent->sem must be held.
*/
int device_attach(struct device * dev)
{
@@ -152,10 +155,14 @@ static int __driver_attach(struct device * dev, void * data)
* is an error.
*/
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver)
driver_probe_device(drv, dev);
up(&dev->sem);
+ if (dev->parent)
+ up(&dev->parent->sem);
return 0;
}
@@ -181,6 +188,8 @@ void driver_attach(struct device_driver * drv)
* Manually detach device from driver.
*
* __device_release_driver() must be called with @dev->sem held.
+ * When called for a USB interface, @dev->parent->sem must be held
+ * as well.
*/
static void __device_release_driver(struct device * dev)
@@ -233,10 +242,14 @@ void driver_detach(struct device_driver * drv)
get_device(dev);
spin_unlock(&drv->klist_devices.k_lock);
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
down(&dev->sem);
if (dev->driver == drv)
__device_release_driver(dev);
up(&dev->sem);
+ if (dev->parent)
+ up(&dev->parent->sem);
put_device(dev);
}
}