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