最近在调试触摸驱动,分析了一点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,
.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);
CHECK_RETURN_VALUE(ret);
ret = TouchSetupBus(driver, config);
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
return HDF_SUCCESS;
#endif
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通信问题。
|