# 驱动开发
- [驱动模型介绍](#section157425168112)
- [驱动开发步骤](#section1969312275533)
## 驱动模型介绍
HDF框架以组件化的驱动模型作为核心设计思路,为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF框架将一类设备驱动放在同一个host里面,开发者也可以将驱动功能分层独立开发和部署,支持一个驱动多个node,HDF驱动模型如下图所示:
**图 1** HDF驱动模型
![](figure/zh-cn_image_0000001054564784.png)
## 驱动开发步骤
基于HDF框架进行驱动的开发主要分为两个部分,驱动实现和驱动配置,详细开发流程如下所示:
1. 驱动实现
驱动实现包含驱动业务代码和驱动入口注册,具体写法如下:
- 驱动业务代码
```
#include "hdf_device_desc.h" // HDF框架对驱动开放相关能力接口的头文件
#include "hdf_log.h" // HDF 框架提供的日志接口头文件
#define HDF_LOG_TAG "sample_driver" // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签
//驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
{
HDF_LOGD("Sample driver bind success");
return 0;
}
// 驱动自身业务初始的接口
int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
{
HDF_LOGD("Sample driver Init success");
return 0;
}
// 驱动资源释放的接口
void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
{
HDF_LOGD("Sample driver release success");
return;
}
```
- 驱动入口注册到HDF框架
```
// 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量
struct HdfDriverEntry g_sampleDriverEntry = {
.moduleVersion = 1,
.moduleName = "sample_driver",
.Bind = HdfSampleDriverBind,
.Init = HdfSampleDriverInit,
.Release = HdfSampleDriverRelease,
};
// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
HDF_INIT(g_sampleDriverEntry);
```
2. 驱动编译
- liteos
涉及makefile和BUILD.gn修改:
makefile部分:
驱动代码的编译必须要使用HDF框架提供的Makefile模板进行编译。
```
include $(LITEOSTOPDIR)/../../drivers/adapter/lite/khdf/lite.mk #导入hdf预定义内容,必需
MODULE_NAME := #生成的结果文件
LOCAL_INCLUDE := #本驱动的头文件目录
LOCAL_SRCS := #本驱动的源代码文件
LOCAL_CFLAGS := #自定义的编译选项
include $(HDF_DRIVER) #导入模板makefile完成编译
```
编译结果文件链接到内核镜像,添加到drivers/adapter/khdf/liteos目录下的hdf_lite.mk里面,示例如下:
```
LITEOS_BASELIB += -lxxx #链接生成的静态库
LIB_SUBDIRS += #驱动代码Makefile的目录
```
BUILD.gn部分:
添加模块BUILD.gn参考定义如下内容:
import("//build/lite/config/component/lite_component.gni")
import("//drivers/adapter/khdf/liteos/hdf.gni")
module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM)
module_name = "xxx"
hdf_driver(module_name) {
sources = [
"xxx/xxx/xxx.c",
]
public_configs = [ ":public" ] --添加依赖头文件
}
config("public") { --定义依赖的头文件
include_dirs = [
]
}
把新增的BUILD.gn所在的目录添加到/drivers/adapter/khdf/liteos/BUILD.gn里面:
```
group("liteos") {
public_deps = [ ":$module_name" ]
deps = [
"xxx/xxx", --新增的BUILD.gn所在的目录
]
}
```
- linux:
如果需要定义模块控制宏,需要在模块目录xxx里面添加Kconfig文件,并把Kconfig文件路径添加到drivers/adapter/khdf/linux/Kconfig里面:
```
source "drivers/hdf/khdf/xxx/Kconfig"
```
添加模块目录到drivers/adapter/khdf/linux/Makefile:
```
obj-$(CONFIG_DRIVERS_HDF) += xxx/
```
在模块目录xxx里面添加Makefile文件,在Makefile文件里面添加模块代码编译规则:
```
obj-y += xxx.o
```
3. 驱动配置
HDF使用HCS作为配置描述源码,HCS详细介绍参考[配置管理](driver-hdf-manage.md)介绍。
驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息,具体写法如下:
- 驱动设备描述(必选)
HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device\_info.hcs配置文件中添加对应的设备描述,驱动的设备描述填写如下所示:
```
root {
device_info {
match_attr = "hdf_manager";
template host { // host模板,继承该模板的节点(如下sample_host)如果使用模板中的默认值,则节点字段可以缺省
hostName = "";
priority = 100;
template device {
template deviceNode {
policy = 0;
priority = 100;
preload = 0;
permission = 0664;
moduleName = "";
serviceName = "";
deviceMatchAttr = "";
}
}
}
sample_host :: host{
hostName = "host0"; // host名称,host节点是用来存放某一类驱动的容器
priority = 100; // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序
device_sample :: device { // sample设备节点
device0 :: deviceNode { // sample驱动的DeviceNode节点
policy = 1; // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍
priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序
preload = 0; // 驱动按需加载字段,在本章节最后的说明有详细介绍
permission = 0664; // 驱动创建设备节点权限
moduleName = "sample_driver"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
serviceName = "sample_service"; // 驱动对外发布服务的名称,必须唯一
deviceMatchAttr = "sample_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
}
}
}
}
}
```
- 驱动私有配置信息(可选)
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考[驱动开发](#li35182436435))传递给驱动,驱动的配置信息示例如下:
```
root {
SampleDriverConfig {
sample_version = 1;
sample_bus = "I2C_0";
match_attr = "sample_config"; //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致
}
}
```
配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs(这一块可以通过OpenHarmony驱动子系统在DevEco集成驱动开发套件工具一键式配置,具体使用方法参考驱动开发套件中的介绍),示例如下:
```
#include "device_info/device_info.hcs"
#include "sample/sample_config.hcs"
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>驱动加载方式支持按需加载和按序加载两种方式,具体使用方法如下:
>- 按需加载
> ```
> typedef enum {
> DEVICE_PRELOAD_ENABLE = 0,
> DEVICE_PRELOAD_ENABLE_STEP2,
> DEVICE_PRELOAD_DISABLE,
> DEVICE_PRELOAD_INVALID
> } DevicePreload;
> ```
> 配置文件中preload 字段配成 0 (DEVICE\_PRELOAD\_ENABLE ),则系统启动过程中默认加载;配成1(DEVICE\_PRELOAD\_ENABLE\_STEP2),当系统支持快启的时候,则在系统完成之后再加载这一类驱动,否则和DEVICE\_PRELOAD\_ENABLE 含义相同;配成2(DEVICE\_PRELOAD\_DISABLE),则系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务(参考[消息机制](driver-hdf-news.md))时,如果驱动服务不存在时,HDF框架会尝试动态加载该驱动。
>- 按序加载(需要驱动为默认加载)
> 配置文件中的priority(取值范围为整数0到200)是用来表示host和驱动的优先级,不同的host内的驱动,host的priority值越小,驱动加载优先级越高;同一个host内驱动的priority值越小,加载优先级越高。