void watchdog_init( void ) { wdt_init(); wdt_config(); wdt_set_timeout(((WATCHDOG_TIMEOUT/1000)*WATCHDOG_CLK_FREQ)); watchdog_smphr = xSemaphoreCreateBinary(); xTaskCreate( WatchdogTask, (const char *) "Watchdog Task", 60, (void * ) NULL, tskWATCHDOG_PRIORITY, ( TaskHandle_t * ) NULL); }
static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((void __user *)arg, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, (int __user *)arg); case WDIOC_SETOPTIONS: { int options; int retval = -EINVAL; if (get_user(options, (int __user *)arg)) return -EFAULT; if (options & WDIOS_DISABLECARD) { wdt_disable(); retval = 0; } if (options & WDIOS_ENABLECARD) { wdt_enable(); retval = 0; } return retval; } case WDIOC_KEEPALIVE: wdt_keepalive(); return 0; case WDIOC_SETTIMEOUT: { int new_timeout; if (get_user(new_timeout, (int __user *)arg)) return -EFAULT; if (wdt_set_timeout(new_timeout)) return -EINVAL; /* Fall through */ } case WDIOC_GETTIMEOUT: return put_user(timeout, (int __user *)arg); default: return -ENOTTY; } }
static int wdt_open(struct inode *inode, struct file *file) { /* Allow only one person to hold it open */ if (access) return -EBUSY; if (nowayout) __module_get(THIS_MODULE); /* Activate timer */ wdt_reset_counter(); wdt_set_timeout(); printk(KERN_INFO NAME ": enabling watchdog timer\n"); access = 1; return 0; }
int wdt_exit(uev_ctx_t *ctx) { /* Let plugins exit before we leave main loop */ wdt_plugins_exit(ctx); /* Be nice, sync any buffered data to disk first. */ sync(); if (fd != -1) { INFO("Forced watchdog reboot."); wdt_set_timeout(1); close(fd); } /* Tell main() to loop until reboot ... */ wait_reboot = 1; /* Leave main loop. */ return uev_exit(ctx); }
static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int new_timeout; static struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .firmware_version = 0, .identity = "ADM5120_WDT Watchdog", }; switch (cmd) { default: return -ENOTTY; 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: wdt_reset_counter(); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_timeout, (int *)arg)) return -EFAULT; if (new_timeout < 1) return -EINVAL; if (new_timeout > MAX_TIMEOUT) return -EINVAL; timeout = new_timeout; wdt_set_timeout(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timeout, (int *)arg); } } static const struct file_operations wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = wdt_write, .unlocked_ioctl = wdt_ioctl, .open = wdt_open, .release = wdt_release, }; static struct miscdevice wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &wdt_fops, }; static char banner[] __initdata = KERN_INFO NAME ": Watchdog Timer version " VERSION "\n"; static int __init watchdog_init(void) { int ret; ret = misc_register(&wdt_miscdev); if (ret) return ret; wdt_disable(); printk(banner); return 0; } static void __exit watchdog_exit(void) { misc_deregister(&wdt_miscdev); }
static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int status; int new_options, retval = -EINVAL; int new_timeout; union { struct watchdog_info __user *ident; int __user *i; } uarg; uarg.i = (int __user *)arg; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: wdt_get_status(&status); return put_user(status, uarg.i); case WDIOC_GETBOOTSTATUS: return put_user(0, uarg.i); case WDIOC_SETOPTIONS: if (get_user(new_options, uarg.i)) return -EFAULT; if (new_options & WDIOS_DISABLECARD) { wdt_stop(); retval = 0; } if (new_options & WDIOS_ENABLECARD) { wdt_start(); retval = 0; } return retval; case WDIOC_KEEPALIVE: wdt_keepalive(); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_timeout, uarg.i)) return -EFAULT; if (wdt_set_timeout(new_timeout)) return -EINVAL; wdt_keepalive(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timeout, uarg.i); default: return -ENOTTY; } }
/*============================================================================ * Hook to the ioctl file operation */ int vmiwdt_ioctl(struct inode *inode, struct file *file_ptr, uint32_t cmd, unsigned long arg) { int timeout, status = 0; static struct watchdog_info wdt_info = { .options = WDIOF_SETTIMEOUT, .firmware_version = 0, .identity = MOD_NAME }; switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user((void *) arg, &wdt_info, sizeof (wdt_info))) return -EFAULT; break; case WDIOC_GETSTATUS: if (copy_to_user((void *) arg, &status, sizeof (int))) return -EFAULT; break; case WDIOC_KEEPALIVE: wdt_keepalive(); break; case WDIOC_SETTIMEOUT: if (copy_from_user(&timeout, (void *) arg, sizeof (int))) return -EFAULT; /* The wdt_set_timeout function expects milliseconds */ timeout *= 1000; wdt_set_timeout(&timeout); timeout /= 1000; if (copy_to_user((void *) arg, &timeout, sizeof (int))) return -EFAULT; break; #ifdef WDIOC_SETTIMEOUT_MS case WDIOC_SETTIMEOUT_MS: #endif if (copy_from_user(&timeout, (void *) arg, sizeof (int))) return -EFAULT; wdt_set_timeout(&timeout); if (copy_to_user((void *) arg, &timeout, sizeof (int))) return -EFAULT; break; case WDIOC_GETTIMEOUT: /* The wdt_set_timeout function returns milliseconds */ timeout = wdt_get_timeout(); timeout /= 1000; if (copy_to_user((void *) arg, &timeout, sizeof (timeout))) return -EFAULT; break; #ifdef WDIOC_GETTIMEOUT_MS case WDIOC_GETTIMEOUT_MS: #endif timeout = wdt_get_timeout(); if (copy_to_user((void *) arg, &timeout, sizeof (timeout))) return -EFAULT; break; default: return -ENOTTY; } return 0; } /*============================================================================ * Hook for the open file operation */ static int vmiwdt_open(struct inode *inode, struct file *file_ptr) { #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) MOD_INC_USE_COUNT; #endif if (1 == ++vmiwdt_count) { wdt_enable(); } return 0; }
int main(int argc, char *argv[]) { int timeout = WDT_TIMEOUT_DEFAULT; int real_timeout = 0; int T; int background = 1; int use_syslog = 1; int c, status; int log_opts = LOG_NDELAY | LOG_NOWAIT | LOG_PID; struct option long_options[] = { {"load-average", 1, 0, 'a'}, {"foreground", 0, 0, 'n'}, {"help", 0, 0, 'h'}, {"interval", 1, 0, 't'}, {"loglevel", 1, 0, 'l'}, {"meminfo", 1, 0, 'm'}, {"filenr", 1, 0, 'f'}, {"pmon", 2, 0, 'p'}, {"safe-exit", 0, 0, 'e'}, {"syslog", 0, 0, 's'}, #ifndef TESTMODE_DISABLED {"test-mode", 0, 0, 'S'}, /* Hidden test mode, not for public use. */ #endif {"version", 0, 0, 'v'}, {"timeout", 1, 0, 'T'}, {NULL, 0, 0, 0} }; uev_ctx_t ctx; while ((c = getopt_long(argc, argv, "a:f:Fhl:Lm:np::sSt:T:Vvx?", long_options, NULL)) != EOF) { switch (c) { case 'a': if (loadavg_set(optarg)) return usage(1); break; case 'f': if (filenr_set(optarg)) return usage(1); break; case 'h': return usage(0); case 'l': loglevel = __wdog_loglevel(optarg); if (-1 == loglevel) return usage(1); break; case 'm': if (meminfo_set(optarg)) return usage(1); break; case 'F': /* BusyBox watchdogd compat. */ case 'n': /* Run in foreground */ background = 0; use_syslog--; break; case 'p': if (pmon_set(optarg)) return usage(1); break; case 's': use_syslog++; break; #ifndef TESTMODE_DISABLED case 'S': /* Simulate: no interaction with kernel, for testing pmon */ __wdt_testmode = 1; break; #endif case 't': /* Watchdog kick interval */ if (!optarg) { ERROR("Missing interval argument."); return usage(1); } period = atoi(optarg); break; case 'T': /* Watchdog timeout */ if (!optarg) { ERROR("Missing timeout argument."); return usage(1); } timeout = atoi(optarg); break; case 'v': printf("v%s\n", VERSION); return 0; case 'x': /* Safe exit, i.e., don't reboot if we exit and close device */ magic = 1; break; default: printf("Unrecognized option \"-%c\".\n", c); return usage(1); } } /* BusyBox watchdogd compat. */ if (optind < argc) { char *dev = argv[optind]; if (!strncmp(dev, "/dev", 4)) strlcpy(devnode, dev, sizeof(devnode)); } if (background) { DEBUG("Daemonizing ..."); if (-1 == daemon(0, 0)) { PERROR("Failed daemonizing"); return 1; } } if (!background && use_syslog < 1) log_opts |= LOG_PERROR; setlogmask(LOG_UPTO(loglevel)); openlog(NULL, log_opts, LOG_DAEMON); INFO("watchdogd v%s %s ...", PACKAGE_VERSION, wdt_testmode() ? "test mode" : "starting"); uev_init(&ctx); /* Setup callbacks for SIGUSR1 and, optionally, exit magic on SIGINT/SIGTERM */ setup_signals(&ctx); if (wdt_init()) { PERROR("Failed connecting to kernel watchdog driver"); return 1; } /* Set requested WDT timeout right before we enter the event loop. */ if (wdt_set_timeout(timeout)) PERROR("Failed setting HW watchdog timeout: %d", timeout); /* Sanity check with driver that setting actually took. */ real_timeout = wdt_get_timeout(); if (real_timeout < 0) { PERROR("Failed reading current watchdog timeout"); } else { if (real_timeout <= period) { ERROR("Warning, watchdog timeout <= kick interval: %d <= %d", real_timeout, period); } } /* If user did not provide '-k' argument, set to half actual timeout */ if (-1 == period) { if (real_timeout < 0) period = WDT_KICK_DEFAULT; else period = real_timeout / 2; if (!period) period = 1; } /* Calculate period (T) in milliseconds for libuEv */ T = period * 1000; DEBUG("Watchdog kick interval set to %d sec.", period); /* Read boot cause from watchdog and save in /var/run/watchdogd.status */ create_bootstatus(real_timeout, period); /* Every period (T) seconds we kick the wdt */ uev_timer_init(&ctx, &period_watcher, period_cb, NULL, T, T); /* Start all enabled plugins */ wdt_plugins_init(&ctx, T); /* Only create pidfile when we're done with all set up. */ if (pidfile(NULL) && !wdt_testmode()) PERROR("Cannot create pidfile"); status = uev_run(&ctx, 0); if (wdt_testmode()) return status; while (wait_reboot) { int reboot_in = 3 * real_timeout; INFO("Waiting for HW WDT reboot ..."); while (reboot_in > 0) { unsigned int rest = sleep(real_timeout); while (rest) rest = sleep(rest); reboot_in -= real_timeout; } INFO("HW WDT dit not reboot, forcing reboot now ..."); reboot(RB_AUTOBOOT); } return status; }