From c1cc27a74adfab431ed95c467b02b6c4875726e1 Mon Sep 17 00:00:00 2001 From: gkoehler Date: Fri, 21 Oct 2022 22:42:36 +0000 Subject: [PATCH] hw.power, machdep.lidaction, machdep.pwraction for macppc I can now use the power button to power off my macppcs running OpenBSD. The new sysctls machdep.lidaction and machdep.pwraction act like acpibtn(4), but we are missing code to suspend or hibernate a macppc. Small kernels (bsd.rd) continue to ignore the power button. adb(4) sends an environment interrupt when I unplug my PowerBook's AC or close its lid. Rename PMU_INT_WAKEUP to PMU_INT_ENVIRONMENT like other BSDs and Linux. Handle PMU_ENV_LID_CLOSED as a lid sensor and PMU_ENV_AC_POWER by setting sysctl hw.power. Power buttons can either use PMU_ENV_POWER_BUTTON or go through akbd(4); handle both kinds of power buttons in the same way. Other models of macppc, with different power buttons or lids, might not work yet. The lid sensor looks like, $ sysctl hw.sensors hw.sensors.adb0.indicator0=On (lid open) kettenis@ warned against calling prsignal() from interrupt context, and pointed me to task_add(9). --- sys/arch/macppc/dev/adb.c | 52 ++++++++++++++++++++++++++++- sys/arch/macppc/dev/pm_direct.c | 57 ++++++++++++++++++++++++++++++-- sys/arch/macppc/dev/pm_direct.h | 12 +++++-- sys/arch/macppc/include/cpu.h | 11 ++++-- sys/arch/macppc/macppc/machdep.c | 16 ++++++--- sys/dev/adb/adb.h | 4 ++- sys/dev/adb/akbd.c | 9 ++--- 7 files changed, 144 insertions(+), 17 deletions(-) diff --git a/sys/arch/macppc/dev/adb.c b/sys/arch/macppc/dev/adb.c index 57df0ff4e74..540e0934ced 100644 --- a/sys/arch/macppc/dev/adb.c +++ b/sys/arch/macppc/dev/adb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: adb.c,v 1.46 2022/07/02 08:50:41 visa Exp $ */ +/* $OpenBSD: adb.c,v 1.47 2022/10/21 22:42:36 gkoehler Exp $ */ /* $NetBSD: adb.c,v 1.6 1999/08/16 06:28:09 tsubai Exp $ */ /* $NetBSD: adb_direct.c,v 1.14 2000/06/08 22:10:45 tsubai Exp $ */ @@ -89,6 +89,7 @@ #include #include #include +#include #include #include @@ -242,6 +243,11 @@ int adb_intr(void *arg); void adb_cuda_autopoll(void); void adb_cuda_fileserver_mode(void); +#ifndef SMALL_KERNEL +void adb_shutdown(void *); +struct task adb_shutdown_task = TASK_INITIALIZER(adb_shutdown, NULL); +#endif + #ifdef ADB_DEBUG /* * print_single @@ -831,6 +837,49 @@ adb_soft_intr(void) } } +#ifndef SMALL_KERNEL +void +adb_shutdown(void *arg) +{ + extern int allowpowerdown; + + if (allowpowerdown == 1) { + allowpowerdown = 0; + prsignal(initprocess, SIGUSR2); + } +} +#endif /* !SMALL_KERNEL */ + +void +adb_lid_closed_intr(void) +{ +#ifndef SMALL_KERNEL + switch (lid_action) { + case 1: + /* Suspend. */ + break; + case 2: + /* Hibernate. */ + break; + } +#endif +} + +void +adb_power_button_intr(void) +{ +#ifndef SMALL_KERNEL + switch (pwr_action) { + case 1: + task_add(systq, &adb_shutdown_task); + break; + case 2: + /* Suspend. */ + break; + } +#endif +} + /* * This is my version of the ADBOp routine. It mainly just calls the @@ -1597,6 +1646,7 @@ adbattach(struct device *parent, struct device *self, void *aux) adbHardware = ADB_HW_CUDA; else if (strcmp(ca->ca_name, "via-pmu") == 0) { adbHardware = ADB_HW_PMU; + pm_in_adbattach(sc->sc_dev.dv_xname); /* * Bus reset can take a long time if no adb devices are diff --git a/sys/arch/macppc/dev/pm_direct.c b/sys/arch/macppc/dev/pm_direct.c index a5bf4a1d703..78838fd6a93 100644 --- a/sys/arch/macppc/dev/pm_direct.c +++ b/sys/arch/macppc/dev/pm_direct.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pm_direct.c,v 1.31 2022/09/18 21:36:41 gkoehler Exp $ */ +/* $OpenBSD: pm_direct.c,v 1.32 2022/10/21 22:42:36 gkoehler Exp $ */ /* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai Exp $ */ /* @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -142,6 +143,9 @@ signed char pm_receive_cmd_type[] = { -1, -1, -1, -1, -1, -1, -1, -1, }; +int pm_old_env; +struct ksensor pm_lid_sens; +struct ksensordev pm_sensdev; /* * Define the private functions @@ -161,6 +165,10 @@ int pm_send(u_char); void pm_adb_get_TALK_result(PMData *); void pm_adb_get_ADB_data(PMData *); +void pm_env_intr(PMData *); + + +extern int hw_power; /* * These variables are in adb_direct.c. @@ -413,6 +421,21 @@ pmgrop(PMData *pmdata) return rval; } +void +pm_in_adbattach(const char *devname) +{ + /* A PowerBook (including iBook) has a lid. */ + if (strncmp(hw_prod, "PowerBook", 9) == 0) { + strlcpy(pm_sensdev.xname, devname, + sizeof(pm_sensdev.xname)); + strlcpy(pm_lid_sens.desc, "lid open", + sizeof(pm_lid_sens.desc)); + pm_lid_sens.type = SENSOR_INDICATOR; + sensor_attach(&pm_sensdev, &pm_lid_sens); + sensordev_install(&pm_sensdev); + pm_lid_sens.value = 1; /* This is a guess. */ + } +} /* * My PM interrupt routine for the PB Duo series and the PB 5XX series @@ -456,9 +479,11 @@ pm_intr(void) case 0x16: /* ADB device event */ case 0x18: case 0x1e: - case PMU_INT_WAKEUP: pm_adb_get_ADB_data(&pmdata); break; + case PMU_INT_ENVIRONMENT: + pm_env_intr(&pmdata); + break; default: #ifdef ADB_DEBUG if (adb_debug) @@ -663,6 +688,33 @@ pm_adb_get_ADB_data(PMData *pmdata) adb_pass_up(&packet); } +void +pm_env_intr(PMData *pmdata) +{ + int env, old; + + /* We might have 3 bytes data[3..5], but use only data[3]. */ + if (pmdata->num_data < 3) + return; + env = pmdata->data[3]; + old = pm_old_env; + + pm_lid_sens.value = !(env & PMU_ENV_LID_CLOSED); + if (!(old & PMU_ENV_LID_CLOSED) && (env & PMU_ENV_LID_CLOSED)) + adb_lid_closed_intr(); + + hw_power = !!(env & PMU_ENV_AC_POWER); + + /* + * Act if one presses and releases the power button on a Mac + * with no ADB keyboard. + */ + if ((old & PMU_ENV_POWER_BUTTON) && !(env & PMU_ENV_POWER_BUTTON)) + adb_power_button_intr(); + + pm_old_env = env; +} + void pm_adb_restart(void) { @@ -753,6 +805,7 @@ pm_battery_info(int battery, struct pmu_battery_info *info) pmgrop(&p); info->flags = p.data[1]; + hw_power = !!(info->flags & PMU_PWR_AC_PRESENT); switch (p.data[0]) { case 3: diff --git a/sys/arch/macppc/dev/pm_direct.h b/sys/arch/macppc/dev/pm_direct.h index 64f5a1550bb..6caae0ab599 100644 --- a/sys/arch/macppc/dev/pm_direct.h +++ b/sys/arch/macppc/dev/pm_direct.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pm_direct.h,v 1.14 2022/09/18 21:36:41 gkoehler Exp $ */ +/* $OpenBSD: pm_direct.h,v 1.15 2022/10/21 22:42:36 gkoehler Exp $ */ /* $NetBSD: pm_direct.h,v 1.7 2005/01/07 04:59:58 briggs Exp $ */ /* @@ -49,6 +49,7 @@ typedef struct { } PMData; int pmgrop(PMData *); +void pm_in_adbattach(const char *); int pm_adb_op(u_char *, void *, void *, int); void pm_adb_restart(void); void pm_adb_poweroff(void); @@ -104,7 +105,7 @@ void pmu_fileserver_mode(int); #define PMU_INT_SNDBRT 0x08 /* sound/brightness up/down buttons */ #define PMU_INT_ADB 0x10 /* ADB autopoll or reply data */ #define PMU_INT_BATTERY 0x20 -#define PMU_INT_WAKEUP 0x40 +#define PMU_INT_ENVIRONMENT 0x40 #define PMU_INT_TICK 0x80 /* 1-second tick interrupt */ #define PMU_INT_ALL 0xff /* Mask of all interrupts */ @@ -120,6 +121,13 @@ void pmu_fileserver_mode(int); #define PMU_POW_IRLED 0x04 /* IR led power (on wallstreet) */ #define PMU_POW_MEDIABAY 0x08 /* media bay power (wallstreet/lombard ?) */ +/* Bits from PMU_INT_ENVIRONMENT */ +#define PMU_ENV_LID_CLOSED 0x01 /* The lid is closed */ +#define PMU_ENV_AC_POWER 0x04 /* AC is plugged in */ +#define PMU_ENV_POWER_BUTTON 0x08 /* power button on ADB-less Macs */ +#define PMU_ENV_BATTERY 0x10 +#define PMU_ENV_OVER_TEMP 0x20 + /* PMU PMU_POWER_EVENTS commands */ enum { PMU_PWR_GET_POWERUP_EVENTS = 0x00, diff --git a/sys/arch/macppc/include/cpu.h b/sys/arch/macppc/include/cpu.h index 3e64b2bcccf..383859e1a9e 100644 --- a/sys/arch/macppc/include/cpu.h +++ b/sys/arch/macppc/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.14 2013/10/09 17:43:50 mpi Exp $ */ +/* $OpenBSD: cpu.h,v 1.15 2022/10/21 22:42:36 gkoehler Exp $ */ /* $NetBSD: cpu.h,v 1.1 1996/09/30 16:34:21 ws Exp $ */ /* @@ -39,12 +39,16 @@ */ #define CPU_ALLOWAPERTURE 1 /* allow mmap of /dev/xf86 */ #define CPU_ALTIVEC 2 /* altivec is present */ -#define CPU_MAXID 3 /* number of valid machdep ids */ +#define CPU_LIDACTION 3 /* action caused by lid close */ +#define CPU_PWRACTION 4 /* action caused by power button */ +#define CPU_MAXID 5 /* number of valid machdep ids */ #define CTL_MACHDEP_NAMES { \ { 0, 0 }, \ { "allowaperture", CTLTYPE_INT }, \ { "altivec", CTLTYPE_INT }, \ + { "lidaction", CTLTYPE_INT }, \ + { "pwraction", CTLTYPE_INT }, \ } #ifdef _KERNEL @@ -65,5 +69,8 @@ extern void (*ppc64_slew_voltage)(u_int); extern u_int32_t ticks_per_sec; extern u_int32_t ns_per_tick; +extern int lid_action; +extern int pwr_action; + #endif /* _KERNEL */ #endif /* _MACHINE_CPU_H_ */ diff --git a/sys/arch/macppc/macppc/machdep.c b/sys/arch/macppc/macppc/machdep.c index 9d1aef2c364..c6f09bb9b9c 100644 --- a/sys/arch/macppc/macppc/machdep.c +++ b/sys/arch/macppc/macppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.197 2022/10/21 21:26:49 gkoehler Exp $ */ +/* $OpenBSD: machdep.c,v 1.198 2022/10/21 22:42:36 gkoehler Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -117,6 +117,8 @@ void * startsym, *endsym; #ifdef APERTURE int allowaperture = 0; #endif +int lid_action = 1; +int pwr_action = 1; void dumpsys(void); int lcsplx(int ipl); /* called from LCore */ @@ -533,9 +535,14 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) return EJUSTRETURN; } +const struct sysctl_bounded_args cpuctl_vars[] = { + { CPU_ALTIVEC, &ppc_altivec, SYSCTL_INT_READONLY }, + { CPU_LIDACTION, &lid_action, 0, 2 }, + { CPU_PWRACTION, &pwr_action, 0, 2 }, +}; + /* * Machine dependent system variables. - * None for now. */ int cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, @@ -556,10 +563,9 @@ cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, #else return (sysctl_rdint(oldp, oldlenp, newp, 0)); #endif - case CPU_ALTIVEC: - return (sysctl_rdint(oldp, oldlenp, newp, ppc_altivec)); default: - return EOPNOTSUPP; + return (sysctl_bounded_arr(cpuctl_vars, nitems(cpuctl_vars), + name, namelen, oldp, oldlenp, newp, newlen)); } } diff --git a/sys/dev/adb/adb.h b/sys/dev/adb/adb.h index 35d0fb0db56..f05eb1eab8a 100644 --- a/sys/dev/adb/adb.h +++ b/sys/dev/adb/adb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: adb.h,v 1.5 2011/06/16 10:44:33 mpi Exp $ */ +/* $OpenBSD: adb.h,v 1.6 2022/10/21 22:42:36 gkoehler Exp $ */ /* $NetBSD: adbsys.h,v 1.4 2000/12/19 02:59:24 tsubai Exp $ */ /*- @@ -139,6 +139,8 @@ typedef struct { } ADBDataBlock; int adbprint(void *, const char *); +void adb_lid_closed_intr(void); +void adb_power_button_intr(void); int adb_op_sync(Ptr, short); int set_adb_info(ADBSetInfoBlock *, int); diff --git a/sys/dev/adb/akbd.c b/sys/dev/adb/akbd.c index 801f5b7f09a..e2d89cad418 100644 --- a/sys/dev/adb/akbd.c +++ b/sys/dev/adb/akbd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: akbd.c,v 1.15 2022/04/06 18:59:27 naddy Exp $ */ +/* $OpenBSD: akbd.c,v 1.16 2022/10/21 22:42:36 gkoehler Exp $ */ /* $NetBSD: akbd.c,v 1.17 2005/01/15 16:00:59 chs Exp $ */ /* @@ -467,13 +467,14 @@ akbd_processevent(struct akbd_softc *sc, adb_event_t *event) case 2: /* * The reset (or power) key sends 0x7f7f on press and - * 0xffff on release, and we ignore it. + * 0xffff on release. */ if (event->bytes[0] == event->bytes[1] && ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET) { - if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET)) + if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET)) { SET(sc->sc_caps, CL_DOWN_RESET); - else { + adb_power_button_intr(); + } else { if (ISSET(sc->sc_caps, CL_DOWN_RESET)) CLR(sc->sc_caps, CL_DOWN_RESET); else if (ISSET(sc->sc_caps, CL_DOWN_ADB)) { -- 2.20.1