diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-05 01:30:02 -0400 |
|---|---|---|
| committer | Matthew Garrett <mjg@redhat.com> | 2010-10-21 09:36:42 -0400 |
| commit | 1a765cac9a241380511a3b1dd4edf74a41cbfdf9 (patch) | |
| tree | 8750624e54e162082abb379170bf54197d99d2b7 /drivers/platform | |
| parent | 97490f1cf82cccf2e088aafffb0517802f0ee336 (diff) | |
panasonic-laptop - switch to using sparse keymap library
nstead of implementing its own version of keymap hanlding switch over to
using sparse keymap library.
Cc: Harald Welte <laforge@gnumonks.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
| -rw-r--r-- | drivers/platform/x86/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/platform/x86/panasonic-laptop.c | 172 |
2 files changed, 62 insertions, 111 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0b11b41a85f9..c0446d67cf7a 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
| @@ -171,6 +171,7 @@ config PANASONIC_LAPTOP | |||
| 171 | tristate "Panasonic Laptop Extras" | 171 | tristate "Panasonic Laptop Extras" |
| 172 | depends on INPUT && ACPI | 172 | depends on INPUT && ACPI |
| 173 | depends on BACKLIGHT_CLASS_DEVICE | 173 | depends on BACKLIGHT_CLASS_DEVICE |
| 174 | select INPUT_SPARSEKMAP | ||
| 174 | ---help--- | 175 | ---help--- |
| 175 | This driver adds support for access to backlight control and hotkeys | 176 | This driver adds support for access to backlight control and hotkeys |
| 176 | on Panasonic Let's Note laptops. | 177 | on Panasonic Let's Note laptops. |
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index ec01c3d8fc5a..b3b9e0458ae1 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c | |||
| @@ -128,6 +128,7 @@ | |||
| 128 | #include <acpi/acpi_bus.h> | 128 | #include <acpi/acpi_bus.h> |
| 129 | #include <acpi/acpi_drivers.h> | 129 | #include <acpi/acpi_drivers.h> |
| 130 | #include <linux/input.h> | 130 | #include <linux/input.h> |
| 131 | #include <linux/input/sparse-keymap.h> | ||
| 131 | 132 | ||
| 132 | 133 | ||
| 133 | #ifndef ACPI_HOTKEY_COMPONENT | 134 | #ifndef ACPI_HOTKEY_COMPONENT |
| @@ -200,30 +201,29 @@ static struct acpi_driver acpi_pcc_driver = { | |||
| 200 | }, | 201 | }, |
| 201 | }; | 202 | }; |
| 202 | 203 | ||
| 203 | #define KEYMAP_SIZE 11 | 204 | static const struct key_entry panasonic_keymap[] = { |
| 204 | static const unsigned int initial_keymap[KEYMAP_SIZE] = { | 205 | { KE_KEY, 0, { KEY_RESERVED } }, |
| 205 | /* 0 */ KEY_RESERVED, | 206 | { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } }, |
| 206 | /* 1 */ KEY_BRIGHTNESSDOWN, | 207 | { KE_KEY, 2, { KEY_BRIGHTNESSUP } }, |
| 207 | /* 2 */ KEY_BRIGHTNESSUP, | 208 | { KE_KEY, 3, { KEY_DISPLAYTOGGLE } }, |
| 208 | /* 3 */ KEY_DISPLAYTOGGLE, | 209 | { KE_KEY, 4, { KEY_MUTE } }, |
| 209 | /* 4 */ KEY_MUTE, | 210 | { KE_KEY, 5, { KEY_VOLUMEDOWN } }, |
| 210 | /* 5 */ KEY_VOLUMEDOWN, | 211 | { KE_KEY, 6, { KEY_VOLUMEUP } }, |
| 211 | /* 6 */ KEY_VOLUMEUP, | 212 | { KE_KEY, 7, { KEY_SLEEP } }, |
| 212 | /* 7 */ KEY_SLEEP, | 213 | { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */ |
| 213 | /* 8 */ KEY_PROG1, /* Change CPU boost */ | 214 | { KE_KEY, 9, { KEY_BATTERY } }, |
| 214 | /* 9 */ KEY_BATTERY, | 215 | { KE_KEY, 10, { KEY_SUSPEND } }, |
| 215 | /* 10 */ KEY_SUSPEND, | 216 | { KE_END, 0 } |
| 216 | }; | 217 | }; |
| 217 | 218 | ||
| 218 | struct pcc_acpi { | 219 | struct pcc_acpi { |
| 219 | acpi_handle handle; | 220 | acpi_handle handle; |
| 220 | unsigned long num_sifr; | 221 | unsigned long num_sifr; |
| 221 | int sticky_mode; | 222 | int sticky_mode; |
| 222 | u32 *sinf; | 223 | u32 *sinf; |
| 223 | struct acpi_device *device; | 224 | struct acpi_device *device; |
| 224 | struct input_dev *input_dev; | 225 | struct input_dev *input_dev; |
| 225 | struct backlight_device *backlight; | 226 | struct backlight_device *backlight; |
| 226 | unsigned int keymap[KEYMAP_SIZE]; | ||
| 227 | }; | 227 | }; |
| 228 | 228 | ||
| 229 | struct pcc_keyinput { | 229 | struct pcc_keyinput { |
| @@ -446,56 +446,10 @@ static struct attribute_group pcc_attr_group = { | |||
| 446 | 446 | ||
| 447 | /* hotkey input device driver */ | 447 | /* hotkey input device driver */ |
| 448 | 448 | ||
| 449 | static int pcc_getkeycode(struct input_dev *dev, | ||
| 450 | unsigned int scancode, unsigned int *keycode) | ||
| 451 | { | ||
| 452 | struct pcc_acpi *pcc = input_get_drvdata(dev); | ||
| 453 | |||
| 454 | if (scancode >= ARRAY_SIZE(pcc->keymap)) | ||
| 455 | return -EINVAL; | ||
| 456 | |||
| 457 | *keycode = pcc->keymap[scancode]; | ||
| 458 | |||
| 459 | return 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode) | ||
| 463 | { | ||
| 464 | int i; | ||
| 465 | |||
| 466 | for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) { | ||
| 467 | if (pcc->keymap[i] == keycode) | ||
| 468 | return i+1; | ||
| 469 | } | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | static int pcc_setkeycode(struct input_dev *dev, | ||
| 475 | unsigned int scancode, unsigned int keycode) | ||
| 476 | { | ||
| 477 | struct pcc_acpi *pcc = input_get_drvdata(dev); | ||
| 478 | int oldkeycode; | ||
| 479 | |||
| 480 | if (scancode >= ARRAY_SIZE(pcc->keymap)) | ||
| 481 | return -EINVAL; | ||
| 482 | |||
| 483 | oldkeycode = pcc->keymap[scancode]; | ||
| 484 | pcc->keymap[scancode] = keycode; | ||
| 485 | |||
| 486 | set_bit(keycode, dev->keybit); | ||
| 487 | |||
| 488 | if (!keymap_get_by_keycode(pcc, oldkeycode)) | ||
| 489 | clear_bit(oldkeycode, dev->keybit); | ||
| 490 | |||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) | 449 | static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) |
| 495 | { | 450 | { |
| 496 | struct input_dev *hotk_input_dev = pcc->input_dev; | 451 | struct input_dev *hotk_input_dev = pcc->input_dev; |
| 497 | int rc; | 452 | int rc; |
| 498 | int key_code, hkey_num; | ||
| 499 | unsigned long long result; | 453 | unsigned long long result; |
| 500 | 454 | ||
| 501 | rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, | 455 | rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, |
| @@ -508,25 +462,10 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) | |||
| 508 | 462 | ||
| 509 | acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result); | 463 | acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result); |
| 510 | 464 | ||
| 511 | hkey_num = result & 0xf; | 465 | if (!sparse_keymap_report_event(hotk_input_dev, |
| 512 | 466 | result & 0xf, result & 0x80, false)) | |
| 513 | if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) { | ||
| 514 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | 467 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, |
| 515 | "hotkey number out of range: %d\n", | 468 | "Unknown hotkey event: %d\n", result)); |
| 516 | hkey_num)); | ||
| 517 | return; | ||
| 518 | } | ||
| 519 | |||
| 520 | key_code = pcc->keymap[hkey_num]; | ||
| 521 | |||
| 522 | if (key_code != KEY_RESERVED) { | ||
| 523 | int pushed = (result & 0x80) ? TRUE : FALSE; | ||
| 524 | |||
| 525 | input_report_key(hotk_input_dev, key_code, pushed); | ||
| 526 | input_sync(hotk_input_dev); | ||
| 527 | } | ||
| 528 | |||
| 529 | return; | ||
| 530 | } | 469 | } |
| 531 | 470 | ||
| 532 | static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) | 471 | static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) |
| @@ -545,40 +484,55 @@ static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) | |||
| 545 | 484 | ||
| 546 | static int acpi_pcc_init_input(struct pcc_acpi *pcc) | 485 | static int acpi_pcc_init_input(struct pcc_acpi *pcc) |
| 547 | { | 486 | { |
| 548 | int i, rc; | 487 | struct input_dev *input_dev; |
| 488 | int error; | ||
| 549 | 489 | ||
| 550 | pcc->input_dev = input_allocate_device(); | 490 | input_dev = input_allocate_device(); |
| 551 | if (!pcc->input_dev) { | 491 | if (!input_dev) { |
| 552 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | 492 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, |
| 553 | "Couldn't allocate input device for hotkey")); | 493 | "Couldn't allocate input device for hotkey")); |
| 554 | return -ENOMEM; | 494 | return -ENOMEM; |
| 555 | } | 495 | } |
| 556 | 496 | ||
| 557 | pcc->input_dev->evbit[0] = BIT(EV_KEY); | 497 | input_dev->name = ACPI_PCC_DRIVER_NAME; |
| 558 | 498 | input_dev->phys = ACPI_PCC_INPUT_PHYS; | |
| 559 | pcc->input_dev->name = ACPI_PCC_DRIVER_NAME; | 499 | input_dev->id.bustype = BUS_HOST; |
| 560 | pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS; | 500 | input_dev->id.vendor = 0x0001; |
| 561 | pcc->input_dev->id.bustype = BUS_HOST; | 501 | input_dev->id.product = 0x0001; |
| 562 | pcc->input_dev->id.vendor = 0x0001; | 502 | input_dev->id.version = 0x0100; |
| 563 | pcc->input_dev->id.product = 0x0001; | ||
| 564 | pcc->input_dev->id.version = 0x0100; | ||
| 565 | pcc->input_dev->getkeycode = pcc_getkeycode; | ||
| 566 | pcc->input_dev->setkeycode = pcc_setkeycode; | ||
| 567 | 503 | ||
| 568 | /* load initial keymap */ | 504 | error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL); |
| 569 | memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap)); | 505 | if (error) { |
| 506 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 507 | "Unable to setup input device keymap\n")); | ||
| 508 | goto err_free_dev; | ||
| 509 | } | ||
| 570 | 510 | ||
| 571 | for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) | 511 | error = input_register_device(input_dev); |
| 572 | __set_bit(pcc->keymap[i], pcc->input_dev->keybit); | 512 | if (error) { |
| 573 | __clear_bit(KEY_RESERVED, pcc->input_dev->keybit); | 513 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, |
| 514 | "Unable to register input device\n")); | ||
| 515 | goto err_free_keymap; | ||
| 516 | } | ||
| 574 | 517 | ||
| 575 | input_set_drvdata(pcc->input_dev, pcc); | 518 | pcc->input_dev = input_dev; |
| 519 | return 0; | ||
| 576 | 520 | ||
| 577 | rc = input_register_device(pcc->input_dev); | 521 | err_free_keymap: |
| 578 | if (rc < 0) | 522 | sparse_keymap_free(input_dev); |
| 579 | input_free_device(pcc->input_dev); | 523 | err_free_dev: |
| 524 | input_free_device(input_dev); | ||
| 525 | return error; | ||
| 526 | } | ||
| 580 | 527 | ||
| 581 | return rc; | 528 | static void acpi_pcc_destroy_input(struct pcc_acpi *pcc) |
| 529 | { | ||
| 530 | sparse_keymap_free(pcc->input_dev); | ||
| 531 | input_unregister_device(pcc->input_dev); | ||
| 532 | /* | ||
| 533 | * No need to input_free_device() since core input API refcounts | ||
| 534 | * and free()s the device. | ||
| 535 | */ | ||
| 582 | } | 536 | } |
| 583 | 537 | ||
| 584 | /* kernel module interface */ | 538 | /* kernel module interface */ |
| @@ -636,7 +590,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) | |||
| 636 | if (result) { | 590 | if (result) { |
| 637 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | 591 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, |
| 638 | "Error installing keyinput handler\n")); | 592 | "Error installing keyinput handler\n")); |
| 639 | goto out_hotkey; | 593 | goto out_sinf; |
| 640 | } | 594 | } |
| 641 | 595 | ||
| 642 | if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) { | 596 | if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) { |
| @@ -651,7 +605,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) | |||
| 651 | &pcc_backlight_ops, &props); | 605 | &pcc_backlight_ops, &props); |
| 652 | if (IS_ERR(pcc->backlight)) { | 606 | if (IS_ERR(pcc->backlight)) { |
| 653 | result = PTR_ERR(pcc->backlight); | 607 | result = PTR_ERR(pcc->backlight); |
| 654 | goto out_sinf; | 608 | goto out_input; |
| 655 | } | 609 | } |
| 656 | 610 | ||
| 657 | /* read the initial brightness setting from the hardware */ | 611 | /* read the initial brightness setting from the hardware */ |
| @@ -669,12 +623,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) | |||
| 669 | 623 | ||
| 670 | out_backlight: | 624 | out_backlight: |
| 671 | backlight_device_unregister(pcc->backlight); | 625 | backlight_device_unregister(pcc->backlight); |
| 626 | out_input: | ||
| 627 | acpi_pcc_destroy_input(pcc); | ||
| 672 | out_sinf: | 628 | out_sinf: |
| 673 | kfree(pcc->sinf); | 629 | kfree(pcc->sinf); |
| 674 | out_input: | ||
| 675 | input_unregister_device(pcc->input_dev); | ||
| 676 | /* no need to input_free_device() since core input API refcount and | ||
| 677 | * free()s the device */ | ||
| 678 | out_hotkey: | 630 | out_hotkey: |
| 679 | kfree(pcc); | 631 | kfree(pcc); |
| 680 | 632 | ||
| @@ -709,9 +661,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) | |||
| 709 | 661 | ||
| 710 | backlight_device_unregister(pcc->backlight); | 662 | backlight_device_unregister(pcc->backlight); |
| 711 | 663 | ||
| 712 | input_unregister_device(pcc->input_dev); | 664 | acpi_pcc_destroy_input(pcc); |
| 713 | /* no need to input_free_device() since core input API refcount and | ||
| 714 | * free()s the device */ | ||
| 715 | 665 | ||
| 716 | kfree(pcc->sinf); | 666 | kfree(pcc->sinf); |
| 717 | kfree(pcc); | 667 | kfree(pcc); |
