linux驱动开发学习四:中断与时钟

代码如下:
#include <linux/module.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/slab.h> #include <linux/uaccess.h> #include<linux/jiffies.h> #include<linux/timer.h> #define SECOND_MAJOR 260 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; }; static struct second_dev *second_devp; static void second_timer_handler(struct timer_list *s) { mod_timer(&second_devp->s_timer,jiffies+HZ); atomic_inc(&second_devp->counter); printk(KERN_INFO "current jiffies is %ld ",jiffies); } static int second_open(struct inode *ins_timerode,struct file *filep) { timer_setup(&second_devp->s_timer,second_timer_handler,0);  //second_devp->s_timer.function=&second_timer_handler; second_devp->s_timer.expires=jiffies+HZ; add_timer(&second_devp->s_timer); atomic_set(&second_devp->counter,0); return 0; } static int second_release(struct inode *inode,struct file *filep) { del_timer(&second_devp->s_timer); return 0; } static ssize_t second_read(struct file *filep,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, }; static void second_setup_cdev(struct second_dev *dev,int index) { int err; int 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_ERR "Failed to add second device "); } } static int __init 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=kzalloc(sizeof(*second_devp),GFP_KERNEL); if(!second_devp){ ret=-ENOMEM; goto fail_malloc; } second_setup_cdev(second_devp,0); return 0; fail_malloc: unregister_chrdev_region(devno,1); return ret; } module_init(second_init); static void __exit second_exit(void) { cdev_del(&second_devp->cdev); kfree(second_devp); unregister_chrdev_region(MKDEV(second_major,0),1); } module_exit(second_exit); MODULE_AUTHOR("maple"); MODULE_LICENSE("GPL v2");

second_dev结构中增加 timer_list的定时器结构.在调用 second_setup_cdev进行创建设备

second_open中调用timer_setup进行定时器创建.在内核4.15以前使用的是init_timer.在4.15以后删除掉了init_timer

其源码分析如下:

#define timer_setup(timer, callback, flags)

__init_timer((timer), (callback), (flags))

原来这个是一个宏,其实还是调用的是__init_timer

#ifdef CONFIG_LOCKDEPz

#define __init_timer(_timer, _fn, _flags)

do {

static struct lock_class_key __key;

init_timer_key((_timer), (_fn), (_flags), #_timer, &__key);

} while (0)

 

#define __init_timer_on_stack(_timer, _fn, _flags)

do {

static struct lock_class_key __key;

init_timer_on_stack_key((_timer), (_fn), (_flags),

#_timer, &__key);

} while (0)

#else

#define __init_timer(_timer, _fn, _flags)

init_timer_key((_timer), (_fn), (_flags), NULL, NULL)

#define __init_timer_on_stack(_timer, _fn, _flags)

init_timer_on_stack_key((_timer), (_fn), (_flags), NULL, NULL)

#endif


config_lockedp用于检测死锁,常用debug,这里假定没有开这个宏

所以这里的又会转调init_timer_key

void init_timer_key(struct timer_list *timer,

void (*func)(struct timer_list *), unsigned int flags,

const char *name, struct lock_class_key *key)

{

#如果没有打开CONFIG_DEBUG_OBJECTS_TIMERS的话,debug_init null

debug_init(timer);

#所以主要调用这个函数初始化timer

do_init_timer(timer, func, flags, name, key);

}

 

static void do_init_timer(struct timer_list *timer,

void (*func)(struct timer_list *),

unsigned int flags,

const char *name, struct lock_class_key *key)

{

#pprev null,说明这个timer处于pending状态,当然了刚开始创建timer的时候当然要pending了,毕竟

#还没有开始执行

timer->entry.pprev = NULL;

#时间到期要执行的回调函数

timer->function = func;

#看来flags中保存了当前的cpu id

timer->flags = flags | raw_smp_processor_id();

lockdep_init_map(&timer->lockdep_map, name, key, 0);

}

从上面的代码可以看到在timer_setup中已经将对timer的回调函数和参数做了一个初始化.在second_open中初始化了second_devp->counter以及定时器超时的参数



3 每当读取设备的时候的操作就是读取second_devp->counter值并放到用户空间.

makfile文件:


obj-m:=irq_test.o #产生irq_test模块的目标文件


#目标文件 文件 要与模块名字相同


CURRENT_PATH:=$(shell pwd) #模块所在的当前路径


LINUX_KERNEL:=$(shell uname -r) #linux内核代码的当前版本


LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)


CONFIG_MODULE_SIG=n


 


all:

make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules


clean:

make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理模块


执行sudo insmod irq_test.ko报如下错误

insmod: ERROR: could not insert module irq_test.ko: Device or resource busy


执行cat /proc/devices 查看已存在的设备发现有deviceno=248的设备

Character devices:

1 mem

4 /dev/vc/0

4 tty

4 ttyS

5 /dev/tty

5 /dev/console

5 /dev/ptmx

5 ttyprintk

6 lp

7 vcs

10 misc

13 input

21 sg

29 fb

81 video4linux

89 i2c

99 ppdev

108 ppp

116 alsa

128 ptm

136 pts

180 usb

189 usb_device

204 ttyMAX

216 rfcomm

226 drm

241 media

242 aux

243 mei

244 hidraw

245 ttyDBC

246 bsg

247 hmm_device

248 watchdog

249 rtc

250 dax

251 dimmctl

252 ndctl

253 tpm

254 gpiochip

 

在代码中将SECOND_MAJOR修改成260. 编译后再插入就没问题了.

 

执行命令sudo mknod /dev/second c 260 0 创建一个设备

 


 


 

然后另外创建一个文件创建一个while循环不停的读/dev/second设备.这样就能不停的触发second_read获取econd_devp->counter的值

int main()
{
    int fd;
    int counter=0;
    int old_counter=0;
    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
",counter);
                old_counter=counter;
            }
        }
    }
    else{
        printf("open /dev/second failure
");
    }
    return 1;
}

test@test:~/vs_code_prj$ ./test

seconds after open /dev/second:1

seconds after open /dev/second:2

seconds after open /dev/second:3

seconds after open /dev/second:4

seconds after open /dev/second:5

seconds after open /dev/second:6

seconds after open /dev/second:7

seconds after open /dev/second:8

seconds after open /dev/second:9

seconds after open /dev/second:10

seconds after open /dev/second:11

seconds after open /dev/second:12

seconds after open /dev/second:13

 

 

 

 

 



原文地址:https://www.cnblogs.com/zhanghongfeng/p/12358705.html