eeepc-wmi: rework eeepc_wmi_init and eeepc_wmi_exit
[pandora-kernel.git] / drivers / platform / x86 / eeepc-wmi.c
1 /*
2  * Eee PC WMI hotkey driver
3  *
4  * Copyright(C) 2010 Intel Corporation.
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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
27
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/init.h>
31 #include <linux/types.h>
32 #include <linux/slab.h>
33 #include <linux/input.h>
34 #include <linux/input/sparse-keymap.h>
35 #include <linux/fb.h>
36 #include <linux/backlight.h>
37 #include <linux/platform_device.h>
38 #include <acpi/acpi_bus.h>
39 #include <acpi/acpi_drivers.h>
40
41 #define EEEPC_WMI_FILE  "eeepc-wmi"
42
43 MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
44 MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
45 MODULE_LICENSE("GPL");
46
47 #define EEEPC_WMI_EVENT_GUID    "ABBC0F72-8EA1-11D1-00A0-C90629100000"
48 #define EEEPC_WMI_MGMT_GUID     "97845ED0-4E6D-11DE-8A39-0800200C9A66"
49
50 MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
51 MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
52
53 #define NOTIFY_BRNUP_MIN        0x11
54 #define NOTIFY_BRNUP_MAX        0x1f
55 #define NOTIFY_BRNDOWN_MIN      0x20
56 #define NOTIFY_BRNDOWN_MAX      0x2e
57
58 #define EEEPC_WMI_METHODID_DEVS 0x53564544
59 #define EEEPC_WMI_METHODID_DSTS 0x53544344
60 #define EEEPC_WMI_METHODID_CFVS 0x53564643
61
62 #define EEEPC_WMI_DEVID_BACKLIGHT       0x00050012
63
64 static const struct key_entry eeepc_wmi_keymap[] = {
65         /* Sleep already handled via generic ACPI code */
66         { KE_KEY, 0x5d, { KEY_WLAN } },
67         { KE_KEY, 0x32, { KEY_MUTE } },
68         { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
69         { KE_KEY, 0x30, { KEY_VOLUMEUP } },
70         { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
71         { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
72         { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
73         { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */
74         { KE_KEY, 0xe1, { KEY_F14 } },
75         { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } },
76         { KE_KEY, 0xe0, { KEY_PROG1 } },
77         { KE_KEY, 0x5c, { KEY_F15 } },
78         { KE_END, 0},
79 };
80
81 struct bios_args {
82         u32     dev_id;
83         u32     ctrl_param;
84 };
85
86 struct eeepc_wmi {
87         struct input_dev *inputdev;
88         struct backlight_device *backlight_device;
89         struct platform_device *platform_device;
90 };
91
92 /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
93 static struct platform_device *platform_device;
94
95 static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
96 {
97         int err;
98
99         eeepc->inputdev = input_allocate_device();
100         if (!eeepc->inputdev)
101                 return -ENOMEM;
102
103         eeepc->inputdev->name = "Eee PC WMI hotkeys";
104         eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
105         eeepc->inputdev->id.bustype = BUS_HOST;
106         eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
107
108         err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
109         if (err)
110                 goto err_free_dev;
111
112         err = input_register_device(eeepc->inputdev);
113         if (err)
114                 goto err_free_keymap;
115
116         return 0;
117
118 err_free_keymap:
119         sparse_keymap_free(eeepc->inputdev);
120 err_free_dev:
121         input_free_device(eeepc->inputdev);
122         return err;
123 }
124
125 static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
126 {
127         if (eeepc->inputdev) {
128                 sparse_keymap_free(eeepc->inputdev);
129                 input_unregister_device(eeepc->inputdev);
130         }
131
132         eeepc->inputdev = NULL;
133 }
134
135 static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param)
136 {
137         struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
138         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
139         union acpi_object *obj;
140         acpi_status status;
141         u32 tmp;
142
143         status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
144                         1, EEEPC_WMI_METHODID_DSTS, &input, &output);
145
146         if (ACPI_FAILURE(status))
147                 return status;
148
149         obj = (union acpi_object *)output.pointer;
150         if (obj && obj->type == ACPI_TYPE_INTEGER)
151                 tmp = (u32)obj->integer.value;
152         else
153                 tmp = 0;
154
155         if (ctrl_param)
156                 *ctrl_param = tmp;
157
158         kfree(obj);
159
160         return status;
161
162 }
163
164 static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param)
165 {
166         struct bios_args args = {
167                 .dev_id = dev_id,
168                 .ctrl_param = ctrl_param,
169         };
170         struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
171         acpi_status status;
172
173         status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
174                         1, EEEPC_WMI_METHODID_DEVS, &input, NULL);
175
176         return status;
177 }
178
179 static int read_brightness(struct backlight_device *bd)
180 {
181         static u32 ctrl_param;
182         acpi_status status;
183
184         status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &ctrl_param);
185
186         if (ACPI_FAILURE(status))
187                 return -1;
188         else
189                 return ctrl_param & 0xFF;
190 }
191
192 static int update_bl_status(struct backlight_device *bd)
193 {
194
195         static u32 ctrl_param;
196         acpi_status status;
197
198         ctrl_param = bd->props.brightness;
199
200         status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param);
201
202         if (ACPI_FAILURE(status))
203                 return -1;
204         else
205                 return 0;
206 }
207
208 static const struct backlight_ops eeepc_wmi_bl_ops = {
209         .get_brightness = read_brightness,
210         .update_status = update_bl_status,
211 };
212
213 static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code)
214 {
215         struct backlight_device *bd = eeepc->backlight_device;
216         int old = bd->props.brightness;
217         int new = old;
218
219         if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
220                 new = code - NOTIFY_BRNUP_MIN + 1;
221         else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
222                 new = code - NOTIFY_BRNDOWN_MIN;
223
224         bd->props.brightness = new;
225         backlight_update_status(bd);
226         backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
227
228         return old;
229 }
230
231 static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
232 {
233         struct backlight_device *bd;
234         struct backlight_properties props;
235
236         memset(&props, 0, sizeof(struct backlight_properties));
237         props.max_brightness = 15;
238         bd = backlight_device_register(EEEPC_WMI_FILE,
239                                        &eeepc->platform_device->dev, eeepc,
240                                        &eeepc_wmi_bl_ops, &props);
241         if (IS_ERR(bd)) {
242                 pr_err("Could not register backlight device\n");
243                 return PTR_ERR(bd);
244         }
245
246         eeepc->backlight_device = bd;
247
248         bd->props.brightness = read_brightness(bd);
249         bd->props.power = FB_BLANK_UNBLANK;
250         backlight_update_status(bd);
251
252         return 0;
253 }
254
255 static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc)
256 {
257         if (eeepc->backlight_device)
258                 backlight_device_unregister(eeepc->backlight_device);
259
260         eeepc->backlight_device = NULL;
261 }
262
263 static void eeepc_wmi_notify(u32 value, void *context)
264 {
265         struct eeepc_wmi *eeepc = context;
266         struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
267         union acpi_object *obj;
268         acpi_status status;
269         int code;
270         int orig_code;
271
272         status = wmi_get_event_data(value, &response);
273         if (status != AE_OK) {
274                 pr_err("bad event status 0x%x\n", status);
275                 return;
276         }
277
278         obj = (union acpi_object *)response.pointer;
279
280         if (obj && obj->type == ACPI_TYPE_INTEGER) {
281                 code = obj->integer.value;
282                 orig_code = code;
283
284                 if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
285                         code = NOTIFY_BRNUP_MIN;
286                 else if (code >= NOTIFY_BRNDOWN_MIN &&
287                          code <= NOTIFY_BRNDOWN_MAX)
288                         code = NOTIFY_BRNDOWN_MIN;
289
290                 if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
291                         if (!acpi_video_backlight_support())
292                                 eeepc_wmi_backlight_notify(eeepc, orig_code);
293                 }
294
295                 if (!sparse_keymap_report_event(eeepc->inputdev,
296                                                 code, 1, true))
297                         pr_info("Unknown key %x pressed\n", code);
298         }
299
300         kfree(obj);
301 }
302
303 static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
304                            const char *buf, size_t count)
305 {
306         int value;
307         struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
308         acpi_status status;
309
310         if (!count || sscanf(buf, "%i", &value) != 1)
311                 return -EINVAL;
312         if (value < 0 || value > 2)
313                 return -EINVAL;
314
315         status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
316                                      1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
317
318         if (ACPI_FAILURE(status))
319                 return -EIO;
320         else
321                 return count;
322 }
323
324 static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
325
326 static void eeepc_wmi_sysfs_exit(struct platform_device *device)
327 {
328         device_remove_file(&device->dev, &dev_attr_cpufv);
329 }
330
331 static int eeepc_wmi_sysfs_init(struct platform_device *device)
332 {
333         int retval = -ENOMEM;
334
335         retval = device_create_file(&device->dev, &dev_attr_cpufv);
336         if (retval)
337                 goto error_sysfs;
338
339         return 0;
340
341 error_sysfs:
342         eeepc_wmi_sysfs_exit(device);
343         return retval;
344 }
345
346 /*
347  * Platform device
348  */
349 static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc)
350 {
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;
386         acpi_status status;
387         int err;
388
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;
400
401         err = eeepc_wmi_input_init(eeepc);
402         if (err)
403                 goto fail_input;
404
405         if (!acpi_video_backlight_support()) {
406                 err = eeepc_wmi_backlight_init(eeepc);
407                 if (err)
408                         goto fail_backlight;
409         } else
410                 pr_info("Backlight controlled by ACPI video driver\n");
411
412         status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
413                                             eeepc_wmi_notify, eeepc);
414         if (ACPI_FAILURE(status)) {
415                 pr_err("Unable to register notify handler - %d\n",
416                         status);
417                 err = -ENODEV;
418                 goto fail_wmi_handler;
419         }
420
421         return eeepc->platform_device;
422
423 fail_wmi_handler:
424         eeepc_wmi_backlight_exit(eeepc);
425 fail_backlight:
426         eeepc_wmi_input_exit(eeepc);
427 fail_input:
428         eeepc_wmi_platform_exit(eeepc);
429 fail_platform:
430         kfree(eeepc);
431         return ERR_PTR(err);
432 }
433
434 static int eeepc_wmi_remove(struct platform_device *device)
435 {
436         struct eeepc_wmi *eeepc;
437
438         eeepc = platform_get_drvdata(device);
439         wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
440         eeepc_wmi_backlight_exit(eeepc);
441         eeepc_wmi_input_exit(eeepc);
442         eeepc_wmi_platform_exit(eeepc);
443
444         kfree(eeepc);
445         return 0;
446 }
447
448 static struct platform_driver platform_driver = {
449         .driver = {
450                 .name = EEEPC_WMI_FILE,
451                 .owner = THIS_MODULE,
452         },
453 };
454
455 static int __init eeepc_wmi_init(void)
456 {
457         int err;
458
459         if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
460             !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) {
461                 pr_warning("No known WMI GUID found\n");
462                 return -ENODEV;
463         }
464
465         platform_device = eeepc_wmi_add();
466         if (IS_ERR(platform_device)) {
467                 err = PTR_ERR(platform_device);
468                 goto fail_eeepc_wmi;
469         }
470
471         err = platform_driver_register(&platform_driver);
472         if (err) {
473                 pr_warning("Unable to register platform driver\n");
474                 goto fail_platform_driver;
475         }
476
477         return 0;
478
479 fail_platform_driver:
480         eeepc_wmi_remove(platform_device);
481 fail_eeepc_wmi:
482         return err;
483 }
484
485 static void __exit eeepc_wmi_exit(void)
486 {
487         eeepc_wmi_remove(platform_device);
488         platform_driver_unregister(&platform_driver);
489 }
490
491 module_init(eeepc_wmi_init);
492 module_exit(eeepc_wmi_exit);