/***************************************************************************************************
设备驱动中的定时器--机制篇
编译环境:不需要
实 验 者:张永辉 2012年9月13日
***************************************************************************************************/
Linux 内核中定义了一个 timer_list 结构,我们在驱动程序中可以利用之:
struct timer_list
{
struct list_head list;
unsigned long expires; //定时器到期时间
unsigned long data; //作为参数被传入定时器处理函数
void (*function)(unsigned long);
};
下面是关于 timer 的 API 函数:
void add_timer(struct timer_list * timer); //增加定时器
int del_timer(struct timer_list * timer);
int mod_timer (struct timer_list *timer, unsigned long expires); //修改定时器的 expire
使用定时器的一般流程为:
(1)timer、编写 function;
(2)为 timer 的 expires、data、function 赋值;
(3)调用 add_timer 将 timer 加入列表;
(4)在定时器到期时,function 被执行;
(5)在程序中涉及 timer 控制的地方适当地调用 del_timer、mod_timer 删除 timer 或修改 timer 的 expires。
实例:
drivers\char\keyboard.c 中键盘的驱动中关于 timer 的部分:
#include <linux/timer.h>
static struct timer_list key_autorepeat_timer =
{
function: key_callback
};
static void kbd_processkeycode(unsigned char keycode, char up_flag, int autorepeat)
{
char raw_mode = (kbd->kbdmode == VC_RAW);
if (up_flag)
{
rep = 0;
if(!test_and_clear_bit(keycode, key_down))
up_flag = kbd_unexpected_up(keycode);
}else
{
rep = test_and_set_bit(keycode, key_down);
/* If the keyboard autorepeated for us, ignore it.
* We do our own autorepeat processing.*/
if (rep && !autorepeat)
return;
}
if (kbd_repeatkeycode == keycode || !up_flag || raw_mode)
{
kbd_repeatkeycode = -1;
del_timer(&key_autorepeat_timer);
}
...
/** Calculate the next time when we have to do some autorepeat
* processing. Note that we do not do autorepeat processing
* while in raw mode but we do do autorepeat processing in
* medium raw mode. */
if (!up_flag && !raw_mode)
{
kbd_repeatkeycode = keycode;
if (vc_kbd_mode(kbd, VC_REPEAT))
{
if (rep)
key_autorepeat_timer.expires = jiffies + kbd_repeatinterval;
else
key_autorepeat_timer.expires = jiffies + kbd_repeattimeout;
add_timer(&key_autorepeat_timer);
}
}
}