162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Acer WMI Laptop Extras
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2007-2009	Carlos Corbacho <carlos@strangeworlds.co.uk>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Based on acer_acpi:
862306a36Sopenharmony_ci *    Copyright (C) 2005-2007	E.M. Smith
962306a36Sopenharmony_ci *    Copyright (C) 2007-2008	Carlos Corbacho <cathectic@gmail.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/types.h>
1862306a36Sopenharmony_ci#include <linux/dmi.h>
1962306a36Sopenharmony_ci#include <linux/fb.h>
2062306a36Sopenharmony_ci#include <linux/backlight.h>
2162306a36Sopenharmony_ci#include <linux/leds.h>
2262306a36Sopenharmony_ci#include <linux/platform_device.h>
2362306a36Sopenharmony_ci#include <linux/acpi.h>
2462306a36Sopenharmony_ci#include <linux/i8042.h>
2562306a36Sopenharmony_ci#include <linux/rfkill.h>
2662306a36Sopenharmony_ci#include <linux/workqueue.h>
2762306a36Sopenharmony_ci#include <linux/debugfs.h>
2862306a36Sopenharmony_ci#include <linux/slab.h>
2962306a36Sopenharmony_ci#include <linux/input.h>
3062306a36Sopenharmony_ci#include <linux/input/sparse-keymap.h>
3162306a36Sopenharmony_ci#include <acpi/video.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciMODULE_AUTHOR("Carlos Corbacho");
3462306a36Sopenharmony_ciMODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
3562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * Magic Number
3962306a36Sopenharmony_ci * Meaning is unknown - this number is required for writing to ACPI for AMW0
4062306a36Sopenharmony_ci * (it's also used in acerhk when directly accessing the BIOS)
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_ci#define ACER_AMW0_WRITE	0x9610
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * Bit masks for the AMW0 interface
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci#define ACER_AMW0_WIRELESS_MASK  0x35
4862306a36Sopenharmony_ci#define ACER_AMW0_BLUETOOTH_MASK 0x34
4962306a36Sopenharmony_ci#define ACER_AMW0_MAILLED_MASK   0x31
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * Method IDs for WMID interface
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_ci#define ACER_WMID_GET_WIRELESS_METHODID		1
5562306a36Sopenharmony_ci#define ACER_WMID_GET_BLUETOOTH_METHODID	2
5662306a36Sopenharmony_ci#define ACER_WMID_GET_BRIGHTNESS_METHODID	3
5762306a36Sopenharmony_ci#define ACER_WMID_SET_WIRELESS_METHODID		4
5862306a36Sopenharmony_ci#define ACER_WMID_SET_BLUETOOTH_METHODID	5
5962306a36Sopenharmony_ci#define ACER_WMID_SET_BRIGHTNESS_METHODID	6
6062306a36Sopenharmony_ci#define ACER_WMID_GET_THREEG_METHODID		10
6162306a36Sopenharmony_ci#define ACER_WMID_SET_THREEG_METHODID		11
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define ACER_WMID_SET_GAMING_LED_METHODID 2
6462306a36Sopenharmony_ci#define ACER_WMID_GET_GAMING_LED_METHODID 4
6562306a36Sopenharmony_ci#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14
6662306a36Sopenharmony_ci#define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * Acer ACPI method GUIDs
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ci#define AMW0_GUID1		"67C3371D-95A3-4C37-BB61-DD47B491DAAB"
7262306a36Sopenharmony_ci#define AMW0_GUID2		"431F16ED-0C2B-444C-B267-27DEB140CF9C"
7362306a36Sopenharmony_ci#define WMID_GUID1		"6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
7462306a36Sopenharmony_ci#define WMID_GUID2		"95764E09-FB56-4E83-B31A-37761F60994A"
7562306a36Sopenharmony_ci#define WMID_GUID3		"61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
7662306a36Sopenharmony_ci#define WMID_GUID4		"7A4DDFE7-5B5D-40B4-8595-4408E0CC7F56"
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/*
7962306a36Sopenharmony_ci * Acer ACPI event GUIDs
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_ci#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciMODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
8462306a36Sopenharmony_ciMODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
8562306a36Sopenharmony_ciMODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cienum acer_wmi_event_ids {
8862306a36Sopenharmony_ci	WMID_HOTKEY_EVENT = 0x1,
8962306a36Sopenharmony_ci	WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5,
9062306a36Sopenharmony_ci	WMID_GAMING_TURBO_KEY_EVENT = 0x7,
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic const struct key_entry acer_wmi_keymap[] __initconst = {
9462306a36Sopenharmony_ci	{KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
9562306a36Sopenharmony_ci	{KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
9662306a36Sopenharmony_ci	{KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */
9762306a36Sopenharmony_ci	{KE_KEY, 0x12, {KEY_BLUETOOTH} },	/* BT */
9862306a36Sopenharmony_ci	{KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
9962306a36Sopenharmony_ci	{KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
10062306a36Sopenharmony_ci	{KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
10162306a36Sopenharmony_ci	{KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
10262306a36Sopenharmony_ci	{KE_KEY, 0x27, {KEY_HELP} },
10362306a36Sopenharmony_ci	{KE_KEY, 0x29, {KEY_PROG3} },    /* P_Key for TM8372 */
10462306a36Sopenharmony_ci	{KE_IGNORE, 0x41, {KEY_MUTE} },
10562306a36Sopenharmony_ci	{KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
10662306a36Sopenharmony_ci	{KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
10762306a36Sopenharmony_ci	{KE_IGNORE, 0x43, {KEY_NEXTSONG} },
10862306a36Sopenharmony_ci	{KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
10962306a36Sopenharmony_ci	{KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
11062306a36Sopenharmony_ci	{KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
11162306a36Sopenharmony_ci	{KE_IGNORE, 0x45, {KEY_STOP} },
11262306a36Sopenharmony_ci	{KE_IGNORE, 0x50, {KEY_STOP} },
11362306a36Sopenharmony_ci	{KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
11462306a36Sopenharmony_ci	{KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
11562306a36Sopenharmony_ci	{KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
11662306a36Sopenharmony_ci	/*
11762306a36Sopenharmony_ci	 * 0x61 is KEY_SWITCHVIDEOMODE. Usually this is a duplicate input event
11862306a36Sopenharmony_ci	 * with the "Video Bus" input device events. But sometimes it is not
11962306a36Sopenharmony_ci	 * a dup. Map it to KEY_UNKNOWN instead of using KE_IGNORE so that
12062306a36Sopenharmony_ci	 * udev/hwdb can override it on systems where it is not a dup.
12162306a36Sopenharmony_ci	 */
12262306a36Sopenharmony_ci	{KE_KEY, 0x61, {KEY_UNKNOWN} },
12362306a36Sopenharmony_ci	{KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
12462306a36Sopenharmony_ci	{KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
12562306a36Sopenharmony_ci	{KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} },	/* Display Switch */
12662306a36Sopenharmony_ci	{KE_IGNORE, 0x81, {KEY_SLEEP} },
12762306a36Sopenharmony_ci	{KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} },	/* Touch Pad Toggle */
12862306a36Sopenharmony_ci	{KE_IGNORE, 0x84, {KEY_KBDILLUMTOGGLE} }, /* Automatic Keyboard background light toggle */
12962306a36Sopenharmony_ci	{KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
13062306a36Sopenharmony_ci	{KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
13162306a36Sopenharmony_ci	{KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
13262306a36Sopenharmony_ci	{KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
13362306a36Sopenharmony_ci	{KE_KEY, 0x86, {KEY_WLAN} },
13462306a36Sopenharmony_ci	{KE_KEY, 0x87, {KEY_POWER} },
13562306a36Sopenharmony_ci	{KE_END, 0}
13662306a36Sopenharmony_ci};
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic struct input_dev *acer_wmi_input_dev;
13962306a36Sopenharmony_cistatic struct input_dev *acer_wmi_accel_dev;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistruct event_return_value {
14262306a36Sopenharmony_ci	u8 function;
14362306a36Sopenharmony_ci	u8 key_num;
14462306a36Sopenharmony_ci	u16 device_state;
14562306a36Sopenharmony_ci	u16 reserved1;
14662306a36Sopenharmony_ci	u8 kbd_dock_state;
14762306a36Sopenharmony_ci	u8 reserved2;
14862306a36Sopenharmony_ci} __packed;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * GUID3 Get Device Status device flags
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_ci#define ACER_WMID3_GDS_WIRELESS		(1<<0)	/* WiFi */
15462306a36Sopenharmony_ci#define ACER_WMID3_GDS_THREEG		(1<<6)	/* 3G */
15562306a36Sopenharmony_ci#define ACER_WMID3_GDS_WIMAX		(1<<7)	/* WiMAX */
15662306a36Sopenharmony_ci#define ACER_WMID3_GDS_BLUETOOTH	(1<<11)	/* BT */
15762306a36Sopenharmony_ci#define ACER_WMID3_GDS_RFBTN		(1<<14)	/* RF Button */
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci#define ACER_WMID3_GDS_TOUCHPAD		(1<<1)	/* Touchpad */
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/* Hotkey Customized Setting and Acer Application Status.
16262306a36Sopenharmony_ci * Set Device Default Value and Report Acer Application Status.
16362306a36Sopenharmony_ci * When Acer Application starts, it will run this method to inform
16462306a36Sopenharmony_ci * BIOS/EC that Acer Application is on.
16562306a36Sopenharmony_ci * App Status
16662306a36Sopenharmony_ci *	Bit[0]: Launch Manager Status
16762306a36Sopenharmony_ci *	Bit[1]: ePM Status
16862306a36Sopenharmony_ci *	Bit[2]: Device Control Status
16962306a36Sopenharmony_ci *	Bit[3]: Acer Power Button Utility Status
17062306a36Sopenharmony_ci *	Bit[4]: RF Button Status
17162306a36Sopenharmony_ci *	Bit[5]: ODD PM Status
17262306a36Sopenharmony_ci *	Bit[6]: Device Default Value Control
17362306a36Sopenharmony_ci *	Bit[7]: Hall Sensor Application Status
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_cistruct func_input_params {
17662306a36Sopenharmony_ci	u8 function_num;        /* Function Number */
17762306a36Sopenharmony_ci	u16 commun_devices;     /* Communication type devices default status */
17862306a36Sopenharmony_ci	u16 devices;            /* Other type devices default status */
17962306a36Sopenharmony_ci	u8 app_status;          /* Acer Device Status. LM, ePM, RF Button... */
18062306a36Sopenharmony_ci	u8 app_mask;		/* Bit mask to app_status */
18162306a36Sopenharmony_ci	u8 reserved;
18262306a36Sopenharmony_ci} __packed;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct func_return_value {
18562306a36Sopenharmony_ci	u8 error_code;          /* Error Code */
18662306a36Sopenharmony_ci	u8 ec_return_value;     /* EC Return Value */
18762306a36Sopenharmony_ci	u16 reserved;
18862306a36Sopenharmony_ci} __packed;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistruct wmid3_gds_set_input_param {     /* Set Device Status input parameter */
19162306a36Sopenharmony_ci	u8 function_num;        /* Function Number */
19262306a36Sopenharmony_ci	u8 hotkey_number;       /* Hotkey Number */
19362306a36Sopenharmony_ci	u16 devices;            /* Set Device */
19462306a36Sopenharmony_ci	u8 volume_value;        /* Volume Value */
19562306a36Sopenharmony_ci} __packed;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistruct wmid3_gds_get_input_param {     /* Get Device Status input parameter */
19862306a36Sopenharmony_ci	u8 function_num;	/* Function Number */
19962306a36Sopenharmony_ci	u8 hotkey_number;	/* Hotkey Number */
20062306a36Sopenharmony_ci	u16 devices;		/* Get Device */
20162306a36Sopenharmony_ci} __packed;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistruct wmid3_gds_return_value {	/* Get Device Status return value*/
20462306a36Sopenharmony_ci	u8 error_code;		/* Error Code */
20562306a36Sopenharmony_ci	u8 ec_return_value;	/* EC Return Value */
20662306a36Sopenharmony_ci	u16 devices;		/* Current Device Status */
20762306a36Sopenharmony_ci	u32 reserved;
20862306a36Sopenharmony_ci} __packed;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistruct hotkey_function_type_aa {
21162306a36Sopenharmony_ci	u8 type;
21262306a36Sopenharmony_ci	u8 length;
21362306a36Sopenharmony_ci	u16 handle;
21462306a36Sopenharmony_ci	u16 commun_func_bitmap;
21562306a36Sopenharmony_ci	u16 application_func_bitmap;
21662306a36Sopenharmony_ci	u16 media_func_bitmap;
21762306a36Sopenharmony_ci	u16 display_func_bitmap;
21862306a36Sopenharmony_ci	u16 others_func_bitmap;
21962306a36Sopenharmony_ci	u8 commun_fn_key_number;
22062306a36Sopenharmony_ci} __packed;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/*
22362306a36Sopenharmony_ci * Interface capability flags
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_ci#define ACER_CAP_MAILLED		BIT(0)
22662306a36Sopenharmony_ci#define ACER_CAP_WIRELESS		BIT(1)
22762306a36Sopenharmony_ci#define ACER_CAP_BLUETOOTH		BIT(2)
22862306a36Sopenharmony_ci#define ACER_CAP_BRIGHTNESS		BIT(3)
22962306a36Sopenharmony_ci#define ACER_CAP_THREEG			BIT(4)
23062306a36Sopenharmony_ci#define ACER_CAP_SET_FUNCTION_MODE	BIT(5)
23162306a36Sopenharmony_ci#define ACER_CAP_KBD_DOCK		BIT(6)
23262306a36Sopenharmony_ci#define ACER_CAP_TURBO_OC     BIT(7)
23362306a36Sopenharmony_ci#define ACER_CAP_TURBO_LED     BIT(8)
23462306a36Sopenharmony_ci#define ACER_CAP_TURBO_FAN     BIT(9)
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/*
23762306a36Sopenharmony_ci * Interface type flags
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cienum interface_flags {
24062306a36Sopenharmony_ci	ACER_AMW0,
24162306a36Sopenharmony_ci	ACER_AMW0_V2,
24262306a36Sopenharmony_ci	ACER_WMID,
24362306a36Sopenharmony_ci	ACER_WMID_v2,
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#define ACER_DEFAULT_WIRELESS  0
24762306a36Sopenharmony_ci#define ACER_DEFAULT_BLUETOOTH 0
24862306a36Sopenharmony_ci#define ACER_DEFAULT_MAILLED   0
24962306a36Sopenharmony_ci#define ACER_DEFAULT_THREEG    0
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int max_brightness = 0xF;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic int mailled = -1;
25462306a36Sopenharmony_cistatic int brightness = -1;
25562306a36Sopenharmony_cistatic int threeg = -1;
25662306a36Sopenharmony_cistatic int force_series;
25762306a36Sopenharmony_cistatic int force_caps = -1;
25862306a36Sopenharmony_cistatic bool ec_raw_mode;
25962306a36Sopenharmony_cistatic bool has_type_aa;
26062306a36Sopenharmony_cistatic u16 commun_func_bitmap;
26162306a36Sopenharmony_cistatic u8 commun_fn_key_number;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cimodule_param(mailled, int, 0444);
26462306a36Sopenharmony_cimodule_param(brightness, int, 0444);
26562306a36Sopenharmony_cimodule_param(threeg, int, 0444);
26662306a36Sopenharmony_cimodule_param(force_series, int, 0444);
26762306a36Sopenharmony_cimodule_param(force_caps, int, 0444);
26862306a36Sopenharmony_cimodule_param(ec_raw_mode, bool, 0444);
26962306a36Sopenharmony_ciMODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
27062306a36Sopenharmony_ciMODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
27162306a36Sopenharmony_ciMODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
27262306a36Sopenharmony_ciMODULE_PARM_DESC(force_series, "Force a different laptop series");
27362306a36Sopenharmony_ciMODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value");
27462306a36Sopenharmony_ciMODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistruct acer_data {
27762306a36Sopenharmony_ci	int mailled;
27862306a36Sopenharmony_ci	int threeg;
27962306a36Sopenharmony_ci	int brightness;
28062306a36Sopenharmony_ci};
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistruct acer_debug {
28362306a36Sopenharmony_ci	struct dentry *root;
28462306a36Sopenharmony_ci	u32 wmid_devices;
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic struct rfkill *wireless_rfkill;
28862306a36Sopenharmony_cistatic struct rfkill *bluetooth_rfkill;
28962306a36Sopenharmony_cistatic struct rfkill *threeg_rfkill;
29062306a36Sopenharmony_cistatic bool rfkill_inited;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/* Each low-level interface must define at least some of the following */
29362306a36Sopenharmony_cistruct wmi_interface {
29462306a36Sopenharmony_ci	/* The WMI device type */
29562306a36Sopenharmony_ci	u32 type;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* The capabilities this interface provides */
29862306a36Sopenharmony_ci	u32 capability;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Private data for the current interface */
30162306a36Sopenharmony_ci	struct acer_data data;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* debugfs entries associated with this interface */
30462306a36Sopenharmony_ci	struct acer_debug debug;
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci/* The static interface pointer, points to the currently detected interface */
30862306a36Sopenharmony_cistatic struct wmi_interface *interface;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci/*
31162306a36Sopenharmony_ci * Embedded Controller quirks
31262306a36Sopenharmony_ci * Some laptops require us to directly access the EC to either enable or query
31362306a36Sopenharmony_ci * features that are not available through WMI.
31462306a36Sopenharmony_ci */
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistruct quirk_entry {
31762306a36Sopenharmony_ci	u8 wireless;
31862306a36Sopenharmony_ci	u8 mailled;
31962306a36Sopenharmony_ci	s8 brightness;
32062306a36Sopenharmony_ci	u8 bluetooth;
32162306a36Sopenharmony_ci	u8 turbo;
32262306a36Sopenharmony_ci	u8 cpu_fans;
32362306a36Sopenharmony_ci	u8 gpu_fans;
32462306a36Sopenharmony_ci};
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic struct quirk_entry *quirks;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic void __init set_quirks(void)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	if (quirks->mailled)
33162306a36Sopenharmony_ci		interface->capability |= ACER_CAP_MAILLED;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (quirks->brightness)
33462306a36Sopenharmony_ci		interface->capability |= ACER_CAP_BRIGHTNESS;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (quirks->turbo)
33762306a36Sopenharmony_ci		interface->capability |= ACER_CAP_TURBO_OC | ACER_CAP_TURBO_LED
33862306a36Sopenharmony_ci					 | ACER_CAP_TURBO_FAN;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int __init dmi_matched(const struct dmi_system_id *dmi)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	quirks = dmi->driver_data;
34462306a36Sopenharmony_ci	return 1;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int __init set_force_caps(const struct dmi_system_id *dmi)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	if (force_caps == -1) {
35062306a36Sopenharmony_ci		force_caps = (uintptr_t)dmi->driver_data;
35162306a36Sopenharmony_ci		pr_info("Found %s, set force_caps to 0x%x\n", dmi->ident, force_caps);
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	return 1;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic struct quirk_entry quirk_unknown = {
35762306a36Sopenharmony_ci};
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic struct quirk_entry quirk_acer_aspire_1520 = {
36062306a36Sopenharmony_ci	.brightness = -1,
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic struct quirk_entry quirk_acer_travelmate_2490 = {
36462306a36Sopenharmony_ci	.mailled = 1,
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic struct quirk_entry quirk_acer_predator_ph315_53 = {
36862306a36Sopenharmony_ci	.turbo = 1,
36962306a36Sopenharmony_ci	.cpu_fans = 1,
37062306a36Sopenharmony_ci	.gpu_fans = 1,
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/* This AMW0 laptop has no bluetooth */
37462306a36Sopenharmony_cistatic struct quirk_entry quirk_medion_md_98300 = {
37562306a36Sopenharmony_ci	.wireless = 1,
37662306a36Sopenharmony_ci};
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
37962306a36Sopenharmony_ci	.wireless = 2,
38062306a36Sopenharmony_ci};
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic struct quirk_entry quirk_lenovo_ideapad_s205 = {
38362306a36Sopenharmony_ci	.wireless = 3,
38462306a36Sopenharmony_ci};
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/* The Aspire One has a dummy ACPI-WMI interface - disable it */
38762306a36Sopenharmony_cistatic const struct dmi_system_id acer_blacklist[] __initconst = {
38862306a36Sopenharmony_ci	{
38962306a36Sopenharmony_ci		.ident = "Acer Aspire One (SSD)",
39062306a36Sopenharmony_ci		.matches = {
39162306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
39262306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
39362306a36Sopenharmony_ci		},
39462306a36Sopenharmony_ci	},
39562306a36Sopenharmony_ci	{
39662306a36Sopenharmony_ci		.ident = "Acer Aspire One (HDD)",
39762306a36Sopenharmony_ci		.matches = {
39862306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
39962306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
40062306a36Sopenharmony_ci		},
40162306a36Sopenharmony_ci	},
40262306a36Sopenharmony_ci	{}
40362306a36Sopenharmony_ci};
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic const struct dmi_system_id amw0_whitelist[] __initconst = {
40662306a36Sopenharmony_ci	{
40762306a36Sopenharmony_ci		.ident = "Acer",
40862306a36Sopenharmony_ci		.matches = {
40962306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
41062306a36Sopenharmony_ci		},
41162306a36Sopenharmony_ci	},
41262306a36Sopenharmony_ci	{
41362306a36Sopenharmony_ci		.ident = "Gateway",
41462306a36Sopenharmony_ci		.matches = {
41562306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Gateway"),
41662306a36Sopenharmony_ci		},
41762306a36Sopenharmony_ci	},
41862306a36Sopenharmony_ci	{
41962306a36Sopenharmony_ci		.ident = "Packard Bell",
42062306a36Sopenharmony_ci		.matches = {
42162306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
42262306a36Sopenharmony_ci		},
42362306a36Sopenharmony_ci	},
42462306a36Sopenharmony_ci	{}
42562306a36Sopenharmony_ci};
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * This quirk table is only for Acer/Gateway/Packard Bell family
42962306a36Sopenharmony_ci * that those machines are supported by acer-wmi driver.
43062306a36Sopenharmony_ci */
43162306a36Sopenharmony_cistatic const struct dmi_system_id acer_quirks[] __initconst = {
43262306a36Sopenharmony_ci	{
43362306a36Sopenharmony_ci		.callback = dmi_matched,
43462306a36Sopenharmony_ci		.ident = "Acer Aspire 1360",
43562306a36Sopenharmony_ci		.matches = {
43662306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
43762306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
43862306a36Sopenharmony_ci		},
43962306a36Sopenharmony_ci		.driver_data = &quirk_acer_aspire_1520,
44062306a36Sopenharmony_ci	},
44162306a36Sopenharmony_ci	{
44262306a36Sopenharmony_ci		.callback = dmi_matched,
44362306a36Sopenharmony_ci		.ident = "Acer Aspire 1520",
44462306a36Sopenharmony_ci		.matches = {
44562306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
44662306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
44762306a36Sopenharmony_ci		},
44862306a36Sopenharmony_ci		.driver_data = &quirk_acer_aspire_1520,
44962306a36Sopenharmony_ci	},
45062306a36Sopenharmony_ci	{
45162306a36Sopenharmony_ci		.callback = dmi_matched,
45262306a36Sopenharmony_ci		.ident = "Acer Aspire 3100",
45362306a36Sopenharmony_ci		.matches = {
45462306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
45562306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
45662306a36Sopenharmony_ci		},
45762306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
45862306a36Sopenharmony_ci	},
45962306a36Sopenharmony_ci	{
46062306a36Sopenharmony_ci		.callback = dmi_matched,
46162306a36Sopenharmony_ci		.ident = "Acer Aspire 3610",
46262306a36Sopenharmony_ci		.matches = {
46362306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
46462306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
46562306a36Sopenharmony_ci		},
46662306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
46762306a36Sopenharmony_ci	},
46862306a36Sopenharmony_ci	{
46962306a36Sopenharmony_ci		.callback = dmi_matched,
47062306a36Sopenharmony_ci		.ident = "Acer Aspire 5100",
47162306a36Sopenharmony_ci		.matches = {
47262306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
47362306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
47462306a36Sopenharmony_ci		},
47562306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
47662306a36Sopenharmony_ci	},
47762306a36Sopenharmony_ci	{
47862306a36Sopenharmony_ci		.callback = dmi_matched,
47962306a36Sopenharmony_ci		.ident = "Acer Aspire 5610",
48062306a36Sopenharmony_ci		.matches = {
48162306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
48262306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
48362306a36Sopenharmony_ci		},
48462306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
48562306a36Sopenharmony_ci	},
48662306a36Sopenharmony_ci	{
48762306a36Sopenharmony_ci		.callback = dmi_matched,
48862306a36Sopenharmony_ci		.ident = "Acer Aspire 5630",
48962306a36Sopenharmony_ci		.matches = {
49062306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
49162306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
49262306a36Sopenharmony_ci		},
49362306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
49462306a36Sopenharmony_ci	},
49562306a36Sopenharmony_ci	{
49662306a36Sopenharmony_ci		.callback = dmi_matched,
49762306a36Sopenharmony_ci		.ident = "Acer Aspire 5650",
49862306a36Sopenharmony_ci		.matches = {
49962306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
50062306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
50162306a36Sopenharmony_ci		},
50262306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
50362306a36Sopenharmony_ci	},
50462306a36Sopenharmony_ci	{
50562306a36Sopenharmony_ci		.callback = dmi_matched,
50662306a36Sopenharmony_ci		.ident = "Acer Aspire 5680",
50762306a36Sopenharmony_ci		.matches = {
50862306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
50962306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
51062306a36Sopenharmony_ci		},
51162306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
51262306a36Sopenharmony_ci	},
51362306a36Sopenharmony_ci	{
51462306a36Sopenharmony_ci		.callback = dmi_matched,
51562306a36Sopenharmony_ci		.ident = "Acer Aspire 9110",
51662306a36Sopenharmony_ci		.matches = {
51762306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
51862306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
51962306a36Sopenharmony_ci		},
52062306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
52162306a36Sopenharmony_ci	},
52262306a36Sopenharmony_ci	{
52362306a36Sopenharmony_ci		.callback = dmi_matched,
52462306a36Sopenharmony_ci		.ident = "Acer TravelMate 2490",
52562306a36Sopenharmony_ci		.matches = {
52662306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
52762306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
52862306a36Sopenharmony_ci		},
52962306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
53062306a36Sopenharmony_ci	},
53162306a36Sopenharmony_ci	{
53262306a36Sopenharmony_ci		.callback = dmi_matched,
53362306a36Sopenharmony_ci		.ident = "Acer TravelMate 4200",
53462306a36Sopenharmony_ci		.matches = {
53562306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
53662306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
53762306a36Sopenharmony_ci		},
53862306a36Sopenharmony_ci		.driver_data = &quirk_acer_travelmate_2490,
53962306a36Sopenharmony_ci	},
54062306a36Sopenharmony_ci	{
54162306a36Sopenharmony_ci		.callback = dmi_matched,
54262306a36Sopenharmony_ci		.ident = "Acer Predator PH315-53",
54362306a36Sopenharmony_ci		.matches = {
54462306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
54562306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH315-53"),
54662306a36Sopenharmony_ci		},
54762306a36Sopenharmony_ci		.driver_data = &quirk_acer_predator_ph315_53,
54862306a36Sopenharmony_ci	},
54962306a36Sopenharmony_ci	{
55062306a36Sopenharmony_ci		.callback = set_force_caps,
55162306a36Sopenharmony_ci		.ident = "Acer Aspire Switch 10E SW3-016",
55262306a36Sopenharmony_ci		.matches = {
55362306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
55462306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-016"),
55562306a36Sopenharmony_ci		},
55662306a36Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
55762306a36Sopenharmony_ci	},
55862306a36Sopenharmony_ci	{
55962306a36Sopenharmony_ci		.callback = set_force_caps,
56062306a36Sopenharmony_ci		.ident = "Acer Aspire Switch 10 SW5-012",
56162306a36Sopenharmony_ci		.matches = {
56262306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
56362306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
56462306a36Sopenharmony_ci		},
56562306a36Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
56662306a36Sopenharmony_ci	},
56762306a36Sopenharmony_ci	{
56862306a36Sopenharmony_ci		.callback = set_force_caps,
56962306a36Sopenharmony_ci		.ident = "Acer Aspire Switch V 10 SW5-017",
57062306a36Sopenharmony_ci		.matches = {
57162306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
57262306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
57362306a36Sopenharmony_ci		},
57462306a36Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
57562306a36Sopenharmony_ci	},
57662306a36Sopenharmony_ci	{
57762306a36Sopenharmony_ci		.callback = set_force_caps,
57862306a36Sopenharmony_ci		.ident = "Acer One 10 (S1003)",
57962306a36Sopenharmony_ci		.matches = {
58062306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
58162306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
58262306a36Sopenharmony_ci		},
58362306a36Sopenharmony_ci		.driver_data = (void *)ACER_CAP_KBD_DOCK,
58462306a36Sopenharmony_ci	},
58562306a36Sopenharmony_ci	{}
58662306a36Sopenharmony_ci};
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci/*
58962306a36Sopenharmony_ci * This quirk list is for those non-acer machines that have AMW0_GUID1
59062306a36Sopenharmony_ci * but supported by acer-wmi in past days. Keeping this quirk list here
59162306a36Sopenharmony_ci * is only for backward compatible. Please do not add new machine to
59262306a36Sopenharmony_ci * here anymore. Those non-acer machines should be supported by
59362306a36Sopenharmony_ci * appropriate wmi drivers.
59462306a36Sopenharmony_ci */
59562306a36Sopenharmony_cistatic const struct dmi_system_id non_acer_quirks[] __initconst = {
59662306a36Sopenharmony_ci	{
59762306a36Sopenharmony_ci		.callback = dmi_matched,
59862306a36Sopenharmony_ci		.ident = "Fujitsu Siemens Amilo Li 1718",
59962306a36Sopenharmony_ci		.matches = {
60062306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
60162306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
60262306a36Sopenharmony_ci		},
60362306a36Sopenharmony_ci		.driver_data = &quirk_fujitsu_amilo_li_1718,
60462306a36Sopenharmony_ci	},
60562306a36Sopenharmony_ci	{
60662306a36Sopenharmony_ci		.callback = dmi_matched,
60762306a36Sopenharmony_ci		.ident = "Medion MD 98300",
60862306a36Sopenharmony_ci		.matches = {
60962306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
61062306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
61162306a36Sopenharmony_ci		},
61262306a36Sopenharmony_ci		.driver_data = &quirk_medion_md_98300,
61362306a36Sopenharmony_ci	},
61462306a36Sopenharmony_ci	{
61562306a36Sopenharmony_ci		.callback = dmi_matched,
61662306a36Sopenharmony_ci		.ident = "Lenovo Ideapad S205",
61762306a36Sopenharmony_ci		.matches = {
61862306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
61962306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
62062306a36Sopenharmony_ci		},
62162306a36Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
62262306a36Sopenharmony_ci	},
62362306a36Sopenharmony_ci	{
62462306a36Sopenharmony_ci		.callback = dmi_matched,
62562306a36Sopenharmony_ci		.ident = "Lenovo Ideapad S205 (Brazos)",
62662306a36Sopenharmony_ci		.matches = {
62762306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
62862306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
62962306a36Sopenharmony_ci		},
63062306a36Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
63162306a36Sopenharmony_ci	},
63262306a36Sopenharmony_ci	{
63362306a36Sopenharmony_ci		.callback = dmi_matched,
63462306a36Sopenharmony_ci		.ident = "Lenovo 3000 N200",
63562306a36Sopenharmony_ci		.matches = {
63662306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
63762306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
63862306a36Sopenharmony_ci		},
63962306a36Sopenharmony_ci		.driver_data = &quirk_fujitsu_amilo_li_1718,
64062306a36Sopenharmony_ci	},
64162306a36Sopenharmony_ci	{
64262306a36Sopenharmony_ci		.callback = dmi_matched,
64362306a36Sopenharmony_ci		.ident = "Lenovo Ideapad S205-10382JG",
64462306a36Sopenharmony_ci		.matches = {
64562306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
64662306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"),
64762306a36Sopenharmony_ci		},
64862306a36Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
64962306a36Sopenharmony_ci	},
65062306a36Sopenharmony_ci	{
65162306a36Sopenharmony_ci		.callback = dmi_matched,
65262306a36Sopenharmony_ci		.ident = "Lenovo Ideapad S205-1038DPG",
65362306a36Sopenharmony_ci		.matches = {
65462306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
65562306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"),
65662306a36Sopenharmony_ci		},
65762306a36Sopenharmony_ci		.driver_data = &quirk_lenovo_ideapad_s205,
65862306a36Sopenharmony_ci	},
65962306a36Sopenharmony_ci	{}
66062306a36Sopenharmony_ci};
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci/* Find which quirks are needed for a particular vendor/ model pair */
66362306a36Sopenharmony_cistatic void __init find_quirks(void)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	if (!force_series) {
66662306a36Sopenharmony_ci		dmi_check_system(acer_quirks);
66762306a36Sopenharmony_ci		dmi_check_system(non_acer_quirks);
66862306a36Sopenharmony_ci	} else if (force_series == 2490) {
66962306a36Sopenharmony_ci		quirks = &quirk_acer_travelmate_2490;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	if (quirks == NULL)
67362306a36Sopenharmony_ci		quirks = &quirk_unknown;
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci/*
67762306a36Sopenharmony_ci * General interface convenience methods
67862306a36Sopenharmony_ci */
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic bool has_cap(u32 cap)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	return interface->capability & cap;
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci/*
68662306a36Sopenharmony_ci * AMW0 (V1) interface
68762306a36Sopenharmony_ci */
68862306a36Sopenharmony_cistruct wmab_args {
68962306a36Sopenharmony_ci	u32 eax;
69062306a36Sopenharmony_ci	u32 ebx;
69162306a36Sopenharmony_ci	u32 ecx;
69262306a36Sopenharmony_ci	u32 edx;
69362306a36Sopenharmony_ci};
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistruct wmab_ret {
69662306a36Sopenharmony_ci	u32 eax;
69762306a36Sopenharmony_ci	u32 ebx;
69862306a36Sopenharmony_ci	u32 ecx;
69962306a36Sopenharmony_ci	u32 edx;
70062306a36Sopenharmony_ci	u32 eex;
70162306a36Sopenharmony_ci};
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic acpi_status wmab_execute(struct wmab_args *regbuf,
70462306a36Sopenharmony_cistruct acpi_buffer *result)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	struct acpi_buffer input;
70762306a36Sopenharmony_ci	acpi_status status;
70862306a36Sopenharmony_ci	input.length = sizeof(struct wmab_args);
70962306a36Sopenharmony_ci	input.pointer = (u8 *)regbuf;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	status = wmi_evaluate_method(AMW0_GUID1, 0, 1, &input, result);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	return status;
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic acpi_status AMW0_get_u32(u32 *value, u32 cap)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	int err;
71962306a36Sopenharmony_ci	u8 result;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	switch (cap) {
72262306a36Sopenharmony_ci	case ACER_CAP_MAILLED:
72362306a36Sopenharmony_ci		switch (quirks->mailled) {
72462306a36Sopenharmony_ci		default:
72562306a36Sopenharmony_ci			err = ec_read(0xA, &result);
72662306a36Sopenharmony_ci			if (err)
72762306a36Sopenharmony_ci				return AE_ERROR;
72862306a36Sopenharmony_ci			*value = (result >> 7) & 0x1;
72962306a36Sopenharmony_ci			return AE_OK;
73062306a36Sopenharmony_ci		}
73162306a36Sopenharmony_ci		break;
73262306a36Sopenharmony_ci	case ACER_CAP_WIRELESS:
73362306a36Sopenharmony_ci		switch (quirks->wireless) {
73462306a36Sopenharmony_ci		case 1:
73562306a36Sopenharmony_ci			err = ec_read(0x7B, &result);
73662306a36Sopenharmony_ci			if (err)
73762306a36Sopenharmony_ci				return AE_ERROR;
73862306a36Sopenharmony_ci			*value = result & 0x1;
73962306a36Sopenharmony_ci			return AE_OK;
74062306a36Sopenharmony_ci		case 2:
74162306a36Sopenharmony_ci			err = ec_read(0x71, &result);
74262306a36Sopenharmony_ci			if (err)
74362306a36Sopenharmony_ci				return AE_ERROR;
74462306a36Sopenharmony_ci			*value = result & 0x1;
74562306a36Sopenharmony_ci			return AE_OK;
74662306a36Sopenharmony_ci		case 3:
74762306a36Sopenharmony_ci			err = ec_read(0x78, &result);
74862306a36Sopenharmony_ci			if (err)
74962306a36Sopenharmony_ci				return AE_ERROR;
75062306a36Sopenharmony_ci			*value = result & 0x1;
75162306a36Sopenharmony_ci			return AE_OK;
75262306a36Sopenharmony_ci		default:
75362306a36Sopenharmony_ci			err = ec_read(0xA, &result);
75462306a36Sopenharmony_ci			if (err)
75562306a36Sopenharmony_ci				return AE_ERROR;
75662306a36Sopenharmony_ci			*value = (result >> 2) & 0x1;
75762306a36Sopenharmony_ci			return AE_OK;
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci		break;
76062306a36Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
76162306a36Sopenharmony_ci		switch (quirks->bluetooth) {
76262306a36Sopenharmony_ci		default:
76362306a36Sopenharmony_ci			err = ec_read(0xA, &result);
76462306a36Sopenharmony_ci			if (err)
76562306a36Sopenharmony_ci				return AE_ERROR;
76662306a36Sopenharmony_ci			*value = (result >> 4) & 0x1;
76762306a36Sopenharmony_ci			return AE_OK;
76862306a36Sopenharmony_ci		}
76962306a36Sopenharmony_ci		break;
77062306a36Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
77162306a36Sopenharmony_ci		switch (quirks->brightness) {
77262306a36Sopenharmony_ci		default:
77362306a36Sopenharmony_ci			err = ec_read(0x83, &result);
77462306a36Sopenharmony_ci			if (err)
77562306a36Sopenharmony_ci				return AE_ERROR;
77662306a36Sopenharmony_ci			*value = result;
77762306a36Sopenharmony_ci			return AE_OK;
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci		break;
78062306a36Sopenharmony_ci	default:
78162306a36Sopenharmony_ci		return AE_ERROR;
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci	return AE_OK;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic acpi_status AMW0_set_u32(u32 value, u32 cap)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct wmab_args args;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	args.eax = ACER_AMW0_WRITE;
79162306a36Sopenharmony_ci	args.ebx = value ? (1<<8) : 0;
79262306a36Sopenharmony_ci	args.ecx = args.edx = 0;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	switch (cap) {
79562306a36Sopenharmony_ci	case ACER_CAP_MAILLED:
79662306a36Sopenharmony_ci		if (value > 1)
79762306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
79862306a36Sopenharmony_ci		args.ebx |= ACER_AMW0_MAILLED_MASK;
79962306a36Sopenharmony_ci		break;
80062306a36Sopenharmony_ci	case ACER_CAP_WIRELESS:
80162306a36Sopenharmony_ci		if (value > 1)
80262306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
80362306a36Sopenharmony_ci		args.ebx |= ACER_AMW0_WIRELESS_MASK;
80462306a36Sopenharmony_ci		break;
80562306a36Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
80662306a36Sopenharmony_ci		if (value > 1)
80762306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
80862306a36Sopenharmony_ci		args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
80962306a36Sopenharmony_ci		break;
81062306a36Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
81162306a36Sopenharmony_ci		if (value > max_brightness)
81262306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
81362306a36Sopenharmony_ci		switch (quirks->brightness) {
81462306a36Sopenharmony_ci		default:
81562306a36Sopenharmony_ci			return ec_write(0x83, value);
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci	default:
81862306a36Sopenharmony_ci		return AE_ERROR;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	/* Actually do the set */
82262306a36Sopenharmony_ci	return wmab_execute(&args, NULL);
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic acpi_status __init AMW0_find_mailled(void)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	struct wmab_args args;
82862306a36Sopenharmony_ci	struct wmab_ret ret;
82962306a36Sopenharmony_ci	acpi_status status = AE_OK;
83062306a36Sopenharmony_ci	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
83162306a36Sopenharmony_ci	union acpi_object *obj;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	args.eax = 0x86;
83462306a36Sopenharmony_ci	args.ebx = args.ecx = args.edx = 0;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	status = wmab_execute(&args, &out);
83762306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
83862306a36Sopenharmony_ci		return status;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
84162306a36Sopenharmony_ci	if (obj && obj->type == ACPI_TYPE_BUFFER &&
84262306a36Sopenharmony_ci	obj->buffer.length == sizeof(struct wmab_ret)) {
84362306a36Sopenharmony_ci		ret = *((struct wmab_ret *) obj->buffer.pointer);
84462306a36Sopenharmony_ci	} else {
84562306a36Sopenharmony_ci		kfree(out.pointer);
84662306a36Sopenharmony_ci		return AE_ERROR;
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (ret.eex & 0x1)
85062306a36Sopenharmony_ci		interface->capability |= ACER_CAP_MAILLED;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	kfree(out.pointer);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	return AE_OK;
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic const struct acpi_device_id norfkill_ids[] __initconst = {
85862306a36Sopenharmony_ci	{ "VPC2004", 0},
85962306a36Sopenharmony_ci	{ "IBM0068", 0},
86062306a36Sopenharmony_ci	{ "LEN0068", 0},
86162306a36Sopenharmony_ci	{ "SNY5001", 0},	/* sony-laptop in charge */
86262306a36Sopenharmony_ci	{ "HPQ6601", 0},
86362306a36Sopenharmony_ci	{ "", 0},
86462306a36Sopenharmony_ci};
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic int __init AMW0_set_cap_acpi_check_device(void)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	const struct acpi_device_id *id;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	for (id = norfkill_ids; id->id[0]; id++)
87162306a36Sopenharmony_ci		if (acpi_dev_found(id->id))
87262306a36Sopenharmony_ci			return true;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	return false;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic acpi_status __init AMW0_set_capabilities(void)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	struct wmab_args args;
88062306a36Sopenharmony_ci	struct wmab_ret ret;
88162306a36Sopenharmony_ci	acpi_status status;
88262306a36Sopenharmony_ci	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
88362306a36Sopenharmony_ci	union acpi_object *obj;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	/*
88662306a36Sopenharmony_ci	 * On laptops with this strange GUID (non Acer), normal probing doesn't
88762306a36Sopenharmony_ci	 * work.
88862306a36Sopenharmony_ci	 */
88962306a36Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID2)) {
89062306a36Sopenharmony_ci		if ((quirks != &quirk_unknown) ||
89162306a36Sopenharmony_ci		    !AMW0_set_cap_acpi_check_device())
89262306a36Sopenharmony_ci			interface->capability |= ACER_CAP_WIRELESS;
89362306a36Sopenharmony_ci		return AE_OK;
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	args.eax = ACER_AMW0_WRITE;
89762306a36Sopenharmony_ci	args.ecx = args.edx = 0;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	args.ebx = 0xa2 << 8;
90062306a36Sopenharmony_ci	args.ebx |= ACER_AMW0_WIRELESS_MASK;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	status = wmab_execute(&args, &out);
90362306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
90462306a36Sopenharmony_ci		return status;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	obj = out.pointer;
90762306a36Sopenharmony_ci	if (obj && obj->type == ACPI_TYPE_BUFFER &&
90862306a36Sopenharmony_ci	obj->buffer.length == sizeof(struct wmab_ret)) {
90962306a36Sopenharmony_ci		ret = *((struct wmab_ret *) obj->buffer.pointer);
91062306a36Sopenharmony_ci	} else {
91162306a36Sopenharmony_ci		status = AE_ERROR;
91262306a36Sopenharmony_ci		goto out;
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (ret.eax & 0x1)
91662306a36Sopenharmony_ci		interface->capability |= ACER_CAP_WIRELESS;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	args.ebx = 2 << 8;
91962306a36Sopenharmony_ci	args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	/*
92262306a36Sopenharmony_ci	 * It's ok to use existing buffer for next wmab_execute call.
92362306a36Sopenharmony_ci	 * But we need to kfree(out.pointer) if next wmab_execute fail.
92462306a36Sopenharmony_ci	 */
92562306a36Sopenharmony_ci	status = wmab_execute(&args, &out);
92662306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
92762306a36Sopenharmony_ci		goto out;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
93062306a36Sopenharmony_ci	if (obj && obj->type == ACPI_TYPE_BUFFER
93162306a36Sopenharmony_ci	&& obj->buffer.length == sizeof(struct wmab_ret)) {
93262306a36Sopenharmony_ci		ret = *((struct wmab_ret *) obj->buffer.pointer);
93362306a36Sopenharmony_ci	} else {
93462306a36Sopenharmony_ci		status = AE_ERROR;
93562306a36Sopenharmony_ci		goto out;
93662306a36Sopenharmony_ci	}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (ret.eax & 0x1)
93962306a36Sopenharmony_ci		interface->capability |= ACER_CAP_BLUETOOTH;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	/*
94262306a36Sopenharmony_ci	 * This appears to be safe to enable, since all Wistron based laptops
94362306a36Sopenharmony_ci	 * appear to use the same EC register for brightness, even if they
94462306a36Sopenharmony_ci	 * differ for wireless, etc
94562306a36Sopenharmony_ci	 */
94662306a36Sopenharmony_ci	if (quirks->brightness >= 0)
94762306a36Sopenharmony_ci		interface->capability |= ACER_CAP_BRIGHTNESS;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	status = AE_OK;
95062306a36Sopenharmony_ciout:
95162306a36Sopenharmony_ci	kfree(out.pointer);
95262306a36Sopenharmony_ci	return status;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic struct wmi_interface AMW0_interface = {
95662306a36Sopenharmony_ci	.type = ACER_AMW0,
95762306a36Sopenharmony_ci};
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cistatic struct wmi_interface AMW0_V2_interface = {
96062306a36Sopenharmony_ci	.type = ACER_AMW0_V2,
96162306a36Sopenharmony_ci};
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci/*
96462306a36Sopenharmony_ci * New interface (The WMID interface)
96562306a36Sopenharmony_ci */
96662306a36Sopenharmony_cistatic acpi_status
96762306a36Sopenharmony_ciWMI_execute_u32(u32 method_id, u32 in, u32 *out)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
97062306a36Sopenharmony_ci	struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
97162306a36Sopenharmony_ci	union acpi_object *obj;
97262306a36Sopenharmony_ci	u32 tmp = 0;
97362306a36Sopenharmony_ci	acpi_status status;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID1, 0, method_id, &input, &result);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
97862306a36Sopenharmony_ci		return status;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	obj = (union acpi_object *) result.pointer;
98162306a36Sopenharmony_ci	if (obj) {
98262306a36Sopenharmony_ci		if (obj->type == ACPI_TYPE_BUFFER &&
98362306a36Sopenharmony_ci			(obj->buffer.length == sizeof(u32) ||
98462306a36Sopenharmony_ci			obj->buffer.length == sizeof(u64))) {
98562306a36Sopenharmony_ci			tmp = *((u32 *) obj->buffer.pointer);
98662306a36Sopenharmony_ci		} else if (obj->type == ACPI_TYPE_INTEGER) {
98762306a36Sopenharmony_ci			tmp = (u32) obj->integer.value;
98862306a36Sopenharmony_ci		}
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	if (out)
99262306a36Sopenharmony_ci		*out = tmp;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	kfree(result.pointer);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	return status;
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic acpi_status WMID_get_u32(u32 *value, u32 cap)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	acpi_status status;
100262306a36Sopenharmony_ci	u8 tmp;
100362306a36Sopenharmony_ci	u32 result, method_id = 0;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	switch (cap) {
100662306a36Sopenharmony_ci	case ACER_CAP_WIRELESS:
100762306a36Sopenharmony_ci		method_id = ACER_WMID_GET_WIRELESS_METHODID;
100862306a36Sopenharmony_ci		break;
100962306a36Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
101062306a36Sopenharmony_ci		method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
101162306a36Sopenharmony_ci		break;
101262306a36Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
101362306a36Sopenharmony_ci		method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
101462306a36Sopenharmony_ci		break;
101562306a36Sopenharmony_ci	case ACER_CAP_THREEG:
101662306a36Sopenharmony_ci		method_id = ACER_WMID_GET_THREEG_METHODID;
101762306a36Sopenharmony_ci		break;
101862306a36Sopenharmony_ci	case ACER_CAP_MAILLED:
101962306a36Sopenharmony_ci		if (quirks->mailled == 1) {
102062306a36Sopenharmony_ci			ec_read(0x9f, &tmp);
102162306a36Sopenharmony_ci			*value = tmp & 0x1;
102262306a36Sopenharmony_ci			return 0;
102362306a36Sopenharmony_ci		}
102462306a36Sopenharmony_ci		fallthrough;
102562306a36Sopenharmony_ci	default:
102662306a36Sopenharmony_ci		return AE_ERROR;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci	status = WMI_execute_u32(method_id, 0, &result);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (ACPI_SUCCESS(status))
103162306a36Sopenharmony_ci		*value = (u8)result;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	return status;
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic acpi_status WMID_set_u32(u32 value, u32 cap)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	u32 method_id = 0;
103962306a36Sopenharmony_ci	char param;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	switch (cap) {
104262306a36Sopenharmony_ci	case ACER_CAP_BRIGHTNESS:
104362306a36Sopenharmony_ci		if (value > max_brightness)
104462306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
104562306a36Sopenharmony_ci		method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
104662306a36Sopenharmony_ci		break;
104762306a36Sopenharmony_ci	case ACER_CAP_WIRELESS:
104862306a36Sopenharmony_ci		if (value > 1)
104962306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
105062306a36Sopenharmony_ci		method_id = ACER_WMID_SET_WIRELESS_METHODID;
105162306a36Sopenharmony_ci		break;
105262306a36Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
105362306a36Sopenharmony_ci		if (value > 1)
105462306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
105562306a36Sopenharmony_ci		method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
105662306a36Sopenharmony_ci		break;
105762306a36Sopenharmony_ci	case ACER_CAP_THREEG:
105862306a36Sopenharmony_ci		if (value > 1)
105962306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
106062306a36Sopenharmony_ci		method_id = ACER_WMID_SET_THREEG_METHODID;
106162306a36Sopenharmony_ci		break;
106262306a36Sopenharmony_ci	case ACER_CAP_MAILLED:
106362306a36Sopenharmony_ci		if (value > 1)
106462306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
106562306a36Sopenharmony_ci		if (quirks->mailled == 1) {
106662306a36Sopenharmony_ci			param = value ? 0x92 : 0x93;
106762306a36Sopenharmony_ci			i8042_lock_chip();
106862306a36Sopenharmony_ci			i8042_command(&param, 0x1059);
106962306a36Sopenharmony_ci			i8042_unlock_chip();
107062306a36Sopenharmony_ci			return 0;
107162306a36Sopenharmony_ci		}
107262306a36Sopenharmony_ci		break;
107362306a36Sopenharmony_ci	default:
107462306a36Sopenharmony_ci		return AE_ERROR;
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci	return WMI_execute_u32(method_id, (u32)value, NULL);
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic acpi_status wmid3_get_device_status(u32 *value, u16 device)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	struct wmid3_gds_return_value return_value;
108262306a36Sopenharmony_ci	acpi_status status;
108362306a36Sopenharmony_ci	union acpi_object *obj;
108462306a36Sopenharmony_ci	struct wmid3_gds_get_input_param params = {
108562306a36Sopenharmony_ci		.function_num = 0x1,
108662306a36Sopenharmony_ci		.hotkey_number = commun_fn_key_number,
108762306a36Sopenharmony_ci		.devices = device,
108862306a36Sopenharmony_ci	};
108962306a36Sopenharmony_ci	struct acpi_buffer input = {
109062306a36Sopenharmony_ci		sizeof(struct wmid3_gds_get_input_param),
109162306a36Sopenharmony_ci		&params
109262306a36Sopenharmony_ci	};
109362306a36Sopenharmony_ci	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
109662306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
109762306a36Sopenharmony_ci		return status;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	obj = output.pointer;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	if (!obj)
110262306a36Sopenharmony_ci		return AE_ERROR;
110362306a36Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
110462306a36Sopenharmony_ci		kfree(obj);
110562306a36Sopenharmony_ci		return AE_ERROR;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci	if (obj->buffer.length != 8) {
110862306a36Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
110962306a36Sopenharmony_ci		kfree(obj);
111062306a36Sopenharmony_ci		return AE_ERROR;
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
111462306a36Sopenharmony_ci	kfree(obj);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
111762306a36Sopenharmony_ci		pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
111862306a36Sopenharmony_ci			device,
111962306a36Sopenharmony_ci			return_value.error_code,
112062306a36Sopenharmony_ci			return_value.ec_return_value);
112162306a36Sopenharmony_ci	else
112262306a36Sopenharmony_ci		*value = !!(return_value.devices & device);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	return status;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_cistatic acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	u16 device;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	switch (cap) {
113262306a36Sopenharmony_ci	case ACER_CAP_WIRELESS:
113362306a36Sopenharmony_ci		device = ACER_WMID3_GDS_WIRELESS;
113462306a36Sopenharmony_ci		break;
113562306a36Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
113662306a36Sopenharmony_ci		device = ACER_WMID3_GDS_BLUETOOTH;
113762306a36Sopenharmony_ci		break;
113862306a36Sopenharmony_ci	case ACER_CAP_THREEG:
113962306a36Sopenharmony_ci		device = ACER_WMID3_GDS_THREEG;
114062306a36Sopenharmony_ci		break;
114162306a36Sopenharmony_ci	default:
114262306a36Sopenharmony_ci		return AE_ERROR;
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci	return wmid3_get_device_status(value, device);
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic acpi_status wmid3_set_device_status(u32 value, u16 device)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	struct wmid3_gds_return_value return_value;
115062306a36Sopenharmony_ci	acpi_status status;
115162306a36Sopenharmony_ci	union acpi_object *obj;
115262306a36Sopenharmony_ci	u16 devices;
115362306a36Sopenharmony_ci	struct wmid3_gds_get_input_param get_params = {
115462306a36Sopenharmony_ci		.function_num = 0x1,
115562306a36Sopenharmony_ci		.hotkey_number = commun_fn_key_number,
115662306a36Sopenharmony_ci		.devices = commun_func_bitmap,
115762306a36Sopenharmony_ci	};
115862306a36Sopenharmony_ci	struct acpi_buffer get_input = {
115962306a36Sopenharmony_ci		sizeof(struct wmid3_gds_get_input_param),
116062306a36Sopenharmony_ci		&get_params
116162306a36Sopenharmony_ci	};
116262306a36Sopenharmony_ci	struct wmid3_gds_set_input_param set_params = {
116362306a36Sopenharmony_ci		.function_num = 0x2,
116462306a36Sopenharmony_ci		.hotkey_number = commun_fn_key_number,
116562306a36Sopenharmony_ci		.devices = commun_func_bitmap,
116662306a36Sopenharmony_ci	};
116762306a36Sopenharmony_ci	struct acpi_buffer set_input = {
116862306a36Sopenharmony_ci		sizeof(struct wmid3_gds_set_input_param),
116962306a36Sopenharmony_ci		&set_params
117062306a36Sopenharmony_ci	};
117162306a36Sopenharmony_ci	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
117262306a36Sopenharmony_ci	struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
117562306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
117662306a36Sopenharmony_ci		return status;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	obj = output.pointer;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	if (!obj)
118162306a36Sopenharmony_ci		return AE_ERROR;
118262306a36Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
118362306a36Sopenharmony_ci		kfree(obj);
118462306a36Sopenharmony_ci		return AE_ERROR;
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci	if (obj->buffer.length != 8) {
118762306a36Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
118862306a36Sopenharmony_ci		kfree(obj);
118962306a36Sopenharmony_ci		return AE_ERROR;
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
119362306a36Sopenharmony_ci	kfree(obj);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value) {
119662306a36Sopenharmony_ci		pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
119762306a36Sopenharmony_ci			return_value.error_code,
119862306a36Sopenharmony_ci			return_value.ec_return_value);
119962306a36Sopenharmony_ci		return status;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	devices = return_value.devices;
120362306a36Sopenharmony_ci	set_params.devices = (value) ? (devices | device) : (devices & ~device);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
120662306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
120762306a36Sopenharmony_ci		return status;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	obj = output2.pointer;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	if (!obj)
121262306a36Sopenharmony_ci		return AE_ERROR;
121362306a36Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
121462306a36Sopenharmony_ci		kfree(obj);
121562306a36Sopenharmony_ci		return AE_ERROR;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci	if (obj->buffer.length != 4) {
121862306a36Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
121962306a36Sopenharmony_ci		kfree(obj);
122062306a36Sopenharmony_ci		return AE_ERROR;
122162306a36Sopenharmony_ci	}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
122462306a36Sopenharmony_ci	kfree(obj);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
122762306a36Sopenharmony_ci		pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
122862306a36Sopenharmony_ci			return_value.error_code,
122962306a36Sopenharmony_ci			return_value.ec_return_value);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	return status;
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic acpi_status wmid_v2_set_u32(u32 value, u32 cap)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	u16 device;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	switch (cap) {
123962306a36Sopenharmony_ci	case ACER_CAP_WIRELESS:
124062306a36Sopenharmony_ci		device = ACER_WMID3_GDS_WIRELESS;
124162306a36Sopenharmony_ci		break;
124262306a36Sopenharmony_ci	case ACER_CAP_BLUETOOTH:
124362306a36Sopenharmony_ci		device = ACER_WMID3_GDS_BLUETOOTH;
124462306a36Sopenharmony_ci		break;
124562306a36Sopenharmony_ci	case ACER_CAP_THREEG:
124662306a36Sopenharmony_ci		device = ACER_WMID3_GDS_THREEG;
124762306a36Sopenharmony_ci		break;
124862306a36Sopenharmony_ci	default:
124962306a36Sopenharmony_ci		return AE_ERROR;
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci	return wmid3_set_device_status(value, device);
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct hotkey_function_type_aa *type_aa;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	/* We are looking for OEM-specific Type AAh */
125962306a36Sopenharmony_ci	if (header->type != 0xAA)
126062306a36Sopenharmony_ci		return;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	has_type_aa = true;
126362306a36Sopenharmony_ci	type_aa = (struct hotkey_function_type_aa *) header;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	pr_info("Function bitmap for Communication Button: 0x%x\n",
126662306a36Sopenharmony_ci		type_aa->commun_func_bitmap);
126762306a36Sopenharmony_ci	commun_func_bitmap = type_aa->commun_func_bitmap;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
127062306a36Sopenharmony_ci		interface->capability |= ACER_CAP_WIRELESS;
127162306a36Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
127262306a36Sopenharmony_ci		interface->capability |= ACER_CAP_THREEG;
127362306a36Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
127462306a36Sopenharmony_ci		interface->capability |= ACER_CAP_BLUETOOTH;
127562306a36Sopenharmony_ci	if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN)
127662306a36Sopenharmony_ci		commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	commun_fn_key_number = type_aa->commun_fn_key_number;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic acpi_status __init WMID_set_capabilities(void)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
128462306a36Sopenharmony_ci	union acpi_object *obj;
128562306a36Sopenharmony_ci	acpi_status status;
128662306a36Sopenharmony_ci	u32 devices;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	status = wmi_query_block(WMID_GUID2, 0, &out);
128962306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
129062306a36Sopenharmony_ci		return status;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
129362306a36Sopenharmony_ci	if (obj) {
129462306a36Sopenharmony_ci		if (obj->type == ACPI_TYPE_BUFFER &&
129562306a36Sopenharmony_ci			(obj->buffer.length == sizeof(u32) ||
129662306a36Sopenharmony_ci			obj->buffer.length == sizeof(u64))) {
129762306a36Sopenharmony_ci			devices = *((u32 *) obj->buffer.pointer);
129862306a36Sopenharmony_ci		} else if (obj->type == ACPI_TYPE_INTEGER) {
129962306a36Sopenharmony_ci			devices = (u32) obj->integer.value;
130062306a36Sopenharmony_ci		} else {
130162306a36Sopenharmony_ci			kfree(out.pointer);
130262306a36Sopenharmony_ci			return AE_ERROR;
130362306a36Sopenharmony_ci		}
130462306a36Sopenharmony_ci	} else {
130562306a36Sopenharmony_ci		kfree(out.pointer);
130662306a36Sopenharmony_ci		return AE_ERROR;
130762306a36Sopenharmony_ci	}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
131062306a36Sopenharmony_ci	if (devices & 0x07)
131162306a36Sopenharmony_ci		interface->capability |= ACER_CAP_WIRELESS;
131262306a36Sopenharmony_ci	if (devices & 0x40)
131362306a36Sopenharmony_ci		interface->capability |= ACER_CAP_THREEG;
131462306a36Sopenharmony_ci	if (devices & 0x10)
131562306a36Sopenharmony_ci		interface->capability |= ACER_CAP_BLUETOOTH;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	if (!(devices & 0x20))
131862306a36Sopenharmony_ci		max_brightness = 0x9;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	kfree(out.pointer);
132162306a36Sopenharmony_ci	return status;
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cistatic struct wmi_interface wmid_interface = {
132562306a36Sopenharmony_ci	.type = ACER_WMID,
132662306a36Sopenharmony_ci};
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic struct wmi_interface wmid_v2_interface = {
132962306a36Sopenharmony_ci	.type = ACER_WMID_v2,
133062306a36Sopenharmony_ci};
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci/*
133362306a36Sopenharmony_ci * WMID Gaming interface
133462306a36Sopenharmony_ci */
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic acpi_status
133762306a36Sopenharmony_ciWMI_gaming_execute_u64(u32 method_id, u64 in, u64 *out)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	struct acpi_buffer input = { (acpi_size) sizeof(u64), (void *)(&in) };
134062306a36Sopenharmony_ci	struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
134162306a36Sopenharmony_ci	union acpi_object *obj;
134262306a36Sopenharmony_ci	u32 tmp = 0;
134362306a36Sopenharmony_ci	acpi_status status;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID4, 0, method_id, &input, &result);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
134862306a36Sopenharmony_ci		return status;
134962306a36Sopenharmony_ci	obj = (union acpi_object *) result.pointer;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	if (obj) {
135262306a36Sopenharmony_ci		if (obj->type == ACPI_TYPE_BUFFER) {
135362306a36Sopenharmony_ci			if (obj->buffer.length == sizeof(u32))
135462306a36Sopenharmony_ci				tmp = *((u32 *) obj->buffer.pointer);
135562306a36Sopenharmony_ci			else if (obj->buffer.length == sizeof(u64))
135662306a36Sopenharmony_ci				tmp = *((u64 *) obj->buffer.pointer);
135762306a36Sopenharmony_ci		} else if (obj->type == ACPI_TYPE_INTEGER) {
135862306a36Sopenharmony_ci			tmp = (u64) obj->integer.value;
135962306a36Sopenharmony_ci		}
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	if (out)
136362306a36Sopenharmony_ci		*out = tmp;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	kfree(result.pointer);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	return status;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cistatic acpi_status WMID_gaming_set_u64(u64 value, u32 cap)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	u32 method_id = 0;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	if (!(interface->capability & cap))
137562306a36Sopenharmony_ci		return AE_BAD_PARAMETER;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	switch (cap) {
137862306a36Sopenharmony_ci	case ACER_CAP_TURBO_LED:
137962306a36Sopenharmony_ci		method_id = ACER_WMID_SET_GAMING_LED_METHODID;
138062306a36Sopenharmony_ci		break;
138162306a36Sopenharmony_ci	case ACER_CAP_TURBO_FAN:
138262306a36Sopenharmony_ci		method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR;
138362306a36Sopenharmony_ci		break;
138462306a36Sopenharmony_ci	case ACER_CAP_TURBO_OC:
138562306a36Sopenharmony_ci		method_id = ACER_WMID_SET_GAMING_MISC_SETTING_METHODID;
138662306a36Sopenharmony_ci		break;
138762306a36Sopenharmony_ci	default:
138862306a36Sopenharmony_ci		return AE_BAD_PARAMETER;
138962306a36Sopenharmony_ci	}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	return WMI_gaming_execute_u64(method_id, value, NULL);
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_cistatic acpi_status WMID_gaming_get_u64(u64 *value, u32 cap)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	acpi_status status;
139762306a36Sopenharmony_ci	u64 result;
139862306a36Sopenharmony_ci	u64 input;
139962306a36Sopenharmony_ci	u32 method_id;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	if (!(interface->capability & cap))
140262306a36Sopenharmony_ci		return AE_BAD_PARAMETER;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	switch (cap) {
140562306a36Sopenharmony_ci	case ACER_CAP_TURBO_LED:
140662306a36Sopenharmony_ci		method_id = ACER_WMID_GET_GAMING_LED_METHODID;
140762306a36Sopenharmony_ci		input = 0x1;
140862306a36Sopenharmony_ci		break;
140962306a36Sopenharmony_ci	default:
141062306a36Sopenharmony_ci		return AE_BAD_PARAMETER;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci	status = WMI_gaming_execute_u64(method_id, input, &result);
141362306a36Sopenharmony_ci	if (ACPI_SUCCESS(status))
141462306a36Sopenharmony_ci		*value = (u64) result;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	return status;
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic void WMID_gaming_set_fan_mode(u8 fan_mode)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	/* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/
142262306a36Sopenharmony_ci	u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0;
142362306a36Sopenharmony_ci	int i;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (quirks->cpu_fans > 0)
142662306a36Sopenharmony_ci		gpu_fan_config2 |= 1;
142762306a36Sopenharmony_ci	for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
142862306a36Sopenharmony_ci		gpu_fan_config2 |= 1 << (i + 1);
142962306a36Sopenharmony_ci	for (i = 0; i < quirks->gpu_fans; ++i)
143062306a36Sopenharmony_ci		gpu_fan_config2 |= 1 << (i + 3);
143162306a36Sopenharmony_ci	if (quirks->cpu_fans > 0)
143262306a36Sopenharmony_ci		gpu_fan_config1 |= fan_mode;
143362306a36Sopenharmony_ci	for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
143462306a36Sopenharmony_ci		gpu_fan_config1 |= fan_mode << (2 * i + 2);
143562306a36Sopenharmony_ci	for (i = 0; i < quirks->gpu_fans; ++i)
143662306a36Sopenharmony_ci		gpu_fan_config1 |= fan_mode << (2 * i + 6);
143762306a36Sopenharmony_ci	WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN);
143862306a36Sopenharmony_ci}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci/*
144162306a36Sopenharmony_ci * Generic Device (interface-independent)
144262306a36Sopenharmony_ci */
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic acpi_status get_u32(u32 *value, u32 cap)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	acpi_status status = AE_ERROR;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	switch (interface->type) {
144962306a36Sopenharmony_ci	case ACER_AMW0:
145062306a36Sopenharmony_ci		status = AMW0_get_u32(value, cap);
145162306a36Sopenharmony_ci		break;
145262306a36Sopenharmony_ci	case ACER_AMW0_V2:
145362306a36Sopenharmony_ci		if (cap == ACER_CAP_MAILLED) {
145462306a36Sopenharmony_ci			status = AMW0_get_u32(value, cap);
145562306a36Sopenharmony_ci			break;
145662306a36Sopenharmony_ci		}
145762306a36Sopenharmony_ci		fallthrough;
145862306a36Sopenharmony_ci	case ACER_WMID:
145962306a36Sopenharmony_ci		status = WMID_get_u32(value, cap);
146062306a36Sopenharmony_ci		break;
146162306a36Sopenharmony_ci	case ACER_WMID_v2:
146262306a36Sopenharmony_ci		if (cap & (ACER_CAP_WIRELESS |
146362306a36Sopenharmony_ci			   ACER_CAP_BLUETOOTH |
146462306a36Sopenharmony_ci			   ACER_CAP_THREEG))
146562306a36Sopenharmony_ci			status = wmid_v2_get_u32(value, cap);
146662306a36Sopenharmony_ci		else if (wmi_has_guid(WMID_GUID2))
146762306a36Sopenharmony_ci			status = WMID_get_u32(value, cap);
146862306a36Sopenharmony_ci		break;
146962306a36Sopenharmony_ci	}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	return status;
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic acpi_status set_u32(u32 value, u32 cap)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	acpi_status status;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	if (interface->capability & cap) {
147962306a36Sopenharmony_ci		switch (interface->type) {
148062306a36Sopenharmony_ci		case ACER_AMW0:
148162306a36Sopenharmony_ci			return AMW0_set_u32(value, cap);
148262306a36Sopenharmony_ci		case ACER_AMW0_V2:
148362306a36Sopenharmony_ci			if (cap == ACER_CAP_MAILLED)
148462306a36Sopenharmony_ci				return AMW0_set_u32(value, cap);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci			/*
148762306a36Sopenharmony_ci			 * On some models, some WMID methods don't toggle
148862306a36Sopenharmony_ci			 * properly. For those cases, we want to run the AMW0
148962306a36Sopenharmony_ci			 * method afterwards to be certain we've really toggled
149062306a36Sopenharmony_ci			 * the device state.
149162306a36Sopenharmony_ci			 */
149262306a36Sopenharmony_ci			if (cap == ACER_CAP_WIRELESS ||
149362306a36Sopenharmony_ci				cap == ACER_CAP_BLUETOOTH) {
149462306a36Sopenharmony_ci				status = WMID_set_u32(value, cap);
149562306a36Sopenharmony_ci				if (ACPI_FAILURE(status))
149662306a36Sopenharmony_ci					return status;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci				return AMW0_set_u32(value, cap);
149962306a36Sopenharmony_ci			}
150062306a36Sopenharmony_ci			fallthrough;
150162306a36Sopenharmony_ci		case ACER_WMID:
150262306a36Sopenharmony_ci			return WMID_set_u32(value, cap);
150362306a36Sopenharmony_ci		case ACER_WMID_v2:
150462306a36Sopenharmony_ci			if (cap & (ACER_CAP_WIRELESS |
150562306a36Sopenharmony_ci				   ACER_CAP_BLUETOOTH |
150662306a36Sopenharmony_ci				   ACER_CAP_THREEG))
150762306a36Sopenharmony_ci				return wmid_v2_set_u32(value, cap);
150862306a36Sopenharmony_ci			else if (wmi_has_guid(WMID_GUID2))
150962306a36Sopenharmony_ci				return WMID_set_u32(value, cap);
151062306a36Sopenharmony_ci			fallthrough;
151162306a36Sopenharmony_ci		default:
151262306a36Sopenharmony_ci			return AE_BAD_PARAMETER;
151362306a36Sopenharmony_ci		}
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci	return AE_BAD_PARAMETER;
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_cistatic void __init acer_commandline_init(void)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	/*
152162306a36Sopenharmony_ci	 * These will all fail silently if the value given is invalid, or the
152262306a36Sopenharmony_ci	 * capability isn't available on the given interface
152362306a36Sopenharmony_ci	 */
152462306a36Sopenharmony_ci	if (mailled >= 0)
152562306a36Sopenharmony_ci		set_u32(mailled, ACER_CAP_MAILLED);
152662306a36Sopenharmony_ci	if (!has_type_aa && threeg >= 0)
152762306a36Sopenharmony_ci		set_u32(threeg, ACER_CAP_THREEG);
152862306a36Sopenharmony_ci	if (brightness >= 0)
152962306a36Sopenharmony_ci		set_u32(brightness, ACER_CAP_BRIGHTNESS);
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci/*
153362306a36Sopenharmony_ci * LED device (Mail LED only, no other LEDs known yet)
153462306a36Sopenharmony_ci */
153562306a36Sopenharmony_cistatic void mail_led_set(struct led_classdev *led_cdev,
153662306a36Sopenharmony_cienum led_brightness value)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	set_u32(value, ACER_CAP_MAILLED);
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cistatic struct led_classdev mail_led = {
154262306a36Sopenharmony_ci	.name = "acer-wmi::mail",
154362306a36Sopenharmony_ci	.brightness_set = mail_led_set,
154462306a36Sopenharmony_ci};
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic int acer_led_init(struct device *dev)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	return led_classdev_register(dev, &mail_led);
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic void acer_led_exit(void)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	set_u32(LED_OFF, ACER_CAP_MAILLED);
155462306a36Sopenharmony_ci	led_classdev_unregister(&mail_led);
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci/*
155862306a36Sopenharmony_ci * Backlight device
155962306a36Sopenharmony_ci */
156062306a36Sopenharmony_cistatic struct backlight_device *acer_backlight_device;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_cistatic int read_brightness(struct backlight_device *bd)
156362306a36Sopenharmony_ci{
156462306a36Sopenharmony_ci	u32 value;
156562306a36Sopenharmony_ci	get_u32(&value, ACER_CAP_BRIGHTNESS);
156662306a36Sopenharmony_ci	return value;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic int update_bl_status(struct backlight_device *bd)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	int intensity = backlight_get_brightness(bd);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	set_u32(intensity, ACER_CAP_BRIGHTNESS);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	return 0;
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_cistatic const struct backlight_ops acer_bl_ops = {
157962306a36Sopenharmony_ci	.get_brightness = read_brightness,
158062306a36Sopenharmony_ci	.update_status = update_bl_status,
158162306a36Sopenharmony_ci};
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_cistatic int acer_backlight_init(struct device *dev)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	struct backlight_properties props;
158662306a36Sopenharmony_ci	struct backlight_device *bd;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	memset(&props, 0, sizeof(struct backlight_properties));
158962306a36Sopenharmony_ci	props.type = BACKLIGHT_PLATFORM;
159062306a36Sopenharmony_ci	props.max_brightness = max_brightness;
159162306a36Sopenharmony_ci	bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
159262306a36Sopenharmony_ci				       &props);
159362306a36Sopenharmony_ci	if (IS_ERR(bd)) {
159462306a36Sopenharmony_ci		pr_err("Could not register Acer backlight device\n");
159562306a36Sopenharmony_ci		acer_backlight_device = NULL;
159662306a36Sopenharmony_ci		return PTR_ERR(bd);
159762306a36Sopenharmony_ci	}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	acer_backlight_device = bd;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	bd->props.power = FB_BLANK_UNBLANK;
160262306a36Sopenharmony_ci	bd->props.brightness = read_brightness(bd);
160362306a36Sopenharmony_ci	backlight_update_status(bd);
160462306a36Sopenharmony_ci	return 0;
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_cistatic void acer_backlight_exit(void)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	backlight_device_unregister(acer_backlight_device);
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci/*
161362306a36Sopenharmony_ci * Accelerometer device
161462306a36Sopenharmony_ci */
161562306a36Sopenharmony_cistatic acpi_handle gsensor_handle;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_cistatic int acer_gsensor_init(void)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	acpi_status status;
162062306a36Sopenharmony_ci	struct acpi_buffer output;
162162306a36Sopenharmony_ci	union acpi_object out_obj;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	output.length = sizeof(out_obj);
162462306a36Sopenharmony_ci	output.pointer = &out_obj;
162562306a36Sopenharmony_ci	status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
162662306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
162762306a36Sopenharmony_ci		return -1;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	return 0;
163062306a36Sopenharmony_ci}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_cistatic int acer_gsensor_open(struct input_dev *input)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	return acer_gsensor_init();
163562306a36Sopenharmony_ci}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_cistatic int acer_gsensor_event(void)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	acpi_status status;
164062306a36Sopenharmony_ci	struct acpi_buffer output;
164162306a36Sopenharmony_ci	union acpi_object out_obj[5];
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	if (!acer_wmi_accel_dev)
164462306a36Sopenharmony_ci		return -1;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	output.length = sizeof(out_obj);
164762306a36Sopenharmony_ci	output.pointer = out_obj;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
165062306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
165162306a36Sopenharmony_ci		return -1;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	if (out_obj->package.count != 4)
165462306a36Sopenharmony_ci		return -1;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	input_report_abs(acer_wmi_accel_dev, ABS_X,
165762306a36Sopenharmony_ci		(s16)out_obj->package.elements[0].integer.value);
165862306a36Sopenharmony_ci	input_report_abs(acer_wmi_accel_dev, ABS_Y,
165962306a36Sopenharmony_ci		(s16)out_obj->package.elements[1].integer.value);
166062306a36Sopenharmony_ci	input_report_abs(acer_wmi_accel_dev, ABS_Z,
166162306a36Sopenharmony_ci		(s16)out_obj->package.elements[2].integer.value);
166262306a36Sopenharmony_ci	input_sync(acer_wmi_accel_dev);
166362306a36Sopenharmony_ci	return 0;
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci/*
166762306a36Sopenharmony_ci *  Predator series turbo button
166862306a36Sopenharmony_ci */
166962306a36Sopenharmony_cistatic int acer_toggle_turbo(void)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	u64 turbo_led_state;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	/* Get current state from turbo button */
167462306a36Sopenharmony_ci	if (ACPI_FAILURE(WMID_gaming_get_u64(&turbo_led_state, ACER_CAP_TURBO_LED)))
167562306a36Sopenharmony_ci		return -1;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (turbo_led_state) {
167862306a36Sopenharmony_ci		/* Turn off turbo led */
167962306a36Sopenharmony_ci		WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci		/* Set FAN mode to auto */
168262306a36Sopenharmony_ci		WMID_gaming_set_fan_mode(0x1);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		/* Set OC to normal */
168562306a36Sopenharmony_ci		WMID_gaming_set_u64(0x5, ACER_CAP_TURBO_OC);
168662306a36Sopenharmony_ci		WMID_gaming_set_u64(0x7, ACER_CAP_TURBO_OC);
168762306a36Sopenharmony_ci	} else {
168862306a36Sopenharmony_ci		/* Turn on turbo led */
168962306a36Sopenharmony_ci		WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci		/* Set FAN mode to turbo */
169262306a36Sopenharmony_ci		WMID_gaming_set_fan_mode(0x2);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci		/* Set OC to turbo mode */
169562306a36Sopenharmony_ci		WMID_gaming_set_u64(0x205, ACER_CAP_TURBO_OC);
169662306a36Sopenharmony_ci		WMID_gaming_set_u64(0x207, ACER_CAP_TURBO_OC);
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci	return turbo_led_state;
169962306a36Sopenharmony_ci}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci/*
170262306a36Sopenharmony_ci * Switch series keyboard dock status
170362306a36Sopenharmony_ci */
170462306a36Sopenharmony_cistatic int acer_kbd_dock_state_to_sw_tablet_mode(u8 kbd_dock_state)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	switch (kbd_dock_state) {
170762306a36Sopenharmony_ci	case 0x01: /* Docked, traditional clamshell laptop mode */
170862306a36Sopenharmony_ci		return 0;
170962306a36Sopenharmony_ci	case 0x04: /* Stand-alone tablet */
171062306a36Sopenharmony_ci	case 0x40: /* Docked, tent mode, keyboard not usable */
171162306a36Sopenharmony_ci		return 1;
171262306a36Sopenharmony_ci	default:
171362306a36Sopenharmony_ci		pr_warn("Unknown kbd_dock_state 0x%02x\n", kbd_dock_state);
171462306a36Sopenharmony_ci	}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	return 0;
171762306a36Sopenharmony_ci}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_cistatic void acer_kbd_dock_get_initial_state(void)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	u8 *output, input[8] = { 0x05, 0x00, };
172262306a36Sopenharmony_ci	struct acpi_buffer input_buf = { sizeof(input), input };
172362306a36Sopenharmony_ci	struct acpi_buffer output_buf = { ACPI_ALLOCATE_BUFFER, NULL };
172462306a36Sopenharmony_ci	union acpi_object *obj;
172562306a36Sopenharmony_ci	acpi_status status;
172662306a36Sopenharmony_ci	int sw_tablet_mode;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input_buf, &output_buf);
172962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
173062306a36Sopenharmony_ci		pr_err("Error getting keyboard-dock initial status: %s\n",
173162306a36Sopenharmony_ci		       acpi_format_exception(status));
173262306a36Sopenharmony_ci		return;
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	obj = output_buf.pointer;
173662306a36Sopenharmony_ci	if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
173762306a36Sopenharmony_ci		pr_err("Unexpected output format getting keyboard-dock initial status\n");
173862306a36Sopenharmony_ci		goto out_free_obj;
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	output = obj->buffer.pointer;
174262306a36Sopenharmony_ci	if (output[0] != 0x00 || (output[3] != 0x05 && output[3] != 0x45)) {
174362306a36Sopenharmony_ci		pr_err("Unexpected output [0]=0x%02x [3]=0x%02x getting keyboard-dock initial status\n",
174462306a36Sopenharmony_ci		       output[0], output[3]);
174562306a36Sopenharmony_ci		goto out_free_obj;
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(output[4]);
174962306a36Sopenharmony_ci	input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ciout_free_obj:
175262306a36Sopenharmony_ci	kfree(obj);
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_cistatic void acer_kbd_dock_event(const struct event_return_value *event)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	int sw_tablet_mode;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	if (!has_cap(ACER_CAP_KBD_DOCK))
176062306a36Sopenharmony_ci		return;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(event->kbd_dock_state);
176362306a36Sopenharmony_ci	input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
176462306a36Sopenharmony_ci	input_sync(acer_wmi_input_dev);
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci/*
176862306a36Sopenharmony_ci * Rfkill devices
176962306a36Sopenharmony_ci */
177062306a36Sopenharmony_cistatic void acer_rfkill_update(struct work_struct *ignored);
177162306a36Sopenharmony_cistatic DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
177262306a36Sopenharmony_cistatic void acer_rfkill_update(struct work_struct *ignored)
177362306a36Sopenharmony_ci{
177462306a36Sopenharmony_ci	u32 state;
177562306a36Sopenharmony_ci	acpi_status status;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
177862306a36Sopenharmony_ci		status = get_u32(&state, ACER_CAP_WIRELESS);
177962306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
178062306a36Sopenharmony_ci			if (quirks->wireless == 3)
178162306a36Sopenharmony_ci				rfkill_set_hw_state(wireless_rfkill, !state);
178262306a36Sopenharmony_ci			else
178362306a36Sopenharmony_ci				rfkill_set_sw_state(wireless_rfkill, !state);
178462306a36Sopenharmony_ci		}
178562306a36Sopenharmony_ci	}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
178862306a36Sopenharmony_ci		status = get_u32(&state, ACER_CAP_BLUETOOTH);
178962306a36Sopenharmony_ci		if (ACPI_SUCCESS(status))
179062306a36Sopenharmony_ci			rfkill_set_sw_state(bluetooth_rfkill, !state);
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
179462306a36Sopenharmony_ci		status = get_u32(&state, ACER_WMID3_GDS_THREEG);
179562306a36Sopenharmony_ci		if (ACPI_SUCCESS(status))
179662306a36Sopenharmony_ci			rfkill_set_sw_state(threeg_rfkill, !state);
179762306a36Sopenharmony_ci	}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cistatic int acer_rfkill_set(void *data, bool blocked)
180362306a36Sopenharmony_ci{
180462306a36Sopenharmony_ci	acpi_status status;
180562306a36Sopenharmony_ci	u32 cap = (unsigned long)data;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (rfkill_inited) {
180862306a36Sopenharmony_ci		status = set_u32(!blocked, cap);
180962306a36Sopenharmony_ci		if (ACPI_FAILURE(status))
181062306a36Sopenharmony_ci			return -ENODEV;
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	return 0;
181462306a36Sopenharmony_ci}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_cistatic const struct rfkill_ops acer_rfkill_ops = {
181762306a36Sopenharmony_ci	.set_block = acer_rfkill_set,
181862306a36Sopenharmony_ci};
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cistatic struct rfkill *acer_rfkill_register(struct device *dev,
182162306a36Sopenharmony_ci					   enum rfkill_type type,
182262306a36Sopenharmony_ci					   char *name, u32 cap)
182362306a36Sopenharmony_ci{
182462306a36Sopenharmony_ci	int err;
182562306a36Sopenharmony_ci	struct rfkill *rfkill_dev;
182662306a36Sopenharmony_ci	u32 state;
182762306a36Sopenharmony_ci	acpi_status status;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	rfkill_dev = rfkill_alloc(name, dev, type,
183062306a36Sopenharmony_ci				  &acer_rfkill_ops,
183162306a36Sopenharmony_ci				  (void *)(unsigned long)cap);
183262306a36Sopenharmony_ci	if (!rfkill_dev)
183362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	status = get_u32(&state, cap);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	err = rfkill_register(rfkill_dev);
183862306a36Sopenharmony_ci	if (err) {
183962306a36Sopenharmony_ci		rfkill_destroy(rfkill_dev);
184062306a36Sopenharmony_ci		return ERR_PTR(err);
184162306a36Sopenharmony_ci	}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	if (ACPI_SUCCESS(status))
184462306a36Sopenharmony_ci		rfkill_set_sw_state(rfkill_dev, !state);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	return rfkill_dev;
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_cistatic int acer_rfkill_init(struct device *dev)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	int err;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
185462306a36Sopenharmony_ci		wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
185562306a36Sopenharmony_ci			"acer-wireless", ACER_CAP_WIRELESS);
185662306a36Sopenharmony_ci		if (IS_ERR(wireless_rfkill)) {
185762306a36Sopenharmony_ci			err = PTR_ERR(wireless_rfkill);
185862306a36Sopenharmony_ci			goto error_wireless;
185962306a36Sopenharmony_ci		}
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
186362306a36Sopenharmony_ci		bluetooth_rfkill = acer_rfkill_register(dev,
186462306a36Sopenharmony_ci			RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
186562306a36Sopenharmony_ci			ACER_CAP_BLUETOOTH);
186662306a36Sopenharmony_ci		if (IS_ERR(bluetooth_rfkill)) {
186762306a36Sopenharmony_ci			err = PTR_ERR(bluetooth_rfkill);
186862306a36Sopenharmony_ci			goto error_bluetooth;
186962306a36Sopenharmony_ci		}
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	if (has_cap(ACER_CAP_THREEG)) {
187362306a36Sopenharmony_ci		threeg_rfkill = acer_rfkill_register(dev,
187462306a36Sopenharmony_ci			RFKILL_TYPE_WWAN, "acer-threeg",
187562306a36Sopenharmony_ci			ACER_CAP_THREEG);
187662306a36Sopenharmony_ci		if (IS_ERR(threeg_rfkill)) {
187762306a36Sopenharmony_ci			err = PTR_ERR(threeg_rfkill);
187862306a36Sopenharmony_ci			goto error_threeg;
187962306a36Sopenharmony_ci		}
188062306a36Sopenharmony_ci	}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	rfkill_inited = true;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
188562306a36Sopenharmony_ci	    has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
188662306a36Sopenharmony_ci		schedule_delayed_work(&acer_rfkill_work,
188762306a36Sopenharmony_ci			round_jiffies_relative(HZ));
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	return 0;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_cierror_threeg:
189262306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
189362306a36Sopenharmony_ci		rfkill_unregister(bluetooth_rfkill);
189462306a36Sopenharmony_ci		rfkill_destroy(bluetooth_rfkill);
189562306a36Sopenharmony_ci	}
189662306a36Sopenharmony_cierror_bluetooth:
189762306a36Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
189862306a36Sopenharmony_ci		rfkill_unregister(wireless_rfkill);
189962306a36Sopenharmony_ci		rfkill_destroy(wireless_rfkill);
190062306a36Sopenharmony_ci	}
190162306a36Sopenharmony_cierror_wireless:
190262306a36Sopenharmony_ci	return err;
190362306a36Sopenharmony_ci}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_cistatic void acer_rfkill_exit(void)
190662306a36Sopenharmony_ci{
190762306a36Sopenharmony_ci	if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
190862306a36Sopenharmony_ci	    has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
190962306a36Sopenharmony_ci		cancel_delayed_work_sync(&acer_rfkill_work);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	if (has_cap(ACER_CAP_WIRELESS)) {
191262306a36Sopenharmony_ci		rfkill_unregister(wireless_rfkill);
191362306a36Sopenharmony_ci		rfkill_destroy(wireless_rfkill);
191462306a36Sopenharmony_ci	}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BLUETOOTH)) {
191762306a36Sopenharmony_ci		rfkill_unregister(bluetooth_rfkill);
191862306a36Sopenharmony_ci		rfkill_destroy(bluetooth_rfkill);
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	if (has_cap(ACER_CAP_THREEG)) {
192262306a36Sopenharmony_ci		rfkill_unregister(threeg_rfkill);
192362306a36Sopenharmony_ci		rfkill_destroy(threeg_rfkill);
192462306a36Sopenharmony_ci	}
192562306a36Sopenharmony_ci	return;
192662306a36Sopenharmony_ci}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_cistatic void acer_wmi_notify(u32 value, void *context)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
193162306a36Sopenharmony_ci	union acpi_object *obj;
193262306a36Sopenharmony_ci	struct event_return_value return_value;
193362306a36Sopenharmony_ci	acpi_status status;
193462306a36Sopenharmony_ci	u16 device_state;
193562306a36Sopenharmony_ci	const struct key_entry *key;
193662306a36Sopenharmony_ci	u32 scancode;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	status = wmi_get_event_data(value, &response);
193962306a36Sopenharmony_ci	if (status != AE_OK) {
194062306a36Sopenharmony_ci		pr_warn("bad event status 0x%x\n", status);
194162306a36Sopenharmony_ci		return;
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	obj = (union acpi_object *)response.pointer;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	if (!obj)
194762306a36Sopenharmony_ci		return;
194862306a36Sopenharmony_ci	if (obj->type != ACPI_TYPE_BUFFER) {
194962306a36Sopenharmony_ci		pr_warn("Unknown response received %d\n", obj->type);
195062306a36Sopenharmony_ci		kfree(obj);
195162306a36Sopenharmony_ci		return;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_ci	if (obj->buffer.length != 8) {
195462306a36Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
195562306a36Sopenharmony_ci		kfree(obj);
195662306a36Sopenharmony_ci		return;
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	return_value = *((struct event_return_value *)obj->buffer.pointer);
196062306a36Sopenharmony_ci	kfree(obj);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	switch (return_value.function) {
196362306a36Sopenharmony_ci	case WMID_HOTKEY_EVENT:
196462306a36Sopenharmony_ci		device_state = return_value.device_state;
196562306a36Sopenharmony_ci		pr_debug("device state: 0x%x\n", device_state);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci		key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
196862306a36Sopenharmony_ci							return_value.key_num);
196962306a36Sopenharmony_ci		if (!key) {
197062306a36Sopenharmony_ci			pr_warn("Unknown key number - 0x%x\n",
197162306a36Sopenharmony_ci				return_value.key_num);
197262306a36Sopenharmony_ci		} else {
197362306a36Sopenharmony_ci			scancode = return_value.key_num;
197462306a36Sopenharmony_ci			switch (key->keycode) {
197562306a36Sopenharmony_ci			case KEY_WLAN:
197662306a36Sopenharmony_ci			case KEY_BLUETOOTH:
197762306a36Sopenharmony_ci				if (has_cap(ACER_CAP_WIRELESS))
197862306a36Sopenharmony_ci					rfkill_set_sw_state(wireless_rfkill,
197962306a36Sopenharmony_ci						!(device_state & ACER_WMID3_GDS_WIRELESS));
198062306a36Sopenharmony_ci				if (has_cap(ACER_CAP_THREEG))
198162306a36Sopenharmony_ci					rfkill_set_sw_state(threeg_rfkill,
198262306a36Sopenharmony_ci						!(device_state & ACER_WMID3_GDS_THREEG));
198362306a36Sopenharmony_ci				if (has_cap(ACER_CAP_BLUETOOTH))
198462306a36Sopenharmony_ci					rfkill_set_sw_state(bluetooth_rfkill,
198562306a36Sopenharmony_ci						!(device_state & ACER_WMID3_GDS_BLUETOOTH));
198662306a36Sopenharmony_ci				break;
198762306a36Sopenharmony_ci			case KEY_TOUCHPAD_TOGGLE:
198862306a36Sopenharmony_ci				scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ?
198962306a36Sopenharmony_ci						KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF;
199062306a36Sopenharmony_ci			}
199162306a36Sopenharmony_ci			sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
199262306a36Sopenharmony_ci		}
199362306a36Sopenharmony_ci		break;
199462306a36Sopenharmony_ci	case WMID_ACCEL_OR_KBD_DOCK_EVENT:
199562306a36Sopenharmony_ci		acer_gsensor_event();
199662306a36Sopenharmony_ci		acer_kbd_dock_event(&return_value);
199762306a36Sopenharmony_ci		break;
199862306a36Sopenharmony_ci	case WMID_GAMING_TURBO_KEY_EVENT:
199962306a36Sopenharmony_ci		if (return_value.key_num == 0x4)
200062306a36Sopenharmony_ci			acer_toggle_turbo();
200162306a36Sopenharmony_ci		break;
200262306a36Sopenharmony_ci	default:
200362306a36Sopenharmony_ci		pr_warn("Unknown function number - %d - %d\n",
200462306a36Sopenharmony_ci			return_value.function, return_value.key_num);
200562306a36Sopenharmony_ci		break;
200662306a36Sopenharmony_ci	}
200762306a36Sopenharmony_ci}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_cistatic acpi_status __init
201062306a36Sopenharmony_ciwmid3_set_function_mode(struct func_input_params *params,
201162306a36Sopenharmony_ci			struct func_return_value *return_value)
201262306a36Sopenharmony_ci{
201362306a36Sopenharmony_ci	acpi_status status;
201462306a36Sopenharmony_ci	union acpi_object *obj;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	struct acpi_buffer input = { sizeof(struct func_input_params), params };
201762306a36Sopenharmony_ci	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
202062306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
202162306a36Sopenharmony_ci		return status;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	obj = output.pointer;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	if (!obj)
202662306a36Sopenharmony_ci		return AE_ERROR;
202762306a36Sopenharmony_ci	else if (obj->type != ACPI_TYPE_BUFFER) {
202862306a36Sopenharmony_ci		kfree(obj);
202962306a36Sopenharmony_ci		return AE_ERROR;
203062306a36Sopenharmony_ci	}
203162306a36Sopenharmony_ci	if (obj->buffer.length != 4) {
203262306a36Sopenharmony_ci		pr_warn("Unknown buffer length %d\n", obj->buffer.length);
203362306a36Sopenharmony_ci		kfree(obj);
203462306a36Sopenharmony_ci		return AE_ERROR;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	*return_value = *((struct func_return_value *)obj->buffer.pointer);
203862306a36Sopenharmony_ci	kfree(obj);
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	return status;
204162306a36Sopenharmony_ci}
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_cistatic int __init acer_wmi_enable_ec_raw(void)
204462306a36Sopenharmony_ci{
204562306a36Sopenharmony_ci	struct func_return_value return_value;
204662306a36Sopenharmony_ci	acpi_status status;
204762306a36Sopenharmony_ci	struct func_input_params params = {
204862306a36Sopenharmony_ci		.function_num = 0x1,
204962306a36Sopenharmony_ci		.commun_devices = 0xFFFF,
205062306a36Sopenharmony_ci		.devices = 0xFFFF,
205162306a36Sopenharmony_ci		.app_status = 0x00,		/* Launch Manager Deactive */
205262306a36Sopenharmony_ci		.app_mask = 0x01,
205362306a36Sopenharmony_ci	};
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	status = wmid3_set_function_mode(&params, &return_value);
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
205862306a36Sopenharmony_ci		pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
205962306a36Sopenharmony_ci			return_value.error_code,
206062306a36Sopenharmony_ci			return_value.ec_return_value);
206162306a36Sopenharmony_ci	else
206262306a36Sopenharmony_ci		pr_info("Enabled EC raw mode\n");
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	return status;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_cistatic int __init acer_wmi_enable_lm(void)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	struct func_return_value return_value;
207062306a36Sopenharmony_ci	acpi_status status;
207162306a36Sopenharmony_ci	struct func_input_params params = {
207262306a36Sopenharmony_ci		.function_num = 0x1,
207362306a36Sopenharmony_ci		.commun_devices = 0xFFFF,
207462306a36Sopenharmony_ci		.devices = 0xFFFF,
207562306a36Sopenharmony_ci		.app_status = 0x01,            /* Launch Manager Active */
207662306a36Sopenharmony_ci		.app_mask = 0x01,
207762306a36Sopenharmony_ci	};
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	status = wmid3_set_function_mode(&params, &return_value);
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
208262306a36Sopenharmony_ci		pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
208362306a36Sopenharmony_ci			return_value.error_code,
208462306a36Sopenharmony_ci			return_value.ec_return_value);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	return status;
208762306a36Sopenharmony_ci}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cistatic int __init acer_wmi_enable_rf_button(void)
209062306a36Sopenharmony_ci{
209162306a36Sopenharmony_ci	struct func_return_value return_value;
209262306a36Sopenharmony_ci	acpi_status status;
209362306a36Sopenharmony_ci	struct func_input_params params = {
209462306a36Sopenharmony_ci		.function_num = 0x1,
209562306a36Sopenharmony_ci		.commun_devices = 0xFFFF,
209662306a36Sopenharmony_ci		.devices = 0xFFFF,
209762306a36Sopenharmony_ci		.app_status = 0x10,            /* RF Button Active */
209862306a36Sopenharmony_ci		.app_mask = 0x10,
209962306a36Sopenharmony_ci	};
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	status = wmid3_set_function_mode(&params, &return_value);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	if (return_value.error_code || return_value.ec_return_value)
210462306a36Sopenharmony_ci		pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n",
210562306a36Sopenharmony_ci			return_value.error_code,
210662306a36Sopenharmony_ci			return_value.ec_return_value);
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	return status;
210962306a36Sopenharmony_ci}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_cistatic int __init acer_wmi_accel_setup(void)
211262306a36Sopenharmony_ci{
211362306a36Sopenharmony_ci	struct acpi_device *adev;
211462306a36Sopenharmony_ci	int err;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	adev = acpi_dev_get_first_match_dev("BST0001", NULL, -1);
211762306a36Sopenharmony_ci	if (!adev)
211862306a36Sopenharmony_ci		return -ENODEV;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	gsensor_handle = acpi_device_handle(adev);
212162306a36Sopenharmony_ci	acpi_dev_put(adev);
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	acer_wmi_accel_dev = input_allocate_device();
212462306a36Sopenharmony_ci	if (!acer_wmi_accel_dev)
212562306a36Sopenharmony_ci		return -ENOMEM;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	acer_wmi_accel_dev->open = acer_gsensor_open;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
213062306a36Sopenharmony_ci	acer_wmi_accel_dev->phys = "wmi/input1";
213162306a36Sopenharmony_ci	acer_wmi_accel_dev->id.bustype = BUS_HOST;
213262306a36Sopenharmony_ci	acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
213362306a36Sopenharmony_ci	input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
213462306a36Sopenharmony_ci	input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
213562306a36Sopenharmony_ci	input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	err = input_register_device(acer_wmi_accel_dev);
213862306a36Sopenharmony_ci	if (err)
213962306a36Sopenharmony_ci		goto err_free_dev;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	return 0;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_cierr_free_dev:
214462306a36Sopenharmony_ci	input_free_device(acer_wmi_accel_dev);
214562306a36Sopenharmony_ci	return err;
214662306a36Sopenharmony_ci}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_cistatic int __init acer_wmi_input_setup(void)
214962306a36Sopenharmony_ci{
215062306a36Sopenharmony_ci	acpi_status status;
215162306a36Sopenharmony_ci	int err;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	acer_wmi_input_dev = input_allocate_device();
215462306a36Sopenharmony_ci	if (!acer_wmi_input_dev)
215562306a36Sopenharmony_ci		return -ENOMEM;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	acer_wmi_input_dev->name = "Acer WMI hotkeys";
215862306a36Sopenharmony_ci	acer_wmi_input_dev->phys = "wmi/input0";
215962306a36Sopenharmony_ci	acer_wmi_input_dev->id.bustype = BUS_HOST;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
216262306a36Sopenharmony_ci	if (err)
216362306a36Sopenharmony_ci		goto err_free_dev;
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	if (has_cap(ACER_CAP_KBD_DOCK))
216662306a36Sopenharmony_ci		input_set_capability(acer_wmi_input_dev, EV_SW, SW_TABLET_MODE);
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
216962306a36Sopenharmony_ci						acer_wmi_notify, NULL);
217062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
217162306a36Sopenharmony_ci		err = -EIO;
217262306a36Sopenharmony_ci		goto err_free_dev;
217362306a36Sopenharmony_ci	}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	if (has_cap(ACER_CAP_KBD_DOCK))
217662306a36Sopenharmony_ci		acer_kbd_dock_get_initial_state();
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	err = input_register_device(acer_wmi_input_dev);
217962306a36Sopenharmony_ci	if (err)
218062306a36Sopenharmony_ci		goto err_uninstall_notifier;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	return 0;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_cierr_uninstall_notifier:
218562306a36Sopenharmony_ci	wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
218662306a36Sopenharmony_cierr_free_dev:
218762306a36Sopenharmony_ci	input_free_device(acer_wmi_input_dev);
218862306a36Sopenharmony_ci	return err;
218962306a36Sopenharmony_ci}
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_cistatic void acer_wmi_input_destroy(void)
219262306a36Sopenharmony_ci{
219362306a36Sopenharmony_ci	wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
219462306a36Sopenharmony_ci	input_unregister_device(acer_wmi_input_dev);
219562306a36Sopenharmony_ci}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci/*
219862306a36Sopenharmony_ci * debugfs functions
219962306a36Sopenharmony_ci */
220062306a36Sopenharmony_cistatic u32 get_wmid_devices(void)
220162306a36Sopenharmony_ci{
220262306a36Sopenharmony_ci	struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
220362306a36Sopenharmony_ci	union acpi_object *obj;
220462306a36Sopenharmony_ci	acpi_status status;
220562306a36Sopenharmony_ci	u32 devices = 0;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	status = wmi_query_block(WMID_GUID2, 0, &out);
220862306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
220962306a36Sopenharmony_ci		return 0;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	obj = (union acpi_object *) out.pointer;
221262306a36Sopenharmony_ci	if (obj) {
221362306a36Sopenharmony_ci		if (obj->type == ACPI_TYPE_BUFFER &&
221462306a36Sopenharmony_ci			(obj->buffer.length == sizeof(u32) ||
221562306a36Sopenharmony_ci			obj->buffer.length == sizeof(u64))) {
221662306a36Sopenharmony_ci			devices = *((u32 *) obj->buffer.pointer);
221762306a36Sopenharmony_ci		} else if (obj->type == ACPI_TYPE_INTEGER) {
221862306a36Sopenharmony_ci			devices = (u32) obj->integer.value;
221962306a36Sopenharmony_ci		}
222062306a36Sopenharmony_ci	}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	kfree(out.pointer);
222362306a36Sopenharmony_ci	return devices;
222462306a36Sopenharmony_ci}
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci/*
222762306a36Sopenharmony_ci * Platform device
222862306a36Sopenharmony_ci */
222962306a36Sopenharmony_cistatic int acer_platform_probe(struct platform_device *device)
223062306a36Sopenharmony_ci{
223162306a36Sopenharmony_ci	int err;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED)) {
223462306a36Sopenharmony_ci		err = acer_led_init(&device->dev);
223562306a36Sopenharmony_ci		if (err)
223662306a36Sopenharmony_ci			goto error_mailled;
223762306a36Sopenharmony_ci	}
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS)) {
224062306a36Sopenharmony_ci		err = acer_backlight_init(&device->dev);
224162306a36Sopenharmony_ci		if (err)
224262306a36Sopenharmony_ci			goto error_brightness;
224362306a36Sopenharmony_ci	}
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	err = acer_rfkill_init(&device->dev);
224662306a36Sopenharmony_ci	if (err)
224762306a36Sopenharmony_ci		goto error_rfkill;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	return err;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_cierror_rfkill:
225262306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS))
225362306a36Sopenharmony_ci		acer_backlight_exit();
225462306a36Sopenharmony_cierror_brightness:
225562306a36Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
225662306a36Sopenharmony_ci		acer_led_exit();
225762306a36Sopenharmony_cierror_mailled:
225862306a36Sopenharmony_ci	return err;
225962306a36Sopenharmony_ci}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_cistatic void acer_platform_remove(struct platform_device *device)
226262306a36Sopenharmony_ci{
226362306a36Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
226462306a36Sopenharmony_ci		acer_led_exit();
226562306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS))
226662306a36Sopenharmony_ci		acer_backlight_exit();
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	acer_rfkill_exit();
226962306a36Sopenharmony_ci}
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
227262306a36Sopenharmony_cistatic int acer_suspend(struct device *dev)
227362306a36Sopenharmony_ci{
227462306a36Sopenharmony_ci	u32 value;
227562306a36Sopenharmony_ci	struct acer_data *data = &interface->data;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	if (!data)
227862306a36Sopenharmony_ci		return -ENOMEM;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED)) {
228162306a36Sopenharmony_ci		get_u32(&value, ACER_CAP_MAILLED);
228262306a36Sopenharmony_ci		set_u32(LED_OFF, ACER_CAP_MAILLED);
228362306a36Sopenharmony_ci		data->mailled = value;
228462306a36Sopenharmony_ci	}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS)) {
228762306a36Sopenharmony_ci		get_u32(&value, ACER_CAP_BRIGHTNESS);
228862306a36Sopenharmony_ci		data->brightness = value;
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	return 0;
229262306a36Sopenharmony_ci}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_cistatic int acer_resume(struct device *dev)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	struct acer_data *data = &interface->data;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	if (!data)
229962306a36Sopenharmony_ci		return -ENOMEM;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
230262306a36Sopenharmony_ci		set_u32(data->mailled, ACER_CAP_MAILLED);
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	if (has_cap(ACER_CAP_BRIGHTNESS))
230562306a36Sopenharmony_ci		set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	if (acer_wmi_accel_dev)
230862306a36Sopenharmony_ci		acer_gsensor_init();
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	return 0;
231162306a36Sopenharmony_ci}
231262306a36Sopenharmony_ci#else
231362306a36Sopenharmony_ci#define acer_suspend	NULL
231462306a36Sopenharmony_ci#define acer_resume	NULL
231562306a36Sopenharmony_ci#endif
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_cistatic void acer_platform_shutdown(struct platform_device *device)
232062306a36Sopenharmony_ci{
232162306a36Sopenharmony_ci	struct acer_data *data = &interface->data;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	if (!data)
232462306a36Sopenharmony_ci		return;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	if (has_cap(ACER_CAP_MAILLED))
232762306a36Sopenharmony_ci		set_u32(LED_OFF, ACER_CAP_MAILLED);
232862306a36Sopenharmony_ci}
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_cistatic struct platform_driver acer_platform_driver = {
233162306a36Sopenharmony_ci	.driver = {
233262306a36Sopenharmony_ci		.name = "acer-wmi",
233362306a36Sopenharmony_ci		.pm = &acer_pm,
233462306a36Sopenharmony_ci	},
233562306a36Sopenharmony_ci	.probe = acer_platform_probe,
233662306a36Sopenharmony_ci	.remove_new = acer_platform_remove,
233762306a36Sopenharmony_ci	.shutdown = acer_platform_shutdown,
233862306a36Sopenharmony_ci};
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_cistatic struct platform_device *acer_platform_device;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_cistatic void remove_debugfs(void)
234362306a36Sopenharmony_ci{
234462306a36Sopenharmony_ci	debugfs_remove_recursive(interface->debug.root);
234562306a36Sopenharmony_ci}
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_cistatic void __init create_debugfs(void)
234862306a36Sopenharmony_ci{
234962306a36Sopenharmony_ci	interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	debugfs_create_u32("devices", S_IRUGO, interface->debug.root,
235262306a36Sopenharmony_ci			   &interface->debug.wmid_devices);
235362306a36Sopenharmony_ci}
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_cistatic int __init acer_wmi_init(void)
235662306a36Sopenharmony_ci{
235762306a36Sopenharmony_ci	int err;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	pr_info("Acer Laptop ACPI-WMI Extras\n");
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	if (dmi_check_system(acer_blacklist)) {
236262306a36Sopenharmony_ci		pr_info("Blacklisted hardware detected - not loading\n");
236362306a36Sopenharmony_ci		return -ENODEV;
236462306a36Sopenharmony_ci	}
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	find_quirks();
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	/*
236962306a36Sopenharmony_ci	 * The AMW0_GUID1 wmi is not only found on Acer family but also other
237062306a36Sopenharmony_ci	 * machines like Lenovo, Fujitsu and Medion. In the past days,
237162306a36Sopenharmony_ci	 * acer-wmi driver handled those non-Acer machines by quirks list.
237262306a36Sopenharmony_ci	 * But actually acer-wmi driver was loaded on any machines that have
237362306a36Sopenharmony_ci	 * AMW0_GUID1. This behavior is strange because those machines should
237462306a36Sopenharmony_ci	 * be supported by appropriate wmi drivers. e.g. fujitsu-laptop,
237562306a36Sopenharmony_ci	 * ideapad-laptop. So, here checks the machine that has AMW0_GUID1
237662306a36Sopenharmony_ci	 * should be in Acer/Gateway/Packard Bell white list, or it's already
237762306a36Sopenharmony_ci	 * in the past quirk list.
237862306a36Sopenharmony_ci	 */
237962306a36Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1) &&
238062306a36Sopenharmony_ci	    !dmi_check_system(amw0_whitelist) &&
238162306a36Sopenharmony_ci	    quirks == &quirk_unknown) {
238262306a36Sopenharmony_ci		pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n");
238362306a36Sopenharmony_ci		return -ENODEV;
238462306a36Sopenharmony_ci	}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	/*
238762306a36Sopenharmony_ci	 * Detect which ACPI-WMI interface we're using.
238862306a36Sopenharmony_ci	 */
238962306a36Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
239062306a36Sopenharmony_ci		interface = &AMW0_V2_interface;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
239362306a36Sopenharmony_ci		interface = &wmid_interface;
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	if (wmi_has_guid(WMID_GUID3))
239662306a36Sopenharmony_ci		interface = &wmid_v2_interface;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (interface)
239962306a36Sopenharmony_ci		dmi_walk(type_aa_dmi_decode, NULL);
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	if (wmi_has_guid(WMID_GUID2) && interface) {
240262306a36Sopenharmony_ci		if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
240362306a36Sopenharmony_ci			pr_err("Unable to detect available WMID devices\n");
240462306a36Sopenharmony_ci			return -ENODEV;
240562306a36Sopenharmony_ci		}
240662306a36Sopenharmony_ci		/* WMID always provides brightness methods */
240762306a36Sopenharmony_ci		interface->capability |= ACER_CAP_BRIGHTNESS;
240862306a36Sopenharmony_ci	} else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa && force_caps == -1) {
240962306a36Sopenharmony_ci		pr_err("No WMID device detection method found\n");
241062306a36Sopenharmony_ci		return -ENODEV;
241162306a36Sopenharmony_ci	}
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
241462306a36Sopenharmony_ci		interface = &AMW0_interface;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci		if (ACPI_FAILURE(AMW0_set_capabilities())) {
241762306a36Sopenharmony_ci			pr_err("Unable to detect available AMW0 devices\n");
241862306a36Sopenharmony_ci			return -ENODEV;
241962306a36Sopenharmony_ci		}
242062306a36Sopenharmony_ci	}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	if (wmi_has_guid(AMW0_GUID1))
242362306a36Sopenharmony_ci		AMW0_find_mailled();
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	if (!interface) {
242662306a36Sopenharmony_ci		pr_err("No or unsupported WMI interface, unable to load\n");
242762306a36Sopenharmony_ci		return -ENODEV;
242862306a36Sopenharmony_ci	}
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	set_quirks();
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
243362306a36Sopenharmony_ci		interface->capability &= ~ACER_CAP_BRIGHTNESS;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	if (wmi_has_guid(WMID_GUID3))
243662306a36Sopenharmony_ci		interface->capability |= ACER_CAP_SET_FUNCTION_MODE;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	if (force_caps != -1)
243962306a36Sopenharmony_ci		interface->capability = force_caps;
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	if (wmi_has_guid(WMID_GUID3) &&
244262306a36Sopenharmony_ci	    (interface->capability & ACER_CAP_SET_FUNCTION_MODE)) {
244362306a36Sopenharmony_ci		if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
244462306a36Sopenharmony_ci			pr_warn("Cannot enable RF Button Driver\n");
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci		if (ec_raw_mode) {
244762306a36Sopenharmony_ci			if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
244862306a36Sopenharmony_ci				pr_err("Cannot enable EC raw mode\n");
244962306a36Sopenharmony_ci				return -ENODEV;
245062306a36Sopenharmony_ci			}
245162306a36Sopenharmony_ci		} else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
245262306a36Sopenharmony_ci			pr_err("Cannot enable Launch Manager mode\n");
245362306a36Sopenharmony_ci			return -ENODEV;
245462306a36Sopenharmony_ci		}
245562306a36Sopenharmony_ci	} else if (ec_raw_mode) {
245662306a36Sopenharmony_ci		pr_info("No WMID EC raw mode enable method\n");
245762306a36Sopenharmony_ci	}
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
246062306a36Sopenharmony_ci		err = acer_wmi_input_setup();
246162306a36Sopenharmony_ci		if (err)
246262306a36Sopenharmony_ci			return err;
246362306a36Sopenharmony_ci		err = acer_wmi_accel_setup();
246462306a36Sopenharmony_ci		if (err && err != -ENODEV)
246562306a36Sopenharmony_ci			pr_warn("Cannot enable accelerometer\n");
246662306a36Sopenharmony_ci	}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	err = platform_driver_register(&acer_platform_driver);
246962306a36Sopenharmony_ci	if (err) {
247062306a36Sopenharmony_ci		pr_err("Unable to register platform driver\n");
247162306a36Sopenharmony_ci		goto error_platform_register;
247262306a36Sopenharmony_ci	}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	acer_platform_device = platform_device_alloc("acer-wmi", PLATFORM_DEVID_NONE);
247562306a36Sopenharmony_ci	if (!acer_platform_device) {
247662306a36Sopenharmony_ci		err = -ENOMEM;
247762306a36Sopenharmony_ci		goto error_device_alloc;
247862306a36Sopenharmony_ci	}
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	err = platform_device_add(acer_platform_device);
248162306a36Sopenharmony_ci	if (err)
248262306a36Sopenharmony_ci		goto error_device_add;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	if (wmi_has_guid(WMID_GUID2)) {
248562306a36Sopenharmony_ci		interface->debug.wmid_devices = get_wmid_devices();
248662306a36Sopenharmony_ci		create_debugfs();
248762306a36Sopenharmony_ci	}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	/* Override any initial settings with values from the commandline */
249062306a36Sopenharmony_ci	acer_commandline_init();
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	return 0;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_cierror_device_add:
249562306a36Sopenharmony_ci	platform_device_put(acer_platform_device);
249662306a36Sopenharmony_cierror_device_alloc:
249762306a36Sopenharmony_ci	platform_driver_unregister(&acer_platform_driver);
249862306a36Sopenharmony_cierror_platform_register:
249962306a36Sopenharmony_ci	if (wmi_has_guid(ACERWMID_EVENT_GUID))
250062306a36Sopenharmony_ci		acer_wmi_input_destroy();
250162306a36Sopenharmony_ci	if (acer_wmi_accel_dev)
250262306a36Sopenharmony_ci		input_unregister_device(acer_wmi_accel_dev);
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	return err;
250562306a36Sopenharmony_ci}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_cistatic void __exit acer_wmi_exit(void)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci	if (wmi_has_guid(ACERWMID_EVENT_GUID))
251062306a36Sopenharmony_ci		acer_wmi_input_destroy();
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	if (acer_wmi_accel_dev)
251362306a36Sopenharmony_ci		input_unregister_device(acer_wmi_accel_dev);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	remove_debugfs();
251662306a36Sopenharmony_ci	platform_device_unregister(acer_platform_device);
251762306a36Sopenharmony_ci	platform_driver_unregister(&acer_platform_driver);
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	pr_info("Acer Laptop WMI Extras unloaded\n");
252062306a36Sopenharmony_ci	return;
252162306a36Sopenharmony_ci}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_cimodule_init(acer_wmi_init);
252462306a36Sopenharmony_cimodule_exit(acer_wmi_exit);
2525