diff options
author | Corentin Chary <corentincj@iksaif.net> | 2010-11-29 02:14:05 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-01-07 17:03:42 -0500 |
commit | 27c136c8738f6bec10c26aaf0a486f19edef7bf7 (patch) | |
tree | 5de03b4c3b824e9d49ccc3acaf31f8f653eadf0a /drivers/platform | |
parent | 72135d21b587debcbcc57e0dbcc8bcfa4dacb661 (diff) |
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 0d50fbbe247..dfbb295326b 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c | |||
@@ -86,8 +86,10 @@ struct bios_args { | |||
86 | struct eeepc_wmi { | 86 | struct eeepc_wmi { |
87 | struct input_dev *inputdev; | 87 | struct input_dev *inputdev; |
88 | struct backlight_device *backlight_device; | 88 | struct backlight_device *backlight_device; |
89 | struct platform_device *platform_device; | ||
89 | }; | 90 | }; |
90 | 91 | ||
92 | /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ | ||
91 | static struct platform_device *platform_device; | 93 | static struct platform_device *platform_device; |
92 | 94 | ||
93 | static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) | 95 | static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) |
@@ -101,7 +103,7 @@ static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) | |||
101 | eeepc->inputdev->name = "Eee PC WMI hotkeys"; | 103 | eeepc->inputdev->name = "Eee PC WMI hotkeys"; |
102 | eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; | 104 | eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; |
103 | eeepc->inputdev->id.bustype = BUS_HOST; | 105 | eeepc->inputdev->id.bustype = BUS_HOST; |
104 | eeepc->inputdev->dev.parent = &platform_device->dev; | 106 | eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; |
105 | 107 | ||
106 | err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); | 108 | err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); |
107 | if (err) | 109 | if (err) |
@@ -234,7 +236,7 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) | |||
234 | memset(&props, 0, sizeof(struct backlight_properties)); | 236 | memset(&props, 0, sizeof(struct backlight_properties)); |
235 | props.max_brightness = 15; | 237 | props.max_brightness = 15; |
236 | bd = backlight_device_register(EEEPC_WMI_FILE, | 238 | bd = backlight_device_register(EEEPC_WMI_FILE, |
237 | &platform_device->dev, eeepc, | 239 | &eeepc->platform_device->dev, eeepc, |
238 | &eeepc_wmi_bl_ops, &props); | 240 | &eeepc_wmi_bl_ops, &props); |
239 | if (IS_ERR(bd)) { | 241 | if (IS_ERR(bd)) { |
240 | pr_err("Could not register backlight device\n"); | 242 | pr_err("Could not register backlight device\n"); |
@@ -337,49 +339,99 @@ static int eeepc_wmi_sysfs_init(struct platform_device *device) | |||
337 | return 0; | 339 | return 0; |
338 | 340 | ||
339 | error_sysfs: | 341 | error_sysfs: |
340 | eeepc_wmi_sysfs_exit(platform_device); | 342 | eeepc_wmi_sysfs_exit(device); |
341 | return retval; | 343 | return retval; |
342 | } | 344 | } |
343 | 345 | ||
344 | static int __devinit eeepc_wmi_platform_probe(struct platform_device *device) | 346 | /* |
347 | * Platform device | ||
348 | */ | ||
349 | static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) | ||
345 | { | 350 | { |
346 | struct eeepc_wmi *eeepc; | ||
347 | int err; | 351 | int err; |
352 | |||
353 | eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); | ||
354 | if (!eeepc->platform_device) | ||
355 | return -ENOMEM; | ||
356 | platform_set_drvdata(eeepc->platform_device, eeepc); | ||
357 | |||
358 | err = platform_device_add(eeepc->platform_device); | ||
359 | if (err) | ||
360 | goto fail_platform_device; | ||
361 | |||
362 | err = eeepc_wmi_sysfs_init(eeepc->platform_device); | ||
363 | if (err) | ||
364 | goto fail_sysfs; | ||
365 | return 0; | ||
366 | |||
367 | fail_sysfs: | ||
368 | platform_device_del(eeepc->platform_device); | ||
369 | fail_platform_device: | ||
370 | platform_device_put(eeepc->platform_device); | ||
371 | return err; | ||
372 | } | ||
373 | |||
374 | static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) | ||
375 | { | ||
376 | eeepc_wmi_sysfs_exit(eeepc->platform_device); | ||
377 | platform_device_unregister(eeepc->platform_device); | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * WMI Driver | ||
382 | */ | ||
383 | static struct platform_device * __init eeepc_wmi_add(void) | ||
384 | { | ||
385 | struct eeepc_wmi *eeepc; | ||
348 | acpi_status status; | 386 | acpi_status status; |
387 | int err; | ||
349 | 388 | ||
350 | eeepc = platform_get_drvdata(device); | 389 | eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); |
390 | if (!eeepc) | ||
391 | return ERR_PTR(-ENOMEM); | ||
392 | |||
393 | /* | ||
394 | * Register the platform device first. It is used as a parent for the | ||
395 | * sub-devices below. | ||
396 | */ | ||
397 | err = eeepc_wmi_platform_init(eeepc); | ||
398 | if (err) | ||
399 | goto fail_platform; | ||
351 | 400 | ||
352 | err = eeepc_wmi_input_init(eeepc); | 401 | err = eeepc_wmi_input_init(eeepc); |
353 | if (err) | 402 | if (err) |
354 | goto error_input; | 403 | goto fail_input; |
355 | 404 | ||
356 | if (!acpi_video_backlight_support()) { | 405 | if (!acpi_video_backlight_support()) { |
357 | err = eeepc_wmi_backlight_init(eeepc); | 406 | err = eeepc_wmi_backlight_init(eeepc); |
358 | if (err) | 407 | if (err) |
359 | goto error_backlight; | 408 | goto fail_backlight; |
360 | } else | 409 | } else |
361 | pr_info("Backlight controlled by ACPI video driver\n"); | 410 | pr_info("Backlight controlled by ACPI video driver\n"); |
362 | 411 | ||
363 | status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, | 412 | status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, |
364 | eeepc_wmi_notify, eeepc); | 413 | eeepc_wmi_notify, eeepc); |
365 | if (ACPI_FAILURE(status)) { | 414 | if (ACPI_FAILURE(status)) { |
366 | pr_err("Unable to register notify handler - %d\n", | 415 | pr_err("Unable to register notify handler - %d\n", |
367 | status); | 416 | status); |
368 | err = -ENODEV; | 417 | err = -ENODEV; |
369 | goto error_wmi; | 418 | goto fail_wmi_handler; |
370 | } | 419 | } |
371 | 420 | ||
372 | return 0; | 421 | return eeepc->platform_device; |
373 | 422 | ||
374 | error_wmi: | 423 | fail_wmi_handler: |
375 | eeepc_wmi_backlight_exit(eeepc); | 424 | eeepc_wmi_backlight_exit(eeepc); |
376 | error_backlight: | 425 | fail_backlight: |
377 | eeepc_wmi_input_exit(eeepc); | 426 | eeepc_wmi_input_exit(eeepc); |
378 | error_input: | 427 | fail_input: |
379 | return err; | 428 | eeepc_wmi_platform_exit(eeepc); |
429 | fail_platform: | ||
430 | kfree(eeepc); | ||
431 | return ERR_PTR(err); | ||
380 | } | 432 | } |
381 | 433 | ||
382 | static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) | 434 | static int eeepc_wmi_remove(struct platform_device *device) |
383 | { | 435 | { |
384 | struct eeepc_wmi *eeepc; | 436 | struct eeepc_wmi *eeepc; |
385 | 437 | ||
@@ -387,7 +439,9 @@ static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) | |||
387 | wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); | 439 | wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); |
388 | eeepc_wmi_backlight_exit(eeepc); | 440 | eeepc_wmi_backlight_exit(eeepc); |
389 | eeepc_wmi_input_exit(eeepc); | 441 | eeepc_wmi_input_exit(eeepc); |
442 | eeepc_wmi_platform_exit(eeepc); | ||
390 | 443 | ||
444 | kfree(eeepc); | ||
391 | return 0; | 445 | return 0; |
392 | } | 446 | } |
393 | 447 | ||
@@ -396,13 +450,10 @@ static struct platform_driver platform_driver = { | |||
396 | .name = EEEPC_WMI_FILE, | 450 | .name = EEEPC_WMI_FILE, |
397 | .owner = THIS_MODULE, | 451 | .owner = THIS_MODULE, |
398 | }, | 452 | }, |
399 | .probe = eeepc_wmi_platform_probe, | ||
400 | .remove = __devexit_p(eeepc_wmi_platform_remove), | ||
401 | }; | 453 | }; |
402 | 454 | ||
403 | static int __init eeepc_wmi_init(void) | 455 | static int __init eeepc_wmi_init(void) |
404 | { | 456 | { |
405 | struct eeepc_wmi *eeepc; | ||
406 | int err; | 457 | int err; |
407 | 458 | ||
408 | if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || | 459 | if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || |
@@ -411,58 +462,30 @@ static int __init eeepc_wmi_init(void) | |||
411 | return -ENODEV; | 462 | return -ENODEV; |
412 | } | 463 | } |
413 | 464 | ||
414 | eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); | 465 | platform_device = eeepc_wmi_add(); |
415 | if (!eeepc) | 466 | if (IS_ERR(platform_device)) { |
416 | return -ENOMEM; | 467 | err = PTR_ERR(platform_device); |
417 | 468 | goto fail_eeepc_wmi; | |
418 | platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); | ||
419 | if (!platform_device) { | ||
420 | pr_warning("Unable to allocate platform device\n"); | ||
421 | err = -ENOMEM; | ||
422 | goto fail_platform; | ||
423 | } | 469 | } |
424 | 470 | ||
425 | err = platform_device_add(platform_device); | ||
426 | if (err) { | ||
427 | pr_warning("Unable to add platform device\n"); | ||
428 | goto put_dev; | ||
429 | } | ||
430 | |||
431 | platform_set_drvdata(platform_device, eeepc); | ||
432 | |||
433 | err = platform_driver_register(&platform_driver); | 471 | err = platform_driver_register(&platform_driver); |
434 | if (err) { | 472 | if (err) { |
435 | pr_warning("Unable to register platform driver\n"); | 473 | pr_warning("Unable to register platform driver\n"); |
436 | goto del_dev; | 474 | goto fail_platform_driver; |
437 | } | 475 | } |
438 | 476 | ||
439 | err = eeepc_wmi_sysfs_init(platform_device); | ||
440 | if (err) | ||
441 | goto del_sysfs; | ||
442 | |||
443 | return 0; | 477 | return 0; |
444 | 478 | ||
445 | del_sysfs: | 479 | fail_platform_driver: |
446 | eeepc_wmi_sysfs_exit(platform_device); | 480 | eeepc_wmi_remove(platform_device); |
447 | del_dev: | 481 | fail_eeepc_wmi: |
448 | platform_device_del(platform_device); | ||
449 | put_dev: | ||
450 | platform_device_put(platform_device); | ||
451 | fail_platform: | ||
452 | kfree(eeepc); | ||
453 | |||
454 | return err; | 482 | return err; |
455 | } | 483 | } |
456 | 484 | ||
457 | static void __exit eeepc_wmi_exit(void) | 485 | static void __exit eeepc_wmi_exit(void) |
458 | { | 486 | { |
459 | struct eeepc_wmi *eeepc; | 487 | eeepc_wmi_remove(platform_device); |
460 | |||
461 | eeepc_wmi_sysfs_exit(platform_device); | ||
462 | eeepc = platform_get_drvdata(platform_device); | ||
463 | platform_driver_unregister(&platform_driver); | 488 | platform_driver_unregister(&platform_driver); |
464 | platform_device_unregister(platform_device); | ||
465 | kfree(eeepc); | ||
466 | } | 489 | } |
467 | 490 | ||
468 | module_init(eeepc_wmi_init); | 491 | module_init(eeepc_wmi_init); |