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