IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 移植openharmony之调试gt911触摸 -> 正文阅读

[游戏开发]移植openharmony之调试gt911触摸

最近在调试触摸驱动,分析了一点openharmony的hdf框架下的触摸,将过程记录下,首先肯定是加载input设备管理驱动:input设备管理驱动由HDF驱动加载,完成设备manager的创建并对其初始化。如下图所示,我这里就是先加载了drivers/framework/model/input/driver/hdf_input_device_manager.c驱动文件。这种文件一般不需要修改,直接使用即可。都是提供给其他文件使用的接口居多。
在这里插入图片描述
然后就是加载平台驱动过程了,因为我们是触摸屏,所以加载的文件drivers/framework/model/input/driver/hdf_touch.c文件,这个文件可以着重分析下

struct HdfDriverEntry g_hdfTouchEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_TOUCH",
    .Bind = HdfTouchDriverBind, //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
    .Init = HdfTouchDriverProbe, //
    .Release = HdfTouchDriverRelease,
};

HDF_INIT(g_hdfTouchEntry);

那么首先执行的函数为HdfTouchDriverProbe,

static int32_t HdfTouchDriverProbe(struct HdfDeviceObject *device)
{
    int32_t ret;
    TouchBoardCfg *boardCfg = NULL;
    TouchDriver *touchDriver = NULL;

    HDF_LOGI("%s: enter", __func__);
    if (device == NULL) {
        HDF_LOGE("%s: param is null", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    boardCfg = BoardConfigInstance(device); //主要实现数据配置解析功能
    if (boardCfg == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }
    touchDriver = TouchDriverInstance(); //只是申请变量并初始化结构体
    if (touchDriver == NULL) {
        goto EXIT;
    }

    ret = TouchDriverInit(touchDriver, boardCfg);
    if (ret == HDF_SUCCESS) {
        touchDriver->hdfTouchDev = device;
        touchDriver->boardCfg = boardCfg;
        AddTouchDriver(touchDriver);
        device->priv = (void *)touchDriver;
        HDF_LOGI("%s: %s exit succ", __func__, boardCfg->attr.devName);
        return HDF_SUCCESS;
    }

EXIT:
    OsalMemFree(boardCfg);
    if (touchDriver != NULL) {
        touchDriver->boardCfg = NULL;
        OsalMemFree(touchDriver);
    }
    return HDF_FAILURE;
}

重点先看下这个函数,是如何解析板级配置信息的,

static TouchBoardCfg *BoardConfigInstance(struct HdfDeviceObject *device)
{
    TouchBoardCfg *boardCfg = (TouchBoardCfg *)OsalMemAlloc(sizeof(TouchBoardCfg));
    if (boardCfg == NULL) {
        HDF_LOGE("%s: instance board config failed", __func__);
        return NULL;
    }
    (void)memset_s(boardCfg, sizeof(TouchBoardCfg), 0, sizeof(TouchBoardCfg));

    if (ParseTouchBoardConfig(device->property, boardCfg) != HDF_SUCCESS) {
        HDF_LOGE("%s: parse board config failed", __func__);
        OsalMemFree(boardCfg);
        boardCfg = NULL;
    }
    return boardCfg;
}

然后drivers/framework/model/input/driver/input_config_parser.c里面执行ParseTouchBoardConfig函数

int32_t ParseTouchBoardConfig(const struct DeviceResourceNode *node, TouchBoardCfg *config)
{
    int32_t ret;
    struct DeviceResourceIface *parser = NULL;

    if (node == NULL || config == NULL) {
        HDF_LOGE("%s: input param is null", __func__);
        return HDF_FAILURE;
    }
    parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (parser == NULL) {
        HDF_LOGE("%s: invalid parser", __func__);
        return HDF_FAILURE;
    }
    config->boardNode = node;
    const struct DeviceResourceNode *attrNode = parser->GetChildNode(node, "inputAttr");
    const struct DeviceResourceNode *busNode = parser->GetChildNode(node, "busConfig");
    const struct DeviceResourceNode *pinsNode = parser->GetChildNode(node, "pinConfig");
    const struct DeviceResourceNode *powerNode = parser->GetChildNode(node, "powerConfig");
    const struct DeviceResourceNode *featureNode = parser->GetChildNode(node, "featureConfig");
    if (attrNode == NULL || busNode == NULL || pinsNode == NULL || powerNode == NULL || featureNode == NULL) {
        HDF_LOGE("%s: get child node fail!", __func__);
        return HDF_FAILURE;
    }

    ret = ParseAttr(parser, attrNode, &config->attr);
    CHECK_PARSER_RET(ret, "ParseAttr");
    ret = ParseBus(parser, busNode, &config->bus);
    CHECK_PARSER_RET(ret, "ParseBus");
    ret = ParsePins(parser, pinsNode, &config->pins);
    CHECK_PARSER_RET(ret, "ParsePins");
    ret = ParsePower(parser, powerNode, &config->power);
    CHECK_PARSER_RET(ret, "ParsePower");
    ret = ParseFeature(parser, featureNode, &config->feature);
    CHECK_PARSER_RET(ret, "ParseFeature");
    return HDF_SUCCESS;
}

重点展开此函数 DeviceResourceGetIfaceInstance,
struct DeviceResourceIface *parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
执行的是drivers/framework/ability/config/device_resource_if.c,其实就是返回一个可以操作获取hcs资源的接口函数,主要的接口函数如下

 static void HcsIfaceConstruct(struct DeviceResourceIface *instance)
{
    instance->GetRootNode = HcsGetRootNode;
    instance->GetBool = HcsGetBool;
    instance->GetUint8 = HcsGetUint8;
    instance->GetUint8ArrayElem = HcsGetUint8ArrayElem;
    instance->GetUint8Array = HcsGetUint8Array;
    instance->GetUint16 = HcsGetUint16;
    instance->GetUint16ArrayElem = HcsGetUint16ArrayElem;
    instance->GetUint16Array = HcsGetUint16Array;
    instance->GetUint32 = HcsGetUint32;
    instance->GetUint32ArrayElem = HcsGetUint32ArrayElem;
    instance->GetUint32Array = HcsGetUint32Array;
    instance->GetUint64 = HcsGetUint64;
    instance->GetUint64ArrayElem = HcsGetUint64ArrayElem;
    instance->GetUint64Array = HcsGetUint64Array;
    instance->GetString = HcsGetString;
    instance->GetStringArrayElem = HcsGetStringArrayElem;
    instance->GetElemNum = HcsGetElemNum;
    instance->GetNodeByMatchAttr = HcsGetNodeByMatchAttr;
    instance->GetChildNode = HcsGetChildNode;
    instance->GetNodeByRefAttr = HcsGetNodeByRefAttr;
}

回到之前,那我们操作const struct DeviceResourceNode *attrNode = parser->GetChildNode(node, “inputAttr”);函数,其实执行的就是HcsGetChildNode函数,此函数定义在drivers/framework/ability/config/hcs_parser/src/hcs_tree_if.c文件中

const struct DeviceResourceNode *HcsGetChildNode(const struct DeviceResourceNode *node, const char *nodeName)
{
    struct DeviceResourceNode *child = NULL;
    if ((node == NULL) || (nodeName == NULL)) {
        HDF_LOGE("%s failed, the node or nodeName is NULL", __func__);
        return NULL;
    }

    for (child = node->child; child != NULL; child = child->sibling) {
        if ((child->name != NULL) && (strcmp(nodeName, child->name) == 0)) {
            break;
        }
    }
    return child;
}

很简单,直接遍历查找匹配字段返回即可,所以其实就是遍历节点,然后返回对应字段的描述。通过上述函数,重要的节点信息已经保存到变量boardCfg中,然后执行TouchDriverInit函数,将会使用到这些数据进行初始化操作。

static int32_t TouchDriverInit(TouchDriver *driver, TouchBoardCfg *config)
{
    int32_t ret = TouchInitData(driver, config); //展开如下,可以看出其实就是给变量赋值
/*
static int32_t TouchInitData(TouchDriver *driver, TouchBoardCfg *config)
{
    driver->devType = config->attr.devType; //获取hcs中的inputAttr节点下的inputType字段
    driver->devName = config->attr.devName; //获取hcs中的inputAttr节点下的devName字段
    driver->i2cClient.i2cCfg.busNum = config->bus.i2c.busNum;//获取hcs中的busConfig节点下的ParseBus字段
    driver->irqStopFlag = false;

    return HDF_SUCCESS;
}

*/
    CHECK_RETURN_VALUE(ret);

    ret = TouchSetupBus(driver, config); //主要打开设备操作节点,类似linux应用层,打开dev/i2c节点
    /*
    static int32_t TouchSetupBus(TouchDriver *driver, TouchBoardCfg *config)
{
    uint8_t busType = config->bus.busType;
    uint8_t busNum = config->bus.i2c.busNum;
    if (busType == I2C_TYPE) {
        uint32_t i2cClkAddr = config->bus.i2c.i2cClkReg[0];
        uint32_t i2cClkValue = config->bus.i2c.i2cClkReg[1];
        uint32_t i2cDataAddr = config->bus.i2c.i2cDataReg[0];
        uint32_t i2cDataValue = config->bus.i2c.i2cDataReg[1];

        if (InputPinMuxCfg(i2cClkAddr, REGISTER_BYTE_SIZE, i2cClkValue) != HDF_SUCCESS) {
            return HDF_FAILURE;
        }
        if (InputPinMuxCfg(i2cDataAddr, REGISTER_BYTE_SIZE, i2cDataValue) != HDF_SUCCESS) {
            return HDF_FAILURE;
        }

        //get i2c handle
        driver->i2cClient.i2cHandle = I2cOpen(busNum);
        if (driver->i2cClient.i2cHandle == NULL) {
            HDF_LOGE("%s: open i2c%u failed", __func__, busNum);
            return HDF_FAILURE;
        }
        return HDF_SUCCESS;
    }

    if (busType == SPI_TYPE) {
        HDF_LOGI("%s: setup spi bus succ", __func__);
        return HDF_SUCCESS;
    }

    return HDF_FAILURE;
}

    */


    CHECK_RETURN_VALUE(ret);

    ret = OsalMutexInit(&driver->mutex);
    CHECK_RETURN_VALUE(ret);

    driver->initedFlag = true;
    return HDF_SUCCESS;
}

然后再加载器件驱动:器件驱动也由HDF框架加载,完成器件设备的实例化,包括器件私有配置解析和平台预留的差异化接口适配。这里使用的是gt911触摸芯片,所以执行的文件是drivers/framework/model/input/driver/touchscreen/touch_gt911.c,
入口函数内容如下

static int32_t HdfGoodixChipInit(struct HdfDeviceObject *device)
{
    TouchChipCfg *chipCfg = NULL;
    ChipDevice *chipDev = NULL;

    HDF_LOGI("%s: enter", __func__);
    if (device == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }

    chipCfg = ChipConfigInstance(device);
    if (chipCfg == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }

    chipDev = ChipDeviceInstance();
    if (chipDev == NULL) {
        goto EXIT;
    }

    chipDev->chipCfg = chipCfg;
    chipDev->ops = &g_gt911ChipOps;
    chipDev->chipName = chipCfg->chipName;
    chipDev->vendorName = chipCfg->vendorName;

    if (RegisterChipDevice(chipDev) != HDF_SUCCESS) {
        goto EXIT1;
    }
    HDF_LOGI("%s: exit succ, chipName = %s", __func__, chipCfg->chipName);
    return HDF_SUCCESS;

EXIT1:
    OsalMemFree(chipDev);
EXIT:
    FreeChipConfig(chipCfg);
    return HDF_FAILURE;
}

执行函数

static TouchChipCfg *ChipConfigInstance(struct HdfDeviceObject *device)
{
    TouchChipCfg *chipCfg = (TouchChipCfg *)OsalMemAlloc(sizeof(TouchChipCfg));
    if (chipCfg == NULL) {
        HDF_LOGE("%s: instance chip config failed", __func__);
        return NULL;
    }
    (void)memset_s(chipCfg, sizeof(TouchChipCfg), 0, sizeof(TouchChipCfg));

    if (ParseTouchChipConfig(device->property, chipCfg) != HDF_SUCCESS) {
        HDF_LOGE("%s: parse chip config failed", __func__);
        OsalMemFree(chipCfg);
        chipCfg = NULL;
    }
    return chipCfg;
}
int32_t ParseTouchChipConfig(const struct DeviceResourceNode *node, TouchChipCfg *config)
{
    int32_t ret;
    struct DeviceResourceIface *parser = NULL;
    if (node == NULL || config == NULL) {
        HDF_LOGE("%s: point is null", __func__);
        return HDF_FAILURE;
    }
    parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (parser == NULL) {
        HDF_LOGE("%s: instance parser failed", __func__);
        return HDF_FAILURE;
    }

    config->chipNode = node;
    ret = parser->GetString(node, "chipName", &config->chipName, NULL);
    CHECK_PARSER_RET(ret, "GetString");
    ret = parser->GetString(node, "vendorName", &config->vendorName, NULL);
    CHECK_PARSER_RET(ret, "GetString");
    ret = parser->GetString(node, "chipInfo", &config->chipInfo, NULL);
    CHECK_PARSER_RET(ret, "GetString");
    ret = parser->GetUint16(node, "chipVersion", &config->chipVersion, 0);
    CHECK_PARSER_RET(ret, "GetUint16");
    ret = parser->GetUint8(node, "busType", &config->bus.busType, 0);
    CHECK_PARSER_RET(ret, "GetUint8");
    if (config->bus.busType == I2C) {
        ret = parser->GetUint16(node, "irqFlag", &config->bus.chipI2c.irqFlag, 0);
        CHECK_PARSER_RET(ret, "GetUint16");
        ret = parser->GetUint32(node, "deviceAddr", &config->bus.chipI2c.commAddr, 0);
        CHECK_PARSER_RET(ret, "GetUint32");
        ret = parser->GetUint32(node, "maxSpeed", &config->bus.chipI2c.maxSpeed, DEFAULT_I2C_SPEED);
        CHECK_PARSER_RET(ret, "GetUint32");
    } else {
        ret = parser->GetUint16(node, "irqFlag", &config->bus.chipSpi.irqFlag, 0);
        CHECK_PARSER_RET(ret, "GetUint16");
        ret = parser->GetUint8(node, "wordMode", &config->bus.chipSpi.wordMode, 0);
        CHECK_PARSER_RET(ret, "GetUint8");
        ret = parser->GetUint8(node, "commMode", &config->bus.chipSpi.commMode, 0);
        CHECK_PARSER_RET(ret, "GetUint8");
        ret = parser->GetUint32(node, "maxSpeed", &config->bus.chipSpi.maxSpeed, DEFAULT_SPI_SPEED);
        CHECK_PARSER_RET(ret, "GetUint32");
    }
    const struct DeviceResourceNode *pwrSeqNode = parser->GetChildNode(node, "powerSequence");
    if (pwrSeqNode == NULL) {
        HDF_LOGE("%s: get powerSequence child node failed", __func__);
        return HDF_FAILURE;
    }
    if (ParsePowerSequence(parser, pwrSeqNode, &config->pwrSeq) != HDF_SUCCESS) {
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

总之也是获取hcs资源为主,获取完器件资源后,然后就是调用RegisterChipDevice,将实例化的器件设备向平台驱动注册,实现设备和驱动的绑定,并完成中断注册、上下电等器件初始化工作,然后又回到hdf_touch.c文件中执行,

int32_t RegisterChipDevice(ChipDevice *chipDev)
{
    int32_t ret;
    InputDevice *inputDev = NULL;
    if ((chipDev == NULL) || (chipDev->chipCfg == NULL)) {
        return HDF_ERR_INVALID_PARAM;
    }

    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 = InputDeviceInstance(chipDev);
    if (inputDev == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }

    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;
}
static int32_t ChipDriverInit(ChipDevice *chipDev)
{
    int32_t ret = SetPowerOnTiming(chipDev);
    CHECK_RETURN_VALUE(ret);

    if ((chipDev->ops == NULL) || (chipDev->ops->Detect == NULL)) {
        return HDF_FAILURE;
    }

    ret = chipDev->ops->Detect(chipDev);
    CHECK_RETURN_VALUE(ret);
    HDF_LOGI("%s: chipDetect succ, ret = %d ", __func__, ret);

#if defined(CONFIG_ARCH_SPRD)
    HDF_LOGI("%s: DAYU do not update firmware", __func__);
#else
    ret = chipDev->ops->UpdateFirmware(chipDev);
    CHECK_RETURN_VALUE(ret);
    HDF_LOGI("%s: update firmware success", __func__);
#endif

    ret = SetupChipIrq(chipDev);
    CHECK_RETURN_VALUE(ret);
    return HDF_SUCCESS;
}

我这边在使用的时候,发现经常会出现i2c通信不正常的问题,抓取上电时序的波形比较乱,然后产生了追踪下如何执行的,后面发现,这里会去操作IO寄存器的值,但是我的已经在linux内核里面初始化过GPIO了,我只需要申请并使用就可,所以我这边这里不需要操作。

static int32_t InputPinMuxCfg(uint32_t regAddr, int32_t regSize, uint32_t regValue)
{
#if defined(CONFIG_ARCH_SPRD)
    return HDF_SUCCESS;
#endif
#ifdef USER_NOT_IOSET    //add by myself
    return HDF_SUCCESS;
#endif                   //add end
    uint8_t *base = NULL;
    if (regAddr == 0) {
        HDF_LOGE("%s: regAddr invalid", __func__);
        return HDF_FAILURE;
    }
    base = OsalIoRemap(regAddr, regSize);
    if (base == NULL) {
        HDF_LOGE("%s: ioremap failed", __func__);
        return HDF_FAILURE;
    }
    OSAL_WRITEL(regValue, base);
    OsalIoUnmap((void *)base);
    return HDF_SUCCESS;
}

在这里插入图片描述
目前测试很多次,不会出现偶发性I2c通信不正常的问题了。
献上失败的打印log,这种情况一般是上电时序问题造成的,我是先在linux内核调试好了触摸,再在HDF框架中调试的,所以可以排除I2C通信问题。
在这里插入图片描述

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:42:53  更:2022-04-04 12:45:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年10日历 -2024/10/25 0:34:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码