[Intel-gfx] [PATCH i-g-t v4] tools: Add intel_dp_compliance for DisplayPort 1.2 compliance automation
Petri Latvala
petri.latvala at intel.com
Tue Jan 24 09:49:48 UTC 2017
Just one more nitpick (in two parts) below. With that, you can
consider this now to be
Reviewed-by: Petri Latvala <petri.latvala at intel.com>
This patch can be pushed when the kernel changes that contain "must be
kept in sync" numbers in intel_dp_compliance.c have landed (and have
been double-checked to match).
--
Petri Latvala
On Mon, Jan 23, 2017 at 06:48:53PM -0800, Manasi Navare wrote:
> From: "Navare, Manasi D" <manasi.d.navare at intel.com>
>
> This is the userspace component of the Displayport Compliance
> testing software required for compliance testing of the I915
> Display Port driver. This must be running in order to successfully
> complete Display Port compliance testing. This app and the kernel
> code that accompanies it has been written to satify the requirements
> of the Displayport Link CTS 1.2 rev1.1 specification from VESA.
> Note that this application does not support eDP compliance testing.
> This utility has an automation support for the Link training tests
> (4.3.1.1. - 4.3.2.3), EDID tests (4.2.2.3
> - 4.2.2.6) and Video Pattern generation tests (4.3.3.1) from CTS
> specification 1.2 Rev 1.1.
>
> This tool has the support for responding to the hotplug uevents
> sent by compliance testting unit after each test.
>
> The Linux DUT running this utility must be in text (console) mode
> and cannot have any other display manager running. Since this uses
> sysfs nodes for kernel interaction, this utility should be run as
> Root. Once this user application is up and running, waiting for
> test requests, the test appliance software on the windows host
> can now be used to execute the compliance tests.
>
> This app is based on some prior work done in April 2015 (by
> Todd Previte <tprevite at gmail.com>)
>
> v2:
> * Add mode unset on hotplug uevent on disconnect (Manasi Navare)
>
> v3:
> Made capitalization consistent
> Reduced line lengths
> Added return value checks
> Changed how GLib is linked
> Fixed build warnings
>
> v4:
> * Conditionally build this tool if UDEV is present (Petri Latvala)
> * igt_warn and info cleanup to remove \r
> * Add intel_dp_compliance to tools/.gitignore
> * Change the year in copyright statements to current (Petri Latvala)
>
> Cc: Petri Latvala <petri.latvala at intel.com>
> Cc: Marius Vlad <marius.c.vlad at intel.com>
> Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
> Signed-off-by: Manasi Navare <manasi.d.navare at intel.com>
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan at intel.com>
> ---
> configure.ac | 1 +
> tools/.gitignore | 1 +
> tools/Makefile.am | 6 +-
> tools/Makefile.sources | 6 +
> tools/intel_dp_compliance.c | 1104 +++++++++++++++++++++++++++++++++++
> tools/intel_dp_compliance.h | 35 ++
> tools/intel_dp_compliance_hotplug.c | 124 ++++
> 7 files changed, 1276 insertions(+), 1 deletion(-)
> create mode 100644 tools/intel_dp_compliance.c
> create mode 100644 tools/intel_dp_compliance.h
> create mode 100644 tools/intel_dp_compliance_hotplug.c
>
> diff --git a/configure.ac b/configure.ac
> index 411bfab..d268140 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -164,6 +164,7 @@ PKG_CHECK_MODULES(XRANDR, xrandr >= 1.3, AC_DEFINE(HAVE_XRANDR, 1, [Have libXran
> # for testdisplay
> PKG_CHECK_MODULES(CAIRO, [cairo >= 1.12.0])
> PKG_CHECK_MODULES(LIBUDEV, [libudev], [udev=yes], [udev=no])
> +AM_CONDITIONAL(HAVE_UDEV, [test "x$udev" = xyes])
> if test x"$udev" = xyes; then
> AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
> fi
> diff --git a/tools/.gitignore b/tools/.gitignore
> index 13825a3..9bb889f 100644
> --- a/tools/.gitignore
> +++ b/tools/.gitignore
> @@ -8,6 +8,7 @@ intel_bios_dumper
> intel_bios_reader
> intel_display_crc
> intel_display_poller
> +intel_dp_compliance
> intel_dump_decode
> intel_error_decode
> intel_firmware_decode
> diff --git a/tools/Makefile.am b/tools/Makefile.am
> index 18f86f6..363945d 100644
> --- a/tools/Makefile.am
> +++ b/tools/Makefile.am
> @@ -7,6 +7,11 @@ bin_PROGRAMS += $(LIBDRM_INTEL_BIN)
> intel_error_decode_LDFLAGS = -lz
> endif
>
> +if HAVE_UDEV
> +bin_PROGRAMS += intel_dp_compliance
> +intel_dp_compliance_LDADD = $(top_builddir)/lib/libintel_tools.la $(GLIB_LIBS)
> +endif
> +
> SUBDIRS = null_state_gen registers
>
> AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
> @@ -16,7 +21,6 @@ AM_CFLAGS = $(DEBUG_CFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) \
> LDADD = $(top_builddir)/lib/libintel_tools.la
> AM_LDFLAGS = -Wl,--as-needed
>
> -
> # aubdumper
>
> module_LTLIBRARIES = intel_aubdump.la
> diff --git a/tools/Makefile.sources b/tools/Makefile.sources
> index e2451ea..34c7a74 100644
> --- a/tools/Makefile.sources
> +++ b/tools/Makefile.sources
> @@ -56,3 +56,9 @@ intel_l3_parity_SOURCES = \
> intel_l3_parity.h \
> intel_l3_udev_listener.c
>
> +intel_dp_compliance_SOURCES = \
> + intel_dp_compliance.c \
> + intel_dp_compliance.h \
> + intel_dp_compliance_hotplug.c \
> + $(NULL)
> +
> diff --git a/tools/intel_dp_compliance.c b/tools/intel_dp_compliance.c
> new file mode 100644
> index 0000000..b25fe86
> --- /dev/null
> +++ b/tools/intel_dp_compliance.c
> @@ -0,0 +1,1104 @@
> +/*
> + * Copyright © 2017 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Displayport Compliance Testing Application
> + *
> + * This is the userspace component of the Displayport Compliance testing
> + * software required for compliance testing of the I915 Display Port driver.
> + * This must be running in order to successfully complete Display Port
> + * compliance testing. This app and the kernel code that accompanies it has been
> + * written to satify the requirements of the Displayport Link CTS 1.2 rev1.1
> + * specification from VESA. Note that this application does not support eDP
> + * compliance testing.
> + *
> + * Compliance Testing requires several components:
> + * - A kernel build that contains the patch set for DP compliance support
> + * - A Displayport Compliance Testing appliance such as Unigraf-DPR120
> + * - This user application
> + * - A windows host machine to run the DPR test software
> + * - Root access on the DUT due to the use of sysfs utility
> + *
> + * Test Setup:
> + * It is strongly recommended that the windows host, test appliance and DUT
> + * be freshly restarted before any testing begins to ensure that any previous
> + * configurations and settings will not interfere with test process. Refer to
> + * the test appliance documentation for setup, software installation and
> + * operation specific to that device.
> + *
> + * The Linux DUT must be in text (console) mode and cannot have any other
> + * display manager running. You must be logged in as root to run this user app.
> + * Once the user application is up and running, waiting for test requests, the
> + * software on the windows host can now be used to execute the compliance tests.
> + *
> + * This userspace application supports following tests from the DP CTS Spec
> + * Rev 1.1:
> + * - Link Training Tests: Supports tests 4.3.1.1 to 4.3.2.3
> + * - EDID Tests: Supports EDID read (4.2.2.3),EDID Read failure and corruption
> + * detection tests (4.2.2.4, 4.2.2.5, 4.2.2.6)
> + * - Video Pattern generation tests: This supports only the 24 and 18bpp color
> + * ramp test pattern (4.3.3.1).
> + *
> + * Connections (required):
> + * - Test Appliance connected to the external Displayport connector on the DUT
> + * - Test Appliance Monitor Out connected to Displayport connector on the
> + * monitor
> + * - Test appliance connected to the Windows Host via USB
> + *
> + * Debugfs Files:
> + * The file root for all the debugfs file:
> + * /sys/kernel/debug/dri/0/
> + *
> + * The specific files are as follows:
> + *
> + * i915_dp_test_active
> + * A simple flag that indicates whether or not compliance testing is currently
> + * active in the kernel. This flag is polled by userspace and once set, invokes
> + * the test handler in the user app. This flag is set by the test handler in the
> + * kernel after reading the registers requested by the test appliance.
> + *
> + * i915_dp_test_data
> + * Test data is used by the kernel to pass parameters to the user app. Eg: In
> + * case of EDID tests, the data that is delivered to the userspace is the video
> + * mode to be set for the test.
> + * In case of video pattern test, the data that is delivered to the userspace is
> + * the width and height of the test pattern and the bits per color value.
> + *
> + * i915_dp_test_type
> + * The test type variable instructs the user app as to what the requested test
> + * was from the sink device. These values defined at the top of the application's
> + * main implementation file must be kept in sync with the values defined in the
> + * kernel's drm_dp_helper.h file.
> + * This app is based on some prior work submitted in April 2015 by Todd Previte
> + * (<tprevite at gmail.com>)
> + *
> + *
> + * This tool can be run as:
> + * ./intel_dp_compliance It will wait till you start compliance suite from
> + * DPR 120.
> + * ./intel_dp_compliance -h This will open the help
> + * ./intel_dp_compliance -i This will provide information about current
> + * connectors/CRTCs. This can be used for debugging purpose.
> + *
> + * Authors:
> + * Manasi Navare <manasi.d.navare at intel.com>
> + *
> + * Elements of the modeset code adapted from David Herrmann's
> + * DRM modeset example
> + *
> + */
> +#include "igt.h"
> +#include <errno.h>
> +#include <getopt.h>
> +#include <math.h>
> +#include <stdint.h>
> +#include <stdbool.h>
> +#include <strings.h>
> +#include <unistd.h>
> +#include <termios.h>
> +#include <sys/poll.h>
> +#include <sys/time.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/select.h>
> +#include <assert.h>
> +#include <signal.h>
> +#include <fcntl.h>
> +#include <time.h>
> +
> +#include "intel_dp_compliance.h"
> +
> +#include <stdlib.h>
> +#include <signal.h>
> +
> +/* User Input definitions */
> +#define HELP_DESCRIPTION 1
> +
> +/* Debugfs file definitions */
> +#define INTEL_DP_TEST_TYPE_FILE "i915_dp_test_type"
> +#define INTEL_DP_TEST_ACTIVE_FILE "i915_dp_test_active"
> +#define INTEL_DP_TEST_DATA_FILE "i915_dp_test_data"
> +
> +/* DRM definitions - must be kept in sync with the DRM header */
> +#define DP_TEST_LINK_TRAINING (1 << 0)
> +#define DP_TEST_LINK_VIDEO_PATTERN (1 << 1)
> +#define DP_TEST_LINK_EDID_READ (1 << 2)
> +#define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */
> +
> +#define DP_COMPLIANCE_TEST_TYPE_MASK (DP_TEST_LINK_TRAINING | \
> + DP_TEST_LINK_VIDEO_PATTERN | \
> + DP_TEST_LINK_EDID_READ | \
> + DP_TEST_LINK_PHY_TEST_PATTERN)
> +
> +/* NOTE: These must be kept in sync with the definitions in intel_dp.c */
> +#define INTEL_DP_EDID_SHIFT_MASK 0
> +#define INTEL_DP_EDID_OK (0 << INTEL_DP_EDID_SHIFT_MASK)
> +#define INTEL_DP_EDID_CORRUPT (1 << INTEL_DP_EDID_SHIFT_MASK)
> +#define INTEL_DP_RESOLUTION_SHIFT_MASK 0
> +#define INTEL_DP_RESOLUTION_PREFERRED (1 << INTEL_DP_RESOLUTION_SHIFT_MASK)
> +#define INTEL_DP_RESOLUTION_STANDARD (2 << INTEL_DP_RESOLUTION_SHIFT_MASK)
> +#define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK)
> +#define DP_COMPLIANCE_VIDEO_MODE_MASK (INTEL_DP_RESOLUTION_PREFERRED |\
> + INTEL_DP_RESOLUTION_STANDARD |\
> + INTEL_DP_RESOLUTION_FAILSAFE)
> +
> +/* Global file pointers for the sysfs files */
> +FILE *test_active_fp, *test_data_fp, *test_type_fp;
> +
> +bool video_pattern_flag;
> +
> +/* Video pattern test globals */
> +uint16_t hdisplay;
> +uint16_t vdisplay;
> +uint8_t bitdepth;
> +
> +static int tio_fd;
> +struct termios saved_tio;
> +
> +drmModeRes *resources;
> +int drm_fd, modes;
> +uint64_t tiling = LOCAL_DRM_FORMAT_MOD_NONE;
> +uint32_t depth = 24, stride, bpp;
> +int specified_mode_num = -1, specified_disp_id = -1;
> +int width, height;
> +uint32_t test_crtc;
> +uint32_t test_connector_id;
> +enum {
> + INTEL_MODE_INVALID = -1,
> + INTEL_MODE_NONE = 0,
> + INTEL_MODE_PREFERRED,
> + INTEL_MODE_STANDARD,
> + INTEL_MODE_FAILSAFE,
> + INTEL_MODE_VIDEO_PATTERN_TEST
> +} intel_display_mode;
> +
> +struct test_video_pattern {
> + uint16_t hdisplay;
> + uint16_t vdisplay;
> + uint8_t bitdepth;
> + uint32_t fb;
> + uint32_t size;
> + struct igt_fb fb_pattern;
> + drmModeModeInfo mode;
> + uint32_t *pixmap;
> +};
> +
> +struct connector {
> + uint32_t id;
> + int mode_valid;
> + drmModeModeInfo mode, mode_standard, mode_preferred, mode_failsafe;
> + drmModeConnector *connector;
> + int crtc;
> + /* Standard and preferred frame buffer*/
> + uint32_t fb, fb_width, fb_height, fb_size;
> + uint8_t *pixmap;
> + struct igt_fb fb_video_pattern;
> + /* Failsafe framebuffer - note this is a 16-bit buffer */
> + uint32_t failsafe_fb, failsafe_width, failsafe_height;
> + uint32_t failsafe_size;
> + uint8_t *failsafe_pixmap;
> + struct igt_fb fb_failsafe_pattern;
> + struct test_video_pattern test_pattern;
> +};
> +
> +static void clear_test_active(void)
> +{
> + rewind(test_active_fp);
> + fprintf(test_active_fp, "%d", 0);
> + fflush(test_active_fp);
> +}
> +
> +static void setup_debugfs_files(void)
> +{
> + test_type_fp = igt_debugfs_fopen(INTEL_DP_TEST_TYPE_FILE, "r");
> + igt_require(test_type_fp);
> +
> + test_data_fp = igt_debugfs_fopen(INTEL_DP_TEST_DATA_FILE, "r");
> + igt_require(test_data_fp);
> +
> + test_active_fp = igt_debugfs_fopen(INTEL_DP_TEST_ACTIVE_FILE, "w+");
> + igt_require(test_active_fp);
> +
> + /* Reset the active flag for safety */
> + clear_test_active();
> +}
> +
> +static unsigned long get_test_type(void)
> +{
> + unsigned long test_type;
> + int ret;
> +
> + if (!test_type_fp)
> + fprintf(stderr, "Invalid test_type file\n");
> + rewind(test_type_fp);
> + ret = fscanf(test_type_fp, "%lx", &test_type);
> + if (ret < 1 || test_type <= 0) {
> + igt_warn("test_type read failed - %lx\n", test_type);
> + return 0;
> + }
> +
> + return test_type;
> +}
> +
> +static unsigned long get_test_edid_data(void)
> +{
> + unsigned long test_data;
> + int ret;
> +
> + if (!test_data_fp)
> + fprintf(stderr, "Invalid test_data file\r\n");
> +
> + rewind(test_data_fp);
> + ret = fscanf(test_data_fp, "%lx", &test_data);
> + if (ret < 1 || test_data <= 0) {
> + igt_warn("test_data read failed - %lx\r\n", test_data);
> + return 0;
> + }
> +
> + return test_data;
> +}
> +
> +static void get_test_videopattern_data(void)
> +{
> + int count = 0;
> + uint16_t video_pattern_value[3];
> + char video_pattern_attribute[15];
> + int ret;
> +
> + if (!test_data_fp)
> + fprintf(stderr, "Invalid test_data file\n");
> +
> + rewind(test_data_fp);
> + while (!feof(test_data_fp) && count < 3) {
> + ret = fscanf(test_data_fp, "%s %u\n", video_pattern_attribute,
> + (unsigned int *)&video_pattern_value[count++]);
> + if (ret < 2) {
> + igt_warn("test_data read failed\n");
> + return;
> + }
> + }
> +
> + hdisplay = video_pattern_value[0];
> + vdisplay = video_pattern_value[1];
> + bitdepth = video_pattern_value[2];
> + igt_info("Hdisplay = %d\n", hdisplay);
> + igt_info("Vdisplay = %d\n", vdisplay);
> + igt_info("BitDepth = %u\n", bitdepth);
> +
> +}
> +
> +static int process_test_request(int test_type)
> +{
> + int mode;
> + unsigned long test_data_edid;
> + bool valid = false;
> + switch (test_type) {
> + case DP_TEST_LINK_VIDEO_PATTERN:
> + video_pattern_flag = true;
> + get_test_videopattern_data();
> + mode = INTEL_MODE_VIDEO_PATTERN_TEST;
> + valid = true;
> + break;
> + case DP_TEST_LINK_EDID_READ:
> + test_data_edid = get_test_edid_data();
> + mode = (test_data_edid & DP_COMPLIANCE_VIDEO_MODE_MASK) >>
> + INTEL_DP_RESOLUTION_SHIFT_MASK;
> + valid = true;
> + break;
> + default:
> + /* Unknown test type */
> + fprintf(stderr, "Invalid test request, ignored.\n");
> + break;
> + }
> +
> + if (valid)
> + return update_display(mode, true);
> +
> + return -1;
> +}
> +
> +static void dump_connectors_fd(int drmfd)
> +{
> + int i, j;
> +
> + drmModeRes *mode_resources = drmModeGetResources(drmfd);
> +
> + if (!mode_resources) {
> + igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
> + return;
> + }
> +
> + igt_info("Connectors:\n");
> + igt_info("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
> + for (i = 0; i < mode_resources->count_connectors; i++) {
> + drmModeConnector *connector;
> +
> + connector = drmModeGetConnectorCurrent(drmfd,
> + mode_resources->connectors[i]);
> + if (!connector) {
> + igt_warn("Could not get connector %i: %s\n",
> + mode_resources->connectors[i], strerror(errno));
> + continue;
> + }
> +
> + igt_info("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
> + connector->connector_id,
> + connector->encoder_id,
> + kmstest_connector_status_str(connector->connection),
> + kmstest_connector_type_str(connector->connector_type),
> + connector->mmWidth,
> + connector->mmHeight,
> + connector->count_modes);
> +
> + if (!connector->count_modes)
> + continue;
> +
> + igt_info(" Modes:\n");
> + igt_info(" name refresh (Hz) hdisp hss hse htot vdisp ""vss vse vtot flags type clock\n");
> + for (j = 0; j < connector->count_modes; j++) {
> + igt_info("[%d]", j);
> + kmstest_dump_mode(&connector->modes[j]);
> + }
> +
> + drmModeFreeConnector(connector);
> + }
> + igt_info("\n");
> +
> + drmModeFreeResources(mode_resources);
> +}
> +
> +static void dump_crtcs_fd(int drmfd)
> +{
> + int i;
> + drmModeRes *mode_resources;
> +
> + mode_resources = drmModeGetResources(drmfd);
> + if (!mode_resources) {
> + igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
> + return;
> + }
> +
> + igt_info("CRTCs:\n");
> + igt_info("id\tfb\tpos\tsize\n");
> + for (i = 0; i < mode_resources->count_crtcs; i++) {
> + drmModeCrtc *crtc;
> +
> + crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]);
> + if (!crtc) {
> + igt_warn("Could not get crtc %i: %s\n", mode_resources->crtcs[i], strerror(errno));
> + continue;
> + }
> + igt_info("%d\t%d\t(%d,%d)\t(%dx%d)\n",
> + crtc->crtc_id,
> + crtc->buffer_id,
> + crtc->x,
> + crtc->y,
> + crtc->width,
> + crtc->height);
> +
> + kmstest_dump_mode(&crtc->mode);
> +
> + drmModeFreeCrtc(crtc);
> + }
> + igt_info("\n");
> +
> + drmModeFreeResources(mode_resources);
> +}
> +
> +static void dump_info(void)
> +{
> + dump_connectors_fd(drm_fd);
> + dump_crtcs_fd(drm_fd);
> +}
> +
> +static int setup_framebuffers(struct connector *dp_conn)
> +{
> +
> + dp_conn->fb = igt_create_fb(drm_fd,
> + dp_conn->fb_width, dp_conn->fb_height,
> + DRM_FORMAT_XRGB8888,
> + LOCAL_DRM_FORMAT_MOD_NONE,
> + &dp_conn->fb_video_pattern);
> + igt_assert(dp_conn->fb);
> +
> + /* Map the mapping of GEM object into the virtual address space */
> + dp_conn->pixmap = gem_mmap__gtt(drm_fd,
> + dp_conn->fb_video_pattern.gem_handle,
> + dp_conn->fb_video_pattern.size,
> + PROT_READ | PROT_WRITE);
> + if (dp_conn->pixmap == NULL)
> + return -1;
> +
> + gem_set_domain(drm_fd, dp_conn->fb_video_pattern.gem_handle,
> + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> + dp_conn->fb_size = dp_conn->fb_video_pattern.size;
> +
> + /* After filling the device memory with 0s it needs to be unmapped */
> + memset(dp_conn->pixmap, 0, dp_conn->fb_size);
> + munmap(dp_conn->pixmap, dp_conn->fb_size);
> +
> + return 0;
> +}
> +
> +static int setup_failsafe_framebuffer(struct connector *dp_conn)
> +{
> +
> + dp_conn->failsafe_fb = igt_create_fb(drm_fd,
> + dp_conn->failsafe_width,
> + dp_conn->failsafe_height,
> + DRM_FORMAT_XRGB8888,
> + LOCAL_DRM_FORMAT_MOD_NONE,
> + &dp_conn->fb_failsafe_pattern);
> + igt_assert(dp_conn->failsafe_fb);
> +
> + /* Map the mapping of GEM object into the virtual address space */
> + dp_conn->failsafe_pixmap = gem_mmap__gtt(drm_fd,
> + dp_conn->fb_failsafe_pattern.gem_handle,
> + dp_conn->fb_failsafe_pattern.size,
> + PROT_READ | PROT_WRITE);
> + if (dp_conn->failsafe_pixmap == NULL)
> + return -1;
> +
> + gem_set_domain(drm_fd, dp_conn->fb_failsafe_pattern.gem_handle,
> + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> + dp_conn->failsafe_size = dp_conn->fb_failsafe_pattern.size;
> +
> + /* After filling the device framebuffer the mapped memory needs to be freed */
> + memset(dp_conn->failsafe_pixmap, 0, dp_conn->failsafe_size);
> + munmap(dp_conn->failsafe_pixmap, dp_conn->failsafe_size);
> +
> + return 0;
> +
> +}
> +
> +static int setup_video_pattern_framebuffer(struct connector *dp_conn)
> +{
> + uint32_t video_width, video_height;
> +
> + video_width = dp_conn->test_pattern.hdisplay;
> + video_height = dp_conn->test_pattern.vdisplay;
> + dp_conn->test_pattern.fb = igt_create_fb(drm_fd,
> + video_width, video_height,
> + DRM_FORMAT_XRGB8888,
> + LOCAL_DRM_FORMAT_MOD_NONE,
> + &dp_conn->test_pattern.fb_pattern);
> + igt_assert(dp_conn->test_pattern.fb);
> +
> + /* Map the mapping of GEM object into the virtual address space */
> + dp_conn->test_pattern.pixmap = gem_mmap__gtt(drm_fd,
> + dp_conn->test_pattern.fb_pattern.gem_handle,
> + dp_conn->test_pattern.fb_pattern.size,
> + PROT_READ | PROT_WRITE);
> + if (dp_conn->test_pattern.pixmap == NULL)
> + return -1;
> +
> + gem_set_domain(drm_fd, dp_conn->test_pattern.fb_pattern.gem_handle,
> + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> +
> + dp_conn->test_pattern.size = dp_conn->test_pattern.fb_pattern.size;
> +
> + memset(dp_conn->test_pattern.pixmap, 0, dp_conn->test_pattern.size);
> + return 0;
> +
> +}
> +
> +static int fill_framebuffer(struct connector *dp_conn)
> +{
> + uint32_t tile_height, tile_width, video_width, video_height;
> + uint32_t *red_ptr, *green_ptr, *blue_ptr, *white_ptr, *src_ptr, *dst_ptr;
> + int x, y;
> + int32_t pixel_val;
> +
> + video_width = dp_conn->test_pattern.hdisplay;
> + video_height = dp_conn->test_pattern.vdisplay;
> +
> + tile_height = 64;
> + tile_width = 1 << (dp_conn->test_pattern.bitdepth);
> +
> + red_ptr = dp_conn->test_pattern.pixmap;
> + green_ptr = red_ptr + (video_width * tile_height);
> + blue_ptr = green_ptr + (video_width * tile_height);
> + white_ptr = blue_ptr + (video_width * tile_height);
> + x = 0;
> +
> + /* Fill the frame buffer with video pattern from CTS 3.1.5 */
> + while (x < video_width) {
> + for (pixel_val = 0; pixel_val < 256;
> + pixel_val = pixel_val + (256 / tile_width)) {
> + red_ptr[x] = pixel_val << 16;
> + green_ptr[x] = pixel_val << 8;
> + blue_ptr[x] = pixel_val << 0;
> + white_ptr[x] = red_ptr[x] | green_ptr[x] | blue_ptr[x];
> + if (++x >= video_width)
> + break;
> + }
> + }
> + for (y = 0; y < video_height; y++) {
> + if (y == 0 || y == 64 || y == 128 || y == 192)
> + continue;
> + switch ((y / tile_height) % 4) {
> + case 0:
> + src_ptr = red_ptr;
> + break;
> + case 1:
> + src_ptr = green_ptr;
> + break;
> + case 2:
> + src_ptr = blue_ptr;
> + break;
> + case 3:
> + src_ptr = white_ptr;
> + break;
> + }
> + dst_ptr = dp_conn->test_pattern.pixmap + (y * video_width);
> + memcpy(dst_ptr, src_ptr, (video_width * 4));
> + }
> + munmap(dp_conn->test_pattern.pixmap,
> + dp_conn->test_pattern.size);
> + return 0;
> +}
> +
> +static int set_test_mode(struct connector *dp_conn)
> +{
> + int ret = 0;
> + int i;
> + bool found_std = false, found_fs = false;
> + drmModeConnector *c = dp_conn->connector;
> +
> + /* Ignore any disconnected devices */
> + if (c->connection != DRM_MODE_CONNECTED) {
> + igt_warn("Connector %u disconnected\n", c->connector_id);
> + return -ENOENT;
> + }
> + igt_info("Connector setup:\n");
> + /* Setup preferred mode - should be mode[0] in the list */
> + dp_conn->mode_preferred = c->modes[0];
> + dp_conn->fb_width = c->modes[0].hdisplay;
> + dp_conn->fb_height = c->modes[0].vdisplay;
> +
> + dp_conn->test_pattern.mode = c->modes[0];
> + dp_conn->test_pattern.mode.hdisplay = c->modes[0].hdisplay;
> + dp_conn->test_pattern.mode.vdisplay = c->modes[0].vdisplay;
> +
> + igt_info("Preferred mode (mode 0) for connector %u is %ux%u\n",
> + dp_conn->id, c->modes[0].hdisplay, c->modes[0].vdisplay);
> + fflush(stdin);
> +
> + for (i = 1; i < c->count_modes; i++) {
> + /* Standard mode is 800x600 at 60 */
> + if (c->modes[i].hdisplay == 800 &&
> + c->modes[i].vdisplay == 600 &&
> + c->modes[i].vrefresh == 60 &&
> + found_std == false) {
> + dp_conn->mode_standard = c->modes[i];
> + igt_info("Standard mode (%d) for connector %u is %ux%u\n",
> + i,
> + c->connector_id,
> + c->modes[i].hdisplay,
> + c->modes[i].vdisplay);
> + found_std = true;
> + }
> + /* Failsafe mode is 640x480 at 60 */
> + if (c->modes[i].hdisplay == 640 &&
> + c->modes[i].vdisplay == 480 &&
> + c->modes[i].vrefresh == 60 &&
> + found_fs == false) {
> + dp_conn->mode_failsafe = c->modes[i];
> + dp_conn->failsafe_width = c->modes[i].hdisplay;
> + dp_conn->failsafe_height = c->modes[i].vdisplay;
> + igt_info("Failsafe mode (%d) for connector %u is %ux%u\n",
> + i,
> + c->connector_id,
> + c->modes[i].hdisplay,
> + c->modes[i].vdisplay);
> + found_fs = true;
> + }
> + }
> +
> + ret = setup_framebuffers(dp_conn);
> + if (ret) {
> + igt_warn("Creating framebuffer for connector %u failed (%d)\n",
> + c->connector_id, ret);
> + return ret;
> + }
> +
> + if (found_fs) {
> + ret = setup_failsafe_framebuffer(dp_conn);
> + if (ret) {
> + igt_warn("Creating failsafe framebuffer for connector %u failed (%d)\n",
> + c->connector_id, ret);
> + return ret;
> + }
> + }
> +
> + if (video_pattern_flag) {
> + dp_conn->test_pattern.hdisplay = hdisplay;
> + dp_conn->test_pattern.vdisplay = vdisplay;
> + dp_conn->test_pattern.bitdepth = bitdepth;
> +
> + ret = setup_video_pattern_framebuffer(dp_conn);
> + if (ret) {
> + igt_warn("Creating framebuffer for connector %u failed (%d)\n",
> + c->connector_id, ret);
> + return ret;
> + }
> +
> + ret = fill_framebuffer(dp_conn);
> + if (ret) {
> + igt_warn("Filling framebuffer for connector %u failed (%d)\n",
> + c->connector_id, ret);
> + return ret;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static int set_video(int mode, struct connector *test_connector)
> +{
> + drmModeModeInfo *requested_mode;
> + uint32_t required_fb_id;
> + struct igt_fb required_fb;
> + int ret = 0;
> +
> + switch (mode) {
> + case INTEL_MODE_NONE:
> + igt_info("NONE\n");
> + ret = drmModeSetCrtc(drm_fd, test_connector->crtc,
> + -1, 0, 0, NULL, 0, NULL);
> + goto out;
> + case INTEL_MODE_PREFERRED:
> + igt_info("PREFERRED\n");
> + requested_mode = &test_connector->mode_preferred;
> + required_fb_id = test_connector->fb;
> + required_fb = test_connector->fb_video_pattern;
> + break;
> + case INTEL_MODE_STANDARD:
> + igt_info("STANDARD\n");
> + requested_mode = &test_connector->mode_standard;
> + required_fb_id = test_connector->fb;
> + required_fb = test_connector->fb_video_pattern;
> + break;
> + case INTEL_MODE_FAILSAFE:
> + igt_info("FAILSAFE\n");
> + requested_mode = &test_connector->mode_failsafe;
> + required_fb_id = test_connector->failsafe_fb;
> + required_fb = test_connector->fb_failsafe_pattern;
> + break;
> + case INTEL_MODE_VIDEO_PATTERN_TEST:
> + igt_info("VIDEO PATTERN TEST\n");
> + requested_mode = &test_connector->test_pattern.mode;
> + required_fb_id = test_connector->test_pattern.fb;
> + required_fb = test_connector->test_pattern.fb_pattern;
> + break;
> + case INTEL_MODE_INVALID:
> + default:
> + igt_warn("INVALID! (%08x) Mode set aborted!\n", mode);
> + return -1;
> + }
> +
> + igt_info("CRTC(%u):", test_connector->crtc);
> + kmstest_dump_mode(requested_mode);
> + ret = drmModeSetCrtc(drm_fd, test_connector->crtc, required_fb_id, 0, 0,
> + &test_connector->id, 1, requested_mode);
> + if (ret) {
> + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n",
> + requested_mode->hdisplay, requested_mode->vdisplay,
> + requested_mode->vrefresh, strerror(errno));
> + igt_remove_fb(drm_fd, &required_fb);
> +
> + }
> + /* Keep the pattern on output lines for 1 sec for DPR-120 to detect it */
> + sleep(1);
> +
> +out:
> + if (ret) {
> + igt_warn("Failed to set CRTC for connector %u\n",
> + test_connector->id);
> + }
> +
> + return ret;
> +}
> +
> +static int
> +set_default_mode(struct connector *c, bool set_mode)
> +{
> + unsigned int fb_id = 0;
> + struct igt_fb fb_info;
> + int ret = 0;
> +
> + if (!set_mode) {
> + ret = drmModeSetCrtc(drm_fd, c->crtc, 0, 0, 0,
> + NULL, 0, NULL);
> + if (ret)
> + igt_warn("Failed to unset mode");
> + return ret;
> + }
> +
> + c->mode = c->connector->modes[0];
> +
> + width = c->mode.hdisplay;
> + height = c->mode.vdisplay;
> +
> + fb_id = igt_create_pattern_fb(drm_fd, width, height,
> + DRM_FORMAT_XRGB8888,
> + tiling, &fb_info);
> +
> + igt_info("CRTC(%u):[%d]", c->crtc, 0);
> + kmstest_dump_mode(&c->mode);
> + drmModeSetCrtc(drm_fd, c->crtc, -1, 0, 0, NULL, 0, NULL);
> + ret = drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0,
> + &c->id, 1, &c->mode);
> + if (ret) {
> + igt_warn("Failed to set mode (%dx%d@%dHz): %s\n",
> + width, height, c->mode.vrefresh, strerror(errno));
> + igt_remove_fb(drm_fd, &fb_info);
> +
> + }
> +
> + return ret;
> +}
> +
> +static uint32_t find_crtc_for_connector(drmModeConnector *c)
> +{
> + drmModeEncoder *e;
> + uint32_t possible_crtcs;
> + int i, j;
> +
> + for (i = 0; i < c->count_encoders; i++) {
> + e = drmModeGetEncoder(drm_fd, c->encoders[i]);
> + possible_crtcs = e->possible_crtcs;
> + drmModeFreeEncoder(e);
> +
> + for (j = 0; possible_crtcs >> j; j++)
> + if (possible_crtcs & (1 << j))
> + return resources->crtcs[j];
> + }
> + return 0;
> +}
> +
> +/*
> + * Re-probe connectors and do a modeset based on test request or
> + * in case of a hotplug uevent.
> + *
> + * @mode: Video mode requested by the test
> + * @is_compliance_test: 1: If it is a compliance test
> + * 0: If it is a hotplug event
> + *
> + * Returns:
> + * 0: On Success
> + * -1: On failure
> + */
> +int update_display(int mode, bool is_compliance_test)
> +{
> + struct connector *connectors, *conn;
> + int cnt, ret = 0;
> + bool set_mode;
> +
> + resources = drmModeGetResources(drm_fd);
> + if (!resources) {
> + igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
> + return -1;
> + }
> +
> + connectors = calloc(resources->count_connectors,
> + sizeof(struct connector));
> + if (!connectors)
> + return -1;
> +
> + /* Find any connected displays */
> + for (cnt = 0; cnt < resources->count_connectors; cnt++) {
> + drmModeConnector *c;
> +
> + conn = &connectors[cnt];
> + conn->id = resources->connectors[cnt];
> + c = drmModeGetConnector(drm_fd, conn->id);
> + if (c->connector_type == DRM_MODE_CONNECTOR_DisplayPort &&
> + c->connection == DRM_MODE_CONNECTED) {
> + test_connector_id = c->connector_id;
> + conn->connector = c;
> + conn->crtc = find_crtc_for_connector(c);
> + test_crtc = conn->crtc;
> + set_mode = true;
> + break;
> + } else if (c->connector_id == test_connector_id &&
> + c->connection == DRM_MODE_DISCONNECTED) {
> + conn->connector = c;
> + conn->crtc = test_crtc;
> + set_mode = false;
> + break;
> + }
> + }
> +
> + if (cnt == resources->count_connectors) {
> + ret = -1;
> + goto err;
> + }
> +
> + if (is_compliance_test) {
> + set_test_mode(conn);
> + ret = set_video(INTEL_MODE_NONE, conn);
> + ret = set_video(mode, conn);
> +
> + } else
> + ret = set_default_mode(conn, set_mode);
> +
> + err:
> + drmModeFreeConnector(conn->connector);
> + /* Error condition if no connected displays */
> + free(connectors);
> + drmModeFreeResources(resources);
> + return ret;
> +}
> +
> +static const char optstr[] = "hi";
> +
> +static void __attribute__((noreturn)) usage(char *name, char opt)
> +{
> + igt_info("usage: %s [-hi]\n", name);
> + igt_info("\t-i\tdump info\n");
> + igt_info("\tDefault is to respond to DPR-120 tests\n");
> + exit((opt != 'h') ? -1 : 0);
> +}
> +
> +static void cleanup_debugfs(void)
> +{
> + fclose(test_active_fp);
> + fclose(test_data_fp);
> + fclose(test_type_fp);
> +}
> +
> +static void __attribute__((noreturn)) cleanup_and_exit(int ret)
> +{
> + cleanup_debugfs();
> + close(drm_fd);
> + igt_info("Compliance testing application exiting\n");
> + exit(ret);
> +}
> +
> +static void cleanup_test(void)
> +{
> + video_pattern_flag = false;
> + hdisplay = 0;
> + vdisplay = 0;
> + bitdepth = 0;
> +}
> +
> +static void read_test_request(void)
> +{
> + unsigned long test_type;
> +
> + test_type = get_test_type();
> + process_test_request(test_type);
> + cleanup_test();
> + clear_test_active();
> +}
> +
> +static gboolean test_handler(GIOChannel *source, GIOCondition condition,
> + gpointer data)
> +{
> + unsigned long test_active;
> + int ret;
> +
> + rewind(test_active_fp);
> +
> + ret = fscanf(test_active_fp, "%lx", &test_active);
> + if (ret < 1)
> + return FALSE;
> +
> + if (test_active)
> + read_test_request();
> + return TRUE;
> +}
> +
> +static gboolean input_event(GIOChannel *source, GIOCondition condition,
> + gpointer data)
> +{
> + gchar buf[2];
> + gsize count;
> +
> + count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf));
> + if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) {
> + cleanup_and_exit(0);
> + }
> +
> + return TRUE;
> +}
> +
> +static void enter_exec_path(char **argv)
> +{
> + char *exec_path = NULL;
> + char *pos = NULL;
> + short len_path = 0;
> + int ret;
> +
> + len_path = strlen(argv[0]);
> + exec_path = (char *) malloc(len_path);
> +
> + memcpy(exec_path, argv[0], len_path);
> + pos = strrchr(exec_path, '/');
> + if (pos != NULL)
> + *(pos+1) = '\0';
> +
> + ret = chdir(exec_path);
> + igt_assert_eq(ret, 0);
> + free(exec_path);
> +}
> +
> +static void restore_termio_mode(int sig)
> +{
> + tcsetattr(tio_fd, TCSANOW, &saved_tio);
> + close(tio_fd);
> +}
> +
> +static void set_termio_mode(void)
> +{
> + struct termios tio;
> +
> + /* don't attempt to set terminal attributes if not in the foreground
> + * process group
> + */
> + if (getpgrp() != tcgetpgrp(STDOUT_FILENO))
> + return;
> +
> + tio_fd = dup(STDIN_FILENO);
> + tcgetattr(tio_fd, &saved_tio);
> + igt_install_exit_handler(restore_termio_mode);
> + tio = saved_tio;
> + tio.c_lflag &= ~(ICANON | ECHO);
> + tcsetattr(tio_fd, TCSANOW, &tio);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int c;
> + int ret = 0;
> + GIOChannel *stdinchannel, *testactive_channel;
> + GMainLoop *mainloop;
> + bool opt_dump_info = false;
> + struct option long_opts[] = {
> + {"help-description", 0, 0, HELP_DESCRIPTION},
> + {"help", 0, 0, 'h'},
> + };
> +
> + igt_skip_on_simulation();
> +
> + enter_exec_path(argv);
> +
> + while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) {
> + switch (c) {
> + case 'i':
> + opt_dump_info = true;
> + break;
> + case HELP_DESCRIPTION:
> + igt_info("DP Compliance Test Suite using DPR-120\n");
> + igt_info("EDID tests\n");
> + igt_info("Video Pattern Generation tests\n");
> + exit(0);
> + break;
> + default:
> + /* fall through */
> + case 'h':
> + usage(argv[0], c);
> + break;
> + }
> + }
> +
> + set_termio_mode();
> +
> + igt_info("*************DP Compliance Testing using DPR-120*************\n");
> + igt_info("Waiting for test request......\n");
This printout could be moved below all the required setup that happens below...
> + drm_fd = drm_open_driver(DRIVER_ANY);
> +
> + kmstest_set_vt_graphics_mode();
> + setup_debugfs_files();
> + cleanup_test();
> +
> + if (opt_dump_info) {
> + dump_info();
> + goto out_close;
> + }
> +
> + /* Get the DP connector ID and CRTC */
> + if (update_display(0, false)) {
> + igt_warn("Failed to set default mode\n");
> + ret = -1;
> + goto out_close;
> + }
> +
> + mainloop = g_main_loop_new(NULL, FALSE);
> + if (!mainloop) {
> + igt_warn("Failed to create GMainLoop\n");
> + ret = -1;
> + goto out_close;
> + }
> +
> + if (!intel_dp_compliance_setup_hotplug()) {
> + igt_warn("Failed to initialize hotplug support\n");
> + goto out_mainloop;
> + }
> +
> + testactive_channel = g_io_channel_unix_new(fileno(test_active_fp));
> + if (!testactive_channel) {
> + igt_warn("Failed to create test_active GIOChannel\n");
> + goto out_close;
> + }
> +
> + ret = g_io_add_watch(testactive_channel, G_IO_IN | G_IO_ERR,
> + test_handler, NULL);
> + if (ret < 0) {
> + igt_warn("Failed to add watch on udev GIOChannel\n");
> + goto out_close;
> + }
> +
> + stdinchannel = g_io_channel_unix_new(0);
> + if (!stdinchannel) {
> + igt_warn("Failed to create stdin GIOChannel\n");
> + goto out_hotplug;
> + }
> +
> + ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event,
> + NULL);
> + if (ret < 0) {
> + igt_warn("Failed to add watch on stdin GIOChannel\n");
> + goto out_stdio;
> + }
> +
> + ret = 0;
... to here maybe.
> +
> + g_main_loop_run(mainloop);
> +
> +out_stdio:
> + g_io_channel_shutdown(stdinchannel, TRUE, NULL);
> +out_hotplug:
> + intel_dp_compliance_cleanup_hotplug();
> +out_mainloop:
> + g_main_loop_unref(mainloop);
> +out_close:
> + cleanup_debugfs();
> + close(drm_fd);
> +
> + igt_assert_eq(ret, 0);
> +
> + igt_info("Compliance testing application exiting\n");
> + igt_exit();
> +}
> diff --git a/tools/intel_dp_compliance.h b/tools/intel_dp_compliance.h
> new file mode 100644
> index 0000000..50a9662
> --- /dev/null
> +++ b/tools/intel_dp_compliance.h
> @@ -0,0 +1,35 @@
> +/*
> + * Copyright 2017 Intel Corporation
> + * Manasi Navare <manasi.d.navare at intel.com>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <glib.h>
> +
> +extern int drm_fd;
> +
> +gboolean intel_dp_compliance_setup_hotplug(void);
> +void intel_dp_compliance_cleanup_hotplug(void);
> +
> +/* called by the hotplug code */
> +int update_display(int mode, bool is_compliance_test);
> diff --git a/tools/intel_dp_compliance_hotplug.c b/tools/intel_dp_compliance_hotplug.c
> new file mode 100644
> index 0000000..b57f8a2
> --- /dev/null
> +++ b/tools/intel_dp_compliance_hotplug.c
> @@ -0,0 +1,124 @@
> +/*
> + * Copyright 2017 Intel Corporation
> + * Jesse Barnes <jesse.barnes at intel.com>
> + * Manasi Navare <manasi.d.navare at intel.com>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "igt.h"
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +
> +#include <sys/stat.h>
> +
> +#include "intel_dp_compliance.h"
> +#include <libudev.h>
> +static struct udev_monitor *uevent_monitor;
> +static struct udev *udev;
> +static GIOChannel *udevchannel;
> +
> +static gboolean hotplug_event(GIOChannel *source, GIOCondition condition,
> + gpointer data)
> +{
> + struct udev_device *dev;
> + dev_t udev_devnum;
> + struct stat s;
> + const char *hotplug;
> +
> + dev = udev_monitor_receive_device(uevent_monitor);
> + if (!dev)
> + goto out;
> +
> + udev_devnum = udev_device_get_devnum(dev);
> + fstat(drm_fd, &s);
> +
> + hotplug = udev_device_get_property_value(dev, "HOTPLUG");
> +
> + if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
> + hotplug && atoi(hotplug) == 1)
> + update_display(0, false);
> +
> + udev_device_unref(dev);
> +out:
> + return TRUE;
> +}
> +
> +
> +gboolean intel_dp_compliance_setup_hotplug(void)
> +{
> + int ret;
> +
> + udev = udev_new();
> + if (!udev) {
> + igt_warn("Failed to create udev object\n");
> + goto out;
> + }
> +
> + uevent_monitor = udev_monitor_new_from_netlink(udev, "udev");
> + if (!uevent_monitor) {
> + igt_warn("Failed to create udev event monitor\n");
> + goto out;
> + }
> +
> + ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor,
> + "drm",
> + "drm_minor");
> + if (ret < 0) {
> + igt_warn("Failed to filter for drm events\n");
> + goto out;
> + }
> +
> + ret = udev_monitor_enable_receiving(uevent_monitor);
> + if (ret < 0) {
> + igt_warn("Failed to enable udev event reception\n");
> + goto out;
> + }
> +
> + udevchannel =
> + g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor));
> + if (!udevchannel) {
> + igt_warn("Failed to create udev GIOChannel\n");
> + goto out;
> + }
> +
> + ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event,
> + udev);
> + if (ret < 0) {
> + igt_warn("Failed to add watch on udev GIOChannel\n");
> + goto out;
> + }
> +
> + return TRUE;
> +
> +out:
> + intel_dp_compliance_cleanup_hotplug();
> + return FALSE;
> +}
> +
> +void intel_dp_compliance_cleanup_hotplug(void)
> +{
> + if (udevchannel)
> + g_io_channel_shutdown(udevchannel, TRUE, NULL);
> + if (uevent_monitor)
> + udev_monitor_unref(uevent_monitor);
> + if (udev)
> + udev_unref(udev);
> +}
> --
> 1.9.1
>
More information about the Intel-gfx
mailing list