diff --git a/config/linux/ipu6epmtl/libcamhal_profile.xml b/config/linux/ipu6epmtl/libcamhal_profile.xml index 7a671a7..427c3c3 100644 --- a/config/linux/ipu6epmtl/libcamhal_profile.xml +++ b/config/linux/ipu6epmtl/libcamhal_profile.xml @@ -35,6 +35,7 @@ imx415-a-0,imx415-b-4, ar0233-1-0,ar0234-a-0,ar0234-b-4, ar0820-1-0,ar0830-a-0,ar0830-b-4, - isx031-a-0,isx031-b-4"/> + isx031-a-0,isx031-b-4, + acpi"/> diff --git a/config/linux/ipu6epmtl/sensors/acpi.xml b/config/linux/ipu6epmtl/sensors/acpi.xml new file mode 100644 index 0000000..281069b --- /dev/null +++ b/config/linux/ipu6epmtl/sensors/acpi.xml @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/platformdata/CameraParser.cpp b/src/platformdata/CameraParser.cpp index 02e2857..b5ed946 100644 --- a/src/platformdata/CameraParser.cpp +++ b/src/platformdata/CameraParser.cpp @@ -952,6 +952,8 @@ void CameraParser::parseControlElement(CameraParser* profiles, const char* name, McCtl ctl; MediaCtlConf& mc = profiles->pCurrentCam->mMediaCtlConfs.back(); + std::string acpiName; + std::string subEntity; int idx = 0; while (atts[idx]) { const char* key = atts[idx]; @@ -962,6 +964,10 @@ void CameraParser::parseControlElement(CameraParser* profiles, const char* name, if (profiles->mMC) { ctl.entity = profiles->mMC->getEntityIdByName(ctl.entityName.c_str()); } + } else if (strcmp(key, "acpiName") == 0) { + acpiName = val; + } else if (strcmp(key, "subEntity") == 0) { + subEntity = val; } else if (strcmp(key, "ctrlId") == 0) { if (!strcmp(val, "V4L2_CID_LINK_FREQ")) { ctl.ctlCmd = V4L2_CID_LINK_FREQ; @@ -1015,6 +1021,11 @@ void CameraParser::parseControlElement(CameraParser* profiles, const char* name, idx += 2; } + if (!acpiName.empty() && profiles->mMC) { + ctl.entityName = profiles->mMC->acpiName2EntityName(acpiName, subEntity); + ctl.entity = profiles->mMC->getEntityIdByName(ctl.entityName.c_str()); + } + mc.ctls.push_back(ctl); } @@ -1029,6 +1040,8 @@ void CameraParser::parseSelectionElement(CameraParser* profiles, const char* nam sel.height = 0; // height is not specified, need to be calc later. sel.formatType = FC_SELECTION; + std::string acpiName; + std::string subEntity; int idx = 0; while (atts[idx]) { const char* key = atts[idx]; @@ -1039,6 +1052,10 @@ void CameraParser::parseSelectionElement(CameraParser* profiles, const char* nam if (profiles->mMC) { sel.entity = profiles->mMC->getEntityIdByName(sel.entityName.c_str()); } + } else if (strcmp(key, "acpiName") == 0) { + acpiName = val; + } else if (strcmp(key, "subEntity") == 0) { + subEntity = val; } else if (strcmp(key, "pad") == 0) { sel.pad = strtoul(val, nullptr, 10); } else if (strcmp(key, "target") == 0) { @@ -1059,6 +1076,11 @@ void CameraParser::parseSelectionElement(CameraParser* profiles, const char* nam idx += 2; } + if (!acpiName.empty() && profiles->mMC) { + sel.entityName = profiles->mMC->acpiName2EntityName(acpiName, subEntity); + sel.entity = profiles->mMC->getEntityIdByName(sel.entityName.c_str()); + } + mc.formats.push_back(sel); } @@ -1565,8 +1587,29 @@ void CameraParser::parseVideoElement(CameraParser* profiles, const char* name, McVideoNode videoNode; MediaCtlConf& mc = profiles->pCurrentCam->mMediaCtlConfs.back(); - videoNode.name = replaceStringInXml(profiles, atts[1], name); - videoNode.videoNodeType = GetNodeType(atts[3]); + std::string acpiName; + std::string subEntity; + int idx = 0; + while (atts[idx]) { + const char* key = atts[idx]; + const char* val = atts[idx + 1]; + LOG2("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx + 1, val); + if (strcmp(key, "name") == 0) { + videoNode.name = replaceStringInXml(profiles, val, name); + } else if (strcmp(key, "acpiName") == 0) { + acpiName = val; + } else if (strcmp(key, "subEntity") == 0) { + subEntity = val; + } else if (strcmp(key, "videoNodeType") == 0) { + videoNode.videoNodeType = GetNodeType(val); + } + idx += 2; + } + + if (!acpiName.empty() && profiles->mMC) { + videoNode.name = profiles->mMC->acpiName2EntityName(acpiName, subEntity); + } + LOG2("@%s, name:%s, videoNodeType:%d", __func__, videoNode.name.c_str(), videoNode.videoNodeType); @@ -2505,12 +2548,22 @@ std::vector CameraParser::getAvailableSensors( if (mMC && mMC->checkAvailableSensor(sensor)) { availableSensors.push_back(sensor); LOG2("@%s, available sensor name: %s", __func__, sensor.c_str()); + continue; + } + // Look for ACPI-described sensors: any pure-source entity in + // the media graph that exposes a non-empty firmware_node/path is + // treated as ACPI-described. + else if (mMC && mMC->checkAvailableAcpiSensor()) { + availableSensors.push_back(sensor); + LOG2("@%s, found ACPI-described sensor %s", __func__, sensor.c_str()); + continue; + } #ifdef LINUX_BUILD - } else if (sensor.find("_usb") != string::npos) { + else if (sensor.find("_usb") != string::npos) { availableSensors.push_back(sensor); LOG2("@%s, available usb sensor name: %s", __func__, sensor.c_str()); -#endif } +#endif } else { // sensors with suffix port number std::string portNum = sensor.substr(sensor.find_last_of('-') + 1); diff --git a/src/v4l2/MediaControl.cpp b/src/v4l2/MediaControl.cpp index 127744e..f1a4193 100644 --- a/src/v4l2/MediaControl.cpp +++ b/src/v4l2/MediaControl.cpp @@ -61,6 +61,7 @@ struct MediaEntity { unsigned int numLinks; char devname[32]; + char acpiname[32]; }; static const string ivscName = "Intel IVSC CSI"; @@ -515,7 +516,7 @@ int MediaControl::getDevnameFromSysfs(MediaEntity* entity) { ret = readlink(sysName, target, MAX_TARGET_NAME); if (ret <= 0) { - LOGE("readlink sysName %s failed ret %d.", sysName, ret); + LOGE("readlink entity %s sysName %s failed ret %d.", entity->info.name, sysName, ret); return -EINVAL; } target[MAX_TARGET_NAME - 1] = '\0'; @@ -541,6 +542,20 @@ int MediaControl::getDevnameFromSysfs(MediaEntity* entity) { snprintf(entity->devname, sizeof(entity->devname), "/dev/%s", d); } + size_t sysNameLen = strlen(sysName); + snprintf(sysName + sysNameLen, sizeof(sysName) - sysNameLen, "/device/firmware_node/path"); + FILE* fp = fopen(sysName, "rb"); + if (fp) { + if (fgets(entity->acpiname, sizeof(entity->acpiname), fp) != nullptr) { + size_t len = strlen(entity->acpiname); + if (len > 0 && entity->acpiname[len - 1] == '\n') { + entity->acpiname[len - 1] = '\0'; + } + } + fclose(fp); + } + LOG1("name %s devname %s acpiname %s", entity->info.name, entity->devname, entity->acpiname); + return 0; } @@ -1209,6 +1224,55 @@ bool MediaControl::checkAvailableSensor(const std::string& sensorEntityName, return false; } +// This function must be called after enumEntities(). +// Recursively walk the source side of the given sink and return true if any +// pure source entity has a non-empty acpiname (i.e. is ACPI-described). +bool MediaControl::checkHasAcpiSource(const MediaEntity* sink) { + for (unsigned int i = 0U; i < sink->numLinks; ++i) { + if (sink->links[i].sink->entity == sink) { + MediaEntity* pre = sink->links[i].source->entity; + if (isMediaSourceEntity(pre)) { + if (pre->acpiname[0] != '\0') { + return true; + } + } else { + if (checkHasAcpiSource(pre)) { + return true; + } + } + } + } + return false; +} + +// This function must be called after enumEntities(). +bool MediaControl::checkAvailableAcpiSensor(const std::string& sinkEntityName) { + LOG1("@%s, sinkEntityName:%s", __func__, sinkEntityName.c_str()); + + for (auto& entity : mEntities) { + if (strcmp(sinkEntityName.c_str(), entity.info.name) == 0) { + return checkHasAcpiSource(&entity); + } + } + + return false; +} + +// This function must be called after enumEntities(). +bool MediaControl::checkAvailableAcpiSensor() { + LOG1("@%s", __func__); + + for (auto& entity : mEntities) { + if (isMediaSourceEntity(&entity) && entity.acpiname[0] != '\0') { + LOG1("@%s, found ACPI source entity %s (acpiname=%s)", __func__, entity.info.name, + entity.acpiname); + return true; + } + } + + return false; +} + // This function must be called after enumEntities(). int MediaControl::getI2CBusAddress(const string& sensorEntityName, const string& sinkEntityName, string* i2cBus) { @@ -1242,6 +1306,19 @@ int MediaControl::getI2CBusAddress(const string& sensorEntityName, const string& return UNKNOWN_ERROR; } +std::string MediaControl::acpiName2EntityName(const std::string& acpiName, + const std::string& subEntity) { + for (auto& entity : mEntities) { + if (strcmp(entity.acpiname, acpiName.c_str()) == 0) { + if (subEntity.empty() || strstr(entity.info.name, subEntity.c_str()) != nullptr) { + return std::string(entity.info.name); + } + } + } + + return ""; +} + // DUMP_ENTITY_TOPOLOGY_S void MediaControl::dumpTopologyDot() { printf("digraph board {\n"); diff --git a/src/v4l2/MediaControl.h b/src/v4l2/MediaControl.h index f9666bf..2709523 100644 --- a/src/v4l2/MediaControl.h +++ b/src/v4l2/MediaControl.h @@ -306,6 +306,9 @@ class MediaControl { bool checkAvailableSensor(const std::string& sensorEntityName); bool checkAvailableSensor(const std::string& sensorEntityName, const std::string& sinkEntityName); + + bool checkAvailableAcpiSensor(const std::string& sinkEntityName); + bool checkAvailableAcpiSensor(); /** * Getting I2C bus address by the name of sensor entity and the name of sensor's sink entity. * @@ -317,6 +320,9 @@ class MediaControl { int getI2CBusAddress(const std::string& sensorEntityName, const std::string& sinkEntityName, std::string* i2cBus); + std::string acpiName2EntityName(const std::string& acpiName, + const std::string& subEntity = ""); + int getMediaCfgId() { return mMediaCfgId; } private: @@ -338,6 +344,7 @@ class MediaControl { MediaEntity* getEntityById(uint32_t id); MediaEntity* getEntityByName(const char* name); bool checkHasSource(const MediaEntity* sink, const std::string& source); + bool checkHasAcpiSource(const MediaEntity* sink); // set up entity link.