modetest.c revision 7d13a5d0
1/* 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> 7 * 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: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 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 24 * IN THE SOFTWARE. 25 */ 26 27/* 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. 36 * 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. 39 */ 40#include "config.h" 41 42#include <assert.h> 43#include <ctype.h> 44#include <stdbool.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <stdint.h> 48#include <inttypes.h> 49#include <unistd.h> 50#include <string.h> 51#include <errno.h> 52#include <sys/poll.h> 53#include <sys/time.h> 54 55#include "xf86drm.h" 56#include "xf86drmMode.h" 57#include "drm_fourcc.h" 58#include "libkms.h" 59 60#include "buffers.h" 61 62struct crtc { 63 drmModeCrtc *crtc; 64 drmModeObjectProperties *props; 65 drmModePropertyRes **props_info; 66 drmModeModeInfo *mode; 67}; 68 69struct encoder { 70 drmModeEncoder *encoder; 71}; 72 73struct connector { 74 drmModeConnector *connector; 75 drmModeObjectProperties *props; 76 drmModePropertyRes **props_info; 77}; 78 79struct fb { 80 drmModeFB *fb; 81}; 82 83struct plane { 84 drmModePlane *plane; 85 drmModeObjectProperties *props; 86 drmModePropertyRes **props_info; 87}; 88 89struct resources { 90 drmModeRes *res; 91 drmModePlaneRes *plane_res; 92 93 struct crtc *crtcs; 94 struct encoder *encoders; 95 struct connector *connectors; 96 struct fb *fbs; 97 struct plane *planes; 98}; 99 100struct device { 101 int fd; 102 103 struct resources *resources; 104 struct kms_driver *kms; 105 106 struct { 107 unsigned int width; 108 unsigned int height; 109 110 unsigned int fb_id; 111 struct kms_bo *bo; 112 } mode; 113}; 114 115#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 116 117struct type_name { 118 int type; 119 const char *name; 120}; 121 122#define type_name_fn(res) \ 123const char * res##_str(int type) { \ 124 unsigned int i; \ 125 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 126 if (res##_names[i].type == type) \ 127 return res##_names[i].name; \ 128 } \ 129 return "(invalid)"; \ 130} 131 132struct type_name encoder_type_names[] = { 133 { DRM_MODE_ENCODER_NONE, "none" }, 134 { DRM_MODE_ENCODER_DAC, "DAC" }, 135 { DRM_MODE_ENCODER_TMDS, "TMDS" }, 136 { DRM_MODE_ENCODER_LVDS, "LVDS" }, 137 { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, 138}; 139 140static type_name_fn(encoder_type) 141 142struct type_name connector_status_names[] = { 143 { DRM_MODE_CONNECTED, "connected" }, 144 { DRM_MODE_DISCONNECTED, "disconnected" }, 145 { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, 146}; 147 148static type_name_fn(connector_status) 149 150struct type_name connector_type_names[] = { 151 { DRM_MODE_CONNECTOR_Unknown, "unknown" }, 152 { DRM_MODE_CONNECTOR_VGA, "VGA" }, 153 { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 154 { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 155 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 156 { DRM_MODE_CONNECTOR_Composite, "composite" }, 157 { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, 158 { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 159 { DRM_MODE_CONNECTOR_Component, "component" }, 160 { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, 161 { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 162 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 163 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 164 { DRM_MODE_CONNECTOR_TV, "TV" }, 165 { DRM_MODE_CONNECTOR_eDP, "eDP" }, 166}; 167 168static type_name_fn(connector_type) 169 170#define bit_name_fn(res) \ 171const char * res##_str(int type) { \ 172 unsigned int i; \ 173 const char *sep = ""; \ 174 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 175 if (type & (1 << i)) { \ 176 printf("%s%s", sep, res##_names[i]); \ 177 sep = ", "; \ 178 } \ 179 } \ 180 return NULL; \ 181} 182 183static const char *mode_type_names[] = { 184 "builtin", 185 "clock_c", 186 "crtc_c", 187 "preferred", 188 "default", 189 "userdef", 190 "driver", 191}; 192 193static bit_name_fn(mode_type) 194 195static const char *mode_flag_names[] = { 196 "phsync", 197 "nhsync", 198 "pvsync", 199 "nvsync", 200 "interlace", 201 "dblscan", 202 "csync", 203 "pcsync", 204 "ncsync", 205 "hskew", 206 "bcast", 207 "pixmux", 208 "dblclk", 209 "clkdiv2" 210}; 211 212static bit_name_fn(mode_flag) 213 214static void dump_encoders(struct device *dev) 215{ 216 drmModeEncoder *encoder; 217 int i; 218 219 printf("Encoders:\n"); 220 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 221 for (i = 0; i < dev->resources->res->count_encoders; i++) { 222 encoder = dev->resources->encoders[i].encoder; 223 if (!encoder) 224 continue; 225 226 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 227 encoder->encoder_id, 228 encoder->crtc_id, 229 encoder_type_str(encoder->encoder_type), 230 encoder->possible_crtcs, 231 encoder->possible_clones); 232 } 233 printf("\n"); 234} 235 236static void dump_mode(drmModeModeInfo *mode) 237{ 238 printf(" %s %d %d %d %d %d %d %d %d %d", 239 mode->name, 240 mode->vrefresh, 241 mode->hdisplay, 242 mode->hsync_start, 243 mode->hsync_end, 244 mode->htotal, 245 mode->vdisplay, 246 mode->vsync_start, 247 mode->vsync_end, 248 mode->vtotal); 249 250 printf(" flags: "); 251 mode_flag_str(mode->flags); 252 printf("; type: "); 253 mode_type_str(mode->type); 254 printf("\n"); 255} 256 257static void dump_blob(struct device *dev, uint32_t blob_id) 258{ 259 uint32_t i; 260 unsigned char *blob_data; 261 drmModePropertyBlobPtr blob; 262 263 blob = drmModeGetPropertyBlob(dev->fd, blob_id); 264 if (!blob) 265 return; 266 267 blob_data = blob->data; 268 269 for (i = 0; i < blob->length; i++) { 270 if (i % 16 == 0) 271 printf("\n\t\t\t"); 272 printf("%.2hhx", blob_data[i]); 273 } 274 printf("\n"); 275 276 drmModeFreePropertyBlob(blob); 277} 278 279static void dump_prop(struct device *dev, drmModePropertyPtr prop, 280 uint32_t prop_id, uint64_t value) 281{ 282 int i; 283 printf("\t%d", prop_id); 284 if (!prop) { 285 printf("\n"); 286 return; 287 } 288 289 printf(" %s:\n", prop->name); 290 291 printf("\t\tflags:"); 292 if (prop->flags & DRM_MODE_PROP_PENDING) 293 printf(" pending"); 294 if (prop->flags & DRM_MODE_PROP_RANGE) 295 printf(" range"); 296 if (prop->flags & DRM_MODE_PROP_IMMUTABLE) 297 printf(" immutable"); 298 if (prop->flags & DRM_MODE_PROP_ENUM) 299 printf(" enum"); 300 if (prop->flags & DRM_MODE_PROP_BITMASK) 301 printf(" bitmask"); 302 if (prop->flags & DRM_MODE_PROP_BLOB) 303 printf(" blob"); 304 printf("\n"); 305 306 if (prop->flags & DRM_MODE_PROP_RANGE) { 307 printf("\t\tvalues:"); 308 for (i = 0; i < prop->count_values; i++) 309 printf(" %"PRIu64, prop->values[i]); 310 printf("\n"); 311 } 312 313 if (prop->flags & DRM_MODE_PROP_ENUM) { 314 printf("\t\tenums:"); 315 for (i = 0; i < prop->count_enums; i++) 316 printf(" %s=%llu", prop->enums[i].name, 317 prop->enums[i].value); 318 printf("\n"); 319 } else if (prop->flags & DRM_MODE_PROP_BITMASK) { 320 printf("\t\tvalues:"); 321 for (i = 0; i < prop->count_enums; i++) 322 printf(" %s=0x%llx", prop->enums[i].name, 323 (1LL << prop->enums[i].value)); 324 printf("\n"); 325 } else { 326 assert(prop->count_enums == 0); 327 } 328 329 if (prop->flags & DRM_MODE_PROP_BLOB) { 330 printf("\t\tblobs:\n"); 331 for (i = 0; i < prop->count_blobs; i++) 332 dump_blob(dev, prop->blob_ids[i]); 333 printf("\n"); 334 } else { 335 assert(prop->count_blobs == 0); 336 } 337 338 printf("\t\tvalue:"); 339 if (prop->flags & DRM_MODE_PROP_BLOB) 340 dump_blob(dev, value); 341 else 342 printf(" %"PRIu64"\n", value); 343} 344 345static void dump_connectors(struct device *dev) 346{ 347 int i, j; 348 349 printf("Connectors:\n"); 350 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); 351 for (i = 0; i < dev->resources->res->count_connectors; i++) { 352 struct connector *_connector = &dev->resources->connectors[i]; 353 drmModeConnector *connector = _connector->connector; 354 if (!connector) 355 continue; 356 357 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", 358 connector->connector_id, 359 connector->encoder_id, 360 connector_status_str(connector->connection), 361 connector_type_str(connector->connector_type), 362 connector->mmWidth, connector->mmHeight, 363 connector->count_modes); 364 365 for (j = 0; j < connector->count_encoders; j++) 366 printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 367 printf("\n"); 368 369 if (connector->count_modes) { 370 printf(" modes:\n"); 371 printf("\tname refresh (Hz) hdisp hss hse htot vdisp " 372 "vss vse vtot)\n"); 373 for (j = 0; j < connector->count_modes; j++) 374 dump_mode(&connector->modes[j]); 375 } 376 377 if (_connector->props) { 378 printf(" props:\n"); 379 for (j = 0; j < (int)_connector->props->count_props; j++) 380 dump_prop(dev, _connector->props_info[j], 381 _connector->props->props[j], 382 _connector->props->prop_values[j]); 383 } 384 } 385 printf("\n"); 386} 387 388static void dump_crtcs(struct device *dev) 389{ 390 int i; 391 uint32_t j; 392 393 printf("CRTCs:\n"); 394 printf("id\tfb\tpos\tsize\n"); 395 for (i = 0; i < dev->resources->res->count_crtcs; i++) { 396 struct crtc *_crtc = &dev->resources->crtcs[i]; 397 drmModeCrtc *crtc = _crtc->crtc; 398 if (!crtc) 399 continue; 400 401 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 402 crtc->crtc_id, 403 crtc->buffer_id, 404 crtc->x, crtc->y, 405 crtc->width, crtc->height); 406 dump_mode(&crtc->mode); 407 408 if (_crtc->props) { 409 printf(" props:\n"); 410 for (j = 0; j < _crtc->props->count_props; j++) 411 dump_prop(dev, _crtc->props_info[j], 412 _crtc->props->props[j], 413 _crtc->props->prop_values[j]); 414 } else { 415 printf(" no properties found\n"); 416 } 417 } 418 printf("\n"); 419} 420 421static void dump_framebuffers(struct device *dev) 422{ 423 drmModeFB *fb; 424 int i; 425 426 printf("Frame buffers:\n"); 427 printf("id\tsize\tpitch\n"); 428 for (i = 0; i < dev->resources->res->count_fbs; i++) { 429 fb = dev->resources->fbs[i].fb; 430 if (!fb) 431 continue; 432 433 printf("%u\t(%ux%u)\t%u\n", 434 fb->fb_id, 435 fb->width, fb->height, 436 fb->pitch); 437 } 438 printf("\n"); 439} 440 441static void dump_planes(struct device *dev) 442{ 443 unsigned int i, j; 444 445 printf("Planes:\n"); 446 printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); 447 448 if (!dev->resources->plane_res) 449 return; 450 451 for (i = 0; i < dev->resources->plane_res->count_planes; i++) { 452 struct plane *plane = &dev->resources->planes[i]; 453 drmModePlane *ovr = plane->plane; 454 if (!ovr) 455 continue; 456 457 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n", 458 ovr->plane_id, ovr->crtc_id, ovr->fb_id, 459 ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, 460 ovr->gamma_size, ovr->possible_crtcs); 461 462 if (!ovr->count_formats) 463 continue; 464 465 printf(" formats:"); 466 for (j = 0; j < ovr->count_formats; j++) 467 printf(" %4.4s", (char *)&ovr->formats[j]); 468 printf("\n"); 469 470 if (plane->props) { 471 printf(" props:\n"); 472 for (j = 0; j < plane->props->count_props; j++) 473 dump_prop(dev, plane->props_info[j], 474 plane->props->props[j], 475 plane->props->prop_values[j]); 476 } else { 477 printf(" no properties found\n"); 478 } 479 } 480 printf("\n"); 481 482 return; 483} 484 485static void free_resources(struct resources *res) 486{ 487 if (!res) 488 return; 489 490#define free_resource(_res, __res, type, Type) \ 491 do { \ 492 int i; \ 493 if (!(_res)->type##s) \ 494 break; \ 495 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 496 if (!(_res)->type##s[i].type) \ 497 break; \ 498 drmModeFree##Type((_res)->type##s[i].type); \ 499 } \ 500 free((_res)->type##s); \ 501 } while (0) 502 503#define free_properties(_res, __res, type) \ 504 do { \ 505 int i; \ 506 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 507 drmModeFreeObjectProperties(res->type##s[i].props); \ 508 free(res->type##s[i].props_info); \ 509 } \ 510 } while (0) 511 512 if (res->res) { 513 free_properties(res, res, crtc); 514 515 free_resource(res, res, crtc, Crtc); 516 free_resource(res, res, encoder, Encoder); 517 free_resource(res, res, connector, Connector); 518 free_resource(res, res, fb, FB); 519 520 drmModeFreeResources(res->res); 521 } 522 523 if (res->plane_res) { 524 free_properties(res, plane_res, plane); 525 526 free_resource(res, plane_res, plane, Plane); 527 528 drmModeFreePlaneResources(res->plane_res); 529 } 530 531 free(res); 532} 533 534static struct resources *get_resources(struct device *dev) 535{ 536 struct resources *res; 537 int i; 538 539 res = malloc(sizeof *res); 540 if (res == 0) 541 return NULL; 542 543 memset(res, 0, sizeof *res); 544 545 res->res = drmModeGetResources(dev->fd); 546 if (!res->res) { 547 fprintf(stderr, "drmModeGetResources failed: %s\n", 548 strerror(errno)); 549 goto error; 550 } 551 552 res->crtcs = malloc(res->res->count_crtcs * sizeof *res->crtcs); 553 res->encoders = malloc(res->res->count_encoders * sizeof *res->encoders); 554 res->connectors = malloc(res->res->count_connectors * sizeof *res->connectors); 555 res->fbs = malloc(res->res->count_fbs * sizeof *res->fbs); 556 557 if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) 558 goto error; 559 560 memset(res->crtcs , 0, res->res->count_crtcs * sizeof *res->crtcs); 561 memset(res->encoders, 0, res->res->count_encoders * sizeof *res->encoders); 562 memset(res->connectors, 0, res->res->count_connectors * sizeof *res->connectors); 563 memset(res->fbs, 0, res->res->count_fbs * sizeof *res->fbs); 564 565#define get_resource(_res, __res, type, Type) \ 566 do { \ 567 int i; \ 568 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 569 (_res)->type##s[i].type = \ 570 drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \ 571 if (!(_res)->type##s[i].type) \ 572 fprintf(stderr, "could not get %s %i: %s\n", \ 573 #type, (_res)->__res->type##s[i], \ 574 strerror(errno)); \ 575 } \ 576 } while (0) 577 578 get_resource(res, res, crtc, Crtc); 579 get_resource(res, res, encoder, Encoder); 580 get_resource(res, res, connector, Connector); 581 get_resource(res, res, fb, FB); 582 583#define get_properties(_res, __res, type, Type) \ 584 do { \ 585 int i; \ 586 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 587 struct type *obj = &res->type##s[i]; \ 588 unsigned int j; \ 589 obj->props = \ 590 drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ 591 DRM_MODE_OBJECT_##Type); \ 592 if (!obj->props) { \ 593 fprintf(stderr, \ 594 "could not get %s %i properties: %s\n", \ 595 #type, obj->type->type##_id, \ 596 strerror(errno)); \ 597 continue; \ 598 } \ 599 obj->props_info = malloc(obj->props->count_props * \ 600 sizeof *obj->props_info); \ 601 if (!obj->props_info) \ 602 continue; \ 603 for (j = 0; j < obj->props->count_props; ++j) \ 604 obj->props_info[j] = \ 605 drmModeGetProperty(dev->fd, obj->props->props[j]); \ 606 } \ 607 } while (0) 608 609 get_properties(res, res, crtc, CRTC); 610 get_properties(res, res, connector, CONNECTOR); 611 612 for (i = 0; i < res->res->count_crtcs; ++i) 613 res->crtcs[i].mode = &res->crtcs[i].crtc->mode; 614 615 res->plane_res = drmModeGetPlaneResources(dev->fd); 616 if (!res->plane_res) { 617 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 618 strerror(errno)); 619 return res; 620 } 621 622 res->planes = malloc(res->plane_res->count_planes * sizeof *res->planes); 623 if (!res->planes) 624 goto error; 625 626 memset(res->planes, 0, res->plane_res->count_planes * sizeof *res->planes); 627 628 get_resource(res, plane_res, plane, Plane); 629 get_properties(res, plane_res, plane, PLANE); 630 631 return res; 632 633error: 634 free_resources(res); 635 return NULL; 636} 637 638static int get_crtc_index(struct device *dev, uint32_t id) 639{ 640 int i; 641 642 for (i = 0; i < dev->resources->res->count_crtcs; ++i) { 643 drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; 644 if (crtc && crtc->crtc_id == id) 645 return i; 646 } 647 648 return -1; 649} 650 651static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) 652{ 653 drmModeConnector *connector; 654 int i; 655 656 for (i = 0; i < dev->resources->res->count_connectors; i++) { 657 connector = dev->resources->connectors[i].connector; 658 if (connector && connector->connector_id == id) 659 return connector; 660 } 661 662 return NULL; 663} 664 665static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) 666{ 667 drmModeEncoder *encoder; 668 int i; 669 670 for (i = 0; i < dev->resources->res->count_encoders; i++) { 671 encoder = dev->resources->encoders[i].encoder; 672 if (encoder && encoder->encoder_id == id) 673 return encoder; 674 } 675 676 return NULL; 677} 678 679/* ----------------------------------------------------------------------------- 680 * Pipes and planes 681 */ 682 683/* 684 * Mode setting with the kernel interfaces is a bit of a chore. 685 * First you have to find the connector in question and make sure the 686 * requested mode is available. 687 * Then you need to find the encoder attached to that connector so you 688 * can bind it with a free crtc. 689 */ 690struct pipe_arg { 691 uint32_t *con_ids; 692 unsigned int num_cons; 693 uint32_t crtc_id; 694 char mode_str[64]; 695 char format_str[5]; 696 unsigned int vrefresh; 697 unsigned int fourcc; 698 drmModeModeInfo *mode; 699 struct crtc *crtc; 700 unsigned int fb_id[2], current_fb_id; 701 struct timeval start; 702 703 int swap_count; 704}; 705 706struct plane_arg { 707 uint32_t crtc_id; /* the id of CRTC to bind to */ 708 bool has_position; 709 int32_t x, y; 710 uint32_t w, h; 711 double scale; 712 unsigned int fb_id; 713 char format_str[5]; /* need to leave room for terminating \0 */ 714 unsigned int fourcc; 715}; 716 717static drmModeModeInfo * 718connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, 719 const unsigned int vrefresh) 720{ 721 drmModeConnector *connector; 722 drmModeModeInfo *mode; 723 int i; 724 725 connector = get_connector_by_id(dev, con_id); 726 if (!connector || !connector->count_modes) 727 return NULL; 728 729 for (i = 0; i < connector->count_modes; i++) { 730 mode = &connector->modes[i]; 731 if (!strcmp(mode->name, mode_str)) { 732 /* If the vertical refresh frequency is not specified then return the 733 * first mode that match with the name. Else, return the mode that match 734 * the name and the specified vertical refresh frequency. 735 */ 736 if (vrefresh == 0) 737 return mode; 738 else if (mode->vrefresh == vrefresh) 739 return mode; 740 } 741 } 742 743 return NULL; 744} 745 746static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) 747{ 748 uint32_t possible_crtcs = ~0; 749 uint32_t active_crtcs = 0; 750 unsigned int crtc_idx; 751 unsigned int i; 752 int j; 753 754 for (i = 0; i < pipe->num_cons; ++i) { 755 uint32_t crtcs_for_connector = 0; 756 drmModeConnector *connector; 757 drmModeEncoder *encoder; 758 int idx; 759 760 connector = get_connector_by_id(dev, pipe->con_ids[i]); 761 if (!connector) 762 return NULL; 763 764 for (j = 0; j < connector->count_encoders; ++j) { 765 encoder = get_encoder_by_id(dev, connector->encoders[j]); 766 if (!encoder) 767 continue; 768 769 crtcs_for_connector |= encoder->possible_crtcs; 770 771 idx = get_crtc_index(dev, encoder->crtc_id); 772 if (idx >= 0) 773 active_crtcs |= 1 << idx; 774 } 775 776 possible_crtcs &= crtcs_for_connector; 777 } 778 779 if (!possible_crtcs) 780 return NULL; 781 782 /* Return the first possible and active CRTC if one exists, or the first 783 * possible CRTC otherwise. 784 */ 785 if (possible_crtcs & active_crtcs) 786 crtc_idx = ffs(possible_crtcs & active_crtcs); 787 else 788 crtc_idx = ffs(possible_crtcs); 789 790 return &dev->resources->crtcs[crtc_idx - 1]; 791} 792 793static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) 794{ 795 drmModeModeInfo *mode = NULL; 796 int i; 797 798 pipe->mode = NULL; 799 800 for (i = 0; i < (int)pipe->num_cons; i++) { 801 mode = connector_find_mode(dev, pipe->con_ids[i], 802 pipe->mode_str, pipe->vrefresh); 803 if (mode == NULL) { 804 fprintf(stderr, 805 "failed to find mode \"%s\" for connector %u\n", 806 pipe->mode_str, pipe->con_ids[i]); 807 return -EINVAL; 808 } 809 } 810 811 /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise 812 * locate a CRTC that can be attached to all the connectors. 813 */ 814 if (pipe->crtc_id != (uint32_t)-1) { 815 for (i = 0; i < dev->resources->res->count_crtcs; i++) { 816 struct crtc *crtc = &dev->resources->crtcs[i]; 817 818 if (pipe->crtc_id == crtc->crtc->crtc_id) { 819 pipe->crtc = crtc; 820 break; 821 } 822 } 823 } else { 824 pipe->crtc = pipe_find_crtc(dev, pipe); 825 } 826 827 if (!pipe->crtc) { 828 fprintf(stderr, "failed to find CRTC for pipe\n"); 829 return -EINVAL; 830 } 831 832 pipe->mode = mode; 833 pipe->crtc->mode = mode; 834 835 return 0; 836} 837 838/* ----------------------------------------------------------------------------- 839 * Properties 840 */ 841 842struct property_arg { 843 uint32_t obj_id; 844 uint32_t obj_type; 845 char name[DRM_PROP_NAME_LEN+1]; 846 uint32_t prop_id; 847 uint64_t value; 848}; 849 850static void set_property(struct device *dev, struct property_arg *p) 851{ 852 drmModeObjectProperties *props = NULL; 853 drmModePropertyRes **props_info = NULL; 854 const char *obj_type; 855 int ret; 856 int i; 857 858 p->obj_type = 0; 859 p->prop_id = 0; 860 861#define find_object(_res, __res, type, Type) \ 862 do { \ 863 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 864 struct type *obj = &(_res)->type##s[i]; \ 865 if (obj->type->type##_id != p->obj_id) \ 866 continue; \ 867 p->obj_type = DRM_MODE_OBJECT_##Type; \ 868 obj_type = #Type; \ 869 props = obj->props; \ 870 props_info = obj->props_info; \ 871 } \ 872 } while(0) \ 873 874 find_object(dev->resources, res, crtc, CRTC); 875 if (p->obj_type == 0) 876 find_object(dev->resources, res, connector, CONNECTOR); 877 if (p->obj_type == 0) 878 find_object(dev->resources, plane_res, plane, PLANE); 879 if (p->obj_type == 0) { 880 fprintf(stderr, "Object %i not found, can't set property\n", 881 p->obj_id); 882 return; 883 } 884 885 if (!props) { 886 fprintf(stderr, "%s %i has no properties\n", 887 obj_type, p->obj_id); 888 return; 889 } 890 891 for (i = 0; i < (int)props->count_props; ++i) { 892 if (!props_info[i]) 893 continue; 894 if (strcmp(props_info[i]->name, p->name) == 0) 895 break; 896 } 897 898 if (i == (int)props->count_props) { 899 fprintf(stderr, "%s %i has no %s property\n", 900 obj_type, p->obj_id, p->name); 901 return; 902 } 903 904 p->prop_id = props->props[i]; 905 906 ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, 907 p->prop_id, p->value); 908 if (ret < 0) 909 fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", 910 obj_type, p->obj_id, p->name, p->value, strerror(errno)); 911} 912 913/* -------------------------------------------------------------------------- */ 914 915static void 916page_flip_handler(int fd, unsigned int frame, 917 unsigned int sec, unsigned int usec, void *data) 918{ 919 struct pipe_arg *pipe; 920 unsigned int new_fb_id; 921 struct timeval end; 922 double t; 923 924 pipe = data; 925 if (pipe->current_fb_id == pipe->fb_id[0]) 926 new_fb_id = pipe->fb_id[1]; 927 else 928 new_fb_id = pipe->fb_id[0]; 929 930 drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id, 931 DRM_MODE_PAGE_FLIP_EVENT, pipe); 932 pipe->current_fb_id = new_fb_id; 933 pipe->swap_count++; 934 if (pipe->swap_count == 60) { 935 gettimeofday(&end, NULL); 936 t = end.tv_sec + end.tv_usec * 1e-6 - 937 (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); 938 fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); 939 pipe->swap_count = 0; 940 pipe->start = end; 941 } 942} 943 944static int set_plane(struct device *dev, struct plane_arg *p) 945{ 946 drmModePlane *ovr; 947 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 948 uint32_t plane_id = 0; 949 struct kms_bo *plane_bo; 950 uint32_t plane_flags = 0; 951 int crtc_x, crtc_y, crtc_w, crtc_h; 952 struct crtc *crtc = NULL; 953 unsigned int pipe; 954 unsigned int i; 955 956 /* Find an unused plane which can be connected to our CRTC. Find the 957 * CRTC index first, then iterate over available planes. 958 */ 959 for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) { 960 if (p->crtc_id == dev->resources->res->crtcs[i]) { 961 crtc = &dev->resources->crtcs[i]; 962 pipe = i; 963 break; 964 } 965 } 966 967 if (!crtc) { 968 fprintf(stderr, "CRTC %u not found\n", p->crtc_id); 969 return -1; 970 } 971 972 for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) { 973 ovr = dev->resources->planes[i].plane; 974 if (!ovr) 975 continue; 976 977 if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id) 978 plane_id = ovr->plane_id; 979 } 980 981 if (!plane_id) { 982 fprintf(stderr, "no unused plane available for CRTC %u\n", 983 crtc->crtc->crtc_id); 984 return -1; 985 } 986 987 fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", 988 p->w, p->h, p->format_str, plane_id); 989 990 plane_bo = create_test_buffer(dev->kms, p->fourcc, p->w, p->h, handles, 991 pitches, offsets, PATTERN_TILES); 992 if (plane_bo == NULL) 993 return -1; 994 995 /* just use single plane format for now.. */ 996 if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc, 997 handles, pitches, offsets, &p->fb_id, plane_flags)) { 998 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 999 return -1; 1000 } 1001 1002 crtc_w = p->w * p->scale; 1003 crtc_h = p->h * p->scale; 1004 if (!p->has_position) { 1005 /* Default to the middle of the screen */ 1006 crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; 1007 crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; 1008 } else { 1009 crtc_x = p->x; 1010 crtc_y = p->y; 1011 } 1012 1013 /* note src coords (last 4 args) are in Q16 format */ 1014 if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id, 1015 plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, 1016 0, 0, p->w << 16, p->h << 16)) { 1017 fprintf(stderr, "failed to enable plane: %s\n", 1018 strerror(errno)); 1019 return -1; 1020 } 1021 1022 ovr->crtc_id = crtc->crtc->crtc_id; 1023 1024 return 0; 1025} 1026 1027static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1028{ 1029 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 1030 unsigned int fb_id; 1031 struct kms_bo *bo; 1032 unsigned int i; 1033 unsigned int j; 1034 int ret, x; 1035 1036 dev->mode.width = 0; 1037 dev->mode.height = 0; 1038 1039 for (i = 0; i < count; i++) { 1040 struct pipe_arg *pipe = &pipes[i]; 1041 1042 ret = pipe_find_crtc_and_mode(dev, pipe); 1043 if (ret < 0) 1044 continue; 1045 1046 dev->mode.width += pipe->mode->hdisplay; 1047 if (dev->mode.height < pipe->mode->vdisplay) 1048 dev->mode.height = pipe->mode->vdisplay; 1049 } 1050 1051 bo = create_test_buffer(dev->kms, pipes[0].fourcc, 1052 dev->mode.width, dev->mode.height, 1053 handles, pitches, offsets, PATTERN_SMPTE); 1054 if (bo == NULL) 1055 return; 1056 1057 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, 1058 pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0); 1059 if (ret) { 1060 fprintf(stderr, "failed to add fb (%ux%u): %s\n", 1061 dev->mode.width, dev->mode.height, strerror(errno)); 1062 return; 1063 } 1064 1065 x = 0; 1066 for (i = 0; i < count; i++) { 1067 struct pipe_arg *pipe = &pipes[i]; 1068 1069 if (pipe->mode == NULL) 1070 continue; 1071 1072 printf("setting mode %s-%dHz@%s on connectors ", 1073 pipe->mode_str, pipe->mode->vrefresh, pipe->format_str); 1074 for (j = 0; j < pipe->num_cons; ++j) 1075 printf("%u, ", pipe->con_ids[j]); 1076 printf("crtc %d\n", pipe->crtc->crtc->crtc_id); 1077 1078 ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id, 1079 x, 0, pipe->con_ids, pipe->num_cons, 1080 pipe->mode); 1081 1082 /* XXX: Actually check if this is needed */ 1083 drmModeDirtyFB(dev->fd, fb_id, NULL, 0); 1084 1085 x += pipe->mode->hdisplay; 1086 1087 if (ret) { 1088 fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 1089 return; 1090 } 1091 } 1092 1093 dev->mode.bo = bo; 1094 dev->mode.fb_id = fb_id; 1095} 1096 1097static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1098{ 1099 unsigned int i; 1100 1101 /* set up planes/overlays */ 1102 for (i = 0; i < count; i++) 1103 if (set_plane(dev, &p[i])) 1104 return; 1105} 1106 1107static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1108{ 1109 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 1110 unsigned int other_fb_id; 1111 struct kms_bo *other_bo; 1112 drmEventContext evctx; 1113 unsigned int i; 1114 int ret; 1115 1116 other_bo = create_test_buffer(dev->kms, pipes[0].fourcc, 1117 dev->mode.width, dev->mode.height, 1118 handles, pitches, offsets, PATTERN_PLAIN); 1119 if (other_bo == NULL) 1120 return; 1121 1122 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, 1123 pipes[0].fourcc, handles, pitches, offsets, 1124 &other_fb_id, 0); 1125 if (ret) { 1126 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 1127 return; 1128 } 1129 1130 for (i = 0; i < count; i++) { 1131 struct pipe_arg *pipe = &pipes[i]; 1132 1133 if (pipe->mode == NULL) 1134 continue; 1135 1136 ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id, 1137 other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, 1138 pipe); 1139 if (ret) { 1140 fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); 1141 return; 1142 } 1143 gettimeofday(&pipe->start, NULL); 1144 pipe->swap_count = 0; 1145 pipe->fb_id[0] = dev->mode.fb_id; 1146 pipe->fb_id[1] = other_fb_id; 1147 pipe->current_fb_id = other_fb_id; 1148 } 1149 1150 memset(&evctx, 0, sizeof evctx); 1151 evctx.version = DRM_EVENT_CONTEXT_VERSION; 1152 evctx.vblank_handler = NULL; 1153 evctx.page_flip_handler = page_flip_handler; 1154 1155 while (1) { 1156#if 0 1157 struct pollfd pfd[2]; 1158 1159 pfd[0].fd = 0; 1160 pfd[0].events = POLLIN; 1161 pfd[1].fd = fd; 1162 pfd[1].events = POLLIN; 1163 1164 if (poll(pfd, 2, -1) < 0) { 1165 fprintf(stderr, "poll error\n"); 1166 break; 1167 } 1168 1169 if (pfd[0].revents) 1170 break; 1171#else 1172 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 1173 fd_set fds; 1174 int ret; 1175 1176 FD_ZERO(&fds); 1177 FD_SET(0, &fds); 1178 FD_SET(dev->fd, &fds); 1179 ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); 1180 1181 if (ret <= 0) { 1182 fprintf(stderr, "select timed out or error (ret %d)\n", 1183 ret); 1184 continue; 1185 } else if (FD_ISSET(0, &fds)) { 1186 break; 1187 } 1188#endif 1189 1190 drmHandleEvent(dev->fd, &evctx); 1191 } 1192 1193 kms_bo_destroy(&other_bo); 1194} 1195 1196#define min(a, b) ((a) < (b) ? (a) : (b)) 1197 1198/* XXX local definition of GNUism for expedience */ 1199static char * 1200strchrnul(const char *s, int c) 1201{ 1202 1203 while ((*s != c) && (*s != '\0')) 1204 s++; 1205 1206 return __UNCONST(s); 1207} 1208 1209static int parse_connector(struct pipe_arg *pipe, const char *arg) 1210{ 1211 unsigned int len; 1212 unsigned int i; 1213 const char *p; 1214 char *endp; 1215 1216 pipe->vrefresh = 0; 1217 pipe->crtc_id = (uint32_t)-1; 1218 strcpy(pipe->format_str, "XR24"); 1219 1220 /* Count the number of connectors and allocate them. */ 1221 pipe->num_cons = 1; 1222 for (p = arg; isdigit(*p) || *p == ','; ++p) { 1223 if (*p == ',') 1224 pipe->num_cons++; 1225 } 1226 1227 pipe->con_ids = malloc(pipe->num_cons * sizeof *pipe->con_ids); 1228 if (pipe->con_ids == NULL) 1229 return -1; 1230 1231 /* Parse the connectors. */ 1232 for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { 1233 pipe->con_ids[i] = strtoul(p, &endp, 10); 1234 if (*endp != ',') 1235 break; 1236 } 1237 1238 if (i != pipe->num_cons - 1) 1239 return -1; 1240 1241 /* Parse the remaining parameters. */ 1242 if (*endp == '@') { 1243 arg = endp + 1; 1244 pipe->crtc_id = strtoul(arg, &endp, 10); 1245 } 1246 if (*endp != ':') 1247 return -1; 1248 1249 arg = endp + 1; 1250 1251 /* Search for the vertical refresh or the format. */ 1252 p = strpbrk(arg, "-@"); 1253 if (p == NULL) 1254 p = arg + strlen(arg); 1255 len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); 1256 strncpy(pipe->mode_str, arg, len); 1257 pipe->mode_str[len] = '\0'; 1258 1259 if (*p == '-') { 1260 pipe->vrefresh = strtoul(p + 1, &endp, 10); 1261 p = endp; 1262 } 1263 1264 if (*p == '@') { 1265 strncpy(pipe->format_str, p + 1, 4); 1266 pipe->format_str[4] = '\0'; 1267 } 1268 1269 pipe->fourcc = format_fourcc(pipe->format_str); 1270 if (pipe->fourcc == 0) { 1271 fprintf(stderr, "unknown format %s\n", pipe->format_str); 1272 return -1; 1273 } 1274 1275 return 0; 1276} 1277 1278static int parse_plane(struct plane_arg *plane, const char *p) 1279{ 1280 char *end; 1281 1282 memset(plane, 0, sizeof *plane); 1283 1284 plane->crtc_id = strtoul(p, &end, 10); 1285 if (*end != ':') 1286 return -EINVAL; 1287 1288 p = end + 1; 1289 plane->w = strtoul(p, &end, 10); 1290 if (*end != 'x') 1291 return -EINVAL; 1292 1293 p = end + 1; 1294 plane->h = strtoul(p, &end, 10); 1295 1296 if (*end == '+' || *end == '-') { 1297 plane->x = strtol(end, &end, 10); 1298 if (*end != '+' && *end != '-') 1299 return -EINVAL; 1300 plane->y = strtol(end, &end, 10); 1301 1302 plane->has_position = true; 1303 } 1304 1305 if (*end == '*') { 1306 p = end + 1; 1307 plane->scale = strtod(p, &end); 1308 if (plane->scale <= 0.0) 1309 return -EINVAL; 1310 } else { 1311 plane->scale = 1.0; 1312 } 1313 1314 if (*end == '@') { 1315 p = end + 1; 1316 if (strlen(p) != 4) 1317 return -EINVAL; 1318 1319 strcpy(plane->format_str, p); 1320 } else { 1321 strcpy(plane->format_str, "XR24"); 1322 } 1323 1324 plane->fourcc = format_fourcc(plane->format_str); 1325 if (plane->fourcc == 0) { 1326 fprintf(stderr, "unknown format %s\n", plane->format_str); 1327 return -EINVAL; 1328 } 1329 1330 return 0; 1331} 1332 1333static int parse_property(struct property_arg *p, const char *arg) 1334{ 1335 if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3) 1336 return -1; 1337 1338 p->obj_type = 0; 1339 p->name[DRM_PROP_NAME_LEN] = '\0'; 1340 1341 return 0; 1342} 1343 1344static void usage(char *name) 1345{ 1346 fprintf(stderr, "usage: %s [-cDdefMPpsvw]\n", name); 1347 1348 fprintf(stderr, "\n Query options:\n\n"); 1349 fprintf(stderr, "\t-c\tlist connectors\n"); 1350 fprintf(stderr, "\t-e\tlist encoders\n"); 1351 fprintf(stderr, "\t-f\tlist framebuffers\n"); 1352 fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); 1353 1354 fprintf(stderr, "\n Test options:\n\n"); 1355 fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); 1356 fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n"); 1357 fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 1358 fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); 1359 1360 fprintf(stderr, "\n Generic options:\n\n"); 1361 fprintf(stderr, "\t-d\tdrop master after mode set\n"); 1362 fprintf(stderr, "\t-M module\tuse the given driver\n"); 1363 fprintf(stderr, "\t-D device\tuse the given device\n"); 1364 1365 fprintf(stderr, "\n\tDefault is to dump all info.\n"); 1366 exit(0); 1367} 1368 1369static int page_flipping_supported(void) 1370{ 1371 /*FIXME: generic ioctl needed? */ 1372 return 1; 1373#if 0 1374 int ret, value; 1375 struct drm_i915_getparam gp; 1376 1377 gp.param = I915_PARAM_HAS_PAGEFLIPPING; 1378 gp.value = &value; 1379 1380 ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 1381 if (ret) { 1382 fprintf(stderr, "drm_i915_getparam: %m\n"); 1383 return 0; 1384 } 1385 1386 return *gp.value; 1387#endif 1388} 1389 1390static char optstr[] = "cdD:efM:P:ps:vw:"; 1391 1392int main(int argc, char **argv) 1393{ 1394 struct device dev; 1395 1396 int c; 1397 int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; 1398 int drop_master = 0; 1399 int test_vsync = 0; 1400 const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos", "tilcdc", "msm" }; 1401 char *device = NULL; 1402 char *module = NULL; 1403 unsigned int i; 1404 int count = 0, plane_count = 0; 1405 unsigned int prop_count = 0; 1406 struct pipe_arg *pipe_args = NULL; 1407 struct plane_arg *plane_args = NULL; 1408 struct property_arg *prop_args = NULL; 1409 unsigned int args = 0; 1410 int ret; 1411 1412 memset(&dev, 0, sizeof dev); 1413 1414 opterr = 0; 1415 while ((c = getopt(argc, argv, optstr)) != -1) { 1416 args++; 1417 1418 switch (c) { 1419 case 'c': 1420 connectors = 1; 1421 break; 1422 case 'D': 1423 device = optarg; 1424 args--; 1425 break; 1426 case 'd': 1427 drop_master = 1; 1428 break; 1429 case 'e': 1430 encoders = 1; 1431 break; 1432 case 'f': 1433 framebuffers = 1; 1434 break; 1435 case 'M': 1436 module = optarg; 1437 /* Preserve the default behaviour of dumping all information. */ 1438 args--; 1439 break; 1440 case 'P': 1441 plane_args = realloc(plane_args, 1442 (plane_count + 1) * sizeof *plane_args); 1443 if (plane_args == NULL) { 1444 fprintf(stderr, "memory allocation failed\n"); 1445 return 1; 1446 } 1447 1448 if (parse_plane(&plane_args[plane_count], optarg) < 0) 1449 usage(argv[0]); 1450 1451 plane_count++; 1452 break; 1453 case 'p': 1454 crtcs = 1; 1455 planes = 1; 1456 break; 1457 case 's': 1458 pipe_args = realloc(pipe_args, 1459 (count + 1) * sizeof *pipe_args); 1460 if (pipe_args == NULL) { 1461 fprintf(stderr, "memory allocation failed\n"); 1462 return 1; 1463 } 1464 1465 if (parse_connector(&pipe_args[count], optarg) < 0) 1466 usage(argv[0]); 1467 1468 count++; 1469 break; 1470 case 'v': 1471 test_vsync = 1; 1472 break; 1473 case 'w': 1474 prop_args = realloc(prop_args, 1475 (prop_count + 1) * sizeof *prop_args); 1476 if (prop_args == NULL) { 1477 fprintf(stderr, "memory allocation failed\n"); 1478 return 1; 1479 } 1480 1481 if (parse_property(&prop_args[prop_count], optarg) < 0) 1482 usage(argv[0]); 1483 1484 prop_count++; 1485 break; 1486 default: 1487 usage(argv[0]); 1488 break; 1489 } 1490 } 1491 1492 if (!args) 1493 encoders = connectors = crtcs = planes = framebuffers = 1; 1494 1495 if (module) { 1496 dev.fd = drmOpen(module, device); 1497 if (dev.fd < 0) { 1498 fprintf(stderr, "failed to open device '%s'.\n", module); 1499 return 1; 1500 } 1501 } else { 1502 for (i = 0; i < ARRAY_SIZE(modules); i++) { 1503 printf("trying to open device '%s'...", modules[i]); 1504 dev.fd = drmOpen(modules[i], device); 1505 if (dev.fd < 0) { 1506 printf("failed.\n"); 1507 } else { 1508 printf("success.\n"); 1509 break; 1510 } 1511 } 1512 1513 if (dev.fd < 0) { 1514 fprintf(stderr, "no device found.\n"); 1515 return 1; 1516 } 1517 } 1518 1519 if (test_vsync && !page_flipping_supported()) { 1520 fprintf(stderr, "page flipping not supported by drm.\n"); 1521 return -1; 1522 } 1523 1524 if (test_vsync && !count) { 1525 fprintf(stderr, "page flipping requires at least one -s option.\n"); 1526 return -1; 1527 } 1528 1529 dev.resources = get_resources(&dev); 1530 if (!dev.resources) { 1531 drmClose(dev.fd); 1532 return 1; 1533 } 1534 1535#define dump_resource(dev, res) if (res) dump_##res(dev) 1536 1537 dump_resource(&dev, encoders); 1538 dump_resource(&dev, connectors); 1539 dump_resource(&dev, crtcs); 1540 dump_resource(&dev, planes); 1541 dump_resource(&dev, framebuffers); 1542 1543 for (i = 0; i < prop_count; ++i) 1544 set_property(&dev, &prop_args[i]); 1545 1546 if (count || plane_count) { 1547 ret = kms_create(dev.fd, &dev.kms); 1548 if (ret) { 1549 fprintf(stderr, "failed to create kms driver: %s\n", 1550 strerror(-ret)); 1551 return 1; 1552 } 1553 1554 if (count) 1555 set_mode(&dev, pipe_args, count); 1556 1557 if (plane_count) 1558 set_planes(&dev, plane_args, plane_count); 1559 1560 if (test_vsync) 1561 test_page_flip(&dev, pipe_args, count); 1562 1563 if (drop_master) 1564 drmDropMaster(dev.fd); 1565 1566 kms_bo_destroy(&dev.mode.bo); 1567 kms_destroy(&dev.kms); 1568 1569 getchar(); 1570 } 1571 1572 free_resources(dev.resources); 1573 1574 return 0; 1575} 1576