OpenHarmony Input 驱动框架 精华

RestartHua
发布于 2022-3-31 15:50
浏览
3收藏

一、Hdf Framework

HDF 驱动框架

OpenAtom OpenHarmony(以下简称“OpenHarmony”)系统 HDF 驱动框架采用 C 语言面向对象编程模型构建,通过平台解耦、内核解耦,来达到兼容不同内核,统一平台底座的目的,从而帮助开发者实现驱动一次开发,多系统部署的效果。 (引用原文
OpenHarmony Input 驱动框架-鸿蒙开发者社区

代码目录

/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驱动模型

OpenHarmony 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设备的业务控制接口,包括获取器件信息及设备类型、设置电源状态等

OpenHarmony 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;
}

2
收藏 3
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

学习一波文章,感谢分享。

回复
2022-3-31 19:23:50
回复
    相关推荐