zoukankan      html  css  js  c++  java
  • 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>
    command 1 
    "); break;
     78         case COMMAND2: printk("<0>
    command 2 
    "); break;
     79         default: printk("<0>command default 
    "); 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
    
    ",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
    
    ",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 !!!
    ");
    22         exit(-1);
    23     }
    24     printf("open /dev/cdev succefully
    ");
    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: 
    %s
    
    ",key_data);    
    32     //}
    33     close(fd);
    34     return 0;
    35 }
    View Code
  • 相关阅读:
    legend3---videojs存储视频的播放速率便于用户观看视频
    legend3---mathjax的动态渲染问题解决
    matplotlib库疑难问题---10、画直方图
    matplotlib库疑难问题---9、画箭头(综合实例)
    js释放图片资源
    javascript中的原型与原型链
    前端跨域方式
    matplotlib清除 axes 和 figure
    matplotlib画直方图细解
    CentOS 7.8 安装 Python 3.8.5
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4297149.html
Copyright © 2011-2022 走看看