crypto: algapi - Remove unneeded null check
[safe/jmp/linux-2.6] / drivers / base / platform.c
index d2198f6..58efaf2 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);
@@ -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,22 +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);
-
-       /* We will remove platform_data field from struct device
-       * if all platform devices pass its platform specific data
-       * from platform_device. The conversion is going to be a
-       * long time, so we allow the two cases coexist to make
-       * this kind of fix more easily*/
-       if (pdev->platform_data && pdev->dev.platform_data) {
-               printk(KERN_ERR
-                              "%s: use which platform_data?\n",
-                              dev_name(&pdev->dev));
-       } else if (pdev->platform_data) {
-               pdev->dev.platform_data = pdev->platform_data;
-       } else if (pdev->dev.platform_data) {
-               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];
@@ -455,6 +441,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)
 {
@@ -485,22 +472,6 @@ 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
  * @drv: platform driver structure
@@ -514,10 +485,7 @@ 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);
@@ -554,11 +522,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.
@@ -649,44 +621,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;
 }
@@ -710,6 +662,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)
@@ -741,8 +700,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;
@@ -777,8 +734,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;
@@ -824,8 +779,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;
@@ -860,8 +813,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;
@@ -896,8 +847,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;
@@ -932,8 +881,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;
@@ -952,7 +899,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,
@@ -967,22 +939,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);
 
@@ -990,6 +957,8 @@ int __init platform_bus_init(void)
 {
        int error;
 
+       early_platform_cleanup();
+
        error = device_register(&platform_bus);
        if (error)
                return error;
@@ -1020,3 +989,255 @@ u64 dma_get_required_mask(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dma_get_required_mask);
 #endif
+
+static __initdata LIST_HEAD(early_platform_driver_list);
+static __initdata LIST_HEAD(early_platform_device_list);
+
+/**
+ * early_platform_driver_register
+ * @epdrv: early_platform driver structure
+ * @buf: string passed from early_param()
+ */
+int __init early_platform_driver_register(struct early_platform_driver *epdrv,
+                                         char *buf)
+{
+       char *tmp;
+       int n;
+
+       /* Simply add the driver to the end of the global list.
+        * Drivers will by default be put on the list in compiled-in order.
+        */
+       if (!epdrv->list.next) {
+               INIT_LIST_HEAD(&epdrv->list);
+               list_add_tail(&epdrv->list, &early_platform_driver_list);
+       }
+
+       /* If the user has specified device then make sure the driver
+        * gets prioritized. The driver of the last device specified on
+        * command line will be put first on the list.
+        */
+       n = strlen(epdrv->pdrv->driver.name);
+       if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
+               list_move(&epdrv->list, &early_platform_driver_list);
+
+               /* Allow passing parameters after device name */
+               if (buf[n] == '\0' || buf[n] == ',')
+                       epdrv->requested_id = -1;
+               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
+ * @devs: array of early platform devices to add
+ * @num: number of early platform devices in array
+ */
+void __init early_platform_add_devices(struct platform_device **devs, int num)
+{
+       struct device *dev;
+       int i;
+
+       /* simply add the devices to list */
+       for (i = 0; i < num; i++) {
+               dev = &devs[i]->dev;
+
+               if (!dev->devres_head.next) {
+                       INIT_LIST_HEAD(&dev->devres_head);
+                       list_add_tail(&dev->devres_head,
+                                     &early_platform_device_list);
+               }
+       }
+}
+
+/**
+ * early_platform_driver_register_all
+ * @class_str: string to identify early platform driver class
+ */
+void __init early_platform_driver_register_all(char *class_str)
+{
+       /* The "class_str" parameter may or may not be present on the kernel
+        * command line. If it is present then there may be more than one
+        * matching parameter.
+        *
+        * Since we register our early platform drivers using early_param()
+        * we need to make sure that they also get registered in the case
+        * when the parameter is missing from the kernel command line.
+        *
+        * We use parse_early_options() to make sure the early_param() gets
+        * called at least once. The early_param() may be called more than
+        * once since the name of the preferred device may be specified on
+        * the kernel command line. early_platform_driver_register() handles
+        * this case for us.
+        */
+       parse_early_options(class_str);
+}
+
+/**
+ * early_platform_match
+ * @epdrv: early platform driver structure
+ * @id: id to match against
+ */
+static  __init struct platform_device *
+early_platform_match(struct early_platform_driver *epdrv, int id)
+{
+       struct platform_device *pd;
+
+       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+                       if (pd->id == id)
+                               return pd;
+
+       return NULL;
+}
+
+/**
+ * early_platform_left
+ * @epdrv: early platform driver structure
+ * @id: return true if id or above exists
+ */
+static  __init int early_platform_left(struct early_platform_driver *epdrv,
+                                      int id)
+{
+       struct platform_device *pd;
+
+       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+                       if (pd->id >= id)
+                               return 1;
+
+       return 0;
+}
+
+/**
+ * early_platform_driver_probe_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
+ */
+static int __init early_platform_driver_probe_id(char *class_str,
+                                                int id,
+                                                int nr_probe)
+{
+       struct early_platform_driver *epdrv;
+       struct platform_device *match;
+       int match_id;
+       int n = 0;
+       int left = 0;
+
+       list_for_each_entry(epdrv, &early_platform_driver_list, list) {
+               /* only use drivers matching our class_str */
+               if (strcmp(class_str, epdrv->class_str))
+                       continue;
+
+               if (id == -2) {
+                       match_id = epdrv->requested_id;
+                       left = 1;
+
+               } else {
+                       match_id = id;
+                       left += early_platform_left(epdrv, id);
+
+                       /* skip requested id */
+                       switch (epdrv->requested_id) {
+                       case EARLY_PLATFORM_ID_ERROR:
+                       case EARLY_PLATFORM_ID_UNSET:
+                               break;
+                       default:
+                               if (epdrv->requested_id == id)
+                                       match_id = EARLY_PLATFORM_ID_UNSET;
+                       }
+               }
+
+               switch (match_id) {
+               case EARLY_PLATFORM_ID_ERROR:
+                       pr_warning("%s: unable to parse %s parameter\n",
+                                  class_str, epdrv->pdrv->driver.name);
+                       /* fall-through */
+               case EARLY_PLATFORM_ID_UNSET:
+                       match = NULL;
+                       break;
+               default:
+                       match = early_platform_match(epdrv, match_id);
+               }
+
+               if (match) {
+                       if (epdrv->pdrv->probe(match))
+                               pr_warning("%s: unable to probe %s early.\n",
+                                          class_str, match->name);
+                       else
+                               n++;
+               }
+
+               if (n >= nr_probe)
+                       break;
+       }
+
+       if (left)
+               return n;
+       else
+               return -ENODEV;
+}
+
+/**
+ * early_platform_driver_probe
+ * @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
+ */
+int __init early_platform_driver_probe(char *class_str,
+                                      int nr_probe,
+                                      int user_only)
+{
+       int k, n, i;
+
+       n = 0;
+       for (i = -2; n < nr_probe; i++) {
+               k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
+
+               if (k < 0)
+                       break;
+
+               n += k;
+
+               if (user_only)
+                       break;
+       }
+
+       return n;
+}
+
+/**
+ * early_platform_cleanup - clean up early platform code
+ */
+void __init early_platform_cleanup(void)
+{
+       struct platform_device *pd, *pd2;
+
+       /* clean up the devres list used to chain devices */
+       list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
+                                dev.devres_head) {
+               list_del(&pd->dev.devres_head);
+               memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
+       }
+}
+