x86 platform drivers: hp-wmi Use consistent prefix string for messages.
[pandora-kernel.git] / drivers / platform / x86 / hp-wmi.c
1 /*
2  * HP 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/slab.h>
30 #include <linux/types.h>
31 #include <linux/input.h>
32 #include <acpi/acpi_drivers.h>
33 #include <linux/platform_device.h>
34 #include <linux/acpi.h>
35 #include <linux/rfkill.h>
36 #include <linux/string.h>
37
38 MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
39 MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
40 MODULE_LICENSE("GPL");
41
42 MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
43 MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
44
45 #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
46 #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
47
48 #define HPWMI_DISPLAY_QUERY 0x1
49 #define HPWMI_HDDTEMP_QUERY 0x2
50 #define HPWMI_ALS_QUERY 0x3
51 #define HPWMI_HARDWARE_QUERY 0x4
52 #define HPWMI_WIRELESS_QUERY 0x5
53 #define HPWMI_HOTKEY_QUERY 0xc
54
55 #define PREFIX "HP WMI: "
56
57 enum hp_wmi_radio {
58         HPWMI_WIFI = 0,
59         HPWMI_BLUETOOTH = 1,
60         HPWMI_WWAN = 2,
61 };
62
63 enum hp_wmi_event_ids {
64         HPWMI_DOCK_EVENT = 1,
65         HPWMI_BEZEL_BUTTON = 4,
66         HPWMI_WIRELESS = 5,
67 };
68
69 static int __devinit hp_wmi_bios_setup(struct platform_device *device);
70 static int __exit hp_wmi_bios_remove(struct platform_device *device);
71 static int hp_wmi_resume_handler(struct device *device);
72
73 struct bios_args {
74         u32 signature;
75         u32 command;
76         u32 commandtype;
77         u32 datasize;
78         u32 data;
79 };
80
81 struct bios_return {
82         u32 sigpass;
83         u32 return_code;
84         u32 value;
85 };
86
87 struct key_entry {
88         char type;              /* See KE_* below */
89         u16 code;
90         u16 keycode;
91 };
92
93 enum { KE_KEY, KE_END };
94
95 static struct key_entry hp_wmi_keymap[] = {
96         {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
97         {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
98         {KE_KEY, 0x20e6, KEY_PROG1},
99         {KE_KEY, 0x2142, KEY_MEDIA},
100         {KE_KEY, 0x213b, KEY_INFO},
101         {KE_KEY, 0x2169, KEY_DIRECTION},
102         {KE_KEY, 0x231b, KEY_HELP},
103         {KE_END, 0}
104 };
105
106 static struct input_dev *hp_wmi_input_dev;
107 static struct platform_device *hp_wmi_platform_dev;
108
109 static struct rfkill *wifi_rfkill;
110 static struct rfkill *bluetooth_rfkill;
111 static struct rfkill *wwan_rfkill;
112
113 static const struct dev_pm_ops hp_wmi_pm_ops = {
114         .resume  = hp_wmi_resume_handler,
115         .restore  = hp_wmi_resume_handler,
116 };
117
118 static struct platform_driver hp_wmi_driver = {
119         .driver = {
120                 .name = "hp-wmi",
121                 .owner = THIS_MODULE,
122                 .pm = &hp_wmi_pm_ops,
123         },
124         .probe = hp_wmi_bios_setup,
125         .remove = hp_wmi_bios_remove,
126 };
127
128 static int hp_wmi_perform_query(int query, int write, int value)
129 {
130         struct bios_return bios_return;
131         acpi_status status;
132         union acpi_object *obj;
133         struct bios_args args = {
134                 .signature = 0x55434553,
135                 .command = write ? 0x2 : 0x1,
136                 .commandtype = query,
137                 .datasize = write ? 0x4 : 0,
138                 .data = value,
139         };
140         struct acpi_buffer input = { sizeof(struct bios_args), &args };
141         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
142
143         status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
144
145         obj = output.pointer;
146
147         if (!obj)
148                 return -EINVAL;
149         else if (obj->type != ACPI_TYPE_BUFFER) {
150                 kfree(obj);
151                 return -EINVAL;
152         }
153
154         bios_return = *((struct bios_return *)obj->buffer.pointer);
155         kfree(obj);
156         if (bios_return.return_code > 0)
157                 return bios_return.return_code * -1;
158         else
159                 return bios_return.value;
160 }
161
162 static int hp_wmi_display_state(void)
163 {
164         return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0);
165 }
166
167 static int hp_wmi_hddtemp_state(void)
168 {
169         return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0);
170 }
171
172 static int hp_wmi_als_state(void)
173 {
174         return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0);
175 }
176
177 static int hp_wmi_dock_state(void)
178 {
179         int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
180
181         if (ret < 0)
182                 return ret;
183
184         return ret & 0x1;
185 }
186
187 static int hp_wmi_tablet_state(void)
188 {
189         int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
190
191         if (ret < 0)
192                 return ret;
193
194         return (ret & 0x4) ? 1 : 0;
195 }
196
197 static int hp_wmi_set_block(void *data, bool blocked)
198 {
199         enum hp_wmi_radio r = (enum hp_wmi_radio) data;
200         int query = BIT(r + 8) | ((!blocked) << r);
201
202         return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
203 }
204
205 static const struct rfkill_ops hp_wmi_rfkill_ops = {
206         .set_block = hp_wmi_set_block,
207 };
208
209 static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
210 {
211         int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
212         int mask = 0x200 << (r * 8);
213
214         if (wireless & mask)
215                 return false;
216         else
217                 return true;
218 }
219
220 static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
221 {
222         int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
223         int mask = 0x800 << (r * 8);
224
225         if (wireless & mask)
226                 return false;
227         else
228                 return true;
229 }
230
231 static ssize_t show_display(struct device *dev, struct device_attribute *attr,
232                             char *buf)
233 {
234         int value = hp_wmi_display_state();
235         if (value < 0)
236                 return -EINVAL;
237         return sprintf(buf, "%d\n", value);
238 }
239
240 static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr,
241                             char *buf)
242 {
243         int value = hp_wmi_hddtemp_state();
244         if (value < 0)
245                 return -EINVAL;
246         return sprintf(buf, "%d\n", value);
247 }
248
249 static ssize_t show_als(struct device *dev, struct device_attribute *attr,
250                         char *buf)
251 {
252         int value = hp_wmi_als_state();
253         if (value < 0)
254                 return -EINVAL;
255         return sprintf(buf, "%d\n", value);
256 }
257
258 static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
259                          char *buf)
260 {
261         int value = hp_wmi_dock_state();
262         if (value < 0)
263                 return -EINVAL;
264         return sprintf(buf, "%d\n", value);
265 }
266
267 static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
268                          char *buf)
269 {
270         int value = hp_wmi_tablet_state();
271         if (value < 0)
272                 return -EINVAL;
273         return sprintf(buf, "%d\n", value);
274 }
275
276 static ssize_t set_als(struct device *dev, struct device_attribute *attr,
277                        const char *buf, size_t count)
278 {
279         u32 tmp = simple_strtoul(buf, NULL, 10);
280         hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp);
281         return count;
282 }
283
284 static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
285 static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
286 static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
287 static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
288 static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
289
290 static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
291 {
292         struct key_entry *key;
293
294         for (key = hp_wmi_keymap; key->type != KE_END; key++)
295                 if (code == key->code)
296                         return key;
297
298         return NULL;
299 }
300
301 static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
302 {
303         struct key_entry *key;
304
305         for (key = hp_wmi_keymap; key->type != KE_END; key++)
306                 if (key->type == KE_KEY && keycode == key->keycode)
307                         return key;
308
309         return NULL;
310 }
311
312 static int hp_wmi_getkeycode(struct input_dev *dev,
313                              unsigned int scancode, unsigned int *keycode)
314 {
315         struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
316
317         if (key && key->type == KE_KEY) {
318                 *keycode = key->keycode;
319                 return 0;
320         }
321
322         return -EINVAL;
323 }
324
325 static int hp_wmi_setkeycode(struct input_dev *dev,
326                              unsigned int scancode, unsigned int keycode)
327 {
328         struct key_entry *key;
329         unsigned int old_keycode;
330
331         key = hp_wmi_get_entry_by_scancode(scancode);
332         if (key && key->type == KE_KEY) {
333                 old_keycode = key->keycode;
334                 key->keycode = keycode;
335                 set_bit(keycode, dev->keybit);
336                 if (!hp_wmi_get_entry_by_keycode(old_keycode))
337                         clear_bit(old_keycode, dev->keybit);
338                 return 0;
339         }
340
341         return -EINVAL;
342 }
343
344 static void hp_wmi_notify(u32 value, void *context)
345 {
346         struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
347         static struct key_entry *key;
348         union acpi_object *obj;
349         int eventcode, key_code;
350         acpi_status status;
351
352         status = wmi_get_event_data(value, &response);
353         if (status != AE_OK) {
354                 printk(KERN_INFO PREFIX "bad event status 0x%x\n", status);
355                 return;
356         }
357
358         obj = (union acpi_object *)response.pointer;
359
360         if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
361                 printk(KERN_INFO PREFIX "Unknown response received\n");
362                 kfree(obj);
363                 return;
364         }
365
366         eventcode = *((u8 *) obj->buffer.pointer);
367         kfree(obj);
368         switch (eventcode) {
369         case HPWMI_DOCK_EVENT:
370                 input_report_switch(hp_wmi_input_dev, SW_DOCK,
371                                     hp_wmi_dock_state());
372                 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
373                                     hp_wmi_tablet_state());
374                 input_sync(hp_wmi_input_dev);
375                 break;
376         case HPWMI_BEZEL_BUTTON:
377                 key_code = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
378                                                  0);
379                 key = hp_wmi_get_entry_by_scancode(key_code);
380                 if (key) {
381                         switch (key->type) {
382                         case KE_KEY:
383                                 input_report_key(hp_wmi_input_dev,
384                                                  key->keycode, 1);
385                                 input_sync(hp_wmi_input_dev);
386                                 input_report_key(hp_wmi_input_dev,
387                                                  key->keycode, 0);
388                                 input_sync(hp_wmi_input_dev);
389                                 break;
390                         }
391                 } else
392                         printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
393                                key_code);
394                 break;
395         case HPWMI_WIRELESS:
396                 if (wifi_rfkill)
397                         rfkill_set_states(wifi_rfkill,
398                                           hp_wmi_get_sw_state(HPWMI_WIFI),
399                                           hp_wmi_get_hw_state(HPWMI_WIFI));
400                 if (bluetooth_rfkill)
401                         rfkill_set_states(bluetooth_rfkill,
402                                           hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
403                                           hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
404                 if (wwan_rfkill)
405                         rfkill_set_states(wwan_rfkill,
406                                           hp_wmi_get_sw_state(HPWMI_WWAN),
407                                           hp_wmi_get_hw_state(HPWMI_WWAN));
408                 break;
409         default:
410                 printk(KERN_INFO PREFIX "Unknown eventcode - %d\n",
411                        eventcode);
412                 break;
413         }
414 }
415
416 static int __init hp_wmi_input_setup(void)
417 {
418         struct key_entry *key;
419         int err;
420
421         hp_wmi_input_dev = input_allocate_device();
422
423         hp_wmi_input_dev->name = "HP WMI hotkeys";
424         hp_wmi_input_dev->phys = "wmi/input0";
425         hp_wmi_input_dev->id.bustype = BUS_HOST;
426         hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
427         hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
428
429         for (key = hp_wmi_keymap; key->type != KE_END; key++) {
430                 switch (key->type) {
431                 case KE_KEY:
432                         set_bit(EV_KEY, hp_wmi_input_dev->evbit);
433                         set_bit(key->keycode, hp_wmi_input_dev->keybit);
434                         break;
435                 }
436         }
437
438         set_bit(EV_SW, hp_wmi_input_dev->evbit);
439         set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
440         set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
441
442         /* Set initial hardware state */
443         input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
444         input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
445                             hp_wmi_tablet_state());
446         input_sync(hp_wmi_input_dev);
447
448         err = input_register_device(hp_wmi_input_dev);
449
450         if (err) {
451                 input_free_device(hp_wmi_input_dev);
452                 return err;
453         }
454
455         return 0;
456 }
457
458 static void cleanup_sysfs(struct platform_device *device)
459 {
460         device_remove_file(&device->dev, &dev_attr_display);
461         device_remove_file(&device->dev, &dev_attr_hddtemp);
462         device_remove_file(&device->dev, &dev_attr_als);
463         device_remove_file(&device->dev, &dev_attr_dock);
464         device_remove_file(&device->dev, &dev_attr_tablet);
465 }
466
467 static int __devinit hp_wmi_bios_setup(struct platform_device *device)
468 {
469         int err;
470         int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
471
472         err = device_create_file(&device->dev, &dev_attr_display);
473         if (err)
474                 goto add_sysfs_error;
475         err = device_create_file(&device->dev, &dev_attr_hddtemp);
476         if (err)
477                 goto add_sysfs_error;
478         err = device_create_file(&device->dev, &dev_attr_als);
479         if (err)
480                 goto add_sysfs_error;
481         err = device_create_file(&device->dev, &dev_attr_dock);
482         if (err)
483                 goto add_sysfs_error;
484         err = device_create_file(&device->dev, &dev_attr_tablet);
485         if (err)
486                 goto add_sysfs_error;
487
488         if (wireless & 0x1) {
489                 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
490                                            RFKILL_TYPE_WLAN,
491                                            &hp_wmi_rfkill_ops,
492                                            (void *) HPWMI_WIFI);
493                 rfkill_init_sw_state(wifi_rfkill,
494                                      hp_wmi_get_sw_state(HPWMI_WIFI));
495                 rfkill_set_hw_state(wifi_rfkill,
496                                     hp_wmi_get_hw_state(HPWMI_WIFI));
497                 err = rfkill_register(wifi_rfkill);
498                 if (err)
499                         goto register_wifi_error;
500         }
501
502         if (wireless & 0x2) {
503                 bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
504                                                 RFKILL_TYPE_BLUETOOTH,
505                                                 &hp_wmi_rfkill_ops,
506                                                 (void *) HPWMI_BLUETOOTH);
507                 rfkill_init_sw_state(bluetooth_rfkill,
508                                      hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
509                 rfkill_set_hw_state(bluetooth_rfkill,
510                                     hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
511                 err = rfkill_register(bluetooth_rfkill);
512                 if (err)
513                         goto register_bluetooth_error;
514         }
515
516         if (wireless & 0x4) {
517                 wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
518                                            RFKILL_TYPE_WWAN,
519                                            &hp_wmi_rfkill_ops,
520                                            (void *) HPWMI_WWAN);
521                 rfkill_init_sw_state(wwan_rfkill,
522                                      hp_wmi_get_sw_state(HPWMI_WWAN));
523                 rfkill_set_hw_state(wwan_rfkill,
524                                     hp_wmi_get_hw_state(HPWMI_WWAN));
525                 err = rfkill_register(wwan_rfkill);
526                 if (err)
527                         goto register_wwan_err;
528         }
529
530         return 0;
531 register_wwan_err:
532         rfkill_destroy(wwan_rfkill);
533         if (bluetooth_rfkill)
534                 rfkill_unregister(bluetooth_rfkill);
535 register_bluetooth_error:
536         rfkill_destroy(bluetooth_rfkill);
537         if (wifi_rfkill)
538                 rfkill_unregister(wifi_rfkill);
539 register_wifi_error:
540         rfkill_destroy(wifi_rfkill);
541 add_sysfs_error:
542         cleanup_sysfs(device);
543         return err;
544 }
545
546 static int __exit hp_wmi_bios_remove(struct platform_device *device)
547 {
548         cleanup_sysfs(device);
549
550         if (wifi_rfkill) {
551                 rfkill_unregister(wifi_rfkill);
552                 rfkill_destroy(wifi_rfkill);
553         }
554         if (bluetooth_rfkill) {
555                 rfkill_unregister(bluetooth_rfkill);
556                 rfkill_destroy(bluetooth_rfkill);
557         }
558         if (wwan_rfkill) {
559                 rfkill_unregister(wwan_rfkill);
560                 rfkill_destroy(wwan_rfkill);
561         }
562
563         return 0;
564 }
565
566 static int hp_wmi_resume_handler(struct device *device)
567 {
568         /*
569          * Hardware state may have changed while suspended, so trigger
570          * input events for the current state. As this is a switch,
571          * the input layer will only actually pass it on if the state
572          * changed.
573          */
574         if (hp_wmi_input_dev) {
575                 input_report_switch(hp_wmi_input_dev, SW_DOCK,
576                                     hp_wmi_dock_state());
577                 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
578                                     hp_wmi_tablet_state());
579                 input_sync(hp_wmi_input_dev);
580         }
581
582         if (wifi_rfkill)
583                 rfkill_set_states(wifi_rfkill,
584                                   hp_wmi_get_sw_state(HPWMI_WIFI),
585                                   hp_wmi_get_hw_state(HPWMI_WIFI));
586         if (bluetooth_rfkill)
587                 rfkill_set_states(bluetooth_rfkill,
588                                   hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
589                                   hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
590         if (wwan_rfkill)
591                 rfkill_set_states(wwan_rfkill,
592                                   hp_wmi_get_sw_state(HPWMI_WWAN),
593                                   hp_wmi_get_hw_state(HPWMI_WWAN));
594
595         return 0;
596 }
597
598 static int __init hp_wmi_init(void)
599 {
600         int err;
601
602         if (wmi_has_guid(HPWMI_EVENT_GUID)) {
603                 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
604                                                  hp_wmi_notify, NULL);
605                 if (ACPI_SUCCESS(err))
606                         hp_wmi_input_setup();
607         }
608
609         if (wmi_has_guid(HPWMI_BIOS_GUID)) {
610                 err = platform_driver_register(&hp_wmi_driver);
611                 if (err)
612                         return 0;
613                 hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
614                 if (!hp_wmi_platform_dev) {
615                         platform_driver_unregister(&hp_wmi_driver);
616                         return 0;
617                 }
618                 platform_device_add(hp_wmi_platform_dev);
619         }
620
621         return 0;
622 }
623
624 static void __exit hp_wmi_exit(void)
625 {
626         if (wmi_has_guid(HPWMI_EVENT_GUID)) {
627                 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
628                 input_unregister_device(hp_wmi_input_dev);
629         }
630         if (hp_wmi_platform_dev) {
631                 platform_device_del(hp_wmi_platform_dev);
632                 platform_driver_unregister(&hp_wmi_driver);
633         }
634 }
635
636 module_init(hp_wmi_init);
637 module_exit(hp_wmi_exit);