4

OpenHarmony Input 驱动框架

 2 years ago
source link: https://os.51cto.com/article/705539.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

6766c9d7236124fb29015557169b94549a2983.png

一、Hdf Framework

HDF 驱动框架

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

resize,w_1035,h_691

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

resize,w_1015,h_551

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

resize,w_896,h_513

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

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

71eea7105a1cf9982d2996c42d853b97bd50ef.jpg


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK