微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > linux驱动之内核定时器驱动设计

linux驱动之内核定时器驱动设计

时间:12-01 来源:互联网 点击:
我的环境:

Fedora 14 内核版本为2.6.38.1

开发板:ARM9 TQ2440

移植内核版本:linux-2.6.30.4

定时器在linux内核中主要是采用一个结构体实现的。但是需要注意定时器是一个只运行一次的对象,也就是当一个定时器结束以后,还需要重现添加定时器。但是可以采用mod_timer()函数动态的改变定时器到达时间。

这个驱动主要实现内核定时器的基本操作。内核定时器主要是是通过下面的结构体struct timer_list实现。需要的头文件包括#include,但是在实际开发过程中不需要包含该头文件,因为在sched.h中包含了该头文件。

struct timer_list {

struct list_head entry;

unsigned long expires;

void (*function)(unsigned long);

unsigned long data;

struct tvec_base *base;

#ifdef CONFIG_TIMER_STATS

void *start_site;

char start_comm[16];

int start_pid;

#endif

#ifdef CONFIG_LOCKDEP

struct lockdep_map lockdep_map;

#endif

};

定时器的实现主要是该结构体的填充和部分函数的配合即可完成。其中红色的部分是最主要的几个元素,1、expires主要是用来定义定时器到期的时间,通常采用jiffies这个全局变量和HZ这个全局变量配合设置该元素的值。比如expires = jiffies + n*HZ,其中jiffies是自启动以来的滴答数,HZ是一秒种的滴答数。

2、function可以知道是一个函数指针,该函数就是定时器的处理函数,类似我们在中断中的中断函数,其实定时器和中断有很大的相似性。定时器处理函数是自己定义的函数。

3、data通常是实现参数的传递,从function的参数类型可以知道,data可以作为定时器处理函数的参数。

其他的元素可以通过内核的函数来初始化。

初始化函数为:

init_timer(struct timer_list * timer);

或者直接DEFINE_TIMER宏实现定义和初始化操作。

#define DEFINE_TIMER(_name, _function, _expires, _data)

struct timer_list _name =

TIMER_INITIALIZER(_function, _expires, _data)

添加定时器到内核的函数:

void add_timer(struct timer_list *timer)

{

BUG_ON(timer_pending(timer));

mod_timer(timer, timer->expires);

}

删除定时器函数,如果定时器的定时时间还没有到达,那么才可以删除定时器:

int del_timer(struct timer_list *timer)

修改定时器的到达时间,该函数的特点是,不管定时器是否到达时间,都会重现添加一个定时器到内核。所以可以在定时处理函数中可以调用该函数修改需要重新定义的到达时间。

int mode_timer(struct timer_list *timer,unsigned long expires)

int mod_timer(struct timer_list *timer, unsigned long expires)

{

/*

* This is a common optimization triggered by the

* networking code - if the timer is re-modified

* to be the same thing then just return:

*/

if (timer->expires == expires && timer_pending(timer))

return 1;

/*注意调用的条件,也就是说明当前的定时器为链表的最后一个*/

return __mod_timer(timer, expires, false);

}

static inline int

__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)

{

struct tvec_base *base, *new_base;

unsigned long flags;

int ret;

ret = 0;

timer_stats_timer_set_start_info(timer);

BUG_ON(!timer->function);

base = lock_timer_base(timer, &flags);

if (timer_pending(timer)) {

detach_timer(timer, 0);

ret = 1;

} else {

if (pending_only)

goto out_unlock;

}

debug_timer_activate(timer);

new_base = __get_cpu_var(tvec_bases);

if (base != new_base) {

/*

* We are trying to schedule the timer on the local CPU.

* However we cant change timers base while it is running,

* otherwise del_timer_sync() cant detect that the timers

* handler yet has not finished. This also guarantees that

* the timer is serialized wrt itself.

*/

if (likely(base->running_timer != timer)) {

/* See the comment in lock_timer_base() */

timer_set_base(timer, NULL);

spin_unlock(&base->lock);

base = new_base;

spin_lock(&base->lock);

timer_set_base(timer, base);

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top