diff options
author | Corentin Chary <corentincj@iksaif.net> | 2010-11-29 08:14:05 +0100 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-01-07 17:03:42 -0500 |
commit | 27c136c8738f6bec10c26aaf0a486f19edef7bf7 (patch) | |
tree | 5de03b4c3b824e9d49ccc3acaf31f8f653eadf0a /drivers/platform | |
parent | 72135d21b587debcbcc57e0dbcc8bcfa4dacb661 (diff) | |
download | linux-27c136c8738f6bec10c26aaf0a486f19edef7bf7.tar.gz linux-27c136c8738f6bec10c26aaf0a486f19edef7bf7.tar.bz2 linux-27c136c8738f6bec10c26aaf0a486f19edef7bf7.zip |
eeepc-wmi: rework eeepc_wmi_init and eeepc_wmi_exit
The old code was using platform_driver.probe to initialize
eeepc_wmi context. That's a mistake because if probe fail,
eeepc_platform_register() won't tell anyone, and chaos will happen.
Wrap add and remove code inside eeepc_wmi_add() / eeepc_wmi_remove(),
and try to use the static platform_device only in eeepc_wmi_init()
and eeepc_wmi_exit()
The code is now very similar to eeepc-laptop, except eeepc_laptop_add
and eeepc_laptop_remove are called from acpi_driver, not module
init/exit functions, but WMI doesn't provide such functionalities (yet ?).
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/eeepc-wmi.c | 135 |
1 files changed, 79 insertions, 56 deletions
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 0d50fbbe2478..dfbb295326be 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -86,8 +86,10 @@ struct bios_args { struct eeepc_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; + struct platform_device *platform_device; }; +/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ static struct platform_device *platform_device; static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) @@ -101,7 +103,7 @@ static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) eeepc->inputdev->name = "Eee PC WMI hotkeys"; eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; eeepc->inputdev->id.bustype = BUS_HOST; - eeepc->inputdev->dev.parent = &platform_device->dev; + eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); if (err) @@ -234,7 +236,7 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 15; bd = backlight_device_register(EEEPC_WMI_FILE, - &platform_device->dev, eeepc, + &eeepc->platform_device->dev, eeepc, &eeepc_wmi_bl_ops, &props); if (IS_ERR(bd)) { pr_err("Could not register backlight device\n"); @@ -337,49 +339,99 @@ static int eeepc_wmi_sysfs_init(struct platform_device *device) return 0; error_sysfs: - eeepc_wmi_sysfs_exit(platform_device); + eeepc_wmi_sysfs_exit(device); return retval; } -static int __devinit eeepc_wmi_platform_probe(struct platform_device *device) +/* + * Platform device + */ +static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) { - struct eeepc_wmi *eeepc; int err; + + eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); + if (!eeepc->platform_device) + return -ENOMEM; + platform_set_drvdata(eeepc->platform_device, eeepc); + + err = platform_device_add(eeepc->platform_device); + if (err) + goto fail_platform_device; + + err = eeepc_wmi_sysfs_init(eeepc->platform_device); + if (err) + goto fail_sysfs; + return 0; + +fail_sysfs: + platform_device_del(eeepc->platform_device); +fail_platform_device: + platform_device_put(eeepc->platform_device); + return err; +} + +static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) +{ + eeepc_wmi_sysfs_exit(eeepc->platform_device); + platform_device_unregister(eeepc->platform_device); +} + +/* + * WMI Driver + */ +static struct platform_device * __init eeepc_wmi_add(void) +{ + struct eeepc_wmi *eeepc; acpi_status status; + int err; - eeepc = platform_get_drvdata(device); + eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); + if (!eeepc) + return ERR_PTR(-ENOMEM); + + /* + * Register the platform device first. It is used as a parent for the + * sub-devices below. + */ + err = eeepc_wmi_platform_init(eeepc); + if (err) + goto fail_platform; err = eeepc_wmi_input_init(eeepc); if (err) - goto error_input; + goto fail_input; if (!acpi_video_backlight_support()) { err = eeepc_wmi_backlight_init(eeepc); if (err) - goto error_backlight; + goto fail_backlight; } else pr_info("Backlight controlled by ACPI video driver\n"); status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, - eeepc_wmi_notify, eeepc); + eeepc_wmi_notify, eeepc); if (ACPI_FAILURE(status)) { pr_err("Unable to register notify handler - %d\n", status); err = -ENODEV; - goto error_wmi; + goto fail_wmi_handler; } - return 0; + return eeepc->platform_device; -error_wmi: +fail_wmi_handler: eeepc_wmi_backlight_exit(eeepc); -error_backlight: +fail_backlight: eeepc_wmi_input_exit(eeepc); -error_input: - return err; +fail_input: + eeepc_wmi_platform_exit(eeepc); +fail_platform: + kfree(eeepc); + return ERR_PTR(err); } -static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) +static int eeepc_wmi_remove(struct platform_device *device) { struct eeepc_wmi *eeepc; @@ -387,7 +439,9 @@ static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); eeepc_wmi_backlight_exit(eeepc); eeepc_wmi_input_exit(eeepc); + eeepc_wmi_platform_exit(eeepc); + kfree(eeepc); return 0; } @@ -396,13 +450,10 @@ static struct platform_driver platform_driver = { .name = EEEPC_WMI_FILE, .owner = THIS_MODULE, }, - .probe = eeepc_wmi_platform_probe, - .remove = __devexit_p(eeepc_wmi_platform_remove), }; static int __init eeepc_wmi_init(void) { - struct eeepc_wmi *eeepc; int err; if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || @@ -411,58 +462,30 @@ static int __init eeepc_wmi_init(void) return -ENODEV; } - eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); - if (!eeepc) - return -ENOMEM; - - platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); - if (!platform_device) { - pr_warning("Unable to allocate platform device\n"); - err = -ENOMEM; - goto fail_platform; + platform_device = eeepc_wmi_add(); + if (IS_ERR(platform_device)) { + err = PTR_ERR(platform_device); + goto fail_eeepc_wmi; } - err = platform_device_add(platform_device); - if (err) { - pr_warning("Unable to add platform device\n"); - goto put_dev; - } - - platform_set_drvdata(platform_device, eeepc); - err = platform_driver_register(&platform_driver); if (err) { pr_warning("Unable to register platform driver\n"); - goto del_dev; + goto fail_platform_driver; } - err = eeepc_wmi_sysfs_init(platform_device); - if (err) - goto del_sysfs; - return 0; -del_sysfs: - eeepc_wmi_sysfs_exit(platform_device); -del_dev: - platform_device_del(platform_device); -put_dev: - platform_device_put(platform_device); -fail_platform: - kfree(eeepc); - +fail_platform_driver: + eeepc_wmi_remove(platform_device); +fail_eeepc_wmi: return err; } static void __exit eeepc_wmi_exit(void) { - struct eeepc_wmi *eeepc; - - eeepc_wmi_sysfs_exit(platform_device); - eeepc = platform_get_drvdata(platform_device); + eeepc_wmi_remove(platform_device); platform_driver_unregister(&platform_driver); - platform_device_unregister(platform_device); - kfree(eeepc); } module_init(eeepc_wmi_init); |