目录
3 struct cdev与const struct file_operations之间的关系
1.什么是字符设备
字符设备是指只能一个一个字节进行读写操作的设备,不能随机读取设备中的每一个数据,取数据要
按照先后次序来进行,字符设备时面向流的设备,常见的字符设备有:
鼠标,
键盘,
串口,
控制台,
led等.
一般每一个字符设备或者块设备都会在dev目录下对应一个设备文件,Linux用户层程序通过设备文件来使用
驱动程序,操作字符设备或者块设备.
2.如何来描述字符设备
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\include\linux\types.h
typedef unsigned int __u32;
typedef __u32 __kernel_dev_t;
typedef __kernel_dev_t dev_t;
问题:为什么不直接写成 typedef unsigned int dev_t;
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\include\linux\cdev.h
struct cdev {
struct kobject kobj; // 内嵌的内核对象
struct module *owner;// 该字符设备所在的内核模块(所有者)的对象指针
const struct file_operations *ops;// 字符设备所能实现的操作表
struct list_head list;// 用来将已经向内核注册的所有字符设备形成链表
dev_t dev;//字符设备的设备号,由主设备号和次设备号构成(如果是一次申请多个设备号,此设备号为第一个),主设备号12位,次设备号20位
unsigned int count; // 隶属于同一主设备号的次设备号的个数
} __randomize_layout;
3 struct cdev与const struct file_operations之间的关系
4.struct file_operations源码
E:\004-代码\002-内核源码\linux-4.15.1\linux-4.15.1\include\linux\fs.h
construct 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 *);
int (*iterate_shared) (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 *);
unsigned long mmap_supported_flags;
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 (*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
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);
} __randomize_layout;
从源码中可以看出,每个字段都是一个函数,都是指向VFS层所调用的系统调用所对应的函数.
5.字符设备驱动框架
6.编写字符设备驱动的步骤
cdev_alloc()--动态申请或构造cdev内存
cdev_init() --初始化函数,初始化cdev的成员并且建立起cdev与file_operations之间的关联关系
cdev_add() --注册cdev设备对象,也就是添加cdev对象到字符设备列表中
cdev_del() --将cdev对象从系统中删除,也就是注销
cdev_put() --释放cdev内存
设备号的申请与释放
一个字符设备或者一个块设备都有一个主设备号和一个次设备号,主设备号用来标识与设备文件相连的
驱动程序,用来反映设备的类型,次设备号被驱动程序用来辨别操作的到底是哪一个设备,用来区分同类
型的设备,在这里给出三个宏和三个函数分别从设备号中提取主设备号和次设备号,将主设备号和次设
备号拼凑成设备号,静态地申请设备号,动态地申请设备号以及释放设备号.
7.字符设备结构
问题:struct char_device_struct与struct cdev有什么关系?
8.字符设备驱动程序的注册
这个cdrdevs就是字符设备表.
9.从系统调用到驱动程序
10.用户空间与内核空间数据的传送
11.参考资料与思考问题