]> git.ipfire.org Git - people/arne_f/kernel.git/blame - drivers/platform/x86/acer-wmi.c
sony-laptop:irq: Remove IRQF_DISABLED
[people/arne_f/kernel.git] / drivers / platform / x86 / acer-wmi.c
CommitLineData
745a5d21
CC
1/*
2 * Acer WMI Laptop Extras
3 *
4f0175dc 4 * Copyright (C) 2007-2009 Carlos Corbacho <carlos@strangeworlds.co.uk>
745a5d21
CC
5 *
6 * Based on acer_acpi:
7 * Copyright (C) 2005-2007 E.M. Smith
8 * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
cae15702
LCY
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
745a5d21
CC
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/dmi.h>
f2b585b4 32#include <linux/fb.h>
745a5d21
CC
33#include <linux/backlight.h>
34#include <linux/leds.h>
35#include <linux/platform_device.h>
36#include <linux/acpi.h>
37#include <linux/i8042.h>
0606e1ab
CC
38#include <linux/rfkill.h>
39#include <linux/workqueue.h>
81143522 40#include <linux/debugfs.h>
5a0e3ad6 41#include <linux/slab.h>
3fdca87d
LCY
42#include <linux/input.h>
43#include <linux/input/sparse-keymap.h>
745a5d21
CC
44
45#include <acpi/acpi_drivers.h>
46
47MODULE_AUTHOR("Carlos Corbacho");
48MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
49MODULE_LICENSE("GPL");
50
745a5d21
CC
51/*
52 * Magic Number
53 * Meaning is unknown - this number is required for writing to ACPI for AMW0
54 * (it's also used in acerhk when directly accessing the BIOS)
55 */
56#define ACER_AMW0_WRITE 0x9610
57
58/*
59 * Bit masks for the AMW0 interface
60 */
61#define ACER_AMW0_WIRELESS_MASK 0x35
62#define ACER_AMW0_BLUETOOTH_MASK 0x34
63#define ACER_AMW0_MAILLED_MASK 0x31
64
65/*
66 * Method IDs for WMID interface
67 */
68#define ACER_WMID_GET_WIRELESS_METHODID 1
69#define ACER_WMID_GET_BLUETOOTH_METHODID 2
70#define ACER_WMID_GET_BRIGHTNESS_METHODID 3
71#define ACER_WMID_SET_WIRELESS_METHODID 4
72#define ACER_WMID_SET_BLUETOOTH_METHODID 5
73#define ACER_WMID_SET_BRIGHTNESS_METHODID 6
74#define ACER_WMID_GET_THREEG_METHODID 10
75#define ACER_WMID_SET_THREEG_METHODID 11
76
77/*
78 * Acer ACPI method GUIDs
79 */
80#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
5753dd53 81#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
bbb70607 82#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
298f19b2 83#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A"
b3c9092b 84#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
745a5d21 85
3fdca87d
LCY
86/*
87 * Acer ACPI event GUIDs
88 */
89#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
90
745a5d21 91MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
08a0799d 92MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
3fdca87d
LCY
93MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
94
95enum acer_wmi_event_ids {
96 WMID_HOTKEY_EVENT = 0x1,
97};
98
99static const struct key_entry acer_wmi_keymap[] = {
100 {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
8ae68de1 101 {KE_KEY, 0x03, {KEY_WLAN} }, /* WiFi */
1a04d8ff 102 {KE_KEY, 0x04, {KEY_WLAN} }, /* WiFi */
3fdca87d
LCY
103 {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */
104 {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */
105 {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
106 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
107 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
8ae68de1
MF
108 {KE_IGNORE, 0x41, {KEY_MUTE} },
109 {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
110 {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
111 {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
112 {KE_IGNORE, 0x45, {KEY_STOP} },
113 {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
114 {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
115 {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
116 {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
117 {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
3fdca87d 118 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
8ae68de1 119 {KE_IGNORE, 0x81, {KEY_SLEEP} },
8941178e 120 {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */
8ae68de1 121 {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
3fdca87d
LCY
122 {KE_END, 0}
123};
124
125static struct input_dev *acer_wmi_input_dev;
126
127struct event_return_value {
128 u8 function;
129 u8 key_num;
130 u16 device_state;
131 u32 reserved;
132} __attribute__((packed));
745a5d21 133
b3c9092b
LCY
134/*
135 * GUID3 Get Device Status device flags
136 */
6c3df88f 137#define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */
b3c9092b 138#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */
6d88ff0f 139#define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */
6c3df88f 140#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */
b3c9092b 141
59ccf2f3
FLCY
142struct lm_input_params {
143 u8 function_num; /* Function Number */
144 u16 commun_devices; /* Communication type devices default status */
145 u16 devices; /* Other type devices default status */
146 u8 lm_status; /* Launch Manager Status */
147 u16 reserved;
148} __attribute__((packed));
149
150struct lm_return_value {
151 u8 error_code; /* Error Code */
152 u8 ec_return_value; /* EC Return Value */
153 u16 reserved;
154} __attribute__((packed));
155
b3c9092b
LCY
156struct wmid3_gds_input_param { /* Get Device Status input parameter */
157 u8 function_num; /* Function Number */
158 u8 hotkey_number; /* Hotkey Number */
159 u16 devices; /* Get Device */
160} __attribute__((packed));
161
162struct wmid3_gds_return_value { /* Get Device Status return value*/
163 u8 error_code; /* Error Code */
164 u8 ec_return_value; /* EC Return Value */
165 u16 devices; /* Current Device Status */
166 u32 reserved;
167} __attribute__((packed));
168
6c3df88f
LCY
169struct hotkey_function_type_aa {
170 u8 type;
171 u8 length;
172 u16 handle;
173 u16 commun_func_bitmap;
174} __attribute__((packed));
175
745a5d21
CC
176/*
177 * Interface capability flags
178 */
179#define ACER_CAP_MAILLED (1<<0)
180#define ACER_CAP_WIRELESS (1<<1)
181#define ACER_CAP_BLUETOOTH (1<<2)
182#define ACER_CAP_BRIGHTNESS (1<<3)
183#define ACER_CAP_THREEG (1<<4)
184#define ACER_CAP_ANY (0xFFFFFFFF)
185
186/*
187 * Interface type flags
188 */
189enum interface_flags {
190 ACER_AMW0,
191 ACER_AMW0_V2,
192 ACER_WMID,
193};
194
195#define ACER_DEFAULT_WIRELESS 0
196#define ACER_DEFAULT_BLUETOOTH 0
197#define ACER_DEFAULT_MAILLED 0
198#define ACER_DEFAULT_THREEG 0
199
200static int max_brightness = 0xF;
201
745a5d21
CC
202static int mailled = -1;
203static int brightness = -1;
204static int threeg = -1;
205static int force_series;
59ccf2f3 206static bool ec_raw_mode;
6c3df88f 207static bool has_type_aa;
745a5d21
CC
208
209module_param(mailled, int, 0444);
745a5d21
CC
210module_param(brightness, int, 0444);
211module_param(threeg, int, 0444);
212module_param(force_series, int, 0444);
59ccf2f3 213module_param(ec_raw_mode, bool, 0444);
745a5d21
CC
214MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
215MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
216MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
217MODULE_PARM_DESC(force_series, "Force a different laptop series");
59ccf2f3 218MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
745a5d21
CC
219
220struct acer_data {
221 int mailled;
745a5d21
CC
222 int threeg;
223 int brightness;
224};
225
81143522
CC
226struct acer_debug {
227 struct dentry *root;
228 struct dentry *devices;
229 u32 wmid_devices;
230};
231
0606e1ab
CC
232static struct rfkill *wireless_rfkill;
233static struct rfkill *bluetooth_rfkill;
b3c9092b 234static struct rfkill *threeg_rfkill;
8215af01 235static bool rfkill_inited;
0606e1ab 236
745a5d21
CC
237/* Each low-level interface must define at least some of the following */
238struct wmi_interface {
239 /* The WMI device type */
240 u32 type;
241
242 /* The capabilities this interface provides */
243 u32 capability;
244
245 /* Private data for the current interface */
246 struct acer_data data;
81143522
CC
247
248 /* debugfs entries associated with this interface */
249 struct acer_debug debug;
745a5d21
CC
250};
251
252/* The static interface pointer, points to the currently detected interface */
253static struct wmi_interface *interface;
254
255/*
256 * Embedded Controller quirks
257 * Some laptops require us to directly access the EC to either enable or query
258 * features that are not available through WMI.
259 */
260
261struct quirk_entry {
262 u8 wireless;
263 u8 mailled;
9991d9f2 264 s8 brightness;
745a5d21
CC
265 u8 bluetooth;
266};
267
268static struct quirk_entry *quirks;
269
270static void set_quirks(void)
271{
83097aca
AV
272 if (!interface)
273 return;
274
745a5d21
CC
275 if (quirks->mailled)
276 interface->capability |= ACER_CAP_MAILLED;
277
278 if (quirks->brightness)
279 interface->capability |= ACER_CAP_BRIGHTNESS;
280}
281
282static int dmi_matched(const struct dmi_system_id *dmi)
283{
284 quirks = dmi->driver_data;
d53bf0f3 285 return 1;
745a5d21
CC
286}
287
288static struct quirk_entry quirk_unknown = {
289};
290
9991d9f2
CC
291static struct quirk_entry quirk_acer_aspire_1520 = {
292 .brightness = -1,
293};
294
745a5d21
CC
295static struct quirk_entry quirk_acer_travelmate_2490 = {
296 .mailled = 1,
297};
298
299/* This AMW0 laptop has no bluetooth */
300static struct quirk_entry quirk_medion_md_98300 = {
301 .wireless = 1,
302};
303
6f061ab5
CC
304static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
305 .wireless = 2,
306};
307
15b956a0
LCY
308static struct quirk_entry quirk_lenovo_ideapad_s205 = {
309 .wireless = 3,
310};
311
a74dd5fd
CC
312/* The Aspire One has a dummy ACPI-WMI interface - disable it */
313static struct dmi_system_id __devinitdata acer_blacklist[] = {
314 {
315 .ident = "Acer Aspire One (SSD)",
316 .matches = {
317 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
318 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
319 },
320 },
321 {
322 .ident = "Acer Aspire One (HDD)",
323 .matches = {
324 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
325 DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
326 },
327 },
328 {}
329};
330
745a5d21 331static struct dmi_system_id acer_quirks[] = {
9991d9f2
CC
332 {
333 .callback = dmi_matched,
334 .ident = "Acer Aspire 1360",
335 .matches = {
336 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
337 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
338 },
339 .driver_data = &quirk_acer_aspire_1520,
340 },
341 {
342 .callback = dmi_matched,
343 .ident = "Acer Aspire 1520",
344 .matches = {
345 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
346 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
347 },
348 .driver_data = &quirk_acer_aspire_1520,
349 },
745a5d21
CC
350 {
351 .callback = dmi_matched,
352 .ident = "Acer Aspire 3100",
353 .matches = {
354 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
355 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
356 },
357 .driver_data = &quirk_acer_travelmate_2490,
358 },
ed9cfe98
CC
359 {
360 .callback = dmi_matched,
361 .ident = "Acer Aspire 3610",
362 .matches = {
363 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
364 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
365 },
366 .driver_data = &quirk_acer_travelmate_2490,
367 },
745a5d21
CC
368 {
369 .callback = dmi_matched,
370 .ident = "Acer Aspire 5100",
371 .matches = {
372 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
373 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
374 },
375 .driver_data = &quirk_acer_travelmate_2490,
376 },
ed9cfe98
CC
377 {
378 .callback = dmi_matched,
379 .ident = "Acer Aspire 5610",
380 .matches = {
381 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
382 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
383 },
384 .driver_data = &quirk_acer_travelmate_2490,
385 },
745a5d21
CC
386 {
387 .callback = dmi_matched,
388 .ident = "Acer Aspire 5630",
389 .matches = {
390 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
391 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
392 },
393 .driver_data = &quirk_acer_travelmate_2490,
394 },
395 {
396 .callback = dmi_matched,
397 .ident = "Acer Aspire 5650",
398 .matches = {
399 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
400 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
401 },
402 .driver_data = &quirk_acer_travelmate_2490,
403 },
404 {
405 .callback = dmi_matched,
406 .ident = "Acer Aspire 5680",
407 .matches = {
408 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
409 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
410 },
411 .driver_data = &quirk_acer_travelmate_2490,
412 },
413 {
414 .callback = dmi_matched,
415 .ident = "Acer Aspire 9110",
416 .matches = {
417 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
418 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
419 },
420 .driver_data = &quirk_acer_travelmate_2490,
421 },
422 {
423 .callback = dmi_matched,
424 .ident = "Acer TravelMate 2490",
425 .matches = {
426 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
427 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
428 },
429 .driver_data = &quirk_acer_travelmate_2490,
430 },
262ee35b
CC
431 {
432 .callback = dmi_matched,
433 .ident = "Acer TravelMate 4200",
434 .matches = {
435 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
436 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
437 },
438 .driver_data = &quirk_acer_travelmate_2490,
439 },
6f061ab5
CC
440 {
441 .callback = dmi_matched,
442 .ident = "Fujitsu Siemens Amilo Li 1718",
443 .matches = {
444 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
445 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
446 },
447 .driver_data = &quirk_fujitsu_amilo_li_1718,
448 },
745a5d21
CC
449 {
450 .callback = dmi_matched,
451 .ident = "Medion MD 98300",
452 .matches = {
453 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
454 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
455 },
456 .driver_data = &quirk_medion_md_98300,
457 },
15b956a0
LCY
458 {
459 .callback = dmi_matched,
460 .ident = "Lenovo Ideapad S205",
461 .matches = {
462 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
463 DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
464 },
465 .driver_data = &quirk_lenovo_ideapad_s205,
466 },
be3128b1
SF
467 {
468 .callback = dmi_matched,
469 .ident = "Lenovo 3000 N200",
470 .matches = {
471 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
472 DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
473 },
474 .driver_data = &quirk_fujitsu_amilo_li_1718,
475 },
745a5d21
CC
476 {}
477};
478
479/* Find which quirks are needed for a particular vendor/ model pair */
480static void find_quirks(void)
481{
482 if (!force_series) {
483 dmi_check_system(acer_quirks);
484 } else if (force_series == 2490) {
485 quirks = &quirk_acer_travelmate_2490;
486 }
487
488 if (quirks == NULL)
489 quirks = &quirk_unknown;
490
491 set_quirks();
492}
493
494/*
495 * General interface convenience methods
496 */
497
498static bool has_cap(u32 cap)
499{
500 if ((interface->capability & cap) != 0)
501 return 1;
502
503 return 0;
504}
505
506/*
507 * AMW0 (V1) interface
508 */
509struct wmab_args {
510 u32 eax;
511 u32 ebx;
512 u32 ecx;
513 u32 edx;
514};
515
516struct wmab_ret {
517 u32 eax;
518 u32 ebx;
519 u32 ecx;
520 u32 edx;
521 u32 eex;
522};
523
524static acpi_status wmab_execute(struct wmab_args *regbuf,
525struct acpi_buffer *result)
526{
527 struct acpi_buffer input;
528 acpi_status status;
529 input.length = sizeof(struct wmab_args);
530 input.pointer = (u8 *)regbuf;
531
532 status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
533
534 return status;
535}
536
537static acpi_status AMW0_get_u32(u32 *value, u32 cap,
538struct wmi_interface *iface)
539{
540 int err;
541 u8 result;
542
543 switch (cap) {
544 case ACER_CAP_MAILLED:
545 switch (quirks->mailled) {
546 default:
547 err = ec_read(0xA, &result);
548 if (err)
549 return AE_ERROR;
550 *value = (result >> 7) & 0x1;
551 return AE_OK;
552 }
553 break;
554 case ACER_CAP_WIRELESS:
555 switch (quirks->wireless) {
556 case 1:
557 err = ec_read(0x7B, &result);
558 if (err)
559 return AE_ERROR;
560 *value = result & 0x1;
561 return AE_OK;
6f061ab5
CC
562 case 2:
563 err = ec_read(0x71, &result);
564 if (err)
565 return AE_ERROR;
566 *value = result & 0x1;
567 return AE_OK;
15b956a0
LCY
568 case 3:
569 err = ec_read(0x78, &result);
570 if (err)
571 return AE_ERROR;
572 *value = result & 0x1;
573 return AE_OK;
745a5d21
CC
574 default:
575 err = ec_read(0xA, &result);
576 if (err)
577 return AE_ERROR;
578 *value = (result >> 2) & 0x1;
579 return AE_OK;
580 }
581 break;
582 case ACER_CAP_BLUETOOTH:
583 switch (quirks->bluetooth) {
584 default:
585 err = ec_read(0xA, &result);
586 if (err)
587 return AE_ERROR;
588 *value = (result >> 4) & 0x1;
589 return AE_OK;
590 }
591 break;
592 case ACER_CAP_BRIGHTNESS:
593 switch (quirks->brightness) {
594 default:
595 err = ec_read(0x83, &result);
596 if (err)
597 return AE_ERROR;
598 *value = result;
599 return AE_OK;
600 }
601 break;
602 default:
08237974 603 return AE_ERROR;
745a5d21
CC
604 }
605 return AE_OK;
606}
607
608static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
609{
610 struct wmab_args args;
611
612 args.eax = ACER_AMW0_WRITE;
613 args.ebx = value ? (1<<8) : 0;
614 args.ecx = args.edx = 0;
615
616 switch (cap) {
617 case ACER_CAP_MAILLED:
618 if (value > 1)
619 return AE_BAD_PARAMETER;
620 args.ebx |= ACER_AMW0_MAILLED_MASK;
621 break;
622 case ACER_CAP_WIRELESS:
623 if (value > 1)
624 return AE_BAD_PARAMETER;
625 args.ebx |= ACER_AMW0_WIRELESS_MASK;
626 break;
627 case ACER_CAP_BLUETOOTH:
628 if (value > 1)
629 return AE_BAD_PARAMETER;
630 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
631 break;
632 case ACER_CAP_BRIGHTNESS:
633 if (value > max_brightness)
634 return AE_BAD_PARAMETER;
635 switch (quirks->brightness) {
745a5d21 636 default:
4609d029
CC
637 return ec_write(0x83, value);
638 break;
745a5d21
CC
639 }
640 default:
08237974 641 return AE_ERROR;
745a5d21
CC
642 }
643
644 /* Actually do the set */
645 return wmab_execute(&args, NULL);
646}
647
648static acpi_status AMW0_find_mailled(void)
649{
650 struct wmab_args args;
651 struct wmab_ret ret;
652 acpi_status status = AE_OK;
653 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
654 union acpi_object *obj;
655
656 args.eax = 0x86;
657 args.ebx = args.ecx = args.edx = 0;
658
659 status = wmab_execute(&args, &out);
660 if (ACPI_FAILURE(status))
661 return status;
662
663 obj = (union acpi_object *) out.pointer;
664 if (obj && obj->type == ACPI_TYPE_BUFFER &&
665 obj->buffer.length == sizeof(struct wmab_ret)) {
666 ret = *((struct wmab_ret *) obj->buffer.pointer);
667 } else {
7677fbdf 668 kfree(out.pointer);
745a5d21
CC
669 return AE_ERROR;
670 }
671
672 if (ret.eex & 0x1)
673 interface->capability |= ACER_CAP_MAILLED;
674
675 kfree(out.pointer);
676
677 return AE_OK;
678}
679
680static acpi_status AMW0_set_capabilities(void)
681{
682 struct wmab_args args;
683 struct wmab_ret ret;
7677fbdf 684 acpi_status status;
745a5d21
CC
685 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
686 union acpi_object *obj;
687
5753dd53
CC
688 /*
689 * On laptops with this strange GUID (non Acer), normal probing doesn't
690 * work.
691 */
692 if (wmi_has_guid(AMW0_GUID2)) {
693 interface->capability |= ACER_CAP_WIRELESS;
694 return AE_OK;
695 }
696
745a5d21
CC
697 args.eax = ACER_AMW0_WRITE;
698 args.ecx = args.edx = 0;
699
700 args.ebx = 0xa2 << 8;
701 args.ebx |= ACER_AMW0_WIRELESS_MASK;
702
703 status = wmab_execute(&args, &out);
704 if (ACPI_FAILURE(status))
705 return status;
706
7677fbdf 707 obj = out.pointer;
745a5d21
CC
708 if (obj && obj->type == ACPI_TYPE_BUFFER &&
709 obj->buffer.length == sizeof(struct wmab_ret)) {
710 ret = *((struct wmab_ret *) obj->buffer.pointer);
711 } else {
7677fbdf
AL
712 status = AE_ERROR;
713 goto out;
745a5d21
CC
714 }
715
716 if (ret.eax & 0x1)
717 interface->capability |= ACER_CAP_WIRELESS;
718
719 args.ebx = 2 << 8;
720 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
721
7677fbdf
AL
722 /*
723 * It's ok to use existing buffer for next wmab_execute call.
724 * But we need to kfree(out.pointer) if next wmab_execute fail.
725 */
745a5d21
CC
726 status = wmab_execute(&args, &out);
727 if (ACPI_FAILURE(status))
7677fbdf 728 goto out;
745a5d21
CC
729
730 obj = (union acpi_object *) out.pointer;
731 if (obj && obj->type == ACPI_TYPE_BUFFER
732 && obj->buffer.length == sizeof(struct wmab_ret)) {
733 ret = *((struct wmab_ret *) obj->buffer.pointer);
734 } else {
7677fbdf
AL
735 status = AE_ERROR;
736 goto out;
745a5d21
CC
737 }
738
739 if (ret.eax & 0x1)
740 interface->capability |= ACER_CAP_BLUETOOTH;
741
745a5d21
CC
742 /*
743 * This appears to be safe to enable, since all Wistron based laptops
744 * appear to use the same EC register for brightness, even if they
745 * differ for wireless, etc
746 */
9991d9f2
CC
747 if (quirks->brightness >= 0)
748 interface->capability |= ACER_CAP_BRIGHTNESS;
745a5d21 749
7677fbdf
AL
750 status = AE_OK;
751out:
752 kfree(out.pointer);
753 return status;
745a5d21
CC
754}
755
756static struct wmi_interface AMW0_interface = {
757 .type = ACER_AMW0,
758};
759
760static struct wmi_interface AMW0_V2_interface = {
761 .type = ACER_AMW0_V2,
762};
763
764/*
765 * New interface (The WMID interface)
766 */
767static acpi_status
768WMI_execute_u32(u32 method_id, u32 in, u32 *out)
769{
770 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
771 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
772 union acpi_object *obj;
773 u32 tmp;
774 acpi_status status;
775
776 status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
777
778 if (ACPI_FAILURE(status))
779 return status;
780
781 obj = (union acpi_object *) result.pointer;
782 if (obj && obj->type == ACPI_TYPE_BUFFER &&
ab6a9316
LCY
783 (obj->buffer.length == sizeof(u32) ||
784 obj->buffer.length == sizeof(u64))) {
745a5d21 785 tmp = *((u32 *) obj->buffer.pointer);
987dfbaa
LCY
786 } else if (obj->type == ACPI_TYPE_INTEGER) {
787 tmp = (u32) obj->integer.value;
745a5d21
CC
788 } else {
789 tmp = 0;
790 }
791
792 if (out)
793 *out = tmp;
794
795 kfree(result.pointer);
796
797 return status;
798}
799
800static acpi_status WMID_get_u32(u32 *value, u32 cap,
801struct wmi_interface *iface)
802{
803 acpi_status status;
804 u8 tmp;
805 u32 result, method_id = 0;
806
807 switch (cap) {
808 case ACER_CAP_WIRELESS:
809 method_id = ACER_WMID_GET_WIRELESS_METHODID;
810 break;
811 case ACER_CAP_BLUETOOTH:
812 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
813 break;
814 case ACER_CAP_BRIGHTNESS:
815 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
816 break;
817 case ACER_CAP_THREEG:
818 method_id = ACER_WMID_GET_THREEG_METHODID;
819 break;
820 case ACER_CAP_MAILLED:
821 if (quirks->mailled == 1) {
822 ec_read(0x9f, &tmp);
823 *value = tmp & 0x1;
824 return 0;
825 }
826 default:
08237974 827 return AE_ERROR;
745a5d21
CC
828 }
829 status = WMI_execute_u32(method_id, 0, &result);
830
831 if (ACPI_SUCCESS(status))
832 *value = (u8)result;
833
834 return status;
835}
836
837static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
838{
839 u32 method_id = 0;
840 char param;
841
842 switch (cap) {
843 case ACER_CAP_BRIGHTNESS:
844 if (value > max_brightness)
845 return AE_BAD_PARAMETER;
846 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
847 break;
848 case ACER_CAP_WIRELESS:
849 if (value > 1)
850 return AE_BAD_PARAMETER;
851 method_id = ACER_WMID_SET_WIRELESS_METHODID;
852 break;
853 case ACER_CAP_BLUETOOTH:
854 if (value > 1)
855 return AE_BAD_PARAMETER;
856 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
857 break;
858 case ACER_CAP_THREEG:
859 if (value > 1)
860 return AE_BAD_PARAMETER;
861 method_id = ACER_WMID_SET_THREEG_METHODID;
862 break;
863 case ACER_CAP_MAILLED:
864 if (value > 1)
865 return AE_BAD_PARAMETER;
866 if (quirks->mailled == 1) {
867 param = value ? 0x92 : 0x93;
181d683d 868 i8042_lock_chip();
745a5d21 869 i8042_command(&param, 0x1059);
181d683d 870 i8042_unlock_chip();
745a5d21
CC
871 return 0;
872 }
873 break;
874 default:
08237974 875 return AE_ERROR;
745a5d21
CC
876 }
877 return WMI_execute_u32(method_id, (u32)value, NULL);
878}
879
6c3df88f
LCY
880static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
881{
882 struct hotkey_function_type_aa *type_aa;
883
884 /* We are looking for OEM-specific Type AAh */
885 if (header->type != 0xAA)
886 return;
887
888 has_type_aa = true;
889 type_aa = (struct hotkey_function_type_aa *) header;
890
cae15702 891 pr_info("Function bitmap for Communication Button: 0x%x\n",
6c3df88f
LCY
892 type_aa->commun_func_bitmap);
893
894 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
895 interface->capability |= ACER_CAP_WIRELESS;
896 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
897 interface->capability |= ACER_CAP_THREEG;
898 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
899 interface->capability |= ACER_CAP_BLUETOOTH;
900}
901
745a5d21
CC
902static acpi_status WMID_set_capabilities(void)
903{
904 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
905 union acpi_object *obj;
906 acpi_status status;
907 u32 devices;
908
909 status = wmi_query_block(WMID_GUID2, 1, &out);
910 if (ACPI_FAILURE(status))
911 return status;
912
913 obj = (union acpi_object *) out.pointer;
914 if (obj && obj->type == ACPI_TYPE_BUFFER &&
ab6a9316
LCY
915 (obj->buffer.length == sizeof(u32) ||
916 obj->buffer.length == sizeof(u64))) {
745a5d21 917 devices = *((u32 *) obj->buffer.pointer);
987dfbaa
LCY
918 } else if (obj->type == ACPI_TYPE_INTEGER) {
919 devices = (u32) obj->integer.value;
745a5d21 920 } else {
66904863 921 kfree(out.pointer);
745a5d21
CC
922 return AE_ERROR;
923 }
924
6c3df88f
LCY
925 dmi_walk(type_aa_dmi_decode, NULL);
926 if (!has_type_aa) {
927 interface->capability |= ACER_CAP_WIRELESS;
a8d1a266
LCY
928 if (devices & 0x40)
929 interface->capability |= ACER_CAP_THREEG;
6c3df88f
LCY
930 if (devices & 0x10)
931 interface->capability |= ACER_CAP_BLUETOOTH;
932 }
745a5d21
CC
933
934 /* WMID always provides brightness methods */
935 interface->capability |= ACER_CAP_BRIGHTNESS;
936
745a5d21
CC
937 if (!(devices & 0x20))
938 max_brightness = 0x9;
939
66904863 940 kfree(out.pointer);
745a5d21
CC
941 return status;
942}
943
944static struct wmi_interface wmid_interface = {
945 .type = ACER_WMID,
946};
947
948/*
949 * Generic Device (interface-independent)
950 */
951
952static acpi_status get_u32(u32 *value, u32 cap)
953{
08237974 954 acpi_status status = AE_ERROR;
745a5d21
CC
955
956 switch (interface->type) {
957 case ACER_AMW0:
958 status = AMW0_get_u32(value, cap, interface);
959 break;
960 case ACER_AMW0_V2:
961 if (cap == ACER_CAP_MAILLED) {
962 status = AMW0_get_u32(value, cap, interface);
963 break;
964 }
965 case ACER_WMID:
966 status = WMID_get_u32(value, cap, interface);
967 break;
968 }
969
970 return status;
971}
972
973static acpi_status set_u32(u32 value, u32 cap)
974{
5c742b45
CC
975 acpi_status status;
976
745a5d21
CC
977 if (interface->capability & cap) {
978 switch (interface->type) {
979 case ACER_AMW0:
980 return AMW0_set_u32(value, cap, interface);
981 case ACER_AMW0_V2:
5c742b45
CC
982 if (cap == ACER_CAP_MAILLED)
983 return AMW0_set_u32(value, cap, interface);
984
985 /*
986 * On some models, some WMID methods don't toggle
987 * properly. For those cases, we want to run the AMW0
988 * method afterwards to be certain we've really toggled
989 * the device state.
990 */
991 if (cap == ACER_CAP_WIRELESS ||
992 cap == ACER_CAP_BLUETOOTH) {
993 status = WMID_set_u32(value, cap, interface);
994 if (ACPI_FAILURE(status))
995 return status;
996
997 return AMW0_set_u32(value, cap, interface);
998 }
745a5d21
CC
999 case ACER_WMID:
1000 return WMID_set_u32(value, cap, interface);
1001 default:
1002 return AE_BAD_PARAMETER;
1003 }
1004 }
1005 return AE_BAD_PARAMETER;
1006}
1007
1008static void __init acer_commandline_init(void)
1009{
1010 /*
1011 * These will all fail silently if the value given is invalid, or the
1012 * capability isn't available on the given interface
1013 */
c2647b5e
LCY
1014 if (mailled >= 0)
1015 set_u32(mailled, ACER_CAP_MAILLED);
1016 if (!has_type_aa && threeg >= 0)
6c3df88f 1017 set_u32(threeg, ACER_CAP_THREEG);
c2647b5e
LCY
1018 if (brightness >= 0)
1019 set_u32(brightness, ACER_CAP_BRIGHTNESS);
745a5d21
CC
1020}
1021
1022/*
1023 * LED device (Mail LED only, no other LEDs known yet)
1024 */
1025static void mail_led_set(struct led_classdev *led_cdev,
1026enum led_brightness value)
1027{
1028 set_u32(value, ACER_CAP_MAILLED);
1029}
1030
1031static struct led_classdev mail_led = {
343c0042 1032 .name = "acer-wmi::mail",
745a5d21
CC
1033 .brightness_set = mail_led_set,
1034};
1035
7560e385 1036static int __devinit acer_led_init(struct device *dev)
745a5d21
CC
1037{
1038 return led_classdev_register(dev, &mail_led);
1039}
1040
1041static void acer_led_exit(void)
1042{
9a0b74fd 1043 set_u32(LED_OFF, ACER_CAP_MAILLED);
745a5d21
CC
1044 led_classdev_unregister(&mail_led);
1045}
1046
1047/*
1048 * Backlight device
1049 */
1050static struct backlight_device *acer_backlight_device;
1051
1052static int read_brightness(struct backlight_device *bd)
1053{
1054 u32 value;
1055 get_u32(&value, ACER_CAP_BRIGHTNESS);
1056 return value;
1057}
1058
1059static int update_bl_status(struct backlight_device *bd)
1060{
f2b585b4
CC
1061 int intensity = bd->props.brightness;
1062
1063 if (bd->props.power != FB_BLANK_UNBLANK)
1064 intensity = 0;
1065 if (bd->props.fb_blank != FB_BLANK_UNBLANK)
1066 intensity = 0;
1067
1068 set_u32(intensity, ACER_CAP_BRIGHTNESS);
1069
745a5d21
CC
1070 return 0;
1071}
1072
acc2472e 1073static const struct backlight_ops acer_bl_ops = {
745a5d21
CC
1074 .get_brightness = read_brightness,
1075 .update_status = update_bl_status,
1076};
1077
7560e385 1078static int __devinit acer_backlight_init(struct device *dev)
745a5d21 1079{
a19a6ee6 1080 struct backlight_properties props;
745a5d21
CC
1081 struct backlight_device *bd;
1082
a19a6ee6 1083 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 1084 props.type = BACKLIGHT_PLATFORM;
a19a6ee6
MG
1085 props.max_brightness = max_brightness;
1086 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
1087 &props);
745a5d21 1088 if (IS_ERR(bd)) {
cae15702 1089 pr_err("Could not register Acer backlight device\n");
745a5d21
CC
1090 acer_backlight_device = NULL;
1091 return PTR_ERR(bd);
1092 }
1093
1094 acer_backlight_device = bd;
1095
f2b585b4 1096 bd->props.power = FB_BLANK_UNBLANK;
6f6ef82c 1097 bd->props.brightness = read_brightness(bd);
745a5d21
CC
1098 backlight_update_status(bd);
1099 return 0;
1100}
1101
7560e385 1102static void acer_backlight_exit(void)
745a5d21
CC
1103{
1104 backlight_device_unregister(acer_backlight_device);
1105}
1106
b3c9092b
LCY
1107static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1108{
1109 struct wmid3_gds_return_value return_value;
1110 acpi_status status;
1111 union acpi_object *obj;
1112 struct wmid3_gds_input_param params = {
1113 .function_num = 0x1,
1114 .hotkey_number = 0x01,
1115 .devices = device,
1116 };
1117 struct acpi_buffer input = {
1118 sizeof(struct wmid3_gds_input_param),
1119 &params
1120 };
1121 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1122
1123 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
1124 if (ACPI_FAILURE(status))
1125 return status;
1126
1127 obj = output.pointer;
1128
1129 if (!obj)
1130 return AE_ERROR;
1131 else if (obj->type != ACPI_TYPE_BUFFER) {
1132 kfree(obj);
1133 return AE_ERROR;
1134 }
1135 if (obj->buffer.length != 8) {
249c720d 1136 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
b3c9092b
LCY
1137 kfree(obj);
1138 return AE_ERROR;
1139 }
1140
1141 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1142 kfree(obj);
1143
1144 if (return_value.error_code || return_value.ec_return_value)
249c720d
JP
1145 pr_warn("Get Device Status failed: 0x%x - 0x%x\n",
1146 return_value.error_code,
b3c9092b
LCY
1147 return_value.ec_return_value);
1148 else
1149 *value = !!(return_value.devices & device);
1150
1151 return status;
1152}
1153
466449cf
LCY
1154static acpi_status get_device_status(u32 *value, u32 cap)
1155{
1156 if (wmi_has_guid(WMID_GUID3)) {
1157 u16 device;
1158
1159 switch (cap) {
1160 case ACER_CAP_WIRELESS:
1161 device = ACER_WMID3_GDS_WIRELESS;
1162 break;
1163 case ACER_CAP_BLUETOOTH:
1164 device = ACER_WMID3_GDS_BLUETOOTH;
1165 break;
1166 case ACER_CAP_THREEG:
1167 device = ACER_WMID3_GDS_THREEG;
1168 break;
1169 default:
1170 return AE_ERROR;
1171 }
1172 return wmid3_get_device_status(value, device);
1173
1174 } else {
1175 return get_u32(value, cap);
1176 }
1177}
1178
6d88ff0f
LCY
1179static acpi_status wmid3_set_device_status(u32 value, u16 device)
1180{
1181 struct wmid3_gds_return_value return_value;
1182 acpi_status status;
1183 union acpi_object *obj;
1184 u16 devices;
1185 struct wmid3_gds_input_param params = {
1186 .function_num = 0x1,
1187 .hotkey_number = 0x01,
ae821c1b
LCY
1188 .devices = ACER_WMID3_GDS_WIRELESS |
1189 ACER_WMID3_GDS_THREEG |
1190 ACER_WMID3_GDS_WIMAX |
6d88ff0f
LCY
1191 ACER_WMID3_GDS_BLUETOOTH,
1192 };
1193 struct acpi_buffer input = {
1194 sizeof(struct wmid3_gds_input_param),
1195 &params
1196 };
1197 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1198 struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
1199
1200 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
1201 if (ACPI_FAILURE(status))
1202 return status;
1203
1204 obj = output.pointer;
1205
1206 if (!obj)
1207 return AE_ERROR;
1208 else if (obj->type != ACPI_TYPE_BUFFER) {
1209 kfree(obj);
1210 return AE_ERROR;
1211 }
1212 if (obj->buffer.length != 8) {
1213 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1214 kfree(obj);
1215 return AE_ERROR;
1216 }
1217
1218 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1219 kfree(obj);
1220
1221 if (return_value.error_code || return_value.ec_return_value) {
1222 pr_warning("Get Current Device Status failed: "
1223 "0x%x - 0x%x\n", return_value.error_code,
1224 return_value.ec_return_value);
1225 return status;
1226 }
1227
1228 devices = return_value.devices;
1229 params.function_num = 0x2;
1230 params.hotkey_number = 0x01;
1231 params.devices = (value) ? (devices | device) : (devices & ~device);
1232
1233 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
1234 if (ACPI_FAILURE(status))
1235 return status;
1236
1237 obj = output2.pointer;
1238
1239 if (!obj)
1240 return AE_ERROR;
1241 else if (obj->type != ACPI_TYPE_BUFFER) {
1242 kfree(obj);
1243 return AE_ERROR;
1244 }
1245 if (obj->buffer.length != 4) {
1246 pr_warning("Unknown buffer length %d\n", obj->buffer.length);
1247 kfree(obj);
1248 return AE_ERROR;
1249 }
1250
1251 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1252 kfree(obj);
1253
1254 if (return_value.error_code || return_value.ec_return_value)
1255 pr_warning("Set Device Status failed: "
1256 "0x%x - 0x%x\n", return_value.error_code,
1257 return_value.ec_return_value);
1258
1259 return status;
1260}
1261
1262static acpi_status set_device_status(u32 value, u32 cap)
1263{
1264 if (wmi_has_guid(WMID_GUID3)) {
1265 u16 device;
1266
1267 switch (cap) {
1268 case ACER_CAP_WIRELESS:
1269 device = ACER_WMID3_GDS_WIRELESS;
1270 break;
1271 case ACER_CAP_BLUETOOTH:
1272 device = ACER_WMID3_GDS_BLUETOOTH;
1273 break;
1274 case ACER_CAP_THREEG:
1275 device = ACER_WMID3_GDS_THREEG;
1276 break;
1277 default:
1278 return AE_ERROR;
1279 }
1280 return wmid3_set_device_status(value, device);
1281
1282 } else {
1283 return set_u32(value, cap);
1284 }
1285}
1286
0606e1ab
CC
1287/*
1288 * Rfkill devices
1289 */
0606e1ab
CC
1290static void acer_rfkill_update(struct work_struct *ignored);
1291static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
1292static void acer_rfkill_update(struct work_struct *ignored)
1293{
1294 u32 state;
1295 acpi_status status;
1296
1709adab
LCY
1297 if (has_cap(ACER_CAP_WIRELESS)) {
1298 status = get_u32(&state, ACER_CAP_WIRELESS);
1299 if (ACPI_SUCCESS(status)) {
1300 if (quirks->wireless == 3)
1301 rfkill_set_hw_state(wireless_rfkill, !state);
1302 else
1303 rfkill_set_sw_state(wireless_rfkill, !state);
15b956a0
LCY
1304 }
1305 }
0606e1ab
CC
1306
1307 if (has_cap(ACER_CAP_BLUETOOTH)) {
1308 status = get_u32(&state, ACER_CAP_BLUETOOTH);
1309 if (ACPI_SUCCESS(status))
a878417c 1310 rfkill_set_sw_state(bluetooth_rfkill, !state);
0606e1ab
CC
1311 }
1312
b3c9092b
LCY
1313 if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
1314 status = wmid3_get_device_status(&state,
1315 ACER_WMID3_GDS_THREEG);
1316 if (ACPI_SUCCESS(status))
1317 rfkill_set_sw_state(threeg_rfkill, !state);
1318 }
1319
ae3a1b46 1320 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
0606e1ab
CC
1321}
1322
19d337df 1323static int acer_rfkill_set(void *data, bool blocked)
0606e1ab
CC
1324{
1325 acpi_status status;
19d337df 1326 u32 cap = (unsigned long)data;
8215af01
LCY
1327
1328 if (rfkill_inited) {
6d88ff0f 1329 status = set_device_status(!blocked, cap);
8215af01
LCY
1330 if (ACPI_FAILURE(status))
1331 return -ENODEV;
1332 }
1333
0606e1ab
CC
1334 return 0;
1335}
1336
19d337df
JB
1337static const struct rfkill_ops acer_rfkill_ops = {
1338 .set_block = acer_rfkill_set,
1339};
1340
1341static struct rfkill *acer_rfkill_register(struct device *dev,
1342 enum rfkill_type type,
1343 char *name, u32 cap)
0606e1ab
CC
1344{
1345 int err;
0606e1ab 1346 struct rfkill *rfkill_dev;
466449cf
LCY
1347 u32 state;
1348 acpi_status status;
0606e1ab 1349
19d337df
JB
1350 rfkill_dev = rfkill_alloc(name, dev, type,
1351 &acer_rfkill_ops,
1352 (void *)(unsigned long)cap);
0606e1ab
CC
1353 if (!rfkill_dev)
1354 return ERR_PTR(-ENOMEM);
0606e1ab 1355
466449cf 1356 status = get_device_status(&state, cap);
466449cf 1357
0606e1ab
CC
1358 err = rfkill_register(rfkill_dev);
1359 if (err) {
19d337df 1360 rfkill_destroy(rfkill_dev);
0606e1ab
CC
1361 return ERR_PTR(err);
1362 }
8215af01
LCY
1363
1364 if (ACPI_SUCCESS(status))
1365 rfkill_set_sw_state(rfkill_dev, !state);
1366
0606e1ab
CC
1367 return rfkill_dev;
1368}
1369
1370static int acer_rfkill_init(struct device *dev)
1371{
1709adab
LCY
1372 int err;
1373
1374 if (has_cap(ACER_CAP_WIRELESS)) {
1375 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
1376 "acer-wireless", ACER_CAP_WIRELESS);
1377 if (IS_ERR(wireless_rfkill)) {
1378 err = PTR_ERR(wireless_rfkill);
1379 goto error_wireless;
1380 }
1381 }
0606e1ab
CC
1382
1383 if (has_cap(ACER_CAP_BLUETOOTH)) {
1384 bluetooth_rfkill = acer_rfkill_register(dev,
1385 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
1386 ACER_CAP_BLUETOOTH);
1387 if (IS_ERR(bluetooth_rfkill)) {
1709adab
LCY
1388 err = PTR_ERR(bluetooth_rfkill);
1389 goto error_bluetooth;
0606e1ab
CC
1390 }
1391 }
1392
b3c9092b
LCY
1393 if (has_cap(ACER_CAP_THREEG)) {
1394 threeg_rfkill = acer_rfkill_register(dev,
1395 RFKILL_TYPE_WWAN, "acer-threeg",
1396 ACER_CAP_THREEG);
1397 if (IS_ERR(threeg_rfkill)) {
1709adab
LCY
1398 err = PTR_ERR(threeg_rfkill);
1399 goto error_threeg;
b3c9092b
LCY
1400 }
1401 }
1402
8215af01
LCY
1403 rfkill_inited = true;
1404
1709adab
LCY
1405 if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1406 has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
70a9b904
LCY
1407 schedule_delayed_work(&acer_rfkill_work,
1408 round_jiffies_relative(HZ));
0606e1ab
CC
1409
1410 return 0;
1709adab
LCY
1411
1412error_threeg:
1413 if (has_cap(ACER_CAP_BLUETOOTH)) {
1414 rfkill_unregister(bluetooth_rfkill);
1415 rfkill_destroy(bluetooth_rfkill);
1416 }
1417error_bluetooth:
1418 if (has_cap(ACER_CAP_WIRELESS)) {
1419 rfkill_unregister(wireless_rfkill);
1420 rfkill_destroy(wireless_rfkill);
1421 }
1422error_wireless:
1423 return err;
0606e1ab
CC
1424}
1425
1426static void acer_rfkill_exit(void)
1427{
1709adab
LCY
1428 if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1429 has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
70a9b904 1430 cancel_delayed_work_sync(&acer_rfkill_work);
19d337df 1431
1709adab
LCY
1432 if (has_cap(ACER_CAP_WIRELESS)) {
1433 rfkill_unregister(wireless_rfkill);
1434 rfkill_destroy(wireless_rfkill);
1435 }
19d337df 1436
0606e1ab 1437 if (has_cap(ACER_CAP_BLUETOOTH)) {
0606e1ab 1438 rfkill_unregister(bluetooth_rfkill);
19d337df 1439 rfkill_destroy(bluetooth_rfkill);
0606e1ab 1440 }
b3c9092b
LCY
1441
1442 if (has_cap(ACER_CAP_THREEG)) {
1443 rfkill_unregister(threeg_rfkill);
1444 rfkill_destroy(threeg_rfkill);
1445 }
0606e1ab
CC
1446 return;
1447}
1448
745a5d21 1449/*
7d9a06de 1450 * sysfs interface
745a5d21 1451 */
7d9a06de
CC
1452static ssize_t show_bool_threeg(struct device *dev,
1453 struct device_attribute *attr, char *buf)
1454{
745a5d21 1455 u32 result; \
b3c9092b 1456 acpi_status status;
7b8aca65
LCY
1457
1458 pr_info("This threeg sysfs will be removed in 2012"
1459 " - used by: %s\n", current->comm);
b3c9092b
LCY
1460 if (wmi_has_guid(WMID_GUID3))
1461 status = wmid3_get_device_status(&result,
1462 ACER_WMID3_GDS_THREEG);
1463 else
1464 status = get_u32(&result, ACER_CAP_THREEG);
7d9a06de
CC
1465 if (ACPI_SUCCESS(status))
1466 return sprintf(buf, "%u\n", result);
1467 return sprintf(buf, "Read error\n");
1468}
1469
1470static ssize_t set_bool_threeg(struct device *dev,
1471 struct device_attribute *attr, const char *buf, size_t count)
1472{
1473 u32 tmp = simple_strtoul(buf, NULL, 10);
1474 acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
7b8aca65
LCY
1475 pr_info("This threeg sysfs will be removed in 2012"
1476 " - used by: %s\n", current->comm);
1477 if (ACPI_FAILURE(status))
1478 return -EINVAL;
7d9a06de
CC
1479 return count;
1480}
b80b168f 1481static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
7d9a06de 1482 set_bool_threeg);
745a5d21 1483
745a5d21
CC
1484static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1485 char *buf)
1486{
7b8aca65
LCY
1487 pr_info("This interface sysfs will be removed in 2012"
1488 " - used by: %s\n", current->comm);
745a5d21
CC
1489 switch (interface->type) {
1490 case ACER_AMW0:
1491 return sprintf(buf, "AMW0\n");
1492 case ACER_AMW0_V2:
1493 return sprintf(buf, "AMW0 v2\n");
1494 case ACER_WMID:
1495 return sprintf(buf, "WMID\n");
1496 default:
1497 return sprintf(buf, "Error!\n");
1498 }
1499}
1500
370525df 1501static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
745a5d21 1502
3fdca87d
LCY
1503static void acer_wmi_notify(u32 value, void *context)
1504{
1505 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1506 union acpi_object *obj;
1507 struct event_return_value return_value;
1508 acpi_status status;
92530664
SF
1509 u16 device_state;
1510 const struct key_entry *key;
3fdca87d
LCY
1511
1512 status = wmi_get_event_data(value, &response);
1513 if (status != AE_OK) {
249c720d 1514 pr_warn("bad event status 0x%x\n", status);
3fdca87d
LCY
1515 return;
1516 }
1517
1518 obj = (union acpi_object *)response.pointer;
1519
1520 if (!obj)
1521 return;
1522 if (obj->type != ACPI_TYPE_BUFFER) {
249c720d 1523 pr_warn("Unknown response received %d\n", obj->type);
3fdca87d
LCY
1524 kfree(obj);
1525 return;
1526 }
1527 if (obj->buffer.length != 8) {
249c720d 1528 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
3fdca87d
LCY
1529 kfree(obj);
1530 return;
1531 }
1532
1533 return_value = *((struct event_return_value *)obj->buffer.pointer);
1534 kfree(obj);
1535
1536 switch (return_value.function) {
1537 case WMID_HOTKEY_EVENT:
92530664
SF
1538 device_state = return_value.device_state;
1539 pr_debug("device state: 0x%x\n", device_state);
1540
1541 key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
1542 return_value.key_num);
1543 if (!key) {
249c720d 1544 pr_warn("Unknown key number - 0x%x\n",
3fdca87d 1545 return_value.key_num);
92530664
SF
1546 } else {
1547 switch (key->keycode) {
1548 case KEY_WLAN:
1549 case KEY_BLUETOOTH:
1550 if (has_cap(ACER_CAP_WIRELESS))
1551 rfkill_set_sw_state(wireless_rfkill,
1552 !(device_state & ACER_WMID3_GDS_WIRELESS));
1553 if (has_cap(ACER_CAP_THREEG))
1554 rfkill_set_sw_state(threeg_rfkill,
1555 !(device_state & ACER_WMID3_GDS_THREEG));
1556 if (has_cap(ACER_CAP_BLUETOOTH))
1557 rfkill_set_sw_state(bluetooth_rfkill,
1558 !(device_state & ACER_WMID3_GDS_BLUETOOTH));
1559 break;
1560 }
1561 sparse_keymap_report_entry(acer_wmi_input_dev, key,
1562 1, true);
1563 }
3fdca87d
LCY
1564 break;
1565 default:
249c720d 1566 pr_warn("Unknown function number - %d - %d\n",
3fdca87d
LCY
1567 return_value.function, return_value.key_num);
1568 break;
1569 }
1570}
1571
59ccf2f3
FLCY
1572static acpi_status
1573wmid3_set_lm_mode(struct lm_input_params *params,
1574 struct lm_return_value *return_value)
1575{
1576 acpi_status status;
1577 union acpi_object *obj;
1578
1579 struct acpi_buffer input = { sizeof(struct lm_input_params), params };
1580 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1581
1582 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
1583 if (ACPI_FAILURE(status))
1584 return status;
1585
1586 obj = output.pointer;
1587
1588 if (!obj)
1589 return AE_ERROR;
1590 else if (obj->type != ACPI_TYPE_BUFFER) {
1591 kfree(obj);
1592 return AE_ERROR;
1593 }
1594 if (obj->buffer.length != 4) {
249c720d 1595 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
59ccf2f3
FLCY
1596 kfree(obj);
1597 return AE_ERROR;
1598 }
1599
1600 *return_value = *((struct lm_return_value *)obj->buffer.pointer);
1601 kfree(obj);
1602
1603 return status;
1604}
1605
1606static int acer_wmi_enable_ec_raw(void)
1607{
1608 struct lm_return_value return_value;
1609 acpi_status status;
1610 struct lm_input_params params = {
1611 .function_num = 0x1,
1612 .commun_devices = 0xFFFF,
1613 .devices = 0xFFFF,
1614 .lm_status = 0x00, /* Launch Manager Deactive */
1615 };
1616
1617 status = wmid3_set_lm_mode(&params, &return_value);
1618
1619 if (return_value.error_code || return_value.ec_return_value)
249c720d
JP
1620 pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
1621 return_value.error_code,
1622 return_value.ec_return_value);
59ccf2f3 1623 else
249c720d 1624 pr_info("Enabled EC raw mode\n");
59ccf2f3
FLCY
1625
1626 return status;
1627}
1628
1629static int acer_wmi_enable_lm(void)
1630{
1631 struct lm_return_value return_value;
1632 acpi_status status;
1633 struct lm_input_params params = {
1634 .function_num = 0x1,
1635 .commun_devices = 0xFFFF,
1636 .devices = 0xFFFF,
1637 .lm_status = 0x01, /* Launch Manager Active */
1638 };
1639
1640 status = wmid3_set_lm_mode(&params, &return_value);
1641
1642 if (return_value.error_code || return_value.ec_return_value)
249c720d
JP
1643 pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
1644 return_value.error_code,
1645 return_value.ec_return_value);
59ccf2f3
FLCY
1646
1647 return status;
1648}
1649
3fdca87d
LCY
1650static int __init acer_wmi_input_setup(void)
1651{
1652 acpi_status status;
1653 int err;
1654
1655 acer_wmi_input_dev = input_allocate_device();
1656 if (!acer_wmi_input_dev)
1657 return -ENOMEM;
1658
1659 acer_wmi_input_dev->name = "Acer WMI hotkeys";
1660 acer_wmi_input_dev->phys = "wmi/input0";
1661 acer_wmi_input_dev->id.bustype = BUS_HOST;
1662
1663 err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
1664 if (err)
1665 goto err_free_dev;
1666
1667 status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
1668 acer_wmi_notify, NULL);
1669 if (ACPI_FAILURE(status)) {
1670 err = -EIO;
1671 goto err_free_keymap;
1672 }
1673
1674 err = input_register_device(acer_wmi_input_dev);
1675 if (err)
1676 goto err_uninstall_notifier;
1677
1678 return 0;
1679
1680err_uninstall_notifier:
1681 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1682err_free_keymap:
1683 sparse_keymap_free(acer_wmi_input_dev);
1684err_free_dev:
1685 input_free_device(acer_wmi_input_dev);
1686 return err;
1687}
1688
1689static void acer_wmi_input_destroy(void)
1690{
1691 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1692 sparse_keymap_free(acer_wmi_input_dev);
1693 input_unregister_device(acer_wmi_input_dev);
1694}
1695
81143522
CC
1696/*
1697 * debugfs functions
1698 */
1699static u32 get_wmid_devices(void)
1700{
1701 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1702 union acpi_object *obj;
1703 acpi_status status;
66904863 1704 u32 devices = 0;
81143522
CC
1705
1706 status = wmi_query_block(WMID_GUID2, 1, &out);
1707 if (ACPI_FAILURE(status))
1708 return 0;
1709
1710 obj = (union acpi_object *) out.pointer;
1711 if (obj && obj->type == ACPI_TYPE_BUFFER &&
ab6a9316
LCY
1712 (obj->buffer.length == sizeof(u32) ||
1713 obj->buffer.length == sizeof(u64))) {
66904863 1714 devices = *((u32 *) obj->buffer.pointer);
987dfbaa
LCY
1715 } else if (obj->type == ACPI_TYPE_INTEGER) {
1716 devices = (u32) obj->integer.value;
81143522 1717 }
66904863
AL
1718
1719 kfree(out.pointer);
1720 return devices;
81143522
CC
1721}
1722
745a5d21
CC
1723/*
1724 * Platform device
1725 */
1726static int __devinit acer_platform_probe(struct platform_device *device)
1727{
1728 int err;
1729
1730 if (has_cap(ACER_CAP_MAILLED)) {
1731 err = acer_led_init(&device->dev);
1732 if (err)
1733 goto error_mailled;
1734 }
1735
1736 if (has_cap(ACER_CAP_BRIGHTNESS)) {
1737 err = acer_backlight_init(&device->dev);
1738 if (err)
1739 goto error_brightness;
1740 }
1741
0606e1ab 1742 err = acer_rfkill_init(&device->dev);
350e3290
AW
1743 if (err)
1744 goto error_rfkill;
0606e1ab
CC
1745
1746 return err;
745a5d21 1747
350e3290
AW
1748error_rfkill:
1749 if (has_cap(ACER_CAP_BRIGHTNESS))
1750 acer_backlight_exit();
745a5d21 1751error_brightness:
350e3290
AW
1752 if (has_cap(ACER_CAP_MAILLED))
1753 acer_led_exit();
745a5d21
CC
1754error_mailled:
1755 return err;
1756}
1757
1758static int acer_platform_remove(struct platform_device *device)
1759{
1760 if (has_cap(ACER_CAP_MAILLED))
1761 acer_led_exit();
1762 if (has_cap(ACER_CAP_BRIGHTNESS))
1763 acer_backlight_exit();
0606e1ab
CC
1764
1765 acer_rfkill_exit();
745a5d21
CC
1766 return 0;
1767}
1768
1769static int acer_platform_suspend(struct platform_device *dev,
1770pm_message_t state)
1771{
1772 u32 value;
1773 struct acer_data *data = &interface->data;
1774
1775 if (!data)
1776 return -ENOMEM;
1777
745a5d21
CC
1778 if (has_cap(ACER_CAP_MAILLED)) {
1779 get_u32(&value, ACER_CAP_MAILLED);
9a0b74fd 1780 set_u32(LED_OFF, ACER_CAP_MAILLED);
745a5d21
CC
1781 data->mailled = value;
1782 }
1783
1784 if (has_cap(ACER_CAP_BRIGHTNESS)) {
1785 get_u32(&value, ACER_CAP_BRIGHTNESS);
1786 data->brightness = value;
1787 }
1788
1789 return 0;
1790}
1791
1792static int acer_platform_resume(struct platform_device *device)
1793{
1794 struct acer_data *data = &interface->data;
1795
1796 if (!data)
1797 return -ENOMEM;
1798
745a5d21
CC
1799 if (has_cap(ACER_CAP_MAILLED))
1800 set_u32(data->mailled, ACER_CAP_MAILLED);
1801
1802 if (has_cap(ACER_CAP_BRIGHTNESS))
1803 set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
1804
1805 return 0;
1806}
1807
9a0b74fd
PR
1808static void acer_platform_shutdown(struct platform_device *device)
1809{
1810 struct acer_data *data = &interface->data;
1811
1812 if (!data)
1813 return;
1814
1815 if (has_cap(ACER_CAP_MAILLED))
1816 set_u32(LED_OFF, ACER_CAP_MAILLED);
1817}
1818
745a5d21
CC
1819static struct platform_driver acer_platform_driver = {
1820 .driver = {
1821 .name = "acer-wmi",
1822 .owner = THIS_MODULE,
1823 },
1824 .probe = acer_platform_probe,
1825 .remove = acer_platform_remove,
1826 .suspend = acer_platform_suspend,
1827 .resume = acer_platform_resume,
9a0b74fd 1828 .shutdown = acer_platform_shutdown,
745a5d21
CC
1829};
1830
1831static struct platform_device *acer_platform_device;
1832
1833static int remove_sysfs(struct platform_device *device)
1834{
745a5d21
CC
1835 if (has_cap(ACER_CAP_THREEG))
1836 device_remove_file(&device->dev, &dev_attr_threeg);
1837
1838 device_remove_file(&device->dev, &dev_attr_interface);
1839
1840 return 0;
1841}
1842
1843static int create_sysfs(void)
1844{
1845 int retval = -ENOMEM;
1846
745a5d21
CC
1847 if (has_cap(ACER_CAP_THREEG)) {
1848 retval = device_create_file(&acer_platform_device->dev,
1849 &dev_attr_threeg);
1850 if (retval)
1851 goto error_sysfs;
1852 }
1853
1854 retval = device_create_file(&acer_platform_device->dev,
1855 &dev_attr_interface);
1856 if (retval)
1857 goto error_sysfs;
1858
1859 return 0;
1860
1861error_sysfs:
1862 remove_sysfs(acer_platform_device);
1863 return retval;
1864}
1865
81143522
CC
1866static void remove_debugfs(void)
1867{
1868 debugfs_remove(interface->debug.devices);
1869 debugfs_remove(interface->debug.root);
1870}
1871
1872static int create_debugfs(void)
1873{
1874 interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
1875 if (!interface->debug.root) {
cae15702 1876 pr_err("Failed to create debugfs directory");
81143522
CC
1877 return -ENOMEM;
1878 }
1879
1880 interface->debug.devices = debugfs_create_u32("devices", S_IRUGO,
1881 interface->debug.root,
1882 &interface->debug.wmid_devices);
1883 if (!interface->debug.devices)
1884 goto error_debugfs;
1885
1886 return 0;
1887
1888error_debugfs:
39dbbb45 1889 remove_debugfs();
81143522
CC
1890 return -ENOMEM;
1891}
1892
745a5d21
CC
1893static int __init acer_wmi_init(void)
1894{
1895 int err;
1896
cae15702 1897 pr_info("Acer Laptop ACPI-WMI Extras\n");
745a5d21 1898
a74dd5fd 1899 if (dmi_check_system(acer_blacklist)) {
cae15702 1900 pr_info("Blacklisted hardware detected - not loading\n");
a74dd5fd
CC
1901 return -ENODEV;
1902 }
1903
9991d9f2
CC
1904 find_quirks();
1905
745a5d21
CC
1906 /*
1907 * Detect which ACPI-WMI interface we're using.
1908 */
1909 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1910 interface = &AMW0_V2_interface;
1911
1912 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1913 interface = &wmid_interface;
1914
1915 if (wmi_has_guid(WMID_GUID2) && interface) {
1916 if (ACPI_FAILURE(WMID_set_capabilities())) {
cae15702 1917 pr_err("Unable to detect available WMID devices\n");
745a5d21
CC
1918 return -ENODEV;
1919 }
1920 } else if (!wmi_has_guid(WMID_GUID2) && interface) {
cae15702 1921 pr_err("No WMID device detection method found\n");
745a5d21
CC
1922 return -ENODEV;
1923 }
1924
1925 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
1926 interface = &AMW0_interface;
1927
1928 if (ACPI_FAILURE(AMW0_set_capabilities())) {
cae15702 1929 pr_err("Unable to detect available AMW0 devices\n");
745a5d21
CC
1930 return -ENODEV;
1931 }
1932 }
1933
9b963c40
CC
1934 if (wmi_has_guid(AMW0_GUID1))
1935 AMW0_find_mailled();
745a5d21 1936
745a5d21 1937 if (!interface) {
cae15702 1938 pr_err("No or unsupported WMI interface, unable to load\n");
745a5d21
CC
1939 return -ENODEV;
1940 }
1941
83097aca
AV
1942 set_quirks();
1943
1ba869ec 1944 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
febf2d95 1945 interface->capability &= ~ACER_CAP_BRIGHTNESS;
cae15702 1946 pr_info("Brightness must be controlled by "
febf2d95
TR
1947 "generic video driver\n");
1948 }
1949
59ccf2f3
FLCY
1950 if (wmi_has_guid(WMID_GUID3)) {
1951 if (ec_raw_mode) {
1952 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
cae15702 1953 pr_err("Cannot enable EC raw mode\n");
59ccf2f3
FLCY
1954 return -ENODEV;
1955 }
1956 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
cae15702 1957 pr_err("Cannot enable Launch Manager mode\n");
59ccf2f3
FLCY
1958 return -ENODEV;
1959 }
1960 } else if (ec_raw_mode) {
cae15702 1961 pr_info("No WMID EC raw mode enable method\n");
59ccf2f3
FLCY
1962 }
1963
3fdca87d
LCY
1964 if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
1965 err = acer_wmi_input_setup();
1966 if (err)
1967 return err;
1968 }
1969
1c79632b
AL
1970 err = platform_driver_register(&acer_platform_driver);
1971 if (err) {
cae15702 1972 pr_err("Unable to register platform driver.\n");
745a5d21
CC
1973 goto error_platform_register;
1974 }
1c79632b 1975
745a5d21 1976 acer_platform_device = platform_device_alloc("acer-wmi", -1);
1c79632b
AL
1977 if (!acer_platform_device) {
1978 err = -ENOMEM;
1979 goto error_device_alloc;
1980 }
1981
1982 err = platform_device_add(acer_platform_device);
1983 if (err)
1984 goto error_device_add;
745a5d21
CC
1985
1986 err = create_sysfs();
1987 if (err)
1c79632b 1988 goto error_create_sys;
745a5d21 1989
81143522
CC
1990 if (wmi_has_guid(WMID_GUID2)) {
1991 interface->debug.wmid_devices = get_wmid_devices();
1992 err = create_debugfs();
1993 if (err)
1c79632b 1994 goto error_create_debugfs;
81143522
CC
1995 }
1996
745a5d21
CC
1997 /* Override any initial settings with values from the commandline */
1998 acer_commandline_init();
1999
2000 return 0;
2001
1c79632b
AL
2002error_create_debugfs:
2003 remove_sysfs(acer_platform_device);
2004error_create_sys:
2005 platform_device_del(acer_platform_device);
2006error_device_add:
2007 platform_device_put(acer_platform_device);
2008error_device_alloc:
2009 platform_driver_unregister(&acer_platform_driver);
745a5d21 2010error_platform_register:
3fdca87d
LCY
2011 if (wmi_has_guid(ACERWMID_EVENT_GUID))
2012 acer_wmi_input_destroy();
2013
1c79632b 2014 return err;
745a5d21
CC
2015}
2016
2017static void __exit acer_wmi_exit(void)
2018{
3fdca87d
LCY
2019 if (wmi_has_guid(ACERWMID_EVENT_GUID))
2020 acer_wmi_input_destroy();
2021
745a5d21 2022 remove_sysfs(acer_platform_device);
39dbbb45 2023 remove_debugfs();
97ba0af0 2024 platform_device_unregister(acer_platform_device);
745a5d21
CC
2025 platform_driver_unregister(&acer_platform_driver);
2026
cae15702 2027 pr_info("Acer Laptop WMI Extras unloaded\n");
745a5d21
CC
2028 return;
2029}
2030
2031module_init(acer_wmi_init);
2032module_exit(acer_wmi_exit);