Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: (70 commits)
  [WATCHDOG] more coding style clean-up's
  [WATCHDOG] sbc8360.c - move stop code into a function
  [WATCHDOG] Coding style - Indentation - part 2
  [WATCHDOG] Coding style - Indentation - part 1
  [WATCHDOG] mpc8xxx_wdt: add support for MPC8xx watchdogs
  [WATCHDOG] mpc8xxx_wdt: fix build
  [WATCHDOG] mpc8xxx_wdt: various renames, mostly s/mpc83xx/mpc8xxx/g
  [WATCHDOG] mpc83xx_wdt: rename to mpc8xxx_wdt
  [WATCHDOG] mpc83xx_wdt: add support for MPC86xx CPUs
  [WATCHDOG] mpc83xx_wdt: convert to the OF platform driver
  [WATCHDOG] pcwd: a couple of watchdogs escaped conversion
  [WATCHDOG] Clean-up includes
  [WATCHDOG] hpwdt.c - fix double includes
  [WATCHDOG 57/57] wdt501/pci: Clean up, coding style and switch to unlocked_ioctl
  [WATCHDOG 56/57] wdt977: clean up, coding style and switch to unlocked_ioctl
  [WATCHDOG 55/57] wdt285: switch to unlocked_ioctl and tidy up oddments of coding style
  [WATCHDOG 54/57] wdrtas: clean up, coding style, switch to unlocked_ioctl
  [WATCHDOG 53/57] wafer5823wdt: Clean up, coding style, switch to unlocked_ioctl
  [WATCHDOG 52/57] w83977f_wdt: clean up, coding style and switch to unlocked_ioctl
  [WATCHDOG 51/57] w83877f_wdt: clean up code, coding style, switch to unlocked_ioctl
  ...
This commit is contained in:
Linus Torvalds 2008-08-07 18:05:09 -07:00
commit b588e2bbd7
70 changed files with 3844 additions and 3753 deletions

View file

@ -463,7 +463,7 @@ config PC87413_WDT
module will be called pc87413_wdt.
Most people will say N.
config 60XX_WDT
tristate "SBC-60XX Watchdog Timer"
depends on X86
@ -695,9 +695,17 @@ config 8xx_WDT
tristate "MPC8xx Watchdog Timer"
depends on 8xx
config 83xx_WDT
tristate "MPC83xx Watchdog Timer"
depends on PPC_83xx
config 8xxx_WDT
tristate "MPC8xxx Platform Watchdog Timer"
depends on PPC_8xx || PPC_83xx || PPC_86xx
help
This driver is for a SoC level watchdog that exists on some
Freescale PowerPC processors. So far this driver supports:
- MPC8xx watchdogs
- MPC83xx watchdogs
- MPC86xx watchdogs
For BookE processors (MPC85xx) use the BOOKE_WDT driver instead.
config MV64X60_WDT
tristate "MV64X60 (Marvell Discovery) Watchdog Timer"

View file

@ -92,7 +92,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
# MIPS Architecture
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
@ -103,7 +103,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
# POWERPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o

View file

@ -58,39 +58,45 @@
#include <linux/types.h> /* For standard types (like size_t) */
#include <linux/errno.h> /* For the -ENODEV/... values */
#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/fs.h> /* For file operations */
#include <linux/ioport.h> /* For io-port access */
#include <linux/platform_device.h> /* For platform_driver framework */
#include <linux/init.h> /* For __init/__exit/... */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/io.h> /* For inb/outb/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <linux/io.h> /* For inb/outb/... */
/* Module information */
#define DRV_NAME "acquirewdt"
#define PFX DRV_NAME ": "
#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 */
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 char expect_close;
/* 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_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_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
static int nowayout = WATCHDOG_NOWAYOUT;
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
@ -112,18 +118,18 @@ static void acq_stop(void)
* /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 */
if(count) {
if (count) {
if (!nowayout) {
size_t i;
/* note: just in case someone wrote the magic character
* five months ago... */
five months ago... */
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++) {
char c;
if (get_user(c, buf + i))
@ -132,64 +138,55 @@ static ssize_t acq_write(struct file *file, const char __user *buf, size_t count
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 */
acq_keepalive();
}
return count;
}
static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long acq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int options, retval = -EINVAL;
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident =
{
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
};
switch(cmd)
{
switch (cmd) {
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_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
acq_keepalive();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_HEARTBEAT, p);
return put_user(0, p);
case WDIOC_SETOPTIONS:
{
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD)
{
acq_stop();
retval = 0;
}
if (options & WDIOS_ENABLECARD)
{
acq_keepalive();
retval = 0;
}
return retval;
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
acq_stop();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
acq_keepalive();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
acq_keepalive();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_HEARTBEAT, p);
default:
return -ENOTTY;
return -ENOTTY;
}
}
@ -211,7 +208,8 @@ static int acq_close(struct inode *inode, struct file *file)
if (expect_close == 42) {
acq_stop();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
acq_keepalive();
}
clear_bit(0, &acq_is_open);
@ -227,7 +225,7 @@ static const struct file_operations acq_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = acq_write,
.ioctl = acq_ioctl,
.unlocked_ioctl = acq_ioctl,
.open = acq_open,
.release = acq_close,
};
@ -248,32 +246,29 @@ static int __devinit acq_probe(struct platform_device *dev)
if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_stop);
printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n", wdt_stop);
ret = -EIO;
goto out;
}
}
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);
ret = -EIO;
goto unreg_stop;
}
ret = misc_register(&acq_miscdev);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_regions;
}
printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
nowayout);
printk(KERN_INFO PFX "initialized. (nowayout=%d)\n", nowayout);
return 0;
unreg_regions:
release_region(wdt_start, 1);
unreg_stop:
@ -286,9 +281,9 @@ static int __devinit acq_probe(struct platform_device *dev)
static int __devexit acq_remove(struct platform_device *dev)
{
misc_deregister(&acq_miscdev);
release_region(wdt_start,1);
if(wdt_stop != wdt_start)
release_region(wdt_stop,1);
release_region(wdt_start, 1);
if (wdt_stop != wdt_start)
release_region(wdt_stop, 1);
return 0;
}
@ -313,18 +308,19 @@ static int __init acq_init(void)
{
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);
if (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)) {
err = PTR_ERR(acq_platform_device);
goto unreg_platform_driver;
}
return 0;
unreg_platform_driver:

View file

@ -37,9 +37,9 @@
#include <linux/ioport.h>
#include <linux/platform_device.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>
#define DRV_NAME "advantechwdt"
@ -47,7 +47,8 @@
#define WATCHDOG_NAME "Advantech WDT"
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
static struct platform_device *advwdt_platform_device; /* the watchdog platform device */
/* the watchdog platform device */
static struct platform_device *advwdt_platform_device;
static unsigned long advwdt_is_open;
static char adv_expect_close;
@ -72,35 +73,35 @@ MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
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;
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
*/
static void
advwdt_ping(void)
static void advwdt_ping(void)
{
/* Write a watchdog value */
outb_p(timeout, wdt_start);
}
static void
advwdt_disable(void)
static void advwdt_disable(void)
{
inb_p(wdt_stop);
}
static int
advwdt_set_heartbeat(int t)
static int advwdt_set_heartbeat(int t)
{
if ((t < 1) || (t > 63))
if (t < 1 || t > 63)
return -EINVAL;
timeout = t;
return 0;
}
@ -109,8 +110,8 @@ advwdt_set_heartbeat(int t)
* /dev/watchdog handling
*/
static ssize_t
advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
static ssize_t advwdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count) {
if (!nowayout) {
@ -120,7 +121,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp
for (i = 0; i != count; i++) {
char c;
if (get_user(c, buf+i))
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V')
adv_expect_close = 42;
@ -131,9 +132,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp
return count;
}
static int
advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int new_timeout;
void __user *argp = (void __user *)arg;
@ -146,57 +145,50 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
advwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (advwdt_set_heartbeat(new_timeout))
return -EINVAL;
advwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
return put_user(0, p);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
int options, retval = -EINVAL;
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
advwdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
advwdt_ping();
retval = 0;
}
return retval;
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
advwdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
advwdt_ping();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
advwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (advwdt_set_heartbeat(new_timeout))
return -EINVAL;
advwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
return -ENOTTY;
}
return 0;
}
static int
advwdt_open(struct inode *inode, struct file *file)
static int advwdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(0, &advwdt_is_open))
return -EBUSY;
@ -208,13 +200,13 @@ advwdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static int
advwdt_close(struct inode *inode, struct file *file)
static int advwdt_close(struct inode *inode, struct file *file)
{
if (adv_expect_close == 42) {
advwdt_disable();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
advwdt_ping();
}
clear_bit(0, &advwdt_is_open);
@ -230,7 +222,7 @@ static const struct file_operations advwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = advwdt_write,
.ioctl = advwdt_ioctl,
.unlocked_ioctl = advwdt_ioctl,
.open = advwdt_open,
.release = advwdt_close,
};
@ -245,23 +237,24 @@ static struct miscdevice advwdt_miscdev = {
* Init & exit routines
*/
static int __devinit
advwdt_probe(struct platform_device *dev)
static int __devinit advwdt_probe(struct platform_device *dev)
{
int ret;
if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_stop);
printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n",
wdt_stop);
ret = -EIO;
goto out;
}
}
if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_start);
printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n",
wdt_start);
ret = -EIO;
goto unreg_stop;
}
@ -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 */
if (advwdt_set_heartbeat(timeout)) {
advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
timeout);
printk(KERN_INFO PFX
"timeout value must be 1<=x<=63, using %d\n", timeout);
}
ret = misc_register(&advwdt_miscdev);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
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);
out:
return ret;
unreg_regions:
@ -293,19 +285,17 @@ advwdt_probe(struct platform_device *dev)
goto out;
}
static int __devexit
advwdt_remove(struct platform_device *dev)
static int __devexit advwdt_remove(struct platform_device *dev)
{
misc_deregister(&advwdt_miscdev);
release_region(wdt_start,1);
if(wdt_stop != wdt_start)
release_region(wdt_stop,1);
release_region(wdt_start, 1);
if (wdt_stop != wdt_start)
release_region(wdt_stop, 1);
return 0;
}
static void
advwdt_shutdown(struct platform_device *dev)
static void advwdt_shutdown(struct platform_device *dev)
{
/* Turn the WDT off if we have a soft shutdown */
advwdt_disable();
@ -321,18 +311,19 @@ static struct platform_driver advwdt_driver = {
},
};
static int __init
advwdt_init(void)
static int __init advwdt_init(void)
{
int err;
printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
printk(KERN_INFO
"WDT driver for Advantech single board computer initialising.\n");
err = platform_driver_register(&advwdt_driver);
if (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)) {
err = PTR_ERR(advwdt_platform_device);
goto unreg_platform_driver;
@ -345,8 +336,7 @@ advwdt_init(void)
return err;
}
static void __exit
advwdt_exit(void)
static void __exit advwdt_exit(void)
{
platform_device_unregister(advwdt_platform_device);
platform_driver_unregister(&advwdt_driver);

View file

@ -18,9 +18,8 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define WATCHDOG_NAME "ALi_M1535"
#define PFX WATCHDOG_NAME ": "
@ -30,17 +29,21 @@
static unsigned long ali_is_open;
static char ali_expect_release;
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 */
/* module parameters */
static int timeout = WATCHDOG_TIMEOUT;
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;
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
@ -103,15 +106,16 @@ static void ali_keepalive(void)
static int ali_settimer(int t)
{
if(t < 0)
if (t < 0)
return -EINVAL;
else if(t < 60)
else if (t < 60)
ali_timeout_bits = t|(1<<6);
else if(t < 3600)
else if (t < 3600)
ali_timeout_bits = (t/60)|(1<<7);
else if(t < 18000)
else if (t < 18000)
ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
else return -EINVAL;
else
return -EINVAL;
timeout = t;
return 0;
@ -134,21 +138,22 @@ static int ali_settimer(int t)
*/
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 */
if (len) {
if (!nowayout) {
size_t i;
/* note: just in case someone wrote the magic character
* five months ago... */
/* note: just in case someone wrote the
magic character five months ago... */
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++) {
char c;
if(get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
ali_expect_release = 42;
@ -163,7 +168,6 @@ static ssize_t ali_write(struct file *file, const char __user *data,
/*
* ali_ioctl - handle watchdog ioctls
* @inode: VFS inode
* @file: VFS file pointer
* @cmd: ioctl number
* @arg: arguments to the ioctl
@ -172,8 +176,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
*/
static int ali_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@ -186,57 +189,45 @@ static int ali_ioctl(struct inode *inode, struct file *file,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof (ident)) ? -EFAULT : 0;
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_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
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;
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
ali_stop();
retval = 0;
}
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
if (ali_settimer(new_timeout))
return -EINVAL;
ali_keepalive();
/* Fall */
if (new_options & WDIOS_ENABLECARD) {
ali_start();
retval = 0;
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
return retval;
}
case WDIOC_KEEPALIVE:
ali_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
{
int new_timeout;
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 +265,11 @@ static int ali_release(struct inode *inode, struct file *file)
/*
* Shut off the timer.
*/
if (ali_expect_release == 42) {
if (ali_expect_release == 42)
ali_stop();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
else {
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
ali_keepalive();
}
clear_bit(0, &ali_is_open);
@ -292,13 +284,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) {
/* Turn the WDT off */
ali_stop();
}
if (code == SYS_DOWN || code == SYS_HALT)
ali_stop(); /* Turn the WDT off */
return NOTIFY_DONE;
}
@ -340,10 +330,10 @@ static int __init ali_find_watchdog(void)
/* Check for the a 7101 PMU */
pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
if(pdev == NULL)
if (pdev == NULL)
return -ENODEV;
if(pci_enable_device(pdev)) {
if (pci_enable_device(pdev)) {
pci_dev_put(pdev);
return -EIO;
}
@ -355,9 +345,12 @@ static int __init ali_find_watchdog(void)
*/
pci_read_config_dword(pdev, 0xCC, &wdog);
wdog &= ~0x3F; /* Timer bits */
wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); /* Issued events */
wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); /* No monitor bits */
/* Timer bits */
wdog &= ~0x3F;
/* 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);
@ -369,12 +362,12 @@ static int __init ali_find_watchdog(void)
*/
static const struct file_operations ali_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ali_write,
.ioctl = ali_ioctl,
.open = ali_open,
.release = ali_release,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ali_write,
.unlocked_ioctl = ali_ioctl,
.open = ali_open,
.release = ali_release,
};
static struct miscdevice ali_miscdev = {
@ -399,15 +392,16 @@ static int __init watchdog_init(void)
int ret;
/* Check whether or not the hardware watchdog is there */
if (ali_find_watchdog() != 0) {
if (ali_find_watchdog() != 0)
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) {
timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 0<timeout<18000, using %d\n",
timeout);
printk(KERN_INFO PFX
"timeout value must be 0 < timeout < 18000, using %d\n",
timeout);
}
/* Calculate the watchdog's timeout */
@ -415,15 +409,16 @@ static int __init watchdog_init(void)
ret = register_reboot_notifier(&ali_notifier);
if (ret != 0) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
goto out;
}
ret = misc_register(&ali_miscdev);
if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_reboot;
}

View file

@ -31,9 +31,9 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#define OUR_NAME "alim7101_wdt"
@ -60,13 +60,17 @@
*/
#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_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_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 DEFINE_TIMER(timer, wdt_timer_ping, 0, 1);
@ -77,8 +81,9 @@ static struct pci_dev *alim7101_pmu;
static int nowayout = WATCHDOG_NOWAYOUT;
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) ")");
/*
* Whack the dog
@ -89,23 +94,26 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL
* 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) */
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, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
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) {
pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
| 0x20);
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
& ~0x20);
pci_read_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, &tmp);
pci_write_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, tmp | 0x20);
pci_write_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, tmp & ~0x20);
}
} 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 */
mod_timer(&timer, jiffies + WDT_INTERVAL);
@ -117,21 +125,27 @@ static void wdt_timer_ping(unsigned long data)
static void wdt_change(int writeval)
{
char tmp;
char tmp;
pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp);
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) {
pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20);
pci_read_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, &tmp);
pci_write_config_byte(alim7101_pmu,
ALI_7101_GPIO_O, tmp & ~0x20);
}
} 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) {
pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20);
pci_read_config_byte(alim7101_pmu,
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)
* /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 */
if(count) {
if (count) {
if (!nowayout) {
size_t ofs;
@ -183,7 +198,7 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
/* now scan */
for (ofs = 0; ofs != count; ofs++) {
char c;
if (get_user(c, buf+ofs))
if (get_user(c, buf + ofs))
return -EFAULT;
if (c == 'V')
wdt_expect_close = 42;
@ -195,119 +210,116 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
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... */
if(test_and_set_bit(0, &wdt_is_open))
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
/* Good, fire up the show */
wdt_startup();
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();
else {
/* 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);
wdt_expect_close = 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;
int __user *p = argp;
static struct watchdog_info ident =
{
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.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_SETOPTIONS:
{
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;
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:
{
int new_timeout;
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 */
if (new_options & WDIOS_ENABLECARD) {
wdt_startup();
retval = 0;
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
return retval;
}
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
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);
default:
return -ENOTTY;
}
}
static const struct file_operations wdt_fops = {
.owner= THIS_MODULE,
.llseek= no_llseek,
.write= fop_write,
.open= fop_open,
.release= fop_close,
.ioctl= fop_ioctl,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = fop_write,
.open = fop_open,
.release = fop_close,
.unlocked_ioctl = fop_ioctl,
};
static struct miscdevice wdt_miscdev = {
.minor=WATCHDOG_MINOR,
.name="watchdog",
.fops=&wdt_fops,
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &wdt_fops,
};
/*
* 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();
if (code==SYS_RESTART) {
if (code == SYS_RESTART) {
/*
* Cobalt devices have no way of rebooting themselves other than
* getting the watchdog to pull reset, so we restart the watchdog on
* reboot with no heartbeat
* Cobalt devices have no way of rebooting themselves other
* than getting the watchdog to pull reset, so we restart the
* watchdog on reboot with no heartbeat
*/
wdt_change(WDT_ENABLE);
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
* turn the timebomb registers off.
*/
static struct notifier_block wdt_notifier=
{
static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys,
};
@ -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,
NULL);
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;
}
pci_read_config_byte(ali1543_south, 0x5e, &tmp);
@ -363,24 +375,25 @@ static int __init alim7101_wdt_init(void)
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");
goto err_out;
}
}
nowayout = 1;
} 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");
goto err_out;
}
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
{
if (timeout < 1 || timeout > 3600) {
/* arbitrary upper limit */
timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
timeout);
printk(KERN_INFO PFX
"timeout value must be 1 <= x <= 3600, using %d\n",
timeout);
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
rc);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", rc);
goto err_out;
}
@ -391,9 +404,8 @@ static int __init alim7101_wdt_init(void)
goto err_out_reboot;
}
if (nowayout) {
if (nowayout)
__module_get(THIS_MODULE);
}
printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);

View file

@ -213,7 +213,7 @@ static int ar7_wdt_notify_sys(struct notifier_block *this,
}
static struct notifier_block ar7_wdt_notifier = {
.notifier_call = ar7_wdt_notify_sys
.notifier_call = ar7_wdt_notify_sys,
};
static ssize_t ar7_wdt_write(struct file *file, const char *data,
@ -230,7 +230,7 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data,
expect_close = 0;
for (i = 0; i < len; ++i) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 1;
@ -251,8 +251,6 @@ static long ar7_wdt_ioctl(struct file *file,
int new_margin;
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg, &ident,
sizeof(ident)))
@ -281,6 +279,8 @@ static long ar7_wdt_ioctl(struct file *file,
if (put_user(margin, (int *)arg))
return -EFAULT;
return 0;
default:
return -ENOTTY;
}
}

View file

@ -212,8 +212,8 @@ static struct watchdog_info at32_wdt_info = {
/*
* Handle commands from user-space.
*/
static int at32_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long at32_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = -ENOTTY;
int time;
@ -221,27 +221,10 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file,
int __user *p = argp;
switch (cmd) {
case WDIOC_KEEPALIVE:
at32_wdt_pat();
ret = 0;
break;
case WDIOC_GETSUPPORT:
ret = copy_to_user(argp, &at32_wdt_info,
sizeof(at32_wdt_info)) ? -EFAULT : 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, p);
if (ret)
break;
ret = at32_wdt_settimeout(time);
if (ret)
break;
/* Enable new time value */
at32_wdt_start();
/* fall through */
case WDIOC_GETTIMEOUT:
ret = put_user(wdt->timeout, p);
break;
case WDIOC_GETSTATUS:
ret = put_user(0, p);
break;
@ -258,6 +241,23 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file,
at32_wdt_start();
ret = 0;
break;
case WDIOC_KEEPALIVE:
at32_wdt_pat();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, p);
if (ret)
break;
ret = at32_wdt_settimeout(time);
if (ret)
break;
/* Enable new time value */
at32_wdt_start();
/* fall through */
case WDIOC_GETTIMEOUT:
ret = put_user(wdt->timeout, p);
break;
}
return ret;
@ -283,7 +283,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data,
*/
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_release = 42;
@ -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 = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = at32_wdt_ioctl,
.unlocked_ioctl = at32_wdt_ioctl,
.open = at32_wdt_open,
.release = at32_wdt_close,
.write = at32_wdt_write,
@ -391,7 +391,6 @@ static int __exit at32_wdt_remove(struct platform_device *pdev)
wdt = NULL;
platform_set_drvdata(pdev, NULL);
}
return 0;
}

View file

@ -20,7 +20,7 @@
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <asm/arch/at91_st.h>
@ -31,11 +31,14 @@ static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT;
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
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
@ -46,7 +49,7 @@ static unsigned long at91wdt_busy;
/*
* 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);
}
@ -54,16 +57,17 @@ static void inline at91_wdt_stop(void)
/*
* 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);
}
/*
* 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);
}
@ -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)
{
/* Disable the watchdog when file is closed */
if (!nowayout)
at91_wdt_stop(); /* Disable the watchdog when file is closed */
at91_wdt_stop();
clear_bit(0, &at91wdt_busy);
return 0;
@ -110,7 +115,8 @@ static int at91_wdt_settimeout(int new_time)
if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
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;
return 0;
}
@ -123,60 +129,52 @@ static struct watchdog_info at91_wdt_info = {
/*
* Handle commands from user-space.
*/
static int at91_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long at91_wdt_ioct(struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_value;
switch(cmd) {
case WDIOC_KEEPALIVE:
at91_wdt_reload(); /* pat the watchdog */
return 0;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
if (at91_wdt_settimeout(new_value))
return -EINVAL;
/* Enable new time value */
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &at91_wdt_info,
sizeof(at91_wdt_info)) ? -EFAULT : 0;
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 current 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();
return 0;
default:
return -ENOTTY;
return 0;
case WDIOC_KEEPALIVE:
at91_wdt_reload(); /* pat the watchdog */
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
if (at91_wdt_settimeout(new_value))
return -EINVAL;
/* Enable new time value */
at91_wdt_start();
/* Return current value */
return put_user(wdt_time, p);
case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p);
default:
return -ENOTTY;
}
}
/*
* 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 */
return len;
@ -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 = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = at91_wdt_ioctl,
.unlocked_ioctl = at91_wdt_ioctl,
.open = at91_wdt_open,
.release = at91_wdt_close,
.write = at91_wdt_write,
@ -211,7 +209,8 @@ static int __init at91wdt_probe(struct platform_device *pdev)
if (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;
}
@ -265,7 +264,8 @@ static struct platform_driver at91wdt_driver = {
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)) {
at91_wdt_settimeout(WDT_DEFAULT_TIME);
pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);

View file

@ -24,8 +24,8 @@
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <asm/blackfin.h>
#include <asm/uaccess.h>
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am")
@ -148,7 +148,8 @@ static int bfin_wdt_set_timeout(unsigned long t)
int run = bfin_wdt_running();
bfin_wdt_stop();
bfin_write_WDOG_CNT(cnt);
if (run) bfin_wdt_start();
if (run)
bfin_wdt_start();
}
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
@ -191,16 +192,15 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
{
stampit();
if (expect_close == 42) {
if (expect_close == 42)
bfin_wdt_stop();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
else {
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
bfin_wdt_keepalive();
}
expect_close = 0;
clear_bit(0, &open_check);
return 0;
}
@ -214,7 +214,7 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
* Pings the watchdog on write.
*/
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();
@ -241,7 +241,6 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
/**
* bfin_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device
* @cmd: watchdog command
* @arg: argument
@ -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
* watchdog API.
*/
static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long bfin_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@ -258,59 +257,49 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
stampit();
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
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();
case WDIOC_GETSUPPORT:
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_SETOPTIONS: {
unsigned long flags;
int options, ret = -EINVAL;
case WDIOC_SETTIMEOUT: {
int new_timeout;
if (get_user(options, p))
return -EFAULT;
if (get_user(new_timeout, p))
return -EFAULT;
if (bfin_wdt_set_timeout(new_timeout))
return -EINVAL;
spin_lock_irqsave(&bfin_wdt_spinlock, flags);
if (options & WDIOS_DISABLECARD) {
bfin_wdt_stop();
ret = 0;
}
/* 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;
}
if (options & WDIOS_ENABLECARD) {
bfin_wdt_start();
ret = 0;
}
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
return ret;
if (options & WDIOS_ENABLECARD) {
bfin_wdt_start();
ret = 0;
}
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
return ret;
}
case WDIOC_KEEPALIVE:
bfin_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT: {
int new_timeout;
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);
default:
return -ENOTTY;
}
}
@ -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
* shutdown event.
*/
static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
static int bfin_wdt_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{
stampit();
@ -379,12 +368,12 @@ static int bfin_wdt_resume(struct platform_device *pdev)
#endif
static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = bfin_wdt_write,
.ioctl = bfin_wdt_ioctl,
.open = bfin_wdt_open,
.release = bfin_wdt_release,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = bfin_wdt_write,
.unlocked_ioctl = bfin_wdt_ioctl,
.open = bfin_wdt_open,
.release = bfin_wdt_release,
};
static struct miscdevice bfin_wdt_miscdev = {
@ -396,8 +385,8 @@ static struct miscdevice bfin_wdt_miscdev = {
static struct watchdog_info bfin_wdt_info = {
.identity = "Blackfin Watchdog",
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
};
static struct notifier_block bfin_wdt_notifier = {
@ -416,14 +405,16 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
ret = register_reboot_notifier(&bfin_wdt_notifier);
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;
}
ret = misc_register(&bfin_wdt_miscdev);
if (ret) {
pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
pr_devinit(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&bfin_wdt_notifier);
return ret;
}
@ -516,7 +507,11 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
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_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) ")");

View file

@ -18,9 +18,9 @@
#include <linux/miscdevice.h>
#include <linux/notifier.h>
#include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <asm/reg_booke.h>
#include <asm/uaccess.h>
#include <asm/system.h>
/* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
@ -32,7 +32,7 @@
*/
#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
#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
#endif /* for timing information */
@ -82,16 +82,15 @@ static struct watchdog_info ident = {
.identity = "PowerPC Book-E Watchdog",
};
static int booke_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long booke_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
u32 tmp = 0;
u32 __user *p = (u32 __user *)arg;
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(struct watchdog_info)))
if (copy_to_user(arg, &ident, sizeof(struct watchdog_info)))
return -EFAULT;
case WDIOC_GETSTATUS:
return put_user(ident.options, p);
@ -100,16 +99,6 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file,
tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
/* returns 1 if last reset was caused by the WDT */
return (tmp ? 1 : 0);
case WDIOC_KEEPALIVE:
booke_wdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(booke_wdt_period, p))
return -EFAULT;
mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
return 0;
case WDIOC_GETTIMEOUT:
return put_user(booke_wdt_period, p);
case WDIOC_SETOPTIONS:
if (get_user(tmp, p))
return -EINVAL;
@ -119,6 +108,17 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file,
} else
return -EINVAL;
return 0;
case WDIOC_KEEPALIVE:
booke_wdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(booke_wdt_period, p))
return -EFAULT;
mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP(0)) |
WDTP(booke_wdt_period));
return 0;
case WDIOC_GETTIMEOUT:
return put_user(booke_wdt_period, p);
default:
return -ENOTTY;
}
@ -132,8 +132,9 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1;
on_each_cpu(__booke_wdt_enable, NULL, 0);
printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled "
"(wdt_period=%d)\n", booke_wdt_period);
printk(KERN_INFO
"PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
booke_wdt_period);
}
spin_unlock(&booke_wdt_lock);
@ -144,7 +145,7 @@ static const struct file_operations booke_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = booke_wdt_write,
.ioctl = booke_wdt_ioctl,
.unlocked_ioctl = booke_wdt_ioctl,
.open = booke_wdt_open,
};
@ -175,8 +176,9 @@ static int __init booke_wdt_init(void)
spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) {
printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled "
"(wdt_period=%d)\n", booke_wdt_period);
printk(KERN_INFO
"PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
booke_wdt_period);
on_each_cpu(__booke_wdt_enable, NULL, 0);
}
spin_unlock(&booke_wdt_lock);

View file

@ -30,16 +30,16 @@
#include <linux/timer.h>
#include <linux/completion.h>
#include <linux/jiffies.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
/* adjustable parameters */
static int verbose = 0;
static int verbose;
static int port = 0x91;
static int ticks = 10000;
static spinlock_t cpu5wdt_lock;
#define PFX "cpu5wdt: "
@ -70,12 +70,13 @@ static struct {
static void cpu5wdt_trigger(unsigned long unused)
{
if ( verbose > 2 )
if (verbose > 2)
printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
if( cpu5wdt_device.running )
if (cpu5wdt_device.running)
ticks--;
spin_lock(&cpu5wdt_lock);
/* keep watchdog alive */
outb(1, port + CPU5WDT_TRIGGER_REG);
@ -86,6 +87,7 @@ static void cpu5wdt_trigger(unsigned long unused)
/* ticks doesn't matter anyway */
complete(&cpu5wdt_device.stop);
}
spin_unlock(&cpu5wdt_lock);
}
@ -93,14 +95,17 @@ static void cpu5wdt_reset(void)
{
ticks = cpu5wdt_device.default_ticks;
if ( verbose )
if (verbose)
printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
}
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;
outb(0, port + CPU5WDT_TIME_A_REG);
outb(0, port + CPU5WDT_TIME_B_REG);
@ -111,18 +116,20 @@ static void cpu5wdt_start(void)
}
/* if process dies, counter is not decremented */
cpu5wdt_device.running++;
spin_unlock_irqrestore(&cpu5wdt_lock, flags);
}
static int cpu5wdt_stop(void)
{
if ( cpu5wdt_device.running )
unsigned long flags;
spin_lock_irqsave(&cpu5wdt_lock, flags);
if (cpu5wdt_device.running)
cpu5wdt_device.running = 0;
ticks = cpu5wdt_device.default_ticks;
if ( verbose )
spin_unlock_irqrestore(&cpu5wdt_lock, flags);
if (verbose)
printk(KERN_CRIT PFX "stop not possible\n");
return -EIO;
}
@ -130,9 +137,8 @@ static int cpu5wdt_stop(void)
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 nonseekable_open(inode, file);
}
@ -142,67 +148,58 @@ static int cpu5wdt_release(struct inode *inode, struct file *file)
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;
int __user *p = argp;
unsigned int value;
static struct watchdog_info ident =
{
static struct watchdog_info ident = {
.options = WDIOF_CARDRESET,
.identity = "CPU5 WDT",
};
switch(cmd) {
case WDIOC_KEEPALIVE:
cpu5wdt_reset();
break;
case WDIOC_GETSTATUS:
value = inb(port + CPU5WDT_STATUS_REG);
value = (value >> 2) & 1;
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
case WDIOC_GETSUPPORT:
if ( copy_to_user(argp, &ident, sizeof(ident)) )
return -EFAULT;
break;
case WDIOC_SETOPTIONS:
if ( copy_from_user(&value, argp, sizeof(int)) )
return -EFAULT;
switch(value) {
case WDIOS_ENABLECARD:
cpu5wdt_start();
break;
case WDIOS_DISABLECARD:
return cpu5wdt_stop();
default:
return -EINVAL;
}
break;
default:
return -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
value = inb(port + CPU5WDT_STATUS_REG);
value = (value >> 2) & 1;
return put_user(value, p);
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(value, p))
return -EFAULT;
if (value & WDIOS_ENABLECARD)
cpu5wdt_start();
if (value & WDIOS_DISABLECARD)
cpu5wdt_stop();
break;
case WDIOC_KEEPALIVE:
cpu5wdt_reset();
break;
default:
return -ENOTTY;
}
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;
cpu5wdt_reset();
return count;
}
static const struct file_operations cpu5wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = cpu5wdt_ioctl,
.unlocked_ioctl = cpu5wdt_ioctl,
.open = cpu5wdt_open,
.write = cpu5wdt_write,
.release = cpu5wdt_release,
@ -221,37 +218,36 @@ static int __devinit cpu5wdt_init(void)
unsigned int val;
int err;
if ( verbose )
printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
if (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");
err = -EBUSY;
goto no_port;
}
if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
/* watchdog reboot? */
val = inb(port + CPU5WDT_STATUS_REG);
val = (val >> 2) & 1;
if (!val)
printk(KERN_INFO PFX "sorry, was my fault\n");
err = misc_register(&cpu5wdt_misc);
if (err < 0) {
printk(KERN_ERR PFX "misc_register failed\n");
goto no_misc;
}
/* watchdog reboot? */
val = inb(port + CPU5WDT_STATUS_REG);
val = (val >> 2) & 1;
if ( !val )
printk(KERN_INFO PFX "sorry, was my fault\n");
init_completion(&cpu5wdt_device.stop);
cpu5wdt_device.queue = 0;
clear_bit(0, &cpu5wdt_device.inuse);
setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0);
cpu5wdt_device.default_ticks = ticks;
printk(KERN_INFO PFX "init success\n");
return 0;
no_misc:
@ -267,7 +263,7 @@ static int __devinit cpu5wdt_init_module(void)
static void __devexit cpu5wdt_exit(void)
{
if ( cpu5wdt_device.queue ) {
if (cpu5wdt_device.queue) {
cpu5wdt_device.queue = 0;
wait_for_completion(&cpu5wdt_device.stop);
}

View file

@ -22,10 +22,10 @@
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define MODULE_NAME "DAVINCI-WDT: "
@ -143,9 +143,8 @@ static struct watchdog_info ident = {
.identity = "DaVinci Watchdog",
};
static int
davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long davinci_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = -ENOTTY;
@ -160,14 +159,14 @@ davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(0, (int *)arg);
break;
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_service();
ret = 0;
break;
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
}
return ret;
}
@ -184,7 +183,7 @@ static const struct file_operations davinci_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = davinci_wdt_write,
.ioctl = davinci_wdt_ioctl,
.unlocked_ioctl = davinci_wdt_ioctl,
.open = davinci_wdt_open,
.release = davinci_wdt_release,
};

View file

@ -28,9 +28,9 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#define WDT_VERSION "0.3"
#define PFX "ep93xx_wdt: "
@ -136,9 +136,8 @@ static struct watchdog_info ident = {
.identity = "EP93xx Watchdog",
};
static int
ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long ep93xx_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = -ENOTTY;
@ -156,15 +155,15 @@ ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(boot_status, (int __user *)arg);
break;
case WDIOC_GETTIMEOUT:
/* actually, it is 0.250 seconds.... */
ret = put_user(1, (int __user *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_keepalive();
ret = 0;
break;
case WDIOC_GETTIMEOUT:
/* actually, it is 0.250 seconds.... */
ret = put_user(1, (int __user *)arg);
break;
}
return ret;
}
@ -174,8 +173,8 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_shutdown();
else
printk(KERN_CRIT PFX "Device closed unexpectedly - "
"timer will not stop\n");
printk(KERN_CRIT PFX
"Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &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)
static const struct file_operations ep93xx_wdt_fops = {
.owner = THIS_MODULE,
.write = ep93xx_wdt_write,
.ioctl = ep93xx_wdt_ioctl,
.unlocked_ioctl = ep93xx_wdt_ioctl,
.open = ep93xx_wdt_open,
.release = ep93xx_wdt_release,
};
@ -243,7 +242,9 @@ module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
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>,"
"Alessandro Zummo <a.zummo@towertech.it>");

View file

@ -56,14 +56,15 @@
#include <linux/notifier.h>
#include <linux/reboot.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>
static unsigned long eurwdt_is_open;
static int eurwdt_timeout;
static char eur_expect_close;
static spinlock_t eurwdt_lock;
/*
* You must set these - there is no sane way to probe for this board.
@ -78,7 +79,9 @@ static char *ev = "int";
static int nowayout = WATCHDOG_NOWAYOUT;
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
@ -137,7 +140,8 @@ static void eurwdt_activate_timer(void)
{
eurwdt_disable_timer();
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 */
if (irq == 2 || irq > 15 || irq < 0) {
@ -206,21 +210,21 @@ size_t count, loff_t *ppos)
for (i = 0; i != count; i++) {
char c;
if(get_user(c, buf+i))
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V')
eur_expect_close = 42;
}
}
spin_lock(&eurwdt_lock);
eurwdt_ping(); /* the default timeout */
spin_unlock(&eurwdt_lock);
}
return count;
}
/**
* eurwdt_ioctl:
* @inode: inode of the device
* @file: file handle to the device
* @cmd: watchdog command
* @arg: argument pointer
@ -229,13 +233,14 @@ size_t count, loff_t *ppos)
* according to their available features.
*/
static int eurwdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long eurwdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "WDT Eurotech CPU-1220/1410",
};
@ -243,10 +248,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
int time;
int options, retval = -EINVAL;
switch(cmd) {
default:
return -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
@ -254,8 +256,26 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
if (get_user(options, p))
return -EFAULT;
spin_lock(&eurwdt_lock);
if (options & WDIOS_DISABLECARD) {
eurwdt_disable_timer();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
eurwdt_activate_timer();
eurwdt_ping();
retval = 0;
}
spin_unlock(&eurwdt_lock);
return retval;
case WDIOC_KEEPALIVE:
spin_lock(&eurwdt_lock);
eurwdt_ping();
spin_unlock(&eurwdt_lock);
return 0;
case WDIOC_SETTIMEOUT:
@ -266,26 +286,17 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
if (time < 0 || time > 255)
return -EINVAL;
spin_lock(&eurwdt_lock);
eurwdt_timeout = time;
eurwdt_set_timeout(time);
spin_unlock(&eurwdt_lock);
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(eurwdt_timeout, p);
case WDIOC_SETOPTIONS:
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
eurwdt_disable_timer();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
eurwdt_activate_timer();
eurwdt_ping();
retval = 0;
}
return retval;
default:
return -ENOTTY;
}
}
@ -322,10 +333,11 @@ static int eurwdt_open(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();
} else {
printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
else {
printk(KERN_CRIT
"eurwdt: Unexpected close, not stopping watchdog!\n");
eurwdt_ping();
}
clear_bit(0, &eurwdt_is_open);
@ -348,10 +360,8 @@ static int eurwdt_release(struct inode *inode, struct file *file)
static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
{
if (code == SYS_DOWN || code == SYS_HALT) {
/* Turn the card off */
eurwdt_disable_timer();
}
if (code == SYS_DOWN || code == SYS_HALT)
eurwdt_disable_timer(); /* Turn the card off */
return NOTIFY_DONE;
}
@ -362,11 +372,11 @@ static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
static const struct file_operations eurwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = eurwdt_write,
.ioctl = eurwdt_ioctl,
.open = eurwdt_open,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = eurwdt_write,
.unlocked_ioctl = eurwdt_ioctl,
.open = eurwdt_open,
.release = eurwdt_release,
};
@ -419,7 +429,7 @@ static int __init eurwdt_init(void)
int ret;
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);
goto out;
}
@ -432,10 +442,13 @@ static int __init eurwdt_init(void)
ret = register_reboot_notifier(&eurwdt_notifier);
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;
}
spin_lock_init(&eurwdt_lock);
ret = misc_register(&eurwdt_miscdev);
if (ret) {
printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",

View file

@ -17,8 +17,8 @@
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <asm/geode.h>
#define GEODEWDT_HZ 500
@ -77,27 +77,24 @@ static int geodewdt_set_heartbeat(int val)
return 0;
}
static int
geodewdt_open(struct inode *inode, struct file *file)
static int geodewdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags))
return -EBUSY;
if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags))
return -EBUSY;
if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags))
__module_get(THIS_MODULE);
if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags))
__module_get(THIS_MODULE);
geodewdt_ping();
return nonseekable_open(inode, file);
return nonseekable_open(inode, file);
}
static int
geodewdt_release(struct inode *inode, struct file *file)
static int geodewdt_release(struct inode *inode, struct file *file)
{
if (safe_close) {
geodewdt_disable();
module_put(THIS_MODULE);
}
else {
} else {
printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n");
geodewdt_ping();
@ -109,11 +106,10 @@ geodewdt_release(struct inode *inode, struct file *file)
return 0;
}
static ssize_t
geodewdt_write(struct file *file, const char __user *data, size_t len,
loff_t *ppos)
static ssize_t geodewdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
if(len) {
if (len) {
if (!nowayout) {
size_t i;
safe_close = 0;
@ -134,9 +130,8 @@ geodewdt_write(struct file *file, const char __user *data, size_t len,
return len;
}
static int
geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static int geodewdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@ -147,9 +142,9 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
};
};
switch(cmd) {
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
@ -159,22 +154,6 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
geodewdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(interval, p))
return -EFAULT;
if (geodewdt_set_heartbeat(interval))
return -EINVAL;
/* Fall through */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS:
{
int options, ret = -EINVAL;
@ -194,6 +173,20 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return ret;
}
case WDIOC_KEEPALIVE:
geodewdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(interval, p))
return -EFAULT;
if (geodewdt_set_heartbeat(interval))
return -EINVAL;
/* Fall through */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
}
@ -202,22 +195,21 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
static const struct file_operations geodewdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = geodewdt_write,
.ioctl = geodewdt_ioctl,
.open = geodewdt_open,
.release = geodewdt_release,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = geodewdt_write,
.ioctl = geodewdt_ioctl,
.open = geodewdt_open,
.release = geodewdt_release,
};
static struct miscdevice geodewdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &geodewdt_fops
.fops = &geodewdt_fops,
};
static int __devinit
geodewdt_probe(struct platform_device *dev)
static int __devinit geodewdt_probe(struct platform_device *dev)
{
int ret, timer;
@ -248,15 +240,13 @@ geodewdt_probe(struct platform_device *dev)
return ret;
}
static int __devexit
geodewdt_remove(struct platform_device *dev)
static int __devexit geodewdt_remove(struct platform_device *dev)
{
misc_deregister(&geodewdt_miscdev);
return 0;
}
static void
geodewdt_shutdown(struct platform_device *dev)
static void geodewdt_shutdown(struct platform_device *dev)
{
geodewdt_disable();
}
@ -271,8 +261,7 @@ static struct platform_driver geodewdt_driver = {
},
};
static int __init
geodewdt_init(void)
static int __init geodewdt_init(void)
{
int ret;
@ -292,8 +281,7 @@ geodewdt_init(void)
return ret;
}
static void __exit
geodewdt_exit(void)
static void __exit geodewdt_exit(void)
{
platform_device_unregister(geodewdt_platform_device);
platform_driver_unregister(&geodewdt_driver);

View file

@ -39,9 +39,7 @@
#include <linux/string.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
#include <asm/dmi.h>
#include <asm/desc.h>
#include <asm/kdebug.h>
#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */
#define CRU_BIOS_SIGNATURE_VALUE 0x55524324
@ -407,7 +405,7 @@ static int __devinit detect_cru_service(void)
dmi_walk(dmi_find_cru);
/* if cru_rom_addr has been set then we found a CRU service */
return ((cru_rom_addr != NULL)? 0: -ENODEV);
return ((cru_rom_addr != NULL) ? 0: -ENODEV);
}
/* ------------------------------------------------------------------------- */
@ -535,7 +533,7 @@ static ssize_t hpwdt_write(struct file *file, const char __user *data,
/* scan to see whether or not we got the magic char. */
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_release = 42;

View file

@ -9,18 +9,18 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* based on i810-tco.c which is in turn based on softdog.c
* based on i810-tco.c which is in turn based on softdog.c
*
* The timer is implemented in the following I/O controller hubs:
* (See the intel documentation on http://developer.intel.com.)
* 6300ESB chip : document number 300641-003
* The timer is implemented in the following I/O controller hubs:
* (See the intel documentation on http://developer.intel.com.)
* 6300ESB chip : document number 300641-003
*
* 2004YYZZ Ross Biro
* Initial version 0.01
* 2004YYZZ Ross Biro
* Version 0.02
* Version 0.02
* 20050210 David Härdeman <david@2gen.com>
* Ported driver to kernel 2.6
* Ported driver to kernel 2.6
*/
/*
@ -38,9 +38,8 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/io.h>
/* Module and version information */
#define ESB_VERSION "0.03"
@ -59,17 +58,17 @@
#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */
/* Lock register bits */
#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */
#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */
#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */
#define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */
#define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */
#define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */
/* Config register bits */
#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */
#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */
#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */
#define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */
#define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */
#define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */
/* Reload register bits */
#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */
#define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */
/* Magic constants */
#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 */
static char esb_expect_close;
/* 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 */
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;
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
@ -103,9 +108,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
* reload register. After this the appropriate registers can be written
* to once before they need to be unlocked again.
*/
static inline void esb_unlock_registers(void) {
writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
static inline void esb_unlock_registers(void)
{
writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
}
static void esb_timer_start(void)
@ -114,8 +120,7 @@ static void esb_timer_start(void)
/* Enable or Enable + Lock? */
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)
@ -140,7 +145,7 @@ static void esb_timer_keepalive(void)
spin_lock(&esb_lock);
esb_unlock_registers();
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);
}
@ -165,9 +170,9 @@ static int esb_timer_set_heartbeat(int time)
/* Write timer 2 */
esb_unlock_registers();
writel(val, ESB_TIMER2_REG);
writel(val, ESB_TIMER2_REG);
/* Reload */
/* Reload */
esb_unlock_registers();
writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
@ -179,54 +184,55 @@ static int esb_timer_set_heartbeat(int time)
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
* acount which stage is running, but it looks
* like a 20 bit count down, so we might as well report it.
*/
pci_read_config_dword(esb_pci, 0x64, &count);
return (int)count;
* acount which stage is running, but it looks
* like a 20 bit count down, so we might as well report it.
*/
pci_read_config_dword(esb_pci, 0x64, &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 */
if (test_and_set_bit(0, &timer_alive))
return -EBUSY;
/* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &timer_alive))
return -EBUSY;
/* Reload and activate timer */
esb_timer_keepalive ();
esb_timer_start ();
/* Reload and activate timer */
esb_timer_keepalive();
esb_timer_start();
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. */
if (esb_expect_close == 42) {
esb_timer_stop ();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
esb_timer_keepalive ();
}
clear_bit(0, &timer_alive);
esb_expect_close = 0;
return 0;
/* Shut off the timer. */
if (esb_expect_close == 42)
esb_timer_stop();
else {
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
esb_timer_keepalive();
}
clear_bit(0, &timer_alive);
esb_expect_close = 0;
return 0;
}
static ssize_t esb_write (struct file *file, const char __user *data,
size_t len, loff_t * ppos)
static ssize_t esb_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
/* See if we got the magic character 'V' and reload the timer */
if (len) {
if (len) {
if (!nowayout) {
size_t i;
@ -237,7 +243,7 @@ static ssize_t esb_write (struct file *file, const char __user *data,
/* scan to see whether or not we got the magic character */
for (i = 0; i != len; i++) {
char c;
if(get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
esb_expect_close = 42;
@ -245,92 +251,84 @@ static ssize_t esb_write (struct file *file, const char __user *data,
}
/* someone wrote to us, we should reload the timer */
esb_timer_keepalive ();
esb_timer_keepalive();
}
return len;
}
static int esb_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int new_options, retval = -EINVAL;
int new_heartbeat;
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = ESB_MODULE_NAME,
.firmware_version = 0,
.identity = ESB_MODULE_NAME,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof (ident)) ? -EFAULT : 0;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
return put_user (esb_timer_read(), p);
case WDIOC_GETSTATUS:
return put_user(esb_timer_read(), p);
case WDIOC_GETBOOTSTATUS:
return put_user (triggered, p);
case WDIOC_GETBOOTSTATUS:
return put_user(triggered, p);
case WDIOC_KEEPALIVE:
esb_timer_keepalive ();
return 0;
case WDIOC_SETOPTIONS:
{
if (get_user(new_options, p))
return -EFAULT;
case WDIOC_SETOPTIONS:
{
if (get_user (new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
esb_timer_stop();
retval = 0;
}
if (new_options & WDIOS_DISABLECARD) {
esb_timer_stop ();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
esb_timer_keepalive();
esb_timer_start();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
esb_timer_keepalive();
return 0;
if (new_options & WDIOS_ENABLECARD) {
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;
}
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
*/
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) {
/* Turn the WDT off */
esb_timer_stop ();
}
if (code == SYS_DOWN || code == SYS_HALT)
esb_timer_stop(); /* Turn the WDT off */
return NOTIFY_DONE;
return NOTIFY_DONE;
}
/*
@ -338,22 +336,22 @@ static int esb_notify_sys (struct notifier_block *this, unsigned long code, void
*/
static const struct file_operations esb_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = esb_write,
.ioctl = esb_ioctl,
.open = esb_open,
.release = esb_release,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = esb_write,
.unlocked_ioctl = esb_ioctl,
.open = esb_open,
.release = esb_release,
};
static struct miscdevice esb_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &esb_fops,
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &esb_fops,
};
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 = {
* want to register another driver on the same PCI id.
*/
static struct pci_device_id esb_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
{ 0, }, /* End of list */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE (pci, esb_pci_tbl);
MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
/*
* Init & exit routines
*/
static unsigned char __init esb_getdevice (void)
static unsigned char __init esb_getdevice(void)
{
u8 val1;
unsigned short val2;
/*
* Find the PCI device
*/
struct pci_dev *dev = NULL;
/*
* Find the PCI device
*/
esb_pci = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_ESB_9, NULL);
for_each_pci_dev(dev) {
if (pci_match_id(esb_pci_tbl, dev)) {
esb_pci = dev;
break;
}
}
if (esb_pci) {
if (pci_enable_device(esb_pci)) {
printk (KERN_ERR PFX "failed to enable device\n");
if (esb_pci) {
if (pci_enable_device(esb_pci)) {
printk(KERN_ERR PFX "failed to enable device\n");
goto err_devput;
}
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;
}
BASEADDR = ioremap(pci_resource_start(esb_pci, 0),
pci_resource_len(esb_pci, 0));
if (BASEADDR == NULL) {
/* Something's wrong here, BASEADDR has to be set */
printk (KERN_ERR PFX "failed to get BASEADDR\n");
goto err_release;
}
/* Something's wrong here, BASEADDR has to be set */
printk(KERN_ERR PFX "failed to get BASEADDR\n");
goto err_release;
}
/*
* The watchdog has two timers, it can be setup so that the
@ -425,7 +417,7 @@ static unsigned char __init esb_getdevice (void)
/* Check that the WDT isn't already locked */
pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
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 */
pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
@ -452,44 +444,44 @@ static unsigned char __init esb_getdevice (void)
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 */
if (!esb_getdevice () || esb_pci == NULL)
return -ENODEV;
/* Check whether or not the hardware watchdog is there */
if (!esb_getdevice() || esb_pci == NULL)
return -ENODEV;
/* Check that the heartbeat value is within it's range ; if not reset to the default */
if (esb_timer_set_heartbeat (heartbeat)) {
esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT);
printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n",
heartbeat);
}
/* Check that the heartbeat value is within it's range;
if not reset to the default */
if (esb_timer_set_heartbeat(heartbeat)) {
esb_timer_set_heartbeat(WATCHDOG_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) {
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
goto err_unmap;
}
ret = register_reboot_notifier(&esb_notifier);
if (ret != 0) {
printk(KERN_ERR PFX "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:
unregister_reboot_notifier(&esb_notifier);
unregister_reboot_notifier(&esb_notifier);
err_unmap:
iounmap(BASEADDR);
/* err_release: */
@ -498,18 +490,18 @@ static int __init watchdog_init (void)
pci_disable_device(esb_pci);
/* err_devput: */
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 */
if (!nowayout)
esb_timer_stop ();
esb_timer_stop();
/* Deregister */
misc_deregister(&esb_miscdev);
unregister_reboot_notifier(&esb_notifier);
unregister_reboot_notifier(&esb_notifier);
iounmap(BASEADDR);
pci_release_region(esb_pci, 0);
pci_disable_device(esb_pci);

View file

@ -0,0 +1,15 @@
/* 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

View file

@ -18,9 +18,9 @@
*/
/* Module and version information */
#define DRV_NAME "iTCO_vendor_support"
#define DRV_VERSION "1.01"
#define DRV_RELDATE "11-Nov-2006"
#define DRV_NAME "iTCO_vendor_support"
#define DRV_VERSION "1.01"
#define DRV_RELDATE "11-Nov-2006"
#define PFX DRV_NAME ": "
/* Includes */
@ -31,19 +31,22 @@
#include <linux/kernel.h> /* For printk/panic/... */
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/ioport.h> /* For io-port access */
#include <linux/io.h> /* For inb/outb/... */
#include <asm/io.h> /* For inb/outb/... */
#include "iTCO_vendor.h"
/* iTCO defines */
#define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */
#define TCOBASE acpibase + 0x60 /* TCO base address */
#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
#define TCOBASE acpibase + 0x60 /* TCO base address */
#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
/* List of vendor support modes */
#define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
#define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
/* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
#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_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+");
@ -143,34 +146,35 @@ static void supermicro_old_pre_keepalive(unsigned long acpibase)
*/
/* I/O Port's */
#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
/* Control Register's */
#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */
#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
#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 */
/* (Bit 3: 0 = seconds, 1 = minutes */
#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */
/* (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 */
/* Bit 6: timer is reset by kbd interrupt */
/* Bit 7: timer is reset by mouse interrupt */
#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */
/* Bit 6: timer is reset by kbd interrupt */
/* Bit 7: timer is reset by mouse interrupt */
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_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */
outb(SM_WATCHPAGE, SM_REGINDEX);
/* Switch to watchdog control page */
outb(SM_CTLPAGESW, SM_REGINDEX);
outb(SM_CTLPAGE, SM_DATAIO);
}
@ -192,7 +196,7 @@ static void supermicro_new_pre_start(unsigned int heartbeat)
outb(val, SM_DATAIO);
/* Write heartbeat interval to WDOG */
outb (SM_WATCHTIMER, SM_REGINDEX);
outb(SM_WATCHTIMER, SM_REGINDEX);
outb((heartbeat & 255), SM_DATAIO);
/* Make sure keyboard/mouse interrupts don't interfere */
@ -277,7 +281,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
int iTCO_vendor_check_noreboot_on(void)
{
switch(vendorsupport) {
switch (vendorsupport) {
case SUPERMICRO_OLD_BOARD:
return 0;
default:
@ -288,13 +292,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
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;
}
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);

View file

@ -55,9 +55,9 @@
*/
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.03"
#define DRV_RELDATE "30-Apr-2008"
#define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.03"
#define DRV_RELDATE "30-Apr-2008"
#define PFX DRV_NAME ": "
/* Includes */
@ -66,7 +66,8 @@
#include <linux/types.h> /* For standard types (like size_t) */
#include <linux/errno.h> /* For the -ENODEV/... values */
#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/init.h> /* For __init/__exit/... */
#include <linux/fs.h> /* For file operations */
@ -74,9 +75,10 @@
#include <linux/pci.h> /* For pci functions */
#include <linux/ioport.h> /* For io-port access */
#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 <asm/io.h> /* For inb/outb/... */
#include "iTCO_vendor.h"
/* TCO related info */
enum iTCO_chipsets {
@ -105,7 +107,7 @@ enum iTCO_chipsets {
TCO_ICH9, /* ICH9 */
TCO_ICH9R, /* ICH9R */
TCO_ICH9DH, /* ICH9DH */
TCO_ICH9DO, /* ICH9DO */
TCO_ICH9DO, /* ICH9DO */
TCO_631XESB, /* 631xESB/632xESB */
};
@ -140,7 +142,7 @@ static struct {
{"ICH9DH", 2},
{"ICH9DO", 2},
{"631xESB/632xESB", 2},
{NULL,0}
{NULL, 0}
};
#define ITCO_PCI_DEVICE(dev, data) \
@ -159,32 +161,32 @@ static struct {
* functions that probably will be registered by other drivers.
*/
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_82801AB_0, TCO_ICH0 )},
{ 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_82801CA_0, TCO_ICH3 )},
{ 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_12, TCO_ICH4M )},
{ 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_82801AA_0, TCO_ICH)},
{ 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_10, TCO_ICH2M)},
{ 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_82801DB_0, TCO_ICH4)},
{ 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_82801EB_0, TCO_ICH5)},
{ 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_1, TCO_ICH6M )},
{ 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_1, TCO_ICH7M )},
{ 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_2, TCO_ICH6W)},
{ 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_31, TCO_ICH7MDH)},
{ 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_2, TCO_ICH8DH )},
{ 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(0x2918, TCO_ICH9 )},
{ 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_4, TCO_ICH9DO )},
{ 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_2, TCO_ICH8DH)},
{ 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(0x2918, TCO_ICH9)},
{ 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_4, TCO_ICH9DO)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2671, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2672, TCO_631XESB)},
@ -203,13 +205,15 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x267f, TCO_631XESB)},
{ 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 */
#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */
#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */
/* TCO base address */
#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 TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
#define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
@ -222,15 +226,21 @@ MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
/* internal variables */
static unsigned long is_active;
static char expect_release;
static struct { /* this is private data for the iTCO_wdt device */
unsigned int iTCO_version; /* TCO version/generation */
unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */
spinlock_t io_lock; /* the lock for io operations */
struct pci_dev *pdev; /* the PCI-device */
static struct { /* this is private data for the iTCO_wdt device */
/* TCO version/generation */
unsigned int iTCO_version;
/* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
unsigned long ACPIBASE;
/* 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;
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 */
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
@ -240,22 +250,9 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* 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
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Some TCO specific functions
@ -369,11 +366,10 @@ static int iTCO_wdt_keepalive(void)
iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
/* 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);
} else if (iTCO_wdt_private.iTCO_version == 1) {
else if (iTCO_wdt_private.iTCO_version == 1)
outb(0x01, TCO_RLD);
}
spin_unlock(&iTCO_wdt_private.io_lock);
return 0;
@ -425,7 +421,7 @@ static int iTCO_wdt_set_heartbeat(int t)
return 0;
}
static int iTCO_wdt_get_timeleft (int *time_left)
static int iTCO_wdt_get_timeleft(int *time_left)
{
unsigned int val16;
unsigned char val8;
@ -454,7 +450,7 @@ static int iTCO_wdt_get_timeleft (int *time_left)
* /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 */
if (test_and_set_bit(0, &is_active))
@ -468,7 +464,7 @@ static int iTCO_wdt_open (struct inode *inode, struct file *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.
@ -476,7 +472,8 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file)
if (expect_release == 42) {
iTCO_wdt_stop();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
iTCO_wdt_keepalive();
}
clear_bit(0, &is_active);
@ -484,22 +481,23 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file)
return 0;
}
static ssize_t iTCO_wdt_write (struct file *file, const char __user *data,
size_t len, loff_t * ppos)
static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
/* See if we got the magic character 'V' and reload the timer */
if (len) {
if (!nowayout) {
size_t i;
/* note: just in case someone wrote the magic character
* five months ago... */
/* note: just in case someone wrote the magic
character five months ago... */
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++) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_release = 42;
@ -512,8 +510,8 @@ static ssize_t iTCO_wdt_write (struct file *file, const char __user *data,
return len;
}
static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_options, retval = -EINVAL;
int new_heartbeat;
@ -528,64 +526,52 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof (ident)) ? -EFAULT : 0;
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_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
{
if (get_user(new_options, p))
return -EFAULT;
case WDIOC_KEEPALIVE:
if (new_options & WDIOS_DISABLECARD) {
iTCO_wdt_stop();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
iTCO_wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
iTCO_wdt_stop();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
iTCO_wdt_keepalive();
iTCO_wdt_start();
retval = 0;
}
return retval;
iTCO_wdt_start();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
iTCO_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
{
if (get_user(new_heartbeat, p))
return -EFAULT;
if (iTCO_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
iTCO_wdt_keepalive();
/* Fall */
}
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
case WDIOC_GETTIMELEFT:
{
int time_left;
if (iTCO_wdt_get_timeleft(&time_left))
return -EINVAL;
return put_user(time_left, p);
}
default:
return -ENOTTY;
case WDIOC_SETTIMEOUT:
{
if (get_user(new_heartbeat, p))
return -EFAULT;
if (iTCO_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
iTCO_wdt_keepalive();
/* Fall */
}
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
case WDIOC_GETTIMELEFT:
{
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,
*/
static const struct file_operations iTCO_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = iTCO_wdt_write,
.ioctl = iTCO_wdt_ioctl,
.open = iTCO_wdt_open,
.release = iTCO_wdt_release,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = iTCO_wdt_write,
.unlocked_ioctl = iTCO_wdt_ioctl,
.open = iTCO_wdt_open,
.release = iTCO_wdt_release,
};
static struct miscdevice iTCO_wdt_miscdev = {
@ -612,7 +598,8 @@ static struct miscdevice iTCO_wdt_miscdev = {
* 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;
u32 base_address;
@ -632,17 +619,19 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device
pci_dev_put(pdev);
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.pdev = pdev;
/* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */
/* To get access to it you have to read RCBA from PCI Config space 0xf0
and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */
/* Get the Memory-Mapped GCS register, we need it for the
NO_REBOOT flag (TCO v2). To get access to it you have to
read RCBA from PCI Config space 0xf0 and use it as base.
GCS = RCBA + ICH6_GCS(0x3410). */
if (iTCO_wdt_private.iTCO_version == 2) {
pci_read_config_dword(pdev, 0xf0, &base_address);
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 */
@ -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 */
if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
SMI_EN );
printk(KERN_ERR PFX
"I/O address 0x%04lx already in use\n", SMI_EN);
ret = -EIO;
goto out;
}
@ -667,18 +656,20 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device
outl(val32, SMI_EN);
release_region(SMI_EN, 4);
/* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */
if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) {
printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n",
/* The TCO I/O registers reside in a 32-byte range pointed to
by the TCOBASE value */
if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
TCOBASE);
ret = -EIO;
goto out;
}
printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
iTCO_chipset_info[ent->driver_data].name,
iTCO_chipset_info[ent->driver_data].iTCO_version,
TCOBASE);
printk(KERN_INFO PFX
"Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
iTCO_chipset_info[ent->driver_data].name,
iTCO_chipset_info[ent->driver_data].iTCO_version,
TCOBASE);
/* Clear out the (probably old) status */
outb(0, TCO1_STS);
@ -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 */
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)) {
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",
heartbeat);
printk(KERN_INFO PFX "heartbeat value must be 2 < heartbeat < 39 (TCO v1) or 613 (TCO v2), using %d\n",
heartbeat);
}
ret = misc_register(&iTCO_wdt_miscdev);
if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_region;
}
printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
return 0;
unreg_region:
release_region (TCOBASE, 0x20);
release_region(TCOBASE, 0x20);
out:
if (iTCO_wdt_private.iTCO_version == 2)
iounmap(iTCO_wdt_private.gcs);
@ -796,7 +789,8 @@ static int __init iTCO_wdt_init_module(void)
if (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)) {
err = PTR_ERR(iTCO_wdt_platform_device);
goto unreg_platform_driver;

View file

@ -41,9 +41,9 @@
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
static struct platform_device *ibwdt_platform_device;
@ -120,15 +120,16 @@ static int wd_margin = WD_TIMO;
static int nowayout = WATCHDOG_NOWAYOUT;
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
*/
static void
ibwdt_ping(void)
static void ibwdt_ping(void)
{
spin_lock(&ibwdt_lock);
@ -138,16 +139,14 @@ ibwdt_ping(void)
spin_unlock(&ibwdt_lock);
}
static void
ibwdt_disable(void)
static void ibwdt_disable(void)
{
spin_lock(&ibwdt_lock);
outb_p(0, WDT_STOP);
spin_unlock(&ibwdt_lock);
}
static int
ibwdt_set_heartbeat(int t)
static int ibwdt_set_heartbeat(int t)
{
int i;
@ -165,8 +164,8 @@ ibwdt_set_heartbeat(int t)
* /dev/watchdog handling
*/
static ssize_t
ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
static ssize_t ibwdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count) {
if (!nowayout) {
@ -188,77 +187,71 @@ ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppo
return count;
}
static int
ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int new_margin;
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "IB700 WDT",
};
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
ibwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
if (ibwdt_set_heartbeat(new_margin))
return -EINVAL;
ibwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(wd_times[wd_margin], p);
return put_user(0, p);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
int options, retval = -EINVAL;
if (get_user(options, p))
return -EFAULT;
if (get_user(options, p))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
ibwdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
ibwdt_ping();
retval = 0;
}
return retval;
if (options & WDIOS_DISABLECARD) {
ibwdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
ibwdt_ping();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
ibwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
if (ibwdt_set_heartbeat(new_margin))
return -EINVAL;
ibwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(wd_times[wd_margin], p);
default:
return -ENOTTY;
return -ENOTTY;
}
return 0;
}
static int
ibwdt_open(struct inode *inode, struct file *file)
static int 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;
}
if (nowayout)
__module_get(THIS_MODULE);
@ -267,13 +260,13 @@ ibwdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static int
ibwdt_close(struct inode *inode, struct file *file)
static int ibwdt_close(struct inode *inode, struct file *file)
{
if (expect_close == 42) {
ibwdt_disable();
} 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();
}
clear_bit(0, &ibwdt_is_open);
@ -289,7 +282,7 @@ static const struct file_operations ibwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ibwdt_write,
.ioctl = ibwdt_ioctl,
.unlocked_ioctl = ibwdt_ioctl,
.open = ibwdt_open,
.release = ibwdt_close,
};
@ -310,21 +303,23 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
#if WDT_START != WDT_STOP
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;
goto out_nostopreg;
}
#endif
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;
goto out_nostartreg;
}
res = misc_register(&ibwdt_miscdev);
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;
}
return 0;
@ -342,9 +337,9 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
static int __devexit ibwdt_remove(struct platform_device *dev)
{
misc_deregister(&ibwdt_miscdev);
release_region(WDT_START,1);
release_region(WDT_START, 1);
#if WDT_START != WDT_STOP
release_region(WDT_STOP,1);
release_region(WDT_STOP, 1);
#endif
return 0;
}
@ -369,13 +364,15 @@ static int __init ibwdt_init(void)
{
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);
if (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)) {
err = PTR_ERR(ibwdt_platform_device);
goto unreg_platform_driver;

View file

@ -19,9 +19,8 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/dmi.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/uaccess.h>
enum {
@ -70,10 +69,13 @@ static char asr_expect_close;
static unsigned int asr_type, asr_base, asr_length;
static unsigned int asr_read_addr, asr_write_addr;
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);
reg = inb(asr_read_addr);
@ -83,12 +85,21 @@ static void asr_toggle(void)
outb(reg & ~asr_toggle_mask, asr_write_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)
{
unsigned char reg;
spin_lock(&asr_lock);
if (asr_type == ASMTYPE_TOPAZ) {
/* asr_write_addr == asr_read_addr */
reg = inb(asr_read_addr);
@ -99,17 +110,21 @@ static void asr_enable(void)
* First make sure the hardware timer is reset by toggling
* ASR hardware timer line.
*/
asr_toggle();
__asr_toggle();
reg = inb(asr_read_addr);
outb(reg & ~asr_disable_mask, asr_write_addr);
}
reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
}
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)
/* asr_write_addr == asr_read_addr */
@ -122,6 +137,7 @@ static void asr_disable(void)
outb(reg | asr_disable_mask, asr_write_addr);
}
reg = inb(asr_read_addr);
spin_unlock(&asr_lock);
}
static int __init asr_get_base_address(void)
@ -133,7 +149,8 @@ static int __init asr_get_base_address(void)
switch (asr_type) {
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, 0x2f);
@ -154,14 +171,26 @@ static int __init asr_get_base_address(void)
case ASMTYPE_JASPER:
type = "Jaspers ";
/* FIXME: need to use pci_config_lock here, but it's not exported */
#if 0
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);*/
/* Select the SuperIO chip in the PCI I/O port register */
outl(0x8000f858, 0xcf8);
/* BUS 0, Slot 1F, fnc 0, offset 58 */
/*
* Read the base address for the SuperIO chip.
* Only the lower 16 bits are valid, but the address is word
@ -170,7 +199,7 @@ static int __init asr_get_base_address(void)
asr_base = inl(0xcfc) & 0xfffe;
/* spin_unlock_irqrestore(&pci_config_lock, flags);*/
#endif
asr_read_addr = asr_write_addr =
asr_base + JASPER_ASR_REG_OFFSET;
asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
@ -241,66 +270,57 @@ static ssize_t asr_write(struct file *file, const char __user *buf,
return count;
}
static int asr_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long asr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
.options = WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.identity = "IBM ASR"
.identity = "IBM ASR",
};
void __user *argp = (void __user *)arg;
int __user *p = argp;
int heartbeat;
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:
asr_toggle();
return 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;
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_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;
}
case WDIOC_KEEPALIVE:
asr_toggle();
return 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);
default:
return -ENOTTY;
}
return -ENOTTY;
}
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;
asr_toggle();
@ -314,7 +334,8 @@ static int asr_release(struct inode *inode, struct file *file)
if (asr_expect_close == 42)
asr_disable();
else {
printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
printk(KERN_CRIT PFX
"unexpected close, not stopping watchdog!\n");
asr_toggle();
}
clear_bit(0, &asr_is_open);
@ -323,12 +344,12 @@ static int asr_release(struct inode *inode, struct file *file)
}
static const struct file_operations asr_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = asr_write,
.ioctl = asr_ioctl,
.open = asr_open,
.release = asr_release,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = asr_write,
.unlocked_ioctl = asr_ioctl,
.open = asr_open,
.release = asr_release,
};
static struct miscdevice asr_miscdev = {
@ -367,6 +388,8 @@ static int __init ibmasr_init(void)
if (!asr_type)
return -ENODEV;
spin_lock_init(&asr_lock);
rc = asr_get_base_address();
if (rc)
return rc;
@ -395,7 +418,9 @@ module_init(ibmasr_init);
module_exit(ibmasr_exit);
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_AUTHOR("Andrey Panin");

View file

@ -1,7 +1,8 @@
/*
* 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
* modify it under the terms of the GNU General Public License
@ -22,32 +23,42 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <asm/sgi/mc.h>
#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 */
static int nowayout = WATCHDOG_NOWAYOUT;
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)
{
u32 mc_ctrl0 = sgimc->cpuctrl0;
u32 mc_ctrl0;
spin_lock(&indydog_lock);
mc_ctrl0 = sgimc->cpuctrl0;
mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
sgimc->cpuctrl0 = mc_ctrl0;
spin_unlock(&indydog_lock);
}
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;
sgimc->cpuctrl0 = mc_ctrl0;
spin_unlock(&indydog_lock);
printk(KERN_INFO PFX "Stopped watchdog timer.\n");
}
@ -62,7 +73,7 @@ static void indydog_ping(void)
*/
static int indydog_open(struct inode *inode, struct file *file)
{
if (indydog_alive)
if (test_and_set_bit(0, &indydog_alive))
return -EBUSY;
if (nowayout)
@ -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 */
if (!nowayout)
indydog_stop(); /* Turn the WDT off */
indydog_alive = 0;
clear_bit(0, &indydog_alive);
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. */
if (len) {
if (len)
indydog_ping();
}
return len;
}
static int indydog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long indydog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int options, retval = -EINVAL;
static struct watchdog_info ident = {
@ -111,42 +120,40 @@ static int indydog_ioctl(struct inode *inode, struct file *file,
};
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg,
&ident, sizeof(ident)))
return -EFAULT;
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0,(int *)arg);
case WDIOC_KEEPALIVE:
indydog_ping();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_TIMEOUT,(int *)arg);
case WDIOC_SETOPTIONS:
{
if (get_user(options, (int *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
indydog_stop();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
indydog_start();
retval = 0;
}
return retval;
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg,
&ident, sizeof(ident)))
return -EFAULT;
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int *)arg);
case WDIOC_SETOPTIONS:
{
if (get_user(options, (int *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
indydog_stop();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
indydog_start();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
indydog_ping();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_TIMEOUT, (int *)arg);
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)
indydog_stop(); /* Turn the WDT off */
@ -158,7 +165,7 @@ static const struct file_operations indydog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = indydog_write,
.ioctl = indydog_ioctl,
.unlocked_ioctl = indydog_ioctl,
.open = indydog_open,
.release = indydog_release,
};
@ -180,17 +187,20 @@ static int __init watchdog_init(void)
{
int ret;
spin_lock_init(&indydog_lock);
ret = register_reboot_notifier(&indydog_notifier);
if (ret) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&indydog_miscdev);
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&indydog_notifier);
return ret;
}

View file

@ -37,6 +37,7 @@
static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned long wdt_status;
static unsigned long boot_status;
static spinlock_t wdt_lock;
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
@ -68,8 +69,10 @@ static void wdt_enable(void)
/* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
* Takes approx. 10.7s to timeout
*/
spin_lock(&wdt_lock);
write_wdtcr(IOP_WDTCR_EN_ARM);
write_wdtcr(IOP_WDTCR_EN);
spin_unlock(&wdt_lock);
}
/* returns 0 if the timer was successfully disabled */
@ -77,9 +80,11 @@ static int wdt_disable(void)
{
/* Stop Counting */
if (wdt_supports_disable()) {
spin_lock(&wdt_lock);
write_wdtcr(IOP_WDTCR_DIS_ARM);
write_wdtcr(IOP_WDTCR_DIS);
clear_bit(WDT_ENABLED, &wdt_status);
spin_unlock(&wdt_lock);
printk(KERN_INFO "WATCHDOG: Disabled\n");
return 0;
} else
@ -92,16 +97,12 @@ static int iop_wdt_open(struct inode *inode, struct file *file)
return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
wdt_enable();
set_bit(WDT_ENABLED, &wdt_status);
return nonseekable_open(inode, file);
}
static ssize_t
iop_wdt_write(struct file *file, const char *data, size_t len,
static ssize_t iop_wdt_write(struct file *file, const char *data, size_t len,
loff_t *ppos)
{
if (len) {
@ -121,46 +122,35 @@ iop_wdt_write(struct file *file, const char *data, size_t len,
}
wdt_enable();
}
return len;
}
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "iop watchdog",
};
static int
iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long iop_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int options;
int ret = -ENOTTY;
int __user *argp = (int __user *)arg;
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user
((struct watchdog_info *)arg, &ident, sizeof ident))
if (copy_to_user(argp, &ident, sizeof ident))
ret = -EFAULT;
else
ret = 0;
break;
case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg);
ret = put_user(0, argp);
break;
case WDIOC_GETBOOTSTATUS:
ret = put_user(boot_status, (int *)arg);
break;
case WDIOC_GETTIMEOUT:
ret = put_user(iop_watchdog_timeout(), (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
ret = put_user(boot_status, argp);
break;
case WDIOC_SETOPTIONS:
@ -177,14 +167,21 @@ iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
} else
ret = 0;
}
if (options & WDIOS_ENABLECARD) {
wdt_enable();
ret = 0;
}
break;
}
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_GETTIMEOUT:
ret = put_user(iop_watchdog_timeout(), argp);
break;
}
return ret;
}
@ -214,7 +211,7 @@ static const struct file_operations iop_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = iop_wdt_write,
.ioctl = iop_wdt_ioctl,
.unlocked_ioctl = iop_wdt_ioctl,
.open = iop_wdt_open,
.release = iop_wdt_release,
};
@ -229,10 +226,8 @@ static int __init iop_wdt_init(void)
{
int ret;
ret = misc_register(&iop_wdt_miscdev);
if (ret == 0)
printk("iop watchdog timer: timeout %lu sec\n",
iop_watchdog_timeout());
spin_lock_init(&wdt_lock);
/* check if the reset was caused by the watchdog timer */
boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
@ -242,6 +237,13 @@ static int __init iop_wdt_init(void)
*/
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(KERN_INFO "iop watchdog timer: timeout %lu sec\n",
iop_watchdog_timeout());
return ret;
}

View file

@ -221,7 +221,7 @@ static ssize_t it8712f_wdt_write(struct file *file, const char __user *data,
expect_close = 0;
for (i = 0; i < len; ++i) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -244,8 +244,6 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
int value;
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
@ -284,6 +282,8 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
if (put_user(margin, p))
return -EFAULT;
return 0;
default:
return -ENOTTY;
}
}

View file

@ -25,42 +25,45 @@
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
static int nowayout = WATCHDOG_NOWAYOUT;
static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status;
static spinlock_t wdt_lock;
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
static unsigned long wdt_tick_rate;
static void
wdt_enable(void)
static void wdt_enable(void)
{
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
spin_unlock(&wdt_lock);
}
static void
wdt_disable(void)
static void wdt_disable(void)
{
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CTL, 0);
spin_unlock(&wdt_lock);
}
static void
wdt_keepalive(void)
static void wdt_keepalive(void)
{
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
spin_unlock(&wdt_lock);
}
static int
ixp2000_wdt_open(struct inode *inode, struct file *file)
static int ixp2000_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;
@ -72,8 +75,8 @@ ixp2000_wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static ssize_t
ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{
if (len) {
if (!nowayout) {
@ -103,9 +106,8 @@ static struct watchdog_info ident = {
.identity = "IXP2000 Watchdog",
};
static int
ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = -ENOTTY;
int time;
@ -124,6 +126,11 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(0, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
if (ret)
@ -141,26 +148,18 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
}
return ret;
}
static int
ixp2000_wdt_release(struct inode *inode, struct file *file)
static int 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();
} else {
else
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n");
}
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
@ -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,
.llseek = no_llseek,
.write = ixp2000_wdt_write,
.ioctl = ixp2000_wdt_ioctl,
.unlocked_ioctl = ixp2000_wdt_ioctl,
.open = ixp2000_wdt_open,
.release = ixp2000_wdt_release,
};
static struct miscdevice ixp2000_wdt_miscdev =
{
static struct miscdevice ixp2000_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &ixp2000_wdt_fops,
@ -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");
return -EIO;
}
wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
spin_lock_init(&wdt_lock);
return misc_register(&ixp2000_wdt_miscdev);
}

View file

@ -22,48 +22,48 @@
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
static int nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status;
static unsigned long boot_status;
static spin_lock_t wdt_lock;
#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
static void
wdt_enable(void)
static void wdt_enable(void)
{
spin_lock(&wdt_lock);
*IXP4XX_OSWK = IXP4XX_WDT_KEY;
*IXP4XX_OSWE = 0;
*IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
*IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
*IXP4XX_OSWK = 0;
spin_unlock(&wdt_lock);
}
static void
wdt_disable(void)
static void wdt_disable(void)
{
spin_lock(&wdt_lock);
*IXP4XX_OSWK = IXP4XX_WDT_KEY;
*IXP4XX_OSWE = 0;
*IXP4XX_OSWK = 0;
spin_unlock(&wdt_lock);
}
static int
ixp4xx_wdt_open(struct inode *inode, struct file *file)
static int ixp4xx_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
wdt_enable();
return nonseekable_open(inode, file);
}
@ -87,7 +87,6 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
}
wdt_enable();
}
return len;
}
@ -98,9 +97,8 @@ static struct watchdog_info ident = {
};
static int
ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long ixp4xx_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = -ENOTTY;
int time;
@ -119,6 +117,11 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(boot_status, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
if (ret)
@ -136,25 +139,17 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
}
return ret;
}
static int
ixp4xx_wdt_release(struct inode *inode, struct file *file)
static int 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();
} else {
else
printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n");
}
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
@ -162,18 +157,16 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file)
}
static const struct file_operations ixp4xx_wdt_fops =
{
static const struct file_operations ixp4xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ixp4xx_wdt_write,
.ioctl = ixp4xx_wdt_ioctl,
.unlocked_ioctl = ixp4xx_wdt_ioctl,
.open = ixp4xx_wdt_open,
.release = ixp4xx_wdt_release,
};
static struct miscdevice ixp4xx_wdt_miscdev =
{
static struct miscdevice ixp4xx_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &ixp4xx_wdt_fops,
@ -186,19 +179,18 @@ static int __init ixp4xx_wdt_init(void)
asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
if (!(processor_id & 0xf) && !cpu_is_ixp46x()) {
printk("IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected - "
"watchdog disabled\n");
printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected"
" - watchdog disabled\n");
return -ENODEV;
}
ret = misc_register(&ixp4xx_wdt_miscdev);
if (ret == 0)
printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat);
spin_lock_init(&wdt_lock);
boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
WDIOF_CARDRESET : 0;
ret = misc_register(&ixp4xx_wdt_miscdev);
if (ret == 0)
printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec\n",
heartbeat);
return ret;
}

View file

@ -19,8 +19,8 @@
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/arch/regs-timer.h>
@ -31,38 +31,44 @@ static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT;
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
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
static unsigned long ks8695wdt_busy;
static spinlock_t ks8695_lock;
/* ......................................................................... */
/*
* Disable the watchdog.
*/
static void inline ks8695_wdt_stop(void)
static inline void ks8695_wdt_stop(void)
{
unsigned long tmcon;
spin_lock(&ks8695_lock);
/* disable timer0 */
tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
spin_unlock(&ks8695_lock);
}
/*
* Enable and reset the watchdog.
*/
static void inline ks8695_wdt_start(void)
static inline void ks8695_wdt_start(void)
{
unsigned long tmcon;
unsigned long tval = wdt_time * CLOCK_TICK_RATE;
spin_lock(&ks8695_lock);
/* disable timer0 */
tmcon = __raw_readl(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)
/* re-enable timer0 */
tmcon = __raw_readl(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)
*/
static void inline ks8695_wdt_reload(void)
static inline void ks8695_wdt_reload(void)
{
unsigned long tmcon;
spin_lock(&ks8695_lock);
/* disable, then re-enable timer0 */
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);
}
/*
@ -102,7 +111,8 @@ static int ks8695_wdt_settimeout(int new_time)
if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
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;
return 0;
}
@ -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)
{
/* Disable the watchdog when file is closed */
if (!nowayout)
ks8695_wdt_stop(); /* Disable the watchdog when file is closed */
ks8695_wdt_stop();
clear_bit(0, &ks8695wdt_busy);
return 0;
}
@ -143,60 +153,52 @@ static struct watchdog_info ks8695_wdt_info = {
/*
* Handle commands from user-space.
*/
static int ks8695_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long ks8695_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_value;
switch(cmd) {
case WDIOC_KEEPALIVE:
ks8695_wdt_reload(); /* pat the watchdog */
return 0;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
if (ks8695_wdt_settimeout(new_value))
return -EINVAL;
/* Enable new time value */
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ks8695_wdt_info,
sizeof(ks8695_wdt_info)) ? -EFAULT : 0;
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 current 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();
return 0;
default:
return -ENOTTY;
return 0;
case WDIOC_KEEPALIVE:
ks8695_wdt_reload(); /* pat the watchdog */
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
if (ks8695_wdt_settimeout(new_value))
return -EINVAL;
/* Enable new time value */
ks8695_wdt_start();
/* Return current value */
return put_user(wdt_time, p);
case WDIOC_GETTIMEOUT:
return put_user(wdt_time, p);
default:
return -ENOTTY;
}
}
/*
* 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 */
return 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 = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = ks8695_wdt_ioctl,
.unlocked_ioctl = ks8695_wdt_ioctl,
.open = ks8695_wdt_open,
.release = ks8695_wdt_close,
.write = ks8695_wdt_write,
@ -231,7 +233,8 @@ static int __init ks8695wdt_probe(struct platform_device *pdev)
if (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;
}
@ -285,12 +288,14 @@ static struct platform_driver ks8695wdt_driver = {
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)) {
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);
}

View file

@ -40,9 +40,9 @@
#include <linux/notifier.h>
#include <linux/reboot.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>
/* ports */
@ -95,7 +95,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
static int nowayout = WATCHDOG_NOWAYOUT;
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"
@ -114,7 +116,7 @@ static struct watchdog_info zf_info = {
* 3 = GEN_SCI
* defaults to GEN_RESET (0)
*/
static int action = 0;
static int action;
module_param(action, int, 0);
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);
static int zf_action = GEN_RESET;
static unsigned long zf_is_open;
static char zf_expect_close;
static DEFINE_SPINLOCK(zf_lock);
static DEFINE_SPINLOCK(zf_port_lock);
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) */
@ -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)
{
switch(n){
case WD1:
zf_writew(COUNTER_1, new);
case WD2:
zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
default:
return;
switch (n) {
case WD1:
zf_writew(COUNTER_1, new);
case WD2:
zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
default:
return;
}
}
@ -241,10 +242,8 @@ static void zf_ping(unsigned long data)
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);
/*
* reset event is activated by transition from 0 to 1 on
* RESET_WD1 bit and we assume that it is already zero...
@ -261,24 +260,21 @@ static void zf_ping(unsigned long data)
spin_unlock_irqrestore(&zf_port_lock, flags);
mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
}else{
} else
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,
loff_t *ppos)
{
/* See if we got the magic character */
if(count){
if (count) {
/*
* no need to check for close confirmation
* no way to disable watchdog ;)
*/
if (!nowayout) {
size_t ofs;
/*
* note: just in case someone wrote the magic character
* five months ago...
@ -286,11 +282,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
zf_expect_close = 0;
/* now scan */
for (ofs = 0; ofs != count; ofs++){
for (ofs = 0; ofs != count; ofs++) {
char c;
if (get_user(c, buf + ofs))
return -EFAULT;
if (c == 'V'){
if (c == 'V') {
zf_expect_close = 42;
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,
*/
next_heartbeat = jiffies + ZF_USER_TIMEO;
dprintk("user ping at %ld\n", jiffies);
}
return count;
}
static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long zf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@ -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)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
zf_ping(0);
break;
default:
return -ENOTTY;
}
return 0;
}
static int zf_open(struct inode *inode, struct file *file)
{
spin_lock(&zf_lock);
if(test_and_set_bit(0, &zf_is_open)) {
spin_unlock(&zf_lock);
if (test_and_set_bit(0, &zf_is_open))
return -EBUSY;
}
if (nowayout)
__module_get(THIS_MODULE);
spin_unlock(&zf_lock);
zf_timer_on();
return nonseekable_open(inode, file);
}
static int zf_close(struct inode *inode, struct file *file)
{
if(zf_expect_close == 42){
if (zf_expect_close == 42)
zf_timer_off();
} else {
else {
del_timer(&zf_timer);
printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
}
spin_lock(&zf_lock);
clear_bit(0, &zf_is_open);
spin_unlock(&zf_lock);
zf_expect_close = 0;
return 0;
}
@ -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,
void *unused)
{
if(code == SYS_DOWN || code == SYS_HALT){
if (code == SYS_DOWN || code == SYS_HALT)
zf_timer_off();
}
return NOTIFY_DONE;
}
static const struct file_operations zf_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = zf_write,
.ioctl = zf_ioctl,
.open = zf_open,
.release = zf_close,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = zf_write,
.unlocked_ioctl = zf_ioctl,
.open = zf_open,
.release = zf_close,
};
static struct miscdevice zf_miscdev = {
@ -402,7 +373,7 @@ static struct miscdevice zf_miscdev = {
.name = "watchdog",
.fops = &zf_fops,
};
/*
* The device needs to learn about soft shutdowns in order to
@ -423,22 +394,23 @@ static int __init zf_init(void)
{
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();
if ((!ret) || (ret == 0xffff)) {
if (!ret || ret == 0xffff) {
printk(KERN_WARNING PFX ": no ZF-Logic found\n");
return -ENODEV;
}
if((action <= 3) && (action >= 0)){
zf_action = zf_action>>action;
} else
if (action <= 3 && action >= 0)
zf_action = zf_action >> action;
else
action = 0;
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",
ZF_IOBASE);
ret = -EBUSY;
@ -446,14 +418,14 @@ static int __init zf_init(void)
}
ret = register_reboot_notifier(&zf_notifier);
if(ret){
if (ret) {
printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
ret);
goto no_reboot;
}
ret = misc_register(&zf_miscdev);
if (ret){
if (ret) {
printk(KERN_ERR "can't misc_register on minor=%d\n",
WATCHDOG_MINOR);
goto no_misc;

View file

@ -29,7 +29,8 @@
* - support for one more type board
*
* 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>
* - make mixcomwd_opened unsigned,
@ -53,8 +54,8 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/io.h>
/*
* We have two types of cards that can be probed:
@ -108,18 +109,19 @@ static char expect_close;
static int nowayout = WATCHDOG_NOWAYOUT;
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)
{
outb_p(55,watchdog_port);
outb_p(55, watchdog_port);
return;
}
static void mixcomwd_timerfun(unsigned long d)
{
mixcomwd_ping();
mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
}
@ -129,22 +131,22 @@ static void mixcomwd_timerfun(unsigned long d)
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;
}
mixcomwd_ping();
if (nowayout) {
if (nowayout)
/*
* fops_get() code via open() has already done
* a try_module_get() so it is safe to do the
* __module_get().
*/
__module_get(THIS_MODULE);
} else {
if(mixcomwd_timer_alive) {
else {
if (mixcomwd_timer_alive) {
del_timer(&mixcomwd_timer);
mixcomwd_timer_alive=0;
mixcomwd_timer_alive = 0;
}
}
return nonseekable_open(inode, 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)
{
if (expect_close == 42) {
if(mixcomwd_timer_alive) {
printk(KERN_ERR PFX "release called while internal timer alive");
if (mixcomwd_timer_alive) {
printk(KERN_ERR PFX
"release called while internal timer alive");
return -EBUSY;
}
mixcomwd_timer_alive=1;
mixcomwd_timer_alive = 1;
mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
} else {
printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
}
} else
printk(KERN_CRIT PFX
"WDT device closed unexpectedly. WDT will not stop!\n");
clear_bit(0,&mixcomwd_opened);
expect_close=0;
clear_bit(0, &mixcomwd_opened);
expect_close = 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) {
size_t i;
@ -192,8 +195,8 @@ static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t
return len;
}
static int mixcomwd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long mixcomwd_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@ -204,32 +207,23 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
.identity = "MixCOM watchdog",
};
switch(cmd)
{
case WDIOC_GETSTATUS:
status=mixcomwd_opened;
if (!nowayout) {
status|=mixcomwd_timer_alive;
}
if (copy_to_user(p, &status, sizeof(int))) {
return -EFAULT;
}
break;
case WDIOC_GETBOOTSTATUS:
if (copy_to_user(p, &status, sizeof(int))) {
return -EFAULT;
}
break;
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) {
return -EFAULT;
}
break;
case WDIOC_KEEPALIVE:
mixcomwd_ping();
break;
default:
return -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
status = mixcomwd_opened;
if (!nowayout)
status |= mixcomwd_timer_alive;
return put_user(status, p);
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
mixcomwd_ping();
break;
default:
return -ENOTTY;
}
return 0;
}
@ -238,7 +232,7 @@ static const struct file_operations mixcomwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mixcomwd_write,
.ioctl = mixcomwd_ioctl,
.unlocked_ioctl = mixcomwd_ioctl,
.open = mixcomwd_open,
.release = mixcomwd_release,
};
@ -253,15 +247,14 @@ static int __init checkcard(int port, int card_id)
{
int id;
if (!request_region(port, 1, "MixCOM watchdog")) {
if (!request_region(port, 1, "MixCOM watchdog"))
return 0;
}
id=inb_p(port);
if (card_id==MIXCOM_ID)
id = inb_p(port);
if (card_id == MIXCOM_ID)
id &= 0x3f;
if (id!=card_id) {
if (id != card_id) {
release_region(port, 1);
return 0;
}
@ -270,9 +263,7 @@ static int __init checkcard(int port, int card_id)
static int __init mixcomwd_init(void)
{
int i;
int ret;
int found=0;
int i, ret, found = 0;
for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) {
if (checkcard(mixcomwd_io_info[i].ioport,
@ -283,20 +274,22 @@ static int __init mixcomwd_init(void)
}
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;
}
ret = misc_register(&mixcomwd_miscdev);
if (ret)
{
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
if (ret) {
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto error_misc_register_watchdog;
}
printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
VERSION, watchdog_port);
printk(KERN_INFO
"MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
VERSION, watchdog_port);
return 0;
@ -309,15 +302,15 @@ static int __init mixcomwd_init(void)
static void __exit mixcomwd_exit(void)
{
if (!nowayout) {
if(mixcomwd_timer_alive) {
if (mixcomwd_timer_alive) {
printk(KERN_WARNING PFX "I quit now, hardware will"
" probably reboot!\n");
del_timer_sync(&mixcomwd_timer);
mixcomwd_timer_alive=0;
mixcomwd_timer_alive = 0;
}
}
misc_deregister(&mixcomwd_miscdev);
release_region(watchdog_port,1);
release_region(watchdog_port, 1);
}
module_init(mixcomwd_init);

View file

@ -5,7 +5,7 @@
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/of_platform.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <asm/mpc52xx.h>
@ -57,7 +57,8 @@ static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
/* set timeout, with maximum prescaler */
out_be32(&wdt->regs->count, 0x0 | wdt->count);
/* 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);
return 0;
@ -66,7 +67,8 @@ static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
{
spin_lock(&wdt->io_lock);
/* 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);
return 0;
}
@ -92,8 +94,8 @@ static struct watchdog_info mpc5200_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "mpc5200 watchdog on GPT0",
};
static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long mpc5200_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct mpc5200_wdt *wdt = file->private_data;
int __user *data = (int __user *)arg;
@ -103,7 +105,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = copy_to_user(data, &mpc5200_wdt_info,
sizeof(mpc5200_wdt_info));
sizeof(mpc5200_wdt_info));
if (ret)
ret = -EFAULT;
break;
@ -135,6 +137,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
}
return ret;
}
static int mpc5200_wdt_open(struct inode *inode, struct file *file)
{
/* /dev/watchdog can only be opened once */
@ -161,13 +164,14 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file)
static const struct file_operations mpc5200_wdt_fops = {
.owner = THIS_MODULE,
.write = mpc5200_wdt_write,
.ioctl = mpc5200_wdt_ioctl,
.unlocked_ioctl = mpc5200_wdt_ioctl,
.open = mpc5200_wdt_open,
.release = mpc5200_wdt_release,
};
/* 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;
int err;
@ -215,9 +219,9 @@ static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *ma
return 0;
iounmap(wdt->regs);
out_release:
out_release:
release_mem_region(wdt->mem.start, size);
out_free:
out_free:
kfree(wdt);
return err;
}

View file

@ -1,230 +0,0 @@
/*
* mpc83xx_wdt.c - MPC83xx watchdog userspace interface
*
* Authors: Dave Updegraff <dave@cray.org>
* Kumar Gala <galak@kernel.crashing.org>
* Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
* ..and from sc520_wdt
*
* Note: it appears that you can only actually ENABLE or DISABLE the thing
* once after POR. Once enabled, you cannot disable, and vice versa.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/watchdog.h>
#include <asm/io.h>
#include <asm/uaccess.h>
struct mpc83xx_wdt {
__be32 res0;
__be32 swcrr; /* System watchdog control register */
#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
__be32 swcnr; /* System watchdog count register */
u8 res1[2];
__be16 swsrr; /* System watchdog service register */
u8 res2[0xF0];
};
static struct mpc83xx_wdt __iomem *wd_base;
static u16 timeout = 0xffff;
module_param(timeout, ushort, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535");
static int reset = 1;
module_param(reset, bool, 0);
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
* to 0
*/
static int prescale = 1;
static unsigned int timeout_sec;
static unsigned long wdt_is_open;
static DEFINE_SPINLOCK(wdt_spinlock);
static void mpc83xx_wdt_keepalive(void)
{
/* Ping the WDT */
spin_lock(&wdt_spinlock);
out_be16(&wd_base->swsrr, 0x556c);
out_be16(&wd_base->swsrr, 0xaa39);
spin_unlock(&wdt_spinlock);
}
static ssize_t mpc83xx_wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count)
mpc83xx_wdt_keepalive();
return count;
}
static int mpc83xx_wdt_open(struct inode *inode, struct file *file)
{
u32 tmp = SWCRR_SWEN;
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
/* Once we start the watchdog we can't stop it */
__module_get(THIS_MODULE);
/* Good, fire up the show */
if (prescale)
tmp |= SWCRR_SWPR;
if (reset)
tmp |= SWCRR_SWRI;
tmp |= timeout << 16;
out_be32(&wd_base->swcrr, tmp);
return nonseekable_open(inode, file);
}
static int mpc83xx_wdt_release(struct inode *inode, struct file *file)
{
printk(KERN_CRIT "Unexpected close, not stopping watchdog!\n");
mpc83xx_wdt_keepalive();
clear_bit(0, &wdt_is_open);
return 0;
}
static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = "MPC83xx",
};
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:
mpc83xx_wdt_keepalive();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(timeout_sec, p);
default:
return -ENOTTY;
}
}
static const struct file_operations mpc83xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpc83xx_wdt_write,
.ioctl = mpc83xx_wdt_ioctl,
.open = mpc83xx_wdt_open,
.release = mpc83xx_wdt_release,
};
static struct miscdevice mpc83xx_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &mpc83xx_wdt_fops,
};
static int __devinit mpc83xx_wdt_probe(struct platform_device *dev)
{
struct resource *r;
int ret;
unsigned int *freq = dev->dev.platform_data;
/* get a pointer to the register memory */
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!r) {
ret = -ENODEV;
goto err_out;
}
wd_base = ioremap(r->start, sizeof (struct mpc83xx_wdt));
if (wd_base == NULL) {
ret = -ENOMEM;
goto err_out;
}
ret = misc_register(&mpc83xx_wdt_miscdev);
if (ret) {
printk(KERN_ERR "cannot register miscdev on minor=%d "
"(err=%d)\n",
WATCHDOG_MINOR, ret);
goto err_unmap;
}
/* Calculate the timeout in seconds */
if (prescale)
timeout_sec = (timeout * 0x10000) / (*freq);
else
timeout_sec = timeout / (*freq);
printk(KERN_INFO "WDT driver for MPC83xx initialized. "
"mode:%s timeout=%d (%d seconds)\n",
reset ? "reset":"interrupt", timeout, timeout_sec);
return 0;
err_unmap:
iounmap(wd_base);
err_out:
return ret;
}
static int __devexit mpc83xx_wdt_remove(struct platform_device *dev)
{
misc_deregister(&mpc83xx_wdt_miscdev);
iounmap(wd_base);
return 0;
}
static struct platform_driver mpc83xx_wdt_driver = {
.probe = mpc83xx_wdt_probe,
.remove = __devexit_p(mpc83xx_wdt_remove),
.driver = {
.name = "mpc83xx_wdt",
.owner = THIS_MODULE,
},
};
static int __init mpc83xx_wdt_init(void)
{
return platform_driver_register(&mpc83xx_wdt_driver);
}
static void __exit mpc83xx_wdt_exit(void)
{
platform_driver_unregister(&mpc83xx_wdt_driver);
}
module_init(mpc83xx_wdt_init);
module_exit(mpc83xx_wdt_exit);
MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
MODULE_DESCRIPTION("Driver for watchdog timer in MPC83xx uProcessor");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:mpc83xx_wdt");

View file

@ -16,36 +16,35 @@
#include <linux/module.h>
#include <linux/watchdog.h>
#include <asm/8xx_immap.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <syslib/m8xx_wdt.h>
static unsigned long wdt_opened;
static int wdt_status;
static spinlock_t wdt_lock;
static void mpc8xx_wdt_handler_disable(void)
{
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)
m8xx_wdt_stop_timer();
else
out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
}
static void mpc8xx_wdt_handler_enable(void)
{
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)
m8xx_wdt_install_timer();
else
out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
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)
{
if (test_and_set_bit(0, &wdt_opened))
return -EBUSY;
m8xx_wdt_reset();
mpc8xx_wdt_handler_disable();
return nonseekable_open(inode, file);
}
static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
{
m8xx_wdt_reset();
#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
mpc8xx_wdt_handler_enable();
#endif
clear_bit(0, &wdt_opened);
return 0;
}
static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
loff_t * ppos)
static ssize_t mpc8xx_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{
if (len)
if (len) {
spin_lock(&wdt_lock);
m8xx_wdt_reset();
spin_unlock(&wdt_lock);
}
return len;
}
static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long mpc8xx_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int timeout;
static struct watchdog_info info = {
@ -112,15 +108,19 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
return -EOPNOTSUPP;
case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);
m8xx_wdt_reset();
wdt_status |= WDIOF_KEEPALIVEPING;
spin_unlock(&wdt_lock);
break;
case WDIOC_SETTIMEOUT:
return -EOPNOTSUPP;
case WDIOC_GETTIMEOUT:
spin_lock(&wdt_lock);
timeout = m8xx_wdt_get_timeout();
spin_unlock(&wdt_lock);
if (put_user(timeout, (int *)arg))
return -EFAULT;
break;
@ -136,7 +136,7 @@ static const struct file_operations mpc8xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpc8xx_wdt_write,
.ioctl = mpc8xx_wdt_ioctl,
.unlocked_ioctl = mpc8xx_wdt_ioctl,
.open = mpc8xx_wdt_open,
.release = mpc8xx_wdt_release,
};
@ -149,6 +149,7 @@ static struct miscdevice mpc8xx_wdt_miscdev = {
static int __init mpc8xx_wdt_init(void)
{
spin_lock_init(&wdt_lock);
return misc_register(&mpc8xx_wdt_miscdev);
}

View file

@ -0,0 +1,316 @@
/*
* mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
*
* Authors: Dave Updegraff <dave@cray.org>
* Kumar Gala <galak@kernel.crashing.org>
* Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
* ..and from sc520_wdt
* Copyright (c) 2008 MontaVista Software, Inc.
* Anton Vorontsov <avorontsov@ru.mvista.com>
*
* Note: it appears that you can only actually ENABLE or DISABLE the thing
* once after POR. Once enabled, you cannot disable, and vice versa.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/of_platform.h>
#include <linux/module.h>
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <sysdev/fsl_soc.h>
struct mpc8xxx_wdt {
__be32 res0;
__be32 swcrr; /* System watchdog control register */
#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
__be32 swcnr; /* System watchdog count register */
u8 res1[2];
__be16 swsrr; /* System watchdog service register */
u8 res2[0xF0];
};
struct mpc8xxx_wdt_type {
int prescaler;
bool hw_enabled;
};
static struct mpc8xxx_wdt __iomem *wd_base;
static u16 timeout = 0xffff;
module_param(timeout, ushort, 0);
MODULE_PARM_DESC(timeout,
"Watchdog timeout in ticks. (0<timeout<65536, default=65535");
static int reset = 1;
module_param(reset, bool, 0);
MODULE_PARM_DESC(reset,
"Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* We always prescale, but if someone really doesn't want to they can set this
* to 0
*/
static int prescale = 1;
static unsigned int timeout_sec;
static unsigned long wdt_is_open;
static DEFINE_SPINLOCK(wdt_spinlock);
static void mpc8xxx_wdt_keepalive(void)
{
/* Ping the WDT */
spin_lock(&wdt_spinlock);
out_be16(&wd_base->swsrr, 0x556c);
out_be16(&wd_base->swsrr, 0xaa39);
spin_unlock(&wdt_spinlock);
}
static void mpc8xxx_wdt_timer_ping(unsigned long arg);
static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, 0);
static void mpc8xxx_wdt_timer_ping(unsigned long arg)
{
mpc8xxx_wdt_keepalive();
/* We're pinging it twice faster than needed, just to be sure. */
mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
}
static void mpc8xxx_wdt_pr_warn(const char *msg)
{
pr_crit("mpc8xxx_wdt: %s, expect the %s soon!\n", msg,
reset ? "reset" : "machine check exception");
}
static ssize_t mpc8xxx_wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count)
mpc8xxx_wdt_keepalive();
return count;
}
static int mpc8xxx_wdt_open(struct inode *inode, struct file *file)
{
u32 tmp = SWCRR_SWEN;
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
/* Once we start the watchdog we can't stop it */
if (nowayout)
__module_get(THIS_MODULE);
/* Good, fire up the show */
if (prescale)
tmp |= SWCRR_SWPR;
if (reset)
tmp |= SWCRR_SWRI;
tmp |= timeout << 16;
out_be32(&wd_base->swcrr, tmp);
del_timer_sync(&wdt_timer);
return nonseekable_open(inode, file);
}
static int mpc8xxx_wdt_release(struct inode *inode, struct file *file)
{
if (!nowayout)
mpc8xxx_wdt_timer_ping(0);
else
mpc8xxx_wdt_pr_warn("watchdog closed");
clear_bit(0, &wdt_is_open);
return 0;
}
static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = "MPC8xxx",
};
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:
mpc8xxx_wdt_keepalive();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(timeout_sec, p);
default:
return -ENOTTY;
}
}
static const struct file_operations mpc8xxx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpc8xxx_wdt_write,
.unlocked_ioctl = mpc8xxx_wdt_ioctl,
.open = mpc8xxx_wdt_open,
.release = mpc8xxx_wdt_release,
};
static struct miscdevice mpc8xxx_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &mpc8xxx_wdt_fops,
};
static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
int ret;
struct device_node *np = ofdev->node;
struct mpc8xxx_wdt_type *wdt_type = match->data;
u32 freq = fsl_get_sys_freq();
bool enabled;
if (!freq || freq == -1)
return -EINVAL;
wd_base = of_iomap(np, 0);
if (!wd_base)
return -ENOMEM;
enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN;
if (!enabled && wdt_type->hw_enabled) {
pr_info("mpc8xxx_wdt: could not be enabled in software\n");
ret = -ENOSYS;
goto err_unmap;
}
/* Calculate the timeout in seconds */
if (prescale)
timeout_sec = (timeout * wdt_type->prescaler) / freq;
else
timeout_sec = timeout / freq;
pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d "
"(%d seconds)\n", reset ? "reset" : "interrupt", timeout,
timeout_sec);
/*
* If the watchdog was previously enabled or we're running on
* MPC8xxx, we should ping the wdt from the kernel until the
* userspace handles it.
*/
if (enabled)
mpc8xxx_wdt_timer_ping(0);
return 0;
err_unmap:
iounmap(wd_base);
wd_base = NULL;
return ret;
}
static int __devexit mpc8xxx_wdt_remove(struct of_device *ofdev)
{
mpc8xxx_wdt_pr_warn("watchdog removed");
del_timer_sync(&wdt_timer);
misc_deregister(&mpc8xxx_wdt_miscdev);
iounmap(wd_base);
return 0;
}
static const struct of_device_id mpc8xxx_wdt_match[] = {
{
.compatible = "mpc83xx_wdt",
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x10000,
},
},
{
.compatible = "fsl,mpc8610-wdt",
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x10000,
.hw_enabled = true,
},
},
{
.compatible = "fsl,mpc823-wdt",
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x800,
},
},
{},
};
MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match);
static struct of_platform_driver mpc8xxx_wdt_driver = {
.match_table = mpc8xxx_wdt_match,
.probe = mpc8xxx_wdt_probe,
.remove = __devexit_p(mpc8xxx_wdt_remove),
.driver = {
.name = "mpc8xxx_wdt",
.owner = THIS_MODULE,
},
};
/*
* We do wdt initialization in two steps: arch_initcall probes the wdt
* very early to start pinging the watchdog (misc devices are not yet
* available), and later module_init() just registers the misc device.
*/
static int __init mpc8xxx_wdt_init_late(void)
{
int ret;
if (!wd_base)
return -ENODEV;
ret = misc_register(&mpc8xxx_wdt_miscdev);
if (ret) {
pr_err("cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
return ret;
}
return 0;
}
module_init(mpc8xxx_wdt_init_late);
static int __init mpc8xxx_wdt_init(void)
{
return of_register_platform_driver(&mpc8xxx_wdt_driver);
}
arch_initcall(mpc8xxx_wdt_init);
static void __exit mpc8xxx_wdt_exit(void)
{
of_unregister_platform_driver(&mpc8xxx_wdt_driver);
}
module_exit(mpc8xxx_wdt_exit);
MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
MODULE_DESCRIPTION("Driver for watchdog timer in MPC8xx/MPC83xx/MPC86xx "
"uProcessors");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);

View file

@ -29,9 +29,9 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <asm/hardware/arm_twd.h>
#include <asm/uaccess.h>
struct mpcore_wdt {
unsigned long timer_alive;
@ -43,17 +43,20 @@ struct mpcore_wdt {
};
static struct platform_device *mpcore_wdt_dev;
extern unsigned int mpcore_timer_rate;
#define TIMER_MARGIN 60
static int mpcore_margin = TIMER_MARGIN;
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;
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
static int mpcore_noboot = ONLY_TESTING;
@ -70,14 +73,12 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
/* Check it really was our interrupt */
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 */
writel(1, wdt->base + TWD_WDOG_INTSTAT);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
@ -96,22 +97,26 @@ static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
count = (mpcore_timer_rate / 256) * mpcore_margin;
/* Reload the counter */
spin_lock(&wdt_lock);
writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
wdt->perturb = wdt->perturb ? 0 : 1;
spin_unlock(&wdt_lock);
}
static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
{
spin_lock(&wdt_lock);
writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
writel(0x0, wdt->base + TWD_WDOG_CONTROL);
spin_unlock(&wdt_lock);
}
static void mpcore_wdt_start(struct mpcore_wdt *wdt)
{
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 */
mpcore_wdt_keepalive(wdt);
@ -122,6 +127,7 @@ static void mpcore_wdt_start(struct mpcore_wdt *wdt)
/* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
}
spin_unlock(&wdt_lock);
}
static int mpcore_wdt_set_heartbeat(int t)
@ -164,10 +170,11 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
* Shut off the timer.
* 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);
} else {
dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n");
else {
dev_printk(KERN_CRIT, wdt->dev,
"unexpected close, not stopping watchdog!\n");
mpcore_wdt_keepalive(wdt);
}
clear_bit(0, &wdt->timer_alive);
@ -175,7 +182,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
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;
@ -210,8 +218,8 @@ static struct watchdog_info ident = {
.identity = "MPcore Watchdog",
};
static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct mpcore_wdt *wdt = file->private_data;
int ret;
@ -235,6 +243,12 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
ret = 0;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
uarg.i = 0;
ret = 0;
break;
case WDIOC_SETOPTIONS:
ret = -EINVAL;
if (uarg.i & WDIOS_DISABLECARD) {
@ -247,12 +261,6 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
}
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
uarg.i = 0;
ret = 0;
break;
case WDIOC_KEEPALIVE:
mpcore_wdt_keepalive(wdt);
ret = 0;
@ -301,7 +309,7 @@ static const struct file_operations mpcore_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpcore_wdt_write,
.ioctl = mpcore_wdt_ioctl,
.unlocked_ioctl = mpcore_wdt_ioctl,
.open = mpcore_wdt_open,
.release = mpcore_wdt_release,
};
@ -349,14 +357,17 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
mpcore_wdt_miscdev.parent = &dev->dev;
ret = misc_register(&mpcore_wdt_miscdev);
if (ret) {
dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
dev_printk(KERN_ERR, _dev,
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
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) {
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;
}
@ -366,13 +377,13 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
return 0;
err_irq:
err_irq:
misc_deregister(&mpcore_wdt_miscdev);
err_misc:
err_misc:
iounmap(wdt->base);
err_free:
err_free:
kfree(wdt);
err_out:
err_out:
return ret;
}
@ -415,7 +426,7 @@ static int __init mpcore_wdt_init(void)
*/
if (mpcore_wdt_set_heartbeat(mpcore_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);
}

View file

@ -1,7 +1,8 @@
/*
* 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
*
* (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
@ -46,12 +47,11 @@
#include <linux/jiffies.h>
#include <linux/watchdog.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/gpio.h>
#define MTX1_WDT_INTERVAL (5 * HZ)
@ -59,6 +59,7 @@ static int ticks = 100 * HZ;
static struct {
struct completion stop;
spinlock_t lock;
int running;
struct timer_list timer;
int queue;
@ -71,6 +72,7 @@ static void mtx1_wdt_trigger(unsigned long unused)
{
u32 tmp;
spin_lock(&mtx1_wdt_device.lock);
if (mtx1_wdt_device.running)
ticks--;
/*
@ -79,13 +81,13 @@ static void mtx1_wdt_trigger(unsigned long unused)
tmp = au_readl(GPIO2_DIR);
tmp = (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)
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
else {
else
complete(&mtx1_wdt_device.stop);
}
spin_unlock(&mtx1_wdt_device.lock);
}
static void mtx1_wdt_reset(void)
@ -96,23 +98,25 @@ static void mtx1_wdt_reset(void)
static void mtx1_wdt_start(void)
{
spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
if (!mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 1;
gpio_set_value(mtx1_wdt_device.gpio, 1);
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
}
mtx1_wdt_device.running++;
spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
}
static int mtx1_wdt_stop(void)
{
spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
if (mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 0;
gpio_set_value(mtx1_wdt_device.gpio, 0);
}
ticks = mtx1_wdt_device.default_ticks;
spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
return 0;
}
@ -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))
return -EBUSY;
return nonseekable_open(inode, file);
}
@ -133,54 +136,51 @@ static int mtx1_wdt_release(struct inode *inode, struct file *file)
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;
int __user *p = (int __user *)argp;
unsigned int value;
static struct watchdog_info ident =
{
static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET,
.identity = "MTX-1 WDT",
};
switch(cmd) {
case WDIOC_KEEPALIVE:
mtx1_wdt_reset();
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
case WDIOC_GETSUPPORT:
if ( copy_to_user(argp, &ident, sizeof(ident)) )
return -EFAULT;
break;
case WDIOC_SETOPTIONS:
if ( copy_from_user(&value, argp, sizeof(int)) )
return -EFAULT;
switch(value) {
case WDIOS_ENABLECARD:
mtx1_wdt_start();
break;
case WDIOS_DISABLECARD:
return mtx1_wdt_stop();
default:
return -EINVAL;
}
break;
default:
return -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
put_user(0, p);
break;
case WDIOC_SETOPTIONS:
if (get_user(value, p))
return -EFAULT;
if (value & WDIOS_ENABLECARD)
mtx1_wdt_start();
else if (value & WDIOS_DISABLECARD)
mtx1_wdt_stop();
else
return -EINVAL;
return 0;
case WDIOC_KEEPALIVE:
mtx1_wdt_reset();
break;
default:
return -ENOTTY;
}
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)
return -EIO;
mtx1_wdt_reset();
return count;
}
@ -188,17 +188,17 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count,
static const struct file_operations mtx1_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = mtx1_wdt_ioctl,
.unlocked_ioctl = mtx1_wdt_ioctl,
.open = mtx1_wdt_open,
.write = mtx1_wdt_write,
.release = mtx1_wdt_release
.release = mtx1_wdt_release,
};
static struct miscdevice mtx1_wdt_misc = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &mtx1_wdt_fops
.fops = &mtx1_wdt_fops,
};
@ -208,29 +208,26 @@ static int mtx1_wdt_probe(struct platform_device *pdev)
mtx1_wdt_device.gpio = pdev->resource[0].start;
if ((ret = misc_register(&mtx1_wdt_misc)) < 0) {
spin_lock_init(&mtx1_wdt_device.lock);
init_completion(&mtx1_wdt_device.stop);
mtx1_wdt_device.queue = 0;
clear_bit(0, &mtx1_wdt_device.inuse);
setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L);
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;
}
init_completion(&mtx1_wdt_device.stop);
mtx1_wdt_device.queue = 0;
clear_bit(0, &mtx1_wdt_device.inuse);
setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L);
mtx1_wdt_device.default_ticks = ticks;
mtx1_wdt_start();
printk(KERN_INFO "MTX-1 Watchdog driver\n");
return 0;
}
static int mtx1_wdt_remove(struct platform_device *pdev)
{
/* FIXME: do we need to lock this test ? */
if (mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 0;
wait_for_completion(&mtx1_wdt_device.stop);

View file

@ -8,7 +8,7 @@
* and services the watchdog.
*
* Derived from mpc8xx_wdt.c, with the following copyright.
*
*
* 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
@ -22,10 +22,9 @@
#include <linux/module.h>
#include <linux/watchdog.h>
#include <linux/platform_device.h>
#include <linux/mv643xx.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define MV64x60_WDT_WDC_OFFSET 0
@ -61,7 +60,9 @@ static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
static int nowayout = WATCHDOG_NOWAYOUT;
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)
{
@ -150,7 +151,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,
size_t len, loff_t * ppos)
size_t len, loff_t *ppos)
{
if (len) {
if (!nowayout) {
@ -160,7 +161,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
for (i = 0; i != len; i++) {
char c;
if(get_user(c, data + i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -172,8 +173,8 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
return len;
}
static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long mv64x60_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int timeout;
int options;
@ -240,7 +241,7 @@ static const struct file_operations mv64x60_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mv64x60_wdt_write,
.ioctl = mv64x60_wdt_ioctl,
.unlocked_ioctl = mv64x60_wdt_ioctl,
.open = mv64x60_wdt_open,
.release = mv64x60_wdt_release,
};

View file

@ -40,10 +40,9 @@
#include <linux/moduleparam.h>
#include <linux/clk.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/hardware.h>
#include <asm/arch/prcm.h>
@ -54,11 +53,12 @@ module_param(timer_margin, uint, 0);
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
static int omap_wdt_users;
static struct clk *armwdt_ck = NULL;
static struct clk *mpu_wdt_ick = NULL;
static struct clk *mpu_wdt_fck = NULL;
static struct clk *armwdt_ck;
static struct clk *mpu_wdt_ick;
static struct clk *mpu_wdt_fck;
static unsigned int wdt_trgr_pattern = 0x1234;
static spinlock_t wdt_lock;
static void omap_wdt_ping(void)
{
@ -174,30 +174,29 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
return 0;
}
static ssize_t
omap_wdt_write(struct file *file, const char __user *data,
static ssize_t omap_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
/* Refresh LOAD_TIME. */
if (len)
if (len) {
spin_lock(&wdt_lock);
omap_wdt_ping();
spin_unlock(&wdt_lock);
}
return len;
}
static int
omap_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_margin;
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.identity = "OMAP Watchdog",
.options = WDIOF_SETTIMEOUT,
.firmware_version = 0,
};
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident));
@ -211,28 +210,34 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg);
case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);
omap_wdt_ping();
spin_unlock(&wdt_lock);
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, (int __user *)arg))
return -EFAULT;
omap_wdt_adjust_timeout(new_margin);
spin_lock(&wdt_lock);
omap_wdt_disable();
omap_wdt_set_timeout();
omap_wdt_enable();
omap_wdt_ping();
spin_unlock(&wdt_lock);
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timer_margin, (int __user *)arg);
default:
return -ENOTTY;
}
}
static const struct file_operations omap_wdt_fops = {
.owner = THIS_MODULE,
.write = omap_wdt_write,
.ioctl = omap_wdt_ioctl,
.unlocked_ioctl = omap_wdt_ioctl,
.open = omap_wdt_open,
.release = omap_wdt_release,
};
@ -240,7 +245,7 @@ static const struct file_operations omap_wdt_fops = {
static struct miscdevice omap_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &omap_wdt_fops
.fops = &omap_wdt_fops,
};
static int __init omap_wdt_probe(struct platform_device *pdev)
@ -373,6 +378,7 @@ static struct platform_driver omap_wdt_driver = {
static int __init omap_wdt_init(void)
{
spin_lock_init(&wdt_lock);
return platform_driver_register(&omap_wdt_driver);
}

View file

@ -31,14 +31,14 @@
#include <linux/spinlock.h>
#include <linux/moduleparam.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>
/* #define DEBUG 1 */
#define DEFAULT_TIMEOUT 1 /* 1 minute */
#define DEFAULT_TIMEOUT 1 /* 1 minute */
#define MAX_TIMEOUT 255
#define VERSION "1.1"
@ -46,22 +46,22 @@
#define PFX MODNAME ": "
#define DPFX MODNAME " - DEBUG: "
#define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */
#define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */
#define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1)
#define SWC_LDN 0x04
#define SIOCFG2 0x22 /* Serial IO register */
#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */
#define WDTO 0x11 /* Watchdog timeout register */
#define WDCFG 0x12 /* Watchdog config register */
#define SIOCFG2 0x22 /* Serial IO register */
#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */
#define WDTO 0x11 /* Watchdog timeout register */
#define WDCFG 0x12 /* Watchdog config register */
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 unsigned long timer_enabled = 0; /* is the timer enabled? */
static int timeout = DEFAULT_TIMEOUT; /* timeout value */
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;
@ -69,7 +69,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
/* 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;
@ -77,7 +77,7 @@ static inline void pc87413_select_wdt_out (void)
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*/
outb_p(SIOCFG2, WDT_INDEX_IO_PORT);
@ -85,8 +85,9 @@ static inline void pc87413_select_wdt_out (void)
outb_p(cr_data, WDT_DATA_IO_PORT);
#ifdef DEBUG
printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:"
" Bit7 to 1: %d\n", cr_data);
printk(KERN_INFO DPFX
"Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n",
cr_data);
#endif
}
@ -94,18 +95,18 @@ static inline void pc87413_select_wdt_out (void)
static inline void pc87413_enable_swc(void)
{
unsigned int cr_data=0;
unsigned int cr_data = 0;
/* Step 2: Enable SWC functions */
outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */
outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */
outb_p(SWC_LDN, WDT_DATA_IO_PORT);
outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */
outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */
cr_data = inb(WDT_DATA_IO_PORT);
cr_data |= 0x01; /* Set Bit0 to 1 */
cr_data |= 0x01; /* Set Bit0 to 1 */
outb_p(0x30, WDT_INDEX_IO_PORT);
outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */
outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */
#ifdef DEBUG
printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n");
@ -121,20 +122,19 @@ static inline unsigned int pc87413_get_swc_base(void)
/* Step 3: Read SWC I/O Base Address */
outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */
outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */
addr_h = inb(WDT_DATA_IO_PORT);
outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */
outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */
addr_l = inb(WDT_DATA_IO_PORT);
swc_base_addr = (addr_h << 8) + addr_l;
#ifdef DEBUG
printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d,"
" res %d\n", addr_l, addr_h, swc_base_addr);
printk(KERN_INFO DPFX
"Read SWC I/O Base Address: low %d, high %d, res %d\n",
addr_l, addr_h, swc_base_addr);
#endif
return swc_base_addr;
}
@ -143,9 +143,7 @@ static inline unsigned int pc87413_get_swc_base(void)
static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
{
/* Step 4: Select Bank3 of SWC */
outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
#ifdef DEBUG
printk(KERN_INFO DPFX "Select Bank3 of SWC\n");
#endif
@ -157,9 +155,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
char pc87413_time)
{
/* Step 5: Programm WDTO, Twd. */
outb_p(pc87413_time, swc_base_addr + WDTO);
#ifdef DEBUG
printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);
#endif
@ -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)
{
/* 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
printk(KERN_INFO DPFX "Enable WDEN\n");
#endif
@ -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)
{
/* 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
printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");
#endif
@ -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)
{
/* 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
printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");
#endif
@ -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)
{
/* 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
printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");
#endif
@ -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)
{
/* 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
printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");
#endif
@ -314,8 +300,8 @@ static int pc87413_open(struct inode *inode, struct file *file)
/* Reload and activate timer */
pc87413_refresh();
printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to"
" %d minute(s).\n", timeout);
printk(KERN_INFO MODNAME
"Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
return nonseekable_open(inode, file);
}
@ -338,17 +324,15 @@ static int pc87413_release(struct inode *inode, struct file *file)
if (expect_close == 42) {
pc87413_disable();
printk(KERN_INFO MODNAME "Watchdog disabled,"
" sleeping again...\n");
printk(KERN_INFO MODNAME
"Watchdog disabled, sleeping again...\n");
} else {
printk(KERN_CRIT MODNAME "Unexpected close, not stopping"
" watchdog!\n");
printk(KERN_CRIT MODNAME
"Unexpected close, not stopping watchdog!\n");
pc87413_refresh();
}
clear_bit(0, &timer_enabled);
expect_close = 0;
return 0;
}
@ -386,10 +370,11 @@ static ssize_t pc87413_write(struct file *file, const char __user *data,
/* reset expect flag */
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++) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -404,7 +389,6 @@ static ssize_t pc87413_write(struct file *file, const char __user *data,
/**
* pc87413_ioctl:
* @inode: inode of the device
* @file: file handle to the device
* @cmd: watchdog command
* @arg: argument pointer
@ -414,8 +398,8 @@ static ssize_t pc87413_write(struct file *file, const char __user *data,
* querying capabilities and current status.
*/
static int pc87413_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long pc87413_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_timeout;
@ -426,75 +410,58 @@ static int pc87413_ioctl(struct inode *inode, struct file *file,
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "PC87413(HF/F) watchdog"
.identity = "PC87413(HF/F) watchdog",
};
uarg.i = (int __user *)arg;
switch(cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident,
sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
return put_user(pc87413_status(), uarg.i);
case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_KEEPALIVE:
pc87413_refresh();
#ifdef DEBUG
printk(KERN_INFO DPFX "keepalive\n");
#endif
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, uarg.i))
return -EFAULT;
// the API states this is given in secs
new_timeout /= 60;
if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
return -EINVAL;
timeout = new_timeout;
pc87413_refresh();
// fall through and return the new timeout...
case WDIOC_GETTIMEOUT:
new_timeout = timeout * 60;
return put_user(new_timeout, uarg.i);
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;
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident,
sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
return put_user(pc87413_status(), uarg.i);
case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
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;
}
case WDIOC_KEEPALIVE:
pc87413_refresh();
#ifdef DEBUG
printk(KERN_INFO DPFX "keepalive\n");
#endif
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, uarg.i))
return -EFAULT;
/* the API states this is given in secs */
new_timeout /= 60;
if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
return -EINVAL;
timeout = new_timeout;
pc87413_refresh();
/* fall through and return the new timeout... */
case WDIOC_GETTIMEOUT:
new_timeout = timeout * 60;
return put_user(new_timeout, uarg.i);
default:
return -ENOTTY;
}
}
@ -517,10 +484,8 @@ static int pc87413_notify_sys(struct notifier_block *this,
void *unused)
{
if (code == SYS_DOWN || code == SYS_HALT)
{
/* Turn the card off */
pc87413_disable();
}
return NOTIFY_DONE;
}
@ -530,21 +495,19 @@ static const struct file_operations pc87413_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pc87413_write,
.ioctl = pc87413_ioctl,
.unlocked_ioctl = pc87413_ioctl,
.open = pc87413_open,
.release = pc87413_release,
};
static struct notifier_block pc87413_notifier =
{
static struct notifier_block pc87413_notifier = {
.notifier_call = pc87413_notify_sys,
};
static struct miscdevice pc87413_miscdev=
{
static struct miscdevice pc87413_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &pc87413_fops
.fops = &pc87413_fops,
};
/* -- Module init functions -------------------------------------*/
@ -561,29 +524,26 @@ static int __init pc87413_init(void)
{
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"); */
ret = register_reboot_notifier(&pc87413_notifier);
if (ret != 0) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
}
ret = misc_register(&pc87413_miscdev);
if (ret != 0) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&pc87413_notifier);
return ret;
}
printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
pc87413_enable();
return 0;
}
@ -600,17 +560,16 @@ static int __init pc87413_init(void)
static void __exit pc87413_exit(void)
{
/* Stop the timer before we leave */
if (!nowayout)
{
if (!nowayout) {
pc87413_disable();
printk(KERN_INFO MODNAME "Watchdog disabled.\n");
}
misc_deregister(&pc87413_miscdev);
unregister_reboot_notifier(&pc87413_notifier);
/* release_region(io,2); */
/* release_region(io, 2); */
printk(MODNAME " watchdog component driver removed.\n");
printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
}
module_init(pc87413_init);
@ -626,8 +585,12 @@ module_param(io, int, 0);
MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ").");
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_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) ")");

