platform: Make platform resource input parameters const
[safe/jmp/linux-2.6] / drivers / base / platform.c
index d1d0ee4..c5fbe19 100644 (file)
@@ -10,6 +10,7 @@
  * information.
  */
 
+#include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -17,6 +18,7 @@
 #include <linux/bootmem.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include "base.h"
 
@@ -69,7 +71,8 @@ EXPORT_SYMBOL_GPL(platform_get_irq);
  * @name: resource name
  */
 struct resource *platform_get_resource_byname(struct platform_device *dev,
-                                             unsigned int type, char *name)
+                                             unsigned int type,
+                                             const char *name)
 {
        int i;
 
@@ -88,7 +91,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource_byname);
  * @dev: platform device
  * @name: IRQ name
  */
-int platform_get_irq_byname(struct platform_device *dev, char *name)
+int platform_get_irq_byname(struct platform_device *dev, const char *name)
 {
        struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
                                                          name);
@@ -125,7 +128,7 @@ struct platform_object {
 };
 
 /**
- * platform_device_put
+ * platform_device_put - destroy a platform device
  * @pdev: platform device to free
  *
  * Free all memory associated with a platform device.  This function must
@@ -149,7 +152,7 @@ static void platform_device_release(struct device *dev)
 }
 
 /**
- * platform_device_alloc
+ * platform_device_alloc - create a platform device
  * @name: base name of the device we're adding
  * @id: instance id
  *
@@ -174,7 +177,7 @@ struct platform_device *platform_device_alloc(const char *name, int id)
 EXPORT_SYMBOL_GPL(platform_device_alloc);
 
 /**
- * platform_device_add_resources
+ * platform_device_add_resources - add resources to a platform device
  * @pdev: platform device allocated by platform_device_alloc to add resources to
  * @res: set of resources that needs to be allocated for the device
  * @num: number of resources
@@ -184,7 +187,7 @@ EXPORT_SYMBOL_GPL(platform_device_alloc);
  * released.
  */
 int platform_device_add_resources(struct platform_device *pdev,
-                                 struct resource *res, unsigned int num)
+                                 const struct resource *res, unsigned int num)
 {
        struct resource *r;
 
@@ -199,7 +202,7 @@ int platform_device_add_resources(struct platform_device *pdev,
 EXPORT_SYMBOL_GPL(platform_device_add_resources);
 
 /**
- * platform_device_add_data
+ * platform_device_add_data - add platform-specific data to a platform device
  * @pdev: platform device allocated by platform_device_alloc to add resources to
  * @data: platform specific data for this platform device
  * @size: size of platform specific data
@@ -211,15 +214,13 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);
 int platform_device_add_data(struct platform_device *pdev, const void *data,
                             size_t size)
 {
-       void *d;
+       void *d = kmemdup(data, size, GFP_KERNEL);
 
-       d = kmalloc(size, GFP_KERNEL);
        if (d) {
-               memcpy(d, data, size);
                pdev->dev.platform_data = d;
-               pdev->platform_data = d;
+               return 0;
        }
-       return d ? 0 : -ENOMEM;
+       return -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(platform_device_add_data);
 
@@ -245,9 +246,7 @@ int platform_device_add(struct platform_device *pdev)
        if (pdev->id != -1)
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
        else
-               dev_set_name(&pdev->dev, pdev->name);
-
-       pdev->platform_data = pdev->dev.platform_data;
+               dev_set_name(&pdev->dev, "%s", pdev->name);
 
        for (i = 0; i < pdev->num_resources; i++) {
                struct resource *p, *r = &pdev->resource[i];
@@ -345,7 +344,7 @@ void platform_device_unregister(struct platform_device *pdev)
 EXPORT_SYMBOL_GPL(platform_device_unregister);
 
 /**
- * platform_device_register_simple
+ * platform_device_register_simple - add a platform-level device and its resources
  * @name: base name of the device we're adding
  * @id: instance id
  * @res: set of resources that needs to be allocated for the device
@@ -363,10 +362,12 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
  * enumeration tasks, they don't fully conform to the Linux driver model.
  * In particular, when such drivers are built as modules, they can't be
  * "hotplugged".
+ *
+ * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
  */
 struct platform_device *platform_device_register_simple(const char *name,
                                                        int id,
-                                                       struct resource *res,
+                                                       const struct resource *res,
                                                        unsigned int num)
 {
        struct platform_device *pdev;
@@ -397,7 +398,7 @@ error:
 EXPORT_SYMBOL_GPL(platform_device_register_simple);
 
 /**
- * platform_device_register_data
+ * platform_device_register_data - add a platform-level device with platform-specific data
  * @parent: parent device for the device we're adding
  * @name: base name of the device we're adding
  * @id: instance id
@@ -409,6 +410,8 @@ EXPORT_SYMBOL_GPL(platform_device_register_simple);
  * allocated for the device allows drivers using such devices to be
  * unloaded without waiting for the last reference to the device to be
  * dropped.
+ *
+ * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
  */
 struct platform_device *platform_device_register_data(
                struct device *parent,
@@ -442,6 +445,7 @@ error:
        platform_device_put(pdev);
        return ERR_PTR(retval);
 }
+EXPORT_SYMBOL_GPL(platform_device_register_data);
 
 static int platform_drv_probe(struct device *_dev)
 {
@@ -472,24 +476,8 @@ static void platform_drv_shutdown(struct device *_dev)
        drv->shutdown(dev);
 }
 
-static int platform_drv_suspend(struct device *_dev, pm_message_t state)
-{
-       struct platform_driver *drv = to_platform_driver(_dev->driver);
-       struct platform_device *dev = to_platform_device(_dev);
-
-       return drv->suspend(dev, state);
-}
-
-static int platform_drv_resume(struct device *_dev)
-{
-       struct platform_driver *drv = to_platform_driver(_dev->driver);
-       struct platform_device *dev = to_platform_device(_dev);
-
-       return drv->resume(dev);
-}
-
 /**
- * platform_driver_register
+ * platform_driver_register - register a driver for platform-level devices
  * @drv: platform driver structure
  */
 int platform_driver_register(struct platform_driver *drv)
@@ -501,16 +489,13 @@ int platform_driver_register(struct platform_driver *drv)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;
-       if (drv->suspend)
-               drv->driver.suspend = platform_drv_suspend;
-       if (drv->resume)
-               drv->driver.resume = platform_drv_resume;
+
        return driver_register(&drv->driver);
 }
 EXPORT_SYMBOL_GPL(platform_driver_register);
 
 /**
- * platform_driver_unregister
+ * platform_driver_unregister - unregister a driver for platform-level devices
  * @drv: platform driver structure
  */
 void platform_driver_unregister(struct platform_driver *drv)
@@ -541,11 +526,15 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
 {
        int retval, code;
 
+       /* make sure driver won't have bind/unbind attributes */
+       drv->driver.suppress_bind_attrs = true;
+
        /* temporary section violation during probe() */
        drv->probe = probe;
        retval = code = platform_driver_register(drv);
 
-       /* Fixup that section violation, being paranoid about code scanning
+       /*
+        * Fixup that section violation, being paranoid about code scanning
         * the list of drivers in order to probe new devices.  Check to see
         * if the probe was successful, and make sure any forced probes of
         * new devices fail.
@@ -563,6 +552,66 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
 }
 EXPORT_SYMBOL_GPL(platform_driver_probe);
 
+/**
+ * platform_create_bundle - register driver and create corresponding device
+ * @driver: platform driver structure
+ * @probe: the driver probe routine, probably from an __init section
+ * @res: set of resources that needs to be allocated for the device
+ * @n_res: number of resources
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
+ *
+ * Use this in legacy-style modules that probe hardware directly and
+ * register a single platform device and corresponding platform driver.
+ *
+ * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
+ */
+struct platform_device * __init_or_module platform_create_bundle(
+                       struct platform_driver *driver,
+                       int (*probe)(struct platform_device *),
+                       struct resource *res, unsigned int n_res,
+                       const void *data, size_t size)
+{
+       struct platform_device *pdev;
+       int error;
+
+       pdev = platform_device_alloc(driver->driver.name, -1);
+       if (!pdev) {
+               error = -ENOMEM;
+               goto err_out;
+       }
+
+       if (res) {
+               error = platform_device_add_resources(pdev, res, n_res);
+               if (error)
+                       goto err_pdev_put;
+       }
+
+       if (data) {
+               error = platform_device_add_data(pdev, data, size);
+               if (error)
+                       goto err_pdev_put;
+       }
+
+       error = platform_device_add(pdev);
+       if (error)
+               goto err_pdev_put;
+
+       error = platform_driver_probe(driver, probe);
+       if (error)
+               goto err_pdev_del;
+
+       return pdev;
+
+err_pdev_del:
+       platform_device_del(pdev);
+err_pdev_put:
+       platform_device_put(pdev);
+err_out:
+       return ERR_PTR(error);
+}
+EXPORT_SYMBOL_GPL(platform_create_bundle);
+
 /* modalias support enables more hands-off userspace setup:
  * (a) environment variable lets new-style hotplug events work once system is
  *     fully running:  "modprobe $MODALIAS"
@@ -593,7 +642,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 }
 
 static const struct platform_device_id *platform_match_id(
-                       struct platform_device_id *id,
+                       const struct platform_device_id *id,
                        struct platform_device *pdev)
 {
        while (id->name[0]) {
@@ -636,44 +685,24 @@ static int platform_match(struct device *dev, struct device_driver *drv)
 
 static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
 {
-       int ret = 0;
-
-       if (dev->driver && dev->driver->suspend)
-               ret = dev->driver->suspend(dev, mesg);
-
-       return ret;
-}
-
-static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg)
-{
        struct platform_driver *pdrv = to_platform_driver(dev->driver);
        struct platform_device *pdev = to_platform_device(dev);
        int ret = 0;
 
-       if (dev->driver && pdrv->suspend_late)
-               ret = pdrv->suspend_late(pdev, mesg);
+       if (dev->driver && pdrv->suspend)
+               ret = pdrv->suspend(pdev, mesg);
 
        return ret;
 }
 
-static int platform_legacy_resume_early(struct device *dev)
+static int platform_legacy_resume(struct device *dev)
 {
        struct platform_driver *pdrv = to_platform_driver(dev->driver);
        struct platform_device *pdev = to_platform_device(dev);
        int ret = 0;
 
-       if (dev->driver && pdrv->resume_early)
-               ret = pdrv->resume_early(pdev);
-
-       return ret;
-}
-
-static int platform_legacy_resume(struct device *dev)
-{
-       int ret = 0;
-
-       if (dev->driver && dev->driver->resume)
-               ret = dev->driver->resume(dev);
+       if (dev->driver && pdrv->resume)
+               ret = pdrv->resume(pdev);
 
        return ret;
 }
@@ -697,6 +726,13 @@ static void platform_pm_complete(struct device *dev)
                drv->pm->complete(dev);
 }
 
+#else /* !CONFIG_PM_SLEEP */
+
+#define platform_pm_prepare            NULL
+#define platform_pm_complete           NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
 #ifdef CONFIG_SUSPEND
 
 static int platform_pm_suspend(struct device *dev)
@@ -728,8 +764,6 @@ static int platform_pm_suspend_noirq(struct device *dev)
        if (drv->pm) {
                if (drv->pm->suspend_noirq)
                        ret = drv->pm->suspend_noirq(dev);
-       } else {
-               ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND);
        }
 
        return ret;
@@ -764,8 +798,6 @@ static int platform_pm_resume_noirq(struct device *dev)
        if (drv->pm) {
                if (drv->pm->resume_noirq)
                        ret = drv->pm->resume_noirq(dev);
-       } else {
-               ret = platform_legacy_resume_early(dev);
        }
 
        return ret;
@@ -811,8 +843,6 @@ static int platform_pm_freeze_noirq(struct device *dev)
        if (drv->pm) {
                if (drv->pm->freeze_noirq)
                        ret = drv->pm->freeze_noirq(dev);
-       } else {
-               ret = platform_legacy_suspend_late(dev, PMSG_FREEZE);
        }
 
        return ret;
@@ -847,8 +877,6 @@ static int platform_pm_thaw_noirq(struct device *dev)
        if (drv->pm) {
                if (drv->pm->thaw_noirq)
                        ret = drv->pm->thaw_noirq(dev);
-       } else {
-               ret = platform_legacy_resume_early(dev);
        }
 
        return ret;
@@ -883,8 +911,6 @@ static int platform_pm_poweroff_noirq(struct device *dev)
        if (drv->pm) {
                if (drv->pm->poweroff_noirq)
                        ret = drv->pm->poweroff_noirq(dev);
-       } else {
-               ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE);
        }
 
        return ret;
@@ -919,8 +945,6 @@ static int platform_pm_restore_noirq(struct device *dev)
        if (drv->pm) {
                if (drv->pm->restore_noirq)
                        ret = drv->pm->restore_noirq(dev);
-       } else {
-               ret = platform_legacy_resume_early(dev);
        }
 
        return ret;
@@ -939,7 +963,32 @@ static int platform_pm_restore_noirq(struct device *dev)
 
 #endif /* !CONFIG_HIBERNATION */
 
-static struct dev_pm_ops platform_dev_pm_ops = {
+#ifdef CONFIG_PM_RUNTIME
+
+int __weak platform_pm_runtime_suspend(struct device *dev)
+{
+       return -ENOSYS;
+};
+
+int __weak platform_pm_runtime_resume(struct device *dev)
+{
+       return -ENOSYS;
+};
+
+int __weak platform_pm_runtime_idle(struct device *dev)
+{
+       return -ENOSYS;
+};
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define platform_pm_runtime_suspend NULL
+#define platform_pm_runtime_resume NULL
+#define platform_pm_runtime_idle NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops platform_dev_pm_ops = {
        .prepare = platform_pm_prepare,
        .complete = platform_pm_complete,
        .suspend = platform_pm_suspend,
@@ -954,22 +1003,17 @@ static struct dev_pm_ops platform_dev_pm_ops = {
        .thaw_noirq = platform_pm_thaw_noirq,
        .poweroff_noirq = platform_pm_poweroff_noirq,
        .restore_noirq = platform_pm_restore_noirq,
+       .runtime_suspend = platform_pm_runtime_suspend,
+       .runtime_resume = platform_pm_runtime_resume,
+       .runtime_idle = platform_pm_runtime_idle,
 };
 
-#define PLATFORM_PM_OPS_PTR    (&platform_dev_pm_ops)
-
-#else /* !CONFIG_PM_SLEEP */
-
-#define PLATFORM_PM_OPS_PTR    NULL
-
-#endif /* !CONFIG_PM_SLEEP */
-
 struct bus_type platform_bus_type = {
        .name           = "platform",
        .dev_attrs      = platform_dev_attrs,
        .match          = platform_match,
        .uevent         = platform_uevent,
-       .pm             = PLATFORM_PM_OPS_PTR,
+       .pm             = &platform_dev_pm_ops,
 };
 EXPORT_SYMBOL_GPL(platform_bus_type);
 
@@ -1014,14 +1058,16 @@ static __initdata LIST_HEAD(early_platform_driver_list);
 static __initdata LIST_HEAD(early_platform_device_list);
 
 /**
- * early_platform_driver_register
+ * early_platform_driver_register - register early platform driver
  * @epdrv: early_platform driver structure
  * @buf: string passed from early_param()
+ *
+ * Helper function for early_platform_init() / early_platform_init_buffer()
  */
 int __init early_platform_driver_register(struct early_platform_driver *epdrv,
                                          char *buf)
 {
-       unsigned long index;
+       char *tmp;
        int n;
 
        /* Simply add the driver to the end of the global list.
@@ -1040,22 +1086,40 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv,
        if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
                list_move(&epdrv->list, &early_platform_driver_list);
 
-               if (!strcmp(buf, epdrv->pdrv->driver.name))
+               /* Allow passing parameters after device name */
+               if (buf[n] == '\0' || buf[n] == ',')
                        epdrv->requested_id = -1;
-               else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10,
-                                                        &index) == 0)
-                       epdrv->requested_id = index;
-               else
-                       epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
+               else {
+                       epdrv->requested_id = simple_strtoul(&buf[n + 1],
+                                                            &tmp, 10);
+
+                       if (buf[n] != '.' || (tmp == &buf[n + 1])) {
+                               epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
+                               n = 0;
+                       } else
+                               n += strcspn(&buf[n + 1], ",") + 1;
+               }
+
+               if (buf[n] == ',')
+                       n++;
+
+               if (epdrv->bufsize) {
+                       memcpy(epdrv->buffer, &buf[n],
+                              min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
+                       epdrv->buffer[epdrv->bufsize - 1] = '\0';
+               }
        }
 
        return 0;
 }
 
 /**
- * early_platform_add_devices - add a numbers of early platform devices
+ * early_platform_add_devices - adds a number of early platform devices
  * @devs: array of early platform devices to add
  * @num: number of early platform devices in array
+ *
+ * Used by early architecture code to register early platform devices and
+ * their platform data.
  */
 void __init early_platform_add_devices(struct platform_device **devs, int num)
 {
@@ -1075,8 +1139,12 @@ void __init early_platform_add_devices(struct platform_device **devs, int num)
 }
 
 /**
- * early_platform_driver_register_all
+ * early_platform_driver_register_all - register early platform drivers
  * @class_str: string to identify early platform driver class
+ *
+ * Used by architecture code to register all early platform drivers
+ * for a certain class. If omitted then only early platform drivers
+ * with matching kernel command line class parameters will be registered.
  */
 void __init early_platform_driver_register_all(char *class_str)
 {
@@ -1098,7 +1166,7 @@ void __init early_platform_driver_register_all(char *class_str)
 }
 
 /**
- * early_platform_match
+ * early_platform_match - find early platform device matching driver
  * @epdrv: early platform driver structure
  * @id: id to match against
  */
