static int pc87413_release(struct inode *inode, struct file *file)
{
	/* Shut off the timer. */

	if (expect_close == 42) {
		pc87413_disable();
		pr_info("Watchdog disabled, sleeping again...\n");
	} else {
		pr_crit("Unexpected close, not stopping watchdog!\n");
		pc87413_refresh();
	}
	clear_bit(0, &timer_enabled);
	expect_close = 0;
	return 0;
}
Esempio n. 2
0
static int pc87413_release(struct inode *inode, struct file *file)
{
    /* Shut off the timer. */

    if (expect_close == 42) {
        pc87413_disable();
        printk(KERN_INFO MODNAME "Watchdog disabled,"
                                 " sleeping again...\n");
    } else {
        printk(KERN_CRIT MODNAME "Unexpected close, not stopping"
                                 " watchdog!\n");
        pc87413_refresh();
    }

    clear_bit(0, &timer_enabled);
    expect_close = 0;

    return 0;
}
Esempio n. 3
0
static long pc87413_ioctl(struct file *file, unsigned int cmd,
						unsigned long arg)
{
	int new_timeout;

	union {
		struct watchdog_info __user *ident;
		int __user *i;
	} uarg;

	static struct watchdog_info ident = {
		.options          = WDIOF_KEEPALIVEPING |
				    WDIOF_SETTIMEOUT |
				    WDIOF_MAGICCLOSE,
		.firmware_version = 1,
		.identity         = "PC87413(HF/F) watchdog",
	};

	uarg.i = (int __user *)arg;

	switch (cmd) {
	case WDIOC_GETSUPPORT:
		return copy_to_user(uarg.ident, &ident,
					sizeof(ident)) ? -EFAULT : 0;
	case WDIOC_GETSTATUS:
		return put_user(pc87413_status(), uarg.i);
	case WDIOC_GETBOOTSTATUS:
		return put_user(0, uarg.i);
	case WDIOC_SETOPTIONS:
	{
		int options, retval = -EINVAL;
		if (get_user(options, uarg.i))
			return -EFAULT;
		if (options & WDIOS_DISABLECARD) {
			pc87413_disable();
			retval = 0;
		}
		if (options & WDIOS_ENABLECARD) {
			pc87413_enable();
			retval = 0;
		}
		return retval;
	}
	case WDIOC_KEEPALIVE:
		pc87413_refresh();
#ifdef DEBUG
		printk(KERN_INFO DPFX "keepalive\n");
#endif
		return 0;
	case WDIOC_SETTIMEOUT:
		if (get_user(new_timeout, uarg.i))
			return -EFAULT;
		/* the API states this is given in secs */
		new_timeout /= 60;
		if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
			return -EINVAL;
		timeout = new_timeout;
		pc87413_refresh();
		/* fall through and return the new timeout... */
	case WDIOC_GETTIMEOUT:
		new_timeout = timeout * 60;
		return put_user(new_timeout, uarg.i);
	default:
		return -ENOTTY;
	}
}

/* -- Notifier funtions -----------------------------------------*/

/**
 *	notify_sys:
 *	@this: our notifier block
 *	@code: the event being reported
 *	@unused: unused
 *
 *	Our notifier is called on system shutdowns. We want to turn the card
 *	off at reboot otherwise the machine will reboot again during memory
 *	test or worse yet during the following fsck. This would suck, in fact
 *	trust me - if it happens it does suck.
 */

static int pc87413_notify_sys(struct notifier_block *this,
			      unsigned long code,
			      void *unused)
{
	if (code == SYS_DOWN || code == SYS_HALT)
		/* Turn the card off */
		pc87413_disable();
	return NOTIFY_DONE;
}

/* -- Module's structures ---------------------------------------*/

static const struct file_operations pc87413_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.write		= pc87413_write,
	.unlocked_ioctl	= pc87413_ioctl,
	.open		= pc87413_open,
	.release	= pc87413_release,
};

static struct notifier_block pc87413_notifier = {
	.notifier_call  = pc87413_notify_sys,
};

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

/* -- Module init functions -------------------------------------*/

/**
 * 	pc87413_init: module's "constructor"
 *
 *	Set up the WDT watchdog board. All we have to do is grab the
 *	resources we require and bitch if anyone beat us to them.
 *	The open() function will actually kick the board off.
 */

static int __init pc87413_init(void)
{
	int ret;

	printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
							WDT_INDEX_IO_PORT);

	/* request_region(io, 2, "pc87413"); */

	ret = register_reboot_notifier(&pc87413_notifier);
	if (ret != 0) {
		printk(KERN_ERR PFX
			"cannot register reboot notifier (err=%d)\n", ret);
	}

	ret = misc_register(&pc87413_miscdev);
	if (ret != 0) {
		printk(KERN_ERR PFX
			"cannot register miscdev on minor=%d (err=%d)\n",
			WATCHDOG_MINOR, ret);
		unregister_reboot_notifier(&pc87413_notifier);
		return ret;
	}
	printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
	pc87413_enable();
	return 0;
}

/**
 *	pc87413_exit: module's "destructor"
 *
 *	Unload the watchdog. You cannot do this with any file handles open.
 *	If your watchdog is set to continue ticking on close and you unload
 *	it, well it keeps ticking. We won't get the interrupt but the board
 *	will not touch PC memory so all is fine. You just have to load a new
 *	module in 60 seconds or reboot.
 */

static void __exit pc87413_exit(void)
{
	/* Stop the timer before we leave */
	if (!nowayout) {
		pc87413_disable();
		printk(KERN_INFO MODNAME "Watchdog disabled.\n");
	}

	misc_deregister(&pc87413_miscdev);
	unregister_reboot_notifier(&pc87413_notifier);
	/* release_region(io, 2); */

	printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
}

module_init(pc87413_init);
module_exit(pc87413_exit);

MODULE_AUTHOR("Sven Anders <*****@*****.**>, "
		"Marcus Junker <*****@*****.**>,");
MODULE_DESCRIPTION("PC87413 WDT driver");
MODULE_LICENSE("GPL");

MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);

module_param(io, int, 0);
MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ").");

module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,
		"Watchdog timeout in minutes (default="
				__MODULE_STRING(timeout) ").");

module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout,
		"Watchdog cannot be stopped once started (default="
				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");