⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ep9315wdt.c

📁 ARM-LINUX EP9315 的看门狗驱动程序源代码
💻 C
字号:
/*
 *
 *
 *
 *
 *
 *
 *
 */


#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/stat.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>

#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>

#include "ep9315wdt.h"

MODULE_LICENSE("GPL");

#undef DEBUG
#define DEBUG
#ifdef DEBUG
	#define DPRINTK(fmt, arg...)	printk(KERN_DEBUG "%s:"fmt, __FUNCTION__, ##arg)
#else
	#define DPRINTK(fmt, arg...)
#endif	/*	#ifdef DEBUG	*/


#define EP9315_WDT_CLEAR			0x5555
#define EP9315_WDT_DISABLE		0xAA55
#define EP9315_WDT_ENABLE			0xAAAA

static unsigned long ep9315_wdt_users = 0;
#define WDT_OPENED_BITS			1
#define WDT_RUNNING				8
static unsigned long expect_close = 0;
#define EP9315_CLOSE_MAGIC			(0x5AFC4453)
static unsigned long boot_status;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
	static int nowaystop= 1;
#else
	static int nowaystop = 0;
#endif

module_param(nowaystop, int, S_IRUGO);
MODULE_PARM_DESC(nowaystop, "Watchdog cannot be stopped once started (default 0-->NO)");

static int margin_200ms = 300;		/*	(200ms) default 60s	*/
static int margin = 60;		/*	60s	*/
module_param(margin, int, S_IRUGO);
MODULE_PARM_DESC(margin, "Watchdog margin in 200ms (default 60s)");

#ifdef CONFIG_WATCHDONG_INSMODSTART
	static int insmodstart = 1;
#else
	static int insmodstart = 0;
#endif
module_param(insmodstart, int, S_IRUGO);
MODULE_PARM_DESC(insmodstart, "Watchdog start immediately when insmod watchdog module (default 0-->NO)");



struct timer_list WDTtimer;
#define TIMER_INTERVAL				((200*HZ)/1000)		//200ms
static int WDTtimercount = 0;

/*
 *	use timer to delay the outdate time
 *	timer is use 200ms
 */
static void TimerOutFunc(unsigned long data)
{
	if(++WDTtimercount <= margin_200ms)
		{	/*continue add_timer	*/
		WDTtimer.expires = jiffies + TIMER_INTERVAL;
		add_timer(&WDTtimer);

		outl(EP9315_WDT_CLEAR, WATCHDOG);

		DPRINTK("%d\n", WDTtimercount);
		}
	else
		{	/* time out, do not add_timer, wait watchdog time out, reset system	*/
		DPRINTK("time out\n");
		}
}


/*
 *	Allow only one person to hold it open
 */
static int ep9315wdt_open(struct inode *inodp, struct file *filp)
{
	nonseekable_open(inodp, filp);
	if(test_and_set_bit(WDT_OPENED_BITS, &ep9315_wdt_users))
		return -EBUSY;

	outl(EP9315_WDT_CLEAR, WATCHDOG);
	
	WDTtimer.expires = jiffies + TIMER_INTERVAL;
	WDTtimer.function = TimerOutFunc;
	WDTtimer.data = 0;

	add_timer(&WDTtimer);
	set_bit(WDT_RUNNING, &ep9315_wdt_users);

	outl(EP9315_WDT_ENABLE, WATCHDOG);

	outl(EP9315_WDT_CLEAR, WATCHDOG);	

	return 0;
}

/*
 *	shut off the timer.
 *	lock it in if it's a module and we defined...NOWAYOUT
 *	oddly, the watchdog can only be enabled, but we can turn off
 *	the interrupt, which appears to prevent the watchdong timing out.
 */

static int ep9315wdt_release(struct inode *inodp, struct file *filp)
{
	int ret = 0;
	WDTtimercount = 0;

	if(expect_close == EP9315_CLOSE_MAGIC)
		{	/*	can be stop	*/
		/*	stop watchdog	*/
		outl(EP9315_WDT_DISABLE, WATCHDOG);
		/*	del the timer	*/
		del_timer_sync(&WDTtimer);
		clear_bit(WDT_RUNNING, &ep9315_wdt_users);
		DPRINTK("stop wdt\n");
		}
	else
		{	/*	cann't be stopped	*/
		printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n");
		ret = -EBUSY;
		}

	clear_bit(WDT_OPENED_BITS, &ep9315_wdt_users);
	expect_close = 0;	

	return ret;
}

