xf86Crtc.c revision 1b5d61b8
1/* 2 * Copyright © 2006 Keith Packard 3 * Copyright © 2008 Red Hat, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting documentation, and 9 * that the name of the copyright holders not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. The copyright holders make no representations 12 * about the suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 * OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_XORG_CONFIG_H 25#include <xorg-config.h> 26#endif 27 28#include <stddef.h> 29#include <string.h> 30#include <stdio.h> 31 32#include "xf86.h" 33#include "xf86DDC.h" 34#include "xf86Crtc.h" 35#include "xf86Modes.h" 36#include "xf86Priv.h" 37#include "xf86RandR12.h" 38#include "X11/extensions/render.h" 39#include "X11/extensions/dpmsconst.h" 40#include "X11/Xatom.h" 41#include "picturestr.h" 42 43#ifdef XV 44#include "xf86xv.h" 45#endif 46 47#define NO_OUTPUT_DEFAULT_WIDTH 1024 48#define NO_OUTPUT_DEFAULT_HEIGHT 768 49/* 50 * Initialize xf86CrtcConfig structure 51 */ 52 53int xf86CrtcConfigPrivateIndex = -1; 54 55void 56xf86CrtcConfigInit(ScrnInfoPtr scrn, const xf86CrtcConfigFuncsRec * funcs) 57{ 58 xf86CrtcConfigPtr config; 59 60 if (xf86CrtcConfigPrivateIndex == -1) 61 xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); 62 config = xnfcalloc(1, sizeof(xf86CrtcConfigRec)); 63 64 config->funcs = funcs; 65 config->compat_output = -1; 66 67 scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; 68} 69 70void 71xf86CrtcSetSizeRange(ScrnInfoPtr scrn, 72 int minWidth, int minHeight, int maxWidth, int maxHeight) 73{ 74 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 75 76 config->minWidth = minWidth; 77 config->minHeight = minHeight; 78 config->maxWidth = maxWidth; 79 config->maxHeight = maxHeight; 80} 81 82/* 83 * Crtc functions 84 */ 85xf86CrtcPtr 86xf86CrtcCreate(ScrnInfoPtr scrn, const xf86CrtcFuncsRec * funcs) 87{ 88 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 89 xf86CrtcPtr crtc, *crtcs; 90 91 crtc = calloc(sizeof(xf86CrtcRec), 1); 92 if (!crtc) 93 return NULL; 94 crtc->version = XF86_CRTC_VERSION; 95 crtc->scrn = scrn; 96 crtc->funcs = funcs; 97#ifdef RANDR_12_INTERFACE 98 crtc->randr_crtc = NULL; 99#endif 100 crtc->rotation = RR_Rotate_0; 101 crtc->desiredRotation = RR_Rotate_0; 102 pixman_transform_init_identity(&crtc->crtc_to_framebuffer); 103 pixman_f_transform_init_identity(&crtc->f_crtc_to_framebuffer); 104 pixman_f_transform_init_identity(&crtc->f_framebuffer_to_crtc); 105 crtc->filter = NULL; 106 crtc->params = NULL; 107 crtc->nparams = 0; 108 crtc->filter_width = 0; 109 crtc->filter_height = 0; 110 crtc->transform_in_use = FALSE; 111 crtc->transformPresent = FALSE; 112 crtc->desiredTransformPresent = FALSE; 113 memset(&crtc->bounds, '\0', sizeof(crtc->bounds)); 114 115 /* Preallocate gamma at a sensible size. */ 116 crtc->gamma_size = 256; 117 crtc->gamma_red = xallocarray(crtc->gamma_size, 3 * sizeof(CARD16)); 118 if (!crtc->gamma_red) { 119 free(crtc); 120 return NULL; 121 } 122 crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 123 crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 124 125 if (xf86_config->crtc) 126 crtcs = reallocarray(xf86_config->crtc, 127 xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr)); 128 else 129 crtcs = xallocarray(xf86_config->num_crtc + 1, sizeof(xf86CrtcPtr)); 130 if (!crtcs) { 131 free(crtc->gamma_red); 132 free(crtc); 133 return NULL; 134 } 135 xf86_config->crtc = crtcs; 136 xf86_config->crtc[xf86_config->num_crtc++] = crtc; 137 return crtc; 138} 139 140void 141xf86CrtcDestroy(xf86CrtcPtr crtc) 142{ 143 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 144 int c; 145 146 (*crtc->funcs->destroy) (crtc); 147 for (c = 0; c < xf86_config->num_crtc; c++) 148 if (xf86_config->crtc[c] == crtc) { 149 memmove(&xf86_config->crtc[c], 150 &xf86_config->crtc[c + 1], 151 ((xf86_config->num_crtc - (c + 1)) * sizeof(void *))); 152 xf86_config->num_crtc--; 153 break; 154 } 155 free(crtc->params); 156 free(crtc->gamma_red); 157 free(crtc); 158} 159 160/** 161 * Return whether any outputs are connected to the specified pipe 162 */ 163 164Bool 165xf86CrtcInUse(xf86CrtcPtr crtc) 166{ 167 ScrnInfoPtr pScrn = crtc->scrn; 168 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 169 int o; 170 171 for (o = 0; o < xf86_config->num_output; o++) 172 if (xf86_config->output[o]->crtc == crtc) 173 return TRUE; 174 return FALSE; 175} 176 177/** 178 * Return whether the crtc is leased by a client 179 */ 180 181static Bool 182xf86CrtcIsLeased(xf86CrtcPtr crtc) 183{ 184 /* If the DIX structure hasn't been created, it can't have been leased */ 185 if (!crtc->randr_crtc) 186 return FALSE; 187 return RRCrtcIsLeased(crtc->randr_crtc); 188} 189 190/** 191 * Return whether the output is leased by a client 192 */ 193 194static Bool 195xf86OutputIsLeased(xf86OutputPtr output) 196{ 197 /* If the DIX structure hasn't been created, it can't have been leased */ 198 if (!output->randr_output) 199 return FALSE; 200 return RROutputIsLeased(output->randr_output); 201} 202 203void 204xf86CrtcSetScreenSubpixelOrder(ScreenPtr pScreen) 205{ 206 int subpixel_order = SubPixelUnknown; 207 Bool has_none = FALSE; 208 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 209 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 210 int icrtc, o; 211 212 for (icrtc = 0; icrtc < xf86_config->num_crtc; icrtc++) { 213 xf86CrtcPtr crtc = xf86_config->crtc[icrtc]; 214 215 for (o = 0; o < xf86_config->num_output; o++) { 216 xf86OutputPtr output = xf86_config->output[o]; 217 218 if (output->crtc == crtc) { 219 switch (output->subpixel_order) { 220 case SubPixelNone: 221 has_none = TRUE; 222 break; 223 case SubPixelUnknown: 224 break; 225 default: 226 subpixel_order = output->subpixel_order; 227 break; 228 } 229 } 230 if (subpixel_order != SubPixelUnknown) 231 break; 232 } 233 if (subpixel_order != SubPixelUnknown) { 234 static const int circle[4] = { 235 SubPixelHorizontalRGB, 236 SubPixelVerticalRGB, 237 SubPixelHorizontalBGR, 238 SubPixelVerticalBGR, 239 }; 240 int rotate; 241 int sc; 242 243 for (rotate = 0; rotate < 4; rotate++) 244 if (crtc->rotation & (1 << rotate)) 245 break; 246 for (sc = 0; sc < 4; sc++) 247 if (circle[sc] == subpixel_order) 248 break; 249 sc = (sc + rotate) & 0x3; 250 if ((crtc->rotation & RR_Reflect_X) && !(sc & 1)) 251 sc ^= 2; 252 if ((crtc->rotation & RR_Reflect_Y) && (sc & 1)) 253 sc ^= 2; 254 subpixel_order = circle[sc]; 255 break; 256 } 257 } 258 if (subpixel_order == SubPixelUnknown && has_none) 259 subpixel_order = SubPixelNone; 260 PictureSetSubpixelOrder(pScreen, subpixel_order); 261} 262 263/** 264 * Sets the given video mode on the given crtc 265 */ 266Bool 267xf86CrtcSetModeTransform(xf86CrtcPtr crtc, DisplayModePtr mode, 268 Rotation rotation, RRTransformPtr transform, int x, 269 int y) 270{ 271 ScrnInfoPtr scrn = crtc->scrn; 272 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 273 int i; 274 Bool ret = FALSE; 275 Bool didLock = FALSE; 276 DisplayModePtr adjusted_mode; 277 DisplayModeRec saved_mode; 278 int saved_x, saved_y; 279 Rotation saved_rotation; 280 RRTransformRec saved_transform; 281 Bool saved_transform_present; 282 283 crtc->enabled = xf86CrtcInUse(crtc) && !xf86CrtcIsLeased(crtc); 284 285 /* We only hit this if someone explicitly sends a "disabled" modeset. */ 286 if (!crtc->enabled) { 287 /* Check everything for stuff that should be off. */ 288 xf86DisableUnusedFunctions(scrn); 289 return TRUE; 290 } 291 292 adjusted_mode = xf86DuplicateMode(mode); 293 294 saved_mode = crtc->mode; 295 saved_x = crtc->x; 296 saved_y = crtc->y; 297 saved_rotation = crtc->rotation; 298 if (crtc->transformPresent) { 299 RRTransformInit(&saved_transform); 300 RRTransformCopy(&saved_transform, &crtc->transform); 301 } 302 saved_transform_present = crtc->transformPresent; 303 304 /* Update crtc values up front so the driver can rely on them for mode 305 * setting. 306 */ 307 crtc->mode = *mode; 308 crtc->x = x; 309 crtc->y = y; 310 crtc->rotation = rotation; 311 if (transform) { 312 RRTransformCopy(&crtc->transform, transform); 313 crtc->transformPresent = TRUE; 314 } 315 else 316 crtc->transformPresent = FALSE; 317 318 if (crtc->funcs->set_mode_major) { 319 ret = crtc->funcs->set_mode_major(crtc, mode, rotation, x, y); 320 goto done; 321 } 322 323 didLock = crtc->funcs->lock(crtc); 324 /* Pass our mode to the outputs and the CRTC to give them a chance to 325 * adjust it according to limitations or output properties, and also 326 * a chance to reject the mode entirely. 327 */ 328 for (i = 0; i < xf86_config->num_output; i++) { 329 xf86OutputPtr output = xf86_config->output[i]; 330 331 if (output->crtc != crtc) 332 continue; 333 334 if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { 335 goto done; 336 } 337 } 338 339 if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { 340 goto done; 341 } 342 343 if (!xf86CrtcRotate(crtc)) 344 goto done; 345 346 /* Prepare the outputs and CRTCs before setting the mode. */ 347 for (i = 0; i < xf86_config->num_output; i++) { 348 xf86OutputPtr output = xf86_config->output[i]; 349 350 if (output->crtc != crtc) 351 continue; 352 353 /* Disable the output as the first thing we do. */ 354 output->funcs->prepare(output); 355 } 356 357 crtc->funcs->prepare(crtc); 358 359 /* Set up the DPLL and any output state that needs to adjust or depend 360 * on the DPLL. 361 */ 362 crtc->funcs->mode_set(crtc, mode, adjusted_mode, crtc->x, crtc->y); 363 for (i = 0; i < xf86_config->num_output; i++) { 364 xf86OutputPtr output = xf86_config->output[i]; 365 366 if (output->crtc == crtc) 367 output->funcs->mode_set(output, mode, adjusted_mode); 368 } 369 370 /* Only upload when needed, to avoid unneeded delays. */ 371 if (!crtc->active && crtc->funcs->gamma_set) 372 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 373 crtc->gamma_blue, crtc->gamma_size); 374 375 /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ 376 crtc->funcs->commit(crtc); 377 for (i = 0; i < xf86_config->num_output; i++) { 378 xf86OutputPtr output = xf86_config->output[i]; 379 380 if (output->crtc == crtc) 381 output->funcs->commit(output); 382 } 383 384 ret = TRUE; 385 386 done: 387 if (ret) { 388 crtc->active = TRUE; 389 if (scrn->pScreen) 390 xf86CrtcSetScreenSubpixelOrder(scrn->pScreen); 391 if (scrn->ModeSet) 392 scrn->ModeSet(scrn); 393 394 /* Make sure the HW cursor is hidden if it's supposed to be, in case 395 * it was hidden while the CRTC was disabled 396 */ 397 if (!xf86_config->cursor_on) 398 xf86_hide_cursors(scrn); 399 } 400 else { 401 crtc->x = saved_x; 402 crtc->y = saved_y; 403 crtc->rotation = saved_rotation; 404 crtc->mode = saved_mode; 405 if (saved_transform_present) 406 RRTransformCopy(&crtc->transform, &saved_transform); 407 crtc->transformPresent = saved_transform_present; 408 } 409 410 free((void *) adjusted_mode->name); 411 free(adjusted_mode); 412 413 if (didLock) 414 crtc->funcs->unlock(crtc); 415 416 return ret; 417} 418 419/** 420 * Sets the given video mode on the given crtc, but without providing 421 * a transform 422 */ 423Bool 424xf86CrtcSetMode(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, 425 int x, int y) 426{ 427 return xf86CrtcSetModeTransform(crtc, mode, rotation, NULL, x, y); 428} 429 430/** 431 * Pans the screen, does not change the mode 432 */ 433void 434xf86CrtcSetOrigin(xf86CrtcPtr crtc, int x, int y) 435{ 436 ScrnInfoPtr scrn = crtc->scrn; 437 438 crtc->x = x; 439 crtc->y = y; 440 441 if (xf86CrtcIsLeased(crtc)) 442 return; 443 444 if (crtc->funcs->set_origin) { 445 if (!xf86CrtcRotate(crtc)) 446 return; 447 crtc->funcs->set_origin(crtc, x, y); 448 if (scrn->ModeSet) 449 scrn->ModeSet(scrn); 450 } 451 else 452 xf86CrtcSetMode(crtc, &crtc->mode, crtc->rotation, x, y); 453} 454 455/* 456 * Output functions 457 */ 458 459extern XF86ConfigPtr xf86configptr; 460 461typedef enum { 462 OPTION_PREFERRED_MODE, 463 OPTION_ZOOM_MODES, 464 OPTION_POSITION, 465 OPTION_BELOW, 466 OPTION_RIGHT_OF, 467 OPTION_ABOVE, 468 OPTION_LEFT_OF, 469 OPTION_ENABLE, 470 OPTION_DISABLE, 471 OPTION_MIN_CLOCK, 472 OPTION_MAX_CLOCK, 473 OPTION_IGNORE, 474 OPTION_ROTATE, 475 OPTION_PANNING, 476 OPTION_PRIMARY, 477 OPTION_DEFAULT_MODES, 478} OutputOpts; 479 480static OptionInfoRec xf86OutputOptions[] = { 481 {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE}, 482 {OPTION_ZOOM_MODES, "ZoomModes", OPTV_STRING, {0}, FALSE }, 483 {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE}, 484 {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE}, 485 {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE}, 486 {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE}, 487 {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE}, 488 {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE}, 489 {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE}, 490 {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE}, 491 {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE}, 492 {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE}, 493 {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE}, 494 {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE}, 495 {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE}, 496 {OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE}, 497 {-1, NULL, OPTV_NONE, {0}, FALSE}, 498}; 499 500enum { 501 OPTION_MODEDEBUG, 502 OPTION_PREFER_CLONEMODE, 503}; 504 505static OptionInfoRec xf86DeviceOptions[] = { 506 {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE}, 507 {OPTION_PREFER_CLONEMODE, "PreferCloneMode", OPTV_BOOLEAN, {0}, FALSE}, 508 {-1, NULL, OPTV_NONE, {0}, FALSE}, 509}; 510 511static void 512xf86OutputSetMonitor(xf86OutputPtr output) 513{ 514 char *option_name; 515 const char *monitor; 516 517 if (!output->name) 518 return; 519 520 free(output->options); 521 522 output->options = xnfalloc(sizeof(xf86OutputOptions)); 523 memcpy(output->options, xf86OutputOptions, sizeof(xf86OutputOptions)); 524 525 XNFasprintf(&option_name, "monitor-%s", output->name); 526 monitor = xf86findOptionValue(output->scrn->options, option_name); 527 if (!monitor) 528 monitor = output->name; 529 else 530 xf86MarkOptionUsedByName(output->scrn->options, option_name); 531 free(option_name); 532 output->conf_monitor = xf86findMonitor(monitor, 533 xf86configptr->conf_monitor_lst); 534 /* 535 * Find the monitor section of the screen and use that 536 */ 537 if (!output->conf_monitor && output->use_screen_monitor) 538 output->conf_monitor = xf86findMonitor(output->scrn->monitor->id, 539 xf86configptr->conf_monitor_lst); 540 if (output->conf_monitor) { 541 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 542 "Output %s using monitor section %s\n", 543 output->name, output->conf_monitor->mon_identifier); 544 xf86ProcessOptions(output->scrn->scrnIndex, 545 output->conf_monitor->mon_option_lst, 546 output->options); 547 } 548 else 549 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 550 "Output %s has no monitor section\n", output->name); 551} 552 553static Bool 554xf86OutputEnabled(xf86OutputPtr output, Bool strict) 555{ 556 Bool enable, disable; 557 558 /* check to see if this output was enabled in the config file */ 559 if (xf86GetOptValBool(output->options, OPTION_ENABLE, &enable) && enable) { 560 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 561 "Output %s enabled by config file\n", output->name); 562 return TRUE; 563 } 564 /* or if this output was disabled in the config file */ 565 if (xf86GetOptValBool(output->options, OPTION_DISABLE, &disable) && disable) { 566 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 567 "Output %s disabled by config file\n", output->name); 568 return FALSE; 569 } 570 571 /* If not, try to only light up the ones we know are connected which are supposed to be on the desktop */ 572 if (strict) { 573 enable = output->status == XF86OutputStatusConnected && !output->non_desktop; 574 } 575 /* But if that fails, try to light up even outputs we're unsure of */ 576 else { 577 enable = output->status != XF86OutputStatusDisconnected; 578 } 579 580 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 581 "Output %s %sconnected\n", output->name, enable ? "" : "dis"); 582 return enable; 583} 584 585static Bool 586xf86OutputIgnored(xf86OutputPtr output) 587{ 588 return xf86ReturnOptValBool(output->options, OPTION_IGNORE, FALSE); 589} 590 591static const char *direction[4] = { 592 "normal", 593 "left", 594 "inverted", 595 "right" 596}; 597 598static Rotation 599xf86OutputInitialRotation(xf86OutputPtr output) 600{ 601 const char *rotate_name = xf86GetOptValString(output->options, 602 OPTION_ROTATE); 603 int i; 604 605 if (!rotate_name) { 606 if (output->initial_rotation) 607 return output->initial_rotation; 608 return RR_Rotate_0; 609 } 610 611 for (i = 0; i < 4; i++) 612 if (xf86nameCompare(direction[i], rotate_name) == 0) 613 return 1 << i; 614 return RR_Rotate_0; 615} 616 617xf86OutputPtr 618xf86OutputCreate(ScrnInfoPtr scrn, 619 const xf86OutputFuncsRec * funcs, const char *name) 620{ 621 xf86OutputPtr output, *outputs; 622 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 623 int len; 624 Bool primary; 625 626 if (name) 627 len = strlen(name) + 1; 628 else 629 len = 0; 630 631 output = calloc(sizeof(xf86OutputRec) + len, 1); 632 if (!output) 633 return NULL; 634 output->scrn = scrn; 635 output->funcs = funcs; 636 if (name) { 637 output->name = (char *) (output + 1); 638 strcpy(output->name, name); 639 } 640 output->subpixel_order = SubPixelUnknown; 641 /* 642 * Use the old per-screen monitor section for the first output 643 */ 644 output->use_screen_monitor = (xf86_config->num_output == 0); 645#ifdef RANDR_12_INTERFACE 646 output->randr_output = NULL; 647#endif 648 if (name) { 649 xf86OutputSetMonitor(output); 650 if (xf86OutputIgnored(output)) { 651 free(output); 652 return FALSE; 653 } 654 } 655 656 if (xf86_config->output) 657 outputs = reallocarray(xf86_config->output, 658 xf86_config->num_output + 1, 659 sizeof(xf86OutputPtr)); 660 else 661 outputs = xallocarray(xf86_config->num_output + 1, 662 sizeof(xf86OutputPtr)); 663 if (!outputs) { 664 free(output); 665 return NULL; 666 } 667 668 xf86_config->output = outputs; 669 670 if (xf86GetOptValBool(output->options, OPTION_PRIMARY, &primary) && primary) { 671 memmove(xf86_config->output + 1, xf86_config->output, 672 xf86_config->num_output * sizeof(xf86OutputPtr)); 673 xf86_config->output[0] = output; 674 } 675 else { 676 xf86_config->output[xf86_config->num_output] = output; 677 } 678 679 xf86_config->num_output++; 680 681 return output; 682} 683 684Bool 685xf86OutputRename(xf86OutputPtr output, const char *name) 686{ 687 char *newname = strdup(name); 688 689 if (!newname) 690 return FALSE; /* so sorry... */ 691 692 if (output->name && output->name != (char *) (output + 1)) 693 free(output->name); 694 output->name = newname; 695 xf86OutputSetMonitor(output); 696 if (xf86OutputIgnored(output)) 697 return FALSE; 698 return TRUE; 699} 700 701void 702xf86OutputUseScreenMonitor(xf86OutputPtr output, Bool use_screen_monitor) 703{ 704 if (use_screen_monitor != output->use_screen_monitor) { 705 output->use_screen_monitor = use_screen_monitor; 706 xf86OutputSetMonitor(output); 707 } 708} 709 710void 711xf86OutputDestroy(xf86OutputPtr output) 712{ 713 ScrnInfoPtr scrn = output->scrn; 714 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 715 int o; 716 717 (*output->funcs->destroy) (output); 718 while (output->probed_modes) 719 xf86DeleteMode(&output->probed_modes, output->probed_modes); 720 for (o = 0; o < xf86_config->num_output; o++) 721 if (xf86_config->output[o] == output) { 722 memmove(&xf86_config->output[o], 723 &xf86_config->output[o + 1], 724 ((xf86_config->num_output - (o + 1)) * sizeof(void *))); 725 xf86_config->num_output--; 726 break; 727 } 728 if (output->name && output->name != (char *) (output + 1)) 729 free(output->name); 730 free(output); 731} 732 733/* 734 * Called during CreateScreenResources to hook up RandR 735 */ 736static Bool 737xf86CrtcCreateScreenResources(ScreenPtr screen) 738{ 739 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 740 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 741 742 screen->CreateScreenResources = config->CreateScreenResources; 743 744 if (!(*screen->CreateScreenResources) (screen)) 745 return FALSE; 746 747 if (!xf86RandR12CreateScreenResources(screen)) 748 return FALSE; 749 750 return TRUE; 751} 752 753/* 754 * Clean up config on server reset 755 */ 756static Bool 757xf86CrtcCloseScreen(ScreenPtr screen) 758{ 759 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 760 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 761 int o, c; 762 763 /* The randr_output and randr_crtc pointers are already invalid as 764 * the DIX resources were freed when the associated resources were 765 * freed. Clear them now; referencing through them during the rest 766 * of the CloseScreen sequence will not end well. 767 */ 768 for (o = 0; o < config->num_output; o++) { 769 xf86OutputPtr output = config->output[o]; 770 771 output->randr_output = NULL; 772 } 773 for (c = 0; c < config->num_crtc; c++) { 774 xf86CrtcPtr crtc = config->crtc[c]; 775 776 crtc->randr_crtc = NULL; 777 } 778 779 screen->CloseScreen = config->CloseScreen; 780 781 xf86RotateCloseScreen(screen); 782 783 xf86RandR12CloseScreen(screen); 784 785 screen->CloseScreen(screen); 786 787 /* detach any providers */ 788 if (config->randr_provider) { 789 RRProviderDestroy(config->randr_provider); 790 config->randr_provider = NULL; 791 } 792 return TRUE; 793} 794 795/* 796 * Called at ScreenInit time to set up 797 */ 798#ifdef RANDR_13_INTERFACE 799int 800#else 801Bool 802#endif 803xf86CrtcScreenInit(ScreenPtr screen) 804{ 805 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 806 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 807 int c; 808 809 /* Rotation */ 810 xf86RandR12Init(screen); 811 812 /* support all rotations if every crtc has the shadow alloc funcs */ 813 for (c = 0; c < config->num_crtc; c++) { 814 xf86CrtcPtr crtc = config->crtc[c]; 815 816 if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) 817 break; 818 } 819 if (c == config->num_crtc) { 820 xf86RandR12SetRotations(screen, RR_Rotate_0 | RR_Rotate_90 | 821 RR_Rotate_180 | RR_Rotate_270 | 822 RR_Reflect_X | RR_Reflect_Y); 823 xf86RandR12SetTransformSupport(screen, TRUE); 824 } 825 else { 826 xf86RandR12SetRotations(screen, RR_Rotate_0); 827 xf86RandR12SetTransformSupport(screen, FALSE); 828 } 829 830 /* Wrap CreateScreenResources so we can initialize the RandR code */ 831 config->CreateScreenResources = screen->CreateScreenResources; 832 screen->CreateScreenResources = xf86CrtcCreateScreenResources; 833 834 config->CloseScreen = screen->CloseScreen; 835 screen->CloseScreen = xf86CrtcCloseScreen; 836 837 /* This might still be marked wrapped from a previous generation */ 838 config->BlockHandler = NULL; 839 840#ifdef XFreeXDGA 841 _xf86_di_dga_init_internal(screen); 842#endif 843#ifdef RANDR_13_INTERFACE 844 return RANDR_INTERFACE_VERSION; 845#else 846 return TRUE; 847#endif 848} 849 850static DisplayModePtr 851xf86DefaultMode(xf86OutputPtr output, int width, int height) 852{ 853 DisplayModePtr target_mode = NULL; 854 DisplayModePtr mode; 855 int target_diff = 0; 856 int target_preferred = 0; 857 int mm_height; 858 859 mm_height = output->mm_height; 860 if (!mm_height) 861 mm_height = (768 * 25.4) / DEFAULT_DPI; 862 /* 863 * Pick a mode closest to DEFAULT_DPI 864 */ 865 for (mode = output->probed_modes; mode; mode = mode->next) { 866 int dpi; 867 int preferred = (((mode->type & M_T_PREFERRED) != 0) + 868 ((mode->type & M_T_USERPREF) != 0)); 869 int diff; 870 871 if (xf86ModeWidth(mode, output->initial_rotation) > width || 872 xf86ModeHeight(mode, output->initial_rotation) > height) 873 continue; 874 875 /* yes, use VDisplay here, not xf86ModeHeight */ 876 dpi = (mode->VDisplay * 254) / (mm_height * 10); 877 diff = dpi - DEFAULT_DPI; 878 diff = diff < 0 ? -diff : diff; 879 if (target_mode == NULL || (preferred > target_preferred) || 880 (preferred == target_preferred && diff < target_diff)) { 881 target_mode = mode; 882 target_diff = diff; 883 target_preferred = preferred; 884 } 885 } 886 return target_mode; 887} 888 889static DisplayModePtr 890xf86ClosestMode(xf86OutputPtr output, 891 DisplayModePtr match, Rotation match_rotation, 892 int width, int height) 893{ 894 DisplayModePtr target_mode = NULL; 895 DisplayModePtr mode; 896 int target_diff = 0; 897 898 /* 899 * Pick a mode closest to the specified mode 900 */ 901 for (mode = output->probed_modes; mode; mode = mode->next) { 902 int dx, dy; 903 int diff; 904 905 if (xf86ModeWidth(mode, output->initial_rotation) > width || 906 xf86ModeHeight(mode, output->initial_rotation) > height) 907 continue; 908 909 /* exact matches are preferred */ 910 if (output->initial_rotation == match_rotation && 911 xf86ModesEqual(mode, match)) 912 return mode; 913 914 dx = xf86ModeWidth(match, match_rotation) - xf86ModeWidth(mode, 915 output-> 916 initial_rotation); 917 dy = xf86ModeHeight(match, match_rotation) - xf86ModeHeight(mode, 918 output-> 919 initial_rotation); 920 diff = dx * dx + dy * dy; 921 if (target_mode == NULL || diff < target_diff) { 922 target_mode = mode; 923 target_diff = diff; 924 } 925 } 926 return target_mode; 927} 928 929static DisplayModePtr 930xf86OutputHasPreferredMode(xf86OutputPtr output, int width, int height) 931{ 932 DisplayModePtr mode; 933 934 for (mode = output->probed_modes; mode; mode = mode->next) { 935 if (xf86ModeWidth(mode, output->initial_rotation) > width || 936 xf86ModeHeight(mode, output->initial_rotation) > height) 937 continue; 938 939 if (mode->type & M_T_PREFERRED) 940 return mode; 941 } 942 return NULL; 943} 944 945static DisplayModePtr 946xf86OutputHasUserPreferredMode(xf86OutputPtr output) 947{ 948 DisplayModePtr mode, first = output->probed_modes; 949 950 for (mode = first; mode && mode->next != first; mode = mode->next) 951 if (mode->type & M_T_USERPREF) 952 return mode; 953 954 return NULL; 955} 956 957static int 958xf86PickCrtcs(ScrnInfoPtr scrn, 959 xf86CrtcPtr * best_crtcs, 960 DisplayModePtr * modes, int n, int width, int height) 961{ 962 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 963 int c, o; 964 xf86OutputPtr output; 965 xf86CrtcPtr crtc; 966 xf86CrtcPtr *crtcs; 967 int best_score; 968 int score; 969 int my_score; 970 971 if (n == config->num_output) 972 return 0; 973 output = config->output[n]; 974 975 /* 976 * Compute score with this output disabled 977 */ 978 best_crtcs[n] = NULL; 979 best_score = xf86PickCrtcs(scrn, best_crtcs, modes, n + 1, width, height); 980 if (modes[n] == NULL) 981 return best_score; 982 983 crtcs = xallocarray(config->num_output, sizeof(xf86CrtcPtr)); 984 if (!crtcs) 985 return best_score; 986 987 my_score = 1; 988 /* Score outputs that are known to be connected higher */ 989 if (output->status == XF86OutputStatusConnected) 990 my_score++; 991 /* Score outputs with preferred modes higher */ 992 if (xf86OutputHasPreferredMode(output, width, height)) 993 my_score++; 994 /* 995 * Select a crtc for this output and 996 * then attempt to configure the remaining 997 * outputs 998 */ 999 for (c = 0; c < config->num_crtc; c++) { 1000 if ((output->possible_crtcs & (1 << c)) == 0) 1001 continue; 1002 1003 crtc = config->crtc[c]; 1004 /* 1005 * Check to see if some other output is 1006 * using this crtc 1007 */ 1008 for (o = 0; o < n; o++) 1009 if (best_crtcs[o] == crtc) 1010 break; 1011 if (o < n) { 1012 /* 1013 * If the two outputs desire the same mode, 1014 * see if they can be cloned 1015 */ 1016 if (xf86ModesEqual(modes[o], modes[n]) && 1017 config->output[o]->initial_rotation == 1018 config->output[n]->initial_rotation && 1019 config->output[o]->initial_x == config->output[n]->initial_x && 1020 config->output[o]->initial_y == config->output[n]->initial_y) { 1021 if ((output->possible_clones & (1 << o)) == 0) 1022 continue; /* nope, try next CRTC */ 1023 } 1024 else 1025 continue; /* different modes, can't clone */ 1026 } 1027 crtcs[n] = crtc; 1028 memcpy(crtcs, best_crtcs, n * sizeof(xf86CrtcPtr)); 1029 score = 1030 my_score + xf86PickCrtcs(scrn, crtcs, modes, n + 1, width, height); 1031 if (score > best_score) { 1032 best_score = score; 1033 memcpy(best_crtcs, crtcs, config->num_output * sizeof(xf86CrtcPtr)); 1034 } 1035 } 1036 free(crtcs); 1037 return best_score; 1038} 1039 1040/* 1041 * Compute the virtual size necessary to place all of the available 1042 * crtcs in the specified configuration. 1043 * 1044 * canGrow indicates that the driver can make the screen larger than its initial 1045 * configuration. If FALSE, this function will enlarge the screen to include 1046 * the largest available mode. 1047 */ 1048 1049static void 1050xf86DefaultScreenLimits(ScrnInfoPtr scrn, int *widthp, int *heightp, 1051 Bool canGrow) 1052{ 1053 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1054 int width = 0, height = 0; 1055 int o; 1056 int c; 1057 int s; 1058 1059 for (c = 0; c < config->num_crtc; c++) { 1060 int crtc_width = 0, crtc_height = 0; 1061 xf86CrtcPtr crtc = config->crtc[c]; 1062 1063 if (crtc->enabled) { 1064 crtc_width = 1065 crtc->desiredX + xf86ModeWidth(&crtc->desiredMode, 1066 crtc->desiredRotation); 1067 crtc_height = 1068 crtc->desiredY + xf86ModeHeight(&crtc->desiredMode, 1069 crtc->desiredRotation); 1070 } 1071 if (!canGrow) { 1072 for (o = 0; o < config->num_output; o++) { 1073 xf86OutputPtr output = config->output[o]; 1074 1075 for (s = 0; s < config->num_crtc; s++) 1076 if (output->possible_crtcs & (1 << s)) { 1077 DisplayModePtr mode; 1078 1079 for (mode = output->probed_modes; mode; 1080 mode = mode->next) { 1081 if (mode->HDisplay > crtc_width) 1082 crtc_width = mode->HDisplay; 1083 if (mode->VDisplay > crtc_width) 1084 crtc_width = mode->VDisplay; 1085 if (mode->VDisplay > crtc_height) 1086 crtc_height = mode->VDisplay; 1087 if (mode->HDisplay > crtc_height) 1088 crtc_height = mode->HDisplay; 1089 } 1090 } 1091 } 1092 } 1093 if (crtc_width > width) 1094 width = crtc_width; 1095 if (crtc_height > height) 1096 height = crtc_height; 1097 } 1098 if (config->maxWidth && width > config->maxWidth) 1099 width = config->maxWidth; 1100 if (config->maxHeight && height > config->maxHeight) 1101 height = config->maxHeight; 1102 if (config->minWidth && width < config->minWidth) 1103 width = config->minWidth; 1104 if (config->minHeight && height < config->minHeight) 1105 height = config->minHeight; 1106 *widthp = width; 1107 *heightp = height; 1108} 1109 1110#define POSITION_UNSET -100000 1111 1112/* 1113 * check if the user configured any outputs at all 1114 * with either a position or a relative setting or a mode. 1115 */ 1116static Bool 1117xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr * modes) 1118{ 1119 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1120 int o; 1121 Bool user_conf = FALSE; 1122 1123 for (o = 0; o < config->num_output; o++) { 1124 xf86OutputPtr output = config->output[o]; 1125 const char *position; 1126 const char *relative_name; 1127 OutputOpts relation; 1128 int r; 1129 1130 static const OutputOpts relations[] = { 1131 OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF 1132 }; 1133 1134 position = xf86GetOptValString(output->options, OPTION_POSITION); 1135 if (position) 1136 user_conf = TRUE; 1137 1138 relation = 0; 1139 relative_name = NULL; 1140 for (r = 0; r < 4; r++) { 1141 relation = relations[r]; 1142 relative_name = xf86GetOptValString(output->options, relation); 1143 if (relative_name) 1144 break; 1145 } 1146 if (relative_name) 1147 user_conf = TRUE; 1148 1149 modes[o] = xf86OutputHasUserPreferredMode(output); 1150 if (modes[o]) 1151 user_conf = TRUE; 1152 } 1153 1154 return user_conf; 1155} 1156 1157static Bool 1158xf86InitialOutputPositions(ScrnInfoPtr scrn, DisplayModePtr * modes) 1159{ 1160 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1161 int o; 1162 int min_x, min_y; 1163 1164 /* check for initial right-of heuristic */ 1165 for (o = 0; o < config->num_output; o++) 1166 { 1167 xf86OutputPtr output = config->output[o]; 1168 1169 if (output->initial_x || output->initial_y) 1170 return TRUE; 1171 } 1172 1173 for (o = 0; o < config->num_output; o++) { 1174 xf86OutputPtr output = config->output[o]; 1175 1176 output->initial_x = output->initial_y = POSITION_UNSET; 1177 } 1178 1179 /* 1180 * Loop until all outputs are set 1181 */ 1182 for (;;) { 1183 Bool any_set = FALSE; 1184 Bool keep_going = FALSE; 1185 1186 for (o = 0; o < config->num_output; o++) { 1187 static const OutputOpts relations[] = { 1188 OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF 1189 }; 1190 xf86OutputPtr output = config->output[o]; 1191 xf86OutputPtr relative; 1192 const char *relative_name; 1193 const char *position; 1194 OutputOpts relation; 1195 int r; 1196 1197 if (output->initial_x != POSITION_UNSET) 1198 continue; 1199 position = xf86GetOptValString(output->options, OPTION_POSITION); 1200 /* 1201 * Absolute position wins 1202 */ 1203 if (position) { 1204 int x, y; 1205 1206 if (sscanf(position, "%d %d", &x, &y) == 2) { 1207 output->initial_x = x; 1208 output->initial_y = y; 1209 } 1210 else { 1211 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1212 "Output %s position not of form \"x y\"\n", 1213 output->name); 1214 output->initial_x = output->initial_y = 0; 1215 } 1216 any_set = TRUE; 1217 continue; 1218 } 1219 /* 1220 * Next comes relative positions 1221 */ 1222 relation = 0; 1223 relative_name = NULL; 1224 for (r = 0; r < 4; r++) { 1225 relation = relations[r]; 1226 relative_name = xf86GetOptValString(output->options, relation); 1227 if (relative_name) 1228 break; 1229 } 1230 if (relative_name) { 1231 int or; 1232 1233 relative = NULL; 1234 for (or = 0; or < config->num_output; or++) { 1235 xf86OutputPtr out_rel = config->output[or]; 1236 XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; 1237 1238 if (rel_mon) { 1239 if (xf86nameCompare(rel_mon->mon_identifier, 1240 relative_name) == 0) { 1241 relative = config->output[or]; 1242 break; 1243 } 1244 } 1245 if (strcmp(out_rel->name, relative_name) == 0) { 1246 relative = config->output[or]; 1247 break; 1248 } 1249 } 1250 if (!relative) { 1251 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1252 "Cannot position output %s relative to unknown output %s\n", 1253 output->name, relative_name); 1254 output->initial_x = 0; 1255 output->initial_y = 0; 1256 any_set = TRUE; 1257 continue; 1258 } 1259 if (!modes[or]) { 1260 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1261 "Cannot position output %s relative to output %s without modes\n", 1262 output->name, relative_name); 1263 output->initial_x = 0; 1264 output->initial_y = 0; 1265 any_set = TRUE; 1266 continue; 1267 } 1268 if (relative->initial_x == POSITION_UNSET) { 1269 keep_going = TRUE; 1270 continue; 1271 } 1272 output->initial_x = relative->initial_x; 1273 output->initial_y = relative->initial_y; 1274 switch (relation) { 1275 case OPTION_BELOW: 1276 output->initial_y += 1277 xf86ModeHeight(modes[or], relative->initial_rotation); 1278 break; 1279 case OPTION_RIGHT_OF: 1280 output->initial_x += 1281 xf86ModeWidth(modes[or], relative->initial_rotation); 1282 break; 1283 case OPTION_ABOVE: 1284 if (modes[o]) 1285 output->initial_y -= 1286 xf86ModeHeight(modes[o], output->initial_rotation); 1287 break; 1288 case OPTION_LEFT_OF: 1289 if (modes[o]) 1290 output->initial_x -= 1291 xf86ModeWidth(modes[o], output->initial_rotation); 1292 break; 1293 default: 1294 break; 1295 } 1296 any_set = TRUE; 1297 continue; 1298 } 1299 1300 /* Nothing set, just stick them at 0,0 */ 1301 output->initial_x = 0; 1302 output->initial_y = 0; 1303 any_set = TRUE; 1304 } 1305 if (!keep_going) 1306 break; 1307 if (!any_set) { 1308 for (o = 0; o < config->num_output; o++) { 1309 xf86OutputPtr output = config->output[o]; 1310 1311 if (output->initial_x == POSITION_UNSET) { 1312 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1313 "Output position loop. Moving %s to 0,0\n", 1314 output->name); 1315 output->initial_x = output->initial_y = 0; 1316 break; 1317 } 1318 } 1319 } 1320 } 1321 1322 /* 1323 * normalize positions 1324 */ 1325 min_x = 1000000; 1326 min_y = 1000000; 1327 for (o = 0; o < config->num_output; o++) { 1328 xf86OutputPtr output = config->output[o]; 1329 1330 if (output->initial_x < min_x) 1331 min_x = output->initial_x; 1332 if (output->initial_y < min_y) 1333 min_y = output->initial_y; 1334 } 1335 1336 for (o = 0; o < config->num_output; o++) { 1337 xf86OutputPtr output = config->output[o]; 1338 1339 output->initial_x -= min_x; 1340 output->initial_y -= min_y; 1341 } 1342 return TRUE; 1343} 1344 1345static void 1346xf86InitialPanning(ScrnInfoPtr scrn) 1347{ 1348 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1349 int o; 1350 1351 for (o = 0; o < config->num_output; o++) { 1352 xf86OutputPtr output = config->output[o]; 1353 const char *panning = xf86GetOptValString(output->options, OPTION_PANNING); 1354 int width, height, left, top; 1355 int track_width, track_height, track_left, track_top; 1356 int brdr[4]; 1357 1358 memset(&output->initialTotalArea, 0, sizeof(BoxRec)); 1359 memset(&output->initialTrackingArea, 0, sizeof(BoxRec)); 1360 memset(output->initialBorder, 0, 4 * sizeof(INT16)); 1361 1362 if (!panning) 1363 continue; 1364 1365 switch (sscanf(panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", 1366 &width, &height, &left, &top, 1367 &track_width, &track_height, &track_left, &track_top, 1368 &brdr[0], &brdr[1], &brdr[2], &brdr[3])) { 1369 case 12: 1370 output->initialBorder[0] = brdr[0]; 1371 output->initialBorder[1] = brdr[1]; 1372 output->initialBorder[2] = brdr[2]; 1373 output->initialBorder[3] = brdr[3]; 1374 /* fall through */ 1375 case 8: 1376 output->initialTrackingArea.x1 = track_left; 1377 output->initialTrackingArea.y1 = track_top; 1378 output->initialTrackingArea.x2 = track_left + track_width; 1379 output->initialTrackingArea.y2 = track_top + track_height; 1380 /* fall through */ 1381 case 4: 1382 output->initialTotalArea.x1 = left; 1383 output->initialTotalArea.y1 = top; 1384 /* fall through */ 1385 case 2: 1386 output->initialTotalArea.x2 = output->initialTotalArea.x1 + width; 1387 output->initialTotalArea.y2 = output->initialTotalArea.y1 + height; 1388 break; 1389 default: 1390 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1391 "Broken panning specification '%s' for output %s in config file\n", 1392 panning, output->name); 1393 } 1394 } 1395} 1396 1397/** Return - 0 + if a should be earlier, same or later than b in list 1398 */ 1399static int 1400xf86ModeCompare(DisplayModePtr a, DisplayModePtr b) 1401{ 1402 int diff; 1403 1404 diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); 1405 if (diff) 1406 return diff; 1407 diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; 1408 if (diff) 1409 return diff; 1410 diff = b->Clock - a->Clock; 1411 return diff; 1412} 1413 1414/** 1415 * Insertion sort input in-place and return the resulting head 1416 */ 1417static DisplayModePtr 1418xf86SortModes(DisplayModePtr input) 1419{ 1420 DisplayModePtr output = NULL, i, o, n, *op, prev; 1421 1422 /* sort by preferred status and pixel area */ 1423 while (input) { 1424 i = input; 1425 input = input->next; 1426 for (op = &output; (o = *op); op = &o->next) 1427 if (xf86ModeCompare(o, i) > 0) 1428 break; 1429 i->next = *op; 1430 *op = i; 1431 } 1432 /* prune identical modes */ 1433 for (o = output; o && (n = o->next); o = n) { 1434 if (!strcmp(o->name, n->name) && xf86ModesEqual(o, n)) { 1435 o->next = n->next; 1436 free((void *) n->name); 1437 free(n); 1438 n = o; 1439 } 1440 } 1441 /* hook up backward links */ 1442 prev = NULL; 1443 for (o = output; o; o = o->next) { 1444 o->prev = prev; 1445 prev = o; 1446 } 1447 return output; 1448} 1449 1450static const char * 1451preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output) 1452{ 1453 const char *preferred_mode = NULL; 1454 1455 /* Check for a configured preference for a particular mode */ 1456 preferred_mode = xf86GetOptValString(output->options, 1457 OPTION_PREFERRED_MODE); 1458 if (preferred_mode) 1459 return preferred_mode; 1460 1461 if (pScrn->display->modes && *pScrn->display->modes) 1462 preferred_mode = *pScrn->display->modes; 1463 1464 return preferred_mode; 1465} 1466 1467/** identify a token 1468 * args 1469 * *src a string with zero or more tokens, e.g. "tok0 tok1", 1470 * **token stores a pointer to the first token character, 1471 * *len stores the token length. 1472 * return 1473 * a pointer into src[] at the token terminating character, or 1474 * NULL if no token is found. 1475 */ 1476static const char * 1477gettoken(const char *src, const char **token, int *len) 1478{ 1479 const char *delim = " \t"; 1480 int skip; 1481 1482 if (!src) 1483 return NULL; 1484 1485 skip = strspn(src, delim); 1486 *token = &src[skip]; 1487 1488 *len = strcspn(*token, delim); 1489 /* Support for backslash escaped delimiters could be implemented 1490 * here. 1491 */ 1492 1493 /* (*token)[0] != '\0' <==> *len > 0 */ 1494 if (*len > 0) 1495 return &(*token)[*len]; 1496 else 1497 return NULL; 1498} 1499 1500/** Check for a user configured zoom mode list, Option "ZoomModes": 1501 * 1502 * Section "Monitor" 1503 * Identifier "a21inch" 1504 * Option "ZoomModes" "1600x1200 1280x1024 1280x1024 640x480" 1505 * EndSection 1506 * 1507 * Each user mode name is searched for independently so the list 1508 * specification order is free. An output mode is matched at most 1509 * once, a mode with an already set M_T_USERDEF type bit is skipped. 1510 * Thus a repeat mode name specification matches the next output mode 1511 * with the same name. 1512 * 1513 * Ctrl+Alt+Keypad-{Plus,Minus} zooms {in,out} by selecting the 1514 * {next,previous} M_T_USERDEF mode in the screen modes list, itself 1515 * sorted toward lower dot area or lower dot clock frequency, see 1516 * modes/xf86Crtc.c: xf86SortModes() xf86SetScrnInfoModes(), and 1517 * common/xf86Cursor.c: xf86ZoomViewport(). 1518 */ 1519static int 1520processZoomModes(xf86OutputPtr output) 1521{ 1522 const char *zoom_modes; 1523 int count = 0; 1524 1525 zoom_modes = xf86GetOptValString(output->options, OPTION_ZOOM_MODES); 1526 1527 if (zoom_modes) { 1528 const char *token, *next; 1529 int len; 1530 1531 next = gettoken(zoom_modes, &token, &len); 1532 while (next) { 1533 DisplayModePtr mode; 1534 1535 for (mode = output->probed_modes; mode; mode = mode->next) 1536 if (!strncmp(token, mode->name, len) /* prefix match */ 1537 && mode->name[len] == '\0' /* equal length */ 1538 && !(mode->type & M_T_USERDEF)) { /* no rematch */ 1539 mode->type |= M_T_USERDEF; 1540 break; 1541 } 1542 1543 count++; 1544 next = gettoken(next, &token, &len); 1545 } 1546 } 1547 1548 return count; 1549} 1550 1551static void 1552GuessRangeFromModes(MonPtr mon, DisplayModePtr mode) 1553{ 1554 if (!mon || !mode) 1555 return; 1556 1557 mon->nHsync = 1; 1558 mon->hsync[0].lo = 1024.0; 1559 mon->hsync[0].hi = 0.0; 1560 1561 mon->nVrefresh = 1; 1562 mon->vrefresh[0].lo = 1024.0; 1563 mon->vrefresh[0].hi = 0.0; 1564 1565 while (mode) { 1566 if (!mode->HSync) 1567 mode->HSync = ((float) mode->Clock) / ((float) mode->HTotal); 1568 1569 if (!mode->VRefresh) 1570 mode->VRefresh = (1000.0 * ((float) mode->Clock)) / 1571 ((float) (mode->HTotal * mode->VTotal)); 1572 1573 if (mode->HSync < mon->hsync[0].lo) 1574 mon->hsync[0].lo = mode->HSync; 1575 1576 if (mode->HSync > mon->hsync[0].hi) 1577 mon->hsync[0].hi = mode->HSync; 1578 1579 if (mode->VRefresh < mon->vrefresh[0].lo) 1580 mon->vrefresh[0].lo = mode->VRefresh; 1581 1582 if (mode->VRefresh > mon->vrefresh[0].hi) 1583 mon->vrefresh[0].hi = mode->VRefresh; 1584 1585 mode = mode->next; 1586 } 1587 1588 /* stretch out the bottom to fit 640x480@60 */ 1589 if (mon->hsync[0].lo > 31.0) 1590 mon->hsync[0].lo = 31.0; 1591 if (mon->vrefresh[0].lo > 58.0) 1592 mon->vrefresh[0].lo = 58.0; 1593} 1594 1595enum det_monrec_source { 1596 sync_config, sync_edid, sync_default 1597}; 1598 1599struct det_monrec_parameter { 1600 MonRec *mon_rec; 1601 int *max_clock; 1602 Bool set_hsync; 1603 Bool set_vrefresh; 1604 enum det_monrec_source *sync_source; 1605}; 1606 1607static void 1608handle_detailed_monrec(struct detailed_monitor_section *det_mon, void *data) 1609{ 1610 struct det_monrec_parameter *p; 1611 1612 p = (struct det_monrec_parameter *) data; 1613 1614 if (det_mon->type == DS_RANGES) { 1615 struct monitor_ranges *ranges = &det_mon->section.ranges; 1616 1617 if (p->set_hsync && ranges->max_h) { 1618 p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h; 1619 p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h; 1620 p->mon_rec->nHsync++; 1621 if (*p->sync_source == sync_default) 1622 *p->sync_source = sync_edid; 1623 } 1624 if (p->set_vrefresh && ranges->max_v) { 1625 p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v; 1626 p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v; 1627 p->mon_rec->nVrefresh++; 1628 if (*p->sync_source == sync_default) 1629 *p->sync_source = sync_edid; 1630 } 1631 if (ranges->max_clock * 1000 > *p->max_clock) 1632 *p->max_clock = ranges->max_clock * 1000; 1633 } 1634} 1635 1636void 1637xf86ProbeOutputModes(ScrnInfoPtr scrn, int maxX, int maxY) 1638{ 1639 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1640 int o; 1641 1642 /* When canGrow was TRUE in the initial configuration we have to 1643 * compare against the maximum values so that we don't drop modes. 1644 * When canGrow was FALSE, the maximum values would have been clamped 1645 * anyway. 1646 */ 1647 if (maxX == 0 || maxY == 0) { 1648 maxX = config->maxWidth; 1649 maxY = config->maxHeight; 1650 } 1651 1652 /* Probe the list of modes for each output. */ 1653 for (o = 0; o < config->num_output; o++) { 1654 xf86OutputPtr output = config->output[o]; 1655 DisplayModePtr mode; 1656 DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL; 1657 const char *preferred_mode; 1658 xf86MonPtr edid_monitor; 1659 XF86ConfMonitorPtr conf_monitor; 1660 MonRec mon_rec; 1661 int min_clock = 0; 1662 int max_clock = 0; 1663 double clock; 1664 Bool add_default_modes; 1665 Bool debug_modes = config->debug_modes || xf86Initialising; 1666 enum det_monrec_source sync_source = sync_default; 1667 1668 while (output->probed_modes != NULL) 1669 xf86DeleteMode(&output->probed_modes, output->probed_modes); 1670 1671 /* 1672 * Check connection status 1673 */ 1674 output->status = (*output->funcs->detect) (output); 1675 1676 if (output->status == XF86OutputStatusDisconnected && 1677 !xf86ReturnOptValBool(output->options, OPTION_ENABLE, FALSE)) { 1678 xf86OutputSetEDID(output, NULL); 1679 continue; 1680 } 1681 1682 memset(&mon_rec, '\0', sizeof(mon_rec)); 1683 1684 conf_monitor = output->conf_monitor; 1685 1686 if (conf_monitor) { 1687 int i; 1688 1689 for (i = 0; i < conf_monitor->mon_n_hsync; i++) { 1690 mon_rec.hsync[mon_rec.nHsync].lo = 1691 conf_monitor->mon_hsync[i].lo; 1692 mon_rec.hsync[mon_rec.nHsync].hi = 1693 conf_monitor->mon_hsync[i].hi; 1694 mon_rec.nHsync++; 1695 sync_source = sync_config; 1696 } 1697 for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) { 1698 mon_rec.vrefresh[mon_rec.nVrefresh].lo = 1699 conf_monitor->mon_vrefresh[i].lo; 1700 mon_rec.vrefresh[mon_rec.nVrefresh].hi = 1701 conf_monitor->mon_vrefresh[i].hi; 1702 mon_rec.nVrefresh++; 1703 sync_source = sync_config; 1704 } 1705 config_modes = xf86GetMonitorModes(scrn, conf_monitor); 1706 } 1707 1708 output_modes = (*output->funcs->get_modes) (output); 1709 1710 /* 1711 * If the user has a preference, respect it. 1712 * Otherwise, don't second-guess the driver. 1713 */ 1714 if (!xf86GetOptValBool(output->options, OPTION_DEFAULT_MODES, 1715 &add_default_modes)) 1716 add_default_modes = (output_modes == NULL); 1717 1718 edid_monitor = output->MonInfo; 1719 1720 if (edid_monitor) { 1721 struct det_monrec_parameter p; 1722 struct disp_features *features = &edid_monitor->features; 1723 struct cea_data_block *hdmi_db; 1724 1725 /* if display is not continuous-frequency, don't add default modes */ 1726 if (!GTF_SUPPORTED(features->msc)) 1727 add_default_modes = FALSE; 1728 1729 p.mon_rec = &mon_rec; 1730 p.max_clock = &max_clock; 1731 p.set_hsync = mon_rec.nHsync == 0; 1732 p.set_vrefresh = mon_rec.nVrefresh == 0; 1733 p.sync_source = &sync_source; 1734 1735 xf86ForEachDetailedBlock(edid_monitor, handle_detailed_monrec, &p); 1736 1737 /* Look at the CEA HDMI vendor block for the max TMDS freq */ 1738 hdmi_db = xf86MonitorFindHDMIBlock(edid_monitor); 1739 if (hdmi_db && hdmi_db->len >= 7) { 1740 int tmds_freq = hdmi_db->u.vendor.hdmi.max_tmds_clock * 5000; 1741 xf86DrvMsg(scrn->scrnIndex, X_PROBED, 1742 "HDMI max TMDS frequency %dKHz\n", tmds_freq); 1743 if (tmds_freq > max_clock) 1744 max_clock = tmds_freq; 1745 } 1746 } 1747 1748 if (xf86GetOptValFreq(output->options, OPTION_MIN_CLOCK, 1749 OPTUNITS_KHZ, &clock)) 1750 min_clock = (int) clock; 1751 if (xf86GetOptValFreq(output->options, OPTION_MAX_CLOCK, 1752 OPTUNITS_KHZ, &clock)) 1753 max_clock = (int) clock; 1754 1755 /* If we still don't have a sync range, guess wildly */ 1756 if (!mon_rec.nHsync || !mon_rec.nVrefresh) 1757 GuessRangeFromModes(&mon_rec, output_modes); 1758 1759 /* 1760 * These limits will end up setting a 1024x768@60Hz mode by default, 1761 * which seems like a fairly good mode to use when nothing else is 1762 * specified 1763 */ 1764 if (mon_rec.nHsync == 0) { 1765 mon_rec.hsync[0].lo = 31.0; 1766 mon_rec.hsync[0].hi = 55.0; 1767 mon_rec.nHsync = 1; 1768 } 1769 if (mon_rec.nVrefresh == 0) { 1770 mon_rec.vrefresh[0].lo = 58.0; 1771 mon_rec.vrefresh[0].hi = 62.0; 1772 mon_rec.nVrefresh = 1; 1773 } 1774 1775 if (add_default_modes) 1776 default_modes = xf86GetDefaultModes(); 1777 1778 /* 1779 * If this is not an RB monitor, remove RB modes from the default 1780 * pool. RB modes from the config or the monitor itself are fine. 1781 */ 1782 if (!mon_rec.reducedblanking) 1783 xf86ValidateModesReducedBlanking(scrn, default_modes); 1784 1785 if (sync_source == sync_config) { 1786 /* 1787 * Check output and config modes against sync range from config file 1788 */ 1789 xf86ValidateModesSync(scrn, output_modes, &mon_rec); 1790 xf86ValidateModesSync(scrn, config_modes, &mon_rec); 1791 } 1792 /* 1793 * Check default modes against sync range 1794 */ 1795 xf86ValidateModesSync(scrn, default_modes, &mon_rec); 1796 /* 1797 * Check default modes against monitor max clock 1798 */ 1799 if (max_clock) { 1800 xf86ValidateModesClocks(scrn, default_modes, 1801 &min_clock, &max_clock, 1); 1802 xf86ValidateModesClocks(scrn, output_modes, 1803 &min_clock, &max_clock, 1); 1804 } 1805 1806 output->probed_modes = NULL; 1807 output->probed_modes = xf86ModesAdd(output->probed_modes, config_modes); 1808 output->probed_modes = xf86ModesAdd(output->probed_modes, output_modes); 1809 output->probed_modes = 1810 xf86ModesAdd(output->probed_modes, default_modes); 1811 1812 /* 1813 * Check all modes against max size, interlace, and doublescan 1814 */ 1815 if (maxX && maxY) 1816 xf86ValidateModesSize(scrn, output->probed_modes, maxX, maxY, 0); 1817 1818 { 1819 int flags = (output->interlaceAllowed ? V_INTERLACE : 0) | 1820 (output->doubleScanAllowed ? V_DBLSCAN : 0); 1821 xf86ValidateModesFlags(scrn, output->probed_modes, flags); 1822 } 1823 1824 /* 1825 * Check all modes against output 1826 */ 1827 for (mode = output->probed_modes; mode != NULL; mode = mode->next) 1828 if (mode->status == MODE_OK) 1829 mode->status = (*output->funcs->mode_valid) (output, mode); 1830 1831 xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes); 1832 1833 output->probed_modes = xf86SortModes(output->probed_modes); 1834 1835 /* Check for a configured preference for a particular mode */ 1836 preferred_mode = preferredMode(scrn, output); 1837 1838 if (preferred_mode) { 1839 for (mode = output->probed_modes; mode; mode = mode->next) { 1840 if (!strcmp(preferred_mode, mode->name)) { 1841 if (mode != output->probed_modes) { 1842 if (mode->prev) 1843 mode->prev->next = mode->next; 1844 if (mode->next) 1845 mode->next->prev = mode->prev; 1846 mode->next = output->probed_modes; 1847 output->probed_modes->prev = mode; 1848 mode->prev = NULL; 1849 output->probed_modes = mode; 1850 } 1851 mode->type |= (M_T_PREFERRED | M_T_USERPREF); 1852 break; 1853 } 1854 } 1855 } 1856 1857 /* Ctrl+Alt+Keypad-{Plus,Minus} zoom mode: M_T_USERDEF mode type */ 1858 processZoomModes(output); 1859 1860 output->initial_rotation = xf86OutputInitialRotation(output); 1861 1862 if (debug_modes) { 1863 if (output->probed_modes != NULL) { 1864 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1865 "Printing probed modes for output %s\n", 1866 output->name); 1867 } 1868 else { 1869 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1870 "No remaining probed modes for output %s\n", 1871 output->name); 1872 } 1873 } 1874 for (mode = output->probed_modes; mode != NULL; mode = mode->next) { 1875 /* The code to choose the best mode per pipe later on will require 1876 * VRefresh to be set. 1877 */ 1878 mode->VRefresh = xf86ModeVRefresh(mode); 1879 xf86SetModeCrtc(mode, INTERLACE_HALVE_V); 1880 1881 if (debug_modes) 1882 xf86PrintModeline(scrn->scrnIndex, mode); 1883 } 1884 } 1885} 1886 1887/** 1888 * Copy one of the output mode lists to the ScrnInfo record 1889 */ 1890 1891static DisplayModePtr 1892biggestMode(DisplayModePtr a, DisplayModePtr b) 1893{ 1894 int A, B; 1895 1896 if (!a) 1897 return b; 1898 if (!b) 1899 return a; 1900 1901 A = a->HDisplay * a->VDisplay; 1902 B = b->HDisplay * b->VDisplay; 1903 1904 if (A > B) 1905 return a; 1906 1907 return b; 1908} 1909 1910static xf86OutputPtr 1911SetCompatOutput(xf86CrtcConfigPtr config) 1912{ 1913 xf86OutputPtr output = NULL, test = NULL; 1914 DisplayModePtr maxmode = NULL, testmode, mode; 1915 int o, compat = -1, count, mincount = 0; 1916 1917 if (config->num_output == 0) 1918 return NULL; 1919 1920 /* Look for one that's definitely connected */ 1921 for (o = 0; o < config->num_output; o++) { 1922 test = config->output[o]; 1923 if (!test->crtc) 1924 continue; 1925 if (test->status != XF86OutputStatusConnected) 1926 continue; 1927 if (!test->probed_modes) 1928 continue; 1929 1930 testmode = mode = test->probed_modes; 1931 for (count = 0; mode; mode = mode->next, count++) 1932 testmode = biggestMode(testmode, mode); 1933 1934 if (!output) { 1935 output = test; 1936 compat = o; 1937 maxmode = testmode; 1938 mincount = count; 1939 } 1940 else if (maxmode == biggestMode(maxmode, testmode)) { 1941 output = test; 1942 compat = o; 1943 maxmode = testmode; 1944 mincount = count; 1945 } 1946 else if ((maxmode->HDisplay == testmode->HDisplay) && 1947 (maxmode->VDisplay == testmode->VDisplay) && 1948 count <= mincount) { 1949 output = test; 1950 compat = o; 1951 maxmode = testmode; 1952 mincount = count; 1953 } 1954 } 1955 1956 /* If we didn't find one, take anything we can get */ 1957 if (!output) { 1958 for (o = 0; o < config->num_output; o++) { 1959 test = config->output[o]; 1960 if (!test->crtc) 1961 continue; 1962 if (!test->probed_modes) 1963 continue; 1964 1965 if (!output) { 1966 output = test; 1967 compat = o; 1968 } 1969 else if (test->probed_modes->HDisplay < 1970 output->probed_modes->HDisplay) { 1971 output = test; 1972 compat = o; 1973 } 1974 } 1975 } 1976 1977 if (compat >= 0) { 1978 config->compat_output = compat; 1979 } 1980 else if (config->compat_output >= 0 && config->compat_output < config->num_output) { 1981 /* Don't change the compat output when no valid outputs found */ 1982 output = config->output[config->compat_output]; 1983 } 1984 1985 /* All outputs are disconnected, select one to fake */ 1986 if (!output && config->num_output) { 1987 config->compat_output = 0; 1988 output = config->output[config->compat_output]; 1989 } 1990 1991 return output; 1992} 1993 1994void 1995xf86SetScrnInfoModes(ScrnInfoPtr scrn) 1996{ 1997 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1998 xf86OutputPtr output; 1999 xf86CrtcPtr crtc; 2000 DisplayModePtr last, mode = NULL; 2001 2002 output = SetCompatOutput(config); 2003 2004 if (!output) 2005 return; /* punt */ 2006 2007 crtc = output->crtc; 2008 2009 /* Clear any existing modes from scrn->modes */ 2010 while (scrn->modes != NULL) 2011 xf86DeleteMode(&scrn->modes, scrn->modes); 2012 2013 /* Set scrn->modes to the mode list for the 'compat' output */ 2014 scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); 2015 2016 if (crtc) { 2017 for (mode = scrn->modes; mode; mode = mode->next) 2018 if (xf86ModesEqual(mode, &crtc->desiredMode)) 2019 break; 2020 } 2021 2022 if (!scrn->modes) { 2023 scrn->modes = xf86ModesAdd(scrn->modes, 2024 xf86CVTMode(scrn->display->virtualX, 2025 scrn->display->virtualY, 2026 60, 0, 0)); 2027 } 2028 2029 /* For some reason, scrn->modes is circular, unlike the other mode 2030 * lists. How great is that? 2031 */ 2032 for (last = scrn->modes; last && last->next; last = last->next); 2033 last->next = scrn->modes; 2034 scrn->modes->prev = last; 2035 if (mode) { 2036 while (scrn->modes != mode) 2037 scrn->modes = scrn->modes->next; 2038 } 2039 2040 scrn->currentMode = scrn->modes; 2041#ifdef XFreeXDGA 2042 if (scrn->pScreen) 2043 _xf86_di_dga_reinit_internal(scrn->pScreen); 2044#endif 2045} 2046 2047static Bool 2048xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2049 Bool *enabled) 2050{ 2051 Bool any_enabled = FALSE; 2052 int o; 2053 2054 /* 2055 * Don't bother enabling outputs on GPU screens: a client needs to attach 2056 * it to a source provider before setting a mode that scans out a shared 2057 * pixmap. 2058 */ 2059 if (scrn->is_gpu) 2060 return FALSE; 2061 2062 for (o = 0; o < config->num_output; o++) 2063 any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); 2064 2065 if (!any_enabled) { 2066 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2067 "No outputs definitely connected, trying again...\n"); 2068 2069 for (o = 0; o < config->num_output; o++) 2070 any_enabled |= enabled[o] = 2071 xf86OutputEnabled(config->output[o], FALSE); 2072 } 2073 2074 return any_enabled; 2075} 2076 2077static Bool 2078nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) 2079{ 2080 int o = *index; 2081 2082 for (o++; o < config->num_output; o++) { 2083 if (enabled[o]) { 2084 *index = o; 2085 return TRUE; 2086 } 2087 } 2088 2089 return FALSE; 2090} 2091 2092static Bool 2093aspectMatch(float a, float b) 2094{ 2095 return fabs(1 - (a / b)) < 0.05; 2096} 2097 2098static DisplayModePtr 2099nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) 2100{ 2101 DisplayModePtr m = NULL; 2102 2103 if (!o) 2104 return NULL; 2105 2106 if (!last) 2107 m = o->probed_modes; 2108 else 2109 m = last->next; 2110 2111 for (; m; m = m->next) 2112 if (aspectMatch(aspect, (float) m->HDisplay / (float) m->VDisplay)) 2113 return m; 2114 2115 return NULL; 2116} 2117 2118static DisplayModePtr 2119bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) 2120{ 2121 int o = -1, p; 2122 DisplayModePtr mode = NULL, test = NULL, match = NULL; 2123 2124 if (!nextEnabledOutput(config, enabled, &o)) 2125 return NULL; 2126 while ((mode = nextAspectMode(config->output[o], mode, aspect))) { 2127 test = mode; 2128 for (p = o; nextEnabledOutput(config, enabled, &p);) { 2129 test = xf86OutputFindClosestMode(config->output[p], mode); 2130 if (!test) 2131 break; 2132 if (test->HDisplay != mode->HDisplay || 2133 test->VDisplay != mode->VDisplay) { 2134 test = NULL; 2135 break; 2136 } 2137 } 2138 2139 /* if we didn't match it on all outputs, try the next one */ 2140 if (!test) 2141 continue; 2142 2143 /* if it's bigger than the last one, save it */ 2144 if (!match || (test->HDisplay > match->HDisplay)) 2145 match = test; 2146 } 2147 2148 /* return the biggest one found */ 2149 return match; 2150} 2151 2152static int 2153numEnabledOutputs(xf86CrtcConfigPtr config, Bool *enabled) 2154{ 2155 int i = 0, p; 2156 2157 for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; 2158 2159 return i; 2160} 2161 2162static Bool 2163xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2164 DisplayModePtr *modes, Bool *enabled, 2165 int width, int height) 2166{ 2167 int o; 2168 int w = 0; 2169 Bool has_tile = FALSE; 2170 uint32_t configured_outputs; 2171 2172 xf86GetOptValBool(config->options, OPTION_PREFER_CLONEMODE, 2173 &scrn->preferClone); 2174 if (scrn->preferClone) 2175 return FALSE; 2176 2177 if (numEnabledOutputs(config, enabled) < 2) 2178 return FALSE; 2179 2180 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2181 DisplayModePtr mode = 2182 xf86OutputHasPreferredMode(config->output[o], width, height); 2183 2184 if (!mode) 2185 return FALSE; 2186 2187 w += mode->HDisplay; 2188 } 2189 2190 if (w > width) 2191 return FALSE; 2192 2193 w = 0; 2194 configured_outputs = 0; 2195 2196 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2197 DisplayModePtr mode = 2198 xf86OutputHasPreferredMode(config->output[o], width, height); 2199 2200 if (configured_outputs & (1 << o)) 2201 continue; 2202 2203 if (config->output[o]->tile_info.group_id) { 2204 has_tile = TRUE; 2205 continue; 2206 } 2207 2208 config->output[o]->initial_x = w; 2209 w += mode->HDisplay; 2210 2211 configured_outputs |= (1 << o); 2212 modes[o] = mode; 2213 } 2214 2215 if (has_tile) { 2216 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2217 int ht, vt, ot; 2218 int add_x, cur_x = w; 2219 struct xf86CrtcTileInfo *tile_info = &config->output[o]->tile_info, *this_tile; 2220 if (configured_outputs & (1 << o)) 2221 continue; 2222 if (!tile_info->group_id) 2223 continue; 2224 2225 if (tile_info->tile_h_loc != 0 && tile_info->tile_v_loc != 0) 2226 continue; 2227 2228 for (ht = 0; ht < tile_info->num_h_tile; ht++) { 2229 int cur_y = 0; 2230 add_x = 0; 2231 for (vt = 0; vt < tile_info->num_v_tile; vt++) { 2232 2233 for (ot = -1; nextEnabledOutput(config, enabled, &ot); ) { 2234 2235 DisplayModePtr mode = 2236 xf86OutputHasPreferredMode(config->output[ot], width, height); 2237 if (!config->output[ot]->tile_info.group_id) 2238 continue; 2239 2240 this_tile = &config->output[ot]->tile_info; 2241 if (this_tile->group_id != tile_info->group_id) 2242 continue; 2243 2244 if (this_tile->tile_h_loc != ht || 2245 this_tile->tile_v_loc != vt) 2246 continue; 2247 2248 config->output[ot]->initial_x = cur_x; 2249 config->output[ot]->initial_y = cur_y; 2250 2251 if (vt == 0) 2252 add_x = this_tile->tile_h_size; 2253 cur_y += this_tile->tile_v_size; 2254 configured_outputs |= (1 << ot); 2255 modes[ot] = mode; 2256 } 2257 } 2258 cur_x += add_x; 2259 } 2260 w = cur_x; 2261 } 2262 } 2263 return TRUE; 2264} 2265 2266static Bool 2267xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2268 DisplayModePtr * modes, Bool *enabled, 2269 int width, int height) 2270{ 2271 int o, p; 2272 int max_pref_width = 0, max_pref_height = 0; 2273 DisplayModePtr *preferred, *preferred_match; 2274 Bool ret = FALSE; 2275 2276 preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2277 preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2278 2279 /* Check if the preferred mode is available on all outputs */ 2280 for (p = -1; nextEnabledOutput(config, enabled, &p);) { 2281 Rotation r = config->output[p]->initial_rotation; 2282 DisplayModePtr mode; 2283 2284 if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], 2285 width, height))) { 2286 int pref_width = xf86ModeWidth(preferred[p], r); 2287 int pref_height = xf86ModeHeight(preferred[p], r); 2288 Bool all_match = TRUE; 2289 2290 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2291 Bool match = FALSE; 2292 xf86OutputPtr output = config->output[o]; 2293 2294 if (o == p) 2295 continue; 2296 2297 /* 2298 * First see if the preferred mode matches on the next 2299 * output as well. This catches the common case of identical 2300 * monitors and makes sure they all have the same timings 2301 * and refresh. If that fails, we fall back to trying to 2302 * match just width & height. 2303 */ 2304 mode = xf86OutputHasPreferredMode(output, pref_width, 2305 pref_height); 2306 if (mode && xf86ModesEqual(mode, preferred[p])) { 2307 preferred[o] = mode; 2308 match = TRUE; 2309 } 2310 else { 2311 for (mode = output->probed_modes; mode; mode = mode->next) { 2312 Rotation ir = output->initial_rotation; 2313 2314 if (xf86ModeWidth(mode, ir) == pref_width && 2315 xf86ModeHeight(mode, ir) == pref_height) { 2316 preferred[o] = mode; 2317 match = TRUE; 2318 } 2319 } 2320 } 2321 2322 all_match &= match; 2323 } 2324 2325 if (all_match && 2326 (pref_width * pref_height > max_pref_width * max_pref_height)) { 2327 for (o = -1; nextEnabledOutput(config, enabled, &o);) 2328 preferred_match[o] = preferred[o]; 2329 max_pref_width = pref_width; 2330 max_pref_height = pref_height; 2331 ret = TRUE; 2332 } 2333 } 2334 } 2335 2336 /* 2337 * If there's no preferred mode, but only one monitor, pick the 2338 * biggest mode for its aspect ratio or 4:3, assuming one exists. 2339 */ 2340 if (!ret) 2341 do { 2342 float aspect = 0.0; 2343 DisplayModePtr a = NULL, b = NULL; 2344 2345 if (numEnabledOutputs(config, enabled) != 1) 2346 break; 2347 2348 p = -1; 2349 nextEnabledOutput(config, enabled, &p); 2350 if (config->output[p]->mm_height) 2351 aspect = (float) config->output[p]->mm_width / 2352 (float) config->output[p]->mm_height; 2353 2354 a = bestModeForAspect(config, enabled, 4.0/3.0); 2355 if (aspect) 2356 b = bestModeForAspect(config, enabled, aspect); 2357 2358 preferred_match[p] = biggestMode(a, b); 2359 2360 if (preferred_match[p]) 2361 ret = TRUE; 2362 2363 } while (0); 2364 2365 if (ret) { 2366 /* oh good, there is a match. stash the selected modes and return. */ 2367 memcpy(modes, preferred_match, 2368 config->num_output * sizeof(DisplayModePtr)); 2369 } 2370 2371 free(preferred); 2372 free(preferred_match); 2373 return ret; 2374} 2375 2376static Bool 2377xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2378 DisplayModePtr * modes, Bool *enabled, int width, int height) 2379{ 2380 int o; 2381 float aspect = 0.0, *aspects; 2382 xf86OutputPtr output; 2383 Bool ret = FALSE; 2384 DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; 2385 2386 aspects = xnfcalloc(config->num_output, sizeof(float)); 2387 2388 /* collect the aspect ratios */ 2389 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2390 output = config->output[o]; 2391 if (output->mm_height) 2392 aspects[o] = (float) output->mm_width / (float) output->mm_height; 2393 else 2394 aspects[o] = 4.0 / 3.0; 2395 } 2396 2397 /* check that they're all the same */ 2398 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2399 output = config->output[o]; 2400 if (!aspect) { 2401 aspect = aspects[o]; 2402 } 2403 else if (!aspectMatch(aspect, aspects[o])) { 2404 goto no_aspect_match; 2405 } 2406 } 2407 2408 /* if they're all 4:3, just skip ahead and save effort */ 2409 if (!aspectMatch(aspect, 4.0 / 3.0)) 2410 aspect_guess = bestModeForAspect(config, enabled, aspect); 2411 2412 no_aspect_match: 2413 base_guess = bestModeForAspect(config, enabled, 4.0 / 3.0); 2414 2415 guess = biggestMode(base_guess, aspect_guess); 2416 2417 if (!guess) 2418 goto out; 2419 2420 /* found a mode that works everywhere, now apply it */ 2421 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2422 modes[o] = xf86OutputFindClosestMode(config->output[o], guess); 2423 } 2424 ret = TRUE; 2425 2426 out: 2427 free(aspects); 2428 return ret; 2429} 2430 2431static Bool 2432xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2433 DisplayModePtr * modes, Bool *enabled, int width, int height) 2434{ 2435 DisplayModePtr target_mode = NULL; 2436 Rotation target_rotation = RR_Rotate_0; 2437 DisplayModePtr default_mode; 2438 int default_preferred, target_preferred = 0, o; 2439 2440 /* User preferred > preferred > other modes */ 2441 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2442 default_mode = xf86DefaultMode(config->output[o], width, height); 2443 if (!default_mode) 2444 continue; 2445 2446 default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + 2447 ((default_mode->type & M_T_USERPREF) != 0)); 2448 2449 if (default_preferred > target_preferred || !target_mode) { 2450 target_mode = default_mode; 2451 target_preferred = default_preferred; 2452 target_rotation = config->output[o]->initial_rotation; 2453 config->compat_output = o; 2454 } 2455 } 2456 2457 if (target_mode) 2458 modes[config->compat_output] = target_mode; 2459 2460 /* Fill in other output modes */ 2461 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2462 if (!modes[o]) 2463 modes[o] = xf86ClosestMode(config->output[o], target_mode, 2464 target_rotation, width, height); 2465 } 2466 2467 return target_mode != NULL; 2468} 2469 2470static Bool 2471xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2472 DisplayModePtr * modes, Bool *enabled, int width, int height) 2473{ 2474 int o; 2475 2476 if (xf86UserConfiguredOutputs(scrn, modes)) 2477 return xf86TargetFallback(scrn, config, modes, enabled, width, height); 2478 2479 for (o = -1; nextEnabledOutput(config, enabled, &o);) 2480 if (xf86OutputHasUserPreferredMode(config->output[o])) 2481 return 2482 xf86TargetFallback(scrn, config, modes, enabled, width, height); 2483 2484 return FALSE; 2485} 2486 2487/** 2488 * Construct default screen configuration 2489 * 2490 * Given auto-detected (and, eventually, configured) values, 2491 * construct a usable configuration for the system 2492 * 2493 * canGrow indicates that the driver can resize the screen to larger than its 2494 * initially configured size via the config->funcs->resize hook. If TRUE, this 2495 * function will set virtualX and virtualY to match the initial configuration 2496 * and leave config->max{Width,Height} alone. If FALSE, it will bloat 2497 * virtual[XY] to include the largest modes and set config->max{Width,Height} 2498 * accordingly. 2499 */ 2500 2501Bool 2502xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow) 2503{ 2504 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2505 int o, c; 2506 xf86CrtcPtr *crtcs; 2507 DisplayModePtr *modes; 2508 Bool *enabled; 2509 int width, height; 2510 int i = scrn->scrnIndex; 2511 Bool have_outputs = TRUE; 2512 Bool ret; 2513 Bool success = FALSE; 2514 2515 /* Set up the device options */ 2516 config->options = xnfalloc(sizeof(xf86DeviceOptions)); 2517 memcpy(config->options, xf86DeviceOptions, sizeof(xf86DeviceOptions)); 2518 xf86ProcessOptions(scrn->scrnIndex, scrn->options, config->options); 2519 config->debug_modes = xf86ReturnOptValBool(config->options, 2520 OPTION_MODEDEBUG, FALSE); 2521 2522 if (scrn->display->virtualX && !scrn->is_gpu) 2523 width = scrn->display->virtualX; 2524 else 2525 width = config->maxWidth; 2526 if (scrn->display->virtualY && !scrn->is_gpu) 2527 height = scrn->display->virtualY; 2528 else 2529 height = config->maxHeight; 2530 2531 xf86ProbeOutputModes(scrn, width, height); 2532 2533 crtcs = xnfcalloc(config->num_output, sizeof(xf86CrtcPtr)); 2534 modes = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2535 enabled = xnfcalloc(config->num_output, sizeof(Bool)); 2536 2537 ret = xf86CollectEnabledOutputs(scrn, config, enabled); 2538 if (ret == FALSE && canGrow) { 2539 if (!scrn->is_gpu) 2540 xf86DrvMsg(i, X_WARNING, 2541 "Unable to find connected outputs - setting %dx%d " 2542 "initial framebuffer\n", 2543 NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT); 2544 have_outputs = FALSE; 2545 } 2546 else { 2547 if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) 2548 xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); 2549 else if (xf86TargetRightOf(scrn, config, modes, enabled, width, height)) 2550 xf86DrvMsg(i, X_INFO, "Using spanning desktop for initial modes\n"); 2551 else if (xf86TargetPreferred 2552 (scrn, config, modes, enabled, width, height)) 2553 xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); 2554 else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) 2555 xf86DrvMsg(i, X_INFO, 2556 "Using fuzzy aspect match for initial modes\n"); 2557 else if (xf86TargetFallback 2558 (scrn, config, modes, enabled, width, height)) 2559 xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); 2560 else 2561 xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); 2562 } 2563 2564 for (o = -1; nextEnabledOutput(config, enabled, &o);) { 2565 if (!modes[o]) 2566 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2567 "Output %s enabled but has no modes\n", 2568 config->output[o]->name); 2569 else 2570 xf86DrvMsg (scrn->scrnIndex, X_INFO, 2571 "Output %s using initial mode %s +%d+%d\n", 2572 config->output[o]->name, modes[o]->name, 2573 config->output[o]->initial_x, 2574 config->output[o]->initial_y); 2575 } 2576 2577 /* 2578 * Set the position of each output 2579 */ 2580 if (!xf86InitialOutputPositions(scrn, modes)) 2581 goto bailout; 2582 2583 /* 2584 * Set initial panning of each output 2585 */ 2586 xf86InitialPanning(scrn); 2587 2588 /* 2589 * Assign CRTCs to fit output configuration 2590 */ 2591 if (have_outputs && !xf86PickCrtcs(scrn, crtcs, modes, 0, width, height)) 2592 goto bailout; 2593 2594 /* XXX override xf86 common frame computation code */ 2595 2596 if (!scrn->is_gpu) { 2597 scrn->display->frameX0 = 0; 2598 scrn->display->frameY0 = 0; 2599 } 2600 2601 for (c = 0; c < config->num_crtc; c++) { 2602 xf86CrtcPtr crtc = config->crtc[c]; 2603 2604 crtc->enabled = FALSE; 2605 memset(&crtc->desiredMode, '\0', sizeof(crtc->desiredMode)); 2606 } 2607 2608 /* 2609 * Set initial configuration 2610 */ 2611 for (o = 0; o < config->num_output; o++) { 2612 xf86OutputPtr output = config->output[o]; 2613 DisplayModePtr mode = modes[o]; 2614 xf86CrtcPtr crtc = crtcs[o]; 2615 2616 if (mode && crtc) { 2617 xf86SaveModeContents(&crtc->desiredMode, mode); 2618 crtc->desiredRotation = output->initial_rotation; 2619 crtc->desiredX = output->initial_x; 2620 crtc->desiredY = output->initial_y; 2621 crtc->desiredTransformPresent = FALSE; 2622 crtc->enabled = TRUE; 2623 memcpy(&crtc->panningTotalArea, &output->initialTotalArea, 2624 sizeof(BoxRec)); 2625 memcpy(&crtc->panningTrackingArea, &output->initialTrackingArea, 2626 sizeof(BoxRec)); 2627 memcpy(crtc->panningBorder, output->initialBorder, 2628 4 * sizeof(INT16)); 2629 output->crtc = crtc; 2630 } 2631 else { 2632 output->crtc = NULL; 2633 } 2634 } 2635 2636 if (scrn->display->virtualX == 0 || scrn->is_gpu) { 2637 /* 2638 * Expand virtual size to cover the current config and potential mode 2639 * switches, if the driver can't enlarge the screen later. 2640 */ 2641 xf86DefaultScreenLimits(scrn, &width, &height, canGrow); 2642 2643 if (have_outputs == FALSE) { 2644 if (width < NO_OUTPUT_DEFAULT_WIDTH && 2645 height < NO_OUTPUT_DEFAULT_HEIGHT) { 2646 width = NO_OUTPUT_DEFAULT_WIDTH; 2647 height = NO_OUTPUT_DEFAULT_HEIGHT; 2648 } 2649 } 2650 2651 if (!scrn->is_gpu) { 2652 scrn->display->virtualX = width; 2653 scrn->display->virtualY = height; 2654 } 2655 } 2656 2657 if (width > scrn->virtualX) 2658 scrn->virtualX = width; 2659 if (height > scrn->virtualY) 2660 scrn->virtualY = height; 2661 2662 /* 2663 * Make sure the configuration isn't too small. 2664 */ 2665 if (width < config->minWidth || height < config->minHeight) 2666 goto bailout; 2667 2668 /* 2669 * Limit the crtc config to virtual[XY] if the driver can't grow the 2670 * desktop. 2671 */ 2672 if (!canGrow) { 2673 xf86CrtcSetSizeRange(scrn, config->minWidth, config->minHeight, 2674 width, height); 2675 } 2676 2677 xf86SetScrnInfoModes(scrn); 2678 2679 success = TRUE; 2680 bailout: 2681 free(crtcs); 2682 free(modes); 2683 free(enabled); 2684 return success; 2685} 2686 2687/* Turn a CRTC off, using the DPMS function and disabling the cursor */ 2688static void 2689xf86DisableCrtc(xf86CrtcPtr crtc) 2690{ 2691 if (xf86CrtcIsLeased(crtc)) 2692 return; 2693 2694 crtc->funcs->dpms(crtc, DPMSModeOff); 2695 xf86_crtc_hide_cursor(crtc); 2696} 2697 2698/* 2699 * Check the CRTC we're going to map each output to vs. it's current 2700 * CRTC. If they don't match, we have to disable the output and the CRTC 2701 * since the driver will have to re-route things. 2702 */ 2703static void 2704xf86PrepareOutputs(ScrnInfoPtr scrn) 2705{ 2706 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2707 int o; 2708 2709 for (o = 0; o < config->num_output; o++) { 2710 xf86OutputPtr output = config->output[o]; 2711 2712 if (xf86OutputIsLeased(output)) 2713 continue; 2714 2715#if RANDR_GET_CRTC_INTERFACE 2716 /* Disable outputs that are unused or will be re-routed */ 2717 if (!output->funcs->get_crtc || 2718 output->crtc != (*output->funcs->get_crtc) (output) || 2719 output->crtc == NULL) 2720#endif 2721 (*output->funcs->dpms) (output, DPMSModeOff); 2722 } 2723} 2724 2725static void 2726xf86PrepareCrtcs(ScrnInfoPtr scrn) 2727{ 2728 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2729 int c; 2730 2731 for (c = 0; c < config->num_crtc; c++) { 2732 xf86CrtcPtr crtc = config->crtc[c]; 2733#if RANDR_GET_CRTC_INTERFACE 2734 xf86OutputPtr output = NULL; 2735 uint32_t desired_outputs = 0, current_outputs = 0; 2736 int o; 2737 2738 if (xf86CrtcIsLeased(crtc)) 2739 continue; 2740 2741 for (o = 0; o < config->num_output; o++) { 2742 output = config->output[o]; 2743 if (output->crtc == crtc) 2744 desired_outputs |= (1 << o); 2745 /* If we can't tell where it's mapped, force it off */ 2746 if (!output->funcs->get_crtc) { 2747 desired_outputs = 0; 2748 break; 2749 } 2750 if ((*output->funcs->get_crtc) (output) == crtc) 2751 current_outputs |= (1 << o); 2752 } 2753 2754 /* 2755 * If mappings are different or the CRTC is unused, 2756 * we need to disable it 2757 */ 2758 if (desired_outputs != current_outputs || !desired_outputs) 2759 xf86DisableCrtc(crtc); 2760#else 2761 if (xf86CrtcIsLeased(crtc)) 2762 continue; 2763 2764 xf86DisableCrtc(crtc); 2765#endif 2766 } 2767} 2768 2769/* 2770 * Using the desired mode information in each crtc, set 2771 * modes (used in EnterVT functions, or at server startup) 2772 */ 2773 2774Bool 2775xf86SetDesiredModes(ScrnInfoPtr scrn) 2776{ 2777 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2778 xf86CrtcPtr crtc = config->crtc[0]; 2779 int enabled = 0, failed = 0; 2780 int c; 2781 2782 /* A driver with this hook will take care of this */ 2783 if (!crtc->funcs->set_mode_major) { 2784 xf86PrepareOutputs(scrn); 2785 xf86PrepareCrtcs(scrn); 2786 } 2787 2788 for (c = 0; c < config->num_crtc; c++) { 2789 xf86OutputPtr output = NULL; 2790 int o; 2791 RRTransformPtr transform; 2792 2793 crtc = config->crtc[c]; 2794 2795 /* Skip disabled CRTCs */ 2796 if (!crtc->enabled) 2797 continue; 2798 2799 if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc) 2800 output = xf86CompatOutput(scrn); 2801 else { 2802 for (o = 0; o < config->num_output; o++) 2803 if (config->output[o]->crtc == crtc) { 2804 output = config->output[o]; 2805 break; 2806 } 2807 } 2808 /* paranoia */ 2809 if (!output) 2810 continue; 2811 2812 /* Mark that we'll need to re-set the mode for sure */ 2813 memset(&crtc->mode, 0, sizeof(crtc->mode)); 2814 if (!crtc->desiredMode.CrtcHDisplay) { 2815 DisplayModePtr mode = 2816 xf86OutputFindClosestMode(output, scrn->currentMode); 2817 2818 if (!mode) 2819 return FALSE; 2820 xf86SaveModeContents(&crtc->desiredMode, mode); 2821 crtc->desiredRotation = RR_Rotate_0; 2822 crtc->desiredTransformPresent = FALSE; 2823 crtc->desiredX = 0; 2824 crtc->desiredY = 0; 2825 } 2826 2827 if (crtc->desiredTransformPresent) 2828 transform = &crtc->desiredTransform; 2829 else 2830 transform = NULL; 2831 if (xf86CrtcSetModeTransform 2832 (crtc, &crtc->desiredMode, crtc->desiredRotation, transform, 2833 crtc->desiredX, crtc->desiredY)) { 2834 ++enabled; 2835 } else { 2836 for (o = 0; o < config->num_output; o++) 2837 if (config->output[o]->crtc == crtc) 2838 config->output[o]->crtc = NULL; 2839 crtc->enabled = FALSE; 2840 ++failed; 2841 } 2842 } 2843 2844 xf86DisableUnusedFunctions(scrn); 2845 return enabled != 0 || failed == 0; 2846} 2847 2848/** 2849 * In the current world order, there are lists of modes per output, which may 2850 * or may not include the mode that was asked to be set by XFree86's mode 2851 * selection. Find the closest one, in the following preference order: 2852 * 2853 * - Equality 2854 * - Closer in size to the requested mode, but no larger 2855 * - Closer in refresh rate to the requested mode. 2856 */ 2857 2858DisplayModePtr 2859xf86OutputFindClosestMode(xf86OutputPtr output, DisplayModePtr desired) 2860{ 2861 DisplayModePtr best = NULL, scan = NULL; 2862 2863 for (scan = output->probed_modes; scan != NULL; scan = scan->next) { 2864 /* If there's an exact match, we're done. */ 2865 if (xf86ModesEqual(scan, desired)) { 2866 best = desired; 2867 break; 2868 } 2869 2870 /* Reject if it's larger than the desired mode. */ 2871 if (scan->HDisplay > desired->HDisplay || 2872 scan->VDisplay > desired->VDisplay) { 2873 continue; 2874 } 2875 2876 /* 2877 * If we haven't picked a best mode yet, use the first 2878 * one in the size range 2879 */ 2880 if (best == NULL) { 2881 best = scan; 2882 continue; 2883 } 2884 2885 /* Find if it's closer to the right size than the current best 2886 * option. 2887 */ 2888 if ((scan->HDisplay > best->HDisplay && 2889 scan->VDisplay >= best->VDisplay) || 2890 (scan->HDisplay >= best->HDisplay && 2891 scan->VDisplay > best->VDisplay)) { 2892 best = scan; 2893 continue; 2894 } 2895 2896 /* Find if it's still closer to the right refresh than the current 2897 * best resolution. 2898 */ 2899 if (scan->HDisplay == best->HDisplay && 2900 scan->VDisplay == best->VDisplay && 2901 (fabs(scan->VRefresh - desired->VRefresh) < 2902 fabs(best->VRefresh - desired->VRefresh))) { 2903 best = scan; 2904 } 2905 } 2906 return best; 2907} 2908 2909/** 2910 * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, 2911 * take the specified mode and apply it to the crtc connected to the compat 2912 * output. Then, find similar modes for the other outputs, as with the 2913 * InitialConfiguration code above. The goal is to clone the desired 2914 * mode across all outputs that are currently active. 2915 */ 2916 2917Bool 2918xf86SetSingleMode(ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) 2919{ 2920 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2921 Bool ok = TRUE; 2922 xf86OutputPtr compat_output; 2923 DisplayModePtr compat_mode = NULL; 2924 int c; 2925 2926 /* 2927 * Let the compat output drive the final mode selection 2928 */ 2929 compat_output = xf86CompatOutput(pScrn); 2930 if (compat_output) 2931 compat_mode = xf86OutputFindClosestMode(compat_output, desired); 2932 if (compat_mode) 2933 desired = compat_mode; 2934 2935 for (c = 0; c < config->num_crtc; c++) { 2936 xf86CrtcPtr crtc = config->crtc[c]; 2937 DisplayModePtr crtc_mode = NULL; 2938 int o; 2939 2940 if (!crtc->enabled) 2941 continue; 2942 2943 for (o = 0; o < config->num_output; o++) { 2944 xf86OutputPtr output = config->output[o]; 2945 DisplayModePtr output_mode; 2946 2947 /* skip outputs not on this crtc */ 2948 if (output->crtc != crtc) 2949 continue; 2950 2951 if (crtc_mode) { 2952 output_mode = xf86OutputFindClosestMode(output, crtc_mode); 2953 if (output_mode != crtc_mode) 2954 output->crtc = NULL; 2955 } 2956 else 2957 crtc_mode = xf86OutputFindClosestMode(output, desired); 2958 } 2959 if (!crtc_mode) { 2960 crtc->enabled = FALSE; 2961 continue; 2962 } 2963 if (!xf86CrtcSetModeTransform(crtc, crtc_mode, rotation, NULL, 0, 0)) 2964 ok = FALSE; 2965 else { 2966 xf86SaveModeContents(&crtc->desiredMode, crtc_mode); 2967 crtc->desiredRotation = rotation; 2968 crtc->desiredTransformPresent = FALSE; 2969 crtc->desiredX = 0; 2970 crtc->desiredY = 0; 2971 } 2972 } 2973 xf86DisableUnusedFunctions(pScrn); 2974#ifdef RANDR_12_INTERFACE 2975 xf86RandR12TellChanged(pScrn->pScreen); 2976#endif 2977 return ok; 2978} 2979 2980/** 2981 * Set the DPMS power mode of all outputs and CRTCs. 2982 * 2983 * If the new mode is off, it will turn off outputs and then CRTCs. 2984 * Otherwise, it will affect CRTCs before outputs. 2985 */ 2986void 2987xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) 2988{ 2989 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2990 int i; 2991 2992 if (!scrn->vtSema) 2993 return; 2994 2995 if (mode == DPMSModeOff) { 2996 for (i = 0; i < config->num_output; i++) { 2997 xf86OutputPtr output = config->output[i]; 2998 2999 if (!xf86OutputIsLeased(output) && output->crtc != NULL) 3000 (*output->funcs->dpms) (output, mode); 3001 } 3002 } 3003 3004 for (i = 0; i < config->num_crtc; i++) { 3005 xf86CrtcPtr crtc = config->crtc[i]; 3006 3007 if (crtc->enabled) 3008 (*crtc->funcs->dpms) (crtc, mode); 3009 } 3010 3011 if (mode != DPMSModeOff) { 3012 for (i = 0; i < config->num_output; i++) { 3013 xf86OutputPtr output = config->output[i]; 3014 3015 if (!xf86OutputIsLeased(output) && output->crtc != NULL) 3016 (*output->funcs->dpms) (output, mode); 3017 } 3018 } 3019} 3020 3021/** 3022 * Implement the screensaver by just calling down into the driver DPMS hooks. 3023 * 3024 * Even for monitors with no DPMS support, by the definition of our DPMS hooks, 3025 * the outputs will still get disabled (blanked). 3026 */ 3027Bool 3028xf86SaveScreen(ScreenPtr pScreen, int mode) 3029{ 3030 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 3031 3032 if (xf86IsUnblank(mode)) 3033 xf86DPMSSet(pScrn, DPMSModeOn, 0); 3034 else 3035 xf86DPMSSet(pScrn, DPMSModeOff, 0); 3036 3037 return TRUE; 3038} 3039 3040/** 3041 * Disable all inactive crtcs and outputs 3042 */ 3043void 3044xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) 3045{ 3046 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3047 int o, c; 3048 3049 for (o = 0; o < xf86_config->num_output; o++) { 3050 xf86OutputPtr output = xf86_config->output[o]; 3051 3052 if (!output->crtc) 3053 (*output->funcs->dpms) (output, DPMSModeOff); 3054 } 3055 3056 for (c = 0; c < xf86_config->num_crtc; c++) { 3057 xf86CrtcPtr crtc = xf86_config->crtc[c]; 3058 3059 if (!crtc->enabled) { 3060 xf86DisableCrtc(crtc); 3061 memset(&crtc->mode, 0, sizeof(crtc->mode)); 3062 xf86RotateDestroy(crtc); 3063 crtc->active = FALSE; 3064 } 3065 } 3066 if (pScrn->pScreen) 3067 xf86_crtc_notify(pScrn->pScreen); 3068 if (pScrn->ModeSet) 3069 pScrn->ModeSet(pScrn); 3070 if (pScrn->pScreen) { 3071 if (pScrn->pScreen->isGPU) 3072 xf86CursorResetCursor(pScrn->pScreen->current_master); 3073 else 3074 xf86CursorResetCursor(pScrn->pScreen); 3075 } 3076} 3077 3078#ifdef RANDR_12_INTERFACE 3079 3080#define EDID_ATOM_NAME "EDID" 3081 3082/** 3083 * Set the RandR EDID property 3084 */ 3085static void 3086xf86OutputSetEDIDProperty(xf86OutputPtr output, void *data, int data_len) 3087{ 3088 Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); 3089 3090 /* This may get called before the RandR resources have been created */ 3091 if (output->randr_output == NULL) 3092 return; 3093 3094 if (data_len != 0) { 3095 RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, 3096 PropModeReplace, data_len, data, FALSE, TRUE); 3097 } 3098 else { 3099 RRDeleteOutputProperty(output->randr_output, edid_atom); 3100 } 3101} 3102 3103#define TILE_ATOM_NAME "TILE" 3104/* changing this in the future could be tricky as people may hardcode 8 */ 3105#define TILE_PROP_NUM_ITEMS 8 3106static void 3107xf86OutputSetTileProperty(xf86OutputPtr output) 3108{ 3109 Atom tile_atom = MakeAtom(TILE_ATOM_NAME, sizeof(TILE_ATOM_NAME) - 1, TRUE); 3110 3111 /* This may get called before the RandR resources have been created */ 3112 if (output->randr_output == NULL) 3113 return; 3114 3115 if (output->tile_info.group_id != 0) { 3116 RRChangeOutputProperty(output->randr_output, tile_atom, XA_INTEGER, 32, 3117 PropModeReplace, TILE_PROP_NUM_ITEMS, (uint32_t *)&output->tile_info, FALSE, TRUE); 3118 } 3119 else { 3120 RRDeleteOutputProperty(output->randr_output, tile_atom); 3121 } 3122} 3123 3124#endif 3125 3126/* Pull out a phyiscal size from a detailed timing if available. */ 3127struct det_phySize_parameter { 3128 xf86OutputPtr output; 3129 ddc_quirk_t quirks; 3130 Bool ret; 3131}; 3132 3133static void 3134handle_detailed_physical_size(struct detailed_monitor_section 3135 *det_mon, void *data) 3136{ 3137 struct det_phySize_parameter *p; 3138 3139 p = (struct det_phySize_parameter *) data; 3140 3141 if (p->ret == TRUE) 3142 return; 3143 3144 xf86DetTimingApplyQuirks(det_mon, p->quirks, 3145 p->output->MonInfo->features.hsize, 3146 p->output->MonInfo->features.vsize); 3147 if (det_mon->type == DT && 3148 det_mon->section.d_timings.h_size != 0 && 3149 det_mon->section.d_timings.v_size != 0) { 3150 /* some sanity checking for aspect ratio: 3151 assume any h / v (or v / h) > 2.4 to be bogus. 3152 This would even include cinemascope */ 3153 if (((det_mon->section.d_timings.h_size * 5) < 3154 (det_mon->section.d_timings.v_size * 12)) && 3155 ((det_mon->section.d_timings.v_size * 5) < 3156 (det_mon->section.d_timings.h_size * 12))) { 3157 p->output->mm_width = det_mon->section.d_timings.h_size; 3158 p->output->mm_height = det_mon->section.d_timings.v_size; 3159 p->ret = TRUE; 3160 } else 3161 xf86DrvMsg(p->output->scrn->scrnIndex, X_WARNING, 3162 "Output %s: Strange aspect ratio (%i/%i), " 3163 "consider adding a quirk\n", p->output->name, 3164 det_mon->section.d_timings.h_size, 3165 det_mon->section.d_timings.v_size); 3166 } 3167} 3168 3169Bool 3170xf86OutputParseKMSTile(const char *tile_data, int tile_length, 3171 struct xf86CrtcTileInfo *tile_info) 3172{ 3173 int ret; 3174 3175 ret = sscanf(tile_data, "%d:%d:%d:%d:%d:%d:%d:%d", 3176 &tile_info->group_id, 3177 &tile_info->flags, 3178 &tile_info->num_h_tile, 3179 &tile_info->num_v_tile, 3180 &tile_info->tile_h_loc, 3181 &tile_info->tile_v_loc, 3182 &tile_info->tile_h_size, 3183 &tile_info->tile_v_size); 3184 if (ret != 8) 3185 return FALSE; 3186 return TRUE; 3187} 3188 3189void 3190xf86OutputSetTile(xf86OutputPtr output, struct xf86CrtcTileInfo *tile_info) 3191{ 3192 if (tile_info) 3193 output->tile_info = *tile_info; 3194 else 3195 memset(&output->tile_info, 0, sizeof(output->tile_info)); 3196#ifdef RANDR_12_INTERFACE 3197 xf86OutputSetTileProperty(output); 3198#endif 3199} 3200 3201/** 3202 * Set the EDID information for the specified output 3203 */ 3204void 3205xf86OutputSetEDID(xf86OutputPtr output, xf86MonPtr edid_mon) 3206{ 3207 ScrnInfoPtr scrn = output->scrn; 3208 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3209 Bool debug_modes = config->debug_modes || xf86Initialising; 3210 3211#ifdef RANDR_12_INTERFACE 3212 int size; 3213#endif 3214 3215 free(output->MonInfo); 3216 3217 output->MonInfo = edid_mon; 3218 output->mm_width = 0; 3219 output->mm_height = 0; 3220 3221 if (debug_modes) { 3222 xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", 3223 output->name); 3224 xf86PrintEDID(edid_mon); 3225 } 3226 3227 /* Set the DDC properties for the 'compat' output */ 3228 /* GPU screens don't have a root window */ 3229 if (output == xf86CompatOutput(scrn) && !scrn->is_gpu) 3230 xf86SetDDCproperties(scrn, edid_mon); 3231 3232#ifdef RANDR_12_INTERFACE 3233 /* Set the RandR output properties */ 3234 size = 0; 3235 if (edid_mon) { 3236 if (edid_mon->ver.version == 1) { 3237 size = 128; 3238 if (edid_mon->flags & EDID_COMPLETE_RAWDATA) 3239 size += edid_mon->no_sections * 128; 3240 } 3241 else if (edid_mon->ver.version == 2) 3242 size = 256; 3243 } 3244 xf86OutputSetEDIDProperty(output, edid_mon ? edid_mon->rawData : NULL, 3245 size); 3246#endif 3247 3248 if (edid_mon) { 3249 3250 struct det_phySize_parameter p; 3251 3252 p.output = output; 3253 p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex, edid_mon, FALSE); 3254 p.ret = FALSE; 3255 xf86ForEachDetailedBlock(edid_mon, handle_detailed_physical_size, &p); 3256 3257 /* if no mm size is available from a detailed timing, check the max size field */ 3258 if ((!output->mm_width || !output->mm_height) && 3259 (edid_mon->features.hsize && edid_mon->features.vsize)) { 3260 output->mm_width = edid_mon->features.hsize * 10; 3261 output->mm_height = edid_mon->features.vsize * 10; 3262 } 3263 } 3264} 3265 3266/** 3267 * Return the list of modes supported by the EDID information 3268 * stored in 'output' 3269 */ 3270DisplayModePtr 3271xf86OutputGetEDIDModes(xf86OutputPtr output) 3272{ 3273 ScrnInfoPtr scrn = output->scrn; 3274 xf86MonPtr edid_mon = output->MonInfo; 3275 3276 if (!edid_mon) 3277 return NULL; 3278 return xf86DDCGetModes(scrn->scrnIndex, edid_mon); 3279} 3280 3281/* maybe we should care about DDC1? meh. */ 3282xf86MonPtr 3283xf86OutputGetEDID(xf86OutputPtr output, I2CBusPtr pDDCBus) 3284{ 3285 ScrnInfoPtr scrn = output->scrn; 3286 xf86MonPtr mon; 3287 3288 mon = xf86DoEEDID(scrn, pDDCBus, TRUE); 3289 if (mon) 3290 xf86DDCApplyQuirks(scrn->scrnIndex, mon); 3291 3292 return mon; 3293} 3294 3295static const char *_xf86ConnectorNames[] = { 3296 "None", "VGA", "DVI-I", "DVI-D", 3297 "DVI-A", "Composite", "S-Video", 3298 "Component", "LFP", "Proprietary", 3299 "HDMI", "DisplayPort", 3300}; 3301 3302const char * 3303xf86ConnectorGetName(xf86ConnectorType connector) 3304{ 3305 return _xf86ConnectorNames[connector]; 3306} 3307 3308#ifdef XV 3309static void 3310x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 3311{ 3312 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 3313 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 3314 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 3315 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 3316 3317 if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) 3318 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 3319} 3320 3321static void 3322x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 3323{ 3324 if (crtc->enabled) { 3325 crtc_box->x1 = crtc->x; 3326 crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 3327 crtc_box->y1 = crtc->y; 3328 crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 3329 } 3330 else 3331 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 3332} 3333 3334static int 3335xf86_crtc_box_area(BoxPtr box) 3336{ 3337 return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); 3338} 3339 3340/* 3341 * Return the crtc covering 'box'. If two crtcs cover a portion of 3342 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 3343 * with greater coverage 3344 */ 3345 3346static xf86CrtcPtr 3347xf86_covering_crtc(ScrnInfoPtr pScrn, 3348 BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret) 3349{ 3350 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3351 xf86CrtcPtr crtc, best_crtc; 3352 int coverage, best_coverage; 3353 int c; 3354 BoxRec crtc_box, cover_box; 3355 3356 best_crtc = NULL; 3357 best_coverage = 0; 3358 crtc_box_ret->x1 = 0; 3359 crtc_box_ret->x2 = 0; 3360 crtc_box_ret->y1 = 0; 3361 crtc_box_ret->y2 = 0; 3362 for (c = 0; c < xf86_config->num_crtc; c++) { 3363 crtc = xf86_config->crtc[c]; 3364 x86_crtc_box(crtc, &crtc_box); 3365 x86_crtc_box_intersect(&cover_box, &crtc_box, box); 3366 coverage = xf86_crtc_box_area(&cover_box); 3367 if (coverage && crtc == desired) { 3368 *crtc_box_ret = crtc_box; 3369 return crtc; 3370 } 3371 else if (coverage > best_coverage) { 3372 *crtc_box_ret = crtc_box; 3373 best_crtc = crtc; 3374 best_coverage = coverage; 3375 } 3376 } 3377 return best_crtc; 3378} 3379 3380/* 3381 * For overlay video, compute the relevant CRTC and 3382 * clip video to that. 3383 * 3384 * returning FALSE means there was a memory failure of some kind, 3385 * not that the video shouldn't be displayed 3386 */ 3387 3388Bool 3389xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, 3390 xf86CrtcPtr * crtc_ret, 3391 xf86CrtcPtr desired_crtc, 3392 BoxPtr dst, 3393 INT32 *xa, 3394 INT32 *xb, 3395 INT32 *ya, 3396 INT32 *yb, RegionPtr reg, INT32 width, INT32 height) 3397{ 3398 Bool ret; 3399 RegionRec crtc_region_local; 3400 RegionPtr crtc_region = reg; 3401 3402 if (crtc_ret) { 3403 BoxRec crtc_box; 3404 xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, 3405 desired_crtc, 3406 &crtc_box); 3407 3408 if (crtc) { 3409 RegionInit(&crtc_region_local, &crtc_box, 1); 3410 crtc_region = &crtc_region_local; 3411 RegionIntersect(crtc_region, crtc_region, reg); 3412 } 3413 *crtc_ret = crtc; 3414 } 3415 3416 ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, 3417 crtc_region, width, height); 3418 3419 if (crtc_region != reg) 3420 RegionUninit(&crtc_region_local); 3421 3422 return ret; 3423} 3424#endif 3425 3426xf86_crtc_notify_proc_ptr 3427xf86_wrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr new) 3428{ 3429 if (xf86CrtcConfigPrivateIndex != -1) { 3430 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3431 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3432 xf86_crtc_notify_proc_ptr old; 3433 3434 old = config->xf86_crtc_notify; 3435 config->xf86_crtc_notify = new; 3436 return old; 3437 } 3438 return NULL; 3439} 3440 3441void 3442xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) 3443{ 3444 if (xf86CrtcConfigPrivateIndex != -1) { 3445 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3446 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3447 3448 config->xf86_crtc_notify = old; 3449 } 3450} 3451 3452void 3453xf86_crtc_notify(ScreenPtr screen) 3454{ 3455 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3456 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3457 3458 if (config->xf86_crtc_notify) 3459 config->xf86_crtc_notify(screen); 3460} 3461 3462Bool 3463xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) 3464{ 3465 if (xf86CrtcConfigPrivateIndex != -1) { 3466 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3467 xf86CrtcPtr crtc; 3468 3469 /* for multiple drivers loaded we need this */ 3470 if (!xf86_config) 3471 return FALSE; 3472 if (xf86_config->num_crtc == 0) 3473 return FALSE; 3474 crtc = xf86_config->crtc[0]; 3475 3476 return crtc->funcs->gamma_set != NULL; 3477 } 3478 3479 return FALSE; 3480} 3481 3482void 3483xf86ProviderSetup(ScrnInfoPtr scrn, 3484 const xf86ProviderFuncsRec *funcs, const char *name) 3485{ 3486 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 3487 3488 assert(!xf86_config->name); 3489 assert(name); 3490 3491 xf86_config->name = strdup(name); 3492 xf86_config->provider_funcs = funcs; 3493#ifdef RANDR_12_INTERFACE 3494 xf86_config->randr_provider = NULL; 3495#endif 3496} 3497 3498void 3499xf86DetachAllCrtc(ScrnInfoPtr scrn) 3500{ 3501 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 3502 int i; 3503 3504 for (i = 0; i < xf86_config->num_crtc; i++) { 3505 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3506 3507 if (crtc->randr_crtc) 3508 RRCrtcDetachScanoutPixmap(crtc->randr_crtc); 3509 3510 /* dpms off */ 3511 xf86DisableCrtc(crtc); 3512 /* force a reset the next time its used */ 3513 crtc->randr_crtc->mode = NULL; 3514 crtc->mode.HDisplay = 0; 3515 crtc->x = crtc->y = 0; 3516 } 3517} 3518