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

📄 wdt.c

📁 linux2.6.13下2440看门狗驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Industrial Computer Source WDT500/501 driver * *	(c) Copyright 1996-1997 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. * *	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. * *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk> * *	Release 0.10. * *	Fixes *		Dave Gregorich	:	Modularisation and minor bugs *		Alan Cox	:	Added the watchdog ioctl() stuff *		Alan Cox	:	Fixed the reboot problem (as noted by *					Matt Crocker). *		Alan Cox	:	Added wdt= boot option *		Alan Cox	:	Cleaned up copy/user stuff *		Tim Hockin	:	Added insmod parameters, comment cleanup *					Parameterized timeout *		Tigran Aivazian	:	Restructured wdt_init() to handle failures *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT *		Matt Domsch	:	Added nowayout module option */#include <linux/config.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/types.h>#include <linux/miscdevice.h>#include <linux/watchdog.h>#include <linux/fs.h>#include <linux/ioport.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/init.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#include "wd501p.h"static unsigned long wdt_is_open;static char expect_close;/* *	Module parameters */#define WD_TIMO 60			/* Default heartbeat = 60 seconds */static int heartbeat = WD_TIMO;static int wd_heartbeat;module_param(heartbeat, int, 0);MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");static int nowayout = WATCHDOG_NOWAYOUT;module_param(nowayout, int, 0);MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");/* You must set these - there is no sane way to probe for this board. */static int io=0x240;static int irq=11;module_param(io, int, 0);MODULE_PARM_DESC(io, "WDT io port (default=0x240)");module_param(irq, int, 0);MODULE_PARM_DESC(irq, "WDT irq (default=11)");#ifdef CONFIG_WDT_501/* Support for the Fan Tachometer on the WDT501-P */static int tachometer;module_param(tachometer, int, 0);MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, default=0)");#endif /* CONFIG_WDT_501 *//* *	Programming support */static void wdt_ctr_mode(int ctr, int mode){	ctr<<=6;	ctr|=0x30;	ctr|=(mode<<1);	outb_p(ctr, WDT_CR);}static void wdt_ctr_load(int ctr, int val){	outb_p(val&0xFF, WDT_COUNT0+ctr);	outb_p(val>>8, WDT_COUNT0+ctr);}/** *	wdt_start: * *	Start the watchdog driver. */static int wdt_start(void){	inb_p(WDT_DC);			/* Disable watchdog */	wdt_ctr_mode(0,3);		/* Program CTR0 for Mode 3: Square Wave Generator */	wdt_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */	wdt_ctr_mode(2,0);		/* Program CTR2 for Mode 0: Pulse on Terminal Count */	wdt_ctr_load(0, 8948);		/* Count at 100Hz */	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */	wdt_ctr_load(2,65535);		/* Length of reset pulse */	outb_p(0, WDT_DC);		/* Enable watchdog */	return 0;}/** *	wdt_stop: * *	Stop the watchdog driver. */static int wdt_stop (void){	/* Turn the card off */	inb_p(WDT_DC);			/* Disable watchdog */	wdt_ctr_load(2,0);		/* 0 length reset pulses now */	return 0;}/** *	wdt_ping: * *	Reload counter one with the watchdog heartbeat. We don't bother reloading *	the cascade counter. */static int wdt_ping(void){	/* Write a watchdog value */	inb_p(WDT_DC);			/* Disable watchdog */	wdt_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */	outb_p(0, WDT_DC);		/* Enable watchdog */	return 0;}/** *	wdt_set_heartbeat: *	@t:		the new heartbeat value that needs to be set. * *	Set a new heartbeat value for the watchdog device. If the heartbeat value is *	incorrect we keep the old value and return -EINVAL. If successfull we *	return 0. */static int wdt_set_heartbeat(int t){	if ((t < 1) || (t > 65535))		return -EINVAL;	heartbeat = t;	wd_heartbeat = t * 100;	return 0;}/** *	wdt_get_status: *	@status:		the new status. * *	Extract the status information from a WDT watchdog device. There are *	several board variants so we have to know which bits are valid. Some *	bits default to one and some to zero in order to be maximally painful. * *	we then map the bits onto the status ioctl flags. */static int wdt_get_status(int *status){	unsigned char new_status=inb_p(WDT_SR);	*status=0;	if (new_status & WDC_SR_ISOI0)		*status |= WDIOF_EXTERN1;	if (new_status & WDC_SR_ISII1)		*status |= WDIOF_EXTERN2;#ifdef CONFIG_WDT_501	if (!(new_status & WDC_SR_TGOOD))		*status |= WDIOF_OVERHEAT;	if (!(new_status & WDC_SR_PSUOVER))		*status |= WDIOF_POWEROVER;	if (!(new_status & WDC_SR_PSUUNDR))		*status |= WDIOF_POWERUNDER;	if (tachometer) {		if (!(new_status & WDC_SR_FANGOOD))			*status |= WDIOF_FANFAULT;	}#endif /* CONFIG_WDT_501 */	return 0;}#ifdef CONFIG_WDT_501/** *	wdt_get_temperature: * *	Reports the temperature in degrees Fahrenheit. The API is in *	farenheit. It was designed by an imperial measurement luddite. */static int wdt_get_temperature(int *temperature){	unsigned short c=inb_p(WDT_RT);	*temperature = (c * 11 / 15) + 7;	return 0;}#endif /* CONFIG_WDT_501 *//** *	wdt_interrupt: *	@irq:		Interrupt number *	@dev_id:	Unused as we don't allow multiple devices. *	@regs:		Unused. * *	Handle an interrupt from the board. These are raised when the status *	map changes in what the board considers an interesting way. That means *	a failure condition occurring. */static irqreturn_t wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs){	/*	 *	Read the status register see what is up and	 *	then printk it.	 */	unsigned char status=inb_p(WDT_SR);	printk(KERN_CRIT "WDT status %d\n", status);#ifdef CONFIG_WDT_501	if (!(status & WDC_SR_TGOOD))		printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));	if (!(status & WDC_SR_PSUOVER))		printk(KERN_CRIT "PSU over voltage.\n");	if (!(status & WDC_SR_PSUUNDR))		printk(KERN_CRIT "PSU under voltage.\n");	if (tachometer) {		if (!(status & WDC_SR_FANGOOD))			printk(KERN_CRIT "Possible fan fault.\n");	}#endif /* CONFIG_WDT_501 */	if (!(status & WDC_SR_WCCR))#ifdef SOFTWARE_REBOOT#ifdef ONLY_TESTING		printk(KERN_CRIT "Would Reboot.\n");#else		printk(KERN_CRIT "Initiating system reboot.\n");		emergency_restart();#endif#else		printk(KERN_CRIT "Reset in 5ms.\n");#endif	return IRQ_HANDLED;}/** *	wdt_write: *	@file: file handle to the watchdog *	@buf: buffer to write (unused as data does not matter here *	@count: count of bytes *	@ppos: pointer to the position to write. No seeks allowed * *	A write to a watchdog device is defined as a keepalive signal. Any *	write of data will do, as we we don't define content meaning. */static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){	if(count) {		if (!nowayout) {			size_t i;			/* In case it was set long ago */			expect_close = 0;			for (i = 0; i != count; i++) {				char c;				if (get_user(c, buf + i))					return -EFAULT;				if (c == 'V')					expect_close = 42;			}		}		wdt_ping();	}	return count;}/** *	wdt_ioctl: *	@inode: inode of the device *	@file: file handle to the device *	@cmd: watchdog command *	@arg: argument pointer * *	The watchdog API defines a common set of functions for all watchdogs *	according to their available features. We only actually usefully support *	querying capabilities and current status. */static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,	unsigned long arg){	void __user *argp = (void __user *)arg;	int __user *p = argp;

⌨️ 快捷键说明

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