看门狗(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;
}

  版权所有,转载请注明转载地址:http://www.cnblogs.com/lihuidashen/p/4501953.html

蜕变成蝶~Linux设备驱动之watchdog设备驱动的更多相关文章

  1. 蜕变成蝶~Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  2. 蜕变成蝶~Linux设备驱动之DMA

    如果不曾相逢 也许 心绪永远不会沉重 如果真的失之交臂 恐怕一生也不得轻松 一个眼神 便足以让心海 掠过飓风 在贫瘠的土地上 更深地懂得风景 一次远行 便足以憔悴了一颗 羸弱的心 每望一眼秋水微澜 便 ...

  3. 蜕变成蝶~Linux设备驱动之CPU与内存和I/O

    那是世上最远的距离 思念让我无法去呼吸 你的一动和一举 占据我心里 陪我每个孤独无尽的夜里 用我心中盛放的画笔 描绘你微笑时的绚丽 爱让人痛彻心底 我却不怀疑 你的存在是我生命的奇迹 感受你的每一次的 ...

  4. 蜕变成蝶~Linux设备驱动之中断与定时器

    “我叮咛你的 你说 不会遗忘 你告诉我的 我也全部珍藏 对于我们来说 记忆是飘不落的日子 永远不会发黄 相聚的时候 总是很短 期待的时候 总是很长 岁月的溪水边 捡拾起多少闪亮的诗行 如果你要想念我  ...

  5. 蜕变成蝶~Linux设备驱动之异步通知和异步I/O

    在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问.因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代.异步通知类 ...

  6. 蜕变成蝶~Linux设备驱动中的阻塞和非阻塞I/O

    今天意外收到一个消息,真是惊呆我了,博客轩给我发了信息,说是俺的博客文章有特色可以出本书,,这简直让我受宠若惊,俺只是个大三的技术宅,写的博客也是自己所学的一些见解和在网上看到我一些博文以及帖子里综合 ...

  7. 蜕变成蝶~Linux设备驱动之按键设备驱动

    在上述的驱动系列博客中,我们已经了解了关于阻塞和非阻塞.异步通知.轮询.内存和I/O口访问.并发控制等知识,按键设备驱动相对来说是比较简单的,本章内容可以加深我们对字符设备驱动架构.阻塞与非阻塞.中断 ...

  8. 蜕变成蝶~Linux设备驱动中的并发控制

    并发和竞争发生在两类体系中: 对称多处理器(SMP)的多个CPU 内核可抢占的单CPU系统 访问共享资源的代码区域称为临界区(critical sections),临界区需要以某种互斥机制加以保护.在 ...

  9. 乾坤合一~Linux设备驱动之块设备驱动

    1. 题外话 在蜕变成蝶的一系列学习当中,我们已经掌握了大部分Linux驱动的知识,在乾坤合一的分享当中,以综合实例为主要讲解,在一个月的蜕茧成蝶的学习探索当中,觉得数据结构,指针,链表等等占据了代码 ...

随机推荐

  1. c# js 删除table原行数据

    function addtreetotable(obj){ var table1 =  document.getElementById("Table1"); var hang =  ...

  2. 在C#中,Json的序列化和反序列化的几种方式总结 转载

    转载自  https://www.cnblogs.com/caofangsheng/p/5687994.html    谢谢 在这篇文章中,我们将会学到如何使用C#,来序列化对象成为Json格式的数据 ...

  3. 关于 extern "C"的说明

    在用C++的项目源码中,经常会不可避免的会看到下面的代码 #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __cplus ...

  4. Servlet(9)—HttpServlet和改进Servlet实例

    HttpServlet:针对Http协议定义的一个Servlet基类,唯一的功能就是强制类型转换ServletRequest转换成HttpServletRequest,ServletResponse转 ...

  5. java内部类(二)

    静态内部类 定义: static修饰的内部类就是静态内部类. 特点: 1.静态内部类不能直接访问外部类的非静态成员,但可以通过new 外部类().成员 的方式访问. 2.如果外部类的静态成员与内部类成 ...

  6. MySQL 数据库-索引注意事项

        索引注意事项 (1)最左前缀原则 如果查询的时候,查询条件精确匹配索引的左边连续一列或几列,则可以命中索引. (2)避免where 子句中对字段施加函数,如to_date(create_tim ...

  7. CSS魔法堂:更丰富的前端动效by CSS Animation

    前言  在<CSS魔法堂:Transition就这么好玩>中我们了解到对于简单的补间动画,我们可以通过transition实现.那到底多简单的动画适合用transtion来实现呢?答案就是 ...

  8. golang time打印出的值是62135596800的来源

    ' 减去62135596800是将"以公元1年1月1日0点为基准"改成"以1970年1月1日0点"为基准 所以,数据库datetime的默认值 : 0000-0 ...

  9. Javascript正则表达入参是null

    今天群友问了一个问题,如下的执行结果是什么? var reg = /^[a-z0-9\u4e00-\u9fa5]{0,15}$/; console.log(reg.test(null)); // tr ...

  10. 【jQuery Demo】图片切换效果整理

    图片的切换效果有很多,比较常见的有水平滚动.垂直滚动.淡入淡出等.我们接下来一一实现这些效果. 1.水平滚动 1) 我们先来实现HTML页面,代码很简单: <div id="conta ...