Here is a new revision that tries to call methods through the node's 
_DSM first, as it does on Linux.

It also no longer takes over power button handling as requested by 
Mark.


acpihid.3

diff --git share/man/man4/Makefile share/man/man4/Makefile
index 2cce0a9a132..bb0b6b10068 100644
--- share/man/man4/Makefile
+++ share/man/man4/Makefile
@@ -3,6 +3,7 @@
 MAN=   aac.4 abcrtc.4 ac97.4 acphy.4 acrtc.4 \
        acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \
        acpibtn.4 acpicbkbd.4 acpicpu.4 acpidock.4 acpihve.4 acpiec.4 \
+       acpihid.4 \
        acpihpet.4 acpimadt.4 acpimcfg.4 acpipci.4 acpiprt.4 acpipwrres.4 \
        acpisbs.4 acpisony.4 acpisurface.4 acpithinkpad.4 acpitoshiba.4 \
        acpitimer.4 acpivideo.4 acpivout.4 acpitz.4 \
diff --git share/man/man4/acpi.4 share/man/man4/acpi.4
index 232d1cd6921..1fba9f5a22d 100644
--- share/man/man4/acpi.4
+++ share/man/man4/acpi.4
@@ -56,6 +56,8 @@ ACPI processor power and performance state
 ACPI docking station
 .It Xr acpiec 4
 ACPI embedded controller
+.It Xr acpihid 4
+ACPI HID event and 5-button array
 .It Xr acpihpet 4
 ACPI high precision event timer
 .It Xr acpihve 4
diff --git share/man/man4/acpihid.4 share/man/man4/acpihid.4
new file mode 100644
index 00000000000..d9914cec7b7
--- /dev/null
+++ share/man/man4/acpihid.4
@@ -0,0 +1,42 @@
+.\"    $OpenBSD$
+.\"
+.\" Copyright (c) 2020 joshua stein <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt ACPIHID 4
+.Os
+.Sh NAME
+.Nm acpihid
+.Nd ACPI HID event and 5-button array
+.Sh SYNOPSIS
+.Cd "acpihid* at acpi?"
+.Sh DESCRIPTION
+The
+.Nm
+driver supports ACPI HID events and 5-button array devices found on some
+tablet devices.
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 6.8 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An joshua stein Aq Mt [email protected] .
diff --git sys/arch/amd64/conf/GENERIC sys/arch/amd64/conf/GENERIC
index 9aa0a390690..618f49fadda 100644
--- sys/arch/amd64/conf/GENERIC
+++ sys/arch/amd64/conf/GENERIC
@@ -71,6 +71,7 @@ acpials*      at acpi?
 tpm*           at acpi?
 acpihve*       at acpi?
 acpisurface*   at acpi?
+acpihid*       at acpi?
 ipmi0          at acpi? disable
 ccpmic*                at iic?
 tipmic*                at iic?
