单片机
返回首页

s3c6410在linux下的WATCHDOG TIMER(看门狗定时器)驱动(3)

2022-06-14 来源:eefocus

前面两篇一篇分析了看门狗定时器的驱动架构,另一篇分析了平台设备对应的probe函数,虽然对应的remove函数没分析,其实和别的平台设备驱动一样,做和probe函数相反的工作。这一篇要说点啥呢?


S3c2410_wdt.c (linux2.6.28driverswatchdog)在这个文件中还有很多函数,我们都没有分析过,这一篇就找些重要的函数分析下。


1、那就先从s3c2410wdt_start函数开始,此函数开启看门狗,源码如下:


static void s3c2410wdt_start(void)

{

unsigned long wtcon;


spin_lock(&wdt_lock);


__s3c2410wdt_stop();先停止看门狗便于设置


wtcon = readl(wdt_base + S3C2410_WTCON);读控制寄存器WTCON

wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;


这里的定义:


#define S3C2410_WTCON_ENABLE  (1<<5)


#define S3C2410_WTCON_DIV128  (3<<3)


对照下面的寄存器图,更直观:

if (soft_noboot) {   这个标志第一篇中说明了它的作用,不明的可以回过去查看。等于1,作为定时器使用。


wtcon |= S3C2410_WTCON_INTEN;使能中断

wtcon &= ~S3C2410_WTCON_RSTEN;不允许发出复位信号

} else {等于0,看门狗做复位电路使用

wtcon &= ~S3C2410_WTCON_INTEN;禁止中断

wtcon |= S3C2410_WTCON_RSTEN;允许复位

}


DBG('%s: wdt_count=0x%08x, wtcon=%08lxn',

   __func__, wdt_count, wtcon);


writel(wdt_count, wdt_base + S3C2410_WTDAT);写数据寄存器

writel(wdt_count, wdt_base + S3C2410_WTCNT);写计数器寄存器

writel(wtcon, wdt_base + S3C2410_WTCON);写控制寄存器

spin_unlock(&wdt_lock);

}


2、接着说s3c2410wdt_stop函数,停止看门狗工作。


static void s3c2410wdt_stop(void)

{

spin_lock(&wdt_lock);

__s3c2410wdt_stop();

spin_unlock(&wdt_lock);

}


static void __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);

}


3、s3c2410wdt_shutdown此函数用于停止看门狗


static void s3c2410wdt_shutdown(struct platform_device *dev)

{

s3c2410wdt_stop();

}


4、s3c2410wdt_suspend该函数用于电源管理,挂起设备


static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)

{

/* Save watchdog state, and turn it off. */保存看门狗当前状态

wtcon_save = readl(wdt_base + S3C2410_WTCON);

wtdat_save = readl(wdt_base + S3C2410_WTDAT);


/* Note that WTCNT doesn't need to be saved. */

s3c2410wdt_stop();关闭看门狗


return 0;

}


5、s3c2410wdt_resume也与电源管理有关,挂起后的恢复


static int s3c2410wdt_resume(struct platform_device *dev)

{

/* Restore watchdog state. */恢复各寄存器的设置

writel(wtdat_save, wdt_base + S3C2410_WTDAT);

writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */

writel(wtcon_save, wdt_base + S3C2410_WTCON);


printk(KERN_INFO PFX 'watchdog %sabledn',

      (wtcon_save & S3C2410_WTCON_ENABLE) ? 'en' : 'dis');


return 0;

}


6、再来看s3c2410wdt_fops结构体中的函数:


static const struct file_operations s3c2410wdt_fops = {

.owner  = THIS_MODULE,

.llseek  = no_llseek,

.write  = s3c2410wdt_write,

.unlocked_ioctl= s3c2410wdt_ioctl,

.open = s3c2410wdt_open,

.release  = s3c2410wdt_release,

};


6.1、先看s3c2410wdt_open函数:在用户调用open函数时被调用。源码如下:


/*

 * /dev/watchdog handling

 */

static int s3c2410wdt_open(struct inode *inode, struct file *file)

