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