static ssize_t ep9315wdt_write(struct file *filp, const char *data, size_t len, loff_t *ppos)
{
	if(len)
		{
		if(!nowaystop)
			{
			size_t i;

			expect_close = 0;

			for(i=0; i!=len; i++)
				{
				char c;

				if(get_user(c, data+i))
					{
					return -EFAULT;
					}

				if(c == 'V')
					{
					expect_close = EP9315_CLOSE_MAGIC;
					DPRINTK("can stop\n");
					}
				}
			}
		/*	clear the timer count	*/
		WDTtimercount = 0;
		}

	return len;
}

static struct watchdog_info ident =
{
	.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
			WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
	.identity = "Ep9315 watchdog",
};

static int ep9315wdt_ioctl(struct inode *inodp, struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret = -ENOIOCTLCMD;
	int time;

	switch(cmd)
		{
		case WDIOC_GETSUPPORT:
			ret = copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)) ? -EFAULT : 0;
			break;

		case WDIOC_GETSTATUS:
			ret = put_user(0, (int *)arg);
			break;

		case WDIOC_GETBOOTSTATUS:
			ret = put_user(boot_status, (unsigned long *)arg);
			break;

		case WDIOC_SETTIMEOUT:
			ret = get_user(time, (int *)arg);
			if(ret)
				{
				break;
				}
			if(time<=0 || time > 255)
				{
				ret = -EINVAL;
				break;
				}
			margin_200ms = (time*HZ)/TIMER_INTERVAL;
			/*	fall through	*/
		case WDIOC_GETTIMEOUT:
			ret = put_user((margin_200ms/(HZ/TIMER_INTERVAL)), (int *)arg);
			break;

		case WDIOC_KEEPALIVE:
			WDTtimercount = 0;
			ret = 0;
			break;
		}

	return ret;
}

static struct file_operations ep9315wdt_fops = 
{
	.owner	=	THIS_MODULE,
	.write	=	ep9315wdt_write,
	.ioctl		=	ep9315wdt_ioctl,
	.open	=	ep9315wdt_open,
	.release	=	ep9315wdt_release,
};

static struct miscdevice ep9315wdt_miscdev =
{
	.minor	=	WATCHDOG_MINOR,
	.name	=	"watchdog/ep9315wdt",
	.fops	=	&ep9315wdt_fops,
};

static int __init ep9315wdt_init_module(void)
{
	int ret = 0;

	boot_status = inl(WATCHDOG);
	boot_status |= ((insmodstart) ? INSMODE_START : 0);
	boot_status |= ((nowaystop) ? NO_WAY_STOP : 0);
	DPRINTK("WATCHDOG=0x%X\n", boot_status);

	init_timer(&WDTtimer);
	DPRINTK("init timer\n");

	if(margin > 0)
		{
		margin_200ms = margin*(HZ/TIMER_INTERVAL);
		}
	else
		{
		return -EINVAL;
		}

	ret =  misc_register(&ep9315wdt_miscdev);
	if(ret == 0)
		{
		printk("EP9315 watchdog timer:timer margin %d sec\n", margin);
		}
	else
		{
		return ret;
		}

	if(insmodstart)
		{
		WDTtimer.expires = jiffies + TIMER_INTERVAL;
		WDTtimer.function = TimerOutFunc;
		WDTtimer.data = 0;

		add_timer(&WDTtimer);
		set_bit(WDT_RUNNING, &ep9315_wdt_users);

		outl(EP9315_WDT_CLEAR, WATCHDOG);
		outl(EP9315_WDT_ENABLE, WATCHDOG);
		}

	return ret;
}

static void __exit ep9315wdt_exit_module(void)
{
	if(test_bit(WDT_RUNNING, &ep9315_wdt_users))
		{
		del_timer_sync(&WDTtimer);
		set_bit(WDT_RUNNING, &ep9315_wdt_users);
		}
	misc_deregister(&ep9315wdt_miscdev);
}

module_init(ep9315wdt_init_module);
module_exit(ep9315wdt_exit_module);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -