A driver for tablet hardware buttons which seems to be a 
standardized interface.  Used on the Surface Go.

When pressing the power button, the driver receives a button down 
and then a button up event, unlike acpibtn.  Since there may be an 
opportunity to do something different based on the duration of the 
button press, it takes over shutdown/suspend from acpibtn(4).


diff --git share/man/man4/Makefile share/man/man4/Makefile
index 2d9a57d3814..258399f2e7a 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/acpihid.4 share/man/man4/acpihid.4
new file mode 100644
index 00000000000..8d54da962d1
--- /dev/null
+++ share/man/man4/acpihid.4
@@ -0,0 +1,47 @@
+.\"    $OpenBSD$
+.\"
+.\" Copyright (c) 2020 joshua stein <j...@openbsd.org>
+.\"
+.\" 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 driver
+.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.
+Power button events are processed according to the
+.Va machdep.pwraction
+sysctl value.
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr acpibtn 4 ,
+.Xr sysctl 8
+.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 j...@jcs.org .
diff --git sys/arch/amd64/conf/GENERIC sys/arch/amd64/conf/GENERIC
index 87893bfafea..b77a3b4ead5 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/acpi.c sys/dev/acpi/acpi.c
index 7c103347980..306419761c7 100644
--- sys/dev/acpi/acpi.c
+++ sys/dev/acpi/acpi.c
@@ -72,6 +72,7 @@ int   acpi_debug = 16;
 int    acpi_poll_enabled;
 int    acpi_hasprocfvs;
 int    acpi_haspci;
+int    acpi_hashidpower;
 
 #define ACPIEN_RETRIES 15
 
@@ -2025,6 +2026,9 @@ acpi_pbtn_task(void *arg0, int dummy)
            en | ACPI_PM1_PWRBTN_EN);
        splx(s);
 
+       if (acpi_hashidpower)
+               return;
+
        switch (pwr_action) {
        case 0:
                break;
diff --git sys/dev/acpi/acpibtn.c sys/dev/acpi/acpibtn.c
index da3b59ef084..e0b759121ee 100644
--- sys/dev/acpi/acpibtn.c
+++ sys/dev/acpi/acpibtn.c
@@ -270,6 +270,9 @@ sleep:
 #endif /* SMALL_KERNEL */
                break;
        case ACPIBTN_POWER:
+               if (acpi_hashidpower)
+                       break;
+
                if (notify_type == 0x80) {
                        switch (pwr_action) {
                        case 0:
diff --git sys/dev/acpi/acpihid.c sys/dev/acpi/acpihid.c
new file mode 100644
index 00000000000..5ec875a86e8
--- /dev/null
+++ sys/dev/acpi/acpihid.c
@@ -0,0 +1,254 @@
+/* $OpenBSD$ */
+/*
+ * ACPI HID event and 5-button array driver
+ *
+ * Copyright (c) 2018 joshua stein <j...@jcs.org>
+ *
+ * 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 */
+
+#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;
+};
+
+int    acpihid_match(struct device *, void *, void *);
+void   acpihid_attach(struct device *, struct device *, void *);
+int    acpihid_button_array_enable(struct acpihid_softc *, int);
+int    acpihid_eval(struct acpihid_softc *, char *, uint64_t *);
+int    acpihid_exec(struct acpihid_softc *, char *, uint64_t);
+int    acpihid_notify(struct aml_node *, int, void *);
+
+#if NAUDIO > 0 && NWSKBD > 0
+extern int wskbd_set_mixervolume(long, long);
+#endif
+
+extern int acpi_hashidpower;
+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
+};
+
+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, ret;
+
+       sc->sc_acpi = (struct acpi_softc *)parent;
+       sc->sc_devnode = aa->aaa_node;
+
+       printf(": %s", sc->sc_devnode->name);
+
+       if (acpihid_eval(sc, "HDMM", &val) != 0) {
+               printf(", failed reading mode\n");
+               return;
+       } else if (val != 0) {
+               printf(", unknown mode %lld\n", val);
+               return;
+       }
+
+       if (acpihid_eval(sc, "HEBC", &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_exec(sc, "HDSM", 1);
+
+       if (sc->sc_5_button) {
+               acpihid_button_array_enable(sc, 1);
+
+               if (acpihid_eval(sc, "BTNL", &ret) == 0) {
+                       printf(", 5 button array");
+                       acpi_hashidpower = 1;
+               } else
+                       printf(", failed enabling HID power button");
+       }
+
+       printf("\n");
+}
+
+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_exec(sc, "BTNE", enable ? cap : 1) != 0) {
+               printf("%s: failed enabling button array\n",
+                   sc->sc_dev.dv_xname);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+acpihid_eval(struct acpihid_softc *sc, char *method, uint64_t *ret)
+{
+       if (aml_evalinteger(acpi_softc, sc->sc_devnode, method, 0, NULL,
+           ret) != 0) {
+               printf("%s: eval of %s failed\n", sc->sc_dev.dv_xname, method);
+               return 1;
+       }
+
+       DPRINTF(("%s: %s = %lld\n", sc->sc_dev.dv_xname, method, *ret));
+
+       return 0;
+}
+
+int
+acpihid_exec(struct acpihid_softc *sc, char *method, uint64_t val)
+{
+       struct aml_node *parent;
+       struct aml_value amlval;
+
+       memset(&amlval, 0, sizeof(amlval));
+       amlval.type = AML_OBJTYPE_INTEGER;
+       amlval.v_integer = val;
+
+       parent = aml_searchname(sc->sc_devnode, method);
+       if (aml_evalnode(acpi_softc, parent, 1, &amlval, NULL) != 0) {
+               printf("%s: exec of %s failed\n", sc->sc_dev.dv_xname, method);
+               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
+       printf("%s: %s: %.2x\n", sc->sc_dev.dv_xname, __func__, notify_type);
+
+       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 */
+               /*
+                * TODO: time press and release, maybe sleep for a short press
+                * and power down for long press, disregarding pwr_action?
+                */
+               switch (pwr_action) {
+               case 0:
+                       break;
+               case 1:
+                       acpi_addtask(sc->sc_acpi, acpi_powerdown_task,
+                           sc->sc_acpi, 0);
+                       break;
+               case 2:
+                       if (acpi_record_event(sc->sc_acpi, 
APM_USER_SUSPEND_REQ))
+                               acpi_addtask(sc->sc_acpi, acpi_sleep_task,
+                                   sc->sc_acpi, ACPI_SLEEP_SUSPEND);
+                       break;
+               }
+               break;
+       default:
+               printf("%s: unhandled button 0x%x\n", sc->sc_dev.dv_xname,
+                   notify_type);
+       }
+
+       return 0;
+}
diff --git sys/dev/acpi/acpivar.h sys/dev/acpi/acpivar.h
index 159b8e7b948..da8a8b128ca 100644
--- sys/dev/acpi/acpivar.h
+++ sys/dev/acpi/acpivar.h
@@ -44,6 +44,7 @@ extern int acpi_debug;
 
 extern int acpi_hasprocfvs;
 extern int acpi_haspci;
+extern int acpi_hashidpower;
 
 struct klist;
 struct acpiec_softc;
diff --git sys/dev/acpi/files.acpi sys/dev/acpi/files.acpi
index 496d7ef1ed1..93e0d21f921 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
+
+# HID event and 5-button array
+device acpihid
+attach acpihid at acpi
+file   dev/acpi/acpihid.c              acpihid

Reply via email to