13f012e29Smrg/*
23f012e29Smrg * Copyright 2008 Tungsten Graphics
33f012e29Smrg *   Jakob Bornecrantz <jakob@tungstengraphics.com>
43f012e29Smrg * Copyright 2008 Intel Corporation
53f012e29Smrg *   Jesse Barnes <jesse.barnes@intel.com>
63f012e29Smrg *
73f012e29Smrg * Permission is hereby granted, free of charge, to any person obtaining a
83f012e29Smrg * copy of this software and associated documentation files (the "Software"),
93f012e29Smrg * to deal in the Software without restriction, including without limitation
103f012e29Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
113f012e29Smrg * and/or sell copies of the Software, and to permit persons to whom the
123f012e29Smrg * Software is furnished to do so, subject to the following conditions:
133f012e29Smrg *
143f012e29Smrg * The above copyright notice and this permission notice shall be included in
153f012e29Smrg * all copies or substantial portions of the Software.
163f012e29Smrg *
173f012e29Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
183f012e29Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
193f012e29Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
203f012e29Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
213f012e29Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
223f012e29Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
233f012e29Smrg * IN THE SOFTWARE.
243f012e29Smrg */
253f012e29Smrg
263f012e29Smrg/*
273f012e29Smrg * This fairly simple test program dumps output in a similar format to the
283f012e29Smrg * "xrandr" tool everyone knows & loves.  It's necessarily slightly different
293f012e29Smrg * since the kernel separates outputs into encoder and connector structures,
303f012e29Smrg * each with their own unique ID.  The program also allows test testing of the
313f012e29Smrg * memory management and mode setting APIs by allowing the user to specify a
323f012e29Smrg * connector and mode to use for mode setting.  If all works as expected, a
333f012e29Smrg * blue background should be painted on the monitor attached to the specified
343f012e29Smrg * connector after the selected mode is set.
353f012e29Smrg *
363f012e29Smrg * TODO: use cairo to write the mode info on the selected output once
373f012e29Smrg *       the mode has been programmed, along with possible test patterns.
383f012e29Smrg */
393f012e29Smrg
403f012e29Smrg#include <errno.h>
413f012e29Smrg#include <stdint.h>
423f012e29Smrg#include <stdio.h>
433f012e29Smrg#include <stdlib.h>
443f012e29Smrg#include <string.h>
456acbc0e0Smrg#include <fcntl.h>
466acbc0e0Smrg#include <unistd.h>
473f012e29Smrg
483f012e29Smrg#include "xf86drm.h"
493f012e29Smrg#include "xf86drmMode.h"
503f012e29Smrg
513f012e29Smrg#include "common.h"
523f012e29Smrg
533f012e29Smrgstruct type_name {
543f012e29Smrg	unsigned int type;
553f012e29Smrg	const char *name;
563f012e29Smrg};
573f012e29Smrg
583f012e29Smrgstatic const char *util_lookup_type_name(unsigned int type,
593f012e29Smrg					 const struct type_name *table,
603f012e29Smrg					 unsigned int count)
613f012e29Smrg{
623f012e29Smrg	unsigned int i;
633f012e29Smrg
643f012e29Smrg	for (i = 0; i < count; i++)
653f012e29Smrg		if (table[i].type == type)
663f012e29Smrg			return table[i].name;
673f012e29Smrg
683f012e29Smrg	return NULL;
693f012e29Smrg}
703f012e29Smrg
713f012e29Smrgstatic const struct type_name encoder_type_names[] = {
723f012e29Smrg	{ DRM_MODE_ENCODER_NONE, "none" },
733f012e29Smrg	{ DRM_MODE_ENCODER_DAC, "DAC" },
743f012e29Smrg	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
753f012e29Smrg	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
763f012e29Smrg	{ DRM_MODE_ENCODER_TVDAC, "TVDAC" },
773f012e29Smrg	{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
783f012e29Smrg	{ DRM_MODE_ENCODER_DSI, "DSI" },
793f012e29Smrg	{ DRM_MODE_ENCODER_DPMST, "DPMST" },
80d8807b2fSmrg	{ DRM_MODE_ENCODER_DPI, "DPI" },
813f012e29Smrg};
823f012e29Smrg
833f012e29Smrgconst char *util_lookup_encoder_type_name(unsigned int type)
843f012e29Smrg{
853f012e29Smrg	return util_lookup_type_name(type, encoder_type_names,
863f012e29Smrg				     ARRAY_SIZE(encoder_type_names));
873f012e29Smrg}
883f012e29Smrg
893f012e29Smrgstatic const struct type_name connector_status_names[] = {
903f012e29Smrg	{ DRM_MODE_CONNECTED, "connected" },
913f012e29Smrg	{ DRM_MODE_DISCONNECTED, "disconnected" },
923f012e29Smrg	{ DRM_MODE_UNKNOWNCONNECTION, "unknown" },
933f012e29Smrg};
943f012e29Smrg
953f012e29Smrgconst char *util_lookup_connector_status_name(unsigned int status)
963f012e29Smrg{
973f012e29Smrg	return util_lookup_type_name(status, connector_status_names,
983f012e29Smrg				     ARRAY_SIZE(connector_status_names));
993f012e29Smrg}
1003f012e29Smrg
1013f012e29Smrgint util_open(const char *device, const char *module)
1023f012e29Smrg{
1036acbc0e0Smrg	int fd = -1;
1046acbc0e0Smrg	drmVersionPtr version;
1053f012e29Smrg
1066acbc0e0Smrg	if (module || device) {
1073f012e29Smrg		fd = drmOpen(module, device);
1083f012e29Smrg		if (fd < 0) {
1096acbc0e0Smrg			fprintf(stderr, "failed to open device '%s' with busid '%s': %s\n",
1106acbc0e0Smrg				module, device, strerror(errno));
1113f012e29Smrg			return -errno;
1123f012e29Smrg		}
1133f012e29Smrg	} else {
1143f012e29Smrg		unsigned int i;
1156acbc0e0Smrg		drmDevicePtr devices[64];
1166acbc0e0Smrg		int num_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
1176acbc0e0Smrg		if (num_devices < 0) {
1186acbc0e0Smrg			fprintf(stderr, "drmGetDevices2() failed with %s\n", strerror(num_devices));
1196acbc0e0Smrg			return num_devices;
1206acbc0e0Smrg		}
1213f012e29Smrg
1226acbc0e0Smrg		for (i = 0; i < num_devices; i++) {
1236acbc0e0Smrg			drmDevicePtr device = devices[i];
1246acbc0e0Smrg			// Select only primary nodes
1256acbc0e0Smrg			if ((device->available_nodes & 1 << DRM_NODE_PRIMARY) == 0)
1266acbc0e0Smrg				continue;
1276acbc0e0Smrg
1286acbc0e0Smrg			printf("trying to open device '%s'... ", device->nodes[DRM_NODE_PRIMARY]);
1296acbc0e0Smrg			fd = open(device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC);
1303f012e29Smrg
1313f012e29Smrg			if (fd < 0) {
1323f012e29Smrg				printf("failed\n");
1336acbc0e0Smrg			} else if (!drmIsKMS(fd)) {
1346acbc0e0Smrg				printf("is not a KMS device\n");
1356acbc0e0Smrg				close(fd);
1366acbc0e0Smrg				fd = -1;
1373f012e29Smrg			} else {
1383f012e29Smrg				printf("done\n");
1393f012e29Smrg				break;
1403f012e29Smrg			}
1413f012e29Smrg		}
1423f012e29Smrg
1433f012e29Smrg		if (fd < 0) {
1443f012e29Smrg			fprintf(stderr, "no device found\n");
1453f012e29Smrg			return -ENODEV;
1463f012e29Smrg		}
1473f012e29Smrg	}
1483f012e29Smrg
1496acbc0e0Smrg	version = drmGetVersion(fd);
1506acbc0e0Smrg	printf("opened device `%s` on driver `%s` (version %d.%d.%d at %s)\n",
1516acbc0e0Smrg	       version->desc,
1526acbc0e0Smrg	       version->name,
1536acbc0e0Smrg	       version->version_major,
1546acbc0e0Smrg	       version->version_minor,
1556acbc0e0Smrg	       version->version_patchlevel,
1566acbc0e0Smrg	       version->date);
1576acbc0e0Smrg	drmFreeVersion(version);
1586acbc0e0Smrg
1593f012e29Smrg	return fd;
1603f012e29Smrg}
161