xref: /freebsd/sys/dev/acpi_support/acpi_asus_wmi.c (revision 027b93c2f5e1b84d9e4569f127b632c704c53b73)
1 /*-
2  * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 #include "opt_acpi.h"
29 #include "opt_evdev.h"
30 #include <sys/param.h>
31 #include <sys/conf.h>
32 #include <sys/uio.h>
33 #include <sys/proc.h>
34 #include <sys/kernel.h>
35 #include <sys/bus.h>
36 #include <sys/sbuf.h>
37 #include <sys/module.h>
38 #include <sys/sysctl.h>
39 
40 #include <contrib/dev/acpica/include/acpi.h>
41 #include <contrib/dev/acpica/include/accommon.h>
42 #include <dev/acpica/acpivar.h>
43 #include "acpi_wmi_if.h"
44 
45 #include <dev/backlight/backlight.h>
46 #include "backlight_if.h"
47 
48 #ifdef EVDEV_SUPPORT
49 #include <dev/evdev/input.h>
50 #include <dev/evdev/evdev.h>
51 #define NO_KEY	KEY_RESERVED
52 #endif
53 
54 #define _COMPONENT	ACPI_OEM
55 ACPI_MODULE_NAME("ASUS-WMI")
56 
57 #define ACPI_ASUS_WMI_MGMT_GUID 	"97845ED0-4E6D-11DE-8A39-0800200C9A66"
58 #define ACPI_ASUS_WMI_EVENT_GUID	"0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
59 #define ACPI_EEEPC_WMI_EVENT_GUID	"ABBC0F72-8EA1-11D1-00A0-C90629100000"
60 
61 /* WMI Methods */
62 #define ASUS_WMI_METHODID_SPEC          0x43455053
63 #define ASUS_WMI_METHODID_SFUN          0x4E554653
64 #define ASUS_WMI_METHODID_DSTS          0x53544344
65 #define ASUS_WMI_METHODID_DSTS2         0x53545344
66 #define ASUS_WMI_METHODID_DEVS          0x53564544
67 #define ASUS_WMI_METHODID_INIT          0x54494E49
68 #define ASUS_WMI_METHODID_HKEY          0x59454B48
69 
70 #define ASUS_WMI_UNSUPPORTED_METHOD     0xFFFFFFFE
71 
72 /* Wireless */
73 #define ASUS_WMI_DEVID_HW_SWITCH        0x00010001
74 #define ASUS_WMI_DEVID_WIRELESS_LED     0x00010002
75 #define ASUS_WMI_DEVID_CWAP             0x00010003
76 #define ASUS_WMI_DEVID_WLAN             0x00010011
77 #define ASUS_WMI_DEVID_BLUETOOTH        0x00010013
78 #define ASUS_WMI_DEVID_GPS              0x00010015
79 #define ASUS_WMI_DEVID_WIMAX            0x00010017
80 #define ASUS_WMI_DEVID_WWAN3G           0x00010019
81 #define ASUS_WMI_DEVID_UWB              0x00010021
82 
83 /* LEDs */
84 #define ASUS_WMI_DEVID_LED1             0x00020011
85 #define ASUS_WMI_DEVID_LED2             0x00020012
86 #define ASUS_WMI_DEVID_LED3             0x00020013
87 #define ASUS_WMI_DEVID_LED4             0x00020014
88 #define ASUS_WMI_DEVID_LED5             0x00020015
89 #define ASUS_WMI_DEVID_LED6             0x00020016
90 
91 /* Backlight and Brightness */
92 #define ASUS_WMI_DEVID_BACKLIGHT        0x00050011
93 #define ASUS_WMI_DEVID_BRIGHTNESS       0x00050012
94 #define ASUS_WMI_DEVID_KBD_BACKLIGHT    0x00050021
95 #define ASUS_WMI_DEVID_LIGHT_SENSOR     0x00050022
96 
97 /* Misc */
98 #define ASUS_WMI_DEVID_CAMERA           0x00060013
99 #define ASUS_WMI_DEVID_CARDREADER       0x00080013
100 #define ASUS_WMI_DEVID_TOUCHPAD         0x00100011
101 #define ASUS_WMI_DEVID_TOUCHPAD_LED     0x00100012
102 #define ASUS_WMI_DEVID_TUF_RGB_MODE	0x00100056
103 #define ASUS_WMI_DEVID_THERMAL_CTRL     0x00110011
104 #define ASUS_WMI_DEVID_FAN_CTRL         0x00110012
105 #define ASUS_WMI_DEVID_PROCESSOR_STATE  0x00120012
106 #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
107 
108 /* DSTS masks */
109 #define ASUS_WMI_DSTS_STATUS_BIT        0x00000001
110 #define ASUS_WMI_DSTS_UNKNOWN_BIT       0x00000002
111 #define ASUS_WMI_DSTS_PRESENCE_BIT      0x00010000
112 #define ASUS_WMI_DSTS_USER_BIT          0x00020000
113 #define ASUS_WMI_DSTS_BIOS_BIT          0x00040000
114 #define ASUS_WMI_DSTS_BRIGHTNESS_MASK   0x000000FF
115 #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK   0x0000FF00
116 
117 /* Events */
118 #define ASUS_WMI_EVENT_QUEUE_SIZE	0x10
119 #define ASUS_WMI_EVENT_QUEUE_END	0x1
120 #define ASUS_WMI_EVENT_MASK		0xFFFF
121 #define ASUS_WMI_EVENT_VALUE_ATK	0xFF
122 
123 struct acpi_asus_wmi_softc {
124 	device_t	dev;
125 	device_t	wmi_dev;
126 	const char	*notify_guid;
127 	struct sysctl_ctx_list	*sysctl_ctx;
128 	struct sysctl_oid	*sysctl_tree;
129 	int		dsts_id;
130 	int		handle_keys;
131 	bool		event_queue;
132 	struct cdev	*kbd_bkl;
133 	uint32_t	kbd_bkl_level;
134 	uint32_t	tuf_rgb_mode;
135 	uint32_t	ttp_mode;
136 #ifdef EVDEV_SUPPORT
137 	struct evdev_dev	*evdev;
138 #endif
139 };
140 
141 static struct {
142 	char	*name;
143 	int	dev_id;
144 	char	*description;
145 	int	flag_rdonly;
146 } acpi_asus_wmi_sysctls[] = {
147 	{
148 		.name		= "hw_switch",
149 		.dev_id		= ASUS_WMI_DEVID_HW_SWITCH,
150 		.description	= "hw_switch",
151 	},
152 	{
153 		.name		= "wireless_led",
154 		.dev_id		= ASUS_WMI_DEVID_WIRELESS_LED,
155 		.description	= "Wireless LED control",
156 	},
157 	{
158 		.name		= "cwap",
159 		.dev_id		= ASUS_WMI_DEVID_CWAP,
160 		.description	= "Alt+F2 function",
161 	},
162 	{
163 		.name		= "wlan",
164 		.dev_id		= ASUS_WMI_DEVID_WLAN,
165 		.description	= "WLAN power control",
166 	},
167 	{
168 		.name		= "bluetooth",
169 		.dev_id		= ASUS_WMI_DEVID_BLUETOOTH,
170 		.description	= "Bluetooth power control",
171 	},
172 	{
173 		.name		= "gps",
174 		.dev_id		= ASUS_WMI_DEVID_GPS,
175 		.description	= "GPS power control",
176 	},
177 	{
178 		.name		= "wimax",
179 		.dev_id		= ASUS_WMI_DEVID_WIMAX,
180 		.description	= "WiMAX power control",
181 	},
182 	{
183 		.name		= "wwan3g",
184 		.dev_id		= ASUS_WMI_DEVID_WWAN3G,
185 		.description	= "WWAN-3G power control",
186 	},
187 	{
188 		.name		= "uwb",
189 		.dev_id		= ASUS_WMI_DEVID_UWB,
190 		.description	= "UWB power control",
191 	},
192 	{
193 		.name		= "led1",
194 		.dev_id		= ASUS_WMI_DEVID_LED1,
195 		.description	= "LED1 control",
196 	},
197 	{
198 		.name		= "led2",
199 		.dev_id		= ASUS_WMI_DEVID_LED2,
200 		.description	= "LED2 control",
201 	},
202 	{
203 		.name		= "led3",
204 		.dev_id		= ASUS_WMI_DEVID_LED3,
205 		.description	= "LED3 control",
206 	},
207 	{
208 		.name		= "led4",
209 		.dev_id		= ASUS_WMI_DEVID_LED4,
210 		.description	= "LED4 control",
211 	},
212 	{
213 		.name		= "led5",
214 		.dev_id		= ASUS_WMI_DEVID_LED5,
215 		.description	= "LED5 control",
216 	},
217 	{
218 		.name		= "led6",
219 		.dev_id		= ASUS_WMI_DEVID_LED6,
220 		.description	= "LED6 control",
221 	},
222 	{
223 		.name		= "backlight",
224 		.dev_id		= ASUS_WMI_DEVID_BACKLIGHT,
225 		.description	= "LCD backlight on/off control",
226 	},
227 	{
228 		.name		= "brightness",
229 		.dev_id		= ASUS_WMI_DEVID_BRIGHTNESS,
230 		.description	= "LCD backlight brightness control",
231 	},
232 	{
233 		.name		= "kbd_backlight",
234 		.dev_id		= ASUS_WMI_DEVID_KBD_BACKLIGHT,
235 		.description	= "Keyboard backlight brightness control",
236 	},
237 	{
238 		.name		= "light_sensor",
239 		.dev_id		= ASUS_WMI_DEVID_LIGHT_SENSOR,
240 		.description	= "Ambient light sensor",
241 	},
242 	{
243 		.name		= "camera",
244 		.dev_id		= ASUS_WMI_DEVID_CAMERA,
245 		.description	= "Camera power control",
246 	},
247 	{
248 		.name		= "cardreader",
249 		.dev_id		= ASUS_WMI_DEVID_CARDREADER,
250 		.description	= "Cardreader power control",
251 	},
252 	{
253 		.name		= "touchpad",
254 		.dev_id		= ASUS_WMI_DEVID_TOUCHPAD,
255 		.description	= "Touchpad control",
256 	},
257 	{
258 		.name		= "touchpad_led",
259 		.dev_id		= ASUS_WMI_DEVID_TOUCHPAD_LED,
260 		.description	= "Touchpad LED control",
261 	},
262 	{
263 		.name		= "themperature",
264 		.dev_id		= ASUS_WMI_DEVID_THERMAL_CTRL,
265 		.description	= "Temperature (C)",
266 		.flag_rdonly	= 1
267 	},
268 	{
269 		.name		= "fan_speed",
270 		.dev_id		= ASUS_WMI_DEVID_FAN_CTRL,
271 		.description	= "Fan speed (0-3)",
272 		.flag_rdonly	= 1
273 	},
274 	{
275 		.name		= "processor_state",
276 		.dev_id		= ASUS_WMI_DEVID_PROCESSOR_STATE,
277 		.flag_rdonly	= 1
278 	},
279 	{
280 		.name		= "throttle_thermal_policy",
281 		.dev_id		= ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
282 		.description	= "Throttle Thermal Policy "
283 				  "(0 - default, 1 - overboost, 2 - silent)",
284 	},
285 	{ NULL, 0, NULL, 0 }
286 };
287 
288 #ifdef EVDEV_SUPPORT
289 static const struct {
290 	UINT32		notify;
291 	uint16_t	key;
292 } acpi_asus_wmi_evdev_map[] = {
293 	{ 0x20, KEY_BRIGHTNESSDOWN },
294 	{ 0x2f, KEY_BRIGHTNESSUP },
295 	{ 0x30, KEY_VOLUMEUP },
296 	{ 0x31, KEY_VOLUMEDOWN },
297 	{ 0x32, KEY_MUTE },
298 	{ 0x35, KEY_SCREENLOCK },
299 	{ 0x38, KEY_PROG3 },		/* Armoury Crate */
300 	{ 0x40, KEY_PREVIOUSSONG },
301 	{ 0x41, KEY_NEXTSONG },
302 	{ 0x43, KEY_STOPCD },		/* Stop/Eject */
303 	{ 0x45, KEY_PLAYPAUSE },
304 	{ 0x4f, KEY_LEFTMETA },		/* Fn-locked "Windows" Key */
305 	{ 0x4c, KEY_MEDIA },		/* WMP Key */
306 	{ 0x50, KEY_EMAIL },
307 	{ 0x51, KEY_WWW },
308 	{ 0x55, KEY_CALC },
309 	{ 0x57, NO_KEY },		/* Battery mode */
310 	{ 0x58, NO_KEY },		/* AC mode */
311 	{ 0x5C, KEY_F15 },		/* Power Gear key */
312 	{ 0x5D, KEY_WLAN },		/* Wireless console Toggle */
313 	{ 0x5E, KEY_WLAN },		/* Wireless console Enable */
314 	{ 0x5F, KEY_WLAN },		/* Wireless console Disable */
315 	{ 0x60, KEY_TOUCHPAD_ON },
316 	{ 0x61, KEY_SWITCHVIDEOMODE },	/* SDSP LCD only */
317 	{ 0x62, KEY_SWITCHVIDEOMODE },	/* SDSP CRT only */
318 	{ 0x63, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT */
319 	{ 0x64, KEY_SWITCHVIDEOMODE },	/* SDSP TV */
320 	{ 0x65, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + TV */
321 	{ 0x66, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + TV */
322 	{ 0x67, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + TV */
323 	{ 0x6B, KEY_TOUCHPAD_TOGGLE },
324 	{ 0x6E, NO_KEY },		/* Low Battery notification */
325 	{ 0x71, KEY_F13 },		/* General-purpose button */
326 	{ 0x79, NO_KEY },	/* Charger type dectection notification */
327 	{ 0x7a, KEY_ALS_TOGGLE },	/* Ambient Light Sensor Toggle */
328 	{ 0x7c, KEY_MICMUTE },
329 	{ 0x7D, KEY_BLUETOOTH },	/* Bluetooth Enable */
330 	{ 0x7E, KEY_BLUETOOTH },	/* Bluetooth Disable */
331 	{ 0x82, KEY_CAMERA },
332 	{ 0x86, KEY_PROG1 },		/* MyASUS Key */
333 	{ 0x88, KEY_RFKILL },		/* Radio Toggle Key */
334 	{ 0x8A, KEY_PROG1 },		/* Color enhancement mode */
335 	{ 0x8C, KEY_SWITCHVIDEOMODE },	/* SDSP DVI only */
336 	{ 0x8D, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + DVI */
337 	{ 0x8E, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + DVI */
338 	{ 0x8F, KEY_SWITCHVIDEOMODE },	/* SDSP TV + DVI */
339 	{ 0x90, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + DVI */
340 	{ 0x91, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + TV + DVI */
341 	{ 0x92, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + TV + DVI */
342 	{ 0x93, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + TV + DVI */
343 	{ 0x95, KEY_MEDIA },
344 	{ 0x99, KEY_PHONE },		/* Conflicts with fan mode switch */
345 	{ 0xA0, KEY_SWITCHVIDEOMODE },	/* SDSP HDMI only */
346 	{ 0xA1, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + HDMI */
347 	{ 0xA2, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + HDMI */
348 	{ 0xA3, KEY_SWITCHVIDEOMODE },	/* SDSP TV + HDMI */
349 	{ 0xA4, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + HDMI */
350 	{ 0xA5, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + TV + HDMI */
351 	{ 0xA6, KEY_SWITCHVIDEOMODE },	/* SDSP CRT + TV + HDMI */
352 	{ 0xA7, KEY_SWITCHVIDEOMODE },	/* SDSP LCD + CRT + TV + HDMI */
353 	{ 0xAE, KEY_FN_F5 },		/* Fn+F5 fan mode on 2020+ */
354 	{ 0xB3, KEY_PROG4 },		/* AURA */
355 	{ 0xB5, KEY_CALC },
356 	{ 0xC4, KEY_KBDILLUMUP },
357 	{ 0xC5, KEY_KBDILLUMDOWN },
358 	{ 0xC6, NO_KEY },		/* Ambient Light Sensor notification */
359 	{ 0xFA, KEY_PROG2 },		/* Lid flip action */
360 	{ 0xBD, KEY_PROG2 },	/* Lid flip action on ROG xflow laptops */
361 };
362 #endif
363 
364 ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device");
365 
366 static void	acpi_asus_wmi_identify(driver_t *driver, device_t parent);
367 static int	acpi_asus_wmi_probe(device_t dev);
368 static int	acpi_asus_wmi_attach(device_t dev);
369 static int	acpi_asus_wmi_detach(device_t dev);
370 static int	acpi_asus_wmi_suspend(device_t dev);
371 static int	acpi_asus_wmi_resume(device_t dev);
372 
373 static int	acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS);
374 static int	acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id,
375 		    int arg, int oldarg);
376 static int	acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id);
377 static int	acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
378 		    UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval);
379 static int	acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
380 		    UINT32 dev_id, UINT32 *retval);
381 static int	acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
382 		    UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
383 static int	acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify,
384 		    int *code);
385 static void	acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
386 static int	acpi_asus_wmi_backlight_update_status(device_t dev,
387 		    struct backlight_props *props);
388 static int	acpi_asus_wmi_backlight_get_status(device_t dev,
389 		    struct backlight_props *props);
390 static int	acpi_asus_wmi_backlight_get_info(device_t dev,
391 		    struct backlight_info *info);
392 
393 static device_method_t acpi_asus_wmi_methods[] = {
394 	/* Device interface */
395 	DEVMETHOD(device_identify, acpi_asus_wmi_identify),
396 	DEVMETHOD(device_probe, acpi_asus_wmi_probe),
397 	DEVMETHOD(device_attach, acpi_asus_wmi_attach),
398 	DEVMETHOD(device_detach, acpi_asus_wmi_detach),
399 	DEVMETHOD(device_suspend, acpi_asus_wmi_suspend),
400 	DEVMETHOD(device_resume, acpi_asus_wmi_resume),
401 
402 	/* Backlight interface */
403         DEVMETHOD(backlight_update_status, acpi_asus_wmi_backlight_update_status),
404         DEVMETHOD(backlight_get_status, acpi_asus_wmi_backlight_get_status),
405         DEVMETHOD(backlight_get_info, acpi_asus_wmi_backlight_get_info),
406 
407 	DEVMETHOD_END
408 };
409 
410 static driver_t	acpi_asus_wmi_driver = {
411 	"acpi_asus_wmi",
412 	acpi_asus_wmi_methods,
413 	sizeof(struct acpi_asus_wmi_softc),
414 };
415 
416 DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 0, 0);
417 MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
418 MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
419 MODULE_DEPEND(acpi_asus_wmi, backlight, 1, 1, 1);
420 #ifdef EVDEV_SUPPORT
421 MODULE_DEPEND(acpi_asus_wmi, evdev, 1, 1, 1);
422 #endif
423 
424 static const uint32_t acpi_asus_wmi_backlight_levels[] = { 0, 33, 66, 100 };
425 
426 static inline uint32_t
devstate_to_kbd_bkl_level(UINT32 val)427 devstate_to_kbd_bkl_level(UINT32 val)
428 {
429 	return (acpi_asus_wmi_backlight_levels[val & 0x3]);
430 }
431 
432 static inline UINT32
kbd_bkl_level_to_devstate(uint32_t bkl)433 kbd_bkl_level_to_devstate(uint32_t bkl)
434 {
435 	UINT32 val;
436 	int i;
437 
438 	for (i = 0; i < nitems(acpi_asus_wmi_backlight_levels); i++) {
439 		if (bkl < acpi_asus_wmi_backlight_levels[i])
440 			break;
441 	}
442 	val = (i - 1) & 0x3;
443 	if (val != 0)
444 		val |= 0x80;
445 	return(val);
446 }
447 
448 static void
acpi_asus_wmi_identify(driver_t * driver,device_t parent)449 acpi_asus_wmi_identify(driver_t *driver, device_t parent)
450 {
451 
452 	/* Don't do anything if driver is disabled. */
453 	if (acpi_disabled("asus_wmi"))
454 		return;
455 
456 	/* Add only a single device instance. */
457 	if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL)
458 		return;
459 
460 	/* Check management GUID to see whether system is compatible. */
461 	if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
462 	    ACPI_ASUS_WMI_MGMT_GUID))
463 		return;
464 
465 	if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL)
466 		device_printf(parent, "add acpi_asus_wmi child failed\n");
467 }
468 
469 static int
acpi_asus_wmi_probe(device_t dev)470 acpi_asus_wmi_probe(device_t dev)
471 {
472 
473 	if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev),
474 	    ACPI_ASUS_WMI_MGMT_GUID))
475 		return (EINVAL);
476 	device_set_desc(dev, "ASUS WMI device");
477 	return (0);
478 }
479 
480 static int
acpi_asus_wmi_attach(device_t dev)481 acpi_asus_wmi_attach(device_t dev)
482 {
483 	struct acpi_asus_wmi_softc	*sc;
484 	UINT32			val;
485 	int			dev_id, i, code;
486 	bool			have_kbd_bkl = false;
487 
488 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
489 
490 	sc = device_get_softc(dev);
491 	sc->dev = dev;
492 	sc->wmi_dev = device_get_parent(dev);
493 	sc->handle_keys = 1;
494 
495 	/* Check management GUID. */
496 	if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
497 	    ACPI_ASUS_WMI_MGMT_GUID)) {
498 		device_printf(dev,
499 		    "WMI device does not provide the ASUS management GUID\n");
500 		return (EINVAL);
501 	}
502 
503 	/* Find proper DSTS method. */
504 	sc->dsts_id = ASUS_WMI_METHODID_DSTS;
505 next:
506 	for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
507 		dev_id = acpi_asus_wmi_sysctls[i].dev_id;
508 		if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
509 			continue;
510 		break;
511 	}
512 	if (acpi_asus_wmi_sysctls[i].name == NULL) {
513 		if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) {
514 			sc->dsts_id = ASUS_WMI_METHODID_DSTS2;
515 			goto next;
516 		} else {
517 			device_printf(dev, "Can not detect DSTS method ID\n");
518 			return (EINVAL);
519 		}
520 	}
521 
522 	/* Find proper and attach to notufy GUID. */
523 	if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
524 	    ACPI_ASUS_WMI_EVENT_GUID))
525 		sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID;
526 	else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
527 	    ACPI_EEEPC_WMI_EVENT_GUID))
528 		sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID;
529 	else
530 		sc->notify_guid = NULL;
531 	if (sc->notify_guid != NULL) {
532 		if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
533 		    sc->notify_guid, acpi_asus_wmi_notify, dev))
534 			sc->notify_guid = NULL;
535 	}
536 	if (sc->notify_guid == NULL)
537 		device_printf(dev, "Could not install event handler!\n");
538 
539 	/* Initialize. */
540 	if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
541 	    ASUS_WMI_METHODID_INIT, 0, 0, 0, &val) && bootverbose)
542 		device_printf(dev, "Initialization: %#x\n", val);
543 	if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
544 	    ASUS_WMI_METHODID_SPEC, 0, 0x9, 0, &val) && bootverbose)
545 		device_printf(dev, "WMI BIOS version: %d.%d\n",
546 		    val >> 16, val & 0xFF);
547 	if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
548 	    ASUS_WMI_METHODID_SFUN, 0, 0, 0, &val) && bootverbose)
549 		device_printf(dev, "SFUN value: %#x\n", val);
550 
551 	ACPI_SERIAL_BEGIN(asus_wmi);
552 
553 	sc->sysctl_ctx = device_get_sysctl_ctx(dev);
554 	sc->sysctl_tree = device_get_sysctl_tree(dev);
555 	SYSCTL_ADD_INT(sc->sysctl_ctx,
556 	    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
557 	    "handle_keys", CTLFLAG_RW, &sc->handle_keys,
558 	    0, "Handle some hardware keys inside the driver");
559 	for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
560 		dev_id = acpi_asus_wmi_sysctls[i].dev_id;
561 		if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
562 			continue;
563 		switch (dev_id) {
564 		case ASUS_WMI_DEVID_THERMAL_CTRL:
565 		case ASUS_WMI_DEVID_PROCESSOR_STATE:
566 		case ASUS_WMI_DEVID_FAN_CTRL:
567 		case ASUS_WMI_DEVID_BRIGHTNESS:
568 			if (val == 0)
569 				continue;
570 			break;
571 		case ASUS_WMI_DEVID_KBD_BACKLIGHT:
572 			sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
573 			have_kbd_bkl = true;
574 			/* FALLTHROUGH */
575 		default:
576 			if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
577 				continue;
578 			break;
579 		}
580 
581 		if (acpi_asus_wmi_sysctls[i].flag_rdonly != 0) {
582 			SYSCTL_ADD_PROC(sc->sysctl_ctx,
583 			    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
584 			    acpi_asus_wmi_sysctls[i].name,
585 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
586 			    sc, i, acpi_asus_wmi_sysctl, "I",
587 			    acpi_asus_wmi_sysctls[i].description);
588 		} else {
589 			SYSCTL_ADD_PROC(sc->sysctl_ctx,
590 			    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
591 			    acpi_asus_wmi_sysctls[i].name,
592 			    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
593 			    sc, i, acpi_asus_wmi_sysctl, "I",
594 			    acpi_asus_wmi_sysctls[i].description);
595 		}
596 	}
597 	ACPI_SERIAL_END(asus_wmi);
598 
599 	/* Detect and flush event queue */
600 	if (sc->dsts_id == ASUS_WMI_METHODID_DSTS2) {
601 		for (i = 0; i <= ASUS_WMI_EVENT_QUEUE_SIZE; i++) {
602 			if (acpi_asus_wmi_get_event_code(sc->wmi_dev,
603 			    ASUS_WMI_EVENT_VALUE_ATK, &code) != 0) {
604 				device_printf(dev,
605 				    "Can not flush event queue\n");
606 				break;
607 			}
608 			if (code == ASUS_WMI_EVENT_QUEUE_END ||
609 			    code == ASUS_WMI_EVENT_MASK) {
610 				sc->event_queue = true;
611 				break;
612 			}
613 		}
614 	}
615 
616 #ifdef EVDEV_SUPPORT
617 	if (sc->notify_guid != NULL) {
618 		sc->evdev = evdev_alloc();
619 		evdev_set_name(sc->evdev, device_get_desc(dev));
620 		evdev_set_phys(sc->evdev, device_get_nameunit(dev));
621 		evdev_set_id(sc->evdev, BUS_HOST, 0, 0, 1);
622 		evdev_support_event(sc->evdev, EV_SYN);
623 		evdev_support_event(sc->evdev, EV_KEY);
624 		for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
625 			if (acpi_asus_wmi_evdev_map[i].key != NO_KEY)
626 				evdev_support_key(sc->evdev,
627 				    acpi_asus_wmi_evdev_map[i].key);
628 		}
629 
630 		if (evdev_register(sc->evdev) != 0) {
631 			device_printf(dev, "Can not register evdev\n");
632 			acpi_asus_wmi_detach(dev);
633 			return (ENXIO);
634 		}
635 	}
636 #endif
637 
638 	if (have_kbd_bkl) {
639 		sc->kbd_bkl = backlight_register("acpi_asus_wmi", dev);
640 		if (sc->kbd_bkl == NULL) {
641 			device_printf(dev, "Can not register backlight\n");
642 			acpi_asus_wmi_detach(dev);
643 			return (ENXIO);
644 		}
645 	}
646 
647 	return (0);
648 }
649 
650 static int
acpi_asus_wmi_detach(device_t dev)651 acpi_asus_wmi_detach(device_t dev)
652 {
653 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
654 
655 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
656 
657 	if (sc->kbd_bkl != NULL)
658 		backlight_destroy(sc->kbd_bkl);
659 
660 	if (sc->notify_guid) {
661 		ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
662 #ifdef EVDEV_SUPPORT
663 		evdev_free(sc->evdev);
664 #endif
665 	}
666 
667 	return (0);
668 }
669 
670 static int
acpi_asus_wmi_suspend(device_t dev)671 acpi_asus_wmi_suspend(device_t dev)
672 {
673 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
674 
675 	if (sc->kbd_bkl != NULL) {
676 		ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
677 		acpi_wpi_asus_set_devstate(sc,
678 		    ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, NULL);
679 	}
680 
681 	return (0);
682 }
683 
684 static int
acpi_asus_wmi_resume(device_t dev)685 acpi_asus_wmi_resume(device_t dev)
686 {
687 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
688 
689 	if (sc->kbd_bkl != NULL) {
690 		ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
691 		acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
692 		    kbd_bkl_level_to_devstate(sc->kbd_bkl_level), NULL);
693 	}
694 
695 	return (0);
696 }
697 
698 static int
acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)699 acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
700 {
701 	struct acpi_asus_wmi_softc	*sc;
702 	int			arg;
703 	int			oldarg;
704 	int			error = 0;
705 	int			function;
706 	int			dev_id;
707 
708 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
709 
710 	sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1;
711 	function = oidp->oid_arg2;
712 	dev_id = acpi_asus_wmi_sysctls[function].dev_id;
713 
714 	ACPI_SERIAL_BEGIN(asus_wmi);
715 	arg = acpi_asus_wmi_sysctl_get(sc, dev_id);
716 	oldarg = arg;
717 	error = sysctl_handle_int(oidp, &arg, 0, req);
718 	if (!error && req->newptr != NULL)
719 		error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg);
720 	ACPI_SERIAL_END(asus_wmi);
721 
722 	return (error);
723 }
724 
725 static int
acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc * sc,int dev_id)726 acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
727 {
728 	UINT32	val = 0;
729 
730 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
731 	ACPI_SERIAL_ASSERT(asus_wmi);
732 
733 	switch(dev_id) {
734 	case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
735 		return (sc->ttp_mode);
736 	default:
737 		break;
738 	}
739 
740 	acpi_wpi_asus_get_devstate(sc, dev_id, &val);
741 
742 	switch(dev_id) {
743 	case ASUS_WMI_DEVID_THERMAL_CTRL:
744 		val = (val - 2731 + 5) / 10;
745 		break;
746 	case ASUS_WMI_DEVID_PROCESSOR_STATE:
747 	case ASUS_WMI_DEVID_FAN_CTRL:
748 		break;
749 	case ASUS_WMI_DEVID_BRIGHTNESS:
750 		val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
751 		break;
752 	case ASUS_WMI_DEVID_KBD_BACKLIGHT:
753 		val &= 0x3;
754 		break;
755 	default:
756 		if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
757 			val = -1;
758 		else
759 			val = !!(val & ASUS_WMI_DSTS_STATUS_BIT);
760 		break;
761 	}
762 
763 	return (val);
764 }
765 
766 static int
acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc * sc,int dev_id,int arg,int oldarg)767 acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg)
768 {
769 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
770 	ACPI_SERIAL_ASSERT(asus_wmi);
771 
772 	switch(dev_id) {
773 	case ASUS_WMI_DEVID_KBD_BACKLIGHT:
774 		arg = min(0x3, arg);
775 		if (arg != 0)
776 			arg |= 0x80;
777 		break;
778 	case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
779 		arg = min(0x2, arg);
780 		sc->ttp_mode = arg;
781 		break;
782 	}
783 
784 	acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL);
785 
786 	return (0);
787 }
788 
789 static __inline void
acpi_asus_wmi_free_buffer(ACPI_BUFFER * buf)790 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
791 	if (buf && buf->Pointer) {
792 		AcpiOsFree(buf->Pointer);
793 	}
794 }
795 
796 static int
acpi_asus_wmi_get_event_code(device_t wmi_dev,UINT32 notify,int * code)797 acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify, int *code)
798 {
799 	ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
800 	ACPI_OBJECT *obj;
801 	int error = 0;
802 
803 	if (ACPI_FAILURE(ACPI_WMI_GET_EVENT_DATA(wmi_dev, notify, &response)))
804 		return (EIO);
805 	obj = (ACPI_OBJECT*) response.Pointer;
806 	if (obj && obj->Type == ACPI_TYPE_INTEGER)
807 		*code = obj->Integer.Value & ASUS_WMI_EVENT_MASK;
808 	else
809 		error = EINVAL;
810 	acpi_asus_wmi_free_buffer(&response);
811 	return (error);
812 }
813 
814 #ifdef EVDEV_SUPPORT
815 static void
acpi_asus_wmi_push_evdev_event(struct evdev_dev * evdev,UINT32 notify)816 acpi_asus_wmi_push_evdev_event(struct evdev_dev *evdev, UINT32 notify)
817 {
818 	int i;
819 	uint16_t key;
820 
821 	for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
822 		if (acpi_asus_wmi_evdev_map[i].notify == notify &&
823 		    acpi_asus_wmi_evdev_map[i].key != NO_KEY) {
824 			key = acpi_asus_wmi_evdev_map[i].key;
825 			evdev_push_key(evdev, key, 1);
826 			evdev_sync(evdev);
827 			evdev_push_key(evdev, key, 0);
828 			evdev_sync(evdev);
829 			break;
830 		}
831 	}
832 }
833 #endif
834 
835 static void
acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc * sc,int code)836 acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc *sc, int code)
837 {
838 	UINT32 val;
839 
840 	if (code != 0) {
841 		acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
842 		    code);
843 #ifdef EVDEV_SUPPORT
844 		acpi_asus_wmi_push_evdev_event(sc->evdev, code);
845 #endif
846 	}
847 	if (code && sc->handle_keys) {
848 		/* Keyboard backlight control. */
849 		if (code == 0xc4 || code == 0xc5) {
850 			acpi_wpi_asus_get_devstate(sc,
851 			    ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
852 			val &= 0x3;
853 			if (code == 0xc4) {
854 				if (val < 0x3)
855 					val++;
856 			} else if (val > 0)
857 				val--;
858 			if (val != 0)
859 				val |= 0x80;
860 			acpi_wpi_asus_set_devstate(sc,
861 			    ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
862 			sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
863 		}
864 		/* Touchpad control. */
865 		if (code == 0x6b) {
866 			acpi_wpi_asus_get_devstate(sc,
867 			    ASUS_WMI_DEVID_TOUCHPAD, &val);
868 			val = !(val & 1);
869 			acpi_wpi_asus_set_devstate(sc,
870 			    ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
871 		}
872 		/* Throttle thermal policy control. */
873 		if (code == 0xae) {
874 			sc->ttp_mode++;
875 			if (sc->ttp_mode > 2)
876 				sc->ttp_mode = 0;
877 			acpi_wpi_asus_set_devstate(sc,
878 			    ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
879 			    sc->ttp_mode, NULL);
880 		}
881 		/* TUF laptop RGB mode control. */
882 		if (code == 0xb3) {
883 			const uint32_t cmd = 0xb4;	/* Save to BIOS */
884 			const uint32_t r = 0xff, g = 0xff, b = 0xff;
885 			const uint32_t speed = 0xeb;	/* Medium */
886 			if (sc->tuf_rgb_mode < 2)
887 				sc->tuf_rgb_mode++;
888 			else if (sc->tuf_rgb_mode == 2)
889 				sc->tuf_rgb_mode = 10;
890 			else sc->tuf_rgb_mode = 0;
891 			acpi_asus_wmi_evaluate_method(sc->wmi_dev,
892 			    ASUS_WMI_METHODID_DEVS,
893 			    ASUS_WMI_DEVID_TUF_RGB_MODE,
894 			    cmd | (sc->tuf_rgb_mode << 8) | (r << 16) | (g << 24),
895 			    b | (speed << 8), NULL);
896 		}
897 	}
898 }
899 
900 static void
acpi_asus_wmi_notify(ACPI_HANDLE h,UINT32 notify,void * context)901 acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
902 {
903 	device_t dev = context;
904 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
905 	int code = 0, i = 1;
906 
907 	ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
908 
909 	if (sc->event_queue)
910 		i += ASUS_WMI_EVENT_QUEUE_SIZE;
911 	do {
912 		if (acpi_asus_wmi_get_event_code(sc->wmi_dev, notify, &code)
913 		    != 0) {
914 			device_printf(dev, "Failed to get event code\n");
915 			return;
916 	        }
917 		if (code == ASUS_WMI_EVENT_QUEUE_END ||
918 		    code == ASUS_WMI_EVENT_MASK)
919 			return;
920 		acpi_asus_wmi_handle_event(sc, code);
921 		if (notify != ASUS_WMI_EVENT_VALUE_ATK)
922 			return;
923 	} while (--i != 0);
924 	if (sc->event_queue)
925 		device_printf(dev, "Can not read event queue, "
926 		    "last code: 0x%x\n", code);
927 }
928 
929 static int
acpi_asus_wmi_evaluate_method(device_t wmi_dev,int method,UINT32 arg0,UINT32 arg1,UINT32 arg2,UINT32 * retval)930 acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
931     UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval)
932 {
933 	UINT32		params[3] = { arg0, arg1, arg2 };
934 	UINT32		result;
935 	ACPI_OBJECT	*obj;
936 	ACPI_BUFFER	in = { sizeof(params), &params };
937 	ACPI_BUFFER	out = { ACPI_ALLOCATE_BUFFER, NULL };
938 
939 	if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev,
940 	    ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) {
941 		acpi_asus_wmi_free_buffer(&out);
942 		return (-EINVAL);
943 	}
944 	obj = out.Pointer;
945 	if (obj && obj->Type == ACPI_TYPE_INTEGER)
946 		result = (UINT32) obj->Integer.Value;
947 	else
948 		result = 0;
949 	acpi_asus_wmi_free_buffer(&out);
950 	if (retval)
951 		*retval = result;
952 	return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0);
953 }
954 
955 static int
acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 * retval)956 acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
957     UINT32 dev_id, UINT32 *retval)
958 {
959 
960 	return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
961 	    sc->dsts_id, dev_id, 0, 0, retval));
962 }
963 
964 static int
acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 ctrl_param,UINT32 * retval)965 acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
966     UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval)
967 {
968 
969 	return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
970 	    ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, 0, retval));
971 }
972 
973 static int
acpi_asus_wmi_backlight_update_status(device_t dev,struct backlight_props * props)974 acpi_asus_wmi_backlight_update_status(device_t dev, struct backlight_props
975     *props)
976 {
977 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
978 
979 	acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
980 	    kbd_bkl_level_to_devstate(props->brightness), NULL);
981 	sc->kbd_bkl_level = props->brightness;
982 
983 	return (0);
984 }
985 
986 static int
acpi_asus_wmi_backlight_get_status(device_t dev,struct backlight_props * props)987 acpi_asus_wmi_backlight_get_status(device_t dev, struct backlight_props *props)
988 {
989 	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
990 
991 	props->brightness = sc->kbd_bkl_level;
992 	props->nlevels = nitems(acpi_asus_wmi_backlight_levels);
993 	memcpy(props->levels, acpi_asus_wmi_backlight_levels,
994 	    sizeof(acpi_asus_wmi_backlight_levels));
995 
996         return (0);
997 }
998 
999 static int
acpi_asus_wmi_backlight_get_info(device_t dev,struct backlight_info * info)1000 acpi_asus_wmi_backlight_get_info(device_t dev, struct backlight_info *info)
1001 {
1002         info->type = BACKLIGHT_TYPE_KEYBOARD;
1003         strlcpy(info->name, "ASUS Keyboard", BACKLIGHTMAXNAMELENGTH);
1004 
1005         return (0);
1006 }
1007