summaryrefslogtreecommitdiff
path: root/sys/arch/sgi
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2012-04-17 15:23:02 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2012-04-17 15:23:02 +0000
commit91ed4a46917ab93a8b6a3c3a667d9e6607c144de (patch)
treeef3f5735fe80ab16b625c7be6d03fbd41eadc1b9 /sys/arch/sgi
parentdff2a6e9e8e7bfbe8ab1fe7968a785952b47b8bc (diff)
panel@hpc: driver for the power button on IP22/IP24, and the volume buttons
where applicable (i.e. Indy only).
Diffstat (limited to 'sys/arch/sgi')
-rw-r--r--sys/arch/sgi/conf/GENERIC-IP224
-rw-r--r--sys/arch/sgi/hpc/panel.c228
2 files changed, 230 insertions, 2 deletions
diff --git a/sys/arch/sgi/conf/GENERIC-IP22 b/sys/arch/sgi/conf/GENERIC-IP22
index 496478f9891..5b59abe8ef5 100644
--- a/sys/arch/sgi/conf/GENERIC-IP22
+++ b/sys/arch/sgi/conf/GENERIC-IP22
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC-IP22,v 1.6 2012/04/16 22:31:34 miod Exp $
+# $OpenBSD: GENERIC-IP22,v 1.7 2012/04/17 15:22:59 miod Exp $
#
# THIS KERNEL IS FOR INDIGO (IP20), INDY (IP22) AND INDIGO2 (IP24) SYSTEMS ONLY.
#
@@ -58,7 +58,7 @@ dsclock0 at hpc0 # IP22/24
sq* at hpc? # On-board Ethernet or E++ adapter
wdsc* at hpc? # On-board SCSI or GIO32 SCSI adapter
#haltwo* at hpc? # Indy/Indigo2 Audio
-#panel* at hpc? # Indy front panel buttons
+panel* at hpc? # Indy front panel buttons
pckbc* at hpc? # Indy/Indigo2 keyboard and mouse
zs0 at hpc0
diff --git a/sys/arch/sgi/hpc/panel.c b/sys/arch/sgi/hpc/panel.c
new file mode 100644
index 00000000000..e9e8bb16b7d
--- /dev/null
+++ b/sys/arch/sgi/hpc/panel.c
@@ -0,0 +1,228 @@
+/* $OpenBSD: panel.c,v 1.1 2012/04/17 15:23:01 miod Exp $ */
+
+/*
+ * Copyright (c) 2012 Miodrag Vallat.
+ *
+ * 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/systm.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/timeout.h>
+#include <sys/workq.h>
+
+#include <machine/autoconf.h>
+#include <mips64/archtype.h>
+#include <machine/bus.h>
+
+#include <sgi/hpc/iocreg.h>
+#include <sgi/hpc/hpcreg.h>
+#include <sgi/hpc/hpcvar.h>
+
+#include <sgi/sgi/ip22.h>
+
+#include "audio.h"
+#include "wskbd.h"
+extern int wskbd_set_mixervolume(long);
+
+struct panel_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ int sc_irq; /* irq number */
+ void *sc_ih; /* irq handler cookie */
+ struct timeout sc_repeat_tmo; /* polling timeout */
+};
+
+/* Repeat delays for volume buttons. */
+#define PANEL_REPEAT_FIRST 400
+#define PANEL_REPEAT_NEXT 100
+
+int panel_match(struct device *, void *, void *);
+void panel_attach(struct device *, struct device *, void *);
+
+struct cfdriver panel_cd = {
+ NULL, "panel", DV_DULL
+};
+
+const struct cfattach panel_ca = {
+ sizeof(struct panel_softc), panel_match, panel_attach
+};
+
+int panel_intr(void *);
+void panel_repeat(void *);
+#if NAUDIO > 0 && NWSKBD > 0
+void panel_volume_adjust(struct panel_softc *, uint8_t);
+#endif
+
+int
+panel_match(struct device *parent, void *vcf, void *aux)
+{
+ struct cfdata *cf = vcf;
+ struct hpc_attach_args *ha = aux;
+
+ if (strcmp(ha->ha_name, cf->cf_driver->cd_name) != 0)
+ return 0;
+
+ if (sys_config.system_type == SGI_IP20)
+ return 0;
+
+ return 1;
+}
+
+void
+panel_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct panel_softc *sc = (struct panel_softc *)self;
+ struct hpc_attach_args *haa = aux;
+
+ sc->sc_iot = haa->ha_st;
+ if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff + 3, 1,
+ &sc->sc_ioh)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ sc->sc_irq = haa->ha_irq;
+ sc->sc_ih = hpc_intr_establish(sc->sc_irq, IPL_BIO, panel_intr, sc,
+ sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf(": can't establish interrupt\n");
+ return;
+ }
+
+ if (sys_config.system_subtype == IP22_INDY)
+ printf(": power and volume buttons\n");
+ else
+ printf(": power button\n");
+
+ timeout_set(&sc->sc_repeat_tmo, panel_repeat, sc);
+}
+
+int
+panel_intr(void *v)
+{
+ struct panel_softc *sc = (struct panel_softc *)v;
+ uint8_t reg, ack;
+ extern int allowpowerdown;
+
+ reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0);
+
+ ack = IOC_PANEL_POWER_STATE;
+ if (sys_config.system_subtype == IP22_INDIGO2 ||
+ (reg & IOC_PANEL_POWER_IRQ) == 0)
+ ack |= IOC_PANEL_POWER_IRQ;
+ if (sys_config.system_subtype == IP22_INDY) {
+ if ((reg & IOC_PANEL_VDOWN_IRQ) == 0)
+ ack |= IOC_PANEL_VDOWN_IRQ;
+ if ((reg & IOC_PANEL_VUP_IRQ) == 0)
+ ack |= IOC_PANEL_VUP_IRQ;
+ }
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0, ack);
+ bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, 1,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+
+ /*
+ * Panel interrupts are latched for about 300 msec after being
+ * acked, and not until all buttons are depressed.
+ * We need to temporary disable the interrupt and switch to polling,
+ * until the interrupt can be enabled again.
+ */
+ hpc_intr_disable(sc->sc_ih);
+
+ /*
+ * If the power button is down, try and issue a shutdown immediately
+ * (if allowed).
+ */
+ if (sys_config.system_subtype == IP22_INDIGO2 ||
+ (reg & IOC_PANEL_POWER_IRQ) == 0) {
+ if (allowpowerdown == 1) {
+ allowpowerdown = 0;
+ psignal(initproc, SIGUSR2);
+ }
+ }
+
+#if NAUDIO > 0 && NWSKBD > 0
+ /*
+ * If any of the volume buttons is down, update volume.
+ */
+ if (sys_config.system_subtype == IP22_INDY)
+ panel_volume_adjust(sc, reg);
+#endif
+
+ timeout_add_msec(&sc->sc_repeat_tmo, PANEL_REPEAT_FIRST);
+
+ return 1;
+}
+
+void
+panel_repeat(void *v)
+{
+ struct panel_softc *sc = (struct panel_softc *)v;
+ uint8_t reg;
+
+ reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0);
+
+#if NAUDIO > 0 && NWSKBD > 0
+ /*
+ * Volume button autorepeat.
+ */
+ if (sys_config.system_subtype == IP22_INDY)
+ panel_volume_adjust(sc, reg);
+#endif
+
+ if (hpc_is_intr_pending(sc->sc_irq)) {
+ /*
+ * Keep acking everything to get the interrupt finally
+ * unlatched.
+ */
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0,
+ IOC_PANEL_POWER_STATE | IOC_PANEL_POWER_IRQ |
+ IOC_PANEL_VDOWN_IRQ | IOC_PANEL_VDOWN_HOLD |
+ IOC_PANEL_VUP_IRQ | IOC_PANEL_VUP_HOLD);
+ bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, 1,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+
+ timeout_add_msec(&sc->sc_repeat_tmo, PANEL_REPEAT_NEXT);
+ } else {
+ hpc_intr_enable(sc->sc_ih);
+ }
+}
+
+#if NAUDIO > 0 && NWSKBD > 0
+void
+panel_volume_adjust(struct panel_softc *sc, uint8_t reg)
+{
+ long adjust;
+
+ switch (reg & (IOC_PANEL_VDOWN_IRQ | IOC_PANEL_VUP_IRQ)) {
+ case 0: /* both buttons pressed: mute */
+ adjust = 0;
+ break;
+ case IOC_PANEL_VDOWN_IRQ: /* up button pressed */
+ adjust = 1;
+ break;
+ case IOC_PANEL_VDUP_IRQ: /* down button pressed */
+ adjust = -1;
+ break;
+ case IOC_PANEL_VDOWN_IRQ | IOC_PANEL_VDUP_IRQ:
+ return;
+ }
+
+ workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume,
+ (void *)adjust, (void *)(int)1);
+}
+#endif