3、HDF框架核心概念:驱动对象、驱动服务、驱动配置、驱动消息机制
好,咱们今天来啃HDF框架的四个核心概念。说实话,这四个东西刚接触时容易搞混,但一旦理清了,整个驱动开发的脉络就通了。我当年第一次看HDF源码时,也是对着这四个概念反复琢磨,才慢慢摸到门道。
驱动对象、驱动服务、驱动配置、驱动消息机制——它们分别回答了四个问题:“谁在干活?”、“能提供什么?”、“怎么配置它?”、“怎么跟它通信?”。咱们一个一个来拆。
3.1 驱动对象(Driver Object)——驱动的“身份证”
驱动对象,说白了就是HDF框架里每个驱动的“户口本”。它告诉框架:“我是谁,我属于哪个设备,我该怎么被初始化”。
在代码里,驱动对象是一个结构体:
struct HdfDriverEntry {
uint32_t moduleVersion;
const char *moduleName;
int32_t (*Bind)(struct HdfDeviceObject *deviceObject);
int32_t (*Init)(struct HdfDeviceObject *deviceObject);
void (*Release)(struct HdfDeviceObject *deviceObject);
};
嗯,这里要注意:Bind、Init、Release这三个函数指针,就是驱动的生命周期回调。框架会在不同阶段调用它们:
- Bind:驱动绑定到设备时调用。我习惯在这里做资源预分配,比如申请内存、注册服务接口。
- Init:驱动初始化时调用。真正的硬件初始化逻辑放这里,比如配置寄存器、启动中断。
- Release:驱动卸载时调用。别忘了释放资源,我曾经漏掉一个定时器没释放,结果系统重启时一直报错。
3.2 驱动服务(Driver Service)——驱动的“能力清单”
驱动对象是“你是谁”,驱动服务就是“你能干什么”。每个驱动可以对外暴露一组服务接口,供其他模块调用。
举个例子,你写了一个I2C驱动,那它提供的服务可能就是:I2cRead()、I2cWrite()、I2cTransfer()。其他模块(比如传感器驱动)通过HDF框架找到这个服务,然后直接调用。
注册服务的代码大概长这样:
int32_t MyDriverBind(struct HdfDeviceObject *deviceObject) {
static struct I2cDriverService service;
service.i2cRead = MyI2cRead;
service.i2cWrite = MyI2cWrite;
// 注册到HDF服务管理器
HdfDeviceRegisterService(deviceObject, &service);
return HDF_SUCCESS;
}
你想想看,如果没有驱动服务机制,每个驱动都得自己搞一套“接口暴露”的方法,那整个系统就乱套了。HDF框架统一了这件事,所有服务都通过服务管理器来查找和调用。
3.3 驱动配置(Driver Configuration)——驱动的“说明书”
驱动配置,就是告诉驱动“你该用哪个GPIO、I2C地址是多少、中断号是什么”。这些信息通常写在HCS(HDF Configuration Source)配置文件中。
HCS文件是HDF框架的“灵魂”之一。它用树形结构描述设备信息,比如:
root {
device_sample {
device0 :: device {
deviceInfo {
policy = 2;
priority = 100;
preload = 0;
permission = 0664;
moduleName = "HDF_SAMPLE";
serviceName = "sample_service";
deviceMatchAttr = "sample_config";
}
}
}
}
这里每个字段都有讲究:
| 字段 | 含义 | 我的建议 |
|---|---|---|
policy |
服务发布策略(0不发布,1对内核发布,2对用户态发布) | 调试阶段用2,发布前改成1 |
priority |
驱动加载优先级(数值越小越优先) | 依赖其他驱动的驱动,优先级要设高(数值小) |
preload |
是否预加载(0不预加载,1预加载) | 系统关键驱动建议预加载 |
deviceMatchAttr |
匹配的设备属性名 | 这个名字要和驱动代码里的一致,否则绑定不上 |
deviceMatchAttr写错了一个字母,结果驱动死活加载不上。排查了半天才发现是配置文件和代码里的名字不匹配。所以,配置文件和驱动代码里的名字一定要严格一致。
3.4 驱动消息机制(Driver Message)——驱动的“通信管道”
最后一个概念,驱动消息机制。它解决的是“驱动之间怎么通信”的问题。
在HDF框架里,驱动消息机制基于消息队列实现。一个驱动可以向另一个驱动发送消息,消息可以是同步的,也可以是异步的。
发送消息的接口很简单:
int32_t HdfDeviceSendEvent(
struct HdfDeviceObject *deviceObject,
uint32_t eventId,
struct HdfSBuf *data
);
接收消息的驱动需要注册一个回调:
int32_t MyDriverEventReceiver(
struct HdfDeviceObject *deviceObject,
uint32_t eventId,
struct HdfSBuf *data
) {
// 处理消息
return HDF_SUCCESS;
}
为什么需要消息机制?你想想看,驱动之间有时候需要“打招呼”。比如电源管理驱动通知外设驱动“系统要休眠了”,或者传感器驱动通知上层“数据准备好了”。如果没有统一的消息机制,每个驱动都得自己搞一套通信方式,那维护起来就是噩梦。
3.5 四个概念的关系——一张图看懂
说了这么多,咱们用一张图把四个概念串起来:
从这张图可以看得很清楚:驱动对象是核心,它通过配置加载,注册服务,并使用消息机制与其他驱动通信。这四个概念缺一不可,共同构成了HDF驱动框架的基石。
好了,这一章的内容就到这里。记住这四个概念,后面咱们写驱动时,每一步都会跟它们打交道。