/* $NetBSD$ */ /* * Copyright (C) 2001 WIDE Project. 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. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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. */ /* * Device driver for JUMPtec watchdog timer BIOS, as well as LAMB LEDs. * http://www.jumptec.de/ */ #include #include #include #include #include #include #include #include struct jumptec_softc { struct device sc_dev; struct sysmon_wdog sc_smw; u_int16_t sc_period; u_int8_t sc_lastarm; }; int jumptecmatch __P((struct device *, struct cfdata *, void *)); void jumptecattach __P((struct device *, struct device *, void *)); int jumptec_wdog_setmode(struct sysmon_wdog *); int jumptec_wdog_tickle(struct sysmon_wdog *); int jumptec_wdog_arm_disarm(struct jumptec_softc *, u_int8_t); struct cfattach jumptec_ca = { sizeof(struct jumptec_softc), jumptecmatch, jumptecattach }; /* ARGSUSED */ int jumptecmatch(struct device *parent, struct cfdata *match, void *aux) { struct isa_attach_args *ia = aux; struct bioscallregs regs; /* is it a JUMPtec device? XXX API abuse */ regs.AX = 0xea01; /* Get manufacturing date */ regs.CL = 0x00; /* default device */ regs.DX = 0x4648; /* magic */ bioscall(0x15, ®s); if (regs.DX != 0x6b6f) /* did we get the magic number? */ return 0; ia->ia_iosize = 3; ia->ia_msize = 0; return 1; } void jumptecattach(struct device *parent, struct device *self, void *aux) { struct jumptec_softc *sc = (struct jumptec_softc *)self; printf(": JUMPtec watchdog timer\n"); /* * Register the Weasel watchdog timer in case user decides * to set 'allow watchdog' to 'YES' after the machine has booted. */ sc->sc_smw.smw_name = "jumptec"; sc->sc_smw.smw_cookie = sc; sc->sc_smw.smw_setmode = jumptec_wdog_setmode; sc->sc_smw.smw_tickle = jumptec_wdog_tickle; sc->sc_smw.smw_period = 1; /* 1sec */ if (sysmon_wdog_register(&sc->sc_smw) != 0) printf("%s: unable to register JUMPtec watchdog with sysmon\n", sc->sc_dev.dv_xname); return; } int jumptec_wdog_setmode(struct sysmon_wdog *smw) { struct jumptec_softc *sc = (struct jumptec_softc *)smw->smw_cookie; int error = 0; int i; printf("setmode\n"); if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) error = jumptec_wdog_arm_disarm(sc, 0); else { switch (smw->smw_period) { case WDOG_PERIOD_DEFAULT: smw->smw_period = 1; /* 1sec */ /* FALLTHROUGH */ case 1: case 2: case 4: case 8: case 16: case 32: for (i = 1; (1 << (i - 1)) < smw->smw_period; i++) ; break; default: /* Unsupported period */ printf("period %u unsupp\n", smw->smw_period); return EINVAL; } error = jumptec_wdog_arm_disarm(sc, i); if (!error) jumptec_wdog_tickle(smw); } return (error); } int jumptec_wdog_tickle(struct sysmon_wdog *smw) { struct jumptec_softc *sc = (struct jumptec_softc *)smw->smw_cookie; struct bioscallregs regs; if (!sc->sc_lastarm) { printf("no arm no tickle\n"); return 0; } printf("tickle\n"); memset(®s, 0, sizeof(regs)); regs.AX = 0xe001; /* Watchdog trigger */ #if 0 /* kernel panic */ bioscall(0x15, ®s); #endif printf("tickle done\n"); return 0; } int jumptec_wdog_arm_disarm(struct jumptec_softc *sc, u_int8_t mode) { struct bioscallregs regs; printf("arm %u\n", mode); memset(®s, 0, sizeof(regs)); regs.AX = 0xe000; /* Watchdog init */ regs.BH = 0x00; regs.BL = mode; /* 0: off, otherwise 2^(BL - 1) sec */ regs.DX = 0x00; /* reset if armed */ #if 0 /* kernel panic */ bioscall(0x15, ®s); #endif printf("arm done\n"); sc->sc_lastarm = mode; return 0; }