20150220 IMX257 linux设备驱动之Cdev结构

20150220 IMX257 linux设备驱动之Cdev结构

2015-02-20 21:17 李海沿

一、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_operationscdev初始化时与之绑定  
  11.     struct list_head list;  
  12.     dev_t dev;  //主设备号24 与次设备号8位,dev_t32位整形  
  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) (intstruct file *, int);  
  23.     int (*lock) (struct file *, intstruct file_lock *);  
  24.     ssize_t (*sendpage) (struct file *, struct page *, intsize_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 *, intstruct 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 *, longstruct 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 <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/errno.h>
  5 #include <linux/types.h>
  6 #include <linux/fcntl.h>
  7 #include <linux/cdev.h>
  8 #include <linux/version.h>
  9 #include <linux/vmalloc.h>
 10 #include <linux/ctype.h>
 11 #include <linux/pagemap.h>
 12 #include <linux/device.h>
 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;    //重定位到文件开头
 89         case 1: pos += off;    break;    //偏移off
 90         default: return -EINVAL;
 91     }
 92     if((pos > MEM_SIZE) || (pos < 0))
 93         return -EINVAL;
 94     filp->f_pos = pos;    //修改文件指针
 95     return filp->f_pos;
 96 }
 97 
 98 static void key_exit_module(void){
 99     if(key_device){
100         cdev_del(&key_device->cdev);//删除CDEV结构体
101         kfree(key_device);            //释放cdev申请的内存
102     }
103     //卸载设备
104     unregister_chrdev_region(MKDEV(KEY_MAJOR,KEY_MINOR),1);
105     device_unregister(drv_class_dev);
106     class_destroy(drv_class);
107 }
108 
109 static struct file_operations key_fops = {
110     .owner = THIS_MODULE,
111     .llseek = key_llseek,
112     .read  = key_read,
113     .write = key_write,
114     .ioctl = key_ioctl,
115     .open = key_open,
116     .release = key_release,
117 };
118 
119 static int key_init_module(void){
120     int ret;
121     ret = register_chrdev_region(MKDEV(KEY_MAJOR,KEY_MINOR),1,"key_cdev");
122     if(ret < 0){
123         printk("<0>error:can‘t get major %d\n\n",KEY_MAJOR);
124         return ret;
125     }
126     drv_class = class_create(THIS_MODULE,Driver_NAME);
127     drv_class_dev = device_create(drv_class,NULL,MKDEV(KEY_MAJOR,KEY_MINOR),NULL,DEVICE_NAME);  /*/dev/key_query*/
128     //分配cdev结构体内存
129     key_device = kmalloc(sizeof(struct key_dev),GFP_KERNEL);
130     if(!key_device){
131         ret = -ENOMEM;
132         goto fail;
133     }
134     //格式化分配的内存
135     memset(key_device,0,sizeof(struct key_dev));
136     //初始化cdev结构,将fops和cdev连接
137     cdev_init(&key_device->cdev,&key_fops);
138     key_device->cdev.owner = THIS_MODULE;
139     key_device->cdev.ops = &key_fops;
140     //注册cdev进入内核
141     ret = cdev_add(&key_device->cdev,MKDEV(KEY_MAJOR,KEY_MINOR),1);
142     if(ret){
143         printk("<0>error in cdev adding %d\n\n",ret);
144         goto fail;
145     }
146     return 0;
147 fail:
148     key_exit_module();
149     return ret;
150 }
151 
152 module_init(key_init_module);
153 module_exit(key_exit_module);
154 
155 MODULE_AUTHOR("Lover雪儿");
156 MODULE_LICENSE("Dual BSD/GPL");
View Code

 

附上应用程序:

技术分享
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <fcntl.h>
 5 #include <sys/types.h>
 6 #include <linux/rtc.h>
 7 #include <linux/ioctl.h>
 8 #include "mx257_gpio.h"
 9 
10 #define COMMAND1 1
11 #define COMMAND2 2
12 
13 int main(int argc, char **argv)
14 {
15     int ret;
16     int fd;
17     unsigned char key_data[256] = {0};
18     
19     fd = open("/dev/cdev",O_RDWR);
20     if(fd < 0){
21         printf("can‘t open !!!\n");
22         exit(-1);
23     }
24     printf("open /dev/cdev succefully\n");
25     ioctl(fd,COMMAND1,0);
26     //while(1){
27         lseek(fd,0,0);    //将文件指针重定位到文件的开头
28         write(fd,"hello,Lover雪儿",sizeof("hello,Lover雪儿"));
29         lseek(fd,0,0);    //将文件指针重定位到文件的开头
30         read(fd,key_data,sizeof("hello,Lover雪儿"));
31         printf("read successfully: \n%s\n\n",key_data);    
32     //}
33     close(fd);
34     return 0;
35 }
View Code

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。