patch-2.1.15 linux/drivers/char/wdt.c
Next file: linux/drivers/net/3c509.c
Previous file: linux/drivers/char/wd501p.h
Back to the patch index
Back to the overall index
- Lines: 228
- Date:
Thu Dec 12 16:51:09 1996
- Orig file:
v2.1.14/linux/drivers/char/wdt.c
- Orig date:
Tue Nov 19 15:53:54 1996
diff -u --recursive --new-file v2.1.14/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
@@ -1,23 +1,27 @@
/*
- * Industrial Computer Source WDT500/501 driver for Linux 1.3.x
+ * Industrial Computer Source WDT500/501 driver for Linux 2.1.x
*
- * (c) Copyright 1995 CymruNET Ltd
- * Innovation Centre
- * Singleton Park
- * Swansea
- * Wales
- * UK
- * SA2 8PP
+ * (c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
+ * http://www.cymru.net
*
- * http://www.cymru.net
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
*
- * This driver is provided under the GNU public license, incorporated
- * herein by reference. The driver is provided without warranty or
- * support.
+ * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
- * Release 0.05.
+ * Release 0.06.
*
- * Some changes by Dave Gregorich to fix modularisation and minor bugs.
+ * Fixes
+ * Dave Gregorich : Modularisation and minor bugs
+ * Alan Cox : Added the watchdog ioctl() stuff
+ * Alan Cox : Fixed the reboot problem (as noted by
+ * Matt Crocker).
*/
#include <linux/config.h>
@@ -28,6 +32,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
#include "wd501p.h"
#include <linux/malloc.h>
#include <linux/ioport.h>
@@ -35,6 +40,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <linux/notifier.h>
static int wdt_is_open=0;
@@ -69,7 +75,33 @@
* Kernel methods.
*/
-static void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static int wdt_status(void)
+{
+ /*
+ * Status register to bit flags
+ */
+
+ int flag=0;
+ unsigned char status=inb_p(WDT_SR);
+ status|=FEATUREMAP1;
+ status&=~FEATUREMAP2;
+
+ if(!(status&WDC_SR_TGOOD))
+ flag|=WDIOF_OVERHEAT;
+ if(!(status&WDC_SR_PSUOVER))
+ flag|=WDIOF_POWEROVER;
+ if(!(status&WDC_SR_PSUUNDR))
+ flag|=WDIOF_POWERUNDER;
+ if(!(status&WDC_SR_FANGOOD))
+ flag|=WDIOF_FANFAULT;
+ if(status&WDC_SR_ISOI0)
+ flag|=WDIOF_EXTERN1;
+ if(status&WDC_SR_ISII1)
+ flag|=WDIOF_EXTERN2;
+ return flag;
+}
+
+void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/*
* Read the status register see what is up and
@@ -111,14 +143,23 @@
return -ESPIPE;
}
-static long wdt_write(struct inode *inode, struct file *file, const char *buf, unsigned long count)
+static void wdt_ping(void)
{
/* Write a watchdog value */
inb_p(WDT_DC);
wdt_ctr_mode(1,2);
wdt_ctr_load(1,WD_TIMO); /* Timeout */
outb_p(0, WDT_DC);
- return count;
+}
+
+static long wdt_write(struct inode *inode, struct file *file, const char *buf, unsigned long count)
+{
+ if(count)
+ {
+ wdt_ping();
+ return 1;
+ }
+ return 0;
}
/*
@@ -150,7 +191,41 @@
static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- return -EINVAL;
+ int i;
+ static struct watchdog_info ident=
+ {
+ WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
+ |WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT,
+ 1,
+ "WDT500/501"
+ };
+
+ ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */
+ switch(cmd)
+ {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info));
+ if (i)
+ return i;
+ else
+ return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident));
+
+ case WDIOC_GETSTATUS:
+ i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(int));
+ if (i)
+ return i;
+ else
+ {
+ return put_user(wdt_status(),(int *)arg);
+ }
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, (int *)arg);
+ case WDIOC_KEEPALIVE:
+ wdt_ping();
+ return 0;
+ }
}
static int wdt_open(struct inode *inode, struct file *file)
@@ -197,6 +272,22 @@
}
/*
+ * Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if(code==SYS_DOWN || code==SYS_HALT)
+ {
+ /* Turn the card off */
+ inb_p(WDT_DC);
+ wdt_ctr_load(2,0);
+ }
+ return NOTIFY_DONE;
+}
+
+/*
* Kernel Interfaces
*/
@@ -229,6 +320,18 @@
};
#endif
+/*
+ * The WDT card needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier=
+{
+ wdt_notify_sys,
+ NULL,
+ 0
+};
+
#ifdef MODULE
int init_module(void)
@@ -244,6 +347,7 @@
misc_register(&temp_miscdev);
#endif
request_region(io, 8, "wdt501");
+ notifier_chain_register(&boot_notifier_list, &wdt_notifier);
return 0;
}
@@ -253,6 +357,7 @@
#ifdef CONFIG_WDT_501
misc_deregister(&temp_miscdev);
#endif
+ notifier_chain_unregister(&boot_notifier_list, &wdt_notifier);
release_region(io,8);
free_irq(irq, NULL);
}
@@ -272,6 +377,7 @@
misc_register(&temp_miscdev);
#endif
request_region(io, 8, "wdt501");
+ notifier_chain_register(&boot_notifier_list, &wdt_notifier);
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov