On 10 April 2015 at 16:54, Todd Previte <tprevite@xxxxxxxxx> wrote: > 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. Just a few comments below from a cursory glance through the code. There are some places where greater use of the i-g-t library may bring some advantages. > > Signed-off-by: Todd Previte <tprevite@xxxxxxxxx> > --- > 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 Yes, this should be a Makefile! Once common i-g-t flags are added there are a few minor compiler warnings, mostly introduced by $(CWARNFLAGS). You'll also need to decide if you want to install the program by default, and if so then including a man page would be useful. > + > +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 A couple of complaints from git-am about trailing whitespace around here and elsewhere. > + * Performs Displayport compliance testing for the Intel i915 driver > + * > + * Copyright ? 2014-2015 Intel Corporation I guess '?' should be '©'. > + * > + * 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@xxxxxxxxx> > + * > + * 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); Some of the lines around here appear to be intended by one space. > + > +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); Normally "\n" would suffice, but "\r\n" is needed since the terminal is in "raw" mode. I suggest perhaps looking at igt_debug_wait_for_keypress for a way to wait for single key entry without putting the terminal permanently into "raw" mode. > + 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); igt_debugfs_open would provide some useful advantages here, such as making sure debugfs is mounted and finding the correct minor number. > + > + 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; > + } > + } drm_open_any will search for the first i915 device, and drm_open_any_master will also ensure it is drm master. > + > + 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@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@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"); Would the standard ctrl-c and a signal handler suffice? This would avoid using special terminal modes. Alternatively, there is also an example of using the GLib mainloop in testdisplay and monitoring stdin. > + > + 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: You might want to look at igt_install_exit_handler for this, as it runs exit handlers from atexit as well as when a signal is received. The terminal reset code also ought to run when a signal is received (e.g. after ctrl-c). > + 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 > +*/ I'm not sure what the copyright status of this code is. > + > +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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx