harddog_kern.c 4.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11
/* 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.
12 13 14 15
 *
 *	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.
L
Linus Torvalds 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 *	(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>
32
 *	Added soft_noboot; Allows testing the softdog trigger without
L
Linus Torvalds 已提交
33 34 35
 *	requiring a recompile.
 *	Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
 */
36

L
Linus Torvalds 已提交
37 38 39 40 41 42 43 44 45 46
#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
static int timer_alive;
static int harddog_in_fd = -1;
static int harddog_out_fd = -1;

/*
 *	Allow only one person to hold it open
 */
61

L
Linus Torvalds 已提交
62 63 64 65
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;
72
#ifdef CONFIG_HARDDOG_NOWAYOUT
L
Linus Torvalds 已提交
73 74 75 76 77 78 79
	__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
			     loff_t *ppos)
{
	/*
	 *	Refresh the timer.
	 */
	if(len)
120
		return ping_watchdog(harddog_out_fd);
L
Linus Torvalds 已提交
121 122 123 124 125 126
	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
		case WDIOC_KEEPALIVE:
144
			return ping_watchdog(harddog_out_fd);
L
Linus Torvalds 已提交
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
	}
}

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);

175
	return 0;
L
Linus Torvalds 已提交
176 177 178 179 180 181 182 183 184
}

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

module_init(harddog_init);
module_exit(harddog_exit);