Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[sfrench/cifs-2.6.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 <linux/platform_device.h>
33 #include <linux/acpi.h>
34 #include <linux/rfkill.h>
35 #include <linux/string.h>
36
37 MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
38 MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
39 MODULE_LICENSE("GPL");
40
41 MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
42 MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
43
44 #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
45 #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
46
47 #define HPWMI_DISPLAY_QUERY 0x1
48 #define HPWMI_HDDTEMP_QUERY 0x2
49 #define HPWMI_ALS_QUERY 0x3
50 #define HPWMI_HARDWARE_QUERY 0x4
51 #define HPWMI_WIRELESS_QUERY 0x5
52 #define HPWMI_HOTKEY_QUERY 0xc
53
54 #define PREFIX "HP WMI: "
55 #define UNIMP "Unimplemented "
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_PARK_HDD = 2,
66         HPWMI_SMART_ADAPTER = 3,
67         HPWMI_BEZEL_BUTTON = 4,
68         HPWMI_WIRELESS = 5,
69         HPWMI_CPU_BATTERY_THROTTLE = 6,
70         HPWMI_LOCK_SWITCH = 7,
71 };
72
73 static int __devinit hp_wmi_bios_setup(struct platform_device *device);
74 static int __exit hp_wmi_bios_remove(struct platform_device *device);
75 static int hp_wmi_resume_handler(struct device *device);
76
77 struct bios_args {
78         u32 signature;
79         u32 command;
80         u32 commandtype;
81         u32 datasize;
82         char *data;
83 };
84
85 struct bios_return {
86         u32 sigpass;
87         u32 return_code;
88 };
89
90 struct key_entry {
91         char type;              /* See KE_* below */
92         u16 code;
93         u16 keycode;
94 };
95
96 enum { KE_KEY, KE_END };
97
98 static struct key_entry hp_wmi_keymap[] = {
99         {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
100         {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
101         {KE_KEY, 0x20e6, KEY_PROG1},
102         {KE_KEY, 0x20e8, KEY_MEDIA},
103         {KE_KEY, 0x2142, KEY_MEDIA},
104         {KE_KEY, 0x213b, KEY_INFO},
105         {KE_KEY, 0x2169, KEY_DIRECTION},
106         {KE_KEY, 0x231b, KEY_HELP},
107         {KE_END, 0}
108 };
109
110 static struct input_dev *hp_wmi_input_dev;
111 static struct platform_device *hp_wmi_platform_dev;
112
113 static struct rfkill *wifi_rfkill;
114 static struct rfkill *bluetooth_rfkill;
115 static struct rfkill *wwan_rfkill;
116
117 static const struct dev_pm_ops hp_wmi_pm_ops = {
118         .resume  = hp_wmi_resume_handler,
119         .restore  = hp_wmi_resume_handler,
120 };
121
122 static struct platform_driver hp_wmi_driver = {
123         .driver = {
124                 .name = "hp-wmi",
125                 .owner = THIS_MODULE,
126                 .pm = &hp_wmi_pm_ops,
127         },
128         .probe = hp_wmi_bios_setup,
129         .remove = hp_wmi_bios_remove,
130 };
131
132 /*
133  * hp_wmi_perform_query
134  *
135  * query:       The commandtype -> What should be queried
136  * write:       The command -> 0 read, 1 write, 3 ODM specific
137  * buffer:      Buffer used as input and/or output
138  * buffersize:  Size of buffer
139  *
140  * returns zero on success
141  *         an HP WMI query specific error code (which is positive)
142  *         -EINVAL if the query was not successful at all
143  *         -EINVAL if the output buffer size exceeds buffersize
144  *
145  * Note: The buffersize must at least be the maximum of the input and output
146  *       size. E.g. Battery info query (0x7) is defined to have 1 byte input
147  *       and 128 byte output. The caller would do:
148  *       buffer = kzalloc(128, GFP_KERNEL);
149  *       ret = hp_wmi_perform_query(0x7, 0, buffer, 128)
150  */
151 static int hp_wmi_perform_query(int query, int write, char *buffer,
152                                 int buffersize)
153 {
154         struct bios_return bios_return;
155         acpi_status status;
156         union acpi_object *obj;
157         struct bios_args args = {
158                 .signature = 0x55434553,
159                 .command = write ? 0x2 : 0x1,
160                 .commandtype = query,
161                 .datasize = buffersize,
162                 .data = buffer,
163         };
164         struct acpi_buffer input = { sizeof(struct bios_args), &args };
165         struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
166
167         status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
168
169         obj = output.pointer;
170
171         if (!obj)
172                 return -EINVAL;
173         else if (obj->type != ACPI_TYPE_BUFFER) {
174                 kfree(obj);
175                 return -EINVAL;
176         }
177
178         bios_return = *((struct bios_return *)obj->buffer.pointer);
179
180         if (bios_return.return_code) {
181                 printk(KERN_WARNING PREFIX "Query %d returned %d\n", query,
182                        bios_return.return_code);
183                 kfree(obj);
184                 return bios_return.return_code;
185         }
186         if (obj->buffer.length - sizeof(bios_return) > buffersize) {
187                 kfree(obj);
188                 return -EINVAL;
189         }
190
191         memset(buffer, 0, buffersize);
192         memcpy(buffer,
193                ((char *)obj->buffer.pointer) + sizeof(struct bios_return),
194                obj->buffer.length - sizeof(bios_return));
195         kfree(obj);
196         return 0;
197 }
198
199 static int hp_wmi_display_state(void)
200 {
201         int state;
202         int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, (char *)&state,
203                                        sizeof(state));
204         if (ret)
205                 return -EINVAL;
206         return state;
207 }
208
209 static int hp_wmi_hddtemp_state(void)
210 {
211         int state;
212         int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, (char *)&state,
213                                        sizeof(state));
214         if (ret)
215                 return -EINVAL;
216         return state;
217 }
218
219 static int hp_wmi_als_state(void)
220 {
221         int state;
222         int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, (char *)&state,
223                                        sizeof(state));
224         if (ret)
225                 return -EINVAL;
226         return state;
227 }
228
229 static int hp_wmi_dock_state(void)
230 {
231         int state;
232         int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
233                                        sizeof(state));
234
235         if (ret)
236                 return -EINVAL;
237
238         return state & 0x1;
239 }
240
241 static int hp_wmi_tablet_state(void)
242 {
243         int state;
244         int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state,
245                                        sizeof(state));
246         if (ret)
247                 return ret;
248
249         return (state & 0x4) ? 1 : 0;
250 }
251
252 static int hp_wmi_set_block(void *data, bool blocked)
253 {
254         enum hp_wmi_radio r = (enum hp_wmi_radio) data;
255         int query = BIT(r + 8) | ((!blocked) << r);
256         int ret;
257
258         ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
259                                    (char *)&query, sizeof(query));
260         if (ret)
261                 return -EINVAL;
262         return 0;
263 }
264
265 static const struct rfkill_ops hp_wmi_rfkill_ops = {
266         .set_block = hp_wmi_set_block,
267 };
268
269 static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
270 {
271         int wireless;
272         int mask;
273         hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
274                              (char *)&wireless, sizeof(wireless));
275         /* TBD: Pass error */
276
277         mask = 0x200 << (r * 8);
278
279         if (wireless & mask)
280                 return false;
281         else
282                 return true;
283 }
284
285 static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
286 {
287         int wireless;
288         int mask;
289         hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
290                              (char *)&wireless, sizeof(wireless));
291         /* TBD: Pass error */
292
293         mask = 0x800 << (r * 8);
294
295         if (wireless & mask)
296                 return false;
297         else
298                 return true;
299 }
300
301 static ssize_t show_display(struct device *dev, struct device_attribute *attr,
302                             char *buf)
303 {
304         int value = hp_wmi_display_state();
305         if (value < 0)
306                 return -EINVAL;
307         return sprintf(buf, "%d\n", value);
308 }
309
310 static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr,
311                             char *buf)
312 {
313         int value = hp_wmi_hddtemp_state();
314         if (value < 0)
315                 return -EINVAL;
316         return sprintf(buf, "%d\n", value);
317 }
318
319 static ssize_t show_als(struct device *dev, struct device_attribute *attr,
320                         char *buf)
321 {
322         int value = hp_wmi_als_state();
323         if (value < 0)
324                 return -EINVAL;
325         return sprintf(buf, "%d\n", value);
326 }
327
328 static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
329                          char *buf)
330 {
331         int value = hp_wmi_dock_state();
332         if (value < 0)
333                 return -EINVAL;
334         return sprintf(buf, "%d\n", value);
335 }
336
337 static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
338                          char *buf)
339 {
340         int value = hp_wmi_tablet_state();
341         if (value < 0)
342                 return -EINVAL;
343         return sprintf(buf, "%d\n", value);
344 }
345
346 static ssize_t set_als(struct device *dev, struct device_attribute *attr,
347                        const char *buf, size_t count)
348 {
349         u32 tmp = simple_strtoul(buf, NULL, 10);
350         int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, (char *)&tmp,
351                                        sizeof(tmp));
352         if (ret)
353                 return -EINVAL;
354
355         return count;
356 }
357
358 static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
359 static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
360 static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
361 static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
362 static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
363
364 static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
365 {
366         struct key_entry *key;
367
368         for (key = hp_wmi_keymap; key->type != KE_END; key++)
369                 if (code == key->code)
370                         return key;
371
372         return NULL;
373 }
374
375 static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
376 {
377         struct key_entry *key;
378
379         for (key = hp_wmi_keymap; key->type != KE_END; key++)
380                 if (key->type == KE_KEY && keycode == key->keycode)
381                         return key;
382
383         return NULL;
384 }
385
386 static int hp_wmi_getkeycode(struct input_dev *dev,
387                              unsigned int scancode, unsigned int *keycode)
388 {
389         struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
390
391         if (key && key->type == KE_KEY) {
392                 *keycode = key->keycode;
393                 return 0;
394         }
395
396         return -EINVAL;
397 }
398
399 static int hp_wmi_setkeycode(struct input_dev *dev,
400                              unsigned int scancode, unsigned int keycode)
401 {
402         struct key_entry *key;
403         unsigned int old_keycode;
404
405         key = hp_wmi_get_entry_by_scancode(scancode);
406         if (key && key->type == KE_KEY) {
407                 old_keycode = key->keycode;
408                 key->keycode = keycode;
409                 set_bit(keycode, dev->keybit);
410                 if (!hp_wmi_get_entry_by_keycode(old_keycode))
411                         clear_bit(old_keycode, dev->keybit);
412                 return 0;
413         }
414
415         return -EINVAL;
416 }
417
418 static void hp_wmi_notify(u32 value, void *context)
419 {
420         struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
421         static struct key_entry *key;
422         union acpi_object *obj;
423         u32 event_id, event_data;
424         int key_code, ret;
425         u32 *location;
426         acpi_status status;
427
428         status = wmi_get_event_data(value, &response);
429         if (status != AE_OK) {
430                 printk(KERN_INFO PREFIX "bad event status 0x%x\n", status);
431                 return;
432         }
433
434         obj = (union acpi_object *)response.pointer;
435
436         if (!obj)
437                 return;
438         if (obj->type != ACPI_TYPE_BUFFER) {
439                 printk(KERN_INFO "hp-wmi: Unknown response received %d\n",
440                        obj->type);
441                 kfree(obj);
442                 return;
443         }
444
445         /*
446          * Depending on ACPI version the concatenation of id and event data
447          * inside _WED function will result in a 8 or 16 byte buffer.
448          */
449         location = (u32 *)obj->buffer.pointer;
450         if (obj->buffer.length == 8) {
451                 event_id = *location;
452                 event_data = *(location + 1);
453         } else if (obj->buffer.length == 16) {
454                 event_id = *location;
455                 event_data = *(location + 2);
456         } else {
457                 printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n",
458                        obj->buffer.length);
459                 kfree(obj);
460                 return;
461         }
462         kfree(obj);
463
464         switch (event_id) {
465         case HPWMI_DOCK_EVENT:
466                 input_report_switch(hp_wmi_input_dev, SW_DOCK,
467                                     hp_wmi_dock_state());
468                 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
469                                     hp_wmi_tablet_state());
470                 input_sync(hp_wmi_input_dev);
471                 break;
472         case HPWMI_PARK_HDD:
473                 break;
474         case HPWMI_SMART_ADAPTER:
475                 break;
476         case HPWMI_BEZEL_BUTTON:
477                 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
478                                            (char *)&key_code,
479                                            sizeof(key_code));
480                 if (ret)
481                         break;
482                 key = hp_wmi_get_entry_by_scancode(key_code);
483                 if (key) {
484                         switch (key->type) {
485                         case KE_KEY:
486                                 input_report_key(hp_wmi_input_dev,
487                                                  key->keycode, 1);
488                                 input_sync(hp_wmi_input_dev);
489                                 input_report_key(hp_wmi_input_dev,
490                                                  key->keycode, 0);
491                                 input_sync(hp_wmi_input_dev);
492                                 break;
493                         }
494                 } else
495                         printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
496                                key_code);
497                 break;
498         case HPWMI_WIRELESS:
499                 if (wifi_rfkill)
500                         rfkill_set_states(wifi_rfkill,
501                                           hp_wmi_get_sw_state(HPWMI_WIFI),
502                                           hp_wmi_get_hw_state(HPWMI_WIFI));
503                 if (bluetooth_rfkill)
504                         rfkill_set_states(bluetooth_rfkill,
505                                           hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
506                                           hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
507                 if (wwan_rfkill)
508                         rfkill_set_states(wwan_rfkill,
509                                           hp_wmi_get_sw_state(HPWMI_WWAN),
510                                           hp_wmi_get_hw_state(HPWMI_WWAN));
511                 break;
512         case HPWMI_CPU_BATTERY_THROTTLE:
513                 printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell"
514                        " battery event detected\n");
515                 break;
516         case HPWMI_LOCK_SWITCH:
517                 break;
518         default:
519                 printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n",
520                        event_id, event_data);
521                 break;
522         }
523 }
524
525 static int __init hp_wmi_input_setup(void)
526 {
527         struct key_entry *key;
528         int err;
529
530         hp_wmi_input_dev = input_allocate_device();
531         if (!hp_wmi_input_dev)
532                 return -ENOMEM;
533
534         hp_wmi_input_dev->name = "HP WMI hotkeys";
535         hp_wmi_input_dev->phys = "wmi/input0";
536         hp_wmi_input_dev->id.bustype = BUS_HOST;
537         hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
538         hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
539
540         for (key = hp_wmi_keymap; key->type != KE_END; key++) {
541                 switch (key->type) {
542                 case KE_KEY:
543                         set_bit(EV_KEY, hp_wmi_input_dev->evbit);
544                         set_bit(key->keycode, hp_wmi_input_dev->keybit);
545                         break;
546                 }
547         }
548
549         set_bit(EV_SW, hp_wmi_input_dev->evbit);
550         set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
551         set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
552
553         /* Set initial hardware state */
554         input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
555         input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
556                             hp_wmi_tablet_state());
557         input_sync(hp_wmi_input_dev);
558
559         err = input_register_device(hp_wmi_input_dev);
560
561         if (err) {
562                 input_free_device(hp_wmi_input_dev);
563                 return err;
564         }
565
566         return 0;
567 }
568
569 static void cleanup_sysfs(struct platform_device *device)
570 {
571         device_remove_file(&device->dev, &dev_attr_display);
572         device_remove_file(&device->dev, &dev_attr_hddtemp);
573         device_remove_file(&device->dev, &dev_attr_als);
574         device_remove_file(&device->dev, &dev_attr_dock);
575         device_remove_file(&device->dev, &dev_attr_tablet);
576 }
577
578 static int __devinit hp_wmi_bios_setup(struct platform_device *device)
579 {
580         int err;
581         int wireless;
582
583         err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, (char *)&wireless,
584                                    sizeof(wireless));
585         if (err)
586                 return err;
587
588         err = device_create_file(&device->dev, &dev_attr_display);
589         if (err)
590                 goto add_sysfs_error;
591         err = device_create_file(&device->dev, &dev_attr_hddtemp);
592         if (err)
593                 goto add_sysfs_error;
594         err = device_create_file(&device->dev, &dev_attr_als);
595         if (err)
596                 goto add_sysfs_error;
597         err = device_create_file(&device->dev, &dev_attr_dock);
598         if (err)
599                 goto add_sysfs_error;
600         err = device_create_file(&device->dev, &dev_attr_tablet);
601         if (err)
602                 goto add_sysfs_error;
603
604         if (wireless & 0x1) {
605                 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
606                                            RFKILL_TYPE_WLAN,
607                                            &hp_wmi_rfkill_ops,
608                                            (void *) HPWMI_WIFI);
609                 rfkill_init_sw_state(wifi_rfkill,
610                                      hp_wmi_get_sw_state(HPWMI_WIFI));
611                 rfkill_set_hw_state(wifi_rfkill,
612                                     hp_wmi_get_hw_state(HPWMI_WIFI));
613                 err = rfkill_register(wifi_rfkill);
614                 if (err)
615                         goto register_wifi_error;
616         }
617
618         if (wireless & 0x2) {
619                 bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
620                                                 RFKILL_TYPE_BLUETOOTH,
621                                                 &hp_wmi_rfkill_ops,
622                                                 (void *) HPWMI_BLUETOOTH);
623                 rfkill_init_sw_state(bluetooth_rfkill,
624                                      hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
625                 rfkill_set_hw_state(bluetooth_rfkill,
626                                     hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
627                 err = rfkill_register(bluetooth_rfkill);
628                 if (err)
629                         goto register_bluetooth_error;
630         }
631
632         if (wireless & 0x4) {
633                 wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
634                                            RFKILL_TYPE_WWAN,
635                                            &hp_wmi_rfkill_ops,
636                                            (void *) HPWMI_WWAN);
637                 rfkill_init_sw_state(wwan_rfkill,
638                                      hp_wmi_get_sw_state(HPWMI_WWAN));
639                 rfkill_set_hw_state(wwan_rfkill,
640                                     hp_wmi_get_hw_state(HPWMI_WWAN));
641                 err = rfkill_register(wwan_rfkill);
642                 if (err)
643                         goto register_wwan_err;
644         }
645
646         return 0;
647 register_wwan_err:
648         rfkill_destroy(wwan_rfkill);
649         if (bluetooth_rfkill)
650                 rfkill_unregister(bluetooth_rfkill);
651 register_bluetooth_error:
652         rfkill_destroy(bluetooth_rfkill);
653         if (wifi_rfkill)
654                 rfkill_unregister(wifi_rfkill);
655 register_wifi_error:
656         rfkill_destroy(wifi_rfkill);
657 add_sysfs_error:
658         cleanup_sysfs(device);
659         return err;
660 }
661
662 static int __exit hp_wmi_bios_remove(struct platform_device *device)
663 {
664         cleanup_sysfs(device);
665
666         if (wifi_rfkill) {
667                 rfkill_unregister(wifi_rfkill);
668                 rfkill_destroy(wifi_rfkill);
669         }
670         if (bluetooth_rfkill) {
671                 rfkill_unregister(bluetooth_rfkill);
672                 rfkill_destroy(bluetooth_rfkill);
673         }
674         if (wwan_rfkill) {
675                 rfkill_unregister(wwan_rfkill);
676                 rfkill_destroy(wwan_rfkill);
677         }
678
679         return 0;
680 }
681
682 static int hp_wmi_resume_handler(struct device *device)
683 {
684         /*
685          * Hardware state may have changed while suspended, so trigger
686          * input events for the current state. As this is a switch,
687          * the input layer will only actually pass it on if the state
688          * changed.
689          */
690         if (hp_wmi_input_dev) {
691                 input_report_switch(hp_wmi_input_dev, SW_DOCK,
692                                     hp_wmi_dock_state());
693                 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
694                                     hp_wmi_tablet_state());
695                 input_sync(hp_wmi_input_dev);
696         }
697
698         if (wifi_rfkill)
699                 rfkill_set_states(wifi_rfkill,
700                                   hp_wmi_get_sw_state(HPWMI_WIFI),
701                                   hp_wmi_get_hw_state(HPWMI_WIFI));
702         if (bluetooth_rfkill)
703                 rfkill_set_states(bluetooth_rfkill,
704                                   hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
705                                   hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
706         if (wwan_rfkill)
707                 rfkill_set_states(wwan_rfkill,
708                                   hp_wmi_get_sw_state(HPWMI_WWAN),
709                                   hp_wmi_get_hw_state(HPWMI_WWAN));
710
711         return 0;
712 }
713
714 static int __init hp_wmi_init(void)
715 {
716         int err;
717         int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
718         int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
719
720         if (event_capable) {
721                 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
722                                                  hp_wmi_notify, NULL);
723                 if (ACPI_FAILURE(err))
724                         return -EINVAL;
725                 err = hp_wmi_input_setup();
726                 if (err) {
727                         wmi_remove_notify_handler(HPWMI_EVENT_GUID);
728                         return err;
729                 }
730         }
731
732         if (bios_capable) {
733                 err = platform_driver_register(&hp_wmi_driver);
734                 if (err)
735                         goto err_driver_reg;
736                 hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
737                 if (!hp_wmi_platform_dev) {
738                         err = -ENOMEM;
739                         goto err_device_alloc;
740                 }
741                 err = platform_device_add(hp_wmi_platform_dev);
742                 if (err)
743                         goto err_device_add;
744         }
745
746         if (!bios_capable && !event_capable)
747                 return -ENODEV;
748
749         return 0;
750
751 err_device_add:
752         platform_device_put(hp_wmi_platform_dev);
753 err_device_alloc:
754         platform_driver_unregister(&hp_wmi_driver);
755 err_driver_reg:
756         if (wmi_has_guid(HPWMI_EVENT_GUID)) {
757                 input_unregister_device(hp_wmi_input_dev);
758                 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
759         }
760
761         return err;
762 }
763
764 static void __exit hp_wmi_exit(void)
765 {
766         if (wmi_has_guid(HPWMI_EVENT_GUID)) {
767                 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
768                 input_unregister_device(hp_wmi_input_dev);
769         }
770         if (hp_wmi_platform_dev) {
771                 platform_device_unregister(hp_wmi_platform_dev);
772                 platform_driver_unregister(&hp_wmi_driver);
773         }
774 }
775
776 module_init(hp_wmi_init);
777 module_exit(hp_wmi_exit);