• 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

     

     

     

     

     

    
    
    
    
  • 相关阅读:
    Easyui datagrid行内【添加】、【编辑】、【上移】、【下移】
    使用dynamic linq 解决自定义查询的若干弊端
    用CS的思维可以指导BS的项目吗?
    那些让 Web 开发者们深感意外的事情
    asp.net实现access数据库分页
    那些相见恨晚的 JavaScript 技巧
    Javascript的执行过程详细研究
    asp.net 遍历文件夹下全部子文件夹并绑定到gridview上
    无废话JavaScript(下)
    asp.net DataTable导出 excel的方法记录(第三方)
  • 原文地址:https://www.cnblogs.com/zhanghongfeng/p/12358705.html
Copyright © 2020-2023  润新知