OpenHarmony Input 驱动框架 精华
一、Hdf Framework
HDF 驱动框架
OpenAtom OpenHarmony(以下简称“OpenHarmony”)系统 HDF 驱动框架采用 C 语言面向对象编程模型构建,通过平台解耦、内核解耦,来达到兼容不同内核,统一平台底座的目的,从而帮助开发者实现驱动一次开发,多系统部署的效果。 (引用原文)
代码目录
/drivers/framework
├── ability #提供驱动开发的能力支持,如消息模型库等
│ ├── config #配置解析代码
│ └── sbuf #数据序列化代码
├── core #实现驱动框架的核心代码
│ ├── adapter #实现对内核操作接口适配,提供抽象化的接口供开发者使用
│ ├── common #驱动框架公共基础代码
│ ├── host #驱动宿主环境模块
│ ├── manager #驱动框架管理模块
│ └── shared #host和manager共享模块代码
├── include #驱动框架对外提供能力的头文件
│ ├── config #提供配置解析能力的头文件
│ ├── core #驱动框架对外提供的头文件
│ ├── net #网络数据操作相关的头文件
│ ├── osal #系统适配相关接口的头文件
│ ├── platform #平台设备相关接口的头文件
│ ├── utils #驱动框架公共能力的头文件
│ └── wifi #WLAN对外提供能力的头文件
├── model #提供驱动通用框架模型
│ ├── display #显示框架模型
│ ├── input #输入框架模型
│ ├── network #WLAN框架模型
│ └── sensor #Sensor驱动模型
├── support #提系统的基础能力
│ └── platform #平台设备驱动框架及访问接口,范围包括GPIO、I2C、SPI等
├── tools #hdf框架工具相关的源码
│ └── hc-gen #配置管理工具源码
└── utils #提供基础数据结构和算法等
二、input 驱动模型
基于HDF驱动框架的Input驱动模型
Input驱动模型介绍
Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者的器件驱动开发效率。如下部分为模型各部分的说明:
- Input设备管理:为各类输入设备驱动提供Input设备的注册、注销接口,同时统一管理Input设备列表。
- Input平台驱动:指各类Input设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向manager注册Input设备等。
- Input器件驱动:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化。
- Input数据通道:提供一套通用的数据上报通道,各类别的Input设备驱动均可用此通道上报Input事件。
- Input配置解析:负责对Input设备的板级配置及器件私有配置进行解析及管理。
Input模型工作流程解析
私有配置信息解析
./drivers/framework/model/input/driver/input_config_parser.c
根据 OSAL 提供的配置解析函数,可以将 hcs 文件中各字段含义进行解析,具体请参考 input_config_parser.c 中各函数的实现。如果提供的模板不能满足需求,在 hcs 文件中添加相应信息后,需要根据添加的字段开发相应的解析函数。
static int32_t ParseAttr(struct DeviceResourceIface *parser, const struct DeviceResourceNode *attrNode,
BoardAttrCfg *attr)
{
int32_t ret;
ret = parser->GetUint8(attrNode, "inputType", &attr->devType, 0);
CHECK_PARSER_RET(ret, "GetUint8");
ret = parser->GetString(attrNode, "devName", &attr->devName, NULL);
CHECK_PARSER_RET(ret, "GetString");
ret = parser->GetUint32(attrNode, "solutionX", &attr->resolutionX, 0);
CHECK_PARSER_RET(ret, "GetUint32");
ret = parser->GetUint32(attrNode, "solutionY", &attr->resolutionY, 0);
CHECK_PARSER_RET(ret, "GetUint32");
return HDF_SUCCESS;
}
管理驱动层初始化及注册驱动至HDF框架
./drivers/framework/model/input/driver/hdf_input_device_manager.c
static int32_t HdfInputManagerInit(struct HdfDeviceObject *device)
{
HDF_LOGI("%s: enter", __func__);
if (device == NULL) {
HDF_LOGE("%s: device is null", __func__);
return HDF_ERR_INVALID_PARAM;
}
/* 分配内存给manager,manager中将存放所有input设备 */
g_inputManager = InputManagerInstance();
if (g_inputManager == NULL) {
return HDF_ERR_MALLOC_FAIL;
}
if (OsalMutexInit(&g_inputManager->mutex) != HDF_SUCCESS) {
HDF_LOGE("%s: mutex init failed", __func__);
OsalMemFree(g_inputManager);
g_inputManager = NULL;
return HDF_FAILURE;
}
g_inputManager->initialized = true;
g_inputManager->hdfDevObj = device;
HDF_LOGI("%s: exit succ", __func__);
return HDF_SUCCESS;
}
struct HdfDriverEntry g_hdfInputEntry = {
.moduleVersion = 1,
.moduleName = "HDF_INPUT_MANAGER",
.Bind = HdfInputManagerBind,
.Init = HdfInputManagerInit,
.Release = HdfInputManagerRelease,
};
HDF_INIT(g_hdfInputEntry); //驱动注册入口
公共驱动层初始化及注册驱动至HDF框架
./drivers/framework/model/input/driver/hdf_touch.c
static int32_t HdfTouchDriverProbe(struct HdfDeviceObject *device)
{
...
/* 板级信息结构体内存申请及hcs配置信息解析 */
boardCfg = BoardConfigInstance(device);
...
/* 公共驱动结构体内存申请 */
touchDriver = TouchDriverInstance();
...
/* 依据解析出的板级信息进行公共资源初始化,如IIC初始化 */
ret = TouchDriverInit(touchDriver, boardCfg);
if (ret == HDF_SUCCESS) {
...
/* 添加驱动至公共驱动层驱动管理链表,当设备与驱动进行绑定时使用该链表进行查询 */
AddTouchDriver(touchDriver);
...
}
...
}
struct HdfDriverEntry g_hdfTouchEntry = {
.moduleVersion = 1,
.moduleName = "HDF_TOUCH",
.Bind = HdfTouchDriverBind,
.Init = HdfTouchDriverProbe,
.Release = HdfTouchDriverRelease,
};
HDF_INIT(g_hdfTouchEntry); //驱动注册入口
器件驱动层初始化及注册驱动至HDF框架
具体请参考适配器件私有驱动器件层驱动初始化及注册驱动至 HDF 框架部分。
具体调用逻辑串联函数
Input 模型管理层驱动 init 函数初始化了设备管理链表**,公共驱动层**初始化函数完成了相关结构体的内存申请。器件驱动相关信息通过 RegisterChipDevice 函数对公共驱动层相关结构体进行信息填充,同时完成了相关硬件信息的初始化(如中断注册等),绑定设备与驱动组成 inputDev 通过 RegisterInputDevice 函数向驱动管理层进行注册,在 RegisterInputDevice 函数中主要实现了将 inputDev 向设备管理链表的添加等功能。如下所示为两个函数的实现部分:
./drivers/framework/model/input/driver/hdf_touch.c
int32_t RegisterTouchChipDevice(ChipDevice *chipDev)
{
int32_t ret;
InputDevice *inputDev = NULL;
if ((chipDev == NULL) || (chipDev->chipCfg == NULL)) {
return HDF_ERR_INVALID_PARAM;
}
/* 绑定设备与驱动,从而通过InputDeviceInstance函数创建inputDev */
ret = DeviceBindDriver(chipDev);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: chip device match driver failed", __func__);
return HDF_FAILURE;
}
/* 主要包含器件中断注册及中断处理函数,处理函数中有数据上报用户态的数据通道 */
ret = ChipDriverInit(chipDev);
if (ret != HDF_SUCCESS) {
goto EXIT;
}
/* 申请内存实例化InputDev */
inputDev = InputDeviceInstance(chipDev);
if (inputDev == NULL) {
return HDF_ERR_MALLOC_FAIL;
}
/* 将InputDev设备注册至input驱动管理层 */
ret = RegisterInputDevice(inputDev);
if (ret != HDF_SUCCESS) {
goto EXIT1;
}
chipDev->driver->inputDev = inputDev;
chipDev->ops->SetAbility(chipDev);
return HDF_SUCCESS;
EXIT1:
OsalMemFree(inputDev);
EXIT:
chipDev->driver->device = NULL;
return HDF_FAILURE;
}
./drivers/framework/model/input/driver/hdf_input_device_manager.c
int32_t RegisterInputDevice(InputDevice *inputDev)
{
int32_t ret;
HDF_LOGI("%s: enter", __func__);
if (inputDev == NULL) {
HDF_LOGE("%s: inputdev is null", __func__);
return HDF_ERR_INVALID_PARAM;
}
if ((g_inputManager == NULL) || (g_inputManager->initialized == false)) {
HDF_LOGE("%s: dev manager is null or initialized failed", __func__);
return HDF_FAILURE;
}
OsalMutexLock(&g_inputManager->mutex);
/* 申请ID,该ID对于不同input设备唯一 */
ret = AllocDeviceID(inputDev);
if (ret != HDF_SUCCESS) {
goto EXIT;
}
/* 该函数包含了对hid类设备的特殊处理,对于触摸屏驱动,该函数无实质操作; */
ret = CreateDeviceNode(inputDev);
if (ret != HDF_SUCCESS) {
goto EXIT1;
}
/* 内核态数据传送至用户态需使用IOService能力,需要申请buffer */
ret = AllocPackageBuffer(inputDev);
if (ret != HDF_SUCCESS) {
goto EXIT1;
}
/* 将input设备添加进设备全局管理链表 */
AddInputDevice(inputDev);
OsalMutexUnlock(&g_inputManager->mutex);
HDF_LOGI("%s: exit succ, devCount is %d", __func__, g_inputManager->devCount);
return HDF_SUCCESS;
EXIT1:
DeleteDeviceNode(inputDev);
EXIT:
OsalMutexUnlock(&g_inputManager->mutex);
return ret;
}
三、Input模块HDI接口层框架
Input模块HDI(Hardware Driver Interface)接口定义及其实现,对上层输入服务提供操作input设备的驱动能力接口,HDI接口主要包括如下三大类:
-
InputManager:管理输入设备,包括输入设备的打开、关闭、设备列表信息获取等;
-
InputReporter:负责输入事件的上报,包括注册、注销数据上报回调函数等;
-
InputController:提供input设备的业务控制接口,包括获取器件信息及设备类型、设置电源状态等
目录
drivers_peripheral 仓下源代码目录结构如下所示
/drivers/peripheral/input
├── hal # input模块的hal层代码
│ └── include # input模块hal层内部的头文件
│ └── src # input模块hal层代码的具体实现
├── interfaces # input模块对上层服务提供的驱动能力接口
│ └── include # input模块对外提供的接口定义
├── test # input模块的测试代码
│ └── unittest # input模块的单元测试代码
使用说明
**drivers_peripheral**仓核心功能是提供Input驱动能力接口供上层输入系统服务调用,提供的驱动能力接口统一归属为HDI接口层。
通过如下简要示例代码说明Input HDI接口的使用:
#include "input_manager.h"
#define DEV_INDEX 1
IInputInterface *g_inputInterface;
InputReportEventCb g_callback;
/* 定义数据上报的回调函数 */
static void ReportEventPkgCallback(const EventPackage **pkgs, uint32_t count)
{
if (pkgs == NULL || count > MAX_PKG_NUM) {
return;
}
for (uint32_t i = 0; i < count; i++) {
HDF_LOGI("%s: pkgs[%d] = 0x%x, 0x%x, %d", __func__, i, pkgs[i]->type, pkgs[i]->code, pkgs[i]->value);
}
}
int InputServiceSample(void)
{
uint32_t devType = INIT_DEFAULT_VALUE;
/* 获取Input驱动能力接口 */
int ret = GetInputInterface(&g_inputInterface);
if (ret != INPUT_SUCCESS) {
HDF_LOGE("%s: get input interfaces failed, ret = %d", __func__, ret);
return ret;
}
INPUT_CHECK_NULL_POINTER(g_inputInterface, INPUT_NULL_PTR);
INPUT_CHECK_NULL_POINTER(g_inputInterface->iInputManager, INPUT_NULL_PTR);
/* 打开特定的input设备 */
ret = g_inputInterface->iInputManager->OpenInputDevice(DEV_INDEX);
if (ret) {
HDF_LOGE("%s: open input device failed, ret = %d", __func__, ret);
return ret;
}
INPUT_CHECK_NULL_POINTER(g_inputInterface->iInputController, INPUT_NULL_PTR);
/* 获取对应input设备的类型 */
ret = g_inputInterface->iInputController->GetDeviceType(DEV_INDEX, &devType);
if (ret) {
HDF_LOGE("%s: get device type failed, ret: %d", __FUNCTION__, ret);
return ret;
}
HDF_LOGI("%s: device1's type is %u\n", __FUNCTION__, devType);
/* 给特定的input设备注册数据上报回调函数 */
g_callback.ReportEventPkgCallback = ReportEventPkgCallback;
INPUT_CHECK_NULL_POINTER(g_inputInterface->iInputReporter, INPUT_NULL_PTR);
ret = g_inputInterface->iInputReporter->RegisterReportCallback(DEV_INDEX, &g_callback);
if (ret) {
HDF_LOGE("%s: register callback failed, ret: %d", __FUNCTION__, ret);
return ret;
}
HDF_LOGI("%s: wait 10s for testing, pls touch the panel now", __FUNCTION__);
OsalMSleep(KEEP_ALIVE_TIME_MS);
/* 注销特定input设备上的回调函数 */
ret = g_inputInterface->iInputReporter->UnregisterReportCallback(DEV_INDEX);
if (ret) {
HDF_LOGE("%s: unregister callback failed, ret: %d", __FUNCTION__, ret);
return ret;
}
/* 关闭特定的input设备 */
ret = g_inputInterface->iInputManager->CloseInputDevice(DEV_INDEX);
if (ret) {
HDF_LOGE("%s: close device failed, ret: %d", __FUNCTION__, ret);
return ret;
}
return 0;
}
学习一波文章,感谢分享。