xf86Crtc.c revision 6747b715
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 } else { 375 crtc->x = saved_x; 376 crtc->y = saved_y; 377 crtc->rotation = saved_rotation; 378 crtc->mode = saved_mode; 379 if (saved_transform_present) 380 RRTransformCopy (&crtc->transform, &saved_transform); 381 crtc->transformPresent = saved_transform_present; 382 } 383 384 free(adjusted_mode->name); 385 free(adjusted_mode); 386 387 if (didLock) 388 crtc->funcs->unlock (crtc); 389 390 return ret; 391} 392 393/** 394 * Sets the given video mode on the given crtc, but without providing 395 * a transform 396 */ 397Bool 398xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, 399 int x, int y) 400{ 401 return xf86CrtcSetModeTransform (crtc, mode, rotation, NULL, x, y); 402} 403 404/** 405 * Pans the screen, does not change the mode 406 */ 407void 408xf86CrtcSetOrigin (xf86CrtcPtr crtc, int x, int y) 409{ 410 crtc->x = x; 411 crtc->y = y; 412 if (crtc->funcs->set_origin) { 413 if (!xf86CrtcRotate (crtc)) 414 return; 415 crtc->funcs->set_origin (crtc, x, y); 416 } 417 else 418 xf86CrtcSetMode (crtc, &crtc->mode, crtc->rotation, x, y); 419} 420 421/* 422 * Output functions 423 */ 424 425extern XF86ConfigPtr xf86configptr; 426 427typedef enum { 428 OPTION_PREFERRED_MODE, 429 OPTION_POSITION, 430 OPTION_BELOW, 431 OPTION_RIGHT_OF, 432 OPTION_ABOVE, 433 OPTION_LEFT_OF, 434 OPTION_ENABLE, 435 OPTION_DISABLE, 436 OPTION_MIN_CLOCK, 437 OPTION_MAX_CLOCK, 438 OPTION_IGNORE, 439 OPTION_ROTATE, 440 OPTION_PANNING, 441 OPTION_PRIMARY, 442 OPTION_DEFAULT_MODES, 443} OutputOpts; 444 445static OptionInfoRec xf86OutputOptions[] = { 446 {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, 447 {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, 448 {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, 449 {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, 450 {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, 451 {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, 452 {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, 453 {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, 454 {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, 455 {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, 456 {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, 457 {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, 458 {OPTION_PANNING, "Panning", OPTV_STRING, {0}, FALSE }, 459 {OPTION_PRIMARY, "Primary", OPTV_BOOLEAN, {0}, FALSE }, 460 {OPTION_DEFAULT_MODES, "DefaultModes", OPTV_BOOLEAN, {0}, FALSE }, 461 {-1, NULL, OPTV_NONE, {0}, FALSE }, 462}; 463 464enum { 465 OPTION_MODEDEBUG, 466}; 467 468static OptionInfoRec xf86DeviceOptions[] = { 469 {OPTION_MODEDEBUG, "ModeDebug", OPTV_BOOLEAN, {0}, FALSE }, 470 {-1, NULL, OPTV_NONE, {0}, FALSE }, 471}; 472 473static void 474xf86OutputSetMonitor (xf86OutputPtr output) 475{ 476 char *option_name; 477 static const char monitor_prefix[] = "monitor-"; 478 char *monitor; 479 480 if (!output->name) 481 return; 482 483 free(output->options); 484 485 output->options = xnfalloc (sizeof (xf86OutputOptions)); 486 memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); 487 488 option_name = xnfalloc (strlen (monitor_prefix) + 489 strlen (output->name) + 1); 490 strcpy (option_name, monitor_prefix); 491 strcat (option_name, output->name); 492 monitor = xf86findOptionValue (output->scrn->options, option_name); 493 if (!monitor) 494 monitor = output->name; 495 else 496 xf86MarkOptionUsedByName (output->scrn->options, option_name); 497 free(option_name); 498 output->conf_monitor = xf86findMonitor (monitor, 499 xf86configptr->conf_monitor_lst); 500 /* 501 * Find the monitor section of the screen and use that 502 */ 503 if (!output->conf_monitor && output->use_screen_monitor) 504 output->conf_monitor = xf86findMonitor (output->scrn->monitor->id, 505 xf86configptr->conf_monitor_lst); 506 if (output->conf_monitor) 507 { 508 xf86DrvMsg (output->scrn->scrnIndex, X_INFO, 509 "Output %s using monitor section %s\n", 510 output->name, output->conf_monitor->mon_identifier); 511 xf86ProcessOptions (output->scrn->scrnIndex, 512 output->conf_monitor->mon_option_lst, 513 output->options); 514 } 515 else 516 xf86DrvMsg (output->scrn->scrnIndex, X_INFO, 517 "Output %s has no monitor section\n", 518 output->name); 519} 520 521static Bool 522xf86OutputEnabled (xf86OutputPtr output, Bool strict) 523{ 524 Bool enable, disable; 525 526 /* check to see if this output was enabled in the config file */ 527 if (xf86GetOptValBool (output->options, OPTION_ENABLE, &enable) && enable) 528 { 529 xf86DrvMsg (output->scrn->scrnIndex, X_INFO, 530 "Output %s enabled by config file\n", output->name); 531 return TRUE; 532 } 533 /* or if this output was disabled in the config file */ 534 if (xf86GetOptValBool (output->options, OPTION_DISABLE, &disable) && disable) 535 { 536 xf86DrvMsg (output->scrn->scrnIndex, X_INFO, 537 "Output %s disabled by config file\n", output->name); 538 return FALSE; 539 } 540 541 /* If not, try to only light up the ones we know are connected */ 542 if (strict) { 543 enable = output->status == XF86OutputStatusConnected; 544 } 545 /* But if that fails, try to light up even outputs we're unsure of */ 546 else { 547 enable = output->status != XF86OutputStatusDisconnected; 548 } 549 550 xf86DrvMsg (output->scrn->scrnIndex, X_INFO, 551 "Output %s %sconnected\n", output->name, enable ? "" : "dis"); 552 return enable; 553} 554 555static Bool 556xf86OutputIgnored (xf86OutputPtr output) 557{ 558 return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); 559} 560 561static char *direction[4] = { 562 "normal", 563 "left", 564 "inverted", 565 "right" 566}; 567 568static Rotation 569xf86OutputInitialRotation (xf86OutputPtr output) 570{ 571 char *rotate_name = xf86GetOptValString (output->options, 572 OPTION_ROTATE); 573 int i; 574 575 if (!rotate_name) { 576 if (output->initial_rotation) 577 return output->initial_rotation; 578 return RR_Rotate_0; 579 } 580 581 for (i = 0; i < 4; i++) 582 if (xf86nameCompare (direction[i], rotate_name) == 0) 583 return 1 << i; 584 return RR_Rotate_0; 585} 586 587xf86OutputPtr 588xf86OutputCreate (ScrnInfoPtr scrn, 589 const xf86OutputFuncsRec *funcs, 590 const char *name) 591{ 592 xf86OutputPtr output, *outputs; 593 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 594 int len; 595 Bool primary; 596 597 if (name) 598 len = strlen (name) + 1; 599 else 600 len = 0; 601 602 output = calloc(sizeof (xf86OutputRec) + len, 1); 603 if (!output) 604 return NULL; 605 output->scrn = scrn; 606 output->funcs = funcs; 607 if (name) 608 { 609 output->name = (char *) (output + 1); 610 strcpy (output->name, name); 611 } 612 output->subpixel_order = SubPixelUnknown; 613 /* 614 * Use the old per-screen monitor section for the first output 615 */ 616 output->use_screen_monitor = (xf86_config->num_output == 0); 617#ifdef RANDR_12_INTERFACE 618 output->randr_output = NULL; 619#endif 620 if (name) 621 { 622 xf86OutputSetMonitor (output); 623 if (xf86OutputIgnored (output)) 624 { 625 free(output); 626 return FALSE; 627 } 628 } 629 630 631 if (xf86_config->output) 632 outputs = realloc(xf86_config->output, 633 (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); 634 else 635 outputs = malloc((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); 636 if (!outputs) 637 { 638 free(output); 639 return NULL; 640 } 641 642 xf86_config->output = outputs; 643 644 if (xf86GetOptValBool (output->options, OPTION_PRIMARY, &primary) && primary) 645 { 646 memmove(xf86_config->output + 1, xf86_config->output, 647 xf86_config->num_output * sizeof (xf86OutputPtr)); 648 xf86_config->output[0] = output; 649 } 650 else 651 { 652 xf86_config->output[xf86_config->num_output] = output; 653 } 654 655 xf86_config->num_output++; 656 657 return output; 658} 659 660Bool 661xf86OutputRename (xf86OutputPtr output, const char *name) 662{ 663 int len = strlen(name) + 1; 664 char *newname = malloc(len); 665 666 if (!newname) 667 return FALSE; /* so sorry... */ 668 669 strcpy (newname, name); 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 enum { sync_config, sync_edid, sync_default }; 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 = xf86ReturnOptValBool(output->options, OPTION_DEFAULT_MODES, TRUE); 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 edid_monitor = output->MonInfo; 1617 1618 if (edid_monitor) 1619 { 1620 struct det_monrec_parameter p; 1621 struct disp_features *features = &edid_monitor->features; 1622 1623 /* if display is not continuous-frequency, don't add default modes */ 1624 if (!GTF_SUPPORTED(features->msc)) 1625 add_default_modes = FALSE; 1626 1627 p.mon_rec = &mon_rec; 1628 p.max_clock = &max_clock; 1629 p.set_hsync = mon_rec.nHsync == 0; 1630 p.set_vrefresh = mon_rec.nVrefresh == 0; 1631 p.sync_source = &sync_source; 1632 1633 xf86ForEachDetailedBlock(edid_monitor, 1634 handle_detailed_monrec, 1635 &p); 1636 } 1637 1638 if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, 1639 OPTUNITS_KHZ, &clock)) 1640 min_clock = (int) clock; 1641 if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, 1642 OPTUNITS_KHZ, &clock)) 1643 max_clock = (int) clock; 1644 1645 /* If we still don't have a sync range, guess wildly */ 1646 if (!mon_rec.nHsync || !mon_rec.nVrefresh) 1647 GuessRangeFromModes(&mon_rec, output_modes); 1648 1649 /* 1650 * These limits will end up setting a 1024x768@60Hz mode by default, 1651 * which seems like a fairly good mode to use when nothing else is 1652 * specified 1653 */ 1654 if (mon_rec.nHsync == 0) 1655 { 1656 mon_rec.hsync[0].lo = 31.0; 1657 mon_rec.hsync[0].hi = 55.0; 1658 mon_rec.nHsync = 1; 1659 } 1660 if (mon_rec.nVrefresh == 0) 1661 { 1662 mon_rec.vrefresh[0].lo = 58.0; 1663 mon_rec.vrefresh[0].hi = 62.0; 1664 mon_rec.nVrefresh = 1; 1665 } 1666 1667 if (add_default_modes) 1668 default_modes = xf86GetDefaultModes (); 1669 1670 /* 1671 * If this is not an RB monitor, remove RB modes from the default 1672 * pool. RB modes from the config or the monitor itself are fine. 1673 */ 1674 if (!mon_rec.reducedblanking) 1675 xf86ValidateModesReducedBlanking (scrn, default_modes); 1676 1677 if (sync_source == sync_config) 1678 { 1679 /* 1680 * Check output and config modes against sync range from config file 1681 */ 1682 xf86ValidateModesSync (scrn, output_modes, &mon_rec); 1683 xf86ValidateModesSync (scrn, config_modes, &mon_rec); 1684 } 1685 /* 1686 * Check default modes against sync range 1687 */ 1688 xf86ValidateModesSync (scrn, default_modes, &mon_rec); 1689 /* 1690 * Check default modes against monitor max clock 1691 */ 1692 if (max_clock) { 1693 xf86ValidateModesClocks(scrn, default_modes, 1694 &min_clock, &max_clock, 1); 1695 xf86ValidateModesClocks(scrn, output_modes, 1696 &min_clock, &max_clock, 1); 1697 } 1698 1699 output->probed_modes = NULL; 1700 output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); 1701 output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); 1702 output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); 1703 1704 /* 1705 * Check all modes against max size, interlace, and doublescan 1706 */ 1707 if (maxX && maxY) 1708 xf86ValidateModesSize (scrn, output->probed_modes, 1709 maxX, maxY, 0); 1710 1711 { 1712 int flags = (output->interlaceAllowed ? V_INTERLACE : 0) | 1713 (output->doubleScanAllowed ? V_DBLSCAN : 0); 1714 xf86ValidateModesFlags (scrn, output->probed_modes, flags); 1715 } 1716 1717 /* 1718 * Check all modes against output 1719 */ 1720 for (mode = output->probed_modes; mode != NULL; mode = mode->next) 1721 if (mode->status == MODE_OK) 1722 mode->status = (*output->funcs->mode_valid)(output, mode); 1723 1724 xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes); 1725 1726 output->probed_modes = xf86SortModes (output->probed_modes); 1727 1728 /* Check for a configured preference for a particular mode */ 1729 preferred_mode = preferredMode(scrn, output); 1730 1731 if (preferred_mode) 1732 { 1733 for (mode = output->probed_modes; mode; mode = mode->next) 1734 { 1735 if (!strcmp (preferred_mode, mode->name)) 1736 { 1737 if (mode != output->probed_modes) 1738 { 1739 if (mode->prev) 1740 mode->prev->next = mode->next; 1741 if (mode->next) 1742 mode->next->prev = mode->prev; 1743 mode->next = output->probed_modes; 1744 output->probed_modes->prev = mode; 1745 mode->prev = NULL; 1746 output->probed_modes = mode; 1747 } 1748 mode->type |= (M_T_PREFERRED|M_T_USERPREF); 1749 break; 1750 } 1751 } 1752 } 1753 1754 output->initial_rotation = xf86OutputInitialRotation (output); 1755 1756 if (debug_modes) { 1757 if (output->probed_modes != NULL) { 1758 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1759 "Printing probed modes for output %s\n", 1760 output->name); 1761 } else { 1762 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1763 "No remaining probed modes for output %s\n", 1764 output->name); 1765 } 1766 } 1767 for (mode = output->probed_modes; mode != NULL; mode = mode->next) 1768 { 1769 /* The code to choose the best mode per pipe later on will require 1770 * VRefresh to be set. 1771 */ 1772 mode->VRefresh = xf86ModeVRefresh(mode); 1773 xf86SetModeCrtc(mode, INTERLACE_HALVE_V); 1774 1775 if (debug_modes) 1776 xf86PrintModeline(scrn->scrnIndex, mode); 1777 } 1778 } 1779} 1780 1781 1782/** 1783 * Copy one of the output mode lists to the ScrnInfo record 1784 */ 1785 1786/* XXX where does this function belong? Here? */ 1787void 1788xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); 1789 1790static DisplayModePtr 1791biggestMode(DisplayModePtr a, DisplayModePtr b) 1792{ 1793 int A, B; 1794 1795 if (!a) 1796 return b; 1797 if (!b) 1798 return a; 1799 1800 A = a->HDisplay * a->VDisplay; 1801 B = b->HDisplay * b->VDisplay; 1802 1803 if (A > B) 1804 return a; 1805 1806 return b; 1807} 1808 1809static xf86OutputPtr 1810SetCompatOutput(xf86CrtcConfigPtr config) 1811{ 1812 xf86OutputPtr output = NULL, test = NULL; 1813 DisplayModePtr maxmode = NULL, testmode, mode; 1814 int o, compat = -1, count, mincount = 0; 1815 1816 /* Look for one that's definitely connected */ 1817 for (o = 0; o < config->num_output; o++) 1818 { 1819 test = config->output[o]; 1820 if (!test->crtc) 1821 continue; 1822 if (test->status != XF86OutputStatusConnected) 1823 continue; 1824 if (!test->probed_modes) 1825 continue; 1826 1827 testmode = mode = test->probed_modes; 1828 for (count = 0; mode; mode = mode->next, count++) 1829 testmode = biggestMode(testmode, mode); 1830 1831 if (!output) { 1832 output = test; 1833 compat = o; 1834 maxmode = testmode; 1835 mincount = count; 1836 } else if (maxmode == biggestMode(maxmode, testmode)) { 1837 output = test; 1838 compat = o; 1839 maxmode = testmode; 1840 mincount = count; 1841 } else if ((maxmode->HDisplay == testmode->HDisplay) && 1842 (maxmode->VDisplay == testmode->VDisplay) && 1843 count <= mincount) { 1844 output = test; 1845 compat = o; 1846 maxmode = testmode; 1847 mincount = count; 1848 } 1849 } 1850 1851 /* If we didn't find one, take anything we can get */ 1852 if (!output) 1853 { 1854 for (o = 0; o < config->num_output; o++) 1855 { 1856 test = config->output[o]; 1857 if (!test->crtc) 1858 continue; 1859 if (!test->probed_modes) 1860 continue; 1861 1862 if (!output) { 1863 output = test; 1864 compat = o; 1865 } else if (test->probed_modes->HDisplay < output->probed_modes->HDisplay) { 1866 output = test; 1867 compat = o; 1868 } 1869 } 1870 } 1871 1872 if (compat >= 0) { 1873 config->compat_output = compat; 1874 } else { 1875 /* Don't change the compat output when no valid outputs found */ 1876 output = config->output[config->compat_output]; 1877 } 1878 1879 return output; 1880} 1881 1882void 1883xf86SetScrnInfoModes (ScrnInfoPtr scrn) 1884{ 1885 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1886 xf86OutputPtr output; 1887 xf86CrtcPtr crtc; 1888 DisplayModePtr last, mode = NULL; 1889 1890 output = SetCompatOutput(config); 1891 1892 if (!output) 1893 return; /* punt */ 1894 1895 crtc = output->crtc; 1896 1897 /* Clear any existing modes from scrn->modes */ 1898 while (scrn->modes != NULL) 1899 xf86DeleteMode(&scrn->modes, scrn->modes); 1900 1901 /* Set scrn->modes to the mode list for the 'compat' output */ 1902 scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); 1903 1904 if (crtc) { 1905 for (mode = scrn->modes; mode; mode = mode->next) 1906 if (xf86ModesEqual (mode, &crtc->desiredMode)) 1907 break; 1908 } 1909 1910 if (scrn->modes != NULL) { 1911 /* For some reason, scrn->modes is circular, unlike the other mode 1912 * lists. How great is that? 1913 */ 1914 for (last = scrn->modes; last && last->next; last = last->next) 1915 ; 1916 last->next = scrn->modes; 1917 scrn->modes->prev = last; 1918 if (mode) { 1919 while (scrn->modes != mode) 1920 scrn->modes = scrn->modes->next; 1921 } 1922 } 1923 scrn->currentMode = scrn->modes; 1924#ifdef XFreeXDGA 1925 if (scrn->pScreen) 1926 _xf86_di_dga_reinit_internal(scrn->pScreen); 1927#endif 1928} 1929 1930static Bool 1931xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 1932 Bool *enabled) 1933{ 1934 Bool any_enabled = FALSE; 1935 int o; 1936 1937 for (o = 0; o < config->num_output; o++) 1938 any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); 1939 1940 if (!any_enabled) { 1941 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1942 "No outputs definitely connected, trying again...\n"); 1943 1944 for (o = 0; o < config->num_output; o++) 1945 any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], FALSE); 1946 } 1947 1948 return any_enabled; 1949} 1950 1951static Bool 1952nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) 1953{ 1954 int o = *index; 1955 1956 for (o++; o < config->num_output; o++) { 1957 if (enabled[o]) { 1958 *index = o; 1959 return TRUE; 1960 } 1961 } 1962 1963 return FALSE; 1964} 1965 1966static Bool 1967aspectMatch(float a, float b) 1968{ 1969 return fabs(1 - (a / b)) < 0.05; 1970} 1971 1972static DisplayModePtr 1973nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) 1974{ 1975 DisplayModePtr m = NULL; 1976 1977 if (!o) 1978 return NULL; 1979 1980 if (!last) 1981 m = o->probed_modes; 1982 else 1983 m = last->next; 1984 1985 for (; m; m = m->next) 1986 if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay)) 1987 return m; 1988 1989 return NULL; 1990} 1991 1992static DisplayModePtr 1993bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) 1994{ 1995 int o = -1, p; 1996 DisplayModePtr mode = NULL, test = NULL, match = NULL; 1997 1998 if (!nextEnabledOutput(config, enabled, &o)) 1999 return NULL; 2000 while ((mode = nextAspectMode(config->output[o], mode, aspect))) { 2001 test = mode; 2002 for (p = o; nextEnabledOutput(config, enabled, &p); ) { 2003 test = xf86OutputFindClosestMode(config->output[p], mode); 2004 if (!test) 2005 break; 2006 if (test->HDisplay != mode->HDisplay || 2007 test->VDisplay != mode->VDisplay) { 2008 test = NULL; 2009 break; 2010 } 2011 } 2012 2013 /* if we didn't match it on all outputs, try the next one */ 2014 if (!test) 2015 continue; 2016 2017 /* if it's bigger than the last one, save it */ 2018 if (!match || (test->HDisplay > match->HDisplay)) 2019 match = test; 2020 } 2021 2022 /* return the biggest one found */ 2023 return match; 2024} 2025 2026static Bool 2027xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2028 DisplayModePtr *modes, Bool *enabled, 2029 int width, int height) 2030{ 2031 int o, p; 2032 int max_pref_width = 0, max_pref_height = 0; 2033 DisplayModePtr *preferred, *preferred_match; 2034 Bool ret = FALSE; 2035 2036 preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2037 preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2038 2039 /* Check if the preferred mode is available on all outputs */ 2040 for (p = -1; nextEnabledOutput(config, enabled, &p); ) { 2041 Rotation r = config->output[p]->initial_rotation; 2042 DisplayModePtr mode; 2043 if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], 2044 width, height))) { 2045 int pref_width = xf86ModeWidth(preferred[p], r); 2046 int pref_height = xf86ModeHeight(preferred[p], r); 2047 Bool all_match = TRUE; 2048 2049 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2050 Bool match = FALSE; 2051 xf86OutputPtr output = config->output[o]; 2052 if (o == p) 2053 continue; 2054 2055 for (mode = output->probed_modes; mode; mode = mode->next) { 2056 Rotation r = output->initial_rotation; 2057 if (xf86ModeWidth(mode, r) == pref_width && 2058 xf86ModeHeight(mode, r) == pref_height) { 2059 preferred[o] = mode; 2060 match = TRUE; 2061 } 2062 } 2063 2064 all_match &= match; 2065 } 2066 2067 if (all_match && 2068 (pref_width*pref_height > max_pref_width*max_pref_height)) { 2069 for (o = -1; nextEnabledOutput(config, enabled, &o); ) 2070 preferred_match[o] = preferred[o]; 2071 max_pref_width = pref_width; 2072 max_pref_height = pref_height; 2073 ret = TRUE; 2074 } 2075 } 2076 } 2077 2078 /* 2079 * If there's no preferred mode, but only one monitor, pick the 2080 * biggest mode for its aspect ratio, assuming one exists. 2081 */ 2082 if (!ret) do { 2083 int i = 0; 2084 float aspect = 0.0; 2085 2086 /* count the number of enabled outputs */ 2087 for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; 2088 2089 if (i != 1) 2090 break; 2091 2092 p = -1; 2093 nextEnabledOutput(config, enabled, &p); 2094 if (config->output[p]->mm_height) 2095 aspect = (float)config->output[p]->mm_width / 2096 (float)config->output[p]->mm_height; 2097 2098 if (aspect) 2099 preferred_match[p] = bestModeForAspect(config, enabled, aspect); 2100 2101 if (preferred_match[p]) 2102 ret = TRUE; 2103 2104 } while (0); 2105 2106 if (ret) { 2107 /* oh good, there is a match. stash the selected modes and return. */ 2108 memcpy(modes, preferred_match, 2109 config->num_output * sizeof(DisplayModePtr)); 2110 } 2111 2112 free(preferred); 2113 free(preferred_match); 2114 return ret; 2115} 2116 2117static Bool 2118xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2119 DisplayModePtr *modes, Bool *enabled, 2120 int width, int height) 2121{ 2122 int o; 2123 float aspect = 0.0, *aspects; 2124 xf86OutputPtr output; 2125 Bool ret = FALSE; 2126 DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; 2127 2128 aspects = xnfcalloc(config->num_output, sizeof(float)); 2129 2130 /* collect the aspect ratios */ 2131 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2132 output = config->output[o]; 2133 if (output->mm_height) 2134 aspects[o] = (float)output->mm_width / (float)output->mm_height; 2135 else 2136 aspects[o] = 4.0 / 3.0; 2137 } 2138 2139 /* check that they're all the same */ 2140 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2141 output = config->output[o]; 2142 if (!aspect) { 2143 aspect = aspects[o]; 2144 } else if (!aspectMatch(aspect, aspects[o])) { 2145 goto no_aspect_match; 2146 } 2147 } 2148 2149 /* if they're all 4:3, just skip ahead and save effort */ 2150 if (!aspectMatch(aspect, 4.0/3.0)) 2151 aspect_guess = bestModeForAspect(config, enabled, aspect); 2152 2153no_aspect_match: 2154 base_guess = bestModeForAspect(config, enabled, 4.0/3.0); 2155 2156 guess = biggestMode(base_guess, aspect_guess); 2157 2158 if (!guess) 2159 goto out; 2160 2161 /* found a mode that works everywhere, now apply it */ 2162 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2163 modes[o] = xf86OutputFindClosestMode(config->output[o], guess); 2164 } 2165 ret = TRUE; 2166 2167out: 2168 free(aspects); 2169 return ret; 2170} 2171 2172static Bool 2173xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2174 DisplayModePtr *modes, Bool *enabled, 2175 int width, int height) 2176{ 2177 DisplayModePtr target_mode = NULL; 2178 Rotation target_rotation = RR_Rotate_0; 2179 DisplayModePtr default_mode; 2180 int default_preferred, target_preferred = 0, o; 2181 2182 /* User preferred > preferred > other modes */ 2183 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2184 default_mode = xf86DefaultMode (config->output[o], width, height); 2185 if (!default_mode) 2186 continue; 2187 2188 default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + 2189 ((default_mode->type & M_T_USERPREF) != 0)); 2190 2191 if (default_preferred > target_preferred || !target_mode) { 2192 target_mode = default_mode; 2193 target_preferred = default_preferred; 2194 target_rotation = config->output[o]->initial_rotation; 2195 config->compat_output = o; 2196 } 2197 } 2198 2199 if (target_mode) 2200 modes[config->compat_output] = target_mode; 2201 2202 /* Fill in other output modes */ 2203 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2204 if (!modes[o]) 2205 modes[o] = xf86ClosestMode(config->output[o], target_mode, 2206 target_rotation, width, height); 2207 } 2208 2209 return target_mode != NULL; 2210} 2211 2212static Bool 2213xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2214 DisplayModePtr *modes, Bool *enabled, 2215 int width, int height) 2216{ 2217 int o; 2218 2219 if (xf86UserConfiguredOutputs(scrn, modes)) 2220 return xf86TargetFallback(scrn, config, modes, enabled, width, height); 2221 2222 for (o = -1; nextEnabledOutput(config, enabled, &o); ) 2223 if (xf86OutputHasUserPreferredMode(config->output[o])) 2224 return 2225 xf86TargetFallback(scrn, config, modes, enabled, width, height); 2226 2227 return FALSE; 2228} 2229 2230static Bool 2231xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, 2232 float gamma_blue) 2233{ 2234 int i, size = 256; 2235 CARD16 *red, *green, *blue; 2236 2237 red = malloc(3 * size * sizeof(CARD16)); 2238 green = red + size; 2239 blue = green + size; 2240 2241 /* Only cause warning if user wanted gamma to be set. */ 2242 if (!crtc->funcs->gamma_set && (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0)) { 2243 free(red); 2244 return FALSE; 2245 } else if (!crtc->funcs->gamma_set) { 2246 free(red); 2247 return TRUE; 2248 } 2249 2250 /* At this early stage none of the randr-interface stuff is up. 2251 * So take the default gamma size for lack of something better. 2252 */ 2253 for (i = 0; i < size; i++) { 2254 if (gamma_red == 1.0) 2255 red[i] = i << 8; 2256 else 2257 red[i] = (CARD16)(pow((double)i/(double)(size - 1), 2258 1. / (double)gamma_red) * (double)(size - 1) * 256); 2259 2260 if (gamma_green == 1.0) 2261 green[i] = i << 8; 2262 else 2263 green[i] = (CARD16)(pow((double)i/(double)(size - 1), 2264 1. / (double)gamma_green) * (double)(size - 1) * 256); 2265 2266 if (gamma_blue == 1.0) 2267 blue[i] = i << 8; 2268 else 2269 blue[i] = (CARD16)(pow((double)i/(double)(size - 1), 2270 1. / (double)gamma_blue) * (double)(size - 1) * 256); 2271 } 2272 2273 /* Default size is 256, so anything else is failure. */ 2274 if (size != crtc->gamma_size) { 2275 free(red); 2276 return FALSE; 2277 } 2278 2279 crtc->gamma_size = size; 2280 memcpy (crtc->gamma_red, red, crtc->gamma_size * sizeof (CARD16)); 2281 memcpy (crtc->gamma_green, green, crtc->gamma_size * sizeof (CARD16)); 2282 memcpy (crtc->gamma_blue, blue, crtc->gamma_size * sizeof (CARD16)); 2283 2284 /* Do not set gamma now, delay until the crtc is activated. */ 2285 2286 free(red); 2287 2288 return TRUE; 2289} 2290 2291static Bool 2292xf86OutputSetInitialGamma(xf86OutputPtr output) 2293{ 2294 XF86ConfMonitorPtr mon = output->conf_monitor; 2295 float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; 2296 2297 if (!mon) 2298 return TRUE; 2299 2300 if (!output->crtc) 2301 return FALSE; 2302 2303 /* Get configured values, where they exist. */ 2304 if (mon->mon_gamma_red >= GAMMA_MIN && 2305 mon->mon_gamma_red <= GAMMA_MAX) 2306 gamma_red = mon->mon_gamma_red; 2307 2308 if (mon->mon_gamma_green >= GAMMA_MIN && 2309 mon->mon_gamma_green <= GAMMA_MAX) 2310 gamma_green = mon->mon_gamma_green; 2311 2312 if (mon->mon_gamma_blue >= GAMMA_MIN && 2313 mon->mon_gamma_blue <= GAMMA_MAX) 2314 gamma_blue = mon->mon_gamma_blue; 2315 2316 /* This avoids setting gamma 1.0 in case another cloned output on this crtc has a specific gamma. */ 2317 if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { 2318 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", output->name, gamma_red, gamma_green, gamma_blue); 2319 return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, gamma_blue); 2320 }else 2321 return TRUE; 2322} 2323 2324/** 2325 * Construct default screen configuration 2326 * 2327 * Given auto-detected (and, eventually, configured) values, 2328 * construct a usable configuration for the system 2329 * 2330 * canGrow indicates that the driver can resize the screen to larger than its 2331 * initially configured size via the config->funcs->resize hook. If TRUE, this 2332 * function will set virtualX and virtualY to match the initial configuration 2333 * and leave config->max{Width,Height} alone. If FALSE, it will bloat 2334 * virtual[XY] to include the largest modes and set config->max{Width,Height} 2335 * accordingly. 2336 */ 2337 2338Bool 2339xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) 2340{ 2341 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2342 int o, c; 2343 xf86CrtcPtr *crtcs; 2344 DisplayModePtr *modes; 2345 Bool *enabled; 2346 int width, height; 2347 int i = scrn->scrnIndex; 2348 Bool have_outputs = TRUE; 2349 Bool ret; 2350 2351 /* Set up the device options */ 2352 config->options = xnfalloc (sizeof (xf86DeviceOptions)); 2353 memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); 2354 xf86ProcessOptions (scrn->scrnIndex, 2355 scrn->options, 2356 config->options); 2357 config->debug_modes = xf86ReturnOptValBool (config->options, 2358 OPTION_MODEDEBUG, FALSE); 2359 2360 if (scrn->display->virtualX) 2361 width = scrn->display->virtualX; 2362 else 2363 width = config->maxWidth; 2364 if (scrn->display->virtualY) 2365 height = scrn->display->virtualY; 2366 else 2367 height = config->maxHeight; 2368 2369 xf86ProbeOutputModes (scrn, width, height); 2370 2371 crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); 2372 modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); 2373 enabled = xnfcalloc (config->num_output, sizeof (Bool)); 2374 2375 ret = xf86CollectEnabledOutputs(scrn, config, enabled); 2376 if (ret == FALSE && canGrow) { 2377 xf86DrvMsg(i, X_WARNING, "Unable to find connected outputs - setting %dx%d initial framebuffer\n", 2378 NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT); 2379 have_outputs = FALSE; 2380 } else { 2381 if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) 2382 xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); 2383 else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height)) 2384 xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); 2385 else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) 2386 xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n"); 2387 else if (xf86TargetFallback(scrn, config, modes, enabled, width, height)) 2388 xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); 2389 else 2390 xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); 2391 } 2392 2393 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2394 if (!modes[o]) 2395 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 2396 "Output %s enabled but has no modes\n", 2397 config->output[o]->name); 2398 else 2399 xf86DrvMsg (scrn->scrnIndex, X_INFO, 2400 "Output %s using initial mode %s\n", 2401 config->output[o]->name, modes[o]->name); 2402 } 2403 2404 /* 2405 * Set the position of each output 2406 */ 2407 if (!xf86InitialOutputPositions (scrn, modes)) 2408 { 2409 free(crtcs); 2410 free(modes); 2411 return FALSE; 2412 } 2413 2414 /* 2415 * Set initial panning of each output 2416 */ 2417 xf86InitialPanning (scrn); 2418 2419 /* 2420 * Assign CRTCs to fit output configuration 2421 */ 2422 if (have_outputs && !xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) 2423 { 2424 free(crtcs); 2425 free(modes); 2426 return FALSE; 2427 } 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 return FALSE; 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 2528 free(crtcs); 2529 free(modes); 2530 return TRUE; 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} 2898 2899#ifdef RANDR_12_INTERFACE 2900 2901#define EDID_ATOM_NAME "EDID" 2902 2903/** 2904 * Set the RandR EDID property 2905 */ 2906static void 2907xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) 2908{ 2909 Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); 2910 2911 /* This may get called before the RandR resources have been created */ 2912 if (output->randr_output == NULL) 2913 return; 2914 2915 if (data_len != 0) { 2916 RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, 2917 PropModeReplace, data_len, data, FALSE, TRUE); 2918 } else { 2919 RRDeleteOutputProperty(output->randr_output, edid_atom); 2920 } 2921} 2922 2923#endif 2924 2925/* Pull out a phyiscal size from a detailed timing if available. */ 2926struct det_phySize_parameter { 2927 xf86OutputPtr output; 2928 ddc_quirk_t quirks; 2929 Bool ret; 2930}; 2931 2932static void handle_detailed_physical_size(struct detailed_monitor_section 2933 *det_mon, void *data) 2934{ 2935 struct det_phySize_parameter *p; 2936 p = (struct det_phySize_parameter *)data; 2937 2938 if (p->ret == TRUE ) 2939 return ; 2940 2941 xf86DetTimingApplyQuirks(det_mon, p->quirks, 2942 p->output->MonInfo->features.hsize, 2943 p->output->MonInfo->features.vsize); 2944 if (det_mon->type == DT && 2945 det_mon->section.d_timings.h_size != 0 && 2946 det_mon->section.d_timings.v_size != 0) { 2947 2948 p->output->mm_width = det_mon->section.d_timings.h_size; 2949 p->output->mm_height = det_mon->section.d_timings.v_size; 2950 p->ret = TRUE; 2951 } 2952} 2953 2954/** 2955 * Set the EDID information for the specified output 2956 */ 2957void 2958xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) 2959{ 2960 ScrnInfoPtr scrn = output->scrn; 2961 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2962 Bool debug_modes = config->debug_modes || xf86Initialising; 2963#ifdef RANDR_12_INTERFACE 2964 int size; 2965#endif 2966 2967 if (output->MonInfo != NULL) 2968 free(output->MonInfo); 2969 2970 output->MonInfo = edid_mon; 2971 2972 if (debug_modes) { 2973 xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", 2974 output->name); 2975 xf86PrintEDID(edid_mon); 2976 } 2977 2978 /* Set the DDC properties for the 'compat' output */ 2979 if (output == xf86CompatOutput(scrn)) 2980 xf86SetDDCproperties(scrn, edid_mon); 2981 2982#ifdef RANDR_12_INTERFACE 2983 /* Set the RandR output properties */ 2984 size = 0; 2985 if (edid_mon) 2986 { 2987 if (edid_mon->ver.version == 1) { 2988 size = 128; 2989 if (edid_mon->flags & EDID_COMPLETE_RAWDATA) 2990 size += edid_mon->no_sections * 128; 2991 } else if (edid_mon->ver.version == 2) 2992 size = 256; 2993 } 2994 xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); 2995#endif 2996 2997 if (edid_mon) { 2998 2999 struct det_phySize_parameter p; 3000 p.output = output; 3001 p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE); 3002 p.ret = FALSE; 3003 xf86ForEachDetailedBlock(edid_mon, 3004 handle_detailed_physical_size, &p); 3005 3006 /* if no mm size is available from a detailed timing, check the max size field */ 3007 if ((!output->mm_width || !output->mm_height) && 3008 (edid_mon->features.hsize && edid_mon->features.vsize)) 3009 { 3010 output->mm_width = edid_mon->features.hsize * 10; 3011 output->mm_height = edid_mon->features.vsize * 10; 3012 } 3013 } 3014} 3015 3016/** 3017 * Return the list of modes supported by the EDID information 3018 * stored in 'output' 3019 */ 3020DisplayModePtr 3021xf86OutputGetEDIDModes (xf86OutputPtr output) 3022{ 3023 ScrnInfoPtr scrn = output->scrn; 3024 xf86MonPtr edid_mon = output->MonInfo; 3025 3026 if (!edid_mon) 3027 return NULL; 3028 return xf86DDCGetModes(scrn->scrnIndex, edid_mon); 3029} 3030 3031/* maybe we should care about DDC1? meh. */ 3032xf86MonPtr 3033xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) 3034{ 3035 ScrnInfoPtr scrn = output->scrn; 3036 xf86MonPtr mon; 3037 3038 mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE); 3039 if (mon) 3040 xf86DDCApplyQuirks(scrn->scrnIndex, mon); 3041 3042 return mon; 3043} 3044 3045static char *_xf86ConnectorNames[] = { 3046 "None", "VGA", "DVI-I", "DVI-D", 3047 "DVI-A", "Composite", "S-Video", 3048 "Component", "LFP", "Proprietary", 3049 "HDMI", "DisplayPort", 3050 }; 3051char * 3052xf86ConnectorGetName(xf86ConnectorType connector) 3053{ 3054 return _xf86ConnectorNames[connector]; 3055} 3056 3057static void 3058x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 3059{ 3060 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 3061 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 3062 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 3063 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 3064 3065 if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) 3066 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 3067} 3068 3069static void 3070x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 3071{ 3072 if (crtc->enabled) { 3073 crtc_box->x1 = crtc->x; 3074 crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 3075 crtc_box->y1 = crtc->y; 3076 crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 3077 } else 3078 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 3079} 3080 3081static int 3082xf86_crtc_box_area(BoxPtr box) 3083{ 3084 return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); 3085} 3086 3087/* 3088 * Return the crtc covering 'box'. If two crtcs cover a portion of 3089 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 3090 * with greater coverage 3091 */ 3092 3093static xf86CrtcPtr 3094xf86_covering_crtc(ScrnInfoPtr pScrn, 3095 BoxPtr box, 3096 xf86CrtcPtr desired, 3097 BoxPtr crtc_box_ret) 3098{ 3099 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3100 xf86CrtcPtr crtc, best_crtc; 3101 int coverage, best_coverage; 3102 int c; 3103 BoxRec crtc_box, cover_box; 3104 3105 best_crtc = NULL; 3106 best_coverage = 0; 3107 crtc_box_ret->x1 = 0; 3108 crtc_box_ret->x2 = 0; 3109 crtc_box_ret->y1 = 0; 3110 crtc_box_ret->y2 = 0; 3111 for (c = 0; c < xf86_config->num_crtc; c++) { 3112 crtc = xf86_config->crtc[c]; 3113 x86_crtc_box(crtc, &crtc_box); 3114 x86_crtc_box_intersect(&cover_box, &crtc_box, box); 3115 coverage = xf86_crtc_box_area(&cover_box); 3116 if (coverage && crtc == desired) { 3117 *crtc_box_ret = crtc_box; 3118 return crtc; 3119 } else if (coverage > best_coverage) { 3120 *crtc_box_ret = crtc_box; 3121 best_crtc = crtc; 3122 best_coverage = coverage; 3123 } 3124 } 3125 return best_crtc; 3126} 3127 3128/* 3129 * For overlay video, compute the relevant CRTC and 3130 * clip video to that. 3131 * 3132 * returning FALSE means there was a memory failure of some kind, 3133 * not that the video shouldn't be displayed 3134 */ 3135 3136Bool 3137xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, 3138 xf86CrtcPtr *crtc_ret, 3139 xf86CrtcPtr desired_crtc, 3140 BoxPtr dst, 3141 INT32 *xa, 3142 INT32 *xb, 3143 INT32 *ya, 3144 INT32 *yb, 3145 RegionPtr reg, 3146 INT32 width, 3147 INT32 height) 3148{ 3149 Bool ret; 3150 RegionRec crtc_region_local; 3151 RegionPtr crtc_region = reg; 3152 3153 if (crtc_ret) { 3154 BoxRec crtc_box; 3155 xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, 3156 desired_crtc, 3157 &crtc_box); 3158 3159 if (crtc) { 3160 RegionInit(&crtc_region_local, &crtc_box, 1); 3161 crtc_region = &crtc_region_local; 3162 RegionIntersect(crtc_region, crtc_region, reg); 3163 } 3164 *crtc_ret = crtc; 3165 } 3166 3167 ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, 3168 crtc_region, width, height); 3169 3170 if (crtc_region != reg) 3171 RegionUninit(&crtc_region_local); 3172 3173 return ret; 3174} 3175 3176xf86_crtc_notify_proc_ptr 3177xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new) 3178{ 3179 if (xf86CrtcConfigPrivateIndex != -1) 3180 { 3181 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3182 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3183 xf86_crtc_notify_proc_ptr old; 3184 3185 old = config->xf86_crtc_notify; 3186 config->xf86_crtc_notify = new; 3187 return old; 3188 } 3189 return NULL; 3190} 3191 3192void 3193xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) 3194{ 3195 if (xf86CrtcConfigPrivateIndex != -1) 3196 { 3197 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3198 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3199 3200 config->xf86_crtc_notify = old; 3201 } 3202} 3203 3204void 3205xf86_crtc_notify(ScreenPtr screen) 3206{ 3207 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3208 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3209 3210 if (config->xf86_crtc_notify) 3211 config->xf86_crtc_notify(screen); 3212} 3213 3214Bool 3215xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) 3216{ 3217 if (xf86CrtcConfigPrivateIndex != -1) { 3218 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3219 xf86CrtcPtr crtc; 3220 3221 /* for multiple drivers loaded we need this */ 3222 if (!xf86_config) 3223 return FALSE; 3224 if (xf86_config->num_crtc == 0) 3225 return FALSE; 3226 crtc = xf86_config->crtc[0]; 3227 3228 return crtc->funcs->gamma_set != NULL; 3229 } 3230 3231 return FALSE; 3232} 3233