2 * Industrial Computer Source WDT500/501 driver for Linux 2.1.x
4 * (c) Copyright 1996-1997 Alan Cox <alan@cymru.net>, All Rights Reserved.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
12 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
16 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
21 * Dave Gregorich : Modularisation and minor bugs
22 * Alan Cox : Added the watchdog ioctl() stuff
23 * Alan Cox : Fixed the reboot problem (as noted by
25 * Alan Cox : Added wdt= boot option
28 #include <linux/config.h>
29 #include <linux/module.h>
30 #include <linux/version.h>
31 #include <linux/types.h>
32 #include <linux/errno.h>
33 #include <linux/kernel.h>
34 #include <linux/sched.h>
35 #include <linux/miscdevice.h>
36 #include <linux/watchdog.h>
38 #include <linux/malloc.h>
39 #include <linux/ioport.h>
40 #include <linux/fcntl.h>
42 #include <asm/uaccess.h>
43 #include <asm/system.h>
44 #include <linux/notifier.h>
45 #include <linux/reboot.h>
46 #include <linux/init.h>
48 static int wdt_is_open
=0;
51 * You must set these - there is no sane way to probe for this board.
52 * You can use wdt=x,y to set these now.
58 #define WD_TIMO (100*60) /* 1 minute */
64 __initfunc(void wdt_setup(char *str
, int *ints
))
78 static void wdt_ctr_mode(int ctr
, int mode
)
86 static void wdt_ctr_load(int ctr
, int val
)
88 outb_p(val
&0xFF, WDT_COUNT0
+ctr
);
89 outb_p(val
>>8, WDT_COUNT0
+ctr
);
96 static int wdt_status(void)
99 * Status register to bit flags
103 unsigned char status
=inb_p(WDT_SR
);
105 status
&=~FEATUREMAP2
;
107 if(!(status
&WDC_SR_TGOOD
))
108 flag
|=WDIOF_OVERHEAT
;
109 if(!(status
&WDC_SR_PSUOVER
))
110 flag
|=WDIOF_POWEROVER
;
111 if(!(status
&WDC_SR_PSUUNDR
))
112 flag
|=WDIOF_POWERUNDER
;
113 if(!(status
&WDC_SR_FANGOOD
))
114 flag
|=WDIOF_FANFAULT
;
115 if(status
&WDC_SR_ISOI0
)
117 if(status
&WDC_SR_ISII1
)
122 void wdt_interrupt(int irq
, void *dev_id
, struct pt_regs
*regs
)
125 * Read the status register see what is up and
129 unsigned char status
=inb_p(WDT_SR
);
132 status
&=~FEATUREMAP2
;
134 printk(KERN_CRIT
"WDT status %d\n", status
);
136 if(!(status
&WDC_SR_TGOOD
))
137 printk(KERN_CRIT
"Overheat alarm.(%d)\n",inb_p(WDT_RT
));
138 if(!(status
&WDC_SR_PSUOVER
))
139 printk(KERN_CRIT
"PSU over voltage.\n");
140 if(!(status
&WDC_SR_PSUUNDR
))
141 printk(KERN_CRIT
"PSU under voltage.\n");
142 if(!(status
&WDC_SR_FANGOOD
))
143 printk(KERN_CRIT
"Possible fan fault.\n");
144 if(!(status
&WDC_SR_WCCR
))
145 #ifdef SOFTWARE_REBOOT
147 printk(KERN_CRIT
"Would Reboot.\n");
149 printk(KERN_CRIT
"Initiating system reboot.\n");
150 machine_restart(NULL
);
153 printk(KERN_CRIT
"Reset in 5ms.\n");
158 static long long wdt_llseek(struct file
*file
, long long offset
, int origin
)
163 static void wdt_ping(void)
165 /* Write a watchdog value */
168 wdt_ctr_load(1,WD_TIMO
); /* Timeout */
172 static ssize_t
wdt_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
174 /* Can't seek (pwrite) on this device */
175 if (ppos
!= &file
->f_pos
)
187 * Read reports the temperature in degrees Fahrenheit.
190 static ssize_t
wdt_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ptr
)
192 unsigned short c
=inb_p(WDT_RT
);
196 /* Can't seek (pread) on this device */
197 if (ptr
!= &file
->f_pos
)
200 switch(MINOR(file
->f_dentry
->d_inode
->i_rdev
))
203 err
=verify_area(VERIFY_WRITE
, buf
, 1);
209 copy_to_user(buf
,&cp
,1);
216 static int wdt_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
220 static struct watchdog_info ident
=
222 WDIOF_OVERHEAT
|WDIOF_POWERUNDER
|WDIOF_POWEROVER
223 |WDIOF_EXTERN1
|WDIOF_EXTERN2
|WDIOF_FANFAULT
,
228 ident
.options
&=WDT_OPTION_MASK
; /* Mask down to the card we have */
233 case WDIOC_GETSUPPORT
:
234 i
= verify_area(VERIFY_WRITE
, (void*) arg
, sizeof(struct watchdog_info
));
238 return copy_to_user((struct watchdog_info
*)arg
, &ident
, sizeof(ident
));
240 case WDIOC_GETSTATUS
:
241 i
= verify_area(VERIFY_WRITE
, (void*) arg
, sizeof(int));
246 return put_user(wdt_status(),(int *)arg
);
248 case WDIOC_GETBOOTSTATUS
:
249 return put_user(0, (int *)arg
);
250 case WDIOC_KEEPALIVE
:
256 static int wdt_open(struct inode
*inode
, struct file
*file
)
258 switch(MINOR(inode
->i_rdev
))
269 inb_p(WDT_DC
); /* Disable */
273 wdt_ctr_load(0, 8948); /* count at 100Hz */
274 wdt_ctr_load(1,WD_TIMO
); /* Timeout 120 seconds */
275 wdt_ctr_load(2,65535);
276 outb_p(0, WDT_DC
); /* Enable */
286 static int wdt_release(struct inode
*inode
, struct file
*file
)
288 if(MINOR(inode
->i_rdev
)==WATCHDOG_MINOR
)
290 #ifndef CONFIG_WATCHDOG_NOWAYOUT
291 inb_p(WDT_DC
); /* Disable counters */
292 wdt_ctr_load(2,0); /* 0 length reset pulses now */
301 * Notifier for system down
304 static int wdt_notify_sys(struct notifier_block
*this, unsigned long code
,
307 if(code
==SYS_DOWN
|| code
==SYS_HALT
)
309 /* Turn the card off */
321 static struct file_operations wdt_fops
= {
325 NULL
, /* No Readdir */
326 NULL
, /* No Select */
334 static struct miscdevice wdt_miscdev
=
341 #ifdef CONFIG_WDT_501
342 static struct miscdevice temp_miscdev
=
351 * The WDT card needs to learn about soft shutdowns in order to
352 * turn the timebomb registers off.
355 static struct notifier_block wdt_notifier
=
364 #define wdt_init init_module
366 void cleanup_module(void)
368 misc_deregister(&wdt_miscdev
);
369 #ifdef CONFIG_WDT_501
370 misc_deregister(&temp_miscdev
);
372 unregister_reboot_notifier(&wdt_notifier
);
373 release_region(io
,8);
379 __initfunc(int wdt_init(void))
381 printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io
,irq
);
382 if(request_irq(irq
, wdt_interrupt
, SA_INTERRUPT
, "wdt501p", NULL
))
384 printk("IRQ %d is not free.\n", irq
);
387 misc_register(&wdt_miscdev
);
388 #ifdef CONFIG_WDT_501
389 misc_register(&temp_miscdev
);
391 request_region(io
, 8, "wdt501p");
392 register_reboot_notifier(&wdt_notifier
);