xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xf86Crtc.c (108415B)


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