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