字符驱动剖析----cdev(基本知识1)

cdev是linux用来管理字符设备的结构体,其在内核中采用数组结构设计,这样系统中有多少个主设备号就约定了数组大小,此设备号采用链表管理,同一主设备号下可以有多个子设备。设备即文件,上层应用要访问设备,必须通过文件,cdev中包含file_operations结构体,该结构体就是驱动的文件操作集合。

cdev.h位于    /usr/src/linux-headers-4.15.0-55/include/linux 

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CDEV_H
#define _LINUX_CDEV_H

#include <linux/kobject.h>
#include <linux/kdev_t.h>
#include <linux/list.h>
#include <linux/device.h>

struct file_operations;
struct inode;
struct module;

struct cdev {
	struct kobject kobj;
	struct module *owner;
	const struct file_operations *ops;
	struct list_head list;
	dev_t dev;
	unsigned int count;
} __randomize_layout;

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

struct cdev *cdev_alloc(void);

void cdev_put(struct cdev *p);

int cdev_add(struct cdev *, dev_t, unsigned);

void cdev_set_parent(struct cdev *p, struct kobject *kobj);
int cdev_device_add(struct cdev *cdev, struct device *dev);
void cdev_device_del(struct cdev *cdev, struct device *dev);

void cdev_del(struct cdev *);

void cd_forget(struct inode *);

#endif

在开始编写驱动前,还需要学习一下驱动程序操作时一个重要的数据结构,file_operations。

在获取了一些设备编号后,我们还没有将任何驱动程序操作连接到这些编号,file_operations结构就是用来建立这种连接的。

位置: /usr/src/linux-headers-4.15.0-55/include/linux

struct iov_iter;

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 *);
	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 (*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);
} __randomize_layout;
struct file_operations { 
 
    struct module *owner;//拥有该结构的模块的指针,一般为THIS_MODULES 
 
 
    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 (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的读取操作 
 
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的写入操作 
 
    int (*readdir) (struct file *, void *, filldir_t);//仅用于读取目录,对于设备文件,该字段为NULL 
 
    unsigned int (*poll) (struct file *, struct poll_table_struct *); //轮询函数,判断目前是否可以进行非阻塞的读写或写入 
 
    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //执行设备I/O控制命令 
 
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系统,将使用此种函数指针代替ioctl 
 
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系统上,32位的ioctl调用将使用此函数指针代替 
 
 
    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 *, struct dentry *, int datasync); //刷新待处理的数据 
 
    int (*aio_fsync) (struct kiocb *, int datasync); //异步刷新待处理的数据 
 
    int (*fasync) (int, struct file *, int); //通知设备FASYNC标志发生变化 
 
    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 **); 
 
};

__user字符

它其实是一种形式的文档而已,表明指针是一个用户空间地址,因此不能被直接引用。对通常的编译来将,__user没有任何效果,但是可由外部检查软件使用,用来寻找对用户空间的错误使用。

发布了165 篇原创文章 · 获赞 26 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_42269817/article/details/103889281
今日推荐