Hi Marc, > > Coming back to now: if the driver incorporates the timer (like all other > > devices that can be started but not stopped once started do), then the start > > and stop functions are not empty. > > The timer (with the example that I prepared as part of the generic code) is > > not so difficult and will be a good solution for the time being. (Unless > > Dmitry Artamonow's comment about the fact that the watchdog could perhaps > > be started and stopped is correct... This should be investigated first imho). > > > The watchdog can not be started and stopped from the driver. This is > what I investigated first and found impossible (and explains why this > driver is still missing). > > I do not fully understand yet what has to be done with the timer. Below the example driver that should get included in the Documentation. Kind regards, Wim. -------------------------------------------------------------------------------- /* * Watchdog timer driver example with timer. * * Copyright (C) 2009-2011 Wim Van Sebroeck <wim@xxxxxxxxx> * * 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. */ /* * Some watchdog device can't stop once started. To support * the magic_close feature we therefor need to use an internal * timer to keep the watchdog being pinged when /dev/watchdog has * been closed correctly. * * This is an example driver for these kind of watchdog devices. */ #define DRV_NAME KBUILD_MODNAME #define pr_fmt(fmt) DRV_NAME ": " fmt #include <linux/init.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/watchdog.h> #include <linux/jiffies.h> #include <linux/timer.h> #include <linux/platform_device.h> /* Hardware heartbeat in seconds */ #define WDT_HW_HEARTBEAT 2 /* Timer heartbeat (500ms) */ #define WDT_HEARTBEAT (HZ/2) /* should be <= ((WDT_HW_HEARTBEAT*HZ)/2) */ /* User land timeout */ #define WDT_TIMEOUT 15 static int timeout = WDT_TIMEOUT; module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. " "(default = " __MODULE_STRING(WDT_TIMEOUT) ")"); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started. " "(default = " __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static struct watchdog_device wdt_dev; static void wdt_timer_tick(unsigned long data); static DEFINE_TIMER(timer, wdt_timer_tick, 0, 0); /* The timer that pings the watchdog */ static unsigned long next_heartbeat; /* the next_heartbeat for the timer */ static unsigned long running; /* is watchdog running for userspace? */ static struct platform_device *wdt_platform_device; /* * Reset the watchdog timer. (ie, pat the watchdog) */ static inline void wdt_reset(void) { /* Reset the watchdog timer hardware here */ } /* * Timer tick: the timer will make sure that the watchdog timer hardware * is being reset in time. The conditions to do this are: * 1) the watchog timer has been started and /dev/watchdog is open * and there is still time left before userspace should send the * next heartbeat/ping. (note: the internal heartbeat is much smaller * then the external/userspace heartbeat). * 2) the watchdog timer has been stopped by userspace. */ static void wdt_timer_tick(unsigned long data) { if (time_before(jiffies, next_heartbeat) || (!test_bit(WDOG_ACTIVE, &wdt_dev.status))) { wdt_reset(); mod_timer(&timer, jiffies + WDT_HEARTBEAT); } else pr_crit("I will reboot your machine !\n"); } /* * The watchdog operations */ static int wdt_ping(struct watchdog_device *wdd) { /* calculate when the next userspace timeout will be */ next_heartbeat = jiffies + timeout * HZ; return 0; } static int wdt_start(struct watchdog_device *wdd) { /* calculate the next userspace timeout and modify the timer */ wdt_ping(wdd); mod_timer(&timer, jiffies + WDT_HEARTBEAT); /* Start the watchdog timer hardware here */ pr_info("wdt_start\n"); running = 1; return 0; } static int wdt_stop(struct watchdog_device *wdd) { /* The watchdog timer hardware can not be stopped... */ pr_info("wdt_stop\n"); running = 0; return 0; } static unsigned int wdt_status(struct watchdog_device *wdd) { return WDIOF_FANFAULT; } static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout) { if (new_timeout < 1) return -EINVAL; return 0; } /* * The watchdog kernel structures */ static const struct watchdog_info wdt_info = { .identity = DRV_NAME, .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, }; static const struct watchdog_ops wdt_ops = { .owner = THIS_MODULE, .start = wdt_start, .stop = wdt_stop, .ping = wdt_ping, .status = wdt_status, .set_timeout = wdt_set_timeout, }; static struct watchdog_device wdt_dev = { .info = &wdt_info, .ops = &wdt_ops, }; /* * The watchdog timer drivers init and exit routines */ static int __devinit wdt_probe(struct platform_device *pdev) { int res; /* Register other stuff */ /* Set watchdog_device parameters */ wdt_dev.timeout = timeout; /* wdt_dev.dev.parent = &pdev->dev;*/ if (nowayout) set_bit(WDOG_NO_WAY_OUT, &wdt_dev.status); /* Register the watchdog timer device */ res = watchdog_register_device(&wdt_dev); if (res) { pr_err("watchdog_register_device returned %d\n", res); return res; } pr_info("enabled (timeout=%d sec)\n", timeout); return 0; } static int __devexit wdt_remove(struct platform_device *pdev) { /* Unregister the watchdog timer device */ watchdog_unregister_device(&wdt_dev); /* stop and delete the timer */ pr_warn("I quit now, hardware will probably reboot!\n"); del_timer(&timer); /* Unregister other stuff */ return 0; } static struct platform_driver wdt_driver = { .probe = wdt_probe, .remove = __devexit_p(wdt_remove), .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, }; static int __init wdt_init(void) { int err; pr_info("WDT driver initialising.\n"); err = platform_driver_register(&wdt_driver); if (err) return err; wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); if (IS_ERR(wdt_platform_device)) { err = PTR_ERR(wdt_platform_device); goto unreg_platform_driver; } return 0; unreg_platform_driver: platform_driver_unregister(&wdt_driver); return err; } static void __exit wdt_exit(void) { platform_device_unregister(wdt_platform_device); platform_driver_unregister(&wdt_driver); pr_info("Watchdog Module Unloaded.\n"); } module_init(wdt_init); module_exit(wdt_exit); MODULE_AUTHOR("Wim Van Sebroeck <wim@xxxxxxxxx>"); MODULE_DESCRIPTION("WatchDog Timer Driver example with timer"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html