aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@srcf.ucam.org>2009-01-09 15:17:11 -0500
committerLen Brown <len.brown@intel.com>2009-04-03 22:54:50 -0400
commit0b3f6109f0c9ff926b5ffc80dc1cebb24f192b35 (patch)
tree01a5a5076735492e55d590525d1fd774b23165a6 /drivers/platform
parent8e0ee43bc2c3e19db56a4adaa9a9b04ce885cd84 (diff)
dell-wmi: new driver for hotkey control
Add a WMI driver for Dell laptops. Currently it does nothing but send a generic input event when a button with a picture of a battery on it is pressed, but maybe other uses will appear over time. Signed-off-by: Matthew Garrett <mjg@redhat.com> Cc: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig10
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/dell-wmi.c210
3 files changed, 221 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 3608081bc3e0..a27bff3007c8 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -67,6 +67,16 @@ config DELL_LAPTOP
67 This driver adds support for rfkill and backlight control to Dell 67 This driver adds support for rfkill and backlight control to Dell
68 laptops. 68 laptops.
69 69
70config DELL_WMI
71 tristate "Dell WMI extras"
72 depends on ACPI_WMI
73 depends on INPUT
74 ---help---
75 Say Y here if you want to support WMI-based hotkeys on Dell laptops.
76
77 To compile this driver as a module, choose M here: the module will
78 be called dell-wmi.
79
70config FUJITSU_LAPTOP 80config FUJITSU_LAPTOP
71 tristate "Fujitsu Laptop Extras" 81 tristate "Fujitsu Laptop Extras"
72 depends on ACPI 82 depends on ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index e29065120be9..e40c7bd1b87e 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
7obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 7obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
8obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o 8obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
9obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 9obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
10obj-$(CONFIG_DELL_WMI) += dell-wmi.o
10obj-$(CONFIG_ACER_WMI) += acer-wmi.o 11obj-$(CONFIG_ACER_WMI) += acer-wmi.o
11obj-$(CONFIG_HP_WMI) += hp-wmi.o 12obj-$(CONFIG_HP_WMI) += hp-wmi.o
12obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o 13obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
new file mode 100644
index 000000000000..2fab94162147
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi.c
@@ -0,0 +1,210 @@
1/*
2 * Dell WMI hotkeys
3 *
4 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5 *
6 * Portions based on wistron_btns.c:
7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
8 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
9 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/types.h>
30#include <linux/input.h>
31#include <acpi/acpi_drivers.h>
32#include <linux/acpi.h>
33#include <linux/string.h>
34
35MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
36MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
37MODULE_LICENSE("GPL");
38
39#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
40
41MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
42
43struct key_entry {
44 char type; /* See KE_* below */
45 u16 code;
46 u16 keycode;
47};
48
49enum { KE_KEY, KE_SW, KE_END };
50
51static struct key_entry dell_wmi_keymap[] = {
52 {KE_KEY, 0xe045, KEY_PROG1},
53 {KE_END, 0}
54};
55
56static struct input_dev *dell_wmi_input_dev;
57
58static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
59{
60 struct key_entry *key;
61
62 for (key = dell_wmi_keymap; key->type != KE_END; key++)
63 if (code == key->code)
64 return key;
65
66 return NULL;
67}
68
69static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode)
70{
71 struct key_entry *key;
72
73 for (key = dell_wmi_keymap; key->type != KE_END; key++)
74 if (key->type == KE_KEY && keycode == key->keycode)
75 return key;
76
77 return NULL;
78}
79
80static int dell_wmi_getkeycode(struct input_dev *dev, int scancode,
81 int *keycode)
82{
83 struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
84
85 if (key && key->type == KE_KEY) {
86 *keycode = key->keycode;
87 return 0;
88 }
89
90 return -EINVAL;
91}
92
93static int dell_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
94{
95 struct key_entry *key;
96 int old_keycode;
97
98 if (keycode < 0 || keycode > KEY_MAX)
99 return -EINVAL;
100
101 key = dell_wmi_get_entry_by_scancode(scancode);
102 if (key && key->type == KE_KEY) {
103 old_keycode = key->keycode;
104 key->keycode = keycode;
105 set_bit(keycode, dev->keybit);
106 if (!dell_wmi_get_entry_by_keycode(old_keycode))
107 clear_bit(old_keycode, dev->keybit);
108 return 0;
109 }
110 return -EINVAL;
111}
112
113static void dell_wmi_notify(u32 value, void *context)
114{
115 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
116 static struct key_entry *key;
117 union acpi_object *obj;
118
119 wmi_get_event_data(value, &response);
120
121 obj = (union acpi_object *)response.pointer;
122
123 if (obj && obj->type == ACPI_TYPE_BUFFER) {
124 int *buffer = (int *)obj->buffer.pointer;
125 key = dell_wmi_get_entry_by_scancode(buffer[1]);
126 if (key) {
127 input_report_key(dell_wmi_input_dev, key->keycode, 1);
128 input_sync(dell_wmi_input_dev);
129 input_report_key(dell_wmi_input_dev, key->keycode, 0);
130 input_sync(dell_wmi_input_dev);
131 } else
132 printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
133 buffer[1]);
134 }
135}
136
137static int __init dell_wmi_input_setup(void)
138{
139 struct key_entry *key;
140 int err;
141
142 dell_wmi_input_dev = input_allocate_device();
143
144 if (!dell_wmi_input_dev)
145 return -ENOMEM;
146
147 dell_wmi_input_dev->name = "Dell WMI hotkeys";
148 dell_wmi_input_dev->phys = "wmi/input0";
149 dell_wmi_input_dev->id.bustype = BUS_HOST;
150 dell_wmi_input_dev->getkeycode = dell_wmi_getkeycode;
151 dell_wmi_input_dev->setkeycode = dell_wmi_setkeycode;
152
153 for (key = dell_wmi_keymap; key->type != KE_END; key++) {
154 switch (key->type) {
155 case KE_KEY:
156 set_bit(EV_KEY, dell_wmi_input_dev->evbit);
157 set_bit(key->keycode, dell_wmi_input_dev->keybit);
158 break;
159 case KE_SW:
160 set_bit(EV_SW, dell_wmi_input_dev->evbit);
161 set_bit(key->keycode, dell_wmi_input_dev->swbit);
162 break;
163 }
164 }
165
166 err = input_register_device(dell_wmi_input_dev);
167
168 if (err) {
169 input_free_device(dell_wmi_input_dev);
170 return err;
171 }
172
173 return 0;
174}
175
176static int __init dell_wmi_init(void)
177{
178 int err;
179
180 if (wmi_has_guid(DELL_EVENT_GUID)) {
181 err = dell_wmi_input_setup();
182
183 if (err)
184 return err;
185
186 err = wmi_install_notify_handler(DELL_EVENT_GUID,
187 dell_wmi_notify, NULL);
188 if (err) {
189 input_unregister_device(dell_wmi_input_dev);
190 printk(KERN_ERR "dell-wmi: Unable to register"
191 " notify handler - %d\n", err);
192 return err;
193 }
194
195 } else
196 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
197
198 return 0;
199}
200
201static void __exit dell_wmi_exit(void)
202{
203 if (wmi_has_guid(DELL_EVENT_GUID)) {
204 wmi_remove_notify_handler(DELL_EVENT_GUID);
205 input_unregister_device(dell_wmi_input_dev);
206 }
207}
208
209module_init(dell_wmi_init);
210module_exit(dell_wmi_exit);