modetest.c revision b317c96361f88a0a4ccb2faeff09b0476d142c68
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 <stdio.h> 44#include <stdlib.h> 45#include <stdint.h> 46#include <unistd.h> 47#include <string.h> 48#include <errno.h> 49#include <sys/poll.h> 50#include <sys/time.h> 51 52#include "xf86drm.h" 53#include "xf86drmMode.h" 54#include "libkms.h" 55 56#ifdef HAVE_CAIRO 57#include <math.h> 58#include <cairo.h> 59#endif 60 61drmModeRes *resources; 62int fd, modes; 63 64#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 65 66struct type_name { 67 int type; 68 char *name; 69}; 70 71#define type_name_fn(res) \ 72char * res##_str(int type) { \ 73 int i; \ 74 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 75 if (res##_names[i].type == type) \ 76 return res##_names[i].name; \ 77 } \ 78 return "(invalid)"; \ 79} 80 81struct type_name encoder_type_names[] = { 82 { DRM_MODE_ENCODER_NONE, "none" }, 83 { DRM_MODE_ENCODER_DAC, "DAC" }, 84 { DRM_MODE_ENCODER_TMDS, "TMDS" }, 85 { DRM_MODE_ENCODER_LVDS, "LVDS" }, 86 { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, 87}; 88 89type_name_fn(encoder_type) 90 91struct type_name connector_status_names[] = { 92 { DRM_MODE_CONNECTED, "connected" }, 93 { DRM_MODE_DISCONNECTED, "disconnected" }, 94 { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, 95}; 96 97type_name_fn(connector_status) 98 99struct type_name connector_type_names[] = { 100 { DRM_MODE_CONNECTOR_Unknown, "unknown" }, 101 { DRM_MODE_CONNECTOR_VGA, "VGA" }, 102 { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 103 { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 104 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 105 { DRM_MODE_CONNECTOR_Composite, "composite" }, 106 { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, 107 { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 108 { DRM_MODE_CONNECTOR_Component, "component" }, 109 { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, 110 { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, 111 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 112 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 113 { DRM_MODE_CONNECTOR_TV, "TV" }, 114 { DRM_MODE_CONNECTOR_eDP, "embedded displayport" }, 115}; 116 117type_name_fn(connector_type) 118 119void dump_encoders(void) 120{ 121 drmModeEncoder *encoder; 122 int i; 123 124 printf("Encoders:\n"); 125 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 126 for (i = 0; i < resources->count_encoders; i++) { 127 encoder = drmModeGetEncoder(fd, resources->encoders[i]); 128 129 if (!encoder) { 130 fprintf(stderr, "could not get encoder %i: %s\n", 131 resources->encoders[i], strerror(errno)); 132 continue; 133 } 134 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 135 encoder->encoder_id, 136 encoder->crtc_id, 137 encoder_type_str(encoder->encoder_type), 138 encoder->possible_crtcs, 139 encoder->possible_clones); 140 drmModeFreeEncoder(encoder); 141 } 142 printf("\n"); 143} 144 145void dump_mode(drmModeModeInfo *mode) 146{ 147 printf(" %s %d %d %d %d %d %d %d %d %d\n", 148 mode->name, 149 mode->vrefresh, 150 mode->hdisplay, 151 mode->hsync_start, 152 mode->hsync_end, 153 mode->htotal, 154 mode->vdisplay, 155 mode->vsync_start, 156 mode->vsync_end, 157 mode->vtotal); 158} 159 160static void 161dump_props(drmModeConnector *connector) 162{ 163 drmModePropertyPtr props; 164 int i; 165 166 for (i = 0; i < connector->count_props; i++) { 167 props = drmModeGetProperty(fd, connector->props[i]); 168 printf("\t%s, flags %d\n", props->name, props->flags); 169 drmModeFreeProperty(props); 170 } 171} 172 173void dump_connectors(void) 174{ 175 drmModeConnector *connector; 176 int i, j; 177 178 printf("Connectors:\n"); 179 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); 180 for (i = 0; i < resources->count_connectors; i++) { 181 connector = drmModeGetConnector(fd, resources->connectors[i]); 182 183 if (!connector) { 184 fprintf(stderr, "could not get connector %i: %s\n", 185 resources->connectors[i], strerror(errno)); 186 continue; 187 } 188 189 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", 190 connector->connector_id, 191 connector->encoder_id, 192 connector_status_str(connector->connection), 193 connector_type_str(connector->connector_type), 194 connector->mmWidth, connector->mmHeight, 195 connector->count_modes); 196 197 for (j = 0; j < connector->count_encoders; j++) 198 printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 199 printf("\n"); 200 201 if (!connector->count_modes) 202 continue; 203 204 printf(" modes:\n"); 205 printf(" name refresh (Hz) hdisp hss hse htot vdisp " 206 "vss vse vtot)\n"); 207 for (j = 0; j < connector->count_modes; j++) 208 dump_mode(&connector->modes[j]); 209 210 printf(" props:\n"); 211 dump_props(connector); 212 213 drmModeFreeConnector(connector); 214 } 215 printf("\n"); 216} 217 218void dump_crtcs(void) 219{ 220 drmModeCrtc *crtc; 221 int i; 222 223 printf("CRTCs:\n"); 224 printf("id\tfb\tpos\tsize\n"); 225 for (i = 0; i < resources->count_crtcs; i++) { 226 crtc = drmModeGetCrtc(fd, resources->crtcs[i]); 227 228 if (!crtc) { 229 fprintf(stderr, "could not get crtc %i: %s\n", 230 resources->crtcs[i], strerror(errno)); 231 continue; 232 } 233 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 234 crtc->crtc_id, 235 crtc->buffer_id, 236 crtc->x, crtc->y, 237 crtc->width, crtc->height); 238 dump_mode(&crtc->mode); 239 240 drmModeFreeCrtc(crtc); 241 } 242 printf("\n"); 243} 244 245void dump_framebuffers(void) 246{ 247 drmModeFB *fb; 248 int i; 249 250 printf("Frame buffers:\n"); 251 printf("id\tsize\tpitch\n"); 252 for (i = 0; i < resources->count_fbs; i++) { 253 fb = drmModeGetFB(fd, resources->fbs[i]); 254 255 if (!fb) { 256 fprintf(stderr, "could not get fb %i: %s\n", 257 resources->fbs[i], strerror(errno)); 258 continue; 259 } 260 printf("%u\t(%ux%u)\t%u\n", 261 fb->fb_id, 262 fb->width, fb->height, 263 fb->pitch); 264 265 drmModeFreeFB(fb); 266 } 267 printf("\n"); 268} 269 270/* 271 * Mode setting with the kernel interfaces is a bit of a chore. 272 * First you have to find the connector in question and make sure the 273 * requested mode is available. 274 * Then you need to find the encoder attached to that connector so you 275 * can bind it with a free crtc. 276 */ 277struct connector { 278 uint32_t id; 279 char mode_str[64]; 280 drmModeModeInfo *mode; 281 drmModeEncoder *encoder; 282 int crtc; 283 unsigned int fb_id[2], current_fb_id; 284 struct timeval start; 285 286 int swap_count; 287}; 288 289static void 290connector_find_mode(struct connector *c) 291{ 292 drmModeConnector *connector; 293 int i, j; 294 295 /* First, find the connector & mode */ 296 c->mode = NULL; 297 for (i = 0; i < resources->count_connectors; i++) { 298 connector = drmModeGetConnector(fd, resources->connectors[i]); 299 300 if (!connector) { 301 fprintf(stderr, "could not get connector %i: %s\n", 302 resources->connectors[i], strerror(errno)); 303 drmModeFreeConnector(connector); 304 continue; 305 } 306 307 if (!connector->count_modes) { 308 drmModeFreeConnector(connector); 309 continue; 310 } 311 312 if (connector->connector_id != c->id) { 313 drmModeFreeConnector(connector); 314 continue; 315 } 316 317 for (j = 0; j < connector->count_modes; j++) { 318 c->mode = &connector->modes[j]; 319 if (!strcmp(c->mode->name, c->mode_str)) 320 break; 321 } 322 323 /* Found it, break out */ 324 if (c->mode) 325 break; 326 327 drmModeFreeConnector(connector); 328 } 329 330 if (!c->mode) { 331 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 332 return; 333 } 334 335 /* Now get the encoder */ 336 for (i = 0; i < resources->count_encoders; i++) { 337 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 338 339 if (!c->encoder) { 340 fprintf(stderr, "could not get encoder %i: %s\n", 341 resources->encoders[i], strerror(errno)); 342 drmModeFreeEncoder(c->encoder); 343 continue; 344 } 345 346 if (c->encoder->encoder_id == connector->encoder_id) 347 break; 348 349 drmModeFreeEncoder(c->encoder); 350 } 351 352 if (c->crtc == -1) 353 c->crtc = c->encoder->crtc_id; 354} 355 356static struct kms_bo * 357allocate_buffer(struct kms_driver *kms, 358 int width, int height, int *stride) 359{ 360 struct kms_bo *bo; 361 unsigned bo_attribs[] = { 362 KMS_WIDTH, 0, 363 KMS_HEIGHT, 0, 364 KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8, 365 KMS_TERMINATE_PROP_LIST 366 }; 367 int ret; 368 369 bo_attribs[1] = width; 370 bo_attribs[3] = height; 371 372 ret = kms_bo_create(kms, bo_attribs, &bo); 373 if (ret) { 374 fprintf(stderr, "failed to alloc buffer: %s\n", 375 strerror(-ret)); 376 return NULL; 377 } 378 379 ret = kms_bo_get_prop(bo, KMS_PITCH, stride); 380 if (ret) { 381 fprintf(stderr, "failed to retreive buffer stride: %s\n", 382 strerror(-ret)); 383 kms_bo_destroy(&bo); 384 return NULL; 385 } 386 387 return bo; 388} 389 390static void 391make_pwetty(void *data, int width, int height, int stride) 392{ 393#ifdef HAVE_CAIRO 394 cairo_surface_t *surface; 395 cairo_t *cr; 396 int x, y; 397 398 surface = cairo_image_surface_create_for_data(data, 399 CAIRO_FORMAT_ARGB32, 400 width, height, 401 stride); 402 cr = cairo_create(surface); 403 cairo_surface_destroy(surface); 404 405 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); 406 for (x = 0; x < width; x += 250) 407 for (y = 0; y < height; y += 250) { 408 char buf[64]; 409 410 cairo_move_to(cr, x, y - 20); 411 cairo_line_to(cr, x, y + 20); 412 cairo_move_to(cr, x - 20, y); 413 cairo_line_to(cr, x + 20, y); 414 cairo_new_sub_path(cr); 415 cairo_arc(cr, x, y, 10, 0, M_PI * 2); 416 cairo_set_line_width(cr, 4); 417 cairo_set_source_rgb(cr, 0, 0, 0); 418 cairo_stroke_preserve(cr); 419 cairo_set_source_rgb(cr, 1, 1, 1); 420 cairo_set_line_width(cr, 2); 421 cairo_stroke(cr); 422 423 snprintf(buf, sizeof buf, "%d, %d", x, y); 424 cairo_move_to(cr, x + 20, y + 20); 425 cairo_text_path(cr, buf); 426 cairo_set_source_rgb(cr, 0, 0, 0); 427 cairo_stroke_preserve(cr); 428 cairo_set_source_rgb(cr, 1, 1, 1); 429 cairo_fill(cr); 430 } 431 432 cairo_destroy(cr); 433#endif 434} 435 436static int 437create_test_buffer(struct kms_driver *kms, 438 int width, int height, int *stride_out, 439 struct kms_bo **bo_out) 440{ 441 struct kms_bo *bo; 442 int ret, i, j, stride; 443 void *virtual; 444 445 bo = allocate_buffer(kms, width, height, &stride); 446 if (!bo) 447 return -1; 448 449 ret = kms_bo_map(bo, &virtual); 450 if (ret) { 451 fprintf(stderr, "failed to map buffer: %s\n", 452 strerror(-ret)); 453 kms_bo_destroy(&bo); 454 return -1; 455 } 456 457 /* paint the buffer with colored tiles */ 458 for (j = 0; j < height; j++) { 459 uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride); 460 for (i = 0; i < width; i++) { 461 div_t d = div(i, width); 462 fb_ptr[i] = 463 0x00130502 * (d.quot >> 6) + 464 0x000a1120 * (d.rem >> 6); 465 } 466 } 467 468 make_pwetty(virtual, width, height, stride); 469 470 kms_bo_unmap(bo); 471 472 *bo_out = bo; 473 *stride_out = stride; 474 return 0; 475} 476 477static int 478create_grey_buffer(struct kms_driver *kms, 479 int width, int height, int *stride_out, 480 struct kms_bo **bo_out) 481{ 482 struct kms_bo *bo; 483 int size, ret, stride; 484 void *virtual; 485 486 bo = allocate_buffer(kms, width, height, &stride); 487 if (!bo) 488 return -1; 489 490 ret = kms_bo_map(bo, &virtual); 491 if (ret) { 492 fprintf(stderr, "failed to map buffer: %s\n", 493 strerror(-ret)); 494 kms_bo_destroy(&bo); 495 return -1; 496 } 497 498 size = stride * height; 499 memset(virtual, 0x77, size); 500 kms_bo_unmap(bo); 501 502 *bo_out = bo; 503 *stride_out = stride; 504 505 return 0; 506} 507 508void 509page_flip_handler(int fd, unsigned int frame, 510 unsigned int sec, unsigned int usec, void *data) 511{ 512 struct connector *c; 513 unsigned int new_fb_id; 514 struct timeval end; 515 double t; 516 517 c = data; 518 if (c->current_fb_id == c->fb_id[0]) 519 new_fb_id = c->fb_id[1]; 520 else 521 new_fb_id = c->fb_id[0]; 522 523 drmModePageFlip(fd, c->crtc, new_fb_id, 524 DRM_MODE_PAGE_FLIP_EVENT, c); 525 c->current_fb_id = new_fb_id; 526 c->swap_count++; 527 if (c->swap_count == 60) { 528 gettimeofday(&end, NULL); 529 t = end.tv_sec + end.tv_usec * 1e-6 - 530 (c->start.tv_sec + c->start.tv_usec * 1e-6); 531 fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t); 532 c->swap_count = 0; 533 c->start = end; 534 } 535} 536 537static void 538set_mode(struct connector *c, int count, int page_flip) 539{ 540 struct kms_driver *kms; 541 struct kms_bo *bo, *other_bo; 542 unsigned int fb_id, other_fb_id; 543 int i, ret, width, height, x, stride; 544 unsigned handle; 545 drmEventContext evctx; 546 547 width = 0; 548 height = 0; 549 for (i = 0; i < count; i++) { 550 connector_find_mode(&c[i]); 551 if (c[i].mode == NULL) 552 continue; 553 width += c[i].mode->hdisplay; 554 if (height < c[i].mode->vdisplay) 555 height = c[i].mode->vdisplay; 556 } 557 558 ret = kms_create(fd, &kms); 559 if (ret) { 560 fprintf(stderr, "failed to create kms driver: %s\n", 561 strerror(-ret)); 562 return; 563 } 564 565 if (create_test_buffer(kms, width, height, &stride, &bo)) 566 return; 567 568 kms_bo_get_prop(bo, KMS_HANDLE, &handle); 569 ret = drmModeAddFB(fd, width, height, 24, 32, stride, handle, &fb_id); 570 if (ret) { 571 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 572 return; 573 } 574 575 x = 0; 576 for (i = 0; i < count; i++) { 577 if (c[i].mode == NULL) 578 continue; 579 580 printf("setting mode %s on connector %d, crtc %d\n", 581 c[i].mode_str, c[i].id, c[i].crtc); 582 583 ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, 584 &c[i].id, 1, c[i].mode); 585 x += c[i].mode->hdisplay; 586 587 if (ret) { 588 fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 589 return; 590 } 591 } 592 593 if (!page_flip) 594 return; 595 596 if (create_grey_buffer(kms, width, height, &stride, &other_bo)) 597 return; 598 599 kms_bo_get_prop(other_bo, KMS_HANDLE, &handle); 600 ret = drmModeAddFB(fd, width, height, 32, 32, stride, handle, 601 &other_fb_id); 602 if (ret) { 603 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 604 return; 605 } 606 607 for (i = 0; i < count; i++) { 608 if (c[i].mode == NULL) 609 continue; 610 611 drmModePageFlip(fd, c[i].crtc, other_fb_id, 612 DRM_MODE_PAGE_FLIP_EVENT, &c[i]); 613 gettimeofday(&c[i].start, NULL); 614 c[i].swap_count = 0; 615 c[i].fb_id[0] = fb_id; 616 c[i].fb_id[1] = other_fb_id; 617 c[i].current_fb_id = other_fb_id; 618 } 619 620 memset(&evctx, 0, sizeof evctx); 621 evctx.version = DRM_EVENT_CONTEXT_VERSION; 622 evctx.vblank_handler = NULL; 623 evctx.page_flip_handler = page_flip_handler; 624 625 while (1) { 626#if 0 627 struct pollfd pfd[2]; 628 629 pfd[0].fd = 0; 630 pfd[0].events = POLLIN; 631 pfd[1].fd = fd; 632 pfd[1].events = POLLIN; 633 634 if (poll(pfd, 2, -1) < 0) { 635 fprintf(stderr, "poll error\n"); 636 break; 637 } 638 639 if (pfd[0].revents) 640 break; 641#else 642 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 643 fd_set fds; 644 int ret; 645 646 FD_ZERO(&fds); 647 FD_SET(0, &fds); 648 FD_SET(fd, &fds); 649 ret = select(fd + 1, &fds, NULL, NULL, &timeout); 650 651 if (ret <= 0) { 652 fprintf(stderr, "select timed out or error (ret %d)\n", 653 ret); 654 continue; 655 } else if (FD_ISSET(0, &fds)) { 656 break; 657 } 658#endif 659 660 drmHandleEvent(fd, &evctx); 661 } 662 663 kms_bo_destroy(&bo); 664 kms_bo_destroy(&other_bo); 665 kms_destroy(&kms); 666} 667 668extern char *optarg; 669extern int optind, opterr, optopt; 670static char optstr[] = "ecpmfs:v"; 671 672void usage(char *name) 673{ 674 fprintf(stderr, "usage: %s [-ecpmf]\n", name); 675 fprintf(stderr, "\t-e\tlist encoders\n"); 676 fprintf(stderr, "\t-c\tlist connectors\n"); 677 fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); 678 fprintf(stderr, "\t-m\tlist modes\n"); 679 fprintf(stderr, "\t-f\tlist framebuffers\n"); 680 fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 681 fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); 682 fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); 683 fprintf(stderr, "\n\tDefault is to dump all info.\n"); 684 exit(0); 685} 686 687#define dump_resource(res) if (res) dump_##res() 688 689static int page_flipping_supported(int fd) 690{ 691 /*FIXME: generic ioctl needed? */ 692 return 1; 693#if 0 694 int ret, value; 695 struct drm_i915_getparam gp; 696 697 gp.param = I915_PARAM_HAS_PAGEFLIPPING; 698 gp.value = &value; 699 700 ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 701 if (ret) { 702 fprintf(stderr, "drm_i915_getparam: %m\n"); 703 return 0; 704 } 705 706 return *gp.value; 707#endif 708} 709 710int main(int argc, char **argv) 711{ 712 int c; 713 int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; 714 int test_vsync = 0; 715 char *modules[] = { "i915", "radeon", "nouveau" }; 716 char *modeset = NULL; 717 int i, count = 0; 718 struct connector con_args[2]; 719 720 opterr = 0; 721 while ((c = getopt(argc, argv, optstr)) != -1) { 722 switch (c) { 723 case 'e': 724 encoders = 1; 725 break; 726 case 'c': 727 connectors = 1; 728 break; 729 case 'p': 730 crtcs = 1; 731 break; 732 case 'm': 733 modes = 1; 734 break; 735 case 'f': 736 framebuffers = 1; 737 break; 738 case 'v': 739 test_vsync = 1; 740 break; 741 case 's': 742 modeset = strdup(optarg); 743 con_args[count].crtc = -1; 744 if (sscanf(optarg, "%d:%64s", 745 &con_args[count].id, 746 con_args[count].mode_str) != 2 && 747 sscanf(optarg, "%d@%d:%64s", 748 &con_args[count].id, 749 &con_args[count].crtc, 750 con_args[count].mode_str) != 3) 751 usage(argv[0]); 752 count++; 753 break; 754 default: 755 usage(argv[0]); 756 break; 757 } 758 } 759 760 if (argc == 1) 761 encoders = connectors = crtcs = modes = framebuffers = 1; 762 763 for (i = 0; i < ARRAY_SIZE(modules); i++) { 764 printf("trying to load module %s...", modules[i]); 765 fd = drmOpen(modules[i], NULL); 766 if (fd < 0) { 767 printf("failed.\n"); 768 } else { 769 printf("success.\n"); 770 break; 771 } 772 } 773 774 if (test_vsync && !page_flipping_supported(fd)) { 775 fprintf(stderr, "page flipping not supported by drm.\n"); 776 return -1; 777 } 778 779 if (i == ARRAY_SIZE(modules)) { 780 fprintf(stderr, "failed to load any modules, aborting.\n"); 781 return -1; 782 } 783 784 resources = drmModeGetResources(fd); 785 if (!resources) { 786 fprintf(stderr, "drmModeGetResources failed: %s\n", 787 strerror(errno)); 788 drmClose(fd); 789 return 1; 790 } 791 792 dump_resource(encoders); 793 dump_resource(connectors); 794 dump_resource(crtcs); 795 dump_resource(framebuffers); 796 797 if (count > 0) { 798 set_mode(con_args, count, test_vsync); 799 getchar(); 800 } 801 802 drmModeFreeResources(resources); 803 804 return 0; 805} 806