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