1237981Smav/*- 2237981Smav * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org> 3237981Smav * All rights reserved. 4237981Smav * 5237981Smav * Redistribution and use in source and binary forms, with or without 6237981Smav * modification, are permitted provided that the following conditions 7237981Smav * are met: 8237981Smav * 1. Redistributions of source code must retain the above copyright 9237981Smav * notice, this list of conditions and the following disclaimer. 10237981Smav * 2. Redistributions in binary form must reproduce the above copyright 11237981Smav * notice, this list of conditions and the following disclaimer in the 12237981Smav * documentation and/or other materials provided with the distribution. 13237981Smav * 14237981Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15237981Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16237981Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17237981Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18237981Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19237981Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20237981Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21237981Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22237981Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23237981Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24237981Smav * SUCH DAMAGE. 25237981Smav */ 26237981Smav 27237981Smav#include <sys/cdefs.h> 28237981Smav__FBSDID("$FreeBSD: releng/10.3/sys/dev/acpi_support/acpi_asus_wmi.c 273736 2014-10-27 14:38:00Z hselasky $"); 29237981Smav 30237981Smav#include "opt_acpi.h" 31237981Smav#include <sys/param.h> 32237981Smav#include <sys/conf.h> 33237981Smav#include <sys/uio.h> 34237981Smav#include <sys/proc.h> 35237981Smav#include <sys/kernel.h> 36237981Smav#include <sys/bus.h> 37237981Smav#include <sys/sbuf.h> 38237981Smav#include <sys/module.h> 39237981Smav#include <sys/sysctl.h> 40237981Smav 41237981Smav#include <contrib/dev/acpica/include/acpi.h> 42237981Smav#include <contrib/dev/acpica/include/accommon.h> 43237981Smav#include <dev/acpica/acpivar.h> 44237981Smav#include "acpi_wmi_if.h" 45237981Smav 46237981Smav#define _COMPONENT ACPI_OEM 47237981SmavACPI_MODULE_NAME("ASUS-WMI") 48237981Smav 49237981Smav#define ACPI_ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" 50237981Smav#define ACPI_ASUS_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" 51237981Smav#define ACPI_EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" 52237981Smav 53237981Smav/* WMI Methods */ 54237981Smav#define ASUS_WMI_METHODID_SPEC 0x43455053 55237981Smav#define ASUS_WMI_METHODID_SFUN 0x4E554653 56237981Smav#define ASUS_WMI_METHODID_DSTS 0x53544344 57237981Smav#define ASUS_WMI_METHODID_DSTS2 0x53545344 58237981Smav#define ASUS_WMI_METHODID_DEVS 0x53564544 59237981Smav#define ASUS_WMI_METHODID_INIT 0x54494E49 60237981Smav#define ASUS_WMI_METHODID_HKEY 0x59454B48 61237981Smav 62237981Smav#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE 63237981Smav 64237981Smav/* Wireless */ 65237981Smav#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001 66237981Smav#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 67237981Smav#define ASUS_WMI_DEVID_CWAP 0x00010003 68237981Smav#define ASUS_WMI_DEVID_WLAN 0x00010011 69237981Smav#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 70237981Smav#define ASUS_WMI_DEVID_GPS 0x00010015 71237981Smav#define ASUS_WMI_DEVID_WIMAX 0x00010017 72237981Smav#define ASUS_WMI_DEVID_WWAN3G 0x00010019 73237981Smav#define ASUS_WMI_DEVID_UWB 0x00010021 74237981Smav 75237981Smav/* LEDs */ 76237981Smav#define ASUS_WMI_DEVID_LED1 0x00020011 77237981Smav#define ASUS_WMI_DEVID_LED2 0x00020012 78237981Smav#define ASUS_WMI_DEVID_LED3 0x00020013 79237981Smav#define ASUS_WMI_DEVID_LED4 0x00020014 80237981Smav#define ASUS_WMI_DEVID_LED5 0x00020015 81237981Smav#define ASUS_WMI_DEVID_LED6 0x00020016 82237981Smav 83237981Smav/* Backlight and Brightness */ 84237981Smav#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 85237981Smav#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 86237981Smav#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 87237981Smav#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 88237981Smav 89237981Smav/* Misc */ 90237981Smav#define ASUS_WMI_DEVID_CAMERA 0x00060013 91237981Smav#define ASUS_WMI_DEVID_CARDREADER 0x00080013 92237981Smav#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 93237981Smav#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 94237981Smav#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 95237981Smav#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 96237981Smav#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 97237981Smav 98237981Smav/* DSTS masks */ 99237981Smav#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 100237981Smav#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 101237981Smav#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000 102237981Smav#define ASUS_WMI_DSTS_USER_BIT 0x00020000 103237981Smav#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000 104237981Smav#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF 105237981Smav#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 106237981Smav 107237981Smav 108237981Smavstruct acpi_asus_wmi_softc { 109237981Smav device_t dev; 110237981Smav device_t wmi_dev; 111237981Smav const char *notify_guid; 112237981Smav struct sysctl_ctx_list *sysctl_ctx; 113237981Smav struct sysctl_oid *sysctl_tree; 114237981Smav int dsts_id; 115237981Smav int handle_keys; 116237981Smav}; 117237981Smav 118237981Smavstatic struct { 119237981Smav char *name; 120237981Smav int dev_id; 121237981Smav char *description; 122273736Shselasky int flag_rdonly; 123237981Smav} acpi_asus_wmi_sysctls[] = { 124237981Smav { 125237981Smav .name = "hw_switch", 126237981Smav .dev_id = ASUS_WMI_DEVID_HW_SWITCH, 127237981Smav .description = "hw_switch", 128237981Smav }, 129237981Smav { 130237981Smav .name = "wireless_led", 131237981Smav .dev_id = ASUS_WMI_DEVID_WIRELESS_LED, 132237981Smav .description = "Wireless LED control", 133237981Smav }, 134237981Smav { 135237981Smav .name = "cwap", 136237981Smav .dev_id = ASUS_WMI_DEVID_CWAP, 137237981Smav .description = "Alt+F2 function", 138237981Smav }, 139237981Smav { 140237981Smav .name = "wlan", 141237981Smav .dev_id = ASUS_WMI_DEVID_WLAN, 142237981Smav .description = "WLAN power control", 143237981Smav }, 144237981Smav { 145237981Smav .name = "bluetooth", 146237981Smav .dev_id = ASUS_WMI_DEVID_BLUETOOTH, 147237981Smav .description = "Bluetooth power control", 148237981Smav }, 149237981Smav { 150237981Smav .name = "gps", 151237981Smav .dev_id = ASUS_WMI_DEVID_GPS, 152237981Smav .description = "GPS power control", 153237981Smav }, 154237981Smav { 155237981Smav .name = "wimax", 156237981Smav .dev_id = ASUS_WMI_DEVID_WIMAX, 157237981Smav .description = "WiMAX power control", 158237981Smav }, 159237981Smav { 160237981Smav .name = "wwan3g", 161237981Smav .dev_id = ASUS_WMI_DEVID_WWAN3G, 162237981Smav .description = "WWAN-3G power control", 163237981Smav }, 164237981Smav { 165237981Smav .name = "uwb", 166237981Smav .dev_id = ASUS_WMI_DEVID_UWB, 167237981Smav .description = "UWB power control", 168237981Smav }, 169237981Smav { 170237981Smav .name = "led1", 171237981Smav .dev_id = ASUS_WMI_DEVID_LED1, 172237981Smav .description = "LED1 control", 173237981Smav }, 174237981Smav { 175237981Smav .name = "led2", 176237981Smav .dev_id = ASUS_WMI_DEVID_LED2, 177237981Smav .description = "LED2 control", 178237981Smav }, 179237981Smav { 180237981Smav .name = "led3", 181237981Smav .dev_id = ASUS_WMI_DEVID_LED3, 182237981Smav .description = "LED3 control", 183237981Smav }, 184237981Smav { 185237981Smav .name = "led4", 186237981Smav .dev_id = ASUS_WMI_DEVID_LED4, 187237981Smav .description = "LED4 control", 188237981Smav }, 189237981Smav { 190237981Smav .name = "led5", 191237981Smav .dev_id = ASUS_WMI_DEVID_LED5, 192237981Smav .description = "LED5 control", 193237981Smav }, 194237981Smav { 195237981Smav .name = "led6", 196237981Smav .dev_id = ASUS_WMI_DEVID_LED6, 197237981Smav .description = "LED6 control", 198237981Smav }, 199237981Smav { 200237981Smav .name = "backlight", 201237981Smav .dev_id = ASUS_WMI_DEVID_BACKLIGHT, 202237981Smav .description = "LCD backlight on/off control", 203237981Smav }, 204237981Smav { 205237981Smav .name = "brightness", 206237981Smav .dev_id = ASUS_WMI_DEVID_BRIGHTNESS, 207237981Smav .description = "LCD backlight brightness control", 208237981Smav }, 209237981Smav { 210237981Smav .name = "kbd_backlight", 211237981Smav .dev_id = ASUS_WMI_DEVID_KBD_BACKLIGHT, 212237981Smav .description = "Keyboard backlight brightness control", 213237981Smav }, 214237981Smav { 215237981Smav .name = "light_sensor", 216237981Smav .dev_id = ASUS_WMI_DEVID_LIGHT_SENSOR, 217237981Smav .description = "Ambient light sensor", 218237981Smav }, 219237981Smav { 220237981Smav .name = "camera", 221237981Smav .dev_id = ASUS_WMI_DEVID_CAMERA, 222237981Smav .description = "Camera power control", 223237981Smav }, 224237981Smav { 225237981Smav .name = "cardreader", 226237981Smav .dev_id = ASUS_WMI_DEVID_CARDREADER, 227237981Smav .description = "Cardreader power control", 228237981Smav }, 229237981Smav { 230237981Smav .name = "touchpad", 231237981Smav .dev_id = ASUS_WMI_DEVID_TOUCHPAD, 232237981Smav .description = "Touchpad control", 233237981Smav }, 234237981Smav { 235237981Smav .name = "touchpad_led", 236237981Smav .dev_id = ASUS_WMI_DEVID_TOUCHPAD_LED, 237237981Smav .description = "Touchpad LED control", 238237981Smav }, 239237981Smav { 240237981Smav .name = "themperature", 241237981Smav .dev_id = ASUS_WMI_DEVID_THERMAL_CTRL, 242237981Smav .description = "Temperature (C)", 243273736Shselasky .flag_rdonly = 1 244237981Smav }, 245237981Smav { 246237981Smav .name = "fan_speed", 247237981Smav .dev_id = ASUS_WMI_DEVID_FAN_CTRL, 248237981Smav .description = "Fan speed (0-3)", 249273736Shselasky .flag_rdonly = 1 250237981Smav }, 251237981Smav { 252237981Smav .name = "processor_state", 253237981Smav .dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE, 254273736Shselasky .flag_rdonly = 1 255237981Smav }, 256237981Smav { NULL, 0, NULL, 0 } 257237981Smav}; 258237981Smav 259237981SmavACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device"); 260237981Smav 261237981Smavstatic void acpi_asus_wmi_identify(driver_t *driver, device_t parent); 262237981Smavstatic int acpi_asus_wmi_probe(device_t dev); 263237981Smavstatic int acpi_asus_wmi_attach(device_t dev); 264237981Smavstatic int acpi_asus_wmi_detach(device_t dev); 265237981Smav 266237981Smavstatic int acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS); 267237981Smavstatic int acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, 268237981Smav int arg, int oldarg); 269237981Smavstatic int acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id); 270237981Smavstatic int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method, 271237981Smav UINT32 arg0, UINT32 arg1, UINT32 *retval); 272237981Smavstatic int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc, 273237981Smav UINT32 dev_id, UINT32 *retval); 274237981Smavstatic int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc, 275237981Smav UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval); 276237981Smavstatic void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context); 277237981Smav 278237981Smavstatic device_method_t acpi_asus_wmi_methods[] = { 279237981Smav DEVMETHOD(device_identify, acpi_asus_wmi_identify), 280237981Smav DEVMETHOD(device_probe, acpi_asus_wmi_probe), 281237981Smav DEVMETHOD(device_attach, acpi_asus_wmi_attach), 282237981Smav DEVMETHOD(device_detach, acpi_asus_wmi_detach), 283246128Ssbz 284246128Ssbz DEVMETHOD_END 285237981Smav}; 286237981Smav 287237981Smavstatic driver_t acpi_asus_wmi_driver = { 288237981Smav "acpi_asus_wmi", 289237981Smav acpi_asus_wmi_methods, 290237981Smav sizeof(struct acpi_asus_wmi_softc), 291237981Smav}; 292237981Smav 293237981Smavstatic devclass_t acpi_asus_wmi_devclass; 294237981Smav 295237981SmavDRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 296237981Smav acpi_asus_wmi_devclass, 0, 0); 297237981SmavMODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1); 298237981SmavMODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1); 299237981Smav 300237981Smavstatic void 301237981Smavacpi_asus_wmi_identify(driver_t *driver, device_t parent) 302237981Smav{ 303237981Smav 304237981Smav /* Don't do anything if driver is disabled. */ 305237981Smav if (acpi_disabled("asus_wmi")) 306237981Smav return; 307237981Smav 308237981Smav /* Add only a single device instance. */ 309237981Smav if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL) 310237981Smav return; 311237981Smav 312237981Smav /* Check management GUID to see whether system is compatible. */ 313237981Smav if (!ACPI_WMI_PROVIDES_GUID_STRING(parent, 314237981Smav ACPI_ASUS_WMI_MGMT_GUID)) 315237981Smav return; 316237981Smav 317237981Smav if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL) 318237981Smav device_printf(parent, "add acpi_asus_wmi child failed\n"); 319237981Smav} 320237981Smav 321237981Smavstatic int 322237981Smavacpi_asus_wmi_probe(device_t dev) 323237981Smav{ 324237981Smav 325237981Smav if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev), 326237981Smav ACPI_ASUS_WMI_MGMT_GUID)) 327237981Smav return (EINVAL); 328237981Smav device_set_desc(dev, "ASUS WMI device"); 329237981Smav return (0); 330237981Smav} 331237981Smav 332237981Smavstatic int 333237981Smavacpi_asus_wmi_attach(device_t dev) 334237981Smav{ 335237981Smav struct acpi_asus_wmi_softc *sc; 336237981Smav UINT32 val; 337237981Smav int dev_id, i; 338237981Smav 339237981Smav ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 340237981Smav 341237981Smav sc = device_get_softc(dev); 342237981Smav sc->dev = dev; 343237981Smav sc->wmi_dev = device_get_parent(dev); 344237981Smav sc->handle_keys = 1; 345237981Smav 346237981Smav /* Check management GUID. */ 347237981Smav if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 348237981Smav ACPI_ASUS_WMI_MGMT_GUID)) { 349237981Smav device_printf(dev, 350237981Smav "WMI device does not provide the ASUS management GUID\n"); 351237981Smav return (EINVAL); 352237981Smav } 353237981Smav 354237981Smav /* Find proper DSTS method. */ 355237981Smav sc->dsts_id = ASUS_WMI_METHODID_DSTS; 356237981Smavnext: 357237981Smav for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) { 358237981Smav dev_id = acpi_asus_wmi_sysctls[i].dev_id; 359237981Smav if (acpi_wpi_asus_get_devstate(sc, dev_id, &val)) 360237981Smav continue; 361237981Smav break; 362237981Smav } 363237981Smav if (acpi_asus_wmi_sysctls[i].name == NULL) { 364237981Smav if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) { 365237981Smav sc->dsts_id = ASUS_WMI_METHODID_DSTS2; 366237981Smav goto next; 367237981Smav } else { 368237981Smav device_printf(dev, "Can not detect DSTS method ID\n"); 369237981Smav return (EINVAL); 370237981Smav } 371237981Smav } 372237981Smav 373237981Smav /* Find proper and attach to notufy GUID. */ 374237981Smav if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 375237981Smav ACPI_ASUS_WMI_EVENT_GUID)) 376237981Smav sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID; 377237981Smav else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 378237981Smav ACPI_EEEPC_WMI_EVENT_GUID)) 379237981Smav sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID; 380237981Smav else 381237981Smav sc->notify_guid = NULL; 382237981Smav if (sc->notify_guid != NULL) { 383237981Smav if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev, 384237981Smav sc->notify_guid, acpi_asus_wmi_notify, dev)) 385237981Smav sc->notify_guid = NULL; 386237981Smav } 387237981Smav if (sc->notify_guid == NULL) 388237981Smav device_printf(dev, "Could not install event handler!\n"); 389237981Smav 390237981Smav /* Initialize. */ 391237981Smav if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, 392237981Smav ASUS_WMI_METHODID_INIT, 0, 0, &val) && bootverbose) 393237981Smav device_printf(dev, "Initialization: %#x\n", val); 394237981Smav if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, 395237981Smav ASUS_WMI_METHODID_SPEC, 0, 0x9, &val) && bootverbose) 396237981Smav device_printf(dev, "WMI BIOS version: %d.%d\n", 397237981Smav val >> 16, val & 0xFF); 398237981Smav if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, 399237981Smav ASUS_WMI_METHODID_SFUN, 0, 0, &val) && bootverbose) 400237981Smav device_printf(dev, "SFUN value: %#x\n", val); 401237981Smav 402237981Smav ACPI_SERIAL_BEGIN(asus_wmi); 403237981Smav 404237981Smav sc->sysctl_ctx = device_get_sysctl_ctx(dev); 405237981Smav sc->sysctl_tree = device_get_sysctl_tree(dev); 406237981Smav SYSCTL_ADD_INT(sc->sysctl_ctx, 407237981Smav SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 408237981Smav "handle_keys", CTLFLAG_RW, &sc->handle_keys, 409237981Smav 0, "Handle some hardware keys inside the driver"); 410237981Smav for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) { 411237981Smav dev_id = acpi_asus_wmi_sysctls[i].dev_id; 412237981Smav if (acpi_wpi_asus_get_devstate(sc, dev_id, &val)) 413237981Smav continue; 414237981Smav switch (dev_id) { 415237981Smav case ASUS_WMI_DEVID_THERMAL_CTRL: 416237981Smav case ASUS_WMI_DEVID_PROCESSOR_STATE: 417237981Smav case ASUS_WMI_DEVID_FAN_CTRL: 418237981Smav case ASUS_WMI_DEVID_BRIGHTNESS: 419237981Smav if (val == 0) 420237981Smav continue; 421237981Smav break; 422237981Smav default: 423237981Smav if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0) 424237981Smav continue; 425237981Smav break; 426237981Smav } 427237981Smav 428273736Shselasky if (acpi_asus_wmi_sysctls[i].flag_rdonly != 0) { 429273736Shselasky SYSCTL_ADD_PROC(sc->sysctl_ctx, 430273736Shselasky SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 431273736Shselasky acpi_asus_wmi_sysctls[i].name, 432273736Shselasky CTLTYPE_INT | CTLFLAG_RD, 433273736Shselasky sc, i, acpi_asus_wmi_sysctl, "I", 434273736Shselasky acpi_asus_wmi_sysctls[i].description); 435273736Shselasky } else { 436273736Shselasky SYSCTL_ADD_PROC(sc->sysctl_ctx, 437273736Shselasky SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 438273736Shselasky acpi_asus_wmi_sysctls[i].name, 439273736Shselasky CTLTYPE_INT | CTLFLAG_RW, 440273736Shselasky sc, i, acpi_asus_wmi_sysctl, "I", 441273736Shselasky acpi_asus_wmi_sysctls[i].description); 442273736Shselasky } 443237981Smav } 444237981Smav ACPI_SERIAL_END(asus_wmi); 445237981Smav 446237981Smav return (0); 447237981Smav} 448237981Smav 449237981Smavstatic int 450237981Smavacpi_asus_wmi_detach(device_t dev) 451237981Smav{ 452237981Smav struct acpi_asus_wmi_softc *sc = device_get_softc(dev); 453237981Smav 454237981Smav ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 455237981Smav 456237981Smav if (sc->notify_guid) 457237981Smav ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid); 458237981Smav 459237981Smav return (0); 460237981Smav} 461237981Smav 462237981Smavstatic int 463237981Smavacpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS) 464237981Smav{ 465237981Smav struct acpi_asus_wmi_softc *sc; 466237981Smav int arg; 467237981Smav int oldarg; 468237981Smav int error = 0; 469237981Smav int function; 470237981Smav int dev_id; 471237981Smav 472237981Smav ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 473237981Smav 474237981Smav sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1; 475237981Smav function = oidp->oid_arg2; 476237981Smav dev_id = acpi_asus_wmi_sysctls[function].dev_id; 477237981Smav 478237981Smav ACPI_SERIAL_BEGIN(asus_wmi); 479237981Smav arg = acpi_asus_wmi_sysctl_get(sc, dev_id); 480237981Smav oldarg = arg; 481237981Smav error = sysctl_handle_int(oidp, &arg, 0, req); 482237981Smav if (!error && req->newptr != NULL) 483237981Smav error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg); 484237981Smav ACPI_SERIAL_END(asus_wmi); 485237981Smav 486237981Smav return (error); 487237981Smav} 488237981Smav 489237981Smavstatic int 490237981Smavacpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id) 491237981Smav{ 492237981Smav UINT32 val = 0; 493237981Smav 494237981Smav ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 495237981Smav ACPI_SERIAL_ASSERT(asus_wmi); 496237981Smav 497237981Smav acpi_wpi_asus_get_devstate(sc, dev_id, &val); 498237981Smav 499237981Smav switch(dev_id) { 500237981Smav case ASUS_WMI_DEVID_THERMAL_CTRL: 501237981Smav val = (val - 2732 + 5) / 10; 502237981Smav break; 503237981Smav case ASUS_WMI_DEVID_PROCESSOR_STATE: 504237981Smav case ASUS_WMI_DEVID_FAN_CTRL: 505237981Smav break; 506237981Smav case ASUS_WMI_DEVID_BRIGHTNESS: 507237981Smav val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK; 508237981Smav break; 509237981Smav case ASUS_WMI_DEVID_KBD_BACKLIGHT: 510237981Smav val &= 0x7; 511237981Smav break; 512237981Smav default: 513237981Smav if (val & ASUS_WMI_DSTS_UNKNOWN_BIT) 514237981Smav val = -1; 515237981Smav else 516237981Smav val = !!(val & ASUS_WMI_DSTS_STATUS_BIT); 517237981Smav break; 518237981Smav } 519237981Smav 520237981Smav return (val); 521237981Smav} 522237981Smav 523237981Smavstatic int 524237981Smavacpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg) 525237981Smav{ 526237981Smav ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 527237981Smav ACPI_SERIAL_ASSERT(asus_wmi); 528237981Smav 529237981Smav switch(dev_id) { 530237981Smav case ASUS_WMI_DEVID_KBD_BACKLIGHT: 531237981Smav arg = min(0x7, arg); 532237981Smav if (arg != 0) 533237981Smav arg |= 0x80; 534237981Smav break; 535237981Smav } 536237981Smav 537237981Smav acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL); 538237981Smav 539237981Smav return (0); 540237981Smav} 541237981Smav 542237981Smavstatic __inline void 543237981Smavacpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) { 544237981Smav if (buf && buf->Pointer) { 545237981Smav AcpiOsFree(buf->Pointer); 546237981Smav } 547237981Smav} 548237981Smav 549237981Smavstatic void 550237981Smavacpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context) 551237981Smav{ 552237981Smav device_t dev = context; 553237981Smav ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 554237981Smav UINT32 val; 555237981Smav int code = 0; 556237981Smav 557237981Smav struct acpi_asus_wmi_softc *sc = device_get_softc(dev); 558237981Smav ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL }; 559237981Smav ACPI_OBJECT *obj; 560237981Smav ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response); 561237981Smav obj = (ACPI_OBJECT*) response.Pointer; 562237981Smav if (obj && obj->Type == ACPI_TYPE_INTEGER) { 563237981Smav code = obj->Integer.Value; 564237981Smav acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT, 565237981Smav code); 566237981Smav } 567237981Smav if (code && sc->handle_keys) { 568237981Smav /* Keyboard backlight control. */ 569237981Smav if (code == 0xc4 || code == 0xc5) { 570237981Smav acpi_wpi_asus_get_devstate(sc, 571237981Smav ASUS_WMI_DEVID_KBD_BACKLIGHT, &val); 572237981Smav val &= 0x7; 573237981Smav if (code == 0xc4) { 574237981Smav if (val < 0x7) 575237981Smav val++; 576237981Smav } else if (val > 0) 577237981Smav val--; 578237981Smav if (val != 0) 579237981Smav val |= 0x80; 580237981Smav acpi_wpi_asus_set_devstate(sc, 581237981Smav ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL); 582237981Smav } 583237981Smav /* Touchpad control. */ 584237981Smav if (code == 0x6b) { 585237981Smav acpi_wpi_asus_get_devstate(sc, 586237981Smav ASUS_WMI_DEVID_TOUCHPAD, &val); 587237981Smav val = !(val & 1); 588237981Smav acpi_wpi_asus_set_devstate(sc, 589237981Smav ASUS_WMI_DEVID_TOUCHPAD, val, NULL); 590237981Smav } 591237981Smav } 592237981Smav acpi_asus_wmi_free_buffer(&response); 593237981Smav} 594237981Smav 595237981Smavstatic int 596237981Smavacpi_asus_wmi_evaluate_method(device_t wmi_dev, int method, 597237981Smav UINT32 arg0, UINT32 arg1, UINT32 *retval) 598237981Smav{ 599237981Smav UINT32 params[2] = { arg0, arg1 }; 600237981Smav UINT32 result; 601237981Smav ACPI_OBJECT *obj; 602237981Smav ACPI_BUFFER in = { sizeof(params), ¶ms }; 603237981Smav ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL }; 604237981Smav 605237981Smav if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev, 606237981Smav ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) { 607237981Smav acpi_asus_wmi_free_buffer(&out); 608237981Smav return (-EINVAL); 609237981Smav } 610237981Smav obj = out.Pointer; 611237981Smav if (obj && obj->Type == ACPI_TYPE_INTEGER) 612237981Smav result = (UINT32) obj->Integer.Value; 613237981Smav else 614237981Smav result = 0; 615237981Smav acpi_asus_wmi_free_buffer(&out); 616237981Smav if (retval) 617237981Smav *retval = result; 618237981Smav return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0); 619237981Smav} 620237981Smav 621237981Smavstatic int 622237981Smavacpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc, 623237981Smav UINT32 dev_id, UINT32 *retval) 624237981Smav{ 625237981Smav 626237981Smav return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, 627237981Smav sc->dsts_id, dev_id, 0, retval)); 628237981Smav} 629237981Smav 630237981Smavstatic int 631237981Smavacpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc, 632237981Smav UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval) 633237981Smav{ 634237981Smav 635237981Smav return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, 636237981Smav ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval)); 637237981Smav} 638