博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
蜕变成蝶~Linux设备驱动之watchdog设备驱动
阅读量:7119 次
发布时间:2019-06-28

本文共 13745 字,大约阅读时间需要 45 分钟。

  看门狗(watchdog )分硬件看门狗和软件看门狗。硬件看门狗是利用一个定时器 电路,其定时输出连接到电路的复位端,程序在一定时间范围内对定时器清零 (俗称 “喂狗”),如果程序出现故障,不在定时周期内复位看门狗,就使得看门狗定时器溢出产生复位信号 并重启系统。软件看门狗原理上一样,只是将硬件电路上的定时器用处理器的内部定 时器代替。

1 看门狗的三个寄存器

1.1 watchdog原理

  S3C2410内部集成了watchdog,提供3 个寄存器对watchdog 进行操作,这3 个寄存器分别为WTCON (watchdog 控制寄存器)、WTDAT (watchdog 数据寄存器)和WTCNT(watchdog 记数寄存器) S3c2440的看门狗的原理框图如下:

  可以看到,看门狗定时器的频率由PCLK提供,其预分频器最大取值为255+1;另外,通过MUX,可以进一步降低频率。定时器采用递减模式,一旦到0,则可以触发看门狗中断以及RESET复位信号。 看门狗定时器的频率的计算公式如下:

t_watchdog = 1/[PCLK/(Prescaler value + 1)/Division_factor]

1.2 开启S3C2410 的看门狗 

