OpenHarmony HDF驱动框架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 1IInputInterface *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 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;}