示例#1
0
static void pc87413_disable(void)
{
	unsigned int swc_base_addr;

	spin_lock(&io_lock);

	pc87413_select_wdt_out();
	pc87413_enable_swc();
	swc_base_addr = pc87413_get_swc_base();
	pc87413_swc_bank3(swc_base_addr);
	pc87413_disable_sw_wd_tren(swc_base_addr);
	pc87413_disable_sw_wd_trg(swc_base_addr);
	pc87413_programm_wdto(swc_base_addr, 0);

	spin_unlock(&io_lock);
}
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 const 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
		pr_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;

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

	if (!request_muxed_region(io, 2, MODNAME))
		return -EBUSY;

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

	ret = misc_register(&pc87413_miscdev);
	if (ret != 0) {
		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
		       WATCHDOG_MINOR, ret);
		goto reboot_unreg;
	}
	pr_info("initialized. timeout=%d min\n", timeout);

	pc87413_select_wdt_out();
	pc87413_enable_swc();
	pc87413_get_swc_base_addr();

	if (!request_region(swc_base_addr, 0x20, MODNAME)) {
		pr_err("cannot request SWC region at 0x%x\n", swc_base_addr);
		ret = -EBUSY;
		goto misc_unreg;
	}

	pc87413_enable();

	release_region(io, 2);
	return 0;

misc_unreg:
	misc_deregister(&pc87413_miscdev);
reboot_unreg:
	unregister_reboot_notifier(&pc87413_notifier);
	release_region(io, 2);
	return ret;
}

/**
 *	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();
		pr_info("Watchdog disabled\n");
	}

	misc_deregister(&pc87413_miscdev);
	unregister_reboot_notifier(&pc87413_notifier);
	release_region(swc_base_addr, 0x20);

	pr_info("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_DEFAULT) ").");

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

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