一、看门狗模块介绍
1.1、计数器介绍
本文使用的WDT内部包含一个32位计数器。WDT运行时计数器递减计数。可配置当计数器减为0时WDT发出超时中断还是直接系统复位。发出超时中断后WDT等待中断处理的时间长度可配置,超过等待中断处理的时间还没有重启计数器则系统复位。支持暂停功能。
1.2、计数频率介绍
可以通过配置寄存器实现设置计数器的计数频率,每1个pclk_wdt计数一次、每2个pclk_wdt、4个pclk_wdt、8个pclk_wdt计数一次,最高支持每 32768 个 pclk_wdt 周期计数一次。
1.3、喂狗操作介绍
用户发起的“喂狗”操作(写0x76至WDT_CRR寄存器)可以重启 WDT,并自动重载计数器值(重载值由WDT_TORR的TOP位设置),开始新一轮的定时操作。“喂狗”操作也可以清除WDT超时中断。
二、驱动程序分析
2.1、模块加载函数
在这里我们把看门狗设备作为一个平台设备,首先看下模块加载函数:
- static int __init watchdog_init(void)
- {
- return platform_driver_register(&gsc3280wdt_driver);
- }
- static void __exit watchdog_exit(void)
- {
- platform_driver_unregister(&gsc3280wdt_driver);
- }
- module_init(watchdog_init);
- module_exit(watchdog_exit);
在这里涉及到一个平台驱动gsc3280wdt_driver,其具体内容如下:
- static struct platform_driver gsc3280wdt_driver = {
- .probe = gsc3280wdt_probe,
- .remove = __devexit_p(gsc3280wdt_remove),
- .shutdown = gsc3280wdt_shutdown,
- .suspend = gsc3280wdt_suspend,
- .resume = gsc3280wdt_resume,
- .driver = {
- .owner = THIS_MODULE,
- .name = "gsc3280_watchdog",
- },
- };
看门狗的平台驱动结构体中定义了很多函数,包括探测函数、移除函数、挂起和恢复函数,接下来我们一一分析。
2.2、探测、移除、关闭、挂起和恢复函数
2.2.1、探测(gsc3280wdt_probe)函数
探测函数是平台驱动中最重要的,我们首先来分析它,在分析探测函数之前,先看下看门狗驱动的结构体,如下:
- struct gsc3280_wdt {
- struct device *dev;
- char name[20]; //看门狗名字
- spinlock_t wdt_lock;
- unsigned long open_lock; //位控制锁
- struct resource *wdt_mem;
- struct resource *wdt_irq;
- void __iomem *wdt_base;
- struct clk *wdt_clock; //看门狗时钟
- struct list_head device_entry; //list链表,在open函数中找到注册的看门狗结构体
- //set parameter
- //寄存器参数,在挂起函数中保存,在恢复函数中使用
- unsigned int wdt_cr;
- unsigned int torr;
- unsigned int pclkOne;
- };
看门狗驱动的探测函数如下:
- static int __devinit gsc3280wdt_probe(struct platform_device *pdev)
- {
- int ret = 0, size = 0;
- unsigned long rate = 0;
- struct gsc3280_wdt *wdt;
-
- printk(KERN_INFO "######gsc3280 watchdog probe start######\n");
- wdt = kzalloc(sizeof(struct gsc3280_wdt), GFP_KERNEL); //看门狗驱动结构体
- if (!wdt) {
- DBG("ERROR:no memory for state\n");
- return -ENOMEM;
- }
- /* Initialize the driver data */
- wdt->dev = &pdev->dev;
- strlcpy(wdt->name, GSC3280_WDT_NAME, sizeof(wdt->name));
- spin_lock_init(&wdt->wdt_lock);
- INIT_LIST_HEAD(&wdt->device_entry);
- /* get the memory region for the watchdog timer */
- wdt->wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (wdt->wdt_mem == NULL) {
- DBG("ERROR:no memory resource specified\n");
- ret = -ENOENT;
- goto free;
- }
- size = resource_size(wdt->wdt_mem);
- if (!request_mem_region(wdt->wdt_mem->start, size, pdev->name)) {
- DBG("ERROR:failed to get memory region\n");
- ret = -EBUSY;
- goto free;
- }
- wdt->wdt_base = ioremap(wdt->wdt_mem->start, size);
- if (wdt->wdt_base == NULL) {
- DBG("ERROR:failed to ioremap() region\n");
- ret = -EINVAL;
- goto err_req;
- }
-
- DBG("probe: mapped wdt_base=%p\n", wdt->wdt_base);
- wdt->wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //申请中断
- if (wdt->wdt_irq == NULL) {
- DBG("ERROR:no irq resource specified\n");
- ret = -ENOENT;
- goto err_map;
- }
- ret = request_irq(wdt->wdt_irq->start, gsc3280wdt_irq, 0, pdev->name, wdt);
- if (ret != 0) {
- DBG("ERROR:failed to install irq (%d)\n", ret);
- goto err_map;
- }
-
- wdt->wdt_clock = clk_get(NULL, "wdt"); //申请时钟
- if (IS_ERR(wdt->wdt_clock)) {
- DBG("ERROR:failed to find watchdog clock source\n");
- ret = PTR_ERR(wdt->wdt_clock);
- goto err_irq;
- }
- rate = clk_get_rate(wdt->wdt_clock);
- DBG("rate is %ld\n", rate);
- clk_enable(wdt->wdt_clock); //使能时钟
- ret = misc_register (&gsc3280wdt_miscdev);
- if(ret < 0) {
- DBG("ERROR:misc register watchdog error\n");
- goto err_clk;
- }
- mutex_lock(&wdt_device_list_lock);
- list_add(&wdt->device_entry, &wdt_device_list);
- mutex_unlock(&wdt_device_list_lock);
- platform_set_drvdata(pdev, wdt); //保存到pdev的私有数据成员中
- printk(KERN_INFO "######gsc3280 watchdog probe success######\n");
- return ret;
-
- err_clk:
- clk_disable(wdt->wdt_clock);
- clk_put(wdt->wdt_clock);
- err_irq:
- free_irq(wdt->wdt_irq->start, pdev);
- err_map:
- iounmap(wdt->wdt_base);
- err_req:
- release_mem_region(wdt->wdt_mem->start, size);
- wdt->wdt_mem = NULL;
- free:
- kfree(wdt);
-
- printk(KERN_INFO "!!!!!!gsc3280 watchdog probe err!!!!!!\n");
- return ret;
- }
静态全局链表和互斥锁:
- static LIST_HEAD(wdt_device_list);
- static DEFINE_MUTEX(wdt_device_list_lock);
探测函数gsc3280wdt_probe说明:
1、gsc3280_wdt结构体是本文看门狗所使用的一些资源,类似于i2c总线驱动中的i2c_adapter,具体作用在接下来会一一讲述。
2、探测函数首先申请了gsc3280_wdt结构体内存,然后对其内容进行了初始化。
3、探测函数进行了资源申请、IO口映射和中断申请等操作。
4、为了方便,本文将看门狗注册为混杂设备,混杂设备的具体特性可参考网络。看门狗混杂设备结构体gsc3280wdt_miscdev定义了本文所支持的操作,包括read、write和io_ctl等,2.3中会重点讲述。
5、本文件开头定义了一个静态全局的链表和互斥锁,程序如上所示,在探测函数的最后,使用语句list_add(&wdt->device_entry, &wdt_device_list);将结构体类型为gsc3280_wdt的wdt中的成员device_entry链接进全局链表wdt_device_list,在file_operations的open函数中,可以通过遍历链表wdt_device_list来寻找结构体wdt。互斥锁wdt_device_list_lock实现对链表wdt_device_list的互斥访问。
6、最后使用platform_set_drvdata(pdev, wdt);将wdt保存到pdev的私有数据成员中,在移除、挂起和恢复等函数中使用。
2.2.2、移除函数gsc3280wdt_remove
代码如下:
- static int __devexit gsc3280wdt_remove(struct platform_device *dev)
- {
- struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
-
- misc_deregister(&gsc3280wdt_miscdev);
- clk_disable(wdt->wdt_clock);
- clk_put(wdt->wdt_clock);
- wdt->wdt_clock = NULL;
- free_irq(wdt->wdt_irq->start, dev);
- wdt->wdt_irq = NULL;
- iounmap(wdt->wdt_base);
- release_mem_region(wdt->wdt_mem->start, resource_size(wdt->wdt_mem));
- wdt->wdt_mem = NULL;
- kfree(wdt);
- printk(KERN_INFO "######gsc3280 remove ok######\n");
- return 0;
- }
说明:
1、platform_get_drvdata(dev);函数就是从dev中的私有结构体中取得wdt,对应探测函数中的platform_set_drvdata(pdev, wdt);。
2、接下来的程序就比较简单,基本是探测函数的相反--对资源的释放。
2.2.3、关闭函数gsc3280wdt_shutdown
具体代码如下:
- static void gsc3280wdt_shutdown(struct platform_device *dev)
- {
- struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
-
- gsc3280wdt_stop(wdt);
- printk(KERN_INFO "######gsc3280 shutdown ok######\n");
- }
从程序中可以看出,主要就是看门狗的关闭函数,看门狗关闭函数gsc3280wdt_stop如下:
- static void gsc3280wdt_stop(struct gsc3280_wdt *wdt)
- {
- unsigned int tmp_value = 0;
-
- spin_lock(&wdt->wdt_lock);
- tmp_value = readl(GSC3280_WDT_SYS_CFG);
- writel(tmp_value | GSC3280_WDT_SYS_CFG_PAUSE, GSC3280_WDT_SYS_CFG);
- spin_unlock(&wdt->wdt_lock);
- }
从看门狗关闭函数中可以看出,首先上自旋锁,然后操作寄存器,将相应位置1,停止看门狗,最后释放自旋锁。
2.2.4、挂起函数gsc3280wdt_suspend
如果Linux内核支持电源管理,则挂起和恢复函数起作用。挂起函数代码如下:
- static int gsc3280wdt_suspend(struct platform_device *dev, pm_message_t state)
- {
- struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
-
- spin_lock(&wdt->wdt_lock);
- /* Save watchdog state, and turn it off. */
- wdt->pclkOne = readl(GSC3280_WDT_SYS_CFG) & 0x0f;
- wdt->torr = readl(wdt->wdt_base + WDT_TORR) & 0x0000ffff;
- wdt->wdt_cr = readl(wdt->wdt_base + WDT_CR);
- spin_unlock(&wdt->wdt_lock);
- /* Note that WTCNT doesn't need to be saved. */
- gsc3280wdt_stop(wdt);
- return 0;
- }
说明:
1、挂起函数主要完成在挂起前对变量的保存,上面主要完成对主要寄存器值的保存,以便在恢复函数中使用。
2、接下来就是暂停看门狗。
2.2.5、恢复函数gsc3280wdt_resume
代码如下:
- static int gsc3280wdt_resume(struct platform_device *dev)
- {
- struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
-
- gsc3280_watchdog_init(wdt)
- return 0;
- }
从程序中看出,调用了看门狗初始化函数gsc3280_watchdog_init,代码具体如下:
- static int gsc3280_watchdog_init(struct gsc3280_wdt *wdt)
- {
- unsigned int tmp_value = 0;
-
- DBG("Enter watchdog_init\n");
- spin_lock(&wdt->wdt_lock);
- tmp_value = readl(GSC3280_WDT_SYS_CFG);
- writel((tmp_value & 0xf0) | wdt->pclkOne, GSC3280_WDT_SYS_CFG);
- tmp_value = readl(GSC3280_WDT_SYS_CFG);
- DBG("wdt_pclk = %x\n", tmp_value & 0x0f);
- writel(wdt->torr & 0xffff , wdt->wdt_base + WDT_TORR);
- //0x1d:reset directly, 0x1f: reset after interrupt
- writel(wdt->wdt_cr & 0x1d, wdt->wdt_base + WDT_CR);
- DBG("wdt_ccvr = %x\n", readl(wdt->wdt_base + WDT_CCVR));
- DBG("wdt_cr = %x\n", readl(wdt->wdt_base + WDT_CR));
-
- tmp_value = readl(GSC3280_WDT_SYS_CFG);
- writel(tmp_value & ~GSC3280_WDT_SYS_CFG_PAUSE, GSC3280_WDT_SYS_CFG); //start watchdog
- spin_unlock(&wdt->wdt_lock);
- return 0;
- }
说明:
1、程序中多处用到了DBG宏,主要作用用来打印调试信息,在调试中使用,2.4会具体讲述。
2、为了对资源的保护,在操作看门狗寄存器前,首先上自旋锁,在操作结束后,关闭自旋锁。
3、此函数不止在恢复函数中调用,在开启看门狗等地方也调用,主要用来对寄存器的赋值,包括分频系数、TOR值和控制寄存器等,具体在2.3.3中的io_ctl中讲述。如果是在开启看门狗中使用,则在调用此函数之前会先对其赋值。
2.3、混杂设备gsc3280wdt_miscdev
在2.2.1中的探测函数中,我们使用语句ret
= misc_register
(&gsc3280wdt_miscdev);来注册混杂设备,
gsc3280wdt_miscdev具体内容如下:
- static const struct file_operations gsc3280wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = gsc3280wdt_write,
- .unlocked_ioctl = gsc3280wdt_ioctl,
- .open = gsc3280wdt_open,
- .release = gsc3280wdt_release,
- };
- static struct miscdevice gsc3280wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &gsc3280wdt_fops,
- };
到这里就注册了应用层调用底层驱动的接口,包括open、write、release和io_ctl等。接下来我们一一分析这些接口函数。
2.3.1、Open函数gsc3280wdt_open
在探测函数中,我们申请了gsc3280_wdt类型的内存空间,并对其进行了初始化,此结构体在open、write、release和io_ctl等函数中都需要使用,那在这些函数中怎么找到这个结构体呢?就是通过在open函数中,通过我们定义的全局链表wdt_device_list来找到。找到后,赋值给file的私有成员,那么在write、release和io_ctl等函数中也能使用了,gsc3280wdt_open函数如下:
- static int gsc3280wdt_open(struct inode *inode, struct file *file)
- {
- int status = -ENXIO;
- struct gsc3280_wdt *wdt;
-
- mutex_lock(&wdt_device_list_lock);
- list_for_each_entry(wdt, &wdt_device_list, device_entry) {
- if(strcmp(wdt->name, GSC3280_WDT_NAME) == 0) {
- status = 0;
- break;
- }
- }
- if (status == 0) {
- file->private_data = wdt;
- }
- mutex_unlock(&wdt_device_list_lock);
- if (test_and_set_bit(0, &wdt->open_lock)) {
- DBG("ERROR:gsc3280 open err, busy\n");
- return -EBUSY;
- }
- return nonseekable_open(inode, file);
- }
说明:
1、使用锁wdt_device_list_lock来对链表wdt_device_list进行保护,保证其互斥访问。
2、在探测函数中有语句:list_add(&wdt->device_entry, &wdt_device_list);,将wdt->device_entry加入链表wdt_device_list。那么在此处的open函数中,首先遍历链表wdt_device_list,根据wdt成员中的名字来判断是不是我们需要找的内容,如果是,将标志变量置0,将wdt保存在file的私有成员中。
3、设置位变量,标注已经打开了看门狗设备,防止重复打开。
2.3.2、释放函数gsc3280wdt_release
程序如下:
- static int gsc3280wdt_release(struct inode *inode, struct file *file)
- {
- struct gsc3280_wdt *wdt = file->private_data;
-
- gsc3280wdt_stop(wdt);
- clear_bit(0, &wdt->open_lock);
- DBG("gsc3280 release ok\n");
- return 0;
- }
说明:首先关闭看门狗,然后清除位变量,标注已经释放看门狗。
2.3.3、控制函数gsc3280wdt_ioctl
控制函数就是应用层通过io_ctl向驱动发送命令,本文看门狗所支持的命令包括如下:
- #define WDT_IOC_MAGIC 'W'
- #define WDT_IOC_MAXNR 6
- #define WDT_START _IO(WDT_IOC_MAGIC, 0)
- #define WDT_KEEPALIVE _IO(WDT_IOC_MAGIC, 1)
- #define WDT_PAUSE _IO(WDT_IOC_MAGIC, 2)
- #define WDT_READ _IO(WDT_IOC_MAGIC, 3)
- #define WDT_SETTIMEOUT _IOWR(WDT_IOC_MAGIC, 4, int)
- #define WDT_GETTIMEOUT _IOR(WDT_IOC_MAGIC, 5, int)
控制函数的具体程序如下:
- static long gsc3280wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- int new_margin;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
- struct gsc3280_wdt *wdt;
-
- if (_IOC_TYPE(cmd) != WDT_IOC_MAGIC)
- return -ENOTTY;
- if (_IOC_NR(cmd) > WDT_IOC_MAXNR)
- return -ENOTTY;
-
- wdt = file->private_data;
- switch (cmd) {
- case WDT_START:
- gsc3280wdt_start(wdt);
- return 0;
- case WDT_KEEPALIVE:
- gsc3280wdt_keepalive(wdt);
- return 0;
- case WDT_PAUSE:
- gsc3280wdt_stop(wdt);
- return 0;
- case WDT_READ:
- ReadDebug(wdt);
- return 0;
- case WDT_SETTIMEOUT:
- if (get_user(new_margin, p))
- return -EFAULT;
- wdt->pclkOne= new_margin & 0x000f;
- wdt->torr = (new_margin >> 4) & 0xffff;
- gsc3280wdt_set_par(wdt);
- gsc3280wdt_keepalive(wdt);
- return 0;
- case WDT_GETTIMEOUT:
- return put_user(gsc3280wdt_read_par(wdt), p);
- default:
- return -ENOTTY;
- }
- }
说明:控制函数首先对命令的有效性进行检验。
2.3.3.1、看门狗开始工作命令WDT_START
具体内容如下:
- static void gsc3280wdt_start(struct gsc3280_wdt *wdt)
- {
- DBG("watchdog start\n");
- wdt->wdt_cr = 0x1f;
- wdt->torr = 0x05;
- wdt->pclkOne = 0x08;
- gsc3280_watchdog_init(wdt);
- gsc3280_watchdog_enable(wdt);
- gsc3280wdt_keepalive(wdt);
- }
首先将寄存器的默认值赋值给变量。然后初始化看门狗,此函数在2.2.5中已经讲述,接下来就是使能看门狗和喂狗,程序具体如下:
- static void gsc3280_watchdog_enable(struct gsc3280_wdt *wdt)
- {
- spin_lock(&wdt->wdt_lock);
- //0x1d:reset directly, 0x1f: reset after interrupt
- writel(0x1d, wdt->wdt_base + WDT_CR);
- spin_unlock(&wdt->wdt_lock);
- }
- static void gsc3280wdt_keepalive(struct gsc3280_wdt *wdt)
- {
- spin_lock(&wdt->wdt_lock);
- writel(WDT_FEED_VALUE, wdt->wdt_base + WDT_CRR);
- spin_unlock(&wdt->wdt_lock);
- DBG("feed watchdog\n");
- }
从程序中可以看出,都是对寄存器进行相应的操作。
2.3.3.2、喂狗命令WDT_KEEPALIVE:
调用喂狗函数gsc3280wdt_keepalive实现,此函数在上面已经讲述。
2.3.3.3、看门狗暂停命令WDT_PAUSE
调用函数gsc3280wdt_stop实现此功能。
2.3.3.4、读取调试信息命令WDT_READ
读取调试信息,具体程序如下:
- static void ReadDebug(struct gsc3280_wdt *wdt)
- {
- unsigned int tmp_value = 0;
-
- DBG("read register\n");
- tmp_value = readl((unsigned int *)(GSC3280_SYSCTL_BASEADDR + SYS_WDT_EN_OFFSET));
- DBG("sys_wdt_en = %x\n", tmp_value & 0x04000000);
- DBG("sys_wdt_cfg = %x\n", readl(GSC3280_WDT_SYS_CFG));
- DBG("ccvr = %x\n", readl(wdt->wdt_base + WDT_CCVR));
- DBG("cr = %x\n", readl(wdt->wdt_base + WDT_CR));
- DBG("torr = %x\n", readl(wdt->wdt_base + WDT_TORR));
- }
2.3.3.5、设置和读取看门狗超时时间命令
此处的命令涉及到与应用层数据的交互,对于设置命令来说,首先从应用层取得数据,然后对数据进行分解,最后调用函数gsc3280wdt_set_par进行设置,函数如下:
- static void gsc3280wdt_set_par(struct gsc3280_wdt *wdt)
- {
- unsigned int tmp_value = 0;
-
- spin_lock(&wdt->wdt_lock);
- tmp_value = readl(GSC3280_WDT_SYS_CFG);
- writel((tmp_value & 0xf0) | wdt->pclkOne, GSC3280_WDT_SYS_CFG);
- DBG("sys_wdt_cfg = %x\n", readl(GSC3280_WDT_SYS_CFG));
-
- writel(wdt->torr, wdt->wdt_base + WDT_TORR);
- DBG("wdt_torr = %x\n", readl(wdt->wdt_base + WDT_TORR));
- spin_unlock(&wdt->wdt_lock);
- }
对于读取参数函数,直接调用gsc3280wdt_read_par来读取参数,程序如下:
- static int gsc3280wdt_read_par(struct gsc3280_wdt *wdt)
- {
- unsigned int cfg = 0, torr = 0;
- cfg = readl(GSC3280_WDT_SYS_CFG) & 0x000f;
- torr = readl(wdt->wdt_base + WDT_TORR);
- cfg |= (torr << 4) & 0xfffffff0;
-
- DBG("%x\n", cfg);
- return cfg;
- }
2.4、DBG调试信息的开启与关闭
在本文件的开头,对DBG进行了定义,具体内容如下:
- #ifdef GSC3280_WDT_DEBUG
- #define DBG(msg...) do { \
- printk(KERN_INFO msg); \
- } while (0)
- #else
- #define DBG(msg...) do { } while(0)
- #endif
对于宏GSC3280_WDT_DEBUG的开启与关闭,是通过在linux内核目录:/driver/watchdog/下的makefile来实现的,在此makefile文件末尾增加如下内容:
- ccflags-$(CONFIG_GSC3280_WDT_DEBUG) := -DGSC3280_WDT_DEBUG
表示如果在kconfig下定义了CONFIG_GSC3280_WDT_DEBUG,则宏GSC3280_WDT_DEBUG也被定义。kconfig文件增加如下内容:
- config GSC3280_WDT_DEBUG
- bool "GSC3280 watchdog debugging messages"
- help
- Say Y here if you want the GSC3280 to produce a bunch of debug
- messages to the system log. Select this if you are having a
- problem with GSC3280 and want to see more of what is going on.
在make menuconfig下,选中"GSC3280 watchdog debugging messages"即可实现打印调试信息,取消则不显示,如下图:
三、应用层测试程序分析
本文提供了完善的应用层测试代码,具体如下:
- #include "wdtApp.h"
-
- int main(int argc, char **argv)
- {
- char str[10] = {0};
- unsigned char i = 0;
- unsigned int idCmd = 0;
- int fd = 0, idFreq = 0;
- fd = open("/dev/watchdog", O_RDWR);
- if(fd < 0)
- {
- printf("Open PWM Device Faild!\n");
- exit(1);
- }
- while(1)
- {
- idCmd = 0;
- printf("please enter the cmd and freq :\n");
- scanf("%s%x", str, &idFreq);
- //printf("cmd = %s, idFreq = %d\n", str, idFreq);
- if(idFreq > 0)
- {
- if(strcmp(str, "ST") == 0)
- {
- idCmd = WDT_START;
- }
- else if(strcmp(str, "A") == 0)
- {
- idCmd = WDT_KEEPALIVE;
- }
- else if(strcmp(str, "P") == 0)
- {
- idCmd = WDT_PAUSE;
- }
- else if(strcmp(str, "R") == 0)
- {
- idCmd = WDT_READ;
- }
- else if(strcmp(str, "SE") == 0)
- {
- idCmd = WDT_SETTIMEOUT;
- }
- else if(strcmp(str, "GE") == 0)
- {
- idCmd = WDT_GETTIMEOUT;
- }
- else if(strcmp(str, "Q") == 0)
- {
- printf("quit wdt control\n");
- break;
- }
- else
- {
- printf("wrong cmd\n");
- }
- if(idCmd != 0)
- {
- if(ioctl(fd, idCmd, &idFreq) < 0)
- {
- printf("CMD fail\n");
- break;
- }
- if(idCmd == WDT_GETTIMEOUT)
- {
- printf("idFreq = %x\n", idFreq);
- }
- }
- }/* end if(idFreq >= 0) */
- else
- {
- printf("wrong input freq(< 0)\n");
- }
- }/* end while(1) */
- close(fd);
- return 0;
- }
如上所以,通过相应命令即可实现对看门狗的控制。