您的位置 首页 IOT

arm驱动linux内核时钟

《[arm驱动]linux内核时钟》涉及内核驱动函数四个,内核结构体一个,分析了内核驱动函数一个;可参考的相关应用程序模板或内核驱动模板一个…

《[arm驱动]linux内核时钟》触及内核驱动函数四个,内核结构体一个,剖析了内核驱动函数一个;可参阅的相关应用程序模板或内核驱动模板一个,可参阅的相关应用程序模板或内核驱动一个

一、内核定时器
含义:内核定时器是软件含义上的定时器,终究依靠定时器来完结。时钟中止处理程序会引发Timer_softirq软中止,运转当时处理器上到期的一切定时器。
二、linux设备驱动编程
linux内核供给一组函数,时钟数据结构;这组函数和数据结构使驱动工程师不必关怀详细的软件定时器终究对应着怎样的内核和硬件行为。
三、数据结构和函数:
1)数据结构
结构体一)Linux在include/linux/timer.h头文件中界说了数据结构timer_list来描绘一个内核定时器:

struct timer_list {
struct list_head list; //定时器列表
unsigned long expires; //定时器到期时刻,单位HZ等效与秒
void (*function)(unsigned long); //处理函数
unsigned long data;//作为参数被输入定时器处理函数
……………..
};

2)定时器界说及处理函数
a)界说一个内核定时器

struct timer_list my_timer;

内核驱动函数一)b)初始化定时器的timer_list的entry中的next指针为null

void init_timer(struct *timer_list timer);

内核源码一)init_timer内核源码

void fastcall init_timer(struct timer_list *timer)
{
timer->entry.next = NULL;
timer->base = __raw_get_cpu_var(tvec_bases);
#ifdef CONFIG_TIMER_STATS
timer->start_site = NULL;
timer->start_pid = -1;
memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
}

内核驱动函数二)c)添加定时器

void add_timer(struct timer_list *timer)

内核驱动函数三)d)删去定时器

int del_timer(struct timer_list * timer)

内核驱动函数四)e)修正定时器的expire

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

模板一)四、内核定时器运用模板(结合虚拟内存)

a)结构体界说

#define TIMERDELAY 2
struct VirtualDisk{
struct cdev cdev;//详细看cdev机制
timer_list my_timer;//设备要用的定时器
};

b)结构体赋值,添加时钟,时钟要处理的函数

/***********时钟函数,只需调用initMytimer************/
//完结作业后,往往会拖延expires并将定时器再次添加到内核定时器链表,以便定时器能再次被触发
static void domytimer(unsigned long arg){//just used by initMytimer function
struct VirtualDisk* myVirtualDiskp = (struct VirtualDisk *)(arg);//很重要
//……….加上你还要做的代码…………
printk(“arg is %ld\n”, myVirtualDiskp->mytimer.expires);//打印现在的expires
myVirtualDiskp->mytimer.expires = jiffies + (TIMERDELAY*HZ);//”HZ”等效与”秒”
add_timer(&myVirtualDiskp->mytimer);
//…………………..
}
static void initMytimer(struct VirtualDisk *myVirtualDiskp, int delay){
init_timer(&myVirtualDiskp->mytimer);
myVirtualDiskp->mytimer.data = (unsigned long) myVirtualDiskp;
myVirtualDiskp->mytimer.function = &domytimer;
myVirtualDiskp->mytimer.expires = jiffies + (delay*HZ);
add_timer(&myVirtualDiskp->mytimer);
}
/***********************/

c)exit()或其他开释函数中删去时钟

if(VirtualDiskp)del_timer(&VirtualDiskp->mytimer);

实例一)五、完好代码

