xf86Crtc.c revision 1b5d61b8
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 disp_features *features = &edid_monitor->features;
1723            struct cea_data_block *hdmi_db;
1724
1725            /* if display is not continuous-frequency, don't add default modes */
1726            if (!GTF_SUPPORTED(features->msc))
1727                add_default_modes = FALSE;
1728
1729            p.mon_rec = &mon_rec;
1730            p.max_clock = &max_clock;
1731            p.set_hsync = mon_rec.nHsync == 0;
1732            p.set_vrefresh = mon_rec.nVrefresh == 0;
1733            p.sync_source = &sync_source;
1734
1735            xf86ForEachDetailedBlock(edid_monitor, handle_detailed_monrec, &p);
1736
1737            /* Look at the CEA HDMI vendor block for the max TMDS freq */
1738            hdmi_db = xf86MonitorFindHDMIBlock(edid_monitor);
1739            if (hdmi_db && hdmi_db->len >= 7) {
1740                int tmds_freq = hdmi_db->u.vendor.hdmi.max_tmds_clock * 5000;
1741                xf86DrvMsg(scrn->scrnIndex, X_PROBED,
1742                           "HDMI max TMDS frequency %dKHz\n", tmds_freq);
1743                if (tmds_freq > max_clock)
1744                    max_clock = tmds_freq;
1745            }
1746        }
1747
1748        if (xf86GetOptValFreq(output->options, OPTION_MIN_CLOCK,
1749                              OPTUNITS_KHZ, &clock))
1750            min_clock = (int) clock;
1751        if (xf86GetOptValFreq(output->options, OPTION_MAX_CLOCK,
1752                              OPTUNITS_KHZ, &clock))
1753            max_clock = (int) clock;
1754
1755        /* If we still don't have a sync range, guess wildly */
1756        if (!mon_rec.nHsync || !mon_rec.nVrefresh)
1757            GuessRangeFromModes(&mon_rec, output_modes);
1758
1759        /*
1760         * These limits will end up setting a 1024x768@60Hz mode by default,
1761         * which seems like a fairly good mode to use when nothing else is
1762         * specified
1763         */
1764        if (mon_rec.nHsync == 0) {
1765            mon_rec.hsync[0].lo = 31.0;
1766            mon_rec.hsync[0].hi = 55.0;
1767            mon_rec.nHsync = 1;
1768        }
1769        if (mon_rec.nVrefresh == 0) {
1770            mon_rec.vrefresh[0].lo = 58.0;
1771            mon_rec.vrefresh[0].hi = 62.0;
1772            mon_rec.nVrefresh = 1;
1773        }
1774
1775        if (add_default_modes)
1776            default_modes = xf86GetDefaultModes();
1777
1778        /*
1779         * If this is not an RB monitor, remove RB modes from the default
1780         * pool.  RB modes from the config or the monitor itself are fine.
1781         */
1782        if (!mon_rec.reducedblanking)
1783            xf86ValidateModesReducedBlanking(scrn, default_modes);
1784
1785        if (sync_source == sync_config) {
1786            /*
1787             * Check output and config modes against sync range from config file
1788             */
1789            xf86ValidateModesSync(scrn, output_modes, &mon_rec);
1790            xf86ValidateModesSync(scrn, config_modes, &mon_rec);
1791        }
1792        /*
1793         * Check default modes against sync range
1794         */
1795        xf86ValidateModesSync(scrn, default_modes, &mon_rec);
1796        /*
1797         * Check default modes against monitor max clock
1798         */
1799        if (max_clock) {
1800            xf86ValidateModesClocks(scrn, default_modes,
1801                                    &min_clock, &max_clock, 1);
1802            xf86ValidateModesClocks(scrn, output_modes,
1803                                    &min_clock, &max_clock, 1);
1804        }
1805
1806        output->probed_modes = NULL;
1807        output->probed_modes = xf86ModesAdd(output->probed_modes, config_modes);
1808        output->probed_modes = xf86ModesAdd(output->probed_modes, output_modes);
1809        output->probed_modes =
1810            xf86ModesAdd(output->probed_modes, default_modes);
1811
1812        /*
1813         * Check all modes against max size, interlace, and doublescan
1814         */
1815        if (maxX && maxY)
1816            xf86ValidateModesSize(scrn, output->probed_modes, maxX, maxY, 0);
1817
1818        {
1819            int flags = (output->interlaceAllowed ? V_INTERLACE : 0) |
1820                (output->doubleScanAllowed ? V_DBLSCAN : 0);
1821            xf86ValidateModesFlags(scrn, output->probed_modes, flags);
1822        }
1823
1824        /*
1825         * Check all modes against output
1826         */
1827        for (mode = output->probed_modes; mode != NULL; mode = mode->next)
1828            if (mode->status == MODE_OK)
1829                mode->status = (*output->funcs->mode_valid) (output, mode);
1830
1831        xf86PruneInvalidModes(scrn, &output->probed_modes, debug_modes);
1832
1833        output->probed_modes = xf86SortModes(output->probed_modes);
1834
1835        /* Check for a configured preference for a particular mode */
1836        preferred_mode = preferredMode(scrn, output);
1837
1838        if (preferred_mode) {
1839            for (mode = output->probed_modes; mode; mode = mode->next) {
1840                if (!strcmp(preferred_mode, mode->name)) {
1841                    if (mode != output->probed_modes) {
1842                        if (mode->prev)
1843                            mode->prev->next = mode->next;
1844                        if (mode->next)
1845                            mode->next->prev = mode->prev;
1846                        mode->next = output->probed_modes;
1847                        output->probed_modes->prev = mode;
1848                        mode->prev = NULL;
1849                        output->probed_modes = mode;
1850                    }
1851                    mode->type |= (M_T_PREFERRED | M_T_USERPREF);
1852                    break;
1853                }
1854            }
1855        }
1856
1857        /* Ctrl+Alt+Keypad-{Plus,Minus} zoom mode: M_T_USERDEF mode type */
1858        processZoomModes(output);
1859
1860        output->initial_rotation = xf86OutputInitialRotation(output);
1861
1862        if (debug_modes) {
1863            if (output->probed_modes != NULL) {
1864                xf86DrvMsg(scrn->scrnIndex, X_INFO,
1865                           "Printing probed modes for output %s\n",
1866                           output->name);
1867            }
1868            else {
1869                xf86DrvMsg(scrn->scrnIndex, X_INFO,
1870                           "No remaining probed modes for output %s\n",
1871                           output->name);
1872            }
1873        }
1874        for (mode = output->probed_modes; mode != NULL; mode = mode->next) {
1875            /* The code to choose the best mode per pipe later on will require
1876             * VRefresh to be set.
1877             */
1878            mode->VRefresh = xf86ModeVRefresh(mode);
1879            xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
1880
1881            if (debug_modes)
1882                xf86PrintModeline(scrn->scrnIndex, mode);
1883        }
1884    }
1885}
1886
1887/**
1888 * Copy one of the output mode lists to the ScrnInfo record
1889 */
1890
1891static DisplayModePtr
1892biggestMode(DisplayModePtr a, DisplayModePtr b)
1893{
1894    int A, B;
1895
1896    if (!a)
1897        return b;
1898    if (!b)
1899        return a;
1900
1901    A = a->HDisplay * a->VDisplay;
1902    B = b->HDisplay * b->VDisplay;
1903
1904    if (A > B)
1905        return a;
1906
1907    return b;
1908}
1909
1910static xf86OutputPtr
1911SetCompatOutput(xf86CrtcConfigPtr config)
1912{
1913    xf86OutputPtr output = NULL, test = NULL;
1914    DisplayModePtr maxmode = NULL, testmode, mode;
1915    int o, compat = -1, count, mincount = 0;
1916
1917    if (config->num_output == 0)
1918        return NULL;
1919
1920    /* Look for one that's definitely connected */
1921    for (o = 0; o < config->num_output; o++) {
1922        test = config->output[o];
1923        if (!test->crtc)
1924            continue;
1925        if (test->status != XF86OutputStatusConnected)
1926            continue;
1927        if (!test->probed_modes)
1928            continue;
1929
1930        testmode = mode = test->probed_modes;
1931        for (count = 0; mode; mode = mode->next, count++)
1932            testmode = biggestMode(testmode, mode);
1933
1934        if (!output) {
1935            output = test;
1936            compat = o;
1937            maxmode = testmode;
1938            mincount = count;
1939        }
1940        else if (maxmode == biggestMode(maxmode, testmode)) {
1941            output = test;
1942            compat = o;
1943            maxmode = testmode;
1944            mincount = count;
1945        }
1946        else if ((maxmode->HDisplay == testmode->HDisplay) &&
1947                 (maxmode->VDisplay == testmode->VDisplay) &&
1948                 count <= mincount) {
1949            output = test;
1950            compat = o;
1951            maxmode = testmode;
1952            mincount = count;
1953        }
1954    }
1955
1956    /* If we didn't find one, take anything we can get */
1957    if (!output) {
1958        for (o = 0; o < config->num_output; o++) {
1959            test = config->output[o];
1960            if (!test->crtc)
1961                continue;
1962            if (!test->probed_modes)
1963                continue;
1964
1965            if (!output) {
1966                output = test;
1967                compat = o;
1968            }
1969            else if (test->probed_modes->HDisplay <
1970                     output->probed_modes->HDisplay) {
1971                output = test;
1972                compat = o;
1973            }
1974        }
1975    }
1976
1977    if (compat >= 0) {
1978        config->compat_output = compat;
1979    }
1980    else if (config->compat_output >= 0 && config->compat_output < config->num_output) {
1981        /* Don't change the compat output when no valid outputs found */
1982        output = config->output[config->compat_output];
1983    }
1984
1985    /* All outputs are disconnected, select one to fake */
1986    if (!output && config->num_output) {
1987        config->compat_output = 0;
1988        output = config->output[config->compat_output];
1989    }
1990
1991    return output;
1992}
1993
1994void
1995xf86SetScrnInfoModes(ScrnInfoPtr scrn)
1996{
1997    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1998    xf86OutputPtr output;
1999    xf86CrtcPtr crtc;
2000    DisplayModePtr last, mode = NULL;
2001
2002    output = SetCompatOutput(config);
2003
2004    if (!output)
2005        return;                 /* punt */
2006
2007    crtc = output->crtc;
2008
2009    /* Clear any existing modes from scrn->modes */
2010    while (scrn->modes != NULL)
2011        xf86DeleteMode(&scrn->modes, scrn->modes);
2012
2013    /* Set scrn->modes to the mode list for the 'compat' output */
2014    scrn->modes = xf86DuplicateModes(scrn, output->probed_modes);
2015
2016    if (crtc) {
2017        for (mode = scrn->modes; mode; mode = mode->next)
2018            if (xf86ModesEqual(mode, &crtc->desiredMode))
2019                break;
2020    }
2021
2022    if (!scrn->modes) {
2023        scrn->modes = xf86ModesAdd(scrn->modes,
2024                                   xf86CVTMode(scrn->display->virtualX,
2025                                               scrn->display->virtualY,
2026                                               60, 0, 0));
2027    }
2028
2029    /* For some reason, scrn->modes is circular, unlike the other mode
2030     * lists.  How great is that?
2031     */
2032    for (last = scrn->modes; last && last->next; last = last->next);
2033    last->next = scrn->modes;
2034    scrn->modes->prev = last;
2035    if (mode) {
2036        while (scrn->modes != mode)
2037            scrn->modes = scrn->modes->next;
2038    }
2039
2040    scrn->currentMode = scrn->modes;
2041#ifdef XFreeXDGA
2042    if (scrn->pScreen)
2043        _xf86_di_dga_reinit_internal(scrn->pScreen);
2044#endif
2045}
2046
2047static Bool
2048xf86CollectEnabledOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2049                          Bool *enabled)
2050{
2051    Bool any_enabled = FALSE;
2052    int o;
2053
2054    /*
2055     * Don't bother enabling outputs on GPU screens: a client needs to attach
2056     * it to a source provider before setting a mode that scans out a shared
2057     * pixmap.
2058     */
2059    if (scrn->is_gpu)
2060        return FALSE;
2061
2062    for (o = 0; o < config->num_output; o++)
2063        any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE);
2064
2065    if (!any_enabled) {
2066        xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2067                   "No outputs definitely connected, trying again...\n");
2068
2069        for (o = 0; o < config->num_output; o++)
2070            any_enabled |= enabled[o] =
2071                xf86OutputEnabled(config->output[o], FALSE);
2072    }
2073
2074    return any_enabled;
2075}
2076
2077static Bool
2078nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index)
2079{
2080    int o = *index;
2081
2082    for (o++; o < config->num_output; o++) {
2083        if (enabled[o]) {
2084            *index = o;
2085            return TRUE;
2086        }
2087    }
2088
2089    return FALSE;
2090}
2091
2092static Bool
2093aspectMatch(float a, float b)
2094{
2095    return fabs(1 - (a / b)) < 0.05;
2096}
2097
2098static DisplayModePtr
2099nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect)
2100{
2101    DisplayModePtr m = NULL;
2102
2103    if (!o)
2104        return NULL;
2105
2106    if (!last)
2107        m = o->probed_modes;
2108    else
2109        m = last->next;
2110
2111    for (; m; m = m->next)
2112        if (aspectMatch(aspect, (float) m->HDisplay / (float) m->VDisplay))
2113            return m;
2114
2115    return NULL;
2116}
2117
2118static DisplayModePtr
2119bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect)
2120{
2121    int o = -1, p;
2122    DisplayModePtr mode = NULL, test = NULL, match = NULL;
2123
2124    if (!nextEnabledOutput(config, enabled, &o))
2125        return NULL;
2126    while ((mode = nextAspectMode(config->output[o], mode, aspect))) {
2127        test = mode;
2128        for (p = o; nextEnabledOutput(config, enabled, &p);) {
2129            test = xf86OutputFindClosestMode(config->output[p], mode);
2130            if (!test)
2131                break;
2132            if (test->HDisplay != mode->HDisplay ||
2133                test->VDisplay != mode->VDisplay) {
2134                test = NULL;
2135                break;
2136            }
2137        }
2138
2139        /* if we didn't match it on all outputs, try the next one */
2140        if (!test)
2141            continue;
2142
2143        /* if it's bigger than the last one, save it */
2144        if (!match || (test->HDisplay > match->HDisplay))
2145            match = test;
2146    }
2147
2148    /* return the biggest one found */
2149    return match;
2150}
2151
2152static int
2153numEnabledOutputs(xf86CrtcConfigPtr config, Bool *enabled)
2154{
2155    int i = 0, p;
2156
2157    for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ;
2158
2159    return i;
2160}
2161
2162static Bool
2163xf86TargetRightOf(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2164                  DisplayModePtr *modes, Bool *enabled,
2165                  int width, int height)
2166{
2167    int o;
2168    int w = 0;
2169    Bool has_tile = FALSE;
2170    uint32_t configured_outputs;
2171
2172    xf86GetOptValBool(config->options, OPTION_PREFER_CLONEMODE,
2173                      &scrn->preferClone);
2174    if (scrn->preferClone)
2175        return FALSE;
2176
2177    if (numEnabledOutputs(config, enabled) < 2)
2178        return FALSE;
2179
2180    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2181        DisplayModePtr mode =
2182            xf86OutputHasPreferredMode(config->output[o], width, height);
2183
2184        if (!mode)
2185            return FALSE;
2186
2187        w += mode->HDisplay;
2188    }
2189
2190    if (w > width)
2191        return FALSE;
2192
2193    w = 0;
2194    configured_outputs = 0;
2195
2196    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2197        DisplayModePtr mode =
2198            xf86OutputHasPreferredMode(config->output[o], width, height);
2199
2200        if (configured_outputs & (1 << o))
2201            continue;
2202
2203        if (config->output[o]->tile_info.group_id) {
2204            has_tile = TRUE;
2205            continue;
2206        }
2207
2208        config->output[o]->initial_x = w;
2209        w += mode->HDisplay;
2210
2211        configured_outputs |= (1 << o);
2212        modes[o] = mode;
2213    }
2214
2215    if (has_tile) {
2216        for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2217            int ht, vt, ot;
2218            int add_x, cur_x = w;
2219            struct xf86CrtcTileInfo *tile_info = &config->output[o]->tile_info, *this_tile;
2220            if (configured_outputs & (1 << o))
2221                continue;
2222            if (!tile_info->group_id)
2223                continue;
2224
2225            if (tile_info->tile_h_loc != 0 && tile_info->tile_v_loc != 0)
2226                continue;
2227
2228            for (ht = 0; ht < tile_info->num_h_tile; ht++) {
2229                int cur_y = 0;
2230                add_x = 0;
2231                for (vt = 0; vt < tile_info->num_v_tile; vt++) {
2232
2233                    for (ot = -1; nextEnabledOutput(config, enabled, &ot); ) {
2234
2235                        DisplayModePtr mode =
2236                            xf86OutputHasPreferredMode(config->output[ot], width, height);
2237                        if (!config->output[ot]->tile_info.group_id)
2238                            continue;
2239
2240                        this_tile = &config->output[ot]->tile_info;
2241                        if (this_tile->group_id != tile_info->group_id)
2242                            continue;
2243
2244                        if (this_tile->tile_h_loc != ht ||
2245                            this_tile->tile_v_loc != vt)
2246                            continue;
2247
2248                        config->output[ot]->initial_x = cur_x;
2249                        config->output[ot]->initial_y = cur_y;
2250
2251                        if (vt == 0)
2252                            add_x = this_tile->tile_h_size;
2253                        cur_y += this_tile->tile_v_size;
2254                        configured_outputs |= (1 << ot);
2255                        modes[ot] = mode;
2256                    }
2257                }
2258                cur_x += add_x;
2259            }
2260            w = cur_x;
2261        }
2262    }
2263    return TRUE;
2264}
2265
2266static Bool
2267xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2268                    DisplayModePtr * modes, Bool *enabled,
2269                    int width, int height)
2270{
2271    int o, p;
2272    int max_pref_width = 0, max_pref_height = 0;
2273    DisplayModePtr *preferred, *preferred_match;
2274    Bool ret = FALSE;
2275
2276    preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
2277    preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
2278
2279    /* Check if the preferred mode is available on all outputs */
2280    for (p = -1; nextEnabledOutput(config, enabled, &p);) {
2281        Rotation r = config->output[p]->initial_rotation;
2282        DisplayModePtr mode;
2283
2284        if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p],
2285                                                       width, height))) {
2286            int pref_width = xf86ModeWidth(preferred[p], r);
2287            int pref_height = xf86ModeHeight(preferred[p], r);
2288            Bool all_match = TRUE;
2289
2290            for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2291                Bool match = FALSE;
2292                xf86OutputPtr output = config->output[o];
2293
2294                if (o == p)
2295                    continue;
2296
2297                /*
2298                 * First see if the preferred mode matches on the next
2299                 * output as well.  This catches the common case of identical
2300                 * monitors and makes sure they all have the same timings
2301                 * and refresh.  If that fails, we fall back to trying to
2302                 * match just width & height.
2303                 */
2304                mode = xf86OutputHasPreferredMode(output, pref_width,
2305                                                  pref_height);
2306                if (mode && xf86ModesEqual(mode, preferred[p])) {
2307                    preferred[o] = mode;
2308                    match = TRUE;
2309                }
2310                else {
2311                    for (mode = output->probed_modes; mode; mode = mode->next) {
2312                        Rotation ir = output->initial_rotation;
2313
2314                        if (xf86ModeWidth(mode, ir) == pref_width &&
2315                            xf86ModeHeight(mode, ir) == pref_height) {
2316                            preferred[o] = mode;
2317                            match = TRUE;
2318                        }
2319                    }
2320                }
2321
2322                all_match &= match;
2323            }
2324
2325            if (all_match &&
2326                (pref_width * pref_height > max_pref_width * max_pref_height)) {
2327                for (o = -1; nextEnabledOutput(config, enabled, &o);)
2328                    preferred_match[o] = preferred[o];
2329                max_pref_width = pref_width;
2330                max_pref_height = pref_height;
2331                ret = TRUE;
2332            }
2333        }
2334    }
2335
2336    /*
2337     * If there's no preferred mode, but only one monitor, pick the
2338     * biggest mode for its aspect ratio or 4:3, assuming one exists.
2339     */
2340    if (!ret)
2341        do {
2342            float aspect = 0.0;
2343            DisplayModePtr a = NULL, b = NULL;
2344
2345            if (numEnabledOutputs(config, enabled) != 1)
2346                break;
2347
2348            p = -1;
2349            nextEnabledOutput(config, enabled, &p);
2350            if (config->output[p]->mm_height)
2351                aspect = (float) config->output[p]->mm_width /
2352                    (float) config->output[p]->mm_height;
2353
2354            a = bestModeForAspect(config, enabled, 4.0/3.0);
2355            if (aspect)
2356                b = bestModeForAspect(config, enabled, aspect);
2357
2358            preferred_match[p] = biggestMode(a, b);
2359
2360            if (preferred_match[p])
2361                ret = TRUE;
2362
2363        } while (0);
2364
2365    if (ret) {
2366        /* oh good, there is a match.  stash the selected modes and return. */
2367        memcpy(modes, preferred_match,
2368               config->num_output * sizeof(DisplayModePtr));
2369    }
2370
2371    free(preferred);
2372    free(preferred_match);
2373    return ret;
2374}
2375
2376static Bool
2377xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2378                 DisplayModePtr * modes, Bool *enabled, int width, int height)
2379{
2380    int o;
2381    float aspect = 0.0, *aspects;
2382    xf86OutputPtr output;
2383    Bool ret = FALSE;
2384    DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL;
2385
2386    aspects = xnfcalloc(config->num_output, sizeof(float));
2387
2388    /* collect the aspect ratios */
2389    for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2390        output = config->output[o];
2391        if (output->mm_height)
2392            aspects[o] = (float) output->mm_width / (float) output->mm_height;
2393        else
2394            aspects[o] = 4.0 / 3.0;
2395    }
2396
2397    /* check that they're all the same */
2398    for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2399        output = config->output[o];
2400        if (!aspect) {
2401            aspect = aspects[o];
2402        }
2403        else if (!aspectMatch(aspect, aspects[o])) {
2404            goto no_aspect_match;
2405        }
2406    }
2407
2408    /* if they're all 4:3, just skip ahead and save effort */
2409    if (!aspectMatch(aspect, 4.0 / 3.0))
2410        aspect_guess = bestModeForAspect(config, enabled, aspect);
2411
2412 no_aspect_match:
2413    base_guess = bestModeForAspect(config, enabled, 4.0 / 3.0);
2414
2415    guess = biggestMode(base_guess, aspect_guess);
2416
2417    if (!guess)
2418        goto out;
2419
2420    /* found a mode that works everywhere, now apply it */
2421    for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2422        modes[o] = xf86OutputFindClosestMode(config->output[o], guess);
2423    }
2424    ret = TRUE;
2425
2426 out:
2427    free(aspects);
2428    return ret;
2429}
2430
2431static Bool
2432xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2433                   DisplayModePtr * modes, Bool *enabled, int width, int height)
2434{
2435    DisplayModePtr target_mode = NULL;
2436    Rotation target_rotation = RR_Rotate_0;
2437    DisplayModePtr default_mode;
2438    int default_preferred, target_preferred = 0, o;
2439
2440    /* User preferred > preferred > other modes */
2441    for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2442        default_mode = xf86DefaultMode(config->output[o], width, height);
2443        if (!default_mode)
2444            continue;
2445
2446        default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) +
2447                             ((default_mode->type & M_T_USERPREF) != 0));
2448
2449        if (default_preferred > target_preferred || !target_mode) {
2450            target_mode = default_mode;
2451            target_preferred = default_preferred;
2452            target_rotation = config->output[o]->initial_rotation;
2453            config->compat_output = o;
2454        }
2455    }
2456
2457    if (target_mode)
2458        modes[config->compat_output] = target_mode;
2459
2460    /* Fill in other output modes */
2461    for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2462        if (!modes[o])
2463            modes[o] = xf86ClosestMode(config->output[o], target_mode,
2464                                       target_rotation, width, height);
2465    }
2466
2467    return target_mode != NULL;
2468}
2469
2470static Bool
2471xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2472                   DisplayModePtr * modes, Bool *enabled, int width, int height)
2473{
2474    int o;
2475
2476    if (xf86UserConfiguredOutputs(scrn, modes))
2477        return xf86TargetFallback(scrn, config, modes, enabled, width, height);
2478
2479    for (o = -1; nextEnabledOutput(config, enabled, &o);)
2480        if (xf86OutputHasUserPreferredMode(config->output[o]))
2481            return
2482                xf86TargetFallback(scrn, config, modes, enabled, width, height);
2483
2484    return FALSE;
2485}
2486
2487/**
2488 * Construct default screen configuration
2489 *
2490 * Given auto-detected (and, eventually, configured) values,
2491 * construct a usable configuration for the system
2492 *
2493 * canGrow indicates that the driver can resize the screen to larger than its
2494 * initially configured size via the config->funcs->resize hook.  If TRUE, this
2495 * function will set virtualX and virtualY to match the initial configuration
2496 * and leave config->max{Width,Height} alone.  If FALSE, it will bloat
2497 * virtual[XY] to include the largest modes and set config->max{Width,Height}
2498 * accordingly.
2499 */
2500
2501Bool
2502xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow)
2503{
2504    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2505    int o, c;
2506    xf86CrtcPtr *crtcs;
2507    DisplayModePtr *modes;
2508    Bool *enabled;
2509    int width, height;
2510    int i = scrn->scrnIndex;
2511    Bool have_outputs = TRUE;
2512    Bool ret;
2513    Bool success = FALSE;
2514
2515    /* Set up the device options */
2516    config->options = xnfalloc(sizeof(xf86DeviceOptions));
2517    memcpy(config->options, xf86DeviceOptions, sizeof(xf86DeviceOptions));
2518    xf86ProcessOptions(scrn->scrnIndex, scrn->options, config->options);
2519    config->debug_modes = xf86ReturnOptValBool(config->options,
2520                                               OPTION_MODEDEBUG, FALSE);
2521
2522    if (scrn->display->virtualX && !scrn->is_gpu)
2523        width = scrn->display->virtualX;
2524    else
2525        width = config->maxWidth;
2526    if (scrn->display->virtualY && !scrn->is_gpu)
2527        height = scrn->display->virtualY;
2528    else
2529        height = config->maxHeight;
2530
2531    xf86ProbeOutputModes(scrn, width, height);
2532
2533    crtcs = xnfcalloc(config->num_output, sizeof(xf86CrtcPtr));
2534    modes = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
2535    enabled = xnfcalloc(config->num_output, sizeof(Bool));
2536
2537    ret = xf86CollectEnabledOutputs(scrn, config, enabled);
2538    if (ret == FALSE && canGrow) {
2539        if (!scrn->is_gpu)
2540            xf86DrvMsg(i, X_WARNING,
2541		       "Unable to find connected outputs - setting %dx%d "
2542                       "initial framebuffer\n",
2543                       NO_OUTPUT_DEFAULT_WIDTH, NO_OUTPUT_DEFAULT_HEIGHT);
2544        have_outputs = FALSE;
2545    }
2546    else {
2547        if (xf86TargetUserpref(scrn, config, modes, enabled, width, height))
2548            xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n");
2549        else if (xf86TargetRightOf(scrn, config, modes, enabled, width, height))
2550            xf86DrvMsg(i, X_INFO, "Using spanning desktop for initial modes\n");
2551        else if (xf86TargetPreferred
2552                 (scrn, config, modes, enabled, width, height))
2553            xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n");
2554        else if (xf86TargetAspect(scrn, config, modes, enabled, width, height))
2555            xf86DrvMsg(i, X_INFO,
2556                       "Using fuzzy aspect match for initial modes\n");
2557        else if (xf86TargetFallback
2558                 (scrn, config, modes, enabled, width, height))
2559            xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n");
2560        else
2561            xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n");
2562    }
2563
2564    for (o = -1; nextEnabledOutput(config, enabled, &o);) {
2565        if (!modes[o])
2566            xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2567                       "Output %s enabled but has no modes\n",
2568                       config->output[o]->name);
2569        else
2570            xf86DrvMsg (scrn->scrnIndex, X_INFO,
2571                        "Output %s using initial mode %s +%d+%d\n",
2572                        config->output[o]->name, modes[o]->name,
2573                        config->output[o]->initial_x,
2574                        config->output[o]->initial_y);
2575    }
2576
2577    /*
2578     * Set the position of each output
2579     */
2580    if (!xf86InitialOutputPositions(scrn, modes))
2581        goto bailout;
2582
2583    /*
2584     * Set initial panning of each output
2585     */
2586    xf86InitialPanning(scrn);
2587
2588    /*
2589     * Assign CRTCs to fit output configuration
2590     */
2591    if (have_outputs && !xf86PickCrtcs(scrn, crtcs, modes, 0, width, height))
2592        goto bailout;
2593
2594    /* XXX override xf86 common frame computation code */
2595
2596    if (!scrn->is_gpu) {
2597        scrn->display->frameX0 = 0;
2598        scrn->display->frameY0 = 0;
2599    }
2600
2601    for (c = 0; c < config->num_crtc; c++) {
2602        xf86CrtcPtr crtc = config->crtc[c];
2603
2604        crtc->enabled = FALSE;
2605        memset(&crtc->desiredMode, '\0', sizeof(crtc->desiredMode));
2606    }
2607
2608    /*
2609     * Set initial configuration
2610     */
2611    for (o = 0; o < config->num_output; o++) {
2612        xf86OutputPtr output = config->output[o];
2613        DisplayModePtr mode = modes[o];
2614        xf86CrtcPtr crtc = crtcs[o];
2615
2616        if (mode && crtc) {
2617            xf86SaveModeContents(&crtc->desiredMode, mode);
2618            crtc->desiredRotation = output->initial_rotation;
2619            crtc->desiredX = output->initial_x;
2620            crtc->desiredY = output->initial_y;
2621            crtc->desiredTransformPresent = FALSE;
2622            crtc->enabled = TRUE;
2623            memcpy(&crtc->panningTotalArea, &output->initialTotalArea,
2624                   sizeof(BoxRec));
2625            memcpy(&crtc->panningTrackingArea, &output->initialTrackingArea,
2626                   sizeof(BoxRec));
2627            memcpy(crtc->panningBorder, output->initialBorder,
2628                   4 * sizeof(INT16));
2629            output->crtc = crtc;
2630        }
2631        else {
2632            output->crtc = NULL;
2633        }
2634    }
2635
2636    if (scrn->display->virtualX == 0 || scrn->is_gpu) {
2637        /*
2638         * Expand virtual size to cover the current config and potential mode
2639         * switches, if the driver can't enlarge the screen later.
2640         */
2641        xf86DefaultScreenLimits(scrn, &width, &height, canGrow);
2642
2643        if (have_outputs == FALSE) {
2644            if (width < NO_OUTPUT_DEFAULT_WIDTH &&
2645                height < NO_OUTPUT_DEFAULT_HEIGHT) {
2646                width = NO_OUTPUT_DEFAULT_WIDTH;
2647                height = NO_OUTPUT_DEFAULT_HEIGHT;
2648            }
2649        }
2650
2651	if (!scrn->is_gpu) {
2652            scrn->display->virtualX = width;
2653            scrn->display->virtualY = height;
2654	}
2655    }
2656
2657    if (width > scrn->virtualX)
2658        scrn->virtualX = width;
2659    if (height > scrn->virtualY)
2660        scrn->virtualY = height;
2661
2662    /*
2663     * Make sure the configuration isn't too small.
2664     */
2665    if (width < config->minWidth || height < config->minHeight)
2666        goto bailout;
2667
2668    /*
2669     * Limit the crtc config to virtual[XY] if the driver can't grow the
2670     * desktop.
2671     */
2672    if (!canGrow) {
2673        xf86CrtcSetSizeRange(scrn, config->minWidth, config->minHeight,
2674                             width, height);
2675    }
2676
2677    xf86SetScrnInfoModes(scrn);
2678
2679    success = TRUE;
2680 bailout:
2681    free(crtcs);
2682    free(modes);
2683    free(enabled);
2684    return success;
2685}
2686
2687/* Turn a CRTC off, using the DPMS function and disabling the cursor */
2688static void
2689xf86DisableCrtc(xf86CrtcPtr crtc)
2690{
2691    if (xf86CrtcIsLeased(crtc))
2692        return;
2693
2694    crtc->funcs->dpms(crtc, DPMSModeOff);
2695    xf86_crtc_hide_cursor(crtc);
2696}
2697
2698/*
2699 * Check the CRTC we're going to map each output to vs. it's current
2700 * CRTC.  If they don't match, we have to disable the output and the CRTC
2701 * since the driver will have to re-route things.
2702 */
2703static void
2704xf86PrepareOutputs(ScrnInfoPtr scrn)
2705{
2706    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2707    int o;
2708
2709    for (o = 0; o < config->num_output; o++) {
2710        xf86OutputPtr output = config->output[o];
2711
2712        if (xf86OutputIsLeased(output))
2713            continue;
2714
2715#if RANDR_GET_CRTC_INTERFACE
2716        /* Disable outputs that are unused or will be re-routed */
2717        if (!output->funcs->get_crtc ||
2718            output->crtc != (*output->funcs->get_crtc) (output) ||
2719            output->crtc == NULL)
2720#endif
2721            (*output->funcs->dpms) (output, DPMSModeOff);
2722    }
2723}
2724
2725static void
2726xf86PrepareCrtcs(ScrnInfoPtr scrn)
2727{
2728    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2729    int c;
2730
2731    for (c = 0; c < config->num_crtc; c++) {
2732        xf86CrtcPtr crtc = config->crtc[c];
2733#if RANDR_GET_CRTC_INTERFACE
2734        xf86OutputPtr output = NULL;
2735        uint32_t desired_outputs = 0, current_outputs = 0;
2736        int o;
2737
2738        if (xf86CrtcIsLeased(crtc))
2739            continue;
2740
2741        for (o = 0; o < config->num_output; o++) {
2742            output = config->output[o];
2743            if (output->crtc == crtc)
2744                desired_outputs |= (1 << o);
2745            /* If we can't tell where it's mapped, force it off */
2746            if (!output->funcs->get_crtc) {
2747                desired_outputs = 0;
2748                break;
2749            }
2750            if ((*output->funcs->get_crtc) (output) == crtc)
2751                current_outputs |= (1 << o);
2752        }
2753
2754        /*
2755         * If mappings are different or the CRTC is unused,
2756         * we need to disable it
2757         */
2758        if (desired_outputs != current_outputs || !desired_outputs)
2759            xf86DisableCrtc(crtc);
2760#else
2761        if (xf86CrtcIsLeased(crtc))
2762            continue;
2763
2764        xf86DisableCrtc(crtc);
2765#endif
2766    }
2767}
2768
2769/*
2770 * Using the desired mode information in each crtc, set
2771 * modes (used in EnterVT functions, or at server startup)
2772 */
2773
2774Bool
2775xf86SetDesiredModes(ScrnInfoPtr scrn)
2776{
2777    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2778    xf86CrtcPtr crtc = config->crtc[0];
2779    int enabled = 0, failed = 0;
2780    int c;
2781
2782    /* A driver with this hook will take care of this */
2783    if (!crtc->funcs->set_mode_major) {
2784        xf86PrepareOutputs(scrn);
2785        xf86PrepareCrtcs(scrn);
2786    }
2787
2788    for (c = 0; c < config->num_crtc; c++) {
2789        xf86OutputPtr output = NULL;
2790        int o;
2791        RRTransformPtr transform;
2792
2793        crtc = config->crtc[c];
2794
2795        /* Skip disabled CRTCs */
2796        if (!crtc->enabled)
2797            continue;
2798
2799        if (xf86CompatOutput(scrn) && xf86CompatCrtc(scrn) == crtc)
2800            output = xf86CompatOutput(scrn);
2801        else {
2802            for (o = 0; o < config->num_output; o++)
2803                if (config->output[o]->crtc == crtc) {
2804                    output = config->output[o];
2805                    break;
2806                }
2807        }
2808        /* paranoia */
2809        if (!output)
2810            continue;
2811
2812        /* Mark that we'll need to re-set the mode for sure */
2813        memset(&crtc->mode, 0, sizeof(crtc->mode));
2814        if (!crtc->desiredMode.CrtcHDisplay) {
2815            DisplayModePtr mode =
2816                xf86OutputFindClosestMode(output, scrn->currentMode);
2817
2818            if (!mode)
2819                return FALSE;
2820            xf86SaveModeContents(&crtc->desiredMode, mode);
2821            crtc->desiredRotation = RR_Rotate_0;
2822            crtc->desiredTransformPresent = FALSE;
2823            crtc->desiredX = 0;
2824            crtc->desiredY = 0;
2825        }
2826
2827        if (crtc->desiredTransformPresent)
2828            transform = &crtc->desiredTransform;
2829        else
2830            transform = NULL;
2831        if (xf86CrtcSetModeTransform
2832            (crtc, &crtc->desiredMode, crtc->desiredRotation, transform,
2833             crtc->desiredX, crtc->desiredY)) {
2834            ++enabled;
2835        } else {
2836            for (o = 0; o < config->num_output; o++)
2837                if (config->output[o]->crtc == crtc)
2838                    config->output[o]->crtc = NULL;
2839            crtc->enabled = FALSE;
2840            ++failed;
2841	}
2842    }
2843
2844    xf86DisableUnusedFunctions(scrn);
2845    return enabled != 0 || failed == 0;
2846}
2847
2848/**
2849 * In the current world order, there are lists of modes per output, which may
2850 * or may not include the mode that was asked to be set by XFree86's mode
2851 * selection.  Find the closest one, in the following preference order:
2852 *
2853 * - Equality
2854 * - Closer in size to the requested mode, but no larger
2855 * - Closer in refresh rate to the requested mode.
2856 */
2857
2858DisplayModePtr
2859xf86OutputFindClosestMode(xf86OutputPtr output, DisplayModePtr desired)
2860{
2861    DisplayModePtr best = NULL, scan = NULL;
2862
2863    for (scan = output->probed_modes; scan != NULL; scan = scan->next) {
2864        /* If there's an exact match, we're done. */
2865        if (xf86ModesEqual(scan, desired)) {
2866            best = desired;
2867            break;
2868        }
2869
2870        /* Reject if it's larger than the desired mode. */
2871        if (scan->HDisplay > desired->HDisplay ||
2872            scan->VDisplay > desired->VDisplay) {
2873            continue;
2874        }
2875
2876        /*
2877         * If we haven't picked a best mode yet, use the first
2878         * one in the size range
2879         */
2880        if (best == NULL) {
2881            best = scan;
2882            continue;
2883        }
2884
2885        /* Find if it's closer to the right size than the current best
2886         * option.
2887         */
2888        if ((scan->HDisplay > best->HDisplay &&
2889             scan->VDisplay >= best->VDisplay) ||
2890            (scan->HDisplay >= best->HDisplay &&
2891             scan->VDisplay > best->VDisplay)) {
2892            best = scan;
2893            continue;
2894        }
2895
2896        /* Find if it's still closer to the right refresh than the current
2897         * best resolution.
2898         */
2899        if (scan->HDisplay == best->HDisplay &&
2900            scan->VDisplay == best->VDisplay &&
2901            (fabs(scan->VRefresh - desired->VRefresh) <
2902             fabs(best->VRefresh - desired->VRefresh))) {
2903            best = scan;
2904        }
2905    }
2906    return best;
2907}
2908
2909/**
2910 * When setting a mode through XFree86-VidModeExtension or XFree86-DGA,
2911 * take the specified mode and apply it to the crtc connected to the compat
2912 * output. Then, find similar modes for the other outputs, as with the
2913 * InitialConfiguration code above. The goal is to clone the desired
2914 * mode across all outputs that are currently active.
2915 */
2916
2917Bool
2918xf86SetSingleMode(ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation)
2919{
2920    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2921    Bool ok = TRUE;
2922    xf86OutputPtr compat_output;
2923    DisplayModePtr compat_mode = NULL;
2924    int c;
2925
2926    /*
2927     * Let the compat output drive the final mode selection
2928     */
2929    compat_output = xf86CompatOutput(pScrn);
2930    if (compat_output)
2931        compat_mode = xf86OutputFindClosestMode(compat_output, desired);
2932    if (compat_mode)
2933        desired = compat_mode;
2934
2935    for (c = 0; c < config->num_crtc; c++) {
2936        xf86CrtcPtr crtc = config->crtc[c];
2937        DisplayModePtr crtc_mode = NULL;
2938        int o;
2939
2940        if (!crtc->enabled)
2941            continue;
2942
2943        for (o = 0; o < config->num_output; o++) {
2944            xf86OutputPtr output = config->output[o];
2945            DisplayModePtr output_mode;
2946
2947            /* skip outputs not on this crtc */
2948            if (output->crtc != crtc)
2949                continue;
2950
2951            if (crtc_mode) {
2952                output_mode = xf86OutputFindClosestMode(output, crtc_mode);
2953                if (output_mode != crtc_mode)
2954                    output->crtc = NULL;
2955            }
2956            else
2957                crtc_mode = xf86OutputFindClosestMode(output, desired);
2958        }
2959        if (!crtc_mode) {
2960            crtc->enabled = FALSE;
2961            continue;
2962        }
2963        if (!xf86CrtcSetModeTransform(crtc, crtc_mode, rotation, NULL, 0, 0))
2964            ok = FALSE;
2965        else {
2966            xf86SaveModeContents(&crtc->desiredMode, crtc_mode);
2967            crtc->desiredRotation = rotation;
2968            crtc->desiredTransformPresent = FALSE;
2969            crtc->desiredX = 0;
2970            crtc->desiredY = 0;
2971        }
2972    }
2973    xf86DisableUnusedFunctions(pScrn);
2974#ifdef RANDR_12_INTERFACE
2975    xf86RandR12TellChanged(pScrn->pScreen);
2976#endif
2977    return ok;
2978}
2979
2980/**
2981 * Set the DPMS power mode of all outputs and CRTCs.
2982 *
2983 * If the new mode is off, it will turn off outputs and then CRTCs.
2984 * Otherwise, it will affect CRTCs before outputs.
2985 */
2986void
2987xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags)
2988{
2989    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2990    int i;
2991
2992    if (!scrn->vtSema)
2993        return;
2994
2995    if (mode == DPMSModeOff) {
2996        for (i = 0; i < config->num_output; i++) {
2997            xf86OutputPtr output = config->output[i];
2998
2999            if (!xf86OutputIsLeased(output) && output->crtc != NULL)
3000                (*output->funcs->dpms) (output, mode);
3001        }
3002    }
3003
3004    for (i = 0; i < config->num_crtc; i++) {
3005        xf86CrtcPtr crtc = config->crtc[i];
3006
3007        if (crtc->enabled)
3008            (*crtc->funcs->dpms) (crtc, mode);
3009    }
3010
3011    if (mode != DPMSModeOff) {
3012        for (i = 0; i < config->num_output; i++) {
3013            xf86OutputPtr output = config->output[i];
3014
3015            if (!xf86OutputIsLeased(output) && output->crtc != NULL)
3016                (*output->funcs->dpms) (output, mode);
3017        }
3018    }
3019}
3020
3021/**
3022 * Implement the screensaver by just calling down into the driver DPMS hooks.
3023 *
3024 * Even for monitors with no DPMS support, by the definition of our DPMS hooks,
3025 * the outputs will still get disabled (blanked).
3026 */
3027Bool
3028xf86SaveScreen(ScreenPtr pScreen, int mode)
3029{
3030    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
3031
3032    if (xf86IsUnblank(mode))
3033        xf86DPMSSet(pScrn, DPMSModeOn, 0);
3034    else
3035        xf86DPMSSet(pScrn, DPMSModeOff, 0);
3036
3037    return TRUE;
3038}
3039
3040/**
3041 * Disable all inactive crtcs and outputs
3042 */
3043void
3044xf86DisableUnusedFunctions(ScrnInfoPtr pScrn)
3045{
3046    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3047    int o, c;
3048
3049    for (o = 0; o < xf86_config->num_output; o++) {
3050        xf86OutputPtr output = xf86_config->output[o];
3051
3052        if (!output->crtc)
3053            (*output->funcs->dpms) (output, DPMSModeOff);
3054    }
3055
3056    for (c = 0; c < xf86_config->num_crtc; c++) {
3057        xf86CrtcPtr crtc = xf86_config->crtc[c];
3058
3059        if (!crtc->enabled) {
3060            xf86DisableCrtc(crtc);
3061            memset(&crtc->mode, 0, sizeof(crtc->mode));
3062            xf86RotateDestroy(crtc);
3063            crtc->active = FALSE;
3064        }
3065    }
3066    if (pScrn->pScreen)
3067        xf86_crtc_notify(pScrn->pScreen);
3068    if (pScrn->ModeSet)
3069        pScrn->ModeSet(pScrn);
3070    if (pScrn->pScreen) {
3071        if (pScrn->pScreen->isGPU)
3072            xf86CursorResetCursor(pScrn->pScreen->current_master);
3073        else
3074            xf86CursorResetCursor(pScrn->pScreen);
3075    }
3076}
3077
3078#ifdef RANDR_12_INTERFACE
3079
3080#define EDID_ATOM_NAME		"EDID"
3081
3082/**
3083 * Set the RandR EDID property
3084 */
3085static void
3086xf86OutputSetEDIDProperty(xf86OutputPtr output, void *data, int data_len)
3087{
3088    Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE);
3089
3090    /* This may get called before the RandR resources have been created */
3091    if (output->randr_output == NULL)
3092        return;
3093
3094    if (data_len != 0) {
3095        RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8,
3096                               PropModeReplace, data_len, data, FALSE, TRUE);
3097    }
3098    else {
3099        RRDeleteOutputProperty(output->randr_output, edid_atom);
3100    }
3101}
3102
3103#define TILE_ATOM_NAME		"TILE"
3104/* changing this in the future could be tricky as people may hardcode 8 */
3105#define TILE_PROP_NUM_ITEMS		8
3106static void
3107xf86OutputSetTileProperty(xf86OutputPtr output)
3108{
3109    Atom tile_atom = MakeAtom(TILE_ATOM_NAME, sizeof(TILE_ATOM_NAME) - 1, TRUE);
3110
3111    /* This may get called before the RandR resources have been created */
3112    if (output->randr_output == NULL)
3113        return;
3114
3115    if (output->tile_info.group_id != 0) {
3116        RRChangeOutputProperty(output->randr_output, tile_atom, XA_INTEGER, 32,
3117                               PropModeReplace, TILE_PROP_NUM_ITEMS, (uint32_t *)&output->tile_info, FALSE, TRUE);
3118    }
3119    else {
3120        RRDeleteOutputProperty(output->randr_output, tile_atom);
3121    }
3122}
3123
3124#endif
3125
3126/* Pull out a phyiscal size from a detailed timing if available. */
3127struct det_phySize_parameter {
3128    xf86OutputPtr output;
3129    ddc_quirk_t quirks;
3130    Bool ret;
3131};
3132
3133static void
3134handle_detailed_physical_size(struct detailed_monitor_section
3135                              *det_mon, void *data)
3136{
3137    struct det_phySize_parameter *p;
3138
3139    p = (struct det_phySize_parameter *) data;
3140
3141    if (p->ret == TRUE)
3142        return;
3143
3144    xf86DetTimingApplyQuirks(det_mon, p->quirks,
3145                             p->output->MonInfo->features.hsize,
3146                             p->output->MonInfo->features.vsize);
3147    if (det_mon->type == DT &&
3148        det_mon->section.d_timings.h_size != 0 &&
3149        det_mon->section.d_timings.v_size != 0) {
3150        /* some sanity checking for aspect ratio:
3151           assume any h / v (or v / h) > 2.4 to be bogus.
3152           This would even include cinemascope */
3153        if (((det_mon->section.d_timings.h_size * 5) <
3154             (det_mon->section.d_timings.v_size * 12)) &&
3155            ((det_mon->section.d_timings.v_size * 5) <
3156             (det_mon->section.d_timings.h_size * 12))) {
3157            p->output->mm_width = det_mon->section.d_timings.h_size;
3158            p->output->mm_height = det_mon->section.d_timings.v_size;
3159            p->ret = TRUE;
3160        } else
3161            xf86DrvMsg(p->output->scrn->scrnIndex, X_WARNING,
3162                       "Output %s: Strange aspect ratio (%i/%i), "
3163                       "consider adding a quirk\n", p->output->name,
3164                       det_mon->section.d_timings.h_size,
3165                       det_mon->section.d_timings.v_size);
3166    }
3167}
3168
3169Bool
3170xf86OutputParseKMSTile(const char *tile_data, int tile_length,
3171                       struct xf86CrtcTileInfo *tile_info)
3172{
3173    int ret;
3174
3175    ret = sscanf(tile_data, "%d:%d:%d:%d:%d:%d:%d:%d",
3176                 &tile_info->group_id,
3177                 &tile_info->flags,
3178                 &tile_info->num_h_tile,
3179                 &tile_info->num_v_tile,
3180                 &tile_info->tile_h_loc,
3181                 &tile_info->tile_v_loc,
3182                 &tile_info->tile_h_size,
3183                 &tile_info->tile_v_size);
3184    if (ret != 8)
3185        return FALSE;
3186    return TRUE;
3187}
3188
3189void
3190xf86OutputSetTile(xf86OutputPtr output, struct xf86CrtcTileInfo *tile_info)
3191{
3192    if (tile_info)
3193        output->tile_info = *tile_info;
3194    else
3195        memset(&output->tile_info, 0, sizeof(output->tile_info));
3196#ifdef RANDR_12_INTERFACE
3197    xf86OutputSetTileProperty(output);
3198#endif
3199}
3200
3201/**
3202 * Set the EDID information for the specified output
3203 */
3204void
3205xf86OutputSetEDID(xf86OutputPtr output, xf86MonPtr edid_mon)
3206{
3207    ScrnInfoPtr scrn = output->scrn;
3208    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3209    Bool debug_modes = config->debug_modes || xf86Initialising;
3210
3211#ifdef RANDR_12_INTERFACE
3212    int size;
3213#endif
3214
3215    free(output->MonInfo);
3216
3217    output->MonInfo = edid_mon;
3218    output->mm_width = 0;
3219    output->mm_height = 0;
3220
3221    if (debug_modes) {
3222        xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n",
3223                   output->name);
3224        xf86PrintEDID(edid_mon);
3225    }
3226
3227    /* Set the DDC properties for the 'compat' output */
3228    /* GPU screens don't have a root window */
3229    if (output == xf86CompatOutput(scrn) && !scrn->is_gpu)
3230        xf86SetDDCproperties(scrn, edid_mon);
3231
3232#ifdef RANDR_12_INTERFACE
3233    /* Set the RandR output properties */
3234    size = 0;
3235    if (edid_mon) {
3236        if (edid_mon->ver.version == 1) {
3237            size = 128;
3238            if (edid_mon->flags & EDID_COMPLETE_RAWDATA)
3239                size += edid_mon->no_sections * 128;
3240        }
3241        else if (edid_mon->ver.version == 2)
3242            size = 256;
3243    }
3244    xf86OutputSetEDIDProperty(output, edid_mon ? edid_mon->rawData : NULL,
3245                              size);
3246#endif
3247
3248    if (edid_mon) {
3249
3250        struct det_phySize_parameter p;
3251
3252        p.output = output;
3253        p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex, edid_mon, FALSE);
3254        p.ret = FALSE;
3255        xf86ForEachDetailedBlock(edid_mon, handle_detailed_physical_size, &p);
3256
3257        /* if no mm size is available from a detailed timing, check the max size field */
3258        if ((!output->mm_width || !output->mm_height) &&
3259            (edid_mon->features.hsize && edid_mon->features.vsize)) {
3260            output->mm_width = edid_mon->features.hsize * 10;
3261            output->mm_height = edid_mon->features.vsize * 10;
3262        }
3263    }
3264}
3265
3266/**
3267 * Return the list of modes supported by the EDID information
3268 * stored in 'output'
3269 */
3270DisplayModePtr
3271xf86OutputGetEDIDModes(xf86OutputPtr output)
3272{
3273    ScrnInfoPtr scrn = output->scrn;
3274    xf86MonPtr edid_mon = output->MonInfo;
3275
3276    if (!edid_mon)
3277        return NULL;
3278    return xf86DDCGetModes(scrn->scrnIndex, edid_mon);
3279}
3280
3281/* maybe we should care about DDC1?  meh. */
3282xf86MonPtr
3283xf86OutputGetEDID(xf86OutputPtr output, I2CBusPtr pDDCBus)
3284{
3285    ScrnInfoPtr scrn = output->scrn;
3286    xf86MonPtr mon;
3287
3288    mon = xf86DoEEDID(scrn, pDDCBus, TRUE);
3289    if (mon)
3290        xf86DDCApplyQuirks(scrn->scrnIndex, mon);
3291
3292    return mon;
3293}
3294
3295static const char *_xf86ConnectorNames[] = {
3296    "None", "VGA", "DVI-I", "DVI-D",
3297    "DVI-A", "Composite", "S-Video",
3298    "Component", "LFP", "Proprietary",
3299    "HDMI", "DisplayPort",
3300};
3301
3302const char *
3303xf86ConnectorGetName(xf86ConnectorType connector)
3304{
3305    return _xf86ConnectorNames[connector];
3306}
3307
3308#ifdef XV
3309static void
3310x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
3311{
3312    dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
3313    dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
3314    dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
3315    dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
3316
3317    if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
3318        dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
3319}
3320
3321static void
3322x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
3323{
3324    if (crtc->enabled) {
3325        crtc_box->x1 = crtc->x;
3326        crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
3327        crtc_box->y1 = crtc->y;
3328        crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
3329    }
3330    else
3331        crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
3332}
3333
3334static int
3335xf86_crtc_box_area(BoxPtr box)
3336{
3337    return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
3338}
3339
3340/*
3341 * Return the crtc covering 'box'. If two crtcs cover a portion of
3342 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
3343 * with greater coverage
3344 */
3345
3346static xf86CrtcPtr
3347xf86_covering_crtc(ScrnInfoPtr pScrn,
3348                   BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
3349{
3350    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3351    xf86CrtcPtr crtc, best_crtc;
3352    int coverage, best_coverage;
3353    int c;
3354    BoxRec crtc_box, cover_box;
3355
3356    best_crtc = NULL;
3357    best_coverage = 0;
3358    crtc_box_ret->x1 = 0;
3359    crtc_box_ret->x2 = 0;
3360    crtc_box_ret->y1 = 0;
3361    crtc_box_ret->y2 = 0;
3362    for (c = 0; c < xf86_config->num_crtc; c++) {
3363        crtc = xf86_config->crtc[c];
3364        x86_crtc_box(crtc, &crtc_box);
3365        x86_crtc_box_intersect(&cover_box, &crtc_box, box);
3366        coverage = xf86_crtc_box_area(&cover_box);
3367        if (coverage && crtc == desired) {
3368            *crtc_box_ret = crtc_box;
3369            return crtc;
3370        }
3371        else if (coverage > best_coverage) {
3372            *crtc_box_ret = crtc_box;
3373            best_crtc = crtc;
3374            best_coverage = coverage;
3375        }
3376    }
3377    return best_crtc;
3378}
3379
3380/*
3381 * For overlay video, compute the relevant CRTC and
3382 * clip video to that.
3383 *
3384 * returning FALSE means there was a memory failure of some kind,
3385 * not that the video shouldn't be displayed
3386 */
3387
3388Bool
3389xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn,
3390                            xf86CrtcPtr * crtc_ret,
3391                            xf86CrtcPtr desired_crtc,
3392                            BoxPtr dst,
3393                            INT32 *xa,
3394                            INT32 *xb,
3395                            INT32 *ya,
3396                            INT32 *yb, RegionPtr reg, INT32 width, INT32 height)
3397{
3398    Bool ret;
3399    RegionRec crtc_region_local;
3400    RegionPtr crtc_region = reg;
3401
3402    if (crtc_ret) {
3403        BoxRec crtc_box;
3404        xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst,
3405                                              desired_crtc,
3406                                              &crtc_box);
3407
3408        if (crtc) {
3409            RegionInit(&crtc_region_local, &crtc_box, 1);
3410            crtc_region = &crtc_region_local;
3411            RegionIntersect(crtc_region, crtc_region, reg);
3412        }
3413        *crtc_ret = crtc;
3414    }
3415
3416    ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb,
3417                                crtc_region, width, height);
3418
3419    if (crtc_region != reg)
3420        RegionUninit(&crtc_region_local);
3421
3422    return ret;
3423}
3424#endif
3425
3426xf86_crtc_notify_proc_ptr
3427xf86_wrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr new)
3428{
3429    if (xf86CrtcConfigPrivateIndex != -1) {
3430        ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3431        xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3432        xf86_crtc_notify_proc_ptr old;
3433
3434        old = config->xf86_crtc_notify;
3435        config->xf86_crtc_notify = new;
3436        return old;
3437    }
3438    return NULL;
3439}
3440
3441void
3442xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old)
3443{
3444    if (xf86CrtcConfigPrivateIndex != -1) {
3445        ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3446        xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3447
3448        config->xf86_crtc_notify = old;
3449    }
3450}
3451
3452void
3453xf86_crtc_notify(ScreenPtr screen)
3454{
3455    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3456    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3457
3458    if (config->xf86_crtc_notify)
3459        config->xf86_crtc_notify(screen);
3460}
3461
3462Bool
3463xf86_crtc_supports_gamma(ScrnInfoPtr pScrn)
3464{
3465    if (xf86CrtcConfigPrivateIndex != -1) {
3466        xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3467        xf86CrtcPtr crtc;
3468
3469        /* for multiple drivers loaded we need this */
3470        if (!xf86_config)
3471            return FALSE;
3472        if (xf86_config->num_crtc == 0)
3473            return FALSE;
3474        crtc = xf86_config->crtc[0];
3475
3476        return crtc->funcs->gamma_set != NULL;
3477    }
3478
3479    return FALSE;
3480}
3481
3482void
3483xf86ProviderSetup(ScrnInfoPtr scrn,
3484                  const xf86ProviderFuncsRec *funcs, const char *name)
3485{
3486    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3487
3488    assert(!xf86_config->name);
3489    assert(name);
3490
3491    xf86_config->name = strdup(name);
3492    xf86_config->provider_funcs = funcs;
3493#ifdef RANDR_12_INTERFACE
3494    xf86_config->randr_provider = NULL;
3495#endif
3496}
3497
3498void
3499xf86DetachAllCrtc(ScrnInfoPtr scrn)
3500{
3501        xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3502        int i;
3503
3504        for (i = 0; i < xf86_config->num_crtc; i++) {
3505            xf86CrtcPtr crtc = xf86_config->crtc[i];
3506
3507            if (crtc->randr_crtc)
3508                RRCrtcDetachScanoutPixmap(crtc->randr_crtc);
3509
3510            /* dpms off */
3511            xf86DisableCrtc(crtc);
3512            /* force a reset the next time its used */
3513            crtc->randr_crtc->mode = NULL;
3514            crtc->mode.HDisplay = 0;
3515            crtc->x = crtc->y = 0;
3516        }
3517}
3518