[PATCH] dcdbas: convert to the new platform device interface
authorDmitry Torokhov <dtor_core@ameritech.net>
Wed, 22 Mar 2006 08:07:56 +0000 (00:07 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 22 Mar 2006 15:53:56 +0000 (07:53 -0800)
Do not use platform_device_register_simple() as it is going away, define
dcdbas_driver and implement ->probe() and ->remove() functions so manual
binding and unbinding will work with this driver.

Also switch to using attribute_group when creating sysfs attributes and
make sure to check and handle errors; explicitely remove attributes when
detaching driver.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/firmware/dcdbas.c

index 4652512f7d1a928a6830b5d15d91f4c20bdfc59e..3a4e5c5b4e1fc9d0fb421f9ed3cedd38a5f1fa26 100644 (file)
@@ -530,30 +530,27 @@ static DCDBAS_DEV_ATTR_RW(host_control_action);
 static DCDBAS_DEV_ATTR_RW(host_control_smi_type);
 static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown);
 
-static struct device_attribute *dcdbas_dev_attrs[] = {
-       &dev_attr_smi_data_buf_size,
-       &dev_attr_smi_data_buf_phys_addr,
-       &dev_attr_smi_request,
-       &dev_attr_host_control_action,
-       &dev_attr_host_control_smi_type,
-       &dev_attr_host_control_on_shutdown,
+static struct attribute *dcdbas_dev_attrs[] = {
+       &dev_attr_smi_data_buf_size.attr,
+       &dev_attr_smi_data_buf_phys_addr.attr,
+       &dev_attr_smi_request.attr,
+       &dev_attr_host_control_action.attr,
+       &dev_attr_host_control_smi_type.attr,
+       &dev_attr_host_control_on_shutdown.attr,
        NULL
 };
 
-/**
- * dcdbas_init: initialize driver
- */
-static int __init dcdbas_init(void)
+static struct attribute_group dcdbas_attr_group = {
+       .attrs = dcdbas_dev_attrs,
+};
+
+static int __devinit dcdbas_probe(struct platform_device *dev)
 {
-       int i;
+       int i, error;
 
        host_control_action = HC_ACTION_NONE;
        host_control_smi_type = HC_SMITYPE_NONE;
 
-       dcdbas_pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
-       if (IS_ERR(dcdbas_pdev))
-               return PTR_ERR(dcdbas_pdev);
-
        /*
         * BIOS SMI calls require buffer addresses be in 32-bit address space.
         * This is done by setting the DMA mask below.
@@ -561,19 +558,79 @@ static int __init dcdbas_init(void)
        dcdbas_pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
        dcdbas_pdev->dev.dma_mask = &dcdbas_pdev->dev.coherent_dma_mask;
 
+       error = sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group);
+       if (error)
+               return error;
+
+       for (i = 0; dcdbas_bin_attrs[i]; i++) {
+               error = sysfs_create_bin_file(&dev->dev.kobj,
+                                             dcdbas_bin_attrs[i]);
+               if (error) {
+                       while (--i >= 0)
+                               sysfs_remove_bin_file(&dev->dev.kobj,
+                                                     dcdbas_bin_attrs[i]);
+                       sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group);
+                       return error;
+               }
+       }
+
        register_reboot_notifier(&dcdbas_reboot_nb);
 
+       dev_info(&dev->dev, "%s (version %s)\n",
+                DRIVER_DESCRIPTION, DRIVER_VERSION);
+
+       return 0;
+}
+
+static int __devexit dcdbas_remove(struct platform_device *dev)
+{
+       int i;
+
+       unregister_reboot_notifier(&dcdbas_reboot_nb);
        for (i = 0; dcdbas_bin_attrs[i]; i++)
-               sysfs_create_bin_file(&dcdbas_pdev->dev.kobj,
-                                     dcdbas_bin_attrs[i]);
+               sysfs_remove_bin_file(&dev->dev.kobj, dcdbas_bin_attrs[i]);
+       sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
 
-       for (i = 0; dcdbas_dev_attrs[i]; i++)
-               device_create_file(&dcdbas_pdev->dev, dcdbas_dev_attrs[i]);
+       return 0;
+}
 
-       dev_info(&dcdbas_pdev->dev, "%s (version %s)\n",
-                DRIVER_DESCRIPTION, DRIVER_VERSION);
+static struct platform_driver dcdbas_driver = {
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = dcdbas_probe,
+       .remove         = __devexit_p(dcdbas_remove),
+};
+
+/**
+ * dcdbas_init: initialize driver
+ */
+static int __init dcdbas_init(void)
+{
+       int error;
+
+       error = platform_driver_register(&dcdbas_driver);
+       if (error)
+               return error;
+
+       dcdbas_pdev = platform_device_alloc(DRIVER_NAME, -1);
+       if (!dcdbas_pdev) {
+               error = -ENOMEM;
+               goto err_unregister_driver;
+       }
+
+       error = platform_device_add(dcdbas_pdev);
+       if (error)
+               goto err_free_device;
 
        return 0;
+
+ err_free_device:
+       platform_device_put(dcdbas_pdev);
+ err_unregister_driver:
+       platform_driver_unregister(&dcdbas_driver);
+       return error;
 }
 
 /**
@@ -588,6 +645,15 @@ static void __exit dcdbas_exit(void)
        unregister_reboot_notifier(&dcdbas_reboot_nb);
        smi_data_buf_free();
        platform_device_unregister(dcdbas_pdev);
+       platform_driver_unregister(&dcdbas_driver);
+
+       /*
+        * We have to free the buffer here instead of dcdbas_remove
+        * because only in module exit function we can be sure that
+        * all sysfs attributes belonging to this module have been
+        * released.
+        */
+       smi_data_buf_free();
 }
 
 module_init(dcdbas_init);