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