diff options
Diffstat (limited to 'sys/dev/watchdog')
-rw-r--r-- | sys/dev/watchdog/watchdog.c | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/sys/dev/watchdog/watchdog.c b/sys/dev/watchdog/watchdog.c index 06498c9..e7edf31 100644 --- a/sys/dev/watchdog/watchdog.c +++ b/sys/dev/watchdog/watchdog.c @@ -40,35 +40,73 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> static struct cdev *wd_dev; +static volatile u_int wd_last_u; + +static int +kern_do_pat(u_int utim) +{ + int error; + + if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) + return (EINVAL); + + if ((utim & WD_LASTVAL) != 0) { + MPASS((wd_last_u & ~WD_INTERVAL) == 0); + utim &= ~WD_LASTVAL; + utim |= wd_last_u; + } else + wd_last_u = (utim & WD_INTERVAL); + if ((utim & WD_INTERVAL) == WD_TO_NEVER) { + utim = 0; + + /* Assume all is well; watchdog signals failure. */ + error = 0; + } else { + /* Assume no watchdog available; watchdog flags success */ + error = EOPNOTSUPP; + } + EVENTHANDLER_INVOKE(watchdog_list, utim, &error); + return (error); +} static int wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags __unused, struct thread *td) { - int error; u_int u; if (cmd != WDIOCPATPAT) return (ENOIOCTL); u = *(u_int *)data; - if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_INTERVAL)) + if (u & ~(WD_ACTIVE | WD_PASSIVE | WD_LASTVAL | WD_INTERVAL)) return (EINVAL); if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE)) return (EINVAL); - if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && (u & WD_INTERVAL) > 0) + if ((u & (WD_ACTIVE | WD_PASSIVE)) == 0 && ((u & WD_INTERVAL) > 0 || + (u & WD_LASTVAL) != 0)) return (EINVAL); if (u & WD_PASSIVE) return (ENOSYS); /* XXX Not implemented yet */ - if ((u & WD_INTERVAL) == WD_TO_NEVER) { - u = 0; - /* Assume all is well; watchdog signals failure. */ - error = 0; - } else { - /* Assume no watchdog available; watchdog flags success */ - error = EOPNOTSUPP; - } - EVENTHANDLER_INVOKE(watchdog_list, u, &error); - return (error); + u &= ~(WD_ACTIVE | WD_PASSIVE); + + return (kern_do_pat(u)); +} + +u_int +wdog_kern_last_timeout(void) +{ + + return (wd_last_u); +} + +int +wdog_kern_pat(u_int utim) +{ + + if (utim & ~(WD_LASTVAL | WD_INTERVAL)) + return (EINVAL); + + return (kern_do_pat(utim)); } static struct cdevsw wd_cdevsw = { |