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