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