diff options
Diffstat (limited to 'drivers/acpi/hotkey.c')
-rw-r--r-- | drivers/acpi/hotkey.c | 281 |
1 files changed, 119 insertions, 162 deletions
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c index 32c9d88fd196..1ba2db671865 100644 --- a/drivers/acpi/hotkey.c +++ b/drivers/acpi/hotkey.c | |||
@@ -91,6 +91,14 @@ enum { | |||
91 | HK_EVENT_ENTERRING_S5, | 91 | HK_EVENT_ENTERRING_S5, |
92 | }; | 92 | }; |
93 | 93 | ||
94 | enum conf_entry_enum { | ||
95 | bus_handle = 0, | ||
96 | bus_method = 1, | ||
97 | action_handle = 2, | ||
98 | method = 3, | ||
99 | LAST_CONF_ENTRY | ||
100 | }; | ||
101 | |||
94 | /* procdir we use */ | 102 | /* procdir we use */ |
95 | static struct proc_dir_entry *hotkey_proc_dir; | 103 | static struct proc_dir_entry *hotkey_proc_dir; |
96 | static struct proc_dir_entry *hotkey_config; | 104 | static struct proc_dir_entry *hotkey_config; |
@@ -244,19 +252,15 @@ static int hotkey_info_open_fs(struct inode *inode, struct file *file) | |||
244 | 252 | ||
245 | static char *format_result(union acpi_object *object) | 253 | static char *format_result(union acpi_object *object) |
246 | { | 254 | { |
247 | char *buf = NULL; | 255 | char *buf; |
248 | |||
249 | buf = (char *)kmalloc(RESULT_STR_LEN, GFP_KERNEL); | ||
250 | if (buf) | ||
251 | memset(buf, 0, RESULT_STR_LEN); | ||
252 | else | ||
253 | goto do_fail; | ||
254 | 256 | ||
257 | buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL); | ||
258 | if (!buf) | ||
259 | return NULL; | ||
255 | /* Now, just support integer type */ | 260 | /* Now, just support integer type */ |
256 | if (object->type == ACPI_TYPE_INTEGER) | 261 | if (object->type == ACPI_TYPE_INTEGER) |
257 | sprintf(buf, "%d\n", (u32) object->integer.value); | 262 | sprintf(buf, "%d\n", (u32) object->integer.value); |
258 | do_fail: | 263 | return buf; |
259 | return (buf); | ||
260 | } | 264 | } |
261 | 265 | ||
262 | static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) | 266 | static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) |
@@ -486,98 +490,102 @@ static void free_hotkey_device(union acpi_hotkey *key) | |||
486 | 490 | ||
487 | static void free_hotkey_buffer(union acpi_hotkey *key) | 491 | static void free_hotkey_buffer(union acpi_hotkey *key) |
488 | { | 492 | { |
493 | /* key would never be null, action method could be */ | ||
489 | kfree(key->event_hotkey.action_method); | 494 | kfree(key->event_hotkey.action_method); |
490 | } | 495 | } |
491 | 496 | ||
492 | static void free_poll_hotkey_buffer(union acpi_hotkey *key) | 497 | static void free_poll_hotkey_buffer(union acpi_hotkey *key) |
493 | { | 498 | { |
499 | /* key would never be null, others could be*/ | ||
494 | kfree(key->poll_hotkey.action_method); | 500 | kfree(key->poll_hotkey.action_method); |
495 | kfree(key->poll_hotkey.poll_method); | 501 | kfree(key->poll_hotkey.poll_method); |
496 | kfree(key->poll_hotkey.poll_result); | 502 | kfree(key->poll_hotkey.poll_result); |
497 | } | 503 | } |
498 | static int | 504 | static int |
499 | init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str, | 505 | init_hotkey_device(union acpi_hotkey *key, char **config_entry, |
500 | char *method, int std_num, int external_num) | 506 | int std_num, int external_num) |
501 | { | 507 | { |
502 | acpi_handle tmp_handle; | 508 | acpi_handle tmp_handle; |
503 | acpi_status status = AE_OK; | 509 | acpi_status status = AE_OK; |
504 | 510 | ||
505 | |||
506 | if (std_num < 0 || IS_POLL(std_num) || !key) | 511 | if (std_num < 0 || IS_POLL(std_num) || !key) |
507 | goto do_fail; | 512 | goto do_fail; |
508 | 513 | ||
509 | if (!bus_str || !action_str || !method) | 514 | if (!config_entry[bus_handle] || !config_entry[action_handle] |
515 | || !config_entry[method]) | ||
510 | goto do_fail; | 516 | goto do_fail; |
511 | 517 | ||
512 | key->link.hotkey_type = ACPI_HOTKEY_EVENT; | 518 | key->link.hotkey_type = ACPI_HOTKEY_EVENT; |
513 | key->link.hotkey_standard_num = std_num; | 519 | key->link.hotkey_standard_num = std_num; |
514 | key->event_hotkey.flag = 0; | 520 | key->event_hotkey.flag = 0; |
515 | key->event_hotkey.action_method = method; | 521 | key->event_hotkey.action_method = config_entry[method]; |
516 | 522 | ||
517 | status = | 523 | status = acpi_get_handle(NULL, config_entry[bus_handle], |
518 | acpi_get_handle(NULL, bus_str, &(key->event_hotkey.bus_handle)); | 524 | &(key->event_hotkey.bus_handle)); |
519 | if (ACPI_FAILURE(status)) | 525 | if (ACPI_FAILURE(status)) |
520 | goto do_fail; | 526 | goto do_fail_zero; |
521 | key->event_hotkey.external_hotkey_num = external_num; | 527 | key->event_hotkey.external_hotkey_num = external_num; |
522 | status = | 528 | status = acpi_get_handle(NULL, config_entry[action_handle], |
523 | acpi_get_handle(NULL, action_str, | ||
524 | &(key->event_hotkey.action_handle)); | 529 | &(key->event_hotkey.action_handle)); |
525 | if (ACPI_FAILURE(status)) | 530 | if (ACPI_FAILURE(status)) |
526 | goto do_fail; | 531 | goto do_fail_zero; |
527 | status = acpi_get_handle(key->event_hotkey.action_handle, | 532 | status = acpi_get_handle(key->event_hotkey.action_handle, |
528 | method, &tmp_handle); | 533 | config_entry[method], &tmp_handle); |
529 | if (ACPI_FAILURE(status)) | 534 | if (ACPI_FAILURE(status)) |
530 | goto do_fail; | 535 | goto do_fail_zero; |
531 | return AE_OK; | 536 | return AE_OK; |
532 | do_fail: | 537 | do_fail_zero: |
538 | key->event_hotkey.action_method = NULL; | ||
539 | do_fail: | ||
533 | return -ENODEV; | 540 | return -ENODEV; |
534 | } | 541 | } |
535 | 542 | ||
536 | static int | 543 | static int |
537 | init_poll_hotkey_device(union acpi_hotkey *key, | 544 | init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry, |
538 | char *poll_str, | 545 | int std_num) |
539 | char *poll_method, | ||
540 | char *action_str, char *action_method, int std_num) | ||
541 | { | 546 | { |
542 | acpi_status status = AE_OK; | 547 | acpi_status status = AE_OK; |
543 | acpi_handle tmp_handle; | 548 | acpi_handle tmp_handle; |
544 | 549 | ||
545 | |||
546 | if (std_num < 0 || IS_EVENT(std_num) || !key) | 550 | if (std_num < 0 || IS_EVENT(std_num) || !key) |
547 | goto do_fail; | 551 | goto do_fail; |
548 | 552 | if (!config_entry[bus_handle] ||!config_entry[bus_method] || | |
549 | if (!poll_str || !poll_method || !action_str || !action_method) | 553 | !config_entry[action_handle] || !config_entry[method]) |
550 | goto do_fail; | 554 | goto do_fail; |
551 | 555 | ||
552 | key->link.hotkey_type = ACPI_HOTKEY_POLLING; | 556 | key->link.hotkey_type = ACPI_HOTKEY_POLLING; |
553 | key->link.hotkey_standard_num = std_num; | 557 | key->link.hotkey_standard_num = std_num; |
554 | key->poll_hotkey.flag = 0; | 558 | key->poll_hotkey.flag = 0; |
555 | key->poll_hotkey.poll_method = poll_method; | 559 | key->poll_hotkey.poll_method = config_entry[bus_method]; |
556 | key->poll_hotkey.action_method = action_method; | 560 | key->poll_hotkey.action_method = config_entry[method]; |
557 | 561 | ||
558 | status = | 562 | status = acpi_get_handle(NULL, config_entry[bus_handle], |
559 | acpi_get_handle(NULL, poll_str, &(key->poll_hotkey.poll_handle)); | 563 | &(key->poll_hotkey.poll_handle)); |
560 | if (ACPI_FAILURE(status)) | 564 | if (ACPI_FAILURE(status)) |
561 | goto do_fail; | 565 | goto do_fail_zero; |
562 | status = acpi_get_handle(key->poll_hotkey.poll_handle, | 566 | status = acpi_get_handle(key->poll_hotkey.poll_handle, |
563 | poll_method, &tmp_handle); | 567 | config_entry[bus_method], &tmp_handle); |
564 | if (ACPI_FAILURE(status)) | 568 | if (ACPI_FAILURE(status)) |
565 | goto do_fail; | 569 | goto do_fail_zero; |
566 | status = | 570 | status = |
567 | acpi_get_handle(NULL, action_str, | 571 | acpi_get_handle(NULL, config_entry[action_handle], |
568 | &(key->poll_hotkey.action_handle)); | 572 | &(key->poll_hotkey.action_handle)); |
569 | if (ACPI_FAILURE(status)) | 573 | if (ACPI_FAILURE(status)) |
570 | goto do_fail; | 574 | goto do_fail_zero; |
571 | status = acpi_get_handle(key->poll_hotkey.action_handle, | 575 | status = acpi_get_handle(key->poll_hotkey.action_handle, |
572 | action_method, &tmp_handle); | 576 | config_entry[method], &tmp_handle); |
573 | if (ACPI_FAILURE(status)) | 577 | if (ACPI_FAILURE(status)) |
574 | goto do_fail; | 578 | goto do_fail_zero; |
575 | key->poll_hotkey.poll_result = | 579 | key->poll_hotkey.poll_result = |
576 | (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); | 580 | (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); |
577 | if (!key->poll_hotkey.poll_result) | 581 | if (!key->poll_hotkey.poll_result) |
578 | goto do_fail; | 582 | goto do_fail_zero; |
579 | return AE_OK; | 583 | return AE_OK; |
580 | do_fail: | 584 | |
585 | do_fail_zero: | ||
586 | key->poll_hotkey.poll_method = NULL; | ||
587 | key->poll_hotkey.action_method = NULL; | ||
588 | do_fail: | ||
581 | return -ENODEV; | 589 | return -ENODEV; |
582 | } | 590 | } |
583 | 591 | ||
@@ -652,17 +660,18 @@ static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset) | |||
652 | } | 660 | } |
653 | 661 | ||
654 | static int | 662 | static int |
655 | get_parms(char *config_record, | 663 | get_parms(char *config_record, int *cmd, char **config_entry, |
656 | int *cmd, | 664 | int *internal_event_num, int *external_event_num) |
657 | char **bus_handle, | ||
658 | char **bus_method, | ||
659 | char **action_handle, | ||
660 | char **method, int *internal_event_num, int *external_event_num) | ||
661 | { | 665 | { |
666 | /* the format of *config_record = | ||
667 | * "1:\d+:*" : "cmd:internal_event_num" | ||
668 | * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" : | ||
669 | * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num" | ||
670 | */ | ||
662 | char *tmp, *tmp1, count; | 671 | char *tmp, *tmp1, count; |
672 | int i; | ||
663 | 673 | ||
664 | sscanf(config_record, "%d", cmd); | 674 | sscanf(config_record, "%d", cmd); |
665 | |||
666 | if (*cmd == 1) { | 675 | if (*cmd == 1) { |
667 | if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != | 676 | if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != |
668 | 2) | 677 | 2) |
@@ -674,59 +683,27 @@ get_parms(char *config_record, | |||
674 | if (!tmp) | 683 | if (!tmp) |
675 | goto do_fail; | 684 | goto do_fail; |
676 | tmp++; | 685 | tmp++; |
677 | tmp1 = strchr(tmp, ':'); | 686 | for (i = 0; i < LAST_CONF_ENTRY; i++) { |
678 | if (!tmp1) | 687 | tmp1 = strchr(tmp, ':'); |
679 | goto do_fail; | 688 | if (!tmp1) { |
680 | 689 | goto do_fail; | |
681 | count = tmp1 - tmp; | 690 | } |
682 | *bus_handle = (char *)kmalloc(count + 1, GFP_KERNEL); | 691 | count = tmp1 - tmp; |
683 | if (!*bus_handle) | 692 | config_entry[i] = kzalloc(count + 1, GFP_KERNEL); |
684 | goto do_fail; | 693 | if (!config_entry[i]) |
685 | strncpy(*bus_handle, tmp, count); | 694 | goto handle_failure; |
686 | *(*bus_handle + count) = 0; | 695 | strncpy(config_entry[i], tmp, count); |
687 | 696 | tmp = tmp1 + 1; | |
688 | tmp = tmp1; | 697 | } |
689 | tmp++; | 698 | if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0) |
690 | tmp1 = strchr(tmp, ':'); | 699 | goto handle_failure; |
691 | if (!tmp1) | 700 | if (!IS_OTHERS(*internal_event_num)) { |
692 | goto do_fail; | 701 | return 6; |
693 | count = tmp1 - tmp; | 702 | } |
694 | *bus_method = (char *)kmalloc(count + 1, GFP_KERNEL); | 703 | handle_failure: |
695 | if (!*bus_method) | 704 | while (i-- > 0) |
696 | goto do_fail; | 705 | kfree(config_entry[i]); |
697 | strncpy(*bus_method, tmp, count); | 706 | do_fail: |
698 | *(*bus_method + count) = 0; | ||
699 | |||
700 | tmp = tmp1; | ||
701 | tmp++; | ||
702 | tmp1 = strchr(tmp, ':'); | ||
703 | if (!tmp1) | ||
704 | goto do_fail; | ||
705 | count = tmp1 - tmp; | ||
706 | *action_handle = (char *)kmalloc(count + 1, GFP_KERNEL); | ||
707 | if (!*action_handle) | ||
708 | goto do_fail; | ||
709 | strncpy(*action_handle, tmp, count); | ||
710 | *(*action_handle + count) = 0; | ||
711 | |||
712 | tmp = tmp1; | ||
713 | tmp++; | ||
714 | tmp1 = strchr(tmp, ':'); | ||
715 | if (!tmp1) | ||
716 | goto do_fail; | ||
717 | count = tmp1 - tmp; | ||
718 | *method = (char *)kmalloc(count + 1, GFP_KERNEL); | ||
719 | if (!*method) | ||
720 | goto do_fail; | ||
721 | strncpy(*method, tmp, count); | ||
722 | *(*method + count) = 0; | ||
723 | |||
724 | if (sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num) <= | ||
725 | 0) | ||
726 | goto do_fail; | ||
727 | |||
728 | return 6; | ||
729 | do_fail: | ||
730 | return -1; | 707 | return -1; |
731 | } | 708 | } |
732 | 709 | ||
@@ -736,50 +713,34 @@ static ssize_t hotkey_write_config(struct file *file, | |||
736 | size_t count, loff_t * data) | 713 | size_t count, loff_t * data) |
737 | { | 714 | { |
738 | char *config_record = NULL; | 715 | char *config_record = NULL; |
739 | char *bus_handle = NULL; | 716 | char *config_entry[LAST_CONF_ENTRY]; |
740 | char *bus_method = NULL; | ||
741 | char *action_handle = NULL; | ||
742 | char *method = NULL; | ||
743 | int cmd, internal_event_num, external_event_num; | 717 | int cmd, internal_event_num, external_event_num; |
744 | int ret = 0; | 718 | int ret = 0; |
745 | union acpi_hotkey *key = NULL; | 719 | union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL); |
746 | 720 | ||
721 | if (!key) | ||
722 | return -ENOMEM; | ||
747 | 723 | ||
748 | config_record = (char *)kmalloc(count + 1, GFP_KERNEL); | 724 | config_record = kzalloc(count + 1, GFP_KERNEL); |
749 | if (!config_record) | 725 | if (!config_record) { |
726 | kfree(key); | ||
750 | return -ENOMEM; | 727 | return -ENOMEM; |
728 | } | ||
751 | 729 | ||
752 | if (copy_from_user(config_record, buffer, count)) { | 730 | if (copy_from_user(config_record, buffer, count)) { |
753 | kfree(config_record); | 731 | kfree(config_record); |
732 | kfree(key); | ||
754 | printk(KERN_ERR PREFIX "Invalid data\n"); | 733 | printk(KERN_ERR PREFIX "Invalid data\n"); |
755 | return -EINVAL; | 734 | return -EINVAL; |
756 | } | 735 | } |
757 | config_record[count] = 0; | 736 | ret = get_parms(config_record, &cmd, config_entry, |
758 | 737 | &internal_event_num, &external_event_num); | |
759 | ret = get_parms(config_record, | ||
760 | &cmd, | ||
761 | &bus_handle, | ||
762 | &bus_method, | ||
763 | &action_handle, | ||
764 | &method, &internal_event_num, &external_event_num); | ||
765 | |||
766 | kfree(config_record); | 738 | kfree(config_record); |
767 | if (IS_OTHERS(internal_event_num)) | ||
768 | goto do_fail; | ||
769 | if (ret != 6) { | 739 | if (ret != 6) { |
770 | do_fail: | ||
771 | kfree(bus_handle); | ||
772 | kfree(bus_method); | ||
773 | kfree(action_handle); | ||
774 | kfree(method); | ||
775 | printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret); | 740 | printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret); |
776 | return -EINVAL; | 741 | return -EINVAL; |
777 | } | 742 | } |
778 | 743 | ||
779 | key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL); | ||
780 | if (!key) | ||
781 | goto do_fail; | ||
782 | memset(key, 0, sizeof(union acpi_hotkey)); | ||
783 | if (cmd == 1) { | 744 | if (cmd == 1) { |
784 | union acpi_hotkey *tmp = NULL; | 745 | union acpi_hotkey *tmp = NULL; |
785 | tmp = get_hotkey_by_event(&global_hotkey_list, | 746 | tmp = get_hotkey_by_event(&global_hotkey_list, |
@@ -791,34 +752,19 @@ static ssize_t hotkey_write_config(struct file *file, | |||
791 | goto cont_cmd; | 752 | goto cont_cmd; |
792 | } | 753 | } |
793 | if (IS_EVENT(internal_event_num)) { | 754 | if (IS_EVENT(internal_event_num)) { |
794 | kfree(bus_method); | 755 | if (init_hotkey_device(key, config_entry, |
795 | ret = init_hotkey_device(key, bus_handle, action_handle, method, | 756 | internal_event_num, external_event_num)) |
796 | internal_event_num, | 757 | goto init_hotkey_fail; |
797 | external_event_num); | 758 | } else { |
798 | } else | 759 | if (init_poll_hotkey_device(key, config_entry, |
799 | ret = init_poll_hotkey_device(key, bus_handle, bus_method, | 760 | internal_event_num)) |
800 | action_handle, method, | 761 | goto init_poll_hotkey_fail; |
801 | internal_event_num); | ||
802 | if (ret) { | ||
803 | kfree(bus_handle); | ||
804 | kfree(action_handle); | ||
805 | if (IS_EVENT(internal_event_num)) | ||
806 | free_hotkey_buffer(key); | ||
807 | else | ||
808 | free_poll_hotkey_buffer(key); | ||
809 | kfree(key); | ||
810 | printk(KERN_ERR PREFIX "Invalid hotkey\n"); | ||
811 | return -EINVAL; | ||
812 | } | 762 | } |
813 | 763 | cont_cmd: | |
814 | cont_cmd: | ||
815 | kfree(bus_handle); | ||
816 | kfree(action_handle); | ||
817 | |||
818 | switch (cmd) { | 764 | switch (cmd) { |
819 | case 0: | 765 | case 0: |
820 | if (get_hotkey_by_event | 766 | if (get_hotkey_by_event(&global_hotkey_list, |
821 | (&global_hotkey_list, key->link.hotkey_standard_num)) | 767 | key->link.hotkey_standard_num)) |
822 | goto fail_out; | 768 | goto fail_out; |
823 | else | 769 | else |
824 | hotkey_add(key); | 770 | hotkey_add(key); |
@@ -827,6 +773,7 @@ static ssize_t hotkey_write_config(struct file *file, | |||
827 | hotkey_remove(key); | 773 | hotkey_remove(key); |
828 | break; | 774 | break; |
829 | case 2: | 775 | case 2: |
776 | /* key is kfree()ed if matched*/ | ||
830 | if (hotkey_update(key)) | 777 | if (hotkey_update(key)) |
831 | goto fail_out; | 778 | goto fail_out; |
832 | break; | 779 | break; |
@@ -835,11 +782,22 @@ static ssize_t hotkey_write_config(struct file *file, | |||
835 | break; | 782 | break; |
836 | } | 783 | } |
837 | return count; | 784 | return count; |
838 | fail_out: | 785 | |
839 | if (IS_EVENT(internal_event_num)) | 786 | init_poll_hotkey_fail: /* failed init_poll_hotkey_device */ |
840 | free_hotkey_buffer(key); | 787 | kfree(config_entry[bus_method]); |
841 | else | 788 | config_entry[bus_method] = NULL; |
842 | free_poll_hotkey_buffer(key); | 789 | init_hotkey_fail: /* failed init_hotkey_device */ |
790 | kfree(config_entry[method]); | ||
791 | fail_out: | ||
792 | kfree(config_entry[bus_handle]); | ||
793 | kfree(config_entry[action_handle]); | ||
794 | /* No double free since elements =NULL for error cases */ | ||
795 | if (IS_EVENT(internal_event_num)) { | ||
796 | if (config_entry[bus_method]) | ||
797 | kfree(config_entry[bus_method]); | ||
798 | free_hotkey_buffer(key); /* frees [method] */ | ||
799 | } else | ||
800 | free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */ | ||
843 | kfree(key); | 801 | kfree(key); |
844 | printk(KERN_ERR PREFIX "invalid key\n"); | 802 | printk(KERN_ERR PREFIX "invalid key\n"); |
845 | return -EINVAL; | 803 | return -EINVAL; |
@@ -923,10 +881,9 @@ static ssize_t hotkey_execute_aml_method(struct file *file, | |||
923 | union acpi_hotkey *key; | 881 | union acpi_hotkey *key; |
924 | 882 | ||
925 | 883 | ||
926 | arg = (char *)kmalloc(count + 1, GFP_KERNEL); | 884 | arg = kzalloc(count + 1, GFP_KERNEL); |
927 | if (!arg) | 885 | if (!arg) |
928 | return -ENOMEM; | 886 | return -ENOMEM; |
929 | arg[count] = 0; | ||
930 | 887 | ||
931 | if (copy_from_user(arg, buffer, count)) { | 888 | if (copy_from_user(arg, buffer, count)) { |
932 | kfree(arg); | 889 | kfree(arg); |