2 * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
35 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/sysctl.h>
41 #include <contrib/dev/acpica/include/acpi.h>
42 #include <contrib/dev/acpica/include/accommon.h>
43 #include <dev/acpica/acpivar.h>
44 #include "acpi_wmi_if.h"
46 #define _COMPONENT ACPI_OEM
47 ACPI_MODULE_NAME("ASUS-WMI")
49 #define ACPI_ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
50 #define ACPI_ASUS_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
51 #define ACPI_EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
54 #define ASUS_WMI_METHODID_SPEC 0x43455053
55 #define ASUS_WMI_METHODID_SFUN 0x4E554653
56 #define ASUS_WMI_METHODID_DSTS 0x53544344
57 #define ASUS_WMI_METHODID_DSTS2 0x53545344
58 #define ASUS_WMI_METHODID_DEVS 0x53564544
59 #define ASUS_WMI_METHODID_INIT 0x54494E49
60 #define ASUS_WMI_METHODID_HKEY 0x59454B48
62 #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
65 #define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
66 #define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
67 #define ASUS_WMI_DEVID_CWAP 0x00010003
68 #define ASUS_WMI_DEVID_WLAN 0x00010011
69 #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
70 #define ASUS_WMI_DEVID_GPS 0x00010015
71 #define ASUS_WMI_DEVID_WIMAX 0x00010017
72 #define ASUS_WMI_DEVID_WWAN3G 0x00010019
73 #define ASUS_WMI_DEVID_UWB 0x00010021
76 #define ASUS_WMI_DEVID_LED1 0x00020011
77 #define ASUS_WMI_DEVID_LED2 0x00020012
78 #define ASUS_WMI_DEVID_LED3 0x00020013
79 #define ASUS_WMI_DEVID_LED4 0x00020014
80 #define ASUS_WMI_DEVID_LED5 0x00020015
81 #define ASUS_WMI_DEVID_LED6 0x00020016
83 /* Backlight and Brightness */
84 #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
85 #define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
86 #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
87 #define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022
90 #define ASUS_WMI_DEVID_CAMERA 0x00060013
91 #define ASUS_WMI_DEVID_CARDREADER 0x00080013
92 #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
93 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
94 #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
95 #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
96 #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
99 #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
100 #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
101 #define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
102 #define ASUS_WMI_DSTS_USER_BIT 0x00020000
103 #define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
104 #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
105 #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
108 struct acpi_asus_wmi_softc {
111 const char *notify_guid;
112 struct sysctl_ctx_list *sysctl_ctx;
113 struct sysctl_oid *sysctl_tree;
123 } acpi_asus_wmi_sysctls[] = {
126 .dev_id = ASUS_WMI_DEVID_HW_SWITCH,
127 .description = "hw_switch",
128 .access = CTLTYPE_INT | CTLFLAG_RW
131 .name = "wireless_led",
132 .dev_id = ASUS_WMI_DEVID_WIRELESS_LED,
133 .description = "Wireless LED control",
134 .access = CTLTYPE_INT | CTLFLAG_RW
138 .dev_id = ASUS_WMI_DEVID_CWAP,
139 .description = "Alt+F2 function",
140 .access = CTLTYPE_INT | CTLFLAG_RW
144 .dev_id = ASUS_WMI_DEVID_WLAN,
145 .description = "WLAN power control",
146 .access = CTLTYPE_INT | CTLFLAG_RW
150 .dev_id = ASUS_WMI_DEVID_BLUETOOTH,
151 .description = "Bluetooth power control",
152 .access = CTLTYPE_INT | CTLFLAG_RW
156 .dev_id = ASUS_WMI_DEVID_GPS,
157 .description = "GPS power control",
158 .access = CTLTYPE_INT | CTLFLAG_RW
162 .dev_id = ASUS_WMI_DEVID_WIMAX,
163 .description = "WiMAX power control",
164 .access = CTLTYPE_INT | CTLFLAG_RW
168 .dev_id = ASUS_WMI_DEVID_WWAN3G,
169 .description = "WWAN-3G power control",
170 .access = CTLTYPE_INT | CTLFLAG_RW
174 .dev_id = ASUS_WMI_DEVID_UWB,
175 .description = "UWB power control",
176 .access = CTLTYPE_INT | CTLFLAG_RW
180 .dev_id = ASUS_WMI_DEVID_LED1,
181 .description = "LED1 control",
182 .access = CTLTYPE_INT | CTLFLAG_RW
186 .dev_id = ASUS_WMI_DEVID_LED2,
187 .description = "LED2 control",
188 .access = CTLTYPE_INT | CTLFLAG_RW
192 .dev_id = ASUS_WMI_DEVID_LED3,
193 .description = "LED3 control",
194 .access = CTLTYPE_INT | CTLFLAG_RW
198 .dev_id = ASUS_WMI_DEVID_LED4,
199 .description = "LED4 control",
200 .access = CTLTYPE_INT | CTLFLAG_RW
204 .dev_id = ASUS_WMI_DEVID_LED5,
205 .description = "LED5 control",
206 .access = CTLTYPE_INT | CTLFLAG_RW
210 .dev_id = ASUS_WMI_DEVID_LED6,
211 .description = "LED6 control",
212 .access = CTLTYPE_INT | CTLFLAG_RW
216 .dev_id = ASUS_WMI_DEVID_BACKLIGHT,
217 .description = "LCD backlight on/off control",
218 .access = CTLTYPE_INT | CTLFLAG_RW
221 .name = "brightness",
222 .dev_id = ASUS_WMI_DEVID_BRIGHTNESS,
223 .description = "LCD backlight brightness control",
224 .access = CTLTYPE_INT | CTLFLAG_RW
227 .name = "kbd_backlight",
228 .dev_id = ASUS_WMI_DEVID_KBD_BACKLIGHT,
229 .description = "Keyboard backlight brightness control",
230 .access = CTLTYPE_INT | CTLFLAG_RW
233 .name = "light_sensor",
234 .dev_id = ASUS_WMI_DEVID_LIGHT_SENSOR,
235 .description = "Ambient light sensor",
236 .access = CTLTYPE_INT | CTLFLAG_RW
240 .dev_id = ASUS_WMI_DEVID_CAMERA,
241 .description = "Camera power control",
242 .access = CTLTYPE_INT | CTLFLAG_RW
245 .name = "cardreader",
246 .dev_id = ASUS_WMI_DEVID_CARDREADER,
247 .description = "Cardreader power control",
248 .access = CTLTYPE_INT | CTLFLAG_RW
252 .dev_id = ASUS_WMI_DEVID_TOUCHPAD,
253 .description = "Touchpad control",
254 .access = CTLTYPE_INT | CTLFLAG_RW
257 .name = "touchpad_led",
258 .dev_id = ASUS_WMI_DEVID_TOUCHPAD_LED,
259 .description = "Touchpad LED control",
260 .access = CTLTYPE_INT | CTLFLAG_RW
263 .name = "themperature",
264 .dev_id = ASUS_WMI_DEVID_THERMAL_CTRL,
265 .description = "Temperature (C)",
266 .access = CTLTYPE_INT | CTLFLAG_RD
270 .dev_id = ASUS_WMI_DEVID_FAN_CTRL,
271 .description = "Fan speed (0-3)",
272 .access = CTLTYPE_INT | CTLFLAG_RD
275 .name = "processor_state",
276 .dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE,
277 .description = "Processor state",
278 .access = CTLTYPE_INT | CTLFLAG_RW
283 ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device");
285 static void acpi_asus_wmi_identify(driver_t *driver, device_t parent);
286 static int acpi_asus_wmi_probe(device_t dev);
287 static int acpi_asus_wmi_attach(device_t dev);
288 static int acpi_asus_wmi_detach(device_t dev);
290 static int acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS);
291 static int acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id,
292 int arg, int oldarg);
293 static int acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id);
294 static int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
295 UINT32 arg0, UINT32 arg1, UINT32 *retval);
296 static int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
297 UINT32 dev_id, UINT32 *retval);
298 static int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
299 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
300 static void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
302 static device_method_t acpi_asus_wmi_methods[] = {
303 DEVMETHOD(device_identify, acpi_asus_wmi_identify),
304 DEVMETHOD(device_probe, acpi_asus_wmi_probe),
305 DEVMETHOD(device_attach, acpi_asus_wmi_attach),
306 DEVMETHOD(device_detach, acpi_asus_wmi_detach),
311 static driver_t acpi_asus_wmi_driver = {
313 acpi_asus_wmi_methods,
314 sizeof(struct acpi_asus_wmi_softc),
317 static devclass_t acpi_asus_wmi_devclass;
319 DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver,
320 acpi_asus_wmi_devclass, 0, 0);
321 MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
322 MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
325 acpi_asus_wmi_identify(driver_t *driver, device_t parent)
328 /* Don't do anything if driver is disabled. */
329 if (acpi_disabled("asus_wmi"))
332 /* Add only a single device instance. */
333 if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL)
336 /* Check management GUID to see whether system is compatible. */
337 if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
338 ACPI_ASUS_WMI_MGMT_GUID))
341 if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL)
342 device_printf(parent, "add acpi_asus_wmi child failed\n");
346 acpi_asus_wmi_probe(device_t dev)
349 if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev),
350 ACPI_ASUS_WMI_MGMT_GUID))
352 device_set_desc(dev, "ASUS WMI device");
357 acpi_asus_wmi_attach(device_t dev)
359 struct acpi_asus_wmi_softc *sc;
363 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
365 sc = device_get_softc(dev);
367 sc->wmi_dev = device_get_parent(dev);
370 /* Check management GUID. */
371 if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
372 ACPI_ASUS_WMI_MGMT_GUID)) {
374 "WMI device does not provide the ASUS management GUID\n");
378 /* Find proper DSTS method. */
379 sc->dsts_id = ASUS_WMI_METHODID_DSTS;
381 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
382 dev_id = acpi_asus_wmi_sysctls[i].dev_id;
383 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
387 if (acpi_asus_wmi_sysctls[i].name == NULL) {
388 if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) {
389 sc->dsts_id = ASUS_WMI_METHODID_DSTS2;
392 device_printf(dev, "Can not detect DSTS method ID\n");
397 /* Find proper and attach to notufy GUID. */
398 if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
399 ACPI_ASUS_WMI_EVENT_GUID))
400 sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID;
401 else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
402 ACPI_EEEPC_WMI_EVENT_GUID))
403 sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID;
405 sc->notify_guid = NULL;
406 if (sc->notify_guid != NULL) {
407 if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
408 sc->notify_guid, acpi_asus_wmi_notify, dev))
409 sc->notify_guid = NULL;
411 if (sc->notify_guid == NULL)
412 device_printf(dev, "Could not install event handler!\n");
415 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
416 ASUS_WMI_METHODID_INIT, 0, 0, &val) && bootverbose)
417 device_printf(dev, "Initialization: %#x\n", val);
418 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
419 ASUS_WMI_METHODID_SPEC, 0, 0x9, &val) && bootverbose)
420 device_printf(dev, "WMI BIOS version: %d.%d\n",
421 val >> 16, val & 0xFF);
422 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
423 ASUS_WMI_METHODID_SFUN, 0, 0, &val) && bootverbose)
424 device_printf(dev, "SFUN value: %#x\n", val);
426 ACPI_SERIAL_BEGIN(asus_wmi);
428 sc->sysctl_ctx = device_get_sysctl_ctx(dev);
429 sc->sysctl_tree = device_get_sysctl_tree(dev);
430 SYSCTL_ADD_INT(sc->sysctl_ctx,
431 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
432 "handle_keys", CTLFLAG_RW, &sc->handle_keys,
433 0, "Handle some hardware keys inside the driver");
434 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
435 dev_id = acpi_asus_wmi_sysctls[i].dev_id;
436 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
439 case ASUS_WMI_DEVID_THERMAL_CTRL:
440 case ASUS_WMI_DEVID_PROCESSOR_STATE:
441 case ASUS_WMI_DEVID_FAN_CTRL:
442 case ASUS_WMI_DEVID_BRIGHTNESS:
447 if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
452 SYSCTL_ADD_PROC(sc->sysctl_ctx,
453 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
454 acpi_asus_wmi_sysctls[i].name,
455 acpi_asus_wmi_sysctls[i].access,
456 sc, i, acpi_asus_wmi_sysctl, "I",
457 acpi_asus_wmi_sysctls[i].description);
459 ACPI_SERIAL_END(asus_wmi);
465 acpi_asus_wmi_detach(device_t dev)
467 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
469 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
472 ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
478 acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
480 struct acpi_asus_wmi_softc *sc;
487 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
489 sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1;
490 function = oidp->oid_arg2;
491 dev_id = acpi_asus_wmi_sysctls[function].dev_id;
493 ACPI_SERIAL_BEGIN(asus_wmi);
494 arg = acpi_asus_wmi_sysctl_get(sc, dev_id);
496 error = sysctl_handle_int(oidp, &arg, 0, req);
497 if (!error && req->newptr != NULL)
498 error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg);
499 ACPI_SERIAL_END(asus_wmi);
505 acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
509 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
510 ACPI_SERIAL_ASSERT(asus_wmi);
512 acpi_wpi_asus_get_devstate(sc, dev_id, &val);
515 case ASUS_WMI_DEVID_THERMAL_CTRL:
516 val = (val - 2732 + 5) / 10;
518 case ASUS_WMI_DEVID_PROCESSOR_STATE:
519 case ASUS_WMI_DEVID_FAN_CTRL:
521 case ASUS_WMI_DEVID_BRIGHTNESS:
522 val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
524 case ASUS_WMI_DEVID_KBD_BACKLIGHT:
528 if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
531 val = !!(val & ASUS_WMI_DSTS_STATUS_BIT);
539 acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg)
541 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
542 ACPI_SERIAL_ASSERT(asus_wmi);
545 case ASUS_WMI_DEVID_KBD_BACKLIGHT:
552 acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL);
558 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
559 if (buf && buf->Pointer) {
560 AcpiOsFree(buf->Pointer);
565 acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
567 device_t dev = context;
568 ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
572 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
573 ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
575 ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response);
576 obj = (ACPI_OBJECT*) response.Pointer;
577 if (obj && obj->Type == ACPI_TYPE_INTEGER) {
578 code = obj->Integer.Value;
579 acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
582 if (code && sc->handle_keys) {
583 /* Keyboard backlight control. */
584 if (code == 0xc4 || code == 0xc5) {
585 acpi_wpi_asus_get_devstate(sc,
586 ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
595 acpi_wpi_asus_set_devstate(sc,
596 ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
598 /* Touchpad control. */
600 acpi_wpi_asus_get_devstate(sc,
601 ASUS_WMI_DEVID_TOUCHPAD, &val);
603 acpi_wpi_asus_set_devstate(sc,
604 ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
607 acpi_asus_wmi_free_buffer(&response);
611 acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
612 UINT32 arg0, UINT32 arg1, UINT32 *retval)
614 UINT32 params[2] = { arg0, arg1 };
617 ACPI_BUFFER in = { sizeof(params), ¶ms };
618 ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
620 if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev,
621 ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) {
622 acpi_asus_wmi_free_buffer(&out);
626 if (obj && obj->Type == ACPI_TYPE_INTEGER)
627 result = (UINT32) obj->Integer.Value;
630 acpi_asus_wmi_free_buffer(&out);
633 return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0);
637 acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
638 UINT32 dev_id, UINT32 *retval)
641 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
642 sc->dsts_id, dev_id, 0, retval));
646 acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
647 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval)
650 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
651 ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval));