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

📄 wdt_pci.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Industrial Computer Source PCI-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 *		JP Nollmann	:	Added support for PCI wdt501p *		Alan Cox	:	Split ISA and PCI cards into two drivers *		Jeff Garzik	:	PCI cleanups *		Tigran Aivazian	:	Restructured wdtpci_init_one() to handle failures *		Joel Becker 	:	Added WDIOC_GET/SETTIMEOUT *		Zwane Mwaikambo	:	Magic char closing, locking changes, cleanups *		Matt Domsch	:	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/ioport.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/pci.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#define WDT_IS_PCI#include "wd501p.h"#define PFX "wdt_pci: "/* * Until Access I/O gets their application for a PCI vendor ID approved, * I don't think that it's appropriate to move these constants into the * regular pci_ids.h file. -- JPN 2000/01/18 */#ifndef PCI_VENDOR_ID_ACCESSIO#define PCI_VENDOR_ID_ACCESSIO 0x494f#endif#ifndef PCI_DEVICE_ID_WDG_CSM#define PCI_DEVICE_ID_WDG_CSM 0x22c0#endif/* We can only use 1 card due to the /dev/watchdog restriction */static int dev_count;static struct semaphore open_sem;static spinlock_t wdtpci_lock;static char expect_close;static int io;static int irq;/* Default timeout */#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)");#ifdef CONFIG_WDT_501_PCI/* Support for the Fan Tachometer on the PCI-WDT501 */static int tachometer;module_param(tachometer, int, 0);MODULE_PARM_DESC(tachometer, "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");#endif /* CONFIG_WDT_501_PCI *//* *	Programming support */static void wdtpci_ctr_mode(int ctr, int mode){	ctr<<=6;	ctr|=0x30;	ctr|=(mode<<1);	outb_p(ctr, WDT_CR);}static void wdtpci_ctr_load(int ctr, int val){	outb_p(val&0xFF, WDT_COUNT0+ctr);	outb_p(val>>8, WDT_COUNT0+ctr);}/** *	wdtpci_start: * *	Start the watchdog driver. */static int wdtpci_start(void){	unsigned long flags;	spin_lock_irqsave(&wdtpci_lock, flags);	/*	 * "pet" the watchdog, as Access says.	 * This resets the clock outputs.	 */	inb_p(WDT_DC);			/* Disable watchdog */	wdtpci_ctr_mode(2,0);		/* Program CTR2 for Mode 0: Pulse on Terminal Count */	outb_p(0, WDT_DC);		/* Enable watchdog */	inb_p(WDT_DC);			/* Disable watchdog */	outb_p(0, WDT_CLOCK);		/* 2.0833MHz clock */	inb_p(WDT_BUZZER);		/* disable */	inb_p(WDT_OPTONOTRST);		/* disable */	inb_p(WDT_OPTORST);		/* disable */	inb_p(WDT_PROGOUT);		/* disable */	wdtpci_ctr_mode(0,3);		/* Program CTR0 for Mode 3: Square Wave Generator */	wdtpci_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */	wdtpci_ctr_mode(2,1);		/* Program CTR2 for Mode 1: Retriggerable One-Shot */	wdtpci_ctr_load(0,20833);	/* count at 100Hz */	wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */	/* DO NOT LOAD CTR2 on PCI card! -- JPN */	outb_p(0, WDT_DC);		/* Enable watchdog */	spin_unlock_irqrestore(&wdtpci_lock, flags);	return 0;}/** *	wdtpci_stop: * *	Stop the watchdog driver. */static int wdtpci_stop (void){	unsigned long flags;	/* Turn the card off */	spin_lock_irqsave(&wdtpci_lock, flags);	inb_p(WDT_DC);			/* Disable watchdog */	wdtpci_ctr_load(2,0);		/* 0 length reset pulses now */	spin_unlock_irqrestore(&wdtpci_lock, flags);	return 0;}/** *	wdtpci_ping: * *	Reload counter one with the watchdog heartbeat. We don't bother reloading *	the cascade counter. */static int wdtpci_ping(void){	unsigned long flags;	/* Write a watchdog value */	spin_lock_irqsave(&wdtpci_lock, flags);	inb_p(WDT_DC);			/* Disable watchdog */	wdtpci_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */	wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */	outb_p(0, WDT_DC);		/* Enable watchdog */	spin_unlock_irqrestore(&wdtpci_lock, flags);	return 0;}/** *	wdtpci_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 wdtpci_set_heartbeat(int t){	/* Arbitrary, can't find the card's limits */	if ((t < 1) || (t > 65535))		return -EINVAL;	heartbeat = t;	wd_heartbeat = t * 100;	return 0;}/** *	wdtpci_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 wdtpci_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_PCI	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_PCI */	return 0;}#ifdef CONFIG_WDT_501_PCI/** *	wdtpci_get_temperature: * *	Reports the temperature in degrees Fahrenheit. The API is in *	farenheit. It was designed by an imperial measurement luddite. */static int wdtpci_get_temperature(int *temperature){	unsigned short c=inb_p(WDT_RT);	*temperature = (c * 11 / 15) + 7;	return 0;}#endif /* CONFIG_WDT_501_PCI *//** *	wdtpci_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 wdtpci_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 PFX "status %d\n", status);#ifdef CONFIG_WDT_501_PCI	if (!(status & WDC_SR_TGOOD)) 		printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",inb_p(WDT_RT));	if (!(status & WDC_SR_PSUOVER)) 		printk(KERN_CRIT PFX "PSU over voltage.\n");	if (!(status & WDC_SR_PSUUNDR)) 		printk(KERN_CRIT PFX "PSU under voltage.\n");	if (tachometer) {		if (!(status & WDC_SR_FANGOOD))			printk(KERN_CRIT PFX "Possible fan fault.\n");	}#endif /* CONFIG_WDT_501_PCI */	if (!(status&WDC_SR_WCCR))#ifdef SOFTWARE_REBOOT#ifdef ONLY_TESTING		printk(KERN_CRIT PFX "Would Reboot.\n");#else		printk(KERN_CRIT PFX "Initiating system reboot.\n");		emergency_restart(NULL);#endif#else		printk(KERN_CRIT PFX "Reset in 5ms.\n");#endif	return IRQ_HANDLED;}/** *	wdtpci_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 wdtpci_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){	if (count) {		if (!nowayout) {			size_t i;			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;			}		}		wdtpci_ping();	}	return count;}/** *	wdtpci_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 wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,	unsigned long arg){	int new_heartbeat;	int status;	void __user *argp = (void __user *)arg;	int __user *p = argp;	static struct watchdog_info ident = {		.options =		WDIOF_SETTIMEOUT|					WDIOF_MAGICCLOSE|					WDIOF_KEEPALIVEPING,		.firmware_version =	1,		.identity =		"PCI-WDT500/501",	};	/* Add options according to the card we have */	ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);

⌨️ 快捷键说明

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