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;//长度}
- linux device drivers 读书笔记(第三章)
- Linux Device Drivers读书笔记01-03章
- linux device drivers 读书笔记(第二章)
- linux device drivers 读书笔记(第一章)
- 读书笔记《Linux Device Drivers》:第一章,设备驱动介绍
- 《Essential Linux Device Drivers》 第6章 Serial Drivers
- 《Essential Linux Device Drivers》 第7章 Input Drivers
- 《Essential Linux Device Drivers》 第6章 Serial Drivers
- 《Linux Device Drivers》第三章 字符设备驱动程序——note
- 《Essential Linux Device Drivers》第1章
- 《Essential Linux Device Drivers》第2章
- 《Essential Linux Device Drivers》第3章
- 《Essential Linux Device Drivers》第4章
- 《Essential Linux Device Drivers》第5章
- 《Essential Linux Device Drivers》第6章
- 《Essential Linux Device Drivers》第7章
- 《Essential Linux Device Drivers》第8章
- 《Essential Linux Device Drivers》第1章
- 小波分析解读
- Linux学习笔记 -- day01 基本命令
- RGBD slam 学习, qt 工程环境配置.md
- CF198 div1 D - Iahub and Xors
- 最后一公里极速配送
- linux device drivers 读书笔记(第三章)
- 元组与列表的区别
- hdu 1166 敌兵布阵(线段树+单点更新)
- php使用mcript扩展实现对称加密
- Git_Git本地操作_第3课_Git基本工作流程
- Android实现简单的音乐播放
- Python中实现switch功能
- JSP过滤器---JavaWeb
- java 抽象工厂模式