//“timerlist_drv”,”timerlist_”
#include //模块所需的很多符号和函数界说
#include #include //文件体系相关的函数和头文件
#include //指定初始化和铲除函数
#include #include //cdev结构的头文件包含#include #include //#include //包含驱动程序运用的大部分内核API的界说,包含睡觉函数以及各种变量声明
#include //在内核和用户空间中移动数据的函数
#include
#include
#include
#include
#include /*timer*/
#include /*jiffies*/
#define VIRTUALDISK_SIZE 0x1000//4k
#define MEM_CLEAR 0x1
#define VIRTUALDISK_MAJOR 250
/******timer *******/
#define TIMERDELAY 2
int VirtualDisk_major = VIRTUALDISK_MAJOR;
struct VirtualDisk{
struct cdev cdev;//详细看cdev机制
unsigned char mem[VIRTUALDISK_SIZE ];
long count; /*记载设备现在被多少设备翻开*/
struct timer_list mytimer;
};
static struct class *timerlist_class;
static struct class_device *timerlist_class_dev;
struct VirtualDisk *VirtualDiskp;
/*********timer opration*************/
static void domytimer(unsigned long arg){//just used by follow function
struct VirtualDisk* myVirtualDiskp = (struct VirtualDisk *)(arg);
printk(“arg is %ld\n”, myVirtualDiskp->mytimer.expires);
myVirtualDiskp->mytimer.expires = jiffies + (TIMERDELAY*HZ);
add_timer(&myVirtualDiskp->mytimer);
}
static void initMytimer(struct VirtualDisk *myVirtualDiskp, int delay){
init_timer(&myVirtualDiskp->mytimer);
myVirtualDiskp->mytimer.data = (unsigned long) myVirtualDiskp;
myVirtualDiskp->mytimer.function = &domytimer;
myVirtualDiskp->mytimer.expires = jiffies + (delay*HZ);
add_timer(&myVirtualDiskp->mytimer);
}
/*********timer opration over*************/
static int timerlist_drv_open(struct inode *inode, struct file *file)
{
printk(“timerlist_dev read\n”);
file->private_data = VirtualDiskp;
VirtualDiskp->count++; /*添加设备翻开次数*/
return 0;
}
static int timerlist_drv_release(struct inode *inode, struct file *file)
{
printk(“timerlist_dev release\n”);
VirtualDiskp->count–; /*削减设备翻开次数*/
return 0;
}
/*seek文件定位函数:seek()函数对文件定位的开端地址可所以文件最初(SEEK_SET,0)、当时方位(SEEK_CUR,1)、文件尾(SEEK_END,2)*/
static loff_t timerlist_drv_llseek(struct file *file, loff_t offset, int origin){
loff_t ret = 0;/*回来的方位偏移*/
switch (origin)
{
case SEEK_SET: /*相对文件开端方位偏移*/
if (offset < 0)/*offset不合法*/
{
ret = – EINVAL; /*无效的指针*/
break;
}
if ((unsigned int)offset > VIRTUALDISK_SIZE)/*偏移大于设备内存*/
{
ret = – EINVAL; /*无效的指针*/
break;
}
file->f_pos = (unsigned int)offset; /*更新文件指针方位*/
ret = file->f_pos;/*回来的方位偏移*/
break;
case SEEK_CUR: /*相对文件当时方位偏移*/
if ((file->f_pos + offset) > VIRTUALDISK_SIZE)/*偏移大于设备内存*/
{
ret = – EINVAL;/*无效的指针*/
break;
}
if ((file->f_pos + offset) < 0)/*指针不合法*/
{
ret = – EINVAL;/*无效的指针*/
break;
}
file->f_pos += offset;/*更新文件指针方位*/
ret = file->f_pos;/*回来的方位偏移*/
break;
default:
ret = – EINVAL;/*无效的指针*/
break;
}
return ret;
}
/*设备操控函数:ioctl()函数承受的MEM_CLEAR指令,这个指令将大局内存的有用数据长度清零,关于设备不支持的指令,ioctl()函数应该回来-EINVAL*/
static int timerlist_drv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){
struct VirtualDisk *devp = file->private_data;/*取得设备结构体指针*/
switch (cmd)
{
case MEM_CLEAR:/*设备内存清零*/
memset(devp->mem, 0, VIRTUALDISK_SIZE);
printk(KERN_INFO “VirtualDisk is set to zero\n”);
break;
default:
return – EINVAL;
}
return 0;
}
/*读函数:读写函数主要是让设备结构体的mem[]数组与用户空间交互数据,并跟着拜访字节数改变回来用户的文件读写偏移方位*/
static ssize_t timerlist_drv_read(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk(“timerlist_dev read\n”);
unsigned long p = *ppos; /*记载文件指针偏移方位*/
unsigned int countt = count;/*记载需求读取的字节数*/
int ret = 0; /*回来值*/
struct VirtualDisk *devp = file->private_data; /*取得设备结构体指针*/
/*剖析和获取有用的读长度*/
if (p >= VIRTUALDISK_SIZE ) /*要读取的偏移大于设备的内存空间*/
return countt ? – ENXIO: 0;/*读取地址过错*/
if (countt > VIRTUALDISK_SIZE – p)/*要读取的字节大于设备的内存空间*/
countt = VIRTUALDISK_SIZE – p;/*酿制读取的字节数设为剩下的字节数*/
/*内核空间->用户空间交流数据*/
if (copy_to_user(buf, (void*)(devp->mem + p), countt))
{
ret = – EFAULT;
}
else
{
*ppos += countt;
ret = countt;
printk(“read %d bytes(s) is %ld\n”, countt, p);
}
printk(“bytes(s) is %s\n”, buf);
initMytimer(devp, 2);
return ret;
}
/*
file 是文件指针,count 是恳求的传输数据长度,buff 参数是指向用户空间的缓冲区,这个缓冲区或许保存要写入的数据,或许是一个寄存新读入数据的空缓冲区,该地址在内核空间不能直接读写,ppos 是一个指针指向一个”long offset type”目标, 它指出用户正在存取的文件方位. 回来值是一个”signed size type。写的方位相关于文件最初的偏移。
*/
static ssize_t timerlist_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk(“timerlist_dev write\n”);
unsigned long p = *ppos; /*记载文件指针偏移方位*/
int ret = 0; /*回来值*/
unsigned int countt = count;/*记载需求写入的字节数*/
struct VirtualDisk *devp = file->private_data; /*取得设备结构体指针*/
/*剖析和获取有用的写长度*/
if (p >= VIRTUALDISK_SIZE )/*要写入的偏移大于设备的内存空间*/
return countt ? – ENXIO: 0;/*写入地址过错*/
if (countt > VIRTUALDISK_SIZE – p)/*要写入的字节大于设备的内存空间*/
countt = VIRTUALDISK_SIZE – p;/*酿制写入的字节数设为剩下的字节数*/
/*用户空间->内核空间*/
if (copy_from_user(devp->mem + p, buf, countt))
ret = – EFAULT;
else
{
*ppos += countt;/*添加偏移方位*/
ret = countt;/*回来实践的写入字节数*/
printk(“written %d bytes(s) from%ld\n”, countt, p);
}
return ret;
return 0;
}
static struct file_operations timerlist_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,面向编译模块时主动创立的__this_module变量 */
.read = timerlist_drv_read,
.write = timerlist_drv_write,
.open = timerlist_drv_open,
.release = timerlist_drv_release,
.llseek = timerlist_drv_llseek,
.ioctl = timerlist_drv_ioctl,
};
/*将 cdev 结构嵌入一个你自己的设备特定的结构,你应当初始化你现已分配的结构运用以上函数,有一个其他的 struct cdev 成员你需求初始化. 象 file_operations 结构,struct cdev 有一个具有者成员,应当设置为 THIS_MODULE,一旦 cdev 结构树立, 最终的过程是把它告知内核, 调用:
cdev_add(&dev->cdev, devno, 1);*/
static void VirtualDisk_setup_cdev(struct VirtualDisk *dev, int minorIndex){
int err;
int devno = MKDEV(VirtualDisk_major, minorIndex);
cdev_init(&dev->cdev, &timerlist_drv_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if(err){
printk(“error %d cdev file added\n”, err);
}
}
static int timerlist_drv_init(void)
{
int result;
dev_t devno = MKDEV(VirtualDisk_major, 0);
if(VirtualDisk_major){
result = register_chrdev_region(devno, 1, “timerlist_dev”);
}else{
result = alloc_chrdev_region(&devno, 0, 1, “timerlist_dev”);
VirtualDisk_major = MAJOR(devno);
}
if(result < 0 ){
return result;
}
VirtualDiskp = kmalloc(sizeof(struct VirtualDisk), GFP_KERNEL);
if(!VirtualDiskp){
result = -ENOMEM;
goto fail_malloc;
}
memset(VirtualDiskp, 0, sizeof(struct VirtualDisk));
VirtualDisk_setup_cdev(VirtualDiskp, 0);
timerlist_class = class_create(THIS_MODULE, “timerlist_drv”);
if (IS_ERR(timerlist_class))
return PTR_ERR(timerlist_class);
timerlist_class_dev = class_device_create(timerlist_class, NULL, MKDEV(VirtualDisk_major, 0), NULL, “timerlist_dev”); /* /dev/xyz */
if (IS_ERR(timerlist_class_dev))
return PTR_ERR(timerlist_class_dev);
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
static void timerlist_drv_exit(void)
{
if(VirtualDiskp)del_timer(&VirtualDiskp->mytimer);
cdev_del(&VirtualDiskp->cdev);
kfree(VirtualDiskp);
unregister_chrdev_region(MKDEV(VirtualDisk_major, 0), 1);
class_device_unregister(timerlist_class_dev);
class_destroy(timerlist_class);
}
module_init(timerlist_drv_init);
module_exit(timerlist_drv_exit);
MODULE_LICENSE(“GPL”);

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/iot/265206.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部