2 * DRM based mode setting test program
3 * Copyright 2008 Tungsten Graphics
4 * Jakob Bornecrantz <jakob@tungstengraphics.com>
5 * Copyright 2008 Intel Corporation
6 * Jesse Barnes <jesse.barnes@intel.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * This fairly simple test program dumps output in a similar format to the
29 * "xrandr" tool everyone knows & loves. It's necessarily slightly different
30 * since the kernel separates outputs into encoder and connector structures,
31 * each with their own unique ID. The program also allows test testing of the
32 * memory management and mode setting APIs by allowing the user to specify a
33 * connector and mode to use for mode setting. If all works as expected, a
34 * blue background should be painted on the monitor attached to the specified
35 * connector after the selected mode is set.
37 * TODO: use cairo to write the mode info on the selected output once
38 * the mode has been programmed, along with possible test patterns.
55 #include "xf86drmMode.h"
56 #include "drm_fourcc.h"
63 drmModeObjectProperties *props;
64 drmModePropertyRes **props_info;
68 drmModeEncoder *encoder;
72 drmModeConnector *connector;
73 drmModeObjectProperties *props;
74 drmModePropertyRes **props_info;
83 drmModeObjectProperties *props;
84 drmModePropertyRes **props_info;
89 drmModePlaneRes *plane_res;
92 struct encoder *encoders;
93 struct connector *connectors;
101 struct resources *resources;
102 struct kms_driver *kms;
105 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
112 #define type_name_fn(res) \
113 const char * res##_str(int type) { \
115 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
116 if (res##_names[i].type == type) \
117 return res##_names[i].name; \
119 return "(invalid)"; \
122 struct type_name encoder_type_names[] = {
123 { DRM_MODE_ENCODER_NONE, "none" },
124 { DRM_MODE_ENCODER_DAC, "DAC" },
125 { DRM_MODE_ENCODER_TMDS, "TMDS" },
126 { DRM_MODE_ENCODER_LVDS, "LVDS" },
127 { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
130 static type_name_fn(encoder_type)
132 struct type_name connector_status_names[] = {
133 { DRM_MODE_CONNECTED, "connected" },
134 { DRM_MODE_DISCONNECTED, "disconnected" },
135 { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
138 static type_name_fn(connector_status)
140 struct type_name connector_type_names[] = {
141 { DRM_MODE_CONNECTOR_Unknown, "unknown" },
142 { DRM_MODE_CONNECTOR_VGA, "VGA" },
143 { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
144 { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
145 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
146 { DRM_MODE_CONNECTOR_Composite, "composite" },
147 { DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
148 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
149 { DRM_MODE_CONNECTOR_Component, "component" },
150 { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
151 { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
152 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
153 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
154 { DRM_MODE_CONNECTOR_TV, "TV" },
155 { DRM_MODE_CONNECTOR_eDP, "eDP" },
158 static type_name_fn(connector_type)
160 #define bit_name_fn(res) \
161 const char * res##_str(int type) { \
163 const char *sep = ""; \
164 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
165 if (type & (1 << i)) { \
166 printf("%s%s", sep, res##_names[i]); \
173 static const char *mode_type_names[] = {
183 static bit_name_fn(mode_type)
185 static const char *mode_flag_names[] = {
202 static bit_name_fn(mode_flag)
204 static void dump_encoders(struct device *dev)
206 drmModeEncoder *encoder;
209 printf("Encoders:\n");
210 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
211 for (i = 0; i < dev->resources->res->count_encoders; i++) {
212 encoder = dev->resources->encoders[i].encoder;
216 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
219 encoder_type_str(encoder->encoder_type),
220 encoder->possible_crtcs,
221 encoder->possible_clones);
226 static void dump_mode(drmModeModeInfo *mode)
228 printf(" %s %d %d %d %d %d %d %d %d %d",
241 mode_flag_str(mode->flags);
243 mode_type_str(mode->type);
247 static void dump_blob(struct device *dev, uint32_t blob_id)
250 unsigned char *blob_data;
251 drmModePropertyBlobPtr blob;
253 blob = drmModeGetPropertyBlob(dev->fd, blob_id);
257 blob_data = blob->data;
259 for (i = 0; i < blob->length; i++) {
262 printf("%.2hhx", blob_data[i]);
266 drmModeFreePropertyBlob(blob);
269 static void dump_prop(struct device *dev, drmModePropertyPtr prop,
270 uint32_t prop_id, uint64_t value)
273 printf("\t%d", prop_id);
279 printf(" %s:\n", prop->name);
281 printf("\t\tflags:");
282 if (prop->flags & DRM_MODE_PROP_PENDING)
284 if (prop->flags & DRM_MODE_PROP_RANGE)
286 if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
287 printf(" immutable");
288 if (prop->flags & DRM_MODE_PROP_ENUM)
290 if (prop->flags & DRM_MODE_PROP_BITMASK)
292 if (prop->flags & DRM_MODE_PROP_BLOB)
296 if (prop->flags & DRM_MODE_PROP_RANGE) {
297 printf("\t\tvalues:");
298 for (i = 0; i < prop->count_values; i++)
299 printf(" %"PRIu64, prop->values[i]);
303 if (prop->flags & DRM_MODE_PROP_ENUM) {
304 printf("\t\tenums:");
305 for (i = 0; i < prop->count_enums; i++)
306 printf(" %s=%llu", prop->enums[i].name,
307 prop->enums[i].value);
309 } else if (prop->flags & DRM_MODE_PROP_BITMASK) {
310 printf("\t\tvalues:");
311 for (i = 0; i < prop->count_enums; i++)
312 printf(" %s=0x%llx", prop->enums[i].name,
313 (1LL << prop->enums[i].value));
316 assert(prop->count_enums == 0);
319 if (prop->flags & DRM_MODE_PROP_BLOB) {
320 printf("\t\tblobs:\n");
321 for (i = 0; i < prop->count_blobs; i++)
322 dump_blob(dev, prop->blob_ids[i]);
325 assert(prop->count_blobs == 0);
328 printf("\t\tvalue:");
329 if (prop->flags & DRM_MODE_PROP_BLOB)
330 dump_blob(dev, value);
332 printf(" %"PRIu64"\n", value);
335 static void dump_connectors(struct device *dev)
339 printf("Connectors:\n");
340 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n");
341 for (i = 0; i < dev->resources->res->count_connectors; i++) {
342 struct connector *_connector = &dev->resources->connectors[i];
343 drmModeConnector *connector = _connector->connector;
347 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t",
348 connector->connector_id,
349 connector->encoder_id,
350 connector_status_str(connector->connection),
351 connector_type_str(connector->connector_type),
352 connector->mmWidth, connector->mmHeight,
353 connector->count_modes);
355 for (j = 0; j < connector->count_encoders; j++)
356 printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
359 if (connector->count_modes) {
361 printf("\tname refresh (Hz) hdisp hss hse htot vdisp "
363 for (j = 0; j < connector->count_modes; j++)
364 dump_mode(&connector->modes[j]);
367 if (_connector->props) {
369 for (j = 0; j < (int)_connector->props->count_props; j++)
370 dump_prop(dev, _connector->props_info[j],
371 _connector->props->props[j],
372 _connector->props->prop_values[j]);
378 static void dump_crtcs(struct device *dev)
384 printf("id\tfb\tpos\tsize\n");
385 for (i = 0; i < dev->resources->res->count_crtcs; i++) {
386 struct crtc *_crtc = &dev->resources->crtcs[i];
387 drmModeCrtc *crtc = _crtc->crtc;
391 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
395 crtc->width, crtc->height);
396 dump_mode(&crtc->mode);
400 for (j = 0; j < _crtc->props->count_props; j++)
401 dump_prop(dev, _crtc->props_info[j],
402 _crtc->props->props[j],
403 _crtc->props->prop_values[j]);
405 printf(" no properties found\n");
411 static void dump_framebuffers(struct device *dev)
416 printf("Frame buffers:\n");
417 printf("id\tsize\tpitch\n");
418 for (i = 0; i < dev->resources->res->count_fbs; i++) {
419 fb = dev->resources->fbs[i].fb;
423 printf("%u\t(%ux%u)\t%u\n",
425 fb->width, fb->height,
431 static void dump_planes(struct device *dev)
436 printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
438 if (!dev->resources->plane_res)
441 for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
442 struct plane *plane = &dev->resources->planes[i];
443 drmModePlane *ovr = plane->plane;
447 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n",
448 ovr->plane_id, ovr->crtc_id, ovr->fb_id,
449 ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
450 ovr->gamma_size, ovr->possible_crtcs);
452 if (!ovr->count_formats)
456 for (j = 0; j < ovr->count_formats; j++)
457 printf(" %4.4s", (char *)&ovr->formats[j]);
462 for (j = 0; j < plane->props->count_props; j++)
463 dump_prop(dev, plane->props_info[j],
464 plane->props->props[j],
465 plane->props->prop_values[j]);
467 printf(" no properties found\n");
475 static void free_resources(struct resources *res)
480 #define free_resource(_res, __res, type, Type) \
483 if (!(_res)->type##s) \
485 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
486 if (!(_res)->type##s[i].type) \
488 drmModeFree##Type((_res)->type##s[i].type); \
490 free((_res)->type##s); \
493 #define free_properties(_res, __res, type) \
496 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
497 drmModeFreeObjectProperties(res->type##s[i].props); \
498 free(res->type##s[i].props_info); \
503 free_properties(res, res, crtc);
505 free_resource(res, res, crtc, Crtc);
506 free_resource(res, res, encoder, Encoder);
507 free_resource(res, res, connector, Connector);
508 free_resource(res, res, fb, FB);
510 drmModeFreeResources(res->res);
513 if (res->plane_res) {
514 free_properties(res, plane_res, plane);
516 free_resource(res, plane_res, plane, Plane);
518 drmModeFreePlaneResources(res->plane_res);
524 static struct resources *get_resources(struct device *dev)
526 struct resources *res;
528 res = malloc(sizeof *res);
532 memset(res, 0, sizeof *res);
534 res->res = drmModeGetResources(dev->fd);
536 fprintf(stderr, "drmModeGetResources failed: %s\n",
541 res->crtcs = malloc(res->res->count_crtcs * sizeof *res->crtcs);
542 res->encoders = malloc(res->res->count_encoders * sizeof *res->encoders);
543 res->connectors = malloc(res->res->count_connectors * sizeof *res->connectors);
544 res->fbs = malloc(res->res->count_fbs * sizeof *res->fbs);
546 if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs)
549 memset(res->crtcs , 0, res->res->count_crtcs * sizeof *res->crtcs);
550 memset(res->encoders, 0, res->res->count_encoders * sizeof *res->encoders);
551 memset(res->connectors, 0, res->res->count_connectors * sizeof *res->connectors);
552 memset(res->fbs, 0, res->res->count_fbs * sizeof *res->fbs);
554 #define get_resource(_res, __res, type, Type) \
557 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
558 (_res)->type##s[i].type = \
559 drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \
560 if (!(_res)->type##s[i].type) \
561 fprintf(stderr, "could not get %s %i: %s\n", \
562 #type, (_res)->__res->type##s[i], \
567 get_resource(res, res, crtc, Crtc);
568 get_resource(res, res, encoder, Encoder);
569 get_resource(res, res, connector, Connector);
570 get_resource(res, res, fb, FB);
572 #define get_properties(_res, __res, type, Type) \
575 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
576 struct type *obj = &res->type##s[i]; \
579 drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
580 DRM_MODE_OBJECT_##Type); \
583 "could not get %s %i properties: %s\n", \
584 #type, obj->type->type##_id, \
588 obj->props_info = malloc(obj->props->count_props * \
589 sizeof *obj->props_info); \
590 if (!obj->props_info) \
592 for (j = 0; j < obj->props->count_props; ++j) \
593 obj->props_info[j] = \
594 drmModeGetProperty(dev->fd, obj->props->props[j]); \
598 get_properties(res, res, crtc, CRTC);
599 get_properties(res, res, connector, CONNECTOR);
601 res->plane_res = drmModeGetPlaneResources(dev->fd);
602 if (!res->plane_res) {
603 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
608 res->planes = malloc(res->plane_res->count_planes * sizeof *res->planes);
612 memset(res->planes, 0, res->plane_res->count_planes * sizeof *res->planes);
614 get_resource(res, plane_res, plane, Plane);
615 get_properties(res, plane_res, plane, PLANE);
624 /* -----------------------------------------------------------------------------
625 * Connectors and planes
629 * Mode setting with the kernel interfaces is a bit of a chore.
630 * First you have to find the connector in question and make sure the
631 * requested mode is available.
632 * Then you need to find the encoder attached to that connector so you
633 * can bind it with a free crtc.
635 struct connector_arg {
640 drmModeModeInfo *mode;
641 drmModeEncoder *encoder;
644 unsigned int fb_id[2], current_fb_id;
645 struct timeval start;
651 uint32_t con_id; /* the id of connector to bind to */
656 char format_str[5]; /* need to leave room for terminating \0 */
660 static void connector_find_mode(struct device *dev, struct connector_arg *c)
662 drmModeConnector *connector;
665 /* First, find the connector & mode */
667 for (i = 0; i < dev->resources->res->count_connectors; i++) {
668 connector = dev->resources->connectors[i].connector;
672 if (!connector->count_modes)
675 if (connector->connector_id != c->id)
678 for (j = 0; j < connector->count_modes; j++) {
679 c->mode = &connector->modes[j];
680 if (!strcmp(c->mode->name, c->mode_str))
684 /* Found it, break out */
690 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
694 /* Now get the encoder */
695 for (i = 0; i < dev->resources->res->count_encoders; i++) {
696 c->encoder = dev->resources->encoders[i].encoder;
700 if (c->encoder->encoder_id == connector->encoder_id)
705 c->crtc = c->encoder->crtc_id;
707 /* and figure out which crtc index it is: */
708 for (i = 0; i < dev->resources->res->count_crtcs; i++) {
709 if (c->crtc == (int)dev->resources->res->crtcs[i]) {
717 /* -----------------------------------------------------------------------------
721 struct property_arg {
724 char name[DRM_PROP_NAME_LEN+1];
729 static void set_property(struct device *dev, struct property_arg *p)
731 drmModeObjectProperties *props;
732 drmModePropertyRes **props_info;
733 const char *obj_type;
740 #define find_object(_res, __res, type, Type) \
742 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
743 struct type *obj = &(_res)->type##s[i]; \
744 if (obj->type->type##_id != p->obj_id) \
746 p->obj_type = DRM_MODE_OBJECT_##Type; \
748 props = obj->props; \
749 props_info = obj->props_info; \
753 find_object(dev->resources, res, crtc, CRTC);
754 if (p->obj_type == 0)
755 find_object(dev->resources, res, connector, CONNECTOR);
756 if (p->obj_type == 0)
757 find_object(dev->resources, plane_res, plane, PLANE);
758 if (p->obj_type == 0) {
759 fprintf(stderr, "Object %i not found, can't set property\n",
765 fprintf(stderr, "%s %i has no properties\n",
766 obj_type, p->obj_id);
770 for (i = 0; i < (int)props->count_props; ++i) {
773 if (strcmp(props_info[i]->name, p->name) == 0)
777 if (i == (int)props->count_props) {
778 fprintf(stderr, "%s %i has no %s property\n",
779 obj_type, p->obj_id, p->name);
783 p->prop_id = props->props[i];
785 ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
786 p->prop_id, p->value);
788 fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
789 obj_type, p->obj_id, p->name, p->value, strerror(errno));
792 /* -------------------------------------------------------------------------- */
795 page_flip_handler(int fd, unsigned int frame,
796 unsigned int sec, unsigned int usec, void *data)
798 struct connector_arg *c;
799 unsigned int new_fb_id;
804 if (c->current_fb_id == c->fb_id[0])
805 new_fb_id = c->fb_id[1];
807 new_fb_id = c->fb_id[0];
809 drmModePageFlip(fd, c->crtc, new_fb_id,
810 DRM_MODE_PAGE_FLIP_EVENT, c);
811 c->current_fb_id = new_fb_id;
813 if (c->swap_count == 60) {
814 gettimeofday(&end, NULL);
815 t = end.tv_sec + end.tv_usec * 1e-6 -
816 (c->start.tv_sec + c->start.tv_usec * 1e-6);
817 fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t);
824 set_plane(struct device *dev, struct connector_arg *c, struct plane_arg *p)
827 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
828 uint32_t plane_id = 0;
829 struct kms_bo *plane_bo;
830 uint32_t plane_flags = 0;
831 int crtc_x, crtc_y, crtc_w, crtc_h;
834 /* find an unused plane which can be connected to our crtc */
835 for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) {
836 ovr = dev->resources->planes[i].plane;
840 if ((ovr->possible_crtcs & (1 << c->pipe)) && !ovr->crtc_id)
841 plane_id = ovr->plane_id;
845 fprintf(stderr, "no unused plane available for CRTC %u\n", c->crtc);
849 fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
850 p->w, p->h, p->format_str, plane_id);
852 plane_bo = create_test_buffer(dev->kms, p->fourcc, p->w, p->h, handles,
853 pitches, offsets, PATTERN_TILES);
854 if (plane_bo == NULL)
857 /* just use single plane format for now.. */
858 if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
859 handles, pitches, offsets, &p->fb_id, plane_flags)) {
860 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
864 if (!p->has_position) {
865 /* Default to the middle of the screen */
866 crtc_x = (c->mode->hdisplay - p->w) / 2;
867 crtc_y = (c->mode->vdisplay - p->h) / 2;
875 /* note src coords (last 4 args) are in Q16 format */
876 if (drmModeSetPlane(dev->fd, plane_id, c->crtc, p->fb_id,
877 plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
878 0, 0, p->w << 16, p->h << 16)) {
879 fprintf(stderr, "failed to enable plane: %s\n",
884 ovr->crtc_id = c->crtc;
889 static void set_mode(struct device *dev, struct connector_arg *c, int count,
890 struct plane_arg *p, int plane_count, int page_flip)
892 struct kms_bo *bo, *other_bo;
893 unsigned int fb_id, other_fb_id;
894 int i, j, ret, width, height, x;
895 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
896 drmEventContext evctx;
900 for (i = 0; i < count; i++) {
901 connector_find_mode(dev, &c[i]);
902 if (c[i].mode == NULL)
904 width += c[i].mode->hdisplay;
905 if (height < c[i].mode->vdisplay)
906 height = c[i].mode->vdisplay;
909 bo = create_test_buffer(dev->kms, c->fourcc, width, height, handles,
910 pitches, offsets, PATTERN_SMPTE);
914 ret = drmModeAddFB2(dev->fd, width, height, c->fourcc,
915 handles, pitches, offsets, &fb_id, 0);
917 fprintf(stderr, "failed to add fb (%ux%u): %s\n",
918 width, height, strerror(errno));
923 for (i = 0; i < count; i++) {
924 if (c[i].mode == NULL)
927 printf("setting mode %s@%s on connector %d, crtc %d\n",
928 c[i].mode_str, c[i].format_str, c[i].id, c[i].crtc);
930 ret = drmModeSetCrtc(dev->fd, c[i].crtc, fb_id, x, 0,
931 &c[i].id, 1, c[i].mode);
933 /* XXX: Actually check if this is needed */
934 drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
936 x += c[i].mode->hdisplay;
939 fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
943 /* if we have a plane/overlay to show, set that up now: */
944 for (j = 0; j < plane_count; j++)
945 if (p[j].con_id == c[i].id)
946 if (set_plane(dev, &c[i], &p[j]))
953 other_bo = create_test_buffer(dev->kms, c->fourcc, width, height, handles,
954 pitches, offsets, PATTERN_PLAIN);
955 if (other_bo == NULL)
958 ret = drmModeAddFB2(dev->fd, width, height, c->fourcc, handles, pitches, offsets,
961 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
965 for (i = 0; i < count; i++) {
966 if (c[i].mode == NULL)
969 ret = drmModePageFlip(dev->fd, c[i].crtc, other_fb_id,
970 DRM_MODE_PAGE_FLIP_EVENT, &c[i]);
972 fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
975 gettimeofday(&c[i].start, NULL);
977 c[i].fb_id[0] = fb_id;
978 c[i].fb_id[1] = other_fb_id;
979 c[i].current_fb_id = other_fb_id;
982 memset(&evctx, 0, sizeof evctx);
983 evctx.version = DRM_EVENT_CONTEXT_VERSION;
984 evctx.vblank_handler = NULL;
985 evctx.page_flip_handler = page_flip_handler;
989 struct pollfd pfd[2];
992 pfd[0].events = POLLIN;
994 pfd[1].events = POLLIN;
996 if (poll(pfd, 2, -1) < 0) {
997 fprintf(stderr, "poll error\n");
1004 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
1010 FD_SET(dev->fd, &fds);
1011 ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout);
1014 fprintf(stderr, "select timed out or error (ret %d)\n",
1017 } else if (FD_ISSET(0, &fds)) {
1022 drmHandleEvent(dev->fd, &evctx);
1025 kms_bo_destroy(&bo);
1026 kms_bo_destroy(&other_bo);
1029 #define min(a, b) ((a) < (b) ? (a) : (b))
1031 static int parse_connector(struct connector_arg *c, const char *arg)
1038 strcpy(c->format_str, "XR24");
1040 c->id = strtoul(arg, &endp, 10);
1043 c->crtc = strtoul(arg, &endp, 10);
1050 p = strchrnul(arg, '@');
1051 len = min(sizeof c->mode_str - 1, (unsigned int)(p - arg));
1052 strncpy(c->mode_str, arg, len);
1053 c->mode_str[len] = '\0';
1056 strncpy(c->format_str, p + 1, 4);
1057 c->format_str[4] = '\0';
1060 c->fourcc = format_fourcc(c->format_str);
1061 if (c->fourcc == 0) {
1062 fprintf(stderr, "unknown format %s\n", c->format_str);
1069 static int parse_plane(struct plane_arg *plane, const char *p)
1073 memset(plane, 0, sizeof *plane);
1075 plane->con_id = strtoul(p, &end, 10);
1080 plane->w = strtoul(p, &end, 10);
1085 plane->h = strtoul(p, &end, 10);
1087 if (*end == '+' || *end == '-') {
1088 plane->x = strtol(end, &end, 10);
1089 if (*end != '+' && *end != '-')
1091 plane->y = strtol(end, &end, 10);
1093 plane->has_position = true;
1101 strcpy(plane->format_str, p);
1103 strcpy(plane->format_str, "XR24");
1106 plane->fourcc = format_fourcc(plane->format_str);
1107 if (plane->fourcc == 0) {
1108 fprintf(stderr, "unknown format %s\n", plane->format_str);
1115 static int parse_property(struct property_arg *p, const char *arg)
1117 if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3)
1121 p->name[DRM_PROP_NAME_LEN] = '\0';
1126 static void usage(char *name)
1128 fprintf(stderr, "usage: %s [-cdefMmPpsvw]\n", name);
1130 fprintf(stderr, "\n Query options:\n\n");
1131 fprintf(stderr, "\t-c\tlist connectors\n");
1132 fprintf(stderr, "\t-e\tlist encoders\n");
1133 fprintf(stderr, "\t-f\tlist framebuffers\n");
1134 fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
1136 fprintf(stderr, "\n Test options:\n\n");
1137 fprintf(stderr, "\t-P <connector_id>:<w>x<h>[+<x>+<y>][@<format>]\tset a plane\n");
1138 fprintf(stderr, "\t-s <connector_id>[@<crtc_id>]:<mode>[@<format>]\tset a mode\n");
1139 fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
1140 fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
1142 fprintf(stderr, "\n Generic options:\n\n");
1143 fprintf(stderr, "\t-d\tdrop master after mode set\n");
1144 fprintf(stderr, "\t-M module\tuse the given driver\n");
1146 fprintf(stderr, "\n\tDefault is to dump all info.\n");
1150 static int page_flipping_supported(void)
1152 /*FIXME: generic ioctl needed? */
1156 struct drm_i915_getparam gp;
1158 gp.param = I915_PARAM_HAS_PAGEFLIPPING;
1161 ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
1163 fprintf(stderr, "drm_i915_getparam: %m\n");
1171 static char optstr[] = "cdefM:P:ps:vw:";
1173 int main(int argc, char **argv)
1178 int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
1179 int drop_master = 0;
1181 const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos", "tilcdc" };
1182 char *module = NULL;
1184 int count = 0, plane_count = 0;
1185 unsigned int prop_count = 0;
1186 struct connector_arg *con_args = NULL;
1187 struct plane_arg *plane_args = NULL;
1188 struct property_arg *prop_args = NULL;
1189 unsigned int args = 0;
1193 while ((c = getopt(argc, argv, optstr)) != -1) {
1211 /* Preserve the default behaviour of dumping all information. */
1215 plane_args = realloc(plane_args,
1216 (plane_count + 1) * sizeof *plane_args);
1217 if (plane_args == NULL) {
1218 fprintf(stderr, "memory allocation failed\n");
1222 if (parse_plane(&plane_args[plane_count], optarg) < 0)
1232 con_args = realloc(con_args,
1233 (count + 1) * sizeof *con_args);
1234 if (con_args == NULL) {
1235 fprintf(stderr, "memory allocation failed\n");
1239 if (parse_connector(&con_args[count], optarg) < 0)
1248 prop_args = realloc(prop_args,
1249 (prop_count + 1) * sizeof *prop_args);
1250 if (prop_args == NULL) {
1251 fprintf(stderr, "memory allocation failed\n");
1255 if (parse_property(&prop_args[prop_count], optarg) < 0)
1267 encoders = connectors = crtcs = planes = framebuffers = 1;
1270 dev.fd = drmOpen(module, NULL);
1272 fprintf(stderr, "failed to open device '%s'.\n", module);
1276 for (i = 0; i < ARRAY_SIZE(modules); i++) {
1277 printf("trying to open device '%s'...", modules[i]);
1278 dev.fd = drmOpen(modules[i], NULL);
1280 printf("failed.\n");
1282 printf("success.\n");
1288 fprintf(stderr, "no device found.\n");
1293 if (test_vsync && !page_flipping_supported()) {
1294 fprintf(stderr, "page flipping not supported by drm.\n");
1298 dev.resources = get_resources(&dev);
1299 if (!dev.resources) {
1304 #define dump_resource(dev, res) if (res) dump_##res(dev)
1306 dump_resource(&dev, encoders);
1307 dump_resource(&dev, connectors);
1308 dump_resource(&dev, crtcs);
1309 dump_resource(&dev, planes);
1310 dump_resource(&dev, framebuffers);
1312 for (i = 0; i < prop_count; ++i)
1313 set_property(&dev, &prop_args[i]);
1316 ret = kms_create(dev.fd, &dev.kms);
1318 fprintf(stderr, "failed to create kms driver: %s\n",
1323 set_mode(&dev, con_args, count, plane_args, plane_count, test_vsync);
1325 drmDropMaster(dev.fd);
1327 kms_destroy(&dev.kms);
1331 free_resources(dev.resources);