赞
踩
目录
1.3 __watchdog_register_device
1.4 最终misc_register注册watchdog_miscdev
3. 使用标准的内核框架wdt driver时,需要特别注意以下两点
版本:Linux 4.14
用到的文件:
kernel\watchdog.c
drivers\watchdog\dw_wdt.c
drivers\watchdog\watchdog_dev.c
drivers\watchdog\watchdog_core.c
wdt的驱动挺特别的,linux内核中也对它做了一个封装并归纳处理总结出了一个框架,分为以下三层:统一driver层(watchdog_dev),核心层(watchdog_core),具体的设备层(本文以dw wdt为例)。
在写wdt的时候会发现,和其他driver不同的是,不需要我们在自己的driver中去创建节点,我们只需要实现ops结构体成员即可,然后去调用wdt核心层的api注册ops即可。
其实,创建节点的工作在wdt的统一driver层已经实现了,这是因wdt设备在各个soc上是一个高度统一的设备,可以被高度抽象出来,查看代码watchdog_dev.c中就可以看到,这是一个标准的字符设备驱动,该文件中创建”dev/watchdog”节点,同时向上层提供了ioctl接口。
driver中的各个接口调用都是以函数指针的方式去调用,而这些函数指针在我们每个soc自己的巨头的wdt driver层去初始化然后注册。
drivers\watchdog\dw_wdt.c
- #ifdef CONFIG_OF
- static const struct of_device_id dw_wdt_of_match[] = {
- { .compatible = "snps,dw-wdt", },
- { /* sentinel */ }
- };
- MODULE_DEVICE_TABLE(of, dw_wdt_of_match);
- #endif
-
- static struct platform_driver dw_wdt_driver = {
- .probe = dw_wdt_drv_probe,
- .remove = dw_wdt_drv_remove,
- .driver = {
- .name = "dw_wdt",
- .of_match_table = of_match_ptr(dw_wdt_of_match),
- .pm = &dw_wdt_pm_ops,
- },
- };
设备树中比较compatible = "snps,dw-wdt",比较通过后调用dw_wdt_drv_probe函数。
- static int dw_wdt_drv_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct watchdog_device *wdd;
- struct dw_wdt *dw_wdt;
- struct resource *mem;
- int ret;
-
- dw_wdt = devm_kzalloc(dev, sizeof(*dw_wdt), GFP_KERNEL);
- if (!dw_wdt)
- return -ENOMEM;
-
- wdd->info = &dw_wdt_ident;
- wdd->ops = &dw_wdt_ops; //设置操作函数
- ........
-
- watchdog_set_nowayout(wdd, nowayout);
-
- ........
-
- platform_set_drvdata(pdev, dw_wdt);
-
- watchdog_set_restart_priority(wdd, 128);
-
- ret = watchdog_register_device(wdd);
- if (ret)
- goto out_disable_clk;
-
- return 0;
-
- out_disable_clk:
- clk_disable_unprepare(dw_wdt->clk);
- return ret;
- }
-
- static const struct watchdog_ops dw_wdt_ops = {
- .owner = THIS_MODULE,
- .start = dw_wdt_start,
- .stop = dw_wdt_stop,
- .ping = dw_wdt_ping,
- .set_timeout = dw_wdt_set_timeout,
- .get_timeleft = dw_wdt_get_timeleft,
- .restart = dw_wdt_restart,
- };
前面一些关于硬件、IO等的设置,这里不做介绍,注意wdt的fops就行。我们主要讲watchdog_register_device函数。
该函数drivers\watchdog\watchdog_core.c在这里面,如下:
- int watchdog_register_device(struct watchdog_device *wdd)
- {
- int ret;
-
- mutex_lock(&wtd_deferred_reg_mutex);
- if (wtd_deferred_reg_done)
- ret = __watchdog_register_device(wdd);
- else
- ret = watchdog_deferred_registration_add(wdd);
- mutex_unlock(&wtd_deferred_reg_mutex);
- return ret;
- }
wtd_deferred_reg_done全局变量已经定义了,所以走__watchdog_register_device分支。
- static int __init watchdog_deferred_registration(void)
- {
- mutex_lock(&wtd_deferred_reg_mutex);
- wtd_deferred_reg_done = true;
- while (!list_empty(&wtd_deferred_reg_list)) {
- struct watchdog_device *wdd;
-
- wdd = list_first_entry(&wtd_deferred_reg_list,
- struct watchdog_device, deferred);
- list_del(&wdd->deferred);
- __watchdog_register_device(wdd);
- }
- mutex_unlock(&wtd_deferred_reg_mutex);
- return 0;
- }
-
- static int __init watchdog_init(void)
- {
- int err;
-
- err = watchdog_dev_init();
- if (err < 0)
- return err;
-
- watchdog_deferred_registration();
- return 0;
- }
-
- subsys_initcall_sync(watchdog_init);
- static int __watchdog_register_device(struct watchdog_device *wdd)
- {
- int ret, id = -1;
- .......
-
- ret = watchdog_dev_register(wdd);
-
- ....
-
- return 0;
- }
其他不管,发现调用watchdog_dev_register。
- static int watchdog_cdev_register(struct watchdog_device *wdd)
- {
- struct watchdog_core_data *wd_data;
- int err;
-
- ......
-
- if (wdd->id == 0) {
- old_wd_data = wd_data;
- watchdog_miscdev.parent = wdd->parent;
- err = misc_register(&watchdog_miscdev);
- if (err != 0) {
- pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
- wdd->info->identity, WATCHDOG_MINOR, err);
- if (err == -EBUSY)
- pr_err("%s: a legacy watchdog module is probably present.\n",
- wdd->info->identity);
- old_wd_data = NULL;
- kfree(wd_data);
- return err;
- }
- }
-
- .......
- return 0;
- }
发现最终注册了一个混杂设备watchdog_miscdev,其定义如下。
- static const struct file_operations watchdog_fops = {
- .owner = THIS_MODULE,
- .write = watchdog_write,
- .unlocked_ioctl = watchdog_ioctl,
- .open = watchdog_open,
- .release = watchdog_release,
- };
-
- static struct miscdevice watchdog_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &watchdog_fops,
- };
- /*
- * watchdog_open: open the /dev/watchdog* devices.
- * @inode: inode of device
- * @file: file handle to device
- *
- * When the /dev/watchdog* device gets opened, we start the watchdog.
- * Watch out: the /dev/watchdog device is single open, so we make sure
- * it can only be opened once.
- */
- static int watchdog_open(struct inode *inode, struct file *file)
- {
- struct watchdog_core_data *wd_data;
- struct watchdog_device *wdd;
- bool hw_running;
- int err;
-
- ......
-
- err = watchdog_start(wdd);
- if (err < 0)
- goto out_mod;
-
- ......
- }
当打开open("/dev/watchdog")时,最终调用watchdog_open,可以看出最终调用了watchdog_start。
- /*
- * watchdog_start: wrapper to start the watchdog.
- * @wdd: the watchdog device to start
- *
- * The caller must hold wd_data->lock.
- *
- * Start the watchdog if it is not active and mark it active.
- * This function returns zero on success or a negative errno code for
- * failure.
- */
-
- static int watchdog_start(struct watchdog_device *wdd)
- {
- struct watchdog_core_data *wd_data = wdd->wd_data;
- unsigned long started_at;
- int err;
-
- .....
- set_bit(_WDOG_KEEPALIVE, &wd_data->status);
-
- started_at = jiffies;
- if (watchdog_hw_running(wdd) && wdd->ops->ping)
- err = wdd->ops->ping(wdd);
- else
- err = wdd->ops->start(wdd);
- .....
-
- return err;
- }
查看watchdog_start源码可知,最终调用了wdt fops中的start函数。
- /*
- * watchdog_write: writes to the watchdog.
- * @file: file from VFS
- * @data: user address of data
- * @len: length of data
- * @ppos: pointer to the file offset
- *
- * A write to a watchdog device is defined as a keepalive ping.
- * Writing the magic 'V' sequence allows the next close to turn
- * off the watchdog (if 'nowayout' is not set).
- */
-
- static ssize_t watchdog_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
- {
- struct watchdog_core_data *wd_data = file->private_data;
- struct watchdog_device *wdd;
- int err;
- size_t i;
- char c;
-
- if (len == 0)
- return 0;
-
- /*
- * Note: just in case someone wrote the magic character
- * five months ago...
- */
- clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
-
- /* scan to see whether or not we got the magic character */
- for (i = 0; i != len; i++) {
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
- }
-
- /* someone wrote to us, so we send the watchdog a keepalive ping */
-
- err = -ENODEV;
- mutex_lock(&wd_data->lock);
- wdd = wd_data->wdd;
- if (wdd)
- err = watchdog_ping(wdd);
- mutex_unlock(&wd_data->lock);
-
- if (err < 0)
- return err;
-
- return len;
- }
这里的写有一个特殊操作,如果向wdt节点写“V”字符时,则会置位标志为_WDOG_ALLOW_RELEASE,即允许release,当上层去close节点的时候会callback到这一层的release接口,release会去判断_WDOG_ALLOW_RELEASE,如果不被置位则不执行watchdog_stop,即虽然上层关掉了fd,但是底层实际没有执行stop的操作。如果被置位,就执行watchdog_stop,按照上面的分析,watchdog_stop又会判断NOWAYOUT是否被置位。即想要关闭wdt,首先需要disable _WDOG_ALLOW_RELEASE,即去掉该选项。即在close节点前向节点写“V”,然后再clsoe,这样才可以正真调用到具体driver的stop接口
- /*
- * watchdog_release: release the watchdog device.
- * @inode: inode of device
- * @file: file handle to device
- *
- * This is the code for when /dev/watchdog gets closed. We will only
- * stop the watchdog when we have received the magic char (and nowayout
- * was not set), else the watchdog will keep running.
- */
-
- static int watchdog_release(struct inode *inode, struct file *file)
- {
- struct watchdog_core_data *wd_data = file->private_data;
- struct watchdog_device *wdd;
- int err = -EBUSY;
- bool running;
- ......
-
- /*
- * We only stop the watchdog if we received the magic character
- * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
- * watchdog_stop will fail.
- */
- if (!test_bit(WDOG_ACTIVE, &wdd->status))
- err = 0;
- else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) ||
- !(wdd->info->options & WDIOF_MAGICCLOSE))
- err = watchdog_stop(wdd);
-
- /* If the watchdog was not stopped, send a keepalive ping */
- if (err < 0) {
- pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id);
- watchdog_ping(wdd);
- }
-
- watchdog_update_worker(wdd);
-
- /* make sure that /dev/watchdog can be re-opened */
- clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
- ......
- return 0;
- }
release 接口,上层做close的时候会调用到。release会去判断_WDOG_ALLOW_RELEASE,而这个标志在write函数中会被置位,(向节点写“V”操作)。如果不被置位则不执行watchdog_stop即虽然上层关掉了fd,但是底层实际没有执行stop的操作。如果被置位,就执行watchdog_stop,按照上面的分析,watchdog_stop又会判断NOWAYOUT是否被置位。即想要关闭wdt,首先需要disable _WDOG_ALLOW_RELEASE,即去掉该选项。然后在close节点前向节点写“V”,然后再clsoe,这样才可以正真调用到具体driver的stop接口。
- /*
- * watchdog_stop: wrapper to stop the watchdog.
- * @wdd: the watchdog device to stop
- *
- * The caller must hold wd_data->lock.
- *
- * Stop the watchdog if it is still active and unmark it active.
- * This function returns zero on success or a negative errno code for
- * failure.
- * If the 'nowayout' feature was set, the watchdog cannot be stopped.
- */
-
- static int watchdog_stop(struct watchdog_device *wdd)
- {
- int err = 0;
-
- if (!watchdog_active(wdd))
- return 0;
-
- if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
- pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n",
- wdd->id);
- return -EBUSY;
- }
-
- if (wdd->ops->stop) {
- clear_bit(WDOG_HW_RUNNING, &wdd->status);
- err = wdd->ops->stop(wdd);
- } else {
- set_bit(WDOG_HW_RUNNING, &wdd->status);
- }
-
- if (err == 0) {
- clear_bit(WDOG_ACTIVE, &wdd->status);
- watchdog_update_worker(wdd);
- }
-
- return err;
- }
WDOG_NO_WAY_OUT,这里有个特殊的一点是上层调用进这个接口想关闭wdt即终止计数功能时,这里会判断status是否被设置为WDOG_NO_WAY_OUT状态,如果设置了,则直接返回不去调用实际driver中的stop函数。也就是说当NOWAYOUT被配置后,无论上层是close wdt节点还是调用统一层stop接口,wdt都是不会关掉的,会一直计数下去,如果不持续喂狗就会reset。
- static bool nowayout = WATCHDOG_NOWAYOUT;
- #define WATCHDOG_NOWAYOUT IS_BUILTIN(CONFIG_WATCHDOG_NOWAYOUT)
- /* Use the following function to set the nowayout feature */
- static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout)
- {
- if (nowayout)
- set_bit(WDOG_NO_WAY_OUT, &wdd->status);
- }
由上可以看出如果配置了CONFIG_WATCHDOG_NOWAYOUT项,则watchdog_set_nowayout在dw_wdt_drv_probe就会被执行,WDOG_NO_WAY_OUT状态就会被置起来,当上层通过ioctl调用了wdt同一层的stop接口时,则直接返回。
- /*
- * watchdog_set_timeout: set the watchdog timer timeout
- * @wdd: the watchdog device to set the timeout for
- * @timeout: timeout to set in seconds
- *
- * The caller must hold wd_data->lock.
- */
-
- static int watchdog_set_timeout(struct watchdog_device *wdd,
- unsigned int timeout)
- {
- int err = 0;
-
- if (!(wdd->info->options & WDIOF_SETTIMEOUT))
- return -EOPNOTSUPP;
-
- if (watchdog_timeout_invalid(wdd, timeout))
- return -EINVAL;
-
- if (wdd->ops->set_timeout) {
- err = wdd->ops->set_timeout(wdd, timeout);
- } else {
- wdd->timeout = timeout;
- /* Disable pretimeout if it doesn't fit the new timeout */
- if (wdd->pretimeout >= wdd->timeout)
- wdd->pretimeout = 0;
- }
- watchdog_update_worker(wdd);
- return err;
- }
设置超时时间,一般正常喂狗会下发一个时间,如果上层想主动重启,只需设置时间为0,当然实际的底层driver需要对时间做判断,当时间为0时,就重启系统。
- /*
- * watchdog_ping: ping the watchdog.
- * @wdd: the watchdog device to ping
- *
- * The caller must hold wd_data->lock.
- *
- * If the watchdog has no own ping operation then it needs to be
- * restarted via the start operation. This wrapper function does
- * exactly that.
- * We only ping when the watchdog device is running.
- */
-
- static int watchdog_ping(struct watchdog_device *wdd)
- {
- struct watchdog_core_data *wd_data = wdd->wd_data;
-
- if (!watchdog_active(wdd) && !watchdog_hw_running(wdd))
- return 0;
-
- set_bit(_WDOG_KEEPALIVE, &wd_data->status);
-
- wd_data->last_keepalive = jiffies;
- return __watchdog_ping(wdd);
- }
-
- static int __watchdog_ping(struct watchdog_device *wdd)
- {
- struct watchdog_core_data *wd_data = wdd->wd_data;
- unsigned long earliest_keepalive = wd_data->last_hw_keepalive +
- msecs_to_jiffies(wdd->min_hw_heartbeat_ms);
- int err;
-
- if (time_is_after_jiffies(earliest_keepalive)) {
- mod_delayed_work(watchdog_wq, &wd_data->work,
- earliest_keepalive - jiffies);
- return 0;
- }
-
- wd_data->last_hw_keepalive = jiffies;
-
- if (wdd->ops->ping)
- err = wdd->ops->ping(wdd); /* ping the watchdog */
- else
- err = wdd->ops->start(wdd); /* restart watchdog */
-
- watchdog_update_worker(wdd);
-
- return err;
- }
- /*
- * watchdog_ioctl: handle the different ioctl's for the watchdog device.
- * @file: file handle to the device
- * @cmd: watchdog command
- * @arg: argument pointer
- *
- * The watchdog API defines a common set of functions for all watchdogs
- * according to their available features.
- */
-
- static long watchdog_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
- {
- struct watchdog_core_data *wd_data = file->private_data;
- void __user *argp = (void __user *)arg;
- struct watchdog_device *wdd;
- int __user *p = argp;
- unsigned int val;
- int err;
-
- mutex_lock(&wd_data->lock);
-
- wdd = wd_data->wdd;
- if (!wdd) {
- err = -ENODEV;
- goto out_ioctl;
- }
-
- err = watchdog_ioctl_op(wdd, cmd, arg);
- if (err != -ENOIOCTLCMD)
- goto out_ioctl;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- err = copy_to_user(argp, wdd->info,
- sizeof(struct watchdog_info)) ? -EFAULT : 0;
- break;
- case WDIOC_GETSTATUS:
- val = watchdog_get_status(wdd);
- err = put_user(val, p);
- break;
- case WDIOC_GETBOOTSTATUS:
- err = put_user(wdd->bootstatus, p);
- break;
- case WDIOC_SETOPTIONS:
- if (get_user(val, p)) {
- err = -EFAULT;
- break;
- }
- if (val & WDIOS_DISABLECARD) {
- err = watchdog_stop(wdd);
- if (err < 0)
- break;
- }
- if (val & WDIOS_ENABLECARD)
- err = watchdog_start(wdd);
- break;
- case WDIOC_KEEPALIVE:
- if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) {
- err = -EOPNOTSUPP;
- break;
- }
- err = watchdog_ping(wdd);
- break;
- case WDIOC_SETTIMEOUT:
- if (get_user(val, p)) {
- err = -EFAULT;
- break;
- }
- err = watchdog_set_timeout(wdd, val);
- if (err < 0)
- break;
- /* If the watchdog is active then we send a keepalive ping
- * to make sure that the watchdog keep's running (and if
- * possible that it takes the new timeout) */
- err = watchdog_ping(wdd);
- if (err < 0)
- break;
- /* Fall */
- case WDIOC_GETTIMEOUT:
- /* timeout == 0 means that we don't know the timeout */
- if (wdd->timeout == 0) {
- err = -EOPNOTSUPP;
- break;
- }
- err = put_user(wdd->timeout, p);
- break;
- case WDIOC_GETTIMELEFT:
- err = watchdog_get_timeleft(wdd, &val);
- if (err < 0)
- break;
- err = put_user(val, p);
- break;
- case WDIOC_SETPRETIMEOUT:
- if (get_user(val, p)) {
- err = -EFAULT;
- break;
- }
- err = watchdog_set_pretimeout(wdd, val);
- break;
- case WDIOC_GETPRETIMEOUT:
- err = put_user(wdd->pretimeout, p);
- break;
- default:
- err = -ENOTTY;
- break;
- }
-
- out_ioctl:
- mutex_unlock(&wd_data->lock);
- return err;
- }
有的时候我们希望看门狗不被停止,即上层的任何关狗的动作都不予支持,此时就可以使用NOWAYOUT功能,接配置内核的标准配置项:CONFIG_WATCHDOG_NOWAYOUT
使能该项后,要为我们的driver所用需要在具体的wdt driver中对该配置进行支持,即调用watchdog_set_nowayout()去设置WDOG_NO_WAY_OUT:
- static bool nowayout = WATCHDOG_NOWAYOUT;
- #define WATCHDOG_NOWAYOUT IS_BUILTIN(CONFIG_WATCHDOG_NOWAYOUT)
- /* Use the following function to set the nowayout feature */
- static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout)
- {
- if (nowayout)
- set_bit(WDOG_NO_WAY_OUT, &wdd->status);
- }
配置后会去执行set_bit(WDOG_NO_WAY_OUT, &wdd->status);置位WDOG_NO_WAY_OUT。在上层调用统一driver层IOCTL去调用watchdog_stop()时,watchdog_stop会去判断是否WDOG_NO_WAY_OUT被置位,如果设置了,则直接返回不去调用实际driver中的stop函数
这样就可以屏蔽所有关wdt的动作,这个操作仍然在统一设备层,具体的wdt driver不用管这个
有的时候我们想停掉狗,不想然他reset,如果系统使用了标准的wdt框架,则需要magic close的支持。
magic close即向wdt节点写字符“V”向wdt节点写“V”字符时,被调用到的接口watchdog_write()会置位标志为_WDOG_ALLOW_RELEASE。当上层close节点时,会调用标准的wdt统一driver层的release接口,release会去判断_WDOG_ALLOW_RELEASE,如果不被置位则不执行watchdog_stop即虽然上层关掉了fd,但是底层实际没有执行stop的操作。如果被置位,就执行watchdog_stop,按照上面的分析,watchdog_stop又会判断NOWAYOUT是否被置位。
所以想要关闭wdt rest功能结束其计数,首先需要disable _WDOG_ALLOW_RELEASE,即去掉该选项。然后在close节点前向节点写“V”,然后再clsoe,这样才可以正真调用到具体driver的stop接口。
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <pthread.h>
- #include <sys/ioctl.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/time.h>
- #include <unistd.h>
- #include <time.h>
- #include <getopt.h>
- #include <sys/signal.h>
-
- //watchdog
- #define WATCHDOG_IOCTL_BASE 'W'
-
- struct watchdog_info {
- unsigned int options; /* Options the card/driver supports */
- unsigned int firmware_version; /* Firmware version of the card */
- char identity[32]; /* Identity of the board */
- };
-
- #define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
- #define WDIOC_GETSTATUS _IOR(WATCHDOG_IOCTL_BASE, 1, int)
- #define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
- #define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int)
- #define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
- #define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
- #define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
- #define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int)
- #define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
- #define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
- #define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
-
- #define WDIOF_OVERHEAT 0x0001 /* Reset due to CPU overheat */
- #define WDIOF_FANFAULT 0x0002 /* Fan failed */
- #define WDIOF_EXTERN1 0x0004 /* External relay 1 */
- #define WDIOF_EXTERN2 0x0008 /* External relay 2 */
- #define WDIOF_POWERUNDER 0x0010 /* Power bad/power fault */
- #define WDIOF_CARDRESET 0x0020 /* Card previously reset the CPU */
- #define WDIOF_POWEROVER 0x0040 /* Power over voltage */
- #define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */
- #define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */
- #define WDIOF_PRETIMEOUT 0x0200 /* Pretimeout (in seconds), get/set */
- #define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */
-
- #define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */
- #define WDIOS_ENABLECARD 0x0002 /* Turn on the watchdog timer */
- #define WDIOS_TEMPPANIC 0x0004 /* Kernel panic on temperature trip */
-
- int wdt_fd;
- int time_out = 5;
- #define DEFAULT_PING_RATE 1
- void stop_signal()
- {
- int val = 0 , ret = 0 ;
-
- val = WDIOS_DISABLECARD ;
- ret = ioctl(wdt_fd, WDIOC_SETOPTIONS, &val) ;
- if (ret < 0)
- printf("ioctl WDIOC_GETSUPPORT failed with %d.\n", ret);
-
- printf("===watchdow will be closed===\n") ;
- close(wdt_fd) ;
- exit(0);
-
- }
-
- int main(int argc, char *argv[])
- {
- int ret;
- static int count = 0;
- struct watchdog_info wdt_info;
- unsigned int ping_rate = DEFAULT_PING_RATE;
-
- signal(SIGINT, stop_signal) ;
-
- wdt_fd = open("/dev/watchdog0", O_RDWR);
- if(wdt_fd < 0)
- {
- printf("open /dev/watchdog0 failed.\n");
- }
-
- /* get watchdog infomation struct */
- ret = ioctl(wdt_fd, WDIOC_GETSUPPORT, &wdt_info);
- if (ret < 0)
- printf("ioctl WDIOC_GETSUPPORT failed.\n");
- else
- {
- printf("options = 0x%x,id = %s\n", wdt_info.options, wdt_info.identity);
- }
-
- ioctl(wdt_fd, WDIOC_SETTIMEOUT, &time_out);
- if (ret < 0)
- printf("ioctl WDIOC_SETTIMEOUT failed.\n");
-
- while(1)
- {
-
- if(count > 10)
- {
- printf("unfood watchdog, count = %d \n",count++);
- }
- else
- {
- ioctl(wdt_fd,WDIOC_KEEPALIVE,NULL);
- printf("food watchdog, count = %d \n",count++);
- }
- sleep(DEFAULT_PING_RATE);
- }
-
- close(wdt_fd);
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。