16365d093b3d5b5edf8ef1ed6c3eec1eff33c479
[linux-2.6.git] / drivers / watchdog / smsc37b787_wdt.c
1 /*
2  *      SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x
3  *
4  *      Based on acquirewdt.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
5  *      and some other existing drivers
6  *
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.
11  *
12  *      The authors do NOT admit liability nor provide warranty for
13  *      any of this software. This material is provided "AS-IS" in
14  *      the hope that it may be useful for others.
15  *
16  *      (C) Copyright 2003-2006  Sven Anders <anders@anduras.de>
17  *
18  *  History:
19  *      2003 - Created version 1.0 for Linux 2.4.x.
20  *      2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE
21  *             features. Released version 1.1
22  *
23  *  Theory of operation:
24  *
25  *      A Watchdog Timer (WDT) is a hardware circuit that can
26  *      reset the computer system in case of a software fault.
27  *      You probably knew that already.
28  *
29  *      Usually a userspace daemon will notify the kernel WDT driver
30  *      via the /dev/watchdog special device file that userspace is
31  *      still alive, at regular intervals.  When such a notification
32  *      occurs, the driver will usually tell the hardware watchdog
33  *      that everything is in order, and that the watchdog should wait
34  *      for yet another little while to reset the system.
35  *      If userspace fails (RAM error, kernel bug, whatever), the
36  *      notifications cease to occur, and the hardware watchdog will
37  *      reset the system (causing a reboot) after the timeout occurs.
38  *
39  * Create device with:
40  *  mknod /dev/watchdog c 10 130
41  *
42  * For an example userspace keep-alive daemon, see:
43  *   Documentation/watchdog/wdt.txt
44  */
45
46 #include <linux/module.h>
47 #include <linux/moduleparam.h>
48 #include <linux/types.h>
49 #include <linux/miscdevice.h>
50 #include <linux/watchdog.h>
51 #include <linux/delay.h>
52 #include <linux/fs.h>
53 #include <linux/ioport.h>
54 #include <linux/notifier.h>
55 #include <linux/reboot.h>
56 #include <linux/init.h>
57 #include <linux/spinlock.h>
58 #include <linux/io.h>
59 #include <linux/uaccess.h>
60
61
62 /* enable support for minutes as units? */
63 /* (does not always work correctly, so disabled by default!) */
64 #define SMSC_SUPPORT_MINUTES
65 #undef SMSC_SUPPORT_MINUTES
66
67 #define MAX_TIMEOUT     255
68
69 #define UNIT_SECOND     0
70 #define UNIT_MINUTE     1
71
72 #define MODNAME         "smsc37b787_wdt: "
73 #define VERSION         "1.1"
74
75 #define IOPORT          0x3F0
76 #define IOPORT_SIZE     2
77 #define IODEV_NO        8
78
79 static int unit = UNIT_SECOND;  /* timer's unit */
80 static int timeout = 60;        /* timeout value: default is 60 "units" */
81 static unsigned long timer_enabled;   /* is the timer enabled? */
82
83 static char expect_close;       /* is the close expected? */
84
85 static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */
86
87 static int nowayout = WATCHDOG_NOWAYOUT;
88
89 /* -- Low level function ----------------------------------------*/
90
91 /* unlock the IO chip */
92
93 static inline void open_io_config(void)
94 {
95         outb(0x55, IOPORT);
96         mdelay(1);
97         outb(0x55, IOPORT);
98 }
99
100 /* lock the IO chip */
101 static inline void close_io_config(void)
102 {
103         outb(0xAA, IOPORT);
104 }
105
106 /* select the IO device */
107 static inline void select_io_device(unsigned char devno)
108 {
109         outb(0x07, IOPORT);
110         outb(devno, IOPORT+1);
111 }
112
113 /* write to the control register */
114 static inline void write_io_cr(unsigned char reg, unsigned char data)
115 {
116         outb(reg, IOPORT);
117         outb(data, IOPORT+1);
118 }
119
120 /* read from the control register */
121 static inline char read_io_cr(unsigned char reg)
122 {
123         outb(reg, IOPORT);
124         return inb(IOPORT+1);
125 }
126
127 /* -- Medium level functions ------------------------------------*/
128
129 static inline void gpio_bit12(unsigned char reg)
130 {
131         /* -- General Purpose I/O Bit 1.2 --
132          * Bit 0,   In/Out: 0 = Output, 1 = Input
133          * Bit 1,   Polarity: 0 = No Invert, 1 = Invert
134          * Bit 2,   Group Enable Intr.: 0 = Disable, 1 = Enable
135          * Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
136          *                           11 = Either Edge Triggered Intr. 2
137          * Bit 5/6  (Reserved)
138          * Bit 7,   Output Type: 0 = Push Pull Bit, 1 = Open Drain
139          */
140         write_io_cr(0xE2, reg);
141 }
142
143 static inline void gpio_bit13(unsigned char reg)
144 {
145         /* -- General Purpose I/O Bit 1.3 --
146          * Bit 0,  In/Out: 0 = Output, 1 = Input
147          * Bit 1,  Polarity: 0 = No Invert, 1 = Invert
148          * Bit 2,  Group Enable Intr.: 0 = Disable, 1 = Enable
149          * Bit 3,  Function select: 0 = GPI/O, 1 = LED
150          * Bit 4-6 (Reserved)
151          * Bit 7,  Output Type: 0 = Push Pull Bit, 1 = Open Drain
152          */
153         write_io_cr(0xE3, reg);
154 }
155
156 static inline void wdt_timer_units(unsigned char new_units)
157 {
158         /* -- Watchdog timer units --
159          * Bit 0-6 (Reserved)
160          * Bit 7,  WDT Time-out Value Units Select
161          *         (0 = Minutes, 1 = Seconds)
162          */
163         write_io_cr(0xF1, new_units);
164 }
165
166 static inline void wdt_timeout_value(unsigned char new_timeout)
167 {
168         /* -- Watchdog Timer Time-out Value --
169          * Bit 0-7 Binary coded units (0=Disabled, 1..255)
170          */
171         write_io_cr(0xF2, new_timeout);
172 }
173
174 static inline void wdt_timer_conf(unsigned char conf)
175 {
176         /* -- Watchdog timer configuration --
177          * Bit 0   Joystick enable: 0* = No Reset, 1 = Reset WDT upon
178          *                                                      Gameport I/O
179          * Bit 1   Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
180          * Bit 2   Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr
181          * Bit 3   Reset the timer
182          *         (Wrong in SMsC documentation? Given as: PowerLED Timout
183          *                                                      Enabled)
184          * Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,
185          *            0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)
186          */
187         write_io_cr(0xF3, conf);
188 }
189
190 static inline void wdt_timer_ctrl(unsigned char reg)
191 {
192         /* -- Watchdog timer control --
193          * Bit 0   Status Bit: 0 = Timer counting, 1 = Timeout occurred
194          * Bit 1   Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz
195          * Bit 2   Force Timeout: 1 = Forces WD timeout event (self-cleaning)
196          * Bit 3   P20 Force Timeout enabled:
197          *          0 = P20 activity does not generate the WD timeout event
198          *          1 = P20 Allows rising edge of P20, from the keyboard
199          *              controller, to force the WD timeout event.
200          * Bit 4   (Reserved)
201          * -- Soft power management --
202          * Bit 5   Stop Counter: 1 = Stop software power down counter
203          *            set via register 0xB8, (self-cleaning)
204          *            (Upon read: 0 = Counter running, 1 = Counter stopped)
205          * Bit 6   Restart Counter: 1 = Restart software power down counter
206          *            set via register 0xB8, (self-cleaning)
207          * Bit 7   SPOFF: 1 = Force software power down (self-cleaning)
208          */
209         write_io_cr(0xF4, reg);
210 }
211
212 /* -- Higher level functions ------------------------------------*/
213
214 /* initialize watchdog */
215
216 static void wb_smsc_wdt_initialize(void)
217 {
218         unsigned char old;
219
220         spin_lock(&io_lock);
221         open_io_config();
222         select_io_device(IODEV_NO);
223
224         /* enable the watchdog */
225         gpio_bit13(0x08);  /* Select pin 80 = LED not GPIO */
226         gpio_bit12(0x0A);  /* Set pin 79 = WDT not
227                               GPIO/Output/Polarity=Invert */
228         /* disable the timeout */
229         wdt_timeout_value(0);
230
231         /* reset control register */
232         wdt_timer_ctrl(0x00);
233
234         /* reset configuration register */
235         wdt_timer_conf(0x00);
236
237         /* read old (timer units) register */
238         old = read_io_cr(0xF1) & 0x7F;
239         if (unit == UNIT_SECOND)
240                 old |= 0x80;    /* set to seconds */
241
242         /* set the watchdog timer units */
243         wdt_timer_units(old);
244
245         close_io_config();
246         spin_unlock(&io_lock);
247 }
248
249 /* shutdown the watchdog */
250
251 static void wb_smsc_wdt_shutdown(void)
252 {
253         spin_lock(&io_lock);
254         open_io_config();
255         select_io_device(IODEV_NO);
256
257         /* disable the watchdog */
258         gpio_bit13(0x09);
259         gpio_bit12(0x09);
260
261         /* reset watchdog config register */
262         wdt_timer_conf(0x00);
263
264         /* reset watchdog control register */
265         wdt_timer_ctrl(0x00);
266
267         /* disable timeout */
268         wdt_timeout_value(0x00);
269
270         close_io_config();
271         spin_unlock(&io_lock);
272 }
273
274 /* set timeout => enable watchdog */
275
276 static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
277 {
278         spin_lock(&io_lock);
279         open_io_config();
280         select_io_device(IODEV_NO);
281
282         /* set Power LED to blink, if we enable the timeout */
283         wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
284
285         /* set timeout value */
286         wdt_timeout_value(new_timeout);
287
288         close_io_config();
289         spin_unlock(&io_lock);
290 }
291
292 /* get timeout */
293
294 static unsigned char wb_smsc_wdt_get_timeout(void)
295 {
296         unsigned char set_timeout;
297
298         spin_lock(&io_lock);
299         open_io_config();
300         select_io_device(IODEV_NO);
301         set_timeout = read_io_cr(0xF2);
302         close_io_config();
303         spin_unlock(&io_lock);
304
305         return set_timeout;
306 }
307
308 /* disable watchdog */
309
310 static void wb_smsc_wdt_disable(void)
311 {
312         /* set the timeout to 0 to disable the watchdog */
313         wb_smsc_wdt_set_timeout(0);
314 }
315
316 /* enable watchdog by setting the current timeout */
317
318 static void wb_smsc_wdt_enable(void)
319 {
320         /* set the current timeout... */
321         wb_smsc_wdt_set_timeout(timeout);
322 }
323
324 /* reset the timer */
325
326 static void wb_smsc_wdt_reset_timer(void)
327 {
328         spin_lock(&io_lock);
329         open_io_config();
330         select_io_device(IODEV_NO);
331
332         /* reset the timer */
333         wdt_timeout_value(timeout);
334         wdt_timer_conf(0x08);
335
336         close_io_config();
337         spin_unlock(&io_lock);
338 }
339
340 /* return, if the watchdog is enabled (timeout is set...) */
341
342 static int wb_smsc_wdt_status(void)
343 {
344         return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING;
345 }
346
347
348 /* -- File operations -------------------------------------------*/
349
350 /* open => enable watchdog and set initial timeout */
351
352 static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
353 {
354         /* /dev/watchdog can only be opened once */
355
356         if (test_and_set_bit(0, &timer_enabled))
357                 return -EBUSY;
358
359         if (nowayout)
360                 __module_get(THIS_MODULE);
361
362         /* Reload and activate timer */
363         wb_smsc_wdt_enable();
364
365         printk(KERN_INFO MODNAME
366                 "Watchdog enabled. Timeout set to %d %s.\n",
367                 timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
368
369         return nonseekable_open(inode, file);
370 }
371
372 /* close => shut off the timer */
373
374 static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
375 {
376         /* Shut off the timer. */
377
378         if (expect_close == 42) {
379                 wb_smsc_wdt_disable();
380                 printk(KERN_INFO MODNAME
381                                 "Watchdog disabled, sleeping again...\n");
382         } else {
383                 printk(KERN_CRIT MODNAME
384                                 "Unexpected close, not stopping watchdog!\n");
385                 wb_smsc_wdt_reset_timer();
386         }
387
388         clear_bit(0, &timer_enabled);
389         expect_close = 0;
390         return 0;
391 }
392
393 /* write => update the timer to keep the machine alive */
394
395 static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
396                                  size_t len, loff_t *ppos)
397 {
398         /* See if we got the magic character 'V' and reload the timer */
399         if (len) {
400                 if (!nowayout) {
401                         size_t i;
402
403                         /* reset expect flag */
404                         expect_close = 0;
405
406                         /* scan to see whether or not we got the
407                            magic character */
408                         for (i = 0; i != len; i++) {
409                                 char c;
410                                 if (get_user(c, data + i))
411                                         return -EFAULT;
412                                 if (c == 'V')
413                                         expect_close = 42;
414                         }
415                 }
416
417                 /* someone wrote to us, we should reload the timer */
418                 wb_smsc_wdt_reset_timer();
419         }
420         return len;
421 }
422
423 /* ioctl => control interface */
424
425 static long wb_smsc_wdt_ioctl(struct file *file,
426                                         unsigned int cmd, unsigned long arg)
427 {
428         int new_timeout;
429
430         union {
431                 struct watchdog_info __user *ident;
432                 int __user *i;
433         } uarg;
434
435         static const struct watchdog_info ident = {
436                 .options =              WDIOF_KEEPALIVEPING |
437                                         WDIOF_SETTIMEOUT |
438                                         WDIOF_MAGICCLOSE,
439                 .firmware_version =     0,
440                 .identity =             "SMsC 37B787 Watchdog",
441         };
442
443         uarg.i = (int __user *)arg;
444
445         switch (cmd) {
446         case WDIOC_GETSUPPORT:
447                 return copy_to_user(uarg.ident, &ident, sizeof(ident))
448                                                                 ? -EFAULT : 0;
449         case WDIOC_GETSTATUS:
450                 return put_user(wb_smsc_wdt_status(), uarg.i);
451         case WDIOC_GETBOOTSTATUS:
452                 return put_user(0, uarg.i);
453         case WDIOC_SETOPTIONS:
454         {
455                 int options, retval = -EINVAL;
456
457                 if (get_user(options, uarg.i))
458                         return -EFAULT;
459
460                 if (options & WDIOS_DISABLECARD) {
461                         wb_smsc_wdt_disable();
462                         retval = 0;
463                 }
464                 if (options & WDIOS_ENABLECARD) {
465                         wb_smsc_wdt_enable();
466                         retval = 0;
467                 }
468                 return retval;
469         }
470         case WDIOC_KEEPALIVE:
471                 wb_smsc_wdt_reset_timer();
472                 return 0;
473         case WDIOC_SETTIMEOUT:
474                 if (get_user(new_timeout, uarg.i))
475                         return -EFAULT;
476                 /* the API states this is given in secs */
477                 if (unit == UNIT_MINUTE)
478                         new_timeout /= 60;
479                 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
480                         return -EINVAL;
481                 timeout = new_timeout;
482                 wb_smsc_wdt_set_timeout(timeout);
483                 /* fall through and return the new timeout... */
484         case WDIOC_GETTIMEOUT:
485                 new_timeout = timeout;
486                 if (unit == UNIT_MINUTE)
487                         new_timeout *= 60;
488                 return put_user(new_timeout, uarg.i);
489         default:
490                 return -ENOTTY;
491         }
492 }
493
494 /* -- Notifier funtions -----------------------------------------*/
495
496 static int wb_smsc_wdt_notify_sys(struct notifier_block *this,
497                                         unsigned long code, void *unused)
498 {
499         if (code == SYS_DOWN || code == SYS_HALT) {
500                 /* set timeout to 0, to avoid possible race-condition */
501                 timeout = 0;
502                 wb_smsc_wdt_disable();
503         }
504         return NOTIFY_DONE;
505 }
506
507 /* -- Module's structures ---------------------------------------*/
508
509 static const struct file_operations wb_smsc_wdt_fops = {
510         .owner    = THIS_MODULE,
511         .llseek         = no_llseek,
512         .write          = wb_smsc_wdt_write,
513         .unlocked_ioctl = wb_smsc_wdt_ioctl,
514         .open           = wb_smsc_wdt_open,
515         .release        = wb_smsc_wdt_release,
516 };
517
518 static struct notifier_block wb_smsc_wdt_notifier = {
519         .notifier_call  = wb_smsc_wdt_notify_sys,
520 };
521
522 static struct miscdevice wb_smsc_wdt_miscdev = {
523         .minor          = WATCHDOG_MINOR,
524         .name           = "watchdog",
525         .fops           = &wb_smsc_wdt_fops,
526 };
527
528 /* -- Module init functions -------------------------------------*/
529
530 /* module's "constructor" */
531
532 static int __init wb_smsc_wdt_init(void)
533 {
534         int ret;
535
536         printk(KERN_INFO "SMsC 37B787 watchdog component driver "
537                                         VERSION " initialising...\n");
538
539         if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
540                 printk(KERN_ERR MODNAME "Unable to register IO port %#x\n",
541                                                                 IOPORT);
542                 ret = -EBUSY;
543                 goto out_pnp;
544         }
545
546         /* set new maximum, if it's too big */
547         if (timeout > MAX_TIMEOUT)
548                 timeout = MAX_TIMEOUT;
549
550         /* init the watchdog timer */
551         wb_smsc_wdt_initialize();
552
553         ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
554         if (ret) {
555                 printk(KERN_ERR MODNAME
556                         "Unable to register reboot notifier err = %d\n", ret);
557                 goto out_io;
558         }
559
560         ret = misc_register(&wb_smsc_wdt_miscdev);
561         if (ret) {
562                 printk(KERN_ERR MODNAME
563                         "Unable to register miscdev on minor %d\n",
564                                                         WATCHDOG_MINOR);
565                 goto out_rbt;
566         }
567
568         /* output info */
569         printk(KERN_INFO MODNAME "Timeout set to %d %s.\n",
570                 timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
571         printk(KERN_INFO MODNAME
572                 "Watchdog initialized and sleeping (nowayout=%d)...\n",
573                                                                 nowayout);
574 out_clean:
575         return ret;
576
577 out_rbt:
578         unregister_reboot_notifier(&wb_smsc_wdt_notifier);
579
580 out_io:
581         release_region(IOPORT, IOPORT_SIZE);
582
583 out_pnp:
584         goto out_clean;
585 }
586
587 /* module's "destructor" */
588
589 static void __exit wb_smsc_wdt_exit(void)
590 {
591         /* Stop the timer before we leave */
592         if (!nowayout) {
593                 wb_smsc_wdt_shutdown();
594                 printk(KERN_INFO MODNAME "Watchdog disabled.\n");
595         }
596
597         misc_deregister(&wb_smsc_wdt_miscdev);
598         unregister_reboot_notifier(&wb_smsc_wdt_notifier);
599         release_region(IOPORT, IOPORT_SIZE);
600
601         printk(KERN_INFO "SMsC 37B787 watchdog component driver removed.\n");
602 }
603
604 module_init(wb_smsc_wdt_init);
605 module_exit(wb_smsc_wdt_exit);
606
607 MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
608 MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version "
609                                                                 VERSION ")");
610 MODULE_LICENSE("GPL");
611
612 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
613
614 #ifdef SMSC_SUPPORT_MINUTES
615 module_param(unit, int, 0);
616 MODULE_PARM_DESC(unit,
617                 "set unit to use, 0=seconds or 1=minutes, default is 0");
618 #endif
619
620 module_param(timeout, int, 0);
621 MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
622
623 module_param(nowayout, int, 0);
624 MODULE_PARM_DESC(nowayout,
625                 "Watchdog cannot be stopped once started (default="
626                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");