Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
a31ebc7d
Commit
a31ebc7d
authored
Jan 10, 2003
by
Dave Jones
Browse files
Options
Browse Files
Download
Plain Diff
Merge tetrachloride.(none):/mnt/stuff/kernel/2.5/bk-linus
into tetrachloride.(none):/mnt/stuff/kernel/2.5/watchdog
parents
60e7fd5e
4b378dd8
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
2293 additions
and
438 deletions
+2293
-438
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Kconfig
+20
-0
drivers/char/watchdog/Makefile
drivers/char/watchdog/Makefile
+5
-0
drivers/char/watchdog/acquirewdt.c
drivers/char/watchdog/acquirewdt.c
+52
-44
drivers/char/watchdog/advantechwdt.c
drivers/char/watchdog/advantechwdt.c
+45
-35
drivers/char/watchdog/alim7101_wdt.c
drivers/char/watchdog/alim7101_wdt.c
+345
-0
drivers/char/watchdog/eurotechwdt.c
drivers/char/watchdog/eurotechwdt.c
+264
-252
drivers/char/watchdog/i810-tco.c
drivers/char/watchdog/i810-tco.c
+3
-1
drivers/char/watchdog/ib700wdt.c
drivers/char/watchdog/ib700wdt.c
+44
-30
drivers/char/watchdog/indydog.c
drivers/char/watchdog/indydog.c
+182
-0
drivers/char/watchdog/machzwd.c
drivers/char/watchdog/machzwd.c
+9
-8
drivers/char/watchdog/mixcomwd.c
drivers/char/watchdog/mixcomwd.c
+23
-4
drivers/char/watchdog/pcwd.c
drivers/char/watchdog/pcwd.c
+73
-38
drivers/char/watchdog/sbc60xxwdt.c
drivers/char/watchdog/sbc60xxwdt.c
+3
-3
drivers/char/watchdog/sc1200wdt.c
drivers/char/watchdog/sc1200wdt.c
+479
-0
drivers/char/watchdog/sc520_wdt.c
drivers/char/watchdog/sc520_wdt.c
+394
-0
drivers/char/watchdog/shwdt.c
drivers/char/watchdog/shwdt.c
+9
-9
drivers/char/watchdog/softdog.c
drivers/char/watchdog/softdog.c
+20
-1
drivers/char/watchdog/w83877f_wdt.c
drivers/char/watchdog/w83877f_wdt.c
+3
-3
drivers/char/watchdog/wafer5823wdt.c
drivers/char/watchdog/wafer5823wdt.c
+262
-0
drivers/char/watchdog/wdt.c
drivers/char/watchdog/wdt.c
+24
-7
drivers/char/watchdog/wdt977.c
drivers/char/watchdog/wdt977.c
+18
-0
drivers/char/watchdog/wdt_pci.c
drivers/char/watchdog/wdt_pci.c
+15
-3
include/linux/watchdog.h
include/linux/watchdog.h
+1
-0
No files found.
drivers/char/watchdog/Kconfig
View file @
a31ebc7d
...
...
@@ -283,4 +283,24 @@ config MACHZ_WDT
The module is called machzwd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
config W83877F_WDT
tristate "W83877F Computer Watchdog"
depends on WATCHDOG
config SC520_WDT
tristate "AMD Elan SC520 processor Watchdog"
depends on WATCHDOG
config ALIM7101_WDT
tristate "ALi M7101 PMU Computer Watchdog"
depends on WATCHDOG
config SC1200_WDT
tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
depends on WATCHDOG
config WAFER_WDT
tristate "ICP Wafer 5823 Single Board Computer Watchdog"
depends on WATCHDOG
endmenu
drivers/char/watchdog/Makefile
View file @
a31ebc7d
...
...
@@ -23,3 +23,8 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SH_WDT)
+=
shwdt.o
obj-$(CONFIG_EUROTECH_WDT)
+=
eurotechwdt.o
obj-$(CONFIG_SOFT_WATCHDOG)
+=
softdog.o
obj-$(CONFIG_W83877F_WDT)
+=
w83877f_wdt.o
obj-$(CONFIG_SC520_WDT)
+=
sc520_wdt.o
obj-$(CONFIG_ALIM7101_WDT)
+=
alim7101_wdt.o
obj-$(CONFIG_SC1200_WDT)
+=
sc1200wdt.o
obj-$(CONFIG_WAFER_WDT)
+=
wafer5823wdt.o
drivers/char/watchdog/acquirewdt.c
View file @
a31ebc7d
...
...
@@ -45,6 +45,7 @@
static
int
acq_is_open
;
static
spinlock_t
acq_lock
;
static
int
expect_close
=
0
;
/*
* You must set these - there is no sane way to probe for this board.
...
...
@@ -79,8 +80,20 @@ static ssize_t acq_write(struct file *file, const char *buf, size_t count, loff_
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
count
)
{
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
acq_ping
();
return
1
;
}
...
...
@@ -97,9 +110,11 @@ static ssize_t acq_read(struct file *file, char *buf, size_t count, loff_t *ppos
static
int
acq_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
static
struct
watchdog_info
ident
=
{
WDIOF_KEEPALIVEPING
,
1
,
"Acquire WDT"
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"Acquire WDT"
};
switch
(
cmd
)
...
...
@@ -126,39 +141,35 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static
int
acq_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
switch
(
minor
(
inode
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
spin_lock
(
&
acq_lock
);
if
(
acq_is_open
)
{
spin_unlock
(
&
acq_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
{
MOD_INC_USE_COUNT
;
}
/*
* Activate
*/
acq_is_open
=
1
;
inb_p
(
WDT_START
);
if
((
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
))
{
spin_lock
(
&
acq_lock
);
if
(
acq_is_open
)
{
spin_unlock
(
&
acq_lock
);
return
0
;
default:
return
-
ENODEV
;
return
-
EBUSY
;
}
if
(
nowayout
)
MOD_INC_USE_COUNT
;
/* Activate */
acq_is_open
=
1
;
inb_p
(
WDT_START
);
spin_unlock
(
&
acq_lock
);
return
0
;
}
else
{
return
-
ENODEV
;
}
}
static
int
acq_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
spin_lock
(
&
acq_lock
);
if
(
!
nowayout
)
{
if
(
expect_close
)
inb_p
(
WDT_STOP
);
}
else
printk
(
KERN_CRIT
"WDT closed unexpectedly. WDT will not stop!
\n
"
);
acq_is_open
=
0
;
spin_unlock
(
&
acq_lock
);
}
...
...
@@ -173,10 +184,9 @@ static int acq_notify_sys(struct notifier_block *this, unsigned long code,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Turn the card off */
inb_p
(
WDT_STOP
);
}
return
NOTIFY_DONE
;
}
...
...
@@ -196,9 +206,9 @@ static struct file_operations acq_fops = {
static
struct
miscdevice
acq_miscdev
=
{
WATCHDOG_MINOR
,
"watchdog"
,
&
acq_fops
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
acq_fops
};
...
...
@@ -207,11 +217,11 @@ static struct miscdevice acq_miscdev=
* turn the timebomb registers off.
*/
static
struct
notifier_block
acq_notifier
=
static
struct
notifier_block
acq_notifier
=
{
acq_notify_sys
,
NULL
,
0
.
notifier_call
=
acq_notify_sys
,
.
next
=
NULL
,
.
priority
=
0
};
static
int
__init
acq_init
(
void
)
...
...
@@ -221,17 +231,15 @@ static int __init acq_init(void)
spin_lock_init
(
&
acq_lock
);
if
(
misc_register
(
&
acq_miscdev
))
return
-
ENODEV
;
if
(
!
request_region
(
WDT_STOP
,
1
,
"Acquire WDT"
))
{
if
(
!
request_region
(
WDT_STOP
,
1
,
"Acquire WDT"
))
{
misc_deregister
(
&
acq_miscdev
);
return
-
EIO
;
}
if
(
!
request_region
(
WDT_START
,
1
,
"Acquire WDT"
))
{
}
if
(
!
request_region
(
WDT_START
,
1
,
"Acquire WDT"
))
{
release_region
(
WDT_STOP
,
1
);
misc_deregister
(
&
acq_miscdev
);
return
-
EIO
;
}
}
register_reboot_notifier
(
&
acq_notifier
);
return
0
;
...
...
drivers/char/watchdog/advantechwdt.c
View file @
a31ebc7d
...
...
@@ -47,6 +47,7 @@
#include <linux/smp_lock.h>
static
int
advwdt_is_open
;
static
char
adv_expect_close
;
static
spinlock_t
advwdt_lock
;
/*
...
...
@@ -99,10 +100,22 @@ advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
return
-
ESPIPE
;
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
adv_expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
adv_expect_close
=
42
;
}
}
advwdt_ping
();
return
1
;
}
return
0
;
return
count
;
}
static
ssize_t
...
...
@@ -116,9 +129,11 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
WDIOF_KEEPALIVEPING
,
1
,
"Advantech WDT"
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"Advantech WDT"
};
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
)))
...
...
@@ -143,26 +158,23 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static
int
advwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
switch
(
minor
(
inode
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
spin_lock
(
&
advwdt_lock
);
if
(
advwdt_is_open
)
{
spin_unlock
(
&
advwdt_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
{
MOD_INC_USE_COUNT
;
}
/*
* Activate
*/
advwdt_is_open
=
1
;
advwdt_ping
();
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
spin_lock
(
&
advwdt_lock
);
if
(
advwdt_is_open
)
{
spin_unlock
(
&
advwdt_lock
);
return
0
;
default:
return
-
ENODEV
;
return
-
EBUSY
;
}
if
(
nowayout
)
MOD_INC_USE_COUNT
;
/* Activate */
advwdt_is_open
=
1
;
advwdt_ping
();
spin_unlock
(
&
advwdt_lock
);
return
0
;
}
else
{
return
-
ENODEV
;
}
}
...
...
@@ -171,9 +183,9 @@ advwdt_close(struct inode *inode, struct file *file)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
spin_lock
(
&
advwdt_lock
);
if
(
!
nowayout
)
{
if
(
!
nowayout
)
inb_p
(
WDT_STOP
);
}
advwdt_is_open
=
0
;
spin_unlock
(
&
advwdt_lock
);
}
...
...
@@ -188,10 +200,10 @@ static int
advwdt_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 */
inb_p
(
WDT_STOP
);
}
return
NOTIFY_DONE
;
}
...
...
@@ -209,9 +221,9 @@ static struct file_operations advwdt_fops = {
};
static
struct
miscdevice
advwdt_miscdev
=
{
WATCHDOG_MINOR
,
"watchdog"
,
&
advwdt_fops
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
advwdt_fops
};
/*
...
...
@@ -220,9 +232,9 @@ static struct miscdevice advwdt_miscdev = {
*/
static
struct
notifier_block
advwdt_notifier
=
{
advwdt_notify_sys
,
NULL
,
0
.
notifier_call
=
advwdt_notify_sys
,
.
next
=
NULL
,
.
priority
=
0
};
static
void
__init
...
...
@@ -276,5 +288,3 @@ module_exit(advwdt_exit);
MODULE_LICENSE
(
"GPL"
);
/* end of advantechwdt.c */
drivers/char/watchdog/alim7101_wdt.c
0 → 100644
View file @
a31ebc7d
/*
* ALi M7101 PMU Computer Watchdog Timer driver for Linux 2.4.x
*
* Based on w83877f_wdt.c by Scott Jennings <management@oro.net>
* and the Cobalt kernel WDT timer driver by Tim Hockin
* <thockin@cobaltnet.com>
*
* (c)2002 Steve Hill <steve@navaho.co.uk>
*
* Theory of operation:
* A Watchdog Timer (WDT) is a hardware circuit that can
* reset the computer system in case of a software fault.
* You probably knew that already.
*
* Usually a userspace daemon will notify the kernel WDT driver
* via the /proc/watchdog special device file that userspace is
* still alive, at regular intervals. When such a notification
* occurs, the driver will usually tell the hardware watchdog
* that everything is in order, and that the watchdog should wait
* for yet another little while to reset the system.
* If userspace fails (RAM error, kernel bug, whatever), the
* notifications cease to occur, and the hardware watchdog will
* reset the system (causing a reboot) after the timeout occurs.
*
* This WDT driver is different from most other Linux WDT
* drivers in that the driver will ping the watchdog by itself,
* because this particular WDT has a very short timeout (1.6
* seconds) and it would be insane to count on any userspace
* daemon always getting scheduled within that time frame.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/pci.h>
#define OUR_NAME "alim7101_wdt"
#define WDT_ENABLE 0x9C
#define WDT_DISABLE 0x8C
#define ALI_7101_WDT 0x92
#define ALI_WDT_ARM 0x01
/*
* We're going to use a 1 second timeout.
* If we reset the watchdog every ~250ms we should be safe. */
#define WDT_INTERVAL (HZ/4+1)
/*
* We must not require too good response from the userspace daemon.
* Here we require the userspace daemon to send us a heartbeat
* char to /dev/watchdog every 30 seconds.
*/
#define WDT_HEARTBEAT (HZ * 30)
static
void
wdt_timer_ping
(
unsigned
long
);
static
struct
timer_list
timer
;
static
unsigned
long
next_heartbeat
;
static
unsigned
long
wdt_is_open
;
static
int
wdt_expect_close
;
static
struct
pci_dev
*
alim7101_pmu
;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
#else
static
int
nowayout
=
0
;
#endif
MODULE_PARM
(
nowayout
,
"i"
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
/*
* Whack the dog
*/
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
;
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
));
}
else
{
printk
(
OUR_NAME
": Heartbeat lost! Will not ping the watchdog
\n
"
);
}
/* Re-set the timer interval */
timer
.
expires
=
jiffies
+
WDT_INTERVAL
;
add_timer
(
&
timer
);
}
/*
* Utility routines
*/
static
void
wdt_change
(
int
writeval
)
{
char
tmp
;
pci_read_config_byte
(
alim7101_pmu
,
0x92
,
&
tmp
);
if
(
writeval
==
WDT_ENABLE
)
pci_write_config_byte
(
alim7101_pmu
,
ALI_7101_WDT
,
(
tmp
|
ALI_WDT_ARM
));
else
pci_write_config_byte
(
alim7101_pmu
,
ALI_7101_WDT
,
(
tmp
&
~
ALI_WDT_ARM
));
}
static
void
wdt_startup
(
void
)
{
next_heartbeat
=
jiffies
+
WDT_HEARTBEAT
;
/* We must enable before we kick off the timer in case the timer
occurs as we ping it */
wdt_change
(
WDT_ENABLE
);
/* Start the timer */
timer
.
expires
=
jiffies
+
WDT_INTERVAL
;
add_timer
(
&
timer
);
printk
(
OUR_NAME
": Watchdog timer is now enabled.
\n
"
);
}
static
void
wdt_turnoff
(
void
)
{
/* Stop the timer */
del_timer_sync
(
&
timer
);
wdt_change
(
WDT_DISABLE
);
printk
(
OUR_NAME
": Watchdog timer is now disabled...
\n
"
);
}
/*
* /dev/watchdog handling
*/
static
ssize_t
fop_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
/* We can't seek */
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
/* See if we got the magic character */
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
ofs
;
/* note: just in case someone wrote the magic character
* five months ago... */
wdt_expect_close
=
0
;
/* now scan */
for
(
ofs
=
0
;
ofs
!=
count
;
ofs
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
ofs
))
return
-
EFAULT
;
if
(
c
==
'V'
)
wdt_expect_close
=
1
;
}
}
/* someone wrote to us, we should restart timer */
next_heartbeat
=
jiffies
+
WDT_HEARTBEAT
;
return
1
;
};
return
0
;
}
static
ssize_t
fop_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
/* No can do */
return
-
EINVAL
;
}
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
))
return
-
EBUSY
;
/* Good, fire up the show */
wdt_startup
();
return
0
;
}
static
int
fop_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
wdt_expect_close
)
wdt_turnoff
();
else
printk
(
OUR_NAME
": device file closed unexpectedly. Will not stop the WDT!
\n
"
);
clear_bit
(
0
,
&
wdt_is_open
);
return
0
;
}
static
int
fop_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"ALiM7101"
};
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
return
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
))
?-
EFAULT
:
0
;
case
WDIOC_KEEPALIVE
:
next_heartbeat
=
jiffies
+
WDT_HEARTBEAT
;
return
0
;
default:
return
-
ENOTTY
;
}
}
static
struct
file_operations
wdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
read
=
fop_read
,
.
write
=
fop_write
,
.
open
=
fop_open
,
.
release
=
fop_close
,
.
ioctl
=
fop_ioctl
};
static
struct
miscdevice
wdt_miscdev
=
{
.
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
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
wdt_turnoff
();
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
*/
wdt_change
(
WDT_ENABLE
);
printk
(
OUR_NAME
": Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.
\n
"
);
}
return
NOTIFY_DONE
;
}
/*
* The WDT needs to learn about soft shutdowns in order to
* turn the timebomb registers off.
*/
static
struct
notifier_block
wdt_notifier
=
{
.
notifier_call
=
wdt_notify_sys
,
.
next
=
0
,
.
priority
=
0
};
static
void
__exit
alim7101_wdt_unload
(
void
)
{
wdt_turnoff
();
/* Deregister */
misc_deregister
(
&
wdt_miscdev
);
unregister_reboot_notifier
(
&
wdt_notifier
);
}
static
int
__init
alim7101_wdt_init
(
void
)
{
int
rc
=
-
EBUSY
;
struct
pci_dev
*
ali1543_south
;
char
tmp
;
printk
(
KERN_INFO
OUR_NAME
": Steve Hill <steve@navaho.co.uk>.
\n
"
);
alim7101_pmu
=
pci_find_device
(
PCI_VENDOR_ID_AL
,
PCI_DEVICE_ID_AL_M7101
,
NULL
);
if
(
!
alim7101_pmu
)
{
printk
(
KERN_INFO
OUR_NAME
": ALi M7101 PMU not present - WDT not set
\n
"
);
return
-
EBUSY
;
}
/* Set the WDT in the PMU to 1 second */
pci_write_config_byte
(
alim7101_pmu
,
ALI_7101_WDT
,
0x02
);
ali1543_south
=
pci_find_device
(
PCI_VENDOR_ID_AL
,
PCI_DEVICE_ID_AL_M1533
,
NULL
);
if
(
!
ali1543_south
)
{
printk
(
KERN_INFO
OUR_NAME
": ALi 1543 South-Bridge not present - WDT not set
\n
"
);
return
-
EBUSY
;
}
pci_read_config_byte
(
ali1543_south
,
0x5e
,
&
tmp
);
if
((
tmp
&
0x1e
)
!=
0x12
)
{
printk
(
KERN_INFO
OUR_NAME
": ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set
\n
"
);
return
-
EBUSY
;
}
init_timer
(
&
timer
);
timer
.
function
=
wdt_timer_ping
;
timer
.
data
=
1
;
rc
=
misc_register
(
&
wdt_miscdev
);
if
(
rc
)
return
rc
;
rc
=
register_reboot_notifier
(
&
wdt_notifier
);
if
(
rc
)
{
misc_deregister
(
&
wdt_miscdev
);
return
rc
;
}
printk
(
KERN_INFO
OUR_NAME
": WDT driver for ALi M7101 initialised.
\n
"
);
return
0
;
}
module_init
(
alim7101_wdt_init
);
module_exit
(
alim7101_wdt_unload
);
MODULE_AUTHOR
(
"Steve Hill"
);
MODULE_LICENSE
(
"GPL"
);
drivers/char/watchdog/eurotechwdt.c
View file @
a31ebc7d
...
...
@@ -7,23 +7,23 @@
* Based on wdt.c.
* Original copyright messages:
*
*
(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
*
http://www.redhat.com
*
(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
*
http://www.redhat.com
*
*
This program is free software; you can redistribute it and/or
*
modify it under the terms of the GNU General Public License
*
as published by the Free Software Foundation; either version
*
2 of the License, or (at your option) any later version.
*
This program is free software; you can redistribute it and/or
*
modify it under the terms of the GNU General Public License
*
as published by the Free Software Foundation; either version
*
2 of the License, or (at your option) any later version.
*
*
Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
*
warranty for any of this software. This material is provided
*
"AS-IS" and at no charge.
*
Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
*
warranty for any of this software. This material is provided
*
"AS-IS" and at no charge.
*
*
(c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>*
*
(c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
*
14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
*
Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*
Added timeout module option to override default
*
14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
*
Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*
Added timeout module option to override default
*/
#include <linux/config.h>
...
...
@@ -49,17 +49,18 @@
static
int
eurwdt_is_open
;
static
spinlock_t
eurwdt_lock
;
static
char
eur_expect_close
;
/*
*
You must set these - there is no sane way to probe for this board.
*
You can use wdt=x,y to set these now.
* You must set these - there is no sane way to probe for this board.
* You can use wdt=x,y to set these now.
*/
static
int
io
=
0x3f0
;
static
int
irq
=
10
;
static
char
*
ev
=
"int"
;
#define WDT_TIMEOUT 60
/* 1 minute */
#define WDT_TIMEOUT 60
/* 1 minute */
static
int
timeout
=
WDT_TIMEOUT
;
MODULE_PARM
(
timeout
,
"i"
);
...
...
@@ -80,10 +81,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
#define WDT_CTRL_REG 0x30
#define WDT_OUTPIN_CFG 0xe2
#define WDT_EVENT_INT
0x00
#define WDT_EVENT_REBOOT
0x08
#define WDT_EVENT_INT
0x00
#define WDT_EVENT_REBOOT
0x08
#define WDT_UNIT_SEL 0xf1
#define WDT_UNIT_SECS
0x80
#define WDT_UNIT_SECS
0x80
#define WDT_TIMEOUT_VAL 0xf2
#define WDT_TIMER_CFG 0xf3
...
...
@@ -91,27 +92,27 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
#ifndef MODULE
/**
*
eurwdt_setup:
*
@str: command line string
* eurwdt_setup:
* @str: command line string
*
*
Setup options. The board isn't really probe-able so we have to
*
get the user to tell us the configuration. Sane people build it
*
modular but the others come here.
* Setup options. The board isn't really probe-able so we have to
* get the user to tell us the configuration. Sane people build it
* modular but the others come here.
*/
static
int
__init
eurwdt_setup
(
char
*
str
)
{
int
ints
[
4
];
int
ints
[
4
];
str
=
get_options
(
str
,
ARRAY_SIZE
(
ints
),
ints
);
str
=
get_options
(
str
,
ARRAY_SIZE
(
ints
),
ints
);
if
(
ints
[
0
]
>
0
)
{
io
=
ints
[
1
];
if
(
ints
[
0
]
>
1
)
irq
=
ints
[
2
];
}
if
(
ints
[
0
]
>
0
)
{
io
=
ints
[
1
];
if
(
ints
[
0
]
>
1
)
irq
=
ints
[
2
];
}
return
1
;
return
1
;
}
__setup
(
"wdt="
,
eurwdt_setup
);
...
...
@@ -127,7 +128,7 @@ MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `reboot')");
/*
*
Programming support
* Programming support
*/
static
void
__init
eurwdt_validate_timeout
(
void
)
...
...
@@ -135,265 +136,276 @@ static void __init eurwdt_validate_timeout(void)
if
(
timeout
<
0
||
timeout
>
255
)
{
timeout
=
WDT_TIMEOUT
;
printk
(
KERN_INFO
"eurwdt: timeout must be 0 < x < 255, using %d
\n
"
,
timeout
);
timeout
);
}
}
static
inline
void
eurwdt_write_reg
(
u8
index
,
u8
data
)
{
outb
(
index
,
io
);
outb
(
data
,
io
+
1
);
outb
(
index
,
io
);
outb
(
data
,
io
+
1
);
}
static
inline
void
eurwdt_lock_chip
(
void
)
{
outb
(
0xaa
,
io
);
outb
(
0xaa
,
io
);
}
static
inline
void
eurwdt_unlock_chip
(
void
)
{
outb
(
0x55
,
io
);
eurwdt_write_reg
(
0x07
,
0x08
);
/* set the logical device */
outb
(
0x55
,
io
);
eurwdt_write_reg
(
0x07
,
0x08
);
/* set the logical device */
}
static
inline
void
eurwdt_set_timeout
(
int
timeout
)
{
eurwdt_write_reg
(
WDT_TIMEOUT_VAL
,
(
u8
)
timeout
);
eurwdt_write_reg
(
WDT_TIMEOUT_VAL
,
(
u8
)
timeout
);
}
static
inline
void
eurwdt_disable_timer
(
void
)
{
eurwdt_set_timeout
(
0
);
eurwdt_set_timeout
(
0
);
}
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
);
/* Setting interrupt line */
if
(
irq
==
2
||
irq
>
15
||
irq
<
0
)
{
printk
(
KERN_ERR
": invalid irq number
\n
"
);
irq
=
0
;
/* if invalid we disable interrupt */
}
if
(
irq
==
0
)
printk
(
KERN_INFO
": interrupt disabled
\n
"
);
eurwdt_write_reg
(
WDT_TIMER_CFG
,
irq
<<
4
);
eurwdt_write_reg
(
WDT_UNIT_SEL
,
WDT_UNIT_SECS
);
/* we use seconds */
eurwdt_set_timeout
(
0
);
/* the default timeout */
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
);
/* Setting interrupt line */
if
(
irq
==
2
||
irq
>
15
||
irq
<
0
)
{
printk
(
KERN_ERR
": invalid irq number
\n
"
);
irq
=
0
;
/* if invalid we disable interrupt */
}
if
(
irq
==
0
)
printk
(
KERN_INFO
": interrupt disabled
\n
"
);
eurwdt_write_reg
(
WDT_TIMER_CFG
,
irq
<<
4
);
eurwdt_write_reg
(
WDT_UNIT_SEL
,
WDT_UNIT_SECS
);
/* we use seconds */
eurwdt_set_timeout
(
0
);
/* the default timeout */
}
/*
*
Kernel methods.
* Kernel methods.
*/
void
eurwdt_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
printk
(
KERN_CRIT
"timeout WDT timeout
\n
"
);
printk
(
KERN_CRIT
"timeout WDT timeout
\n
"
);
#ifdef ONLY_TESTING
printk
(
KERN_CRIT
"Would Reboot.
\n
"
);
printk
(
KERN_CRIT
"Would Reboot.
\n
"
);
#else
printk
(
KERN_CRIT
"Initiating system reboot.
\n
"
);
machine_restart
(
NULL
);
printk
(
KERN_CRIT
"Initiating system reboot.
\n
"
);
machine_restart
(
NULL
);
#endif
}
/**
*
eurwdt_ping:
* eurwdt_ping:
*
*
Reload counter one with the watchdog timeout.
* Reload counter one with the watchdog timeout.
*/
static
void
eurwdt_ping
(
void
)
{
/* Write the watchdog default value */
eurwdt_set_timeout
(
timeout
);
/* Write the watchdog default value */
eurwdt_set_timeout
(
timeout
);
}
/**
*
eurwdt_write:
*
@file: file handle to the watchdog
*
@buf: buffer to write (unused as data does not matter here
*
@count: count of bytes
*
@ppos: pointer to the position to write. No seeks allowed
* eurwdt_write:
* @file: file handle to the watchdog
* @buf: buffer to write (unused as data does not matter here
* @count: count of bytes
* @ppos: pointer to the position to write. No seeks allowed
*
*
A write to a watchdog device is defined as a keepalive signal. Any
*
write of data will do, as we we don't define content meaning.
* A write to a watchdog device is defined as a keepalive signal. Any
* write of data will do, as we we don't define content meaning.
*/
static
ssize_t
eurwdt_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
/* Can't seek (pwrite) on this device */
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
count
)
{
eurwdt_ping
();
/* the default timeout */
return
1
;
}
/* Can't seek (pwrite) on this device */
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
eur_expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
eur_expect_close
=
42
;
}
}
eurwdt_ping
();
/* the default timeout */
return
1
;
}
return
0
;
return
0
;
}
/**
*
eurwdt_ioctl:
*
@inode: inode of the device
*
@file: file handle to the device
*
@cmd: watchdog command
*
@arg: argument pointer
* eurwdt_ioctl:
* @inode: inode of the device
* @file: file handle to the device
* @cmd: watchdog command
* @arg: argument pointer
*
*
The watchdog API defines a common set of functions for all watchdogs
*
according to their available features.
* The watchdog API defines a common set of functions for all watchdogs
* according to their available features.
*/
static
int
eurwdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_CARDRESET
,
.
firmware_version
=
1
,
.
identity
=
"WDT Eurotech CPU-1220/1410"
,
};
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_CARDRESET
,
.
firmware_version
=
1
,
.
identity
=
"WDT Eurotech CPU-1220/1410"
,
};
int
time
;
int
time
;
switch
(
cmd
)
{
default:
return
-
ENOTTY
;
switch
(
cmd
)
{
default:
return
-
ENOTTY
;
case
WDIOC_GETSUPPORT
:
return
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
))
?
-
EFAULT
:
0
;
case
WDIOC_GETSUPPORT
:
return
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
))
?
-
EFAULT
:
0
;
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
0
,
(
int
*
)
arg
);
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
0
,
(
int
*
)
arg
);
case
WDIOC_KEEPALIVE
:
eurwdt_ping
();
return
0
;
case
WDIOC_KEEPALIVE
:
eurwdt_ping
();
return
0
;
case
WDIOC_SETTIMEOUT
:
if
(
copy_from_user
(
&
time
,
(
int
*
)
arg
,
sizeof
(
int
)))
return
-
EFAULT
;
case
WDIOC_SETTIMEOUT
:
if
(
copy_from_user
(
&
time
,
(
int
*
)
arg
,
sizeof
(
int
)))
return
-
EFAULT
;
/* Sanity check */
if
(
time
<
0
||
time
>
255
)
return
-
EINVAL
;
/* Sanity check */
if
(
time
<
0
||
time
>
255
)
return
-
EINVAL
;
timeout
=
time
;
eurwdt_set_timeout
(
time
);
return
0
;
}
timeout
=
time
;
eurwdt_set_timeout
(
time
);
return
0
;
}
}
/**
*
eurwdt_open:
*
@inode: inode of device
*
@file: file handle to device
* eurwdt_open:
* @inode: inode of device
* @file: file handle to device
*
*
The misc device has been opened. The watchdog device is single
*
open and on opening we load the counter.
* The misc device has been opened. The watchdog device is single
* open and on opening we load the counter.
*/
static
int
eurwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
switch
(
minor
(
inode
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
spin_lock
(
&
eurwdt_lock
);
if
(
eurwdt_is_open
)
{
spin_unlock
(
&
eurwdt_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
{
MOD_INC_USE_COUNT
;
}
eurwdt_is_open
=
1
;
/* Activate the WDT */
eurwdt_activate_timer
();
spin_unlock
(
&
eurwdt_lock
);
MOD_INC_USE_COUNT
;
return
0
;
case
TEMP_MINOR
:
return
0
;
default:
return
-
ENODEV
;
}
switch
(
minor
(
inode
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
spin_lock
(
&
eurwdt_lock
);
if
(
eurwdt_is_open
)
{
spin_unlock
(
&
eurwdt_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
MOD_INC_USE_COUNT
;
eurwdt_is_open
=
1
;
/* Activate the WDT */
eurwdt_activate_timer
();
spin_unlock
(
&
eurwdt_lock
);
MOD_INC_USE_COUNT
;
return
0
;
case
TEMP_MINOR
:
return
0
;
default:
return
-
ENODEV
;
}
}
/**
*
eurwdt_release:
*
@inode: inode to board
*
@file: file handle to board
* eurwdt_release:
* @inode: inode to board
* @file: file handle to board
*
*
The watchdog has a configurable API. There is a religious dispute
*
between people who want their watchdog to be able to shut down and
*
those who want to be sure if the watchdog manager dies the machine
*
reboots. In the former case we disable the counters, in the latter
*
case you have to open it again very soon.
* The watchdog has a configurable API. There is a religious dispute
* between people who want their watchdog to be able to shut down and
* those who want to be sure if the watchdog manager dies the machine
* reboots. In the former case we disable the counters, in the latter
* case you have to open it again very soon.
*/
static
int
eurwdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
!
nowayout
)
{
eurwdt_disable_timer
();
}
eurwdt_is_open
=
0
;
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
!
nowayout
)
eurwdt_disable_timer
();
MOD_DEC_USE_COUNT
;
}
eurwdt_is_open
=
0
;
MOD_DEC_USE_COUNT
;
}
return
0
;
return
0
;
}
/**
*
eurwdt_notify_sys:
*
@this: our notifier block
*
@code: the event being reported
*
@unused: unused
* eurwdt_notify_sys:
* @this: our notifier block
* @code: the event being reported
* @unused: unused
*
*
Our notifier is called on system shutdowns. We want to turn the card
*
off at reboot otherwise the machine will reboot again during memory
*
test or worse yet during the following fsck. This would suck, in fact
*
trust me - if it happens it does suck.
* Our notifier is called on system shutdowns. We want to turn the card
* off at reboot otherwise the machine will reboot again during memory
* test or worse yet during the following fsck. This would suck, in fact
* trust me - if it happens it does suck.
*/
static
int
eurwdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Turn the card off */
eurwdt_disable_timer
();
}
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Turn the card off */
eurwdt_disable_timer
();
}
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
}
/*
*
Kernel Interfaces
* Kernel Interfaces
*/
static
struct
file_operations
eurwdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
eurwdt_write
,
.
ioctl
=
eurwdt_ioctl
,
.
open
=
eurwdt_open
,
.
release
=
eurwdt_release
,
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
eurwdt_write
,
.
ioctl
=
eurwdt_ioctl
,
.
open
=
eurwdt_open
,
.
release
=
eurwdt_release
,
};
static
struct
miscdevice
eurwdt_miscdev
=
{
...
...
@@ -403,8 +415,8 @@ static struct miscdevice eurwdt_miscdev = {
};
/*
*
The WDT card needs to learn about soft shutdowns in order to
*
turn the timebomb registers off.
* The WDT card needs to learn about soft shutdowns in order to
* turn the timebomb registers off.
*/
static
struct
notifier_block
eurwdt_notifier
=
{
...
...
@@ -412,85 +424,85 @@ static struct notifier_block eurwdt_notifier = {
};
/**
*
cleanup_module:
* cleanup_module:
*
*
Unload the watchdog. You cannot do this with any file handles open.
*
If your watchdog is set to continue ticking on close and you unload
*
it, well it keeps ticking. We won't get the interrupt but the board
*
will not touch PC memory so all is fine. You just have to load a new
*
module in 60 seconds or reboot.
* Unload the watchdog. You cannot do this with any file handles open.
* If your watchdog is set to continue ticking on close and you unload
* it, well it keeps ticking. We won't get the interrupt but the board
* will not touch PC memory so all is fine. You just have to load a new
* module in 60 seconds or reboot.
*/
static
void
__exit
eurwdt_exit
(
void
)
{
eurwdt_lock_chip
();
eurwdt_lock_chip
();
misc_deregister
(
&
eurwdt_miscdev
);
misc_deregister
(
&
eurwdt_miscdev
);
unregister_reboot_notifier
(
&
eurwdt_notifier
);
release_region
(
io
,
2
);
free_irq
(
irq
,
NULL
);
unregister_reboot_notifier
(
&
eurwdt_notifier
);
release_region
(
io
,
2
);
free_irq
(
irq
,
NULL
);
}
/**
*
eurwdt_init:
* eurwdt_init:
*
*
Set up the WDT watchdog board. After grabbing the resources
*
we require we need also to unlock the device.
*
The open() function will actually kick the board off.
* Set up the WDT watchdog board. After grabbing the resources
* we require we need also to unlock the device.
* The open() function will actually kick the board off.
*/
static
int
__init
eurwdt_init
(
void
)
{
int
ret
;
eurwdt_validate_timeout
();
ret
=
misc_register
(
&
eurwdt_miscdev
);
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: can't misc_register on minor=%d
\n
"
,
WATCHDOG_MINOR
);
goto
out
;
}
ret
=
request_irq
(
irq
,
eurwdt_interrupt
,
SA_INTERRUPT
,
"eurwdt"
,
NULL
);
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: IRQ %d is not free.
\n
"
,
irq
);
goto
outmisc
;
}
if
(
!
request_region
(
io
,
2
,
"eurwdt"
))
{
printk
(
KERN_ERR
"eurwdt: IO %X is not free.
\n
"
,
io
);
ret
=
-
EBUSY
;
goto
outirq
;
}
ret
=
register_reboot_notifier
(
&
eurwdt_notifier
);
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: can't register reboot notifier (err=%d)
\n
"
,
ret
);
goto
outreg
;
}
eurwdt_unlock_chip
();
ret
=
0
;
printk
(
KERN_INFO
"Eurotech WDT driver 0.01 at %X (Interrupt %d)"
" - timeout event: %s
\n
"
,
io
,
irq
,
(
!
strcmp
(
"int"
,
ev
)
?
"int"
:
"reboot"
));
spin_lock_init
(
&
eurwdt_lock
);
out:
return
ret
;
outreg:
release_region
(
io
,
2
);
outirq:
free_irq
(
irq
,
NULL
);
outmisc:
misc_deregister
(
&
eurwdt_miscdev
);
goto
out
;
int
ret
;
eurwdt_validate_timeout
();
ret
=
misc_register
(
&
eurwdt_miscdev
);
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: can't misc_register on minor=%d
\n
"
,
WATCHDOG_MINOR
);
goto
out
;
}
ret
=
request_irq
(
irq
,
eurwdt_interrupt
,
SA_INTERRUPT
,
"eurwdt"
,
NULL
);
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: IRQ %d is not free.
\n
"
,
irq
);
goto
outmisc
;
}
if
(
!
request_region
(
io
,
2
,
"eurwdt"
))
{
printk
(
KERN_ERR
"eurwdt: IO %X is not free.
\n
"
,
io
);
ret
=
-
EBUSY
;
goto
outirq
;
}
ret
=
register_reboot_notifier
(
&
eurwdt_notifier
);
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: can't register reboot notifier (err=%d)
\n
"
,
ret
);
goto
outreg
;
}
eurwdt_unlock_chip
();
ret
=
0
;
printk
(
KERN_INFO
"Eurotech WDT driver 0.01 at %X (Interrupt %d)"
" - timeout event: %s
\n
"
,
io
,
irq
,
(
!
strcmp
(
"int"
,
ev
)
?
"int"
:
"reboot"
));
spin_lock_init
(
&
eurwdt_lock
);
out:
return
ret
;
outreg:
release_region
(
io
,
2
);
outirq:
free_irq
(
irq
,
NULL
);
outmisc:
misc_deregister
(
&
eurwdt_miscdev
);
goto
out
;
}
module_init
(
eurwdt_init
);
...
...
drivers/char/watchdog/i810-tco.c
View file @
a31ebc7d
...
...
@@ -244,7 +244,9 @@ static int i810tco_ioctl (struct inode *inode, struct file *file,
int
options
,
retval
=
-
EINVAL
;
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
,
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
0
,
.
identity
=
"i810 TCO timer"
,
};
...
...
drivers/char/watchdog/ib700wdt.c
View file @
a31ebc7d
...
...
@@ -54,6 +54,7 @@
static
int
ibwdt_is_open
;
static
spinlock_t
ibwdt_lock
;
static
int
expect_close
=
0
;
/*
*
...
...
@@ -136,6 +137,21 @@ ibwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
return
-
ESPIPE
;
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
ibwdt_ping
();
return
1
;
}
...
...
@@ -153,7 +169,9 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
WDIOF_KEEPALIVEPING
,
1
,
"IB700 WDT"
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"IB700 WDT"
};
switch
(
cmd
)
{
...
...
@@ -180,42 +198,38 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static
int
ibwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
switch
(
minor
(
inode
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
spin_lock
(
&
ibwdt_lock
);
if
(
ibwdt_is_open
)
{
spin_unlock
(
&
ibwdt_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
{
MOD_INC_USE_COUNT
;
}
/*
* Activate
*/
ibwdt_is_open
=
1
;
ibwdt_ping
();
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
spin_lock
(
&
ibwdt_lock
);
if
(
ibwdt_is_open
)
{
spin_unlock
(
&
ibwdt_lock
);
return
0
;
default:
return
-
ENODEV
;
return
-
EBUSY
;
}
if
(
nowayout
)
MOD_INC_USE_COUNT
;
/* Activate */
ibwdt_is_open
=
1
;
ibwdt_ping
();
spin_unlock
(
&
ibwdt_lock
);
return
0
;
}
else
{
return
-
ENODEV
;
}
}
static
int
ibwdt_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
lock_kernel
();
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
spin_lock
(
&
ibwdt_lock
);
if
(
!
nowayout
)
{
if
(
expect_close
)
outb_p
(
timeout_val
,
WDT_STOP
);
}
else
printk
(
KERN_CRIT
"WDT device closed unexpectedly. WDT will not stop!
\n
"
);
ibwdt_is_open
=
0
;
spin_unlock
(
&
ibwdt_lock
);
}
unlock_kernel
();
return
0
;
}
...
...
@@ -248,9 +262,9 @@ static struct file_operations ibwdt_fops = {
};
static
struct
miscdevice
ibwdt_miscdev
=
{
WATCHDOG_MINOR
,
"watchdog"
,
&
ibwdt_fops
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
ibwdt_fops
};
/*
...
...
@@ -259,9 +273,9 @@ static struct miscdevice ibwdt_miscdev = {
*/
static
struct
notifier_block
ibwdt_notifier
=
{
ibwdt_notify_sys
,
NULL
,
0
.
notifier_call
=
ibwdt_notify_sys
,
.
next
=
NULL
,
.
priority
=
0
};
static
int
__init
...
...
drivers/char/watchdog/indydog.c
0 → 100644
View file @
a31ebc7d
/*
* IndyDog 0.2 A Hardware Watchdog Device for SGI IP22
*
* (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
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* based on softdog.c by Alan Cox <alan@redhat.com>
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/sgi/sgimc.h>
static
unsigned
long
indydog_alive
;
static
struct
sgimc_misc_ctrl
*
mcmisc_regs
;
static
int
expect_close
=
0
;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
#else
static
int
nowayout
=
0
;
#endif
MODULE_PARM
(
nowayout
,
"i"
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
static
void
indydog_ping
()
{
mcmisc_regs
->
watchdogt
=
0
;
}
/*
* Allow only one person to hold it open
*/
static
int
indydog_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
u32
mc_ctrl0
;
if
(
test_and_set_bit
(
0
,
&
indydog_alive
)
)
return
-
EBUSY
;
if
(
nowayout
)
MOD_INC_USE_COUNT
;
/*
* Activate timer
*/
mcmisc_regs
=
(
struct
sgimc_misc_ctrl
*
)(
KSEG1
+
0x1fa00000
);
mc_ctrl0
=
mcmisc_regs
->
cpuctrl0
|
SGIMC_CCTRL0_WDOG
;
mcmisc_regs
->
cpuctrl0
=
mc_ctrl0
;
indydog_ping
();
printk
(
"Started watchdog timer.
\n
"
);
return
0
;
}
static
int
indydog_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
)
{
u32
mc_ctrl0
=
mcmisc_regs
->
cpuctrl0
;
mc_ctrl0
&=
~
SGIMC_CCTRL0_WDOG
;
mcmisc_regs
->
cpuctrl0
=
mc_ctrl0
;
printk
(
"Stopped watchdog timer.
\n
"
);
}
else
{
printk
(
KERN_CRIT
"WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
clear_bit
(
0
,
&
indydog_alive
);
return
0
;
}
static
ssize_t
indydog_write
(
struct
file
*
file
,
const
char
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
/* Can't seek (pwrite) on this device */
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
/* Refresh the timer. */
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
indydog_ping
();
return
1
;
}
return
0
;
}
static
int
indydog_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_MAGICCLOSE
,
.
identity
=
"Hardware Watchdog for SGI IP22"
,
};
switch
(
cmd
)
{
default:
return
-
ENOIOCTLCMD
;
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
;
}
}
static
struct
file_operations
indydog_fops
=
{
.
owner
=
THIS_MODULE
,
.
write
=
indydog_write
,
.
ioctl
=
indydog_ioctl
,
.
open
=
indydog_open
,
.
release
=
indydog_release
,
};
static
struct
miscdevice
indydog_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
indydog_fops
,
};
static
const
char
banner
[]
__initdata
=
KERN_INFO
"Hardware Watchdog Timer for SGI IP22: 0.2
\n
"
;
static
int
__init
watchdog_init
(
void
)
{
int
ret
;
ret
=
misc_register
(
&
indydog_miscdev
);
if
(
ret
)
return
ret
;
printk
(
banner
);
return
0
;
}
static
void
__exit
watchdog_exit
(
void
)
{
misc_deregister
(
&
indydog_miscdev
);
}
module_init
(
watchdog_init
);
module_exit
(
watchdog_exit
);
MODULE_LICENSE
(
"GPL"
);
drivers/char/watchdog/machzwd.c
View file @
a31ebc7d
...
...
@@ -117,7 +117,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
#define PFX "machzwd"
static
struct
watchdog_info
zf_info
=
{
.
options
=
WDIOF_KEEPALIVEPING
,
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"ZF-Logic watchdog"
};
...
...
@@ -314,10 +314,10 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
/* See if we got the magic character */
if
(
count
){
/*
* no need to check for close confirmation
* no way to disable watchdog ;)
*/
/*
* no need to check for close confirmation
* no way to disable watchdog ;)
*/
if
(
!
nowayout
)
{
size_t
ofs
;
...
...
@@ -328,7 +328,7 @@ static ssize_t zf_write(struct file *file, const char *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
;
...
...
@@ -338,6 +338,7 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
}
}
}
/*
* Well, anyhow someone wrote to us,
* we should return that favour
...
...
@@ -395,9 +396,9 @@ static int zf_open(struct inode *inode, struct file *file)
return
-
EBUSY
;
}
if
(
nowayout
)
{
if
(
nowayout
)
MOD_INC_USE_COUNT
;
}
zf_is_open
=
1
;
spin_unlock
(
&
zf_lock
);
...
...
drivers/char/watchdog/mixcomwd.c
View file @
a31ebc7d
...
...
@@ -62,6 +62,7 @@ static long mixcomwd_opened; /* long req'd for setbit --RR */
static
int
watchdog_port
;
static
int
mixcomwd_timer_alive
;
static
struct
timer_list
mixcomwd_timer
=
TIMER_INITIALIZER
(
NULL
,
0
,
0
);
static
int
expect_close
=
0
;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
...
...
@@ -109,8 +110,7 @@ static int mixcomwd_open(struct inode *inode, struct file *file)
static
int
mixcomwd_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
!
nowayout
)
{
if
(
expect_close
)
{
if
(
mixcomwd_timer_alive
)
{
printk
(
KERN_ERR
"mixcomwd: release called while internal timer alive"
);
return
-
EBUSY
;
...
...
@@ -121,7 +121,10 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
mixcomwd_timer
.
data
=
0
;
mixcomwd_timer_alive
=
1
;
add_timer
(
&
mixcomwd_timer
);
}
else
{
printk
(
KERN_CRIT
"mixcomwd: WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
clear_bit
(
0
,
&
mixcomwd_opened
);
return
0
;
}
...
...
@@ -135,6 +138,20 @@ static ssize_t mixcomwd_write(struct file *file, const char *data, size_t len, l
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
mixcomwd_ping
();
return
1
;
}
...
...
@@ -145,8 +162,10 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
status
;
static
struct
watchdog_info
ident
=
{
WDIOF_KEEPALIVEPING
,
1
,
"MixCOM watchdog"
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"MixCOM watchdog"
};
switch
(
cmd
)
...
...
drivers/char/watchdog/pcwd.c
View file @
a31ebc7d
...
...
@@ -40,6 +40,8 @@
* 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>
* Added timeout module option to override default
*/
#include <linux/module.h>
...
...
@@ -76,7 +78,7 @@
*/
static
int
pcwd_ioports
[]
=
{
0x270
,
0x350
,
0x370
,
0x000
};
#define WD_VER "1.1
0 (06/05/99
)"
#define WD_VER "1.1
2 (12/14/2001
)"
/*
* It should be noted that PCWD_REVISION_B was removed because A and B
...
...
@@ -88,7 +90,23 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
#define PCWD_REVISION_A 1
#define PCWD_REVISION_C 2
#define WD_TIMEOUT 3
/* 1 1/2 seconds for a timeout */
#define WD_TIMEOUT 4
/* 2 seconds for a timeout */
static
int
timeout_val
=
WD_TIMEOUT
;
static
int
timeout
=
2
;
static
int
expect_close
=
0
;
MODULE_PARM
(
timeout
,
"i"
);
MODULE_PARM_DESC
(
timeout
,
"Watchdog timeout in seconds (default=2)"
);
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
#else
static
int
nowayout
=
0
;
#endif
MODULE_PARM
(
nowayout
,
"i"
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
/*
* These are the defines for the PC Watchdog card, revision A.
...
...
@@ -121,7 +139,7 @@ static int __init pcwd_checkcard(void)
if
(
prev_card_dat
==
0xFF
)
return
0
;
while
(
count
<
WD_TIMEOUT
)
{
while
(
count
<
timeout_val
)
{
/* Read the raw card data from the port, and strip off the
first 4 bits */
...
...
@@ -256,7 +274,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
else
cdat
=
inb
(
current_readport
+
1
);
spin_unlock
(
&
io_lock
);
rv
=
0
;
rv
=
WDIOF_MAGICCLOSE
;
if
(
revision
==
PCWD_REVISION_A
)
{
...
...
@@ -385,8 +403,22 @@ static ssize_t pcwd_write(struct file *file, const char *buf, size_t len,
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
len
)
{
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
pcwd_send_heartbeat
();
return
1
;
}
...
...
@@ -395,28 +427,26 @@ static ssize_t pcwd_write(struct file *file, const char *buf, size_t len,
static
int
pcwd_open
(
struct
inode
*
ino
,
struct
file
*
filep
)
{
switch
(
minor
(
ino
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
if
(
!
atomic_dec_and_test
(
&
open_allowed
)
)
{
switch
(
minor
(
ino
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
if
(
!
atomic_dec_and_test
(
&
open_allowed
)
)
{
atomic_inc
(
&
open_allowed
);
return
-
EBUSY
;
}
MOD_INC_USE_COUNT
;
/* Enable the port */
if
(
revision
==
PCWD_REVISION_C
)
{
spin_lock
(
&
io_lock
);
outb_p
(
0x00
,
current_readport
+
3
);
spin_unlock
(
&
io_lock
);
}
return
(
0
);
case
TEMP_MINOR
:
return
(
0
);
default:
return
(
-
ENODEV
);
}
return
-
EBUSY
;
}
MOD_INC_USE_COUNT
;
/* Enable the port */
if
(
revision
==
PCWD_REVISION_C
)
{
spin_lock
(
&
io_lock
);
outb_p
(
0x00
,
current_readport
+
3
);
spin_unlock
(
&
io_lock
);
}
return
(
0
);
case
TEMP_MINOR
:
return
(
0
);
default:
return
(
-
ENODEV
);
}
}
static
ssize_t
pcwd_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
...
...
@@ -448,18 +478,17 @@ static ssize_t pcwd_read(struct file *file, char *buf, size_t count,
static
int
pcwd_close
(
struct
inode
*
ino
,
struct
file
*
filep
)
{
if
(
minor
(
ino
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
/* Disable the board */
if
(
revision
==
PCWD_REVISION_C
)
{
spin_lock
(
&
io_lock
);
outb_p
(
0xA5
,
current_readport
+
3
);
outb_p
(
0xA5
,
current_readport
+
3
);
spin_unlock
(
&
io_lock
);
if
(
minor
(
ino
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
expect_close
)
{
/* Disable the board */
if
(
revision
==
PCWD_REVISION_C
)
{
spin_lock
(
&
io_lock
);
outb_p
(
0xA5
,
current_readport
+
3
);
outb_p
(
0xA5
,
current_readport
+
3
);
spin_unlock
(
&
io_lock
);
}
atomic_inc
(
&
open_allowed
);
}
atomic_inc
(
&
open_allowed
);
#endif
}
return
0
;
}
...
...
@@ -560,9 +589,15 @@ static struct miscdevice temp_miscdev = {
&
pcwd_fops
};
static
void
__init
pcwd_validate_timeout
(
void
)
{
timeout_val
=
timeout
*
2
;
}
static
int
__init
pcwatchdog_init
(
void
)
{
int
i
,
found
=
0
;
pcwd_validate_timeout
();
spin_lock_init
(
&
io_lock
);
revision
=
PCWD_REVISION_A
;
...
...
drivers/char/watchdog/sbc60xxwdt.c
View file @
a31ebc7d
...
...
@@ -244,9 +244,9 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
static
struct
watchdog_info
ident
=
{
0
,
1
,
"SB60xx"
.
options
=
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"SB60xx"
};
switch
(
cmd
)
...
...
drivers/char/watchdog/sc1200wdt.c
0 → 100644
View file @
a31ebc7d
/*
* National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
* (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>,
* All Rights Reserved.
* Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively.
*
* 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.
*
* The author(s) of this software shall not be held liable for damages
* of any nature resulting due to the use of this software. This
* software is provided AS-IS with no warranties.
*
* Changelog:
* 20020220 Zwane Mwaikambo Code based on datasheet, no hardware.
* 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox.
* 20020222 Zwane Mwaikambo Added probing.
* 20020225 Zwane Mwaikambo Added ISAPNP support.
* 20020412 Rob Radez Broke out start/stop functions
* <rob@osinvestor.com> Return proper status instead of temperature warning
* Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
* Fix CONFIG_WATCHDOG_NOWAYOUT
* 20020530 Joel Becker Add Matt Domsch's nowayout module option
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <asm/semaphore.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/isapnp.h>
#include <linux/pci.h>
#define SC1200_MODULE_VER "build 20020303"
#define SC1200_MODULE_NAME "sc1200wdt"
#define PFX SC1200_MODULE_NAME ": "
#define MAX_TIMEOUT 255
/* 255 minutes */
#define PMIR (io)
/* Power Management Index Register */
#define PMDR (io+1)
/* Power Management Data Register */
/* Data Register indexes */
#define FER1 0x00
/* Function enable register 1 */
#define FER2 0x01
/* Function enable register 2 */
#define PMC1 0x02
/* Power Management Ctrl 1 */
#define PMC2 0x03
/* Power Management Ctrl 2 */
#define PMC3 0x04
/* Power Management Ctrl 3 */
#define WDTO 0x05
/* Watchdog timeout register */
#define WDCF 0x06
/* Watchdog config register */
#define WDST 0x07
/* Watchdog status register */
/* WDCF bitfields - which devices assert WDO */
#define KBC_IRQ 0x01
/* Keyboard Controller */
#define MSE_IRQ 0x02
/* Mouse */
#define UART1_IRQ 0x03
/* Serial0 */
#define UART2_IRQ 0x04
/* Serial1 */
/* 5 -7 are reserved */
static
char
banner
[]
__initdata
=
KERN_INFO
PFX
SC1200_MODULE_VER
;
static
int
timeout
=
1
;
static
int
io
=
-
1
;
static
int
io_len
=
2
;
/* for non plug and play */
struct
semaphore
open_sem
;
static
char
expect_close
;
spinlock_t
sc1200wdt_lock
;
/* io port access serialisation */
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
static
int
isapnp
=
1
;
static
struct
pci_dev
*
wdt_dev
;
MODULE_PARM
(
isapnp
,
"i"
);
MODULE_PARM_DESC
(
isapnp
,
"When set to 0 driver ISA PnP support will be disabled"
);
#endif
MODULE_PARM
(
io
,
"i"
);
MODULE_PARM_DESC
(
io
,
"io port"
);
MODULE_PARM
(
timeout
,
"i"
);
MODULE_PARM_DESC
(
timeout
,
"range is 0-255 minutes, default is 1"
);
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
#else
static
int
nowayout
=
0
;
#endif
MODULE_PARM
(
nowayout
,
"i"
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
/* Read from Data Register */
static
inline
void
sc1200wdt_read_data
(
unsigned
char
index
,
unsigned
char
*
data
)
{
spin_lock
(
&
sc1200wdt_lock
);
outb_p
(
index
,
PMIR
);
*
data
=
inb
(
PMDR
);
spin_unlock
(
&
sc1200wdt_lock
);
}
/* Write to Data Register */
static
inline
void
sc1200wdt_write_data
(
unsigned
char
index
,
unsigned
char
data
)
{
spin_lock
(
&
sc1200wdt_lock
);
outb_p
(
index
,
PMIR
);
outb
(
data
,
PMDR
);
spin_unlock
(
&
sc1200wdt_lock
);
}
static
void
sc1200wdt_start
(
void
)
{
unsigned
char
reg
;
sc1200wdt_read_data
(
WDCF
,
&
reg
);
/* assert WDO when any of the following interrupts are triggered too */
reg
|=
(
KBC_IRQ
|
MSE_IRQ
|
UART1_IRQ
|
UART2_IRQ
);
sc1200wdt_write_data
(
WDCF
,
reg
);
/* set the timeout and get the ball rolling */
sc1200wdt_write_data
(
WDTO
,
timeout
);
}
static
void
sc1200wdt_stop
(
void
)
{
sc1200wdt_write_data
(
WDTO
,
0
);
}
/* This returns the status of the WDO signal, inactive high. */
static
inline
int
sc1200wdt_status
(
void
)
{
unsigned
char
ret
;
sc1200wdt_read_data
(
WDST
,
&
ret
);
/* If the bit is inactive, the watchdog is enabled, so return
* KEEPALIVEPING which is a bit of a kludge because there's nothing
* else for enabled/disabled status
*/
return
(
ret
&
0x01
)
?
0
:
WDIOF_KEEPALIVEPING
;
/* bits 1 - 7 are undefined */
}
static
int
sc1200wdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* allow one at a time */
if
(
down_trylock
(
&
open_sem
))
return
-
EBUSY
;
if
(
timeout
>
MAX_TIMEOUT
)
timeout
=
MAX_TIMEOUT
;
sc1200wdt_start
();
printk
(
KERN_INFO
PFX
"Watchdog enabled, timeout = %d min(s)"
,
timeout
);
return
0
;
}
static
int
sc1200wdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
new_timeout
;
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
0
,
.
identity
=
"PC87307/PC97307"
};
switch
(
cmd
)
{
default:
return
-
ENOTTY
;
/* Keep Pavel Machek amused ;) */
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
ident
))
return
-
EFAULT
;
return
0
;
case
WDIOC_GETSTATUS
:
return
put_user
(
sc1200wdt_status
(),
(
int
*
)
arg
);
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
0
,
(
int
*
)
arg
);
case
WDIOC_KEEPALIVE
:
sc1200wdt_write_data
(
WDTO
,
timeout
);
return
0
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
new_timeout
,
(
int
*
)
arg
))
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
,
(
int
*
)
arg
);
case
WDIOC_SETOPTIONS
:
{
int
options
,
retval
=
-
EINVAL
;
if
(
get_user
(
options
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
options
&
WDIOS_DISABLECARD
)
{
sc1200wdt_stop
();
retval
=
0
;
}
if
(
options
&
WDIOS_ENABLECARD
)
{
sc1200wdt_start
();
retval
=
0
;
}
return
retval
;
}
}
}
static
int
sc1200wdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
expect_close
==
42
)
{
sc1200wdt_stop
();
printk
(
KERN_INFO
PFX
"Watchdog disabled
\n
"
);
}
else
{
sc1200wdt_write_data
(
WDTO
,
timeout
);
printk
(
KERN_CRIT
PFX
"Unexpected close!, timeout = %d min(s)
\n
"
,
timeout
);
}
up
(
&
open_sem
);
expect_close
=
0
;
return
0
;
}
static
ssize_t
sc1200wdt_write
(
struct
file
*
file
,
const
char
*
data
,
size_t
len
,
loff_t
*
ppos
)
{
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
42
;
}
}
sc1200wdt_write_data
(
WDTO
,
timeout
);
return
len
;
}
return
0
;
}
static
int
sc1200wdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
sc1200wdt_stop
();
return
NOTIFY_DONE
;
}
static
struct
notifier_block
sc1200wdt_notifier
=
{
notifier_call:
sc1200wdt_notify_sys
};
static
struct
file_operations
sc1200wdt_fops
=
{
owner:
THIS_MODULE
,
write:
sc1200wdt_write
,
ioctl:
sc1200wdt_ioctl
,
open:
sc1200wdt_open
,
release:
sc1200wdt_release
};
static
struct
miscdevice
sc1200wdt_miscdev
=
{
minor:
WATCHDOG_MINOR
,
name:
"watchdog"
,
fops:
&
sc1200wdt_fops
,
};
static
int
__init
sc1200wdt_probe
(
void
)
{
/* The probe works by reading the PMC3 register's default value of 0x0e
* there is one caveat, if the device disables the parallel port or any
* of the UARTs we won't be able to detect it.
* Nb. This could be done with accuracy by reading the SID registers, but
* we don't have access to those io regions.
*/
unsigned
char
reg
;
sc1200wdt_read_data
(
PMC3
,
&
reg
);
reg
&=
0x0f
;
/* we don't want the UART busy bits */
return
(
reg
==
0x0e
)
?
0
:
-
ENODEV
;
}
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
static
int
__init
sc1200wdt_isapnp_probe
(
void
)
{
int
ret
;
/* The WDT is logical device 8 on the main device */
wdt_dev
=
isapnp_find_dev
(
NULL
,
ISAPNP_VENDOR
(
'N'
,
'S'
,
'C'
),
ISAPNP_FUNCTION
(
0x08
),
NULL
);
if
(
!
wdt_dev
)
return
-
ENODEV
;
if
(
wdt_dev
->
prepare
(
wdt_dev
)
<
0
)
{
printk
(
KERN_ERR
PFX
"ISA PnP found device that could not be autoconfigured
\n
"
);
return
-
EAGAIN
;
}
if
(
!
(
pci_resource_flags
(
wdt_dev
,
0
)
&
IORESOURCE_IO
))
{
printk
(
KERN_ERR
PFX
"ISA PnP could not find io ports
\n
"
);
return
-
ENODEV
;
}
ret
=
wdt_dev
->
activate
(
wdt_dev
);
if
(
ret
&&
(
ret
!=
-
EBUSY
))
return
-
ENOMEM
;
/* io port resource overriding support? */
io
=
pci_resource_start
(
wdt_dev
,
0
);
io_len
=
pci_resource_len
(
wdt_dev
,
0
);
printk
(
KERN_DEBUG
PFX
"ISA PnP found device at io port %#x/%d
\n
"
,
io
,
io_len
);
return
0
;
}
#endif
/* CONFIG_ISAPNP */
static
int
__init
sc1200wdt_init
(
void
)
{
int
ret
;
printk
(
banner
);
spin_lock_init
(
&
sc1200wdt_lock
);
sema_init
(
&
open_sem
,
1
);
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
if
(
isapnp
)
{
ret
=
sc1200wdt_isapnp_probe
();
if
(
ret
)
goto
out_clean
;
}
#endif
if
(
io
==
-
1
)
{
printk
(
KERN_ERR
PFX
"io parameter must be specified
\n
"
);
ret
=
-
EINVAL
;
goto
out_clean
;
}
if
(
!
request_region
(
io
,
io_len
,
SC1200_MODULE_NAME
))
{
printk
(
KERN_ERR
PFX
"Unable to register IO port %#x
\n
"
,
io
);
ret
=
-
EBUSY
;
goto
out_pnp
;
}
ret
=
sc1200wdt_probe
();
if
(
ret
)
goto
out_io
;
ret
=
register_reboot_notifier
(
&
sc1200wdt_notifier
);
if
(
ret
)
{
printk
(
KERN_ERR
PFX
"Unable to register reboot notifier err = %d
\n
"
,
ret
);
goto
out_io
;
}
ret
=
misc_register
(
&
sc1200wdt_miscdev
);
if
(
ret
)
{
printk
(
KERN_ERR
PFX
"Unable to register miscdev on minor %d
\n
"
,
WATCHDOG_MINOR
);
goto
out_rbt
;
}
/* ret = 0 */
out_clean:
return
ret
;
out_rbt:
unregister_reboot_notifier
(
&
sc1200wdt_notifier
);
out_io:
release_region
(
io
,
io_len
);
out_pnp:
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
if
(
isapnp
&&
wdt_dev
)
wdt_dev
->
deactivate
(
wdt_dev
);
#endif
goto
out_clean
;
}
static
void
__exit
sc1200wdt_exit
(
void
)
{
misc_deregister
(
&
sc1200wdt_miscdev
);
unregister_reboot_notifier
(
&
sc1200wdt_notifier
);
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
if
(
isapnp
&&
wdt_dev
)
wdt_dev
->
deactivate
(
wdt_dev
);
#endif
release_region
(
io
,
io_len
);
}
#ifndef MODULE
static
int
__init
sc1200wdt_setup
(
char
*
str
)
{
int
ints
[
4
];
str
=
get_options
(
str
,
ARRAY_SIZE
(
ints
),
ints
);
if
(
ints
[
0
]
>
0
)
{
io
=
ints
[
1
];
if
(
ints
[
0
]
>
1
)
timeout
=
ints
[
2
];
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
if
(
ints
[
0
]
>
2
)
isapnp
=
ints
[
3
];
#endif
}
return
1
;
}
__setup
(
"sc1200wdt="
,
sc1200wdt_setup
);
#endif
/* MODULE */
module_init
(
sc1200wdt_init
);
module_exit
(
sc1200wdt_exit
);
MODULE_AUTHOR
(
"Zwane Mwaikambo <zwane@commfireservices.com>"
);
MODULE_DESCRIPTION
(
"Driver for National Semiconductor PC87307/PC97307 watchdog component"
);
MODULE_LICENSE
(
"GPL"
);
EXPORT_NO_SYMBOLS
;
drivers/char/watchdog/sc520_wdt.c
0 → 100644
View file @
a31ebc7d
/*
* AMD Elan SC520 processor Watchdog Timer driver for Linux 2.4.x
*
* Based on acquirewdt.c by Alan Cox,
* and sbc60xxwdt.c by Jakob Oestergaard <jakob@ostenfeld.dk>
*
* 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.
*
* The authors do NOT admit liability nor provide warranty for
* any of this software. This material is provided "AS-IS" in
* the hope that it may be useful for others.
*
* (c) Copyright 2001 Scott Jennings <linuxdrivers@oro.net>
* 9/27 - 2001 [Initial release]
*
* Additional fixes Alan Cox
* - Fixed formatting
* - Removed debug printks
* - Fixed SMP built kernel deadlock
* - Switched to private locks not lock_kernel
* - Used ioremap/writew/readw
* - Added NOWAYOUT support
*
* Theory of operation:
* A Watchdog Timer (WDT) is a hardware circuit that can
* reset the computer system in case of a software fault.
* You probably knew that already.
*
* Usually a userspace daemon will notify the kernel WDT driver
* via the /proc/watchdog special device file that userspace is
* still alive, at regular intervals. When such a notification
* occurs, the driver will usually tell the hardware watchdog
* that everything is in order, and that the watchdog should wait
* for yet another little while to reset the system.
* If userspace fails (RAM error, kernel bug, whatever), the
* notifications cease to occur, and the hardware watchdog will
* reset the system (causing a reboot) after the timeout occurs.
*
* This WDT driver is different from most other Linux WDT
* drivers in that the driver will ping the watchdog by itself,
* because this particular WDT has a very short timeout (1.6
* seconds) and it would be insane to count on any userspace
* daemon always getting scheduled within that time frame.
*
* This driver uses memory mapped IO, and spinlock.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
/*
* The SC520 can timeout anywhere from 492us to 32.21s.
* If we reset the watchdog every ~250ms we should be safe.
*/
#define WDT_INTERVAL (HZ/4+1)
/*
* We must not require too good response from the userspace daemon.
* Here we require the userspace daemon to send us a heartbeat
* char to /dev/watchdog every 30 seconds.
*/
#define WDT_HEARTBEAT (HZ * 30)
/*
* AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
*
* 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s
* 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s
*/
#define TIMEOUT_EXPONENT ( 1 << 3 )
/* 0x08 = 2.01s */
/* #define MMCR_BASE_DEFAULT 0xfffef000 */
#define MMCR_BASE_DEFAULT ((__u16 *)0xffffe)
#define OFFS_WDTMRCTL ((unsigned int)0xcb0)
#define WDT_ENB 0x8000
/* [15] Watchdog Timer Enable */
#define WDT_WRST_ENB 0x4000
/* [14] Watchdog Timer Reset Enable */
#define OUR_NAME "sc520_wdt"
#define WRT_DOG(data) *wdtmrctl=data
static
__u16
*
wdtmrctl
;
static
void
wdt_timer_ping
(
unsigned
long
);
static
struct
timer_list
timer
;
static
unsigned
long
next_heartbeat
;
static
unsigned
long
wdt_is_open
;
static
int
wdt_expect_close
;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
#else
static
int
nowayout
=
0
;
#endif
MODULE_PARM
(
nowayout
,
"i"
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
static
spinlock_t
wdt_spinlock
;
/*
* Whack the dog
*/
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
))
{
/* Ping the WDT */
spin_lock
(
&
wdt_spinlock
);
writew
(
0xAAAA
,
wdtmrctl
);
writew
(
0x5555
,
wdtmrctl
);
spin_unlock
(
&
wdt_spinlock
);
/* Re-set the timer interval */
timer
.
expires
=
jiffies
+
WDT_INTERVAL
;
add_timer
(
&
timer
);
}
else
{
printk
(
OUR_NAME
": Heartbeat lost! Will not ping the watchdog
\n
"
);
}
}
/*
* Utility routines
*/
static
void
wdt_config
(
int
writeval
)
{
__u16
dummy
;
unsigned
long
flags
;
/* buy some time (ping) */
spin_lock_irqsave
(
&
wdt_spinlock
,
flags
);
dummy
=
readw
(
wdtmrctl
);
/* ensure write synchronization */
writew
(
0xAAAA
,
wdtmrctl
);
writew
(
0x5555
,
wdtmrctl
);
/* make WDT configuration register writable one time */
writew
(
0x3333
,
wdtmrctl
);
writew
(
0xCCCC
,
wdtmrctl
);
/* write WDT configuration register */
writew
(
writeval
,
wdtmrctl
);
spin_unlock_irqrestore
(
&
wdt_spinlock
,
flags
);
}
static
void
wdt_startup
(
void
)
{
next_heartbeat
=
jiffies
+
WDT_HEARTBEAT
;
/* Start the timer */
timer
.
expires
=
jiffies
+
WDT_INTERVAL
;
add_timer
(
&
timer
);
wdt_config
(
WDT_ENB
|
WDT_WRST_ENB
|
TIMEOUT_EXPONENT
);
printk
(
OUR_NAME
": Watchdog timer is now enabled.
\n
"
);
}
static
void
wdt_turnoff
(
void
)
{
if
(
!
nowayout
)
{
/* Stop the timer */
del_timer
(
&
timer
);
wdt_config
(
0
);
printk
(
OUR_NAME
": Watchdog timer is now disabled...
\n
"
);
}
}
/*
* /dev/watchdog handling
*/
static
ssize_t
fop_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
/* We can't seek */
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
/* See if we got the magic character */
if
(
count
)
{
size_t
ofs
;
/* note: just in case someone wrote the magic character
* five months ago... */
wdt_expect_close
=
0
;
/* now scan */
for
(
ofs
=
0
;
ofs
!=
count
;
ofs
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
ofs
))
return
-
EFAULT
;
if
(
c
==
'V'
)
wdt_expect_close
=
1
;
}
/* Well, anyhow someone wrote to us, we should return that favour */
next_heartbeat
=
jiffies
+
WDT_HEARTBEAT
;
return
1
;
}
return
0
;
}
static
int
fop_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
switch
(
minor
(
inode
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
/* Just in case we're already talking to someone... */
if
(
test_and_set_bit
(
0
,
&
wdt_is_open
))
return
-
EBUSY
;
/* Good, fire up the show */
wdt_startup
();
if
(
nowayout
)
MOD_INC_USE_COUNT
;
return
0
;
default:
return
-
ENODEV
;
}
}
static
int
fop_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
wdt_expect_close
)
wdt_turnoff
();
else
{
del_timer
(
&
timer
);
printk
(
OUR_NAME
": device file closed unexpectedly. Will not stop the WDT!
\n
"
);
}
}
clear_bit
(
0
,
&
wdt_is_open
);
return
0
;
}
static
long
long
fop_llseek
(
struct
file
*
file
,
long
long
offset
,
int
origin
)
{
return
-
ESPIPE
;
}
static
int
fop_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"SC520"
};
switch
(
cmd
)
{
default:
return
-
ENOIOCTLCMD
;
case
WDIOC_GETSUPPORT
:
return
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
))
?-
EFAULT
:
0
;
case
WDIOC_KEEPALIVE
:
next_heartbeat
=
jiffies
+
WDT_HEARTBEAT
;
return
0
;
}
}
static
struct
file_operations
wdt_fops
=
{
owner:
THIS_MODULE
,
llseek:
fop_llseek
,
write:
fop_write
,
open:
fop_open
,
release:
fop_close
,
ioctl:
fop_ioctl
};
static
struct
miscdevice
wdt_miscdev
=
{
WATCHDOG_MINOR
,
"watchdog"
,
&
wdt_fops
};
/*
* Notifier for system down
*/
static
int
wdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
wdt_turnoff
();
return
NOTIFY_DONE
;
}
/*
* The WDT needs to learn about soft shutdowns in order to
* turn the timebomb registers off.
*/
static
struct
notifier_block
wdt_notifier
=
{
wdt_notify_sys
,
0
,
0
};
static
void
__exit
sc520_wdt_unload
(
void
)
{
wdt_turnoff
();
/* Deregister */
misc_deregister
(
&
wdt_miscdev
);
iounmap
(
wdtmrctl
);
unregister_reboot_notifier
(
&
wdt_notifier
);
}
static
int
__init
sc520_wdt_init
(
void
)
{
int
rc
=
-
EBUSY
;
unsigned
long
cbar
;
spin_lock_init
(
&
wdt_spinlock
);
init_timer
(
&
timer
);
timer
.
function
=
wdt_timer_ping
;
timer
.
data
=
0
;
rc
=
misc_register
(
&
wdt_miscdev
);
if
(
rc
)
goto
err_out_region2
;
rc
=
register_reboot_notifier
(
&
wdt_notifier
);
if
(
rc
)
goto
err_out_miscdev
;
/* get the Base Address Register */
cbar
=
inl_p
(
0xfffc
);
printk
(
OUR_NAME
": CBAR: 0x%08lx
\n
"
,
cbar
);
/* check if MMCR aliasing bit is set */
if
(
cbar
&
0x80000000
)
{
printk
(
OUR_NAME
": MMCR Aliasing enabled.
\n
"
);
wdtmrctl
=
(
__u16
*
)(
cbar
&
0x3fffffff
);
}
else
{
printk
(
OUR_NAME
"!!! WARNING !!!
\n
"
"
\t
MMCR Aliasing found NOT enabled!
\n
"
"
\t
Using default value of: %p
\n
"
"
\t
This has not been tested!
\n
"
"
\t
Please email Scott Jennings <smj@oro.net>
\n
"
"
\t
and Bill Jennings <bj@oro.net> if it works!
\n
"
,
MMCR_BASE_DEFAULT
);
wdtmrctl
=
MMCR_BASE_DEFAULT
;
}
wdtmrctl
=
(
__u16
*
)((
char
*
)
wdtmrctl
+
OFFS_WDTMRCTL
);
wdtmrctl
=
ioremap
((
unsigned
long
)
wdtmrctl
,
2
);
printk
(
KERN_INFO
OUR_NAME
": WDT driver for SC520 initialised.
\n
"
);
return
0
;
err_out_miscdev:
misc_deregister
(
&
wdt_miscdev
);
err_out_region2:
return
rc
;
}
module_init
(
sc520_wdt_init
);
module_exit
(
sc520_wdt_unload
);
MODULE_AUTHOR
(
"Scott and Bill Jennings"
);
MODULE_DESCRIPTION
(
"Driver for watchdog timer in AMD
\"
Elan
\"
SC520 uProcessor"
);
MODULE_LICENSE
(
"GPL"
);
EXPORT_NO_SYMBOLS
;
drivers/char/watchdog/shwdt.c
View file @
a31ebc7d
...
...
@@ -334,21 +334,21 @@ static struct file_operations sh_wdt_fops = {
};
static
struct
watchdog_info
sh_wdt_info
=
{
WDIOF_KEEPALIVEPING
,
1
,
"SH WDT"
,
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"SH WDT"
,
};
static
struct
notifier_block
sh_wdt_notifier
=
{
sh_wdt_notify_sys
,
NULL
,
0
.
notifier_call
=
sh_wdt_notify_sys
,
.
next
=
NULL
,
.
priority
=
0
};
static
struct
miscdevice
sh_wdt_miscdev
=
{
WATCHDOG_MINOR
,
"watchdog"
,
&
sh_wdt_fops
,
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
&
sh_wdt_fops
,
};
/**
...
...
drivers/char/watchdog/softdog.c
View file @
a31ebc7d
...
...
@@ -47,6 +47,7 @@
#define TIMER_MARGIN 60
/* (secs) Default is 1 minute */
static
int
expect_close
=
0
;
static
int
soft_margin
=
TIMER_MARGIN
;
/* in seconds */
MODULE_PARM
(
soft_margin
,
"i"
);
...
...
@@ -79,7 +80,7 @@ static int timer_alive;
static
void
watchdog_fire
(
unsigned
long
data
)
{
#ifdef ONLY_TESTING
printk
(
KERN_CRIT
"SOFTDOG: Would Reboot.
\n
"
);
printk
(
KERN_CRIT
"SOFTDOG: Would Reboot.
\n
"
);
#else
printk
(
KERN_CRIT
"SOFTDOG: Initiating system reboot.
\n
"
);
machine_restart
(
NULL
);
...
...
@@ -114,6 +115,8 @@ static int softdog_release(struct inode *inode, struct file *file)
*/
if
(
!
nowayout
)
{
del_timer
(
&
watchdog_ticktock
);
}
else
{
printk
(
KERN_CRIT
"SOFTDOG: WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
timer_alive
=
0
;
return
0
;
...
...
@@ -129,6 +132,21 @@ static ssize_t softdog_write(struct file *file, const char *data, size_t len, lo
* Refresh the timer.
*/
if
(
len
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
mod_timer
(
&
watchdog_ticktock
,
jiffies
+
(
soft_margin
*
HZ
));
return
1
;
}
...
...
@@ -139,6 +157,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
unsigned
int
cmd
,
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
identity
=
"Software Watchdog"
,
};
switch
(
cmd
)
{
...
...
drivers/char/watchdog/w83877f_wdt.c
View file @
a31ebc7d
...
...
@@ -251,9 +251,9 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
static
struct
watchdog_info
ident
=
{
0
,
1
,
"W83877F"
.
options
=
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"W83877F"
};
switch
(
cmd
)
...
...
drivers/char/watchdog/wafer5823wdt.c
0 → 100644
View file @
a31ebc7d
/*
* ICP Wafer 5823 Single Board Computer WDT driver for Linux 2.4.x
* 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
*
* Based on advantechwdt.c which is based on wdt.c.
* Original copyright messages:
*
* (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
* http://www.redhat.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/spinlock.h>
static
unsigned
long
wafwdt_is_open
;
static
spinlock_t
wafwdt_lock
;
static
int
expect_close
=
0
;
/*
* 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.
*/
#define WDT_START 0x443
#define WDT_STOP 0x843
#define WD_TIMO 60
/* 1 minute */
static
int
wd_margin
=
WD_TIMO
;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
#else
static
int
nowayout
=
0
;
#endif
MODULE_PARM
(
nowayout
,
"i"
);
MODULE_PARM_DESC
(
nowayout
,
"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"
);
static
void
wafwdt_ping
(
void
)
{
/* pat watchdog */
spin_lock
(
&
wafwdt_lock
);
inb_p
(
WDT_STOP
);
inb_p
(
WDT_START
);
spin_unlock
(
&
wafwdt_lock
);
}
static
void
wafwdt_start
(
void
)
{
/* start up watchdog */
outb_p
(
wd_margin
,
WDT_START
);
inb_p
(
WDT_START
);
}
static
void
wafwdt_stop
(
void
)
{
/* stop watchdog */
inb_p
(
WDT_STOP
);
}
static
ssize_t
wafwdt_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
/* Can't seek (pwrite) on this device */
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
wafwdt_ping
();
return
1
;
}
return
0
;
}
static
int
wafwdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
new_margin
;
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"Wafer 5823 WDT"
};
int
one
=
1
;
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
)))
return
-
EFAULT
;
break
;
case
WDIOC_GETSTATUS
:
if
(
copy_to_user
((
int
*
)
arg
,
&
one
,
sizeof
(
int
)))
return
-
EFAULT
;
break
;
case
WDIOC_KEEPALIVE
:
wafwdt_ping
();
break
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
new_margin
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
((
new_margin
<
1
)
||
(
new_margin
>
255
))
return
-
EINVAL
;
wd_margin
=
new_margin
;
wafwdt_stop
();
wafwdt_start
();
/* Fall */
case
WDIOC_GETTIMEOUT
:
return
put_user
(
wd_margin
,
(
int
*
)
arg
);
default:
return
-
ENOTTY
;
}
return
0
;
}
static
int
wafwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
test_and_set_bit
(
0
,
&
wafwdt_is_open
))
return
-
EBUSY
;
wafwdt_start
();
return
0
;
}
static
int
wafwdt_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
clear_bit
(
0
,
&
wafwdt_is_open
);
if
(
expect_close
)
{
wafwdt_stop
();
}
else
{
printk
(
KERN_CRIT
"WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
return
0
;
}
/*
* Notifier for system down
*/
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 */
wafwdt_stop
();
}
return
NOTIFY_DONE
;
}
/*
* Kernel Interfaces
*/
static
struct
file_operations
wafwdt_fops
=
{
owner:
THIS_MODULE
,
write:
wafwdt_write
,
ioctl:
wafwdt_ioctl
,
open:
wafwdt_open
,
release:
wafwdt_close
,
};
static
struct
miscdevice
wafwdt_miscdev
=
{
WATCHDOG_MINOR
,
"watchdog"
,
&
wafwdt_fops
};
/*
* The WDT needs to learn about soft shutdowns in order to
* turn the timebomb registers off.
*/
static
struct
notifier_block
wafwdt_notifier
=
{
wafwdt_notify_sys
,
NULL
,
0
};
static
int
__init
wafwdt_init
(
void
)
{
printk
(
KERN_INFO
"WDT driver for Wafer 5823 single board computer initialising.
\n
"
);
spin_lock_init
(
&
wafwdt_lock
);
if
(
!
request_region
(
WDT_STOP
,
1
,
"Wafer 5823 WDT"
))
goto
error
;
if
(
!
request_region
(
WDT_START
,
1
,
"Wafer 5823 WDT"
))
goto
error2
;
if
(
misc_register
(
&
wafwdt_miscdev
)
<
0
)
goto
error3
;
register_reboot_notifier
(
&
wafwdt_notifier
);
return
0
;
error3:
release_region
(
WDT_START
,
1
);
error2:
release_region
(
WDT_STOP
,
1
);
error:
return
-
ENODEV
;
}
static
void
__exit
wafwdt_exit
(
void
)
{
misc_deregister
(
&
wafwdt_miscdev
);
unregister_reboot_notifier
(
&
wafwdt_notifier
);
release_region
(
WDT_STOP
,
1
);
release_region
(
WDT_START
,
1
);
}
module_init
(
wafwdt_init
);
module_exit
(
wafwdt_exit
);
MODULE_AUTHOR
(
"Justin Cormack"
);
MODULE_LICENSE
(
"GPL"
);
EXPORT_NO_SYMBOLS
;
/* end of wafer5823wdt.c */
drivers/char/watchdog/wdt.c
View file @
a31ebc7d
...
...
@@ -52,6 +52,7 @@
#include <asm/system.h>
static
unsigned
long
wdt_is_open
;
static
int
expect_close
;
/*
* You must set these - there is no sane way to probe for this board.
...
...
@@ -258,8 +259,21 @@ static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
count
)
{
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
wdt_ping
();
return
1
;
}
...
...
@@ -317,10 +331,11 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
static
struct
watchdog_info
ident
=
{
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
WDIOF_POWEROVER
|
WDIOF_EXTERN1
|
WDIOF_EXTERN2
|
WDIOF_FANFAULT
,
1
,
"WDT500/501"
.
options
=
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
WDIOF_POWEROVER
|
WDIOF_EXTERN1
|
WDIOF_EXTERN2
|
WDIOF_FANFAULT
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"WDT500/501"
};
ident
.
options
&=
WDT_OPTION_MASK
;
/* Mask down to the card we have */
...
...
@@ -399,9 +414,11 @@ static int wdt_release(struct inode *inode, struct file *file)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
!
nowayout
)
{
if
(
expect_close
)
{
inb_p
(
WDT_DC
);
/* Disable counters */
wdt_ctr_load
(
2
,
0
);
/* 0 length reset pulses now */
}
else
{
printk
(
KERN_CRIT
"wdt: WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
clear_bit
(
0
,
&
wdt_is_open
);
}
...
...
drivers/char/watchdog/wdt977.c
View file @
a31ebc7d
...
...
@@ -41,6 +41,7 @@ static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */
static
int
timeoutM
=
DEFAULT_TIMEOUT
;
/* timeout in minutes */
static
unsigned
long
timer_alive
;
static
int
testmode
;
static
int
expect_close
=
0
;
MODULE_PARM
(
timeout
,
"i"
);
MODULE_PARM_DESC
(
timeout
,
"Watchdog timeout in seconds (60..15300), default=60"
);
...
...
@@ -196,6 +197,8 @@ static int wdt977_release(struct inode *inode, struct file *file)
clear_bit
(
0
,
&
timer_alive
);
printk
(
KERN_INFO
"Wdt977 Watchdog: shutdown
\n
"
);
}
else
{
printk
(
KERN_CRIT
"WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
return
0
;
}
...
...
@@ -220,6 +223,21 @@ static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, lo
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
/* In case it was set long ago */
expect_close
=
0
;
for
(
i
=
0
;
i
!=
len
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
kick_wdog
();
return
1
;
}
...
...
drivers/char/watchdog/wdt_pci.c
View file @
a31ebc7d
...
...
@@ -73,6 +73,7 @@
#endif
static
unsigned
long
wdt_is_open
;
static
int
expect_close
=
0
;
/*
* You must set these - there is no sane way to probe for this board.
...
...
@@ -276,6 +277,16 @@ static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, lo
if
(
count
)
{
if
(
!
nowayout
)
{
size_t
i
;
for
(
i
=
0
;
i
!=
count
;
i
++
)
{
char
c
;
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
wdtpci_ping
();
return
1
;
}
...
...
@@ -332,9 +343,10 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd
unsigned
long
arg
)
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
WDIOF_POWEROVER
|
WDIOF_EXTERN1
|
WDIOF_EXTERN2
|
WDIOF_FANFAULT
,
.
options
=
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
WDIOF_POWEROVER
|
WDIOF_EXTERN1
|
WDIOF_EXTERN2
|
WDIOF_FANFAULT
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"WDT500/501PCI"
,
};
...
...
include/linux/watchdog.h
View file @
a31ebc7d
...
...
@@ -39,6 +39,7 @@ struct watchdog_info {
#define WDIOF_CARDRESET 0x0020
/* Card previously reset the CPU */
#define WDIOF_POWEROVER 0x0040
/* Power over voltage */
#define WDIOF_SETTIMEOUT 0x0080
/* Set timeout (in seconds) */
#define WDIOF_MAGICCLOSE 0x0100
/* Supports magic close char */
#define WDIOF_KEEPALIVEPING 0x8000
/* Keep alive ping reply */
#define WDIOS_DISABLECARD 0x0001
/* Turn off the watchdog timer */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment