Commit 96e2e6fa authored by Wim Van Sebroeck's avatar Wim Van Sebroeck

[WATCHDOG] Merge code clean-up's from Alan Cox.

Merge branch 'alan' of ../linux-2.6-watchdog-mm
Fixed Conflicts in the following files:
	drivers/watchdog/booke_wdt.c
	drivers/watchdog/mpc5200_wdt.c
	drivers/watchdog/sc1200wdt.c
Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
parents 0967d61e 7c4be5aa
...@@ -58,39 +58,46 @@ ...@@ -58,39 +58,46 @@
#include <linux/types.h> /* For standard types (like size_t) */ #include <linux/types.h> /* For standard types (like size_t) */
#include <linux/errno.h> /* For the -ENODEV/... values */ #include <linux/errno.h> /* For the -ENODEV/... values */
#include <linux/kernel.h> /* For printk/panic/... */ #include <linux/kernel.h> /* For printk/panic/... */
#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV
(WATCHDOG_MINOR) */
#include <linux/watchdog.h> /* For the watchdog specific items */ #include <linux/watchdog.h> /* For the watchdog specific items */
#include <linux/fs.h> /* For file operations */ #include <linux/fs.h> /* For file operations */
#include <linux/ioport.h> /* For io-port access */ #include <linux/ioport.h> /* For io-port access */
#include <linux/platform_device.h> /* For platform_driver framework */ #include <linux/platform_device.h> /* For platform_driver framework */
#include <linux/init.h> /* For __init/__exit/... */ #include <linux/init.h> /* For __init/__exit/... */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */ #include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/io.h> /* For inb/outb/... */ #include <linux/io.h> /* For inb/outb/... */
/* Module information */ /* Module information */
#define DRV_NAME "acquirewdt" #define DRV_NAME "acquirewdt"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
#define WATCHDOG_NAME "Acquire WDT" #define WATCHDOG_NAME "Acquire WDT"
#define WATCHDOG_HEARTBEAT 0 /* There is no way to see what the correct time-out period is */ /* There is no way to see what the correct time-out period is */
#define WATCHDOG_HEARTBEAT 0
/* internal variables */ /* internal variables */
static struct platform_device *acq_platform_device; /* the watchdog platform device */ /* the watchdog platform device */
static struct platform_device *acq_platform_device;
static unsigned long acq_is_open; static unsigned long acq_is_open;
static char expect_close; static char expect_close;
/* module parameters */ /* module parameters */
static int wdt_stop = 0x43; /* You must set this - there is no sane way to probe for this board. */ /* You must set this - there is no sane way to probe for this board. */
static int wdt_stop = 0x43;
module_param(wdt_stop, int, 0); module_param(wdt_stop, int, 0);
MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)"); MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)");
static int wdt_start = 0x443; /* You must set this - there is no sane way to probe for this board. */ /* You must set this - there is no sane way to probe for this board. */
static int wdt_start = 0x443;
module_param(wdt_start, int, 0); module_param(wdt_start, int, 0);
MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)"); MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Watchdog Operations * Watchdog Operations
...@@ -112,18 +119,18 @@ static void acq_stop(void) ...@@ -112,18 +119,18 @@ static void acq_stop(void)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) static ssize_t acq_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) { if (count) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the magic character
* five months ago... */ * five months ago... */
expect_close = 0; expect_close = 0;
/* scan to see whether or not we got the
/* scan to see whether or not we got the magic character */ magic character */
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))
...@@ -132,64 +139,55 @@ static ssize_t acq_write(struct file *file, const char __user *buf, size_t count ...@@ -132,64 +139,55 @@ static ssize_t acq_write(struct file *file, const char __user *buf, size_t count
expect_close = 42; expect_close = 42;
} }
} }
/* Well, anyhow someone wrote to us, we should
/* Well, anyhow someone wrote to us, we should return that favour */ return that favour */
acq_keepalive(); acq_keepalive();
} }
return count; return count;
} }
static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long acq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = static struct watchdog_info ident = {
{
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = WATCHDOG_NAME, .identity = WATCHDOG_NAME,
}; };
switch(cmd) switch (cmd) {
{
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
acq_keepalive(); acq_keepalive();
return 0; return 0;
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_HEARTBEAT, p); return put_user(WATCHDOG_HEARTBEAT, p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
if (get_user(options, p)) if (get_user(options, p))
return -EFAULT; return -EFAULT;
if (options & WDIOS_DISABLECARD) {
if (options & WDIOS_DISABLECARD) acq_stop();
{ retval = 0;
acq_stop(); }
retval = 0; if (options & WDIOS_ENABLECARD) {
} acq_keepalive();
retval = 0;
if (options & WDIOS_ENABLECARD) }
{ return retval;
acq_keepalive();
retval = 0;
}
return retval;
} }
default: default:
return -ENOTTY; return -ENOTTY;
} }
} }
...@@ -211,7 +209,8 @@ static int acq_close(struct inode *inode, struct file *file) ...@@ -211,7 +209,8 @@ static int acq_close(struct inode *inode, struct file *file)
if (expect_close == 42) { if (expect_close == 42) {
acq_stop(); acq_stop();
} else { } else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
acq_keepalive(); acq_keepalive();
} }
clear_bit(0, &acq_is_open); clear_bit(0, &acq_is_open);
...@@ -227,7 +226,7 @@ static const struct file_operations acq_fops = { ...@@ -227,7 +226,7 @@ static const struct file_operations acq_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = acq_write, .write = acq_write,
.ioctl = acq_ioctl, .unlocked_ioctl = acq_ioctl,
.open = acq_open, .open = acq_open,
.release = acq_close, .release = acq_close,
}; };
...@@ -248,32 +247,29 @@ static int __devinit acq_probe(struct platform_device *dev) ...@@ -248,32 +247,29 @@ static int __devinit acq_probe(struct platform_device *dev)
if (wdt_stop != wdt_start) { if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX
wdt_stop); "I/O address 0x%04x already in use\n", wdt_stop);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
} }
if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_start); wdt_start);
ret = -EIO; ret = -EIO;
goto unreg_stop; goto unreg_stop;
} }
ret = misc_register(&acq_miscdev); ret = misc_register(&acq_miscdev);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_regions; goto unreg_regions;
} }
printk(KERN_INFO PFX "initialized. (nowayout=%d)\n", nowayout);
printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
nowayout);
return 0; return 0;
unreg_regions: unreg_regions:
release_region(wdt_start, 1); release_region(wdt_start, 1);
unreg_stop: unreg_stop:
...@@ -286,9 +282,9 @@ static int __devinit acq_probe(struct platform_device *dev) ...@@ -286,9 +282,9 @@ static int __devinit acq_probe(struct platform_device *dev)
static int __devexit acq_remove(struct platform_device *dev) static int __devexit acq_remove(struct platform_device *dev)
{ {
misc_deregister(&acq_miscdev); misc_deregister(&acq_miscdev);
release_region(wdt_start,1); release_region(wdt_start, 1);
if(wdt_stop != wdt_start) if (wdt_stop != wdt_start)
release_region(wdt_stop,1); release_region(wdt_stop, 1);
return 0; return 0;
} }
...@@ -313,18 +309,19 @@ static int __init acq_init(void) ...@@ -313,18 +309,19 @@ static int __init acq_init(void)
{ {
int err; int err;
printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n"); printk(KERN_INFO
"WDT driver for Acquire single board computer initialising.\n");
err = platform_driver_register(&acquirewdt_driver); err = platform_driver_register(&acquirewdt_driver);
if (err) if (err)
return err; return err;
acq_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); acq_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
if (IS_ERR(acq_platform_device)) { if (IS_ERR(acq_platform_device)) {
err = PTR_ERR(acq_platform_device); err = PTR_ERR(acq_platform_device);
goto unreg_platform_driver; goto unreg_platform_driver;
} }
return 0; return 0;
unreg_platform_driver: unreg_platform_driver:
......
...@@ -72,35 +72,35 @@ MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)"); ...@@ -72,35 +72,35 @@ MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=63, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Watchdog Operations * Watchdog Operations
*/ */
static void static void advwdt_ping(void)
advwdt_ping(void)
{ {
/* Write a watchdog value */ /* Write a watchdog value */
outb_p(timeout, wdt_start); outb_p(timeout, wdt_start);
} }
static void static void advwdt_disable(void)
advwdt_disable(void)
{ {
inb_p(wdt_stop); inb_p(wdt_stop);
} }
static int static int advwdt_set_heartbeat(int t)
advwdt_set_heartbeat(int t)
{ {
if ((t < 1) || (t > 63)) if (t < 1 || t > 63)
return -EINVAL; return -EINVAL;
timeout = t; timeout = t;
return 0; return 0;
} }
...@@ -109,8 +109,8 @@ advwdt_set_heartbeat(int t) ...@@ -109,8 +109,8 @@ advwdt_set_heartbeat(int t)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t static ssize_t advwdt_write(struct file *file, const char __user *buf,
advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
...@@ -131,9 +131,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp ...@@ -131,9 +131,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp
return count; return count;
} }
static int static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{ {
int new_timeout; int new_timeout;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
...@@ -146,57 +144,50 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -146,57 +144,50 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
advwdt_ping(); advwdt_ping();
break; break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p)) if (get_user(new_timeout, p))
return -EFAULT; return -EFAULT;
if (advwdt_set_heartbeat(new_timeout)) if (advwdt_set_heartbeat(new_timeout))
return -EINVAL; return -EINVAL;
advwdt_ping(); advwdt_ping();
/* Fall */ /* Fall */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(timeout, p); return put_user(timeout, p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) { if (get_user(options, p))
advwdt_disable(); return -EFAULT;
retval = 0; if (options & WDIOS_DISABLECARD) {
} advwdt_disable();
retval = 0;
if (options & WDIOS_ENABLECARD) { }
advwdt_ping(); if (options & WDIOS_ENABLECARD) {
retval = 0; advwdt_ping();
} retval = 0;
}
return retval; return retval;
} }
default: default:
return -ENOTTY; return -ENOTTY;
} }
return 0; return 0;
} }
static int static int advwdt_open(struct inode *inode, struct file *file)
advwdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &advwdt_is_open)) if (test_and_set_bit(0, &advwdt_is_open))
return -EBUSY; return -EBUSY;
...@@ -214,7 +205,8 @@ advwdt_close(struct inode *inode, struct file *file) ...@@ -214,7 +205,8 @@ advwdt_close(struct inode *inode, struct file *file)
if (adv_expect_close == 42) { if (adv_expect_close == 42) {
advwdt_disable(); advwdt_disable();
} else { } else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
advwdt_ping(); advwdt_ping();
} }
clear_bit(0, &advwdt_is_open); clear_bit(0, &advwdt_is_open);
...@@ -230,7 +222,7 @@ static const struct file_operations advwdt_fops = { ...@@ -230,7 +222,7 @@ static const struct file_operations advwdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = advwdt_write, .write = advwdt_write,
.ioctl = advwdt_ioctl, .unlocked_ioctl = advwdt_ioctl,
.open = advwdt_open, .open = advwdt_open,
.release = advwdt_close, .release = advwdt_close,
}; };
...@@ -245,23 +237,24 @@ static struct miscdevice advwdt_miscdev = { ...@@ -245,23 +237,24 @@ static struct miscdevice advwdt_miscdev = {
* Init & exit routines * Init & exit routines
*/ */
static int __devinit static int __devinit advwdt_probe(struct platform_device *dev)
advwdt_probe(struct platform_device *dev)
{ {
int ret; int ret;
if (wdt_stop != wdt_start) { if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX
wdt_stop); "I/O address 0x%04x already in use\n",
wdt_stop);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
} }
if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX
wdt_start); "I/O address 0x%04x already in use\n",
wdt_start);
ret = -EIO; ret = -EIO;
goto unreg_stop; goto unreg_stop;
} }
...@@ -269,20 +262,19 @@ advwdt_probe(struct platform_device *dev) ...@@ -269,20 +262,19 @@ advwdt_probe(struct platform_device *dev)
/* Check that the heartbeat value is within it's range ; if not reset to the default */ /* Check that the heartbeat value is within it's range ; if not reset to the default */
if (advwdt_set_heartbeat(timeout)) { if (advwdt_set_heartbeat(timeout)) {
advwdt_set_heartbeat(WATCHDOG_TIMEOUT); advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n", printk(KERN_INFO PFX
timeout); "timeout value must be 1<=x<=63, using %d\n", timeout);
} }
ret = misc_register(&advwdt_miscdev); ret = misc_register(&advwdt_miscdev);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_regions; goto unreg_regions;
} }
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout); timeout, nowayout);
out: out:
return ret; return ret;
unreg_regions: unreg_regions:
...@@ -293,8 +285,7 @@ advwdt_probe(struct platform_device *dev) ...@@ -293,8 +285,7 @@ advwdt_probe(struct platform_device *dev)
goto out; goto out;
} }
static int __devexit static int __devexit advwdt_remove(struct platform_device *dev)
advwdt_remove(struct platform_device *dev)
{ {
misc_deregister(&advwdt_miscdev); misc_deregister(&advwdt_miscdev);
release_region(wdt_start,1); release_region(wdt_start,1);
...@@ -304,8 +295,7 @@ advwdt_remove(struct platform_device *dev) ...@@ -304,8 +295,7 @@ advwdt_remove(struct platform_device *dev)
return 0; return 0;
} }
static void static void advwdt_shutdown(struct platform_device *dev)
advwdt_shutdown(struct platform_device *dev)
{ {
/* Turn the WDT off if we have a soft shutdown */ /* Turn the WDT off if we have a soft shutdown */
advwdt_disable(); advwdt_disable();
...@@ -321,8 +311,7 @@ static struct platform_driver advwdt_driver = { ...@@ -321,8 +311,7 @@ static struct platform_driver advwdt_driver = {
}, },
}; };
static int __init static int __init advwdt_init(void)
advwdt_init(void)
{ {
int err; int err;
...@@ -332,7 +321,8 @@ advwdt_init(void) ...@@ -332,7 +321,8 @@ advwdt_init(void)
if (err) if (err)
return err; return err;
advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); advwdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
if (IS_ERR(advwdt_platform_device)) { if (IS_ERR(advwdt_platform_device)) {
err = PTR_ERR(advwdt_platform_device); err = PTR_ERR(advwdt_platform_device);
goto unreg_platform_driver; goto unreg_platform_driver;
...@@ -345,8 +335,7 @@ advwdt_init(void) ...@@ -345,8 +335,7 @@ advwdt_init(void)
return err; return err;
} }
static void __exit static void __exit advwdt_exit(void)
advwdt_exit(void)
{ {
platform_device_unregister(advwdt_platform_device); platform_device_unregister(advwdt_platform_device);
platform_driver_unregister(&advwdt_driver); platform_driver_unregister(&advwdt_driver);
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <linux/io.h>
#define WATCHDOG_NAME "ALi_M1535" #define WATCHDOG_NAME "ALi_M1535"
#define PFX WATCHDOG_NAME ": " #define PFX WATCHDOG_NAME ": "
...@@ -30,17 +30,21 @@ ...@@ -30,17 +30,21 @@
static unsigned long ali_is_open; static unsigned long ali_is_open;
static char ali_expect_release; static char ali_expect_release;
static struct pci_dev *ali_pci; static struct pci_dev *ali_pci;
static u32 ali_timeout_bits; /* stores the computed timeout */ static u32 ali_timeout_bits; /* stores the computed timeout */
static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */ static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */
/* module parameters */ /* module parameters */
static int timeout = WATCHDOG_TIMEOUT; static int timeout = WATCHDOG_TIMEOUT;
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (0<timeout<18000, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (0 < timeout < 18000, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* ali_start - start watchdog countdown * ali_start - start watchdog countdown
...@@ -103,15 +107,16 @@ static void ali_keepalive(void) ...@@ -103,15 +107,16 @@ static void ali_keepalive(void)
static int ali_settimer(int t) static int ali_settimer(int t)
{ {
if(t < 0) if (t < 0)
return -EINVAL; return -EINVAL;
else if(t < 60) else if (t < 60)
ali_timeout_bits = t|(1<<6); ali_timeout_bits = t|(1<<6);
else if(t < 3600) else if (t < 3600)
ali_timeout_bits = (t/60)|(1<<7); ali_timeout_bits = (t/60)|(1<<7);
else if(t < 18000) else if (t < 18000)
ali_timeout_bits = (t/300)|(1<<6)|(1<<7); ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
else return -EINVAL; else
return -EINVAL;
timeout = t; timeout = t;
return 0; return 0;
...@@ -134,21 +139,22 @@ static int ali_settimer(int t) ...@@ -134,21 +139,22 @@ static int ali_settimer(int t)
*/ */
static ssize_t ali_write(struct file *file, const char __user *data, static ssize_t ali_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos) size_t len, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the
* five months ago... */ magic character five months ago... */
ali_expect_release = 0; ali_expect_release = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got
the magic character */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if(get_user(c, data+i)) if (get_user(c, data+i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
ali_expect_release = 42; ali_expect_release = 42;
...@@ -163,7 +169,6 @@ static ssize_t ali_write(struct file *file, const char __user *data, ...@@ -163,7 +169,6 @@ static ssize_t ali_write(struct file *file, const char __user *data,
/* /*
* ali_ioctl - handle watchdog ioctls * ali_ioctl - handle watchdog ioctls
* @inode: VFS inode
* @file: VFS file pointer * @file: VFS file pointer
* @cmd: ioctl number * @cmd: ioctl number
* @arg: arguments to the ioctl * @arg: arguments to the ioctl
...@@ -172,8 +177,7 @@ static ssize_t ali_write(struct file *file, const char __user *data, ...@@ -172,8 +177,7 @@ static ssize_t ali_write(struct file *file, const char __user *data,
* we want an extension to enable irq ack monitoring and the like * we want an extension to enable irq ack monitoring and the like
*/ */
static int ali_ioctl(struct inode *inode, struct file *file, static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -186,57 +190,45 @@ static int ali_ioctl(struct inode *inode, struct file *file, ...@@ -186,57 +190,45 @@ static int ali_ioctl(struct inode *inode, struct file *file,
}; };
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
sizeof (ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
ali_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if (get_user (new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
ali_stop();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
ali_start();
retval = 0;
}
return retval; case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
ali_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
ali_stop();
retval = 0;
} }
if (new_options & WDIOS_ENABLECARD) {
case WDIOC_SETTIMEOUT: ali_start();
{ retval = 0;
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
if (ali_settimer(new_timeout))
return -EINVAL;
ali_keepalive();
/* Fall */
} }
return retval;
case WDIOC_GETTIMEOUT: }
return put_user(timeout, p); case WDIOC_SETTIMEOUT:
{
default: int new_timeout;
return -ENOTTY; if (get_user(new_timeout, p))
return -EFAULT;
if (ali_settimer(new_timeout))
return -EINVAL;
ali_keepalive();
/* Fall */
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
} }
} }
...@@ -274,10 +266,11 @@ static int ali_release(struct inode *inode, struct file *file) ...@@ -274,10 +266,11 @@ static int ali_release(struct inode *inode, struct file *file)
/* /*
* Shut off the timer. * Shut off the timer.
*/ */
if (ali_expect_release == 42) { if (ali_expect_release == 42)
ali_stop(); ali_stop();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
ali_keepalive(); ali_keepalive();
} }
clear_bit(0, &ali_is_open); clear_bit(0, &ali_is_open);
...@@ -292,13 +285,11 @@ static int ali_release(struct inode *inode, struct file *file) ...@@ -292,13 +285,11 @@ static int ali_release(struct inode *inode, struct file *file)
*/ */
static int ali_notify_sys(struct notifier_block *this, unsigned long code, void *unused) static int ali_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{ {
if (code==SYS_DOWN || code==SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the WDT off */ ali_stop(); /* Turn the WDT off */
ali_stop();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -340,10 +331,10 @@ static int __init ali_find_watchdog(void) ...@@ -340,10 +331,10 @@ static int __init ali_find_watchdog(void)
/* Check for the a 7101 PMU */ /* Check for the a 7101 PMU */
pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL); pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
if(pdev == NULL) if (pdev == NULL)
return -ENODEV; return -ENODEV;
if(pci_enable_device(pdev)) { if (pci_enable_device(pdev)) {
pci_dev_put(pdev); pci_dev_put(pdev);
return -EIO; return -EIO;
} }
...@@ -355,9 +346,12 @@ static int __init ali_find_watchdog(void) ...@@ -355,9 +346,12 @@ static int __init ali_find_watchdog(void)
*/ */
pci_read_config_dword(pdev, 0xCC, &wdog); pci_read_config_dword(pdev, 0xCC, &wdog);
wdog &= ~0x3F; /* Timer bits */ /* Timer bits */
wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); /* Issued events */ wdog &= ~0x3F;
wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); /* No monitor bits */ /* Issued events */
wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24));
/* No monitor bits */
wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9));
pci_write_config_dword(pdev, 0xCC, wdog); pci_write_config_dword(pdev, 0xCC, wdog);
...@@ -369,12 +363,12 @@ static int __init ali_find_watchdog(void) ...@@ -369,12 +363,12 @@ static int __init ali_find_watchdog(void)
*/ */
static const struct file_operations ali_fops = { static const struct file_operations ali_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ali_write, .write = ali_write,
.ioctl = ali_ioctl, .unlocked_ioctl = ali_ioctl,
.open = ali_open, .open = ali_open,
.release = ali_release, .release = ali_release,
}; };
static struct miscdevice ali_miscdev = { static struct miscdevice ali_miscdev = {
...@@ -399,15 +393,16 @@ static int __init watchdog_init(void) ...@@ -399,15 +393,16 @@ static int __init watchdog_init(void)
int ret; int ret;
/* Check whether or not the hardware watchdog is there */ /* Check whether or not the hardware watchdog is there */
if (ali_find_watchdog() != 0) { if (ali_find_watchdog() != 0)
return -ENODEV; return -ENODEV;
}
/* Check that the timeout value is within it's range ; if not reset to the default */ /* Check that the timeout value is within it's range;
if not reset to the default */
if (timeout < 1 || timeout >= 18000) { if (timeout < 1 || timeout >= 18000) {
timeout = WATCHDOG_TIMEOUT; timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 0<timeout<18000, using %d\n", printk(KERN_INFO PFX
timeout); "timeout value must be 0 < timeout < 18000, using %d\n",
timeout);
} }
/* Calculate the watchdog's timeout */ /* Calculate the watchdog's timeout */
...@@ -415,15 +410,16 @@ static int __init watchdog_init(void) ...@@ -415,15 +410,16 @@ static int __init watchdog_init(void)
ret = register_reboot_notifier(&ali_notifier); ret = register_reboot_notifier(&ali_notifier);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
goto out; goto out;
} }
ret = misc_register(&ali_miscdev); ret = misc_register(&ali_miscdev);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_reboot; goto unreg_reboot;
} }
......
...@@ -32,8 +32,8 @@ ...@@ -32,8 +32,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define OUR_NAME "alim7101_wdt" #define OUR_NAME "alim7101_wdt"
...@@ -60,13 +60,17 @@ ...@@ -60,13 +60,17 @@
*/ */
#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
static int timeout = WATCHDOG_TIMEOUT;
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */ static int use_gpio; /* Use the pic (for a1d revision alim7101) */
module_param(use_gpio, int, 0); module_param(use_gpio, int, 0);
MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)"); MODULE_PARM_DESC(use_gpio,
"Use the gpio watchdog (required by old cobalt boards).");
static void wdt_timer_ping(unsigned long); static void wdt_timer_ping(unsigned long);
static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1); static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1);
...@@ -77,8 +81,9 @@ static struct pci_dev *alim7101_pmu; ...@@ -77,8 +81,9 @@ static struct pci_dev *alim7101_pmu;
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" MODULE_PARM_DESC(nowayout,
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Whack the dog * Whack the dog
...@@ -89,23 +94,26 @@ static void wdt_timer_ping(unsigned long data) ...@@ -89,23 +94,26 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL /* If we got a heartbeat pulse within the WDT_US_INTERVAL
* we agree to ping the WDT * we agree to ping the WDT
*/ */
char tmp; char tmp;
if(time_before(jiffies, next_heartbeat)) if (time_before(jiffies, next_heartbeat)) {
{
/* Ping the WDT (this is actually a disarm/arm sequence) */ /* Ping the WDT (this is actually a disarm/arm sequence) */
pci_read_config_byte(alim7101_pmu, 0x92, &tmp); pci_read_config_byte(alim7101_pmu, 0x92, &tmp);
pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); pci_write_config_byte(alim7101_pmu,
pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
pci_write_config_byte(alim7101_pmu,
ALI_7101_WDT, (tmp | ALI_WDT_ARM));
if (use_gpio) { if (use_gpio) {
pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); pci_read_config_byte(alim7101_pmu,
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp ALI_7101_GPIO_O, &tmp);
| 0x20); pci_write_config_byte(alim7101_pmu,
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp ALI_7101_GPIO_O, tmp | 0x20);
& ~0x20); pci_write_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, tmp & ~0x20);
} }
} else { } else {
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); printk(KERN_WARNING PFX
"Heartbeat lost! Will not ping the watchdog\n");
} }
/* Re-set the timer interval */ /* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL); mod_timer(&timer, jiffies + WDT_INTERVAL);
...@@ -121,17 +129,23 @@ static void wdt_change(int writeval) ...@@ -121,17 +129,23 @@ static void wdt_change(int writeval)
pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp); pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp);
if (writeval == WDT_ENABLE) { if (writeval == WDT_ENABLE) {
pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); pci_write_config_byte(alim7101_pmu,
ALI_7101_WDT, (tmp | ALI_WDT_ARM));
if (use_gpio) { if (use_gpio) {
pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); pci_read_config_byte(alim7101_pmu,
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20); ALI_7101_GPIO_O, &tmp);
pci_write_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, tmp & ~0x20);
} }
} else { } else {
pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); pci_write_config_byte(alim7101_pmu,
ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
if (use_gpio) { if (use_gpio) {
pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); pci_read_config_byte(alim7101_pmu,
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20); ALI_7101_GPIO_O, &tmp);
pci_write_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, tmp | 0x20);
} }
} }
} }
...@@ -169,10 +183,11 @@ static void wdt_keepalive(void) ...@@ -169,10 +183,11 @@ static void wdt_keepalive(void)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) static ssize_t fop_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) { if (count) {
if (!nowayout) { if (!nowayout) {
size_t ofs; size_t ofs;
...@@ -195,119 +210,116 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou ...@@ -195,119 +210,116 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
return count; return count;
} }
static int fop_open(struct inode * inode, struct file * file) static int fop_open(struct inode *inode, struct file *file)
{ {
/* Just in case we're already talking to someone... */ /* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open)) if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
/* Good, fire up the show */ /* Good, fire up the show */
wdt_startup(); wdt_startup();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int fop_close(struct inode * inode, struct file * file) static int fop_close(struct inode *inode, struct file *file)
{ {
if(wdt_expect_close == 42) if (wdt_expect_close == 42)
wdt_turnoff(); wdt_turnoff();
else { else {
/* wim: shouldn't there be a: del_timer(&timer); */ /* wim: shouldn't there be a: del_timer(&timer); */
printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); printk(KERN_CRIT PFX
"device file closed unexpectedly. Will not stop the WDT!\n");
} }
clear_bit(0, &wdt_is_open); clear_bit(0, &wdt_is_open);
wdt_expect_close = 0; wdt_expect_close = 0;
return 0; return 0;
} }
static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = static struct watchdog_info ident = {
{ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "ALiM7101", .identity = "ALiM7101",
}; };
switch(cmd) switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{ {
case WDIOC_GETSUPPORT: int new_options, retval = -EINVAL;
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if(get_user(new_options, p))
return -EFAULT;
if(new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
if(new_options & WDIOS_ENABLECARD) {
wdt_startup();
retval = 0;
}
return retval; if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
} }
case WDIOC_SETTIMEOUT: if (new_options & WDIOS_ENABLECARD) {
{ wdt_startup();
int new_timeout; retval = 0;
if(get_user(new_timeout, p))
return -EFAULT;
if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
return -EINVAL;
timeout = new_timeout;
wdt_keepalive();
/* Fall through */
} }
case WDIOC_GETTIMEOUT: return retval;
return put_user(timeout, p); }
default: case WDIOC_SETTIMEOUT:
return -ENOTTY; {
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
/* arbitrary upper limit */
if (new_timeout < 1 || new_timeout > 3600)
return -EINVAL;
timeout = new_timeout;
wdt_keepalive();
/* Fall through */
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
} }
} }
static const struct file_operations wdt_fops = { static const struct file_operations wdt_fops = {
.owner= THIS_MODULE, .owner = THIS_MODULE,
.llseek= no_llseek, .llseek = no_llseek,
.write= fop_write, .write = fop_write,
.open= fop_open, .open = fop_open,
.release= fop_close, .release = fop_close,
.ioctl= fop_ioctl, .unlocked_ioctl = fop_ioctl,
}; };
static struct miscdevice wdt_miscdev = { static struct miscdevice wdt_miscdev = {
.minor=WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name="watchdog", .name = "watchdog",
.fops=&wdt_fops, .fops = &wdt_fops,
}; };
/* /*
* Notifier for system down * Notifier for system down
*/ */
static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) static int wdt_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{ {
if (code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
wdt_turnoff(); wdt_turnoff();
if (code==SYS_RESTART) { if (code == SYS_RESTART) {
/* /*
* Cobalt devices have no way of rebooting themselves other than * Cobalt devices have no way of rebooting themselves other
* getting the watchdog to pull reset, so we restart the watchdog on * than getting the watchdog to pull reset, so we restart the
* reboot with no heartbeat * watchdog on reboot with no heartbeat
*/ */
wdt_change(WDT_ENABLE); wdt_change(WDT_ENABLE);
printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n"); printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n");
...@@ -320,8 +332,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void ...@@ -320,8 +332,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void
* turn the timebomb registers off. * turn the timebomb registers off.
*/ */
static struct notifier_block wdt_notifier= static struct notifier_block wdt_notifier = {
{
.notifier_call = wdt_notify_sys, .notifier_call = wdt_notify_sys,
}; };
...@@ -354,7 +365,8 @@ static int __init alim7101_wdt_init(void) ...@@ -354,7 +365,8 @@ static int __init alim7101_wdt_init(void)
ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
NULL); NULL);
if (!ali1543_south) { if (!ali1543_south) {
printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n"); printk(KERN_INFO PFX
"ALi 1543 South-Bridge not present - WDT not set\n");
goto err_out; goto err_out;
} }
pci_read_config_byte(ali1543_south, 0x5e, &tmp); pci_read_config_byte(ali1543_south, 0x5e, &tmp);
...@@ -363,24 +375,25 @@ static int __init alim7101_wdt_init(void) ...@@ -363,24 +375,25 @@ static int __init alim7101_wdt_init(void)
if (!use_gpio) { if (!use_gpio) {
printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
goto err_out; goto err_out;
} }
nowayout = 1; nowayout = 1;
} else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
goto err_out; goto err_out;
} }
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ if (timeout < 1 || timeout > 3600) {
{ /* arbitrary upper limit */
timeout = WATCHDOG_TIMEOUT; timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", printk(KERN_INFO PFX
timeout); "timeout value must be 1 <= x <= 3600, using %d\n",
timeout);
} }
rc = register_reboot_notifier(&wdt_notifier); rc = register_reboot_notifier(&wdt_notifier);
if (rc) { if (rc) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
rc); "cannot register reboot notifier (err=%d)\n", rc);
goto err_out; goto err_out;
} }
...@@ -391,9 +404,8 @@ static int __init alim7101_wdt_init(void) ...@@ -391,9 +404,8 @@ static int __init alim7101_wdt_init(void)
goto err_out_reboot; goto err_out_reboot;
} }
if (nowayout) { if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
}
printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout); timeout, nowayout);
......
...@@ -212,8 +212,8 @@ static struct watchdog_info at32_wdt_info = { ...@@ -212,8 +212,8 @@ static struct watchdog_info at32_wdt_info = {
/* /*
* Handle commands from user-space. * Handle commands from user-space.
*/ */
static int at32_wdt_ioctl(struct inode *inode, struct file *file, static long at32_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
int time; int time;
...@@ -298,7 +298,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data, ...@@ -298,7 +298,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data,
static const struct file_operations at32_wdt_fops = { static const struct file_operations at32_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = at32_wdt_ioctl, .unlocked_ioctl = at32_wdt_ioctl,
.open = at32_wdt_open, .open = at32_wdt_open,
.release = at32_wdt_close, .release = at32_wdt_close,
.write = at32_wdt_write, .write = at32_wdt_write,
...@@ -391,7 +391,6 @@ static int __exit at32_wdt_remove(struct platform_device *pdev) ...@@ -391,7 +391,6 @@ static int __exit at32_wdt_remove(struct platform_device *pdev)
wdt = NULL; wdt = NULL;
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
} }
return 0; return 0;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/arch/at91_st.h> #include <asm/arch/at91_st.h>
...@@ -31,11 +31,14 @@ static int wdt_time = WDT_DEFAULT_TIME; ...@@ -31,11 +31,14 @@ static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0); module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
__MODULE_STRING(WDT_DEFAULT_TIME) ")");
#ifdef CONFIG_WATCHDOG_NOWAYOUT #ifdef CONFIG_WATCHDOG_NOWAYOUT
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#endif #endif
...@@ -46,7 +49,7 @@ static unsigned long at91wdt_busy; ...@@ -46,7 +49,7 @@ static unsigned long at91wdt_busy;
/* /*
* Disable the watchdog. * Disable the watchdog.
*/ */
static void inline at91_wdt_stop(void) static inline void at91_wdt_stop(void)
{ {
at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN); at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
} }
...@@ -54,16 +57,17 @@ static void inline at91_wdt_stop(void) ...@@ -54,16 +57,17 @@ static void inline at91_wdt_stop(void)
/* /*
* Enable and reset the watchdog. * Enable and reset the watchdog.
*/ */
static void inline at91_wdt_start(void) static inline void at91_wdt_start(void)
{ {
at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV)); at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN |
(((65536 * wdt_time) >> 8) & AT91_ST_WDV));
at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
} }
/* /*
* Reload the watchdog timer. (ie, pat the watchdog) * Reload the watchdog timer. (ie, pat the watchdog)
*/ */
static void inline at91_wdt_reload(void) static inline void at91_wdt_reload(void)
{ {
at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
} }
...@@ -89,8 +93,9 @@ static int at91_wdt_open(struct inode *inode, struct file *file) ...@@ -89,8 +93,9 @@ static int at91_wdt_open(struct inode *inode, struct file *file)
*/ */
static int at91_wdt_close(struct inode *inode, struct file *file) static int at91_wdt_close(struct inode *inode, struct file *file)
{ {
/* Disable the watchdog when file is closed */
if (!nowayout) if (!nowayout)
at91_wdt_stop(); /* Disable the watchdog when file is closed */ at91_wdt_stop();
clear_bit(0, &at91wdt_busy); clear_bit(0, &at91wdt_busy);
return 0; return 0;
...@@ -110,7 +115,8 @@ static int at91_wdt_settimeout(int new_time) ...@@ -110,7 +115,8 @@ static int at91_wdt_settimeout(int new_time)
if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
return -EINVAL; return -EINVAL;
/* Set new watchdog time. It will be used when at91_wdt_start() is called. */ /* Set new watchdog time. It will be used when
at91_wdt_start() is called. */
wdt_time = new_time; wdt_time = new_time;
return 0; return 0;
} }
...@@ -123,60 +129,52 @@ static struct watchdog_info at91_wdt_info = { ...@@ -123,60 +129,52 @@ static struct watchdog_info at91_wdt_info = {
/* /*
* Handle commands from user-space. * Handle commands from user-space.
*/ */
static int at91_wdt_ioctl(struct inode *inode, struct file *file, static long at91_wdt_ioct(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_value; int new_value;
switch(cmd) { switch (cmd) {
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
at91_wdt_reload(); /* pat the watchdog */ at91_wdt_reload(); /* pat the watchdog */
return 0; return 0;
case WDIOC_GETSUPPORT:
case WDIOC_GETSUPPORT: return copy_to_user(argp, &at91_wdt_info,
return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0; sizeof(at91_wdt_info)) ? -EFAULT : 0;
case WDIOC_SETTIMEOUT:
case WDIOC_SETTIMEOUT: if (get_user(new_value, p))
if (get_user(new_value, p)) return -EFAULT;
return -EFAULT; if (at91_wdt_settimeout(new_value))
return -EINVAL;
if (at91_wdt_settimeout(new_value)) /* Enable new time value */
return -EINVAL; at91_wdt_start();
/* Return current value */
/* Enable new time value */ return put_user(wdt_time, p);
case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p);
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(new_value, p))
return -EFAULT;
if (new_value & WDIOS_DISABLECARD)
at91_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
at91_wdt_start(); at91_wdt_start();
return 0;
/* Return current value */ default:
return put_user(wdt_time, p); return -ENOTTY;
case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p);
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(new_value, p))
return -EFAULT;
if (new_value & WDIOS_DISABLECARD)
at91_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
at91_wdt_start();
return 0;
default:
return -ENOTTY;
} }
} }
/* /*
* Pat the watchdog whenever device is written to. * Pat the watchdog whenever device is written to.
*/ */
static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) static ssize_t at91_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{ {
at91_wdt_reload(); /* pat the watchdog */ at91_wdt_reload(); /* pat the watchdog */
return len; return len;
...@@ -187,7 +185,7 @@ static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, l ...@@ -187,7 +185,7 @@ static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, l
static const struct file_operations at91wdt_fops = { static const struct file_operations at91wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = at91_wdt_ioctl, .unlocked_ioctl = at91_wdt_ioctl,
.open = at91_wdt_open, .open = at91_wdt_open,
.release = at91_wdt_close, .release = at91_wdt_close,
.write = at91_wdt_write, .write = at91_wdt_write,
...@@ -211,7 +209,8 @@ static int __init at91wdt_probe(struct platform_device *pdev) ...@@ -211,7 +209,8 @@ static int __init at91wdt_probe(struct platform_device *pdev)
if (res) if (res)
return res; return res;
printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); printk(KERN_INFO "AT91 Watchdog Timer enabled (%d seconds%s)\n",
wdt_time, nowayout ? ", nowayout" : "");
return 0; return 0;
} }
...@@ -265,7 +264,8 @@ static struct platform_driver at91wdt_driver = { ...@@ -265,7 +264,8 @@ static struct platform_driver at91wdt_driver = {
static int __init at91_wdt_init(void) static int __init at91_wdt_init(void)
{ {
/* Check that the heartbeat value is within range; if not reset to the default */ /* Check that the heartbeat value is within range;
if not reset to the default */
if (at91_wdt_settimeout(wdt_time)) { if (at91_wdt_settimeout(wdt_time)) {
at91_wdt_settimeout(WDT_DEFAULT_TIME); at91_wdt_settimeout(WDT_DEFAULT_TIME);
pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) #define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am") #define stampit() stamp("here i am")
...@@ -148,7 +148,8 @@ static int bfin_wdt_set_timeout(unsigned long t) ...@@ -148,7 +148,8 @@ static int bfin_wdt_set_timeout(unsigned long t)
int run = bfin_wdt_running(); int run = bfin_wdt_running();
bfin_wdt_stop(); bfin_wdt_stop();
bfin_write_WDOG_CNT(cnt); bfin_write_WDOG_CNT(cnt);
if (run) bfin_wdt_start(); if (run)
bfin_wdt_start();
} }
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
...@@ -191,16 +192,15 @@ static int bfin_wdt_release(struct inode *inode, struct file *file) ...@@ -191,16 +192,15 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
{ {
stampit(); stampit();
if (expect_close == 42) { if (expect_close == 42)
bfin_wdt_stop(); bfin_wdt_stop();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
bfin_wdt_keepalive(); bfin_wdt_keepalive();
} }
expect_close = 0; expect_close = 0;
clear_bit(0, &open_check); clear_bit(0, &open_check);
return 0; return 0;
} }
...@@ -214,7 +214,7 @@ static int bfin_wdt_release(struct inode *inode, struct file *file) ...@@ -214,7 +214,7 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
* Pings the watchdog on write. * Pings the watchdog on write.
*/ */
static ssize_t bfin_wdt_write(struct file *file, const char __user *data, static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
stampit(); stampit();
...@@ -241,7 +241,6 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data, ...@@ -241,7 +241,6 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
/** /**
* bfin_wdt_ioctl - Query Device * bfin_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device * @file: file handle of device
* @cmd: watchdog command * @cmd: watchdog command
* @arg: argument * @arg: argument
...@@ -249,8 +248,8 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data, ...@@ -249,8 +248,8 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
* Query basic information from the device or ping it, as outlined by the * Query basic information from the device or ping it, as outlined by the
* watchdog API. * watchdog API.
*/ */
static int bfin_wdt_ioctl(struct inode *inode, struct file *file, static long bfin_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -258,59 +257,49 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -258,59 +257,49 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
stampit(); stampit();
switch (cmd) { switch (cmd) {
default: case WDIOC_GETSUPPORT:
return -ENOTTY; if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
return -EFAULT;
case WDIOC_GETSUPPORT: else
if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
return -EFAULT;
else
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
case WDIOC_KEEPALIVE:
bfin_wdt_keepalive();
return 0; return 0;
case WDIOC_GETSTATUS:
case WDIOC_SETTIMEOUT: { case WDIOC_GETBOOTSTATUS:
int new_timeout; return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
case WDIOC_KEEPALIVE:
if (get_user(new_timeout, p)) bfin_wdt_keepalive();
return -EFAULT; return 0;
case WDIOC_SETTIMEOUT: {
if (bfin_wdt_set_timeout(new_timeout)) int new_timeout;
return -EINVAL;
if (get_user(new_timeout, p))
return -EFAULT;
if (bfin_wdt_set_timeout(new_timeout))
return -EINVAL;
}
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS: {
unsigned long flags;
int options, ret = -EINVAL;
if (get_user(options, p))
return -EFAULT;
spin_lock_irqsave(&bfin_wdt_spinlock, flags);
if (options & WDIOS_DISABLECARD) {
bfin_wdt_stop();
ret = 0;
} }
/* Fall */ if (options & WDIOS_ENABLECARD) {
case WDIOC_GETTIMEOUT: bfin_wdt_start();
return put_user(timeout, p); ret = 0;
case WDIOC_SETOPTIONS: {
unsigned long flags;
int options, ret = -EINVAL;
if (get_user(options, p))
return -EFAULT;
spin_lock_irqsave(&bfin_wdt_spinlock, flags);
if (options & WDIOS_DISABLECARD) {
bfin_wdt_stop();
ret = 0;
}
if (options & WDIOS_ENABLECARD) {
bfin_wdt_start();
ret = 0;
}
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
return ret;
} }
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
return ret;
}
default:
return -ENOTTY;
} }
} }
...@@ -323,8 +312,8 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -323,8 +312,8 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
* Handles specific events, such as turning off the watchdog during a * Handles specific events, such as turning off the watchdog during a
* shutdown event. * shutdown event.
*/ */
static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code, static int bfin_wdt_notify_sys(struct notifier_block *this,
void *unused) unsigned long code, void *unused)
{ {
stampit(); stampit();
...@@ -379,12 +368,12 @@ static int bfin_wdt_resume(struct platform_device *pdev) ...@@ -379,12 +368,12 @@ static int bfin_wdt_resume(struct platform_device *pdev)
#endif #endif
static const struct file_operations bfin_wdt_fops = { static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = bfin_wdt_write, .write = bfin_wdt_write,
.ioctl = bfin_wdt_ioctl, .unlocked_ioctl = bfin_wdt_ioctl,
.open = bfin_wdt_open, .open = bfin_wdt_open,
.release = bfin_wdt_release, .release = bfin_wdt_release,
}; };
static struct miscdevice bfin_wdt_miscdev = { static struct miscdevice bfin_wdt_miscdev = {
...@@ -396,8 +385,8 @@ static struct miscdevice bfin_wdt_miscdev = { ...@@ -396,8 +385,8 @@ static struct miscdevice bfin_wdt_miscdev = {
static struct watchdog_info bfin_wdt_info = { static struct watchdog_info bfin_wdt_info = {
.identity = "Blackfin Watchdog", .identity = "Blackfin Watchdog",
.options = WDIOF_SETTIMEOUT | .options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
}; };
static struct notifier_block bfin_wdt_notifier = { static struct notifier_block bfin_wdt_notifier = {
...@@ -416,14 +405,16 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev) ...@@ -416,14 +405,16 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
ret = register_reboot_notifier(&bfin_wdt_notifier); ret = register_reboot_notifier(&bfin_wdt_notifier);
if (ret) { if (ret) {
pr_devinit(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); pr_devinit(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
return ret; return ret;
} }
ret = misc_register(&bfin_wdt_miscdev); ret = misc_register(&bfin_wdt_miscdev);
if (ret) { if (ret) {
pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", pr_devinit(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&bfin_wdt_notifier); unregister_reboot_notifier(&bfin_wdt_notifier);
return ret; return ret;
} }
...@@ -516,7 +507,11 @@ MODULE_LICENSE("GPL"); ...@@ -516,7 +507,11 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
module_param(timeout, uint, 0); module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <asm/reg_booke.h> #include <asm/reg_booke.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
/* If the kernel parameter wdt=1, the watchdog will be enabled at boot. /* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
*/ */
#ifdef CONFIG_FSL_BOOKE #ifdef CONFIG_FSL_BOOKE
#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */ #define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */
#else #else
#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ #define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
#endif /* for timing information */ #endif /* for timing information */
...@@ -82,16 +82,15 @@ static struct watchdog_info ident = { ...@@ -82,16 +82,15 @@ static struct watchdog_info ident = {
.identity = "PowerPC Book-E Watchdog", .identity = "PowerPC Book-E Watchdog",
}; };
static int booke_wdt_ioctl(struct inode *inode, struct file *file, static long booke_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
u32 tmp = 0; u32 tmp = 0;
u32 __user *p = (u32 __user *)arg; u32 __user *p = (u32 __user *)arg;
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info __user *)arg, &ident, if (copy_to_user(arg, &ident, sizeof(struct watchdog_info)))
sizeof(struct watchdog_info)))
return -EFAULT; return -EFAULT;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
return put_user(ident.options, p); return put_user(ident.options, p);
...@@ -106,7 +105,8 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -106,7 +105,8 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(booke_wdt_period, p)) if (get_user(booke_wdt_period, p))
return -EFAULT; return -EFAULT;
mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period)); mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP(0)) |
WDTP(booke_wdt_period));
return 0; return 0;
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(booke_wdt_period, p); return put_user(booke_wdt_period, p);
...@@ -132,8 +132,9 @@ static int booke_wdt_open(struct inode *inode, struct file *file) ...@@ -132,8 +132,9 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
if (booke_wdt_enabled == 0) { if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1; booke_wdt_enabled = 1;
on_each_cpu(__booke_wdt_enable, NULL, 0); on_each_cpu(__booke_wdt_enable, NULL, 0);
printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " printk(KERN_INFO
"(wdt_period=%d)\n", booke_wdt_period); "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
booke_wdt_period);
} }
spin_unlock(&booke_wdt_lock); spin_unlock(&booke_wdt_lock);
...@@ -144,7 +145,7 @@ static const struct file_operations booke_wdt_fops = { ...@@ -144,7 +145,7 @@ static const struct file_operations booke_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = booke_wdt_write, .write = booke_wdt_write,
.ioctl = booke_wdt_ioctl, .unlocked_ioctl = booke_wdt_ioctl,
.open = booke_wdt_open, .open = booke_wdt_open,
}; };
...@@ -175,8 +176,9 @@ static int __init booke_wdt_init(void) ...@@ -175,8 +176,9 @@ static int __init booke_wdt_init(void)
spin_lock(&booke_wdt_lock); spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) { if (booke_wdt_enabled == 1) {
printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " printk(KERN_INFO
"(wdt_period=%d)\n", booke_wdt_period); "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
booke_wdt_period);
on_each_cpu(__booke_wdt_enable, NULL, 0); on_each_cpu(__booke_wdt_enable, NULL, 0);
} }
spin_unlock(&booke_wdt_lock); spin_unlock(&booke_wdt_lock);
......
...@@ -30,16 +30,16 @@ ...@@ -30,16 +30,16 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
/* adjustable parameters */ /* adjustable parameters */
static int verbose = 0; static int verbose;
static int port = 0x91; static int port = 0x91;
static int ticks = 10000; static int ticks = 10000;
static spinlock_t cpu5wdt_lock;
#define PFX "cpu5wdt: " #define PFX "cpu5wdt: "
...@@ -70,12 +70,13 @@ static struct { ...@@ -70,12 +70,13 @@ static struct {
static void cpu5wdt_trigger(unsigned long unused) static void cpu5wdt_trigger(unsigned long unused)
{ {
if ( verbose > 2 ) if (verbose > 2)
printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks); printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
if( cpu5wdt_device.running ) if (cpu5wdt_device.running)
ticks--; ticks--;
spin_lock(&cpu5wdt_lock);
/* keep watchdog alive */ /* keep watchdog alive */
outb(1, port + CPU5WDT_TRIGGER_REG); outb(1, port + CPU5WDT_TRIGGER_REG);
...@@ -86,6 +87,7 @@ static void cpu5wdt_trigger(unsigned long unused) ...@@ -86,6 +87,7 @@ static void cpu5wdt_trigger(unsigned long unused)
/* ticks doesn't matter anyway */ /* ticks doesn't matter anyway */
complete(&cpu5wdt_device.stop); complete(&cpu5wdt_device.stop);
} }
spin_unlock(&cpu5wdt_lock);
} }
...@@ -93,14 +95,17 @@ static void cpu5wdt_reset(void) ...@@ -93,14 +95,17 @@ static void cpu5wdt_reset(void)
{ {
ticks = cpu5wdt_device.default_ticks; ticks = cpu5wdt_device.default_ticks;
if ( verbose ) if (verbose)
printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks); printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
} }
static void cpu5wdt_start(void) static void cpu5wdt_start(void)
{ {
if ( !cpu5wdt_device.queue ) { unsigned long flags;
spin_lock_irqsave(&cpu5wdt_lock, flags);
if (!cpu5wdt_device.queue) {
cpu5wdt_device.queue = 1; cpu5wdt_device.queue = 1;
outb(0, port + CPU5WDT_TIME_A_REG); outb(0, port + CPU5WDT_TIME_A_REG);
outb(0, port + CPU5WDT_TIME_B_REG); outb(0, port + CPU5WDT_TIME_B_REG);
...@@ -111,18 +116,20 @@ static void cpu5wdt_start(void) ...@@ -111,18 +116,20 @@ static void cpu5wdt_start(void)
} }
/* if process dies, counter is not decremented */ /* if process dies, counter is not decremented */
cpu5wdt_device.running++; cpu5wdt_device.running++;
spin_unlock_irqrestore(&cpu5wdt_lock, flags);
} }
static int cpu5wdt_stop(void) static int cpu5wdt_stop(void)
{ {
if ( cpu5wdt_device.running ) unsigned long flags;
cpu5wdt_device.running = 0;
spin_lock_irqsave(&cpu5wdt_lock, flags);
if (cpu5wdt_device.running)
cpu5wdt_device.running = 0;
ticks = cpu5wdt_device.default_ticks; ticks = cpu5wdt_device.default_ticks;
spin_unlock_irqrestore(&cpu5wdt_lock, flags);
if ( verbose ) if (verbose)
printk(KERN_CRIT PFX "stop not possible\n"); printk(KERN_CRIT PFX "stop not possible\n");
return -EIO; return -EIO;
} }
...@@ -130,9 +137,8 @@ static int cpu5wdt_stop(void) ...@@ -130,9 +137,8 @@ static int cpu5wdt_stop(void)
static int cpu5wdt_open(struct inode *inode, struct file *file) static int cpu5wdt_open(struct inode *inode, struct file *file)
{ {
if ( test_and_set_bit(0, &cpu5wdt_device.inuse) ) if (test_and_set_bit(0, &cpu5wdt_device.inuse))
return -EBUSY; return -EBUSY;
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -142,67 +148,58 @@ static int cpu5wdt_release(struct inode *inode, struct file *file) ...@@ -142,67 +148,58 @@ static int cpu5wdt_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static long cpu5wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp;
unsigned int value; unsigned int value;
static struct watchdog_info ident = static struct watchdog_info ident = {
{
.options = WDIOF_CARDRESET, .options = WDIOF_CARDRESET,
.identity = "CPU5 WDT", .identity = "CPU5 WDT",
}; };
switch(cmd) { switch (cmd) {
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
cpu5wdt_reset(); cpu5wdt_reset();
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
value = inb(port + CPU5WDT_STATUS_REG); value = inb(port + CPU5WDT_STATUS_REG);
value = (value >> 2) & 1; value = (value >> 2) & 1;
if ( copy_to_user(argp, &value, sizeof(int)) ) return put_user(value, p);
return -EFAULT; case WDIOC_GETBOOTSTATUS:
break; return put_user(0, p);
case WDIOC_GETBOOTSTATUS: case WDIOC_GETSUPPORT:
if ( copy_to_user(argp, &value, sizeof(int)) ) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETSUPPORT: case WDIOC_SETOPTIONS:
if ( copy_to_user(argp, &ident, sizeof(ident)) ) if (get_user(value, p))
return -EFAULT; return -EFAULT;
break; if (value & WDIOS_ENABLECARD)
case WDIOC_SETOPTIONS: cpu5wdt_start();
if ( copy_from_user(&value, argp, sizeof(int)) ) if (value & WDIOS_DISABLECARD)
return -EFAULT; cpu5wdt_stop();
switch(value) { break;
case WDIOS_ENABLECARD: default:
cpu5wdt_start(); return -ENOTTY;
break;
case WDIOS_DISABLECARD:
return cpu5wdt_stop();
default:
return -EINVAL;
}
break;
default:
return -ENOTTY;
} }
return 0; return 0;
} }
static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) static ssize_t cpu5wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
if ( !count ) if (!count)
return -EIO; return -EIO;
cpu5wdt_reset(); cpu5wdt_reset();
return count; return count;
} }
static const struct file_operations cpu5wdt_fops = { static const struct file_operations cpu5wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = cpu5wdt_ioctl, .unlocked_ioctl = cpu5wdt_ioctl,
.open = cpu5wdt_open, .open = cpu5wdt_open,
.write = cpu5wdt_write, .write = cpu5wdt_write,
.release = cpu5wdt_release, .release = cpu5wdt_release,
...@@ -221,37 +218,36 @@ static int __devinit cpu5wdt_init(void) ...@@ -221,37 +218,36 @@ static int __devinit cpu5wdt_init(void)
unsigned int val; unsigned int val;
int err; int err;
if ( verbose ) if (verbose)
printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose); printk(KERN_DEBUG PFX
"port=0x%x, verbose=%i\n", port, verbose);
if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) { init_completion(&cpu5wdt_device.stop);
spin_lock_init(&cpu5wdt_lock);
cpu5wdt_device.queue = 0;
setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0);
cpu5wdt_device.default_ticks = ticks;
if (!request_region(port, CPU5WDT_EXTENT, PFX)) {
printk(KERN_ERR PFX "request_region failed\n"); printk(KERN_ERR PFX "request_region failed\n");
err = -EBUSY; err = -EBUSY;
goto no_port; goto no_port;
} }
if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
printk(KERN_ERR PFX "misc_register failed\n");
goto no_misc;
}
/* watchdog reboot? */ /* watchdog reboot? */
val = inb(port + CPU5WDT_STATUS_REG); val = inb(port + CPU5WDT_STATUS_REG);
val = (val >> 2) & 1; val = (val >> 2) & 1;
if ( !val ) if (!val)
printk(KERN_INFO PFX "sorry, was my fault\n"); printk(KERN_INFO PFX "sorry, was my fault\n");
init_completion(&cpu5wdt_device.stop); err = misc_register(&cpu5wdt_misc);
cpu5wdt_device.queue = 0; if (err < 0) {
printk(KERN_ERR PFX "misc_register failed\n");
clear_bit(0, &cpu5wdt_device.inuse); goto no_misc;
}
setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0);
cpu5wdt_device.default_ticks = ticks;
printk(KERN_INFO PFX "init success\n"); printk(KERN_INFO PFX "init success\n");
return 0; return 0;
no_misc: no_misc:
...@@ -267,7 +263,7 @@ static int __devinit cpu5wdt_init_module(void) ...@@ -267,7 +263,7 @@ static int __devinit cpu5wdt_init_module(void)
static void __devexit cpu5wdt_exit(void) static void __devexit cpu5wdt_exit(void)
{ {
if ( cpu5wdt_device.queue ) { if (cpu5wdt_device.queue) {
cpu5wdt_device.queue = 0; cpu5wdt_device.queue = 0;
wait_for_completion(&cpu5wdt_device.stop); wait_for_completion(&cpu5wdt_device.stop);
} }
......
...@@ -22,10 +22,10 @@ ...@@ -22,10 +22,10 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define MODULE_NAME "DAVINCI-WDT: " #define MODULE_NAME "DAVINCI-WDT: "
...@@ -143,9 +143,8 @@ static struct watchdog_info ident = { ...@@ -143,9 +143,8 @@ static struct watchdog_info ident = {
.identity = "DaVinci Watchdog", .identity = "DaVinci Watchdog",
}; };
static int static long davinci_wdt_ioctl(struct file *file,
davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
...@@ -184,7 +183,7 @@ static const struct file_operations davinci_wdt_fops = { ...@@ -184,7 +183,7 @@ static const struct file_operations davinci_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = davinci_wdt_write, .write = davinci_wdt_write,
.ioctl = davinci_wdt_ioctl, .unlocked_ioctl = davinci_wdt_ioctl,
.open = davinci_wdt_open, .open = davinci_wdt_open,
.release = davinci_wdt_release, .release = davinci_wdt_release,
}; };
......
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/uaccess.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
#define WDT_VERSION "0.3" #define WDT_VERSION "0.3"
#define PFX "ep93xx_wdt: " #define PFX "ep93xx_wdt: "
...@@ -136,9 +136,8 @@ static struct watchdog_info ident = { ...@@ -136,9 +136,8 @@ static struct watchdog_info ident = {
.identity = "EP93xx Watchdog", .identity = "EP93xx Watchdog",
}; };
static int static long ep93xx_wdt_ioctl(struct file *file,
ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
...@@ -174,8 +173,8 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file) ...@@ -174,8 +173,8 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_shutdown(); wdt_shutdown();
else else
printk(KERN_CRIT PFX "Device closed unexpectedly - " printk(KERN_CRIT PFX
"timer will not stop\n"); "Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
...@@ -186,7 +185,7 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file) ...@@ -186,7 +185,7 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file)
static const struct file_operations ep93xx_wdt_fops = { static const struct file_operations ep93xx_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.write = ep93xx_wdt_write, .write = ep93xx_wdt_write,
.ioctl = ep93xx_wdt_ioctl, .unlocked_ioctl = ep93xx_wdt_ioctl,
.open = ep93xx_wdt_open, .open = ep93xx_wdt_open,
.release = ep93xx_wdt_release, .release = ep93xx_wdt_release,
}; };
...@@ -243,7 +242,9 @@ module_param(nowayout, int, 0); ...@@ -243,7 +242,9 @@ module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>," MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
"Alessandro Zummo <a.zummo@towertech.it>"); "Alessandro Zummo <a.zummo@towertech.it>");
......
...@@ -56,14 +56,15 @@ ...@@ -56,14 +56,15 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
static unsigned long eurwdt_is_open; static unsigned long eurwdt_is_open;
static int eurwdt_timeout; static int eurwdt_timeout;
static char eur_expect_close; static char eur_expect_close;
static spinlock_t eurwdt_lock;
/* /*
* You must set these - there is no sane way to probe for this board. * You must set these - there is no sane way to probe for this board.
...@@ -78,7 +79,9 @@ static char *ev = "int"; ...@@ -78,7 +79,9 @@ static char *ev = "int";
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Some symbolic names * Some symbolic names
...@@ -137,7 +140,8 @@ static void eurwdt_activate_timer(void) ...@@ -137,7 +140,8 @@ static void eurwdt_activate_timer(void)
{ {
eurwdt_disable_timer(); eurwdt_disable_timer();
eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */ eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */
eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT); eurwdt_write_reg(WDT_OUTPIN_CFG,
!strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT);
/* Setting interrupt line */ /* Setting interrupt line */
if (irq == 2 || irq > 15 || irq < 0) { if (irq == 2 || irq > 15 || irq < 0) {
...@@ -206,21 +210,21 @@ size_t count, loff_t *ppos) ...@@ -206,21 +210,21 @@ size_t count, loff_t *ppos)
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))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
eur_expect_close = 42; eur_expect_close = 42;
} }
} }
spin_lock(&eurwdt_lock);
eurwdt_ping(); /* the default timeout */ eurwdt_ping(); /* the default timeout */
spin_unlock(&eurwdt_lock);
} }
return count; return count;
} }
/** /**
* eurwdt_ioctl: * eurwdt_ioctl:
* @inode: inode of the device
* @file: file handle to the device * @file: file handle to the device
* @cmd: watchdog command * @cmd: watchdog command
* @arg: argument pointer * @arg: argument pointer
...@@ -229,13 +233,14 @@ size_t count, loff_t *ppos) ...@@ -229,13 +233,14 @@ size_t count, loff_t *ppos)
* according to their available features. * according to their available features.
*/ */
static int eurwdt_ioctl(struct inode *inode, struct file *file, static long eurwdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "WDT Eurotech CPU-1220/1410", .identity = "WDT Eurotech CPU-1220/1410",
}; };
...@@ -243,7 +248,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -243,7 +248,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
int time; int time;
int options, retval = -EINVAL; int options, retval = -EINVAL;
switch(cmd) { switch (cmd) {
default: default:
return -ENOTTY; return -ENOTTY;
...@@ -255,7 +260,9 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -255,7 +260,9 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
spin_lock(&eurwdt_lock);
eurwdt_ping(); eurwdt_ping();
spin_unlock(&eurwdt_lock);
return 0; return 0;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
...@@ -266,8 +273,10 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -266,8 +273,10 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
if (time < 0 || time > 255) if (time < 0 || time > 255)
return -EINVAL; return -EINVAL;
spin_lock(&eurwdt_lock);
eurwdt_timeout = time; eurwdt_timeout = time;
eurwdt_set_timeout(time); eurwdt_set_timeout(time);
spin_unlock(&eurwdt_lock);
/* Fall */ /* Fall */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
...@@ -276,6 +285,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -276,6 +285,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
if (get_user(options, p)) if (get_user(options, p))
return -EFAULT; return -EFAULT;
spin_lock(&eurwdt_lock);
if (options & WDIOS_DISABLECARD) { if (options & WDIOS_DISABLECARD) {
eurwdt_disable_timer(); eurwdt_disable_timer();
retval = 0; retval = 0;
...@@ -285,6 +295,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, ...@@ -285,6 +295,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
eurwdt_ping(); eurwdt_ping();
retval = 0; retval = 0;
} }
spin_unlock(&eurwdt_lock);
return retval; return retval;
} }
} }
...@@ -322,10 +333,11 @@ static int eurwdt_open(struct inode *inode, struct file *file) ...@@ -322,10 +333,11 @@ static int eurwdt_open(struct inode *inode, struct file *file)
static int eurwdt_release(struct inode *inode, struct file *file) static int eurwdt_release(struct inode *inode, struct file *file)
{ {
if (eur_expect_close == 42) { if (eur_expect_close == 42)
eurwdt_disable_timer(); eurwdt_disable_timer();
} else { else {
printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT
"eurwdt: Unexpected close, not stopping watchdog!\n");
eurwdt_ping(); eurwdt_ping();
} }
clear_bit(0, &eurwdt_is_open); clear_bit(0, &eurwdt_is_open);
...@@ -362,11 +374,11 @@ static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code, ...@@ -362,11 +374,11 @@ static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
static const struct file_operations eurwdt_fops = { static const struct file_operations eurwdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = eurwdt_write, .write = eurwdt_write,
.ioctl = eurwdt_ioctl, .unlocked_ioctl = eurwdt_ioctl,
.open = eurwdt_open, .open = eurwdt_open,
.release = eurwdt_release, .release = eurwdt_release,
}; };
...@@ -419,7 +431,7 @@ static int __init eurwdt_init(void) ...@@ -419,7 +431,7 @@ static int __init eurwdt_init(void)
int ret; int ret;
ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
if(ret) { if (ret) {
printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
goto out; goto out;
} }
...@@ -432,10 +444,13 @@ static int __init eurwdt_init(void) ...@@ -432,10 +444,13 @@ static int __init eurwdt_init(void)
ret = register_reboot_notifier(&eurwdt_notifier); ret = register_reboot_notifier(&eurwdt_notifier);
if (ret) { if (ret) {
printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret); printk(KERN_ERR
"eurwdt: can't register reboot notifier (err=%d)\n", ret);
goto outreg; goto outreg;
} }
spin_lock_init(&eurwdt_lock);
ret = misc_register(&eurwdt_miscdev); ret = misc_register(&eurwdt_miscdev);
if (ret) { if (ret) {
printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
......
...@@ -39,9 +39,9 @@ ...@@ -39,9 +39,9 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/dmi.h> #include <linux/dmi.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/kdebug.h> #include <linux/kdebug.h>
#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */
#define CRU_BIOS_SIGNATURE_VALUE 0x55524324 #define CRU_BIOS_SIGNATURE_VALUE 0x55524324
......
...@@ -38,9 +38,8 @@ ...@@ -38,9 +38,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h> #include <linux/io.h>
#include <asm/io.h>
/* Module and version information */ /* Module and version information */
#define ESB_VERSION "0.03" #define ESB_VERSION "0.03"
...@@ -59,17 +58,17 @@ ...@@ -59,17 +58,17 @@
#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ #define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */
/* Lock register bits */ /* Lock register bits */
#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */ #define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */
#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */ #define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */
#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */ #define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */
/* Config register bits */ /* Config register bits */
#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */ #define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */
#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ #define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */
#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ #define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */
/* Reload register bits */ /* Reload register bits */
#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */ #define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */
/* Magic constants */ /* Magic constants */
#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ #define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
...@@ -84,14 +83,20 @@ static unsigned short triggered; /* The status of the watchdog upon boot */ ...@@ -84,14 +83,20 @@ static unsigned short triggered; /* The status of the watchdog upon boot */
static char esb_expect_close; static char esb_expect_close;
/* module parameters */ /* module parameters */
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */ /* 30 sec default heartbeat (1 < heartbeat < 2*1023) */
#define WATCHDOG_HEARTBEAT 30
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
module_param(heartbeat, int, 0); module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat in seconds. (1<heartbeat<2046, default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Some i6300ESB specific functions * Some i6300ESB specific functions
...@@ -104,8 +109,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _ ...@@ -104,8 +109,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
* to once before they need to be unlocked again. * to once before they need to be unlocked again.
*/ */
static inline void esb_unlock_registers(void) { static inline void esb_unlock_registers(void) {
writeb(ESB_UNLOCK1, ESB_RELOAD_REG); writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
writeb(ESB_UNLOCK2, ESB_RELOAD_REG); writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
} }
static void esb_timer_start(void) static void esb_timer_start(void)
...@@ -114,8 +119,7 @@ static void esb_timer_start(void) ...@@ -114,8 +119,7 @@ static void esb_timer_start(void)
/* Enable or Enable + Lock? */ /* Enable or Enable + Lock? */
val = 0x02 | (nowayout ? 0x01 : 0x00); val = 0x02 | (nowayout ? 0x01 : 0x00);
pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
} }
static int esb_timer_stop(void) static int esb_timer_stop(void)
...@@ -140,7 +144,7 @@ static void esb_timer_keepalive(void) ...@@ -140,7 +144,7 @@ static void esb_timer_keepalive(void)
spin_lock(&esb_lock); spin_lock(&esb_lock);
esb_unlock_registers(); esb_unlock_registers();
writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
/* FIXME: Do we need to flush anything here? */ /* FIXME: Do we need to flush anything here? */
spin_unlock(&esb_lock); spin_unlock(&esb_lock);
} }
...@@ -167,7 +171,7 @@ static int esb_timer_set_heartbeat(int time) ...@@ -167,7 +171,7 @@ static int esb_timer_set_heartbeat(int time)
esb_unlock_registers(); esb_unlock_registers();
writel(val, ESB_TIMER2_REG); writel(val, ESB_TIMER2_REG);
/* Reload */ /* Reload */
esb_unlock_registers(); esb_unlock_registers();
writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
...@@ -179,54 +183,55 @@ static int esb_timer_set_heartbeat(int time) ...@@ -179,54 +183,55 @@ static int esb_timer_set_heartbeat(int time)
return 0; return 0;
} }
static int esb_timer_read (void) static int esb_timer_read(void)
{ {
u32 count; u32 count;
/* This isn't documented, and doesn't take into /* This isn't documented, and doesn't take into
* acount which stage is running, but it looks * acount which stage is running, but it looks
* like a 20 bit count down, so we might as well report it. * like a 20 bit count down, so we might as well report it.
*/ */
pci_read_config_dword(esb_pci, 0x64, &count); pci_read_config_dword(esb_pci, 0x64, &count);
return (int)count; return (int)count;
} }
/* /*
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static int esb_open (struct inode *inode, struct file *file) static int esb_open(struct inode *inode, struct file *file)
{ {
/* /dev/watchdog can only be opened once */ /* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &timer_alive)) if (test_and_set_bit(0, &timer_alive))
return -EBUSY; return -EBUSY;
/* Reload and activate timer */ /* Reload and activate timer */
esb_timer_keepalive (); esb_timer_keepalive();
esb_timer_start (); esb_timer_start();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int esb_release (struct inode *inode, struct file *file) static int esb_release(struct inode *inode, struct file *file)
{ {
/* Shut off the timer. */ /* Shut off the timer. */
if (esb_expect_close == 42) { if (esb_expect_close == 42)
esb_timer_stop (); esb_timer_stop();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
esb_timer_keepalive (); "Unexpected close, not stopping watchdog!\n");
} esb_timer_keepalive();
clear_bit(0, &timer_alive); }
esb_expect_close = 0; clear_bit(0, &timer_alive);
return 0; esb_expect_close = 0;
return 0;
} }
static ssize_t esb_write (struct file *file, const char __user *data, static ssize_t esb_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos) size_t len, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
...@@ -237,7 +242,7 @@ static ssize_t esb_write (struct file *file, const char __user *data, ...@@ -237,7 +242,7 @@ static ssize_t esb_write (struct file *file, const char __user *data,
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the magic character */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if(get_user(c, data+i)) if (get_user(c, data+i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
esb_expect_close = 42; esb_expect_close = 42;
...@@ -245,13 +250,12 @@ static ssize_t esb_write (struct file *file, const char __user *data, ...@@ -245,13 +250,12 @@ static ssize_t esb_write (struct file *file, const char __user *data,
} }
/* someone wrote to us, we should reload the timer */ /* someone wrote to us, we should reload the timer */
esb_timer_keepalive (); esb_timer_keepalive();
} }
return len; return len;
} }
static int esb_ioctl (struct inode *inode, struct file *file, static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
int new_options, retval = -EINVAL; int new_options, retval = -EINVAL;
int new_heartbeat; int new_heartbeat;
...@@ -266,71 +270,65 @@ static int esb_ioctl (struct inode *inode, struct file *file, ...@@ -266,71 +270,65 @@ static int esb_ioctl (struct inode *inode, struct file *file,
}; };
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, return copy_to_user(argp, &ident,
sizeof (ident)) ? -EFAULT : 0; sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
return put_user (esb_timer_read(), p);
case WDIOC_GETBOOTSTATUS:
return put_user (triggered, p);
case WDIOC_KEEPALIVE:
esb_timer_keepalive ();
return 0;
case WDIOC_SETOPTIONS: case WDIOC_GETSTATUS:
{ return put_user(esb_timer_read(), p);
if (get_user (new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) { case WDIOC_GETBOOTSTATUS:
esb_timer_stop (); return put_user(triggered, p);
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) { case WDIOC_KEEPALIVE:
esb_timer_keepalive (); esb_timer_keepalive();
esb_timer_start (); return 0;
retval = 0;
}
return retval; case WDIOC_SETOPTIONS:
} {
if (get_user(new_options, p))
return -EFAULT;
case WDIOC_SETTIMEOUT: if (new_options & WDIOS_DISABLECARD) {
{ esb_timer_stop();
if (get_user(new_heartbeat, p)) retval = 0;
return -EFAULT; }
if (esb_timer_set_heartbeat(new_heartbeat))
return -EINVAL;
esb_timer_keepalive ();
/* Fall */
}
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
default: if (new_options & WDIOS_ENABLECARD) {
return -ENOTTY; esb_timer_keepalive();
} esb_timer_start();
retval = 0;
}
return retval;
}
case WDIOC_SETTIMEOUT:
{
if (get_user(new_heartbeat, p))
return -EFAULT;
if (esb_timer_set_heartbeat(new_heartbeat))
return -EINVAL;
esb_timer_keepalive();
/* Fall */
}
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
default:
return -ENOTTY;
}
} }
/* /*
* Notify system * Notify system
*/ */
static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused) static int esb_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{ {
if (code==SYS_DOWN || code==SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT) {
/* Turn the WDT off */ /* Turn the WDT off */
esb_timer_stop (); esb_timer_stop();
} }
return NOTIFY_DONE;
return NOTIFY_DONE;
} }
/* /*
...@@ -338,22 +336,22 @@ static int esb_notify_sys (struct notifier_block *this, unsigned long code, void ...@@ -338,22 +336,22 @@ static int esb_notify_sys (struct notifier_block *this, unsigned long code, void
*/ */
static const struct file_operations esb_fops = { static const struct file_operations esb_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = esb_write, .write = esb_write,
.ioctl = esb_ioctl, .unlocked_ioctl = esb_ioctl,
.open = esb_open, .open = esb_open,
.release = esb_release, .release = esb_release,
}; };
static struct miscdevice esb_miscdev = { static struct miscdevice esb_miscdev = {
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &esb_fops, .fops = &esb_fops,
}; };
static struct notifier_block esb_notifier = { static struct notifier_block esb_notifier = {
.notifier_call = esb_notify_sys, .notifier_call = esb_notify_sys,
}; };
/* /*
...@@ -365,50 +363,44 @@ static struct notifier_block esb_notifier = { ...@@ -365,50 +363,44 @@ static struct notifier_block esb_notifier = {
* want to register another driver on the same PCI id. * want to register another driver on the same PCI id.
*/ */
static struct pci_device_id esb_pci_tbl[] = { static struct pci_device_id esb_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
{ 0, }, /* End of list */ { 0, }, /* End of list */
}; };
MODULE_DEVICE_TABLE (pci, esb_pci_tbl); MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
/* /*
* Init & exit routines * Init & exit routines
*/ */
static unsigned char __init esb_getdevice (void) static unsigned char __init esb_getdevice(void)
{ {
u8 val1; u8 val1;
unsigned short val2; unsigned short val2;
/*
* Find the PCI device
*/
struct pci_dev *dev = NULL; esb_pci = pci_get_device(PCI_VENDOR_ID_INTEL,
/* PCI_DEVICE_ID_INTEL_ESB_9, NULL);
* Find the PCI device
*/
for_each_pci_dev(dev) {
if (pci_match_id(esb_pci_tbl, dev)) {
esb_pci = dev;
break;
}
}
if (esb_pci) { if (esb_pci) {
if (pci_enable_device(esb_pci)) { if (pci_enable_device(esb_pci)) {
printk (KERN_ERR PFX "failed to enable device\n"); printk(KERN_ERR PFX "failed to enable device\n");
goto err_devput; goto err_devput;
} }
if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) { if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
printk (KERN_ERR PFX "failed to request region\n"); printk(KERN_ERR PFX "failed to request region\n");
goto err_disable; goto err_disable;
} }
BASEADDR = ioremap(pci_resource_start(esb_pci, 0), BASEADDR = ioremap(pci_resource_start(esb_pci, 0),
pci_resource_len(esb_pci, 0)); pci_resource_len(esb_pci, 0));
if (BASEADDR == NULL) { if (BASEADDR == NULL) {
/* Something's wrong here, BASEADDR has to be set */ /* Something's wrong here, BASEADDR has to be set */
printk (KERN_ERR PFX "failed to get BASEADDR\n"); printk(KERN_ERR PFX "failed to get BASEADDR\n");
goto err_release; goto err_release;
} }
/* /*
* The watchdog has two timers, it can be setup so that the * The watchdog has two timers, it can be setup so that the
...@@ -425,7 +417,7 @@ static unsigned char __init esb_getdevice (void) ...@@ -425,7 +417,7 @@ static unsigned char __init esb_getdevice (void)
/* Check that the WDT isn't already locked */ /* Check that the WDT isn't already locked */
pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1); pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
if (val1 & ESB_WDT_LOCK) if (val1 & ESB_WDT_LOCK)
printk (KERN_WARNING PFX "nowayout already set\n"); printk(KERN_WARNING PFX "nowayout already set\n");
/* Set the timer to watchdog mode and disable it for now */ /* Set the timer to watchdog mode and disable it for now */
pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00); pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
...@@ -452,44 +444,44 @@ static unsigned char __init esb_getdevice (void) ...@@ -452,44 +444,44 @@ static unsigned char __init esb_getdevice (void)
return 0; return 0;
} }
static int __init watchdog_init (void) static int __init watchdog_init(void)
{ {
int ret; int ret;
/* Check whether or not the hardware watchdog is there */ /* Check whether or not the hardware watchdog is there */
if (!esb_getdevice () || esb_pci == NULL) if (!esb_getdevice() || esb_pci == NULL)
return -ENODEV; return -ENODEV;
/* Check that the heartbeat value is within it's range ; if not reset to the default */ /* Check that the heartbeat value is within it's range;
if (esb_timer_set_heartbeat (heartbeat)) { if not reset to the default */
esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT); if (esb_timer_set_heartbeat(heartbeat)) {
printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n", esb_timer_set_heartbeat(WATCHDOG_HEARTBEAT);
heartbeat); printk(KERN_INFO PFX
} "heartbeat value must be 1<heartbeat<2046, using %d\n",
heartbeat);
ret = register_reboot_notifier(&esb_notifier); }
if (ret != 0) { ret = register_reboot_notifier(&esb_notifier);
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", if (ret != 0) {
ret); printk(KERN_ERR PFX
goto err_unmap; "cannot register reboot notifier (err=%d)\n", ret);
} goto err_unmap;
}
ret = misc_register(&esb_miscdev);
if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto err_notifier;
}
esb_timer_stop ();
printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
BASEADDR, heartbeat, nowayout);
return 0; ret = misc_register(&esb_miscdev);
if (ret != 0) {
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto err_notifier;
}
esb_timer_stop();
printk(KERN_INFO PFX
"initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
BASEADDR, heartbeat, nowayout);
return 0;
err_notifier: err_notifier:
unregister_reboot_notifier(&esb_notifier); unregister_reboot_notifier(&esb_notifier);
err_unmap: err_unmap:
iounmap(BASEADDR); iounmap(BASEADDR);
/* err_release: */ /* err_release: */
...@@ -498,18 +490,18 @@ static int __init watchdog_init (void) ...@@ -498,18 +490,18 @@ static int __init watchdog_init (void)
pci_disable_device(esb_pci); pci_disable_device(esb_pci);
/* err_devput: */ /* err_devput: */
pci_dev_put(esb_pci); pci_dev_put(esb_pci);
return ret; return ret;
} }
static void __exit watchdog_cleanup (void) static void __exit watchdog_cleanup(void)
{ {
/* Stop the timer before we leave */ /* Stop the timer before we leave */
if (!nowayout) if (!nowayout)
esb_timer_stop (); esb_timer_stop();
/* Deregister */ /* Deregister */
misc_deregister(&esb_miscdev); misc_deregister(&esb_miscdev);
unregister_reboot_notifier(&esb_notifier); unregister_reboot_notifier(&esb_notifier);
iounmap(BASEADDR); iounmap(BASEADDR);
pci_release_region(esb_pci, 0); pci_release_region(esb_pci, 0);
pci_disable_device(esb_pci); pci_disable_device(esb_pci);
......
/* iTCO Vendor Specific Support hooks */
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
extern void iTCO_vendor_pre_stop(unsigned long);
extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
extern int iTCO_vendor_check_noreboot_on(void);
#else
#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
#define iTCO_vendor_pre_stop(acpibase) {}
#define iTCO_vendor_pre_keepalive(acpibase, heartbeat) {}
#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
#define iTCO_vendor_check_noreboot_on() 1
/* 1=check noreboot; 0=don't check */
#endif
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
#include <linux/init.h> /* For __init/__exit/... */ #include <linux/init.h> /* For __init/__exit/... */
#include <linux/ioport.h> /* For io-port access */ #include <linux/ioport.h> /* For io-port access */
#include <asm/io.h> /* For inb/outb/... */ #include <linux/io.h> /* For inb/outb/... */
#include "iTCO_vendor.h"
/* iTCO defines */ /* iTCO defines */
#define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */ #define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */
...@@ -40,10 +42,12 @@ ...@@ -40,10 +42,12 @@
#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
/* List of vendor support modes */ /* List of vendor support modes */
#define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
#define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ #define SUPERMICRO_OLD_BOARD 1
/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
#define SUPERMICRO_NEW_BOARD 2
static int vendorsupport = 0; static int vendorsupport;
module_param(vendorsupport, int, 0); module_param(vendorsupport, int, 0);
MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+"); MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+");
...@@ -143,34 +147,35 @@ static void supermicro_old_pre_keepalive(unsigned long acpibase) ...@@ -143,34 +147,35 @@ static void supermicro_old_pre_keepalive(unsigned long acpibase)
*/ */
/* I/O Port's */ /* I/O Port's */
#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ #define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ #define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
/* Control Register's */ /* Control Register's */
#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ #define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ #define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */
#define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ #define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */
#define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ #define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */
#define SM_ENDWATCH 0xAA /* Watchdog lock control page */ #define SM_ENDWATCH 0xAA /* Watchdog lock control page */
#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ #define SM_COUNTMODE 0xf5 /* Watchdog count mode select */
/* (Bit 3: 0 = seconds, 1 = minutes */ /* (Bit 3: 0 = seconds, 1 = minutes */
#define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ #define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */
#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ #define SM_RESETCONTROL 0xf7 /* Watchdog reset control */
/* Bit 6: timer is reset by kbd interrupt */ /* Bit 6: timer is reset by kbd interrupt */
/* Bit 7: timer is reset by mouse interrupt */ /* Bit 7: timer is reset by mouse interrupt */
static void supermicro_new_unlock_watchdog(void) static void supermicro_new_unlock_watchdog(void)
{ {
outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */ /* Write 0x87 to port 0x2e twice */
outb(SM_WATCHPAGE, SM_REGINDEX); outb(SM_WATCHPAGE, SM_REGINDEX);
outb(SM_WATCHPAGE, SM_REGINDEX);
outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */ /* Switch to watchdog control page */
outb(SM_CTLPAGESW, SM_REGINDEX);
outb(SM_CTLPAGE, SM_DATAIO); outb(SM_CTLPAGE, SM_DATAIO);
} }
...@@ -192,7 +197,7 @@ static void supermicro_new_pre_start(unsigned int heartbeat) ...@@ -192,7 +197,7 @@ static void supermicro_new_pre_start(unsigned int heartbeat)
outb(val, SM_DATAIO); outb(val, SM_DATAIO);
/* Write heartbeat interval to WDOG */ /* Write heartbeat interval to WDOG */
outb (SM_WATCHTIMER, SM_REGINDEX); outb(SM_WATCHTIMER, SM_REGINDEX);
outb((heartbeat & 255), SM_DATAIO); outb((heartbeat & 255), SM_DATAIO);
/* Make sure keyboard/mouse interrupts don't interfere */ /* Make sure keyboard/mouse interrupts don't interfere */
...@@ -277,7 +282,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); ...@@ -277,7 +282,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
int iTCO_vendor_check_noreboot_on(void) int iTCO_vendor_check_noreboot_on(void)
{ {
switch(vendorsupport) { switch (vendorsupport) {
case SUPERMICRO_OLD_BOARD: case SUPERMICRO_OLD_BOARD:
return 0; return 0;
default: default:
...@@ -288,13 +293,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on); ...@@ -288,13 +293,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
static int __init iTCO_vendor_init_module(void) static int __init iTCO_vendor_init_module(void)
{ {
printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport); printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
return 0; return 0;
} }
static void __exit iTCO_vendor_exit_module(void) static void __exit iTCO_vendor_exit_module(void)
{ {
printk (KERN_INFO PFX "Module Unloaded\n"); printk(KERN_INFO PFX "Module Unloaded\n");
} }
module_init(iTCO_vendor_init_module); module_init(iTCO_vendor_init_module);
......
...@@ -66,7 +66,8 @@ ...@@ -66,7 +66,8 @@
#include <linux/types.h> /* For standard types (like size_t) */ #include <linux/types.h> /* For standard types (like size_t) */
#include <linux/errno.h> /* For the -ENODEV/... values */ #include <linux/errno.h> /* For the -ENODEV/... values */
#include <linux/kernel.h> /* For printk/panic/... */ #include <linux/kernel.h> /* For printk/panic/... */
#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV
(WATCHDOG_MINOR) */
#include <linux/watchdog.h> /* For the watchdog specific items */ #include <linux/watchdog.h> /* For the watchdog specific items */
#include <linux/init.h> /* For __init/__exit/... */ #include <linux/init.h> /* For __init/__exit/... */
#include <linux/fs.h> /* For file operations */ #include <linux/fs.h> /* For file operations */
...@@ -74,9 +75,10 @@ ...@@ -74,9 +75,10 @@
#include <linux/pci.h> /* For pci functions */ #include <linux/pci.h> /* For pci functions */
#include <linux/ioport.h> /* For io-port access */ #include <linux/ioport.h> /* For io-port access */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <linux/io.h> /* For inb/outb/... */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */ #include "iTCO_vendor.h"
#include <asm/io.h> /* For inb/outb/... */
/* TCO related info */ /* TCO related info */
enum iTCO_chipsets { enum iTCO_chipsets {
...@@ -140,7 +142,7 @@ static struct { ...@@ -140,7 +142,7 @@ static struct {
{"ICH9DH", 2}, {"ICH9DH", 2},
{"ICH9DO", 2}, {"ICH9DO", 2},
{"631xESB/632xESB", 2}, {"631xESB/632xESB", 2},
{NULL,0} {NULL, 0}
}; };
#define ITCO_PCI_DEVICE(dev, data) \ #define ITCO_PCI_DEVICE(dev, data) \
...@@ -159,32 +161,32 @@ static struct { ...@@ -159,32 +161,32 @@ static struct {
* functions that probably will be registered by other drivers. * functions that probably will be registered by other drivers.
*/ */
static struct pci_device_id iTCO_wdt_pci_tbl[] = { static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8 )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M)},
{ ITCO_PCI_DEVICE(0x2918, TCO_ICH9 )}, { ITCO_PCI_DEVICE(0x2918, TCO_ICH9)},
{ ITCO_PCI_DEVICE(0x2916, TCO_ICH9R )}, { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO )}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2671, TCO_631XESB)}, { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2672, TCO_631XESB)}, { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)},
...@@ -203,13 +205,15 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { ...@@ -203,13 +205,15 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x267f, TCO_631XESB)}, { ITCO_PCI_DEVICE(0x267f, TCO_631XESB)},
{ 0, }, /* End of list */ { 0, }, /* End of list */
}; };
MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
/* Address definitions for the TCO */ /* Address definitions for the TCO */
#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */ /* TCO base address */
#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */ #define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60
/* SMI Control and Enable Register */
#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30
#define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ #define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Curr. Value */
#define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */ #define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */
#define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ #define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
#define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ #define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
...@@ -222,15 +226,21 @@ MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); ...@@ -222,15 +226,21 @@ MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
/* internal variables */ /* internal variables */
static unsigned long is_active; static unsigned long is_active;
static char expect_release; static char expect_release;
static struct { /* this is private data for the iTCO_wdt device */ static struct { /* this is private data for the iTCO_wdt device */
unsigned int iTCO_version; /* TCO version/generation */ /* TCO version/generation */
unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ unsigned int iTCO_version;
unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */ /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
spinlock_t io_lock; /* the lock for io operations */ unsigned long ACPIBASE;
struct pci_dev *pdev; /* the PCI-device */ /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
unsigned long __iomem *gcs;
/* the lock for io operations */
spinlock_t io_lock;
/* the PCI-device */
struct pci_dev *pdev;
} iTCO_wdt_private; } iTCO_wdt_private;
static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */ /* the watchdog platform device */
static struct platform_device *iTCO_wdt_platform_device;
/* module parameters */ /* module parameters */
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
...@@ -240,22 +250,9 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO ...@@ -240,22 +250,9 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
/* iTCO Vendor Specific Support hooks */ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
extern void iTCO_vendor_pre_stop(unsigned long);
extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
extern int iTCO_vendor_check_noreboot_on(void);
#else
#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
#define iTCO_vendor_pre_stop(acpibase) {}
#define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {}
#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
#define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */
#endif
/* /*
* Some TCO specific functions * Some TCO specific functions
...@@ -369,11 +366,10 @@ static int iTCO_wdt_keepalive(void) ...@@ -369,11 +366,10 @@ static int iTCO_wdt_keepalive(void)
iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
/* Reload the timer by writing to the TCO Timer Counter register */ /* Reload the timer by writing to the TCO Timer Counter register */
if (iTCO_wdt_private.iTCO_version == 2) { if (iTCO_wdt_private.iTCO_version == 2)
outw(0x01, TCO_RLD); outw(0x01, TCO_RLD);
} else if (iTCO_wdt_private.iTCO_version == 1) { else if (iTCO_wdt_private.iTCO_version == 1)
outb(0x01, TCO_RLD); outb(0x01, TCO_RLD);
}
spin_unlock(&iTCO_wdt_private.io_lock); spin_unlock(&iTCO_wdt_private.io_lock);
return 0; return 0;
...@@ -425,7 +421,7 @@ static int iTCO_wdt_set_heartbeat(int t) ...@@ -425,7 +421,7 @@ static int iTCO_wdt_set_heartbeat(int t)
return 0; return 0;
} }
static int iTCO_wdt_get_timeleft (int *time_left) static int iTCO_wdt_get_timeleft(int *time_left)
{ {
unsigned int val16; unsigned int val16;
unsigned char val8; unsigned char val8;
...@@ -454,7 +450,7 @@ static int iTCO_wdt_get_timeleft (int *time_left) ...@@ -454,7 +450,7 @@ static int iTCO_wdt_get_timeleft (int *time_left)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static int iTCO_wdt_open (struct inode *inode, struct file *file) static int iTCO_wdt_open(struct inode *inode, struct file *file)
{ {
/* /dev/watchdog can only be opened once */ /* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &is_active)) if (test_and_set_bit(0, &is_active))
...@@ -468,7 +464,7 @@ static int iTCO_wdt_open (struct inode *inode, struct file *file) ...@@ -468,7 +464,7 @@ static int iTCO_wdt_open (struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int iTCO_wdt_release (struct inode *inode, struct file *file) static int iTCO_wdt_release(struct inode *inode, struct file *file)
{ {
/* /*
* Shut off the timer. * Shut off the timer.
...@@ -476,7 +472,8 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file) ...@@ -476,7 +472,8 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file)
if (expect_release == 42) { if (expect_release == 42) {
iTCO_wdt_stop(); iTCO_wdt_stop();
} else { } else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
iTCO_wdt_keepalive(); iTCO_wdt_keepalive();
} }
clear_bit(0, &is_active); clear_bit(0, &is_active);
...@@ -484,19 +481,20 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file) ...@@ -484,19 +481,20 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file)
return 0; return 0;
} }
static ssize_t iTCO_wdt_write (struct file *file, const char __user *data, static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos) size_t len, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the magic
* five months ago... */ character five months ago... */
expect_release = 0; expect_release = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the
magic character */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if (get_user(c, data+i)) if (get_user(c, data+i))
...@@ -512,8 +510,8 @@ static ssize_t iTCO_wdt_write (struct file *file, const char __user *data, ...@@ -512,8 +510,8 @@ static ssize_t iTCO_wdt_write (struct file *file, const char __user *data,
return len; return len;
} }
static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int new_options, retval = -EINVAL; int new_options, retval = -EINVAL;
int new_heartbeat; int new_heartbeat;
...@@ -528,64 +526,52 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, ...@@ -528,64 +526,52 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
}; };
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
sizeof (ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
case WDIOC_GETSTATUS: return put_user(0, p);
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
iTCO_wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS: case WDIOC_KEEPALIVE:
{ iTCO_wdt_keepalive();
if (get_user(new_options, p)) return 0;
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
iTCO_wdt_stop();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) { case WDIOC_SETOPTIONS:
iTCO_wdt_keepalive(); {
iTCO_wdt_start(); if (get_user(new_options, p))
retval = 0; return -EFAULT;
}
return retval; if (new_options & WDIOS_DISABLECARD) {
iTCO_wdt_stop();
retval = 0;
} }
if (new_options & WDIOS_ENABLECARD) {
case WDIOC_SETTIMEOUT:
{
if (get_user(new_heartbeat, p))
return -EFAULT;
if (iTCO_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
iTCO_wdt_keepalive(); iTCO_wdt_keepalive();
/* Fall */ iTCO_wdt_start();
retval = 0;
} }
return retval;
case WDIOC_GETTIMEOUT: }
return put_user(heartbeat, p); case WDIOC_SETTIMEOUT:
{
case WDIOC_GETTIMELEFT: if (get_user(new_heartbeat, p))
{ return -EFAULT;
int time_left; if (iTCO_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
if (iTCO_wdt_get_timeleft(&time_left)) iTCO_wdt_keepalive();
return -EINVAL; /* Fall */
}
return put_user(time_left, p); case WDIOC_GETTIMEOUT:
} return put_user(heartbeat, p);
case WDIOC_GETTIMELEFT:
default: {
return -ENOTTY; int time_left;
if (iTCO_wdt_get_timeleft(&time_left))
return -EINVAL;
return put_user(time_left, p);
}
default:
return -ENOTTY;
} }
} }
...@@ -594,12 +580,12 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, ...@@ -594,12 +580,12 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
*/ */
static const struct file_operations iTCO_wdt_fops = { static const struct file_operations iTCO_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = iTCO_wdt_write, .write = iTCO_wdt_write,
.ioctl = iTCO_wdt_ioctl, .unlocked_ioctl = iTCO_wdt_ioctl,
.open = iTCO_wdt_open, .open = iTCO_wdt_open,
.release = iTCO_wdt_release, .release = iTCO_wdt_release,
}; };
static struct miscdevice iTCO_wdt_miscdev = { static struct miscdevice iTCO_wdt_miscdev = {
...@@ -612,7 +598,8 @@ static struct miscdevice iTCO_wdt_miscdev = { ...@@ -612,7 +598,8 @@ static struct miscdevice iTCO_wdt_miscdev = {
* Init & exit routines * Init & exit routines
*/ */
static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev) static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
const struct pci_device_id *ent, struct platform_device *dev)
{ {
int ret; int ret;
u32 base_address; u32 base_address;
...@@ -632,17 +619,19 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device ...@@ -632,17 +619,19 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device
pci_dev_put(pdev); pci_dev_put(pdev);
return -ENODEV; return -ENODEV;
} }
iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version; iTCO_wdt_private.iTCO_version =
iTCO_chipset_info[ent->driver_data].iTCO_version;
iTCO_wdt_private.ACPIBASE = base_address; iTCO_wdt_private.ACPIBASE = base_address;
iTCO_wdt_private.pdev = pdev; iTCO_wdt_private.pdev = pdev;
/* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */ /* Get the Memory-Mapped GCS register, we need it for the
/* To get access to it you have to read RCBA from PCI Config space 0xf0 NO_REBOOT flag (TCO v2). To get access to it you have to
and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */ read RCBA from PCI Config space 0xf0 and use it as base.
GCS = RCBA + ICH6_GCS(0x3410). */
if (iTCO_wdt_private.iTCO_version == 2) { if (iTCO_wdt_private.iTCO_version == 2) {
pci_read_config_dword(pdev, 0xf0, &base_address); pci_read_config_dword(pdev, 0xf0, &base_address);
RCBA = base_address & 0xffffc000; RCBA = base_address & 0xffffc000;
iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4); iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
} }
/* Check chipset's NO_REBOOT bit */ /* Check chipset's NO_REBOOT bit */
...@@ -657,8 +646,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device ...@@ -657,8 +646,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device
/* Set the TCO_EN bit in SMI_EN register */ /* Set the TCO_EN bit in SMI_EN register */
if (!request_region(SMI_EN, 4, "iTCO_wdt")) { if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", printk(KERN_ERR PFX
SMI_EN ); "I/O address 0x%04lx already in use\n", SMI_EN);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
...@@ -667,18 +656,20 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device ...@@ -667,18 +656,20 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device
outl(val32, SMI_EN); outl(val32, SMI_EN);
release_region(SMI_EN, 4); release_region(SMI_EN, 4);
/* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ /* The TCO I/O registers reside in a 32-byte range pointed to
if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) { by the TCOBASE value */
printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n", if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
TCOBASE); TCOBASE);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n", printk(KERN_INFO PFX
iTCO_chipset_info[ent->driver_data].name, "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
iTCO_chipset_info[ent->driver_data].iTCO_version, iTCO_chipset_info[ent->driver_data].name,
TCOBASE); iTCO_chipset_info[ent->driver_data].iTCO_version,
TCOBASE);
/* Clear out the (probably old) status */ /* Clear out the (probably old) status */
outb(0, TCO1_STS); outb(0, TCO1_STS);
...@@ -687,27 +678,29 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device ...@@ -687,27 +678,29 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device
/* Make sure the watchdog is not running */ /* Make sure the watchdog is not running */
iTCO_wdt_stop(); iTCO_wdt_stop();
/* Check that the heartbeat value is within it's range ; if not reset to the default */ /* Check that the heartbeat value is within it's range;
if not reset to the default */
if (iTCO_wdt_set_heartbeat(heartbeat)) { if (iTCO_wdt_set_heartbeat(heartbeat)) {
iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n", printk(KERN_INFO PFX "heartbeat value must be 2 < heartbeat < 39 (TCO v1) or 613 (TCO v2), using %d\n",
heartbeat); heartbeat);
} }
ret = misc_register(&iTCO_wdt_miscdev); ret = misc_register(&iTCO_wdt_miscdev);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_region; goto unreg_region;
} }
printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout); heartbeat, nowayout);
return 0; return 0;
unreg_region: unreg_region:
release_region (TCOBASE, 0x20); release_region(TCOBASE, 0x20);
out: out:
if (iTCO_wdt_private.iTCO_version == 2) if (iTCO_wdt_private.iTCO_version == 2)
iounmap(iTCO_wdt_private.gcs); iounmap(iTCO_wdt_private.gcs);
...@@ -796,7 +789,8 @@ static int __init iTCO_wdt_init_module(void) ...@@ -796,7 +789,8 @@ static int __init iTCO_wdt_init_module(void)
if (err) if (err)
return err; return err;
iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
if (IS_ERR(iTCO_wdt_platform_device)) { if (IS_ERR(iTCO_wdt_platform_device)) {
err = PTR_ERR(iTCO_wdt_platform_device); err = PTR_ERR(iTCO_wdt_platform_device);
goto unreg_platform_driver; goto unreg_platform_driver;
......
...@@ -42,8 +42,8 @@ ...@@ -42,8 +42,8 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
static struct platform_device *ibwdt_platform_device; static struct platform_device *ibwdt_platform_device;
...@@ -120,7 +120,9 @@ static int wd_margin = WD_TIMO; ...@@ -120,7 +120,9 @@ static int wd_margin = WD_TIMO;
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
...@@ -165,8 +167,8 @@ ibwdt_set_heartbeat(int t) ...@@ -165,8 +167,8 @@ ibwdt_set_heartbeat(int t)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t static ssize_t ibwdt_write(struct file *file, const char __user *buf,
ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
...@@ -188,77 +190,71 @@ ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppo ...@@ -188,77 +190,71 @@ ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppo
return count; return count;
} }
static int static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{ {
int new_margin; int new_margin;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "IB700 WDT", .identity = "IB700 WDT",
}; };
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
ibwdt_ping(); ibwdt_ping();
break; break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p)) if (get_user(new_margin, p))
return -EFAULT; return -EFAULT;
if (ibwdt_set_heartbeat(new_margin)) if (ibwdt_set_heartbeat(new_margin))
return -EINVAL; return -EINVAL;
ibwdt_ping(); ibwdt_ping();
/* Fall */ /* Fall */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(wd_times[wd_margin], p); return put_user(wd_times[wd_margin], p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
if (get_user(options, p)) if (get_user(options, p))
return -EFAULT; return -EFAULT;
if (options & WDIOS_DISABLECARD) { if (options & WDIOS_DISABLECARD) {
ibwdt_disable(); ibwdt_disable();
retval = 0; retval = 0;
} }
if (options & WDIOS_ENABLECARD) {
if (options & WDIOS_ENABLECARD) { ibwdt_ping();
ibwdt_ping(); retval = 0;
retval = 0; }
} return retval;
return retval;
} }
default: default:
return -ENOTTY; return -ENOTTY;
} }
return 0; return 0;
} }
static int static int ibwdt_open(struct inode *inode, struct file *file)
ibwdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &ibwdt_is_open)) { if (test_and_set_bit(0, &ibwdt_is_open))
return -EBUSY; return -EBUSY;
}
if (nowayout) if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
...@@ -273,7 +269,8 @@ ibwdt_close(struct inode *inode, struct file *file) ...@@ -273,7 +269,8 @@ ibwdt_close(struct inode *inode, struct file *file)
if (expect_close == 42) { if (expect_close == 42) {
ibwdt_disable(); ibwdt_disable();
} else { } else {
printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); printk(KERN_CRIT PFX
"WDT device closed unexpectedly. WDT will not stop!\n");
ibwdt_ping(); ibwdt_ping();
} }
clear_bit(0, &ibwdt_is_open); clear_bit(0, &ibwdt_is_open);
...@@ -289,7 +286,7 @@ static const struct file_operations ibwdt_fops = { ...@@ -289,7 +286,7 @@ static const struct file_operations ibwdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ibwdt_write, .write = ibwdt_write,
.ioctl = ibwdt_ioctl, .unlocked_ioctl = ibwdt_ioctl,
.open = ibwdt_open, .open = ibwdt_open,
.release = ibwdt_close, .release = ibwdt_close,
}; };
...@@ -310,21 +307,23 @@ static int __devinit ibwdt_probe(struct platform_device *dev) ...@@ -310,21 +307,23 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
#if WDT_START != WDT_STOP #if WDT_START != WDT_STOP
if (!request_region(WDT_STOP, 1, "IB700 WDT")) { if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
printk (KERN_ERR PFX "STOP method I/O %X is not available.\n", WDT_STOP); printk(KERN_ERR PFX "STOP method I/O %X is not available.\n",
WDT_STOP);
res = -EIO; res = -EIO;
goto out_nostopreg; goto out_nostopreg;
} }
#endif #endif
if (!request_region(WDT_START, 1, "IB700 WDT")) { if (!request_region(WDT_START, 1, "IB700 WDT")) {
printk (KERN_ERR PFX "START method I/O %X is not available.\n", WDT_START); printk(KERN_ERR PFX "START method I/O %X is not available.\n",
WDT_START);
res = -EIO; res = -EIO;
goto out_nostartreg; goto out_nostartreg;
} }
res = misc_register(&ibwdt_miscdev); res = misc_register(&ibwdt_miscdev);
if (res) { if (res) {
printk (KERN_ERR PFX "failed to register misc device\n"); printk(KERN_ERR PFX "failed to register misc device\n");
goto out_nomisc; goto out_nomisc;
} }
return 0; return 0;
...@@ -342,9 +341,9 @@ static int __devinit ibwdt_probe(struct platform_device *dev) ...@@ -342,9 +341,9 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
static int __devexit ibwdt_remove(struct platform_device *dev) static int __devexit ibwdt_remove(struct platform_device *dev)
{ {
misc_deregister(&ibwdt_miscdev); misc_deregister(&ibwdt_miscdev);
release_region(WDT_START,1); release_region(WDT_START, 1);
#if WDT_START != WDT_STOP #if WDT_START != WDT_STOP
release_region(WDT_STOP,1); release_region(WDT_STOP, 1);
#endif #endif
return 0; return 0;
} }
...@@ -369,13 +368,15 @@ static int __init ibwdt_init(void) ...@@ -369,13 +368,15 @@ static int __init ibwdt_init(void)
{ {
int err; int err;
printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n"); printk(KERN_INFO PFX
"WDT driver for IB700 single board computer initialising.\n");
err = platform_driver_register(&ibwdt_driver); err = platform_driver_register(&ibwdt_driver);
if (err) if (err)
return err; return err;
ibwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); ibwdt_platform_device = platform_device_register_simple(DRV_NAME,
-1, NULL, 0);
if (IS_ERR(ibwdt_platform_device)) { if (IS_ERR(ibwdt_platform_device)) {
err = PTR_ERR(ibwdt_platform_device); err = PTR_ERR(ibwdt_platform_device);
goto unreg_platform_driver; goto unreg_platform_driver;
......
...@@ -19,9 +19,8 @@ ...@@ -19,9 +19,8 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/io.h>
#include <asm/io.h> #include <linux/uaccess.h>
#include <asm/uaccess.h>
enum { enum {
...@@ -70,10 +69,13 @@ static char asr_expect_close; ...@@ -70,10 +69,13 @@ static char asr_expect_close;
static unsigned int asr_type, asr_base, asr_length; static unsigned int asr_type, asr_base, asr_length;
static unsigned int asr_read_addr, asr_write_addr; static unsigned int asr_read_addr, asr_write_addr;
static unsigned char asr_toggle_mask, asr_disable_mask; static unsigned char asr_toggle_mask, asr_disable_mask;
static spinlock_t asr_lock;
static void asr_toggle(void) static void __asr_toggle(void)
{ {
unsigned char reg = inb(asr_read_addr); unsigned char reg;
reg = inb(asr_read_addr);
outb(reg & ~asr_toggle_mask, asr_write_addr); outb(reg & ~asr_toggle_mask, asr_write_addr);
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
...@@ -83,12 +85,21 @@ static void asr_toggle(void) ...@@ -83,12 +85,21 @@ static void asr_toggle(void)
outb(reg & ~asr_toggle_mask, asr_write_addr); outb(reg & ~asr_toggle_mask, asr_write_addr);
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
}
static void asr_toggle(void)
{
spin_lock(&asr_lock);
__asr_toggle();
spin_unlock(&asr_lock);
} }
static void asr_enable(void) static void asr_enable(void)
{ {
unsigned char reg; unsigned char reg;
spin_lock(&asr_lock);
if (asr_type == ASMTYPE_TOPAZ) { if (asr_type == ASMTYPE_TOPAZ) {
/* asr_write_addr == asr_read_addr */ /* asr_write_addr == asr_read_addr */
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
...@@ -99,17 +110,21 @@ static void asr_enable(void) ...@@ -99,17 +110,21 @@ static void asr_enable(void)
* First make sure the hardware timer is reset by toggling * First make sure the hardware timer is reset by toggling
* ASR hardware timer line. * ASR hardware timer line.
*/ */
asr_toggle(); __asr_toggle();
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
outb(reg & ~asr_disable_mask, asr_write_addr); outb(reg & ~asr_disable_mask, asr_write_addr);
} }
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
} }
static void asr_disable(void) static void asr_disable(void)
{ {
unsigned char reg = inb(asr_read_addr); unsigned char reg;
spin_lock(&asr_lock);
reg = inb(asr_read_addr);
if (asr_type == ASMTYPE_TOPAZ) if (asr_type == ASMTYPE_TOPAZ)
/* asr_write_addr == asr_read_addr */ /* asr_write_addr == asr_read_addr */
...@@ -122,6 +137,7 @@ static void asr_disable(void) ...@@ -122,6 +137,7 @@ static void asr_disable(void)
outb(reg | asr_disable_mask, asr_write_addr); outb(reg | asr_disable_mask, asr_write_addr);
} }
reg = inb(asr_read_addr); reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
} }
static int __init asr_get_base_address(void) static int __init asr_get_base_address(void)
...@@ -133,7 +149,8 @@ static int __init asr_get_base_address(void) ...@@ -133,7 +149,8 @@ static int __init asr_get_base_address(void)
switch (asr_type) { switch (asr_type) {
case ASMTYPE_TOPAZ: case ASMTYPE_TOPAZ:
/* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ /* SELECT SuperIO CHIP FOR QUERYING
(WRITE 0x07 TO BOTH 0x2E and 0x2F) */
outb(0x07, 0x2e); outb(0x07, 0x2e);
outb(0x07, 0x2f); outb(0x07, 0x2f);
...@@ -154,14 +171,26 @@ static int __init asr_get_base_address(void) ...@@ -154,14 +171,26 @@ static int __init asr_get_base_address(void)
case ASMTYPE_JASPER: case ASMTYPE_JASPER:
type = "Jaspers "; type = "Jaspers ";
#if 0
/* FIXME: need to use pci_config_lock here, but it's not exported */ u32 r;
/* Suggested fix */
pdev = pci_get_bus_and_slot(0, DEVFN(0x1f, 0));
if (pdev == NULL)
return -ENODEV;
pci_read_config_dword(pdev, 0x58, &r);
asr_base = r & 0xFFFE;
pci_dev_put(pdev);
#else
/* FIXME: need to use pci_config_lock here,
but it's not exported */
/* spin_lock_irqsave(&pci_config_lock, flags);*/ /* spin_lock_irqsave(&pci_config_lock, flags);*/
/* Select the SuperIO chip in the PCI I/O port register */ /* Select the SuperIO chip in the PCI I/O port register */
outl(0x8000f858, 0xcf8); outl(0x8000f858, 0xcf8);
/* BUS 0, Slot 1F, fnc 0, offset 58 */
/* /*
* Read the base address for the SuperIO chip. * Read the base address for the SuperIO chip.
* Only the lower 16 bits are valid, but the address is word * Only the lower 16 bits are valid, but the address is word
...@@ -170,7 +199,7 @@ static int __init asr_get_base_address(void) ...@@ -170,7 +199,7 @@ static int __init asr_get_base_address(void)
asr_base = inl(0xcfc) & 0xfffe; asr_base = inl(0xcfc) & 0xfffe;
/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ /* spin_unlock_irqrestore(&pci_config_lock, flags);*/
#endif
asr_read_addr = asr_write_addr = asr_read_addr = asr_write_addr =
asr_base + JASPER_ASR_REG_OFFSET; asr_base + JASPER_ASR_REG_OFFSET;
asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
...@@ -241,11 +270,10 @@ static ssize_t asr_write(struct file *file, const char __user *buf, ...@@ -241,11 +270,10 @@ static ssize_t asr_write(struct file *file, const char __user *buf,
return count; return count;
} }
static int asr_ioctl(struct inode *inode, struct file *file, static long asr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
static const struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | .options = WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.identity = "IBM ASR" .identity = "IBM ASR"
}; };
...@@ -254,53 +282,45 @@ static int asr_ioctl(struct inode *inode, struct file *file, ...@@ -254,53 +282,45 @@ static int asr_ioctl(struct inode *inode, struct file *file,
int heartbeat; int heartbeat;
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-EFAULT : 0; case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
case WDIOC_GETSTATUS: return put_user(0, p);
case WDIOC_GETBOOTSTATUS: case WDIOC_KEEPALIVE:
return put_user(0, p); asr_toggle();
return 0;
case WDIOC_KEEPALIVE: /*
* The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
* and WDIOC_GETTIMEOUT always returns 256.
*/
case WDIOC_GETTIMEOUT:
heartbeat = 256;
return put_user(heartbeat, p);
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
asr_disable();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
asr_enable();
asr_toggle(); asr_toggle();
return 0; retval = 0;
/*
* The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
* and WDIOC_GETTIMEOUT always returns 256.
*/
case WDIOC_GETTIMEOUT:
heartbeat = 256;
return put_user(heartbeat, p);
case WDIOC_SETOPTIONS: {
int new_options, retval = -EINVAL;
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
asr_disable();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
asr_enable();
asr_toggle();
retval = 0;
}
return retval;
} }
return retval;
}
default:
return -ENOTTY;
} }
return -ENOTTY;
} }
static int asr_open(struct inode *inode, struct file *file) static int asr_open(struct inode *inode, struct file *file)
{ {
if(test_and_set_bit(0, &asr_is_open)) if (test_and_set_bit(0, &asr_is_open))
return -EBUSY; return -EBUSY;
asr_toggle(); asr_toggle();
...@@ -314,7 +334,8 @@ static int asr_release(struct inode *inode, struct file *file) ...@@ -314,7 +334,8 @@ static int asr_release(struct inode *inode, struct file *file)
if (asr_expect_close == 42) if (asr_expect_close == 42)
asr_disable(); asr_disable();
else { else {
printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"unexpected close, not stopping watchdog!\n");
asr_toggle(); asr_toggle();
} }
clear_bit(0, &asr_is_open); clear_bit(0, &asr_is_open);
...@@ -323,12 +344,12 @@ static int asr_release(struct inode *inode, struct file *file) ...@@ -323,12 +344,12 @@ static int asr_release(struct inode *inode, struct file *file)
} }
static const struct file_operations asr_fops = { static const struct file_operations asr_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = asr_write, .write = asr_write,
.ioctl = asr_ioctl, .unlocked_ioctl = asr_ioctl,
.open = asr_open, .open = asr_open,
.release = asr_release, .release = asr_release,
}; };
static struct miscdevice asr_miscdev = { static struct miscdevice asr_miscdev = {
...@@ -367,6 +388,8 @@ static int __init ibmasr_init(void) ...@@ -367,6 +388,8 @@ static int __init ibmasr_init(void)
if (!asr_type) if (!asr_type)
return -ENODEV; return -ENODEV;
spin_lock_init(&asr_lock);
rc = asr_get_base_address(); rc = asr_get_base_address();
if (rc) if (rc)
return rc; return rc;
...@@ -395,7 +418,9 @@ module_init(ibmasr_init); ...@@ -395,7 +418,9 @@ module_init(ibmasr_init);
module_exit(ibmasr_exit); module_exit(ibmasr_exit);
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
MODULE_AUTHOR("Andrey Panin"); MODULE_AUTHOR("Andrey Panin");
......
/* /*
* IndyDog 0.3 A Hardware Watchdog Device for SGI IP22 * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22
* *
* (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved. * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>,
* All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -22,32 +23,42 @@ ...@@ -22,32 +23,42 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/sgi/mc.h> #include <asm/sgi/mc.h>
#define PFX "indydog: " #define PFX "indydog: "
static int indydog_alive; static unsigned long indydog_alive;
static spinlock_t indydog_lock;
#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void indydog_start(void) static void indydog_start(void)
{ {
u32 mc_ctrl0 = sgimc->cpuctrl0; u32 mc_ctrl0;
spin_lock(&indydog_lock);
mc_ctrl0 = sgimc->cpuctrl0;
mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG; mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
sgimc->cpuctrl0 = mc_ctrl0; sgimc->cpuctrl0 = mc_ctrl0;
spin_unlock(&indydog_lock);
} }
static void indydog_stop(void) static void indydog_stop(void)
{ {
u32 mc_ctrl0 = sgimc->cpuctrl0; u32 mc_ctrl0;
spin_lock(&indydog_lock);
mc_ctrl0 = sgimc->cpuctrl0;
mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG; mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
sgimc->cpuctrl0 = mc_ctrl0; sgimc->cpuctrl0 = mc_ctrl0;
spin_unlock(&indydog_lock);
printk(KERN_INFO PFX "Stopped watchdog timer.\n"); printk(KERN_INFO PFX "Stopped watchdog timer.\n");
} }
...@@ -62,7 +73,7 @@ static void indydog_ping(void) ...@@ -62,7 +73,7 @@ static void indydog_ping(void)
*/ */
static int indydog_open(struct inode *inode, struct file *file) static int indydog_open(struct inode *inode, struct file *file)
{ {
if (indydog_alive) if (test_and_set_bit(0, &indydog_alive))
return -EBUSY; return -EBUSY;
if (nowayout) if (nowayout)
...@@ -84,23 +95,21 @@ static int indydog_release(struct inode *inode, struct file *file) ...@@ -84,23 +95,21 @@ static int indydog_release(struct inode *inode, struct file *file)
* Lock it in if it's a module and we defined ...NOWAYOUT */ * Lock it in if it's a module and we defined ...NOWAYOUT */
if (!nowayout) if (!nowayout)
indydog_stop(); /* Turn the WDT off */ indydog_stop(); /* Turn the WDT off */
clear_bit(0, &indydog_alive);
indydog_alive = 0;
return 0; return 0;
} }
static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos) static ssize_t indydog_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{ {
/* Refresh the timer. */ /* Refresh the timer. */
if (len) { if (len)
indydog_ping(); indydog_ping();
}
return len; return len;
} }
static int indydog_ioctl(struct inode *inode, struct file *file, static long indydog_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
static struct watchdog_info ident = { static struct watchdog_info ident = {
...@@ -111,42 +120,40 @@ static int indydog_ioctl(struct inode *inode, struct file *file, ...@@ -111,42 +120,40 @@ static int indydog_ioctl(struct inode *inode, struct file *file,
}; };
switch (cmd) { switch (cmd) {
default: case WDIOC_GETSUPPORT:
return -ENOTTY; if (copy_to_user((struct watchdog_info *)arg,
case WDIOC_GETSUPPORT: &ident, sizeof(ident)))
if (copy_to_user((struct watchdog_info *)arg, return -EFAULT;
&ident, sizeof(ident))) return 0;
return -EFAULT; case WDIOC_GETSTATUS:
return 0; case WDIOC_GETBOOTSTATUS:
case WDIOC_GETSTATUS: return put_user(0, (int *)arg);
case WDIOC_GETBOOTSTATUS: case WDIOC_KEEPALIVE:
return put_user(0,(int *)arg); indydog_ping();
case WDIOC_KEEPALIVE: return 0;
indydog_ping(); case WDIOC_GETTIMEOUT:
return 0; return put_user(WATCHDOG_TIMEOUT, (int *)arg);
case WDIOC_GETTIMEOUT: case WDIOC_SETOPTIONS:
return put_user(WATCHDOG_TIMEOUT,(int *)arg); {
case WDIOC_SETOPTIONS: if (get_user(options, (int *)arg))
{ return -EFAULT;
if (get_user(options, (int *)arg)) if (options & WDIOS_DISABLECARD) {
return -EFAULT; indydog_stop();
retval = 0;
if (options & WDIOS_DISABLECARD) { }
indydog_stop(); if (options & WDIOS_ENABLECARD) {
retval = 0; indydog_start();
} retval = 0;
if (options & WDIOS_ENABLECARD) {
indydog_start();
retval = 0;
}
return retval;
} }
return retval;
}
default:
return -ENOTTY;
} }
} }
static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused) static int indydog_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
indydog_stop(); /* Turn the WDT off */ indydog_stop(); /* Turn the WDT off */
...@@ -158,7 +165,7 @@ static const struct file_operations indydog_fops = { ...@@ -158,7 +165,7 @@ static const struct file_operations indydog_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = indydog_write, .write = indydog_write,
.ioctl = indydog_ioctl, .unlocked_ioctl = indydog_ioctl,
.open = indydog_open, .open = indydog_open,
.release = indydog_release, .release = indydog_release,
}; };
...@@ -180,17 +187,20 @@ static int __init watchdog_init(void) ...@@ -180,17 +187,20 @@ static int __init watchdog_init(void)
{ {
int ret; int ret;
spin_lock_init(&indydog_lock);
ret = register_reboot_notifier(&indydog_notifier); ret = register_reboot_notifier(&indydog_notifier);
if (ret) { if (ret) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
return ret; return ret;
} }
ret = misc_register(&indydog_miscdev); ret = misc_register(&indydog_miscdev);
if (ret) { if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&indydog_notifier); unregister_reboot_notifier(&indydog_notifier);
return ret; return ret;
} }
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned long wdt_status; static unsigned long wdt_status;
static unsigned long boot_status; static unsigned long boot_status;
static spinlock_t wdt_lock;
#define WDT_IN_USE 0 #define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1 #define WDT_OK_TO_CLOSE 1
...@@ -68,8 +69,10 @@ static void wdt_enable(void) ...@@ -68,8 +69,10 @@ static void wdt_enable(void)
/* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
* Takes approx. 10.7s to timeout * Takes approx. 10.7s to timeout
*/ */
spin_lock(&wdt_lock);
write_wdtcr(IOP_WDTCR_EN_ARM); write_wdtcr(IOP_WDTCR_EN_ARM);
write_wdtcr(IOP_WDTCR_EN); write_wdtcr(IOP_WDTCR_EN);
spin_unlock(&wdt_lock);
} }
/* returns 0 if the timer was successfully disabled */ /* returns 0 if the timer was successfully disabled */
...@@ -77,9 +80,11 @@ static int wdt_disable(void) ...@@ -77,9 +80,11 @@ static int wdt_disable(void)
{ {
/* Stop Counting */ /* Stop Counting */
if (wdt_supports_disable()) { if (wdt_supports_disable()) {
spin_lock(&wdt_lock);
write_wdtcr(IOP_WDTCR_DIS_ARM); write_wdtcr(IOP_WDTCR_DIS_ARM);
write_wdtcr(IOP_WDTCR_DIS); write_wdtcr(IOP_WDTCR_DIS);
clear_bit(WDT_ENABLED, &wdt_status); clear_bit(WDT_ENABLED, &wdt_status);
spin_unlock(&wdt_lock);
printk(KERN_INFO "WATCHDOG: Disabled\n"); printk(KERN_INFO "WATCHDOG: Disabled\n");
return 0; return 0;
} else } else
...@@ -92,16 +97,12 @@ static int iop_wdt_open(struct inode *inode, struct file *file) ...@@ -92,16 +97,12 @@ static int iop_wdt_open(struct inode *inode, struct file *file)
return -EBUSY; return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
wdt_enable(); wdt_enable();
set_bit(WDT_ENABLED, &wdt_status); set_bit(WDT_ENABLED, &wdt_status);
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static ssize_t static ssize_t iop_wdt_write(struct file *file, const char *data, size_t len,
iop_wdt_write(struct file *file, const char *data, size_t len,
loff_t *ppos) loff_t *ppos)
{ {
if (len) { if (len) {
...@@ -121,41 +122,39 @@ iop_wdt_write(struct file *file, const char *data, size_t len, ...@@ -121,41 +122,39 @@ iop_wdt_write(struct file *file, const char *data, size_t len,
} }
wdt_enable(); wdt_enable();
} }
return len; return len;
} }
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "iop watchdog", .identity = "iop watchdog",
}; };
static int static long iop_wdt_ioctl(struct file *file,
iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int options; int options;
int ret = -ENOTTY; int ret = -ENOTTY;
int __user *argp = (int __user *)arg;
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user if (copy_to_user(argp, &ident, sizeof ident))
((struct watchdog_info *)arg, &ident, sizeof ident))
ret = -EFAULT; ret = -EFAULT;
else else
ret = 0; ret = 0;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg); ret = put_user(0, argp);
break; break;
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
ret = put_user(boot_status, (int *)arg); ret = put_user(boot_status, argp);
break; break;
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
ret = put_user(iop_watchdog_timeout(), (int *)arg); ret = put_user(iop_watchdog_timeout(), argp);
break; break;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
...@@ -177,14 +176,12 @@ iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -177,14 +176,12 @@ iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
} else } else
ret = 0; ret = 0;
} }
if (options & WDIOS_ENABLECARD) { if (options & WDIOS_ENABLECARD) {
wdt_enable(); wdt_enable();
ret = 0; ret = 0;
} }
break; break;
} }
return ret; return ret;
} }
...@@ -214,7 +211,7 @@ static const struct file_operations iop_wdt_fops = { ...@@ -214,7 +211,7 @@ static const struct file_operations iop_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = iop_wdt_write, .write = iop_wdt_write,
.ioctl = iop_wdt_ioctl, .unlocked_ioctl = iop_wdt_ioctl,
.open = iop_wdt_open, .open = iop_wdt_open,
.release = iop_wdt_release, .release = iop_wdt_release,
}; };
...@@ -229,10 +226,8 @@ static int __init iop_wdt_init(void) ...@@ -229,10 +226,8 @@ static int __init iop_wdt_init(void)
{ {
int ret; int ret;
ret = misc_register(&iop_wdt_miscdev); spin_lock_init(&wdt_lock);
if (ret == 0)
printk("iop watchdog timer: timeout %lu sec\n",
iop_watchdog_timeout());
/* check if the reset was caused by the watchdog timer */ /* check if the reset was caused by the watchdog timer */
boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0; boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
...@@ -242,6 +237,13 @@ static int __init iop_wdt_init(void) ...@@ -242,6 +237,13 @@ static int __init iop_wdt_init(void)
*/ */
write_wdtsr(IOP13XX_WDTCR_IB_RESET); write_wdtsr(IOP13XX_WDTCR_IB_RESET);
/* Register after we have the device set up so we cannot race
with an open */
ret = misc_register(&iop_wdt_miscdev);
if (ret == 0)
printk("iop watchdog timer: timeout %lu sec\n",
iop_watchdog_timeout());
return ret; return ret;
} }
......
...@@ -25,42 +25,45 @@ ...@@ -25,42 +25,45 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/uaccess.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */ static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status; static unsigned long wdt_status;
static spinlock_t wdt_lock;
#define WDT_IN_USE 0 #define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1 #define WDT_OK_TO_CLOSE 1
static unsigned long wdt_tick_rate; static unsigned long wdt_tick_rate;
static void static void wdt_enable(void)
wdt_enable(void)
{ {
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE); ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE); ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE); ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
spin_unlock(&wdt_lock);
} }
static void static void wdt_disable(void)
wdt_disable(void)
{ {
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CTL, 0); ixp2000_reg_write(IXP2000_T4_CTL, 0);
spin_unlock(&wdt_lock);
} }
static void static void wdt_keepalive(void)
wdt_keepalive(void)
{ {
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
spin_unlock(&wdt_lock);
} }
static int static int ixp2000_wdt_open(struct inode *inode, struct file *file)
ixp2000_wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(WDT_IN_USE, &wdt_status)) if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY; return -EBUSY;
...@@ -72,8 +75,8 @@ ixp2000_wdt_open(struct inode *inode, struct file *file) ...@@ -72,8 +75,8 @@ ixp2000_wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static ssize_t static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
...@@ -103,9 +106,8 @@ static struct watchdog_info ident = { ...@@ -103,9 +106,8 @@ static struct watchdog_info ident = {
.identity = "IXP2000 Watchdog", .identity = "IXP2000 Watchdog",
}; };
static int static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd,
ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
int time; int time;
...@@ -151,16 +153,13 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -151,16 +153,13 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return ret; return ret;
} }
static int static int ixp2000_wdt_release(struct inode *inode, struct file *file)
ixp2000_wdt_release(struct inode *inode, struct file *file)
{ {
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable(); wdt_disable();
} else { else
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n"); "timer will not stop\n");
}
clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
...@@ -168,18 +167,16 @@ ixp2000_wdt_release(struct inode *inode, struct file *file) ...@@ -168,18 +167,16 @@ ixp2000_wdt_release(struct inode *inode, struct file *file)
} }
static const struct file_operations ixp2000_wdt_fops = static const struct file_operations ixp2000_wdt_fops = {
{
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ixp2000_wdt_write, .write = ixp2000_wdt_write,
.ioctl = ixp2000_wdt_ioctl, .unlocked_ioctl = ixp2000_wdt_ioctl,
.open = ixp2000_wdt_open, .open = ixp2000_wdt_open,
.release = ixp2000_wdt_release, .release = ixp2000_wdt_release,
}; };
static struct miscdevice ixp2000_wdt_miscdev = static struct miscdevice ixp2000_wdt_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &ixp2000_wdt_fops, .fops = &ixp2000_wdt_fops,
...@@ -191,9 +188,8 @@ static int __init ixp2000_wdt_init(void) ...@@ -191,9 +188,8 @@ static int __init ixp2000_wdt_init(void)
printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n"); printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
return -EIO; return -EIO;
} }
wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256; wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
spin_lock_init(&wdt_lock);
return misc_register(&ixp2000_wdt_miscdev); return misc_register(&ixp2000_wdt_miscdev);
} }
......
...@@ -30,40 +30,40 @@ static int nowayout = WATCHDOG_NOWAYOUT; ...@@ -30,40 +30,40 @@ static int nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = 60; /* (secs) Default is 1 minute */ static int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status; static unsigned long wdt_status;
static unsigned long boot_status; static unsigned long boot_status;
static spin_lock_t wdt_lock;
#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
#define WDT_IN_USE 0 #define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1 #define WDT_OK_TO_CLOSE 1
static void static void wdt_enable(void)
wdt_enable(void)
{ {
spin_lock(&wdt_lock);
*IXP4XX_OSWK = IXP4XX_WDT_KEY; *IXP4XX_OSWK = IXP4XX_WDT_KEY;
*IXP4XX_OSWE = 0; *IXP4XX_OSWE = 0;
*IXP4XX_OSWT = WDT_TICK_RATE * heartbeat; *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
*IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE; *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
*IXP4XX_OSWK = 0; *IXP4XX_OSWK = 0;
spin_unlock(&wdt_lock);
} }
static void static void wdt_disable(void)
wdt_disable(void)
{ {
spin_lock(&wdt_lock);
*IXP4XX_OSWK = IXP4XX_WDT_KEY; *IXP4XX_OSWK = IXP4XX_WDT_KEY;
*IXP4XX_OSWE = 0; *IXP4XX_OSWE = 0;
*IXP4XX_OSWK = 0; *IXP4XX_OSWK = 0;
spin_unlock(&wdt_lock);
} }
static int static int ixp4xx_wdt_open(struct inode *inode, struct file *file)
ixp4xx_wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(WDT_IN_USE, &wdt_status)) if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY; return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
wdt_enable(); wdt_enable();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -87,7 +87,6 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) ...@@ -87,7 +87,6 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
} }
wdt_enable(); wdt_enable();
} }
return len; return len;
} }
...@@ -98,9 +97,8 @@ static struct watchdog_info ident = { ...@@ -98,9 +97,8 @@ static struct watchdog_info ident = {
}; };
static int static long ixp4xx_wdt_ioctl(struct file *file, unsigned int cmd,
ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
int time; int time;
...@@ -145,16 +143,13 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -145,16 +143,13 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return ret; return ret;
} }
static int static int ixp4xx_wdt_release(struct inode *inode, struct file *file)
ixp4xx_wdt_release(struct inode *inode, struct file *file)
{ {
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable(); wdt_disable();
} else { else
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n"); "timer will not stop\n");
}
clear_bit(WDT_IN_USE, &wdt_status); clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status); clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
...@@ -167,7 +162,7 @@ static const struct file_operations ixp4xx_wdt_fops = ...@@ -167,7 +162,7 @@ static const struct file_operations ixp4xx_wdt_fops =
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = ixp4xx_wdt_write, .write = ixp4xx_wdt_write,
.ioctl = ixp4xx_wdt_ioctl, .unlocked_ioctl = ixp4xx_wdt_ioctl,
.open = ixp4xx_wdt_open, .open = ixp4xx_wdt_open,
.release = ixp4xx_wdt_release, .release = ixp4xx_wdt_release,
}; };
...@@ -191,14 +186,12 @@ static int __init ixp4xx_wdt_init(void) ...@@ -191,14 +186,12 @@ static int __init ixp4xx_wdt_init(void)
return -ENODEV; return -ENODEV;
} }
spin_lock_init(&wdt_lock);
boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
WDIOF_CARDRESET : 0;
ret = misc_register(&ixp4xx_wdt_miscdev); ret = misc_register(&ixp4xx_wdt_miscdev);
if (ret == 0) if (ret == 0)
printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat); printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat);
boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
WDIOF_CARDRESET : 0;
return ret; return ret;
} }
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/arch/regs-timer.h> #include <asm/arch/regs-timer.h>
...@@ -31,38 +31,44 @@ static int wdt_time = WDT_DEFAULT_TIME; ...@@ -31,38 +31,44 @@ static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0); module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
__MODULE_STRING(WDT_DEFAULT_TIME) ")");
#ifdef CONFIG_WATCHDOG_NOWAYOUT #ifdef CONFIG_WATCHDOG_NOWAYOUT
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#endif #endif
static unsigned long ks8695wdt_busy; static unsigned long ks8695wdt_busy;
static spinlock_t ks8695_lock;
/* ......................................................................... */ /* ......................................................................... */
/* /*
* Disable the watchdog. * Disable the watchdog.
*/ */
static void inline ks8695_wdt_stop(void) static inline void ks8695_wdt_stop(void)
{ {
unsigned long tmcon; unsigned long tmcon;
spin_lock(&ks8695_lock);
/* disable timer0 */ /* disable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
spin_unlock(&ks8695_lock);
} }
/* /*
* Enable and reset the watchdog. * Enable and reset the watchdog.
*/ */
static void inline ks8695_wdt_start(void) static inline void ks8695_wdt_start(void)
{ {
unsigned long tmcon; unsigned long tmcon;
unsigned long tval = wdt_time * CLOCK_TICK_RATE; unsigned long tval = wdt_time * CLOCK_TICK_RATE;
spin_lock(&ks8695_lock);
/* disable timer0 */ /* disable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
...@@ -73,19 +79,22 @@ static void inline ks8695_wdt_start(void) ...@@ -73,19 +79,22 @@ static void inline ks8695_wdt_start(void)
/* re-enable timer0 */ /* re-enable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
spin_unlock(&ks8695_lock);
} }
/* /*
* Reload the watchdog timer. (ie, pat the watchdog) * Reload the watchdog timer. (ie, pat the watchdog)
*/ */
static void inline ks8695_wdt_reload(void) static inline void ks8695_wdt_reload(void)
{ {
unsigned long tmcon; unsigned long tmcon;
spin_lock(&ks8695_lock);
/* disable, then re-enable timer0 */ /* disable, then re-enable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
spin_unlock(&ks8695_lock);
} }
/* /*
...@@ -102,7 +111,8 @@ static int ks8695_wdt_settimeout(int new_time) ...@@ -102,7 +111,8 @@ static int ks8695_wdt_settimeout(int new_time)
if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
return -EINVAL; return -EINVAL;
/* Set new watchdog time. It will be used when ks8695_wdt_start() is called. */ /* Set new watchdog time. It will be used when
ks8695_wdt_start() is called. */
wdt_time = new_time; wdt_time = new_time;
return 0; return 0;
} }
...@@ -128,9 +138,9 @@ static int ks8695_wdt_open(struct inode *inode, struct file *file) ...@@ -128,9 +138,9 @@ static int ks8695_wdt_open(struct inode *inode, struct file *file)
*/ */
static int ks8695_wdt_close(struct inode *inode, struct file *file) static int ks8695_wdt_close(struct inode *inode, struct file *file)
{ {
/* Disable the watchdog when file is closed */
if (!nowayout) if (!nowayout)
ks8695_wdt_stop(); /* Disable the watchdog when file is closed */ ks8695_wdt_stop();
clear_bit(0, &ks8695wdt_busy); clear_bit(0, &ks8695wdt_busy);
return 0; return 0;
} }
...@@ -143,60 +153,52 @@ static struct watchdog_info ks8695_wdt_info = { ...@@ -143,60 +153,52 @@ static struct watchdog_info ks8695_wdt_info = {
/* /*
* Handle commands from user-space. * Handle commands from user-space.
*/ */
static int ks8695_wdt_ioctl(struct inode *inode, struct file *file, static long ks8695_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_value; int new_value;
switch(cmd) { switch (cmd) {
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
ks8695_wdt_reload(); /* pat the watchdog */ ks8695_wdt_reload(); /* pat the watchdog */
return 0; return 0;
case WDIOC_GETSUPPORT:
case WDIOC_GETSUPPORT: return copy_to_user(argp, &ks8695_wdt_info,
return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0; sizeof(ks8695_wdt_info)) ? -EFAULT : 0;
case WDIOC_SETTIMEOUT:
case WDIOC_SETTIMEOUT: if (get_user(new_value, p))
if (get_user(new_value, p)) return -EFAULT;
return -EFAULT; if (ks8695_wdt_settimeout(new_value))
return -EINVAL;
if (ks8695_wdt_settimeout(new_value)) /* Enable new time value */
return -EINVAL; ks8695_wdt_start();
/* Return current value */
/* Enable new time value */ return put_user(wdt_time, p);
case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p);
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(new_value, p))
return -EFAULT;
if (new_value & WDIOS_DISABLECARD)
ks8695_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
ks8695_wdt_start(); ks8695_wdt_start();
return 0;
/* Return current value */ default:
return put_user(wdt_time, p); return -ENOTTY;
case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p);
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(new_value, p))
return -EFAULT;
if (new_value & WDIOS_DISABLECARD)
ks8695_wdt_stop();
if (new_value & WDIOS_ENABLECARD)
ks8695_wdt_start();
return 0;
default:
return -ENOTTY;
} }
} }
/* /*
* Pat the watchdog whenever device is written to. * Pat the watchdog whenever device is written to.
*/ */
static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) static ssize_t ks8695_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{ {
ks8695_wdt_reload(); /* pat the watchdog */ ks8695_wdt_reload(); /* pat the watchdog */
return len; return len;
...@@ -207,7 +209,7 @@ static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, ...@@ -207,7 +209,7 @@ static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len,
static const struct file_operations ks8695wdt_fops = { static const struct file_operations ks8695wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = ks8695_wdt_ioctl, .unlocked_ioctl = ks8695_wdt_ioctl,
.open = ks8695_wdt_open, .open = ks8695_wdt_open,
.release = ks8695_wdt_close, .release = ks8695_wdt_close,
.write = ks8695_wdt_write, .write = ks8695_wdt_write,
...@@ -231,7 +233,8 @@ static int __init ks8695wdt_probe(struct platform_device *pdev) ...@@ -231,7 +233,8 @@ static int __init ks8695wdt_probe(struct platform_device *pdev)
if (res) if (res)
return res; return res;
printk("KS8695 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); printk(KERN_INFO "KS8695 Watchdog Timer enabled (%d seconds%s)\n",
wdt_time, nowayout ? ", nowayout" : "");
return 0; return 0;
} }
...@@ -285,12 +288,14 @@ static struct platform_driver ks8695wdt_driver = { ...@@ -285,12 +288,14 @@ static struct platform_driver ks8695wdt_driver = {
static int __init ks8695_wdt_init(void) static int __init ks8695_wdt_init(void)
{ {
/* Check that the heartbeat value is within range; if not reset to the default */ spin_lock_init(&ks8695_lock);
/* Check that the heartbeat value is within range;
if not reset to the default */
if (ks8695_wdt_settimeout(wdt_time)) { if (ks8695_wdt_settimeout(wdt_time)) {
ks8695_wdt_settimeout(WDT_DEFAULT_TIME); ks8695_wdt_settimeout(WDT_DEFAULT_TIME);
pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", wdt_time, WDT_MAX_TIME); pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n",
wdt_time, WDT_MAX_TIME);
} }
return platform_driver_register(&ks8695wdt_driver); return platform_driver_register(&ks8695wdt_driver);
} }
......
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
/* ports */ /* ports */
...@@ -95,7 +95,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ...@@ -95,7 +95,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#define PFX "machzwd" #define PFX "machzwd"
...@@ -114,7 +116,7 @@ static struct watchdog_info zf_info = { ...@@ -114,7 +116,7 @@ static struct watchdog_info zf_info = {
* 3 = GEN_SCI * 3 = GEN_SCI
* defaults to GEN_RESET (0) * defaults to GEN_RESET (0)
*/ */
static int action = 0; static int action;
module_param(action, int, 0); module_param(action, int, 0);
MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
...@@ -123,10 +125,9 @@ static void zf_ping(unsigned long data); ...@@ -123,10 +125,9 @@ static void zf_ping(unsigned long data);
static int zf_action = GEN_RESET; static int zf_action = GEN_RESET;
static unsigned long zf_is_open; static unsigned long zf_is_open;
static char zf_expect_close; static char zf_expect_close;
static DEFINE_SPINLOCK(zf_lock);
static DEFINE_SPINLOCK(zf_port_lock); static DEFINE_SPINLOCK(zf_port_lock);
static DEFINE_TIMER(zf_timer, zf_ping, 0, 0); static DEFINE_TIMER(zf_timer, zf_ping, 0, 0);
static unsigned long next_heartbeat = 0; static unsigned long next_heartbeat;
/* timeout for user land heart beat (10 seconds) */ /* timeout for user land heart beat (10 seconds) */
...@@ -171,13 +172,13 @@ static inline void zf_set_control(unsigned short new) ...@@ -171,13 +172,13 @@ static inline void zf_set_control(unsigned short new)
static inline void zf_set_timer(unsigned short new, unsigned char n) static inline void zf_set_timer(unsigned short new, unsigned char n)
{ {
switch(n){ switch (n) {
case WD1: case WD1:
zf_writew(COUNTER_1, new); zf_writew(COUNTER_1, new);
case WD2: case WD2:
zf_writeb(COUNTER_2, new > 0xff ? 0xff : new); zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
default: default:
return; return;
} }
} }
...@@ -241,10 +242,8 @@ static void zf_ping(unsigned long data) ...@@ -241,10 +242,8 @@ static void zf_ping(unsigned long data)
zf_writeb(COUNTER_2, 0xff); zf_writeb(COUNTER_2, 0xff);
if(time_before(jiffies, next_heartbeat)){ if (time_before(jiffies, next_heartbeat)) {
dprintk("time_before: %ld\n", next_heartbeat - jiffies); dprintk("time_before: %ld\n", next_heartbeat - jiffies);
/* /*
* reset event is activated by transition from 0 to 1 on * reset event is activated by transition from 0 to 1 on
* RESET_WD1 bit and we assume that it is already zero... * RESET_WD1 bit and we assume that it is already zero...
...@@ -261,24 +260,21 @@ static void zf_ping(unsigned long data) ...@@ -261,24 +260,21 @@ static void zf_ping(unsigned long data)
spin_unlock_irqrestore(&zf_port_lock, flags); spin_unlock_irqrestore(&zf_port_lock, flags);
mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
}else{ } else
printk(KERN_CRIT PFX ": I will reset your machine\n"); printk(KERN_CRIT PFX ": I will reset your machine\n");
}
} }
static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
/* See if we got the magic character */ /* See if we got the magic character */
if(count){ if (count) {
/* /*
* no need to check for close confirmation * no need to check for close confirmation
* no way to disable watchdog ;) * no way to disable watchdog ;)
*/ */
if (!nowayout) { if (!nowayout) {
size_t ofs; size_t ofs;
/* /*
* note: just in case someone wrote the magic character * note: just in case someone wrote the magic character
* five months ago... * five months ago...
...@@ -286,11 +282,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, ...@@ -286,11 +282,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
zf_expect_close = 0; zf_expect_close = 0;
/* now scan */ /* now scan */
for (ofs = 0; ofs != count; ofs++){ for (ofs = 0; ofs != count; ofs++) {
char c; char c;
if (get_user(c, buf + ofs)) if (get_user(c, buf + ofs))
return -EFAULT; return -EFAULT;
if (c == 'V'){ if (c == 'V') {
zf_expect_close = 42; zf_expect_close = 42;
dprintk("zf_expect_close = 42\n"); dprintk("zf_expect_close = 42\n");
} }
...@@ -303,14 +299,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, ...@@ -303,14 +299,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
*/ */
next_heartbeat = jiffies + ZF_USER_TIMEO; next_heartbeat = jiffies + ZF_USER_TIMEO;
dprintk("user ping at %ld\n", jiffies); dprintk("user ping at %ld\n", jiffies);
} }
return count; return count;
} }
static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long zf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -319,55 +312,38 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -319,55 +312,38 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (copy_to_user(argp, &zf_info, sizeof(zf_info))) if (copy_to_user(argp, &zf_info, sizeof(zf_info)))
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
zf_ping(0); zf_ping(0);
break; break;
default: default:
return -ENOTTY; return -ENOTTY;
} }
return 0; return 0;
} }
static int zf_open(struct inode *inode, struct file *file) static int zf_open(struct inode *inode, struct file *file)
{ {
spin_lock(&zf_lock); if (test_and_set_bit(0, &zf_is_open))
if(test_and_set_bit(0, &zf_is_open)) {
spin_unlock(&zf_lock);
return -EBUSY; return -EBUSY;
}
if (nowayout) if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
spin_unlock(&zf_lock);
zf_timer_on(); zf_timer_on();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int zf_close(struct inode *inode, struct file *file) static int zf_close(struct inode *inode, struct file *file)
{ {
if(zf_expect_close == 42){ if (zf_expect_close == 42)
zf_timer_off(); zf_timer_off();
} else { else {
del_timer(&zf_timer); del_timer(&zf_timer);
printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
} }
spin_lock(&zf_lock);
clear_bit(0, &zf_is_open); clear_bit(0, &zf_is_open);
spin_unlock(&zf_lock);
zf_expect_close = 0; zf_expect_close = 0;
return 0; return 0;
} }
...@@ -378,23 +354,18 @@ static int zf_close(struct inode *inode, struct file *file) ...@@ -378,23 +354,18 @@ static int zf_close(struct inode *inode, struct file *file)
static int zf_notify_sys(struct notifier_block *this, unsigned long code, static int zf_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code == SYS_DOWN || code == SYS_HALT){ if (code == SYS_DOWN || code == SYS_HALT)
zf_timer_off(); zf_timer_off();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static const struct file_operations zf_fops = { static const struct file_operations zf_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = zf_write, .write = zf_write,
.ioctl = zf_ioctl, .unlocked_ioctl = zf_ioctl,
.open = zf_open, .open = zf_open,
.release = zf_close, .release = zf_close,
}; };
static struct miscdevice zf_miscdev = { static struct miscdevice zf_miscdev = {
...@@ -402,7 +373,7 @@ static struct miscdevice zf_miscdev = { ...@@ -402,7 +373,7 @@ static struct miscdevice zf_miscdev = {
.name = "watchdog", .name = "watchdog",
.fops = &zf_fops, .fops = &zf_fops,
}; };
/* /*
* The device needs to learn about soft shutdowns in order to * The device needs to learn about soft shutdowns in order to
...@@ -423,22 +394,23 @@ static int __init zf_init(void) ...@@ -423,22 +394,23 @@ static int __init zf_init(void)
{ {
int ret; int ret;
printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); printk(KERN_INFO PFX
": MachZ ZF-Logic Watchdog driver initializing.\n");
ret = zf_get_ZFL_version(); ret = zf_get_ZFL_version();
if ((!ret) || (ret == 0xffff)) { if (!ret || ret == 0xffff) {
printk(KERN_WARNING PFX ": no ZF-Logic found\n"); printk(KERN_WARNING PFX ": no ZF-Logic found\n");
return -ENODEV; return -ENODEV;
} }
if((action <= 3) && (action >= 0)){ if (action <= 3 && action >= 0)
zf_action = zf_action>>action; zf_action = zf_action >> action;
} else else
action = 0; action = 0;
zf_show_action(action); zf_show_action(action);
if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) {
printk(KERN_ERR "cannot reserve I/O ports at %d\n", printk(KERN_ERR "cannot reserve I/O ports at %d\n",
ZF_IOBASE); ZF_IOBASE);
ret = -EBUSY; ret = -EBUSY;
...@@ -446,14 +418,14 @@ static int __init zf_init(void) ...@@ -446,14 +418,14 @@ static int __init zf_init(void)
} }
ret = register_reboot_notifier(&zf_notifier); ret = register_reboot_notifier(&zf_notifier);
if(ret){ if (ret) {
printk(KERN_ERR "can't register reboot notifier (err=%d)\n", printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
ret); ret);
goto no_reboot; goto no_reboot;
} }
ret = misc_register(&zf_miscdev); ret = misc_register(&zf_miscdev);
if (ret){ if (ret) {
printk(KERN_ERR "can't misc_register on minor=%d\n", printk(KERN_ERR "can't misc_register on minor=%d\n",
WATCHDOG_MINOR); WATCHDOG_MINOR);
goto no_misc; goto no_misc;
......
...@@ -29,7 +29,8 @@ ...@@ -29,7 +29,8 @@
* - support for one more type board * - support for one more type board
* *
* Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com> * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
* - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT * - added nowayout module option to override
* CONFIG_WATCHDOG_NOWAYOUT
* *
* Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com> * Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com>
* - make mixcomwd_opened unsigned, * - make mixcomwd_opened unsigned,
...@@ -53,8 +54,8 @@ ...@@ -53,8 +54,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <linux/io.h>
/* /*
* We have two types of cards that can be probed: * We have two types of cards that can be probed:
...@@ -108,18 +109,19 @@ static char expect_close; ...@@ -108,18 +109,19 @@ static char expect_close;
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void mixcomwd_ping(void) static void mixcomwd_ping(void)
{ {
outb_p(55,watchdog_port); outb_p(55, watchdog_port);
return; return;
} }
static void mixcomwd_timerfun(unsigned long d) static void mixcomwd_timerfun(unsigned long d)
{ {
mixcomwd_ping(); mixcomwd_ping();
mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
} }
...@@ -129,22 +131,22 @@ static void mixcomwd_timerfun(unsigned long d) ...@@ -129,22 +131,22 @@ static void mixcomwd_timerfun(unsigned long d)
static int mixcomwd_open(struct inode *inode, struct file *file) static int mixcomwd_open(struct inode *inode, struct file *file)
{ {
if(test_and_set_bit(0,&mixcomwd_opened)) { if (test_and_set_bit(0, &mixcomwd_opened))
return -EBUSY; return -EBUSY;
}
mixcomwd_ping(); mixcomwd_ping();
if (nowayout) { if (nowayout)
/* /*
* fops_get() code via open() has already done * fops_get() code via open() has already done
* a try_module_get() so it is safe to do the * a try_module_get() so it is safe to do the
* __module_get(). * __module_get().
*/ */
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
} else { else {
if(mixcomwd_timer_alive) { if (mixcomwd_timer_alive) {
del_timer(&mixcomwd_timer); del_timer(&mixcomwd_timer);
mixcomwd_timer_alive=0; mixcomwd_timer_alive = 0;
} }
} }
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
...@@ -153,26 +155,27 @@ static int mixcomwd_open(struct inode *inode, struct file *file) ...@@ -153,26 +155,27 @@ static int mixcomwd_open(struct inode *inode, struct file *file)
static int mixcomwd_release(struct inode *inode, struct file *file) static int mixcomwd_release(struct inode *inode, struct file *file)
{ {
if (expect_close == 42) { if (expect_close == 42) {
if(mixcomwd_timer_alive) { if (mixcomwd_timer_alive) {
printk(KERN_ERR PFX "release called while internal timer alive"); printk(KERN_ERR PFX
"release called while internal timer alive");
return -EBUSY; return -EBUSY;
} }
mixcomwd_timer_alive=1; mixcomwd_timer_alive = 1;
mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
} else { } else
printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); printk(KERN_CRIT PFX
} "WDT device closed unexpectedly. WDT will not stop!\n");
clear_bit(0,&mixcomwd_opened); clear_bit(0, &mixcomwd_opened);
expect_close=0; expect_close = 0;
return 0; return 0;
} }
static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) static ssize_t mixcomwd_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{ {
if(len) if (len) {
{
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
...@@ -192,8 +195,8 @@ static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t ...@@ -192,8 +195,8 @@ static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t
return len; return len;
} }
static int mixcomwd_ioctl(struct inode *inode, struct file *file, static long mixcomwd_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -204,32 +207,23 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, ...@@ -204,32 +207,23 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
.identity = "MixCOM watchdog", .identity = "MixCOM watchdog",
}; };
switch(cmd) switch (cmd) {
{ case WDIOC_GETSTATUS:
case WDIOC_GETSTATUS: status = mixcomwd_opened;
status=mixcomwd_opened; if (!nowayout)
if (!nowayout) { status |= mixcomwd_timer_alive;
status|=mixcomwd_timer_alive; return put_user(status, p);
} case WDIOC_GETBOOTSTATUS:
if (copy_to_user(p, &status, sizeof(int))) { return put_user(0, p);
return -EFAULT; case WDIOC_GETSUPPORT:
} if (copy_to_user(argp, &ident, sizeof(ident)))
break; return -EFAULT;
case WDIOC_GETBOOTSTATUS: break;
if (copy_to_user(p, &status, sizeof(int))) { case WDIOC_KEEPALIVE:
return -EFAULT; mixcomwd_ping();
} break;
break; default:
case WDIOC_GETSUPPORT: return -ENOTTY;
if (copy_to_user(argp, &ident, sizeof(ident))) {
return -EFAULT;
}
break;
case WDIOC_KEEPALIVE:
mixcomwd_ping();
break;
default:
return -ENOTTY;
} }
return 0; return 0;
} }
...@@ -238,7 +232,7 @@ static const struct file_operations mixcomwd_fops = { ...@@ -238,7 +232,7 @@ static const struct file_operations mixcomwd_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = mixcomwd_write, .write = mixcomwd_write,
.ioctl = mixcomwd_ioctl, .unlocked_ioctl = mixcomwd_ioctl,
.open = mixcomwd_open, .open = mixcomwd_open,
.release = mixcomwd_release, .release = mixcomwd_release,
}; };
...@@ -253,15 +247,14 @@ static int __init checkcard(int port, int card_id) ...@@ -253,15 +247,14 @@ static int __init checkcard(int port, int card_id)
{ {
int id; int id;
if (!request_region(port, 1, "MixCOM watchdog")) { if (!request_region(port, 1, "MixCOM watchdog"))
return 0; return 0;
}
id=inb_p(port); id = inb_p(port);
if (card_id==MIXCOM_ID) if (card_id == MIXCOM_ID)
id &= 0x3f; id &= 0x3f;
if (id!=card_id) { if (id != card_id) {
release_region(port, 1); release_region(port, 1);
return 0; return 0;
} }
...@@ -270,9 +263,7 @@ static int __init checkcard(int port, int card_id) ...@@ -270,9 +263,7 @@ static int __init checkcard(int port, int card_id)
static int __init mixcomwd_init(void) static int __init mixcomwd_init(void)
{ {
int i; int i, ret, found = 0;
int ret;
int found=0;
for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) { for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) {
if (checkcard(mixcomwd_io_info[i].ioport, if (checkcard(mixcomwd_io_info[i].ioport,
...@@ -283,20 +274,22 @@ static int __init mixcomwd_init(void) ...@@ -283,20 +274,22 @@ static int __init mixcomwd_init(void)
} }
if (!found) { if (!found) {
printk(KERN_ERR PFX "No card detected, or port not available.\n"); printk(KERN_ERR PFX
"No card detected, or port not available.\n");
return -ENODEV; return -ENODEV;
} }
ret = misc_register(&mixcomwd_miscdev); ret = misc_register(&mixcomwd_miscdev);
if (ret) if (ret) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
goto error_misc_register_watchdog; goto error_misc_register_watchdog;
} }
printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n", printk(KERN_INFO
VERSION, watchdog_port); "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
VERSION, watchdog_port);
return 0; return 0;
...@@ -309,15 +302,15 @@ static int __init mixcomwd_init(void) ...@@ -309,15 +302,15 @@ static int __init mixcomwd_init(void)
static void __exit mixcomwd_exit(void) static void __exit mixcomwd_exit(void)
{ {
if (!nowayout) { if (!nowayout) {
if(mixcomwd_timer_alive) { if (mixcomwd_timer_alive) {
printk(KERN_WARNING PFX "I quit now, hardware will" printk(KERN_WARNING PFX "I quit now, hardware will"
" probably reboot!\n"); " probably reboot!\n");
del_timer_sync(&mixcomwd_timer); del_timer_sync(&mixcomwd_timer);
mixcomwd_timer_alive=0; mixcomwd_timer_alive = 0;
} }
} }
misc_deregister(&mixcomwd_miscdev); misc_deregister(&mixcomwd_miscdev);
release_region(watchdog_port,1); release_region(watchdog_port, 1);
} }
module_init(mixcomwd_init); module_init(mixcomwd_init);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/mpc52xx.h> #include <asm/mpc52xx.h>
...@@ -57,7 +57,8 @@ static int mpc5200_wdt_start(struct mpc5200_wdt *wdt) ...@@ -57,7 +57,8 @@ static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
/* set timeout, with maximum prescaler */ /* set timeout, with maximum prescaler */
out_be32(&wdt->regs->count, 0x0 | wdt->count); out_be32(&wdt->regs->count, 0x0 | wdt->count);
/* enable watchdog */ /* enable watchdog */
out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER); out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT |
GPT_MODE_MS_TIMER);
spin_unlock(&wdt->io_lock); spin_unlock(&wdt->io_lock);
return 0; return 0;
...@@ -66,7 +67,8 @@ static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt) ...@@ -66,7 +67,8 @@ static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
{ {
spin_lock(&wdt->io_lock); spin_lock(&wdt->io_lock);
/* writing A5 to OCPW resets the watchdog */ /* writing A5 to OCPW resets the watchdog */
out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode))); out_be32(&wdt->regs->mode, 0xA5000000 |
(0xffffff & in_be32(&wdt->regs->mode)));
spin_unlock(&wdt->io_lock); spin_unlock(&wdt->io_lock);
return 0; return 0;
} }
...@@ -92,8 +94,8 @@ static struct watchdog_info mpc5200_wdt_info = { ...@@ -92,8 +94,8 @@ static struct watchdog_info mpc5200_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "mpc5200 watchdog on GPT0", .identity = "mpc5200 watchdog on GPT0",
}; };
static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, static long mpc5200_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
struct mpc5200_wdt *wdt = file->private_data; struct mpc5200_wdt *wdt = file->private_data;
int __user *data = (int __user *)arg; int __user *data = (int __user *)arg;
...@@ -103,7 +105,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -103,7 +105,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
ret = copy_to_user(data, &mpc5200_wdt_info, ret = copy_to_user(data, &mpc5200_wdt_info,
sizeof(mpc5200_wdt_info)); sizeof(mpc5200_wdt_info));
if (ret) if (ret)
ret = -EFAULT; ret = -EFAULT;
break; break;
...@@ -135,6 +137,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -135,6 +137,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
} }
return ret; return ret;
} }
static int mpc5200_wdt_open(struct inode *inode, struct file *file) static int mpc5200_wdt_open(struct inode *inode, struct file *file)
{ {
/* /dev/watchdog can only be opened once */ /* /dev/watchdog can only be opened once */
...@@ -167,7 +170,8 @@ static const struct file_operations mpc5200_wdt_fops = { ...@@ -167,7 +170,8 @@ static const struct file_operations mpc5200_wdt_fops = {
}; };
/* module operations */ /* module operations */
static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match) static int mpc5200_wdt_probe(struct of_device *op,
const struct of_device_id *match)
{ {
struct mpc5200_wdt *wdt; struct mpc5200_wdt *wdt;
int err; int err;
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
struct mpc83xx_wdt { struct mpc83xx_wdt {
__be32 res0; __be32 res0;
...@@ -42,11 +42,13 @@ static struct mpc83xx_wdt __iomem *wd_base; ...@@ -42,11 +42,13 @@ static struct mpc83xx_wdt __iomem *wd_base;
static u16 timeout = 0xffff; static u16 timeout = 0xffff;
module_param(timeout, ushort, 0); module_param(timeout, ushort, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in ticks. (0<timeout<65536, default=65535");
static int reset = 1; static int reset = 1;
module_param(reset, bool, 0); module_param(reset, bool, 0);
MODULE_PARM_DESC(reset, "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset"); MODULE_PARM_DESC(reset,
"Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
/* /*
* We always prescale, but if someone really doesn't want to they can set this * We always prescale, but if someone really doesn't want to they can set this
...@@ -105,8 +107,8 @@ static int mpc83xx_wdt_release(struct inode *inode, struct file *file) ...@@ -105,8 +107,8 @@ static int mpc83xx_wdt_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file, static long mpc83xx_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
...@@ -136,7 +138,7 @@ static const struct file_operations mpc83xx_wdt_fops = { ...@@ -136,7 +138,7 @@ static const struct file_operations mpc83xx_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = mpc83xx_wdt_write, .write = mpc83xx_wdt_write,
.ioctl = mpc83xx_wdt_ioctl, .unlocked_ioctl = mpc83xx_wdt_ioctl,
.open = mpc83xx_wdt_open, .open = mpc83xx_wdt_open,
.release = mpc83xx_wdt_release, .release = mpc83xx_wdt_release,
}; };
...@@ -161,8 +163,7 @@ static int __devinit mpc83xx_wdt_probe(struct platform_device *dev) ...@@ -161,8 +163,7 @@ static int __devinit mpc83xx_wdt_probe(struct platform_device *dev)
goto err_out; goto err_out;
} }
wd_base = ioremap(r->start, sizeof (struct mpc83xx_wdt)); wd_base = ioremap(r->start, sizeof(struct mpc83xx_wdt));
if (wd_base == NULL) { if (wd_base == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_out; goto err_out;
......
...@@ -16,36 +16,35 @@ ...@@ -16,36 +16,35 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/8xx_immap.h> #include <asm/8xx_immap.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <linux/io.h>
#include <syslib/m8xx_wdt.h> #include <syslib/m8xx_wdt.h>
static unsigned long wdt_opened; static unsigned long wdt_opened;
static int wdt_status; static int wdt_status;
static spinlock_t wdt_lock;
static void mpc8xx_wdt_handler_disable(void) static void mpc8xx_wdt_handler_disable(void)
{ {
volatile uint __iomem *piscr; volatile uint __iomem *piscr;
piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr; piscr = (uint *)&((immap_t *)IMAP_ADDR)->im_sit.sit_piscr;
if (!m8xx_has_internal_rtc) if (!m8xx_has_internal_rtc)
m8xx_wdt_stop_timer(); m8xx_wdt_stop_timer();
else else
out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE)); out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n"); printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
} }
static void mpc8xx_wdt_handler_enable(void) static void mpc8xx_wdt_handler_enable(void)
{ {
volatile uint __iomem *piscr; volatile uint __iomem *piscr;
piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr; piscr = (uint *)&((immap_t *)IMAP_ADDR)->im_sit.sit_piscr;
if (!m8xx_has_internal_rtc) if (!m8xx_has_internal_rtc)
m8xx_wdt_install_timer(); m8xx_wdt_install_timer();
else else
out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE); out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n"); printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
} }
...@@ -53,37 +52,34 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file) ...@@ -53,37 +52,34 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &wdt_opened)) if (test_and_set_bit(0, &wdt_opened))
return -EBUSY; return -EBUSY;
m8xx_wdt_reset(); m8xx_wdt_reset();
mpc8xx_wdt_handler_disable(); mpc8xx_wdt_handler_disable();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int mpc8xx_wdt_release(struct inode *inode, struct file *file) static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
{ {
m8xx_wdt_reset(); m8xx_wdt_reset();
#if !defined(CONFIG_WATCHDOG_NOWAYOUT) #if !defined(CONFIG_WATCHDOG_NOWAYOUT)
mpc8xx_wdt_handler_enable(); mpc8xx_wdt_handler_enable();
#endif #endif
clear_bit(0, &wdt_opened); clear_bit(0, &wdt_opened);
return 0; return 0;
} }
static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len, static ssize_t mpc8xx_wdt_write(struct file *file, const char *data,
loff_t * ppos) size_t len, loff_t *ppos)
{ {
if (len) if (len) {
spin_lock(&wdt_lock);
m8xx_wdt_reset(); m8xx_wdt_reset();
spin_unlock(&wdt_lock);
}
return len; return len;
} }
static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file, static long mpc8xx_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int timeout; int timeout;
static struct watchdog_info info = { static struct watchdog_info info = {
...@@ -112,15 +108,19 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -112,15 +108,19 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
return -EOPNOTSUPP; return -EOPNOTSUPP;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);
m8xx_wdt_reset(); m8xx_wdt_reset();
wdt_status |= WDIOF_KEEPALIVEPING; wdt_status |= WDIOF_KEEPALIVEPING;
spin_unlock(&wdt_lock);
break; break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
return -EOPNOTSUPP; return -EOPNOTSUPP;
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
spin_lock(&wdt_lock);
timeout = m8xx_wdt_get_timeout(); timeout = m8xx_wdt_get_timeout();
spin_unlock(&wdt_lock);
if (put_user(timeout, (int *)arg)) if (put_user(timeout, (int *)arg))
return -EFAULT; return -EFAULT;
break; break;
...@@ -136,7 +136,7 @@ static const struct file_operations mpc8xx_wdt_fops = { ...@@ -136,7 +136,7 @@ static const struct file_operations mpc8xx_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = mpc8xx_wdt_write, .write = mpc8xx_wdt_write,
.ioctl = mpc8xx_wdt_ioctl, .unlocked_ioctl = mpc8xx_wdt_ioctl,
.open = mpc8xx_wdt_open, .open = mpc8xx_wdt_open,
.release = mpc8xx_wdt_release, .release = mpc8xx_wdt_release,
}; };
...@@ -149,6 +149,7 @@ static struct miscdevice mpc8xx_wdt_miscdev = { ...@@ -149,6 +149,7 @@ static struct miscdevice mpc8xx_wdt_miscdev = {
static int __init mpc8xx_wdt_init(void) static int __init mpc8xx_wdt_init(void)
{ {
spin_lock_init(&wdt_lock);
return misc_register(&mpc8xx_wdt_miscdev); return misc_register(&mpc8xx_wdt_miscdev);
} }
......
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <asm/hardware/arm_twd.h> #include <asm/hardware/arm_twd.h>
#include <asm/uaccess.h>
struct mpcore_wdt { struct mpcore_wdt {
unsigned long timer_alive; unsigned long timer_alive;
...@@ -43,17 +43,20 @@ struct mpcore_wdt { ...@@ -43,17 +43,20 @@ struct mpcore_wdt {
}; };
static struct platform_device *mpcore_wdt_dev; static struct platform_device *mpcore_wdt_dev;
extern unsigned int mpcore_timer_rate; extern unsigned int mpcore_timer_rate;
#define TIMER_MARGIN 60 #define TIMER_MARGIN 60
static int mpcore_margin = TIMER_MARGIN; static int mpcore_margin = TIMER_MARGIN;
module_param(mpcore_margin, int, 0); module_param(mpcore_margin, int, 0);
MODULE_PARM_DESC(mpcore_margin, "MPcore timer margin in seconds. (0<mpcore_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")"); MODULE_PARM_DESC(mpcore_margin,
"MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default="
__MODULE_STRING(TIMER_MARGIN) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#define ONLY_TESTING 0 #define ONLY_TESTING 0
static int mpcore_noboot = ONLY_TESTING; static int mpcore_noboot = ONLY_TESTING;
...@@ -70,14 +73,12 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg) ...@@ -70,14 +73,12 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
/* Check it really was our interrupt */ /* Check it really was our interrupt */
if (readl(wdt->base + TWD_WDOG_INTSTAT)) { if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
dev_printk(KERN_CRIT, wdt->dev, "Triggered - Reboot ignored.\n"); dev_printk(KERN_CRIT, wdt->dev,
"Triggered - Reboot ignored.\n");
/* Clear the interrupt on the watchdog */ /* Clear the interrupt on the watchdog */
writel(1, wdt->base + TWD_WDOG_INTSTAT); writel(1, wdt->base + TWD_WDOG_INTSTAT);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -96,22 +97,26 @@ static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt) ...@@ -96,22 +97,26 @@ static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
count = (mpcore_timer_rate / 256) * mpcore_margin; count = (mpcore_timer_rate / 256) * mpcore_margin;
/* Reload the counter */ /* Reload the counter */
spin_lock(&wdt_lock);
writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD); writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
wdt->perturb = wdt->perturb ? 0 : 1; wdt->perturb = wdt->perturb ? 0 : 1;
spin_unlock(&wdt_lock);
} }
static void mpcore_wdt_stop(struct mpcore_wdt *wdt) static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
{ {
spin_lock(&wdt_lock);
writel(0x12345678, wdt->base + TWD_WDOG_DISABLE); writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
writel(0x87654321, wdt->base + TWD_WDOG_DISABLE); writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
writel(0x0, wdt->base + TWD_WDOG_CONTROL); writel(0x0, wdt->base + TWD_WDOG_CONTROL);
spin_unlock(&wdt_lock);
} }
static void mpcore_wdt_start(struct mpcore_wdt *wdt) static void mpcore_wdt_start(struct mpcore_wdt *wdt)
{ {
dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n"); dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
spin_lock(&wdt_lock);
/* This loads the count register but does NOT start the count yet */ /* This loads the count register but does NOT start the count yet */
mpcore_wdt_keepalive(wdt); mpcore_wdt_keepalive(wdt);
...@@ -122,6 +127,7 @@ static void mpcore_wdt_start(struct mpcore_wdt *wdt) ...@@ -122,6 +127,7 @@ static void mpcore_wdt_start(struct mpcore_wdt *wdt)
/* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */ /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL); writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
} }
spin_unlock(&wdt_lock);
} }
static int mpcore_wdt_set_heartbeat(int t) static int mpcore_wdt_set_heartbeat(int t)
...@@ -164,10 +170,11 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file) ...@@ -164,10 +170,11 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
* Shut off the timer. * Shut off the timer.
* Lock it in if it's a module and we set nowayout * Lock it in if it's a module and we set nowayout
*/ */
if (wdt->expect_close == 42) { if (wdt->expect_close == 42)
mpcore_wdt_stop(wdt); mpcore_wdt_stop(wdt);
} else { else {
dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n"); dev_printk(KERN_CRIT, wdt->dev,
"unexpected close, not stopping watchdog!\n");
mpcore_wdt_keepalive(wdt); mpcore_wdt_keepalive(wdt);
} }
clear_bit(0, &wdt->timer_alive); clear_bit(0, &wdt->timer_alive);
...@@ -175,7 +182,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file) ...@@ -175,7 +182,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static ssize_t mpcore_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) static ssize_t mpcore_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{ {
struct mpcore_wdt *wdt = file->private_data; struct mpcore_wdt *wdt = file->private_data;
...@@ -210,8 +218,8 @@ static struct watchdog_info ident = { ...@@ -210,8 +218,8 @@ static struct watchdog_info ident = {
.identity = "MPcore Watchdog", .identity = "MPcore Watchdog",
}; };
static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
struct mpcore_wdt *wdt = file->private_data; struct mpcore_wdt *wdt = file->private_data;
int ret; int ret;
...@@ -301,7 +309,7 @@ static const struct file_operations mpcore_wdt_fops = { ...@@ -301,7 +309,7 @@ static const struct file_operations mpcore_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = mpcore_wdt_write, .write = mpcore_wdt_write,
.ioctl = mpcore_wdt_ioctl, .unlocked_ioctl = mpcore_wdt_ioctl,
.open = mpcore_wdt_open, .open = mpcore_wdt_open,
.release = mpcore_wdt_release, .release = mpcore_wdt_release,
}; };
...@@ -349,14 +357,17 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) ...@@ -349,14 +357,17 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
mpcore_wdt_miscdev.parent = &dev->dev; mpcore_wdt_miscdev.parent = &dev->dev;
ret = misc_register(&mpcore_wdt_miscdev); ret = misc_register(&mpcore_wdt_miscdev);
if (ret) { if (ret) {
dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n", dev_printk(KERN_ERR, _dev,
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto err_misc; goto err_misc;
} }
ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, "mpcore_wdt", wdt); ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED,
"mpcore_wdt", wdt);
if (ret) { if (ret) {
dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq); dev_printk(KERN_ERR, _dev,
"cannot register IRQ%d for watchdog\n", wdt->irq);
goto err_irq; goto err_irq;
} }
...@@ -415,7 +426,7 @@ static int __init mpcore_wdt_init(void) ...@@ -415,7 +426,7 @@ static int __init mpcore_wdt_init(void)
*/ */
if (mpcore_wdt_set_heartbeat(mpcore_margin)) { if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
mpcore_wdt_set_heartbeat(TIMER_MARGIN); mpcore_wdt_set_heartbeat(TIMER_MARGIN);
printk(KERN_INFO "mpcore_margin value must be 0<mpcore_margin<65536, using %d\n", printk(KERN_INFO "mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
TIMER_MARGIN); TIMER_MARGIN);
} }
......
/* /*
* Driver for the MTX-1 Watchdog. * Driver for the MTX-1 Watchdog.
* *
* (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved. * (C) Copyright 2005 4G Systems <info@4g-systems.biz>,
* All Rights Reserved.
* http://www.4g-systems.biz * http://www.4g-systems.biz
* *
* (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
...@@ -46,12 +47,11 @@ ...@@ -46,12 +47,11 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h>
#include <asm/io.h> #include <linux/uaccess.h>
#include <asm/uaccess.h> #include <linux/gpio.h>
#include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1000.h>
#include <asm/gpio.h>
#define MTX1_WDT_INTERVAL (5 * HZ) #define MTX1_WDT_INTERVAL (5 * HZ)
...@@ -59,6 +59,7 @@ static int ticks = 100 * HZ; ...@@ -59,6 +59,7 @@ static int ticks = 100 * HZ;
static struct { static struct {
struct completion stop; struct completion stop;
spinlock_t lock;
int running; int running;
struct timer_list timer; struct timer_list timer;
int queue; int queue;
...@@ -71,6 +72,7 @@ static void mtx1_wdt_trigger(unsigned long unused) ...@@ -71,6 +72,7 @@ static void mtx1_wdt_trigger(unsigned long unused)
{ {
u32 tmp; u32 tmp;
spin_lock(&mtx1_wdt_device.lock);
if (mtx1_wdt_device.running) if (mtx1_wdt_device.running)
ticks--; ticks--;
/* /*
...@@ -79,13 +81,13 @@ static void mtx1_wdt_trigger(unsigned long unused) ...@@ -79,13 +81,13 @@ static void mtx1_wdt_trigger(unsigned long unused)
tmp = au_readl(GPIO2_DIR); tmp = au_readl(GPIO2_DIR);
tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) | tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) |
((~tmp) & (1 << mtx1_wdt_device.gpio)); ((~tmp) & (1 << mtx1_wdt_device.gpio));
au_writel (tmp, GPIO2_DIR); au_writel(tmp, GPIO2_DIR);
if (mtx1_wdt_device.queue && ticks) if (mtx1_wdt_device.queue && ticks)
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
else { else
complete(&mtx1_wdt_device.stop); complete(&mtx1_wdt_device.stop);
} spin_unlock(&mtx1_wdt_device.lock);
} }
static void mtx1_wdt_reset(void) static void mtx1_wdt_reset(void)
...@@ -96,23 +98,25 @@ static void mtx1_wdt_reset(void) ...@@ -96,23 +98,25 @@ static void mtx1_wdt_reset(void)
static void mtx1_wdt_start(void) static void mtx1_wdt_start(void)
{ {
spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
if (!mtx1_wdt_device.queue) { if (!mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 1; mtx1_wdt_device.queue = 1;
gpio_set_value(mtx1_wdt_device.gpio, 1); gpio_set_value(mtx1_wdt_device.gpio, 1);
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
} }
mtx1_wdt_device.running++; mtx1_wdt_device.running++;
spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
} }
static int mtx1_wdt_stop(void) static int mtx1_wdt_stop(void)
{ {
spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
if (mtx1_wdt_device.queue) { if (mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 0; mtx1_wdt_device.queue = 0;
gpio_set_value(mtx1_wdt_device.gpio, 0); gpio_set_value(mtx1_wdt_device.gpio, 0);
} }
ticks = mtx1_wdt_device.default_ticks; ticks = mtx1_wdt_device.default_ticks;
spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
return 0; return 0;
} }
...@@ -122,7 +126,6 @@ static int mtx1_wdt_open(struct inode *inode, struct file *file) ...@@ -122,7 +126,6 @@ static int mtx1_wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) if (test_and_set_bit(0, &mtx1_wdt_device.inuse))
return -EBUSY; return -EBUSY;
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -133,54 +136,51 @@ static int mtx1_wdt_release(struct inode *inode, struct file *file) ...@@ -133,54 +136,51 @@ static int mtx1_wdt_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static long mtx1_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = (int __user *)argp;
unsigned int value; unsigned int value;
static struct watchdog_info ident = static const struct watchdog_info ident = {
{
.options = WDIOF_CARDRESET, .options = WDIOF_CARDRESET,
.identity = "MTX-1 WDT", .identity = "MTX-1 WDT",
}; };
switch(cmd) { switch (cmd) {
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
mtx1_wdt_reset(); mtx1_wdt_reset();
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) ) put_user(0, p);
return -EFAULT; break;
break; case WDIOC_GETSUPPORT:
case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident)))
if ( copy_to_user(argp, &ident, sizeof(ident)) ) return -EFAULT;
return -EFAULT; break;
break; case WDIOC_SETOPTIONS:
case WDIOC_SETOPTIONS: if (get_user(value, p))
if ( copy_from_user(&value, argp, sizeof(int)) ) return -EFAULT;
return -EFAULT; if (value & WDIOS_ENABLECARD)
switch(value) { mtx1_wdt_start();
case WDIOS_ENABLECARD: else if (value & WDIOS_DISABLECARD)
mtx1_wdt_start(); mtx1_wdt_stop();
break; else
case WDIOS_DISABLECARD: return -EINVAL;
return mtx1_wdt_stop(); return 0;
default: default:
return -EINVAL; return -ENOTTY;
}
break;
default:
return -ENOTTY;
} }
return 0; return 0;
} }
static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) static ssize_t mtx1_wdt_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{ {
if (!count) if (!count)
return -EIO; return -EIO;
mtx1_wdt_reset(); mtx1_wdt_reset();
return count; return count;
} }
...@@ -188,7 +188,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, ...@@ -188,7 +188,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count,
static const struct file_operations mtx1_wdt_fops = { static const struct file_operations mtx1_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.ioctl = mtx1_wdt_ioctl, .unlocked_ioctl = mtx1_wdt_ioctl,
.open = mtx1_wdt_open, .open = mtx1_wdt_open,
.write = mtx1_wdt_write, .write = mtx1_wdt_write,
.release = mtx1_wdt_release .release = mtx1_wdt_release
...@@ -208,29 +208,26 @@ static int mtx1_wdt_probe(struct platform_device *pdev) ...@@ -208,29 +208,26 @@ static int mtx1_wdt_probe(struct platform_device *pdev)
mtx1_wdt_device.gpio = pdev->resource[0].start; mtx1_wdt_device.gpio = pdev->resource[0].start;
if ((ret = misc_register(&mtx1_wdt_misc)) < 0) { spin_lock_init(&mtx1_wdt_device.lock);
printk(KERN_ERR " mtx-1_wdt : failed to register\n");
return ret;
}
init_completion(&mtx1_wdt_device.stop); init_completion(&mtx1_wdt_device.stop);
mtx1_wdt_device.queue = 0; mtx1_wdt_device.queue = 0;
clear_bit(0, &mtx1_wdt_device.inuse); clear_bit(0, &mtx1_wdt_device.inuse);
setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L);
mtx1_wdt_device.default_ticks = ticks; mtx1_wdt_device.default_ticks = ticks;
ret = misc_register(&mtx1_wdt_misc);
if (ret < 0) {
printk(KERN_ERR " mtx-1_wdt : failed to register\n");
return ret;
}
mtx1_wdt_start(); mtx1_wdt_start();
printk(KERN_INFO "MTX-1 Watchdog driver\n"); printk(KERN_INFO "MTX-1 Watchdog driver\n");
return 0; return 0;
} }
static int mtx1_wdt_remove(struct platform_device *pdev) static int mtx1_wdt_remove(struct platform_device *pdev)
{ {
/* FIXME: do we need to lock this test ? */
if (mtx1_wdt_device.queue) { if (mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 0; mtx1_wdt_device.queue = 0;
wait_for_completion(&mtx1_wdt_device.stop); wait_for_completion(&mtx1_wdt_device.stop);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* and services the watchdog. * and services the watchdog.
* *
* Derived from mpc8xx_wdt.c, with the following copyright. * Derived from mpc8xx_wdt.c, with the following copyright.
* *
* 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
* the terms of the GNU General Public License version 2. This program * the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express * is licensed "as is" without any warranty of any kind, whether express
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mv643xx.h> #include <linux/mv643xx.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <linux/io.h>
#define MV64x60_WDT_WDC_OFFSET 0 #define MV64x60_WDT_WDC_OFFSET 0
...@@ -61,7 +61,9 @@ static DEFINE_SPINLOCK(mv64x60_wdt_spinlock); ...@@ -61,7 +61,9 @@ static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift) static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
{ {
...@@ -150,7 +152,7 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file) ...@@ -150,7 +152,7 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file)
} }
static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos) size_t len, loff_t *ppos)
{ {
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
...@@ -160,7 +162,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, ...@@ -160,7 +162,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if(get_user(c, data + i)) if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
if (c == 'V') if (c == 'V')
expect_close = 42; expect_close = 42;
...@@ -172,8 +174,8 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, ...@@ -172,8 +174,8 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
return len; return len;
} }
static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, static long mv64x60_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int timeout; int timeout;
int options; int options;
...@@ -240,7 +242,7 @@ static const struct file_operations mv64x60_wdt_fops = { ...@@ -240,7 +242,7 @@ static const struct file_operations mv64x60_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = mv64x60_wdt_write, .write = mv64x60_wdt_write,
.ioctl = mv64x60_wdt_ioctl, .unlocked_ioctl = mv64x60_wdt_ioctl,
.open = mv64x60_wdt_open, .open = mv64x60_wdt_open,
.release = mv64x60_wdt_release, .release = mv64x60_wdt_release,
}; };
......
...@@ -41,9 +41,9 @@ ...@@ -41,9 +41,9 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <asm/io.h> #include </io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/hardware.h> #include <linux/hardware.h>
#include <asm/arch/prcm.h> #include <asm/arch/prcm.h>
...@@ -54,11 +54,12 @@ module_param(timer_margin, uint, 0); ...@@ -54,11 +54,12 @@ module_param(timer_margin, uint, 0);
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
static int omap_wdt_users; static int omap_wdt_users;
static struct clk *armwdt_ck = NULL; static struct clk *armwdt_ck;
static struct clk *mpu_wdt_ick = NULL; static struct clk *mpu_wdt_ick;
static struct clk *mpu_wdt_fck = NULL; static struct clk *mpu_wdt_fck;
static unsigned int wdt_trgr_pattern = 0x1234; static unsigned int wdt_trgr_pattern = 0x1234;
static spinlock_t wdt_lock;
static void omap_wdt_ping(void) static void omap_wdt_ping(void)
{ {
...@@ -174,22 +175,23 @@ static int omap_wdt_release(struct inode *inode, struct file *file) ...@@ -174,22 +175,23 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static ssize_t static ssize_t omap_wdt_write(struct file *file, const char __user *data,
omap_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
/* Refresh LOAD_TIME. */ /* Refresh LOAD_TIME. */
if (len) if (len) {
spin_lock(&wdt_lock);
omap_wdt_ping(); omap_wdt_ping();
spin_unlock(&wdt_lock);
}
return len; return len;
} }
static int static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
omap_wdt_ioctl(struct inode *inode, struct file *file, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
int new_margin; int new_margin;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.identity = "OMAP Watchdog", .identity = "OMAP Watchdog",
.options = WDIOF_SETTIMEOUT, .options = WDIOF_SETTIMEOUT,
.firmware_version = 0, .firmware_version = 0,
...@@ -211,18 +213,22 @@ omap_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -211,18 +213,22 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
return put_user(omap_prcm_get_reset_sources(), return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg); (int __user *)arg);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);
omap_wdt_ping(); omap_wdt_ping();
spin_unlock(&wdt_lock);
return 0; return 0;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(new_margin, (int __user *)arg)) if (get_user(new_margin, (int __user *)arg))
return -EFAULT; return -EFAULT;
omap_wdt_adjust_timeout(new_margin); omap_wdt_adjust_timeout(new_margin);
spin_lock(&wdt_lock);
omap_wdt_disable(); omap_wdt_disable();
omap_wdt_set_timeout(); omap_wdt_set_timeout();
omap_wdt_enable(); omap_wdt_enable();
omap_wdt_ping(); omap_wdt_ping();
spin_unlock(&wdt_lock);
/* Fall */ /* Fall */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(timer_margin, (int __user *)arg); return put_user(timer_margin, (int __user *)arg);
...@@ -232,7 +238,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -232,7 +238,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
static const struct file_operations omap_wdt_fops = { static const struct file_operations omap_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.write = omap_wdt_write, .write = omap_wdt_write,
.ioctl = omap_wdt_ioctl, .unlocked_ioctl = omap_wdt_ioctl,
.open = omap_wdt_open, .open = omap_wdt_open,
.release = omap_wdt_release, .release = omap_wdt_release,
}; };
...@@ -373,6 +379,7 @@ static struct platform_driver omap_wdt_driver = { ...@@ -373,6 +379,7 @@ static struct platform_driver omap_wdt_driver = {
static int __init omap_wdt_init(void) static int __init omap_wdt_init(void)
{ {
spin_lock_init(&wdt_lock);
return platform_driver_register(&omap_wdt_driver); return platform_driver_register(&omap_wdt_driver);
} }
......
...@@ -31,9 +31,9 @@ ...@@ -31,9 +31,9 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
/* #define DEBUG 1 */ /* #define DEBUG 1 */
...@@ -56,12 +56,12 @@ ...@@ -56,12 +56,12 @@
static int io = 0x2E; /* Address used on Portwell Boards */ static int io = 0x2E; /* Address used on Portwell Boards */
static int timeout = DEFAULT_TIMEOUT; /* timeout value */ static int timeout = DEFAULT_TIMEOUT; /* timeout value */
static unsigned long timer_enabled = 0; /* is the timer enabled? */ static unsigned long timer_enabled; /* is the timer enabled? */
static char expect_close; /* is the close expected? */ static char expect_close; /* is the close expected? */
static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */ static DEFINE_SPINLOCK(io_lock); /* to guard us from io races */
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
...@@ -69,7 +69,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; ...@@ -69,7 +69,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
/* Select pins for Watchdog output */ /* Select pins for Watchdog output */
static inline void pc87413_select_wdt_out (void) static inline void pc87413_select_wdt_out(void)
{ {
unsigned int cr_data = 0; unsigned int cr_data = 0;
...@@ -77,7 +77,7 @@ static inline void pc87413_select_wdt_out (void) ...@@ -77,7 +77,7 @@ static inline void pc87413_select_wdt_out (void)
outb_p(SIOCFG2, WDT_INDEX_IO_PORT); outb_p(SIOCFG2, WDT_INDEX_IO_PORT);
cr_data = inb (WDT_DATA_IO_PORT); cr_data = inb(WDT_DATA_IO_PORT);
cr_data |= 0x80; /* Set Bit7 to 1*/ cr_data |= 0x80; /* Set Bit7 to 1*/
outb_p(SIOCFG2, WDT_INDEX_IO_PORT); outb_p(SIOCFG2, WDT_INDEX_IO_PORT);
...@@ -85,8 +85,9 @@ static inline void pc87413_select_wdt_out (void) ...@@ -85,8 +85,9 @@ static inline void pc87413_select_wdt_out (void)
outb_p(cr_data, WDT_DATA_IO_PORT); outb_p(cr_data, WDT_DATA_IO_PORT);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:" printk(KERN_INFO DPFX
" Bit7 to 1: %d\n", cr_data); "Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n",
cr_data);
#endif #endif
} }
...@@ -94,7 +95,7 @@ static inline void pc87413_select_wdt_out (void) ...@@ -94,7 +95,7 @@ static inline void pc87413_select_wdt_out (void)
static inline void pc87413_enable_swc(void) static inline void pc87413_enable_swc(void)
{ {
unsigned int cr_data=0; unsigned int cr_data = 0;
/* Step 2: Enable SWC functions */ /* Step 2: Enable SWC functions */
...@@ -129,12 +130,11 @@ static inline unsigned int pc87413_get_swc_base(void) ...@@ -129,12 +130,11 @@ static inline unsigned int pc87413_get_swc_base(void)
addr_l = inb(WDT_DATA_IO_PORT); addr_l = inb(WDT_DATA_IO_PORT);
swc_base_addr = (addr_h << 8) + addr_l; swc_base_addr = (addr_h << 8) + addr_l;
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d," printk(KERN_INFO DPFX
" res %d\n", addr_l, addr_h, swc_base_addr); "Read SWC I/O Base Address: low %d, high %d, res %d\n",
addr_l, addr_h, swc_base_addr);
#endif #endif
return swc_base_addr; return swc_base_addr;
} }
...@@ -143,9 +143,7 @@ static inline unsigned int pc87413_get_swc_base(void) ...@@ -143,9 +143,7 @@ static inline unsigned int pc87413_get_swc_base(void)
static inline void pc87413_swc_bank3(unsigned int swc_base_addr) static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
{ {
/* Step 4: Select Bank3 of SWC */ /* Step 4: Select Bank3 of SWC */
outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); printk(KERN_INFO DPFX "Select Bank3 of SWC\n");
#endif #endif
...@@ -157,9 +155,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr, ...@@ -157,9 +155,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
char pc87413_time) char pc87413_time)
{ {
/* Step 5: Programm WDTO, Twd. */ /* Step 5: Programm WDTO, Twd. */
outb_p(pc87413_time, swc_base_addr + WDTO); outb_p(pc87413_time, swc_base_addr + WDTO);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);
#endif #endif
...@@ -170,9 +166,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr, ...@@ -170,9 +166,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
static inline void pc87413_enable_wden(unsigned int swc_base_addr) static inline void pc87413_enable_wden(unsigned int swc_base_addr)
{ {
/* Step 6: Enable WDEN */ /* Step 6: Enable WDEN */
outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "Enable WDEN\n"); printk(KERN_INFO DPFX "Enable WDEN\n");
#endif #endif
...@@ -182,9 +176,7 @@ static inline void pc87413_enable_wden(unsigned int swc_base_addr) ...@@ -182,9 +176,7 @@ static inline void pc87413_enable_wden(unsigned int swc_base_addr)
static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
{ {
/* Enable SW_WD_TREN */ /* Enable SW_WD_TREN */
outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");
#endif #endif
...@@ -195,9 +187,7 @@ static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) ...@@ -195,9 +187,7 @@ static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
{ {
/* Disable SW_WD_TREN */ /* Disable SW_WD_TREN */
outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");
#endif #endif
...@@ -208,9 +198,7 @@ static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) ...@@ -208,9 +198,7 @@ static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
{ {
/* Enable SW_WD_TRG */ /* Enable SW_WD_TRG */
outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");
#endif #endif
...@@ -221,9 +209,7 @@ static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) ...@@ -221,9 +209,7 @@ static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr) static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
{ {
/* Disable SW_WD_TRG */ /* Disable SW_WD_TRG */
outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");
#endif #endif
...@@ -314,8 +300,8 @@ static int pc87413_open(struct inode *inode, struct file *file) ...@@ -314,8 +300,8 @@ static int pc87413_open(struct inode *inode, struct file *file)
/* Reload and activate timer */ /* Reload and activate timer */
pc87413_refresh(); pc87413_refresh();
printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to" printk(KERN_INFO MODNAME
" %d minute(s).\n", timeout); "Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -338,17 +324,15 @@ static int pc87413_release(struct inode *inode, struct file *file) ...@@ -338,17 +324,15 @@ static int pc87413_release(struct inode *inode, struct file *file)
if (expect_close == 42) { if (expect_close == 42) {
pc87413_disable(); pc87413_disable();
printk(KERN_INFO MODNAME "Watchdog disabled," printk(KERN_INFO MODNAME
" sleeping again...\n"); "Watchdog disabled, sleeping again...\n");
} else { } else {
printk(KERN_CRIT MODNAME "Unexpected close, not stopping" printk(KERN_CRIT MODNAME
" watchdog!\n"); "Unexpected close, not stopping watchdog!\n");
pc87413_refresh(); pc87413_refresh();
} }
clear_bit(0, &timer_enabled); clear_bit(0, &timer_enabled);
expect_close = 0; expect_close = 0;
return 0; return 0;
} }
...@@ -386,7 +370,8 @@ static ssize_t pc87413_write(struct file *file, const char __user *data, ...@@ -386,7 +370,8 @@ static ssize_t pc87413_write(struct file *file, const char __user *data,
/* reset expect flag */ /* reset expect flag */
expect_close = 0; expect_close = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the
magic character */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if (get_user(c, data+i)) if (get_user(c, data+i))
...@@ -404,7 +389,6 @@ static ssize_t pc87413_write(struct file *file, const char __user *data, ...@@ -404,7 +389,6 @@ static ssize_t pc87413_write(struct file *file, const char __user *data,
/** /**
* pc87413_ioctl: * pc87413_ioctl:
* @inode: inode of the device
* @file: file handle to the device * @file: file handle to the device
* @cmd: watchdog command * @cmd: watchdog command
* @arg: argument pointer * @arg: argument pointer
...@@ -414,8 +398,8 @@ static ssize_t pc87413_write(struct file *file, const char __user *data, ...@@ -414,8 +398,8 @@ static ssize_t pc87413_write(struct file *file, const char __user *data,
* querying capabilities and current status. * querying capabilities and current status.
*/ */
static int pc87413_ioctl(struct inode *inode, struct file *file, static long pc87413_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int new_timeout; int new_timeout;
...@@ -426,75 +410,58 @@ static int pc87413_ioctl(struct inode *inode, struct file *file, ...@@ -426,75 +410,58 @@ static int pc87413_ioctl(struct inode *inode, struct file *file,
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | .options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "PC87413(HF/F) watchdog" .identity = "PC87413(HF/F) watchdog"
}; };
uarg.i = (int __user *)arg; uarg.i = (int __user *)arg;
switch(cmd) { switch (cmd) {
default: case WDIOC_GETSUPPORT:
return -ENOTTY; return copy_to_user(uarg.ident, &ident,
sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSUPPORT: case WDIOC_GETSTATUS:
return copy_to_user(uarg.ident, &ident, return put_user(pc87413_status(), uarg.i);
sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_GETSTATUS: case WDIOC_KEEPALIVE:
return put_user(pc87413_status(), uarg.i); pc87413_refresh();
case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_KEEPALIVE:
pc87413_refresh();
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO DPFX "keepalive\n"); printk(KERN_INFO DPFX "keepalive\n");
#endif #endif
return 0; return 0;
case WDIOC_SETTIMEOUT:
case WDIOC_SETTIMEOUT: if (get_user(new_timeout, uarg.i))
if (get_user(new_timeout, uarg.i)) return -EFAULT;
return -EFAULT; /* the API states this is given in secs */
new_timeout /= 60;
// the API states this is given in secs if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
new_timeout /= 60; return -EINVAL;
timeout = new_timeout;
if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) pc87413_refresh();
return -EINVAL; /* fall through and return the new timeout... */
case WDIOC_GETTIMEOUT:
timeout = new_timeout; new_timeout = timeout * 60;
pc87413_refresh(); return put_user(new_timeout, uarg.i);
case WDIOC_SETOPTIONS:
// fall through and return the new timeout... {
int options, retval = -EINVAL;
case WDIOC_GETTIMEOUT: if (get_user(options, uarg.i))
return -EFAULT;
new_timeout = timeout * 60; if (options & WDIOS_DISABLECARD) {
pc87413_disable();
return put_user(new_timeout, uarg.i); retval = 0;
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;
} }
if (options & WDIOS_ENABLECARD) {
pc87413_enable();
retval = 0;
}
return retval;
}
default:
return -ENOTTY;
} }
} }
...@@ -517,10 +484,8 @@ static int pc87413_notify_sys(struct notifier_block *this, ...@@ -517,10 +484,8 @@ static int pc87413_notify_sys(struct notifier_block *this,
void *unused) void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
{
/* Turn the card off */ /* Turn the card off */
pc87413_disable(); pc87413_disable();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -530,18 +495,16 @@ static const struct file_operations pc87413_fops = { ...@@ -530,18 +495,16 @@ static const struct file_operations pc87413_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = pc87413_write, .write = pc87413_write,
.ioctl = pc87413_ioctl, .unlocked_ioctl = pc87413_ioctl,
.open = pc87413_open, .open = pc87413_open,
.release = pc87413_release, .release = pc87413_release,
}; };
static struct notifier_block pc87413_notifier = static struct notifier_block pc87413_notifier = {
{
.notifier_call = pc87413_notify_sys, .notifier_call = pc87413_notify_sys,
}; };
static struct miscdevice pc87413_miscdev= static struct miscdevice pc87413_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &pc87413_fops .fops = &pc87413_fops
...@@ -561,29 +524,26 @@ static int __init pc87413_init(void) ...@@ -561,29 +524,26 @@ static int __init pc87413_init(void)
{ {
int ret; int ret;
printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT); printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
WDT_INDEX_IO_PORT);
/* request_region(io, 2, "pc87413"); */ /* request_region(io, 2, "pc87413"); */
ret = register_reboot_notifier(&pc87413_notifier); ret = register_reboot_notifier(&pc87413_notifier);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
} }
ret = misc_register(&pc87413_miscdev); ret = misc_register(&pc87413_miscdev);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret); WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&pc87413_notifier); unregister_reboot_notifier(&pc87413_notifier);
return ret; return ret;
} }
printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout); printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
pc87413_enable(); pc87413_enable();
return 0; return 0;
} }
...@@ -600,8 +560,7 @@ static int __init pc87413_init(void) ...@@ -600,8 +560,7 @@ static int __init pc87413_init(void)
static void __exit pc87413_exit(void) static void __exit pc87413_exit(void)
{ {
/* Stop the timer before we leave */ /* Stop the timer before we leave */
if (!nowayout) if (!nowayout) {
{
pc87413_disable(); pc87413_disable();
printk(KERN_INFO MODNAME "Watchdog disabled.\n"); printk(KERN_INFO MODNAME "Watchdog disabled.\n");
} }
...@@ -626,8 +585,12 @@ module_param(io, int, 0); ...@@ -626,8 +585,12 @@ module_param(io, int, 0);
MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ").");
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ")."); MODULE_PARM_DESC(timeout,
"Watchdog timeout in minutes (default="
__MODULE_STRING(timeout) ").");
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
...@@ -40,13 +40,15 @@ ...@@ -40,13 +40,15 @@
* fairly useless proc entry. * fairly useless proc entry.
* 990610 removed said useless proc code for the merge <alan> * 990610 removed said useless proc code for the merge <alan>
* 000403 Removed last traces of proc code. <davej> * 000403 Removed last traces of proc code. <davej>
* 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com> * 011214 Added nowayout module option to override
* CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
* Added timeout module option to override default * Added timeout module option to override default
*/ */
/* /*
* A bells and whistles driver is available from http://www.pcwd.de/ * A bells and whistles driver is available from http://www.pcwd.de/
* More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ * More info available at http://www.berkprod.com/ or
* http://www.pcwatchdog.com/
*/ */
#include <linux/module.h> /* For module specific items */ #include <linux/module.h> /* For module specific items */
...@@ -65,9 +67,8 @@ ...@@ -65,9 +67,8 @@
#include <linux/isa.h> /* For isa devices */ #include <linux/isa.h> /* For isa devices */
#include <linux/ioport.h> /* For io-port access */ #include <linux/ioport.h> /* For io-port access */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */ #include <linux/io.h> /* For inb/outb/... */
#include <asm/io.h> /* For inb/outb/... */
/* Module and version information */ /* Module and version information */
#define WATCHDOG_VERSION "1.20" #define WATCHDOG_VERSION "1.20"
...@@ -111,14 +112,16 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; ...@@ -111,14 +112,16 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */
#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */
#define WD_REVC_TTRP 0x04 /* Temperature Trip status */ #define WD_REVC_TTRP 0x04 /* Temperature Trip status */
#define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */ #define WD_REVC_RL2A 0x08 /* Relay 2 activated by
on-board processor */
#define WD_REVC_RL1A 0x10 /* Relay 1 active */ #define WD_REVC_RL1A 0x10 /* Relay 1 active */
#define WD_REVC_R2DS 0x40 /* Relay 2 disable */ #define WD_REVC_R2DS 0x40 /* Relay 2 disable */
#define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ #define WD_REVC_RLY2 0x80 /* Relay 2 activated? */
/* Port 2 : Control Status #2 */ /* Port 2 : Control Status #2 */
#define WD_WDIS 0x10 /* Watchdog Disabled */ #define WD_WDIS 0x10 /* Watchdog Disabled */
#define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */
#define WD_SSEL 0x40 /* Watchdog Switch Select (1:SW1 <-> 0:SW2) */ #define WD_SSEL 0x40 /* Watchdog Switch Select
(1:SW1 <-> 0:SW2) */
#define WD_WCMD 0x80 /* Watchdog Command Mode */ #define WD_WCMD 0x80 /* Watchdog Command Mode */
/* max. time we give an ISA watchdog card to process a command */ /* max. time we give an ISA watchdog card to process a command */
...@@ -168,11 +171,15 @@ static int cards_found; ...@@ -168,11 +171,15 @@ static int cards_found;
static atomic_t open_allowed = ATOMIC_INIT(1); static atomic_t open_allowed = ATOMIC_INIT(1);
static char expect_close; static char expect_close;
static int temp_panic; static int temp_panic;
static struct { /* this is private data for each ISA-PC watchdog card */
/* this is private data for each ISA-PC watchdog card */
static struct {
char fw_ver_str[6]; /* The cards firmware version */ char fw_ver_str[6]; /* The cards firmware version */
int revision; /* The card's revision */ int revision; /* The card's revision */
int supports_temp; /* Wether or not the card has a temperature device */ int supports_temp; /* Whether or not the card has
int command_mode; /* Wether or not the card is in command mode */ a temperature device */
int command_mode; /* Whether or not the card is in
command mode */
int boot_status; /* The card's boot status */ int boot_status; /* The card's boot status */
int io_addr; /* The cards I/O address */ int io_addr; /* The cards I/O address */
spinlock_t io_lock; /* the lock for io operations */ spinlock_t io_lock; /* the lock for io operations */
...@@ -186,16 +193,20 @@ static struct { /* this is private data for each ISA-PC watchdog card */ ...@@ -186,16 +193,20 @@ static struct { /* this is private data for each ISA-PC watchdog card */
#define DEBUG 2 /* print fancy stuff too */ #define DEBUG 2 /* print fancy stuff too */
static int debug = QUIET; static int debug = QUIET;
module_param(debug, int, 0); module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); MODULE_PARM_DESC(debug,
"Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */ /* default heartbeat = delay-time from dip-switches */
#define WATCHDOG_HEARTBEAT 0
static int heartbeat = WATCHDOG_HEARTBEAT; static int heartbeat = WATCHDOG_HEARTBEAT;
module_param(heartbeat, int, 0); module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2 <= heartbeat <= 7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Internal functions * Internal functions
...@@ -224,7 +235,7 @@ static int send_isa_command(int cmd) ...@@ -224,7 +235,7 @@ static int send_isa_command(int cmd)
if (port0 == last_port0) if (port0 == last_port0)
break; /* Data is stable */ break; /* Data is stable */
udelay (250); udelay(250);
} }
if (debug >= DEBUG) if (debug >= DEBUG)
...@@ -236,7 +247,7 @@ static int send_isa_command(int cmd) ...@@ -236,7 +247,7 @@ static int send_isa_command(int cmd)
static int set_command_mode(void) static int set_command_mode(void)
{ {
int i, found=0, count=0; int i, found = 0, count = 0;
/* Set the card into command mode */ /* Set the card into command mode */
spin_lock(&pcwd_private.io_lock); spin_lock(&pcwd_private.io_lock);
...@@ -296,7 +307,8 @@ static inline void pcwd_get_firmware(void) ...@@ -296,7 +307,8 @@ static inline void pcwd_get_firmware(void)
ten = send_isa_command(CMD_ISA_VERSION_TENTH); ten = send_isa_command(CMD_ISA_VERSION_TENTH);
hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
minor = send_isa_command(CMD_ISA_VERSION_MINOR); minor = send_isa_command(CMD_ISA_VERSION_MINOR);
sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor); sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c",
one, ten, hund, minor);
} }
unset_command_mode(); unset_command_mode();
...@@ -305,7 +317,7 @@ static inline void pcwd_get_firmware(void) ...@@ -305,7 +317,7 @@ static inline void pcwd_get_firmware(void)
static inline int pcwd_get_option_switches(void) static inline int pcwd_get_option_switches(void)
{ {
int option_switches=0; int option_switches = 0;
if (set_command_mode()) { if (set_command_mode()) {
/* Get switch settings */ /* Get switch settings */
...@@ -322,7 +334,9 @@ static void pcwd_show_card_info(void) ...@@ -322,7 +334,9 @@ static void pcwd_show_card_info(void)
/* Get some extra info from the hardware (in command/debug/diag mode) */ /* Get some extra info from the hardware (in command/debug/diag mode) */
if (pcwd_private.revision == PCWD_REVISION_A) if (pcwd_private.revision == PCWD_REVISION_A)
printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr); printk(KERN_INFO PFX
"ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
pcwd_private.io_addr);
else if (pcwd_private.revision == PCWD_REVISION_C) { else if (pcwd_private.revision == PCWD_REVISION_C) {
pcwd_get_firmware(); pcwd_get_firmware();
printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
...@@ -347,12 +361,15 @@ static void pcwd_show_card_info(void) ...@@ -347,12 +361,15 @@ static void pcwd_show_card_info(void)
printk(KERN_INFO PFX "Previous reboot was caused by the card\n"); printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
if (pcwd_private.boot_status & WDIOF_OVERHEAT) { if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n"); printk(KERN_EMERG PFX
printk(KERN_EMERG PFX "CPU Overheat\n"); "Card senses a CPU Overheat. Panicking!\n");
printk(KERN_EMERG PFX
"CPU Overheat\n");
} }
if (pcwd_private.boot_status == 0) if (pcwd_private.boot_status == 0)
printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n"); printk(KERN_INFO PFX
"No previous trip detected - Cold boot or reset\n");
} }
static void pcwd_timer_ping(unsigned long data) static void pcwd_timer_ping(unsigned long data)
...@@ -361,11 +378,12 @@ static void pcwd_timer_ping(unsigned long data) ...@@ -361,11 +378,12 @@ static void pcwd_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_INTERVAL /* If we got a heartbeat pulse within the WDT_INTERVAL
* we agree to ping the WDT */ * we agree to ping the WDT */
if(time_before(jiffies, pcwd_private.next_heartbeat)) { if (time_before(jiffies, pcwd_private.next_heartbeat)) {
/* Ping the watchdog */ /* Ping the watchdog */
spin_lock(&pcwd_private.io_lock); spin_lock(&pcwd_private.io_lock);
if (pcwd_private.revision == PCWD_REVISION_A) { if (pcwd_private.revision == PCWD_REVISION_A) {
/* Rev A cards are reset by setting the WD_WDRST bit in register 1 */ /* Rev A cards are reset by setting the
WD_WDRST bit in register 1 */
wdrst_stat = inb_p(pcwd_private.io_addr); wdrst_stat = inb_p(pcwd_private.io_addr);
wdrst_stat &= 0x0F; wdrst_stat &= 0x0F;
wdrst_stat |= WD_WDRST; wdrst_stat |= WD_WDRST;
...@@ -381,7 +399,8 @@ static void pcwd_timer_ping(unsigned long data) ...@@ -381,7 +399,8 @@ static void pcwd_timer_ping(unsigned long data)
spin_unlock(&pcwd_private.io_lock); spin_unlock(&pcwd_private.io_lock);
} else { } else {
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); printk(KERN_WARNING PFX
"Heartbeat lost! Will not ping the watchdog\n");
} }
} }
...@@ -454,7 +473,7 @@ static int pcwd_keepalive(void) ...@@ -454,7 +473,7 @@ static int pcwd_keepalive(void)
static int pcwd_set_heartbeat(int t) static int pcwd_set_heartbeat(int t)
{ {
if ((t < 2) || (t > 7200)) /* arbitrary upper limit */ if (t < 2 || t > 7200) /* arbitrary upper limit */
return -EINVAL; return -EINVAL;
heartbeat = t; heartbeat = t;
...@@ -470,7 +489,7 @@ static int pcwd_get_status(int *status) ...@@ -470,7 +489,7 @@ static int pcwd_get_status(int *status)
{ {
int control_status; int control_status;
*status=0; *status = 0;
spin_lock(&pcwd_private.io_lock); spin_lock(&pcwd_private.io_lock);
if (pcwd_private.revision == PCWD_REVISION_A) if (pcwd_private.revision == PCWD_REVISION_A)
/* Rev A cards return status information from /* Rev A cards return status information from
...@@ -494,9 +513,9 @@ static int pcwd_get_status(int *status) ...@@ -494,9 +513,9 @@ static int pcwd_get_status(int *status)
if (control_status & WD_T110) { if (control_status & WD_T110) {
*status |= WDIOF_OVERHEAT; *status |= WDIOF_OVERHEAT;
if (temp_panic) { if (temp_panic) {
printk(KERN_INFO PFX "Temperature overheat trip!\n"); printk(KERN_INFO PFX
"Temperature overheat trip!\n");
kernel_power_off(); kernel_power_off();
/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
} }
} }
} else { } else {
...@@ -506,9 +525,9 @@ static int pcwd_get_status(int *status) ...@@ -506,9 +525,9 @@ static int pcwd_get_status(int *status)
if (control_status & WD_REVC_TTRP) { if (control_status & WD_REVC_TTRP) {
*status |= WDIOF_OVERHEAT; *status |= WDIOF_OVERHEAT;
if (temp_panic) { if (temp_panic) {
printk(KERN_INFO PFX "Temperature overheat trip!\n"); printk(KERN_INFO PFX
"Temperature overheat trip!\n");
kernel_power_off(); kernel_power_off();
/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
} }
} }
} }
...@@ -524,18 +543,21 @@ static int pcwd_clear_status(void) ...@@ -524,18 +543,21 @@ static int pcwd_clear_status(void)
spin_lock(&pcwd_private.io_lock); spin_lock(&pcwd_private.io_lock);
if (debug >= VERBOSE) if (debug >= VERBOSE)
printk(KERN_INFO PFX "clearing watchdog trip status\n"); printk(KERN_INFO PFX
"clearing watchdog trip status\n");
control_status = inb_p(pcwd_private.io_addr + 1); control_status = inb_p(pcwd_private.io_addr + 1);
if (debug >= DEBUG) { if (debug >= DEBUG) {
printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status); printk(KERN_DEBUG PFX "status was: 0x%02x\n",
control_status);
printk(KERN_DEBUG PFX "sending: 0x%02x\n", printk(KERN_DEBUG PFX "sending: 0x%02x\n",
(control_status & WD_REVC_R2DS)); (control_status & WD_REVC_R2DS));
} }
/* clear reset status & Keep Relay 2 disable state as it is */ /* clear reset status & Keep Relay 2 disable state as it is */
outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1); outb_p((control_status & WD_REVC_R2DS),
pcwd_private.io_addr + 1);
spin_unlock(&pcwd_private.io_lock); spin_unlock(&pcwd_private.io_lock);
} }
...@@ -572,8 +594,7 @@ static int pcwd_get_temperature(int *temperature) ...@@ -572,8 +594,7 @@ static int pcwd_get_temperature(int *temperature)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static int pcwd_ioctl(struct inode *inode, struct file *file, static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
int rv; int rv;
int status; int status;
...@@ -590,12 +611,12 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, ...@@ -590,12 +611,12 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
.identity = "PCWD", .identity = "PCWD",
}; };
switch(cmd) { switch (cmd) {
default: default:
return -ENOTTY; return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident))) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -613,25 +634,22 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, ...@@ -613,25 +634,22 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
return put_user(temperature, argp); return put_user(temperature, argp);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
if (pcwd_private.revision == PCWD_REVISION_C) if (pcwd_private.revision == PCWD_REVISION_C) {
{ if (get_user(rv, argp))
if(copy_from_user(&rv, argp, sizeof(int)))
return -EFAULT; return -EFAULT;
if (rv & WDIOS_DISABLECARD) if (rv & WDIOS_DISABLECARD) {
{ status = pcwd_stop();
return pcwd_stop(); if (status < 0)
return status;
} }
if (rv & WDIOS_ENABLECARD) {
if (rv & WDIOS_ENABLECARD) status = pcwd_start();
{ if (status < 0)
return pcwd_start(); return status;
} }
if (rv & WDIOS_TEMPPANIC) if (rv & WDIOS_TEMPPANIC)
{
temp_panic = 1; temp_panic = 1;
}
} }
return -EINVAL; return -EINVAL;
...@@ -682,16 +700,10 @@ static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len, ...@@ -682,16 +700,10 @@ static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len,
static int pcwd_open(struct inode *inode, struct file *file) static int pcwd_open(struct inode *inode, struct file *file)
{ {
if (!atomic_dec_and_test(&open_allowed) ) { if (test_and_set_bit(0, &open_allowed))
if (debug >= VERBOSE)
printk(KERN_ERR PFX "Attempt to open already opened device.\n");
atomic_inc( &open_allowed );
return -EBUSY; return -EBUSY;
}
if (nowayout) if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
/* Activate */ /* Activate */
pcwd_start(); pcwd_start();
pcwd_keepalive(); pcwd_keepalive();
...@@ -700,14 +712,15 @@ static int pcwd_open(struct inode *inode, struct file *file) ...@@ -700,14 +712,15 @@ static int pcwd_open(struct inode *inode, struct file *file)
static int pcwd_close(struct inode *inode, struct file *file) static int pcwd_close(struct inode *inode, struct file *file)
{ {
if (expect_close == 42) { if (expect_close == 42)
pcwd_stop(); pcwd_stop();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
pcwd_keepalive(); pcwd_keepalive();
} }
expect_close = 0; expect_close = 0;
atomic_inc( &open_allowed ); clear_bit(0, &open_allowed);
return 0; return 0;
} }
...@@ -750,7 +763,7 @@ static const struct file_operations pcwd_fops = { ...@@ -750,7 +763,7 @@ static const struct file_operations pcwd_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = pcwd_write, .write = pcwd_write,
.ioctl = pcwd_ioctl, .unlocked_ioctl = pcwd_ioctl,
.open = pcwd_open, .open = pcwd_open,
.release = pcwd_close, .release = pcwd_close,
}; };
...@@ -788,7 +801,7 @@ static inline int get_revision(void) ...@@ -788,7 +801,7 @@ static inline int get_revision(void)
* presumes a floating bus reads as 0xff. */ * presumes a floating bus reads as 0xff. */
if ((inb(pcwd_private.io_addr + 2) == 0xFF) || if ((inb(pcwd_private.io_addr + 2) == 0xFF) ||
(inb(pcwd_private.io_addr + 3) == 0xFF)) (inb(pcwd_private.io_addr + 3) == 0xFF))
r=PCWD_REVISION_A; r = PCWD_REVISION_A;
spin_unlock(&pcwd_private.io_lock); spin_unlock(&pcwd_private.io_lock);
return r; return r;
...@@ -803,7 +816,7 @@ static inline int get_revision(void) ...@@ -803,7 +816,7 @@ static inline int get_revision(void)
*/ */
static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
{ {
int base_addr=pcwd_ioports[id]; int base_addr = pcwd_ioports[id];
int port0, last_port0; /* Reg 0, in case it's REV A */ int port0, last_port0; /* Reg 0, in case it's REV A */
int port1, last_port1; /* Register 1 for REV C cards */ int port1, last_port1; /* Register 1 for REV C cards */
int i; int i;
...@@ -813,7 +826,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) ...@@ -813,7 +826,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n", printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
id); id);
if (!request_region (base_addr, 4, "PCWD")) { if (!request_region(base_addr, 4, "PCWD")) {
printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr); printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
return 0; return 0;
} }
...@@ -842,7 +855,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) ...@@ -842,7 +855,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
} }
} }
} }
release_region (base_addr, 4); release_region(base_addr, 4);
return retval; return retval;
} }
...@@ -857,7 +870,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) ...@@ -857,7 +870,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
cards_found++; cards_found++;
if (cards_found == 1) if (cards_found == 1)
printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n",
WD_VER);
if (cards_found > 1) { if (cards_found > 1) {
printk(KERN_ERR PFX "This driver only supports 1 device\n"); printk(KERN_ERR PFX "This driver only supports 1 device\n");
...@@ -875,10 +889,11 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) ...@@ -875,10 +889,11 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
/* Check card's revision */ /* Check card's revision */
pcwd_private.revision = get_revision(); pcwd_private.revision = get_revision();
if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { if (!request_region(pcwd_private.io_addr,
(pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
pcwd_private.io_addr); pcwd_private.io_addr);
ret=-EIO; ret = -EIO;
goto error_request_region; goto error_request_region;
} }
...@@ -908,26 +923,30 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) ...@@ -908,26 +923,30 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
if (heartbeat == 0) if (heartbeat == 0)
heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)]; heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)];
/* Check that the heartbeat value is within it's range ; if not reset to the default */ /* Check that the heartbeat value is within it's range;
if not reset to the default */
if (pcwd_set_heartbeat(heartbeat)) { if (pcwd_set_heartbeat(heartbeat)) {
pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n", printk(KERN_INFO PFX
WATCHDOG_HEARTBEAT); "heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
WATCHDOG_HEARTBEAT);
} }
if (pcwd_private.supports_temp) { if (pcwd_private.supports_temp) {
ret = misc_register(&temp_miscdev); ret = misc_register(&temp_miscdev);
if (ret) { if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
TEMP_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
TEMP_MINOR, ret);
goto error_misc_register_temp; goto error_misc_register_temp;
} }
} }
ret = misc_register(&pcwd_miscdev); ret = misc_register(&pcwd_miscdev);
if (ret) { if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto error_misc_register_watchdog; goto error_misc_register_watchdog;
} }
...@@ -940,7 +959,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) ...@@ -940,7 +959,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
if (pcwd_private.supports_temp) if (pcwd_private.supports_temp)
misc_deregister(&temp_miscdev); misc_deregister(&temp_miscdev);
error_misc_register_temp: error_misc_register_temp:
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); release_region(pcwd_private.io_addr,
(pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
error_request_region: error_request_region:
pcwd_private.io_addr = 0x0000; pcwd_private.io_addr = 0x0000;
cards_found--; cards_found--;
...@@ -964,7 +984,8 @@ static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id) ...@@ -964,7 +984,8 @@ static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
misc_deregister(&pcwd_miscdev); misc_deregister(&pcwd_miscdev);
if (pcwd_private.supports_temp) if (pcwd_private.supports_temp)
misc_deregister(&temp_miscdev); misc_deregister(&temp_miscdev);
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); release_region(pcwd_private.io_addr,
(pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
pcwd_private.io_addr = 0x0000; pcwd_private.io_addr = 0x0000;
cards_found--; cards_found--;
......
...@@ -30,8 +30,8 @@ ...@@ -30,8 +30,8 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <linux/io.h>
#define MODULE_NAME "PNX4008-WDT: " #define MODULE_NAME "PNX4008-WDT: "
...@@ -144,9 +144,8 @@ static int pnx4008_wdt_open(struct inode *inode, struct file *file) ...@@ -144,9 +144,8 @@ static int pnx4008_wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static ssize_t static ssize_t pnx4008_wdt_write(struct file *file, const char *data,
pnx4008_wdt_write(struct file *file, const char *data, size_t len, size_t len, loff_t *ppos)
loff_t * ppos)
{ {
if (len) { if (len) {
if (!nowayout) { if (!nowayout) {
...@@ -169,15 +168,14 @@ pnx4008_wdt_write(struct file *file, const char *data, size_t len, ...@@ -169,15 +168,14 @@ pnx4008_wdt_write(struct file *file, const char *data, size_t len,
return len; return len;
} }
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "PNX4008 Watchdog", .identity = "PNX4008 Watchdog",
}; };
static int static long pnx4008_wdt_ioctl(struct inode *inode, struct file *file,
pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
int time; int time;
...@@ -238,7 +236,7 @@ static const struct file_operations pnx4008_wdt_fops = { ...@@ -238,7 +236,7 @@ static const struct file_operations pnx4008_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = pnx4008_wdt_write, .write = pnx4008_wdt_write,
.ioctl = pnx4008_wdt_ioctl, .unlocked_ioctl = pnx4008_wdt_ioctl,
.open = pnx4008_wdt_open, .open = pnx4008_wdt_open,
.release = pnx4008_wdt_release, .release = pnx4008_wdt_release,
}; };
......
...@@ -29,10 +29,10 @@ ...@@ -29,10 +29,10 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/io.h> #include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/rm9k-ocd.h> #include <asm/rm9k-ocd.h>
...@@ -53,10 +53,12 @@ static void wdt_gpi_stop(void); ...@@ -53,10 +53,12 @@ static void wdt_gpi_stop(void);
static void wdt_gpi_set_timeout(unsigned int); static void wdt_gpi_set_timeout(unsigned int);
static int wdt_gpi_open(struct inode *, struct file *); static int wdt_gpi_open(struct inode *, struct file *);
static int wdt_gpi_release(struct inode *, struct file *); static int wdt_gpi_release(struct inode *, struct file *);
static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *); static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t,
loff_t *);
static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long);
static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *);
static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); static const struct resource *wdt_gpi_get_resource(struct platform_device *,
const char *, unsigned int);
static int __init wdt_gpi_probe(struct device *); static int __init wdt_gpi_probe(struct device *);
static int __exit wdt_gpi_remove(struct device *); static int __exit wdt_gpi_remove(struct device *);
...@@ -68,7 +70,7 @@ static int locked; ...@@ -68,7 +70,7 @@ static int locked;
/* These are set from device resources */ /* These are set from device resources */
static void __iomem * wd_regs; static void __iomem *wd_regs;
static unsigned int wd_irq, wd_ctr; static unsigned int wd_irq, wd_ctr;
...@@ -216,7 +218,8 @@ static int wdt_gpi_release(struct inode *inode, struct file *file) ...@@ -216,7 +218,8 @@ static int wdt_gpi_release(struct inode *inode, struct file *file)
if (expect_close) { if (expect_close) {
wdt_gpi_stop(); wdt_gpi_stop();
free_irq(wd_irq, &miscdev); free_irq(wd_irq, &miscdev);
printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); printk(KERN_INFO "%s: watchdog stopped\n",
wdt_gpi_name);
} else { } else {
printk(KERN_CRIT "%s: unexpected close() -" printk(KERN_CRIT "%s: unexpected close() -"
" watchdog left running\n", " watchdog left running\n",
...@@ -241,8 +244,7 @@ wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) ...@@ -241,8 +244,7 @@ wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o)
return s ? 1 : 0; return s ? 1 : 0;
} }
static long static long wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{ {
long res = -ENOTTY; long res = -ENOTTY;
const long size = _IOC_SIZE(cmd); const long size = _IOC_SIZE(cmd);
...@@ -271,7 +273,8 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) ...@@ -271,7 +273,8 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
wdinfo.options = nowayout ? wdinfo.options = nowayout ?
WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING : WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING :
WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE; WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE;
res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size; res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size;
break; break;
......
...@@ -26,13 +26,13 @@ ...@@ -26,13 +26,13 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/uaccess.h>
#ifdef CONFIG_ARCH_PXA #ifdef CONFIG_ARCH_PXA
#include <asm/arch/pxa-regs.h> #include <asm/arch/pxa-regs.h>
#endif #endif
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/uaccess.h>
#define OSCR_FREQ CLOCK_TICK_RATE #define OSCR_FREQ CLOCK_TICK_RATE
...@@ -45,7 +45,7 @@ static int boot_status; ...@@ -45,7 +45,7 @@ static int boot_status;
*/ */
static int sa1100dog_open(struct inode *inode, struct file *file) static int sa1100dog_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(1,&sa1100wdt_users)) if (test_and_set_bit(1, &sa1100wdt_users))
return -EBUSY; return -EBUSY;
/* Activate SA1100 Watchdog timer */ /* Activate SA1100 Watchdog timer */
...@@ -66,28 +66,27 @@ static int sa1100dog_open(struct inode *inode, struct file *file) ...@@ -66,28 +66,27 @@ static int sa1100dog_open(struct inode *inode, struct file *file)
static int sa1100dog_release(struct inode *inode, struct file *file) static int sa1100dog_release(struct inode *inode, struct file *file)
{ {
printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n"); printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n");
clear_bit(1, &sa1100wdt_users); clear_bit(1, &sa1100wdt_users);
return 0; return 0;
} }
static ssize_t sa1100dog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) static ssize_t sa1100dog_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{ {
if (len) if (len)
/* Refresh OSMR3 timer. */ /* Refresh OSMR3 timer. */
OSMR3 = OSCR + pre_margin; OSMR3 = OSCR + pre_margin;
return len; return len;
} }
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING,
.identity = "SA1100/PXA255 Watchdog", .identity = "SA1100/PXA255 Watchdog",
}; };
static int sa1100dog_ioctl(struct inode *inode, struct file *file, static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
int time; int time;
...@@ -134,18 +133,16 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file, ...@@ -134,18 +133,16 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file,
return ret; return ret;
} }
static const struct file_operations sa1100dog_fops = static const struct file_operations sa1100dog_fops = {
{
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = sa1100dog_write, .write = sa1100dog_write,
.ioctl = sa1100dog_ioctl, .unlocked_ioctl = sa1100dog_ioctl,
.open = sa1100dog_open, .open = sa1100dog_open,
.release = sa1100dog_release, .release = sa1100dog_release,
}; };
static struct miscdevice sa1100dog_miscdev = static struct miscdevice sa1100dog_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &sa1100dog_fops, .fops = &sa1100dog_fops,
...@@ -167,8 +164,9 @@ static int __init sa1100dog_init(void) ...@@ -167,8 +164,9 @@ static int __init sa1100dog_init(void)
ret = misc_register(&sa1100dog_miscdev); ret = misc_register(&sa1100dog_miscdev);
if (ret == 0) if (ret == 0)
printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", printk(KERN_INFO
margin); "SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
margin);
return ret; return ret;
} }
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <asm/sibyte/sb1250_int.h> #include <asm/sibyte/sb1250_int.h>
#include <asm/sibyte/sb1250_scd.h> #include <asm/sibyte/sb1250_scd.h>
static DEFINE_SPINLOCK(sbwd_lock);
/* /*
* set the initial count value of a timer * set the initial count value of a timer
...@@ -65,8 +66,10 @@ ...@@ -65,8 +66,10 @@
*/ */
void sbwdog_set(char __iomem *wdog, unsigned long t) void sbwdog_set(char __iomem *wdog, unsigned long t)
{ {
spin_lock(&sbwd_lock);
__raw_writeb(0, wdog - 0x10); __raw_writeb(0, wdog - 0x10);
__raw_writeq(t & 0x7fffffUL, wdog); __raw_writeq(t & 0x7fffffUL, wdog);
spin_unlock(&sbwd_lock);
} }
/* /*
...@@ -77,7 +80,9 @@ void sbwdog_set(char __iomem *wdog, unsigned long t) ...@@ -77,7 +80,9 @@ void sbwdog_set(char __iomem *wdog, unsigned long t)
*/ */
void sbwdog_pet(char __iomem *wdog) void sbwdog_pet(char __iomem *wdog)
{ {
spin_lock(&sbwd_lock);
__raw_writeb(__raw_readb(wdog) | 1, wdog); __raw_writeb(__raw_readb(wdog) | 1, wdog);
spin_unlock(&sbwd_lock);
} }
static unsigned long sbwdog_gate; /* keeps it to one thread only */ static unsigned long sbwdog_gate; /* keeps it to one thread only */
...@@ -86,8 +91,9 @@ static char __iomem *user_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_1)); ...@@ -86,8 +91,9 @@ static char __iomem *user_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_1));
static unsigned long timeout = 0x7fffffUL; /* useconds: 8.3ish secs. */ static unsigned long timeout = 0x7fffffUL; /* useconds: 8.3ish secs. */
static int expect_close; static int expect_close;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
.identity = "SiByte Watchdog", .identity = "SiByte Watchdog",
}; };
...@@ -97,9 +103,8 @@ static struct watchdog_info ident = { ...@@ -97,9 +103,8 @@ static struct watchdog_info ident = {
static int sbwdog_open(struct inode *inode, struct file *file) static int sbwdog_open(struct inode *inode, struct file *file)
{ {
nonseekable_open(inode, file); nonseekable_open(inode, file);
if (test_and_set_bit(0, &sbwdog_gate)) { if (test_and_set_bit(0, &sbwdog_gate))
return -EBUSY; return -EBUSY;
}
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
/* /*
...@@ -120,8 +125,9 @@ static int sbwdog_release(struct inode *inode, struct file *file) ...@@ -120,8 +125,9 @@ static int sbwdog_release(struct inode *inode, struct file *file)
__raw_writeb(0, user_dog); __raw_writeb(0, user_dog);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} else { } else {
printk(KERN_CRIT "%s: Unexpected close, not stopping watchdog!\n", printk(KERN_CRIT
ident.identity); "%s: Unexpected close, not stopping watchdog!\n",
ident.identity);
sbwdog_pet(user_dog); sbwdog_pet(user_dog);
} }
clear_bit(0, &sbwdog_gate); clear_bit(0, &sbwdog_gate);
...@@ -147,12 +153,10 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data, ...@@ -147,12 +153,10 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data,
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if (get_user(c, data + i)) { if (get_user(c, data + i))
return -EFAULT; return -EFAULT;
} if (c == 'V')
if (c == 'V') {
expect_close = 42; expect_close = 42;
}
} }
sbwdog_pet(user_dog); sbwdog_pet(user_dog);
} }
...@@ -160,8 +164,8 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data, ...@@ -160,8 +164,8 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data,
return len; return len;
} }
static int sbwdog_ioctl(struct inode *inode, struct file *file, static long sbwdog_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int ret = -ENOTTY; int ret = -ENOTTY;
unsigned long time; unsigned long time;
...@@ -180,9 +184,8 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file, ...@@ -180,9 +184,8 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file,
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
ret = get_user(time, p); ret = get_user(time, p);
if (ret) { if (ret)
break; break;
}
time *= 1000000; time *= 1000000;
if (time > 0x7fffffUL) { if (time > 0x7fffffUL) {
...@@ -226,18 +229,16 @@ sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf) ...@@ -226,18 +229,16 @@ sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf)
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static const struct file_operations sbwdog_fops = static const struct file_operations sbwdog_fops = {
{
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = sbwdog_write, .write = sbwdog_write,
.ioctl = sbwdog_ioctl, .unlocked_ioctl = sbwdog_ioctl,
.open = sbwdog_open, .open = sbwdog_open,
.release = sbwdog_release, .release = sbwdog_release,
}; };
static struct miscdevice sbwdog_miscdev = static struct miscdevice sbwdog_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &sbwdog_fops, .fops = &sbwdog_fops,
...@@ -267,13 +268,12 @@ irqreturn_t sbwdog_interrupt(int irq, void *addr) ...@@ -267,13 +268,12 @@ irqreturn_t sbwdog_interrupt(int irq, void *addr)
/* /*
* if it's the second watchdog timer, it's for those users * if it's the second watchdog timer, it's for those users
*/ */
if (wd_cfg_reg == user_dog) { if (wd_cfg_reg == user_dog)
printk(KERN_CRIT printk(KERN_CRIT
"%s in danger of initiating system reset in %ld.%01ld seconds\n", "%s in danger of initiating system reset in %ld.%01ld seconds\n",
ident.identity, wd_init / 1000000, (wd_init / 100000) % 10); ident.identity, wd_init / 1000000, (wd_init / 100000) % 10);
} else { else
cfg |= 1; cfg |= 1;
}
__raw_writeb(cfg, wd_cfg_reg); __raw_writeb(cfg, wd_cfg_reg);
...@@ -289,28 +289,31 @@ static int __init sbwdog_init(void) ...@@ -289,28 +289,31 @@ static int __init sbwdog_init(void)
*/ */
ret = register_reboot_notifier(&sbwdog_notifier); ret = register_reboot_notifier(&sbwdog_notifier);
if (ret) { if (ret) {
printk (KERN_ERR "%s: cannot register reboot notifier (err=%d)\n", printk(KERN_ERR
ident.identity, ret); "%s: cannot register reboot notifier (err=%d)\n",
ident.identity, ret);
return ret; return ret;
} }
/* /*
* get the resources * get the resources
*/ */
ret = misc_register(&sbwdog_miscdev);
if (ret == 0) {
printk(KERN_INFO "%s: timeout is %ld.%ld secs\n", ident.identity,
timeout / 1000000, (timeout / 100000) % 10);
}
ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED,
ident.identity, (void *)user_dog); ident.identity, (void *)user_dog);
if (ret) { if (ret) {
printk(KERN_ERR "%s: failed to request irq 1 - %d\n", ident.identity, printk(KERN_ERR "%s: failed to request irq 1 - %d\n",
ret); ident.identity, ret);
misc_deregister(&sbwdog_miscdev); return ret;
} }
ret = misc_register(&sbwdog_miscdev);
if (ret == 0) {
printk(KERN_INFO "%s: timeout is %ld.%ld secs\n",
ident.identity,
timeout / 1000000, (timeout / 100000) % 10);
} else
free_irq(1, (void *)user_dog);
return ret; return ret;
} }
...@@ -327,7 +330,7 @@ MODULE_DESCRIPTION("SiByte Watchdog"); ...@@ -327,7 +330,7 @@ MODULE_DESCRIPTION("SiByte Watchdog");
module_param(timeout, ulong, 0); module_param(timeout, ulong, 0);
MODULE_PARM_DESC(timeout, MODULE_PARM_DESC(timeout,
"Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)"); "Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
...@@ -336,16 +339,15 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ...@@ -336,16 +339,15 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
* example code that can be put in a platform code area to utilize the * example code that can be put in a platform code area to utilize the
* first watchdog timer for the kernels own purpose. * first watchdog timer for the kernels own purpose.
void void platform_wd_setup(void)
platform_wd_setup(void)
{ {
int ret; int ret;
ret = request_irq(0, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED,
"Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0)); "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0));
if (ret) { if (ret) {
printk(KERN_CRIT "Watchdog IRQ zero(0) failed to be requested - %d\n", printk(KERN_CRIT
ret); "Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
} }
} }
......
...@@ -16,19 +16,23 @@ ...@@ -16,19 +16,23 @@
* *
* 12/4 - 2000 [Initial revision] * 12/4 - 2000 [Initial revision]
* 25/4 - 2000 Added /dev/watchdog support * 25/4 - 2000 Added /dev/watchdog support
* 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1"
* on success
* 12/4 - 2002 [rob@osinvestor.com] eliminate fop_read * 12/4 - 2002 [rob@osinvestor.com] eliminate fop_read
* fix possible wdt_is_open race * fix possible wdt_is_open race
* add CONFIG_WATCHDOG_NOWAYOUT support * add CONFIG_WATCHDOG_NOWAYOUT support
* remove lock_kernel/unlock_kernel pairs * remove lock_kernel/unlock_kernel pairs
* added KERN_* to printk's * added KERN_* to printk's
* got rid of extraneous comments * got rid of extraneous comments
* changed watchdog_info to correctly reflect what the driver offers * changed watchdog_info to correctly reflect what
* added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, * the driver offers
* WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS,
* WDIOC_SETTIMEOUT, WDIOC_GETTIMEOUT, and
* WDIOC_SETOPTIONS ioctls
* 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
* use module_param * use module_param
* made timeout (the emulated heartbeat) a module_param * made timeout (the emulated heartbeat) a
* module_param
* made the keepalive ping an internal subroutine * made the keepalive ping an internal subroutine
* made wdt_stop and wdt_start module params * made wdt_stop and wdt_start module params
* added extra printk's for startup problems * added extra printk's for startup problems
...@@ -56,9 +60,9 @@ ...@@ -56,9 +60,9 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define OUR_NAME "sbc60xxwdt" #define OUR_NAME "sbc60xxwdt"
...@@ -94,13 +98,18 @@ MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 0x443)"); ...@@ -94,13 +98,18 @@ MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 0x443)");
*/ */
#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ static int timeout = WATCHDOG_TIMEOUT; /* in seconds, multiplied by HZ to
get seconds to wait for a ping */
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void wdt_timer_ping(unsigned long); static void wdt_timer_ping(unsigned long);
static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
...@@ -117,15 +126,14 @@ static void wdt_timer_ping(unsigned long data) ...@@ -117,15 +126,14 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL /* If we got a heartbeat pulse within the WDT_US_INTERVAL
* we agree to ping the WDT * we agree to ping the WDT
*/ */
if(time_before(jiffies, next_heartbeat)) if (time_before(jiffies, next_heartbeat)) {
{
/* Ping the WDT by reading from wdt_start */ /* Ping the WDT by reading from wdt_start */
inb_p(wdt_start); inb_p(wdt_start);
/* Re-set the timer interval */ /* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL); mod_timer(&timer, jiffies + WDT_INTERVAL);
} else { } else
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); printk(KERN_WARNING PFX
} "Heartbeat lost! Will not ping the watchdog\n");
} }
/* /*
...@@ -159,40 +167,40 @@ static void wdt_keepalive(void) ...@@ -159,40 +167,40 @@ static void wdt_keepalive(void)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) static ssize_t fop_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) if (count) {
{ if (!nowayout) {
if (!nowayout)
{
size_t ofs; size_t ofs;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the
* five months ago... */ magic character five months ago... */
wdt_expect_close = 0; wdt_expect_close = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the
for(ofs = 0; ofs != count; ofs++) magic character */
{ for (ofs = 0; ofs != count; ofs++) {
char c; char c;
if(get_user(c, buf+ofs)) if (get_user(c, buf+ofs))
return -EFAULT; return -EFAULT;
if(c == 'V') if (c == 'V')
wdt_expect_close = 42; wdt_expect_close = 42;
} }
} }
/* Well, anyhow someone wrote to us, we should return that favour */ /* Well, anyhow someone wrote to us, we should
return that favour */
wdt_keepalive(); wdt_keepalive();
} }
return count; return count;
} }
static int fop_open(struct inode * inode, struct file * file) static int fop_open(struct inode *inode, struct file *file)
{ {
/* Just in case we're already talking to someone... */ /* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open)) if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
if (nowayout) if (nowayout)
...@@ -203,78 +211,72 @@ static int fop_open(struct inode * inode, struct file * file) ...@@ -203,78 +211,72 @@ static int fop_open(struct inode * inode, struct file * file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int fop_close(struct inode * inode, struct file * file) static int fop_close(struct inode *inode, struct file *file)
{ {
if(wdt_expect_close == 42) if (wdt_expect_close == 42)
wdt_turnoff(); wdt_turnoff();
else { else {
del_timer(&timer); del_timer(&timer);
printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); printk(KERN_CRIT PFX
"device file closed unexpectedly. Will not stop the WDT!\n");
} }
clear_bit(0, &wdt_is_open); clear_bit(0, &wdt_is_open);
wdt_expect_close = 0; wdt_expect_close = 0;
return 0; return 0;
} }
static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident= static const struct watchdog_info ident = {
{ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "SBC60xx", .identity = "SBC60xx",
}; };
switch(cmd) switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{ {
default: int new_options, retval = -EINVAL;
return -ENOTTY; if (get_user(new_options, p))
case WDIOC_GETSUPPORT: return -EFAULT;
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; if (new_options & WDIOS_DISABLECARD) {
case WDIOC_GETSTATUS: wdt_turnoff();
case WDIOC_GETBOOTSTATUS: retval = 0;
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if(get_user(new_options, p))
return -EFAULT;
if(new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
if(new_options & WDIOS_ENABLECARD) {
wdt_startup();
retval = 0;
}
return retval;
} }
case WDIOC_SETTIMEOUT: if (new_options & WDIOS_ENABLECARD) {
{ wdt_startup();
int new_timeout; retval = 0;
if(get_user(new_timeout, p))
return -EFAULT;
if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
return -EINVAL;
timeout = new_timeout;
wdt_keepalive();
/* Fall through */
} }
case WDIOC_GETTIMEOUT: return retval;
return put_user(timeout, p); }
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
/* arbitrary upper limit */
if (new_timeout < 1 || new_timeout > 3600)
return -EINVAL;
timeout = new_timeout;
wdt_keepalive();
/* Fall through */
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
} }
} }
...@@ -284,7 +286,7 @@ static const struct file_operations wdt_fops = { ...@@ -284,7 +286,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write, .write = fop_write,
.open = fop_open, .open = fop_open,
.release = fop_close, .release = fop_close,
.ioctl = fop_ioctl, .unlocked_ioctl = fop_ioctl,
}; };
static struct miscdevice wdt_miscdev = { static struct miscdevice wdt_miscdev = {
...@@ -300,7 +302,7 @@ static struct miscdevice wdt_miscdev = { ...@@ -300,7 +302,7 @@ static struct miscdevice wdt_miscdev = {
static int wdt_notify_sys(struct notifier_block *this, unsigned long code, static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
wdt_turnoff(); wdt_turnoff();
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -310,8 +312,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, ...@@ -310,8 +312,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
* turn the timebomb registers off. * turn the timebomb registers off.
*/ */
static struct notifier_block wdt_notifier= static struct notifier_block wdt_notifier = {
{
.notifier_call = wdt_notify_sys, .notifier_call = wdt_notify_sys,
}; };
...@@ -324,23 +325,22 @@ static void __exit sbc60xxwdt_unload(void) ...@@ -324,23 +325,22 @@ static void __exit sbc60xxwdt_unload(void)
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
release_region(wdt_stop,1); release_region(wdt_stop, 1);
release_region(wdt_start,1); release_region(wdt_start, 1);
} }
static int __init sbc60xxwdt_init(void) static int __init sbc60xxwdt_init(void)
{ {
int rc = -EBUSY; int rc = -EBUSY;
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
{
timeout = WATCHDOG_TIMEOUT; timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", printk(KERN_INFO PFX
timeout); "timeout value must be 1 <= x <= 3600, using %d\n",
} timeout);
}
if (!request_region(wdt_start, 1, "SBC 60XX WDT")) if (!request_region(wdt_start, 1, "SBC 60XX WDT")) {
{
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_start); wdt_start);
rc = -EIO; rc = -EIO;
...@@ -348,33 +348,30 @@ static int __init sbc60xxwdt_init(void) ...@@ -348,33 +348,30 @@ static int __init sbc60xxwdt_init(void)
} }
/* We cannot reserve 0x45 - the kernel already has! */ /* We cannot reserve 0x45 - the kernel already has! */
if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) if (wdt_stop != 0x45 && wdt_stop != wdt_start) {
{ if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) {
if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) printk(KERN_ERR PFX
{ "I/O address 0x%04x already in use\n",
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", wdt_stop);
wdt_stop);
rc = -EIO; rc = -EIO;
goto err_out_region1; goto err_out_region1;
} }
} }
rc = register_reboot_notifier(&wdt_notifier); rc = register_reboot_notifier(&wdt_notifier);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", "cannot register reboot notifier (err=%d)\n", rc);
rc);
goto err_out_region2; goto err_out_region2;
} }
rc = misc_register(&wdt_miscdev); rc = misc_register(&wdt_miscdev);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", "cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc); wdt_miscdev.minor, rc);
goto err_out_reboot; goto err_out_reboot;
} }
printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout); timeout, nowayout);
...@@ -383,10 +380,10 @@ static int __init sbc60xxwdt_init(void) ...@@ -383,10 +380,10 @@ static int __init sbc60xxwdt_init(void)
err_out_reboot: err_out_reboot:
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
err_out_region2: err_out_region2:
if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) if (wdt_stop != 0x45 && wdt_stop != wdt_start)
release_region(wdt_stop,1); release_region(wdt_stop, 1);
err_out_region1: err_out_region1:
release_region(wdt_start,1); release_region(wdt_start, 1);
err_out: err_out:
return rc; return rc;
} }
......
...@@ -27,10 +27,10 @@ ...@@ -27,10 +27,10 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h>
#define SBC7240_PREFIX "sbc7240_wdt: " #define SBC7240_PREFIX "sbc7240_wdt: "
...@@ -159,7 +159,7 @@ static int fop_close(struct inode *inode, struct file *file) ...@@ -159,7 +159,7 @@ static int fop_close(struct inode *inode, struct file *file)
return 0; return 0;
} }
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING| .options = WDIOF_KEEPALIVEPING|
WDIOF_SETTIMEOUT| WDIOF_SETTIMEOUT|
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
...@@ -168,14 +168,12 @@ static struct watchdog_info ident = { ...@@ -168,14 +168,12 @@ static struct watchdog_info ident = {
}; };
static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user return copy_to_user((void __user *)arg, &ident, sizeof(ident))
((void __user *)arg, &ident, sizeof(ident)) ? -EFAULT : 0;
? -EFAULT : 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, (int __user *)arg); return put_user(0, (int __user *)arg);
...@@ -225,7 +223,7 @@ static const struct file_operations wdt_fops = { ...@@ -225,7 +223,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write, .write = fop_write,
.open = fop_open, .open = fop_open,
.release = fop_close, .release = fop_close,
.ioctl = fop_ioctl, .unlocked_ioctl = fop_ioctl,
}; };
static struct miscdevice wdt_miscdev = { static struct miscdevice wdt_miscdev = {
......
...@@ -48,13 +48,12 @@ ...@@ -48,13 +48,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
static unsigned long sbc8360_is_open; static unsigned long sbc8360_is_open;
static DEFINE_SPINLOCK(sbc8360_lock);
static char expect_close; static char expect_close;
#define PFX "sbc8360: " #define PFX "sbc8360: "
...@@ -204,7 +203,8 @@ module_param(timeout, int, 0); ...@@ -204,7 +203,8 @@ module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Kernel methods. * Kernel methods.
...@@ -232,8 +232,8 @@ static void sbc8360_ping(void) ...@@ -232,8 +232,8 @@ static void sbc8360_ping(void)
} }
/* Userspace pings kernel driver, or requests clean close */ /* Userspace pings kernel driver, or requests clean close */
static ssize_t sbc8360_write(struct file *file, const char __user * buf, static ssize_t sbc8360_write(struct file *file, const char __user *buf,
size_t count, loff_t * ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
...@@ -257,16 +257,12 @@ static ssize_t sbc8360_write(struct file *file, const char __user * buf, ...@@ -257,16 +257,12 @@ static ssize_t sbc8360_write(struct file *file, const char __user * buf,
static int sbc8360_open(struct inode *inode, struct file *file) static int sbc8360_open(struct inode *inode, struct file *file)
{ {
spin_lock(&sbc8360_lock); if (test_and_set_bit(0, &sbc8360_is_open))
if (test_and_set_bit(0, &sbc8360_is_open)) {
spin_unlock(&sbc8360_lock);
return -EBUSY; return -EBUSY;
}
if (nowayout) if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
/* Activate and ping once to start the countdown */ /* Activate and ping once to start the countdown */
spin_unlock(&sbc8360_lock);
sbc8360_activate(); sbc8360_activate();
sbc8360_ping(); sbc8360_ping();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
...@@ -274,16 +270,14 @@ static int sbc8360_open(struct inode *inode, struct file *file) ...@@ -274,16 +270,14 @@ static int sbc8360_open(struct inode *inode, struct file *file)
static int sbc8360_close(struct inode *inode, struct file *file) static int sbc8360_close(struct inode *inode, struct file *file)
{ {
spin_lock(&sbc8360_lock);
if (expect_close == 42) if (expect_close == 42)
outb(0, SBC8360_ENABLE); outb(0, SBC8360_ENABLE);
else else
printk(KERN_CRIT PFX printk(KERN_CRIT PFX
"SBC8360 device closed unexpectedly. SBC8360 will not stop!\n"); "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n");
clear_bit(0, &sbc8360_is_open); clear_bit(0, &sbc8360_is_open);
expect_close = 0; expect_close = 0;
spin_unlock(&sbc8360_lock);
return 0; return 0;
} }
...@@ -382,13 +376,13 @@ static int __init sbc8360_init(void) ...@@ -382,13 +376,13 @@ static int __init sbc8360_init(void)
return 0; return 0;
out_nomisc: out_nomisc:
unregister_reboot_notifier(&sbc8360_notifier); unregister_reboot_notifier(&sbc8360_notifier);
out_noreboot: out_noreboot:
release_region(SBC8360_BASETIME, 1); release_region(SBC8360_BASETIME, 1);
out_nobasetimereg: out_nobasetimereg:
release_region(SBC8360_ENABLE, 1); release_region(SBC8360_ENABLE, 1);
out: out:
return res; return res;
} }
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/io.h> #include <linux/io.h>
#define PFX "epx_c3: " #define PFX "epx_c3: "
static int epx_c3_alive; static int epx_c3_alive;
...@@ -100,12 +100,12 @@ static ssize_t epx_c3_write(struct file *file, const char __user *data, ...@@ -100,12 +100,12 @@ static ssize_t epx_c3_write(struct file *file, const char __user *data,
return len; return len;
} }
static int epx_c3_ioctl(struct inode *inode, struct file *file, static long epx_c3_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
int __user *argp = (void __user *)arg; int __user *argp = (void __user *)arg;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | .options = WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.firmware_version = 0, .firmware_version = 0,
...@@ -158,7 +158,7 @@ static const struct file_operations epx_c3_fops = { ...@@ -158,7 +158,7 @@ static const struct file_operations epx_c3_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = epx_c3_write, .write = epx_c3_write,
.ioctl = epx_c3_ioctl, .unlocked_ioctl = epx_c3_ioctl,
.open = epx_c3_open, .open = epx_c3_open,
.release = epx_c3_release, .release = epx_c3_release,
}; };
......
...@@ -64,9 +64,9 @@ ...@@ -64,9 +64,9 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define OUR_NAME "sc520_wdt" #define OUR_NAME "sc520_wdt"
...@@ -91,13 +91,18 @@ ...@@ -91,13 +91,18 @@
*/ */
#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
static int timeout = WATCHDOG_TIMEOUT;
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1 <= timeout <= 3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* AMD Elan SC520 - Watchdog Timer Registers * AMD Elan SC520 - Watchdog Timer Registers
...@@ -136,8 +141,7 @@ static void wdt_timer_ping(unsigned long data) ...@@ -136,8 +141,7 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL /* If we got a heartbeat pulse within the WDT_US_INTERVAL
* we agree to ping the WDT * we agree to ping the WDT
*/ */
if(time_before(jiffies, next_heartbeat)) if (time_before(jiffies, next_heartbeat)) {
{
/* Ping the WDT */ /* Ping the WDT */
spin_lock(&wdt_spinlock); spin_lock(&wdt_spinlock);
writew(0xAAAA, wdtmrctl); writew(0xAAAA, wdtmrctl);
...@@ -146,9 +150,9 @@ static void wdt_timer_ping(unsigned long data) ...@@ -146,9 +150,9 @@ static void wdt_timer_ping(unsigned long data)
/* Re-set the timer interval */ /* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL); mod_timer(&timer, jiffies + WDT_INTERVAL);
} else { } else
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); printk(KERN_WARNING PFX
} "Heartbeat lost! Will not ping the watchdog\n");
} }
/* /*
...@@ -162,7 +166,7 @@ static void wdt_config(int writeval) ...@@ -162,7 +166,7 @@ static void wdt_config(int writeval)
/* buy some time (ping) */ /* buy some time (ping) */
spin_lock_irqsave(&wdt_spinlock, flags); spin_lock_irqsave(&wdt_spinlock, flags);
dummy=readw(wdtmrctl); /* ensure write synchronization */ dummy = readw(wdtmrctl); /* ensure write synchronization */
writew(0xAAAA, wdtmrctl); writew(0xAAAA, wdtmrctl);
writew(0x5555, wdtmrctl); writew(0x5555, wdtmrctl);
/* unlock WDT = make WDT configuration register writable one time */ /* unlock WDT = make WDT configuration register writable one time */
...@@ -219,10 +223,11 @@ static int wdt_set_heartbeat(int t) ...@@ -219,10 +223,11 @@ static int wdt_set_heartbeat(int t)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) static ssize_t fop_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) { if (count) {
if (!nowayout) { if (!nowayout) {
size_t ofs; size_t ofs;
...@@ -231,25 +236,26 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou ...@@ -231,25 +236,26 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
wdt_expect_close = 0; wdt_expect_close = 0;
/* now scan */ /* now scan */
for(ofs = 0; ofs != count; ofs++) { for (ofs = 0; ofs != count; ofs++) {
char c; char c;
if (get_user(c, buf + ofs)) if (get_user(c, buf + ofs))
return -EFAULT; return -EFAULT;
if(c == 'V') if (c == 'V')
wdt_expect_close = 42; wdt_expect_close = 42;
} }
} }
/* Well, anyhow someone wrote to us, we should return that favour */ /* Well, anyhow someone wrote to us, we should
return that favour */
wdt_keepalive(); wdt_keepalive();
} }
return count; return count;
} }
static int fop_open(struct inode * inode, struct file * file) static int fop_open(struct inode *inode, struct file *file)
{ {
/* Just in case we're already talking to someone... */ /* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open)) if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
if (nowayout) if (nowayout)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
...@@ -259,12 +265,13 @@ static int fop_open(struct inode * inode, struct file * file) ...@@ -259,12 +265,13 @@ static int fop_open(struct inode * inode, struct file * file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int fop_close(struct inode * inode, struct file * file) static int fop_close(struct inode *inode, struct file *file)
{ {
if(wdt_expect_close == 42) { if (wdt_expect_close == 42)
wdt_turnoff(); wdt_turnoff();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
wdt_keepalive(); wdt_keepalive();
} }
clear_bit(0, &wdt_is_open); clear_bit(0, &wdt_is_open);
...@@ -272,63 +279,63 @@ static int fop_close(struct inode * inode, struct file * file) ...@@ -272,63 +279,63 @@ static int fop_close(struct inode * inode, struct file * file)
return 0; return 0;
} }
static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "SC520", .identity = "SC520",
}; };
switch(cmd) switch (cmd)
{ {
default: default:
return -ENOTTY; return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
wdt_keepalive(); wdt_keepalive();
return 0; return 0;
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
int new_options, retval = -EINVAL; int new_options, retval = -EINVAL;
if(get_user(new_options, p))
return -EFAULT;
if(new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
if(new_options & WDIOS_ENABLECARD) { if (get_user(new_options, p))
wdt_startup(); return -EFAULT;
retval = 0;
} if (new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
return retval; if (new_options & WDIOS_ENABLECARD) {
wdt_startup();
retval = 0;
} }
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if(get_user(new_timeout, p)) return retval;
return -EFAULT; }
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if(wdt_set_heartbeat(new_timeout)) if (get_user(new_timeout, p))
return -EINVAL; return -EFAULT;
wdt_keepalive(); if (wdt_set_heartbeat(new_timeout))
/* Fall through */ return -EINVAL;
}
case WDIOC_GETTIMEOUT: wdt_keepalive();
return put_user(timeout, p); /* Fall through */
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
} }
} }
...@@ -338,7 +345,7 @@ static const struct file_operations wdt_fops = { ...@@ -338,7 +345,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write, .write = fop_write,
.open = fop_open, .open = fop_open,
.release = fop_close, .release = fop_close,
.ioctl = fop_ioctl, .unlocked_ioctl = fop_ioctl,
}; };
static struct miscdevice wdt_miscdev = { static struct miscdevice wdt_miscdev = {
...@@ -354,7 +361,7 @@ static struct miscdevice wdt_miscdev = { ...@@ -354,7 +361,7 @@ static struct miscdevice wdt_miscdev = {
static int wdt_notify_sys(struct notifier_block *this, unsigned long code, static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
wdt_turnoff(); wdt_turnoff();
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -383,11 +390,13 @@ static int __init sc520_wdt_init(void) ...@@ -383,11 +390,13 @@ static int __init sc520_wdt_init(void)
{ {
int rc = -EBUSY; int rc = -EBUSY;
/* Check that the timeout value is within it's range ; if not reset to the default */ /* Check that the timeout value is within it's range ;
if not reset to the default */
if (wdt_set_heartbeat(timeout)) { if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT); wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n", printk(KERN_INFO PFX
WATCHDOG_TIMEOUT); "timeout value must be 1 <= timeout <= 3600, using %d\n",
WATCHDOG_TIMEOUT);
} }
wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2);
...@@ -399,20 +408,22 @@ static int __init sc520_wdt_init(void) ...@@ -399,20 +408,22 @@ static int __init sc520_wdt_init(void)
rc = register_reboot_notifier(&wdt_notifier); rc = register_reboot_notifier(&wdt_notifier);
if (rc) { if (rc) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
rc); "cannot register reboot notifier (err=%d)\n", rc);
goto err_out_ioremap; goto err_out_ioremap;
} }
rc = misc_register(&wdt_miscdev); rc = misc_register(&wdt_miscdev);
if (rc) { if (rc) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, rc); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, rc);
goto err_out_notifier; goto err_out_notifier;
} }
printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX
timeout,nowayout); "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0; return 0;
......
...@@ -27,9 +27,8 @@ ...@@ -27,9 +27,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/scx200.h> #include <linux/scx200.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h> #include <linux/io.h>
#include <asm/io.h>
#define NAME "scx200_wdt" #define NAME "scx200_wdt"
...@@ -47,8 +46,9 @@ module_param(nowayout, int, 0); ...@@ -47,8 +46,9 @@ module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
static u16 wdto_restart; static u16 wdto_restart;
static struct semaphore open_semaphore;
static char expect_close; static char expect_close;
static unsigned long open_lock;
static DEFINE_SPINLOCK(scx_lock);
/* Bits of the WDCNFG register */ /* Bits of the WDCNFG register */
#define W_ENABLE 0x00fa /* Enable watchdog */ #define W_ENABLE 0x00fa /* Enable watchdog */
...@@ -59,7 +59,9 @@ static char expect_close; ...@@ -59,7 +59,9 @@ static char expect_close;
static void scx200_wdt_ping(void) static void scx200_wdt_ping(void)
{ {
spin_lock(&scx_lock);
outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO); outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO);
spin_unlock(&scx_lock);
} }
static void scx200_wdt_update_margin(void) static void scx200_wdt_update_margin(void)
...@@ -73,9 +75,11 @@ static void scx200_wdt_enable(void) ...@@ -73,9 +75,11 @@ static void scx200_wdt_enable(void)
printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
wdto_restart); wdto_restart);
spin_lock(&scx_lock);
outw(0, scx200_cb_base + SCx200_WDT_WDTO); outw(0, scx200_cb_base + SCx200_WDT_WDTO);
outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG); outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
spin_unlock(&scx_lock);
scx200_wdt_ping(); scx200_wdt_ping();
} }
...@@ -84,15 +88,17 @@ static void scx200_wdt_disable(void) ...@@ -84,15 +88,17 @@ static void scx200_wdt_disable(void)
{ {
printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
spin_lock(&scx_lock);
outw(0, scx200_cb_base + SCx200_WDT_WDTO); outw(0, scx200_cb_base + SCx200_WDT_WDTO);
outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG); outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
spin_unlock(&scx_lock);
} }
static int scx200_wdt_open(struct inode *inode, struct file *file) static int scx200_wdt_open(struct inode *inode, struct file *file)
{ {
/* only allow one at a time */ /* only allow one at a time */
if (down_trylock(&open_semaphore)) if (test_and_set_bit(0, &open_lock))
return -EBUSY; return -EBUSY;
scx200_wdt_enable(); scx200_wdt_enable();
...@@ -101,13 +107,12 @@ static int scx200_wdt_open(struct inode *inode, struct file *file) ...@@ -101,13 +107,12 @@ static int scx200_wdt_open(struct inode *inode, struct file *file)
static int scx200_wdt_release(struct inode *inode, struct file *file) static int scx200_wdt_release(struct inode *inode, struct file *file)
{ {
if (expect_close != 42) { if (expect_close != 42)
printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n"); printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
} else if (!nowayout) { else if (!nowayout)
scx200_wdt_disable(); scx200_wdt_disable();
}
expect_close = 0; expect_close = 0;
up(&open_semaphore); clear_bit(0, &open_lock);
return 0; return 0;
} }
...@@ -122,8 +127,7 @@ static int scx200_wdt_notify_sys(struct notifier_block *this, ...@@ -122,8 +127,7 @@ static int scx200_wdt_notify_sys(struct notifier_block *this,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static struct notifier_block scx200_wdt_notifier = static struct notifier_block scx200_wdt_notifier = {
{
.notifier_call = scx200_wdt_notify_sys, .notifier_call = scx200_wdt_notify_sys,
}; };
...@@ -131,8 +135,7 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data, ...@@ -131,8 +135,7 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
/* check for a magic close character */ /* check for a magic close character */
if (len) if (len) {
{
size_t i; size_t i;
scx200_wdt_ping(); scx200_wdt_ping();
...@@ -152,15 +155,15 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data, ...@@ -152,15 +155,15 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data,
return 0; return 0;
} }
static int scx200_wdt_ioctl(struct inode *inode, struct file *file, static long scx200_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.identity = "NatSemi SCx200 Watchdog", .identity = "NatSemi SCx200 Watchdog",
.firmware_version = 1, .firmware_version = 1,
.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING), .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
}; };
int new_margin; int new_margin;
...@@ -168,7 +171,7 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -168,7 +171,7 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
default: default:
return -ENOTTY; return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident))) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
return 0; return 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
...@@ -195,18 +198,18 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -195,18 +198,18 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
} }
static const struct file_operations scx200_wdt_fops = { static const struct file_operations scx200_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = scx200_wdt_write, .write = scx200_wdt_write,
.ioctl = scx200_wdt_ioctl, .unlocked_ioctl = scx200_wdt_ioctl,
.open = scx200_wdt_open, .open = scx200_wdt_open,
.release = scx200_wdt_release, .release = scx200_wdt_release,
}; };
static struct miscdevice scx200_wdt_miscdev = { static struct miscdevice scx200_wdt_miscdev = {
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &scx200_wdt_fops, .fops = &scx200_wdt_fops,
}; };
static int __init scx200_wdt_init(void) static int __init scx200_wdt_init(void)
...@@ -229,8 +232,6 @@ static int __init scx200_wdt_init(void) ...@@ -229,8 +232,6 @@ static int __init scx200_wdt_init(void)
scx200_wdt_update_margin(); scx200_wdt_update_margin();
scx200_wdt_disable(); scx200_wdt_disable();
sema_init(&open_semaphore, 1);
r = register_reboot_notifier(&scx200_wdt_notifier); r = register_reboot_notifier(&scx200_wdt_notifier);
if (r) { if (r) {
printk(KERN_ERR NAME ": unable to register reboot notifier"); printk(KERN_ERR NAME ": unable to register reboot notifier");
...@@ -263,7 +264,7 @@ module_exit(scx200_wdt_cleanup); ...@@ -263,7 +264,7 @@ module_exit(scx200_wdt_cleanup);
/* /*
Local variables: Local variables:
compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
c-basic-offset: 8 c-basic-offset: 8
End: End:
*/ */
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/watchdog.h> #include <linux/watchdog.h>
#define PFX "shwdt: " #define PFX "shwdt: "
...@@ -72,6 +72,7 @@ static struct watchdog_info sh_wdt_info; ...@@ -72,6 +72,7 @@ static struct watchdog_info sh_wdt_info;
static char shwdt_expect_close; static char shwdt_expect_close;
static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0); static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0);
static unsigned long next_heartbeat; static unsigned long next_heartbeat;
static DEFINE_SPINLOCK(shwdt_lock);
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
...@@ -86,6 +87,9 @@ static int nowayout = WATCHDOG_NOWAYOUT; ...@@ -86,6 +87,9 @@ static int nowayout = WATCHDOG_NOWAYOUT;
static void sh_wdt_start(void) static void sh_wdt_start(void)
{ {
__u8 csr; __u8 csr;
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ); next_heartbeat = jiffies + (heartbeat * HZ);
mod_timer(&timer, next_ping_period(clock_division_ratio)); mod_timer(&timer, next_ping_period(clock_division_ratio));
...@@ -123,6 +127,7 @@ static void sh_wdt_start(void) ...@@ -123,6 +127,7 @@ static void sh_wdt_start(void)
csr &= ~RSTCSR_RSTS; csr &= ~RSTCSR_RSTS;
sh_wdt_write_rstcsr(csr); sh_wdt_write_rstcsr(csr);
#endif #endif
spin_unlock_irqrestore(&wdt_lock, flags);
} }
/** /**
...@@ -132,12 +137,16 @@ static void sh_wdt_start(void) ...@@ -132,12 +137,16 @@ static void sh_wdt_start(void)
static void sh_wdt_stop(void) static void sh_wdt_stop(void)
{ {
__u8 csr; __u8 csr;
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
del_timer(&timer); del_timer(&timer);
csr = sh_wdt_read_csr(); csr = sh_wdt_read_csr();
csr &= ~WTCSR_TME; csr &= ~WTCSR_TME;
sh_wdt_write_csr(csr); sh_wdt_write_csr(csr);
spin_unlock_irqrestore(&wdt_lock, flags);
} }
/** /**
...@@ -146,7 +155,11 @@ static void sh_wdt_stop(void) ...@@ -146,7 +155,11 @@ static void sh_wdt_stop(void)
*/ */
static inline void sh_wdt_keepalive(void) static inline void sh_wdt_keepalive(void)
{ {
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ); next_heartbeat = jiffies + (heartbeat * HZ);
spin_unlock_irqrestore(&wdt_lock, flags);
} }
/** /**
...@@ -155,10 +168,14 @@ static inline void sh_wdt_keepalive(void) ...@@ -155,10 +168,14 @@ static inline void sh_wdt_keepalive(void)
*/ */
static int sh_wdt_set_heartbeat(int t) static int sh_wdt_set_heartbeat(int t)
{ {
if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */ unsigned long flags;
if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&wdt_lock, flags);
heartbeat = t; heartbeat = t;
spin_unlock_irqrestore(&wdt_lock, flags);
return 0; return 0;
} }
...@@ -170,6 +187,9 @@ static int sh_wdt_set_heartbeat(int t) ...@@ -170,6 +187,9 @@ static int sh_wdt_set_heartbeat(int t)
*/ */
static void sh_wdt_ping(unsigned long data) static void sh_wdt_ping(unsigned long data)
{ {
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
if (time_before(jiffies, next_heartbeat)) { if (time_before(jiffies, next_heartbeat)) {
__u8 csr; __u8 csr;
...@@ -183,6 +203,7 @@ static void sh_wdt_ping(unsigned long data) ...@@ -183,6 +203,7 @@ static void sh_wdt_ping(unsigned long data)
} else } else
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " printk(KERN_WARNING PFX "Heartbeat lost! Will not ping "
"the watchdog\n"); "the watchdog\n");
spin_unlock_irqrestore(&wdt_lock, flags);
} }
/** /**
...@@ -310,7 +331,6 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -310,7 +331,6 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma)
/** /**
* sh_wdt_ioctl - Query Device * sh_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device * @file: file handle of device
* @cmd: watchdog command * @cmd: watchdog command
* @arg: argument * @arg: argument
...@@ -318,53 +338,51 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -318,53 +338,51 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma)
* Query basic information from the device or ping it, as outlined by the * Query basic information from the device or ping it, as outlined by the
* watchdog API. * watchdog API.
*/ */
static int sh_wdt_ioctl(struct inode *inode, struct file *file, static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int new_heartbeat; int new_heartbeat;
int options, retval = -EINVAL; int options, retval = -EINVAL;
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info *)arg, return copy_to_user((struct watchdog_info *)arg,
&sh_wdt_info, &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
sizeof(sh_wdt_info)) ? -EFAULT : 0; case WDIOC_GETSTATUS:
case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS:
case WDIOC_GETBOOTSTATUS: return put_user(0, (int *)arg);
return put_user(0, (int *)arg); case WDIOC_KEEPALIVE:
case WDIOC_KEEPALIVE: sh_wdt_keepalive();
sh_wdt_keepalive(); return 0;
return 0; case WDIOC_SETTIMEOUT:
case WDIOC_SETTIMEOUT: if (get_user(new_heartbeat, (int *)arg))
if (get_user(new_heartbeat, (int *)arg)) return -EFAULT;
return -EFAULT;
if (sh_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
sh_wdt_keepalive();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, (int *)arg);
case WDIOC_SETOPTIONS:
if (get_user(options, (int *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
sh_wdt_stop();
retval = 0;
}
if (options & WDIOS_ENABLECARD) { if (sh_wdt_set_heartbeat(new_heartbeat))
sh_wdt_start(); return -EINVAL;
retval = 0;
}
return retval; sh_wdt_keepalive();
default: /* Fall */
return -ENOTTY; case WDIOC_GETTIMEOUT:
} return put_user(heartbeat, (int *)arg);
case WDIOC_SETOPTIONS:
if (get_user(options, (int *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
sh_wdt_stop();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
sh_wdt_start();
retval = 0;
}
return retval;
default:
return -ENOTTY;
}
return 0; return 0;
} }
...@@ -390,13 +408,13 @@ static const struct file_operations sh_wdt_fops = { ...@@ -390,13 +408,13 @@ static const struct file_operations sh_wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = sh_wdt_write, .write = sh_wdt_write,
.ioctl = sh_wdt_ioctl, .unlocked_ioctl = sh_wdt_ioctl,
.open = sh_wdt_open, .open = sh_wdt_open,
.release = sh_wdt_close, .release = sh_wdt_close,
.mmap = sh_wdt_mmap, .mmap = sh_wdt_mmap,
}; };
static struct watchdog_info sh_wdt_info = { static const struct watchdog_info sh_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
...@@ -422,30 +440,33 @@ static int __init sh_wdt_init(void) ...@@ -422,30 +440,33 @@ static int __init sh_wdt_init(void)
{ {
int rc; int rc;
if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { if (clock_division_ratio < 0x5 || clock_division_ratio > 0x7) {
clock_division_ratio = WTCSR_CKS_4096; clock_division_ratio = WTCSR_CKS_4096;
printk(KERN_INFO PFX "clock_division_ratio value must " printk(KERN_INFO PFX
"be 0x5<=x<=0x7, using %d\n", clock_division_ratio); "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
clock_division_ratio);
} }
rc = sh_wdt_set_heartbeat(heartbeat); rc = sh_wdt_set_heartbeat(heartbeat);
if (unlikely(rc)) { if (unlikely(rc)) {
heartbeat = WATCHDOG_HEARTBEAT; heartbeat = WATCHDOG_HEARTBEAT;
printk(KERN_INFO PFX "heartbeat value must " printk(KERN_INFO PFX
"be 1<=x<=3600, using %d\n", heartbeat); "heartbeat value must be 1<=x<=3600, using %d\n",
heartbeat);
} }
rc = register_reboot_notifier(&sh_wdt_notifier); rc = register_reboot_notifier(&sh_wdt_notifier);
if (unlikely(rc)) { if (unlikely(rc)) {
printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
rc); "Can't register reboot notifier (err=%d)\n", rc);
return rc; return rc;
} }
rc = misc_register(&sh_wdt_miscdev); rc = misc_register(&sh_wdt_miscdev);
if (unlikely(rc)) { if (unlikely(rc)) {
printk(KERN_ERR PFX "Can't register miscdev on " printk(KERN_ERR PFX
"minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); "Can't register miscdev on minor=%d (err=%d)\n",
sh_wdt_miscdev.minor, rc);
unregister_reboot_notifier(&sh_wdt_notifier); unregister_reboot_notifier(&sh_wdt_notifier);
return rc; return rc;
} }
...@@ -476,10 +497,14 @@ module_param(clock_division_ratio, int, 0); ...@@ -476,10 +497,14 @@ module_param(clock_division_ratio, int, 0);
MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")"); MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")");
module_param(heartbeat, int, 0); module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
module_init(sh_wdt_init); module_init(sh_wdt_init);
module_exit(sh_wdt_exit); module_exit(sh_wdt_exit);
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* History: * History:
* 2003 - Created version 1.0 for Linux 2.4.x. * 2003 - Created version 1.0 for Linux 2.4.x.
* 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE
* features. Released version 1.1 * features. Released version 1.1
* *
* Theory of operation: * Theory of operation:
* *
...@@ -55,9 +55,9 @@ ...@@ -55,9 +55,9 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
/* enable support for minutes as units? */ /* enable support for minutes as units? */
...@@ -71,15 +71,15 @@ ...@@ -71,15 +71,15 @@
#define UNIT_MINUTE 1 #define UNIT_MINUTE 1
#define MODNAME "smsc37b787_wdt: " #define MODNAME "smsc37b787_wdt: "
#define VERSION "1.1" #define VERSION "1.1"
#define IOPORT 0x3F0 #define IOPORT 0x3F0
#define IOPORT_SIZE 2 #define IOPORT_SIZE 2
#define IODEV_NO 8 #define IODEV_NO 8
static int unit = UNIT_SECOND; /* timer's unit */ static int unit = UNIT_SECOND; /* timer's unit */
static int timeout = 60; /* timeout value: default is 60 "units" */ static int timeout = 60; /* timeout value: default is 60 "units" */
static unsigned long timer_enabled = 0; /* is the timer enabled? */ static unsigned long timer_enabled; /* is the timer enabled? */
static char expect_close; /* is the close expected? */ static char expect_close; /* is the close expected? */
...@@ -93,114 +93,121 @@ static int nowayout = WATCHDOG_NOWAYOUT; ...@@ -93,114 +93,121 @@ static int nowayout = WATCHDOG_NOWAYOUT;
static inline void open_io_config(void) static inline void open_io_config(void)
{ {
outb(0x55, IOPORT); outb(0x55, IOPORT);
mdelay(1); mdelay(1);
outb(0x55, IOPORT); outb(0x55, IOPORT);
} }
/* lock the IO chip */ /* lock the IO chip */
static inline void close_io_config(void) static inline void close_io_config(void)
{ {
outb(0xAA, IOPORT); outb(0xAA, IOPORT);
} }
/* select the IO device */ /* select the IO device */
static inline void select_io_device(unsigned char devno) static inline void select_io_device(unsigned char devno)
{ {
outb(0x07, IOPORT); outb(0x07, IOPORT);
outb(devno, IOPORT+1); outb(devno, IOPORT+1);
} }
/* write to the control register */ /* write to the control register */
static inline void write_io_cr(unsigned char reg, unsigned char data) static inline void write_io_cr(unsigned char reg, unsigned char data)
{ {
outb(reg, IOPORT); outb(reg, IOPORT);
outb(data, IOPORT+1); outb(data, IOPORT+1);
} }
/* read from the control register */ /* read from the control register */
static inline char read_io_cr(unsigned char reg) static inline char read_io_cr(unsigned char reg)
{ {
outb(reg, IOPORT); outb(reg, IOPORT);
return inb(IOPORT+1); return inb(IOPORT+1);
} }
/* -- Medium level functions ------------------------------------*/ /* -- Medium level functions ------------------------------------*/
static inline void gpio_bit12(unsigned char reg) static inline void gpio_bit12(unsigned char reg)
{ {
// -- General Purpose I/O Bit 1.2 -- /* -- General Purpose I/O Bit 1.2 --
// Bit 0, In/Out: 0 = Output, 1 = Input * Bit 0, In/Out: 0 = Output, 1 = Input
// Bit 1, Polarity: 0 = No Invert, 1 = Invert * Bit 1, Polarity: 0 = No Invert, 1 = Invert
// Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable * Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
// Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17, * Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
// 11 = Either Edge Triggered Intr. 2 * 11 = Either Edge Triggered Intr. 2
// Bit 5/6 (Reserved) * Bit 5/6 (Reserved)
// Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain * Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
write_io_cr(0xE2, reg); */
write_io_cr(0xE2, reg);
} }
static inline void gpio_bit13(unsigned char reg) static inline void gpio_bit13(unsigned char reg)
{ {
// -- General Purpose I/O Bit 1.3 -- /* -- General Purpose I/O Bit 1.3 --
// Bit 0, In/Out: 0 = Output, 1 = Input * Bit 0, In/Out: 0 = Output, 1 = Input
// Bit 1, Polarity: 0 = No Invert, 1 = Invert * Bit 1, Polarity: 0 = No Invert, 1 = Invert
// Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable * Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
// Bit 3, Function select: 0 = GPI/O, 1 = LED * Bit 3, Function select: 0 = GPI/O, 1 = LED
// Bit 4-6 (Reserved) * Bit 4-6 (Reserved)
// Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain * Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
write_io_cr(0xE3, reg); */
write_io_cr(0xE3, reg);
} }
static inline void wdt_timer_units(unsigned char new_units) static inline void wdt_timer_units(unsigned char new_units)
{ {
// -- Watchdog timer units -- /* -- Watchdog timer units --
// Bit 0-6 (Reserved) * Bit 0-6 (Reserved)
// Bit 7, WDT Time-out Value Units Select * Bit 7, WDT Time-out Value Units Select
// (0 = Minutes, 1 = Seconds) * (0 = Minutes, 1 = Seconds)
write_io_cr(0xF1, new_units); */
write_io_cr(0xF1, new_units);
} }
static inline void wdt_timeout_value(unsigned char new_timeout) static inline void wdt_timeout_value(unsigned char new_timeout)
{ {
// -- Watchdog Timer Time-out Value -- /* -- Watchdog Timer Time-out Value --
// Bit 0-7 Binary coded units (0=Disabled, 1..255) * Bit 0-7 Binary coded units (0=Disabled, 1..255)
write_io_cr(0xF2, new_timeout); */
write_io_cr(0xF2, new_timeout);
} }
static inline void wdt_timer_conf(unsigned char conf) static inline void wdt_timer_conf(unsigned char conf)
{ {
// -- Watchdog timer configuration -- /* -- Watchdog timer configuration --
// Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O * Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon
// Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr. * Gameport I/O
// Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr. * Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
// Bit 3 Reset the timer * Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr
// (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled) * Bit 3 Reset the timer
// Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled, * (Wrong in SMsC documentation? Given as: PowerLED Timout
// 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15) * Enabled)
write_io_cr(0xF3, conf); * Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,
* 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)
*/
write_io_cr(0xF3, conf);
} }
static inline void wdt_timer_ctrl(unsigned char reg) static inline void wdt_timer_ctrl(unsigned char reg)
{ {
// -- Watchdog timer control -- /* -- Watchdog timer control --
// Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured * Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured
// Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz * Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz
// Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) * Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning)
// Bit 3 P20 Force Timeout enabled: * Bit 3 P20 Force Timeout enabled:
// 0 = P20 activity does not generate the WD timeout event * 0 = P20 activity does not generate the WD timeout event
// 1 = P20 Allows rising edge of P20, from the keyboard * 1 = P20 Allows rising edge of P20, from the keyboard
// controller, to force the WD timeout event. * controller, to force the WD timeout event.
// Bit 4 (Reserved) * Bit 4 (Reserved)
// -- Soft power management -- * -- Soft power management --
// Bit 5 Stop Counter: 1 = Stop software power down counter * Bit 5 Stop Counter: 1 = Stop software power down counter
// set via register 0xB8, (self-cleaning) * set via register 0xB8, (self-cleaning)
// (Upon read: 0 = Counter running, 1 = Counter stopped) * (Upon read: 0 = Counter running, 1 = Counter stopped)
// Bit 6 Restart Counter: 1 = Restart software power down counter * Bit 6 Restart Counter: 1 = Restart software power down counter
// set via register 0xB8, (self-cleaning) * set via register 0xB8, (self-cleaning)
// Bit 7 SPOFF: 1 = Force software power down (self-cleaning) * Bit 7 SPOFF: 1 = Force software power down (self-cleaning)
*/
write_io_cr(0xF4, reg); write_io_cr(0xF4, reg);
} }
/* -- Higher level functions ------------------------------------*/ /* -- Higher level functions ------------------------------------*/
...@@ -209,33 +216,34 @@ static inline void wdt_timer_ctrl(unsigned char reg) ...@@ -209,33 +216,34 @@ static inline void wdt_timer_ctrl(unsigned char reg)
static void wb_smsc_wdt_initialize(void) static void wb_smsc_wdt_initialize(void)
{ {
unsigned char old; unsigned char old;
spin_lock(&io_lock); spin_lock(&io_lock);
open_io_config(); open_io_config();
select_io_device(IODEV_NO); select_io_device(IODEV_NO);
// enable the watchdog /* enable the watchdog */
gpio_bit13(0x08); // Select pin 80 = LED not GPIO gpio_bit13(0x08); /* Select pin 80 = LED not GPIO */
gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert gpio_bit12(0x0A); /* Set pin 79 = WDT not
GPIO/Output/Polarity=Invert */
/* disable the timeout */
wdt_timeout_value(0);
// disable the timeout /* reset control register */
wdt_timeout_value(0); wdt_timer_ctrl(0x00);
// reset control register /* reset configuration register */
wdt_timer_ctrl(0x00);
// reset configuration register
wdt_timer_conf(0x00); wdt_timer_conf(0x00);
// read old (timer units) register /* read old (timer units) register */
old = read_io_cr(0xF1) & 0x7F; old = read_io_cr(0xF1) & 0x7F;
if (unit == UNIT_SECOND) old |= 0x80; // set to seconds if (unit == UNIT_SECOND)
old |= 0x80; /* set to seconds */
// set the watchdog timer units /* set the watchdog timer units */
wdt_timer_units(old); wdt_timer_units(old);
close_io_config(); close_io_config();
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
...@@ -244,23 +252,23 @@ static void wb_smsc_wdt_initialize(void) ...@@ -244,23 +252,23 @@ static void wb_smsc_wdt_initialize(void)
static void wb_smsc_wdt_shutdown(void) static void wb_smsc_wdt_shutdown(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
open_io_config(); open_io_config();
select_io_device(IODEV_NO); select_io_device(IODEV_NO);
// disable the watchdog /* disable the watchdog */
gpio_bit13(0x09); gpio_bit13(0x09);
gpio_bit12(0x09); gpio_bit12(0x09);
// reset watchdog config register /* reset watchdog config register */
wdt_timer_conf(0x00); wdt_timer_conf(0x00);
// reset watchdog control register /* reset watchdog control register */
wdt_timer_ctrl(0x00); wdt_timer_ctrl(0x00);
// disable timeout /* disable timeout */
wdt_timeout_value(0x00); wdt_timeout_value(0x00);
close_io_config(); close_io_config();
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
...@@ -269,16 +277,16 @@ static void wb_smsc_wdt_shutdown(void) ...@@ -269,16 +277,16 @@ static void wb_smsc_wdt_shutdown(void)
static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
open_io_config(); open_io_config();
select_io_device(IODEV_NO); select_io_device(IODEV_NO);
// set Power LED to blink, if we enable the timeout /* set Power LED to blink, if we enable the timeout */
wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02); wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
// set timeout value /* set timeout value */
wdt_timeout_value(new_timeout); wdt_timeout_value(new_timeout);
close_io_config(); close_io_config();
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
...@@ -286,32 +294,32 @@ static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) ...@@ -286,32 +294,32 @@ static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
static unsigned char wb_smsc_wdt_get_timeout(void) static unsigned char wb_smsc_wdt_get_timeout(void)
{ {
unsigned char set_timeout; unsigned char set_timeout;
spin_lock(&io_lock); spin_lock(&io_lock);
open_io_config(); open_io_config();
select_io_device(IODEV_NO); select_io_device(IODEV_NO);
set_timeout = read_io_cr(0xF2); set_timeout = read_io_cr(0xF2);
close_io_config(); close_io_config();
spin_unlock(&io_lock); spin_unlock(&io_lock);
return set_timeout; return set_timeout;
} }
/* disable watchdog */ /* disable watchdog */
static void wb_smsc_wdt_disable(void) static void wb_smsc_wdt_disable(void)
{ {
// set the timeout to 0 to disable the watchdog /* set the timeout to 0 to disable the watchdog */
wb_smsc_wdt_set_timeout(0); wb_smsc_wdt_set_timeout(0);
} }
/* enable watchdog by setting the current timeout */ /* enable watchdog by setting the current timeout */
static void wb_smsc_wdt_enable(void) static void wb_smsc_wdt_enable(void)
{ {
// set the current timeout... /* set the current timeout... */
wb_smsc_wdt_set_timeout(timeout); wb_smsc_wdt_set_timeout(timeout);
} }
/* reset the timer */ /* reset the timer */
...@@ -319,14 +327,14 @@ static void wb_smsc_wdt_enable(void) ...@@ -319,14 +327,14 @@ static void wb_smsc_wdt_enable(void)
static void wb_smsc_wdt_reset_timer(void) static void wb_smsc_wdt_reset_timer(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
open_io_config(); open_io_config();
select_io_device(IODEV_NO); select_io_device(IODEV_NO);
// reset the timer /* reset the timer */
wdt_timeout_value(timeout); wdt_timeout_value(timeout);
wdt_timer_conf(0x08); wdt_timer_conf(0x08);
close_io_config(); close_io_config();
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
...@@ -355,7 +363,9 @@ static int wb_smsc_wdt_open(struct inode *inode, struct file *file) ...@@ -355,7 +363,9 @@ static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
/* Reload and activate timer */ /* Reload and activate timer */
wb_smsc_wdt_enable(); wb_smsc_wdt_enable();
printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); printk(KERN_INFO MODNAME
"Watchdog enabled. Timeout set to %d %s.\n",
timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -367,10 +377,12 @@ static int wb_smsc_wdt_release(struct inode *inode, struct file *file) ...@@ -367,10 +377,12 @@ static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
/* Shut off the timer. */ /* Shut off the timer. */
if (expect_close == 42) { if (expect_close == 42) {
wb_smsc_wdt_disable(); wb_smsc_wdt_disable();
printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n"); printk(KERN_INFO MODNAME
"Watchdog disabled, sleeping again...\n");
} else { } else {
printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT MODNAME
"Unexpected close, not stopping watchdog!\n");
wb_smsc_wdt_reset_timer(); wb_smsc_wdt_reset_timer();
} }
...@@ -392,7 +404,8 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, ...@@ -392,7 +404,8 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
/* reset expect flag */ /* reset expect flag */
expect_close = 0; expect_close = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the
magic character */
for (i = 0; i != len; i++) { for (i = 0; i != len; i++) {
char c; char c;
if (get_user(c, data+i)) if (get_user(c, data+i))
...@@ -410,8 +423,8 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, ...@@ -410,8 +423,8 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
/* ioctl => control interface */ /* ioctl => control interface */
static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, static long wb_smsc_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int new_timeout; int new_timeout;
...@@ -420,9 +433,9 @@ static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -420,9 +433,9 @@ static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
int __user *i; int __user *i;
} uarg; } uarg;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | .options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
.firmware_version = 0, .firmware_version = 0,
.identity = "SMsC 37B787 Watchdog" .identity = "SMsC 37B787 Watchdog"
...@@ -431,78 +444,62 @@ static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -431,78 +444,62 @@ static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
uarg.i = (int __user *)arg; uarg.i = (int __user *)arg;
switch (cmd) { switch (cmd) {
default: case WDIOC_GETSUPPORT:
return -ENOTTY; return copy_to_user(uarg.ident, &ident, sizeof(ident))
? -EFAULT : 0;
case WDIOC_GETSUPPORT: case WDIOC_GETSTATUS:
return copy_to_user(uarg.ident, &ident, return put_user(wb_smsc_wdt_status(), uarg.i);
sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_GETSTATUS: case WDIOC_KEEPALIVE:
return put_user(wb_smsc_wdt_status(), uarg.i); wb_smsc_wdt_reset_timer();
return 0;
case WDIOC_GETBOOTSTATUS: case WDIOC_SETTIMEOUT:
return put_user(0, uarg.i); if (get_user(new_timeout, uarg.i))
return -EFAULT;
case WDIOC_KEEPALIVE: /* the API states this is given in secs */
wb_smsc_wdt_reset_timer(); if (unit == UNIT_MINUTE)
return 0; new_timeout /= 60;
if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
case WDIOC_SETTIMEOUT: return -EINVAL;
if (get_user(new_timeout, uarg.i)) timeout = new_timeout;
return -EFAULT; wb_smsc_wdt_set_timeout(timeout);
/* fall through and return the new timeout... */
// the API states this is given in secs case WDIOC_GETTIMEOUT:
if (unit == UNIT_MINUTE) new_timeout = timeout;
new_timeout /= 60; if (unit == UNIT_MINUTE)
if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
return -EINVAL;
timeout = new_timeout;
wb_smsc_wdt_set_timeout(timeout);
// fall through and return the new timeout...
case WDIOC_GETTIMEOUT:
new_timeout = timeout;
if (unit == UNIT_MINUTE)
new_timeout *= 60; new_timeout *= 60;
return put_user(new_timeout, uarg.i);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
return put_user(new_timeout, uarg.i); if (get_user(options, uarg.i))
return -EFAULT;
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
if (get_user(options, uarg.i))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
wb_smsc_wdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
wb_smsc_wdt_enable();
retval = 0;
}
return retval; if (options & WDIOS_DISABLECARD) {
wb_smsc_wdt_disable();
retval = 0;
} }
if (options & WDIOS_ENABLECARD) {
wb_smsc_wdt_enable();
retval = 0;
}
return retval;
}
default:
return -ENOTTY;
} }
} }
/* -- Notifier funtions -----------------------------------------*/ /* -- Notifier funtions -----------------------------------------*/
static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) static int wb_smsc_wdt_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT) {
{ /* set timeout to 0, to avoid possible race-condition */
// set timeout to 0, to avoid possible race-condition timeout = 0;
timeout = 0;
wb_smsc_wdt_disable(); wb_smsc_wdt_disable();
} }
return NOTIFY_DONE; return NOTIFY_DONE;
...@@ -510,23 +507,20 @@ static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long cod ...@@ -510,23 +507,20 @@ static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long cod
/* -- Module's structures ---------------------------------------*/ /* -- Module's structures ---------------------------------------*/
static const struct file_operations wb_smsc_wdt_fops = static const struct file_operations wb_smsc_wdt_fops = {
{ .owner = THIS_MODULE,
.owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = wb_smsc_wdt_write, .write = wb_smsc_wdt_write,
.ioctl = wb_smsc_wdt_ioctl, .unlocked_ioctl = wb_smsc_wdt_ioctl,
.open = wb_smsc_wdt_open, .open = wb_smsc_wdt_open,
.release = wb_smsc_wdt_release, .release = wb_smsc_wdt_release,
}; };
static struct notifier_block wb_smsc_wdt_notifier = static struct notifier_block wb_smsc_wdt_notifier = {
{
.notifier_call = wb_smsc_wdt_notify_sys, .notifier_call = wb_smsc_wdt_notify_sys,
}; };
static struct miscdevice wb_smsc_wdt_miscdev = static struct miscdevice wb_smsc_wdt_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &wb_smsc_wdt_fops, .fops = &wb_smsc_wdt_fops,
...@@ -540,39 +534,44 @@ static int __init wb_smsc_wdt_init(void) ...@@ -540,39 +534,44 @@ static int __init wb_smsc_wdt_init(void)
{ {
int ret; int ret;
printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n"); printk(KERN_INFO "SMsC 37B787 watchdog component driver "
VERSION " initialising...\n");
if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT); printk(KERN_ERR MODNAME "Unable to register IO port %#x\n",
IOPORT);
ret = -EBUSY; ret = -EBUSY;
goto out_pnp; goto out_pnp;
} }
// set new maximum, if it's too big /* set new maximum, if it's too big */
if (timeout > MAX_TIMEOUT) if (timeout > MAX_TIMEOUT)
timeout = MAX_TIMEOUT; timeout = MAX_TIMEOUT;
// init the watchdog timer /* init the watchdog timer */
wb_smsc_wdt_initialize(); wb_smsc_wdt_initialize();
ret = register_reboot_notifier(&wb_smsc_wdt_notifier); ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
if (ret) { if (ret) {
printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret); printk(KERN_ERR MODNAME
"Unable to register reboot notifier err = %d\n", ret);
goto out_io; goto out_io;
} }
ret = misc_register(&wb_smsc_wdt_miscdev); ret = misc_register(&wb_smsc_wdt_miscdev);
if (ret) { if (ret) {
printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); printk(KERN_ERR MODNAME
"Unable to register miscdev on minor %d\n",
WATCHDOG_MINOR);
goto out_rbt; goto out_rbt;
} }
// output info /* output info */
printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); printk(KERN_INFO MODNAME "Timeout set to %d %s.\n",
printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout); timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
printk(KERN_INFO MODNAME
// ret = 0 "Watchdog initialized and sleeping (nowayout=%d)...\n",
nowayout);
out_clean: out_clean:
return ret; return ret;
...@@ -591,8 +590,7 @@ static int __init wb_smsc_wdt_init(void) ...@@ -591,8 +590,7 @@ static int __init wb_smsc_wdt_init(void)
static void __exit wb_smsc_wdt_exit(void) static void __exit wb_smsc_wdt_exit(void)
{ {
/* Stop the timer before we leave */ /* Stop the timer before we leave */
if (!nowayout) if (!nowayout) {
{
wb_smsc_wdt_shutdown(); wb_smsc_wdt_shutdown();
printk(KERN_INFO MODNAME "Watchdog disabled.\n"); printk(KERN_INFO MODNAME "Watchdog disabled.\n");
} }
...@@ -601,25 +599,29 @@ static void __exit wb_smsc_wdt_exit(void) ...@@ -601,25 +599,29 @@ static void __exit wb_smsc_wdt_exit(void)
unregister_reboot_notifier(&wb_smsc_wdt_notifier); unregister_reboot_notifier(&wb_smsc_wdt_notifier);
release_region(IOPORT, IOPORT_SIZE); release_region(IOPORT, IOPORT_SIZE);
printk("SMsC 37B787 watchdog component driver removed.\n"); printk(KERN_INFO "SMsC 37B787 watchdog component driver removed.\n");
} }
module_init(wb_smsc_wdt_init); module_init(wb_smsc_wdt_init);
module_exit(wb_smsc_wdt_exit); module_exit(wb_smsc_wdt_exit);
MODULE_AUTHOR("Sven Anders <anders@anduras.de>"); MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")"); MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version "
VERSION ")");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
#ifdef SMSC_SUPPORT_MINUTES #ifdef SMSC_SUPPORT_MINUTES
module_param(unit, int, 0); module_param(unit, int, 0);
MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0"); MODULE_PARM_DESC(unit,
"set unit to use, 0=seconds or 1=minutes, default is 0");
#endif #endif
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
...@@ -47,19 +47,22 @@ ...@@ -47,19 +47,22 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#define PFX "SoftDog: " #define PFX "SoftDog: "
#define TIMER_MARGIN 60 /* Default is 60 seconds */ #define TIMER_MARGIN 60 /* Default is 60 seconds */
static int soft_margin = TIMER_MARGIN; /* in seconds */ static int soft_margin = TIMER_MARGIN; /* in seconds */
module_param(soft_margin, int, 0); module_param(soft_margin, int, 0);
MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0<soft_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")"); MODULE_PARM_DESC(soft_margin,
"Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default="
__MODULE_STRING(TIMER_MARGIN) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#ifdef ONLY_TESTING #ifdef ONLY_TESTING
static int soft_noboot = 1; static int soft_noboot = 1;
...@@ -93,8 +96,7 @@ static void watchdog_fire(unsigned long data) ...@@ -93,8 +96,7 @@ static void watchdog_fire(unsigned long data)
if (soft_noboot) if (soft_noboot)
printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
else else {
{
printk(KERN_CRIT PFX "Initiating system reboot.\n"); printk(KERN_CRIT PFX "Initiating system reboot.\n");
emergency_restart(); emergency_restart();
printk(KERN_CRIT PFX "Reboot didn't ?????\n"); printk(KERN_CRIT PFX "Reboot didn't ?????\n");
...@@ -153,7 +155,8 @@ static int softdog_release(struct inode *inode, struct file *file) ...@@ -153,7 +155,8 @@ static int softdog_release(struct inode *inode, struct file *file)
softdog_stop(); softdog_stop();
module_put(THIS_MODULE); module_put(THIS_MODULE);
} else { } else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
set_bit(0, &orphan_timer); set_bit(0, &orphan_timer);
softdog_keepalive(); softdog_keepalive();
} }
...@@ -162,12 +165,13 @@ static int softdog_release(struct inode *inode, struct file *file) ...@@ -162,12 +165,13 @@ static int softdog_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static ssize_t softdog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) static ssize_t softdog_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{ {
/* /*
* Refresh the timer. * Refresh the timer.
*/ */
if(len) { if (len) {
if (!nowayout) { if (!nowayout) {
size_t i; size_t i;
...@@ -188,13 +192,13 @@ static ssize_t softdog_write(struct file *file, const char __user *data, size_t ...@@ -188,13 +192,13 @@ static ssize_t softdog_write(struct file *file, const char __user *data, size_t
return len; return len;
} }
static int softdog_ioctl(struct inode *inode, struct file *file, static long softdog_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_margin; int new_margin;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | .options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
...@@ -202,26 +206,25 @@ static int softdog_ioctl(struct inode *inode, struct file *file, ...@@ -202,26 +206,25 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
.identity = "Software Watchdog", .identity = "Software Watchdog",
}; };
switch (cmd) { switch (cmd) {
default: default:
return -ENOTTY; return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS:
case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS:
case WDIOC_GETBOOTSTATUS: return put_user(0, p);
return put_user(0, p); case WDIOC_KEEPALIVE:
case WDIOC_KEEPALIVE: softdog_keepalive();
softdog_keepalive(); return 0;
return 0; case WDIOC_SETTIMEOUT:
case WDIOC_SETTIMEOUT: if (get_user(new_margin, p))
if (get_user(new_margin, p)) return -EFAULT;
return -EFAULT; if (softdog_set_heartbeat(new_margin))
if (softdog_set_heartbeat(new_margin)) return -EINVAL;
return -EINVAL; softdog_keepalive();
softdog_keepalive(); /* Fall */
/* Fall */ case WDIOC_GETTIMEOUT:
case WDIOC_GETTIMEOUT: return put_user(soft_margin, p);
return put_user(soft_margin, p);
} }
} }
...@@ -232,10 +235,9 @@ static int softdog_ioctl(struct inode *inode, struct file *file, ...@@ -232,10 +235,9 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
static int softdog_notify_sys(struct notifier_block *this, unsigned long code, static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code==SYS_DOWN || code==SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the WDT off */ /* Turn the WDT off */
softdog_stop(); softdog_stop();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -247,7 +249,7 @@ static const struct file_operations softdog_fops = { ...@@ -247,7 +249,7 @@ static const struct file_operations softdog_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = softdog_write, .write = softdog_write,
.ioctl = softdog_ioctl, .unlocked_ioctl = softdog_ioctl,
.open = softdog_open, .open = softdog_open,
.release = softdog_release, .release = softdog_release,
}; };
...@@ -268,24 +270,27 @@ static int __init watchdog_init(void) ...@@ -268,24 +270,27 @@ static int __init watchdog_init(void)
{ {
int ret; int ret;
/* Check that the soft_margin value is within it's range ; if not reset to the default */ /* Check that the soft_margin value is within it's range;
if not reset to the default */
if (softdog_set_heartbeat(soft_margin)) { if (softdog_set_heartbeat(soft_margin)) {
softdog_set_heartbeat(TIMER_MARGIN); softdog_set_heartbeat(TIMER_MARGIN);
printk(KERN_INFO PFX "soft_margin value must be 0<soft_margin<65536, using %d\n", printk(KERN_INFO PFX
"soft_margin must be 0 < soft_margin < 65536, using %d\n",
TIMER_MARGIN); TIMER_MARGIN);
} }
ret = register_reboot_notifier(&softdog_notifier); ret = register_reboot_notifier(&softdog_notifier);
if (ret) { if (ret) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
return ret; return ret;
} }
ret = misc_register(&softdog_miscdev); ret = misc_register(&softdog_miscdev);
if (ret) { if (ret) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&softdog_notifier); unregister_reboot_notifier(&softdog_notifier);
return ret; return ret;
} }
......
...@@ -45,27 +45,34 @@ static unsigned long txx9wdt_alive; ...@@ -45,27 +45,34 @@ static unsigned long txx9wdt_alive;
static int expect_close; static int expect_close;
static struct txx9_tmr_reg __iomem *txx9wdt_reg; static struct txx9_tmr_reg __iomem *txx9wdt_reg;
static struct clk *txx9_imclk; static struct clk *txx9_imclk;
static DECLARE_LOCK(txx9_lock);
static void txx9wdt_ping(void) static void txx9wdt_ping(void)
{ {
spin_lock(&txx9_lock);
__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
spin_unlock(&txx9_lock);
} }
static void txx9wdt_start(void) static void txx9wdt_start(void)
{ {
spin_lock(&txx9_lock);
__raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra); __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
__raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr); __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
__raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */ __raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */
__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
&txx9wdt_reg->tcr); &txx9wdt_reg->tcr);
__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
spin_unlock(&txx9_lock);
} }
static void txx9wdt_stop(void) static void txx9wdt_stop(void)
{ {
spin_lock(&txx9_lock);
__raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr); __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
__raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE, __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
&txx9wdt_reg->tcr); &txx9wdt_reg->tcr);
spin_unlock(&txx9_lock);
} }
static int txx9wdt_open(struct inode *inode, struct file *file) static int txx9wdt_open(struct inode *inode, struct file *file)
...@@ -120,13 +127,13 @@ static ssize_t txx9wdt_write(struct file *file, const char __user *data, ...@@ -120,13 +127,13 @@ static ssize_t txx9wdt_write(struct file *file, const char __user *data,
return len; return len;
} }
static int txx9wdt_ioctl(struct inode *inode, struct file *file, static long txx9wdt_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_timeout; int new_timeout;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT | .options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
...@@ -168,18 +175,18 @@ static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code, ...@@ -168,18 +175,18 @@ static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
} }
static const struct file_operations txx9wdt_fops = { static const struct file_operations txx9wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = txx9wdt_write, .write = txx9wdt_write,
.ioctl = txx9wdt_ioctl, .unlocked_ioctl = txx9wdt_ioctl,
.open = txx9wdt_open, .open = txx9wdt_open,
.release = txx9wdt_release, .release = txx9wdt_release,
}; };
static struct miscdevice txx9wdt_miscdev = { static struct miscdevice txx9wdt_miscdev = {
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &txx9wdt_fops, .fops = &txx9wdt_fops,
}; };
static struct notifier_block txx9wdt_notifier = { static struct notifier_block txx9wdt_notifier = {
......
...@@ -37,9 +37,9 @@ ...@@ -37,9 +37,9 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define WATCHDOG_NAME "w83627hf/thf/hg WDT" #define WATCHDOG_NAME "w83627hf/thf/hg WDT"
...@@ -57,22 +57,26 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); ...@@ -57,22 +57,26 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1 <= timeout <= 255, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Kernel methods. * Kernel methods.
*/ */
#define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */ #define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */
#define WDT_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ #define WDT_EFIR (wdt_io+0) /* Extended Function Index Register
(same as EFER) */
#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */ #define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
static void static void w83627hf_select_wd_register(void)
w83627hf_select_wd_register(void)
{ {
unsigned char c; unsigned char c;
outb_p(0x87, WDT_EFER); /* Enter extended function mode */ outb_p(0x87, WDT_EFER); /* Enter extended function mode */
...@@ -93,43 +97,45 @@ w83627hf_select_wd_register(void) ...@@ -93,43 +97,45 @@ w83627hf_select_wd_register(void)
outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */ outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
} }
static void static void w83627hf_unselect_wd_register(void)
w83627hf_unselect_wd_register(void)
{ {
outb_p(0xAA, WDT_EFER); /* Leave extended function mode */ outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
} }
/* tyan motherboards seem to set F5 to 0x4C ? /* tyan motherboards seem to set F5 to 0x4C ?
* So explicitly init to appropriate value. */ * So explicitly init to appropriate value. */
static void
w83627hf_init(void) static void w83627hf_init(void)
{ {
unsigned char t; unsigned char t;
w83627hf_select_wd_register(); w83627hf_select_wd_register();
outb_p(0xF6, WDT_EFER); /* Select CRF6 */ outb_p(0xF6, WDT_EFER); /* Select CRF6 */
t=inb_p(WDT_EFDR); /* read CRF6 */ t = inb_p(WDT_EFDR); /* read CRF6 */
if (t != 0) { if (t != 0) {
printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout); printk(KERN_INFO PFX
"Watchdog already running. Resetting timeout to %d sec\n",
timeout);
outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
} }
outb_p(0xF5, WDT_EFER); /* Select CRF5 */ outb_p(0xF5, WDT_EFER); /* Select CRF5 */
t=inb_p(WDT_EFDR); /* read CRF5 */ t = inb_p(WDT_EFDR); /* read CRF5 */
t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */ t &= ~0x0C; /* set second mode & disable keyboard
turning off watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF5 */ outb_p(t, WDT_EFDR); /* Write back to CRF5 */
outb_p(0xF7, WDT_EFER); /* Select CRF7 */ outb_p(0xF7, WDT_EFER); /* Select CRF7 */
t=inb_p(WDT_EFDR); /* read CRF7 */ t = inb_p(WDT_EFDR); /* read CRF7 */
t&=~0xC0; /* disable keyboard & mouse turning off watchdog */ t &= ~0xC0; /* disable keyboard & mouse turning off
watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF7 */ outb_p(t, WDT_EFDR); /* Write back to CRF7 */
w83627hf_unselect_wd_register(); w83627hf_unselect_wd_register();
} }
static void static void wdt_ctrl(int timeout)
wdt_ctrl(int timeout)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
...@@ -143,32 +149,28 @@ wdt_ctrl(int timeout) ...@@ -143,32 +149,28 @@ wdt_ctrl(int timeout)
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
static int static int wdt_ping(void)
wdt_ping(void)
{ {
wdt_ctrl(timeout); wdt_ctrl(timeout);
return 0; return 0;
} }
static int static int wdt_disable(void)
wdt_disable(void)
{ {
wdt_ctrl(0); wdt_ctrl(0);
return 0; return 0;
} }
static int static int wdt_set_heartbeat(int t)
wdt_set_heartbeat(int t)
{ {
if ((t < 1) || (t > 255)) if (t < 1 || t > 255)
return -EINVAL; return -EINVAL;
timeout = t; timeout = t;
return 0; return 0;
} }
static ssize_t static ssize_t wdt_write(struct file *file, const char __user *buf,
wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
...@@ -189,72 +191,61 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ...@@ -189,72 +191,61 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
return count; return count;
} }
static int static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_timeout; int new_timeout;
static struct watchdog_info ident = { static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "W83627HF WDT", .identity = "W83627HF WDT",
}; };
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
wdt_ping(); wdt_ping();
break; break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p)) if (get_user(new_timeout, p))
return -EFAULT; return -EFAULT;
if (wdt_set_heartbeat(new_timeout)) if (wdt_set_heartbeat(new_timeout))
return -EINVAL; return -EINVAL;
wdt_ping(); wdt_ping();
/* Fall */ /* Fall */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(timeout, p); return put_user(timeout, p);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
{ {
int options, retval = -EINVAL; int options, retval = -EINVAL;
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
wdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
wdt_ping();
retval = 0;
}
return retval; if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
wdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
wdt_ping();
retval = 0;
}
return retval;
} }
default: default:
return -ENOTTY; return -ENOTTY;
} }
return 0; return 0;
} }
static int static int wdt_open(struct inode *inode, struct file *file)
wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &wdt_is_open)) if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
...@@ -266,13 +257,13 @@ wdt_open(struct inode *inode, struct file *file) ...@@ -266,13 +257,13 @@ wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int static int wdt_close(struct inode *inode, struct file *file)
wdt_close(struct inode *inode, struct file *file)
{ {
if (expect_close == 42) { if (expect_close == 42)
wdt_disable(); wdt_disable();
} else { else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
wdt_ping(); wdt_ping();
} }
expect_close = 0; expect_close = 0;
...@@ -284,8 +275,7 @@ wdt_close(struct inode *inode, struct file *file) ...@@ -284,8 +275,7 @@ wdt_close(struct inode *inode, struct file *file)
* Notifier for system down * Notifier for system down
*/ */
static int static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT) {
...@@ -303,7 +293,7 @@ static const struct file_operations wdt_fops = { ...@@ -303,7 +293,7 @@ static const struct file_operations wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = wdt_write, .write = wdt_write,
.ioctl = wdt_ioctl, .unlocked_ioctl = wdt_ioctl,
.open = wdt_open, .open = wdt_open,
.release = wdt_close, .release = wdt_close,
}; };
...@@ -323,8 +313,7 @@ static struct notifier_block wdt_notifier = { ...@@ -323,8 +313,7 @@ static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys, .notifier_call = wdt_notify_sys,
}; };
static int __init static int __init wdt_init(void)
wdt_init(void)
{ {
int ret; int ret;
...@@ -332,12 +321,13 @@ wdt_init(void) ...@@ -332,12 +321,13 @@ wdt_init(void)
if (wdt_set_heartbeat(timeout)) { if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT); wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", printk(KERN_INFO PFX
WATCHDOG_TIMEOUT); "timeout value must be 1 <= timeout <= 255, using %d\n",
WATCHDOG_TIMEOUT);
} }
if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_io); wdt_io);
ret = -EIO; ret = -EIO;
goto out; goto out;
...@@ -347,20 +337,22 @@ wdt_init(void) ...@@ -347,20 +337,22 @@ wdt_init(void)
ret = register_reboot_notifier(&wdt_notifier); ret = register_reboot_notifier(&wdt_notifier);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
goto unreg_regions; goto unreg_regions;
} }
ret = misc_register(&wdt_miscdev); ret = misc_register(&wdt_miscdev);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_reboot; goto unreg_reboot;
} }
printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX
timeout, nowayout); "initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
out: out:
return ret; return ret;
...@@ -371,12 +363,11 @@ wdt_init(void) ...@@ -371,12 +363,11 @@ wdt_init(void)
goto out; goto out;
} }
static void __exit static void __exit wdt_exit(void)
wdt_exit(void)
{ {
misc_deregister(&wdt_miscdev); misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
release_region(wdt_io,1); release_region(wdt_io, 1);
} }
module_init(wdt_init); module_init(wdt_init);
......
...@@ -36,9 +36,9 @@ ...@@ -36,9 +36,9 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define WATCHDOG_NAME "w83697hf/hg WDT" #define WATCHDOG_NAME "w83697hf/hg WDT"
...@@ -53,37 +53,43 @@ static DEFINE_SPINLOCK(io_lock); ...@@ -53,37 +53,43 @@ static DEFINE_SPINLOCK(io_lock);
/* You must set this - there is no sane way to probe for this board. */ /* You must set this - there is no sane way to probe for this board. */
static int wdt_io = 0x2e; static int wdt_io = 0x2e;
module_param(wdt_io, int, 0); module_param(wdt_io, int, 0);
MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); MODULE_PARM_DESC(wdt_io,
"w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255 (default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1<= timeout <=255 (default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static int early_disable = WATCHDOG_EARLY_DISABLE; static int early_disable = WATCHDOG_EARLY_DISABLE;
module_param(early_disable, int, 0); module_param(early_disable, int, 0);
MODULE_PARM_DESC(early_disable, "Watchdog gets disabled at boot time (default=" __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")"); MODULE_PARM_DESC(early_disable,
"Watchdog gets disabled at boot time (default="
__MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")");
/* /*
* Kernel methods. * Kernel methods.
*/ */
#define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */ #define W83697HF_EFER (wdt_io + 0) /* Extended Function Enable Register */
#define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ #define W83697HF_EFIR (wdt_io + 0) /* Extended Function Index Register
#define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */ (same as EFER) */
#define W83697HF_EFDR (wdt_io + 1) /* Extended Function Data Register */
static inline void static inline void w83697hf_unlock(void)
w83697hf_unlock(void)
{ {
outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */
outb_p(0x87, W83697HF_EFER); /* Again according to manual */ outb_p(0x87, W83697HF_EFER); /* Again according to manual */
} }
static inline void static inline void w83697hf_lock(void)
w83697hf_lock(void)
{ {
outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */
} }
...@@ -93,41 +99,36 @@ w83697hf_lock(void) ...@@ -93,41 +99,36 @@ w83697hf_lock(void)
* w83697hf_write_timeout() must be called with the device unlocked. * w83697hf_write_timeout() must be called with the device unlocked.
*/ */
static unsigned char static unsigned char w83697hf_get_reg(unsigned char reg)
w83697hf_get_reg(unsigned char reg)
{ {
outb_p(reg, W83697HF_EFIR); outb_p(reg, W83697HF_EFIR);
return inb_p(W83697HF_EFDR); return inb_p(W83697HF_EFDR);
} }
static void static void w83697hf_set_reg(unsigned char reg, unsigned char data)
w83697hf_set_reg(unsigned char reg, unsigned char data)
{ {
outb_p(reg, W83697HF_EFIR); outb_p(reg, W83697HF_EFIR);
outb_p(data, W83697HF_EFDR); outb_p(data, W83697HF_EFDR);
} }
static void static void w83697hf_write_timeout(int timeout)
w83697hf_write_timeout(int timeout)
{ {
w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */ /* Write Timeout counter to CRF4 */
w83697hf_set_reg(0xF4, timeout);
} }
static void static void w83697hf_select_wdt(void)
w83697hf_select_wdt(void)
{ {
w83697hf_unlock(); w83697hf_unlock();
w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */
} }
static inline void static inline void w83697hf_deselect_wdt(void)
w83697hf_deselect_wdt(void)
{ {
w83697hf_lock(); w83697hf_lock();
} }
static void static void w83697hf_init(void)
w83697hf_init(void)
{ {
unsigned char bbuf; unsigned char bbuf;
...@@ -136,7 +137,9 @@ w83697hf_init(void) ...@@ -136,7 +137,9 @@ w83697hf_init(void)
bbuf = w83697hf_get_reg(0x29); bbuf = w83697hf_get_reg(0x29);
bbuf &= ~0x60; bbuf &= ~0x60;
bbuf |= 0x20; bbuf |= 0x20;
w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
/* Set pin 119 to WDTO# mode (= CR29, WDT0) */
w83697hf_set_reg(0x29, bbuf);
bbuf = w83697hf_get_reg(0xF3); bbuf = w83697hf_get_reg(0xF3);
bbuf &= ~0x04; bbuf &= ~0x04;
...@@ -145,8 +148,7 @@ w83697hf_init(void) ...@@ -145,8 +148,7 @@ w83697hf_init(void)
w83697hf_deselect_wdt(); w83697hf_deselect_wdt();
} }
static void static void wdt_ping(void)
wdt_ping(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
w83697hf_select_wdt(); w83697hf_select_wdt();
...@@ -157,8 +159,7 @@ wdt_ping(void) ...@@ -157,8 +159,7 @@ wdt_ping(void)
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
static void static void wdt_enable(void)
wdt_enable(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
w83697hf_select_wdt(); w83697hf_select_wdt();
...@@ -170,8 +171,7 @@ wdt_enable(void) ...@@ -170,8 +171,7 @@ wdt_enable(void)
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
static void static void wdt_disable(void)
wdt_disable(void)
{ {
spin_lock(&io_lock); spin_lock(&io_lock);
w83697hf_select_wdt(); w83697hf_select_wdt();
...@@ -183,8 +183,7 @@ wdt_disable(void) ...@@ -183,8 +183,7 @@ wdt_disable(void)
spin_unlock(&io_lock); spin_unlock(&io_lock);
} }
static unsigned char static unsigned char wdt_running(void)
wdt_running(void)
{ {
unsigned char t; unsigned char t;
...@@ -199,18 +198,17 @@ wdt_running(void) ...@@ -199,18 +198,17 @@ wdt_running(void)
return t; return t;
} }
static int static int wdt_set_heartbeat(int t)
wdt_set_heartbeat(int t)
{ {
if ((t < 1) || (t > 255)) if (t < 1 || t > 255)
return -EINVAL; return -EINVAL;
timeout = t; timeout = t;
return 0; return 0;
} }
static ssize_t static ssize_t wdt_write(struct file *file, const char __user *buf,
wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) { if (count) {
if (!nowayout) { if (!nowayout) {
...@@ -231,15 +229,14 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ...@@ -231,15 +229,14 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
return count; return count;
} }
static int static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
int new_timeout; int new_timeout;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "W83697HF WDT", .identity = "W83697HF WDT",
}; };
...@@ -295,8 +292,7 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -295,8 +292,7 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return 0; return 0;
} }
static int static int wdt_open(struct inode *inode, struct file *file)
wdt_open(struct inode *inode, struct file *file)
{ {
if (test_and_set_bit(0, &wdt_is_open)) if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
...@@ -308,13 +304,13 @@ wdt_open(struct inode *inode, struct file *file) ...@@ -308,13 +304,13 @@ wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int static int wdt_close(struct inode *inode, struct file *file)
wdt_close(struct inode *inode, struct file *file)
{ {
if (expect_close == 42) { if (expect_close == 42)
wdt_disable(); wdt_disable();
} else { else {
printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
wdt_ping(); wdt_ping();
} }
expect_close = 0; expect_close = 0;
...@@ -326,8 +322,7 @@ wdt_close(struct inode *inode, struct file *file) ...@@ -326,8 +322,7 @@ wdt_close(struct inode *inode, struct file *file)
* Notifier for system down * Notifier for system down
*/ */
static int static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT) {
...@@ -345,7 +340,7 @@ static const struct file_operations wdt_fops = { ...@@ -345,7 +340,7 @@ static const struct file_operations wdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = wdt_write, .write = wdt_write,
.ioctl = wdt_ioctl, .unlocked_ioctl = wdt_ioctl,
.open = wdt_open, .open = wdt_open,
.release = wdt_close, .release = wdt_close,
}; };
...@@ -365,36 +360,38 @@ static struct notifier_block wdt_notifier = { ...@@ -365,36 +360,38 @@ static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys, .notifier_call = wdt_notify_sys,
}; };
static int static int w83697hf_check_wdt(void)
w83697hf_check_wdt(void)
{ {
if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io); printk(KERN_ERR PFX
"I/O address 0x%x already in use\n", wdt_io);
return -EIO; return -EIO;
} }
printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io); printk(KERN_DEBUG PFX
"Looking for watchdog at address 0x%x\n", wdt_io);
w83697hf_unlock(); w83697hf_unlock();
if (w83697hf_get_reg(0x20) == 0x60) { if (w83697hf_get_reg(0x20) == 0x60) {
printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io); printk(KERN_INFO PFX
"watchdog found at address 0x%x\n", wdt_io);
w83697hf_lock(); w83697hf_lock();
return 0; return 0;
} }
w83697hf_lock(); /* Reprotect in case it was a compatible device */ /* Reprotect in case it was a compatible device */
w83697hf_lock();
printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); printk(KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io);
release_region(wdt_io, 2); release_region(wdt_io, 2);
return -EIO; return -EIO;
} }
static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 };
static int __init static int __init wdt_init(void)
wdt_init(void)
{ {
int ret, i, found = 0; int ret, i, found = 0;
printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); printk(KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
if (wdt_io == 0) { if (wdt_io == 0) {
/* we will autodetect the W83697HF/HG watchdog */ /* we will autodetect the W83697HF/HG watchdog */
...@@ -409,7 +406,7 @@ wdt_init(void) ...@@ -409,7 +406,7 @@ wdt_init(void)
} }
if (!found) { if (!found) {
printk (KERN_ERR PFX "No W83697HF/HG could be found\n"); printk(KERN_ERR PFX "No W83697HF/HG could be found\n");
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
...@@ -423,25 +420,27 @@ wdt_init(void) ...@@ -423,25 +420,27 @@ wdt_init(void)
if (wdt_set_heartbeat(timeout)) { if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT); wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", printk(KERN_INFO PFX
WATCHDOG_TIMEOUT); "timeout value must be 1 <= timeout <= 255, using %d\n",
WATCHDOG_TIMEOUT);
} }
ret = register_reboot_notifier(&wdt_notifier); ret = register_reboot_notifier(&wdt_notifier);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
goto unreg_regions; goto unreg_regions;
} }
ret = misc_register(&wdt_miscdev); ret = misc_register(&wdt_miscdev);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_reboot; goto unreg_reboot;
} }
printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout); timeout, nowayout);
out: out:
...@@ -453,8 +452,7 @@ wdt_init(void) ...@@ -453,8 +452,7 @@ wdt_init(void)
goto out; goto out;
} }
static void __exit static void __exit wdt_exit(void)
wdt_exit(void)
{ {
misc_deregister(&wdt_miscdev); misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
......
...@@ -23,13 +23,16 @@ ...@@ -23,13 +23,16 @@
* Added KERN_* tags to printks * Added KERN_* tags to printks
* add CONFIG_WATCHDOG_NOWAYOUT support * add CONFIG_WATCHDOG_NOWAYOUT support
* fix possible wdt_is_open race * fix possible wdt_is_open race
* changed watchdog_info to correctly reflect what the driver offers * changed watchdog_info to correctly reflect what
* added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, * the driver offers
* added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS,
* WDIOC_SETTIMEOUT,
* WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
* 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
* added extra printk's for startup problems * added extra printk's for startup problems
* use module_param * use module_param
* made timeout (the emulated heartbeat) a module_param * made timeout (the emulated heartbeat) a
* module_param
* made the keepalive ping an internal subroutine * made the keepalive ping an internal subroutine
* *
* This WDT driver is different from most other Linux WDT * This WDT driver is different from most other Linux WDT
...@@ -51,8 +54,8 @@ ...@@ -51,8 +54,8 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define OUR_NAME "w83877f_wdt" #define OUR_NAME "w83877f_wdt"
...@@ -80,14 +83,19 @@ ...@@ -80,14 +83,19 @@
*/ */
#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
static int timeout = WATCHDOG_TIMEOUT;
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=3600, default="
__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void wdt_timer_ping(unsigned long); static void wdt_timer_ping(unsigned long);
static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
...@@ -105,8 +113,7 @@ static void wdt_timer_ping(unsigned long data) ...@@ -105,8 +113,7 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL /* If we got a heartbeat pulse within the WDT_US_INTERVAL
* we agree to ping the WDT * we agree to ping the WDT
*/ */
if(time_before(jiffies, next_heartbeat)) if (time_before(jiffies, next_heartbeat)) {
{
/* Ping the WDT */ /* Ping the WDT */
spin_lock(&wdt_spinlock); spin_lock(&wdt_spinlock);
...@@ -118,9 +125,9 @@ static void wdt_timer_ping(unsigned long data) ...@@ -118,9 +125,9 @@ static void wdt_timer_ping(unsigned long data)
spin_unlock(&wdt_spinlock); spin_unlock(&wdt_spinlock);
} else { } else
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); printk(KERN_WARNING PFX
} "Heartbeat lost! Will not ping the watchdog\n");
} }
/* /*
...@@ -181,22 +188,21 @@ static void wdt_keepalive(void) ...@@ -181,22 +188,21 @@ static void wdt_keepalive(void)
* /dev/watchdog handling * /dev/watchdog handling
*/ */
static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) static ssize_t fop_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) if (count) {
{ if (!nowayout) {
if (!nowayout)
{
size_t ofs; size_t ofs;
/* note: just in case someone wrote the magic character /* note: just in case someone wrote the magic
* five months ago... */ character five months ago... */
wdt_expect_close = 0; wdt_expect_close = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the
for(ofs = 0; ofs != count; ofs++) magic character */
{ for (ofs = 0; ofs != count; ofs++) {
char c; char c;
if (get_user(c, buf + ofs)) if (get_user(c, buf + ofs))
return -EFAULT; return -EFAULT;
...@@ -211,10 +217,10 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou ...@@ -211,10 +217,10 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
return count; return count;
} }
static int fop_open(struct inode * inode, struct file * file) static int fop_open(struct inode *inode, struct file *file)
{ {
/* Just in case we're already talking to someone... */ /* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open)) if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
/* Good, fire up the show */ /* Good, fire up the show */
...@@ -222,78 +228,78 @@ static int fop_open(struct inode * inode, struct file * file) ...@@ -222,78 +228,78 @@ static int fop_open(struct inode * inode, struct file * file)
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
static int fop_close(struct inode * inode, struct file * file) static int fop_close(struct inode *inode, struct file *file)
{ {
if(wdt_expect_close == 42) if (wdt_expect_close == 42)
wdt_turnoff(); wdt_turnoff();
else { else {
del_timer(&timer); del_timer(&timer);
printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); printk(KERN_CRIT PFX
"device file closed unexpectedly. Will not stop the WDT!\n");
} }
clear_bit(0, &wdt_is_open); clear_bit(0, &wdt_is_open);
wdt_expect_close = 0; wdt_expect_close = 0;
return 0; return 0;
} }
static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident= static const struct watchdog_info ident = {
{ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "W83877F", .identity = "W83877F",
}; };
switch(cmd) switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{ {
default: int new_options, retval = -EINVAL;
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if(get_user(new_options, p))
return -EFAULT;
if(new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
if(new_options & WDIOS_ENABLECARD) { if (get_user(new_options, p))
wdt_startup(); return -EFAULT;
retval = 0;
}
return retval; if (new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
} }
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if(get_user(new_timeout, p)) if (new_options & WDIOS_ENABLECARD) {
return -EFAULT; wdt_startup();
retval = 0;
}
if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ return retval;
return -EINVAL; }
case WDIOC_SETTIMEOUT:
{
int new_timeout;
timeout = new_timeout; if (get_user(new_timeout, p))
wdt_keepalive(); return -EFAULT;
/* Fall through */
} /* arbitrary upper limit */
case WDIOC_GETTIMEOUT: if (new_timeout < 1 || new_timeout > 3600)
return put_user(timeout, p); return -EINVAL;
timeout = new_timeout;
wdt_keepalive();
/* Fall through */
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
} }
} }
...@@ -303,7 +309,7 @@ static const struct file_operations wdt_fops = { ...@@ -303,7 +309,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write, .write = fop_write,
.open = fop_open, .open = fop_open,
.release = fop_close, .release = fop_close,
.ioctl = fop_ioctl, .unlocked_ioctl = fop_ioctl,
}; };
static struct miscdevice wdt_miscdev = { static struct miscdevice wdt_miscdev = {
...@@ -319,7 +325,7 @@ static struct miscdevice wdt_miscdev = { ...@@ -319,7 +325,7 @@ static struct miscdevice wdt_miscdev = {
static int wdt_notify_sys(struct notifier_block *this, unsigned long code, static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
wdt_turnoff(); wdt_turnoff();
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -329,8 +335,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, ...@@ -329,8 +335,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
* turn the timebomb registers off. * turn the timebomb registers off.
*/ */
static struct notifier_block wdt_notifier= static struct notifier_block wdt_notifier = {
{
.notifier_call = wdt_notify_sys, .notifier_call = wdt_notify_sys,
}; };
...@@ -342,31 +347,29 @@ static void __exit w83877f_wdt_unload(void) ...@@ -342,31 +347,29 @@ static void __exit w83877f_wdt_unload(void)
misc_deregister(&wdt_miscdev); misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
release_region(WDT_PING,1); release_region(WDT_PING, 1);
release_region(ENABLE_W83877F_PORT,2); release_region(ENABLE_W83877F_PORT, 2);
} }
static int __init w83877f_wdt_init(void) static int __init w83877f_wdt_init(void)
{ {
int rc = -EBUSY; int rc = -EBUSY;
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
{
timeout = WATCHDOG_TIMEOUT; timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", printk(KERN_INFO PFX
timeout); "timeout value must be 1 <= x <= 3600, using %d\n",
timeout);
} }
if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) {
{
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
ENABLE_W83877F_PORT); ENABLE_W83877F_PORT);
rc = -EIO; rc = -EIO;
goto err_out; goto err_out;
} }
if (!request_region(WDT_PING, 1, "W8387FF WDT")) if (!request_region(WDT_PING, 1, "W8387FF WDT")) {
{
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
WDT_PING); WDT_PING);
rc = -EIO; rc = -EIO;
...@@ -374,22 +377,22 @@ static int __init w83877f_wdt_init(void) ...@@ -374,22 +377,22 @@ static int __init w83877f_wdt_init(void)
} }
rc = register_reboot_notifier(&wdt_notifier); rc = register_reboot_notifier(&wdt_notifier);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", "cannot register reboot notifier (err=%d)\n", rc);
rc);
goto err_out_region2; goto err_out_region2;
} }
rc = misc_register(&wdt_miscdev); rc = misc_register(&wdt_miscdev);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", "cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc); wdt_miscdev.minor, rc);
goto err_out_reboot; goto err_out_reboot;
} }
printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX
"WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout); timeout, nowayout);
return 0; return 0;
...@@ -397,9 +400,9 @@ static int __init w83877f_wdt_init(void) ...@@ -397,9 +400,9 @@ static int __init w83877f_wdt_init(void)
err_out_reboot: err_out_reboot:
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
err_out_region2: err_out_region2:
release_region(WDT_PING,1); release_region(WDT_PING, 1);
err_out_region1: err_out_region1:
release_region(ENABLE_W83877F_PORT,2); release_region(ENABLE_W83877F_PORT, 2);
err_out: err_out:
return rc; return rc;
} }
......
...@@ -26,10 +26,10 @@ ...@@ -26,10 +26,10 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h>
#define WATCHDOG_VERSION "1.00" #define WATCHDOG_VERSION "1.00"
#define WATCHDOG_NAME "W83977F WDT" #define WATCHDOG_NAME "W83977F WDT"
...@@ -53,13 +53,17 @@ static char expect_close; ...@@ -53,13 +53,17 @@ static char expect_close;
static DEFINE_SPINLOCK(spinlock); static DEFINE_SPINLOCK(spinlock);
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds (15..7635), default="
__MODULE_STRING(DEFAULT_TIMEOUT) ")");
module_param(testmode, int, 0); module_param(testmode, int, 0);
MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Start the watchdog * Start the watchdog
...@@ -72,8 +76,8 @@ static int wdt_start(void) ...@@ -72,8 +76,8 @@ static int wdt_start(void)
spin_lock_irqsave(&spinlock, flags); spin_lock_irqsave(&spinlock, flags);
/* Unlock the SuperIO chip */ /* Unlock the SuperIO chip */
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* /*
* Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
...@@ -81,50 +85,49 @@ static int wdt_start(void) ...@@ -81,50 +85,49 @@ static int wdt_start(void)
* F3 is set to enable watchdog LED blink at timeout. * F3 is set to enable watchdog LED blink at timeout.
* F4 is used to just clear the TIMEOUT'ed state (bit 0). * F4 is used to just clear the TIMEOUT'ed state (bit 0).
*/ */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT); outb_p(0x08, IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT); outb_p(0xF2, IO_INDEX_PORT);
outb_p(timeoutW,IO_DATA_PORT); outb_p(timeoutW, IO_DATA_PORT);
outb_p(0xF3,IO_INDEX_PORT); outb_p(0xF3, IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT); outb_p(0x08, IO_DATA_PORT);
outb_p(0xF4,IO_INDEX_PORT); outb_p(0xF4, IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT); outb_p(0x00, IO_DATA_PORT);
/* Set device Aux2 active */ /* Set device Aux2 active */
outb_p(0x30,IO_INDEX_PORT); outb_p(0x30, IO_INDEX_PORT);
outb_p(0x01,IO_DATA_PORT); outb_p(0x01, IO_DATA_PORT);
/* /*
* Select device Aux1 (dev=7) to set GP16 as the watchdog output * Select device Aux1 (dev=7) to set GP16 as the watchdog output
* (in reg E6) and GP13 as the watchdog LED output (in reg E3). * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
* Map GP16 at pin 119. * Map GP16 at pin 119.
* In test mode watch the bit 0 on F4 to indicate "triggered" or * In test mode watch the bit 0 on F4 to indicate "triggered" or
* check watchdog LED on SBC. * check watchdog LED on SBC.
*/ */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x07,IO_DATA_PORT); outb_p(0x07, IO_DATA_PORT);
if (!testmode) if (!testmode) {
{
unsigned pin_map; unsigned pin_map;
outb_p(0xE6,IO_INDEX_PORT); outb_p(0xE6, IO_INDEX_PORT);
outb_p(0x0A,IO_DATA_PORT); outb_p(0x0A, IO_DATA_PORT);
outb_p(0x2C,IO_INDEX_PORT); outb_p(0x2C, IO_INDEX_PORT);
pin_map = inb_p(IO_DATA_PORT); pin_map = inb_p(IO_DATA_PORT);
pin_map |= 0x10; pin_map |= 0x10;
pin_map &= ~(0x20); pin_map &= ~(0x20);
outb_p(0x2C,IO_INDEX_PORT); outb_p(0x2C, IO_INDEX_PORT);
outb_p(pin_map,IO_DATA_PORT); outb_p(pin_map, IO_DATA_PORT);
} }
outb_p(0xE3,IO_INDEX_PORT); outb_p(0xE3, IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT); outb_p(0x08, IO_DATA_PORT);
/* Set device Aux1 active */ /* Set device Aux1 active */
outb_p(0x30,IO_INDEX_PORT); outb_p(0x30, IO_INDEX_PORT);
outb_p(0x01,IO_DATA_PORT); outb_p(0x01, IO_DATA_PORT);
/* Lock the SuperIO chip */ /* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT); outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
...@@ -144,42 +147,41 @@ static int wdt_stop(void) ...@@ -144,42 +147,41 @@ static int wdt_stop(void)
spin_lock_irqsave(&spinlock, flags); spin_lock_irqsave(&spinlock, flags);
/* Unlock the SuperIO chip */ /* Unlock the SuperIO chip */
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* /*
* Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
* F2 is reset to its default value (watchdog timer disabled). * F2 is reset to its default value (watchdog timer disabled).
* F3 is reset to its default state. * F3 is reset to its default state.
* F4 clears the TIMEOUT'ed state (bit 0) - back to default. * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
*/ */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT); outb_p(0x08, IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT); outb_p(0xF2, IO_INDEX_PORT);
outb_p(0xFF,IO_DATA_PORT); outb_p(0xFF, IO_DATA_PORT);
outb_p(0xF3,IO_INDEX_PORT); outb_p(0xF3, IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT); outb_p(0x00, IO_DATA_PORT);
outb_p(0xF4,IO_INDEX_PORT); outb_p(0xF4, IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT); outb_p(0x00, IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT); outb_p(0xF2, IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT); outb_p(0x00, IO_DATA_PORT);
/* /*
* Select device Aux1 (dev=7) to set GP16 (in reg E6) and * Select device Aux1 (dev=7) to set GP16 (in reg E6) and
* Gp13 (in reg E3) as inputs. * Gp13 (in reg E3) as inputs.
*/ */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x07,IO_DATA_PORT); outb_p(0x07, IO_DATA_PORT);
if (!testmode) if (!testmode) {
{ outb_p(0xE6, IO_INDEX_PORT);
outb_p(0xE6,IO_INDEX_PORT); outb_p(0x01, IO_DATA_PORT);
outb_p(0x01,IO_DATA_PORT);
} }
outb_p(0xE3,IO_INDEX_PORT); outb_p(0xE3, IO_INDEX_PORT);
outb_p(0x01,IO_DATA_PORT); outb_p(0x01, IO_DATA_PORT);
/* Lock the SuperIO chip */ /* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT); outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
...@@ -200,17 +202,17 @@ static int wdt_keepalive(void) ...@@ -200,17 +202,17 @@ static int wdt_keepalive(void)
spin_lock_irqsave(&spinlock, flags); spin_lock_irqsave(&spinlock, flags);
/* Unlock the SuperIO chip */ /* Unlock the SuperIO chip */
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* Select device Aux2 (device=8) to kick watchdog reg F2 */ /* Select device Aux2 (device=8) to kick watchdog reg F2 */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT); outb_p(0x08, IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT); outb_p(0xF2, IO_INDEX_PORT);
outb_p(timeoutW,IO_DATA_PORT); outb_p(timeoutW, IO_DATA_PORT);
/* Lock the SuperIO chip */ /* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT); outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
...@@ -227,7 +229,7 @@ static int wdt_set_timeout(int t) ...@@ -227,7 +229,7 @@ static int wdt_set_timeout(int t)
/* /*
* Convert seconds to watchdog counter time units, rounding up. * Convert seconds to watchdog counter time units, rounding up.
* On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup
* value. This information is supplied in the PCM-5335 manual and was * value. This information is supplied in the PCM-5335 manual and was
* checked by me on a real board. This is a bit strange because W83977f * checked by me on a real board. This is a bit strange because W83977f
* datasheet says counter unit is in minutes! * datasheet says counter unit is in minutes!
...@@ -241,7 +243,7 @@ static int wdt_set_timeout(int t) ...@@ -241,7 +243,7 @@ static int wdt_set_timeout(int t)
return -EINVAL; return -EINVAL;
/* /*
* timeout is the timeout in seconds, * timeout is the timeout in seconds,
* timeoutW is the timeout in watchdog counter units. * timeoutW is the timeout in watchdog counter units.
*/ */
timeoutW = tmrval; timeoutW = tmrval;
...@@ -261,17 +263,17 @@ static int wdt_get_status(int *status) ...@@ -261,17 +263,17 @@ static int wdt_get_status(int *status)
spin_lock_irqsave(&spinlock, flags); spin_lock_irqsave(&spinlock, flags);
/* Unlock the SuperIO chip */ /* Unlock the SuperIO chip */
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
outb_p(UNLOCK_DATA,IO_INDEX_PORT); outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* Select device Aux2 (device=8) to read watchdog reg F4 */ /* Select device Aux2 (device=8) to read watchdog reg F4 */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT); outb_p(0x08, IO_DATA_PORT);
outb_p(0xF4,IO_INDEX_PORT); outb_p(0xF4, IO_INDEX_PORT);
new_status = inb_p(IO_DATA_PORT); new_status = inb_p(IO_DATA_PORT);
/* Lock the SuperIO chip */ /* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT); outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
...@@ -290,7 +292,7 @@ static int wdt_get_status(int *status) ...@@ -290,7 +292,7 @@ static int wdt_get_status(int *status)
static int wdt_open(struct inode *inode, struct file *file) static int wdt_open(struct inode *inode, struct file *file)
{ {
/* If the watchdog is alive we don't need to start it again */ /* If the watchdog is alive we don't need to start it again */
if( test_and_set_bit(0, &timer_alive) ) if (test_and_set_bit(0, &timer_alive))
return -EBUSY; return -EBUSY;
if (nowayout) if (nowayout)
...@@ -306,13 +308,13 @@ static int wdt_release(struct inode *inode, struct file *file) ...@@ -306,13 +308,13 @@ static int wdt_release(struct inode *inode, struct file *file)
* Shut off the timer. * Shut off the timer.
* Lock it in if it's a module and we set nowayout * Lock it in if it's a module and we set nowayout
*/ */
if (expect_close == 42) if (expect_close == 42) {
{
wdt_stop(); wdt_stop();
clear_bit(0, &timer_alive); clear_bit(0, &timer_alive);
} else { } else {
wdt_keepalive(); wdt_keepalive();
printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"unexpected close, not stopping watchdog!\n");
} }
expect_close = 0; expect_close = 0;
return 0; return 0;
...@@ -333,24 +335,22 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, ...@@ -333,24 +335,22 @@ static ssize_t wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if(count) if (count) {
{ if (!nowayout) {
if (!nowayout)
{
size_t ofs; size_t ofs;
/* note: just in case someone wrote the magic character long ago */ /* note: just in case someone wrote the
magic character long ago */
expect_close = 0; expect_close = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the
for(ofs = 0; ofs != count; ofs++) magic character */
{ for (ofs = 0; ofs != count; ofs++) {
char c; char c;
if (get_user(c, buf + ofs)) if (get_user(c, buf + ofs))
return -EFAULT; return -EFAULT;
if (c == 'V') { if (c == 'V')
expect_close = 42; expect_close = 42;
}
} }
} }
...@@ -377,8 +377,7 @@ static struct watchdog_info ident = { ...@@ -377,8 +377,7 @@ static struct watchdog_info ident = {
.identity = WATCHDOG_NAME, .identity = WATCHDOG_NAME,
}; };
static int wdt_ioctl(struct inode *inode, struct file *file, static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
int status; int status;
int new_options, retval = -EINVAL; int new_options, retval = -EINVAL;
...@@ -390,13 +389,13 @@ static int wdt_ioctl(struct inode *inode, struct file *file, ...@@ -390,13 +389,13 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
uarg.i = (int __user *)arg; uarg.i = (int __user *)arg;
switch(cmd) switch (cmd) {
{
default: default:
return -ENOTTY; return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; return copy_to_user(uarg.ident, &ident,
sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
wdt_get_status(&status); wdt_get_status(&status);
...@@ -410,7 +409,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, ...@@ -410,7 +409,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
return 0; return 0;
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
if (get_user (new_options, uarg.i)) if (get_user(new_options, uarg.i))
return -EFAULT; return -EFAULT;
if (new_options & WDIOS_DISABLECARD) { if (new_options & WDIOS_DISABLECARD) {
...@@ -444,23 +443,21 @@ static int wdt_ioctl(struct inode *inode, struct file *file, ...@@ -444,23 +443,21 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
static int wdt_notify_sys(struct notifier_block *this, unsigned long code, static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if (code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
wdt_stop(); wdt_stop();
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static const struct file_operations wdt_fops= static const struct file_operations wdt_fops = {
{
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = wdt_write, .write = wdt_write,
.ioctl = wdt_ioctl, .unlocked_ioctl = wdt_ioctl,
.open = wdt_open, .open = wdt_open,
.release = wdt_release, .release = wdt_release,
}; };
static struct miscdevice wdt_miscdev= static struct miscdevice wdt_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &wdt_fops, .fops = &wdt_fops,
...@@ -474,20 +471,20 @@ static int __init w83977f_wdt_init(void) ...@@ -474,20 +471,20 @@ static int __init w83977f_wdt_init(void)
{ {
int rc; int rc;
printk(KERN_INFO PFX DRIVER_VERSION); printk(KERN_INFO PFX DRIVER_VERSION);
/* /*
* Check that the timeout value is within it's range ; * Check that the timeout value is within it's range;
* if not reset to the default * if not reset to the default
*/ */
if (wdt_set_timeout(timeout)) { if (wdt_set_timeout(timeout)) {
wdt_set_timeout(DEFAULT_TIMEOUT); wdt_set_timeout(DEFAULT_TIMEOUT);
printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n", printk(KERN_INFO PFX
DEFAULT_TIMEOUT); "timeout value must be 15 <= timeout <= 7635, using %d\n",
DEFAULT_TIMEOUT);
} }
if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
{
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
IO_INDEX_PORT); IO_INDEX_PORT);
rc = -EIO; rc = -EIO;
...@@ -495,30 +492,30 @@ static int __init w83977f_wdt_init(void) ...@@ -495,30 +492,30 @@ static int __init w83977f_wdt_init(void)
} }
rc = register_reboot_notifier(&wdt_notifier); rc = register_reboot_notifier(&wdt_notifier);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", "cannot register reboot notifier (err=%d)\n", rc);
rc);
goto err_out_region; goto err_out_region;
} }
rc = misc_register(&wdt_miscdev); rc = misc_register(&wdt_miscdev);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", "cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc); wdt_miscdev.minor, rc);
goto err_out_reboot; goto err_out_reboot;
} }
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", printk(KERN_INFO PFX
timeout, nowayout, testmode); "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
timeout, nowayout, testmode);
return 0; return 0;
err_out_reboot: err_out_reboot:
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
err_out_region: err_out_region:
release_region(IO_INDEX_PORT,2); release_region(IO_INDEX_PORT, 2);
err_out: err_out:
return rc; return rc;
} }
...@@ -528,7 +525,7 @@ static void __exit w83977f_wdt_exit(void) ...@@ -528,7 +525,7 @@ static void __exit w83977f_wdt_exit(void)
wdt_stop(); wdt_stop();
misc_deregister(&wdt_miscdev); misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
release_region(IO_INDEX_PORT,2); release_region(IO_INDEX_PORT, 2);
} }
module_init(w83977f_wdt_init); module_init(w83977f_wdt_init);
......
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#define WATCHDOG_NAME "Wafer 5823 WDT" #define WATCHDOG_NAME "Wafer 5823 WDT"
#define PFX WATCHDOG_NAME ": " #define PFX WATCHDOG_NAME ": "
...@@ -61,11 +61,15 @@ static int wdt_start = 0x443; ...@@ -61,11 +61,15 @@ static int wdt_start = 0x443;
static int timeout = WD_TIMO; /* in seconds */ static int timeout = WD_TIMO; /* in seconds */
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WD_TIMO) "."); MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. 1 <= timeout <= 255, default="
__MODULE_STRING(WD_TIMO) ".");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void wafwdt_ping(void) static void wafwdt_ping(void)
{ {
...@@ -90,7 +94,8 @@ wafwdt_stop(void) ...@@ -90,7 +94,8 @@ wafwdt_stop(void)
inb_p(wdt_stop); inb_p(wdt_stop);
} }
static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) static ssize_t wafwdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
/* See if we got the magic character 'V' and reload the timer */ /* See if we got the magic character 'V' and reload the timer */
if (count) { if (count) {
...@@ -100,7 +105,8 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co ...@@ -100,7 +105,8 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co
/* In case it was set long ago */ /* In case it was set long ago */
expect_close = 0; expect_close = 0;
/* scan to see whether or not we got the magic character */ /* scan to see whether or not we got the magic
character */
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))
...@@ -109,27 +115,29 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co ...@@ -109,27 +115,29 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co
expect_close = 42; expect_close = 42;
} }
} }
/* Well, anyhow someone wrote to us, we should return that favour */ /* Well, anyhow someone wrote to us, we should
return that favour */
wafwdt_ping(); wafwdt_ping();
} }
return count; return count;
} }
static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, static long wafwdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int new_timeout; int new_timeout;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int __user *p = argp; int __user *p = argp;
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1, .firmware_version = 1,
.identity = "Wafer 5823 WDT", .identity = "Wafer 5823 WDT",
}; };
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof (ident))) if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT; return -EFAULT;
break; break;
...@@ -194,10 +202,11 @@ static int wafwdt_open(struct inode *inode, struct file *file) ...@@ -194,10 +202,11 @@ static int wafwdt_open(struct inode *inode, struct file *file)
static int static int
wafwdt_close(struct inode *inode, struct file *file) wafwdt_close(struct inode *inode, struct file *file)
{ {
if (expect_close == 42) { if (expect_close == 42)
wafwdt_stop(); wafwdt_stop();
} else { else {
printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); printk(KERN_CRIT PFX
"WDT device closed unexpectedly. WDT will not stop!\n");
wafwdt_ping(); wafwdt_ping();
} }
clear_bit(0, &wafwdt_is_open); clear_bit(0, &wafwdt_is_open);
...@@ -209,12 +218,11 @@ wafwdt_close(struct inode *inode, struct file *file) ...@@ -209,12 +218,11 @@ wafwdt_close(struct inode *inode, struct file *file)
* Notifier for system down * Notifier for system down
*/ */
static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
{ {
if (code == SYS_DOWN || code == SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the WDT off */
wafwdt_stop(); wafwdt_stop();
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -226,7 +234,7 @@ static const struct file_operations wafwdt_fops = { ...@@ -226,7 +234,7 @@ static const struct file_operations wafwdt_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = wafwdt_write, .write = wafwdt_write,
.ioctl = wafwdt_ioctl, .unlocked_ioctl = wafwdt_ioctl,
.open = wafwdt_open, .open = wafwdt_open,
.release = wafwdt_close, .release = wafwdt_close,
}; };
...@@ -250,25 +258,28 @@ static int __init wafwdt_init(void) ...@@ -250,25 +258,28 @@ static int __init wafwdt_init(void)
{ {
int ret; int ret;
printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n"); printk(KERN_INFO
"WDT driver for Wafer 5823 single board computer initialising.\n");
if (timeout < 1 || timeout > 255) { if (timeout < 1 || timeout > 255) {
timeout = WD_TIMO; timeout = WD_TIMO;
printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n", printk(KERN_INFO PFX
timeout); "timeout value must be 1 <= x <= 255, using %d\n",
timeout);
} }
if (wdt_stop != wdt_start) { if (wdt_stop != wdt_start) {
if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) { if (!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX
wdt_stop); "I/O address 0x%04x already in use\n",
wdt_stop);
ret = -EIO; ret = -EIO;
goto error; goto error;
} }
} }
if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) { if (!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_start); wdt_start);
ret = -EIO; ret = -EIO;
goto error2; goto error2;
...@@ -276,19 +287,20 @@ static int __init wafwdt_init(void) ...@@ -276,19 +287,20 @@ static int __init wafwdt_init(void)
ret = register_reboot_notifier(&wafwdt_notifier); ret = register_reboot_notifier(&wafwdt_notifier);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", printk(KERN_ERR PFX
ret); "cannot register reboot notifier (err=%d)\n", ret);
goto error3; goto error3;
} }
ret = misc_register(&wafwdt_miscdev); ret = misc_register(&wafwdt_miscdev);
if (ret != 0) { if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", printk(KERN_ERR PFX
WATCHDOG_MINOR, ret); "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto error4; goto error4;
} }
printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout); timeout, nowayout);
return ret; return ret;
...@@ -307,7 +319,7 @@ static void __exit wafwdt_exit(void) ...@@ -307,7 +319,7 @@ static void __exit wafwdt_exit(void)
{ {
misc_deregister(&wafwdt_miscdev); misc_deregister(&wafwdt_miscdev);
unregister_reboot_notifier(&wafwdt_notifier); unregister_reboot_notifier(&wafwdt_notifier);
if(wdt_stop != wdt_start) if (wdt_stop != wdt_start)
release_region(wdt_stop, 1); release_region(wdt_stop, 1);
release_region(wdt_start, 1); release_region(wdt_start, 1);
} }
......
...@@ -35,9 +35,9 @@ ...@@ -35,9 +35,9 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <asm/rtas.h> #include <asm/rtas.h>
#include <asm/uaccess.h>
#define WDRTAS_MAGIC_CHAR 42 #define WDRTAS_MAGIC_CHAR 42
#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \ #define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \
...@@ -56,7 +56,7 @@ static int wdrtas_nowayout = 0; ...@@ -56,7 +56,7 @@ static int wdrtas_nowayout = 0;
#endif #endif
static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0); static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
static char wdrtas_expect_close = 0; static char wdrtas_expect_close;
static int wdrtas_interval; static int wdrtas_interval;
...@@ -86,8 +86,8 @@ static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN]; ...@@ -86,8 +86,8 @@ static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
* RTAS function set-indicator (surveillance). The unit of interval is * RTAS function set-indicator (surveillance). The unit of interval is
* seconds. * seconds.
*/ */
static int
wdrtas_set_interval(int interval) static int wdrtas_set_interval(int interval)
{ {
long result; long result;
static int print_msg = 10; static int print_msg = 10;
...@@ -97,7 +97,7 @@ wdrtas_set_interval(int interval) ...@@ -97,7 +97,7 @@ wdrtas_set_interval(int interval)
result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
WDRTAS_SURVEILLANCE_IND, 0, interval); WDRTAS_SURVEILLANCE_IND, 0, interval);
if ( (result < 0) && (print_msg) ) { if (result < 0 && print_msg) {
printk(KERN_ERR "wdrtas: setting the watchdog to %i " printk(KERN_ERR "wdrtas: setting the watchdog to %i "
"timeout failed: %li\n", interval, result); "timeout failed: %li\n", interval, result);
print_msg--; print_msg--;
...@@ -116,16 +116,14 @@ wdrtas_set_interval(int interval) ...@@ -116,16 +116,14 @@ wdrtas_set_interval(int interval)
* as reported by the RTAS function ibm,get-system-parameter. The unit * as reported by the RTAS function ibm,get-system-parameter. The unit
* of the return value is seconds. * of the return value is seconds.
*/ */
static int static int wdrtas_get_interval(int fallback_value)
wdrtas_get_interval(int fallback_value)
{ {
long result; long result;
char value[4]; char value[4];
result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL, result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
WDRTAS_SP_SPI, (void *)__pa(&value), 4); WDRTAS_SP_SPI, (void *)__pa(&value), 4);
if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) || if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
(result < 0) ) {
printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog " printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
"timeout (%li). Continuing\n", result); "timeout (%li). Continuing\n", result);
return fallback_value; return fallback_value;
...@@ -141,8 +139,7 @@ wdrtas_get_interval(int fallback_value) ...@@ -141,8 +139,7 @@ wdrtas_get_interval(int fallback_value)
* wdrtas_timer_start starts the watchdog by calling the RTAS function * wdrtas_timer_start starts the watchdog by calling the RTAS function
* set-interval (surveillance) * set-interval (surveillance)
*/ */
static void static void wdrtas_timer_start(void)
wdrtas_timer_start(void)
{ {
wdrtas_set_interval(wdrtas_interval); wdrtas_set_interval(wdrtas_interval);
} }
...@@ -153,8 +150,7 @@ wdrtas_timer_start(void) ...@@ -153,8 +150,7 @@ wdrtas_timer_start(void)
* wdrtas_timer_stop stops the watchdog timer by calling the RTAS function * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
* set-interval (surveillance) * set-interval (surveillance)
*/ */
static void static void wdrtas_timer_stop(void)
wdrtas_timer_stop(void)
{ {
wdrtas_set_interval(0); wdrtas_set_interval(0);
} }
...@@ -165,8 +161,7 @@ wdrtas_timer_stop(void) ...@@ -165,8 +161,7 @@ wdrtas_timer_stop(void)
* wdrtas_log_scanned_event prints a message to the log buffer dumping * wdrtas_log_scanned_event prints a message to the log buffer dumping
* the results of the last event-scan call * the results of the last event-scan call
*/ */
static void static void wdrtas_log_scanned_event(void)
wdrtas_log_scanned_event(void)
{ {
int i; int i;
...@@ -175,13 +170,13 @@ wdrtas_log_scanned_event(void) ...@@ -175,13 +170,13 @@ wdrtas_log_scanned_event(void)
"%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x\n", "%02x %02x %02x %02x %02x %02x %02x %02x\n",
(i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
} }
...@@ -192,8 +187,7 @@ wdrtas_log_scanned_event(void) ...@@ -192,8 +187,7 @@ wdrtas_log_scanned_event(void)
* RTAS function event-scan and repeats these calls as long as there are * RTAS function event-scan and repeats these calls as long as there are
* events available. All events will be dumped. * events available. All events will be dumped.
*/ */
static void static void wdrtas_timer_keepalive(void)
wdrtas_timer_keepalive(void)
{ {
long result; long result;
...@@ -218,8 +212,7 @@ wdrtas_timer_keepalive(void) ...@@ -218,8 +212,7 @@ wdrtas_timer_keepalive(void)
* wdrtas_get_temperature returns the current temperature in Fahrenheit. It * wdrtas_get_temperature returns the current temperature in Fahrenheit. It
* uses the RTAS call get-sensor-state, token 3 to do so * uses the RTAS call get-sensor-state, token 3 to do so
*/ */
static int static int wdrtas_get_temperature(void)
wdrtas_get_temperature(void)
{ {
long result; long result;
int temperature = 0; int temperature = 0;
...@@ -243,8 +236,7 @@ wdrtas_get_temperature(void) ...@@ -243,8 +236,7 @@ wdrtas_get_temperature(void)
* returns a bitmask of defines WDIOF_... as defined in * returns a bitmask of defines WDIOF_... as defined in
* include/linux/watchdog.h * include/linux/watchdog.h
*/ */
static int static int wdrtas_get_status(void)
wdrtas_get_status(void)
{ {
return 0; /* TODO */ return 0; /* TODO */
} }
...@@ -255,8 +247,7 @@ wdrtas_get_status(void) ...@@ -255,8 +247,7 @@ wdrtas_get_status(void)
* returns a bitmask of defines WDIOF_... as defined in * returns a bitmask of defines WDIOF_... as defined in
* include/linux/watchdog.h, indicating why the watchdog rebooted the system * include/linux/watchdog.h, indicating why the watchdog rebooted the system
*/ */
static int static int wdrtas_get_boot_status(void)
wdrtas_get_boot_status(void)
{ {
return 0; /* TODO */ return 0; /* TODO */
} }
...@@ -276,8 +267,7 @@ wdrtas_get_boot_status(void) ...@@ -276,8 +267,7 @@ wdrtas_get_boot_status(void)
* character 'V'. This character allows the watchdog device to be closed * character 'V'. This character allows the watchdog device to be closed
* properly. * properly.
*/ */
static ssize_t static ssize_t wdrtas_write(struct file *file, const char __user *buf,
wdrtas_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
int i; int i;
...@@ -306,7 +296,6 @@ wdrtas_write(struct file *file, const char __user *buf, ...@@ -306,7 +296,6 @@ wdrtas_write(struct file *file, const char __user *buf,
/** /**
* wdrtas_ioctl - ioctl function for the watchdog device * wdrtas_ioctl - ioctl function for the watchdog device
* @inode: inode structure
* @file: file structure * @file: file structure
* @cmd: command for ioctl * @cmd: command for ioctl
* @arg: argument pointer * @arg: argument pointer
...@@ -315,9 +304,9 @@ wdrtas_write(struct file *file, const char __user *buf, ...@@ -315,9 +304,9 @@ wdrtas_write(struct file *file, const char __user *buf,
* *
* wdrtas_ioctl implements the watchdog API ioctls * wdrtas_ioctl implements the watchdog API ioctls
*/ */
static int
wdrtas_ioctl(struct inode *inode, struct file *file, static long wdrtas_ioctl(struct file *file, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
int __user *argp = (void __user *)arg; int __user *argp = (void __user *)arg;
int i; int i;
...@@ -357,9 +346,9 @@ wdrtas_ioctl(struct inode *inode, struct file *file, ...@@ -357,9 +346,9 @@ wdrtas_ioctl(struct inode *inode, struct file *file,
wdrtas_timer_keepalive(); wdrtas_timer_keepalive();
wdrtas_timer_start(); wdrtas_timer_start();
} }
/* not implemented. Done by H8
if (i & WDIOS_TEMPPANIC) { if (i & WDIOS_TEMPPANIC) {
/* not implemented. Done by H8 */ } */
}
return 0; return 0;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
...@@ -399,8 +388,7 @@ wdrtas_ioctl(struct inode *inode, struct file *file, ...@@ -399,8 +388,7 @@ wdrtas_ioctl(struct inode *inode, struct file *file,
* *
* function called when watchdog device is opened * function called when watchdog device is opened
*/ */
static int static int wdrtas_open(struct inode *inode, struct file *file)
wdrtas_open(struct inode *inode, struct file *file)
{ {
/* only open once */ /* only open once */
if (atomic_inc_return(&wdrtas_miscdev_open) > 1) { if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
...@@ -423,8 +411,7 @@ wdrtas_open(struct inode *inode, struct file *file) ...@@ -423,8 +411,7 @@ wdrtas_open(struct inode *inode, struct file *file)
* *
* close function. Always succeeds * close function. Always succeeds
*/ */
static int static int wdrtas_close(struct inode *inode, struct file *file)
wdrtas_close(struct inode *inode, struct file *file)
{ {
/* only stop watchdog, if this was announced using 'V' before */ /* only stop watchdog, if this was announced using 'V' before */
if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR) if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
...@@ -453,8 +440,7 @@ wdrtas_close(struct inode *inode, struct file *file) ...@@ -453,8 +440,7 @@ wdrtas_close(struct inode *inode, struct file *file)
* wdrtas_temp_read gives the temperature to the users by copying this * wdrtas_temp_read gives the temperature to the users by copying this
* value as one byte into the user space buffer. The unit is Fahrenheit... * value as one byte into the user space buffer. The unit is Fahrenheit...
*/ */
static ssize_t static ssize_t wdrtas_temp_read(struct file *file, char __user *buf,
wdrtas_temp_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
int temperature = 0; int temperature = 0;
...@@ -478,8 +464,7 @@ wdrtas_temp_read(struct file *file, char __user *buf, ...@@ -478,8 +464,7 @@ wdrtas_temp_read(struct file *file, char __user *buf,
* *
* function called when temperature device is opened * function called when temperature device is opened
*/ */
static int static int wdrtas_temp_open(struct inode *inode, struct file *file)
wdrtas_temp_open(struct inode *inode, struct file *file)
{ {
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -493,8 +478,7 @@ wdrtas_temp_open(struct inode *inode, struct file *file) ...@@ -493,8 +478,7 @@ wdrtas_temp_open(struct inode *inode, struct file *file)
* *
* close function. Always succeeds * close function. Always succeeds
*/ */
static int static int wdrtas_temp_close(struct inode *inode, struct file *file)
wdrtas_temp_close(struct inode *inode, struct file *file)
{ {
return 0; return 0;
} }
...@@ -509,10 +493,10 @@ wdrtas_temp_close(struct inode *inode, struct file *file) ...@@ -509,10 +493,10 @@ wdrtas_temp_close(struct inode *inode, struct file *file)
* *
* wdrtas_reboot stops the watchdog in case of a reboot * wdrtas_reboot stops the watchdog in case of a reboot
*/ */
static int static int wdrtas_reboot(struct notifier_block *this,
wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr) unsigned long code, void *ptr)
{ {
if ( (code==SYS_DOWN) || (code==SYS_HALT) ) if (code == SYS_DOWN || code == SYS_HALT)
wdrtas_timer_stop(); wdrtas_timer_stop();
return NOTIFY_DONE; return NOTIFY_DONE;
...@@ -524,7 +508,7 @@ static const struct file_operations wdrtas_fops = { ...@@ -524,7 +508,7 @@ static const struct file_operations wdrtas_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = wdrtas_write, .write = wdrtas_write,
.ioctl = wdrtas_ioctl, .unlocked_ioctl = wdrtas_ioctl,
.open = wdrtas_open, .open = wdrtas_open,
.release = wdrtas_close, .release = wdrtas_close,
}; };
...@@ -562,8 +546,7 @@ static struct notifier_block wdrtas_notifier = { ...@@ -562,8 +546,7 @@ static struct notifier_block wdrtas_notifier = {
* this watchdog driver. It tolerates, if "get-sensor-state" and * this watchdog driver. It tolerates, if "get-sensor-state" and
* "ibm,get-system-parameter" are not available. * "ibm,get-system-parameter" are not available.
*/ */
static int static int wdrtas_get_tokens(void)
wdrtas_get_tokens(void)
{ {
wdrtas_token_get_sensor_state = rtas_token("get-sensor-state"); wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) { if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
...@@ -603,8 +586,7 @@ wdrtas_get_tokens(void) ...@@ -603,8 +586,7 @@ wdrtas_get_tokens(void)
* wdrtas_register_devs unregisters the watchdog and temperature watchdog * wdrtas_register_devs unregisters the watchdog and temperature watchdog
* misc devs * misc devs
*/ */
static void static void wdrtas_unregister_devs(void)
wdrtas_unregister_devs(void)
{ {
misc_deregister(&wdrtas_miscdev); misc_deregister(&wdrtas_miscdev);
if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
...@@ -619,8 +601,7 @@ wdrtas_unregister_devs(void) ...@@ -619,8 +601,7 @@ wdrtas_unregister_devs(void)
* wdrtas_register_devs registers the watchdog and temperature watchdog * wdrtas_register_devs registers the watchdog and temperature watchdog
* misc devs * misc devs
*/ */
static int static int wdrtas_register_devs(void)
wdrtas_register_devs(void)
{ {
int result; int result;
...@@ -651,8 +632,7 @@ wdrtas_register_devs(void) ...@@ -651,8 +632,7 @@ wdrtas_register_devs(void)
* *
* registers the file handlers and the reboot notifier * registers the file handlers and the reboot notifier
*/ */
static int __init static int __init wdrtas_init(void)
wdrtas_init(void)
{ {
if (wdrtas_get_tokens()) if (wdrtas_get_tokens())
return -ENODEV; return -ENODEV;
...@@ -680,8 +660,7 @@ wdrtas_init(void) ...@@ -680,8 +660,7 @@ wdrtas_init(void)
* *
* unregisters the file handlers and the reboot notifier * unregisters the file handlers and the reboot notifier
*/ */
static void __exit static void __exit wdrtas_exit(void)
wdrtas_exit(void)
{ {
if (!wdrtas_nowayout) if (!wdrtas_nowayout)
wdrtas_timer_stop(); wdrtas_timer_stop();
......
...@@ -26,9 +26,9 @@ ...@@ -26,9 +26,9 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/hardware/dec21285.h> #include <asm/hardware/dec21285.h>
...@@ -115,8 +115,8 @@ static int watchdog_release(struct inode *inode, struct file *file) ...@@ -115,8 +115,8 @@ static int watchdog_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static ssize_t static ssize_t watchdog_write(struct file *file, const char *data,
watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
/* /*
* Refresh the timer. * Refresh the timer.
...@@ -127,19 +127,18 @@ watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) ...@@ -127,19 +127,18 @@ watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
return len; return len;
} }
static struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT, .options = WDIOF_SETTIMEOUT,
.identity = "Footbridge Watchdog", .identity = "Footbridge Watchdog",
}; };
static int static long watchdog_ioctl(struct file *file, unsigned int cmd,
watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
unsigned int new_margin; unsigned int new_margin;
int ret = -ENOTTY; int ret = -ENOTTY;
switch(cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
ret = 0; ret = 0;
if (copy_to_user((void *)arg, &ident, sizeof(ident))) if (copy_to_user((void *)arg, &ident, sizeof(ident)))
...@@ -148,7 +147,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -148,7 +147,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
ret = put_user(0,(int *)arg); ret = put_user(0, (int *)arg);
break; break;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
...@@ -182,7 +181,7 @@ static const struct file_operations watchdog_fops = { ...@@ -182,7 +181,7 @@ static const struct file_operations watchdog_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = watchdog_write, .write = watchdog_write,
.ioctl = watchdog_ioctl, .unlocked_ioctl = watchdog_ioctl,
.open = watchdog_open, .open = watchdog_open,
.release = watchdog_release, .release = watchdog_release,
}; };
...@@ -204,11 +203,13 @@ static int __init footbridge_watchdog_init(void) ...@@ -204,11 +203,13 @@ static int __init footbridge_watchdog_init(void)
if (retval < 0) if (retval < 0)
return retval; return retval;
printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", printk(KERN_INFO
soft_margin); "Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
soft_margin);
if (machine_is_cats()) if (machine_is_cats())
printk("Warning: Watchdog reset may not work on this machine.\n"); printk(KERN_WARN
"Warning: Watchdog reset may not work on this machine.\n");
return 0; return 0;
} }
...@@ -223,7 +224,7 @@ MODULE_LICENSE("GPL"); ...@@ -223,7 +224,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
module_param(soft_margin, int, 0); module_param(soft_margin, int, 0);
MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds"); MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
module_init(footbridge_watchdog_init); module_init(footbridge_watchdog_init);
module_exit(footbridge_watchdog_exit); module_exit(footbridge_watchdog_exit);
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
* 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
* nwwatchdog_init. * nwwatchdog_init.
* 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks
* remove limitiation to be used on Netwinders only * remove limitiation to be used on
* Netwinders only
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -33,11 +34,11 @@ ...@@ -33,11 +34,11 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/uaccess.h>
#define WATCHDOG_VERSION "0.04" #define WATCHDOG_VERSION "0.04"
#define WATCHDOG_NAME "Wdt977" #define WATCHDOG_NAME "Wdt977"
...@@ -45,7 +46,7 @@ ...@@ -45,7 +46,7 @@
#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
#define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */ #define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */
#define IO_DATA_PORT (IO_INDEX_PORT+1) #define IO_DATA_PORT (IO_INDEX_PORT + 1)
#define UNLOCK_DATA 0x87 #define UNLOCK_DATA 0x87
#define LOCK_DATA 0xAA #define LOCK_DATA 0xAA
...@@ -62,13 +63,16 @@ static char expect_close; ...@@ -62,13 +63,16 @@ static char expect_close;
static DEFINE_SPINLOCK(spinlock); static DEFINE_SPINLOCK(spinlock);
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300), default="
__MODULE_STRING(DEFAULT_TIMEOUT) ")");
module_param(testmode, int, 0); module_param(testmode, int, 0);
MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* /*
* Start the watchdog * Start the watchdog
...@@ -95,14 +99,16 @@ static int wdt977_start(void) ...@@ -95,14 +99,16 @@ static int wdt977_start(void)
outb_p(0xF2, IO_INDEX_PORT); outb_p(0xF2, IO_INDEX_PORT);
outb_p(timeoutM, IO_DATA_PORT); outb_p(timeoutM, IO_DATA_PORT);
outb_p(0xF3, IO_INDEX_PORT); outb_p(0xF3, IO_INDEX_PORT);
outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */ outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for
kbd/mouse/LED */
outb_p(0xF4, IO_INDEX_PORT); outb_p(0xF4, IO_INDEX_PORT);
outb_p(0x00, IO_DATA_PORT); outb_p(0x00, IO_DATA_PORT);
/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ /* At last select device Aux1 (dev=7) and set GP16 as a
/* in test mode watch the bit 1 on F4 to indicate "triggered" */ * watchdog output. In test mode watch the bit 1 on F4 to
if (!testmode) * indicate "triggered"
{ */
if (!testmode) {
outb_p(DEVICE_REGISTER, IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x07, IO_DATA_PORT); outb_p(0x07, IO_DATA_PORT);
outb_p(0xE6, IO_INDEX_PORT); outb_p(0xE6, IO_INDEX_PORT);
...@@ -147,7 +153,8 @@ static int wdt977_stop(void) ...@@ -147,7 +153,8 @@ static int wdt977_stop(void)
outb_p(0xF2, IO_INDEX_PORT); outb_p(0xF2, IO_INDEX_PORT);
outb_p(0x00, IO_DATA_PORT); outb_p(0x00, IO_DATA_PORT);
/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ /* at last select device Aux1 (dev=7) and set
GP16 as a watchdog output */
outb_p(DEVICE_REGISTER, IO_INDEX_PORT); outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x07, IO_DATA_PORT); outb_p(0x07, IO_DATA_PORT);
outb_p(0xE6, IO_INDEX_PORT); outb_p(0xE6, IO_INDEX_PORT);
...@@ -202,16 +209,18 @@ static int wdt977_set_timeout(int t) ...@@ -202,16 +209,18 @@ static int wdt977_set_timeout(int t)
tmrval = (t + 59) / 60; tmrval = (t + 59) / 60;
if (machine_is_netwinder()) { if (machine_is_netwinder()) {
/* we have a hw bug somewhere, so each 977 minute is actually only 30sec /* we have a hw bug somewhere, so each 977 minute is actually
* this limits the max timeout to half of device max of 255 minutes... * only 30sec. This limits the max timeout to half of device
* max of 255 minutes...
*/ */
tmrval += tmrval; tmrval += tmrval;
} }
if ((tmrval < 1) || (tmrval > 255)) if (tmrval < 1 || tmrval > 255)
return -EINVAL; return -EINVAL;
/* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */ /* timeout is the timeout in seconds, timeoutM is
the timeout in minutes) */
timeout = t; timeout = t;
timeoutM = tmrval; timeoutM = tmrval;
return 0; return 0;
...@@ -243,7 +252,7 @@ static int wdt977_get_status(int *status) ...@@ -243,7 +252,7 @@ static int wdt977_get_status(int *status)
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
*status=0; *status = 0;
if (new_status & 1) if (new_status & 1)
*status |= WDIOF_CARDRESET; *status |= WDIOF_CARDRESET;
...@@ -258,7 +267,7 @@ static int wdt977_get_status(int *status) ...@@ -258,7 +267,7 @@ static int wdt977_get_status(int *status)
static int wdt977_open(struct inode *inode, struct file *file) static int wdt977_open(struct inode *inode, struct file *file)
{ {
/* If the watchdog is alive we don't need to start it again */ /* If the watchdog is alive we don't need to start it again */
if( test_and_set_bit(0,&timer_alive) ) if (test_and_set_bit(0, &timer_alive))
return -EBUSY; return -EBUSY;
if (nowayout) if (nowayout)
...@@ -274,13 +283,13 @@ static int wdt977_release(struct inode *inode, struct file *file) ...@@ -274,13 +283,13 @@ static int wdt977_release(struct inode *inode, struct file *file)
* Shut off the timer. * Shut off the timer.
* Lock it in if it's a module and we set nowayout * Lock it in if it's a module and we set nowayout
*/ */
if (expect_close == 42) if (expect_close == 42) {
{
wdt977_stop(); wdt977_stop();
clear_bit(0,&timer_alive); clear_bit(0, &timer_alive);
} else { } else {
wdt977_keepalive(); wdt977_keepalive();
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
} }
expect_close = 0; expect_close = 0;
return 0; return 0;
...@@ -301,17 +310,14 @@ static int wdt977_release(struct inode *inode, struct file *file) ...@@ -301,17 +310,14 @@ static int wdt977_release(struct inode *inode, struct file *file)
static ssize_t wdt977_write(struct file *file, const char __user *buf, static ssize_t wdt977_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
if (count) if (count) {
{ if (!nowayout) {
if (!nowayout)
{
size_t i; size_t i;
/* In case it was set long ago */ /* In case it was set long ago */
expect_close = 0; 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))
return -EFAULT; return -EFAULT;
...@@ -326,6 +332,14 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, ...@@ -326,6 +332,14 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf,
return count; return count;
} }
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
};
/* /*
* wdt977_ioctl: * wdt977_ioctl:
* @inode: inode of the device * @inode: inode of the device
...@@ -337,16 +351,8 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, ...@@ -337,16 +351,8 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf,
* according to their available features. * according to their available features.
*/ */
static struct watchdog_info ident = { static long wdt977_ioctl(struct file *file, unsigned int cmd,
.options = WDIOF_SETTIMEOUT | unsigned long arg)
WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
};
static int wdt977_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{ {
int status; int status;
int new_options, retval = -EINVAL; int new_options, retval = -EINVAL;
...@@ -358,8 +364,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, ...@@ -358,8 +364,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
uarg.i = (int __user *)arg; uarg.i = (int __user *)arg;
switch(cmd) switch (cmd) {
{
default: default:
return -ENOTTY; return -ENOTTY;
...@@ -379,7 +384,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, ...@@ -379,7 +384,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
return 0; return 0;
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
if (get_user (new_options, uarg.i)) if (get_user(new_options, uarg.i))
return -EFAULT; return -EFAULT;
if (new_options & WDIOS_DISABLECARD) { if (new_options & WDIOS_DISABLECARD) {
...@@ -413,23 +418,21 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, ...@@ -413,23 +418,21 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
static int wdt977_notify_sys(struct notifier_block *this, unsigned long code, static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if(code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
wdt977_stop(); wdt977_stop();
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static const struct file_operations wdt977_fops= static const struct file_operations wdt977_fops = {
{
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.write = wdt977_write, .write = wdt977_write,
.ioctl = wdt977_ioctl, .unlocked_ioctl = wdt977_ioctl,
.open = wdt977_open, .open = wdt977_open,
.release = wdt977_release, .release = wdt977_release,
}; };
static struct miscdevice wdt977_miscdev= static struct miscdevice wdt977_miscdev = {
{
.minor = WATCHDOG_MINOR, .minor = WATCHDOG_MINOR,
.name = "watchdog", .name = "watchdog",
.fops = &wdt977_fops, .fops = &wdt977_fops,
...@@ -443,51 +446,48 @@ static int __init wd977_init(void) ...@@ -443,51 +446,48 @@ static int __init wd977_init(void)
{ {
int rc; int rc;
//if (!machine_is_netwinder())
// return -ENODEV;
printk(KERN_INFO PFX DRIVER_VERSION); printk(KERN_INFO PFX DRIVER_VERSION);
/* Check that the timeout value is within it's range ; if not reset to the default */ /* Check that the timeout value is within its range;
if (wdt977_set_timeout(timeout)) if not reset to the default */
{ if (wdt977_set_timeout(timeout)) {
wdt977_set_timeout(DEFAULT_TIMEOUT); wdt977_set_timeout(DEFAULT_TIMEOUT);
printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n", printk(KERN_INFO PFX
DEFAULT_TIMEOUT); "timeout value must be 60 < timeout < 15300, using %d\n",
DEFAULT_TIMEOUT);
} }
/* on Netwinder the IOports are already reserved by /* on Netwinder the IOports are already reserved by
* arch/arm/mach-footbridge/netwinder-hw.c * arch/arm/mach-footbridge/netwinder-hw.c
*/ */
if (!machine_is_netwinder()) if (!machine_is_netwinder()) {
{ if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) printk(KERN_ERR PFX
{ "I/O address 0x%04x already in use\n",
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", IO_INDEX_PORT);
IO_INDEX_PORT);
rc = -EIO; rc = -EIO;
goto err_out; goto err_out;
} }
} }
rc = register_reboot_notifier(&wdt977_notifier); rc = register_reboot_notifier(&wdt977_notifier);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", "cannot register reboot notifier (err=%d)\n", rc);
rc);
goto err_out_region; goto err_out_region;
} }
rc = misc_register(&wdt977_miscdev); rc = misc_register(&wdt977_miscdev);
if (rc) if (rc) {
{ printk(KERN_ERR PFX
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", "cannot register miscdev on minor=%d (err=%d)\n",
wdt977_miscdev.minor, rc); wdt977_miscdev.minor, rc);
goto err_out_reboot; goto err_out_reboot;
} }
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", printk(KERN_INFO PFX
timeout, nowayout, testmode); "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
timeout, nowayout, testmode);
return 0; return 0;
...@@ -495,7 +495,7 @@ static int __init wd977_init(void) ...@@ -495,7 +495,7 @@ static int __init wd977_init(void)
unregister_reboot_notifier(&wdt977_notifier); unregister_reboot_notifier(&wdt977_notifier);
err_out_region: err_out_region:
if (!machine_is_netwinder()) if (!machine_is_netwinder())
release_region(IO_INDEX_PORT,2); release_region(IO_INDEX_PORT, 2);
err_out: err_out:
return rc; return rc;
} }
...@@ -505,7 +505,7 @@ static void __exit wd977_exit(void) ...@@ -505,7 +505,7 @@ static void __exit wd977_exit(void)
wdt977_stop(); wdt977_stop();
misc_deregister(&wdt977_miscdev); misc_deregister(&wdt977_miscdev);
unregister_reboot_notifier(&wdt977_notifier); unregister_reboot_notifier(&wdt977_notifier);
release_region(IO_INDEX_PORT,2); release_region(IO_INDEX_PORT, 2);
} }
module_init(wd977_init); module_init(wd977_init);
......
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