2
* Eee PC WMI hotkey driver
4
* Copyright(C) 2010 Intel Corporation.
5
* Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
7
* Portions based on wistron_btns.c:
8
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
9
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
10
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
12
* This program is free software; you can redistribute it and/or modify
13
* it under the terms of the GNU General Public License as published by
14
* the Free Software Foundation; either version 2 of the License, or
15
* (at your option) any later version.
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU General Public License for more details.
22
* You should have received a copy of the GNU General Public License
23
* along with this program; if not, write to the Free Software
24
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29
#include <linux/kernel.h>
30
#include <linux/module.h>
31
#include <linux/init.h>
32
#include <linux/types.h>
33
#include <linux/slab.h>
34
#include <linux/input.h>
35
#include <linux/input/sparse-keymap.h>
37
#include <linux/backlight.h>
38
#include <linux/leds.h>
39
#include <linux/rfkill.h>
40
#include <linux/debugfs.h>
41
#include <linux/seq_file.h>
42
#include <linux/platform_device.h>
43
#include <acpi/acpi_bus.h>
44
#include <acpi/acpi_drivers.h>
46
#define EEEPC_WMI_FILE "eeepc-wmi"
48
MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
49
MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
50
MODULE_LICENSE("GPL");
52
#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */
54
#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
55
#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
57
MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
58
MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID);
60
#define NOTIFY_BRNUP_MIN 0x11
61
#define NOTIFY_BRNUP_MAX 0x1f
62
#define NOTIFY_BRNDOWN_MIN 0x20
63
#define NOTIFY_BRNDOWN_MAX 0x2e
65
#define EEEPC_WMI_METHODID_DEVS 0x53564544
66
#define EEEPC_WMI_METHODID_DSTS 0x53544344
67
#define EEEPC_WMI_METHODID_CFVS 0x53564643
69
#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012
70
#define EEEPC_WMI_DEVID_TPDLED 0x00100011
71
#define EEEPC_WMI_DEVID_WLAN 0x00010011
72
#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013
73
#define EEEPC_WMI_DEVID_WWAN3G 0x00010019
75
static const struct key_entry eeepc_wmi_keymap[] = {
76
/* Sleep already handled via generic ACPI code */
77
{ KE_KEY, 0x5d, { KEY_WLAN } },
78
{ KE_KEY, 0x32, { KEY_MUTE } },
79
{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
80
{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
81
{ KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } },
82
{ KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } },
83
{ KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
84
{ KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */
85
{ KE_KEY, 0xe1, { KEY_F14 } },
86
{ KE_KEY, 0xe9, { KEY_DISPLAY_OFF } },
87
{ KE_KEY, 0xe0, { KEY_PROG1 } },
88
{ KE_KEY, 0x5c, { KEY_F15 } },
98
* eeepc-wmi/ - debugfs root directory
99
* dev_id - current dev_id
100
* ctrl_param - current ctrl_param
101
* devs - call DEVS(dev_id, ctrl_param) and print result
102
* dsts - call DSTS(dev_id) and print result
104
struct eeepc_wmi_debug {
111
struct input_dev *inputdev;
112
struct backlight_device *backlight_device;
113
struct platform_device *platform_device;
115
struct led_classdev tpd_led;
117
struct workqueue_struct *led_workqueue;
118
struct work_struct tpd_led_work;
120
struct rfkill *wlan_rfkill;
121
struct rfkill *bluetooth_rfkill;
122
struct rfkill *wwan3g_rfkill;
124
struct eeepc_wmi_debug debug;
127
/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */
128
static struct platform_device *platform_device;
130
static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc)
134
eeepc->inputdev = input_allocate_device();
135
if (!eeepc->inputdev)
138
eeepc->inputdev->name = "Eee PC WMI hotkeys";
139
eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0";
140
eeepc->inputdev->id.bustype = BUS_HOST;
141
eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
143
err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL);
147
err = input_register_device(eeepc->inputdev);
149
goto err_free_keymap;
154
sparse_keymap_free(eeepc->inputdev);
156
input_free_device(eeepc->inputdev);
160
static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc)
162
if (eeepc->inputdev) {
163
sparse_keymap_free(eeepc->inputdev);
164
input_unregister_device(eeepc->inputdev);
167
eeepc->inputdev = NULL;
170
static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval)
172
struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id };
173
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
174
union acpi_object *obj;
178
status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
179
1, EEEPC_WMI_METHODID_DSTS, &input, &output);
181
if (ACPI_FAILURE(status))
184
obj = (union acpi_object *)output.pointer;
185
if (obj && obj->type == ACPI_TYPE_INTEGER)
186
tmp = (u32)obj->integer.value;
199
static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
202
struct bios_args args = {
204
.ctrl_param = ctrl_param,
206
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
210
status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
211
EEEPC_WMI_METHODID_DEVS,
214
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
215
union acpi_object *obj;
218
status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1,
219
EEEPC_WMI_METHODID_DEVS,
222
if (ACPI_FAILURE(status))
225
obj = (union acpi_object *)output.pointer;
226
if (obj && obj->type == ACPI_TYPE_INTEGER)
227
tmp = (u32)obj->integer.value;
243
* These functions actually update the LED's, and are called from a
244
* workqueue. By doing this as separate work rather than when the LED
245
* subsystem asks, we avoid messing with the Eeepc ACPI stuff during a
246
* potentially bad time, such as a timer interrupt.
248
static void tpd_led_update(struct work_struct *work)
251
struct eeepc_wmi *eeepc;
253
eeepc = container_of(work, struct eeepc_wmi, tpd_led_work);
255
ctrl_param = eeepc->tpd_led_wk;
256
eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL);
259
static void tpd_led_set(struct led_classdev *led_cdev,
260
enum led_brightness value)
262
struct eeepc_wmi *eeepc;
264
eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
266
eeepc->tpd_led_wk = !!value;
267
queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
270
static int read_tpd_state(struct eeepc_wmi *eeepc)
275
status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval);
277
if (ACPI_FAILURE(status))
279
else if (!retval || retval == 0x00060000)
281
* if touchpad led is present, DSTS will set some bits,
282
* usually 0x00020000.
283
* 0x00060000 means that the device is not supported
287
/* Status is stored in the first bit */
291
static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
293
struct eeepc_wmi *eeepc;
295
eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led);
297
return read_tpd_state(eeepc);
300
static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc)
304
if (read_tpd_state(eeepc) < 0)
307
eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
308
if (!eeepc->led_workqueue)
310
INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
312
eeepc->tpd_led.name = "eeepc::touchpad";
313
eeepc->tpd_led.brightness_set = tpd_led_set;
314
eeepc->tpd_led.brightness_get = tpd_led_get;
315
eeepc->tpd_led.max_brightness = 1;
317
rv = led_classdev_register(&eeepc->platform_device->dev,
320
destroy_workqueue(eeepc->led_workqueue);
327
static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc)
329
if (eeepc->tpd_led.dev)
330
led_classdev_unregister(&eeepc->tpd_led);
331
if (eeepc->led_workqueue)
332
destroy_workqueue(eeepc->led_workqueue);
338
static int eeepc_rfkill_set(void *data, bool blocked)
340
int dev_id = (unsigned long)data;
341
u32 ctrl_param = !blocked;
343
return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL);
346
static void eeepc_rfkill_query(struct rfkill *rfkill, void *data)
348
int dev_id = (unsigned long)data;
352
status = eeepc_wmi_get_devstate(dev_id, &retval);
354
if (ACPI_FAILURE(status))
357
rfkill_set_sw_state(rfkill, !(retval & 0x1));
360
static const struct rfkill_ops eeepc_rfkill_ops = {
361
.set_block = eeepc_rfkill_set,
362
.query = eeepc_rfkill_query,
365
static int eeepc_new_rfkill(struct eeepc_wmi *eeepc,
366
struct rfkill **rfkill,
368
enum rfkill_type type, int dev_id)
374
status = eeepc_wmi_get_devstate(dev_id, &retval);
376
if (ACPI_FAILURE(status))
379
/* If the device is present, DSTS will always set some bits
380
* 0x00070000 - 1110000000000000000 - device supported
381
* 0x00060000 - 1100000000000000000 - not supported
382
* 0x00020000 - 0100000000000000000 - device supported
383
* 0x00010000 - 0010000000000000000 - not supported / special mode ?
385
if (!retval || retval == 0x00060000)
388
*rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
389
&eeepc_rfkill_ops, (void *)(long)dev_id);
394
rfkill_init_sw_state(*rfkill, !(retval & 0x1));
395
result = rfkill_register(*rfkill);
397
rfkill_destroy(*rfkill);
404
static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc)
406
if (eeepc->wlan_rfkill) {
407
rfkill_unregister(eeepc->wlan_rfkill);
408
rfkill_destroy(eeepc->wlan_rfkill);
409
eeepc->wlan_rfkill = NULL;
411
if (eeepc->bluetooth_rfkill) {
412
rfkill_unregister(eeepc->bluetooth_rfkill);
413
rfkill_destroy(eeepc->bluetooth_rfkill);
414
eeepc->bluetooth_rfkill = NULL;
416
if (eeepc->wwan3g_rfkill) {
417
rfkill_unregister(eeepc->wwan3g_rfkill);
418
rfkill_destroy(eeepc->wwan3g_rfkill);
419
eeepc->wwan3g_rfkill = NULL;
423
static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc)
427
result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
428
"eeepc-wlan", RFKILL_TYPE_WLAN,
429
EEEPC_WMI_DEVID_WLAN);
431
if (result && result != -ENODEV)
434
result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
435
"eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
436
EEEPC_WMI_DEVID_BLUETOOTH);
438
if (result && result != -ENODEV)
441
result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
442
"eeepc-wwan3g", RFKILL_TYPE_WWAN,
443
EEEPC_WMI_DEVID_WWAN3G);
445
if (result && result != -ENODEV)
449
if (result && result != -ENODEV)
450
eeepc_wmi_rfkill_exit(eeepc);
452
if (result == -ENODEV)
461
static int read_brightness(struct backlight_device *bd)
466
status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval);
468
if (ACPI_FAILURE(status))
471
return retval & 0xFF;
474
static int update_bl_status(struct backlight_device *bd)
480
ctrl_param = bd->props.brightness;
482
status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT,
485
if (ACPI_FAILURE(status))
491
static const struct backlight_ops eeepc_wmi_bl_ops = {
492
.get_brightness = read_brightness,
493
.update_status = update_bl_status,
496
static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code)
498
struct backlight_device *bd = eeepc->backlight_device;
499
int old = bd->props.brightness;
502
if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
503
new = code - NOTIFY_BRNUP_MIN + 1;
504
else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
505
new = code - NOTIFY_BRNDOWN_MIN;
507
bd->props.brightness = new;
508
backlight_update_status(bd);
509
backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
514
static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc)
516
struct backlight_device *bd;
517
struct backlight_properties props;
519
memset(&props, 0, sizeof(struct backlight_properties));
520
props.max_brightness = 15;
521
bd = backlight_device_register(EEEPC_WMI_FILE,
522
&eeepc->platform_device->dev, eeepc,
523
&eeepc_wmi_bl_ops, &props);
525
pr_err("Could not register backlight device\n");
529
eeepc->backlight_device = bd;
531
bd->props.brightness = read_brightness(bd);
532
bd->props.power = FB_BLANK_UNBLANK;
533
backlight_update_status(bd);
538
static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc)
540
if (eeepc->backlight_device)
541
backlight_device_unregister(eeepc->backlight_device);
543
eeepc->backlight_device = NULL;
546
static void eeepc_wmi_notify(u32 value, void *context)
548
struct eeepc_wmi *eeepc = context;
549
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
550
union acpi_object *obj;
555
status = wmi_get_event_data(value, &response);
556
if (status != AE_OK) {
557
pr_err("bad event status 0x%x\n", status);
561
obj = (union acpi_object *)response.pointer;
563
if (obj && obj->type == ACPI_TYPE_INTEGER) {
564
code = obj->integer.value;
567
if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
568
code = NOTIFY_BRNUP_MIN;
569
else if (code >= NOTIFY_BRNDOWN_MIN &&
570
code <= NOTIFY_BRNDOWN_MAX)
571
code = NOTIFY_BRNDOWN_MIN;
573
if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
574
if (!acpi_video_backlight_support())
575
eeepc_wmi_backlight_notify(eeepc, orig_code);
578
if (!sparse_keymap_report_event(eeepc->inputdev,
580
pr_info("Unknown key %x pressed\n", code);
586
static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
587
const char *buf, size_t count)
590
struct acpi_buffer input = { (acpi_size)sizeof(value), &value };
593
if (!count || sscanf(buf, "%i", &value) != 1)
595
if (value < 0 || value > 2)
598
status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID,
599
1, EEEPC_WMI_METHODID_CFVS, &input, NULL);
601
if (ACPI_FAILURE(status))
607
static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
609
static struct attribute *platform_attributes[] = {
610
&dev_attr_cpufv.attr,
614
static struct attribute_group platform_attribute_group = {
615
.attrs = platform_attributes
618
static void eeepc_wmi_sysfs_exit(struct platform_device *device)
620
sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
623
static int eeepc_wmi_sysfs_init(struct platform_device *device)
625
return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
631
static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc)
635
eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1);
636
if (!eeepc->platform_device)
638
platform_set_drvdata(eeepc->platform_device, eeepc);
640
err = platform_device_add(eeepc->platform_device);
642
goto fail_platform_device;
644
err = eeepc_wmi_sysfs_init(eeepc->platform_device);
650
platform_device_del(eeepc->platform_device);
651
fail_platform_device:
652
platform_device_put(eeepc->platform_device);
656
static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc)
658
eeepc_wmi_sysfs_exit(eeepc->platform_device);
659
platform_device_unregister(eeepc->platform_device);
665
struct eeepc_wmi_debugfs_node {
666
struct eeepc_wmi *eeepc;
668
int (*show)(struct seq_file *m, void *data);
671
static int show_dsts(struct seq_file *m, void *data)
673
struct eeepc_wmi *eeepc = m->private;
677
status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval);
679
if (ACPI_FAILURE(status))
682
seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval);
687
static int show_devs(struct seq_file *m, void *data)
689
struct eeepc_wmi *eeepc = m->private;
693
status = eeepc_wmi_set_devstate(eeepc->debug.dev_id,
694
eeepc->debug.ctrl_param, &retval);
695
if (ACPI_FAILURE(status))
698
seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id,
699
eeepc->debug.ctrl_param, retval);
704
static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = {
705
{ NULL, "devs", show_devs },
706
{ NULL, "dsts", show_dsts },
709
static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file)
711
struct eeepc_wmi_debugfs_node *node = inode->i_private;
713
return single_open(file, node->show, node->eeepc);
716
static const struct file_operations eeepc_wmi_debugfs_io_ops = {
717
.owner = THIS_MODULE,
718
.open = eeepc_wmi_debugfs_open,
721
.release = single_release,
724
static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc)
726
debugfs_remove_recursive(eeepc->debug.root);
729
static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc)
734
eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL);
735
if (!eeepc->debug.root) {
736
pr_err("failed to create debugfs directory");
740
dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR,
741
eeepc->debug.root, &eeepc->debug.dev_id);
745
dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR,
746
eeepc->debug.root, &eeepc->debug.ctrl_param);
750
for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) {
751
struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i];
754
dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO,
755
eeepc->debug.root, node,
756
&eeepc_wmi_debugfs_io_ops);
758
pr_err("failed to create debug file: %s\n", node->name);
766
eeepc_wmi_debugfs_exit(eeepc);
773
static struct platform_device * __init eeepc_wmi_add(void)
775
struct eeepc_wmi *eeepc;
779
eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL);
781
return ERR_PTR(-ENOMEM);
784
* Register the platform device first. It is used as a parent for the
787
err = eeepc_wmi_platform_init(eeepc);
791
err = eeepc_wmi_input_init(eeepc);
795
err = eeepc_wmi_led_init(eeepc);
799
err = eeepc_wmi_rfkill_init(eeepc);
803
if (!acpi_video_backlight_support()) {
804
err = eeepc_wmi_backlight_init(eeepc);
808
pr_info("Backlight controlled by ACPI video driver\n");
810
status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID,
811
eeepc_wmi_notify, eeepc);
812
if (ACPI_FAILURE(status)) {
813
pr_err("Unable to register notify handler - %d\n",
816
goto fail_wmi_handler;
819
err = eeepc_wmi_debugfs_init(eeepc);
823
return eeepc->platform_device;
826
wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
828
eeepc_wmi_backlight_exit(eeepc);
830
eeepc_wmi_rfkill_exit(eeepc);
832
eeepc_wmi_led_exit(eeepc);
834
eeepc_wmi_input_exit(eeepc);
836
eeepc_wmi_platform_exit(eeepc);
842
static int eeepc_wmi_remove(struct platform_device *device)
844
struct eeepc_wmi *eeepc;
846
eeepc = platform_get_drvdata(device);
847
wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID);
848
eeepc_wmi_backlight_exit(eeepc);
849
eeepc_wmi_input_exit(eeepc);
850
eeepc_wmi_led_exit(eeepc);
851
eeepc_wmi_rfkill_exit(eeepc);
852
eeepc_wmi_debugfs_exit(eeepc);
853
eeepc_wmi_platform_exit(eeepc);
859
static struct platform_driver platform_driver = {
861
.name = EEEPC_WMI_FILE,
862
.owner = THIS_MODULE,
866
static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level,
867
void *context, void **retval)
869
pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID);
870
*(bool *)context = true;
871
return AE_CTRL_TERMINATE;
874
static int __init eeepc_wmi_check_atkd(void)
879
status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device,
882
if (ACPI_FAILURE(status) || !found)
887
static int __init eeepc_wmi_init(void)
891
if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) ||
892
!wmi_has_guid(EEEPC_WMI_MGMT_GUID)) {
893
pr_warning("No known WMI GUID found\n");
897
if (eeepc_wmi_check_atkd()) {
898
pr_warning("WMI device present, but legacy ATKD device is also "
899
"present and enabled.");
900
pr_warning("You probably booted with acpi_osi=\"Linux\" or "
901
"acpi_osi=\"!Windows 2009\"");
902
pr_warning("Can't load eeepc-wmi, use default acpi_osi "
903
"(preferred) or eeepc-laptop");
907
platform_device = eeepc_wmi_add();
908
if (IS_ERR(platform_device)) {
909
err = PTR_ERR(platform_device);
913
err = platform_driver_register(&platform_driver);
915
pr_warning("Unable to register platform driver\n");
916
goto fail_platform_driver;
921
fail_platform_driver:
922
eeepc_wmi_remove(platform_device);
927
static void __exit eeepc_wmi_exit(void)
929
eeepc_wmi_remove(platform_device);
930
platform_driver_unregister(&platform_driver);
933
module_init(eeepc_wmi_init);
934
module_exit(eeepc_wmi_exit);