20150220 IMX257 linux设备驱动之Cdev结构
2015-02-20 21:17 李海沿
一、CDEV结构
|
二、file_operation 结构
|
三、为cdev申请内存
接下来,我们就需要为cdev申请内存,然后再通过cdev_init 函数将cdev与file_operation结构体联系起来,
|
最后通过cdev_add函数,将cdev添加到内核中
|
四、实例解析
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");
附上应用程序:
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 }