linux/arch/um/drivers/harddog_kern.c
<<
>>
Prefs
   1/* UML hardware watchdog, shamelessly stolen from:
   2 *
   3 *      SoftDog 0.05:   A Software Watchdog Device
   4 *
   5 *      (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
   6 *                              http://www.redhat.com
   7 *
   8 *      This program is free software; you can redistribute it and/or
   9 *      modify it under the terms of the GNU General Public License
  10 *      as published by the Free Software Foundation; either version
  11 *      2 of the License, or (at your option) any later version.
  12 *
  13 *      Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  14 *      warranty for any of this software. This material is provided
  15 *      "AS-IS" and at no charge.
  16 *
  17 *      (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  18 *
  19 *      Software only watchdog driver. Unlike its big brother the WDT501P
  20 *      driver this won't always recover a failed machine.
  21 *
  22 *  03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
  23 *      Modularised.
  24 *      Added soft_margin; use upon insmod to change the timer delay.
  25 *      NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
  26 *          minors.
  27 *
  28 *  19980911 Alan Cox
  29 *      Made SMP safe for 2.3.x
  30 *
  31 *  20011127 Joel Becker (jlbec@evilplan.org>
  32 *      Added soft_noboot; Allows testing the softdog trigger without
  33 *      requiring a recompile.
  34 *      Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
  35 */
  36
  37#include <linux/module.h>
  38#include <linux/types.h>
  39#include <linux/kernel.h>
  40#include <linux/fs.h>
  41#include <linux/mm.h>
  42#include <linux/miscdevice.h>
  43#include <linux/watchdog.h>
  44#include <linux/reboot.h>
  45#include <linux/smp_lock.h>
  46#include <linux/init.h>
  47#include <linux/spinlock.h>
  48#include <asm/uaccess.h>
  49#include "mconsole.h"
  50
  51MODULE_LICENSE("GPL");
  52
  53static DEFINE_SPINLOCK(lock);
  54static int timer_alive;
  55static int harddog_in_fd = -1;
  56static int harddog_out_fd = -1;
  57
  58/*
  59 *      Allow only one person to hold it open
  60 */
  61
  62extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock);
  63
  64static int harddog_open(struct inode *inode, struct file *file)
  65{
  66        int err = -EBUSY;
  67        char *sock = NULL;
  68
  69        lock_kernel();
  70        spin_lock(&lock);
  71        if(timer_alive)
  72                goto err;
  73#ifdef CONFIG_WATCHDOG_NOWAYOUT
  74        __module_get(THIS_MODULE);
  75#endif
  76
  77#ifdef CONFIG_MCONSOLE
  78        sock = mconsole_notify_socket();
  79#endif
  80        err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
  81        if(err)
  82                goto err;
  83
  84        timer_alive = 1;
  85        spin_unlock(&lock);
  86        unlock_kernel();
  87        return nonseekable_open(inode, file);
  88err:
  89        spin_unlock(&lock);
  90        unlock_kernel();
  91        return err;
  92}
  93
  94extern void stop_watchdog(int in_fd, int out_fd);
  95
  96static int harddog_release(struct inode *inode, struct file *file)
  97{
  98        /*
  99         *      Shut off the timer.
 100         */
 101
 102        spin_lock(&lock);
 103
 104        stop_watchdog(harddog_in_fd, harddog_out_fd);
 105        harddog_in_fd = -1;
 106        harddog_out_fd = -1;
 107
 108        timer_alive=0;
 109        spin_unlock(&lock);
 110
 111        return 0;
 112}
 113
 114extern int ping_watchdog(int fd);
 115
 116static ssize_t harddog_write(struct file *file, const char __user *data, size_t len,
 117                             loff_t *ppos)
 118{
 119        /*
 120         *      Refresh the timer.
 121         */
 122        if(len)
 123                return ping_watchdog(harddog_out_fd);
 124        return 0;
 125}
 126
 127static int harddog_ioctl(struct inode *inode, struct file *file,
 128                         unsigned int cmd, unsigned long arg)
 129{
 130        void __user *argp= (void __user *)arg;
 131        static struct watchdog_info ident = {
 132                WDIOC_SETTIMEOUT,
 133                0,
 134                "UML Hardware Watchdog"
 135        };
 136        switch (cmd) {
 137                default:
 138                        return -ENOTTY;
 139                case WDIOC_GETSUPPORT:
 140                        if(copy_to_user(argp, &ident, sizeof(ident)))
 141                                return -EFAULT;
 142                        return 0;
 143                case WDIOC_GETSTATUS:
 144                case WDIOC_GETBOOTSTATUS:
 145                        return put_user(0,(int __user *)argp);
 146                case WDIOC_KEEPALIVE:
 147                        return ping_watchdog(harddog_out_fd);
 148        }
 149}
 150
 151static const struct file_operations harddog_fops = {
 152        .owner          = THIS_MODULE,
 153        .write          = harddog_write,
 154        .ioctl          = harddog_ioctl,
 155        .open           = harddog_open,
 156        .release        = harddog_release,
 157};
 158
 159static struct miscdevice harddog_miscdev = {
 160        .minor          = WATCHDOG_MINOR,
 161        .name           = "watchdog",
 162        .fops           = &harddog_fops,
 163};
 164
 165static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
 166
 167static int __init harddog_init(void)
 168{
 169        int ret;
 170
 171        ret = misc_register(&harddog_miscdev);
 172
 173        if (ret)
 174                return ret;
 175
 176        printk(banner);
 177
 178        return 0;
 179}
 180
 181static void __exit harddog_exit(void)
 182{
 183        misc_deregister(&harddog_miscdev);
 184}
 185
 186module_init(harddog_init);
 187module_exit(harddog_exit);
 188