patch-1.3.57 linux/drivers/char/wdt.c

Next file: linux/drivers/net/arcnet.c
Previous file: linux/drivers/char/wd501p.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.56/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
@@ -0,0 +1,271 @@
+/*
+ *	Industrial Computer Source WDT500/501 driver for Linux 1.3.x
+ *
+ *	(c) Copyright 1995	CymruNET Ltd
+ *				Innovation Centre
+ *				Singleton Park
+ *				Swansea
+ *				Wales
+ *				UK
+ *				SA2 8PP
+ *
+ *	http://www.cymru.net
+ *
+ *	This driver is provided under the GNU public license, incorporated
+ *	herein by reference. The driver is provided without warranty or 
+ *	support.
+ *
+ *	Release 0.04.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mouse.h>
+#include "wd501p.h"
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+static int wdt_is_open=0;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ */
+ 
+int io=0x240;
+int irq=14;
+
+#define WD_TIMO (100*60)		/* 1 minute */
+
+/*
+ *	Programming suppoort
+ */
+ 
+static void wdt_ctr_mode(int ctr, int mode)
+{
+	ctr<<=6;
+	ctr|=0x30;
+	ctr|=(mode<<1);
+	outb_p(ctr, WDT_CR);
+}
+
+static void wdt_ctr_load(int ctr, int val)
+{
+	outb_p(val&0xFF, WDT_COUNT0+ctr);
+	outb_p(val>>8, WDT_COUNT0+ctr);
+}
+
+/*
+ *	Kernel methods.
+ */
+ 
+static void wdt_interrupt(int irq, struct pt_regs *regs)
+{
+	/*
+	 *	Read the status register see what is up and
+	 *	then printk it.
+	 */
+	 
+	unsigned char status=inb_p(WDT_SR);
+	
+	status|=FEATUREMAP1;
+	status&=~FEATUREMAP2;	
+	
+	printk(KERN_CRIT "WDT status %d\n", status);
+	
+	if(!(status&WDC_SR_TGOOD))
+		printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
+	if(!(status&WDC_SR_PSUOVER))
+		printk(KERN_CRIT "PSU over voltage.\n");
+	if(!(status&WDC_SR_PSUUNDR))
+		printk(KERN_CRIT "PSU under voltage.\n");
+	if(!(status&WDC_SR_FANGOOD))
+		printk(KERN_CRIT "Possible fan fault.\n");
+	if(!(status&WDC_SR_WCCR))
+#ifdef SOFTWARE_REBOOT
+#ifdef ONLY_TESTING
+		printk(KERN_CRIT "Would Reboot.\n");
+#else		
+		printk(KERN_CRIT "Initiating system reboot.\n");
+		hard_reset_now();
+#endif		
+#else
+		printk(KERN_CRIT "Reset in 5ms.\n");
+#endif		
+}
+
+
+static int wdt_lseek(struct inode *inode, struct file *file, off_t offset, 
+	int origin)
+{
+	return -ESPIPE;
+}
+
+static int wdt_write(struct inode *inode, struct file *file, char *buf, int count)
+{
+	/* 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;
+}
+
+/*
+ *	Read reports the temperature in farenheit
+ */
+ 
+static int wdt_read(struct inode *inode, struct file *file, char *buf, int count)
+{
+	unsigned short c=inb_p(WDT_RT);
+	unsigned char cp;
+	int err;
+	
+	switch(MINOR(inode->i_rdev))
+	{
+		case TEMP_MINOR:
+			err=verify_area(VERIFY_WRITE, buf, 1);
+			if(err)
+				return err;
+			c*=11;
+			c/=15;
+			cp=c;
+			memcpy_tofs(buf,&cp,1);
+			return 1;
+		default:
+			return -EINVAL;
+	}
+}
+
+static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return -EINVAL;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+	switch(MINOR(inode->i_rdev))
+	{
+		case WATCHDOG_MINOR:
+			if(wdt_is_open)
+				return -EBUSY;
+			MOD_INC_USE_COUNT;
+			/*
+			 *	Activate 
+			 */
+	 
+			wdt_is_open=1;
+			inb_p(WDT_DC);		/* Disable */
+			wdt_ctr_mode(0,3);
+			wdt_ctr_mode(1,2);
+			wdt_ctr_mode(2,0);
+			wdt_ctr_load(0, 8948);		/* count at 100Hz */
+			wdt_ctr_load(1,WD_TIMO);	/* Timeout 120 seconds */
+			wdt_ctr_load(2,65535);
+			outb_p(0, WDT_DC);	/* Enable */
+			return 0;
+		case TEMP_MINOR:
+			MOD_INC_USE_COUNT;
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+static void wdt_release(struct inode *inode, struct file *file)
+{
+	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+	{
+		inb_p(WDT_DC);		/* Disable counters */
+		wdt_ctr_load(2,0);	/* 0 length reset pulses now */
+		wdt_is_open=0;
+	}
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+ 
+ 
+static struct file_operations wdt_fops = {
+	wdt_lseek,
+	wdt_read,
+	wdt_write,
+	NULL,		/* No Readdir */
+	NULL,		/* No Select */
+	wdt_ioctl,
+	NULL,		/* No mmap */
+	wdt_open,
+	wdt_release
+};
+
+static struct mouse wdt_mouse=
+{
+	WATCHDOG_MINOR,
+	"wdt",
+	&wdt_fops
+};
+
+static struct mouse temp_mouse=
+{
+	TEMP_MINOR,
+	"temperature",
+	&wdt_fops
+};
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	printk("WDT501-P module at %X(Interrupt %d)\n", io,irq);
+	if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p"))
+	{
+		printk("IRQ %d is not free.\n", irq);
+		return -EIO;
+	}
+	mouse_register(&wdt_mouse);
+#ifdef CONFIG_WDT_501	
+	mouse_register(&temp_mouse);
+#endif	
+	request_region(io, 8, "wdt501");
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	mouse_deregister(&wdt_mouse);
+#ifdef CONFIG_WDT_501	
+	mouse_deregister(&temp_mouse);
+#endif	
+	release_region(io,8);
+	free_irq(irq);
+}
+
+#else
+
+int wdt_init(void)
+{
+	printk("WDT500/501-P driver at %X(Interrupt %d)\n", io,irq);
+	if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p"))
+	{
+		printk("IRQ %d is not free.\n", irq);
+		return -EIO;
+	}
+	mouse_register(&wdt_mouse);
+	mouse_register(&temp_mouse);
+	request_region(io, 8, "wdt501");
+	return 0;
+}
+
+#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this