官方说明:
HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
以下通过一个最简易的例程来了解HDF,并且解释如何通过HDF框架来开发Openharmony平台设备(Platform Device)驱动,为系统及外设驱动提供访问接口。
本例在Openharmony中的V3.1 版本中,创建KHDF驱动程序。
创建KHDF驱动程序步骤如下:
添加目录: //driver/adapter/khdf/linux中创建目录newdevice
添加文件: //driver/adapter/khdf/newdevice添加文件test_newdevice.c与Makefile
添加配置: //vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs
编译烧录:
通过HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
// driver/adapter/khdf/newdevice/test_newdevice.c
#include "hdf_device_desc.h"
#include "hdf_dlist.h"
#include "hdf_log.h"
....
struct HdfDriverEntry g_test_newdevice = {
.moduleVersion = 1,
.moduleName = "test_hdf_newdevice", // 通过此模块名匹配hcs配置文件中模块名
.Init = HdfNewdeviceInit, // 驱动自身业务初始的接口
.Bind = HdfNewdeviceBind, // 驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
.Release = HdfNewdeviceRelease, // 驱动资源释放的接口
};
HDF_INIT(g_test_newdevice); // 注册到HDF框架
通过指定Bind,HdfNewdeviceBind将相关的服务接口绑定到HDF框架,通过Dispatch对用户态应用的消息进行处理。
// driver/adapter/khdf/newdevice/test_newdevice.c
...
int32_t HdfNewdeviceIoServiceDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
{
...
}
int32_t HdfNewdeviceBind(struct HdfDeviceObject *deviceObject)
{
HDF_LOGD("enter %s", __func__);
static struct IDeviceIoService newdeviceService = {
//.Open = HdfNewdeviceDriverOpen,
.Dispatch = HdfNewdeviceIoServiceDispatch, // 驱动服务通过此函数进行分发处理
//.Release = HdfnewdeviceDriverClose,
};
deviceObject->service = &newdeviceService;
}
...
定义TEST_WRITE_DATA的cmdId号,对写入的数据进行打印,并返回应答数据。HdfDeviceSendEvent对应用端通过HdfDeviceRegisterEventListener方法注册的监听器HdfDevEventlistener对象均可以接受到cmdId消息。HdfDevEventlistener将会应用端进行说明。
// driver/adapter/khdf/newdevice/test_newdevice.c
...
#define TEST_WRITE_DATA 1234
int32_t HdfNewdeviceIoServiceDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
{
HDF_LOGD("enter %s: received cmd %d", __func__, cmdId);
if (cmdID == TEST_WRITE_DATA) {
const char *readData = HdfSbufReadString(data);
if (readData != NULL) {
HDF_LOGD("%s: read data is: %s", __func__, readData);
}
if (HdfSbufWriteString(reply, "I am driver's reply string!")) {
return HdfDeviceSendEvent(client->device, cmdId, data);
}
}
HDF_LOGE("%s: return fail", __func__);
return HDF_FAILURE;
}
...
HdfNewdeviceInit实现驱动自身业务初始的接口
HdfNewdeviceRelease实现驱动资源释放的接口
// driver/adapter/khdf/newdevice/test_newdevice.c
...
int32_t HdfNewdeviceInit(struct HdfDeviceObject *deviceObject)
{
HDF_LOGD("enter %s", __func__);
return 0;
}
void HdfNewdeviceRelease(struct HdfDeviceObject *deviceObject)
{
HDF_LOGD("enter %s", __func__);
}
...
obj-y += test_newdevice.o
ccflags-y += -I$(srctree)/include/hdf \
-I$(srctree)/include/hdf/osal \
-I$(srctree)/include/hdf/utils \
-I$(srctree)/drivers/hdf/framework/utils/include \
-I$(srctree)/drivers/hdf/khdf/osal/include \
-I$(srctree)/bounds_checking_function/include \
-I$(srctree)/drivers/hdf/framework/include/core \
-I$(srctree)/drivers/hdf/framework/core/common/include/host \
-I$(srctree)/drivers/framework/core/host/include
配置文件有两部份:
驱动设备描述:指示驱动的加载信息内容。必选项
驱动私有配置:配置驱动的硬件配置信息。可选项
HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device_info.hcs配置文件中添加对应的设备描述,驱动的设备描述填写如下所示:
// vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs
root {
...
test_newdevice :: host {
hostName = "test_newdevice";// host名称,host节点是用来存放某一类驱动的容器
device_sample :: device { // sample设备节点
device0 ::deviceNode {
policy = 2;
priority = 10;
preload = 0;
permission = 0664;
moduleName = "test_hdf_newdevice";
serviceName = "test_hdf_newdevice1";
deviceMatchAttr = "sample_config";
}
}
}
...
}
policy字段是驱动服务发布的策略,在Openharmony驱动服务管理章节有详细介绍.
priority字段驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序
preload字段驱动按需加载字段
permission字段驱动创建设备节点权限
moduleName字段驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
serviceName字段驱动对外发布服务的名称,必须唯一,在设备的/dev可以查看到该名称
deviceMatchAttr字段驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init传递给驱动,驱动的配置信息示例如下:
// vendor/hihope/rk3568/hdf_config/khdf/hdf.hcs
root {
...
SampleDriverConfig {
sample_version = 1;
sample_bus = "";
match_attr = "sample_config";//该字段的值必须和device_info.hcs中的deviceMatchAttr值一致
}
}
配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs.
在根目录下执行 ./build.sh --product-name rk3568 --ccache
单独编译内核:切换至out/kernel/src_tmp/linux-5.10目录下,执行./make-ohos.sh TB-RK3568X0
进入开发板中的/dev目录下,可以查看到test_hdf_newdevice1设备