@@ -1116,7 +1184,7 @@ early_platform_match(struct early_platform_driver *epdrv, int id)
 }
 
 /**
- * early_platform_left
+ * early_platform_left - check if early platform driver has matching devices
  * @epdrv: early platform driver structure
  * @id: return true if id or above exists
  */
@@ -1134,7 +1202,7 @@ static  __init int early_platform_left(struct early_platform_driver *epdrv,
 }
 
 /**
- * early_platform_driver_probe_id
+ * early_platform_driver_probe_id - probe drivers matching class_str and id
  * @class_str: string to identify early platform driver class
  * @id: id to match against
  * @nr_probe: number of platform devices to successfully probe before exiting
@@ -1204,10 +1272,14 @@ static int __init early_platform_driver_probe_id(char *class_str,
 }
 
 /**
- * early_platform_driver_probe
+ * early_platform_driver_probe - probe a class of registered drivers
  * @class_str: string to identify early platform driver class
  * @nr_probe: number of platform devices to successfully probe before exiting
  * @user_only: only probe user specified early platform devices
+ *
+ * Used by architecture code to probe registered early platform drivers
+ * within a certain class. For probe to happen a registered early platform
+ * device matching a registered early platform driver is needed.
  */
 int __init early_platform_driver_probe(char *class_str,
                                       int nr_probe,