Skip to content

Commit d5bf6a7

Browse files
committed
acpi_asus_wmi(4): Add support for WMI event queue
Event codes are expected to be retrieved from a queue on at least some models. Specifically, very likely the ACPI WMI devices with _UID ATK are queued whereas those with ASUSWMI are not. Sponsored by: Future Crew LLC MFC after: 1 month Reviewed by: mav Differential Revision: https://reviews.freebsd.org/D48984
1 parent f134662 commit d5bf6a7

File tree

1 file changed

+76
-13
lines changed

1 file changed

+76
-13
lines changed

sys/dev/acpi_support/acpi_asus_wmi.c

+76-13
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ ACPI_MODULE_NAME("ASUS-WMI")
112112
#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
113113
#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
114114

115+
/* Events */
116+
#define ASUS_WMI_EVENT_QUEUE_SIZE 0x10
117+
#define ASUS_WMI_EVENT_QUEUE_END 0x1
118+
#define ASUS_WMI_EVENT_MASK 0xFFFF
119+
#define ASUS_WMI_EVENT_VALUE_ATK 0xFF
120+
115121
struct acpi_asus_wmi_softc {
116122
device_t dev;
117123
device_t wmi_dev;
@@ -120,6 +126,7 @@ struct acpi_asus_wmi_softc {
120126
struct sysctl_oid *sysctl_tree;
121127
int dsts_id;
122128
int handle_keys;
129+
bool event_queue;
123130
struct cdev *kbd_bkl;
124131
uint32_t kbd_bkl_level;
125132
#ifdef EVDEV_SUPPORT
@@ -363,6 +370,8 @@ static int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
363370
UINT32 dev_id, UINT32 *retval);
364371
static int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
365372
UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
373+
static int acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify,
374+
int *code);
366375
static void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
367376
static int acpi_asus_wmi_backlight_update_status(device_t dev,
368377
struct backlight_props *props);
@@ -463,7 +472,7 @@ acpi_asus_wmi_attach(device_t dev)
463472
{
464473
struct acpi_asus_wmi_softc *sc;
465474
UINT32 val;
466-
int dev_id, i;
475+
int dev_id, i, code;
467476
bool have_kbd_bkl = false;
468477

469478
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
@@ -577,6 +586,23 @@ acpi_asus_wmi_attach(device_t dev)
577586
}
578587
ACPI_SERIAL_END(asus_wmi);
579588

589+
/* Detect and flush event queue */
590+
if (sc->dsts_id == ASUS_WMI_METHODID_DSTS2) {
591+
for (i = 0; i <= ASUS_WMI_EVENT_QUEUE_SIZE; i++) {
592+
if (acpi_asus_wmi_get_event_code(sc->wmi_dev,
593+
ASUS_WMI_EVENT_VALUE_ATK, &code) != 0) {
594+
device_printf(dev,
595+
"Can not flush event queue\n");
596+
break;
597+
}
598+
if (code == ASUS_WMI_EVENT_QUEUE_END ||
599+
code == ASUS_WMI_EVENT_MASK) {
600+
sc->event_queue = true;
601+
break;
602+
}
603+
}
604+
}
605+
580606
#ifdef EVDEV_SUPPORT
581607
if (sc->notify_guid != NULL) {
582608
sc->evdev = evdev_alloc();
@@ -746,6 +772,24 @@ acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
746772
}
747773
}
748774

775+
static int
776+
acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify, int *code)
777+
{
778+
ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
779+
ACPI_OBJECT *obj;
780+
int error = 0;
781+
782+
if (ACPI_FAILURE(ACPI_WMI_GET_EVENT_DATA(wmi_dev, notify, &response)))
783+
return (EIO);
784+
obj = (ACPI_OBJECT*) response.Pointer;
785+
if (obj && obj->Type == ACPI_TYPE_INTEGER)
786+
*code = obj->Integer.Value & ASUS_WMI_EVENT_MASK;
787+
else
788+
error = EINVAL;
789+
acpi_asus_wmi_free_buffer(&response);
790+
return (error);
791+
}
792+
749793
#ifdef EVDEV_SUPPORT
750794
static void
751795
acpi_asus_wmi_push_evdev_event(struct evdev_dev *evdev, UINT32 notify)
@@ -768,20 +812,11 @@ acpi_asus_wmi_push_evdev_event(struct evdev_dev *evdev, UINT32 notify)
768812
#endif
769813

770814
static void
771-
acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
815+
acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc *sc, int code)
772816
{
773-
device_t dev = context;
774-
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
775817
UINT32 val;
776-
int code = 0;
777818

778-
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
779-
ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
780-
ACPI_OBJECT *obj;
781-
ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response);
782-
obj = (ACPI_OBJECT*) response.Pointer;
783-
if (obj && obj->Type == ACPI_TYPE_INTEGER) {
784-
code = obj->Integer.Value;
819+
if (code != 0) {
785820
acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
786821
code);
787822
#ifdef EVDEV_SUPPORT
@@ -814,7 +849,35 @@ acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
814849
ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
815850
}
816851
}
817-
acpi_asus_wmi_free_buffer(&response);
852+
}
853+
854+
static void
855+
acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
856+
{
857+
device_t dev = context;
858+
struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
859+
int code = 0, i = 1;
860+
861+
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
862+
863+
if (sc->event_queue)
864+
i += ASUS_WMI_EVENT_QUEUE_SIZE;
865+
do {
866+
if (acpi_asus_wmi_get_event_code(sc->wmi_dev, notify, &code)
867+
!= 0) {
868+
device_printf(dev, "Failed to get event code\n");
869+
return;
870+
}
871+
if (code == ASUS_WMI_EVENT_QUEUE_END ||
872+
code == ASUS_WMI_EVENT_MASK)
873+
return;
874+
acpi_asus_wmi_handle_event(sc, code);
875+
if (notify != ASUS_WMI_EVENT_VALUE_ATK)
876+
return;
877+
} while (--i != 0);
878+
if (sc->event_queue)
879+
device_printf(dev, "Can not read event queue, "
880+
"last code: 0x%x\n", code);
818881
}
819882

820883
static int

0 commit comments

Comments
 (0)