[Intel-gfx] [PATCH i-g-t] tools: Add intel_dp_compliance for DisplayPort 1.2 compliance automation

Manasi Navare manasi.d.navare at intel.com
Fri Dec 2 19:23:58 UTC 2016


On Wed, Nov 23, 2016 at 03:59:52PM +0200, Jani Nikula wrote:
> On Tue, 22 Nov 2016, Manasi Navare <manasi.d.navare at intel.com> wrote:
> > +
> > +static void get_test_videopattern_data(void)
> > +{
> > +	int count = 0;
> > +	uint16_t video_pattern_value[3];
> > +	char video_pattern_attribute[15];
> > +
> > +	if (!test_data_fp)
> > +		fprintf(stderr, "Invalid Test data File pointer\r\n");
> > +
> > +	rewind(test_data_fp);
> > +	while (!feof(test_data_fp) && count < 3)
> > +		fscanf(test_data_fp, "%s %u\n", video_pattern_attribute,
> > +		       (unsigned int *)&video_pattern_value[count++]);
> > +
> > +	hdisplay = video_pattern_value[0];
> > +	vdisplay = video_pattern_value[1];
> > +	bitdepth = video_pattern_value[2];
> > +	igt_info("Hdisplay = %d\r\n", hdisplay);
> > +	igt_info("Vdisplay = %d\r\n", vdisplay);
> > +	igt_info("BitDepth = %u\r\n", bitdepth);
> > +
> > +}
> 
> If you have this working now, I guess we can go with what's in [1] since
> that's fairly isolated for now. It's debugfs, so we can remove it
> later. In the long run, I do want this using DPCD directly though.
> 
> BR,
> Jani.
> 
> 
> 
> [1] http://patchwork.freedesktop.org/patch/msgid/1479850766-32748-6-git-send-email-manasi.d.navare@intel.com
> 
> 
> 
>

Thanks for your feedback Jani.
Yes, I have the debugfs interface fully functional and validated with DPR-120
compliance unit. So I agree that we can stick with this for now and since its
debugfs we can replace it later with reading the dpcd directly in IGT tool
if and when the number of DPCD registers increases for more testing. For now its
literally only 3 values (for video) and 1 for EDID that we are reading from DPCD 
through the debugfs interface.

