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