一个例子了解通过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 driver's 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 驱动设备描述

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值相等

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设备

你可能感兴趣的:(openharmony)