View file

@ -40,13 +40,15 @@
* fairly useless proc entry.
* 990610 removed said useless proc code for the merge <alan>
* 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
*/
/*
* 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 */
@ -65,9 +67,8 @@
#include <linux/isa.h> /* For isa devices */
#include <linux/ioport.h> /* For io-port access */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/io.h> /* For inb/outb/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <linux/io.h> /* For inb/outb/... */
/* Module and version information */
#define WATCHDOG_VERSION "1.20"
@ -111,14 +112,16 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */
#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */
#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_R2DS 0x40 /* Relay 2 disable */
#define WD_REVC_RLY2 0x80 /* Relay 2 activated? */
/* Port 2 : Control Status #2 */
#define WD_WDIS 0x10 /* Watchdog Disabled */
#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 */
/* max. time we give an ISA watchdog card to process a command */
@ -142,7 +145,7 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
#define CMD_ISA_RESET_RELAYS 0x0D
/* Watchdog's Dip Switch heartbeat values */
static const int heartbeat_tbl [] = {
static const int heartbeat_tbl[] = {
20, /* OFF-OFF-OFF = 20 Sec */
40, /* OFF-OFF-ON = 40 Sec */
60, /* OFF-ON-OFF = 1 Min */
@ -168,11 +171,15 @@ static int cards_found;
static atomic_t open_allowed = ATOMIC_INIT(1);
static char expect_close;
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 */
int revision; /* The card's revision */
int supports_temp; /* Wether or not the card has a temperature device */
int command_mode; /* Wether or not the card is in command mode */
int supports_temp; /* Whether or not the card has
a temperature device */
int command_mode; /* Whether or not the card is in
command mode */
int boot_status; /* The card's boot status */
int io_addr; /* The cards I/O address */
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 */
#define DEBUG 2 /* print fancy stuff too */
static int debug = QUIET;
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;
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;
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
@ -224,7 +235,7 @@ static int send_isa_command(int cmd)
if (port0 == last_port0)
break; /* Data is stable */
udelay (250);
udelay(250);
}
if (debug >= DEBUG)
@ -236,7 +247,7 @@ static int send_isa_command(int cmd)
static int set_command_mode(void)
{
int i, found=0, count=0;
int i, found = 0, count = 0;
/* Set the card into command mode */
spin_lock(&pcwd_private.io_lock);
@ -261,7 +272,7 @@ static int set_command_mode(void)
printk(KERN_DEBUG PFX "command_mode=%d\n",
pcwd_private.command_mode);
return(found);
return found;
}
static void unset_command_mode(void)
@ -296,7 +307,8 @@ static inline void pcwd_get_firmware(void)
ten = send_isa_command(CMD_ISA_VERSION_TENTH);
hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
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();
@ -305,7 +317,7 @@ static inline void pcwd_get_firmware(void)
static inline int pcwd_get_option_switches(void)
{
int option_switches=0;
int option_switches = 0;
if (set_command_mode()) {
/* Get switch settings */
@ -313,7 +325,7 @@ static inline int pcwd_get_option_switches(void)
}
unset_command_mode();
return(option_switches);
return option_switches;
}
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) */
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) {
pcwd_get_firmware();
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)
printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
printk(KERN_EMERG PFX "CPU Overheat\n");
printk(KERN_EMERG PFX
"Card senses a CPU Overheat. Panicking!\n");
printk(KERN_EMERG PFX
"CPU Overheat\n");
}
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)
@ -361,11 +378,12 @@ static void pcwd_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_INTERVAL
* 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 */
spin_lock(&pcwd_private.io_lock);
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 &= 0x0F;
wdrst_stat |= WD_WDRST;
@ -381,7 +399,8 @@ static void pcwd_timer_ping(unsigned long data)
spin_unlock(&pcwd_private.io_lock);
} 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)
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;
heartbeat = t;
@ -470,7 +489,7 @@ static int pcwd_get_status(int *status)
{
int control_status;
*status=0;
*status = 0;
spin_lock(&pcwd_private.io_lock);
if (pcwd_private.revision == PCWD_REVISION_A)
/* Rev A cards return status information from
@ -494,9 +513,9 @@ static int pcwd_get_status(int *status)
if (control_status & WD_T110) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
printk(KERN_INFO PFX "Temperature overheat trip!\n");
printk(KERN_INFO PFX
"Temperature overheat trip!\n");
kernel_power_off();
/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
}
}
} else {
@ -506,9 +525,9 @@ static int pcwd_get_status(int *status)
if (control_status & WD_REVC_TTRP) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
printk(KERN_INFO PFX "Temperature overheat trip!\n");
printk(KERN_INFO PFX
"Temperature overheat trip!\n");
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)
spin_lock(&pcwd_private.io_lock);
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);
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",
(control_status & WD_REVC_R2DS));
}
/* 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);
}
@ -572,8 +594,7 @@ static int pcwd_get_temperature(int *temperature)
* /dev/watchdog handling
*/
static int pcwd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int rv;
int status;
@ -590,12 +611,9 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
.identity = "PCWD",
};
switch(cmd) {
default:
return -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident)))
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
return 0;
@ -613,25 +631,22 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
return put_user(temperature, argp);
case WDIOC_SETOPTIONS:
if (pcwd_private.revision == PCWD_REVISION_C)
{
if(copy_from_user(&rv, argp, sizeof(int)))
if (pcwd_private.revision == PCWD_REVISION_C) {
if (get_user(rv, argp))
return -EFAULT;
if (rv & WDIOS_DISABLECARD)
{
return pcwd_stop();
if (rv & WDIOS_DISABLECARD) {
status = pcwd_stop();
if (status < 0)
return status;
}
if (rv & WDIOS_ENABLECARD)
{
return pcwd_start();
if (rv & WDIOS_ENABLECARD) {
status = pcwd_start();
if (status < 0)
return status;
}
if (rv & WDIOS_TEMPPANIC)
{
temp_panic = 1;
}
}
return -EINVAL;
@ -651,6 +666,9 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, argp);
default:
return -ENOTTY;
}
return 0;
@ -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)
{
if (!atomic_dec_and_test(&open_allowed) ) {
if (debug >= VERBOSE)
printk(KERN_ERR PFX "Attempt to open already opened device.\n");
atomic_inc( &open_allowed );
if (test_and_set_bit(0, &open_allowed))
return -EBUSY;
}
if (nowayout)
__module_get(THIS_MODULE);
/* Activate */
pcwd_start();
pcwd_keepalive();
@ -700,14 +712,15 @@ static int pcwd_open(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();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
else {
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
pcwd_keepalive();
}
expect_close = 0;
atomic_inc( &open_allowed );
clear_bit(0, &open_allowed);
return 0;
}
@ -750,7 +763,7 @@ static const struct file_operations pcwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pcwd_write,
.ioctl = pcwd_ioctl,
.unlocked_ioctl = pcwd_ioctl,
.open = pcwd_open,
.release = pcwd_close,
};
@ -788,7 +801,7 @@ static inline int get_revision(void)
* presumes a floating bus reads as 0xff. */
if ((inb(pcwd_private.io_addr + 2) == 0xFF) ||
(inb(pcwd_private.io_addr + 3) == 0xFF))
r=PCWD_REVISION_A;
r = PCWD_REVISION_A;
spin_unlock(&pcwd_private.io_lock);
return r;
@ -803,7 +816,7 @@ static inline int get_revision(void)
*/
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 port1, last_port1; /* Register 1 for REV C cards */
int i;
@ -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",
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);
return 0;
}
@ -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;
}
@ -857,7 +870,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
cards_found++;
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) {
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)
/* Check card's 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",
pcwd_private.io_addr);
ret=-EIO;
ret = -EIO;
goto error_request_region;
}
@ -908,26 +923,30 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
if (heartbeat == 0)
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)) {
pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
WATCHDOG_HEARTBEAT);
printk(KERN_INFO PFX
"heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
WATCHDOG_HEARTBEAT);
}
if (pcwd_private.supports_temp) {
ret = misc_register(&temp_miscdev);
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
TEMP_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
TEMP_MINOR, ret);
goto error_misc_register_temp;
}
}
ret = misc_register(&pcwd_miscdev);
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto error_misc_register_watchdog;
}
@ -940,7 +959,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
if (pcwd_private.supports_temp)
misc_deregister(&temp_miscdev);
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:
pcwd_private.io_addr = 0x0000;
cards_found--;
@ -964,7 +984,8 @@ static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
misc_deregister(&pcwd_miscdev);
if (pcwd_private.supports_temp)
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;
cards_found--;

View file

@ -46,9 +46,8 @@
#include <linux/pci.h> /* For pci functions */
#include <linux/ioport.h> /* For io-port access */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/io.h> /* For inb/outb/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <linux/io.h> /* For inb/outb/... */
/* Module and version information */
#define WATCHDOG_VERSION "1.03"
@ -97,7 +96,7 @@
#define CMD_GET_CLEAR_RESET_COUNT 0x84
/* Watchdog's Dip Switch heartbeat values */
static const int heartbeat_tbl [] = {
static const int heartbeat_tbl[] = {
5, /* OFF-OFF-OFF = 5 Sec */
10, /* OFF-OFF-ON = 10 Sec */
30, /* OFF-ON-OFF = 30 Sec */
@ -220,11 +219,10 @@ static void pcipcwd_show_card_info(void)
int option_switches;
got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
if (got_fw_rev) {
if (got_fw_rev)
sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
} else {
else
sprintf(fw_ver_str, "<card no answer>");
}
/* Get switch settings */
option_switches = pcipcwd_get_option_switches();
@ -331,7 +329,7 @@ static int pcipcwd_get_status(int *status)
{
int control_status;
*status=0;
*status = 0;
control_status = inb_p(pcipcwd_private.io_addr + 1);
if (control_status & WD_PCI_WTRP)
*status |= WDIOF_CARDRESET;
@ -369,8 +367,8 @@ static int pcipcwd_clear_status(void)
outb_p((control_status & WD_PCI_R2DS) | WD_PCI_WTRP, pcipcwd_private.io_addr + 1);
/* clear reset counter */
msb=0;
reset_counter=0xff;
msb = 0;
reset_counter = 0xff;
send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);
if (debug >= DEBUG) {
@ -442,7 +440,7 @@ static ssize_t pcipcwd_write(struct file *file, const char __user *data,
/* scan to see whether or not we got the magic character */
for (i = 0; i != len; i++) {
char c;
if(get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_release = 42;
@ -455,8 +453,8 @@ static ssize_t pcipcwd_write(struct file *file, const char __user *data,
return len;
}
static int pcipcwd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long pcipcwd_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@ -471,92 +469,89 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof (ident)) ? -EFAULT : 0;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
{
int status;
case WDIOC_GETSTATUS:
{
int status;
pcipcwd_get_status(&status);
return put_user(status, p);
}
pcipcwd_get_status(&status);
case WDIOC_GETBOOTSTATUS:
return put_user(pcipcwd_private.boot_status, p);
return put_user(status, p);
case WDIOC_GETTEMP:
{
int temperature;
if (pcipcwd_get_temperature(&temperature))
return -EFAULT;
return put_user(temperature, p);
}
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
if (pcipcwd_stop())
return -EIO;
retval = 0;
}
case WDIOC_GETBOOTSTATUS:
return put_user(pcipcwd_private.boot_status, p);
case WDIOC_GETTEMP:
{
int temperature;
if (pcipcwd_get_temperature(&temperature))
return -EFAULT;
return put_user(temperature, p);
if (new_options & WDIOS_ENABLECARD) {
if (pcipcwd_start())
return -EIO;
retval = 0;
}
case WDIOC_KEEPALIVE:
pcipcwd_keepalive();
return 0;
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if (get_user (new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
if (pcipcwd_stop())
return -EIO;
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
if (pcipcwd_start())
return -EIO;
retval = 0;
}
if (new_options & WDIOS_TEMPPANIC) {
temp_panic = 1;
retval = 0;
}
return retval;
if (new_options & WDIOS_TEMPPANIC) {
temp_panic = 1;
retval = 0;
}
case WDIOC_SETTIMEOUT:
{
int new_heartbeat;
return retval;
}
if (get_user(new_heartbeat, p))
return -EFAULT;
case WDIOC_KEEPALIVE:
pcipcwd_keepalive();
return 0;
if (pcipcwd_set_heartbeat(new_heartbeat))
return -EINVAL;
case WDIOC_SETTIMEOUT:
{
int new_heartbeat;
pcipcwd_keepalive();
/* Fall */
}
if (get_user(new_heartbeat, p))
return -EFAULT;
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
if (pcipcwd_set_heartbeat(new_heartbeat))
return -EINVAL;
case WDIOC_GETTIMELEFT:
{
int time_left;
pcipcwd_keepalive();
/* Fall */
}
if (pcipcwd_get_timeleft(&time_left))
return -EFAULT;
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
return put_user(time_left, p);
}
case WDIOC_GETTIMELEFT:
{
int time_left;
default:
return -ENOTTY;
if (pcipcwd_get_timeleft(&time_left))
return -EFAULT;
return put_user(time_left, p);
}
default:
return -ENOTTY;
}
}
@ -603,7 +598,7 @@ static ssize_t pcipcwd_temp_read(struct file *file, char __user *data,
if (pcipcwd_get_temperature(&temperature))
return -EFAULT;
if (copy_to_user (data, &temperature, 1))
if (copy_to_user(data, &temperature, 1))
return -EFAULT;
return 1;
@ -628,10 +623,8 @@ static int pcipcwd_temp_release(struct inode *inode, struct file *file)
static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
{
if (code==SYS_DOWN || code==SYS_HALT) {
/* Turn the WDT off */
pcipcwd_stop();
}
if (code == SYS_DOWN || code == SYS_HALT)
pcipcwd_stop(); /* Turn the WDT off */
return NOTIFY_DONE;
}
@ -644,7 +637,7 @@ static const struct file_operations pcipcwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pcipcwd_write,
.ioctl = pcipcwd_ioctl,
.unlocked_ioctl = pcipcwd_ioctl,
.open = pcipcwd_open,
.release = pcipcwd_release,
};

View file

@ -40,8 +40,7 @@
#include <linux/slab.h> /* For kmalloc, ... */
#include <linux/mutex.h> /* For mutex locking */
#include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */
#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#ifdef CONFIG_USB_DEBUG
@ -88,7 +87,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
#define USB_PCWD_PRODUCT_ID 0x1140
/* table of devices that work with this driver */
static struct usb_device_id usb_pcwd_table [] = {
static struct usb_device_id usb_pcwd_table[] = {
{ USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) },
{ } /* Terminating entry */
};
@ -110,7 +109,7 @@ MODULE_DEVICE_TABLE (usb, usb_pcwd_table);
#define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG
/* Watchdog's Dip Switch heartbeat values */
static const int heartbeat_tbl [] = {
static const int heartbeat_tbl[] = {
5, /* OFF-OFF-OFF = 5 Sec */
10, /* OFF-OFF-ON = 10 Sec */
30, /* OFF-ON-OFF = 30 Sec */
@ -130,15 +129,15 @@ static char expect_release;
/* Structure to hold all of our device specific stuff */
struct usb_pcwd_private {
struct usb_device * udev; /* save off the usb device pointer */
struct usb_interface * interface; /* the interface for this device */
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
unsigned int interface_number; /* the interface number used for cmd's */
unsigned char * intr_buffer; /* the buffer to intr data */
unsigned char *intr_buffer; /* the buffer to intr data */
dma_addr_t intr_dma; /* the dma address for the intr buffer */
size_t intr_size; /* the size of the intr buffer */
struct urb * intr_urb; /* the urb used for the intr pipe */
struct urb *intr_urb; /* the urb used for the intr pipe */
unsigned char cmd_command; /* The command that is reported back */
unsigned char cmd_data_msb; /* The data MSB that is reported back */
@ -154,8 +153,8 @@ static struct usb_pcwd_private *usb_pcwd_device;
static DEFINE_MUTEX(disconnect_mutex);
/* local function prototypes */
static int usb_pcwd_probe (struct usb_interface *interface, const struct usb_device_id *id);
static void usb_pcwd_disconnect (struct usb_interface *interface);
static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_device_id *id);
static void usb_pcwd_disconnect(struct usb_interface *interface);
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver usb_pcwd_driver = {
@ -195,10 +194,10 @@ static void usb_pcwd_intr_done(struct urb *urb)
usb_pcwd->cmd_data_lsb = data[2];
/* notify anyone waiting that the cmd has finished */
atomic_set (&usb_pcwd->cmd_received, 1);
atomic_set(&usb_pcwd->cmd_received, 1);
resubmit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n",
retval);
@ -224,7 +223,7 @@ static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned cha
dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
buf[0], buf[1], buf[2]);
atomic_set (&usb_pcwd->cmd_received, 0);
atomic_set(&usb_pcwd->cmd_received, 0);
if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0),
HID_REQ_SET_REPORT, HID_DT_REPORT,
@ -237,7 +236,7 @@ static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned cha
got_response = 0;
for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) {
mdelay(1);
if (atomic_read (&usb_pcwd->cmd_received))
if (atomic_read(&usb_pcwd->cmd_received))
got_response = 1;
}
@ -356,7 +355,7 @@ static ssize_t usb_pcwd_write(struct file *file, const char __user *data,
/* scan to see whether or not we got the magic character */
for (i = 0; i != len; i++) {
char c;
if(get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_release = 42;
@ -369,8 +368,8 @@ static ssize_t usb_pcwd_write(struct file *file, const char __user *data,
return len;
}
static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long usb_pcwd_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@ -383,77 +382,76 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof (ident)) ? -EFAULT : 0;
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_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_GETTEMP:
{
int temperature;
case WDIOC_GETTEMP:
{
int temperature;
if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
return -EFAULT;
if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
return -EFAULT;
return put_user(temperature, p);
return put_user(temperature, p);
}
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
usb_pcwd_stop(usb_pcwd_device);
retval = 0;
}
case WDIOC_KEEPALIVE:
usb_pcwd_keepalive(usb_pcwd_device);
return 0;
case WDIOC_SETOPTIONS:
{
int new_options, retval = -EINVAL;
if (get_user (new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
usb_pcwd_stop(usb_pcwd_device);
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
usb_pcwd_start(usb_pcwd_device);
retval = 0;
}
return retval;
if (new_options & WDIOS_ENABLECARD) {
usb_pcwd_start(usb_pcwd_device);
retval = 0;
}
case WDIOC_SETTIMEOUT:
{
int new_heartbeat;
return retval;
}
if (get_user(new_heartbeat, p))
return -EFAULT;
case WDIOC_KEEPALIVE:
usb_pcwd_keepalive(usb_pcwd_device);
return 0;
if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat))
return -EINVAL;
case WDIOC_SETTIMEOUT:
{
int new_heartbeat;
usb_pcwd_keepalive(usb_pcwd_device);
/* Fall */
}
if (get_user(new_heartbeat, p))
return -EFAULT;
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat))
return -EINVAL;
case WDIOC_GETTIMELEFT:
{
int time_left;
usb_pcwd_keepalive(usb_pcwd_device);
/* Fall */
}
if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
return -EFAULT;
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
return put_user(time_left, p);
}
case WDIOC_GETTIMELEFT:
{
int time_left;
default:
return -ENOTTY;
if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
return -EFAULT;
return put_user(time_left, p);
}
default:
return -ENOTTY;
}
}
@ -519,10 +517,8 @@ static int usb_pcwd_temperature_release(struct inode *inode, struct file *file)
static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
{
if (code==SYS_DOWN || code==SYS_HALT) {
/* Turn the WDT off */
usb_pcwd_stop(usb_pcwd_device);
}
if (code == SYS_DOWN || code == SYS_HALT)
usb_pcwd_stop(usb_pcwd_device); /* Turn the WDT off */
return NOTIFY_DONE;
}
@ -535,7 +531,7 @@ static const struct file_operations usb_pcwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = usb_pcwd_write,
.ioctl = usb_pcwd_ioctl,
.unlocked_ioctl = usb_pcwd_ioctl,
.open = usb_pcwd_open,
.release = usb_pcwd_release,
};
@ -567,13 +563,13 @@ static struct notifier_block usb_pcwd_notifier = {
/**
* usb_pcwd_delete
*/
static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd)
static inline void usb_pcwd_delete(struct usb_pcwd_private *usb_pcwd)
{
usb_free_urb(usb_pcwd->intr_urb);
if (usb_pcwd->intr_buffer != NULL)
usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size,
usb_pcwd->intr_buffer, usb_pcwd->intr_dma);
kfree (usb_pcwd);
kfree(usb_pcwd);
}
/**
@ -626,7 +622,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
/* allocate memory for our device and initialize it */
usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
if (usb_pcwd == NULL) {
printk(KERN_ERR PFX "Out of memory\n");
goto error;
@ -641,7 +637,8 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8);
/* set up the memory buffer's */
if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) {
usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma);
if (!usb_pcwd->intr_buffer) {
printk(KERN_ERR PFX "Out of memory\n");
goto error;
}
@ -675,11 +672,10 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
/* Get the Firmware Version */
got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
if (got_fw_rev) {
if (got_fw_rev)
sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
} else {
else
sprintf(fw_ver_str, "<card no answer>");
}
printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n",
fw_ver_str);
@ -725,7 +721,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
}
/* we can register the device now, as it is ready */
usb_set_intfdata (interface, usb_pcwd);
usb_set_intfdata(interface, usb_pcwd);
printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
@ -759,8 +755,8 @@ static void usb_pcwd_disconnect(struct usb_interface *interface)
/* prevent races with open() */
mutex_lock(&disconnect_mutex);
usb_pcwd = usb_get_intfdata (interface);
usb_set_intfdata (interface, NULL);
usb_pcwd = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
mutex_lock(&usb_pcwd->mtx);
@ -820,5 +816,5 @@ static void __exit usb_pcwd_exit(void)
}
module_init (usb_pcwd_init);
module_exit (usb_pcwd_exit);
module_init(usb_pcwd_init);
module_exit(usb_pcwd_exit);

View file

@ -28,10 +28,10 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define MODULE_NAME "PNX4008-WDT: "
@ -144,9 +144,8 @@ static int pnx4008_wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static ssize_t
pnx4008_wdt_write(struct file *file, const char *data, size_t len,
loff_t * ppos)
static ssize_t pnx4008_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{
if (len) {
if (!nowayout) {
@ -169,15 +168,14 @@ pnx4008_wdt_write(struct file *file, const char *data, size_t len,
return len;
}
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "PNX4008 Watchdog",
};
static int
pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long pnx4008_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = -ENOTTY;
int time;
@ -196,6 +194,11 @@ pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = put_user(boot_status, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
if (ret)
@ -213,11 +216,6 @@ pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
}
return ret;
}
@ -238,7 +236,7 @@ static const struct file_operations pnx4008_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pnx4008_wdt_write,
.ioctl = pnx4008_wdt_ioctl,
.unlocked_ioctl = pnx4008_wdt_ioctl,
.open = pnx4008_wdt_open,
.release = pnx4008_wdt_release,
};

View file

@ -29,10 +29,10 @@
#include <linux/notifier.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <asm/io.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/rm9k-ocd.h>
@ -53,10 +53,12 @@ static void wdt_gpi_stop(void);
static void wdt_gpi_set_timeout(unsigned int);
static int wdt_gpi_open(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 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 __exit wdt_gpi_remove(struct device *);
@ -68,7 +70,7 @@ static int locked;
/* These are set from device resources */
static void __iomem * wd_regs;
static void __iomem *wd_regs;
static unsigned int wd_irq, wd_ctr;
@ -216,7 +218,8 @@ static int wdt_gpi_release(struct inode *inode, struct file *file)
if (expect_close) {
wdt_gpi_stop();
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 {
printk(KERN_CRIT "%s: unexpected close() -"
" watchdog left running\n",
@ -231,8 +234,8 @@ static int wdt_gpi_release(struct inode *inode, struct file *file)
return 0;
}
static ssize_t
wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o)
static ssize_t wdt_gpi_write(struct file *f, const char __user *d, size_t s,
loff_t *o)
{
char val;
@ -241,8 +244,7 @@ wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o)
return s ? 1 : 0;
}
static long
wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
static long wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
long res = -ENOTTY;
const long size = _IOC_SIZE(cmd);
@ -271,7 +273,8 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
case WDIOC_GETSUPPORT:
wdinfo.options = nowayout ?
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;
break;
@ -322,8 +325,8 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
/* Shutdown notifier */
static int
wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused)
static int wdt_gpi_notify(struct notifier_block *this, unsigned long code,
void *unused)
{
if (code == SYS_DOWN || code == SYS_HALT)
wdt_gpi_stop();
@ -333,9 +336,8 @@ wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused)
/* Init & exit procedures */
static const struct resource *
wdt_gpi_get_resource(struct platform_device *pdv, const char *name,
unsigned int type)
static const struct resource *wdt_gpi_get_resource(struct platform_device *pdv,
const char *name, unsigned int type)
{
char buf[80];
if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf)

View file

@ -305,8 +305,6 @@ static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd,
int new_margin;
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &s3c2410_wdt_ident,
sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;
@ -325,6 +323,8 @@ static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd,
return put_user(tmr_margin, p);
case WDIOC_GETTIMEOUT:
return put_user(tmr_margin, p);
default:
return -ENOTTY;
}
}

View file

@ -26,13 +26,13 @@
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
#ifdef CONFIG_ARCH_PXA
#include <asm/arch/pxa-regs.h>
#endif
#include <asm/hardware.h>
#include <asm/uaccess.h>
#define OSCR_FREQ CLOCK_TICK_RATE
@ -45,7 +45,7 @@ static int boot_status;
*/
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;
/* Activate SA1100 Watchdog timer */
@ -66,28 +66,27 @@ static int sa1100dog_open(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");
clear_bit(1, &sa1100wdt_users);
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)
/* Refresh OSMR3 timer. */
OSMR3 = OSCR + pre_margin;
return len;
}
static struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING,
.identity = "SA1100/PXA255 Watchdog",
};
static int sa1100dog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = -ENOTTY;
int time;
@ -108,6 +107,11 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file,
ret = put_user(boot_status, p);
break;
case WDIOC_KEEPALIVE:
OSMR3 = OSCR + pre_margin;
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, p);
if (ret)
@ -125,27 +129,20 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
ret = put_user(pre_margin / OSCR_FREQ, p);
break;
case WDIOC_KEEPALIVE:
OSMR3 = OSCR + pre_margin;
ret = 0;
break;
}
return ret;
}
static const struct file_operations sa1100dog_fops =
{
static const struct file_operations sa1100dog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sa1100dog_write,
.ioctl = sa1100dog_ioctl,
.unlocked_ioctl = sa1100dog_ioctl,
.open = sa1100dog_open,
.release = sa1100dog_release,
};
static struct miscdevice sa1100dog_miscdev =
{
static struct miscdevice sa1100dog_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &sa1100dog_fops,
@ -167,8 +164,9 @@ static int __init sa1100dog_init(void)
ret = misc_register(&sa1100dog_miscdev);
if (ret == 0)
printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
margin);
printk(KERN_INFO
"SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
margin);
return ret;
}

View file

