20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22 #include <linux/module.h>
26 #include <linux/watchdog.h>
28 #include <linux/reboot.h>
42 static int margin = 60;
50 static u16 wdto_restart;
52 static unsigned long open_lock;
56 #define W_ENABLE 0x00fa
57 #define W_DISABLE 0x0000
60 #define W_SCALE (32768/1024)
62 static void scx200_wdt_ping(
void)
66 spin_unlock(&scx_lock);
69 static void scx200_wdt_update_margin(
void)
71 pr_info(
"timer margin %d seconds\n", margin);
72 wdto_restart = margin *
W_SCALE;
75 static void scx200_wdt_enable(
void)
77 pr_debug(
"enabling watchdog timer, wdto_restart = %d\n", wdto_restart);
83 spin_unlock(&scx_lock);
88 static void scx200_wdt_disable(
void)
90 pr_debug(
"disabling watchdog timer\n");
96 spin_unlock(&scx_lock);
109 static int scx200_wdt_release(
struct inode *inode,
struct file *file)
111 if (expect_close != 42)
112 pr_warn(
"watchdog device closed unexpectedly, will not disable the watchdog timer\n");
114 scx200_wdt_disable();
126 scx200_wdt_disable();
132 .notifier_call = scx200_wdt_notify_sys,
135 static ssize_t scx200_wdt_write(
struct file *file,
const char __user *
data,
136 size_t len, loff_t *ppos)
145 for (i = 0; i < len; ++
i) {
159 static long scx200_wdt_ioctl(
struct file *file,
unsigned int cmd,
165 .identity =
"NatSemi SCx200 Watchdog",
166 .firmware_version = 1,
191 scx200_wdt_update_margin();
205 .write = scx200_wdt_write,
206 .unlocked_ioctl = scx200_wdt_ioctl,
207 .open = scx200_wdt_open,
208 .release = scx200_wdt_release,
211 static struct miscdevice scx200_wdt_miscdev = {
214 .fops = &scx200_wdt_fops,
217 static int __init scx200_wdt_init(
void)
221 pr_debug(
"NatSemi SCx200 Watchdog Driver\n");
229 "NatSemi SCx200 Watchdog")) {
230 pr_warn(
"watchdog I/O region busy\n");
234 scx200_wdt_update_margin();
235 scx200_wdt_disable();
239 pr_err(
"unable to register reboot notifier\n");
256 static void __exit scx200_wdt_cleanup(
void)