Manasi

 
> > +
> > +static int process_test_request(int test_type)
> > +{
> > +	int mode;
> > +	unsigned long test_data_edid;
> > +	int status = 0;
> > +
> > +	switch (test_type) {
> > +	case DP_TEST_LINK_VIDEO_PATTERN:
> > +		video_pattern_flag = true;
> > +		get_test_videopattern_data();
> > +		mode = INTEL_MODE_VIDEO_PATTERN_TEST;
> > +		break;
> > +	case DP_TEST_LINK_EDID_READ:
> > +		test_data_edid = get_test_edid_data();
> > +		mode = (test_data_edid & DP_COMPLIANCE_VIDEO_MODE_MASK) >>
> > +			INTEL_DP_RESOLUTION_SHIFT_MASK;
> > +		break;
> > +	default:
> > +		/* Unknown test type */
> > +		fprintf(stderr, "Invalid test request. Ignored.\r\n");
> > +		break;
> > +	}
> > +	status = update_display(mode, true);
> > +
> > +	/* Return 0 on success and -1 on failure */
> > +	return status;
> > +}
> > +
> > +static void dump_connectors_fd(int drmfd)
> > +{
> > +	int i, j;
> > +
> > +	drmModeRes *mode_resources = drmModeGetResources(drmfd);
> > +
> > +	if (!mode_resources) {
> > +		igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
> > +		return;
> > +	}
> > +
> > +	igt_info("Connectors:\n");
> > +	igt_info("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
> > +	for (i = 0; i < mode_resources->count_connectors; i++) {
> > +		drmModeConnector *connector;
> > +
> > +		connector = drmModeGetConnectorCurrent(drmfd,
> > +						       mode_resources->connectors[i]);
> > +		if (!connector) {
> > +			igt_warn("could not get connector %i: %s\n", mode_resources->connectors[i], strerror(errno));
> > +			continue;
> > +		}
> > +
> > +		igt_info("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", connector->connector_id, connector->encoder_id, kmstest_connector_status_str(connector->connection), kmstest_connector_type_str(connector->connector_type), connector->mmWidth, connector->mmHeight, connector->count_modes);
> > +
> > +		if (!connector->count_modes)
> > +			continue;
> > +
> > +		igt_info("  modes:\n");
> > +		igt_info("  name refresh (Hz) hdisp hss hse htot vdisp ""vss vse vtot flags type clock\n");
> > +		for (j = 0; j < connector->count_modes; j++) {
> > +			igt_info("[%d]", j);
> > +			kmstest_dump_mode(&connector->modes[j]);
> > +		}
> > +
> > +		drmModeFreeConnector(connector);
> > +	}
> > +	igt_info("\n");
> > +
> > +	drmModeFreeResources(mode_resources);
> > +}
> > +
> > +static void dump_crtcs_fd(int drmfd)
> > +{
> > +	int i;
> > +	drmModeRes *mode_resources = drmModeGetResources(drmfd);
> > +
> > +	igt_info("CRTCs:\n");
> > +	igt_info("id\tfb\tpos\tsize\n");
> > +	for (i = 0; i < mode_resources->count_crtcs; i++) {
> > +		drmModeCrtc *crtc;
> > +
> > +		crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]);
> > +		if (!crtc) {
> > +			igt_warn("could not get crtc %i: %s\n", mode_resources->crtcs[i], strerror(errno));
> > +			continue;
> > +		}
> > +		igt_info("%d\t%d\t(%d,%d)\t(%dx%d)\n", crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, crtc->width, crtc->height);
> > +		kmstest_dump_mode(&crtc->mode);
> > +
> > +		drmModeFreeCrtc(crtc);
> > +	}
> > +	igt_info("\n");
> > +
> > +	drmModeFreeResources(mode_resources);
> > +}
> > +
> > +static void dump_info(void)
> > +{
> > +	dump_connectors_fd(drm_fd);
> > +	dump_crtcs_fd(drm_fd);
> > +}
> > +
> > +static void connector_find_preferred_mode(uint32_t connector_id,
> > +					  unsigned long crtc_idx_mask,
> > +					  struct connector *c)
> > +{
> > +	struct kmstest_connector_config config;
> > +	bool ret;
> > +
> > +	ret = kmstest_probe_connector_config(drm_fd, connector_id,
> > +					     crtc_idx_mask, &config);
> > +	if (!ret) {
> > +		c->mode_valid = 0;
> > +		return;
> > +	}
> > +
> > +	c->connector = config.connector;
> > +	c->encoder = config.encoder;
> > +	c->crtc = config.crtc->crtc_id;
> > +	c->pipe = config.pipe;
> > +
> > +	if (c->connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort ||
> > +	    c->connector->connection !=  DRM_MODE_CONNECTED) {
> > +		c->mode_valid = 0;
> > +		return;
> > +	}
> > +
> > +	c->mode = config.default_mode;
> > +	c->mode_valid = 1;
> > +}
> > +
> > +static int setup_framebuffers(struct connector *dp_conn)
> > +{
> > +
> > +	dp_conn->fb = igt_create_fb(drm_fd,
> > +				    dp_conn->fb_width, dp_conn->fb_height,
> > +				    DRM_FORMAT_XRGB8888,
> > +				    LOCAL_DRM_FORMAT_MOD_NONE,
> > +				    &dp_conn->fb_video_pattern);
> > +	igt_assert(dp_conn->fb);
> > +
> > +	/* Map the mapping of GEM object into the virtual address space */
> > +	dp_conn->pixmap = gem_mmap__gtt(drm_fd,
> > +					dp_conn->fb_video_pattern.gem_handle,
> > +					dp_conn->fb_video_pattern.size,
> > +					PROT_READ | PROT_WRITE);
> > +	gem_set_domain(drm_fd, dp_conn->fb_video_pattern.gem_handle,
> > +		       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> > +	dp_conn->fb_size = dp_conn->fb_video_pattern.size;
> > +
> > +	/* After filling the device memory with 0s it needs to be unmapped */
> > +	memset(dp_conn->pixmap, 0, dp_conn->fb_size);
> > +	munmap(dp_conn->pixmap, dp_conn->fb_size);
> > +
> > +	return 0;
> > +}
> > +
> > +static int setup_failsafe_framebuffer(struct connector *dp_conn)
> > +{
> > +
> > +	dp_conn->failsafe_fb = igt_create_fb(drm_fd,
> > +					     dp_conn->failsafe_width,
> > +					     dp_conn->failsafe_height,
> > +					     DRM_FORMAT_XRGB8888,
> > +					     LOCAL_DRM_FORMAT_MOD_NONE,
> > +					     &dp_conn->fb_failsafe_pattern);
> > +	igt_assert(dp_conn->failsafe_fb);
> > +
> > +	/* Map the mapping of GEM object into the virtual address space */
> > +	dp_conn->failsafe_pixmap = gem_mmap__gtt(drm_fd,
> > +						 dp_conn->fb_failsafe_pattern.gem_handle,
> > +						 dp_conn->fb_failsafe_pattern.size,
> > +						 PROT_READ | PROT_WRITE);
> > +	gem_set_domain(drm_fd, dp_conn->fb_failsafe_pattern.gem_handle,
> > +		       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> > +	dp_conn->failsafe_size = dp_conn->fb_failsafe_pattern.size;
> > +
> > +	/* After filling the device framebuffer the mapped memory needs to be freed */
> > +	memset(dp_conn->failsafe_pixmap, 0, dp_conn->failsafe_size);
> > +	munmap(dp_conn->failsafe_pixmap, dp_conn->failsafe_size);
> > +
> > +	return 0;
> > +
> > +}
> > +
> > +static int setup_video_pattern_framebuffer(struct connector *dp_conn)
> > +{
> > +	uint32_t  video_width, video_height;
> > +
> > +	video_width = dp_conn->test_pattern.hdisplay;
> > +	video_height = dp_conn->test_pattern.vdisplay;
> > +	dp_conn->test_pattern.fb = igt_create_fb(drm_fd,
> > +						 video_width, video_height,
> > +						 DRM_FORMAT_XRGB8888,
> > +						 LOCAL_DRM_FORMAT_MOD_NONE,
> > +						 &dp_conn->test_pattern.fb_pattern);
> > +	igt_assert(dp_conn->test_pattern.fb);
> > +
> > +	/* Map the mapping of GEM object into the virtual address space */
> > +	dp_conn->test_pattern.pixmap = gem_mmap__gtt(drm_fd,
> > +						     dp_conn->test_pattern.fb_pattern.gem_handle,
> > +						     dp_conn->test_pattern.fb_pattern.size,
> > +						     PROT_READ | PROT_WRITE);
> > +	gem_set_domain(drm_fd, dp_conn->test_pattern.fb_pattern.gem_handle,
> > +		       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> > +
> > +	dp_conn->test_pattern.size = dp_conn->test_pattern.fb_pattern.size;
> > +
> > +	memset(dp_conn->test_pattern.pixmap, 0, dp_conn->test_pattern.size);
> > +	return 0;
> > +
> > +}
> > +
> > +static int fill_framebuffer(struct connector *dp_conn)
> > +{
> > +	uint32_t tile_height, tile_width, video_width, video_height;
> > +	uint32_t *red_ptr, *green_ptr, *blue_ptr, *white_ptr, *src_ptr, *dst_ptr;
> > +	int x, y;
> > +	int32_t pixel_val;
> > +
> > +	video_width = dp_conn->test_pattern.hdisplay;
> > +	video_height = dp_conn->test_pattern.vdisplay;
> > +
> > +	tile_height = 64;
> > +	tile_width = 1 <<  (dp_conn->test_pattern.bitdepth);
> > +
> > +	red_ptr = dp_conn->test_pattern.pixmap;
> > +	green_ptr = red_ptr + (video_width * tile_height);
> > +	blue_ptr = green_ptr + (video_width * tile_height);
> > +	white_ptr = blue_ptr + (video_width * tile_height);
> > +	x = 0;
> > +
> > +	/* Fill the frame buffer with video pattern from CTS 3.1.5 */
> > +	while (x < video_width) {
> > +		for (pixel_val = 0; pixel_val < 256;
> > +		     pixel_val = pixel_val + (256 / tile_width)) {
> > +			red_ptr[x] = pixel_val << 16;
> > +			green_ptr[x] = pixel_val << 8;
> > +			blue_ptr[x] = pixel_val << 0;
> > +			white_ptr[x] = red_ptr[x] | green_ptr[x] | blue_ptr[x];
> > +			if (++x >= video_width)
> > +				break;
> > +		}
> > +	}
> > +	for (y = 0; y < video_height; y++) {
> > +		if (y == 0 || y == 64 || y == 128 || y == 192)
> > +			continue;
> > +		switch ((y / tile_height) % 4) {
> > +		case 0:
> > +			src_ptr = red_ptr;
> > +			break;
> > +		case 1:
> > +			src_ptr = green_ptr;
> > +			break;
> > +		case 2:
> > +			src_ptr = blue_ptr;
> > +			break;
> > +		case 3:
> > +			src_ptr = white_ptr;
> > +			break;
> > +		}
> > +		dst_ptr = dp_conn->test_pattern.pixmap + (y * video_width);
> > +		memcpy(dst_ptr, src_ptr, (video_width * 4));
> > +	}
> > +	munmap(dp_conn->test_pattern.pixmap,
> > +	       dp_conn->test_pattern.size);
> > +	return 0;
> > +}
> > +
> > +static int set_test_mode(struct connector *dp_conn)
> > +{
> > +	int ret = 0;
> > +	int i;
> > +	bool found_std = false, found_fs = false;
> > +	drmModeConnector *c = dp_conn->connector;
> > +
> > +	/* Ignore any disconnected devices */
> > +	if (c->connection != DRM_MODE_CONNECTED) {
> > +		igt_warn("Connector %u disconnected\r\n", c->connector_id);
> > +		return -ENOENT;
> > +	}
> > +	igt_info("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;
> > +
> > +	dp_conn->test_pattern.mode = c->modes[0];
> > +	dp_conn->test_pattern.mode.hdisplay = c->modes[0].hdisplay;
> > +	dp_conn->test_pattern.mode.vdisplay = c->modes[0].vdisplay;
> > +
> > +	igt_info("Preferred mode (mode 0) for connector %u is %ux%u\r\n",
> > +		 dp_conn->id, c->modes[0].hdisplay, c->modes[0].vdisplay);
> > +	fflush(stdin);
> > +
> > +	for (i = 1; i < c->count_modes; i++) {
> > +		/* Standard mode is 800x600 at 60 */
> > +		if (c->modes[i].hdisplay == 800 &&
> > +		    c->modes[i].vdisplay == 600 &&
> > +		    c->modes[i].vrefresh == 60 &&
> > +		    found_std == false) {
> > +			dp_conn->mode_standard = c->modes[i];
> > +			igt_info("Standard mode (%d) for connector %u is %ux%u\r\n",
> > +				 i,
> > +				 c->connector_id,
> > +				 c->modes[i].hdisplay,
> > +				 c->modes[i].vdisplay);
> > +			found_std = true;
> > +		}
> > +		/* Failsafe mode is 640x480 at 60 */
> > +		if (c->modes[i].hdisplay == 640 &&
> > +		    c->modes[i].vdisplay == 480 &&
> > +		    c->modes[i].vrefresh == 60 &&
> > +		    found_fs == false) {
> > +			dp_conn->mode_failsafe = c->modes[i];
> > +			dp_conn->failsafe_width = c->modes[i].hdisplay;
> > +			dp_conn->failsafe_height = c->modes[i].vdisplay;
> > +			igt_info("Failsafe mode (%d) for connector %u is %ux%u\r\n",
> > +				 i,
> > +				 c->connector_id,
> > +				 c->modes[i].hdisplay,
> > +				 c->modes[i].vdisplay);
> > +			found_fs = true;
> > +		}
> > +	}
> > +
> > +	ret = setup_framebuffers(dp_conn);
> > +	if (ret) {
> > +		igt_warn("Create framebuffer for connector %u failed (%d)\r\n",
> > +			 c->connector_id, ret);
> > +		return ret;
> > +	}
> > +
> > +	if (found_fs) {
> > +		ret = setup_failsafe_framebuffer(dp_conn);
> > +		if (ret) {
> > +			igt_warn("Create failsafe framebuffer for connector %u"
> > +				 "failed (%d)\r\n",
> > +				 c->connector_id, ret);
> > +			return ret;
> > +		}
> > +	}
> > +
> > +	if (video_pattern_flag) {
> > +		dp_conn->test_pattern.hdisplay = hdisplay;
> > +		dp_conn->test_pattern.vdisplay = vdisplay;
> > +		dp_conn->test_pattern.bitdepth = bitdepth;
> > +		ret = setup_video_pattern_framebuffer(dp_conn);
> > +		if (ret) {
> > +			igt_warn("Create framebuffer for connector %u failed (%d)\r\n",
> > +				 c->connector_id, ret);
> > +			return ret;
> > +		}
> > +		ret = fill_framebuffer(dp_conn);
> > +		if (ret) {
> > +			igt_warn("Fill framebuffer for connector %u failed (%d)\r\n",
> > +				 c->connector_id, ret);
> > +			return ret;
> > +		}
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static int set_video(int mode, struct connector *test_connector)
> > +{
> > +	drmModeModeInfo *requested_mode;
> > +	uint32_t required_fb_id;
> > +	struct igt_fb required_fb;
> > +	int ret = 0;
> > +
> > +	switch (mode) {
> > +	case INTEL_MODE_NONE:
> > +		igt_info("NONE\r\n");
> > +		ret = drmModeSetCrtc(drm_fd, test_connector->crtc,
> > +				     -1, 0, 0, NULL, 0, NULL);
> > +		goto out;
> > +	case INTEL_MODE_PREFERRED:
> > +		igt_info("PREFERRED\r\n");
> > +		requested_mode =  &test_connector->mode_preferred;
> > +		required_fb_id = test_connector->fb;
> > +		required_fb = test_connector->fb_video_pattern;
> > +		break;
> > +	case INTEL_MODE_STANDARD:
> > +		igt_info("STANDARD\r\n");
> > +		requested_mode =  &test_connector->mode_standard;
> > +		required_fb_id = test_connector->fb;
> > +		required_fb = test_connector->fb_video_pattern;
> > +		break;
> > +	case INTEL_MODE_FAILSAFE:
> > +		igt_info("FAILSAFE\r\n");
> > +		requested_mode =  &test_connector->mode_failsafe;
> > +		required_fb_id = test_connector->failsafe_fb;
> > +		required_fb = test_connector->fb_failsafe_pattern;
> > +		break;
> > +	case INTEL_MODE_VIDEO_PATTERN_TEST:
> > +		igt_info("VIDEO PATTERN TEST\r\n");
> > +		requested_mode = &test_connector->test_pattern.mode;
> > +		required_fb_id = test_connector->test_pattern.fb;
> > +		required_fb = test_connector->test_pattern.fb_pattern;
> > +		break;
> > +	case INTEL_MODE_INVALID:
> > +	default:
> > +		igt_warn("INVALID! (%08x) Mode set aborted!\r\n", mode);
> > +		return -1;
> > +	}
> > +
> > +	igt_info("CRTC(%u):", test_connector->crtc);
> > +	kmstest_dump_mode(requested_mode);
> > +	ret = drmModeSetCrtc(drm_fd, test_connector->crtc, required_fb_id, 0, 0,
> > +			     &test_connector->id, 1, requested_mode);
> > +	if (ret) {
> > +		igt_warn("failed to set mode (%dx%d@%dHz): %s\n",
> > +			 requested_mode->hdisplay, requested_mode->vdisplay,
> > +			 requested_mode->vrefresh, strerror(errno));
> > +		igt_remove_fb(drm_fd, &required_fb);
> > +
> > +	}
> > +	/* Keep the pattern on output lines for atleast 0.5 secs for
> > +	 * DPR-120 to detect it.
> > +	 */
> > +	usleep(1000000);
> > +
> > +out:
> > +	if (ret) {
> > +		igt_warn("Failed to set CRTC for connector %u\r\n",
> > +			 test_connector->id);
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static int
> > +set_default_mode(struct connector *c)
> > +{
> > +	unsigned int fb_id = 0;
> > +	struct igt_fb fb_info;
> > +	int ret = 0;
> > +
> > +	c->mode = c->connector->modes[0];
> > +
> > +	if (!c->mode_valid)
> > +		return -1;
> > +
> > +	width = c->mode.hdisplay;
> > +	height = c->mode.vdisplay;
> > +
> > +	fb_id = igt_create_pattern_fb(drm_fd, width, height,
> > +				      DRM_FORMAT_XRGB8888,
> > +				      tiling, &fb_info);
> > +
> > +	igt_info("CRTC(%u):[%d]", c->crtc, 0);
> > +	kmstest_dump_mode(&c->mode);
> > +	drmModeSetCrtc(drm_fd, c->crtc, -1, 0, 0, NULL, 0, NULL);
> > +	ret = drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0,
> > +			     &c->id, 1, &c->mode);
> > +	if (ret) {
> > +		igt_warn("failed to set mode (%dx%d@%dHz): %s\n", width, height, c->mode.vrefresh, strerror(errno));
> > +		igt_remove_fb(drm_fd, &fb_info);
> > +
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +/*
> > + * Re-probe connectors and do a modeset based on test request or
> > + * in case of a hotplug uevent.
> > + *
> > + * @mode: Video mode requested by the test
> > + * @is_compliance_test: 1: If it is a compliance test
> > + *                      0: If it is a hotplug event
> > + *
> > + * Returns:
> > + * 0: On Success
> > + * -1: On failure
> > + */
> > +int update_display(int mode, bool is_compliance_test)
> > +{
> > +	struct connector *connectors;
> > +	int c, ret = 0;
> > +	unsigned long crtc_idx_mask = -1UL;
> > +
> > +	resources = drmModeGetResources(drm_fd);
> > +	if (!resources) {
> > +		igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
> > +		return -1;
> > +	}
> > +
> > +	connectors = calloc(resources->count_connectors,
> > +			    sizeof(struct connector));
> > +	if (!connectors)
> > +		return -1;
> > +
> > +	/* Find any connected displays */
> > +	for (c = 0; c < resources->count_connectors; c++) {
> > +
> > +		struct connector *connector = &connectors[c];
> > +
> > +		connector->id = resources->connectors[c];
> > +		connector_find_preferred_mode(connector->id,
> > +					      crtc_idx_mask,
> > +					      connector);
> > +		if (!connector->mode_valid)
> > +			continue;
> > +		if (is_compliance_test) {
> > +			set_test_mode(connector);
> > +			ret = set_video(INTEL_MODE_NONE, connector);
> > +			ret = set_video(mode, connector);
> > +
> > +		} else
> > +			ret = set_default_mode(connector);
> > +
> > +		crtc_idx_mask &= ~(1 << connector->pipe);
> > +
> > +		drmModeFreeEncoder(connector->encoder);
> > +		drmModeFreeConnector(connector->connector);
> > +
> > +	}
> > +
> > +	/* Error condition if no connected displays */
> > +
> > +	free(connectors);
> > +	drmModeFreeResources(resources);
> > +	return ret;
> > +}
> > +
> > +static const char optstr[] = "hi";
> > +
> > +static void __attribute__((noreturn)) usage(char *name, char opt)
> > +{
> > +	igt_info("usage: %s [-hi]\n", name);
> > +	igt_info("\t-i\tdump info\n");
> > +	igt_info("\tDefault is to respond to DPR-120 tests.\n");
> > +	exit((opt != 'h') ? -1 : 0);
> > +}
> > +
> > +static void cleanup_debugfs(void)
> > +{
> > +	fclose(test_active_fp);
> > +	fclose(test_data_fp);
> > +	fclose(test_type_fp);
> > +}
> > +
> > +static void __attribute__((noreturn)) cleanup_and_exit(int ret)
> > +{
> > +	cleanup_debugfs();
> > +	close(drm_fd);
> > +	igt_info("Compliance testing Application Exiting\n");
> > +	exit(ret);
> > +}
> > +
> > +static void cleanup_test(void)
> > +{
> > +	video_pattern_flag = false;
> > +	hdisplay = 0;
> > +	vdisplay = 0;
> > +	bitdepth = 0;
> > +}
> > +
> > +static void read_test_request(void)
> > +{
> > +	unsigned long test_type;
> > +
> > +	test_type = get_test_type();
> > +	process_test_request(test_type);
> > +	cleanup_test();
> > +	clear_test_active();
> > +}
> > +
> > +static gboolean test_handler(GIOChannel *source, GIOCondition condition,
> > +			     gpointer data)
> > +{
> > +	unsigned long test_active;
> > +
> > +	rewind(test_active_fp);
> > +	fscanf(test_active_fp, "%lx", &test_active);
> > +	if (test_active)
> > +		read_test_request();
> > +	return TRUE;
> > +}
> > +
> > +static gboolean input_event(GIOChannel *source, GIOCondition condition,
> > +				gpointer data)
> > +{
> > +	gchar buf[2];
> > +	gsize count;
> > +
> > +	count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf));
> > +	if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) {
> > +		cleanup_and_exit(0);
> > +	}
> > +
> > +	return TRUE;
> > +}
> > +
> > +static void enter_exec_path(char **argv)
> > +{
> > +	char *exec_path = NULL;
> > +	char *pos = NULL;
> > +	short len_path = 0;
> > +	int ret;
> > +
> > +	len_path = strlen(argv[0]);
> > +	exec_path = (char *) malloc(len_path);
> > +
> > +	memcpy(exec_path, argv[0], len_path);
> > +	pos = strrchr(exec_path, '/');
> > +	if (pos != NULL)
> > +		*(pos+1) = '\0';
> > +
> > +	ret = chdir(exec_path);
> > +	igt_assert_eq(ret, 0);
> > +	free(exec_path);
> > +}
> > +
> > +static void restore_termio_mode(int sig)
> > +{
> > +	tcsetattr(tio_fd, TCSANOW, &saved_tio);
> > +	close(tio_fd);
> > +}
> > +
> > +static void set_termio_mode(void)
> > +{
> > +	struct termios tio;
> > +
> > +	/* don't attempt to set terminal attributes if not in the foreground
> > +	 * process group
> > +	 */
> > +	if (getpgrp() != tcgetpgrp(STDOUT_FILENO))
> > +		return;
> > +
> > +	tio_fd = dup(STDIN_FILENO);
> > +	tcgetattr(tio_fd, &saved_tio);
> > +	igt_install_exit_handler(restore_termio_mode);
> > +	tio = saved_tio;
> > +	tio.c_lflag &= ~(ICANON | ECHO);
> > +	tcsetattr(tio_fd, TCSANOW, &tio);
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	int c;
> > +	int ret = 0;
> > +	GIOChannel *stdinchannel, *testactive_channel;
> > +	GMainLoop *mainloop;
> > +	bool opt_dump_info = false;
> > +	struct option long_opts[] = {
> > +		{"help-description", 0, 0, HELP_DESCRIPTION},
> > +		{"help", 0, 0, 'h'},
> > +	};
> > +
> > +	igt_skip_on_simulation();
> > +
> > +	enter_exec_path(argv);
> > +
> > +	while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) {
> > +		switch (c) {
> > +		case 'i':
> > +			opt_dump_info = true;
> > +			break;
> > +		case HELP_DESCRIPTION:
> > +			igt_info("DP Compliance Test Suite using DPR-120\n");
> > +			igt_info("EDID Tests\n");
> > +			igt_info("Video Pattern Generation Tests\n");
> > +			exit(0);
> > +			break;
> > +		default:
> > +			/* fall through */
> > +		case 'h':
> > +			usage(argv[0], c);
> > +			break;
> > +		}
> > +	}
> > +
> > +	set_termio_mode();
> > +
> > +	igt_info("*************DP Compliance Testing using DPR-120*************\n");
> > +	igt_info("Waiting for Test Request Input......\n");
> > +	drm_fd = drm_open_driver(DRIVER_ANY);
> > +
> > +	if (opt_dump_info) {
> > +		dump_info();
> > +		goto out_close;
> > +	}
> > +
> > +	kmstest_set_vt_graphics_mode();
> > +	setup_debugfs_files();
> > +	cleanup_test();
> > +
> > +	mainloop = g_main_loop_new(NULL, FALSE);
> > +	if (!mainloop) {
> > +		igt_warn("failed to create glib mainloop\n");
> > +		ret = -1;
> > +		goto out_close;
> > +	}
> > +
> > +	if (!intel_dp_compliance_setup_hotplug()) {
> > +		igt_warn("failed to initialize hotplug support\n");
> > +		goto out_mainloop;
> > +	}
> > +
> > +	testactive_channel = g_io_channel_unix_new(fileno(test_active_fp));
> > +	if (!testactive_channel) {
> > +		igt_warn("failed to create Test Active GIO channel\n");
> > +		goto out_close;
> > +	}
> > +
> > +	ret = g_io_add_watch(testactive_channel, G_IO_IN | G_IO_ERR, test_handler,
> > +			     NULL);
> > +	if (ret < 0) {
> > +		igt_warn("failed to add watch on udev GIO channel\n");
> > +		goto out_close;
> > +	}
> > +
> > +	stdinchannel = g_io_channel_unix_new(0);
> > +	if (!stdinchannel) {
> > +		igt_warn("failed to create stdin GIO channel\n");
> > +		goto out_hotplug;
> > +	}
> > +
> > +	ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event,
> > +			     NULL);
> > +	if (ret < 0) {
> > +		igt_warn("failed to add watch on stdin GIO channel\n");
> > +		goto out_stdio;
> > +	}
> > +
> > +	ret = 0;
> > +
> > +	g_main_loop_run(mainloop);
> > +
> > +out_stdio:
> > +	g_io_channel_shutdown(stdinchannel, TRUE, NULL);
> > +out_hotplug:
> > +	intel_dp_compliance_cleanup_hotplug();
> > +out_mainloop:
> > +	g_main_loop_unref(mainloop);
> > +out_close:
> > +	cleanup_debugfs();
> > +	close(drm_fd);
> > +
> > +	igt_assert_eq(ret, 0);
> > +
> > +	igt_info("Compliance testing application exiting.\n");
> > +	igt_exit();
> > +}
> > diff --git a/tools/intel_dp_compliance.h b/tools/intel_dp_compliance.h
> > new file mode 100644
> > index 0000000..ade1e2f
> > --- /dev/null
> > +++ b/tools/intel_dp_compliance.h
> > @@ -0,0 +1,35 @@
> > +/*
> > + * Copyright 2010 Intel Corporation
> > + * Manasi Navare <manasi.d.navare at intel.com>
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaining a
> > + * copy of this software and associated documentation files (the "Software"),
> > + * to deal in the Software without restriction, including without limitation
> > + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> > + * and/or sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be included in
> > + * all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + */
> > +
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <stdlib.h>
> > +#include <glib.h>
> > +
> > +extern int drm_fd;
> > +
> > +gboolean intel_dp_compliance_setup_hotplug(void);
> > +void intel_dp_compliance_cleanup_hotplug(void);
> > +
> > +/* called by the hotplug code */
> > +int update_display(int mode, bool is_compliance_test);
> > diff --git a/tools/intel_dp_compliance_hotplug.c b/tools/intel_dp_compliance_hotplug.c
> > new file mode 100644
> > index 0000000..d489026
> > --- /dev/null
> > +++ b/tools/intel_dp_compliance_hotplug.c
> > @@ -0,0 +1,123 @@
> > +/*
> > + * Copyright 2010 Intel Corporation
> > + *   Jesse Barnes <jesse.barnes at intel.com>
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaining a
> > + * copy of this software and associated documentation files (the "Software"),
> > + * to deal in the Software without restriction, including without limitation
> > + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> > + * and/or sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be included in
> > + * all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> > + * IN THE SOFTWARE.
> > + */
> > +
> > +#include "igt.h"
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <stdlib.h>
> > +
> > +#include <sys/stat.h>
> > +
> > +#include "intel_dp_compliance.h"
> > +#include <libudev.h>
> > +static struct udev_monitor *uevent_monitor;
> > +static struct udev *udev;
> > +static GIOChannel *udevchannel;
> > +
> > +static gboolean hotplug_event(GIOChannel *source, GIOCondition condition,
> > +			      gpointer data)
> > +{
> > +	struct udev_device *dev;
> > +	dev_t udev_devnum;
> > +	struct stat s;
> > +	const char *hotplug;
> > +
> > +	dev = udev_monitor_receive_device(uevent_monitor);
> > +	if (!dev)
> > +		goto out;
> > +
> > +	udev_devnum = udev_device_get_devnum(dev);
> > +	fstat(drm_fd, &s);
> > +
> > +	hotplug = udev_device_get_property_value(dev, "HOTPLUG");
> > +
> > +	if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
> > +	    hotplug && atoi(hotplug) == 1)
> > +		update_display(0, false);
> > +
> > +	udev_device_unref(dev);
> > +out:
> > +	return TRUE;
> > +}
> > +
> > +
> > +gboolean intel_dp_compliance_setup_hotplug(void)
> > +{
> > +	int ret;
> > +
> > +	udev = udev_new();
> > +	if (!udev) {
> > +		igt_warn("failed to create udev object\n");
> > +		goto out;
> > +	}
> > +
> > +	uevent_monitor = udev_monitor_new_from_netlink(udev, "udev");
> > +	if (!uevent_monitor) {
> > +		igt_warn("failed to create udev event monitor\n");
> > +		goto out;
> > +	}
> > +
> > +	ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor,
> > +							      "drm",
> > +							      "drm_minor");
> > +	if (ret < 0) {
> > +		igt_warn("failed to filter for drm events\n");
> > +		goto out;
> > +	}
> > +
> > +	ret = udev_monitor_enable_receiving(uevent_monitor);
> > +	if (ret < 0) {
> > +		igt_warn("failed to enable udev event reception\n");
> > +		goto out;
> > +	}
> > +
> > +	udevchannel =
> > +		g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor));
> > +	if (!udevchannel) {
> > +		igt_warn("failed to create udev GIO channel\n");
> > +		goto out;
> > +	}
> > +
> > +	ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event,
> > +			     udev);
> > +	if (ret < 0) {
> > +		igt_warn("failed to add watch on udev GIO channel\n");
> > +		goto out;
> > +	}
> > +
> > +	return TRUE;
> > +
> > +out:
> > +	intel_dp_compliance_cleanup_hotplug();
> > +	return FALSE;
> > +}
> > +
> > +void intel_dp_compliance_cleanup_hotplug(void)
> > +{
> > +	if (udevchannel)
> > +		g_io_channel_shutdown(udevchannel, TRUE, NULL);
> > +	if (uevent_monitor)
> > +		udev_monitor_unref(uevent_monitor);
> > +	if (udev)
> > +		udev_unref(udev);
> > +}
> 
> -- 
> Jani Nikula, Intel Open Source Technology Center


More information about the Intel-gfx mailing list