diff options
-rw-r--r-- | drivers/platform/x86/eeepc-wmi.c | 170 |
1 files changed, 164 insertions, 6 deletions
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index a70d76a463a6..253070ab963c 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/backlight.h> | 36 | #include <linux/backlight.h> |
37 | #include <linux/leds.h> | 37 | #include <linux/leds.h> |
38 | #include <linux/rfkill.h> | 38 | #include <linux/rfkill.h> |
39 | #include <linux/debugfs.h> | ||
40 | #include <linux/seq_file.h> | ||
39 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
40 | #include <acpi/acpi_bus.h> | 42 | #include <acpi/acpi_bus.h> |
41 | #include <acpi/acpi_drivers.h> | 43 | #include <acpi/acpi_drivers.h> |
@@ -89,6 +91,19 @@ struct bios_args { | |||
89 | u32 ctrl_param; | 91 | u32 ctrl_param; |
90 | }; | 92 | }; |
91 | 93 | ||
94 | /* | ||
95 | * eeepc-wmi/ - debugfs root directory | ||
96 | * dev_id - current dev_id | ||
97 | * ctrl_param - current ctrl_param | ||
98 | * devs - call DEVS(dev_id, ctrl_param) and print result | ||
99 | * dsts - call DSTS(dev_id) and print result | ||
100 | */ | ||
101 | struct eeepc_wmi_debug { | ||
102 | struct dentry *root; | ||
103 | u32 dev_id; | ||
104 | u32 ctrl_param; | ||
105 | }; | ||
106 | |||
92 | struct eeepc_wmi { | 107 | struct eeepc_wmi { |
93 | struct input_dev *inputdev; | 108 | struct input_dev *inputdev; |
94 | struct backlight_device *backlight_device; | 109 | struct backlight_device *backlight_device; |
@@ -102,6 +117,8 @@ struct eeepc_wmi { | |||
102 | struct rfkill *wlan_rfkill; | 117 | struct rfkill *wlan_rfkill; |
103 | struct rfkill *bluetooth_rfkill; | 118 | struct rfkill *bluetooth_rfkill; |
104 | struct rfkill *wwan3g_rfkill; | 119 | struct rfkill *wwan3g_rfkill; |
120 | |||
121 | struct eeepc_wmi_debug debug; | ||
105 | }; | 122 | }; |
106 | 123 | ||
107 | /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ | 124 | /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ |
@@ -176,7 +193,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param) | |||
176 | 193 | ||
177 | } | 194 | } |
178 | 195 | ||
179 | static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param) | 196 | static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, |
197 | u32 *retval) | ||
180 | { | 198 | { |
181 | struct bios_args args = { | 199 | struct bios_args args = { |
182 | .dev_id = dev_id, | 200 | .dev_id = dev_id, |
@@ -185,8 +203,32 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param) | |||
185 | struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; | 203 | struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; |
186 | acpi_status status; | 204 | acpi_status status; |
187 | 205 | ||
188 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, | 206 | if (!retval) { |
189 | 1, EEEPC_WMI_METHODID_DEVS, &input, NULL); | 207 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, |
208 | EEEPC_WMI_METHODID_DEVS, | ||
209 | &input, NULL); | ||
210 | } else { | ||
211 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
212 | union acpi_object *obj; | ||
213 | u32 tmp; | ||
214 | |||
215 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, | ||
216 | EEEPC_WMI_METHODID_DEVS, | ||
217 | &input, &output); | ||
218 | |||
219 | if (ACPI_FAILURE(status)) | ||
220 | return status; | ||
221 | |||
222 | obj = (union acpi_object *)output.pointer; | ||
223 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
224 | tmp = (u32)obj->integer.value; | ||
225 | else | ||
226 | tmp = 0; | ||
227 | |||
228 | *retval = tmp; | ||
229 | |||
230 | kfree(obj); | ||
231 | } | ||
190 | 232 | ||
191 | return status; | 233 | return status; |
192 | } | 234 | } |
@@ -208,7 +250,7 @@ static void tpd_led_update(struct work_struct *work) | |||
208 | eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); | 250 | eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); |
209 | 251 | ||
210 | ctrl_param = eeepc->tpd_led_wk; | 252 | ctrl_param = eeepc->tpd_led_wk; |
211 | eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param); | 253 | eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL); |
212 | } | 254 | } |
213 | 255 | ||
214 | static void tpd_led_set(struct led_classdev *led_cdev, | 256 | static void tpd_led_set(struct led_classdev *led_cdev, |
@@ -295,7 +337,7 @@ static int eeepc_rfkill_set(void *data, bool blocked) | |||
295 | int dev_id = (unsigned long)data; | 337 | int dev_id = (unsigned long)data; |
296 | u32 ctrl_param = !blocked; | 338 | u32 ctrl_param = !blocked; |
297 | 339 | ||
298 | return eeepc_wmi_set_devstate(dev_id, ctrl_param); | 340 | return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); |
299 | } | 341 | } |
300 | 342 | ||
301 | static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) | 343 | static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) |
@@ -434,7 +476,8 @@ static int update_bl_status(struct backlight_device *bd) | |||
434 | 476 | ||
435 | ctrl_param = bd->props.brightness; | 477 | ctrl_param = bd->props.brightness; |
436 | 478 | ||
437 | status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param); | 479 | status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, |
480 | ctrl_param, NULL); | ||
438 | 481 | ||
439 | if (ACPI_FAILURE(status)) | 482 | if (ACPI_FAILURE(status)) |
440 | return -1; | 483 | return -1; |
@@ -614,6 +657,114 @@ static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) | |||
614 | } | 657 | } |
615 | 658 | ||
616 | /* | 659 | /* |
660 | * debugfs | ||
661 | */ | ||
662 | struct eeepc_wmi_debugfs_node { | ||
663 | struct eeepc_wmi *eeepc; | ||
664 | char *name; | ||
665 | int (*show)(struct seq_file *m, void *data); | ||
666 | }; | ||
667 | |||
668 | static int show_dsts(struct seq_file *m, void *data) | ||
669 | { | ||
670 | struct eeepc_wmi *eeepc = m->private; | ||
671 | acpi_status status; | ||
672 | u32 retval = -1; | ||
673 | |||
674 | status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); | ||
675 | |||
676 | if (ACPI_FAILURE(status)) | ||
677 | return -EIO; | ||
678 | |||
679 | seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static int show_devs(struct seq_file *m, void *data) | ||
685 | { | ||
686 | struct eeepc_wmi *eeepc = m->private; | ||
687 | acpi_status status; | ||
688 | u32 retval = -1; | ||
689 | |||
690 | status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, | ||
691 | eeepc->debug.ctrl_param, &retval); | ||
692 | if (ACPI_FAILURE(status)) | ||
693 | return -EIO; | ||
694 | |||
695 | seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, | ||
696 | eeepc->debug.ctrl_param, retval); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { | ||
702 | { NULL, "devs", show_devs }, | ||
703 | { NULL, "dsts", show_dsts }, | ||
704 | }; | ||
705 | |||
706 | static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) | ||
707 | { | ||
708 | struct eeepc_wmi_debugfs_node *node = inode->i_private; | ||
709 | |||
710 | return single_open(file, node->show, node->eeepc); | ||
711 | } | ||
712 | |||
713 | static const struct file_operations eeepc_wmi_debugfs_io_ops = { | ||
714 | .owner = THIS_MODULE, | ||
715 | .open = eeepc_wmi_debugfs_open, | ||
716 | .read = seq_read, | ||
717 | .llseek = seq_lseek, | ||
718 | .release = single_release, | ||
719 | }; | ||
720 | |||
721 | static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) | ||
722 | { | ||
723 | debugfs_remove_recursive(eeepc->debug.root); | ||
724 | } | ||
725 | |||
726 | static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) | ||
727 | { | ||
728 | struct dentry *dent; | ||
729 | int i; | ||
730 | |||
731 | eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); | ||
732 | if (!eeepc->debug.root) { | ||
733 | pr_err("failed to create debugfs directory"); | ||
734 | goto error_debugfs; | ||
735 | } | ||
736 | |||
737 | dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, | ||
738 | eeepc->debug.root, &eeepc->debug.dev_id); | ||
739 | if (!dent) | ||
740 | goto error_debugfs; | ||
741 | |||
742 | dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, | ||
743 | eeepc->debug.root, &eeepc->debug.ctrl_param); | ||
744 | if (!dent) | ||
745 | goto error_debugfs; | ||
746 | |||
747 | for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { | ||
748 | struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; | ||
749 | |||
750 | node->eeepc = eeepc; | ||
751 | dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, | ||
752 | eeepc->debug.root, node, | ||
753 | &eeepc_wmi_debugfs_io_ops); | ||
754 | if (!dent) { | ||
755 | pr_err("failed to create debug file: %s\n", node->name); | ||
756 | goto error_debugfs; | ||
757 | } | ||
758 | } | ||
759 | |||
760 | return 0; | ||
761 | |||
762 | error_debugfs: | ||
763 | eeepc_wmi_debugfs_exit(eeepc); | ||
764 | return -ENOMEM; | ||
765 | } | ||
766 | |||
767 | /* | ||
617 | * WMI Driver | 768 | * WMI Driver |
618 | */ | 769 | */ |
619 | static struct platform_device * __init eeepc_wmi_add(void) | 770 | static struct platform_device * __init eeepc_wmi_add(void) |
@@ -662,8 +813,14 @@ static struct platform_device * __init eeepc_wmi_add(void) | |||
662 | goto fail_wmi_handler; | 813 | goto fail_wmi_handler; |
663 | } | 814 | } |
664 | 815 | ||
816 | err = eeepc_wmi_debugfs_init(eeepc); | ||
817 | if (err) | ||
818 | goto fail_debugfs; | ||
819 | |||
665 | return eeepc->platform_device; | 820 | return eeepc->platform_device; |
666 | 821 | ||
822 | fail_debugfs: | ||
823 | wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); | ||
667 | fail_wmi_handler: | 824 | fail_wmi_handler: |
668 | eeepc_wmi_backlight_exit(eeepc); | 825 | eeepc_wmi_backlight_exit(eeepc); |
669 | fail_backlight: | 826 | fail_backlight: |
@@ -689,6 +846,7 @@ static int eeepc_wmi_remove(struct platform_device *device) | |||
689 | eeepc_wmi_input_exit(eeepc); | 846 | eeepc_wmi_input_exit(eeepc); |
690 | eeepc_wmi_led_exit(eeepc); | 847 | eeepc_wmi_led_exit(eeepc); |
691 | eeepc_wmi_rfkill_exit(eeepc); | 848 | eeepc_wmi_rfkill_exit(eeepc); |
849 | eeepc_wmi_debugfs_exit(eeepc); | ||
692 | eeepc_wmi_platform_exit(eeepc); | 850 | eeepc_wmi_platform_exit(eeepc); |
693 | 851 | ||
694 | kfree(eeepc); | 852 | kfree(eeepc); |