linux驱动 — 字符设备解析

前言

linux字符设备驱动学的是云里雾里,一团乱麻,剪不断理还乱… 放弃?

不,反正闲着也是闲着,打王者还老遇到坑,免不了上火!

那就一点一点来吧,弄一点是一点

问题

开始可能很多同学跟我一样,从代码入手,点亮一个led,急于看到结果,然后一顿操作猛如虎,驱动学的特别苦,面试一问二百五!

因此,现在我想改变下策略,从基本概念开始,不急着去写代码,先去了解下字符设备驱动框架,然后去弄懂如下几个概念:

1、啥是设备号,用来干嘛的

2、file_operations结构体的作用

3、cdev是啥

上面这三个应该就是字符设备驱动的关键了,把它们弄熟了才能更好的编写字符设备驱动

概念理解

1、字符设备驱动框架

字符设备是Linux三大设备之一,另外两种我就不提了,字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,所以学好它是我们嵌入式开发人员势在必行的

常见的字符设备包括鼠标、键盘、显示器、串口等,用ls -l /dev指令可以查看很多设备文件,c就是字符设备, 后面的数值就是主设备号和次设备号,这个特别重要

2、啥是设备号,用来干嘛的?

设备号又分为主设备号和次设备号

主设备号用来区分不同硬件设备类型,如串口和USB之间的区别,表示对应的驱动程序,也就是说一个主设备号对应一个驱动程序。

次设备号用来区分同一类型的多个设备,如串口1和串口2之间的区别,由内核使用,用于确定/dev下的设备文件对应的具体设备。

如下:各文件主设备号一致,次设备号不同
同类型设备
作用:因为linux下兼文件。各种设备都以文件的形式存放在/dev目录下,称为设备文件

应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了
号,所以每个设备号就分为了主设备号和次设备号。

其中与设备号相关的比较重要的三个宏,代码中尽量使用宏,减少兼容性问题

#define MAJOR(dev)	((dev)>>8)
#define MINOR(dev)	((dev) & 0xff)
#define MKDEV(ma,mi)	((ma)<<8 | (mi))

3、file_operations结构体的作用

file_operations结构体是字符设备驱动与内核的接口,是用户空间对Linux进行系统调用最终的落实者, 这个结构体包含对文件打开,关闭,读写,控制的一系列成员函数。

//结构体定义如下:

static struct file_operations chrdev_fops = {
	.owner 		= THIS_MODULE,		//指向拥有这个结构的模块的指针.用来在它的操作还在被使用时阻止模块被卸载
	.open		= chrdev_open,		//以下都是些常用接口,应用层调用时对应的驱动层实现
	.release	= chrdev_release,
	.write 		= chrdev_write,
	.read		= chrdev_read,
};

4、cdev是啥

cdev是字符设备对象结构体,是linux用来管理字符设备的,其在内核中采用数组结构设计,这样系统中有多少个主设备号就约定了数组大小,此设备号采用链表管理,同一主设备号下可以有多个子设备。

cdev 结构体中包含 设备号 dev_t 和 file_operations 结构指针

<include/linux/cdev.h>
struct cdev { 
	struct kobject kobj;              	//内嵌的内核对象.
	struct module *owner;           	//该字符设备所在的内核模块的对象指针.
	const struct file_operations *ops;  //该结构描述了字符设备所能实现的方法,是非常关键的一个结构体.
	struct list_head list;             	//用来将已经向内核注册的所有字符设备形成链表.
	dev_t dev;                    		//字符设备的设备号,由主设备号和次设备号构成.
	unsigned int count;             	//同一主设备号下的次设备号的个数.
};

扩展:应用程序是怎么跟驱动程序产生联系的呢,比如open函数,其调用大致过程如下:

1、应用程序open打开一个设备节点文件:int open("/dev/text", O_RDWR);

2、会产生open系统调用,然后进入内核,调用sys_open函数,就直接到VFS层了,并产生struct file表示一个打开的文件

3、然后VFS虚文件系统open根据传进来的路径转换为inode,通过 inode 节点获取到文件设备号

4、遍历 cdev 链表,与此文件的设备号进行比较,如果相同则表示匹配成功

5、将匹配成功的 cdev 结构体中的 file_operations 赋值给此文件的 struct file,从而关联到驱动层中的file_operations

6、最后根据file_operations中函数指针就可以找到该结构体中对该种文件操作的所有方法

大致过程就是:应用层open --> 系统调用sys_open --> VFS层 --> 得到inode --> 获取设备号 --> 遍历cdev --> 设备号匹配就进行关联

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东皇※太一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值