打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Platform总线驱动之

一、看门狗模块介绍

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、模块加载函数

        在这里我们把看门狗设备作为一个平台设备,首先看下模块加载函数:

点击(此处)折叠或打开

  1. static int __init watchdog_init(void)
  2. {
  3.     return platform_driver_register(&gsc3280wdt_driver);
  4. }
  5. static void __exit watchdog_exit(void)
  6. {
  7.     platform_driver_unregister(&gsc3280wdt_driver);
  8. }
  9. module_init(watchdog_init);
  10. module_exit(watchdog_exit);

        在这里涉及到一个平台驱动gsc3280wdt_driver,其具体内容如下:

点击(此处)折叠或打开

  1. static struct platform_driver gsc3280wdt_driver = {
  2.     .probe        = gsc3280wdt_probe,
  3.     .remove        = __devexit_p(gsc3280wdt_remove),
  4.     .shutdown    = gsc3280wdt_shutdown,
  5.     .suspend        = gsc3280wdt_suspend,
  6.     .resume        = gsc3280wdt_resume,
  7.     .driver        = {
  8.         .owner    = THIS_MODULE,
  9.         .name    = "gsc3280_watchdog",
  10.     },
  11. };

        看门狗的平台驱动结构体中定义了很多函数,包括探测函数、移除函数、挂起和恢复函数,接下来我们一一分析。

2.2、探测、移除、关闭、挂起和恢复函数

2.2.1、探测(gsc3280wdt_probe)函数

        探测函数是平台驱动中最重要的,我们首先来分析它,在分析探测函数之前,先看下看门狗驱动的结构体,如下:

点击(此处)折叠或打开

  1. struct gsc3280_wdt {
  2.     struct device        *dev;
  3.     char                name[20];    //看门狗名字
  4.     spinlock_t        wdt_lock;
  5.     unsigned long        open_lock;    //位控制锁
  6.     struct resource    *wdt_mem;
  7.     struct resource    *wdt_irq;
  8.     void __iomem        *wdt_base;
  9.     struct clk            *wdt_clock;    //看门狗时钟
  10.     struct list_head    device_entry;    //list链表,在open函数中找到注册的看门狗结构体
  11.     //set parameter
  12.     //寄存器参数,在挂起函数中保存,在恢复函数中使用
  13.     unsigned int wdt_cr;
  14.     unsigned int torr;
  15.     unsigned int pclkOne;
  16. };
        看门狗驱动的探测函数如下:

