xf86Crtc.c revision b86d567b
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 RANDR_13_INTERFACE
773    return RANDR_INTERFACE_VERSION;
774#else
775    return TRUE;
776#endif
777}
778
779static DisplayModePtr
780xf86DefaultMode (xf86OutputPtr output, int width, int height)
781{
782    DisplayModePtr  target_mode = NULL;
783    DisplayModePtr  mode;
784    int		    target_diff = 0;
785    int		    target_preferred = 0;
786    int		    mm_height;
787
788    mm_height = output->mm_height;
789    if (!mm_height)
790	mm_height = (768 * 25.4) / DEFAULT_DPI;
791    /*
792     * Pick a mode closest to DEFAULT_DPI
793     */
794    for (mode = output->probed_modes; mode; mode = mode->next)
795    {
796	int	    dpi;
797	int	    preferred = (((mode->type & M_T_PREFERRED) != 0) +
798				 ((mode->type & M_T_USERPREF) != 0));
799	int	    diff;
800
801	if (xf86ModeWidth (mode, output->initial_rotation) > width ||
802	    xf86ModeHeight (mode, output->initial_rotation) > height)
803	    continue;
804
805	/* yes, use VDisplay here, not xf86ModeHeight */
806	dpi = (mode->VDisplay * 254) / (mm_height * 10);
807	diff = dpi - DEFAULT_DPI;
808	diff = diff < 0 ? -diff : diff;
809	if (target_mode == NULL || (preferred > target_preferred) ||
810	    (preferred == target_preferred && diff < target_diff))
811	{
812	    target_mode = mode;
813	    target_diff = diff;
814	    target_preferred = preferred;
815	}
816    }
817    return target_mode;
818}
819
820static DisplayModePtr
821xf86ClosestMode (xf86OutputPtr output,
822		 DisplayModePtr match, Rotation match_rotation,
823		 int width, int height)
824{
825    DisplayModePtr  target_mode = NULL;
826    DisplayModePtr  mode;
827    int		    target_diff = 0;
828
829    /*
830     * Pick a mode closest to the specified mode
831     */
832    for (mode = output->probed_modes; mode; mode = mode->next)
833    {
834	int	    dx, dy;
835	int	    diff;
836
837	if (xf86ModeWidth (mode, output->initial_rotation) > width ||
838	    xf86ModeHeight (mode, output->initial_rotation) > height)
839	    continue;
840
841	/* exact matches are preferred */
842	if (output->initial_rotation == match_rotation &&
843	    xf86ModesEqual (mode, match))
844	    return mode;
845
846	dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation);
847	dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation);
848	diff = dx * dx + dy * dy;
849	if (target_mode == NULL || diff < target_diff)
850	{
851	    target_mode = mode;
852	    target_diff = diff;
853	}
854    }
855    return target_mode;
856}
857
858static DisplayModePtr
859xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height)
860{
861    DisplayModePtr  mode;
862
863    for (mode = output->probed_modes; mode; mode = mode->next)
864    {
865	if (xf86ModeWidth (mode, output->initial_rotation) > width ||
866	    xf86ModeHeight (mode, output->initial_rotation) > height)
867	    continue;
868
869	if (mode->type & M_T_PREFERRED)
870	    return mode;
871    }
872    return NULL;
873}
874
875static DisplayModePtr
876xf86OutputHasUserPreferredMode (xf86OutputPtr output)
877{
878    DisplayModePtr mode, first = output->probed_modes;
879
880    for (mode = first; mode && mode->next != first; mode = mode->next)
881	if (mode->type & M_T_USERPREF)
882	    return mode;
883
884    return NULL;
885}
886
887static int
888xf86PickCrtcs (ScrnInfoPtr	scrn,
889	       xf86CrtcPtr	*best_crtcs,
890	       DisplayModePtr	*modes,
891	       int		n,
892	       int		width,
893	       int		height)
894{
895    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
896    int		    c, o;
897    xf86OutputPtr   output;
898    xf86CrtcPtr	    crtc;
899    xf86CrtcPtr	    *crtcs;
900    xf86CrtcPtr	    best_crtc;
901    int		    best_score;
902    int		    score;
903    int		    my_score;
904
905    if (n == config->num_output)
906	return 0;
907    output = config->output[n];
908
909    /*
910     * Compute score with this output disabled
911     */
912    best_crtcs[n] = NULL;
913    best_crtc = NULL;
914    best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height);
915    if (modes[n] == NULL)
916	return best_score;
917
918    crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr));
919    if (!crtcs)
920	return best_score;
921
922    my_score = 1;
923    /* Score outputs that are known to be connected higher */
924    if (output->status == XF86OutputStatusConnected)
925	my_score++;
926    /* Score outputs with preferred modes higher */
927    if (xf86OutputHasPreferredMode (output, width, height))
928	my_score++;
929    /*
930     * Select a crtc for this output and
931     * then attempt to configure the remaining
932     * outputs
933     */
934    for (c = 0; c < config->num_crtc; c++)
935    {
936	if ((output->possible_crtcs & (1 << c)) == 0)
937	    continue;
938
939	crtc = config->crtc[c];
940	/*
941	 * Check to see if some other output is
942	 * using this crtc
943	 */
944	for (o = 0; o < n; o++)
945	    if (best_crtcs[o] == crtc)
946		break;
947	if (o < n)
948	{
949	    /*
950	     * If the two outputs desire the same mode,
951	     * see if they can be cloned
952	     */
953	    if (xf86ModesEqual (modes[o], modes[n]) &&
954		config->output[o]->initial_rotation == config->output[n]->initial_rotation &&
955		config->output[o]->initial_x == config->output[n]->initial_x &&
956		config->output[o]->initial_y == config->output[n]->initial_y)
957	    {
958		if ((output->possible_clones & (1 << o)) == 0)
959		    continue;		/* nope, try next CRTC */
960	    }
961	    else
962		continue;		/* different modes, can't clone */
963	}
964	crtcs[n] = crtc;
965	memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr));
966	score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height);
967	if (score > best_score)
968	{
969	    best_crtc = crtc;
970	    best_score = score;
971	    memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr));
972	}
973    }
974    xfree (crtcs);
975    return best_score;
976}
977
978
979/*
980 * Compute the virtual size necessary to place all of the available
981 * crtcs in the specified configuration.
982 *
983 * canGrow indicates that the driver can make the screen larger than its initial
984 * configuration.  If FALSE, this function will enlarge the screen to include
985 * the largest available mode.
986 */
987
988static void
989xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp,
990			 Bool canGrow)
991{
992    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
993    int	    width = 0, height = 0;
994    int	    o;
995    int	    c;
996    int	    s;
997
998    for (c = 0; c < config->num_crtc; c++)
999    {
1000	int	    crtc_width = 0, crtc_height = 0;
1001	xf86CrtcPtr crtc = config->crtc[c];
1002
1003	if (crtc->enabled)
1004	{
1005	    crtc_width = crtc->x + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation);
1006	    crtc_height = crtc->y + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation);
1007	}
1008	if (!canGrow) {
1009	    for (o = 0; o < config->num_output; o++)
1010	    {
1011		xf86OutputPtr   output = config->output[o];
1012
1013		for (s = 0; s < config->num_crtc; s++)
1014		    if (output->possible_crtcs & (1 << s))
1015		    {
1016			DisplayModePtr  mode;
1017			for (mode = output->probed_modes; mode; mode = mode->next)
1018			{
1019			    if (mode->HDisplay > crtc_width)
1020				crtc_width = mode->HDisplay;
1021			    if (mode->VDisplay > crtc_width)
1022				crtc_width = mode->VDisplay;
1023			    if (mode->VDisplay > crtc_height)
1024				crtc_height = mode->VDisplay;
1025			    if (mode->HDisplay > crtc_height)
1026				crtc_height = mode->HDisplay;
1027			}
1028		    }
1029	    }
1030	}
1031	if (crtc_width > width)
1032	    width = crtc_width;
1033	if (crtc_height > height)
1034	    height = crtc_height;
1035    }
1036    if (config->maxWidth && width > config->maxWidth) width = config->maxWidth;
1037    if (config->maxHeight && height > config->maxHeight) height = config->maxHeight;
1038    if (config->minWidth && width < config->minWidth) width = config->minWidth;
1039    if (config->minHeight && height < config->minHeight) height = config->minHeight;
1040    *widthp = width;
1041    *heightp = height;
1042}
1043
1044#define POSITION_UNSET	-100000
1045
1046/*
1047 * check if the user configured any outputs at all
1048 * with either a position or a relative setting or a mode.
1049 */
1050static Bool
1051xf86UserConfiguredOutputs(ScrnInfoPtr scrn, DisplayModePtr *modes)
1052{
1053    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
1054    int o;
1055    Bool user_conf = FALSE;
1056
1057    for (o = 0; o < config->num_output; o++)
1058    {
1059	xf86OutputPtr output = config->output[o];
1060	char	    *position;
1061	char	    *relative_name;
1062	OutputOpts	    relation;
1063	int r;
1064	static const OutputOpts	relations[] = {
1065	    OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
1066	};
1067
1068	position = xf86GetOptValString (output->options,
1069					OPTION_POSITION);
1070	if (position)
1071	    user_conf = TRUE;
1072
1073	relation = 0;
1074	relative_name = NULL;
1075	for (r = 0; r < 4; r++)
1076	{
1077	    relation = relations[r];
1078	    relative_name = xf86GetOptValString (output->options,
1079						     relation);
1080	    if (relative_name)
1081		break;
1082	}
1083	if (relative_name)
1084	    user_conf = TRUE;
1085
1086	modes[o] = xf86OutputHasUserPreferredMode(output);
1087	if (modes[o])
1088	    user_conf = TRUE;
1089    }
1090
1091    return user_conf;
1092}
1093
1094static Bool
1095xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes)
1096{
1097    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
1098    int			o;
1099    int			min_x, min_y;
1100
1101    for (o = 0; o < config->num_output; o++)
1102    {
1103	xf86OutputPtr	output = config->output[o];
1104
1105	output->initial_x = output->initial_y = POSITION_UNSET;
1106    }
1107
1108    /*
1109     * Loop until all outputs are set
1110     */
1111    for (;;)
1112    {
1113	Bool	any_set = FALSE;
1114	Bool	keep_going = FALSE;
1115
1116	for (o = 0; o < config->num_output; o++)
1117	{
1118	    static const OutputOpts	relations[] = {
1119		OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
1120	    };
1121	    xf86OutputPtr   output = config->output[o];
1122	    xf86OutputPtr   relative;
1123	    char	    *relative_name;
1124	    char	    *position;
1125	    OutputOpts	    relation;
1126	    int		    r;
1127
1128	    if (output->initial_x != POSITION_UNSET)
1129		continue;
1130	    position = xf86GetOptValString (output->options,
1131					    OPTION_POSITION);
1132	    /*
1133	     * Absolute position wins
1134	     */
1135	    if (position)
1136	    {
1137		int		    x, y;
1138		if (sscanf (position, "%d %d", &x, &y) == 2)
1139		{
1140		    output->initial_x = x;
1141		    output->initial_y = y;
1142		}
1143		else
1144		{
1145		    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
1146				"Output %s position not of form \"x y\"\n",
1147				output->name);
1148		    output->initial_x = output->initial_y = 0;
1149		}
1150		any_set = TRUE;
1151		continue;
1152	    }
1153	    /*
1154	     * Next comes relative positions
1155	     */
1156	    relation = 0;
1157	    relative_name = NULL;
1158	    for (r = 0; r < 4; r++)
1159	    {
1160		relation = relations[r];
1161		relative_name = xf86GetOptValString (output->options,
1162						     relation);
1163		if (relative_name)
1164		    break;
1165	    }
1166	    if (relative_name)
1167	    {
1168		int or;
1169		relative = NULL;
1170		for (or = 0; or < config->num_output; or++)
1171		{
1172		    xf86OutputPtr	out_rel = config->output[or];
1173		    XF86ConfMonitorPtr	rel_mon = out_rel->conf_monitor;
1174
1175		    if (rel_mon)
1176		    {
1177			if (xf86nameCompare (rel_mon->mon_identifier,
1178					      relative_name) == 0)
1179			{
1180			    relative = config->output[or];
1181			    break;
1182			}
1183		    }
1184		    if (strcmp (out_rel->name, relative_name) == 0)
1185		    {
1186			relative = config->output[or];
1187			break;
1188		    }
1189		}
1190		if (!relative)
1191		{
1192		    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
1193				"Cannot position output %s relative to unknown output %s\n",
1194				output->name, relative_name);
1195		    output->initial_x = 0;
1196		    output->initial_y = 0;
1197		    any_set = TRUE;
1198		    continue;
1199		}
1200		if (!modes[or])
1201		{
1202		    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
1203				"Cannot position output %s relative to output %s without modes\n",
1204				output->name, relative_name);
1205		    output->initial_x = 0;
1206		    output->initial_y = 0;
1207		    any_set = TRUE;
1208		    continue;
1209		}
1210		if (relative->initial_x == POSITION_UNSET)
1211		{
1212		    keep_going = TRUE;
1213		    continue;
1214		}
1215		output->initial_x = relative->initial_x;
1216		output->initial_y = relative->initial_y;
1217		switch (relation) {
1218		case OPTION_BELOW:
1219		    output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation);
1220		    break;
1221		case OPTION_RIGHT_OF:
1222		    output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation);
1223		    break;
1224		case OPTION_ABOVE:
1225		    if (modes[o])
1226			output->initial_y -= xf86ModeHeight (modes[o], output->initial_rotation);
1227		    break;
1228		case OPTION_LEFT_OF:
1229		    if (modes[o])
1230			output->initial_x -= xf86ModeWidth (modes[o], output->initial_rotation);
1231		    break;
1232		default:
1233		    break;
1234		}
1235		any_set = TRUE;
1236		continue;
1237	    }
1238
1239	    /* Nothing set, just stick them at 0,0 */
1240	    output->initial_x = 0;
1241	    output->initial_y = 0;
1242	    any_set = TRUE;
1243	}
1244	if (!keep_going)
1245	    break;
1246	if (!any_set)
1247	{
1248	    for (o = 0; o < config->num_output; o++)
1249	    {
1250		xf86OutputPtr   output = config->output[o];
1251		if (output->initial_x == POSITION_UNSET)
1252		{
1253		    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
1254				"Output position loop. Moving %s to 0,0\n",
1255				output->name);
1256		    output->initial_x = output->initial_y = 0;
1257		    break;
1258		}
1259	    }
1260	}
1261    }
1262
1263    /*
1264     * normalize positions
1265     */
1266    min_x = 1000000;
1267    min_y = 1000000;
1268    for (o = 0; o < config->num_output; o++)
1269    {
1270	xf86OutputPtr	output = config->output[o];
1271
1272	if (output->initial_x < min_x)
1273	    min_x = output->initial_x;
1274	if (output->initial_y < min_y)
1275	    min_y = output->initial_y;
1276    }
1277
1278    for (o = 0; o < config->num_output; o++)
1279    {
1280	xf86OutputPtr	output = config->output[o];
1281
1282	output->initial_x -= min_x;
1283	output->initial_y -= min_y;
1284    }
1285    return TRUE;
1286}
1287
1288static void
1289xf86InitialPanning (ScrnInfoPtr scrn)
1290{
1291    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
1292    int			o;
1293
1294    for (o = 0; o < config->num_output; o++)
1295    {
1296	xf86OutputPtr	output = config->output[o];
1297	char	       *panning = xf86GetOptValString (output->options, OPTION_PANNING);
1298	int		width, height, left, top;
1299	int		track_width, track_height, track_left, track_top;
1300	int		brdr[4];
1301
1302	memset (&output->initialTotalArea,    0, sizeof(BoxRec));
1303	memset (&output->initialTrackingArea, 0, sizeof(BoxRec));
1304	memset (output->initialBorder,        0, 4*sizeof(INT16));
1305
1306	if (! panning)
1307	    continue;
1308
1309	switch (sscanf (panning, "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d",
1310			&width, &height, &left, &top,
1311			&track_width, &track_height, &track_left, &track_top,
1312			&brdr[0], &brdr[1], &brdr[2], &brdr[3])) {
1313	case 12:
1314	    output->initialBorder[0] = brdr[0];
1315	    output->initialBorder[1] = brdr[1];
1316	    output->initialBorder[2] = brdr[2];
1317	    output->initialBorder[3] = brdr[3];
1318	    /* fall through */
1319	case 8:
1320	    output->initialTrackingArea.x1 = track_left;
1321	    output->initialTrackingArea.y1 = track_top;
1322	    output->initialTrackingArea.x2 = track_left + track_width;
1323	    output->initialTrackingArea.y2 = track_top  + track_height;
1324	    /* fall through */
1325	case 4:
1326	    output->initialTotalArea.x1 = left;
1327	    output->initialTotalArea.y1 = top;
1328	    /* fall through */
1329	case 2:
1330	    output->initialTotalArea.x2 = output->initialTotalArea.x1 + width;
1331	    output->initialTotalArea.y2 = output->initialTotalArea.y1 + height;
1332	    break;
1333	default:
1334	    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
1335			"Broken panning specification '%s' for output %s in config file\n",
1336			panning, output->name);
1337	}
1338    }
1339}
1340
1341/*
1342 * XXX walk the monitor mode list and prune out duplicates that
1343 * are inserted by xf86DDCMonitorSet. In an ideal world, that
1344 * function would do this work by itself.
1345 */
1346
1347static void
1348xf86PruneDuplicateMonitorModes (MonPtr Monitor)
1349{
1350    DisplayModePtr  master, clone, next;
1351
1352    for (master = Monitor->Modes;
1353	 master && master != Monitor->Last;
1354	 master = master->next)
1355    {
1356	for (clone = master->next; clone && clone != Monitor->Modes; clone = next)
1357	{
1358	    next = clone->next;
1359	    if (xf86ModesEqual (master, clone))
1360	    {
1361		if (Monitor->Last == clone)
1362		    Monitor->Last = clone->prev;
1363		xf86DeleteMode (&Monitor->Modes, clone);
1364	    }
1365	}
1366    }
1367}
1368
1369/** Return - 0 + if a should be earlier, same or later than b in list
1370 */
1371static int
1372xf86ModeCompare (DisplayModePtr a, DisplayModePtr b)
1373{
1374    int	diff;
1375
1376    diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0);
1377    if (diff)
1378	return diff;
1379    diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay;
1380    if (diff)
1381	return diff;
1382    diff = b->Clock - a->Clock;
1383    return diff;
1384}
1385
1386/**
1387 * Insertion sort input in-place and return the resulting head
1388 */
1389static DisplayModePtr
1390xf86SortModes (DisplayModePtr input)
1391{
1392    DisplayModePtr  output = NULL, i, o, n, *op, prev;
1393
1394    /* sort by preferred status and pixel area */
1395    while (input)
1396    {
1397	i = input;
1398	input = input->next;
1399	for (op = &output; (o = *op); op = &o->next)
1400	    if (xf86ModeCompare (o, i) > 0)
1401		break;
1402	i->next = *op;
1403	*op = i;
1404    }
1405    /* prune identical modes */
1406    for (o = output; o && (n = o->next); o = n)
1407    {
1408	if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n))
1409	{
1410	    o->next = n->next;
1411	    xfree (n->name);
1412	    xfree (n);
1413	    n = o;
1414	}
1415    }
1416    /* hook up backward links */
1417    prev = NULL;
1418    for (o = output; o; o = o->next)
1419    {
1420	o->prev = prev;
1421	prev = o;
1422    }
1423    return output;
1424}
1425
1426static char *
1427preferredMode(ScrnInfoPtr pScrn, xf86OutputPtr output)
1428{
1429    char *preferred_mode = NULL;
1430
1431    /* Check for a configured preference for a particular mode */
1432    preferred_mode = xf86GetOptValString (output->options,
1433					  OPTION_PREFERRED_MODE);
1434    if (preferred_mode)
1435	return preferred_mode;
1436
1437    if (pScrn->display->modes && *pScrn->display->modes)
1438	preferred_mode = *pScrn->display->modes;
1439
1440    return preferred_mode;
1441}
1442
1443static void
1444GuessRangeFromModes(MonPtr mon, DisplayModePtr mode)
1445{
1446    if (!mon || !mode)
1447       return;
1448
1449    mon->nHsync = 1;
1450    mon->hsync[0].lo = 1024.0;
1451    mon->hsync[0].hi = 0.0;
1452
1453    mon->nVrefresh = 1;
1454    mon->vrefresh[0].lo = 1024.0;
1455    mon->vrefresh[0].hi = 0.0;
1456
1457    while (mode) {
1458	if (!mode->HSync)
1459	    mode->HSync = ((float) mode->Clock ) / ((float) mode->HTotal);
1460
1461	if (!mode->VRefresh)
1462	    mode->VRefresh = (1000.0 * ((float) mode->Clock)) /
1463		((float) (mode->HTotal * mode->VTotal));
1464
1465	if (mode->HSync < mon->hsync[0].lo)
1466	    mon->hsync[0].lo = mode->HSync;
1467
1468	if (mode->HSync > mon->hsync[0].hi)
1469	    mon->hsync[0].hi = mode->HSync;
1470
1471	if (mode->VRefresh < mon->vrefresh[0].lo)
1472	    mon->vrefresh[0].lo = mode->VRefresh;
1473
1474	if (mode->VRefresh > mon->vrefresh[0].hi)
1475	    mon->vrefresh[0].hi = mode->VRefresh;
1476
1477	mode = mode->next;
1478    }
1479
1480    /* stretch out the bottom to fit 640x480@60 */
1481    if (mon->hsync[0].lo > 31.0)
1482       mon->hsync[0].lo = 31.0;
1483    if (mon->vrefresh[0].lo > 58.0)
1484       mon->vrefresh[0].lo = 58.0;
1485}
1486
1487_X_EXPORT void
1488xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
1489{
1490    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
1491    int			o;
1492
1493    /* When canGrow was TRUE in the initial configuration we have to
1494     * compare against the maximum values so that we don't drop modes.
1495     * When canGrow was FALSE, the maximum values would have been clamped
1496     * anyway.
1497     */
1498    if (maxX == 0 || maxY == 0) {
1499	maxX = config->maxWidth;
1500	maxY = config->maxHeight;
1501    }
1502
1503    /* Elide duplicate modes before defaulting code uses them */
1504    xf86PruneDuplicateMonitorModes (scrn->monitor);
1505
1506    /* Probe the list of modes for each output. */
1507    for (o = 0; o < config->num_output; o++)
1508    {
1509	xf86OutputPtr	    output = config->output[o];
1510	DisplayModePtr	    mode;
1511	DisplayModePtr	    config_modes = NULL, output_modes, default_modes = NULL;
1512	char		    *preferred_mode;
1513	xf86MonPtr	    edid_monitor;
1514	XF86ConfMonitorPtr  conf_monitor;
1515	MonRec		    mon_rec;
1516	int		    min_clock = 0;
1517	int		    max_clock = 0;
1518	double		    clock;
1519	Bool                add_default_modes = TRUE;
1520	enum { sync_config, sync_edid, sync_default } sync_source = sync_default;
1521
1522	while (output->probed_modes != NULL)
1523	    xf86DeleteMode(&output->probed_modes, output->probed_modes);
1524
1525	/*
1526	 * Check connection status
1527	 */
1528	output->status = (*output->funcs->detect)(output);
1529
1530	if (output->status == XF86OutputStatusDisconnected)
1531	{
1532	    xf86OutputSetEDID (output, NULL);
1533	    continue;
1534	}
1535
1536	memset (&mon_rec, '\0', sizeof (mon_rec));
1537
1538	conf_monitor = output->conf_monitor;
1539
1540	if (conf_monitor)
1541	{
1542	    int	i;
1543
1544	    for (i = 0; i < conf_monitor->mon_n_hsync; i++)
1545	    {
1546		mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo;
1547		mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi;
1548		mon_rec.nHsync++;
1549		sync_source = sync_config;
1550	    }
1551	    for (i = 0; i < conf_monitor->mon_n_vrefresh; i++)
1552	    {
1553		mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo;
1554		mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi;
1555		mon_rec.nVrefresh++;
1556		sync_source = sync_config;
1557	    }
1558	    config_modes = xf86GetMonitorModes (scrn, conf_monitor);
1559	}
1560
1561	output_modes = (*output->funcs->get_modes) (output);
1562
1563	edid_monitor = output->MonInfo;
1564
1565	if (edid_monitor)
1566	{
1567	    int			    i;
1568	    Bool		    set_hsync = mon_rec.nHsync == 0;
1569	    Bool		    set_vrefresh = mon_rec.nVrefresh == 0;
1570	    struct disp_features    *features = &edid_monitor->features;
1571
1572	    /* if display is not continuous-frequency, don't add default modes */
1573	    if (!GTF_SUPPORTED(features->msc))
1574		add_default_modes = FALSE;
1575
1576	    for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++)
1577	    {
1578		if (edid_monitor->det_mon[i].type == DS_RANGES)
1579		{
1580		    struct monitor_ranges   *ranges = &edid_monitor->det_mon[i].section.ranges;
1581		    if (set_hsync && ranges->max_h)
1582		    {
1583			mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h;
1584			mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h;
1585			mon_rec.nHsync++;
1586			if (sync_source == sync_default)
1587			    sync_source = sync_edid;
1588		    }
1589		    if (set_vrefresh && ranges->max_v)
1590		    {
1591			mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v;
1592			mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v;
1593			mon_rec.nVrefresh++;
1594			if (sync_source == sync_default)
1595			    sync_source = sync_edid;
1596		    }
1597		    if (ranges->max_clock * 1000 > max_clock)
1598			max_clock = ranges->max_clock * 1000;
1599		}
1600	    }
1601	}
1602
1603	if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK,
1604			       OPTUNITS_KHZ, &clock))
1605	    min_clock = (int) clock;
1606	if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK,
1607			       OPTUNITS_KHZ, &clock))
1608	    max_clock = (int) clock;
1609
1610	/* If we still don't have a sync range, guess wildly */
1611	if (!mon_rec.nHsync || !mon_rec.nVrefresh)
1612	    GuessRangeFromModes(&mon_rec, output_modes);
1613
1614	/*
1615	 * These limits will end up setting a 1024x768@60Hz mode by default,
1616	 * which seems like a fairly good mode to use when nothing else is
1617	 * specified
1618	 */
1619	if (mon_rec.nHsync == 0)
1620	{
1621	    mon_rec.hsync[0].lo = 31.0;
1622	    mon_rec.hsync[0].hi = 55.0;
1623	    mon_rec.nHsync = 1;
1624	}
1625	if (mon_rec.nVrefresh == 0)
1626	{
1627	    mon_rec.vrefresh[0].lo = 58.0;
1628	    mon_rec.vrefresh[0].hi = 62.0;
1629	    mon_rec.nVrefresh = 1;
1630	}
1631
1632	if (add_default_modes)
1633	    default_modes = xf86GetDefaultModes (output->interlaceAllowed,
1634						 output->doubleScanAllowed);
1635
1636	/*
1637	 * If this is not an RB monitor, remove RB modes from the default
1638	 * pool.  RB modes from the config or the monitor itself are fine.
1639	 */
1640	if (!mon_rec.reducedblanking)
1641	    xf86ValidateModesReducedBlanking (scrn, default_modes);
1642
1643	if (sync_source == sync_config)
1644	{
1645	    /*
1646	     * Check output and config modes against sync range from config file
1647	     */
1648	    xf86ValidateModesSync (scrn, output_modes, &mon_rec);
1649	    xf86ValidateModesSync (scrn, config_modes, &mon_rec);
1650	}
1651	/*
1652	 * Check default modes against sync range
1653	 */
1654        xf86ValidateModesSync (scrn, default_modes, &mon_rec);
1655	/*
1656	 * Check default modes against monitor max clock
1657	 */
1658	if (max_clock) {
1659	    xf86ValidateModesClocks(scrn, default_modes,
1660				    &min_clock, &max_clock, 1);
1661	    xf86ValidateModesClocks(scrn, output_modes,
1662				    &min_clock, &max_clock, 1);
1663	}
1664
1665	output->probed_modes = NULL;
1666	output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes);
1667	output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes);
1668	output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes);
1669
1670	/*
1671	 * Check all modes against max size
1672	 */
1673	if (maxX && maxY)
1674	    xf86ValidateModesSize (scrn, output->probed_modes,
1675				       maxX, maxY, 0);
1676
1677	/*
1678	 * Check all modes against output
1679	 */
1680	for (mode = output->probed_modes; mode != NULL; mode = mode->next)
1681	    if (mode->status == MODE_OK)
1682		mode->status = (*output->funcs->mode_valid)(output, mode);
1683
1684	xf86PruneInvalidModes(scrn, &output->probed_modes,
1685			      config->debug_modes);
1686
1687	output->probed_modes = xf86SortModes (output->probed_modes);
1688
1689	/* Check for a configured preference for a particular mode */
1690	preferred_mode = preferredMode(scrn, output);
1691
1692	if (preferred_mode)
1693	{
1694	    for (mode = output->probed_modes; mode; mode = mode->next)
1695	    {
1696		if (!strcmp (preferred_mode, mode->name))
1697		{
1698		    if (mode != output->probed_modes)
1699		    {
1700			if (mode->prev)
1701			    mode->prev->next = mode->next;
1702			if (mode->next)
1703			    mode->next->prev = mode->prev;
1704			mode->next = output->probed_modes;
1705			output->probed_modes->prev = mode;
1706			mode->prev = NULL;
1707			output->probed_modes = mode;
1708		    }
1709		    mode->type |= (M_T_PREFERRED|M_T_USERPREF);
1710		    break;
1711		}
1712	    }
1713	}
1714
1715	output->initial_rotation = xf86OutputInitialRotation (output);
1716
1717	if (config->debug_modes) {
1718	    if (output->probed_modes != NULL) {
1719		xf86DrvMsg(scrn->scrnIndex, X_INFO,
1720			   "Printing probed modes for output %s\n",
1721			   output->name);
1722	    } else {
1723		xf86DrvMsg(scrn->scrnIndex, X_INFO,
1724			   "No remaining probed modes for output %s\n",
1725			   output->name);
1726	    }
1727	}
1728	for (mode = output->probed_modes; mode != NULL; mode = mode->next)
1729	{
1730	    /* The code to choose the best mode per pipe later on will require
1731	     * VRefresh to be set.
1732	     */
1733	    mode->VRefresh = xf86ModeVRefresh(mode);
1734	    xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
1735
1736	    if (config->debug_modes)
1737		xf86PrintModeline(scrn->scrnIndex, mode);
1738	}
1739    }
1740}
1741
1742
1743/**
1744 * Copy one of the output mode lists to the ScrnInfo record
1745 */
1746
1747/* XXX where does this function belong? Here? */
1748_X_EXPORT void
1749xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y);
1750
1751static DisplayModePtr
1752biggestMode(DisplayModePtr a, DisplayModePtr b)
1753{
1754    int A, B;
1755
1756    if (!a)
1757	return b;
1758    if (!b)
1759	return a;
1760
1761    A = a->HDisplay * a->VDisplay;
1762    B = b->HDisplay * b->VDisplay;
1763
1764    if (A > B)
1765	return a;
1766
1767    return b;
1768}
1769
1770static xf86OutputPtr
1771SetCompatOutput(xf86CrtcConfigPtr config)
1772{
1773    xf86OutputPtr output = NULL, test = NULL;
1774    DisplayModePtr maxmode = NULL, testmode, mode;
1775    int o, compat = -1, count, mincount = 0;
1776
1777    /* Look for one that's definitely connected */
1778    for (o = 0; o < config->num_output; o++)
1779    {
1780	test = config->output[o];
1781	if (!test->crtc)
1782	    continue;
1783	if (test->status != XF86OutputStatusConnected)
1784	    continue;
1785	if (!test->probed_modes)
1786	    continue;
1787
1788	testmode = mode = test->probed_modes;
1789	for (count = 0; mode; mode = mode->next, count++)
1790	    testmode = biggestMode(testmode, mode);
1791
1792	if (!output) {
1793	    output = test;
1794	    compat = o;
1795	    maxmode = testmode;
1796	    mincount = count;
1797	} else if (maxmode == biggestMode(maxmode, testmode)) {
1798	    output = test;
1799	    compat = o;
1800	    maxmode = testmode;
1801	    mincount = count;
1802	} else if ((maxmode->HDisplay == testmode->HDisplay) &&
1803		(maxmode->VDisplay == testmode->VDisplay) &&
1804		count <= mincount) {
1805	    output = test;
1806	    compat = o;
1807	    maxmode = testmode;
1808	    mincount = count;
1809	}
1810    }
1811
1812    /* If we didn't find one, take anything we can get */
1813    if (!output)
1814    {
1815	for (o = 0; o < config->num_output; o++)
1816	{
1817	    test = config->output[o];
1818	    if (!test->crtc)
1819		continue;
1820	    if (!test->probed_modes)
1821		continue;
1822
1823	    if (!output) {
1824		output = test;
1825		compat = o;
1826	    } else if (test->probed_modes->HDisplay < output->probed_modes->HDisplay) {
1827		output = test;
1828		compat = o;
1829	    }
1830	}
1831    }
1832
1833    if (compat >= 0) {
1834	config->compat_output = compat;
1835    } else {
1836	/* Don't change the compat output when no valid outputs found */
1837	output = config->output[config->compat_output];
1838    }
1839
1840    return output;
1841}
1842
1843_X_EXPORT void
1844xf86SetScrnInfoModes (ScrnInfoPtr scrn)
1845{
1846    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
1847    xf86OutputPtr	output;
1848    xf86CrtcPtr		crtc;
1849    DisplayModePtr	last, mode = NULL;
1850
1851    output = SetCompatOutput(config);
1852
1853    if (!output)
1854	return; /* punt */
1855
1856    crtc = output->crtc;
1857
1858    /* Clear any existing modes from scrn->modes */
1859    while (scrn->modes != NULL)
1860	xf86DeleteMode(&scrn->modes, scrn->modes);
1861
1862    /* Set scrn->modes to the mode list for the 'compat' output */
1863    scrn->modes = xf86DuplicateModes(scrn, output->probed_modes);
1864
1865    if (crtc) {
1866	for (mode = scrn->modes; mode; mode = mode->next)
1867	    if (xf86ModesEqual (mode, &crtc->desiredMode))
1868		break;
1869    }
1870
1871    if (scrn->modes != NULL) {
1872	/* For some reason, scrn->modes is circular, unlike the other mode
1873	 * lists.  How great is that?
1874	 */
1875	for (last = scrn->modes; last && last->next; last = last->next)
1876	    ;
1877	last->next = scrn->modes;
1878	scrn->modes->prev = last;
1879	if (mode) {
1880	    while (scrn->modes != mode)
1881		scrn->modes = scrn->modes->next;
1882	}
1883    }
1884    scrn->currentMode = scrn->modes;
1885}
1886
1887static void
1888xf86EnableOutputs(ScrnInfoPtr scrn, xf86CrtcConfigPtr config, Bool *enabled)
1889{
1890    Bool any_enabled = FALSE;
1891    int o;
1892
1893    for (o = 0; o < config->num_output; o++)
1894	any_enabled |= enabled[o] = xf86OutputEnabled(config->output[o], TRUE);
1895
1896    if (!any_enabled) {
1897	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1898		   "No outputs definitely connected, trying again...\n");
1899
1900	for (o = 0; o < config->num_output; o++)
1901	    enabled[o] = xf86OutputEnabled(config->output[o], FALSE);
1902    }
1903}
1904
1905static Bool
1906nextEnabledOutput(xf86CrtcConfigPtr config, Bool *enabled, int *index)
1907{
1908    int o = *index;
1909
1910    for (o++; o < config->num_output; o++) {
1911	if (enabled[o]) {
1912	    *index = o;
1913	    return TRUE;
1914	}
1915    }
1916
1917    return FALSE;
1918}
1919
1920static Bool
1921aspectMatch(float a, float b)
1922{
1923    return fabs(1 - (a / b)) < 0.05;
1924}
1925
1926static DisplayModePtr
1927nextAspectMode(xf86OutputPtr o, DisplayModePtr last, float aspect)
1928{
1929    DisplayModePtr m = NULL;
1930
1931    if (!o)
1932	return NULL;
1933
1934    if (!last)
1935	m = o->probed_modes;
1936    else
1937	m = last->next;
1938
1939    for (; m; m = m->next)
1940	if (aspectMatch(aspect, (float)m->HDisplay / (float)m->VDisplay))
1941	    return m;
1942
1943    return NULL;
1944}
1945
1946static DisplayModePtr
1947bestModeForAspect(xf86CrtcConfigPtr config, Bool *enabled, float aspect)
1948{
1949    int o = -1, p;
1950    DisplayModePtr mode = NULL, test = NULL, match = NULL;
1951
1952    if (!nextEnabledOutput(config, enabled, &o))
1953	return NULL;
1954    while ((mode = nextAspectMode(config->output[o], mode, aspect))) {
1955	test = mode;
1956	for (p = o; nextEnabledOutput(config, enabled, &p); ) {
1957	    test = xf86OutputFindClosestMode(config->output[p], mode);
1958	    if (!test)
1959		break;
1960	    if (test->HDisplay != mode->HDisplay ||
1961		    test->VDisplay != mode->VDisplay) {
1962		test = NULL;
1963		break;
1964	    }
1965	}
1966
1967	/* if we didn't match it on all outputs, try the next one */
1968	if (!test)
1969	    continue;
1970
1971	/* if it's bigger than the last one, save it */
1972	if (!match || (test->HDisplay > match->HDisplay))
1973	    match = test;
1974    }
1975
1976    /* return the biggest one found */
1977    return match;
1978}
1979
1980static Bool
1981xf86TargetPreferred(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
1982		    DisplayModePtr *modes, Bool *enabled,
1983		    int width, int height)
1984{
1985    int o, p;
1986    int max_pref_width = 0, max_pref_height = 0;
1987    DisplayModePtr *preferred, *preferred_match;
1988    Bool ret = FALSE;
1989
1990    preferred = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
1991    preferred_match = xnfcalloc(config->num_output, sizeof(DisplayModePtr));
1992
1993    /* Check if the preferred mode is available on all outputs */
1994    for (p = -1; nextEnabledOutput(config, enabled, &p); ) {
1995	Rotation r = config->output[p]->initial_rotation;
1996	DisplayModePtr mode;
1997	if ((preferred[p] = xf86OutputHasPreferredMode(config->output[p],
1998			width, height))) {
1999	    int pref_width = xf86ModeWidth(preferred[p], r);
2000	    int pref_height = xf86ModeHeight(preferred[p], r);
2001	    Bool all_match = TRUE;
2002
2003	    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2004		Bool match = FALSE;
2005		xf86OutputPtr output = config->output[o];
2006		if (o == p)
2007		    continue;
2008
2009		for (mode = output->probed_modes; mode; mode = mode->next) {
2010		    Rotation r = output->initial_rotation;
2011		    if (xf86ModeWidth(mode, r) == pref_width &&
2012			    xf86ModeHeight(mode, r) == pref_height) {
2013			preferred[o] = mode;
2014			match = TRUE;
2015		    }
2016		}
2017
2018		all_match &= match;
2019	    }
2020
2021	    if (all_match &&
2022		    (pref_width*pref_height > max_pref_width*max_pref_height)) {
2023		for (o = -1; nextEnabledOutput(config, enabled, &o); )
2024		    preferred_match[o] = preferred[o];
2025		max_pref_width = pref_width;
2026		max_pref_height = pref_height;
2027		ret = TRUE;
2028	    }
2029	}
2030    }
2031
2032    /*
2033     * If there's no preferred mode, but only one monitor, pick the
2034     * biggest mode for its aspect ratio, assuming one exists.
2035     */
2036    if (!ret) do {
2037	int i = 0;
2038	float aspect = 0.0;
2039
2040	/* count the number of enabled outputs */
2041	for (i = 0, p = -1; nextEnabledOutput(config, enabled, &p); i++) ;
2042
2043	if (i != 1)
2044	    break;
2045
2046	p = -1;
2047	nextEnabledOutput(config, enabled, &p);
2048	if (config->output[p]->mm_height)
2049	    aspect = (float)config->output[p]->mm_width /
2050		     (float)config->output[p]->mm_height;
2051
2052	if (aspect)
2053	    preferred_match[p] = bestModeForAspect(config, enabled, aspect);
2054
2055	if (preferred_match[p])
2056	    ret = TRUE;
2057
2058    } while (0);
2059
2060    if (ret) {
2061	/* oh good, there is a match.  stash the selected modes and return. */
2062	memcpy(modes, preferred_match,
2063		config->num_output * sizeof(DisplayModePtr));
2064    }
2065
2066    xfree(preferred);
2067    xfree(preferred_match);
2068    return ret;
2069}
2070
2071static Bool
2072xf86TargetAspect(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2073		 DisplayModePtr *modes, Bool *enabled,
2074		 int width, int height)
2075{
2076    int o;
2077    float aspect = 0.0, *aspects;
2078    xf86OutputPtr output;
2079    Bool ret = FALSE;
2080    DisplayModePtr guess = NULL, aspect_guess = NULL, base_guess = NULL;
2081
2082    aspects = xnfcalloc(config->num_output, sizeof(float));
2083
2084    /* collect the aspect ratios */
2085    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2086	output = config->output[o];
2087	if (output->mm_height)
2088	    aspects[o] = (float)output->mm_width / (float)output->mm_height;
2089	else
2090	    aspects[o] = 4.0 / 3.0;
2091    }
2092
2093    /* check that they're all the same */
2094    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2095	output = config->output[o];
2096	if (!aspect) {
2097	    aspect = aspects[o];
2098	} else if (!aspectMatch(aspect, aspects[o])) {
2099	    goto no_aspect_match;
2100	}
2101    }
2102
2103    /* if they're all 4:3, just skip ahead and save effort */
2104    if (!aspectMatch(aspect, 4.0/3.0))
2105	aspect_guess = bestModeForAspect(config, enabled, aspect);
2106
2107no_aspect_match:
2108    base_guess = bestModeForAspect(config, enabled, 4.0/3.0);
2109
2110    guess = biggestMode(base_guess, aspect_guess);
2111
2112    if (!guess)
2113	goto out;
2114
2115    /* found a mode that works everywhere, now apply it */
2116    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2117	modes[o] = xf86OutputFindClosestMode(config->output[o], guess);
2118    }
2119    ret = TRUE;
2120
2121out:
2122    xfree(aspects);
2123    return ret;
2124}
2125
2126static Bool
2127xf86TargetFallback(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2128		   DisplayModePtr *modes, Bool *enabled,
2129		   int width, int height)
2130{
2131    DisplayModePtr target_mode = NULL;
2132    Rotation target_rotation = RR_Rotate_0;
2133    DisplayModePtr default_mode;
2134    int default_preferred, target_preferred = 0, o;
2135
2136    /* User preferred > preferred > other modes */
2137    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2138	default_mode = xf86DefaultMode (config->output[o], width, height);
2139	if (!default_mode)
2140	    continue;
2141
2142	default_preferred = (((default_mode->type & M_T_PREFERRED) != 0) +
2143		((default_mode->type & M_T_USERPREF) != 0));
2144
2145	if (default_preferred > target_preferred || !target_mode) {
2146	    target_mode = default_mode;
2147	    target_preferred = default_preferred;
2148	    target_rotation = config->output[o]->initial_rotation;
2149	    config->compat_output = o;
2150	}
2151    }
2152
2153    if (target_mode)
2154	modes[config->compat_output] = target_mode;
2155
2156    /* Fill in other output modes */
2157    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2158	if (!modes[o])
2159	    modes[o] = xf86ClosestMode(config->output[o], target_mode,
2160				       target_rotation, width, height);
2161    }
2162
2163    return (target_mode != NULL);
2164}
2165
2166static Bool
2167xf86TargetUserpref(ScrnInfoPtr scrn, xf86CrtcConfigPtr config,
2168		   DisplayModePtr *modes, Bool *enabled,
2169		   int width, int height)
2170{
2171    int o;
2172
2173    if (xf86UserConfiguredOutputs(scrn, modes))
2174	return xf86TargetFallback(scrn, config, modes, enabled, width, height);
2175
2176    for (o = -1; nextEnabledOutput(config, enabled, &o); )
2177	if (xf86OutputHasUserPreferredMode(config->output[o]))
2178	    return
2179		xf86TargetFallback(scrn, config, modes, enabled, width, height);
2180
2181    return FALSE;
2182}
2183
2184
2185/**
2186 * Construct default screen configuration
2187 *
2188 * Given auto-detected (and, eventually, configured) values,
2189 * construct a usable configuration for the system
2190 *
2191 * canGrow indicates that the driver can resize the screen to larger than its
2192 * initially configured size via the config->funcs->resize hook.  If TRUE, this
2193 * function will set virtualX and virtualY to match the initial configuration
2194 * and leave config->max{Width,Height} alone.  If FALSE, it will bloat
2195 * virtual[XY] to include the largest modes and set config->max{Width,Height}
2196 * accordingly.
2197 */
2198
2199_X_EXPORT Bool
2200xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow)
2201{
2202    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
2203    int			o, c;
2204    xf86CrtcPtr		*crtcs;
2205    DisplayModePtr	*modes;
2206    Bool		*enabled;
2207    int			width, height;
2208    int			i = scrn->scrnIndex;
2209
2210    /* Set up the device options */
2211    config->options = xnfalloc (sizeof (xf86DeviceOptions));
2212    memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions));
2213    xf86ProcessOptions (scrn->scrnIndex,
2214			scrn->options,
2215			config->options);
2216    config->debug_modes = xf86ReturnOptValBool (config->options,
2217						OPTION_MODEDEBUG, FALSE);
2218
2219    if (scrn->display->virtualX)
2220	width = scrn->display->virtualX;
2221    else
2222	width = config->maxWidth;
2223    if (scrn->display->virtualY)
2224	height = scrn->display->virtualY;
2225    else
2226	height = config->maxHeight;
2227
2228    xf86ProbeOutputModes (scrn, width, height);
2229
2230    crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr));
2231    modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr));
2232    enabled = xnfcalloc (config->num_output, sizeof (Bool));
2233
2234    xf86EnableOutputs(scrn, config, enabled);
2235
2236    if (xf86TargetUserpref(scrn, config, modes, enabled, width, height))
2237	xf86DrvMsg(i, X_INFO, "Using user preference for initial modes\n");
2238    else if (xf86TargetPreferred(scrn, config, modes, enabled, width, height))
2239	xf86DrvMsg(i, X_INFO, "Using exact sizes for initial modes\n");
2240    else if (xf86TargetAspect(scrn, config, modes, enabled, width, height))
2241	xf86DrvMsg(i, X_INFO, "Using fuzzy aspect match for initial modes\n");
2242    else if (xf86TargetFallback(scrn, config, modes, enabled, width, height))
2243	xf86DrvMsg(i, X_INFO, "Using sloppy heuristic for initial modes\n");
2244    else
2245	xf86DrvMsg(i, X_WARNING, "Unable to find initial modes\n");
2246
2247    for (o = -1; nextEnabledOutput(config, enabled, &o); ) {
2248	if (!modes[o])
2249	    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
2250			"Output %s enabled but has no modes\n",
2251			config->output[o]->name);
2252	else
2253	    xf86DrvMsg (scrn->scrnIndex, X_INFO,
2254			"Output %s using initial mode %s\n",
2255			config->output[o]->name, modes[o]->name);
2256    }
2257
2258    /*
2259     * Set the position of each output
2260     */
2261    if (!xf86InitialOutputPositions (scrn, modes))
2262    {
2263	xfree (crtcs);
2264	xfree (modes);
2265	return FALSE;
2266    }
2267
2268    /*
2269     * Set initial panning of each output
2270     */
2271    xf86InitialPanning (scrn);
2272
2273    /*
2274     * Assign CRTCs to fit output configuration
2275     */
2276    if (!xf86PickCrtcs (scrn, crtcs, modes, 0, width, height))
2277    {
2278	xfree (crtcs);
2279	xfree (modes);
2280	return FALSE;
2281    }
2282
2283    /* XXX override xf86 common frame computation code */
2284
2285    scrn->display->frameX0 = 0;
2286    scrn->display->frameY0 = 0;
2287
2288    for (c = 0; c < config->num_crtc; c++)
2289    {
2290	xf86CrtcPtr	crtc = config->crtc[c];
2291
2292	crtc->enabled = FALSE;
2293	memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode));
2294    }
2295
2296    /*
2297     * Set initial configuration
2298     */
2299    for (o = 0; o < config->num_output; o++)
2300    {
2301	xf86OutputPtr	output = config->output[o];
2302	DisplayModePtr	mode = modes[o];
2303        xf86CrtcPtr	crtc = crtcs[o];
2304
2305	if (mode && crtc)
2306	{
2307	    crtc->desiredMode = *mode;
2308	    crtc->desiredRotation = output->initial_rotation;
2309	    crtc->desiredX = output->initial_x;
2310	    crtc->desiredY = output->initial_y;
2311	    crtc->desiredTransformPresent = FALSE;
2312	    crtc->enabled = TRUE;
2313	    crtc->x = output->initial_x;
2314	    crtc->y = output->initial_y;
2315	    memcpy (&crtc->panningTotalArea,    &output->initialTotalArea,    sizeof(BoxRec));
2316	    memcpy (&crtc->panningTrackingArea, &output->initialTrackingArea, sizeof(BoxRec));
2317	    memcpy (crtc->panningBorder,        output->initialBorder,        4*sizeof(INT16));
2318	    output->crtc = crtc;
2319	} else {
2320	    output->crtc = NULL;
2321	}
2322    }
2323
2324    if (scrn->display->virtualX == 0)
2325    {
2326	/*
2327	 * Expand virtual size to cover the current config and potential mode
2328	 * switches, if the driver can't enlarge the screen later.
2329	 */
2330	xf86DefaultScreenLimits (scrn, &width, &height, canGrow);
2331
2332	scrn->display->virtualX = width;
2333	scrn->display->virtualY = height;
2334    }
2335
2336    if (width > scrn->virtualX)
2337	scrn->virtualX = width;
2338    if (height > scrn->virtualY)
2339	scrn->virtualY = height;
2340
2341    /*
2342     * Make sure the configuration isn't too small.
2343     */
2344    if (width < config->minWidth || height < config->minHeight)
2345	return FALSE;
2346
2347    /*
2348     * Limit the crtc config to virtual[XY] if the driver can't grow the
2349     * desktop.
2350     */
2351    if (!canGrow)
2352    {
2353	xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight,
2354			      width, height);
2355    }
2356
2357    /* Mirror output modes to scrn mode list */
2358    xf86SetScrnInfoModes (scrn);
2359
2360    xfree (crtcs);
2361    xfree (modes);
2362    return TRUE;
2363}
2364
2365/*
2366 * Check the CRTC we're going to map each output to vs. it's current
2367 * CRTC.  If they don't match, we have to disable the output and the CRTC
2368 * since the driver will have to re-route things.
2369 */
2370static void
2371xf86PrepareOutputs (ScrnInfoPtr scrn)
2372{
2373    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(scrn);
2374    int			o;
2375
2376    for (o = 0; o < config->num_output; o++) {
2377	xf86OutputPtr output = config->output[o];
2378#if RANDR_GET_CRTC_INTERFACE
2379	/* Disable outputs that are unused or will be re-routed */
2380	if (!output->funcs->get_crtc ||
2381	    output->crtc != (*output->funcs->get_crtc)(output) ||
2382	    output->crtc == NULL)
2383#endif
2384	    (*output->funcs->dpms)(output, DPMSModeOff);
2385    }
2386}
2387
2388static void
2389xf86PrepareCrtcs (ScrnInfoPtr scrn)
2390{
2391    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(scrn);
2392    int			c;
2393
2394    for (c = 0; c < config->num_crtc; c++) {
2395#if RANDR_GET_CRTC_INTERFACE
2396	xf86CrtcPtr	crtc = config->crtc[c];
2397	xf86OutputPtr	output = NULL;
2398	uint32_t	desired_outputs = 0, current_outputs = 0;
2399	int		o;
2400
2401	for (o = 0; o < config->num_output; o++) {
2402	    output = config->output[o];
2403	    if (output->crtc == crtc)
2404		desired_outputs |= (1<<o);
2405	    /* If we can't tell where it's mapped, force it off */
2406	    if (!output->funcs->get_crtc) {
2407		desired_outputs = 0;
2408		break;
2409	    }
2410	    if ((*output->funcs->get_crtc)(output) == crtc)
2411		current_outputs |= (1<<o);
2412	}
2413
2414	/*
2415	 * If mappings are different or the CRTC is unused,
2416	 * we need to disable it
2417	 */
2418	if (desired_outputs != current_outputs ||
2419	    !desired_outputs)
2420	    (*crtc->funcs->dpms)(crtc, DPMSModeOff);
2421#else
2422	(*crtc->funcs->dpms)(crtc, DPMSModeOff);
2423#endif
2424    }
2425}
2426
2427/*
2428 * Using the desired mode information in each crtc, set
2429 * modes (used in EnterVT functions, or at server startup)
2430 */
2431
2432_X_EXPORT Bool
2433xf86SetDesiredModes (ScrnInfoPtr scrn)
2434{
2435    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(scrn);
2436    xf86CrtcPtr         crtc = config->crtc[0];
2437    int			c;
2438
2439    /* A driver with this hook will take care of this */
2440    if (!crtc->funcs->set_mode_major) {
2441	xf86PrepareOutputs(scrn);
2442	xf86PrepareCrtcs(scrn);
2443    }
2444
2445    for (c = 0; c < config->num_crtc; c++)
2446    {
2447	xf86OutputPtr	output = NULL;
2448	int		o;
2449	RRTransformPtr	transform;
2450
2451	crtc = config->crtc[c];
2452
2453	/* Skip disabled CRTCs */
2454	if (!crtc->enabled)
2455	    continue;
2456
2457	if (config->output[config->compat_output]->crtc == crtc)
2458	    output = config->output[config->compat_output];
2459	else
2460	{
2461	    for (o = 0; o < config->num_output; o++)
2462		if (config->output[o]->crtc == crtc)
2463		{
2464		    output = config->output[o];
2465		    break;
2466		}
2467	}
2468	/* paranoia */
2469	if (!output)
2470	    continue;
2471
2472	/* Mark that we'll need to re-set the mode for sure */
2473	memset(&crtc->mode, 0, sizeof(crtc->mode));
2474	if (!crtc->desiredMode.CrtcHDisplay)
2475	{
2476	    DisplayModePtr  mode = xf86OutputFindClosestMode (output, scrn->currentMode);
2477
2478	    if (!mode)
2479		return FALSE;
2480	    crtc->desiredMode = *mode;
2481	    crtc->desiredRotation = RR_Rotate_0;
2482	    crtc->desiredTransformPresent = FALSE;
2483	    crtc->desiredX = 0;
2484	    crtc->desiredY = 0;
2485	}
2486
2487	if (crtc->desiredTransformPresent)
2488	    transform = &crtc->desiredTransform;
2489	else
2490	    transform = NULL;
2491	if (!xf86CrtcSetModeTransform (crtc, &crtc->desiredMode, crtc->desiredRotation,
2492				       transform, crtc->desiredX, crtc->desiredY))
2493	    return FALSE;
2494    }
2495
2496    xf86DisableUnusedFunctions(scrn);
2497    return TRUE;
2498}
2499
2500/**
2501 * In the current world order, there are lists of modes per output, which may
2502 * or may not include the mode that was asked to be set by XFree86's mode
2503 * selection.  Find the closest one, in the following preference order:
2504 *
2505 * - Equality
2506 * - Closer in size to the requested mode, but no larger
2507 * - Closer in refresh rate to the requested mode.
2508 */
2509
2510_X_EXPORT DisplayModePtr
2511xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired)
2512{
2513    DisplayModePtr	best = NULL, scan = NULL;
2514
2515    for (scan = output->probed_modes; scan != NULL; scan = scan->next)
2516    {
2517	/* If there's an exact match, we're done. */
2518	if (xf86ModesEqual(scan, desired)) {
2519	    best = desired;
2520	    break;
2521	}
2522
2523	/* Reject if it's larger than the desired mode. */
2524	if (scan->HDisplay > desired->HDisplay ||
2525	    scan->VDisplay > desired->VDisplay)
2526	{
2527	    continue;
2528	}
2529
2530	/*
2531	 * If we haven't picked a best mode yet, use the first
2532	 * one in the size range
2533	 */
2534	if (best == NULL)
2535	{
2536	    best = scan;
2537	    continue;
2538	}
2539
2540	/* Find if it's closer to the right size than the current best
2541	 * option.
2542	 */
2543	if ((scan->HDisplay > best->HDisplay &&
2544	     scan->VDisplay >= best->VDisplay) ||
2545	    (scan->HDisplay >= best->HDisplay &&
2546	     scan->VDisplay > best->VDisplay))
2547	{
2548	    best = scan;
2549	    continue;
2550	}
2551
2552	/* Find if it's still closer to the right refresh than the current
2553	 * best resolution.
2554	 */
2555	if (scan->HDisplay == best->HDisplay &&
2556	    scan->VDisplay == best->VDisplay &&
2557	    (fabs(scan->VRefresh - desired->VRefresh) <
2558	     fabs(best->VRefresh - desired->VRefresh))) {
2559	    best = scan;
2560	}
2561    }
2562    return best;
2563}
2564
2565/**
2566 * When setting a mode through XFree86-VidModeExtension or XFree86-DGA,
2567 * take the specified mode and apply it to the crtc connected to the compat
2568 * output. Then, find similar modes for the other outputs, as with the
2569 * InitialConfiguration code above. The goal is to clone the desired
2570 * mode across all outputs that are currently active.
2571 */
2572
2573_X_EXPORT Bool
2574xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation)
2575{
2576    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
2577    Bool		ok = TRUE;
2578    xf86OutputPtr	compat_output = config->output[config->compat_output];
2579    DisplayModePtr	compat_mode;
2580    int			c;
2581
2582    /*
2583     * Let the compat output drive the final mode selection
2584     */
2585    compat_mode = xf86OutputFindClosestMode (compat_output, desired);
2586    if (compat_mode)
2587	desired = compat_mode;
2588
2589    for (c = 0; c < config->num_crtc; c++)
2590    {
2591	xf86CrtcPtr	crtc = config->crtc[c];
2592	DisplayModePtr	crtc_mode = NULL;
2593	int		o;
2594
2595	if (!crtc->enabled)
2596	    continue;
2597
2598	for (o = 0; o < config->num_output; o++)
2599	{
2600	    xf86OutputPtr   output = config->output[o];
2601	    DisplayModePtr  output_mode;
2602
2603	    /* skip outputs not on this crtc */
2604	    if (output->crtc != crtc)
2605		continue;
2606
2607	    if (crtc_mode)
2608	    {
2609		output_mode = xf86OutputFindClosestMode (output, crtc_mode);
2610		if (output_mode != crtc_mode)
2611		    output->crtc = NULL;
2612	    }
2613	    else
2614		crtc_mode = xf86OutputFindClosestMode (output, desired);
2615	}
2616	if (!crtc_mode)
2617	{
2618	    crtc->enabled = FALSE;
2619	    continue;
2620	}
2621	if (!xf86CrtcSetModeTransform (crtc, crtc_mode, rotation, NULL, 0, 0))
2622	    ok = FALSE;
2623	else
2624	{
2625	    crtc->desiredMode = *crtc_mode;
2626	    crtc->desiredRotation = rotation;
2627	    crtc->desiredTransformPresent = FALSE;
2628	    crtc->desiredX = 0;
2629	    crtc->desiredY = 0;
2630	}
2631    }
2632    xf86DisableUnusedFunctions(pScrn);
2633#ifdef RANDR_12_INTERFACE
2634    xf86RandR12TellChanged (pScrn->pScreen);
2635#endif
2636    return ok;
2637}
2638
2639
2640/**
2641 * Set the DPMS power mode of all outputs and CRTCs.
2642 *
2643 * If the new mode is off, it will turn off outputs and then CRTCs.
2644 * Otherwise, it will affect CRTCs before outputs.
2645 */
2646_X_EXPORT void
2647xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags)
2648{
2649    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
2650    int			i;
2651
2652    if (!scrn->vtSema)
2653	return;
2654
2655    if (mode == DPMSModeOff) {
2656	for (i = 0; i < config->num_output; i++) {
2657	    xf86OutputPtr output = config->output[i];
2658	    if (output->crtc != NULL)
2659		(*output->funcs->dpms) (output, mode);
2660	}
2661    }
2662
2663    for (i = 0; i < config->num_crtc; i++) {
2664	xf86CrtcPtr crtc = config->crtc[i];
2665	if (crtc->enabled)
2666	    (*crtc->funcs->dpms) (crtc, mode);
2667    }
2668
2669    if (mode != DPMSModeOff) {
2670	for (i = 0; i < config->num_output; i++) {
2671	    xf86OutputPtr output = config->output[i];
2672	    if (output->crtc != NULL)
2673		(*output->funcs->dpms) (output, mode);
2674	}
2675    }
2676}
2677
2678/**
2679 * Implement the screensaver by just calling down into the driver DPMS hooks.
2680 *
2681 * Even for monitors with no DPMS support, by the definition of our DPMS hooks,
2682 * the outputs will still get disabled (blanked).
2683 */
2684_X_EXPORT Bool
2685xf86SaveScreen(ScreenPtr pScreen, int mode)
2686{
2687    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2688
2689    if (xf86IsUnblank(mode))
2690	xf86DPMSSet(pScrn, DPMSModeOn, 0);
2691    else
2692	xf86DPMSSet(pScrn, DPMSModeOff, 0);
2693
2694    return TRUE;
2695}
2696
2697/**
2698 * Disable all inactive crtcs and outputs
2699 */
2700_X_EXPORT void
2701xf86DisableUnusedFunctions(ScrnInfoPtr pScrn)
2702{
2703    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2704    int			o, c;
2705
2706    for (o = 0; o < xf86_config->num_output; o++)
2707    {
2708	xf86OutputPtr  output = xf86_config->output[o];
2709	if (!output->crtc)
2710	    (*output->funcs->dpms)(output, DPMSModeOff);
2711    }
2712
2713    for (c = 0; c < xf86_config->num_crtc; c++)
2714    {
2715	xf86CrtcPtr crtc = xf86_config->crtc[c];
2716
2717	if (!crtc->enabled)
2718	{
2719	    crtc->funcs->dpms(crtc, DPMSModeOff);
2720	    memset(&crtc->mode, 0, sizeof(crtc->mode));
2721	    xf86RotateDestroy(crtc);
2722	}
2723    }
2724    if (pScrn->pScreen)
2725	xf86_crtc_notify(pScrn->pScreen);
2726}
2727
2728#ifdef RANDR_12_INTERFACE
2729
2730#define EDID_ATOM_NAME		"EDID_DATA"
2731
2732/**
2733 * Set the RandR EDID property
2734 */
2735static void
2736xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len)
2737{
2738    Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE);
2739
2740    /* This may get called before the RandR resources have been created */
2741    if (output->randr_output == NULL)
2742	return;
2743
2744    if (data_len != 0) {
2745	RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8,
2746			       PropModeReplace, data_len, data, FALSE, TRUE);
2747    } else {
2748	RRDeleteOutputProperty(output->randr_output, edid_atom);
2749    }
2750}
2751
2752#endif
2753
2754/**
2755 * Set the EDID information for the specified output
2756 */
2757_X_EXPORT void
2758xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
2759{
2760    ScrnInfoPtr		scrn = output->scrn;
2761    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
2762    int			i;
2763#ifdef RANDR_12_INTERFACE
2764    int			size;
2765#endif
2766
2767    if (output->MonInfo != NULL)
2768	xfree(output->MonInfo);
2769
2770    output->MonInfo = edid_mon;
2771
2772    if (config->debug_modes) {
2773	xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n",
2774		   output->name);
2775	xf86PrintEDID(edid_mon);
2776    }
2777
2778    /* Set the DDC properties for the 'compat' output */
2779    if (output == config->output[config->compat_output])
2780        xf86SetDDCproperties(scrn, edid_mon);
2781
2782#ifdef RANDR_12_INTERFACE
2783    /* Set the RandR output properties */
2784    size = 0;
2785    if (edid_mon)
2786    {
2787	if (edid_mon->ver.version == 1) {
2788	    size = 128;
2789	    if (edid_mon->flags & EDID_COMPLETE_RAWDATA)
2790		size += edid_mon->no_sections * 128;
2791	} else if (edid_mon->ver.version == 2)
2792	    size = 256;
2793    }
2794    xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size);
2795#endif
2796
2797    if (edid_mon)
2798    {
2799	/* Pull out a phyiscal size from a detailed timing if available. */
2800	for (i = 0; i < 4; i++) {
2801	    if (edid_mon->det_mon[i].type == DT &&
2802		edid_mon->det_mon[i].section.d_timings.h_size != 0 &&
2803		edid_mon->det_mon[i].section.d_timings.v_size != 0)
2804	    {
2805		output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size;
2806		output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size;
2807		break;
2808	    }
2809	}
2810
2811	/* if no mm size is available from a detailed timing, check the max size field */
2812	if ((!output->mm_width || !output->mm_height) &&
2813	    (edid_mon->features.hsize && edid_mon->features.vsize))
2814	{
2815	    output->mm_width = edid_mon->features.hsize * 10;
2816	    output->mm_height = edid_mon->features.vsize * 10;
2817	}
2818    }
2819}
2820
2821/**
2822 * Return the list of modes supported by the EDID information
2823 * stored in 'output'
2824 */
2825_X_EXPORT DisplayModePtr
2826xf86OutputGetEDIDModes (xf86OutputPtr output)
2827{
2828    ScrnInfoPtr	scrn = output->scrn;
2829    xf86MonPtr	edid_mon = output->MonInfo;
2830
2831    if (!edid_mon)
2832	return NULL;
2833    return xf86DDCGetModes(scrn->scrnIndex, edid_mon);
2834}
2835
2836/* maybe we should care about DDC1?  meh. */
2837_X_EXPORT xf86MonPtr
2838xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus)
2839{
2840    ScrnInfoPtr	scrn = output->scrn;
2841    xf86MonPtr mon;
2842
2843    mon = xf86DoEEDID(scrn->scrnIndex, pDDCBus, TRUE);
2844    if (mon)
2845        xf86DDCApplyQuirks(scrn->scrnIndex, mon);
2846
2847    return mon;
2848}
2849
2850static char *_xf86ConnectorNames[] = {
2851					"None", "VGA", "DVI-I", "DVI-D",
2852					"DVI-A", "Composite", "S-Video",
2853					"Component", "LFP", "Proprietary",
2854					"HDMI", "DisplayPort",
2855				     };
2856_X_EXPORT char *
2857xf86ConnectorGetName(xf86ConnectorType connector)
2858{
2859    return _xf86ConnectorNames[connector];
2860}
2861
2862static void
2863x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
2864{
2865    dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
2866    dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
2867    dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
2868    dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
2869
2870    if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
2871	dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
2872}
2873
2874static void
2875x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
2876{
2877    if (crtc->enabled) {
2878	crtc_box->x1 = crtc->x;
2879	crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
2880	crtc_box->y1 = crtc->y;
2881	crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
2882    } else
2883	crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
2884}
2885
2886static int
2887xf86_crtc_box_area(BoxPtr box)
2888{
2889    return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
2890}
2891
2892/*
2893 * Return the crtc covering 'box'. If two crtcs cover a portion of
2894 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
2895 * with greater coverage
2896 */
2897
2898static xf86CrtcPtr
2899xf86_covering_crtc(ScrnInfoPtr pScrn,
2900		   BoxPtr      box,
2901		   xf86CrtcPtr desired,
2902		   BoxPtr      crtc_box_ret)
2903{
2904    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2905    xf86CrtcPtr		crtc, best_crtc;
2906    int			coverage, best_coverage;
2907    int			c;
2908    BoxRec		crtc_box, cover_box;
2909
2910    best_crtc = NULL;
2911    best_coverage = 0;
2912    crtc_box_ret->x1 = 0;
2913    crtc_box_ret->x2 = 0;
2914    crtc_box_ret->y1 = 0;
2915    crtc_box_ret->y2 = 0;
2916    for (c = 0; c < xf86_config->num_crtc; c++) {
2917	crtc = xf86_config->crtc[c];
2918	x86_crtc_box(crtc, &crtc_box);
2919	x86_crtc_box_intersect(&cover_box, &crtc_box, box);
2920	coverage = xf86_crtc_box_area(&cover_box);
2921	if (coverage && crtc == desired) {
2922	    *crtc_box_ret = crtc_box;
2923	    return crtc;
2924	} else if (coverage > best_coverage) {
2925	    *crtc_box_ret = crtc_box;
2926	    best_crtc = crtc;
2927	    best_coverage = coverage;
2928	}
2929    }
2930    return best_crtc;
2931}
2932
2933/*
2934 * For overlay video, compute the relevant CRTC and
2935 * clip video to that.
2936 *
2937 * returning FALSE means there was a memory failure of some kind,
2938 * not that the video shouldn't be displayed
2939 */
2940
2941_X_EXPORT Bool
2942xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn,
2943			    xf86CrtcPtr *crtc_ret,
2944			    xf86CrtcPtr desired_crtc,
2945			    BoxPtr      dst,
2946			    INT32	*xa,
2947			    INT32	*xb,
2948			    INT32	*ya,
2949			    INT32	*yb,
2950			    RegionPtr   reg,
2951			    INT32	width,
2952			    INT32	height)
2953{
2954    Bool	ret;
2955    RegionRec	crtc_region_local;
2956    RegionPtr	crtc_region = reg;
2957
2958    if (crtc_ret) {
2959	BoxRec		crtc_box;
2960	xf86CrtcPtr	crtc = xf86_covering_crtc(pScrn, dst,
2961						  desired_crtc,
2962						  &crtc_box);
2963
2964	if (crtc) {
2965	    REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1);
2966	    crtc_region = &crtc_region_local;
2967	    REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg);
2968	}
2969	*crtc_ret = crtc;
2970    }
2971
2972    ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb,
2973				crtc_region, width, height);
2974
2975    if (crtc_region != reg)
2976	REGION_UNINIT (pScreen, &crtc_region_local);
2977
2978    return ret;
2979}
2980
2981xf86_crtc_notify_proc_ptr
2982xf86_wrap_crtc_notify (ScreenPtr screen, xf86_crtc_notify_proc_ptr new)
2983{
2984    if (xf86CrtcConfigPrivateIndex != -1)
2985    {
2986	ScrnInfoPtr		scrn = xf86Screens[screen->myNum];
2987	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
2988	xf86_crtc_notify_proc_ptr	old;
2989
2990	old = config->xf86_crtc_notify;
2991	config->xf86_crtc_notify = new;
2992	return old;
2993    }
2994    return NULL;
2995}
2996
2997void
2998xf86_unwrap_crtc_notify(ScreenPtr screen, xf86_crtc_notify_proc_ptr old)
2999{
3000    if (xf86CrtcConfigPrivateIndex != -1)
3001    {
3002	ScrnInfoPtr		scrn = xf86Screens[screen->myNum];
3003	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
3004
3005	config->xf86_crtc_notify = old;
3006    }
3007}
3008
3009void
3010xf86_crtc_notify(ScreenPtr screen)
3011{
3012    ScrnInfoPtr		scrn = xf86Screens[screen->myNum];
3013    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
3014
3015    if (config->xf86_crtc_notify)
3016	config->xf86_crtc_notify(screen);
3017}
3018