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