18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Acer WMI Laptop Extras
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2007-2009	Carlos Corbacho <carlos@strangeworlds.co.uk>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Based on acer_acpi:
88c2ecf20Sopenharmony_ci *    Copyright (C) 2005-2007	E.M. Smith
98c2ecf20Sopenharmony_ci *    Copyright (C) 2007-2008	Carlos Corbacho <cathectic@gmail.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/init.h>
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <linux/dmi.h>
198c2ecf20Sopenharmony_ci#include <linux/fb.h>
208c2ecf20Sopenharmony_ci#include <linux/backlight.h>
218c2ecf20Sopenharmony_ci#include <linux/leds.h>
228c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
238c2ecf20Sopenharmony_ci#include <linux/acpi.h>
248c2ecf20Sopenharmony_ci#include <linux/i8042.h>
258c2ecf20Sopenharmony_ci#include <linux/rfkill.h>
268c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
278c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci#include <linux/input.h>
308c2ecf20Sopenharmony_ci#include <linux/input/sparse-keymap.h>
318c2ecf20Sopenharmony_ci#include <acpi/video.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciACPI_MODULE_NAME(KBUILD_MODNAME);
348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Carlos Corbacho");
358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * Magic Number
408c2ecf20Sopenharmony_ci * Meaning is unknown - this number is required for writing to ACPI for AMW0
418c2ecf20Sopenharmony_ci * (it's also used in acerhk when directly accessing the BIOS)
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci#define ACER_AMW0_WRITE	0x9610
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * Bit masks for the AMW0 interface
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci#define ACER_AMW0_WIRELESS_MASK  0x35
498c2ecf20Sopenharmony_ci#define ACER_AMW0_BLUETOOTH_MASK 0x34
508c2ecf20Sopenharmony_ci#define ACER_AMW0_MAILLED_MASK   0x31
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/*
538c2ecf20Sopenharmony_ci * Method IDs for WMID interface
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ci#define ACER_WMID_GET_WIRELESS_METHODID		1
568c2ecf20Sopenharmony_ci#define ACER_WMID_GET_BLUETOOTH_METHODID	2
578c2ecf20Sopenharmony_ci#define ACER_WMID_GET_BRIGHTNESS_METHODID	3
588c2ecf20Sopenharmony_ci#define ACER_WMID_SET_WIRELESS_METHODID		4
598c2ecf20Sopenharmony_ci#define ACER_WMID_SET_BLUETOOTH_METHODID	5
608c2ecf20Sopenharmony_ci#define ACER_WMID_SET_BRIGHTNESS_METHODID	6
618c2ecf20Sopenharmony_ci#define ACER_WMID_GET_THREEG_METHODID		10
628c2ecf20Sopenharmony_ci#define ACER_WMID_SET_THREEG_METHODID		11
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * Acer ACPI method GUIDs
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_ci#define AMW0_GUID1		"67C3371D-95A3-4C37-BB61-DD47B491DAAB"
688c2ecf20Sopenharmony_ci#define AMW0_GUID2		"431F16ED-0C2B-444C-B267-27DEB140CF9C"
698c2ecf20Sopenharmony_ci#define WMID_GUID1		"6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
708c2ecf20Sopenharmony_ci#define WMID_GUID2		"95764E09-FB56-4E83-B31A-37761F60994A"
718c2ecf20Sopenharmony_ci#define WMID_GUID3		"61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * Acer ACPI event GUIDs
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_ci#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciMODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
798c2ecf20Sopenharmony_ciMODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
808c2ecf20Sopenharmony_ciMODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cienum acer_wmi_event_ids {
838c2ecf20Sopenharmony_ci	WMID_HOTKEY_EVENT = 0x1,
848c2ecf20Sopenharmony_ci	WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5,
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic const struct key_entry acer_wmi_keymap[] __initconst = {
888c2ecf20Sopenharmony_ci	{KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
898c2ecf20Sopenharmony_ci	{KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
908c2ecf20Sopenharmony_ci	{KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */
918c2ecf20Sopenharmony_ci	{KE_KEY, 0x12, {KEY_BLUETOOTH} },	/* BT */
928c2ecf20Sopenharmony_ci	{KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
938c2ecf20Sopenharmony_ci	{KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
948c2ecf20Sopenharmony_ci	{KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
958c2ecf20Sopenharmony_ci	{KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
968c2ecf20Sopenharmony_ci	{KE_KEY, 0x27, {KEY_HELP} },
978c2ecf20Sopenharmony_ci	{KE_KEY, 0x29, {KEY_PROG3} },    /* P_Key for TM8372 */
988c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x41, {KEY_MUTE} },
998c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
1008c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
1018c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x43, {KEY_NEXTSONG} },
1028c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
1038c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
1048c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
1058c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x45, {KEY_STOP} },
1068c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x50, {KEY_STOP} },
1078c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
1088c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
1098c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
1108c2ecf20Sopenharmony_ci	/*
1118c2ecf20Sopenharmony_ci	 * 0x61 is KEY_SWITCHVIDEOMODE. Usually this is a duplicate input event
1128c2ecf20Sopenharmony_ci	 * with the "Video Bus" input device events. But sometimes it is not
1138c2ecf20Sopenharmony_ci	 * a dup. Map it to KEY_UNKNOWN instead of using KE_IGNORE so that
1148c2ecf20Sopenharmony_ci	 * udev/hwdb can override it on systems where it is not a dup.
1158c2ecf20Sopenharmony_ci	 */
1168c2ecf20Sopenharmony_ci	{KE_KEY, 0x61, {KEY_UNKNOWN} },
1178c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
1188c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
1198c2ecf20Sopenharmony_ci	{KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} },	/* Display Switch */
1208c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x81, {KEY_SLEEP} },
1218c2ecf20Sopenharmony_ci	{KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} },	/* Touch Pad Toggle */
1228c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x84, {KEY_KBDILLUMTOGGLE} }, /* Automatic Keyboard background light toggle */
1238c2ecf20Sopenharmony_ci	{KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
1248c2ecf20Sopenharmony_ci	{KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
1258c2ecf20Sopenharmony_ci	{KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
1268c2ecf20Sopenharmony_ci	{KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
1278c2ecf20Sopenharmony_ci	{KE_KEY, 0x86, {KEY_WLAN} },
1288c2ecf20Sopenharmony_ci	{KE_KEY, 0x87, {KEY_POWER} },
1298c2ecf20Sopenharmony_ci	{KE_END, 0}
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic struct input_dev *acer_wmi_input_dev;
1338c2ecf20Sopenharmony_cistatic struct input_dev *acer_wmi_accel_dev;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistruct event_return_value {
1368c2ecf20Sopenharmony_ci	u8 function;
1378c2ecf20Sopenharmony_ci	u8 key_num;
1388c2ecf20Sopenharmony_ci	u16 device_state;
1398c2ecf20Sopenharmony_ci	u16 reserved1;
1408c2ecf20Sopenharmony_ci	u8 kbd_dock_state;
1418c2ecf20Sopenharmony_ci	u8 reserved2;
1428c2ecf20Sopenharmony_ci} __attribute__((packed));
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/*
1458c2ecf20Sopenharmony_ci * GUID3 Get Device Status device flags
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_ci#define ACER_WMID3_GDS_WIRELESS		(1<<0)	/* WiFi */
1488c2ecf20Sopenharmony_ci#define ACER_WMID3_GDS_THREEG		(1<<6)	/* 3G */
1498c2ecf20Sopenharmony_ci#define ACER_WMID3_GDS_WIMAX		(1<<7)	/* WiMAX */
1508c2ecf20Sopenharmony_ci#define ACER_WMID3_GDS_BLUETOOTH	(1<<11)	/* BT */
1518c2ecf20Sopenharmony_ci#define ACER_WMID3_GDS_RFBTN		(1<<14)	/* RF Button */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci#define ACER_WMID3_GDS_TOUCHPAD		(1<<1)	/* Touchpad */
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/* Hotkey Customized Setting and Acer Application Status.
1568c2ecf20Sopenharmony_ci * Set Device Default Value and Report Acer Application Status.
1578c2ecf20Sopenharmony_ci * When Acer Application starts, it will run this method to inform
1588c2ecf20Sopenharmony_ci * BIOS/EC that Acer Application is on.
1598c2ecf20Sopenharmony_ci * App Status
1608c2ecf20Sopenharmony_ci *	Bit[0]: Launch Manager Status
1618c2ecf20Sopenharmony_ci *	Bit[1]: ePM Status
1628c2ecf20Sopenharmony_ci *	Bit[2]: Device Control Status
1638c2ecf20Sopenharmony_ci *	Bit[3]: Acer Power Button Utility Status
1648c2ecf20Sopenharmony_ci *	Bit[4]: RF Button Status
1658c2ecf20Sopenharmony_ci *	Bit[5]: ODD PM Status
1668c2ecf20Sopenharmony_ci *	Bit[6]: Device Default Value Control
1678c2ecf20Sopenharmony_ci *	Bit[7]: Hall Sensor Application Status
1688c2ecf20Sopenharmony_ci */
1698c2ecf20Sopenharmony_cistruct func_input_params {
1708c2ecf20Sopenharmony_ci	u8 function_num;        /* Function Number */
1718c2ecf20Sopenharmony_ci	u16 commun_devices;     /* Communication type devices default status */
1728c2ecf20Sopenharmony_ci	u16 devices;            /* Other type devices default status */
1738c2ecf20Sopenharmony_ci	u8 app_status;          /* Acer Device Status. LM, ePM, RF Button... */
1748c2ecf20Sopenharmony_ci	u8 app_mask;		/* Bit mask to app_status */
1758c2ecf20Sopenharmony_ci	u8 reserved;
1768c2ecf20Sopenharmony_ci} __attribute__((packed));
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistruct func_return_value {
1798c2ecf20Sopenharmony_ci	u8 error_code;          /* Error Code */
1808c2ecf20Sopenharmony_ci	u8 ec_return_value;     /* EC Return Value */
1818c2ecf20Sopenharmony_ci	u16 reserved;
1828c2ecf20Sopenharmony_ci} __attribute__((packed));
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistruct wmid3_gds_set_input_param {     /* Set Device Status input parameter */
1858c2ecf20Sopenharmony_ci	u8 function_num;        /* Function Number */
1868c2ecf20Sopenharmony_ci	u8 hotkey_number;       /* Hotkey Number */
1878c2ecf20Sopenharmony_ci	u16 devices;            /* Set Device */
1888c2ecf20Sopenharmony_ci	u8 volume_value;        /* Volume Value */
1898c2ecf20Sopenharmony_ci} __attribute__((packed));
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistruct wmid3_gds_get_input_param {     /* Get Device Status input parameter */
1928c2ecf20Sopenharmony_ci	u8 function_num;	/* Function Number */
1938c2ecf20Sopenharmony_ci	u8 hotkey_number;	/* Hotkey Number */
1948c2ecf20Sopenharmony_ci	u16 devices;		/* Get Device */
1958c2ecf20Sopenharmony_ci} __attribute__((packed));
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistruct wmid3_gds_return_value {	/* Get Device Status return value*/
1988c2ecf20Sopenharmony_ci	u8 error_code;		/* Error Code */
1998c2ecf20Sopenharmony_ci	u8 ec_return_value;	/* EC Return Value */
2008c2ecf20Sopenharmony_ci	u16 devices;		/* Current Device Status */
2018c2ecf20Sopenharmony_ci	u32 reserved;
2028c2ecf20Sopenharmony_ci} __attribute__((packed));
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistruct hotkey_function_type_aa {
2058c2ecf20Sopenharmony_ci	u8 type;
2068c2ecf20Sopenharmony_ci	u8 length;
2078c2ecf20Sopenharmony_ci	u16 handle;
2088c2ecf20Sopenharmony_ci	u16 commun_func_bitmap;
2098c2ecf20Sopenharmony_ci	u16 application_func_bitmap;
2108c2ecf20Sopenharmony_ci	u16 media_func_bitmap;
2118c2ecf20Sopenharmony_ci	u16 display_func_bitmap;
2128c2ecf20Sopenharmony_ci	u16 others_func_bitmap;
2138c2ecf20Sopenharmony_ci	u8 commun_fn_key_number;
2148c2ecf20Sopenharmony_ci} __attribute__((packed));
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/*
2178c2ecf20Sopenharmony_ci * Interface capability flags
2188c2ecf20Sopenharmony_ci */
2198c2ecf20Sopenharmony_ci#define ACER_CAP_MAILLED		BIT(0)
2208c2ecf20Sopenharmony_ci#define ACER_CAP_WIRELESS		BIT(1)
2218c2ecf20Sopenharmony_ci#define ACER_CAP_BLUETOOTH		BIT(2)
2228c2ecf20Sopenharmony_ci#define ACER_CAP_BRIGHTNESS		BIT(3)
2238c2ecf20Sopenharmony_ci#define ACER_CAP_THREEG			BIT(4)
2248c2ecf20Sopenharmony_ci#define ACER_CAP_SET_FUNCTION_MODE	BIT(5)
2258c2ecf20Sopenharmony_ci#define ACER_CAP_KBD_DOCK		BIT(6)
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci/*
2288c2ecf20Sopenharmony_ci * Interface type flags
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_cienum interface_flags {
2318c2ecf20Sopenharmony_ci	ACER_AMW0,
2328c2ecf20Sopenharmony_ci	ACER_AMW0_V2,
2338c2ecf20Sopenharmony_ci	ACER_WMID,
2348c2ecf20Sopenharmony_ci	ACER_WMID_v2,
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#define ACER_DEFAULT_WIRELESS  0
2388c2ecf20Sopenharmony_ci#define ACER_DEFAULT_BLUETOOTH 0
2398c2ecf20Sopenharmony_ci#define ACER_DEFAULT_MAILLED   0
2408c2ecf20Sopenharmony_ci#define ACER_DEFAULT_THREEG    0
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int max_brightness = 0xF;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int mailled = -1;
2458c2ecf20Sopenharmony_cistatic int brightness = -1;
2468c2ecf20Sopenharmony_cistatic int threeg = -1;
2478c2ecf20Sopenharmony_cistatic int force_series;
2488c2ecf20Sopenharmony_cistatic int force_caps = -1;
2498c2ecf20Sopenharmony_cistatic bool ec_raw_mode;
2508c2ecf20Sopenharmony_cistatic bool has_type_aa;
2518c2ecf20Sopenharmony_cistatic u16 commun_func_bitmap;
2528c2ecf20Sopenharmony_cistatic u8 commun_fn_key_number;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cimodule_param(mailled, int, 0444);
2558c2ecf20Sopenharmony_cimodule_param(brightness, int, 0444);
2568c2ecf20Sopenharmony_cimodule_param(threeg, int, 0444);
2578c2ecf20Sopenharmony_cimodule_param(force_series, int, 0444);
2588c2ecf20Sopenharmony_cimodule_param(force_caps, int, 0444);
2598c2ecf20Sopenharmony_cimodule_param(ec_raw_mode, bool, 0444);
2608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
2618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
2628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
2638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_series, "Force a different laptop series");
2648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value");
2658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistruct acer_data {
2688c2ecf20Sopenharmony_ci	int mailled;
2698c2ecf20Sopenharmony_ci	int threeg;
2708c2ecf20Sopenharmony_ci	int brightness;
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistruct acer_debug {
2748c2ecf20Sopenharmony_ci	struct dentry *root;
2758c2ecf20Sopenharmony_ci	u32 wmid_devices;
2768c2ecf20Sopenharmony_ci};
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic struct rfkill *wireless_rfkill;
2798c2ecf20Sopenharmony_cistatic struct rfkill *bluetooth_rfkill;
2808c2ecf20Sopenharmony_cistatic struct rfkill *threeg_rfkill;
2818c2ecf20Sopenharmony_cistatic bool rfkill_inited;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/* Each low-level interface must define at least some of the following */
2848c2ecf20Sopenharmony_cistruct wmi_interface {
2858c2ecf20Sopenharmony_ci	/* The WMI device type */
2868c2ecf20Sopenharmony_ci	u32 type;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/* The capabilities this interface provides */
2898c2ecf20Sopenharmony_ci	u32 capability;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* Private data for the current interface */
2928c2ecf20Sopenharmony_ci	struct acer_data data;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/* debugfs entries associated with this interface */
2958c2ecf20Sopenharmony_ci	struct acer_debug debug;
2968c2ecf20Sopenharmony_ci};
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/* The static interface pointer, points to the currently detected interface */
2998c2ecf20Sopenharmony_cistatic struct wmi_interface *interface;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/*
3028c2ecf20Sopenharmony_ci * Embedded Controller quirks
3038c2ecf20Sopenharmony_ci * Some laptops require us to directly access the EC to either enable or query
3048c2ecf20Sopenharmony_ci * features that are not available through WMI.
3058c2ecf20Sopenharmony_ci */
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistruct quirk_entry {
3088c2ecf20Sopenharmony_ci	u8 wireless;
3098c2ecf20Sopenharmony_ci	u8 mailled;
3108c2ecf20Sopenharmony_ci	s8 brightness;
3118c2ecf20Sopenharmony_ci	u8 bluetooth;
3128c2ecf20Sopenharmony_ci};
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic struct quirk_entry *quirks;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic void __init set_quirks(void)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	if (!interface)
3198c2ecf20Sopenharmony_ci		return;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (quirks->mailled)
3228c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_MAILLED;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (quirks->brightness)
3258c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_BRIGHTNESS;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int __init dmi_matched(const struct dmi_system_id *dmi)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	quirks = dmi->driver_data;
3318c2ecf20Sopenharmony_ci	return 1;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int __init set_force_caps(const struct dmi_system_id *dmi)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	if (force_caps == -1) {
3378c2ecf20Sopenharmony_ci		force_caps = (uintptr_t)dmi->driver_data;
3388c2ecf20Sopenharmony_ci		pr_info("Found %s, set force_caps to 0x%x\n", dmi->ident, force_caps);
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci	return 1;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic struct quirk_entry quirk_unknown = {
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic struct quirk_entry quirk_acer_aspire_1520 = {
3478c2ecf20Sopenharmony_ci	.brightness = -1,
3488c2ecf20Sopenharmony_ci};
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic struct quirk_entry quirk_acer_travelmate_2490 = {
3518c2ecf20Sopenharmony_ci	.mailled = 1,
3528c2ecf20Sopenharmony_ci};
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci/* This AMW0 laptop has no bluetooth */
3558c2ecf20Sopenharmony_cistatic struct quirk_entry quirk_medion_md_98300 = {
3568c2ecf20Sopenharmony_ci	.wireless = 1,
3578c2ecf20Sopenharmony_ci};
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
3608c2ecf20Sopenharmony_ci	.wireless = 2,
3618c2ecf20Sopenharmony_ci};
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic struct quirk_entry quirk_lenovo_ideapad_s205 = {
3648c2ecf20Sopenharmony_ci	.wireless = 3,
3658c2ecf20Sopenharmony_ci};
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/* The Aspire One has a dummy ACPI-WMI interface - disable it */
3688c2ecf20Sopenharmony_cistatic const struct dmi_system_id acer_blacklist[] __initconst = {
3698c2ecf20Sopenharmony_ci	{
3708c2ecf20Sopenharmony_ci		.ident = "Acer Aspire One (SSD)",
3718c2ecf20Sopenharmony_ci		.matches = {
3728c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
3738c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
3748c2ecf20Sopenharmony_ci		},
3758c2ecf20Sopenharmony_ci	},
3768c2ecf20Sopenharmony_ci	{
3778c2ecf20Sopenharmony_ci		.ident = "Acer Aspire One (HDD)",
3788c2ecf20Sopenharmony_ci		.matches = {
3798c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
3808c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
3818c2ecf20Sopenharmony_ci		},
3828c2ecf20Sopenharmony_ci	},
3838c2ecf20Sopenharmony_ci	{}
3848c2ecf20Sopenharmony_ci};
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic const struct dmi_system_id amw0_whitelist[] __initconst = {
3878c2ecf20Sopenharmony_ci	{
3888c2ecf20Sopenharmony_ci		.ident = "Acer",
3898c2ecf20Sopenharmony_ci		.matches = {
3908c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
3918c2ecf20Sopenharmony_ci		},
3928c2ecf20Sopenharmony_ci	},
3938c2ecf20Sopenharmony_ci	{
3948c2ecf20Sopenharmony_ci		.ident = "Gateway",
3958c2ecf20Sopenharmony_ci		.matches = {
3968c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Gateway"),
3978c2ecf20Sopenharmony_ci		},
3988c2ecf20Sopenharmony_ci	},
3998c2ecf20Sopenharmony_ci	{
4008c2ecf20Sopenharmony_ci		.ident = "Packard Bell",
4018c2ecf20Sopenharmony_ci		.matches = {
4028c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
4038c2ecf20Sopenharmony_ci		},
4048c2ecf20Sopenharmony_ci	},
4058c2ecf20Sopenharmony_ci	{}
4068c2ecf20Sopenharmony_ci};
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/*
4098c2ecf20Sopenharmony_ci * This quirk table is only for Acer/Gateway/Packard Bell family
4108c2ecf20Sopenharmony_ci * that those machines are supported by acer-wmi driver.
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_cistatic const struct dmi_system_id acer_quirks[] __initconst = {
4138c2ecf20Sopenharmony_ci	{
4148c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4158c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 1360",
4168c2ecf20Sopenharmony_ci		.matches = {
4178c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4188c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
4198c2ecf20Sopenharmony_ci		},
4208c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_aspire_1520,
4218c2ecf20Sopenharmony_ci	},
4228c2ecf20Sopenharmony_ci	{
4238c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4248c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 1520",
4258c2ecf20Sopenharmony_ci		.matches = {
4268c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4278c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
4288c2ecf20Sopenharmony_ci		},
4298c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_aspire_1520,
4308c2ecf20Sopenharmony_ci	},
4318c2ecf20Sopenharmony_ci	{
4328c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4338c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 3100",
4348c2ecf20Sopenharmony_ci		.matches = {
4358c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4368c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
4378c2ecf20Sopenharmony_ci		},
4388c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
4398c2ecf20Sopenharmony_ci	},
4408c2ecf20Sopenharmony_ci	{
4418c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4428c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 3610",
4438c2ecf20Sopenharmony_ci		.matches = {
4448c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4458c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
4468c2ecf20Sopenharmony_ci		},
4478c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
4488c2ecf20Sopenharmony_ci	},
4498c2ecf20Sopenharmony_ci	{
4508c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4518c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 5100",
4528c2ecf20Sopenharmony_ci		.matches = {
4538c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4548c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
4558c2ecf20Sopenharmony_ci		},
4568c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
4578c2ecf20Sopenharmony_ci	},
4588c2ecf20Sopenharmony_ci	{
4598c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4608c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 5610",
4618c2ecf20Sopenharmony_ci		.matches = {
4628c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4638c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
4648c2ecf20Sopenharmony_ci		},
4658c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
4668c2ecf20Sopenharmony_ci	},
4678c2ecf20Sopenharmony_ci	{
4688c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4698c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 5630",
4708c2ecf20Sopenharmony_ci		.matches = {
4718c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4728c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
4738c2ecf20Sopenharmony_ci		},
4748c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
4758c2ecf20Sopenharmony_ci	},
4768c2ecf20Sopenharmony_ci	{
4778c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4788c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 5650",
4798c2ecf20Sopenharmony_ci		.matches = {
4808c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4818c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
4828c2ecf20Sopenharmony_ci		},
4838c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
4848c2ecf20Sopenharmony_ci	},
4858c2ecf20Sopenharmony_ci	{
4868c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4878c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 5680",
4888c2ecf20Sopenharmony_ci		.matches = {
4898c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4908c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
4918c2ecf20Sopenharmony_ci		},
4928c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
4938c2ecf20Sopenharmony_ci	},
4948c2ecf20Sopenharmony_ci	{
4958c2ecf20Sopenharmony_ci		.callback = dmi_matched,
4968c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 9110",
4978c2ecf20Sopenharmony_ci		.matches = {
4988c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
4998c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
5008c2ecf20Sopenharmony_ci		},
5018c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
5028c2ecf20Sopenharmony_ci	},
5038c2ecf20Sopenharmony_ci	{
5048c2ecf20Sopenharmony_ci		.callback = dmi_matched,
5058c2ecf20Sopenharmony_ci		.ident = "Acer TravelMate 2490",
5068c2ecf20Sopenharmony_ci		.matches = {
5078c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
5088c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
5098c2ecf20Sopenharmony_ci		},
5108c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
5118c2ecf20Sopenharmony_ci	},
5128c2ecf20Sopenharmony_ci	{
5138c2ecf20Sopenharmony_ci		.callback = dmi_matched,
5148c2ecf20Sopenharmony_ci		.ident = "Acer TravelMate 4200",
5158c2ecf20Sopenharmony_ci		.matches = {
5168c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
5178c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
5188c2ecf20Sopenharmony_ci		},
5198c2ecf20Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
5208c2ecf20Sopenharmony_ci	},
5218c2ecf20Sopenharmony_ci	{
5228c2ecf20Sopenharmony_ci		.callback = set_force_caps,
5238c2ecf20Sopenharmony_ci		.ident = "Acer Aspire Switch 10E SW3-016",
5248c2ecf20Sopenharmony_ci		.matches = {
5258c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
5268c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-016"),
5278c2ecf20Sopenharmony_ci		},
5288c2ecf20Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
5298c2ecf20Sopenharmony_ci	},
5308c2ecf20Sopenharmony_ci	{
5318c2ecf20Sopenharmony_ci		.callback = set_force_caps,
5328c2ecf20Sopenharmony_ci		.ident = "Acer Aspire Switch 10 SW5-012",
5338c2ecf20Sopenharmony_ci		.matches = {
5348c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
5358c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
5368c2ecf20Sopenharmony_ci		},
5378c2ecf20Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
5388c2ecf20Sopenharmony_ci	},
5398c2ecf20Sopenharmony_ci	{
5408c2ecf20Sopenharmony_ci		.callback = set_force_caps,
5418c2ecf20Sopenharmony_ci		.ident = "Acer Aspire Switch V 10 SW5-017",
5428c2ecf20Sopenharmony_ci		.matches = {
5438c2ecf20Sopenharmony_ci			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
5448c2ecf20Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
5458c2ecf20Sopenharmony_ci		},
5468c2ecf20Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
5478c2ecf20Sopenharmony_ci	},
5488c2ecf20Sopenharmony_ci	{
5498c2ecf20Sopenharmony_ci		.callback = set_force_caps,
5508c2ecf20Sopenharmony_ci		.ident = "Acer One 10 (S1003)",
5518c2ecf20Sopenharmony_ci		.matches = {
5528c2ecf20Sopenharmony_ci			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
5538c2ecf20Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
5548c2ecf20Sopenharmony_ci		},
5558c2ecf20Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
5568c2ecf20Sopenharmony_ci	},
5578c2ecf20Sopenharmony_ci	{}
5588c2ecf20Sopenharmony_ci};
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci/*
5618c2ecf20Sopenharmony_ci * This quirk list is for those non-acer machines that have AMW0_GUID1
5628c2ecf20Sopenharmony_ci * but supported by acer-wmi in past days. Keeping this quirk list here
5638c2ecf20Sopenharmony_ci * is only for backward compatible. Please do not add new machine to
5648c2ecf20Sopenharmony_ci * here anymore. Those non-acer machines should be supported by
5658c2ecf20Sopenharmony_ci * appropriate wmi drivers.
5668c2ecf20Sopenharmony_ci */
5678c2ecf20Sopenharmony_cistatic const struct dmi_system_id non_acer_quirks[] __initconst = {
5688c2ecf20Sopenharmony_ci	{
5698c2ecf20Sopenharmony_ci		.callback = dmi_matched,
5708c2ecf20Sopenharmony_ci		.ident = "Fujitsu Siemens Amilo Li 1718",
5718c2ecf20Sopenharmony_ci		.matches = {
5728c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
5738c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
5748c2ecf20Sopenharmony_ci		},
5758c2ecf20Sopenharmony_ci		.driver_data = &quirk_fujitsu_amilo_li_1718,
5768c2ecf20Sopenharmony_ci	},
5778c2ecf20Sopenharmony_ci	{
5788c2ecf20Sopenharmony_ci		.callback = dmi_matched,
5798c2ecf20Sopenharmony_ci		.ident = "Medion MD 98300",
5808c2ecf20Sopenharmony_ci		.matches = {
5818c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
5828c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
5838c2ecf20Sopenharmony_ci		},
5848c2ecf20Sopenharmony_ci		.driver_data = &quirk_medion_md_98300,
5858c2ecf20Sopenharmony_ci	},
5868c2ecf20Sopenharmony_ci	{
5878c2ecf20Sopenharmony_ci		.callback = dmi_matched,
5888c2ecf20Sopenharmony_ci		.ident = "Lenovo Ideapad S205",
5898c2ecf20Sopenharmony_ci		.matches = {
5908c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
5918c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
5928c2ecf20Sopenharmony_ci		},
5938c2ecf20Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
5948c2ecf20Sopenharmony_ci	},
5958c2ecf20Sopenharmony_ci	{
5968c2ecf20Sopenharmony_ci		.callback = dmi_matched,
5978c2ecf20Sopenharmony_ci		.ident = "Lenovo Ideapad S205 (Brazos)",
5988c2ecf20Sopenharmony_ci		.matches = {
5998c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
6008c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
6018c2ecf20Sopenharmony_ci		},
6028c2ecf20Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
6038c2ecf20Sopenharmony_ci	},
6048c2ecf20Sopenharmony_ci	{
6058c2ecf20Sopenharmony_ci		.callback = dmi_matched,
6068c2ecf20Sopenharmony_ci		.ident = "Lenovo 3000 N200",
6078c2ecf20Sopenharmony_ci		.matches = {
6088c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
6098c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
6108c2ecf20Sopenharmony_ci		},
6118c2ecf20Sopenharmony_ci		.driver_data = &quirk_fujitsu_amilo_li_1718,
6128c2ecf20Sopenharmony_ci	},
6138c2ecf20Sopenharmony_ci	{
6148c2ecf20Sopenharmony_ci		.callback = dmi_matched,
6158c2ecf20Sopenharmony_ci		.ident = "Lenovo Ideapad S205-10382JG",
6168c2ecf20Sopenharmony_ci		.matches = {
6178c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
6188c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"),
6198c2ecf20Sopenharmony_ci		},
6208c2ecf20Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
6218c2ecf20Sopenharmony_ci	},
6228c2ecf20Sopenharmony_ci	{
6238c2ecf20Sopenharmony_ci		.callback = dmi_matched,
6248c2ecf20Sopenharmony_ci		.ident = "Lenovo Ideapad S205-1038DPG",
6258c2ecf20Sopenharmony_ci		.matches = {
6268c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
6278c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"),
6288c2ecf20Sopenharmony_ci		},
6298c2ecf20Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
6308c2ecf20Sopenharmony_ci	},
6318c2ecf20Sopenharmony_ci	{}
6328c2ecf20Sopenharmony_ci};
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cistatic int __init
6358c2ecf20Sopenharmony_civideo_set_backlight_video_vendor(const struct dmi_system_id *d)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	interface->capability &= ~ACER_CAP_BRIGHTNESS;
6388c2ecf20Sopenharmony_ci	pr_info("Brightness must be controlled by generic video driver\n");
6398c2ecf20Sopenharmony_ci	return 0;
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
6438c2ecf20Sopenharmony_ci	{
6448c2ecf20Sopenharmony_ci		.callback = video_set_backlight_video_vendor,
6458c2ecf20Sopenharmony_ci		.ident = "Acer TravelMate 4750",
6468c2ecf20Sopenharmony_ci		.matches = {
6478c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
6488c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
6498c2ecf20Sopenharmony_ci		},
6508c2ecf20Sopenharmony_ci	},
6518c2ecf20Sopenharmony_ci	{
6528c2ecf20Sopenharmony_ci		.callback = video_set_backlight_video_vendor,
6538c2ecf20Sopenharmony_ci		.ident = "Acer Extensa 5235",
6548c2ecf20Sopenharmony_ci		.matches = {
6558c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
6568c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
6578c2ecf20Sopenharmony_ci		},
6588c2ecf20Sopenharmony_ci	},
6598c2ecf20Sopenharmony_ci	{
6608c2ecf20Sopenharmony_ci		.callback = video_set_backlight_video_vendor,
6618c2ecf20Sopenharmony_ci		.ident = "Acer TravelMate 5760",
6628c2ecf20Sopenharmony_ci		.matches = {
6638c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
6648c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
6658c2ecf20Sopenharmony_ci		},
6668c2ecf20Sopenharmony_ci	},
6678c2ecf20Sopenharmony_ci	{
6688c2ecf20Sopenharmony_ci		.callback = video_set_backlight_video_vendor,
6698c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 5750",
6708c2ecf20Sopenharmony_ci		.matches = {
6718c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
6728c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
6738c2ecf20Sopenharmony_ci		},
6748c2ecf20Sopenharmony_ci	},
6758c2ecf20Sopenharmony_ci	{
6768c2ecf20Sopenharmony_ci		.callback = video_set_backlight_video_vendor,
6778c2ecf20Sopenharmony_ci		.ident = "Acer Aspire 5741",
6788c2ecf20Sopenharmony_ci		.matches = {
6798c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
6808c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
6818c2ecf20Sopenharmony_ci		},
6828c2ecf20Sopenharmony_ci	},
6838c2ecf20Sopenharmony_ci	{
6848c2ecf20Sopenharmony_ci		/*
6858c2ecf20Sopenharmony_ci		 * Note no video_set_backlight_video_vendor, we must use the
6868c2ecf20Sopenharmony_ci		 * acer interface, as there is no native backlight interface.
6878c2ecf20Sopenharmony_ci		 */
6888c2ecf20Sopenharmony_ci		.ident = "Acer KAV80",
6898c2ecf20Sopenharmony_ci		.matches = {
6908c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
6918c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
6928c2ecf20Sopenharmony_ci		},
6938c2ecf20Sopenharmony_ci	},
6948c2ecf20Sopenharmony_ci	{}
6958c2ecf20Sopenharmony_ci};
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci/* Find which quirks are needed for a particular vendor/ model pair */
6988c2ecf20Sopenharmony_cistatic void __init find_quirks(void)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	if (!force_series) {
7018c2ecf20Sopenharmony_ci		dmi_check_system(acer_quirks);
7028c2ecf20Sopenharmony_ci		dmi_check_system(non_acer_quirks);
7038c2ecf20Sopenharmony_ci	} else if (force_series == 2490) {
7048c2ecf20Sopenharmony_ci		quirks = &quirk_acer_travelmate_2490;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (quirks == NULL)
7088c2ecf20Sopenharmony_ci		quirks = &quirk_unknown;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	set_quirks();
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci/*
7148c2ecf20Sopenharmony_ci * General interface convenience methods
7158c2ecf20Sopenharmony_ci */
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic bool has_cap(u32 cap)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	return interface->capability & cap;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci/*
7238c2ecf20Sopenharmony_ci * AMW0 (V1) interface
7248c2ecf20Sopenharmony_ci */
7258c2ecf20Sopenharmony_cistruct wmab_args {
7268c2ecf20Sopenharmony_ci	u32 eax;
7278c2ecf20Sopenharmony_ci	u32 ebx;
7288c2ecf20Sopenharmony_ci	u32 ecx;
7298c2ecf20Sopenharmony_ci	u32 edx;
7308c2ecf20Sopenharmony_ci};
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_cistruct wmab_ret {
7338c2ecf20Sopenharmony_ci	u32 eax;
7348c2ecf20Sopenharmony_ci	u32 ebx;
7358c2ecf20Sopenharmony_ci	u32 ecx;
7368c2ecf20Sopenharmony_ci	u32 edx;
7378c2ecf20Sopenharmony_ci	u32 eex;
7388c2ecf20Sopenharmony_ci};
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_cistatic acpi_status wmab_execute(struct wmab_args *regbuf,
7418c2ecf20Sopenharmony_cistruct acpi_buffer *result)
7428c2ecf20Sopenharmony_ci{
7438c2ecf20Sopenharmony_ci	struct acpi_buffer input;
7448c2ecf20Sopenharmony_ci	acpi_status status;
7458c2ecf20Sopenharmony_ci	input.length = sizeof(struct wmab_args);
7468c2ecf20Sopenharmony_ci	input.pointer = (u8 *)regbuf;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	status = wmi_evaluate_method(AMW0_GUID1, 0, 1, &input, result);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	return status;
7518c2ecf20Sopenharmony_ci}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_cistatic acpi_status AMW0_get_u32(u32 *value, u32 cap)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	int err;
7568c2ecf20Sopenharmony_ci	u8 result;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	switch (cap) {
7598c2ecf20Sopenharmony_ci	case ACER_CAP_MAILLED:
7608c2ecf20Sopenharmony_ci		switch (quirks->mailled) {
7618c2ecf20Sopenharmony_ci		default:
7628c2ecf20Sopenharmony_ci			err = ec_read(0xA, &result);
7638c2ecf20Sopenharmony_ci			if (err)
7648c2ecf20Sopenharmony_ci				return AE_ERROR;
7658c2ecf20Sopenharmony_ci			*value = (result >> 7) & 0x1;
7668c2ecf20Sopenharmony_ci			return AE_OK;
7678c2ecf20Sopenharmony_ci		}
7688c2ecf20Sopenharmony_ci		break;
7698c2ecf20Sopenharmony_ci	case ACER_CAP_WIRELESS:
7708c2ecf20Sopenharmony_ci		switch (quirks->wireless) {
7718c2ecf20Sopenharmony_ci		case 1:
7728c2ecf20Sopenharmony_ci			err = ec_read(0x7B, &result);
7738c2ecf20Sopenharmony_ci			if (err)
7748c2ecf20Sopenharmony_ci				return AE_ERROR;
7758c2ecf20Sopenharmony_ci			*value = result & 0x1;
7768c2ecf20Sopenharmony_ci			return AE_OK;
7778c2ecf20Sopenharmony_ci		case 2:
7788c2ecf20Sopenharmony_ci			err = ec_read(0x71, &result);
7798c2ecf20Sopenharmony_ci			if (err)
7808c2ecf20Sopenharmony_ci				return AE_ERROR;
7818c2ecf20Sopenharmony_ci			*value = result & 0x1;
7828c2ecf20Sopenharmony_ci			return AE_OK;
7838c2ecf20Sopenharmony_ci		case 3:
7848c2ecf20Sopenharmony_ci			err = ec_read(0x78, &result);
7858c2ecf20Sopenharmony_ci			if (err)
7868c2ecf20Sopenharmony_ci				return AE_ERROR;
7878c2ecf20Sopenharmony_ci			*value = result & 0x1;
7888c2ecf20Sopenharmony_ci			return AE_OK;
7898c2ecf20Sopenharmony_ci		default:
7908c2ecf20Sopenharmony_ci			err = ec_read(0xA, &result);
7918c2ecf20Sopenharmony_ci			if (err)
7928c2ecf20Sopenharmony_ci				return AE_ERROR;
7938c2ecf20Sopenharmony_ci			*value = (result >> 2) & 0x1;
7948c2ecf20Sopenharmony_ci			return AE_OK;
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci		break;
7978c2ecf20Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
7988c2ecf20Sopenharmony_ci		switch (quirks->bluetooth) {
7998c2ecf20Sopenharmony_ci		default:
8008c2ecf20Sopenharmony_ci			err = ec_read(0xA, &result);
8018c2ecf20Sopenharmony_ci			if (err)
8028c2ecf20Sopenharmony_ci				return AE_ERROR;
8038c2ecf20Sopenharmony_ci			*value = (result >> 4) & 0x1;
8048c2ecf20Sopenharmony_ci			return AE_OK;
8058c2ecf20Sopenharmony_ci		}
8068c2ecf20Sopenharmony_ci		break;
8078c2ecf20Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
8088c2ecf20Sopenharmony_ci		switch (quirks->brightness) {
8098c2ecf20Sopenharmony_ci		default:
8108c2ecf20Sopenharmony_ci			err = ec_read(0x83, &result);
8118c2ecf20Sopenharmony_ci			if (err)
8128c2ecf20Sopenharmony_ci				return AE_ERROR;
8138c2ecf20Sopenharmony_ci			*value = result;
8148c2ecf20Sopenharmony_ci			return AE_OK;
8158c2ecf20Sopenharmony_ci		}
8168c2ecf20Sopenharmony_ci		break;
8178c2ecf20Sopenharmony_ci	default:
8188c2ecf20Sopenharmony_ci		return AE_ERROR;
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci	return AE_OK;
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_cistatic acpi_status AMW0_set_u32(u32 value, u32 cap)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct wmab_args args;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	args.eax = ACER_AMW0_WRITE;
8288c2ecf20Sopenharmony_ci	args.ebx = value ? (1<<8) : 0;
8298c2ecf20Sopenharmony_ci	args.ecx = args.edx = 0;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	switch (cap) {
8328c2ecf20Sopenharmony_ci	case ACER_CAP_MAILLED:
8338c2ecf20Sopenharmony_ci		if (value > 1)
8348c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
8358c2ecf20Sopenharmony_ci		args.ebx |= ACER_AMW0_MAILLED_MASK;
8368c2ecf20Sopenharmony_ci		break;
8378c2ecf20Sopenharmony_ci	case ACER_CAP_WIRELESS:
8388c2ecf20Sopenharmony_ci		if (value > 1)
8398c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
8408c2ecf20Sopenharmony_ci		args.ebx |= ACER_AMW0_WIRELESS_MASK;
8418c2ecf20Sopenharmony_ci		break;
8428c2ecf20Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
8438c2ecf20Sopenharmony_ci		if (value > 1)
8448c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
8458c2ecf20Sopenharmony_ci		args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
8468c2ecf20Sopenharmony_ci		break;
8478c2ecf20Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
8488c2ecf20Sopenharmony_ci		if (value > max_brightness)
8498c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
8508c2ecf20Sopenharmony_ci		switch (quirks->brightness) {
8518c2ecf20Sopenharmony_ci		default:
8528c2ecf20Sopenharmony_ci			return ec_write(0x83, value);
8538c2ecf20Sopenharmony_ci			break;
8548c2ecf20Sopenharmony_ci		}
8558c2ecf20Sopenharmony_ci	default:
8568c2ecf20Sopenharmony_ci		return AE_ERROR;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	/* Actually do the set */
8608c2ecf20Sopenharmony_ci	return wmab_execute(&args, NULL);
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic acpi_status __init AMW0_find_mailled(void)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	struct wmab_args args;
8668c2ecf20Sopenharmony_ci	struct wmab_ret ret;
8678c2ecf20Sopenharmony_ci	acpi_status status = AE_OK;
8688c2ecf20Sopenharmony_ci	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
8698c2ecf20Sopenharmony_ci	union acpi_object *obj;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	args.eax = 0x86;
8728c2ecf20Sopenharmony_ci	args.ebx = args.ecx = args.edx = 0;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	status = wmab_execute(&args, &out);
8758c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
8768c2ecf20Sopenharmony_ci		return status;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
8798c2ecf20Sopenharmony_ci	if (obj && obj->type == ACPI_TYPE_BUFFER &&
8808c2ecf20Sopenharmony_ci	obj->buffer.length == sizeof(struct wmab_ret)) {
8818c2ecf20Sopenharmony_ci		ret = *((struct wmab_ret *) obj->buffer.pointer);
8828c2ecf20Sopenharmony_ci	} else {
8838c2ecf20Sopenharmony_ci		kfree(out.pointer);
8848c2ecf20Sopenharmony_ci		return AE_ERROR;
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (ret.eex & 0x1)
8888c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_MAILLED;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	kfree(out.pointer);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	return AE_OK;
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_cistatic const struct acpi_device_id norfkill_ids[] __initconst = {
8968c2ecf20Sopenharmony_ci	{ "VPC2004", 0},
8978c2ecf20Sopenharmony_ci	{ "IBM0068", 0},
8988c2ecf20Sopenharmony_ci	{ "LEN0068", 0},
8998c2ecf20Sopenharmony_ci	{ "SNY5001", 0},	/* sony-laptop in charge */
9008c2ecf20Sopenharmony_ci	{ "HPQ6601", 0},
9018c2ecf20Sopenharmony_ci	{ "", 0},
9028c2ecf20Sopenharmony_ci};
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic int __init AMW0_set_cap_acpi_check_device(void)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	const struct acpi_device_id *id;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	for (id = norfkill_ids; id->id[0]; id++)
9098c2ecf20Sopenharmony_ci		if (acpi_dev_found(id->id))
9108c2ecf20Sopenharmony_ci			return true;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	return false;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic acpi_status __init AMW0_set_capabilities(void)
9168c2ecf20Sopenharmony_ci{
9178c2ecf20Sopenharmony_ci	struct wmab_args args;
9188c2ecf20Sopenharmony_ci	struct wmab_ret ret;
9198c2ecf20Sopenharmony_ci	acpi_status status;
9208c2ecf20Sopenharmony_ci	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
9218c2ecf20Sopenharmony_ci	union acpi_object *obj;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	/*
9248c2ecf20Sopenharmony_ci	 * On laptops with this strange GUID (non Acer), normal probing doesn't
9258c2ecf20Sopenharmony_ci	 * work.
9268c2ecf20Sopenharmony_ci	 */
9278c2ecf20Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID2)) {
9288c2ecf20Sopenharmony_ci		if ((quirks != &quirk_unknown) ||
9298c2ecf20Sopenharmony_ci		    !AMW0_set_cap_acpi_check_device())
9308c2ecf20Sopenharmony_ci			interface->capability |= ACER_CAP_WIRELESS;
9318c2ecf20Sopenharmony_ci		return AE_OK;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	args.eax = ACER_AMW0_WRITE;
9358c2ecf20Sopenharmony_ci	args.ecx = args.edx = 0;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	args.ebx = 0xa2 << 8;
9388c2ecf20Sopenharmony_ci	args.ebx |= ACER_AMW0_WIRELESS_MASK;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	status = wmab_execute(&args, &out);
9418c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
9428c2ecf20Sopenharmony_ci		return status;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	obj = out.pointer;
9458c2ecf20Sopenharmony_ci	if (obj && obj->type == ACPI_TYPE_BUFFER &&
9468c2ecf20Sopenharmony_ci	obj->buffer.length == sizeof(struct wmab_ret)) {
9478c2ecf20Sopenharmony_ci		ret = *((struct wmab_ret *) obj->buffer.pointer);
9488c2ecf20Sopenharmony_ci	} else {
9498c2ecf20Sopenharmony_ci		status = AE_ERROR;
9508c2ecf20Sopenharmony_ci		goto out;
9518c2ecf20Sopenharmony_ci	}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	if (ret.eax & 0x1)
9548c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_WIRELESS;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	args.ebx = 2 << 8;
9578c2ecf20Sopenharmony_ci	args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	/*
9608c2ecf20Sopenharmony_ci	 * It's ok to use existing buffer for next wmab_execute call.
9618c2ecf20Sopenharmony_ci	 * But we need to kfree(out.pointer) if next wmab_execute fail.
9628c2ecf20Sopenharmony_ci	 */
9638c2ecf20Sopenharmony_ci	status = wmab_execute(&args, &out);
9648c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
9658c2ecf20Sopenharmony_ci		goto out;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
9688c2ecf20Sopenharmony_ci	if (obj && obj->type == ACPI_TYPE_BUFFER
9698c2ecf20Sopenharmony_ci	&& obj->buffer.length == sizeof(struct wmab_ret)) {
9708c2ecf20Sopenharmony_ci		ret = *((struct wmab_ret *) obj->buffer.pointer);
9718c2ecf20Sopenharmony_ci	} else {
9728c2ecf20Sopenharmony_ci		status = AE_ERROR;
9738c2ecf20Sopenharmony_ci		goto out;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	if (ret.eax & 0x1)
9778c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_BLUETOOTH;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	/*
9808c2ecf20Sopenharmony_ci	 * This appears to be safe to enable, since all Wistron based laptops
9818c2ecf20Sopenharmony_ci	 * appear to use the same EC register for brightness, even if they
9828c2ecf20Sopenharmony_ci	 * differ for wireless, etc
9838c2ecf20Sopenharmony_ci	 */
9848c2ecf20Sopenharmony_ci	if (quirks->brightness >= 0)
9858c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_BRIGHTNESS;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	status = AE_OK;
9888c2ecf20Sopenharmony_ciout:
9898c2ecf20Sopenharmony_ci	kfree(out.pointer);
9908c2ecf20Sopenharmony_ci	return status;
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cistatic struct wmi_interface AMW0_interface = {
9948c2ecf20Sopenharmony_ci	.type = ACER_AMW0,
9958c2ecf20Sopenharmony_ci};
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic struct wmi_interface AMW0_V2_interface = {
9988c2ecf20Sopenharmony_ci	.type = ACER_AMW0_V2,
9998c2ecf20Sopenharmony_ci};
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci/*
10028c2ecf20Sopenharmony_ci * New interface (The WMID interface)
10038c2ecf20Sopenharmony_ci */
10048c2ecf20Sopenharmony_cistatic acpi_status
10058c2ecf20Sopenharmony_ciWMI_execute_u32(u32 method_id, u32 in, u32 *out)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
10088c2ecf20Sopenharmony_ci	struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
10098c2ecf20Sopenharmony_ci	union acpi_object *obj;
10108c2ecf20Sopenharmony_ci	u32 tmp = 0;
10118c2ecf20Sopenharmony_ci	acpi_status status;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID1, 0, method_id, &input, &result);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
10168c2ecf20Sopenharmony_ci		return status;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	obj = (union acpi_object *) result.pointer;
10198c2ecf20Sopenharmony_ci	if (obj) {
10208c2ecf20Sopenharmony_ci		if (obj->type == ACPI_TYPE_BUFFER &&
10218c2ecf20Sopenharmony_ci			(obj->buffer.length == sizeof(u32) ||
10228c2ecf20Sopenharmony_ci			obj->buffer.length == sizeof(u64))) {
10238c2ecf20Sopenharmony_ci			tmp = *((u32 *) obj->buffer.pointer);
10248c2ecf20Sopenharmony_ci		} else if (obj->type == ACPI_TYPE_INTEGER) {
10258c2ecf20Sopenharmony_ci			tmp = (u32) obj->integer.value;
10268c2ecf20Sopenharmony_ci		}
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (out)
10308c2ecf20Sopenharmony_ci		*out = tmp;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	kfree(result.pointer);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	return status;
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic acpi_status WMID_get_u32(u32 *value, u32 cap)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	acpi_status status;
10408c2ecf20Sopenharmony_ci	u8 tmp;
10418c2ecf20Sopenharmony_ci	u32 result, method_id = 0;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	switch (cap) {
10448c2ecf20Sopenharmony_ci	case ACER_CAP_WIRELESS:
10458c2ecf20Sopenharmony_ci		method_id = ACER_WMID_GET_WIRELESS_METHODID;
10468c2ecf20Sopenharmony_ci		break;
10478c2ecf20Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
10488c2ecf20Sopenharmony_ci		method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
10498c2ecf20Sopenharmony_ci		break;
10508c2ecf20Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
10518c2ecf20Sopenharmony_ci		method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
10528c2ecf20Sopenharmony_ci		break;
10538c2ecf20Sopenharmony_ci	case ACER_CAP_THREEG:
10548c2ecf20Sopenharmony_ci		method_id = ACER_WMID_GET_THREEG_METHODID;
10558c2ecf20Sopenharmony_ci		break;
10568c2ecf20Sopenharmony_ci	case ACER_CAP_MAILLED:
10578c2ecf20Sopenharmony_ci		if (quirks->mailled == 1) {
10588c2ecf20Sopenharmony_ci			ec_read(0x9f, &tmp);
10598c2ecf20Sopenharmony_ci			*value = tmp & 0x1;
10608c2ecf20Sopenharmony_ci			return 0;
10618c2ecf20Sopenharmony_ci		}
10628c2ecf20Sopenharmony_ci		fallthrough;
10638c2ecf20Sopenharmony_ci	default:
10648c2ecf20Sopenharmony_ci		return AE_ERROR;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci	status = WMI_execute_u32(method_id, 0, &result);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
10698c2ecf20Sopenharmony_ci		*value = (u8)result;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	return status;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic acpi_status WMID_set_u32(u32 value, u32 cap)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	u32 method_id = 0;
10778c2ecf20Sopenharmony_ci	char param;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	switch (cap) {
10808c2ecf20Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
10818c2ecf20Sopenharmony_ci		if (value > max_brightness)
10828c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
10838c2ecf20Sopenharmony_ci		method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
10848c2ecf20Sopenharmony_ci		break;
10858c2ecf20Sopenharmony_ci	case ACER_CAP_WIRELESS:
10868c2ecf20Sopenharmony_ci		if (value > 1)
10878c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
10888c2ecf20Sopenharmony_ci		method_id = ACER_WMID_SET_WIRELESS_METHODID;
10898c2ecf20Sopenharmony_ci		break;
10908c2ecf20Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
10918c2ecf20Sopenharmony_ci		if (value > 1)
10928c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
10938c2ecf20Sopenharmony_ci		method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
10948c2ecf20Sopenharmony_ci		break;
10958c2ecf20Sopenharmony_ci	case ACER_CAP_THREEG:
10968c2ecf20Sopenharmony_ci		if (value > 1)
10978c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
10988c2ecf20Sopenharmony_ci		method_id = ACER_WMID_SET_THREEG_METHODID;
10998c2ecf20Sopenharmony_ci		break;
11008c2ecf20Sopenharmony_ci	case ACER_CAP_MAILLED:
11018c2ecf20Sopenharmony_ci		if (value > 1)
11028c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
11038c2ecf20Sopenharmony_ci		if (quirks->mailled == 1) {
11048c2ecf20Sopenharmony_ci			param = value ? 0x92 : 0x93;
11058c2ecf20Sopenharmony_ci			i8042_lock_chip();
11068c2ecf20Sopenharmony_ci			i8042_command(&param, 0x1059);
11078c2ecf20Sopenharmony_ci			i8042_unlock_chip();
11088c2ecf20Sopenharmony_ci			return 0;
11098c2ecf20Sopenharmony_ci		}
11108c2ecf20Sopenharmony_ci		break;
11118c2ecf20Sopenharmony_ci	default:
11128c2ecf20Sopenharmony_ci		return AE_ERROR;
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci	return WMI_execute_u32(method_id, (u32)value, NULL);
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic acpi_status wmid3_get_device_status(u32 *value, u16 device)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	struct wmid3_gds_return_value return_value;
11208c2ecf20Sopenharmony_ci	acpi_status status;
11218c2ecf20Sopenharmony_ci	union acpi_object *obj;
11228c2ecf20Sopenharmony_ci	struct wmid3_gds_get_input_param params = {
11238c2ecf20Sopenharmony_ci		.function_num = 0x1,
11248c2ecf20Sopenharmony_ci		.hotkey_number = commun_fn_key_number,
11258c2ecf20Sopenharmony_ci		.devices = device,
11268c2ecf20Sopenharmony_ci	};
11278c2ecf20Sopenharmony_ci	struct acpi_buffer input = {
11288c2ecf20Sopenharmony_ci		sizeof(struct wmid3_gds_get_input_param),
11298c2ecf20Sopenharmony_ci		&params
11308c2ecf20Sopenharmony_ci	};
11318c2ecf20Sopenharmony_ci	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
11348c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
11358c2ecf20Sopenharmony_ci		return status;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	obj = output.pointer;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if (!obj)
11408c2ecf20Sopenharmony_ci		return AE_ERROR;
11418c2ecf20Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
11428c2ecf20Sopenharmony_ci		kfree(obj);
11438c2ecf20Sopenharmony_ci		return AE_ERROR;
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci	if (obj->buffer.length != 8) {
11468c2ecf20Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
11478c2ecf20Sopenharmony_ci		kfree(obj);
11488c2ecf20Sopenharmony_ci		return AE_ERROR;
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
11528c2ecf20Sopenharmony_ci	kfree(obj);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
11558c2ecf20Sopenharmony_ci		pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
11568c2ecf20Sopenharmony_ci			device,
11578c2ecf20Sopenharmony_ci			return_value.error_code,
11588c2ecf20Sopenharmony_ci			return_value.ec_return_value);
11598c2ecf20Sopenharmony_ci	else
11608c2ecf20Sopenharmony_ci		*value = !!(return_value.devices & device);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	return status;
11638c2ecf20Sopenharmony_ci}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_cistatic acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
11668c2ecf20Sopenharmony_ci{
11678c2ecf20Sopenharmony_ci	u16 device;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	switch (cap) {
11708c2ecf20Sopenharmony_ci	case ACER_CAP_WIRELESS:
11718c2ecf20Sopenharmony_ci		device = ACER_WMID3_GDS_WIRELESS;
11728c2ecf20Sopenharmony_ci		break;
11738c2ecf20Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
11748c2ecf20Sopenharmony_ci		device = ACER_WMID3_GDS_BLUETOOTH;
11758c2ecf20Sopenharmony_ci		break;
11768c2ecf20Sopenharmony_ci	case ACER_CAP_THREEG:
11778c2ecf20Sopenharmony_ci		device = ACER_WMID3_GDS_THREEG;
11788c2ecf20Sopenharmony_ci		break;
11798c2ecf20Sopenharmony_ci	default:
11808c2ecf20Sopenharmony_ci		return AE_ERROR;
11818c2ecf20Sopenharmony_ci	}
11828c2ecf20Sopenharmony_ci	return wmid3_get_device_status(value, device);
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cistatic acpi_status wmid3_set_device_status(u32 value, u16 device)
11868c2ecf20Sopenharmony_ci{
11878c2ecf20Sopenharmony_ci	struct wmid3_gds_return_value return_value;
11888c2ecf20Sopenharmony_ci	acpi_status status;
11898c2ecf20Sopenharmony_ci	union acpi_object *obj;
11908c2ecf20Sopenharmony_ci	u16 devices;
11918c2ecf20Sopenharmony_ci	struct wmid3_gds_get_input_param get_params = {
11928c2ecf20Sopenharmony_ci		.function_num = 0x1,
11938c2ecf20Sopenharmony_ci		.hotkey_number = commun_fn_key_number,
11948c2ecf20Sopenharmony_ci		.devices = commun_func_bitmap,
11958c2ecf20Sopenharmony_ci	};
11968c2ecf20Sopenharmony_ci	struct acpi_buffer get_input = {
11978c2ecf20Sopenharmony_ci		sizeof(struct wmid3_gds_get_input_param),
11988c2ecf20Sopenharmony_ci		&get_params
11998c2ecf20Sopenharmony_ci	};
12008c2ecf20Sopenharmony_ci	struct wmid3_gds_set_input_param set_params = {
12018c2ecf20Sopenharmony_ci		.function_num = 0x2,
12028c2ecf20Sopenharmony_ci		.hotkey_number = commun_fn_key_number,
12038c2ecf20Sopenharmony_ci		.devices = commun_func_bitmap,
12048c2ecf20Sopenharmony_ci	};
12058c2ecf20Sopenharmony_ci	struct acpi_buffer set_input = {
12068c2ecf20Sopenharmony_ci		sizeof(struct wmid3_gds_set_input_param),
12078c2ecf20Sopenharmony_ci		&set_params
12088c2ecf20Sopenharmony_ci	};
12098c2ecf20Sopenharmony_ci	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
12108c2ecf20Sopenharmony_ci	struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
12138c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
12148c2ecf20Sopenharmony_ci		return status;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	obj = output.pointer;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (!obj)
12198c2ecf20Sopenharmony_ci		return AE_ERROR;
12208c2ecf20Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
12218c2ecf20Sopenharmony_ci		kfree(obj);
12228c2ecf20Sopenharmony_ci		return AE_ERROR;
12238c2ecf20Sopenharmony_ci	}
12248c2ecf20Sopenharmony_ci	if (obj->buffer.length != 8) {
12258c2ecf20Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
12268c2ecf20Sopenharmony_ci		kfree(obj);
12278c2ecf20Sopenharmony_ci		return AE_ERROR;
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
12318c2ecf20Sopenharmony_ci	kfree(obj);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value) {
12348c2ecf20Sopenharmony_ci		pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
12358c2ecf20Sopenharmony_ci			return_value.error_code,
12368c2ecf20Sopenharmony_ci			return_value.ec_return_value);
12378c2ecf20Sopenharmony_ci		return status;
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	devices = return_value.devices;
12418c2ecf20Sopenharmony_ci	set_params.devices = (value) ? (devices | device) : (devices & ~device);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
12448c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
12458c2ecf20Sopenharmony_ci		return status;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	obj = output2.pointer;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	if (!obj)
12508c2ecf20Sopenharmony_ci		return AE_ERROR;
12518c2ecf20Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
12528c2ecf20Sopenharmony_ci		kfree(obj);
12538c2ecf20Sopenharmony_ci		return AE_ERROR;
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci	if (obj->buffer.length != 4) {
12568c2ecf20Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
12578c2ecf20Sopenharmony_ci		kfree(obj);
12588c2ecf20Sopenharmony_ci		return AE_ERROR;
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
12628c2ecf20Sopenharmony_ci	kfree(obj);
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
12658c2ecf20Sopenharmony_ci		pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
12668c2ecf20Sopenharmony_ci			return_value.error_code,
12678c2ecf20Sopenharmony_ci			return_value.ec_return_value);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	return status;
12708c2ecf20Sopenharmony_ci}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cistatic acpi_status wmid_v2_set_u32(u32 value, u32 cap)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	u16 device;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	switch (cap) {
12778c2ecf20Sopenharmony_ci	case ACER_CAP_WIRELESS:
12788c2ecf20Sopenharmony_ci		device = ACER_WMID3_GDS_WIRELESS;
12798c2ecf20Sopenharmony_ci		break;
12808c2ecf20Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
12818c2ecf20Sopenharmony_ci		device = ACER_WMID3_GDS_BLUETOOTH;
12828c2ecf20Sopenharmony_ci		break;
12838c2ecf20Sopenharmony_ci	case ACER_CAP_THREEG:
12848c2ecf20Sopenharmony_ci		device = ACER_WMID3_GDS_THREEG;
12858c2ecf20Sopenharmony_ci		break;
12868c2ecf20Sopenharmony_ci	default:
12878c2ecf20Sopenharmony_ci		return AE_ERROR;
12888c2ecf20Sopenharmony_ci	}
12898c2ecf20Sopenharmony_ci	return wmid3_set_device_status(value, device);
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct hotkey_function_type_aa *type_aa;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	/* We are looking for OEM-specific Type AAh */
12978c2ecf20Sopenharmony_ci	if (header->type != 0xAA)
12988c2ecf20Sopenharmony_ci		return;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	has_type_aa = true;
13018c2ecf20Sopenharmony_ci	type_aa = (struct hotkey_function_type_aa *) header;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	pr_info("Function bitmap for Communication Button: 0x%x\n",
13048c2ecf20Sopenharmony_ci		type_aa->commun_func_bitmap);
13058c2ecf20Sopenharmony_ci	commun_func_bitmap = type_aa->commun_func_bitmap;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
13088c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_WIRELESS;
13098c2ecf20Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
13108c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_THREEG;
13118c2ecf20Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
13128c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_BLUETOOTH;
13138c2ecf20Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN)
13148c2ecf20Sopenharmony_ci		commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	commun_fn_key_number = type_aa->commun_fn_key_number;
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_cistatic acpi_status __init WMID_set_capabilities(void)
13208c2ecf20Sopenharmony_ci{
13218c2ecf20Sopenharmony_ci	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
13228c2ecf20Sopenharmony_ci	union acpi_object *obj;
13238c2ecf20Sopenharmony_ci	acpi_status status;
13248c2ecf20Sopenharmony_ci	u32 devices;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	status = wmi_query_block(WMID_GUID2, 0, &out);
13278c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
13288c2ecf20Sopenharmony_ci		return status;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
13318c2ecf20Sopenharmony_ci	if (obj) {
13328c2ecf20Sopenharmony_ci		if (obj->type == ACPI_TYPE_BUFFER &&
13338c2ecf20Sopenharmony_ci			(obj->buffer.length == sizeof(u32) ||
13348c2ecf20Sopenharmony_ci			obj->buffer.length == sizeof(u64))) {
13358c2ecf20Sopenharmony_ci			devices = *((u32 *) obj->buffer.pointer);
13368c2ecf20Sopenharmony_ci		} else if (obj->type == ACPI_TYPE_INTEGER) {
13378c2ecf20Sopenharmony_ci			devices = (u32) obj->integer.value;
13388c2ecf20Sopenharmony_ci		} else {
13398c2ecf20Sopenharmony_ci			kfree(out.pointer);
13408c2ecf20Sopenharmony_ci			return AE_ERROR;
13418c2ecf20Sopenharmony_ci		}
13428c2ecf20Sopenharmony_ci	} else {
13438c2ecf20Sopenharmony_ci		kfree(out.pointer);
13448c2ecf20Sopenharmony_ci		return AE_ERROR;
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
13488c2ecf20Sopenharmony_ci	if (devices & 0x07)
13498c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_WIRELESS;
13508c2ecf20Sopenharmony_ci	if (devices & 0x40)
13518c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_THREEG;
13528c2ecf20Sopenharmony_ci	if (devices & 0x10)
13538c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_BLUETOOTH;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	if (!(devices & 0x20))
13568c2ecf20Sopenharmony_ci		max_brightness = 0x9;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	kfree(out.pointer);
13598c2ecf20Sopenharmony_ci	return status;
13608c2ecf20Sopenharmony_ci}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_cistatic struct wmi_interface wmid_interface = {
13638c2ecf20Sopenharmony_ci	.type = ACER_WMID,
13648c2ecf20Sopenharmony_ci};
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic struct wmi_interface wmid_v2_interface = {
13678c2ecf20Sopenharmony_ci	.type = ACER_WMID_v2,
13688c2ecf20Sopenharmony_ci};
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci/*
13718c2ecf20Sopenharmony_ci * Generic Device (interface-independent)
13728c2ecf20Sopenharmony_ci */
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_cistatic acpi_status get_u32(u32 *value, u32 cap)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	acpi_status status = AE_ERROR;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	switch (interface->type) {
13798c2ecf20Sopenharmony_ci	case ACER_AMW0:
13808c2ecf20Sopenharmony_ci		status = AMW0_get_u32(value, cap);
13818c2ecf20Sopenharmony_ci		break;
13828c2ecf20Sopenharmony_ci	case ACER_AMW0_V2:
13838c2ecf20Sopenharmony_ci		if (cap == ACER_CAP_MAILLED) {
13848c2ecf20Sopenharmony_ci			status = AMW0_get_u32(value, cap);
13858c2ecf20Sopenharmony_ci			break;
13868c2ecf20Sopenharmony_ci		}
13878c2ecf20Sopenharmony_ci		fallthrough;
13888c2ecf20Sopenharmony_ci	case ACER_WMID:
13898c2ecf20Sopenharmony_ci		status = WMID_get_u32(value, cap);
13908c2ecf20Sopenharmony_ci		break;
13918c2ecf20Sopenharmony_ci	case ACER_WMID_v2:
13928c2ecf20Sopenharmony_ci		if (cap & (ACER_CAP_WIRELESS |
13938c2ecf20Sopenharmony_ci			   ACER_CAP_BLUETOOTH |
13948c2ecf20Sopenharmony_ci			   ACER_CAP_THREEG))
13958c2ecf20Sopenharmony_ci			status = wmid_v2_get_u32(value, cap);
13968c2ecf20Sopenharmony_ci		else if (wmi_has_guid(WMID_GUID2))
13978c2ecf20Sopenharmony_ci			status = WMID_get_u32(value, cap);
13988c2ecf20Sopenharmony_ci		break;
13998c2ecf20Sopenharmony_ci	}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	return status;
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic acpi_status set_u32(u32 value, u32 cap)
14058c2ecf20Sopenharmony_ci{
14068c2ecf20Sopenharmony_ci	acpi_status status;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	if (interface->capability & cap) {
14098c2ecf20Sopenharmony_ci		switch (interface->type) {
14108c2ecf20Sopenharmony_ci		case ACER_AMW0:
14118c2ecf20Sopenharmony_ci			return AMW0_set_u32(value, cap);
14128c2ecf20Sopenharmony_ci		case ACER_AMW0_V2:
14138c2ecf20Sopenharmony_ci			if (cap == ACER_CAP_MAILLED)
14148c2ecf20Sopenharmony_ci				return AMW0_set_u32(value, cap);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci			/*
14178c2ecf20Sopenharmony_ci			 * On some models, some WMID methods don't toggle
14188c2ecf20Sopenharmony_ci			 * properly. For those cases, we want to run the AMW0
14198c2ecf20Sopenharmony_ci			 * method afterwards to be certain we've really toggled
14208c2ecf20Sopenharmony_ci			 * the device state.
14218c2ecf20Sopenharmony_ci			 */
14228c2ecf20Sopenharmony_ci			if (cap == ACER_CAP_WIRELESS ||
14238c2ecf20Sopenharmony_ci				cap == ACER_CAP_BLUETOOTH) {
14248c2ecf20Sopenharmony_ci				status = WMID_set_u32(value, cap);
14258c2ecf20Sopenharmony_ci				if (ACPI_FAILURE(status))
14268c2ecf20Sopenharmony_ci					return status;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci				return AMW0_set_u32(value, cap);
14298c2ecf20Sopenharmony_ci			}
14308c2ecf20Sopenharmony_ci			fallthrough;
14318c2ecf20Sopenharmony_ci		case ACER_WMID:
14328c2ecf20Sopenharmony_ci			return WMID_set_u32(value, cap);
14338c2ecf20Sopenharmony_ci		case ACER_WMID_v2:
14348c2ecf20Sopenharmony_ci			if (cap & (ACER_CAP_WIRELESS |
14358c2ecf20Sopenharmony_ci				   ACER_CAP_BLUETOOTH |
14368c2ecf20Sopenharmony_ci				   ACER_CAP_THREEG))
14378c2ecf20Sopenharmony_ci				return wmid_v2_set_u32(value, cap);
14388c2ecf20Sopenharmony_ci			else if (wmi_has_guid(WMID_GUID2))
14398c2ecf20Sopenharmony_ci				return WMID_set_u32(value, cap);
14408c2ecf20Sopenharmony_ci			fallthrough;
14418c2ecf20Sopenharmony_ci		default:
14428c2ecf20Sopenharmony_ci			return AE_BAD_PARAMETER;
14438c2ecf20Sopenharmony_ci		}
14448c2ecf20Sopenharmony_ci	}
14458c2ecf20Sopenharmony_ci	return AE_BAD_PARAMETER;
14468c2ecf20Sopenharmony_ci}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_cistatic void __init acer_commandline_init(void)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	/*
14518c2ecf20Sopenharmony_ci	 * These will all fail silently if the value given is invalid, or the
14528c2ecf20Sopenharmony_ci	 * capability isn't available on the given interface
14538c2ecf20Sopenharmony_ci	 */
14548c2ecf20Sopenharmony_ci	if (mailled >= 0)
14558c2ecf20Sopenharmony_ci		set_u32(mailled, ACER_CAP_MAILLED);
14568c2ecf20Sopenharmony_ci	if (!has_type_aa && threeg >= 0)
14578c2ecf20Sopenharmony_ci		set_u32(threeg, ACER_CAP_THREEG);
14588c2ecf20Sopenharmony_ci	if (brightness >= 0)
14598c2ecf20Sopenharmony_ci		set_u32(brightness, ACER_CAP_BRIGHTNESS);
14608c2ecf20Sopenharmony_ci}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci/*
14638c2ecf20Sopenharmony_ci * LED device (Mail LED only, no other LEDs known yet)
14648c2ecf20Sopenharmony_ci */
14658c2ecf20Sopenharmony_cistatic void mail_led_set(struct led_classdev *led_cdev,
14668c2ecf20Sopenharmony_cienum led_brightness value)
14678c2ecf20Sopenharmony_ci{
14688c2ecf20Sopenharmony_ci	set_u32(value, ACER_CAP_MAILLED);
14698c2ecf20Sopenharmony_ci}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_cistatic struct led_classdev mail_led = {
14728c2ecf20Sopenharmony_ci	.name = "acer-wmi::mail",
14738c2ecf20Sopenharmony_ci	.brightness_set = mail_led_set,
14748c2ecf20Sopenharmony_ci};
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_cistatic int acer_led_init(struct device *dev)
14778c2ecf20Sopenharmony_ci{
14788c2ecf20Sopenharmony_ci	return led_classdev_register(dev, &mail_led);
14798c2ecf20Sopenharmony_ci}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_cistatic void acer_led_exit(void)
14828c2ecf20Sopenharmony_ci{
14838c2ecf20Sopenharmony_ci	set_u32(LED_OFF, ACER_CAP_MAILLED);
14848c2ecf20Sopenharmony_ci	led_classdev_unregister(&mail_led);
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci/*
14888c2ecf20Sopenharmony_ci * Backlight device
14898c2ecf20Sopenharmony_ci */
14908c2ecf20Sopenharmony_cistatic struct backlight_device *acer_backlight_device;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_cistatic int read_brightness(struct backlight_device *bd)
14938c2ecf20Sopenharmony_ci{
14948c2ecf20Sopenharmony_ci	u32 value;
14958c2ecf20Sopenharmony_ci	get_u32(&value, ACER_CAP_BRIGHTNESS);
14968c2ecf20Sopenharmony_ci	return value;
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_cistatic int update_bl_status(struct backlight_device *bd)
15008c2ecf20Sopenharmony_ci{
15018c2ecf20Sopenharmony_ci	int intensity = bd->props.brightness;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	if (bd->props.power != FB_BLANK_UNBLANK)
15048c2ecf20Sopenharmony_ci		intensity = 0;
15058c2ecf20Sopenharmony_ci	if (bd->props.fb_blank != FB_BLANK_UNBLANK)
15068c2ecf20Sopenharmony_ci		intensity = 0;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	set_u32(intensity, ACER_CAP_BRIGHTNESS);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	return 0;
15118c2ecf20Sopenharmony_ci}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_cistatic const struct backlight_ops acer_bl_ops = {
15148c2ecf20Sopenharmony_ci	.get_brightness = read_brightness,
15158c2ecf20Sopenharmony_ci	.update_status = update_bl_status,
15168c2ecf20Sopenharmony_ci};
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_cistatic int acer_backlight_init(struct device *dev)
15198c2ecf20Sopenharmony_ci{
15208c2ecf20Sopenharmony_ci	struct backlight_properties props;
15218c2ecf20Sopenharmony_ci	struct backlight_device *bd;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	memset(&props, 0, sizeof(struct backlight_properties));
15248c2ecf20Sopenharmony_ci	props.type = BACKLIGHT_PLATFORM;
15258c2ecf20Sopenharmony_ci	props.max_brightness = max_brightness;
15268c2ecf20Sopenharmony_ci	bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
15278c2ecf20Sopenharmony_ci				       &props);
15288c2ecf20Sopenharmony_ci	if (IS_ERR(bd)) {
15298c2ecf20Sopenharmony_ci		pr_err("Could not register Acer backlight device\n");
15308c2ecf20Sopenharmony_ci		acer_backlight_device = NULL;
15318c2ecf20Sopenharmony_ci		return PTR_ERR(bd);
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	acer_backlight_device = bd;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	bd->props.power = FB_BLANK_UNBLANK;
15378c2ecf20Sopenharmony_ci	bd->props.brightness = read_brightness(bd);
15388c2ecf20Sopenharmony_ci	backlight_update_status(bd);
15398c2ecf20Sopenharmony_ci	return 0;
15408c2ecf20Sopenharmony_ci}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_cistatic void acer_backlight_exit(void)
15438c2ecf20Sopenharmony_ci{
15448c2ecf20Sopenharmony_ci	backlight_device_unregister(acer_backlight_device);
15458c2ecf20Sopenharmony_ci}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci/*
15488c2ecf20Sopenharmony_ci * Accelerometer device
15498c2ecf20Sopenharmony_ci */
15508c2ecf20Sopenharmony_cistatic acpi_handle gsensor_handle;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_cistatic int acer_gsensor_init(void)
15538c2ecf20Sopenharmony_ci{
15548c2ecf20Sopenharmony_ci	acpi_status status;
15558c2ecf20Sopenharmony_ci	struct acpi_buffer output;
15568c2ecf20Sopenharmony_ci	union acpi_object out_obj;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	output.length = sizeof(out_obj);
15598c2ecf20Sopenharmony_ci	output.pointer = &out_obj;
15608c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
15618c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
15628c2ecf20Sopenharmony_ci		return -1;
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	return 0;
15658c2ecf20Sopenharmony_ci}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_cistatic int acer_gsensor_open(struct input_dev *input)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	return acer_gsensor_init();
15708c2ecf20Sopenharmony_ci}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_cistatic int acer_gsensor_event(void)
15738c2ecf20Sopenharmony_ci{
15748c2ecf20Sopenharmony_ci	acpi_status status;
15758c2ecf20Sopenharmony_ci	struct acpi_buffer output;
15768c2ecf20Sopenharmony_ci	union acpi_object out_obj[5];
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	if (!acer_wmi_accel_dev)
15798c2ecf20Sopenharmony_ci		return -1;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	output.length = sizeof(out_obj);
15828c2ecf20Sopenharmony_ci	output.pointer = out_obj;
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
15858c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
15868c2ecf20Sopenharmony_ci		return -1;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	if (out_obj->package.count != 4)
15898c2ecf20Sopenharmony_ci		return -1;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	input_report_abs(acer_wmi_accel_dev, ABS_X,
15928c2ecf20Sopenharmony_ci		(s16)out_obj->package.elements[0].integer.value);
15938c2ecf20Sopenharmony_ci	input_report_abs(acer_wmi_accel_dev, ABS_Y,
15948c2ecf20Sopenharmony_ci		(s16)out_obj->package.elements[1].integer.value);
15958c2ecf20Sopenharmony_ci	input_report_abs(acer_wmi_accel_dev, ABS_Z,
15968c2ecf20Sopenharmony_ci		(s16)out_obj->package.elements[2].integer.value);
15978c2ecf20Sopenharmony_ci	input_sync(acer_wmi_accel_dev);
15988c2ecf20Sopenharmony_ci	return 0;
15998c2ecf20Sopenharmony_ci}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci/*
16028c2ecf20Sopenharmony_ci * Switch series keyboard dock status
16038c2ecf20Sopenharmony_ci */
16048c2ecf20Sopenharmony_cistatic int acer_kbd_dock_state_to_sw_tablet_mode(u8 kbd_dock_state)
16058c2ecf20Sopenharmony_ci{
16068c2ecf20Sopenharmony_ci	switch (kbd_dock_state) {
16078c2ecf20Sopenharmony_ci	case 0x01: /* Docked, traditional clamshell laptop mode */
16088c2ecf20Sopenharmony_ci		return 0;
16098c2ecf20Sopenharmony_ci	case 0x04: /* Stand-alone tablet */
16108c2ecf20Sopenharmony_ci	case 0x40: /* Docked, tent mode, keyboard not usable */
16118c2ecf20Sopenharmony_ci		return 1;
16128c2ecf20Sopenharmony_ci	default:
16138c2ecf20Sopenharmony_ci		pr_warn("Unknown kbd_dock_state 0x%02x\n", kbd_dock_state);
16148c2ecf20Sopenharmony_ci	}
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	return 0;
16178c2ecf20Sopenharmony_ci}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_cistatic void acer_kbd_dock_get_initial_state(void)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	u8 *output, input[8] = { 0x05, 0x00, };
16228c2ecf20Sopenharmony_ci	struct acpi_buffer input_buf = { sizeof(input), input };
16238c2ecf20Sopenharmony_ci	struct acpi_buffer output_buf = { ACPI_ALLOCATE_BUFFER, NULL };
16248c2ecf20Sopenharmony_ci	union acpi_object *obj;
16258c2ecf20Sopenharmony_ci	acpi_status status;
16268c2ecf20Sopenharmony_ci	int sw_tablet_mode;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input_buf, &output_buf);
16298c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
16308c2ecf20Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status, "Error getting keyboard-dock initial status"));
16318c2ecf20Sopenharmony_ci		return;
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	obj = output_buf.pointer;
16358c2ecf20Sopenharmony_ci	if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
16368c2ecf20Sopenharmony_ci		pr_err("Unexpected output format getting keyboard-dock initial status\n");
16378c2ecf20Sopenharmony_ci		goto out_free_obj;
16388c2ecf20Sopenharmony_ci	}
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	output = obj->buffer.pointer;
16418c2ecf20Sopenharmony_ci	if (output[0] != 0x00 || (output[3] != 0x05 && output[3] != 0x45)) {
16428c2ecf20Sopenharmony_ci		pr_err("Unexpected output [0]=0x%02x [3]=0x%02x getting keyboard-dock initial status\n",
16438c2ecf20Sopenharmony_ci		       output[0], output[3]);
16448c2ecf20Sopenharmony_ci		goto out_free_obj;
16458c2ecf20Sopenharmony_ci	}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(output[4]);
16488c2ecf20Sopenharmony_ci	input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ciout_free_obj:
16518c2ecf20Sopenharmony_ci	kfree(obj);
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic void acer_kbd_dock_event(const struct event_return_value *event)
16558c2ecf20Sopenharmony_ci{
16568c2ecf20Sopenharmony_ci	int sw_tablet_mode;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	if (!has_cap(ACER_CAP_KBD_DOCK))
16598c2ecf20Sopenharmony_ci		return;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(event->kbd_dock_state);
16628c2ecf20Sopenharmony_ci	input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
16638c2ecf20Sopenharmony_ci	input_sync(acer_wmi_input_dev);
16648c2ecf20Sopenharmony_ci}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci/*
16678c2ecf20Sopenharmony_ci * Rfkill devices
16688c2ecf20Sopenharmony_ci */
16698c2ecf20Sopenharmony_cistatic void acer_rfkill_update(struct work_struct *ignored);
16708c2ecf20Sopenharmony_cistatic DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
16718c2ecf20Sopenharmony_cistatic void acer_rfkill_update(struct work_struct *ignored)
16728c2ecf20Sopenharmony_ci{
16738c2ecf20Sopenharmony_ci	u32 state;
16748c2ecf20Sopenharmony_ci	acpi_status status;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
16778c2ecf20Sopenharmony_ci		status = get_u32(&state, ACER_CAP_WIRELESS);
16788c2ecf20Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
16798c2ecf20Sopenharmony_ci			if (quirks->wireless == 3)
16808c2ecf20Sopenharmony_ci				rfkill_set_hw_state(wireless_rfkill, !state);
16818c2ecf20Sopenharmony_ci			else
16828c2ecf20Sopenharmony_ci				rfkill_set_sw_state(wireless_rfkill, !state);
16838c2ecf20Sopenharmony_ci		}
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
16878c2ecf20Sopenharmony_ci		status = get_u32(&state, ACER_CAP_BLUETOOTH);
16888c2ecf20Sopenharmony_ci		if (ACPI_SUCCESS(status))
16898c2ecf20Sopenharmony_ci			rfkill_set_sw_state(bluetooth_rfkill, !state);
16908c2ecf20Sopenharmony_ci	}
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
16938c2ecf20Sopenharmony_ci		status = get_u32(&state, ACER_WMID3_GDS_THREEG);
16948c2ecf20Sopenharmony_ci		if (ACPI_SUCCESS(status))
16958c2ecf20Sopenharmony_ci			rfkill_set_sw_state(threeg_rfkill, !state);
16968c2ecf20Sopenharmony_ci	}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_cistatic int acer_rfkill_set(void *data, bool blocked)
17028c2ecf20Sopenharmony_ci{
17038c2ecf20Sopenharmony_ci	acpi_status status;
17048c2ecf20Sopenharmony_ci	u32 cap = (unsigned long)data;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	if (rfkill_inited) {
17078c2ecf20Sopenharmony_ci		status = set_u32(!blocked, cap);
17088c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(status))
17098c2ecf20Sopenharmony_ci			return -ENODEV;
17108c2ecf20Sopenharmony_ci	}
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	return 0;
17138c2ecf20Sopenharmony_ci}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_cistatic const struct rfkill_ops acer_rfkill_ops = {
17168c2ecf20Sopenharmony_ci	.set_block = acer_rfkill_set,
17178c2ecf20Sopenharmony_ci};
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_cistatic struct rfkill *acer_rfkill_register(struct device *dev,
17208c2ecf20Sopenharmony_ci					   enum rfkill_type type,
17218c2ecf20Sopenharmony_ci					   char *name, u32 cap)
17228c2ecf20Sopenharmony_ci{
17238c2ecf20Sopenharmony_ci	int err;
17248c2ecf20Sopenharmony_ci	struct rfkill *rfkill_dev;
17258c2ecf20Sopenharmony_ci	u32 state;
17268c2ecf20Sopenharmony_ci	acpi_status status;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	rfkill_dev = rfkill_alloc(name, dev, type,
17298c2ecf20Sopenharmony_ci				  &acer_rfkill_ops,
17308c2ecf20Sopenharmony_ci				  (void *)(unsigned long)cap);
17318c2ecf20Sopenharmony_ci	if (!rfkill_dev)
17328c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	status = get_u32(&state, cap);
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	err = rfkill_register(rfkill_dev);
17378c2ecf20Sopenharmony_ci	if (err) {
17388c2ecf20Sopenharmony_ci		rfkill_destroy(rfkill_dev);
17398c2ecf20Sopenharmony_ci		return ERR_PTR(err);
17408c2ecf20Sopenharmony_ci	}
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
17438c2ecf20Sopenharmony_ci		rfkill_set_sw_state(rfkill_dev, !state);
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	return rfkill_dev;
17468c2ecf20Sopenharmony_ci}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_cistatic int acer_rfkill_init(struct device *dev)
17498c2ecf20Sopenharmony_ci{
17508c2ecf20Sopenharmony_ci	int err;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
17538c2ecf20Sopenharmony_ci		wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
17548c2ecf20Sopenharmony_ci			"acer-wireless", ACER_CAP_WIRELESS);
17558c2ecf20Sopenharmony_ci		if (IS_ERR(wireless_rfkill)) {
17568c2ecf20Sopenharmony_ci			err = PTR_ERR(wireless_rfkill);
17578c2ecf20Sopenharmony_ci			goto error_wireless;
17588c2ecf20Sopenharmony_ci		}
17598c2ecf20Sopenharmony_ci	}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
17628c2ecf20Sopenharmony_ci		bluetooth_rfkill = acer_rfkill_register(dev,
17638c2ecf20Sopenharmony_ci			RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
17648c2ecf20Sopenharmony_ci			ACER_CAP_BLUETOOTH);
17658c2ecf20Sopenharmony_ci		if (IS_ERR(bluetooth_rfkill)) {
17668c2ecf20Sopenharmony_ci			err = PTR_ERR(bluetooth_rfkill);
17678c2ecf20Sopenharmony_ci			goto error_bluetooth;
17688c2ecf20Sopenharmony_ci		}
17698c2ecf20Sopenharmony_ci	}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_THREEG)) {
17728c2ecf20Sopenharmony_ci		threeg_rfkill = acer_rfkill_register(dev,
17738c2ecf20Sopenharmony_ci			RFKILL_TYPE_WWAN, "acer-threeg",
17748c2ecf20Sopenharmony_ci			ACER_CAP_THREEG);
17758c2ecf20Sopenharmony_ci		if (IS_ERR(threeg_rfkill)) {
17768c2ecf20Sopenharmony_ci			err = PTR_ERR(threeg_rfkill);
17778c2ecf20Sopenharmony_ci			goto error_threeg;
17788c2ecf20Sopenharmony_ci		}
17798c2ecf20Sopenharmony_ci	}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	rfkill_inited = true;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
17848c2ecf20Sopenharmony_ci	    has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
17858c2ecf20Sopenharmony_ci		schedule_delayed_work(&acer_rfkill_work,
17868c2ecf20Sopenharmony_ci			round_jiffies_relative(HZ));
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	return 0;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_cierror_threeg:
17918c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
17928c2ecf20Sopenharmony_ci		rfkill_unregister(bluetooth_rfkill);
17938c2ecf20Sopenharmony_ci		rfkill_destroy(bluetooth_rfkill);
17948c2ecf20Sopenharmony_ci	}
17958c2ecf20Sopenharmony_cierror_bluetooth:
17968c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
17978c2ecf20Sopenharmony_ci		rfkill_unregister(wireless_rfkill);
17988c2ecf20Sopenharmony_ci		rfkill_destroy(wireless_rfkill);
17998c2ecf20Sopenharmony_ci	}
18008c2ecf20Sopenharmony_cierror_wireless:
18018c2ecf20Sopenharmony_ci	return err;
18028c2ecf20Sopenharmony_ci}
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_cistatic void acer_rfkill_exit(void)
18058c2ecf20Sopenharmony_ci{
18068c2ecf20Sopenharmony_ci	if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
18078c2ecf20Sopenharmony_ci	    has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
18088c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&acer_rfkill_work);
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
18118c2ecf20Sopenharmony_ci		rfkill_unregister(wireless_rfkill);
18128c2ecf20Sopenharmony_ci		rfkill_destroy(wireless_rfkill);
18138c2ecf20Sopenharmony_ci	}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
18168c2ecf20Sopenharmony_ci		rfkill_unregister(bluetooth_rfkill);
18178c2ecf20Sopenharmony_ci		rfkill_destroy(bluetooth_rfkill);
18188c2ecf20Sopenharmony_ci	}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_THREEG)) {
18218c2ecf20Sopenharmony_ci		rfkill_unregister(threeg_rfkill);
18228c2ecf20Sopenharmony_ci		rfkill_destroy(threeg_rfkill);
18238c2ecf20Sopenharmony_ci	}
18248c2ecf20Sopenharmony_ci	return;
18258c2ecf20Sopenharmony_ci}
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_cistatic void acer_wmi_notify(u32 value, void *context)
18288c2ecf20Sopenharmony_ci{
18298c2ecf20Sopenharmony_ci	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
18308c2ecf20Sopenharmony_ci	union acpi_object *obj;
18318c2ecf20Sopenharmony_ci	struct event_return_value return_value;
18328c2ecf20Sopenharmony_ci	acpi_status status;
18338c2ecf20Sopenharmony_ci	u16 device_state;
18348c2ecf20Sopenharmony_ci	const struct key_entry *key;
18358c2ecf20Sopenharmony_ci	u32 scancode;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	status = wmi_get_event_data(value, &response);
18388c2ecf20Sopenharmony_ci	if (status != AE_OK) {
18398c2ecf20Sopenharmony_ci		pr_warn("bad event status 0x%x\n", status);
18408c2ecf20Sopenharmony_ci		return;
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	obj = (union acpi_object *)response.pointer;
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	if (!obj)
18468c2ecf20Sopenharmony_ci		return;
18478c2ecf20Sopenharmony_ci	if (obj->type != ACPI_TYPE_BUFFER) {
18488c2ecf20Sopenharmony_ci		pr_warn("Unknown response received %d\n", obj->type);
18498c2ecf20Sopenharmony_ci		kfree(obj);
18508c2ecf20Sopenharmony_ci		return;
18518c2ecf20Sopenharmony_ci	}
18528c2ecf20Sopenharmony_ci	if (obj->buffer.length != 8) {
18538c2ecf20Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
18548c2ecf20Sopenharmony_ci		kfree(obj);
18558c2ecf20Sopenharmony_ci		return;
18568c2ecf20Sopenharmony_ci	}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	return_value = *((struct event_return_value *)obj->buffer.pointer);
18598c2ecf20Sopenharmony_ci	kfree(obj);
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	switch (return_value.function) {
18628c2ecf20Sopenharmony_ci	case WMID_HOTKEY_EVENT:
18638c2ecf20Sopenharmony_ci		device_state = return_value.device_state;
18648c2ecf20Sopenharmony_ci		pr_debug("device state: 0x%x\n", device_state);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci		key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
18678c2ecf20Sopenharmony_ci							return_value.key_num);
18688c2ecf20Sopenharmony_ci		if (!key) {
18698c2ecf20Sopenharmony_ci			pr_warn("Unknown key number - 0x%x\n",
18708c2ecf20Sopenharmony_ci				return_value.key_num);
18718c2ecf20Sopenharmony_ci		} else {
18728c2ecf20Sopenharmony_ci			scancode = return_value.key_num;
18738c2ecf20Sopenharmony_ci			switch (key->keycode) {
18748c2ecf20Sopenharmony_ci			case KEY_WLAN:
18758c2ecf20Sopenharmony_ci			case KEY_BLUETOOTH:
18768c2ecf20Sopenharmony_ci				if (has_cap(ACER_CAP_WIRELESS))
18778c2ecf20Sopenharmony_ci					rfkill_set_sw_state(wireless_rfkill,
18788c2ecf20Sopenharmony_ci						!(device_state & ACER_WMID3_GDS_WIRELESS));
18798c2ecf20Sopenharmony_ci				if (has_cap(ACER_CAP_THREEG))
18808c2ecf20Sopenharmony_ci					rfkill_set_sw_state(threeg_rfkill,
18818c2ecf20Sopenharmony_ci						!(device_state & ACER_WMID3_GDS_THREEG));
18828c2ecf20Sopenharmony_ci				if (has_cap(ACER_CAP_BLUETOOTH))
18838c2ecf20Sopenharmony_ci					rfkill_set_sw_state(bluetooth_rfkill,
18848c2ecf20Sopenharmony_ci						!(device_state & ACER_WMID3_GDS_BLUETOOTH));
18858c2ecf20Sopenharmony_ci				break;
18868c2ecf20Sopenharmony_ci			case KEY_TOUCHPAD_TOGGLE:
18878c2ecf20Sopenharmony_ci				scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ?
18888c2ecf20Sopenharmony_ci						KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF;
18898c2ecf20Sopenharmony_ci			}
18908c2ecf20Sopenharmony_ci			sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
18918c2ecf20Sopenharmony_ci		}
18928c2ecf20Sopenharmony_ci		break;
18938c2ecf20Sopenharmony_ci	case WMID_ACCEL_OR_KBD_DOCK_EVENT:
18948c2ecf20Sopenharmony_ci		acer_gsensor_event();
18958c2ecf20Sopenharmony_ci		acer_kbd_dock_event(&return_value);
18968c2ecf20Sopenharmony_ci		break;
18978c2ecf20Sopenharmony_ci	default:
18988c2ecf20Sopenharmony_ci		pr_warn("Unknown function number - %d - %d\n",
18998c2ecf20Sopenharmony_ci			return_value.function, return_value.key_num);
19008c2ecf20Sopenharmony_ci		break;
19018c2ecf20Sopenharmony_ci	}
19028c2ecf20Sopenharmony_ci}
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_cistatic acpi_status __init
19058c2ecf20Sopenharmony_ciwmid3_set_function_mode(struct func_input_params *params,
19068c2ecf20Sopenharmony_ci			struct func_return_value *return_value)
19078c2ecf20Sopenharmony_ci{
19088c2ecf20Sopenharmony_ci	acpi_status status;
19098c2ecf20Sopenharmony_ci	union acpi_object *obj;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	struct acpi_buffer input = { sizeof(struct func_input_params), params };
19128c2ecf20Sopenharmony_ci	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
19158c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
19168c2ecf20Sopenharmony_ci		return status;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	obj = output.pointer;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	if (!obj)
19218c2ecf20Sopenharmony_ci		return AE_ERROR;
19228c2ecf20Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
19238c2ecf20Sopenharmony_ci		kfree(obj);
19248c2ecf20Sopenharmony_ci		return AE_ERROR;
19258c2ecf20Sopenharmony_ci	}
19268c2ecf20Sopenharmony_ci	if (obj->buffer.length != 4) {
19278c2ecf20Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
19288c2ecf20Sopenharmony_ci		kfree(obj);
19298c2ecf20Sopenharmony_ci		return AE_ERROR;
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	*return_value = *((struct func_return_value *)obj->buffer.pointer);
19338c2ecf20Sopenharmony_ci	kfree(obj);
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	return status;
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_cistatic int __init acer_wmi_enable_ec_raw(void)
19398c2ecf20Sopenharmony_ci{
19408c2ecf20Sopenharmony_ci	struct func_return_value return_value;
19418c2ecf20Sopenharmony_ci	acpi_status status;
19428c2ecf20Sopenharmony_ci	struct func_input_params params = {
19438c2ecf20Sopenharmony_ci		.function_num = 0x1,
19448c2ecf20Sopenharmony_ci		.commun_devices = 0xFFFF,
19458c2ecf20Sopenharmony_ci		.devices = 0xFFFF,
19468c2ecf20Sopenharmony_ci		.app_status = 0x00,		/* Launch Manager Deactive */
19478c2ecf20Sopenharmony_ci		.app_mask = 0x01,
19488c2ecf20Sopenharmony_ci	};
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	status = wmid3_set_function_mode(&params, &return_value);
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
19538c2ecf20Sopenharmony_ci		pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
19548c2ecf20Sopenharmony_ci			return_value.error_code,
19558c2ecf20Sopenharmony_ci			return_value.ec_return_value);
19568c2ecf20Sopenharmony_ci	else
19578c2ecf20Sopenharmony_ci		pr_info("Enabled EC raw mode\n");
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	return status;
19608c2ecf20Sopenharmony_ci}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_cistatic int __init acer_wmi_enable_lm(void)
19638c2ecf20Sopenharmony_ci{
19648c2ecf20Sopenharmony_ci	struct func_return_value return_value;
19658c2ecf20Sopenharmony_ci	acpi_status status;
19668c2ecf20Sopenharmony_ci	struct func_input_params params = {
19678c2ecf20Sopenharmony_ci		.function_num = 0x1,
19688c2ecf20Sopenharmony_ci		.commun_devices = 0xFFFF,
19698c2ecf20Sopenharmony_ci		.devices = 0xFFFF,
19708c2ecf20Sopenharmony_ci		.app_status = 0x01,            /* Launch Manager Active */
19718c2ecf20Sopenharmony_ci		.app_mask = 0x01,
19728c2ecf20Sopenharmony_ci	};
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	status = wmid3_set_function_mode(&params, &return_value);
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
19778c2ecf20Sopenharmony_ci		pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
19788c2ecf20Sopenharmony_ci			return_value.error_code,
19798c2ecf20Sopenharmony_ci			return_value.ec_return_value);
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	return status;
19828c2ecf20Sopenharmony_ci}
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_cistatic int __init acer_wmi_enable_rf_button(void)
19858c2ecf20Sopenharmony_ci{
19868c2ecf20Sopenharmony_ci	struct func_return_value return_value;
19878c2ecf20Sopenharmony_ci	acpi_status status;
19888c2ecf20Sopenharmony_ci	struct func_input_params params = {
19898c2ecf20Sopenharmony_ci		.function_num = 0x1,
19908c2ecf20Sopenharmony_ci		.commun_devices = 0xFFFF,
19918c2ecf20Sopenharmony_ci		.devices = 0xFFFF,
19928c2ecf20Sopenharmony_ci		.app_status = 0x10,            /* RF Button Active */
19938c2ecf20Sopenharmony_ci		.app_mask = 0x10,
19948c2ecf20Sopenharmony_ci	};
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	status = wmid3_set_function_mode(&params, &return_value);
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
19998c2ecf20Sopenharmony_ci		pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n",
20008c2ecf20Sopenharmony_ci			return_value.error_code,
20018c2ecf20Sopenharmony_ci			return_value.ec_return_value);
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	return status;
20048c2ecf20Sopenharmony_ci}
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_cistatic int __init acer_wmi_accel_setup(void)
20078c2ecf20Sopenharmony_ci{
20088c2ecf20Sopenharmony_ci	struct acpi_device *adev;
20098c2ecf20Sopenharmony_ci	int err;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	adev = acpi_dev_get_first_match_dev("BST0001", NULL, -1);
20128c2ecf20Sopenharmony_ci	if (!adev)
20138c2ecf20Sopenharmony_ci		return -ENODEV;
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	gsensor_handle = acpi_device_handle(adev);
20168c2ecf20Sopenharmony_ci	acpi_dev_put(adev);
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	acer_wmi_accel_dev = input_allocate_device();
20198c2ecf20Sopenharmony_ci	if (!acer_wmi_accel_dev)
20208c2ecf20Sopenharmony_ci		return -ENOMEM;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	acer_wmi_accel_dev->open = acer_gsensor_open;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
20258c2ecf20Sopenharmony_ci	acer_wmi_accel_dev->phys = "wmi/input1";
20268c2ecf20Sopenharmony_ci	acer_wmi_accel_dev->id.bustype = BUS_HOST;
20278c2ecf20Sopenharmony_ci	acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
20288c2ecf20Sopenharmony_ci	input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
20298c2ecf20Sopenharmony_ci	input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
20308c2ecf20Sopenharmony_ci	input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	err = input_register_device(acer_wmi_accel_dev);
20338c2ecf20Sopenharmony_ci	if (err)
20348c2ecf20Sopenharmony_ci		goto err_free_dev;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	return 0;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_cierr_free_dev:
20398c2ecf20Sopenharmony_ci	input_free_device(acer_wmi_accel_dev);
20408c2ecf20Sopenharmony_ci	return err;
20418c2ecf20Sopenharmony_ci}
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_cistatic int __init acer_wmi_input_setup(void)
20448c2ecf20Sopenharmony_ci{
20458c2ecf20Sopenharmony_ci	acpi_status status;
20468c2ecf20Sopenharmony_ci	int err;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	acer_wmi_input_dev = input_allocate_device();
20498c2ecf20Sopenharmony_ci	if (!acer_wmi_input_dev)
20508c2ecf20Sopenharmony_ci		return -ENOMEM;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	acer_wmi_input_dev->name = "Acer WMI hotkeys";
20538c2ecf20Sopenharmony_ci	acer_wmi_input_dev->phys = "wmi/input0";
20548c2ecf20Sopenharmony_ci	acer_wmi_input_dev->id.bustype = BUS_HOST;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
20578c2ecf20Sopenharmony_ci	if (err)
20588c2ecf20Sopenharmony_ci		goto err_free_dev;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_KBD_DOCK))
20618c2ecf20Sopenharmony_ci		input_set_capability(acer_wmi_input_dev, EV_SW, SW_TABLET_MODE);
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
20648c2ecf20Sopenharmony_ci						acer_wmi_notify, NULL);
20658c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
20668c2ecf20Sopenharmony_ci		err = -EIO;
20678c2ecf20Sopenharmony_ci		goto err_free_dev;
20688c2ecf20Sopenharmony_ci	}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_KBD_DOCK))
20718c2ecf20Sopenharmony_ci		acer_kbd_dock_get_initial_state();
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	err = input_register_device(acer_wmi_input_dev);
20748c2ecf20Sopenharmony_ci	if (err)
20758c2ecf20Sopenharmony_ci		goto err_uninstall_notifier;
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	return 0;
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_cierr_uninstall_notifier:
20808c2ecf20Sopenharmony_ci	wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
20818c2ecf20Sopenharmony_cierr_free_dev:
20828c2ecf20Sopenharmony_ci	input_free_device(acer_wmi_input_dev);
20838c2ecf20Sopenharmony_ci	return err;
20848c2ecf20Sopenharmony_ci}
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_cistatic void acer_wmi_input_destroy(void)
20878c2ecf20Sopenharmony_ci{
20888c2ecf20Sopenharmony_ci	wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
20898c2ecf20Sopenharmony_ci	input_unregister_device(acer_wmi_input_dev);
20908c2ecf20Sopenharmony_ci}
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci/*
20938c2ecf20Sopenharmony_ci * debugfs functions
20948c2ecf20Sopenharmony_ci */
20958c2ecf20Sopenharmony_cistatic u32 get_wmid_devices(void)
20968c2ecf20Sopenharmony_ci{
20978c2ecf20Sopenharmony_ci	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
20988c2ecf20Sopenharmony_ci	union acpi_object *obj;
20998c2ecf20Sopenharmony_ci	acpi_status status;
21008c2ecf20Sopenharmony_ci	u32 devices = 0;
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	status = wmi_query_block(WMID_GUID2, 0, &out);
21038c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
21048c2ecf20Sopenharmony_ci		return 0;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
21078c2ecf20Sopenharmony_ci	if (obj) {
21088c2ecf20Sopenharmony_ci		if (obj->type == ACPI_TYPE_BUFFER &&
21098c2ecf20Sopenharmony_ci			(obj->buffer.length == sizeof(u32) ||
21108c2ecf20Sopenharmony_ci			obj->buffer.length == sizeof(u64))) {
21118c2ecf20Sopenharmony_ci			devices = *((u32 *) obj->buffer.pointer);
21128c2ecf20Sopenharmony_ci		} else if (obj->type == ACPI_TYPE_INTEGER) {
21138c2ecf20Sopenharmony_ci			devices = (u32) obj->integer.value;
21148c2ecf20Sopenharmony_ci		}
21158c2ecf20Sopenharmony_ci	}
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	kfree(out.pointer);
21188c2ecf20Sopenharmony_ci	return devices;
21198c2ecf20Sopenharmony_ci}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci/*
21228c2ecf20Sopenharmony_ci * Platform device
21238c2ecf20Sopenharmony_ci */
21248c2ecf20Sopenharmony_cistatic int acer_platform_probe(struct platform_device *device)
21258c2ecf20Sopenharmony_ci{
21268c2ecf20Sopenharmony_ci	int err;
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED)) {
21298c2ecf20Sopenharmony_ci		err = acer_led_init(&device->dev);
21308c2ecf20Sopenharmony_ci		if (err)
21318c2ecf20Sopenharmony_ci			goto error_mailled;
21328c2ecf20Sopenharmony_ci	}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS)) {
21358c2ecf20Sopenharmony_ci		err = acer_backlight_init(&device->dev);
21368c2ecf20Sopenharmony_ci		if (err)
21378c2ecf20Sopenharmony_ci			goto error_brightness;
21388c2ecf20Sopenharmony_ci	}
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	err = acer_rfkill_init(&device->dev);
21418c2ecf20Sopenharmony_ci	if (err)
21428c2ecf20Sopenharmony_ci		goto error_rfkill;
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	return err;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_cierror_rfkill:
21478c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS))
21488c2ecf20Sopenharmony_ci		acer_backlight_exit();
21498c2ecf20Sopenharmony_cierror_brightness:
21508c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
21518c2ecf20Sopenharmony_ci		acer_led_exit();
21528c2ecf20Sopenharmony_cierror_mailled:
21538c2ecf20Sopenharmony_ci	return err;
21548c2ecf20Sopenharmony_ci}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_cistatic int acer_platform_remove(struct platform_device *device)
21578c2ecf20Sopenharmony_ci{
21588c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
21598c2ecf20Sopenharmony_ci		acer_led_exit();
21608c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS))
21618c2ecf20Sopenharmony_ci		acer_backlight_exit();
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	acer_rfkill_exit();
21648c2ecf20Sopenharmony_ci	return 0;
21658c2ecf20Sopenharmony_ci}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
21688c2ecf20Sopenharmony_cistatic int acer_suspend(struct device *dev)
21698c2ecf20Sopenharmony_ci{
21708c2ecf20Sopenharmony_ci	u32 value;
21718c2ecf20Sopenharmony_ci	struct acer_data *data = &interface->data;
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	if (!data)
21748c2ecf20Sopenharmony_ci		return -ENOMEM;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED)) {
21778c2ecf20Sopenharmony_ci		get_u32(&value, ACER_CAP_MAILLED);
21788c2ecf20Sopenharmony_ci		set_u32(LED_OFF, ACER_CAP_MAILLED);
21798c2ecf20Sopenharmony_ci		data->mailled = value;
21808c2ecf20Sopenharmony_ci	}
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS)) {
21838c2ecf20Sopenharmony_ci		get_u32(&value, ACER_CAP_BRIGHTNESS);
21848c2ecf20Sopenharmony_ci		data->brightness = value;
21858c2ecf20Sopenharmony_ci	}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	return 0;
21888c2ecf20Sopenharmony_ci}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_cistatic int acer_resume(struct device *dev)
21918c2ecf20Sopenharmony_ci{
21928c2ecf20Sopenharmony_ci	struct acer_data *data = &interface->data;
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	if (!data)
21958c2ecf20Sopenharmony_ci		return -ENOMEM;
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
21988c2ecf20Sopenharmony_ci		set_u32(data->mailled, ACER_CAP_MAILLED);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS))
22018c2ecf20Sopenharmony_ci		set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	if (acer_wmi_accel_dev)
22048c2ecf20Sopenharmony_ci		acer_gsensor_init();
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	return 0;
22078c2ecf20Sopenharmony_ci}
22088c2ecf20Sopenharmony_ci#else
22098c2ecf20Sopenharmony_ci#define acer_suspend	NULL
22108c2ecf20Sopenharmony_ci#define acer_resume	NULL
22118c2ecf20Sopenharmony_ci#endif
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_cistatic void acer_platform_shutdown(struct platform_device *device)
22168c2ecf20Sopenharmony_ci{
22178c2ecf20Sopenharmony_ci	struct acer_data *data = &interface->data;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	if (!data)
22208c2ecf20Sopenharmony_ci		return;
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
22238c2ecf20Sopenharmony_ci		set_u32(LED_OFF, ACER_CAP_MAILLED);
22248c2ecf20Sopenharmony_ci}
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_cistatic struct platform_driver acer_platform_driver = {
22278c2ecf20Sopenharmony_ci	.driver = {
22288c2ecf20Sopenharmony_ci		.name = "acer-wmi",
22298c2ecf20Sopenharmony_ci		.pm = &acer_pm,
22308c2ecf20Sopenharmony_ci	},
22318c2ecf20Sopenharmony_ci	.probe = acer_platform_probe,
22328c2ecf20Sopenharmony_ci	.remove = acer_platform_remove,
22338c2ecf20Sopenharmony_ci	.shutdown = acer_platform_shutdown,
22348c2ecf20Sopenharmony_ci};
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_cistatic struct platform_device *acer_platform_device;
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_cistatic void remove_debugfs(void)
22398c2ecf20Sopenharmony_ci{
22408c2ecf20Sopenharmony_ci	debugfs_remove_recursive(interface->debug.root);
22418c2ecf20Sopenharmony_ci}
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_cistatic void __init create_debugfs(void)
22448c2ecf20Sopenharmony_ci{
22458c2ecf20Sopenharmony_ci	interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	debugfs_create_u32("devices", S_IRUGO, interface->debug.root,
22488c2ecf20Sopenharmony_ci			   &interface->debug.wmid_devices);
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_cistatic int __init acer_wmi_init(void)
22528c2ecf20Sopenharmony_ci{
22538c2ecf20Sopenharmony_ci	int err;
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	pr_info("Acer Laptop ACPI-WMI Extras\n");
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	if (dmi_check_system(acer_blacklist)) {
22588c2ecf20Sopenharmony_ci		pr_info("Blacklisted hardware detected - not loading\n");
22598c2ecf20Sopenharmony_ci		return -ENODEV;
22608c2ecf20Sopenharmony_ci	}
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci	find_quirks();
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	/*
22658c2ecf20Sopenharmony_ci	 * The AMW0_GUID1 wmi is not only found on Acer family but also other
22668c2ecf20Sopenharmony_ci	 * machines like Lenovo, Fujitsu and Medion. In the past days,
22678c2ecf20Sopenharmony_ci	 * acer-wmi driver handled those non-Acer machines by quirks list.
22688c2ecf20Sopenharmony_ci	 * But actually acer-wmi driver was loaded on any machines that have
22698c2ecf20Sopenharmony_ci	 * AMW0_GUID1. This behavior is strange because those machines should
22708c2ecf20Sopenharmony_ci	 * be supported by appropriate wmi drivers. e.g. fujitsu-laptop,
22718c2ecf20Sopenharmony_ci	 * ideapad-laptop. So, here checks the machine that has AMW0_GUID1
22728c2ecf20Sopenharmony_ci	 * should be in Acer/Gateway/Packard Bell white list, or it's already
22738c2ecf20Sopenharmony_ci	 * in the past quirk list.
22748c2ecf20Sopenharmony_ci	 */
22758c2ecf20Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1) &&
22768c2ecf20Sopenharmony_ci	    !dmi_check_system(amw0_whitelist) &&
22778c2ecf20Sopenharmony_ci	    quirks == &quirk_unknown) {
22788c2ecf20Sopenharmony_ci		pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n");
22798c2ecf20Sopenharmony_ci		return -ENODEV;
22808c2ecf20Sopenharmony_ci	}
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	/*
22838c2ecf20Sopenharmony_ci	 * Detect which ACPI-WMI interface we're using.
22848c2ecf20Sopenharmony_ci	 */
22858c2ecf20Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
22868c2ecf20Sopenharmony_ci		interface = &AMW0_V2_interface;
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
22898c2ecf20Sopenharmony_ci		interface = &wmid_interface;
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci	if (wmi_has_guid(WMID_GUID3))
22928c2ecf20Sopenharmony_ci		interface = &wmid_v2_interface;
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	if (interface)
22958c2ecf20Sopenharmony_ci		dmi_walk(type_aa_dmi_decode, NULL);
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	if (wmi_has_guid(WMID_GUID2) && interface) {
22988c2ecf20Sopenharmony_ci		if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
22998c2ecf20Sopenharmony_ci			pr_err("Unable to detect available WMID devices\n");
23008c2ecf20Sopenharmony_ci			return -ENODEV;
23018c2ecf20Sopenharmony_ci		}
23028c2ecf20Sopenharmony_ci		/* WMID always provides brightness methods */
23038c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_BRIGHTNESS;
23048c2ecf20Sopenharmony_ci	} else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa && force_caps == -1) {
23058c2ecf20Sopenharmony_ci		pr_err("No WMID device detection method found\n");
23068c2ecf20Sopenharmony_ci		return -ENODEV;
23078c2ecf20Sopenharmony_ci	}
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
23108c2ecf20Sopenharmony_ci		interface = &AMW0_interface;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(AMW0_set_capabilities())) {
23138c2ecf20Sopenharmony_ci			pr_err("Unable to detect available AMW0 devices\n");
23148c2ecf20Sopenharmony_ci			return -ENODEV;
23158c2ecf20Sopenharmony_ci		}
23168c2ecf20Sopenharmony_ci	}
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1))
23198c2ecf20Sopenharmony_ci		AMW0_find_mailled();
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	if (!interface) {
23228c2ecf20Sopenharmony_ci		pr_err("No or unsupported WMI interface, unable to load\n");
23238c2ecf20Sopenharmony_ci		return -ENODEV;
23248c2ecf20Sopenharmony_ci	}
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	set_quirks();
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	if (dmi_check_system(video_vendor_dmi_table))
23298c2ecf20Sopenharmony_ci		acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
23328c2ecf20Sopenharmony_ci		interface->capability &= ~ACER_CAP_BRIGHTNESS;
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci	if (wmi_has_guid(WMID_GUID3))
23358c2ecf20Sopenharmony_ci		interface->capability |= ACER_CAP_SET_FUNCTION_MODE;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	if (force_caps != -1)
23388c2ecf20Sopenharmony_ci		interface->capability = force_caps;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	if (wmi_has_guid(WMID_GUID3) &&
23418c2ecf20Sopenharmony_ci	    (interface->capability & ACER_CAP_SET_FUNCTION_MODE)) {
23428c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
23438c2ecf20Sopenharmony_ci			pr_warn("Cannot enable RF Button Driver\n");
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci		if (ec_raw_mode) {
23468c2ecf20Sopenharmony_ci			if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
23478c2ecf20Sopenharmony_ci				pr_err("Cannot enable EC raw mode\n");
23488c2ecf20Sopenharmony_ci				return -ENODEV;
23498c2ecf20Sopenharmony_ci			}
23508c2ecf20Sopenharmony_ci		} else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
23518c2ecf20Sopenharmony_ci			pr_err("Cannot enable Launch Manager mode\n");
23528c2ecf20Sopenharmony_ci			return -ENODEV;
23538c2ecf20Sopenharmony_ci		}
23548c2ecf20Sopenharmony_ci	} else if (ec_raw_mode) {
23558c2ecf20Sopenharmony_ci		pr_info("No WMID EC raw mode enable method\n");
23568c2ecf20Sopenharmony_ci	}
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
23598c2ecf20Sopenharmony_ci		err = acer_wmi_input_setup();
23608c2ecf20Sopenharmony_ci		if (err)
23618c2ecf20Sopenharmony_ci			return err;
23628c2ecf20Sopenharmony_ci		err = acer_wmi_accel_setup();
23638c2ecf20Sopenharmony_ci		if (err && err != -ENODEV)
23648c2ecf20Sopenharmony_ci			pr_warn("Cannot enable accelerometer\n");
23658c2ecf20Sopenharmony_ci	}
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	err = platform_driver_register(&acer_platform_driver);
23688c2ecf20Sopenharmony_ci	if (err) {
23698c2ecf20Sopenharmony_ci		pr_err("Unable to register platform driver\n");
23708c2ecf20Sopenharmony_ci		goto error_platform_register;
23718c2ecf20Sopenharmony_ci	}
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	acer_platform_device = platform_device_alloc("acer-wmi", -1);
23748c2ecf20Sopenharmony_ci	if (!acer_platform_device) {
23758c2ecf20Sopenharmony_ci		err = -ENOMEM;
23768c2ecf20Sopenharmony_ci		goto error_device_alloc;
23778c2ecf20Sopenharmony_ci	}
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	err = platform_device_add(acer_platform_device);
23808c2ecf20Sopenharmony_ci	if (err)
23818c2ecf20Sopenharmony_ci		goto error_device_add;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	if (wmi_has_guid(WMID_GUID2)) {
23848c2ecf20Sopenharmony_ci		interface->debug.wmid_devices = get_wmid_devices();
23858c2ecf20Sopenharmony_ci		create_debugfs();
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	/* Override any initial settings with values from the commandline */
23898c2ecf20Sopenharmony_ci	acer_commandline_init();
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	return 0;
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_cierror_device_add:
23948c2ecf20Sopenharmony_ci	platform_device_put(acer_platform_device);
23958c2ecf20Sopenharmony_cierror_device_alloc:
23968c2ecf20Sopenharmony_ci	platform_driver_unregister(&acer_platform_driver);
23978c2ecf20Sopenharmony_cierror_platform_register:
23988c2ecf20Sopenharmony_ci	if (wmi_has_guid(ACERWMID_EVENT_GUID))
23998c2ecf20Sopenharmony_ci		acer_wmi_input_destroy();
24008c2ecf20Sopenharmony_ci	if (acer_wmi_accel_dev)
24018c2ecf20Sopenharmony_ci		input_unregister_device(acer_wmi_accel_dev);
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	return err;
24048c2ecf20Sopenharmony_ci}
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_cistatic void __exit acer_wmi_exit(void)
24078c2ecf20Sopenharmony_ci{
24088c2ecf20Sopenharmony_ci	if (wmi_has_guid(ACERWMID_EVENT_GUID))
24098c2ecf20Sopenharmony_ci		acer_wmi_input_destroy();
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	if (acer_wmi_accel_dev)
24128c2ecf20Sopenharmony_ci		input_unregister_device(acer_wmi_accel_dev);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	remove_debugfs();
24158c2ecf20Sopenharmony_ci	platform_device_unregister(acer_platform_device);
24168c2ecf20Sopenharmony_ci	platform_driver_unregister(&acer_platform_driver);
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	pr_info("Acer Laptop WMI Extras unloaded\n");
24198c2ecf20Sopenharmony_ci	return;
24208c2ecf20Sopenharmony_ci}
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_cimodule_init(acer_wmi_init);
24238c2ecf20Sopenharmony_cimodule_exit(acer_wmi_exit);
2424