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 427 devstate_to_kbd_bkl_level(UINT32 val) 428 { 429 return (acpi_asus_wmi_backlight_levels[val & 0x3]); 430 } 431 432 static inline UINT32 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 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", DEVICE_UNIT_ANY) != 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", DEVICE_UNIT_ANY) == NULL) 466 device_printf(parent, "add acpi_asus_wmi child failed\n"); 467 } 468 469 static int 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 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 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 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 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 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 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 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 790 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) { 791 if (buf && buf->Pointer) { 792 AcpiOsFree(buf->Pointer); 793 } 794 } 795 796 static int 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 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 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 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 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), ¶ms }; 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 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 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 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 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 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