linux字符设备驱动模型(一)

一、基础概念

1、linux系统将设备分为3种类型:字符设备(如鼠标、键盘等按字节流顺序与系统通信的设备)、块设备(如硬盘、U盘等可以读取指定位置数据的设备)、网络设备(网卡)。

2、设备在系统中被当作一个文件,对设备文件进行操作即是对设备硬件的操作。

3、设备号:使用dev_t(u_long)类型存储,分为主设备号(major)和次设备号(minor)两部分。主设备号使用设备号的高12位表示,次设备号由低20位表示。

4、设备号的分配方式:在构建字符设备之前,先要向系统申请一个或者多个设备号。分配方式有两种,静态和动态。

(1)静态分配:即手动为设备分配设备号,可能造成与其它设备的设备号冲突。

int register_chrdev_region(dev_t from,unsigned count,const char *name)

from是要分配的设备号范围的起始值,一般只提供from的主设备号部分,次设备号部分常设为0;count是需要申请的连续设备号的个数;name是和该范围编号关联的设备名称,该名称不能超过64字节。

(2)动态分配:

int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)

dev为输出参数,函数执行成功后分配的设备号将保存在dev中,如果分配了多个连续的设备号,则dev为分配的第一个设备号;baseminor表示要申请的第一个次设备号,通常设为0;其余参数同上。

(3)设备号的释放:使用上面两种方式分配的设备号,都应该在不使用设备时释放设备号,使用如下函数操作。

void unregister_chrdev_region(dev_t from,unsigned count)

参数意义同上。通常,在模块的卸载函数中调用该函数释放设备号。

二、两个重要的结构体:cdev和file_opterations

1、cdev结构体:linux内核中使用cdev结构体描述字符设备,是所有字符设备的抽象,包含了大量字符设备所共有的特性。

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;

        其中kobj结构用于内核管理字符设备;ops结构是指向file_operations结构体的指针,该结构定义了操作字符设备的函数;list为一双向链表;dev为用来存储所申请的设备号;count表示目前在使用该驱动程序的设备数目,当使用rmmod卸载模块时,如果count成员不为0,则系统不允许卸载该模块。

         每一个字符设备在/dev目录下都有一个设备文件,打开设备文件就相当于打开相应的设备。如应用程序打开一个设备文件A,系统就会生成一个inode结点,内核最终会调用chrdev_open()函数将inode.i_devices添加到相应cdev结构的list中,形成一个新的链表,即表示该设备使用由cdev结构定义的驱动程序。于是就可以使用对应cdev中的ops指针中的相应操作函数(open、read、write、close、seek、ioctl等)对该设备进行操作。

cdev与inode结构体的关系如图所示:

cdev结构体与inode结构体的关系


2、file_operations:是一个对设备进行操作的抽象结构体。

         linux内核允许为设备建立一个设备文件,对设备文件的所有操作,就相当于对设备的操作,这样的好处是,用户程序可以使用访问普通文件的方式访问设备文件,进而访问设备。这种方法使得开发者不必去熟悉新的驱动接口就能访问设备。对普通文件的访问,常使用open()、read()、write()、close()、ioctl()等方法,对设备文件的访问,同样可以使用这些方法,这些调用最终会调用file_operations结构中对应的操作函数。对开发者来说,只要为不同的设备编写不同的操作函数就可以了。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 (*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);
}

其中owner成员为指向拥有该结构模块的指针,该成员用来维持模块的引用计数,当模块还在使用时,不能用rmmod卸载模块。其它函数指针则顾名思义很容易理解。

cdev与file_operations结构体的关系如下图所示:

cdev与file_operations

        

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值