点击(此处)折叠或打开

  1. static int __devinit gsc3280wdt_probe(struct platform_device *pdev)
  2. {
  3.     int ret = 0, size = 0;
  4.     unsigned long rate = 0;
  5.     struct gsc3280_wdt *wdt;

  6.     printk(KERN_INFO "######gsc3280 watchdog probe start######\n");
  7.     wdt = kzalloc(sizeof(struct gsc3280_wdt), GFP_KERNEL);    //看门狗驱动结构体
  8.     if (!wdt) {
  9.         DBG("ERROR:no memory for state\n");
  10.         return -ENOMEM;
  11.     }
  12.     /* Initialize the driver data */
  13.     wdt->dev = &pdev->dev;
  14.     strlcpy(wdt->name, GSC3280_WDT_NAME, sizeof(wdt->name));
  15.     spin_lock_init(&wdt->wdt_lock);
  16.     INIT_LIST_HEAD(&wdt->device_entry);
  17.     /* get the memory region for the watchdog timer */
  18.     wdt->wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  19.     if (wdt->wdt_mem == NULL) {
  20.         DBG("ERROR:no memory resource specified\n");
  21.         ret = -ENOENT;
  22.         goto free;
  23.     }
  24.     size = resource_size(wdt->wdt_mem);
  25.     if (!request_mem_region(wdt->wdt_mem->start, size, pdev->name)) {
  26.         DBG("ERROR:failed to get memory region\n");
  27.         ret = -EBUSY;
  28.         goto free;
  29.     }
  30.     wdt->wdt_base = ioremap(wdt->wdt_mem->start, size);
  31.     if (wdt->wdt_base == NULL) {
  32.         DBG("ERROR:failed to ioremap() region\n");
  33.         ret = -EINVAL;
  34.         goto err_req;
  35.     }

  36.     DBG("probe: mapped wdt_base=%p\n", wdt->wdt_base);
  1.     wdt->wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);    //申请中断
  2.     if (wdt->wdt_irq == NULL) {
  3.         DBG("ERROR:no irq resource specified\n");
  4.         ret = -ENOENT;
  5.         goto err_map;
  6.     }
  7.     ret = request_irq(wdt->wdt_irq->start, gsc3280wdt_irq, 0, pdev->name, wdt);
  8.     if (ret != 0) {
  9.         DBG("ERROR:failed to install irq (%d)\n", ret);
  10.         goto err_map;
  11.     }
  12.     
  13.     wdt->wdt_clock = clk_get(NULL, "wdt");     //申请时钟
  14.     if (IS_ERR(wdt->wdt_clock)) {
  15.         DBG("ERROR:failed to find watchdog clock source\n");
  16.         ret = PTR_ERR(wdt->wdt_clock);
  17.         goto err_irq;
  18.     }
  19.     rate = clk_get_rate(wdt->wdt_clock);
  20.     DBG("rate is %ld\n", rate);
  21.     clk_enable(wdt->wdt_clock);    //使能时钟
  22.     ret = misc_register (&gsc3280wdt_miscdev);
  23.     if(ret < 0) {
  24.         DBG("ERROR:misc register watchdog error\n");
  25.         goto err_clk;
  26.     }
  27.     mutex_lock(&wdt_device_list_lock);
  28.     list_add(&wdt->device_entry, &wdt_device_list);
  29.     mutex_unlock(&wdt_device_list_lock);
  30.     platform_set_drvdata(pdev, wdt);    //保存到pdev的私有数据成员中
  31.     printk(KERN_INFO "######gsc3280 watchdog probe success######\n");
  32.     return ret;

  33.  err_clk:
  34.     clk_disable(wdt->wdt_clock);
  35.     clk_put(wdt->wdt_clock);
  36.  err_irq:
  37.     free_irq(wdt->wdt_irq->start, pdev);
  38.  err_map:
  39.     iounmap(wdt->wdt_base);
  40.  err_req:
  41.     release_mem_region(wdt->wdt_mem->start, size);
  42.     wdt->wdt_mem = NULL;
  43. free:
  44.     kfree(wdt);

  45.     printk(KERN_INFO "!!!!!!gsc3280 watchdog probe err!!!!!!\n");
  46.     return ret;
  47. }
        静态全局链表和互斥锁:

点击(此处)折叠或打开

  1. static LIST_HEAD(wdt_device_list);
  2. 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

        代码如下:

点击(此处)折叠或打开

  1. static int __devexit gsc3280wdt_remove(struct platform_device *dev)
  2. {
  3.     struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
  4.     
  5.     misc_deregister(&gsc3280wdt_miscdev);
  6.     clk_disable(wdt->wdt_clock);
  7.     clk_put(wdt->wdt_clock);
  8.     wdt->wdt_clock = NULL;
  9.     free_irq(wdt->wdt_irq->start, dev);
  10.     wdt->wdt_irq = NULL;
  11.     iounmap(wdt->wdt_base);
  12.     release_mem_region(wdt->wdt_mem->start, resource_size(wdt->wdt_mem));
  13.     wdt->wdt_mem = NULL;
  14.     kfree(wdt);
  15.     printk(KERN_INFO "######gsc3280 remove ok######\n");
  16.     return 0;
  17. }

        说明:
        1、platform_get_drvdata(dev);函数就是从dev中的私有结构体中取得wdt,对应探测函数中的platform_set_drvdata(pdev, wdt);。
        2、接下来的程序就比较简单,基本是探测函数的相反--对资源的释放。

2.2.3、关闭函数gsc3280wdt_shutdown

        具体代码如下:

点击(此处)折叠或打开

  1. static void gsc3280wdt_shutdown(struct platform_device *dev)
  2. {
  3.     struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
  4.     
  5.     gsc3280wdt_stop(wdt);
  6.     printk(KERN_INFO "######gsc3280 shutdown ok######\n");
  7. }

        从程序中可以看出,主要就是看门狗的关闭函数,看门狗关闭函数gsc3280wdt_stop如下:

