开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 31 天,点击查看活动详情。
一、总线、设备、驱动
硬编码式的驱动开发带来的问题:
- 垃圾代码太多
- 结构不清晰
- 一些统一设备功能难以支持
- 开发效率低下
1. 初期解决思路:设备和驱动分离
struct device
来表示一个具体设备,主要提供具体设备相关的资源(如寄存器地址、GPIO、中断等等)。
struct device_driver
来表示一个设备驱动,一个驱动可以支持多个操作逻辑相同的设备。
带来的问题-------怎样将二者进行关联(匹配)?
硬件上同一总线上的设备遵循一致的时序通信,在其基础上增加管理设备和驱动的软件功能;于是引入总线(bus),各种总线的核心框架由内核来实现,通信时序一般由SOC供应商支持。
内核中用struct bus_type
来表示一种总线,总线可以是实际存在的总线,也可以是虚拟总线:
-
实际总线:提供时序通信方式 + 管理设备和驱动
-
虚拟总线:仅用来管理设备和驱动(最核心的作用之一就是完成设备和驱动的匹配)
理解方式:
设备:提供硬件资源——男方
驱动:提供驱动代码——女方
总线:匹配设备和驱动——婚介所:提供沟通机制,完成拉郎配
整体的一个思路就是:先开发硬件模块,再开发驱动模块,最后建立一种关系将两者结合起来。
2. 升级思路:根据设备树,在系统启动时自动产生每个节点对应的设备
初期方案,各种device需要编码方式注册进内核中的设备管理结构中,为了进一步减少这样的编码,引进设备树。
二、基本数据类型
1. struct device
struct device
{
struct bus_type *bus; //总线类型
dev_t devt; //设备号
struct device_driver *driver; //设备驱动
struct device_node *of_node;//设备树中的节点,重要
void (*release)(struct device *dev);//删除设备,重要
//.......
};
2. struct device_driver
struct device_driver
{
const char *name; //驱动名称,匹配device用,重要
struct bus_type *bus; //总线类型
struct module *owner; //模块THIS_MODULE
const struct of_device_id *of_match_table;//用于设备树匹配
struct of_device_id对象地址) 重要
//......
}
struct of_device_id
{
char name[32];//设备名
char type[32];//设备类型
char compatible[128]; //用于device和driver的match,重点
};
//用到结构体数组,一般不指定大小,初始化时最后加{}表示 数组结束