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