1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <getopt.h>
7 
8 #include <drm.h>
9 #include <drm_fourcc.h>
10 #include <errno.h>
11 #include <xf86drm.h>
12 #include <xf86drmMode.h>
13 
14 #include "bo.h"
15 #include "dev.h"
16 #include "modeset.h"
17 
show_usage(char * name)18 static void show_usage(char *name)
19 {
20 	printf("Usage: %s [OPTION]\n", name);
21 	printf("   -c, --card      Index of dri card (ie: /dev/dri/cardN)\n");
22 	printf("   -r, --crtc      Index of crtc to use for test\n");
23 	printf("\n\n");
24 }
25 
parse_arguments(int argc,char * argv[],int * card,int * crtc)26 void parse_arguments(int argc, char *argv[], int *card, int *crtc)
27 {
28 	static struct option options[] = {
29 		{ "card", required_argument, NULL, 'c' },
30 		{ "crtc", required_argument, NULL, 'r' },
31 		{ "help", no_argument, NULL, 'h' },
32 	};
33 	int option_index = 0;
34 	int c;
35 
36 	*card = -1;
37 	*crtc = -1;
38 	do {
39 		c = getopt_long(argc, argv, "c:r:h", options, &option_index);
40 		switch (c) {
41 		case 0:
42 		case 'h':
43 			show_usage(argv[0]);
44 			exit(0);
45 		case -1:
46 			break;
47 		case 'c':
48 			if (optarg[0] < '0' || optarg[0] > '9') {
49 				printf("Invalid card value '%s'!\n", optarg);
50 				show_usage(argv[0]);
51 				exit(-1);
52 			}
53 			*card = optarg[0] - '0';
54 			break;
55 		case 'r':
56 			if (optarg[0] < '0' || optarg[0] > '9') {
57 				printf("Invalid crtc value '%s'!\n", optarg);
58 				show_usage(argv[0]);
59 				exit(-1);
60 			}
61 			*crtc = optarg[0] - '0';
62 			break;
63 		}
64 	} while (c != -1);
65 
66 	if (*card < 0 || *crtc < 0) {
67 		show_usage(argv[0]);
68 		exit(-1);
69 	}
70 }
71 
get_prop_id(struct sp_dev * dev,drmModeObjectPropertiesPtr props,const char * name)72 static uint32_t get_prop_id(struct sp_dev *dev,
73 			drmModeObjectPropertiesPtr props, const char *name)
74 {
75 	drmModePropertyPtr p;
76 	uint32_t i, prop_id = 0; /* Property ID should always be > 0 */
77 
78 	for (i = 0; !prop_id && i < props->count_props; i++) {
79 		p = drmModeGetProperty(dev->fd, props->props[i]);
80 		if (!strcmp(p->name, name))
81 			prop_id = p->prop_id;
82 		drmModeFreeProperty(p);
83 	}
84 	if (!prop_id)
85 		printf("Could not find %s property\n", name);
86 	return prop_id;
87 }
88 
get_supported_format(struct sp_plane * plane,uint32_t * format)89 static int get_supported_format(struct sp_plane *plane, uint32_t *format)
90 {
91 	uint32_t i;
92 
93 	for (i = 0; i < plane->plane->count_formats; i++) {
94 		if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 ||
95 		    plane->plane->formats[i] == DRM_FORMAT_ARGB8888 ||
96 		    plane->plane->formats[i] == DRM_FORMAT_RGBA8888) {
97 			*format = plane->plane->formats[i];
98 			return 0;
99 		}
100 	}
101 	printf("No suitable formats found!\n");
102 	return -ENOENT;
103 }
104 
create_sp_dev(int card)105 struct sp_dev *create_sp_dev(int card)
106 {
107 	struct sp_dev *dev;
108 	int ret, fd, i, j;
109 	drmModeRes *r = NULL;
110 	drmModePlaneRes *pr = NULL;
111 	char card_path[256];
112 
113 	snprintf(card_path, sizeof(card_path), "/dev/dri/card%d", card);
114 
115 	fd = open(card_path, O_RDWR);
116 	if (fd < 0) {
117 		printf("failed to open card0\n");
118 		return NULL;
119 	}
120 
121 	dev = calloc(1, sizeof(*dev));
122 	if (!dev) {
123 		printf("failed to allocate dev\n");
124 		return NULL;
125 	}
126 
127 	dev->fd = fd;
128 
129 	ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
130 	if (ret) {
131 		printf("failed to set client cap\n");
132 		goto err;
133 	}
134 
135 	ret = drmSetClientCap(dev->fd, DRM_CLIENT_CAP_ATOMIC, 1);
136 	if (ret) {
137 		printf("Failed to set atomic cap %d", ret);
138 		goto err;
139 	}
140 
141 	r = drmModeGetResources(dev->fd);
142 	if (!r) {
143 		printf("failed to get r\n");
144 		goto err;
145 	}
146 
147 	dev->num_connectors = r->count_connectors;
148 	dev->connectors = calloc(dev->num_connectors,
149 				sizeof(struct sp_connector));
150 	if (!dev->connectors) {
151 		printf("failed to allocate connectors\n");
152 		goto err;
153 	}
154 	for (i = 0; i < dev->num_connectors; i++) {
155 		drmModeObjectPropertiesPtr props;
156 		dev->connectors[i].conn = drmModeGetConnector(dev->fd,
157 					r->connectors[i]);
158 		if (!dev->connectors[i].conn) {
159 			printf("failed to get connector %d\n", i);
160 			goto err;
161 		}
162 
163 		props = drmModeObjectGetProperties(dev->fd, r->connectors[i],
164 				DRM_MODE_OBJECT_CONNECTOR);
165 		if (!props) {
166 			printf("failed to get connector properties\n");
167 			goto err;
168 		}
169 
170 		dev->connectors[i].crtc_id_pid = get_prop_id(dev, props,
171 								"CRTC_ID");
172 		drmModeFreeObjectProperties(props);
173 		if (!dev->connectors[i].crtc_id_pid)
174 			goto err;
175 	}
176 
177 	dev->num_encoders = r->count_encoders;
178 	dev->encoders = calloc(dev->num_encoders, sizeof(*dev->encoders));
179 	if (!dev->encoders) {
180 		printf("failed to allocate encoders\n");
181 		goto err;
182 	}
183 	for (i = 0; i < dev->num_encoders; i++) {
184 		dev->encoders[i] = drmModeGetEncoder(dev->fd, r->encoders[i]);
185 		if (!dev->encoders[i]) {
186 			printf("failed to get encoder %d\n", i);
187 			goto err;
188 		}
189 	}
190 
191 	dev->num_crtcs = r->count_crtcs;
192 	dev->crtcs = calloc(dev->num_crtcs, sizeof(struct sp_crtc));
193 	if (!dev->crtcs) {
194 		printf("failed to allocate crtcs\n");
195 		goto err;
196 	}
197 	for (i = 0; i < dev->num_crtcs; i++) {
198 		drmModeObjectPropertiesPtr props;
199 
200 		dev->crtcs[i].crtc = drmModeGetCrtc(dev->fd, r->crtcs[i]);
201 		if (!dev->crtcs[i].crtc) {
202 			printf("failed to get crtc %d\n", i);
203 			goto err;
204 		}
205 		dev->crtcs[i].pipe = i;
206 		dev->crtcs[i].num_planes = 0;
207 
208 		props = drmModeObjectGetProperties(dev->fd, r->crtcs[i],
209 				DRM_MODE_OBJECT_CRTC);
210 		if (!props) {
211 			printf("failed to get crtc properties\n");
212 			goto err;
213 		}
214 
215 		dev->crtcs[i].mode_pid = get_prop_id(dev, props, "MODE_ID");
216 		dev->crtcs[i].active_pid = get_prop_id(dev, props, "ACTIVE");
217 		drmModeFreeObjectProperties(props);
218 		if (!dev->crtcs[i].mode_pid || !dev->crtcs[i].active_pid)
219 			goto err;
220 	}
221 
222 	pr = drmModeGetPlaneResources(dev->fd);
223 	if (!pr) {
224 		printf("failed to get plane resources\n");
225 		goto err;
226 	}
227 	dev->num_planes = pr->count_planes;
228 	dev->planes = calloc(dev->num_planes, sizeof(struct sp_plane));
229 	for(i = 0; i < dev->num_planes; i++) {
230 		drmModeObjectPropertiesPtr props;
231 		struct sp_plane *plane = &dev->planes[i];
232 
233 		plane->dev = dev;
234 		plane->plane = drmModeGetPlane(dev->fd, pr->planes[i]);
235 		if (!plane->plane) {
236 			printf("failed to get plane %d\n", i);
237 			goto err;
238 		}
239 		plane->bo = NULL;
240 		plane->in_use = 0;
241 
242 		ret = get_supported_format(plane, &plane->format);
243 		if (ret) {
244 			printf("failed to get supported format: %d\n", ret);
245 			goto err;
246 		}
247 
248 		for (j = 0; j < dev->num_crtcs; j++) {
249 			if (plane->plane->possible_crtcs & (1 << j))
250 				dev->crtcs[j].num_planes++;
251 		}
252 
253 		props = drmModeObjectGetProperties(dev->fd, pr->planes[i],
254 				DRM_MODE_OBJECT_PLANE);
255 		if (!props) {
256 			printf("failed to get plane properties\n");
257 			goto err;
258 		}
259 		plane->crtc_pid = get_prop_id(dev, props, "CRTC_ID");
260 		if (!plane->crtc_pid) {
261 			drmModeFreeObjectProperties(props);
262 			goto err;
263 		}
264 		plane->fb_pid = get_prop_id(dev, props, "FB_ID");
265 		if (!plane->fb_pid) {
266 			drmModeFreeObjectProperties(props);
267 			goto err;
268 		}
269 		plane->crtc_x_pid = get_prop_id(dev, props, "CRTC_X");
270 		if (!plane->crtc_x_pid) {
271 			drmModeFreeObjectProperties(props);
272 			goto err;
273 		}
274 		plane->crtc_y_pid = get_prop_id(dev, props, "CRTC_Y");
275 		if (!plane->crtc_y_pid) {
276 			drmModeFreeObjectProperties(props);
277 			goto err;
278 		}
279 		plane->crtc_w_pid = get_prop_id(dev, props, "CRTC_W");
280 		if (!plane->crtc_w_pid) {
281 			drmModeFreeObjectProperties(props);
282 			goto err;
283 		}
284 		plane->crtc_h_pid = get_prop_id(dev, props, "CRTC_H");
285 		if (!plane->crtc_h_pid) {
286 			drmModeFreeObjectProperties(props);
287 			goto err;
288 		}
289 		plane->src_x_pid = get_prop_id(dev, props, "SRC_X");
290 		if (!plane->src_x_pid) {
291 			drmModeFreeObjectProperties(props);
292 			goto err;
293 		}
294 		plane->src_y_pid = get_prop_id(dev, props, "SRC_Y");
295 		if (!plane->src_y_pid) {
296 			drmModeFreeObjectProperties(props);
297 			goto err;
298 		}
299 		plane->src_w_pid = get_prop_id(dev, props, "SRC_W");
300 		if (!plane->src_w_pid) {
301 			drmModeFreeObjectProperties(props);
302 			goto err;
303 		}
304 		plane->src_h_pid = get_prop_id(dev, props, "SRC_H");
305 		if (!plane->src_h_pid) {
306 			drmModeFreeObjectProperties(props);
307 			goto err;
308 		}
309 		drmModeFreeObjectProperties(props);
310 	}
311 
312 	if (pr)
313 		drmModeFreePlaneResources(pr);
314 	if (r)
315 		drmModeFreeResources(r);
316 
317 	return dev;
318 err:
319 	if (pr)
320 		drmModeFreePlaneResources(pr);
321 	if (r)
322 		drmModeFreeResources(r);
323 	destroy_sp_dev(dev);
324 	return NULL;
325 }
326 
destroy_sp_dev(struct sp_dev * dev)327 void destroy_sp_dev(struct sp_dev *dev)
328 {
329 	int i;
330 
331 	if (dev->planes) {
332 		for (i = 0; i< dev->num_planes; i++) {
333 			if (dev->planes[i].in_use)
334 				put_sp_plane(&dev->planes[i]);
335 			if (dev->planes[i].plane)
336 				drmModeFreePlane(dev->planes[i].plane);
337 			if (dev->planes[i].bo)
338 				free_sp_bo(dev->planes[i].bo);
339 		}
340 		free(dev->planes);
341 	}
342 	if (dev->crtcs) {
343 		for (i = 0; i< dev->num_crtcs; i++) {
344 			if (dev->crtcs[i].crtc)
345 				drmModeFreeCrtc(dev->crtcs[i].crtc);
346 		}
347 		free(dev->crtcs);
348 	}
349 	if (dev->encoders) {
350 		for (i = 0; i< dev->num_encoders; i++) {
351 			if (dev->encoders[i])
352 				drmModeFreeEncoder(dev->encoders[i]);
353 		}
354 		free(dev->encoders);
355 	}
356 	if (dev->connectors) {
357 		for (i = 0; i< dev->num_connectors; i++) {
358 			if (dev->connectors[i].conn)
359 				drmModeFreeConnector(dev->connectors[i].conn);
360 		}
361 		free(dev->connectors);
362 	}
363 
364 	close(dev->fd);
365 	free(dev);
366 }
367