patch-2.1.15 linux/drivers/char/pcwd.c
Next file: linux/drivers/char/psaux.c
Previous file: linux/drivers/char/n_tty.c
Back to the patch index
Back to the overall index
- Lines: 461
- Date:
Thu Dec 12 16:51:09 1996
- Orig file:
v2.1.14/linux/drivers/char/pcwd.c
- Orig date:
Fri Aug 23 09:11:25 1996
diff -u --recursive --new-file v2.1.14/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
@@ -15,6 +15,10 @@
* check_region command due to Alan's suggestion.
* 960821 Made changes to compile in newer 2.0.x kernels. Added
* "cold reboot sense" entry.
+ * 960825 Made a few changes to code, deleted some defines and made
+ * typedefs to replace them. Made heartbeat reset only available
+ * via ioctl, and removed the write routine.
+ * 960828 Added new items for PC Watchdog Rev.C card.
*/
#include <linux/module.h>
@@ -24,6 +28,7 @@
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/timer.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/string.h>
@@ -33,37 +38,67 @@
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/mm.h>
-#include <linux/pcwd.h>
-
+#include <linux/watchdog.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
-#define WD_VER "0.50 (08/21/96)"
-#define WD_MINOR 130 /* Minor device number */
+typedef struct pcwd_ioports {
+ int first_port;
+ int range;
+} IOPS;
-#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */
+/*
+** These are the auto-probe addresses available for the Rev.A version of the
+** PC Watchdog card.
+*/
+
+static IOPS pcwd_ioports[] = {
+ { 0x270, 3 },
+ { 0x350, 3 },
+ { 0x370, 3 },
+ { 0x000, 0 }
+};
-#define WD_TIMERRESET_PORT1 0x270 /* Reset port - first choice */
-#define WD_TIMERRESET_PORT2 0x370 /* Reset port - second choice */
-#define WD_CTLSTAT_PORT1 0x271 /* Control port - first choice */
-#define WD_CTLSTAT_PORT2 0x371 /* Control port - second choice */
-#define WD_PORT_EXTENT 2 /* Takes up two addresses */
+#ifdef DEBUG
+#define dprintk(x) printk(x)
+#else
+#define dprintk(x)
+#endif
+#ifdef CONFIG_PCWD_REV_A
+#define CARD_REV "A"
+#define PORT_OFFSET 0
+#define PORT_RANGE 2
#define WD_WDRST 0x01 /* Previously reset state */
#define WD_T110 0x02 /* Temperature overheat sense */
#define WD_HRTBT 0x04 /* Heartbeat sense */
#define WD_RLY2 0x08 /* External relay triggered */
#define WD_SRLY2 0x80 /* Software external relay triggered */
+#endif
+#ifdef CONFIG_PCWD_REV_C
+#define CARD_REV "C"
+#define PORT_OFFSET 1
+#define PORT_RANGE 4
+#define WD_WDRST 0x01 /* Previously reset state */
+#define WD_T110 0x04 /* Temperature overheat sense */
+#endif
-static int current_ctlport, current_readport;
-static int is_open, is_eof;
+#define WD_VER "0.52 (08/28/96)"
+#define WD_MINOR 130 /* Minor device number */
+
+#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */
+
+
+static int current_readport;
+static int is_open, initial_status, supports_temp, mode_debug;
int pcwd_checkcard(void)
{
int card_dat, prev_card_dat, found = 0, count = 0, done = 0;
/* As suggested by Alan Cox */
- if (check_region(current_ctlport, WD_PORT_EXTENT)) {
- printk("pcwd: Port 0x%x unavailable.\n", current_ctlport);
+ if (check_region(current_readport, PORT_RANGE)) {
+ printk("pcwd: Port 0x%x unavailable.\n", current_readport);
return 0;
}
@@ -71,11 +106,13 @@
prev_card_dat = 0x00;
prev_card_dat = inb(current_readport);
+ if (prev_card_dat == 0xFF) {
+ dprintk(("pcwd: No card detected at 0x%03x\n", current_readport));
+ return 0;
+ }
while(count < WD_TIMEOUT) {
-#ifdef DEBUG
- printk("pcwd: Run #%d on port 0x%03x\n", count, current_readport);
-#endif
+ dprintk(("pcwd: Run #%d on port 0x%03x\n", count, current_readport));
/* Read the raw card data from the port, and strip off the
first 4 bits */
@@ -96,9 +133,7 @@
count++;
done = 1;
-#ifdef DEBUG
- printk("pcwd: I show nothing on this port.\n");
-#endif
+ dprintk(("pcwd: I show nothing on this port.\n"));
}
/* If there's a heart beat in both instances, then this means we
@@ -109,9 +144,8 @@
(!done)) {
found = 1;
done = 1;
-#ifdef DEBUG
- printk("pcwd: I show alternate heart beats. Card detected.\n");
-#endif
+
+ dprintk(("pcwd: I show alternate heart beats. Card detected.\n"));
break;
}
@@ -125,9 +159,7 @@
if ((card_dat == prev_card_dat) && (!done)) {
count++;
-#ifdef DEBUG
- printk("pcwd: The card data is exactly the same (possibility).\n");
-#endif
+ dprintk(("pcwd: The card data is exactly the same (possibility).\n"));
done = 1;
}
@@ -137,9 +169,7 @@
if ((card_dat != prev_card_dat) && (!done)) {
done = 1;
found = 1;
-#ifdef DEBUG
- printk("pcwd: I show alternate heart beats. Card detected.\n");
-#endif
+ dprintk(("pcwd: I show alternate heart beats. Card detected.\n"));
break;
}
@@ -156,43 +186,35 @@
{
int card_status = 0x0000;
- card_status = inb(current_readport);
+ initial_status = card_status = inb(current_readport + PORT_OFFSET);
if (card_status & WD_WDRST)
printk("pcwd: Previous reboot was caused by the card.\n");
- if (card_status & WD_T110)
- printk("pcwd: CPU overheat sense.\n");
+ if (supports_temp)
+ if(card_status & WD_T110)
+ printk("pcwd: CPU overheat sense.\n");
if ((!(card_status & WD_WDRST)) &&
(!(card_status & WD_T110)))
printk("pcwd: Cold boot sense.\n");
}
-static int pcwd_return_data(void)
-{
- return(inb(current_readport));
-}
-
-static int pcwd_write(struct inode *inode, struct file *file, const char *data,
- int len)
+static void pcwd_send_heartbeat(void)
{
int wdrst_stat;
if (!is_open)
- return -EIO;
+ return;
-#ifdef DEBUG
- printk("pcwd: write request\n");
-#endif
+ dprintk(("pcwd: heartbeat\n"));
wdrst_stat = inb_p(current_readport);
wdrst_stat &= 0x0F;
wdrst_stat |= WD_WDRST;
- outb_p(wdrst_stat, current_ctlport);
-
+ outb_p(wdrst_stat, current_readport + PORT_OFFSET);
return(1);
}
@@ -200,58 +222,118 @@
unsigned int cmd, unsigned long arg)
{
int i, cdat, rv;
-
+ static struct watchdog_ident ident=
+ {
+ WDIOF_OVERHEAT|WDIOF_CARDRESET,
+#ifdef CONFIG_PCWD_REV_A
+ 1,
+#else
+ 3,
+#endif
+ "PCWD revision "CARD_REV"."
+ };
+
switch(cmd) {
default:
return -ENOIOCTLCMD;
- case PCWD_GETSTAT:
+ case WDIOC_GETSUPPORT:
+ i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info));
+ if (i)
+ return i;
+ else
+ return copy_to_user(arg, &ident, sizeof(ident));
+
+ case WDIOC_GETSTATUS:
i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(int));
if (i)
return i;
else {
- cdat = pcwd_return_data();
+ cdat = inb(current_readport);
rv = 0;
if (cdat & WD_WDRST)
- rv |= 0x01;
+ rv |= WDIOF_CARDRESET;
if (cdat & WD_T110)
- rv |= 0x02;
+ rv |= WDIOF_OVERHEAT;
- put_user(rv, (int *) arg);
- return 0;
+ return put_user(rv, (int *) arg);
}
break;
- case PCWD_PING:
- pcwd_write(NULL, NULL, NULL, 1); /* Is this legal? */
+ case WDIOC_GETBOOTSTATUS:
+ i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(int));
+ if (i)
+ return i;
+ else {
+ int rv;
+ rv = 0;
+
+ if (initial_status & WD_WDRST)
+ rv |= WDIOF_CARDRESET;
+
+ if (initial_status & WD_T110)
+ rv |= WDIOF_OVERHEAT;
+ return put_user(rv, (int *) arg);
+ }
break;
+
+ case WDIOC_GETTEMP:
+ i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(int));
+ if (i)
+ return i;
+ else {
+ int rv;
+
+ rv = 0;
+ if ((supports_temp) && (mode_debug == 0)) {
+ rv = inb(current_readport);
+ return put_user(rv, (int*) arg);
+ } else
+ return put_user(rv, (int*) arg);
+ }
+
+ case WDIOC_KEEPALIVE:
+ pcwd_send_heartbeat();
+ return 0;
}
return 0;
}
+static long pcwd_write(struct file *file, struct inode *inode, const char *buf, unsigned long len)
+{
+ if(len)
+ {
+ pcwd_send_heartbeat();
+ return 1;
+ }
+}
+
static int pcwd_open(struct inode *ino, struct file *filep)
{
-#ifdef DEBUG
- printk("pcwd: open request\n");
-#endif
+ dprintk(("pcwd: open request\n"));
MOD_INC_USE_COUNT;
- is_eof = 0;
return(0);
}
static void pcwd_close(struct inode *ino, struct file *filep)
{
-#ifdef DEBUG
- printk("pcwd: close request\n");
-#endif
+ dprintk(("pcwd: close request\n"));
MOD_DEC_USE_COUNT;
}
+static void get_support(void)
+{
+#ifdef CONFIG_PCWD_REV_C
+ if (inb(current_readport) != 0xF0)
+#endif
+ supports_temp = 1;
+}
+
static struct file_operations pcwd_fops = {
NULL, /* Seek */
NULL, /* Read */
@@ -276,48 +358,57 @@
int pcwatchdog_init(void)
#endif
{
-#ifdef DEBUG
- printk("pcwd: Success.\n");
-#endif
- printk("pcwd: v%s Ken Hollis (khollis@bitgate.com)\n", WD_VER);
+ int i, found = 0;
-#ifdef DEBUG
- printk("pcwd: About to perform card autosense loop.\n");
-#endif
+ dprintk(("pcwd: Success.\n"));
+ printk(KERN_INFO "pcwd: v%s Ken Hollis (khollis@bitgate.com)\n", WD_VER);
+
+ dprintk(("pcwd: About to perform card autosense loop.\n"));
- is_eof = 0;
+ /* Initial variables */
is_open = 0;
+ supports_temp = 0;
+ mode_debug = 0;
+ initial_status = 0x0000;
- current_ctlport = WD_TIMERRESET_PORT1;
- current_readport = WD_CTLSTAT_PORT1;
+ dprintk(("pcwd: Revision " CARD_REV " support defined.\n"));
+
+ for (i = 0; pcwd_ioports[i].first_port != 0; i++) {
+ current_readport = pcwd_ioports[i].first_port;
if (!pcwd_checkcard()) {
-#ifdef DEBUG
- printk("pcwd: Trying port 0x370.\n");
-#endif
+ dprintk(("pcwd: Trying port 0x%03x.\n", pcwd_ioports[i].first_port));
+ if (pcwd_checkcard()) {
+ found = 1;
+ break;
+ }
+ }
- current_ctlport = WD_TIMERRESET_PORT2;
- current_readport = WD_CTLSTAT_PORT2;
+ if (!found) {
+ printk("pcwd: No card detected.\n");
+ return(-EIO);
+ }
- if (!pcwd_checkcard()) {
- printk("pcwd: No card detected, or wrong port assigned.\n");
- return(-EIO);
- } else
- printk("pcwd: Watchdog Rev.A detected at port 0x370\n");
- } else
- printk("pcwd: Watchdog Rev.A detected at port 0x270\n");
+ is_open = 1;
- pcwd_showprevstate();
+ get_support();
-#ifdef DEBUG
- printk("pcwd: Requesting region entry\n");
+#ifdef CONFIG_PCWD_REV_A
+ printk("pcwd: PC Watchdog (REV.A) detected at port 0x%03x\n", current_readport);
+#endif
+#ifdef CONFIG_PCWD_REV_C
+ printk("pcwd: PC Watchdog (REV.C) detected at port 0x%03x -%stemp. support\n",
+ current_readport, (supports_temp) ? " Has " : " No ");
#endif
- request_region(current_ctlport, WD_PORT_EXTENT, "PCWD Rev.A (Berkshire)");
-
-#ifdef DEBUG
- printk("pcwd: character device creation.\n");
+#ifdef CONFIG_PCWD_SHOW_PREVSTAT
+ pcwd_showprevstate();
#endif
+ dprintk(("pcwd: Requesting region entry\n"));
+
+ request_region(current_readport, PORT_RANGE, "PCWD Rev." CARD_REV "(Berkshire)");
+
+ dprintk(("pcwd: character device creation.\n"));
misc_register(&pcwd_miscdev);
@@ -328,10 +419,9 @@
void cleanup_module(void)
{
misc_deregister(&pcwd_miscdev);
- release_region(current_ctlport, 2);
-#ifdef DEBUG
- printk("pcwd: Cleanup successful.\n");
-#endif
+ release_region(current_readport, PORT_RANGE);
+
+ dprintk(("pcwd: Cleanup successful.\n"));
}
#endif
@@ -339,9 +429,7 @@
** TODO:
**
** Both Revisions:
-** o) Support for revision B of the Watchdog Card
** o) Implement the rest of the IOCTLs as discussed with Alan Cox
-** o) Implement only card heartbeat reset via IOCTL, not via write
** o) Faster card detection routines
** o) /proc device creation
**
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov