Merge master.kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
[pandora-kernel.git] / drivers / base / dd.c
index c5d6bb4..510e788 100644 (file)
 #define to_drv(node) container_of(node, struct device_driver, kobj.entry)
 
 
-/**
- *     device_bind_driver - bind a driver to one device.
- *     @dev:   device.
- *
- *     Allow manual attachment of a driver to a device.
- *     Caller must have already set @dev->driver.
- *
- *     Note that this does not modify the bus reference count
- *     nor take the bus's rwsem. Please verify those are accounted
- *     for before calling this. (It is ok to call with no other effort
- *     from a driver's probe() method.)
- *
- *     This function must be called with @dev->sem held.
- */
-int device_bind_driver(struct device *dev)
+static void driver_bound(struct device *dev)
 {
-       int ret;
-
        if (klist_node_attached(&dev->knode_driver)) {
                printk(KERN_WARNING "%s: device %s already bound\n",
                        __FUNCTION__, kobject_name(&dev->kobj));
-               return 0;
+               return;
        }
 
        pr_debug("bound device '%s' to driver '%s'\n",
                 dev->bus_id, dev->driver->name);
+
+       if (dev->bus)
+               blocking_notifier_call_chain(&dev->bus->bus_notifier,
+                                            BUS_NOTIFY_BOUND_DRIVER, dev);
+
        klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
+}
+
+static int driver_sysfs_add(struct device *dev)
+{
+       int ret;
+
        ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
                          kobject_name(&dev->kobj));
        if (ret == 0) {
@@ -65,6 +60,36 @@ int device_bind_driver(struct device *dev)
        return ret;
 }
 
+static void driver_sysfs_remove(struct device *dev)
+{
+       struct device_driver *drv = dev->driver;
+
+       if (drv) {
+               sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+               sysfs_remove_link(&dev->kobj, "driver");
+       }
+}
+
+/**
+ *     device_bind_driver - bind a driver to one device.
+ *     @dev:   device.
+ *
+ *     Allow manual attachment of a driver to a device.
+ *     Caller must have already set @dev->driver.
+ *
+ *     Note that this does not modify the bus reference count
+ *     nor take the bus's rwsem. Please verify those are accounted
+ *     for before calling this. (It is ok to call with no other effort
+ *     from a driver's probe() method.)
+ *
+ *     This function must be called with @dev->sem held.
+ */
+int device_bind_driver(struct device *dev)
+{
+       driver_bound(dev);
+       return driver_sysfs_add(dev);
+}
+
 struct stupid_thread_structure {
        struct device_driver *drv;
        struct device *dev;
@@ -85,30 +110,32 @@ static int really_probe(void *void_data)
                 drv->bus->name, drv->name, dev->bus_id);
 
        dev->driver = drv;
+       if (driver_sysfs_add(dev)) {
+               printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
+                       __FUNCTION__, dev->bus_id);
+               goto probe_failed;
+       }
+
        if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
-               if (ret) {
-                       dev->driver = NULL;
+               if (ret)
                        goto probe_failed;
-               }
        } else if (drv->probe) {
                ret = drv->probe(dev);
-               if (ret) {
-                       dev->driver = NULL;
+               if (ret)
                        goto probe_failed;
-               }
-       }
-       if (device_bind_driver(dev)) {
-               printk(KERN_ERR "%s: device_bind_driver(%s) failed\n",
-                       __FUNCTION__, dev->bus_id);
-               /* How does undo a ->probe?  We're screwed. */
        }
+
+       driver_bound(dev);
        ret = 1;
        pr_debug("%s: Bound Device %s to Driver %s\n",
                 drv->bus->name, dev->bus_id, drv->name);
        goto done;
 
 probe_failed:
+       driver_sysfs_remove(dev);
+       dev->driver = NULL;
+
        if (ret == -ENODEV || ret == -ENXIO) {
                /* Driver matched, but didn't support device
                 * or device not found.
@@ -284,10 +311,15 @@ static void __device_release_driver(struct device * dev)
        drv = dev->driver;
        if (drv) {
                get_driver(drv);
-               sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+               driver_sysfs_remove(dev);
                sysfs_remove_link(&dev->kobj, "driver");
                klist_remove(&dev->knode_driver);
 
+               if (dev->bus)
+                       blocking_notifier_call_chain(&dev->bus->bus_notifier,
+                                                    BUS_NOTIFY_UNBIND_DRIVER,
+                                                    dev);
+
                if (dev->bus && dev->bus->remove)
                        dev->bus->remove(dev);
                else if (drv->remove)