From: kettenis Date: Sat, 27 Aug 2022 16:56:25 +0000 (+0000) Subject: Add power button support. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=dc827a2681fbba1fb8c0fc3b4d126782d171e0e5;p=openbsd Add power button support. ok tobhe@ --- diff --git a/sys/arch/arm64/dev/aplsmc.c b/sys/arch/arm64/dev/aplsmc.c index 43ee3bc80ca..578711b899e 100644 --- a/sys/arch/arm64/dev/aplsmc.c +++ b/sys/arch/arm64/dev/aplsmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplsmc.c,v 1.12 2022/06/12 16:00:12 kettenis Exp $ */ +/* $OpenBSD: aplsmc.c,v 1.13 2022/08/27 16:56:25 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include @@ -42,12 +44,14 @@ extern void (*powerdownfn)(void); #define SMC_EP 32 /* SMC commands */ +#define SMC_CMD(d) ((d) & 0xff) #define SMC_READ_KEY 0x10 #define SMC_WRITE_KEY 0x11 #define SMC_GET_KEY_BY_INDEX 0x12 #define SMC_GET_KEY_INFO 0x13 #define SMC_GET_SRAM_ADDR 0x17 #define SMC_SRAM_SIZE 0x4000 +#define SMC_NOTIFICATION 0x18 /* SMC errors */ #define SMC_ERROR(d) ((d) & 0xff) @@ -79,6 +83,18 @@ struct aplsmc_sensor { int flags; }; +/* SMC events */ +#define SMC_EV_TYPE(d) (((d) >> 48) & 0xffff) +#define SMC_EV_TYPE_BTN 0x7201 +#define SMC_EV_TYPE_LID 0x7203 +#define SMC_EV_SUBTYPE(d) (((d) >> 40) & 0xff) +#define SMC_EV_DATA(d) (((d) >> 32) & 0xff) + +/* Button events */ +#define SMC_PWRBTN_OFF 0x00 +#define SMC_PWRBTN_SHORT 0x06 +#define SMC_PWRBTN_LONG 0xfe + #define APLSMC_BE (1 << 0) #define APLSMC_HIDDEN (1 << 1) @@ -154,6 +170,7 @@ void aplsmc_callback(void *, uint64_t); int aplsmc_send_cmd(struct aplsmc_softc *, uint16_t, uint32_t, uint16_t); int aplsmc_wait_cmd(struct aplsmc_softc *sc); int aplsmc_read_key(struct aplsmc_softc *, uint32_t, void *, size_t); +int aplsmc_write_key(struct aplsmc_softc *, uint32_t, void *, size_t); void aplsmc_refresh_sensors(void *); int aplsmc_apminfo(struct apm_power_info *); void aplsmc_set_pin(void *, uint32_t *, int); @@ -177,6 +194,7 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux) struct aplsmc_softc *sc = (struct aplsmc_softc *)self; struct fdt_attach_args *faa = aux; uint8_t data[SMC_CLKM_LEN]; + uint8_t ntap; int error, node; #ifndef SMALL_KERNEL int i; @@ -259,6 +277,10 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux) config_mountroot(self, aplsmc_reboot_attachhook); } + /* Enable notifications. */ + ntap = 1; + aplsmc_write_key(sc, SMC_KEY("NTAP"), &ntap, sizeof(ntap)); + #ifndef SMALL_KERNEL for (i = 0; i < nitems(aplsmc_sensors); i++) { @@ -309,11 +331,53 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux) #endif } +void +aplsmc_handle_notification(struct aplsmc_softc *sc, uint64_t data) +{ + extern int allowpowerdown; + + switch (SMC_EV_TYPE(data)) { + case SMC_EV_TYPE_BTN: + switch (SMC_EV_SUBTYPE(data)) { + case SMC_PWRBTN_SHORT: + if (SMC_EV_DATA(data) == 1 && allowpowerdown) { + allowpowerdown = 0; + prsignal(initprocess, SIGUSR2); + } + break; + case SMC_PWRBTN_LONG: + break; + case SMC_PWRBTN_OFF: + /* XXX Do emergency shutdown? */ + break; + default: + printf("%s: SMV_EV_TYPE_BTN 0x%016llx\n", + sc->sc_dev.dv_xname, data); + break; + } + break; + case SMC_EV_TYPE_LID: + /* XXX Handle lid events. */ + break; + default: +#ifdef APLSMC_DEBUG + printf("%s: unhandled event 0x%016llx\n", + sc->sc_dev.dv_xname, data); +#endif + break; + } +} + void aplsmc_callback(void *arg, uint64_t data) { struct aplsmc_softc *sc = arg; + if (SMC_CMD(data) == SMC_NOTIFICATION) { + aplsmc_handle_notification(sc, data); + return; + } + sc->sc_data = data; wakeup(&sc->sc_data); }