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