分类: LINUX
2018-09-15 14:42:01
原文地址:linux驱动之--cdev 作者:小米拍客光
前面写到如何向系统申请一个设备号,设备号就像我们的身份证号一样,号本身并没有什么特殊的意义,只有把这个号和人对应才有意义,通用设备号也需要和一个特殊的东西对于,这就是cdev, cdev是linux下抽象出来的一个用来描述一个字符设备的结构体,在linux下定义如下:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
结构体中有几个成员事我们写驱动的时候必须关心的:
dev 类型是dev_t,也就是我们的设备号
ops是一个同样也是一个结构体并且是一个字符驱动实现的主体,字符驱动通常需要和应用程序交互,在学linux系统编程的时候,都会讲到linux 应用程序通过系统调用陷入到内核空间,从而执行内核代码,而驱动作为内核的一部分同样也是需要在内核空间执行的,ops也就是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 (*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);
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 **);
long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);
};
我们在驱动中要做的事情就是申请一个cdev并把cdev注册到系统中去,操作cdev的函数有:
void cdev_init(struct cdev *, const struct file_operations *);
struct cdev *cdev_alloc(void);
int cdev_add(struct cdev *, dev_t, unsigned);
void cdev_del(struct cdev *);
1、cdev的定义
cdev的定义有两种方式一种是:struct cdev cdev;另外一种是:strcut cdev cdev;cdev = cdev_alloc();
2、cdev的初始化
cdev_init实现cdev的初始化,主要的工作是将我们定义好的file_operaionts与cdev关联起来,file_operations的实现根据实际需求来实现,后面详细介绍。
3、cdev的注册
cdev_add实现cdev的注册,linux内核里维护了一个cdev_map的表,所谓cdev的注册就是把我们的cdev注册到cdev_map表上,cdev_map表结构如图:
4、设备的删除
cdev_del 将我们的cdev从cdev_map中移除。