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