xref: /freebsd/sys/dev/acpi_support/acpi_asus_wmi.c (revision 027b93c2f5e1b84d9e4569f127b632c704c53b73)
1461a98a2SAlexander Motin /*-
2461a98a2SAlexander Motin  * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
3461a98a2SAlexander Motin  * All rights reserved.
4461a98a2SAlexander Motin  *
5461a98a2SAlexander Motin  * Redistribution and use in source and binary forms, with or without
6461a98a2SAlexander Motin  * modification, are permitted provided that the following conditions
7461a98a2SAlexander Motin  * are met:
8461a98a2SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
9461a98a2SAlexander Motin  *    notice, this list of conditions and the following disclaimer.
10461a98a2SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
11461a98a2SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
12461a98a2SAlexander Motin  *    documentation and/or other materials provided with the distribution.
13461a98a2SAlexander Motin  *
14461a98a2SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15461a98a2SAlexander Motin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16461a98a2SAlexander Motin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17461a98a2SAlexander Motin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18461a98a2SAlexander Motin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19461a98a2SAlexander Motin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20461a98a2SAlexander Motin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21461a98a2SAlexander Motin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22461a98a2SAlexander Motin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23461a98a2SAlexander Motin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24461a98a2SAlexander Motin  * SUCH DAMAGE.
25461a98a2SAlexander Motin  */
26461a98a2SAlexander Motin 
27461a98a2SAlexander Motin #include <sys/cdefs.h>
28461a98a2SAlexander Motin #include "opt_acpi.h"
295e41194bSVladimir Kondratyev #include "opt_evdev.h"
30461a98a2SAlexander Motin #include <sys/param.h>
31461a98a2SAlexander Motin #include <sys/conf.h>
32461a98a2SAlexander Motin #include <sys/uio.h>
33461a98a2SAlexander Motin #include <sys/proc.h>
34461a98a2SAlexander Motin #include <sys/kernel.h>
35461a98a2SAlexander Motin #include <sys/bus.h>
36461a98a2SAlexander Motin #include <sys/sbuf.h>
37461a98a2SAlexander Motin #include <sys/module.h>
38461a98a2SAlexander Motin #include <sys/sysctl.h>
39461a98a2SAlexander Motin 
40461a98a2SAlexander Motin #include <contrib/dev/acpica/include/acpi.h>
41461a98a2SAlexander Motin #include <contrib/dev/acpica/include/accommon.h>
42461a98a2SAlexander Motin #include <dev/acpica/acpivar.h>
43461a98a2SAlexander Motin #include "acpi_wmi_if.h"
44461a98a2SAlexander Motin 
45f134662aSVladimir Kondratyev #include <dev/backlight/backlight.h>
46f134662aSVladimir Kondratyev #include "backlight_if.h"
47f134662aSVladimir Kondratyev 
485e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
495e41194bSVladimir Kondratyev #include <dev/evdev/input.h>
505e41194bSVladimir Kondratyev #include <dev/evdev/evdev.h>
515e41194bSVladimir Kondratyev #define NO_KEY	KEY_RESERVED
525e41194bSVladimir Kondratyev #endif
535e41194bSVladimir Kondratyev 
54461a98a2SAlexander Motin #define _COMPONENT	ACPI_OEM
55461a98a2SAlexander Motin ACPI_MODULE_NAME("ASUS-WMI")
56461a98a2SAlexander Motin 
57461a98a2SAlexander Motin #define ACPI_ASUS_WMI_MGMT_GUID 	"97845ED0-4E6D-11DE-8A39-0800200C9A66"
58461a98a2SAlexander Motin #define ACPI_ASUS_WMI_EVENT_GUID	"0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
59461a98a2SAlexander Motin #define ACPI_EEEPC_WMI_EVENT_GUID	"ABBC0F72-8EA1-11D1-00A0-C90629100000"
60461a98a2SAlexander Motin 
61461a98a2SAlexander Motin /* WMI Methods */
62461a98a2SAlexander Motin #define ASUS_WMI_METHODID_SPEC          0x43455053
63461a98a2SAlexander Motin #define ASUS_WMI_METHODID_SFUN          0x4E554653
64461a98a2SAlexander Motin #define ASUS_WMI_METHODID_DSTS          0x53544344
65461a98a2SAlexander Motin #define ASUS_WMI_METHODID_DSTS2         0x53545344
66461a98a2SAlexander Motin #define ASUS_WMI_METHODID_DEVS          0x53564544
67461a98a2SAlexander Motin #define ASUS_WMI_METHODID_INIT          0x54494E49
68461a98a2SAlexander Motin #define ASUS_WMI_METHODID_HKEY          0x59454B48
69461a98a2SAlexander Motin 
70461a98a2SAlexander Motin #define ASUS_WMI_UNSUPPORTED_METHOD     0xFFFFFFFE
71461a98a2SAlexander Motin 
72461a98a2SAlexander Motin /* Wireless */
73461a98a2SAlexander Motin #define ASUS_WMI_DEVID_HW_SWITCH        0x00010001
74461a98a2SAlexander Motin #define ASUS_WMI_DEVID_WIRELESS_LED     0x00010002
75461a98a2SAlexander Motin #define ASUS_WMI_DEVID_CWAP             0x00010003
76461a98a2SAlexander Motin #define ASUS_WMI_DEVID_WLAN             0x00010011
77461a98a2SAlexander Motin #define ASUS_WMI_DEVID_BLUETOOTH        0x00010013
78461a98a2SAlexander Motin #define ASUS_WMI_DEVID_GPS              0x00010015
79461a98a2SAlexander Motin #define ASUS_WMI_DEVID_WIMAX            0x00010017
80461a98a2SAlexander Motin #define ASUS_WMI_DEVID_WWAN3G           0x00010019
81461a98a2SAlexander Motin #define ASUS_WMI_DEVID_UWB              0x00010021
82461a98a2SAlexander Motin 
83461a98a2SAlexander Motin /* LEDs */
84461a98a2SAlexander Motin #define ASUS_WMI_DEVID_LED1             0x00020011
85461a98a2SAlexander Motin #define ASUS_WMI_DEVID_LED2             0x00020012
86461a98a2SAlexander Motin #define ASUS_WMI_DEVID_LED3             0x00020013
87461a98a2SAlexander Motin #define ASUS_WMI_DEVID_LED4             0x00020014
88461a98a2SAlexander Motin #define ASUS_WMI_DEVID_LED5             0x00020015
89461a98a2SAlexander Motin #define ASUS_WMI_DEVID_LED6             0x00020016
90461a98a2SAlexander Motin 
91461a98a2SAlexander Motin /* Backlight and Brightness */
92461a98a2SAlexander Motin #define ASUS_WMI_DEVID_BACKLIGHT        0x00050011
93461a98a2SAlexander Motin #define ASUS_WMI_DEVID_BRIGHTNESS       0x00050012
94461a98a2SAlexander Motin #define ASUS_WMI_DEVID_KBD_BACKLIGHT    0x00050021
95461a98a2SAlexander Motin #define ASUS_WMI_DEVID_LIGHT_SENSOR     0x00050022
96461a98a2SAlexander Motin 
97461a98a2SAlexander Motin /* Misc */
98461a98a2SAlexander Motin #define ASUS_WMI_DEVID_CAMERA           0x00060013
99461a98a2SAlexander Motin #define ASUS_WMI_DEVID_CARDREADER       0x00080013
100461a98a2SAlexander Motin #define ASUS_WMI_DEVID_TOUCHPAD         0x00100011
101461a98a2SAlexander Motin #define ASUS_WMI_DEVID_TOUCHPAD_LED     0x00100012
102*027b93c2SVladimir Kondratyev #define ASUS_WMI_DEVID_TUF_RGB_MODE	0x00100056
103461a98a2SAlexander Motin #define ASUS_WMI_DEVID_THERMAL_CTRL     0x00110011
104461a98a2SAlexander Motin #define ASUS_WMI_DEVID_FAN_CTRL         0x00110012
105461a98a2SAlexander Motin #define ASUS_WMI_DEVID_PROCESSOR_STATE  0x00120012
106*027b93c2SVladimir Kondratyev #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
107461a98a2SAlexander Motin 
108461a98a2SAlexander Motin /* DSTS masks */
109461a98a2SAlexander Motin #define ASUS_WMI_DSTS_STATUS_BIT        0x00000001
110461a98a2SAlexander Motin #define ASUS_WMI_DSTS_UNKNOWN_BIT       0x00000002
111461a98a2SAlexander Motin #define ASUS_WMI_DSTS_PRESENCE_BIT      0x00010000
112461a98a2SAlexander Motin #define ASUS_WMI_DSTS_USER_BIT          0x00020000
113461a98a2SAlexander Motin #define ASUS_WMI_DSTS_BIOS_BIT          0x00040000
114461a98a2SAlexander Motin #define ASUS_WMI_DSTS_BRIGHTNESS_MASK   0x000000FF
115461a98a2SAlexander Motin #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK   0x0000FF00
116461a98a2SAlexander Motin 
117d5bf6a72SVladimir Kondratyev /* Events */
118d5bf6a72SVladimir Kondratyev #define ASUS_WMI_EVENT_QUEUE_SIZE	0x10
119d5bf6a72SVladimir Kondratyev #define ASUS_WMI_EVENT_QUEUE_END	0x1
120d5bf6a72SVladimir Kondratyev #define ASUS_WMI_EVENT_MASK		0xFFFF
121d5bf6a72SVladimir Kondratyev #define ASUS_WMI_EVENT_VALUE_ATK	0xFF
122d5bf6a72SVladimir Kondratyev 
123461a98a2SAlexander Motin struct acpi_asus_wmi_softc {
124461a98a2SAlexander Motin 	device_t	dev;
125461a98a2SAlexander Motin 	device_t	wmi_dev;
126461a98a2SAlexander Motin 	const char	*notify_guid;
127461a98a2SAlexander Motin 	struct sysctl_ctx_list	*sysctl_ctx;
128461a98a2SAlexander Motin 	struct sysctl_oid	*sysctl_tree;
129461a98a2SAlexander Motin 	int		dsts_id;
130461a98a2SAlexander Motin 	int		handle_keys;
131d5bf6a72SVladimir Kondratyev 	bool		event_queue;
132f134662aSVladimir Kondratyev 	struct cdev	*kbd_bkl;
133f134662aSVladimir Kondratyev 	uint32_t	kbd_bkl_level;
134*027b93c2SVladimir Kondratyev 	uint32_t	tuf_rgb_mode;
135*027b93c2SVladimir Kondratyev 	uint32_t	ttp_mode;
1365e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
1375e41194bSVladimir Kondratyev 	struct evdev_dev	*evdev;
1385e41194bSVladimir Kondratyev #endif
139461a98a2SAlexander Motin };
140461a98a2SAlexander Motin 
141461a98a2SAlexander Motin static struct {
142461a98a2SAlexander Motin 	char	*name;
143461a98a2SAlexander Motin 	int	dev_id;
144461a98a2SAlexander Motin 	char	*description;
145f0188618SHans Petter Selasky 	int	flag_rdonly;
146461a98a2SAlexander Motin } acpi_asus_wmi_sysctls[] = {
147461a98a2SAlexander Motin 	{
148461a98a2SAlexander Motin 		.name		= "hw_switch",
149461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_HW_SWITCH,
150461a98a2SAlexander Motin 		.description	= "hw_switch",
151461a98a2SAlexander Motin 	},
152461a98a2SAlexander Motin 	{
153461a98a2SAlexander Motin 		.name		= "wireless_led",
154461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_WIRELESS_LED,
155461a98a2SAlexander Motin 		.description	= "Wireless LED control",
156461a98a2SAlexander Motin 	},
157461a98a2SAlexander Motin 	{
158461a98a2SAlexander Motin 		.name		= "cwap",
159461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_CWAP,
160461a98a2SAlexander Motin 		.description	= "Alt+F2 function",
161461a98a2SAlexander Motin 	},
162461a98a2SAlexander Motin 	{
163461a98a2SAlexander Motin 		.name		= "wlan",
164461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_WLAN,
165461a98a2SAlexander Motin 		.description	= "WLAN power control",
166461a98a2SAlexander Motin 	},
167461a98a2SAlexander Motin 	{
168461a98a2SAlexander Motin 		.name		= "bluetooth",
169461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_BLUETOOTH,
170461a98a2SAlexander Motin 		.description	= "Bluetooth power control",
171461a98a2SAlexander Motin 	},
172461a98a2SAlexander Motin 	{
173461a98a2SAlexander Motin 		.name		= "gps",
174461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_GPS,
175461a98a2SAlexander Motin 		.description	= "GPS power control",
176461a98a2SAlexander Motin 	},
177461a98a2SAlexander Motin 	{
178461a98a2SAlexander Motin 		.name		= "wimax",
179461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_WIMAX,
180461a98a2SAlexander Motin 		.description	= "WiMAX power control",
181461a98a2SAlexander Motin 	},
182461a98a2SAlexander Motin 	{
183461a98a2SAlexander Motin 		.name		= "wwan3g",
184461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_WWAN3G,
185461a98a2SAlexander Motin 		.description	= "WWAN-3G power control",
186461a98a2SAlexander Motin 	},
187461a98a2SAlexander Motin 	{
188461a98a2SAlexander Motin 		.name		= "uwb",
189461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_UWB,
190461a98a2SAlexander Motin 		.description	= "UWB power control",
191461a98a2SAlexander Motin 	},
192461a98a2SAlexander Motin 	{
193461a98a2SAlexander Motin 		.name		= "led1",
194461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_LED1,
195461a98a2SAlexander Motin 		.description	= "LED1 control",
196461a98a2SAlexander Motin 	},
197461a98a2SAlexander Motin 	{
198461a98a2SAlexander Motin 		.name		= "led2",
199461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_LED2,
200461a98a2SAlexander Motin 		.description	= "LED2 control",
201461a98a2SAlexander Motin 	},
202461a98a2SAlexander Motin 	{
203461a98a2SAlexander Motin 		.name		= "led3",
204461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_LED3,
205461a98a2SAlexander Motin 		.description	= "LED3 control",
206461a98a2SAlexander Motin 	},
207461a98a2SAlexander Motin 	{
208461a98a2SAlexander Motin 		.name		= "led4",
209461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_LED4,
210461a98a2SAlexander Motin 		.description	= "LED4 control",
211461a98a2SAlexander Motin 	},
212461a98a2SAlexander Motin 	{
213461a98a2SAlexander Motin 		.name		= "led5",
214461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_LED5,
215461a98a2SAlexander Motin 		.description	= "LED5 control",
216461a98a2SAlexander Motin 	},
217461a98a2SAlexander Motin 	{
218461a98a2SAlexander Motin 		.name		= "led6",
219461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_LED6,
220461a98a2SAlexander Motin 		.description	= "LED6 control",
221461a98a2SAlexander Motin 	},
222461a98a2SAlexander Motin 	{
223461a98a2SAlexander Motin 		.name		= "backlight",
224461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_BACKLIGHT,
225461a98a2SAlexander Motin 		.description	= "LCD backlight on/off control",
226461a98a2SAlexander Motin 	},
227461a98a2SAlexander Motin 	{
228461a98a2SAlexander Motin 		.name		= "brightness",
229461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_BRIGHTNESS,
230461a98a2SAlexander Motin 		.description	= "LCD backlight brightness control",
231461a98a2SAlexander Motin 	},
232461a98a2SAlexander Motin 	{
233461a98a2SAlexander Motin 		.name		= "kbd_backlight",
234461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_KBD_BACKLIGHT,
235461a98a2SAlexander Motin 		.description	= "Keyboard backlight brightness control",
236461a98a2SAlexander Motin 	},
237461a98a2SAlexander Motin 	{
238461a98a2SAlexander Motin 		.name		= "light_sensor",
239461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_LIGHT_SENSOR,
240461a98a2SAlexander Motin 		.description	= "Ambient light sensor",
241461a98a2SAlexander Motin 	},
242461a98a2SAlexander Motin 	{
243461a98a2SAlexander Motin 		.name		= "camera",
244461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_CAMERA,
245461a98a2SAlexander Motin 		.description	= "Camera power control",
246461a98a2SAlexander Motin 	},
247461a98a2SAlexander Motin 	{
248461a98a2SAlexander Motin 		.name		= "cardreader",
249461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_CARDREADER,
250461a98a2SAlexander Motin 		.description	= "Cardreader power control",
251461a98a2SAlexander Motin 	},
252461a98a2SAlexander Motin 	{
253461a98a2SAlexander Motin 		.name		= "touchpad",
254461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_TOUCHPAD,
255461a98a2SAlexander Motin 		.description	= "Touchpad control",
256461a98a2SAlexander Motin 	},
257461a98a2SAlexander Motin 	{
258461a98a2SAlexander Motin 		.name		= "touchpad_led",
259461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_TOUCHPAD_LED,
260461a98a2SAlexander Motin 		.description	= "Touchpad LED control",
261461a98a2SAlexander Motin 	},
262461a98a2SAlexander Motin 	{
263461a98a2SAlexander Motin 		.name		= "themperature",
264461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_THERMAL_CTRL,
265461a98a2SAlexander Motin 		.description	= "Temperature (C)",
266f0188618SHans Petter Selasky 		.flag_rdonly	= 1
267461a98a2SAlexander Motin 	},
268461a98a2SAlexander Motin 	{
269461a98a2SAlexander Motin 		.name		= "fan_speed",
270461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_FAN_CTRL,
271461a98a2SAlexander Motin 		.description	= "Fan speed (0-3)",
272f0188618SHans Petter Selasky 		.flag_rdonly	= 1
273461a98a2SAlexander Motin 	},
274461a98a2SAlexander Motin 	{
275461a98a2SAlexander Motin 		.name		= "processor_state",
276461a98a2SAlexander Motin 		.dev_id		= ASUS_WMI_DEVID_PROCESSOR_STATE,
277f0188618SHans Petter Selasky 		.flag_rdonly	= 1
278461a98a2SAlexander Motin 	},
279*027b93c2SVladimir Kondratyev 	{
280*027b93c2SVladimir Kondratyev 		.name		= "throttle_thermal_policy",
281*027b93c2SVladimir Kondratyev 		.dev_id		= ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
282*027b93c2SVladimir Kondratyev 		.description	= "Throttle Thermal Policy "
283*027b93c2SVladimir Kondratyev 				  "(0 - default, 1 - overboost, 2 - silent)",
284*027b93c2SVladimir Kondratyev 	},
285461a98a2SAlexander Motin 	{ NULL, 0, NULL, 0 }
286461a98a2SAlexander Motin };
287461a98a2SAlexander Motin 
2885e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
2895e41194bSVladimir Kondratyev static const struct {
2905e41194bSVladimir Kondratyev 	UINT32		notify;
2915e41194bSVladimir Kondratyev 	uint16_t	key;
2925e41194bSVladimir Kondratyev } acpi_asus_wmi_evdev_map[] = {
2935e41194bSVladimir Kondratyev 	{ 0x20, KEY_BRIGHTNESSDOWN },
2945e41194bSVladimir Kondratyev 	{ 0x2f, KEY_BRIGHTNESSUP },
2955e41194bSVladimir Kondratyev 	{ 0x30, KEY_VOLUMEUP },
2965e41194bSVladimir Kondratyev 	{ 0x31, KEY_VOLUMEDOWN },
2975e41194bSVladimir Kondratyev 	{ 0x32, KEY_MUTE },
2985e41194bSVladimir Kondratyev 	{ 0x35, KEY_SCREENLOCK },
2995e41194bSVladimir Kondratyev 	{ 0x38, KEY_PROG3 },		/* Armoury Crate */
3005e41194bSVladimir Kondratyev 	{ 0x40, KEY_PREVIOUSSONG },
3015e41194bSVladimir Kondratyev 	{ 0x41, KEY_NEXTSONG },
3025e41194bSVladimir Kondratyev 	{ 0x43, KEY_STOPCD },		/* Stop/Eject */
3035e41194bSVladimir Kondratyev 	{ 0x45, KEY_PLAYPAUSE },
3045e41194bSVladimir Kondratyev 	{ 0x4f, KEY_LEFTMETA },		/* Fn-locked "Windows" Key */
3055e41194bSVladimir Kondratyev 	{ 0x4c, KEY_MEDIA },		/* WMP Key */
3065e41194bSVladimir Kondratyev 	{ 0x50, KEY_EMAIL },
3075e41194bSVladimir Kondratyev 	{ 0x51, KEY_WWW },
3085e41194bSVladimir Kondratyev 	{ 0x55, KEY_CALC },
3095e41194bSVladimir Kondratyev 	{ 0x57, NO_KEY },		/* Battery mode */
3105e41194bSVladimir Kondratyev 	{ 0x58, NO_KEY },		/* AC mode */
3115e41194bSVladimir Kondratyev 	{ 0x5C, KEY_F15 },		/* Power Gear key */
3125e41194bSVladimir Kondratyev 	{ 0x5D, KEY_WLAN },		/* Wireless console Toggle */
3135e41194bSVladimir Kondratyev 	{ 0x5E, KEY_WLAN },		/* Wireless console Enable */
3145e41194bSVladimir Kondratyev 	{ 0x5F, KEY_WLAN },		/* Wireless console Disable */
3155e41194bSVladimir Kondratyev 	{ 0x60, KEY_TOUCHPAD_ON },
3165e41194bSVladimir Kondratyev 	{ 0x61, KEY_SWITCHVIDEOMODE },	/* SDSP LCD only */
3175e41194bSVladimir Kondratyev 	{ 0x62, KEY_SWITCHVIDEOMODE },	/* SDSP CRT only */
3185e41194bSVladimir Kondratyev 	{ 0x63, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT */
3195e41194bSVladimir Kondratyev 	{ 0x64, KEY_SWITCHVIDEOMODE },	/* SDSP TV */
3205e41194bSVladimir Kondratyev 	{ 0x65, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + TV */
3215e41194bSVladimir Kondratyev 	{ 0x66, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + TV */
3225e41194bSVladimir Kondratyev 	{ 0x67, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + TV */
3235e41194bSVladimir Kondratyev 	{ 0x6B, KEY_TOUCHPAD_TOGGLE },
3245e41194bSVladimir Kondratyev 	{ 0x6E, NO_KEY },		/* Low Battery notification */
3255e41194bSVladimir Kondratyev 	{ 0x71, KEY_F13 },		/* General-purpose button */
3265e41194bSVladimir Kondratyev 	{ 0x79, NO_KEY },	/* Charger type dectection notification */
3275e41194bSVladimir Kondratyev 	{ 0x7a, KEY_ALS_TOGGLE },	/* Ambient Light Sensor Toggle */
3285e41194bSVladimir Kondratyev 	{ 0x7c, KEY_MICMUTE },
3295e41194bSVladimir Kondratyev 	{ 0x7D, KEY_BLUETOOTH },	/* Bluetooth Enable */
3305e41194bSVladimir Kondratyev 	{ 0x7E, KEY_BLUETOOTH },	/* Bluetooth Disable */
3315e41194bSVladimir Kondratyev 	{ 0x82, KEY_CAMERA },
3325e41194bSVladimir Kondratyev 	{ 0x86, KEY_PROG1 },		/* MyASUS Key */
3335e41194bSVladimir Kondratyev 	{ 0x88, KEY_RFKILL },		/* Radio Toggle Key */
3345e41194bSVladimir Kondratyev 	{ 0x8A, KEY_PROG1 },		/* Color enhancement mode */
3355e41194bSVladimir Kondratyev 	{ 0x8C, KEY_SWITCHVIDEOMODE },	/* SDSP DVI only */
3365e41194bSVladimir Kondratyev 	{ 0x8D, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + DVI */
3375e41194bSVladimir Kondratyev 	{ 0x8E, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + DVI */
3385e41194bSVladimir Kondratyev 	{ 0x8F, KEY_SWITCHVIDEOMODE },	/* SDSP TV + DVI */
3395e41194bSVladimir Kondratyev 	{ 0x90, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + DVI */
3405e41194bSVladimir Kondratyev 	{ 0x91, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + TV + DVI */
3415e41194bSVladimir Kondratyev 	{ 0x92, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + TV + DVI */
3425e41194bSVladimir Kondratyev 	{ 0x93, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + TV + DVI */
3435e41194bSVladimir Kondratyev 	{ 0x95, KEY_MEDIA },
3445e41194bSVladimir Kondratyev 	{ 0x99, KEY_PHONE },		/* Conflicts with fan mode switch */
3455e41194bSVladimir Kondratyev 	{ 0xA0, KEY_SWITCHVIDEOMODE },	/* SDSP HDMI only */
3465e41194bSVladimir Kondratyev 	{ 0xA1, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + HDMI */
3475e41194bSVladimir Kondratyev 	{ 0xA2, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + HDMI */
3485e41194bSVladimir Kondratyev 	{ 0xA3, KEY_SWITCHVIDEOMODE },	/* SDSP TV + HDMI */
3495e41194bSVladimir Kondratyev 	{ 0xA4, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + HDMI */
3505e41194bSVladimir Kondratyev 	{ 0xA5, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + TV + HDMI */
3515e41194bSVladimir Kondratyev 	{ 0xA6, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + TV + HDMI */
3525e41194bSVladimir Kondratyev 	{ 0xA7, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + TV + HDMI */
3535e41194bSVladimir Kondratyev 	{ 0xAE, KEY_FN_F5 },		/* Fn+F5 fan mode on 2020+ */
3545e41194bSVladimir Kondratyev 	{ 0xB3, KEY_PROG4 },		/* AURA */
3555e41194bSVladimir Kondratyev 	{ 0xB5, KEY_CALC },
3565e41194bSVladimir Kondratyev 	{ 0xC4, KEY_KBDILLUMUP },
3575e41194bSVladimir Kondratyev 	{ 0xC5, KEY_KBDILLUMDOWN },
3585e41194bSVladimir Kondratyev 	{ 0xC6, NO_KEY },		/* Ambient Light Sensor notification */
3595e41194bSVladimir Kondratyev 	{ 0xFA, KEY_PROG2 },		/* Lid flip action */
3605e41194bSVladimir Kondratyev 	{ 0xBD, KEY_PROG2 },	/* Lid flip action on ROG xflow laptops */
3615e41194bSVladimir Kondratyev };
3625e41194bSVladimir Kondratyev #endif
3635e41194bSVladimir Kondratyev 
364461a98a2SAlexander Motin ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device");
365461a98a2SAlexander Motin 
366461a98a2SAlexander Motin static void	acpi_asus_wmi_identify(driver_t *driver, device_t parent);
367461a98a2SAlexander Motin static int	acpi_asus_wmi_probe(device_t dev);
368461a98a2SAlexander Motin static int	acpi_asus_wmi_attach(device_t dev);
369461a98a2SAlexander Motin static int	acpi_asus_wmi_detach(device_t dev);
370f134662aSVladimir Kondratyev static int	acpi_asus_wmi_suspend(device_t dev);
371f134662aSVladimir Kondratyev static int	acpi_asus_wmi_resume(device_t dev);
372461a98a2SAlexander Motin 
373461a98a2SAlexander Motin static int	acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS);
374461a98a2SAlexander Motin static int	acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id,
375461a98a2SAlexander Motin 		    int arg, int oldarg);
376461a98a2SAlexander Motin static int	acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id);
377461a98a2SAlexander Motin static int	acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
378*027b93c2SVladimir Kondratyev 		    UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval);
379461a98a2SAlexander Motin static int	acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
380461a98a2SAlexander Motin 		    UINT32 dev_id, UINT32 *retval);
381461a98a2SAlexander Motin static int	acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
382461a98a2SAlexander Motin 		    UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
383d5bf6a72SVladimir Kondratyev static int	acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify,
384d5bf6a72SVladimir Kondratyev 		    int *code);
385461a98a2SAlexander Motin static void	acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
386f134662aSVladimir Kondratyev static int	acpi_asus_wmi_backlight_update_status(device_t dev,
387f134662aSVladimir Kondratyev 		    struct backlight_props *props);
388f134662aSVladimir Kondratyev static int	acpi_asus_wmi_backlight_get_status(device_t dev,
389f134662aSVladimir Kondratyev 		    struct backlight_props *props);
390f134662aSVladimir Kondratyev static int	acpi_asus_wmi_backlight_get_info(device_t dev,
391f134662aSVladimir Kondratyev 		    struct backlight_info *info);
392461a98a2SAlexander Motin 
393461a98a2SAlexander Motin static device_method_t acpi_asus_wmi_methods[] = {
394f134662aSVladimir Kondratyev 	/* Device interface */
395461a98a2SAlexander Motin 	DEVMETHOD(device_identify, acpi_asus_wmi_identify),
396461a98a2SAlexander Motin 	DEVMETHOD(device_probe, acpi_asus_wmi_probe),
397461a98a2SAlexander Motin 	DEVMETHOD(device_attach, acpi_asus_wmi_attach),
398461a98a2SAlexander Motin 	DEVMETHOD(device_detach, acpi_asus_wmi_detach),
399f134662aSVladimir Kondratyev 	DEVMETHOD(device_suspend, acpi_asus_wmi_suspend),
400f134662aSVladimir Kondratyev 	DEVMETHOD(device_resume, acpi_asus_wmi_resume),
401f134662aSVladimir Kondratyev 
402f134662aSVladimir Kondratyev 	/* Backlight interface */
403f134662aSVladimir Kondratyev         DEVMETHOD(backlight_update_status, acpi_asus_wmi_backlight_update_status),
404f134662aSVladimir Kondratyev         DEVMETHOD(backlight_get_status, acpi_asus_wmi_backlight_get_status),
405f134662aSVladimir Kondratyev         DEVMETHOD(backlight_get_info, acpi_asus_wmi_backlight_get_info),
40661bfd867SSofian Brabez 
40761bfd867SSofian Brabez 	DEVMETHOD_END
408461a98a2SAlexander Motin };
409461a98a2SAlexander Motin 
410461a98a2SAlexander Motin static driver_t	acpi_asus_wmi_driver = {
411461a98a2SAlexander Motin 	"acpi_asus_wmi",
412461a98a2SAlexander Motin 	acpi_asus_wmi_methods,
413461a98a2SAlexander Motin 	sizeof(struct acpi_asus_wmi_softc),
414461a98a2SAlexander Motin };
415461a98a2SAlexander Motin 
41690161e72SJohn Baldwin DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 0, 0);
417461a98a2SAlexander Motin MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
418461a98a2SAlexander Motin MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
419f134662aSVladimir Kondratyev MODULE_DEPEND(acpi_asus_wmi, backlight, 1, 1, 1);
4205e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
4215e41194bSVladimir Kondratyev MODULE_DEPEND(acpi_asus_wmi, evdev, 1, 1, 1);
4225e41194bSVladimir Kondratyev #endif
423461a98a2SAlexander Motin 
424f134662aSVladimir Kondratyev static const uint32_t acpi_asus_wmi_backlight_levels[] = { 0, 33, 66, 100 };
425f134662aSVladimir Kondratyev 
426f134662aSVladimir Kondratyev static inline uint32_t
devstate_to_kbd_bkl_level(UINT32 val)427f134662aSVladimir Kondratyev devstate_to_kbd_bkl_level(UINT32 val)
428f134662aSVladimir Kondratyev {
429f134662aSVladimir Kondratyev 	return (acpi_asus_wmi_backlight_levels[val & 0x3]);
430f134662aSVladimir Kondratyev }
431f134662aSVladimir Kondratyev 
432f134662aSVladimir Kondratyev static inline UINT32
kbd_bkl_level_to_devstate(uint32_t bkl)433f134662aSVladimir Kondratyev kbd_bkl_level_to_devstate(uint32_t bkl)
434f134662aSVladimir Kondratyev {
435f134662aSVladimir Kondratyev 	UINT32 val;
436f134662aSVladimir Kondratyev 	int i;
437f134662aSVladimir Kondratyev 
438f134662aSVladimir Kondratyev 	for (i = 0; i < nitems(acpi_asus_wmi_backlight_levels); i++) {
439f134662aSVladimir Kondratyev 		if (bkl < acpi_asus_wmi_backlight_levels[i])
440f134662aSVladimir Kondratyev 			break;
441f134662aSVladimir Kondratyev 	}
442f134662aSVladimir Kondratyev 	val = (i - 1) & 0x3;
443f134662aSVladimir Kondratyev 	if (val != 0)
444f134662aSVladimir Kondratyev 		val |= 0x80;
445f134662aSVladimir Kondratyev 	return(val);
446f134662aSVladimir Kondratyev }
447f134662aSVladimir Kondratyev 
448461a98a2SAlexander Motin static void
acpi_asus_wmi_identify(driver_t * driver,device_t parent)449461a98a2SAlexander Motin acpi_asus_wmi_identify(driver_t *driver, device_t parent)
450461a98a2SAlexander Motin {
451461a98a2SAlexander Motin 
452461a98a2SAlexander Motin 	/* Don't do anything if driver is disabled. */
453461a98a2SAlexander Motin 	if (acpi_disabled("asus_wmi"))
454461a98a2SAlexander Motin 		return;
455461a98a2SAlexander Motin 
456461a98a2SAlexander Motin 	/* Add only a single device instance. */
457461a98a2SAlexander Motin 	if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL)
458461a98a2SAlexander Motin 		return;
459461a98a2SAlexander Motin 
460461a98a2SAlexander Motin 	/* Check management GUID to see whether system is compatible. */
461461a98a2SAlexander Motin 	if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
462461a98a2SAlexander Motin 	    ACPI_ASUS_WMI_MGMT_GUID))
463461a98a2SAlexander Motin 		return;
464461a98a2SAlexander Motin 
465461a98a2SAlexander Motin 	if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL)
466461a98a2SAlexander Motin 		device_printf(parent, "add acpi_asus_wmi child failed\n");
467461a98a2SAlexander Motin }
468461a98a2SAlexander Motin 
469461a98a2SAlexander Motin static int
acpi_asus_wmi_probe(device_t dev)470461a98a2SAlexander Motin acpi_asus_wmi_probe(device_t dev)
471461a98a2SAlexander Motin {
472461a98a2SAlexander Motin 
473461a98a2SAlexander Motin 	if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev),
474461a98a2SAlexander Motin 	    ACPI_ASUS_WMI_MGMT_GUID))
475461a98a2SAlexander Motin 		return (EINVAL);
476461a98a2SAlexander Motin 	device_set_desc(dev, "ASUS WMI device");
477461a98a2SAlexander Motin 	return (0);
478461a98a2SAlexander Motin }
479461a98a2SAlexander Motin 
480461a98a2SAlexander Motin static int
acpi_asus_wmi_attach(device_t dev)481461a98a2SAlexander Motin acpi_asus_wmi_attach(device_t dev)
482461a98a2SAlexander Motin {
483461a98a2SAlexander Motin 	struct acpi_asus_wmi_softc	*sc;
484461a98a2SAlexander Motin 	UINT32			val;
485d5bf6a72SVladimir Kondratyev 	int			dev_id, i, code;
486f134662aSVladimir Kondratyev 	bool			have_kbd_bkl = false;
487461a98a2SAlexander Motin 
488461a98a2SAlexander Motin 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
489461a98a2SAlexander Motin 
490461a98a2SAlexander Motin 	sc = device_get_softc(dev);
491461a98a2SAlexander Motin 	sc->dev = dev;
492461a98a2SAlexander Motin 	sc->wmi_dev = device_get_parent(dev);
493461a98a2SAlexander Motin 	sc->handle_keys = 1;
494461a98a2SAlexander Motin 
495461a98a2SAlexander Motin 	/* Check management GUID. */
496461a98a2SAlexander Motin 	if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
497461a98a2SAlexander Motin 	    ACPI_ASUS_WMI_MGMT_GUID)) {
498461a98a2SAlexander Motin 		device_printf(dev,
499461a98a2SAlexander Motin 		    "WMI device does not provide the ASUS management GUID\n");
500461a98a2SAlexander Motin 		return (EINVAL);
501461a98a2SAlexander Motin 	}
502461a98a2SAlexander Motin 
503461a98a2SAlexander Motin 	/* Find proper DSTS method. */
504461a98a2SAlexander Motin 	sc->dsts_id = ASUS_WMI_METHODID_DSTS;
505461a98a2SAlexander Motin next:
506461a98a2SAlexander Motin 	for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
507461a98a2SAlexander Motin 		dev_id = acpi_asus_wmi_sysctls[i].dev_id;
508461a98a2SAlexander Motin 		if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
509461a98a2SAlexander Motin 			continue;
510461a98a2SAlexander Motin 		break;
511461a98a2SAlexander Motin 	}
512461a98a2SAlexander Motin 	if (acpi_asus_wmi_sysctls[i].name == NULL) {
513461a98a2SAlexander Motin 		if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) {
514461a98a2SAlexander Motin 			sc->dsts_id = ASUS_WMI_METHODID_DSTS2;
515461a98a2SAlexander Motin 			goto next;
516461a98a2SAlexander Motin 		} else {
517461a98a2SAlexander Motin 			device_printf(dev, "Can not detect DSTS method ID\n");
518461a98a2SAlexander Motin 			return (EINVAL);
519461a98a2SAlexander Motin 		}
520461a98a2SAlexander Motin 	}
521461a98a2SAlexander Motin 
522461a98a2SAlexander Motin 	/* Find proper and attach to notufy GUID. */
523461a98a2SAlexander Motin 	if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
524461a98a2SAlexander Motin 	    ACPI_ASUS_WMI_EVENT_GUID))
525461a98a2SAlexander Motin 		sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID;
526461a98a2SAlexander Motin 	else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
527461a98a2SAlexander Motin 	    ACPI_EEEPC_WMI_EVENT_GUID))
528461a98a2SAlexander Motin 		sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID;
529461a98a2SAlexander Motin 	else
530461a98a2SAlexander Motin 		sc->notify_guid = NULL;
531461a98a2SAlexander Motin 	if (sc->notify_guid != NULL) {
532461a98a2SAlexander Motin 		if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
533461a98a2SAlexander Motin 		    sc->notify_guid, acpi_asus_wmi_notify, dev))
534461a98a2SAlexander Motin 			sc->notify_guid = NULL;
535461a98a2SAlexander Motin 	}
536461a98a2SAlexander Motin 	if (sc->notify_guid == NULL)
537461a98a2SAlexander Motin 		device_printf(dev, "Could not install event handler!\n");
538461a98a2SAlexander Motin 
539461a98a2SAlexander Motin 	/* Initialize. */
540461a98a2SAlexander Motin 	if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
541*027b93c2SVladimir Kondratyev 	    ASUS_WMI_METHODID_INIT, 0, 0, 0, &val) && bootverbose)
542461a98a2SAlexander Motin 		device_printf(dev, "Initialization: %#x\n", val);
543461a98a2SAlexander Motin 	if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
544*027b93c2SVladimir Kondratyev 	    ASUS_WMI_METHODID_SPEC, 0, 0x9, 0, &val) && bootverbose)
545461a98a2SAlexander Motin 		device_printf(dev, "WMI BIOS version: %d.%d\n",
546461a98a2SAlexander Motin 		    val >> 16, val & 0xFF);
547461a98a2SAlexander Motin 	if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
548*027b93c2SVladimir Kondratyev 	    ASUS_WMI_METHODID_SFUN, 0, 0, 0, &val) && bootverbose)
549461a98a2SAlexander Motin 		device_printf(dev, "SFUN value: %#x\n", val);
550461a98a2SAlexander Motin 
551461a98a2SAlexander Motin 	ACPI_SERIAL_BEGIN(asus_wmi);
552461a98a2SAlexander Motin 
553461a98a2SAlexander Motin 	sc->sysctl_ctx = device_get_sysctl_ctx(dev);
554461a98a2SAlexander Motin 	sc->sysctl_tree = device_get_sysctl_tree(dev);
555461a98a2SAlexander Motin 	SYSCTL_ADD_INT(sc->sysctl_ctx,
556461a98a2SAlexander Motin 	    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
557461a98a2SAlexander Motin 	    "handle_keys", CTLFLAG_RW, &sc->handle_keys,
558461a98a2SAlexander Motin 	    0, "Handle some hardware keys inside the driver");
559461a98a2SAlexander Motin 	for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
560461a98a2SAlexander Motin 		dev_id = acpi_asus_wmi_sysctls[i].dev_id;
561461a98a2SAlexander Motin 		if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
562461a98a2SAlexander Motin 			continue;
563461a98a2SAlexander Motin 		switch (dev_id) {
564461a98a2SAlexander Motin 		case ASUS_WMI_DEVID_THERMAL_CTRL:
565461a98a2SAlexander Motin 		case ASUS_WMI_DEVID_PROCESSOR_STATE:
566461a98a2SAlexander Motin 		case ASUS_WMI_DEVID_FAN_CTRL:
567461a98a2SAlexander Motin 		case ASUS_WMI_DEVID_BRIGHTNESS:
568461a98a2SAlexander Motin 			if (val == 0)
569461a98a2SAlexander Motin 				continue;
570461a98a2SAlexander Motin 			break;
571f134662aSVladimir Kondratyev 		case ASUS_WMI_DEVID_KBD_BACKLIGHT:
572f134662aSVladimir Kondratyev 			sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
573f134662aSVladimir Kondratyev 			have_kbd_bkl = true;
574f134662aSVladimir Kondratyev 			/* FALLTHROUGH */
575461a98a2SAlexander Motin 		default:
576461a98a2SAlexander Motin 			if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
577461a98a2SAlexander Motin 				continue;
578461a98a2SAlexander Motin 			break;
579461a98a2SAlexander Motin 		}
580461a98a2SAlexander Motin 
581f0188618SHans Petter Selasky 		if (acpi_asus_wmi_sysctls[i].flag_rdonly != 0) {
582461a98a2SAlexander Motin 			SYSCTL_ADD_PROC(sc->sysctl_ctx,
583461a98a2SAlexander Motin 			    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
584461a98a2SAlexander Motin 			    acpi_asus_wmi_sysctls[i].name,
5856237a1ccSAlexander Motin 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
586461a98a2SAlexander Motin 			    sc, i, acpi_asus_wmi_sysctl, "I",
587461a98a2SAlexander Motin 			    acpi_asus_wmi_sysctls[i].description);
588f0188618SHans Petter Selasky 		} else {
589f0188618SHans Petter Selasky 			SYSCTL_ADD_PROC(sc->sysctl_ctx,
590f0188618SHans Petter Selasky 			    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
591f0188618SHans Petter Selasky 			    acpi_asus_wmi_sysctls[i].name,
5926237a1ccSAlexander Motin 			    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
593f0188618SHans Petter Selasky 			    sc, i, acpi_asus_wmi_sysctl, "I",
594f0188618SHans Petter Selasky 			    acpi_asus_wmi_sysctls[i].description);
595f0188618SHans Petter Selasky 		}
596461a98a2SAlexander Motin 	}
597461a98a2SAlexander Motin 	ACPI_SERIAL_END(asus_wmi);
598461a98a2SAlexander Motin 
599d5bf6a72SVladimir Kondratyev 	/* Detect and flush event queue */
600d5bf6a72SVladimir Kondratyev 	if (sc->dsts_id == ASUS_WMI_METHODID_DSTS2) {
601d5bf6a72SVladimir Kondratyev 		for (i = 0; i <= ASUS_WMI_EVENT_QUEUE_SIZE; i++) {
602d5bf6a72SVladimir Kondratyev 			if (acpi_asus_wmi_get_event_code(sc->wmi_dev,
603d5bf6a72SVladimir Kondratyev 			    ASUS_WMI_EVENT_VALUE_ATK, &code) != 0) {
604d5bf6a72SVladimir Kondratyev 				device_printf(dev,
605d5bf6a72SVladimir Kondratyev 				    "Can not flush event queue\n");
606d5bf6a72SVladimir Kondratyev 				break;
607d5bf6a72SVladimir Kondratyev 			}
608d5bf6a72SVladimir Kondratyev 			if (code == ASUS_WMI_EVENT_QUEUE_END ||
609d5bf6a72SVladimir Kondratyev 			    code == ASUS_WMI_EVENT_MASK) {
610d5bf6a72SVladimir Kondratyev 				sc->event_queue = true;
611d5bf6a72SVladimir Kondratyev 				break;
612d5bf6a72SVladimir Kondratyev 			}
613d5bf6a72SVladimir Kondratyev 		}
614d5bf6a72SVladimir Kondratyev 	}
615d5bf6a72SVladimir Kondratyev 
6165e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
6175e41194bSVladimir Kondratyev 	if (sc->notify_guid != NULL) {
6185e41194bSVladimir Kondratyev 		sc->evdev = evdev_alloc();
6195e41194bSVladimir Kondratyev 		evdev_set_name(sc->evdev, device_get_desc(dev));
6205e41194bSVladimir Kondratyev 		evdev_set_phys(sc->evdev, device_get_nameunit(dev));
6215e41194bSVladimir Kondratyev 		evdev_set_id(sc->evdev, BUS_HOST, 0, 0, 1);
6225e41194bSVladimir Kondratyev 		evdev_support_event(sc->evdev, EV_SYN);
6235e41194bSVladimir Kondratyev 		evdev_support_event(sc->evdev, EV_KEY);
6245e41194bSVladimir Kondratyev 		for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
6255e41194bSVladimir Kondratyev 			if (acpi_asus_wmi_evdev_map[i].key != NO_KEY)
6265e41194bSVladimir Kondratyev 				evdev_support_key(sc->evdev,
6275e41194bSVladimir Kondratyev 				    acpi_asus_wmi_evdev_map[i].key);
6285e41194bSVladimir Kondratyev 		}
6295e41194bSVladimir Kondratyev 
6305e41194bSVladimir Kondratyev 		if (evdev_register(sc->evdev) != 0) {
631f134662aSVladimir Kondratyev 			device_printf(dev, "Can not register evdev\n");
6325e41194bSVladimir Kondratyev 			acpi_asus_wmi_detach(dev);
6335e41194bSVladimir Kondratyev 			return (ENXIO);
6345e41194bSVladimir Kondratyev 		}
6355e41194bSVladimir Kondratyev 	}
6365e41194bSVladimir Kondratyev #endif
6375e41194bSVladimir Kondratyev 
638f134662aSVladimir Kondratyev 	if (have_kbd_bkl) {
639f134662aSVladimir Kondratyev 		sc->kbd_bkl = backlight_register("acpi_asus_wmi", dev);
640f134662aSVladimir Kondratyev 		if (sc->kbd_bkl == NULL) {
641f134662aSVladimir Kondratyev 			device_printf(dev, "Can not register backlight\n");
642f134662aSVladimir Kondratyev 			acpi_asus_wmi_detach(dev);
643f134662aSVladimir Kondratyev 			return (ENXIO);
644f134662aSVladimir Kondratyev 		}
645f134662aSVladimir Kondratyev 	}
646f134662aSVladimir Kondratyev 
647461a98a2SAlexander Motin 	return (0);
648461a98a2SAlexander Motin }
649461a98a2SAlexander Motin 
650461a98a2SAlexander Motin static int
acpi_asus_wmi_detach(device_t dev)651461a98a2SAlexander Motin acpi_asus_wmi_detach(device_t dev)
652461a98a2SAlexander Motin {
653461a98a2SAlexander Motin 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
654461a98a2SAlexander Motin 
655461a98a2SAlexander Motin 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
656461a98a2SAlexander Motin 
657f134662aSVladimir Kondratyev 	if (sc->kbd_bkl != NULL)
658f134662aSVladimir Kondratyev 		backlight_destroy(sc->kbd_bkl);
659f134662aSVladimir Kondratyev 
6605e41194bSVladimir Kondratyev 	if (sc->notify_guid) {
661461a98a2SAlexander Motin 		ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
6625e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
6635e41194bSVladimir Kondratyev 		evdev_free(sc->evdev);
6645e41194bSVladimir Kondratyev #endif
6655e41194bSVladimir Kondratyev 	}
666461a98a2SAlexander Motin 
667461a98a2SAlexander Motin 	return (0);
668461a98a2SAlexander Motin }
669461a98a2SAlexander Motin 
670461a98a2SAlexander Motin static int
acpi_asus_wmi_suspend(device_t dev)671f134662aSVladimir Kondratyev acpi_asus_wmi_suspend(device_t dev)
672f134662aSVladimir Kondratyev {
673f134662aSVladimir Kondratyev 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
674f134662aSVladimir Kondratyev 
675f134662aSVladimir Kondratyev 	if (sc->kbd_bkl != NULL) {
676f134662aSVladimir Kondratyev 		ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
677f134662aSVladimir Kondratyev 		acpi_wpi_asus_set_devstate(sc,
678f134662aSVladimir Kondratyev 		    ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, NULL);
679f134662aSVladimir Kondratyev 	}
680f134662aSVladimir Kondratyev 
681f134662aSVladimir Kondratyev 	return (0);
682f134662aSVladimir Kondratyev }
683f134662aSVladimir Kondratyev 
684f134662aSVladimir Kondratyev static int
acpi_asus_wmi_resume(device_t dev)685f134662aSVladimir Kondratyev acpi_asus_wmi_resume(device_t dev)
686f134662aSVladimir Kondratyev {
687f134662aSVladimir Kondratyev 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
688f134662aSVladimir Kondratyev 
689f134662aSVladimir Kondratyev 	if (sc->kbd_bkl != NULL) {
690f134662aSVladimir Kondratyev 		ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
691f134662aSVladimir Kondratyev 		acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
692f134662aSVladimir Kondratyev 		    kbd_bkl_level_to_devstate(sc->kbd_bkl_level), NULL);
693f134662aSVladimir Kondratyev 	}
694f134662aSVladimir Kondratyev 
695f134662aSVladimir Kondratyev 	return (0);
696f134662aSVladimir Kondratyev }
697f134662aSVladimir Kondratyev 
698f134662aSVladimir Kondratyev static int
acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)699461a98a2SAlexander Motin acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
700461a98a2SAlexander Motin {
701461a98a2SAlexander Motin 	struct acpi_asus_wmi_softc	*sc;
702461a98a2SAlexander Motin 	int			arg;
703461a98a2SAlexander Motin 	int			oldarg;
704461a98a2SAlexander Motin 	int			error = 0;
705461a98a2SAlexander Motin 	int			function;
706461a98a2SAlexander Motin 	int			dev_id;
707461a98a2SAlexander Motin 
708461a98a2SAlexander Motin 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
709461a98a2SAlexander Motin 
710461a98a2SAlexander Motin 	sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1;
711461a98a2SAlexander Motin 	function = oidp->oid_arg2;
712461a98a2SAlexander Motin 	dev_id = acpi_asus_wmi_sysctls[function].dev_id;
713461a98a2SAlexander Motin 
714461a98a2SAlexander Motin 	ACPI_SERIAL_BEGIN(asus_wmi);
715461a98a2SAlexander Motin 	arg = acpi_asus_wmi_sysctl_get(sc, dev_id);
716461a98a2SAlexander Motin 	oldarg = arg;
717461a98a2SAlexander Motin 	error = sysctl_handle_int(oidp, &arg, 0, req);
718461a98a2SAlexander Motin 	if (!error && req->newptr != NULL)
719461a98a2SAlexander Motin 		error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg);
720461a98a2SAlexander Motin 	ACPI_SERIAL_END(asus_wmi);
721461a98a2SAlexander Motin 
722461a98a2SAlexander Motin 	return (error);
723461a98a2SAlexander Motin }
724461a98a2SAlexander Motin 
725461a98a2SAlexander Motin static int
acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc * sc,int dev_id)726461a98a2SAlexander Motin acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
727461a98a2SAlexander Motin {
728461a98a2SAlexander Motin 	UINT32	val = 0;
729461a98a2SAlexander Motin 
730461a98a2SAlexander Motin 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
731461a98a2SAlexander Motin 	ACPI_SERIAL_ASSERT(asus_wmi);
732461a98a2SAlexander Motin 
733*027b93c2SVladimir Kondratyev 	switch(dev_id) {
734*027b93c2SVladimir Kondratyev 	case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
735*027b93c2SVladimir Kondratyev 		return (sc->ttp_mode);
736*027b93c2SVladimir Kondratyev 	default:
737*027b93c2SVladimir Kondratyev 		break;
738*027b93c2SVladimir Kondratyev 	}
739*027b93c2SVladimir Kondratyev 
740461a98a2SAlexander Motin 	acpi_wpi_asus_get_devstate(sc, dev_id, &val);
741461a98a2SAlexander Motin 
742461a98a2SAlexander Motin 	switch(dev_id) {
743461a98a2SAlexander Motin 	case ASUS_WMI_DEVID_THERMAL_CTRL:
7449d6672e1SLuiz Otavio O Souza 		val = (val - 2731 + 5) / 10;
745461a98a2SAlexander Motin 		break;
746461a98a2SAlexander Motin 	case ASUS_WMI_DEVID_PROCESSOR_STATE:
747461a98a2SAlexander Motin 	case ASUS_WMI_DEVID_FAN_CTRL:
748461a98a2SAlexander Motin 		break;
749461a98a2SAlexander Motin 	case ASUS_WMI_DEVID_BRIGHTNESS:
750461a98a2SAlexander Motin 		val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
751461a98a2SAlexander Motin 		break;
752461a98a2SAlexander Motin 	case ASUS_WMI_DEVID_KBD_BACKLIGHT:
753f134662aSVladimir Kondratyev 		val &= 0x3;
754461a98a2SAlexander Motin 		break;
755461a98a2SAlexander Motin 	default:
756461a98a2SAlexander Motin 		if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
757461a98a2SAlexander Motin 			val = -1;
758461a98a2SAlexander Motin 		else
759461a98a2SAlexander Motin 			val = !!(val & ASUS_WMI_DSTS_STATUS_BIT);
760461a98a2SAlexander Motin 		break;
761461a98a2SAlexander Motin 	}
762461a98a2SAlexander Motin 
763461a98a2SAlexander Motin 	return (val);
764461a98a2SAlexander Motin }
765461a98a2SAlexander Motin 
766461a98a2SAlexander Motin static int
acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc * sc,int dev_id,int arg,int oldarg)767461a98a2SAlexander Motin acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg)
768461a98a2SAlexander Motin {
769461a98a2SAlexander Motin 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
770461a98a2SAlexander Motin 	ACPI_SERIAL_ASSERT(asus_wmi);
771461a98a2SAlexander Motin 
772461a98a2SAlexander Motin 	switch(dev_id) {
773461a98a2SAlexander Motin 	case ASUS_WMI_DEVID_KBD_BACKLIGHT:
774f134662aSVladimir Kondratyev 		arg = min(0x3, arg);
775461a98a2SAlexander Motin 		if (arg != 0)
776461a98a2SAlexander Motin 			arg |= 0x80;
777461a98a2SAlexander Motin 		break;
778*027b93c2SVladimir Kondratyev 	case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
779*027b93c2SVladimir Kondratyev 		arg = min(0x2, arg);
780*027b93c2SVladimir Kondratyev 		sc->ttp_mode = arg;
781*027b93c2SVladimir Kondratyev 		break;
782461a98a2SAlexander Motin 	}
783461a98a2SAlexander Motin 
784461a98a2SAlexander Motin 	acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL);
785461a98a2SAlexander Motin 
786461a98a2SAlexander Motin 	return (0);
787461a98a2SAlexander Motin }
788461a98a2SAlexander Motin 
789461a98a2SAlexander Motin static __inline void
acpi_asus_wmi_free_buffer(ACPI_BUFFER * buf)790461a98a2SAlexander Motin acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
791461a98a2SAlexander Motin 	if (buf && buf->Pointer) {
792461a98a2SAlexander Motin 		AcpiOsFree(buf->Pointer);
793461a98a2SAlexander Motin 	}
794461a98a2SAlexander Motin }
795461a98a2SAlexander Motin 
796d5bf6a72SVladimir Kondratyev static int
acpi_asus_wmi_get_event_code(device_t wmi_dev,UINT32 notify,int * code)797d5bf6a72SVladimir Kondratyev acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify, int *code)
798d5bf6a72SVladimir Kondratyev {
799d5bf6a72SVladimir Kondratyev 	ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
800d5bf6a72SVladimir Kondratyev 	ACPI_OBJECT *obj;
801d5bf6a72SVladimir Kondratyev 	int error = 0;
802d5bf6a72SVladimir Kondratyev 
803d5bf6a72SVladimir Kondratyev 	if (ACPI_FAILURE(ACPI_WMI_GET_EVENT_DATA(wmi_dev, notify, &response)))
804d5bf6a72SVladimir Kondratyev 		return (EIO);
805d5bf6a72SVladimir Kondratyev 	obj = (ACPI_OBJECT*) response.Pointer;
806d5bf6a72SVladimir Kondratyev 	if (obj && obj->Type == ACPI_TYPE_INTEGER)
807d5bf6a72SVladimir Kondratyev 		*code = obj->Integer.Value & ASUS_WMI_EVENT_MASK;
808d5bf6a72SVladimir Kondratyev 	else
809d5bf6a72SVladimir Kondratyev 		error = EINVAL;
810d5bf6a72SVladimir Kondratyev 	acpi_asus_wmi_free_buffer(&response);
811d5bf6a72SVladimir Kondratyev 	return (error);
812d5bf6a72SVladimir Kondratyev }
813d5bf6a72SVladimir Kondratyev 
8145e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
8155e41194bSVladimir Kondratyev static void
acpi_asus_wmi_push_evdev_event(struct evdev_dev * evdev,UINT32 notify)8165e41194bSVladimir Kondratyev acpi_asus_wmi_push_evdev_event(struct evdev_dev *evdev, UINT32 notify)
8175e41194bSVladimir Kondratyev {
8185e41194bSVladimir Kondratyev 	int i;
8195e41194bSVladimir Kondratyev 	uint16_t key;
8205e41194bSVladimir Kondratyev 
8215e41194bSVladimir Kondratyev 	for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
8225e41194bSVladimir Kondratyev 		if (acpi_asus_wmi_evdev_map[i].notify == notify &&
8235e41194bSVladimir Kondratyev 		    acpi_asus_wmi_evdev_map[i].key != NO_KEY) {
8245e41194bSVladimir Kondratyev 			key = acpi_asus_wmi_evdev_map[i].key;
8255e41194bSVladimir Kondratyev 			evdev_push_key(evdev, key, 1);
8265e41194bSVladimir Kondratyev 			evdev_sync(evdev);
8275e41194bSVladimir Kondratyev 			evdev_push_key(evdev, key, 0);
8285e41194bSVladimir Kondratyev 			evdev_sync(evdev);
8295e41194bSVladimir Kondratyev 			break;
8305e41194bSVladimir Kondratyev 		}
8315e41194bSVladimir Kondratyev 	}
8325e41194bSVladimir Kondratyev }
8335e41194bSVladimir Kondratyev #endif
8345e41194bSVladimir Kondratyev 
835461a98a2SAlexander Motin static void
acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc * sc,int code)836d5bf6a72SVladimir Kondratyev acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc *sc, int code)
837461a98a2SAlexander Motin {
838461a98a2SAlexander Motin 	UINT32 val;
839461a98a2SAlexander Motin 
840d5bf6a72SVladimir Kondratyev 	if (code != 0) {
841461a98a2SAlexander Motin 		acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
842461a98a2SAlexander Motin 		    code);
8435e41194bSVladimir Kondratyev #ifdef EVDEV_SUPPORT
8445e41194bSVladimir Kondratyev 		acpi_asus_wmi_push_evdev_event(sc->evdev, code);
8455e41194bSVladimir Kondratyev #endif
846461a98a2SAlexander Motin 	}
847461a98a2SAlexander Motin 	if (code && sc->handle_keys) {
848461a98a2SAlexander Motin 		/* Keyboard backlight control. */
849461a98a2SAlexander Motin 		if (code == 0xc4 || code == 0xc5) {
850461a98a2SAlexander Motin 			acpi_wpi_asus_get_devstate(sc,
851461a98a2SAlexander Motin 			    ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
852f134662aSVladimir Kondratyev 			val &= 0x3;
853461a98a2SAlexander Motin 			if (code == 0xc4) {
854f134662aSVladimir Kondratyev 				if (val < 0x3)
855461a98a2SAlexander Motin 					val++;
856461a98a2SAlexander Motin 			} else if (val > 0)
857461a98a2SAlexander Motin 				val--;
858461a98a2SAlexander Motin 			if (val != 0)
859461a98a2SAlexander Motin 				val |= 0x80;
860461a98a2SAlexander Motin 			acpi_wpi_asus_set_devstate(sc,
861461a98a2SAlexander Motin 			    ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
862f134662aSVladimir Kondratyev 			sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
863461a98a2SAlexander Motin 		}
864461a98a2SAlexander Motin 		/* Touchpad control. */
865461a98a2SAlexander Motin 		if (code == 0x6b) {
866461a98a2SAlexander Motin 			acpi_wpi_asus_get_devstate(sc,
867461a98a2SAlexander Motin 			    ASUS_WMI_DEVID_TOUCHPAD, &val);
868461a98a2SAlexander Motin 			val = !(val & 1);
869461a98a2SAlexander Motin 			acpi_wpi_asus_set_devstate(sc,
870461a98a2SAlexander Motin 			    ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
871461a98a2SAlexander Motin 		}
872*027b93c2SVladimir Kondratyev 		/* Throttle thermal policy control. */
873*027b93c2SVladimir Kondratyev 		if (code == 0xae) {
874*027b93c2SVladimir Kondratyev 			sc->ttp_mode++;
875*027b93c2SVladimir Kondratyev 			if (sc->ttp_mode > 2)
876*027b93c2SVladimir Kondratyev 				sc->ttp_mode = 0;
877*027b93c2SVladimir Kondratyev 			acpi_wpi_asus_set_devstate(sc,
878*027b93c2SVladimir Kondratyev 			    ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
879*027b93c2SVladimir Kondratyev 			    sc->ttp_mode, NULL);
880*027b93c2SVladimir Kondratyev 		}
881*027b93c2SVladimir Kondratyev 		/* TUF laptop RGB mode control. */
882*027b93c2SVladimir Kondratyev 		if (code == 0xb3) {
883*027b93c2SVladimir Kondratyev 			const uint32_t cmd = 0xb4;	/* Save to BIOS */
884*027b93c2SVladimir Kondratyev 			const uint32_t r = 0xff, g = 0xff, b = 0xff;
885*027b93c2SVladimir Kondratyev 			const uint32_t speed = 0xeb;	/* Medium */
886*027b93c2SVladimir Kondratyev 			if (sc->tuf_rgb_mode < 2)
887*027b93c2SVladimir Kondratyev 				sc->tuf_rgb_mode++;
888*027b93c2SVladimir Kondratyev 			else if (sc->tuf_rgb_mode == 2)
889*027b93c2SVladimir Kondratyev 				sc->tuf_rgb_mode = 10;
890*027b93c2SVladimir Kondratyev 			else sc->tuf_rgb_mode = 0;
891*027b93c2SVladimir Kondratyev 			acpi_asus_wmi_evaluate_method(sc->wmi_dev,
892*027b93c2SVladimir Kondratyev 			    ASUS_WMI_METHODID_DEVS,
893*027b93c2SVladimir Kondratyev 			    ASUS_WMI_DEVID_TUF_RGB_MODE,
894*027b93c2SVladimir Kondratyev 			    cmd | (sc->tuf_rgb_mode << 8) | (r << 16) | (g << 24),
895*027b93c2SVladimir Kondratyev 			    b | (speed << 8), NULL);
896*027b93c2SVladimir Kondratyev 		}
897461a98a2SAlexander Motin 	}
898d5bf6a72SVladimir Kondratyev }
899d5bf6a72SVladimir Kondratyev 
900d5bf6a72SVladimir Kondratyev static void
acpi_asus_wmi_notify(ACPI_HANDLE h,UINT32 notify,void * context)901d5bf6a72SVladimir Kondratyev acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
902d5bf6a72SVladimir Kondratyev {
903d5bf6a72SVladimir Kondratyev 	device_t dev = context;
904d5bf6a72SVladimir Kondratyev 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
905d5bf6a72SVladimir Kondratyev 	int code = 0, i = 1;
906d5bf6a72SVladimir Kondratyev 
907d5bf6a72SVladimir Kondratyev 	ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
908d5bf6a72SVladimir Kondratyev 
909d5bf6a72SVladimir Kondratyev 	if (sc->event_queue)
910d5bf6a72SVladimir Kondratyev 		i += ASUS_WMI_EVENT_QUEUE_SIZE;
911d5bf6a72SVladimir Kondratyev 	do {
912d5bf6a72SVladimir Kondratyev 		if (acpi_asus_wmi_get_event_code(sc->wmi_dev, notify, &code)
913d5bf6a72SVladimir Kondratyev 		    != 0) {
914d5bf6a72SVladimir Kondratyev 			device_printf(dev, "Failed to get event code\n");
915d5bf6a72SVladimir Kondratyev 			return;
916d5bf6a72SVladimir Kondratyev 	        }
917d5bf6a72SVladimir Kondratyev 		if (code == ASUS_WMI_EVENT_QUEUE_END ||
918d5bf6a72SVladimir Kondratyev 		    code == ASUS_WMI_EVENT_MASK)
919d5bf6a72SVladimir Kondratyev 			return;
920d5bf6a72SVladimir Kondratyev 		acpi_asus_wmi_handle_event(sc, code);
921d5bf6a72SVladimir Kondratyev 		if (notify != ASUS_WMI_EVENT_VALUE_ATK)
922d5bf6a72SVladimir Kondratyev 			return;
923d5bf6a72SVladimir Kondratyev 	} while (--i != 0);
924d5bf6a72SVladimir Kondratyev 	if (sc->event_queue)
925d5bf6a72SVladimir Kondratyev 		device_printf(dev, "Can not read event queue, "
926d5bf6a72SVladimir Kondratyev 		    "last code: 0x%x\n", code);
927461a98a2SAlexander Motin }
928461a98a2SAlexander Motin 
929461a98a2SAlexander Motin static int
acpi_asus_wmi_evaluate_method(device_t wmi_dev,int method,UINT32 arg0,UINT32 arg1,UINT32 arg2,UINT32 * retval)930461a98a2SAlexander Motin acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
931*027b93c2SVladimir Kondratyev     UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval)
932461a98a2SAlexander Motin {
933*027b93c2SVladimir Kondratyev 	UINT32		params[3] = { arg0, arg1, arg2 };
934461a98a2SAlexander Motin 	UINT32		result;
935461a98a2SAlexander Motin 	ACPI_OBJECT	*obj;
936461a98a2SAlexander Motin 	ACPI_BUFFER	in = { sizeof(params), &params };
937461a98a2SAlexander Motin 	ACPI_BUFFER	out = { ACPI_ALLOCATE_BUFFER, NULL };
938461a98a2SAlexander Motin 
939461a98a2SAlexander Motin 	if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev,
940461a98a2SAlexander Motin 	    ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) {
941461a98a2SAlexander Motin 		acpi_asus_wmi_free_buffer(&out);
942461a98a2SAlexander Motin 		return (-EINVAL);
943461a98a2SAlexander Motin 	}
944461a98a2SAlexander Motin 	obj = out.Pointer;
945461a98a2SAlexander Motin 	if (obj && obj->Type == ACPI_TYPE_INTEGER)
946461a98a2SAlexander Motin 		result = (UINT32) obj->Integer.Value;
947461a98a2SAlexander Motin 	else
948461a98a2SAlexander Motin 		result = 0;
949461a98a2SAlexander Motin 	acpi_asus_wmi_free_buffer(&out);
950461a98a2SAlexander Motin 	if (retval)
951461a98a2SAlexander Motin 		*retval = result;
952461a98a2SAlexander Motin 	return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0);
953461a98a2SAlexander Motin }
954461a98a2SAlexander Motin 
955461a98a2SAlexander Motin static int
acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 * retval)956461a98a2SAlexander Motin acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
957461a98a2SAlexander Motin     UINT32 dev_id, UINT32 *retval)
958461a98a2SAlexander Motin {
959461a98a2SAlexander Motin 
960461a98a2SAlexander Motin 	return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
961*027b93c2SVladimir Kondratyev 	    sc->dsts_id, dev_id, 0, 0, retval));
962461a98a2SAlexander Motin }
963461a98a2SAlexander Motin 
964461a98a2SAlexander Motin static int
acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 ctrl_param,UINT32 * retval)965461a98a2SAlexander Motin acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
966461a98a2SAlexander Motin     UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval)
967461a98a2SAlexander Motin {
968461a98a2SAlexander Motin 
969461a98a2SAlexander Motin 	return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
970*027b93c2SVladimir Kondratyev 	    ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, 0, retval));
971461a98a2SAlexander Motin }
972f134662aSVladimir Kondratyev 
973f134662aSVladimir Kondratyev static int
acpi_asus_wmi_backlight_update_status(device_t dev,struct backlight_props * props)974f134662aSVladimir Kondratyev acpi_asus_wmi_backlight_update_status(device_t dev, struct backlight_props
975f134662aSVladimir Kondratyev     *props)
976f134662aSVladimir Kondratyev {
977f134662aSVladimir Kondratyev 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
978f134662aSVladimir Kondratyev 
979f134662aSVladimir Kondratyev 	acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
980f134662aSVladimir Kondratyev 	    kbd_bkl_level_to_devstate(props->brightness), NULL);
981f134662aSVladimir Kondratyev 	sc->kbd_bkl_level = props->brightness;
982f134662aSVladimir Kondratyev 
983f134662aSVladimir Kondratyev 	return (0);
984f134662aSVladimir Kondratyev }
985f134662aSVladimir Kondratyev 
986f134662aSVladimir Kondratyev static int
acpi_asus_wmi_backlight_get_status(device_t dev,struct backlight_props * props)987f134662aSVladimir Kondratyev acpi_asus_wmi_backlight_get_status(device_t dev, struct backlight_props *props)
988f134662aSVladimir Kondratyev {
989f134662aSVladimir Kondratyev 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
990f134662aSVladimir Kondratyev 
991f134662aSVladimir Kondratyev 	props->brightness = sc->kbd_bkl_level;
992f134662aSVladimir Kondratyev 	props->nlevels = nitems(acpi_asus_wmi_backlight_levels);
993f134662aSVladimir Kondratyev 	memcpy(props->levels, acpi_asus_wmi_backlight_levels,
994f134662aSVladimir Kondratyev 	    sizeof(acpi_asus_wmi_backlight_levels));
995f134662aSVladimir Kondratyev 
996f134662aSVladimir Kondratyev         return (0);
997f134662aSVladimir Kondratyev }
998f134662aSVladimir Kondratyev 
999f134662aSVladimir Kondratyev static int
acpi_asus_wmi_backlight_get_info(device_t dev,struct backlight_info * info)1000f134662aSVladimir Kondratyev acpi_asus_wmi_backlight_get_info(device_t dev, struct backlight_info *info)
1001f134662aSVladimir Kondratyev {
1002f134662aSVladimir Kondratyev         info->type = BACKLIGHT_TYPE_KEYBOARD;
1003f134662aSVladimir Kondratyev         strlcpy(info->name, "ASUS Keyboard", BACKLIGHTMAXNAMELENGTH);
1004f134662aSVladimir Kondratyev 
1005f134662aSVladimir Kondratyev         return (0);
1006f134662aSVladimir Kondratyev }
1007