linux device drivers 读书笔记(第三章)

来源:互联网 发布:域名注册查询软件 编辑:程序博客网 时间:2024/05/22 04:41

scull的design

(举了一个具体的scull字符设备的例子)

主从设备号

字符设备是通过文件系统中的名字进入的,
而在相应目录下使用ls -l可以看到有两个数字,分别是主从号
主号表明设备相应的驱动,而从号表示具体哪个设备被指向.

设备号的内部表示

dev_t类型定义于

MAJOR(dev_t dev);MINOR(dev_t dev);//分别得到主从设备号
MKDEV(int major, int minor);//通过主从设备号得到一个dev_t

分配和释放一个设备号

驱动需要做的第一件事就是获得一个或多个设备号来使用
相应的函数定义在

int register_chrdev_region(dev_t first, unsigned int count, char *name);

first是逆向分配的设备号数字的范围的第一个设备号,一般从设备号部分是0.count是你请求的连续设备号的总数,name是和分配的设备号范围相应的设备名,分配成功返回0,否则返回负数错误代码.

这个函数用于你知道你想分配什么设备号,否则使用另外一个函数进行动态分配

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);

firstminor是第一个需要用的从设备号,一般是0.dev_t是输出,如果分配成功,里边即保存的分配后的dev_t.

取消分配是用另外一个函数

voidunregistered_传入的_region(dev_t first, unsigned int count);

动态分配主设备号

由于一些设备号可能已经被使用,所以我们一般使用动态分配的方法,不过这样意味着我们无法提前创建设备节点,因为主设备号是可变的.所以动态分配后我们需要从/proc/devices中获取信息,创建特殊的文件

一些重要的数据结构

File operations 文件操作

用来指明驱动的操作,在linux/fs.h中定义,每一个域指明一个操作,指向一个函数.

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 (*setfl)(struct file *, unsigned long);    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    ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,            loff_t, size_t, unsigned int);    int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,            u64);    ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,            u64);};

file结构

同样在linux/fs.h中定义,表示一个打开的文件,注意和用户空间FILE区分.在open时被创建,然后在其他操作时被传入

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 */

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#if IS_ENABLED(CONFIG_FS_ENCRYPTION)    struct fscrypt_info *i_crypt_info;#endif    void            *i_private; /* fs or device private pointer */};

字符设备注册

内核使用结构体cdev来表示字符设备,在内核调用你的设备的操作之前,你必须分配和注册一个或多个这些结构.在

struct cdev *my_cdev = cdev_alloc();my_cdev -> ops = &my_ops;

也可以用已经有的自己的cdev来存储一个分配的cdev

void cdev_init(struct cdev *cdev, struct file_operations *fops);

最后需要

int cdev_add(struct cdev *dev, dev_t num, unsigned int count);

count是设备关联的设备号的数量

移除一个字符设备

void cdev_del(struct cdev *dev);

open和release

open方法

原型

int (*open)(struct inode *inode, struct file *filep);

用来进行初始化操作,表明打开了一个设备

release方法

做一些结束之后的操作

read和write

read和write负责和应用程序交互数据,
原型

ssize_t read(struct file *filep, char __user *buff, size_t count, loff_t *offp);ssize_t write(struct file *filep, const char __user *buff, size_t count, loff_t *offp);

filep是文件指针,count是数量,offp表明文件位置.

对于和用户空间内存的交互,我们需要使用一些特殊的函数,定义于

unsigned long copy_to_user(void __user *to, const void *from, unsigned long count);unsigned long copy_from_user(void *to, const void __user *from, unsigned long count);

它们和memcpy用途一样,不过都保证了用户空间和内核空间的内存交互是安全的.当地址空间无效的时候,copy将不会发生

readv和writev

是read和write的两个vector版本,用来依次处理一定数量的read和write
原型

ssize_t (*readv) (struct file *filp, const struct iovec *iov, unsigned long count, loff_t *ppos);ssize_t (*writev) (struct file *filp, const struct iovec *iov, unsigned long count, loff_t *ppos);

iovec是在

struct iovec {void __user *iov_base;//需要传输的数据的开始,在用户空间__kernel_size_t iov_len;//长度}
0 0
原创粉丝点击