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
53int xf86CrtcConfigPrivateIndex = -1;
54
55void
56xf86CrtcConfigInit(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
70void
71xf86CrtcSetSizeRange(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 */
85xf86CrtcPtr
86xf86CrtcCreate(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
140void
141xf86CrtcDestroy(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
164Bool
165xf86CrtcInUse(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
181static Bool
182xf86CrtcIsLeased(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
194static Bool
195xf86OutputIsLeased(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
203void
204xf86CrtcSetScreenSubpixelOrder(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 */
266Bool
267xf86CrtcSetModeTransform(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 */
423Bool
424xf86CrtcSetMode(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 */
433void
434xf86CrtcSetOrigin(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
459extern XF86ConfigPtr xf86configptr;
460
461typedef 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
480static 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
500enum {
501    OPTION_MODEDEBUG,
502    OPTION_PREFER_CLONEMODE,
503    OPTION_NO_OUTPUT_INITIAL_SIZE,
504};
505
506static 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
513static void
514xf86OutputSetMonitor(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
555Bool
556xf86OutputForceEnabled(xf86OutputPtr output)
557{
558    Bool enable;
559
560    if (xf86GetOptValBool(output->options, OPTION_ENABLE, &enable) && enable)
561        return TRUE;
562    return FALSE;
563}
564
565static Bool
566xf86OutputEnabled(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
597static Bool
598xf86OutputIgnored(xf86OutputPtr output)
599{
600    return xf86ReturnOptValBool(output->options, OPTION_IGNORE, FALSE);
601}
602
603static const char *direction[4] = {
604    "normal",
605    "left",
606    "inverted",
607    "right"
608};
609
610static Rotation
611xf86OutputInitialRotation(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
629xf86OutputPtr
630xf86OutputCreate(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
696Bool
697xf86OutputRename(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
713void
714xf86OutputUseScreenMonitor(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
722void
723xf86OutputDestroy(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 */
748static Bool
749xf86CrtcCreateScreenResources(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 */
768static Bool
769xf86CrtcCloseScreen(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
811int
812#else
813Bool
814#endif
815xf86CrtcScreenInit(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
862static DisplayModePtr
863xf86DefaultMode(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
901static DisplayModePtr
902xf86ClosestMode(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
941static DisplayModePtr
942xf86OutputHasPreferredMode(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
957static DisplayModePtr
958xf86OutputHasUserPreferredMode(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
969static int
970xf86PickCrtcs(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
1061static void
1062xf86DefaultScreenLimits(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 */
1128static Bool
1129xf86UserConfiguredOutputs(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
1169static Bool
1170xf86InitialOutputPositions(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
1357static void
1358xf86InitialPanning(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 */
1411static int
1412xf86ModeCompare(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 */
1429static DisplayModePtr
1430xf86SortModes(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
1462static const char *
1463preferredMode(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 */
1488static const char *
1489gettoken(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 */
1531static int
1532processZoomModes(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
1563static void
1564GuessRangeFromModes(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
1607enum det_monrec_source {
1608    sync_config, sync_edid, sync_default
1609};
1610
1611struct 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
1619static void
1620handle_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
1648void
1649xf86ProbeOutputModes(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
1902static DisplayModePtr
1903biggestMode(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
1921static xf86OutputPtr
1922SetCompatOutput(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
2005void
2006xf86SetScrnInfoModes(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
2058static Bool
2059xf86CollectEnabledOutputs(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
2088static Bool
2089nextEnabledOutput(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
2103static Bool
2104aspectMatch(float a, float b)
2105{
2106    return fabs(1 - (a / b)) < 0.05;
2107}
2108
2109static DisplayModePtr
2110nextAspectMode(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
2129static DisplayModePtr
2130bestModeForAspect(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
2163static int
2164numEnabledOutputs(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
2173static Bool
2174xf86TargetRightOf(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
2277static Bool
2278xf86TargetPreferred(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
2387static Bool
2388xf86TargetAspect(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
2442static Bool
2443xf86TargetFallback(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
2481static Bool
2482xf86TargetUserpref(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
2498void
2499xf86AssignNoOutputInitialSize(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
2538Bool
2539xf86InitialConfiguration(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 */
2729static void
2730xf86DisableCrtc(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 */
2744static void
2745xf86PrepareOutputs(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
2766static void
2767xf86PrepareCrtcs(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
2815Bool
2816xf86SetDesiredModes(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
2899DisplayModePtr
2900xf86OutputFindClosestMode(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
2958Bool
2959xf86SetSingleMode(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 */
3027void
3028xf86DPMSSet(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 */
3068Bool
3069xf86SaveScreen(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 */
3084void
3085xf86DisableUnusedFunctions(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 */
3126static void
3127xf86OutputSetEDIDProperty(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
3147static void
3148xf86OutputSetTileProperty(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. */
3168struct det_phySize_parameter {
3169    xf86OutputPtr output;
3170    ddc_quirk_t quirks;
3171    Bool ret;
3172};
3173
3174static void
3175handle_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
3210Bool
3211xf86OutputParseKMSTile(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
3230void
3231xf86OutputSetTile(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 */
3245void
3246xf86OutputSetEDID(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 */
3311DisplayModePtr
3312xf86OutputGetEDIDModes(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. */
3323xf86MonPtr
3324xf86OutputGetEDID(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
3336static 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
3343const char *
3344xf86ConnectorGetName(xf86ConnectorType connector)
3345{
3346    return _xf86ConnectorNames[connector];
3347}
3348
3349#ifdef XV
3350static void
3351x86_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
3362static void
3363x86_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
3375static int
3376xf86_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
3387static xf86CrtcPtr
3388xf86_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
3429Bool
3430xf86_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
3467xf86_crtc_notify_proc_ptr
3468xf86_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
3482void
3483xf86_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
3493void
3494xf86_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
3503Bool
3504xf86_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
3523void
3524xf86ProviderSetup(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
3539void
3540xf86DetachAllCrtc(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}
3559