IMX257 linux设备驱动之Cdev结构

发布时间: 2024-08-15
来源: 电子工程世界

一、CDEV结构

  1. /*  

  2. *内核源码位置  

  3. *linux2.6.38/include/linux/cdev.h  

  4. */  

  5.     

  6. struct cdev {  

  7.     struct kobject kobj;  

  8.     struct module *owner;   //一般初始化为:THIS_MODULE  

  9.     const struct file_operations *ops;   

  10. //字符设备用到的例外一个重要的结构体file_operations,cdev初始化时与之绑定  

  11.     struct list_head list;  

  12.     dev_t dev;  //主设备号24位 与次设备号8位,dev_t为32位整形  

  13.     unsigned int count;  

  14. };

 

二、file_operation 结构

  1. /* 

  2. ~/include/linux/fs.h 

  3. */  

  4.     

  5. struct file_operations {  

  6.     struct module *owner;  

  7.     loff_t (*llseek) (struct file *, loff_t, int);  

  8.     ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);  

  9.     ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);  

  10.     ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);  

  11.     ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);  

  12.     int (*readdir) (struct file *, void *, filldir_t);  

  13.     unsigned int (*poll) (struct file *, struct poll_table_struct *);  

  14.     long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);  

  15.     long (*compat_ioctl) (struct file *, unsigned int, unsigned long);  

  16.     int (*mmap) (struct file *, struct vm_area_struct *);  

  17.     int (*open) (struct inode *, struct file *);  

  18.     int (*flush) (struct file *, fl_owner_t id);  

  19.     int (*release) (struct inode *, struct file *);  

  20.     int (*fsync) (struct file *, int datasync);  

  21.     int (*aio_fsync) (struct kiocb *, int datasync);  

  22.     int (*fasync) (int, struct file *, int);  

  23.     int (*lock) (struct file *, int, struct file_lock *);  

  24.     ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);  

  25.     unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);  

  26.     int (*check_flags)(int);  

  27.     int (*flock) (struct file *, int, struct file_lock *);  

  28.     ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);  

  29.     ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);  

  30.     int (*setlease)(struct file *, long, struct file_lock **);  

  31.     long (*fallocate)(struct file *file, int mode, loff_t offset,  

  32.               loff_t len);  

  33. };  

 

三、为cdev申请内存

接下来,我们就需要为cdev申请内存,然后再通过cdev_init 函数将cdev与file_operation结构体联系起来,

  1. void cdev_init(struct cdev *cdev, const struct file_operations *fops)  

  2. {  

  3.     memset(cdev, 0, sizeof *cdev);  

  4.     INIT_LIST_HEAD(&cdev->list);  

  5.     kobject_init(&cdev->kobj, &ktype_cdev_default);  

  6.     cdev->ops = fops;  

  7. }  

 

最后通过cdev_add函数,将cdev添加到内核中

  1. int cdev_add(struct cdev *p, dev_t dev, unsigned count)  

  2. {  

  3.     p->dev = dev;  

  4.     p->count = count;  

  5.     return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);  

  6. }  

 

四、实例解析

1.自定义一个cdev结构体

如图所示,上述代码中,先自定义一个简单的cdev结构体key_dev,然后再实例化key_device, 接下来就定义一个我们接下来要操作的数组key_buff[MEM_SIZE],MEM_SIZE为自定义的内存的大小。

 

2.在init函数中初始化cdev结构体

当我们的应用程序调用open函数打开设备时,

在init函数中初始化cdev结构体,为cdev结构体开辟内存,连接cdev与fops结构体,注册cdev进入内核

 

3.一旦注册入内核,我们就可以开始使用了

当我们的应用程序打开设备时,在open函数中将filp的private_data赋值为我们所分配的key_device的结构体

 

4.释放cdev内存

当我们不用驱动时自然就要释放我们刚刚开辟的内存。

如图所示,首先删除cdev结构体,然后再使用kfree来释放cdev释放申请的内存

 

5.编译与测试

 

 

如图所示,我们在应用程序中先使用write函数往数组中写入'hello,Lover雪儿'的字符串,然后再使用read函数读取内容,但是,必须注意一点,在每次read后者write前,必须先使用lseek函数中重定位指针。

附上驱动程序源代码:

  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 

 14 #define DEVICE_NAME    'cdev'

 15 #define Driver_NAME 'key_cdev'

 16 

 17 #define KEY_MAJOR 220

 18 #define KEY_MINOR 0

 19 #define COMMAND1 1

 20 #define COMMAND2 2

 21 #define MEM_SIZE 256

 22 

 23 struct key_dev {

 24         struct cdev cdev;

 25 };

 26 struct key_dev *key_device;

 27 static unsigned char key_buff[MEM_SIZE];

 28 

 29 //auto to create device node

 30 static struct class *drv_class = NULL;

 31 static struct class_device *drv_class_dev = NULL;

 32 

 33 static int key_open(struct inode *inode,struct file *filp){

 34     filp->private_data = key_device;

 35     return 0;

 36 }

 37 

 38 static int key_release(struct inode* inode,struct file *filp){

 39     return 0;

 40 }

 41 

 42 static ssize_t key_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){

 43     ssize_t ret = 0;

 44     loff_t pos = *f_pos;

 45     if(pos > MEM_SIZE)    //如果文件指针偏移超出文件大小

 46         return ret = 0;

 47     if(count > (MEM_SIZE - pos))

 48         count = 256 - pos;    //若内存不足,则写到内存满的位置

 49     pos += count;

 50     //读出数据

 51     if(copy_to_user(buf,key_buff + *f_pos,count)){

 52         return ret = -EFAULT;

 53     }

 54     *f_pos = pos;

 55     return count;

 56 }

 57 

 58 static ssize_t key_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){

 59     ssize_t ret = -ENOMEM;

 60     loff_t pos = *f_pos;        //获取当前文件指针偏移

 61     if(pos > MEM_SIZE)    //如果文件指针偏移超出文件大小

 62         return ret;

 63     if(count > (MEM_SIZE - pos))

 64         count = 256 - pos;    //若内存不足,则写到内存满的位置

 65     pos += count;

 66     //从fops处开始写入数据

 67     if(copy_from_user(key_buff + *f_pos,buf,count)){

 68         ret = -EFAULT;

 69         return ret;

 70     }

 71     *f_pos = pos;

 72     return count;

 73 }

 74 

 75 static int key_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){

 76     switch(cmd){

 77         case COMMAND1: printk('<0>ncommand 1 n'); break;

 78         case COMMAND2: printk('<0>ncommand 2 n'); break;

 79         default: printk('<0>command default n'); break;

 80     }

 81     return 0;

 82 }

 83 

 84 static loff_t key_llseek(struct file *filp, loff_t off, int whence){

 85     loff_t pos;

 86     pos = filp->f_pos;    //获取文件指针当前位置

 87     switch(whence){

 88         case 0: pos = off;    break;    //重定位到文件开头

文章来源于: 电子工程世界 原文链接

本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。