# HG changeset patch # User Thinker K.F. Li # Date 1215499307 -28800 # Node ID 76ce6e6624b8e48e6752bc3eb26ea75a68ef68d9 # Parent e59963b503cbdc336b10e84e83cedb496aa6738b Make vordog compatible with watchdog(9). diff -r e59963b503cb -r 76ce6e6624b8 vordog.c --- a/vordog.c Tue Jul 08 12:31:29 2008 +0800 +++ b/vordog.c Tue Jul 08 14:41:47 2008 +0800 @@ -33,6 +33,7 @@ #include #include #include +#include #include "vordog.h" #if 0 @@ -43,12 +44,15 @@ #define VD_STATUS 0x841 #define VD_INITVAL 0x84a #define VD_CTR 0x84b +/* trigger PCIRST */ +#define VD_TIMER_RST 0xc typedef struct vd_softc { struct cdev *_cdev; device_t dev; int open_cnt; - int init_val; + u_int init_val; + eventhandler_tag wd9_tag; } *vd_softc_t; #define CDEV_2_SOFTC(_cdev) ((_cdev)->si_drv1) @@ -98,7 +102,6 @@ static void setup_timer(vordog_cfg_t cfg) { int val; -#define VD_TIMER_RST 0xc val = cfg->init_val & 0xff; outb(VD_INITVAL, val); @@ -107,7 +110,7 @@ } static void -reset_timer(int init_val) { +reset_timer(void) { outb(VD_STATUS, 0xc0); } @@ -123,16 +126,17 @@ int r = 0; vd_softc_t sc; vordog_cfg_t cfg; + static const u_int unit_factors[] = {0, 1, 60, 360}; sc = CDEV_2_SOFTC(dev); switch(cmd) { case VDCTL_ENABLE: cfg = (vordog_cfg_t)data; - sc->init_val = cfg->init_val & 0xff; + sc->init_val = (cfg->init_val & 0xff) * unit_factors[cfg->unit]; setup_timer(cfg); break; case VDCTL_RESET: - reset_timer(sc->init_val); + reset_timer(); break; case VDCTL_DISABLE: disable_timer(); @@ -151,6 +155,67 @@ .d_name = "vordog", }; +/* Implements watchdog(9) compatible driver. */ +static int +vordog_wd9_init(int timeout) { + int val; + + if(timeout < 0 || timeout > 255) + return EINVAL; + + outb(VD_INITVAL, timeout & 0xff); + val = 0x80 | (VDT_1S << 4) | VD_TIMER_RST; + outb(VD_CTR, val); + return 0; +} + +static void +vordog_wd9_reset(void) { + outb(VD_STATUS, 0xc0); +} + +static void +vordog_wd9_disable(void) { + outb(VD_CTR, 0); + outb(VD_STATUS, 0xc0); +} + +static void +vordog_wd9_evh(void *private, u_int cmd, int *error) { + vd_softc_t sc; + u_int timeout, u; + static const int timeouts[] = { 1, 2, 3, 5, 9, 18, 35, 69, 138}; + + sc = (vd_softc_t)private; + + u = cmd & WD_INTERVAL; + if(u < 31 || u > 39) { + vordog_wd9_disable(); + sc->init_val = 0; + return; + } + + timeout = timeouts[u - 31]; + if(timeout != sc->init_val) { + vordog_wd9_init(timeout); + sc->init_val = timeout; + } else { + vordog_wd9_reset(); + } +} + +static void +vordog_wd9_register(vd_softc_t sc) { + sc->wd9_tag = \ + EVENTHANDLER_REGISTER(watchdog_list, vordog_wd9_evh, sc, 0); +} + +static void +vordog_wd9_unregister(vd_softc_t sc) { + EVENTHANDLER_DEREGISTER(watchdog_list, sc->wd9_tag); +} + + /* Following implements a new bus device. * It is attached under nexus bus, an on board device as `vordog0'. */ @@ -202,10 +267,13 @@ sc->open_cnt = 0; sc->init_val = 0; + sc->wd9_tag = NULL; device_set_desc(dev, "Watchdog of Vortex86 SoC"); device_printf(dev, " at port 0x%x\n", VD_STATUS); + vordog_wd9_register(sc); + return 0; } @@ -217,6 +285,10 @@ if(sc->open_cnt != 0) return EBUSY; + disable_timer(); + + vordog_wd9_unregister(sc); + _cdev = sc->_cdev; destroy_dev(_cdev);