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
  • 相关阅读:
    windows中dos命令指南
    HDU 2084 数塔 (dp)
    HDU 1176 免费馅饼 (dp)
    HDU 1004 Let the Balloon Rise (map)
    变态杀人狂 (数学)
    HDU 2717 Catch That Cow (深搜)
    HDU 1234 开门人和关门人 (模拟)
    HDU 1070 Milk (模拟)
    HDU 1175 连连看 (深搜+剪枝)
    HDU 1159 Common Subsequence (dp)
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4297149.html
Copyright © 2011-2022 走看看