1/*
2 * Copyright © 2014 NVIDIA Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <stdio.h>
29#include <string.h>
30#include <unistd.h>
31
32#include "util/common.h"
33#include "libkms-test.h"
34
35static const char *const connector_names[] = {
36	"Unknown",
37	"VGA",
38	"DVI-I",
39	"DVI-D",
40	"DVI-A",
41	"Composite",
42	"SVIDEO",
43	"LVDS",
44	"Component",
45	"9PinDIN",
46	"DisplayPort",
47	"HDMI-A",
48	"HDMI-B",
49	"TV",
50	"eDP",
51	"Virtual",
52	"DSI",
53};
54
55static void kms_device_probe_screens(struct kms_device *device)
56{
57	unsigned int counts[ARRAY_SIZE(connector_names)];
58	struct kms_screen *screen;
59	drmModeRes *res;
60	int i;
61
62	memset(counts, 0, sizeof(counts));
63
64	res = drmModeGetResources(device->fd);
65	if (!res)
66		return;
67
68	device->screens = calloc(res->count_connectors, sizeof(screen));
69	if (!device->screens)
70		return;
71
72	for (i = 0; i < res->count_connectors; i++) {
73		unsigned int *count;
74		const char *type;
75		int len;
76
77		screen = kms_screen_create(device, res->connectors[i]);
78		if (!screen)
79			continue;
80
81		/* assign a unique name to this screen */
82		type = connector_names[screen->type];
83		count = &counts[screen->type];
84
85		len = snprintf(NULL, 0, "%s-%u", type, *count);
86
87		screen->name = malloc(len + 1);
88		if (!screen->name) {
89			free(screen);
90			continue;
91		}
92
93		snprintf(screen->name, len + 1, "%s-%u", type, *count);
94		(*count)++;
95
96		device->screens[i] = screen;
97		device->num_screens++;
98	}
99
100	drmModeFreeResources(res);
101}
102
103static void kms_device_probe_crtcs(struct kms_device *device)
104{
105	struct kms_crtc *crtc;
106	drmModeRes *res;
107	int i;
108
109	res = drmModeGetResources(device->fd);
110	if (!res)
111		return;
112
113	device->crtcs = calloc(res->count_crtcs, sizeof(crtc));
114	if (!device->crtcs)
115		return;
116
117	for (i = 0; i < res->count_crtcs; i++) {
118		crtc = kms_crtc_create(device, res->crtcs[i]);
119		if (!crtc)
120			continue;
121
122		device->crtcs[i] = crtc;
123		device->num_crtcs++;
124	}
125
126	drmModeFreeResources(res);
127}
128
129static void kms_device_probe_planes(struct kms_device *device)
130{
131	struct kms_plane *plane;
132	drmModePlaneRes *res;
133	unsigned int i;
134
135	res = drmModeGetPlaneResources(device->fd);
136	if (!res)
137		return;
138
139	device->planes = calloc(res->count_planes, sizeof(plane));
140	if (!device->planes)
141		return;
142
143	for (i = 0; i < res->count_planes; i++) {
144		plane = kms_plane_create(device, res->planes[i]);
145		if (!plane)
146			continue;
147
148		device->planes[i] = plane;
149		device->num_planes++;
150	}
151
152	drmModeFreePlaneResources(res);
153}
154
155static void kms_device_probe(struct kms_device *device)
156{
157	kms_device_probe_screens(device);
158	kms_device_probe_crtcs(device);
159	kms_device_probe_planes(device);
160}
161
162struct kms_device *kms_device_open(int fd)
163{
164	struct kms_device *device;
165
166	device = calloc(1, sizeof(*device));
167	if (!device)
168		return NULL;
169
170	device->fd = fd;
171
172	kms_device_probe(device);
173
174	return device;
175}
176
177void kms_device_close(struct kms_device *device)
178{
179	unsigned int i;
180
181	for (i = 0; i < device->num_planes; i++)
182		kms_plane_free(device->planes[i]);
183
184	free(device->planes);
185
186	for (i = 0; i < device->num_crtcs; i++)
187		kms_crtc_free(device->crtcs[i]);
188
189	free(device->crtcs);
190
191	for (i = 0; i < device->num_screens; i++)
192		kms_screen_free(device->screens[i]);
193
194	free(device->screens);
195
196	if (device->fd >= 0)
197		close(device->fd);
198
199	free(device);
200}
201
202struct kms_plane *kms_device_find_plane_by_type(struct kms_device *device,
203						uint32_t type,
204						unsigned int index)
205{
206	unsigned int i;
207
208	for (i = 0; i < device->num_planes; i++) {
209		if (device->planes[i]->type == type) {
210			if (index == 0)
211				return device->planes[i];
212
213			index--;
214		}
215	}
216
217	return NULL;
218}
219