美文网首页
Linux一个驱动中多个设备文件的访问

Linux一个驱动中多个设备文件的访问

作者: 二进制人类 | 来源:发表于2022-11-21 12:07 被阅读0次

    驱动注册的时候,以结点的形式添加到系统中,可以在系统中去找到结点的所有信息:在open操做方法中有struct inode指针参数

    struct inode {
    umode_ti_mode;
    unsigned shorti_opflags;
    uid_ti_uid;
    gid_ti_gid;
    unsigned inti_flags;
    
    #ifdef CONFIG_FS_POSIX_ACL
    struct posix_acl*i_acl;
    struct posix_acl*i_default_acl;
    #endif
    
    const struct inode_operations*i_op;
    struct super_block*i_sb;
    struct address_space*i_mapping;
    
    #ifdef CONFIG_SECURITY
    void*i_security;
    #endif
    
    /* Stat data, not accessed from path walking */
    unsigned longi_ino;
    /*
     * Filesystems may only read i_nlink directly.  They shall use the
     * following functions for modification:
     *
     *    (set|clear|inc|drop)_nlink
     *    inode_(inc|dec)_link_count
     */
    union {
    const unsigned int i_nlink;
    unsigned int __i_nlink;
    };
    dev_ti_rdev;        /* 设备号:获取到主设备号和次设备号 */
    struct timespeci_atime;
    struct timespeci_mtime;
    struct timespeci_ctime;
    spinlock_ti_lock;/* i_blocks, i_bytes, maybe i_size */
    unsigned short          i_bytes;
    blkcnt_ti_blocks;
    loff_ti_size;
    
    #ifdef __NEED_I_SIZE_ORDERED
    seqcount_ti_size_seqcount;
    #endif
    
    /* Misc */
    unsigned longi_state;
    struct mutexi_mutex;
    
    unsigned longdirtied_when;/* jiffies of first dirtying */
    
    struct hlist_nodei_hash;
    struct list_headi_wb_list;/* backing dev IO list */
    struct list_headi_lru;/* inode LRU list */
    struct list_headi_sb_list;
    union {
    struct list_headi_dentry;
    struct rcu_headi_rcu;
    };
    atomic_ti_count;
    unsigned inti_blkbits;
    u64i_version;
    atomic_ti_dio_count;
    atomic_ti_writecount;
    const struct file_operations*i_fop;/* former ->i_op->default_file_ops */
    struct file_lock*i_flock;
    struct address_spacei_data;
    #ifdef CONFIG_QUOTA
    struct dquot*i_dquot[MAXQUOTAS];
    #endif
    struct list_headi_devices;
    union {
    struct pipe_inode_info*i_pipe;
    struct block_device*i_bdev;
    struct cdev*i_cdev;
    };
    
    __u32i_generation;
    
    #ifdef CONFIG_FSNOTIFY
    __u32i_fsnotify_mask; /* all events this inode cares about */
    struct hlist_headi_fsnotify_marks;
    #endif
    
    #ifdef CONFIG_IMA
    atomic_ti_readcount; /* struct files open RO */
    #endif
    void*i_private; /* fs or device private pointer */
    };
    

    获取设备号

    dev_t dev_num = inode_p->i_rdev;    /* 当前打开设备的设备号 */
    主设备号:    MAJOR(dev_num)    一个驱动所管理的一类设备
    次设备号:    MINOR(dev_num)    一个驱动中管理的的多个设备中,当前访问设备的编号。
    

    依据次设备访问设备文件

    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/device.h>
    
    
    static dev_t dev_num;           /* dev_num存储申请成功的设备号 */
    static unsigned int count = 4;  /* 次设备的数量 */
    static struct cdev *cdev_p;     /* 字符设备注册结构体指针 */
    static struct class * class_p;  
    static struct device * device_p;
    
    int my_char_driver_open(struct inode *inode_p, struct file *file_p)
    {
        dev_t my_dev;
    
        my_dev = inode_p->i_rdev;
        printk(KERN_INFO "my char driver open <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));
        
        return 0;
    }
    
    int my_char_driver_release(struct inode *inode_p, struct file *file_p)
    {
        dev_t my_dev;
    
        my_dev = inode_p->i_rdev;
        printk(KERN_INFO "my char driver release <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));
        
        return 0;
    }
    
    const struct file_operations fops = {
        .owner = THIS_MODULE,
        .open = my_char_driver_open,
        .release= my_char_driver_release
    };
    
    /* 定义模块加载入口函数 */
    static int __init my_char_driver_init(void)
    {
        int ret = 0;
    
        register_chrdev_region(dev_t from, unsigned count, const char * name)   
        /* 1. 申请设备号:手动申请(给定主设备号和起始次设备号)/动态申请(返回设备号) */
        ret = alloc_chrdev_region(&dev_num, 0, count, "chrdev");    /* 动态申请设备号 */
        if (ret != 0) {
            goto err0;
        }
    
        /* 2. 注册设备到系统中,由系统统一调度管理 */
        /* 2.1 申请字符设备注册结构体空间*/
        cdev_p = cdev_alloc();
        if (cdev_p == NULL) {
            ret = - ENOMEM;
            goto err1;
        }
    
        /* 2.2 初始化字符数设备结构体空间中的操作方法集 */
        cdev_init(cdev_p, &fops);
    
        /* 2.3 添加字符设备结构体到系统中,由系统统一调度管理 */
        ret = cdev_add(cdev_p, dev_num, count);
        if (ret != 0) {
            goto err2;
        }
    
        /* 3. 创建设备节点(可选:一般都会加上) */
        /* 3.1 创建节点对象 */
        class_p =  class_create(THIS_MODULE, "mychar");
        if (IS_ERR(class_p)) {
            ret = - ENOMEM;
            goto err3;
        }
    
        int i;
        for (i = 0; i < count; i++) {       /* 由于驱动可以管理多个设备文件,需要循环创建设备文件 */
            char drv_name[20] = {0};
            sprintf(drv_name, "mychar%d",i);
            
            /* 3.2 创建设备节点 */
            device_p = device_create(class_p, NULL, MKDEV(MAJOR(dev_num), i), NULL, drv_name);
            if (IS_ERR(device_p)) {
                ret = - ENOMEM;
                goto err4;
            }
        }
    
        printk(KERN_INFO "my char driver : <major: %d, minor: %d> init success\n", MAJOR(dev_num), MINOR(dev_num));
        return 0;
        
    err4:
        /* 释放创建成功的设备节点 */
        for (i--; i >= 0; i--)
            device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
        
        /* 释放设备节点对象 */
        class_destroy(class_p);
    err3:
        
    err2:
        /* 释放字符设备结构体空间 */
        cdev_del(cdev_p);
    err1:
        /* 释放设备号 */
        unregister_chrdev_region(dev_num, count);
    err0:
        return ret;
    }
    
    /* 定义模块卸载入口函数 */
    static void __exit my_char_driver_exit(void)
    {
        /* 释放设备节点 */
        int i;
        for (i = 0; i < count; i++) 
            device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
    
        /* 释放设备节点对象 */
        class_destroy(class_p);
    
        /* 释放字符设备结构体空间 */
        cdev_del(cdev_p);
        
        /* 释放设备号 */
        unregister_chrdev_region(dev_num, count);
        printk(KERN_INFO "my char driver exit success\n");
    }
    
    module_init(my_char_driver_init);       /* 声明模块加载入口函数 */
    module_exit(my_char_driver_exit);       /* 声明模块卸载入口函数 */
    MODULE_LICENSE("GPL");                  /* 许可证明:采用的GPL协议 */
    
    

    相关文章

      网友评论

          本文标题:Linux一个驱动中多个设备文件的访问

          本文链接:https://www.haomeiwen.com/subject/fzuttdtx.html