• 使用内核定时器的秒字符设备


                                             秒字符设备

          秒字符设备也是字符驱动,所以与之前的字符设备驱动程序的框架类似,模块编译,模块加载与卸载也与内核模块的编译,加载卸载一致。秒字符设备驱(second)的实现,创建目录(second),在该目录下创建设备文件(second.c),内容按下面的代码写即可,在同一目录下编写相应的Makefile文件,然后make就可以编译模块了,然后插入模块(可以带参数,如:sudo insmod second.ko second_major=249),设备驱动程序就好了,但是现在在/dev中并没有”second”这个字符设备驱动,必须创建设备节点才行,创建设备节点的命令是:mknod /dev/chardev0 c 250 0其中chardev0是设备名,c说明设备是字符设备,250是主设备号,0是次设备号,这些都要根据自己的设备驱动程序来赋予相应的值(此处为:mknod /dev/second c 249 0)。设备节点创建成功后在/dev中就可以看到自己创建的设备了或者使用ls-l second(设备名)来查看详细信息。

    秒字符设备驱动实现后要进行测试,创建测试文件(test.c)内容按下面的代码写即可。然后编译运行测试文件,就可以看到效果了。

    秒字符设备(second.c)源码:

    #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 249//宏定义主设备号

    static int second_major =SECOND_MAJOR; //模块参数,可以输入主设备号

     

    struct second_dev//second设备结构体

    {

    struct cdev cdev;//cdev结构体

    atomic_t counter;//一共经历的秒数

    struct timer_lists_timer;//设备要使用的定时器

    };

     

    struct second_dev*second_devp; //设备结构体指针

     

    //定时器处理函数

    static voidsecond_timer_handle(unsigned long arg)

    {

    mod_timer(&second_devp->s_timer,jiffies+HZ);

    atomic_inc(&second_devp->counter);//counter1

    printk(KERN_NOTICE "currentjiffies 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->counter,0);//设置counter初值为0

    return 0;

    }

     

    /文件释放

    int second_release(structinode *inode,struct file *filp)

    {

    del_timer(&second_devp->s_timer);//释放定时器

     

    return 0;

    }

     

    //读函数

    static ssize_tsecond_read(struct file *filp,char __user *buf,size_t count,loff_t*ppos)

    {

    int counter;

     

    counter=atomic_read(&second_devp->counter);//获得counter 的当前值

    if(put_user(counter,(int*)buf)) //由于内核空间和用户空间不能直接互访,所以用put_user函数将counter的值从内核复制到用户buf所指的空间。

    return -EFAULT;

    else

    return sizeof(unsigned int);

    }

     

    //文件操作结构体

    static const structfile_operations second_fops =

    {

    .owner=THIS_MODULE,

    .open=second_open,

    .release=second_release,

    .read=second_read

    };

     

    //初始化并注册cdev

    static voidsecond_setup_cdev(struct second_dev *dev,int index)

    {

    interr,devno=MKDEV(second_major,index); //获得主设备号

    cdev_init(&dev->cdev,&second_fops);

    dev->cdev.owner=THIS_MODULE;

    dev->cdev.ops=&second_fops;

    err=cdev_add(&dev->cdev,devno,1);//注册设备号

    if(err)

    printk(KERN_NOTICE "error %dadding led %d",err,index);

    }

     

    //模块加载函数

    intsecond_init(void)

    {

    int ret;

    dev_tdevno=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(structsecond_dev),GFP_KERNEL);

    if(!second_devp)//申请失败

    {

    ret = -ENOMEM;

    goto fail_malloc;

    }

     

    //设置second_devp所指的大小为sizeof(strcutsecond_dev)的内存均为0

    memset(second_devp,0,sizeof(struct second_dev));

    second_setup_cdev(second_devp,0);//初始化并注册cdev

    return 0;

    fail_malloc:unregister_chrdev_region(devno,1);

    }

     

    //模块卸载函数

    voidsecond_exit(void)

    {

    cdev_del(&second_devp->cdev);//注销cdev

    kfree(second_devp);//释放设备结构体内存

    unregister_chrdev_region(MKDEV(second_major,0),1);//释放设备号

    }

     

    MODULE_AUTHOR("wangfangyong");

    MODULE_LICENSE("GPL");

     

    module_param(second_major,int,S_IRUGO);

     

    module_init(second_init);

    module_exit(second_exit);

     

     

    Makefile文件源码:

    obj-m := second.o

    path =/usr/src/linux-headers-$(shell uname -r)

    all:

    make -C $(path) M=$(PWD)modules

    clean:

    make -C $(path) M=$(PWD)clean

     

     

     

    测试文件(test.c)源码:

    #include<stdio.h>

    #include<stdlib.h>

    #include<sys/types.h>

    #include<sys/stat.h>

    #include<unistd.h>

    #include<fcntl.h>

    #include<string.h>

     

    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\n",counter);

    old_counter=counter;

    }

    }

    }

    else

    printf("device openfail\n");

    }

  • 相关阅读:
    能量最小化初探,graphcuts能量最小化调用
    【设计】B 端产品设计
    【产品分析】关于字节跳动的神话与现实
    【UI】数据表格设计
    【设计】交互文档结构
    【作品集】UX作品集
    【产品方法论】需求是怎么来的
    【ML】人脸识别
    【ML】DL的参数量计算
    【网站部署】flask
  • 原文地址:https://www.cnblogs.com/276815076/p/1846039.html
Copyright © 2020-2023  润新知