xf86Crtc.c revision 8223e2f2
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; 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 != NULL) { 1919 /* For some reason, scrn->modes is circular, unlike the other mode 1920 * lists. How great is that? 1921 */ 1922 for (last = scrn->modes; last && last->next; last = last->next) 1923 ; 1924 last->next = scrn->modes; 1925 scrn->modes->prev = last; 1926 if (mode) { 1927 while (scrn->modes != mode) 1928 scrn->modes = scrn->modes->next; 1929 } 1930 } 1931 scrn->currentMode = scrn->modes; 1932#ifdef XFreeXDGA 1933 if (scrn->pScreen) 1934 _xf86_di_dga_reinit_internal(scrn->pScreen); 1935#endif 1936} 1937 1938static Bool 1939xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 1940 Bool *enabled) 1941{ 1942 Bool any_enabled = FALSE; 1943 int o; 1944 1945 for (o = 0; o < config->num_output; o++) 1946 any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); 1947 1948 if (!any_enabled) { 1949 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1950 "No outputs definitely connected, trying again...\n"); 1951 1952 for (o = 0; o < config->num_output; o++) 1953 any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], FALSE); 1954 } 1955 1956 return any_enabled; 1957} 1958 1959static Bool 1960nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) 1961{ 1962 int o = *index; 1963 1964 for (o++; o < config->num_output; o++) { 1965 if (enabled[o]) { 1966 *index = o; 1967 return TRUE; 1968 } 1969 } 1970 1971 return FALSE; 1972} 1973 1974static Bool 1975aspectMatch(float a, float b) 1976{ 1977 return fabs(1 - (a / b)) < 0.05; 1978} 1979 1980static DisplayModePtr 1981nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) 1982{ 1983 DisplayModePtr m = NULL; 1984 1985 if (!o) 1986 return NULL; 1987 1988 if (!last) 1989 m = o->probed_modes; 1990 else 1991 m = last->next; 1992 1993 for (; m; m = m->next) 1994 if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay)) 1995 return m; 1996 1997 return NULL; 1998} 1999 2000static DisplayModePtr 2001bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) 2002{ 2003 int o = -1, p; 2004 DisplayModePtr mode = NULL, test = NULL, match = NULL; 2005 2006 if (!nextEnabledOutput(config, enabled, &o)) 2007 return NULL; 2008 while ((mode = nextAspectMode(config->output[o], mode, aspect))) { 2009 test = mode; 2010 for (p = o; nextEnabledOutput(config, enabled, &p); ) { 2011 test = xf86OutputFindClosestMode(config->output[p], mode); 2012 if (!test) 2013 break; 2014 if (test->HDisplay != mode->HDisplay || 2015 test->VDisplay != mode->VDisplay) { 2016 test = NULL; 2017 break; 2018 } 2019 } 2020 2021 /* if we didn't match it on all outputs, try the next one */ 2022 if (!test) 2023 continue; 2024 2025 /* if it's bigger than the last one, save it */ 2026 if (!match || (test->HDisplay > match->HDisplay)) 2027 match = test; 2028 } 2029 2030 /* return the biggest one found */ 2031 return match; 2032} 2033 2034static Bool 2035xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2036 DisplayModePtr *modes, Bool *enabled, 2037 int width, int height) 2038{ 2039 int o, p; 2040 int max_pref_width = 0, max_pref_height = 0; 2041 DisplayModePtr *preferred, *preferred_match; 2042 Bool ret = FALSE; 2043 2044 preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2045 preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 2046 2047 /* Check if the preferred mode is available on all outputs */ 2048 for (p = -1; nextEnabledOutput(config, enabled, &p); ) { 2049 Rotation r = config->output[p]->initial_rotation; 2050 DisplayModePtr mode; 2051 if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], 2052 width, height))) { 2053 int pref_width = xf86ModeWidth(preferred[p], r); 2054 int pref_height = xf86ModeHeight(preferred[p], r); 2055 Bool all_match = TRUE; 2056 2057 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2058 Bool match = FALSE; 2059 xf86OutputPtr output = config->output[o]; 2060 if (o == p) 2061 continue; 2062 2063 for (mode = output->probed_modes; mode; mode = mode->next) { 2064 Rotation r = output->initial_rotation; 2065 if (xf86ModeWidth(mode, r) == pref_width && 2066 xf86ModeHeight(mode, r) == pref_height) { 2067 preferred[o] = mode; 2068 match = TRUE; 2069 } 2070 } 2071 2072 all_match &= match; 2073 } 2074 2075 if (all_match && 2076 (pref_width*pref_height > max_pref_width*max_pref_height)) { 2077 for (o = -1; nextEnabledOutput(config, enabled, &o); ) 2078 preferred_match[o] = preferred[o]; 2079 max_pref_width = pref_width; 2080 max_pref_height = pref_height; 2081 ret = TRUE; 2082 } 2083 } 2084 } 2085 2086 /* 2087 * If there's no preferred mode, but only one monitor, pick the 2088 * biggest mode for its aspect ratio, assuming one exists. 2089 */ 2090 if (!ret) do { 2091 int i = 0; 2092 float aspect = 0.0; 2093 2094 /* count the number of enabled outputs */ 2095 for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; 2096 2097 if (i != 1) 2098 break; 2099 2100 p = -1; 2101 nextEnabledOutput(config, enabled, &p); 2102 if (config->output[p]->mm_height) 2103 aspect = (float)config->output[p]->mm_width / 2104 (float)config->output[p]->mm_height; 2105 2106 if (aspect) 2107 preferred_match[p] = bestModeForAspect(config, enabled, aspect); 2108 2109 if (preferred_match[p]) 2110 ret = TRUE; 2111 2112 } while (0); 2113 2114 if (ret) { 2115 /* oh good, there is a match. stash the selected modes and return. */ 2116 memcpy(modes, preferred_match, 2117 config->num_output * sizeof(DisplayModePtr)); 2118 } 2119 2120 free(preferred); 2121 free(preferred_match); 2122 return ret; 2123} 2124 2125static Bool 2126xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2127 DisplayModePtr *modes, Bool *enabled, 2128 int width, int height) 2129{ 2130 int o; 2131 float aspect = 0.0, *aspects; 2132 xf86OutputPtr output; 2133 Bool ret = FALSE; 2134 DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; 2135 2136 aspects = xnfcalloc(config->num_output, sizeof(float)); 2137 2138 /* collect the aspect ratios */ 2139 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2140 output = config->output[o]; 2141 if (output->mm_height) 2142 aspects[o] = (float)output->mm_width / (float)output->mm_height; 2143 else 2144 aspects[o] = 4.0 / 3.0; 2145 } 2146 2147 /* check that they're all the same */ 2148 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2149 output = config->output[o]; 2150 if (!aspect) { 2151 aspect = aspects[o]; 2152 } else if (!aspectMatch(aspect, aspects[o])) { 2153 goto no_aspect_match; 2154 } 2155 } 2156 2157 /* if they're all 4:3, just skip ahead and save effort */ 2158 if (!aspectMatch(aspect, 4.0/3.0)) 2159 aspect_guess = bestModeForAspect(config, enabled, aspect); 2160 2161no_aspect_match: 2162 base_guess = bestModeForAspect(config, enabled, 4.0/3.0); 2163 2164 guess = biggestMode(base_guess, aspect_guess); 2165 2166 if (!guess) 2167 goto out; 2168 2169 /* found a mode that works everywhere, now apply it */ 2170 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2171 modes[o] = xf86OutputFindClosestMode(config->output[o], guess); 2172 } 2173 ret = TRUE; 2174 2175out: 2176 free(aspects); 2177 return ret; 2178} 2179 2180static Bool 2181xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2182 DisplayModePtr *modes, Bool *enabled, 2183 int width, int height) 2184{ 2185 DisplayModePtr target_mode = NULL; 2186 Rotation target_rotation = RR_Rotate_0; 2187 DisplayModePtr default_mode; 2188 int default_preferred, target_preferred = 0, o; 2189 2190 /* User preferred > preferred > other modes */ 2191 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2192 default_mode = xf86DefaultMode (config->output[o], width, height); 2193 if (!default_mode) 2194 continue; 2195 2196 default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + 2197 ((default_mode->type & M_T_USERPREF) != 0)); 2198 2199 if (default_preferred > target_preferred || !target_mode) { 2200 target_mode = default_mode; 2201 target_preferred = default_preferred; 2202 target_rotation = config->output[o]->initial_rotation; 2203 config->compat_output = o; 2204 } 2205 } 2206 2207 if (target_mode) 2208 modes[config->compat_output] = target_mode; 2209 2210 /* Fill in other output modes */ 2211 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2212 if (!modes[o]) 2213 modes[o] = xf86ClosestMode(config->output[o], target_mode, 2214 target_rotation, width, height); 2215 } 2216 2217 return target_mode != NULL; 2218} 2219 2220static Bool 2221xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2222 DisplayModePtr *modes, Bool *enabled, 2223 int width, int height) 2224{ 2225 int o; 2226 2227 if (xf86UserConfiguredOutputs(scrn, modes)) 2228 return xf86TargetFallback(scrn, config, modes, enabled, width, height); 2229 2230 for (o = -1; nextEnabledOutput(config, enabled, &o); ) 2231 if (xf86OutputHasUserPreferredMode(config->output[o])) 2232 return 2233 xf86TargetFallback(scrn, config, modes, enabled, width, height); 2234 2235 return FALSE; 2236} 2237 2238static Bool 2239xf86CrtcSetInitialGamma(xf86CrtcPtr crtc, float gamma_red, float gamma_green, 2240 float gamma_blue) 2241{ 2242 int i, size = 256; 2243 CARD16 *red, *green, *blue; 2244 2245 red = malloc(3 * size * sizeof(CARD16)); 2246 green = red + size; 2247 blue = green + size; 2248 2249 /* Only cause warning if user wanted gamma to be set. */ 2250 if (!crtc->funcs->gamma_set && (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0)) { 2251 free(red); 2252 return FALSE; 2253 } else if (!crtc->funcs->gamma_set) { 2254 free(red); 2255 return TRUE; 2256 } 2257 2258 /* At this early stage none of the randr-interface stuff is up. 2259 * So take the default gamma size for lack of something better. 2260 */ 2261 for (i = 0; i < size; i++) { 2262 if (gamma_red == 1.0) 2263 red[i] = i << 8; 2264 else 2265 red[i] = (CARD16)(pow((double)i/(double)(size - 1), 2266 1. / (double)gamma_red) * (double)(size - 1) * 256); 2267 2268 if (gamma_green == 1.0) 2269 green[i] = i << 8; 2270 else 2271 green[i] = (CARD16)(pow((double)i/(double)(size - 1), 2272 1. / (double)gamma_green) * (double)(size - 1) * 256); 2273 2274 if (gamma_blue == 1.0) 2275 blue[i] = i << 8; 2276 else 2277 blue[i] = (CARD16)(pow((double)i/(double)(size - 1), 2278 1. / (double)gamma_blue) * (double)(size - 1) * 256); 2279 } 2280 2281 /* Default size is 256, so anything else is failure. */ 2282 if (size != crtc->gamma_size) { 2283 free(red); 2284 return FALSE; 2285 } 2286 2287 crtc->gamma_size = size; 2288 memcpy (crtc->gamma_red, red, crtc->gamma_size * sizeof (CARD16)); 2289 memcpy (crtc->gamma_green, green, crtc->gamma_size * sizeof (CARD16)); 2290 memcpy (crtc->gamma_blue, blue, crtc->gamma_size * sizeof (CARD16)); 2291 2292 /* Do not set gamma now, delay until the crtc is activated. */ 2293 2294 free(red); 2295 2296 return TRUE; 2297} 2298 2299static Bool 2300xf86OutputSetInitialGamma(xf86OutputPtr output) 2301{ 2302 XF86ConfMonitorPtr mon = output->conf_monitor; 2303 float gamma_red = 1.0, gamma_green = 1.0, gamma_blue = 1.0; 2304 2305 if (!mon) 2306 return TRUE; 2307 2308 if (!output->crtc) 2309 return FALSE; 2310 2311 /* Get configured values, where they exist. */ 2312 if (mon->mon_gamma_red >= GAMMA_MIN && 2313 mon->mon_gamma_red <= GAMMA_MAX) 2314 gamma_red = mon->mon_gamma_red; 2315 2316 if (mon->mon_gamma_green >= GAMMA_MIN && 2317 mon->mon_gamma_green <= GAMMA_MAX) 2318 gamma_green = mon->mon_gamma_green; 2319 2320 if (mon->mon_gamma_blue >= GAMMA_MIN && 2321 mon->mon_gamma_blue <= GAMMA_MAX) 2322 gamma_blue = mon->mon_gamma_blue; 2323 2324 /* This avoids setting gamma 1.0 in case another cloned output on this crtc has a specific gamma. */ 2325 if (gamma_red != 1.0 || gamma_green != 1.0 || gamma_blue != 1.0) { 2326 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Output %s wants gamma correction (%.1f, %.1f, %.1f)\n", output->name, gamma_red, gamma_green, gamma_blue); 2327 return xf86CrtcSetInitialGamma(output->crtc, gamma_red, gamma_green, gamma_blue); 2328 }else 2329 return TRUE; 2330} 2331 2332/** 2333 * Construct default screen configuration 2334 * 2335 * Given auto-detected (and, eventually, configured) values, 2336 * construct a usable configuration for the system 2337 * 2338 * canGrow indicates that the driver can resize the screen to larger than its 2339 * initially configured size via the config->funcs->resize hook. If TRUE, this 2340 * function will set virtualX and virtualY to match the initial configuration 2341 * and leave config->max{Width,Height} alone. If FALSE, it will bloat 2342 * virtual[XY] to include the largest modes and set config->max{Width,Height} 2343 * accordingly. 2344 */ 2345 2346Bool 2347xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) 2348{ 2349 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2350 int o, c; 2351 xf86CrtcPtr *crtcs; 2352 DisplayModePtr *modes; 2353 Bool *enabled; 2354 int width, height; 2355 int i = scrn->scrnIndex; 2356 Bool have_outputs = TRUE; 2357 Bool ret; 2358 Bool success = FALSE; 2359 2360 /* Set up the device options */ 2361 config->options = xnfalloc (sizeof (xf86DeviceOptions)); 2362 memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); 2363 xf86ProcessOptions (scrn->scrnIndex, 2364 scrn->options, 2365 config->options); 2366 config->debug_modes = xf86ReturnOptValBool (config->options, 2367 OPTION_MODEDEBUG, FALSE); 2368 2369 if (scrn->display->virtualX) 2370 width = scrn->display->virtualX; 2371 else 2372 width = config->maxWidth; 2373 if (scrn->display->virtualY) 2374 height = scrn->display->virtualY; 2375 else 2376 height = config->maxHeight; 2377 2378 xf86ProbeOutputModes (scrn, width, height); 2379 2380 crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); 2381 modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); 2382 enabled = xnfcalloc (config->num_output, sizeof (Bool)); 2383 2384 ret = xf86CollectEnabledOutputs(scrn, config, enabled); 2385 if (ret == FALSE && canGrow) { 2386 xf86DrvMsg(i, X_WARNING, "Unable to find connected outputs - setting %dx%d initial framebuffer\n", 2387 NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT); 2388 have_outputs = FALSE; 2389 } else { 2390 if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) 2391 xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); 2392 else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height)) 2393 xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); 2394 else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) 2395 xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n"); 2396 else if (xf86TargetFallback(scrn, config, modes, enabled, width, height)) 2397 xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); 2398 else 2399 xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); 2400 } 2401 2402 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2403 if (!modes[o]) 2404 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 2405 "Output %s enabled but has no modes\n", 2406 config->output[o]->name); 2407 else 2408 xf86DrvMsg (scrn->scrnIndex, X_INFO, 2409 "Output %s using initial mode %s\n", 2410 config->output[o]->name, modes[o]->name); 2411 } 2412 2413 /* 2414 * Set the position of each output 2415 */ 2416 if (!xf86InitialOutputPositions (scrn, modes)) 2417 goto bailout; 2418 2419 /* 2420 * Set initial panning of each output 2421 */ 2422 xf86InitialPanning (scrn); 2423 2424 /* 2425 * Assign CRTCs to fit output configuration 2426 */ 2427 if (have_outputs && !xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) 2428 goto bailout; 2429 2430 /* XXX override xf86 common frame computation code */ 2431 2432 scrn->display->frameX0 = 0; 2433 scrn->display->frameY0 = 0; 2434 2435 for (c = 0; c < config->num_crtc; c++) 2436 { 2437 xf86CrtcPtr crtc = config->crtc[c]; 2438 2439 crtc->enabled = FALSE; 2440 memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); 2441 /* Set default gamma for all crtc's. */ 2442 /* This is done to avoid problems later on with cloned outputs. */ 2443 xf86CrtcSetInitialGamma(crtc, 1.0, 1.0, 1.0); 2444 } 2445 2446 if (xf86_crtc_supports_gamma(scrn)) 2447 xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using default gamma of (1.0, 1.0, 1.0) unless otherwise stated.\n"); 2448 2449 /* 2450 * Set initial configuration 2451 */ 2452 for (o = 0; o < config->num_output; o++) 2453 { 2454 xf86OutputPtr output = config->output[o]; 2455 DisplayModePtr mode = modes[o]; 2456 xf86CrtcPtr crtc = crtcs[o]; 2457 2458 if (mode && crtc) 2459 { 2460 crtc->desiredMode = *mode; 2461 crtc->desiredRotation = output->initial_rotation; 2462 crtc->desiredX = output->initial_x; 2463 crtc->desiredY = output->initial_y; 2464 crtc->desiredTransformPresent = FALSE; 2465 crtc->enabled = TRUE; 2466 memcpy (&crtc->panningTotalArea, &output->initialTotalArea, sizeof(BoxRec)); 2467 memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, sizeof(BoxRec)); 2468 memcpy (crtc->panningBorder, output->initialBorder, 4*sizeof(INT16)); 2469 output->crtc = crtc; 2470 if (!xf86OutputSetInitialGamma(output)) 2471 xf86DrvMsg (scrn->scrnIndex, X_WARNING, "Initial gamma correction for output %s: failed.\n", output->name); 2472 } else { 2473 output->crtc = NULL; 2474 } 2475 } 2476 2477 if (scrn->display->virtualX == 0) 2478 { 2479 /* 2480 * Expand virtual size to cover the current config and potential mode 2481 * switches, if the driver can't enlarge the screen later. 2482 */ 2483 xf86DefaultScreenLimits (scrn, &width, &height, canGrow); 2484 2485 if (have_outputs == FALSE) { 2486 if (width < NO_OUTPUT_DEFAULT_WIDTH && height < NO_OUTPUT_DEFAULT_HEIGHT) { 2487 width = NO_OUTPUT_DEFAULT_WIDTH; 2488 height = NO_OUTPUT_DEFAULT_HEIGHT; 2489 } 2490 } 2491 2492 scrn->display->virtualX = width; 2493 scrn->display->virtualY = height; 2494 } 2495 2496 if (width > scrn->virtualX) 2497 scrn->virtualX = width; 2498 if (height > scrn->virtualY) 2499 scrn->virtualY = height; 2500 2501 /* 2502 * Make sure the configuration isn't too small. 2503 */ 2504 if (width < config->minWidth || height < config->minHeight) 2505 goto bailout; 2506 2507 /* 2508 * Limit the crtc config to virtual[XY] if the driver can't grow the 2509 * desktop. 2510 */ 2511 if (!canGrow) 2512 { 2513 xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, 2514 width, height); 2515 } 2516 2517 if (have_outputs) { 2518 /* Mirror output modes to scrn mode list */ 2519 xf86SetScrnInfoModes (scrn); 2520 } else { 2521 /* Clear any existing modes from scrn->modes */ 2522 while (scrn->modes != NULL) 2523 xf86DeleteMode(&scrn->modes, scrn->modes); 2524 scrn->modes = xf86ModesAdd(scrn->modes, 2525 xf86CVTMode(width, height, 60, 0, 0)); 2526 } 2527 2528 success = TRUE; 2529 bailout: 2530 free(crtcs); 2531 free(modes); 2532 free(enabled); 2533 return success; 2534} 2535 2536/* 2537 * Check the CRTC we're going to map each output to vs. it's current 2538 * CRTC. If they don't match, we have to disable the output and the CRTC 2539 * since the driver will have to re-route things. 2540 */ 2541static void 2542xf86PrepareOutputs (ScrnInfoPtr scrn) 2543{ 2544 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2545 int o; 2546 2547 for (o = 0; o < config->num_output; o++) { 2548 xf86OutputPtr output = config->output[o]; 2549#if RANDR_GET_CRTC_INTERFACE 2550 /* Disable outputs that are unused or will be re-routed */ 2551 if (!output->funcs->get_crtc || 2552 output->crtc != (*output->funcs->get_crtc)(output) || 2553 output->crtc == NULL) 2554#endif 2555 (*output->funcs->dpms)(output, DPMSModeOff); 2556 } 2557} 2558 2559static void 2560xf86PrepareCrtcs (ScrnInfoPtr scrn) 2561{ 2562 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2563 int c; 2564 2565 for (c = 0; c < config->num_crtc; c++) { 2566#if RANDR_GET_CRTC_INTERFACE 2567 xf86CrtcPtr crtc = config->crtc[c]; 2568 xf86OutputPtr output = NULL; 2569 uint32_t desired_outputs = 0, current_outputs = 0; 2570 int o; 2571 2572 for (o = 0; o < config->num_output; o++) { 2573 output = config->output[o]; 2574 if (output->crtc == crtc) 2575 desired_outputs |= (1<<o); 2576 /* If we can't tell where it's mapped, force it off */ 2577 if (!output->funcs->get_crtc) { 2578 desired_outputs = 0; 2579 break; 2580 } 2581 if ((*output->funcs->get_crtc)(output) == crtc) 2582 current_outputs |= (1<<o); 2583 } 2584 2585 /* 2586 * If mappings are different or the CRTC is unused, 2587 * we need to disable it 2588 */ 2589 if (desired_outputs != current_outputs || 2590 !desired_outputs) 2591 (*crtc->funcs->dpms)(crtc, DPMSModeOff); 2592#else 2593 (*crtc->funcs->dpms)(crtc, DPMSModeOff); 2594#endif 2595 } 2596} 2597 2598/* 2599 * Using the desired mode information in each crtc, set 2600 * modes (used in EnterVT functions, or at server startup) 2601 */ 2602 2603Bool 2604xf86SetDesiredModes (ScrnInfoPtr scrn) 2605{ 2606 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2607 xf86CrtcPtr crtc = config->crtc[0]; 2608 int c; 2609 2610 /* A driver with this hook will take care of this */ 2611 if (!crtc->funcs->set_mode_major) { 2612 xf86PrepareOutputs(scrn); 2613 xf86PrepareCrtcs(scrn); 2614 } 2615 2616 for (c = 0; c < config->num_crtc; c++) 2617 { 2618 xf86OutputPtr output = NULL; 2619 int o; 2620 RRTransformPtr transform; 2621 2622 crtc = config->crtc[c]; 2623 2624 /* Skip disabled CRTCs */ 2625 if (!crtc->enabled) 2626 continue; 2627 2628 if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc) 2629 output = xf86CompatOutput(scrn); 2630 else 2631 { 2632 for (o = 0; o < config->num_output; o++) 2633 if (config->output[o]->crtc == crtc) 2634 { 2635 output = config->output[o]; 2636 break; 2637 } 2638 } 2639 /* paranoia */ 2640 if (!output) 2641 continue; 2642 2643 /* Mark that we'll need to re-set the mode for sure */ 2644 memset(&crtc->mode, 0, sizeof(crtc->mode)); 2645 if (!crtc->desiredMode.CrtcHDisplay) 2646 { 2647 DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); 2648 2649 if (!mode) 2650 return FALSE; 2651 crtc->desiredMode = *mode; 2652 crtc->desiredRotation = RR_Rotate_0; 2653 crtc->desiredTransformPresent = FALSE; 2654 crtc->desiredX = 0; 2655 crtc->desiredY = 0; 2656 } 2657 2658 if (crtc->desiredTransformPresent) 2659 transform = &crtc->desiredTransform; 2660 else 2661 transform = NULL; 2662 if (!xf86CrtcSetModeTransform (crtc, &crtc->desiredMode, crtc->desiredRotation, 2663 transform, crtc->desiredX, crtc->desiredY)) 2664 return FALSE; 2665 } 2666 2667 xf86DisableUnusedFunctions(scrn); 2668 return TRUE; 2669} 2670 2671/** 2672 * In the current world order, there are lists of modes per output, which may 2673 * or may not include the mode that was asked to be set by XFree86's mode 2674 * selection. Find the closest one, in the following preference order: 2675 * 2676 * - Equality 2677 * - Closer in size to the requested mode, but no larger 2678 * - Closer in refresh rate to the requested mode. 2679 */ 2680 2681DisplayModePtr 2682xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) 2683{ 2684 DisplayModePtr best = NULL, scan = NULL; 2685 2686 for (scan = output->probed_modes; scan != NULL; scan = scan->next) 2687 { 2688 /* If there's an exact match, we're done. */ 2689 if (xf86ModesEqual(scan, desired)) { 2690 best = desired; 2691 break; 2692 } 2693 2694 /* Reject if it's larger than the desired mode. */ 2695 if (scan->HDisplay > desired->HDisplay || 2696 scan->VDisplay > desired->VDisplay) 2697 { 2698 continue; 2699 } 2700 2701 /* 2702 * If we haven't picked a best mode yet, use the first 2703 * one in the size range 2704 */ 2705 if (best == NULL) 2706 { 2707 best = scan; 2708 continue; 2709 } 2710 2711 /* Find if it's closer to the right size than the current best 2712 * option. 2713 */ 2714 if ((scan->HDisplay > best->HDisplay && 2715 scan->VDisplay >= best->VDisplay) || 2716 (scan->HDisplay >= best->HDisplay && 2717 scan->VDisplay > best->VDisplay)) 2718 { 2719 best = scan; 2720 continue; 2721 } 2722 2723 /* Find if it's still closer to the right refresh than the current 2724 * best resolution. 2725 */ 2726 if (scan->HDisplay == best->HDisplay && 2727 scan->VDisplay == best->VDisplay && 2728 (fabs(scan->VRefresh - desired->VRefresh) < 2729 fabs(best->VRefresh - desired->VRefresh))) { 2730 best = scan; 2731 } 2732 } 2733 return best; 2734} 2735 2736/** 2737 * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, 2738 * take the specified mode and apply it to the crtc connected to the compat 2739 * output. Then, find similar modes for the other outputs, as with the 2740 * InitialConfiguration code above. The goal is to clone the desired 2741 * mode across all outputs that are currently active. 2742 */ 2743 2744Bool 2745xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) 2746{ 2747 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2748 Bool ok = TRUE; 2749 xf86OutputPtr compat_output; 2750 DisplayModePtr compat_mode = NULL; 2751 int c; 2752 2753 /* 2754 * Let the compat output drive the final mode selection 2755 */ 2756 compat_output = xf86CompatOutput(pScrn); 2757 if (compat_output) 2758 compat_mode = xf86OutputFindClosestMode (compat_output, desired); 2759 if (compat_mode) 2760 desired = compat_mode; 2761 2762 for (c = 0; c < config->num_crtc; c++) 2763 { 2764 xf86CrtcPtr crtc = config->crtc[c]; 2765 DisplayModePtr crtc_mode = NULL; 2766 int o; 2767 2768 if (!crtc->enabled) 2769 continue; 2770 2771 for (o = 0; o < config->num_output; o++) 2772 { 2773 xf86OutputPtr output = config->output[o]; 2774 DisplayModePtr output_mode; 2775 2776 /* skip outputs not on this crtc */ 2777 if (output->crtc != crtc) 2778 continue; 2779 2780 if (crtc_mode) 2781 { 2782 output_mode = xf86OutputFindClosestMode (output, crtc_mode); 2783 if (output_mode != crtc_mode) 2784 output->crtc = NULL; 2785 } 2786 else 2787 crtc_mode = xf86OutputFindClosestMode (output, desired); 2788 } 2789 if (!crtc_mode) 2790 { 2791 crtc->enabled = FALSE; 2792 continue; 2793 } 2794 if (!xf86CrtcSetModeTransform (crtc, crtc_mode, rotation, NULL, 0, 0)) 2795 ok = FALSE; 2796 else 2797 { 2798 crtc->desiredMode = *crtc_mode; 2799 crtc->desiredRotation = rotation; 2800 crtc->desiredTransformPresent = FALSE; 2801 crtc->desiredX = 0; 2802 crtc->desiredY = 0; 2803 } 2804 } 2805 xf86DisableUnusedFunctions(pScrn); 2806#ifdef RANDR_12_INTERFACE 2807 xf86RandR12TellChanged (pScrn->pScreen); 2808#endif 2809 return ok; 2810} 2811 2812 2813/** 2814 * Set the DPMS power mode of all outputs and CRTCs. 2815 * 2816 * If the new mode is off, it will turn off outputs and then CRTCs. 2817 * Otherwise, it will affect CRTCs before outputs. 2818 */ 2819void 2820xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) 2821{ 2822 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2823 int i; 2824 2825 if (!scrn->vtSema) 2826 return; 2827 2828 if (mode == DPMSModeOff) { 2829 for (i = 0; i < config->num_output; i++) { 2830 xf86OutputPtr output = config->output[i]; 2831 if (output->crtc != NULL) 2832 (*output->funcs->dpms) (output, mode); 2833 } 2834 } 2835 2836 for (i = 0; i < config->num_crtc; i++) { 2837 xf86CrtcPtr crtc = config->crtc[i]; 2838 if (crtc->enabled) 2839 (*crtc->funcs->dpms) (crtc, mode); 2840 } 2841 2842 if (mode != DPMSModeOff) { 2843 for (i = 0; i < config->num_output; i++) { 2844 xf86OutputPtr output = config->output[i]; 2845 if (output->crtc != NULL) 2846 (*output->funcs->dpms) (output, mode); 2847 } 2848 } 2849} 2850 2851/** 2852 * Implement the screensaver by just calling down into the driver DPMS hooks. 2853 * 2854 * Even for monitors with no DPMS support, by the definition of our DPMS hooks, 2855 * the outputs will still get disabled (blanked). 2856 */ 2857Bool 2858xf86SaveScreen(ScreenPtr pScreen, int mode) 2859{ 2860 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 2861 2862 if (xf86IsUnblank(mode)) 2863 xf86DPMSSet(pScrn, DPMSModeOn, 0); 2864 else 2865 xf86DPMSSet(pScrn, DPMSModeOff, 0); 2866 2867 return TRUE; 2868} 2869 2870/** 2871 * Disable all inactive crtcs and outputs 2872 */ 2873void 2874xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) 2875{ 2876 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2877 int o, c; 2878 2879 for (o = 0; o < xf86_config->num_output; o++) 2880 { 2881 xf86OutputPtr output = xf86_config->output[o]; 2882 if (!output->crtc) 2883 (*output->funcs->dpms)(output, DPMSModeOff); 2884 } 2885 2886 for (c = 0; c < xf86_config->num_crtc; c++) 2887 { 2888 xf86CrtcPtr crtc = xf86_config->crtc[c]; 2889 2890 if (!crtc->enabled) 2891 { 2892 crtc->funcs->dpms(crtc, DPMSModeOff); 2893 memset(&crtc->mode, 0, sizeof(crtc->mode)); 2894 xf86RotateDestroy(crtc); 2895 crtc->active = FALSE; 2896 } 2897 } 2898 if (pScrn->pScreen) 2899 xf86_crtc_notify(pScrn->pScreen); 2900} 2901 2902#ifdef RANDR_12_INTERFACE 2903 2904#define EDID_ATOM_NAME "EDID" 2905 2906/** 2907 * Set the RandR EDID property 2908 */ 2909static void 2910xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) 2911{ 2912 Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); 2913 2914 /* This may get called before the RandR resources have been created */ 2915 if (output->randr_output == NULL) 2916 return; 2917 2918 if (data_len != 0) { 2919 RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, 2920 PropModeReplace, data_len, data, FALSE, TRUE); 2921 } else { 2922 RRDeleteOutputProperty(output->randr_output, edid_atom); 2923 } 2924} 2925 2926#endif 2927 2928/* Pull out a phyiscal size from a detailed timing if available. */ 2929struct det_phySize_parameter { 2930 xf86OutputPtr output; 2931 ddc_quirk_t quirks; 2932 Bool ret; 2933}; 2934 2935static void handle_detailed_physical_size(struct detailed_monitor_section 2936 *det_mon, void *data) 2937{ 2938 struct det_phySize_parameter *p; 2939 p = (struct det_phySize_parameter *)data; 2940 2941 if (p->ret == TRUE ) 2942 return ; 2943 2944 xf86DetTimingApplyQuirks(det_mon, p->quirks, 2945 p->output->MonInfo->features.hsize, 2946 p->output->MonInfo->features.vsize); 2947 if (det_mon->type == DT && 2948 det_mon->section.d_timings.h_size != 0 && 2949 det_mon->section.d_timings.v_size != 0) { 2950 2951 p->output->mm_width = det_mon->section.d_timings.h_size; 2952 p->output->mm_height = det_mon->section.d_timings.v_size; 2953 p->ret = TRUE; 2954 } 2955} 2956 2957/** 2958 * Set the EDID information for the specified output 2959 */ 2960void 2961xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) 2962{ 2963 ScrnInfoPtr scrn = output->scrn; 2964 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2965 Bool debug_modes = config->debug_modes || xf86Initialising; 2966#ifdef RANDR_12_INTERFACE 2967 int size; 2968#endif 2969 2970 if (output->MonInfo != NULL) 2971 free(output->MonInfo); 2972 2973 output->MonInfo = edid_mon; 2974 output->mm_width = 0; 2975 output->mm_height = 0; 2976 2977 if (debug_modes) { 2978 xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", 2979 output->name); 2980 xf86PrintEDID(edid_mon); 2981 } 2982 2983 /* Set the DDC properties for the 'compat' output */ 2984 if (output == xf86CompatOutput(scrn)) 2985 xf86SetDDCproperties(scrn, edid_mon); 2986 2987#ifdef RANDR_12_INTERFACE 2988 /* Set the RandR output properties */ 2989 size = 0; 2990 if (edid_mon) 2991 { 2992 if (edid_mon->ver.version == 1) { 2993 size = 128; 2994 if (edid_mon->flags & EDID_COMPLETE_RAWDATA) 2995 size += edid_mon->no_sections * 128; 2996 } else if (edid_mon->ver.version == 2) 2997 size = 256; 2998 } 2999 xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); 3000#endif 3001 3002 if (edid_mon) { 3003 3004 struct det_phySize_parameter p; 3005 p.output = output; 3006 p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE); 3007 p.ret = FALSE; 3008 xf86ForEachDetailedBlock(edid_mon, 3009 handle_detailed_physical_size, &p); 3010 3011 /* if no mm size is available from a detailed timing, check the max size field */ 3012 if ((!output->mm_width || !output->mm_height) && 3013 (edid_mon->features.hsize && edid_mon->features.vsize)) 3014 { 3015 output->mm_width = edid_mon->features.hsize * 10; 3016 output->mm_height = edid_mon->features.vsize * 10; 3017 } 3018 } 3019} 3020 3021/** 3022 * Return the list of modes supported by the EDID information 3023 * stored in 'output' 3024 */ 3025DisplayModePtr 3026xf86OutputGetEDIDModes (xf86OutputPtr output) 3027{ 3028 ScrnInfoPtr scrn = output->scrn; 3029 xf86MonPtr edid_mon = output->MonInfo; 3030 3031 if (!edid_mon) 3032 return NULL; 3033 return xf86DDCGetModes(scrn->scrnIndex, edid_mon); 3034} 3035 3036/* maybe we should care about DDC1? meh. */ 3037xf86MonPtr 3038xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) 3039{ 3040 ScrnInfoPtr scrn = output->scrn; 3041 xf86MonPtr mon; 3042 3043 mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE); 3044 if (mon) 3045 xf86DDCApplyQuirks(scrn->scrnIndex, mon); 3046 3047 return mon; 3048} 3049 3050static char *_xf86ConnectorNames[] = { 3051 "None", "VGA", "DVI-I", "DVI-D", 3052 "DVI-A", "Composite", "S-Video", 3053 "Component", "LFP", "Proprietary", 3054 "HDMI", "DisplayPort", 3055 }; 3056char * 3057xf86ConnectorGetName(xf86ConnectorType connector) 3058{ 3059 return _xf86ConnectorNames[connector]; 3060} 3061 3062static void 3063x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 3064{ 3065 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 3066 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 3067 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 3068 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 3069 3070 if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) 3071 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 3072} 3073 3074static void 3075x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 3076{ 3077 if (crtc->enabled) { 3078 crtc_box->x1 = crtc->x; 3079 crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 3080 crtc_box->y1 = crtc->y; 3081 crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 3082 } else 3083 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 3084} 3085 3086static int 3087xf86_crtc_box_area(BoxPtr box) 3088{ 3089 return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); 3090} 3091 3092/* 3093 * Return the crtc covering 'box'. If two crtcs cover a portion of 3094 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 3095 * with greater coverage 3096 */ 3097 3098static xf86CrtcPtr 3099xf86_covering_crtc(ScrnInfoPtr pScrn, 3100 BoxPtr box, 3101 xf86CrtcPtr desired, 3102 BoxPtr crtc_box_ret) 3103{ 3104 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3105 xf86CrtcPtr crtc, best_crtc; 3106 int coverage, best_coverage; 3107 int c; 3108 BoxRec crtc_box, cover_box; 3109 3110 best_crtc = NULL; 3111 best_coverage = 0; 3112 crtc_box_ret->x1 = 0; 3113 crtc_box_ret->x2 = 0; 3114 crtc_box_ret->y1 = 0; 3115 crtc_box_ret->y2 = 0; 3116 for (c = 0; c < xf86_config->num_crtc; c++) { 3117 crtc = xf86_config->crtc[c]; 3118 x86_crtc_box(crtc, &crtc_box); 3119 x86_crtc_box_intersect(&cover_box, &crtc_box, box); 3120 coverage = xf86_crtc_box_area(&cover_box); 3121 if (coverage && crtc == desired) { 3122 *crtc_box_ret = crtc_box; 3123 return crtc; 3124 } else if (coverage > best_coverage) { 3125 *crtc_box_ret = crtc_box; 3126 best_crtc = crtc; 3127 best_coverage = coverage; 3128 } 3129 } 3130 return best_crtc; 3131} 3132 3133/* 3134 * For overlay video, compute the relevant CRTC and 3135 * clip video to that. 3136 * 3137 * returning FALSE means there was a memory failure of some kind, 3138 * not that the video shouldn't be displayed 3139 */ 3140 3141Bool 3142xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, 3143 xf86CrtcPtr *crtc_ret, 3144 xf86CrtcPtr desired_crtc, 3145 BoxPtr dst, 3146 INT32 *xa, 3147 INT32 *xb, 3148 INT32 *ya, 3149 INT32 *yb, 3150 RegionPtr reg, 3151 INT32 width, 3152 INT32 height) 3153{ 3154 Bool ret; 3155 RegionRec crtc_region_local; 3156 RegionPtr crtc_region = reg; 3157 3158 if (crtc_ret) { 3159 BoxRec crtc_box; 3160 xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, 3161 desired_crtc, 3162 &crtc_box); 3163 3164 if (crtc) { 3165 RegionInit(&crtc_region_local, &crtc_box, 1); 3166 crtc_region = &crtc_region_local; 3167 RegionIntersect(crtc_region, crtc_region, reg); 3168 } 3169 *crtc_ret = crtc; 3170 } 3171 3172 ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, 3173 crtc_region, width, height); 3174 3175 if (crtc_region != reg) 3176 RegionUninit(&crtc_region_local); 3177 3178 return ret; 3179} 3180 3181xf86_crtc_notify_proc_ptr 3182xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new) 3183{ 3184 if (xf86CrtcConfigPrivateIndex != -1) 3185 { 3186 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3187 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3188 xf86_crtc_notify_proc_ptr old; 3189 3190 old = config->xf86_crtc_notify; 3191 config->xf86_crtc_notify = new; 3192 return old; 3193 } 3194 return NULL; 3195} 3196 3197void 3198xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) 3199{ 3200 if (xf86CrtcConfigPrivateIndex != -1) 3201 { 3202 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3203 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3204 3205 config->xf86_crtc_notify = old; 3206 } 3207} 3208 3209void 3210xf86_crtc_notify(ScreenPtr screen) 3211{ 3212 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3213 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3214 3215 if (config->xf86_crtc_notify) 3216 config->xf86_crtc_notify(screen); 3217} 3218 3219Bool 3220xf86_crtc_supports_gamma(ScrnInfoPtr pScrn) 3221{ 3222 if (xf86CrtcConfigPrivateIndex != -1) { 3223 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3224 xf86CrtcPtr crtc; 3225 3226 /* for multiple drivers loaded we need this */ 3227 if (!xf86_config) 3228 return FALSE; 3229 if (xf86_config->num_crtc == 0) 3230 return FALSE; 3231 crtc = xf86_config->crtc[0]; 3232 3233 return crtc->funcs->gamma_set != NULL; 3234 } 3235 3236 return FALSE; 3237} 3238