--- /dev/null
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/Imakefile.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/Imakefile 2005-08-18 19:40:24.000000000 -0400
+@@ -37,14 +37,14 @@
+
+ #if !I830Only
+ I810SRCS = i810_cursor.c i810_accel.c i810_memory.c i810_wmark.c i810_dga.c \
+- i810_video.c i810_io.c
++ i810_video.c i810_io.c i830_modes.c
+ I810OBJS = i810_cursor.o i810_accel.o i810_memory.o i810_wmark.o i810_dga.o \
+- i810_video.o i810_io.o
++ i810_video.o i810_io.o i830_modes.o
+ #endif
+ I830SRCS = i830_driver.c i830_memory.c i830_cursor.c i830_accel.c i830_io.c \
+- i830_dga.c $(I830SRCS1) $(I830SRCS2)
++ i830_dga.c i830_shadow.c $(I830SRCS1) $(I830SRCS2)
+ I830OBJS = i830_driver.o i830_memory.o i830_cursor.o i830_accel.o i830_io.o \
+- i830_dga.o $(I830OBJS1) $(I830OBJS2)
++ i830_dga.o i830_shadow.o $(I830OBJS1) $(I830OBJS2)
+
+ SRCS = i810_driver.c \
+ $(I810SRCS) $(I830SRCS) $(DRISRCS)
+@@ -121,6 +121,7 @@
+ InstallDriverSDKNonExecFile(i830_dri.h,$(DRIVERSDKDIR)/drivers/i810)
+ InstallDriverSDKNonExecFile(i830_driver.c,$(DRIVERSDKDIR)/drivers/i810)
+ InstallDriverSDKNonExecFile(i830_memory.c,$(DRIVERSDKDIR)/drivers/i810)
++InstallDriverSDKNonExecFile(i830_shadow.c,$(DRIVERSDKDIR)/drivers/i810)
+ InstallDriverSDKNonExecFile(i830_video.c,$(DRIVERSDKDIR)/drivers/i810)
+
+ InstallDriverSDKObjectModule(i810,$(DRIVERSDKMODULEDIR),drivers)
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/common.h.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/common.h 2005-08-18 19:40:24.000000000 -0400
+@@ -2,7 +2,7 @@
+ /**************************************************************************
+
+ Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+-Copyright © 2002 David Dawes
++Copyright © 2002 David Dawes
+
+ All Rights Reserved.
+
+@@ -79,6 +79,7 @@
+ extern const char *I810ddcSymbols[];
+ extern const char *I810fbSymbols[];
+ extern const char *I810xaaSymbols[];
++extern const char *I810shadowFBSymbols[];
+ #ifdef XF86DRI
+ extern const char *I810driSymbols[];
+ extern const char *I810drmSymbols[];
+@@ -305,6 +306,22 @@
+ #define PCI_CHIP_I915_G_BRIDGE 0x2580
+ #endif
+
++#ifndef PCI_CHIP_I915_GM
++#define PCI_CHIP_I915_GM 0x2592
++#define PCI_CHIP_I915_GM_BRIDGE 0x2590
++#endif
++
++#ifndef PCI_CHIP_E7221_G
++#define PCI_CHIP_E7221_G 0x258A
++/* Same as I915_G_BRIDGE */
++#define PCI_CHIP_E7221_G_BRIDGE 0x2580
++#endif
++
++#ifndef PCI_CHIP_I945_G
++#define PCI_CHIP_I945_G 0x2772
++#define PCI_CHIP_I945_G_BRIDGE 0x2770
++#endif
++
+ #define IS_I810(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I810 || \
+ pI810->PciInfo->chipType == PCI_CHIP_I810_DC100 || \
+ pI810->PciInfo->chipType == PCI_CHIP_I810_E)
+@@ -312,10 +329,14 @@
+ #define IS_I830(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I830_M)
+ #define IS_845G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_845_G)
+ #define IS_I85X(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I855_GM)
++#define IS_I852(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I855_GM && (pI810->variant == I852_GM || pI810->variant == I852_GME))
++#define IS_I855(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I855_GM && (pI810->variant == I855_GM || pI810->variant == I855_GME))
+ #define IS_I865G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I865_G)
+-#define IS_I915G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I915_G)
++#define IS_I915G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I915_G || pI810->PciInfo->chipType == PCI_CHIP_E7221_G)
++#define IS_I915GM(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I915_GM)
++#define IS_I945G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I945_G)
+
+-#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810))
++#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810) || IS_I915GM(pI810))
+
+ #define GTT_PAGE_SIZE KB(4)
+ #define ROUND_TO(x, y) (((x) + (y) - 1) / (y) * (y))
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i810.man.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i810.man 2005-08-18 19:40:24.000000000 -0400
+@@ -25,7 +25,7 @@
+ .SH SUPPORTED HARDWARE
+ .B i810
+ supports the i810, i810-DC100, i810e, i815, 830M, 845G, 852GM, 855GM,
+-865G and 915G chipsets.
++865G, 915G and 915GM chipsets.
+
+ .SH CONFIGURATION DETAILS
+ Please refer to __xconfigfile__(__filemansuffix__) for general configuration
+@@ -191,6 +191,17 @@
+ the machine has booted, but unfortunately it doesn't always work and
+ is extremely dependent upon the Video BIOS.
+ Default: disabled
++.TP
++.BI "Option \*qRotate\*q \*qCW\*q"
++.TP
++.BI "Option \*qRotate\*q \*qCCW\*q"
++Rotate the desktop 90 degrees clockwise or counterclockwise. This option
++forces the ShadowFB option on, and disables acceleration.
++Default: no rotation.
++.TP
++.BI "Option \*qShadowFB\*q \*q" boolean \*q
++Enable or disable use of the shadow framebuffer layer. This option
++disables acceleration. Default: off.
+
+ .SH "SEE ALSO"
+ __xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
+@@ -199,5 +210,5 @@
+ Jeff Hartmann, Mark Vojkovich, Alan Hourihane, H. J. Lu. 830M and 845G
+ support reworked for XFree86 4.3 by David Dawes and Keith Whitwell.
+ 852GM, 855GM, and 865G support added by David Dawes and Keith Whitwell.
+-915G support added by Alan Hourihane and Keith Whitwell.
++915G and 915GM support added by Alan Hourihane and Keith Whitwell.
+ Dual Head, Clone and lid status support added by Alan Hourihane.
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i810_accel.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i810_accel.c 2005-08-18 19:40:24.000000000 -0400
+@@ -259,7 +259,7 @@
+ #ifdef XF86DRI
+ /* VT switching tries to do this.
+ */
+- if ((!pI810->LockHeld && pI810->directRenderingEnabled) || !pScrn->vtSema) {
++ if (!pI810->LockHeld && pI810->directRenderingEnabled) {
+ return;
+ }
+ #endif
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c 2005-08-18 19:40:24.000000000 -0400
+@@ -1498,10 +1498,10 @@
+ return FALSE;
+ }
+ if (pI810->cursorARGBHandle != 0)
+- if (drmAgpUnbind(pI810->drmSubFD, pI810->cursorARGBHandle) != 0) {
+- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
+- return FALSE;
+- }
++ if (drmAgpUnbind(pI810->drmSubFD, pI810->cursorARGBHandle) != 0) {
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
++ return FALSE;
++ }
+ if (pI810->agpAcquired == TRUE)
+ drmAgpRelease(pI810->drmSubFD);
+ pI810->agpAcquired = FALSE;
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.h.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.h 2005-08-18 19:40:24.000000000 -0400
+@@ -3,7 +3,6 @@
+ #ifndef _I810_DRI_
+ #define _I810_DRI_
+
+-#include "xf86dri.h"
+ #include "xf86drm.h"
+ #include "i810_common.h"
+
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c 2005-08-18 19:40:24.000000000 -0400
+@@ -74,7 +74,7 @@
+ #include "fb.h"
+ #include "miscstruct.h"
+ #include "xf86xv.h"
+-#include "Xv.h"
++#include <X11/extensions/Xv.h>
+ #include "vbe.h"
+
+ #include "i810.h"
+@@ -129,6 +129,9 @@
+ {PCI_CHIP_I855_GM, "852GM/855GM"},
+ {PCI_CHIP_I865_G, "865G"},
+ {PCI_CHIP_I915_G, "915G"},
++ {PCI_CHIP_E7221_G, "E7221 (i915)"},
++ {PCI_CHIP_I915_GM, "915GM"},
++ {PCI_CHIP_I945_G, "945G"},
+ {-1, NULL}
+ };
+
+@@ -144,6 +147,9 @@
+ {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA},
+ {PCI_CHIP_I865_G, PCI_CHIP_I865_G, RES_SHARED_VGA},
+ {PCI_CHIP_I915_G, PCI_CHIP_I915_G, RES_SHARED_VGA},
++ {PCI_CHIP_E7221_G, PCI_CHIP_E7221_G, RES_SHARED_VGA},
++ {PCI_CHIP_I915_GM, PCI_CHIP_I915_GM, RES_SHARED_VGA},
++ {PCI_CHIP_I945_G, PCI_CHIP_I945_G, RES_SHARED_VGA},
+ {-1, -1, RES_UNDEFINED }
+ };
+
+@@ -262,6 +268,11 @@
+ NULL
+ };
+
++const char *I810shadowFBSymbols[] = {
++ "ShadowFBInit",
++ NULL
++};
++
+ #ifdef XF86DRI
+ const char *I810drmSymbols[] = {
+ "drmAddBufs",
+@@ -303,13 +314,6 @@
+ NULL
+ };
+
+-#ifdef XF86DRI
+-
+-static const char *driShadowFBSymbols[] = {
+- "ShadowFBInit",
+- NULL
+-};
+-
+ const char *I810shadowSymbols[] = {
+ "shadowInit",
+ "shadowSetup",
+@@ -317,9 +321,7 @@
+ NULL
+ };
+
+-#endif
+-
+-#endif /* I830_ONLY */
++#endif
+
+ #ifndef I810_DEBUG
+ int I810_DEBUG = (0
+@@ -388,7 +390,7 @@
+ I810drmSymbols,
+ I810driSymbols,
+ I810shadowSymbols,
+- driShadowFBSymbols,
++ I810shadowFBSymbols,
+ #endif
+ I810vbeSymbols, vbeOptionalSymbols,
+ I810ddcSymbols, I810int10Symbols, NULL);
+@@ -560,6 +562,9 @@
+ case PCI_CHIP_I830_M:
+ case PCI_CHIP_I855_GM:
+ case PCI_CHIP_I915_G:
++ case PCI_CHIP_E7221_G:
++ case PCI_CHIP_I915_GM:
++ case PCI_CHIP_I945_G:
+ xf86SetEntitySharable(usedChips[i]);
+
+ /* Allocate an entity private if necessary */
+@@ -1080,7 +1088,7 @@
+ "Couldn't load shadowfb module:\n");
+ }
+ else {
+- xf86LoaderReqSymLists(driShadowFBSymbols, NULL);
++ xf86LoaderReqSymLists(I810shadowFBSymbols, NULL);
+ }
+ }
+
+@@ -1729,6 +1737,21 @@
+ i810Reg->ExtHorizBlank = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 6;
+
+ /*
++ * the KGA fix in vgaHW.c results in the first
++ * scanline and the first character clock (8 pixels)
++ * of each scanline thereafter on display with an i810
++ * to be blank. Restoring CRTC 3, 5, & 22 to their
++ * "theoretical" values corrects the problem. KAO.
++ */
++ pVga->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80;
++ pVga->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2)
++ | (((mode->CrtcHSyncEnd >> 3)) & 0x1F);
++ pVga->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
++
++ i810Reg->ExtHorizBlank = vgaHWHBlankKGA(mode, pVga, 7, 0);
++ vgaHWVBlankKGA(mode, pVga, 8, 0);
++
++ /*
+ * The following workarounds are needed to get video overlay working
+ * at 1024x768 and 1280x1024 display resolutions.
+ */
+@@ -1787,7 +1810,6 @@
+ {
+ vgaHWPtr hwp;
+ I810Ptr pI810;
+- vgaRegPtr pVga;
+
+ hwp = VGAHWPTR(pScrn);
+ pI810 = I810PTR(pScrn);
+@@ -1796,18 +1818,6 @@
+
+ if (!vgaHWInit(pScrn, mode))
+ return FALSE;
+- /*
+- * the KGA fix in vgaHW.c results in the first
+- * scanline and the first character clock (8 pixels)
+- * of each scanline thereafter on display with an i810
+- * to be blank. Restoring CRTC 3, 5, & 22 to their
+- * "theoretical" values corrects the problem. KAO.
+- */
+- pVga = &VGAHWPTR(pScrn)->ModeReg;
+- pVga->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80;
+- pVga->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2)
+- | (((mode->CrtcHSyncEnd >> 3)) & 0x1F);
+- pVga->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
+
+ pScrn->vtSema = TRUE;
+
+@@ -2097,8 +2107,8 @@
+
+ #ifdef XF86DRI
+ /*
+- * Setup DRI after visuals have been established, but before cfbScreenInit
+- * is called. cfbScreenInit will eventually call into the drivers
++ * Setup DRI after visuals have been established, but before fbScreenInit
++ * is called. fbScreenInit will eventually call into the drivers
+ * InitGLXVisuals call back.
+ */
+ /*
+@@ -2241,7 +2251,7 @@
+
+ #ifdef XF86DRI
+ if (pI810->directRenderingEnabled) {
+- /* Now that mi, cfb, drm and others have done their thing,
++ /* Now that mi, fb, drm and others have done their thing,
+ * complete the DRI setup.
+ */
+ pI810->directRenderingEnabled = I810DRIFinishScreenInit(pScreen);
+@@ -2255,9 +2265,9 @@
+ #endif
+
+ if (pI810->directRenderingEnabled) {
+- xf86DrvMsg(pScrn->scrnIndex, driFrom, "Direct rendering enabled\n");
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
+ } else {
+- xf86DrvMsg(pScrn->scrnIndex, driFrom, "Direct rendering disabled\n");
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n");
+ }
+
+ pScreen->SaveScreen = I810SaveScreen;
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i810_hwmc.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i810_hwmc.c 2005-08-18 19:40:24.000000000 -0400
+@@ -50,8 +50,8 @@
+
+ #include "xf86xv.h"
+ #include "xf86xvmc.h"
+-#include "Xv.h"
+-#include "XvMC.h"
++#include <X11/extensions/Xv.h>
++#include <X11/extensions/XvMC.h>
+ #include "xaa.h"
+ #include "xaalocal.h"
+ #include "dixstruct.h"
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i830.h.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830.h 2005-08-18 19:40:24.000000000 -0400
+@@ -75,7 +75,7 @@
+
+ /*
+ * The mode handling is based upon the VESA driver written by
+- * Paulo César Pereira de Andrade <pcpa@conectiva.com.br>.
++ * Paulo César Pereira de Andrade <pcpa@conectiva.com.br>.
+ */
+
+ #define PIPE_NONE 0<<0
+@@ -91,7 +91,7 @@
+ typedef struct _VESARec {
+ /* SVGA state */
+ pointer state, pstate;
+- int statePage, stateSize, stateMode;
++ int statePage, stateSize, stateMode, stateRefresh;
+ CARD32 *savedPal;
+ int savedScanlinePitch;
+ xf86MonPtr monitor;
+@@ -165,13 +165,17 @@
+
+ Bool newPipeSwitch;
+
++ Bool fakeSwitch;
++
++ int fixedPipe;
++
+ Bool Clone;
+ int CloneRefresh;
+ int CloneHDisplay;
+ int CloneVDisplay;
+
+ I830EntPtr entityPrivate;
+- int pipe;
++ int pipe, origPipe;
+ int init;
+
+ unsigned int bufferOffset; /* for I830SelectBuffer */
+@@ -234,6 +238,7 @@
+
+ int MonType1;
+ int MonType2;
++ Bool specifiedMonitor;
+
+ DGAModePtr DGAModes;
+ int numDGAModes;
+@@ -297,7 +302,15 @@
+ drm_handle_t ring_map;
+ #endif
+
++ /* Broken-out options. */
+ OptionInfoPtr Options;
++ int rotate;
++ Bool shadowFB;
++
++ /* Support for shadowFB and rotation. */
++ unsigned char *shadowPtr;
++ int shadowPitch;
++ void (*PointerMoved)(int, int, int);
+
+ /* Stolen memory support */
+ Bool StolenOnly;
+@@ -320,10 +333,11 @@
+ /* Use BIOS call 0x5f05 to set the refresh rate. */
+ Bool useExtendedRefresh;
+
+- Bool checkLid;
++ Bool checkDevices;
+ int monitorSwitch;
+ int operatingDevices;
+ int savedDevices;
++ int lastDevice1, lastDevice2;
+
+ /* These are indexed by the display types */
+ Bool displayAttached[NumDisplayTypes];
+@@ -343,6 +357,7 @@
+ Bool starting;
+ Bool closing;
+ Bool suspended;
++ Bool leaving;
+
+ /* fbOffset converted to (x, y). */
+ int xoffset;
+@@ -353,7 +368,7 @@
+ Bool displayInfo;
+ Bool devicePresence;
+
+- OsTimerPtr lidTimer;
++ OsTimerPtr devicesTimer;
+ } I830Rec;
+
+ #define I830PTR(p) ((I830Ptr)((p)->driverPrivate))
+@@ -390,6 +405,7 @@
+ extern void I830SetupMemoryTiling(ScrnInfoPtr pScrn);
+ extern Bool I830DRIScreenInit(ScreenPtr pScreen);
+ extern Bool I830DRIDoMappings(ScreenPtr pScreen);
++extern Bool I830DRIResume(ScreenPtr pScreen);
+ extern void I830DRICloseScreen(ScreenPtr pScreen);
+ extern Bool I830DRIFinishScreenInit(ScreenPtr pScreen);
+ #endif
+@@ -423,13 +439,27 @@
+
+ extern void I830ChangeFrontbuffer(ScrnInfoPtr pScrn,int buffer);
+
++extern DisplayModePtr I830GetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe,
++ VbeInfoBlock *vbe);
++extern void I830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe);
++extern void I830UnsetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe);
++extern void I830PrintModes(ScrnInfoPtr pScrn);
++extern int I830GetBestRefresh(ScrnInfoPtr pScrn, int refresh);
++extern Bool I830CheckModeSupport(ScrnInfoPtr pScrn, int x, int y, int mode);
++extern void I830PointerMoved(int index, int x, int y);
++extern void I830RefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
++extern void I830RefreshArea8(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
++extern void I830RefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
++extern void I830RefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
++extern void I830RefreshArea32(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
++
+ /*
+ * 12288 is set as the maximum, chosen because it is enough for
+ * 1920x1440@32bpp with a 2048 pixel line pitch with some to spare.
+ */
+ #define I830_MAXIMUM_VBIOS_MEM 12288
+-#define I830_DEFAULT_VIDEOMEM_2D (MB(8) / 1024)
+-#define I830_DEFAULT_VIDEOMEM_3D (MB(32) / 1024)
++#define I830_DEFAULT_VIDEOMEM_2D (MB(32) / 1024)
++#define I830_DEFAULT_VIDEOMEM_3D (MB(64) / 1024)
+
+ /* Flags for memory allocation function */
+ #define FROM_ANYWHERE 0x00000000
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i830_common.h.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_common.h 2005-08-18 19:40:24.000000000 -0400
+@@ -55,7 +55,8 @@
+ typedef struct {
+ enum {
+ I830_INIT_DMA = 0x01,
+- I830_CLEANUP_DMA = 0x02
++ I830_CLEANUP_DMA = 0x02,
++ I830_RESUME_DMA = 0x03
+ } func;
+ unsigned int mmio_offset;
+ int sarea_priv_offset;
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i830_cursor.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_cursor.c 2005-08-18 19:40:24.000000000 -0400
+@@ -2,7 +2,7 @@
+ /**************************************************************************
+
+ Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+-Copyright © 2002 David Dawes
++Copyright © 2002 David Dawes
+ All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+@@ -82,7 +82,7 @@
+
+ DPRINTF(PFX, "I830InitHWCursor\n");
+ /* Initialise the HW cursor registers, leaving the cursor hidden. */
+- if (IS_MOBILE(pI830) || IS_I915G(pI830)) {
++ if (IS_MOBILE(pI830) || IS_I915G(pI830) || IS_I945G(pI830)) {
+ temp = INREG(CURSOR_A_CONTROL);
+ temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE | MCURSOR_MEM_TYPE_LOCAL |
+ MCURSOR_PIPE_SELECT);
+@@ -304,7 +304,7 @@
+ }
+
+ /* have to upload the base for the new position */
+- if (IS_I915G(pI830)) {
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
+ if (pI830->CursorIsARGB)
+ OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
+ else
+@@ -335,7 +335,7 @@
+ pI830->CursorMemARGB->Physical, pI830->CursorMemARGB->Start);
+
+ pI830->cursorOn = TRUE;
+- if (IS_MOBILE(pI830) || IS_I915G(pI830)) {
++ if (IS_MOBILE(pI830) || IS_I915G(pI830) || IS_I945G(pI830)) {
+ temp = INREG(CURSOR_A_CONTROL);
+ temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
+ if (pI830->CursorIsARGB)
+@@ -383,7 +383,7 @@
+ DPRINTF(PFX, "I830HideCursor\n");
+
+ pI830->cursorOn = FALSE;
+- if (IS_MOBILE(pI830) || IS_I915G(pI830)) {
++ if (IS_MOBILE(pI830) || IS_I915G(pI830) || IS_I945G(pI830)) {
+ temp = INREG(CURSOR_A_CONTROL);
+ temp &= ~CURSOR_MODE;
+ temp |= CURSOR_MODE_DISABLE;
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i830_dri.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_dri.c 2005-08-18 19:40:24.000000000 -0400
+@@ -2,7 +2,7 @@
+ /**************************************************************************
+
+ Copyright 2001 VA Linux Systems Inc., Fremont, California.
+-Copyright © 2002 by David Dawes
++Copyright © 2002 by David Dawes
+
+ All Rights Reserved.
+
+@@ -163,6 +163,24 @@
+ }
+
+ static Bool
++I830ResumeDma(ScrnInfoPtr pScrn)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ drmI830Init info;
++
++ memset(&info, 0, sizeof(drmI830Init));
++ info.func = I830_RESUME_DMA;
++
++ if (drmCommandWrite(pI830->drmSubFD, DRM_I830_INIT,
++ &info, sizeof(drmI830Init))) {
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I830 Dma Resume Failed\n");
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++static Bool
+ I830SetParam(ScrnInfoPtr pScrn, int param, int value)
+ {
+ I830Ptr pI830 = I830PTR(pScrn);
+@@ -510,7 +528,7 @@
+ return FALSE;
+ }
+
+- /* Check the i830 DRM versioning */
++ /* Check the i915 DRM versioning */
+ {
+ drmVersionPtr version;
+
+@@ -568,10 +586,18 @@
+ drmFreeVersion(version);
+ return FALSE;
+ }
++ if (strncmp(version->name, I830KernelDriverName, strlen(I830KernelDriverName))) {
++ xf86DrvMsg(pScreen->myNum, X_WARNING,
++ "i830 Kernel module detected, Use the i915 Kernel module instead, aborting DRI init.\n");
++ I830DRICloseScreen(pScreen);
++ drmFreeVersion(version);
++ return FALSE;
++ }
+ pI830->drmMinor = version->version_minor;
+ drmFreeVersion(version);
+ }
+ }
++
+ return TRUE;
+ }
+
+@@ -655,7 +681,10 @@
+ xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] textures = 0x%08lx\n",
+ pI830DRI->textures);
+
+- I830InitDma(pScrn);
++ if (!I830InitDma(pScrn)) {
++ DRICloseScreen(pScreen);
++ return FALSE;
++ }
+
+ if (pI830->PciInfo->chipType != PCI_CHIP_845_G &&
+ pI830->PciInfo->chipType != PCI_CHIP_I830_M) {
+@@ -742,6 +771,41 @@
+ return TRUE;
+ }
+
++Bool
++I830DRIResume(ScreenPtr pScreen)
++{
++ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
++ I830Ptr pI830 = I830PTR(pScrn);
++ I830DRIPtr pI830DRI = (I830DRIPtr) pI830->pDRIInfo->devPrivate;
++
++ DPRINTF(PFX, "I830DRIResume\n");
++
++ I830ResumeDma(pScrn);
++
++ {
++ pI830DRI->irq = drmGetInterruptFromBusID(pI830->drmSubFD,
++ ((pciConfigPtr) pI830->
++ PciInfo->thisCard)->busnum,
++ ((pciConfigPtr) pI830->
++ PciInfo->thisCard)->devnum,
++ ((pciConfigPtr) pI830->
++ PciInfo->thisCard)->funcnum);
++
++ if (drmCtlInstHandler(pI830->drmSubFD, pI830DRI->irq)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
++ "[drm] failure adding irq handler\n");
++ pI830DRI->irq = 0;
++ return FALSE;
++ }
++ else
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "[drm] dma control initialized, using IRQ %d\n",
++ pI830DRI->irq);
++ }
++
++ return FALSE;
++}
++
+ void
+ I830DRICloseScreen(ScreenPtr pScreen)
+ {
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i830_driver.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_driver.c 2005-08-18 19:40:24.000000000 -0400
+@@ -2,7 +2,7 @@
+ /**************************************************************************
+
+ Copyright 2001 VA Linux Systems Inc., Fremont, California.
+-Copyright © 2002 by David Dawes
++Copyright © 2002 by David Dawes
+
+ All Rights Reserved.
+
+@@ -49,7 +49,7 @@
+
+ /*
+ * Mode handling is based on the VESA driver written by:
+- * Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
++ * Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
+ */
+
+ /*
+@@ -160,11 +160,12 @@
+ #include "vgaHW.h"
+ #include "mipointer.h"
+ #include "micmap.h"
++#include "shadowfb.h"
+
+ #include "fb.h"
+ #include "miscstruct.h"
+ #include "xf86xv.h"
+-#include "Xv.h"
++#include <X11/extensions/Xv.h>
+ #include "vbe.h"
+ #include "vbeModes.h"
+
+@@ -185,6 +186,9 @@
+ {PCI_CHIP_I855_GM, "852GM/855GM"},
+ {PCI_CHIP_I865_G, "865G"},
+ {PCI_CHIP_I915_G, "915G"},
++ {PCI_CHIP_E7221_G, "E7221 (i915)"},
++ {PCI_CHIP_I915_GM, "915GM"},
++ {PCI_CHIP_I945_G, "945G"},
+ {-1, NULL}
+ };
+
+@@ -194,6 +198,9 @@
+ {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA},
+ {PCI_CHIP_I865_G, PCI_CHIP_I865_G, RES_SHARED_VGA},
+ {PCI_CHIP_I915_G, PCI_CHIP_I915_G, RES_SHARED_VGA},
++ {PCI_CHIP_E7221_G, PCI_CHIP_E7221_G, RES_SHARED_VGA},
++ {PCI_CHIP_I915_GM, PCI_CHIP_I915_GM, RES_SHARED_VGA},
++ {PCI_CHIP_I945_G, PCI_CHIP_I945_G, RES_SHARED_VGA},
+ {-1, -1, RES_UNDEFINED}
+ };
+
+@@ -218,8 +225,10 @@
+ OPTION_MONITOR_LAYOUT,
+ OPTION_CLONE,
+ OPTION_CLONE_REFRESH,
+- OPTION_CHECKLID,
+- OPTION_FLIP_PRIMARY
++ OPTION_CHECKDEVICES,
++ OPTION_FIXEDPIPE,
++ OPTION_SHADOW_FB,
++ OPTION_ROTATE
+ } I830Opts;
+
+ static OptionInfoRec I830BIOSOptions[] = {
+@@ -237,8 +246,10 @@
+ {OPTION_MONITOR_LAYOUT, "MonitorLayout", OPTV_ANYSTR,{0}, FALSE},
+ {OPTION_CLONE, "Clone", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_CLONE_REFRESH,"CloneRefresh",OPTV_INTEGER, {0}, FALSE},
+- {OPTION_CHECKLID, "CheckLid", OPTV_BOOLEAN, {0}, FALSE},
+- {OPTION_FLIP_PRIMARY,"FlipPrimary", OPTV_BOOLEAN, {0}, FALSE},
++ {OPTION_CHECKDEVICES, "CheckDevices",OPTV_BOOLEAN, {0}, FALSE},
++ {OPTION_FIXEDPIPE, "FixedPipe", OPTV_ANYSTR, {0}, FALSE},
++ {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE},
++ {OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE},
+ {-1, NULL, OPTV_NONE, {0}, FALSE}
+ };
+ /* *INDENT-ON* */
+@@ -251,7 +262,7 @@
+ static Bool I830BIOSEnterVT(int scrnIndex, int flags);
+ static Bool I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode,
+ VbeCRTCInfoBlock *block);
+-static CARD32 I830LidTimer(OsTimerPtr timer, CARD32 now, pointer arg);
++static CARD32 I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg);
+ static Bool SetPipeAccess(ScrnInfoPtr pScrn);
+ static Bool IsPrimary(ScrnInfoPtr pScrn);
+
+@@ -363,11 +374,14 @@
+ ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
+ }
+
+-/* Various extended video BIOS functions. */
+-static const int refreshes[] = {
+- 43, 56, 60, 70, 72, 75, 85, 100, 120
++/* Various extended video BIOS functions.
++ * 100 and 120Hz aren't really supported, they work but only get close
++ * to the requested refresh, and really not close enough.
++ * I've seen 100Hz come out at 104Hz, and 120Hz come out at 128Hz */
++const int i830refreshes[] = {
++ 43, 56, 60, 70, 72, 75, 85 /* 100, 120 */
+ };
+-static const int nrefreshes = sizeof(refreshes) / sizeof(refreshes[0]);
++static const int nrefreshes = sizeof(i830refreshes) / sizeof(i830refreshes[0]);
+
+ static Bool
+ Check5fStatus(ScrnInfoPtr pScrn, int func, int ax)
+@@ -390,7 +404,28 @@
+ }
+ }
+
+-#if 0
++static int
++GetToggleList(ScrnInfoPtr pScrn, int toggle)
++{
++ vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe;
++
++ DPRINTF(PFX, "GetToggleList\n");
++
++ pVbe->pInt10->num = 0x10;
++ pVbe->pInt10->ax = 0x5f64;
++ pVbe->pInt10->bx = 0x500;
++
++ pVbe->pInt10->bx |= toggle;
++
++ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
++ if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Toggle (%d) 0x%x\n", toggle, pVbe->pInt10->cx);
++ return pVbe->pInt10->cx & 0xffff;
++ }
++
++ return 0;
++}
++
+ static int
+ BitToRefresh(int bits)
+ {
+@@ -398,12 +433,12 @@
+
+ for (i = 0; i < nrefreshes; i++)
+ if (bits & (1 << i))
+- return refreshes[i];
++ return i830refreshes[i];
+ return 0;
+ }
+
+ static int
+-GetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh, int *availRefresh)
++GetRefreshRate(ScrnInfoPtr pScrn, int mode, int *availRefresh)
+ {
+ vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe;
+
+@@ -413,8 +448,6 @@
+ if (mode & 0x100)
+ return 0;
+
+- SetPipeAccess(pScrn);
+-
+ pVbe->pInt10->num = 0x10;
+ pVbe->pInt10->ax = 0x5f05;
+ pVbe->pInt10->bx = (mode & 0xff) | 0x100;
+@@ -427,48 +460,181 @@
+ } else
+ return 0;
+ }
+-#endif
+
+-static int
+-SetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh)
++struct panelid {
++ short hsize;
++ short vsize;
++ short fptype;
++ char redbpp;
++ char greenbpp;
++ char bluebpp;
++ char reservedbpp;
++ int rsvdoffscrnmemsize;
++ int rsvdoffscrnmemptr;
++ char reserved[14];
++};
++
++static void
++I830InterpretPanelID(int scrnIndex, unsigned char *tmp)
+ {
+- int i;
+- vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe;
++ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
++ struct panelid *block = (struct panelid *)tmp;
+
+- DPRINTF(PFX, "SetRefreshRate: mode 0x%x, refresh: %d\n", mode, refresh);
++#define PANEL_DEFAULT_HZ 60
+
+- /* Only 8-bit mode numbers are supported. */
+- if (mode & 0x100)
+- return 0;
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "PanelID returned panel resolution : %dx%d\n",
++ block->hsize, block->vsize);
+
+- pVbe->pInt10->num = 0x10;
+- pVbe->pInt10->ax = 0x5f05;
+- pVbe->pInt10->bx = mode & 0xff;
++ /* If we get bogus values from this, don't accept it */
++ if (block->hsize == 0 || block->vsize == 0) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Bad Panel resolution - ignoring panelID\n");
++
++ return;
++ }
++
++ /* If we have monitor timings then don't overwrite them */
++ if (pScrn->monitor->nHsync > 0 &&
++ pScrn->monitor->nVrefresh > 0)
++ return;
++
++ /* With panels, we're always assuming a refresh of 60Hz */
++
++ pScrn->monitor->nHsync = 1;
++ pScrn->monitor->nVrefresh = 1;
++
++ /* Give a little tolerance for the selected panel */
++ pScrn->monitor->hsync[0].lo = (float)((PANEL_DEFAULT_HZ/1.05)*block->vsize)/1000;
++ pScrn->monitor->hsync[0].hi = (float)((PANEL_DEFAULT_HZ/0.95)*block->vsize)/1000;
++ pScrn->monitor->vrefresh[0].lo = (float)PANEL_DEFAULT_HZ;
++ pScrn->monitor->vrefresh[0].hi = (float)PANEL_DEFAULT_HZ;
++}
++
++/* This should probably go into the VBE layer */
++static unsigned char *
++vbeReadPanelID(vbeInfoPtr pVbe)
++{
++ int RealOff = pVbe->real_mode_base;
++ pointer page = pVbe->memory;
++ unsigned char *tmp = NULL;
++ int screen = pVbe->pInt10->scrnIndex;
++
++ pVbe->pInt10->ax = 0x4F11;
++ pVbe->pInt10->bx = 0x01;
++ pVbe->pInt10->cx = 0;
++ pVbe->pInt10->dx = 0;
++ pVbe->pInt10->es = SEG_ADDR(RealOff);
++ pVbe->pInt10->di = SEG_OFF(RealOff);
++ pVbe->pInt10->num = 0x10;
++
++ xf86ExecX86int10(pVbe->pInt10);
++
++ if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
++ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID invalid\n");
++ goto error;
++ }
++ switch (pVbe->pInt10->ax & 0xff00) {
++ case 0x0:
++ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read successfully\n");
++ tmp = (unsigned char *)xnfalloc(32);
++ memcpy(tmp,page,32);
++ break;
++ case 0x100:
++ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read failed\n");
++ break;
++ default:
++ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID unknown failure %i\n",
++ pVbe->pInt10->ax & 0xff00);
++ break;
++ }
++
++ error:
++ return tmp;
++}
++
++static void
++vbeDoPanelID(vbeInfoPtr pVbe)
++{
++ unsigned char *PanelID_data;
++
++ if (!pVbe) return;
++
++ PanelID_data = vbeReadPanelID(pVbe);
++
++ if (!PanelID_data)
++ return;
++
++ I830InterpretPanelID(pVbe->pInt10->scrnIndex, PanelID_data);
++}
++
++int
++I830GetBestRefresh(ScrnInfoPtr pScrn, int refresh)
++{
++ int i;
+
+ for (i = nrefreshes - 1; i >= 0; i--) {
+ /*
+ * Look for the highest value that the requested (refresh + 2) is
+ * greater than or equal to.
+ */
+- if (refreshes[i] <= (refresh + 2))
++ if (i830refreshes[i] <= (refresh + 2))
+ break;
+ }
+ /* i can be 0 if the requested refresh was higher than the max. */
+ if (i == 0) {
+- if (refresh >= refreshes[nrefreshes - 1])
++ if (refresh >= i830refreshes[nrefreshes - 1])
+ i = nrefreshes - 1;
+ }
++
++ return i;
++}
++
++static int
++SetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh)
++{
++ vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe;
++ int i = I830GetBestRefresh(pScrn, refresh);
++
++ DPRINTF(PFX, "SetRefreshRate: mode 0x%x, refresh: %d\n", mode, refresh);
++
+ DPRINTF(PFX, "Setting refresh rate to %dHz for mode 0x%02x\n",
+- refreshes[i], mode & 0xff);
++ i830refreshes[i], mode & 0xff);
++
++ /* Only 8-bit mode numbers are supported. */
++ if (mode & 0x100)
++ return 0;
++
++ pVbe->pInt10->num = 0x10;
++ pVbe->pInt10->ax = 0x5f05;
++ pVbe->pInt10->bx = mode & 0xff;
++
+ pVbe->pInt10->cx = 1 << i;
+ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
+ if (Check5fStatus(pScrn, 0x5f05, pVbe->pInt10->ax))
+- return refreshes[i];
++ return i830refreshes[i];
+ else
+ return 0;
+ }
+
+ static Bool
++SetPowerStatus(ScrnInfoPtr pScrn, int mode)
++{
++ vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe;
++
++ pVbe->pInt10->num = 0x10;
++ pVbe->pInt10->ax = 0x5f64;
++ pVbe->pInt10->bx = 0x0800 | mode;
++ pVbe->pInt10->cx = 0x0000;
++
++ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
++ if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax))
++ return TRUE;
++
++ return FALSE;
++}
++
++static Bool
+ GetModeSupport(ScrnInfoPtr pScrn, int modePipeA, int modePipeB,
+ int devicesPipeA, int devicesPipeB, int *maxBandwidth,
+ int *bandwidthPipeA, int *bandwidthPipeB)
+@@ -480,7 +646,7 @@
+
+ /* Only 8-bit mode numbers are supported. */
+ if ((modePipeA & 0x100) || (modePipeB & 0x100))
+- return 0;
++ return FALSE;
+
+ pVbe->pInt10->num = 0x10;
+ pVbe->pInt10->ax = 0x5f28;
+@@ -575,55 +741,144 @@
+ pVbe->pInt10->bx = 0x100;
+
+ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
+- if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax))
++ if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) {
+ return pVbe->pInt10->cx & 0xffff;
+- else
+- return -1;
++ } else {
++ if (pI830->PciInfo->chipType == PCI_CHIP_E7221_G) /* FIXED CONFIG */
++ return PIPE_CRT;
++ else
++ return -1;
++ }
+ }
+
+-/* This is needed for SetDisplayDevices to work correctly on I915G
+- * and possibly later Video BIOS builds around 3272 (but not sure here).
+- * So enable for all chipsets now as it has no bad side effects, apart
+- * from slightly longer startup time.
+- */
+-#define I915G_WORKAROUND
++static int
++GetBIOSPipe(ScrnInfoPtr pScrn)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ vbeInfoPtr pVbe = pI830->pVbe;
++ int pipe;
++
++ DPRINTF(PFX, "GetBIOSPipe:\n");
++
++ /* single pipe machines should always return Pipe A */
++ if (pI830->availablePipes == 1) return 0;
++
++ pVbe->pInt10->num = 0x10;
++ pVbe->pInt10->ax = 0x5f1c;
++ pVbe->pInt10->bx = 0x100;
++
++ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
++ if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax)) {
++ if (pI830->newPipeSwitch) {
++ pipe = ((pVbe->pInt10->bx & 0x0001));
++ } else {
++ pipe = ((pVbe->pInt10->cx & 0x0100) >> 8);
++ }
++ return pipe;
++ }
++
++ /* failed, assume pipe A */
++ return 0;
++}
+
+ static Bool
+-SetDisplayDevices(ScrnInfoPtr pScrn, int devices)
++SetBIOSPipe(ScrnInfoPtr pScrn, int pipe)
+ {
+ I830Ptr pI830 = I830PTR(pScrn);
+ vbeInfoPtr pVbe = pI830->pVbe;
+- CARD32 temp;
+
+-#ifdef I915G_WORKAROUND
+- int getmode;
+- int mode;
++ DPRINTF(PFX, "SetBIOSPipe: pipe 0x%x\n", pipe);
++
++ /* single pipe machines should always return TRUE */
++ if (pI830->availablePipes == 1) return TRUE;
++
++ pVbe->pInt10->num = 0x10;
++ pVbe->pInt10->ax = 0x5f1c;
++ if (pI830->newPipeSwitch) {
++ pVbe->pInt10->bx = pipe;
++ pVbe->pInt10->cx = 0;
++ } else {
++ pVbe->pInt10->bx = 0x0;
++ pVbe->pInt10->cx = pipe << 8;
++ }
++
++ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
++ if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax)) {
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static Bool
++SetPipeAccess(ScrnInfoPtr pScrn)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++
++ /* Don't try messing with the pipe, unless we're dual head */
++ if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone || pI830->origPipe != pI830->pipe) {
++ if (!SetBIOSPipe(pScrn, pI830->pipe))
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++static Bool
++I830Set640x480(ScrnInfoPtr pScrn)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ int m = 0x30; /* 640x480 8bpp */
++
+ switch (pScrn->depth) {
+- case 8:
+- mode = 0x30;
+- break;
+ case 15:
+- mode = 0x40;
+- break;
++ m = 0x40;
++ break;
+ case 16:
+- mode = 0x41;
+- break;
++ m = 0x41;
++ break;
+ case 24:
+- mode = 0x50;
+- break;
+- default:
+- mode = 0x30;
+- break;
++ m = 0x50;
++ break;
+ }
+- mode |= (1 << 15) | (1 << 14);
++ m |= (1 << 15) | (1 << 14);
++ return VBESetVBEMode(pI830->pVbe, m, NULL);
++}
++
++/* This is needed for SetDisplayDevices to work correctly on I915G.
++ * Enable for all chipsets now as it has no bad side effects, apart
++ * from slightly longer startup time.
++ */
++#define I915G_WORKAROUND
++
++static Bool
++SetDisplayDevices(ScrnInfoPtr pScrn, int devices)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ vbeInfoPtr pVbe = pI830->pVbe;
++ CARD32 temp;
++ int singlepipe = 0;
++#ifdef I915G_WORKAROUND
++ int getmode1;
++ Bool setmode = FALSE;
+ #endif
+
+ DPRINTF(PFX, "SetDisplayDevices: devices 0x%x\n", devices);
+
++ if (!pI830->specifiedMonitor)
++ return TRUE;
++
+ #ifdef I915G_WORKAROUND
+- if (pI830->bios_version >= 3272) {
+- VBEGetVBEMode(pVbe, &getmode);
+- I830VESASetVBEMode(pScrn, mode, NULL);
++ if (pI830->preinit)
++ setmode = TRUE;
++ if (pI830->leaving)
++ setmode = FALSE;
++ if (pI830->closing)
++ setmode = FALSE;
++
++ if (setmode) {
++ VBEGetVBEMode(pVbe, &getmode1);
++ I830Set640x480(pScrn);
+ }
+ #endif
+
+@@ -635,28 +890,146 @@
+ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
+ if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) {
+ #ifdef I915G_WORKAROUND
+- if (pI830->bios_version >= 3272)
+- I830VESASetVBEMode(pScrn, getmode, NULL);
++ if (setmode) {
++ VBESetVBEMode(pI830->pVbe, getmode1 | 1<<15, NULL);
++ }
+ #endif
++ pI830->pipeEnabled[0] = (devices & 0xff) ? TRUE : FALSE;
++ pI830->pipeEnabled[1] = (devices & 0xff00) ? TRUE : FALSE;
++
+ return TRUE;
+ }
+
+ #ifdef I915G_WORKAROUND
+- if (pI830->bios_version >= 3272)
+- I830VESASetVBEMode(pScrn, getmode, NULL);
++ if (setmode)
++ VBESetVBEMode(pI830->pVbe, getmode1 | 1<<15, NULL);
+ #endif
+
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "SetDisplayDevices call failed, writing config directly to SWF0.\n");
++ if (devices & 0xff) {
++ pVbe->pInt10->num = 0x10;
++ pVbe->pInt10->ax = 0x5f64;
++ pVbe->pInt10->bx = 0x1;
++ pVbe->pInt10->cx = devices & 0xff;
++
++ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
++ if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Successfully set display devices to 0x%x.\n",devices & 0xff);
++ singlepipe = devices & 0xff00; /* set alternate */
++ } else {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Failed to set display devices to 0x%x.\n",devices & 0xff);
++ singlepipe = devices;
++ }
++ } else
++ singlepipe = devices;
++
++ if (singlepipe == devices && devices & 0xff00) {
++ pVbe->pInt10->num = 0x10;
++ pVbe->pInt10->ax = 0x5f64;
++ pVbe->pInt10->bx = 0x1;
++ pVbe->pInt10->cx = devices & 0xff00;
++
++ xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
++ if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Successfully set display devices to 0x%x.\n",devices & 0xff00);
++ singlepipe = devices & 0xff; /* set alternate */
++ } else {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Failed to set display devices to 0x%x.\n",devices & 0xff00);
++ singlepipe = devices;
++ }
++ }
++
++ /* LVDS doesn't exist on these */
++ if (IS_I830(pI830) || IS_845G(pI830) || IS_I865G(pI830))
++ singlepipe &= ~(PIPE_LFP | (PIPE_LFP<<8));
++
++ if (pI830->availablePipes == 1)
++ singlepipe &= 0xFF;
++
++ /* Disable LVDS */
++ if (singlepipe & PIPE_LFP) {
++ /* LFP on PipeA is unlikely! */
++ OUTREG(0x61200, INREG(0x61200) & ~0x80000000);
++ OUTREG(0x61204, INREG(0x61204) & ~0x00000001);
++ while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1));
++ /* Fix up LVDS */
++ OUTREG(LVDS, (INREG(LVDS) & ~1<<30) | 0x80000300);
++ /* Enable LVDS */
++ OUTREG(0x61200, INREG(0x61200) | 0x80000000);
++ OUTREG(0x61204, INREG(0x61204) | 0x00000001);
++ while (!(INREG(0x61200) & 0x80000000) && !(INREG(0x61204) & 1));
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Enabling LVDS directly. Pipe A.\n");
++ } else
++ if (singlepipe & (PIPE_LFP << 8)) {
++ OUTREG(0x61200, INREG(0x61200) & ~0x80000000);
++ OUTREG(0x61204, INREG(0x61204) & ~0x00000001);
++ while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1));
++ /* Fix up LVDS */
++ OUTREG(LVDS, (INREG(LVDS) | 1<<30) | 0x80000300);
++ /* Enable LVDS */
++ OUTREG(0x61200, INREG(0x61200) | 0x80000000);
++ OUTREG(0x61204, INREG(0x61204) | 0x00000001);
++ while (!(INREG(0x61200) & 0x80000000) && !(INREG(0x61204) & 1));
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Enabling LVDS directly. Pipe B.\n");
++ }
++ else if (!(IS_I830(pI830) || IS_845G(pI830) || IS_I865G(pI830))) {
++ if (!(devices & (PIPE_LFP | PIPE_LFP<<8))) {
++ OUTREG(0x61200, INREG(0x61200) & ~0x80000000);
++ OUTREG(0x61204, INREG(0x61204) & ~0x00000001);
++ while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1));
++ /* Fix up LVDS */
++ OUTREG(LVDS, (INREG(LVDS) | 1<<30) & ~0x80000300);
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Disabling LVDS directly.\n");
++ }
++ }
++
++ /* Now try to program the registers directly if the BIOS failed. */
++ temp = INREG(ADPA);
++ temp &= ~(ADPA_DAC_ENABLE | ADPA_PIPE_SELECT_MASK);
++ temp &= ~(ADPA_VSYNC_CNTL_DISABLE | ADPA_HSYNC_CNTL_DISABLE);
++ /* Turn on ADPA */
++ if (singlepipe & PIPE_CRT) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Enabling ADPA directly. Pipe A.\n");
++ temp |= ADPA_DAC_ENABLE | ADPA_PIPE_A_SELECT;
++ OUTREG(ADPA, temp);
++ } else
++ if (singlepipe & (PIPE_CRT << 8)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Enabling ADPA directly. Pipe B.\n");
++ temp |= ADPA_DAC_ENABLE | ADPA_PIPE_B_SELECT;
++ OUTREG(ADPA, temp);
++ }
++ else {
++ if (!(devices & (PIPE_CRT | PIPE_CRT<<8))) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Disabling ADPA directly.\n");
++ temp |= ADPA_VSYNC_CNTL_DISABLE | ADPA_HSYNC_CNTL_DISABLE;
++ OUTREG(ADPA, temp);
++ }
++ }
++
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,"Writing config directly to SWF0.\n");
+ temp = INREG(SWF0);
+ OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff));
+
+- if (GetDisplayDevices(pScrn) != devices)
++ if (GetDisplayDevices(pScrn) != devices) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "SetDisplayDevices failed with devices 0x%x instead of 0x%x\n",
+ GetDisplayDevices(pScrn), devices);
++ return FALSE;
++ }
+
+- return FALSE;
++ pI830->pipeEnabled[0] = (devices & 0xff) ? TRUE : FALSE;
++ pI830->pipeEnabled[1] = (devices & 0xff00) ? TRUE : FALSE;
++
++ return TRUE;
+ }
+
+ static Bool
+@@ -916,9 +1289,10 @@
+ /* Check for active devices connected to each display pipe. */
+ for (n = 0; n < pI830->availablePipes; n++) {
+ pipe = ((pI830->operatingDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK);
+- if (pipe) {
++ if (pipe)
+ pI830->pipeEnabled[n] = TRUE;
+- }
++ else
++ pI830->pipeEnabled[n] = FALSE;
+ }
+
+ GetPipeSizes(pScrn);
+@@ -942,7 +1316,7 @@
+ * The GTT varying according the the FbMapSize and the popup is 4KB */
+ range = (pI830->FbMapSize / (1024*1024)) + 4;
+
+- if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830)) {
++ if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
+ switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ case I855_GMCH_GMS_STOLEN_1M:
+ memsize = MB(1) - KB(range);
+@@ -960,11 +1334,11 @@
+ memsize = MB(32) - KB(range);
+ break;
+ case I915G_GMCH_GMS_STOLEN_48M:
+- if (IS_I915G(pI830))
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))
+ memsize = MB(48) - KB(range);
+ break;
+ case I915G_GMCH_GMS_STOLEN_64M:
+- if (IS_I915G(pI830))
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))
+ memsize = MB(64) - KB(range);
+ break;
+ }
+@@ -1331,157 +1705,189 @@
+ }
+ }
+
+-/*
+- * Use the native method instead of the vgahw method. So far this is
+- * only used for 8-bit mode.
+- *
+- * XXX Look into using the 10-bit gamma correction mode for 15/16/24 bit,
+- * and see if a DirectColor visual can be offered.
+- */
+ static void
+ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
+ LOCO * colors, VisualPtr pVisual)
+ {
+ I830Ptr pI830;
+- int i, index;
++ int i,j, index;
+ unsigned char r, g, b;
+ CARD32 val, temp;
++ int palreg;
++ int dspreg, dspbase;
+
+ DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors);
+ pI830 = I830PTR(pScrn);
+
+ if (pI830->pipe == 0) {
+- /* It seems that an initial read is needed. */
+- temp = INREG(PALETTE_A);
++ palreg = PALETTE_A;
++ dspreg = DSPACNTR;
++ dspbase = DSPABASE;
++ } else {
++ palreg = PALETTE_B;
++ dspreg = DSPBCNTR;
++ dspbase = DSPBBASE;
++ }
++
++ OUTREG(dspreg, INREG(dspreg) | DISPPLANE_GAMMA_ENABLE);
++ OUTREG(dspbase, INREG(dspbase));
++
++ /* It seems that an initial read is needed. */
++ temp = INREG(palreg);
++
++ switch(pScrn->depth) {
++ case 15:
+ for (i = 0; i < numColors; i++) {
+- index = indices[i];
+- r = colors[index].red;
+- g = colors[index].green;
+- b = colors[index].blue;
+- val = (r << 16) | (g << 8) | b;
+- OUTREG(PALETTE_A + index * 4, val);
++ index = indices[i];
++ r = colors[index].red;
++ g = colors[index].green;
++ b = colors[index].blue;
++ for (j = 0; j < 8; j++) {
++ val = (r << 16) | (g << 8) | b;
++ OUTREG(palreg + index * 32 + (j * 4), val);
++ }
+ }
+- }
+- if (pI830->pipe == 1) {
+- /* It seems that an initial read is needed. */
+- temp = INREG(PALETTE_B);
++ break;
++ case 16:
+ for (i = 0; i < numColors; i++) {
++ index = indices[i / 2];
++ r = colors[index].red;
++ b = colors[index].blue;
++ index = indices[i];
++ g = colors[index].green;
++
++ val = (r << 16) | (g << 8) | b;
++ OUTREG(palreg + index * 16, val);
++ OUTREG(palreg + index * 16 + 4, val);
++ OUTREG(palreg + index * 16 + 8, val);
++ OUTREG(palreg + index * 16 + 12, val);
++
++ i++;
++ index = indices[i];
++ g = colors[index].green;
++
++ val = (r << 16) | (g << 8) | b;
++ OUTREG(palreg + index * 16, val);
++ OUTREG(palreg + index * 16 + 4, val);
++ OUTREG(palreg + index * 16 + 8, val);
++ OUTREG(palreg + index * 16 + 12, val);
++ }
++ break;
++ default:
++ for(i = 0; i < numColors; i++) {
+ index = indices[i];
+ r = colors[index].red;
+ g = colors[index].green;
+ b = colors[index].blue;
+ val = (r << 16) | (g << 8) | b;
+- OUTREG(PALETTE_B + index * 4, val);
++ OUTREG(palreg + index * 4, val);
+ }
++ break;
+ }
+ }
+
+-static void
+-PreInitCleanup(ScrnInfoPtr pScrn)
+-{
+- I830Ptr pI830 = I830PTR(pScrn);
+-
+- if (IsPrimary(pScrn) && pI830->LpRing) {
+- xfree(pI830->LpRing);
+- pI830->LpRing = NULL;
+- }
+- if (IsPrimary(pScrn) && pI830->CursorMem) {
+- xfree(pI830->CursorMem);
+- pI830->CursorMem = NULL;
+- }
+- if (IsPrimary(pScrn) && pI830->CursorMemARGB) {
+- xfree(pI830->CursorMemARGB);
+- pI830->CursorMemARGB = NULL;
+- }
+- if (IsPrimary(pScrn) && pI830->OverlayMem) {
+- xfree(pI830->OverlayMem);
+- pI830->OverlayMem = NULL;
+- }
+- if (IsPrimary(pScrn) && pI830->overlayOn) {
+- xfree(pI830->overlayOn);
+- pI830->overlayOn = NULL;
+- }
+- if (!IsPrimary(pScrn) && pI830->entityPrivate)
+- pI830->entityPrivate->pScrn_2 = NULL;
+- RestoreBIOSMemSize(pScrn);
+- if (pI830->swfSaved) {
+- OUTREG(SWF0, pI830->saveSWF0);
+- OUTREG(SWF4, pI830->saveSWF4);
+- }
+- if (pI830->MMIOBase)
+- I830UnmapMMIO(pScrn);
+- I830BIOSFreeRec(pScrn);
+-}
+-
+ static int
+-GetBIOSPipe(ScrnInfoPtr pScrn)
++I830UseDDC(ScrnInfoPtr pScrn)
+ {
+- I830Ptr pI830 = I830PTR(pScrn);
+- vbeInfoPtr pVbe = pI830->pVbe;
+- int pipe;
+-
+- DPRINTF(PFX, "GetBIOSPipe:\n");
+-
+- /* single pipe machines should always return Pipe A */
+- if (pI830->availablePipes == 1) return 0;
+-
+- pVbe->pInt10->num = 0x10;
+- pVbe->pInt10->ax = 0x5f1c;
+- pVbe->pInt10->bx = 0x100;
+-
+- xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
+- if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax)) {
+- if (pI830->newPipeSwitch) {
+- pipe = ((pVbe->pInt10->bx & 0x0001));
+- } else {
+- pipe = ((pVbe->pInt10->cx & 0x0100) >> 8);
+- }
+- return pipe;
+- }
+-
+- return -1;
+-}
+-
+-static Bool
+-SetBIOSPipe(ScrnInfoPtr pScrn, int pipe)
+-{
+- I830Ptr pI830 = I830PTR(pScrn);
+- vbeInfoPtr pVbe = pI830->pVbe;
++ xf86MonPtr DDC = (xf86MonPtr)(pScrn->monitor->DDC);
++ struct detailed_monitor_section* detMon;
++ struct monitor_ranges *mon_range = NULL;
++ int i;
+
+- DPRINTF(PFX, "SetBIOSPipe: pipe 0x%x\n", pipe);
++ if (!DDC) return 0;
+
+- /* single pipe machines should always return TRUE */
+- if (pI830->availablePipes == 1) return TRUE;
++ /* Now change the hsync/vrefresh values of the current monitor to
++ * match those of DDC */
++ for (i = 0; i < 4; i++) {
++ detMon = &DDC->det_mon[i];
++ if(detMon->type == DS_RANGES)
++ mon_range = &detMon->section.ranges;
++ }
++
++ if (!mon_range || mon_range->min_h == 0 || mon_range->max_h == 0 ||
++ mon_range->min_v == 0 || mon_range->max_v == 0)
++ return 0; /* bad ddc */
++
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using detected DDC timings\n");
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tHorizSync %d-%d\n",
++ mon_range->min_h, mon_range->max_h);
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tVertRefresh %d-%d\n",
++ mon_range->min_v, mon_range->max_v);
++#define DDC_SYNC_TOLERANCE SYNC_TOLERANCE
++ if (pScrn->monitor->nHsync > 0) {
++ for (i = 0; i < pScrn->monitor->nHsync; i++) {
++ if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_h >
++ pScrn->monitor->hsync[i].lo ||
++ (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_h <
++ pScrn->monitor->hsync[i].hi) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "config file hsync range %g-%gkHz not within DDC "
++ "hsync range %d-%dkHz\n",
++ pScrn->monitor->hsync[i].lo, pScrn->monitor->hsync[i].hi,
++ mon_range->min_h, mon_range->max_h);
++ }
++ pScrn->monitor->hsync[i].lo = mon_range->min_h;
++ pScrn->monitor->hsync[i].hi = mon_range->max_h;
++ }
++ }
+
+- pVbe->pInt10->num = 0x10;
+- pVbe->pInt10->ax = 0x5f1c;
+- if (pI830->newPipeSwitch) {
+- pVbe->pInt10->bx = pipe;
+- pVbe->pInt10->cx = 0;
+- } else {
+- pVbe->pInt10->bx = 0x0;
+- pVbe->pInt10->cx = pipe << 8;
++ if (pScrn->monitor->nVrefresh > 0) {
++ for (i=0; i<pScrn->monitor->nVrefresh; i++) {
++ if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_v >
++ pScrn->monitor->vrefresh[i].lo ||
++ (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_v <
++ pScrn->monitor->vrefresh[i].hi) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "config file vrefresh range %g-%gHz not within DDC "
++ "vrefresh range %d-%dHz\n",
++ pScrn->monitor->vrefresh[i].lo, pScrn->monitor->vrefresh[i].hi,
++ mon_range->min_v, mon_range->max_v);
++ }
++ pScrn->monitor->vrefresh[i].lo = mon_range->min_v;
++ pScrn->monitor->vrefresh[i].hi = mon_range->max_v;
++ }
+ }
+
+- xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
+- if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax))
+- return TRUE;
+-
+- return FALSE;
++ return mon_range->max_clock;
+ }
+
+-static Bool
+-SetPipeAccess(ScrnInfoPtr pScrn)
++static void
++PreInitCleanup(ScrnInfoPtr pScrn)
+ {
+ I830Ptr pI830 = I830PTR(pScrn);
+
+- /* Don't try messing with the pipe, unless we're dual head */
+- if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) {
+- if (!SetBIOSPipe(pScrn, pI830->pipe))
+- return FALSE;
++ if (IsPrimary(pScrn))
++ pI830->entityPrivate->pScrn_1 = NULL;
++ if (IsPrimary(pScrn) && pI830->LpRing) {
++ xfree(pI830->LpRing);
++ pI830->LpRing = NULL;
+ }
+-
+- return TRUE;
++ if (IsPrimary(pScrn) && pI830->CursorMem) {
++ xfree(pI830->CursorMem);
++ pI830->CursorMem = NULL;
++ }
++ if (IsPrimary(pScrn) && pI830->CursorMemARGB) {
++ xfree(pI830->CursorMemARGB);
++ pI830->CursorMemARGB = NULL;
++ }
++ if (IsPrimary(pScrn) && pI830->OverlayMem) {
++ xfree(pI830->OverlayMem);
++ pI830->OverlayMem = NULL;
++ }
++ if (IsPrimary(pScrn) && pI830->overlayOn) {
++ xfree(pI830->overlayOn);
++ pI830->overlayOn = NULL;
++ }
++ if (!IsPrimary(pScrn) && pI830->entityPrivate)
++ pI830->entityPrivate->pScrn_2 = NULL;
++ RestoreBIOSMemSize(pScrn);
++ if (pI830->swfSaved) {
++ OUTREG(SWF0, pI830->saveSWF0);
++ OUTREG(SWF4, pI830->saveSWF4);
++ }
++ if (pI830->MMIOBase)
++ I830UnmapMMIO(pScrn);
++ I830BIOSFreeRec(pScrn);
+ }
+
+ static Bool
+@@ -1508,9 +1914,12 @@
+ I830EntPtr pI830Ent = NULL;
+ int mem, memsize;
+ int flags24;
++ int defmon = 0;
+ int i, n;
++ int DDCclock = 0;
+ char *s;
+- pointer pDDCModule, pVBEModule;
++ DisplayModePtr p, pMon;
++ pointer pDDCModule = NULL, pVBEModule = NULL;
+ Bool enable;
+ const char *chipname;
+ unsigned int ver;
+@@ -1660,6 +2069,15 @@
+ case PCI_CHIP_I915_G:
+ chipname = "915G";
+ break;
++ case PCI_CHIP_E7221_G:
++ chipname = "E7221 (i915)";
++ break;
++ case PCI_CHIP_I915_GM:
++ chipname = "915GM";
++ break;
++ case PCI_CHIP_I945_G:
++ chipname = "945G";
++ break;
+ default:
+ chipname = "unknown chipset";
+ break;
+@@ -1697,7 +2115,7 @@
+ pI830->LinearAddr = pI830->pEnt->device->MemBase;
+ from = X_CONFIG;
+ } else {
+- if (IS_I915G(pI830)) {
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
+ pI830->LinearAddr = pI830->PciInfo->memBase[2] & 0xF0000000;
+ from = X_PROBED;
+ } else if (pI830->PciInfo->memBase[1] != 0) {
+@@ -1719,7 +2137,7 @@
+ pI830->MMIOAddr = pI830->pEnt->device->IOBase;
+ from = X_CONFIG;
+ } else {
+- if (IS_I915G(pI830)) {
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
+ pI830->MMIOAddr = pI830->PciInfo->memBase[0] & 0xFFF80000;
+ from = X_PROBED;
+ } else if (pI830->PciInfo->memBase[1]) {
+@@ -1764,11 +2182,14 @@
+ pI830->FbMapSize = 0x4000000; /* 64MB - has this been tested ?? */
+ }
+ } else {
+- if (IS_I915G(pI830)) {
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
+ if (pI830->PciInfo->memBase[2] & 0x08000000)
+ pI830->FbMapSize = 0x8000000; /* 128MB aperture */
+ else
+ pI830->FbMapSize = 0x10000000; /* 256MB aperture */
++
++ if (pI830->PciInfo->chipType == PCI_CHIP_E7221_G)
++ pI830->FbMapSize = 0x8000000; /* 128MB aperture */
+ } else
+ /* 128MB aperture for later chips */
+ pI830->FbMapSize = 0x8000000;
+@@ -1791,7 +2212,10 @@
+ }
+ }
+
+- if (IS_MOBILE(pI830) || IS_I915G(pI830))
++ if (pI830->PciInfo->chipType == PCI_CHIP_E7221_G)
++ pI830->availablePipes = 1;
++ else
++ if (IS_MOBILE(pI830) || IS_I915G(pI830) || IS_I945G(pI830))
+ pI830->availablePipes = 2;
+ else
+ pI830->availablePipes = 1;
+@@ -1866,8 +2290,19 @@
+ }
+ #endif
+
++ pI830->fixedPipe = -1;
++ if ((s = xf86GetOptValString(pI830->Options, OPTION_FIXEDPIPE)) &&
++ IsPrimary(pScrn)) {
++
++ if (strstr(s, "A") || strstr(s, "a") || strstr(s, "0"))
++ pI830->fixedPipe = 0;
++ else if (strstr(s, "B") || strstr(s, "b") || strstr(s, "1"))
++ pI830->fixedPipe = 1;
++ }
++
+ pI830->MonType1 = PIPE_NONE;
+ pI830->MonType2 = PIPE_NONE;
++ pI830->specifiedMonitor = FALSE;
+
+ if ((s = xf86GetOptValString(pI830->Options, OPTION_MONITOR_LAYOUT)) &&
+ IsPrimary(pScrn)) {
+@@ -1947,6 +2382,8 @@
+ "Monitor 1 and 2 cannot be type NONE\n");
+ return FALSE;
+ }
++
++ pI830->specifiedMonitor = TRUE;
+ }
+
+ if (xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) {
+@@ -1963,21 +2400,24 @@
+ return FALSE;
+ }
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling Clone Mode\n");
+- pI830->CloneRefresh = 60; /* default to 60Hz */
+- if (xf86GetOptValInteger(pI830->Options, OPTION_CLONE_REFRESH,
++ pI830->Clone = TRUE;
++ }
++
++ pI830->CloneRefresh = 60; /* default to 60Hz */
++ if (xf86GetOptValInteger(pI830->Options, OPTION_CLONE_REFRESH,
+ &(pI830->CloneRefresh))) {
+- xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Clone Monitor Refresh Rate %d\n",
++ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Clone Monitor Refresh Rate %d\n",
+ pI830->CloneRefresh);
+- }
+- if (pI830->CloneRefresh < 60 || pI830->CloneRefresh > 120) {
+- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad Clone Refresh Rate\n");
+- PreInitCleanup(pScrn);
+- return FALSE;
+- }
+- pI830->Clone = TRUE;
+ }
+
+- if ((pI830->entityPrivate && IsPrimary(pScrn)) || pI830->Clone) {
++ /* See above i830refreshes on why 120Hz is commented out */
++ if (pI830->CloneRefresh < 60 || pI830->CloneRefresh > 85 /* 120 */) {
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad Clone Refresh Rate\n");
++ PreInitCleanup(pScrn);
++ return FALSE;
++ }
++
++ if ((pI830->entityPrivate && IsPrimary(pScrn)) || pI830->Clone) {
+ if ((!xf86GetOptValString(pI830->Options, OPTION_MONITOR_LAYOUT))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "You must have a MonitorLayout "
+ "defined for use in a DualHead or Clone setup.\n");
+@@ -1993,26 +2433,57 @@
+ }
+ }
+
++ xf86GetOptValBool(pI830->Options, OPTION_SHADOW_FB, &pI830->shadowFB);
++ if (pI830->shadowFB) {
++ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: shadow FB enabled\n");
++ }
++
++ if ((s = xf86GetOptValString(pI830->Options, OPTION_ROTATE))) {
++ if(!xf86NameCmp(s, "CW")) {
++ /* accel is disabled below for shadowFB */
++ pI830->shadowFB = TRUE;
++ pI830->rotate = 1;
++ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
++ "Rotating screen clockwise - acceleration disabled\n");
++ } else if(!xf86NameCmp(s, "CCW")) {
++ pI830->shadowFB = TRUE;
++ pI830->rotate = -1;
++ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen"
++ "counter clockwise - acceleration disabled\n");
++ } else {
++ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
++ "value for Option \"Rotate\"\n", s);
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Valid options are \"CW\" or \"CCW\"\n");
++ }
++ }
++
++ if (pI830->shadowFB && !pI830->noAccel) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "HW acceleration not supported with \"shadowFB\".\n");
++ pI830->noAccel = TRUE;
++ }
++
+ /*
+ * Let's setup the mobile systems to check the lid status
+ */
+ if (IS_MOBILE(pI830)) {
+- pI830->checkLid = TRUE;
++ pI830->checkDevices = TRUE;
+
+- if (!xf86ReturnOptValBool(pI830->Options, OPTION_CHECKLID, TRUE)) {
+- pI830->checkLid = FALSE;
+- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status disabled\n");
++ if (!xf86ReturnOptValBool(pI830->Options, OPTION_CHECKDEVICES, TRUE)) {
++ pI830->checkDevices = FALSE;
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays disabled\n");
+ } else
+ if (pI830->entityPrivate && !IsPrimary(pScrn) &&
+- !I830PTR(pI830->entityPrivate->pScrn_1)->checkLid) {
++ !I830PTR(pI830->entityPrivate->pScrn_1)->checkDevices) {
+ /* If checklid is off, on the primary head, then
+ * turn it off on the secondary*/
+- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status disabled\n");
+- pI830->checkLid = FALSE;
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays disabled\n");
++ pI830->checkDevices = FALSE;
+ } else
+- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status enabled\n");
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays enabled\n");
+ } else
+- pI830->checkLid = FALSE;
++ pI830->checkDevices = FALSE;
+
+ /*
+ * The "VideoRam" config file parameter specifies the total amount of
+@@ -2215,13 +2686,22 @@
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS Build: %d\n",pI830->bios_version);
+
+- /* BIOS build 3062 changed the pipe switching functionality */
+- if (pI830->availablePipes == 2 && pI830->bios_version >= 3062) {
++ /* Great..
++ * Intel changed the BIOS version codes and started at 1200.
++ * We know that bios codes for 830M started around 2400.
++ * So we test those conditions to make this judgement. Ugh.
++ */
++ if (pI830->availablePipes == 2 && pI830->bios_version < 2000)
+ pI830->newPipeSwitch = TRUE;
+- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using new Pipe switch code\n");
+- } else
++ else if (pI830->availablePipes == 2 && pI830->bios_version >= 3062)
++ /* BIOS build 3062 changed the pipe switching functionality */
++ pI830->newPipeSwitch = TRUE;
++ else
+ pI830->newPipeSwitch = FALSE;
+
++ if (pI830->newPipeSwitch)
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using new Pipe switch code\n");
++
+ pI830->devicePresence = FALSE;
+ from = X_DEFAULT;
+ if (xf86ReturnOptValBool(pI830->Options, OPTION_DEVICE_PRESENCE, FALSE)) {
+@@ -2250,18 +2730,29 @@
+ pI830->savedDevices = GetDisplayDevices(pScrn);
+
+ if (IsPrimary(pScrn)) {
+- pI830->pipe = GetBIOSPipe(pScrn);
+-
+- if (xf86ReturnOptValBool(pI830->Options, OPTION_FLIP_PRIMARY, FALSE)) {
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Primary flipping enabled\n");
+- pI830->pipe = !pI830->pipe;
+- }
++ pI830->pipe = pI830->origPipe = GetBIOSPipe(pScrn);
+
++ /* Override */
++ if (pI830->fixedPipe != -1) {
++ if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) {
++ pI830->pipe = pI830->fixedPipe;
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Fixed Pipe setting primary to pipe %s.\n",
++ pI830->fixedPipe ? "B" : "A");
++ }
++ }
++
+ /* If the monitors aren't setup, read from the current config */
+- if (pI830->MonType1 == PIPE_NONE)
++ if (pI830->MonType1 == PIPE_NONE && pI830->MonType2 == PIPE_NONE) {
+ pI830->MonType1 = pI830->savedDevices & 0xff;
+- if (pI830->MonType2 == PIPE_NONE)
+ pI830->MonType2 = (pI830->savedDevices & 0xff00) >> 8;
++ } else {
++ /* Here, we've switched pipes from our primary */
++ if (pI830->MonType1 == PIPE_NONE && pI830->pipe == 0)
++ pI830->pipe = 1;
++ if (pI830->MonType2 == PIPE_NONE && pI830->pipe == 1)
++ pI830->pipe = 0;
++ }
+
+ pI830->operatingDevices = (pI830->MonType2 << 8) | pI830->MonType1;
+
+@@ -2273,15 +2764,18 @@
+ pI830->operatingDevices = pI830->MonType1;
+ else
+ pI830->operatingDevices = pI830->MonType2 << 8;
+-
+- if (pI830->operatingDevices & 0xFF00)
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Primary Pipe is %s, switching off second monitor (0x%x)\n",
+- pI830->pipe ? "B" : "A", pI830->operatingDevices);
+ }
++
++ if (pI830->pipe != pI830->origPipe)
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Primary Pipe has been switched from original pipe (%s to %s)\n",
++ pI830->origPipe ? "B" : "A", pI830->pipe ? "B" : "A");
+ } else {
+ I830Ptr pI8301 = I830PTR(pI830Ent->pScrn_1);
+ pI830->operatingDevices = pI8301->operatingDevices;
++ pI830->pipe = !pI8301->pipe;
++ pI830->MonType1 = pI8301->MonType1;
++ pI830->MonType2 = pI8301->MonType2;
+ }
+
+ /* Buggy BIOS 3066 is known to cause this, so turn this off */
+@@ -2309,26 +2803,25 @@
+ return FALSE;
+ }
+
+- if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) {
+- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
++ if (IsPrimary(pScrn)) {
++ if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to switch to monitor configuration (0x%x)\n",
+ pI830->operatingDevices);
+- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Please check the devices specified in your MonitorLayout\n");
+- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "is configured correctly.\n");
+- PreInitCleanup(pScrn);
+- return FALSE;
++ PreInitCleanup(pScrn);
++ return FALSE;
++ }
+ }
+
+ PrintDisplayDeviceInfo(pScrn);
+
+ if (xf86IsEntityShared(pScrn->entityList[0])) {
+ if (!IsPrimary(pScrn)) {
+- I830Ptr pI8301 = I830PTR(pI830Ent->pScrn_1);
+-
+ pI830Ent->pScrn_2 = pScrn;
+- pI830->pipe = !pI8301->pipe;
+
+ /* This could be made to work with a little more fiddling */
+ pI830->directRenderingDisabled = TRUE;
+@@ -2367,14 +2860,13 @@
+ }
+
+ /* Check if the HW cursor needs physical address. */
+- if (IS_MOBILE(pI830) || IS_I915G(pI830))
++ if (IS_MOBILE(pI830) || IS_I915G(pI830) || IS_I945G(pI830))
+ pI830->CursorNeedsPhysical = TRUE;
+ else
+ pI830->CursorNeedsPhysical = FALSE;
+
+- /* Force ring buffer to be in low memory for the 845G and later. */
+- if (IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830))
+- pI830->NeedRingBufferLow = TRUE;
++ /* Force ring buffer to be in low memory for all chipsets */
++ pI830->NeedRingBufferLow = TRUE;
+
+ /*
+ * XXX If we knew the pre-initialised GTT format for certain, we could
+@@ -2413,14 +2905,17 @@
+ "Maximum frambuffer space: %d kByte\n", pScrn->videoRam);
+
+ SetPipeAccess(pScrn);
+- if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) {
+- PreInitCleanup(pScrn);
+- return FALSE;
+- }
+
+- if ((pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule)) != NULL) {
+- xf86PrintEDID(pI830->vesa->monitor);
+- }
++ /* Check we have an LFP connected, before trying to
++ * read PanelID information. */
++ if ( (pI830->pipe == 1 && pI830->operatingDevices & (PIPE_LFP << 8)) ||
++ (pI830->pipe == 0 && pI830->operatingDevices & PIPE_LFP) )
++ vbeDoPanelID(pI830->pVbe);
++
++ pDDCModule = xf86LoadSubModule(pScrn, "ddc");
++
++ pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
++
+ if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL)
+ xf86SetDDCproperties(pScrn, pI830->vesa->monitor);
+ xf86UnloadSubModule(pDDCModule);
+@@ -2485,7 +2980,7 @@
+ }
+ }
+
+- if (pI830->useExtendedRefresh) {
++ if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Will use BIOS call 0x5f05 to set refresh rates for CRTs.\n");
+ }
+@@ -2501,13 +2996,38 @@
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "Maximum space available for video modes: %d kByte\n", memsize);
+
++ /* By now, we should have had some monitor settings, but if not, we
++ * need to setup some defaults. These are used in common/xf86Modes.c
++ * so we'll use them here for GetModePool, and that's all.
++ * We unset them after the call, so we can report 'defaults' as being
++ * used through the common layer.
++ */
++#define DEFAULT_HSYNC_LO 28
++#define DEFAULT_HSYNC_HI 33
++#define DEFAULT_VREFRESH_LO 43
++#define DEFAULT_VREFRESH_HI 72
++
++ if (pScrn->monitor->nHsync == 0) {
++ pScrn->monitor->hsync[0].lo = DEFAULT_HSYNC_LO;
++ pScrn->monitor->hsync[0].hi = DEFAULT_HSYNC_HI;
++ pScrn->monitor->nHsync = 1;
++ defmon |= 1;
++ }
++
++ if (pScrn->monitor->nVrefresh == 0) {
++ pScrn->monitor->vrefresh[0].lo = DEFAULT_VREFRESH_LO;
++ pScrn->monitor->vrefresh[0].hi = DEFAULT_VREFRESH_HI;
++ pScrn->monitor->nVrefresh = 1;
++ defmon |= 2;
++ }
++
++ DDCclock = I830UseDDC(pScrn);
++
+ /*
+ * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS
+- * functions. For that reason it's important to set only
+- * V_MODETYPE_VGA in the flags for VBEGetModePool().
++ * functions.
+ */
+- pScrn->modePool = VBEGetModePool(pScrn, pI830->pVbe, pI830->vbeInfo,
+- V_MODETYPE_VGA);
++ pScrn->modePool = I830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo);
+
+ if (!pScrn->modePool) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+@@ -2516,6 +3036,21 @@
+ return FALSE;
+ }
+
++ /* This may look a little weird, but to notify that we're using the
++ * default hsync/vrefresh we need to unset what we just set .....
++ */
++ if (defmon & 1) {
++ pScrn->monitor->hsync[0].lo = 0;
++ pScrn->monitor->hsync[0].hi = 0;
++ pScrn->monitor->nHsync = 0;
++ }
++
++ if (defmon & 2) {
++ pScrn->monitor->vrefresh[0].lo = 0;
++ pScrn->monitor->vrefresh[0].hi = 0;
++ pScrn->monitor->nVrefresh = 0;
++ }
++
+ SetPipeAccess(pScrn);
+ VBESetModeNames(pScrn->modePool);
+
+@@ -2541,15 +3076,61 @@
+ return FALSE;
+ }
+
+- xf86PruneDriverModes(pScrn);
++ /* Only use this if we've got DDC available */
++ if (DDCclock > 0) {
++ p = pScrn->modes;
++ if (p == NULL)
++ return FALSE;
++ do {
++ int Clock = 100000000; /* incredible value */
+
+- pScrn->currentMode = pScrn->modes;
++ for (pMon = pScrn->monitor->Modes; pMon != NULL; pMon = pMon->next) {
++ if ((pMon->HDisplay != p->HDisplay) ||
++ (pMon->VDisplay != p->VDisplay) ||
++ (pMon->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))
++ continue;
++
++ /* Find lowest supported Clock for this resolution */
++ if (Clock > pMon->Clock)
++ Clock = pMon->Clock;
++ }
++
++ if (DDCclock < 2550 && Clock / 1000.0 > DDCclock) {
++ ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n",
++ p->name, pScrn->monitor->id,
++ Clock/1000.0, DDCclock);
++ p->status = MODE_BAD;
++ }
++ p = p->next;
++ } while (p != NULL && p != pScrn->modes);
++ }
++
++ xf86PruneDriverModes(pScrn);
+
+ if (pScrn->modes == NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+ PreInitCleanup(pScrn);
+ return FALSE;
+ }
++
++ /* Now we check the VESA BIOS's displayWidth and reset if necessary */
++ p = pScrn->modes;
++ do {
++ VbeModeInfoData *data = (VbeModeInfoData *) p->Private;
++ VbeModeInfoBlock *modeInfo;
++
++ /* Get BytesPerScanline so we can reset displayWidth */
++ if ((modeInfo = VBEGetModeInfo(pI830->pVbe, data->mode))) {
++ if (pScrn->displayWidth < modeInfo->BytesPerScanline / pI830->cpp) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Correcting stride (%d -> %d)\n", pScrn->displayWidth, modeInfo->BytesPerScanline);
++ pScrn->displayWidth = modeInfo->BytesPerScanline / pI830->cpp;
++ }
++ }
++ p = p->next;
++ } while (p != NULL && p != pScrn->modes);
++
++ pScrn->currentMode = pScrn->modes;
++
+ #ifndef USE_PITCHES
+ #define USE_PITCHES 1
+ #endif
+@@ -2671,7 +3252,7 @@
+ #endif
+
+ SetPipeAccess(pScrn);
+- VBEPrintModes(pScrn);
++ I830PrintModes(pScrn);
+
+ if (!pI830->vesa->useDefaultRefresh) {
+ /*
+@@ -2682,7 +3263,7 @@
+ * if there are no non-CRT devices attached.
+ */
+ SetPipeAccess(pScrn);
+- VBESetModeParameters(pScrn, pI830->pVbe);
++ I830SetModeParameters(pScrn, pI830->pVbe);
+ }
+
+ /* PreInit shouldn't leave any state changes, so restore this. */
+@@ -2721,11 +3302,6 @@
+ xf86LoaderReqSymLists(I810ramdacSymbols, NULL);
+ }
+
+- if (!SetDisplayDevices(pScrn, pI830->savedDevices)) {
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Failed to switch to saved display devices, continuing.\n");
+- }
+-
+ I830UnmapMMIO(pScrn);
+
+ /* We won't be using the VGA access after the probe. */
+@@ -2733,8 +3309,19 @@
+ xf86SetOperatingState(resVgaIo, pI830->pEnt->index, ResUnusedOpr);
+ xf86SetOperatingState(resVgaMem, pI830->pEnt->index, ResDisableOpr);
+
++ if (pI830->shadowFB) {
++ if (!xf86LoadSubModule(pScrn, "shadowfb")) {
++ I830BIOSFreeRec(pScrn);
++ vbeFree(pI830->pVbe);
++ return FALSE;
++ }
++ xf86LoaderReqSymLists(I810shadowFBSymbols, NULL);
++ }
++
+ VBEFreeVBEInfo(pI830->vbeInfo);
++ pI830->vbeInfo = NULL;
+ vbeFree(pI830->pVbe);
++ pI830->pVbe = NULL;
+
+ /* Use the VBE mode restore workaround by default. */
+ pI830->vbeRestoreWorkaround = TRUE;
+@@ -2953,12 +3540,16 @@
+
+ DPRINTF(PFX, "SaveHWState\n");
+
+- SetPipeAccess(pScrn);
++ if (IsPrimary(pScrn) && pI830->pipe != pI830->origPipe)
++ SetBIOSPipe(pScrn, pI830->origPipe);
++ else
++ SetPipeAccess(pScrn);
+
+ pVesa = pI830->vesa;
+
+ /* Make sure we save at least this information in case of failure. */
+ VBEGetVBEMode(pVbe, &pVesa->stateMode);
++ pVesa->stateRefresh = GetRefreshRate(pScrn, pVesa->stateMode, NULL);
+ modeInfo = VBEGetModeInfo(pVbe, pVesa->stateMode);
+ pVesa->savedScanlinePitch = 0;
+ if (modeInfo) {
+@@ -3024,6 +3615,11 @@
+
+ DPRINTF(PFX, "RestoreHWState\n");
+
++ if (IsPrimary(pScrn) && pI830->pipe != pI830->origPipe)
++ SetBIOSPipe(pScrn, pI830->origPipe);
++ else
++ SetPipeAccess(pScrn);
++
+ pVesa = pI830->vesa;
+
+ /*
+@@ -3031,26 +3627,8 @@
+ * Temporarily program a 640x480 mode before switching back to
+ * text mode.
+ */
+- if (pVesa->useDefaultRefresh) {
+- int mode = 0;
+-
+- switch (pScrn->depth) {
+- case 8:
+- mode = 0x30;
+- break;
+- case 15:
+- mode = 0x40;
+- break;
+- case 16:
+- mode = 0x41;
+- break;
+- case 24:
+- mode = 0x50;
+- break;
+- }
+- mode |= (1 << 15) | (1 << 14);
+- I830VESASetVBEMode(pScrn, mode, NULL);
+- }
++ if (pVesa->useDefaultRefresh)
++ I830Set640x480(pScrn);
+
+ if (pVesa->state && pVesa->stateSize) {
+ CARD16 imr = INREG16(IMR);
+@@ -3083,6 +3661,9 @@
+ "Setting the original video mode instead of restoring\n\t"
+ "the saved state\n");
+ I830VESASetVBEMode(pScrn, pVesa->stateMode, NULL);
++ if (!pVesa->useDefaultRefresh && pI830->useExtendedRefresh) {
++ SetRefreshRate(pScrn, pVesa->stateMode, pVesa->stateRefresh);
++ }
+ }
+ if (pVesa->savedScanlinePitch)
+ VBESetLogicalScanline(pVbe, pVesa->savedScanlinePitch);
+@@ -3094,13 +3675,10 @@
+
+ vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS);
+ vgaHWLock(hwp);
++
+ return TRUE;
+ }
+
+-#ifndef USE_VBE
+-#define USE_VBE 1
+-#endif
+-
+ static void I830SetCloneVBERefresh(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block, int refresh)
+ {
+ I830Ptr pI830 = I830PTR(pScrn);
+@@ -3136,8 +3714,7 @@
+ #endif
+ if (clock)
+ block->PixelClock = clock;
+- block->RefreshRate = ((double)(block->PixelClock) /
+- (double)(p->HTotal * p->VTotal)) * 100;
++ block->RefreshRate = RefreshRate;
+ return;
+ }
+ }
+@@ -3147,62 +3724,138 @@
+ I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block)
+ {
+ I830Ptr pI830 = I830PTR(pScrn);
++ Bool ret = FALSE;
++ int Mon;
+
+ DPRINTF(PFX, "Setting mode 0x%.8x\n", mode);
+
+- if (pI830->Clone && !pI830->preinit) {
++ if (pI830->Clone && pI830->CloneHDisplay && pI830->CloneVDisplay &&
++ !pI830->preinit && !pI830->closing) {
+ VbeCRTCInfoBlock newblock;
+- int Mon;
++ int newmode = mode;
+
+- if (!pI830->pipe)
+- Mon = pI830->MonType2;
+- else
++ if (pI830->pipe == 1)
+ Mon = pI830->MonType1;
++ else
++ Mon = pI830->MonType2;
+
+ SetBIOSPipe(pScrn, !pI830->pipe);
+
+- /* The reason for this code is if we've not got a CRT on this pipe, then
+- * make sure we're using a 60Hz refresh */
+- if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh &&
+- (mode & (1 << 11)) && block) {
+- /* we'll call 5F05 to set the refresh later.... */
+- if (Mon != PIPE_CRT)
+- VBESetVBEMode(pI830->pVbe, mode, NULL);
+- else
+- VBESetVBEMode(pI830->pVbe, mode, block);
+- } else {
+- if (Mon != PIPE_CRT)
+- /* Set clone head to 60Hz because we ain't got a CRT on it */
+- I830SetCloneVBERefresh(pScrn, mode, &newblock, 6000);
+- else
+- /* Set clone head to specified clone refresh rate */
+- I830SetCloneVBERefresh(pScrn, mode, &newblock, pI830->CloneRefresh * 100);
+- if (newblock.RefreshRate == 0)
++ /* Now recheck refresh operations we can use */
++ pI830->useExtendedRefresh = FALSE;
++ pI830->vesa->useDefaultRefresh = FALSE;
++
++ if (Mon != PIPE_CRT) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "A non-CRT device is attached to Clone pipe %c.\n"
++ "\tNo refresh rate overrides will be attempted (0x%x).\n",
++ PIPE_NAME(!pI830->pipe), newmode);
++ pI830->vesa->useDefaultRefresh = TRUE;
++ }
++ /*
++ * Some desktop platforms might not have 0x5f05, so useExtendedRefresh
++ * would need to be set to FALSE for those cases.
++ */
++ if (!pI830->vesa->useDefaultRefresh)
++ pI830->useExtendedRefresh = TRUE;
++
++ newmode |= 1 << 11;
++ if (pI830->vesa->useDefaultRefresh)
++ newmode &= ~(1 << 11);
++
++ if (!SetRefreshRate(pScrn, newmode, 60)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "BIOS call 0x5f05 not supported on Clone Head, "
++ "setting refresh with VBE 3 method.\n");
++ pI830->useExtendedRefresh = FALSE;
++ }
++
++ if (!pI830->vesa->useDefaultRefresh) {
++ I830SetCloneVBERefresh(pScrn, newmode, &newblock, pI830->CloneRefresh * 100);
++
++ if (!VBESetVBEMode(pI830->pVbe, newmode, &newblock)) {
++ if (!VBESetVBEMode(pI830->pVbe, (newmode & ~(1 << 11)), NULL))
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Failed to set mode for Clone head.\n");
++ } else {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Setting refresh on clone head with VBE 3 method.\n");
++ pI830->useExtendedRefresh = FALSE;
++ }
++ } else {
++ if (!VBESetVBEMode(pI830->pVbe, (newmode & ~(1 << 11)), NULL))
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Failed to set mode for Clone head.\n");
++ }
++
++ if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh) {
++ if (!SetRefreshRate(pScrn, newmode, pI830->CloneRefresh))
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Failed to setup clone head mode resolution and refresh.\n");
++ "Failed to set refresh rate to %dHz on Clone head.\n",
++ pI830->CloneRefresh);
+ else
+- VBESetVBEMode(pI830->pVbe, mode, &newblock);
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Set refresh rate to %dHz on Clone head.\n",
++ pI830->CloneRefresh);
+ }
++ SetPipeAccess(pScrn);
+ }
+
+- SetPipeAccess(pScrn);
++ if (pI830->pipe == 0)
++ Mon = pI830->MonType1;
++ else
++ Mon = pI830->MonType2;
+
+-#if USE_VBE
+- return VBESetVBEMode(pI830->pVbe, mode, block);
+-#else
+- {
+- vbeInfoPtr pVbe = pI830->pVbe;
+- pVbe->pInt10->num = 0x10;
+- pVbe->pInt10->ax = 0x80 | (mode & 0x7f);
+- xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
+- pVbe->pInt10->ax = 0x0f00;
+- xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn);
+- if ((pVbe->pInt10->ax & 0x7f) == (mode & 0x7f))
+- return TRUE;
+- else
+- return FALSE;
++ /* Now recheck refresh operations we can use */
++ pI830->useExtendedRefresh = FALSE;
++ pI830->vesa->useDefaultRefresh = FALSE;
++
++ if (Mon != PIPE_CRT)
++ pI830->vesa->useDefaultRefresh = TRUE;
++
++ mode |= 1 << 11;
++ if (pI830->vesa->useDefaultRefresh)
++ mode &= ~(1 << 11);
++ /*
++ * Some desktop platforms might not have 0x5f05, so useExtendedRefresh
++ * would need to be set to FALSE for those cases.
++ */
++ if (!pI830->vesa->useDefaultRefresh)
++ pI830->useExtendedRefresh = TRUE;
++
++ if (!SetRefreshRate(pScrn, mode, 60)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "BIOS call 0x5f05 not supported, "
++ "setting refresh with VBE 3 method.\n");
++ pI830->useExtendedRefresh = FALSE;
+ }
+-#endif
++
++ if (!pI830->vesa->useDefaultRefresh && block) {
++ ret = VBESetVBEMode(pI830->pVbe, mode, block);
++ if (!ret)
++ ret = VBESetVBEMode(pI830->pVbe, (mode & ~(1 << 11)), NULL);
++ else {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Setting refresh with VBE 3 method.\n");
++ pI830->useExtendedRefresh = FALSE;
++ }
++ } else {
++ ret = VBESetVBEMode(pI830->pVbe, (mode & ~(1 << 11)), NULL);
++ }
++
++ /* Might as well bail now if we've failed */
++ if (!ret) return FALSE;
++
++ if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && block) {
++ if (!SetRefreshRate(pScrn, mode, block->RefreshRate / 100)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Failed to set refresh rate to %dHz.\n",
++ block->RefreshRate / 100);
++ pI830->useExtendedRefresh = FALSE;
++ }
++ }
++
++ return ret;
+ }
+
+ static Bool
+@@ -3231,21 +3884,6 @@
+ }
+ #endif
+
+- /*
+- * Do this early to find out if we can support it or not....
+- * Test if the extendedRefresh BIOS function is supported.
+- */
+- if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh &&
+- (mode & (1 << 11)) && data && data->data && data->block) {
+- SetPipeAccess(pScrn);
+- if (!SetRefreshRate(pScrn, mode, 60)) {
+- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+- "BIOS call 0x5f05 not supported, "
+- "setting refresh with VBE 3 method.\n");
+- pI830->useExtendedRefresh = FALSE;
+- }
+- }
+-
+ if (pI830->Clone) {
+ pI830->CloneHDisplay = pMode->HDisplay;
+ pI830->CloneVDisplay = pMode->VDisplay;
+@@ -3258,25 +3896,11 @@
+ ResetState(pScrn, TRUE);
+ #endif
+
+- /* XXX Add macros for the various mode parameter bits. */
+-
+- if (pI830->vesa->useDefaultRefresh)
+- mode &= ~(1 << 11);
++ SetPipeAccess(pScrn);
+
+ if (I830VESASetVBEMode(pScrn, mode, data->block) == FALSE) {
+- if ((data->block && (mode & (1 << 11))) &&
+- I830VESASetVBEMode(pScrn, (mode & ~(1 << 11)), NULL) == TRUE) {
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Set VBE Mode rejected this modeline.\n\t"
+- "Trying standard mode instead!\n");
+- DPRINTF(PFX, "OOPS!\n");
+- xfree(data->block);
+- data->block = NULL;
+- data->mode &= ~(1 << 11);
+- } else {
+- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
+- return FALSE;
+- }
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
++ return FALSE;
+ }
+
+ /*
+@@ -3302,49 +3926,6 @@
+ VBESetGetDACPaletteFormat(pVbe, 8);
+ }
+
+- /*
+- * When it's OK to set better than default refresh rates, set them here.
+- */
+- if (pI830->Clone) {
+- int Mon;
+- if (!pI830->pipe)
+- Mon = pI830->MonType2;
+- else
+- Mon = pI830->MonType1;
+- SetBIOSPipe(pScrn, !pI830->pipe);
+- if (pI830->CloneRefresh && (Mon == PIPE_CRT)) {
+- if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh &&
+- (mode & (1 << 11)) && data && data->data && data->block) {
+- refresh = SetRefreshRate(pScrn, mode, pI830->CloneRefresh);
+- if (!refresh)
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Failed to set refresh rate to %dHz on Clone head.\n",
+- pI830->CloneRefresh);
+- else
+- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+- "Set refresh rate to %dHz on Clone head.\n",
+- pI830->CloneRefresh);
+- } else
+- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+- "Will use VBE3 method to set refresh on Clone head.\n");
+- } else {
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Not attempting to override default refresh on non-CRT clone head\n");
+- }
+- }
+-
+- if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh &&
+- (mode & (1 << 11)) && data && data->data && data->block) {
+- SetPipeAccess(pScrn);
+- refresh = SetRefreshRate(pScrn, mode, data->block->RefreshRate / 100);
+- if (!refresh) {
+- refresh = 60;
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Failed to set refresh rate to %dHz.\n",
+- data->block->RefreshRate / 100);
+- }
+- }
+-
+ /* XXX Fix plane A with pipe A, and plane B with pipe B. */
+ planeA = INREG(DSPACNTR);
+ planeB = INREG(DSPBCNTR);
+@@ -3360,36 +3941,18 @@
+ pI830->planeEnabled[1] ? "enabled" : "disabled",
+ planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A");
+
+- if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) {
++ if (pI830->operatingDevices & 0xff) {
+ pI830->planeEnabled[0] = 1;
+- pI830->pipeEnabled[0] = 1;
+- pI830->planeEnabled[1] = 1;
+- pI830->pipeEnabled[1] = 1;
++ } else {
++ pI830->planeEnabled[0] = 0;
+ }
+
+- /*
+- * Sometimes it seems that no display planes are enabled at this point.
+- * For mobile platforms pick the plane(s) connected to enabled pipes.
+- * For others choose plane A.
+- */
+- if (!pI830->planeEnabled[0] && !pI830->planeEnabled[1]) {
+- if (pI830->availablePipes == 2) {
+- if ((pI830->pipeEnabled[0] &&
+- ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) ||
+- (pI830->pipeEnabled[1] &&
+- ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) {
+- pI830->planeEnabled[0] = TRUE;
+- }
+- if ((pI830->pipeEnabled[0] &&
+- ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) ||
+- (pI830->pipeEnabled[1] &&
+- ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) {
+- pI830->planeEnabled[1] = TRUE;
+- }
+- } else {
+- pI830->planeEnabled[0] = TRUE;
+- }
++ if (pI830->operatingDevices & 0xff00) {
++ pI830->planeEnabled[1] = 1;
++ } else {
++ pI830->planeEnabled[1] = 0;
+ }
++
+ if (pI830->planeEnabled[0]) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane A.\n");
+ planeA |= DISPLAY_PLANE_ENABLE;
+@@ -3433,6 +3996,8 @@
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08lx\n", temp);
+ }
+
++
++
+ if (xf86IsEntityShared(pScrn->entityList[0])) {
+ /* Clean this up !! */
+ if (IsPrimary(pScrn)) {
+@@ -3611,6 +4176,7 @@
+ }
+ }
+
++#if 0
+ {
+ int ret;
+
+@@ -3620,6 +4186,7 @@
+ "LFP compensation mode: 0x%x\n", ret);
+ }
+ }
++#endif
+
+ #if MODESWITCH_RESET_STATE
+ ResetState(pScrn, TRUE);
+@@ -3876,6 +4443,8 @@
+ VisualPtr visual;
+ I830EntPtr pI830Ent = NULL;
+ I830Ptr pI8301 = NULL;
++ int width, height, displayWidth;
++ unsigned char *fbbase;
+ #ifdef XF86DRI
+ Bool driDisabled;
+ #endif
+@@ -3938,26 +4507,22 @@
+ * If we're changing the BIOS's view of the video memory size, do that
+ * first, then re-initialise the VBE information.
+ */
++ if (pI830->pVbe)
++ vbeFree(pI830->pVbe);
+ pI830->pVbe = VBEInit(NULL, pI830->pEnt->index);
+ if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE))
+ SetBIOSMemSize(pScrn, pI830->newBIOSMemSize);
+ if (!pI830->pVbe)
+ return FALSE;
++ if (pI830->vbeInfo)
++ VBEFreeVBEInfo(pI830->vbeInfo);
+ pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe);
+
+ miClearVisualTypes();
+- if (!xf86SetDefaultVisual(pScrn, -1))
+- return FALSE;
+- if (pScrn->bitsPerPixel > 8) {
+- if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
+- pScrn->rgbBits, TrueColor))
+- return FALSE;
+- } else {
+- if (!miSetVisualTypes(pScrn->depth,
++ if (!miSetVisualTypes(pScrn->depth,
+ miGetDefaultVisualMask(pScrn->depth),
+ pScrn->rgbBits, pScrn->defaultVisual))
+ return FALSE;
+- }
+ if (!miSetPixmapDepths())
+ return FALSE;
+
+@@ -4036,7 +4601,7 @@
+ */
+
+ if (pI830->directRenderingEnabled) {
+- if (pI830->noAccel || pI830->SWCursor || pI830->StolenOnly) {
++ if (pI830->noAccel || pI830->SWCursor || (pI830->StolenOnly && IsPrimary(pScrn))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DRI is disabled because it "
+ "needs HW cursor, 2D accel and AGPGART.\n");
+ pI830->directRenderingEnabled = FALSE;
+@@ -4114,10 +4679,26 @@
+ return FALSE;
+
+ DPRINTF(PFX, "assert( if(!fbScreenInit(pScreen, ...) )\n");
+- if (!fbScreenInit(pScreen, pI830->FbBase + pScrn->fbOffset,
+- pScrn->virtualX, pScrn->virtualY,
++ if (pI830->rotate) {
++ height = pScrn->virtualX;
++ width = pScrn->virtualY;
++ } else {
++ width = pScrn->virtualX;
++ height = pScrn->virtualY;
++ }
++ if (pI830->shadowFB) {
++ pI830->shadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
++ pI830->shadowPtr = xalloc(pI830->shadowPitch * height);
++ displayWidth = pI830->shadowPitch / (pScrn->bitsPerPixel >> 3);
++ fbbase = pI830->shadowPtr;
++ } else {
++ pI830->shadowPtr = NULL;
++ fbbase = pI830->FbBase;
++ displayWidth = pScrn->displayWidth;
++ }
++ if (!fbScreenInit(pScreen, fbbase + pScrn->fbOffset, width, height,
+ pScrn->xDpi, pScrn->yDpi,
+- pScrn->displayWidth, pScrn->bitsPerPixel))
++ displayWidth, pScrn->bitsPerPixel))
+ return FALSE;
+
+ if (pScrn->bitsPerPixel > 8) {
+@@ -4139,7 +4720,8 @@
+
+ xf86SetBlackWhitePixels(pScreen);
+
+- I830DGAInit(pScreen);
++ if (!pI830->shadowFB)
++ I830DGAInit(pScreen);
+
+ DPRINTF(PFX,
+ "assert( if(!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) )\n");
+@@ -4177,13 +4759,39 @@
+ } else
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing SW Cursor!\n");
+
++ if (pI830->shadowFB) {
++ RefreshAreaFuncPtr refreshArea = I830RefreshArea;
++ if (pI830->rotate) {
++ if (!pI830->PointerMoved) {
++ pI830->PointerMoved = pScrn->PointerMoved;
++ pScrn->PointerMoved = I830PointerMoved;
++ }
++ switch (pScrn->bitsPerPixel) {
++ case 8:
++ refreshArea = I830RefreshArea8;
++ break;
++ case 16:
++ refreshArea = I830RefreshArea16;
++ break;
++ case 24:
++ refreshArea = I830RefreshArea24;
++ break;
++ case 32:
++ refreshArea = I830RefreshArea32;
++ break;
++ }
++ }
++ ShadowFBInit(pScreen, refreshArea);
++ }
++
+ DPRINTF(PFX, "assert( if(!miCreateDefColormap(pScreen)) )\n");
+ if (!miCreateDefColormap(pScreen))
+ return FALSE;
+
+ DPRINTF(PFX, "assert( if(!xf86HandleColormaps(pScreen, ...)) )\n");
+ if (!xf86HandleColormaps(pScreen, 256, 8, I830LoadPalette, 0,
+- CMAP_RELOAD_ON_MODE_SWITCH)) {
++ CMAP_RELOAD_ON_MODE_SWITCH |
++ CMAP_PALETTED_TRUECOLOR)) {
+ return FALSE;
+ }
+
+@@ -4221,9 +4829,6 @@
+ pI830->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = I830BIOSCloseScreen;
+
+- if (pI830->checkLid)
+- pI830->lidTimer = TimerSet(NULL, 0, 1000, I830LidTimer, pScrn);
+-
+ if (serverGeneration == 1)
+ xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+
+@@ -4335,18 +4940,32 @@
+
+ DPRINTF(PFX, "Leave VT\n");
+
++ pI830->leaving = TRUE;
++
++ if (pI830->devicesTimer)
++ TimerCancel(pI830->devicesTimer);
++ pI830->devicesTimer = NULL;
++
++ if (pI830->Clone) {
++ /* Ensure we don't try and setup modes on a clone head */
++ pI830->CloneHDisplay = 0;
++ pI830->CloneVDisplay = 0;
++ }
++
+ if (!IsPrimary(pScrn)) {
+ I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1);
+ if (!pI8301->GttBound) {
+ return;
+ }
+- }
++ }
+
+ #ifdef XF86DRI
+ if (pI830->directRenderingOpen) {
+ DPRINTF(PFX, "calling dri lock\n");
+ DRILock(screenInfo.screens[scrnIndex], 0);
+ pI830->LockHeld = 1;
++
++ drmCtlUninstHandler(pI830->drmSubFD);
+ }
+ #endif
+
+@@ -4355,8 +4974,10 @@
+ SaveHWOperatingState(pScrn);
+ #endif
+
++ if (pI830->CursorInfoRec && pI830->CursorInfoRec->HideCursor)
++ pI830->CursorInfoRec->HideCursor(pScrn);
++
+ ResetState(pScrn, TRUE);
+- RestoreHWState(pScrn);
+
+ if (IsPrimary(pScrn)) {
+ if (!SetDisplayDevices(pScrn, pI830->savedDevices)) {
+@@ -4369,13 +4990,195 @@
+ }
+ }
+
++ RestoreHWState(pScrn);
+ RestoreBIOSMemSize(pScrn);
+ if (IsPrimary(pScrn))
+ I830UnbindGARTMemory(pScrn);
+ if (pI830->AccelInfoRec)
+ pI830->AccelInfoRec->NeedToSync = FALSE;
++
++ /* DO IT AGAIN! AS IT SEEMS THAT SOME LFPs FLICKER OTHERWISE */
++ if (IsPrimary(pScrn)) {
++ if (!SetDisplayDevices(pScrn, pI830->savedDevices)) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Failed to switch back to original display devices (0x%x) (2)\n",
++ pI830->savedDevices);
++ } else {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Successfully set original devices (2)\n");
++ }
++ }
++}
++
++static Bool
++I830DetectMonitorChange(ScrnInfoPtr pScrn)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ pointer pDDCModule = NULL;
++ DisplayModePtr p, pMon;
++ int memsize;
++ int DDCclock = 0;
++ int displayWidth = pScrn->displayWidth;
++ int curHDisplay = pScrn->currentMode->HDisplay;
++ int curVDisplay = pScrn->currentMode->VDisplay;
++
++ DPRINTF(PFX, "Detect Monitor Change\n");
++
++ SetPipeAccess(pScrn);
++
++ /* Re-read EDID */
++ pDDCModule = xf86LoadSubModule(pScrn, "ddc");
++ if (pI830->vesa->monitor)
++ xfree(pI830->vesa->monitor);
++ pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
++ xf86UnloadSubModule(pDDCModule);
++ if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL)
++ xf86SetDDCproperties(pScrn, pI830->vesa->monitor);
++ else
++ /* No DDC, so get out of here, and continue to use the current settings */
++ return FALSE;
++
++ if (!(DDCclock = I830UseDDC(pScrn)))
++ return FALSE;
++
++ /* Revalidate the modes */
++
++ /*
++ * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS
++ * functions.
++ */
++ pScrn->modePool = I830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo);
++
++ if (!pScrn->modePool) {
++ /* This is bad, which would cause the Xserver to exit, maybe
++ * we should default to a 640x480 @ 60Hz mode here ??? */
++ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
++ "No Video BIOS modes for chosen depth.\n");
++ return FALSE;
++ }
++
++ SetPipeAccess(pScrn);
++ VBESetModeNames(pScrn->modePool);
++
++ if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64))
++ memsize = pI830->vbeInfo->TotalMemory * 64;
++ else
++ memsize = pScrn->videoRam;
++
++ VBEValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, NULL,
++ NULL, 0, MAX_DISPLAY_PITCH, 1,
++ 0, MAX_DISPLAY_HEIGHT,
++ pScrn->display->virtualX,
++ pScrn->display->virtualY,
++ memsize, LOOKUP_BEST_REFRESH);
++
++if (DDCclock > 0) {
++ p = pScrn->modes;
++ if (p == NULL)
++ return FALSE;
++ do {
++ int Clock = 100000000; /* incredible value */
++
++ for (pMon = pScrn->monitor->Modes; pMon != NULL; pMon = pMon->next) {
++ if ((pMon->HDisplay != p->HDisplay) ||
++ (pMon->VDisplay != p->VDisplay) ||
++ (pMon->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))
++ continue;
++
++ /* Find lowest supported Clock for this resolution */
++ if (Clock > pMon->Clock)
++ Clock = pMon->Clock;
++ }
++
++ if (DDCclock < 2550 && Clock / 1000.0 > DDCclock) {
++ ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n",
++ p->name, pScrn->monitor->id,
++ Clock/1000.0, DDCclock);
++ p->status = MODE_BAD;
++ }
++ p = p->next;
++ } while (p != NULL && p != pScrn->modes);
++}
++
++ pScrn->displayWidth = displayWidth; /* restore old displayWidth */
++
++ xf86PruneDriverModes(pScrn);
++ I830PrintModes(pScrn);
++
++ if (!pI830->vesa->useDefaultRefresh)
++ I830SetModeParameters(pScrn, pI830->pVbe);
++
++ /* Now check if the previously used mode is o.k. for the current monitor.
++ * This allows VT switching to continue happily when not disconnecting
++ * and reconnecting monitors */
++
++ pScrn->currentMode = pScrn->modes;
++ p = pScrn->modes;
++ if (p == NULL)
++ return FALSE;
++ do {
++ if ((p->HDisplay == curHDisplay) &&
++ (p->VDisplay == curVDisplay) &&
++ (!(p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))) {
++ pScrn->currentMode = p; /* previous mode is o.k. */
++ }
++ p = p->next;
++ } while (p != NULL && p != pScrn->modes);
++
++ /* Now readjust for panning if necessary */
++ {
++ pScrn->frameX0 = (pScrn->frameX0 + pScrn->frameX1 + 1 - pScrn->currentMode->HDisplay) / 2;
++
++ if (pScrn->frameX0 < 0)
++ pScrn->frameX0 = 0;
++
++ pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay - 1;
++ if (pScrn->frameX1 >= pScrn->virtualX) {
++ pScrn->frameX0 = pScrn->virtualX - pScrn->currentMode->HDisplay;
++ pScrn->frameX1 = pScrn->virtualX - 1;
++ }
++
++ pScrn->frameY0 = (pScrn->frameY0 + pScrn->frameY1 + 1 - pScrn->currentMode->VDisplay) / 2;
++
++ if (pScrn->frameY0 < 0)
++ pScrn->frameY0 = 0;
++
++ pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay - 1;
++ if (pScrn->frameY1 >= pScrn->virtualY) {
++ pScrn->frameY0 = pScrn->virtualY - pScrn->currentMode->VDisplay;
++ pScrn->frameY1 = pScrn->virtualY - 1;
++ }
++ }
++
++ return TRUE;
+ }
+
++Bool
++I830CheckModeSupport(ScrnInfoPtr pScrn, int x, int y, int mode)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ Bool ret = TRUE;
++
++ if (pI830->Clone) {
++ if (pI830->pipeDisplaySize[0].x2 != 0) {
++ if (x > pI830->pipeDisplaySize[0].x2 ||
++ y > pI830->pipeDisplaySize[0].y2) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bad Clone Mode removing\n");
++ return FALSE;
++ }
++ }
++ if (pI830->pipeDisplaySize[1].x2 != 0) {
++ if (x > pI830->pipeDisplaySize[1].x2 ||
++ y > pI830->pipeDisplaySize[1].y2) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bad Clone Mode removing\n");
++ return FALSE;
++ }
++ }
++ }
++
++ return ret;
++}
++
+ /*
+ * This gets called when gaining control of the VT, and from ScreenInit().
+ */
+@@ -4387,15 +5190,56 @@
+
+ DPRINTF(PFX, "Enter VT\n");
+
++ /*
++ * Only save state once per server generation since that's what most
++ * drivers do. Could change this to save state at each VT enter.
++ */
++ if (pI830->SaveGeneration != serverGeneration) {
++ pI830->SaveGeneration = serverGeneration;
++ SaveHWState(pScrn);
++ }
++
++ pI830->leaving = FALSE;
++
+ if (IsPrimary(pScrn)) {
++ /*
++ * This is needed for restoring from ACPI modes (especially S3)
++ * so that we warmboot the Video BIOS. Some platforms have problems,
++ * warm booting when we don't need to, so check that we can call
++ * the Video BIOS with our saved devices, and only when that fails,
++ * we'll warm boot it.
++ */
++ /* Check Pipe conf registers or possibly HTOTAL/VTOTAL for 0x00000000)*/
++ CARD32 temp = pI830->pipe ? INREG(PIPEBCONF) : INREG(PIPEACONF);
++ if (!I830Set640x480(pScrn) || !(temp & 0x80000000)) {
++ xf86Int10InfoPtr pInt;
++
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected resume, re-POSTing.\n");
++
++ pInt = xf86InitInt10(pI830->pEnt->index);
++
++ /* Now perform our warm boot */
++ if (pInt) {
++ pInt->num = 0xe6;
++ xf86ExecX86int10 (pInt);
++ xf86FreeInt10 (pInt);
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Re-POSTing via int10.\n");
++ } else {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Re-POSTing via int10 failed, trying to continue.\n");
++ }
++ }
++
++ /* Finally, re-setup the display devices */
+ if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Failed to switch to configured display devices\n");
+- return FALSE;
++ return FALSE;
+ }
+ }
+
+- /* Setup for checking lid status */
++ /* Setup for device monitoring status */
+ pI830->monitorSwitch = INREG(SWF0) & 0x0000FFFF;
+
+ if (IsPrimary(pScrn))
+@@ -4406,14 +5250,6 @@
+ if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE))
+ SetBIOSMemSize(pScrn, pI830->newBIOSMemSize);
+
+- /*
+- * Only save state once per server generation since that's what most
+- * drivers do. Could change this to save state at each VT enter.
+- */
+- if (pI830->SaveGeneration != serverGeneration) {
+- pI830->SaveGeneration = serverGeneration;
+- SaveHWState(pScrn);
+- }
+ ResetState(pScrn, FALSE);
+ SetHWOperatingState(pScrn);
+
+@@ -4423,8 +5259,13 @@
+ pScrn->virtualY * pScrn->displayWidth * pI830->cpp);
+ #endif
+
++ /* Detect monitor change and switch to suitable mode */
++ if (!pI830->starting)
++ I830DetectMonitorChange(pScrn);
++
+ if (!I830VESASetMode(pScrn, pScrn->currentMode))
+ return FALSE;
++
+ #ifdef I830_XV
+ I830VideoSwitchModeAfter(pScrn, pScrn->currentMode);
+ #endif
+@@ -4441,6 +5282,8 @@
+ #ifdef XF86DRI
+ if (pI830->directRenderingEnabled) {
+ if (!pI830->starting) {
++ I830DRIResume(screenInfo.screens[scrnIndex]);
++
+ I830EmitInvarientState(pScrn);
+ I830RefreshRing(pScrn);
+ I830Sync(pScrn);
+@@ -4453,6 +5296,9 @@
+ }
+ #endif
+
++ if (pI830->checkDevices)
++ pI830->devicesTimer = TimerSet(NULL, 0, 1000, I830CheckDevicesTimer, pScrn);
++
+ return TRUE;
+ }
+
+@@ -4460,8 +5306,6 @@
+ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+ {
+
+- int _head;
+- int _tail;
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ I830Ptr pI830 = I830PTR(pScrn);
+ int ret = TRUE;
+@@ -4469,13 +5313,8 @@
+ DPRINTF(PFX, "I830BIOSSwitchMode: mode == %p\n", mode);
+
+ /* Stops head pointer freezes for 845G */
+- if (!pI830->noAccel && (1 || IS_845G(pI830))) {
+- do {
+- _head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK;
+- _tail = INREG(LP_RING + RING_TAIL) & I830_TAIL_MASK;
+- DELAY(1000);
+- } while (_head != _tail);
+- }
++ if (!pI830->noAccel)
++ (*pI830->AccelInfoRec->Sync)(pScrn);
+
+ #ifndef BINDUNBIND
+ #define BINDUNBIND 0
+@@ -4509,30 +5348,27 @@
+ I830Ptr pI830 = I830PTR(pScrn);
+ Bool on = xf86IsUnblank(mode);
+ CARD32 temp, ctrl, base;
+- int i;
+
+ DPRINTF(PFX, "I830BIOSSaveScreen: %d, on is %s\n", mode, BOOLTOSTRING(on));
+
+ if (pScrn->vtSema) {
+- for (i = 0; i < pI830->availablePipes; i++) {
+- if (i == 0) {
+- ctrl = DSPACNTR;
+- base = DSPABASE;
+- } else {
+- ctrl = DSPBCNTR;
+- base = DSPBADDR;
+- }
+- if (pI830->planeEnabled[i]) {
+- temp = INREG(ctrl);
+- if (on)
+- temp |= DISPLAY_PLANE_ENABLE;
+- else
+- temp &= ~DISPLAY_PLANE_ENABLE;
+- OUTREG(ctrl, temp);
+- /* Flush changes */
+- temp = INREG(base);
+- OUTREG(base, temp);
+- }
++ if (pI830->pipe == 0) {
++ ctrl = DSPACNTR;
++ base = DSPABASE;
++ } else {
++ ctrl = DSPBCNTR;
++ base = DSPBADDR;
++ }
++ if (pI830->planeEnabled[pI830->pipe]) {
++ temp = INREG(ctrl);
++ if (on)
++ temp |= DISPLAY_PLANE_ENABLE;
++ else
++ temp &= ~DISPLAY_PLANE_ENABLE;
++ OUTREG(ctrl, temp);
++ /* Flush changes */
++ temp = INREG(base);
++ OUTREG(base, temp);
+ }
+
+ if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) {
+@@ -4625,6 +5461,10 @@
+ I830BIOSLeaveVT(scrnIndex, 0);
+ }
+
++ if (pI830->devicesTimer)
++ TimerCancel(pI830->devicesTimer);
++ pI830->devicesTimer = NULL;
++
+ DPRINTF(PFX, "\nUnmapping memory\n");
+ I830UnmapMem(pScrn);
+ vgaHWUnmapMem(pScrn);
+@@ -4661,9 +5501,6 @@
+ pI830->overlayOn = NULL;
+ }
+
+- if (pI830->lidTimer)
+- TimerCancel(pI830->lidTimer);
+-
+ pScrn->vtSema = FALSE;
+ pI830->closing = FALSE;
+ pScreen->CloseScreen = pI830->CloseScreen;
+@@ -4743,58 +5580,232 @@
+ return TRUE;
+ }
+
++static int CountBits(int a)
++{
++ int i;
++ int b = 0;
++
++ for (i=0;i<8;i++) {
++ if (a & (1<<i))
++ b+=1;
++ }
++
++ return b;
++}
++
+ static CARD32
+-I830LidTimer(OsTimerPtr timer, CARD32 now, pointer arg)
++I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg)
+ {
+ ScrnInfoPtr pScrn = (ScrnInfoPtr) arg;
+ I830Ptr pI830 = I830PTR(pScrn);
++ int cloned = 0;
+
+ if (pScrn->vtSema) {
+ /* Check for monitor lid being closed/opened and act accordingly */
+- int temp = INREG(SWF0) & 0x0000FFFF;
++ CARD32 adjust;
++ CARD32 temp = INREG(SWF0) & 0x0000FFFF;
++ int fixup = 0;
+
++ /* this avoids a BIOS call if possible */
+ if (pI830->monitorSwitch != temp) {
+- int conf = pI830->operatingDevices;
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+- "Detected possible lid operation, fixing up.\n");
+- if ((temp & 0x0808) == 0x0000) {
+- /* LFP (PIPE A or B) GOING OFF - PROBABLE LID CLOSURE */
+- conf = pI830->operatingDevices & 0xF7F7;
+-#if 0
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Lid is being closed.\n");
+-#endif
+- } else {
+-#if 0
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Lid is being opened.\n");
+-#endif
++ I830Ptr pI8301;
++ I830Ptr pI8302 = NULL;
++ unsigned int toggle = GetToggleList(pScrn, 1);
++
++ GetToggleList(pScrn, 2);
++ GetToggleList(pScrn, 3);
++ GetToggleList(pScrn, 4);
++
++ if (IsPrimary(pScrn))
++ pI8301 = pI830;
++ else
++ pI8301 = I830PTR(pI830->entityPrivate->pScrn_1);
++
++ if (xf86IsEntityShared(pScrn->entityList[0]))
++ pI8302 = I830PTR(pI830->entityPrivate->pScrn_2);
++
++ pI8301->lastDevice1 = pI8301->lastDevice2;
++ pI8301->lastDevice2 = pI8301->monitorSwitch;
++
++ if (CountBits(temp & 0xff) > 1) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected cloned pipe mode (A).\n");
++ if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone)
++ temp = pI8301->MonType2 << 8 | pI8301->MonType1;
++ } else
++ if (CountBits((temp & 0xff00) >> 8) > 1) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected cloned pipe mode (B).\n");
++ if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone)
++ temp = pI8301->MonType2 << 8 | pI8301->MonType1;
++ } else
++ if (pI8301->lastDevice1 && pI8301->lastDevice2) {
++ if ( ((pI8301->lastDevice1 & 0xFF00) == 0) &&
++ ((pI8301->lastDevice2 & 0x00FF) == 0) ) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected last devices (1).\n");
++ cloned = 1;
++ } else if ( ((pI8301->lastDevice2 & 0xFF00) == 0) &&
++ ((pI8301->lastDevice1 & 0x00FF) == 0) ) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected last devices (2).\n");
++ cloned = 1;
++ } else
++ cloned = 0;
++ }
++
++ if (cloned &&
++ ((CountBits(pI830->lastDevice1 & 0xff) > 1) ||
++ ((CountBits((pI830->lastDevice1 & 0xff00) >> 8) > 1))) ) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected duplicate (1).\n");
++ cloned = 0;
++ } else
++ if (cloned &&
++ ((CountBits(pI830->lastDevice2 & 0xff) > 1) ||
++ ((CountBits((pI830->lastDevice2 & 0xff00) >> 8) > 1))) ) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected duplicate (2).\n");
++ cloned = 0;
++ }
++
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Requested display devices 0x%lx.\n", temp);
++
++
++ /* If the BIOS doesn't flip between CRT, LFP and CRT+LFP we fake
++ * it here as it seems some just flip between CRT and LFP. Ugh!
++ *
++ * So this pushes them onto Pipe B and clones the displays, which
++ * is what most BIOS' should be doing.
++ *
++ * Cloned pipe mode should only be done when running single head.
++ */
++ if (xf86IsEntityShared(pScrn->entityList[0]))
++ cloned = 0;
++
++ if (cloned) {
++ if (pI830->Clone)
++ temp = pI8301->MonType2 << 8 | pI8301->MonType1;
++ else if (pI8301->lastDevice1 & 0xFF)
++ temp = pI8301->lastDevice1 << 8 | pI8301->lastDevice2;
++ else
++ temp = pI8301->lastDevice2 << 8 | pI8301->lastDevice1;
++ }
++
++ /* Jump to our next mode if we detect we've been here before */
++ if (temp == pI830->lastDevice1 || temp == pI830->lastDevice2) {
++ temp = toggle;
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected duplicate devices. Toggling (0x%lx)\n", temp);
+ }
+
+- /* If we've defined our own monitors, then get them and set them
+- * up when switching in single head mode, no effect in dual heads
+- * NOTE: This assumes that the LCD is always on Pipe B..... */
+- conf |= pI830->MonType1;
+- if (IsPrimary(pScrn)) {
+- if (!SetDisplayDevices(pScrn, conf))
+- xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to switch "
+- "to configured display devices during lid operation.\n");
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Detected display change operation (0x%x, 0x%x, 0x%lx).\n",
++ pI8301->lastDevice1, pI8301->lastDevice2, temp);
++
++ /* So that if we close on the wrong config, we restore correctly */
++ pI830->specifiedMonitor = TRUE;
++
++ /* double check the display devices are what's configured and try
++ * not to do it twice because of dual heads with the code above */
++ if (!SetDisplayDevices(pScrn, temp)) {
++ if ( cloned &&
++ ((CountBits(temp & 0xff) > 1) ||
++ (CountBits((temp & 0xff00) >> 8) > 1)) ) {
++ temp = pI8301->lastDevice2 | pI8301->lastDevice1;
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Cloning failed, "
++ "trying dual pipe clone mode (0x%lx)\n", temp);
++ if (!SetDisplayDevices(pScrn, temp))
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to switch "
++ "to configured display devices (0x%lx).\n", temp);
++ else
++ pI830->Clone = TRUE;
++ }
+ }
+- pI830->monitorSwitch = conf;
+-
++ pI8301->monitorSwitch = temp;
++ pI8301->operatingDevices = temp;
++ if (xf86IsEntityShared(pScrn->entityList[0])) {
++ pI8302->operatingDevices = temp;
++ pI8302->monitorSwitch = temp;
++ }
++
++ fixup = 1;
++ } else {
++ int offset = pScrn->fbOffset + ((pScrn->frameY0 * pScrn->displayWidth + pScrn->frameX0) * pI830->cpp);
++
++ if (pI830->pipe == 0)
++ adjust = INREG(DSPABASE);
++ else
++ adjust = INREG(DSPBBASE);
++
++ if (adjust != offset) {
++ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
++ "Fixing display offsets.\n");
++
++ I830BIOSAdjustFrame(pScrn->pScreen->myNum, pScrn->frameX0, pScrn->frameY0, 0);
++ }
++ }
++
++ if (fixup) {
++ ScreenPtr pCursorScreen;
++ int x = 0, y = 0;
++
++ pCursorScreen = miPointerCurrentScreen();
++ if (pScrn->pScreen == pCursorScreen)
++ miPointerPosition(&x, &y);
++
+ /* Now, when we're single head, make sure we switch pipes */
+- if (!(xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone)) {
+- if ((temp & 0xFF00) == 0x0000)
+- pI830->pipe = 0;
+- if ((temp & 0x00FF) == 0x0000)
++ if (!(xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) || cloned) {
++ if (temp & 0xFF00)
+ pI830->pipe = 1;
+- }
++ else
++ pI830->pipe = 0;
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Primary pipe is now %s.\n", pI830->pipe ? "B" : "A");
++ }
++
+ I830BIOSSwitchMode(pScrn->pScreen->myNum, pScrn->currentMode, 0);
+ I830BIOSAdjustFrame(pScrn->pScreen->myNum, pScrn->frameX0, pScrn->frameY0, 0);
+-
+- /* Everything should be o.k. now, so make sure the HW cursor is
+- * on the correct pipe */
+- if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) {
+- pI830->CursorInfoRec->ShowCursor(pScrn);
+- pI830->cursorOn = TRUE;
++ if (xf86IsEntityShared(pScrn->entityList[0])) {
++ ScrnInfoPtr pScrn2;
++ I830Ptr pI8302;
++
++ if (IsPrimary(pScrn)) {
++ pScrn2 = pI830->entityPrivate->pScrn_2;
++ pI8302 = I830PTR(pI830->entityPrivate->pScrn_2);
++ } else {
++ pScrn2 = pI830->entityPrivate->pScrn_1;
++ pI8302 = I830PTR(pI830->entityPrivate->pScrn_1);
++ }
++
++ I830BIOSSwitchMode(pScrn2->pScreen->myNum, pScrn2->currentMode, 0);
++ I830BIOSAdjustFrame(pScrn2->pScreen->myNum, pScrn2->frameX0, pScrn2->frameY0, 0);
++ if (pScrn2->pScreen == pCursorScreen) {
++ int sigstate = xf86BlockSIGIO ();
++ miPointerWarpCursor(pScrn2->pScreen,x,y);
++
++ /* xf86Info.currentScreen = pScrn->pScreen; */
++ xf86UnblockSIGIO (sigstate);
++ if (pI8302->CursorInfoRec && !pI8302->SWCursor && pI8302->cursorOn) {
++ pI8302->CursorInfoRec->HideCursor(pScrn);
++ pI8302->CursorInfoRec->ShowCursor(pScrn);
++ pI8302->cursorOn = TRUE;
++ }
++ }
++ }
++
++ if (pScrn->pScreen == pCursorScreen) {
++ int sigstate = xf86BlockSIGIO ();
++ miPointerWarpCursor(pScrn->pScreen,x,y);
++
++ /* xf86Info.currentScreen = pScrn->pScreen; */
++ xf86UnblockSIGIO (sigstate);
++ if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) {
++ pI830->CursorInfoRec->HideCursor(pScrn);
++ pI830->CursorInfoRec->ShowCursor(pScrn);
++ pI830->cursorOn = TRUE;
++ }
+ }
+ }
+ }
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i830_memory.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_memory.c 2005-08-18 19:40:24.000000000 -0400
+@@ -2,7 +2,7 @@
+ /**************************************************************************
+
+ Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+-Copyright © 2002 by David Dawes.
++Copyright © 2002 by David Dawes.
+
+ All Rights Reserved.
+
+@@ -90,7 +90,7 @@
+ end = pool->Free.End;
+
+ start = ROUND_DOWN_TO(end - size, alignment);
+- needed = pool->Free.End - start;
++ needed = end - start;
+ }
+ }
+ if (needed > pool->Free.Size) {
+@@ -123,10 +123,9 @@
+ pool->Free.Start += needed;
+ result->End = pool->Free.Start;
+ } else {
+- result->Start = ROUND_DOWN_TO(pool->Free.End - size, alignment) -
+- pool->Total.End;
+- result->End = pool->Free.End - pool->Total.End;
++ result->Start = ROUND_DOWN_TO(pool->Free.End - size, alignment);
+ pool->Free.End -= needed;
++ result->End = result->Start + needed;
+ }
+ pool->Free.Size = pool->Free.End - pool->Free.Start;
+ result->Size = result->End - result->Start;
+@@ -1236,7 +1235,7 @@
+
+ i830Reg->Fence[nr] = 0;
+
+- if (IS_I915G(pI830))
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))
+ fence_mask = ~I915G_FENCE_START_MASK;
+ else
+ fence_mask = ~I830_FENCE_START_MASK;
+@@ -1244,7 +1243,7 @@
+ if (start & fence_mask) {
+ xf86DrvMsg(X_WARNING, pScrn->scrnIndex,
+ "SetFence: %d: start (0x%08x) is not %s aligned\n",
+- nr, start, (IS_I915G(pI830)) ? "1MB" : "512k");
++ nr, start, (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) ? "1MB" : "512k");
+ return;
+ }
+
+@@ -1264,7 +1263,7 @@
+
+ val = (start | FENCE_X_MAJOR | FENCE_VALID);
+
+- if (IS_I915G(pI830)) {
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
+ switch (size) {
+ case MB(1):
+ val |= I915G_FENCE_SIZE_1M;
+@@ -1325,7 +1324,7 @@
+ }
+ }
+
+- if (IS_I915G(pI830))
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))
+ fence_pitch = pitch / 512;
+ else
+ fence_pitch = pitch / 128;
+--- xc/programs/Xserver/hw/xfree86/drivers/i810/i830_video.c.i945 2005-08-18 19:40:12.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_video.c 2005-08-18 19:40:24.000000000 -0400
+@@ -42,7 +42,7 @@
+ /*
+ * i830_video.c: i830/i845 Xv driver.
+ *
+- * Copyright © 2002 by Alan Hourihane and David Dawes
++ * Copyright © 2002 by Alan Hourihane and David Dawes
+ *
+ * Authors:
+ * Alan Hourihane <alanh@tungstengraphics.com>
+@@ -72,7 +72,7 @@
+
+ #include "i830.h"
+ #include "xf86xv.h"
+-#include "Xv.h"
++#include <X11/extensions/Xv.h>
+ #include "xaa.h"
+ #include "xaalocal.h"
+ #include "dixstruct.h"
+@@ -110,7 +110,7 @@
+
+ #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+-static Atom xvBrightness, xvContrast, xvColorKey;
++static Atom xvBrightness, xvContrast, xvColorKey, xvPipe;
+ static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5;
+
+ #define IMAGE_MAX_WIDTH 1440
+@@ -251,12 +251,20 @@
+ {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
+ };
+
+-#define NUM_ATTRIBUTES 9
++#define CLONE_ATTRIBUTES 1
++static XF86AttributeRec CloneAttributes[CLONE_ATTRIBUTES] = {
++ {XvSettable | XvGettable, 0, 1, "XV_PIPE"}
++};
+
++#define NUM_ATTRIBUTES 3
+ static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
+ {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
+ {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
+- {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
++ {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
++};
++
++#define GAMMA_ATTRIBUTES 6
++static XF86AttributeRec GammaAttributes[GAMMA_ATTRIBUTES] = {
+ {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"},
+ {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"},
+ {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"},
+@@ -342,6 +350,7 @@
+
+ int brightness;
+ int contrast;
++ int pipe;
+
+ RegionRec clip;
+ CARD32 colorKey;
+@@ -503,7 +512,7 @@
+ * Select which pipe the overlay is enabled on.
+ */
+ overlay->OCONFIG &= ~OVERLAY_PIPE_MASK;
+- if (pI830->pipe == 0)
++ if (pPriv->pipe == 0)
+ overlay->OCONFIG |= OVERLAY_PIPE_A;
+ else
+ overlay->OCONFIG |= OVERLAY_PIPE_B;
+@@ -580,6 +589,7 @@
+ I830Ptr pI830 = I830PTR(pScrn);
+ XF86VideoAdaptorPtr adapt;
+ I830PortPrivPtr pPriv;
++ XF86AttributePtr att;
+
+ DPRINTF(PFX, "I830SetupImageVideo\n");
+
+@@ -589,7 +599,7 @@
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+- adapt->name = "Intel(R) 830M/845G/852GM/855GM/865G/915G Video Overlay";
++ adapt->name = "Intel(R) Video Overlay";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = DummyEncoding;
+ adapt->nFormats = NUM_FORMATS;
+@@ -600,12 +610,25 @@
+ pPriv = (I830PortPrivPtr) (&adapt->pPortPrivates[1]);
+
+ adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
+- adapt->pAttributes = Attributes;
++ adapt->nAttributes = NUM_ATTRIBUTES;
++ if (pI830->Clone)
++ adapt->nAttributes += CLONE_ATTRIBUTES;
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))
++ adapt->nAttributes += GAMMA_ATTRIBUTES; /* has gamma */
++ adapt->pAttributes = xnfalloc(sizeof(XF86AttributeRec) * adapt->nAttributes);
++ /* Now copy the attributes */
++ att = adapt->pAttributes;
++ memcpy((char *)att, (char*)Attributes, sizeof(XF86AttributeRec)* NUM_ATTRIBUTES);
++ att+=NUM_ATTRIBUTES;
++ if (pI830->Clone) {
++ memcpy((char*)att, (char*)CloneAttributes, sizeof(XF86AttributeRec) * CLONE_ATTRIBUTES);
++ att+=CLONE_ATTRIBUTES;
++ }
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
++ memcpy((char*)att, (char*)GammaAttributes, sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES);
++ att+=GAMMA_ATTRIBUTES;
++ }
+ adapt->nImages = NUM_IMAGES;
+- if (IS_I915G(pI830))
+- adapt->nAttributes = 9; /* has gamma */
+- else
+- adapt->nAttributes = 3;
+ adapt->pImages = Images;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+@@ -622,6 +645,7 @@
+ pPriv->videoStatus = 0;
+ pPriv->brightness = 0;
+ pPriv->contrast = 64;
++ pPriv->pipe = pI830->pipe; /* default to current pipe */
+ pPriv->linear = NULL;
+ pPriv->currentBuf = 0;
+ pPriv->gamma5 = 0xc0c0c0;
+@@ -655,7 +679,12 @@
+ xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+ xvContrast = MAKE_ATOM("XV_CONTRAST");
+ xvColorKey = MAKE_ATOM("XV_COLORKEY");
+- if (IS_I915G(pI830)) {
++
++ /* Allow the pipe to be switched from pipe A to B when in clone mode */
++ if (pI830->Clone)
++ xvPipe = MAKE_ATOM("XV_PIPE");
++
++ if (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830)) {
+ xvGamma0 = MAKE_ATOM("XV_GAMMA0");
+ xvGamma1 = MAKE_ATOM("XV_GAMMA1");
+ xvGamma2 = MAKE_ATOM("XV_GAMMA2");
+@@ -759,7 +788,21 @@
+ overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
+ if (pPriv->overlayOK)
+ OVERLAY_UPDATE;
+- } else if (attribute == xvGamma0 && (IS_I915G(pI830))) {
++ } else if (pI830->Clone && attribute == xvPipe) {
++ if ((value < 0) || (value > 1))
++ return BadValue;
++ pPriv->pipe = value;
++ /*
++ * Select which pipe the overlay is enabled on.
++ */
++ overlay->OCONFIG &= ~OVERLAY_PIPE_MASK;
++ if (pPriv->pipe == 0)
++ overlay->OCONFIG |= OVERLAY_PIPE_A;
++ else
++ overlay->OCONFIG |= OVERLAY_PIPE_B;
++ if (pPriv->overlayOK)
++ OVERLAY_UPDATE;
++ } else if (attribute == xvGamma0 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ /* Avoid video anomalies, so set gamma registers when overlay is off */
+ /* We also clamp the values if they are outside the ranges */
+ if (!*pI830->overlayOn) {
+@@ -768,35 +811,35 @@
+ pPriv->gamma1 = pPriv->gamma0 + 0x7d;
+ } else
+ return BadRequest;
+- } else if (attribute == xvGamma1 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma1 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ if (!*pI830->overlayOn) {
+ pPriv->gamma1 = value;
+ if (pPriv->gamma1 - pPriv->gamma0 > 0x7d)
+ pPriv->gamma0 = pPriv->gamma1 - 0x7d;
+ } else
+ return BadRequest;
+- } else if (attribute == xvGamma2 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma2 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ if (!*pI830->overlayOn) {
+ pPriv->gamma2 = value;
+ if (pPriv->gamma3 - pPriv->gamma2 > 0x7d)
+ pPriv->gamma3 = pPriv->gamma2 + 0x7d;
+ } else
+ return BadRequest;
+- } else if (attribute == xvGamma3 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma3 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ if (!*pI830->overlayOn) {
+ pPriv->gamma3 = value;
+ if (pPriv->gamma3 - pPriv->gamma2 > 0x7d)
+ pPriv->gamma2 = pPriv->gamma3 - 0x7d;
+ } else
+ return BadRequest;
+- } else if (attribute == xvGamma4 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma4 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ if (!*pI830->overlayOn) {
+ pPriv->gamma4 = value;
+ if (pPriv->gamma5 - pPriv->gamma4 > 0x7d)
+ pPriv->gamma5 = pPriv->gamma4 + 0x7d;
+ } else
+ return BadRequest;
+- } else if (attribute == xvGamma5 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma5 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ if (!*pI830->overlayOn) {
+ pPriv->gamma5 = value;
+ if (pPriv->gamma5 - pPriv->gamma4 > 0x7d)
+@@ -828,7 +871,7 @@
+ attribute == xvGamma2 ||
+ attribute == xvGamma3 ||
+ attribute == xvGamma4 ||
+- attribute == xvGamma5) && (IS_I915G(pI830))) {
++ attribute == xvGamma5) && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ I830UpdateGamma(pScrn);
+ }
+
+@@ -846,17 +889,19 @@
+ *value = pPriv->brightness;
+ } else if (attribute == xvContrast) {
+ *value = pPriv->contrast;
+- } else if (attribute == xvGamma0 && (IS_I915G(pI830))) {
++ } else if (pI830->Clone && attribute == xvPipe) {
++ *value = pPriv->pipe;
++ } else if (attribute == xvGamma0 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ *value = pPriv->gamma0;
+- } else if (attribute == xvGamma1 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma1 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ *value = pPriv->gamma1;
+- } else if (attribute == xvGamma2 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma2 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ *value = pPriv->gamma2;
+- } else if (attribute == xvGamma3 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma3 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ *value = pPriv->gamma3;
+- } else if (attribute == xvGamma4 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma4 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ *value = pPriv->gamma4;
+- } else if (attribute == xvGamma5 && (IS_I915G(pI830))) {
++ } else if (attribute == xvGamma5 && (IS_I915G(pI830) || IS_I915GM(pI830) || IS_I945G(pI830))) {
+ *value = pPriv->gamma5;
+ } else if (attribute == xvColorKey) {
+ *value = pPriv->colorKey;
+@@ -912,7 +957,7 @@
+
+ static void
+ I830CopyPlanarData(ScrnInfoPtr pScrn, unsigned char *buf, int srcPitch,
+- int dstPitch, int srcH, int top, int left,
++ int srcPitch2, int dstPitch, int srcH, int top, int left,
+ int h, int w, int id)
+ {
+ I830Ptr pI830 = I830PTR(pScrn);
+@@ -920,8 +965,8 @@
+ int i;
+ unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3;
+
+- DPRINTF(PFX, "I830CopyPlanarData: srcPitch %d, dstPitch %d\n"
+- "nlines %d, npixels %d, top %d, left %d\n", srcPitch, dstPitch,
++ ErrorF("I830CopyPlanarData: srcPitch %d, srcPitch %d, dstPitch %d\n"
++ "nlines %d, npixels %d, top %d, left %d\n", srcPitch, srcPitch2, dstPitch,
+ h, w, top, left);
+
+ /* Copy Y data */
+@@ -957,12 +1002,12 @@
+
+ for (i = 0; i < h / 2; i++) {
+ memcpy(dst2, src2, w / 2);
+- src2 += srcPitch >> 1;
++ src2 += srcPitch2;
+ dst2 += dstPitch;
+ }
+
+ /* Copy U data for YV12, or V data for I420 */
+- src3 = buf + (srcH * srcPitch) + ((srcH * srcPitch) >> 2) +
++ src3 = buf + (srcH * srcPitch) + ((srcH >> 1) * srcPitch2) +
+ ((top * srcPitch) >> 2) + (left >> 1);
+ ErrorF("src3 is %p, offset is %d\n", src3,
+ (unsigned long)src3 - (unsigned long)buf);
+@@ -980,7 +1025,7 @@
+
+ for (i = 0; i < h / 2; i++) {
+ memcpy(dst3, src3, w / 2);
+- src3 += srcPitch >> 1;
++ src3 += srcPitch2;
+ dst3 += dstPitch;
+ }
+ }
+@@ -1125,70 +1170,126 @@
+ I830OverlayRegPtr overlay =
+ (I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem->Start);
+ unsigned int swidth;
++ unsigned int mask, shift, offsety, offsetu;
+
+- DPRINTF(PFX, "I830DisplayVideo: %dx%d (pitch %d)\n", width, height,
++ ErrorF("I830DisplayVideo: %dx%d (pitch %d)\n", width, height,
+ dstPitch);
+
+ if (!pPriv->overlayOK)
+ return;
+
++ if (IS_I915G(pI830) || IS_I915GM(pI830)) {
++ shift = 6;
++ mask = 0x3f;
++ } else {
++ shift = 5;
++ mask = 0x1f;
++ }
++
++ if (pPriv->currentBuf == 0) {
++ offsety = pPriv->YBuf0offset;
++ offsetu = pPriv->UBuf0offset;
++ } else {
++ offsety = pPriv->YBuf1offset;
++ offsetu = pPriv->UBuf1offset;
++ }
++
+ #if VIDEO_DEBUG
+ CompareOverlay(pI830, (CARD32 *) overlay, 0x100);
+ #endif
+
+ /* When in dual head with different bpp setups we need to refresh the
+ * color key, so let's reset the video parameters and refresh here */
+- I830ResetVideo(pScrn);
++#if 0
++ if (pI830->entityPrivate)
++#endif
++ I830ResetVideo(pScrn);
+
+ switch (id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+- swidth = (width + 1) & ~1 & 0xfff;
++ swidth = width;
++
+ overlay->SWIDTH = swidth;
+ swidth /= 2;
+ overlay->SWIDTH |= (swidth & 0x7ff) << 16;
+
+- swidth = ((pPriv->YBuf0offset + width + 0x1f) >> 5) -
+- (pPriv->YBuf0offset >> 5) - 1;
++ swidth = ((offsety + width + mask) >> shift) -
++ (offsety >> shift);
++
++ if (IS_I915G(pI830) || IS_I915GM(pI830))
++ swidth <<= 1;
+
+- ErrorF("Y width is %d, swidthsw is %d\n", width, swidth);
++ swidth -= 1;
++
++ ErrorF("Y width is %d, swidth is %d\n", width, swidth);
+
+ overlay->SWIDTHSW = swidth << 2;
+
+- swidth = ((pPriv->UBuf0offset + (width / 2) + 0x1f) >> 5) -
+- (pPriv->UBuf0offset >> 5) - 1;
++ swidth = ((offsetu + (width / 2) + mask) >> shift) -
++ (offsetu >> shift);
++
++ if (IS_I915G(pI830) || IS_I915GM(pI830))
++ swidth <<= 1;
++
++ swidth -= 1;
++
+ ErrorF("UV width is %d, swidthsw is %d\n", width / 2, swidth);
+
+ overlay->SWIDTHSW |= swidth << 18;
++
++ ErrorF("HEIGHT is %d\n",height);
++
++ overlay->SHEIGHT = height | ((height / 2) << 16);
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+- /* XXX Check for i845 */
+-
+- swidth = ((width + 31) & ~31) << 1;
++ swidth = width;
+ overlay->SWIDTH = swidth;
+- overlay->SWIDTHSW = swidth >> 3;
++
++ ErrorF("Y width is %d\n", swidth);
++
++ swidth = ((offsety + (width << 1) + mask) >> shift) -
++ (offsety >> shift);
++
++ if (IS_I915G(pI830) || IS_I915GM(pI830))
++ swidth <<= 1;
++
++ swidth -= 1;
++
++ ErrorF("swidthsw is %d\n", swidth);
++
++ overlay->SWIDTHSW = swidth << 2;
++
++ ErrorF("HEIGHT is %d\n",height);
++
++ overlay->SHEIGHT = height;
+ break;
+ }
+
+- overlay->SHEIGHT = height | ((height / 2) << 16);
+-
+ if (pPriv->oneLineMode) {
+ /* change the coordinates with panel fitting active */
+ dstBox->y1 = (((dstBox->y1 - 1) * pPriv->scaleRatio) >> 16) + 1;
+ dstBox->y2 = ((dstBox->y2 * pPriv->scaleRatio) >> 16) + 1;
+-
++
+ /* Now, alter the height, so we scale to the correct size */
+- drw_h = dstBox->y2 - dstBox->y1;
+- if (drw_h < height) drw_h = height;
++ drw_h = ((drw_h * pPriv->scaleRatio) >> 16) + 1;
++
++ /* Keep the engine happy */
++ if (dstBox->y1 < 0) dstBox->y1 = 0;
++ if (dstBox->y2 < 0) dstBox->y2 = 0;
+ }
+
++
+ overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1;
+
+ overlay->DWINSZ = ((dstBox->y2 - dstBox->y1) << 16) |
+ (dstBox->x2 - dstBox->x1);
+
++ ErrorF("dstBox: x1: %d, y1: %d, x2: %d, y2: %d\n", dstBox->x1, dstBox->y1,
++ dstBox->x2, dstBox->y2);
++
+ /* buffer locations */
+ overlay->OBUF_0Y = pPriv->YBuf0offset;
+ overlay->OBUF_0U = pPriv->UBuf0offset;
+@@ -1252,8 +1353,8 @@
+ /*
+ * Y down-scale factor as a multiple of 4096.
+ */
+- xscaleFract = (src_w << 12) / drw_w;
+- yscaleFract = (src_h << 12) / drw_h;
++ xscaleFract = ((src_w - 1) << 12) / drw_w;
++ yscaleFract = ((src_h - 1) << 12) / drw_h;
+
+ /* Calculate the UV scaling factor. */
+ xscaleFractUV = xscaleFract / uvratio;
+@@ -1273,9 +1374,9 @@
+ xscaleIntUV = xscaleFractUV >> 12;
+ yscaleIntUV = yscaleFractUV >> 12;
+
+- ErrorF("xscale: 0x%x.%03x, yscale: 0x%x.%03x\n", xscaleInt,
++ ErrorF("xscale: %x.%03x, yscale: %x.%03x\n", xscaleInt,
+ xscaleFract & 0xFFF, yscaleInt, yscaleFract & 0xFFF);
+- ErrorF("UV xscale: 0x%x.%03x, UV yscale: 0x%x.%03x\n", xscaleIntUV,
++ ErrorF("UV xscale: %x.%03x, UV yscale: %x.%03x\n", xscaleIntUV,
+ xscaleFractUV & 0xFFF, yscaleIntUV, yscaleFractUV & 0xFFF);
+
+ newval = (xscaleInt << 16) |
+@@ -1385,13 +1486,9 @@
+ {
+ ScreenPtr pScreen;
+ FBLinearPtr new_linear;
+- int bytespp = pScrn->bitsPerPixel >> 3;
+
+ DPRINTF(PFX, "I830AllocateMemory\n");
+
+- /* convert size in bytes into number of pixels */
+- size = (size + bytespp - 1) / bytespp;
+-
+ if (linear) {
+ if (linear->size >= size)
+ return linear;
+@@ -1438,7 +1535,7 @@
+ I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
+ ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ INT32 x1, x2, y1, y2;
+- int srcPitch, dstPitch;
++ int srcPitch, srcPitch2 = 0, dstPitch;
+ int top, left, npixels, nlines, size, loops;
+ BoxRec dstBox;
+
+@@ -1448,7 +1545,7 @@
+
+ if (pI830->entityPrivate) {
+ if (pI830->entityPrivate->XvInUse != -1 &&
+- pI830->entityPrivate->XvInUse != pI830->pipe) {
++ pI830->entityPrivate->XvInUse != pPriv->pipe) {
+ #ifdef PANORAMIX
+ if (!noPanoramiXExtension) {
+ return Success; /* faked for trying to share it */
+@@ -1459,9 +1556,16 @@
+ }
+ }
+
+- pI830->entityPrivate->XvInUse = pI830->pipe;
++ pI830->entityPrivate->XvInUse = pPriv->pipe;
+ }
+
++ /* overlay limits */
++ if(src_w > (drw_w * 7))
++ drw_w = src_w * 7;
++
++ if(src_h > (drw_h * 7))
++ drw_h = src_h * 7;
++
+ /* Clip */
+ x1 = src_x;
+ x2 = src_x + src_w;
+@@ -1486,21 +1590,22 @@
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ srcPitch = (width + 3) & ~3;
+- dstPitch = ((width / 2) + 255) & ~255; /* of chroma */
++ srcPitch2 = ((width >> 1) + 3) & ~3;
++ dstPitch = ((width / 2) + 63) & ~63; /* of chroma */
+ size = dstPitch * height * 3;
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+- srcPitch = (width << 1);
+- dstPitch = (srcPitch + 255) & ~255;
++ srcPitch = width << 1;
++ dstPitch = (srcPitch + 63) & ~63; /* of chroma */
+ size = dstPitch * height;
+ break;
+ }
+ ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, dstPitch, size);
+
+- if (!(pPriv->linear = I830AllocateMemory(pScrn, pPriv->linear,
+- size * 2 / pI830->cpp)))
++ /* size is multiplied by 2 because we have two buffers that are flipping */
++ if (!(pPriv->linear = I830AllocateMemory(pScrn, pPriv->linear, size * 2 / pI830->cpp)))
+ return BadAlloc;
+
+ /* fixup pointers */
+@@ -1549,7 +1654,7 @@
+ case FOURCC_I420:
+ top &= ~1;
+ nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
+- I830CopyPlanarData(pScrn, buf, srcPitch, dstPitch, height, top, left,
++ I830CopyPlanarData(pScrn, buf, srcPitch, srcPitch2, dstPitch, height, top, left,
+ nlines, npixels, id);
+ break;
+ case FOURCC_UYVY:
+@@ -1605,21 +1710,13 @@
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ *h = (*h + 1) & ~1;
+-#if 1
+ size = (*w + 3) & ~3;
+-#else
+- size = (*w + 255) & ~255;
+-#endif
+ if (pitches)
+ pitches[0] = size;
+ size *= *h;
+ if (offsets)
+ offsets[1] = size;
+-#if 1
+ tmp = ((*w >> 1) + 3) & ~3;
+-#else
+- tmp = ((*w >> 1) + 255) & ~255;
+-#endif
+ if (pitches)
+ pitches[1] = pitches[2] = tmp;
+ tmp *= (*h >> 1);
+@@ -1836,7 +1933,7 @@
+
+ if (pI830->entityPrivate) {
+ if (pI830->entityPrivate->XvInUse != -1 &&
+- pI830->entityPrivate->XvInUse != pI830->pipe) {
++ pI830->entityPrivate->XvInUse != pI830Priv->pipe) {
+ #ifdef PANORAMIX
+ if (!noPanoramiXExtension) {
+ return Success; /* faked for trying to share it */
+@@ -1847,7 +1944,7 @@
+ }
+ }
+
+- pI830->entityPrivate->XvInUse = pI830->pipe;
++ pI830->entityPrivate->XvInUse = pI830Priv->pipe;
+ }
+
+ x1 = src_x;
+@@ -1978,7 +2075,7 @@
+ if (!pPriv)
+ return;
+
+- if (pI830->pipe == 0) {
++ if (pPriv->pipe == 0) {
+ if (INREG(PIPEACONF) & PIPEACONF_DOUBLE_WIDE) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Disabling XVideo output because Pipe A is in double-wide mode.\n");
+@@ -1990,7 +2087,7 @@
+ }
+ }
+
+- if (pI830->pipe == 1) {
++ if (pPriv->pipe == 1) {
+ if (INREG(PIPEBCONF) & PIPEBCONF_DOUBLE_WIDE) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Disabling XVideo output because Pipe B is in double-wide mode.\n");
+@@ -2002,12 +2099,13 @@
+ }
+ }
+
+- /* Check we are on pipe B and have an LFP connected */
+- if ((pI830->pipe == 1) && (pI830->operatingDevices & (PIPE_LFP << 8))) {
+- size = INREG(PIPEBSRC);
++ /* Check we have an LFP connected */
++ if ((pPriv->pipe == 1 && pI830->operatingDevices & (PIPE_LFP << 8)) ||
++ (pPriv->pipe == 0 && pI830->operatingDevices & PIPE_LFP) ) {
++ size = pI830->pipe ? INREG(PIPEBSRC) : INREG(PIPEASRC);
+ hsize = (size >> 16) & 0x7FF;
+ vsize = size & 0x7FF;
+- active = INREG(VTOTAL_B) & 0x7FF;
++ active = pI830->pipe ? (INREG(VTOTAL_B) & 0x7FF) : (INREG(VTOTAL_A) & 0x7FF);
+
+ if (vsize < active && hsize > 1024)
+ I830SetOneLineModeRatio(pScrn);
+--- /dev/null 2004-06-24 14:04:38.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_modes.c 2005-08-18 19:40:24.000000000 -0400
+@@ -0,0 +1,769 @@
++#define DEBUG_VERB 2
++/*
++ * Copyright © 2002 David Dawes
++ *
++ * 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 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 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 author(s).
++ *
++ * Authors: David Dawes <dawes@xfree86.org>
++ *
++ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/vbe/vbeModes.c,v 1.6 2002/11/02 01:38:25 dawes Exp $
++ */
++/*
++ * Modified by Alan Hourihane <alanh@tungstengraphics.com>
++ * to support extended BIOS modes for the Intel chipsets
++ */
++
++#include "xf86.h"
++#include "xf86_ansic.h"
++#include "vbe.h"
++#include "vbeModes.h"
++#include "i830.h"
++
++#include <math.h>
++
++#define rint(x) floor(x)
++
++#define MARGIN_PERCENT 1.8 /* % of active vertical image */
++#define CELL_GRAN 8.0 /* assumed character cell granularity */
++#define MIN_PORCH 1 /* minimum front porch */
++#define V_SYNC_RQD 3 /* width of vsync in lines */
++#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
++#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
++#define M 600.0 /* blanking formula gradient */
++#define C 40.0 /* blanking formula offset */
++#define K 128.0 /* blanking formula scaling factor */
++#define J 20.0 /* blanking formula scaling factor */
++
++/* C' and M' are part of the Blanking Duty Cycle computation */
++
++#define C_PRIME (((C - J) * K/256.0) + J)
++#define M_PRIME (K/256.0 * M)
++
++extern const int i830refreshes[];
++
++static DisplayModePtr
++I830GetGTF (int h_pixels, int v_lines, float freq,
++ int interlaced, int margins)
++{
++ float h_pixels_rnd;
++ float v_lines_rnd;
++ float v_field_rate_rqd;
++ float top_margin;
++ float bottom_margin;
++ float interlace;
++ float h_period_est;
++ float vsync_plus_bp;
++ float v_back_porch;
++ float total_v_lines;
++ float v_field_rate_est;
++ float h_period;
++ float v_field_rate;
++ float v_frame_rate;
++ float left_margin;
++ float right_margin;
++ float total_active_pixels;
++ float ideal_duty_cycle;
++ float h_blank;
++ float total_pixels;
++ float pixel_freq;
++ float h_freq;
++
++ float h_sync;
++ float h_front_porch;
++ float v_odd_front_porch_lines;
++ char modename[20];
++ DisplayModePtr m;
++
++ m = xnfcalloc(sizeof(DisplayModeRec), 1);
++
++
++ /* 1. In order to give correct results, the number of horizontal
++ * pixels requested is first processed to ensure that it is divisible
++ * by the character size, by rounding it to the nearest character
++ * cell boundary:
++ *
++ * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND])
++ */
++
++ h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
++
++
++ /* 2. If interlace is requested, the number of vertical lines assumed
++ * by the calculation must be halved, as the computation calculates
++ * the number of vertical lines per field. In either case, the
++ * number of lines is rounded to the nearest integer.
++ *
++ * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0),
++ * ROUND([V LINES],0))
++ */
++
++ v_lines_rnd = interlaced ?
++ rint((float) v_lines) / 2.0 :
++ rint((float) v_lines);
++
++ /* 3. Find the frame rate required:
++ *
++ * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2,
++ * [I/P FREQ RQD])
++ */
++
++ v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
++
++ /* 4. Find number of lines in Top margin:
++ *
++ * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
++ * ROUND(([MARGIN%]/100*[V LINES RND]),0),
++ * 0)
++ */
++
++ top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
++
++ /* 5. Find number of lines in Bottom margin:
++ *
++ * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
++ * ROUND(([MARGIN%]/100*[V LINES RND]),0),
++ * 0)
++ */
++
++ bottom_margin = margins ? rint(MARGIN_PERCENT/100.0 * v_lines_rnd) : (0.0);
++
++ /* 6. If interlace is required, then set variable [INTERLACE]=0.5:
++ *
++ * [INTERLACE]=(IF([INT RQD?]="y",0.5,0))
++ */
++
++ interlace = interlaced ? 0.5 : 0.0;
++
++ /* 7. Estimate the Horizontal period
++ *
++ * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) /
++ * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) +
++ * [MIN PORCH RND]+[INTERLACE]) * 1000000
++ */
++
++ h_period_est = (((1.0/v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP/1000000.0))
++ / (v_lines_rnd + (2*top_margin) + MIN_PORCH + interlace)
++ * 1000000.0);
++
++ /* 8. Find the number of lines in V sync + back porch:
++ *
++ * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0)
++ */
++
++ vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP/h_period_est);
++
++ /* 9. Find the number of lines in V back porch alone:
++ *
++ * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND]
++ *
++ * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]?
++ */
++
++ v_back_porch = vsync_plus_bp - V_SYNC_RQD;
++
++ /* 10. Find the total number of lines in Vertical field period:
++ *
++ * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] +
++ * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] +
++ * [MIN PORCH RND]
++ */
++
++ total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp +
++ interlace + MIN_PORCH;
++
++ /* 11. Estimate the Vertical field frequency:
++ *
++ * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000
++ */
++
++ v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
++
++ /* 12. Find the actual horizontal period:
++ *
++ * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST])
++ */
++
++ h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
++
++ /* 13. Find the actual Vertical field frequency:
++ *
++ * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000
++ */
++
++ v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
++
++ /* 14. Find the Vertical frame frequency:
++ *
++ * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE]))
++ */
++
++ v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
++
++ /* 15. Find number of pixels in left margin:
++ *
++ * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
++ * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
++ * [CELL GRAN RND]),0)) * [CELL GRAN RND],
++ * 0))
++ */
++
++ left_margin = margins ?
++ rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
++ 0.0;
++
++ /* 16. Find number of pixels in right margin:
++ *
++ * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
++ * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
++ * [CELL GRAN RND]),0)) * [CELL GRAN RND],
++ * 0))
++ */
++
++ right_margin = margins ?
++ rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
++ 0.0;
++
++ /* 17. Find total number of active pixels in image and left and right
++ * margins:
++ *
++ * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] +
++ * [RIGHT MARGIN (PIXELS)]
++ */
++
++ total_active_pixels = h_pixels_rnd + left_margin + right_margin;
++
++ /* 18. Find the ideal blanking duty cycle from the blanking duty cycle
++ * equation:
++ *
++ * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000)
++ */
++
++ ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
++
++ /* 19. Find the number of pixels in the blanking time to the nearest
++ * double character cell:
++ *
++ * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] *
++ * [IDEAL DUTY CYCLE] /
++ * (100-[IDEAL DUTY CYCLE]) /
++ * (2*[CELL GRAN RND])), 0))
++ * * (2*[CELL GRAN RND])
++ */
++
++ h_blank = rint(total_active_pixels *
++ ideal_duty_cycle /
++ (100.0 - ideal_duty_cycle) /
++ (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
++
++ /* 20. Find total number of pixels:
++ *
++ * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)]
++ */
++
++ total_pixels = total_active_pixels + h_blank;
++
++ /* 21. Find pixel clock frequency:
++ *
++ * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD]
++ */
++
++ pixel_freq = total_pixels / h_period;
++
++ /* 22. Find horizontal frequency:
++ *
++ * [H FREQ] = 1000 / [H PERIOD]
++ */
++
++ h_freq = 1000.0 / h_period;
++
++
++ /* Stage 1 computations are now complete; I should really pass
++ the results to another function and do the Stage 2
++ computations, but I only need a few more values so I'll just
++ append the computations here for now */
++
++
++
++ /* 17. Find the number of pixels in the horizontal sync period:
++ *
++ * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] /
++ * [CELL GRAN RND]),0))*[CELL GRAN RND]
++ */
++
++ h_sync = rint(H_SYNC_PERCENT/100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
++
++ /* 18. Find the number of pixels in the horizontal front porch period:
++ *
++ * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)]
++ */
++
++ h_front_porch = (h_blank / 2.0) - h_sync;
++
++ /* 36. Find the number of lines in the odd front porch period:
++ *
++ * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE])
++ */
++
++ v_odd_front_porch_lines = MIN_PORCH + interlace;
++
++ /* finally, pack the results in the DisplayMode struct */
++
++ m->HDisplay = (int) (h_pixels_rnd);
++ m->HSyncStart = (int) (h_pixels_rnd + h_front_porch);
++ m->HSyncEnd = (int) (h_pixels_rnd + h_front_porch + h_sync);
++ m->HTotal = (int) (total_pixels);
++
++ m->VDisplay = (int) (v_lines_rnd);
++ m->VSyncStart = (int) (v_lines_rnd + v_odd_front_porch_lines);
++ m->VSyncEnd = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
++ m->VTotal = (int) (total_v_lines);
++
++ m->Clock = (int)(pixel_freq * 1000);
++ m->SynthClock = m->Clock;
++ m->HSync = h_freq;
++ m->VRefresh = freq;
++
++ snprintf(modename, sizeof(modename), "%dx%d", m->HDisplay,m->VDisplay);
++ m->name = xnfstrdup(modename);
++
++ return (m);
++}
++
++static DisplayModePtr
++CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, int id,
++ int flags)
++{
++ CARD16 major, minor;
++ VbeModeInfoBlock *mode;
++ DisplayModePtr p = NULL, pMode = NULL;
++ VbeModeInfoData *data;
++ Bool modeOK = FALSE;
++ ModeStatus status = MODE_OK;
++
++ major = (unsigned)(vbe->VESAVersion >> 8);
++ minor = vbe->VESAVersion & 0xff;
++
++ if ((mode = VBEGetModeInfo(pVbe, id)) == NULL)
++ return NULL;
++
++ /* Does the mode match the depth/bpp? */
++ /* Some BIOS's set BitsPerPixel to 15 instead of 16 for 15/16 */
++ if (VBE_MODE_USABLE(mode, flags) &&
++ ((pScrn->bitsPerPixel == 1 && !VBE_MODE_COLOR(mode)) ||
++ (mode->BitsPerPixel > 8 &&
++ (mode->RedMaskSize + mode->GreenMaskSize +
++ mode->BlueMaskSize) == pScrn->depth &&
++ mode->BitsPerPixel == pScrn->bitsPerPixel) ||
++ (mode->BitsPerPixel == 15 && pScrn->depth == 15) ||
++ (mode->BitsPerPixel <= 8 &&
++ mode->BitsPerPixel == pScrn->bitsPerPixel))) {
++ modeOK = TRUE;
++ xf86ErrorFVerb(DEBUG_VERB, "*");
++ }
++
++ if (mode->XResolution && mode->YResolution &&
++ !I830CheckModeSupport(pScrn, mode->XResolution, mode->YResolution, id))
++ modeOK = FALSE;
++
++
++ /*
++ * Check if there's a valid monitor mode that this one can be matched
++ * up with from the 'specified' modes list.
++ */
++ if (modeOK) {
++ for (p = pScrn->monitor->Modes; p != NULL; p = p->next) {
++ if ((p->type != 0) ||
++ (p->HDisplay != mode->XResolution) ||
++ (p->VDisplay != mode->YResolution) ||
++ (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))
++ continue;
++ status = xf86CheckModeForMonitor(p, pScrn->monitor);
++ if (status == MODE_OK) {
++ modeOK = TRUE;
++ break;
++ }
++ }
++ if (p) {
++ pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
++ memcpy((char*)pMode,(char*)p,sizeof(DisplayModeRec));
++ pMode->name = xnfstrdup(p->name);
++ }
++ }
++
++ /*
++ * Now, check if there's a valid monitor mode that this one can be matched
++ * up with from the default modes list. i.e. VESA modes in xf86DefModes.c
++ */
++ if (modeOK && !pMode) {
++ int refresh = 0, calcrefresh = 0;
++ DisplayModePtr newMode = NULL;
++
++ for (p = pScrn->monitor->Modes; p != NULL; p = p->next) {
++ calcrefresh = (int)(((double)(p->Clock * 1000) /
++ (double)(p->HTotal * p->VTotal)) * 100);
++ if ((p->type != M_T_DEFAULT) ||
++ (p->HDisplay != mode->XResolution) ||
++ (p->VDisplay != mode->YResolution) ||
++ (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))
++ continue;
++ status = xf86CheckModeForMonitor(p, pScrn->monitor);
++ if (status == MODE_OK) {
++ if (calcrefresh > refresh) {
++ refresh = calcrefresh;
++ newMode = p;
++ }
++ modeOK = TRUE;
++ }
++ }
++ if (newMode) {
++ pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
++ memcpy((char*)pMode,(char*)newMode,sizeof(DisplayModeRec));
++ pMode->name = xnfstrdup(newMode->name);
++ }
++ }
++
++ /*
++ * Check if there's a valid monitor mode that this one can be matched
++ * up with. The actual matching is done later.
++ */
++ if (modeOK && !pMode) {
++ float vrefresh = 0.0f;
++ int i;
++
++ for (i=0;i<pScrn->monitor->nVrefresh;i++) {
++
++ for (vrefresh = pScrn->monitor->vrefresh[i].hi;
++ vrefresh >= pScrn->monitor->vrefresh[i].lo; vrefresh -= 1.0f) {
++
++ if (vrefresh != (float)0.0f) {
++ float best_vrefresh;
++ int int_vrefresh;
++
++ /* Find the best refresh for the Intel chipsets */
++ int_vrefresh = I830GetBestRefresh(pScrn, (int)vrefresh);
++ best_vrefresh = (float)i830refreshes[int_vrefresh];
++
++ /* Now, grab the best mode from the available refresh */
++ pMode = I830GetGTF(mode->XResolution, mode->YResolution,
++ best_vrefresh, 0, 0);
++
++ pMode->type = M_T_BUILTIN;
++
++ status = xf86CheckModeForMonitor(pMode, pScrn->monitor);
++ if (status == MODE_OK) {
++ if (major >= 3) {
++ if (pMode->Clock * 1000 <= mode->MaxPixelClock)
++ modeOK = TRUE;
++ else
++ modeOK = FALSE;
++ } else
++ modeOK = TRUE;
++ } else
++ modeOK = FALSE;
++ pMode->status = status;
++ } else {
++ modeOK = FALSE;
++ }
++ if (modeOK) break;
++ }
++ if (modeOK) break;
++ }
++ }
++
++ xf86ErrorFVerb(DEBUG_VERB,
++ "Mode: %x (%dx%d)\n", id, mode->XResolution, mode->YResolution);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " ModeAttributes: 0x%x\n", mode->ModeAttributes);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " WinAAttributes: 0x%x\n", mode->WinAAttributes);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " WinBAttributes: 0x%x\n", mode->WinBAttributes);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " WinGranularity: %d\n", mode->WinGranularity);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " WinSize: %d\n", mode->WinSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " WinASegment: 0x%x\n", mode->WinASegment);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " WinBSegment: 0x%x\n", mode->WinBSegment);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " WinFuncPtr: 0x%lx\n", mode->WinFuncPtr);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " BytesPerScanline: %d\n", mode->BytesPerScanline);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " XResolution: %d\n", mode->XResolution);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " YResolution: %d\n", mode->YResolution);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " XCharSize: %d\n", mode->XCharSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " YCharSize: %d\n", mode->YCharSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " NumberOfPlanes: %d\n", mode->NumberOfPlanes);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " BitsPerPixel: %d\n", mode->BitsPerPixel);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " NumberOfBanks: %d\n", mode->NumberOfBanks);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " MemoryModel: %d\n", mode->MemoryModel);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " BankSize: %d\n", mode->BankSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " NumberOfImages: %d\n", mode->NumberOfImages);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " RedMaskSize: %d\n", mode->RedMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " RedFieldPosition: %d\n", mode->RedFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " GreenMaskSize: %d\n", mode->GreenMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " GreenFieldPosition: %d\n", mode->GreenFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " BlueMaskSize: %d\n", mode->BlueMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " BlueFieldPosition: %d\n", mode->BlueFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " RsvdMaskSize: %d\n", mode->RsvdMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " RsvdFieldPosition: %d\n", mode->RsvdFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " DirectColorModeInfo: %d\n", mode->DirectColorModeInfo);
++ if (major >= 2) {
++ xf86ErrorFVerb(DEBUG_VERB,
++ " PhysBasePtr: 0x%lx\n", mode->PhysBasePtr);
++ if (major >= 3) {
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinBytesPerScanLine: %d\n", mode->LinBytesPerScanLine);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " BnkNumberOfImagePages: %d\n", mode->BnkNumberOfImagePages);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinNumberOfImagePages: %d\n", mode->LinNumberOfImagePages);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinRedMaskSize: %d\n", mode->LinRedMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinRedFieldPosition: %d\n", mode->LinRedFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinGreenMaskSize: %d\n", mode->LinGreenMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinGreenFieldPosition: %d\n", mode->LinGreenFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinBlueMaskSize: %d\n", mode->LinBlueMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinBlueFieldPosition: %d\n", mode->LinBlueFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinRsvdMaskSize: %d\n", mode->LinRsvdMaskSize);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " LinRsvdFieldPosition: %d\n", mode->LinRsvdFieldPosition);
++ xf86ErrorFVerb(DEBUG_VERB,
++ " MaxPixelClock: %ld\n", mode->MaxPixelClock);
++ }
++ }
++
++ if (!modeOK) {
++ VBEFreeModeInfo(mode);
++ if (pMode)
++ xfree(pMode);
++ return NULL;
++ }
++
++ pMode->status = MODE_OK;
++ pMode->type = M_T_BUILTIN;
++
++ /* for adjust frame */
++ pMode->HDisplay = mode->XResolution;
++ pMode->VDisplay = mode->YResolution;
++
++ data = xnfcalloc(sizeof(VbeModeInfoData), 1);
++ data->mode = id;
++ data->data = mode;
++ pMode->PrivSize = sizeof(VbeModeInfoData);
++ pMode->Private = (INT32*)data;
++ pMode->next = NULL;
++ return pMode;
++}
++
++/*
++ * Check the available BIOS modes, and extract those that match the
++ * requirements into the modePool. Note: modePool is a NULL-terminated
++ * list.
++ */
++
++DisplayModePtr
++I830GetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
++{
++ DisplayModePtr pMode, p = NULL, modePool = NULL;
++ int i = 0;
++
++ for (i = 0; i < 0x7F; i++) {
++ if ((pMode = CheckMode(pScrn, pVbe, vbe, i, V_MODETYPE_VGA)) != NULL) {
++ ModeStatus status = MODE_OK;
++
++ /* Check the mode against a specified virtual size (if any) */
++ if (pScrn->display->virtualX > 0 &&
++ pMode->HDisplay > pScrn->display->virtualX) {
++ status = MODE_VIRTUAL_X;
++ }
++ if (pScrn->display->virtualY > 0 &&
++ pMode->VDisplay > pScrn->display->virtualY) {
++ status = MODE_VIRTUAL_Y;
++ }
++ if (status != MODE_OK) {
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Not using mode \"%dx%d\" (%s)\n",
++ pMode->HDisplay, pMode->VDisplay,
++ xf86ModeStatusToString(status));
++ } else {
++ if (p == NULL) {
++ modePool = pMode;
++ } else {
++ p->next = pMode;
++ }
++ pMode->prev = NULL;
++ p = pMode;
++ }
++ }
++ }
++ return modePool;
++}
++
++/*
++ * Go through the monitor modes and selecting the best set of
++ * parameters for each BIOS mode. Note: This is only supported in
++ * VBE version 3.0 or later.
++ */
++void
++I830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe)
++{
++ DisplayModePtr pMode;
++ VbeModeInfoData *data;
++
++ pMode = pScrn->modes;
++ do {
++ int clock;
++
++ data = (VbeModeInfoData*)pMode->Private;
++ data->block = xcalloc(sizeof(VbeCRTCInfoBlock), 1);
++ data->block->HorizontalTotal = pMode->HTotal;
++ data->block->HorizontalSyncStart = pMode->HSyncStart;
++ data->block->HorizontalSyncEnd = pMode->HSyncEnd;
++ data->block->VerticalTotal = pMode->VTotal;
++ data->block->VerticalSyncStart = pMode->VSyncStart;
++ data->block->VerticalSyncEnd = pMode->VSyncEnd;
++ data->block->Flags = ((pMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
++ ((pMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
++ data->block->PixelClock = pMode->Clock * 1000;
++ /* XXX May not have this. */
++ clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock);
++ if (clock)
++ data->block->PixelClock = clock;
++#ifdef DEBUG
++ ErrorF("Setting clock %.2fMHz, closest is %.2fMHz\n",
++ (double)data->block->PixelClock / 1000000.0,
++ (double)clock / 1000000.0);
++#endif
++ data->mode |= (1 << 11);
++ if (pMode->VRefresh != 0) {
++ data->block->RefreshRate = pMode->VRefresh * 100;
++ } else {
++ data->block->RefreshRate = (int)(((double)(data->block->PixelClock)/
++ (double)(pMode->HTotal * pMode->VTotal)) * 100);
++ }
++ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
++ "Attempting to use %2.2fHz refresh for mode \"%s\" (%x)\n",
++ (float)(((double)(data->block->PixelClock) / (double)(pMode->HTotal * pMode->VTotal))), pMode->name, data->mode);
++#ifdef DEBUG
++ ErrorF("Video Modeline: ID: 0x%x Name: %s %i %i %i %i - "
++ " %i %i %i %i %.2f MHz Refresh: %.2f Hz\n",
++ data->mode, pMode->name, pMode->HDisplay, pMode->HSyncStart,
++ pMode->HSyncEnd, pMode->HTotal, pMode->VDisplay,
++ pMode->VSyncStart,pMode->VSyncEnd,pMode->VTotal,
++ (double)data->block->PixelClock/1000000.0,
++ (double)data->block->RefreshRate/100);
++#endif
++ pMode = pMode->next;
++ } while (pMode != pScrn->modes);
++}
++
++void
++I830PrintModes(ScrnInfoPtr scrp)
++{
++ DisplayModePtr p;
++ float hsync, refresh = 0;
++ char *desc, *desc2, *prefix, *uprefix;
++
++ if (scrp == NULL)
++ return;
++
++ xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d "
++ "(pitch %d)\n", scrp->virtualX, scrp->virtualY,
++ scrp->displayWidth);
++
++ p = scrp->modes;
++ if (p == NULL)
++ return;
++
++ do {
++ desc = desc2 = "";
++ if (p->HSync > 0.0)
++ hsync = p->HSync;
++ else if (p->HTotal > 0)
++ hsync = (float)p->Clock / (float)p->HTotal;
++ else
++ hsync = 0.0;
++ if (p->VTotal > 0)
++ refresh = hsync * 1000.0 / p->VTotal;
++ if (p->Flags & V_INTERLACE) {
++ refresh *= 2.0;
++ desc = " (I)";
++ }
++ if (p->Flags & V_DBLSCAN) {
++ refresh /= 2.0;
++ desc = " (D)";
++ }
++ if (p->VScan > 1) {
++ refresh /= p->VScan;
++ desc2 = " (VScan)";
++ }
++ if (p->VRefresh > 0.0)
++ refresh = p->VRefresh;
++ if (p->type & M_T_BUILTIN)
++ prefix = "Built-in mode";
++ else if (p->type & M_T_DEFAULT)
++ prefix = "Default mode";
++ else
++ prefix = "Mode";
++ if (p->type & M_T_USERDEF)
++ uprefix = "*";
++ else
++ uprefix = " ";
++ if (p->name)
++ xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
++ "%s%s \"%s\"\n", uprefix, prefix, p->name);
++ else
++ xf86DrvMsg(scrp->scrnIndex, X_PROBED,
++ "%s%s %dx%d (unnamed)\n",
++ uprefix, prefix, p->HDisplay, p->VDisplay);
++ p = p->next;
++ } while (p != NULL && p != scrp->modes);
++}
+--- /dev/null 2004-06-24 14:04:38.000000000 -0400
++++ xc/programs/Xserver/hw/xfree86/drivers/i810/i830_shadow.c 2005-08-18 19:40:24.000000000 -0400
+@@ -0,0 +1,249 @@
++/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/s3virge/s3v_shadow.c,v 1.3 2000/03/31 20:13:33 dawes Exp $ */
++
++/*
++ Copyright (c) 1999,2000 The XFree86 Project Inc.
++ based on code written by Mark Vojkovich <markv@valinux.com>
++*/
++
++/*
++ * Ported from the savage driver to the I830 by
++ * Helmar Spangenberg <hspangenberg@frey.de> and Dima Dorfman
++ */
++
++#include "xf86.h"
++#include "i830.h"
++#include "shadowfb.h"
++#include "servermd.h"
++
++
++void
++I830RefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ int width, height, Bpp, FBPitch;
++ unsigned char *src, *dst;
++
++ Bpp = pScrn->bitsPerPixel >> 3;
++ FBPitch = BitmapBytePad(pScrn->displayWidth * pScrn->bitsPerPixel);
++
++ while(num--) {
++ width = (pbox->x2 - pbox->x1) * Bpp;
++ height = pbox->y2 - pbox->y1;
++ src = pI830->shadowPtr + (pbox->y1 * pI830->shadowPitch) +
++ (pbox->x1 * Bpp);
++ dst = pI830->FbBase + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp);
++
++ while(height--) {
++ memcpy(dst, src, width);
++ dst += FBPitch;
++ src += pI830->shadowPitch;
++ }
++
++ pbox++;
++ }
++}
++
++
++void
++I830PointerMoved(int index, int x, int y)
++{
++ ScrnInfoPtr pScrn = xf86Screens[index];
++ I830Ptr pI830 = I830PTR(pScrn);
++ int newX, newY;
++
++ if(pI830->rotate == 1) {
++ newX = pScrn->pScreen->height - y - 1;
++ newY = x;
++ } else {
++ newX = y;
++ newY = pScrn->pScreen->width - x - 1;
++ }
++
++ (*pI830->PointerMoved)(index, newX, newY);
++}
++
++void
++I830RefreshArea8(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ int count, width, height, y1, y2, dstPitch, srcPitch;
++ CARD8 *dstPtr, *srcPtr, *src;
++ CARD32 *dst;
++
++ dstPitch = pScrn->displayWidth;
++ srcPitch = -pI830->rotate * pI830->shadowPitch;
++
++ while(num--) {
++ width = pbox->x2 - pbox->x1;
++ y1 = pbox->y1 & ~3;
++ y2 = (pbox->y2 + 3) & ~3;
++ height = (y2 - y1) >> 2; /* in dwords */
++
++ if(pI830->rotate == 1) {
++ dstPtr = pI830->FbBase +
++ (pbox->x1 * dstPitch) + pScrn->virtualX - y2;
++ srcPtr = pI830->shadowPtr + ((1 - y2) * srcPitch) + pbox->x1;
++ } else {
++ dstPtr = pI830->FbBase +
++ ((pScrn->virtualY - pbox->x2) * dstPitch) + y1;
++ srcPtr = pI830->shadowPtr + (y1 * srcPitch) + pbox->x2 - 1;
++ }
++
++ while(width--) {
++ src = srcPtr;
++ dst = (CARD32*)dstPtr;
++ count = height;
++ while(count--) {
++ *(dst++) = src[0] | (src[srcPitch] << 8) |
++ (src[srcPitch * 2] << 16) |
++ (src[srcPitch * 3] << 24);
++ src += srcPitch * 4;
++ }
++ srcPtr += pI830->rotate;
++ dstPtr += dstPitch;
++ }
++
++ pbox++;
++ }
++}
++
++
++void
++I830RefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ int count, width, height, y1, y2, dstPitch, srcPitch;
++ CARD16 *dstPtr, *srcPtr, *src;
++ CARD32 *dst;
++
++ dstPitch = pScrn->displayWidth;
++ srcPitch = -pI830->rotate * pI830->shadowPitch >> 1;
++
++ while(num--) {
++ width = pbox->x2 - pbox->x1;
++ y1 = pbox->y1 & ~1;
++ y2 = (pbox->y2 + 1) & ~1;
++ height = (y2 - y1) >> 1; /* in dwords */
++
++ if(pI830->rotate == 1) {
++ dstPtr = (CARD16*)pI830->FbBase +
++ (pbox->x1 * dstPitch) + pScrn->virtualX - y2;
++ srcPtr = (CARD16*)pI830->shadowPtr +
++ ((1 - y2) * srcPitch) + pbox->x1;
++ } else {
++ dstPtr = (CARD16*)pI830->FbBase +
++ ((pScrn->virtualY - pbox->x2) * dstPitch) + y1;
++ srcPtr = (CARD16*)pI830->shadowPtr +
++ (y1 * srcPitch) + pbox->x2 - 1;
++ }
++
++ while(width--) {
++ src = srcPtr;
++ dst = (CARD32*)dstPtr;
++ count = height;
++ while(count--) {
++ *(dst++) = src[0] | (src[srcPitch] << 16);
++ src += srcPitch * 2;
++ }
++ srcPtr += pI830->rotate;
++ dstPtr += dstPitch;
++ }
++
++ pbox++;
++ }
++}
++
++
++/* this one could be faster */
++void
++I830RefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ int count, width, height, y1, y2, dstPitch, srcPitch;
++ CARD8 *dstPtr, *srcPtr, *src;
++ CARD32 *dst;
++
++ dstPitch = BitmapBytePad(pScrn->displayWidth * 24);
++ srcPitch = -pI830->rotate * pI830->shadowPitch;
++
++ while(num--) {
++ width = pbox->x2 - pbox->x1;
++ y1 = pbox->y1 & ~3;
++ y2 = (pbox->y2 + 3) & ~3;
++ height = (y2 - y1) >> 2; /* blocks of 3 dwords */
++
++ if(pI830->rotate == 1) {
++ dstPtr = pI830->FbBase +
++ (pbox->x1 * dstPitch) + ((pScrn->virtualX - y2) * 3);
++ srcPtr = pI830->shadowPtr + ((1 - y2) * srcPitch) + (pbox->x1 * 3);
++ } else {
++ dstPtr = pI830->FbBase +
++ ((pScrn->virtualY - pbox->x2) * dstPitch) + (y1 * 3);
++ srcPtr = pI830->shadowPtr + (y1 * srcPitch) + (pbox->x2 * 3) - 3;
++ }
++
++ while(width--) {
++ src = srcPtr;
++ dst = (CARD32*)dstPtr;
++ count = height;
++ while(count--) {
++ dst[0] = src[0] | (src[1] << 8) | (src[2] << 16) |
++ (src[srcPitch] << 24);
++ dst[1] = src[srcPitch + 1] | (src[srcPitch + 2] << 8) |
++ (src[srcPitch * 2] << 16) |
++ (src[(srcPitch * 2) + 1] << 24);
++ dst[2] = src[(srcPitch * 2) + 2] | (src[srcPitch * 3] << 8) |
++ (src[(srcPitch * 3) + 1] << 16) |
++ (src[(srcPitch * 3) + 2] << 24);
++ dst += 3;
++ src += srcPitch * 4;
++ }
++ srcPtr += pI830->rotate * 3;
++ dstPtr += dstPitch;
++ }
++
++ pbox++;
++ }
++}
++
++void
++I830RefreshArea32(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
++{
++ I830Ptr pI830 = I830PTR(pScrn);
++ int count, width, height, dstPitch, srcPitch;
++ CARD32 *dstPtr, *srcPtr, *src, *dst;
++
++ dstPitch = pScrn->displayWidth;
++ srcPitch = -pI830->rotate * pI830->shadowPitch >> 2;
++
++ while(num--) {
++ width = pbox->x2 - pbox->x1;
++ height = pbox->y2 - pbox->y1;
++
++ if(pI830->rotate == 1) {
++ dstPtr = (CARD32*)pI830->FbBase +
++ (pbox->x1 * dstPitch) + pScrn->virtualX - pbox->y2;
++ srcPtr = (CARD32*)pI830->shadowPtr +
++ ((1 - pbox->y2) * srcPitch) + pbox->x1;
++ } else {
++ dstPtr = (CARD32*)pI830->FbBase +
++ ((pScrn->virtualY - pbox->x2) * dstPitch) + pbox->y1;
++ srcPtr = (CARD32*)pI830->shadowPtr +
++ (pbox->y1 * srcPitch) + pbox->x2 - 1;
++ }
++
++ while(width--) {
++ src = srcPtr;
++ dst = dstPtr;
++ count = height;
++ while(count--) {
++ *(dst++) = *src;
++ src += srcPitch;
++ }
++ srcPtr += pI830->rotate;
++ dstPtr += dstPitch;
++ }
++
++ pbox++;
++ }
++}