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 __FBSDID("$FreeBSD$"); 29 30 #include "opt_acpi.h" 31 #include <sys/param.h> 32 #include <sys/conf.h> 33 #include <sys/uio.h> 34 #include <sys/proc.h> 35 #include <sys/kernel.h> 36 #include <sys/bus.h> 37 #include <sys/sbuf.h> 38 #include <sys/module.h> 39 #include <sys/sysctl.h> 40 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" 45 46 #define _COMPONENT ACPI_OEM 47 ACPI_MODULE_NAME("ASUS-WMI") 48 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" 52 53 /* WMI Methods */ 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 61 62 #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE 63 64 /* Wireless */ 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 74 75 /* LEDs */ 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 82 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 88 89 /* Misc */ 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 97 98 /* DSTS masks */ 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 106 107 108 struct acpi_asus_wmi_softc { 109 device_t dev; 110 device_t wmi_dev; 111 const char *notify_guid; 112 struct sysctl_ctx_list *sysctl_ctx; 113 struct sysctl_oid *sysctl_tree; 114 int dsts_id; 115 int handle_keys; 116 }; 117 118 static struct { 119 char *name; 120 int dev_id; 121 char *description; 122 int access; 123 } acpi_asus_wmi_sysctls[] = { 124 { 125 .name = "hw_switch", 126 .dev_id = ASUS_WMI_DEVID_HW_SWITCH, 127 .description = "hw_switch", 128 .access = CTLTYPE_INT | CTLFLAG_RW 129 }, 130 { 131 .name = "wireless_led", 132 .dev_id = ASUS_WMI_DEVID_WIRELESS_LED, 133 .description = "Wireless LED control", 134 .access = CTLTYPE_INT | CTLFLAG_RW 135 }, 136 { 137 .name = "cwap", 138 .dev_id = ASUS_WMI_DEVID_CWAP, 139 .description = "Alt+F2 function", 140 .access = CTLTYPE_INT | CTLFLAG_RW 141 }, 142 { 143 .name = "wlan", 144 .dev_id = ASUS_WMI_DEVID_WLAN, 145 .description = "WLAN power control", 146 .access = CTLTYPE_INT | CTLFLAG_RW 147 }, 148 { 149 .name = "bluetooth", 150 .dev_id = ASUS_WMI_DEVID_BLUETOOTH, 151 .description = "Bluetooth power control", 152 .access = CTLTYPE_INT | CTLFLAG_RW 153 }, 154 { 155 .name = "gps", 156 .dev_id = ASUS_WMI_DEVID_GPS, 157 .description = "GPS power control", 158 .access = CTLTYPE_INT | CTLFLAG_RW 159 }, 160 { 161 .name = "wimax", 162 .dev_id = ASUS_WMI_DEVID_WIMAX, 163 .description = "WiMAX power control", 164 .access = CTLTYPE_INT | CTLFLAG_RW 165 }, 166 { 167 .name = "wwan3g", 168 .dev_id = ASUS_WMI_DEVID_WWAN3G, 169 .description = "WWAN-3G power control", 170 .access = CTLTYPE_INT | CTLFLAG_RW 171 }, 172 { 173 .name = "uwb", 174 .dev_id = ASUS_WMI_DEVID_UWB, 175 .description = "UWB power control", 176 .access = CTLTYPE_INT | CTLFLAG_RW 177 }, 178 { 179 .name = "led1", 180 .dev_id = ASUS_WMI_DEVID_LED1, 181 .description = "LED1 control", 182 .access = CTLTYPE_INT | CTLFLAG_RW 183 }, 184 { 185 .name = "led2", 186 .dev_id = ASUS_WMI_DEVID_LED2, 187 .description = "LED2 control", 188 .access = CTLTYPE_INT | CTLFLAG_RW 189 }, 190 { 191 .name = "led3", 192 .dev_id = ASUS_WMI_DEVID_LED3, 193 .description = "LED3 control", 194 .access = CTLTYPE_INT | CTLFLAG_RW 195 }, 196 { 197 .name = "led4", 198 .dev_id = ASUS_WMI_DEVID_LED4, 199 .description = "LED4 control", 200 .access = CTLTYPE_INT | CTLFLAG_RW 201 }, 202 { 203 .name = "led5", 204 .dev_id = ASUS_WMI_DEVID_LED5, 205 .description = "LED5 control", 206 .access = CTLTYPE_INT | CTLFLAG_RW 207 }, 208 { 209 .name = "led6", 210 .dev_id = ASUS_WMI_DEVID_LED6, 211 .description = "LED6 control", 212 .access = CTLTYPE_INT | CTLFLAG_RW 213 }, 214 { 215 .name = "backlight", 216 .dev_id = ASUS_WMI_DEVID_BACKLIGHT, 217 .description = "LCD backlight on/off control", 218 .access = CTLTYPE_INT | CTLFLAG_RW 219 }, 220 { 221 .name = "brightness", 222 .dev_id = ASUS_WMI_DEVID_BRIGHTNESS, 223 .description = "LCD backlight brightness control", 224 .access = CTLTYPE_INT | CTLFLAG_RW 225 }, 226 { 227 .name = "kbd_backlight", 228 .dev_id = ASUS_WMI_DEVID_KBD_BACKLIGHT, 229 .description = "Keyboard backlight brightness control", 230 .access = CTLTYPE_INT | CTLFLAG_RW 231 }, 232 { 233 .name = "light_sensor", 234 .dev_id = ASUS_WMI_DEVID_LIGHT_SENSOR, 235 .description = "Ambient light sensor", 236 .access = CTLTYPE_INT | CTLFLAG_RW 237 }, 238 { 239 .name = "camera", 240 .dev_id = ASUS_WMI_DEVID_CAMERA, 241 .description = "Camera power control", 242 .access = CTLTYPE_INT | CTLFLAG_RW 243 }, 244 { 245 .name = "cardreader", 246 .dev_id = ASUS_WMI_DEVID_CARDREADER, 247 .description = "Cardreader power control", 248 .access = CTLTYPE_INT | CTLFLAG_RW 249 }, 250 { 251 .name = "touchpad", 252 .dev_id = ASUS_WMI_DEVID_TOUCHPAD, 253 .description = "Touchpad control", 254 .access = CTLTYPE_INT | CTLFLAG_RW 255 }, 256 { 257 .name = "touchpad_led", 258 .dev_id = ASUS_WMI_DEVID_TOUCHPAD_LED, 259 .description = "Touchpad LED control", 260 .access = CTLTYPE_INT | CTLFLAG_RW 261 }, 262 { 263 .name = "themperature", 264 .dev_id = ASUS_WMI_DEVID_THERMAL_CTRL, 265 .description = "Temperature (C)", 266 .access = CTLTYPE_INT | CTLFLAG_RD 267 }, 268 { 269 .name = "fan_speed", 270 .dev_id = ASUS_WMI_DEVID_FAN_CTRL, 271 .description = "Fan speed (0-3)", 272 .access = CTLTYPE_INT | CTLFLAG_RD 273 }, 274 { 275 .name = "processor_state", 276 .dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE, 277 .description = "Processor state", 278 .access = CTLTYPE_INT | CTLFLAG_RW 279 }, 280 { NULL, 0, NULL, 0 } 281 }; 282 283 ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device"); 284 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); 289 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); 301 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), 307 308 DEVMETHOD_END 309 }; 310 311 static driver_t acpi_asus_wmi_driver = { 312 "acpi_asus_wmi", 313 acpi_asus_wmi_methods, 314 sizeof(struct acpi_asus_wmi_softc), 315 }; 316 317 static devclass_t acpi_asus_wmi_devclass; 318 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); 323 324 static void 325 acpi_asus_wmi_identify(driver_t *driver, device_t parent) 326 { 327 328 /* Don't do anything if driver is disabled. */ 329 if (acpi_disabled("asus_wmi")) 330 return; 331 332 /* Add only a single device instance. */ 333 if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL) 334 return; 335 336 /* Check management GUID to see whether system is compatible. */ 337 if (!ACPI_WMI_PROVIDES_GUID_STRING(parent, 338 ACPI_ASUS_WMI_MGMT_GUID)) 339 return; 340 341 if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL) 342 device_printf(parent, "add acpi_asus_wmi child failed\n"); 343 } 344 345 static int 346 acpi_asus_wmi_probe(device_t dev) 347 { 348 349 if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev), 350 ACPI_ASUS_WMI_MGMT_GUID)) 351 return (EINVAL); 352 device_set_desc(dev, "ASUS WMI device"); 353 return (0); 354 } 355 356 static int 357 acpi_asus_wmi_attach(device_t dev) 358 { 359 struct acpi_asus_wmi_softc *sc; 360 UINT32 val; 361 int dev_id, i; 362 363 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 364 365 sc = device_get_softc(dev); 366 sc->dev = dev; 367 sc->wmi_dev = device_get_parent(dev); 368 sc->handle_keys = 1; 369 370 /* Check management GUID. */ 371 if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 372 ACPI_ASUS_WMI_MGMT_GUID)) { 373 device_printf(dev, 374 "WMI device does not provide the ASUS management GUID\n"); 375 return (EINVAL); 376 } 377 378 /* Find proper DSTS method. */ 379 sc->dsts_id = ASUS_WMI_METHODID_DSTS; 380 next: 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)) 384 continue; 385 break; 386 } 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; 390 goto next; 391 } else { 392 device_printf(dev, "Can not detect DSTS method ID\n"); 393 return (EINVAL); 394 } 395 } 396 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; 404 else 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; 410 } 411 if (sc->notify_guid == NULL) 412 device_printf(dev, "Could not install event handler!\n"); 413 414 /* Initialize. */ 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); 425 426 ACPI_SERIAL_BEGIN(asus_wmi); 427 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)) 437 continue; 438 switch (dev_id) { 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: 443 if (val == 0) 444 continue; 445 break; 446 default: 447 if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0) 448 continue; 449 break; 450 } 451 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); 458 } 459 ACPI_SERIAL_END(asus_wmi); 460 461 return (0); 462 } 463 464 static int 465 acpi_asus_wmi_detach(device_t dev) 466 { 467 struct acpi_asus_wmi_softc *sc = device_get_softc(dev); 468 469 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 470 471 if (sc->notify_guid) 472 ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid); 473 474 return (0); 475 } 476 477 static int 478 acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS) 479 { 480 struct acpi_asus_wmi_softc *sc; 481 int arg; 482 int oldarg; 483 int error = 0; 484 int function; 485 int dev_id; 486 487 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 488 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; 492 493 ACPI_SERIAL_BEGIN(asus_wmi); 494 arg = acpi_asus_wmi_sysctl_get(sc, dev_id); 495 oldarg = arg; 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); 500 501 return (error); 502 } 503 504 static int 505 acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id) 506 { 507 UINT32 val = 0; 508 509 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 510 ACPI_SERIAL_ASSERT(asus_wmi); 511 512 acpi_wpi_asus_get_devstate(sc, dev_id, &val); 513 514 switch(dev_id) { 515 case ASUS_WMI_DEVID_THERMAL_CTRL: 516 val = (val - 2732 + 5) / 10; 517 break; 518 case ASUS_WMI_DEVID_PROCESSOR_STATE: 519 case ASUS_WMI_DEVID_FAN_CTRL: 520 break; 521 case ASUS_WMI_DEVID_BRIGHTNESS: 522 val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK; 523 break; 524 case ASUS_WMI_DEVID_KBD_BACKLIGHT: 525 val &= 0x7; 526 break; 527 default: 528 if (val & ASUS_WMI_DSTS_UNKNOWN_BIT) 529 val = -1; 530 else 531 val = !!(val & ASUS_WMI_DSTS_STATUS_BIT); 532 break; 533 } 534 535 return (val); 536 } 537 538 static int 539 acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg) 540 { 541 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 542 ACPI_SERIAL_ASSERT(asus_wmi); 543 544 switch(dev_id) { 545 case ASUS_WMI_DEVID_KBD_BACKLIGHT: 546 arg = min(0x7, arg); 547 if (arg != 0) 548 arg |= 0x80; 549 break; 550 } 551 552 acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL); 553 554 return (0); 555 } 556 557 static __inline void 558 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) { 559 if (buf && buf->Pointer) { 560 AcpiOsFree(buf->Pointer); 561 } 562 } 563 564 static void 565 acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context) 566 { 567 device_t dev = context; 568 ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 569 UINT32 val; 570 int code = 0; 571 572 struct acpi_asus_wmi_softc *sc = device_get_softc(dev); 573 ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL }; 574 ACPI_OBJECT *obj; 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, 580 code); 581 } 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); 587 val &= 0x7; 588 if (code == 0xc4) { 589 if (val < 0x7) 590 val++; 591 } else if (val > 0) 592 val--; 593 if (val != 0) 594 val |= 0x80; 595 acpi_wpi_asus_set_devstate(sc, 596 ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL); 597 } 598 /* Touchpad control. */ 599 if (code == 0x6b) { 600 acpi_wpi_asus_get_devstate(sc, 601 ASUS_WMI_DEVID_TOUCHPAD, &val); 602 val = !(val & 1); 603 acpi_wpi_asus_set_devstate(sc, 604 ASUS_WMI_DEVID_TOUCHPAD, val, NULL); 605 } 606 } 607 acpi_asus_wmi_free_buffer(&response); 608 } 609 610 static int 611 acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method, 612 UINT32 arg0, UINT32 arg1, UINT32 *retval) 613 { 614 UINT32 params[2] = { arg0, arg1 }; 615 UINT32 result; 616 ACPI_OBJECT *obj; 617 ACPI_BUFFER in = { sizeof(params), ¶ms }; 618 ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL }; 619 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); 623 return (-EINVAL); 624 } 625 obj = out.Pointer; 626 if (obj && obj->Type == ACPI_TYPE_INTEGER) 627 result = (UINT32) obj->Integer.Value; 628 else 629 result = 0; 630 acpi_asus_wmi_free_buffer(&out); 631 if (retval) 632 *retval = result; 633 return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0); 634 } 635 636 static int 637 acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc, 638 UINT32 dev_id, UINT32 *retval) 639 { 640 641 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, 642 sc->dsts_id, dev_id, 0, retval)); 643 } 644 645 static int 646 acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc, 647 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval) 648 { 649 650 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, 651 ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval)); 652 } 653