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
nexedi
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
...
@@ -283,4 +283,24 @@ config MACHZ_WDT
The module is called machzwd.o. If you want to compile it as a
The module is called machzwd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
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
endmenu
drivers/char/watchdog/Makefile
View file @
a31ebc7d
...
@@ -23,3 +23,8 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o
...
@@ -23,3 +23,8 @@ obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SH_WDT)
+=
shwdt.o
obj-$(CONFIG_SH_WDT)
+=
shwdt.o
obj-$(CONFIG_EUROTECH_WDT)
+=
eurotechwdt.o
obj-$(CONFIG_EUROTECH_WDT)
+=
eurotechwdt.o
obj-$(CONFIG_SOFT_WATCHDOG)
+=
softdog.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 @@
...
@@ -45,6 +45,7 @@
static
int
acq_is_open
;
static
int
acq_is_open
;
static
spinlock_t
acq_lock
;
static
spinlock_t
acq_lock
;
static
int
expect_close
=
0
;
/*
/*
* You must set these - there is no sane way to probe for this board.
* You must set these - there is no sane way to probe for this board.
...
@@ -79,8 +80,20 @@ static ssize_t acq_write(struct file *file, const char *buf, size_t count, loff_
...
@@ -79,8 +80,20 @@ static ssize_t acq_write(struct file *file, const char *buf, size_t count, loff_
if
(
ppos
!=
&
file
->
f_pos
)
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
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
();
acq_ping
();
return
1
;
return
1
;
}
}
...
@@ -97,9 +110,11 @@ static ssize_t acq_read(struct file *file, char *buf, size_t count, loff_t *ppos
...
@@ -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
,
static
int
acq_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
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
)
switch
(
cmd
)
...
@@ -126,39 +141,35 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int 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
)
static
int
acq_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
switch
(
minor
(
inode
->
i_rdev
))
if
((
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
))
{
{
spin_lock
(
&
acq_lock
);
case
WATCHDOG_MINOR
:
if
(
acq_is_open
)
{
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
);
spin_unlock
(
&
acq_lock
);
spin_unlock
(
&
acq_lock
);
return
0
;
return
-
EBUSY
;
default:
}
return
-
ENODEV
;
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
)
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
);
spin_lock
(
&
acq_lock
);
if
(
!
nowayout
)
{
if
(
expect_close
)
inb_p
(
WDT_STOP
);
inb_p
(
WDT_STOP
);
}
else
printk
(
KERN_CRIT
"WDT closed unexpectedly. WDT will not stop!
\n
"
);
acq_is_open
=
0
;
acq_is_open
=
0
;
spin_unlock
(
&
acq_lock
);
spin_unlock
(
&
acq_lock
);
}
}
...
@@ -173,10 +184,9 @@ static int acq_notify_sys(struct notifier_block *this, unsigned long code,
...
@@ -173,10 +184,9 @@ static int acq_notify_sys(struct notifier_block *this, unsigned long code,
void
*
unused
)
void
*
unused
)
{
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Turn the card off */
/* Turn the card off */
inb_p
(
WDT_STOP
);
inb_p
(
WDT_STOP
);
}
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
}
}
...
@@ -196,9 +206,9 @@ static struct file_operations acq_fops = {
...
@@ -196,9 +206,9 @@ static struct file_operations acq_fops = {
static
struct
miscdevice
acq_miscdev
=
static
struct
miscdevice
acq_miscdev
=
{
{
WATCHDOG_MINOR
,
.
minor
=
WATCHDOG_MINOR
,
"watchdog"
,
.
name
=
"watchdog"
,
&
acq_fops
.
fops
=
&
acq_fops
};
};
...
@@ -207,11 +217,11 @@ static struct miscdevice acq_miscdev=
...
@@ -207,11 +217,11 @@ static struct miscdevice acq_miscdev=
* turn the timebomb registers off.
* turn the timebomb registers off.
*/
*/
static
struct
notifier_block
acq_notifier
=
static
struct
notifier_block
acq_notifier
=
{
{
acq_notify_sys
,
.
notifier_call
=
acq_notify_sys
,
NULL
,
.
next
=
NULL
,
0
.
priority
=
0
};
};
static
int
__init
acq_init
(
void
)
static
int
__init
acq_init
(
void
)
...
@@ -221,17 +231,15 @@ static int __init acq_init(void)
...
@@ -221,17 +231,15 @@ static int __init acq_init(void)
spin_lock_init
(
&
acq_lock
);
spin_lock_init
(
&
acq_lock
);
if
(
misc_register
(
&
acq_miscdev
))
if
(
misc_register
(
&
acq_miscdev
))
return
-
ENODEV
;
return
-
ENODEV
;
if
(
!
request_region
(
WDT_STOP
,
1
,
"Acquire WDT"
))
if
(
!
request_region
(
WDT_STOP
,
1
,
"Acquire WDT"
))
{
{
misc_deregister
(
&
acq_miscdev
);
misc_deregister
(
&
acq_miscdev
);
return
-
EIO
;
return
-
EIO
;
}
}
if
(
!
request_region
(
WDT_START
,
1
,
"Acquire WDT"
))
if
(
!
request_region
(
WDT_START
,
1
,
"Acquire WDT"
))
{
{
release_region
(
WDT_STOP
,
1
);
release_region
(
WDT_STOP
,
1
);
misc_deregister
(
&
acq_miscdev
);
misc_deregister
(
&
acq_miscdev
);
return
-
EIO
;
return
-
EIO
;
}
}
register_reboot_notifier
(
&
acq_notifier
);
register_reboot_notifier
(
&
acq_notifier
);
return
0
;
return
0
;
...
...
drivers/char/watchdog/advantechwdt.c
View file @
a31ebc7d
...
@@ -47,6 +47,7 @@
...
@@ -47,6 +47,7 @@
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
static
int
advwdt_is_open
;
static
int
advwdt_is_open
;
static
char
adv_expect_close
;
static
spinlock_t
advwdt_lock
;
static
spinlock_t
advwdt_lock
;
/*
/*
...
@@ -99,10 +100,22 @@ advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
...
@@ -99,10 +100,22 @@ advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
return
-
ESPIPE
;
return
-
ESPIPE
;
if
(
count
)
{
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
();
advwdt_ping
();
return
1
;
}
}
return
0
;
return
count
;
}
}
static
ssize_t
static
ssize_t
...
@@ -116,9 +129,11 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
...
@@ -116,9 +129,11 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned
long
arg
)
unsigned
long
arg
)
{
{
static
struct
watchdog_info
ident
=
{
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
)
{
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
)))
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,
...
@@ -143,26 +158,23 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static
int
static
int
advwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
advwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
switch
(
minor
(
inode
->
i_rdev
))
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
case
WATCHDOG_MINOR
:
spin_lock
(
&
advwdt_lock
);
spin_lock
(
&
advwdt_lock
);
if
(
advwdt_is_open
)
{
if
(
advwdt_is_open
)
{
spin_unlock
(
&
advwdt_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
{
MOD_INC_USE_COUNT
;
}
/*
* Activate
*/
advwdt_is_open
=
1
;
advwdt_ping
();
spin_unlock
(
&
advwdt_lock
);
spin_unlock
(
&
advwdt_lock
);
return
0
;
return
-
EBUSY
;
default:
}
return
-
ENODEV
;
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)
...
@@ -171,9 +183,9 @@ advwdt_close(struct inode *inode, struct file *file)
{
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
spin_lock
(
&
advwdt_lock
);
spin_lock
(
&
advwdt_lock
);
if
(
!
nowayout
)
{
if
(
!
nowayout
)
inb_p
(
WDT_STOP
);
inb_p
(
WDT_STOP
);
}
advwdt_is_open
=
0
;
advwdt_is_open
=
0
;
spin_unlock
(
&
advwdt_lock
);
spin_unlock
(
&
advwdt_lock
);
}
}
...
@@ -188,10 +200,10 @@ static int
...
@@ -188,10 +200,10 @@ static int
advwdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
advwdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
void
*
unused
)
{
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
/* Turn the WDT off */
/* Turn the WDT off */
inb_p
(
WDT_STOP
);
inb_p
(
WDT_STOP
);
}
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
}
}
...
@@ -209,9 +221,9 @@ static struct file_operations advwdt_fops = {
...
@@ -209,9 +221,9 @@ static struct file_operations advwdt_fops = {
};
};
static
struct
miscdevice
advwdt_miscdev
=
{
static
struct
miscdevice
advwdt_miscdev
=
{
WATCHDOG_MINOR
,
.
minor
=
WATCHDOG_MINOR
,
"watchdog"
,
.
name
=
"watchdog"
,
&
advwdt_fops
.
fops
=
&
advwdt_fops
};
};
/*
/*
...
@@ -220,9 +232,9 @@ static struct miscdevice advwdt_miscdev = {
...
@@ -220,9 +232,9 @@ static struct miscdevice advwdt_miscdev = {
*/
*/
static
struct
notifier_block
advwdt_notifier
=
{
static
struct
notifier_block
advwdt_notifier
=
{
advwdt_notify_sys
,
.
notifier_call
=
advwdt_notify_sys
,
NULL
,
.
next
=
NULL
,
0
.
priority
=
0
};
};
static
void
__init
static
void
__init
...
@@ -276,5 +288,3 @@ module_exit(advwdt_exit);
...
@@ -276,5 +288,3 @@ module_exit(advwdt_exit);
MODULE_LICENSE
(
"GPL"
);
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 @@
...
@@ -7,23 +7,23 @@
* Based on wdt.c.
* Based on wdt.c.
* Original copyright messages:
* Original copyright messages:
*
*
*
(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
*
(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
*
http://www.redhat.com
*
http://www.redhat.com
*
*
*
This program is free software; you can redistribute it and/or
*
This program is free software; you can redistribute it and/or
*
modify it under the terms of the GNU General Public License
*
modify it under the terms of the GNU General Public License
*
as published by the Free Software Foundation; either version
*
as published by the Free Software Foundation; either version
*
2 of the License, or (at your option) any later version.
*
2 of the License, or (at your option) any later version.
*
*
*
Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
*
Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
*
warranty for any of this software. This material is provided
*
warranty for any of this software. This material is provided
*
"AS-IS" and at no charge.
*
"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>
*
14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
*
Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*
Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*
Added timeout module option to override default
*
Added timeout module option to override default
*/
*/
#include <linux/config.h>
#include <linux/config.h>
...
@@ -49,17 +49,18 @@
...
@@ -49,17 +49,18 @@
static
int
eurwdt_is_open
;
static
int
eurwdt_is_open
;
static
spinlock_t
eurwdt_lock
;
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 must set these - there is no sane way to probe for this board.
*
You can use wdt=x,y to set these now.
* You can use wdt=x,y to set these now.
*/
*/
static
int
io
=
0x3f0
;
static
int
io
=
0x3f0
;
static
int
irq
=
10
;
static
int
irq
=
10
;
static
char
*
ev
=
"int"
;
static
char
*
ev
=
"int"
;
#define WDT_TIMEOUT 60
/* 1 minute */
#define WDT_TIMEOUT 60
/* 1 minute */
static
int
timeout
=
WDT_TIMEOUT
;
static
int
timeout
=
WDT_TIMEOUT
;
MODULE_PARM
(
timeout
,
"i"
);
MODULE_PARM
(
timeout
,
"i"
);
...
@@ -80,10 +81,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
...
@@ -80,10 +81,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
#define WDT_CTRL_REG 0x30
#define WDT_CTRL_REG 0x30
#define WDT_OUTPIN_CFG 0xe2
#define WDT_OUTPIN_CFG 0xe2
#define WDT_EVENT_INT
0x00
#define WDT_EVENT_INT
0x00
#define WDT_EVENT_REBOOT
0x08
#define WDT_EVENT_REBOOT
0x08
#define WDT_UNIT_SEL 0xf1
#define WDT_UNIT_SEL 0xf1
#define WDT_UNIT_SECS
0x80
#define WDT_UNIT_SECS
0x80
#define WDT_TIMEOUT_VAL 0xf2
#define WDT_TIMEOUT_VAL 0xf2
#define WDT_TIMER_CFG 0xf3
#define WDT_TIMER_CFG 0xf3
...
@@ -91,27 +92,27 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
...
@@ -91,27 +92,27 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
#ifndef MODULE
#ifndef MODULE
/**
/**
*
eurwdt_setup:
* eurwdt_setup:
*
@str: command line string
* @str: command line string
*
*
*
Setup options. The board isn't really probe-able so we have to
* 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
* get the user to tell us the configuration. Sane people build it
*
modular but the others come here.
* modular but the others come here.
*/
*/
static
int
__init
eurwdt_setup
(
char
*
str
)
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
)
{
if
(
ints
[
0
]
>
0
)
{
io
=
ints
[
1
];
io
=
ints
[
1
];
if
(
ints
[
0
]
>
1
)
if
(
ints
[
0
]
>
1
)
irq
=
ints
[
2
];
irq
=
ints
[
2
];
}
}
return
1
;
return
1
;
}
}
__setup
(
"wdt="
,
eurwdt_setup
);
__setup
(
"wdt="
,
eurwdt_setup
);
...
@@ -127,7 +128,7 @@ MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `reboot')");
...
@@ -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
)
static
void
__init
eurwdt_validate_timeout
(
void
)
...
@@ -135,265 +136,276 @@ static void __init eurwdt_validate_timeout(void)
...
@@ -135,265 +136,276 @@ static void __init eurwdt_validate_timeout(void)
if
(
timeout
<
0
||
timeout
>
255
)
{
if
(
timeout
<
0
||
timeout
>
255
)
{
timeout
=
WDT_TIMEOUT
;
timeout
=
WDT_TIMEOUT
;
printk
(
KERN_INFO
"eurwdt: timeout must be 0 < x < 255, using %d
\n
"
,
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
)
static
inline
void
eurwdt_write_reg
(
u8
index
,
u8
data
)
{
{
outb
(
index
,
io
);
outb
(
index
,
io
);
outb
(
data
,
io
+
1
);
outb
(
data
,
io
+
1
);
}
}
static
inline
void
eurwdt_lock_chip
(
void
)
static
inline
void
eurwdt_lock_chip
(
void
)
{
{
outb
(
0xaa
,
io
);
outb
(
0xaa
,
io
);
}
}
static
inline
void
eurwdt_unlock_chip
(
void
)
static
inline
void
eurwdt_unlock_chip
(
void
)
{
{
outb
(
0x55
,
io
);
outb
(
0x55
,
io
);
eurwdt_write_reg
(
0x07
,
0x08
);
/* set the logical device */
eurwdt_write_reg
(
0x07
,
0x08
);
/* set the logical device */
}
}
static
inline
void
eurwdt_set_timeout
(
int
timeout
)
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
)
static
inline
void
eurwdt_disable_timer
(
void
)
{
{
eurwdt_set_timeout
(
0
);
eurwdt_set_timeout
(
0
);
}
}
static
void
eurwdt_activate_timer
(
void
)
static
void
eurwdt_activate_timer
(
void
)
{
{
eurwdt_disable_timer
();
eurwdt_disable_timer
();
eurwdt_write_reg
(
WDT_CTRL_REG
,
0x01
);
/* activate the WDT */
eurwdt_write_reg
(
WDT_CTRL_REG
,
0x01
);
/* activate the WDT */
eurwdt_write_reg
(
WDT_OUTPIN_CFG
,
!
strcmp
(
"int"
,
ev
)
?
eurwdt_write_reg
(
WDT_OUTPIN_CFG
,
!
strcmp
(
"int"
,
ev
)
?
WDT_EVENT_INT
:
WDT_EVENT_REBOOT
);
WDT_EVENT_INT
:
WDT_EVENT_REBOOT
);
/* Setting interrupt line */
/* Setting interrupt line */
if
(
irq
==
2
||
irq
>
15
||
irq
<
0
)
{
if
(
irq
==
2
||
irq
>
15
||
irq
<
0
)
{
printk
(
KERN_ERR
": invalid irq number
\n
"
);
printk
(
KERN_ERR
": invalid irq number
\n
"
);
irq
=
0
;
/* if invalid we disable interrupt */
irq
=
0
;
/* if invalid we disable interrupt */
}
}
if
(
irq
==
0
)
if
(
irq
==
0
)
printk
(
KERN_INFO
": interrupt disabled
\n
"
);
printk
(
KERN_INFO
": interrupt disabled
\n
"
);
eurwdt_write_reg
(
WDT_TIMER_CFG
,
irq
<<
4
);
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_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
)
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
#ifdef ONLY_TESTING
printk
(
KERN_CRIT
"Would Reboot.
\n
"
);
printk
(
KERN_CRIT
"Would Reboot.
\n
"
);
#else
#else
printk
(
KERN_CRIT
"Initiating system reboot.
\n
"
);
printk
(
KERN_CRIT
"Initiating system reboot.
\n
"
);
machine_restart
(
NULL
);
machine_restart
(
NULL
);
#endif
#endif
}
}
/**
/**
*
eurwdt_ping:
* eurwdt_ping:
*
*
*
Reload counter one with the watchdog timeout.
* Reload counter one with the watchdog timeout.
*/
*/
static
void
eurwdt_ping
(
void
)
static
void
eurwdt_ping
(
void
)
{
{
/* Write the watchdog default value */
/* Write the watchdog default value */
eurwdt_set_timeout
(
timeout
);
eurwdt_set_timeout
(
timeout
);
}
}
/**
/**
*
eurwdt_write:
* eurwdt_write:
*
@file: file handle to the watchdog
* @file: file handle to the watchdog
*
@buf: buffer to write (unused as data does not matter here
* @buf: buffer to write (unused as data does not matter here
*
@count: count of bytes
* @count: count of bytes
*
@ppos: pointer to the position to write. No seeks allowed
* @ppos: pointer to the position to write. No seeks allowed
*
*
*
A write to a watchdog device is defined as a keepalive signal. Any
* 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.
* 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
,
static
ssize_t
eurwdt_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
loff_t
*
ppos
)
{
{
/* Can't seek (pwrite) on this device */
/* Can't seek (pwrite) on this device */
if
(
ppos
!=
&
file
->
f_pos
)
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
return
-
ESPIPE
;
if
(
count
)
{
if
(
count
)
{
eurwdt_ping
();
/* the default timeout */
if
(
!
nowayout
)
{
return
1
;
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:
* eurwdt_ioctl:
*
@inode: inode of the device
* @inode: inode of the device
*
@file: file handle to the device
* @file: file handle to the device
*
@cmd: watchdog command
* @cmd: watchdog command
*
@arg: argument pointer
* @arg: argument pointer
*
*
*
The watchdog API defines a common set of functions for all watchdogs
* The watchdog API defines a common set of functions for all watchdogs
*
according to their available features.
* according to their available features.
*/
*/
static
int
eurwdt_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
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
=
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_CARDRESET
,
.
options
=
WDIOF_CARDRESET
,
.
firmware_version
=
1
,
.
firmware_version
=
1
,
.
identity
=
"WDT Eurotech CPU-1220/1410"
,
.
identity
=
"WDT Eurotech CPU-1220/1410"
,
};
};
int
time
;
int
time
;
switch
(
cmd
)
{
switch
(
cmd
)
{
default:
default:
return
-
ENOTTY
;
return
-
ENOTTY
;
case
WDIOC_GETSUPPORT
:
case
WDIOC_GETSUPPORT
:
return
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
return
copy_to_user
((
struct
watchdog_info
*
)
arg
,
&
ident
,
sizeof
(
ident
))
?
-
EFAULT
:
0
;
sizeof
(
ident
))
?
-
EFAULT
:
0
;
case
WDIOC_GETBOOTSTATUS
:
case
WDIOC_GETBOOTSTATUS
:
return
put_user
(
0
,
(
int
*
)
arg
);
return
put_user
(
0
,
(
int
*
)
arg
);
case
WDIOC_KEEPALIVE
:
case
WDIOC_KEEPALIVE
:
eurwdt_ping
();
eurwdt_ping
();
return
0
;
return
0
;
case
WDIOC_SETTIMEOUT
:
case
WDIOC_SETTIMEOUT
:
if
(
copy_from_user
(
&
time
,
(
int
*
)
arg
,
sizeof
(
int
)))
if
(
copy_from_user
(
&
time
,
(
int
*
)
arg
,
sizeof
(
int
)))
return
-
EFAULT
;
return
-
EFAULT
;
/* Sanity check */
/* Sanity check */
if
(
time
<
0
||
time
>
255
)
if
(
time
<
0
||
time
>
255
)
return
-
EINVAL
;
return
-
EINVAL
;
timeout
=
time
;
timeout
=
time
;
eurwdt_set_timeout
(
time
);
eurwdt_set_timeout
(
time
);
return
0
;
return
0
;
}
}
}
}
/**
/**
*
eurwdt_open:
* eurwdt_open:
*
@inode: inode of device
* @inode: inode of device
*
@file: file handle to device
* @file: file handle to device
*
*
*
The misc device has been opened. The watchdog device is single
* The misc device has been opened. The watchdog device is single
*
open and on opening we load the counter.
* open and on opening we load the counter.
*/
*/
static
int
eurwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
eurwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
switch
(
minor
(
inode
->
i_rdev
))
{
switch
(
minor
(
inode
->
i_rdev
))
{
case
WATCHDOG_MINOR
:
case
WATCHDOG_MINOR
:
spin_lock
(
&
eurwdt_lock
);
spin_lock
(
&
eurwdt_lock
);
if
(
eurwdt_is_open
)
{
if
(
eurwdt_is_open
)
{
spin_unlock
(
&
eurwdt_lock
);
spin_unlock
(
&
eurwdt_lock
);
return
-
EBUSY
;
return
-
EBUSY
;
}
}
if
(
nowayout
)
{
if
(
nowayout
)
MOD_INC_USE_COUNT
;
MOD_INC_USE_COUNT
;
}
eurwdt_is_open
=
1
;
eurwdt_is_open
=
1
;
/* Activate the WDT */
/* Activate the WDT */
eurwdt_activate_timer
();
eurwdt_activate_timer
();
spin_unlock
(
&
eurwdt_lock
);
spin_unlock
(
&
eurwdt_lock
);
MOD_INC_USE_COUNT
;
MOD_INC_USE_COUNT
;
return
0
;
return
0
;
case
TEMP_MINOR
:
return
0
;
case
TEMP_MINOR
:
return
0
;
default:
return
-
ENODEV
;
default:
}
return
-
ENODEV
;
}
}
}
/**
/**
*
eurwdt_release:
* eurwdt_release:
*
@inode: inode to board
* @inode: inode to board
*
@file: file handle to board
* @file: file handle to board
*
*
*
The watchdog has a configurable API. There is a religious dispute
* The watchdog has a configurable API. There is a religious dispute
*
between people who want their watchdog to be able to shut down and
* 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
* 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
* reboots. In the former case we disable the counters, in the latter
*
case you have to open it again very soon.
* case you have to open it again very soon.
*/
*/
static
int
eurwdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
eurwdt_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
!
nowayout
)
{
if
(
!
nowayout
)
eurwdt_disable_timer
();
eurwdt_disable_timer
();
}
eurwdt_is_open
=
0
;
MOD_DEC_USE_COUNT
;
eurwdt_is_open
=
0
;
}
MOD_DEC_USE_COUNT
;
}
return
0
;
return
0
;
}
}
/**
/**
*
eurwdt_notify_sys:
* eurwdt_notify_sys:
*
@this: our notifier block
* @this: our notifier block
*
@code: the event being reported
* @code: the event being reported
*
@unused: unused
* @unused: unused
*
*
*
Our notifier is called on system shutdowns. We want to turn the card
* Our notifier is called on system shutdowns. We want to turn the card
*
off at reboot otherwise the machine will reboot again during memory
* off at reboot otherwise the machine will reboot again during memory
*
test or worse yet during the following fsck. This would suck, in fact
* test or worse yet during the following fsck. This would suck, in fact
*
trust me - if it happens it does suck.
* trust me - if it happens it does suck.
*/
*/
static
int
eurwdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
static
int
eurwdt_notify_sys
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
unused
)
void
*
unused
)
{
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
if
(
code
==
SYS_DOWN
||
code
==
SYS_HALT
)
{
/* Turn the card off */
/* Turn the card off */
eurwdt_disable_timer
();
eurwdt_disable_timer
();
}
}
return
NOTIFY_DONE
;
return
NOTIFY_DONE
;
}
}
/*
/*
*
Kernel Interfaces
* Kernel Interfaces
*/
*/
static
struct
file_operations
eurwdt_fops
=
{
static
struct
file_operations
eurwdt_fops
=
{
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
llseek
=
no_llseek
,
.
write
=
eurwdt_write
,
.
write
=
eurwdt_write
,
.
ioctl
=
eurwdt_ioctl
,
.
ioctl
=
eurwdt_ioctl
,
.
open
=
eurwdt_open
,
.
open
=
eurwdt_open
,
.
release
=
eurwdt_release
,
.
release
=
eurwdt_release
,
};
};
static
struct
miscdevice
eurwdt_miscdev
=
{
static
struct
miscdevice
eurwdt_miscdev
=
{
...
@@ -403,8 +415,8 @@ 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
* The WDT card needs to learn about soft shutdowns in order to
*
turn the timebomb registers off.
* turn the timebomb registers off.
*/
*/
static
struct
notifier_block
eurwdt_notifier
=
{
static
struct
notifier_block
eurwdt_notifier
=
{
...
@@ -412,85 +424,85 @@ 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.
* 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
* 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
* 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
* will not touch PC memory so all is fine. You just have to load a new
*
module in 60 seconds or reboot.
* module in 60 seconds or reboot.
*/
*/
static
void
__exit
eurwdt_exit
(
void
)
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
);
unregister_reboot_notifier
(
&
eurwdt_notifier
);
release_region
(
io
,
2
);
release_region
(
io
,
2
);
free_irq
(
irq
,
NULL
);
free_irq
(
irq
,
NULL
);
}
}
/**
/**
*
eurwdt_init:
* eurwdt_init:
*
*
*
Set up the WDT watchdog board. After grabbing the resources
* Set up the WDT watchdog board. After grabbing the resources
*
we require we need also to unlock the device.
* we require we need also to unlock the device.
*
The open() function will actually kick the board off.
* The open() function will actually kick the board off.
*/
*/
static
int
__init
eurwdt_init
(
void
)
static
int
__init
eurwdt_init
(
void
)
{
{
int
ret
;
int
ret
;
eurwdt_validate_timeout
();
eurwdt_validate_timeout
();
ret
=
misc_register
(
&
eurwdt_miscdev
);
ret
=
misc_register
(
&
eurwdt_miscdev
);
if
(
ret
)
{
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: can't misc_register on minor=%d
\n
"
,
printk
(
KERN_ERR
"eurwdt: can't misc_register on minor=%d
\n
"
,
WATCHDOG_MINOR
);
WATCHDOG_MINOR
);
goto
out
;
goto
out
;
}
}
ret
=
request_irq
(
irq
,
eurwdt_interrupt
,
SA_INTERRUPT
,
"eurwdt"
,
NULL
);
ret
=
request_irq
(
irq
,
eurwdt_interrupt
,
SA_INTERRUPT
,
"eurwdt"
,
NULL
);
if
(
ret
)
{
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: IRQ %d is not free.
\n
"
,
irq
);
printk
(
KERN_ERR
"eurwdt: IRQ %d is not free.
\n
"
,
irq
);
goto
outmisc
;
goto
outmisc
;
}
}
if
(
!
request_region
(
io
,
2
,
"eurwdt"
))
{
if
(
!
request_region
(
io
,
2
,
"eurwdt"
))
{
printk
(
KERN_ERR
"eurwdt: IO %X is not free.
\n
"
,
io
);
printk
(
KERN_ERR
"eurwdt: IO %X is not free.
\n
"
,
io
);
ret
=
-
EBUSY
;
ret
=
-
EBUSY
;
goto
outirq
;
goto
outirq
;
}
}
ret
=
register_reboot_notifier
(
&
eurwdt_notifier
);
ret
=
register_reboot_notifier
(
&
eurwdt_notifier
);
if
(
ret
)
{
if
(
ret
)
{
printk
(
KERN_ERR
"eurwdt: can't register reboot notifier (err=%d)
\n
"
,
ret
);
printk
(
KERN_ERR
"eurwdt: can't register reboot notifier (err=%d)
\n
"
,
ret
);
goto
outreg
;
goto
outreg
;
}
}
eurwdt_unlock_chip
();
eurwdt_unlock_chip
();
ret
=
0
;
ret
=
0
;
printk
(
KERN_INFO
"Eurotech WDT driver 0.01 at %X (Interrupt %d)"
printk
(
KERN_INFO
"Eurotech WDT driver 0.01 at %X (Interrupt %d)"
" - timeout event: %s
\n
"
,
" - timeout event: %s
\n
"
,
io
,
irq
,
(
!
strcmp
(
"int"
,
ev
)
?
"int"
:
"reboot"
));
io
,
irq
,
(
!
strcmp
(
"int"
,
ev
)
?
"int"
:
"reboot"
));
spin_lock_init
(
&
eurwdt_lock
);
spin_lock_init
(
&
eurwdt_lock
);
out:
out:
return
ret
;
return
ret
;
outreg:
outreg:
release_region
(
io
,
2
);
release_region
(
io
,
2
);
outirq:
outirq:
free_irq
(
irq
,
NULL
);
free_irq
(
irq
,
NULL
);
outmisc:
outmisc:
misc_deregister
(
&
eurwdt_miscdev
);
misc_deregister
(
&
eurwdt_miscdev
);
goto
out
;
goto
out
;
}
}
module_init
(
eurwdt_init
);
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,
...
@@ -244,7 +244,9 @@ static int i810tco_ioctl (struct inode *inode, struct file *file,
int
options
,
retval
=
-
EINVAL
;
int
options
,
retval
=
-
EINVAL
;
static
struct
watchdog_info
ident
=
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
,
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
0
,
.
firmware_version
=
0
,
.
identity
=
"i810 TCO timer"
,
.
identity
=
"i810 TCO timer"
,
};
};
...
...
drivers/char/watchdog/ib700wdt.c
View file @
a31ebc7d
...
@@ -54,6 +54,7 @@
...
@@ -54,6 +54,7 @@
static
int
ibwdt_is_open
;
static
int
ibwdt_is_open
;
static
spinlock_t
ibwdt_lock
;
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)
...
@@ -136,6 +137,21 @@ ibwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
return
-
ESPIPE
;
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
;
}
}
ibwdt_ping
();
ibwdt_ping
();
return
1
;
return
1
;
}
}
...
@@ -153,7 +169,9 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
...
@@ -153,7 +169,9 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned
long
arg
)
unsigned
long
arg
)
{
{
static
struct
watchdog_info
ident
=
{
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
)
{
switch
(
cmd
)
{
...
@@ -180,42 +198,38 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
...
@@ -180,42 +198,38 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static
int
static
int
ibwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
ibwdt_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
switch
(
minor
(
inode
->
i_rdev
))
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
case
WATCHDOG_MINOR
:
spin_lock
(
&
ibwdt_lock
);
spin_lock
(
&
ibwdt_lock
);
if
(
ibwdt_is_open
)
{
if
(
ibwdt_is_open
)
{
spin_unlock
(
&
ibwdt_lock
);
return
-
EBUSY
;
}
if
(
nowayout
)
{
MOD_INC_USE_COUNT
;
}
/*
* Activate
*/
ibwdt_is_open
=
1
;
ibwdt_ping
();
spin_unlock
(
&
ibwdt_lock
);
spin_unlock
(
&
ibwdt_lock
);
return
0
;
return
-
EBUSY
;
default:
}
return
-
ENODEV
;
if
(
nowayout
)
MOD_INC_USE_COUNT
;
/* Activate */
ibwdt_is_open
=
1
;
ibwdt_ping
();
spin_unlock
(
&
ibwdt_lock
);
return
0
;
}
else
{
return
-
ENODEV
;
}
}
}
}
static
int
static
int
ibwdt_close
(
struct
inode
*
inode
,
struct
file
*
file
)
ibwdt_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
lock_kernel
();
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
spin_lock
(
&
ibwdt_lock
);
spin_lock
(
&
ibwdt_lock
);
if
(
!
nowayout
)
{
if
(
expect_close
)
outb_p
(
timeout_val
,
WDT_STOP
);
outb_p
(
timeout_val
,
WDT_STOP
);
}
else
printk
(
KERN_CRIT
"WDT device closed unexpectedly. WDT will not stop!
\n
"
);
ibwdt_is_open
=
0
;
ibwdt_is_open
=
0
;
spin_unlock
(
&
ibwdt_lock
);
spin_unlock
(
&
ibwdt_lock
);
}
}
unlock_kernel
();
return
0
;
return
0
;
}
}
...
@@ -248,9 +262,9 @@ static struct file_operations ibwdt_fops = {
...
@@ -248,9 +262,9 @@ static struct file_operations ibwdt_fops = {
};
};
static
struct
miscdevice
ibwdt_miscdev
=
{
static
struct
miscdevice
ibwdt_miscdev
=
{
WATCHDOG_MINOR
,
.
minor
=
WATCHDOG_MINOR
,
"watchdog"
,
.
name
=
"watchdog"
,
&
ibwdt_fops
.
fops
=
&
ibwdt_fops
};
};
/*
/*
...
@@ -259,9 +273,9 @@ static struct miscdevice ibwdt_miscdev = {
...
@@ -259,9 +273,9 @@ static struct miscdevice ibwdt_miscdev = {
*/
*/
static
struct
notifier_block
ibwdt_notifier
=
{
static
struct
notifier_block
ibwdt_notifier
=
{
ibwdt_notify_sys
,
.
notifier_call
=
ibwdt_notify_sys
,
NULL
,
.
next
=
NULL
,
0
.
priority
=
0
};
};
static
int
__init
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
...
@@ -117,7 +117,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
#define PFX "machzwd"
#define PFX "machzwd"
static
struct
watchdog_info
zf_info
=
{
static
struct
watchdog_info
zf_info
=
{
.
options
=
WDIOF_KEEPALIVEPING
,
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
firmware_version
=
1
,
.
identity
=
"ZF-Logic watchdog"
.
identity
=
"ZF-Logic watchdog"
};
};
...
@@ -314,10 +314,10 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
...
@@ -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 */
/* See if we got the magic character */
if
(
count
){
if
(
count
){
/*
/*
* no need to check for close confirmation
* no need to check for close confirmation
* no way to disable watchdog ;)
* no way to disable watchdog ;)
*/
*/
if
(
!
nowayout
)
{
if
(
!
nowayout
)
{
size_t
ofs
;
size_t
ofs
;
...
@@ -328,7 +328,7 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
...
@@ -328,7 +328,7 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
zf_expect_close
=
0
;
zf_expect_close
=
0
;
/* now scan */
/* now scan */
for
(
ofs
=
0
;
ofs
!=
count
;
ofs
++
){
for
(
ofs
=
0
;
ofs
!=
count
;
ofs
++
){
char
c
;
char
c
;
if
(
get_user
(
c
,
buf
+
ofs
))
if
(
get_user
(
c
,
buf
+
ofs
))
return
-
EFAULT
;
return
-
EFAULT
;
...
@@ -338,6 +338,7 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
...
@@ -338,6 +338,7 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
}
}
}
}
}
}
/*
/*
* Well, anyhow someone wrote to us,
* Well, anyhow someone wrote to us,
* we should return that favour
* we should return that favour
...
@@ -395,9 +396,9 @@ static int zf_open(struct inode *inode, struct file *file)
...
@@ -395,9 +396,9 @@ static int zf_open(struct inode *inode, struct file *file)
return
-
EBUSY
;
return
-
EBUSY
;
}
}
if
(
nowayout
)
{
if
(
nowayout
)
MOD_INC_USE_COUNT
;
MOD_INC_USE_COUNT
;
}
zf_is_open
=
1
;
zf_is_open
=
1
;
spin_unlock
(
&
zf_lock
);
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 */
...
@@ -62,6 +62,7 @@ static long mixcomwd_opened; /* long req'd for setbit --RR */
static
int
watchdog_port
;
static
int
watchdog_port
;
static
int
mixcomwd_timer_alive
;
static
int
mixcomwd_timer_alive
;
static
struct
timer_list
mixcomwd_timer
=
TIMER_INITIALIZER
(
NULL
,
0
,
0
);
static
struct
timer_list
mixcomwd_timer
=
TIMER_INITIALIZER
(
NULL
,
0
,
0
);
static
int
expect_close
=
0
;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
nowayout
=
1
;
static
int
nowayout
=
1
;
...
@@ -109,8 +110,7 @@ static int mixcomwd_open(struct inode *inode, struct file *file)
...
@@ -109,8 +110,7 @@ static int mixcomwd_open(struct inode *inode, struct file *file)
static
int
mixcomwd_release
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
mixcomwd_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
if
(
expect_close
)
{
if
(
!
nowayout
)
{
if
(
mixcomwd_timer_alive
)
{
if
(
mixcomwd_timer_alive
)
{
printk
(
KERN_ERR
"mixcomwd: release called while internal timer alive"
);
printk
(
KERN_ERR
"mixcomwd: release called while internal timer alive"
);
return
-
EBUSY
;
return
-
EBUSY
;
...
@@ -121,7 +121,10 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
...
@@ -121,7 +121,10 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
mixcomwd_timer
.
data
=
0
;
mixcomwd_timer
.
data
=
0
;
mixcomwd_timer_alive
=
1
;
mixcomwd_timer_alive
=
1
;
add_timer
(
&
mixcomwd_timer
);
add_timer
(
&
mixcomwd_timer
);
}
else
{
printk
(
KERN_CRIT
"mixcomwd: WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
}
clear_bit
(
0
,
&
mixcomwd_opened
);
clear_bit
(
0
,
&
mixcomwd_opened
);
return
0
;
return
0
;
}
}
...
@@ -135,6 +138,20 @@ static ssize_t mixcomwd_write(struct file *file, const char *data, size_t len, l
...
@@ -135,6 +138,20 @@ static ssize_t mixcomwd_write(struct file *file, const char *data, size_t len, l
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
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
mixcomwd_ping
();
mixcomwd_ping
();
return
1
;
return
1
;
}
}
...
@@ -145,8 +162,10 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
...
@@ -145,8 +162,10 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
int
status
;
int
status
;
static
struct
watchdog_info
ident
=
{
static
struct
watchdog_info
ident
=
{
WDIOF_KEEPALIVEPING
,
1
,
"MixCOM watchdog"
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
identity
=
"MixCOM watchdog"
};
};
switch
(
cmd
)
switch
(
cmd
)
...
...
drivers/char/watchdog/pcwd.c
View file @
a31ebc7d
...
@@ -40,6 +40,8 @@
...
@@ -40,6 +40,8 @@
* fairly useless proc entry.
* fairly useless proc entry.
* 990610 removed said useless proc code for the merge <alan>
* 990610 removed said useless proc code for the merge <alan>
* 000403 Removed last traces of proc code. <davej>
* 000403 Removed last traces of proc code. <davej>
* 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
* Added timeout module option to override default
*/
*/
#include <linux/module.h>
#include <linux/module.h>
...
@@ -76,7 +78,7 @@
...
@@ -76,7 +78,7 @@
*/
*/
static
int
pcwd_ioports
[]
=
{
0x270
,
0x350
,
0x370
,
0x000
};
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
* 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 };
...
@@ -88,7 +90,23 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
#define PCWD_REVISION_A 1
#define PCWD_REVISION_A 1
#define PCWD_REVISION_C 2
#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.
* These are the defines for the PC Watchdog card, revision A.
...
@@ -121,7 +139,7 @@ static int __init pcwd_checkcard(void)
...
@@ -121,7 +139,7 @@ static int __init pcwd_checkcard(void)
if
(
prev_card_dat
==
0xFF
)
if
(
prev_card_dat
==
0xFF
)
return
0
;
return
0
;
while
(
count
<
WD_TIMEOUT
)
{
while
(
count
<
timeout_val
)
{
/* Read the raw card data from the port, and strip off the
/* Read the raw card data from the port, and strip off the
first 4 bits */
first 4 bits */
...
@@ -256,7 +274,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
...
@@ -256,7 +274,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
else
else
cdat
=
inb
(
current_readport
+
1
);
cdat
=
inb
(
current_readport
+
1
);
spin_unlock
(
&
io_lock
);
spin_unlock
(
&
io_lock
);
rv
=
0
;
rv
=
WDIOF_MAGICCLOSE
;
if
(
revision
==
PCWD_REVISION_A
)
if
(
revision
==
PCWD_REVISION_A
)
{
{
...
@@ -385,8 +403,22 @@ static ssize_t pcwd_write(struct file *file, const char *buf, size_t len,
...
@@ -385,8 +403,22 @@ static ssize_t pcwd_write(struct file *file, const char *buf, size_t len,
if
(
ppos
!=
&
file
->
f_pos
)
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
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
();
pcwd_send_heartbeat
();
return
1
;
return
1
;
}
}
...
@@ -395,28 +427,26 @@ static ssize_t pcwd_write(struct file *file, const char *buf, size_t len,
...
@@ -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
)
static
int
pcwd_open
(
struct
inode
*
ino
,
struct
file
*
filep
)
{
{
switch
(
minor
(
ino
->
i_rdev
))
switch
(
minor
(
ino
->
i_rdev
))
{
{
case
WATCHDOG_MINOR
:
case
WATCHDOG_MINOR
:
if
(
!
atomic_dec_and_test
(
&
open_allowed
)
)
{
if
(
!
atomic_dec_and_test
(
&
open_allowed
)
)
{
atomic_inc
(
&
open_allowed
);
atomic_inc
(
&
open_allowed
);
return
-
EBUSY
;
return
-
EBUSY
;
}
}
MOD_INC_USE_COUNT
;
MOD_INC_USE_COUNT
;
/* Enable the port */
/* Enable the port */
if
(
revision
==
PCWD_REVISION_C
)
if
(
revision
==
PCWD_REVISION_C
)
{
{
spin_lock
(
&
io_lock
);
spin_lock
(
&
io_lock
);
outb_p
(
0x00
,
current_readport
+
3
);
outb_p
(
0x00
,
current_readport
+
3
);
spin_unlock
(
&
io_lock
);
spin_unlock
(
&
io_lock
);
}
}
return
(
0
);
return
(
0
);
case
TEMP_MINOR
:
case
TEMP_MINOR
:
return
(
0
);
return
(
0
);
default:
default:
return
(
-
ENODEV
);
return
(
-
ENODEV
);
}
}
}
}
static
ssize_t
pcwd_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
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,
...
@@ -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
)
static
int
pcwd_close
(
struct
inode
*
ino
,
struct
file
*
filep
)
{
{
if
(
minor
(
ino
->
i_rdev
)
==
WATCHDOG_MINOR
)
if
(
minor
(
ino
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
{
if
(
expect_close
)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
/* Disable the board */
/* Disable the board */
if
(
revision
==
PCWD_REVISION_C
)
{
if
(
revision
==
PCWD_REVISION_C
)
{
spin_lock
(
&
io_lock
);
spin_lock
(
&
io_lock
);
outb_p
(
0xA5
,
current_readport
+
3
);
outb_p
(
0xA5
,
current_readport
+
3
);
outb_p
(
0xA5
,
current_readport
+
3
);
outb_p
(
0xA5
,
current_readport
+
3
);
spin_unlock
(
&
io_lock
);
spin_unlock
(
&
io_lock
);
}
atomic_inc
(
&
open_allowed
);
}
}
atomic_inc
(
&
open_allowed
);
#endif
}
}
return
0
;
return
0
;
}
}
...
@@ -560,9 +589,15 @@ static struct miscdevice temp_miscdev = {
...
@@ -560,9 +589,15 @@ static struct miscdevice temp_miscdev = {
&
pcwd_fops
&
pcwd_fops
};
};
static
void
__init
pcwd_validate_timeout
(
void
)
{
timeout_val
=
timeout
*
2
;
}
static
int
__init
pcwatchdog_init
(
void
)
static
int
__init
pcwatchdog_init
(
void
)
{
{
int
i
,
found
=
0
;
int
i
,
found
=
0
;
pcwd_validate_timeout
();
spin_lock_init
(
&
io_lock
);
spin_lock_init
(
&
io_lock
);
revision
=
PCWD_REVISION_A
;
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,
...
@@ -244,9 +244,9 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
{
static
struct
watchdog_info
ident
=
static
struct
watchdog_info
ident
=
{
{
0
,
.
options
=
WDIOF_MAGICCLOSE
,
1
,
.
firmware_version
=
1
,
"SB60xx"
.
identity
=
"SB60xx"
};
};
switch
(
cmd
)
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 = {
...
@@ -334,21 +334,21 @@ static struct file_operations sh_wdt_fops = {
};
};
static
struct
watchdog_info
sh_wdt_info
=
{
static
struct
watchdog_info
sh_wdt_info
=
{
WDIOF_KEEPALIVEPING
,
.
options
=
WDIOF_KEEPALIVEPING
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
1
,
.
firmware_version
=
1
,
"SH WDT"
,
.
identity
=
"SH WDT"
,
};
};
static
struct
notifier_block
sh_wdt_notifier
=
{
static
struct
notifier_block
sh_wdt_notifier
=
{
sh_wdt_notify_sys
,
.
notifier_call
=
sh_wdt_notify_sys
,
NULL
,
.
next
=
NULL
,
0
.
priority
=
0
};
};
static
struct
miscdevice
sh_wdt_miscdev
=
{
static
struct
miscdevice
sh_wdt_miscdev
=
{
WATCHDOG_MINOR
,
.
minor
=
WATCHDOG_MINOR
,
"watchdog"
,
.
name
=
"watchdog"
,
&
sh_wdt_fops
,
.
fops
&
sh_wdt_fops
,
};
};
/**
/**
...
...
drivers/char/watchdog/softdog.c
View file @
a31ebc7d
...
@@ -47,6 +47,7 @@
...
@@ -47,6 +47,7 @@
#define TIMER_MARGIN 60
/* (secs) Default is 1 minute */
#define TIMER_MARGIN 60
/* (secs) Default is 1 minute */
static
int
expect_close
=
0
;
static
int
soft_margin
=
TIMER_MARGIN
;
/* in seconds */
static
int
soft_margin
=
TIMER_MARGIN
;
/* in seconds */
MODULE_PARM
(
soft_margin
,
"i"
);
MODULE_PARM
(
soft_margin
,
"i"
);
...
@@ -79,7 +80,7 @@ static int timer_alive;
...
@@ -79,7 +80,7 @@ static int timer_alive;
static
void
watchdog_fire
(
unsigned
long
data
)
static
void
watchdog_fire
(
unsigned
long
data
)
{
{
#ifdef ONLY_TESTING
#ifdef ONLY_TESTING
printk
(
KERN_CRIT
"SOFTDOG: Would Reboot.
\n
"
);
printk
(
KERN_CRIT
"SOFTDOG: Would Reboot.
\n
"
);
#else
#else
printk
(
KERN_CRIT
"SOFTDOG: Initiating system reboot.
\n
"
);
printk
(
KERN_CRIT
"SOFTDOG: Initiating system reboot.
\n
"
);
machine_restart
(
NULL
);
machine_restart
(
NULL
);
...
@@ -114,6 +115,8 @@ static int softdog_release(struct inode *inode, struct file *file)
...
@@ -114,6 +115,8 @@ static int softdog_release(struct inode *inode, struct file *file)
*/
*/
if
(
!
nowayout
)
{
if
(
!
nowayout
)
{
del_timer
(
&
watchdog_ticktock
);
del_timer
(
&
watchdog_ticktock
);
}
else
{
printk
(
KERN_CRIT
"SOFTDOG: WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
}
timer_alive
=
0
;
timer_alive
=
0
;
return
0
;
return
0
;
...
@@ -129,6 +132,21 @@ static ssize_t softdog_write(struct file *file, const char *data, size_t len, lo
...
@@ -129,6 +132,21 @@ static ssize_t softdog_write(struct file *file, const char *data, size_t len, lo
* Refresh the timer.
* Refresh the timer.
*/
*/
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
,
data
+
i
))
return
-
EFAULT
;
if
(
c
==
'V'
)
expect_close
=
1
;
}
}
mod_timer
(
&
watchdog_ticktock
,
jiffies
+
(
soft_margin
*
HZ
));
mod_timer
(
&
watchdog_ticktock
,
jiffies
+
(
soft_margin
*
HZ
));
return
1
;
return
1
;
}
}
...
@@ -139,6 +157,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
...
@@ -139,6 +157,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
static
struct
watchdog_info
ident
=
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
identity
=
"Software Watchdog"
,
.
identity
=
"Software Watchdog"
,
};
};
switch
(
cmd
)
{
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,
...
@@ -251,9 +251,9 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
{
static
struct
watchdog_info
ident
=
static
struct
watchdog_info
ident
=
{
{
0
,
.
options
=
WDIOF_MAGICCLOSE
,
1
,
.
firmware_version
=
1
,
"W83877F"
.
identity
=
"W83877F"
};
};
switch
(
cmd
)
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 @@
...
@@ -52,6 +52,7 @@
#include <asm/system.h>
#include <asm/system.h>
static
unsigned
long
wdt_is_open
;
static
unsigned
long
wdt_is_open
;
static
int
expect_close
;
/*
/*
* You must set these - there is no sane way to probe for this board.
* You must set these - there is no sane way to probe for this board.
...
@@ -258,8 +259,21 @@ static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_
...
@@ -258,8 +259,21 @@ static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_
if
(
ppos
!=
&
file
->
f_pos
)
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
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
();
wdt_ping
();
return
1
;
return
1
;
}
}
...
@@ -317,10 +331,11 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
...
@@ -317,10 +331,11 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
{
static
struct
watchdog_info
ident
=
static
struct
watchdog_info
ident
=
{
{
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
WDIOF_POWEROVER
.
options
=
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
WDIOF_POWEROVER
|
WDIOF_EXTERN1
|
WDIOF_EXTERN2
|
WDIOF_FANFAULT
,
|
WDIOF_EXTERN1
|
WDIOF_EXTERN2
|
WDIOF_FANFAULT
1
,
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
"WDT500/501"
.
firmware_version
=
1
,
.
identity
=
"WDT500/501"
};
};
ident
.
options
&=
WDT_OPTION_MASK
;
/* Mask down to the card we have */
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)
...
@@ -399,9 +414,11 @@ static int wdt_release(struct inode *inode, struct file *file)
{
{
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
if
(
minor
(
inode
->
i_rdev
)
==
WATCHDOG_MINOR
)
{
{
if
(
!
nowayout
)
{
if
(
expect_close
)
{
inb_p
(
WDT_DC
);
/* Disable counters */
inb_p
(
WDT_DC
);
/* Disable counters */
wdt_ctr_load
(
2
,
0
);
/* 0 length reset pulses now */
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
);
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 */
...
@@ -41,6 +41,7 @@ static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */
static
int
timeoutM
=
DEFAULT_TIMEOUT
;
/* timeout in minutes */
static
int
timeoutM
=
DEFAULT_TIMEOUT
;
/* timeout in minutes */
static
unsigned
long
timer_alive
;
static
unsigned
long
timer_alive
;
static
int
testmode
;
static
int
testmode
;
static
int
expect_close
=
0
;
MODULE_PARM
(
timeout
,
"i"
);
MODULE_PARM
(
timeout
,
"i"
);
MODULE_PARM_DESC
(
timeout
,
"Watchdog timeout in seconds (60..15300), default=60"
);
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)
...
@@ -196,6 +197,8 @@ static int wdt977_release(struct inode *inode, struct file *file)
clear_bit
(
0
,
&
timer_alive
);
clear_bit
(
0
,
&
timer_alive
);
printk
(
KERN_INFO
"Wdt977 Watchdog: shutdown
\n
"
);
printk
(
KERN_INFO
"Wdt977 Watchdog: shutdown
\n
"
);
}
else
{
printk
(
KERN_CRIT
"WDT device closed unexpectedly. WDT will not stop!
\n
"
);
}
}
return
0
;
return
0
;
}
}
...
@@ -220,6 +223,21 @@ static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, lo
...
@@ -220,6 +223,21 @@ static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, lo
if
(
count
)
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
();
kick_wdog
();
return
1
;
return
1
;
}
}
...
...
drivers/char/watchdog/wdt_pci.c
View file @
a31ebc7d
...
@@ -73,6 +73,7 @@
...
@@ -73,6 +73,7 @@
#endif
#endif
static
unsigned
long
wdt_is_open
;
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.
* 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
...
@@ -276,6 +277,16 @@ static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, lo
if
(
count
)
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
();
wdtpci_ping
();
return
1
;
return
1
;
}
}
...
@@ -332,9 +343,10 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd
...
@@ -332,9 +343,10 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd
unsigned
long
arg
)
unsigned
long
arg
)
{
{
static
struct
watchdog_info
ident
=
{
static
struct
watchdog_info
ident
=
{
.
options
=
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
.
options
=
WDIOF_OVERHEAT
|
WDIOF_POWERUNDER
|
WDIOF_POWEROVER
|
WDIOF_EXTERN1
|
WDIOF_POWEROVER
|
WDIOF_EXTERN1
|
WDIOF_EXTERN2
|
WDIOF_FANFAULT
,
WDIOF_EXTERN2
|
WDIOF_FANFAULT
|
WDIOF_SETTIMEOUT
|
WDIOF_MAGICCLOSE
,
.
firmware_version
=
1
,
.
firmware_version
=
1
,
.
identity
=
"WDT500/501PCI"
,
.
identity
=
"WDT500/501PCI"
,
};
};
...
...
include/linux/watchdog.h
View file @
a31ebc7d
...
@@ -39,6 +39,7 @@ struct watchdog_info {
...
@@ -39,6 +39,7 @@ struct watchdog_info {
#define WDIOF_CARDRESET 0x0020
/* Card previously reset the CPU */
#define WDIOF_CARDRESET 0x0020
/* Card previously reset the CPU */
#define WDIOF_POWEROVER 0x0040
/* Power over voltage */
#define WDIOF_POWEROVER 0x0040
/* Power over voltage */
#define WDIOF_SETTIMEOUT 0x0080
/* Set timeout (in seconds) */
#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 WDIOF_KEEPALIVEPING 0x8000
/* Keep alive ping reply */
#define WDIOS_DISABLECARD 0x0001
/* Turn off the watchdog timer */
#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