[Intel-gfx] [PATCH] igt/dp: Displayport Compliance Testing - Userspace Component

Todd Previte tprevite at gmail.com
Fri Apr 10 08:54:19 PDT 2015


This is the userspace component of the Displayport compliance testing
software requried for compliance testing of the i915 driver. The README
included in the dp_compliance/ directory contains the most up to date
information on the use and operation of the user app.

Signed-off-by: Todd Previte <tprevite at gmail.com>
---
 dp_compliance/README          | 102 ++++++
 dp_compliance/build.sh        |   6 +
 dp_compliance/dp_compliance.c | 782 ++++++++++++++++++++++++++++++++++++++++++
 dp_compliance/input.c         |  48 +++
 4 files changed, 938 insertions(+)
 create mode 100644 dp_compliance/README
 create mode 100755 dp_compliance/build.sh
 create mode 100644 dp_compliance/dp_compliance.c
 create mode 100644 dp_compliance/input.c

diff --git a/dp_compliance/README b/dp_compliance/README
new file mode 100644
index 0000000..1ef4913
--- /dev/null
+++ b/dp_compliance/README
@@ -0,0 +1,102 @@
+
+Displayport Compliance Testing
+Userspace Application
+
+This is the userspace portion of the Displayport Compliance testing suite for the
+i915 driver. It must be running in order to successfully complete Displayport
+compliance testing. This file contains the latest available information about
+the user app and its operation.
+
+This app and the kernel code that accompanies it has been written to satisfy the
+requirements of the Displayport Link CTS Core 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 the Unigraf DPR-100,
+	  DPR-120 or Quantum Data 882EDP
+	- This user application
+	- A Windows host machine to run the test software
+	- Root access on the DUT
+
+Test setup:
+	It is strongly recommended that the Windows host, test appliance and DUT be freshly
+	restarted before testing begins. This ensures that any previous configurations and
+	settings will not interfere with the 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. The easiest way to accomplish this is to place the word “text”
+	on the command line for booting the kernel. The recommended boot parameters for
+	the kernel are as follows:
+		“test debug drm.debug=0x0e”
+	This enables debug output in the logs and will boot the system to a command prompt.
+
+	You must be logged in as root in order to run the user app.
+
+	Connections (required):
+		- Test appliance connected to the external Displayport connector on the DUT
+		- Test appliance connected to the Windows host (usually via USB)
+
+	Connections (optional):
+		- SSH/telnet connection to the DUT from the Windows host or other system
+		- A display attached to the DUT for monitoring the console or running
+		  the user app.
+
+	The user app can be run directly from the console on the DUT (if a non-Displayport
+	display is attached) or from an SSH/telnet session. Generally speaking, it’s best
+	to run from an SSH session, but testing will operate identically regardless of how
+	the user app is launched.
+
+	Once the user application is up and running, waiting for a test request, the software
+	on the Windows host can now be used to execute the compliance tests.
+
+	TL;DR version:
+		- Install test appliance software on Windows host
+		- Adjust command line on Linux DUT as necessary to enable debug and boot
+		  to the console
+		- Connect the test appliance via USB to the Windows host and a Displayport
+		  cable to the DUT
+		- Reboot all systems, including the test appliance
+		- SSH into the DUT or login at the command prompt
+		- Ensure that the booted kernel contains the compliance test patch set
+		  and that a version of IGT with this user app is also present
+		- Launch the user app, as root. Follow the onscreen instructions until
+		  it says it’s waiting for a test to begin
+		- Execute the tests via the software on the Windows host per the
+		  documentation for the test appliance
+
+Debugfs Files:
+
+The file root for all the debugfs files is:
+
+/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.
+
+i915_dp_test_data
+	Test data is used by the kernel to pass parameters to the user app. Currently, the
+	only parameter that is delivered is the video mode to set for the test. As more tests
+	are implemented, this value may be used for additional values or information.
+
+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 and must be kept in sync with the values defined in
+	drm_dp_helper.h.
+
+Test operations:
+
+Notes:
+	If the test_active flag is stuck, it can be cleared with this simple command:
+		echo 0 > /sys/kernel/debug/dri/0/i915_dp_test_active
+	This can happen when the test appliance is connected and a test is run, but the
+	user app isn’t running.
+
diff --git a/dp_compliance/build.sh b/dp_compliance/build.sh
new file mode 100755
index 0000000..0b317a9
--- /dev/null
+++ b/dp_compliance/build.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Simple build script for the compliance app
+# Eventually should be a makefile in IGT
+
+gcc -g3 dp_compliance.c input.c -o dp_compliance_app -Wall `pkg-config --libs --cflags libdrm`
+
diff --git a/dp_compliance/dp_compliance.c b/dp_compliance/dp_compliance.c
new file mode 100644
index 0000000..7d5febb
--- /dev/null
+++ b/dp_compliance/dp_compliance.c
@@ -0,0 +1,782 @@
+/* 
+ * Displayport Compliance Testing Application 
+ * Performs Displayport compliance testing for the Intel i915 driver
+ *
+ * Copyright ? 2014-2015 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.
+ *
+ * Authors:
+ *    Todd Previte <tprevite at gmail.com>
+ * 
+ * Elements of the modeset code adapted from David Herrmann's
+ * DRM modeset example
+ *
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <assert.h>
+#include <drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <i915_drm.h>
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+
+#include <sys/mman.h>
+#include <time.h>
+
+#define I915_DRIVER_NODE		"/dev/dri/card0"
+#define INTEL_DP_DEBUGFS_ROOT		"/sys/kernel/debug/dri/0/"
+
+#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	4
+#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)
+
+enum 
+{
+	INTEL_MODE_INVALID = -1,
+	INTEL_MODE_NONE = 0,
+	INTEL_MODE_PREFERRED,
+	INTEL_MODE_STANDARD,
+	INTEL_MODE_FAILSAFE
+} intel_display_mode;
+
+struct dp_connector {
+	drmModeModeInfo mode_standard, mode_preferred, mode_failsafe;
+	/* Standard and preferred frame buffer*/
+	uint32_t fb, fb_width, fb_height, fb_handle, fb_stride, fb_size;
+	uint8_t *pixmap;
+	/* Failsafe framebuffer - note this is a 16-bit buffer */
+	uint32_t failsafe_fb, failsafe_width, failsafe_height;
+	uint32_t failsafe_handle, failsafe_stride, failsafe_size;
+	uint8_t *failsafe_pixmap;
+
+	uint32_t conn;
+	uint32_t crtc;
+
+	drmModeCrtc *saved_crtc;
+	struct dp_connector *next;
+};
+
+/* Input handling from input.c */
+extern void reset_terminal_mode(void);
+extern void set_conio_terminal_mode(void);
+extern int kbhit(void);
+extern int getch(void);
+
+void setup_debugfs_files(int *test_active_fd, int *test_type_fd,
+			 int *test_data_fd);
+ int setup_crtc_for_connector(int fd, drmModeRes *mr, drmModeConnector *c,
+			      struct dp_connector *dp_conn);
+ int setup_framebuffers(int drv_fd, struct dp_connector *dp_conn);
+ int setup_failsafe_framebuffer(int drv_fd, struct dp_connector *dp_conn);
+ int setup_dp_connector(int drv_fd, drmModeRes *mr, drmModeConnector *c,
+			struct dp_connector *dp_conn);
+ int setup_connectors(int drv_fd, drmModeResPtr pmr);
+ int setup_drm(int *drv_fd, const char *node);
+
+void shutdown(int drv_fd);
+void cleanup_debugfs(void);
+
+ int set_video_mode(int drv_fd, int mode, struct dp_connector *test_connector);
+ int check_test_active(void);
+void clear_test_active(void);
+ int get_test_data(void);
+ int get_test_type(void);
+
+ int process_test_request(int drv_fd, int test_type, int test_data,
+			  struct dp_connector *connector);
+
+/* Global connector list */
+struct dp_connector *dp_connector_list;
+unsigned short dp_connector_count;
+
+/* Global file descriptors */
+int test_active_fd, test_data_fd, test_type_fd;
+
+int get_test_data(void)
+{
+	char data_in[9];
+	int bytes_read;
+	int data;
+
+	assert(test_data_fd > 0);
+	lseek(test_data_fd, 0, SEEK_SET);
+
+	bytes_read = read(test_data_fd, data_in, 8);
+	if (bytes_read <= 0) {
+		printf("Test type read failed - %d\r\n", bytes_read);
+		return 0;
+	}
+	data_in[8] = '\0';
+	data = strtol(data_in, NULL, 16);
+	printf("Test data = %08x\r\n", data);
+	return data;
+}
+
+int get_test_type(void)
+{
+	char data_in[5];
+	int bytes_read;
+	int data;
+
+	assert(test_type_fd > 0);
+	lseek(test_type_fd, 0, SEEK_SET);
+
+	bytes_read = read(test_type_fd, data_in, 4);
+	if (bytes_read <= 0) {
+		printf("Test type read failed - %d\r\n", bytes_read);
+		return 0;
+	}
+	data_in[4] = '\0';
+	data = strtol(data_in, NULL, 16);
+	printf("Test type = %04x\r\n", data);
+	return data;
+}
+
+int process_test_request(int drv_fd, int test_type, int test_data,
+			 struct dp_connector *connector)
+{
+	int status = 0;
+	int mode;
+
+	/* Disable the main link before starting the test
+	 * Note that this should probably be signaled through a debugfs file
+	 * from the kernel at the start of testing.
+	 */
+	set_video_mode(drv_fd, INTEL_MODE_NONE, connector);
+
+	switch (test_type) {
+	case DP_TEST_LINK_TRAINING:
+		/* Link training = future implementation */
+		break;
+	case DP_TEST_LINK_VIDEO_PATTERN:
+		/* Video pattern = future implementation */
+		break;
+	case DP_TEST_LINK_EDID_READ:
+		mode = (test_data & DP_COMPLIANCE_VIDEO_MODE_MASK) >>
+			INTEL_DP_RESOLUTION_SHIFT_MASK;
+		printf("EDID test received, mode %d\r\n", mode);
+		status = set_video_mode(drv_fd, mode, connector);
+		clear_test_active();
+		break;
+	case DP_TEST_LINK_PHY_TEST_PATTERN:
+		/* PHY Test Pattern = future implementation */
+		break;
+	default:
+		/* Unknown test type */
+		printf("Invalid test request. Ignored.\r\n");
+		clear_test_active();
+		break;
+	}
+
+	return status;
+}
+
+void cleanup_debugfs(void)
+{
+	close(test_active_fd);
+	close(test_data_fd);
+	close(test_type_fd);
+}
+
+int check_test_active(void)
+{
+	char data_in[2];
+	int bytes_read;
+
+	assert(test_active_fd > 0);
+	lseek(test_active_fd, 0, SEEK_SET);
+
+	bytes_read = read(test_active_fd, data_in, 2);
+	if (bytes_read <= 0)
+		return 0;
+
+	if (data_in[0] == '1')
+		return 1;
+
+	return 0;
+}
+
+void clear_test_active(void)
+{
+	int bytes_written;
+	char data_out[2];
+
+	assert(test_active_fd > 0);
+	lseek(test_active_fd, 0, SEEK_SET);
+
+	data_out[0] = '0';
+	data_out[1] = '\0';
+
+	bytes_written = write(test_active_fd, data_out, 1);
+	if (bytes_written <= 0)
+		printf("Could not clear test active flag. Write failed!\r\n");
+}
+
+void setup_debugfs_files(int *test_active_fd, int *test_type_fd,
+			 int *test_data_fd)
+{
+	char debugfs_path[256];
+	char *index;
+	int offset;
+
+	offset = strlen(INTEL_DP_DEBUGFS_ROOT);
+	index = &debugfs_path[offset];
+
+	memset(debugfs_path, 0, 256);
+	strcpy(debugfs_path, INTEL_DP_DEBUGFS_ROOT);
+
+	strcpy(index, INTEL_DP_TEST_TYPE_FILE);
+	*test_type_fd = open(debugfs_path, O_RDONLY);
+	assert(*test_type_fd > 0);
+	printf("Test type path   : %s\r\n", debugfs_path);
+
+	strcpy(index, INTEL_DP_TEST_DATA_FILE);
+	*test_data_fd = open(debugfs_path, O_RDONLY);
+	assert(*test_data_fd > 0);
+	printf("Test data path   : %s\r\n", debugfs_path);
+
+	strcpy(index, INTEL_DP_TEST_ACTIVE_FILE);
+	*test_active_fd = open(debugfs_path, O_RDWR);
+	assert(*test_active_fd > 0);
+	printf("Test active path : %s\r\n", debugfs_path);
+
+	/* Reset the active flag for safety */
+	clear_test_active();
+}
+
+int setup_drm(int *drv_fd, const char *node)
+{
+	int fd, ret;
+	uint64_t use_dumb_buffers;
+
+	if (!drmAvailable()) {
+		printf("Error: DRM not available\r\n");
+		return -EOPNOTSUPP;
+	}
+
+	fd = drmOpen("i915", NULL);
+
+	if (fd < 0) {
+		fd = open(node, O_RDWR | O_CLOEXEC);
+		if (fd < 0) {
+			ret = -errno;
+			printf("Error: could not open '%s'\r\n", node);
+			return ret;
+		}
+	}
+
+	drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &use_dumb_buffers);
+
+	if (!use_dumb_buffers) {
+		printf("'%s' does not support dumb buffers\r\n", node);
+		close(fd);
+		return -EOPNOTSUPP;
+	}
+	*drv_fd = fd;
+
+	return 0;
+}
+
+int setup_connectors(int drv_fd, drmModeResPtr pmr)
+{
+	int ret, i;
+	drmModeConnector *c;
+	struct dp_connector *dp_conn;
+
+	pmr = drmModeGetResources(drv_fd);
+	if (!pmr) {
+		printf("ERROR: Failed to retrieve DRM resources\r\n");
+		return -1;
+	}
+
+	for (i = 0; i < pmr->count_connectors; i++) {
+
+		c = drmModeGetConnector(drv_fd, pmr->connectors[i]);
+		if (!c) {
+			printf("Failed to retrieve connector %u:%u\r\n",
+			       i,
+			       pmr->connectors[i]);
+			continue;
+		}
+
+		if(c->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+			continue;
+
+		dp_conn = malloc(sizeof(*dp_conn));
+		memset(dp_conn, 0, sizeof(*dp_conn));
+		dp_conn->conn = c->connector_id;
+
+		/* Setup the DP connector*/
+		ret = setup_dp_connector(drv_fd, pmr, c, dp_conn);
+		if (ret) {
+			if (ret != -ENOENT) {
+				errno = -ret;
+				printf("Failed to setup DP connector %u:%u\r\n",
+				       i,
+				       pmr->connectors[i]);
+			}
+			free(dp_conn);
+			drmModeFreeConnector(c);
+			continue;
+		}
+		else
+			dp_connector_count++;
+		/* free connector data and link device into global list */
+		drmModeFreeConnector(c);
+		dp_conn->next = dp_connector_list;
+		dp_connector_list = dp_conn;
+	}
+
+	return 0;
+}
+
+int setup_dp_connector(int drv_fd, drmModeRes *mr, drmModeConnector *c,
+		       struct dp_connector *dp_conn)
+{
+	int ret, i;
+	bool found_std = false, found_fs = false;
+
+	/* Ignore any disconnected devices */
+	if (c->connection != DRM_MODE_CONNECTED) {
+		printf("Connector %u disconnected\r\n", c->connector_id);
+		return -ENOENT;
+	}
+	printf("Connector Setup:\r\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;
+	printf("\tPreferred mode (mode 0) for connector %u is %ux%u\r\n",
+	       c->connector_id, c->modes[0].hdisplay, c->modes[0].vdisplay);
+
+	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];
+			printf("\tStandard mode (%d) for connector %u is %ux%u\r\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;
+			printf("\tFailsafe mode (%d) for connector %u is %ux%u\r\n",
+			       i,
+			       c->connector_id,
+			       c->modes[i].hdisplay,
+			       c->modes[i].vdisplay);
+		}
+	}
+
+	ret = setup_crtc_for_connector(drv_fd, mr, c, dp_conn);
+	if (ret) {
+		printf("Set CRTC for connector %u failed (%d)\r\n",
+		       c->connector_id, ret);
+		return ret;
+	}
+
+	ret = setup_framebuffers(drv_fd, dp_conn);
+	if (ret) {
+		printf("Create framebuffer for connector %u failed (%d)\r\n",
+		       c->connector_id, ret);
+		return ret;
+	}
+
+	ret = setup_failsafe_framebuffer(drv_fd, dp_conn);
+	if (ret) {
+		printf("Create failsafe framebuffer for connector %u failed (%d)\r\n",
+		       c->connector_id, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+int setup_crtc_for_connector(int fd, drmModeRes *mr, drmModeConnector *c,
+			     struct dp_connector *dp_conn)
+{
+	drmModeEncoder *drm_encoder = NULL;
+	struct dp_connector *dpc;
+	int i, j;
+	int32_t crtc;
+
+	/* Use attached encoder if possible */
+	if (c->encoder_id)
+		drm_encoder = drmModeGetEncoder(fd, c->encoder_id);
+
+	if (drm_encoder) {
+		if (drm_encoder->crtc_id) {
+			crtc = drm_encoder->crtc_id;
+			for (dpc = dp_connector_list; dpc; dpc = dpc->next) {
+				if (dpc->crtc == crtc) {
+					crtc = -1;
+					break;
+				}
+			}
+			if (crtc >= 0) {
+				drmModeFreeEncoder(drm_encoder);
+				dp_conn->crtc = crtc;
+				return 0;
+			}
+		}
+		drmModeFreeEncoder(drm_encoder);
+	}
+
+	/* Check all encoder/crtc combinations */
+	for (i = 0; i < c->count_encoders; ++i) {
+		drm_encoder = drmModeGetEncoder(fd, c->encoders[i]);
+		if (!drm_encoder) {
+			continue;
+		}
+		for (j = 0; j < mr->count_crtcs; ++j) {
+			if (!(drm_encoder->possible_crtcs & (1 << j)))
+				continue;
+			crtc = mr->crtcs[j];
+			for (dpc = dp_connector_list; dpc; dpc = dpc->next) {
+				if (dpc->crtc == crtc) {
+					crtc = -1;
+					break;
+				}
+			}
+			if (crtc >= 0) {
+				drmModeFreeEncoder(drm_encoder);
+				dp_conn->crtc = crtc;
+				return 0;
+			}
+		}
+		drmModeFreeEncoder(drm_encoder);
+	}
+	printf("No CRTC available for connector %u\r\n", c->connector_id);
+	return -ENOENT;
+}
+
+int setup_framebuffers(int drv_fd, struct dp_connector *dp_conn)
+{
+	struct drm_mode_create_dumb creq;
+	struct drm_mode_destroy_dumb dreq;
+	struct drm_mode_map_dumb mreq;
+	int ret;
+
+	memset(&creq, 0, sizeof(creq));
+	memset(&mreq, 0, sizeof(mreq));
+
+	creq.width = dp_conn->fb_width;
+	creq.height = dp_conn->fb_height;
+	creq.bpp = 32;
+	ret = drmIoctl(drv_fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
+	if (ret < 0) {
+		printf("Create dumb buffer failed\r\n");
+		return -errno;
+	}
+	dp_conn->fb_stride = creq.pitch;
+	dp_conn->fb_size = creq.size;
+	dp_conn->fb_handle = creq.handle;
+
+	ret = drmModeAddFB(drv_fd, dp_conn->fb_width, dp_conn->fb_height,
+			   24, 32, dp_conn->fb_stride, dp_conn->fb_handle,
+			   &dp_conn->fb);
+	if (ret) {
+		printf("Create framebuffer failed\r\n");
+		ret = -errno;
+		goto cleanup;
+	}
+
+	mreq.handle = dp_conn->fb_handle;
+	ret = drmIoctl(drv_fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
+	if (ret) {
+		printf("Map dumb buffer failed\r\n");
+		ret = -errno;
+		goto fb_fail;
+	}
+
+	dp_conn->pixmap = mmap(0, dp_conn->fb_size, PROT_READ | PROT_WRITE,
+			       MAP_SHARED, drv_fd, mreq.offset);
+	if (dp_conn->pixmap == MAP_FAILED) {
+		printf("Mmap failed\r\n");
+		ret = -errno;
+		goto fb_fail;
+	}
+	memset(dp_conn->pixmap, 0, dp_conn->fb_size);
+	return 0;
+
+fb_fail:
+	drmModeRmFB(drv_fd, dp_conn->fb);
+
+cleanup:
+	memset(&dreq, 0, sizeof(dreq));
+	dreq.handle = dp_conn->fb_handle;
+	drmIoctl(drv_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+	return ret;
+}
+
+int setup_failsafe_framebuffer(int drv_fd, struct dp_connector *dp_conn)
+{
+	struct drm_mode_create_dumb creq;
+	struct drm_mode_destroy_dumb dreq;
+	struct drm_mode_map_dumb mreq;
+	int ret;
+
+	memset(&creq, 0, sizeof(creq));
+	creq.width = dp_conn->failsafe_width;
+	creq.height = dp_conn->failsafe_height;
+	creq.bpp = 16;
+	ret = drmIoctl(drv_fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
+	if (ret < 0) {
+		printf("Create dumb buffer failed\r\n");
+		return -errno;
+	}
+
+	dp_conn->failsafe_stride = creq.pitch;
+	dp_conn->failsafe_size = creq.size;
+	dp_conn->failsafe_handle = creq.handle;
+
+	ret = drmModeAddFB(drv_fd, dp_conn->failsafe_width,
+			   dp_conn->failsafe_height, 16, 16,
+			   dp_conn->failsafe_stride, dp_conn->failsafe_handle,
+			   &dp_conn->failsafe_fb);
+	if (ret) {
+		printf("Create framebuffer failed\r\n");
+		ret = -errno;
+		goto cleanup;
+	}
+
+	memset(&mreq, 0, sizeof(mreq));
+	mreq.handle = dp_conn->failsafe_handle;
+	ret = drmIoctl(drv_fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
+	if (ret) {
+		printf("Map dumb buffer failed\r\n");
+		ret = -errno;
+		goto fb_fail;
+	}
+
+	dp_conn->failsafe_pixmap = mmap(0, dp_conn->failsafe_size,
+					PROT_READ | PROT_WRITE, MAP_SHARED,
+					drv_fd, mreq.offset);
+	if (dp_conn->failsafe_pixmap == MAP_FAILED) {
+		printf("cannot mmap dumb buffer (%d): %m\r\n", errno);
+		ret = -errno;
+		goto fb_fail;
+	}
+
+	memset(dp_conn->failsafe_pixmap, 0, dp_conn->failsafe_size);
+	return 0;
+
+fb_fail:
+	drmModeRmFB(drv_fd, dp_conn->failsafe_fb);
+
+cleanup:
+	memset(&dreq, 0, sizeof(dreq));
+	dreq.handle = dp_conn->failsafe_handle;
+	drmIoctl(drv_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+	return ret;
+}
+
+int set_video_mode(int drv_fd, int mode, struct dp_connector *test_connector)
+{
+	drmModeModeInfo *requested_mode;
+	uint32_t required_fb;
+	int ret = 0;
+
+	printf("Mode requested: ");
+	switch (mode) {
+	case INTEL_MODE_NONE:
+		printf("NONE\r\n");
+		ret = drmModeSetCrtc(drv_fd, test_connector->crtc,
+				     -1, 0, 0, NULL, 0, NULL);
+		goto out;
+		break;
+	case INTEL_MODE_PREFERRED:
+		 printf("PREFERRED\r\n");
+		 requested_mode =  &test_connector->mode_preferred;
+		 required_fb = test_connector->fb;
+		 break;
+	 case INTEL_MODE_STANDARD:
+		 printf("STANDARD\r\n");
+		 requested_mode =  &test_connector->mode_standard;
+		 required_fb = test_connector->fb;
+		 break;
+	 case INTEL_MODE_FAILSAFE:
+		 printf("FAILSAFE\r\n");
+		 requested_mode =  &test_connector->mode_failsafe;
+		 required_fb = test_connector->failsafe_fb;
+		 break;
+	 case INTEL_MODE_INVALID:
+	 default:
+		 printf("INVALID! (%08x) Mode set aborted!\r\n", mode);
+		 return -1;
+	 break;
+	}
+	test_connector->saved_crtc = drmModeGetCrtc(drv_fd, test_connector->crtc);
+	ret = drmModeSetCrtc(drv_fd, test_connector->crtc, required_fb, 0, 0,
+			     &test_connector->conn, 1, requested_mode);
+out:
+	if (ret) {
+		printf("Failed to set CRTC for connector %u\r\n",
+		       test_connector->conn);
+	}
+	return ret;
+}
+
+void shutdown(int drv_fd)
+{
+	int i;
+	struct dp_connector *index = dp_connector_list, *prev;
+	struct drm_mode_destroy_dumb dreq;
+
+	for (i = 0; i < dp_connector_count; i++) {
+		if (index->saved_crtc) {
+			drmModeSetCrtc(drv_fd, index->saved_crtc->crtc_id,
+				       index->saved_crtc->buffer_id,
+				       index->saved_crtc->x,
+				       index->saved_crtc->y, &index->conn, 1,
+				       &index->saved_crtc->mode);
+			drmModeFreeCrtc(index->saved_crtc);
+		}
+		drmModeRmFB(drv_fd, index->fb);
+		/* Clean up dumb buffer */
+		memset(&dreq, 0, sizeof(dreq));
+		dreq.handle = index->fb_handle;
+		drmIoctl(drv_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+		prev = index;
+		index = index->next;
+		free(prev);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int status = 0;
+	int drv_fd = 0;
+	drmModeResPtr mode_resources = NULL;
+	int done = 0;
+	char input;
+	struct dp_connector *active_connector;
+	int test_data, test_type;
+
+	/* Setup input for keyboard handling - from input.c */
+	set_conio_terminal_mode();
+
+	printf("ATTENTION:\r\n"
+	       "   Ensure that no display manager is running\r\n"
+	       "   App must be run as root in console/text mode\r\n"
+	       "   Continue? (Y/N)"
+	       );
+	input = getchar();
+
+	if (input != 'Y' && input != 'y')
+		goto exit;
+
+	/* All-in-one setup function to get DRM off the ground */
+	setup_drm(&drv_fd, I915_DRIVER_NODE);
+
+	/* From moderes, get the connectors, encoders, CRTCs, etc */
+	setup_connectors(drv_fd, mode_resources);
+
+	active_connector = &dp_connector_list[0];
+
+	setup_debugfs_files(&test_active_fd, &test_type_fd, &test_data_fd);
+
+	printf("\r\n\r\nWaiting for test requests. 'X' or 'Q' exits\r\n"); 
+
+	while (!done) {
+		if (kbhit()) {
+			input = getch();
+			switch (input) {
+			case 'q':
+			case 'Q':
+			case 'x':
+			case 'X':
+				done = 1;
+				break;
+			}
+		}
+		usleep(1000);
+		if (check_test_active()) {
+			test_data = get_test_data();
+			test_type = get_test_type();
+			process_test_request(drv_fd, test_type, test_data, active_connector);
+			usleep(10000);
+		}
+	}
+
+exit:
+	cleanup_debugfs();
+
+	shutdown(drv_fd);
+
+	if (drv_fd > 0) {
+		status = drmClose(drv_fd); 
+		if (status)
+			printf("Error: Failed to close i915 driver\r\n");
+	}
+
+	printf("Compliance testing application exiting.\r\n"
+	       "If testing has been performed, you may want to restart\r\n"
+	       "the system to ensure it returns to normal operation.\r\n");
+
+	return status;
+}
+
diff --git a/dp_compliance/input.c b/dp_compliance/input.c
new file mode 100644
index 0000000..7281ce6
--- /dev/null
+++ b/dp_compliance/input.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <termios.h>
+
+/* Code sourced from stackoverflow.com -
+	http://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input 
+*/
+
+struct termios orig_termios;
+
+void reset_terminal_mode()
+{
+    tcsetattr(0, TCSANOW, &orig_termios);
+}
+
+void set_conio_terminal_mode()
+{
+    struct termios new_termios;
+
+    /* take two copies - one for now, one for later */
+    tcgetattr(0, &orig_termios);
+    memcpy(&new_termios, &orig_termios, sizeof(new_termios));
+
+    /* register cleanup handler, and set the new terminal mode */
+    atexit(reset_terminal_mode);
+    cfmakeraw(&new_termios);
+    tcsetattr(0, TCSANOW, &new_termios);
+}
+
+int kbhit()
+{
+    struct timeval tv = { 0L, 0L };
+    fd_set fds;
+    FD_ZERO(&fds);
+    FD_SET(0, &fds);
+    return select(1, &fds, NULL, NULL, &tv);
+}
+
+int getch()
+{
+    int r;
+    unsigned char c = 0;
+    if ((r = read(0, &c, sizeof(c))) < 0) {
+        return r;
+    } else return c;
+}
-- 
1.9.1



More information about the Intel-gfx mailing list