PageRenderTime 49ms CodeModel.GetById 13ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/char/watchdog/indydog.c

https://bitbucket.org/evzijst/gittest
C | 221 lines | 163 code | 39 blank | 19 comment | 15 complexity | 6ae3ebedcc508134534ac44724b95443 MD5 | raw file
  1/*
  2 *	IndyDog	0.3	A Hardware Watchdog Device for SGI IP22
  3 *
  4 *	(c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
  5 *
  6 *	This program is free software; you can redistribute it and/or
  7 *	modify it under the terms of the GNU General Public License
  8 *	as published by the Free Software Foundation; either version
  9 *	2 of the License, or (at your option) any later version.
 10 *
 11 *	based on softdog.c by Alan Cox <alan@redhat.com>
 12 */
 13
 14#include <linux/module.h>
 15#include <linux/moduleparam.h>
 16#include <linux/config.h>
 17#include <linux/types.h>
 18#include <linux/kernel.h>
 19#include <linux/fs.h>
 20#include <linux/mm.h>
 21#include <linux/miscdevice.h>
 22#include <linux/watchdog.h>
 23#include <linux/notifier.h>
 24#include <linux/reboot.h>
 25#include <linux/init.h>
 26#include <asm/uaccess.h>
 27#include <asm/sgi/mc.h>
 28
 29#define PFX "indydog: "
 30static int indydog_alive;
 31
 32#ifdef CONFIG_WATCHDOG_NOWAYOUT
 33static int nowayout = 1;
 34#else
 35static int nowayout = 0;
 36#endif
 37
 38#define WATCHDOG_TIMEOUT 30		/* 30 sec default timeout */
 39
 40module_param(nowayout, int, 0);
 41MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 42
 43static void indydog_start(void)
 44{
 45	u32 mc_ctrl0 = sgimc->cpuctrl0;
 46
 47	mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
 48	sgimc->cpuctrl0 = mc_ctrl0;
 49}
 50
 51static void indydog_stop(void)
 52{
 53	u32 mc_ctrl0 = sgimc->cpuctrl0;
 54
 55	mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
 56	sgimc->cpuctrl0 = mc_ctrl0;
 57
 58	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
 59}
 60
 61static void indydog_ping(void)
 62{
 63	sgimc->watchdogt = 0;
 64}
 65
 66/*
 67 *	Allow only one person to hold it open
 68 */
 69static int indydog_open(struct inode *inode, struct file *file)
 70{
 71	if (indydog_alive)
 72		return -EBUSY;
 73
 74	if (nowayout)
 75		__module_get(THIS_MODULE);
 76
 77	/* Activate timer */
 78	indydog_start();
 79	indydog_ping();
 80
 81	indydog_alive = 1;
 82	printk(KERN_INFO "Started watchdog timer.\n");
 83
 84	return nonseekable_open(inode, file);
 85}
 86
 87static int indydog_release(struct inode *inode, struct file *file)
 88{
 89	/* Shut off the timer.
 90	 * Lock it in if it's a module and we defined ...NOWAYOUT */
 91	if (!nowayout)
 92		indydog_stop();		/* Turn the WDT off */
 93
 94	indydog_alive = 0;
 95
 96	return 0;
 97}
 98
 99static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
100{
101	/* Refresh the timer. */
102	if (len) {
103		indydog_ping();
104	}
105	return len;
106}
107
108static int indydog_ioctl(struct inode *inode, struct file *file,
109	unsigned int cmd, unsigned long arg)
110{
111	int options, retval = -EINVAL;
112	static struct watchdog_info ident = {
113		.options		= WDIOF_KEEPALIVEPING |
114					  WDIOF_MAGICCLOSE,
115		.firmware_version	= 0,
116		.identity		= "Hardware Watchdog for SGI IP22",
117	};
118
119	switch (cmd) {
120		default:
121			return -ENOIOCTLCMD;
122		case WDIOC_GETSUPPORT:
123			if (copy_to_user((struct watchdog_info *)arg,
124					 &ident, sizeof(ident)))
125				return -EFAULT;
126			return 0;
127		case WDIOC_GETSTATUS:
128		case WDIOC_GETBOOTSTATUS:
129			return put_user(0,(int *)arg);
130		case WDIOC_KEEPALIVE:
131			indydog_ping();
132			return 0;
133		case WDIOC_GETTIMEOUT:
134			return put_user(WATCHDOG_TIMEOUT,(int *)arg);
135		case WDIOC_SETOPTIONS:
136		{
137			if (get_user(options, (int *)arg))
138				return -EFAULT;
139
140			if (options & WDIOS_DISABLECARD) {
141				indydog_stop();
142				retval = 0;
143			}
144
145			if (options & WDIOS_ENABLECARD) {
146				indydog_start();
147				retval = 0;
148			}
149
150			return retval;
151		}
152	}
153}
154
155static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
156{
157	if (code == SYS_DOWN || code == SYS_HALT)
158		indydog_stop();		/* Turn the WDT off */
159
160	return NOTIFY_DONE;
161}
162
163static struct file_operations indydog_fops = {
164	.owner		= THIS_MODULE,
165	.llseek		= no_llseek,
166	.write		= indydog_write,
167	.ioctl		= indydog_ioctl,
168	.open		= indydog_open,
169	.release	= indydog_release,
170};
171
172static struct miscdevice indydog_miscdev = {
173	.minor		= WATCHDOG_MINOR,
174	.name		= "watchdog",
175	.fops		= &indydog_fops,
176};
177
178static struct notifier_block indydog_notifier = {
179	.notifier_call = indydog_notify_sys,
180};
181
182static char banner[] __initdata =
183	KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
184
185static int __init watchdog_init(void)
186{
187	int ret;
188
189	ret = register_reboot_notifier(&indydog_notifier);
190	if (ret) {
191		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
192			ret);
193		return ret;
194	}
195
196	ret = misc_register(&indydog_miscdev);
197	if (ret) {
198		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
199			WATCHDOG_MINOR, ret);
200		unregister_reboot_notifier(&indydog_notifier);
201		return ret;
202	}
203
204	printk(banner);
205
206	return 0;
207}
208
209static void __exit watchdog_exit(void)
210{
211	misc_deregister(&indydog_miscdev);
212	unregister_reboot_notifier(&indydog_notifier);
213}
214
215module_init(watchdog_init);
216module_exit(watchdog_exit);
217
218MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
219MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
220MODULE_LICENSE("GPL");
221MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);