diff --git sys/dev/acpi/acpihid.c sys/dev/acpi/acpihid.c
new file mode 100644
index 00000000000..063fee1dc21
--- /dev/null
+++ sys/dev/acpi/acpihid.c
@@ -0,0 +1,401 @@
+/* $OpenBSD$ */
+/*
+ * ACPI HID event and 5-button array driver
+ *
+ * Copyright (c) 2018, 2020 joshua stein <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/signalvar.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/apmvar.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#include "audio.h"
+#include "wskbd.h"
+
+/* #define ACPIHID_DEBUG */
+#define ACPIHID_DEBUG
+
+#ifdef ACPIHID_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+struct acpihid_softc {
+       struct device           sc_dev;
+
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+
+       struct acpi_softc       *sc_acpi;
+       struct aml_node         *sc_devnode;
+       int                     sc_5_button;
+
+       /*
+        * HEBC v1
+        * 0 - Rotation Lock, Num Lock, Home, End, Page Up, Page Down
+        * 1 - Wireless Radio Control
+        * 2 - System Power Down
+        * 3 - System Hibernate
+        * 4 - System Sleep/ System Wake
+        * 5 - Scan Next Track
+        * 6 - Scan Previous Track
+        * 7 - Stop
+        * 8 - Play/Pause
+        * 9 - Mute
+        * 10 - Volume Increment
+        * 11 - Volume Decrement
+        * 12 - Display Brightness Increment
+        * 13 - Display Brightness Decrement
+        * 14 - Lock Tablet
+        * 15 - Release Tablet
+        * 16 - Toggle Bezel
+        * 17 - 5 button array
+        * 18-31 - reserved
+        *
+        * HEBC v2
+        * 0-17 - Same as v1 version
+        * 18 – Power Button
+        * 19 - W Home Button
+        * 20 - Volume Up Button
+        * 21 - Volume Down Button
+        * 22 – Rotation Lock Button
+        * 23-31 – reserved
+        */
+       uint32_t                sc_dsm_fn_mask;
+};
+
+enum {
+       ACPIHID_FUNC_INVALID,
+       ACPIHID_FUNC_BTNL,
+       ACPIHID_FUNC_HDMM,
+       ACPIHID_FUNC_HDSM,
+       ACPIHID_FUNC_HDEM,
+       ACPIHID_FUNC_BTNS,
+       ACPIHID_FUNC_BTNE,
+       ACPIHID_FUNC_HEBC_V1,
+       ACPIHID_FUNC_VGBS,
+       ACPIHID_FUNC_HEBC_V2,
+       ACPIHID_FUNC_MAX,
+};
+
+static const char *acpihid_dsm_funcs[] = {
+       NULL,
+       "BTNL",
+       "HDMM",
+       "HDSM",
+       "HDEM",
+       "BTNS",
+       "BTNE",
+       "HEBC",
+       "VGBS",
+       "HEBC",
+};
+
+int    acpihid_match(struct device *, void *, void *);
+void   acpihid_attach(struct device *, struct device *, void *);
+void   acpihid_init_dsm(struct acpihid_softc *);
+int    acpihid_button_array_enable(struct acpihid_softc *, int);
+int    acpihid_eval(struct acpihid_softc *, int, int64_t, int64_t *);
+int    acpihid_notify(struct aml_node *, int, void *);
+
+#if NAUDIO > 0 && NWSKBD > 0
+extern int wskbd_set_mixervolume(long, long);
+#endif
+
+extern int pwr_action;
+
+struct cfattach acpihid_ca = {
+       sizeof(struct acpihid_softc),
+       acpihid_match,
+       acpihid_attach,
+       NULL,
+       NULL,
+};
+
+struct cfdriver acpihid_cd = {
+       NULL, "acpihid", DV_DULL
+};
+
+const char *acpihid_hids[] = {
+       "INT33D5",
+       NULL
+};
+
+/* eeec56b3-4442-408f-a792-4edd4d758054 */
+static uint8_t acpihid_guid[] = {
+       0xB3, 0x56, 0xEC, 0xEE, 0x42, 0x44, 0x8F, 0x40,
+       0xA7, 0x92, 0x4E, 0xDD, 0x4D, 0x75, 0x80, 0x54,
+};
+
+int
+acpihid_match(struct device *parent, void *match, void *aux)
+{
+       struct acpi_attach_args *aa = aux;
+       struct cfdata           *cf = match;
+
+       return (acpi_matchhids(aa, acpihid_hids, cf->cf_driver->cd_name));
+}
+
+void
+acpihid_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct acpihid_softc    *sc = (struct acpihid_softc *)self;
+       struct acpi_attach_args *aa = aux;
+       uint64_t                 val;
+
+       sc->sc_acpi = (struct acpi_softc *)parent;
+       sc->sc_devnode = aa->aaa_node;
+
+       printf(": %s", sc->sc_devnode->name);
+
+       acpihid_init_dsm(sc);
+
+       if (acpihid_eval(sc, ACPIHID_FUNC_HDMM, 0, &val) != 0) {
+               printf(", failed reading mode\n");
+               return;
+       } else if (val != 0) {
+               printf(", unknown mode %lld\n", val);
+               return;
+       }
+
+       if ((acpihid_eval(sc, ACPIHID_FUNC_HEBC_V2, 0, &val) == 0 &&
+           (val & 0x60000)) ||
+           (acpihid_eval(sc, ACPIHID_FUNC_HEBC_V1, 0, &val) == 0 &&
+           (val & 0x20000)))
+               sc->sc_5_button = 1;
+
+       aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpihid_notify,
+           sc, ACPIDEV_NOPOLL);
+
+       /* enable hid set */
+       acpihid_eval(sc, ACPIHID_FUNC_HDSM, 1, NULL);
+
+       if (sc->sc_5_button) {
+               acpihid_button_array_enable(sc, 1);
+
+               if (acpihid_eval(sc, ACPIHID_FUNC_BTNL, 0, NULL) == 0)
+                       printf(", 5 button array");
+               else
+                       printf(", failed enabling HID power button");
+       }
+
+       printf("\n");
+}
+
+void
+acpihid_init_dsm(struct acpihid_softc *sc)
+{
+       struct aml_value cmd[4], res;
+
+       sc->sc_dsm_fn_mask = 0;
+
+       if (!aml_searchname(sc->sc_devnode, "_DSM")) {
+               DPRINTF(("%s: no _DSM support\n", sc->sc_dev.dv_xname));
+               return;
+       }
+
+       bzero(&cmd, sizeof(cmd));
+       cmd[0].type = AML_OBJTYPE_BUFFER;
+       cmd[0].v_buffer = (uint8_t *)&acpihid_guid;
+       cmd[0].length = sizeof(acpihid_guid);
+       /* rev */
+       cmd[1].type = AML_OBJTYPE_INTEGER;
+       cmd[1].v_integer = 1;
+       cmd[1].length = 1;
+       /* func */
+       cmd[2].type = AML_OBJTYPE_INTEGER;
+       cmd[2].v_integer = 0;
+       cmd[2].length = 1;
+       /* not used */
+       cmd[3].type = AML_OBJTYPE_BUFFER;
+       cmd[3].length = 0;
+
+       if (aml_evalname(acpi_softc, sc->sc_devnode, "_DSM", 4, cmd,
+           &res)) {
+               printf("%s: eval of _DSM at %s failed\n",
+                   sc->sc_dev.dv_xname, aml_nodename(sc->sc_devnode));
+               return;
+       }
+
+       if (res.type != AML_OBJTYPE_BUFFER) {
+               printf("%s: bad _DSM result at %s: %d\n", sc->sc_dev.dv_xname,
+                   aml_nodename(sc->sc_devnode), res.type);
+               aml_freevalue(&res);
+               return;
+       }
+
+       sc->sc_dsm_fn_mask = *res.v_buffer;
+       DPRINTF(("%s: _DSM function mask 0x%x\n", sc->sc_dev.dv_xname,
+           sc->sc_dsm_fn_mask));
+
+       aml_freevalue(&res);
+}
+
+int
+acpihid_eval(struct acpihid_softc *sc, int idx, int64_t arg, int64_t *ret)
+{
+       struct aml_value cmd[4], pkg, *ppkg;
+       int64_t tret;
+       const char *dsm_func;
+
+       if (idx <= ACPIHID_FUNC_INVALID || idx >= ACPIHID_FUNC_MAX) {
+               printf("%s: _DSM func index %d out of bounds\n",
+                   sc->sc_dev.dv_xname, idx);
+               return 1;
+       }
+
+       dsm_func = acpihid_dsm_funcs[idx];
+
+       DPRINTF(("%s: executing _DSM %s\n", sc->sc_dev.dv_xname, dsm_func));
+
+       if (!(sc->sc_dsm_fn_mask & idx)) {
+               DPRINTF(("%s: _DSM mask does not support %s (%d), executing "
+                   "directly\n", sc->sc_dev.dv_xname, dsm_func, idx));
+               goto eval_direct;
+       }
+
+       bzero(&pkg, sizeof(pkg));
+       pkg.type = AML_OBJTYPE_INTEGER;
+       pkg.v_integer = arg;
+       pkg.length = 1;
+       ppkg = &pkg;
+
+       bzero(&cmd, sizeof(cmd));
+       cmd[0].type = AML_OBJTYPE_BUFFER;
+       cmd[0].v_buffer = (uint8_t *)&acpihid_guid;
+       cmd[0].length = sizeof(acpihid_guid);
+       /* rev */
+       cmd[1].type = AML_OBJTYPE_INTEGER;
+       cmd[1].v_integer = 1;
+       cmd[1].length = 1;
+       /* func */
+       cmd[2].type = AML_OBJTYPE_INTEGER;
+       cmd[2].v_integer = idx;
+       cmd[2].length = 1;
+       /* arg */
+       cmd[3].type = AML_OBJTYPE_PACKAGE;
+       cmd[3].length = 1;
+       cmd[3].v_package = &ppkg;
+
+       if (aml_evalinteger(acpi_softc, sc->sc_devnode, "_DSM", 4, cmd,
+           &tret)) {
+               DPRINTF(("%s: _DSM %s failed\n", sc->sc_dev.dv_xname,
+                   dsm_func));
+               return 1;
+       }
+
+       DPRINTF(("%s: _DSM eval of %s succeeded\n", sc->sc_dev.dv_xname,
+           dsm_func));
+
+       if (ret != NULL)
+               *ret = tret;
+
+       return 0;
+
+eval_direct:
+       cmd[0].type = AML_OBJTYPE_INTEGER;
+       cmd[0].v_integer = arg;
+       cmd[0].length = 1;
+
+       if (aml_evalinteger(acpi_softc, sc->sc_devnode, dsm_func, 1, cmd,
+           &tret) != 0) {
+               printf("%s: exec of %s failed\n", sc->sc_dev.dv_xname,
+                   dsm_func);
+               return 1;
+       }
+
+       if (ret != NULL)
+               *ret = tret;
+
+       return 0;
+}
+
+int
+acpihid_button_array_enable(struct acpihid_softc *sc, int enable)
+{
+       int64_t cap;
+
+       if (aml_evalinteger(acpi_softc, sc->sc_devnode, "BTNC", 0, NULL,
+           &cap) != 0) {
+               printf("%s: failed getting button array capability\n",
+                   sc->sc_dev.dv_xname);
+               return 1;
+       }
+
+       if (acpihid_eval(sc, ACPIHID_FUNC_BTNE, enable ? cap : 1, NULL) != 0) {
+               printf("%s: failed enabling button array\n",
+                   sc->sc_dev.dv_xname);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+acpihid_notify(struct aml_node *node, int notify_type, void *arg)
+{
+       struct acpihid_softc *sc = arg;
+
+#ifdef ACPIHID_DEBUG
+       DPRINTF(("%s: %s: %.2x\n", sc->sc_dev.dv_xname, __func__,
+           notify_type));
+#endif
+
+       switch (notify_type) {
+       case 0xc2: /* left meta press */
+               break;
+       case 0xc3: /* left meta release */
+               break;
+       case 0xc4: /* volume up press */
+#if NAUDIO > 0 && NWSKBD > 0
+               wskbd_set_mixervolume(1, 1);
+#endif
+               break;
+       case 0xc5: /* volume up release */
+               break;
+       case 0xc6: /* volume down press */
+#if NAUDIO > 0 && NWSKBD > 0
+               wskbd_set_mixervolume(-1, 1);
+#endif
+               break;
+       case 0xc7: /* volume down release */
+               break;
+       case 0xc8: /* rotate lock toggle press */
+               break;
+       case 0xc9: /* rotate lock toggle release */
+               break;
+       case 0xce: /* power button press */
+               break;
+       case 0xcf: /* power button release */
+               break;
+       default:
+               printf("%s: unhandled button 0x%x\n", sc->sc_dev.dv_xname,
+                   notify_type);
+       }
+
+       return 0;
+}
diff --git sys/dev/acpi/files.acpi sys/dev/acpi/files.acpi
index 496d7ef1ed1..2c363be78cf 100644
--- sys/dev/acpi/files.acpi
+++ sys/dev/acpi/files.acpi
@@ -216,3 +216,8 @@ file        dev/acpi/amdgpio.c              amdgpio
 # Broadcom BC7XXX Ethernet controller
 attach bse at acpi with bse_acpi
 file   dev/acpi/if_bse_acpi.c          bse_acpi
+
+# Intel HID event and 5-button array
+device acpihid
+attach acpihid at acpi
+file   dev/acpi/acpihid.c              acpihid

Reply via email to