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