harddog_kern.c 4.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
/* UML hardware watchdog, shamelessly stolen from:
 *
 *	SoftDog	0.05:	A Software Watchdog Device
 *
 *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
 *				http://www.redhat.com
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 *	
 *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
 *	warranty for any of this software. This material is provided 
 *	"AS-IS" and at no charge.	
 *
 *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
 *
 *	Software only watchdog driver. Unlike its big brother the WDT501P
 *	driver this won't always recover a failed machine.
 *
 *  03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
 *	Modularised.
 *	Added soft_margin; use upon insmod to change the timer delay.
 *	NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
 *	    minors.
 *
 *  19980911 Alan Cox
 *	Made SMP safe for 2.3.x
 *
 *  20011127 Joel Becker (jlbec@evilplan.org>
 *	Added soft_noboot; Allows testing the softdog trigger without 
 *	requiring a recompile.
 *	Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
 */
 
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
J
Jeff Dike 已提交
47
#include <linux/spinlock.h>
L
Linus Torvalds 已提交
48 49 50 51 52
#include <asm/uaccess.h>
#include "mconsole.h"

MODULE_LICENSE("GPL");

J
Jeff Dike 已提交
53
static DEFINE_SPINLOCK(lock);
L
Linus Torvalds 已提交
54 55 56 57 58 59 60 61 62 63 64 65
static int timer_alive;
static int harddog_in_fd = -1;
static int harddog_out_fd = -1;

/*
 *	Allow only one person to hold it open
 */
 
extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock);

static int harddog_open(struct inode *inode, struct file *file)
{
J
Jeff Dike 已提交
66
	int err = -EBUSY;
L
Linus Torvalds 已提交
67 68
	char *sock = NULL;

J
Jeff Dike 已提交
69
	spin_lock(&lock);
L
Linus Torvalds 已提交
70
	if(timer_alive)
J
Jeff Dike 已提交
71
		goto err;
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79
#ifdef CONFIG_HARDDOG_NOWAYOUT	 
	__module_get(THIS_MODULE);
#endif

#ifdef CONFIG_MCONSOLE
	sock = mconsole_notify_socket();
#endif
	err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
J
Jeff Dike 已提交
80 81
	if(err)
		goto err;
L
Linus Torvalds 已提交
82 83

	timer_alive = 1;
J
Jeff Dike 已提交
84
	spin_unlock(&lock);
L
Linus Torvalds 已提交
85
	return nonseekable_open(inode, file);
J
Jeff Dike 已提交
86 87 88
err:
	spin_unlock(&lock);
	return err;
L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97
}

extern void stop_watchdog(int in_fd, int out_fd);

static int harddog_release(struct inode *inode, struct file *file)
{
	/*
	 *	Shut off the timer.
	 */
J
Jeff Dike 已提交
98 99

	spin_lock(&lock);
L
Linus Torvalds 已提交
100 101 102 103 104 105

	stop_watchdog(harddog_in_fd, harddog_out_fd);
	harddog_in_fd = -1;
	harddog_out_fd = -1;

	timer_alive=0;
J
Jeff Dike 已提交
106 107
	spin_unlock(&lock);

L
Linus Torvalds 已提交
108 109 110 111 112
	return 0;
}

extern int ping_watchdog(int fd);

A
Al Viro 已提交
113
static ssize_t harddog_write(struct file *file, const char __user *data, size_t len,
L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126
			     loff_t *ppos)
{
	/*
	 *	Refresh the timer.
	 */
	if(len)
		return(ping_watchdog(harddog_out_fd));
	return 0;
}

static int harddog_ioctl(struct inode *inode, struct file *file,
			 unsigned int cmd, unsigned long arg)
{
A
Al Viro 已提交
127
	void __user *argp= (void __user *)arg;
L
Linus Torvalds 已提交
128 129 130 131 132 133 134 135 136
	static struct watchdog_info ident = {
		WDIOC_SETTIMEOUT,
		0,
		"UML Hardware Watchdog"
	};
	switch (cmd) {
		default:
			return -ENOTTY;
		case WDIOC_GETSUPPORT:
A
Al Viro 已提交
137
			if(copy_to_user(argp, &ident, sizeof(ident)))
L
Linus Torvalds 已提交
138 139 140 141
				return -EFAULT;
			return 0;
		case WDIOC_GETSTATUS:
		case WDIOC_GETBOOTSTATUS:
A
Al Viro 已提交
142
			return put_user(0,(int __user *)argp);
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
		case WDIOC_KEEPALIVE:
			return(ping_watchdog(harddog_out_fd));
	}
}

static struct file_operations harddog_fops = {
	.owner		= THIS_MODULE,
	.write		= harddog_write,
	.ioctl		= harddog_ioctl,
	.open		= harddog_open,
	.release	= harddog_release,
};

static struct miscdevice harddog_miscdev = {
	.minor		= WATCHDOG_MINOR,
	.name		= "watchdog",
	.fops		= &harddog_fops,
};

static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";

static int __init harddog_init(void)
{
	int ret;

	ret = misc_register(&harddog_miscdev);

	if (ret)
		return ret;

	printk(banner);

	return(0);
}

static void __exit harddog_exit(void)
{
	misc_deregister(&harddog_miscdev);
}

module_init(harddog_init);
module_exit(harddog_exit);

/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-file-style: "linux"
 * End:
 */