Import 2.1.118
[davej-history.git] / drivers / char / wdt.c
bloba42c35fe3b0f2b7368986ddc9a1da3e2c924474f
1 /*
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.
5 * http://www.cymru.net
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>
18 * Release 0.07.
20 * Fixes
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
24 * Matt Crocker).
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>
37 #include "wd501p.h"
38 #include <linux/malloc.h>
39 #include <linux/ioport.h>
40 #include <linux/fcntl.h>
41 #include <asm/io.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.
55 static int io=0x240;
56 static int irq=11;
58 #define WD_TIMO (100*60) /* 1 minute */
61 * Setup options
64 __initfunc(void wdt_setup(char *str, int *ints))
66 if(ints[0]>0)
68 io=ints[1];
69 if(ints[0]>1)
70 irq=ints[2];
75 * Programming support
78 static void wdt_ctr_mode(int ctr, int mode)
80 ctr<<=6;
81 ctr|=0x30;
82 ctr|=(mode<<1);
83 outb_p(ctr, WDT_CR);
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);
93 * Kernel methods.
96 static int wdt_status(void)
99 * Status register to bit flags
102 int flag=0;
103 unsigned char status=inb_p(WDT_SR);
104 status|=FEATUREMAP1;
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)
116 flag|=WDIOF_EXTERN1;
117 if(status&WDC_SR_ISII1)
118 flag|=WDIOF_EXTERN2;
119 return flag;
122 void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
125 * Read the status register see what is up and
126 * then printk it.
129 unsigned char status=inb_p(WDT_SR);
131 status|=FEATUREMAP1;
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
146 #ifdef ONLY_TESTING
147 printk(KERN_CRIT "Would Reboot.\n");
148 #else
149 printk(KERN_CRIT "Initiating system reboot.\n");
150 machine_restart(NULL);
151 #endif
152 #else
153 printk(KERN_CRIT "Reset in 5ms.\n");
154 #endif
158 static long long wdt_llseek(struct file *file, long long offset, int origin)
160 return -ESPIPE;
163 static void wdt_ping(void)
165 /* Write a watchdog value */
166 inb_p(WDT_DC);
167 wdt_ctr_mode(1,2);
168 wdt_ctr_load(1,WD_TIMO); /* Timeout */
169 outb_p(0, WDT_DC);
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)
176 return -ESPIPE;
178 if(count)
180 wdt_ping();
181 return 1;
183 return 0;
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);
193 unsigned char cp;
194 int err;
196 /* Can't seek (pread) on this device */
197 if (ptr != &file->f_pos)
198 return -ESPIPE;
200 switch(MINOR(file->f_dentry->d_inode->i_rdev))
202 case TEMP_MINOR:
203 err=verify_area(VERIFY_WRITE, buf, 1);
204 if(err)
205 return err;
206 c*=11;
207 c/=15;
208 cp=c+7;
209 copy_to_user(buf,&cp,1);
210 return 1;
211 default:
212 return -EINVAL;
216 static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
217 unsigned long arg)
219 int i;
220 static struct watchdog_info ident=
222 WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
223 |WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT,
225 "WDT500/501"
228 ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */
229 switch(cmd)
231 default:
232 return -ENOIOCTLCMD;
233 case WDIOC_GETSUPPORT:
234 i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info));
235 if (i)
236 return i;
237 else
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));
242 if (i)
243 return i;
244 else
246 return put_user(wdt_status(),(int *)arg);
248 case WDIOC_GETBOOTSTATUS:
249 return put_user(0, (int *)arg);
250 case WDIOC_KEEPALIVE:
251 wdt_ping();
252 return 0;
256 static int wdt_open(struct inode *inode, struct file *file)
258 switch(MINOR(inode->i_rdev))
260 case WATCHDOG_MINOR:
261 if(wdt_is_open)
262 return -EBUSY;
263 MOD_INC_USE_COUNT;
265 * Activate
268 wdt_is_open=1;
269 inb_p(WDT_DC); /* Disable */
270 wdt_ctr_mode(0,3);
271 wdt_ctr_mode(1,2);
272 wdt_ctr_mode(2,0);
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 */
277 return 0;
278 case TEMP_MINOR:
279 MOD_INC_USE_COUNT;
280 return 0;
281 default:
282 return -ENODEV;
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 */
293 #endif
294 wdt_is_open=0;
296 MOD_DEC_USE_COUNT;
297 return 0;
301 * Notifier for system down
304 static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
305 void *unused)
307 if(code==SYS_DOWN || code==SYS_HALT)
309 /* Turn the card off */
310 inb_p(WDT_DC);
311 wdt_ctr_load(2,0);
313 return NOTIFY_DONE;
317 * Kernel Interfaces
321 static struct file_operations wdt_fops = {
322 wdt_llseek,
323 wdt_read,
324 wdt_write,
325 NULL, /* No Readdir */
326 NULL, /* No Select */
327 wdt_ioctl,
328 NULL, /* No mmap */
329 wdt_open,
330 NULL, /* flush */
331 wdt_release
334 static struct miscdevice wdt_miscdev=
336 WATCHDOG_MINOR,
337 "watchdog",
338 &wdt_fops
341 #ifdef CONFIG_WDT_501
342 static struct miscdevice temp_miscdev=
344 TEMP_MINOR,
345 "temperature",
346 &wdt_fops
348 #endif
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=
357 wdt_notify_sys,
358 NULL,
362 #ifdef MODULE
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);
371 #endif
372 unregister_reboot_notifier(&wdt_notifier);
373 release_region(io,8);
374 free_irq(irq, NULL);
377 #endif
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);
385 return -EIO;
387 misc_register(&wdt_miscdev);
388 #ifdef CONFIG_WDT_501
389 misc_register(&temp_miscdev);
390 #endif
391 request_region(io, 8, "wdt501p");
392 register_reboot_notifier(&wdt_notifier);
393 return 0;