linux 驱动层定时器操作
当出现:
Linxu内核编程报错:implicit declaration of function ‘init_timer’
错误原因是:
在4.15内核里,init_timer被移除了,需要换用新的timer_setup接口,可以查看下面的驱动层代码second_open函数
应用层程序
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <poll.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define DEVICE "/dev/second"
void main(void)
{
int fd ;
int counter = 0 ,old_counter = 0;
fd = open(DEVICE,O_RDONLY);
if (fd != -1)
{
while(1)
{
read(fd , &counter,sizeof(unsigned int));
if(counter != old_counter)
{
printf("seconds after open %s :%d\n",DEVICE,counter);
old_counter = counter;
}
}
}
else{
printf("Device open failure\n");
}
}
驱动层程序
/*
* 内核版本 5.12
* 字符设备 second 驱动
*
* 原子操作计数器
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
//#define SECOND_SIZE 0x1000
// #define MEM_CLEAR 0x1
// #define SECOND_MAGIC 'f'
// #define MEM_CLEAR _IO(SECOND_MAGIC,0)
#define SECOND_MAJOR 200
#define DEVICE_NUM 1 //同主设备号,不同次设备号有1个
static int second_major = SECOND_MAJOR;
module_param(second_major,int ,S_IRUGO);
struct second_dev
{
struct cdev cdev;
atomic_t counter;
struct timer_list s_timer;
};
struct second_dev * second_devp;
void second_timer_handler(struct timer_list *arg)
{
struct second_dev *dev = container_of(arg, struct second_dev, s_timer);
mod_timer(&dev->s_timer ,jiffies + HZ); //触发下一次定时
atomic_inc(&dev->counter); //增加秒计数
printk(KERN_INFO "current jiffies is %ld\n",jiffies);
}
ssize_t second_read(struct file *filp, char __user *buf,
size_t size, loff_t *pos)
{
int counter;
counter = atomic_read(&second_devp->counter);
if (put_user(counter ,(int *)buf)) //将counter 放到用户空间
return -EFAULT;
else
return sizeof(unsigned int);
}
int second_open(struct inode *inode, struct file *filp)
{
// #if 内核版本 < 4.15
// init_timer(&second_devp->s_timer);
// second_devp->s_timer.function = second_timer_handler;
// second_devp->s_timer.expires = jiffies + HZ;
// #elif 内核版本 > 4.15
timer_setup(&second_devp->s_timer,&second_timer_handler,0);
//#endif
add_timer(&second_devp->s_timer);
atomic_set(&second_devp->counter , 0); //初始化计数器为0
return 0;
}
int second_release(struct inode *inode, struct file *filp)
{
del_timer(&second_devp->s_timer);
return 0;
}
static const struct file_operations second_fops = {
.owner = THIS_MODULE,
.read = second_read,
.open = second_open,
.release = second_release,
};
static void second_setup_cdev(struct second_dev *dev,int index)
{
int err,devno = MKDEV(second_major,index);
printk(KERN_INFO "index is %d\n",index); //添加打印代码是不想编译时这个代码被优化掉,导致次设备号的设备打不开
cdev_init(&dev->cdev ,&second_fops);
printk(KERN_INFO "dev->cdev is %p\n",&dev->cdev);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev ,devno, 1);
if(err)
printk(KERN_NOTICE "Error %d adding second%d",err,index);
}
static int __init second_init(void)
{
int ret,i;
dev_t devno = MKDEV(second_major,0);
if (second_major)
ret = register_chrdev_region(devno,DEVICE_NUM,"second");
else{
ret = alloc_chrdev_region(&devno,0,DEVICE_NUM,"second");
second_major = MAJOR(devno);
}
if (ret < 0)
return ret;
second_devp = kzalloc(sizeof(struct second_dev) * DEVICE_NUM,GFP_KERNEL);
if (!second_devp)
{
ret = -ENOMEM;
goto fail_malloc;
}
for (i = 0;i < DEVICE_NUM;i++)
{
// mutex_init(&(second_devp+i)->second_mutex);
// init_waitqueue_head(&(second_devp+i)->r_wait);
// init_waitqueue_head(&(second_devp+i)->w_wait);
second_setup_cdev(second_devp + i,i);
}
return 0;
fail_malloc:
unregister_chrdev_region(devno,DEVICE_NUM);
return ret;
}
module_init(second_init);
static void __exit second_exit(void)
{
int i = 0;
for (i = 0;i < DEVICE_NUM;i++)
cdev_del(&(second_devp+i)->cdev);
kfree(second_devp);
unregister_chrdev_region(MKDEV(second_major,0),DEVICE_NUM);
}
module_exit(second_exit);
MODULE_AUTHOR("good man");
MODULE_LICENSE("GPL v2");
实验结果: