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