[PATCH i-g-t RFC] tests/unigraf/unigraf_connectivity: Add unigraf device support

Almahallawy, Khaled khaled.almahallawy at intel.com
Tue May 20 18:49:11 UTC 2025


Hi Louis,

On Sat, 2025-05-17 at 13:11 +0200, Louis Chauvet wrote:
> This commit introduces support for Unigraf devices, aiming to
> facilitate
> the testing of various hardware features related to display
> connections.
> 
Which Unigraf devices are we focusing on? 

> Key feature that unigraf devices can test:
> - Link training
> - Signal integrity
Which specific Unigraf device supports Signal Integrity(SI)? Which
aspects or tests of SI are we addressing?

> - HDCP
> - DSC
Will HDCP/DSC be available without requiring a license?

> - usb-c electrical characteristics
Similarly to SI, which device supports USB-C electrical
characteristics? Or are you referring to USB-C PD flows?

> 
> This implementation utilizes the external libtsi library provided by
> Unigraf, which must be downloaded separately to enable compilation.

If a new device/vendor is introduced to IGT and offers similar tests
and capabilities, do you intend to generalize the interface for tests
rather than using a vendor-specific one?

Thank You
Khaled
> 
> DO NOT MERGE!
> 
> The file lib/unigraf/TSI_types.h currently contains hardcoded values
> that
> should be replaced by the next unigraf release. The current unigraf
> SDK
> release is not c-compatible, so I had to copy those values. The
> proper v1
> will not contains hardcoded value and will use the correct
> TSI_types.h
> file.
> 
> Signed-off-by: Louis Chauvet <louis.chauvet at bootlin.com>
> ---
> Hi everyone,
> 
> I am excited to share I currently have access to a Unigraf device,
> which I believe could significantly enhance the capabilities within
> IGT.
> This device has the potential to enable testing of low-level hardware
> features that are currently not covered. Specifically, Unigraf
> devices can
> assist in testing link training, signal integrity, HDCP, DSC, and
> more.
> 
> It's important to note that the Unigraf SDK is not open-source, and
> the
> communication protocol with the device is proprietary. As a result, I
> have
> utilized the libTSI.so library, which can be downloaded from [1]. In
> this
> RFC, I have not used the official TSI_types.h header because it was
> incompatible with C, so I hardcoded some necessary values. The next
> iteration will use the official TSI_types.h (they plan to fix it for
> the
> next release)
> 
> This RFC is intentionally concise to gather initial feedback from the
> community regarding the integration of a proprietary device into the
> test
> suite. I plan to expand on this work by adding more features and
> pushing
> the developments upstream.
> 
> Looking forward to your thoughts and suggestions!
> 
> Thanks,
> Louis Chauvet
> 
> [1]:https://www.unigraf.fi/downloads/
> ---
>  lib/meson.build                      |   9 ++-
>  lib/unigraf/TSI.h                    |  91 ++++++++++++++++++++++
>  lib/unigraf/TSI_types.h              |  18 +++++
>  lib/unigraf/unigraf.c                | 143
> +++++++++++++++++++++++++++++++++++
>  lib/unigraf/unigraf.h                |  84 ++++++++++++++++++++
>  meson.build                          |  14 ++++
>  tests/meson.build                    |   4 +
>  tests/unigraf/meson.build            |  12 +++
>  tests/unigraf/unigraf_connectivity.c |  79 +++++++++++++++++++
>  9 files changed, 453 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/meson.build b/lib/meson.build
> index 8517cd540437..c1a1c8aa1b24 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -138,6 +138,13 @@ lib_deps = [
>  	zlib
>  ]
>  
> +if libtsi.found()
> +	lib_deps += libtsi
> +	lib_sources += [
> +		'unigraf/unigraf.c'
> +	]
> +endif
> +
>  if libdrm_nouveau.found()
>  	lib_deps += libdrm_nouveau
>  	lib_sources += [
> @@ -177,7 +184,7 @@ if libdrm_amdgpu.found()
>  	if cc.has_function('amdgpu_create_userqueue', dependencies:
> libdrm_amdgpu)
>  		add_project_arguments('-DAMDGPU_USERQ_ENABLED=1',
> language: 'c')
>  		#conf.set('AMDGPU_USERQ_ENABLED', 1)
> -	endif	
> +	endif
>  endif
>  
>  if libunwind.found()
> diff --git a/lib/unigraf/TSI.h b/lib/unigraf/TSI.h
> new file mode 100644
> index 000000000000..e057823c3df0
> --- /dev/null
> +++ b/lib/unigraf/TSI.h
> @@ -0,0 +1,91 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +/*
> + * tsi.h - Header for libTSI.so
> + * Documentation here is taken from official documentation and
> developer observation.
> + */
> +
> +#ifndef TSI_H
> +#define TSI_H
> +
> +#define TSI_CURRENT_VERSION	12
> +#define MAX_EDID_SIZE		4096
> +
> +#define TSI_SUCCESS		0
> +
> +typedef unsigned int		TSI_VERSION_ID;
> +typedef unsigned int		TSI_SEARCH_OPTIONS;
> +typedef unsigned int		TSI_DEVICE_CAPS;
> +typedef unsigned int		TSI_CONFIG_ID;
> +typedef unsigned int		TSI_DEVICE_ID;
> +typedef unsigned int		TSI_INPUT_ID;
> +typedef int			TSI_RESULT;
> +typedef void			*TSI_HANDLE;
> +typedef int			TSI_FLAGS;
> +
> +/**
> + * TSI_Init() - Initialize the TSI library
> + * @ClientVersion: Indicates the version used to call the libTSI.so
> functions.
> + *
> + * Initialize libTSI for use and sets up internal state. It can be
> called
> + * multiple times, but TSI_Clean must be called the exact same
> number of time.
> + *
> + * Returns:
> + * - In case of success: Reference count to the API (number of times
> to call TSI_Clean)
> + * - TSI_ERROR_NOT_COMPATIBLE if the requested client version is not
> supported
> + *   by the library
> + * - TSI_ERROR_COMPATIBILITY_MISMATCH if TSI_Init is called twice
> with
> + *   different client version
> + */
> +TSI_RESULT TSI_Init(TSI_VERSION_ID ClientVersion);
> +
> +/**
> + * TSI_Clean() - Cleans and closes the TSI library
> + *
> + * When TSI_Clean is called for the last time, cleanup the internal
> state. It
> + * should be called exactly the same number of time as TSI_Init
> + */
> +TSI_RESULT TSI_Clean(void);
> +
> +/**
> + * TSI_MISC_GetErrorDescription() - Get a human readable error
> message
> + * @ErrorCode: Error code for which you want the message
> + * @ErrorString: Pointer where to copy the message
> + * @StringMaxLen: Size of the allocated string @ErrorString
> + *
> + * The official documentation states: If the function succeeds, the
> + * return value is the number of characters required for the
> complete
> + * error description string.
> + * In reality, this function always returns 0 or error, so there is
> no way to
> + * tell if the allocated memory was big enough
> + *
> + * Returns:
> + * - >= 0 on success, theorically the required string len to store
> the message
> + * - < 0 on failure
> + */
> +TSI_RESULT TSI_MISC_GetErrorDescription(TSI_RESULT ErrorCode,
> +					char *ErrorString,
> +					unsigned int StringMaxLen);
> +
> +TSI_RESULT TSIX_TS_GetConfigItem(TSI_HANDLE Device, TSI_CONFIG_ID
> ConfigItemID,
> +				 void *ConfigItemData,
> +				 unsigned int ItemMaxSize);
> +
> +TSI_RESULT TSIX_DEV_RescanDevices(TSI_SEARCH_OPTIONS SearchOptions,
> +				  TSI_DEVICE_CAPS RequiredCaps,
> +				  TSI_DEVICE_CAPS UnallowedCaps);
> +TSI_RESULT TSIX_DEV_GetDeviceCount(void);
> +
> +TSI_HANDLE TSIX_DEV_OpenDevice(TSI_DEVICE_ID DeviceID, TSI_RESULT
> *Result);
> +
> +TSI_RESULT TSIX_DEV_CloseDevice(TSI_HANDLE Device);
> +
> +TSI_RESULT TSIX_VIN_Disable(TSI_HANDLE Device);
> +
> +TSI_RESULT TSIX_VIN_Select(TSI_HANDLE Device, TSI_INPUT_ID InputID);
> +TSI_RESULT TSIX_DEV_SelectRole(TSI_HANDLE Device, int RoleIndex);
> +TSI_RESULT TSIX_TS_SetConfigItem(TSI_HANDLE Device, TSI_CONFIG_ID
> ConfigItemID,
> +				 const void *ItemData, unsigned int
> ItemSize);
> +TSI_RESULT TSIX_VIN_Enable(TSI_HANDLE Device, TSI_FLAGS Flags);
> +
> +#endif
> diff --git a/lib/unigraf/TSI_types.h b/lib/unigraf/TSI_types.h
> new file mode 100644
> index 000000000000..a3bd20f53066
> --- /dev/null
> +++ b/lib/unigraf/TSI_types.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +// DO NOT MERGE THIS FILE
> +//
> +// Current unigraf public release are not c-compatible, this file
> hardcode some values
> +// The next release of libTSI should include a c-compatible
> TSI_types.h file, that will
> +// be directly used in place of this file
> +
> +#ifndef TSI_REG_H
> +
> +#define TSI_VERSION_TEXT			0x80000001
> +#define TSI_DEVCAP_VIDEO_CAPTURE		0x00000001
> +#define TSI_SEARCHOPTIONS_SHOW_DEVICES_IN_USE	0x00000001
> +
> +#define TSI_EDID_TE_INPUT			0x1100
> +#define TSI_EDID_SELECT_STREAM			0x1102
> +
> +#endif
> diff --git a/lib/unigraf/unigraf.c b/lib/unigraf/unigraf.c
> new file mode 100644
> index 000000000000..3200cb881f91
> --- /dev/null
> +++ b/lib/unigraf/unigraf.c
> @@ -0,0 +1,143 @@
> +// SPDX-License-Identifier: MIT
> +
> +#include "igt_core.h"
> +#include "igt_edid.h"
> +#include <stdint.h>
> +#include <stdio.h>
> +
> +#include "unigraf.h"
> +#include "TSI.h"
> +#include "TSI_types.h"
> +
> +static int unigraf_open_count;
> +
> +/**
> + * unigraf_exit_handler - Handle the exit signal and clean up
> unigraf resources.
> + * @sig: The signal number received.
> + *
> + * This function is called when the program receives an exit signal.
> It ensures
> + * that all unigraf resources are properly cleaned up by calling
> unigraf_deinit
> + * for each open instance.
> + */
> +static void unigraf_exit_handler(int sig)
> +{
> +	while (unigraf_open_count)
> +		unigraf_deinit();
> +}
> +
> +void unigraf_init(void)
> +{
> +	int ret;
> +
> +	igt_debug("TSI: Initialize unigraf...\n");
> +
> +	__sync_fetch_and_add(&unigraf_open_count, 1);
> +	ret = TSI_Init(TSI_CURRENT_VERSION);
> +	if (ret < TSI_SUCCESS)
> +		__sync_fetch_and_sub(&unigraf_open_count, 1);
> +	else
> +		igt_install_exit_handler(unigraf_exit_handler);
> +	unigraf_assert(ret);
> +}
> +
> +void unigraf_deinit(void)
> +{
> +	igt_debug("TSI: Uninitialize unigraf...\n");
> +
> +	if (unigraf_open_count >= 1) {
> +		TSI_Clean();
> +		__sync_fetch_and_sub(&unigraf_open_count, 1);
> +	}
> +}
> +
> +/**
> + * unigraf_write() - Helper to write a value to unigraf
> + * @dev: device handle, can be null for some config id
> + * @config: config id to write
> + * @data: data to write
> + * @data_len: length of the data
> + * Returns
> + */
> +static void unigraf_write(TSI_HANDLE dev, TSI_CONFIG_ID config,
> const void *data, size_t data_len)
> +{
> +	igt_debug("TSI: Writing %zu bytes to %d\n", data_len,
> config);
> +
> +	unigraf_assert(TSIX_TS_SetConfigItem(dev, config, data,
> data_len));
> +}
> +
> +/**
> + * unigraf_rescan_device() - Force the scan of all connected device
> + */
> +static void unigraf_rescan_devices(void)
> +{
> +	unigraf_assert(TSIX_DEV_RescanDevices(0,
> TSI_DEVCAP_VIDEO_CAPTURE, 0));
> +}
> +
> +/**
> + * unigraf_device_count() - Return the number of scanned devices
> + *
> + * Must be called after a unigraf_rescan_devices().
> + */
> +static unsigned int unigraf_device_count(void)
> +{
> +	return unigraf_assert(TSIX_DEV_GetDeviceCount());
> +}
> +
> +char *unigraf_get_version(TSI_HANDLE dev)
> +{
> +	int ret;
> +	void *data;
> +
> +	igt_debug("TSI: Fetching version for device %p\n", dev);
> +
> +	ret = unigraf_assert(TSIX_TS_GetConfigItem(dev,
> TSI_VERSION_TEXT, NULL, 0));
> +
> +	data = malloc(ret);
> +	memset(data, 0, ret);
> +	ret = unigraf_assert(TSIX_TS_GetConfigItem(dev,
> TSI_VERSION_TEXT, data, ret));
> +
> +	return data;
> +}
> +
> +void unigraf_close_device(TSI_HANDLE dev)
> +{
> +	igt_debug("TSI: Closing device %p\n", dev);
> +	unigraf_assert(TSIX_DEV_CloseDevice(dev));
> +}
> +
> +TSI_HANDLE unigraf_require_device(void)
> +{
> +	TSI_RESULT r;
> +	TSI_HANDLE handle;
> +
> +	unigraf_rescan_devices();
> +
> +	igt_require(unigraf_device_count() >= 1);
> +	handle = TSIX_DEV_OpenDevice(0, &r);
> +	unigraf_assert(r);
> +	igt_assert(handle);
> +
> +	igt_debug("TSI: Opened device %p. Selecting role and
> input...\n", handle);
> +
> +	// By default, enable the first role and input
> +	unigraf_assert(TSIX_DEV_SelectRole(handle, 0));
> +	unigraf_assert(TSIX_VIN_Select(handle, 0));
> +	unigraf_assert(TSIX_VIN_Enable(handle, 0));
> +
> +	return handle;
> +}
> +
> +struct edid *unigraf_read_edid(TSI_HANDLE dev, uint32_t stream,
> uint32_t *edid_size)
> +{
> +	void *edid;
> +
> +	igt_debug("TSI:%p: Read EDID for stream %d...\n", dev,
> stream);
> +
> +	edid = malloc(2048);
> +	memset(edid, 0, 2048);
> +
> +	unigraf_write(dev, TSI_EDID_SELECT_STREAM, &stream,
> sizeof(stream));
> +	*edid_size = unigraf_assert(TSIX_TS_GetConfigItem(dev,
> TSI_EDID_TE_INPUT, edid, 2048));
> +
> +	return edid;
> +}
> diff --git a/lib/unigraf/unigraf.h b/lib/unigraf/unigraf.h
> new file mode 100644
> index 000000000000..57f2597d182d
> --- /dev/null
> +++ b/lib/unigraf/unigraf.h
> @@ -0,0 +1,84 @@
> +/* SPDX-License-Identifier: MIT */
> +
> +#ifndef UNIGRAF_H
> +#define UNIGRAF_H
> +
> +#include <stdint.h>
> +
> +typedef void *TSI_HANDLE;
> +
> +/**
> + * unigraf_assert: Helper macro to assert a TSI return value and
> retrieve a detailed error message.
> + * @result: libTSI return value to check
> + *
> + * This macro checks the return value of a libTSI function call. If
> the return value indicates an
> + * error, it retrieves a detailed error message and asserts with
> that message.
> + * If retrieving the error description fails, it asserts with a
> generic error message.
> + */
> +#define
> unigraf_assert(result)										\
> +({								
> 					\
> +	char
> msg[256];											\
> +	TSI_RESULT __r =
> (result);									\
> +	if (__r < TSI_SUCCESS)
> {									\
> +		TSI_RESULT __r2 = TSI_MISC_GetErrorDescription(__r,
> msg, sizeof(msg));			\
> +		if (__r2 <
> TSI_SUCCESS)									\
> +			igt_assert_f(false, "unigraf error: %d (get
> error description failed: %d)\n",	\
> +				     __r,
> __r2);							\
> +		else						
> 					\
> +			igt_assert_f(false, "unigraf error: %d
> (%s)\n", __r, msg);			\
> +	}							
> 					\
> +	(__r);							
> 					\
> +})
> +
> +/**
> + * unigraf_init() - Initialize the unigraf library
> + *
> + * This function initializes the unigraf library and install an exit
> + * handler to ensure proper cleanup on program termination.
> + */
> +void unigraf_init(void);
> +
> +/**
> + * unigraf_deinit() - Uninitialize the unigraf library
> + */
> +void unigraf_deinit(void);
> +
> +/**
> + * unigraf_get_version() - Retrieve the version information of the
> libTSI library and the device.
> + * @dev: The device handle. If set, the function will also retrieve
> information from the device.
> +
> + * Returns: A null-terminated string containing the version
> information. The caller
> + * is responsible to free this string.
> + */
> +char *unigraf_get_version(TSI_HANDLE dev);
> +
> +/**
> + * unigraf_require_device() - Search and open a device.
> + *
> + * Returns: A non-null opaque pointer to the device handle if
> successful, otherwise NULL.
> + *
> + * This function searches for a compatible device and opens it. If a
> device is found and
> + * successfully opened, it returns a non-null opaque pointer to the
> device handle. If no device
> + * is found or an error occurs during the opening process, the
> function will handle the error
> + * appropriately and return a null pointer.
> + */
> +TSI_HANDLE unigraf_require_device(void);
> +
> +/**
> + * unigraf_close_device() - Close the device.
> + * @dev: The device handle to close.
> + */
> +void unigraf_close_device(TSI_HANDLE dev);
> +
> +/**
> + * unigraf_read_edid() - Read the EDID from the specified input
> + * @dev: The device handle
> + * @stream: The stream ID to read the EDID from
> + * @edid_size: Pointer to an integer where the size of the EDID will
> be stored
> + *
> + * Returns: A pointer to the EDID structure, or NULL if the
> operation failed. The caller
> + * is responsible to free this pointer.
> + */
> +struct edid *unigraf_read_edid(TSI_HANDLE dev, uint32_t stream,
> uint32_t *edid_size);
> +
> +#endif // UNIGRAF_H
> diff --git a/meson.build b/meson.build
> index 6a580bd7e3a3..d143e3835475 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -162,6 +162,12 @@ cairo = dependency('cairo', version : '>1.12.0',
> required : true)
>  libudev = dependency('libudev', required : true)
>  glib = dependency('glib-2.0', required : true)
>  
> +libtsi = cc.find_library('TSI', required : false)
> +
> +if libtsi.found()
> +	config.set('HAVE_UNIGRAF', 1)
> +endif
> +
>  xmlrpc = dependency('xmlrpc', required : false)
>  xmlrpc_util = dependency('xmlrpc_util', required : false)
>  xmlrpc_client = dependency('xmlrpc_client', required : false)
> @@ -285,6 +291,7 @@ libexecdir = join_paths(get_option('libexecdir'),
> 'igt-gpu-tools')
>  amdgpudir = join_paths(libexecdir, 'amdgpu')
>  msmdir = join_paths(libexecdir, 'msm')
>  panfrostdir = join_paths(libexecdir, 'panfrost')
> +unigrafdir = join_paths(libexecdir, 'unigraf')
>  v3ddir = join_paths(libexecdir, 'v3d')
>  vc4dir = join_paths(libexecdir, 'vc4')
>  vmwgfxdir = join_paths(libexecdir, 'vmwgfx')
> @@ -353,6 +360,12 @@ if get_option('use_rpath')
>  		vmwgfx_rpathdir = join_paths(vmwgfx_rpathdir, '..')
>  	endforeach
>  	vmwgfx_rpathdir = join_paths(vmwgfx_rpathdir, libdir)
> +
> +	unigraf_rpathdir = '$ORIGIN'
> +	foreach p : unigrafdir.split('/')
> +		unigraf_rpathdir = join_paths(unigraf_rpathdir,
> '..')
> +	endforeach
> +	unigraf_rpathdir = join_paths(unigraf_rpathdir, libdir)
>  else
>  	bindir_rpathdir = ''
>  	libexecdir_rpathdir = ''
> @@ -362,6 +375,7 @@ else
>  	v3d_rpathdir = ''
>  	vc4_rpathdir = ''
>  	vmwgfx_rpathdir = ''
> +	unigraf_rpathdir = ''
>  endif
>  
>  build_testplan = get_option('testplan')
> diff --git a/tests/meson.build b/tests/meson.build
> index 6328792e3a4d..14798547603f 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -452,6 +452,10 @@ foreach prog : intel_progs
>  	endif
>  endforeach
>  
> +if libtsi.found()
> +	subdir('unigraf')
> +endif
> +
>  if chamelium.found()
>  	foreach prog : chamelium_progs
>  		testexe = executable(prog,
> diff --git a/tests/unigraf/meson.build b/tests/unigraf/meson.build
> new file mode 100644
> index 000000000000..4ef8c32151e4
> --- /dev/null
> +++ b/tests/unigraf/meson.build
> @@ -0,0 +1,12 @@
> +unigraf_progs = [
> +	'unigraf_connectivity',
> +]
> +
> +foreach prog : unigraf_progs
> +	test_executables += executable(prog, prog + '.c',
> +				       dependencies : test_deps,
> +				       install_dir : unigrafdir,
> +				       install_rpath :
> unigraf_rpathdir,
> +				       install : true)
> +	test_list += join_paths('unigraf', prog)
> +endforeach
> diff --git a/tests/unigraf/unigraf_connectivity.c
> b/tests/unigraf/unigraf_connectivity.c
> new file mode 100644
> index 000000000000..01266e84db76
> --- /dev/null
> +++ b/tests/unigraf/unigraf_connectivity.c
> @@ -0,0 +1,79 @@
> +// SPDX-License-Identifier: MIT
> +
> +#include <cstdint>
> +#include <xf86drmMode.h>
> +
> +#include "drmtest.h"
> +#include "igt_aux.h"
> +#include "igt_core.h"
> +#include "igt_kms.h"
> +#include "unigraf/unigraf.h"
> +
> +/**
> + * TEST: unigraf connectivity
> + * Category: Core
> + * Description: Testing connectivity with a unigraf device
> + *
> + * SUBTEST: unigraf-open
> + * Description: Make sure that a unigraf device can be accessed
> + *
> + * SUBTEST: unigraf-connected
> + * Description: Make sure that the unigraf device is connected to
> the DUT
> + */
> +
> +IGT_TEST_DESCRIPTION("Test basic unigraf connectivity");
> +igt_main
> +{
> +	TSI_HANDLE unigraf_dev;
> +
> +	igt_fixture {
> +		unigraf_init();
> +	}
> +
> +	igt_describe("Testing connectivity with a unigraf device");
> +	igt_subtest("unigraf-open") {
> +		unigraf_dev = unigraf_require_device();
> +		unigraf_close_device(unigraf_dev);
> +	}
> +
> +	igt_describe("Make sure that the unigraf device is connected
> to the DUT");
> +	igt_subtest("unigraf-connected") {
> +		drmModePropertyBlobPtr edid_blob = NULL;
> +		struct igt_display display;
> +		uint64_t edid_blob_id;
> +		igt_output_t *output;
> +		uint32_t unigraf_edid_len;
> +		void *unigraf_edid;
> +		int drm_fd;
> +		bool found;
> +
> +		unigraf_dev = unigraf_require_device();
> +
> +		drm_fd = drm_open_driver_master(DRIVER_ANY);
> +		igt_display_require(&display, drm_fd);
> +
> +		unigraf_edid = unigraf_read_edid(unigraf_dev, 0,
> &unigraf_edid_len);
> +
> +		for_each_connected_output(&display, output) {
> +			if (output->config.connector->connector_type
> == DRM_MODE_CONNECTOR_DisplayPort) {
> +				igt_assert(kmstest_get_property(drm_
> fd, output->config.connector->connector_id,
> +								DRM_
> MODE_OBJECT_CONNECTOR, "EDID", NULL,
> +								&edi
> d_blob_id, NULL));
> +				edid_blob =
> drmModeGetPropertyBlob(drm_fd, edid_blob_id);
> +				igt_assert(edid_blob);
> +
> +				found |= memcmp(unigraf_edid,
> edid_blob->data, min(edid_blob->length, unigraf_edid_len)) == 0;
> +
> +				drmModeFreePropertyBlob(edid_blob);
> +			}
> +		}
> +		igt_assert_f(found, "No output with the correct EDID
> was found\n");
> +
> +		free(unigraf_edid);
> +		unigraf_close_device(unigraf_dev);
> +	}
> +
> +	igt_fixture {
> +		unigraf_deinit();
> +	}
> +}
> 
> ---
> base-commit: a5f980e11a5540c1c079cc6fceb2b2d889b5a460
> change-id: 20250425-unigraf-integration-11ed330755d5
> 
> Best regards,



More information about the igt-dev mailing list