之前我们说过,Linux设备主要分为三类:字符设备、块设备和网路插口。

字符设备相对于另外两个设备愈发容易理解,同时,这类设备也适宜大多数简单的硬件设备,为此,接出来我们学习一下字符设备驱动。

字符驱动的学习分为两节:先介绍一下字符驱动驱动中的一些概念,这种概念有些在块设备中也是相同的;之后基于系统的显存创建一个字符设备实例。

linux驱动开发项目_linux设备驱动开发详解 源码_linux驱动开发

本节主要介绍一下驱动中的一些概念,主要学会以下内容:

设备号及其相关操作

字符设备一般坐落/dev目录下,通过设备的名称进行访问,这种名称称为设备文件或节点。在/dev目录下,使用ls-l命令来查看系统中的设备情况,部份结果如下:

linux驱动开发项目_linux驱动开发_linux设备驱动开发详解 源码

ls-l查看设备情况

在每行的最上面的有一个字符(c、d、l、b等)红旗linux6.0,其中,c开头的设备表示的就是字符设备。(类似的,b开头的设备表示块设备、d表示是一个目录、l表示是一个联接)

截图中的字符设备为btrfs-control,具体信息如下:

crw-------   1 root    root     10, 234 7月  25 10:45 btrfs-control

其中的:10,234表示的就是设备的设备号linux设备驱动开发详解 源码,10为主设备号(misc字符设备),234为次设备号。

主设备号用于表示设备对应的驱动程序。Linux内核允许多个驱动程序共享主设备号linux设备驱动开发详解 源码,但许多设备依然根据一个设备号对应一个驱动程序的原则组织;次设备号由内核使用linux系统,用于正确确定设备文件所指的设备,借助次设备号可以获取一个指向内核设备的直接表针,也可以将次设备号当作设备本地字段的索引。

在头文件中提供了一个dev_t类型来保存设备号——在2.6.0内核中,dev_t类型是32位的,其中的12位拿来表示主设备号,剩余20位拿来表示次设备号。但我们不要默认永远都是这样实现的,而应当借助中定义的两个宏来获取dev_t所表示的设备号:

MAJOR(dev_t dev); //返回主设备号
MINOR(dev_t dev);  //返回次设备号

同样,当晓得主设备号和次设备号时,也不要自己自动去拼接生成dev_t变量,而应使用以下宏实现:

MKDEV(int major, int minor); //返回dev_t变量

在驱动程序中,对于设备号的相关操作主要是分配和释放,操作函数都在中进行了申明,主要有以下几个函数:

int register_chrdev_region(dev_t first, unsigned int count, char *name);
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
void unregister_chrdev_region(dev_t first, unsigned int count);

对其中的参数进行说明:

register_chrdev_region看名子就晓得是注册设备号,这个函数适用于注册所需设备编号已知的情况下;在大多数情况下,我们是不晓得设备编号的,可以使用alloc_chrdev_region来分配设备编号;unregister_chrdev_region看名子也晓得,是释放注册的设备编号,通常在退出函数中调用。

对于register_chrdev_region和alloc_chrdev_region,强烈建议使用alloc_chrdev_region来分配设备编号,这样可以促使驱动程序适应性更强。

分配设备编号是驱动代码须要完成的第一件事,后续还须要将内部函数和设备编号联接上去。

文件操作相关的数据结构

文件操作相关的数据结构主要是结构体structfile_operations,其定义在中。

linux驱动开发_linux设备驱动开发详解 源码_linux驱动开发项目

该结构体包含了一组函数表针,用于将内部函数和里面的设备编号联接上去。

该结构体的具体内容请自行查看源码,下边对平时用得比较多的几个函数进行说明:

struct file_operations {
	struct module *owner;
	......
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	......
	__poll_t (*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 (*release) (struct inode *, struct file *);
	......
} ;

目前只要晓得有这个结构体即可,可以在后续驱动中须要使用的时侯再去深入了解。

文件相关的数据结构

文件相关的数据结构主要是structfile结构体,其定义在中。

linux驱动开发_linux驱动开发项目_linux设备驱动开发详解 源码

该结构体表示一个打开的文件,它由内核在open时创建,为此系统中每位打开的文件、设备都有一个对应的file结构体。在文件的所有实例都被关掉后,内核就会释放这个结构体。

具体内容查看源码,下边对比较重要的属性进行说明:

struct file {
	......
	const struct file_operations *f_op;
	......
	unsigned int f_flags;
	fmode_t f_mode;
	......
	loff_t f_pos;
	......
	void *private_data;
	......
}

同样,这个结构体目前只须要了解即可,后续假如有须要再深入了解。

节点相关的数据结构

里面介绍了structfile_operations结构体表示文件操作相关的结构体,structfile结构体表示打开的文件。下边介绍的structinode结构体表示的是文件(节点)。该结构体同样坐落中。

structinode中包含了大量的有关文件的信息,其中对于驱动程序编撰十分重要的主要有以下几个:

struct inode {
	......
	dev_t i_rdev;
	......
	union {
		......
		struct cdev *i_cdev; 
		......
	};
	......
};

以上是本节的主要内容,下一节将会编撰一个字符设备实例。

本文原创地址:https://www.linuxprobe.com/lsbhjqxgczzf.html编辑:刘遄,审核员:暂无