This patch adds support for a new struct device member "assets"
which may point to an array of struct assets.

The array is terminated by one with a NULL pre_probe callback.

These assets consist of named (in .name) or anonymous object
pointers (.data) operated on by specified callbacks.  A void *
is provided to give configuration data or pointer if needed.

Before device probe, any assets associated with the device have
their pre_probe() callback called, which will typically "enable"
them, and after device removal the post_remove() callback is
called which will typically disable them.

Signed-off-by: Andy Green <[email protected]>
---
 drivers/base/dd.c      |   36 ++++++++++++++++++++++++++++++++++++
 include/linux/device.h |   25 +++++++++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index e3bbed8..d37210a 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -261,6 +261,7 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
 
 static int really_probe(struct device *dev, struct device_driver *drv)
 {
+       struct device_asset *asset;
        int ret = 0;
 
        atomic_inc(&probe_count);
@@ -275,6 +276,23 @@ static int really_probe(struct device *dev, struct 
device_driver *drv)
                goto probe_failed;
        }
 
+       asset = dev->assets;
+       while (asset && asset->pre_probe) {
+               dev_info(dev, "Enabling pre-probe asset %s\n", asset->name);
+               ret = asset->pre_probe(dev, asset);
+               if (ret) {
+                       dev_err(dev, "Error Enabling pre-probe asset %s\n",
+                                                                 asset->name);
+                       if (asset != dev->assets)
+                               do {
+                                       asset--;
+                                       asset->post_remove(dev, asset);
+                               } while (asset != dev->assets);
+                       goto probe_failed;
+               }
+               asset++;
+       }
+
        if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
                if (ret)
@@ -478,6 +496,7 @@ EXPORT_SYMBOL_GPL(driver_attach);
 static void __device_release_driver(struct device *dev)
 {
        struct device_driver *drv;
+       struct device_asset *asset;
 
        drv = dev->driver;
        if (drv) {
@@ -496,6 +515,23 @@ static void __device_release_driver(struct device *dev)
                        dev->bus->remove(dev);
                else if (drv->remove)
                        drv->remove(dev);
+
+               asset = dev->assets;
+               if (asset) {
+                       /* remove in reverse order */
+                       while (asset->pre_probe)
+                               asset++;
+
+                       if (asset != dev->assets)
+                               do {
+                                       asset--;
+                                       dev_info(dev,
+                                          "Disabling post-remove asset %s\n",
+                                                                 asset->name);
+                                       asset->post_remove(dev, asset);
+                               } while (asset != dev->assets);
+               }
+
                devres_release_all(dev);
                dev->driver = NULL;
                dev_set_drvdata(dev, NULL);
diff --git a/include/linux/device.h b/include/linux/device.h
index 86ef6ab..6eabe1d 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -577,6 +577,26 @@ struct device_dma_parameters {
 };
 
 /**
+ * struct device_asset - a prerequisite for this device's probing
+ * @name:      Name of the regulator, clock, etc.  Optional.
+ * @asset:     Pointer to the regulator, clock, etc.  If no name is given,
+ *             this can be set before device probe, otherwise the pre_probe
+ *             handler will dereference the name and store a pointer here
+ * @data:      Optional configuration data the asset may need
+ * @pre_probe: Called before this device this is associated with gets
+ *             probed.
+ * @post_remove: Called after this device instance gets removed.
+ */
+
+struct device_asset {
+       const char *name;
+       void *asset;
+       void *data;
+       int (*pre_probe)(struct device *device, struct device_asset *asset);
+       void (*post_remove)(struct device *device, struct device_asset *asset);
+};
+
+/**
  * struct device - The basic device structure
  * @parent:    The device's "parent" device, the device to which it is 
attached.
  *             In most cases, a parent device is some sort of bus or host
@@ -600,6 +620,9 @@ struct device_dma_parameters {
  *             variants, which GPIO pins act in what additional roles, and so
  *             on.  This shrinks the "Board Support Packages" (BSPs) and
  *             minimizes board-specific #ifdefs in drivers.
+ * @assets:    Pointer to a NULL-pre_probe terminated array of named or
+ *             pointed-to objects that should be enabled for this device
+ *             just before probe and disabled after removal
  * @power:     For device power management.
  *             See Documentation/power/devices.txt for details.
  * @pm_domain: Provide callbacks that are executed during system suspend,
@@ -653,6 +676,8 @@ struct device {
                                           device */
        void            *platform_data; /* Platform specific data, device
                                           core doesn't touch it */
+       struct device_asset *assets; /* optional assets enabled before probe
+                                     * and disabled after removal */
        struct dev_pm_info      power;
        struct dev_pm_domain    *pm_domain;
 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to