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.