blob: 694b45ed06a217b604c708a5039c0f238d8441cd [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002/*
3 * Acer WMI Laptop Extras
4 *
Carlos Corbacho4f0175d2009-04-04 09:33:39 +01005 * Copyright (C) 2007-2009 Carlos Corbacho <carlos@strangeworlds.co.uk>
Carlos Corbacho745a5d22008-02-05 02:17:10 +00006 *
7 * Based on acer_acpi:
8 * Copyright (C) 2005-2007 E.M. Smith
9 * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com>
Carlos Corbacho745a5d22008-02-05 02:17:10 +000010 */
11
Lee, Chun-Yicae15702011-03-16 18:52:36 +080012#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
Carlos Corbacho745a5d22008-02-05 02:17:10 +000014#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/types.h>
18#include <linux/dmi.h>
Carlos Corbachof2b585b2008-06-21 09:09:27 +010019#include <linux/fb.h>
Carlos Corbacho745a5d22008-02-05 02:17:10 +000020#include <linux/backlight.h>
21#include <linux/leds.h>
22#include <linux/platform_device.h>
23#include <linux/acpi.h>
24#include <linux/i8042.h>
Carlos Corbacho0606e1a2008-10-08 21:40:21 +010025#include <linux/rfkill.h>
26#include <linux/workqueue.h>
Carlos Corbacho81143522008-06-21 09:09:53 +010027#include <linux/debugfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +080029#include <linux/input.h>
30#include <linux/input/sparse-keymap.h>
Lee, Chun-Yi86924de2012-03-26 15:47:58 -040031#include <acpi/video.h>
Carlos Corbacho745a5d22008-02-05 02:17:10 +000032
33MODULE_AUTHOR("Carlos Corbacho");
34MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
35MODULE_LICENSE("GPL");
36
Carlos Corbacho745a5d22008-02-05 02:17:10 +000037/*
Carlos Corbacho745a5d22008-02-05 02:17:10 +000038 * Magic Number
39 * Meaning is unknown - this number is required for writing to ACPI for AMW0
40 * (it's also used in acerhk when directly accessing the BIOS)
41 */
42#define ACER_AMW0_WRITE 0x9610
43
44/*
45 * Bit masks for the AMW0 interface
46 */
47#define ACER_AMW0_WIRELESS_MASK 0x35
48#define ACER_AMW0_BLUETOOTH_MASK 0x34
49#define ACER_AMW0_MAILLED_MASK 0x31
50
51/*
52 * Method IDs for WMID interface
53 */
54#define ACER_WMID_GET_WIRELESS_METHODID 1
55#define ACER_WMID_GET_BLUETOOTH_METHODID 2
56#define ACER_WMID_GET_BRIGHTNESS_METHODID 3
57#define ACER_WMID_SET_WIRELESS_METHODID 4
58#define ACER_WMID_SET_BLUETOOTH_METHODID 5
59#define ACER_WMID_SET_BRIGHTNESS_METHODID 6
60#define ACER_WMID_GET_THREEG_METHODID 10
61#define ACER_WMID_SET_THREEG_METHODID 11
62
JafarAkhondalica42c112021-08-12 17:23:07 +043063#define ACER_WMID_SET_GAMING_LED_METHODID 2
64#define ACER_WMID_GET_GAMING_LED_METHODID 4
65#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14
66#define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22
67
Carlos Corbacho745a5d22008-02-05 02:17:10 +000068/*
69 * Acer ACPI method GUIDs
70 */
71#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
Carlos Corbacho5753dd52008-06-21 09:09:48 +010072#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
Matthew Garrettbbb70602011-02-09 16:39:40 -050073#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
Pali Rohár298f19b2011-03-11 12:36:43 -050074#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A"
Lee, Chun-Yib3c90922010-12-07 10:29:22 +080075#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
JafarAkhondalica42c112021-08-12 17:23:07 +043076#define WMID_GUID4 "7A4DDFE7-5B5D-40B4-8595-4408E0CC7F56"
Carlos Corbacho745a5d22008-02-05 02:17:10 +000077
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +080078/*
79 * Acer ACPI event GUIDs
80 */
81#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
82
Carlos Corbacho745a5d22008-02-05 02:17:10 +000083MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
Lee, Chun-Yi08a07992011-04-06 17:40:06 +080084MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3");
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +080085MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
86
87enum acer_wmi_event_ids {
88 WMID_HOTKEY_EVENT = 0x1,
Hans de Goede5c54cb62020-10-19 20:56:28 +020089 WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5,
JafarAkhondalica42c112021-08-12 17:23:07 +043090 WMID_GAMING_TURBO_KEY_EVENT = 0x7,
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +080091};
92
Mathias Krause87e44842014-07-16 19:43:05 +020093static const struct key_entry acer_wmi_keymap[] __initconst = {
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +080094 {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
Melchior FRANZ8ae68de2011-05-24 10:35:55 +020095 {KE_KEY, 0x03, {KEY_WLAN} }, /* WiFi */
Seth Forshee1a04d8f2011-06-21 12:00:32 -050096 {KE_KEY, 0x04, {KEY_WLAN} }, /* WiFi */
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +080097 {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */
98 {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */
99 {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
100 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
101 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
Merlin Schumacher67e1d342012-01-24 04:35:35 +0800102 {KE_KEY, 0x29, {KEY_PROG3} }, /* P_Key for TM8372 */
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200103 {KE_IGNORE, 0x41, {KEY_MUTE} },
104 {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
Sergey Senozhatskyca1469f2012-03-12 13:07:13 +0300105 {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200106 {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
Sergey Senozhatskyca1469f2012-03-12 13:07:13 +0300107 {KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200108 {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
Sergey Senozhatskyca1469f2012-03-12 13:07:13 +0300109 {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200110 {KE_IGNORE, 0x45, {KEY_STOP} },
Sergey Senozhatskyca1469f2012-03-12 13:07:13 +0300111 {KE_IGNORE, 0x50, {KEY_STOP} },
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200112 {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
113 {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
Sergey Senozhatskyca1469f2012-03-12 13:07:13 +0300114 {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200115 {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
116 {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
117 {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +0800118 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200119 {KE_IGNORE, 0x81, {KEY_SLEEP} },
Lee, Chun-Yi8e2286c2012-12-14 16:14:27 +0800120 {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */
Timo Witte19cf7052020-08-04 02:14:23 +0200121 {KE_IGNORE, 0x84, {KEY_KBDILLUMTOGGLE} }, /* Automatic Keyboard background light toggle */
Lee, Chun-Yi8e2286c2012-12-14 16:14:27 +0800122 {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
123 {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
Melchior FRANZ8ae68de2011-05-24 10:35:55 +0200124 {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
Sergey Senozhatsky68825ce2012-11-26 21:35:02 +0300125 {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
Chris Chiu5ffa5722017-02-08 07:51:41 -0600126 {KE_KEY, 0x86, {KEY_WLAN} },
Antonio Rosario Intilisanoc7a437f2018-04-27 23:50:21 +0200127 {KE_KEY, 0x87, {KEY_POWER} },
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +0800128 {KE_END, 0}
129};
130
131static struct input_dev *acer_wmi_input_dev;
Marek Vasut1eb3fe12012-06-01 19:11:22 +0200132static struct input_dev *acer_wmi_accel_dev;
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +0800133
134struct event_return_value {
135 u8 function;
136 u8 key_num;
137 u16 device_state;
Hans de Goede5c54cb62020-10-19 20:56:28 +0200138 u16 reserved1;
139 u8 kbd_dock_state;
140 u8 reserved2;
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +0800141} __attribute__((packed));
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000142
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000143/*
Lee, Chun-Yib3c90922010-12-07 10:29:22 +0800144 * GUID3 Get Device Status device flags
145 */
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +0800146#define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */
Lee, Chun-Yib3c90922010-12-07 10:29:22 +0800147#define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */
Lee, Chun-Yi6d88ff02011-05-22 07:33:54 +0800148#define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +0800149#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */
João Paulo Rechi Vita3e2bc5c2017-06-06 13:07:22 -0700150#define ACER_WMID3_GDS_RFBTN (1<<14) /* RF Button */
151
Lee, Chun-Yi8e2286c2012-12-14 16:14:27 +0800152#define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */
Lee, Chun-Yib3c90922010-12-07 10:29:22 +0800153
Chris Chiu280642c2017-02-08 07:51:40 -0600154/* Hotkey Customized Setting and Acer Application Status.
155 * Set Device Default Value and Report Acer Application Status.
156 * When Acer Application starts, it will run this method to inform
157 * BIOS/EC that Acer Application is on.
158 * App Status
159 * Bit[0]: Launch Manager Status
160 * Bit[1]: ePM Status
161 * Bit[2]: Device Control Status
162 * Bit[3]: Acer Power Button Utility Status
163 * Bit[4]: RF Button Status
164 * Bit[5]: ODD PM Status
165 * Bit[6]: Device Default Value Control
166 * Bit[7]: Hall Sensor Application Status
167 */
168struct func_input_params {
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -0500169 u8 function_num; /* Function Number */
170 u16 commun_devices; /* Communication type devices default status */
171 u16 devices; /* Other type devices default status */
Chris Chiu280642c2017-02-08 07:51:40 -0600172 u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */
173 u8 app_mask; /* Bit mask to app_status */
174 u8 reserved;
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -0500175} __attribute__((packed));
176
Chris Chiu280642c2017-02-08 07:51:40 -0600177struct func_return_value {
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -0500178 u8 error_code; /* Error Code */
179 u8 ec_return_value; /* EC Return Value */
180 u16 reserved;
181} __attribute__((packed));
182
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +0800183struct wmid3_gds_set_input_param { /* Set Device Status input parameter */
184 u8 function_num; /* Function Number */
185 u8 hotkey_number; /* Hotkey Number */
186 u16 devices; /* Set Device */
187 u8 volume_value; /* Volume Value */
188} __attribute__((packed));
189
190struct wmid3_gds_get_input_param { /* Get Device Status input parameter */
Lee, Chun-Yib3c90922010-12-07 10:29:22 +0800191 u8 function_num; /* Function Number */
192 u8 hotkey_number; /* Hotkey Number */
193 u16 devices; /* Get Device */
194} __attribute__((packed));
195
196struct wmid3_gds_return_value { /* Get Device Status return value*/
197 u8 error_code; /* Error Code */
198 u8 ec_return_value; /* EC Return Value */
199 u16 devices; /* Current Device Status */
200 u32 reserved;
201} __attribute__((packed));
202
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +0800203struct hotkey_function_type_aa {
204 u8 type;
205 u8 length;
206 u16 handle;
207 u16 commun_func_bitmap;
Lee, Chun-Yi34b6cfa2012-03-19 17:37:32 +0800208 u16 application_func_bitmap;
209 u16 media_func_bitmap;
210 u16 display_func_bitmap;
211 u16 others_func_bitmap;
212 u8 commun_fn_key_number;
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +0800213} __attribute__((packed));
214
Lee, Chun-Yib3c90922010-12-07 10:29:22 +0800215/*
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000216 * Interface capability flags
217 */
Hans de Goede7c936d82020-10-19 20:56:24 +0200218#define ACER_CAP_MAILLED BIT(0)
219#define ACER_CAP_WIRELESS BIT(1)
220#define ACER_CAP_BLUETOOTH BIT(2)
221#define ACER_CAP_BRIGHTNESS BIT(3)
222#define ACER_CAP_THREEG BIT(4)
Hans de Goede82cb8a52020-10-19 20:56:27 +0200223#define ACER_CAP_SET_FUNCTION_MODE BIT(5)
Hans de Goede5c54cb62020-10-19 20:56:28 +0200224#define ACER_CAP_KBD_DOCK BIT(6)
JafarAkhondalica42c112021-08-12 17:23:07 +0430225#define ACER_CAP_TURBO_OC BIT(7)
226#define ACER_CAP_TURBO_LED BIT(8)
227#define ACER_CAP_TURBO_FAN BIT(9)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000228
229/*
230 * Interface type flags
231 */
232enum interface_flags {
233 ACER_AMW0,
234 ACER_AMW0_V2,
235 ACER_WMID,
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +0800236 ACER_WMID_v2,
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000237};
238
239#define ACER_DEFAULT_WIRELESS 0
240#define ACER_DEFAULT_BLUETOOTH 0
241#define ACER_DEFAULT_MAILLED 0
242#define ACER_DEFAULT_THREEG 0
243
244static int max_brightness = 0xF;
245
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000246static int mailled = -1;
247static int brightness = -1;
248static int threeg = -1;
249static int force_series;
Hans de Goede39aa0092020-10-19 20:56:26 +0200250static int force_caps = -1;
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -0500251static bool ec_raw_mode;
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +0800252static bool has_type_aa;
Lee, Chun-Yi1d1fc8a2011-10-06 19:06:13 +0800253static u16 commun_func_bitmap;
Lee, Chun-Yi34b6cfa2012-03-19 17:37:32 +0800254static u8 commun_fn_key_number;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000255
256module_param(mailled, int, 0444);
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000257module_param(brightness, int, 0444);
258module_param(threeg, int, 0444);
259module_param(force_series, int, 0444);
Hans de Goede39aa0092020-10-19 20:56:26 +0200260module_param(force_caps, int, 0444);
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -0500261module_param(ec_raw_mode, bool, 0444);
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000262MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
263MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
264MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
265MODULE_PARM_DESC(force_series, "Force a different laptop series");
Hans de Goede39aa0092020-10-19 20:56:26 +0200266MODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value");
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -0500267MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000268
269struct acer_data {
270 int mailled;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000271 int threeg;
272 int brightness;
273};
274
Carlos Corbacho81143522008-06-21 09:09:53 +0100275struct acer_debug {
276 struct dentry *root;
Carlos Corbacho81143522008-06-21 09:09:53 +0100277 u32 wmid_devices;
278};
279
Carlos Corbacho0606e1a2008-10-08 21:40:21 +0100280static struct rfkill *wireless_rfkill;
281static struct rfkill *bluetooth_rfkill;
Lee, Chun-Yib3c90922010-12-07 10:29:22 +0800282static struct rfkill *threeg_rfkill;
Lee, Chun-Yi8215af02011-03-28 16:52:02 +0800283static bool rfkill_inited;
Carlos Corbacho0606e1a2008-10-08 21:40:21 +0100284
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000285/* Each low-level interface must define at least some of the following */
286struct wmi_interface {
287 /* The WMI device type */
288 u32 type;
289
290 /* The capabilities this interface provides */
291 u32 capability;
292
293 /* Private data for the current interface */
294 struct acer_data data;
Carlos Corbacho81143522008-06-21 09:09:53 +0100295
296 /* debugfs entries associated with this interface */
297 struct acer_debug debug;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000298};
299
300/* The static interface pointer, points to the currently detected interface */
301static struct wmi_interface *interface;
302
303/*
304 * Embedded Controller quirks
305 * Some laptops require us to directly access the EC to either enable or query
306 * features that are not available through WMI.
307 */
308
309struct quirk_entry {
310 u8 wireless;
311 u8 mailled;
Carlos Corbacho9991d9f2008-06-21 09:09:22 +0100312 s8 brightness;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000313 u8 bluetooth;
JafarAkhondalica42c112021-08-12 17:23:07 +0430314 u8 turbo;
315 u8 cpu_fans;
316 u8 gpu_fans;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000317};
318
319static struct quirk_entry *quirks;
320
Mathias Krause76d51dd2014-07-16 19:43:04 +0200321static void __init set_quirks(void)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000322{
323 if (quirks->mailled)
324 interface->capability |= ACER_CAP_MAILLED;
325
326 if (quirks->brightness)
327 interface->capability |= ACER_CAP_BRIGHTNESS;
JafarAkhondalica42c112021-08-12 17:23:07 +0430328
329 if (quirks->turbo)
330 interface->capability |= ACER_CAP_TURBO_OC | ACER_CAP_TURBO_LED
331 | ACER_CAP_TURBO_FAN;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000332}
333
Mathias Krause76d51dd2014-07-16 19:43:04 +0200334static int __init dmi_matched(const struct dmi_system_id *dmi)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000335{
336 quirks = dmi->driver_data;
Axel Lind53bf0f2010-06-30 13:32:16 +0800337 return 1;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000338}
339
Hans de Goede5c54cb62020-10-19 20:56:28 +0200340static int __init set_force_caps(const struct dmi_system_id *dmi)
341{
342 if (force_caps == -1) {
343 force_caps = (uintptr_t)dmi->driver_data;
344 pr_info("Found %s, set force_caps to 0x%x\n", dmi->ident, force_caps);
345 }
346 return 1;
347}
348
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000349static struct quirk_entry quirk_unknown = {
350};
351
Carlos Corbacho9991d9f2008-06-21 09:09:22 +0100352static struct quirk_entry quirk_acer_aspire_1520 = {
353 .brightness = -1,
354};
355
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000356static struct quirk_entry quirk_acer_travelmate_2490 = {
357 .mailled = 1,
358};
359
JafarAkhondalica42c112021-08-12 17:23:07 +0430360static struct quirk_entry quirk_acer_predator_ph315_53 = {
361 .turbo = 1,
362 .cpu_fans = 1,
363 .gpu_fans = 1,
364};
365
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000366/* This AMW0 laptop has no bluetooth */
367static struct quirk_entry quirk_medion_md_98300 = {
368 .wireless = 1,
369};
370
Carlos Corbacho6f061ab2008-06-21 09:09:38 +0100371static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
372 .wireless = 2,
373};
374
Lee, Chun-Yi15b956a2011-07-30 17:00:45 +0800375static struct quirk_entry quirk_lenovo_ideapad_s205 = {
376 .wireless = 3,
377};
378
Carlos Corbachoa74dd5f2009-04-04 09:33:29 +0100379/* The Aspire One has a dummy ACPI-WMI interface - disable it */
Mathias Krause76d51dd2014-07-16 19:43:04 +0200380static const struct dmi_system_id acer_blacklist[] __initconst = {
Carlos Corbachoa74dd5f2009-04-04 09:33:29 +0100381 {
382 .ident = "Acer Aspire One (SSD)",
383 .matches = {
384 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
385 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
386 },
387 },
388 {
389 .ident = "Acer Aspire One (HDD)",
390 .matches = {
391 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
392 DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
393 },
394 },
395 {}
396};
397
Lee, Chun-Yi5241b192016-11-01 12:30:58 +0800398static const struct dmi_system_id amw0_whitelist[] __initconst = {
399 {
400 .ident = "Acer",
401 .matches = {
402 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
403 },
404 },
405 {
406 .ident = "Gateway",
407 .matches = {
408 DMI_MATCH(DMI_SYS_VENDOR, "Gateway"),
409 },
410 },
411 {
412 .ident = "Packard Bell",
413 .matches = {
414 DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
415 },
416 },
417 {}
418};
419
420/*
421 * This quirk table is only for Acer/Gateway/Packard Bell family
422 * that those machines are supported by acer-wmi driver.
423 */
Mathias Krause76d51dd2014-07-16 19:43:04 +0200424static const struct dmi_system_id acer_quirks[] __initconst = {
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000425 {
426 .callback = dmi_matched,
Carlos Corbacho9991d9f2008-06-21 09:09:22 +0100427 .ident = "Acer Aspire 1360",
428 .matches = {
429 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
430 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
431 },
432 .driver_data = &quirk_acer_aspire_1520,
433 },
434 {
435 .callback = dmi_matched,
436 .ident = "Acer Aspire 1520",
437 .matches = {
438 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
439 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
440 },
441 .driver_data = &quirk_acer_aspire_1520,
442 },
443 {
444 .callback = dmi_matched,
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000445 .ident = "Acer Aspire 3100",
446 .matches = {
447 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
448 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
449 },
450 .driver_data = &quirk_acer_travelmate_2490,
451 },
452 {
453 .callback = dmi_matched,
Carlos Corbachoed9cfe92008-03-12 20:13:00 +0000454 .ident = "Acer Aspire 3610",
455 .matches = {
456 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
457 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
458 },
459 .driver_data = &quirk_acer_travelmate_2490,
460 },
461 {
462 .callback = dmi_matched,
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000463 .ident = "Acer Aspire 5100",
464 .matches = {
465 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
466 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
467 },
468 .driver_data = &quirk_acer_travelmate_2490,
469 },
470 {
471 .callback = dmi_matched,
Carlos Corbachoed9cfe92008-03-12 20:13:00 +0000472 .ident = "Acer Aspire 5610",
473 .matches = {
474 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
475 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
476 },
477 .driver_data = &quirk_acer_travelmate_2490,
478 },
479 {
480 .callback = dmi_matched,
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000481 .ident = "Acer Aspire 5630",
482 .matches = {
483 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
484 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
485 },
486 .driver_data = &quirk_acer_travelmate_2490,
487 },
488 {
489 .callback = dmi_matched,
490 .ident = "Acer Aspire 5650",
491 .matches = {
492 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
493 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
494 },
495 .driver_data = &quirk_acer_travelmate_2490,
496 },
497 {
498 .callback = dmi_matched,
499 .ident = "Acer Aspire 5680",
500 .matches = {
501 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
502 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
503 },
504 .driver_data = &quirk_acer_travelmate_2490,
505 },
506 {
507 .callback = dmi_matched,
508 .ident = "Acer Aspire 9110",
509 .matches = {
510 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
511 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
512 },
513 .driver_data = &quirk_acer_travelmate_2490,
514 },
515 {
516 .callback = dmi_matched,
517 .ident = "Acer TravelMate 2490",
518 .matches = {
519 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
520 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
521 },
522 .driver_data = &quirk_acer_travelmate_2490,
523 },
524 {
525 .callback = dmi_matched,
Carlos Corbacho262ee352008-02-16 00:02:56 +0000526 .ident = "Acer TravelMate 4200",
527 .matches = {
528 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
529 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
530 },
531 .driver_data = &quirk_acer_travelmate_2490,
532 },
Hans de Goede5c54cb62020-10-19 20:56:28 +0200533 {
JafarAkhondalica42c112021-08-12 17:23:07 +0430534 .callback = dmi_matched,
535 .ident = "Acer Predator PH315-53",
536 .matches = {
537 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
538 DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH315-53"),
539 },
540 .driver_data = &quirk_acer_predator_ph315_53,
541 },
542 {
Hans de Goede5c54cb62020-10-19 20:56:28 +0200543 .callback = set_force_caps,
Hans de Goedebf753402020-11-23 16:16:25 +0100544 .ident = "Acer Aspire Switch 10E SW3-016",
545 .matches = {
546 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
547 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-016"),
548 },
549 .driver_data = (void *)ACER_CAP_KBD_DOCK,
550 },
551 {
552 .callback = set_force_caps,
Hans de Goede5c54cb62020-10-19 20:56:28 +0200553 .ident = "Acer Aspire Switch 10 SW5-012",
554 .matches = {
555 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
556 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
557 },
558 .driver_data = (void *)ACER_CAP_KBD_DOCK,
559 },
560 {
561 .callback = set_force_caps,
562 .ident = "Acer One 10 (S1003)",
563 .matches = {
564 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"),
565 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"),
566 },
567 .driver_data = (void *)ACER_CAP_KBD_DOCK,
568 },
Lee, Chun-Yi5241b192016-11-01 12:30:58 +0800569 {}
570};
571
572/*
573 * This quirk list is for those non-acer machines that have AMW0_GUID1
574 * but supported by acer-wmi in past days. Keeping this quirk list here
575 * is only for backward compatible. Please do not add new machine to
576 * here anymore. Those non-acer machines should be supported by
577 * appropriate wmi drivers.
578 */
579static const struct dmi_system_id non_acer_quirks[] __initconst = {
Carlos Corbacho262ee352008-02-16 00:02:56 +0000580 {
581 .callback = dmi_matched,
Carlos Corbacho6f061ab2008-06-21 09:09:38 +0100582 .ident = "Fujitsu Siemens Amilo Li 1718",
583 .matches = {
584 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
585 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
586 },
587 .driver_data = &quirk_fujitsu_amilo_li_1718,
588 },
589 {
590 .callback = dmi_matched,
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000591 .ident = "Medion MD 98300",
592 .matches = {
593 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
594 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
595 },
596 .driver_data = &quirk_medion_md_98300,
597 },
Lee, Chun-Yi15b956a2011-07-30 17:00:45 +0800598 {
599 .callback = dmi_matched,
600 .ident = "Lenovo Ideapad S205",
601 .matches = {
602 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
603 DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
604 },
605 .driver_data = &quirk_lenovo_ideapad_s205,
606 },
Seth Forsheebe3128b2011-10-06 15:01:55 -0500607 {
608 .callback = dmi_matched,
Lee, Chun-Yic08f2082012-03-20 11:32:49 +0800609 .ident = "Lenovo Ideapad S205 (Brazos)",
610 .matches = {
611 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
612 DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
613 },
614 .driver_data = &quirk_lenovo_ideapad_s205,
615 },
616 {
617 .callback = dmi_matched,
Seth Forsheebe3128b2011-10-06 15:01:55 -0500618 .ident = "Lenovo 3000 N200",
619 .matches = {
620 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
621 DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
622 },
623 .driver_data = &quirk_fujitsu_amilo_li_1718,
624 },
Lee, Chun-Yie6c33f12012-12-14 16:14:25 +0800625 {
626 .callback = dmi_matched,
627 .ident = "Lenovo Ideapad S205-10382JG",
628 .matches = {
629 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
630 DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"),
631 },
632 .driver_data = &quirk_lenovo_ideapad_s205,
633 },
Lee, Chun-Yi5f3511d2012-12-14 16:14:28 +0800634 {
635 .callback = dmi_matched,
636 .ident = "Lenovo Ideapad S205-1038DPG",
637 .matches = {
638 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
639 DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"),
640 },
641 .driver_data = &quirk_lenovo_ideapad_s205,
642 },
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000643 {}
644};
645
Mathias Krause76d51dd2014-07-16 19:43:04 +0200646static int __init
647video_set_backlight_video_vendor(const struct dmi_system_id *d)
Lee, Chun-Yi86924de2012-03-26 15:47:58 -0400648{
649 interface->capability &= ~ACER_CAP_BRIGHTNESS;
650 pr_info("Brightness must be controlled by generic video driver\n");
651 return 0;
652}
653
Mathias Krause76d51dd2014-07-16 19:43:04 +0200654static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
Lee, Chun-Yi86924de2012-03-26 15:47:58 -0400655 {
656 .callback = video_set_backlight_video_vendor,
657 .ident = "Acer TravelMate 4750",
658 .matches = {
659 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
660 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
661 },
662 },
Lee, Chun-Yi050eff32012-05-21 23:19:51 +0800663 {
664 .callback = video_set_backlight_video_vendor,
665 .ident = "Acer Extensa 5235",
666 .matches = {
667 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
668 DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
669 },
670 },
671 {
672 .callback = video_set_backlight_video_vendor,
673 .ident = "Acer TravelMate 5760",
674 .matches = {
675 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
676 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
677 },
678 },
679 {
680 .callback = video_set_backlight_video_vendor,
681 .ident = "Acer Aspire 5750",
682 .matches = {
683 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
684 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
685 },
686 },
Hans de Goede9404cd952014-05-17 10:48:03 +0200687 {
688 .callback = video_set_backlight_video_vendor,
689 .ident = "Acer Aspire 5741",
690 .matches = {
691 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
692 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
693 },
694 },
Hans de Goede183fd8f2014-10-22 16:06:38 +0200695 {
696 /*
697 * Note no video_set_backlight_video_vendor, we must use the
698 * acer interface, as there is no native backlight interface.
699 */
700 .ident = "Acer KAV80",
701 .matches = {
702 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
703 DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
704 },
705 },
Lee, Chun-Yi86924de2012-03-26 15:47:58 -0400706 {}
707};
708
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000709/* Find which quirks are needed for a particular vendor/ model pair */
Mathias Krause76d51dd2014-07-16 19:43:04 +0200710static void __init find_quirks(void)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000711{
712 if (!force_series) {
713 dmi_check_system(acer_quirks);
Lee, Chun-Yi5241b192016-11-01 12:30:58 +0800714 dmi_check_system(non_acer_quirks);
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000715 } else if (force_series == 2490) {
716 quirks = &quirk_acer_travelmate_2490;
717 }
718
719 if (quirks == NULL)
720 quirks = &quirk_unknown;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000721}
722
723/*
724 * General interface convenience methods
725 */
726
727static bool has_cap(u32 cap)
728{
Gustavo A. R. Silvaaa7d16b2018-08-06 15:38:32 -0500729 return interface->capability & cap;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000730}
731
732/*
733 * AMW0 (V1) interface
734 */
735struct wmab_args {
736 u32 eax;
737 u32 ebx;
738 u32 ecx;
739 u32 edx;
740};
741
742struct wmab_ret {
743 u32 eax;
744 u32 ebx;
745 u32 ecx;
746 u32 edx;
747 u32 eex;
748};
749
750static acpi_status wmab_execute(struct wmab_args *regbuf,
751struct acpi_buffer *result)
752{
753 struct acpi_buffer input;
754 acpi_status status;
755 input.length = sizeof(struct wmab_args);
756 input.pointer = (u8 *)regbuf;
757
Lee, Chun-Yi62fc7432017-06-20 17:06:23 +0800758 status = wmi_evaluate_method(AMW0_GUID1, 0, 1, &input, result);
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000759
760 return status;
761}
762
Lee, Chun-Yi38db1572012-01-09 14:26:44 +0800763static acpi_status AMW0_get_u32(u32 *value, u32 cap)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000764{
765 int err;
766 u8 result;
767
768 switch (cap) {
769 case ACER_CAP_MAILLED:
770 switch (quirks->mailled) {
771 default:
772 err = ec_read(0xA, &result);
773 if (err)
774 return AE_ERROR;
775 *value = (result >> 7) & 0x1;
776 return AE_OK;
777 }
778 break;
779 case ACER_CAP_WIRELESS:
780 switch (quirks->wireless) {
781 case 1:
782 err = ec_read(0x7B, &result);
783 if (err)
784 return AE_ERROR;
785 *value = result & 0x1;
786 return AE_OK;
Carlos Corbacho6f061ab2008-06-21 09:09:38 +0100787 case 2:
788 err = ec_read(0x71, &result);
789 if (err)
790 return AE_ERROR;
791 *value = result & 0x1;
792 return AE_OK;
Lee, Chun-Yi15b956a2011-07-30 17:00:45 +0800793 case 3:
794 err = ec_read(0x78, &result);
795 if (err)
796 return AE_ERROR;
797 *value = result & 0x1;
798 return AE_OK;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000799 default:
800 err = ec_read(0xA, &result);
801 if (err)
802 return AE_ERROR;
803 *value = (result >> 2) & 0x1;
804 return AE_OK;
805 }
806 break;
807 case ACER_CAP_BLUETOOTH:
808 switch (quirks->bluetooth) {
809 default:
810 err = ec_read(0xA, &result);
811 if (err)
812 return AE_ERROR;
813 *value = (result >> 4) & 0x1;
814 return AE_OK;
815 }
816 break;
817 case ACER_CAP_BRIGHTNESS:
818 switch (quirks->brightness) {
819 default:
820 err = ec_read(0x83, &result);
821 if (err)
822 return AE_ERROR;
823 *value = result;
824 return AE_OK;
825 }
826 break;
827 default:
Lin Ming08237972008-08-08 11:57:11 +0800828 return AE_ERROR;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000829 }
830 return AE_OK;
831}
832
Lee, Chun-Yi38db1572012-01-09 14:26:44 +0800833static acpi_status AMW0_set_u32(u32 value, u32 cap)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000834{
835 struct wmab_args args;
836
837 args.eax = ACER_AMW0_WRITE;
838 args.ebx = value ? (1<<8) : 0;
839 args.ecx = args.edx = 0;
840
841 switch (cap) {
842 case ACER_CAP_MAILLED:
843 if (value > 1)
844 return AE_BAD_PARAMETER;
845 args.ebx |= ACER_AMW0_MAILLED_MASK;
846 break;
847 case ACER_CAP_WIRELESS:
848 if (value > 1)
849 return AE_BAD_PARAMETER;
850 args.ebx |= ACER_AMW0_WIRELESS_MASK;
851 break;
852 case ACER_CAP_BLUETOOTH:
853 if (value > 1)
854 return AE_BAD_PARAMETER;
855 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
856 break;
857 case ACER_CAP_BRIGHTNESS:
858 if (value > max_brightness)
859 return AE_BAD_PARAMETER;
860 switch (quirks->brightness) {
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000861 default:
Carlos Corbacho4609d022008-02-08 23:51:49 +0000862 return ec_write(0x83, value);
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000863 }
864 default:
Lin Ming08237972008-08-08 11:57:11 +0800865 return AE_ERROR;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000866 }
867
868 /* Actually do the set */
869 return wmab_execute(&args, NULL);
870}
871
Mathias Krause76d51dd2014-07-16 19:43:04 +0200872static acpi_status __init AMW0_find_mailled(void)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000873{
874 struct wmab_args args;
875 struct wmab_ret ret;
876 acpi_status status = AE_OK;
877 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
878 union acpi_object *obj;
879
880 args.eax = 0x86;
881 args.ebx = args.ecx = args.edx = 0;
882
883 status = wmab_execute(&args, &out);
884 if (ACPI_FAILURE(status))
885 return status;
886
887 obj = (union acpi_object *) out.pointer;
888 if (obj && obj->type == ACPI_TYPE_BUFFER &&
889 obj->buffer.length == sizeof(struct wmab_ret)) {
890 ret = *((struct wmab_ret *) obj->buffer.pointer);
891 } else {
Axel Lin7677fbd2010-07-20 15:19:53 -0700892 kfree(out.pointer);
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000893 return AE_ERROR;
894 }
895
896 if (ret.eex & 0x1)
897 interface->capability |= ACER_CAP_MAILLED;
898
899 kfree(out.pointer);
900
901 return AE_OK;
902}
903
Mathias Krause76d51dd2014-07-16 19:43:04 +0200904static const struct acpi_device_id norfkill_ids[] __initconst = {
Ike Panhc461e7432012-02-03 16:46:39 +0800905 { "VPC2004", 0},
906 { "IBM0068", 0},
907 { "LEN0068", 0},
Lee, Chun-Yi5719b812012-03-23 12:36:44 +0800908 { "SNY5001", 0}, /* sony-laptop in charge */
Michael Powell628b31982015-08-02 22:59:29 +0000909 { "HPQ6601", 0},
Ike Panhc461e7432012-02-03 16:46:39 +0800910 { "", 0},
911};
912
Mathias Krause76d51dd2014-07-16 19:43:04 +0200913static int __init AMW0_set_cap_acpi_check_device(void)
Ike Panhc461e7432012-02-03 16:46:39 +0800914{
915 const struct acpi_device_id *id;
916
917 for (id = norfkill_ids; id->id[0]; id++)
Lukas Wunner8c92a752016-03-24 13:15:20 +0100918 if (acpi_dev_found(id->id))
919 return true;
920
921 return false;
Ike Panhc461e7432012-02-03 16:46:39 +0800922}
923
Mathias Krause76d51dd2014-07-16 19:43:04 +0200924static acpi_status __init AMW0_set_capabilities(void)
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000925{
926 struct wmab_args args;
927 struct wmab_ret ret;
Axel Lin7677fbd2010-07-20 15:19:53 -0700928 acpi_status status;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000929 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
930 union acpi_object *obj;
931
Carlos Corbacho5753dd52008-06-21 09:09:48 +0100932 /*
933 * On laptops with this strange GUID (non Acer), normal probing doesn't
934 * work.
935 */
936 if (wmi_has_guid(AMW0_GUID2)) {
Ike Panhc461e7432012-02-03 16:46:39 +0800937 if ((quirks != &quirk_unknown) ||
938 !AMW0_set_cap_acpi_check_device())
939 interface->capability |= ACER_CAP_WIRELESS;
Carlos Corbacho5753dd52008-06-21 09:09:48 +0100940 return AE_OK;
941 }
942
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000943 args.eax = ACER_AMW0_WRITE;
944 args.ecx = args.edx = 0;
945
946 args.ebx = 0xa2 << 8;
947 args.ebx |= ACER_AMW0_WIRELESS_MASK;
948
949 status = wmab_execute(&args, &out);
950 if (ACPI_FAILURE(status))
951 return status;
952
Axel Lin7677fbd2010-07-20 15:19:53 -0700953 obj = out.pointer;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000954 if (obj && obj->type == ACPI_TYPE_BUFFER &&
955 obj->buffer.length == sizeof(struct wmab_ret)) {
956 ret = *((struct wmab_ret *) obj->buffer.pointer);
957 } else {
Axel Lin7677fbd2010-07-20 15:19:53 -0700958 status = AE_ERROR;
959 goto out;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000960 }
961
962 if (ret.eax & 0x1)
963 interface->capability |= ACER_CAP_WIRELESS;
964
965 args.ebx = 2 << 8;
966 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
967
Axel Lin7677fbd2010-07-20 15:19:53 -0700968 /*
969 * It's ok to use existing buffer for next wmab_execute call.
970 * But we need to kfree(out.pointer) if next wmab_execute fail.
971 */
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000972 status = wmab_execute(&args, &out);
973 if (ACPI_FAILURE(status))
Axel Lin7677fbd2010-07-20 15:19:53 -0700974 goto out;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000975
976 obj = (union acpi_object *) out.pointer;
977 if (obj && obj->type == ACPI_TYPE_BUFFER
978 && obj->buffer.length == sizeof(struct wmab_ret)) {
979 ret = *((struct wmab_ret *) obj->buffer.pointer);
980 } else {
Axel Lin7677fbd2010-07-20 15:19:53 -0700981 status = AE_ERROR;
982 goto out;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000983 }
984
985 if (ret.eax & 0x1)
986 interface->capability |= ACER_CAP_BLUETOOTH;
987
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000988 /*
989 * This appears to be safe to enable, since all Wistron based laptops
990 * appear to use the same EC register for brightness, even if they
991 * differ for wireless, etc
992 */
Carlos Corbacho9991d9f2008-06-21 09:09:22 +0100993 if (quirks->brightness >= 0)
994 interface->capability |= ACER_CAP_BRIGHTNESS;
Carlos Corbacho745a5d22008-02-05 02:17:10 +0000995
Axel Lin7677fbd2010-07-20 15:19:53 -0700996 status = AE_OK;
997out:
998 kfree(out.pointer);
999 return status;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001000}
1001
1002static struct wmi_interface AMW0_interface = {
1003 .type = ACER_AMW0,
1004};
1005
1006static struct wmi_interface AMW0_V2_interface = {
1007 .type = ACER_AMW0_V2,
1008};
1009
1010/*
1011 * New interface (The WMID interface)
1012 */
1013static acpi_status
1014WMI_execute_u32(u32 method_id, u32 in, u32 *out)
1015{
1016 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
1017 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
1018 union acpi_object *obj;
Lee, Chun-Yif20aaba2012-12-14 16:14:26 +08001019 u32 tmp = 0;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001020 acpi_status status;
1021
Lee, Chun-Yi62fc7432017-06-20 17:06:23 +08001022 status = wmi_evaluate_method(WMID_GUID1, 0, method_id, &input, &result);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001023
1024 if (ACPI_FAILURE(status))
1025 return status;
1026
1027 obj = (union acpi_object *) result.pointer;
Lee, Chun-Yif20aaba2012-12-14 16:14:26 +08001028 if (obj) {
1029 if (obj->type == ACPI_TYPE_BUFFER &&
1030 (obj->buffer.length == sizeof(u32) ||
1031 obj->buffer.length == sizeof(u64))) {
1032 tmp = *((u32 *) obj->buffer.pointer);
1033 } else if (obj->type == ACPI_TYPE_INTEGER) {
1034 tmp = (u32) obj->integer.value;
1035 }
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001036 }
1037
1038 if (out)
1039 *out = tmp;
1040
1041 kfree(result.pointer);
1042
1043 return status;
1044}
1045
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001046static acpi_status WMID_get_u32(u32 *value, u32 cap)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001047{
1048 acpi_status status;
1049 u8 tmp;
1050 u32 result, method_id = 0;
1051
1052 switch (cap) {
1053 case ACER_CAP_WIRELESS:
1054 method_id = ACER_WMID_GET_WIRELESS_METHODID;
1055 break;
1056 case ACER_CAP_BLUETOOTH:
1057 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
1058 break;
1059 case ACER_CAP_BRIGHTNESS:
1060 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
1061 break;
1062 case ACER_CAP_THREEG:
1063 method_id = ACER_WMID_GET_THREEG_METHODID;
1064 break;
1065 case ACER_CAP_MAILLED:
1066 if (quirks->mailled == 1) {
1067 ec_read(0x9f, &tmp);
1068 *value = tmp & 0x1;
1069 return 0;
1070 }
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001071 fallthrough;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001072 default:
Lin Ming08237972008-08-08 11:57:11 +08001073 return AE_ERROR;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001074 }
1075 status = WMI_execute_u32(method_id, 0, &result);
1076
1077 if (ACPI_SUCCESS(status))
1078 *value = (u8)result;
1079
1080 return status;
1081}
1082
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001083static acpi_status WMID_set_u32(u32 value, u32 cap)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001084{
1085 u32 method_id = 0;
1086 char param;
1087
1088 switch (cap) {
1089 case ACER_CAP_BRIGHTNESS:
1090 if (value > max_brightness)
1091 return AE_BAD_PARAMETER;
1092 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
1093 break;
1094 case ACER_CAP_WIRELESS:
1095 if (value > 1)
1096 return AE_BAD_PARAMETER;
1097 method_id = ACER_WMID_SET_WIRELESS_METHODID;
1098 break;
1099 case ACER_CAP_BLUETOOTH:
1100 if (value > 1)
1101 return AE_BAD_PARAMETER;
1102 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
1103 break;
1104 case ACER_CAP_THREEG:
1105 if (value > 1)
1106 return AE_BAD_PARAMETER;
1107 method_id = ACER_WMID_SET_THREEG_METHODID;
1108 break;
1109 case ACER_CAP_MAILLED:
1110 if (value > 1)
1111 return AE_BAD_PARAMETER;
1112 if (quirks->mailled == 1) {
1113 param = value ? 0x92 : 0x93;
Dmitry Torokhov181d6832009-09-16 01:06:43 -07001114 i8042_lock_chip();
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001115 i8042_command(&param, 0x1059);
Dmitry Torokhov181d6832009-09-16 01:06:43 -07001116 i8042_unlock_chip();
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001117 return 0;
1118 }
1119 break;
1120 default:
Lin Ming08237972008-08-08 11:57:11 +08001121 return AE_ERROR;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001122 }
1123 return WMI_execute_u32(method_id, (u32)value, NULL);
1124}
1125
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001126static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1127{
1128 struct wmid3_gds_return_value return_value;
1129 acpi_status status;
1130 union acpi_object *obj;
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +08001131 struct wmid3_gds_get_input_param params = {
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001132 .function_num = 0x1,
Lee, Chun-Yi34b6cfa2012-03-19 17:37:32 +08001133 .hotkey_number = commun_fn_key_number,
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001134 .devices = device,
1135 };
1136 struct acpi_buffer input = {
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +08001137 sizeof(struct wmid3_gds_get_input_param),
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001138 &params
1139 };
1140 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1141
1142 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
1143 if (ACPI_FAILURE(status))
1144 return status;
1145
1146 obj = output.pointer;
1147
1148 if (!obj)
1149 return AE_ERROR;
1150 else if (obj->type != ACPI_TYPE_BUFFER) {
1151 kfree(obj);
1152 return AE_ERROR;
1153 }
1154 if (obj->buffer.length != 8) {
1155 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1156 kfree(obj);
1157 return AE_ERROR;
1158 }
1159
1160 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1161 kfree(obj);
1162
1163 if (return_value.error_code || return_value.ec_return_value)
1164 pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
1165 device,
1166 return_value.error_code,
1167 return_value.ec_return_value);
1168 else
1169 *value = !!(return_value.devices & device);
1170
1171 return status;
1172}
1173
1174static acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
1175{
1176 u16 device;
1177
1178 switch (cap) {
1179 case ACER_CAP_WIRELESS:
1180 device = ACER_WMID3_GDS_WIRELESS;
1181 break;
1182 case ACER_CAP_BLUETOOTH:
1183 device = ACER_WMID3_GDS_BLUETOOTH;
1184 break;
1185 case ACER_CAP_THREEG:
1186 device = ACER_WMID3_GDS_THREEG;
1187 break;
1188 default:
1189 return AE_ERROR;
1190 }
1191 return wmid3_get_device_status(value, device);
1192}
1193
1194static acpi_status wmid3_set_device_status(u32 value, u16 device)
1195{
1196 struct wmid3_gds_return_value return_value;
1197 acpi_status status;
1198 union acpi_object *obj;
1199 u16 devices;
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +08001200 struct wmid3_gds_get_input_param get_params = {
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001201 .function_num = 0x1,
Lee, Chun-Yi34b6cfa2012-03-19 17:37:32 +08001202 .hotkey_number = commun_fn_key_number,
Lee, Chun-Yi1d1fc8a2011-10-06 19:06:13 +08001203 .devices = commun_func_bitmap,
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001204 };
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +08001205 struct acpi_buffer get_input = {
1206 sizeof(struct wmid3_gds_get_input_param),
1207 &get_params
1208 };
1209 struct wmid3_gds_set_input_param set_params = {
1210 .function_num = 0x2,
1211 .hotkey_number = commun_fn_key_number,
1212 .devices = commun_func_bitmap,
1213 };
1214 struct acpi_buffer set_input = {
1215 sizeof(struct wmid3_gds_set_input_param),
1216 &set_params
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001217 };
1218 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1219 struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
1220
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +08001221 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001222 if (ACPI_FAILURE(status))
1223 return status;
1224
1225 obj = output.pointer;
1226
1227 if (!obj)
1228 return AE_ERROR;
1229 else if (obj->type != ACPI_TYPE_BUFFER) {
1230 kfree(obj);
1231 return AE_ERROR;
1232 }
1233 if (obj->buffer.length != 8) {
Joe Perches6e71f382011-11-29 11:04:05 -08001234 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001235 kfree(obj);
1236 return AE_ERROR;
1237 }
1238
1239 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1240 kfree(obj);
1241
1242 if (return_value.error_code || return_value.ec_return_value) {
Joe Perches6e71f382011-11-29 11:04:05 -08001243 pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
1244 return_value.error_code,
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001245 return_value.ec_return_value);
1246 return status;
1247 }
1248
1249 devices = return_value.devices;
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +08001250 set_params.devices = (value) ? (devices | device) : (devices & ~device);
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001251
Lee, Chun-Yi996d23b2012-03-19 17:37:33 +08001252 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001253 if (ACPI_FAILURE(status))
1254 return status;
1255
1256 obj = output2.pointer;
1257
1258 if (!obj)
1259 return AE_ERROR;
1260 else if (obj->type != ACPI_TYPE_BUFFER) {
1261 kfree(obj);
1262 return AE_ERROR;
1263 }
1264 if (obj->buffer.length != 4) {
Joe Perches6e71f382011-11-29 11:04:05 -08001265 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001266 kfree(obj);
1267 return AE_ERROR;
1268 }
1269
1270 return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1271 kfree(obj);
1272
1273 if (return_value.error_code || return_value.ec_return_value)
Joe Perches6e71f382011-11-29 11:04:05 -08001274 pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
1275 return_value.error_code,
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001276 return_value.ec_return_value);
1277
1278 return status;
1279}
1280
1281static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
1282{
1283 u16 device;
1284
1285 switch (cap) {
1286 case ACER_CAP_WIRELESS:
1287 device = ACER_WMID3_GDS_WIRELESS;
1288 break;
1289 case ACER_CAP_BLUETOOTH:
1290 device = ACER_WMID3_GDS_BLUETOOTH;
1291 break;
1292 case ACER_CAP_THREEG:
1293 device = ACER_WMID3_GDS_THREEG;
1294 break;
1295 default:
1296 return AE_ERROR;
1297 }
1298 return wmid3_set_device_status(value, device);
1299}
1300
Mathias Krause76d51dd2014-07-16 19:43:04 +02001301static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +08001302{
1303 struct hotkey_function_type_aa *type_aa;
1304
1305 /* We are looking for OEM-specific Type AAh */
1306 if (header->type != 0xAA)
1307 return;
1308
1309 has_type_aa = true;
1310 type_aa = (struct hotkey_function_type_aa *) header;
1311
Lee, Chun-Yicae15702011-03-16 18:52:36 +08001312 pr_info("Function bitmap for Communication Button: 0x%x\n",
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +08001313 type_aa->commun_func_bitmap);
Lee, Chun-Yi1d1fc8a2011-10-06 19:06:13 +08001314 commun_func_bitmap = type_aa->commun_func_bitmap;
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +08001315
1316 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
1317 interface->capability |= ACER_CAP_WIRELESS;
1318 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
1319 interface->capability |= ACER_CAP_THREEG;
1320 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
1321 interface->capability |= ACER_CAP_BLUETOOTH;
Hans de Goede7c936d82020-10-19 20:56:24 +02001322 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN)
João Paulo Rechi Vita3e2bc5c2017-06-06 13:07:22 -07001323 commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN;
Lee, Chun-Yi34b6cfa2012-03-19 17:37:32 +08001324
1325 commun_fn_key_number = type_aa->commun_fn_key_number;
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +08001326}
1327
Mathias Krause76d51dd2014-07-16 19:43:04 +02001328static acpi_status __init WMID_set_capabilities(void)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001329{
1330 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1331 union acpi_object *obj;
1332 acpi_status status;
1333 u32 devices;
1334
Lee, Chun-Yi62fc7432017-06-20 17:06:23 +08001335 status = wmi_query_block(WMID_GUID2, 0, &out);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001336 if (ACPI_FAILURE(status))
1337 return status;
1338
1339 obj = (union acpi_object *) out.pointer;
Lee, Chun-Yif20aaba2012-12-14 16:14:26 +08001340 if (obj) {
1341 if (obj->type == ACPI_TYPE_BUFFER &&
1342 (obj->buffer.length == sizeof(u32) ||
1343 obj->buffer.length == sizeof(u64))) {
1344 devices = *((u32 *) obj->buffer.pointer);
1345 } else if (obj->type == ACPI_TYPE_INTEGER) {
1346 devices = (u32) obj->integer.value;
Lee, Chun-Yif24c96e2013-01-03 10:37:45 +08001347 } else {
1348 kfree(out.pointer);
1349 return AE_ERROR;
Lee, Chun-Yif20aaba2012-12-14 16:14:26 +08001350 }
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001351 } else {
Axel Lin66904862010-07-20 15:19:52 -07001352 kfree(out.pointer);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001353 return AE_ERROR;
1354 }
1355
Lee, Chun-Yi1fbc01a2011-08-18 18:47:34 +08001356 pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
1357 if (devices & 0x07)
1358 interface->capability |= ACER_CAP_WIRELESS;
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001359 if (devices & 0x40)
1360 interface->capability |= ACER_CAP_THREEG;
1361 if (devices & 0x10)
1362 interface->capability |= ACER_CAP_BLUETOOTH;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001363
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001364 if (!(devices & 0x20))
1365 max_brightness = 0x9;
1366
Axel Lin66904862010-07-20 15:19:52 -07001367 kfree(out.pointer);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001368 return status;
1369}
1370
1371static struct wmi_interface wmid_interface = {
1372 .type = ACER_WMID,
1373};
1374
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001375static struct wmi_interface wmid_v2_interface = {
1376 .type = ACER_WMID_v2,
1377};
1378
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001379/*
JafarAkhondalica42c112021-08-12 17:23:07 +04301380 * WMID Gaming interface
1381 */
1382
1383static acpi_status
1384WMI_gaming_execute_u64(u32 method_id, u64 in, u64 *out)
1385{
1386 struct acpi_buffer input = { (acpi_size) sizeof(u64), (void *)(&in) };
1387 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
1388 union acpi_object *obj;
1389 u32 tmp = 0;
1390 acpi_status status;
1391
1392 status = wmi_evaluate_method(WMID_GUID4, 0, method_id, &input, &result);
1393
1394 if (ACPI_FAILURE(status))
1395 return status;
1396 obj = (union acpi_object *) result.pointer;
1397
1398 if (obj) {
1399 if (obj->type == ACPI_TYPE_BUFFER) {
1400 if (obj->buffer.length == sizeof(u32))
1401 tmp = *((u32 *) obj->buffer.pointer);
1402 else if (obj->buffer.length == sizeof(u64))
1403 tmp = *((u64 *) obj->buffer.pointer);
1404 } else if (obj->type == ACPI_TYPE_INTEGER) {
1405 tmp = (u64) obj->integer.value;
1406 }
1407 }
1408
1409 if (out)
1410 *out = tmp;
1411
1412 kfree(result.pointer);
1413
1414 return status;
1415}
1416
1417static acpi_status WMID_gaming_set_u64(u64 value, u32 cap)
1418{
1419 u32 method_id = 0;
1420
1421 if (!(interface->capability & cap))
1422 return AE_BAD_PARAMETER;
1423
1424 switch (cap) {
1425 case ACER_CAP_TURBO_LED:
1426 method_id = ACER_WMID_SET_GAMING_LED_METHODID;
1427 break;
1428 case ACER_CAP_TURBO_FAN:
1429 method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR;
1430 break;
1431 case ACER_CAP_TURBO_OC:
1432 method_id = ACER_WMID_SET_GAMING_MISC_SETTING_METHODID;
1433 break;
1434 default:
1435 return AE_BAD_PARAMETER;
1436 }
1437
1438 return WMI_gaming_execute_u64(method_id, value, NULL);
1439}
1440
1441static acpi_status WMID_gaming_get_u64(u64 *value, u32 cap)
1442{
1443 acpi_status status;
1444 u64 result;
1445 u64 input;
1446 u32 method_id;
1447
1448 if (!(interface->capability & cap))
1449 return AE_BAD_PARAMETER;
1450
1451 switch (cap) {
1452 case ACER_CAP_TURBO_LED:
1453 method_id = ACER_WMID_GET_GAMING_LED_METHODID;
1454 input = 0x1;
1455 break;
1456 default:
1457 return AE_BAD_PARAMETER;
1458 }
1459 status = WMI_gaming_execute_u64(method_id, input, &result);
1460 if (ACPI_SUCCESS(status))
1461 *value = (u64) result;
1462
1463 return status;
1464}
1465
1466static void WMID_gaming_set_fan_mode(u8 fan_mode)
1467{
1468 /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/
1469 u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0;
1470 int i;
1471
1472 if (quirks->cpu_fans > 0)
1473 gpu_fan_config2 |= 1;
1474 for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
1475 gpu_fan_config2 |= 1 << (i + 1);
1476 for (i = 0; i < quirks->gpu_fans; ++i)
1477 gpu_fan_config2 |= 1 << (i + 3);
1478 if (quirks->cpu_fans > 0)
1479 gpu_fan_config1 |= fan_mode;
1480 for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
1481 gpu_fan_config1 |= fan_mode << (2 * i + 2);
1482 for (i = 0; i < quirks->gpu_fans; ++i)
1483 gpu_fan_config1 |= fan_mode << (2 * i + 6);
1484 WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN);
1485}
1486
1487/*
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001488 * Generic Device (interface-independent)
1489 */
1490
1491static acpi_status get_u32(u32 *value, u32 cap)
1492{
Lin Ming08237972008-08-08 11:57:11 +08001493 acpi_status status = AE_ERROR;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001494
1495 switch (interface->type) {
1496 case ACER_AMW0:
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001497 status = AMW0_get_u32(value, cap);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001498 break;
1499 case ACER_AMW0_V2:
1500 if (cap == ACER_CAP_MAILLED) {
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001501 status = AMW0_get_u32(value, cap);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001502 break;
1503 }
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001504 fallthrough;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001505 case ACER_WMID:
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001506 status = WMID_get_u32(value, cap);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001507 break;
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001508 case ACER_WMID_v2:
1509 if (cap & (ACER_CAP_WIRELESS |
1510 ACER_CAP_BLUETOOTH |
1511 ACER_CAP_THREEG))
1512 status = wmid_v2_get_u32(value, cap);
1513 else if (wmi_has_guid(WMID_GUID2))
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001514 status = WMID_get_u32(value, cap);
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001515 break;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001516 }
1517
1518 return status;
1519}
1520
1521static acpi_status set_u32(u32 value, u32 cap)
1522{
Carlos Corbacho5c742b42008-08-06 19:13:56 +01001523 acpi_status status;
1524
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001525 if (interface->capability & cap) {
1526 switch (interface->type) {
1527 case ACER_AMW0:
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001528 return AMW0_set_u32(value, cap);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001529 case ACER_AMW0_V2:
Carlos Corbacho5c742b42008-08-06 19:13:56 +01001530 if (cap == ACER_CAP_MAILLED)
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001531 return AMW0_set_u32(value, cap);
Carlos Corbacho5c742b42008-08-06 19:13:56 +01001532
1533 /*
1534 * On some models, some WMID methods don't toggle
1535 * properly. For those cases, we want to run the AMW0
1536 * method afterwards to be certain we've really toggled
1537 * the device state.
1538 */
1539 if (cap == ACER_CAP_WIRELESS ||
1540 cap == ACER_CAP_BLUETOOTH) {
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001541 status = WMID_set_u32(value, cap);
Carlos Corbacho5c742b42008-08-06 19:13:56 +01001542 if (ACPI_FAILURE(status))
1543 return status;
1544
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001545 return AMW0_set_u32(value, cap);
Carlos Corbacho5c742b42008-08-06 19:13:56 +01001546 }
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001547 fallthrough;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001548 case ACER_WMID:
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001549 return WMID_set_u32(value, cap);
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001550 case ACER_WMID_v2:
1551 if (cap & (ACER_CAP_WIRELESS |
1552 ACER_CAP_BLUETOOTH |
1553 ACER_CAP_THREEG))
1554 return wmid_v2_set_u32(value, cap);
1555 else if (wmi_has_guid(WMID_GUID2))
Lee, Chun-Yi38db1572012-01-09 14:26:44 +08001556 return WMID_set_u32(value, cap);
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001557 fallthrough;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001558 default:
1559 return AE_BAD_PARAMETER;
1560 }
1561 }
1562 return AE_BAD_PARAMETER;
1563}
1564
1565static void __init acer_commandline_init(void)
1566{
1567 /*
1568 * These will all fail silently if the value given is invalid, or the
1569 * capability isn't available on the given interface
1570 */
Lee, Chun-Yic2647b52011-04-15 18:42:47 +08001571 if (mailled >= 0)
1572 set_u32(mailled, ACER_CAP_MAILLED);
1573 if (!has_type_aa && threeg >= 0)
Lee, Chun-Yi6c3df882010-12-07 10:29:23 +08001574 set_u32(threeg, ACER_CAP_THREEG);
Lee, Chun-Yic2647b52011-04-15 18:42:47 +08001575 if (brightness >= 0)
1576 set_u32(brightness, ACER_CAP_BRIGHTNESS);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001577}
1578
1579/*
1580 * LED device (Mail LED only, no other LEDs known yet)
1581 */
1582static void mail_led_set(struct led_classdev *led_cdev,
1583enum led_brightness value)
1584{
1585 set_u32(value, ACER_CAP_MAILLED);
1586}
1587
1588static struct led_classdev mail_led = {
Carlos Corbacho343c0042008-02-24 13:34:18 +00001589 .name = "acer-wmi::mail",
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001590 .brightness_set = mail_led_set,
1591};
1592
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001593static int acer_led_init(struct device *dev)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001594{
1595 return led_classdev_register(dev, &mail_led);
1596}
1597
1598static void acer_led_exit(void)
1599{
Pali Rohár9a0b74f2011-02-26 21:18:58 +01001600 set_u32(LED_OFF, ACER_CAP_MAILLED);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001601 led_classdev_unregister(&mail_led);
1602}
1603
1604/*
1605 * Backlight device
1606 */
1607static struct backlight_device *acer_backlight_device;
1608
1609static int read_brightness(struct backlight_device *bd)
1610{
1611 u32 value;
1612 get_u32(&value, ACER_CAP_BRIGHTNESS);
1613 return value;
1614}
1615
1616static int update_bl_status(struct backlight_device *bd)
1617{
Carlos Corbachof2b585b2008-06-21 09:09:27 +01001618 int intensity = bd->props.brightness;
1619
1620 if (bd->props.power != FB_BLANK_UNBLANK)
1621 intensity = 0;
1622 if (bd->props.fb_blank != FB_BLANK_UNBLANK)
1623 intensity = 0;
1624
1625 set_u32(intensity, ACER_CAP_BRIGHTNESS);
1626
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001627 return 0;
1628}
1629
Lionel Debrouxacc24722010-11-16 14:14:02 +01001630static const struct backlight_ops acer_bl_ops = {
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001631 .get_brightness = read_brightness,
1632 .update_status = update_bl_status,
1633};
1634
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001635static int acer_backlight_init(struct device *dev)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001636{
Matthew Garretta19a6ee2010-02-17 16:39:44 -05001637 struct backlight_properties props;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001638 struct backlight_device *bd;
1639
Matthew Garretta19a6ee2010-02-17 16:39:44 -05001640 memset(&props, 0, sizeof(struct backlight_properties));
Matthew Garrettbb7ca742011-03-22 16:30:21 -07001641 props.type = BACKLIGHT_PLATFORM;
Matthew Garretta19a6ee2010-02-17 16:39:44 -05001642 props.max_brightness = max_brightness;
1643 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
1644 &props);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001645 if (IS_ERR(bd)) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08001646 pr_err("Could not register Acer backlight device\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001647 acer_backlight_device = NULL;
1648 return PTR_ERR(bd);
1649 }
1650
1651 acer_backlight_device = bd;
1652
Carlos Corbachof2b585b2008-06-21 09:09:27 +01001653 bd->props.power = FB_BLANK_UNBLANK;
Carlos Corbacho6f6ef822009-12-26 19:24:31 +00001654 bd->props.brightness = read_brightness(bd);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001655 backlight_update_status(bd);
1656 return 0;
1657}
1658
Sam Ravnborg7560e382008-02-17 13:22:54 +01001659static void acer_backlight_exit(void)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00001660{
1661 backlight_device_unregister(acer_backlight_device);
1662}
1663
1664/*
Marek Vasut1eb3fe12012-06-01 19:11:22 +02001665 * Accelerometer device
1666 */
1667static acpi_handle gsensor_handle;
1668
1669static int acer_gsensor_init(void)
1670{
1671 acpi_status status;
1672 struct acpi_buffer output;
1673 union acpi_object out_obj;
1674
1675 output.length = sizeof(out_obj);
1676 output.pointer = &out_obj;
1677 status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
1678 if (ACPI_FAILURE(status))
1679 return -1;
1680
1681 return 0;
1682}
1683
1684static int acer_gsensor_open(struct input_dev *input)
1685{
1686 return acer_gsensor_init();
1687}
1688
1689static int acer_gsensor_event(void)
1690{
1691 acpi_status status;
1692 struct acpi_buffer output;
1693 union acpi_object out_obj[5];
1694
Hans de Goede9feb0762020-10-19 20:56:25 +02001695 if (!acer_wmi_accel_dev)
Marek Vasut1eb3fe12012-06-01 19:11:22 +02001696 return -1;
1697
1698 output.length = sizeof(out_obj);
1699 output.pointer = out_obj;
1700
1701 status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
1702 if (ACPI_FAILURE(status))
1703 return -1;
1704
1705 if (out_obj->package.count != 4)
1706 return -1;
1707
1708 input_report_abs(acer_wmi_accel_dev, ABS_X,
1709 (s16)out_obj->package.elements[0].integer.value);
1710 input_report_abs(acer_wmi_accel_dev, ABS_Y,
1711 (s16)out_obj->package.elements[1].integer.value);
1712 input_report_abs(acer_wmi_accel_dev, ABS_Z,
1713 (s16)out_obj->package.elements[2].integer.value);
1714 input_sync(acer_wmi_accel_dev);
1715 return 0;
1716}
1717
1718/*
JafarAkhondalica42c112021-08-12 17:23:07 +04301719 * Predator series turbo button
1720 */
1721static int acer_toggle_turbo(void)
1722{
1723 u64 turbo_led_state;
1724
1725 /* Get current state from turbo button */
1726 if (ACPI_FAILURE(WMID_gaming_get_u64(&turbo_led_state, ACER_CAP_TURBO_LED)))
1727 return -1;
1728
1729 if (turbo_led_state) {
1730 /* Turn off turbo led */
1731 WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED);
1732
1733 /* Set FAN mode to auto */
1734 WMID_gaming_set_fan_mode(0x1);
1735
1736 /* Set OC to normal */
1737 WMID_gaming_set_u64(0x5, ACER_CAP_TURBO_OC);
1738 WMID_gaming_set_u64(0x7, ACER_CAP_TURBO_OC);
1739 } else {
1740 /* Turn on turbo led */
1741 WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED);
1742
1743 /* Set FAN mode to turbo */
1744 WMID_gaming_set_fan_mode(0x2);
1745
1746 /* Set OC to turbo mode */
1747 WMID_gaming_set_u64(0x205, ACER_CAP_TURBO_OC);
1748 WMID_gaming_set_u64(0x207, ACER_CAP_TURBO_OC);
1749 }
1750 return turbo_led_state;
1751}
1752
1753/*
Hans de Goede5c54cb62020-10-19 20:56:28 +02001754 * Switch series keyboard dock status
1755 */
1756static int acer_kbd_dock_state_to_sw_tablet_mode(u8 kbd_dock_state)
1757{
1758 switch (kbd_dock_state) {
1759 case 0x01: /* Docked, traditional clamshell laptop mode */
1760 return 0;
1761 case 0x04: /* Stand-alone tablet */
1762 case 0x40: /* Docked, tent mode, keyboard not usable */
1763 return 1;
1764 default:
1765 pr_warn("Unknown kbd_dock_state 0x%02x\n", kbd_dock_state);
1766 }
1767
1768 return 0;
1769}
1770
1771static void acer_kbd_dock_get_initial_state(void)
1772{
1773 u8 *output, input[8] = { 0x05, 0x00, };
1774 struct acpi_buffer input_buf = { sizeof(input), input };
1775 struct acpi_buffer output_buf = { ACPI_ALLOCATE_BUFFER, NULL };
1776 union acpi_object *obj;
1777 acpi_status status;
1778 int sw_tablet_mode;
1779
1780 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input_buf, &output_buf);
1781 if (ACPI_FAILURE(status)) {
Hans de Goedeef14f0e2021-02-04 15:02:05 +01001782 pr_err("Error getting keyboard-dock initial status: %s\n",
1783 acpi_format_exception(status));
Hans de Goede5c54cb62020-10-19 20:56:28 +02001784 return;
1785 }
1786
1787 obj = output_buf.pointer;
1788 if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
1789 pr_err("Unexpected output format getting keyboard-dock initial status\n");
1790 goto out_free_obj;
1791 }
1792
1793 output = obj->buffer.pointer;
1794 if (output[0] != 0x00 || (output[3] != 0x05 && output[3] != 0x45)) {
1795 pr_err("Unexpected output [0]=0x%02x [3]=0x%02x getting keyboard-dock initial status\n",
1796 output[0], output[3]);
1797 goto out_free_obj;
1798 }
1799
1800 sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(output[4]);
1801 input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
1802
1803out_free_obj:
1804 kfree(obj);
1805}
1806
1807static void acer_kbd_dock_event(const struct event_return_value *event)
1808{
1809 int sw_tablet_mode;
1810
1811 if (!has_cap(ACER_CAP_KBD_DOCK))
1812 return;
1813
1814 sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(event->kbd_dock_state);
1815 input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode);
1816 input_sync(acer_wmi_input_dev);
1817}
1818
1819/*
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001820 * Rfkill devices
1821 */
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001822static void acer_rfkill_update(struct work_struct *ignored);
1823static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
1824static void acer_rfkill_update(struct work_struct *ignored)
1825{
1826 u32 state;
1827 acpi_status status;
1828
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001829 if (has_cap(ACER_CAP_WIRELESS)) {
1830 status = get_u32(&state, ACER_CAP_WIRELESS);
1831 if (ACPI_SUCCESS(status)) {
1832 if (quirks->wireless == 3)
1833 rfkill_set_hw_state(wireless_rfkill, !state);
1834 else
1835 rfkill_set_sw_state(wireless_rfkill, !state);
Lee, Chun-Yi15b956a2011-07-30 17:00:45 +08001836 }
1837 }
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001838
1839 if (has_cap(ACER_CAP_BLUETOOTH)) {
1840 status = get_u32(&state, ACER_CAP_BLUETOOTH);
1841 if (ACPI_SUCCESS(status))
Troy Mourea8784172009-06-17 11:51:56 +01001842 rfkill_set_sw_state(bluetooth_rfkill, !state);
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001843 }
1844
Lee, Chun-Yib3c90922010-12-07 10:29:22 +08001845 if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001846 status = get_u32(&state, ACER_WMID3_GDS_THREEG);
Lee, Chun-Yib3c90922010-12-07 10:29:22 +08001847 if (ACPI_SUCCESS(status))
1848 rfkill_set_sw_state(threeg_rfkill, !state);
1849 }
1850
Carlos Corbachoae3a1b42008-10-10 17:33:35 +01001851 schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001852}
1853
Johannes Berg19d337d2009-06-02 13:01:37 +02001854static int acer_rfkill_set(void *data, bool blocked)
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001855{
1856 acpi_status status;
Johannes Berg19d337d2009-06-02 13:01:37 +02001857 u32 cap = (unsigned long)data;
Lee, Chun-Yi8215af02011-03-28 16:52:02 +08001858
1859 if (rfkill_inited) {
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001860 status = set_u32(!blocked, cap);
Lee, Chun-Yi8215af02011-03-28 16:52:02 +08001861 if (ACPI_FAILURE(status))
1862 return -ENODEV;
1863 }
1864
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001865 return 0;
1866}
1867
Johannes Berg19d337d2009-06-02 13:01:37 +02001868static const struct rfkill_ops acer_rfkill_ops = {
1869 .set_block = acer_rfkill_set,
1870};
1871
1872static struct rfkill *acer_rfkill_register(struct device *dev,
1873 enum rfkill_type type,
1874 char *name, u32 cap)
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001875{
1876 int err;
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001877 struct rfkill *rfkill_dev;
Lee, Chun-Yi466449c2010-12-13 10:02:41 +08001878 u32 state;
1879 acpi_status status;
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001880
Johannes Berg19d337d2009-06-02 13:01:37 +02001881 rfkill_dev = rfkill_alloc(name, dev, type,
1882 &acer_rfkill_ops,
1883 (void *)(unsigned long)cap);
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001884 if (!rfkill_dev)
1885 return ERR_PTR(-ENOMEM);
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001886
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08001887 status = get_u32(&state, cap);
Lee, Chun-Yi466449c2010-12-13 10:02:41 +08001888
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001889 err = rfkill_register(rfkill_dev);
1890 if (err) {
Johannes Berg19d337d2009-06-02 13:01:37 +02001891 rfkill_destroy(rfkill_dev);
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001892 return ERR_PTR(err);
1893 }
Lee, Chun-Yi8215af02011-03-28 16:52:02 +08001894
1895 if (ACPI_SUCCESS(status))
1896 rfkill_set_sw_state(rfkill_dev, !state);
1897
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001898 return rfkill_dev;
1899}
1900
1901static int acer_rfkill_init(struct device *dev)
1902{
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001903 int err;
1904
1905 if (has_cap(ACER_CAP_WIRELESS)) {
1906 wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
1907 "acer-wireless", ACER_CAP_WIRELESS);
1908 if (IS_ERR(wireless_rfkill)) {
1909 err = PTR_ERR(wireless_rfkill);
1910 goto error_wireless;
1911 }
1912 }
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001913
1914 if (has_cap(ACER_CAP_BLUETOOTH)) {
1915 bluetooth_rfkill = acer_rfkill_register(dev,
1916 RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
1917 ACER_CAP_BLUETOOTH);
1918 if (IS_ERR(bluetooth_rfkill)) {
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001919 err = PTR_ERR(bluetooth_rfkill);
1920 goto error_bluetooth;
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001921 }
1922 }
1923
Lee, Chun-Yib3c90922010-12-07 10:29:22 +08001924 if (has_cap(ACER_CAP_THREEG)) {
1925 threeg_rfkill = acer_rfkill_register(dev,
1926 RFKILL_TYPE_WWAN, "acer-threeg",
1927 ACER_CAP_THREEG);
1928 if (IS_ERR(threeg_rfkill)) {
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001929 err = PTR_ERR(threeg_rfkill);
1930 goto error_threeg;
Lee, Chun-Yib3c90922010-12-07 10:29:22 +08001931 }
1932 }
1933
Lee, Chun-Yi8215af02011-03-28 16:52:02 +08001934 rfkill_inited = true;
1935
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001936 if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1937 has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
Lee, Chun-Yi70a9b902011-03-28 06:34:13 -04001938 schedule_delayed_work(&acer_rfkill_work,
1939 round_jiffies_relative(HZ));
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001940
1941 return 0;
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001942
1943error_threeg:
1944 if (has_cap(ACER_CAP_BLUETOOTH)) {
1945 rfkill_unregister(bluetooth_rfkill);
1946 rfkill_destroy(bluetooth_rfkill);
1947 }
1948error_bluetooth:
1949 if (has_cap(ACER_CAP_WIRELESS)) {
1950 rfkill_unregister(wireless_rfkill);
1951 rfkill_destroy(wireless_rfkill);
1952 }
1953error_wireless:
1954 return err;
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001955}
1956
1957static void acer_rfkill_exit(void)
1958{
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001959 if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
1960 has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
Lee, Chun-Yi70a9b902011-03-28 06:34:13 -04001961 cancel_delayed_work_sync(&acer_rfkill_work);
Johannes Berg19d337d2009-06-02 13:01:37 +02001962
Lee, Chun-Yi1709ada2011-08-18 18:47:33 +08001963 if (has_cap(ACER_CAP_WIRELESS)) {
1964 rfkill_unregister(wireless_rfkill);
1965 rfkill_destroy(wireless_rfkill);
1966 }
Johannes Berg19d337d2009-06-02 13:01:37 +02001967
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001968 if (has_cap(ACER_CAP_BLUETOOTH)) {
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001969 rfkill_unregister(bluetooth_rfkill);
Johannes Berg19d337d2009-06-02 13:01:37 +02001970 rfkill_destroy(bluetooth_rfkill);
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001971 }
Lee, Chun-Yib3c90922010-12-07 10:29:22 +08001972
1973 if (has_cap(ACER_CAP_THREEG)) {
1974 rfkill_unregister(threeg_rfkill);
1975 rfkill_destroy(threeg_rfkill);
1976 }
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01001977 return;
1978}
1979
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08001980static void acer_wmi_notify(u32 value, void *context)
1981{
1982 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1983 union acpi_object *obj;
1984 struct event_return_value return_value;
1985 acpi_status status;
Seth Forshee92530662011-06-21 12:00:33 -05001986 u16 device_state;
1987 const struct key_entry *key;
Lee, Chun-Yi8e2286c2012-12-14 16:14:27 +08001988 u32 scancode;
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08001989
1990 status = wmi_get_event_data(value, &response);
1991 if (status != AE_OK) {
Joe Perches249c7202011-03-29 15:21:34 -07001992 pr_warn("bad event status 0x%x\n", status);
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08001993 return;
1994 }
1995
1996 obj = (union acpi_object *)response.pointer;
1997
1998 if (!obj)
1999 return;
2000 if (obj->type != ACPI_TYPE_BUFFER) {
Joe Perches249c7202011-03-29 15:21:34 -07002001 pr_warn("Unknown response received %d\n", obj->type);
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002002 kfree(obj);
2003 return;
2004 }
2005 if (obj->buffer.length != 8) {
Joe Perches249c7202011-03-29 15:21:34 -07002006 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002007 kfree(obj);
2008 return;
2009 }
2010
2011 return_value = *((struct event_return_value *)obj->buffer.pointer);
2012 kfree(obj);
2013
2014 switch (return_value.function) {
2015 case WMID_HOTKEY_EVENT:
Seth Forshee92530662011-06-21 12:00:33 -05002016 device_state = return_value.device_state;
2017 pr_debug("device state: 0x%x\n", device_state);
2018
2019 key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
2020 return_value.key_num);
2021 if (!key) {
Joe Perches249c7202011-03-29 15:21:34 -07002022 pr_warn("Unknown key number - 0x%x\n",
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002023 return_value.key_num);
Seth Forshee92530662011-06-21 12:00:33 -05002024 } else {
Lee, Chun-Yi8e2286c2012-12-14 16:14:27 +08002025 scancode = return_value.key_num;
Seth Forshee92530662011-06-21 12:00:33 -05002026 switch (key->keycode) {
2027 case KEY_WLAN:
2028 case KEY_BLUETOOTH:
2029 if (has_cap(ACER_CAP_WIRELESS))
2030 rfkill_set_sw_state(wireless_rfkill,
2031 !(device_state & ACER_WMID3_GDS_WIRELESS));
2032 if (has_cap(ACER_CAP_THREEG))
2033 rfkill_set_sw_state(threeg_rfkill,
2034 !(device_state & ACER_WMID3_GDS_THREEG));
2035 if (has_cap(ACER_CAP_BLUETOOTH))
2036 rfkill_set_sw_state(bluetooth_rfkill,
2037 !(device_state & ACER_WMID3_GDS_BLUETOOTH));
2038 break;
Lee, Chun-Yi8e2286c2012-12-14 16:14:27 +08002039 case KEY_TOUCHPAD_TOGGLE:
2040 scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ?
2041 KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF;
Seth Forshee92530662011-06-21 12:00:33 -05002042 }
Lee, Chun-Yi8e2286c2012-12-14 16:14:27 +08002043 sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
Seth Forshee92530662011-06-21 12:00:33 -05002044 }
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002045 break;
Hans de Goede5c54cb62020-10-19 20:56:28 +02002046 case WMID_ACCEL_OR_KBD_DOCK_EVENT:
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002047 acer_gsensor_event();
Hans de Goede5c54cb62020-10-19 20:56:28 +02002048 acer_kbd_dock_event(&return_value);
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002049 break;
JafarAkhondalica42c112021-08-12 17:23:07 +04302050 case WMID_GAMING_TURBO_KEY_EVENT:
2051 if (return_value.key_num == 0x4)
2052 acer_toggle_turbo();
2053 break;
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002054 default:
Joe Perches249c7202011-03-29 15:21:34 -07002055 pr_warn("Unknown function number - %d - %d\n",
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002056 return_value.function, return_value.key_num);
2057 break;
2058 }
2059}
2060
Mathias Krause76d51dd2014-07-16 19:43:04 +02002061static acpi_status __init
Chris Chiu280642c2017-02-08 07:51:40 -06002062wmid3_set_function_mode(struct func_input_params *params,
2063 struct func_return_value *return_value)
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002064{
2065 acpi_status status;
2066 union acpi_object *obj;
2067
Chris Chiu280642c2017-02-08 07:51:40 -06002068 struct acpi_buffer input = { sizeof(struct func_input_params), params };
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002069 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
2070
2071 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
2072 if (ACPI_FAILURE(status))
2073 return status;
2074
2075 obj = output.pointer;
2076
2077 if (!obj)
2078 return AE_ERROR;
2079 else if (obj->type != ACPI_TYPE_BUFFER) {
2080 kfree(obj);
2081 return AE_ERROR;
2082 }
2083 if (obj->buffer.length != 4) {
Joe Perches249c7202011-03-29 15:21:34 -07002084 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002085 kfree(obj);
2086 return AE_ERROR;
2087 }
2088
Chris Chiu280642c2017-02-08 07:51:40 -06002089 *return_value = *((struct func_return_value *)obj->buffer.pointer);
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002090 kfree(obj);
2091
2092 return status;
2093}
2094
Mathias Krause76d51dd2014-07-16 19:43:04 +02002095static int __init acer_wmi_enable_ec_raw(void)
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002096{
Chris Chiu280642c2017-02-08 07:51:40 -06002097 struct func_return_value return_value;
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002098 acpi_status status;
Chris Chiu280642c2017-02-08 07:51:40 -06002099 struct func_input_params params = {
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002100 .function_num = 0x1,
2101 .commun_devices = 0xFFFF,
2102 .devices = 0xFFFF,
Chris Chiu280642c2017-02-08 07:51:40 -06002103 .app_status = 0x00, /* Launch Manager Deactive */
2104 .app_mask = 0x01,
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002105 };
2106
Chris Chiu280642c2017-02-08 07:51:40 -06002107 status = wmid3_set_function_mode(&params, &return_value);
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002108
2109 if (return_value.error_code || return_value.ec_return_value)
Joe Perches249c7202011-03-29 15:21:34 -07002110 pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
2111 return_value.error_code,
2112 return_value.ec_return_value);
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002113 else
Joe Perches249c7202011-03-29 15:21:34 -07002114 pr_info("Enabled EC raw mode\n");
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002115
2116 return status;
2117}
2118
Mathias Krause76d51dd2014-07-16 19:43:04 +02002119static int __init acer_wmi_enable_lm(void)
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002120{
Chris Chiu280642c2017-02-08 07:51:40 -06002121 struct func_return_value return_value;
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002122 acpi_status status;
Chris Chiu280642c2017-02-08 07:51:40 -06002123 struct func_input_params params = {
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002124 .function_num = 0x1,
2125 .commun_devices = 0xFFFF,
2126 .devices = 0xFFFF,
Chris Chiu280642c2017-02-08 07:51:40 -06002127 .app_status = 0x01, /* Launch Manager Active */
2128 .app_mask = 0x01,
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002129 };
2130
Chris Chiu280642c2017-02-08 07:51:40 -06002131 status = wmid3_set_function_mode(&params, &return_value);
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002132
2133 if (return_value.error_code || return_value.ec_return_value)
Joe Perches249c7202011-03-29 15:21:34 -07002134 pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
2135 return_value.error_code,
2136 return_value.ec_return_value);
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002137
2138 return status;
2139}
2140
Chris Chiu280642c2017-02-08 07:51:40 -06002141static int __init acer_wmi_enable_rf_button(void)
2142{
2143 struct func_return_value return_value;
2144 acpi_status status;
2145 struct func_input_params params = {
2146 .function_num = 0x1,
2147 .commun_devices = 0xFFFF,
2148 .devices = 0xFFFF,
2149 .app_status = 0x10, /* RF Button Active */
2150 .app_mask = 0x10,
2151 };
2152
2153 status = wmid3_set_function_mode(&params, &return_value);
2154
2155 if (return_value.error_code || return_value.ec_return_value)
2156 pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n",
2157 return_value.error_code,
2158 return_value.ec_return_value);
2159
2160 return status;
2161}
2162
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002163static int __init acer_wmi_accel_setup(void)
2164{
Andy Shevchenko6fe93632019-07-23 23:34:11 +03002165 struct acpi_device *adev;
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002166 int err;
2167
Andy Shevchenko6fe93632019-07-23 23:34:11 +03002168 adev = acpi_dev_get_first_match_dev("BST0001", NULL, -1);
2169 if (!adev)
2170 return -ENODEV;
2171
2172 gsensor_handle = acpi_device_handle(adev);
2173 acpi_dev_put(adev);
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002174
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002175 acer_wmi_accel_dev = input_allocate_device();
2176 if (!acer_wmi_accel_dev)
2177 return -ENOMEM;
2178
2179 acer_wmi_accel_dev->open = acer_gsensor_open;
2180
2181 acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
2182 acer_wmi_accel_dev->phys = "wmi/input1";
2183 acer_wmi_accel_dev->id.bustype = BUS_HOST;
2184 acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
2185 input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
2186 input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
2187 input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
2188
2189 err = input_register_device(acer_wmi_accel_dev);
2190 if (err)
2191 goto err_free_dev;
2192
2193 return 0;
2194
2195err_free_dev:
2196 input_free_device(acer_wmi_accel_dev);
2197 return err;
2198}
2199
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002200static int __init acer_wmi_input_setup(void)
2201{
2202 acpi_status status;
2203 int err;
2204
2205 acer_wmi_input_dev = input_allocate_device();
2206 if (!acer_wmi_input_dev)
2207 return -ENOMEM;
2208
2209 acer_wmi_input_dev->name = "Acer WMI hotkeys";
2210 acer_wmi_input_dev->phys = "wmi/input0";
2211 acer_wmi_input_dev->id.bustype = BUS_HOST;
2212
2213 err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
2214 if (err)
2215 goto err_free_dev;
2216
Hans de Goede5c54cb62020-10-19 20:56:28 +02002217 if (has_cap(ACER_CAP_KBD_DOCK))
2218 input_set_capability(acer_wmi_input_dev, EV_SW, SW_TABLET_MODE);
2219
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002220 status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
2221 acer_wmi_notify, NULL);
2222 if (ACPI_FAILURE(status)) {
2223 err = -EIO;
Michał Kępieńcd1aaef2017-03-09 13:11:37 +01002224 goto err_free_dev;
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002225 }
2226
Hans de Goede5c54cb62020-10-19 20:56:28 +02002227 if (has_cap(ACER_CAP_KBD_DOCK))
2228 acer_kbd_dock_get_initial_state();
2229
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002230 err = input_register_device(acer_wmi_input_dev);
2231 if (err)
2232 goto err_uninstall_notifier;
2233
2234 return 0;
2235
2236err_uninstall_notifier:
2237 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002238err_free_dev:
2239 input_free_device(acer_wmi_input_dev);
2240 return err;
2241}
2242
2243static void acer_wmi_input_destroy(void)
2244{
2245 wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002246 input_unregister_device(acer_wmi_input_dev);
2247}
2248
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002249/*
Carlos Corbacho81143522008-06-21 09:09:53 +01002250 * debugfs functions
2251 */
2252static u32 get_wmid_devices(void)
2253{
2254 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
2255 union acpi_object *obj;
2256 acpi_status status;
Axel Lin66904862010-07-20 15:19:52 -07002257 u32 devices = 0;
Carlos Corbacho81143522008-06-21 09:09:53 +01002258
Lee, Chun-Yi62fc7432017-06-20 17:06:23 +08002259 status = wmi_query_block(WMID_GUID2, 0, &out);
Carlos Corbacho81143522008-06-21 09:09:53 +01002260 if (ACPI_FAILURE(status))
2261 return 0;
2262
2263 obj = (union acpi_object *) out.pointer;
Lee, Chun-Yif20aaba2012-12-14 16:14:26 +08002264 if (obj) {
2265 if (obj->type == ACPI_TYPE_BUFFER &&
2266 (obj->buffer.length == sizeof(u32) ||
2267 obj->buffer.length == sizeof(u64))) {
2268 devices = *((u32 *) obj->buffer.pointer);
2269 } else if (obj->type == ACPI_TYPE_INTEGER) {
2270 devices = (u32) obj->integer.value;
2271 }
Carlos Corbacho81143522008-06-21 09:09:53 +01002272 }
Axel Lin66904862010-07-20 15:19:52 -07002273
2274 kfree(out.pointer);
2275 return devices;
Carlos Corbacho81143522008-06-21 09:09:53 +01002276}
2277
2278/*
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002279 * Platform device
2280 */
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002281static int acer_platform_probe(struct platform_device *device)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002282{
2283 int err;
2284
2285 if (has_cap(ACER_CAP_MAILLED)) {
2286 err = acer_led_init(&device->dev);
2287 if (err)
2288 goto error_mailled;
2289 }
2290
2291 if (has_cap(ACER_CAP_BRIGHTNESS)) {
2292 err = acer_backlight_init(&device->dev);
2293 if (err)
2294 goto error_brightness;
2295 }
2296
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01002297 err = acer_rfkill_init(&device->dev);
Andy Whitcroft350e3292009-04-04 09:33:34 +01002298 if (err)
2299 goto error_rfkill;
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01002300
2301 return err;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002302
Andy Whitcroft350e3292009-04-04 09:33:34 +01002303error_rfkill:
2304 if (has_cap(ACER_CAP_BRIGHTNESS))
2305 acer_backlight_exit();
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002306error_brightness:
Andy Whitcroft350e3292009-04-04 09:33:34 +01002307 if (has_cap(ACER_CAP_MAILLED))
2308 acer_led_exit();
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002309error_mailled:
2310 return err;
2311}
2312
2313static int acer_platform_remove(struct platform_device *device)
2314{
2315 if (has_cap(ACER_CAP_MAILLED))
2316 acer_led_exit();
2317 if (has_cap(ACER_CAP_BRIGHTNESS))
2318 acer_backlight_exit();
Carlos Corbacho0606e1a2008-10-08 21:40:21 +01002319
2320 acer_rfkill_exit();
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002321 return 0;
2322}
2323
Mathias Krause80f65552014-07-16 19:43:06 +02002324#ifdef CONFIG_PM_SLEEP
Rafael J. Wysocki3c33be0b2012-06-27 23:19:35 +02002325static int acer_suspend(struct device *dev)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002326{
2327 u32 value;
2328 struct acer_data *data = &interface->data;
2329
2330 if (!data)
2331 return -ENOMEM;
2332
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002333 if (has_cap(ACER_CAP_MAILLED)) {
2334 get_u32(&value, ACER_CAP_MAILLED);
Pali Rohár9a0b74f2011-02-26 21:18:58 +01002335 set_u32(LED_OFF, ACER_CAP_MAILLED);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002336 data->mailled = value;
2337 }
2338
2339 if (has_cap(ACER_CAP_BRIGHTNESS)) {
2340 get_u32(&value, ACER_CAP_BRIGHTNESS);
2341 data->brightness = value;
2342 }
2343
2344 return 0;
2345}
2346
Rafael J. Wysocki3c33be0b2012-06-27 23:19:35 +02002347static int acer_resume(struct device *dev)
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002348{
2349 struct acer_data *data = &interface->data;
2350
2351 if (!data)
2352 return -ENOMEM;
2353
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002354 if (has_cap(ACER_CAP_MAILLED))
2355 set_u32(data->mailled, ACER_CAP_MAILLED);
2356
2357 if (has_cap(ACER_CAP_BRIGHTNESS))
2358 set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
2359
Hans de Goede9feb0762020-10-19 20:56:25 +02002360 if (acer_wmi_accel_dev)
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002361 acer_gsensor_init();
2362
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002363 return 0;
2364}
Mathias Krause80f65552014-07-16 19:43:06 +02002365#else
2366#define acer_suspend NULL
2367#define acer_resume NULL
2368#endif
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002369
Rafael J. Wysocki3c33be0b2012-06-27 23:19:35 +02002370static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
2371
Pali Rohár9a0b74f2011-02-26 21:18:58 +01002372static void acer_platform_shutdown(struct platform_device *device)
2373{
2374 struct acer_data *data = &interface->data;
2375
2376 if (!data)
2377 return;
2378
2379 if (has_cap(ACER_CAP_MAILLED))
2380 set_u32(LED_OFF, ACER_CAP_MAILLED);
2381}
2382
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002383static struct platform_driver acer_platform_driver = {
2384 .driver = {
2385 .name = "acer-wmi",
Rafael J. Wysocki3c33be0b2012-06-27 23:19:35 +02002386 .pm = &acer_pm,
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002387 },
2388 .probe = acer_platform_probe,
2389 .remove = acer_platform_remove,
Pali Rohár9a0b74f2011-02-26 21:18:58 +01002390 .shutdown = acer_platform_shutdown,
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002391};
2392
2393static struct platform_device *acer_platform_device;
2394
Carlos Corbacho81143522008-06-21 09:09:53 +01002395static void remove_debugfs(void)
2396{
Greg Kroah-Hartman0b9dd932019-06-12 14:12:51 +02002397 debugfs_remove_recursive(interface->debug.root);
Carlos Corbacho81143522008-06-21 09:09:53 +01002398}
2399
Greg Kroah-Hartman0b9dd932019-06-12 14:12:51 +02002400static void __init create_debugfs(void)
Carlos Corbacho81143522008-06-21 09:09:53 +01002401{
2402 interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
Carlos Corbacho81143522008-06-21 09:09:53 +01002403
Greg Kroah-Hartman0b9dd932019-06-12 14:12:51 +02002404 debugfs_create_u32("devices", S_IRUGO, interface->debug.root,
2405 &interface->debug.wmid_devices);
Carlos Corbacho81143522008-06-21 09:09:53 +01002406}
2407
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002408static int __init acer_wmi_init(void)
2409{
2410 int err;
2411
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002412 pr_info("Acer Laptop ACPI-WMI Extras\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002413
Carlos Corbachoa74dd5f2009-04-04 09:33:29 +01002414 if (dmi_check_system(acer_blacklist)) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002415 pr_info("Blacklisted hardware detected - not loading\n");
Carlos Corbachoa74dd5f2009-04-04 09:33:29 +01002416 return -ENODEV;
2417 }
2418
Carlos Corbacho9991d9f2008-06-21 09:09:22 +01002419 find_quirks();
2420
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002421 /*
Lee, Chun-Yi5241b192016-11-01 12:30:58 +08002422 * The AMW0_GUID1 wmi is not only found on Acer family but also other
2423 * machines like Lenovo, Fujitsu and Medion. In the past days,
2424 * acer-wmi driver handled those non-Acer machines by quirks list.
2425 * But actually acer-wmi driver was loaded on any machines that have
2426 * AMW0_GUID1. This behavior is strange because those machines should
2427 * be supported by appropriate wmi drivers. e.g. fujitsu-laptop,
2428 * ideapad-laptop. So, here checks the machine that has AMW0_GUID1
2429 * should be in Acer/Gateway/Packard Bell white list, or it's already
2430 * in the past quirk list.
2431 */
2432 if (wmi_has_guid(AMW0_GUID1) &&
2433 !dmi_check_system(amw0_whitelist) &&
2434 quirks == &quirk_unknown) {
Benjamin Herrenschmidt9bd51962018-08-16 09:27:10 +10002435 pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n");
Lee, Chun-Yi5241b192016-11-01 12:30:58 +08002436 return -ENODEV;
2437 }
2438
2439 /*
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002440 * Detect which ACPI-WMI interface we're using.
2441 */
2442 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
2443 interface = &AMW0_V2_interface;
2444
2445 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
2446 interface = &wmid_interface;
2447
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08002448 if (wmi_has_guid(WMID_GUID3))
2449 interface = &wmid_v2_interface;
2450
2451 if (interface)
2452 dmi_walk(type_aa_dmi_decode, NULL);
2453
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002454 if (wmi_has_guid(WMID_GUID2) && interface) {
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08002455 if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002456 pr_err("Unable to detect available WMID devices\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002457 return -ENODEV;
2458 }
Lee, Chun-Yi72e71de2011-08-18 18:47:32 +08002459 /* WMID always provides brightness methods */
2460 interface->capability |= ACER_CAP_BRIGHTNESS;
Hans de Goede39aa0092020-10-19 20:56:26 +02002461 } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa && force_caps == -1) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002462 pr_err("No WMID device detection method found\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002463 return -ENODEV;
2464 }
2465
2466 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
2467 interface = &AMW0_interface;
2468
2469 if (ACPI_FAILURE(AMW0_set_capabilities())) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002470 pr_err("Unable to detect available AMW0 devices\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002471 return -ENODEV;
2472 }
2473 }
2474
Carlos Corbacho9b963c42008-02-24 13:34:29 +00002475 if (wmi_has_guid(AMW0_GUID1))
2476 AMW0_find_mailled();
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002477
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002478 if (!interface) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002479 pr_err("No or unsupported WMI interface, unable to load\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002480 return -ENODEV;
2481 }
2482
Arjan van de Ven83097ac2008-08-23 21:45:21 -07002483 set_quirks();
2484
Corentin Charya60b2172012-06-13 09:32:02 +02002485 if (dmi_check_system(video_vendor_dmi_table))
Hans de Goede9a65f0d2015-06-16 16:27:55 +02002486 acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
2487
2488 if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
Corentin Charya60b2172012-06-13 09:32:02 +02002489 interface->capability &= ~ACER_CAP_BRIGHTNESS;
Thomas Renningerfebf2d92008-08-01 17:37:56 +02002490
Hans de Goede82cb8a52020-10-19 20:56:27 +02002491 if (wmi_has_guid(WMID_GUID3))
2492 interface->capability |= ACER_CAP_SET_FUNCTION_MODE;
2493
Hans de Goede39aa0092020-10-19 20:56:26 +02002494 if (force_caps != -1)
2495 interface->capability = force_caps;
2496
Hans de Goede82cb8a52020-10-19 20:56:27 +02002497 if (wmi_has_guid(WMID_GUID3) &&
2498 (interface->capability & ACER_CAP_SET_FUNCTION_MODE)) {
Chris Chiu280642c2017-02-08 07:51:40 -06002499 if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
2500 pr_warn("Cannot enable RF Button Driver\n");
2501
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002502 if (ec_raw_mode) {
2503 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002504 pr_err("Cannot enable EC raw mode\n");
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002505 return -ENODEV;
2506 }
2507 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002508 pr_err("Cannot enable Launch Manager mode\n");
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002509 return -ENODEV;
2510 }
2511 } else if (ec_raw_mode) {
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002512 pr_info("No WMID EC raw mode enable method\n");
From: Lee, Chun-Yi59ccf2f2011-01-07 17:25:14 -05002513 }
2514
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002515 if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
2516 err = acer_wmi_input_setup();
2517 if (err)
2518 return err;
Lee, Chun-Yi98d610c2016-11-03 08:18:52 +08002519 err = acer_wmi_accel_setup();
Lee, Chun-Yif9ac89f2017-04-28 16:23:59 +08002520 if (err && err != -ENODEV)
2521 pr_warn("Cannot enable accelerometer\n");
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002522 }
2523
Axel Lin1c796322010-06-22 16:17:38 +08002524 err = platform_driver_register(&acer_platform_driver);
2525 if (err) {
Joe Perches6e71f382011-11-29 11:04:05 -08002526 pr_err("Unable to register platform driver\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002527 goto error_platform_register;
2528 }
Axel Lin1c796322010-06-22 16:17:38 +08002529
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002530 acer_platform_device = platform_device_alloc("acer-wmi", -1);
Axel Lin1c796322010-06-22 16:17:38 +08002531 if (!acer_platform_device) {
2532 err = -ENOMEM;
2533 goto error_device_alloc;
2534 }
2535
2536 err = platform_device_add(acer_platform_device);
2537 if (err)
2538 goto error_device_add;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002539
Carlos Corbacho81143522008-06-21 09:09:53 +01002540 if (wmi_has_guid(WMID_GUID2)) {
2541 interface->debug.wmid_devices = get_wmid_devices();
Greg Kroah-Hartman0b9dd932019-06-12 14:12:51 +02002542 create_debugfs();
Carlos Corbacho81143522008-06-21 09:09:53 +01002543 }
2544
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002545 /* Override any initial settings with values from the commandline */
2546 acer_commandline_init();
2547
2548 return 0;
2549
Axel Lin1c796322010-06-22 16:17:38 +08002550error_device_add:
2551 platform_device_put(acer_platform_device);
2552error_device_alloc:
2553 platform_driver_unregister(&acer_platform_driver);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002554error_platform_register:
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002555 if (wmi_has_guid(ACERWMID_EVENT_GUID))
2556 acer_wmi_input_destroy();
Hans de Goede9feb0762020-10-19 20:56:25 +02002557 if (acer_wmi_accel_dev)
2558 input_unregister_device(acer_wmi_accel_dev);
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002559
Axel Lin1c796322010-06-22 16:17:38 +08002560 return err;
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002561}
2562
2563static void __exit acer_wmi_exit(void)
2564{
Lee, Chun-Yi3fdca872010-12-07 10:29:20 +08002565 if (wmi_has_guid(ACERWMID_EVENT_GUID))
2566 acer_wmi_input_destroy();
2567
Hans de Goede9feb0762020-10-19 20:56:25 +02002568 if (acer_wmi_accel_dev)
2569 input_unregister_device(acer_wmi_accel_dev);
Marek Vasut1eb3fe12012-06-01 19:11:22 +02002570
Russ Dill39dbbb42008-09-02 14:35:40 -07002571 remove_debugfs();
Axel Lin97ba0af2010-06-03 15:18:03 +08002572 platform_device_unregister(acer_platform_device);
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002573 platform_driver_unregister(&acer_platform_driver);
2574
Lee, Chun-Yicae15702011-03-16 18:52:36 +08002575 pr_info("Acer Laptop WMI Extras unloaded\n");
Carlos Corbacho745a5d22008-02-05 02:17:10 +00002576 return;
2577}
2578
2579module_init(acer_wmi_init);
2580module_exit(acer_wmi_exit);