1 /*-
2 * Copyright (c) 2012 Alexander Motin <[email protected]>
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 static devclass_t acpi_asus_wmi_devclass;
293
294 DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver,
295 acpi_asus_wmi_devclass, 0, 0);
296 MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
297 MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
298
299 static void
acpi_asus_wmi_identify(driver_t * driver,device_t parent)300 acpi_asus_wmi_identify(driver_t *driver, device_t parent)
301 {
302
303 /* Don't do anything if driver is disabled. */
304 if (acpi_disabled("asus_wmi"))
305 return;
306
307 /* Add only a single device instance. */
308 if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL)
309 return;
310
311 /* Check management GUID to see whether system is compatible. */
312 if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
313 ACPI_ASUS_WMI_MGMT_GUID))
314 return;
315
316 if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL)
317 device_printf(parent, "add acpi_asus_wmi child failed\n");
318 }
319
320 static int
acpi_asus_wmi_probe(device_t dev)321 acpi_asus_wmi_probe(device_t dev)
322 {
323
324 if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev),
325 ACPI_ASUS_WMI_MGMT_GUID))
326 return (EINVAL);
327 device_set_desc(dev, "ASUS WMI device");
328 return (0);
329 }
330
331 static int
acpi_asus_wmi_attach(device_t dev)332 acpi_asus_wmi_attach(device_t dev)
333 {
334 struct acpi_asus_wmi_softc *sc;
335 UINT32 val;
336 int dev_id, i;
337
338 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
339
340 sc = device_get_softc(dev);
341 sc->dev = dev;
342 sc->wmi_dev = device_get_parent(dev);
343 sc->handle_keys = 1;
344
345 /* Check management GUID. */
346 if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
347 ACPI_ASUS_WMI_MGMT_GUID)) {
348 device_printf(dev,
349 "WMI device does not provide the ASUS management GUID\n");
350 return (EINVAL);
351 }
352
353 /* Find proper DSTS method. */
354 sc->dsts_id = ASUS_WMI_METHODID_DSTS;
355 next:
356 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
357 dev_id = acpi_asus_wmi_sysctls[i].dev_id;
358 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
359 continue;
360 break;
361 }
362 if (acpi_asus_wmi_sysctls[i].name == NULL) {
363 if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) {
364 sc->dsts_id = ASUS_WMI_METHODID_DSTS2;
365 goto next;
366 } else {
367 device_printf(dev, "Can not detect DSTS method ID\n");
368 return (EINVAL);
369 }
370 }
371
372 /* Find proper and attach to notufy GUID. */
373 if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
374 ACPI_ASUS_WMI_EVENT_GUID))
375 sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID;
376 else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
377 ACPI_EEEPC_WMI_EVENT_GUID))
378 sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID;
379 else
380 sc->notify_guid = NULL;
381 if (sc->notify_guid != NULL) {
382 if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
383 sc->notify_guid, acpi_asus_wmi_notify, dev))
384 sc->notify_guid = NULL;
385 }
386 if (sc->notify_guid == NULL)
387 device_printf(dev, "Could not install event handler!\n");
388
389 /* Initialize. */
390 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
391 ASUS_WMI_METHODID_INIT, 0, 0, &val) && bootverbose)
392 device_printf(dev, "Initialization: %#x\n", val);
393 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
394 ASUS_WMI_METHODID_SPEC, 0, 0x9, &val) && bootverbose)
395 device_printf(dev, "WMI BIOS version: %d.%d\n",
396 val >> 16, val & 0xFF);
397 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
398 ASUS_WMI_METHODID_SFUN, 0, 0, &val) && bootverbose)
399 device_printf(dev, "SFUN value: %#x\n", val);
400
401 ACPI_SERIAL_BEGIN(asus_wmi);
402
403 sc->sysctl_ctx = device_get_sysctl_ctx(dev);
404 sc->sysctl_tree = device_get_sysctl_tree(dev);
405 SYSCTL_ADD_INT(sc->sysctl_ctx,
406 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
407 "handle_keys", CTLFLAG_RW, &sc->handle_keys,
408 0, "Handle some hardware keys inside the driver");
409 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
410 dev_id = acpi_asus_wmi_sysctls[i].dev_id;
411 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
412 continue;
413 switch (dev_id) {
414 case ASUS_WMI_DEVID_THERMAL_CTRL:
415 case ASUS_WMI_DEVID_PROCESSOR_STATE:
416 case ASUS_WMI_DEVID_FAN_CTRL:
417 case ASUS_WMI_DEVID_BRIGHTNESS:
418 if (val == 0)
419 continue;
420 break;
421 default:
422 if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
423 continue;
424 break;
425 }
426
427 if (acpi_asus_wmi_sysctls[i].flag_rdonly != 0) {
428 SYSCTL_ADD_PROC(sc->sysctl_ctx,
429 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
430 acpi_asus_wmi_sysctls[i].name,
431 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
432 sc, i, acpi_asus_wmi_sysctl, "I",
433 acpi_asus_wmi_sysctls[i].description);
434 } else {
435 SYSCTL_ADD_PROC(sc->sysctl_ctx,
436 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
437 acpi_asus_wmi_sysctls[i].name,
438 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
439 sc, i, acpi_asus_wmi_sysctl, "I",
440 acpi_asus_wmi_sysctls[i].description);
441 }
442 }
443 ACPI_SERIAL_END(asus_wmi);
444
445 return (0);
446 }
447
448 static int
acpi_asus_wmi_detach(device_t dev)449 acpi_asus_wmi_detach(device_t dev)
450 {
451 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
452
453 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
454
455 if (sc->notify_guid)
456 ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
457
458 return (0);
459 }
460
461 static int
acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)462 acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
463 {
464 struct acpi_asus_wmi_softc *sc;
465 int arg;
466 int oldarg;
467 int error = 0;
468 int function;
469 int dev_id;
470
471 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
472
473 sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1;
474 function = oidp->oid_arg2;
475 dev_id = acpi_asus_wmi_sysctls[function].dev_id;
476
477 ACPI_SERIAL_BEGIN(asus_wmi);
478 arg = acpi_asus_wmi_sysctl_get(sc, dev_id);
479 oldarg = arg;
480 error = sysctl_handle_int(oidp, &arg, 0, req);
481 if (!error && req->newptr != NULL)
482 error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg);
483 ACPI_SERIAL_END(asus_wmi);
484
485 return (error);
486 }
487
488 static int
acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc * sc,int dev_id)489 acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
490 {
491 UINT32 val = 0;
492
493 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
494 ACPI_SERIAL_ASSERT(asus_wmi);
495
496 acpi_wpi_asus_get_devstate(sc, dev_id, &val);
497
498 switch(dev_id) {
499 case ASUS_WMI_DEVID_THERMAL_CTRL:
500 val = (val - 2731 + 5) / 10;
501 break;
502 case ASUS_WMI_DEVID_PROCESSOR_STATE:
503 case ASUS_WMI_DEVID_FAN_CTRL:
504 break;
505 case ASUS_WMI_DEVID_BRIGHTNESS:
506 val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
507 break;
508 case ASUS_WMI_DEVID_KBD_BACKLIGHT:
509 val &= 0x7;
510 break;
511 default:
512 if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
513 val = -1;
514 else
515 val = !!(val & ASUS_WMI_DSTS_STATUS_BIT);
516 break;
517 }
518
519 return (val);
520 }
521
522 static int
acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc * sc,int dev_id,int arg,int oldarg)523 acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg)
524 {
525 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
526 ACPI_SERIAL_ASSERT(asus_wmi);
527
528 switch(dev_id) {
529 case ASUS_WMI_DEVID_KBD_BACKLIGHT:
530 arg = min(0x7, arg);
531 if (arg != 0)
532 arg |= 0x80;
533 break;
534 }
535
536 acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL);
537
538 return (0);
539 }
540
541 static __inline void
acpi_asus_wmi_free_buffer(ACPI_BUFFER * buf)542 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
543 if (buf && buf->Pointer) {
544 AcpiOsFree(buf->Pointer);
545 }
546 }
547
548 static void
acpi_asus_wmi_notify(ACPI_HANDLE h,UINT32 notify,void * context)549 acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
550 {
551 device_t dev = context;
552 ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
553 UINT32 val;
554 int code = 0;
555
556 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
557 ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
558 ACPI_OBJECT *obj;
559 ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response);
560 obj = (ACPI_OBJECT*) response.Pointer;
561 if (obj && obj->Type == ACPI_TYPE_INTEGER) {
562 code = obj->Integer.Value;
563 acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
564 code);
565 }
566 if (code && sc->handle_keys) {
567 /* Keyboard backlight control. */
568 if (code == 0xc4 || code == 0xc5) {
569 acpi_wpi_asus_get_devstate(sc,
570 ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
571 val &= 0x7;
572 if (code == 0xc4) {
573 if (val < 0x7)
574 val++;
575 } else if (val > 0)
576 val--;
577 if (val != 0)
578 val |= 0x80;
579 acpi_wpi_asus_set_devstate(sc,
580 ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
581 }
582 /* Touchpad control. */
583 if (code == 0x6b) {
584 acpi_wpi_asus_get_devstate(sc,
585 ASUS_WMI_DEVID_TOUCHPAD, &val);
586 val = !(val & 1);
587 acpi_wpi_asus_set_devstate(sc,
588 ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
589 }
590 }
591 acpi_asus_wmi_free_buffer(&response);
592 }
593
594 static int
acpi_asus_wmi_evaluate_method(device_t wmi_dev,int method,UINT32 arg0,UINT32 arg1,UINT32 * retval)595 acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
596 UINT32 arg0, UINT32 arg1, UINT32 *retval)
597 {
598 UINT32 params[2] = { arg0, arg1 };
599 UINT32 result;
600 ACPI_OBJECT *obj;
601 ACPI_BUFFER in = { sizeof(params), ¶ms };
602 ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
603
604 if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev,
605 ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) {
606 acpi_asus_wmi_free_buffer(&out);
607 return (-EINVAL);
608 }
609 obj = out.Pointer;
610 if (obj && obj->Type == ACPI_TYPE_INTEGER)
611 result = (UINT32) obj->Integer.Value;
612 else
613 result = 0;
614 acpi_asus_wmi_free_buffer(&out);
615 if (retval)
616 *retval = result;
617 return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0);
618 }
619
620 static int
acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 * retval)621 acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
622 UINT32 dev_id, UINT32 *retval)
623 {
624
625 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
626 sc->dsts_id, dev_id, 0, retval));
627 }
628
629 static int
acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 ctrl_param,UINT32 * retval)630 acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
631 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval)
632 {
633
634 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
635 ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval));
636 }
637