点击(此处)折叠或打开

  1. static void gsc3280wdt_stop(struct gsc3280_wdt *wdt)
  2. {
  3.     unsigned int tmp_value = 0;
  4.     
  5.     spin_lock(&wdt->wdt_lock);
  6.     tmp_value = readl(GSC3280_WDT_SYS_CFG);
  7.     writel(tmp_value | GSC3280_WDT_SYS_CFG_PAUSE, GSC3280_WDT_SYS_CFG);
  8.     spin_unlock(&wdt->wdt_lock);
  9. }

        从看门狗关闭函数中可以看出,首先上自旋锁,然后操作寄存器,将相应位置1,停止看门狗,最后释放自旋锁。

2.2.4、挂起函数gsc3280wdt_suspend

        如果Linux内核支持电源管理,则挂起和恢复函数起作用。挂起函数代码如下:

点击(此处)折叠或打开

  1. static int gsc3280wdt_suspend(struct platform_device *dev, pm_message_t state)
  2. {
  3.     struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
  4.     
  5.     spin_lock(&wdt->wdt_lock);
  6.     /* Save watchdog state, and turn it off. */
  7.     wdt->pclkOne = readl(GSC3280_WDT_SYS_CFG) & 0x0f;
  8.     wdt->torr = readl(wdt->wdt_base + WDT_TORR) & 0x0000ffff;
  9.     wdt->wdt_cr = readl(wdt->wdt_base + WDT_CR);
  10.     spin_unlock(&wdt->wdt_lock);
  11.     /* Note that WTCNT doesn't need to be saved. */
  12.     gsc3280wdt_stop(wdt);
  13.     return 0;
  14. }

        说明:

        1、挂起函数主要完成在挂起前对变量的保存,上面主要完成对主要寄存器值的保存,以便在恢复函数中使用。

        2、接下来就是暂停看门狗。

2.2.5、恢复函数gsc3280wdt_resume

        代码如下:

点击(此处)折叠或打开

  1. static int gsc3280wdt_resume(struct platform_device *dev)
  2. {
  3.     struct gsc3280_wdt *wdt = platform_get_drvdata(dev);
  4.     
  5.     gsc3280_watchdog_init(wdt)
  6.     return 0;
  7. }

        从程序中看出,调用了看门狗初始化函数gsc3280_watchdog_init,代码具体如下:

点击(此处)折叠或打开

  1. static int gsc3280_watchdog_init(struct gsc3280_wdt *wdt)
  2. {
  3.     unsigned int tmp_value = 0;
  4.     
  5.     DBG("Enter watchdog_init\n");
  6.     spin_lock(&wdt->wdt_lock);
  7.     tmp_value = readl(GSC3280_WDT_SYS_CFG);
  8.     writel((tmp_value & 0xf0) | wdt->pclkOne, GSC3280_WDT_SYS_CFG);
  9.     tmp_value = readl(GSC3280_WDT_SYS_CFG);
  10.     DBG("wdt_pclk = %x\n", tmp_value & 0x0f);
  11.     writel(wdt->torr & 0xffff , wdt->wdt_base + WDT_TORR);
  12.     //0x1d:reset directly, 0x1f: reset after interrupt
  13.     writel(wdt->wdt_cr & 0x1d, wdt->wdt_base + WDT_CR);
  14.     DBG("wdt_ccvr = %x\n", readl(wdt->wdt_base + WDT_CCVR));
  15.     DBG("wdt_cr = %x\n", readl(wdt->wdt_base + WDT_CR));
  16.     
  17.     tmp_value = readl(GSC3280_WDT_SYS_CFG);
  18.     writel(tmp_value & ~GSC3280_WDT_SYS_CFG_PAUSE, GSC3280_WDT_SYS_CFG); //start watchdog
  19.     spin_unlock(&wdt->wdt_lock);
  20.     return 0;
  21. }

        说明:

        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具体内容如下:

点击(此处)折叠或打开

  1. static const struct file_operations gsc3280wdt_fops = {
  2.     .owner            = THIS_MODULE,
  3.     .llseek            = no_llseek,
  4.     .write            = gsc3280wdt_write,
  5.     .unlocked_ioctl    = gsc3280wdt_ioctl,
  6.     .open            = gsc3280wdt_open,
  7.     .release            = gsc3280wdt_release,
  8. };
  9. static struct miscdevice gsc3280wdt_miscdev = {
  10.     .minor    = WATCHDOG_MINOR,
  11.     .name    = "watchdog",
  12.     .fops    = &gsc3280wdt_fops,
  13. };

        到这里就注册了应用层调用底层驱动的接口,包括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函数如下:

