#include #include #include #include #include #include static int timeout = 60; /* in seconds */ static int nowayout = 0; static char expect_close; static unsigned long open_once=0; module_param(timeout, int, 0); module_param(nowayout, int, 0); static void watchdog_fire(unsigned long data) { printk("reboot...\n"); emergency_restart(); } static int reset_watchdogtimer(void) { printk("reset_watchdogtimer()\n"); return 0; } static int start_watchdogtimer(void) { printk("start_watchdogtimer()\n"); return 0; } static int stop_watchdogtimer(void) { printk("stop_watchdogtimer()\n"); return 0; } static int driver_open(struct inode *inode, struct file *file) { if (test_and_set_bit(0, &open_once)) return -EBUSY; start_watchdogtimer(); return nonseekable_open(inode, file); } static int driver_release(struct inode *inode, struct file *file) { if (expect_close == 42) { stop_watchdogtimer(); } clear_bit(0, &open_once); expect_close = 0; return 0; } static ssize_t driver_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { 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; } } reset_watchdogtimer(); } return len; } static long driver_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int __user *p = argp; static const struct watchdog_info ident = { .options =WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .firmware_version = 0, .identity ="Watchdog-Template", }; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: reset_watchdogtimer(); return 0; case WDIOC_SETTIMEOUT: if (get_user(timeout, p)) return -EFAULT; reset_watchdogtimer(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timeout, p); default: return -ENOTTY; } } static int reboot_callback(struct notifier_block *this, unsigned long code, void *unused) { if (code == SYS_DOWN || code == SYS_HALT) stop_watchdogtimer(); return NOTIFY_DONE; } static const struct file_operations driver_fops = { .owner = THIS_MODULE, .write = driver_write, .unlocked_ioctl = driver_ioctl, .open = driver_open, .release = driver_release, }; static struct miscdevice watchdog_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &driver_fops, }; static struct notifier_block reboot_notifier = { .notifier_call = reboot_callback, }; static int __init driver_init(void) { int ret; ret = misc_register(&watchdog_miscdev); if (ret) { printk("miscr_register failed with %d\n", ret ); return ret; } // init_watchdogtimer( watchdog_fire ); // ... ret = register_reboot_notifier(&reboot_notifier); if( ret ) { misc_deregister(&watchdog_miscdev); printk("register_reboot_notifier failed\n"); return ret; } return 0; } static void __exit watchdog_exit(void) { unregister_reboot_notifier(&reboot_notifier); misc_deregister(&watchdog_miscdev); } module_init(driver_init); module_exit(watchdog_exit); MODULE_LICENSE("GPL");