zoukankan      html  css  js  c++  java
  • Linux驱动开发2——字符设备驱动

    1、申请设备号

    #include <linux/fs.h>
    
    int register_chrdev_region(dev_t first, unsigned int count, char *name);
    静态分配字符设备号,从fist开始的count个,name为设备名称(name会出现在/proc/devices和sysfs中),成功返回0,失败返回一个负的错误码
    
    int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
    动态分配字符设备号,主设备号动态分配,次设备号从firstminor开始的count个,name为设备名称(动态分配的主设备号可以在/proc/devices中获取)
    
    void unregister_chrdev_region(dev_t first, unsigned int count);
    注销字符设备号,从first开始的count个

    2、初始化字符设备

    #include <linux/cdev.h>
    
    动态创建
    struct cdev *my_cdev = cdev_alloc();
    my_cdev->ops = &my_fops;
    
    静态创建
    void cdev_init(struct cdev *cdev, struct file_operations *fops);

    3、添加和删除字符设备

    #include <linux/cdev.h>
    
    添加字符设备
    int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
    
    删除字符设备
    void cdev_del(struct cdev *dev);

     4、关键数据结构

    4.1、file_operations结构体

    struct file_operations {
            struct module *owner;
            loff_t (*llseek) (struct file *, loff_t, int);
            ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
            ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
            ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
            ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
            int (*iterate) (struct file *, struct dir_context *);
            unsigned int (*poll) (struct file *, struct poll_table_struct *);
            long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
            long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
            int (*mmap) (struct file *, struct vm_area_struct *);
            int (*open) (struct inode *, struct file *);
            int (*flush) (struct file *, fl_owner_t id);
            int (*release) (struct inode *, struct file *);
            int (*fsync) (struct file *, loff_t, loff_t, int datasync);
            int (*aio_fsync) (struct kiocb *, int datasync);
            int (*fasync) (int, struct file *, int);
            int (*lock) (struct file *, int, struct file_lock *);
            ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
            unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
            int (*check_flags)(int);
            int (*flock) (struct file *, int, struct file_lock *);
            ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
            ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
            int (*setlease)(struct file *, long, struct file_lock **, void **);
            long (*fallocate)(struct file *file, int mode, loff_t offset,
                              loff_t len);
            void (*show_fdinfo)(struct seq_file *m, struct file *f);
    #ifndef CONFIG_MMU
            unsigned (*mmap_capabilities)(struct file *);
    #endif
    };

     4.2、file结构体

    struct file {
            union {
                    struct llist_node       fu_llist;
                    struct rcu_head         fu_rcuhead;
            } f_u;
            struct path             f_path;
            struct inode            *f_inode;       /* cached value */
            const struct file_operations    *f_op;
    
            /*
             * Protects f_ep_links, f_flags.
             * Must not be taken from IRQ context.
             */
            spinlock_t              f_lock;
            atomic_long_t           f_count;
            unsigned int            f_flags;
            fmode_t                 f_mode;
            struct mutex            f_pos_lock;
            loff_t                  f_pos;
            struct fown_struct      f_owner;
            const struct cred       *f_cred;
            struct file_ra_state    f_ra;
    
            u64                     f_version;
    #ifdef CONFIG_SECURITY
            void                    *f_security;
    #endif
            /* needed for tty driver, and maybe others */
            void                    *private_data;
    
    #ifdef CONFIG_EPOLL
            /* Used by fs/eventpoll.c to link all the hooks to this file */
            struct list_head        f_ep_links;
            struct list_head        f_tfile_llink;
    #endif /* #ifdef CONFIG_EPOLL */
            struct address_space    *f_mapping;
    } __attribute__((aligned(4)));  /* lest something weird decides that 2 is OK */

    4.3、inode结构体

    struct inode {
            umode_t                 i_mode;
            unsigned short          i_opflags;
            kuid_t                  i_uid;
            kgid_t                  i_gid;
            unsigned int            i_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 long           i_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_t                   i_rdev;
            loff_t                  i_size;
            struct timespec         i_atime;
            struct timespec         i_mtime;
            struct timespec         i_ctime;
            spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
            unsigned short          i_bytes;
            unsigned int            i_blkbits;
            blkcnt_t                i_blocks;
    
    #ifdef __NEED_I_SIZE_ORDERED
            seqcount_t              i_size_seqcount;
    #endif
    
            /* Misc */
            unsigned long           i_state;
            struct mutex            i_mutex;
    
            unsigned long           dirtied_when;   /* jiffies of first dirtying */
            unsigned long           dirtied_time_when;
    
            struct hlist_node       i_hash;
            struct list_head        i_io_list;      /* backing dev IO list */
    #ifdef CONFIG_CGROUP_WRITEBACK
            struct bdi_writeback    *i_wb;          /* the associated cgroup wb */
    
            /* foreign inode detection, see wbc_detach_inode() */
            int                     i_wb_frn_winner;
            u16                     i_wb_frn_avg_time;
            u16                     i_wb_frn_history;
    #endif
            struct list_head        i_lru;          /* inode LRU list */
            struct list_head        i_sb_list;
            union {
                    struct hlist_head       i_dentry;
                    struct rcu_head         i_rcu;
            };
            u64                     i_version;
            atomic_t                i_count;
            atomic_t                i_dio_count;
            atomic_t                i_writecount;
    #ifdef CONFIG_IMA
            atomic_t                i_readcount; /* struct files open RO */
    #endif
            const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
            struct file_lock_context        *i_flctx;
            struct address_space    i_data;
            struct list_head        i_devices;
            union {
                    struct pipe_inode_info  *i_pipe;
                    struct block_device     *i_bdev;
                    struct cdev             *i_cdev;
                    char                    *i_link;
            };
    
            __u32                   i_generation;
    
    #ifdef CONFIG_FSNOTIFY
            __u32                   i_fsnotify_mask; /* all events this inode cares about */
            struct hlist_head       i_fsnotify_marks;
    #endif
    
            void                    *i_private; /* fs or device private pointer */
    };

    Linux中一切皆文件,对于字符设备驱动而言,都是通过设备文件进行交互的。Linux内核中,针对每一个文件有一个唯一的inode结构体描述,但是一个文件可以打开多次,所以内核使用file结构体作为文件描述符,每次打开同一个文件,均生成一个新的文件描述符,但是所有的文件描述符都指向同一个inode,表示打开的是同一个文件。inode和file结构体中均有file_operation结构体成员,它就是指向驱动实现的file_operations结构体,为文件操作提供具体实现函数。

    5、container_of宏

    #include <linux/kernel.h>
    
    container_of(pointer, container_type, container_field);

    6、open和release

    6.1、int open(struct inode *inode, struct file *filp);

    open函数中应当进行以下工作:

    1)检查设备特定的错误(如设备未准备好,或者硬件错误)

    2)如果第一次打开,初始化设备

    3)如果需要,更新f_op指针

    4)分配并填充要放入filp_private_data的任何数据结构

    int scull_open(struct inode *inode, struct file *filp)
    {
        struct scull_dev *dev; /* contain cdev member */
    
        dev = contailer_of(inode->i_cdev, struct scull_dev, cdev);
    
        filp->private_data = dev;
    
        return 0;
    }

     6.2、int release(struct inode *inode, struct file *filp);

    release函数应当进行以下工作:

    1)释放open分配在filp->private_data中的任何东西

    2)在最后close关闭设备

    int scull_release(struct inode *inode, struct file *filp)
    {
        return 0;
    }

    7、read和write

    #include <linux/fs.h>
    
    ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp);
    
    ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp);

    8、ioctl

    #include <linux/ioctl.h>

    long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
    long (*compat_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
    cmd - 操作码(四字节,type|nr|direction|size)
    类型:魔数,通常为一个字符,表示特定设备,自定义
    序号:命令序号
    方向:__IOC_NONE|__IOC_READ|__IOC_WRITE
    大小:数据结构大小

          根据方向,可以使用_IO(type,nr)
                         _IOR(type,nr,datatype)
                         _IOW(type,nr,datatype)
          组合生成cmd操作码,size成员通过sizeof(datatype)获取

    反之,可以通过宏解析出cmd操作码的不同字段:
          类型:_IOC_TYPE(cmd)
    方向:_IOC_DIR(cmd)
          序号:_IOC_NR(cmd)
          大小:_IOC_SIZE(cmd)
    arg
    - 可选参数(可以是一个整数或者一个指针)

    返回值:失败返回-ENOTTY或者-ENIVAL给用户

    ioctl函数注册时,需要注意按照以下形式注册:
    struct file_operations globalvar_fops = {
            .owner = THIS_MODULE,
            .open = globalvar_open,
            .release = globalvar_release,
            .read = globalvar_read,
            .write = globalvar_write,
            .unlocked_ioctl = globalvar_ioctl,
    #ifdef CONFIG_COMPAT
            .compat_ioctl   = globalvar_ioctl,
    #endif
    };

    9、access_ok()

    #include <asm/uaccess.h>
    
    检查用户空间地址是否可以存取,成功返回1,失败返回0,失败时,应该给调用者返回-EFAULT错误码
    int access_ok(int type, const void *addr, unsigned long size);
    
    type: VERIFY_READ|VERIFY_WRITE
    addr: 用户空间地址
    size: 大小
  • 相关阅读:
    网站设计中常见的几个错误
    C#的一个小函数来计算一个运算使用的时间和内存
    移动位置社交服务全球热潮日益高涨
    Opera CEO 专访:开源真的那么重要吗?
    N73和蓝牙GPS接收器LD3W----Route66 Mobile7中国版
    激励员工的首席执行官以及他们的秘诀
    2008年智能手机五大发展趋势
    J2EE初学者从这里入门
    Windows Mobile 5.0 开发学习
    手机开发平台指南、教程和资料介绍
  • 原文地址:https://www.cnblogs.com/justin-y-lin/p/10619571.html
Copyright © 2011-2022 走看看