{


printk('s3c2410wdt_open.n');

if (test_and_set_bit(0, &open_lock))

return -EBUSY;

调用此函数测试open_lock的第0位。为0则表示此函数返回0,表示设备没有被另外的程序打开。如果第0位为1,则表示设备已经被打开,返回EBUSY


if (nowayout)不为0,表示看门狗不允许关闭,则增加看门狗模块的引用计数。

__module_get(THIS_MODULE);


allow_close = CLOSE_STATE_NOT;设为不允许关闭


/* start the timer */

s3c2410wdt_start();打开设备

return nonseekable_open(inode, file);不允许调用seek函数,即不允许对设备进行定位。

}


6.2、接着看s3c2410wdt_release函数,在close函数中被调用。函数源码如下:


static int s3c2410wdt_release(struct inode *inode, struct file *file)

{

/*

* Shut off the timer.

* Lock it in if it's a module and we set nowayout

*/

if (allow_close == CLOSE_STATE_ALLOW)看门狗为允许关闭

s3c2410wdt_stop();关闭看门狗

else {

dev_err(wdt_dev, 'Unexpected close, not stopping watchdogn');

s3c2410wdt_keepalive();使看门狗为活动状态

}


其中s3c2410wdt_keepalive函数源码如下:


static void s3c2410wdt_keepalive(void)

{

spin_lock(&wdt_lock);

writel(wdt_count, wdt_base + S3C2410_WTCNT);重新写计数寄存器

spin_unlock(&wdt_lock);

}


allow_close = CLOSE_STATE_NOT;设为不允许关闭

clear_bit(0, &open_lock);将open_lock的第0位设为0,允许打开

return 0;

}


6.3、再来看s3c2410wdt_write函数,该函数主要用来设置allow_close变量为允许关闭状态。如果向设备中写入V,那么就允许关闭设备。源码如下:


static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,

size_t len, loff_t *ppos)

{

/*

* Refresh the timer.

*/

printk('s3c2410wdt_write.n');

if (len) {

if (!nowayout) {  允许关闭

size_t i;


/* In case it was set long ago */

allow_close = CLOSE_STATE_NOT 不允许关闭


           for (i = 0; i != len; i++) {

char c;


if (get_user(c, data + i))

return -EFAULT;

if (c == 'V')

allow_close = CLOSE_STATE_ALLOW;

}如果往看门狗设备中写入V,允许关闭

}

s3c2410wdt_keepalive();

}

return len;

}


6.4、现在来看一个比较重要的函数,s3c2410wdt_ioctl函数用来接受系统的命令,设置看门狗的状态。


static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd,

unsigned long arg)

{

void __user *argp = (void __user *)arg;

int __user *p = argp;

int new_margin;

printk('s3c2410wdt_ioctl.n');


switch (cmd) {

case WDIOC_GETSUPPORT:获取看门狗的信息

return copy_to_user(argp, &s3c2410_wdt_ident,

sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;


其中有定义:


#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE


static const struct watchdog_info s3c2410_wdt_ident = {

.options          =     OPTIONS,

.firmware_version = 0,

.identity         = 'S3C2410 Watchdog',

};

case WDIOC_GETSTATUS:

case WDIOC_GETBOOTSTATUS: 获得看门狗状态

return put_user(0, p);

case WDIOC_KEEPALIVE: 对看门狗进行喂狗

s3c2410wdt_keepalive();

return 0;

case WDIOC_SETTIMEOUT:设置新的超时时间

if (get_user(new_margin, p))

return -EFAULT;

if (s3c2410wdt_set_heartbeat(new_margin))

return -EINVAL;

s3c2410wdt_keepalive();

return put_user(tmr_margin, p);

case WDIOC_GETTIMEOUT:获得看门狗的当前超时时间

return put_user(tmr_margin, p);

default:

return -ENOTTY;

}

}

6.5、不知道你还记得吗?我们在probe函数中,申请的中断,并设置中断处理函数是s3c2410wdt_irq,现在来说这个函数,源码如下:


/* interrupt handler code */

static irqreturn_t s3c2410wdt_irq(int irqno, void *param)

{

dev_info(wdt_dev, 'watchdog timer expired (irq)n');



s3c2410wdt_keepalive();

return IRQ_HANDLED;

}


其实就是喂狗。

————————————————

版权声明:本文为CSDN博主「tianxiawuzhei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/tianxiawuzhei/article/details/7588824


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 家用电源无载自动断电装置的设计与制作

  • 短波AM发射器电路设计图

  • 带有短路保护系统的5V直流稳压电源电路图

  • 如何调制IC555振荡器

  • 基于ICL296的大电流开关稳压器电源电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章