/** * Author:hasen * 参考 :《linux设备驱动开发详解》 * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:时钟 * Date:2014-11-15 */一、内核定时器
struct timer_list {
struct list_head entry ;/*定时器列表*/
unsigned long expires ; /*定时器到期时间(jiffies)*/
void (*function)(unsigned long );/*定时器处理函数*/
unsigned long data ;/*作为参数传入定时器处理函数*/
struct timer_base_s base ;
} 下面定义一个my_timer的定时器struct timer_lsit my_timer ;(2)初始化定时器
void init_timer(struct timer_list *timer) ;上述init_timer()函数初始化timer_list的entry的next为NULL,并给base指针赋值。
#define TIMER_INITIALIZER(_function,_expires,_data){ .entry = {.prev = TIMER_ENTRY_STATIC} , .funciton = (_function), .expires = (_expires) , .data = (_data) , .base = &boot_tvec_bases , } DEFINE_TIMER(_name,_function,_espires,_data)宏是定义并初始化定时器成员的“快捷方式”。这个#define DEFINE_TIMER(_name,_function,_expires,_data) struct timer_list _name = TIMER_INITIALIZER(_function,_expires,_data)此外,setup_timer()函数也可以用来初始化定时器并给其成员赋值,其代码如下:
static inline void setup_timer(struct timer_list *timer,
void (*function)(unsigned long),unsigned long data)
{
timer->function = function ;
timer->data = data ;
init_timer(timer) ;
} (3)增加定时器void add_timer(struct timer_list *timer) ;上述函数用于注册内核定时器,将定时器接入到内核动态定时器链表中。
int del_timer(struct timer_lsit *timer) ;上述函数用于删除定时器。
int mod_timer(struct timer_list *timer,unsigned long expires) ;上述函数用于修改定时器的到期时间,在新的被传入的expires到来后才会执行定时器函数。
示例:内核定时器使用模板
/*xxx设备结构体*/
struct xx_dev{
struct cdev cdev ;
...
timer_lsit xxx_timer ;/*设备要使用的定时器*/
}
/*xxx驱动中的模函数*/
xxx_func1(...)
{
struct xxx_dev *dev = filp->private_data ;
...
/*初始化定时器*/
init_timer(&dev->xxx_timer) ;
dev->xxx_timer.function = &xxx_do_timer ;
dev->xxx_timer.data = (unsigned long)dev ;/*设备结构体指针作为定时器处理函数参数*/
dev->xxx_timer.expires = jiffies + delay ;
/*添加(注册)定时器*/
add_timer(&dev->xxx_timer) ;
...
}
/*xxx驱动中的某函数*/
xxx_func2(...)
{
...
/*删除定时器*/
del_timer(&dev->xxx_timer) ;
...
}
/*定时器处理函数*/
static void xxx_do_timer(unsigned long arg)
{
struct xxx_device *dev = (struct xxx_device*)(arg) ;
...
/*调度定时器再执行*/
dev->xxx_timer.expires = jiffies + delay ;
add_timer(&dev->xxx_timer) ;
...
}
定时器的到期时间往往是在目前的jiffies的基础上添加一个时延,若为Hz,则表示延迟1秒。struct delayed_work{
struct work_struct work ;
struct timer_list timer ;
};
struct work_struct {
atimic_long_t data ;
#define WORK_STRUCT_PENDING 0
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
struct list_head entry ;
work_func_t func ;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map ;
#endif
}; 我们可以通过如下的函数调度一个delayed_work在指定的延时后执行。int schedule_delayed_work(struct delayed_work *work,unsigned long delay) ;当指定的delay到来时delayed_work结构体中work成员的work_func_t类型成员func()会被执行。
typedef void (*work_func_t) (struct work_sturct *work);其中delay参数的单位是jiffies,因此一种常见的与用法如下:
schedule_delayed_work(&work,msecs_to_jiffies(poll_interval)) ;其中的msecs_to_jiffies()用于将毫秒转化为jiffies。
int cancel_delayed_work(struct delayed_work *work) ; int cancel_delayed_work_sync(struct delayed_work *work) ;实例:秒字符设备
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define SECOND_MAJOR 248 /*预设的second的主设备号*/
static int second_major = SECONG_MAJOR ;
/*second设备结构体*/
struct second_dev{
struct cdev cdev ;/*cdev结构体*/
atomic_t counter ;/*一共经历了多少秒*/
struct timer_list s_timer ;/*设备要使用的定时器*/
}
struct second_dev *second_devp ;/*设备结构体指针*/
struct void second_timer_handle(unsigned long arg)
{
mod_timer(&second_devp->s_timer,jiffies + Hz) ;
atomic_inc(&second_devp->counter) ;
printk(KERN_NOTICE "current jiffies is %d\n",jiffies) ;
}
/*文件打开函数*/
int second_open(struct inode *inode ,struct file *filp)
{
/*初始化定时器*/
init_timer(&second_devp->s_timer);
second_devp->s_timer.function = &second_timer_handle ;
second_devp->s_timer.expires = jiffies + Hz ;
add_timer(&second_devp->s_timer) ;/*添加(注册)定时器*/
atomic_set(&second_devp->count,0) ; //计数清0
return 0 ;
}
/*文件释放函数*/
int second_release(struct inode *inode ,struct file *filp)
{
del_timer(&second_devp->s_timer) ;
return 0 ;
}
/*读函数*/
static ssize_t second_read(struct file *filp ,char __user *buf,
size_t count,loff_t *ppos)
{
int counter ;
counter = atomic_read(&second_devp->counter) ;
if(put_user(counter,(int *)buf))
return -EFAULT ;
else
return sizeof(unsigned int) ;
}
/*文件操作结构体*/
static const struct file_operations second_fops = {
.owner = THIS_MODULE ,
.open = second_open ,
.release = second_release ,
.read = second_read ,
} ;
/*初始化并注册cdev*/
static void second_setup_cdev(struct second_dev *dev,int index)
{
int err,devno = MKDEV(second_major,index) ;
cdev_init(&dev->cdev,&second_fops) ;
dev->cdev.owner = THIS_MODULE ;
err = cdev_add(&dev->cdev,devno,1) ;
if(err)
printk(KERN_NOTICE,"Error %d adding LED%d",err,index) ;
}
/*设备驱动模块加载函数*/
int second_init(void)
{
int ret ;
dev_t devno = MKDEV(second_major,0) ;
/*申请设备号*/
if(second_major)
ret = register_chrdev_region(devno,1,"second") ;
else{
ret = alloc_chrdev_region(&devno,0,1,"second") ;
second_major = MAJOR(devno) ;
}
if(ret < 0)
return ret ;
/*动态申请设备结构体的内存*/
second_devp = kmalloc(sizeof(struct second_dev),GFP_KERN) ;
if(!second_devp){/*申请失败*/
ret = -ENOMEM ;
goto fail_malloc ;
}
memset(second_devp,0,sizeof(struct second_dev)) ;
second_setup_cdev(second_devp,0) ;
fail_malloc:
unregister_chrdev_region(devno,1) ;
return ret ;
}
/*模块卸载函数*/
void second_exit(void)
{
cdev_del(&second_devp->cdev) ; /*注销cdev*/
kfree(second_devp) ;/*释放设备结构体内存*/
unregister_chrdev_reigon(MKDEV(second_major,0),1) ;
}
MODULE_AUTHOR("Hasen<hasen.dc@gmail.com>") ;
MODULE_LICENSE("Dual BSD/GPL");
module_param(second_major,int,S_IRUGO) ;
module_init(second_init) ;
module_exit(second_exit) ; 在second的open()函数中,将启动定时器,此后每一秒会再次运行定时器处理函数,在second的#include ...
main()
{
int fd ;
int counter = 0 ;
int old_counter = 0 ;
/*打开/dev/second设备文件*/
fd= open("/dev/second",O_RDONLY) ;
if(fd != -1){
while(1){
read(fd,&counter,sizeof(unsigned int)) ;/*读取目前经历的秒数*/
if(counter != old_counter){
printf("seconds after open /dev/second :%d\n",counter) ;
old_counter = counter ;
}
}
}else{
printf("Device open failure\n") ;
}
} 运行second_test之后,内核将不断地输出目前的jiffies值,而应用程序将不断地输出自打开void ndelay(unsigned long nsecs) ; void udelay(unsigned long usecs) ; void mdelay(unsigned long msecs) ;上述延迟的实现原理本质上是忙等待,它根据CPU频率进行一定次数的循环,软件中进行这样的延迟:
void delay(unsigned int time)
{
while(time--) ;
} ndelay()、udelay()和mdelay()函数的实现方式机理与此类似。内核在启动是,会运行一个延迟测试Calibrating delay loop... 530.84 BogoMIPS (lpj=1327104)毫秒时延(以及更大的秒时延)已经比较大了,在内核当中,最好不要直接使用mdelay()函数,这将无
void msleep(unsigned int millisecs) ; unsigned long msleep_interruptible(unsigned int millisecs) ; void ssleep(unsigned int seconds) ;上述函数将使得调用它的进程睡眠参数指定的时间,msleep()、ssleep()不能被打断,而
/*延迟100个jiffies*/ unsigned long delay = jiffies + 100 ; while(time_before(jiffies,delay)) ; /*延迟2s*/ unsigned long delay = jiffies + 2*Hz ; while(time_before(jiffies,delay)) ;与time_before()对应的还有一个time_after(),它们在内核中定义为(实际上只是将传入的未来时
#define time_after(a,b) (typecheck(unsigned long ,a)) && typecheck(unsigned long ,b) && ((long (b)-(long)(a)<0)) #define time_before(a,b) time_after(b,a)为了防止timer_before()和timer_after()的比较过程中编译优化器对jiffies的优化,内核将其定义
void msleep(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) +1;
while(timeout)
timeout = schedule_timeout_uninterruptible(timeout) ;
}
unsigned long msleep_interruptible(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1 ;
while(timeout && !signal_pending(current))
timeout = schedule_timeout_interruptible(timeout) ;
return jiffies_to_msecs(timeout) ;
} 实际上,schedule_timeout()的实现原理是向系统添加一个定时器,在定时器处理函数中唤醒参数对signed long __sched schedule_timeout_interruptible(signed long timeout)
{
__set_current_state(TASK_INTERRUPTIBLE) ;
return schedule_timeout(timeout) ;
}
signed long __sched schedule_timeout_uninterruptible(signed long timeout)
{
__set_current_state(TASK_UNINTERRUPTIBLE) ;
return schedule_timeout(timeout) ;
} 另外,下面两个函数可以将当前进程添加到等待队列中,从而在等待队列上睡眠。当超时发生时,进sleep_on_timeout(wait_queue_head_t *q,unsigned long timeout) ; interruptible_sleep_on_timeout(wait_queue_head_t *q,unsigned long timeout) ;总结
原文地址:http://blog.csdn.net/android_hasen/article/details/41143207