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
acpi_asus_wmi_identify(driver_t * driver,device_t parent)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
acpi_asus_wmi_probe(device_t dev)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
acpi_asus_wmi_attach(device_t dev)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
acpi_asus_wmi_detach(device_t dev)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
acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)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
acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc * sc,int dev_id)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
acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc * sc,int dev_id,int arg,int oldarg)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
acpi_asus_wmi_free_buffer(ACPI_BUFFER * buf)537 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
538 if (buf && buf->Pointer) {
539 AcpiOsFree(buf->Pointer);
540 }
541 }
542
543 static void
acpi_asus_wmi_notify(ACPI_HANDLE h,UINT32 notify,void * context)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
acpi_asus_wmi_evaluate_method(device_t wmi_dev,int method,UINT32 arg0,UINT32 arg1,UINT32 * retval)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
acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 * retval)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
acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 ctrl_param,UINT32 * retval)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