OSDN Git Service

eeepc-laptop: fix ordering of init and exit functions
authorCorentin Chary <corentincj@iksaif.net>
Tue, 29 Sep 2009 14:01:31 +0000 (16:01 +0200)
committerCorentin Chary <corentincj@iksaif.net>
Wed, 30 Sep 2009 20:17:45 +0000 (22:17 +0200)
1. input and backlight devices were registered after acpi notifications
   are enabled.  This left a window where eeepc_hotk_notify() might
   find these devices in an inconsistent (half-initialized) state.

-> Move all device registration into eeepc_hotk_add(), which is called
   before enabling acpi notifications.

2. input and backlight devices were unregistered before acpi
   notifications are disabled.  This left a window where
   eeepc_hotk_notify() might find these devices in an inconsistent
   (half-destroyed) state.

-> Move all device unregistration into eeepc_hotk_remove(), which is
   called after disabling acpi notifications.

3. The acpi driver was not freed if an error occured further down in
   eeepc_laptop_init().

-> The rest of eeepc_laptop_init() has been moved to eeepc_hotk_add(),
   so this is no longer a problem.

4. The acpi driver was unregistered before the platform driver.  This
   left a window where a sysfs access could attempt to read the ehotk
   structure after it had been freed by eeepc_hotk_remove().

-> The acpi driver is now unregistered as the last step in
   eeepc_laptop_exit(), so this is no longer a problem.

Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/platform/x86/eeepc-laptop.c

index 079b016..c22fe07 100644 (file)
@@ -849,55 +849,6 @@ error_slot:
        return ret;
 }
 
-static int eeepc_hotk_add(struct acpi_device *device)
-{
-       acpi_status status = AE_OK;
-       int result;
-
-       if (!device)
-                return -EINVAL;
-       pr_notice(EEEPC_HOTK_NAME "\n");
-       ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
-       if (!ehotk)
-               return -ENOMEM;
-       ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
-       ehotk->handle = device->handle;
-       strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
-       strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
-       device->driver_data = ehotk;
-       ehotk->device = device;
-       result = eeepc_hotk_check();
-       if (result)
-               goto ehotk_fail;
-       status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
-                                            eeepc_hotk_notify, ehotk);
-       if (ACPI_FAILURE(status))
-               pr_err("Error installing notify handler\n");
-
-       return 0;
-
- ehotk_fail:
-       kfree(ehotk);
-       ehotk = NULL;
-
-       return result;
-}
-
-static int eeepc_hotk_remove(struct acpi_device *device, int type)
-{
-       acpi_status status = 0;
-
-       if (!device || !acpi_driver_data(device))
-                return -EINVAL;
-       status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
-                                           eeepc_hotk_notify);
-       if (ACPI_FAILURE(status))
-               pr_err("Error removing notify handler\n");
-
-       kfree(ehotk);
-       return 0;
-}
-
 static int eeepc_hotk_resume(struct acpi_device *device)
 {
        if (ehotk->wlan_rfkill) {
@@ -1080,19 +1031,6 @@ static void eeepc_hwmon_exit(void)
        eeepc_hwmon_device = NULL;
 }
 
-static void __exit eeepc_laptop_exit(void)
-{
-       eeepc_backlight_exit();
-       eeepc_rfkill_exit();
-       eeepc_input_exit();
-       eeepc_hwmon_exit();
-       acpi_bus_unregister_driver(&eeepc_hotk_driver);
-       sysfs_remove_group(&platform_device->dev.kobj,
-                          &platform_attribute_group);
-       platform_device_unregister(platform_device);
-       platform_driver_unregister(&platform_driver);
-}
-
 static struct rfkill *eeepc_rfkill_alloc(const char *name,
                                         struct device *dev,
                                         enum rfkill_type type, int asl)
@@ -1227,20 +1165,32 @@ static int eeepc_hwmon_init(struct device *dev)
        return result;
 }
 
-static int __init eeepc_laptop_init(void)
+static int eeepc_hotk_add(struct acpi_device *device)
 {
+       acpi_status status;
        struct device *dev;
        int result;
 
-       if (acpi_disabled)
-               return -ENODEV;
-       result = acpi_bus_register_driver(&eeepc_hotk_driver);
-       if (result < 0)
-               return result;
-       if (!ehotk) {
-               acpi_bus_unregister_driver(&eeepc_hotk_driver);
-               return -ENODEV;
-       }
+       if (!device)
+                return -EINVAL;
+       pr_notice(EEEPC_HOTK_NAME "\n");
+       ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
+       if (!ehotk)
+               return -ENOMEM;
+       ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
+       ehotk->handle = device->handle;
+       strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
+       strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
+       device->driver_data = ehotk;
+       ehotk->device = device;
+
+       result = eeepc_hotk_check();
+       if (result)
+               goto fail_check;
+       status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+                                            eeepc_hotk_notify, ehotk);
+       if (ACPI_FAILURE(status))
+               pr_err("Error installing notify handler\n");
 
        eeepc_enable_camera();
 
@@ -1280,6 +1230,7 @@ static int __init eeepc_laptop_init(void)
                goto fail_rfkill;
 
        return 0;
+
 fail_rfkill:
        eeepc_hwmon_exit();
 fail_hwmon:
@@ -1295,8 +1246,57 @@ fail_platform_device1:
        platform_driver_unregister(&platform_driver);
 fail_platform_driver:
        eeepc_input_exit();
+fail_check:
+       kfree(ehotk);
+
        return result;
 }
 
+static int eeepc_hotk_remove(struct acpi_device *device, int type)
+{
+       acpi_status status;
+
+       if (!device || !acpi_driver_data(device))
+                return -EINVAL;
+
+       eeepc_backlight_exit();
+       eeepc_rfkill_exit();
+       eeepc_input_exit();
+       eeepc_hwmon_exit();
+       sysfs_remove_group(&platform_device->dev.kobj,
+                          &platform_attribute_group);
+       platform_device_unregister(platform_device);
+       platform_driver_unregister(&platform_driver);
+
+       status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+                                           eeepc_hotk_notify);
+       if (ACPI_FAILURE(status))
+               pr_err("Error removing notify handler\n");
+
+       kfree(ehotk);
+       return 0;
+}
+
+static int __init eeepc_laptop_init(void)
+{
+       int result;
+
+       if (acpi_disabled)
+               return -ENODEV;
+       result = acpi_bus_register_driver(&eeepc_hotk_driver);
+       if (result < 0)
+               return result;
+       if (!ehotk) {
+               acpi_bus_unregister_driver(&eeepc_hotk_driver);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __exit eeepc_laptop_exit(void)
+{
+       acpi_bus_unregister_driver(&eeepc_hotk_driver);
+}
+
 module_init(eeepc_laptop_init);
 module_exit(eeepc_laptop_exit);