Driver core: add platform_create_bundle() helper
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 30 Dec 2009 04:11:20 +0000 (20:11 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 8 Mar 2010 01:04:46 +0000 (17:04 -0800)
Many legacy-style module create singleton platform devices themselves,
along with corresponding platform driver. Instead of replicating error
handling code in all such drivers, provide a helper that allocates and
registers a single platform device and a driver and binds them together.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/base/platform.c
include/linux/platform_device.h

index 58efaf2f1259404973a2cdb335ca6378ffd85456..937d58021d1b36e3fc069c8e960212ada9c5977a 100644 (file)
@@ -548,6 +548,64 @@ 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.
+ */
+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"
index 71ff887ca44ee6eccfc83416554b556f61a6231c..25e64b43e644260d5b831ef6df556d87419f78e9 100644 (file)
@@ -77,6 +77,11 @@ extern int platform_driver_probe(struct platform_driver *driver,
 #define platform_get_drvdata(_dev)     dev_get_drvdata(&(_dev)->dev)
 #define platform_set_drvdata(_dev,data)        dev_set_drvdata(&(_dev)->dev, (data))
 
+extern struct platform_device *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);
+
 /* early platform driver interface */
 struct early_platform_driver {
        const char *class_str;