tree-wide: fix assorted typos all over the place
[safe/jmp/linux-2.6] / drivers / base / dd.c
index bb5f1eb..ee95c76 100644 (file)
  *
  * Copyright (c) 2002-5 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
- * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
- * Copyright (c) 2007 Novell Inc.
+ * Copyright (c) 2007-2009 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007-2009 Novell Inc.
  *
  * This file is released under the GPLv2
  */
 
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/wait.h>
+#include <linux/async.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -168,18 +171,24 @@ int driver_probe_done(void)
 }
 
 /**
+ * wait_for_device_probe
+ * Wait for device probing to be completed.
+ */
+void wait_for_device_probe(void)
+{
+       /* wait for the known devices to complete their probing */
+       wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
+       async_synchronize_full();
+}
+EXPORT_SYMBOL_GPL(wait_for_device_probe);
+
+/**
  * driver_probe_device - attempt to bind device & driver together
  * @drv: driver to bind a device to
  * @dev: device to try to bind to the driver
  *
- * First, we call the bus's match function, if one present, which should
- * compare the device IDs the driver supports with the device IDs of the
- * device. Note we don't do this ourselves because we don't know the
- * format of the ID structures, nor what is to be considered a match and
- * what is not.
- *
- * This function returns 1 if a match is found, -ENODEV if the device is
- * not registered, and 0 otherwise.
+ * This function returns -ENODEV if the device is not registered,
+ * 1 if the device is bound successfully and 0 otherwise.
  *
  * This function must be called with @dev->sem held.  When called for a
  * USB interface, @dev->parent->sem must be held as well.
@@ -190,21 +199,25 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
 
        if (!device_is_registered(dev))
                return -ENODEV;
-       if (drv->bus->match && !drv->bus->match(dev, drv))
-               goto done;
 
        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
                 drv->bus->name, __func__, dev_name(dev), drv->name);
 
+       pm_runtime_get_noresume(dev);
+       pm_runtime_barrier(dev);
        ret = really_probe(dev, drv);
+       pm_runtime_put_sync(dev);
 
-done:
        return ret;
 }
 
 static int __device_attach(struct device_driver *drv, void *data)
 {
        struct device *dev = data;
+
+       if (!driver_match_device(drv, dev))
+               return 0;
+
        return driver_probe_device(drv, dev);
 }
 
@@ -217,7 +230,7 @@ static int __device_attach(struct device_driver *drv, void *data)
  * pair is found, break out and return.
  *
  * Returns 1 if the device was bound to a driver;
- * 0 if no matching device was found;
+ * 0 if no matching driver was found;
  * -ENODEV if the device is not registered.
  *
  * When called for a USB interface, @dev->parent->sem must be held.
@@ -236,7 +249,9 @@ int device_attach(struct device *dev)
                        ret = 0;
                }
        } else {
+               pm_runtime_get_noresume(dev);
                ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+               pm_runtime_put_sync(dev);
        }
        up(&dev->sem);
        return ret;
@@ -257,7 +272,7 @@ static int __driver_attach(struct device *dev, void *data)
         * is an error.
         */
 
-       if (drv->bus->match && !drv->bus->match(dev, drv))
+       if (!driver_match_device(drv, dev))
                return 0;
 
        if (dev->parent)        /* Needed for USB */
@@ -297,8 +312,10 @@ static void __device_release_driver(struct device *dev)
 
        drv = dev->driver;
        if (drv) {
+               pm_runtime_get_noresume(dev);
+               pm_runtime_barrier(dev);
+
                driver_sysfs_remove(dev);
-               sysfs_remove_link(&dev->kobj, "driver");
 
                if (dev->bus)
                        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
@@ -312,6 +329,12 @@ static void __device_release_driver(struct device *dev)
                devres_release_all(dev);
                dev->driver = NULL;
                klist_remove(&dev->p->knode_driver);
+               if (dev->bus)
+                       blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+                                                    BUS_NOTIFY_UNBOUND_DRIVER,
+                                                    dev);
+
+               pm_runtime_put_sync(dev);
        }
 }
 
@@ -368,3 +391,30 @@ void driver_detach(struct device_driver *drv)
                put_device(dev);
        }
 }
+
+/*
+ * These exports can't be _GPL due to .h files using this within them, and it
+ * might break something that was previously working...
+ */
+void *dev_get_drvdata(const struct device *dev)
+{
+       if (dev && dev->p)
+               return dev->p->driver_data;
+       return NULL;
+}
+EXPORT_SYMBOL(dev_get_drvdata);
+
+void dev_set_drvdata(struct device *dev, void *data)
+{
+       int error;
+
+       if (!dev)
+               return;
+       if (!dev->p) {
+               error = device_private_init(dev);
+               if (error)
+                       return;
+       }
+       dev->p->driver_data = data;
+}
+EXPORT_SYMBOL(dev_set_drvdata);