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

Jani Nikula jani.nikula at linux.intel.com
Wed Nov 23 13:59:52 UTC 2016


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




> +
> +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