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