From 9289c438ac943d9bf08695a41c4021ceba899d1f Mon Sep 17 00:00:00 2001 From: isaki Date: Sun, 27 Nov 2011 09:00:32 +0000 Subject: [PATCH] Add powsw(4) for x68k power switch. It substitutes for a part about power switch handler of pow(4) deleted before. Benefits than pow(4): - separate a front switch (= powsw0) and an EXPWON line (= powsw1) completely. Only powsw0 is enabled in GENERIC by default. - prevent chattering in some hardware individuals. thank you for a report and a test: Yasushi Oshima and Y.Sugahara. --- distrib/sets/lists/man/mi | 5 +- share/man/man4/man4.x68k/Makefile | 4 +- share/man/man4/man4.x68k/powsw.4 | 55 ++++++ sys/arch/x68k/conf/GENERIC | 7 +- sys/arch/x68k/conf/files.x68k | 6 +- sys/arch/x68k/dev/powsw.c | 290 ++++++++++++++++++++++++++++++ 6 files changed, 361 insertions(+), 6 deletions(-) create mode 100644 share/man/man4/man4.x68k/powsw.4 create mode 100644 sys/arch/x68k/dev/powsw.c diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi index 0ffd36215a0d..f04d7cb4bb71 100644 --- a/distrib/sets/lists/man/mi +++ b/distrib/sets/lists/man/mi @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1358 2011/11/26 15:39:49 tsutsui Exp $ +# $NetBSD: mi,v 1.1359 2011/11/27 09:00:32 isaki Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -1826,6 +1826,7 @@ ./usr/share/man/cat4/x68k/mfp.0 man-sys-catman .cat ./usr/share/man/cat4/x68k/neptune.0 man-sys-catman .cat ./usr/share/man/cat4/x68k/pow.0 man-obsolete obsolete +./usr/share/man/cat4/x68k/powsw.0 man-sys-catman .cat ./usr/share/man/cat4/x68k/vs.0 man-sys-catman .cat ./usr/share/man/cat4/x86/amdpcib.0 man-sys-catman .cat ./usr/share/man/cat4/x86/apic.0 man-sys-catman .cat @@ -4592,6 +4593,7 @@ ./usr/share/man/html4/x68k/mfp.html man-sys-htmlman html ./usr/share/man/html4/x68k/neptune.html man-sys-htmlman html ./usr/share/man/html4/x68k/pow.html man-obsolete obsolete +./usr/share/man/html4/x68k/powsw.html man-sys-htmlman html ./usr/share/man/html4/x68k/vs.html man-sys-htmlman html ./usr/share/man/html4/x86/amdpcib.html man-sys-htmlman html ./usr/share/man/html4/x86/apic.html man-sys-htmlman html @@ -7293,6 +7295,7 @@ ./usr/share/man/man4/x68k/mfp.4 man-sys-man .man ./usr/share/man/man4/x68k/neptune.4 man-sys-man .man ./usr/share/man/man4/x68k/pow.4 man-obsolete obsolete +./usr/share/man/man4/x68k/powsw.4 man-sys-man .man ./usr/share/man/man4/x68k/vs.4 man-sys-man .man ./usr/share/man/man4/x86/amdpcib.4 man-sys-man .man ./usr/share/man/man4/x86/apic.4 man-sys-man .man diff --git a/share/man/man4/man4.x68k/Makefile b/share/man/man4/man4.x68k/Makefile index e183311cd592..aeb3a1e584d4 100644 --- a/share/man/man4/man4.x68k/Makefile +++ b/share/man/man4/man4.x68k/Makefile @@ -1,6 +1,6 @@ -# $NetBSD: Makefile,v 1.8 2011/11/19 12:27:43 isaki Exp $ +# $NetBSD: Makefile,v 1.9 2011/11/27 09:00:33 isaki Exp $ -MAN= bmd.4 intio.4 intro.4 mfp.4 neptune.4 vs.4 +MAN= bmd.4 intio.4 intro.4 mfp.4 neptune.4 powsw.4 vs.4 MANSUBDIR=/x68k .include diff --git a/share/man/man4/man4.x68k/powsw.4 b/share/man/man4/man4.x68k/powsw.4 new file mode 100644 index 000000000000..404b30ce9cee --- /dev/null +++ b/share/man/man4/man4.x68k/powsw.4 @@ -0,0 +1,55 @@ +.\" $NetBSD: powsw.4,v 1.1 2011/11/27 09:00:33 isaki Exp $ +.\" +.\" Copyright (c) 2011 Tetsuya Isaki. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 27, 2011 +.Dt POWSW 4 x68k +.Os +.Sh NAME +.Nm powsw +.Nd x68k power switch handler +.Sh SYNOPSIS +.Cd powsw0 at mfp0 +.Cd powsw1 at mfp0 +.Sh DESCRIPTION +The +.Nm +driver monitors x68k's power switch, +and is made as interface to +.Xr sysmon_pswitch 9 . +.Pp +.Nm powsw0 +monitors a front switch. +.Nm powsw1 +monitors an external power switch (EXPWON signal in I/O slot). +.Sh SEE ALSO +.Xr powerd 8 +.Sh HISTORY +.Nm +appeared in +.Nx 6.0 . +.Sh BUGS +I have no idea for +.Nm powsw2 +(rtc alarm). diff --git a/sys/arch/x68k/conf/GENERIC b/sys/arch/x68k/conf/GENERIC index 8dc1b1e3d09d..7d6464d3cb44 100644 --- a/sys/arch/x68k/conf/GENERIC +++ b/sys/arch/x68k/conf/GENERIC @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.157 2011/11/22 21:25:41 tls Exp $ +# $NetBSD: GENERIC,v 1.158 2011/11/27 09:00:32 isaki Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/x68k/conf/std.x68k" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.157 $" +#ident "GENERIC-$Revision: 1.158 $" maxusers 8 @@ -288,6 +288,9 @@ par0 at intio0 addr 0xe8c000 # Builtin printer port sram0 at intio0 addr 0xed0000 # battery-backuped static RAM pseudo-device bell # OPM bell +powsw0 at mfp0 # Front switch +#powsw1 at mfp0 # External power switch + xcom0 at mainbus0 # NS16550 fast serial xcom1 at mainbus0 diff --git a/sys/arch/x68k/conf/files.x68k b/sys/arch/x68k/conf/files.x68k index 5b228ffa28c8..77a432f371c2 100644 --- a/sys/arch/x68k/conf/files.x68k +++ b/sys/arch/x68k/conf/files.x68k @@ -1,4 +1,4 @@ -# $NetBSD: files.x68k,v 1.76 2011/11/19 12:27:43 isaki Exp $ +# $NetBSD: files.x68k,v 1.77 2011/11/27 09:00:32 isaki Exp $ # # new style config file for x68k architecture # @@ -96,6 +96,10 @@ device kbd: event attach kbd at mfp file arch/x68k/dev/kbd.c kbd needs-flag +device powsw: sysmon_power, sysmon_taskq +attach powsw at mfp +file arch/x68k/dev/powsw.c powsw + device rtc attach rtc at intio file arch/x68k/dev/rtclock.c rtc diff --git a/sys/arch/x68k/dev/powsw.c b/sys/arch/x68k/dev/powsw.c new file mode 100644 index 000000000000..2148d4bf1a56 --- /dev/null +++ b/sys/arch/x68k/dev/powsw.c @@ -0,0 +1,290 @@ +/* $NetBSD: powsw.c,v 1.1 2011/11/27 09:00:32 isaki Exp $ */ + +/* + * Copyright (c) 2011 Tetsuya Isaki. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Power switch monitor + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: powsw.c,v 1.1 2011/11/27 09:00:32 isaki Exp $"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +extern int power_switch_is_off; /* XXX should be in .h */ + +//#define POWSW_DEBUG + +#if defined(POWSW_DEBUG) +#define DPRINTF(fmt...) printf(fmt) +#define DEBUG_LOG_ADD(c) sc->sc_log[sc->sc_loglen++] = (c) +#define DEBUG_LOG_PRINT() do { \ + sc->sc_log[sc->sc_loglen] = '\0'; \ + printf("%s", sc->sc_log); \ +} while (0) +#else +#define DPRINTF(fmt...) +#define DEBUG_LOG_ADD(c) +#define DEBUG_LOG_PRINT() +#endif + +/* mask */ +#define POWSW_ALARM (0x01) +#define POWSW_EXTERNAL (0x02) +#define POWSW_FRONT (0x04) + +/* parameter */ +#define POWSW_MAX_TICK (30) +#define POWSW_THRESHOLD (10) + +struct powsw_softc { + device_t sc_dev; + struct sysmon_pswitch sc_smpsw; + callout_t sc_callout; + int sc_mask; + int sc_prev; + int sc_last_sw; + int sc_tick; + int sc_count; +#if defined(POWSW_DEBUG) + char sc_log[100]; + int sc_loglen; +#endif +}; + +extern struct cfdriver powsw_cd; + +static int powsw_match(device_t, cfdata_t, void *); +static void powsw_attach(device_t, device_t, void *); +static int powsw_intr(void *); +static void powsw_softintr(void *); +static void powsw_pswitch_event(void *); +static void powsw_shutdown_check(void *); +static void powsw_reset_counter(struct powsw_softc *); +static void powsw_set_aer(struct powsw_softc *, int); + +CFATTACH_DECL_NEW(powsw, sizeof(struct powsw_softc), + powsw_match, powsw_attach, NULL, NULL); + + +typedef const struct { + int vector; /* interrupt vector */ + int mask; /* mask bit for MFP GPIP */ + const char *name; +} powsw_desc_t; + +static powsw_desc_t powsw_desc[2] = { + { 66, POWSW_FRONT, "Front Switch", }, + { 65, POWSW_EXTERNAL, "External Power Switch", }, + /* XXX I'm not sure about alarm bit */ +}; + + +static int +powsw_match(device_t parent, cfdata_t cf, void *aux) +{ + return 1; +} + +static void +powsw_attach(device_t parent, device_t self, void *aux) +{ + struct powsw_softc *sc = device_private(self); + powsw_desc_t *desc; + const char *xname; + int unit; + int sw; + + unit = device_unit(self); + xname = device_xname(self); + desc = &powsw_desc[unit]; + + memset(sc, 0, sizeof(*sc)); + sc->sc_dev = self; + sc->sc_mask = desc->mask; + sc->sc_prev = -1; + powsw_reset_counter(sc); + + sysmon_task_queue_init(); + sc->sc_smpsw.smpsw_name = xname; + sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_POWER; + if (sysmon_pswitch_register(&sc->sc_smpsw) != 0) + panic("can't register with sysmon"); + + callout_init(&sc->sc_callout, 0); + callout_setfunc(&sc->sc_callout, powsw_softintr, sc); + + if (shutdownhook_establish(powsw_shutdown_check, sc) == NULL) + panic("%s: can't establish shutdown hook", xname); + + if (intio_intr_establish(desc->vector, xname, powsw_intr, sc) < 0) + panic("%s: can't establish interrupt", xname); + + /* Set AER and enable interrupt */ + sw = (mfp_get_gpip() & sc->sc_mask); + powsw_set_aer(sc, sw ? 0 : 1); + mfp_bit_set_ierb(sc->sc_mask); + + aprint_normal(": %s\n", desc->name); +} + +static int +powsw_intr(void *arg) +{ + struct powsw_softc *sc = arg; + + if (sc->sc_tick == 0) { + mfp_bit_clear_ierb(sc->sc_mask); + sc->sc_tick++; + DEBUG_LOG_ADD('i'); + /* + * The button state seems unstable for few ticks, + * so wait a bit to settle. + */ + callout_schedule(&sc->sc_callout, 1); + } else { + DEBUG_LOG_ADD('x'); + } + return 0; +} + +void +powsw_softintr(void *arg) +{ + struct powsw_softc *sc = arg; + int sw; + int s; + + s = spl6(); + + if (sc->sc_tick++ >= POWSW_MAX_TICK) { + /* tick is over, broken switch? */ + printf("%s: unstable power switch?, ignored\n", + device_xname(sc->sc_dev)); + powsw_reset_counter(sc); + + mfp_bit_set_ierb(sc->sc_mask); + splx(s); + return; + } + + sw = (mfp_get_gpip() & sc->sc_mask) ? 1 : 0; + DEBUG_LOG_ADD('0' + sw); + + if (sw == sc->sc_last_sw) { + sc->sc_count++; + } else { + sc->sc_last_sw = sw; + sc->sc_count = 1; + } + + if (sc->sc_count < POWSW_THRESHOLD) { + callout_schedule(&sc->sc_callout, 1); + } else { + /* switch seems stable */ + DEBUG_LOG_PRINT(); + + if (sc->sc_last_sw == sc->sc_prev) { + /* switch state is not changed, it was a noise */ + DPRINTF(" ignore(sw=%d,prev=%d)\n", sc->sc_last_sw, sc->sc_prev); + } else { + /* switch state has been changed */ + sc->sc_prev = sc->sc_last_sw; + powsw_set_aer(sc, 1 - sc->sc_prev); + sysmon_task_queue_sched(0, powsw_pswitch_event, sc); + } + powsw_reset_counter(sc); + mfp_bit_set_ierb(sc->sc_mask); // enable interrupt + } + + splx(s); +} + +static void +powsw_pswitch_event(void *arg) +{ + struct powsw_softc *sc = arg; + int poweroff; + + poweroff = sc->sc_prev; + + DPRINTF(" %s is %s\n", device_xname(sc->sc_dev), + poweroff ? "off(PRESS)" : "on(RELEASE)"); + + sysmon_pswitch_event(&sc->sc_smpsw, + poweroff ? PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED); +} + +static void +powsw_shutdown_check(void *arg) +{ + struct powsw_softc *sc = arg; + int poweroff; + + poweroff = sc->sc_prev; + if (poweroff) + power_switch_is_off = 1; + DPRINTF("powsw_shutdown_check %s = %d\n", + device_xname(sc->sc_dev), power_switch_is_off); +} + +static void +powsw_reset_counter(struct powsw_softc *sc) +{ + sc->sc_last_sw = -1; + sc->sc_tick = 0; + sc->sc_count = 0; +#if defined(POWSW_DEBUG) + sc->sc_loglen = 0; +#endif +} + +static void +powsw_set_aer(struct powsw_softc *sc, int aer) +{ + KASSERT(aer == 0 || aer == 1); + + if (aer == 0) { + mfp_bit_clear_aer(sc->sc_mask); + } else { + mfp_bit_set_aer(sc->sc_mask); + } + DPRINTF(" SetAER=%d", aer); +}