一个例子了解通过Openharmony的HDF框架实现简易驱动的流程
HDF是什么?
官方说明:
HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
以下通过一个最简易的例程来了解HDF,并且解释如何通过HDF框架来开发Openharmony平台设备(Platform Device)驱动,为系统及外设驱动提供访问接口。
一、创建内核态驱动(KHDF)示例驱动
本例在Openharmony中的V3.1 版本中,创建KHDF驱动程序。
1.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
-
编译烧录:
1.2 驱动程序实现test_newdevice.c
通过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框架
1.2.1 驱动入口
通过指定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; } ...
1.2.2 实现Dispatch方法
定义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 drivers reply string!")) { return HdfDeviceSendEvent(client->device, cmdId, data); } } HDF_LOGE("%s: return fail", __func__); return HDF_FAILURE; } ...
1.2.3 硬件业务初始化与释放
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__); } ...
1.3 Makefile
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
1.4 驱动配置
配置文件有两部份:
-
驱动设备描述:指示驱动的加载信息内容。必选项
-
驱动私有配置:配置驱动的硬件配置信息。可选项
1.4.1 驱动设备描述
// 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字段是驱动服务发布的策略,在有详细介绍.
priority字段驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序
preload字段驱动按需加载字段
permission字段驱动创建设备节点权限
moduleName字段驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
serviceName字段驱动对外发布服务的名称,必须唯一,在设备的/dev可以查看到该名称
deviceMatchAttr字段驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
1.4.2 驱动私有配置
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,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.
1.5 编译烧录效果
-
在根目录下执行 ./build.sh --product-name rk3568 --ccache
-
单独编译内核:切换至out/kernel/src_tmp/linux-5.10目录下,执行./make-ohos.sh TB-RK3568X0
-
进入开发板中的/dev目录下,可以查看到test_hdf_newdevice1设备