Skip to content

Commit

Permalink
eeepc-laptop: fix ordering of init and exit functions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alan Jenkins authored and Len Brown committed Aug 28, 2009
1 parent 07e84aa commit 1e77985
Showing 1 changed file with 59 additions and 61 deletions.
120 changes: 59 additions & 61 deletions drivers/platform/x86/eeepc-laptop.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,44 +847,6 @@ static int eeepc_setup_pci_hotplug(void)
return ret;
}

static int eeepc_hotk_add(struct acpi_device *device)
{
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;

return 0;

ehotk_fail:
kfree(ehotk);
ehotk = NULL;

return result;
}

static int eeepc_hotk_remove(struct acpi_device *device, int type)
{
if (!device || !acpi_driver_data(device))
return -EINVAL;

kfree(ehotk);
return 0;
}

static int eeepc_hotk_resume(struct acpi_device *device)
{
if (ehotk->wlan_rfkill) {
Expand Down Expand Up @@ -1066,19 +1028,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 int eeepc_new_rfkill(struct rfkill **rfkill,
const char *name, struct device *dev,
enum rfkill_type type, int cm)
Expand Down Expand Up @@ -1193,21 +1142,27 @@ 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)
{
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;
eeepc_enable_camera();

/* Register platform stuff */
Expand Down Expand Up @@ -1246,6 +1201,7 @@ static int __init eeepc_laptop_init(void)
goto fail_rfkill;

return 0;

fail_rfkill:
eeepc_hwmon_exit();
fail_hwmon:
Expand All @@ -1261,8 +1217,50 @@ static int __init eeepc_laptop_init(void)
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)
{
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);

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);

0 comments on commit 1e77985

Please sign in to comment.