// SPDX-License-Identifier: GPL-2.0-or-later /* * W83877F Computer Watchdog Timer driver * * Based on acquirewdt.c by Alan Cox, * and sbc60xxwdt.c by Jakob Oestergaard <[email protected]> * * 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 <[email protected]> * * 4/19 - 2001 [Initial revision] * 9/27 - 2001 Added spinlocking * 4/12 - 2002 [[email protected]] Eliminate extra comments * Eliminate fop_read * Eliminate extra spin_unlock * Added KERN_* tags to printks * add CONFIG_WATCHDOG_NOWAYOUT support * fix possible wdt_is_open race * changed watchdog_info to correctly reflect what * the driver offers * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, * WDIOC_SETTIMEOUT, * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls * 09/8 - 2003 [[email protected]] cleanup of trailing spaces * added extra printk's for startup problems * use module_param * made timeout (the emulated heartbeat) a * module_param * made the keepalive ping an internal subroutine * * This WDT driver is different from most other Linux WDT * 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. */ #define pr_fmt(fmt) … #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/timer.h> #include <linux/jiffies.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/fs.h> #include <linux/ioport.h> #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> #include <linux/io.h> #include <linux/uaccess.h> #define OUR_NAME … #define ENABLE_W83877F_PORT … #define ENABLE_W83877F … #define DISABLE_W83877F … #define WDT_PING … #define WDT_REGISTER … #define WDT_ENABLE … #define WDT_DISABLE … /* * The W83877F seems to be fixed at 1.6s timeout (at least on the * EMACS PC-104 board I'm using). If we reset the watchdog every * ~250ms we should be safe. */ #define WDT_INTERVAL … /* * 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 WATCHDOG_TIMEOUT … /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ static int timeout = …; module_param(timeout, int, 0); MODULE_PARM_DESC(…) …; static bool nowayout = … WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(…) …; static void wdt_timer_ping(struct timer_list *); static DEFINE_TIMER(timer, wdt_timer_ping); static unsigned long next_heartbeat; static unsigned long wdt_is_open; static char wdt_expect_close; static DEFINE_SPINLOCK(wdt_spinlock); /* * Whack the dog */ static void wdt_timer_ping(struct timer_list *unused) { … } /* * Utility routines */ static void wdt_change(int writeval) { … } static void wdt_startup(void) { … } static void wdt_turnoff(void) { … } static void wdt_keepalive(void) { … } /* * /dev/watchdog handling */ static ssize_t fop_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { … } static int fop_open(struct inode *inode, struct file *file) { … } static int fop_close(struct inode *inode, struct file *file) { … } static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } static const struct file_operations wdt_fops = …; static struct miscdevice wdt_miscdev = …; /* * Notifier for system down */ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { … } /* * The WDT needs to learn about soft shutdowns in order to * turn the timebomb registers off. */ static struct notifier_block wdt_notifier = …; static void __exit w83877f_wdt_unload(void) { … } static int __init w83877f_wdt_init(void) { … } module_init(…) …; module_exit(w83877f_wdt_unload); MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;