Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpi_support/acpi_asus_wmi.c
39534 views
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
#include "opt_acpi.h"
29
#include "opt_evdev.h"
30
#include <sys/param.h>
31
#include <sys/conf.h>
32
#include <sys/uio.h>
33
#include <sys/proc.h>
34
#include <sys/kernel.h>
35
#include <sys/bus.h>
36
#include <sys/sbuf.h>
37
#include <sys/module.h>
38
#include <sys/sysctl.h>
39
40
#include <contrib/dev/acpica/include/acpi.h>
41
#include <contrib/dev/acpica/include/accommon.h>
42
#include <dev/acpica/acpivar.h>
43
#include "acpi_wmi_if.h"
44
45
#include <dev/backlight/backlight.h>
46
#include "backlight_if.h"
47
48
#ifdef EVDEV_SUPPORT
49
#include <dev/evdev/input.h>
50
#include <dev/evdev/evdev.h>
51
#define NO_KEY KEY_RESERVED
52
#endif
53
54
#define _COMPONENT ACPI_OEM
55
ACPI_MODULE_NAME("ASUS-WMI")
56
57
#define ACPI_ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
58
#define ACPI_ASUS_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
59
#define ACPI_EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
60
61
/* WMI Methods */
62
#define ASUS_WMI_METHODID_SPEC 0x43455053
63
#define ASUS_WMI_METHODID_SFUN 0x4E554653
64
#define ASUS_WMI_METHODID_DSTS 0x53544344
65
#define ASUS_WMI_METHODID_DSTS2 0x53545344
66
#define ASUS_WMI_METHODID_DEVS 0x53564544
67
#define ASUS_WMI_METHODID_INIT 0x54494E49
68
#define ASUS_WMI_METHODID_HKEY 0x59454B48
69
70
#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
71
72
/* Wireless */
73
#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
74
#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
75
#define ASUS_WMI_DEVID_CWAP 0x00010003
76
#define ASUS_WMI_DEVID_WLAN 0x00010011
77
#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
78
#define ASUS_WMI_DEVID_GPS 0x00010015
79
#define ASUS_WMI_DEVID_WIMAX 0x00010017
80
#define ASUS_WMI_DEVID_WWAN3G 0x00010019
81
#define ASUS_WMI_DEVID_UWB 0x00010021
82
83
/* LEDs */
84
#define ASUS_WMI_DEVID_LED1 0x00020011
85
#define ASUS_WMI_DEVID_LED2 0x00020012
86
#define ASUS_WMI_DEVID_LED3 0x00020013
87
#define ASUS_WMI_DEVID_LED4 0x00020014
88
#define ASUS_WMI_DEVID_LED5 0x00020015
89
#define ASUS_WMI_DEVID_LED6 0x00020016
90
91
/* Backlight and Brightness */
92
#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
93
#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
94
#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
95
#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022
96
97
/* Misc */
98
#define ASUS_WMI_DEVID_CAMERA 0x00060013
99
#define ASUS_WMI_DEVID_CARDREADER 0x00080013
100
#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
101
#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
102
#define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056
103
#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
104
#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
105
#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
106
#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
107
108
/* DSTS masks */
109
#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
110
#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
111
#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
112
#define ASUS_WMI_DSTS_USER_BIT 0x00020000
113
#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
114
#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
115
#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
116
117
/* Events */
118
#define ASUS_WMI_EVENT_QUEUE_SIZE 0x10
119
#define ASUS_WMI_EVENT_QUEUE_END 0x1
120
#define ASUS_WMI_EVENT_MASK 0xFFFF
121
#define ASUS_WMI_EVENT_VALUE_ATK 0xFF
122
123
struct acpi_asus_wmi_softc {
124
device_t dev;
125
device_t wmi_dev;
126
const char *notify_guid;
127
struct sysctl_ctx_list *sysctl_ctx;
128
struct sysctl_oid *sysctl_tree;
129
int dsts_id;
130
int handle_keys;
131
bool event_queue;
132
struct cdev *kbd_bkl;
133
uint32_t kbd_bkl_level;
134
uint32_t tuf_rgb_mode;
135
uint32_t ttp_mode;
136
#ifdef EVDEV_SUPPORT
137
struct evdev_dev *evdev;
138
#endif
139
};
140
141
static struct {
142
char *name;
143
int dev_id;
144
char *description;
145
int flag_rdonly;
146
} acpi_asus_wmi_sysctls[] = {
147
{
148
.name = "hw_switch",
149
.dev_id = ASUS_WMI_DEVID_HW_SWITCH,
150
.description = "hw_switch",
151
},
152
{
153
.name = "wireless_led",
154
.dev_id = ASUS_WMI_DEVID_WIRELESS_LED,
155
.description = "Wireless LED control",
156
},
157
{
158
.name = "cwap",
159
.dev_id = ASUS_WMI_DEVID_CWAP,
160
.description = "Alt+F2 function",
161
},
162
{
163
.name = "wlan",
164
.dev_id = ASUS_WMI_DEVID_WLAN,
165
.description = "WLAN power control",
166
},
167
{
168
.name = "bluetooth",
169
.dev_id = ASUS_WMI_DEVID_BLUETOOTH,
170
.description = "Bluetooth power control",
171
},
172
{
173
.name = "gps",
174
.dev_id = ASUS_WMI_DEVID_GPS,
175
.description = "GPS power control",
176
},
177
{
178
.name = "wimax",
179
.dev_id = ASUS_WMI_DEVID_WIMAX,
180
.description = "WiMAX power control",
181
},
182
{
183
.name = "wwan3g",
184
.dev_id = ASUS_WMI_DEVID_WWAN3G,
185
.description = "WWAN-3G power control",
186
},
187
{
188
.name = "uwb",
189
.dev_id = ASUS_WMI_DEVID_UWB,
190
.description = "UWB power control",
191
},
192
{
193
.name = "led1",
194
.dev_id = ASUS_WMI_DEVID_LED1,
195
.description = "LED1 control",
196
},
197
{
198
.name = "led2",
199
.dev_id = ASUS_WMI_DEVID_LED2,
200
.description = "LED2 control",
201
},
202
{
203
.name = "led3",
204
.dev_id = ASUS_WMI_DEVID_LED3,
205
.description = "LED3 control",
206
},
207
{
208
.name = "led4",
209
.dev_id = ASUS_WMI_DEVID_LED4,
210
.description = "LED4 control",
211
},
212
{
213
.name = "led5",
214
.dev_id = ASUS_WMI_DEVID_LED5,
215
.description = "LED5 control",
216
},
217
{
218
.name = "led6",
219
.dev_id = ASUS_WMI_DEVID_LED6,
220
.description = "LED6 control",
221
},
222
{
223
.name = "backlight",
224
.dev_id = ASUS_WMI_DEVID_BACKLIGHT,
225
.description = "LCD backlight on/off control",
226
},
227
{
228
.name = "brightness",
229
.dev_id = ASUS_WMI_DEVID_BRIGHTNESS,
230
.description = "LCD backlight brightness control",
231
},
232
{
233
.name = "kbd_backlight",
234
.dev_id = ASUS_WMI_DEVID_KBD_BACKLIGHT,
235
.description = "Keyboard backlight brightness control",
236
},
237
{
238
.name = "light_sensor",
239
.dev_id = ASUS_WMI_DEVID_LIGHT_SENSOR,
240
.description = "Ambient light sensor",
241
},
242
{
243
.name = "camera",
244
.dev_id = ASUS_WMI_DEVID_CAMERA,
245
.description = "Camera power control",
246
},
247
{
248
.name = "cardreader",
249
.dev_id = ASUS_WMI_DEVID_CARDREADER,
250
.description = "Cardreader power control",
251
},
252
{
253
.name = "touchpad",
254
.dev_id = ASUS_WMI_DEVID_TOUCHPAD,
255
.description = "Touchpad control",
256
},
257
{
258
.name = "touchpad_led",
259
.dev_id = ASUS_WMI_DEVID_TOUCHPAD_LED,
260
.description = "Touchpad LED control",
261
},
262
{
263
.name = "themperature",
264
.dev_id = ASUS_WMI_DEVID_THERMAL_CTRL,
265
.description = "Temperature (C)",
266
.flag_rdonly = 1
267
},
268
{
269
.name = "fan_speed",
270
.dev_id = ASUS_WMI_DEVID_FAN_CTRL,
271
.description = "Fan speed (0-3)",
272
.flag_rdonly = 1
273
},
274
{
275
.name = "processor_state",
276
.dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE,
277
.flag_rdonly = 1
278
},
279
{
280
.name = "throttle_thermal_policy",
281
.dev_id = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
282
.description = "Throttle Thermal Policy "
283
"(0 - default, 1 - overboost, 2 - silent)",
284
},
285
{ NULL, 0, NULL, 0 }
286
};
287
288
#ifdef EVDEV_SUPPORT
289
static const struct {
290
UINT32 notify;
291
uint16_t key;
292
} acpi_asus_wmi_evdev_map[] = {
293
{ 0x20, KEY_BRIGHTNESSDOWN },
294
{ 0x2f, KEY_BRIGHTNESSUP },
295
{ 0x30, KEY_VOLUMEUP },
296
{ 0x31, KEY_VOLUMEDOWN },
297
{ 0x32, KEY_MUTE },
298
{ 0x35, KEY_SCREENLOCK },
299
{ 0x38, KEY_PROG3 }, /* Armoury Crate */
300
{ 0x40, KEY_PREVIOUSSONG },
301
{ 0x41, KEY_NEXTSONG },
302
{ 0x43, KEY_STOPCD }, /* Stop/Eject */
303
{ 0x45, KEY_PLAYPAUSE },
304
{ 0x4f, KEY_LEFTMETA }, /* Fn-locked "Windows" Key */
305
{ 0x4c, KEY_MEDIA }, /* WMP Key */
306
{ 0x50, KEY_EMAIL },
307
{ 0x51, KEY_WWW },
308
{ 0x55, KEY_CALC },
309
{ 0x57, NO_KEY }, /* Battery mode */
310
{ 0x58, NO_KEY }, /* AC mode */
311
{ 0x5C, KEY_F15 }, /* Power Gear key */
312
{ 0x5D, KEY_WLAN }, /* Wireless console Toggle */
313
{ 0x5E, KEY_WLAN }, /* Wireless console Enable */
314
{ 0x5F, KEY_WLAN }, /* Wireless console Disable */
315
{ 0x60, KEY_TOUCHPAD_ON },
316
{ 0x61, KEY_SWITCHVIDEOMODE }, /* SDSP LCD only */
317
{ 0x62, KEY_SWITCHVIDEOMODE }, /* SDSP CRT only */
318
{ 0x63, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT */
319
{ 0x64, KEY_SWITCHVIDEOMODE }, /* SDSP TV */
320
{ 0x65, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV */
321
{ 0x66, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV */
322
{ 0x67, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV */
323
{ 0x6B, KEY_TOUCHPAD_TOGGLE },
324
{ 0x6E, NO_KEY }, /* Low Battery notification */
325
{ 0x71, KEY_F13 }, /* General-purpose button */
326
{ 0x79, NO_KEY }, /* Charger type dectection notification */
327
{ 0x7a, KEY_ALS_TOGGLE }, /* Ambient Light Sensor Toggle */
328
{ 0x7c, KEY_MICMUTE },
329
{ 0x7D, KEY_BLUETOOTH }, /* Bluetooth Enable */
330
{ 0x7E, KEY_BLUETOOTH }, /* Bluetooth Disable */
331
{ 0x82, KEY_CAMERA },
332
{ 0x86, KEY_PROG1 }, /* MyASUS Key */
333
{ 0x88, KEY_RFKILL }, /* Radio Toggle Key */
334
{ 0x8A, KEY_PROG1 }, /* Color enhancement mode */
335
{ 0x8C, KEY_SWITCHVIDEOMODE }, /* SDSP DVI only */
336
{ 0x8D, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + DVI */
337
{ 0x8E, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + DVI */
338
{ 0x8F, KEY_SWITCHVIDEOMODE }, /* SDSP TV + DVI */
339
{ 0x90, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + DVI */
340
{ 0x91, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV + DVI */
341
{ 0x92, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV + DVI */
342
{ 0x93, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV + DVI */
343
{ 0x95, KEY_MEDIA },
344
{ 0x99, KEY_PHONE }, /* Conflicts with fan mode switch */
345
{ 0xA0, KEY_SWITCHVIDEOMODE }, /* SDSP HDMI only */
346
{ 0xA1, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + HDMI */
347
{ 0xA2, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + HDMI */
348
{ 0xA3, KEY_SWITCHVIDEOMODE }, /* SDSP TV + HDMI */
349
{ 0xA4, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + HDMI */
350
{ 0xA5, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV + HDMI */
351
{ 0xA6, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV + HDMI */
352
{ 0xA7, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV + HDMI */
353
{ 0xAE, KEY_FN_F5 }, /* Fn+F5 fan mode on 2020+ */
354
{ 0xB3, KEY_PROG4 }, /* AURA */
355
{ 0xB5, KEY_CALC },
356
{ 0xC4, KEY_KBDILLUMUP },
357
{ 0xC5, KEY_KBDILLUMDOWN },
358
{ 0xC6, NO_KEY }, /* Ambient Light Sensor notification */
359
{ 0xFA, KEY_PROG2 }, /* Lid flip action */
360
{ 0xBD, KEY_PROG2 }, /* Lid flip action on ROG xflow laptops */
361
};
362
#endif
363
364
ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device");
365
366
static void acpi_asus_wmi_identify(driver_t *driver, device_t parent);
367
static int acpi_asus_wmi_probe(device_t dev);
368
static int acpi_asus_wmi_attach(device_t dev);
369
static int acpi_asus_wmi_detach(device_t dev);
370
static int acpi_asus_wmi_suspend(device_t dev);
371
static int acpi_asus_wmi_resume(device_t dev);
372
373
static int acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS);
374
static int acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id,
375
int arg, int oldarg);
376
static int acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id);
377
static int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
378
UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval);
379
static int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
380
UINT32 dev_id, UINT32 *retval);
381
static int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
382
UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
383
static int acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify,
384
int *code);
385
static void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
386
static int acpi_asus_wmi_backlight_update_status(device_t dev,
387
struct backlight_props *props);
388
static int acpi_asus_wmi_backlight_get_status(device_t dev,
389
struct backlight_props *props);
390
static int acpi_asus_wmi_backlight_get_info(device_t dev,
391
struct backlight_info *info);
392
393
static device_method_t acpi_asus_wmi_methods[] = {
394
/* Device interface */
395
DEVMETHOD(device_identify, acpi_asus_wmi_identify),
396
DEVMETHOD(device_probe, acpi_asus_wmi_probe),
397
DEVMETHOD(device_attach, acpi_asus_wmi_attach),
398
DEVMETHOD(device_detach, acpi_asus_wmi_detach),
399
DEVMETHOD(device_suspend, acpi_asus_wmi_suspend),
400
DEVMETHOD(device_resume, acpi_asus_wmi_resume),
401
402
/* Backlight interface */
403
DEVMETHOD(backlight_update_status, acpi_asus_wmi_backlight_update_status),
404
DEVMETHOD(backlight_get_status, acpi_asus_wmi_backlight_get_status),
405
DEVMETHOD(backlight_get_info, acpi_asus_wmi_backlight_get_info),
406
407
DEVMETHOD_END
408
};
409
410
static driver_t acpi_asus_wmi_driver = {
411
"acpi_asus_wmi",
412
acpi_asus_wmi_methods,
413
sizeof(struct acpi_asus_wmi_softc),
414
};
415
416
DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 0, 0);
417
MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
418
MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
419
MODULE_DEPEND(acpi_asus_wmi, backlight, 1, 1, 1);
420
#ifdef EVDEV_SUPPORT
421
MODULE_DEPEND(acpi_asus_wmi, evdev, 1, 1, 1);
422
#endif
423
424
static const uint32_t acpi_asus_wmi_backlight_levels[] = { 0, 33, 66, 100 };
425
426
static inline uint32_t
427
devstate_to_kbd_bkl_level(UINT32 val)
428
{
429
return (acpi_asus_wmi_backlight_levels[val & 0x3]);
430
}
431
432
static inline UINT32
433
kbd_bkl_level_to_devstate(uint32_t bkl)
434
{
435
UINT32 val;
436
int i;
437
438
for (i = 0; i < nitems(acpi_asus_wmi_backlight_levels); i++) {
439
if (bkl < acpi_asus_wmi_backlight_levels[i])
440
break;
441
}
442
val = (i - 1) & 0x3;
443
if (val != 0)
444
val |= 0x80;
445
return(val);
446
}
447
448
static void
449
acpi_asus_wmi_identify(driver_t *driver, device_t parent)
450
{
451
452
/* Don't do anything if driver is disabled. */
453
if (acpi_disabled("asus_wmi"))
454
return;
455
456
/* Add only a single device instance. */
457
if (device_find_child(parent, "acpi_asus_wmi", DEVICE_UNIT_ANY) != NULL)
458
return;
459
460
/* Check management GUID to see whether system is compatible. */
461
if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
462
ACPI_ASUS_WMI_MGMT_GUID))
463
return;
464
465
if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", DEVICE_UNIT_ANY) == NULL)
466
device_printf(parent, "add acpi_asus_wmi child failed\n");
467
}
468
469
static int
470
acpi_asus_wmi_probe(device_t dev)
471
{
472
473
if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev),
474
ACPI_ASUS_WMI_MGMT_GUID))
475
return (EINVAL);
476
device_set_desc(dev, "ASUS WMI device");
477
return (0);
478
}
479
480
static int
481
acpi_asus_wmi_attach(device_t dev)
482
{
483
struct acpi_asus_wmi_softc *sc;
484
UINT32 val;
485
int dev_id, i, code;
486
bool have_kbd_bkl = false;
487
488
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
489
490
sc = device_get_softc(dev);
491
sc->dev = dev;
492
sc->wmi_dev = device_get_parent(dev);
493
sc->handle_keys = 1;
494
495
/* Check management GUID. */
496
if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
497
ACPI_ASUS_WMI_MGMT_GUID)) {
498
device_printf(dev,
499
"WMI device does not provide the ASUS management GUID\n");
500
return (EINVAL);
501
}
502
503
/* Find proper DSTS method. */
504
sc->dsts_id = ASUS_WMI_METHODID_DSTS;
505
next:
506
for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
507
dev_id = acpi_asus_wmi_sysctls[i].dev_id;
508
if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
509
continue;
510
break;
511
}
512
if (acpi_asus_wmi_sysctls[i].name == NULL) {
513
if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) {
514
sc->dsts_id = ASUS_WMI_METHODID_DSTS2;
515
goto next;
516
} else {
517
device_printf(dev, "Can not detect DSTS method ID\n");
518
return (EINVAL);
519
}
520
}
521
522
/* Find proper and attach to notufy GUID. */
523
if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
524
ACPI_ASUS_WMI_EVENT_GUID))
525
sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID;
526
else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
527
ACPI_EEEPC_WMI_EVENT_GUID))
528
sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID;
529
else
530
sc->notify_guid = NULL;
531
if (sc->notify_guid != NULL) {
532
if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
533
sc->notify_guid, acpi_asus_wmi_notify, dev))
534
sc->notify_guid = NULL;
535
}
536
if (sc->notify_guid == NULL)
537
device_printf(dev, "Could not install event handler!\n");
538
539
/* Initialize. */
540
if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
541
ASUS_WMI_METHODID_INIT, 0, 0, 0, &val) && bootverbose)
542
device_printf(dev, "Initialization: %#x\n", val);
543
if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
544
ASUS_WMI_METHODID_SPEC, 0, 0x9, 0, &val) && bootverbose)
545
device_printf(dev, "WMI BIOS version: %d.%d\n",
546
val >> 16, val & 0xFF);
547
if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
548
ASUS_WMI_METHODID_SFUN, 0, 0, 0, &val) && bootverbose)
549
device_printf(dev, "SFUN value: %#x\n", val);
550
551
ACPI_SERIAL_BEGIN(asus_wmi);
552
553
sc->sysctl_ctx = device_get_sysctl_ctx(dev);
554
sc->sysctl_tree = device_get_sysctl_tree(dev);
555
SYSCTL_ADD_INT(sc->sysctl_ctx,
556
SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
557
"handle_keys", CTLFLAG_RW, &sc->handle_keys,
558
0, "Handle some hardware keys inside the driver");
559
for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
560
dev_id = acpi_asus_wmi_sysctls[i].dev_id;
561
if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
562
continue;
563
switch (dev_id) {
564
case ASUS_WMI_DEVID_THERMAL_CTRL:
565
case ASUS_WMI_DEVID_PROCESSOR_STATE:
566
case ASUS_WMI_DEVID_FAN_CTRL:
567
case ASUS_WMI_DEVID_BRIGHTNESS:
568
if (val == 0)
569
continue;
570
break;
571
case ASUS_WMI_DEVID_KBD_BACKLIGHT:
572
sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
573
have_kbd_bkl = true;
574
/* FALLTHROUGH */
575
default:
576
if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
577
continue;
578
break;
579
}
580
581
if (acpi_asus_wmi_sysctls[i].flag_rdonly != 0) {
582
SYSCTL_ADD_PROC(sc->sysctl_ctx,
583
SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
584
acpi_asus_wmi_sysctls[i].name,
585
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
586
sc, i, acpi_asus_wmi_sysctl, "I",
587
acpi_asus_wmi_sysctls[i].description);
588
} else {
589
SYSCTL_ADD_PROC(sc->sysctl_ctx,
590
SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
591
acpi_asus_wmi_sysctls[i].name,
592
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
593
sc, i, acpi_asus_wmi_sysctl, "I",
594
acpi_asus_wmi_sysctls[i].description);
595
}
596
}
597
ACPI_SERIAL_END(asus_wmi);
598
599
/* Detect and flush event queue */
600
if (sc->dsts_id == ASUS_WMI_METHODID_DSTS2) {
601
for (i = 0; i <= ASUS_WMI_EVENT_QUEUE_SIZE; i++) {
602
if (acpi_asus_wmi_get_event_code(sc->wmi_dev,
603
ASUS_WMI_EVENT_VALUE_ATK, &code) != 0) {
604
device_printf(dev,
605
"Can not flush event queue\n");
606
break;
607
}
608
if (code == ASUS_WMI_EVENT_QUEUE_END ||
609
code == ASUS_WMI_EVENT_MASK) {
610
sc->event_queue = true;
611
break;
612
}
613
}
614
}
615
616
#ifdef EVDEV_SUPPORT
617
if (sc->notify_guid != NULL) {
618
sc->evdev = evdev_alloc();
619
evdev_set_name(sc->evdev, device_get_desc(dev));
620
evdev_set_phys(sc->evdev, device_get_nameunit(dev));
621
evdev_set_id(sc->evdev, BUS_HOST, 0, 0, 1);
622
evdev_support_event(sc->evdev, EV_SYN);
623
evdev_support_event(sc->evdev, EV_KEY);
624
for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
625
if (acpi_asus_wmi_evdev_map[i].key != NO_KEY)
626
evdev_support_key(sc->evdev,
627
acpi_asus_wmi_evdev_map[i].key);
628
}
629
630
if (evdev_register(sc->evdev) != 0) {
631
device_printf(dev, "Can not register evdev\n");
632
acpi_asus_wmi_detach(dev);
633
return (ENXIO);
634
}
635
}
636
#endif
637
638
if (have_kbd_bkl) {
639
sc->kbd_bkl = backlight_register("acpi_asus_wmi", dev);
640
if (sc->kbd_bkl == NULL) {
641
device_printf(dev, "Can not register backlight\n");
642
acpi_asus_wmi_detach(dev);
643
return (ENXIO);
644
}
645
}
646
647
return (0);
648
}
649
650
static int
651
acpi_asus_wmi_detach(device_t dev)
652
{
653
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
654
655
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
656
657
if (sc->kbd_bkl != NULL)
658
backlight_destroy(sc->kbd_bkl);
659
660
if (sc->notify_guid) {
661
ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
662
#ifdef EVDEV_SUPPORT
663
evdev_free(sc->evdev);
664
#endif
665
}
666
667
return (0);
668
}
669
670
static int
671
acpi_asus_wmi_suspend(device_t dev)
672
{
673
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
674
675
if (sc->kbd_bkl != NULL) {
676
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
677
acpi_wpi_asus_set_devstate(sc,
678
ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, NULL);
679
}
680
681
return (0);
682
}
683
684
static int
685
acpi_asus_wmi_resume(device_t dev)
686
{
687
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
688
689
if (sc->kbd_bkl != NULL) {
690
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
691
acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
692
kbd_bkl_level_to_devstate(sc->kbd_bkl_level), NULL);
693
}
694
695
return (0);
696
}
697
698
static int
699
acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
700
{
701
struct acpi_asus_wmi_softc *sc;
702
int arg;
703
int oldarg;
704
int error = 0;
705
int function;
706
int dev_id;
707
708
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
709
710
sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1;
711
function = oidp->oid_arg2;
712
dev_id = acpi_asus_wmi_sysctls[function].dev_id;
713
714
ACPI_SERIAL_BEGIN(asus_wmi);
715
arg = acpi_asus_wmi_sysctl_get(sc, dev_id);
716
oldarg = arg;
717
error = sysctl_handle_int(oidp, &arg, 0, req);
718
if (!error && req->newptr != NULL)
719
error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg);
720
ACPI_SERIAL_END(asus_wmi);
721
722
return (error);
723
}
724
725
static int
726
acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
727
{
728
UINT32 val = 0;
729
730
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
731
ACPI_SERIAL_ASSERT(asus_wmi);
732
733
switch(dev_id) {
734
case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
735
return (sc->ttp_mode);
736
default:
737
break;
738
}
739
740
acpi_wpi_asus_get_devstate(sc, dev_id, &val);
741
742
switch(dev_id) {
743
case ASUS_WMI_DEVID_THERMAL_CTRL:
744
val = (val - 2731 + 5) / 10;
745
break;
746
case ASUS_WMI_DEVID_PROCESSOR_STATE:
747
case ASUS_WMI_DEVID_FAN_CTRL:
748
break;
749
case ASUS_WMI_DEVID_BRIGHTNESS:
750
val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
751
break;
752
case ASUS_WMI_DEVID_KBD_BACKLIGHT:
753
val &= 0x3;
754
break;
755
default:
756
if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
757
val = -1;
758
else
759
val = !!(val & ASUS_WMI_DSTS_STATUS_BIT);
760
break;
761
}
762
763
return (val);
764
}
765
766
static int
767
acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg)
768
{
769
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
770
ACPI_SERIAL_ASSERT(asus_wmi);
771
772
switch(dev_id) {
773
case ASUS_WMI_DEVID_KBD_BACKLIGHT:
774
arg = min(0x3, arg);
775
if (arg != 0)
776
arg |= 0x80;
777
break;
778
case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
779
arg = min(0x2, arg);
780
sc->ttp_mode = arg;
781
break;
782
}
783
784
acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL);
785
786
return (0);
787
}
788
789
static __inline void
790
acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
791
if (buf && buf->Pointer) {
792
AcpiOsFree(buf->Pointer);
793
}
794
}
795
796
static int
797
acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify, int *code)
798
{
799
ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
800
ACPI_OBJECT *obj;
801
int error = 0;
802
803
if (ACPI_FAILURE(ACPI_WMI_GET_EVENT_DATA(wmi_dev, notify, &response)))
804
return (EIO);
805
obj = (ACPI_OBJECT*) response.Pointer;
806
if (obj && obj->Type == ACPI_TYPE_INTEGER)
807
*code = obj->Integer.Value & ASUS_WMI_EVENT_MASK;
808
else
809
error = EINVAL;
810
acpi_asus_wmi_free_buffer(&response);
811
return (error);
812
}
813
814
#ifdef EVDEV_SUPPORT
815
static void
816
acpi_asus_wmi_push_evdev_event(struct evdev_dev *evdev, UINT32 notify)
817
{
818
int i;
819
uint16_t key;
820
821
for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
822
if (acpi_asus_wmi_evdev_map[i].notify == notify &&
823
acpi_asus_wmi_evdev_map[i].key != NO_KEY) {
824
key = acpi_asus_wmi_evdev_map[i].key;
825
evdev_push_key(evdev, key, 1);
826
evdev_sync(evdev);
827
evdev_push_key(evdev, key, 0);
828
evdev_sync(evdev);
829
break;
830
}
831
}
832
}
833
#endif
834
835
static void
836
acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc *sc, int code)
837
{
838
UINT32 val;
839
840
if (code != 0) {
841
acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
842
code);
843
#ifdef EVDEV_SUPPORT
844
acpi_asus_wmi_push_evdev_event(sc->evdev, code);
845
#endif
846
}
847
if (code && sc->handle_keys) {
848
/* Keyboard backlight control. */
849
if (code == 0xc4 || code == 0xc5) {
850
acpi_wpi_asus_get_devstate(sc,
851
ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
852
val &= 0x3;
853
if (code == 0xc4) {
854
if (val < 0x3)
855
val++;
856
} else if (val > 0)
857
val--;
858
if (val != 0)
859
val |= 0x80;
860
acpi_wpi_asus_set_devstate(sc,
861
ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
862
sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
863
}
864
/* Touchpad control. */
865
if (code == 0x6b) {
866
acpi_wpi_asus_get_devstate(sc,
867
ASUS_WMI_DEVID_TOUCHPAD, &val);
868
val = !(val & 1);
869
acpi_wpi_asus_set_devstate(sc,
870
ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
871
}
872
/* Throttle thermal policy control. */
873
if (code == 0xae) {
874
sc->ttp_mode++;
875
if (sc->ttp_mode > 2)
876
sc->ttp_mode = 0;
877
acpi_wpi_asus_set_devstate(sc,
878
ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
879
sc->ttp_mode, NULL);
880
}
881
/* TUF laptop RGB mode control. */
882
if (code == 0xb3) {
883
const uint32_t cmd = 0xb4; /* Save to BIOS */
884
const uint32_t r = 0xff, g = 0xff, b = 0xff;
885
const uint32_t speed = 0xeb; /* Medium */
886
if (sc->tuf_rgb_mode < 2)
887
sc->tuf_rgb_mode++;
888
else if (sc->tuf_rgb_mode == 2)
889
sc->tuf_rgb_mode = 10;
890
else sc->tuf_rgb_mode = 0;
891
acpi_asus_wmi_evaluate_method(sc->wmi_dev,
892
ASUS_WMI_METHODID_DEVS,
893
ASUS_WMI_DEVID_TUF_RGB_MODE,
894
cmd | (sc->tuf_rgb_mode << 8) | (r << 16) | (g << 24),
895
b | (speed << 8), NULL);
896
}
897
}
898
}
899
900
static void
901
acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
902
{
903
device_t dev = context;
904
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
905
int code = 0, i = 1;
906
907
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
908
909
if (sc->event_queue)
910
i += ASUS_WMI_EVENT_QUEUE_SIZE;
911
do {
912
if (acpi_asus_wmi_get_event_code(sc->wmi_dev, notify, &code)
913
!= 0) {
914
device_printf(dev, "Failed to get event code\n");
915
return;
916
}
917
if (code == ASUS_WMI_EVENT_QUEUE_END ||
918
code == ASUS_WMI_EVENT_MASK)
919
return;
920
acpi_asus_wmi_handle_event(sc, code);
921
if (notify != ASUS_WMI_EVENT_VALUE_ATK)
922
return;
923
} while (--i != 0);
924
if (sc->event_queue)
925
device_printf(dev, "Can not read event queue, "
926
"last code: 0x%x\n", code);
927
}
928
929
static int
930
acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
931
UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval)
932
{
933
UINT32 params[3] = { arg0, arg1, arg2 };
934
UINT32 result;
935
ACPI_OBJECT *obj;
936
ACPI_BUFFER in = { sizeof(params), &params };
937
ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
938
939
if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev,
940
ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) {
941
acpi_asus_wmi_free_buffer(&out);
942
return (-EINVAL);
943
}
944
obj = out.Pointer;
945
if (obj && obj->Type == ACPI_TYPE_INTEGER)
946
result = (UINT32) obj->Integer.Value;
947
else
948
result = 0;
949
acpi_asus_wmi_free_buffer(&out);
950
if (retval)
951
*retval = result;
952
return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0);
953
}
954
955
static int
956
acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
957
UINT32 dev_id, UINT32 *retval)
958
{
959
960
return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
961
sc->dsts_id, dev_id, 0, 0, retval));
962
}
963
964
static int
965
acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
966
UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval)
967
{
968
969
return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
970
ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, 0, retval));
971
}
972
973
static int
974
acpi_asus_wmi_backlight_update_status(device_t dev, struct backlight_props
975
*props)
976
{
977
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
978
979
acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
980
kbd_bkl_level_to_devstate(props->brightness), NULL);
981
sc->kbd_bkl_level = props->brightness;
982
983
return (0);
984
}
985
986
static int
987
acpi_asus_wmi_backlight_get_status(device_t dev, struct backlight_props *props)
988
{
989
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
990
991
props->brightness = sc->kbd_bkl_level;
992
props->nlevels = nitems(acpi_asus_wmi_backlight_levels);
993
memcpy(props->levels, acpi_asus_wmi_backlight_levels,
994
sizeof(acpi_asus_wmi_backlight_levels));
995
996
return (0);
997
}
998
999
static int
1000
acpi_asus_wmi_backlight_get_info(device_t dev, struct backlight_info *info)
1001
{
1002
info->type = BACKLIGHT_TYPE_KEYBOARD;
1003
strlcpy(info->name, "ASUS Keyboard", BACKLIGHTMAXNAMELENGTH);
1004
1005
return (0);
1006
}
1007
1008