@ -57,6 +57,7 @@
#include <asm/sibyte/sb1250_int.h>
#include <asm/sibyte/sb1250_scd.h>
static DEFINE_SPINLOCK(sbwd_lock);
/*
* set the initial count value of a timer
@ -65,8 +66,10 @@
*/
void sbwdog_set(char __iomem *wdog, unsigned long t)
{
spin_lock(&sbwd_lock);
__raw_writeb(0, wdog - 0x10);
__raw_writeq(t & 0x7fffffUL, wdog);
spin_unlock(&sbwd_lock);
}
/*
@ -77,7 +80,9 @@ void sbwdog_set(char __iomem *wdog, unsigned long t)
*/
void sbwdog_pet(char __iomem *wdog)
{
spin_lock(&sbwd_lock);
__raw_writeb(__raw_readb(wdog) | 1, wdog);
spin_unlock(&sbwd_lock);
}
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));
static unsigned long timeout = 0x7fffffUL; /* useconds: 8.3ish secs. */
static int expect_close;
static struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
.identity = "SiByte Watchdog",
};
@ -97,9 +103,8 @@ static struct watchdog_info ident = {
static int sbwdog_open(struct inode *inode, struct file *file)
{
nonseekable_open(inode, file);
if (test_and_set_bit(0, &sbwdog_gate)) {
if (test_and_set_bit(0, &sbwdog_gate))
return -EBUSY;
}
__module_get(THIS_MODULE);
/*
@ -120,8 +125,9 @@ static int sbwdog_release(struct inode *inode, struct file *file)
__raw_writeb(0, user_dog);
module_put(THIS_MODULE);
} else {
printk(KERN_CRIT "%s: Unexpected close, not stopping watchdog!\n",
ident.identity);
printk(KERN_CRIT
"%s: Unexpected close, not stopping watchdog!\n",
ident.identity);
sbwdog_pet(user_dog);
}
clear_bit(0, &sbwdog_gate);
@ -147,12 +153,10 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data,
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i)) {
if (get_user(c, data + i))
return -EFAULT;
}
if (c == 'V') {
if (c == 'V')
expect_close = 42;
}
}
sbwdog_pet(user_dog);
}
@ -160,8 +164,8 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data,
return len;
}
static int sbwdog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long sbwdog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = -ENOTTY;
unsigned long time;
@ -178,11 +182,15 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file,
ret = put_user(0, p);
break;
case WDIOC_KEEPALIVE:
sbwdog_pet(user_dog);
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, p);
if (ret) {
if (ret)
break;
}
time *= 1000000;
if (time > 0x7fffffUL) {
@ -200,11 +208,6 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file,
*/
ret = put_user(__raw_readq(user_dog - 8) / 1000000, p);
break;
case WDIOC_KEEPALIVE:
sbwdog_pet(user_dog);
ret = 0;
break;
}
return ret;
}
@ -212,8 +215,8 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file,
/*
* Notifier for system down
*/
static int
sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf)
static int sbwdog_notify_sys(struct notifier_block *this, unsigned long code,
void *erf)
{
if (code == SYS_DOWN || code == SYS_HALT) {
/*
@ -226,18 +229,16 @@ sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf)
return NOTIFY_DONE;
}
static const struct file_operations sbwdog_fops =
{
static const struct file_operations sbwdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sbwdog_write,
.ioctl = sbwdog_ioctl,
.unlocked_ioctl = sbwdog_ioctl,
.open = sbwdog_open,
.release = sbwdog_release,
};
static struct miscdevice sbwdog_miscdev =
{
static struct miscdevice sbwdog_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &sbwdog_fops,
@ -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 (wd_cfg_reg == user_dog) {
if (wd_cfg_reg == user_dog)
printk(KERN_CRIT
"%s in danger of initiating system reset in %ld.%01ld seconds\n",
ident.identity, wd_init / 1000000, (wd_init / 100000) % 10);
} else {
else
cfg |= 1;
}
__raw_writeb(cfg, wd_cfg_reg);
@ -289,28 +289,31 @@ static int __init sbwdog_init(void)
*/
ret = register_reboot_notifier(&sbwdog_notifier);
if (ret) {
printk (KERN_ERR "%s: cannot register reboot notifier (err=%d)\n",
ident.identity, ret);
printk(KERN_ERR
"%s: cannot register reboot notifier (err=%d)\n",
ident.identity, ret);
return ret;
}
/*
* 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,
ident.identity, (void *)user_dog);
if (ret) {
printk(KERN_ERR "%s: failed to request irq 1 - %d\n", ident.identity,
ret);
misc_deregister(&sbwdog_miscdev);
printk(KERN_ERR "%s: failed to request irq 1 - %d\n",
ident.identity, ret);
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;
}
@ -327,7 +330,7 @@ MODULE_DESCRIPTION("SiByte Watchdog");
module_param(timeout, ulong, 0);
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_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
* first watchdog timer for the kernels own purpose.
void
platform_wd_setup(void)
void platform_wd_setup(void)
{
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));
if (ret) {
printk(KERN_CRIT "Watchdog IRQ zero(0) failed to be requested - %d\n",
ret);
printk(KERN_CRIT
"Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
}
}

View file

@ -16,19 +16,23 @@
*
* 12/4 - 2000 [Initial revision]
* 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
* fix possible wdt_is_open race
* add CONFIG_WATCHDOG_NOWAYOUT support
* remove lock_kernel/unlock_kernel pairs
* added KERN_* to printk's
* got rid of extraneous comments
* changed watchdog_info to correctly reflect what the driver offers
* added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
* WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
* changed watchdog_info to correctly reflect what
* the driver offers
* added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS,
* WDIOC_SETTIMEOUT, WDIOC_GETTIMEOUT, and
* WDIOC_SETOPTIONS ioctls
* 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
* 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 wdt_stop and wdt_start module params
* added extra printk's for startup problems
@ -56,9 +60,9 @@
#include <linux/notifier.h>
#include <linux/reboot.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>
#define OUR_NAME "sbc60xxwdt"
@ -94,13 +98,18 @@ MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 0x443)");
*/
#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_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;
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 DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
@ -117,15 +126,14 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL
* 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 */
inb_p(wdt_start);
/* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL);
} else {
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
}
} else
printk(KERN_WARNING PFX
"Heartbeat lost! Will not ping the watchdog\n");
}
/*
@ -159,40 +167,40 @@ static void wdt_keepalive(void)
* /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 */
if(count)
{
if (!nowayout)
{
if (count) {
if (!nowayout) {
size_t ofs;
/* note: just in case someone wrote the magic character
* five months ago... */
/* note: just in case someone wrote the
magic character five months ago... */
wdt_expect_close = 0;
/* scan to see whether or not we got the magic character */
for(ofs = 0; ofs != count; ofs++)
{
/* scan to see whether or not we got the
magic character */
for (ofs = 0; ofs != count; ofs++) {
char c;
if(get_user(c, buf+ofs))
if (get_user(c, buf + ofs))
return -EFAULT;
if(c == 'V')
if (c == 'V')
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();
}
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... */
if(test_and_set_bit(0, &wdt_is_open))
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
if (nowayout)
@ -203,78 +211,72 @@ static int fop_open(struct inode * inode, struct file * 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();
else {
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);
wdt_expect_close = 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;
int __user *p = argp;
static struct watchdog_info ident=
{
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "SBC60xx",
};
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_SETOPTIONS:
{
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:
{
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;
int new_options, retval = -EINVAL;
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
case WDIOC_SETTIMEOUT:
{
int new_timeout;
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 */
if (new_options & WDIOS_ENABLECARD) {
wdt_startup();
retval = 0;
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
return retval;
}
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
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);
default:
return -ENOTTY;
}
}
@ -284,7 +286,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write,
.open = fop_open,
.release = fop_close,
.ioctl = fop_ioctl,
.unlocked_ioctl = fop_ioctl,
};
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,
void *unused)
{
if(code==SYS_DOWN || code==SYS_HALT)
if (code == SYS_DOWN || code == SYS_HALT)
wdt_turnoff();
return NOTIFY_DONE;
}
@ -310,8 +312,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
* turn the timebomb registers off.
*/
static struct notifier_block wdt_notifier=
{
static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys,
};
@ -324,23 +325,22 @@ static void __exit sbc60xxwdt_unload(void)
unregister_reboot_notifier(&wdt_notifier);
if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
release_region(wdt_stop,1);
release_region(wdt_start,1);
release_region(wdt_stop, 1);
release_region(wdt_start, 1);
}
static int __init sbc60xxwdt_init(void)
{
int rc = -EBUSY;
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
{
if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
timeout);
}
printk(KERN_INFO PFX
"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",
wdt_start);
rc = -EIO;
@ -348,33 +348,30 @@ static int __init sbc60xxwdt_init(void)
}
/* We cannot reserve 0x45 - the kernel already has! */
if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
{
if (!request_region(wdt_stop, 1, "SBC 60XX WDT"))
{
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_stop);
if (wdt_stop != 0x45 && wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) {
printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n",
wdt_stop);
rc = -EIO;
goto err_out_region1;
}
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc)
{
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region2;
}
rc = misc_register(&wdt_miscdev);
if (rc)
{
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc);
goto err_out_reboot;
}
printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
@ -383,10 +380,10 @@ static int __init sbc60xxwdt_init(void)
err_out_reboot:
unregister_reboot_notifier(&wdt_notifier);
err_out_region2:
if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
release_region(wdt_stop,1);
if (wdt_stop != 0x45 && wdt_stop != wdt_start)
release_region(wdt_stop, 1);
err_out_region1:
release_region(wdt_start,1);
release_region(wdt_start, 1);
err_out:
return rc;
}

View file

@ -27,10 +27,10 @@
#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define SBC7240_PREFIX "sbc7240_wdt: "
@ -159,7 +159,7 @@ static int fop_close(struct inode *inode, struct file *file)
return 0;
}
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING|
WDIOF_SETTIMEOUT|
WDIOF_MAGICCLOSE,
@ -168,50 +168,50 @@ static struct watchdog_info ident = {
};
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)
{
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user
((void __user *)arg, &ident, sizeof(ident))
? -EFAULT : 0;
return copy_to_user((void __user *)arg, &ident, sizeof(ident))
? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int __user *)arg);
case WDIOC_SETOPTIONS:
{
int options;
int retval = -EINVAL;
if (get_user(options, (int __user *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
wdt_disable();
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
wdt_enable();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:{
int options;
int retval = -EINVAL;
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if (get_user(options, (int __user *)arg))
return -EFAULT;
if (get_user(new_timeout, (int __user *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
wdt_disable();
retval = 0;
}
if (wdt_set_timeout(new_timeout))
return -EINVAL;
if (options & WDIOS_ENABLECARD) {
wdt_enable();
retval = 0;
}
return retval;
}
case WDIOC_SETTIMEOUT:{
int new_timeout;
if (get_user(new_timeout, (int __user *)arg))
return -EFAULT;
if (wdt_set_timeout(new_timeout))
return -EINVAL;
/* Fall through */
}
/* Fall through */
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, (int __user *)arg);
default:
@ -225,7 +225,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write,
.open = fop_open,
.release = fop_close,
.ioctl = fop_ioctl,
.unlocked_ioctl = fop_ioctl,
};
static struct miscdevice wdt_miscdev = {

View file

@ -48,13 +48,12 @@
#include <linux/init.h>
#include <linux/spinlock.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>
static unsigned long sbc8360_is_open;
static DEFINE_SPINLOCK(sbc8360_lock);
static char expect_close;
#define PFX "sbc8360: "
@ -204,7 +203,8 @@ module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
module_param(nowayout, int, 0);
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.
@ -231,9 +231,16 @@ static void sbc8360_ping(void)
outb(wd_margin, SBC8360_BASETIME);
}
/* stop watchdog */
static void sbc8360_stop(void)
{
/* De-activate the watchdog */
outb(0, SBC8360_ENABLE);
}
/* Userspace pings kernel driver, or requests clean close */
static ssize_t sbc8360_write(struct file *file, const char __user * buf,
size_t count, loff_t * ppos)
static ssize_t sbc8360_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count) {
if (!nowayout) {
@ -257,16 +264,12 @@ static ssize_t sbc8360_write(struct file *file, const char __user * buf,
static int sbc8360_open(struct inode *inode, struct file *file)
{
spin_lock(&sbc8360_lock);
if (test_and_set_bit(0, &sbc8360_is_open)) {
spin_unlock(&sbc8360_lock);
if (test_and_set_bit(0, &sbc8360_is_open))
return -EBUSY;
}
if (nowayout)
__module_get(THIS_MODULE);
/* Activate and ping once to start the countdown */
spin_unlock(&sbc8360_lock);
sbc8360_activate();
sbc8360_ping();
return nonseekable_open(inode, file);
@ -274,16 +277,14 @@ static int sbc8360_open(struct inode *inode, struct file *file)
static int sbc8360_close(struct inode *inode, struct file *file)
{
spin_lock(&sbc8360_lock);
if (expect_close == 42)
outb(0, SBC8360_ENABLE);
sbc8360_stop();
else
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);
expect_close = 0;
spin_unlock(&sbc8360_lock);
return 0;
}
@ -294,10 +295,9 @@ static int sbc8360_close(struct inode *inode, struct file *file)
static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
{
if (code == SYS_DOWN || code == SYS_HALT) {
/* Disable the SBC8360 Watchdog */
outb(0, SBC8360_ENABLE);
}
if (code == SYS_DOWN || code == SYS_HALT)
sbc8360_stop(); /* Disable the SBC8360 Watchdog */
return NOTIFY_DONE;
}
@ -382,13 +382,13 @@ static int __init sbc8360_init(void)
return 0;
out_nomisc:
out_nomisc:
unregister_reboot_notifier(&sbc8360_notifier);
out_noreboot:
out_noreboot:
release_region(SBC8360_BASETIME, 1);
out_nobasetimereg:
out_nobasetimereg:
release_region(SBC8360_ENABLE, 1);
out:
out:
return res;
}

View file

@ -25,8 +25,8 @@
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define PFX "epx_c3: "
static int epx_c3_alive;
@ -100,12 +100,12 @@ static ssize_t epx_c3_write(struct file *file, const char __user *data,
return len;
}
static int epx_c3_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long epx_c3_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int options, retval = -EINVAL;
int __user *argp = (void __user *)arg;
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
@ -120,11 +120,6 @@ static int epx_c3_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, argp);
case WDIOC_KEEPALIVE:
epx_c3_pet();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_TIMEOUT, argp);
case WDIOC_SETOPTIONS:
if (get_user(options, argp))
return -EFAULT;
@ -140,6 +135,11 @@ static int epx_c3_ioctl(struct inode *inode, struct file *file,
}
return retval;
case WDIOC_KEEPALIVE:
epx_c3_pet();
return 0;
case WDIOC_GETTIMEOUT:
return put_user(WATCHDOG_TIMEOUT, argp);
default:
return -ENOTTY;
}
@ -158,7 +158,7 @@ static const struct file_operations epx_c3_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = epx_c3_write,
.ioctl = epx_c3_ioctl,
.unlocked_ioctl = epx_c3_ioctl,
.open = epx_c3_open,
.release = epx_c3_release,
};

View file

@ -196,7 +196,6 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof ident))
return -EFAULT;
@ -208,24 +207,6 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
sc1200wdt_write_data(WDTO, timeout);
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
/* the API states this is given in secs */
new_timeout /= 60;
if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
return -EINVAL;
timeout = new_timeout;
sc1200wdt_write_data(WDTO, timeout);
/* fall through and return the new timeout */
case WDIOC_GETTIMEOUT:
return put_user(timeout * 60, p);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
@ -245,6 +226,24 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
return retval;
}
case WDIOC_KEEPALIVE:
sc1200wdt_write_data(WDTO, timeout);
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
/* the API states this is given in secs */
new_timeout /= 60;
if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
return -EINVAL;
timeout = new_timeout;
sc1200wdt_write_data(WDTO, timeout);
/* fall through and return the new timeout */
case WDIOC_GETTIMEOUT:
return put_user(timeout * 60, p);
default:
return -ENOTTY;
}
@ -280,7 +279,7 @@ static ssize_t sc1200wdt_write(struct file *file, const char __user *data,
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;

View file

@ -64,9 +64,9 @@
#include <linux/reboot.h>
#include <linux/init.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>
#define OUR_NAME "sc520_wdt"
@ -91,13 +91,18 @@
*/
#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_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;
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
@ -136,8 +141,7 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL
* we agree to ping the WDT
*/
if(time_before(jiffies, next_heartbeat))
{
if (time_before(jiffies, next_heartbeat)) {
/* Ping the WDT */
spin_lock(&wdt_spinlock);
writew(0xAAAA, wdtmrctl);
@ -146,9 +150,9 @@ static void wdt_timer_ping(unsigned long data)
/* Re-set the timer interval */
mod_timer(&timer, jiffies + WDT_INTERVAL);
} else {
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
}
} else
printk(KERN_WARNING PFX
"Heartbeat lost! Will not ping the watchdog\n");
}
/*
@ -162,7 +166,7 @@ static void wdt_config(int writeval)
/* buy some time (ping) */
spin_lock_irqsave(&wdt_spinlock, flags);
dummy=readw(wdtmrctl); /* ensure write synchronization */
dummy = readw(wdtmrctl); /* ensure write synchronization */
writew(0xAAAA, wdtmrctl);
writew(0x5555, wdtmrctl);
/* unlock WDT = make WDT configuration register writable one time */
@ -219,10 +223,11 @@ static int wdt_set_heartbeat(int t)
* /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 */
if(count) {
if (count) {
if (!nowayout) {
size_t ofs;
@ -231,25 +236,26 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
wdt_expect_close = 0;
/* now scan */
for(ofs = 0; ofs != count; ofs++) {
for (ofs = 0; ofs != count; ofs++) {
char c;
if (get_user(c, buf + ofs))
return -EFAULT;
if(c == 'V')
if (c == 'V')
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();
}
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... */
if(test_and_set_bit(0, &wdt_is_open))
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
if (nowayout)
__module_get(THIS_MODULE);
@ -259,12 +265,13 @@ static int fop_open(struct inode * inode, struct file * 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();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
else {
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
wdt_keepalive();
}
clear_bit(0, &wdt_is_open);
@ -272,63 +279,62 @@ static int fop_close(struct inode * inode, struct file * file)
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;
int __user *p = argp;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "SC520",
};
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_SETOPTIONS:
{
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:
{
int new_options, retval = -EINVAL;
int new_options, retval = -EINVAL;
if(get_user(new_options, p))
return -EFAULT;
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 (new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if(get_user(new_timeout, p))
return -EFAULT;
if(wdt_set_heartbeat(new_timeout))
return -EINVAL;
wdt_keepalive();
/* Fall through */
if (new_options & WDIOS_ENABLECARD) {
wdt_startup();
retval = 0;
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
return retval;
}
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
{
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
if (wdt_set_heartbeat(new_timeout))
return -EINVAL;
wdt_keepalive();
/* Fall through */
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
}
}
@ -338,7 +344,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write,
.open = fop_open,
.release = fop_close,
.ioctl = fop_ioctl,
.unlocked_ioctl = fop_ioctl,
};
static struct miscdevice wdt_miscdev = {
@ -354,7 +360,7 @@ static struct miscdevice wdt_miscdev = {
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();
return NOTIFY_DONE;
}
@ -383,11 +389,13 @@ static int __init sc520_wdt_init(void)
{
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)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n",
WATCHDOG_TIMEOUT);
printk(KERN_INFO PFX
"timeout value must be 1 <= timeout <= 3600, using %d\n",
WATCHDOG_TIMEOUT);
}
wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2);
@ -399,20 +407,22 @@ static int __init sc520_wdt_init(void)
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
rc);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", rc);
goto err_out_ioremap;
}
rc = misc_register(&wdt_miscdev);
if (rc) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, rc);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, rc);
goto err_out_notifier;
}
printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
timeout,nowayout);
printk(KERN_INFO PFX
"WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0;

View file

@ -27,9 +27,8 @@
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/scx200.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define NAME "scx200_wdt"
@ -47,8 +46,9 @@ module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
static u16 wdto_restart;
static struct semaphore open_semaphore;
static char expect_close;
static unsigned long open_lock;
static DEFINE_SPINLOCK(scx_lock);
/* Bits of the WDCNFG register */
#define W_ENABLE 0x00fa /* Enable watchdog */
@ -59,7 +59,9 @@ static char expect_close;
static void scx200_wdt_ping(void)
{
spin_lock(&scx_lock);
outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO);
spin_unlock(&scx_lock);
}
static void scx200_wdt_update_margin(void)
@ -73,9 +75,11 @@ static void scx200_wdt_enable(void)
printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
wdto_restart);
spin_lock(&scx_lock);
outw(0, scx200_cb_base + SCx200_WDT_WDTO);
outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
spin_unlock(&scx_lock);
scx200_wdt_ping();
}
@ -84,15 +88,17 @@ static void scx200_wdt_disable(void)
{
printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
spin_lock(&scx_lock);
outw(0, scx200_cb_base + SCx200_WDT_WDTO);
outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
spin_unlock(&scx_lock);
}
static int scx200_wdt_open(struct inode *inode, struct file *file)
{
/* only allow one at a time */
if (down_trylock(&open_semaphore))
if (test_and_set_bit(0, &open_lock))
return -EBUSY;
scx200_wdt_enable();
@ -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)
{
if (expect_close != 42) {
if (expect_close != 42)
printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
} else if (!nowayout) {
else if (!nowayout)
scx200_wdt_disable();
}
expect_close = 0;
up(&open_semaphore);
clear_bit(0, &open_lock);
return 0;
}
@ -122,8 +127,7 @@ static int scx200_wdt_notify_sys(struct notifier_block *this,
return NOTIFY_DONE;
}
static struct notifier_block scx200_wdt_notifier =
{
static struct notifier_block scx200_wdt_notifier = {
.notifier_call = scx200_wdt_notify_sys,
};
@ -131,8 +135,7 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
/* check for a magic close character */
if (len)
{
if (len) {
size_t i;
scx200_wdt_ping();
@ -140,7 +143,7 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data,
expect_close = 0;
for (i = 0; i < len; ++i) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -152,23 +155,21 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data,
return 0;
}
static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long scx200_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.identity = "NatSemi SCx200 Watchdog",
.firmware_version = 1,
.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
};
int new_margin;
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident)))
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
return 0;
case WDIOC_GETSTATUS:
@ -191,22 +192,24 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
if (put_user(margin, p))
return -EFAULT;
return 0;
default:
return -ENOTTY;
}
}
static const struct file_operations scx200_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = scx200_wdt_write,
.ioctl = scx200_wdt_ioctl,
.open = scx200_wdt_open,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = scx200_wdt_write,
.unlocked_ioctl = scx200_wdt_ioctl,
.open = scx200_wdt_open,
.release = scx200_wdt_release,
};
static struct miscdevice scx200_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &scx200_wdt_fops,
.name = "watchdog",
.fops = &scx200_wdt_fops,
};
static int __init scx200_wdt_init(void)
@ -229,8 +232,6 @@ static int __init scx200_wdt_init(void)
scx200_wdt_update_margin();
scx200_wdt_disable();
sema_init(&open_semaphore, 1);
r = register_reboot_notifier(&scx200_wdt_notifier);
if (r) {
printk(KERN_ERR NAME ": unable to register reboot notifier");
@ -263,7 +264,7 @@ module_exit(scx200_wdt_cleanup);
/*
Local variables:
compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
c-basic-offset: 8
compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
c-basic-offset: 8
End:
*/

View file

@ -28,9 +28,9 @@
#include <linux/ioport.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/watchdog.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
#define PFX "shwdt: "
@ -72,6 +72,7 @@ static struct watchdog_info sh_wdt_info;
static char shwdt_expect_close;
static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0);
static unsigned long next_heartbeat;
static DEFINE_SPINLOCK(shwdt_lock);
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
@ -86,6 +87,9 @@ static int nowayout = WATCHDOG_NOWAYOUT;
static void sh_wdt_start(void)
{
__u8 csr;
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ);
mod_timer(&timer, next_ping_period(clock_division_ratio));
@ -123,6 +127,7 @@ static void sh_wdt_start(void)
csr &= ~RSTCSR_RSTS;
sh_wdt_write_rstcsr(csr);
#endif
spin_unlock_irqrestore(&wdt_lock, flags);
}
/**
@ -132,12 +137,16 @@ static void sh_wdt_start(void)
static void sh_wdt_stop(void)
{
__u8 csr;
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
del_timer(&timer);
csr = sh_wdt_read_csr();
csr &= ~WTCSR_TME;
sh_wdt_write_csr(csr);
spin_unlock_irqrestore(&wdt_lock, flags);
}
/**
@ -146,7 +155,11 @@ static void sh_wdt_stop(void)
*/
static inline void sh_wdt_keepalive(void)
{
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ);
spin_unlock_irqrestore(&wdt_lock, flags);
}
/**
@ -155,10 +168,14 @@ static inline void sh_wdt_keepalive(void)
*/
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;
spin_lock_irqsave(&wdt_lock, flags);
heartbeat = t;
spin_unlock_irqrestore(&wdt_lock, flags);
return 0;
}
@ -170,6 +187,9 @@ static int sh_wdt_set_heartbeat(int t)
*/
static void sh_wdt_ping(unsigned long data)
{
unsigned long flags;
spin_lock_irqsave(&wdt_lock, flags);
if (time_before(jiffies, next_heartbeat)) {
__u8 csr;
@ -183,6 +203,7 @@ static void sh_wdt_ping(unsigned long data)
} else
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping "
"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)
/**
* sh_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device
* @cmd: watchdog command
* @arg: argument
@ -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
* watchdog API.
*/
static int sh_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_heartbeat;
int options, retval = -EINVAL;
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info *)arg,
&sh_wdt_info,
sizeof(sh_wdt_info)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int *)arg);
case WDIOC_KEEPALIVE:
sh_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_heartbeat, (int *)arg))
return -EFAULT;
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info *)arg,
&sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int *)arg);
case WDIOC_SETOPTIONS:
if (get_user(options, (int *)arg))
return -EFAULT;
if (sh_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
if (options & WDIOS_DISABLECARD) {
sh_wdt_stop();
retval = 0;
}
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_ENABLECARD) {
sh_wdt_start();
retval = 0;
}
if (options & WDIOS_DISABLECARD) {
sh_wdt_stop();
retval = 0;
}
return retval;
case WDIOC_KEEPALIVE:
sh_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_heartbeat, (int *)arg))
return -EFAULT;
if (options & WDIOS_ENABLECARD) {
sh_wdt_start();
retval = 0;
}
if (sh_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
return retval;
default:
return -ENOTTY;
sh_wdt_keepalive();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, (int *)arg);
default:
return -ENOTTY;
}
return 0;
}
@ -390,13 +408,13 @@ static const struct file_operations sh_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sh_wdt_write,
.ioctl = sh_wdt_ioctl,
.unlocked_ioctl = sh_wdt_ioctl,
.open = sh_wdt_open,
.release = sh_wdt_close,
.mmap = sh_wdt_mmap,
};
static struct watchdog_info sh_wdt_info = {
static const struct watchdog_info sh_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1,
@ -422,30 +440,33 @@ static int __init sh_wdt_init(void)
{
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;
printk(KERN_INFO PFX "clock_division_ratio value must "
"be 0x5<=x<=0x7, using %d\n", clock_division_ratio);
printk(KERN_INFO PFX
"clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
clock_division_ratio);
}
rc = sh_wdt_set_heartbeat(heartbeat);
if (unlikely(rc)) {
heartbeat = WATCHDOG_HEARTBEAT;
printk(KERN_INFO PFX "heartbeat value must "
"be 1<=x<=3600, using %d\n", heartbeat);
printk(KERN_INFO PFX
"heartbeat value must be 1<=x<=3600, using %d\n",
heartbeat);
}
rc = register_reboot_notifier(&sh_wdt_notifier);
if (unlikely(rc)) {
printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n",
rc);
printk(KERN_ERR PFX
"Can't register reboot notifier (err=%d)\n", rc);
return rc;
}
rc = misc_register(&sh_wdt_miscdev);
if (unlikely(rc)) {
printk(KERN_ERR PFX "Can't register miscdev on "
"minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc);
printk(KERN_ERR PFX
"Can't register miscdev on minor=%d (err=%d)\n",
sh_wdt_miscdev.minor, rc);
unregister_reboot_notifier(&sh_wdt_notifier);
return rc;
}
@ -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_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_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_exit(sh_wdt_exit);

View file

@ -18,7 +18,7 @@
* History:
* 2003 - Created version 1.0 for Linux 2.4.x.
* 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE
* features. Released version 1.1
* features. Released version 1.1
*
* Theory of operation:
*
@ -55,9 +55,9 @@
#include <linux/reboot.h>
#include <linux/init.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>
/* enable support for minutes as units? */
@ -71,15 +71,15 @@
#define UNIT_MINUTE 1
#define MODNAME "smsc37b787_wdt: "
#define VERSION "1.1"
#define VERSION "1.1"
#define IOPORT 0x3F0
#define IOPORT 0x3F0
#define IOPORT_SIZE 2
#define IODEV_NO 8
#define IODEV_NO 8
static int unit = UNIT_SECOND; /* timer's unit */
static int timeout = 60; /* timeout value: default is 60 "units" */
static unsigned long timer_enabled = 0; /* is the timer enabled? */
static int unit = UNIT_SECOND; /* timer's unit */
static int timeout = 60; /* timeout value: default is 60 "units" */
static unsigned long timer_enabled; /* is the timer enabled? */
static char expect_close; /* is the close expected? */
@ -93,114 +93,121 @@ static int nowayout = WATCHDOG_NOWAYOUT;
static inline void open_io_config(void)
{
outb(0x55, IOPORT);
outb(0x55, IOPORT);
mdelay(1);
outb(0x55, IOPORT);
outb(0x55, IOPORT);
}
/* lock the IO chip */
static inline void close_io_config(void)
{
outb(0xAA, IOPORT);
outb(0xAA, IOPORT);
}
/* select the IO device */
static inline void select_io_device(unsigned char devno)
{
outb(0x07, IOPORT);
outb(devno, IOPORT+1);
outb(0x07, IOPORT);
outb(devno, IOPORT+1);
}
/* write to the control register */
static inline void write_io_cr(unsigned char reg, unsigned char data)
{
outb(reg, IOPORT);
outb(data, IOPORT+1);
outb(reg, IOPORT);
outb(data, IOPORT+1);
}
/* read from the control register */
static inline char read_io_cr(unsigned char reg)
{
outb(reg, IOPORT);
return inb(IOPORT+1);
outb(reg, IOPORT);
return inb(IOPORT+1);
}
/* -- Medium level functions ------------------------------------*/
static inline void gpio_bit12(unsigned char reg)
{
// -- General Purpose I/O Bit 1.2 --
// Bit 0, In/Out: 0 = Output, 1 = Input
// Bit 1, Polarity: 0 = No Invert, 1 = Invert
// Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
// Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
// 11 = Either Edge Triggered Intr. 2
// Bit 5/6 (Reserved)
// Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
write_io_cr(0xE2, reg);
/* -- General Purpose I/O Bit 1.2 --
* Bit 0, In/Out: 0 = Output, 1 = Input
* Bit 1, Polarity: 0 = No Invert, 1 = Invert
* Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
* Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
* 11 = Either Edge Triggered Intr. 2
* Bit 5/6 (Reserved)
* Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
*/
write_io_cr(0xE2, reg);
}
static inline void gpio_bit13(unsigned char reg)
{
// -- General Purpose I/O Bit 1.3 --
// Bit 0, In/Out: 0 = Output, 1 = Input
// Bit 1, Polarity: 0 = No Invert, 1 = Invert
// Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
// Bit 3, Function select: 0 = GPI/O, 1 = LED
// Bit 4-6 (Reserved)
// Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
write_io_cr(0xE3, reg);
/* -- General Purpose I/O Bit 1.3 --
* Bit 0, In/Out: 0 = Output, 1 = Input
* Bit 1, Polarity: 0 = No Invert, 1 = Invert
* Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
* Bit 3, Function select: 0 = GPI/O, 1 = LED
* Bit 4-6 (Reserved)
* Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
*/
write_io_cr(0xE3, reg);
}
static inline void wdt_timer_units(unsigned char new_units)
{
// -- Watchdog timer units --
// Bit 0-6 (Reserved)
// Bit 7, WDT Time-out Value Units Select
// (0 = Minutes, 1 = Seconds)
write_io_cr(0xF1, new_units);
/* -- Watchdog timer units --
* Bit 0-6 (Reserved)
* Bit 7, WDT Time-out Value Units Select
* (0 = Minutes, 1 = Seconds)
*/
write_io_cr(0xF1, new_units);
}
static inline void wdt_timeout_value(unsigned char new_timeout)
{
// -- Watchdog Timer Time-out Value --
// Bit 0-7 Binary coded units (0=Disabled, 1..255)
write_io_cr(0xF2, new_timeout);
/* -- Watchdog Timer Time-out Value --
* Bit 0-7 Binary coded units (0=Disabled, 1..255)
*/
write_io_cr(0xF2, new_timeout);
}
static inline void wdt_timer_conf(unsigned char conf)
{
// -- Watchdog timer configuration --
// Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O
// Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
// Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr.
// Bit 3 Reset the timer
// (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled)
// Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,
// 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)
write_io_cr(0xF3, conf);
/* -- Watchdog timer configuration --
* Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon
* Gameport I/O
* Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
* Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr
* Bit 3 Reset the timer
* (Wrong in SMsC documentation? Given as: PowerLED Timout
* Enabled)
* 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)
{
// -- Watchdog timer control --
// Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured
// 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 3 P20 Force Timeout enabled:
// 0 = P20 activity does not generate the WD timeout event
// 1 = P20 Allows rising edge of P20, from the keyboard
// controller, to force the WD timeout event.
// Bit 4 (Reserved)
// -- Soft power management --
// Bit 5 Stop Counter: 1 = Stop software power down counter
// set via register 0xB8, (self-cleaning)
// (Upon read: 0 = Counter running, 1 = Counter stopped)
// Bit 6 Restart Counter: 1 = Restart software power down counter
// set via register 0xB8, (self-cleaning)
// Bit 7 SPOFF: 1 = Force software power down (self-cleaning)
write_io_cr(0xF4, reg);
/* -- Watchdog timer control --
* Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured
* 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 3 P20 Force Timeout enabled:
* 0 = P20 activity does not generate the WD timeout event
* 1 = P20 Allows rising edge of P20, from the keyboard
* controller, to force the WD timeout event.
* Bit 4 (Reserved)
* -- Soft power management --
* Bit 5 Stop Counter: 1 = Stop software power down counter
* set via register 0xB8, (self-cleaning)
* (Upon read: 0 = Counter running, 1 = Counter stopped)
* Bit 6 Restart Counter: 1 = Restart software power down counter
* set via register 0xB8, (self-cleaning)
* Bit 7 SPOFF: 1 = Force software power down (self-cleaning)
*/
write_io_cr(0xF4, reg);
}
/* -- Higher level functions ------------------------------------*/
@ -209,33 +216,34 @@ static inline void wdt_timer_ctrl(unsigned char reg)
static void wb_smsc_wdt_initialize(void)
{
unsigned char old;
unsigned char old;
spin_lock(&io_lock);
open_io_config();
select_io_device(IODEV_NO);
open_io_config();
select_io_device(IODEV_NO);
// enable the watchdog
gpio_bit13(0x08); // Select pin 80 = LED not GPIO
gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert
/* enable the watchdog */
gpio_bit13(0x08); /* Select pin 80 = LED not GPIO */
gpio_bit12(0x0A); /* Set pin 79 = WDT not
GPIO/Output/Polarity=Invert */
/* disable the timeout */
wdt_timeout_value(0);
// disable the timeout
wdt_timeout_value(0);
/* reset control register */
wdt_timer_ctrl(0x00);
// reset control register
wdt_timer_ctrl(0x00);
// reset configuration register
/* reset configuration register */
wdt_timer_conf(0x00);
// read old (timer units) register
old = read_io_cr(0xF1) & 0x7F;
if (unit == UNIT_SECOND) old |= 0x80; // set to seconds
/* read old (timer units) register */
old = read_io_cr(0xF1) & 0x7F;
if (unit == UNIT_SECOND)
old |= 0x80; /* set to seconds */
// set the watchdog timer units
wdt_timer_units(old);
/* set the watchdog timer units */
wdt_timer_units(old);
close_io_config();
close_io_config();
spin_unlock(&io_lock);
}
@ -244,23 +252,23 @@ static void wb_smsc_wdt_initialize(void)
static void wb_smsc_wdt_shutdown(void)
{
spin_lock(&io_lock);
open_io_config();
select_io_device(IODEV_NO);
open_io_config();
select_io_device(IODEV_NO);
// disable the watchdog
gpio_bit13(0x09);
gpio_bit12(0x09);
/* disable the watchdog */
gpio_bit13(0x09);
gpio_bit12(0x09);
// reset watchdog config register
/* reset watchdog config register */
wdt_timer_conf(0x00);
// reset watchdog control register
wdt_timer_ctrl(0x00);
/* reset watchdog control register */
wdt_timer_ctrl(0x00);
// disable timeout
wdt_timeout_value(0x00);
/* disable timeout */
wdt_timeout_value(0x00);
close_io_config();
close_io_config();
spin_unlock(&io_lock);
}
@ -269,16 +277,16 @@ static void wb_smsc_wdt_shutdown(void)
static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
{
spin_lock(&io_lock);
open_io_config();
select_io_device(IODEV_NO);
open_io_config();
select_io_device(IODEV_NO);
// set Power LED to blink, if we enable the timeout
wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
/* set Power LED to blink, if we enable the timeout */
wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
// set timeout value
wdt_timeout_value(new_timeout);
/* set timeout value */
wdt_timeout_value(new_timeout);
close_io_config();
close_io_config();
spin_unlock(&io_lock);
}
@ -286,32 +294,32 @@ static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
static unsigned char wb_smsc_wdt_get_timeout(void)
{
unsigned char set_timeout;
unsigned char set_timeout;
spin_lock(&io_lock);
open_io_config();
select_io_device(IODEV_NO);
set_timeout = read_io_cr(0xF2);
close_io_config();
open_io_config();
select_io_device(IODEV_NO);
set_timeout = read_io_cr(0xF2);
close_io_config();
spin_unlock(&io_lock);
return set_timeout;
return set_timeout;
}
/* disable watchdog */
static void wb_smsc_wdt_disable(void)
{
// set the timeout to 0 to disable the watchdog
wb_smsc_wdt_set_timeout(0);
/* set the timeout to 0 to disable the watchdog */
wb_smsc_wdt_set_timeout(0);
}
/* enable watchdog by setting the current timeout */
static void wb_smsc_wdt_enable(void)
{
// set the current timeout...
wb_smsc_wdt_set_timeout(timeout);
/* set the current timeout... */
wb_smsc_wdt_set_timeout(timeout);
}
/* reset the timer */
@ -319,14 +327,14 @@ static void wb_smsc_wdt_enable(void)
static void wb_smsc_wdt_reset_timer(void)
{
spin_lock(&io_lock);
open_io_config();
select_io_device(IODEV_NO);
open_io_config();
select_io_device(IODEV_NO);
// reset the timer
/* reset the timer */
wdt_timeout_value(timeout);
wdt_timer_conf(0x08);
close_io_config();
close_io_config();
spin_unlock(&io_lock);
}
@ -355,7 +363,9 @@ static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
/* Reload and activate timer */
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);
}
@ -367,10 +377,12 @@ static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
/* Shut off the timer. */
if (expect_close == 42) {
wb_smsc_wdt_disable();
printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n");
wb_smsc_wdt_disable();
printk(KERN_INFO MODNAME
"Watchdog disabled, sleeping again...\n");
} 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();
}
@ -392,10 +404,11 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
/* reset expect flag */
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++) {
char c;
if (get_user(c, data+i))
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -410,8 +423,8 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
/* ioctl => control interface */
static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long wb_smsc_wdt_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int new_timeout;
@ -420,89 +433,73 @@ static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
int __user *i;
} uarg;
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = "SMsC 37B787 Watchdog"
.identity = "SMsC 37B787 Watchdog",
};
uarg.i = (int __user *)arg;
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident, sizeof(ident))
? -EFAULT : 0;
case WDIOC_GETSTATUS:
return put_user(wb_smsc_wdt_status(), uarg.i);
case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident,
sizeof(ident)) ? -EFAULT : 0;
if (get_user(options, uarg.i))
return -EFAULT;
case WDIOC_GETSTATUS:
return put_user(wb_smsc_wdt_status(), uarg.i);
case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_KEEPALIVE:
wb_smsc_wdt_reset_timer();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, uarg.i))
return -EFAULT;
// the API states this is given in secs
if (unit == UNIT_MINUTE)
new_timeout /= 60;
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;
return put_user(new_timeout, uarg.i);
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;
}
case WDIOC_KEEPALIVE:
wb_smsc_wdt_reset_timer();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, uarg.i))
return -EFAULT;
/* the API states this is given in secs */
if (unit == UNIT_MINUTE)
new_timeout /= 60;
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;
return put_user(new_timeout, uarg.i);
default:
return -ENOTTY;
}
}
/* -- 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)
{
// set timeout to 0, to avoid possible race-condition
timeout = 0;
if (code == SYS_DOWN || code == SYS_HALT) {
/* set timeout to 0, to avoid possible race-condition */
timeout = 0;
wb_smsc_wdt_disable();
}
return NOTIFY_DONE;
@ -510,23 +507,20 @@ static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long cod
/* -- Module's structures ---------------------------------------*/
static const struct file_operations wb_smsc_wdt_fops =
{
.owner = THIS_MODULE,
static const struct file_operations wb_smsc_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wb_smsc_wdt_write,
.ioctl = wb_smsc_wdt_ioctl,
.unlocked_ioctl = wb_smsc_wdt_ioctl,
.open = wb_smsc_wdt_open,
.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,
};
static struct miscdevice wb_smsc_wdt_miscdev =
{
static struct miscdevice wb_smsc_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &wb_smsc_wdt_fops,
@ -540,39 +534,44 @@ static int __init wb_smsc_wdt_init(void)
{
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")) {
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;
goto out_pnp;
}
// set new maximum, if it's too big
if (timeout > MAX_TIMEOUT)
timeout = MAX_TIMEOUT;
/* set new maximum, if it's too big */
if (timeout > MAX_TIMEOUT)
timeout = MAX_TIMEOUT;
// init the watchdog timer
wb_smsc_wdt_initialize();
/* init the watchdog timer */
wb_smsc_wdt_initialize();
ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
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;
}
ret = misc_register(&wb_smsc_wdt_miscdev);
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;
}
// output info
printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout);
// ret = 0
/* output info */
printk(KERN_INFO MODNAME "Timeout set to %d %s.\n",
timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
printk(KERN_INFO MODNAME
"Watchdog initialized and sleeping (nowayout=%d)...\n",
nowayout);
out_clean:
return ret;
@ -591,8 +590,7 @@ static int __init wb_smsc_wdt_init(void)
static void __exit wb_smsc_wdt_exit(void)
{
/* Stop the timer before we leave */
if (!nowayout)
{
if (!nowayout) {
wb_smsc_wdt_shutdown();
printk(KERN_INFO MODNAME "Watchdog disabled.\n");
}
@ -601,25 +599,29 @@ static void __exit wb_smsc_wdt_exit(void)
unregister_reboot_notifier(&wb_smsc_wdt_notifier);
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_exit(wb_smsc_wdt_exit);
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_ALIAS_MISCDEV(WATCHDOG_MINOR);
#ifdef SMSC_SUPPORT_MINUTES
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
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
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) ")");

View file

@ -47,19 +47,22 @@
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#define PFX "SoftDog: "
#define TIMER_MARGIN 60 /* Default is 60 seconds */
static int soft_margin = TIMER_MARGIN; /* in seconds */
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;
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
static int soft_noboot = 1;
@ -93,8 +96,7 @@ static void watchdog_fire(unsigned long data)
if (soft_noboot)
printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
else
{
else {
printk(KERN_CRIT PFX "Initiating system reboot.\n");
emergency_restart();
printk(KERN_CRIT PFX "Reboot didn't ?????\n");
@ -153,7 +155,8 @@ static int softdog_release(struct inode *inode, struct file *file)
softdog_stop();
module_put(THIS_MODULE);
} 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);
softdog_keepalive();
}
@ -162,12 +165,13 @@ static int softdog_release(struct inode *inode, struct file *file)
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.
*/
if(len) {
if (len) {
if (!nowayout) {
size_t i;
@ -188,13 +192,13 @@ static ssize_t softdog_write(struct file *file, const char __user *data, size_t
return len;
}
static int softdog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long softdog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_margin;
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
@ -202,26 +206,25 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
.identity = "Software Watchdog",
};
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:
softdog_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
if (softdog_set_heartbeat(new_margin))
return -EINVAL;
softdog_keepalive();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(soft_margin, p);
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:
softdog_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
if (softdog_set_heartbeat(new_margin))
return -EINVAL;
softdog_keepalive();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(soft_margin, p);
default:
return -ENOTTY;
}
}
@ -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,
void *unused)
{
if(code==SYS_DOWN || code==SYS_HALT) {
if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the WDT off */
softdog_stop();
}
return NOTIFY_DONE;
}
@ -247,7 +249,7 @@ static const struct file_operations softdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = softdog_write,
.ioctl = softdog_ioctl,
.unlocked_ioctl = softdog_ioctl,
.open = softdog_open,
.release = softdog_release,
};
@ -268,24 +270,27 @@ static int __init watchdog_init(void)
{
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)) {
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);
}
ret = register_reboot_notifier(&softdog_notifier);
if (ret) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&softdog_miscdev);
if (ret) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&softdog_notifier);
return ret;
}