void enable watchdog ()      {                       rWTCON = WTCON DIV64 | WTCON RSTEN;//64分频、开启复位信号        rWTDAT = 0x8000;//计数目标                        rWTCON |= WTCON ENABLE;//开启看门狗       }

1.3 S3C2410 的看门狗 “喂狗”

void feed dog () {    rWTCNT=0x8000; }

1.4 看门狗的使用例程 

void main ()      {           init system ();        ...                   enable watchdog ();//启动看门狗        ...        while (1)        {           ...                      feed dog (); //喂狗       }     }

2 watchdog中的数据结

  有一类设备被称为 “平台设备”,通常 SoC 系统中集成的独立的外设单元都被当作平台设备处理

2.1 platform_device 结构体

struct platform device      {        const char  * name;//设备名        u32      id;        struct device dev;                   u32      num resources;//设备所使用各类资源数量        struct resource * resource;//资源      };

2.2 S3C2410 中的平台设备

struct platform device *s3c24xx uart devs[];struct platform device s3c device usb; //USB 控制器                         struct platform device s3c device lcd; //LCD 控制器                             struct platform device s3c device wdt; //看门狗                                                        2                              struct platform device s3c device i2c; //I C 控制器                             struct platform device s3c device iis; //IIS                          struct platform device s3c device rtc; //实时钟         ...       /*SMDK2410开发板使用的平台设备*/                               static struct platform device *smdk2410 devices[]  initdata =       {                 &s3c device usb, //USB                      &s3c device lcd, //LCD                        &s3c device wdt, //看门狗                                        &s3c device i2c, //I C                      &s3c device iis,  //IIS       };

2.3 S3C2410 看门狗的platform_device 结构体

struct platform device s3c device wdt =       {         .name = "s3c2410-wdt",  //设备名         .id =  - 1, .          num resources = ARRAY SIZE (s3c wdt resource),  //资源数量                          .resource = s3c wdt resource,  //看门狗所使用资源       };

2.4 int platform_add_devices()函数

int platform add devices(struct platform device **devs, int num)       {         int i, ret = 0;         for (i = 0; i < num; i++)          { ret = platform device register(devs[i]);/*注册平台设备*/           if (ret) /*注册失败*/           {            while (--i >= 0)                  platform device unregister(devs[i]);/*注销已经注册的平台设备 */            break;          }         }        return ret;      }

2.5 platform_driver 结构体 

struct platform driver       {                                                int (*probe)(struct platform device *);//探测                                         int (*remove)(struct platform device *);//移除                                            void (*shutdown)(struct platform device *);//关闭                                            int (*suspend)(struct platform device *, pm message t state);// 挂起                            int (*resume)(struct platform device *);//恢复                    struct device driver driver;        };

2.6 S3C2410 看门狗的platform_driver 结构体 

static struct platform driver s3c2410wdt driver =       {                                 .probe      = s3c2410wdt probe,//S3C2410看门狗探测                                         .remove     = s3c2410wdt remove,// S3C2410看门狗移除                                         .shutdown   = s3c2410wdt shutdown,//S3C2410看门狗关闭                                         .suspend    = s3c2410wdt suspend,//S3C2410看门狗挂起                                   .resume     = s3c2410wdt resume, //S3C2410看门狗恢复         .driver     = {                                 .owner  = THIS MODULE,            .name   = "s3c2410-wdt",//设备名       }, };

2.7 S3C2410 看门狗所用资源 

static struct resource s3c wdt resource[] =        {          [0] =         {           .start = S3C24XX PA WATCHDOG,     //看门狗I/O 内存开始位置          .end = S3C24XX PA WATCHDOG + S3C24XX SZ WATCHDOG - 1,               //看门狗I/O 内存结束位置           .flags = IORESOURCE MEM,  //I/O 内存资源         } ,         [1] =        {          .start = IRQ WDT, //看门狗开始IRQ 号          .end = IRQ WDT, //看门狗结束IRQ 号          .flags = IORESOURCE IRQ,  //IRQ 资源         }       };

2.8 S3C2410 看门狗驱动的miscdevice 结构体 

static struct miscdevice s3c2410wdt miscdev =  {                              .minor      = WATCHDOG MINOR,//次设备号         .name       = "watchdog",        .fops       = &s3c2410wdt fops,//文件操作结构体 };

2.9 S3C2410 看门狗驱动的文件操作结构体

static struct file operations s3c2410wdt fops = {                     .owner      = THIS MODULE,                .llseek     = no llseek,    //seek                               .write      = s3c2410wdt write,     //写函数                                     .ioctl      = s3c2410wdt ioctl, //ioctl 函数                               .open       = s3c2410wdt open,  //打开函数                              .release    = s3c2410wdt release,//释放函数 };

3 加载和卸载函数 

  驱动模块的加载和卸载函数分别 用 platform_driver_register() 和 platform_driver_ unregister()注册和注销platform_driver

3.1 S3C2410 看门狗驱动

static int     __init watchdog__init (void)       {        printk (banner);                 return   platform driver register(&s3c2410wdt driver);//       注 册platform driver       }             static void     exit watchdog exit (void)        { platform driver unregister (&s3c2410wdt driver);//          注  销 platform driver      }

4 探测和移除函数 

4.1 探测函数

static int s3c2410wdt probe (struct platform device *pdev)       {         struct resource *res;         int started = 0;         int ret;         int size;              DBG ("%s: probe=%p\n", _ _FUNCTION_ _, pdev);              /* 获得看门狗的内存区域 */                                   res = platform get resource (pdev, IORESOURCE MEM, 0);        if (res == NULL)         {                         printk(KERN INFO PFX "failed to get memory region resouce\n");          return  - ENOENT;         }              size = (res->end - res->start) + 1;        //申请I/O 内存                  wdt mem = request mem region (res->start, size, pdev->name);                    if (wdt mem == NULL)         {                      printk(KERN INFO PFX "failed to get memory region\n");          return  - ENOENT;         }                        wdt base = ioremap (res->start, size); //设备内存->虚拟地址                      if (wdt base == 0)         {                             printk(KERN INFO PFX "failed to ioremap () region\n");          return  - EINVAL;         }                                         DBG ("probe: mapped wdt base=%p\n", wdt base);              /* 获得看门狗的中断 */                                 res = platform get resource (pdev, IORESOURCE IRQ, 0);        if (res == NULL) {                            printk(KERN INFO PFX "failed to get irq resource\n");          return  - ENOENT;         }        //申请中断                        ret = request irq (res->start, s3c2410wdt irq, 0, pdev->name, pdev);        if (ret != 0)         {                       printk(KERN INFO PFX "failed to install irq (%d)\n", ret);          return ret;         }                         wdt clock = clk get (&pdev->dev, "watchdog"); //获得看门狗时钟源                 if (wdt clock == NULL)         {                            printk(KERN INFO PFX "failed to find watchdog clock source\n");          return  - ENOENT;         }                        clk enable (wdt clock);              /* 看看是否能设置定时器的超时时间为期望的值,如果不能,使用缺省值 */                                     if (s3c2410wdt set heartbeat (tmr margin))         {                                        started = s3c2410wdt set heartbeat (                               CONFIG S3C2410 WATCHDOG DEFAULT TIME);          if (started == 0)          {                                  printk (KERN INFO PFX "tmr margin value out of range, default %d                                           used\n",CONFIG S3C2410 WATCHDOG DEFAULT TIME);          }          else          {                                 printk (KERN INFO PFX              "default timer value is out of range, cannot start\n");          }         }             //注册miscdevice                            ret = misc register(&s3c2410wdt miscdev);        if (ret)         {                                printk(KERN ERR PFX "cannot registermiscdev on minor=%d (%d)\n",                                 WATCHDOG MINOR, ret);          return ret;         }                            if (tmr atboot && started == 0)         {                              printk(KERN INFO PFX "Starting Watchdog Timer\n");                         s3c2410wdt start ();         }              return 0;      }

4.2 探测函数 

static int s3c2410wdt remove (struct platform device *dev)       {            if (wdt mem != NULL)         {                  release resource (wdt mem); //释放资源                               kfree (wdt mem);//释放内存            wdt mem = NULL;        }       //释放中断                if (wdt irq != NULL)        {                 free irq (wdt irq->start, dev);                wdt irq = NULL; }        //禁止时钟源        if (wdt clock != NULL)        {          clk disable (wdt clock);          clk put (wdt clock);          wdt clock = NULL;         }     misc deregister(&s3c2410wdt miscdev);//注销miscdevice        return 0;     }

5 挂起和恢复函数

5.1 挂起函数

static   int  s3c2410wdt suspend (struct    platform device   *dev, pm message t state)       {         /* 保存看门狗状态,停止它 */                   wtcon save = readl (wdt base + S3C2410 WTCON);                  wtdat save = readl (wdt base + S3C2410 WTDAT);                            s3c2410wdt stop ();               return 0;      }

5.2 恢复函数

static int s3c2410wdt resume (struct platform device *dev)       {         /* 恢复看门狗状态 */                        writel (wtdat save, wdt base + S3C2410 WTDAT);                          writel (wtdat save, wdt base + S3C2410 WTCNT);                         writel (wtcon save, wdt base + S3C2410 WTCON);                                 printk (KERN INFO PFX "watchdog %sabled\n", (wtcon save                           &S3C2410 WTCON ENABLE)? "en" : "dis");             return 0;      }

6 打开和释放函数 

6.1 打开函数

static int s3c2410wdt open (struct inode *inode, struct file *file)       {                       if (down trylock (&open lock))  //获得打开锁           return  - EBUSY;              if (nowayout)         {                     module get (THIS MODULE);         }        else         {                          allow close = CLOSE STATE ALLOW;         }              /* 启动看门狗 */                           s3c2410wdt start ();                                 return nonseekable open (inode, file);      }

6.2 释放函数

static int s3c2410wdt release (struct inode *inode,struct file *file)       {         /* 停止看门狗 */                         if (allow close == CLOSE STATE ALLOW)         {                           s3c2410wdt stop ();        }         else         {                               printk (KERN CRIT  PFX  "Unexpected  close,  not  stopping watchdog!\n");                     s3c2410wdt keepalive ();         }                          allow close = CLOSE STATE NOT;                     up (&open lock);  //释放打开锁        return 0;      }

7 启停watchdog函数和写函数

7.1 启停看门狗函数

/*停止看门狗*/                                   static int s3c2410wdt stop (void)        {         unsigned long wtcon;                              wtcon = readl(wdt base + S3C2410 WTCON);         //停止看门狗,禁止复位                                wtcon &= ~ (S3C2410 WTCON ENABLE | S3C2410 WTCON RSTEN);                                writel (wtcon, wdt base + S3C2410 WTCON);               return 0;       }             /*开启看门狗*/                          static int s3c2410wdt start (void)       {         unsigned long wtcon;                           s3c2410wdt stop ();                                      wtcon = readl(wdt base + S3C2410 WTCON);         //使能看门狗,128 分频                              wtcon |= S3C2410 WTCON ENABLE | S3C2410 WTCON DIV128;                             if (soft noboot)         {                                 wtcon |= S3C2410 WTCON INTEN; //使能中断                                   wtcon &= ~S3C2410 WTCON RSTEN; //禁止复位         }         else         {                                  wtcon &= ~S3C2410 WTCON INTEN; //禁止中断                               wtcon |= S3C2410 WTCON RSTEN; //使能复位         }                                 DBG ("%s: wdt count=0x%08x, wtcon=%08lx\n",        FUNCTION    ,                      wdt count, wtcon);                           writel (wdt count, wdt base + S3C2410 WTDAT);                        writel (wdt count, wdt base + S3C2410 WTCNT);                            writel (wtcon, wdt base + S3C2410 WTCON);               return 0;       }

7.2 写函数

static ssize t s3c2410wdt write (struct file *file, const char      user *data,                size t len, loff t *ppos)        {         /* 刷新看门狗 */         if (len)          {           if (!nowayout) {             size t i;                         allow close = CLOSE STATE NOT;            for (i = 0; i != len; i++)            {              char c;                               if (get user(c, data + i))//用户空间->内核空间                return  - EFAULT;              if (c == 'V ')  //如果写入了'V ' ,允许关闭                               allow close = CLOSE STATE ALLOW;            }          }                      s3c2410wdt keepalive ();         }        return len;      }

  版权所有,转载请注明转载地址:

你可能感兴趣的文章
高可用集群原理概念详述
查看>>
mount NTFS harddisk on slackware ver13.37
查看>>
Liferay Dynamic CSS Filter方法的研究 - 总体过程
查看>>
看完性能简报,想不优化好都难!
查看>>
Qt学习之路(4):初探信号槽
查看>>
CSS伪类的又一个小应用,实现下拉菜单
查看>>
Python协程深入理解
查看>>
Ubuntu 11.10搭建和配置Nagios
查看>>
百度运维部电子竞技大赛!
查看>>
Linux下清空回收站
查看>>
XenMotion 与HA的区别
查看>>
修改Sql Server 2000数据库名称
查看>>
PHP问题 —— Notice: Undefined index:
查看>>
专业的优化服务,就是为你争取时间!
查看>>
solr安装配置
查看>>
SAS接口互连完全指南
查看>>
Word 2003中打开最近操作过的文档的两种推荐的方法
查看>>
LAMP+LNMP视频教程
查看>>
Linux下创建与解压zip, tar, tar.gz和tar.bz2文件
查看>>
《微服务》九大特性重读笔记
查看>>