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