View file

@ -45,27 +45,34 @@ static unsigned long txx9wdt_alive;
static int expect_close;
static struct txx9_tmr_reg __iomem *txx9wdt_reg;
static struct clk *txx9_imclk;
static DECLARE_LOCK(txx9_lock);
static void txx9wdt_ping(void)
{
spin_lock(&txx9_lock);
__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
spin_unlock(&txx9_lock);
}
static void txx9wdt_start(void)
{
spin_lock(&txx9_lock);
__raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
__raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
__raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */
__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
&txx9wdt_reg->tcr);
__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
spin_unlock(&txx9_lock);
}
static void txx9wdt_stop(void)
{
spin_lock(&txx9_lock);
__raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
__raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
&txx9wdt_reg->tcr);
spin_unlock(&txx9_lock);
}
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,
return len;
}
static int txx9wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long txx9wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_timeout;
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
@ -135,8 +142,6 @@ static int txx9wdt_ioctl(struct inode *inode, struct file *file,
};
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
@ -156,6 +161,8 @@ static int txx9wdt_ioctl(struct inode *inode, struct file *file,
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
}
}
@ -168,22 +175,22 @@ static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
}
static const struct file_operations txx9wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = txx9wdt_write,
.ioctl = txx9wdt_ioctl,
.open = txx9wdt_open,
.release = txx9wdt_release,
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = txx9wdt_write,
.unlocked_ioctl = txx9wdt_ioctl,
.open = txx9wdt_open,
.release = txx9wdt_release,
};
static struct miscdevice txx9wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &txx9wdt_fops,
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &txx9wdt_fops,
};
static struct notifier_block txx9wdt_notifier = {
.notifier_call = txx9wdt_notify_sys
.notifier_call = txx9wdt_notify_sys,
};
static int __init txx9wdt_probe(struct platform_device *dev)

View file

@ -37,9 +37,9 @@
#include <linux/reboot.h>
#include <linux/init.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>
#define WATCHDOG_NAME "w83627hf/thf/hg WDT"
@ -57,22 +57,26 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
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;
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.
*/
#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 */
static void
w83627hf_select_wd_register(void)
static void w83627hf_select_wd_register(void)
{
unsigned char c;
outb_p(0x87, WDT_EFER); /* Enter extended function mode */
@ -93,43 +97,45 @@ w83627hf_select_wd_register(void)
outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
}
static void
w83627hf_unselect_wd_register(void)
static void w83627hf_unselect_wd_register(void)
{
outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
}
/* tyan motherboards seem to set F5 to 0x4C ?
* So explicitly init to appropriate value. */
static void
w83627hf_init(void)
static void w83627hf_init(void)
{
unsigned char t;
w83627hf_select_wd_register();
outb_p(0xF6, WDT_EFER); /* Select CRF6 */
t=inb_p(WDT_EFDR); /* read CRF6 */
t = inb_p(WDT_EFDR); /* read CRF6 */
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(0xF5, WDT_EFER); /* Select CRF5 */
t=inb_p(WDT_EFDR); /* read CRF5 */
t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
t = inb_p(WDT_EFDR); /* read CRF5 */
t &= ~0x0C; /* set second mode & disable keyboard
turning off watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF5 */
outb_p(0xF7, WDT_EFER); /* Select CRF7 */
t=inb_p(WDT_EFDR); /* read CRF7 */
t&=~0xC0; /* disable keyboard & mouse turning off watchdog */
t = inb_p(WDT_EFDR); /* read CRF7 */
t &= ~0xC0; /* disable keyboard & mouse turning off
watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF7 */
w83627hf_unselect_wd_register();
}
static void
wdt_ctrl(int timeout)
static void wdt_ctrl(int timeout)
{
spin_lock(&io_lock);
@ -143,32 +149,28 @@ wdt_ctrl(int timeout)
spin_unlock(&io_lock);
}
static int
wdt_ping(void)
static int wdt_ping(void)
{
wdt_ctrl(timeout);
return 0;
}
static int
wdt_disable(void)
static int wdt_disable(void)
{
wdt_ctrl(0);
return 0;
}
static int
wdt_set_heartbeat(int t)
static int wdt_set_heartbeat(int t)
{
if ((t < 1) || (t > 255))
if (t < 1 || t > 255)
return -EINVAL;
timeout = t;
return 0;
}
static ssize_t
wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
static ssize_t wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count) {
if (!nowayout) {
@ -178,7 +180,7 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
for (i = 0; i != count; i++) {
char c;
if (get_user(c, buf+i))
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -189,72 +191,61 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
return count;
}
static int
wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_timeout;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "W83627HF WDT",
};
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (wdt_set_heartbeat(new_timeout))
return -EINVAL;
wdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
return put_user(0, p);
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;
}
case WDIOC_KEEPALIVE:
wdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (wdt_set_heartbeat(new_timeout))
return -EINVAL;
wdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
return -ENOTTY;
}
return 0;
}
static int
wdt_open(struct inode *inode, struct file *file)
static int wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
@ -266,13 +257,13 @@ wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static int
wdt_close(struct inode *inode, struct file *file)
static int wdt_close(struct inode *inode, struct file *file)
{
if (expect_close == 42) {
if (expect_close == 42)
wdt_disable();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
else {
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
wdt_ping();
}
expect_close = 0;
@ -284,14 +275,12 @@ wdt_close(struct inode *inode, struct file *file)
* Notifier for system down
*/
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)
{
if (code == SYS_DOWN || code == SYS_HALT) {
/* Turn the WDT off */
wdt_disable();
}
if (code == SYS_DOWN || code == SYS_HALT)
wdt_disable(); /* Turn the WDT off */
return NOTIFY_DONE;
}
@ -303,7 +292,7 @@ static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdt_write,
.ioctl = wdt_ioctl,
.unlocked_ioctl = wdt_ioctl,
.open = wdt_open,
.release = wdt_close,
};
@ -323,8 +312,7 @@ static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys,
};
static int __init
wdt_init(void)
static int __init wdt_init(void)
{
int ret;
@ -332,12 +320,13 @@ wdt_init(void)
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
WATCHDOG_TIMEOUT);
printk(KERN_INFO PFX
"timeout value must be 1 <= timeout <= 255, using %d\n",
WATCHDOG_TIMEOUT);
}
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);
ret = -EIO;
goto out;
@ -347,20 +336,22 @@ wdt_init(void)
ret = register_reboot_notifier(&wdt_notifier);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
goto unreg_regions;
}
ret = misc_register(&wdt_miscdev);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto unreg_reboot;
}
printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
printk(KERN_INFO PFX
"initialized. timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
out:
return ret;
@ -371,12 +362,11 @@ wdt_init(void)
goto out;
}
static void __exit
wdt_exit(void)
static void __exit wdt_exit(void)
{
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);
release_region(wdt_io,1);
release_region(wdt_io, 1);
}
module_init(wdt_init);

View file

@ -36,9 +36,9 @@
#include <linux/reboot.h>
#include <linux/init.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>
#define WATCHDOG_NAME "w83697hf/hg WDT"
@ -53,37 +53,43 @@ static DEFINE_SPINLOCK(io_lock);
/* You must set this - there is no sane way to probe for this board. */
static int wdt_io = 0x2e;
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 */
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;
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;
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.
*/
#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_EFDR (wdt_io+1) /* Extended Function Data 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_EFDR (wdt_io + 1) /* Extended Function Data Register */
static inline void
w83697hf_unlock(void)
static inline void w83697hf_unlock(void)
{
outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */
outb_p(0x87, W83697HF_EFER); /* Again according to manual */
}
static inline void
w83697hf_lock(void)
static inline void w83697hf_lock(void)
{
outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */
}
@ -93,41 +99,36 @@ w83697hf_lock(void)
* w83697hf_write_timeout() must be called with the device unlocked.
*/
static unsigned char
w83697hf_get_reg(unsigned char reg)
static unsigned char w83697hf_get_reg(unsigned char reg)
{
outb_p(reg, W83697HF_EFIR);
return inb_p(W83697HF_EFDR);
}
static void
w83697hf_set_reg(unsigned char reg, unsigned char data)
static void w83697hf_set_reg(unsigned char reg, unsigned char data)
{
outb_p(reg, W83697HF_EFIR);
outb_p(data, W83697HF_EFDR);
}
static void
w83697hf_write_timeout(int timeout)
static void 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
w83697hf_select_wdt(void)
static void w83697hf_select_wdt(void)
{
w83697hf_unlock();
w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */
}
static inline void
w83697hf_deselect_wdt(void)
static inline void w83697hf_deselect_wdt(void)
{
w83697hf_lock();
}
static void
w83697hf_init(void)
static void w83697hf_init(void)
{
unsigned char bbuf;
@ -136,7 +137,9 @@ w83697hf_init(void)
bbuf = w83697hf_get_reg(0x29);
bbuf &= ~0x60;
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 &= ~0x04;
@ -145,8 +148,7 @@ w83697hf_init(void)
w83697hf_deselect_wdt();
}
static void
wdt_ping(void)
static void wdt_ping(void)
{
spin_lock(&io_lock);
w83697hf_select_wdt();
@ -157,8 +159,7 @@ wdt_ping(void)
spin_unlock(&io_lock);
}
static void
wdt_enable(void)
static void wdt_enable(void)
{
spin_lock(&io_lock);
w83697hf_select_wdt();
@ -170,8 +171,7 @@ wdt_enable(void)
spin_unlock(&io_lock);
}
static void
wdt_disable(void)
static void wdt_disable(void)
{
spin_lock(&io_lock);
w83697hf_select_wdt();
@ -183,8 +183,7 @@ wdt_disable(void)
spin_unlock(&io_lock);
}
static unsigned char
wdt_running(void)
static unsigned char wdt_running(void)
{
unsigned char t;
@ -199,18 +198,17 @@ wdt_running(void)
return t;
}
static int
wdt_set_heartbeat(int t)
static int wdt_set_heartbeat(int t)
{
if ((t < 1) || (t > 255))
if (t < 1 || t > 255)
return -EINVAL;
timeout = t;
return 0;
}
static ssize_t
wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
static ssize_t wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (count) {
if (!nowayout) {
@ -220,7 +218,7 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
for (i = 0; i != count; i++) {
char c;
if (get_user(c, buf+i))
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -231,15 +229,14 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
return count;
}
static int
wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_timeout;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "W83697HF WDT",
};
@ -254,21 +251,6 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (wdt_set_heartbeat(new_timeout))
return -EINVAL;
wdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
@ -289,14 +271,28 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return retval;
}
case WDIOC_KEEPALIVE:
wdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if (wdt_set_heartbeat(new_timeout))
return -EINVAL;
wdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
}
return 0;
}
static int
wdt_open(struct inode *inode, struct file *file)
static int wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
@ -308,13 +304,13 @@ wdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static int
wdt_close(struct inode *inode, struct file *file)
static int wdt_close(struct inode *inode, struct file *file)
{
if (expect_close == 42) {
if (expect_close == 42)
wdt_disable();
} else {
printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
else {
printk(KERN_CRIT PFX
"Unexpected close, not stopping watchdog!\n");
wdt_ping();
}
expect_close = 0;
@ -326,14 +322,12 @@ wdt_close(struct inode *inode, struct file *file)
* Notifier for system down
*/
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)
{
if (code == SYS_DOWN || code == SYS_HALT) {
/* Turn the WDT off */
wdt_disable();
}
if (code == SYS_DOWN || code == SYS_HALT)
wdt_disable(); /* Turn the WDT off */
return NOTIFY_DONE;
}
@ -345,7 +339,7 @@ static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdt_write,
.ioctl = wdt_ioctl,
.unlocked_ioctl = wdt_ioctl,
.open = wdt_open,
.release = wdt_close,
};
@ -365,36 +359,38 @@ static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys,
};
static int
w83697hf_check_wdt(void)
static int w83697hf_check_wdt(void)
{
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;
}
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();
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();
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);
return -EIO;
}
static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 };
static int __init
wdt_init(void)
static int __init wdt_init(void)
{
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) {
/* we will autodetect the W83697HF/HG watchdog */
@ -409,7 +405,7 @@ wdt_init(void)
}
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;
goto out;
}
@ -417,31 +413,33 @@ wdt_init(void)
w83697hf_init();
if (early_disable) {
if (wdt_running())
printk (KERN_WARNING PFX "Stopping previously enabled watchdog until userland kicks in\n");
printk(KERN_WARNING PFX "Stopping previously enabled watchdog until userland kicks in\n");
wdt_disable();
}
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
WATCHDOG_TIMEOUT);
printk(KERN_INFO PFX
"timeout value must be 1 <= timeout <= 255, using %d\n",
WATCHDOG_TIMEOUT);
}
ret = register_reboot_notifier(&wdt_notifier);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
goto unreg_regions;
}
ret = misc_register(&wdt_miscdev);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
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);
out:
@ -453,8 +451,7 @@ wdt_init(void)
goto out;
}
static void __exit
wdt_exit(void)
static void __exit wdt_exit(void)
{
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);

View file

