Displayport Compliance User Application
PATCH 1/1 Displayport Compliance User Application
This is the userspace application that accompanies the Displayport compliance testing patch set. This application must be used in conjunction with the kernel patch set to successfully complete compliance testing.
This is a unified patch that contains the 4 main files in the user app directory. Those files are as follows:
README - contains current information about the compliance test suite build.sh - simple command-line script to build the app dp_compliance.c - the source code for the user app input.c - source code for the input handler in the app
This code currenty resides in a local branch of the Intel Graphics Tools project. The plan is to have this app merged into the IGT project.
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
PATCH 1/1 igt/dp: Displayport Compliance Testing - Userspace Component
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.
--- 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
dp_compliance/README new file +102 -0
@@ -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. +
dp_compliance/build.sh new file +6 -0
@@ -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` +
dp_compliance/dp_compliance.c new file +782 -0
782 lines not on this page · raw message
dp_compliance/input.c new file +48 -0
48 lines not on this page · raw message
Signature · 6 lines
1.9.1 _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH] igt/dp: Displayport Compliance Testing - Userspace Component
Quoted 4 lines · Todd Previte
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.
Quoted 127 lines
Signed-off-by Todd Previte <[email protected]>--- 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.cdp_compliance/README new file +102
-0@@ -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. +dp_compliance/build.sh new file +0
-0
dp_compliance/build.sh line 3
Quoted 3 lines
dp_compliance/build.sh new file +3
-0@@ -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.
dp_compliance/dp_compliance.c line 2
Quoted 11 lines
dp_compliance/build.sh new file +3
-0+ +gcc -g3 dp_compliance.c input.c -o dp_compliance_app -Wall `pkg-config --libs --cflags libdrm` +dp_compliance/dp_compliance.c new file +2
-0@@ -0,0 +1,782 @@ +/* +* Displayport Compliance Testing Application
A couple of complaints from git-am about trailing whitespace around here and elsewhere.
dp_compliance/dp_compliance.c line 5
Quoted 3 lines
dp_compliance/dp_compliance.c new file +3
-0+* Performs Displayport compliance testing for the Intel i915 driver +* +* Copyright ? 2014-2015 Intel Corporation
I guess '?' should be '©'.
Quoted 111 lines
dp_compliance/dp_compliance.c new file +111
-0+* +* 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 <[email protected]> +* +* 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 ); +
dp_compliance/dp_compliance.c line 126
Quoted 10 lines
dp_compliance/dp_compliance.c new file +10
-0+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.
Quoted 27 lines
dp_compliance/dp_compliance.c new file +27
-0+ +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 );
dp_compliance/dp_compliance.c line 163
Quoted 10 lines
dp_compliance/dp_compliance.c new file +10
-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.
Quoted 105 lines
dp_compliance/dp_compliance.c new file +105
-0+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)
dp_compliance/dp_compliance.c line 278
Quoted 10 lines
dp_compliance/dp_compliance.c new file +10
-0+{ +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.
Quoted 30 lines
dp_compliance/dp_compliance.c new file +30
-0+ +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 ; + } +
dp_compliance/dp_compliance.c line 318
Quoted 10 lines
dp_compliance/dp_compliance.c new file +10
-0+ 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.
Quoted 414 lines
dp_compliance/dp_compliance.c new file +414
-0+ +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 */
dp_compliance/dp_compliance.c line 742
Quoted 10 lines
dp_compliance/dp_compliance.c new file +10
-0+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.
Quoted 13 lines
dp_compliance/dp_compliance.c new file +13
-0+ +while (!done) { +if (kbhit ()) { + input =getch (); +switch (input) { +case 'q' : +case 'Q' : +case 'x' : +case 'X' : + done =1 ; +break ; + } + }
dp_compliance/dp_compliance.c line 765
Quoted 10 lines
dp_compliance/dp_compliance.c new file +10
-0+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).
Quoted 23 lines
dp_compliance/dp_compliance.c new file +17
-0+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; +} +dp_compliance/input.c new file +0
-0
dp_compliance/input.c line 9
Quoted 9 lines
dp_compliance/input.c new file +9
-0@@ -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.
Quoted 40 lines
dp_compliance/input.c new file +39
-1+ +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; +} --
Quoted 1 line
1.9.1
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH] igt/dp: Displayport Compliance Testing - Userspace Component
Quoted 141 lines · Thomas Wood
Quoted 4 lines · Todd Previte
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.
Quoted 126 lines
Signed-off-by Todd Previte <[email protected]>--- 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.shcreate mode 100644dp_compliance/dp_compliance.ccreate mode 100644dp_compliance/input.cdp_compliance/README new file +102
-0@@ -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. +dp_compliance/build.sh new file +0
-0dp_compliance/build.sh line 3
Quoted 3 lines
dp_compliance/build.sh new file +3
-0@@ -0,0 +1,6 @@ +#!/bin/sh +# Simple build script for the compliance app +# Eventually should be a makefile in IGTYes, this should be a
Makefile!
Quoted 5 lines
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.
Do you have a standard template for the i-g-t makefile or is it just a matter of cloning an existing one?
It should probably be an optional component of the test suite. Displayport compliance testing requires dedicated HW and SW that isn't generally available to individual developers (mostly because it's rather expensive to obtain). So having it as part of a default installation is probably not worth doing.
Quoted 14 lines
dp_compliance/dp_compliance.c line 2
Quoted 12 lines
dp_compliance/build.sh new file +3
-0+ +gcc -g3 dp_compliance.c input.c -o dp_compliance_app -Wall `pkg-config --libs --cflags libdrm` +dp_compliance/dp_compliance.c new file +2
-0@@ -0,0 +1,782 @@ +/* +* Displayport Compliance Testing Application A couple of complaints from git-am about trailing whitespace around here and elsewhere.
They always sneak in there. I'll scrub it again for whitespace errors.
Quoted 5 lines
dp_compliance/dp_compliance.c line 5
Quoted 4 lines
dp_compliance/dp_compliance.c new file +3
-0+* Performs Displayport compliance testing for the Intel i915 driver +* +* Copyright ? 2014-2015 Intel Corporation I guess '?' should be '©'.
Must have happened when the text encoding changed. I think it's UTF-8 now. Do you have a preference for text file formats within i-g-t?
Quoted 114 lines
Quoted 114 lines
dp_compliance/dp_compliance.c new file +114
-0+* +* 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 <[email protected]> +* +* 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,
Quoted 8 lines
dp_compliance/dp_compliance.c line 126
Quoted 7 lines
dp_compliance/dp_compliance.c new file +7
-0+ 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.
Oh that might have been the auto-align "feature" in my editor. I'll go fix these.
Quoted 33 lines
Quoted 33 lines
dp_compliance/dp_compliance.c new file +33
-0+ +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 ;
Quoted 8 lines
dp_compliance/dp_compliance.c line 163
Quoted 4 lines
dp_compliance/dp_compliance.c new file +4
-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_keypressfor a way to wait for single key entry without putting the terminal permanently into "raw" mode.
Ahhh I knew i-g-t must have something in there to handle this. I'll have a look at it and see what it'll take to use that instead.
Quoted 110 lines
Quoted 110 lines
dp_compliance/dp_compliance.c new file +109
-0+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;
Quoted 8 lines
dp_compliance/dp_compliance.c line 278
Quoted 6 lines
dp_compliance/dp_compliance.c new file +6
-0+ + offset =strlen (INTEL_DP_DEBUGFS_ROOT ); + index = &debugfs_path[offset]; + +memset (debugfs_path,0 ,256 ); +strcpy (debugfs_path,INTEL_DP_DEBUGFS_ROOT );
igt_debugfs_openwould provide some useful advantages here, such as making sure debugfs is mounted and finding the correct minor number.
Works for me. I'll put this on the list.
Quoted 34 lines
Quoted 34 lines
dp_compliance/dp_compliance.c new file +34
-0+ +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 );
Quoted 8 lines
dp_compliance/dp_compliance.c line 318
Quoted 6 lines
dp_compliance/dp_compliance.c new file +6
-0+if (fd <0 ) { + ret = -errno; +printf ("Error: could not open '%s'\r\n" , node); +return ret; + } + }
drm_open_anywill search for the first i915 device, anddrm_open_any_masterwill also ensure it is drm master.
Ok that seems like a better solution. With the early revisions of this app, I recall some issues in trying to open DRM devices. So changing this out for known-good code from i-g-t is the way to go.
Quoted 421 lines
Quoted 421 lines
dp_compliance/dp_compliance.c new file +420
-0+ +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 ];
Quoted 8 lines
dp_compliance/dp_compliance.c line 742
Quoted 4 lines
dp_compliance/dp_compliance.c new file +4
-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.
I recently updated this on my Github repo version. It uses code from testdisplay.c and some that I wrote, which seems to work just fine. Ctrl-C and a sig handler would be fine too, but I wanted the option of accepting input should that become necessary later down the road for additional compliance testing.
Quoted 19 lines
Quoted 19 lines
dp_compliance/dp_compliance.c new file +19
-0+ +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 );
Quoted 8 lines
dp_compliance/dp_compliance.c line 765
Quoted 4 lines
dp_compliance/dp_compliance.c new file +4
-0+ } + } + +exit:You might want to look at
igt_install_exit_handlerfor 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).
I will definitely look into this. Thank you for the suggestion.
Quoted 26 lines
Quoted 26 lines
dp_compliance/dp_compliance.c new file +17
-0+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; +} +dp_compliance/input.c new file +2
-0@@ -0,0 +1,48 @@ +#include <stdlib.h> +#include <string.h>
Quoted 8 lines
dp_compliance/input.c line 9
Quoted 7 lines
dp_compliance/input.c new file +7
-0+#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.
This was the main motivation for removing the original input handler code. So instead of trying to figure out if there's a problem, I removed it and changed over to the code from testdisplay and my stuff that I mentioned further up.
Quoted 34 lines
Quoted 34 lines
dp_compliance/input.c new file +33
-0+ +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 () +{
Quoted 8 lines
Quoted 8 lines
dp_compliance/input.c new file +6
-1+int r; +unsigned char c =0 ; +if ((r =read (0 , &c,sizeof (c))) <0 ) { +return r; + }else return c; +} --1.9.1
Thank you for the review, Thomas! I will post the updated version to the list but if you can always find the latest version on my Github repo here:
https://github.com/tprevite/intel-gpu-tools/tree/dp_compliance
Oddly, that link should have been in the cover letter for this patch series but isn't there. I'll fix that for the next major revision.
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH] igt/dp: Displayport Compliance Testing - Userspace Component
Quoted 189 lines · Todd Previte
Quoted 186 lines · Thomas Wood
Quoted 5 lines · Todd Previte
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.
Quoted 167 lines
Signed-off-by Todd Previte <[email protected]>--- 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.shcreate mode 100644dp_compliance/dp_compliance.ccreate mode 100644dp_compliance/input.cdp_compliance/README new file +5
-0@@ -0,0 +1,102 @@ + +Displayport Compliance Testing +Userspace Application + +This is the userspace portion of the Displayport Compliance testingsuite for the
+i915 driver. It must be running in order to successfully complete Displayport
+compliance testing. This file contains the latest available information aboutdp_compliance/README new file +3
-0+the user app and its operation. + +This app and the kernel code that accompanies it has been written tosatisfy the
+requirements of the Displayport Link CTS Core 1.2 rev1.1 specification from VESA.dp_compliance/README new file +5
-0+ +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 compliancesupport
+ - A Displayport compliance testing appliance such as the Unigraf
DPR-100,dp_compliance/README new file +7
-0+ 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 applianceand 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 thatdp_compliance/README new file +3
-0+ device. + + The Linux DUT must be in text (console) mode and cannot have anyother 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 fordp_compliance/README new file +3
-0+ the kernel are as follows: + “test debug drm.debug=0x0e” + This enables debug output in the logs and will boot the system toa command prompt.
dp_compliance/README new file +5
-0+ + You must be logged in as root in order to run the user app. + + Connections (required): + - Test appliance connected to the external Displayportconnector on the DUT
+ - Test appliance connected to the Windows host (usually
via USB)dp_compliance/README new file +3
-0+ + Connections (optional): + - SSH/telnet connection to the DUT from the Windows hostor other system
+ - A display attached to the DUT for monitoring the
console or runningdp_compliance/README new file +3
-0+ the user app. + + The user app can be run directly from the console on the DUT (ifa 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 howdp_compliance/README new file +3
-0+ the user app is launched. + + Once the user application is up and running, waiting for a testrequest, the software
+ on the Windows host can now be used to execute the compliance
tests.dp_compliance/README new file +4
-0+ + TL;DR version: + - Install test appliance software on Windows host + - Adjust command line on Linux DUT as necessary to enabledebug and boot
dp_compliance/README new file +2
-0+ to the console + - Connect the test appliance via USB to the Windows hostand a Displayport
dp_compliance/README new file +4
-0+ 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 compliancetest 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 untildp_compliance/README new file +2
-0+ it says it’s waiting for a test to begin + - Execute the tests via the software on the Windows hostper the
dp_compliance/README new file +12
-0+ 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 iscurrently active
+ in the kernel. This flag is polled by userspace and once set,
invokes the testdp_compliance/README new file +4
-0+ handler in the user app. + +i915_dp_test_data + Test data is used by the kernel to pass parameters to the userapp. 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.dp_compliance/README new file +3
-0+ +i915_dp_test_type + The test type variable instructs the user app as to what therequested 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 indp_compliance/README new file +6
-0+ drm_dp_helper.h. + +Test operations: + +Notes: + If the test_active flag is stuck, it can be cleared with thissimple command:
dp_compliance/README new file +2
-0+ echo 0 > /sys/kernel/debug/dri/0/i915_dp_test_active + This can happen when the test appliance is connected and a testis run, but the
dp_compliance/README new file +2
-0+ user app isn’t running. +dp_compliance/build.sh new file +0
-0dp_compliance/build.sh line 3
Quoted 3 lines
dp_compliance/build.sh new file +3
-0@@ -0,0 +1,6 @@ +#!/bin/sh +# Simple build script for the compliance app +# Eventually should be a makefile in IGTYes, this should be a
Makefile!
Quoted 8 lines
Quoted 5 lines
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.
Do you have a standard template for the i-g-t makefile or is it just a matter of cloning an existing one?
Just a standard automake Makefile.am. This is what I used:
bin_PROGRAMS=dp_compliance dp_compliance_SOURCES=dp_compliance.c input.c AM_CFLAGS=$(DRM_CFLAGS) $(DEBUG_CFLAGS) $(CWARNFLAGS) LDADD=$(DRM_LIBS)
Then added to the file to AC_CONFIG_FILES in configure.ac and the directory to SUBDIRS in the toplevel Makefile.am.
Quoted 6 lines
It should probably be an optional component of the test suite. Displayport compliance testing requires dedicated HW and SW that isn't generally available to individual developers (mostly because it's rather expensive to obtain). So having it as part of a default installation is probably not worth doing.
Ensuring it is not installed is just a matter of adding the noinst_ prefix to bin_PROGRAMS. Since there are no software dependencies, building it by default makes sense to ensure it is kept up-to-date with any i-g-t library changes.
Quoted 22 lines
Quoted 18 lines
Quoted 13 lines
dp_compliance/build.sh new file +3
-1+ +gcc -g3 dp_compliance.c input.c -o dp_compliance_app -Wall `pkg-config --libs --cflags libdrm` +dp_compliance/dp_compliance.c new file +0
-0dp_compliance/dp_compliance.c line 2
Quoted 2 lines
dp_compliance/dp_compliance.c new file +2
-0@@ -0,0 +1,782 @@ +/* +* Displayport Compliance Testing Application A couple of complaints from git-am about trailing whitespace around here and elsewhere.
They always sneak in there. I'll scrub it again for whitespace errors.
Quoted 2 lines
Quoted 8 lines
Quoted 5 lines
dp_compliance/dp_compliance.c line 5
Quoted 3 lines
dp_compliance/dp_compliance.c new file +3
-0+* Performs Displayport compliance testing for the Intel i915 driver +* +* Copyright ? 2014-2015 Intel Corporation I guess '?' should be '©'.
Must have happened when the text encoding changed. I think it's UTF-8 now. Do you have a preference for text file formats within i-g-t?
UTF-8 is preferable.
Quoted 951 lines
Quoted 138 lines
Quoted 138 lines
dp_compliance/dp_compliance.c new file +2
-0+* +* 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 <[email protected]>
+ *
+ * Elements of the modeset code adapted from David Herrmann's
+ * DRM modeset example
+ *dp_compliance/dp_compliance.c new file +35
-0+*/ + +#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 */
dp_compliance/dp_compliance.c new file +2
-0+ +#define DP_COMPLIANCE_TEST_TYPE_MASK (DP_TEST_LINK_TRAINING| \
dp_compliance/dp_compliance.c new file +5
-0+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 */
dp_compliance/dp_compliance.c new file +5
-0+#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)
+#defineINTEL_DP_RESOLUTION_STANDARD(2 <<INTEL_DP_RESOLUTION_SHIFT_MASK)
+#defineINTEL_DP_RESOLUTION_FAILSAFE(3 <<INTEL_DP_RESOLUTION_SHIFT_MASK)
+#defineDP_COMPLIANCE_VIDEO_MODE_MASK(INTEL_DP_RESOLUTION_PREFERRED|
\
+INTEL_DP_RESOLUTION_STANDARD|
\dp_compliance/dp_compliance.c new file +37
-0+ 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,
+ structdp_connector*dp_conn);
+ intsetup_framebuffers(int drv_fd, struct dp_connector *dp_conn);Quoted 8 lines
Quoted 6 lines
+ int
setup_failsafe_framebuffer(int drv_fd, struct dp_connector *dp_conn);
+ int setup_dp_connector(intdrv_fd, drmModeRes *mr, drmModeConnector *c,
+ structdp_connector*dp_conn);
+ intsetup_connectors(int drv_fd, drmModeResPtr pmr);
+ intsetup_drm(int *drv_fd, const char *node);Some of the lines around here appear to be intended by one space.
Oh that might have been the auto-align "feature" in my editor. I'll go fix these.
Quoted 35 lines
Quoted 35 lines
dp_compliance/dp_compliance.c new file +5
-0+ +void shutdown (int drv_fd); +void cleanup_debugfs (void ); + + int set_video_mode(int drv_fd, int mode, struct dp_connector
*test_connector);
+ intcheck_test_active(void);dp_compliance/dp_compliance.c new file +28
-0+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 ; + }Quoted 8 lines
dp_compliance/dp_compliance.c line 163
Quoted 3 lines
dp_compliance/dp_compliance.c new file +3
-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_keypressfor a way to wait for single key entry without putting the terminal permanently into "raw" mode.Ahhh I knew i-g-t must have something in there to handle this. I'll have a look at it and see what it'll take to use that instead.
Quoted 113 lines
Quoted 113 lines
dp_compliance/dp_compliance.c new file +31
-0+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
dp_compliance/dp_compliance.c new file +70
-0+* 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. Writefailed!\r\n");
dp_compliance/dp_compliance.c new file +9
-0+} + +void setup_debugfs_files (int *test_active_fd,int *test_type_fd, +int *test_data_fd) +{ +char debugfs_path[256 ]; +char *index; +int offset; +Quoted 8 lines
dp_compliance/dp_compliance.c line 278
Quoted 5 lines
dp_compliance/dp_compliance.c new file +5
-0+ offset =strlen (INTEL_DP_DEBUGFS_ROOT ); + index = &debugfs_path[offset]; + +memset (debugfs_path,0 ,256 ); +strcpy (debugfs_path,INTEL_DP_DEBUGFS_ROOT );
igt_debugfs_openwould provide some useful advantages here, such as making sure debugfs is mounted and finding the correct minor number.Works for me. I'll put this on the list.
Quoted 35 lines
Quoted 35 lines
dp_compliance/dp_compliance.c new file +35
-0+ +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 ) {Quoted 8 lines
dp_compliance/dp_compliance.c line 318
Quoted 5 lines
dp_compliance/dp_compliance.c new file +5
-0+ ret = -errno; +printf ("Error: could not open '%s'\r\n" , node); +return ret; + } + }
drm_open_anywill search for the first i915 device, anddrm_open_any_masterwill also ensure it is drm master.Ok that seems like a better solution. With the early revisions of this app, I recall some issues in trying to open DRM devices. So changing this out for known-good code from i-g-t is the way to go.
Quoted 444 lines
Quoted 444 lines
dp_compliance/dp_compliance.c new file +48
-0+ +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",
dp_compliance/dp_compliance.c new file +10
-0+ i, + pmr->connectors[i]); + } +free (dp_conn); +drmModeFreeConnector (c); +continue ; + } +else + dp_connector_count++; +/* free connector data and link device into global list */
dp_compliance/dp_compliance.c new file +26
-0+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);
dp_compliance/dp_compliance.c new file +9
-0+ +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",
dp_compliance/dp_compliance.c new file +15
-0+ 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",
dp_compliance/dp_compliance.c new file +17
-0+ 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",
dp_compliance/dp_compliance.c new file +7
-0+ c->connector_id, ret); +return ret; + } + + ret =setup_failsafe_framebuffer (drv_fd, dp_conn); +if (ret) { + printf("Create failsafe framebuffer for connector %ufailed (%d)\r\n",
dp_compliance/dp_compliance.c new file +8
-0+ c->connector_id, ret); +return ret; + } + +return ret; +} + +int setup_crtc_for_connector(int fd, drmModeRes *mr, drmModeConnector*c,
dp_compliance/dp_compliance.c new file +15
-0+ 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) {dp_compliance/dp_compliance.c new file +25
-0+ 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) {dp_compliance/dp_compliance.c new file +14
-0+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);dp_compliance/dp_compliance.c new file +27
-0+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_compliance/dp_compliance.c new file +16
-0+ &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,dp_compliance/dp_compliance.c new file +43
-0+ 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_compliance/dp_compliance.c new file +18
-0+ &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,dp_compliance/dp_compliance.c new file +21
-0+ 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)dp_compliance/dp_compliance.c new file +35
-0+{ +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,dp_compliance/dp_compliance.c new file +18
-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,dp_compliance/dp_compliance.c new file +3
-0+ index->saved_crtc->buffer_id, + index->saved_crtc->x, + index->saved_crtc->y,
&index->conn, 1,dp_compliance/dp_compliance.c new file +46
-0+ &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);Quoted 8 lines
Quoted 3 lines
dp_compliance/dp_compliance.c new file +2
-0+ + 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.
I recently updated this on my Github repo version. It uses code from
testdisplay.cand some that I wrote, which seems to work just fine. Ctrl-C and a sig handler would be fine too, but I wanted the option of accepting input should that become necessary later down the road for additional compliance testing.Quoted 21 lines
Quoted 21 lines
dp_compliance/dp_compliance.c new file +18
-0+ +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);dp_compliance/dp_compliance.c new file +2
-0+usleep (10000 ); + }Quoted 8 lines
dp_compliance/dp_compliance.c line 765
Quoted 3 lines
dp_compliance/dp_compliance.c new file +3
-0+ } + +exit:You might want to look at
igt_install_exit_handlerfor 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).I will definitely look into this. Thank you for the suggestion.
Quoted 30 lines
Quoted 30 lines
dp_compliance/dp_compliance.c new file +12
-0+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 torestart\r\n"
+ "the system to ensure it returns to normal
operation.\r\n");dp_compliance/dp_compliance.c new file +4
-0+ +return status; +} +dp_compliance/input.c new file +4
-0@@ -0,0 +1,48 @@ +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/select.h> Quoted 8 lines
Quoted 6 lines
dp_compliance/input.c new file +4
-0+#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.
This was the main motivation for removing the original input handler code. So instead of trying to figure out if there's a problem, I removed it and changed over to the code from testdisplay and my stuff that I mentioned further up.
Quoted 34 lines
Quoted 34 lines
dp_compliance/input.c new file +33
-0+ +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 () +{Quoted 8 lines
Quoted 8 lines
dp_compliance/input.c new file +6
-1+int r; +unsigned char c =0 ; +if ((r =read (0 , &c,sizeof (c))) <0 ) { +return r; + }else return c; +} --1.9.1
Thank you for the review, Thomas! I will post the updated version to the list but if you can always find the latest version on my Github repo here:
Quoted 11 lines
https://github.com/tprevite/intel-gpu-tools/tree/dp_compliance
Oddly, that link should have been in the cover letter for this patch series but isn't there. I'll fix that for the next major revision.
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH] igt/dp: Displayport Compliance Testing - Userspace Component
In reply to Todd PreviteQuoted 8 lines · Todd Previte
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 <[email protected]>--- dp_compliance/README | 102 ++++++
Just one small but important typo I noticed in this file ...
Quoted 39 lines
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.cdp_compliance/README new file +24
-0@@ -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
dp_compliance/README line 34
Quoted 10 lines
dp_compliance/README new file +10
-0+ 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”
s/test/text/
.Dave.
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH] igt/dp: Displayport Compliance Testing - Userspace Component
Quoted 62 lines · Dave Gordon
Quoted 8 lines · Todd Previte
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 <[email protected]>--- dp_compliance/README | 102 ++++++Just one small but important typo I noticed in this file ...
Quoted 39 lines
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.shcreate mode 100644dp_compliance/dp_compliance.ccreate mode 100644dp_compliance/input.cdp_compliance/README new file +24
-0@@ -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 freshlydp_compliance/README line 34
Quoted 10 lines
dp_compliance/README new file +10
-0+ 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”s/test/text/
Quoted 1 line
.Dave.
Good catch, Dave, thank you! I'll get that fixed immediately.
-T
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx