xserver: Branch 'server-1.2-branch'

Keith Packard keithp at kemper.freedesktop.org
Thu Feb 15 04:13:17 EET 2007


 configure.ac                     |    1 
 hw/xfree86/Makefile.am           |    5 
 hw/xfree86/ddc/Makefile.am       |    5 
 hw/xfree86/ddc/ddcProperty.c     |    1 
 hw/xfree86/ddc/xf86DDC.c         |    4 
 hw/xfree86/i2c/Makefile.am       |    5 
 hw/xfree86/loader/Makefile.am    |    2 
 hw/xfree86/loader/loadmod.c      |   24 
 hw/xfree86/loader/xf86sym.c      |   88 ++
 hw/xfree86/modes/Makefile.am     |   27 
 hw/xfree86/modes/xf86Crtc.c      | 1587 +++++++++++++++++++++++++++++++++++++++
 hw/xfree86/modes/xf86Crtc.h      |  555 +++++++++++++
 hw/xfree86/modes/xf86DiDGA.c     |  280 ++++++
 hw/xfree86/modes/xf86EdidModes.c |  339 ++++++++
 hw/xfree86/modes/xf86Modes.c     |  635 +++++++++++++++
 hw/xfree86/modes/xf86Modes.h     |   85 ++
 hw/xfree86/modes/xf86RandR12.c   |  950 +++++++++++++++++++++++
 hw/xfree86/modes/xf86RandR12.h   |   37 
 hw/xfree86/modes/xf86Rename.h    |   77 +
 hw/xfree86/modes/xf86Rotate.c    |  402 +++++++++
 hw/xfree86/modes/xf86cvt.c       |  303 +++++++
 hw/xfree86/ramdac/xf86Cursor.c   |    3 
 22 files changed, 5403 insertions(+), 12 deletions(-)

New commits:
diff-tree 12505d9c0a45d855fa85a4e5d4892b3cc590e945 (from d1170fee8a24f6fb9c6c2ff2a1d845adc37729ff)
Author: Keith Packard <keithp at guitar.keithp.com>
Date:   Wed Feb 14 18:13:15 2007 -0800

    Merge crtc/output-based mode selection code.
    
    This code comes from the intel driver, so there's no history in this tree.
    
    As the crtc/output-based mode selection code uses ddc, the ddc and i2c
    modules have been merged into the server. Attempts to load them are safely
    ignored now.

diff --git a/configure.ac b/configure.ac
index a939687..073edf7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1736,6 +1736,7 @@ hw/xfree86/fbdevhw/Makefile
 hw/xfree86/i2c/Makefile
 hw/xfree86/int10/Makefile
 hw/xfree86/loader/Makefile
+hw/xfree86/modes/Makefile
 hw/xfree86/os-support/Makefile
 hw/xfree86/os-support/bsd/Makefile
 hw/xfree86/os-support/bus/Makefile
diff --git a/hw/xfree86/Makefile.am b/hw/xfree86/Makefile.am
index f05308d..e379633 100644
--- a/hw/xfree86/Makefile.am
+++ b/hw/xfree86/Makefile.am
@@ -12,7 +12,7 @@ DOC_SUBDIR = doc
 
 SUBDIRS = common ddc dummylib i2c x86emu int10 fbdevhw os-support parser rac \
           ramdac shadowfb vbe vgahw xaa xf1bpp xf4bpp xf8_16bpp \
-	  xf8_32bpp loader scanpci dixmods exa \
+	  xf8_32bpp loader scanpci dixmods exa modes \
 	  $(DRI_SUBDIR) $(XF86UTILS_SUBDIR) $(DOC_SUBDIR)
 
 DIST_SUBDIRS = common ddc dummylib i2c x86emu int10 fbdevhw os-support \
@@ -47,6 +47,9 @@ XORG_LIBS = \
 	    rac/librac.a \
             parser/libxf86config.a \
 	    dixmods/libdixmods.la \
+	    modes/libxf86modes.a \
+	    ddc/libddc.a \
+	    i2c/libi2c.a \
             @XORG_LIBS@
 
 Xorg_DEPENDENCIES = \
diff --git a/hw/xfree86/ddc/Makefile.am b/hw/xfree86/ddc/Makefile.am
index 7cfff47..3b36f55 100644
--- a/hw/xfree86/ddc/Makefile.am
+++ b/hw/xfree86/ddc/Makefile.am
@@ -1,9 +1,8 @@
 sdk_HEADERS = edid.h vdif.h xf86DDC.h
 
-module_LTLIBRARIES = libddc.la
+noinst_LIBRARIES = libddc.a
 
-libddc_la_LDFLAGS = -avoid-version
-libddc_la_SOURCES = xf86DDC.c edid.c interpret_edid.c print_edid.c \
+libddc_a_SOURCES = xf86DDC.c edid.c interpret_edid.c print_edid.c \
                    interpret_vdif.c print_vdif.c ddcProperty.c
 
 INCLUDES = $(XORG_INCS) -I$(srcdir)/../i2c
diff --git a/hw/xfree86/ddc/ddcProperty.c b/hw/xfree86/ddc/ddcProperty.c
index a1650bc..c68dd08 100644
--- a/hw/xfree86/ddc/ddcProperty.c
+++ b/hw/xfree86/ddc/ddcProperty.c
@@ -31,6 +31,7 @@
 #include "property.h"
 #include "propertyst.h"
 #include "xf86DDC.h"
+#include "xf86_ansic.h"
 
 /*
  * xf86Mode.c should have a some more DisplayModePtr list handling.
diff --git a/hw/xfree86/ddc/xf86DDC.c b/hw/xfree86/ddc/xf86DDC.c
index dd64bd5..4ce585c 100644
--- a/hw/xfree86/ddc/xf86DDC.c
+++ b/hw/xfree86/ddc/xf86DDC.c
@@ -15,6 +15,8 @@
 
 static const OptionInfoRec *DDCAvailableOptions(void *unused);
 
+#if DDC_MODULE
+
 static MODULESETUPPROTO(ddcSetup);
 
 static XF86ModuleVersionInfo ddcVersRec =
@@ -57,6 +59,8 @@ ddcSetup(pointer module, pointer opts, i
     return (pointer)1;
 }
 
+#endif
+
 #define RETRIES 4
 
 static unsigned char *EDIDRead_DDC1(
diff --git a/hw/xfree86/i2c/Makefile.am b/hw/xfree86/i2c/Makefile.am
index cbf4f65..f7c0434 100644
--- a/hw/xfree86/i2c/Makefile.am
+++ b/hw/xfree86/i2c/Makefile.am
@@ -1,4 +1,4 @@
-module_LTLIBRARIES = libi2c.la
+module_LIBRARIES = libi2c.a
 
 multimediadir = $(moduledir)/multimedia
 multimedia_LTLIBRARIES =	\
@@ -10,8 +10,7 @@ multimedia_LTLIBRARIES =	\
 	tda9885_drv.la		\
 	uda1380_drv.la
 
-libi2c_la_LDFLAGS = -avoid-version
-libi2c_la_SOURCES = xf86i2c.c xf86i2cmodule.c
+libi2c_a_SOURCES = xf86i2c.c
 
 INCLUDES = $(XORG_INCS)
 
diff --git a/hw/xfree86/loader/Makefile.am b/hw/xfree86/loader/Makefile.am
index 0306723..0a89d08 100644
--- a/hw/xfree86/loader/Makefile.am
+++ b/hw/xfree86/loader/Makefile.am
@@ -2,7 +2,7 @@ noinst_LIBRARIES = libloader.a
 
 INCLUDES = $(XORG_INCS) -I$(srcdir)/../parser -I$(srcdir)/../dixmods/extmod \
 	   -I$(srcdir)/../vbe -I$(top_srcdir)/miext/cw -I$(srcdir)/../int10 \
-	   -I$(srcdir)/../ddc -I$(srcdir)/../i2c
+	   -I$(srcdir)/../ddc -I$(srcdir)/../i2c -I$(srcdir)/../modes
 
 #AM_LDFLAGS = -r
 AM_CFLAGS = -DIN_LOADER $(XORG_CFLAGS)
diff --git a/hw/xfree86/loader/loadmod.c b/hw/xfree86/loader/loadmod.c
index ec0f181..e489212 100644
--- a/hw/xfree86/loader/loadmod.c
+++ b/hw/xfree86/loader/loadmod.c
@@ -768,7 +768,7 @@ LoadSubModule(ModuleDescPtr parent, cons
 
     submod = doLoadModule(module, NULL, subdirlist, patternlist, options,
 			  modreq, errmaj, errmin, LD_FLAG_GLOBAL);
-    if (submod) {
+    if (submod && submod != (ModuleDescPtr) 1) {
 	parent->child = AddSibling(parent->child, submod);
 	submod->parent = parent;
     }
@@ -799,7 +799,7 @@ LoadSubModuleLocal(ModuleDescPtr parent,
 
     submod = doLoadModule(module, NULL, subdirlist, patternlist, options,
 			  modreq, errmaj, errmin, 0);
-    if (submod) {
+    if (submod && submod != (ModuleDescPtr) 1) {
 	parent->child = AddSibling(parent->child, submod);
 	submod->parent = parent;
     }
@@ -838,6 +838,11 @@ DuplicateModule(ModuleDescPtr mod, Modul
     return ret;
 }
 
+static const char *compiled_in_modules[] = {
+    "ddc",
+    "i2c",
+    NULL
+};
 
 static ModuleDescPtr
 doLoadModule(const char *module, const char *path, const char **subdirlist,
@@ -856,9 +861,17 @@ doLoadModule(const char *module, const c
     PatternPtr patterns = NULL;
     int noncanonical = 0;
     char *m = NULL;
+    char **cim;
 
     xf86MsgVerb(X_INFO, 3, "LoadModule: \"%s\"", module);
 
+    for (cim = compiled_in_modules; *cim; cim++)
+	if (!strcmp (module, *cim))
+	{
+	    xf86MsgVerb(X_INFO, 3, "Module alread ybuilt-in");
+	    return (ModuleDescPtr) 1;
+	}
+
     patterns = InitPatterns(patternlist);
     name = LoaderGetCanonicalName(module, patterns);
     noncanonical = (name && strcmp(module, name) != 0);
@@ -1108,6 +1121,9 @@ UnloadDriver(ModuleDescPtr mod)
 static void
 UnloadModuleOrDriver(ModuleDescPtr mod)
 {
+    if (mod == (ModuleDescPtr) 1)
+	return;
+
     if (mod == NULL || mod->name == NULL)
 	return;
 
@@ -1156,6 +1172,8 @@ FreeModuleDesc(ModuleDescPtr head)
 {
     ModuleDescPtr sibs, prev;
 
+    if (head == (ModuleDescPtr) 1)
+	return;
     /*
      * only free it if it's not marked as in use. In use means that it may
      * be unloaded someday, and UnloadModule or UnloadDriver will free it
@@ -1338,7 +1356,7 @@ LoaderGetCanonicalName(const char *modna
 unsigned long
 LoaderGetModuleVersion(ModuleDescPtr mod)
 {
-    if (!mod || !mod->VersionInfo)
+    if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo)
 	return 0;
 
     return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion,
diff --git a/hw/xfree86/loader/xf86sym.c b/hw/xfree86/loader/xf86sym.c
index 69e11d5..2d1b887 100644
--- a/hw/xfree86/loader/xf86sym.c
+++ b/hw/xfree86/loader/xf86sym.c
@@ -90,6 +90,13 @@
 #include "xf86sbusBus.h"
 #endif
 #include "compiler.h"
+#include "xf86Crtc.h"
+#include "xf86Modes.h"
+#ifdef RANDR
+#include "xf86RandR12.h"
+#endif
+#include "xf86DDC.h"
+#include "edid.h"
 
 #ifndef HAS_GLIBC_SIGSETJMP
 #if defined(setjmp) && defined(__GNU_LIBRARY__) && \
@@ -1171,4 +1178,85 @@ _X_HIDDEN void *xfree86LookupTab[] = {
 
     /* Pci.c */
     SYMVAR(pciNumBuses)
+
+    /* modes */
+    SYMFUNC(xf86CrtcConfigInit)
+    SYMFUNC(xf86CrtcConfigPrivateIndex)
+    SYMFUNC(xf86CrtcCreate)
+    SYMFUNC(xf86CrtcDestroy)
+    SYMFUNC(xf86CrtcInUse)
+    SYMFUNC(xf86CrtcRotate)
+    SYMFUNC(xf86CrtcSetMode)
+    SYMFUNC(xf86CrtcSetSizeRange)
+    SYMFUNC(xf86CVTMode)
+    SYMFUNC(xf86DisableUnusedFunctions)
+    SYMFUNC(xf86DPMSSet)
+    SYMFUNC(xf86DuplicateMode)
+    SYMFUNC(xf86DuplicateModes)
+    SYMFUNC(xf86GetDefaultModes)
+    SYMFUNC(xf86GetMonitorModes)
+    SYMFUNC(xf86InitialConfiguration)
+    SYMFUNC(xf86ModeHSync)
+    SYMFUNC(xf86ModesAdd)
+    SYMFUNC(xf86ModesEqual)
+    SYMFUNC(xf86ModeVRefresh)
+    SYMFUNC(xf86OutputCreate)
+    SYMFUNC(xf86OutputDestroy)
+    SYMFUNC(xf86OutputGetEDID)
+    SYMFUNC(xf86OutputGetEDIDModes)
+    SYMFUNC(xf86OutputRename)
+    SYMFUNC(xf86OutputSetEDID)
+    SYMFUNC(xf86PrintModeline)
+    SYMFUNC(xf86ProbeOutputModes)
+    SYMFUNC(xf86PruneInvalidModes)
+    SYMFUNC(xf86SetModeCrtc)
+    SYMFUNC(xf86SetModeDefaultName)
+    SYMFUNC(xf86SetScrnInfoModes)
+    SYMFUNC(xf86ValidateModesClocks)
+    SYMFUNC(xf86ValidateModesFlags)
+    SYMFUNC(xf86ValidateModesSize)
+    SYMFUNC(xf86ValidateModesSync)
+    SYMFUNC(xf86ValidateModesUserConfig)
+    SYMFUNC(xf86DiDGAInit)
+    SYMFUNC(xf86DiDGAReInit)
+    SYMFUNC(xf86DDCGetModes)
+    SYMFUNC(xf86SaveScreen)
+#ifdef RANDR
+    SYMFUNC(xf86RandR12CreateScreenResources)
+    SYMFUNC(xf86RandR12GetOriginalVirtualSize)
+    SYMFUNC(xf86RandR12GetRotation)
+    SYMFUNC(xf86RandR12Init)
+    SYMFUNC(xf86RandR12PreInit)
+    SYMFUNC(xf86RandR12SetConfig)
+    SYMFUNC(xf86RandR12SetRotations)
+#endif
+
+    SYMFUNC(xf86DoEDID_DDC1)
+    SYMFUNC(xf86DoEDID_DDC2)
+    SYMFUNC(xf86InterpretEDID)
+    SYMFUNC(xf86PrintEDID)
+    SYMFUNC(xf86InterpretVdif)
+    SYMFUNC(xf86print_vdif)
+    SYMFUNC(xf86DDCMonitorSet)
+    SYMFUNC(xf86SetDDCproperties)
+
+    SYMFUNC(xf86CreateI2CBusRec)
+    SYMFUNC(xf86CreateI2CDevRec)
+    SYMFUNC(xf86DestroyI2CBusRec)
+    SYMFUNC(xf86DestroyI2CDevRec)
+    SYMFUNC(xf86I2CBusInit)
+    SYMFUNC(xf86I2CDevInit)
+    SYMFUNC(xf86I2CFindBus)
+    SYMFUNC(xf86I2CFindDev)
+    SYMFUNC(xf86I2CGetScreenBuses)
+    SYMFUNC(xf86I2CProbeAddress)
+    SYMFUNC(xf86I2CReadByte)
+    SYMFUNC(xf86I2CReadBytes)
+    SYMFUNC(xf86I2CReadStatus)
+    SYMFUNC(xf86I2CReadWord)
+    SYMFUNC(xf86I2CWriteByte)
+    SYMFUNC(xf86I2CWriteBytes)
+    SYMFUNC(xf86I2CWriteRead)
+    SYMFUNC(xf86I2CWriteVec)
+    SYMFUNC(xf86I2CWriteWord)
 };
diff --git a/hw/xfree86/modes/Makefile.am b/hw/xfree86/modes/Makefile.am
new file mode 100644
index 0000000..60d2553
--- /dev/null
+++ b/hw/xfree86/modes/Makefile.am
@@ -0,0 +1,27 @@
+noinst_LIBRARIES = libxf86modes.a
+
+libxf86modes_a_SOURCES = \
+	xf86Crtc.c \
+	xf86Crtc.h \
+	xf86cvt.c \
+	xf86DiDGA.c \
+	xf86EdidModes.c \
+	xf86Modes.c \
+	xf86Modes.h \
+	xf86RandR12.c \
+	xf86RandR12.h \
+	xf86Rename.h \
+	xf86Rotate.c
+
+INCLUDES = $(XORG_INCS) -I$(srcdir)/../ddc -I$(srcdir)/../i2c \
+	   -I$(srcdir)/../loader -I$(srcdir)/../rac -I$(srcdir)/../parser \
+           -I$(srcdir)/../scanpci -I$(srcdir)/../vbe -I$(srcdir)/../int10 \
+	   -I$(srcdir)/../vgahw -I$(srcdir)/../dixmods/extmod
+
+sdk_HEADERS = \
+	xf86Crtc.h \
+	xf86Modes.h \
+	xf86RandR12.h \
+	xf86Rename.h
+
+AM_CFLAGS = $(XORG_CFLAGS)
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
new file mode 100644
index 0000000..ab7070b
--- /dev/null
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -0,0 +1,1587 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "xf86.h"
+#include "xf86DDC.h"
+#include "xf86Crtc.h"
+#include "xf86Modes.h"
+#include "xf86RandR12.h"
+#include "X11/extensions/render.h"
+#define DPMS_SERVER
+#include "X11/extensions/dpms.h"
+#include "X11/Xatom.h"
+
+/*
+ * Initialize xf86CrtcConfig structure
+ */
+
+int xf86CrtcConfigPrivateIndex = -1;
+
+void
+xf86CrtcConfigInit (ScrnInfoPtr scrn)
+{
+    xf86CrtcConfigPtr	config;
+    
+    if (xf86CrtcConfigPrivateIndex == -1)
+	xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
+    config = xnfcalloc (1, sizeof (xf86CrtcConfigRec));
+    scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config;
+}
+ 
+void
+xf86CrtcSetSizeRange (ScrnInfoPtr scrn,
+		      int minWidth, int minHeight,
+		      int maxWidth, int maxHeight)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    config->minWidth = minWidth;
+    config->minHeight = minHeight;
+    config->maxWidth = maxWidth;
+    config->maxHeight = maxHeight;
+}
+
+/*
+ * Crtc functions
+ */
+xf86CrtcPtr
+xf86CrtcCreate (ScrnInfoPtr		scrn,
+		const xf86CrtcFuncsRec	*funcs)
+{
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    xf86CrtcPtr		crtc, *crtcs;
+
+    crtc = xcalloc (sizeof (xf86CrtcRec), 1);
+    if (!crtc)
+	return NULL;
+    crtc->scrn = scrn;
+    crtc->funcs = funcs;
+#ifdef RANDR_12_INTERFACE
+    crtc->randr_crtc = NULL;
+#endif
+    crtc->rotation = RR_Rotate_0;
+    crtc->desiredRotation = RR_Rotate_0;
+    if (xf86_config->crtc)
+	crtcs = xrealloc (xf86_config->crtc,
+			  (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr));
+    else
+	crtcs = xalloc ((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr));
+    if (!crtcs)
+    {
+	xfree (crtc);
+	return NULL;
+    }
+    xf86_config->crtc = crtcs;
+    xf86_config->crtc[xf86_config->num_crtc++] = crtc;
+    return crtc;
+}
+
+void
+xf86CrtcDestroy (xf86CrtcPtr crtc)
+{
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+    int			c;
+    
+    (*crtc->funcs->destroy) (crtc);
+    for (c = 0; c < xf86_config->num_crtc; c++)
+	if (xf86_config->crtc[c] == crtc)
+	{
+	    memmove (&xf86_config->crtc[c],
+		     &xf86_config->crtc[c+1],
+		     xf86_config->num_crtc - (c + 1));
+	    xf86_config->num_crtc--;
+	    break;
+	}
+    xfree (crtc);
+}
+
+
+/**
+ * Return whether any outputs are connected to the specified pipe
+ */
+
+Bool
+xf86CrtcInUse (xf86CrtcPtr crtc)
+{
+    ScrnInfoPtr		pScrn = crtc->scrn;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int			o;
+    
+    for (o = 0; o < xf86_config->num_output; o++)
+	if (xf86_config->output[o]->crtc == crtc)
+	    return TRUE;
+    return FALSE;
+}
+
+/**
+ * Sets the given video mode on the given crtc
+ */
+Bool
+xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation,
+		 int x, int y)
+{
+    ScrnInfoPtr		scrn = crtc->scrn;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			i;
+    Bool		ret = FALSE;
+    Bool		didLock = FALSE;
+    DisplayModePtr	adjusted_mode;
+    DisplayModeRec	saved_mode;
+    int			saved_x, saved_y;
+    Rotation		saved_rotation;
+
+    adjusted_mode = xf86DuplicateMode(mode);
+
+    crtc->enabled = xf86CrtcInUse (crtc);
+    
+    if (!crtc->enabled)
+    {
+	/* XXX disable crtc? */
+	return TRUE;
+    }
+
+    didLock = crtc->funcs->lock (crtc);
+
+    saved_mode = crtc->mode;
+    saved_x = crtc->x;
+    saved_y = crtc->y;
+    saved_rotation = crtc->rotation;
+    /* Update crtc values up front so the driver can rely on them for mode
+     * setting.
+     */
+    crtc->mode = *mode;
+    crtc->x = x;
+    crtc->y = y;
+    crtc->rotation = rotation;
+
+    /* XXX short-circuit changes to base location only */
+    
+    /* Pass our mode to the outputs and the CRTC to give them a chance to
+     * adjust it according to limitations or output properties, and also
+     * a chance to reject the mode entirely.
+     */
+    for (i = 0; i < xf86_config->num_output; i++) {
+	xf86OutputPtr output = xf86_config->output[i];
+
+	if (output->crtc != crtc)
+	    continue;
+
+	if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) {
+	    goto done;
+	}
+    }
+
+    if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) {
+	goto done;
+    }
+
+    if (!xf86CrtcRotate (crtc, mode, rotation)) {
+	goto done;
+    }
+
+    /* Disable the outputs and CRTCs before setting the mode. */
+    for (i = 0; i < xf86_config->num_output; i++) {
+	xf86OutputPtr output = xf86_config->output[i];
+
+	if (output->crtc != crtc)
+	    continue;
+
+	/* Disable the output as the first thing we do. */
+	output->funcs->dpms(output, DPMSModeOff);
+    }
+
+    crtc->funcs->dpms(crtc, DPMSModeOff);
+
+    /* Set up the DPLL and any output state that needs to adjust or depend
+     * on the DPLL.
+     */
+    crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y);
+    for (i = 0; i < xf86_config->num_output; i++) 
+    {
+	xf86OutputPtr output = xf86_config->output[i];
+	if (output->crtc == crtc)
+	    output->funcs->mode_set(output, mode, adjusted_mode);
+    }
+
+    /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
+    crtc->funcs->dpms(crtc, DPMSModeOn);
+    for (i = 0; i < xf86_config->num_output; i++) 
+    {
+	xf86OutputPtr output = xf86_config->output[i];
+	if (output->crtc == crtc)
+	    output->funcs->dpms(output, DPMSModeOn);
+    }
+
+    /* XXX free adjustedmode */
+    ret = TRUE;
+done:
+    if (!ret) {
+	crtc->x = saved_x;
+	crtc->y = saved_y;
+	crtc->rotation = saved_rotation;
+	crtc->mode = saved_mode;
+    }
+
+    if (didLock)
+	crtc->funcs->unlock (crtc);
+
+    return ret;
+}
+
+/*
+ * Output functions
+ */
+
+extern XF86ConfigPtr xf86configptr;
+
+typedef enum {
+    OPTION_PREFERRED_MODE,
+    OPTION_POSITION,
+    OPTION_BELOW,
+    OPTION_RIGHT_OF,
+    OPTION_ABOVE,
+    OPTION_LEFT_OF,
+    OPTION_ENABLE,
+    OPTION_DISABLE,
+    OPTION_MIN_CLOCK,
+    OPTION_MAX_CLOCK,
+    OPTION_IGNORE,
+} OutputOpts;
+
+static OptionInfoRec xf86OutputOptions[] = {
+    {OPTION_PREFERRED_MODE, "PreferredMode",	OPTV_STRING,  {0}, FALSE },
+    {OPTION_POSITION,	    "Position",		OPTV_STRING,  {0}, FALSE },
+    {OPTION_BELOW,	    "Below",		OPTV_STRING,  {0}, FALSE },
+    {OPTION_RIGHT_OF,	    "RightOf",		OPTV_STRING,  {0}, FALSE },
+    {OPTION_ABOVE,	    "Above",		OPTV_STRING,  {0}, FALSE },
+    {OPTION_LEFT_OF,	    "LeftOf",		OPTV_STRING,  {0}, FALSE },
+    {OPTION_ENABLE,	    "Enable",		OPTV_BOOLEAN, {0}, FALSE },
+    {OPTION_DISABLE,	    "Disable",		OPTV_BOOLEAN, {0}, FALSE },
+    {OPTION_MIN_CLOCK,	    "MinClock",		OPTV_FREQ,    {0}, FALSE },
+    {OPTION_MAX_CLOCK,	    "MaxClock",		OPTV_FREQ,    {0}, FALSE },
+    {OPTION_IGNORE,	    "Ignore",		OPTV_BOOLEAN, {0}, FALSE },
+    {-1,		    NULL,		OPTV_NONE,    {0}, FALSE },
+};
+
+static void
+xf86OutputSetMonitor (xf86OutputPtr output)
+{
+    char    *option_name;
+    static const char monitor_prefix[] = "monitor-";
+    char    *monitor;
+
+    if (!output->name)
+	return;
+
+    if (output->options)
+	xfree (output->options);
+
+    output->options = xnfalloc (sizeof (xf86OutputOptions));
+    memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions));
+    
+    option_name = xnfalloc (strlen (monitor_prefix) +
+			    strlen (output->name) + 1);
+    strcpy (option_name, monitor_prefix);
+    strcat (option_name, output->name);
+    monitor = xf86findOptionValue (output->scrn->options, option_name);
+    if (!monitor)
+	monitor = output->name;
+    else
+	xf86MarkOptionUsedByName (output->scrn->options, option_name);
+    xfree (option_name);
+    output->conf_monitor = xf86findMonitor (monitor,
+					    xf86configptr->conf_monitor_lst);
+    if (output->conf_monitor)
+	xf86ProcessOptions (output->scrn->scrnIndex,
+			    output->conf_monitor->mon_option_lst,
+			    output->options);
+}
+
+static Bool
+xf86OutputEnabled (xf86OutputPtr    output)
+{
+    /* Check to see if this output was disabled in the config file */
+    if (xf86ReturnOptValBool (output->options, OPTION_ENABLE, TRUE) == FALSE ||
+	xf86ReturnOptValBool (output->options, OPTION_DISABLE, FALSE) == TRUE)
+    {
+	return FALSE;
+    }
+    return TRUE;
+}
+
+static Bool
+xf86OutputIgnored (xf86OutputPtr    output)
+{
+    return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE);
+}
+
+xf86OutputPtr
+xf86OutputCreate (ScrnInfoPtr		    scrn,
+		  const xf86OutputFuncsRec *funcs,
+		  const char		    *name)
+{
+    xf86OutputPtr	output, *outputs;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			len;
+
+    if (name)
+	len = strlen (name) + 1;
+    else
+	len = 0;
+
+    output = xcalloc (sizeof (xf86OutputRec) + len, 1);
+    if (!output)
+	return NULL;
+    output->scrn = scrn;
+    output->funcs = funcs;
+    if (name)
+    {
+	output->name = (char *) (output + 1);
+	strcpy (output->name, name);
+    }
+    output->subpixel_order = SubPixelUnknown;
+#ifdef RANDR_12_INTERFACE
+    output->randr_output = NULL;
+#endif
+    if (name)
+    {
+	xf86OutputSetMonitor (output);
+	if (xf86OutputIgnored (output))
+	{
+	    xfree (output);
+	    return FALSE;
+	}
+    }
+    
+    
+    if (xf86_config->output)
+	outputs = xrealloc (xf86_config->output,
+			  (xf86_config->num_output + 1) * sizeof (xf86OutputPtr));
+    else
+	outputs = xalloc ((xf86_config->num_output + 1) * sizeof (xf86OutputPtr));
+    if (!outputs)
+    {
+	xfree (output);
+	return NULL;
+    }
+    
+    xf86_config->output = outputs;
+    xf86_config->output[xf86_config->num_output++] = output;
+    
+    return output;
+}
+
+Bool
+xf86OutputRename (xf86OutputPtr output, const char *name)
+{
+    int	    len = strlen(name) + 1;
+    char    *newname = xalloc (len);
+    
+    if (!newname)
+	return FALSE;	/* so sorry... */
+    
+    strcpy (newname, name);
+    if (output->name && output->name != (char *) (output + 1))
+	xfree (output->name);
+    output->name = newname;
+    xf86OutputSetMonitor (output);
+    if (xf86OutputIgnored (output))
+	return FALSE;
+    return TRUE;
+}
+
+void
+xf86OutputDestroy (xf86OutputPtr output)
+{
+    ScrnInfoPtr		scrn = output->scrn;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			o;
+    
+    (*output->funcs->destroy) (output);
+    while (output->probed_modes)
+	xf86DeleteMode (&output->probed_modes, output->probed_modes);
+    for (o = 0; o < xf86_config->num_output; o++)
+	if (xf86_config->output[o] == output)
+	{
+	    memmove (&xf86_config->output[o],
+		     &xf86_config->output[o+1],
+		     xf86_config->num_output - (o + 1));
+	    xf86_config->num_output--;
+	    break;
+	}
+    if (output->name && output->name != (char *) (output + 1))
+	xfree (output->name);
+    xfree (output);
+}
+
+static DisplayModePtr
+xf86DefaultMode (xf86OutputPtr output, int width, int height)
+{
+    DisplayModePtr  target_mode = NULL;
+    DisplayModePtr  mode;
+    int		    target_diff = 0;
+    int		    target_preferred = 0;
+    int		    mm_height;
+    
+    mm_height = output->mm_height;
+    if (!mm_height)
+	mm_height = 203;	/* 768 pixels at 96dpi */
+    /*
+     * Pick a mode closest to 96dpi 
+     */
+    for (mode = output->probed_modes; mode; mode = mode->next)
+    {
+	int	    dpi;
+	int	    preferred = (mode->type & M_T_PREFERRED) != 0;
+	int	    diff;
+
+	if (mode->HDisplay > width || mode->VDisplay > height) continue;
+	dpi = (mode->HDisplay * 254) / (mm_height * 10);
+	diff = dpi - 96;
+	diff = diff < 0 ? -diff : diff;
+	if (target_mode == NULL || (preferred > target_preferred) ||
+	    (preferred == target_preferred && diff < target_diff))
+	{
+	    target_mode = mode;
+	    target_diff = diff;
+	    target_preferred = preferred;
+	}
+    }
+    return target_mode;
+}
+
+static DisplayModePtr
+xf86ClosestMode (xf86OutputPtr output, DisplayModePtr match,
+		 int width, int height)
+{
+    DisplayModePtr  target_mode = NULL;
+    DisplayModePtr  mode;
+    int		    target_diff = 0;
+    
+    /*
+     * Pick a mode closest to the specified mode
+     */
+    for (mode = output->probed_modes; mode; mode = mode->next)
+    {
+	int	    dx, dy;
+	int	    diff;
+
+	if (mode->HDisplay > width || mode->VDisplay > height) continue;
+	
+	/* exact matches are preferred */
+	if (xf86ModesEqual (mode, match))
+	    return mode;
+	
+	dx = match->HDisplay - mode->HDisplay;
+	dy = match->VDisplay - mode->VDisplay;
+	diff = dx * dx + dy * dy;
+	if (target_mode == NULL || diff < target_diff)
+	{
+	    target_mode = mode;
+	    target_diff = diff;
+	}
+    }
+    return target_mode;
+}
+
+static Bool
+xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height)
+{
+    DisplayModePtr  mode;
+
+    for (mode = output->probed_modes; mode; mode = mode->next)
+    {
+	if (mode->HDisplay > width || mode->VDisplay > height) continue;
+	if (mode->type & M_T_PREFERRED)
+	    return TRUE;
+    }
+    return FALSE;
+}
+
+static int
+xf86PickCrtcs (ScrnInfoPtr	scrn,
+	       xf86CrtcPtr	*best_crtcs,
+	       DisplayModePtr	*modes,
+	       int		n,
+	       int		width,
+	       int		height)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    int		    c, o, l;
+    xf86OutputPtr   output;
+    xf86CrtcPtr	    crtc;
+    xf86CrtcPtr	    *crtcs;
+    xf86CrtcPtr	    best_crtc;
+    int		    best_score;
+    int		    score;
+    int		    my_score;
+    
+    if (n == config->num_output)
+	return 0;
+    output = config->output[n];
+    
+    /*
+     * Compute score with this output disabled
+     */
+    best_crtcs[n] = NULL;
+    best_crtc = NULL;
+    best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height);
+    if (modes[n] == NULL)
+	return best_score;
+    
+    crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr));
+    if (!crtcs)
+	return best_score;
+
+    my_score = 1;
+    /* Score outputs that are known to be connected higher */
+    if (output->status == XF86OutputStatusConnected)
+	my_score++;
+    /* Score outputs with preferred modes higher */
+    if (xf86OutputHasPreferredMode (output, width, height))
+	my_score++;
+    /*
+     * Select a crtc for this output and
+     * then attempt to configure the remaining
+     * outputs
+     */
+    for (c = 0; c < config->num_crtc; c++)
+    {
+	if ((output->possible_crtcs & (1 << c)) == 0)
+	    continue;
+	
+	crtc = config->crtc[c];
+	/*
+	 * Check to see if some other output is
+	 * using this crtc
+	 */
+	for (o = 0; o < n; o++)
+	    if (best_crtcs[o] == crtc)
+		break;
+	if (o < n)
+	{
+	    /*
+	     * If the two outputs desire the same mode,
+	     * see if they can be cloned
+	     */
+	    if (xf86ModesEqual (modes[o], modes[n]) &&
+		config->output[o]->initial_x == config->output[n]->initial_x &&
+		config->output[o]->initial_y == config->output[n]->initial_y)
+	    {
+		for (l = 0; l < config->num_output; l++)
+		    if (output->possible_clones & (1 << l))
+			break;
+		if (l == config->num_output)
+		    continue;		/* nope, try next CRTC */
+	    }
+	    else
+		continue;		/* different modes, can't clone */
+	}
+	crtcs[n] = crtc;
+	memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr));
+	score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height);
+	if (score > best_score)
+	{
+	    best_crtc = crtc;
+	    best_score = score;
+	    memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr));
+	}
+    }
+    xfree (crtcs);
+    return best_score;
+}
+
+
+/*
+ * Compute the virtual size necessary to place all of the available
+ * crtcs in the specified configuration and also large enough to
+ * resize any crtc to the largest available mode
+ */
+
+static void
+xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    int	    width = 0, height = 0;
+    int	    o;
+    int	    c;
+    int	    s;
+
+    for (c = 0; c < config->num_crtc; c++)
+    {
+	int	    crtc_width = 0, crtc_height = 0;
+	xf86CrtcPtr crtc = config->crtc[c];
+
+	if (crtc->enabled)
+	{
+	    crtc_width = crtc->x + crtc->desiredMode.HDisplay;
+	    crtc_height = crtc->y + crtc->desiredMode.VDisplay;
+	}
+	for (o = 0; o < config->num_output; o++) 
+	{
+	    xf86OutputPtr   output = config->output[o];
+
+	    for (s = 0; s < config->num_crtc; s++)
+		if (output->possible_crtcs & (1 << s))
+		{
+		    DisplayModePtr  mode;
+		    for (mode = output->probed_modes; mode; mode = mode->next)
+		    {
+			if (mode->HDisplay > crtc_width)
+			    crtc_width = mode->HDisplay;
+			if (mode->VDisplay > crtc_height)
+			    crtc_height = mode->VDisplay;
+		    }
+		}
+	}
+	if (crtc_width > width)
+	    width = crtc_width;
+	if (crtc_height > height)
+	    height = crtc_height;
+    }
+    if (config->maxWidth && width > config->maxWidth) width = config->maxWidth;
+    if (config->maxHeight && height > config->maxHeight) height = config->maxHeight;
+    if (config->minWidth && width < config->minWidth) width = config->minWidth;
+    if (config->minHeight && height < config->minHeight) height = config->minHeight;
+    *widthp = width;
+    *heightp = height;
+}
+
+#define POSITION_UNSET	-100000
+
+static Bool
+xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			o;
+    int			min_x, min_y;
+    
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr	output = config->output[o];
+
+	output->initial_x = output->initial_y = POSITION_UNSET;
+    }
+    
+    /*
+     * Loop until all outputs are set
+     */
+    for (;;)
+    {
+	Bool	any_set = FALSE;
+	Bool	keep_going = FALSE;
+
+	for (o = 0; o < config->num_output; o++)	
+	{
+	    static const OutputOpts	relations[] = {
+		OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF
+	    };
+	    xf86OutputPtr   output = config->output[o];
+	    xf86OutputPtr   relative;
+	    char	    *relative_name;
+	    char	    *position;
+	    OutputOpts	    relation;
+	    int		    r;
+
+	    if (output->initial_x != POSITION_UNSET)
+		continue;
+	    position = xf86GetOptValString (output->options,
+					    OPTION_POSITION);
+	    /*
+	     * Absolute position wins
+	     */
+	    if (position)
+	    {
+		int		    x, y;
+		if (sscanf (position, "%d %d", &x, &y) == 2)
+		{
+		    output->initial_x = x;
+		    output->initial_y = y;
+		}
+		else
+		{
+		    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
+				"Output %s position not of form \"x y\"\n",
+				output->name);
+		    output->initial_x = output->initial_y = 0;
+		}
+		any_set = TRUE;
+		continue;
+	    }
+	    /*
+	     * Next comes relative positions
+	     */
+	    relation = 0;
+	    relative_name = NULL;
+	    for (r = 0; r < 4; r++)
+	    {
+		relation = relations[r];
+		relative_name = xf86GetOptValString (output->options,
+						     relation);
+		if (relative_name)
+		    break;
+	    }
+	    if (relative_name)
+	    {
+		int or;
+		relative = NULL;
+		for (or = 0; or < config->num_output; or++)
+		{
+		    xf86OutputPtr	out_rel = config->output[or];
+		    XF86ConfMonitorPtr	rel_mon = out_rel->conf_monitor;
+		    char		*name;
+
+		    if (rel_mon)
+			name = rel_mon->mon_identifier;
+		    else
+			name = out_rel->name;
+		    if (!strcmp (relative_name, name))
+		    {
+			relative = config->output[or];
+			break;
+		    }
+		}
+		if (!relative)
+		{
+		    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
+				"Cannot position output %s relative to unknown output %s\n",
+				output->name, relative_name);
+		    output->initial_x = 0;
+		    output->initial_y = 0;
+		    any_set = TRUE;
+		    continue;
+		}
+		if (relative->initial_x == POSITION_UNSET)
+		{
+		    keep_going = TRUE;
+		    continue;
+		}
+		output->initial_x = relative->initial_x;
+		output->initial_y = relative->initial_y;
+		switch (relation) {
+		case OPTION_BELOW:
+		    output->initial_y += modes[or]->VDisplay;
+		    break;
+		case OPTION_RIGHT_OF:
+		    output->initial_x += modes[or]->HDisplay;
+		    break;
+		case OPTION_ABOVE:
+		    output->initial_y -= modes[o]->VDisplay;
+		    break;
+		case OPTION_LEFT_OF:
+		    output->initial_x -= modes[o]->HDisplay;
+		    break;
+		default:
+		    break;
+		}
+		any_set = TRUE;
+		continue;
+	    }
+	    
+	    /* Nothing set, just stick them at 0,0 */
+	    output->initial_x = 0;
+	    output->initial_y = 0;
+	    any_set = TRUE;
+	}
+	if (!keep_going)
+	    break;
+	if (!any_set) 
+	{
+	    for (o = 0; o < config->num_output; o++)
+	    {
+		xf86OutputPtr   output = config->output[o];
+		if (output->initial_x == POSITION_UNSET)
+		{
+		    xf86DrvMsg (scrn->scrnIndex, X_ERROR,
+				"Output position loop. Moving %s to 0,0\n",
+				output->name);
+		    output->initial_x = output->initial_y = 0;
+		    break;
+		}
+	    }
+	}
+    }
+
+    /*
+     * normalize positions
+     */
+    min_x = 1000000;
+    min_y = 1000000;
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr	output = config->output[o];
+
+	if (output->initial_x < min_x)
+	    min_x = output->initial_x;
+	if (output->initial_y < min_y)
+	    min_y = output->initial_y;
+    }
+    
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr	output = config->output[o];
+
+	output->initial_x -= min_x;
+	output->initial_y -= min_y;
+    }
+    return TRUE;
+}
+
+/*
+ * XXX walk the monitor mode list and prune out duplicates that
+ * are inserted by xf86DDCMonitorSet. In an ideal world, that
+ * function would do this work by itself.
+ */
+
+static void
+xf86PruneDuplicateMonitorModes (MonPtr Monitor)
+{
+    DisplayModePtr  master, clone, next;
+
+    for (master = Monitor->Modes; 
+	 master && master != Monitor->Last; 
+	 master = master->next)
+    {
+	for (clone = master->next; clone && clone != Monitor->Modes; clone = next)
+	{
+	    next = clone->next;
+	    if (xf86ModesEqual (master, clone))
+	    {
+		if (Monitor->Last == clone)
+		    Monitor->Last = clone->prev;
+		xf86DeleteMode (&Monitor->Modes, clone);
+	    }
+	}
+    }
+}
+
+/** Return - 0 + if a should be earlier, same or later than b in list
+ */
+static int
+xf86ModeCompare (DisplayModePtr a, DisplayModePtr b)
+{
+    int	diff;
+
+    diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0);
+    if (diff)
+	return diff;
+    diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay;
+    if (diff)
+	return diff;
+    diff = b->Clock - a->Clock;
+    return diff;
+}
+
+/**
+ * Insertion sort input in-place and return the resulting head
+ */
+static DisplayModePtr
+xf86SortModes (DisplayModePtr input)
+{
+    DisplayModePtr  output = NULL, i, o, n, *op, prev;
+
+    /* sort by preferred status and pixel area */
+    while (input)
+    {
+	i = input;
+	input = input->next;
+	for (op = &output; (o = *op); op = &o->next)
+	    if (xf86ModeCompare (o, i) > 0)
+		break;
+	i->next = *op;
+	*op = i;
+    }
+    /* prune identical modes */
+    for (o = output; o && (n = o->next); o = n)
+    {
+	if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n))
+	{
+	    o->next = n->next;
+	    xfree (n->name);
+	    xfree (n);
+	    n = o;
+	}
+    }
+    /* hook up backward links */
+    prev = NULL;
+    for (o = output; o; o = o->next)
+    {
+	o->prev = prev;
+	prev = o;
+    }
+    return output;
+}
+
+#define DEBUG_REPROBE 1
+
+void
+xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			o;
+
+    if (maxX == 0 || maxY == 0)
+	xf86RandR12GetOriginalVirtualSize (scrn, &maxX, &maxY);
+
+    /* Elide duplicate modes before defaulting code uses them */
+    xf86PruneDuplicateMonitorModes (scrn->monitor);
+    
+    /* Probe the list of modes for each output. */
+    for (o = 0; o < config->num_output; o++) 
+    {
+	xf86OutputPtr	    output = config->output[o];
+	DisplayModePtr	    mode;
+	DisplayModePtr	    config_modes = NULL, output_modes, default_modes;
+	char		    *preferred_mode;
+	xf86MonPtr	    edid_monitor;
+	XF86ConfMonitorPtr  conf_monitor;
+	MonRec		    mon_rec;
+	int		    min_clock = 0;
+	int		    max_clock = 0;
+	double		    clock;
+	enum { sync_config, sync_edid, sync_default } sync_source = sync_default;
+	
+	while (output->probed_modes != NULL)
+	    xf86DeleteMode(&output->probed_modes, output->probed_modes);
+
+	/*
+	 * Check connection status
+	 */
+	output->status = (*output->funcs->detect)(output);
+
+	if (output->status == XF86OutputStatusDisconnected)
+	    continue;
+
+	memset (&mon_rec, '\0', sizeof (mon_rec));
+	
+	conf_monitor = output->conf_monitor;
+	
+	if (conf_monitor)
+	{
+	    int	i;
+	    
+	    for (i = 0; i < conf_monitor->mon_n_hsync; i++)
+	    {
+		mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo;
+		mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi;
+		mon_rec.nHsync++;
+		sync_source = sync_config;
+	    }
+	    for (i = 0; i < conf_monitor->mon_n_vrefresh; i++)
+	    {
+		mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo;
+		mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi;
+		mon_rec.nVrefresh++;
+		sync_source = sync_config;
+	    }
+	    config_modes = xf86GetMonitorModes (scrn, conf_monitor);
+	}
+	
+	output_modes = (*output->funcs->get_modes) (output);
+	
+	edid_monitor = output->MonInfo;
+	
+	if (edid_monitor)
+	{
+	    int			    i;
+	    Bool		    set_hsync = mon_rec.nHsync == 0;
+	    Bool		    set_vrefresh = mon_rec.nVrefresh == 0;
+
+	    for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++)
+	    {
+		if (edid_monitor->det_mon[i].type == DS_RANGES)
+		{
+		    struct monitor_ranges   *ranges = &edid_monitor->det_mon[i].section.ranges;
+		    if (set_hsync && ranges->max_h)
+		    {
+			mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h;
+			mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h;
+			mon_rec.nHsync++;
+			if (sync_source == sync_default)
+			    sync_source = sync_edid;
+		    }
+		    if (set_vrefresh && ranges->max_v)
+		    {
+			mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v;
+			mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v;
+			mon_rec.nVrefresh++;
+			if (sync_source == sync_default)
+			    sync_source = sync_edid;
+		    }
+		    if (ranges->max_clock > max_clock)
+			max_clock = ranges->max_clock;
+		}
+	    }
+	}
+
+	if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK,
+			       OPTUNITS_KHZ, &clock))
+	    min_clock = (int) clock;
+	if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK,
+			       OPTUNITS_KHZ, &clock))
+	    max_clock = (int) clock;
+
+	/*
+	 * These limits will end up setting a 1024x768 at 60Hz mode by default,
+	 * which seems like a fairly good mode to use when nothing else is
+	 * specified
+	 */
+	if (mon_rec.nHsync == 0)
+	{
+	    mon_rec.hsync[0].lo = 31.0;
+	    mon_rec.hsync[0].hi = 55.0;
+	    mon_rec.nHsync = 1;
+	}
+	if (mon_rec.nVrefresh == 0)
+	{
+	    mon_rec.vrefresh[0].lo = 58.0;
+	    mon_rec.vrefresh[0].hi = 62.0;
+	    mon_rec.nVrefresh = 1;
+	}
+	default_modes = xf86GetDefaultModes (output->interlaceAllowed,
+					     output->doubleScanAllowed);
+	
+	if (sync_source == sync_config)
+	{
+	    /* 
+	     * Check output and config modes against sync range from config file
+	     */
+	    xf86ValidateModesSync (scrn, output_modes, &mon_rec);
+	    xf86ValidateModesSync (scrn, config_modes, &mon_rec);
+	}
+	/*
+	 * Check default modes against sync range
+	 */
+        xf86ValidateModesSync (scrn, default_modes, &mon_rec);
+	/*
+	 * Check default modes against monitor max clock
+	 */
+	if (max_clock)
+	    xf86ValidateModesClocks(scrn, default_modes,
+				    &min_clock, &max_clock, 1);
+	
+	output->probed_modes = NULL;
+	output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes);
+	output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes);
+	output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes);
+	
+	/*
+	 * Check all modes against max size
+	 */
+	if (maxX && maxY)
+	    xf86ValidateModesSize (scrn, output->probed_modes,
+				       maxX, maxY, 0);
+	 
+	/*
+	 * Check all modes against output
+	 */
+	for (mode = output->probed_modes; mode != NULL; mode = mode->next) 
+	    if (mode->status == MODE_OK)
+		mode->status = (*output->funcs->mode_valid)(output, mode);
+	
+	xf86PruneInvalidModes(scrn, &output->probed_modes, TRUE);
+	
+	output->probed_modes = xf86SortModes (output->probed_modes);
+	
+	/* Check for a configured preference for a particular mode */
+	preferred_mode = xf86GetOptValString (output->options,
+					      OPTION_PREFERRED_MODE);
+
+	if (preferred_mode)
+	{
+	    for (mode = output->probed_modes; mode; mode = mode->next)
+	    {
+		if (!strcmp (preferred_mode, mode->name))
+		{
+		    if (mode != output->probed_modes)
+		    {
+			if (mode->prev)
+			    mode->prev->next = mode->next;
+			if (mode->next)
+			    mode->next->prev = mode->prev;
+			mode->next = output->probed_modes;
+			output->probed_modes->prev = mode;
+			mode->prev = NULL;
+			output->probed_modes = mode;
+		    }
+		    mode->type |= M_T_PREFERRED;
+		    break;
+		}
+	    }
+	}
+	
+#ifdef DEBUG_REPROBE
+	if (output->probed_modes != NULL) {
+	    xf86DrvMsg(scrn->scrnIndex, X_INFO,
+		       "Printing probed modes for output %s\n",
+		       output->name);
+	} else {
+	    xf86DrvMsg(scrn->scrnIndex, X_INFO,
+		       "No remaining probed modes for output %s\n",
+		       output->name);
+	}
+#endif
+	for (mode = output->probed_modes; mode != NULL; mode = mode->next)
+	{
+	    /* The code to choose the best mode per pipe later on will require
+	     * VRefresh to be set.
+	     */
+	    mode->VRefresh = xf86ModeVRefresh(mode);
+	    xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
+
+#ifdef DEBUG_REPROBE
+	    xf86PrintModeline(scrn->scrnIndex, mode);
+#endif
+	}
+    }
+}
+
+
+/**
+ * Copy one of the output mode lists to the ScrnInfo record
+ */
+
+/* XXX where does this function belong? Here? */
+void
+xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y);
+
+void
+xf86SetScrnInfoModes (ScrnInfoPtr scrn)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    xf86OutputPtr	output;
+    xf86CrtcPtr		crtc;
+    DisplayModePtr	last, mode;
+
+    output = config->output[config->compat_output];
+    if (!output->crtc)
+    {
+	int o;
+
+	output = NULL;
+	for (o = 0; o < config->num_output; o++)
+	    if (config->output[o]->crtc)
+	    {
+		config->compat_output = o;
+		output = config->output[o];
+		break;
+	    }
+	/* no outputs are active, punt and leave things as they are */
+	if (!output)
+	    return;
+    }
+    crtc = output->crtc;
+
+    /* Clear any existing modes from scrn->modes */
+    while (scrn->modes != NULL)
+	xf86DeleteMode(&scrn->modes, scrn->modes);
+
+    /* Set scrn->modes to the mode list for the 'compat' output */
+    scrn->modes = xf86DuplicateModes(scrn, output->probed_modes);
+
+    for (mode = scrn->modes; mode; mode = mode->next)
+	if (xf86ModesEqual (mode, &crtc->desiredMode))
+	    break;
+
+    if (scrn->modes != NULL) {
+	/* For some reason, scrn->modes is circular, unlike the other mode
+	 * lists.  How great is that?
+	 */
+	for (last = scrn->modes; last && last->next; last = last->next)
+	    ;
+	last->next = scrn->modes;
+	scrn->modes->prev = last;
+	if (mode) {
+	    while (scrn->modes != mode)
+		scrn->modes = scrn->modes->next;
+	}
+    }
+    scrn->currentMode = scrn->modes;
+}
+
+/**
+ * Construct default screen configuration
+ *
+ * Given auto-detected (and, eventually, configured) values,
+ * construct a usable configuration for the system
+ */
+
+Bool
+xf86InitialConfiguration (ScrnInfoPtr	    scrn)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			o, c;
+    DisplayModePtr	target_mode = NULL;
+    xf86CrtcPtr		*crtcs;
+    DisplayModePtr	*modes;
+    Bool		*enabled;
+    int			width;
+    int			height;
+
+    if (scrn->display->virtualX)
+	width = scrn->display->virtualX;
+    else
+	width = config->maxWidth;
+    if (scrn->display->virtualY)
+	height = scrn->display->virtualY;
+    else
+	height = config->maxHeight;
+
+    xf86ProbeOutputModes (scrn, width, height);
+
+    crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr));
+    modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr));
+    enabled = xnfcalloc (config->num_output, sizeof (Bool));
+    
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr output = config->output[o];
+	
+	modes[o] = NULL;
+	enabled[o] = (xf86OutputEnabled (output) &&
+		      output->status != XF86OutputStatusDisconnected);
+    }
+    
+    /*
+     * Let outputs with preferred modes drive screen size
+     */
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr output = config->output[o];
+
+	if (enabled[o] &&
+	    xf86OutputHasPreferredMode (output, width, height))
+	{
+	    target_mode = xf86DefaultMode (output, width, height);
+	    if (target_mode)
+	    {
+		modes[o] = target_mode;
+		config->compat_output = o;
+		break;
+	    }
+	}
+    }
+    if (!target_mode)
+    {
+	for (o = 0; o < config->num_output; o++)
+	{
+	    xf86OutputPtr output = config->output[o];
+	    if (enabled[o])
+	    {
+		target_mode = xf86DefaultMode (output, width, height);
+		if (target_mode)
+		{
+		    modes[o] = target_mode;
+		    config->compat_output = o;
+		    break;
+		}
+	    }
+	}
+    }
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr output = config->output[o];
+	
+	if (enabled[o] && !modes[o])
+	    modes[o] = xf86ClosestMode (output, target_mode, width, height);
+    }
+
+    /*
+     * Set the position of each output
+     */
+    if (!xf86InitialOutputPositions (scrn, modes))
+    {
+	xfree (crtcs);
+	xfree (modes);
+	return FALSE;
+    }
+	
+    /*
+     * Assign CRTCs to fit output configuration
+     */
+    if (!xf86PickCrtcs (scrn, crtcs, modes, 0, width, height))
+    {
+	xfree (crtcs);
+	xfree (modes);
+	return FALSE;
+    }
+    
+    /* XXX override xf86 common frame computation code */
+    
+    scrn->display->frameX0 = 0;
+    scrn->display->frameY0 = 0;
+    
+    for (c = 0; c < config->num_crtc; c++)
+    {
+	xf86CrtcPtr	crtc = config->crtc[c];
+
+	crtc->enabled = FALSE;
+	memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode));
+    }
+    
+    /*
+     * Set initial configuration
+     */
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr	output = config->output[o];
+	DisplayModePtr	mode = modes[o];
+        xf86CrtcPtr	crtc = crtcs[o];
+
+	if (mode && crtc)
+	{
+	    crtc->desiredMode = *mode;
+	    crtc->enabled = TRUE;
+	    crtc->x = output->initial_x;
+	    crtc->y = output->initial_y;
+	    output->crtc = crtc;
+	}
+    }
+    
+    if (scrn->display->virtualX == 0)
+    {
+	/*
+	 * Expand virtual size to cover potential mode switches
+	 */
+	xf86DefaultScreenLimits (scrn, &width, &height);
+    
+	scrn->display->virtualX = width;
+	scrn->display->virtualY = height;
+    }
+
+    if (width > scrn->virtualX)
+	scrn->virtualX = width;
+    if (height > scrn->virtualY)
+	scrn->virtualY = height;
+    
+    /* Mirror output modes to scrn mode list */
+    xf86SetScrnInfoModes (scrn);
+    
+    xfree (crtcs);
+    xfree (modes);
+    return TRUE;
+}
+
+/**
+ * Set the DPMS power mode of all outputs and CRTCs.
+ *
+ * If the new mode is off, it will turn off outputs and then CRTCs.
+ * Otherwise, it will affect CRTCs before outputs.
+ */
+void
+xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags)
+{
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			i;
+
+    if (!scrn->vtSema)
+	return;
+
+    if (mode == DPMSModeOff) {
+	for (i = 0; i < config->num_output; i++) {
+	    xf86OutputPtr output = config->output[i];
+	    if (output->crtc != NULL)
+		(*output->funcs->dpms) (output, mode);
+	}
+    }
+
+    for (i = 0; i < config->num_crtc; i++) {
+	xf86CrtcPtr crtc = config->crtc[i];
+	if (crtc->enabled)
+	    (*crtc->funcs->dpms) (crtc, mode);
+    }
+
+    if (mode != DPMSModeOff) {
+	for (i = 0; i < config->num_output; i++) {
+	    xf86OutputPtr output = config->output[i];
+	    if (output->crtc != NULL)
+		(*output->funcs->dpms) (output, mode);
+	}
+    }
+}
+
+/**
+ * Implement the screensaver by just calling down into the driver DPMS hooks.
+ *
+ * Even for monitors with no DPMS support, by the definition of our DPMS hooks,
+ * the outputs will still get disabled (blanked).
+ */
+Bool
+xf86SaveScreen(ScreenPtr pScreen, int mode)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+
+    if (xf86IsUnblank(mode))
+	xf86DPMSSet(pScrn, DPMSModeOn, 0);
+    else
+	xf86DPMSSet(pScrn, DPMSModeOff, 0);
+
+    return TRUE;
+}
+
+/**
+ * Disable all inactive crtcs and outputs
+ */
+void
+xf86DisableUnusedFunctions(ScrnInfoPtr pScrn)
+{
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int			o, c;
+
+    for (o = 0; o < xf86_config->num_output; o++) 
+    {
+	xf86OutputPtr  output = xf86_config->output[o];
+	if (!output->crtc) 
+	    (*output->funcs->dpms)(output, DPMSModeOff);
+    }
+
+    for (c = 0; c < xf86_config->num_crtc; c++) 
+    {
+	xf86CrtcPtr crtc = xf86_config->crtc[c];
+
+	if (!crtc->enabled) 
+	{
+	    crtc->funcs->dpms(crtc, DPMSModeOff);
+	    memset(&crtc->mode, 0, sizeof(crtc->mode));
+	}
+    }
+}
+
+#ifdef RANDR_12_INTERFACE
+
+#define EDID_ATOM_NAME		"EDID_DATA"
+
+/**
+ * Set the RandR EDID property
+ */
+static void
+xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len)
+{
+    Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME), TRUE);
+
+    /* This may get called before the RandR resources have been created */
+    if (output->randr_output == NULL)
+	return;
+
+    if (data_len != 0) {
+	RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8,
+			       PropModeReplace, data_len, data, FALSE);
+    } else {
+	RRDeleteOutputProperty(output->randr_output, edid_atom);
+    }
+}
+
+#endif
+
+/**
+ * Set the EDID information for the specified output
+ */
+void
+xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
+{
+    ScrnInfoPtr		scrn = output->scrn;
+    xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
+    int			i;
+#ifdef RANDR_12_INTERFACE
+    int			size;
+#endif
+    
+    if (output->MonInfo != NULL)
+	xfree(output->MonInfo);
+    
+    output->MonInfo = edid_mon;
+
+    /* Debug info for now, at least */
+    xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", output->name);
+    xf86PrintEDID(edid_mon);
+    
+    /* Set the DDC properties for the 'compat' output */
+    if (output == config->output[config->compat_output])
+        xf86SetDDCproperties(scrn, edid_mon);
+
+#ifdef RANDR_12_INTERFACE
+    /* Set the RandR output properties */
+    size = 0;
+    if (edid_mon)
+    {
+	if (edid_mon->ver.version == 1)
+	    size = 128;
+	else if (edid_mon->ver.version == 2)
+	    size = 256;
+    }
+    xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size);
+#endif
+
+    if (edid_mon)
+    {
+	/* Pull out a phyiscal size from a detailed timing if available. */
+	for (i = 0; i < 4; i++) {
+	    if (edid_mon->det_mon[i].type == DT &&
+		edid_mon->det_mon[i].section.d_timings.h_size != 0 &&
+		edid_mon->det_mon[i].section.d_timings.v_size != 0)
+	    {
+		output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size;
+		output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size;
+		break;
+	    }
+	}
+    
+	/* if no mm size is available from a detailed timing, check the max size field */
+	if ((!output->mm_width || !output->mm_height) &&
+	    (edid_mon->features.hsize && edid_mon->features.vsize))
+	{
+	    output->mm_width = edid_mon->features.hsize * 10;
+	    output->mm_height = edid_mon->features.vsize * 10;
+	}
+    }
+}
+
+/**
+ * Return the list of modes supported by the EDID information
+ * stored in 'output'
+ */
+DisplayModePtr
+xf86OutputGetEDIDModes (xf86OutputPtr output)
+{
+    ScrnInfoPtr	scrn = output->scrn;
+    xf86MonPtr	edid_mon = output->MonInfo;
+
+    if (!edid_mon)
+	return NULL;
+    return xf86DDCGetModes(scrn->scrnIndex, edid_mon);
+}
+
+xf86MonPtr
+xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus)
+{
+    ScrnInfoPtr	scrn = output->scrn;
+
+    return xf86DoEDID_DDC2 (scrn->scrnIndex, pDDCBus);
+}
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
new file mode 100644
index 0000000..49f4965
--- /dev/null
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -0,0 +1,555 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#ifndef _XF86CRTC_H_
+#define _XF86CRTC_H_
+
+#include <edid.h>
+#include "randrstr.h"
+#if XF86_MODES_RENAME
+#include "xf86Rename.h"
+#endif
+#include "xf86Modes.h"
+#include "xf86Parser.h"
+#include "damage.h"
+
+/* Compat definitions for older X Servers. */
+#ifndef M_T_PREFERRED
+#define M_T_PREFERRED	0x08
+#endif
+#ifndef M_T_DRIVER
+#define M_T_DRIVER	0x40
+#endif
+
+typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr;
+typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
+
+typedef enum _xf86OutputStatus {
+   XF86OutputStatusConnected,
+   XF86OutputStatusDisconnected,
+   XF86OutputStatusUnknown,
+} xf86OutputStatus;
+
+typedef struct _xf86CrtcFuncs {
+   /**
+    * Turns the crtc on/off, or sets intermediate power levels if available.
+    *
+    * Unsupported intermediate modes drop to the lower power setting.  If the
+    * mode is DPMSModeOff, the crtc must be disabled sufficiently for it to
+    * be safe to call mode_set.
+    */
+   void
+    (*dpms)(xf86CrtcPtr		crtc,
+	    int		    	mode);
+
+   /**
+    * Saves the crtc's state for restoration on VT switch.
+    */
+   void
+    (*save)(xf86CrtcPtr		crtc);
+
+   /**
+    * Restore's the crtc's state at VT switch.
+    */
+   void
+    (*restore)(xf86CrtcPtr	crtc);
+
+    /**
+     * Lock CRTC prior to mode setting, mostly for DRI.
+     * Returns whether unlock is needed
+     */
+    Bool
+    (*lock) (xf86CrtcPtr crtc);
+    
+    /**
+     * Unlock CRTC after mode setting, mostly for DRI
+     */
+    void
+    (*unlock) (xf86CrtcPtr crtc);
+    
+    /**
+     * Callback to adjust the mode to be set in the CRTC.
+     *
+     * This allows a CRTC to adjust the clock or even the entire set of
+     * timings, which is used for panels with fixed timings or for
+     * buses with clock limitations.
+     */
+    Bool
+    (*mode_fixup)(xf86CrtcPtr crtc,
+		  DisplayModePtr mode,
+		  DisplayModePtr adjusted_mode);
+
+    /**
+     * Callback for setting up a video mode after fixups have been made.
+     */
+    void
+    (*mode_set)(xf86CrtcPtr crtc,
+		DisplayModePtr mode,
+		DisplayModePtr adjusted_mode,
+		int x, int y);
+
+    /* Set the color ramps for the CRTC to the given values. */
+    void
+    (*gamma_set)(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
+		 int size);
+
+    /**
+     * Create shadow pixmap for rotation support
+     */
+    PixmapPtr
+    (*shadow_create) (xf86CrtcPtr crtc, int width, int height);
+    
+    /**
+     * Destroy shadow pixmap
+     */
+    void
+    (*shadow_destroy) (xf86CrtcPtr crtc, PixmapPtr pPixmap);
+
+    /**
+     * Clean up driver-specific bits of the crtc
+     */
+    void
+    (*destroy) (xf86CrtcPtr	crtc);
+} xf86CrtcFuncsRec, *xf86CrtcFuncsPtr;
+
+struct _xf86Crtc {
+    /**
+     * Associated ScrnInfo
+     */
+    ScrnInfoPtr	    scrn;
+    
+    /**
+     * Active state of this CRTC
+     *
+     * Set when this CRTC is driving one or more outputs 
+     */
+    Bool	    enabled;
+    
+    /** Track whether cursor is within CRTC range  */
+    Bool	    cursorInRange;
+    
+    /** Track state of cursor associated with this CRTC */
+    Bool	    cursorShown;
+    
+    /**
+     * Active mode
+     *
+     * This reflects the mode as set in the CRTC currently
+     * It will be cleared when the VT is not active or
+     * during server startup
+     */
+    DisplayModeRec  mode;
+    Rotation	    rotation;
+    PixmapPtr	    rotatedPixmap;
+    /**
+     * Position on screen
+     *
+     * Locates this CRTC within the frame buffer
+     */
+    int		    x, y;
+    
+    /**
+     * Desired mode
+     *
+     * This is set to the requested mode, independent of
+     * whether the VT is active. In particular, it receives
+     * the startup configured mode and saves the active mode
+     * on VT switch.
+     */
+    DisplayModeRec  desiredMode;
+    Rotation	    desiredRotation;
+    int		    desiredX, desiredY;
+    
+    /** crtc-specific functions */
+    const xf86CrtcFuncsRec *funcs;
+
+    /**
+     * Driver private
+     *
+     * Holds driver-private information
+     */
+    void	    *driver_private;
+
+#ifdef RANDR_12_INTERFACE
+    /**
+     * RandR crtc
+     *
+     * When RandR 1.2 is available, this
+     * points at the associated crtc object
+     */
+    RRCrtcPtr	    randr_crtc;
+#else
+    void	    *randr_crtc;
+#endif
+};
+
+typedef struct _xf86OutputFuncs {
+    /**
+     * Called to allow the output a chance to create properties after the
+     * RandR objects have been created.
+     */
+    void
+    (*create_resources)(xf86OutputPtr output);
+
+    /**
+     * Turns the output on/off, or sets intermediate power levels if available.
+     *
+     * Unsupported intermediate modes drop to the lower power setting.  If the
+     * mode is DPMSModeOff, the output must be disabled, as the DPLL may be
+     * disabled afterwards.
+     */
+    void
+    (*dpms)(xf86OutputPtr	output,
+	    int			mode);
+
+    /**
+     * Saves the output's state for restoration on VT switch.
+     */
+    void
+    (*save)(xf86OutputPtr	output);
+
+    /**
+     * Restore's the output's state at VT switch.
+     */
+    void
+    (*restore)(xf86OutputPtr	output);
+
+    /**
+     * Callback for testing a video mode for a given output.
+     *
+     * This function should only check for cases where a mode can't be supported
+     * on the output specifically, and not represent generic CRTC limitations.
+     *
+     * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
+     */
+    int
+    (*mode_valid)(xf86OutputPtr	    output,
+		  DisplayModePtr    pMode);
+
+    /**
+     * Callback to adjust the mode to be set in the CRTC.
+     *
+     * This allows an output to adjust the clock or even the entire set of
+     * timings, which is used for panels with fixed timings or for
+     * buses with clock limitations.
+     */
+    Bool
+    (*mode_fixup)(xf86OutputPtr output,
+		  DisplayModePtr mode,
+		  DisplayModePtr adjusted_mode);
+
+    /**
+     * Callback for setting up a video mode after fixups have been made.
+     *
+     * This is only called while the output is disabled.  The dpms callback
+     * must be all that's necessary for the output, to turn the output on
+     * after this function is called.
+     */
+    void
+    (*mode_set)(xf86OutputPtr  output,
+		DisplayModePtr mode,
+		DisplayModePtr adjusted_mode);
+
+    /**
+     * Probe for a connected output, and return detect_status.
+     */
+    xf86OutputStatus
+    (*detect)(xf86OutputPtr	    output);
+
+    /**
+     * Query the device for the modes it provides.
+     *
+     * This function may also update MonInfo, mm_width, and mm_height.
+     *
+     * \return singly-linked list of modes or NULL if no modes found.
+     */
+    DisplayModePtr
+    (*get_modes)(xf86OutputPtr	    output);
+
+#ifdef RANDR_12_INTERFACE
+    /**
+     * Callback when an output's property has changed.
+     */
+    Bool
+    (*set_property)(xf86OutputPtr output,
+		    Atom property,
+		    RRPropertyValuePtr value);
+#endif
+    /**
+     * Clean up driver-specific bits of the output
+     */
+    void
+    (*destroy) (xf86OutputPtr	    output);
+} xf86OutputFuncsRec, *xf86OutputFuncsPtr;
+
+struct _xf86Output {
+    /**
+     * Associated ScrnInfo
+     */
+    ScrnInfoPtr		scrn;
+
+    /**
+     * Currently connected crtc (if any)
+     *
+     * If this output is not in use, this field will be NULL.
+     */
+    xf86CrtcPtr		crtc;
+
+    /**
+     * Possible CRTCs for this output as a mask of crtc indices
+     */
+    CARD32		possible_crtcs;
+
+    /**
+     * Possible outputs to share the same CRTC as a mask of output indices
+     */
+    CARD32		possible_clones;
+    
+    /**
+     * Whether this output can support interlaced modes
+     */
+    Bool		interlaceAllowed;
+
+    /**
+     * Whether this output can support double scan modes
+     */
+    Bool		doubleScanAllowed;
+
+    /**
+     * List of available modes on this output.
+     *
+     * This should be the list from get_modes(), plus perhaps additional
+     * compatible modes added later.
+     */
+    DisplayModePtr	probed_modes;
+
+    /**
+     * Options parsed from the related monitor section
+     */
+    OptionInfoPtr	options;
+    
+    /**
+     * Configured monitor section
+     */
+    XF86ConfMonitorPtr  conf_monitor;
+    
+    /**
+     * Desired initial position
+     */
+    int			initial_x, initial_y;
+
+    /**
+     * Current connection status
+     *
+     * This indicates whether a monitor is known to be connected
+     * to this output or not, or whether there is no way to tell
+     */
+    xf86OutputStatus	status;
+
+    /** EDID monitor information */
+    xf86MonPtr		MonInfo;
+
+    /** subpixel order */
+    int			subpixel_order;
+
+    /** Physical size of the currently attached output device. */
+    int			mm_width, mm_height;
+
+    /** Output name */
+    char		*name;
+
+    /** output-specific functions */
+    const xf86OutputFuncsRec *funcs;
+
+    /** driver private information */
+    void		*driver_private;
+    
+#ifdef RANDR_12_INTERFACE
+    /**
+     * RandR 1.2 output structure.
+     *
+     * When RandR 1.2 is available, this points at the associated
+     * RandR output structure and is created when this output is created
+     */
+    RROutputPtr		randr_output;
+#else
+    void		*randr_output;
+#endif
+};
+
+typedef struct _xf86CrtcConfig {
+    int			num_output;
+    xf86OutputPtr	*output;
+    /**
+     * compat_output is used whenever we deal
+     * with legacy code that only understands a single
+     * output. pScrn->modes will be loaded from this output,
+     * adjust frame will whack this output, etc.
+     */
+    int			compat_output;
+
+    int			num_crtc;
+    xf86CrtcPtr		*crtc;
+
+    int			minWidth, minHeight;
+    int			maxWidth, maxHeight;
+    
+    /* For crtc-based rotation */
+    DamagePtr   rotationDamage;
+
+    /* DGA */
+    unsigned int	dga_flags;
+    unsigned long	dga_address;
+    DGAModePtr		dga_modes;
+    int			dga_nmode;
+    int			dga_width, dga_height, dga_stride;
+    DisplayModePtr	dga_save_mode;
+
+} xf86CrtcConfigRec, *xf86CrtcConfigPtr;
+
+extern int xf86CrtcConfigPrivateIndex;
+
+#define XF86_CRTC_CONFIG_PTR(p)	((xf86CrtcConfigPtr) ((p)->privates[xf86CrtcConfigPrivateIndex].ptr))
+
+/*
+ * Initialize xf86CrtcConfig structure
+ */
+
+void
+xf86CrtcConfigInit (ScrnInfoPtr		scrn);
+
+void
+xf86CrtcSetSizeRange (ScrnInfoPtr scrn,
+		      int minWidth, int minHeight,
+		      int maxWidth, int maxHeight);
+
+/*
+ * Crtc functions
+ */
+xf86CrtcPtr
+xf86CrtcCreate (ScrnInfoPtr		scrn,
+		const xf86CrtcFuncsRec	*funcs);
+
+void
+xf86CrtcDestroy (xf86CrtcPtr		crtc);
+
+
+/**
+ * Allocate a crtc for the specified output
+ *
+ * Find a currently unused CRTC which is suitable for
+ * the specified output
+ */
+
+xf86CrtcPtr 
+xf86AllocCrtc (xf86OutputPtr		output);
+
+/**
+ * Free a crtc
+ *
+ * Mark the crtc as unused by any outputs
+ */
+
+void
+xf86FreeCrtc (xf86CrtcPtr		crtc);
+
+/**
+ * Sets the given video mode on the given crtc
+ */
+Bool
+xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation,
+		 int x, int y);
+
+/*
+ * Assign crtc rotation during mode set
+ */
+Bool
+xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation);
+
+/**
+ * Return whether any output is assigned to the crtc
+ */
+Bool
+xf86CrtcInUse (xf86CrtcPtr crtc);
+
+/*
+ * Output functions
+ */
+xf86OutputPtr
+xf86OutputCreate (ScrnInfoPtr		scrn,
+		      const xf86OutputFuncsRec *funcs,
+		      const char	*name);
+
+Bool
+xf86OutputRename (xf86OutputPtr output, const char *name);
+
+void
+xf86OutputDestroy (xf86OutputPtr	output);
+
+void
+xf86ProbeOutputModes (ScrnInfoPtr pScrn, int maxX, int maxY);
+
+void
+xf86SetScrnInfoModes (ScrnInfoPtr pScrn);
+
+Bool
+xf86InitialConfiguration (ScrnInfoPtr pScrn);
+
+void
+xf86DPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags);
+    
+Bool
+xf86SaveScreen(ScreenPtr pScreen, int mode);
+
+void
+xf86DisableUnusedFunctions(ScrnInfoPtr pScrn);
+
+/**
+ * Set the EDID information for the specified output
+ */
+void
+xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon);
+
+/**
+ * Return the list of modes supported by the EDID information
+ * stored in 'output'
+ */
+DisplayModePtr
+xf86OutputGetEDIDModes (xf86OutputPtr output);
+
+xf86MonPtr
+xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus);
+
+/**
+ * Initialize dga for this screen
+ */
+
+Bool
+xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address);
+
+/**
+ * Re-initialize dga for this screen (as when the set of modes changes)
+ */
+
+Bool
+xf86DiDGAReInit (ScreenPtr pScreen);
+
+#endif /* _XF86CRTC_H_ */
diff --git a/hw/xfree86/modes/xf86DiDGA.c b/hw/xfree86/modes/xf86DiDGA.c
new file mode 100644
index 0000000..f4ac4de
--- /dev/null
+++ b/hw/xfree86/modes/xf86DiDGA.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "xf86.h"
+#include "xf86DDC.h"
+#include "xf86_OSproc.h"
+#include "dgaproc.h"
+#include "xf86Crtc.h"
+#include "xf86Modes.h"
+#include "gcstruct.h"
+
+static Bool
+xf86_dga_get_modes (ScreenPtr pScreen)
+{
+    ScrnInfoPtr		scrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    DGAModePtr		modes, mode;
+    DisplayModePtr	display_mode;
+    int			bpp = scrn->bitsPerPixel >> 3;
+    int			num;
+
+    num = 0;
+    display_mode = scrn->modes;
+    while (display_mode) 
+    {
+	num++;
+	display_mode = display_mode->next;
+	if (display_mode == scrn->modes)
+	    break;
+    }
+    
+    if (!num)
+	return FALSE;
+    
+    modes = xalloc(num * sizeof(DGAModeRec));
+    if (!modes)
+	return FALSE;
+    
+    num = 0;
+    display_mode = scrn->modes;
+    while (display_mode) 
+    {
+	mode = modes + num++;
+
+	mode->mode = display_mode;
+	mode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
+        mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
+	if (display_mode->Flags & V_DBLSCAN)
+	    mode->flags |= DGA_DOUBLESCAN;
+	if (display_mode->Flags & V_INTERLACE)
+	    mode->flags |= DGA_INTERLACED;
+	mode->byteOrder = scrn->imageByteOrder;
+	mode->depth = scrn->depth;
+	mode->bitsPerPixel = scrn->bitsPerPixel;
+	mode->red_mask = scrn->mask.red;
+	mode->green_mask = scrn->mask.green;
+	mode->blue_mask = scrn->mask.blue;
+	mode->visualClass = (bpp == 1) ? PseudoColor : TrueColor;
+	mode->viewportWidth = display_mode->HDisplay;
+	mode->viewportHeight = display_mode->VDisplay;
+	mode->xViewportStep = (bpp == 3) ? 2 : 1;
+	mode->yViewportStep = 1;
+	mode->viewportFlags = DGA_FLIP_RETRACE;
+	mode->offset = 0;
+	mode->address = (unsigned char *) xf86_config->dga_address;
+	mode->bytesPerScanline = xf86_config->dga_stride;
+	mode->imageWidth = xf86_config->dga_width;
+	mode->imageHeight = xf86_config->dga_height;
+	mode->pixmapWidth = mode->imageWidth;
+	mode->pixmapHeight = mode->imageHeight;
+	mode->maxViewportX = mode->imageWidth -	mode->viewportWidth;
+	mode->maxViewportY = mode->imageHeight - mode->viewportHeight;
+
+	display_mode = display_mode->next;
+	if (display_mode == scrn->modes)
+	    break;
+    }
+    if (xf86_config->dga_modes)
+	xfree (xf86_config->dga_modes);
+    xf86_config->dga_nmode = num;
+    xf86_config->dga_modes = modes;
+    return TRUE;
+}
+
+static Bool
+xf86_dga_set_mode(ScrnInfoPtr scrn, DGAModePtr display_mode)
+{
+    ScreenPtr		pScreen = scrn->pScreen;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    if (!display_mode) 
+    {
+	if (xf86_config->dga_save_mode)
+	{
+	    xf86SwitchMode(pScreen, xf86_config->dga_save_mode);
+	    xf86_config->dga_save_mode = NULL;
+	}
+    }
+    else
+    {
+	if (!xf86_config->dga_save_mode)
+	{
+	    xf86_config->dga_save_mode = scrn->currentMode;
+	    xf86SwitchMode(pScreen, display_mode->mode);
+	}
+    }
+    return TRUE;
+}
+
+static int
+xf86_dga_get_viewport(ScrnInfoPtr scrn)
+{
+    return 0;
+}
+
+static void
+xf86_dga_set_viewport(ScrnInfoPtr scrn, int x, int y, int flags)
+{
+   scrn->AdjustFrame(scrn->pScreen->myNum, x, y, flags);
+}
+
+static Bool
+xf86_dga_get_drawable_and_gc (ScrnInfoPtr scrn, DrawablePtr *ppDrawable, GCPtr *ppGC)
+{
+    ScreenPtr		pScreen = scrn->pScreen;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    PixmapPtr		pPixmap;
+    GCPtr		pGC;
+    
+    pPixmap = GetScratchPixmapHeader (pScreen, xf86_config->dga_width, xf86_config->dga_height,
+				      scrn->depth, scrn->bitsPerPixel, xf86_config->dga_stride, 
+				      (char *) scrn->memPhysBase + scrn->fbOffset);
+    if (!pPixmap)
+	return FALSE;
+    pGC  = GetScratchGC (scrn->depth, pScreen);
+    if (!pGC)
+    {
+	FreeScratchPixmapHeader (pPixmap);
+	return FALSE;
+    }
+    *ppDrawable = &pPixmap->drawable;
+    *ppGC = pGC;
+    return TRUE;
+}
+
+static void
+xf86_dga_release_drawable_and_gc (ScrnInfoPtr scrn, DrawablePtr pDrawable, GCPtr pGC)
+{
+    FreeScratchGC (pGC);
+    FreeScratchPixmapHeader ((PixmapPtr) pDrawable);
+}
+
+static void
+xf86_dga_fill_rect(ScrnInfoPtr scrn, int x, int y, int w, int h, unsigned long color)
+{
+    GCPtr		pGC;
+    DrawablePtr		pDrawable;
+    XID			vals[1];
+    xRectangle		r;
+
+    if (!xf86_dga_get_drawable_and_gc (scrn, &pDrawable, &pGC))
+	return;
+    vals[0] = color;
+    ChangeGC (pGC, GCForeground, vals);
+    ValidateGC (pDrawable, pGC);
+    r.x = x;
+    r.y = y;
+    r.width = w;
+    r.height = h;
+    pGC->ops->PolyFillRect (pDrawable, pGC, 1, &r);
+    xf86_dga_release_drawable_and_gc (scrn, pDrawable, pGC);
+}
+
+static void
+xf86_dga_sync(ScrnInfoPtr scrn)
+{
+    ScreenPtr	pScreen = scrn->pScreen;
+    WindowPtr	pRoot = WindowTable [pScreen->myNum];
+    char	buffer[4];
+
+    pScreen->GetImage (&pRoot->drawable, 0, 0, 1, 1, ZPixmap, ~0L, buffer);
+}
+
+static void
+xf86_dga_blit_rect(ScrnInfoPtr scrn, int srcx, int srcy, int w, int h, int dstx, int dsty)
+{
+    DrawablePtr	pDrawable;
+    GCPtr	pGC;
+
+    if (!xf86_dga_get_drawable_and_gc (scrn, &pDrawable, &pGC))
+	return;
+    ValidateGC (pDrawable, pGC);
+    pGC->ops->CopyArea (pDrawable, pDrawable, pGC, srcx, srcy, w, h, dstx, dsty);
+    xf86_dga_release_drawable_and_gc (scrn, pDrawable, pGC);
+}
+
+static Bool
+xf86_dga_open_framebuffer(ScrnInfoPtr scrn,
+			  char **name,
+			  unsigned char **mem, int *size, int *offset, int *flags)
+{
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    
+    *size = xf86_config->dga_stride * xf86_config->dga_height;
+    *mem = (unsigned char *) (xf86_config->dga_address);
+    *offset = 0;
+    *flags = DGA_NEED_ROOT;
+
+    return TRUE;
+}
+
+static void
+xf86_dga_close_framebuffer(ScrnInfoPtr scrn)
+{
+}
+
+static DGAFunctionRec xf86_dga_funcs = {
+   xf86_dga_open_framebuffer,
+   xf86_dga_close_framebuffer,
+   xf86_dga_set_mode,
+   xf86_dga_set_viewport,
+   xf86_dga_get_viewport,
+   xf86_dga_sync,
+   xf86_dga_fill_rect,
+   xf86_dga_blit_rect,
+   NULL
+};
+
+Bool
+xf86DiDGAReInit (ScreenPtr pScreen)
+{
+    ScrnInfoPtr		scrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    
+    if (!xf86_dga_get_modes (pScreen))
+	return FALSE;
+    
+    return DGAReInitModes (pScreen, xf86_config->dga_modes, xf86_config->dga_nmode);
+}
+
+Bool
+xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address)
+{
+    ScrnInfoPtr		scrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    xf86_config->dga_flags = 0;
+    xf86_config->dga_address = dga_address;
+    xf86_config->dga_width = scrn->virtualX;
+    xf86_config->dga_height = scrn->virtualY;
+    xf86_config->dga_stride = scrn->displayWidth * scrn->bitsPerPixel >> 3;
+    
+    if (!xf86_dga_get_modes (pScreen))
+	return FALSE;
+    
+    return DGAInit(pScreen, &xf86_dga_funcs, xf86_config->dga_modes, xf86_config->dga_nmode);
+}
diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
new file mode 100644
index 0000000..0476a68
--- /dev/null
+++ b/hw/xfree86/modes/xf86EdidModes.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2006 Luc Verhaegen.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file This is a copy of edid_modes.c from the X Server, for compatibility
+ * with old X Servers.
+ */
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "xf86.h"
+#include "xf86DDC.h"
+#include <X11/Xatom.h>
+#include "property.h"
+#include "propertyst.h"
+#include "xf86DDC.h"
+#include "xf86Crtc.h"
+#include <string.h>
+#include <math.h>
+
+/*
+ * Quirks to work around broken EDID data from various monitors.
+ */
+
+typedef enum {
+    DDC_QUIRK_NONE = 0,
+    /* Force detailed sync polarity to -h +v */
+    DDC_QUIRK_DT_SYNC_HM_VP = 1 << 0,
+    /* First detailed mode is bogus, prefer largest mode at 60hz */
+    DDC_QUIRK_PREFER_LARGE_60 = 1 << 1,
+    /* 135MHz clock is too high, drop a bit */
+    DDC_QUIRK_135_CLOCK_TOO_HIGH = 1 << 2
+} ddc_quirk_t;
+
+static Bool quirk_dt_sync_hm_vp (int scrnIndex, xf86MonPtr DDC)
+{
+    /* Belinea 1924S1W */
+    if (memcmp (DDC->vendor.name, "MAX", 4) == 0 &&
+	DDC->vendor.prod_id == 1932)
+	return TRUE;
+    /* Belinea 10 20 30W */
+    if (memcmp (DDC->vendor.name, "MAX", 4) == 0 &&
+	DDC->vendor.prod_id == 2007)
+	return TRUE;
+    /* ViewSonic VX2025wm (bug #9941) */
+    if (memcmp (DDC->vendor.name, "VSC", 4) == 0 &&
+	DDC->vendor.prod_id == 58653)
+	return TRUE;
+
+    return FALSE;
+}
+
+static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC)
+{
+    /* Belinea 10 15 55 */
+    if (memcmp (DDC->vendor.name, "MAX", 4) == 0 &&
+	DDC->vendor.prod_id == 1516)
+	return TRUE;
+    
+    return FALSE;
+}
+
+static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC)
+{
+    /* Envision Peripherals, Inc. EN-7100e.  See bug #9550. */
+    if (memcmp (DDC->vendor.name, "EPI", 4) == 0 &&
+	DDC->vendor.prod_id == 59264)
+	return TRUE;
+    
+    return FALSE;
+}
+
+typedef struct {
+    Bool	(*detect) (int scrnIndex, xf86MonPtr DDC);
+    ddc_quirk_t	quirk;
+    char	*description;
+} ddc_quirk_map_t;
+
+static const ddc_quirk_map_t ddc_quirks[] = {
+    { 
+	quirk_dt_sync_hm_vp,	DDC_QUIRK_DT_SYNC_HM_VP,
+	"Set detailed timing sync polarity to -h +v"
+    },
+    {
+	quirk_prefer_large_60,   DDC_QUIRK_PREFER_LARGE_60,
+	"Detailed timing is not preferred, use largest mode at 60Hz"
+    },
+    {
+	quirk_135_clock_too_high,   DDC_QUIRK_135_CLOCK_TOO_HIGH,
+	"Recommended 135MHz pixel clock is too high"
+    },
+    { 
+	NULL,		DDC_QUIRK_NONE,
+	"No known quirks"
+    },
+};
+
+/*
+ * TODO:
+ *  - for those with access to the VESA DMT standard; review please.
+ */
+#define MODEPREFIX(name) NULL, NULL, name, 0,M_T_DRIVER
+#define MODESUFFIX   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
+
+static DisplayModeRec DDCEstablishedModes[17] = {
+    { MODEPREFIX("800x600"),    40000,  800,  840,  968, 1056, 0,  600,  601,  605,  628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600 at 60Hz */
+    { MODEPREFIX("800x600"),    36000,  800,  824,  896, 1024, 0,  600,  601,  603,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600 at 56Hz */
+    { MODEPREFIX("640x480"),    31500,  640,  656,  720,  840, 0,  480,  481,  484,  500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480 at 75Hz */
+    { MODEPREFIX("640x480"),    31500,  640,  664,  704,  832, 0,  480,  489,  491,  520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480 at 72Hz */
+    { MODEPREFIX("640x480"),    30240,  640,  704,  768,  864, 0,  480,  483,  486,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480 at 67Hz */
+    { MODEPREFIX("640x480"),    25200,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480 at 60Hz */
+    { MODEPREFIX("720x400"),    35500,  720,  738,  846,  900, 0,  400,  421,  423,  449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400 at 88Hz */
+    { MODEPREFIX("720x400"),    28320,  720,  738,  846,  900, 0,  400,  412,  414,  449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400 at 70Hz */
+    { MODEPREFIX("1280x1024"), 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024 at 75Hz */
+    { MODEPREFIX("1024x768"),   78800, 1024, 1040, 1136, 1312, 0,  768,  769,  772,  800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768 at 75Hz */
+    { MODEPREFIX("1024x768"),   75000, 1024, 1048, 1184, 1328, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768 at 70Hz */
+    { MODEPREFIX("1024x768"),   65000, 1024, 1048, 1184, 1344, 0,  768,  771,  777,  806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768 at 60Hz */
+    { MODEPREFIX("1024x768"),   44900, 1024, 1032, 1208, 1264, 0,  768,  768,  776,  817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768 at 43Hz */
+    { MODEPREFIX("832x624"),    57284,  832,  864,  928, 1152, 0,  624,  625,  628,  667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624 at 75Hz */
+    { MODEPREFIX("800x600"),    49500,  800,  816,  896, 1056, 0,  600,  601,  604,  625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600 at 75Hz */
+    { MODEPREFIX("800x600"),    50000,  800,  856,  976, 1040, 0,  600,  637,  643,  666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600 at 72Hz */
+    { MODEPREFIX("1152x864"),  108000, 1152, 1216, 1344, 1600, 0,  864,  865,  868,  900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864 at 75Hz */
+};
+
+static DisplayModePtr
+DDCModesFromEstablished(int scrnIndex, struct established_timings *timing,
+			ddc_quirk_t quirks)
+{
+    DisplayModePtr Modes = NULL, Mode = NULL;
+    CARD32 bits = (timing->t1) | (timing->t2 << 8) |
+        ((timing->t_manu & 0x80) << 9);
+    int i;
+
+    for (i = 0; i < 17; i++) {
+        if (bits & (0x01 << i)) {
+            Mode = xf86DuplicateMode(&DDCEstablishedModes[i]);
+            Modes = xf86ModesAdd(Modes, Mode);
+        }
+    }
+
+    return Modes;
+}
+
+/*
+ *
+ */
+static DisplayModePtr
+DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing,
+			   ddc_quirk_t quirks)
+{
+    DisplayModePtr Modes = NULL, Mode = NULL;
+    int i;
+
+    for (i = 0; i < STD_TIMINGS; i++) {
+        if (timing[i].hsize && timing[i].vsize && timing[i].refresh) {
+            Mode =  xf86CVTMode(timing[i].hsize, timing[i].vsize,
+                                timing[i].refresh, FALSE, FALSE);
+	    Mode->type = M_T_DRIVER;
+            Modes = xf86ModesAdd(Modes, Mode);
+        }
+    }
+
+    return Modes;
+}
+
+/*
+ *
+ */
+static DisplayModePtr
+DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
+			  int preferred, ddc_quirk_t quirks)
+{
+    DisplayModePtr Mode;
+
+    /* We don't do stereo */
+    if (timing->stereo) {
+        xf86DrvMsg(scrnIndex, X_INFO,
+		   "%s: Ignoring: We don't handle stereo.\n", __func__);
+        return NULL;
+    }
+
+    /* We only do seperate sync currently */
+    if (timing->sync != 0x03) {
+         xf86DrvMsg(scrnIndex, X_INFO,
+		    "%s: %dx%d Warning: We only handle seperate"
+                    " sync.\n", __func__, timing->h_active, timing->v_active);
+    }
+
+    Mode = xnfalloc(sizeof(DisplayModeRec));
+    memset(Mode, 0, sizeof(DisplayModeRec));
+
+    Mode->type = M_T_DRIVER;
+    if (preferred)
+	Mode->type |= M_T_PREFERRED;
+
+    if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) &&
+	timing->clock == 135000000 )
+        Mode->Clock = 108880;
+    else
+        Mode->Clock = timing->clock / 1000.0;
+
+    Mode->HDisplay = timing->h_active;
+    Mode->HSyncStart = timing->h_active + timing->h_sync_off;
+    Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width;
+    Mode->HTotal = timing->h_active + timing->h_blanking;
+
+    Mode->VDisplay = timing->v_active;
+    Mode->VSyncStart = timing->v_active + timing->v_sync_off;
+    Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width;
+    Mode->VTotal = timing->v_active + timing->v_blanking;
+
+    xf86SetModeDefaultName(Mode);
+
+    /* We ignore h/v_size and h/v_border for now. */
+
+    if (timing->interlaced)
+        Mode->Flags |= V_INTERLACE;
+
+    if (quirks & DDC_QUIRK_DT_SYNC_HM_VP)
+	Mode->Flags |= V_NHSYNC | V_PVSYNC;
+    else
+    {
+	if (timing->misc & 0x02)
+	    Mode->Flags |= V_PHSYNC;
+	else
+	    Mode->Flags |= V_NHSYNC;
+    
+	if (timing->misc & 0x01)
+	    Mode->Flags |= V_PVSYNC;
+	else
+	    Mode->Flags |= V_NVSYNC;
+    }
+
+    return Mode;
+}
+
+DisplayModePtr
+xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
+{
+    int preferred, i;
+    DisplayModePtr  Modes = NULL, Mode;
+    ddc_quirk_t	    quirks;
+
+    xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
+		DDC->vendor.name, DDC->vendor.prod_id);
+    quirks = DDC_QUIRK_NONE;
+    for (i = 0; ddc_quirks[i].detect; i++)
+	if (ddc_quirks[i].detect (scrnIndex, DDC))
+	{
+	    xf86DrvMsg (scrnIndex, X_INFO, "    EDID quirk: %s\n",
+			ddc_quirks[i].description);
+	    quirks |= ddc_quirks[i].quirk;
+	}
+    
+    preferred = PREFERRED_TIMING_MODE(DDC->features.msc);
+    if (quirks & DDC_QUIRK_PREFER_LARGE_60)
+	preferred = 0;
+
+    for (i = 0; i < DET_TIMINGS; i++) {
+	struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
+
+        switch (det_mon->type) {
+        case DT:
+            Mode = DDCModeFromDetailedTiming(scrnIndex,
+                                             &det_mon->section.d_timings,
+					     preferred,
+					     quirks);
+	    preferred = 0;
+            Modes = xf86ModesAdd(Modes, Mode);
+            break;
+        case DS_STD_TIMINGS:
+            Mode = DDCModesFromStandardTiming(scrnIndex,
+					      det_mon->section.std_t,
+					      quirks);
+            Modes = xf86ModesAdd(Modes, Mode);
+            break;
+        default:
+            break;
+        }
+    }
+
+    /* Add established timings */
+    Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
+    Modes = xf86ModesAdd(Modes, Mode);
+
+    /* Add standard timings */
+    Mode = DDCModesFromStandardTiming(scrnIndex, DDC->timings2, quirks);
+    Modes = xf86ModesAdd(Modes, Mode);
+
+    if (quirks & DDC_QUIRK_PREFER_LARGE_60)
+    {
+	DisplayModePtr	best = Modes;
+	for (Mode = Modes; Mode; Mode = Mode->next)
+	{
+	    if (Mode == best) continue;
+	    if (Mode->HDisplay * Mode->VDisplay > best->HDisplay * best->VDisplay)
+	    {
+		best = Mode;
+		continue;
+	    }
+	    if (Mode->HDisplay * Mode->VDisplay == best->HDisplay * best->VDisplay)
+	    {
+		double	mode_refresh = xf86ModeVRefresh (Mode);
+		double	best_refresh = xf86ModeVRefresh (best);
+		double	mode_dist = fabs(mode_refresh - 60.0);
+		double	best_dist = fabs(best_refresh - 60.0);
+		if (mode_dist < best_dist)
+		{
+		    best = Mode;
+		    continue;
+		}
+	    }
+	}
+	if (best)
+	    best->type |= M_T_PREFERRED;
+    }
+    return Modes;
+}
diff --git a/hw/xfree86/modes/xf86Modes.c b/hw/xfree86/modes/xf86Modes.c
new file mode 100644
index 0000000..d126e5e
--- /dev/null
+++ b/hw/xfree86/modes/xf86Modes.c
@@ -0,0 +1,635 @@
+/* -*- c-basic-offset: 4 -*- */
+/* $XdotOrg: xserver/xorg/hw/xfree86/common/xf86Mode.c,v 1.10 2006/03/07 16:00:57 libv Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Mode.c,v 1.69 2003/10/08 14:58:28 dawes Exp $ */
+/*
+ * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "xf86.h"
+#include "xf86Modes.h"
+#include "xf86Priv.h"
+
+extern XF86ConfigPtr xf86configptr;
+
+/**
+ * @file this file contains symbols from xf86Mode.c and friends that are static
+ * there but we still want to use.  We need to come up with better API here.
+ */
+
+#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0)
+/**
+ * Calculates the horizontal sync rate of a mode.
+ *
+ * Exact copy of xf86Mode.c's.
+ */
+double
+xf86ModeHSync(DisplayModePtr mode)
+{
+    double hsync = 0.0;
+    
+    if (mode->HSync > 0.0)
+	    hsync = mode->HSync;
+    else if (mode->HTotal > 0)
+	    hsync = (float)mode->Clock / (float)mode->HTotal;
+
+    return hsync;
+}
+
+/**
+ * Calculates the vertical refresh rate of a mode.
+ *
+ * Exact copy of xf86Mode.c's.
+ */
+double
+xf86ModeVRefresh(DisplayModePtr mode)
+{
+    double refresh = 0.0;
+
+    if (mode->VRefresh > 0.0)
+	refresh = mode->VRefresh;
+    else if (mode->HTotal > 0 && mode->VTotal > 0) {
+	refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
+	if (mode->Flags & V_INTERLACE)
+	    refresh *= 2.0;
+	if (mode->Flags & V_DBLSCAN)
+	    refresh /= 2.0;
+	if (mode->VScan > 1)
+	    refresh /= (float)(mode->VScan);
+    }
+    return refresh;
+}
+
+/** Sets a default mode name of <width>x<height> on a mode. */
+void
+xf86SetModeDefaultName(DisplayModePtr mode)
+{
+    if (mode->name != NULL)
+	xfree(mode->name);
+
+    mode->name = XNFprintf("%dx%d", mode->HDisplay, mode->VDisplay);
+}
+
+/*
+ * xf86SetModeCrtc
+ *
+ * Initialises the Crtc parameters for a mode.  The initialisation includes
+ * adjustments for interlaced and double scan modes.
+ *
+ * Exact copy of xf86Mode.c's.
+ */
+void
+xf86SetModeCrtc(DisplayModePtr p, int adjustFlags)
+{
+    if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN))
+	return;
+
+    p->CrtcHDisplay             = p->HDisplay;
+    p->CrtcHSyncStart           = p->HSyncStart;
+    p->CrtcHSyncEnd             = p->HSyncEnd;
+    p->CrtcHTotal               = p->HTotal;
+    p->CrtcHSkew                = p->HSkew;
+    p->CrtcVDisplay             = p->VDisplay;
+    p->CrtcVSyncStart           = p->VSyncStart;
+    p->CrtcVSyncEnd             = p->VSyncEnd;
+    p->CrtcVTotal               = p->VTotal;
+    if (p->Flags & V_INTERLACE) {
+	if (adjustFlags & INTERLACE_HALVE_V) {
+	    p->CrtcVDisplay         /= 2;
+	    p->CrtcVSyncStart       /= 2;
+	    p->CrtcVSyncEnd         /= 2;
+	    p->CrtcVTotal           /= 2;
+	}
+	/* Force interlaced modes to have an odd VTotal */
+	/* maybe we should only do this when INTERLACE_HALVE_V is set? */
+	p->CrtcVTotal |= 1;
+    }
+
+    if (p->Flags & V_DBLSCAN) {
+        p->CrtcVDisplay         *= 2;
+        p->CrtcVSyncStart       *= 2;
+        p->CrtcVSyncEnd         *= 2;
+        p->CrtcVTotal           *= 2;
+    }
+    if (p->VScan > 1) {
+        p->CrtcVDisplay         *= p->VScan;
+        p->CrtcVSyncStart       *= p->VScan;
+        p->CrtcVSyncEnd         *= p->VScan;
+        p->CrtcVTotal           *= p->VScan;
+    }
+    p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay);
+    p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal);
+    p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay);
+    p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal);
+
+    p->CrtcHAdjusted = FALSE;
+    p->CrtcVAdjusted = FALSE;
+}
+
+/**
+ * Allocates and returns a copy of pMode, including pointers within pMode.
+ */
+DisplayModePtr
+xf86DuplicateMode(DisplayModePtr pMode)
+{
+    DisplayModePtr pNew;
+
+    pNew = xnfalloc(sizeof(DisplayModeRec));
+    *pNew = *pMode;
+    pNew->next = NULL;
+    pNew->prev = NULL;
+    if (pNew->name == NULL) {
+	xf86SetModeDefaultName(pMode);
+    } else {
+	pNew->name = xnfstrdup(pMode->name);
+    }
+
+    return pNew;
+}
+
+/**
+ * Duplicates every mode in the given list and returns a pointer to the first
+ * mode.
+ *
+ * \param modeList doubly-linked mode list
+ */
+DisplayModePtr
+xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList)
+{
+    DisplayModePtr first = NULL, last = NULL;
+    DisplayModePtr mode;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	DisplayModePtr new;
+
+	new = xf86DuplicateMode(mode);
+
+	/* Insert pNew into modeList */
+	if (last) {
+	    last->next = new;
+	    new->prev = last;
+	} else {
+	    first = new;
+	    new->prev = NULL;
+	}
+	new->next = NULL;
+	last = new;
+    }
+
+    return first;
+}
+
+/**
+ * Returns true if the given modes should program to the same timings.
+ *
+ * This doesn't use Crtc values, as it might be used on ModeRecs without the
+ * Crtc values set.  So, it's assumed that the other numbers are enough.
+ *
+ * This isn't in xf86Modes.c, but it might deserve to be there.
+ */
+Bool
+xf86ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2)
+{
+     if (pMode1->Clock == pMode2->Clock &&
+	 pMode1->HDisplay == pMode2->HDisplay &&
+	 pMode1->HSyncStart == pMode2->HSyncStart &&
+	 pMode1->HSyncEnd == pMode2->HSyncEnd &&
+	 pMode1->HTotal == pMode2->HTotal &&
+	 pMode1->HSkew == pMode2->HSkew &&
+	 pMode1->VDisplay == pMode2->VDisplay &&
+	 pMode1->VSyncStart == pMode2->VSyncStart &&
+	 pMode1->VSyncEnd == pMode2->VSyncEnd &&
+	 pMode1->VTotal == pMode2->VTotal &&
+	 pMode1->VScan == pMode2->VScan &&
+	 pMode1->Flags == pMode2->Flags)
+     {
+	return TRUE;
+     } else {
+	return FALSE;
+     }
+}
+
+/* exact copy of xf86Mode.c */
+static void
+add(char **p, char *new)
+{
+    *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2);
+    strcat(*p, " ");
+    strcat(*p, new);
+}
+
+/**
+ * Print out a modeline.
+ *
+ * Convenient VRefresh printing was added, though, compared to xf86Mode.c
+ */
+void
+xf86PrintModeline(int scrnIndex,DisplayModePtr mode)
+{
+    char tmp[256];
+    char *flags = xnfcalloc(1, 1);
+
+    if (mode->HSkew) { 
+	snprintf(tmp, 256, "hskew %i", mode->HSkew); 
+	add(&flags, tmp);
+    }
+    if (mode->VScan) { 
+	snprintf(tmp, 256, "vscan %i", mode->VScan); 
+	add(&flags, tmp);
+    }
+    if (mode->Flags & V_INTERLACE) add(&flags, "interlace");
+    if (mode->Flags & V_CSYNC) add(&flags, "composite");
+    if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan");
+    if (mode->Flags & V_BCAST) add(&flags, "bcast");
+    if (mode->Flags & V_PHSYNC) add(&flags, "+hsync");
+    if (mode->Flags & V_NHSYNC) add(&flags, "-hsync");
+    if (mode->Flags & V_PVSYNC) add(&flags, "+vsync");
+    if (mode->Flags & V_NVSYNC) add(&flags, "-vsync");
+    if (mode->Flags & V_PCSYNC) add(&flags, "+csync");
+    if (mode->Flags & V_NCSYNC) add(&flags, "-csync");
+#if 0
+    if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2");
+#endif
+    xf86DrvMsg(scrnIndex, X_INFO,
+		   "Modeline \"%s\"x%.01f  %6.2f  %i %i %i %i  %i %i %i %i%s "
+		   "(%.01f kHz)\n",
+		   mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay,
+		   mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
+		   mode->VDisplay, mode->VSyncStart, mode->VSyncEnd,
+		   mode->VTotal, flags, xf86ModeHSync(mode));
+    xfree(flags);
+}
+#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */
+
+/**
+ * Marks as bad any modes with unsupported flags.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ * \param flags flags supported by the driver.
+ *
+ * \bug only V_INTERLACE and V_DBLSCAN are supported.  Is that enough?
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+			    int flags)
+{
+    DisplayModePtr mode;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE))
+	    mode->status = MODE_NO_INTERLACE;
+	if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN))
+	    mode->status = MODE_NO_DBLESCAN;
+    }
+}
+
+/**
+ * Marks as bad any modes extending beyond the given max X, Y, or pitch.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+			  int maxX, int maxY, int maxPitch)
+{
+    DisplayModePtr mode;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	if (maxPitch > 0 && mode->HDisplay > maxPitch)
+	    mode->status = MODE_BAD_WIDTH;
+
+	if (maxX > 0 && mode->HDisplay > maxX)
+	    mode->status = MODE_VIRTUAL_X;
+
+	if (maxY > 0 && mode->VDisplay > maxY)
+	    mode->status = MODE_VIRTUAL_Y;
+
+	if (mode->next == modeList)
+	    break;
+    }
+}
+
+/**
+ * Marks as bad any modes that aren't supported by the given monitor's
+ * hsync and vrefresh ranges.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+			  MonPtr mon)
+{
+    DisplayModePtr mode;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	Bool bad;
+	int i;
+
+	bad = TRUE;
+	for (i = 0; i < mon->nHsync; i++) {
+	    if (xf86ModeHSync(mode) >= mon->hsync[i].lo &&
+		xf86ModeHSync(mode) <= mon->hsync[i].hi)
+	    {
+		bad = FALSE;
+	    }
+	}
+	if (bad)
+	    mode->status = MODE_HSYNC;
+
+	bad = TRUE;
+	for (i = 0; i < mon->nVrefresh; i++) {
+	    if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo &&
+		xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi)
+	    {
+		bad = FALSE;
+	    }
+	}
+	if (bad)
+	    mode->status = MODE_VSYNC;
+
+	if (mode->next == modeList)
+	    break;
+    }
+}
+
+/**
+ * Marks as bad any modes extending beyond outside of the given clock ranges.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ * \param min pointer to minimums of clock ranges
+ * \param max pointer to maximums of clock ranges
+ * \param n_ranges number of ranges.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+			    int *min, int *max, int n_ranges)
+{
+    DisplayModePtr mode;
+    int i;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	Bool good = FALSE;
+	for (i = 0; i < n_ranges; i++) {
+	    if (mode->Clock >= min[i] && mode->Clock <= max[i]) {
+		good = TRUE;
+		break;
+	    }
+	}
+	if (!good)
+	    mode->status = MODE_CLOCK_RANGE;
+    }
+}
+
+/**
+ * If the user has specified a set of mode names to use, mark as bad any modes
+ * not listed.
+ *
+ * The user mode names specified are prefixes to names of modes, so "1024x768"
+ * will match modes named "1024x768", "1024x768x75", "1024x768-good", but
+ * "1024x768x75" would only match "1024x768x75" from that list.
+ *
+ * MODE_BAD is used as the rejection flag, for lack of a better flag.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList)
+{
+    DisplayModePtr mode;
+
+    if (pScrn->display->modes[0] == NULL)
+	return;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	int i;
+	Bool good = FALSE;
+
+	for (i = 0; pScrn->display->modes[i] != NULL; i++) {
+	    if (strncmp(pScrn->display->modes[i], mode->name,
+			strlen(pScrn->display->modes[i])) == 0) {
+		good = TRUE;
+		break;
+	    }
+	}
+	if (!good)
+	    mode->status = MODE_BAD;
+    }
+}
+
+
+/**
+ * Frees any modes from the list with a status other than MODE_OK.
+ *
+ * \param modeList pointer to a doubly-linked or circular list of modes.
+ * \param verbose determines whether the reason for mode invalidation is
+ *	  printed.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
+			  Bool verbose)
+{
+    DisplayModePtr mode;
+
+    for (mode = *modeList; mode != NULL;) {
+	DisplayModePtr next = mode->next, first = *modeList;
+
+	if (mode->status != MODE_OK) {
+	    if (verbose) {
+		char *type = "";
+		if (mode->type & M_T_BUILTIN)
+		    type = "built-in ";
+		else if (mode->type & M_T_DEFAULT)
+		    type = "default ";
+		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+			   "Not using %smode \"%s\" (%s)\n", type, mode->name,
+			   xf86ModeStatusToString(mode->status));
+	    }
+	    xf86DeleteMode(modeList, mode);
+	}
+
+	if (next == first)
+	    break;
+	mode = next;
+    }
+}
+
+/**
+ * Adds the new mode into the mode list, and returns the new list
+ *
+ * \param modes doubly-linked mode list.
+ */
+DisplayModePtr
+xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new)
+{
+    if (modes == NULL)
+	return new;
+
+    if (new) {
+	DisplayModePtr mode = modes;
+
+	while (mode->next)
+	    mode = mode->next;
+
+	mode->next = new;
+	new->prev = mode;
+    }
+
+    return modes;
+}
+
+/**
+ * Build a mode list from a list of config file modes
+ */
+static DisplayModePtr
+xf86GetConfigModes (XF86ConfModeLinePtr conf_mode)
+{
+    DisplayModePtr  head = NULL, prev = NULL, mode;
+    
+    for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next)
+    {
+        mode = xcalloc(1, sizeof(DisplayModeRec));
+	if (!mode)
+	    continue;
+        mode->name       = xstrdup(conf_mode->ml_identifier);
+	if (!mode->name)
+	{
+	    xfree (mode);
+	    continue;
+	}
+	mode->type       = 0;
+        mode->Clock      = conf_mode->ml_clock;
+        mode->HDisplay   = conf_mode->ml_hdisplay;
+        mode->HSyncStart = conf_mode->ml_hsyncstart;
+        mode->HSyncEnd   = conf_mode->ml_hsyncend;
+        mode->HTotal     = conf_mode->ml_htotal;
+        mode->VDisplay   = conf_mode->ml_vdisplay;
+        mode->VSyncStart = conf_mode->ml_vsyncstart;
+        mode->VSyncEnd   = conf_mode->ml_vsyncend;
+        mode->VTotal     = conf_mode->ml_vtotal;
+        mode->Flags      = conf_mode->ml_flags;
+        mode->HSkew      = conf_mode->ml_hskew;
+        mode->VScan      = conf_mode->ml_vscan;
+
+        mode->prev = prev;
+	mode->next = NULL;
+	if (prev)
+	    prev->next = mode;
+	else
+	    head = mode;
+	prev = mode;
+    }
+    return head;
+}
+
+/**
+ * Build a mode list from a monitor configuration
+ */
+DisplayModePtr
+xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor)
+{
+    DisplayModePtr	    modes = NULL;
+    XF86ConfModesLinkPtr    modes_link;
+    
+    if (!conf_monitor)
+	return NULL;
+
+    /*
+     * first we collect the mode lines from the UseModes directive
+     */
+    for (modes_link = conf_monitor->mon_modes_sect_lst; 
+	 modes_link; 
+	 modes_link = modes_link->list.next)
+    {
+	/* If this modes link hasn't been resolved, go look it up now */
+	if (!modes_link->ml_modes)
+	    modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str, 
+						  xf86configptr->conf_modes_lst);
+	if (modes_link->ml_modes)
+	    modes = xf86ModesAdd (modes,
+				  xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst));
+    }
+
+    return xf86ModesAdd (modes,
+			 xf86GetConfigModes (conf_monitor->mon_modeline_lst));
+}
+
+/**
+ * Build a mode list containing all of the default modes
+ */
+DisplayModePtr
+xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed)
+{
+    DisplayModePtr  head = NULL, prev = NULL, mode;
+    int		    i;
+
+    for (i = 0; xf86DefaultModes[i].name != NULL; i++)
+    {
+	DisplayModePtr	defMode = &xf86DefaultModes[i];
+	
+	if (!interlaceAllowed && (defMode->Flags & V_INTERLACE))
+	    continue;
+	if (!doubleScanAllowed && (defMode->Flags & V_DBLSCAN))
+	    continue;
+
+	mode = xalloc(sizeof(DisplayModeRec));
+	if (!mode)
+	    continue;
+        memcpy(mode,&xf86DefaultModes[i],sizeof(DisplayModeRec));
+        mode->name = xstrdup(xf86DefaultModes[i].name);
+        if (!mode->name)
+	{
+	    xfree (mode);
+	    continue;
+	}
+        mode->prev = prev;
+	mode->next = NULL;
+	if (prev)
+	    prev->next = mode;
+	else
+	    head = mode;
+	prev = mode;
+    }
+    return head;
+}
diff --git a/hw/xfree86/modes/xf86Modes.h b/hw/xfree86/modes/xf86Modes.h
new file mode 100644
index 0000000..60e2790
--- /dev/null
+++ b/hw/xfree86/modes/xf86Modes.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric at anholt.net>
+ *
+ */
+
+#ifndef _I830_XF86MODES_H_
+#define _I830_XF86MODES_H_
+#include "xorgVersion.h"
+#include "xf86Parser.h"
+#include "edid.h"
+#if XF86_MODES_RENAME
+#include "xf86Rename.h"
+#endif
+
+double xf86ModeHSync(DisplayModePtr mode);
+double xf86ModeVRefresh(DisplayModePtr mode);
+DisplayModePtr xf86DuplicateMode(DisplayModePtr pMode);
+DisplayModePtr xf86DuplicateModes(ScrnInfoPtr pScrn,
+				       DisplayModePtr modeList);
+void xf86SetModeDefaultName(DisplayModePtr mode);
+void xf86SetModeCrtc(DisplayModePtr p, int adjustFlags);
+Bool xf86ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2);
+void xf86PrintModeline(int scrnIndex,DisplayModePtr mode);
+DisplayModePtr xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new);
+
+DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC);
+DisplayModePtr xf86CVTMode(int HDisplay, int VDisplay, float VRefresh,
+			   Bool Reduced, Bool Interlaced);
+
+void
+xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+		       int flags);
+
+void
+xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+			int *min, int *max, int n_ranges);
+
+void
+xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+		      int maxX, int maxY, int maxPitch);
+
+void
+xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+		      MonPtr mon);
+
+void
+xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
+		      Bool verbose);
+
+void
+xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+		       int flags);
+
+void
+xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList);
+
+DisplayModePtr
+xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor);
+
+DisplayModePtr
+xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed);
+
+#endif /* _I830_XF86MODES_H_ */
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
new file mode 100644
index 0000000..bafe71f
--- /dev/null
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -0,0 +1,950 @@
+/* $XdotOrg: xc/programs/Xserver/hw/xfree86/common/xf86RandR.c,v 1.3 2004/07/30 21:53:09 eich Exp $ */
+/*
+ * $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86RandR.c,v 1.7tsi Exp $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "xf86.h"
+#include "os.h"
+#include "mibank.h"
+#include "globals.h"
+#include "xf86.h"
+#include "xf86Priv.h"
+#include "xf86DDC.h"
+#include "mipointer.h"
+#include "windowstr.h"
+#include <randrstr.h>
+#include <X11/extensions/render.h>
+
+#include "xf86Crtc.h"
+#include "xf86RandR12.h"
+
+typedef struct _xf86RandR12Info {
+    int				    virtualX;
+    int				    virtualY;
+    int				    mmWidth;
+    int				    mmHeight;
+    int				    maxX;
+    int				    maxY;
+    Rotation			    rotation; /* current mode */
+    Rotation                        supported_rotations; /* driver supported */
+} XF86RandRInfoRec, *XF86RandRInfoPtr;
+
+#ifdef RANDR_12_INTERFACE
+static Bool xf86RandR12Init12 (ScreenPtr pScreen);
+static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen);
+#endif
+
+static int	    xf86RandR12Index;
+static int	    xf86RandR12Generation;
+
+#define XF86RANDRINFO(p) \
+	((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr)
+
+static int
+xf86RandR12ModeRefresh (DisplayModePtr mode)
+{
+    if (mode->VRefresh)
+	return (int) (mode->VRefresh + 0.5);
+    else
+	return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
+}
+
+static Bool
+xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations)
+{
+    RRScreenSizePtr	    pSize;
+    ScrnInfoPtr		    scrp = XF86SCRNINFO(pScreen);
+    XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
+    DisplayModePtr	    mode;
+    int			    refresh0 = 60;
+    int			    maxX = 0, maxY = 0;
+
+    *rotations = randrp->supported_rotations;
+
+    if (randrp->virtualX == -1 || randrp->virtualY == -1)
+    {
+	randrp->virtualX = scrp->virtualX;
+	randrp->virtualY = scrp->virtualY;
+    }
+
+    /* Re-probe the outputs for new monitors or modes */
+    xf86ProbeOutputModes (scrp, 0, 0);
+    xf86SetScrnInfoModes (scrp);
+    xf86DiDGAReInit (pScreen);
+
+    for (mode = scrp->modes; ; mode = mode->next)
+    {
+	int refresh = xf86RandR12ModeRefresh (mode);
+	if (randrp->maxX == 0 || randrp->maxY == 0)
+	{
+		if (maxX < mode->HDisplay)
+			maxX = mode->HDisplay;
+		if (maxY < mode->VDisplay)
+			maxY = mode->VDisplay;
+	}
+	if (mode == scrp->modes)
+	    refresh0 = refresh;
+	pSize = RRRegisterSize (pScreen,
+				mode->HDisplay, mode->VDisplay,
+				randrp->mmWidth, randrp->mmHeight);
+	if (!pSize)
+	    return FALSE;
+	RRRegisterRate (pScreen, pSize, refresh);
+
+	if (xf86ModesEqual(mode, scrp->currentMode) &&
+	    mode->HDisplay == scrp->virtualX &&
+	    mode->VDisplay == scrp->virtualY)
+	{
+	    RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize);
+	}
+	if (mode->next == scrp->modes)
+	    break;
+    }
+
+    if (randrp->maxX == 0 || randrp->maxY == 0)
+    {
+	randrp->maxX = maxX;
+	randrp->maxY = maxY;
+    }
+
+    if (scrp->currentMode->HDisplay != randrp->virtualX ||
+	scrp->currentMode->VDisplay != randrp->virtualY)
+    {
+	pSize = RRRegisterSize (pScreen,
+				randrp->virtualX, randrp->virtualY,
+				randrp->mmWidth,
+				randrp->mmHeight);
+	if (!pSize)
+	    return FALSE;
+	RRRegisterRate (pScreen, pSize, refresh0);
+	if (scrp->virtualX == randrp->virtualX &&
+	    scrp->virtualY == randrp->virtualY)
+	{
+	    RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize);
+	}
+    }
+
+    return TRUE;
+}
+
+static Bool
+xf86RandR12SetMode (ScreenPtr	    pScreen,
+		  DisplayModePtr    mode,
+		  Bool		    useVirtual,
+		  int		    mmWidth,
+		  int		    mmHeight)
+{
+    ScrnInfoPtr		scrp = XF86SCRNINFO(pScreen);
+    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
+    int			oldWidth = pScreen->width;
+    int			oldHeight = pScreen->height;
+    int			oldmmWidth = pScreen->mmWidth;
+    int			oldmmHeight = pScreen->mmHeight;
+    WindowPtr		pRoot = WindowTable[pScreen->myNum];
+    DisplayModePtr      currentMode = NULL;
+    Bool 		ret = TRUE;
+    PixmapPtr 		pspix = NULL;
+
+    if (pRoot)
+	(*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE);
+    if (useVirtual)
+    {
+	scrp->virtualX = randrp->virtualX;
+	scrp->virtualY = randrp->virtualY;
+    }
+    else
+    {
+	scrp->virtualX = mode->HDisplay;
+	scrp->virtualY = mode->VDisplay;
+    }
+
+    if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270))
+    {
+	/* If the screen is rotated 90 or 270 degrees, swap the sizes. */
+	pScreen->width = scrp->virtualY;
+	pScreen->height = scrp->virtualX;
+	pScreen->mmWidth = mmHeight;
+	pScreen->mmHeight = mmWidth;
+    }
+    else
+    {
+	pScreen->width = scrp->virtualX;
+	pScreen->height = scrp->virtualY;
+	pScreen->mmWidth = mmWidth;
+	pScreen->mmHeight = mmHeight;
+    }
+    if (scrp->currentMode == mode) {
+        /* Save current mode */
+        currentMode = scrp->currentMode;
+        /* Reset, just so we ensure the drivers SwitchMode is called */
+        scrp->currentMode = NULL;
+    }
+    /*
+     * We know that if the driver failed to SwitchMode to the rotated
+     * version, then it should revert back to it's prior mode.
+     */
+    if (!xf86SwitchMode (pScreen, mode))
+    {
+        ret = FALSE;
+	scrp->virtualX = pScreen->width = oldWidth;
+	scrp->virtualY = pScreen->height = oldHeight;
+	pScreen->mmWidth = oldmmWidth;
+	pScreen->mmHeight = oldmmHeight;
+        scrp->currentMode = currentMode;
+    }
+    /*
+     * Get the new Screen pixmap ptr as SwitchMode might have called
+     * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back...
+     * Unfortunately.
+     */
+    pspix = (*pScreen->GetScreenPixmap) (pScreen);
+    if (pspix->devPrivate.ptr)
+       scrp->pixmapPrivate = pspix->devPrivate;
+
+    /*
+     * Make sure the layout is correct
+     */
+    xf86ReconfigureLayout();
+
+    /*
+     * Make sure the whole screen is visible
+     */
+    xf86SetViewport (pScreen, pScreen->width, pScreen->height);
+    xf86SetViewport (pScreen, 0, 0);
+    if (pRoot)
+	(*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE);
+    return ret;
+}
+
+Bool
+xf86RandR12SetConfig (ScreenPtr		pScreen,
+		    Rotation		rotation,
+		    int			rate,
+		    RRScreenSizePtr	pSize)
+{
+    ScrnInfoPtr		scrp = XF86SCRNINFO(pScreen);
+    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
+    DisplayModePtr	mode;
+    int			px, py;
+    Bool		useVirtual = FALSE;
+    int			maxX = 0, maxY = 0;
+    Rotation		oldRotation = randrp->rotation;
+
+    randrp->rotation = rotation;
+
+    if (randrp->virtualX == -1 || randrp->virtualY == -1)
+    {
+	randrp->virtualX = scrp->virtualX;
+	randrp->virtualY = scrp->virtualY;
+    }
+
+    miPointerPosition (&px, &py);
+    for (mode = scrp->modes; ; mode = mode->next)
+    {
+	if (randrp->maxX == 0 || randrp->maxY == 0)
+	{
+		if (maxX < mode->HDisplay)
+			maxX = mode->HDisplay;
+		if (maxY < mode->VDisplay)
+			maxY = mode->VDisplay;
+	}
+	if (mode->HDisplay == pSize->width &&
+	    mode->VDisplay == pSize->height &&
+	    (rate == 0 || xf86RandR12ModeRefresh (mode) == rate))
+	    break;
+	if (mode->next == scrp->modes)
+	{
+	    if (pSize->width == randrp->virtualX &&
+		pSize->height == randrp->virtualY)
+	    {
+		mode = scrp->modes;
+		useVirtual = TRUE;
+		break;
+	    }
+    	    if (randrp->maxX == 0 || randrp->maxY == 0)
+    	    {
+		randrp->maxX = maxX;
+		randrp->maxY = maxY;
+    	    }
+	    return FALSE;
+	}
+    }
+
+    if (randrp->maxX == 0 || randrp->maxY == 0)
+    {
+	randrp->maxX = maxX;
+	randrp->maxY = maxY;
+    }
+
+    if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth,
+			   pSize->mmHeight)) {
+        randrp->rotation = oldRotation;
+	return FALSE;
+    }
+
+    /*
+     * Move the cursor back where it belongs; SwitchMode repositions it
+     */
+    if (pScreen == miPointerCurrentScreen ())
+    {
+        px = (px >= pScreen->width ? (pScreen->width - 1) : px);
+        py = (py >= pScreen->height ? (pScreen->height - 1) : py);
+
+	xf86SetViewport(pScreen, px, py);
+
+	(*pScreen->SetCursorPosition) (pScreen, px, py, FALSE);
+    }
+
+    return TRUE;
+}
+
+static Bool
+xf86RandR12ScreenSetSize (ScreenPtr	pScreen,
+			CARD16		width,
+			CARD16		height,
+			CARD32		mmWidth,
+			CARD32		mmHeight)
+{
+    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
+    ScrnInfoPtr		pScrn = XF86SCRNINFO(pScreen);
+    WindowPtr		pRoot = WindowTable[pScreen->myNum];
+    Bool 		ret = TRUE;
+
+    if (randrp->virtualX == -1 || randrp->virtualY == -1)
+    {
+	randrp->virtualX = pScrn->virtualX;
+	randrp->virtualY = pScrn->virtualY;
+    }
+    if (pRoot)
+	(*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE);
+    pScrn->virtualX = width;
+    pScrn->virtualY = height;
+
+    pScreen->width = pScrn->virtualX;
+    pScreen->height = pScrn->virtualY;
+    pScreen->mmWidth = mmWidth;
+    pScreen->mmHeight = mmHeight;
+
+    xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1);
+    xf86SetViewport (pScreen, 0, 0);
+    if (pRoot)
+	(*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE);
+#if RANDR_12_INTERFACE
+    if (WindowTable[pScreen->myNum])
+	RRScreenSizeNotify (pScreen);
+#endif
+    return ret;
+}
+
+Rotation
+xf86RandR12GetRotation(ScreenPtr pScreen)
+{
+    XF86RandRInfoPtr	    randrp = XF86RANDRINFO(pScreen);
+
+    return randrp->rotation;
+}
+
+Bool
+xf86RandR12CreateScreenResources (ScreenPtr pScreen)
+{
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
+    int			c;
+    int			width, height;
+    int			mmWidth, mmHeight;
+#ifdef PANORAMIX
+    /* XXX disable RandR when using Xinerama */
+    if (!noPanoramiXExtension)
+	return TRUE;
+#endif
+
+    /*
+     * Compute size of screen
+     */
+    width = 0; height = 0;
+    for (c = 0; c < config->num_crtc; c++)
+    {
+	xf86CrtcPtr crtc = config->crtc[c];
+	int	    crtc_width = crtc->x + crtc->mode.HDisplay;
+	int	    crtc_height = crtc->y + crtc->mode.VDisplay;
+	
+	if (crtc->enabled && crtc_width > width)
+	    width = crtc_width;
+	if (crtc->enabled && crtc_height > height)
+	    height = crtc_height;
+    }
+    
+    if (width && height)
+    {
+	/*
+	 * Compute physical size of screen
+	 */
+	if (monitorResolution) 
+	{
+	    mmWidth = width * 25.4 / monitorResolution;
+	    mmHeight = height * 25.4 / monitorResolution;
+	}
+	else
+	{
+	    mmWidth = pScreen->mmWidth;
+	    mmHeight = pScreen->mmHeight;
+	}
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "Setting screen physical size to %d x %d\n",
+		   mmWidth, mmHeight);
+	xf86RandR12ScreenSetSize (pScreen,
+				  width,
+				  height,
+				  mmWidth,
+				  mmHeight);
+    }
+
+    if (randrp->virtualX == -1 || randrp->virtualY == -1)
+    {
+	randrp->virtualX = pScrn->virtualX;
+	randrp->virtualY = pScrn->virtualY;
+    }
+#if RANDR_12_INTERFACE
+    if (xf86RandR12CreateScreenResources12 (pScreen))
+	return TRUE;
+#endif
+    return TRUE;
+}
+
+
+Bool
+xf86RandR12Init (ScreenPtr pScreen)
+{
+    rrScrPrivPtr	rp;
+    XF86RandRInfoPtr	randrp;
+
+#ifdef PANORAMIX
+    /* XXX disable RandR when using Xinerama */
+    if (!noPanoramiXExtension)
+	return TRUE;
+#endif
+    if (xf86RandR12Generation != serverGeneration)
+    {
+	xf86RandR12Index = AllocateScreenPrivateIndex();
+	xf86RandR12Generation = serverGeneration;
+    }
+
+    randrp = xalloc (sizeof (XF86RandRInfoRec));
+    if (!randrp)
+	return FALSE;
+
+    if (!RRScreenInit(pScreen))
+    {
+	xfree (randrp);
+	return FALSE;
+    }
+    rp = rrGetScrPriv(pScreen);
+    rp->rrGetInfo = xf86RandR12GetInfo;
+    rp->rrSetConfig = xf86RandR12SetConfig;
+
+    randrp->virtualX = -1;
+    randrp->virtualY = -1;
+    randrp->mmWidth = pScreen->mmWidth;
+    randrp->mmHeight = pScreen->mmHeight;
+
+    randrp->rotation = RR_Rotate_0; /* initial rotated mode */
+
+    randrp->supported_rotations = RR_Rotate_0;
+
+    randrp->maxX = randrp->maxY = 0;
+
+    pScreen->devPrivates[xf86RandR12Index].ptr = randrp;
+
+#if RANDR_12_INTERFACE
+    if (!xf86RandR12Init12 (pScreen))
+	return FALSE;
+#endif
+    return TRUE;
+}
+
+void
+xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations)
+{
+    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int			c;
+
+    randrp->supported_rotations = rotations;
+
+#if RANDR_12_INTERFACE
+    for (c = 0; c < config->num_crtc; c++) {
+	xf86CrtcPtr    crtc = config->crtc[c];
+
+	RRCrtcSetRotations (crtc->randr_crtc, rotations);
+    }
+#endif
+}
+
+void
+xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y)
+{
+    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+
+    if (xf86RandR12Generation != serverGeneration ||
+	XF86RANDRINFO(pScreen)->virtualX == -1)
+    {
+	*x = pScrn->virtualX;
+	*y = pScrn->virtualY;
+    } else {
+	XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
+
+	*x = randrp->virtualX;
+	*y = randrp->virtualY;
+    }
+}
+
+#if RANDR_12_INTERFACE
+static Bool
+xf86RandR12CrtcNotify (RRCrtcPtr	randr_crtc)
+{
+    ScreenPtr		pScreen = randr_crtc->pScreen;
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+    RRModePtr		randr_mode = NULL;
+    int			x;
+    int			y;
+    Rotation		rotation;
+    int			numOutputs;
+    RROutputPtr		*randr_outputs;
+    RROutputPtr		randr_output;
+    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
+    xf86OutputPtr	output;
+    int			i, j;
+    DisplayModePtr	mode = &crtc->mode;
+    Bool		ret;
+
+    randr_outputs = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr));
+    if (!randr_outputs)
+	return FALSE;
+    x = crtc->x;
+    y = crtc->y;
+    rotation = crtc->rotation;
+    numOutputs = 0;
+    randr_mode = NULL;
+    for (i = 0; i < config->num_output; i++)
+    {
+	output = config->output[i];
+	if (output->crtc == crtc)
+	{
+	    randr_output = output->randr_output;
+	    randr_outputs[numOutputs++] = randr_output;
+	    /*
+	     * We make copies of modes, so pointer equality 
+	     * isn't sufficient
+	     */
+	    for (j = 0; j < randr_output->numModes; j++)
+	    {
+		DisplayModePtr	outMode = randr_output->modes[j]->devPrivate;
+		if (xf86ModesEqual(mode, outMode))
+		{
+		    randr_mode = randr_output->modes[j];
+		    break;
+		}
+	    }
+	}
+    }
+    ret = RRCrtcNotify (randr_crtc, randr_mode, x, y,
+			rotation, numOutputs, randr_outputs);
+    DEALLOCATE_LOCAL(randr_outputs);
+    return ret;
+}
+
+static Bool
+xf86RandR12CrtcSet (ScreenPtr	pScreen,
+		  RRCrtcPtr	randr_crtc,
+		  RRModePtr	randr_mode,
+		  int		x,
+		  int		y,
+		  Rotation	rotation,
+		  int		num_randr_outputs,
+		  RROutputPtr	*randr_outputs)
+{
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
+    DisplayModePtr	mode = randr_mode ? randr_mode->devPrivate : NULL;
+    Bool		changed = FALSE;
+    int			o, ro;
+    xf86CrtcPtr		*save_crtcs;
+    Bool		save_enabled = crtc->enabled;
+
+    save_crtcs = ALLOCATE_LOCAL(config->num_crtc * sizeof (xf86CrtcPtr));
+    if ((mode != NULL) != crtc->enabled)
+	changed = TRUE;
+    else if (mode && !xf86ModesEqual (&crtc->mode, mode))
+	changed = TRUE;
+    
+    if (rotation != crtc->rotation)
+	changed = TRUE;
+
+    if (x != crtc->x || y != crtc->y)
+	changed = TRUE;
+    for (o = 0; o < config->num_output; o++) 
+    {
+	xf86OutputPtr  output = config->output[o];
+	xf86CrtcPtr    new_crtc;
+
+	save_crtcs[o] = output->crtc;
+	
+	if (output->crtc == crtc)
+	    new_crtc = NULL;
+	else
+	    new_crtc = output->crtc;
+	for (ro = 0; ro < num_randr_outputs; ro++) 
+	    if (output->randr_output == randr_outputs[ro])
+	    {
+		new_crtc = crtc;
+		break;
+	    }
+	if (new_crtc != output->crtc)
+	{
+	    changed = TRUE;
+	    output->crtc = new_crtc;
+	}
+    }
+    /* XXX need device-independent mode setting code through an API */
+    if (changed)
+    {
+	crtc->enabled = mode != NULL;
+
+	if (mode)
+	{
+	    if (!xf86CrtcSetMode (crtc, mode, rotation, x, y))
+	    {
+		crtc->enabled = save_enabled;
+		for (o = 0; o < config->num_output; o++)
+		{
+		    xf86OutputPtr	output = config->output[o];
+		    output->crtc = save_crtcs[o];
+		}
+		DEALLOCATE_LOCAL(save_crtcs);
+		return FALSE;
+	    }
+	    /*
+	     * Save the last successful setting for EnterVT
+	     */
+	    crtc->desiredMode = *mode;
+	    crtc->desiredRotation = rotation;
+	    crtc->desiredX = x;
+	    crtc->desiredY = y;
+	}
+	xf86DisableUnusedFunctions (pScrn);
+    }
+    DEALLOCATE_LOCAL(save_crtcs);
+    return xf86RandR12CrtcNotify (randr_crtc);
+}
+
+static Bool
+xf86RandR12CrtcSetGamma (ScreenPtr    pScreen,
+			 RRCrtcPtr    randr_crtc)
+{
+    xf86CrtcPtr		crtc = randr_crtc->devPrivate;
+
+    if (crtc->funcs->gamma_set == NULL)
+	return FALSE;
+
+    crtc->funcs->gamma_set(crtc, randr_crtc->gammaRed, randr_crtc->gammaGreen,
+			   randr_crtc->gammaBlue, randr_crtc->gammaSize);
+
+    return TRUE;
+}
+
+static Bool
+xf86RandR12OutputSetProperty (ScreenPtr pScreen,
+			      RROutputPtr randr_output,
+			      Atom property,
+			      RRPropertyValuePtr value)
+{
+    xf86OutputPtr output = randr_output->devPrivate;
+
+    /* If we don't have any property handler, then we don't care what the
+     * user is setting properties to.
+     */
+    if (output->funcs->set_property == NULL)
+	return TRUE;
+
+    return output->funcs->set_property(output, property, value);
+}
+
+/**
+ * Given a list of xf86 modes and a RandR Output object, construct
+ * RandR modes and assign them to the output
+ */
+static Bool
+xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes)
+{
+    DisplayModePtr  mode;
+    RRModePtr	    *rrmodes = NULL;
+    int		    nmode = 0;
+    int		    npreferred = 0;
+    Bool	    ret = TRUE;
+    int		    pref;
+
+    for (mode = modes; mode; mode = mode->next)
+	nmode++;
+
+    if (nmode) {
+	rrmodes = xalloc (nmode * sizeof (RRModePtr));
+	
+	if (!rrmodes)
+	    return FALSE;
+	nmode = 0;
+
+	for (pref = 1; pref >= 0; pref--) {
+	    for (mode = modes; mode; mode = mode->next) {
+		if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) {
+		    xRRModeInfo		modeInfo;
+		    RRModePtr		rrmode;
+		    
+		    modeInfo.nameLength = strlen (mode->name);
+		    modeInfo.width = mode->HDisplay;
+		    modeInfo.dotClock = mode->Clock * 1000;
+		    modeInfo.hSyncStart = mode->HSyncStart;
+		    modeInfo.hSyncEnd = mode->HSyncEnd;
+		    modeInfo.hTotal = mode->HTotal;
+		    modeInfo.hSkew = mode->HSkew;
+
+		    modeInfo.height = mode->VDisplay;
+		    modeInfo.vSyncStart = mode->VSyncStart;
+		    modeInfo.vSyncEnd = mode->VSyncEnd;
+		    modeInfo.vTotal = mode->VTotal;
+		    modeInfo.modeFlags = mode->Flags;
+
+		    rrmode = RRModeGet (&modeInfo, mode->name);
+		    if (rrmode) {
+			rrmode->devPrivate = mode;
+			rrmodes[nmode++] = rrmode;
+			npreferred += pref;
+		    }
+		}
+	    }
+	}
+    }
+    
+    ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred);
+    xfree (rrmodes);
+    return ret;
+}
+
+/*
+ * Mirror the current mode configuration to RandR
+ */
+static Bool
+xf86RandR12SetInfo12 (ScreenPtr pScreen)
+{
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+    RROutputPtr		*clones;
+    RRCrtcPtr		*crtcs;
+    int			ncrtc;
+    int			o, c, l;
+    RRCrtcPtr		randr_crtc;
+    int			nclone;
+    
+    clones = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr));
+    crtcs = ALLOCATE_LOCAL (config->num_crtc * sizeof (RRCrtcPtr));
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr	output = config->output[o];
+	
+	ncrtc = 0;
+	for (c = 0; c < config->num_crtc; c++)
+	    if (output->possible_crtcs & (1 << c))
+		crtcs[ncrtc++] = config->crtc[c]->randr_crtc;
+
+	if (output->crtc)
+	    randr_crtc = output->crtc->randr_crtc;
+	else
+	    randr_crtc = NULL;
+
+	if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc))
+	{
+	    DEALLOCATE_LOCAL (crtcs);
+	    DEALLOCATE_LOCAL (clones);
+	    return FALSE;
+	}
+
+	RROutputSetCrtc (output->randr_output, randr_crtc);
+	RROutputSetPhysicalSize(output->randr_output, 
+				output->mm_width,
+				output->mm_height);
+	xf86RROutputSetModes (output->randr_output, output->probed_modes);
+
+	switch (output->status) {
+	case XF86OutputStatusConnected:
+	    RROutputSetConnection (output->randr_output, RR_Connected);
+	    break;
+	case XF86OutputStatusDisconnected:
+	    RROutputSetConnection (output->randr_output, RR_Disconnected);
+	    break;
+	case XF86OutputStatusUnknown:
+	    RROutputSetConnection (output->randr_output, RR_UnknownConnection);
+	    break;
+	}
+
+	RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order);
+
+	/*
+	 * Valid clones
+	 */
+	nclone = 0;
+	for (l = 0; l < config->num_output; l++)
+	{
+	    xf86OutputPtr	    clone = config->output[l];
+	    
+	    if (l != o && (output->possible_clones & (1 << l)))
+		clones[nclone++] = clone->randr_output;
+	}
+	if (!RROutputSetClones (output->randr_output, clones, nclone))
+	{
+	    DEALLOCATE_LOCAL (crtcs);
+	    DEALLOCATE_LOCAL (clones);
+	    return FALSE;
+	}
+    }
+    DEALLOCATE_LOCAL (crtcs);
+    DEALLOCATE_LOCAL (clones);
+    return TRUE;
+}
+
+
+
+/*
+ * Query the hardware for the current state, then mirror
+ * that to RandR
+ */
+static Bool
+xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations)
+{
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+
+    xf86ProbeOutputModes (pScrn, 0, 0);
+    xf86SetScrnInfoModes (pScrn);
+    xf86DiDGAReInit (pScreen);
+    return xf86RandR12SetInfo12 (pScreen);
+}
+
+static Bool
+xf86RandR12CreateObjects12 (ScreenPtr pScreen)
+{
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int			c;
+    int			o;
+    
+    if (!RRInit ())
+	return FALSE;
+
+    /*
+     * Configure crtcs
+     */
+    for (c = 0; c < config->num_crtc; c++)
+    {
+	xf86CrtcPtr    crtc = config->crtc[c];
+	
+	crtc->randr_crtc = RRCrtcCreate (crtc);
+	RRCrtcAttachScreen (crtc->randr_crtc, pScreen);
+	RRCrtcGammaSetSize (crtc->randr_crtc, 256);
+    }
+    /*
+     * Configure outputs
+     */
+    for (o = 0; o < config->num_output; o++)
+    {
+	xf86OutputPtr	output = config->output[o];
+
+	output->randr_output = RROutputCreate (output->name, 
+					       strlen (output->name),
+					       output);
+	RROutputAttachScreen (output->randr_output, pScreen);
+
+	if (output->funcs->create_resources != NULL)
+	    output->funcs->create_resources(output);
+    }
+    return TRUE;
+}
+
+static Bool
+xf86RandR12CreateScreenResources12 (ScreenPtr pScreen)
+{
+    int			c;
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    XF86RandRInfoPtr	randrp = XF86RANDRINFO(pScreen);
+    xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+    for (c = 0; c < config->num_crtc; c++)
+	xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
+    
+    
+    RRScreenSetSizeRange (pScreen, 320, 240,
+			  randrp->virtualX, randrp->virtualY);
+    return TRUE;
+}
+
+static void
+xf86RandR12PointerMoved (int scrnIndex, int x, int y)
+{
+}
+
+static Bool
+xf86RandR12Init12 (ScreenPtr pScreen)
+{
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    rrScrPrivPtr	rp = rrGetScrPriv(pScreen);
+
+    rp->rrGetInfo = xf86RandR12GetInfo12;
+    rp->rrScreenSetSize = xf86RandR12ScreenSetSize;
+    rp->rrCrtcSet = xf86RandR12CrtcSet;
+    rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
+    rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
+    rp->rrSetConfig = NULL;
+    pScrn->PointerMoved = xf86RandR12PointerMoved;
+    if (!xf86RandR12CreateObjects12 (pScreen))
+	return FALSE;
+
+    /*
+     * Configure output modes
+     */
+    if (!xf86RandR12SetInfo12 (pScreen))
+	return FALSE;
+    return TRUE;
+}
+
+#endif
+
+Bool
+xf86RandR12PreInit (ScrnInfoPtr pScrn)
+{
+    return TRUE;
+}
diff --git a/hw/xfree86/modes/xf86RandR12.h b/hw/xfree86/modes/xf86RandR12.h
new file mode 100644
index 0000000..8a4668b
--- /dev/null
+++ b/hw/xfree86/modes/xf86RandR12.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _XF86_RANDR_H_
+#define _XF86_RANDR_H_
+#include <randrstr.h>
+#include <X11/extensions/render.h>
+
+Bool xf86RandR12CreateScreenResources (ScreenPtr pScreen);
+Bool xf86RandR12Init(ScreenPtr pScreen);
+void xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotation);
+Bool xf86RandR12SetConfig(ScreenPtr pScreen, Rotation rotation, int rate,
+			RRScreenSizePtr pSize);
+Rotation xf86RandR12GetRotation(ScreenPtr pScreen);
+void xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y);
+Bool xf86RandR12PreInit (ScrnInfoPtr pScrn);
+
+#endif /* _XF86_RANDR_H_ */
diff --git a/hw/xfree86/modes/xf86Rename.h b/hw/xfree86/modes/xf86Rename.h
new file mode 100644
index 0000000..a00253d
--- /dev/null
+++ b/hw/xfree86/modes/xf86Rename.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _XF86RENAME_H_
+#define _XF86RENAME_H_
+
+#include "local_xf86Rename.h"
+
+#define xf86CrtcConfigInit XF86NAME(xf86CrtcConfigInit)
+#define xf86CrtcConfigPrivateIndex XF86NAME(xf86CrtcConfigPrivateIndex)
+#define xf86CrtcCreate XF86NAME(xf86CrtcCreate)
+#define xf86CrtcDestroy XF86NAME(xf86CrtcDestroy)
+#define xf86CrtcInUse XF86NAME(xf86CrtcInUse)
+#define xf86CrtcRotate XF86NAME(xf86CrtcRotate)
+#define xf86CrtcSetMode XF86NAME(xf86CrtcSetMode)
+#define xf86CrtcSetSizeRange XF86NAME(xf86CrtcSetSizeRange)
+#define xf86CVTMode XF86NAME(xf86CVTMode)
+#define xf86DisableUnusedFunctions XF86NAME(xf86DisableUnusedFunctions)
+#define xf86DPMSSet XF86NAME(xf86DPMSSet)
+#define xf86DuplicateMode XF86NAME(xf86DuplicateMode)
+#define xf86DuplicateModes XF86NAME(xf86DuplicateModes)
+#define xf86GetDefaultModes XF86NAME(xf86GetDefaultModes)
+#define xf86GetMonitorModes XF86NAME(xf86GetMonitorModes)
+#define xf86InitialConfiguration XF86NAME(xf86InitialConfiguration)
+#define xf86ModeHSync XF86NAME(xf86ModeHSync)
+#define xf86ModesAdd XF86NAME(xf86ModesAdd)
+#define xf86ModesEqual XF86NAME(xf86ModesEqual)
+#define xf86ModeVRefresh XF86NAME(xf86ModeVRefresh)
+#define xf86OutputCreate XF86NAME(xf86OutputCreate)
+#define xf86OutputDestroy XF86NAME(xf86OutputDestroy)
+#define xf86OutputGetEDID XF86NAME(xf86OutputGetEDID)
+#define xf86OutputGetEDIDModes XF86NAME(xf86OutputGetEDIDModes)
+#define xf86OutputRename XF86NAME(xf86OutputRename)
+#define xf86OutputSetEDID XF86NAME(xf86OutputSetEDID)
+#define xf86PrintModeline XF86NAME(xf86PrintModeline)
+#define xf86ProbeOutputModes XF86NAME(xf86ProbeOutputModes)
+#define xf86PruneInvalidModes XF86NAME(xf86PruneInvalidModes)
+#define xf86SetModeCrtc XF86NAME(xf86SetModeCrtc)
+#define xf86SetModeDefaultName XF86NAME(xf86SetModeDefaultName)
+#define xf86SetScrnInfoModes XF86NAME(xf86SetScrnInfoModes)
+#define xf86ValidateModesClocks XF86NAME(xf86ValidateModesClocks)
+#define xf86ValidateModesFlags XF86NAME(xf86ValidateModesFlags)
+#define xf86ValidateModesSize XF86NAME(xf86ValidateModesSize)
+#define xf86ValidateModesSync XF86NAME(xf86ValidateModesSync)
+#define xf86ValidateModesUserConfig XF86NAME(xf86ValidateModesUserConfig)
+#define xf86DiDGAInit XF86NAME(xf86DiDGAInit)
+#define xf86DiDGAReInit XF86NAME(xf86DiDGAReInit)
+#define xf86DDCGetModes XF86NAME(xf86DDCGetModes)
+#define xf86RandR12CreateScreenResources XF86NAME(xf86RandR12CreateScreenResources)
+#define xf86RandR12GetOriginalVirtualSize XF86NAME(xf86RandR12GetOriginalVirtualSize)
+#define xf86RandR12GetRotation XF86NAME(xf86RandR12GetRotation)
+#define xf86RandR12Init XF86NAME(xf86RandR12Init)
+#define xf86RandR12PreInit XF86NAME(xf86RandR12PreInit)
+#define xf86RandR12SetConfig XF86NAME(xf86RandR12SetConfig)
+#define xf86RandR12SetRotations XF86NAME(xf86RandR12SetRotations)
+#define xf86SaveScreen XF86NAME(xf86SaveScreen)
+
+#endif /* _XF86RENAME_H_ */
diff --git a/hw/xfree86/modes/xf86Rotate.c b/hw/xfree86/modes/xf86Rotate.c
new file mode 100644
index 0000000..1e79063
--- /dev/null
+++ b/hw/xfree86/modes/xf86Rotate.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "xf86.h"
+#include "xf86DDC.h"
+#include "fb.h"
+#include "windowstr.h"
+#include "xf86Crtc.h"
+#include "xf86Modes.h"
+#include "xf86RandR12.h"
+#include "X11/extensions/render.h"
+#define DPMS_SERVER
+#include "X11/extensions/dpms.h"
+#include "X11/Xatom.h"
+
+static int
+mode_height (DisplayModePtr mode, Rotation rotation)
+{
+    switch (rotation & 0xf) {
+    case RR_Rotate_0:
+    case RR_Rotate_180:
+	return mode->VDisplay;
+    case RR_Rotate_90:
+    case RR_Rotate_270:
+	return mode->HDisplay;
+    default:
+	return 0;
+    }
+}
+
+static int
+mode_width (DisplayModePtr mode, Rotation rotation)
+{
+    switch (rotation & 0xf) {
+    case RR_Rotate_0:
+    case RR_Rotate_180:
+	return mode->HDisplay;
+    case RR_Rotate_90:
+    case RR_Rotate_270:
+	return mode->VDisplay;
+    default:
+	return 0;
+    }
+}
+
+/* borrowed from composite extension, move to Render and publish? */
+
+static VisualPtr
+compGetWindowVisual (WindowPtr pWin)
+{
+    ScreenPtr	    pScreen = pWin->drawable.pScreen;
+    VisualID	    vid = wVisual (pWin);
+    int		    i;
+
+    for (i = 0; i < pScreen->numVisuals; i++)
+	if (pScreen->visuals[i].vid == vid)
+	    return &pScreen->visuals[i];
+    return 0;
+}
+
+static PictFormatPtr
+compWindowFormat (WindowPtr pWin)
+{
+    ScreenPtr	pScreen = pWin->drawable.pScreen;
+    
+    return PictureMatchVisual (pScreen, pWin->drawable.depth,
+			       compGetWindowVisual (pWin));
+}
+
+static void
+xf86RotateBox (BoxPtr dst, BoxPtr src, Rotation rotation,
+	       int dest_width, int dest_height)
+{
+    switch (rotation & 0xf) {
+    default:
+    case RR_Rotate_0:
+	*dst = *src;
+	break;
+    case RR_Rotate_90:
+	dst->x1 = src->y1;
+	dst->y1 = dest_height - src->x2;
+	dst->x2 = src->y2;
+	dst->y2 = dest_height - src->x1;
+	break;
+    case RR_Rotate_180:
+	dst->x1 = dest_width - src->x2;
+	dst->y1 = dest_height - src->y2;
+	dst->x2 = dest_width - src->x1;
+	dst->y2 = dest_height - src->y1;
+	break;
+    case RR_Rotate_270:
+	dst->x1 = dest_width - src->y2;
+	dst->y1 = src->x1;
+	dst->y2 = src->x2;
+	dst->x2 = dest_width - src->y1;
+	break;
+    }
+    if (rotation & RR_Reflect_X) {
+	int x1 = dst->x1;
+	dst->x1 = dest_width - dst->x2;
+	dst->x2 = dest_width - x1;
+    }
+    if (rotation & RR_Reflect_Y) {
+	int y1 = dst->y1;
+	dst->y1 = dest_height - dst->y2;
+	dst->y2 = dest_height - y1;
+    }
+}
+
+static void
+xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
+{
+    ScrnInfoPtr		scrn = crtc->scrn;
+    ScreenPtr		screen = scrn->pScreen;
+    WindowPtr		root = WindowTable[screen->myNum];
+    PixmapPtr		dst_pixmap = crtc->rotatedPixmap;
+    PictFormatPtr	format = compWindowFormat (WindowTable[screen->myNum]);
+    int			error;
+    PicturePtr		src, dst;
+    PictTransform	transform;
+    int			n = REGION_NUM_RECTS(region);
+    BoxPtr		b = REGION_RECTS(region);
+    XID			include_inferiors = IncludeInferiors;
+    
+    src = CreatePicture (None,
+			 &root->drawable,
+			 format,
+			 CPSubwindowMode,
+			 &include_inferiors,
+			 serverClient,
+			 &error);
+    if (!src) {
+	ErrorF("couldn't create src pict\n");
+	return;
+    }
+    dst = CreatePicture (None,
+			 &dst_pixmap->drawable,
+			 format,
+			 0L,
+			 NULL,
+			 serverClient,
+			 &error);
+    if (!dst) {
+	ErrorF("couldn't create src pict\n");
+	return;
+    }
+
+    memset (&transform, '\0', sizeof (transform));
+    transform.matrix[2][2] = IntToxFixed(1);
+    transform.matrix[0][2] = IntToxFixed(crtc->x);
+    transform.matrix[1][2] = IntToxFixed(crtc->y);
+    switch (crtc->rotation & 0xf) {
+    default:
+    case RR_Rotate_0:
+	transform.matrix[0][0] = IntToxFixed(1);
+	transform.matrix[1][1] = IntToxFixed(1);
+	break;
+    case RR_Rotate_90:
+	transform.matrix[0][1] = IntToxFixed(-1);
+	transform.matrix[1][0] = IntToxFixed(1);
+	transform.matrix[0][2] += IntToxFixed(crtc->mode.VDisplay);
+	break;
+    case RR_Rotate_180:
+	transform.matrix[0][0] = IntToxFixed(-1);
+	transform.matrix[1][1] = IntToxFixed(-1);
+	transform.matrix[0][2] += IntToxFixed(crtc->mode.HDisplay);
+	transform.matrix[1][2] += IntToxFixed(crtc->mode.VDisplay);
+	break;
+    case RR_Rotate_270:
+	transform.matrix[0][1] = IntToxFixed(1);
+	transform.matrix[1][0] = IntToxFixed(-1);
+	transform.matrix[1][2] += IntToxFixed(crtc->mode.HDisplay);
+	break;
+    }
+
+    /* handle reflection */
+    if (crtc->rotation & RR_Reflect_X)
+    {
+	/* XXX figure this out */
+    }
+    if (crtc->rotation & RR_Reflect_Y)
+    {
+	/* XXX figure this out too */
+    }
+
+    error = SetPictureTransform (src, &transform);
+    if (error) {
+	ErrorF("Couldn't set transform\n");
+	return;
+    }
+
+    while (n--)
+    {
+	BoxRec	dst_box;
+
+	xf86RotateBox (&dst_box, b, crtc->rotation,
+		       crtc->mode.HDisplay, crtc->mode.VDisplay);
+	CompositePicture (PictOpSrc,
+			  src, NULL, dst,
+			  dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1,
+			  dst_box.x2 - dst_box.x1,
+			  dst_box.y2 - dst_box.y1);
+	b++;
+    }
+    FreePicture (src, None);
+    FreePicture (dst, None);
+}
+
+static void
+xf86RotateRedisplay(ScreenPtr pScreen)
+{
+    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    DamagePtr		damage = xf86_config->rotationDamage;
+    RegionPtr		region;
+
+    if (!damage)
+	return;
+    region = DamageRegion(damage);
+    if (REGION_NOTEMPTY(pScreen, region)) 
+    {
+	int		    c;
+	
+	for (c = 0; c < xf86_config->num_crtc; c++)
+	{
+	    xf86CrtcPtr	    crtc = xf86_config->crtc[c];
+
+	    if (crtc->rotation != RR_Rotate_0)
+	    {
+		BoxRec	    box;
+		RegionRec   crtc_damage;
+
+		/* compute portion of damage that overlaps crtc */
+		box.x1 = crtc->x;
+		box.x2 = crtc->x + mode_width (&crtc->mode, crtc->rotation);
+		box.y1 = crtc->y;
+		box.y2 = crtc->y + mode_height (&crtc->mode, crtc->rotation);
+		REGION_INIT(pScreen, &crtc_damage, &box, 1);
+		REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region);
+		
+		/* update damaged region */
+		if (REGION_NOTEMPTY(pScreen, &crtc_damage))
+    		    xf86RotateCrtcRedisplay (crtc, &crtc_damage);
+		
+		REGION_UNINIT (pScreen, &crtc_damage);
+	    }
+	}
+	DamageEmpty(damage);
+    }
+}
+
+static void
+xf86RotateBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead)
+{
+    ScreenPtr pScreen = (ScreenPtr) data;
+
+    xf86RotateRedisplay(pScreen);
+}
+
+static void
+xf86RotateWakeupHandler(pointer data, int i, pointer LastSelectMask)
+{
+}
+
+Bool
+xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
+{
+    ScrnInfoPtr		pScrn = crtc->scrn;
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    ScreenPtr		pScreen = pScrn->pScreen;
+    
+    if (rotation == RR_Rotate_0)
+    {
+	/* Free memory from rotation */
+	if (crtc->rotatedPixmap)
+	{
+	    crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap);
+	    crtc->rotatedPixmap = NULL;
+	}
+
+	if (xf86_config->rotationDamage)
+	{
+	    /* Free damage structure */
+	    DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
+			      xf86_config->rotationDamage);
+	    DamageDestroy (xf86_config->rotationDamage);
+	    xf86_config->rotationDamage = NULL;
+	    /* Free block/wakeup handler */
+	    RemoveBlockAndWakeupHandlers (xf86RotateBlockHandler,
+					  xf86RotateWakeupHandler,
+					  (pointer) pScreen);
+	}
+    }
+    else
+    {
+	/* 
+	 * these are the size of the shadow pixmap, which
+	 * matches the mode, not the pre-rotated copy in the
+	 * frame buffer
+	 */
+	int	    width = mode->HDisplay;
+	int	    height = mode->VDisplay;
+	PixmapPtr   shadow = crtc->rotatedPixmap;
+	int	    old_width = shadow ? shadow->drawable.width : 0;
+	int	    old_height = shadow ? shadow->drawable.height : 0;
+	BoxRec	    damage_box;
+	RegionRec   damage_region;
+	
+	/* Allocate memory for rotation */
+	if (old_width != width || old_height != height)
+	{
+	    if (shadow)
+	    {
+		crtc->funcs->shadow_destroy (crtc, shadow);
+		crtc->rotatedPixmap = NULL;
+	    }
+	    shadow = crtc->funcs->shadow_create (crtc, width, height);
+	    if (!shadow)
+		goto bail1;
+	    crtc->rotatedPixmap = shadow;
+	}
+	
+	if (!xf86_config->rotationDamage)
+	{
+	    /* Create damage structure */
+	    xf86_config->rotationDamage = DamageCreate (NULL, NULL,
+						DamageReportNone,
+						TRUE, pScreen, pScreen);
+	    if (!xf86_config->rotationDamage)
+		goto bail2;
+	    
+	    /* Hook damage to screen pixmap */
+	    DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
+			    xf86_config->rotationDamage);
+	    
+	    /* Assign block/wakeup handler */
+	    if (!RegisterBlockAndWakeupHandlers (xf86RotateBlockHandler,
+						 xf86RotateWakeupHandler,
+						 (pointer) pScreen))
+	    {
+		goto bail3;
+	    }
+	    damage_box.x1 = 0;
+	    damage_box.y1 = 0;
+	    damage_box.x2 = mode_width (mode, rotation);
+	    damage_box.y2 = mode_height (mode, rotation);
+	    REGION_INIT (pScreen, &damage_region, &damage_box, 1);
+	    DamageDamageRegion (&(*pScreen->GetScreenPixmap)(pScreen)->drawable,
+				&damage_region);
+	    REGION_UNINIT (pScreen, &damage_region);
+	}
+	if (0)
+	{
+bail3:
+	    DamageDestroy (xf86_config->rotationDamage);
+	    xf86_config->rotationDamage = NULL;
+	    
+bail2:
+	    if (shadow)
+	    {
+		crtc->funcs->shadow_destroy (crtc, shadow);
+		crtc->rotatedPixmap = NULL;
+	    }
+bail1:
+	    if (old_width && old_height)
+		crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc,
+								  old_width,
+								  old_height);
+	    return FALSE;
+	}
+    }
+    
+    /* All done */
+    return TRUE;
+}
diff --git a/hw/xfree86/modes/xf86cvt.c b/hw/xfree86/modes/xf86cvt.c
new file mode 100644
index 0000000..4256577
--- /dev/null
+++ b/hw/xfree86/modes/xf86cvt.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2005-2006 Luc Verhaegen.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file This is a copy of xf86cvt.c from the X Server, for compatibility with
+ * old servers (pre-1.2).
+ */
+
+/*
+ * The reason for having this function in a file of its own is
+ * so that ../utils/cvt/cvt can link to it, and that xf86CVTMode
+ * code is shared directly.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "xf86.h"
+
+#include <string.h>
+
+/*
+ * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh.
+ *
+ * These calculations are stolen from the CVT calculation spreadsheet written
+ * by Graham Loveridge. He seems to be claiming no copyright and there seems to
+ * be no license attached to this. He apparently just wants to see his name
+ * mentioned.
+ *
+ * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls
+ *
+ * Comments and structure corresponds to the comments and structure of the xls.
+ * This should ease importing of future changes to the standard (not very
+ * likely though).
+ *
+ * About margins; i'm sure that they are to be the bit between HDisplay and
+ * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and 
+ * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking
+ * outside sync "margin" for some reason. Since we prefer seeing proper
+ * blanking instead of the overscan colour, and since the Crtc* values will
+ * probably get altered after us, we will disable margins altogether. With
+ * these calculations, Margins will plainly expand H/VDisplay, and we don't
+ * want that. -- libv
+ *
+ */
+_X_EXPORT DisplayModePtr
+xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced,
+	    Bool Interlaced)
+{
+    DisplayModeRec  *Mode = xnfalloc(sizeof(DisplayModeRec));
+
+    /* 1) top/bottom margin size (% of height) - default: 1.8 */
+#define CVT_MARGIN_PERCENTAGE 1.8    
+
+    /* 2) character cell horizontal granularity (pixels) - default 8 */
+#define CVT_H_GRANULARITY 8
+
+    /* 4) Minimum vertical porch (lines) - default 3 */
+#define CVT_MIN_V_PORCH 3
+
+    /* 4) Minimum number of vertical back porch lines - default 6 */
+#define CVT_MIN_V_BPORCH 6
+
+    /* Pixel Clock step (kHz) */
+#define CVT_CLOCK_STEP 250
+
+    Bool Margins = FALSE;
+    float  VFieldRate, HPeriod;
+    int  HDisplayRnd, HMargin;
+    int  VDisplayRnd, VMargin, VSync;
+    float  Interlace; /* Please rename this */
+
+    memset(Mode, 0, sizeof(DisplayModeRec));
+
+    /* CVT default is 60.0Hz */
+    if (!VRefresh)
+        VRefresh = 60.0;
+
+    /* 1. Required field rate */
+    if (Interlaced)
+        VFieldRate = VRefresh * 2;
+    else
+        VFieldRate = VRefresh;
+
+    /* 2. Horizontal pixels */
+    HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY);
+
+    /* 3. Determine left and right borders */
+    if (Margins) {
+        /* right margin is actually exactly the same as left */
+        HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
+        HMargin -= HMargin % CVT_H_GRANULARITY;
+    } else
+        HMargin = 0;
+
+    /* 4. Find total active pixels */
+    Mode->HDisplay = HDisplayRnd + 2*HMargin;
+
+    /* 5. Find number of lines per field */
+    if (Interlaced)
+        VDisplayRnd = VDisplay / 2;
+    else
+        VDisplayRnd = VDisplay;
+
+    /* 6. Find top and bottom margins */
+    /* nope. */
+    if (Margins)
+        /* top and bottom margins are equal again. */
+        VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
+    else
+        VMargin = 0;
+
+    Mode->VDisplay = VDisplay + 2*VMargin;
+
+    /* 7. Interlace */
+    if (Interlaced)
+        Interlace = 0.5;
+    else
+        Interlace = 0.0;
+
+    /* Determine VSync Width from aspect ratio */
+    if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay))
+        VSync = 4;
+    else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay))
+        VSync = 5;
+    else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay))
+        VSync = 6;
+    else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay))
+        VSync = 7;
+    else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))
+        VSync = 7;
+    else /* Custom */
+        VSync = 10;
+
+    if (!Reduced) { /* simplified GTF calculation */
+
+        /* 4) Minimum time of vertical sync + back porch interval (µs) 
+         * default 550.0 */
+#define CVT_MIN_VSYNC_BP 550.0
+
+        /* 3) Nominal HSync width (% of line period) - default 8 */
+#define CVT_HSYNC_PERCENTAGE 8
+
+        float  HBlankPercentage;
+        int  VSyncAndBackPorch, VBackPorch;
+        int  HBlank;
+
+        /* 8. Estimated Horizontal period */
+        HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) / 
+            (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace);
+
+        /* 9. Find number of lines in sync + backporch */
+        if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH))
+            VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH;
+        else
+            VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1;
+
+        /* 10. Find number of lines in back porch */
+        VBackPorch = VSyncAndBackPorch - VSync;
+
+        /* 11. Find total number of lines in vertical field */
+        Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace
+            + CVT_MIN_V_PORCH;
+
+        /* 5) Definition of Horizontal blanking time limitation */
+        /* Gradient (%/kHz) - default 600 */
+#define CVT_M_FACTOR 600
+
+        /* Offset (%) - default 40 */
+#define CVT_C_FACTOR 40
+
+        /* Blanking time scaling factor - default 128 */
+#define CVT_K_FACTOR 128
+
+        /* Scaling factor weighting - default 20 */
+#define CVT_J_FACTOR 20
+
+#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256
+#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
+        CVT_J_FACTOR
+
+        /* 12. Find ideal blanking duty cycle from formula */
+        HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0;
+
+        /* 13. Blanking time */
+        if (HBlankPercentage < 20)
+            HBlankPercentage = 20;
+
+        HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage);
+        HBlank -= HBlank % (2*CVT_H_GRANULARITY);
+        
+        /* 14. Find total number of pixels in a line. */
+        Mode->HTotal = Mode->HDisplay + HBlank;
+
+        /* Fill in HSync values */
+        Mode->HSyncEnd = Mode->HDisplay + HBlank / 2;
+
+        Mode->HSyncStart = Mode->HSyncEnd - 
+            (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100;
+        Mode->HSyncStart += CVT_H_GRANULARITY - 
+            Mode->HSyncStart % CVT_H_GRANULARITY;
+
+        /* Fill in VSync values */
+        Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH;
+        Mode->VSyncEnd = Mode->VSyncStart + VSync;
+
+    } else { /* Reduced blanking */
+        /* Minimum vertical blanking interval time (µs) - default 460 */
+#define CVT_RB_MIN_VBLANK 460.0
+
+        /* Fixed number of clocks for horizontal sync */
+#define CVT_RB_H_SYNC 32.0
+
+        /* Fixed number of clocks for horizontal blanking */
+#define CVT_RB_H_BLANK 160.0
+
+        /* Fixed number of lines for vertical front porch - default 3 */
+#define CVT_RB_VFPORCH 3
+
+        int  VBILines;
+
+        /* 8. Estimate Horizontal period. */
+        HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / 
+            (VDisplayRnd + 2*VMargin);
+
+        /* 9. Find number of lines in vertical blanking */
+        VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
+
+        /* 10. Check if vertical blanking is sufficient */
+        if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
+            VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
+        
+        /* 11. Find total number of lines in vertical field */
+        Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines;
+
+        /* 12. Find total number of pixels in a line */
+        Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK;
+
+        /* Fill in HSync values */
+        Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2;
+        Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC;
+
+        /* Fill in VSync values */
+        Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH;
+        Mode->VSyncEnd = Mode->VSyncStart + VSync;
+    }
+
+    /* 15/13. Find pixel clock frequency (kHz for xf86) */
+    Mode->Clock = Mode->HTotal * 1000.0 / HPeriod;
+    Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP;
+
+    /* 16/14. Find actual Horizontal Frequency (kHz) */
+    Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal);
+
+    /* 17/15. Find actual Field rate */
+    Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / 
+        ((float) (Mode->HTotal * Mode->VTotal));
+
+    /* 18/16. Find actual vertical frame frequency */
+    /* ignore - just set the mode flag for interlaced */
+    if (Interlaced)
+        Mode->VTotal *= 2;
+
+    {
+        char  Name[256];
+        Name[0] = 0;
+
+        snprintf(Name, 256, "%dx%d", HDisplay, VDisplay);
+
+        Mode->name = xnfalloc(strlen(Name) + 1);
+        memcpy(Mode->name, Name, strlen(Name) + 1);
+    }
+
+    if (Reduced)
+        Mode->Flags |= V_PHSYNC | V_NVSYNC;
+    else
+        Mode->Flags |= V_NHSYNC | V_PVSYNC;
+
+    if (Interlaced)
+        Mode->Flags |= V_INTERLACE;
+
+    return Mode;
+}
diff --git a/hw/xfree86/ramdac/xf86Cursor.c b/hw/xfree86/ramdac/xf86Cursor.c
index a903f7f..4578076 100644
--- a/hw/xfree86/ramdac/xf86Cursor.c
+++ b/hw/xfree86/ramdac/xf86Cursor.c
@@ -199,10 +199,11 @@ xf86CursorEnableDisableFBAccess(
 	pScreen->devPrivates[xf86CursorScreenIndex].ptr;
 
     if (!enable && ScreenPriv->CurrentCursor != NullCursor) {
-	ScreenPriv->SavedCursor = ScreenPriv->CurrentCursor;
+	CursorPtr   currentCursor = ScreenPriv->CurrentCursor;
 	xf86CursorSetCursor(pScreen, NullCursor, ScreenPriv->x, ScreenPriv->y);
 	ScreenPriv->isUp = FALSE;
 	ScreenPriv->SWCursor = TRUE;
+	ScreenPriv->SavedCursor = currentCursor;
     }
 
     if (ScreenPriv->EnableDisableFBAccess)



More information about the xorg-commit mailing list