0
点赞
收藏
分享

微信扫一扫

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. struct cdev {  
  6.     struct kobject kobj;  
  7.     struct module *owner;   //一般初始化为:THIS_MODULE  
  8.     const struct file_operations *ops;   
  9. //字符设备用到的例外一个重要的结构体file_operations,cdev初始化时与之绑定  
  10.     struct list_head list;  
  11.     dev_t dev;  //主设备号24位 与次设备号8位,dev_t为32位整形  
  12.     unsigned int count;  
  13. };



二、file_operation 结构




  1. /* 
  2. ~/include/linux/fs.h 
  3. */  

  4. struct​ file_operations {  
  5.     ​struct​ module *owner;  
  6.     loff_t (*llseek) (​struct​ file *, loff_t, ​int​);  
  7.     ssize_t (*read) (​struct​ file *, ​char​ __user *, ​size_t​, loff_t *);  
  8.     ssize_t (*write) (​struct​ file *, ​const​ ​char​ __user *, ​size_t​, loff_t *);  
  9.     ssize_t (*aio_read) (​struct​ kiocb *, ​const​ ​struct​ iovec *, unsigned ​long​, loff_t);  
  10.     ssize_t (*aio_write) (​struct​ kiocb *, ​const​ ​struct​ iovec *, unsigned ​long​, loff_t);  
  11.     ​int​ (*readdir) (​struct​ file *, ​void​ *, filldir_t);  
  12.     unsigned ​int​ (*poll) (​struct​ file *, ​struct​ poll_table_struct *);  
  13.     ​long​ (*unlocked_ioctl) (​struct​ file *, unsigned ​int​, unsigned ​long​);  
  14.     ​long​ (*compat_ioctl) (​struct​ file *, unsigned ​int​, unsigned ​long​);  
  15.     ​int​ (*mmap) (​struct​ file *, ​struct​ vm_area_struct *);  
  16.     ​int​ (*open) (​struct​ inode *, ​struct​ file *);  
  17.     ​int​ (*flush) (​struct​ file *, fl_owner_t id);  
  18.     ​int​ (*release) (​struct​ inode *, ​struct​ file *);  
  19.     ​int​ (*fsync) (​struct​ file *, ​int​ datasync);  
  20.     ​int​ (*aio_fsync) (​struct​ kiocb *, ​int​ datasync);  
  21.     ​int​ (*fasync) (​int​, ​struct​ file *, ​int​);  
  22.     ​int​ (*lock) (​struct​ file *, ​int​, ​struct​ file_lock *);  
  23.     ssize_t (*sendpage) (​struct​ file *, ​struct​ page *, ​int​, ​size_t​, loff_t *, ​int​);  
  24.     unsigned ​long​ (*get_unmapped_area)(​struct​ file *, unsigned ​long​, unsigned ​long​, unsigned ​long​, unsigned ​long​);  
  25.     ​int​ (*check_flags)(​int​);  
  26.     ​int​ (*flock) (​struct​ file *, ​int​, ​struct​ file_lock *);  
  27.     ssize_t (*splice_write)(​struct​ pipe_inode_info *, ​struct​ file *, loff_t *, ​size_t​, unsigned ​int​);  
  28.     ssize_t (*splice_read)(​struct​ file *, loff_t *, ​struct​ pipe_inode_info *, ​size_t​, unsigned ​int​);  
  29.     ​int​ (*setlease)(​struct​ file *, ​long​, ​struct​ file_lock **);  
  30.     ​long​ (*fallocate)(​struct​ file *file, ​int​ mode, loff_t offset,  
  31.               loff_t len);  
  32. };  



三、为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结构体

20150220  IMX257  linux设备驱动之Cdev结构_#define

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


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

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

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

20150220  IMX257  linux设备驱动之Cdev结构_linux_02


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

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

20150220  IMX257  linux设备驱动之Cdev结构_#define_03


4.释放cdev内存

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

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

20150220  IMX257  linux设备驱动之Cdev结构_#define_04


5.编译与测试


20150220  IMX257  linux设备驱动之Cdev结构_#include_05


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

20150220  IMX257  linux设备驱动之Cdev结构_#include_06


附上驱动程序源代码:

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



举报

相关推荐

0 条评论