点击(此处)折叠或打开

  1. static int gsc3280wdt_open(struct inode *inode, struct file *file)
  2. {
  3.     int status = -ENXIO;
  4.     struct gsc3280_wdt *wdt;

  5.     mutex_lock(&wdt_device_list_lock);
  6.     list_for_each_entry(wdt, &wdt_device_list, device_entry) {
  7.         if(strcmp(wdt->name, GSC3280_WDT_NAME) == 0) {
  8.             status = 0;
  9.             break;
  10.         }
  11.     }
  12.     if (status == 0) {
  13.         file->private_data = wdt;
  14.     }
  15.     mutex_unlock(&wdt_device_list_lock);
  16.     if (test_and_set_bit(0, &wdt->open_lock)) {
  17.         DBG("ERROR:gsc3280 open err, busy\n");
  18.         return -EBUSY;
  19.     }
  20.     return nonseekable_open(inode, file);
  21. }

        说明:

        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

        程序如下:

点击(此处)折叠或打开

  1. static int gsc3280wdt_release(struct inode *inode, struct file *file)
  2. {
  3.     struct gsc3280_wdt *wdt = file->private_data;
  4.     
  5.     gsc3280wdt_stop(wdt);
  6.     clear_bit(0, &wdt->open_lock);
  7.     DBG("gsc3280 release ok\n");
  8.     return 0;
  9. }

        说明:首先关闭看门狗,然后清除位变量,标注已经释放看门狗。

2.3.3、控制函数gsc3280wdt_ioctl

        控制函数就是应用层通过io_ctl向驱动发送命令,本文看门狗所支持的命令包括如下:

点击(此处)折叠或打开

  1. #define WDT_IOC_MAGIC            'W'
  2. #define WDT_IOC_MAXNR            6
  3. #define WDT_START                _IO(WDT_IOC_MAGIC, 0)
  4. #define WDT_KEEPALIVE            _IO(WDT_IOC_MAGIC, 1)
  5. #define WDT_PAUSE                _IO(WDT_IOC_MAGIC, 2)
  6. #define WDT_READ                _IO(WDT_IOC_MAGIC, 3)
  7. #define WDT_SETTIMEOUT        _IOWR(WDT_IOC_MAGIC, 4, int)
  8. #define WDT_GETTIMEOUT        _IOR(WDT_IOC_MAGIC, 5, int)

        控制函数的具体程序如下:

点击(此处)折叠或打开

  1. static long gsc3280wdt_ioctl(struct file *file,    unsigned int cmd, unsigned long arg)
  2. {
  3.     int new_margin;
  4.     void __user *argp = (void __user *)arg;
  5.     int __user *p = argp;
  6.     struct gsc3280_wdt *wdt;

  7.     if (_IOC_TYPE(cmd) != WDT_IOC_MAGIC)
  8.         return -ENOTTY;
  9.     if (_IOC_NR(cmd) > WDT_IOC_MAXNR)
  10.         return -ENOTTY;

  11.     wdt = file->private_data;
  12.     switch (cmd) {
  13.         case WDT_START:
  14.             gsc3280wdt_start(wdt);
  15.             return 0;
  16.         case WDT_KEEPALIVE:
  17.             gsc3280wdt_keepalive(wdt);
  18.             return 0;
  19.         case WDT_PAUSE:
  20.             gsc3280wdt_stop(wdt);
  21.             return 0;
  22.         case WDT_READ:
  23.             ReadDebug(wdt);
  24.             return 0;
  25.         case WDT_SETTIMEOUT:
  26.             if (get_user(new_margin, p))
  27.                 return -EFAULT;
  28.             wdt->pclkOne= new_margin & 0x000f;
  29.             wdt->torr = (new_margin >> 4) & 0xffff;
  30.             gsc3280wdt_set_par(wdt);
  31.             gsc3280wdt_keepalive(wdt);
  32.             return 0;
  33.         case WDT_GETTIMEOUT:
  34.             return put_user(gsc3280wdt_read_par(wdt), p);
  35.         default:
  36.             return -ENOTTY;
  37.     }
  38. }

        说明:控制函数首先对命令的有效性进行检验。

2.3.3.1、看门狗开始工作命令WDT_START

        具体内容如下:

