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