hw.power, machdep.lidaction, machdep.pwraction for macppc
authorgkoehler <gkoehler@openbsd.org>
Fri, 21 Oct 2022 22:42:36 +0000 (22:42 +0000)
committergkoehler <gkoehler@openbsd.org>
Fri, 21 Oct 2022 22:42:36 +0000 (22:42 +0000)
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
sys/arch/macppc/dev/pm_direct.c
sys/arch/macppc/dev/pm_direct.h
sys/arch/macppc/include/cpu.h
sys/arch/macppc/macppc/machdep.c
sys/dev/adb/adb.h
sys/dev/adb/akbd.c

index 57df0ff..540e093 100644 (file)
@@ -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 <sys/fcntl.h>
 #include <sys/proc.h>
 #include <sys/signalvar.h>
+#include <sys/task.h>
 #include <sys/timeout.h>
 #include <sys/systm.h>
 
@@ -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
index a5bf4a1..78838fd 100644 (file)
@@ -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 <sys/param.h>
 #include <sys/device.h>
 #include <sys/systm.h>
+#include <sys/sensors.h>
 
 #include <machine/cpu.h>
 
@@ -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:
index 64f5a15..6caae0a 100644 (file)
@@ -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,
index 3e64b2b..383859e 100644 (file)
@@ -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 $       */
 
 /*
  */
 #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_ */
index 9d1aef2..c6f09bb 100644 (file)
@@ -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));
        }
 }
 
index 35d0fb0..f05eb1e 100644 (file)
@@ -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);
 
index 801f5b7..e2d89ca 100644 (file)
@@ -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)) {