点击(此处)折叠或打开

  1. static void gsc3280wdt_start(struct gsc3280_wdt *wdt)
  2. {
  3.     DBG("watchdog start\n");
  4.     wdt->wdt_cr = 0x1f;
  5.     wdt->torr = 0x05;
  6.     wdt->pclkOne = 0x08;
  7.     gsc3280_watchdog_init(wdt);
  8.     gsc3280_watchdog_enable(wdt);
  9.     gsc3280wdt_keepalive(wdt);
  10. }

        首先将寄存器的默认值赋值给变量。然后初始化看门狗,此函数在2.2.5中已经讲述,接下来就是使能看门狗和喂狗,程序具体如下:

点击(此处)折叠或打开

  1. static void gsc3280_watchdog_enable(struct gsc3280_wdt *wdt)
  2. {
  3.     spin_lock(&wdt->wdt_lock);
  4.     //0x1d:reset directly, 0x1f: reset after interrupt
  5.     writel(0x1d, wdt->wdt_base + WDT_CR);
  6.     spin_unlock(&wdt->wdt_lock);
  7. }
  8. static void gsc3280wdt_keepalive(struct gsc3280_wdt *wdt)
  9. {
  10.     spin_lock(&wdt->wdt_lock);
  11.     writel(WDT_FEED_VALUE, wdt->wdt_base + WDT_CRR);
  12.     spin_unlock(&wdt->wdt_lock);
  13.     DBG("feed watchdog\n");
  14. }

        从程序中可以看出,都是对寄存器进行相应的操作。

2.3.3.2、喂狗命令WDT_KEEPALIVE:

        调用喂狗函数gsc3280wdt_keepalive实现,此函数在上面已经讲述。

2.3.3.3、看门狗暂停命令WDT_PAUSE

        调用函数gsc3280wdt_stop实现此功能。

2.3.3.4、读取调试信息命令WDT_READ

        读取调试信息,具体程序如下:

点击(此处)折叠或打开

  1. static void ReadDebug(struct gsc3280_wdt *wdt)
  2. {
  3.     unsigned int tmp_value = 0;
  4.     
  5.     DBG("read register\n");
  6.     tmp_value = readl((unsigned int *)(GSC3280_SYSCTL_BASEADDR + SYS_WDT_EN_OFFSET));
  7.     DBG("sys_wdt_en = %x\n", tmp_value & 0x04000000);
  8.     DBG("sys_wdt_cfg = %x\n", readl(GSC3280_WDT_SYS_CFG));
  9.     DBG("ccvr = %x\n", readl(wdt->wdt_base + WDT_CCVR));
  10.     DBG("cr = %x\n", readl(wdt->wdt_base + WDT_CR));
  11.     DBG("torr = %x\n", readl(wdt->wdt_base + WDT_TORR));
  12. }

2.3.3.5、设置和读取看门狗超时时间命令

        此处的命令涉及到与应用层数据的交互,对于设置命令来说,首先从应用层取得数据,然后对数据进行分解,最后调用函数gsc3280wdt_set_par进行设置,函数如下:

点击(此处)折叠或打开

  1. static void gsc3280wdt_set_par(struct gsc3280_wdt *wdt)
  2. {
  3.     unsigned int tmp_value = 0;
  4.     
  5.     spin_lock(&wdt->wdt_lock);
  6.     tmp_value = readl(GSC3280_WDT_SYS_CFG);
  7.     writel((tmp_value & 0xf0) | wdt->pclkOne, GSC3280_WDT_SYS_CFG);
  8.     DBG("sys_wdt_cfg = %x\n", readl(GSC3280_WDT_SYS_CFG));
  9.     
  10.     writel(wdt->torr, wdt->wdt_base + WDT_TORR);    
  11.     DBG("wdt_torr = %x\n", readl(wdt->wdt_base + WDT_TORR));
  12.     spin_unlock(&wdt->wdt_lock);
  13. }

        对于读取参数函数,直接调用gsc3280wdt_read_par来读取参数,程序如下:

点击(此处)折叠或打开

  1. static int gsc3280wdt_read_par(struct gsc3280_wdt *wdt)
  2. {
  3.     unsigned int cfg = 0, torr = 0;
  4.     cfg = readl(GSC3280_WDT_SYS_CFG) & 0x000f;
  5.     torr = readl(wdt->wdt_base + WDT_TORR);
  6.     cfg |= (torr << 4) & 0xfffffff0;
  7.     
  8.     DBG("%x\n", cfg);
  9.     return cfg;
  10. }

2.4、DBG调试信息的开启与关闭

        在本文件的开头,对DBG进行了定义,具体内容如下:

点击(此处)折叠或打开

  1. #ifdef GSC3280_WDT_DEBUG
  2. #define DBG(msg...) do { \
  3.         printk(KERN_INFO msg); \
  4.     } while (0)
  5. #else
  6. #define DBG(msg...)    do { } while(0)
  7. #endif
        对于宏GSC3280_WDT_DEBUG的开启与关闭,是通过在linux内核目录:/driver/watchdog/下的makefile来实现的,在此makefile文件末尾增加如下内容:

点击(此处)折叠或打开

  1. ccflags-$(CONFIG_GSC3280_WDT_DEBUG) := -DGSC3280_WDT_DEBUG
        表示如果在kconfig下定义了CONFIG_GSC3280_WDT_DEBUG,则宏GSC3280_WDT_DEBUG也被定义。kconfig文件增加如下内容:

点击(此处)折叠或打开

  1. config GSC3280_WDT_DEBUG
  2.     bool "GSC3280 watchdog debugging messages"
  3.     help
  4.      Say Y here if you want the GSC3280 to produce a bunch of debug
  5.      messages to the system log. Select this if you are having a
  6.      problem with GSC3280 and want to see more of what is going on.

        在make menuconfig下,选中"GSC3280 watchdog debugging messages"即可实现打印调试信息,取消则不显示,如下图:



三、应用层测试序分析

        本文提供了完善的应用层测试代码,具体如下:

点击(此处)折叠或打开

  1. #include "wdtApp.h"

  2. int main(int argc, char **argv)
  3. {
  4.     char str[10] = {0};
  5.     unsigned char i = 0;
  6.     unsigned int idCmd = 0;
  7.     int fd = 0, idFreq = 0;
  8.     fd = open("/dev/watchdog", O_RDWR);
  9.     if(fd < 0)
  10.     {
  11.         printf("Open PWM Device Faild!\n");
  12.         exit(1);
  13.     }
  14.     while(1)
  15.     {
  16.         idCmd = 0;
  17.         printf("please enter the cmd and freq :\n");
  18.         scanf("%s%x", str, &idFreq);
  19.         //printf("cmd = %s, idFreq = %d\n", str, idFreq);
  20.         if(idFreq > 0)
  21.         {
  22.             if(strcmp(str, "ST") == 0)
  23.             {
  24.                 idCmd = WDT_START;
  25.             }
  26.             else if(strcmp(str, "A") == 0)
  27.             {
  28.                 idCmd = WDT_KEEPALIVE;
  29.             }
  30.             else if(strcmp(str, "P") == 0)
  31.             {
  32.                 idCmd = WDT_PAUSE;
  33.             }
  34.             else if(strcmp(str, "R") == 0)
  35.             {
  36.                 idCmd = WDT_READ;
  37.             }
  38.             else if(strcmp(str, "SE") == 0)
  39.             {
  40.                 idCmd = WDT_SETTIMEOUT;
  41.             }
  42.             else if(strcmp(str, "GE") == 0)
  43.             {
  44.                 idCmd = WDT_GETTIMEOUT;
  45.             }
  46.             else if(strcmp(str, "Q") == 0)
  47.             {
  48.                 printf("quit wdt control\n");
  49.                 break;
  50.             }
  51.             else
  52.             {
  53.                 printf("wrong cmd\n");
  54.             }
  55.             if(idCmd != 0)
  56.             {
  57.                 if(ioctl(fd, idCmd, &idFreq) < 0)
  58.                 {
  59.                     printf("CMD fail\n");
  60.                     break;
  61.                 }
  62.                 if(idCmd == WDT_GETTIMEOUT)
  63.                 {
  64.                     printf("idFreq = %x\n", idFreq);
  65.                 }
  66.             }
  67.         }/* end if(idFreq >= 0) */
  68.         else
  69.         {
  70.             printf("wrong input freq(< 0)\n");
  71.         }
  72.     }/* end while(1) */
  73.     close(fd);
  74.     return 0;
  75. }

        如上所以,通过相应命令即可实现对看门狗的控制。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
WatchDog驱动程序
Linux驱动修炼之道
linux驱动模型开发
一线触摸屏协议驱动
什么是看门狗(watchdog)
linux嵌入式系统开发之看门狗---驱动篇
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服