aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPoul-Henning Kamp <phk@FreeBSD.org>2004-02-28 20:06:59 +0000
committerPoul-Henning Kamp <phk@FreeBSD.org>2004-02-28 20:06:59 +0000
commit3e2c971172f16c3dbf180df5c63b16ed56ff2cdd (patch)
treef6fc64bd55b4b3efe406ada1c01bbd455a6d33c3
parente8577ac876da374dd7eca5c35c41ce9af3d5e307 (diff)
downloadsrc-3e2c971172f16c3dbf180df5c63b16ed56ff2cdd.tar.gz
src-3e2c971172f16c3dbf180df5c63b16ed56ff2cdd.zip
Add a generic watchdog facility which through a single device entry
in /dev controls all available watchdog implementations.
Notes
Notes: svn path=/head/; revision=126370
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/watchdog/watchdog.c89
-rw-r--r--sys/i386/i386/elan-mmcr.c141
-rw-r--r--sys/sys/watchdog.h19
4 files changed, 168 insertions, 82 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 12576e0e5bcf..78c0234794f3 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -868,6 +868,7 @@ dev/vx/if_vx.c optional vx
dev/vx/if_vx_eisa.c optional vx eisa
dev/vx/if_vx_pci.c optional vx pci
#dev/wlp/if_wlp.c optional wlp card
+dev/watchdog/watchdog.c standard
dev/wds/wd7000.c optional wds isa
dev/wi/if_wi.c optional wi
dev/wi/if_wi_pccard.c optional wi pccard
diff --git a/sys/dev/watchdog/watchdog.c b/sys/dev/watchdog/watchdog.c
new file mode 100644
index 000000000000..a76e3ef2830b
--- /dev/null
+++ b/sys/dev/watchdog/watchdog.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2004 Poul-Henning Kamp
+ * 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
+ * in this position and unchanged.
+ * 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 AUTHORS ``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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/watchdog.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+static dev_t wd_dev;
+
+static int
+wd_ioctl(dev_t 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))
+ return (EINVAL);
+ if ((u & (WD_ACTIVE | WD_PASSIVE)) == (WD_ACTIVE | WD_PASSIVE))
+ return (EINVAL);
+ if ((u & WD_INTERVAL) == WD_TO_NEVER)
+ u = 0;
+ error = EOPNOTSUPP;
+ EVENTHANDLER_INVOKE(watchdog_list, u, &error);
+ return (error);
+}
+
+static struct cdevsw wd_cdevsw = {
+ .d_version = D_VERSION,
+ .d_ioctl = wd_ioctl,
+ .d_name = "watchdog",
+};
+
+static int
+watchdog_modevent(module_t mod __unused, int type, void *data __unused)
+{
+ switch(type) {
+ case MOD_LOAD:
+ wd_dev = make_dev(&wd_cdevsw, 0,
+ UID_ROOT, GID_WHEEL, 0600, _PATH_WATCHDOG);
+ return 0;
+ case MOD_UNLOAD:
+ destroy_dev(wd_dev);
+ return 0;
+ case MOD_SHUTDOWN:
+ return 0;
+ default:
+ return EOPNOTSUPP;
+ }
+}
+
+DEV_MODULE(watchdog, watchdog_modevent, NULL);
diff --git a/sys/i386/i386/elan-mmcr.c b/sys/i386/i386/elan-mmcr.c
index 80d8759b3cce..15e1f5e20ea6 100644
--- a/sys/i386/i386/elan-mmcr.c
+++ b/sys/i386/i386/elan-mmcr.c
@@ -323,75 +323,14 @@ init_AMD_Elan_sc520(void)
tc_init(&elan_timecounter);
}
-static d_ioctl_t elan_ioctl;
-static d_mmap_t elan_mmap;
-
-static struct cdevsw elan_cdevsw = {
- .d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
- .d_ioctl = elan_ioctl,
- .d_mmap = elan_mmap,
- .d_name = "elan",
-};
-
static void
-elan_drvinit(void)
-{
-
- /* If no elan found, just return */
- if (mmcrptr == NULL)
- return;
-
- printf("Elan-mmcr driver: MMCR at %p.%s\n",
- mmcrptr,
-#ifdef CPU_ELAN_PPS
- " PPS support."
-#else
- ""
-#endif
- );
-
- make_dev(&elan_cdevsw, 0,
- UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
-
-#ifdef CPU_SOEKRIS
- /* Create the error LED on GPIO9 */
- led_cookie[9] = 0x02000c34;
- led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
-
- /* Disable the unavailable GPIO pins */
- strcpy(gpio_config, "-----....--..--------..---------");
-#else /* !CPU_SOEKRIS */
- /* We don't know which pins are available so enable them all */
- strcpy(gpio_config, "................................");
-#endif /* CPU_SOEKRIS */
-}
-
-SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);
-
-static int
-elan_mmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
-{
-
- if (offset >= 0x1000)
- return (-1);
- *paddr = 0xfffef000;
- return (0);
-}
-
-static int
-elan_watchdog(u_int spec)
+elan_watchdog(void *foo __unused, u_int spec, int *error)
{
u_int u, v;
static u_int cur;
- if (spec & ~__WD_LEGAL)
- return (EINVAL);
- switch (spec & (WD_ACTIVE|WD_PASSIVE)) {
- case WD_ACTIVE:
- u = spec & WD_INTERVAL;
- if (u > 35)
- return (EINVAL);
+ u = spec & WD_INTERVAL;
+ if (spec && u <= 35) {
u = imax(u - 5, 24);
v = 2 << (u - 24);
v |= 0xc000;
@@ -422,10 +361,9 @@ elan_watchdog(u_int spec)
elan_mmcr->WDTMRCTL = 0x5555;
}
elan_mmcr->GPECHO = u;
- return (0);
- case WD_PASSIVE:
- return (EOPNOTSUPP);
- case 0:
+ *error = 0;
+ return;
+ } else {
u = elan_mmcr->GPECHO;
elan_mmcr->GPECHO = 0;
elan_mmcr->WDTMRCTL = 0x3333;
@@ -434,19 +372,25 @@ elan_watchdog(u_int spec)
elan_mmcr->WDTMRCTL = u;
elan_mmcr->GPECHO = u;
cur = 0;
- return (0);
- default:
- return (EINVAL);
+ return;
}
-
}
static int
+elan_mmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
+{
+
+ if (offset >= 0x1000)
+ return (-1);
+ *paddr = 0xfffef000;
+ return (0);
+}
+static int
elan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr)
{
int error;
- error = ENOTTY;
+ error = ENOIOCTL;
#ifdef CPU_ELAN_PPS
if (pps_a != 0)
@@ -460,14 +404,55 @@ elan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr)
} else {
elan_timecounter.tc_poll_pps = NULL;
}
- if (error != ENOTTY)
+ if (error != ENOIOCTL)
return (error);
#endif
- if (cmd == WDIOCPATPAT)
- return elan_watchdog(*((u_int*)arg));
-
- /* Other future ioctl handling here */
return(error);
}
+static struct cdevsw elan_cdevsw = {
+ .d_version = D_VERSION,
+ .d_flags = D_NEEDGIANT,
+ .d_ioctl = elan_ioctl,
+ .d_mmap = elan_mmap,
+ .d_name = "elan",
+};
+
+static void
+elan_drvinit(void)
+{
+
+ /* If no elan found, just return */
+ if (mmcrptr == NULL)
+ return;
+
+ printf("Elan-mmcr driver: MMCR at %p.%s\n",
+ mmcrptr,
+#ifdef CPU_ELAN_PPS
+ " PPS support."
+#else
+ ""
+#endif
+ );
+
+ make_dev(&elan_cdevsw, 0,
+ UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
+
+#ifdef CPU_SOEKRIS
+ /* Create the error LED on GPIO9 */
+ led_cookie[9] = 0x02000c34;
+ led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
+
+ /* Disable the unavailable GPIO pins */
+ strcpy(gpio_config, "-----....--..--------..---------");
+#else /* !CPU_SOEKRIS */
+ /* We don't know which pins are available so enable them all */
+ strcpy(gpio_config, "................................");
+#endif /* CPU_SOEKRIS */
+
+ EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0);
+}
+
+SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);
+
diff --git a/sys/sys/watchdog.h b/sys/sys/watchdog.h
index 8cfac00b3e95..a67b68b4392d 100644
--- a/sys/sys/watchdog.h
+++ b/sys/sys/watchdog.h
@@ -30,6 +30,12 @@
#include <sys/ioccom.h>
+#ifdef I_HAVE_TOTALLY_LOST_MY_SENSE_OF_HUMOUR
+#define _PATH_WATCHDOG "watchdog"
+#else
+#define _PATH_WATCHDOG "fido"
+#endif
+
#define WDIOCPATPAT _IOW('W', 42, u_int)
#define WD_ACTIVE 0x8000000
@@ -56,10 +62,6 @@
* NB: Expect variance in the +/- 10-20% range.
*/
-#ifdef _KERNEL
-#define __WD_LEGAL (WD_ACTIVE | WD_PASSIVE | WD_INTERVAL)
-#endif
-
/* Handy macros for humans not used to power of two nanoseconds */
#define WD_TO_NEVER 0
#define WD_TO_1MS 20
@@ -73,4 +75,13 @@
#define WD_TO_16SEC 34
#define WD_TO_32SEC 35
+#ifdef _KERNEL
+
+#include <sys/eventhandler.h>
+
+typedef void (*watchdog_fn)(void *, u_int, int *);
+
+EVENTHANDLER_DECLARE(watchdog_list, watchdog_fn);
+#endif
+
#endif /* _SYS_WATCHDOG_H */