Commit bd5490e4 authored by Dave Jones's avatar Dave Jones Committed by Dave Jones

[WATCHDOG] Final 2.4 changes for wdt_pci.c

parent cbe6ef3a
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
* Alan Cox : Split ISA and PCI cards into two drivers * Alan Cox : Split ISA and PCI cards into two drivers
* Jeff Garzik : PCI cleanups * Jeff Garzik : PCI cleanups
* Tigran Aivazian : Restructured wdtpci_init_one() to handle failures * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures
* Matt Domsch : added nowayout and timeout module options * 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/config.h>
...@@ -67,23 +69,18 @@ ...@@ -67,23 +69,18 @@
#define PCI_DEVICE_ID_WDG_CSM 0x22c0 #define PCI_DEVICE_ID_WDG_CSM 0x22c0
#endif #endif
static unsigned long wdt_is_open; static struct semaphore open_sem;
static spinlock_t wdtpci_lock;
static int expect_close = 0; static int expect_close = 0;
/* static int io;
* You must set these - there is no sane way to probe for this board. static int irq;
* You can use wdt=x,y to set these now.
*/
static int io=0x240;
static int irq=11;
/* Default timeout */
#define WD_TIMO (100*60) /* 1 minute */ #define WD_TIMO (100*60) /* 1 minute */
#define WD_TIMO_MAX (WD_TIMO*60) /* 1 hour(?) */
static int timeout_val = WD_TIMO; /* value passed to card */ static int wd_margin = WD_TIMO;
static int timeout = 60; /* in seconds */
MODULE_PARM(timeout,"i");
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
#ifdef CONFIG_WATCHDOG_NOWAYOUT #ifdef CONFIG_WATCHDOG_NOWAYOUT
static int nowayout = 1; static int nowayout = 1;
...@@ -94,43 +91,6 @@ static int nowayout = 0; ...@@ -94,43 +91,6 @@ static int nowayout = 0;
MODULE_PARM(nowayout,"i"); MODULE_PARM(nowayout,"i");
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
static void __init
wdtpci_validate_timeout(void)
{
timeout_val = timeout * 100;
}
#ifndef MODULE
/**
* wdtpci_setup:
* @str: command line string
*
* Setup options. The board isn't really probe-able so we have to
* get the user to tell us the configuration. Sane people build it
* modular but the others come here.
*/
static int __init wdtpci_setup(char *str)
{
int ints[4];
str = get_options (str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0)
{
io = ints[1];
if(ints[0] > 1)
irq = ints[2];
}
return 1;
}
__setup("wdt=", wdtpci_setup);
#endif /* !MODULE */
/* /*
* Programming support * Programming support
*/ */
...@@ -246,11 +206,15 @@ static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -246,11 +206,15 @@ static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void wdtpci_ping(void) static void wdtpci_ping(void)
{ {
unsigned long flags;
/* Write a watchdog value */ /* Write a watchdog value */
spin_lock_irqsave(&wdtpci_lock, flags);
inb_p(WDT_DC); inb_p(WDT_DC);
wdtpci_ctr_mode(1,2); wdtpci_ctr_mode(1,2);
wdtpci_ctr_load(1,timeout_val); /* Timeout */ wdtpci_ctr_load(1,wd_margin); /* Timeout */
outb_p(0, WDT_DC); outb_p(0, WDT_DC);
spin_unlock_irqrestore(&wdtpci_lock, flags);
} }
/** /**
...@@ -270,10 +234,12 @@ static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, lo ...@@ -270,10 +234,12 @@ static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, lo
if (ppos != &file->f_pos) if (ppos != &file->f_pos)
return -ESPIPE; return -ESPIPE;
if(count) if (count) {
{
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
expect_close = 0;
for (i = 0; i != count; i++) { for (i = 0; i != count; i++) {
char c; char c;
if(get_user(c, buf+i)) if(get_user(c, buf+i))
...@@ -283,9 +249,9 @@ static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, lo ...@@ -283,9 +249,9 @@ static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, lo
} }
} }
wdtpci_ping(); wdtpci_ping();
return 1;
} }
return 0;
return count;
} }
/** /**
...@@ -337,6 +303,7 @@ static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *p ...@@ -337,6 +303,7 @@ static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *p
static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int new_margin;
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_OVERHEAT | WDIOF_POWERUNDER | .options = WDIOF_OVERHEAT | WDIOF_POWERUNDER |
WDIOF_POWEROVER | WDIOF_EXTERN1 | WDIOF_POWEROVER | WDIOF_EXTERN1 |
...@@ -361,6 +328,18 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -361,6 +328,18 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
wdtpci_ping(); wdtpci_ping();
return 0; return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, (int *)arg))
return -EFAULT;
/* Arbitrary, can't find the card's limits */
new_margin *= 100;
if ((new_margin < 0) || (new_margin > WD_TIMO_MAX))
return -EINVAL;
wd_margin = new_margin;
wdtpci_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(wd_margin / 100, (int *)arg);
} }
} }
...@@ -378,19 +357,21 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -378,19 +357,21 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd
static int wdtpci_open(struct inode *inode, struct file *file) static int wdtpci_open(struct inode *inode, struct file *file)
{ {
unsigned long flags;
switch(minor(inode->i_rdev)) switch(minor(inode->i_rdev))
{ {
case WATCHDOG_MINOR: case WATCHDOG_MINOR:
if( test_and_set_bit(0,&wdt_is_open) ) if (down_trylock(&open_sem))
{
return -EBUSY; return -EBUSY;
}
if (nowayout) { if (nowayout) {
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
} }
/* /*
* Activate * Activate
*/ */
spin_lock_irqsave(&wdtpci_lock, flags);
inb_p(WDT_DC); /* Disable */ inb_p(WDT_DC); /* Disable */
...@@ -413,9 +394,10 @@ static int wdtpci_open(struct inode *inode, struct file *file) ...@@ -413,9 +394,10 @@ static int wdtpci_open(struct inode *inode, struct file *file)
wdtpci_ctr_mode(1,2); wdtpci_ctr_mode(1,2);
wdtpci_ctr_mode(2,1); wdtpci_ctr_mode(2,1);
wdtpci_ctr_load(0,20833); /* count at 100Hz */ wdtpci_ctr_load(0,20833); /* count at 100Hz */
wdtpci_ctr_load(1,timeout_val); /* Timeout */ wdtpci_ctr_load(1,wd_margin);/* Timeout 60 seconds */
/* DO NOT LOAD CTR2 on PCI card! -- JPN */ /* DO NOT LOAD CTR2 on PCI card! -- JPN */
outb_p(0, WDT_DC); /* Enable */ outb_p(0, WDT_DC); /* Enable */
spin_unlock_irqrestore(&wdtpci_lock, flags);
return 0; return 0;
case TEMP_MINOR: case TEMP_MINOR:
return 0; return 0;
...@@ -438,13 +420,19 @@ static int wdtpci_open(struct inode *inode, struct file *file) ...@@ -438,13 +420,19 @@ static int wdtpci_open(struct inode *inode, struct file *file)
static int wdtpci_release(struct inode *inode, struct file *file) static int wdtpci_release(struct inode *inode, struct file *file)
{ {
if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{ if (minor(inode->i_rdev)==WATCHDOG_MINOR) {
if (!nowayout) { unsigned long flags;
if (expect_close) {
spin_lock_irqsave(&wdtpci_lock, flags);
inb_p(WDT_DC); /* Disable counters */ inb_p(WDT_DC); /* Disable counters */
wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
spin_unlock_irqrestore(&wdtpci_lock, flags);
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
wdtpci_ping();
} }
clear_bit(0, &wdt_is_open ); up(&open_sem);
} }
return 0; return 0;
} }
...@@ -464,11 +452,14 @@ static int wdtpci_release(struct inode *inode, struct file *file) ...@@ -464,11 +452,14 @@ static int wdtpci_release(struct inode *inode, struct file *file)
static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code==SYS_DOWN || code==SYS_HALT) unsigned long flags;
{
if (code==SYS_DOWN || code==SYS_HALT) {
/* Turn the card off */ /* Turn the card off */
spin_lock_irqsave(&wdtpci_lock, flags);
inb_p(WDT_DC); inb_p(WDT_DC);
wdtpci_ctr_load(2,0); wdtpci_ctr_load(2,0);
spin_unlock_irqrestore(&wdtpci_lock, flags);
} }
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -528,6 +519,9 @@ static int __init wdtpci_init_one (struct pci_dev *dev, ...@@ -528,6 +519,9 @@ static int __init wdtpci_init_one (struct pci_dev *dev,
if (pci_enable_device (dev)) if (pci_enable_device (dev))
goto out; goto out;
sema_init(&open_sem, 1);
spin_lock_init(&wdtpci_lock);
irq = dev->irq; irq = dev->irq;
io = pci_resource_start (dev, 2); io = pci_resource_start (dev, 2);
printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
...@@ -646,8 +640,6 @@ static int __init wdtpci_init(void) ...@@ -646,8 +640,6 @@ static int __init wdtpci_init(void)
if (rc < 1) if (rc < 1)
return -ENODEV; return -ENODEV;
wdtpci_validate_timeout();
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment