您的位置:首页 > 其它

使用内核定时器的second字符设备驱动

2015-04-21 17:38 501 查看
second.c:

#include<linux/kernel.h>

#include<linux/module.h>

#include<linux/fs.h>  //file_operations

#include<linux/types.h> //dev_t

#include<linux/cdev.h>

#include<linux/slab.h> //kcalloc

#include<linux/uaccess.h> //copy_to_user,copy_from_user

#include<linux/interrupt.h>//中断

#include<linux/timer.h>

#define SECOND_MAJOR 112

static int second_major = SECOND_MAJOR;

//second设备结构体

struct second_dev{

    struct cdev cdev;

    atomic_t counter; //一共经历了多少秒

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

};

struct second_dev *second_devp;

//定时器处理函数

static void second_timer_handle(unsigned long arg){

    mod_timer(&second_devp->s_timer,jiffies + HZ);  //修改定时器的到期时间

    atomic_inc(&second_devp->counter);  //经历时间+1秒

    printk(KERN_NOTICE "current jiffies is %ld\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;

4000
    //添加(注册)定时器

    add_timer(&second_devp->s_timer);

    //计数清零

    atomic_set(&second_devp->counter,0);

    return 0;

}

//文件释放函数

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

    del_timer(&second_devp->s_timer);

    return 0;

}

//读函数

static ssize_t second_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos){

    int counter;

    counter = atomic_read(&second_devp->counter); //atomic原子

    //相对于copy_to_user和copy_from_user,这两个函数主要用于完成一些简单类型变量(char、int、long等)的拷贝任务

    //对于一些复合类型的变量,比如数据结构或者数组类型,get_user和put_user函数还是无法胜任

    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,

};

//初始化并注册cdev

static void second_setup_cdev(struct second_dev *dev,int index){

    int err,devno = MKDEV(second_major,index);

    cdev_init(&dev->cdev,&second_fops); //cdev初始化并关联fops

    dev->cdev.owner = THIS_MODULE;

    dev->cdev.ops = &second_fops;

    err = cdev_add(&dev->cdev,devno,1);  //添加设备

    if(err)

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

}

//设备驱动模块加载函数

static __init int second_init(void){ //必须有void !!!!!

    int ret;

    dev_t devno = MKDEV(second_major,0); //此设备号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(struct second_dev),GFP_KERNEL);

    if(!second_devp){ //失败

        ret = - ENOMEM;

        goto fail_malloc;

    }

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

    second_setup_cdev(second_devp,0);

    return 0;

    fail_malloc:unregister_chrdev_region(devno,1);

    return ret;

}

//模块卸载函数

void second_exit(void){  //必须要有void !!!!!!!!!

    cdev_del(&second_devp->cdev);  //删除设备

    kfree(second_devp);

    unregister_chrdev_region(MKDEV(second_major,0),1);

}

MODULE_AUTHOR("ZHYANG");

MODULE_LICENSE("Dual BSD/GPL");

module_param(second_major,int,S_IRUGO);

module_init(second_init);

module_exit(second_exit);

test_second.c:

#include<stdio.h>

#include<fcntl.h>

int main(){

    int fd;

    int counter=0;

    int old_counter = 0;

    //打开/dev/second设备文件

    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 open failure\n");

    close(fd);

}

以上代码在3内核版本中测试通过




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: