最近在调试触摸驱动,分析了一点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 handledriver->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__);
#elseret = chipDev->ops->UpdateFirmware(chipDev);CHECK_RETURN_VALUE(ret);HDF_LOGI("%s: update firmware success", __func__);
#endifret = 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 myselfreturn HDF_SUCCESS;
#endif //add enduint8_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通信问题。
最后经过测试发现,触摸驱动是乱的,对不上屏幕,然后对应本板子,做如下修改即可
diff --git a/drivers/framework/model/input/driver/hdf_touch.c b/drivers/framework/model/input/driver/hdf_touch.c
index 9602a3e136..459ec88dd1 100644
--- a/drivers/framework/model/input/driver/hdf_touch.c
+++ b/drivers/framework/model/input/driver/hdf_touch.c
@@ -194,7 +194,6 @@ static int32_t IrqHandle(uint16_t intGpioNum, void *data)HDF_LOGE("%s: disable irq failed, ret %d", __func__, ret);return HDF_FAILURE;}
-EventHandle(driver, driver->device);ret = GpioEnableIrq(intGpioNum);
@@ -272,9 +271,9 @@ static int32_t ChipDriverInit(ChipDevice *chipDev)#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__);
+// ret = chipDev->ops->UpdateFirmware(chipDev);
+ // CHECK_RETURN_VALUE(ret);
+ //HDF_LOGI("%s: update firmware success", __func__);
这里修改的主要是去掉固件下发的功能,我们不需要每次都下发固件,所以我们注释掉,使用默认的有可能造成触摸硬件本身就变乱的情况,请谨慎操作。
diff --git a/drivers/framework/model/input/driver/touchscreen/touch_gt911.c b/drivers/framework/model/input/driver/touchscreen/touch_gt911.c
index fb3f5e96fd..6aa7f85b04 100644
--- a/drivers/framework/model/input/driver/touchscreen/touch_gt911.c
+++ b/drivers/framework/model/input/driver/touchscreen/touch_gt911.c
@@ -101,11 +101,15 @@ static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uframe->fingers[i].x = ((buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) <<ONE_BYTE_OFFSET)) * resX / resY;
-#else
+#else/*frame->fingers[i].y = (buf[GT_POINT_SIZE * i + GT_X_LOW] & ONE_BYTE_MASK) |((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);frame->fingers[i].x = (buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |
- ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
+ ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);*/
+ frame->fingers[i].x = (buf[GT_POINT_SIZE * i + GT_X_LOW] & ONE_BYTE_MASK) |
+ ((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
+ frame->fingers[i].y = ((buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET));#endifif (frame->fingers[i].x == 0) {frame->fingers[i].x = X_OFFSET;
@@ -122,6 +126,7 @@ static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, u((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET));}frame->fingers[i].valid = true;
+// HDF_LOGD("fr_x = %d,fr_y = %d\n",frame->fingers[i].x,frame->fingers[i].y);}}
我这里是通过HDF_LOGD(“fr_x = %d,fr_y = %d\n”,frame->fingers[i].x,frame->fingers[i].y);把触摸点打印出来了,然后慢慢调整即可。