]> git.hungrycats.org Git - linux/commitdiff
[WATCHDOG] v2.6.2 indydog-v0.3_update
authorWim Van Sebroeck <wim@iguana.be>
Wed, 11 Feb 2004 22:01:53 +0000 (23:01 +0100)
committerLinus Torvalds <torvalds@home.osdl.org>
Wed, 11 Feb 2004 22:01:53 +0000 (23:01 +0100)
Added notifier support
Moved start and stop code to their own subroutines
Extended ioctl support
Add MODULE_* info

drivers/char/watchdog/indydog.c

index 3ebcfa0204d4d07fc8bfb9c4a1d9a40f2478bada..42363f353e71c2bac3bb139d55d7dff162378a19 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     IndyDog 0.2     A Hardware Watchdog Device for SGI IP22
+ *     IndyDog 0.3     A Hardware Watchdog Device for SGI IP22
  *
  *     (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
  *
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <asm/uaccess.h>
 #include <asm/sgi/sgimc.h>
 
+#define PFX "indydog: "
+#define WATCHDOG_HEARTBEAT 60
+
 static unsigned long indydog_alive;
 static struct sgimc_misc_ctrl *mcmisc_regs;
 static char expect_close;
@@ -37,11 +42,30 @@ static int nowayout = 0;
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
-static void indydog_ping()
+static void indydog_start(void)
 {
-       mcmisc_regs->watchdogt = 0;
+       u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
+
+       mc_ctrl0 |= SGIMC_CCTRL0_WDOG;
+       mcmisc_regs->cpuctrl0 = mc_ctrl0;
+
+       printk(KERN_INFO PFX "Started watchdog timer.\n");
 }
 
+static void indydog_stop(void)
+{
+       u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
+
+       mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
+       mcmisc_regs->cpuctrl0 = mc_ctrl0;
+
+       printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+}
+
+static void indydog_ping(void)
+{
+       mcmisc_regs->watchdogt = 0;
+}
 
 /*
  *     Allow only one person to hold it open
@@ -49,8 +73,6 @@ static void indydog_ping()
 
 static int indydog_open(struct inode *inode, struct file *file)
 {
-       u32 mc_ctrl0;
-
        if( test_and_set_bit(0,&indydog_alive) )
                return -EBUSY;
 
@@ -60,13 +82,9 @@ static int indydog_open(struct inode *inode, struct file *file)
        /*
         *      Activate timer
         */
-       mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
-
-       mc_ctrl0 = mcmisc_regs->cpuctrl0 | SGIMC_CCTRL0_WDOG;
-       mcmisc_regs->cpuctrl0 = mc_ctrl0;
+       indydog_start();
        indydog_ping();
 
-       printk("Started watchdog timer.\n");
        return 0;
 }
 
@@ -78,12 +96,10 @@ static int indydog_release(struct inode *inode, struct file *file)
         */
 
        if (expect_close == 42) {
-               u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
-               mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
-               mcmisc_regs->cpuctrl0 = mc_ctrl0;
-               printk("Stopped watchdog timer.\n");
+               indydog_stop();
        } else {
-               printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+               printk(KERN_CRIT PFX "WDT device closed unexpectedly.  WDT will not stop!\n");
+               indydog_ping();
        }
        clear_bit(0,&indydog_alive);
        expect_close = 0;
@@ -121,9 +137,12 @@ static ssize_t indydog_write(struct file *file, const char *data, size_t len, lo
 static int indydog_ioctl(struct inode *inode, struct file *file,
        unsigned int cmd, unsigned long arg)
 {
+       int options, retval = -EINVAL;
        static struct watchdog_info ident = {
-               .options = WDIOF_MAGICCLOSE,
-               .identity = "Hardware Watchdog for SGI IP22",
+               .options =              WDIOF_KEEPALIVEPING |
+                                       WDIOF_MAGICCLOSE,
+               .firmware_version =     0,
+               .identity =             "Hardware Watchdog for SGI IP22",
        };
 
        switch (cmd) {
@@ -139,9 +158,40 @@ static int indydog_ioctl(struct inode *inode, struct file *file,
                case WDIOC_KEEPALIVE:
                        indydog_ping();
                        return 0;
+               case WDIOC_GETTIMEOUT:
+                       return put_user(WATCHDOG_TIMEOUT,(int *)arg);
+               case WDIOC_SETOPTIONS:
+               {
+                       if (get_user(options, (int *)arg))
+                               return -EFAULT;
+
+                       if (options & WDIOS_DISABLECARD)
+                       {
+                               indydog_stop();
+                               retval = 0;
+                       }
+
+                       if (options & WDIOS_ENABLECARD)
+                       {
+                               indydog_start();
+                               retval = 0;
+                       }
+
+                       return retval;
+               }
        }
 }
 
+static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+       if (code==SYS_DOWN || code==SYS_HALT) {
+               /* Turn the WDT off */
+               indydog_stop();
+       }
+
+       return NOTIFY_DONE;
+}
+
 static struct file_operations indydog_fops = {
        .owner  = THIS_MODULE,
        .write  = indydog_write,
@@ -156,16 +206,32 @@ static struct miscdevice indydog_miscdev = {
        .fops   = &indydog_fops,
 };
 
-static char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n";
+static struct notifier_block indydog_notifier = {
+       .notifier_call = indydog_notify_sys,
+};
+
+static char banner[] __initdata = KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
 
 static int __init watchdog_init(void)
 {
        int ret;
 
-       ret = misc_register(&indydog_miscdev);
+       mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
+
+       ret = register_reboot_notifier(&indydog_notifier);
+       if (ret) {
+               printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+                       ret);
+               return ret;
+       }
 
-       if (ret)
+       ret = misc_register(&indydog_miscdev);
+       if (ret) {
+               printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+                       WATCHDOG_MINOR, ret);
+               unregister_reboot_notifier(&indydog_notifier);
                return ret;
+       }
 
        printk(banner);
 
@@ -175,8 +241,13 @@ static int __init watchdog_init(void)
 static void __exit watchdog_exit(void)
 {
        misc_deregister(&indydog_miscdev);
+       unregister_reboot_notifier(&indydog_notifier);
 }
 
 module_init(watchdog_init);
 module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
+MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);