]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/base/bus.c
[PATCH] memhotplug: register_memory should be global
[linux-2.6-omap-h63xx.git] / drivers / base / bus.c
index fa601b085eba71a5f633ebd25de237838b3211fe..29f6af554e715ed408f0f23e8da838284dbc9dc7 100644 (file)
@@ -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);
@@ -420,6 +428,26 @@ static void driver_remove_attrs(struct bus_type * bus, struct device_driver * dr
        }
 }
 
+#ifdef CONFIG_HOTPLUG
+/*
+ * Thanks to drivers making their tables __devinit, we can't allow manual
+ * bind and unbind from userspace unless CONFIG_HOTPLUG is enabled.
+ */
+static void add_bind_files(struct device_driver *drv)
+{
+       driver_create_file(drv, &driver_attr_unbind);
+       driver_create_file(drv, &driver_attr_bind);
+}
+
+static void remove_bind_files(struct device_driver *drv)
+{
+       driver_remove_file(drv, &driver_attr_bind);
+       driver_remove_file(drv, &driver_attr_unbind);
+}
+#else
+static inline void add_bind_files(struct device_driver *drv) {}
+static inline void remove_bind_files(struct device_driver *drv) {}
+#endif
 
 /**
  *     bus_add_driver - Add a driver to the bus.
@@ -449,8 +477,7 @@ int bus_add_driver(struct device_driver * drv)
                module_add_driver(drv->owner, drv);
 
                driver_add_attrs(bus, drv);
-               driver_create_file(drv, &driver_attr_unbind);
-               driver_create_file(drv, &driver_attr_bind);
+               add_bind_files(drv);
        }
        return error;
 }
@@ -468,8 +495,7 @@ int bus_add_driver(struct device_driver * drv)
 void bus_remove_driver(struct device_driver * drv)
 {
        if (drv->bus) {
-               driver_remove_file(drv, &driver_attr_bind);
-               driver_remove_file(drv, &driver_attr_unbind);
+               remove_bind_files(drv);
                driver_remove_attrs(drv->bus, drv);
                klist_remove(&drv->knode_bus);
                pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
@@ -484,8 +510,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;
 }