xf86Crtc.c revision b86d567b
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 RANDR_13_INTERFACE 773 return RANDR_INTERFACE_VERSION; 774#else 775 return TRUE; 776#endif 777} 778 779static DisplayModePtr 780xf86DefaultMode (xf86OutputPtr output, int width, int height) 781{ 782 DisplayModePtr target_mode = NULL; 783 DisplayModePtr mode; 784 int target_diff = 0; 785 int target_preferred = 0; 786 int mm_height; 787 788 mm_height = output->mm_height; 789 if (!mm_height) 790 mm_height = (768 * 25.4) / DEFAULT_DPI; 791 /* 792 * Pick a mode closest to DEFAULT_DPI 793 */ 794 for (mode = output->probed_modes; mode; mode = mode->next) 795 { 796 int dpi; 797 int preferred = (((mode->type & M_T_PREFERRED) != 0) + 798 ((mode->type & M_T_USERPREF) != 0)); 799 int diff; 800 801 if (xf86ModeWidth (mode, output->initial_rotation) > width || 802 xf86ModeHeight (mode, output->initial_rotation) > height) 803 continue; 804 805 /* yes, use VDisplay here, not xf86ModeHeight */ 806 dpi = (mode->VDisplay * 254) / (mm_height * 10); 807 diff = dpi - DEFAULT_DPI; 808 diff = diff < 0 ? -diff : diff; 809 if (target_mode == NULL || (preferred > target_preferred) || 810 (preferred == target_preferred && diff < target_diff)) 811 { 812 target_mode = mode; 813 target_diff = diff; 814 target_preferred = preferred; 815 } 816 } 817 return target_mode; 818} 819 820static DisplayModePtr 821xf86ClosestMode (xf86OutputPtr output, 822 DisplayModePtr match, Rotation match_rotation, 823 int width, int height) 824{ 825 DisplayModePtr target_mode = NULL; 826 DisplayModePtr mode; 827 int target_diff = 0; 828 829 /* 830 * Pick a mode closest to the specified mode 831 */ 832 for (mode = output->probed_modes; mode; mode = mode->next) 833 { 834 int dx, dy; 835 int diff; 836 837 if (xf86ModeWidth (mode, output->initial_rotation) > width || 838 xf86ModeHeight (mode, output->initial_rotation) > height) 839 continue; 840 841 /* exact matches are preferred */ 842 if (output->initial_rotation == match_rotation && 843 xf86ModesEqual (mode, match)) 844 return mode; 845 846 dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); 847 dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); 848 diff = dx * dx + dy * dy; 849 if (target_mode == NULL || diff < target_diff) 850 { 851 target_mode = mode; 852 target_diff = diff; 853 } 854 } 855 return target_mode; 856} 857 858static DisplayModePtr 859xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) 860{ 861 DisplayModePtr mode; 862 863 for (mode = output->probed_modes; mode; mode = mode->next) 864 { 865 if (xf86ModeWidth (mode, output->initial_rotation) > width || 866 xf86ModeHeight (mode, output->initial_rotation) > height) 867 continue; 868 869 if (mode->type & M_T_PREFERRED) 870 return mode; 871 } 872 return NULL; 873} 874 875static DisplayModePtr 876xf86OutputHasUserPreferredMode (xf86OutputPtr output) 877{ 878 DisplayModePtr mode, first = output->probed_modes; 879 880 for (mode = first; mode && mode->next != first; mode = mode->next) 881 if (mode->type & M_T_USERPREF) 882 return mode; 883 884 return NULL; 885} 886 887static int 888xf86PickCrtcs (ScrnInfoPtr scrn, 889 xf86CrtcPtr *best_crtcs, 890 DisplayModePtr *modes, 891 int n, 892 int width, 893 int height) 894{ 895 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 896 int c, o; 897 xf86OutputPtr output; 898 xf86CrtcPtr crtc; 899 xf86CrtcPtr *crtcs; 900 xf86CrtcPtr best_crtc; 901 int best_score; 902 int score; 903 int my_score; 904 905 if (n == config->num_output) 906 return 0; 907 output = config->output[n]; 908 909 /* 910 * Compute score with this output disabled 911 */ 912 best_crtcs[n] = NULL; 913 best_crtc = NULL; 914 best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height); 915 if (modes[n] == NULL) 916 return best_score; 917 918 crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr)); 919 if (!crtcs) 920 return best_score; 921 922 my_score = 1; 923 /* Score outputs that are known to be connected higher */ 924 if (output->status == XF86OutputStatusConnected) 925 my_score++; 926 /* Score outputs with preferred modes higher */ 927 if (xf86OutputHasPreferredMode (output, width, height)) 928 my_score++; 929 /* 930 * Select a crtc for this output and 931 * then attempt to configure the remaining 932 * outputs 933 */ 934 for (c = 0; c < config->num_crtc; c++) 935 { 936 if ((output->possible_crtcs & (1 << c)) == 0) 937 continue; 938 939 crtc = config->crtc[c]; 940 /* 941 * Check to see if some other output is 942 * using this crtc 943 */ 944 for (o = 0; o < n; o++) 945 if (best_crtcs[o] == crtc) 946 break; 947 if (o < n) 948 { 949 /* 950 * If the two outputs desire the same mode, 951 * see if they can be cloned 952 */ 953 if (xf86ModesEqual (modes[o], modes[n]) && 954 config->output[o]->initial_rotation == config->output[n]->initial_rotation && 955 config->output[o]->initial_x == config->output[n]->initial_x && 956 config->output[o]->initial_y == config->output[n]->initial_y) 957 { 958 if ((output->possible_clones & (1 << o)) == 0) 959 continue; /* nope, try next CRTC */ 960 } 961 else 962 continue; /* different modes, can't clone */ 963 } 964 crtcs[n] = crtc; 965 memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); 966 score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height); 967 if (score > best_score) 968 { 969 best_crtc = crtc; 970 best_score = score; 971 memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); 972 } 973 } 974 xfree (crtcs); 975 return best_score; 976} 977 978 979/* 980 * Compute the virtual size necessary to place all of the available 981 * crtcs in the specified configuration. 982 * 983 * canGrow indicates that the driver can make the screen larger than its initial 984 * configuration. If FALSE, this function will enlarge the screen to include 985 * the largest available mode. 986 */ 987 988static void 989xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp, 990 Bool canGrow) 991{ 992 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 993 int width = 0, height = 0; 994 int o; 995 int c; 996 int s; 997 998 for (c = 0; c < config->num_crtc; c++) 999 { 1000 int crtc_width = 0, crtc_height = 0; 1001 xf86CrtcPtr crtc = config->crtc[c]; 1002 1003 if (crtc->enabled) 1004 { 1005 crtc_width = crtc->x + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); 1006 crtc_height = crtc->y + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); 1007 } 1008 if (!canGrow) { 1009 for (o = 0; o < config->num_output; o++) 1010 { 1011 xf86OutputPtr output = config->output[o]; 1012 1013 for (s = 0; s < config->num_crtc; s++) 1014 if (output->possible_crtcs & (1 << s)) 1015 { 1016 DisplayModePtr mode; 1017 for (mode = output->probed_modes; mode; mode = mode->next) 1018 { 1019 if (mode->HDisplay > crtc_width) 1020 crtc_width = mode->HDisplay; 1021 if (mode->VDisplay > crtc_width) 1022 crtc_width = mode->VDisplay; 1023 if (mode->VDisplay > crtc_height) 1024 crtc_height = mode->VDisplay; 1025 if (mode->HDisplay > crtc_height) 1026 crtc_height = mode->HDisplay; 1027 } 1028 } 1029 } 1030 } 1031 if (crtc_width > width) 1032 width = crtc_width; 1033 if (crtc_height > height) 1034 height = crtc_height; 1035 } 1036 if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; 1037 if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; 1038 if (config->minWidth && width < config->minWidth) width = config->minWidth; 1039 if (config->minHeight && height < config->minHeight) height = config->minHeight; 1040 *widthp = width; 1041 *heightp = height; 1042} 1043 1044#define POSITION_UNSET -100000 1045 1046/* 1047 * check if the user configured any outputs at all 1048 * with either a position or a relative setting or a mode. 1049 */ 1050static Bool 1051xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr *modes) 1052{ 1053 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1054 int o; 1055 Bool user_conf = FALSE; 1056 1057 for (o = 0; o < config->num_output; o++) 1058 { 1059 xf86OutputPtr output = config->output[o]; 1060 char *position; 1061 char *relative_name; 1062 OutputOpts relation; 1063 int r; 1064 static const OutputOpts relations[] = { 1065 OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF 1066 }; 1067 1068 position = xf86GetOptValString (output->options, 1069 OPTION_POSITION); 1070 if (position) 1071 user_conf = TRUE; 1072 1073 relation = 0; 1074 relative_name = NULL; 1075 for (r = 0; r < 4; r++) 1076 { 1077 relation = relations[r]; 1078 relative_name = xf86GetOptValString (output->options, 1079 relation); 1080 if (relative_name) 1081 break; 1082 } 1083 if (relative_name) 1084 user_conf = TRUE; 1085 1086 modes[o] = xf86OutputHasUserPreferredMode(output); 1087 if (modes[o]) 1088 user_conf = TRUE; 1089 } 1090 1091 return user_conf; 1092} 1093 1094static Bool 1095xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) 1096{ 1097 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1098 int o; 1099 int min_x, min_y; 1100 1101 for (o = 0; o < config->num_output; o++) 1102 { 1103 xf86OutputPtr output = config->output[o]; 1104 1105 output->initial_x = output->initial_y = POSITION_UNSET; 1106 } 1107 1108 /* 1109 * Loop until all outputs are set 1110 */ 1111 for (;;) 1112 { 1113 Bool any_set = FALSE; 1114 Bool keep_going = FALSE; 1115 1116 for (o = 0; o < config->num_output; o++) 1117 { 1118 static const OutputOpts relations[] = { 1119 OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF 1120 }; 1121 xf86OutputPtr output = config->output[o]; 1122 xf86OutputPtr relative; 1123 char *relative_name; 1124 char *position; 1125 OutputOpts relation; 1126 int r; 1127 1128 if (output->initial_x != POSITION_UNSET) 1129 continue; 1130 position = xf86GetOptValString (output->options, 1131 OPTION_POSITION); 1132 /* 1133 * Absolute position wins 1134 */ 1135 if (position) 1136 { 1137 int x, y; 1138 if (sscanf (position, "%d %d", &x, &y) == 2) 1139 { 1140 output->initial_x = x; 1141 output->initial_y = y; 1142 } 1143 else 1144 { 1145 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 1146 "Output %s position not of form \"x y\"\n", 1147 output->name); 1148 output->initial_x = output->initial_y = 0; 1149 } 1150 any_set = TRUE; 1151 continue; 1152 } 1153 /* 1154 * Next comes relative positions 1155 */ 1156 relation = 0; 1157 relative_name = NULL; 1158 for (r = 0; r < 4; r++) 1159 { 1160 relation = relations[r]; 1161 relative_name = xf86GetOptValString (output->options, 1162 relation); 1163 if (relative_name) 1164 break; 1165 } 1166 if (relative_name) 1167 { 1168 int or; 1169 relative = NULL; 1170 for (or = 0; or < config->num_output; or++) 1171 { 1172 xf86OutputPtr out_rel = config->output[or]; 1173 XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; 1174 1175 if (rel_mon) 1176 { 1177 if (xf86nameCompare (rel_mon->mon_identifier, 1178 relative_name) == 0) 1179 { 1180 relative = config->output[or]; 1181 break; 1182 } 1183 } 1184 if (strcmp (out_rel->name, relative_name) == 0) 1185 { 1186 relative = config->output[or]; 1187 break; 1188 } 1189 } 1190 if (!relative) 1191 { 1192 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 1193 "Cannot position output %s relative to unknown output %s\n", 1194 output->name, relative_name); 1195 output->initial_x = 0; 1196 output->initial_y = 0; 1197 any_set = TRUE; 1198 continue; 1199 } 1200 if (!modes[or]) 1201 { 1202 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 1203 "Cannot position output %s relative to output %s without modes\n", 1204 output->name, relative_name); 1205 output->initial_x = 0; 1206 output->initial_y = 0; 1207 any_set = TRUE; 1208 continue; 1209 } 1210 if (relative->initial_x == POSITION_UNSET) 1211 { 1212 keep_going = TRUE; 1213 continue; 1214 } 1215 output->initial_x = relative->initial_x; 1216 output->initial_y = relative->initial_y; 1217 switch (relation) { 1218 case OPTION_BELOW: 1219 output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); 1220 break; 1221 case OPTION_RIGHT_OF: 1222 output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); 1223 break; 1224 case OPTION_ABOVE: 1225 if (modes[o]) 1226 output->initial_y -= xf86ModeHeight (modes[o], output->initial_rotation); 1227 break; 1228 case OPTION_LEFT_OF: 1229 if (modes[o]) 1230 output->initial_x -= xf86ModeWidth (modes[o], output->initial_rotation); 1231 break; 1232 default: 1233 break; 1234 } 1235 any_set = TRUE; 1236 continue; 1237 } 1238 1239 /* Nothing set, just stick them at 0,0 */ 1240 output->initial_x = 0; 1241 output->initial_y = 0; 1242 any_set = TRUE; 1243 } 1244 if (!keep_going) 1245 break; 1246 if (!any_set) 1247 { 1248 for (o = 0; o < config->num_output; o++) 1249 { 1250 xf86OutputPtr output = config->output[o]; 1251 if (output->initial_x == POSITION_UNSET) 1252 { 1253 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 1254 "Output position loop. Moving %s to 0,0\n", 1255 output->name); 1256 output->initial_x = output->initial_y = 0; 1257 break; 1258 } 1259 } 1260 } 1261 } 1262 1263 /* 1264 * normalize positions 1265 */ 1266 min_x = 1000000; 1267 min_y = 1000000; 1268 for (o = 0; o < config->num_output; o++) 1269 { 1270 xf86OutputPtr output = config->output[o]; 1271 1272 if (output->initial_x < min_x) 1273 min_x = output->initial_x; 1274 if (output->initial_y < min_y) 1275 min_y = output->initial_y; 1276 } 1277 1278 for (o = 0; o < config->num_output; o++) 1279 { 1280 xf86OutputPtr output = config->output[o]; 1281 1282 output->initial_x -= min_x; 1283 output->initial_y -= min_y; 1284 } 1285 return TRUE; 1286} 1287 1288static void 1289xf86InitialPanning (ScrnInfoPtr scrn) 1290{ 1291 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1292 int o; 1293 1294 for (o = 0; o < config->num_output; o++) 1295 { 1296 xf86OutputPtr output = config->output[o]; 1297 char *panning = xf86GetOptValString (output->options, OPTION_PANNING); 1298 int width, height, left, top; 1299 int track_width, track_height, track_left, track_top; 1300 int brdr[4]; 1301 1302 memset (&output->initialTotalArea, 0, sizeof(BoxRec)); 1303 memset (&output->initialTrackingArea, 0, sizeof(BoxRec)); 1304 memset (output->initialBorder, 0, 4*sizeof(INT16)); 1305 1306 if (! panning) 1307 continue; 1308 1309 switch (sscanf (panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", 1310 &width, &height, &left, &top, 1311 &track_width, &track_height, &track_left, &track_top, 1312 &brdr[0], &brdr[1], &brdr[2], &brdr[3])) { 1313 case 12: 1314 output->initialBorder[0] = brdr[0]; 1315 output->initialBorder[1] = brdr[1]; 1316 output->initialBorder[2] = brdr[2]; 1317 output->initialBorder[3] = brdr[3]; 1318 /* fall through */ 1319 case 8: 1320 output->initialTrackingArea.x1 = track_left; 1321 output->initialTrackingArea.y1 = track_top; 1322 output->initialTrackingArea.x2 = track_left + track_width; 1323 output->initialTrackingArea.y2 = track_top + track_height; 1324 /* fall through */ 1325 case 4: 1326 output->initialTotalArea.x1 = left; 1327 output->initialTotalArea.y1 = top; 1328 /* fall through */ 1329 case 2: 1330 output->initialTotalArea.x2 = output->initialTotalArea.x1 + width; 1331 output->initialTotalArea.y2 = output->initialTotalArea.y1 + height; 1332 break; 1333 default: 1334 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 1335 "Broken panning specification '%s' for output %s in config file\n", 1336 panning, output->name); 1337 } 1338 } 1339} 1340 1341/* 1342 * XXX walk the monitor mode list and prune out duplicates that 1343 * are inserted by xf86DDCMonitorSet. In an ideal world, that 1344 * function would do this work by itself. 1345 */ 1346 1347static void 1348xf86PruneDuplicateMonitorModes (MonPtr Monitor) 1349{ 1350 DisplayModePtr master, clone, next; 1351 1352 for (master = Monitor->Modes; 1353 master && master != Monitor->Last; 1354 master = master->next) 1355 { 1356 for (clone = master->next; clone && clone != Monitor->Modes; clone = next) 1357 { 1358 next = clone->next; 1359 if (xf86ModesEqual (master, clone)) 1360 { 1361 if (Monitor->Last == clone) 1362 Monitor->Last = clone->prev; 1363 xf86DeleteMode (&Monitor->Modes, clone); 1364 } 1365 } 1366 } 1367} 1368 1369/** Return - 0 + if a should be earlier, same or later than b in list 1370 */ 1371static int 1372xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) 1373{ 1374 int diff; 1375 1376 diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); 1377 if (diff) 1378 return diff; 1379 diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; 1380 if (diff) 1381 return diff; 1382 diff = b->Clock - a->Clock; 1383 return diff; 1384} 1385 1386/** 1387 * Insertion sort input in-place and return the resulting head 1388 */ 1389static DisplayModePtr 1390xf86SortModes (DisplayModePtr input) 1391{ 1392 DisplayModePtr output = NULL, i, o, n, *op, prev; 1393 1394 /* sort by preferred status and pixel area */ 1395 while (input) 1396 { 1397 i = input; 1398 input = input->next; 1399 for (op = &output; (o = *op); op = &o->next) 1400 if (xf86ModeCompare (o, i) > 0) 1401 break; 1402 i->next = *op; 1403 *op = i; 1404 } 1405 /* prune identical modes */ 1406 for (o = output; o && (n = o->next); o = n) 1407 { 1408 if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) 1409 { 1410 o->next = n->next; 1411 xfree (n->name); 1412 xfree (n); 1413 n = o; 1414 } 1415 } 1416 /* hook up backward links */ 1417 prev = NULL; 1418 for (o = output; o; o = o->next) 1419 { 1420 o->prev = prev; 1421 prev = o; 1422 } 1423 return output; 1424} 1425 1426static char * 1427preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output) 1428{ 1429 char *preferred_mode = NULL; 1430 1431 /* Check for a configured preference for a particular mode */ 1432 preferred_mode = xf86GetOptValString (output->options, 1433 OPTION_PREFERRED_MODE); 1434 if (preferred_mode) 1435 return preferred_mode; 1436 1437 if (pScrn->display->modes && *pScrn->display->modes) 1438 preferred_mode = *pScrn->display->modes; 1439 1440 return preferred_mode; 1441} 1442 1443static void 1444GuessRangeFromModes(MonPtr mon, DisplayModePtr mode) 1445{ 1446 if (!mon || !mode) 1447 return; 1448 1449 mon->nHsync = 1; 1450 mon->hsync[0].lo = 1024.0; 1451 mon->hsync[0].hi = 0.0; 1452 1453 mon->nVrefresh = 1; 1454 mon->vrefresh[0].lo = 1024.0; 1455 mon->vrefresh[0].hi = 0.0; 1456 1457 while (mode) { 1458 if (!mode->HSync) 1459 mode->HSync = ((float) mode->Clock ) / ((float) mode->HTotal); 1460 1461 if (!mode->VRefresh) 1462 mode->VRefresh = (1000.0 * ((float) mode->Clock)) / 1463 ((float) (mode->HTotal * mode->VTotal)); 1464 1465 if (mode->HSync < mon->hsync[0].lo) 1466 mon->hsync[0].lo = mode->HSync; 1467 1468 if (mode->HSync > mon->hsync[0].hi) 1469 mon->hsync[0].hi = mode->HSync; 1470 1471 if (mode->VRefresh < mon->vrefresh[0].lo) 1472 mon->vrefresh[0].lo = mode->VRefresh; 1473 1474 if (mode->VRefresh > mon->vrefresh[0].hi) 1475 mon->vrefresh[0].hi = mode->VRefresh; 1476 1477 mode = mode->next; 1478 } 1479 1480 /* stretch out the bottom to fit 640x480@60 */ 1481 if (mon->hsync[0].lo > 31.0) 1482 mon->hsync[0].lo = 31.0; 1483 if (mon->vrefresh[0].lo > 58.0) 1484 mon->vrefresh[0].lo = 58.0; 1485} 1486 1487_X_EXPORT void 1488xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) 1489{ 1490 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1491 int o; 1492 1493 /* When canGrow was TRUE in the initial configuration we have to 1494 * compare against the maximum values so that we don't drop modes. 1495 * When canGrow was FALSE, the maximum values would have been clamped 1496 * anyway. 1497 */ 1498 if (maxX == 0 || maxY == 0) { 1499 maxX = config->maxWidth; 1500 maxY = config->maxHeight; 1501 } 1502 1503 /* Elide duplicate modes before defaulting code uses them */ 1504 xf86PruneDuplicateMonitorModes (scrn->monitor); 1505 1506 /* Probe the list of modes for each output. */ 1507 for (o = 0; o < config->num_output; o++) 1508 { 1509 xf86OutputPtr output = config->output[o]; 1510 DisplayModePtr mode; 1511 DisplayModePtr config_modes = NULL, output_modes, default_modes = NULL; 1512 char *preferred_mode; 1513 xf86MonPtr edid_monitor; 1514 XF86ConfMonitorPtr conf_monitor; 1515 MonRec mon_rec; 1516 int min_clock = 0; 1517 int max_clock = 0; 1518 double clock; 1519 Bool add_default_modes = TRUE; 1520 enum { sync_config, sync_edid, sync_default } sync_source = sync_default; 1521 1522 while (output->probed_modes != NULL) 1523 xf86DeleteMode(&output->probed_modes, output->probed_modes); 1524 1525 /* 1526 * Check connection status 1527 */ 1528 output->status = (*output->funcs->detect)(output); 1529 1530 if (output->status == XF86OutputStatusDisconnected) 1531 { 1532 xf86OutputSetEDID (output, NULL); 1533 continue; 1534 } 1535 1536 memset (&mon_rec, '\0', sizeof (mon_rec)); 1537 1538 conf_monitor = output->conf_monitor; 1539 1540 if (conf_monitor) 1541 { 1542 int i; 1543 1544 for (i = 0; i < conf_monitor->mon_n_hsync; i++) 1545 { 1546 mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; 1547 mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; 1548 mon_rec.nHsync++; 1549 sync_source = sync_config; 1550 } 1551 for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) 1552 { 1553 mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; 1554 mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; 1555 mon_rec.nVrefresh++; 1556 sync_source = sync_config; 1557 } 1558 config_modes = xf86GetMonitorModes (scrn, conf_monitor); 1559 } 1560 1561 output_modes = (*output->funcs->get_modes) (output); 1562 1563 edid_monitor = output->MonInfo; 1564 1565 if (edid_monitor) 1566 { 1567 int i; 1568 Bool set_hsync = mon_rec.nHsync == 0; 1569 Bool set_vrefresh = mon_rec.nVrefresh == 0; 1570 struct disp_features *features = &edid_monitor->features; 1571 1572 /* if display is not continuous-frequency, don't add default modes */ 1573 if (!GTF_SUPPORTED(features->msc)) 1574 add_default_modes = FALSE; 1575 1576 for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++) 1577 { 1578 if (edid_monitor->det_mon[i].type == DS_RANGES) 1579 { 1580 struct monitor_ranges *ranges = &edid_monitor->det_mon[i].section.ranges; 1581 if (set_hsync && ranges->max_h) 1582 { 1583 mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h; 1584 mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h; 1585 mon_rec.nHsync++; 1586 if (sync_source == sync_default) 1587 sync_source = sync_edid; 1588 } 1589 if (set_vrefresh && ranges->max_v) 1590 { 1591 mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v; 1592 mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v; 1593 mon_rec.nVrefresh++; 1594 if (sync_source == sync_default) 1595 sync_source = sync_edid; 1596 } 1597 if (ranges->max_clock * 1000 > max_clock) 1598 max_clock = ranges->max_clock * 1000; 1599 } 1600 } 1601 } 1602 1603 if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, 1604 OPTUNITS_KHZ, &clock)) 1605 min_clock = (int) clock; 1606 if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, 1607 OPTUNITS_KHZ, &clock)) 1608 max_clock = (int) clock; 1609 1610 /* If we still don't have a sync range, guess wildly */ 1611 if (!mon_rec.nHsync || !mon_rec.nVrefresh) 1612 GuessRangeFromModes(&mon_rec, output_modes); 1613 1614 /* 1615 * These limits will end up setting a 1024x768@60Hz mode by default, 1616 * which seems like a fairly good mode to use when nothing else is 1617 * specified 1618 */ 1619 if (mon_rec.nHsync == 0) 1620 { 1621 mon_rec.hsync[0].lo = 31.0; 1622 mon_rec.hsync[0].hi = 55.0; 1623 mon_rec.nHsync = 1; 1624 } 1625 if (mon_rec.nVrefresh == 0) 1626 { 1627 mon_rec.vrefresh[0].lo = 58.0; 1628 mon_rec.vrefresh[0].hi = 62.0; 1629 mon_rec.nVrefresh = 1; 1630 } 1631 1632 if (add_default_modes) 1633 default_modes = xf86GetDefaultModes (output->interlaceAllowed, 1634 output->doubleScanAllowed); 1635 1636 /* 1637 * If this is not an RB monitor, remove RB modes from the default 1638 * pool. RB modes from the config or the monitor itself are fine. 1639 */ 1640 if (!mon_rec.reducedblanking) 1641 xf86ValidateModesReducedBlanking (scrn, default_modes); 1642 1643 if (sync_source == sync_config) 1644 { 1645 /* 1646 * Check output and config modes against sync range from config file 1647 */ 1648 xf86ValidateModesSync (scrn, output_modes, &mon_rec); 1649 xf86ValidateModesSync (scrn, config_modes, &mon_rec); 1650 } 1651 /* 1652 * Check default modes against sync range 1653 */ 1654 xf86ValidateModesSync (scrn, default_modes, &mon_rec); 1655 /* 1656 * Check default modes against monitor max clock 1657 */ 1658 if (max_clock) { 1659 xf86ValidateModesClocks(scrn, default_modes, 1660 &min_clock, &max_clock, 1); 1661 xf86ValidateModesClocks(scrn, output_modes, 1662 &min_clock, &max_clock, 1); 1663 } 1664 1665 output->probed_modes = NULL; 1666 output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); 1667 output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); 1668 output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); 1669 1670 /* 1671 * Check all modes against max size 1672 */ 1673 if (maxX && maxY) 1674 xf86ValidateModesSize (scrn, output->probed_modes, 1675 maxX, maxY, 0); 1676 1677 /* 1678 * Check all modes against output 1679 */ 1680 for (mode = output->probed_modes; mode != NULL; mode = mode->next) 1681 if (mode->status == MODE_OK) 1682 mode->status = (*output->funcs->mode_valid)(output, mode); 1683 1684 xf86PruneInvalidModes(scrn, &output->probed_modes, 1685 config->debug_modes); 1686 1687 output->probed_modes = xf86SortModes (output->probed_modes); 1688 1689 /* Check for a configured preference for a particular mode */ 1690 preferred_mode = preferredMode(scrn, output); 1691 1692 if (preferred_mode) 1693 { 1694 for (mode = output->probed_modes; mode; mode = mode->next) 1695 { 1696 if (!strcmp (preferred_mode, mode->name)) 1697 { 1698 if (mode != output->probed_modes) 1699 { 1700 if (mode->prev) 1701 mode->prev->next = mode->next; 1702 if (mode->next) 1703 mode->next->prev = mode->prev; 1704 mode->next = output->probed_modes; 1705 output->probed_modes->prev = mode; 1706 mode->prev = NULL; 1707 output->probed_modes = mode; 1708 } 1709 mode->type |= (M_T_PREFERRED|M_T_USERPREF); 1710 break; 1711 } 1712 } 1713 } 1714 1715 output->initial_rotation = xf86OutputInitialRotation (output); 1716 1717 if (config->debug_modes) { 1718 if (output->probed_modes != NULL) { 1719 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1720 "Printing probed modes for output %s\n", 1721 output->name); 1722 } else { 1723 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1724 "No remaining probed modes for output %s\n", 1725 output->name); 1726 } 1727 } 1728 for (mode = output->probed_modes; mode != NULL; mode = mode->next) 1729 { 1730 /* The code to choose the best mode per pipe later on will require 1731 * VRefresh to be set. 1732 */ 1733 mode->VRefresh = xf86ModeVRefresh(mode); 1734 xf86SetModeCrtc(mode, INTERLACE_HALVE_V); 1735 1736 if (config->debug_modes) 1737 xf86PrintModeline(scrn->scrnIndex, mode); 1738 } 1739 } 1740} 1741 1742 1743/** 1744 * Copy one of the output mode lists to the ScrnInfo record 1745 */ 1746 1747/* XXX where does this function belong? Here? */ 1748_X_EXPORT void 1749xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); 1750 1751static DisplayModePtr 1752biggestMode(DisplayModePtr a, DisplayModePtr b) 1753{ 1754 int A, B; 1755 1756 if (!a) 1757 return b; 1758 if (!b) 1759 return a; 1760 1761 A = a->HDisplay * a->VDisplay; 1762 B = b->HDisplay * b->VDisplay; 1763 1764 if (A > B) 1765 return a; 1766 1767 return b; 1768} 1769 1770static xf86OutputPtr 1771SetCompatOutput(xf86CrtcConfigPtr config) 1772{ 1773 xf86OutputPtr output = NULL, test = NULL; 1774 DisplayModePtr maxmode = NULL, testmode, mode; 1775 int o, compat = -1, count, mincount = 0; 1776 1777 /* Look for one that's definitely connected */ 1778 for (o = 0; o < config->num_output; o++) 1779 { 1780 test = config->output[o]; 1781 if (!test->crtc) 1782 continue; 1783 if (test->status != XF86OutputStatusConnected) 1784 continue; 1785 if (!test->probed_modes) 1786 continue; 1787 1788 testmode = mode = test->probed_modes; 1789 for (count = 0; mode; mode = mode->next, count++) 1790 testmode = biggestMode(testmode, mode); 1791 1792 if (!output) { 1793 output = test; 1794 compat = o; 1795 maxmode = testmode; 1796 mincount = count; 1797 } else if (maxmode == biggestMode(maxmode, testmode)) { 1798 output = test; 1799 compat = o; 1800 maxmode = testmode; 1801 mincount = count; 1802 } else if ((maxmode->HDisplay == testmode->HDisplay) && 1803 (maxmode->VDisplay == testmode->VDisplay) && 1804 count <= mincount) { 1805 output = test; 1806 compat = o; 1807 maxmode = testmode; 1808 mincount = count; 1809 } 1810 } 1811 1812 /* If we didn't find one, take anything we can get */ 1813 if (!output) 1814 { 1815 for (o = 0; o < config->num_output; o++) 1816 { 1817 test = config->output[o]; 1818 if (!test->crtc) 1819 continue; 1820 if (!test->probed_modes) 1821 continue; 1822 1823 if (!output) { 1824 output = test; 1825 compat = o; 1826 } else if (test->probed_modes->HDisplay < output->probed_modes->HDisplay) { 1827 output = test; 1828 compat = o; 1829 } 1830 } 1831 } 1832 1833 if (compat >= 0) { 1834 config->compat_output = compat; 1835 } else { 1836 /* Don't change the compat output when no valid outputs found */ 1837 output = config->output[config->compat_output]; 1838 } 1839 1840 return output; 1841} 1842 1843_X_EXPORT void 1844xf86SetScrnInfoModes (ScrnInfoPtr scrn) 1845{ 1846 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1847 xf86OutputPtr output; 1848 xf86CrtcPtr crtc; 1849 DisplayModePtr last, mode = NULL; 1850 1851 output = SetCompatOutput(config); 1852 1853 if (!output) 1854 return; /* punt */ 1855 1856 crtc = output->crtc; 1857 1858 /* Clear any existing modes from scrn->modes */ 1859 while (scrn->modes != NULL) 1860 xf86DeleteMode(&scrn->modes, scrn->modes); 1861 1862 /* Set scrn->modes to the mode list for the 'compat' output */ 1863 scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); 1864 1865 if (crtc) { 1866 for (mode = scrn->modes; mode; mode = mode->next) 1867 if (xf86ModesEqual (mode, &crtc->desiredMode)) 1868 break; 1869 } 1870 1871 if (scrn->modes != NULL) { 1872 /* For some reason, scrn->modes is circular, unlike the other mode 1873 * lists. How great is that? 1874 */ 1875 for (last = scrn->modes; last && last->next; last = last->next) 1876 ; 1877 last->next = scrn->modes; 1878 scrn->modes->prev = last; 1879 if (mode) { 1880 while (scrn->modes != mode) 1881 scrn->modes = scrn->modes->next; 1882 } 1883 } 1884 scrn->currentMode = scrn->modes; 1885} 1886 1887static void 1888xf86EnableOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, Bool *enabled) 1889{ 1890 Bool any_enabled = FALSE; 1891 int o; 1892 1893 for (o = 0; o < config->num_output; o++) 1894 any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE); 1895 1896 if (!any_enabled) { 1897 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1898 "No outputs definitely connected, trying again...\n"); 1899 1900 for (o = 0; o < config->num_output; o++) 1901 enabled[o] = xf86OutputEnabled(config->output[o], FALSE); 1902 } 1903} 1904 1905static Bool 1906nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index) 1907{ 1908 int o = *index; 1909 1910 for (o++; o < config->num_output; o++) { 1911 if (enabled[o]) { 1912 *index = o; 1913 return TRUE; 1914 } 1915 } 1916 1917 return FALSE; 1918} 1919 1920static Bool 1921aspectMatch(float a, float b) 1922{ 1923 return fabs(1 - (a / b)) < 0.05; 1924} 1925 1926static DisplayModePtr 1927nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect) 1928{ 1929 DisplayModePtr m = NULL; 1930 1931 if (!o) 1932 return NULL; 1933 1934 if (!last) 1935 m = o->probed_modes; 1936 else 1937 m = last->next; 1938 1939 for (; m; m = m->next) 1940 if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay)) 1941 return m; 1942 1943 return NULL; 1944} 1945 1946static DisplayModePtr 1947bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect) 1948{ 1949 int o = -1, p; 1950 DisplayModePtr mode = NULL, test = NULL, match = NULL; 1951 1952 if (!nextEnabledOutput(config, enabled, &o)) 1953 return NULL; 1954 while ((mode = nextAspectMode(config->output[o], mode, aspect))) { 1955 test = mode; 1956 for (p = o; nextEnabledOutput(config, enabled, &p); ) { 1957 test = xf86OutputFindClosestMode(config->output[p], mode); 1958 if (!test) 1959 break; 1960 if (test->HDisplay != mode->HDisplay || 1961 test->VDisplay != mode->VDisplay) { 1962 test = NULL; 1963 break; 1964 } 1965 } 1966 1967 /* if we didn't match it on all outputs, try the next one */ 1968 if (!test) 1969 continue; 1970 1971 /* if it's bigger than the last one, save it */ 1972 if (!match || (test->HDisplay > match->HDisplay)) 1973 match = test; 1974 } 1975 1976 /* return the biggest one found */ 1977 return match; 1978} 1979 1980static Bool 1981xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 1982 DisplayModePtr *modes, Bool *enabled, 1983 int width, int height) 1984{ 1985 int o, p; 1986 int max_pref_width = 0, max_pref_height = 0; 1987 DisplayModePtr *preferred, *preferred_match; 1988 Bool ret = FALSE; 1989 1990 preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 1991 preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr)); 1992 1993 /* Check if the preferred mode is available on all outputs */ 1994 for (p = -1; nextEnabledOutput(config, enabled, &p); ) { 1995 Rotation r = config->output[p]->initial_rotation; 1996 DisplayModePtr mode; 1997 if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p], 1998 width, height))) { 1999 int pref_width = xf86ModeWidth(preferred[p], r); 2000 int pref_height = xf86ModeHeight(preferred[p], r); 2001 Bool all_match = TRUE; 2002 2003 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2004 Bool match = FALSE; 2005 xf86OutputPtr output = config->output[o]; 2006 if (o == p) 2007 continue; 2008 2009 for (mode = output->probed_modes; mode; mode = mode->next) { 2010 Rotation r = output->initial_rotation; 2011 if (xf86ModeWidth(mode, r) == pref_width && 2012 xf86ModeHeight(mode, r) == pref_height) { 2013 preferred[o] = mode; 2014 match = TRUE; 2015 } 2016 } 2017 2018 all_match &= match; 2019 } 2020 2021 if (all_match && 2022 (pref_width*pref_height > max_pref_width*max_pref_height)) { 2023 for (o = -1; nextEnabledOutput(config, enabled, &o); ) 2024 preferred_match[o] = preferred[o]; 2025 max_pref_width = pref_width; 2026 max_pref_height = pref_height; 2027 ret = TRUE; 2028 } 2029 } 2030 } 2031 2032 /* 2033 * If there's no preferred mode, but only one monitor, pick the 2034 * biggest mode for its aspect ratio, assuming one exists. 2035 */ 2036 if (!ret) do { 2037 int i = 0; 2038 float aspect = 0.0; 2039 2040 /* count the number of enabled outputs */ 2041 for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ; 2042 2043 if (i != 1) 2044 break; 2045 2046 p = -1; 2047 nextEnabledOutput(config, enabled, &p); 2048 if (config->output[p]->mm_height) 2049 aspect = (float)config->output[p]->mm_width / 2050 (float)config->output[p]->mm_height; 2051 2052 if (aspect) 2053 preferred_match[p] = bestModeForAspect(config, enabled, aspect); 2054 2055 if (preferred_match[p]) 2056 ret = TRUE; 2057 2058 } while (0); 2059 2060 if (ret) { 2061 /* oh good, there is a match. stash the selected modes and return. */ 2062 memcpy(modes, preferred_match, 2063 config->num_output * sizeof(DisplayModePtr)); 2064 } 2065 2066 xfree(preferred); 2067 xfree(preferred_match); 2068 return ret; 2069} 2070 2071static Bool 2072xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2073 DisplayModePtr *modes, Bool *enabled, 2074 int width, int height) 2075{ 2076 int o; 2077 float aspect = 0.0, *aspects; 2078 xf86OutputPtr output; 2079 Bool ret = FALSE; 2080 DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL; 2081 2082 aspects = xnfcalloc(config->num_output, sizeof(float)); 2083 2084 /* collect the aspect ratios */ 2085 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2086 output = config->output[o]; 2087 if (output->mm_height) 2088 aspects[o] = (float)output->mm_width / (float)output->mm_height; 2089 else 2090 aspects[o] = 4.0 / 3.0; 2091 } 2092 2093 /* check that they're all the same */ 2094 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2095 output = config->output[o]; 2096 if (!aspect) { 2097 aspect = aspects[o]; 2098 } else if (!aspectMatch(aspect, aspects[o])) { 2099 goto no_aspect_match; 2100 } 2101 } 2102 2103 /* if they're all 4:3, just skip ahead and save effort */ 2104 if (!aspectMatch(aspect, 4.0/3.0)) 2105 aspect_guess = bestModeForAspect(config, enabled, aspect); 2106 2107no_aspect_match: 2108 base_guess = bestModeForAspect(config, enabled, 4.0/3.0); 2109 2110 guess = biggestMode(base_guess, aspect_guess); 2111 2112 if (!guess) 2113 goto out; 2114 2115 /* found a mode that works everywhere, now apply it */ 2116 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2117 modes[o] = xf86OutputFindClosestMode(config->output[o], guess); 2118 } 2119 ret = TRUE; 2120 2121out: 2122 xfree(aspects); 2123 return ret; 2124} 2125 2126static Bool 2127xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2128 DisplayModePtr *modes, Bool *enabled, 2129 int width, int height) 2130{ 2131 DisplayModePtr target_mode = NULL; 2132 Rotation target_rotation = RR_Rotate_0; 2133 DisplayModePtr default_mode; 2134 int default_preferred, target_preferred = 0, o; 2135 2136 /* User preferred > preferred > other modes */ 2137 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2138 default_mode = xf86DefaultMode (config->output[o], width, height); 2139 if (!default_mode) 2140 continue; 2141 2142 default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) + 2143 ((default_mode->type & M_T_USERPREF) != 0)); 2144 2145 if (default_preferred > target_preferred || !target_mode) { 2146 target_mode = default_mode; 2147 target_preferred = default_preferred; 2148 target_rotation = config->output[o]->initial_rotation; 2149 config->compat_output = o; 2150 } 2151 } 2152 2153 if (target_mode) 2154 modes[config->compat_output] = target_mode; 2155 2156 /* Fill in other output modes */ 2157 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2158 if (!modes[o]) 2159 modes[o] = xf86ClosestMode(config->output[o], target_mode, 2160 target_rotation, width, height); 2161 } 2162 2163 return (target_mode != NULL); 2164} 2165 2166static Bool 2167xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, 2168 DisplayModePtr *modes, Bool *enabled, 2169 int width, int height) 2170{ 2171 int o; 2172 2173 if (xf86UserConfiguredOutputs(scrn, modes)) 2174 return xf86TargetFallback(scrn, config, modes, enabled, width, height); 2175 2176 for (o = -1; nextEnabledOutput(config, enabled, &o); ) 2177 if (xf86OutputHasUserPreferredMode(config->output[o])) 2178 return 2179 xf86TargetFallback(scrn, config, modes, enabled, width, height); 2180 2181 return FALSE; 2182} 2183 2184 2185/** 2186 * Construct default screen configuration 2187 * 2188 * Given auto-detected (and, eventually, configured) values, 2189 * construct a usable configuration for the system 2190 * 2191 * canGrow indicates that the driver can resize the screen to larger than its 2192 * initially configured size via the config->funcs->resize hook. If TRUE, this 2193 * function will set virtualX and virtualY to match the initial configuration 2194 * and leave config->max{Width,Height} alone. If FALSE, it will bloat 2195 * virtual[XY] to include the largest modes and set config->max{Width,Height} 2196 * accordingly. 2197 */ 2198 2199_X_EXPORT Bool 2200xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) 2201{ 2202 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2203 int o, c; 2204 xf86CrtcPtr *crtcs; 2205 DisplayModePtr *modes; 2206 Bool *enabled; 2207 int width, height; 2208 int i = scrn->scrnIndex; 2209 2210 /* Set up the device options */ 2211 config->options = xnfalloc (sizeof (xf86DeviceOptions)); 2212 memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); 2213 xf86ProcessOptions (scrn->scrnIndex, 2214 scrn->options, 2215 config->options); 2216 config->debug_modes = xf86ReturnOptValBool (config->options, 2217 OPTION_MODEDEBUG, FALSE); 2218 2219 if (scrn->display->virtualX) 2220 width = scrn->display->virtualX; 2221 else 2222 width = config->maxWidth; 2223 if (scrn->display->virtualY) 2224 height = scrn->display->virtualY; 2225 else 2226 height = config->maxHeight; 2227 2228 xf86ProbeOutputModes (scrn, width, height); 2229 2230 crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); 2231 modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); 2232 enabled = xnfcalloc (config->num_output, sizeof (Bool)); 2233 2234 xf86EnableOutputs(scrn, config, enabled); 2235 2236 if (xf86TargetUserpref(scrn, config, modes, enabled, width, height)) 2237 xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n"); 2238 else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height)) 2239 xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n"); 2240 else if (xf86TargetAspect(scrn, config, modes, enabled, width, height)) 2241 xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n"); 2242 else if (xf86TargetFallback(scrn, config, modes, enabled, width, height)) 2243 xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n"); 2244 else 2245 xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n"); 2246 2247 for (o = -1; nextEnabledOutput(config, enabled, &o); ) { 2248 if (!modes[o]) 2249 xf86DrvMsg (scrn->scrnIndex, X_ERROR, 2250 "Output %s enabled but has no modes\n", 2251 config->output[o]->name); 2252 else 2253 xf86DrvMsg (scrn->scrnIndex, X_INFO, 2254 "Output %s using initial mode %s\n", 2255 config->output[o]->name, modes[o]->name); 2256 } 2257 2258 /* 2259 * Set the position of each output 2260 */ 2261 if (!xf86InitialOutputPositions (scrn, modes)) 2262 { 2263 xfree (crtcs); 2264 xfree (modes); 2265 return FALSE; 2266 } 2267 2268 /* 2269 * Set initial panning of each output 2270 */ 2271 xf86InitialPanning (scrn); 2272 2273 /* 2274 * Assign CRTCs to fit output configuration 2275 */ 2276 if (!xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) 2277 { 2278 xfree (crtcs); 2279 xfree (modes); 2280 return FALSE; 2281 } 2282 2283 /* XXX override xf86 common frame computation code */ 2284 2285 scrn->display->frameX0 = 0; 2286 scrn->display->frameY0 = 0; 2287 2288 for (c = 0; c < config->num_crtc; c++) 2289 { 2290 xf86CrtcPtr crtc = config->crtc[c]; 2291 2292 crtc->enabled = FALSE; 2293 memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); 2294 } 2295 2296 /* 2297 * Set initial configuration 2298 */ 2299 for (o = 0; o < config->num_output; o++) 2300 { 2301 xf86OutputPtr output = config->output[o]; 2302 DisplayModePtr mode = modes[o]; 2303 xf86CrtcPtr crtc = crtcs[o]; 2304 2305 if (mode && crtc) 2306 { 2307 crtc->desiredMode = *mode; 2308 crtc->desiredRotation = output->initial_rotation; 2309 crtc->desiredX = output->initial_x; 2310 crtc->desiredY = output->initial_y; 2311 crtc->desiredTransformPresent = FALSE; 2312 crtc->enabled = TRUE; 2313 crtc->x = output->initial_x; 2314 crtc->y = output->initial_y; 2315 memcpy (&crtc->panningTotalArea, &output->initialTotalArea, sizeof(BoxRec)); 2316 memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, sizeof(BoxRec)); 2317 memcpy (crtc->panningBorder, output->initialBorder, 4*sizeof(INT16)); 2318 output->crtc = crtc; 2319 } else { 2320 output->crtc = NULL; 2321 } 2322 } 2323 2324 if (scrn->display->virtualX == 0) 2325 { 2326 /* 2327 * Expand virtual size to cover the current config and potential mode 2328 * switches, if the driver can't enlarge the screen later. 2329 */ 2330 xf86DefaultScreenLimits (scrn, &width, &height, canGrow); 2331 2332 scrn->display->virtualX = width; 2333 scrn->display->virtualY = height; 2334 } 2335 2336 if (width > scrn->virtualX) 2337 scrn->virtualX = width; 2338 if (height > scrn->virtualY) 2339 scrn->virtualY = height; 2340 2341 /* 2342 * Make sure the configuration isn't too small. 2343 */ 2344 if (width < config->minWidth || height < config->minHeight) 2345 return FALSE; 2346 2347 /* 2348 * Limit the crtc config to virtual[XY] if the driver can't grow the 2349 * desktop. 2350 */ 2351 if (!canGrow) 2352 { 2353 xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, 2354 width, height); 2355 } 2356 2357 /* Mirror output modes to scrn mode list */ 2358 xf86SetScrnInfoModes (scrn); 2359 2360 xfree (crtcs); 2361 xfree (modes); 2362 return TRUE; 2363} 2364 2365/* 2366 * Check the CRTC we're going to map each output to vs. it's current 2367 * CRTC. If they don't match, we have to disable the output and the CRTC 2368 * since the driver will have to re-route things. 2369 */ 2370static void 2371xf86PrepareOutputs (ScrnInfoPtr scrn) 2372{ 2373 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2374 int o; 2375 2376 for (o = 0; o < config->num_output; o++) { 2377 xf86OutputPtr output = config->output[o]; 2378#if RANDR_GET_CRTC_INTERFACE 2379 /* Disable outputs that are unused or will be re-routed */ 2380 if (!output->funcs->get_crtc || 2381 output->crtc != (*output->funcs->get_crtc)(output) || 2382 output->crtc == NULL) 2383#endif 2384 (*output->funcs->dpms)(output, DPMSModeOff); 2385 } 2386} 2387 2388static void 2389xf86PrepareCrtcs (ScrnInfoPtr scrn) 2390{ 2391 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2392 int c; 2393 2394 for (c = 0; c < config->num_crtc; c++) { 2395#if RANDR_GET_CRTC_INTERFACE 2396 xf86CrtcPtr crtc = config->crtc[c]; 2397 xf86OutputPtr output = NULL; 2398 uint32_t desired_outputs = 0, current_outputs = 0; 2399 int o; 2400 2401 for (o = 0; o < config->num_output; o++) { 2402 output = config->output[o]; 2403 if (output->crtc == crtc) 2404 desired_outputs |= (1<<o); 2405 /* If we can't tell where it's mapped, force it off */ 2406 if (!output->funcs->get_crtc) { 2407 desired_outputs = 0; 2408 break; 2409 } 2410 if ((*output->funcs->get_crtc)(output) == crtc) 2411 current_outputs |= (1<<o); 2412 } 2413 2414 /* 2415 * If mappings are different or the CRTC is unused, 2416 * we need to disable it 2417 */ 2418 if (desired_outputs != current_outputs || 2419 !desired_outputs) 2420 (*crtc->funcs->dpms)(crtc, DPMSModeOff); 2421#else 2422 (*crtc->funcs->dpms)(crtc, DPMSModeOff); 2423#endif 2424 } 2425} 2426 2427/* 2428 * Using the desired mode information in each crtc, set 2429 * modes (used in EnterVT functions, or at server startup) 2430 */ 2431 2432_X_EXPORT Bool 2433xf86SetDesiredModes (ScrnInfoPtr scrn) 2434{ 2435 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2436 xf86CrtcPtr crtc = config->crtc[0]; 2437 int c; 2438 2439 /* A driver with this hook will take care of this */ 2440 if (!crtc->funcs->set_mode_major) { 2441 xf86PrepareOutputs(scrn); 2442 xf86PrepareCrtcs(scrn); 2443 } 2444 2445 for (c = 0; c < config->num_crtc; c++) 2446 { 2447 xf86OutputPtr output = NULL; 2448 int o; 2449 RRTransformPtr transform; 2450 2451 crtc = config->crtc[c]; 2452 2453 /* Skip disabled CRTCs */ 2454 if (!crtc->enabled) 2455 continue; 2456 2457 if (config->output[config->compat_output]->crtc == crtc) 2458 output = config->output[config->compat_output]; 2459 else 2460 { 2461 for (o = 0; o < config->num_output; o++) 2462 if (config->output[o]->crtc == crtc) 2463 { 2464 output = config->output[o]; 2465 break; 2466 } 2467 } 2468 /* paranoia */ 2469 if (!output) 2470 continue; 2471 2472 /* Mark that we'll need to re-set the mode for sure */ 2473 memset(&crtc->mode, 0, sizeof(crtc->mode)); 2474 if (!crtc->desiredMode.CrtcHDisplay) 2475 { 2476 DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); 2477 2478 if (!mode) 2479 return FALSE; 2480 crtc->desiredMode = *mode; 2481 crtc->desiredRotation = RR_Rotate_0; 2482 crtc->desiredTransformPresent = FALSE; 2483 crtc->desiredX = 0; 2484 crtc->desiredY = 0; 2485 } 2486 2487 if (crtc->desiredTransformPresent) 2488 transform = &crtc->desiredTransform; 2489 else 2490 transform = NULL; 2491 if (!xf86CrtcSetModeTransform (crtc, &crtc->desiredMode, crtc->desiredRotation, 2492 transform, crtc->desiredX, crtc->desiredY)) 2493 return FALSE; 2494 } 2495 2496 xf86DisableUnusedFunctions(scrn); 2497 return TRUE; 2498} 2499 2500/** 2501 * In the current world order, there are lists of modes per output, which may 2502 * or may not include the mode that was asked to be set by XFree86's mode 2503 * selection. Find the closest one, in the following preference order: 2504 * 2505 * - Equality 2506 * - Closer in size to the requested mode, but no larger 2507 * - Closer in refresh rate to the requested mode. 2508 */ 2509 2510_X_EXPORT DisplayModePtr 2511xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) 2512{ 2513 DisplayModePtr best = NULL, scan = NULL; 2514 2515 for (scan = output->probed_modes; scan != NULL; scan = scan->next) 2516 { 2517 /* If there's an exact match, we're done. */ 2518 if (xf86ModesEqual(scan, desired)) { 2519 best = desired; 2520 break; 2521 } 2522 2523 /* Reject if it's larger than the desired mode. */ 2524 if (scan->HDisplay > desired->HDisplay || 2525 scan->VDisplay > desired->VDisplay) 2526 { 2527 continue; 2528 } 2529 2530 /* 2531 * If we haven't picked a best mode yet, use the first 2532 * one in the size range 2533 */ 2534 if (best == NULL) 2535 { 2536 best = scan; 2537 continue; 2538 } 2539 2540 /* Find if it's closer to the right size than the current best 2541 * option. 2542 */ 2543 if ((scan->HDisplay > best->HDisplay && 2544 scan->VDisplay >= best->VDisplay) || 2545 (scan->HDisplay >= best->HDisplay && 2546 scan->VDisplay > best->VDisplay)) 2547 { 2548 best = scan; 2549 continue; 2550 } 2551 2552 /* Find if it's still closer to the right refresh than the current 2553 * best resolution. 2554 */ 2555 if (scan->HDisplay == best->HDisplay && 2556 scan->VDisplay == best->VDisplay && 2557 (fabs(scan->VRefresh - desired->VRefresh) < 2558 fabs(best->VRefresh - desired->VRefresh))) { 2559 best = scan; 2560 } 2561 } 2562 return best; 2563} 2564 2565/** 2566 * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, 2567 * take the specified mode and apply it to the crtc connected to the compat 2568 * output. Then, find similar modes for the other outputs, as with the 2569 * InitialConfiguration code above. The goal is to clone the desired 2570 * mode across all outputs that are currently active. 2571 */ 2572 2573_X_EXPORT Bool 2574xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) 2575{ 2576 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2577 Bool ok = TRUE; 2578 xf86OutputPtr compat_output = config->output[config->compat_output]; 2579 DisplayModePtr compat_mode; 2580 int c; 2581 2582 /* 2583 * Let the compat output drive the final mode selection 2584 */ 2585 compat_mode = xf86OutputFindClosestMode (compat_output, desired); 2586 if (compat_mode) 2587 desired = compat_mode; 2588 2589 for (c = 0; c < config->num_crtc; c++) 2590 { 2591 xf86CrtcPtr crtc = config->crtc[c]; 2592 DisplayModePtr crtc_mode = NULL; 2593 int o; 2594 2595 if (!crtc->enabled) 2596 continue; 2597 2598 for (o = 0; o < config->num_output; o++) 2599 { 2600 xf86OutputPtr output = config->output[o]; 2601 DisplayModePtr output_mode; 2602 2603 /* skip outputs not on this crtc */ 2604 if (output->crtc != crtc) 2605 continue; 2606 2607 if (crtc_mode) 2608 { 2609 output_mode = xf86OutputFindClosestMode (output, crtc_mode); 2610 if (output_mode != crtc_mode) 2611 output->crtc = NULL; 2612 } 2613 else 2614 crtc_mode = xf86OutputFindClosestMode (output, desired); 2615 } 2616 if (!crtc_mode) 2617 { 2618 crtc->enabled = FALSE; 2619 continue; 2620 } 2621 if (!xf86CrtcSetModeTransform (crtc, crtc_mode, rotation, NULL, 0, 0)) 2622 ok = FALSE; 2623 else 2624 { 2625 crtc->desiredMode = *crtc_mode; 2626 crtc->desiredRotation = rotation; 2627 crtc->desiredTransformPresent = FALSE; 2628 crtc->desiredX = 0; 2629 crtc->desiredY = 0; 2630 } 2631 } 2632 xf86DisableUnusedFunctions(pScrn); 2633#ifdef RANDR_12_INTERFACE 2634 xf86RandR12TellChanged (pScrn->pScreen); 2635#endif 2636 return ok; 2637} 2638 2639 2640/** 2641 * Set the DPMS power mode of all outputs and CRTCs. 2642 * 2643 * If the new mode is off, it will turn off outputs and then CRTCs. 2644 * Otherwise, it will affect CRTCs before outputs. 2645 */ 2646_X_EXPORT void 2647xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) 2648{ 2649 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2650 int i; 2651 2652 if (!scrn->vtSema) 2653 return; 2654 2655 if (mode == DPMSModeOff) { 2656 for (i = 0; i < config->num_output; i++) { 2657 xf86OutputPtr output = config->output[i]; 2658 if (output->crtc != NULL) 2659 (*output->funcs->dpms) (output, mode); 2660 } 2661 } 2662 2663 for (i = 0; i < config->num_crtc; i++) { 2664 xf86CrtcPtr crtc = config->crtc[i]; 2665 if (crtc->enabled) 2666 (*crtc->funcs->dpms) (crtc, mode); 2667 } 2668 2669 if (mode != DPMSModeOff) { 2670 for (i = 0; i < config->num_output; i++) { 2671 xf86OutputPtr output = config->output[i]; 2672 if (output->crtc != NULL) 2673 (*output->funcs->dpms) (output, mode); 2674 } 2675 } 2676} 2677 2678/** 2679 * Implement the screensaver by just calling down into the driver DPMS hooks. 2680 * 2681 * Even for monitors with no DPMS support, by the definition of our DPMS hooks, 2682 * the outputs will still get disabled (blanked). 2683 */ 2684_X_EXPORT Bool 2685xf86SaveScreen(ScreenPtr pScreen, int mode) 2686{ 2687 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 2688 2689 if (xf86IsUnblank(mode)) 2690 xf86DPMSSet(pScrn, DPMSModeOn, 0); 2691 else 2692 xf86DPMSSet(pScrn, DPMSModeOff, 0); 2693 2694 return TRUE; 2695} 2696 2697/** 2698 * Disable all inactive crtcs and outputs 2699 */ 2700_X_EXPORT void 2701xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) 2702{ 2703 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2704 int o, c; 2705 2706 for (o = 0; o < xf86_config->num_output; o++) 2707 { 2708 xf86OutputPtr output = xf86_config->output[o]; 2709 if (!output->crtc) 2710 (*output->funcs->dpms)(output, DPMSModeOff); 2711 } 2712 2713 for (c = 0; c < xf86_config->num_crtc; c++) 2714 { 2715 xf86CrtcPtr crtc = xf86_config->crtc[c]; 2716 2717 if (!crtc->enabled) 2718 { 2719 crtc->funcs->dpms(crtc, DPMSModeOff); 2720 memset(&crtc->mode, 0, sizeof(crtc->mode)); 2721 xf86RotateDestroy(crtc); 2722 } 2723 } 2724 if (pScrn->pScreen) 2725 xf86_crtc_notify(pScrn->pScreen); 2726} 2727 2728#ifdef RANDR_12_INTERFACE 2729 2730#define EDID_ATOM_NAME "EDID_DATA" 2731 2732/** 2733 * Set the RandR EDID property 2734 */ 2735static void 2736xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) 2737{ 2738 Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); 2739 2740 /* This may get called before the RandR resources have been created */ 2741 if (output->randr_output == NULL) 2742 return; 2743 2744 if (data_len != 0) { 2745 RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, 2746 PropModeReplace, data_len, data, FALSE, TRUE); 2747 } else { 2748 RRDeleteOutputProperty(output->randr_output, edid_atom); 2749 } 2750} 2751 2752#endif 2753 2754/** 2755 * Set the EDID information for the specified output 2756 */ 2757_X_EXPORT void 2758xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) 2759{ 2760 ScrnInfoPtr scrn = output->scrn; 2761 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2762 int i; 2763#ifdef RANDR_12_INTERFACE 2764 int size; 2765#endif 2766 2767 if (output->MonInfo != NULL) 2768 xfree(output->MonInfo); 2769 2770 output->MonInfo = edid_mon; 2771 2772 if (config->debug_modes) { 2773 xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", 2774 output->name); 2775 xf86PrintEDID(edid_mon); 2776 } 2777 2778 /* Set the DDC properties for the 'compat' output */ 2779 if (output == config->output[config->compat_output]) 2780 xf86SetDDCproperties(scrn, edid_mon); 2781 2782#ifdef RANDR_12_INTERFACE 2783 /* Set the RandR output properties */ 2784 size = 0; 2785 if (edid_mon) 2786 { 2787 if (edid_mon->ver.version == 1) { 2788 size = 128; 2789 if (edid_mon->flags & EDID_COMPLETE_RAWDATA) 2790 size += edid_mon->no_sections * 128; 2791 } else if (edid_mon->ver.version == 2) 2792 size = 256; 2793 } 2794 xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); 2795#endif 2796 2797 if (edid_mon) 2798 { 2799 /* Pull out a phyiscal size from a detailed timing if available. */ 2800 for (i = 0; i < 4; i++) { 2801 if (edid_mon->det_mon[i].type == DT && 2802 edid_mon->det_mon[i].section.d_timings.h_size != 0 && 2803 edid_mon->det_mon[i].section.d_timings.v_size != 0) 2804 { 2805 output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size; 2806 output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size; 2807 break; 2808 } 2809 } 2810 2811 /* if no mm size is available from a detailed timing, check the max size field */ 2812 if ((!output->mm_width || !output->mm_height) && 2813 (edid_mon->features.hsize && edid_mon->features.vsize)) 2814 { 2815 output->mm_width = edid_mon->features.hsize * 10; 2816 output->mm_height = edid_mon->features.vsize * 10; 2817 } 2818 } 2819} 2820 2821/** 2822 * Return the list of modes supported by the EDID information 2823 * stored in 'output' 2824 */ 2825_X_EXPORT DisplayModePtr 2826xf86OutputGetEDIDModes (xf86OutputPtr output) 2827{ 2828 ScrnInfoPtr scrn = output->scrn; 2829 xf86MonPtr edid_mon = output->MonInfo; 2830 2831 if (!edid_mon) 2832 return NULL; 2833 return xf86DDCGetModes(scrn->scrnIndex, edid_mon); 2834} 2835 2836/* maybe we should care about DDC1? meh. */ 2837_X_EXPORT xf86MonPtr 2838xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) 2839{ 2840 ScrnInfoPtr scrn = output->scrn; 2841 xf86MonPtr mon; 2842 2843 mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE); 2844 if (mon) 2845 xf86DDCApplyQuirks(scrn->scrnIndex, mon); 2846 2847 return mon; 2848} 2849 2850static char *_xf86ConnectorNames[] = { 2851 "None", "VGA", "DVI-I", "DVI-D", 2852 "DVI-A", "Composite", "S-Video", 2853 "Component", "LFP", "Proprietary", 2854 "HDMI", "DisplayPort", 2855 }; 2856_X_EXPORT char * 2857xf86ConnectorGetName(xf86ConnectorType connector) 2858{ 2859 return _xf86ConnectorNames[connector]; 2860} 2861 2862static void 2863x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 2864{ 2865 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 2866 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 2867 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 2868 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 2869 2870 if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) 2871 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 2872} 2873 2874static void 2875x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 2876{ 2877 if (crtc->enabled) { 2878 crtc_box->x1 = crtc->x; 2879 crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 2880 crtc_box->y1 = crtc->y; 2881 crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 2882 } else 2883 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 2884} 2885 2886static int 2887xf86_crtc_box_area(BoxPtr box) 2888{ 2889 return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); 2890} 2891 2892/* 2893 * Return the crtc covering 'box'. If two crtcs cover a portion of 2894 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 2895 * with greater coverage 2896 */ 2897 2898static xf86CrtcPtr 2899xf86_covering_crtc(ScrnInfoPtr pScrn, 2900 BoxPtr box, 2901 xf86CrtcPtr desired, 2902 BoxPtr crtc_box_ret) 2903{ 2904 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2905 xf86CrtcPtr crtc, best_crtc; 2906 int coverage, best_coverage; 2907 int c; 2908 BoxRec crtc_box, cover_box; 2909 2910 best_crtc = NULL; 2911 best_coverage = 0; 2912 crtc_box_ret->x1 = 0; 2913 crtc_box_ret->x2 = 0; 2914 crtc_box_ret->y1 = 0; 2915 crtc_box_ret->y2 = 0; 2916 for (c = 0; c < xf86_config->num_crtc; c++) { 2917 crtc = xf86_config->crtc[c]; 2918 x86_crtc_box(crtc, &crtc_box); 2919 x86_crtc_box_intersect(&cover_box, &crtc_box, box); 2920 coverage = xf86_crtc_box_area(&cover_box); 2921 if (coverage && crtc == desired) { 2922 *crtc_box_ret = crtc_box; 2923 return crtc; 2924 } else if (coverage > best_coverage) { 2925 *crtc_box_ret = crtc_box; 2926 best_crtc = crtc; 2927 best_coverage = coverage; 2928 } 2929 } 2930 return best_crtc; 2931} 2932 2933/* 2934 * For overlay video, compute the relevant CRTC and 2935 * clip video to that. 2936 * 2937 * returning FALSE means there was a memory failure of some kind, 2938 * not that the video shouldn't be displayed 2939 */ 2940 2941_X_EXPORT Bool 2942xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, 2943 xf86CrtcPtr *crtc_ret, 2944 xf86CrtcPtr desired_crtc, 2945 BoxPtr dst, 2946 INT32 *xa, 2947 INT32 *xb, 2948 INT32 *ya, 2949 INT32 *yb, 2950 RegionPtr reg, 2951 INT32 width, 2952 INT32 height) 2953{ 2954 Bool ret; 2955 RegionRec crtc_region_local; 2956 RegionPtr crtc_region = reg; 2957 2958 if (crtc_ret) { 2959 BoxRec crtc_box; 2960 xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, 2961 desired_crtc, 2962 &crtc_box); 2963 2964 if (crtc) { 2965 REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1); 2966 crtc_region = &crtc_region_local; 2967 REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg); 2968 } 2969 *crtc_ret = crtc; 2970 } 2971 2972 ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, 2973 crtc_region, width, height); 2974 2975 if (crtc_region != reg) 2976 REGION_UNINIT (pScreen, &crtc_region_local); 2977 2978 return ret; 2979} 2980 2981xf86_crtc_notify_proc_ptr 2982xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new) 2983{ 2984 if (xf86CrtcConfigPrivateIndex != -1) 2985 { 2986 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 2987 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2988 xf86_crtc_notify_proc_ptr old; 2989 2990 old = config->xf86_crtc_notify; 2991 config->xf86_crtc_notify = new; 2992 return old; 2993 } 2994 return NULL; 2995} 2996 2997void 2998xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old) 2999{ 3000 if (xf86CrtcConfigPrivateIndex != -1) 3001 { 3002 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3003 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3004 3005 config->xf86_crtc_notify = old; 3006 } 3007} 3008 3009void 3010xf86_crtc_notify(ScreenPtr screen) 3011{ 3012 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 3013 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3014 3015 if (config->xf86_crtc_notify) 3016 config->xf86_crtc_notify(screen); 3017} 3018