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 struct acpi_asus_wmi_softc { 108 device_t dev; 109 device_t wmi_dev; 110 const char *notify_guid; 111 struct sysctl_ctx_list *sysctl_ctx; 112 struct sysctl_oid *sysctl_tree; 113 int dsts_id; 114 int handle_keys; 115 }; 116 117 static struct { 118 char *name; 119 int dev_id; 120 char *description; 121 int flag_rdonly; 122 } acpi_asus_wmi_sysctls[] = { 123 { 124 .name = "hw_switch", 125 .dev_id = ASUS_WMI_DEVID_HW_SWITCH, 126 .description = "hw_switch", 127 }, 128 { 129 .name = "wireless_led", 130 .dev_id = ASUS_WMI_DEVID_WIRELESS_LED, 131 .description = "Wireless LED control", 132 }, 133 { 134 .name = "cwap", 135 .dev_id = ASUS_WMI_DEVID_CWAP, 136 .description = "Alt+F2 function", 137 }, 138 { 139 .name = "wlan", 140 .dev_id = ASUS_WMI_DEVID_WLAN, 141 .description = "WLAN power control", 142 }, 143 { 144 .name = "bluetooth", 145 .dev_id = ASUS_WMI_DEVID_BLUETOOTH, 146 .description = "Bluetooth power control", 147 }, 148 { 149 .name = "gps", 150 .dev_id = ASUS_WMI_DEVID_GPS, 151 .description = "GPS power control", 152 }, 153 { 154 .name = "wimax", 155 .dev_id = ASUS_WMI_DEVID_WIMAX, 156 .description = "WiMAX power control", 157 }, 158 { 159 .name = "wwan3g", 160 .dev_id = ASUS_WMI_DEVID_WWAN3G, 161 .description = "WWAN-3G power control", 162 }, 163 { 164 .name = "uwb", 165 .dev_id = ASUS_WMI_DEVID_UWB, 166 .description = "UWB power control", 167 }, 168 { 169 .name = "led1", 170 .dev_id = ASUS_WMI_DEVID_LED1, 171 .description = "LED1 control", 172 }, 173 { 174 .name = "led2", 175 .dev_id = ASUS_WMI_DEVID_LED2, 176 .description = "LED2 control", 177 }, 178 { 179 .name = "led3", 180 .dev_id = ASUS_WMI_DEVID_LED3, 181 .description = "LED3 control", 182 }, 183 { 184 .name = "led4", 185 .dev_id = ASUS_WMI_DEVID_LED4, 186 .description = "LED4 control", 187 }, 188 { 189 .name = "led5", 190 .dev_id = ASUS_WMI_DEVID_LED5, 191 .description = "LED5 control", 192 }, 193 { 194 .name = "led6", 195 .dev_id = ASUS_WMI_DEVID_LED6, 196 .description = "LED6 control", 197 }, 198 { 199 .name = "backlight", 200 .dev_id = ASUS_WMI_DEVID_BACKLIGHT, 201 .description = "LCD backlight on/off control", 202 }, 203 { 204 .name = "brightness", 205 .dev_id = ASUS_WMI_DEVID_BRIGHTNESS, 206 .description = "LCD backlight brightness control", 207 }, 208 { 209 .name = "kbd_backlight", 210 .dev_id = ASUS_WMI_DEVID_KBD_BACKLIGHT, 211 .description = "Keyboard backlight brightness control", 212 }, 213 { 214 .name = "light_sensor", 215 .dev_id = ASUS_WMI_DEVID_LIGHT_SENSOR, 216 .description = "Ambient light sensor", 217 }, 218 { 219 .name = "camera", 220 .dev_id = ASUS_WMI_DEVID_CAMERA, 221 .description = "Camera power control", 222 }, 223 { 224 .name = "cardreader", 225 .dev_id = ASUS_WMI_DEVID_CARDREADER, 226 .description = "Cardreader power control", 227 }, 228 { 229 .name = "touchpad", 230 .dev_id = ASUS_WMI_DEVID_TOUCHPAD, 231 .description = "Touchpad control", 232 }, 233 { 234 .name = "touchpad_led", 235 .dev_id = ASUS_WMI_DEVID_TOUCHPAD_LED, 236 .description = "Touchpad LED control", 237 }, 238 { 239 .name = "themperature", 240 .dev_id = ASUS_WMI_DEVID_THERMAL_CTRL, 241 .description = "Temperature (C)", 242 .flag_rdonly = 1 243 }, 244 { 245 .name = "fan_speed", 246 .dev_id = ASUS_WMI_DEVID_FAN_CTRL, 247 .description = "Fan speed (0-3)", 248 .flag_rdonly = 1 249 }, 250 { 251 .name = "processor_state", 252 .dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE, 253 .flag_rdonly = 1 254 }, 255 { NULL, 0, NULL, 0 } 256 }; 257 258 ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device"); 259 260 static void acpi_asus_wmi_identify(driver_t *driver, device_t parent); 261 static int acpi_asus_wmi_probe(device_t dev); 262 static int acpi_asus_wmi_attach(device_t dev); 263 static int acpi_asus_wmi_detach(device_t dev); 264 265 static int acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS); 266 static int acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, 267 int arg, int oldarg); 268 static int acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id); 269 static int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method, 270 UINT32 arg0, UINT32 arg1, UINT32 *retval); 271 static int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc, 272 UINT32 dev_id, UINT32 *retval); 273 static int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc, 274 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval); 275 static void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context); 276 277 static device_method_t acpi_asus_wmi_methods[] = { 278 DEVMETHOD(device_identify, acpi_asus_wmi_identify), 279 DEVMETHOD(device_probe, acpi_asus_wmi_probe), 280 DEVMETHOD(device_attach, acpi_asus_wmi_attach), 281 DEVMETHOD(device_detach, acpi_asus_wmi_detach), 282 283 DEVMETHOD_END 284 }; 285 286 static driver_t acpi_asus_wmi_driver = { 287 "acpi_asus_wmi", 288 acpi_asus_wmi_methods, 289 sizeof(struct acpi_asus_wmi_softc), 290 }; 291 292 DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 0, 0); 293 MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1); 294 MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1); 295 296 static void 297 acpi_asus_wmi_identify(driver_t *driver, device_t parent) 298 { 299 300 /* Don't do anything if driver is disabled. */ 301 if (acpi_disabled("asus_wmi")) 302 return; 303 304 /* Add only a single device instance. */ 305 if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL) 306 return; 307 308 /* Check management GUID to see whether system is compatible. */ 309 if (!ACPI_WMI_PROVIDES_GUID_STRING(parent, 310 ACPI_ASUS_WMI_MGMT_GUID)) 311 return; 312 313 if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL) 314 device_printf(parent, "add acpi_asus_wmi child failed\n"); 315 } 316 317 static int 318 acpi_asus_wmi_probe(device_t dev) 319 { 320 321 if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev), 322 ACPI_ASUS_WMI_MGMT_GUID)) 323 return (EINVAL); 324 device_set_desc(dev, "ASUS WMI device"); 325 return (0); 326 } 327 328 static int 329 acpi_asus_wmi_attach(device_t dev) 330 { 331 struct acpi_asus_wmi_softc *sc; 332 UINT32 val; 333 int dev_id, i; 334 335 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 336 337 sc = device_get_softc(dev); 338 sc->dev = dev; 339 sc->wmi_dev = device_get_parent(dev); 340 sc->handle_keys = 1; 341 342 /* Check management GUID. */ 343 if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 344 ACPI_ASUS_WMI_MGMT_GUID)) { 345 device_printf(dev, 346 "WMI device does not provide the ASUS management GUID\n"); 347 return (EINVAL); 348 } 349 350 /* Find proper DSTS method. */ 351 sc->dsts_id = ASUS_WMI_METHODID_DSTS; 352 next: 353 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) { 354 dev_id = acpi_asus_wmi_sysctls[i].dev_id; 355 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val)) 356 continue; 357 break; 358 } 359 if (acpi_asus_wmi_sysctls[i].name == NULL) { 360 if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) { 361 sc->dsts_id = ASUS_WMI_METHODID_DSTS2; 362 goto next; 363 } else { 364 device_printf(dev, "Can not detect DSTS method ID\n"); 365 return (EINVAL); 366 } 367 } 368 369 /* Find proper and attach to notufy GUID. */ 370 if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 371 ACPI_ASUS_WMI_EVENT_GUID)) 372 sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID; 373 else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 374 ACPI_EEEPC_WMI_EVENT_GUID)) 375 sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID; 376 else 377 sc->notify_guid = NULL; 378 if (sc->notify_guid != NULL) { 379 if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev, 380 sc->notify_guid, acpi_asus_wmi_notify, dev)) 381 sc->notify_guid = NULL; 382 } 383 if (sc->notify_guid == NULL) 384 device_printf(dev, "Could not install event handler!\n"); 385 386 /* Initialize. */ 387 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, 388 ASUS_WMI_METHODID_INIT, 0, 0, &val) && bootverbose) 389 device_printf(dev, "Initialization: %#x\n", val); 390 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, 391 ASUS_WMI_METHODID_SPEC, 0, 0x9, &val) && bootverbose) 392 device_printf(dev, "WMI BIOS version: %d.%d\n", 393 val >> 16, val & 0xFF); 394 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, 395 ASUS_WMI_METHODID_SFUN, 0, 0, &val) && bootverbose) 396 device_printf(dev, "SFUN value: %#x\n", val); 397 398 ACPI_SERIAL_BEGIN(asus_wmi); 399 400 sc->sysctl_ctx = device_get_sysctl_ctx(dev); 401 sc->sysctl_tree = device_get_sysctl_tree(dev); 402 SYSCTL_ADD_INT(sc->sysctl_ctx, 403 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 404 "handle_keys", CTLFLAG_RW, &sc->handle_keys, 405 0, "Handle some hardware keys inside the driver"); 406 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) { 407 dev_id = acpi_asus_wmi_sysctls[i].dev_id; 408 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val)) 409 continue; 410 switch (dev_id) { 411 case ASUS_WMI_DEVID_THERMAL_CTRL: 412 case ASUS_WMI_DEVID_PROCESSOR_STATE: 413 case ASUS_WMI_DEVID_FAN_CTRL: 414 case ASUS_WMI_DEVID_BRIGHTNESS: 415 if (val == 0) 416 continue; 417 break; 418 default: 419 if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0) 420 continue; 421 break; 422 } 423 424 if (acpi_asus_wmi_sysctls[i].flag_rdonly != 0) { 425 SYSCTL_ADD_PROC(sc->sysctl_ctx, 426 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 427 acpi_asus_wmi_sysctls[i].name, 428 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 429 sc, i, acpi_asus_wmi_sysctl, "I", 430 acpi_asus_wmi_sysctls[i].description); 431 } else { 432 SYSCTL_ADD_PROC(sc->sysctl_ctx, 433 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 434 acpi_asus_wmi_sysctls[i].name, 435 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 436 sc, i, acpi_asus_wmi_sysctl, "I", 437 acpi_asus_wmi_sysctls[i].description); 438 } 439 } 440 ACPI_SERIAL_END(asus_wmi); 441 442 return (0); 443 } 444 445 static int 446 acpi_asus_wmi_detach(device_t dev) 447 { 448 struct acpi_asus_wmi_softc *sc = device_get_softc(dev); 449 450 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 451 452 if (sc->notify_guid) 453 ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid); 454 455 return (0); 456 } 457 458 static int 459 acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS) 460 { 461 struct acpi_asus_wmi_softc *sc; 462 int arg; 463 int oldarg; 464 int error = 0; 465 int function; 466 int dev_id; 467 468 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 469 470 sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1; 471 function = oidp->oid_arg2; 472 dev_id = acpi_asus_wmi_sysctls[function].dev_id; 473 474 ACPI_SERIAL_BEGIN(asus_wmi); 475 arg = acpi_asus_wmi_sysctl_get(sc, dev_id); 476 oldarg = arg; 477 error = sysctl_handle_int(oidp, &arg, 0, req); 478 if (!error && req->newptr != NULL) 479 error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg); 480 ACPI_SERIAL_END(asus_wmi); 481 482 return (error); 483 } 484 485 static int 486 acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id) 487 { 488 UINT32 val = 0; 489 490 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 491 ACPI_SERIAL_ASSERT(asus_wmi); 492 493 acpi_wpi_asus_get_devstate(sc, dev_id, &val); 494 495 switch(dev_id) { 496 case ASUS_WMI_DEVID_THERMAL_CTRL: 497 val = (val - 2731 + 5) / 10; 498 break; 499 case ASUS_WMI_DEVID_PROCESSOR_STATE: 500 case ASUS_WMI_DEVID_FAN_CTRL: 501 break; 502 case ASUS_WMI_DEVID_BRIGHTNESS: 503 val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK; 504 break; 505 case ASUS_WMI_DEVID_KBD_BACKLIGHT: 506 val &= 0x7; 507 break; 508 default: 509 if (val & ASUS_WMI_DSTS_UNKNOWN_BIT) 510 val = -1; 511 else 512 val = !!(val & ASUS_WMI_DSTS_STATUS_BIT); 513 break; 514 } 515 516 return (val); 517 } 518 519 static int 520 acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg) 521 { 522 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 523 ACPI_SERIAL_ASSERT(asus_wmi); 524 525 switch(dev_id) { 526 case ASUS_WMI_DEVID_KBD_BACKLIGHT: 527 arg = min(0x7, arg); 528 if (arg != 0) 529 arg |= 0x80; 530 break; 531 } 532 533 acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL); 534 535 return (0); 536 } 537 538 static __inline void 539 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) { 540 if (buf && buf->Pointer) { 541 AcpiOsFree(buf->Pointer); 542 } 543 } 544 545 static void 546 acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context) 547 { 548 device_t dev = context; 549 ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 550 UINT32 val; 551 int code = 0; 552 553 struct acpi_asus_wmi_softc *sc = device_get_softc(dev); 554 ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL }; 555 ACPI_OBJECT *obj; 556 ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response); 557 obj = (ACPI_OBJECT*) response.Pointer; 558 if (obj && obj->Type == ACPI_TYPE_INTEGER) { 559 code = obj->Integer.Value; 560 acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT, 561 code); 562 } 563 if (code && sc->handle_keys) { 564 /* Keyboard backlight control. */ 565 if (code == 0xc4 || code == 0xc5) { 566 acpi_wpi_asus_get_devstate(sc, 567 ASUS_WMI_DEVID_KBD_BACKLIGHT, &val); 568 val &= 0x7; 569 if (code == 0xc4) { 570 if (val < 0x7) 571 val++; 572 } else if (val > 0) 573 val--; 574 if (val != 0) 575 val |= 0x80; 576 acpi_wpi_asus_set_devstate(sc, 577 ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL); 578 } 579 /* Touchpad control. */ 580 if (code == 0x6b) { 581 acpi_wpi_asus_get_devstate(sc, 582 ASUS_WMI_DEVID_TOUCHPAD, &val); 583 val = !(val & 1); 584 acpi_wpi_asus_set_devstate(sc, 585 ASUS_WMI_DEVID_TOUCHPAD, val, NULL); 586 } 587 } 588 acpi_asus_wmi_free_buffer(&response); 589 } 590 591 static int 592 acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method, 593 UINT32 arg0, UINT32 arg1, UINT32 *retval) 594 { 595 UINT32 params[2] = { arg0, arg1 }; 596 UINT32 result; 597 ACPI_OBJECT *obj; 598 ACPI_BUFFER in = { sizeof(params), ¶ms }; 599 ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL }; 600 601 if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev, 602 ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) { 603 acpi_asus_wmi_free_buffer(&out); 604 return (-EINVAL); 605 } 606 obj = out.Pointer; 607 if (obj && obj->Type == ACPI_TYPE_INTEGER) 608 result = (UINT32) obj->Integer.Value; 609 else 610 result = 0; 611 acpi_asus_wmi_free_buffer(&out); 612 if (retval) 613 *retval = result; 614 return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0); 615 } 616 617 static int 618 acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc, 619 UINT32 dev_id, UINT32 *retval) 620 { 621 622 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, 623 sc->dsts_id, dev_id, 0, retval)); 624 } 625 626 static int 627 acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc, 628 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval) 629 { 630 631 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, 632 ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval)); 633 } 634