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