Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/acpi/wmi Fix dell WMI mappings:
details: https://anonhg.NetBSD.org/src/rev/663e45a99ecd
branches: trunk
changeset: 357929:663e45a99ecd
user: bouyer <bouyer%NetBSD.org@localhost>
date: Sun Dec 03 17:40:48 2017 +0000
description:
Fix dell WMI mappings:
- query the descriptor to get the interface version, needed to workaround
a bug in the BIOS/ACPI
- properly decode the event buffer in type/subtype, and handle multiple events
per handler call
- record some known type/subtype in a table, with associated actions.
Informations mostly from linux. Tested on a Dell 5480 laptop.
diffstat:
sys/dev/acpi/wmi/wmi_dell.c | 196 +++++++++++++++++++++++++++++++++----------
1 files changed, 149 insertions(+), 47 deletions(-)
diffs (272 lines):
diff -r e2a40c7b3363 -r 663e45a99ecd sys/dev/acpi/wmi/wmi_dell.c
--- a/sys/dev/acpi/wmi/wmi_dell.c Sun Dec 03 17:34:50 2017 +0000
+++ b/sys/dev/acpi/wmi/wmi_dell.c Sun Dec 03 17:40:48 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wmi_dell.c,v 1.9 2015/04/23 23:23:00 pgoyette Exp $ */
+/* $NetBSD: wmi_dell.c,v 1.10 2017/12/03 17:40:48 bouyer Exp $ */
/*-
* Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wmi_dell.c,v 1.9 2015/04/23 23:23:00 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wmi_dell.c,v 1.10 2017/12/03 17:40:48 bouyer Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -43,29 +43,69 @@
#include <dev/sysmon/sysmonvar.h>
+#ifdef WMI_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
#define _COMPONENT ACPI_RESOURCE_COMPONENT
ACPI_MODULE_NAME ("wmi_dell")
-#define WMI_DELL_HOTKEY_BRIGHTNESS_DOWN 0xE005
-#define WMI_DELL_HOTKEY_BRIGHTNESS_UP 0xE006
-#define WMI_DELL_HOTKEY_DISPLAY_CYCLE 0xE00B
-#define WMI_DELL_HOTKEY_VOLUME_MUTE 0xE020
-#define WMI_DELL_HOTKEY_VOLUME_DOWN 0xE02E
-#define WMI_DELL_HOTKEY_VOLUME_UP 0xE030
-/* WMI_DELL_HOTKEY_UNKNOWN 0xXXXX */
-
#define WMI_DELL_PSW_DISPLAY_CYCLE 0
#define WMI_DELL_PSW_COUNT 1
#define WMI_DELL_GUID_EVENT "9DBB5994-A997-11DA-B012-B622A1EF5492"
+#define WMI_DELL_GUID_DESC "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
struct wmi_dell_softc {
device_t sc_dev;
device_t sc_parent;
+ int sc_version;
struct sysmon_pswitch sc_smpsw[WMI_DELL_PSW_COUNT];
bool sc_smpsw_valid;
};
+#define WMI_DELLA_PMF 0x0
+#define WMI_DELLA_PSW 0x1
+#define WMI_DELLA_IGN 0x2
+
+const struct wmi_dell_actions {
+ u_int wda_action;
+ u_int wda_type;
+ u_int wda_subtype;
+ u_int wda_data;
+} wmi_dell_actions[] = {
+ /* type 0 */
+ /* brightness control */
+ {WMI_DELLA_PMF, 0x0000, 0xe005, PMFE_DISPLAY_BRIGHTNESS_DOWN},
+ {WMI_DELLA_PMF, 0x0000, 0xe006, PMFE_DISPLAY_BRIGHTNESS_UP},
+ {WMI_DELLA_PSW, 0x0000, 0xe00b, WMI_DELL_PSW_DISPLAY_CYCLE},
+
+ {WMI_DELLA_PMF, 0x0000, 0xe008, PMFE_RADIO_TOGGLE},
+ {WMI_DELLA_IGN, 0x0000, 0xe00c, 0}, /* keyboard illumination */
+
+ /* volume control */
+ {WMI_DELLA_PMF, 0x0000, 0xe020, PMFE_AUDIO_VOLUME_TOGGLE},
+ {WMI_DELLA_PMF, 0x0000, 0xe02e, PMFE_AUDIO_VOLUME_DOWN},
+ {WMI_DELLA_PMF, 0x0000, 0xe030, PMFE_AUDIO_VOLUME_UP},
+ {WMI_DELLA_PMF, 0x0000, 0xe0f8, PMFE_AUDIO_VOLUME_DOWN},
+ {WMI_DELLA_PMF, 0x0000, 0xe0f9, PMFE_AUDIO_VOLUME_UP},
+
+
+ /* type 0x10 */
+ {WMI_DELLA_PMF, 0x0010, 0x0057, PMFE_DISPLAY_BRIGHTNESS_DOWN},
+ {WMI_DELLA_PMF, 0x0010, 0x0058, PMFE_DISPLAY_BRIGHTNESS_UP},
+ {WMI_DELLA_IGN, 0x0010, 0x0151, 0}, /* Fn-lock */
+ {WMI_DELLA_IGN, 0x0010, 0x0152, 0}, /* keyboard illumination */
+ {WMI_DELLA_PMF, 0x0010, 0x0153, PMFE_RADIO_TOGGLE},
+ {WMI_DELLA_IGN, 0x0010, 0x0155, 0}, /* Stealth mode toggle */
+ {WMI_DELLA_IGN, 0x0010, 0xE035, 0}, /* Fn-lock */
+
+ /* type 0x11 */
+ {WMI_DELLA_IGN, 0x0011, 0x02eb5, 0}, /* keyboard illumination */
+};
+
static int wmi_dell_match(device_t, cfdata_t, void *);
static void wmi_dell_attach(device_t, device_t, void *);
static int wmi_dell_detach(device_t, int);
@@ -87,6 +127,9 @@
{
struct wmi_dell_softc *sc = device_private(self);
ACPI_STATUS rv;
+ ACPI_BUFFER obuf;
+ ACPI_OBJECT *obj;
+ uint32_t *data;
int e;
sc->sc_dev = self;
@@ -100,8 +143,34 @@
return;
}
+ memset(&obuf, 0, sizeof(obuf));
+ rv = acpi_wmi_data_query(parent, WMI_DELL_GUID_DESC, 0, &obuf);
+ if (ACPI_FAILURE(rv)) {
+ aprint_error(": failed to query WMI descriptor: %s\n",
+ AcpiFormatException(rv));
+ return;
+ }
+ obj = obuf.Pointer;
+ if (obj->Type != ACPI_TYPE_BUFFER) {
+ aprint_error(": wrong type %d for WMI descriptor\n", obj->Type);
+ return;
+ }
+ if (obj->Buffer.Length != 128) {
+ aprint_error(": wrong len %d for WMI descriptor",
+ obj->Buffer.Length);
+ if (obj->Buffer.Length < 16) {
+ aprint_error("\n");
+ return;
+ }
+ }
+ data = (uint32_t *)obj->Buffer.Pointer;
+ if (data[0] != 0x4C4C4544 || data[1] != 0x494D5720) {
+ aprint_error(": wrong WMI descriptor signature 0x%x 0x%x",
+ data[0], data[1]);
+ }
+ sc->sc_version = data[2];
aprint_naive("\n");
- aprint_normal(": Dell WMI mappings\n");
+ aprint_normal(": Dell WMI mappings version %d\n", sc->sc_version);
sc->sc_smpsw[WMI_DELL_PSW_DISPLAY_CYCLE].smpsw_name =
PSWITCH_HK_DISPLAY_CYCLE;
@@ -159,6 +228,43 @@
}
static void
+wmi_dell_action(struct wmi_dell_softc *sc, uint16_t *data, int len)
+{
+ int i;
+ for (i = 0; i < __arraycount(wmi_dell_actions); i++) {
+ const struct wmi_dell_actions *wda = &wmi_dell_actions[i];
+ if (wda->wda_type == data[0] &&
+ wda->wda_subtype == data[1]) {
+ switch(wda->wda_action) {
+ case WMI_DELLA_IGN:
+ DPRINTF((" ignored"));
+ return;
+ case WMI_DELLA_PMF:
+ DPRINTF((" pmf %d",
+ wda->wda_data));
+ pmf_event_inject(NULL,
+ wda->wda_data);
+ return;
+ case WMI_DELLA_PSW:
+ DPRINTF((" psw %d",
+ wda->wda_data));
+ sysmon_pswitch_event(
+ &sc->sc_smpsw[wda->wda_data],
+ PSWITCH_EVENT_PRESSED);
+ return;
+ default:
+ printf("unknown dell wmi action %d\n",
+ wda->wda_action);
+ return;
+ }
+
+ }
+ }
+ aprint_debug_dev(sc->sc_dev, "unkown event 0x%4X 0x%4X\n",
+ data[0], data[1]);
+}
+
+static void
wmi_dell_notify_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux)
{
struct wmi_dell_softc *sc;
@@ -166,7 +272,8 @@
ACPI_OBJECT *obj;
ACPI_BUFFER buf;
ACPI_STATUS rv;
- uint32_t val;
+ uint16_t *data, *end;
+ int i, len;
buf.Pointer = NULL;
@@ -183,45 +290,40 @@
goto out;
}
- val = obj->Buffer.Pointer[1] & 0xFFFF;
-
- switch (val) {
-
- case WMI_DELL_HOTKEY_BRIGHTNESS_DOWN:
- pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN);
- break;
+ data = (void *)(&obj->Buffer.Pointer[0]);
+ end = (void *)(&obj->Buffer.Pointer[obj->Buffer.Length]);
- case WMI_DELL_HOTKEY_BRIGHTNESS_UP:
- pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP);
- break;
+ DPRINTF(("wmi_dell_notify_handler buffer len %d\n",
+ obj->Buffer.Length));
+ while (data < end) {
+ DPRINTF(("wmi_dell_notify_handler len %d", data[0]));
+ if (data[0] == 0) {
+ DPRINTF(("\n"));
+ break;
+ }
+ len = data[0] + 1;
- case WMI_DELL_HOTKEY_DISPLAY_CYCLE:
-
- if (sc->sc_smpsw_valid != true) {
- rv = AE_ABORT_METHOD;
+ if (&data[len] >= end) {
+ DPRINTF(("\n"));
break;
}
-
- sysmon_pswitch_event(&sc->sc_smpsw[WMI_DELL_PSW_DISPLAY_CYCLE],
- PSWITCH_EVENT_PRESSED);
- break;
-
- case WMI_DELL_HOTKEY_VOLUME_MUTE:
- pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE);
- break;
-
- case WMI_DELL_HOTKEY_VOLUME_DOWN:
- pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN);
- break;
-
- case WMI_DELL_HOTKEY_VOLUME_UP:
- pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP);
- break;
-
- default:
- aprint_debug_dev(sc->sc_dev,
- "unknown key 0x%02X for event 0x%02X\n", val, evt);
- break;
+ if (len < 2) {
+ DPRINTF(("\n"));
+ continue;
+ }
+ for (i = 1; i < len; i++)
+ DPRINTF((" 0x%04X", data[i]));
+ wmi_dell_action(sc, &data[1], len - 1);
+ DPRINTF(("\n"));
+ data = &data[len];
+ /*
+ * WMI interface version 0 don't clear the buffer from previous
+ * event, so if the current event is smaller than the previous
+ * one there will be garbage after the current event.
+ * workaround by processing only the first event
+ */
+ if (sc->sc_version == 0)
+ break;
}
out:
Home |
Main Index |
Thread Index |
Old Index