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