]> git.ipfire.org Git - people/arne_f/kernel.git/blame - drivers/platform/x86/acer-wmi.c
platform/x86: acer-wmi: Cleanup ACER_CAP_FOO defines
[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>
86924de2 44#include <acpi/video.h>
745a5d21
CC
45
46MODULE_AUTHOR("Carlos Corbacho");
47MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
48MODULE_LICENSE("GPL");
49
745a5d21
CC
50/*
51 * Magic Number
52 * Meaning is unknown - this number is required for writing to ACPI for AMW0
53 * (it's also used in acerhk when directly accessing the BIOS)
54 */
55#define ACER_AMW0_WRITE 0x9610
56
57/*
58 * Bit masks for the AMW0 interface
59 */
60#define ACER_AMW0_WIRELESS_MASK 0x35
61#define ACER_AMW0_BLUETOOTH_MASK 0x34
62#define ACER_AMW0_MAILLED_MASK 0x31
63
64/*
65 * Method IDs for WMID interface
66 */
67#define ACER_WMID_GET_WIRELESS_METHODID 1
68#define ACER_WMID_GET_BLUETOOTH_METHODID 2
69#define ACER_WMID_GET_BRIGHTNESS_METHODID 3
70#define ACER_WMID_SET_WIRELESS_METHODID 4
71#define ACER_WMID_SET_BLUETOOTH_METHODID 5
72#define ACER_WMID_SET_BRIGHTNESS_METHODID 6
73#define ACER_WMID_GET_THREEG_METHODID 10
74#define ACER_WMID_SET_THREEG_METHODID 11
75
76/*
77 * Acer ACPI method GUIDs
78 */
79#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
5753dd53 80#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
bbb70607 81#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
298f19b2 82#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A"
b3c9092b 83#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
745a5d21 84
3fdca87d
LCY
85/*
86 * Acer ACPI event GUIDs
87 */
88#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
89
745a5d21 90MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
08a0799d 91MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
3fdca87d
LCY
92MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
93
94enum acer_wmi_event_ids {
95 WMID_HOTKEY_EVENT = 0x1,
1eb3fe1d 96 WMID_ACCEL_EVENT = 0x5,
3fdca87d
LCY
97};
98
87e44849 99static const struct key_entry acer_wmi_keymap[] __initconst = {
3fdca87d 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 */
67e1d34c 108 {KE_KEY, 0x29, {KEY_PROG3} }, /* P_Key for TM8372 */
8ae68de1
MF
109 {KE_IGNORE, 0x41, {KEY_MUTE} },
110 {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
ca1469f5 111 {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
8ae68de1 112 {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
ca1469f5 113 {KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
8ae68de1 114 {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
ca1469f5 115 {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
8ae68de1 116 {KE_IGNORE, 0x45, {KEY_STOP} },
ca1469f5 117 {KE_IGNORE, 0x50, {KEY_STOP} },
8ae68de1
MF
118 {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
119 {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
ca1469f5 120 {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
8ae68de1
MF
121 {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
122 {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
123 {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
3fdca87d 124 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
8ae68de1 125 {KE_IGNORE, 0x81, {KEY_SLEEP} },
8e2286ce 126 {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */
8de429bb 127 {KE_IGNORE, 0x84, {KEY_KBDILLUMTOGGLE} }, /* Automatic Keyboard background light toggle */
8e2286ce
LCY
128 {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
129 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
8ae68de1 130 {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
68825ce2 131 {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
5ffa572a 132 {KE_KEY, 0x86, {KEY_WLAN} },
3fdca87d
LCY
133 {KE_END, 0}
134};
135
136static struct input_dev *acer_wmi_input_dev;
1eb3fe1d 137static struct input_dev *acer_wmi_accel_dev;
3fdca87d
LCY
138
139struct event_return_value {
140 u8 function;
141 u8 key_num;
142 u16 device_state;
143 u32 reserved;
144} __attribute__((packed));
745a5d21 145
b3c9092b
LCY
146/*
147 * GUID3 Get Device Status device flags
148 */
6c3df88f 149#define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */
b3c9092b 150#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */
6d88ff0f 151#define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */
6c3df88f 152#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */
3e2bc5c5
JPRV
153#define ACER_WMID3_GDS_RFBTN (1<<14) /* RF Button */
154
8e2286ce 155#define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */
b3c9092b 156
280642c3
CC
157/* Hotkey Customized Setting and Acer Application Status.
158 * Set Device Default Value and Report Acer Application Status.
159 * When Acer Application starts, it will run this method to inform
160 * BIOS/EC that Acer Application is on.
161 * App Status
162 * Bit[0]: Launch Manager Status
163 * Bit[1]: ePM Status
164 * Bit[2]: Device Control Status
165 * Bit[3]: Acer Power Button Utility Status
166 * Bit[4]: RF Button Status
167 * Bit[5]: ODD PM Status
168 * Bit[6]: Device Default Value Control
169 * Bit[7]: Hall Sensor Application Status
170 */
171struct func_input_params {
59ccf2f3
FLCY
172 u8 function_num; /* Function Number */
173 u16 commun_devices; /* Communication type devices default status */
174 u16 devices; /* Other type devices default status */
280642c3
CC
175 u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */
176 u8 app_mask; /* Bit mask to app_status */
177 u8 reserved;
59ccf2f3
FLCY
178} __attribute__((packed));
179
280642c3 180struct func_return_value {
59ccf2f3
FLCY
181 u8 error_code; /* Error Code */
182 u8 ec_return_value; /* EC Return Value */
183 u16 reserved;
184} __attribute__((packed));
185
996d23ba
LCY
186struct wmid3_gds_set_input_param { /* Set Device Status input parameter */
187 u8 function_num; /* Function Number */
188 u8 hotkey_number; /* Hotkey Number */
189 u16 devices; /* Set Device */
190 u8 volume_value; /* Volume Value */
191} __attribute__((packed));
192
193struct wmid3_gds_get_input_param { /* Get Device Status input parameter */
b3c9092b
LCY
194 u8 function_num; /* Function Number */
195 u8 hotkey_number; /* Hotkey Number */
196 u16 devices; /* Get Device */
197} __attribute__((packed));
198
199struct wmid3_gds_return_value { /* Get Device Status return value*/
200 u8 error_code; /* Error Code */
201 u8 ec_return_value; /* EC Return Value */
202 u16 devices; /* Current Device Status */
203 u32 reserved;
204} __attribute__((packed));
205
6c3df88f
LCY
206struct hotkey_function_type_aa {
207 u8 type;
208 u8 length;
209 u16 handle;
210 u16 commun_func_bitmap;
34b6cfab
LCY
211 u16 application_func_bitmap;
212 u16 media_func_bitmap;
213 u16 display_func_bitmap;
214 u16 others_func_bitmap;
215 u8 commun_fn_key_number;
6c3df88f
LCY
216} __attribute__((packed));
217
745a5d21
CC
218/*
219 * Interface capability flags
220 */
d2ddc327
HG
221#define ACER_CAP_MAILLED BIT(0)
222#define ACER_CAP_WIRELESS BIT(1)
223#define ACER_CAP_BLUETOOTH BIT(2)
224#define ACER_CAP_BRIGHTNESS BIT(3)
225#define ACER_CAP_THREEG BIT(4)
226#define ACER_CAP_ACCEL BIT(5)
745a5d21
CC
227
228/*
229 * Interface type flags
230 */
231enum interface_flags {
232 ACER_AMW0,
233 ACER_AMW0_V2,
234 ACER_WMID,
72e71de1 235 ACER_WMID_v2,
745a5d21
CC
236};
237
238#define ACER_DEFAULT_WIRELESS 0
239#define ACER_DEFAULT_BLUETOOTH 0
240#define ACER_DEFAULT_MAILLED 0
241#define ACER_DEFAULT_THREEG 0
242
243static int max_brightness = 0xF;
244
745a5d21
CC
245static int mailled = -1;
246static int brightness = -1;
247static int threeg = -1;
248static int force_series;
59ccf2f3 249static bool ec_raw_mode;
6c3df88f 250static bool has_type_aa;
1d1fc8a7 251static u16 commun_func_bitmap;
34b6cfab 252static u8 commun_fn_key_number;
745a5d21
CC
253
254module_param(mailled, int, 0444);
745a5d21
CC
255module_param(brightness, int, 0444);
256module_param(threeg, int, 0444);
257module_param(force_series, int, 0444);
59ccf2f3 258module_param(ec_raw_mode, bool, 0444);
745a5d21
CC
259MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
260MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
261MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
262MODULE_PARM_DESC(force_series, "Force a different laptop series");
59ccf2f3 263MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
745a5d21
CC
264
265struct acer_data {
266 int mailled;
745a5d21
CC
267 int threeg;
268 int brightness;
269};
270
81143522
CC
271struct acer_debug {
272 struct dentry *root;
273 struct dentry *devices;
274 u32 wmid_devices;
275};
276
0606e1ab
CC
277static struct rfkill *wireless_rfkill;
278static struct rfkill *bluetooth_rfkill;
b3c9092b 279static struct rfkill *threeg_rfkill;
8215af01 280static bool rfkill_inited;
0606e1ab 281
745a5d21
CC
282/* Each low-level interface must define at least some of the following */
283struct wmi_interface {
284 /* The WMI device type */
285 u32 type;
286
287 /* The capabilities this interface provides */
288 u32 capability;
289
290 /* Private data for the current interface */
291 struct acer_data data;
81143522
CC
292
293 /* debugfs entries associated with this interface */
294 struct acer_debug debug;
745a5d21
CC
295};
296
297/* The static interface pointer, points to the currently detected interface */
298static struct wmi_interface *interface;
299
300/*
301 * Embedded Controller quirks
302 * Some laptops require us to directly access the EC to either enable or query
303 * features that are not available through WMI.
304 */
305
306struct quirk_entry {
307 u8 wireless;
308 u8 mailled;
9991d9f2 309 s8 brightness;
745a5d21
CC
310 u8 bluetooth;
311};
312
313static struct quirk_entry *quirks;
314
76d51dd9 315static void __init set_quirks(void)
745a5d21 316{
83097aca
AV
317 if (!interface)
318 return;
319
745a5d21
CC
320 if (quirks->mailled)
321 interface->capability |= ACER_CAP_MAILLED;
322
323 if (quirks->brightness)
324 interface->capability |= ACER_CAP_BRIGHTNESS;
325}
326
76d51dd9 327static int __init dmi_matched(const struct dmi_system_id *dmi)
745a5d21
CC
328{
329 quirks = dmi->driver_data;
d53bf0f3 330 return 1;
745a5d21
CC
331}
332
333static struct quirk_entry quirk_unknown = {
334};
335
9991d9f2
CC
336static struct quirk_entry quirk_acer_aspire_1520 = {
337 .brightness = -1,
338};
339
745a5d21
CC
340static struct quirk_entry quirk_acer_travelmate_2490 = {
341 .mailled = 1,
342};
343
344/* This AMW0 laptop has no bluetooth */
345static struct quirk_entry quirk_medion_md_98300 = {
346 .wireless = 1,
347};
348
6f061ab5
CC
349static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
350 .wireless = 2,
351};
352
15b956a0
LCY
353static struct quirk_entry quirk_lenovo_ideapad_s205 = {
354 .wireless = 3,
355};
356
a74dd5fd 357/* The Aspire One has a dummy ACPI-WMI interface - disable it */
76d51dd9 358static const struct dmi_system_id acer_blacklist[] __initconst = {
a74dd5fd
CC
359 {
360 .ident = "Acer Aspire One (SSD)",
361 .matches = {
362 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
363 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
364 },
365 },
366 {
367 .ident = "Acer Aspire One (HDD)",
368 .matches = {
369 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
370 DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
371 },
372 },
373 {}
374};
375
5241b193
LCY
376static const struct dmi_system_id amw0_whitelist[] __initconst = {
377 {
378 .ident = "Acer",
379 .matches = {
380 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
381 },
382 },
383 {
384 .ident = "Gateway",
385 .matches = {
386 DMI_MATCH(DMI_SYS_VENDOR, "Gateway"),
387 },
388 },
389 {
390 .ident = "Packard Bell",
391 .matches = {
392 DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
393 },
394 },
395 {}
396};
397
398/*
399 * This quirk table is only for Acer/Gateway/Packard Bell family
400 * that those machines are supported by acer-wmi driver.
401 */
76d51dd9 402static const struct dmi_system_id acer_quirks[] __initconst = {
9991d9f2
CC
403 {
404 .callback = dmi_matched,
405 .ident = "Acer Aspire 1360",
406 .matches = {
407 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
408 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
409 },
410 .driver_data = &quirk_acer_aspire_1520,
411 },
412 {
413 .callback = dmi_matched,
414 .ident = "Acer Aspire 1520",
415 .matches = {
416 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
417 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
418 },
419 .driver_data = &quirk_acer_aspire_1520,
420 },
745a5d21
CC
421 {
422 .callback = dmi_matched,
423 .ident = "Acer Aspire 3100",
424 .matches = {
425 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
426 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
427 },
428 .driver_data = &quirk_acer_travelmate_2490,
429 },
ed9cfe98
CC
430 {
431 .callback = dmi_matched,
432 .ident = "Acer Aspire 3610",
433 .matches = {
434 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
435 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
436 },
437 .driver_data = &quirk_acer_travelmate_2490,
438 },
745a5d21
CC
439 {
440 .callback = dmi_matched,
441 .ident = "Acer Aspire 5100",
442 .matches = {
443 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
444 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
445 },
446 .driver_data = &quirk_acer_travelmate_2490,
447 },
ed9cfe98
CC
448 {
449 .callback = dmi_matched,
450 .ident = "Acer Aspire 5610",
451 .matches = {
452 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
453 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
454 },
455 .driver_data = &quirk_acer_travelmate_2490,
456 },
745a5d21
CC
457 {
458 .callback = dmi_matched,
459 .ident = "Acer Aspire 5630",
460 .matches = {
461 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
462 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
463 },
464 .driver_data = &quirk_acer_travelmate_2490,
465 },
466 {
467 .callback = dmi_matched,
468 .ident = "Acer Aspire 5650",
469 .matches = {
470 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
471 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
472 },
473 .driver_data = &quirk_acer_travelmate_2490,
474 },
475 {
476 .callback = dmi_matched,
477 .ident = "Acer Aspire 5680",
478 .matches = {
479 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
480 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
481 },
482 .driver_data = &quirk_acer_travelmate_2490,
483 },
484 {
485 .callback = dmi_matched,
486 .ident = "Acer Aspire 9110",
487 .matches = {
488 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
489 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
490 },
491 .driver_data = &quirk_acer_travelmate_2490,
492 },
493 {
494 .callback = dmi_matched,
495 .ident = "Acer TravelMate 2490",
496 .matches = {
497 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
498 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
499 },
500 .driver_data = &quirk_acer_travelmate_2490,
501 },
262ee35b
CC
502 {
503 .callback = dmi_matched,
504 .ident = "Acer TravelMate 4200",
505 .matches = {
506 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
507 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
508 },
509 .driver_data = &quirk_acer_travelmate_2490,
510 },
5241b193
LCY
511 {}
512};
513
514/*
515 * This quirk list is for those non-acer machines that have AMW0_GUID1
516 * but supported by acer-wmi in past days. Keeping this quirk list here
517 * is only for backward compatible. Please do not add new machine to
518 * here anymore. Those non-acer machines should be supported by
519 * appropriate wmi drivers.
520 */
521static const struct dmi_system_id non_acer_quirks[] __initconst = {
6f061ab5
CC
522 {
523 .callback = dmi_matched,
524 .ident = "Fujitsu Siemens Amilo Li 1718",
525 .matches = {
526 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
527 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
528 },
529 .driver_data = &quirk_fujitsu_amilo_li_1718,
530 },
745a5d21
CC
531 {
532 .callback = dmi_matched,
533 .ident = "Medion MD 98300",
534 .matches = {
535 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
536 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
537 },
538 .driver_data = &quirk_medion_md_98300,
539 },
15b956a0
LCY
540 {
541 .callback = dmi_matched,
542 .ident = "Lenovo Ideapad S205",
543 .matches = {
544 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
545 DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
546 },
547 .driver_data = &quirk_lenovo_ideapad_s205,
548 },
c08f2086
LCY
549 {
550 .callback = dmi_matched,
551 .ident = "Lenovo Ideapad S205 (Brazos)",
552 .matches = {
553 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
554 DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
555 },
556 .driver_data = &quirk_lenovo_ideapad_s205,
557 },
be3128b1
SF
558 {
559 .callback = dmi_matched,
560 .ident = "Lenovo 3000 N200",
561 .matches = {
562 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
563 DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
564 },
565 .driver_data = &quirk_fujitsu_amilo_li_1718,
566 },
e6c33f1f
LCY
567 {
568 .callback = dmi_matched,
569 .ident = "Lenovo Ideapad S205-10382JG",
570 .matches = {
571 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
572 DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"),
573 },
574 .driver_data = &quirk_lenovo_ideapad_s205,
575 },
5f3511d2
LCY
576 {
577 .callback = dmi_matched,
578 .ident = "Lenovo Ideapad S205-1038DPG",
579 .matches = {
580 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
581 DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"),
582 },
583 .driver_data = &quirk_lenovo_ideapad_s205,
584 },
745a5d21
CC
585 {}
586};
587
76d51dd9
MK
588static int __init
589video_set_backlight_video_vendor(const struct dmi_system_id *d)
86924de2
LCY
590{
591 interface->capability &= ~ACER_CAP_BRIGHTNESS;
592 pr_info("Brightness must be controlled by generic video driver\n");
593 return 0;
594}
595
76d51dd9 596static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
86924de2
LCY
597 {
598 .callback = video_set_backlight_video_vendor,
599 .ident = "Acer TravelMate 4750",
600 .matches = {
601 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
602 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
603 },
604 },
050eff39
LCY
605 {
606 .callback = video_set_backlight_video_vendor,
607 .ident = "Acer Extensa 5235",
608 .matches = {
609 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
610 DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
611 },
612 },
613 {
614 .callback = video_set_backlight_video_vendor,
615 .ident = "Acer TravelMate 5760",
616 .matches = {
617 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
618 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
619 },
620 },
621 {
622 .callback = video_set_backlight_video_vendor,
623 .ident = "Acer Aspire 5750",
624 .matches = {
625 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
626 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
627 },
628 },
9404cd95
HG
629 {
630 .callback = video_set_backlight_video_vendor,
631 .ident = "Acer Aspire 5741",
632 .matches = {
633 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
634 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
635 },
636 },
183fd8fc
HG
637 {
638 /*
639 * Note no video_set_backlight_video_vendor, we must use the
640 * acer interface, as there is no native backlight interface.
641 */
642 .ident = "Acer KAV80",
643 .matches = {
644 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
645 DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
646 },
647 },
86924de2
LCY
648 {}
649};
650
745a5d21 651/* Find which quirks are needed for a particular vendor/ model pair */
76d51dd9 652static void __init find_quirks(void)
745a5d21
CC
653{
654 if (!force_series) {
655 dmi_check_system(acer_quirks);
5241b193 656 dmi_check_system(non_acer_quirks);
745a5d21
CC
657 } else if (force_series == 2490) {
658 quirks = &quirk_acer_travelmate_2490;
659 }
660
661 if (quirks == NULL)
662 quirks = &quirk_unknown;
663
664 set_quirks();
665}
666
667/*
668 * General interface convenience methods
669 */
670
671static bool has_cap(u32 cap)
672{
673 if ((interface->capability & cap) != 0)
674 return 1;
675
676 return 0;
677}
678
679/*
680 * AMW0 (V1) interface
681 */
682struct wmab_args {
683 u32 eax;
684 u32 ebx;
685 u32 ecx;
686 u32 edx;
687};
688
689struct wmab_ret {
690 u32 eax;
691 u32 ebx;
692 u32 ecx;
693 u32 edx;
694 u32 eex;
695};
696
697static acpi_status wmab_execute(struct wmab_args *regbuf,
698struct acpi_buffer *result)
699{
700 struct acpi_buffer input;
701 acpi_status status;
702 input.length = sizeof(struct wmab_args);
703 input.pointer = (u8 *)regbuf;
704
62fc743c 705 status = wmi_evaluate_method(AMW0_GUID1, 0, 1, &input, result);
745a5d21
CC
706
707 return status;
708}
709
38db157d 710static acpi_status AMW0_get_u32(u32 *value, u32 cap)
745a5d21
CC
711{
712 int err;
713 u8 result;
714
715 switch (cap) {
716 case ACER_CAP_MAILLED:
717 switch (quirks->mailled) {
718 default:
719 err = ec_read(0xA, &result);
720 if (err)
721 return AE_ERROR;
722 *value = (result >> 7) & 0x1;
723 return AE_OK;
724 }
725 break;
726 case ACER_CAP_WIRELESS:
727 switch (quirks->wireless) {
728 case 1:
729 err = ec_read(0x7B, &result);
730 if (err)
731 return AE_ERROR;
732 *value = result & 0x1;
733 return AE_OK;
6f061ab5
CC
734 case 2:
735 err = ec_read(0x71, &result);
736 if (err)
737 return AE_ERROR;
738 *value = result & 0x1;
739 return AE_OK;
15b956a0
LCY
740 case 3:
741 err = ec_read(0x78, &result);
742 if (err)
743 return AE_ERROR;
744 *value = result & 0x1;
745 return AE_OK;
745a5d21
CC
746 default:
747 err = ec_read(0xA, &result);
748 if (err)
749 return AE_ERROR;
750 *value = (result >> 2) & 0x1;
751 return AE_OK;
752 }
753 break;
754 case ACER_CAP_BLUETOOTH:
755 switch (quirks->bluetooth) {
756 default:
757 err = ec_read(0xA, &result);
758 if (err)
759 return AE_ERROR;
760 *value = (result >> 4) & 0x1;
761 return AE_OK;
762 }
763 break;
764 case ACER_CAP_BRIGHTNESS:
765 switch (quirks->brightness) {
766 default:
767 err = ec_read(0x83, &result);
768 if (err)
769 return AE_ERROR;
770 *value = result;
771 return AE_OK;
772 }
773 break;
774 default:
08237974 775 return AE_ERROR;
745a5d21
CC
776 }
777 return AE_OK;
778}
779
38db157d 780static acpi_status AMW0_set_u32(u32 value, u32 cap)
745a5d21
CC
781{
782 struct wmab_args args;
783
784 args.eax = ACER_AMW0_WRITE;
785 args.ebx = value ? (1<<8) : 0;
786 args.ecx = args.edx = 0;
787
788 switch (cap) {
789 case ACER_CAP_MAILLED:
790 if (value > 1)
791 return AE_BAD_PARAMETER;
792 args.ebx |= ACER_AMW0_MAILLED_MASK;
793 break;
794 case ACER_CAP_WIRELESS:
795 if (value > 1)
796 return AE_BAD_PARAMETER;
797 args.ebx |= ACER_AMW0_WIRELESS_MASK;
798 break;
799 case ACER_CAP_BLUETOOTH:
800 if (value > 1)
801 return AE_BAD_PARAMETER;
802 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
803 break;
804 case ACER_CAP_BRIGHTNESS:
805 if (value > max_brightness)
806 return AE_BAD_PARAMETER;
807 switch (quirks->brightness) {
745a5d21 808 default:
4609d029
CC
809 return ec_write(0x83, value);
810 break;
745a5d21
CC
811 }
812 default:
08237974 813 return AE_ERROR;
745a5d21
CC
814 }
815
816 /* Actually do the set */
817 return wmab_execute(&args, NULL);
818}
819
76d51dd9 820static acpi_status __init AMW0_find_mailled(void)
745a5d21
CC
821{
822 struct wmab_args args;
823 struct wmab_ret ret;
824 acpi_status status = AE_OK;
825 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
826 union acpi_object *obj;
827
828 args.eax = 0x86;
829 args.ebx = args.ecx = args.edx = 0;
830
831 status = wmab_execute(&args, &out);
832 if (ACPI_FAILURE(status))
833 return status;
834
835 obj = (union acpi_object *) out.pointer;
836 if (obj && obj->type == ACPI_TYPE_BUFFER &&
837 obj->buffer.length == sizeof(struct wmab_ret)) {
838 ret = *((struct wmab_ret *) obj->buffer.pointer);
839 } else {
7677fbdf 840 kfree(out.pointer);
745a5d21
CC
841 return AE_ERROR;
842 }
843
844 if (ret.eex & 0x1)
845 interface->capability |= ACER_CAP_MAILLED;
846
847 kfree(out.pointer);
848
849 return AE_OK;
850}
851
76d51dd9 852static const struct acpi_device_id norfkill_ids[] __initconst = {
461e7437
IP
853 { "VPC2004", 0},
854 { "IBM0068", 0},
855 { "LEN0068", 0},
5719b819 856 { "SNY5001", 0}, /* sony-laptop in charge */
628b3198 857 { "HPQ6601", 0},
461e7437
IP
858 { "", 0},
859};
860
76d51dd9 861static int __init AMW0_set_cap_acpi_check_device(void)
461e7437
IP
862{
863 const struct acpi_device_id *id;
864
865 for (id = norfkill_ids; id->id[0]; id++)
8c92a75e
LW
866 if (acpi_dev_found(id->id))
867 return true;
868
869 return false;
461e7437
IP
870}
871
76d51dd9 872static acpi_status __init AMW0_set_capabilities(void)
745a5d21
CC
873{
874 struct wmab_args args;
875 struct wmab_ret ret;
7677fbdf 876 acpi_status status;
745a5d21
CC
877 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
878 union acpi_object *obj;
879
5753dd53
CC
880 /*
881 * On laptops with this strange GUID (non Acer), normal probing doesn't
882 * work.
883 */
884 if (wmi_has_guid(AMW0_GUID2)) {
461e7437
IP
885 if ((quirks != &quirk_unknown) ||
886 !AMW0_set_cap_acpi_check_device())
887 interface->capability |= ACER_CAP_WIRELESS;
5753dd53
CC
888 return AE_OK;
889 }
890
745a5d21
CC
891 args.eax = ACER_AMW0_WRITE;
892 args.ecx = args.edx = 0;
893
894 args.ebx = 0xa2 << 8;
895 args.ebx |= ACER_AMW0_WIRELESS_MASK;
896
897 status = wmab_execute(&args, &out);
898 if (ACPI_FAILURE(status))
899 return status;
900
7677fbdf 901 obj = out.pointer;
745a5d21
CC
902 if (obj && obj->type == ACPI_TYPE_BUFFER &&
903 obj->buffer.length == sizeof(struct wmab_ret)) {
904 ret = *((struct wmab_ret *) obj->buffer.pointer);
905 } else {
7677fbdf
AL
906 status = AE_ERROR;
907 goto out;
745a5d21
CC
908 }
909
910 if (ret.eax & 0x1)
911 interface->capability |= ACER_CAP_WIRELESS;
912
913 args.ebx = 2 << 8;
914 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
915
7677fbdf
AL
916 /*
917 * It's ok to use existing buffer for next wmab_execute call.
918 * But we need to kfree(out.pointer) if next wmab_execute fail.
919 */
745a5d21
CC
920 status = wmab_execute(&args, &out);
921 if (ACPI_FAILURE(status))
7677fbdf 922 goto out;
745a5d21
CC
923
924 obj = (union acpi_object *) out.pointer;
925 if (obj && obj->type == ACPI_TYPE_BUFFER
926 && obj->buffer.length == sizeof(struct wmab_ret)) {
927 ret = *((struct wmab_ret *) obj->buffer.pointer);
928 } else {
7677fbdf
AL
929 status = AE_ERROR;
930 goto out;
745a5d21
CC
931 }
932
933 if (ret.eax & 0x1)
934 interface->capability |= ACER_CAP_BLUETOOTH;
935
745a5d21
CC
936 /*
937 * This appears to be safe to enable, since all Wistron based laptops
938 * appear to use the same EC register for brightness, even if they
939 * differ for wireless, etc
940 */
9991d9f2
CC
941 if (quirks->brightness >= 0)
942 interface->capability |= ACER_CAP_BRIGHTNESS;
745a5d21 943
7677fbdf
AL
944 status = AE_OK;
945out:
946 kfree(out.pointer);
947 return status;
745a5d21
CC
948}
949
950static struct wmi_interface AMW0_interface = {
951 .type = ACER_AMW0,
952};
953
954static struct wmi_interface AMW0_V2_interface = {
955 .type = ACER_AMW0_V2,
956};
957
958/*
959 * New interface (The WMID interface)
960 */
961static acpi_status
962WMI_execute_u32(u32 method_id, u32 in, u32 *out)
963{
964 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
965 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
966 union acpi_object *obj;
f20aaba9 967 u32 tmp = 0;
745a5d21
CC
968 acpi_status status;
969
62fc743c 970 status = wmi_evaluate_method(WMID_GUID1, 0, method_id, &input, &result);
745a5d21
CC
971
972 if (ACPI_FAILURE(status))
973 return status;
974
975 obj = (union acpi_object *) result.pointer;
f20aaba9
LCY
976 if (obj) {
977 if (obj->type == ACPI_TYPE_BUFFER &&
978 (obj->buffer.length == sizeof(u32) ||
979 obj->buffer.length == sizeof(u64))) {
980 tmp = *((u32 *) obj->buffer.pointer);
981 } else if (obj->type == ACPI_TYPE_INTEGER) {
982 tmp = (u32) obj->integer.value;
983 }
745a5d21
CC
984 }
985
986 if (out)
987 *out = tmp;
988
989 kfree(result.pointer);
990
991 return status;
992}
993
38db157d 994static acpi_status WMID_get_u32(u32 *value, u32 cap)
745a5d21
CC
995{
996 acpi_status status;
997 u8 tmp;
998 u32 result, method_id = 0;
999
1000 switch (cap) {
1001 case ACER_CAP_WIRELESS:
1002 method_id = ACER_WMID_GET_WIRELESS_METHODID;
1003 break;
1004 case ACER_CAP_BLUETOOTH:
1005 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
1006 break;
1007 case ACER_CAP_BRIGHTNESS:
1008 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
1009 break;
1010 case ACER_CAP_THREEG:
1011 method_id = ACER_WMID_GET_THREEG_METHODID;
1012 break;
1013 case ACER_CAP_MAILLED:
1014 if (quirks->mailled == 1) {
1015 ec_read(0x9f, &tmp);
1016 *value = tmp & 0x1;
1017 return 0;
1018 }
1019 default:
08237974 1020 return AE_ERROR;
745a5d21
CC
1021 }
1022 status = WMI_execute_u32(method_id, 0, &result);
1023
1024 if (ACPI_SUCCESS(status))
1025 *value = (u8)result;
1026
1027 return status;
1028}
1029
38db157d 1030static acpi_status WMID_set_u32(u32 value, u32 cap)
745a5d21
CC
1031{
1032 u32 method_id = 0;
1033 char param;
1034
1035 switch (cap) {
1036 case ACER_CAP_BRIGHTNESS:
1037 if (value > max_brightness)
1038 return AE_BAD_PARAMETER;
1039 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
1040 break;
1041 case ACER_CAP_WIRELESS:
1042 if (value > 1)
1043 return AE_BAD_PARAMETER;
1044 method_id = ACER_WMID_SET_WIRELESS_METHODID;
1045 break;
1046 case ACER_CAP_BLUETOOTH:
1047 if (value > 1)
1048 return AE_BAD_PARAMETER;
1049 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
1050 break;
1051 case ACER_CAP_THREEG:
1052 if (value > 1)
1053 return AE_BAD_PARAMETER;
1054 method_id = ACER_WMID_SET_THREEG_METHODID;
1055 break;
1056 case ACER_CAP_MAILLED:
1057 if (value > 1)
1058 return AE_BAD_PARAMETER;
1059 if (quirks->mailled == 1) {
1060 param = value ? 0x92 : 0x93;
181d683d 1061 i8042_lock_chip();
745a5d21 1062 i8042_command(&param, 0x1059);
181d683d 1063 i8042_unlock_chip();
745a5d21
CC
1064 return 0;
1065 }
1066 break;
1067 default:
08237974 1068 return AE_ERROR;
745a5d21
CC
1069 }
1070 return WMI_execute_u32(method_id, (u32)value, NULL);
1071}
1072
72e71de1
LCY
1073static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1074{
1075 struct wmid3_gds_return_value return_value;
1076 acpi_status status;
1077 union acpi_object *obj;
996d23ba 1078 struct wmid3_gds_get_input_param params = {
72e71de1 1079 .function_num = 0x1,
34b6cfab 1080 .hotkey_number = commun_fn_key_number,
72e71de1
LCY
1081 .devices = device,
1082 };
1083 struct acpi_buffer input = {
996d23ba 1084 sizeof(struct wmid3_gds_get_input_param),
72e71de1
LCY
1085 &params
1086 };
1087 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1088
1089 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
1090 if (ACPI_FAILURE(status))
1091 return status;
1092
1093 obj = output.pointer;
1094
1095 if (!obj)
1096 return AE_ERROR;
1097 else if (obj->type != ACPI_TYPE_BUFFER) {
1098 kfree(obj);
1099 return AE_ERROR;
1100 }
1101 if (obj->buffer.length != 8) {
1102 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1103 kfree(obj);
1104 return AE_ERROR;
1105 }
1106
1107 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1108 kfree(obj);
1109
1110 if (return_value.error_code || return_value.ec_return_value)
1111 pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
1112 device,
1113 return_value.error_code,
1114 return_value.ec_return_value);
1115 else
1116 *value = !!(return_value.devices & device);
1117
1118 return status;
1119}
1120
1121static acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
1122{
1123 u16 device;
1124
1125 switch (cap) {
1126 case ACER_CAP_WIRELESS:
1127 device = ACER_WMID3_GDS_WIRELESS;
1128 break;
1129 case ACER_CAP_BLUETOOTH:
1130 device = ACER_WMID3_GDS_BLUETOOTH;
1131 break;
1132 case ACER_CAP_THREEG:
1133 device = ACER_WMID3_GDS_THREEG;
1134 break;
1135 default:
1136 return AE_ERROR;
1137 }
1138 return wmid3_get_device_status(value, device);
1139}
1140
1141static acpi_status wmid3_set_device_status(u32 value, u16 device)
1142{
1143 struct wmid3_gds_return_value return_value;
1144 acpi_status status;
1145 union acpi_object *obj;
1146 u16 devices;
996d23ba 1147 struct wmid3_gds_get_input_param get_params = {
72e71de1 1148 .function_num = 0x1,
34b6cfab 1149 .hotkey_number = commun_fn_key_number,
1d1fc8a7 1150 .devices = commun_func_bitmap,
72e71de1 1151 };
996d23ba
LCY
1152 struct acpi_buffer get_input = {
1153 sizeof(struct wmid3_gds_get_input_param),
1154 &get_params
1155 };
1156 struct wmid3_gds_set_input_param set_params = {
1157 .function_num = 0x2,
1158 .hotkey_number = commun_fn_key_number,
1159 .devices = commun_func_bitmap,
1160 };
1161 struct acpi_buffer set_input = {
1162 sizeof(struct wmid3_gds_set_input_param),
1163 &set_params
72e71de1
LCY
1164 };
1165 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1166 struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
1167
996d23ba 1168 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
72e71de1
LCY
1169 if (ACPI_FAILURE(status))
1170 return status;
1171
1172 obj = output.pointer;
1173
1174 if (!obj)
1175 return AE_ERROR;
1176 else if (obj->type != ACPI_TYPE_BUFFER) {
1177 kfree(obj);
1178 return AE_ERROR;
1179 }
1180 if (obj->buffer.length != 8) {
6e71f38b 1181 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
72e71de1
LCY
1182 kfree(obj);
1183 return AE_ERROR;
1184 }
1185
1186 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1187 kfree(obj);
1188
1189 if (return_value.error_code || return_value.ec_return_value) {
6e71f38b
JP
1190 pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
1191 return_value.error_code,
72e71de1
LCY
1192 return_value.ec_return_value);
1193 return status;
1194 }
1195
1196 devices = return_value.devices;
996d23ba 1197 set_params.devices = (value) ? (devices | device) : (devices & ~device);
72e71de1 1198
996d23ba 1199 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
72e71de1
LCY
1200 if (ACPI_FAILURE(status))
1201 return status;
1202
1203 obj = output2.pointer;
1204
1205 if (!obj)
1206 return AE_ERROR;
1207 else if (obj->type != ACPI_TYPE_BUFFER) {
1208 kfree(obj);
1209 return AE_ERROR;
1210 }
1211 if (obj->buffer.length != 4) {
6e71f38b 1212 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
72e71de1
LCY
1213 kfree(obj);
1214 return AE_ERROR;
1215 }
1216
1217 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1218 kfree(obj);
1219
1220 if (return_value.error_code || return_value.ec_return_value)
6e71f38b
JP
1221 pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
1222 return_value.error_code,
72e71de1
LCY
1223 return_value.ec_return_value);
1224
1225 return status;
1226}
1227
1228static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
1229{
1230 u16 device;
1231
1232 switch (cap) {
1233 case ACER_CAP_WIRELESS:
1234 device = ACER_WMID3_GDS_WIRELESS;
1235 break;
1236 case ACER_CAP_BLUETOOTH:
1237 device = ACER_WMID3_GDS_BLUETOOTH;
1238 break;
1239 case ACER_CAP_THREEG:
1240 device = ACER_WMID3_GDS_THREEG;
1241 break;
1242 default:
1243 return AE_ERROR;
1244 }
1245 return wmid3_set_device_status(value, device);
1246}
1247
76d51dd9 1248static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
6c3df88f
LCY
1249{
1250 struct hotkey_function_type_aa *type_aa;
1251
1252 /* We are looking for OEM-specific Type AAh */
1253 if (header->type != 0xAA)
1254 return;
1255
1256 has_type_aa = true;
1257 type_aa = (struct hotkey_function_type_aa *) header;
1258
cae15702 1259 pr_info("Function bitmap for Communication Button: 0x%x\n",
6c3df88f 1260 type_aa->commun_func_bitmap);
1d1fc8a7 1261 commun_func_bitmap = type_aa->commun_func_bitmap;
6c3df88f
LCY
1262
1263 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
1264 interface->capability |= ACER_CAP_WIRELESS;
1265 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
1266 interface->capability |= ACER_CAP_THREEG;
1267 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
1268 interface->capability |= ACER_CAP_BLUETOOTH;
d2ddc327 1269 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN)
3e2bc5c5 1270 commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN;
34b6cfab
LCY
1271
1272 commun_fn_key_number = type_aa->commun_fn_key_number;
6c3df88f
LCY
1273}
1274
76d51dd9 1275static acpi_status __init WMID_set_capabilities(void)
745a5d21
CC
1276{
1277 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1278 union acpi_object *obj;
1279 acpi_status status;
1280 u32 devices;
1281
62fc743c 1282 status = wmi_query_block(WMID_GUID2, 0, &out);
745a5d21
CC
1283 if (ACPI_FAILURE(status))
1284 return status;
1285
1286 obj = (union acpi_object *) out.pointer;
f20aaba9
LCY
1287 if (obj) {
1288 if (obj->type == ACPI_TYPE_BUFFER &&
1289 (obj->buffer.length == sizeof(u32) ||
1290 obj->buffer.length == sizeof(u64))) {
1291 devices = *((u32 *) obj->buffer.pointer);
1292 } else if (obj->type == ACPI_TYPE_INTEGER) {
1293 devices = (u32) obj->integer.value;
f24c96ea
LCY
1294 } else {
1295 kfree(out.pointer);
1296 return AE_ERROR;
f20aaba9 1297 }
745a5d21 1298 } else {
66904863 1299 kfree(out.pointer);
745a5d21
CC
1300 return AE_ERROR;
1301 }
1302
1fbc01a7
LCY
1303 pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
1304 if (devices & 0x07)
1305 interface->capability |= ACER_CAP_WIRELESS;
72e71de1
LCY
1306 if (devices & 0x40)
1307 interface->capability |= ACER_CAP_THREEG;
1308 if (devices & 0x10)
1309 interface->capability |= ACER_CAP_BLUETOOTH;
745a5d21 1310
745a5d21
CC
1311 if (!(devices & 0x20))
1312 max_brightness = 0x9;
1313
66904863 1314 kfree(out.pointer);
745a5d21
CC
1315 return status;
1316}
1317
1318static struct wmi_interface wmid_interface = {
1319 .type = ACER_WMID,
1320};
1321
72e71de1
LCY
1322static struct wmi_interface wmid_v2_interface = {
1323 .type = ACER_WMID_v2,
1324};
1325
745a5d21
CC
1326/*
1327 * Generic Device (interface-independent)
1328 */
1329
1330static acpi_status get_u32(u32 *value, u32 cap)
1331{
08237974 1332 acpi_status status = AE_ERROR;
745a5d21
CC
1333
1334 switch (interface->type) {
1335 case ACER_AMW0:
38db157d 1336 status = AMW0_get_u32(value, cap);
745a5d21
CC
1337 break;
1338 case ACER_AMW0_V2:
1339 if (cap == ACER_CAP_MAILLED) {
38db157d 1340 status = AMW0_get_u32(value, cap);
745a5d21
CC
1341 break;
1342 }
1343 case ACER_WMID:
38db157d 1344 status = WMID_get_u32(value, cap);
745a5d21 1345 break;
72e71de1
LCY
1346 case ACER_WMID_v2:
1347 if (cap & (ACER_CAP_WIRELESS |
1348 ACER_CAP_BLUETOOTH |
1349 ACER_CAP_THREEG))
1350 status = wmid_v2_get_u32(value, cap);
1351 else if (wmi_has_guid(WMID_GUID2))
38db157d 1352 status = WMID_get_u32(value, cap);
72e71de1 1353 break;
745a5d21
CC
1354 }
1355
1356 return status;
1357}
1358
1359static acpi_status set_u32(u32 value, u32 cap)
1360{
5c742b45
CC
1361 acpi_status status;
1362
745a5d21
CC
1363 if (interface->capability & cap) {
1364 switch (interface->type) {
1365 case ACER_AMW0:
38db157d 1366 return AMW0_set_u32(value, cap);
745a5d21 1367 case ACER_AMW0_V2:
5c742b45 1368 if (cap == ACER_CAP_MAILLED)
38db157d 1369 return AMW0_set_u32(value, cap);
5c742b45
CC
1370
1371 /*
1372 * On some models, some WMID methods don't toggle
1373 * properly. For those cases, we want to run the AMW0
1374 * method afterwards to be certain we've really toggled
1375 * the device state.
1376 */
1377 if (cap == ACER_CAP_WIRELESS ||
1378 cap == ACER_CAP_BLUETOOTH) {
38db157d 1379 status = WMID_set_u32(value, cap);
5c742b45
CC
1380 if (ACPI_FAILURE(status))
1381 return status;
1382
38db157d 1383 return AMW0_set_u32(value, cap);
5c742b45 1384 }
745a5d21 1385 case ACER_WMID:
38db157d 1386 return WMID_set_u32(value, cap);
72e71de1
LCY
1387 case ACER_WMID_v2:
1388 if (cap & (ACER_CAP_WIRELESS |
1389 ACER_CAP_BLUETOOTH |
1390 ACER_CAP_THREEG))
1391 return wmid_v2_set_u32(value, cap);
1392 else if (wmi_has_guid(WMID_GUID2))
38db157d 1393 return WMID_set_u32(value, cap);
745a5d21
CC
1394 default:
1395 return AE_BAD_PARAMETER;
1396 }
1397 }
1398 return AE_BAD_PARAMETER;
1399}
1400
1401static void __init acer_commandline_init(void)
1402{
1403 /*
1404 * These will all fail silently if the value given is invalid, or the
1405 * capability isn't available on the given interface
1406 */
c2647b5e
LCY
1407 if (mailled >= 0)
1408 set_u32(mailled, ACER_CAP_MAILLED);
1409 if (!has_type_aa && threeg >= 0)
6c3df88f 1410 set_u32(threeg, ACER_CAP_THREEG);
c2647b5e
LCY
1411 if (brightness >= 0)
1412 set_u32(brightness, ACER_CAP_BRIGHTNESS);
745a5d21
CC
1413}
1414
1415/*
1416 * LED device (Mail LED only, no other LEDs known yet)
1417 */
1418static void mail_led_set(struct led_classdev *led_cdev,
1419enum led_brightness value)
1420{
1421 set_u32(value, ACER_CAP_MAILLED);
1422}
1423
1424static struct led_classdev mail_led = {
343c0042 1425 .name = "acer-wmi::mail",
745a5d21
CC
1426 .brightness_set = mail_led_set,
1427};
1428
b859f159 1429static int acer_led_init(struct device *dev)
745a5d21
CC
1430{
1431 return led_classdev_register(dev, &mail_led);
1432}
1433
1434static void acer_led_exit(void)
1435{
9a0b74fd 1436 set_u32(LED_OFF, ACER_CAP_MAILLED);
745a5d21
CC
1437 led_classdev_unregister(&mail_led);
1438}
1439
1440/*
1441 * Backlight device
1442 */
1443static struct backlight_device *acer_backlight_device;
1444
1445static int read_brightness(struct backlight_device *bd)
1446{
1447 u32 value;
1448 get_u32(&value, ACER_CAP_BRIGHTNESS);
1449 return value;
1450}
1451
1452static int update_bl_status(struct backlight_device *bd)
1453{
f2b585b4
CC
1454 int intensity = bd->props.brightness;
1455
1456 if (bd->props.power != FB_BLANK_UNBLANK)
1457 intensity = 0;
1458 if (bd->props.fb_blank != FB_BLANK_UNBLANK)
1459 intensity = 0;
1460
1461 set_u32(intensity, ACER_CAP_BRIGHTNESS);
1462
745a5d21
CC
1463 return 0;
1464}
1465
acc2472e 1466static const struct backlight_ops acer_bl_ops = {
745a5d21
CC
1467 .get_brightness = read_brightness,
1468 .update_status = update_bl_status,
1469};
1470
b859f159 1471static int acer_backlight_init(struct device *dev)
745a5d21 1472{
a19a6ee6 1473 struct backlight_properties props;
745a5d21
CC
1474 struct backlight_device *bd;
1475
a19a6ee6 1476 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 1477 props.type = BACKLIGHT_PLATFORM;
a19a6ee6
MG
1478 props.max_brightness = max_brightness;
1479 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
1480 &props);
745a5d21 1481 if (IS_ERR(bd)) {
cae15702 1482 pr_err("Could not register Acer backlight device\n");
745a5d21
CC
1483 acer_backlight_device = NULL;
1484 return PTR_ERR(bd);
1485 }
1486
1487 acer_backlight_device = bd;
1488
f2b585b4 1489 bd->props.power = FB_BLANK_UNBLANK;
6f6ef82c 1490 bd->props.brightness = read_brightness(bd);
745a5d21
CC
1491 backlight_update_status(bd);
1492 return 0;
1493}
1494
7560e385 1495static void acer_backlight_exit(void)
745a5d21
CC
1496{
1497 backlight_device_unregister(acer_backlight_device);
1498}
1499
1eb3fe1d
MV
1500/*
1501 * Accelerometer device
1502 */
1503static acpi_handle gsensor_handle;
1504
1505static int acer_gsensor_init(void)
1506{
1507 acpi_status status;
1508 struct acpi_buffer output;
1509 union acpi_object out_obj;
1510
1511 output.length = sizeof(out_obj);
1512 output.pointer = &out_obj;
1513 status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
1514 if (ACPI_FAILURE(status))
1515 return -1;
1516
1517 return 0;
1518}
1519
1520static int acer_gsensor_open(struct input_dev *input)
1521{
1522 return acer_gsensor_init();
1523}
1524
1525static int acer_gsensor_event(void)
1526{
1527 acpi_status status;
1528 struct acpi_buffer output;
1529 union acpi_object out_obj[5];
1530
1531 if (!has_cap(ACER_CAP_ACCEL))
1532 return -1;
1533
1534 output.length = sizeof(out_obj);
1535 output.pointer = out_obj;
1536
1537 status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
1538 if (ACPI_FAILURE(status))
1539 return -1;
1540
1541 if (out_obj->package.count != 4)
1542 return -1;
1543
1544 input_report_abs(acer_wmi_accel_dev, ABS_X,
1545 (s16)out_obj->package.elements[0].integer.value);
1546 input_report_abs(acer_wmi_accel_dev, ABS_Y,
1547 (s16)out_obj->package.elements[1].integer.value);
1548 input_report_abs(acer_wmi_accel_dev, ABS_Z,
1549 (s16)out_obj->package.elements[2].integer.value);
1550 input_sync(acer_wmi_accel_dev);
1551 return 0;
1552}
1553
0606e1ab
CC
1554/*
1555 * Rfkill devices
1556 */
0606e1ab
CC
1557static void acer_rfkill_update(struct work_struct *ignored);
1558static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
1559static void acer_rfkill_update(struct work_struct *ignored)
1560{
1561 u32 state;
1562 acpi_status status;
1563
1709adab
LCY
1564 if (has_cap(ACER_CAP_WIRELESS)) {
1565 status = get_u32(&state, ACER_CAP_WIRELESS);
1566 if (ACPI_SUCCESS(status)) {
1567 if (quirks->wireless == 3)
1568 rfkill_set_hw_state(wireless_rfkill, !state);
1569 else
1570 rfkill_set_sw_state(wireless_rfkill, !state);
15b956a0
LCY
1571 }
1572 }
0606e1ab
CC
1573
1574 if (has_cap(ACER_CAP_BLUETOOTH)) {
1575 status = get_u32(&state, ACER_CAP_BLUETOOTH);
1576 if (ACPI_SUCCESS(status))
a878417c 1577 rfkill_set_sw_state(bluetooth_rfkill, !state);
0606e1ab
CC
1578 }
1579
b3c9092b 1580 if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
72e71de1 1581 status = get_u32(&state, ACER_WMID3_GDS_THREEG);
b3c9092b
LCY
1582 if (ACPI_SUCCESS(status))
1583 rfkill_set_sw_state(threeg_rfkill, !state);
1584 }
1585
ae3a1b46 1586 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
0606e1ab
CC
1587}
1588
19d337df 1589static int acer_rfkill_set(void *data, bool blocked)
0606e1ab
CC
1590{
1591 acpi_status status;
19d337df 1592 u32 cap = (unsigned long)data;
8215af01
LCY
1593
1594 if (rfkill_inited) {
72e71de1 1595 status = set_u32(!blocked, cap);
8215af01
LCY
1596 if (ACPI_FAILURE(status))
1597 return -ENODEV;
1598 }
1599
0606e1ab
CC
1600 return 0;
1601}
1602
19d337df
JB
1603static const struct rfkill_ops acer_rfkill_ops = {
1604 .set_block = acer_rfkill_set,
1605};
1606
1607static struct rfkill *acer_rfkill_register(struct device *dev,
1608 enum rfkill_type type,
1609 char *name, u32 cap)
0606e1ab
CC
1610{
1611 int err;
0606e1ab 1612 struct rfkill *rfkill_dev;
466449cf
LCY
1613 u32 state;
1614 acpi_status status;
0606e1ab 1615
19d337df
JB
1616 rfkill_dev = rfkill_alloc(name, dev, type,
1617 &acer_rfkill_ops,
1618 (void *)(unsigned long)cap);
0606e1ab
CC
1619 if (!rfkill_dev)
1620 return ERR_PTR(-ENOMEM);
0606e1ab 1621
72e71de1 1622 status = get_u32(&state, cap);
466449cf 1623
0606e1ab
CC
1624 err = rfkill_register(rfkill_dev);
1625 if (err) {
19d337df 1626 rfkill_destroy(rfkill_dev);
0606e1ab
CC
1627 return ERR_PTR(err);
1628 }
8215af01
LCY
1629
1630 if (ACPI_SUCCESS(status))
1631 rfkill_set_sw_state(rfkill_dev, !state);
1632
0606e1ab
CC
1633 return rfkill_dev;
1634}
1635
1636static int acer_rfkill_init(struct device *dev)
1637{
1709adab
LCY
1638 int err;
1639
1640 if (has_cap(ACER_CAP_WIRELESS)) {
1641 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
1642 "acer-wireless", ACER_CAP_WIRELESS);
1643 if (IS_ERR(wireless_rfkill)) {
1644 err = PTR_ERR(wireless_rfkill);
1645 goto error_wireless;
1646 }
1647 }
0606e1ab
CC
1648
1649 if (has_cap(ACER_CAP_BLUETOOTH)) {
1650 bluetooth_rfkill = acer_rfkill_register(dev,
1651 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
1652 ACER_CAP_BLUETOOTH);
1653 if (IS_ERR(bluetooth_rfkill)) {
1709adab
LCY
1654 err = PTR_ERR(bluetooth_rfkill);
1655 goto error_bluetooth;
0606e1ab
CC
1656 }
1657 }
1658
b3c9092b
LCY
1659 if (has_cap(ACER_CAP_THREEG)) {
1660 threeg_rfkill = acer_rfkill_register(dev,
1661 RFKILL_TYPE_WWAN, "acer-threeg",
1662 ACER_CAP_THREEG);
1663 if (IS_ERR(threeg_rfkill)) {
1709adab
LCY
1664 err = PTR_ERR(threeg_rfkill);
1665 goto error_threeg;
b3c9092b
LCY
1666 }
1667 }
1668
8215af01
LCY
1669 rfkill_inited = true;
1670
1709adab
LCY
1671 if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1672 has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
70a9b904
LCY
1673 schedule_delayed_work(&acer_rfkill_work,
1674 round_jiffies_relative(HZ));
0606e1ab
CC
1675
1676 return 0;
1709adab
LCY
1677
1678error_threeg:
1679 if (has_cap(ACER_CAP_BLUETOOTH)) {
1680 rfkill_unregister(bluetooth_rfkill);
1681 rfkill_destroy(bluetooth_rfkill);
1682 }
1683error_bluetooth:
1684 if (has_cap(ACER_CAP_WIRELESS)) {
1685 rfkill_unregister(wireless_rfkill);
1686 rfkill_destroy(wireless_rfkill);
1687 }
1688error_wireless:
1689 return err;
0606e1ab
CC
1690}
1691
1692static void acer_rfkill_exit(void)
1693{
1709adab
LCY
1694 if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1695 has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
70a9b904 1696 cancel_delayed_work_sync(&acer_rfkill_work);
19d337df 1697
1709adab
LCY
1698 if (has_cap(ACER_CAP_WIRELESS)) {
1699 rfkill_unregister(wireless_rfkill);
1700 rfkill_destroy(wireless_rfkill);
1701 }
19d337df 1702
0606e1ab 1703 if (has_cap(ACER_CAP_BLUETOOTH)) {
0606e1ab 1704 rfkill_unregister(bluetooth_rfkill);
19d337df 1705 rfkill_destroy(bluetooth_rfkill);
0606e1ab 1706 }
b3c9092b
LCY
1707
1708 if (has_cap(ACER_CAP_THREEG)) {
1709 rfkill_unregister(threeg_rfkill);
1710 rfkill_destroy(threeg_rfkill);
1711 }
0606e1ab
CC
1712 return;
1713}
1714
3fdca87d
LCY
1715static void acer_wmi_notify(u32 value, void *context)
1716{
1717 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1718 union acpi_object *obj;
1719 struct event_return_value return_value;
1720 acpi_status status;
92530664
SF
1721 u16 device_state;
1722 const struct key_entry *key;
8e2286ce 1723 u32 scancode;
3fdca87d
LCY
1724
1725 status = wmi_get_event_data(value, &response);
1726 if (status != AE_OK) {
249c720d 1727 pr_warn("bad event status 0x%x\n", status);
3fdca87d
LCY
1728 return;
1729 }
1730
1731 obj = (union acpi_object *)response.pointer;
1732
1733 if (!obj)
1734 return;
1735 if (obj->type != ACPI_TYPE_BUFFER) {
249c720d 1736 pr_warn("Unknown response received %d\n", obj->type);
3fdca87d
LCY
1737 kfree(obj);
1738 return;
1739 }
1740 if (obj->buffer.length != 8) {
249c720d 1741 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
3fdca87d
LCY
1742 kfree(obj);
1743 return;
1744 }
1745
1746 return_value = *((struct event_return_value *)obj->buffer.pointer);
1747 kfree(obj);
1748
1749 switch (return_value.function) {
1750 case WMID_HOTKEY_EVENT:
92530664
SF
1751 device_state = return_value.device_state;
1752 pr_debug("device state: 0x%x\n", device_state);
1753
1754 key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
1755 return_value.key_num);
1756 if (!key) {
249c720d 1757 pr_warn("Unknown key number - 0x%x\n",
3fdca87d 1758 return_value.key_num);
92530664 1759 } else {
8e2286ce 1760 scancode = return_value.key_num;
92530664
SF
1761 switch (key->keycode) {
1762 case KEY_WLAN:
1763 case KEY_BLUETOOTH:
1764 if (has_cap(ACER_CAP_WIRELESS))
1765 rfkill_set_sw_state(wireless_rfkill,
1766 !(device_state & ACER_WMID3_GDS_WIRELESS));
1767 if (has_cap(ACER_CAP_THREEG))
1768 rfkill_set_sw_state(threeg_rfkill,
1769 !(device_state & ACER_WMID3_GDS_THREEG));
1770 if (has_cap(ACER_CAP_BLUETOOTH))
1771 rfkill_set_sw_state(bluetooth_rfkill,
1772 !(device_state & ACER_WMID3_GDS_BLUETOOTH));
1773 break;
8e2286ce
LCY
1774 case KEY_TOUCHPAD_TOGGLE:
1775 scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ?
1776 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF;
92530664 1777 }
8e2286ce 1778 sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
92530664 1779 }
3fdca87d 1780 break;
1eb3fe1d
MV
1781 case WMID_ACCEL_EVENT:
1782 acer_gsensor_event();
1783 break;
3fdca87d 1784 default:
249c720d 1785 pr_warn("Unknown function number - %d - %d\n",
3fdca87d
LCY
1786 return_value.function, return_value.key_num);
1787 break;
1788 }
1789}
1790
76d51dd9 1791static acpi_status __init
280642c3
CC
1792wmid3_set_function_mode(struct func_input_params *params,
1793 struct func_return_value *return_value)
59ccf2f3
FLCY
1794{
1795 acpi_status status;
1796 union acpi_object *obj;
1797
280642c3 1798 struct acpi_buffer input = { sizeof(struct func_input_params), params };
59ccf2f3
FLCY
1799 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1800
1801 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
1802 if (ACPI_FAILURE(status))
1803 return status;
1804
1805 obj = output.pointer;
1806
1807 if (!obj)
1808 return AE_ERROR;
1809 else if (obj->type != ACPI_TYPE_BUFFER) {
1810 kfree(obj);
1811 return AE_ERROR;
1812 }
1813 if (obj->buffer.length != 4) {
249c720d 1814 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
59ccf2f3
FLCY
1815 kfree(obj);
1816 return AE_ERROR;
1817 }
1818
280642c3 1819 *return_value = *((struct func_return_value *)obj->buffer.pointer);
59ccf2f3
FLCY
1820 kfree(obj);
1821
1822 return status;
1823}
1824
76d51dd9 1825static int __init acer_wmi_enable_ec_raw(void)
59ccf2f3 1826{
280642c3 1827 struct func_return_value return_value;
59ccf2f3 1828 acpi_status status;
280642c3 1829 struct func_input_params params = {
59ccf2f3
FLCY
1830 .function_num = 0x1,
1831 .commun_devices = 0xFFFF,
1832 .devices = 0xFFFF,
280642c3
CC
1833 .app_status = 0x00, /* Launch Manager Deactive */
1834 .app_mask = 0x01,
59ccf2f3
FLCY
1835 };
1836
280642c3 1837 status = wmid3_set_function_mode(&params, &return_value);
59ccf2f3
FLCY
1838
1839 if (return_value.error_code || return_value.ec_return_value)
249c720d
JP
1840 pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
1841 return_value.error_code,
1842 return_value.ec_return_value);
59ccf2f3 1843 else
249c720d 1844 pr_info("Enabled EC raw mode\n");
59ccf2f3
FLCY
1845
1846 return status;
1847}
1848
76d51dd9 1849static int __init acer_wmi_enable_lm(void)
59ccf2f3 1850{
280642c3 1851 struct func_return_value return_value;
59ccf2f3 1852 acpi_status status;
280642c3 1853 struct func_input_params params = {
59ccf2f3
FLCY
1854 .function_num = 0x1,
1855 .commun_devices = 0xFFFF,
1856 .devices = 0xFFFF,
280642c3
CC
1857 .app_status = 0x01, /* Launch Manager Active */
1858 .app_mask = 0x01,
59ccf2f3
FLCY
1859 };
1860
280642c3 1861 status = wmid3_set_function_mode(&params, &return_value);
59ccf2f3
FLCY
1862
1863 if (return_value.error_code || return_value.ec_return_value)
249c720d
JP
1864 pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
1865 return_value.error_code,
1866 return_value.ec_return_value);
59ccf2f3
FLCY
1867
1868 return status;
1869}
1870
280642c3
CC
1871static int __init acer_wmi_enable_rf_button(void)
1872{
1873 struct func_return_value return_value;
1874 acpi_status status;
1875 struct func_input_params params = {
1876 .function_num = 0x1,
1877 .commun_devices = 0xFFFF,
1878 .devices = 0xFFFF,
1879 .app_status = 0x10, /* RF Button Active */
1880 .app_mask = 0x10,
1881 };
1882
1883 status = wmid3_set_function_mode(&params, &return_value);
1884
1885 if (return_value.error_code || return_value.ec_return_value)
1886 pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n",
1887 return_value.error_code,
1888 return_value.ec_return_value);
1889
1890 return status;
1891}
1892
98d610c3
LCY
1893#define ACER_WMID_ACCEL_HID "BST0001"
1894
1eb3fe1d
MV
1895static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
1896 void *ctx, void **retval)
1897{
98d610c3
LCY
1898 struct acpi_device *dev;
1899
1900 if (!strcmp(ctx, "SENR")) {
1901 if (acpi_bus_get_device(ah, &dev))
1902 return AE_OK;
f9ac89f5 1903 if (strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
98d610c3
LCY
1904 return AE_OK;
1905 } else
1906 return AE_OK;
1907
1eb3fe1d 1908 *(acpi_handle *)retval = ah;
98d610c3
LCY
1909
1910 return AE_CTRL_TERMINATE;
1eb3fe1d
MV
1911}
1912
1913static int __init acer_wmi_get_handle(const char *name, const char *prop,
1914 acpi_handle *ah)
1915{
1916 acpi_status status;
1917 acpi_handle handle;
1918
1919 BUG_ON(!name || !ah);
1920
24237c43 1921 handle = NULL;
1eb3fe1d
MV
1922 status = acpi_get_devices(prop, acer_wmi_get_handle_cb,
1923 (void *)name, &handle);
f9ac89f5 1924 if (ACPI_SUCCESS(status) && handle) {
1eb3fe1d
MV
1925 *ah = handle;
1926 return 0;
1927 } else {
1928 return -ENODEV;
1929 }
1930}
1931
1932static int __init acer_wmi_accel_setup(void)
1933{
1934 int err;
1935
98d610c3 1936 err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
1eb3fe1d
MV
1937 if (err)
1938 return err;
1939
1940 interface->capability |= ACER_CAP_ACCEL;
1941
1942 acer_wmi_accel_dev = input_allocate_device();
1943 if (!acer_wmi_accel_dev)
1944 return -ENOMEM;
1945
1946 acer_wmi_accel_dev->open = acer_gsensor_open;
1947
1948 acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
1949 acer_wmi_accel_dev->phys = "wmi/input1";
1950 acer_wmi_accel_dev->id.bustype = BUS_HOST;
1951 acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
1952 input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
1953 input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
1954 input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
1955
1956 err = input_register_device(acer_wmi_accel_dev);
1957 if (err)
1958 goto err_free_dev;
1959
1960 return 0;
1961
1962err_free_dev:
1963 input_free_device(acer_wmi_accel_dev);
1964 return err;
1965}
1966
1967static void acer_wmi_accel_destroy(void)
1968{
1969 input_unregister_device(acer_wmi_accel_dev);
1eb3fe1d
MV
1970}
1971
3fdca87d
LCY
1972static int __init acer_wmi_input_setup(void)
1973{
1974 acpi_status status;
1975 int err;
1976
1977 acer_wmi_input_dev = input_allocate_device();
1978 if (!acer_wmi_input_dev)
1979 return -ENOMEM;
1980
1981 acer_wmi_input_dev->name = "Acer WMI hotkeys";
1982 acer_wmi_input_dev->phys = "wmi/input0";
1983 acer_wmi_input_dev->id.bustype = BUS_HOST;
1984
1985 err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
1986 if (err)
1987 goto err_free_dev;
1988
1989 status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
1990 acer_wmi_notify, NULL);
1991 if (ACPI_FAILURE(status)) {
1992 err = -EIO;
cd1aaef0 1993 goto err_free_dev;
3fdca87d
LCY
1994 }
1995
1996 err = input_register_device(acer_wmi_input_dev);
1997 if (err)
1998 goto err_uninstall_notifier;
1999
2000 return 0;
2001
2002err_uninstall_notifier:
2003 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
3fdca87d
LCY
2004err_free_dev:
2005 input_free_device(acer_wmi_input_dev);
2006 return err;
2007}
2008
2009static void acer_wmi_input_destroy(void)
2010{
2011 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
3fdca87d
LCY
2012 input_unregister_device(acer_wmi_input_dev);
2013}
2014
81143522
CC
2015/*
2016 * debugfs functions
2017 */
2018static u32 get_wmid_devices(void)
2019{
2020 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
2021 union acpi_object *obj;
2022 acpi_status status;
66904863 2023 u32 devices = 0;
81143522 2024
62fc743c 2025 status = wmi_query_block(WMID_GUID2, 0, &out);
81143522
CC
2026 if (ACPI_FAILURE(status))
2027 return 0;
2028
2029 obj = (union acpi_object *) out.pointer;
f20aaba9
LCY
2030 if (obj) {
2031 if (obj->type == ACPI_TYPE_BUFFER &&
2032 (obj->buffer.length == sizeof(u32) ||
2033 obj->buffer.length == sizeof(u64))) {
2034 devices = *((u32 *) obj->buffer.pointer);
2035 } else if (obj->type == ACPI_TYPE_INTEGER) {
2036 devices = (u32) obj->integer.value;
2037 }
81143522 2038 }
66904863
AL
2039
2040 kfree(out.pointer);
2041 return devices;
81143522
CC
2042}
2043
745a5d21
CC
2044/*
2045 * Platform device
2046 */
b859f159 2047static int acer_platform_probe(struct platform_device *device)
745a5d21
CC
2048{
2049 int err;
2050
2051 if (has_cap(ACER_CAP_MAILLED)) {
2052 err = acer_led_init(&device->dev);
2053 if (err)
2054 goto error_mailled;
2055 }
2056
2057 if (has_cap(ACER_CAP_BRIGHTNESS)) {
2058 err = acer_backlight_init(&device->dev);
2059 if (err)
2060 goto error_brightness;
2061 }
2062
0606e1ab 2063 err = acer_rfkill_init(&device->dev);
350e3290
AW
2064 if (err)
2065 goto error_rfkill;
0606e1ab
CC
2066
2067 return err;
745a5d21 2068
350e3290
AW
2069error_rfkill:
2070 if (has_cap(ACER_CAP_BRIGHTNESS))
2071 acer_backlight_exit();
745a5d21 2072error_brightness:
350e3290
AW
2073 if (has_cap(ACER_CAP_MAILLED))
2074 acer_led_exit();
745a5d21
CC
2075error_mailled:
2076 return err;
2077}
2078
2079static int acer_platform_remove(struct platform_device *device)
2080{
2081 if (has_cap(ACER_CAP_MAILLED))
2082 acer_led_exit();
2083 if (has_cap(ACER_CAP_BRIGHTNESS))
2084 acer_backlight_exit();
0606e1ab
CC
2085
2086 acer_rfkill_exit();
745a5d21
CC
2087 return 0;
2088}
2089
80f65558 2090#ifdef CONFIG_PM_SLEEP
3c33be0b 2091static int acer_suspend(struct device *dev)
745a5d21
CC
2092{
2093 u32 value;
2094 struct acer_data *data = &interface->data;
2095
2096 if (!data)
2097 return -ENOMEM;
2098
745a5d21
CC
2099 if (has_cap(ACER_CAP_MAILLED)) {
2100 get_u32(&value, ACER_CAP_MAILLED);
9a0b74fd 2101 set_u32(LED_OFF, ACER_CAP_MAILLED);
745a5d21
CC
2102 data->mailled = value;
2103 }
2104
2105 if (has_cap(ACER_CAP_BRIGHTNESS)) {
2106 get_u32(&value, ACER_CAP_BRIGHTNESS);
2107 data->brightness = value;
2108 }
2109
2110 return 0;
2111}
2112
3c33be0b 2113static int acer_resume(struct device *dev)
745a5d21
CC
2114{
2115 struct acer_data *data = &interface->data;
2116
2117 if (!data)
2118 return -ENOMEM;
2119
745a5d21
CC
2120 if (has_cap(ACER_CAP_MAILLED))
2121 set_u32(data->mailled, ACER_CAP_MAILLED);
2122
2123 if (has_cap(ACER_CAP_BRIGHTNESS))
2124 set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
2125
1eb3fe1d
MV
2126 if (has_cap(ACER_CAP_ACCEL))
2127 acer_gsensor_init();
2128
745a5d21
CC
2129 return 0;
2130}
80f65558
MK
2131#else
2132#define acer_suspend NULL
2133#define acer_resume NULL
2134#endif
745a5d21 2135
3c33be0b
RW
2136static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
2137
9a0b74fd
PR
2138static void acer_platform_shutdown(struct platform_device *device)
2139{
2140 struct acer_data *data = &interface->data;
2141
2142 if (!data)
2143 return;
2144
2145 if (has_cap(ACER_CAP_MAILLED))
2146 set_u32(LED_OFF, ACER_CAP_MAILLED);
2147}
2148
745a5d21
CC
2149static struct platform_driver acer_platform_driver = {
2150 .driver = {
2151 .name = "acer-wmi",
3c33be0b 2152 .pm = &acer_pm,
745a5d21
CC
2153 },
2154 .probe = acer_platform_probe,
2155 .remove = acer_platform_remove,
9a0b74fd 2156 .shutdown = acer_platform_shutdown,
745a5d21
CC
2157};
2158
2159static struct platform_device *acer_platform_device;
2160
81143522
CC
2161static void remove_debugfs(void)
2162{
2163 debugfs_remove(interface->debug.devices);
2164 debugfs_remove(interface->debug.root);
2165}
2166
76d51dd9 2167static int __init create_debugfs(void)
81143522
CC
2168{
2169 interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
2170 if (!interface->debug.root) {
cae15702 2171 pr_err("Failed to create debugfs directory");
81143522
CC
2172 return -ENOMEM;
2173 }
2174
2175 interface->debug.devices = debugfs_create_u32("devices", S_IRUGO,
2176 interface->debug.root,
2177 &interface->debug.wmid_devices);
2178 if (!interface->debug.devices)
2179 goto error_debugfs;
2180
2181 return 0;
2182
2183error_debugfs:
39dbbb45 2184 remove_debugfs();
81143522
CC
2185 return -ENOMEM;
2186}
2187
745a5d21
CC
2188static int __init acer_wmi_init(void)
2189{
2190 int err;
2191
cae15702 2192 pr_info("Acer Laptop ACPI-WMI Extras\n");
745a5d21 2193
a74dd5fd 2194 if (dmi_check_system(acer_blacklist)) {
cae15702 2195 pr_info("Blacklisted hardware detected - not loading\n");
a74dd5fd
CC
2196 return -ENODEV;
2197 }
2198
9991d9f2
CC
2199 find_quirks();
2200
5241b193
LCY
2201 /*
2202 * The AMW0_GUID1 wmi is not only found on Acer family but also other
2203 * machines like Lenovo, Fujitsu and Medion. In the past days,
2204 * acer-wmi driver handled those non-Acer machines by quirks list.
2205 * But actually acer-wmi driver was loaded on any machines that have
2206 * AMW0_GUID1. This behavior is strange because those machines should
2207 * be supported by appropriate wmi drivers. e.g. fujitsu-laptop,
2208 * ideapad-laptop. So, here checks the machine that has AMW0_GUID1
2209 * should be in Acer/Gateway/Packard Bell white list, or it's already
2210 * in the past quirk list.
2211 */
2212 if (wmi_has_guid(AMW0_GUID1) &&
2213 !dmi_check_system(amw0_whitelist) &&
2214 quirks == &quirk_unknown) {
2215 pr_err("Unsupported machine has AMW0_GUID1, unable to load\n");
2216 return -ENODEV;
2217 }
2218
745a5d21
CC
2219 /*
2220 * Detect which ACPI-WMI interface we're using.
2221 */
2222 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
2223 interface = &AMW0_V2_interface;
2224
2225 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
2226 interface = &wmid_interface;
2227
72e71de1
LCY
2228 if (wmi_has_guid(WMID_GUID3))
2229 interface = &wmid_v2_interface;
2230
2231 if (interface)
2232 dmi_walk(type_aa_dmi_decode, NULL);
2233
745a5d21 2234 if (wmi_has_guid(WMID_GUID2) && interface) {
72e71de1 2235 if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
cae15702 2236 pr_err("Unable to detect available WMID devices\n");
745a5d21
CC
2237 return -ENODEV;
2238 }
72e71de1
LCY
2239 /* WMID always provides brightness methods */
2240 interface->capability |= ACER_CAP_BRIGHTNESS;
2241 } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
cae15702 2242 pr_err("No WMID device detection method found\n");
745a5d21
CC
2243 return -ENODEV;
2244 }
2245
2246 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
2247 interface = &AMW0_interface;
2248
2249 if (ACPI_FAILURE(AMW0_set_capabilities())) {
cae15702 2250 pr_err("Unable to detect available AMW0 devices\n");
745a5d21
CC
2251 return -ENODEV;
2252 }
2253 }
2254
9b963c40
CC
2255 if (wmi_has_guid(AMW0_GUID1))
2256 AMW0_find_mailled();
745a5d21 2257
745a5d21 2258 if (!interface) {
cae15702 2259 pr_err("No or unsupported WMI interface, unable to load\n");
745a5d21
CC
2260 return -ENODEV;
2261 }
2262
83097aca
AV
2263 set_quirks();
2264
a60b2176 2265 if (dmi_check_system(video_vendor_dmi_table))
9a65f0df
HG
2266 acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
2267
2268 if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
a60b2176 2269 interface->capability &= ~ACER_CAP_BRIGHTNESS;
febf2d95 2270
59ccf2f3 2271 if (wmi_has_guid(WMID_GUID3)) {
280642c3
CC
2272 if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
2273 pr_warn("Cannot enable RF Button Driver\n");
2274
59ccf2f3
FLCY
2275 if (ec_raw_mode) {
2276 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
cae15702 2277 pr_err("Cannot enable EC raw mode\n");
59ccf2f3
FLCY
2278 return -ENODEV;
2279 }
2280 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
cae15702 2281 pr_err("Cannot enable Launch Manager mode\n");
59ccf2f3
FLCY
2282 return -ENODEV;
2283 }
2284 } else if (ec_raw_mode) {
cae15702 2285 pr_info("No WMID EC raw mode enable method\n");
59ccf2f3
FLCY
2286 }
2287
3fdca87d
LCY
2288 if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
2289 err = acer_wmi_input_setup();
2290 if (err)
2291 return err;
98d610c3 2292 err = acer_wmi_accel_setup();
f9ac89f5
LCY
2293 if (err && err != -ENODEV)
2294 pr_warn("Cannot enable accelerometer\n");
3fdca87d
LCY
2295 }
2296
1c79632b
AL
2297 err = platform_driver_register(&acer_platform_driver);
2298 if (err) {
6e71f38b 2299 pr_err("Unable to register platform driver\n");
745a5d21
CC
2300 goto error_platform_register;
2301 }
1c79632b 2302
745a5d21 2303 acer_platform_device = platform_device_alloc("acer-wmi", -1);
1c79632b
AL
2304 if (!acer_platform_device) {
2305 err = -ENOMEM;
2306 goto error_device_alloc;
2307 }
2308
2309 err = platform_device_add(acer_platform_device);
2310 if (err)
2311 goto error_device_add;
745a5d21 2312
81143522
CC
2313 if (wmi_has_guid(WMID_GUID2)) {
2314 interface->debug.wmid_devices = get_wmid_devices();
2315 err = create_debugfs();
2316 if (err)
1c79632b 2317 goto error_create_debugfs;
81143522
CC
2318 }
2319
745a5d21
CC
2320 /* Override any initial settings with values from the commandline */
2321 acer_commandline_init();
2322
2323 return 0;
2324
1c79632b 2325error_create_debugfs:
1c79632b
AL
2326 platform_device_del(acer_platform_device);
2327error_device_add:
2328 platform_device_put(acer_platform_device);
2329error_device_alloc:
2330 platform_driver_unregister(&acer_platform_driver);
745a5d21 2331error_platform_register:
3fdca87d
LCY
2332 if (wmi_has_guid(ACERWMID_EVENT_GUID))
2333 acer_wmi_input_destroy();
1eb3fe1d
MV
2334 if (has_cap(ACER_CAP_ACCEL))
2335 acer_wmi_accel_destroy();
3fdca87d 2336
1c79632b 2337 return err;
745a5d21
CC
2338}
2339
2340static void __exit acer_wmi_exit(void)
2341{
3fdca87d
LCY
2342 if (wmi_has_guid(ACERWMID_EVENT_GUID))
2343 acer_wmi_input_destroy();
2344
1eb3fe1d
MV
2345 if (has_cap(ACER_CAP_ACCEL))
2346 acer_wmi_accel_destroy();
2347
39dbbb45 2348 remove_debugfs();
97ba0af0 2349 platform_device_unregister(acer_platform_device);
745a5d21
CC
2350 platform_driver_unregister(&acer_platform_driver);
2351
cae15702 2352 pr_info("Acer Laptop WMI Extras unloaded\n");
745a5d21
CC
2353 return;
2354}
2355
2356module_init(acer_wmi_init);
2357module_exit(acer_wmi_exit);