[igt-dev] [PATCH i-g-t 2/2] lib/igt_alsa: Check that ELD comes from IGT

Arkadiusz Hiler
2019-09-20T10:47:49Z

From: Simon Ser <simon.ser@intel.com>

Prior to this commit, audio tests play sound on all HDMI/DisplayPort PCM
devices (by filtering devices with the "HDMI" prefix). This had several issues.
First, the PCM device → connector mapping via the ELD wasn't checked. Second,
it makes debugging more complicated: if ALSA doesn't detect the screen, we just
get a Chamelium failure (because it doesn't receive any audio stream). Third,
it would play sounds on real screens too (not only Chamelium) and this could
theorically damage bad hardware (though this is just speculation).

To mitigate this issue, check the monitor name of PCM devices we open and only
keep them if it's an IGT EDID (ie. connected to the Chamelium board).

Note that while this is a good improvement, it isn't a complete fix: the ELD
is only exposed by the HDA Intel driver. This means non-IGT PCM devices won't
be filtered out on non-Intel hardware. There is no driver-agnostic way to get
the screen name, I'm afraid.

Cc: Martin Peres <martin.peres@linux.intel.com>
Signed-off-by: Simon Ser <simon.ser@intel.com>
Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
---
lib/igt_alsa.c | 93 +++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 81 insertions(+), 12 deletions(-)

diff --git a/lib/igt_alsa.c b/lib/igt_alsa.c
index 5b5980a9..e1836be7 100644
--- a/lib/igt_alsa.c
+++ b/lib/igt_alsa.c
@@ -31,6 +31,7 @@
#include "igt_alsa.h"
#include "igt_aux.h"
#include "igt_core.h"
+#include "igt_eld.h"

#define HANDLES_MAX 8

@@ -105,6 +106,68 @@ struct alsa *alsa_init(void)
return alsa;
}

+static bool alsa_dev_has_igt_eld(snd_ctl_t *ctl, int dev)
+{
+ snd_hctl_t *handle;
+ snd_hctl_elem_t *elem;
+ snd_ctl_elem_info_t *info;
+ snd_ctl_elem_value_t *value;
+ const char *name;
+ snd_ctl_elem_type_t type;
+ unsigned int count;
+ const char *eld;
+ bool is_igt, eld_found;
+
+ igt_assert(snd_hctl_open_ctl(&handle, ctl) == 0);
+ igt_assert(snd_hctl_load(handle) == 0);
+ igt_assert(snd_ctl_elem_info_malloc(&info) == 0);
+ igt_assert(snd_ctl_elem_value_malloc(&value) == 0);
+
+ is_igt = eld_found = false;
+ for (elem = snd_hctl_first_elem(handle); elem;
+ elem = snd_hctl_elem_next(elem)) {
+ igt_assert(snd_hctl_elem_info(elem, info) == 0);
+ name = snd_ctl_elem_info_get_name(info);
+ type = snd_ctl_elem_info_get_type(info);
+ count = snd_ctl_elem_info_get_count(info);
+
+ if (strcmp(name, "ELD") != 0)
+ continue;
+ igt_assert(type == SND_CTL_ELEM_TYPE_BYTES);
+ if (snd_ctl_elem_info_get_device(info) != dev)
+ continue;
+
+ eld_found = true;
+
+ igt_assert(snd_hctl_elem_read(elem, value) == 0);
+ if (count == 0) {
+ igt_debug("ELD found for device %s,%d, but it's empty "
+ "(the screen is probably disconnected)\n",
+ snd_hctl_name(handle), dev);
+ break;
+ }
+
+ igt_debug("ELD found for device %s,%d\n",
+ snd_hctl_name(handle), dev);
+ eld = snd_ctl_elem_value_get_bytes(value);
+ is_igt = eld_is_igt(eld, count);
+ break;
+ }
+
+ if (!eld_found) {
+ /* ELDs are probably not supported */
+ igt_debug("ELD not found for device %s,%d, skipping ELD check\n",
+ snd_hctl_name(handle), dev);
+ is_igt = true;
+ }
+
+ snd_ctl_elem_info_free(info);
+ snd_ctl_elem_value_free(value);
+ snd_hctl_free(handle);
+
+ return is_igt;
+}
+
static char *alsa_resolve_indentifier(const char *device_name, int skip)
{
snd_ctl_card_info_t *card_info;
@@ -148,7 +211,6 @@ static char *alsa_resolve_indentifier(const char *device_name, int skip)
}

dev = -1;
-
do {
ret = snd_ctl_pcm_next_device(handle, &dev);
if (ret < 0 || dev < 0)
@@ -167,21 +229,28 @@ static char *alsa_resolve_indentifier(const char *device_name, int skip)

ret = strncmp(device_name, pcm_name,
strlen(device_name));
+ if (ret != 0)
+ continue;

- if (ret == 0) {
- if (skip > 0) {
- skip--;
- continue;
- }
+ if (!alsa_dev_has_igt_eld(handle, dev)) {
+ igt_debug("Device hw:%d,%d matches the name "
+ "but doesn't have an IGT ELD\n",
+ card, dev);
+ continue;
+ }

- igt_debug("Matched device \"%s\"\n", pcm_name);
+ if (skip > 0) {
+ skip--;
+ continue;
+ }

- snprintf(name, sizeof(name), "hw:%d,%d", card,
- dev);
+ igt_debug("Matched device \"%s\" (hw:%d,%d)\n",
+ pcm_name, card, dev);

- identifier = strdup(name);
- goto resolved;
- }
+ snprintf(name, sizeof(name), "hw:%d,%d", card,
+ dev);
+ identifier = strdup(name);
+ goto resolved;
} while (dev >= 0);

snd_ctl_close(handle);
--
2.21.0