@ -23,13 +23,16 @@
* Added KERN_* tags to printks
* add CONFIG_WATCHDOG_NOWAYOUT support
* fix possible wdt_is_open race
* changed watchdog_info to correctly reflect what the driver offers
* added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
* changed watchdog_info to correctly reflect what
* the driver offers
* added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS,
* WDIOC_SETTIMEOUT,
* WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
* 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
* added extra printk's for startup problems
* 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
*
* This WDT driver is different from most other Linux WDT
@ -51,8 +54,8 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/system.h>
#define OUR_NAME "w83877f_wdt"
@ -80,14 +83,19 @@
*/
#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_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;
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 DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
@ -105,8 +113,7 @@ static void wdt_timer_ping(unsigned long data)
/* If we got a heartbeat pulse within the WDT_US_INTERVAL
* we agree to ping the WDT
*/
if(time_before(jiffies, next_heartbeat))
{
if (time_before(jiffies, next_heartbeat)) {
/* Ping the WDT */
spin_lock(&wdt_spinlock);
@ -118,9 +125,9 @@ static void wdt_timer_ping(unsigned long data)
spin_unlock(&wdt_spinlock);
} else {
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
}
} else
printk(KERN_WARNING PFX
"Heartbeat lost! Will not ping the watchdog\n");
}
/*
@ -181,22 +188,21 @@ static void wdt_keepalive(void)
* /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 */
if(count)
{
if (!nowayout)
{
if (count) {
if (!nowayout) {
size_t ofs;
/* note: just in case someone wrote the magic character
* five months ago... */
/* note: just in case someone wrote the magic
character five months ago... */
wdt_expect_close = 0;
/* scan to see whether or not we got the magic character */
for(ofs = 0; ofs != count; ofs++)
{
/* scan to see whether or not we got the
magic character */
for (ofs = 0; ofs != count; ofs++) {
char c;
if (get_user(c, buf + ofs))
return -EFAULT;
@ -211,10 +217,10 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
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... */
if(test_and_set_bit(0, &wdt_is_open))
if (test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
/* Good, fire up the show */
@ -222,78 +228,78 @@ static int fop_open(struct inode * inode, struct file * 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();
else {
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);
wdt_expect_close = 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;
int __user *p = argp;
static struct watchdog_info ident=
{
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "W83877F",
};
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_SETOPTIONS:
{
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:
{
int new_options, retval = -EINVAL;
int new_options, retval = -EINVAL;
if(get_user(new_options, p))
return -EFAULT;
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 (new_options & WDIOS_DISABLECARD) {
wdt_turnoff();
retval = 0;
}
case WDIOC_SETTIMEOUT:
{
int new_timeout;
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 */
if (new_options & WDIOS_ENABLECARD) {
wdt_startup();
retval = 0;
}
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
return retval;
}
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
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);
default:
return -ENOTTY;
}
}
@ -303,7 +309,7 @@ static const struct file_operations wdt_fops = {
.write = fop_write,
.open = fop_open,
.release = fop_close,
.ioctl = fop_ioctl,
.unlocked_ioctl = fop_ioctl,
};
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,
void *unused)
{
if(code==SYS_DOWN || code==SYS_HALT)
if (code == SYS_DOWN || code == SYS_HALT)
wdt_turnoff();
return NOTIFY_DONE;
}
@ -329,8 +335,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
* turn the timebomb registers off.
*/
static struct notifier_block wdt_notifier=
{
static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys,
};
@ -342,31 +347,29 @@ static void __exit w83877f_wdt_unload(void)
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);
release_region(WDT_PING,1);
release_region(ENABLE_W83877F_PORT,2);
release_region(WDT_PING, 1);
release_region(ENABLE_W83877F_PORT, 2);
}
static int __init w83877f_wdt_init(void)
{
int rc = -EBUSY;
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
{
if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
timeout = WATCHDOG_TIMEOUT;
printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
timeout);
printk(KERN_INFO PFX
"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",
ENABLE_W83877F_PORT);
rc = -EIO;
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",
WDT_PING);
rc = -EIO;
@ -374,22 +377,22 @@ static int __init w83877f_wdt_init(void)
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc)
{
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region2;
}
rc = misc_register(&wdt_miscdev);
if (rc)
{
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc);
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);
return 0;
@ -397,9 +400,9 @@ static int __init w83877f_wdt_init(void)
err_out_reboot:
unregister_reboot_notifier(&wdt_notifier);
err_out_region2:
release_region(WDT_PING,1);
release_region(WDT_PING, 1);
err_out_region1:
release_region(ENABLE_W83877F_PORT,2);
release_region(ENABLE_W83877F_PORT, 2);
err_out:
return rc;
}

View file

@ -26,10 +26,10 @@
#include <linux/watchdog.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define WATCHDOG_VERSION "1.00"
#define WATCHDOG_NAME "W83977F WDT"
@ -53,13 +53,17 @@ static char expect_close;
static DEFINE_SPINLOCK(spinlock);
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_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;
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
@ -72,8 +76,8 @@ static int wdt_start(void)
spin_lock_irqsave(&spinlock, flags);
/* 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.
@ -81,50 +85,49 @@ static int wdt_start(void)
* F3 is set to enable watchdog LED blink at timeout.
* F4 is used to just clear the TIMEOUT'ed state (bit 0).
*/
outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT);
outb_p(timeoutW,IO_DATA_PORT);
outb_p(0xF3,IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT);
outb_p(0xF4,IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT);
outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08, IO_DATA_PORT);
outb_p(0xF2, IO_INDEX_PORT);
outb_p(timeoutW, IO_DATA_PORT);
outb_p(0xF3, IO_INDEX_PORT);
outb_p(0x08, IO_DATA_PORT);
outb_p(0xF4, IO_INDEX_PORT);
outb_p(0x00, IO_DATA_PORT);
/* Set device Aux2 active */
outb_p(0x30,IO_INDEX_PORT);
outb_p(0x01,IO_DATA_PORT);
outb_p(0x30, IO_INDEX_PORT);
outb_p(0x01, IO_DATA_PORT);
/*
/*
* 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).
* Map GP16 at pin 119.
* In test mode watch the bit 0 on F4 to indicate "triggered" or
* check watchdog LED on SBC.
*/
outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
outb_p(0x07,IO_DATA_PORT);
if (!testmode)
{
outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x07, IO_DATA_PORT);
if (!testmode) {
unsigned pin_map;
outb_p(0xE6,IO_INDEX_PORT);
outb_p(0x0A,IO_DATA_PORT);
outb_p(0x2C,IO_INDEX_PORT);
outb_p(0xE6, IO_INDEX_PORT);
outb_p(0x0A, IO_DATA_PORT);
outb_p(0x2C, IO_INDEX_PORT);
pin_map = inb_p(IO_DATA_PORT);
pin_map |= 0x10;
pin_map &= ~(0x20);
outb_p(0x2C,IO_INDEX_PORT);
outb_p(pin_map,IO_DATA_PORT);
outb_p(0x2C, IO_INDEX_PORT);
outb_p(pin_map, IO_DATA_PORT);
}
outb_p(0xE3,IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT);
outb_p(0xE3, IO_INDEX_PORT);
outb_p(0x08, IO_DATA_PORT);
/* Set device Aux1 active */
outb_p(0x30,IO_INDEX_PORT);
outb_p(0x01,IO_DATA_PORT);
outb_p(0x30, IO_INDEX_PORT);
outb_p(0x01, IO_DATA_PORT);
/* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT);
outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags);
@ -144,42 +147,41 @@ static int wdt_stop(void)
spin_lock_irqsave(&spinlock, flags);
/* 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.
* F2 is reset to its default value (watchdog timer disabled).
* F3 is reset to its default state.
* F4 clears the TIMEOUT'ed state (bit 0) - back to default.
*/
outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT);
outb_p(0xFF,IO_DATA_PORT);
outb_p(0xF3,IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT);
outb_p(0xF4,IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT);
outb_p(0x00,IO_DATA_PORT);
outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08, IO_DATA_PORT);
outb_p(0xF2, IO_INDEX_PORT);
outb_p(0xFF, IO_DATA_PORT);
outb_p(0xF3, IO_INDEX_PORT);
outb_p(0x00, IO_DATA_PORT);
outb_p(0xF4, IO_INDEX_PORT);
outb_p(0x00, IO_DATA_PORT);
outb_p(0xF2, IO_INDEX_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.
*/
outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
outb_p(0x07,IO_DATA_PORT);
if (!testmode)
{
outb_p(0xE6,IO_INDEX_PORT);
outb_p(0x01,IO_DATA_PORT);
outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x07, IO_DATA_PORT);
if (!testmode) {
outb_p(0xE6, IO_INDEX_PORT);
outb_p(0x01, IO_DATA_PORT);
}
outb_p(0xE3,IO_INDEX_PORT);
outb_p(0x01,IO_DATA_PORT);
outb_p(0xE3, IO_INDEX_PORT);
outb_p(0x01, IO_DATA_PORT);
/* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT);
outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags);
@ -200,17 +202,17 @@ static int wdt_keepalive(void)
spin_lock_irqsave(&spinlock, flags);
/* 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 */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT);
outb_p(0xF2,IO_INDEX_PORT);
outb_p(timeoutW,IO_DATA_PORT);
outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08, IO_DATA_PORT);
outb_p(0xF2, IO_INDEX_PORT);
outb_p(timeoutW, IO_DATA_PORT);
/* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT);
outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags);
@ -227,7 +229,7 @@ static int wdt_set_timeout(int t)
/*
* 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
* checked by me on a real board. This is a bit strange because W83977f
* datasheet says counter unit is in minutes!
@ -241,7 +243,7 @@ static int wdt_set_timeout(int t)
return -EINVAL;
/*
* timeout is the timeout in seconds,
* timeout is the timeout in seconds,
* timeoutW is the timeout in watchdog counter units.
*/
timeoutW = tmrval;
@ -261,17 +263,17 @@ static int wdt_get_status(int *status)
spin_lock_irqsave(&spinlock, flags);
/* 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 */
outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
outb_p(0x08,IO_DATA_PORT);
outb_p(0xF4,IO_INDEX_PORT);
outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x08, IO_DATA_PORT);
outb_p(0xF4, IO_INDEX_PORT);
new_status = inb_p(IO_DATA_PORT);
/* Lock the SuperIO chip */
outb_p(LOCK_DATA,IO_INDEX_PORT);
outb_p(LOCK_DATA, IO_INDEX_PORT);
spin_unlock_irqrestore(&spinlock, flags);
@ -290,7 +292,7 @@ static int wdt_get_status(int *status)
static int wdt_open(struct inode *inode, struct file *file)
{
/* 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;
if (nowayout)
@ -306,13 +308,13 @@ static int wdt_release(struct inode *inode, struct file *file)
* Shut off the timer.
* Lock it in if it's a module and we set nowayout
*/
if (expect_close == 42)
{
if (expect_close == 42) {
wdt_stop();
clear_bit(0, &timer_alive);
} else {
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;
return 0;
@ -333,24 +335,22 @@ static ssize_t wdt_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 */
if(count)
{
if (!nowayout)
{
if (count) {
if (!nowayout) {
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;
/* scan to see whether or not we got the magic character */
for(ofs = 0; ofs != count; ofs++)
{
/* scan to see whether or not we got the
magic character */
for (ofs = 0; ofs != count; ofs++) {
char c;
if (get_user(c, buf + ofs))
return -EFAULT;
if (c == 'V') {
if (c == 'V')
expect_close = 42;
}
}
}
@ -377,8 +377,7 @@ static struct watchdog_info ident = {
.identity = WATCHDOG_NAME,
};
static int wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int status;
int new_options, retval = -EINVAL;
@ -390,13 +389,10 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
uarg.i = (int __user *)arg;
switch(cmd)
{
default:
return -ENOTTY;
switch (cmd) {
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:
wdt_get_status(&status);
@ -405,12 +401,8 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETOPTIONS:
if (get_user (new_options, uarg.i))
if (get_user(new_options, uarg.i))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
@ -425,6 +417,10 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
return retval;
case WDIOC_KEEPALIVE:
wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, uarg.i))
return -EFAULT;
@ -438,29 +434,30 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(timeout, uarg.i);
default:
return -ENOTTY;
}
}
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_stop();
return NOTIFY_DONE;
}
static const struct file_operations wdt_fops=
{
static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdt_write,
.ioctl = wdt_ioctl,
.unlocked_ioctl = wdt_ioctl,
.open = wdt_open,
.release = wdt_release,
};
static struct miscdevice wdt_miscdev=
{
static struct miscdevice wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &wdt_fops,
@ -474,20 +471,20 @@ static int __init w83977f_wdt_init(void)
{
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 (wdt_set_timeout(timeout)) {
wdt_set_timeout(DEFAULT_TIMEOUT);
printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n",
DEFAULT_TIMEOUT);
printk(KERN_INFO PFX
"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",
IO_INDEX_PORT);
rc = -EIO;
@ -495,30 +492,30 @@ static int __init w83977f_wdt_init(void)
}
rc = register_reboot_notifier(&wdt_notifier);
if (rc)
{
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region;
}
rc = misc_register(&wdt_miscdev);
if (rc)
{
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
wdt_miscdev.minor, rc);
goto err_out_reboot;
}
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
timeout, nowayout, testmode);
printk(KERN_INFO PFX
"initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
timeout, nowayout, testmode);
return 0;
err_out_reboot:
unregister_reboot_notifier(&wdt_notifier);
err_out_region:
release_region(IO_INDEX_PORT,2);
release_region(IO_INDEX_PORT, 2);
err_out:
return rc;
}
@ -528,7 +525,7 @@ static void __exit w83977f_wdt_exit(void)
wdt_stop();
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);
release_region(IO_INDEX_PORT,2);
release_region(IO_INDEX_PORT, 2);
}
module_init(w83977f_wdt_init);

View file

@ -1,11 +1,11 @@
/*
* ICP Wafer 5823 Single Board Computer WDT driver
* http://www.icpamerica.com/wafer_5823.php
* May also work on other similar models
* http://www.icpamerica.com/wafer_5823.php
* May also work on other similar models
*
* (c) Copyright 2002 Justin Cormack <justin@street-vision.com>
*
* Release 0.02
* Release 0.02
*
* Based on advantechwdt.c which is based on wdt.c.
* Original copyright messages:
@ -36,8 +36,8 @@
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#define WATCHDOG_NAME "Wafer 5823 WDT"
#define PFX WATCHDOG_NAME ": "
@ -50,10 +50,10 @@ static DEFINE_SPINLOCK(wafwdt_lock);
/*
* You must set these - there is no sane way to probe for this board.
*
* To enable, write the timeout value in seconds (1 to 255) to I/O
* port WDT_START, then read the port to start the watchdog. To pat
* the dog, read port WDT_STOP to stop the timer, then read WDT_START
* to restart it again.
* To enable, write the timeout value in seconds (1 to 255) to I/O
* port WDT_START, then read the port to start the watchdog. To pat
* the dog, read port WDT_STOP to stop the timer, then read WDT_START
* to restart it again.
*/
static int wdt_stop = 0x843;
@ -61,11 +61,15 @@ static int wdt_start = 0x443;
static int timeout = WD_TIMO; /* in seconds */
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;
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)
{
@ -83,14 +87,14 @@ static void wafwdt_start(void)
inb_p(wdt_start);
}
static void
wafwdt_stop(void)
static void wafwdt_stop(void)
{
/* stop watchdog */
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 */
if (count) {
@ -100,7 +104,8 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co
/* In case it was set long ago */
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++) {
char c;
if (get_user(c, buf + i))
@ -109,27 +114,29 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co
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();
}
return count;
}
static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long wafwdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_timeout;
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "Wafer 5823 WDT",
};
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof (ident)))
if (copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
break;
@ -137,22 +144,6 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
wafwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if ((new_timeout < 1) || (new_timeout > 255))
return -EINVAL;
timeout = new_timeout;
wafwdt_stop();
wafwdt_start();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
@ -173,6 +164,22 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return retval;
}
case WDIOC_KEEPALIVE:
wafwdt_ping();
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
if ((new_timeout < 1) || (new_timeout > 255))
return -EINVAL;
timeout = new_timeout;
wafwdt_stop();
wafwdt_start();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
return -ENOTTY;
}
@ -191,13 +198,13 @@ static int wafwdt_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
static int
wafwdt_close(struct inode *inode, struct file *file)
static int wafwdt_close(struct inode *inode, struct file *file)
{
if (expect_close == 42) {
if (expect_close == 42)
wafwdt_stop();
} else {
printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
else {
printk(KERN_CRIT PFX
"WDT device closed unexpectedly. WDT will not stop!\n");
wafwdt_ping();
}
clear_bit(0, &wafwdt_is_open);
@ -209,12 +216,11 @@ wafwdt_close(struct inode *inode, struct file *file)
* 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) {
/* Turn the WDT off */
if (code == SYS_DOWN || code == SYS_HALT)
wafwdt_stop();
}
return NOTIFY_DONE;
}
@ -226,7 +232,7 @@ static const struct file_operations wafwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wafwdt_write,
.ioctl = wafwdt_ioctl,
.unlocked_ioctl = wafwdt_ioctl,
.open = wafwdt_open,
.release = wafwdt_close,
};
@ -250,25 +256,28 @@ static int __init wafwdt_init(void)
{
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) {
timeout = WD_TIMO;
printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n",
timeout);
printk(KERN_INFO PFX
"timeout value must be 1 <= x <= 255, using %d\n",
timeout);
}
if (wdt_stop != wdt_start) {
if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_stop);
if (!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n",
wdt_stop);
ret = -EIO;
goto error;
}
}
if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
if (!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
wdt_start);
ret = -EIO;
goto error2;
@ -276,19 +285,20 @@ static int __init wafwdt_init(void)
ret = register_reboot_notifier(&wafwdt_notifier);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", ret);
goto error3;
}
ret = misc_register(&wafwdt_miscdev);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
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);
return ret;
@ -307,7 +317,7 @@ static void __exit wafwdt_exit(void)
{
misc_deregister(&wafwdt_miscdev);
unregister_reboot_notifier(&wafwdt_notifier);
if(wdt_stop != wdt_start)
if (wdt_stop != wdt_start)
release_region(wdt_stop, 1);
release_region(wdt_start, 1);
}

View file

@ -12,7 +12,7 @@
* http://www.cymru.net
*
* This driver is provided under the GNU General Public License, incorporated
* herein by reference. The driver is provided without warranty or
* herein by reference. The driver is provided without warranty or
* support.
*
* Release 0.04.

View file

@ -35,9 +35,9 @@
#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/uaccess.h>
#include <asm/rtas.h>
#include <asm/uaccess.h>
#define WDRTAS_MAGIC_CHAR 42
#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \
@ -56,7 +56,7 @@ static int wdrtas_nowayout = 0;
#endif
static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
static char wdrtas_expect_close = 0;
static char wdrtas_expect_close;
static int wdrtas_interval;
@ -86,8 +86,8 @@ static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
* RTAS function set-indicator (surveillance). The unit of interval is
* seconds.
*/
static int
wdrtas_set_interval(int interval)
static int wdrtas_set_interval(int interval)
{
long result;
static int print_msg = 10;
@ -97,7 +97,7 @@ wdrtas_set_interval(int interval)
result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
WDRTAS_SURVEILLANCE_IND, 0, interval);
if ( (result < 0) && (print_msg) ) {
if (result < 0 && print_msg) {
printk(KERN_ERR "wdrtas: setting the watchdog to %i "
"timeout failed: %li\n", interval, result);
print_msg--;
@ -116,16 +116,14 @@ wdrtas_set_interval(int interval)
* as reported by the RTAS function ibm,get-system-parameter. The unit
* of the return value is seconds.
*/
static int
wdrtas_get_interval(int fallback_value)
static int wdrtas_get_interval(int fallback_value)
{
long result;
char value[4];
result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
WDRTAS_SP_SPI, (void *)__pa(&value), 4);
if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) ||
(result < 0) ) {
if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
"timeout (%li). Continuing\n", result);
return fallback_value;
@ -141,8 +139,7 @@ wdrtas_get_interval(int fallback_value)
* wdrtas_timer_start starts the watchdog by calling the RTAS function
* set-interval (surveillance)
*/
static void
wdrtas_timer_start(void)
static void wdrtas_timer_start(void)
{
wdrtas_set_interval(wdrtas_interval);
}
@ -153,8 +150,7 @@ wdrtas_timer_start(void)
* wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
* set-interval (surveillance)
*/
static void
wdrtas_timer_stop(void)
static void wdrtas_timer_stop(void)
{
wdrtas_set_interval(0);
}
@ -165,8 +161,7 @@ wdrtas_timer_stop(void)
* wdrtas_log_scanned_event prints a message to the log buffer dumping
* the results of the last event-scan call
*/
static void
wdrtas_log_scanned_event(void)
static void wdrtas_log_scanned_event(void)
{
int i;
@ -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\n",
(i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
}
@ -192,8 +187,7 @@ wdrtas_log_scanned_event(void)
* RTAS function event-scan and repeats these calls as long as there are
* events available. All events will be dumped.
*/
static void
wdrtas_timer_keepalive(void)
static void wdrtas_timer_keepalive(void)
{
long result;
@ -218,8 +212,7 @@ wdrtas_timer_keepalive(void)
* wdrtas_get_temperature returns the current temperature in Fahrenheit. It
* uses the RTAS call get-sensor-state, token 3 to do so
*/
static int
wdrtas_get_temperature(void)
static int wdrtas_get_temperature(void)
{
long result;
int temperature = 0;
@ -243,8 +236,7 @@ wdrtas_get_temperature(void)
* returns a bitmask of defines WDIOF_... as defined in
* include/linux/watchdog.h
*/
static int
wdrtas_get_status(void)
static int wdrtas_get_status(void)
{
return 0; /* TODO */
}
@ -255,8 +247,7 @@ wdrtas_get_status(void)
* returns a bitmask of defines WDIOF_... as defined in
* include/linux/watchdog.h, indicating why the watchdog rebooted the system
*/
static int
wdrtas_get_boot_status(void)
static int wdrtas_get_boot_status(void)
{
return 0; /* TODO */
}
@ -276,8 +267,7 @@ wdrtas_get_boot_status(void)
* character 'V'. This character allows the watchdog device to be closed
* properly.
*/
static ssize_t
wdrtas_write(struct file *file, const char __user *buf,
static ssize_t wdrtas_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
int i;
@ -306,7 +296,6 @@ wdrtas_write(struct file *file, const char __user *buf,
/**
* wdrtas_ioctl - ioctl function for the watchdog device
* @inode: inode structure
* @file: file structure
* @cmd: command for ioctl
* @arg: argument pointer
@ -315,16 +304,16 @@ wdrtas_write(struct file *file, const char __user *buf,
*
* wdrtas_ioctl implements the watchdog API ioctls
*/
static int
wdrtas_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long wdrtas_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int __user *argp = (void __user *)arg;
int i;
static struct watchdog_info wdinfo = {
.options = WDRTAS_SUPPORTED_MASK,
.firmware_version = 0,
.identity = "wdrtas"
.identity = "wdrtas",
};
switch (cmd) {
@ -357,9 +346,9 @@ wdrtas_ioctl(struct inode *inode, struct file *file,
wdrtas_timer_keepalive();
wdrtas_timer_start();
}
/* not implemented. Done by H8
if (i & WDIOS_TEMPPANIC) {
/* not implemented. Done by H8 */
}
} */
return 0;
case WDIOC_KEEPALIVE:
@ -399,8 +388,7 @@ wdrtas_ioctl(struct inode *inode, struct file *file,
*
* function called when watchdog device is opened
*/
static int
wdrtas_open(struct inode *inode, struct file *file)
static int wdrtas_open(struct inode *inode, struct file *file)
{
/* only open once */
if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
@ -423,8 +411,7 @@ wdrtas_open(struct inode *inode, struct file *file)
*
* close function. Always succeeds
*/
static int
wdrtas_close(struct inode *inode, struct file *file)
static int wdrtas_close(struct inode *inode, struct file *file)
{
/* only stop watchdog, if this was announced using 'V' before */
if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
@ -453,8 +440,7 @@ wdrtas_close(struct inode *inode, struct file *file)
* 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...
*/
static ssize_t
wdrtas_temp_read(struct file *file, char __user *buf,
static ssize_t wdrtas_temp_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
int temperature = 0;
@ -478,8 +464,7 @@ wdrtas_temp_read(struct file *file, char __user *buf,
*
* function called when temperature device is opened
*/
static int
wdrtas_temp_open(struct inode *inode, struct file *file)
static int wdrtas_temp_open(struct inode *inode, struct file *file)
{
return nonseekable_open(inode, file);
}
@ -493,8 +478,7 @@ wdrtas_temp_open(struct inode *inode, struct file *file)
*
* close function. Always succeeds
*/
static int
wdrtas_temp_close(struct inode *inode, struct file *file)
static int wdrtas_temp_close(struct inode *inode, struct file *file)
{
return 0;
}
@ -509,10 +493,10 @@ wdrtas_temp_close(struct inode *inode, struct file *file)
*
* wdrtas_reboot stops the watchdog in case of a reboot
*/
static int
wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr)
static int wdrtas_reboot(struct notifier_block *this,
unsigned long code, void *ptr)
{
if ( (code==SYS_DOWN) || (code==SYS_HALT) )
if (code == SYS_DOWN || code == SYS_HALT)
wdrtas_timer_stop();
return NOTIFY_DONE;
@ -524,7 +508,7 @@ static const struct file_operations wdrtas_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdrtas_write,
.ioctl = wdrtas_ioctl,
.unlocked_ioctl = wdrtas_ioctl,
.open = wdrtas_open,
.release = wdrtas_close,
};
@ -562,8 +546,7 @@ static struct notifier_block wdrtas_notifier = {
* this watchdog driver. It tolerates, if "get-sensor-state" and
* "ibm,get-system-parameter" are not available.
*/
static int
wdrtas_get_tokens(void)
static int wdrtas_get_tokens(void)
{
wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
@ -603,8 +586,7 @@ wdrtas_get_tokens(void)
* wdrtas_register_devs unregisters the watchdog and temperature watchdog
* misc devs
*/
static void
wdrtas_unregister_devs(void)
static void wdrtas_unregister_devs(void)
{
misc_deregister(&wdrtas_miscdev);
if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
@ -619,8 +601,7 @@ wdrtas_unregister_devs(void)
* wdrtas_register_devs registers the watchdog and temperature watchdog
* misc devs
*/
static int
wdrtas_register_devs(void)
static int wdrtas_register_devs(void)
{
int result;
@ -651,8 +632,7 @@ wdrtas_register_devs(void)
*
* registers the file handlers and the reboot notifier
*/
static int __init
wdrtas_init(void)
static int __init wdrtas_init(void)
{
if (wdrtas_get_tokens())
return -ENODEV;
@ -680,8 +660,7 @@ wdrtas_init(void)
*
* unregisters the file handlers and the reboot notifier
*/
static void __exit
wdrtas_exit(void)
static void __exit wdrtas_exit(void)
{
if (!wdrtas_nowayout)
wdrtas_timer_stop();

View file

@ -373,8 +373,6 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#endif /* CONFIG_WDT_501 */
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
@ -394,6 +392,8 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
default:
return -ENOTTY;
}
}

View file

@ -26,9 +26,9 @@
#include <linux/reboot.h>
#include <linux/init.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/mach-types.h>
#include <asm/hardware/dec21285.h>
@ -115,8 +115,8 @@ static int watchdog_release(struct inode *inode, struct file *file)
return 0;
}
static ssize_t
watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
static ssize_t watchdog_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{
/*
* Refresh the timer.
@ -127,19 +127,18 @@ watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
return len;
}
static struct watchdog_info ident = {
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT,
.identity = "Footbridge Watchdog",
};
static int
watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
static long watchdog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned int new_margin;
int ret = -ENOTTY;
switch(cmd) {
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = 0;
if (copy_to_user((void *)arg, &ident, sizeof(ident)))
@ -148,7 +147,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
ret = put_user(0,(int *)arg);
ret = put_user(0, (int *)arg);
break;
case WDIOC_KEEPALIVE:
@ -182,7 +181,7 @@ static const struct file_operations watchdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = watchdog_write,
.ioctl = watchdog_ioctl,
.unlocked_ioctl = watchdog_ioctl,
.open = watchdog_open,
.release = watchdog_release,
};
@ -204,11 +203,13 @@ static int __init footbridge_watchdog_init(void)
if (retval < 0)
return retval;
printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
soft_margin);
printk(KERN_INFO
"Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
soft_margin);
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;
}
@ -223,7 +224,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
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_exit(footbridge_watchdog_exit);

View file

@ -19,7 +19,8 @@
* 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
* nwwatchdog_init.
* 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>
@ -33,11 +34,11 @@
#include <linux/watchdog.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#define WATCHDOG_VERSION "0.04"
#define WATCHDOG_NAME "Wdt977"
@ -45,7 +46,7 @@
#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
#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 LOCK_DATA 0xAA
@ -62,13 +63,16 @@ static char expect_close;
static DEFINE_SPINLOCK(spinlock);
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_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;
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
@ -95,14 +99,16 @@ static int wdt977_start(void)
outb_p(0xF2, IO_INDEX_PORT);
outb_p(timeoutM, IO_DATA_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(0x00, IO_DATA_PORT);
/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
/* in test mode watch the bit 1 on F4 to indicate "triggered" */
if (!testmode)
{
/* At last select device Aux1 (dev=7) and set GP16 as a
* watchdog output. In test mode watch the bit 1 on F4 to
* indicate "triggered"
*/
if (!testmode) {
outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
outb_p(0x07, IO_DATA_PORT);
outb_p(0xE6, IO_INDEX_PORT);
@ -147,7 +153,8 @@ static int wdt977_stop(void)
outb_p(0xF2, IO_INDEX_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(0x07, IO_DATA_PORT);
outb_p(0xE6, IO_INDEX_PORT);
@ -202,16 +209,18 @@ static int wdt977_set_timeout(int t)
tmrval = (t + 59) / 60;
if (machine_is_netwinder()) {
/* we have a hw bug somewhere, so each 977 minute is actually only 30sec
* this limits the max timeout to half of device max of 255 minutes...
/* we have a hw bug somewhere, so each 977 minute is actually
* only 30sec. This limits the max timeout to half of device
* max of 255 minutes...
*/
tmrval += tmrval;
}
if ((tmrval < 1) || (tmrval > 255))
if (tmrval < 1 || tmrval > 255)
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;
timeoutM = tmrval;
return 0;
@ -243,7 +252,7 @@ static int wdt977_get_status(int *status)
spin_unlock_irqrestore(&spinlock, flags);
*status=0;
*status = 0;
if (new_status & 1)
*status |= WDIOF_CARDRESET;
@ -258,7 +267,7 @@ static int wdt977_get_status(int *status)
static int wdt977_open(struct inode *inode, struct file *file)
{
/* 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;
if (nowayout)
@ -274,13 +283,13 @@ static int wdt977_release(struct inode *inode, struct file *file)
* Shut off the timer.
* Lock it in if it's a module and we set nowayout
*/
if (expect_close == 42)
{
if (expect_close == 42) {
wdt977_stop();
clear_bit(0,&timer_alive);
clear_bit(0, &timer_alive);
} else {
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;
return 0;
@ -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,
size_t count, loff_t *ppos)
{
if (count)
{
if (!nowayout)
{
if (count) {
if (!nowayout) {
size_t i;
/* In case it was set long ago */
expect_close = 0;
for (i = 0; i != count; i++)
{
for (i = 0; i != count; i++) {
char c;
if (get_user(c, buf + i))
return -EFAULT;
@ -326,6 +332,14 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf,
return count;
}
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
.firmware_version = 1,
.identity = WATCHDOG_NAME,
};
/*
* wdt977_ioctl:
* @inode: inode of the device
@ -337,16 +351,8 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf,
* according to their available features.
*/
static struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
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)
static long wdt977_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int status;
int new_options, retval = -EINVAL;
@ -358,11 +364,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
uarg.i = (int __user *)arg;
switch(cmd)
{
default:
return -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident,
sizeof(ident)) ? -EFAULT : 0;
@ -374,12 +376,8 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETBOOTSTATUS:
return put_user(0, uarg.i);
case WDIOC_KEEPALIVE:
wdt977_keepalive();
return 0;
case WDIOC_SETOPTIONS:
if (get_user (new_options, uarg.i))
if (get_user(new_options, uarg.i))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
@ -394,6 +392,10 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
return retval;
case WDIOC_KEEPALIVE:
wdt977_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, uarg.i))
return -EFAULT;
@ -407,29 +409,30 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(timeout, uarg.i);
default:
return -ENOTTY;
}
}
static int wdt977_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)
wdt977_stop();
return NOTIFY_DONE;
}
static const struct file_operations wdt977_fops=
{
static const struct file_operations wdt977_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdt977_write,
.ioctl = wdt977_ioctl,
.unlocked_ioctl = wdt977_ioctl,
.open = wdt977_open,
.release = wdt977_release,
};
static struct miscdevice wdt977_miscdev=
{
static struct miscdevice wdt977_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &wdt977_fops,
@ -443,51 +446,48 @@ static int __init wd977_init(void)
{
int rc;
//if (!machine_is_netwinder())
// return -ENODEV;
printk(KERN_INFO PFX DRIVER_VERSION);
/* Check that the timeout value is within it's range ; if not reset to the default */
if (wdt977_set_timeout(timeout))
{
/* Check that the timeout value is within its range;
if not reset to the default */
if (wdt977_set_timeout(timeout)) {
wdt977_set_timeout(DEFAULT_TIMEOUT);
printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
DEFAULT_TIMEOUT);
printk(KERN_INFO PFX
"timeout value must be 60 < timeout < 15300, using %d\n",
DEFAULT_TIMEOUT);
}
/* on Netwinder the IOports are already reserved by
* arch/arm/mach-footbridge/netwinder-hw.c
*/
if (!machine_is_netwinder())
{
if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
{
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
IO_INDEX_PORT);
if (!machine_is_netwinder()) {
if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
printk(KERN_ERR PFX
"I/O address 0x%04x already in use\n",
IO_INDEX_PORT);
rc = -EIO;
goto err_out;
}
}
rc = register_reboot_notifier(&wdt977_notifier);
if (rc)
{
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register reboot notifier (err=%d)\n", rc);
goto err_out_region;
}
rc = misc_register(&wdt977_miscdev);
if (rc)
{
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
wdt977_miscdev.minor, rc);
if (rc) {
printk(KERN_ERR PFX
"cannot register miscdev on minor=%d (err=%d)\n",
wdt977_miscdev.minor, rc);
goto err_out_reboot;
}
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
timeout, nowayout, testmode);
printk(KERN_INFO PFX
"initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
timeout, nowayout, testmode);
return 0;
@ -495,7 +495,7 @@ static int __init wd977_init(void)
unregister_reboot_notifier(&wdt977_notifier);
err_out_region:
if (!machine_is_netwinder())
release_region(IO_INDEX_PORT,2);
release_region(IO_INDEX_PORT, 2);
err_out:
return rc;
}
@ -505,7 +505,7 @@ static void __exit wd977_exit(void)
wdt977_stop();
misc_deregister(&wdt977_miscdev);
unregister_reboot_notifier(&wdt977_notifier);
release_region(IO_INDEX_PORT,2);
release_region(IO_INDEX_PORT, 2);
}
module_init(wd977_init);

View file

@ -381,7 +381,7 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf,
for (i = 0; i != count; i++) {
char c;
if (get_user(c, buf+i))
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
@ -428,8 +428,6 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd,
#endif /* CONFIG_WDT_501_PCI */
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
@ -449,7 +447,9 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd,
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
}
default:
return -ENOTTY;
}
}
/**