xf86-video-intel: 8 commits - src/i830_cursor.c src/i830_dga.c src/i830_driver.c src/i830.h src/i830_modes.c src/i830_video.c

Alan Hourihane alanh at kemper.freedesktop.org
Tue Aug 8 13:42:13 EEST 2006


 src/i830.h        |   50 +
 src/i830_cursor.c |  124 ++
 src/i830_dga.c    |   26 
 src/i830_driver.c | 2255 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/i830_modes.c  |  132 ++-
 src/i830_video.c  |  102 ++
 6 files changed, 2573 insertions(+), 116 deletions(-)

New commits:
diff-tree e4f63eaf5efb654121db148f2f8e32cc3b23b6b5 (from parents)
Merge: 633a683a4adcb9a44a54519fd7ff66aab2d12f97 e26f3e30b30a57ab4aad0267d689a9a5d7a5e877
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Tue Aug 8 11:07:56 2006 +0100

    Merge branch 'master' of git+ssh://xorg.freedesktop.org/git/xorg/driver/xf86-video-intel

diff-tree 633a683a4adcb9a44a54519fd7ff66aab2d12f97 (from e71108f1e05b7a8d8edd174eb64edd6cccacbcdc)
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Tue Aug 8 10:23:29 2006 +0100

    Ensure palette is updated in mergedfb & clone modes

diff --git a/src/i830_cursor.c b/src/i830_cursor.c
index 1d7808b..1657f7c 100644
--- a/src/i830_cursor.c
+++ b/src/i830_cursor.c
@@ -116,9 +116,10 @@ I830InitHWCursor(ScrnInfoPtr pScrn)
       temp = INREG(CURSOR_CONTROL);
       temp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE |
 		CURSOR_ENABLE  | CURSOR_STRIDE_MASK);
-      temp |= (CURSOR_FORMAT_3C);
       if (pI830->CursorIsARGB)
-         temp |= CURSOR_GAMMA_ENABLE;
+         temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
+      else 
+         temp |= CURSOR_FORMAT_3C;
       /* This initialises the format and leave the cursor disabled. */
       OUTREG(CURSOR_CONTROL, temp);
       /* Need to set address and size after disabling. */
@@ -588,7 +589,7 @@ I830ShowCursor(ScrnInfoPtr pScrn)
       temp = INREG(CURSOR_A_CONTROL);
       temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT | MCURSOR_GAMMA_ENABLE);
       if (pI830->CursorIsARGB)
-         temp |= CURSOR_MODE_64_ARGB_AX;
+         temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
       else
          temp |= CURSOR_MODE_64_4C_AX;
       temp |= (pI830->pipe << 28); /* Connect to correct pipe */
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 256ae22..84fb21a 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -3486,6 +3486,79 @@ I830LoadPalette(ScrnInfoPtr pScrn, int n
    DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors);
    pI830 = I830PTR(pScrn);
 
+   if (pI830->Clone || pI830->MergedFB) {
+      if (!pI830->pipe == 0) {
+         palreg = PALETTE_A;
+         dspreg = DSPACNTR;
+         dspbase = DSPABASE;
+      } else {
+         palreg = PALETTE_B;
+         dspreg = DSPBCNTR;
+         dspbase = DSPBBASE;
+      }
+   
+      /* To ensure gamma is enabled we need to turn off and on the plane */
+      temp = INREG(dspreg);
+      OUTREG(dspreg, temp & ~(1<<31));
+      OUTREG(dspbase, INREG(dspbase));
+      OUTREG(dspreg, temp | 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;
+         for (j = 0; j < 8; j++) {
+	    OUTREG(palreg + index * 32 + (j * 4), val);
+         }
+       }
+       break;
+      case 16:
+       for (i = 0; i < numColors; i++) {
+         index = indices[i];
+	 r   = colors[index / 2].red;
+	 g   = colors[index].green;
+	 b   = colors[index / 2].blue;
+
+	 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);
+
+   	 if (index <= 31) {
+            r   = colors[index].red;
+	    g   = colors[(index * 2) + 1].green;
+	    b   = colors[index].blue;
+
+	    val = (r << 16) | (g << 8) | b;
+	    OUTREG(palreg + index * 32, val);
+	    OUTREG(palreg + index * 32 + 4, val);
+	    OUTREG(palreg + index * 32 + 8, val);
+	    OUTREG(palreg + index * 32 + 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(palreg + index * 4, val);
+       }
+       break;
+      }
+   }
+
    if (pI830->pipe == 0) {
       palreg = PALETTE_A;
       dspreg = DSPACNTR;
diff-tree e71108f1e05b7a8d8edd174eb64edd6cccacbcdc (from a91a4f95c664f6905fef61dab251707bf2548bb8)
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Fri Jul 28 10:32:12 2006 +0100

    Fix DGA with MergedFB
    Turn off rotation support when MergedFB enabled

diff --git a/src/i830_dga.c b/src/i830_dga.c
index 1129fa3..122e881 100644
--- a/src/i830_dga.c
+++ b/src/i830_dga.c
@@ -99,6 +99,31 @@ I830DGAInit(ScreenPtr pScreen)
 
    while (pMode) {
 
+	if(pI830->MergedFB) {
+	   Bool nogood = FALSE;
+	   /* Filter out all meta modes that would require driver-side panning */
+	   switch(((I830ModePrivatePtr)pMode->Private)->merged.SecondPosition) {
+	   case PosRightOf:
+	   case PosLeftOf:
+	      if( (((I830ModePrivatePtr)pMode->Private)->merged.First->VDisplay !=
+		   ((I830ModePrivatePtr)pMode->Private)->merged.Second->VDisplay)	||
+		  (((I830ModePrivatePtr)pMode->Private)->merged.First->VDisplay != pMode->VDisplay) )
+		 nogood = TRUE;
+	      break;
+	   default:
+	      if( (((I830ModePrivatePtr)pMode->Private)->merged.First->HDisplay !=
+		   ((I830ModePrivatePtr)pMode->Private)->merged.Second->HDisplay)	||
+		  (((I830ModePrivatePtr)pMode->Private)->merged.First->HDisplay != pMode->HDisplay) )
+		 nogood = TRUE;
+	   }
+	   if(nogood) {
+	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+			"DGA: MetaMode %dx%d not suitable for DGA, skipping\n",
+			pMode->HDisplay, pMode->VDisplay);
+	      goto mode_nogood;
+	   }
+	}
+
       newmodes = xrealloc(modes, (num + 1) * sizeof(DGAModeRec));
 
       if (!newmodes) {
@@ -155,6 +180,7 @@ I830DGAInit(ScreenPtr pScreen)
       currentMode->maxViewportY = currentMode->imageHeight -
 	    currentMode->viewportHeight;
 
+mode_nogood:
       pMode = pMode->next;
       if (pMode == firstMode)
 	 break;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index d32efa3..256ae22 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -7088,22 +7088,6 @@ I830BIOSScreenInit(int scrnIndex, Screen
    pI830->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = I830BIOSCloseScreen;
 
-   if (!pI830->MergedFB && pI830->shadowReq.minorversion >= 1) {
-      /* Rotation */
-      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RandR enabled, ignore the following RandR disabled message.\n");
-      xf86DisableRandR(); /* Disable built-in RandR extension */
-      shadowSetup(pScreen);
-      /* support all rotations */
-      I830RandRInit(pScreen, RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270);
-      pI830->PointerMoved = pScrn->PointerMoved;
-      pScrn->PointerMoved = I830PointerMoved;
-      pI830->CreateScreenResources = pScreen->CreateScreenResources;
-      pScreen->CreateScreenResources = I830CreateScreenResources;
-   } else {
-      /* Rotation */
-      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "libshadow is version %d.%d.%d, required 1.1.0 or greater for rotation.\n",pI830->shadowReq.majorversion,pI830->shadowReq.minorversion,pI830->shadowReq.patchlevel);
-   }
-
    if (pI830->MergedFB) {
       pI830->PointerMoved = pScrn->PointerMoved;
       pScrn->PointerMoved = I830MergedPointerMoved;
@@ -7120,6 +7104,20 @@ I830BIOSScreenInit(int scrnIndex, Screen
       } else {
 	  pI830->MouseRestrictions = FALSE;
       }
+   } else if (pI830->shadowReq.minorversion >= 1) {
+      /* Rotation */
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RandR enabled, ignore the following RandR disabled message.\n");
+      xf86DisableRandR(); /* Disable built-in RandR extension */
+      shadowSetup(pScreen);
+      /* support all rotations */
+      I830RandRInit(pScreen, RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270);
+      pI830->PointerMoved = pScrn->PointerMoved;
+      pScrn->PointerMoved = I830PointerMoved;
+      pI830->CreateScreenResources = pScreen->CreateScreenResources;
+      pScreen->CreateScreenResources = I830CreateScreenResources;
+   } else {
+      /* Rotation */
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "libshadow is version %d.%d.%d, required 1.1.0 or greater for rotation.\n",pI830->shadowReq.majorversion,pI830->shadowReq.minorversion,pI830->shadowReq.patchlevel);
    }
 
    if (serverGeneration == 1)
diff-tree a91a4f95c664f6905fef61dab251707bf2548bb8 (from ac3ad32f667b306e771617d784648f7111743f1a)
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Thu Jul 27 16:11:48 2006 +0100

    Fix pipe reversal for Xv

diff --git a/src/i830_video.c b/src/i830_video.c
index 762bddf..b252ac9 100644
--- a/src/i830_video.c
+++ b/src/i830_video.c
@@ -1495,21 +1495,21 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int 
          case PosBelow:
             if ((w2 > 0 && w1 == 0) ||
                 (h2 > 0 && h1 == 0)) {
-               pPriv->pipe = pI830->pipe;
+               pPriv->pipe = !pI830->pipe;
                dstBox->x1 = dstBox2.x1;
                dstBox->y1 = dstBox2.y1;
                dstBox->x2 = dstBox2.x2;
                dstBox->y2 = dstBox2.y2;
             } else 
-               pPriv->pipe = !pI830->pipe;
+               pPriv->pipe = pI830->pipe;
             break;
          case PosLeftOf:
          case PosAbove:
             if ((w1 > 0 && w2 == 0) ||
                 (h1 > 0 && h2 == 0)) { 
-               pPriv->pipe = !pI830->pipe;
-            } else {
                pPriv->pipe = pI830->pipe;
+            } else {
+               pPriv->pipe = !pI830->pipe;
                dstBox->x1 = dstBox2.x1;
                dstBox->y1 = dstBox2.y1;
                dstBox->x2 = dstBox2.x2;
diff-tree ac3ad32f667b306e771617d784648f7111743f1a (from e786e2f9f3a4df31702736db6f68a44c9ebba546)
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Thu Jul 27 15:28:42 2006 +0100

    Calculate allowable refresh rates on the private
    mode data for each independent screen in mergedfb.
    
    Lots of other fixes too.

diff --git a/src/i830_cursor.c b/src/i830_cursor.c
index 3786120..1d7808b 100644
--- a/src/i830_cursor.c
+++ b/src/i830_cursor.c
@@ -432,8 +432,8 @@ I830SetCursorPositionMerged(ScrnInfoPtr 
    temp2 |= ((x2 & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
    temp2 |= ((y2 & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
 
-   OUTREG(CURSOR_A_POSITION, temp2);
-   OUTREG(CURSOR_B_POSITION, temp);
+   OUTREG(CURSOR_A_POSITION, temp);
+   OUTREG(CURSOR_B_POSITION, temp2);
 
    if (pI830->cursorOn) {
       if (hide)
diff --git a/src/i830_driver.c b/src/i830_driver.c
index eb85131..d32efa3 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -742,9 +742,6 @@ I830GenerateModeListFromLargestModes(Scr
      * common mode for First and Second (if available). Additionally, and
      * regardless if the above, we produce a clone mode consisting of
      * the largest common mode (if available) in order to use DGA.
-     * - Clone: If the (global) SecondPosition is Clone, we use the
-     * largest common mode if available, otherwise the first two modes
-     * in each list.
      */
 
     switch(pos) {
@@ -1222,7 +1219,7 @@ I830MergedPointerMoved(int scrnIndex, in
      pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR.Second->VDisplay - 1;
 
      /* No need to update pScrn1->frame?1, done above */
-    if (!pI830->pipe == 0) {
+    if (pI830->pipe == 0) {
        OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp));
        OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp));
     } else {
@@ -5150,8 +5147,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
    }
 
    if (pI830->MergedFB) {
-      DisplayModePtr old_modes;
-      DisplayModePtr cur_mode;
+      DisplayModePtr old_modes, cur_mode;
 
       xf86PruneDriverModes(pI830->pScrn_2);
 
@@ -5915,12 +5911,18 @@ I830VESASetVBEMode(ScrnInfoPtr pScrn, in
    else
       Mon = pI830->MonType2;
 
+
    /* Now recheck refresh operations we can use */
    pI830->useExtendedRefresh = FALSE;
    pI830->vesa->useDefaultRefresh = FALSE;
 
-   if (Mon != PIPE_CRT)
+   if (Mon != PIPE_CRT) {
+      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+		    "A non-CRT device is attached to pipe %c.\n"
+		    "\tNo refresh rate overrides will be attempted.\n",
+		    PIPE_NAME(pI830->pipe));
       pI830->vesa->useDefaultRefresh = TRUE;
+   }
 
    mode |= 1 << 11;
    if (pI830->vesa->useDefaultRefresh)
@@ -6011,13 +6013,24 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
    }else {
       I830ModePrivatePtr s = (I830ModePrivatePtr)mp->merged.Second->Private;
       I830ModePrivatePtr f = (I830ModePrivatePtr)mp->merged.First->Private;
+      int pipe = pI830->pipe; /* save current pipe */
+
       SetBIOSPipe(pScrn, !pI830->pipe);
-      if (I830VESASetVBEMode(pScrn, (f->vbeData.mode | 1<<15 | 1<<14), f->vbeData.block) == FALSE) {
+
+      pI830->pipe = !pI830->pipe;
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode on Pipe %s.\n", pI830->pipe ? "B" : "A");
+
+      if (I830VESASetVBEMode(pScrn, (s->vbeData.mode | 1<<15 | 1<<14), s->vbeData.block) == FALSE) {
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
          return FALSE;
       }
+
+      pI830->pipe = pipe; /* restore current pipe */
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode on Pipe %s.\n", pI830->pipe ? "B" : "A");
+
       SetPipeAccess(pScrn);
-      if (I830VESASetVBEMode(pScrn, (s->vbeData.mode | 1<<15 | 1<<14), s->vbeData.block) == FALSE) {
+
+      if (I830VESASetVBEMode(pScrn, (f->vbeData.mode | 1<<15 | 1<<14), f->vbeData.block) == FALSE) {
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
          return FALSE;
       }
@@ -7170,7 +7183,7 @@ I830BIOSAdjustFrame(int scrnIndex, int x
    if (pI830->MergedFB) {
       I830AdjustFrameMerged(scrnIndex, x, y, flags);
 
-      if (!pI830->pipe == 0) {
+      if (pI830->pipe == 0) {
          OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn->displayWidth + pI830->FirstframeX0) * pI830->cpp));
          OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->pScrn_2->frameY0 * pScrn->displayWidth + pI830->pScrn_2->frameX0) * pI830->cpp));
       } else {
@@ -7344,21 +7357,29 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
 
    /* Re-read EDID */
    pDDCModule = xf86LoadSubModule(pScrn, "ddc");
+
+   if (pI830->MergedFB) {
+      SetBIOSPipe(pScrn, !pI830->pipe);
+      monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
+      if ((pI830->pScrn_2->monitor->DDC = monitor) != NULL) {
+         xf86PrintEDID(monitor);
+         xf86SetDDCproperties(pScrn, monitor);
+      } 
+      SetPipeAccess(pScrn);
+   }
+
    monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
    xf86UnloadSubModule(pDDCModule);
    if ((pScrn->monitor->DDC = monitor) != NULL) {
       xf86PrintEDID(monitor);
       xf86SetDDCproperties(pScrn, monitor);
-   } else 
-      /* No DDC, so get out of here, and continue to use the current settings */
-      return FALSE; 
+   } 
 
-   if (!(DDCclock = I830UseDDC(pScrn)))
-      return FALSE;
+   DDCclock = I830UseDDC(pScrn);
 
+   /* Check if DDC exists on the second head, if not don't abort. */
    if (pI830->MergedFB)
-      if (!(DDCclock2 = I830UseDDC(pScrn)))
-         return FALSE;
+      DDCclock2 = I830UseDDC(pI830->pScrn_2);
 
    /* Revalidate the modes */
 
@@ -7378,7 +7399,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
       return FALSE;
    }
 
-   if (pI830->MergedFB) {
+   if (pI830->MergedFB && DDCclock2 > 0) {
       SetBIOSPipe(pScrn, !pI830->pipe);
       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		 "Retrieving mode pool for second head.\n");
@@ -7394,7 +7415,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
    }
 
    VBESetModeNames(pScrn->modePool);
-   if (pI830->MergedFB)
+   if (pI830->MergedFB && DDCclock2 > 0)
       VBESetModeNames(pI830->pScrn_2->modePool);
 
    if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64))
@@ -7409,7 +7430,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
 			pScrn->display->virtualY,
 			memsize, LOOKUP_BEST_REFRESH);
 
-   if (pI830->MergedFB) {
+   if (pI830->MergedFB && DDCclock2 > 0) {
       VBEValidateModes(pI830->pScrn_2, pI830->pScrn_2->monitor->Modes, 
 		        pI830->pScrn_2->display->modes, NULL,
 			NULL, 0, MAX_DISPLAY_PITCH, 1,
@@ -7450,7 +7471,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
    }
 
    /* Only use this if we've got DDC available */
-   if (DDCclock2 > 0) {
+   if (pI830->MergedFB && DDCclock2 > 0) {
       p = pI830->pScrn_2->modes;
       if (p == NULL)
          return FALSE;
@@ -7484,10 +7505,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
 
    xf86PruneDriverModes(pScrn);
 
-   if (pI830->MergedFB) {
-      DisplayModePtr old_modes;
-      DisplayModePtr cur_mode;
-
+   if (pI830->MergedFB && DDCclock2 > 0) {
       xf86PruneDriverModes(pI830->pScrn_2);
 
       if (pI830->pScrn_2->modes == NULL) {
@@ -7495,6 +7513,10 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
          PreInitCleanup(pScrn);
          return FALSE;
       }
+   }
+
+   if (pI830->MergedFB) {
+      DisplayModePtr old_modes, cur_mode;
 
       old_modes = pScrn->modes;
       cur_mode = pScrn->currentMode;
diff --git a/src/i830_modes.c b/src/i830_modes.c
index 7d71396..7d14519 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -674,23 +674,31 @@ I830GetModePool(ScrnInfoPtr pScrn, vbeIn
 void
 I830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe)
 {
-    DisplayModePtr pMode;
+    I830Ptr pI830 = I830PTR(pScrn);
+    DisplayModePtr pMode = pScrn->modes;
+    DisplayModePtr ppMode = pScrn->modes;
     I830ModePrivatePtr mp = NULL;
 
-    pMode = pScrn->modes;
     do {
 	int clock;
+        
+        mp = (I830ModePrivatePtr) pMode->Private;
 
+        if (pI830->MergedFB) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", pScrn->monitor->id);
+            ppMode = (DisplayModePtr) mp->merged.First;
+            mp = (I830ModePrivatePtr) mp->merged.First->Private;
+        }
 	mp->vbeData.block = xcalloc(sizeof(VbeCRTCInfoBlock), 1);
-	mp->vbeData.block->HorizontalTotal = pMode->HTotal;
-	mp->vbeData.block->HorizontalSyncStart = pMode->HSyncStart;
-	mp->vbeData.block->HorizontalSyncEnd = pMode->HSyncEnd;
-	mp->vbeData.block->VerticalTotal = pMode->VTotal;
-	mp->vbeData.block->VerticalSyncStart = pMode->VSyncStart;
-	mp->vbeData.block->VerticalSyncEnd = pMode->VSyncEnd;
-	mp->vbeData.block->Flags = ((pMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
-				 ((pMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
-	mp->vbeData.block->PixelClock = pMode->Clock * 1000;
+	mp->vbeData.block->HorizontalTotal = ppMode->HTotal;
+	mp->vbeData.block->HorizontalSyncStart = ppMode->HSyncStart;
+	mp->vbeData.block->HorizontalSyncEnd = ppMode->HSyncEnd;
+	mp->vbeData.block->VerticalTotal = ppMode->VTotal;
+	mp->vbeData.block->VerticalSyncStart = ppMode->VSyncStart;
+	mp->vbeData.block->VerticalSyncEnd = ppMode->VSyncEnd;
+	mp->vbeData.block->Flags = ((ppMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
+				 ((ppMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
+	mp->vbeData.block->PixelClock = ppMode->Clock * 1000;
 	/* XXX May not have this. */
 	clock = VBEGetPixelClock(pVbe, mp->vbeData.mode, mp->vbeData.block->PixelClock);
 	if (clock)
@@ -701,26 +709,78 @@ I830SetModeParameters(ScrnInfoPtr pScrn,
 		(double)clock / 1000000.0);
 #endif
 	mp->vbeData.mode |= (1 << 11);
-	if (pMode->VRefresh != 0) {
-	    mp->vbeData.block->RefreshRate = pMode->VRefresh * 100;
+	if (ppMode->VRefresh != 0) {
+	    mp->vbeData.block->RefreshRate = ppMode->VRefresh * 100;
 	} else {
 	    mp->vbeData.block->RefreshRate = (int)(((double)(mp->vbeData.block->PixelClock)/
-                       (double)(pMode->HTotal * pMode->VTotal)) * 100);
+                       (double)(ppMode->HTotal * ppMode->VTotal)) * 100);
 	}
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		       "Attempting to use %2.2fHz refresh for mode \"%s\" (%x)\n",
-		       (float)(((double)(mp->vbeData.block->PixelClock) / (double)(pMode->HTotal * pMode->VTotal))), pMode->name, mp->vbeData.mode);
+		       (float)(((double)(mp->vbeData.block->PixelClock) / (double)(ppMode->HTotal * ppMode->VTotal))), ppMode->name, mp->vbeData.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",
-	       mp->vbeData.mode, pMode->name, pMode->HDisplay, pMode->HSyncStart,
-	       pMode->HSyncEnd, pMode->HTotal, pMode->VDisplay,
-	       pMode->VSyncStart,pMode->VSyncEnd,pMode->VTotal,
+	       mp->vbeData.mode, ppMode->name, ppMode->HDisplay, ppMode->HSyncStart,
+	       ppMode->HSyncEnd, ppMode->HTotal, ppMode->VDisplay,
+	       ppMode->VSyncStart,ppMode->VSyncEnd,ppMode->VTotal,
 	       (double)mp->vbeData.block->PixelClock/1000000.0,
 	       (double)mp->vbeData.block->RefreshRate/100);
 #endif
-	pMode = pMode->next;
+	pMode = ppMode = pMode->next;
     } while (pMode != pScrn->modes);
+
+    if (pI830->MergedFB) {
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", pI830->pScrn_2->monitor->id);
+    pMode = pScrn->modes;
+    	do {
+	    int clock;
+
+            mp = (I830ModePrivatePtr) pMode->Private;
+            ppMode = (DisplayModePtr) mp->merged.Second;
+            mp = (I830ModePrivatePtr) mp->merged.Second->Private;
+
+	    mp->vbeData.block = xcalloc(sizeof(VbeCRTCInfoBlock), 1);
+	    mp->vbeData.block->HorizontalTotal = ppMode->HTotal;
+	    mp->vbeData.block->HorizontalSyncStart = ppMode->HSyncStart;
+	    mp->vbeData.block->HorizontalSyncEnd = ppMode->HSyncEnd;
+	    mp->vbeData.block->VerticalTotal = ppMode->VTotal;
+	    mp->vbeData.block->VerticalSyncStart = ppMode->VSyncStart;
+	    mp->vbeData.block->VerticalSyncEnd = ppMode->VSyncEnd;
+	    mp->vbeData.block->Flags = ((ppMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
+				 ((ppMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
+	    mp->vbeData.block->PixelClock = ppMode->Clock * 1000;
+	    /* XXX May not have this. */
+	    clock = VBEGetPixelClock(pVbe, mp->vbeData.mode, mp->vbeData.block->PixelClock);
+	    if (clock)
+	        mp->vbeData.block->PixelClock = clock;
+#ifdef DEBUG
+	    ErrorF("Setting clock %.2fMHz, closest is %.2fMHz\n",
+		(double)mp->vbeData.block->PixelClock / 1000000.0, 
+		(double)clock / 1000000.0);
+#endif
+	    mp->vbeData.mode |= (1 << 11);
+	    if (ppMode->VRefresh != 0) {
+	        mp->vbeData.block->RefreshRate = ppMode->VRefresh * 100;
+	    } else {
+	        mp->vbeData.block->RefreshRate = (int)(((double)(mp->vbeData.block->PixelClock)/
+                       (double)(ppMode->HTotal * ppMode->VTotal)) * 100);
+	    }
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "Attempting to use %2.2fHz refresh for mode \"%s\" (%x)\n",
+		       (float)(((double)(mp->vbeData.block->PixelClock) / (double)(ppMode->HTotal * ppMode->VTotal))), ppMode->name, mp->vbeData.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",
+	       mp->vbeData.mode, ppMode->name, ppMode->HDisplay, ppMode->HSyncStart,
+	       ppMode->HSyncEnd, ppMode->HTotal, ppMode->VDisplay,
+	       ppMode->VSyncStart,ppMode->VSyncEnd,ppMode->VTotal,
+	       (double)mp->vbeData.block->PixelClock/1000000.0,
+	       (double)mp->vbeData.block->RefreshRate/100);
+#endif
+	    pMode = ppMode = pMode->next;
+        } while (pMode != pScrn->modes);
+    }
 }
 
 void
diff-tree e786e2f9f3a4df31702736db6f68a44c9ebba546 (from 8e6e990db34d63174670512f494fa9adb44786f5)
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Wed Jul 26 16:45:38 2006 +0100

    When detecting new monitors in mergedfb renew the modepool.

diff --git a/src/i830.h b/src/i830.h
index 8a93f78..8b39aa9 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -246,7 +246,7 @@ typedef struct _I830Rec {
    I830MemRange *OverlayMem;
    I830MemRange LinearMem;
 #endif
-   unsigned int LinearAlloc;
+   int LinearAlloc;
 
    Bool MergedFB;
    ScrnInfoPtr pScrn_2;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 4e370b8..eb85131 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -161,6 +161,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #endif
 
 #include <string.h>
+#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 
@@ -1313,14 +1314,6 @@ I830AdjustFrameMerged(int scrnIndex, int
     pScrn1->frameY1   = pScrn1->frameY0   + pI830->currentMode->VDisplay  - 1;
     pScrn1->frameX1 += FirstXOffs + SecondXOffs;
     pScrn1->frameY1 += FirstYOffs + SecondYOffs;
-
-    if (!pI830->pipe == 0) {
-       OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp));
-       OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp));
-    } else {
-       OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp));
-       OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp));
-    }
 }
 
 /* Pseudo-Xinerama extension for MergedFB mode */
@@ -1377,7 +1370,6 @@ I830UpdateXineramaScreenInfo(ScrnInfoPtr
           DisplayModePtr p = currentMode->next;
           DisplayModePtr i = ((I830ModePrivatePtr)currentMode->Private)->merged.First;
           DisplayModePtr j = ((I830ModePrivatePtr)currentMode->Private)->merged.Second;
-          int pos = ((I830ModePrivatePtr)currentMode->Private)->merged.SecondPosition;
 
           if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
 	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
@@ -4125,8 +4117,11 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
    pI830->LinearAlloc = 0;
    if (xf86GetOptValInteger(pI830->Options, OPTION_LINEARALLOC,
 			    &(pI830->LinearAlloc))) {
-      xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Allocating %dKbytes of memory\n",
+      if (pI830->LinearAlloc > 0)
+         xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Allocating %dKbytes of memory\n",
 		 pI830->LinearAlloc);
+      else 
+         pI830->LinearAlloc = 0;
    }
 
    pI830->fixedPipe = -1;
@@ -5115,7 +5110,6 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       } while (p != NULL && p != pScrn->modes);
    }
 
-
    /* Only use this if we've got DDC available */
    if (DDCclock2 > 0) {
       p = pI830->pScrn_2->modes;
@@ -5995,7 +5989,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
    didLock = I830DRILock(pScrn);
 #endif
 
-   if (pI830->Clone || pI830->MergedFB) {
+   if (pI830->Clone) {
       pI830->CloneHDisplay = pMode->HDisplay;
       pI830->CloneVDisplay = pMode->VDisplay;
    }
@@ -6214,15 +6208,21 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
 	    OUTREG(stridereg, pI830->displayWidth * pI830->cpp);
          }
 
-#if 0
 	 if (pI830->MergedFB) {
-            if (i == 0)
-               OUTREG(sizereg, (CDMPTR.First->HDisplay - 1) | ((CDMPTR.First->VDisplay - 1) << 16));
-	    else 
-               OUTREG(sizereg, (CDMPTR.Second->HDisplay - 1) | ((CDMPTR.Second->VDisplay - 1) << 16));
+	    switch (pI830->SecondPosition) {
+	       case PosRightOf:
+	       case PosBelow:
+                  OUTREG(DSPABASE, (CDMPTR.First->HDisplay - 1) | ((CDMPTR.First->VDisplay - 1) << 16));
+                  OUTREG(DSPBBASE, (CDMPTR.Second->HDisplay - 1) | ((CDMPTR.Second->VDisplay - 1) << 16));
+	          break;
+	       case PosLeftOf:
+	       case PosAbove:
+                  OUTREG(DSPABASE, (CDMPTR.Second->HDisplay - 1) | ((CDMPTR.Second->VDisplay - 1) << 16));
+                  OUTREG(DSPBBASE, (CDMPTR.First->HDisplay - 1) | ((CDMPTR.First->VDisplay - 1) << 16));
+	          break;
+	    }
          } else
             OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16));
-#endif
 	 /* Trigger update */
 	 temp = INREG(basereg);
 	 OUTREG(basereg, temp);
@@ -7169,6 +7169,15 @@ I830BIOSAdjustFrame(int scrnIndex, int x
 
    if (pI830->MergedFB) {
       I830AdjustFrameMerged(scrnIndex, x, y, flags);
+
+      if (!pI830->pipe == 0) {
+         OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn->displayWidth + pI830->FirstframeX0) * pI830->cpp));
+         OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->pScrn_2->frameY0 * pScrn->displayWidth + pI830->pScrn_2->frameX0) * pI830->cpp));
+      } else {
+         OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn->displayWidth + pI830->FirstframeX0) * pI830->cpp));
+         OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->pScrn_2->frameY0 * pScrn->displayWidth + pI830->pScrn_2->frameX0) * pI830->cpp));
+      }
+
       return;
    }
 
@@ -7323,7 +7332,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
    pointer pDDCModule = NULL;
    DisplayModePtr p, pMon;
    int memsize;
-   int DDCclock = 0;
+   int DDCclock = 0, DDCclock2 = 0;
    int displayWidth = pScrn->displayWidth;
    int curHDisplay = pScrn->currentMode->HDisplay;
    int curVDisplay = pScrn->currentMode->VDisplay;
@@ -7347,12 +7356,18 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
    if (!(DDCclock = I830UseDDC(pScrn)))
       return FALSE;
 
+   if (pI830->MergedFB)
+      if (!(DDCclock2 = I830UseDDC(pScrn)))
+         return FALSE;
+
    /* Revalidate the modes */
 
    /*
     * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS
     * functions.  
     */
+   SetPipeAccess(pScrn);
+
    pScrn->modePool = I830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo);
 
    if (!pScrn->modePool) {
@@ -7363,8 +7378,24 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
       return FALSE;
    }
 
-   SetPipeAccess(pScrn);
+   if (pI830->MergedFB) {
+      SetBIOSPipe(pScrn, !pI830->pipe);
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		 "Retrieving mode pool for second head.\n");
+      pI830->pScrn_2->modePool = I830GetModePool(pI830->pScrn_2, pI830->pVbe, pI830->vbeInfo);
+
+      if (!pI830->pScrn_2->modePool) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		 "No Video BIOS modes for chosen depth.\n");
+         PreInitCleanup(pScrn);
+         return FALSE;
+      }
+      SetPipeAccess(pScrn);
+   }
+
    VBESetModeNames(pScrn->modePool);
+   if (pI830->MergedFB)
+      VBESetModeNames(pI830->pScrn_2->modePool);
 
    if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64))
       memsize = pI830->vbeInfo->TotalMemory * 64;
@@ -7378,6 +7409,16 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
 			pScrn->display->virtualY,
 			memsize, LOOKUP_BEST_REFRESH);
 
+   if (pI830->MergedFB) {
+      VBEValidateModes(pI830->pScrn_2, pI830->pScrn_2->monitor->Modes, 
+		        pI830->pScrn_2->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)
@@ -7408,9 +7449,70 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
       } while (p != NULL && p != pScrn->modes);
    }
 
+   /* Only use this if we've got DDC available */
+   if (DDCclock2 > 0) {
+      p = pI830->pScrn_2->modes;
+      if (p == NULL)
+         return FALSE;
+      do {
+         int Clock = 100000000; /* incredible value */
+
+	 if (p->status == MODE_OK) {
+            for (pMon = pI830->pScrn_2->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 (Clock != 100000000 && DDCclock2 < 2550 && Clock / 1000.0 > DDCclock2) {
+               ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n",
+		   p->name, pI830->pScrn_2->monitor->id,
+		   Clock/1000.0, DDCclock2);
+               p->status = MODE_BAD;
+            } 
+ 	 }
+         p = p->next;
+      } while (p != NULL && p != pI830->pScrn_2->modes);
+   }
+
    pScrn->displayWidth = displayWidth; /* restore old displayWidth */
 
    xf86PruneDriverModes(pScrn);
+
+   if (pI830->MergedFB) {
+      DisplayModePtr old_modes;
+      DisplayModePtr cur_mode;
+
+      xf86PruneDriverModes(pI830->pScrn_2);
+
+      if (pI830->pScrn_2->modes == NULL) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+         PreInitCleanup(pScrn);
+         return FALSE;
+      }
+
+      old_modes = pScrn->modes;
+      cur_mode = pScrn->currentMode;
+
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
+
+      pScrn->modes = I830GenerateModeList(pScrn, pI830->MetaModes,
+					  old_modes, pI830->pScrn_2->modes,
+					  pI830->SecondPosition);
+
+      if(!pScrn->modes) {
+          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes. Disabling MergedFB.\n");
+	  pScrn->modes = old_modes;
+	  pScrn->currentMode = cur_mode;
+	  pI830->MergedFB = FALSE;
+      }
+   }
+
    I830PrintModes(pScrn);
 
    if (!pI830->vesa->useDefaultRefresh)
@@ -7458,6 +7560,9 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
       }
    }
 
+   if (pI830->MergedFB)
+      I830AdjustFrameMerged(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
    return TRUE;
 }
 
diff --git a/src/i830_modes.c b/src/i830_modes.c
index 383b23c..7d71396 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -675,7 +675,7 @@ void
 I830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe)
 {
     DisplayModePtr pMode;
-    I830ModePrivatePtr mp;
+    I830ModePrivatePtr mp = NULL;
 
     pMode = pScrn->modes;
     do {
diff-tree 8e6e990db34d63174670512f494fa9adb44786f5 (from fd19b12793f09b6714468556ace875ef36ed9e1c)
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Wed Jul 26 10:48:47 2006 +0100

    Update Xvideo to deal with MergedFB modes.

diff --git a/src/i830_driver.c b/src/i830_driver.c
index 784fd23..4e370b8 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -3724,7 +3724,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
    int flags24;
    int defmon = 0;
    int i, n;
-   int DDCclock = 0;
+   int DDCclock = 0, DDCclock2 = 0;
    char *s;
    DisplayModePtr p, pMon;
    xf86MonPtr monitor = NULL;
@@ -4996,6 +4996,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
 
    DDCclock = I830UseDDC(pScrn);
 
+   if (pI830->MergedFB)
+      DDCclock2 = I830UseDDC(pI830->pScrn_2);
+
    /*
     * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS
     * functions. 
@@ -5112,6 +5115,38 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       } while (p != NULL && p != pScrn->modes);
    }
 
+
+   /* Only use this if we've got DDC available */
+   if (DDCclock2 > 0) {
+      p = pI830->pScrn_2->modes;
+      if (p == NULL)
+         return FALSE;
+      do {
+         int Clock = 100000000; /* incredible value */
+
+	 if (p->status == MODE_OK) {
+            for (pMon = pI830->pScrn_2->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 (Clock != 100000000 && DDCclock2 < 2550 && Clock / 1000.0 > DDCclock2) {
+               ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n",
+		   p->name, pI830->pScrn_2->monitor->id,
+		   Clock/1000.0, DDCclock2);
+               p->status = MODE_BAD;
+            } 
+ 	 }
+         p = p->next;
+      } while (p != NULL && p != pI830->pScrn_2->modes);
+   }
+
    xf86PruneDriverModes(pScrn);
 
    if (pScrn->modes == NULL) {
diff --git a/src/i830_video.c b/src/i830_video.c
index a608a7e..762bddf 100644
--- a/src/i830_video.c
+++ b/src/i830_video.c
@@ -1400,6 +1400,7 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int 
    unsigned int swidth;
    unsigned int mask, shift, offsety, offsetu;
    int tmp;
+   BoxRec dstBox2;
 
    ErrorF("I830DisplayVideo: %dx%d (pitch %d)\n", width, height,
 	   dstPitch);
@@ -1411,21 +1412,24 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int 
    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 */
-   if (pI830->entityPrivate)
-      I830ResetVideo(pScrn);
-
-   /* Ensure overlay is turned on with OVERLAY_ENABLE at 0 */
-   if (!*pI830->overlayOn)
-      OVERLAY_UPDATE;
-
    switch (pI830->rotation) {
 	case RR_Rotate_0:
-		dstBox->x1 -= pScrn->frameX0;
-		dstBox->x2 -= pScrn->frameX0;
-		dstBox->y1 -= pScrn->frameY0;
-		dstBox->y2 -= pScrn->frameY0;
+                if (pI830->MergedFB) {
+		   memcpy(&dstBox2, dstBox, sizeof(BoxRec));
+		   dstBox->x1 -= pI830->FirstframeX0;
+		   dstBox->x2 -= pI830->FirstframeX0;
+		   dstBox->y1 -= pI830->FirstframeY0;
+		   dstBox->y2 -= pI830->FirstframeY0;
+		   dstBox2.x1 -= pI830->pScrn_2->frameX0;
+		   dstBox2.x2 -= pI830->pScrn_2->frameX0;
+		   dstBox2.y1 -= pI830->pScrn_2->frameY0;
+		   dstBox2.y2 -= pI830->pScrn_2->frameY0;
+                } else {
+		   dstBox->x1 -= pScrn->frameX0;
+		   dstBox->x2 -= pScrn->frameX0;
+		   dstBox->y1 -= pScrn->frameY0;
+		   dstBox->y2 -= pScrn->frameY0;
+                }
 		break;
 	case RR_Rotate_90:
 		tmp = dstBox->x1;
@@ -1459,6 +1463,72 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int 
 		break;
    }
 
+   if (pI830->MergedFB) {
+      I830ModePrivatePtr mp = (I830ModePrivatePtr)pScrn->currentMode->Private;
+      int w1, h1, w2, h2;
+
+      /* Clip the video to the independent modes of the merged screens */
+      if (dstBox->x1 > mp->merged.First->HDisplay) dstBox->x1 = mp->merged.First->HDisplay - 1;
+      if (dstBox->x2 > mp->merged.First->HDisplay) dstBox->x2 = mp->merged.First->HDisplay - 1;
+      if (dstBox2.x1 > mp->merged.Second->HDisplay) dstBox2.x1 = mp->merged.Second->HDisplay - 1;
+      if (dstBox2.x2 > mp->merged.Second->HDisplay) dstBox2.x2 = mp->merged.Second->HDisplay - 1;
+      if (dstBox->y1 > mp->merged.First->VDisplay) dstBox->y1 = mp->merged.First->VDisplay - 1;
+      if (dstBox->y2 > mp->merged.First->VDisplay) dstBox->y2 = mp->merged.First->VDisplay - 1;
+      if (dstBox2.y1 > mp->merged.Second->VDisplay) dstBox2.y1 = mp->merged.Second->VDisplay - 1;
+      if (dstBox2.y2 > mp->merged.Second->VDisplay) dstBox2.y2 = mp->merged.Second->VDisplay - 1;
+      if (dstBox->y1 < 0) dstBox->y1 = 0;
+      if (dstBox->y2 < 0) dstBox->y2 = 0;
+      if (dstBox->x1 < 0) dstBox->x1 = 0;
+      if (dstBox->x2 < 0) dstBox->x2 = 0;
+      if (dstBox2.y1 < 0) dstBox2.y1 = 0;
+      if (dstBox2.y2 < 0) dstBox2.y2 = 0;
+      if (dstBox2.x1 < 0) dstBox2.x1 = 0;
+      if (dstBox2.x2 < 0) dstBox2.x2 = 0;
+
+      w1 = dstBox->x2 - dstBox->x1;
+      w2 = dstBox2.x2 - dstBox2.x1;
+      h1 = dstBox->y2 - dstBox->y1;
+      h2 = dstBox2.y2 - dstBox2.y1;
+
+      switch (pI830->SecondPosition) {
+         case PosRightOf:
+         case PosBelow:
+            if ((w2 > 0 && w1 == 0) ||
+                (h2 > 0 && h1 == 0)) {
+               pPriv->pipe = pI830->pipe;
+               dstBox->x1 = dstBox2.x1;
+               dstBox->y1 = dstBox2.y1;
+               dstBox->x2 = dstBox2.x2;
+               dstBox->y2 = dstBox2.y2;
+            } else 
+               pPriv->pipe = !pI830->pipe;
+            break;
+         case PosLeftOf:
+         case PosAbove:
+            if ((w1 > 0 && w2 == 0) ||
+                (h1 > 0 && h2 == 0)) { 
+               pPriv->pipe = !pI830->pipe;
+            } else {
+               pPriv->pipe = pI830->pipe;
+               dstBox->x1 = dstBox2.x1;
+               dstBox->y1 = dstBox2.y1;
+               dstBox->x2 = dstBox2.x2;
+               dstBox->y2 = dstBox2.y2;
+            }
+            break;
+      }
+   }
+
+   /* 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.
+    * In MergedFB mode, we may need to flip pipes too. */
+   if (pI830->entityPrivate || pI830->MergedFB)
+      I830ResetVideo(pScrn);
+
+   /* Ensure overlay is turned on with OVERLAY_ENABLE at 0 */
+   if (!*pI830->overlayOn)
+      OVERLAY_UPDATE;
+
    /* Fix up the dstBox if outside the visible screen */
    {
       int offset_x = (dstBox->x1 < 0) ? -dstBox->x1 : 0;
@@ -1522,7 +1592,7 @@ I830DisplayVideo(ScrnInfoPtr pScrn, int 
       /* Keep the engine happy and clip to the real vertical size just
        * in case an LFP is in use and it's not at it's native resolution.
        */
-      int vactive = pI830->pipe ? (INREG(VTOTAL_B) & 0x7FF) : (INREG(VTOTAL_A) & 0x7FF);
+      int vactive = pPriv->pipe ? (INREG(VTOTAL_B) & 0x7FF) : (INREG(VTOTAL_A) & 0x7FF);
 
       vactive += 1;
 
@@ -2553,10 +2623,10 @@ I830VideoSwitchModeAfter(ScrnInfoPtr pSc
    /* 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);
+      size = pPriv->pipe ? INREG(PIPEBSRC) : INREG(PIPEASRC);
       hsize = (size >> 16) & 0x7FF;
       vsize = size & 0x7FF;
-      active = pI830->pipe ? (INREG(VTOTAL_B) & 0x7FF) : (INREG(VTOTAL_A) & 0x7FF);
+      active = pPriv->pipe ? (INREG(VTOTAL_B) & 0x7FF) : (INREG(VTOTAL_A) & 0x7FF);
 
       if (vsize < active && hsize > 1024)
          I830SetOneLineModeRatio(pScrn);
diff-tree fd19b12793f09b6714468556ace875ef36ed9e1c (from 84805167ab8a422966355b9753bfcb4dad802413)
Author: Alan Hourihane <alanh at fairlite.demon.co.uk>
Date:   Tue Jul 25 11:14:11 2006 +0100

    Add mergedfb support to the intel driver with
    additional pseudo-Xinerama support.

diff --git a/src/i830.h b/src/i830.h
index 14e921d..8a93f78 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -56,6 +56,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 #include "xf86xv.h"
 #include "xf86int10.h"
 #include "vbe.h"
+#include "vbeModes.h"
 #include "vgaHW.h"
 #include "randrstr.h"
 
@@ -70,6 +71,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
 #include "common.h"
 
+#define NEED_REPLIES				/* ? */
+#define EXTENSION_PROC_ARGS void *
+#include "extnsionst.h" 			/* required */
+#include <X11/extensions/panoramiXproto.h> 	/* required */
+
 /* I830 Video BIOS support */
 
 /*
@@ -93,7 +99,6 @@ typedef struct _VESARec {
    int statePage, stateSize, stateMode, stateRefresh;
    CARD32 *savedPal;
    int savedScanlinePitch;
-   xf86MonPtr monitor;
    /* Don't try to set the refresh rate for any modes. */
    Bool useDefaultRefresh;
    /* display start */
@@ -155,6 +160,29 @@ typedef struct {
 #endif
 } I830EntRec, *I830EntPtr;
 
+typedef struct _MergedDisplayModeRec {
+    DisplayModePtr First;
+    DisplayModePtr Second;
+    int    SecondPosition;
+} I830MergedDisplayModeRec, *I830MergedDisplayModePtr;
+
+typedef struct _I830XineramaData {
+    int x;
+    int y;
+    int width;
+    int height;
+} I830XineramaData;
+
+typedef struct _ModePrivateRec {
+    I830MergedDisplayModeRec merged;
+    VbeModeInfoData vbeData;
+} I830ModePrivateRec, *I830ModePrivatePtr;
+
+typedef struct _region {
+    int x0,x1,y0,y1;
+} region;
+
+
 typedef struct _I830Rec {
    unsigned char *MMIOBase;
    unsigned char *FbBase;
@@ -219,6 +247,24 @@ typedef struct _I830Rec {
    I830MemRange LinearMem;
 #endif
    unsigned int LinearAlloc;
+
+   Bool MergedFB;
+   ScrnInfoPtr pScrn_2;
+   char	*SecondHSync;
+   char	*SecondVRefresh;
+   char	*MetaModes;
+   int SecondPosition;
+   int FirstXOffs, FirstYOffs, SecondXOffs, SecondYOffs;
+   int FirstframeX0, FirstframeX1, FirstframeY0, FirstframeY1;
+   int MBXNR1XMAX, MBXNR1YMAX, MBXNR2XMAX, MBXNR2YMAX;
+   Bool	NonRect, HaveNonRect, HaveOffsRegions, MouseRestrictions;
+   int maxFirst_X1, maxFirst_X2, maxFirst_Y1, maxFirst_Y2;
+   int maxSecond_X1, maxSecond_X2, maxSecond_Y1, maxSecond_Y2;
+   region NonRectDead, OffDead1, OffDead2;
+   Bool	IntelXinerama;
+   Bool	SecondIsScrn0;
+   ExtensionEntry *XineramaExtEntry;
+   int I830XineramaVX, I830XineramaVY;
   
    XF86ModReqInfo shadowReq; /* to test for later libshadow */
    I830MemRange RotatedMem;
diff --git a/src/i830_cursor.c b/src/i830_cursor.c
index e465b98..3786120 100644
--- a/src/i830_cursor.c
+++ b/src/i830_cursor.c
@@ -93,15 +93,17 @@ I830InitHWCursor(ScrnInfoPtr pScrn)
 		MCURSOR_PIPE_SELECT);
       temp |= CURSOR_MODE_DISABLE;
       temp |= (pI830->pipe << 28);
-      if(pI830->CursorIsARGB)
-         temp |= MCURSOR_GAMMA_ENABLE;
+      if (pI830->CursorIsARGB)
+         temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+      else
+         temp |= CURSOR_MODE_64_4C_AX;
       /* Need to set control, then address. */
       OUTREG(CURSOR_A_CONTROL, temp);
       if (pI830->CursorIsARGB)
          OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
       else
          OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
-      if (pI830->Clone) {
+      if (pI830->Clone || pI830->MergedFB) {
          temp &= ~MCURSOR_PIPE_SELECT;
          temp |= (!pI830->pipe << 28);
          OUTREG(CURSOR_B_CONTROL, temp);
@@ -357,6 +359,102 @@ static void I830LoadCursorARGB (ScrnInfo
 }
 #endif
 
+#define CDMPTR    ((I830ModePrivatePtr)pI830->currentMode->Private)->merged
+
+static void
+I830SetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y)
+{
+   I830Ptr pI830 = I830PTR(pScrn);
+   ScrnInfoPtr    pScrn2 = pI830->pScrn_2;
+   DisplayModePtr mode1 = CDMPTR.First;
+   Bool hide = FALSE, show = FALSE;
+   DisplayModePtr mode2 = CDMPTR.Second;
+   int x1, y1, x2, y2;
+   int total_y1 = pScrn->frameY1 - pScrn->frameY0;
+   int total_y2 = pScrn2->frameY1 - pScrn2->frameY0;
+   CARD32 temp = 0, temp2 = 0;
+
+   x += pScrn->frameX0;
+   y += pScrn->frameY0;
+
+   x1 = x - pI830->FirstframeX0;
+   y1 = y - pI830->FirstframeY0;
+
+   x2 = x - pScrn2->frameX0;
+   y2 = y - pScrn2->frameY0;
+
+   if (y1 > total_y1)
+      y1 = total_y1;
+   if (y2 > total_y2)                  
+      y2 = total_y2;
+
+   /* move cursor offscreen */
+   if (y1 >= 0 && y2 >= mode2->VDisplay) {
+      y2 = -I810_CURSOR_Y;  
+   } else if (y2 >= 0 && y1 >= mode1->VDisplay) {
+      y1 = -I810_CURSOR_Y;  
+   }
+   if (x1 >= 0 && x2 >= mode2->HDisplay) {
+      x2 = -I810_CURSOR_X;  
+   } else if (x2 >= 0 && x1 >= mode1->HDisplay) {
+      x1 = -I810_CURSOR_X;  
+   }
+
+   /* Clamp the cursor position to the visible screen area */
+   if (x1 >= mode1->HDisplay) x1 = mode1->HDisplay - 1;
+   if (y1 >= mode1->VDisplay) y1 = mode1->VDisplay - 1;
+   if (x1 <= -I810_CURSOR_X) x1 = -I810_CURSOR_X + 1;
+   if (y1 <= -I810_CURSOR_Y) y1 = -I810_CURSOR_Y + 1;
+   if (x2 >= mode2->HDisplay) x2 = mode2->HDisplay - 1;
+   if (y2 >= mode2->VDisplay) y2 = mode2->VDisplay - 1;
+   if (x2 <= -I810_CURSOR_X) x2 = -I810_CURSOR_X + 1;
+   if (y2 <= -I810_CURSOR_Y) y2 = -I810_CURSOR_Y + 1;
+
+   if (x1 < 0) {
+      temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+      x1 = -x1;
+   }
+   if (y1 < 0) {
+      temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+      y1 = -y1;
+   }
+   if (x2 < 0) {
+      temp2 |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+      x2 = -x2;
+   }
+   if (y2 < 0) {
+      temp2 |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+      y2 = -y2;
+   }
+
+   temp |= ((x1 & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
+   temp |= ((y1 & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+   temp2 |= ((x2 & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
+   temp2 |= ((y2 & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+
+   OUTREG(CURSOR_A_POSITION, temp2);
+   OUTREG(CURSOR_B_POSITION, temp);
+
+   if (pI830->cursorOn) {
+      if (hide)
+	 pI830->CursorInfoRec->HideCursor(pScrn);
+      else if (show)
+	 pI830->CursorInfoRec->ShowCursor(pScrn);
+      pI830->cursorOn = TRUE;
+   }
+
+   /* have to upload the base for the new position */
+   if (IS_I9XX(pI830)) {
+      if (pI830->CursorIsARGB) {
+         OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
+         OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Physical);
+      } else {
+         OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
+         OUTREG(CURSOR_B_BASE, pI830->CursorMem->Physical);
+      }
+   }
+}
+
 static void
 I830SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
 {
@@ -369,6 +467,11 @@ I830SetCursorPosition(ScrnInfoPtr pScrn,
    static Bool outsideViewport = FALSE;
 #endif
 
+   if (pI830->MergedFB) {
+      I830SetCursorPositionMerged(pScrn, x, y);
+      return;
+   }
+
    oldx += pScrn->frameX0; /* undo what xf86HWCurs did */
    oldy += pScrn->frameY0;
 
@@ -483,9 +586,9 @@ I830ShowCursor(ScrnInfoPtr pScrn)
    pI830->cursorOn = TRUE;
    if (IS_MOBILE(pI830) || IS_I9XX(pI830)) {
       temp = INREG(CURSOR_A_CONTROL);
-      temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
+      temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT | MCURSOR_GAMMA_ENABLE);
       if (pI830->CursorIsARGB)
-         temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+         temp |= CURSOR_MODE_64_ARGB_AX;
       else
          temp |= CURSOR_MODE_64_4C_AX;
       temp |= (pI830->pipe << 28); /* Connect to correct pipe */
@@ -495,7 +598,7 @@ I830ShowCursor(ScrnInfoPtr pScrn)
          OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
       else
          OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
-      if (pI830->Clone) {
+      if (pI830->Clone || pI830->MergedFB) {
          temp &= ~MCURSOR_PIPE_SELECT;
          temp |= (!pI830->pipe << 28);
          OUTREG(CURSOR_B_CONTROL, temp);
@@ -506,7 +609,7 @@ I830ShowCursor(ScrnInfoPtr pScrn)
       }
    } else {
       temp = INREG(CURSOR_CONTROL);
-      temp &= ~(CURSOR_FORMAT_MASK);
+      temp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE);
       temp |= CURSOR_ENABLE;
       if (pI830->CursorIsARGB)
          temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
@@ -539,7 +642,7 @@ I830HideCursor(ScrnInfoPtr pScrn)
          OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
       else
          OUTREG(CURSOR_A_BASE, pI830->CursorMem->Physical);
-      if (pI830->Clone) {
+      if (pI830->Clone || pI830->MergedFB) {
          OUTREG(CURSOR_B_CONTROL, temp);
          if (pI830->CursorIsARGB)
             OUTREG(CURSOR_B_BASE, pI830->CursorMemARGB->Physical);
@@ -570,7 +673,7 @@ I830SetCursorColors(ScrnInfoPtr pScrn, i
    OUTREG(CURSOR_A_PALETTE1, fg & 0x00ffffff);
    OUTREG(CURSOR_A_PALETTE2, fg & 0x00ffffff);
    OUTREG(CURSOR_A_PALETTE3, bg & 0x00ffffff);
-   if (pI830->Clone) {
+   if (pI830->Clone || pI830->MergedFB) {
       OUTREG(CURSOR_B_PALETTE0, bg & 0x00ffffff);
       OUTREG(CURSOR_B_PALETTE1, fg & 0x00ffffff);
       OUTREG(CURSOR_B_PALETTE2, fg & 0x00ffffff);
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 5ce88e1..784fd23 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -178,10 +178,10 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <X11/extensions/randr.h>
 #include "fb.h"
 #include "miscstruct.h"
+#include "dixstruct.h"
 #include "xf86xv.h"
 #include <X11/extensions/Xv.h>
 #include "vbe.h"
-#include "vbeModes.h"
 #include "shadow.h"
 #include "i830.h"
 
@@ -244,7 +244,13 @@ typedef enum {
    OPTION_CHECKDEVICES,
    OPTION_FIXEDPIPE,
    OPTION_ROTATE,
-   OPTION_LINEARALLOC
+   OPTION_LINEARALLOC,
+   OPTION_MERGEDFB,
+   OPTION_METAMODES,
+   OPTION_SECONDHSYNC,
+   OPTION_SECONDVREFRESH,
+   OPTION_SECONDPOSITION,
+   OPTION_INTELXINERAMA
 } I830Opts;
 
 static OptionInfoRec I830BIOSOptions[] = {
@@ -266,6 +272,12 @@ static OptionInfoRec I830BIOSOptions[] =
    {OPTION_FIXEDPIPE,   "FixedPipe",    OPTV_ANYSTR, 	{0},	FALSE},
    {OPTION_ROTATE,      "Rotate",       OPTV_ANYSTR,    {0},    FALSE},
    {OPTION_LINEARALLOC, "LinearAlloc",  OPTV_INTEGER,   {0},    FALSE},
+   {OPTION_MERGEDFB, 	"MergedFB",	OPTV_BOOLEAN,	{0},	FALSE},
+   {OPTION_METAMODES, 	"MetaModes",	OPTV_STRING,	{0},	FALSE},
+   {OPTION_SECONDHSYNC,	"SecondMonitorHorizSync",OPTV_STRING,	{0}, FALSE },
+   {OPTION_SECONDVREFRESH,"SecondMonitorVertRefresh",OPTV_STRING,{0}, FALSE },
+   {OPTION_SECONDPOSITION,"SecondPosition",OPTV_STRING,	{0},	FALSE },
+   {OPTION_INTELXINERAMA,"MergedXinerama",OPTV_BOOLEAN,	{0},	TRUE},
    {-1,			NULL,		OPTV_NONE,	{0},	FALSE}
 };
 /* *INDENT-ON* */
@@ -283,9 +295,24 @@ static Bool SetPipeAccess(ScrnInfoPtr pS
 
 extern int I830EntityIndex;
 
+static Bool 		I830noPanoramiXExtension = TRUE;
+static int		I830XineramaNumScreens = 0;
+static I830XineramaData	*I830XineramadataPtr = NULL;
+static int		I830XineramaGeneration;
+
+static int I830ProcXineramaQueryVersion(ClientPtr client);
+static int I830ProcXineramaGetState(ClientPtr client);
+static int I830ProcXineramaGetScreenCount(ClientPtr client);
+static int I830ProcXineramaGetScreenSize(ClientPtr client);
+static int I830ProcXineramaIsActive(ClientPtr client);
+static int I830ProcXineramaQueryScreens(ClientPtr client);
+static int I830SProcXineramaDispatch(ClientPtr client);
+
 /* temporary */
 extern void xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y);
 
+static const char *SecondMonitorName = "MergedFBMonitor";
+
 
 #ifdef I830DEBUG
 void
@@ -354,11 +381,9 @@ I830BIOSFreeRec(ScrnInfoPtr pScrn)
    if (mode) {
       do {
 	 if (mode->Private) {
-	    VbeModeInfoData *data = (VbeModeInfoData *) mode->Private;
+	    I830ModePrivatePtr mp = (I830ModePrivatePtr) mode->Private;
 
-	    if (data->block)
-	       xfree(data->block);
-	    xfree(data);
+	    xfree(mp);
 	    mode->Private = NULL;
 	 }
 	 mode = mode->next;
@@ -373,8 +398,6 @@ I830BIOSFreeRec(ScrnInfoPtr pScrn)
    }
 
    pVesa = pI830->vesa;
-   if (pVesa->monitor)
-      xfree(pVesa->monitor);
    if (pVesa->savedPal)
       xfree(pVesa->savedPal);
    xfree(pVesa);
@@ -383,6 +406,1613 @@ I830BIOSFreeRec(ScrnInfoPtr pScrn)
    pScrn->driverPrivate = NULL;
 }
 
+static Bool
+InRegion(int x, int y, region r)
+{
+    return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
+}
+
+static int
+I830StrToRanges(range *r, char *s, int max)
+{
+   float num = 0.0;
+   int rangenum = 0;
+   Bool gotdash = FALSE;
+   Bool nextdash = FALSE;
+   char *strnum = NULL;
+   do {
+      switch(*s) {
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case '.':
+         if(strnum == NULL) {
+            strnum = s;
+            gotdash = nextdash;
+            nextdash = FALSE;
+         }
+         break;
+      case '-':
+      case ' ':
+      case 0:
+         if(strnum == NULL) break;
+         sscanf(strnum, "%f", &num);
+	 strnum = NULL;
+         if(gotdash) {
+            r[rangenum - 1].hi = num;
+         } else {
+            r[rangenum].lo = num;
+            r[rangenum].hi = num;
+            rangenum++;
+         }
+         if(*s == '-') nextdash = (rangenum != 0);
+	 else if(rangenum >= max) return rangenum;
+         break;
+      default:
+         return 0;
+      }
+
+   } while(*(s++) != 0);
+
+   return rangenum;
+}
+
+/* Calculate the vertical refresh rate from a mode */
+static float
+I830CalcVRate(DisplayModePtr mode)
+{
+   float hsync, refresh = 0;
+
+   if(mode->HSync > 0.0)
+       	hsync = mode->HSync;
+   else if(mode->HTotal > 0)
+       	hsync = (float)mode->Clock / (float)mode->HTotal;
+   else
+       	hsync = 0.0;
+
+   if(mode->VTotal > 0)
+       	refresh = hsync * 1000.0 / mode->VTotal;
+
+   if(mode->Flags & V_INTERLACE)
+       	refresh *= 2.0;
+
+   if(mode->Flags & V_DBLSCAN)
+       	refresh /= 2.0;
+
+   if(mode->VScan > 1)
+        refresh /= mode->VScan;
+
+   if(mode->VRefresh > 0.0)
+	refresh = mode->VRefresh;
+
+   if(hsync == 0.0 || refresh == 0.0) return 0.0;
+
+   return refresh;
+}
+
+/* Copy and link two modes (i, j) for mergedfb mode
+ * (Code base taken from mga driver)
+ *
+ * - Copy mode i, merge j to copy of i, link the result to dest
+ * - Link i and j in private record.
+ * - If dest is NULL, return value is copy of i linked to itself.
+ * - For mergedfb auto-config, we only check the dimension
+ *   against virtualX/Y, if they were user-provided.
+ * - No special treatment required for CRTxxOffs.
+ * - Provide fake dotclock in order to distinguish between similar
+ *   looking MetaModes (for RandR and VidMode extensions)
+ * - Set unique VRefresh of dest mode for RandR
+ */
+static DisplayModePtr
+I830CopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
+                 DisplayModePtr i, DisplayModePtr j,
+		 int pos)
+{
+    DisplayModePtr mode;
+    int dx = 0,dy = 0;
+
+    if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest;
+    memcpy(mode, i, sizeof(DisplayModeRec));
+    if(!((mode->Private = xalloc(sizeof(I830ModePrivateRec))))) {
+       xfree(mode);
+       return dest;
+    }
+    ((I830ModePrivatePtr)mode->Private)->merged.First = i;
+    ((I830ModePrivatePtr)mode->Private)->merged.Second = j;
+    ((I830ModePrivatePtr)mode->Private)->merged.SecondPosition = pos;
+    if (((I830ModePrivatePtr)i->Private)->vbeData.mode > 0x30) {
+       ((I830ModePrivatePtr)mode->Private)->vbeData.mode = ((I830ModePrivatePtr)i->Private)->vbeData.mode;
+       ((I830ModePrivatePtr)mode->Private)->vbeData.data = ((I830ModePrivatePtr)i->Private)->vbeData.data;
+    } else {
+       ((I830ModePrivatePtr)mode->Private)->vbeData.mode = ((I830ModePrivatePtr)j->Private)->vbeData.mode;
+       ((I830ModePrivatePtr)mode->Private)->vbeData.data = ((I830ModePrivatePtr)j->Private)->vbeData.data;
+    }
+    mode->PrivSize = sizeof(I830ModePrivateRec);
+
+    switch(pos) {
+    case PosLeftOf:
+    case PosRightOf:
+       if(!(pScrn->display->virtualX)) {
+          dx = i->HDisplay + j->HDisplay;
+       } else {
+          dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
+       }
+       dx -= mode->HDisplay;
+       if(!(pScrn->display->virtualY)) {
+          dy = max(i->VDisplay, j->VDisplay);
+       } else {
+          dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
+       }
+       dy -= mode->VDisplay;
+       break;
+    case PosAbove:
+    case PosBelow:
+       if(!(pScrn->display->virtualY)) {
+          dy = i->VDisplay + j->VDisplay;
+       } else {
+          dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
+       }
+       dy -= mode->VDisplay;
+       if(!(pScrn->display->virtualX)) {
+          dx = max(i->HDisplay, j->HDisplay);
+       } else {
+          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
+       }
+       dx -= mode->HDisplay;
+       break;
+    }
+    mode->HDisplay += dx;
+    mode->HSyncStart += dx;
+    mode->HSyncEnd += dx;
+    mode->HTotal += dx;
+    mode->VDisplay += dy;
+    mode->VSyncStart += dy;
+    mode->VSyncEnd += dy;
+    mode->VTotal += dy;
+
+    mode->type = M_T_DEFAULT;
+
+    /* Set up as user defined (ie fake that the mode has been named in the
+     * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+]
+     * when source mode has not been listed there.)
+     */
+    mode->type |= M_T_USERDEF;
+
+    /* Set the VRefresh field (in order to make RandR use it for the rates). We
+     * simply set this to the refresh rate for the First mode (since Second will
+     * mostly be LCD or TV anyway).
+     */
+    mode->VRefresh = I830CalcVRate(i);
+
+    if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > (pScrn->videoRam * 1024)) ||
+	(mode->HDisplay > 4088) ||
+	(mode->VDisplay > 4096) ) {
+
+       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
+		mode->name, mode->HDisplay, mode->VDisplay);
+       xfree(mode->Private);
+       xfree(mode);
+
+       return dest;
+    }
+
+    /* Now see if the resulting mode would be discarded as a "size" by the
+     * RandR extension, and increase its clock by 1000 in case it does.
+     */
+    if(dest) {
+       DisplayModePtr t = dest;
+       do {
+          if((t->HDisplay == mode->HDisplay) &&
+	     (t->VDisplay == mode->VDisplay) &&
+	     ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) {
+	     mode->VRefresh += 1000.0;
+	  }
+	  t = t->next;
+       } while((t) && (t != dest));
+    }
+
+    /* Provide a fake but unique DotClock in order to trick the vidmode
+     * extension to allow selecting among a number of modes whose merged result
+     * looks identical but consists of different modes for First and Second
+     */
+    mode->Clock = (int)(mode->VRefresh * 1000.0);
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)\n",
+	i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
+	mode->HDisplay, mode->VDisplay, (int)mode->VRefresh);
+
+    mode->next = mode;
+    mode->prev = mode;
+
+    if(dest) {
+       mode->next = dest->next; 	/* Insert node after "dest" */
+       dest->next->prev = mode;
+       mode->prev = dest;
+       dest->next = mode;
+    }
+
+    return mode;
+}
+
+/* Helper function to find a mode from a given name
+ * (Code base taken from mga driver)
+ */
+static DisplayModePtr
+I830GetModeFromName(char* str, DisplayModePtr i)
+{
+    DisplayModePtr c = i;
+    if(!i) return NULL;
+    do {
+       if(strcmp(str, c->name) == 0) return c;
+       c = c->next;
+    } while(c != i);
+    return NULL;
+}
+
+static DisplayModePtr
+I830FindWidestTallestMode(DisplayModePtr i, Bool tallest)
+{
+    DisplayModePtr c = i, d = NULL;
+    int max = 0;
+    if(!i) return NULL;
+    do {
+       if(tallest) {
+          if(c->VDisplay > max) {
+	     max = c->VDisplay;
+	     d = c;
+          }
+       } else {
+          if(c->HDisplay > max) {
+	     max = c->HDisplay;
+	     d = c;
+          }
+       }
+       c = c->next;
+    } while(c != i);
+    return d;
+}
+
+static void
+I830FindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
+				DisplayModePtr *a, DisplayModePtr *b)
+{
+    DisplayModePtr c = i, d;
+    int max = 0;
+    Bool foundone;
+
+    (*a) = (*b) = NULL;
+
+    if(!i || !j) return;
+
+    do {
+       d = j;
+       foundone = FALSE;
+       do {
+	  if( (c->HDisplay == d->HDisplay) &&
+	      (c->VDisplay == d->VDisplay) ) {
+	     foundone = TRUE;
+	     break;
+	  }
+	  d = d->next;
+       } while(d != j);
+       if(foundone) {
+	  if(tallest) {
+	     if(c->VDisplay > max) {
+		max = c->VDisplay;
+		(*a) = c;
+		(*b) = d;
+	     }
+	  } else {
+	     if(c->HDisplay > max) {
+		max = c->HDisplay;
+		(*a) = c;
+		(*b) = d;
+	     }
+	  }
+       }
+       c = c->next;
+    } while(c != i);
+}
+
+static DisplayModePtr
+I830GenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
+		    DisplayModePtr i, DisplayModePtr j,
+		    int pos)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    DisplayModePtr mode1 = NULL;
+    DisplayModePtr mode2 = NULL;
+    DisplayModePtr mode3 = NULL;
+    DisplayModePtr mode4 = NULL;
+    DisplayModePtr result = NULL;
+
+    /* Now build a default list of MetaModes.
+     * - Non-clone: If the user enabled NonRectangular, we use the
+     * largest mode for each First and Second. If not, we use the largest
+     * common mode for First and Second (if available). Additionally, and
+     * regardless if the above, we produce a clone mode consisting of
+     * the largest common mode (if available) in order to use DGA.
+     * - Clone: If the (global) SecondPosition is Clone, we use the
+     * largest common mode if available, otherwise the first two modes
+     * in each list.
+     */
+
+    switch(pos) {
+    case PosLeftOf:
+    case PosRightOf:
+       mode1 = I830FindWidestTallestMode(i, FALSE);
+       mode2 = I830FindWidestTallestMode(j, FALSE);
+       I830FindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
+       break;
+    case PosAbove:
+    case PosBelow:
+       mode1 = I830FindWidestTallestMode(i, TRUE);
+       mode2 = I830FindWidestTallestMode(j, TRUE);
+       I830FindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
+       break;
+    }
+
+    if(mode3 && mode4 && !pI830->NonRect) {
+       mode1 = mode3;
+       mode2 = mode2;
+    }
+
+    if(mode1 && mode2) {
+       result = I830CopyModeNLink(pScrn, result, mode1, mode2, pos);
+    }
+
+    return result;
+}
+
+/* Generate the merged-fb mode modelist
+ * (Taken from mga driver)
+ */
+static DisplayModePtr
+I830GenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
+		    DisplayModePtr i, DisplayModePtr j,
+		    int pos)
+{
+    char* strmode = str;
+    char modename[256];
+    Bool gotdash = FALSE;
+    char gotsep = 0;
+    int p; 
+    DisplayModePtr mode1 = NULL;
+    DisplayModePtr mode2 = NULL;
+    DisplayModePtr result = NULL;
+    int myslen;
+
+    do {
+        switch(*str) {
+        case 0:
+        case '-':
+	case '+':
+        case ' ':
+	case ',':
+	case ';':
+           if(strmode != str) {
+
+              myslen = str - strmode;
+              if(myslen > 255) myslen = 255;
+  	      strncpy(modename, strmode, myslen);
+  	      modename[myslen] = 0;
+
+              if(gotdash) {
+                 if(mode1 == NULL) {
+  	             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+  	                        "Error parsing MetaModes parameter\n");
+  	             return NULL;
+  	         }
+                 mode2 = I830GetModeFromName(modename, j);
+                 if(!mode2) {
+                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                        "Mode \"%s\" is not a supported mode for Second\n", modename);
+                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                        "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
+                    mode1 = NULL;
+		    gotsep = 0;
+                 }
+              } else {
+                 mode1 = I830GetModeFromName(modename, i);
+                 if(!mode1) {
+                    char* tmps = str;
+                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                        "Mode \"%s\" is not a supported mode for First\n", modename);
+                    while(*tmps == ' ' || *tmps == ';') tmps++;
+                    /* skip the next mode */
+  	            if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
+                       tmps++;
+		       /* skip spaces */
+		       while(*tmps == ' ' || *tmps == ';') tmps++;
+		       /* skip modename */
+		       while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
+  	               myslen = tmps - strmode;
+  	               if(myslen > 255) myslen = 255;
+  	               strncpy(modename,strmode,myslen);
+  	               modename[myslen] = 0;
+                       str = tmps - 1;
+                    }
+                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                        "\t(Skipping metamode \"%s\")\n", modename);
+                    mode1 = NULL;
+		    gotsep = 0;
+                 }
+              }
+              gotdash = FALSE;
+           }
+           strmode = str + 1;
+           gotdash |= (*str == '-' || *str == '+' || *str == ',');
+	   if (*str == '-' || *str == '+' || *str == ',')
+  	      gotsep = *str;
+
+           if(*str != 0) break;
+	   /* Fall through otherwise */
+
+        default:
+           if(!gotdash && mode1) {
+              p = pos ;
+              if(!mode2) {
+                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                     "Mode \"%s\" is not a supported mode for Second\n", mode1->name);
+                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                     "\t(Skipping metamode \"%s\")\n", modename);
+                 mode1 = NULL;
+              } else {
+                 result = I830CopyModeNLink(pScrn, result, mode1, mode2, p);
+                 mode1 = NULL;
+                 mode2 = NULL;
+              }
+	      gotsep = 0;
+           }
+           break;
+
+        }
+
+    } while(*(str++) != 0);
+     
+    return result;
+}
+
+static DisplayModePtr
+I830GenerateModeList(ScrnInfoPtr pScrn, char* str,
+		    DisplayModePtr i, DisplayModePtr j,
+		    int pos)
+{
+   I830Ptr pI830 = I830PTR(pScrn);
+
+   if(str != NULL) {
+      return(I830GenerateModeListFromMetaModes(pScrn, str, i, j, pos));
+   } else {
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	"No MetaModes given, linking %s modes by default\n",
+	   (pI830->NonRect ?
+		(((pos == PosLeftOf) || (pos == PosRightOf)) ? "widest" :  "tallest")
+		:
+		(((pos == PosLeftOf) || (pos == PosRightOf)) ? "widest common" :  "tallest common")) );
+      return(I830GenerateModeListFromLargestModes(pScrn, i, j, pos));
+   }
+}
+
+static void
+I830RecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    DisplayModePtr mode, bmode;
+    int maxh, maxv;
+    static const char *str = "MergedFB: Virtual %s %d\n";
+    static const char *errstr = "Virtual %s to small for given SecondPosition offset\n";
+
+    mode = bmode = pScrn->modes;
+    maxh = maxv = 0;
+    do {
+       if(mode->HDisplay > maxh) maxh = mode->HDisplay;
+       if(mode->VDisplay > maxv) maxv = mode->VDisplay;
+       mode = mode->next;
+    } while(mode != bmode);
+
+    maxh += pI830->FirstXOffs + pI830->SecondXOffs;
+    maxv += pI830->FirstYOffs + pI830->SecondYOffs;
+
+    if(!(pScrn->display->virtualX)) {
+       if(maxh > 4088) {
+	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		"Virtual width with SecondPosition offset beyond hardware specs\n");
+	  pI830->FirstXOffs = pI830->SecondXOffs = 0;
+	  maxh -= (pI830->FirstXOffs + pI830->SecondXOffs);
+       }
+       pScrn->virtualX = maxh;
+       pScrn->displayWidth = maxh;
+       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
+    } else {
+       if(maxh < pScrn->display->virtualX) {
+	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
+	  pI830->FirstXOffs = pI830->SecondXOffs = 0;
+       }
+    }
+
+    if(!(pScrn->display->virtualY)) {
+       pScrn->virtualY = maxv;
+       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
+    } else {
+       if(maxv < pScrn->display->virtualY) {
+	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
+	  pI830->FirstYOffs = pI830->SecondYOffs = 0;
+       }
+    }
+}
+
+#define SDMPTR(x) ((I830ModePrivatePtr)x->currentMode->Private)->merged
+#define CDMPTR    ((I830ModePrivatePtr)pI830->currentMode->Private)->merged
+
+#define BOUND(test,low,hi) 			\
+    {						\
+	if((test) < (low)) (test) = (low);	\
+	if((test) > (hi))  (test) = (hi);	\
+    }
+
+#define REBOUND(low,hi,test)		\
+    {					\
+	if((test) < (low)) {		\
+		(hi) += (test)-(low);	\
+		(low) = (test); 	\
+	}				\
+	if((test) > (hi)) {		\
+		(low) += (test)-(hi);	\
+		(hi) = (test); 		\
+	}				\
+    }
+
+
+static void
+I830MergedPointerMoved(int scrnIndex, int x, int y)
+{
+  ScrnInfoPtr	pScrn1 = xf86Screens[scrnIndex];
+  I830Ptr	pI830 = I830PTR(pScrn1);
+  ScrnInfoPtr	pScrn2 = pI830->pScrn_2;
+  region	out, in1, in2, f2, f1;
+  int		deltax, deltay;
+  int		temp1, temp2;
+  int		old1x0, old1y0, old2x0, old2y0;
+  int		FirstXOffs = 0, FirstYOffs = 0, SecondXOffs = 0, SecondYOffs = 0;
+  int		HVirt = pScrn1->virtualX;
+  int		VVirt = pScrn1->virtualY;
+  int		sigstate;
+  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
+  int           pos = ((I830MergedDisplayModePtr)pI830->currentMode->Private)->SecondPosition;
+
+  if(pI830->DGAactive) {
+     return;
+     /* DGA: There is no cursor and no panning while DGA is active. */
+  } else {
+     FirstXOffs = pI830->FirstXOffs;
+     FirstYOffs = pI830->FirstYOffs;
+     SecondXOffs = pI830->SecondXOffs;
+     SecondYOffs = pI830->SecondYOffs;
+     HaveNonRect = pI830->HaveNonRect;
+     HaveOffsRegions = pI830->HaveOffsRegions;
+  }
+
+  /* Check if the pointer is inside our dead areas */
+  if((pI830->MouseRestrictions) && !I830noPanoramiXExtension) {
+     if(HaveNonRect) {
+	if(InRegion(x, y, pI830->NonRectDead)) {
+	   switch(pos) {
+	   case PosLeftOf:
+	   case PosRightOf: y = pI830->NonRectDead.y0 - 1;
+			    doit = TRUE;
+			    break;
+	   case PosAbove:
+	   case PosBelow:   x = pI830->NonRectDead.x0 - 1;
+			    doit = TRUE;
+	   default:	    break;
+	   }
+	}
+     }
+     if(HaveOffsRegions) {
+	if(InRegion(x, y, pI830->OffDead1)) {
+	   switch(pos) {
+	   case PosLeftOf:
+	   case PosRightOf: y = pI830->OffDead1.y1;
+			    doit = TRUE;
+			    break;
+	   case PosAbove:
+	   case PosBelow:   x = pI830->OffDead1.x1;
+			    doit = TRUE;
+	   default:	    break;
+	   }
+	} else if(InRegion(x, y, pI830->OffDead2)) {
+	   switch(pos) {
+	   case PosLeftOf:
+	   case PosRightOf: y = pI830->OffDead2.y0 - 1;
+			    doit = TRUE;
+			    break;
+	   case PosAbove:
+	   case PosBelow:   x = pI830->OffDead2.x0 - 1;
+			    doit = TRUE;
+	   default:	    break;
+	   }
+	}
+     }
+     if(doit) {
+	UpdateCurrentTime();
+	sigstate = xf86BlockSIGIO();
+	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
+	xf86UnblockSIGIO(sigstate);
+	return;
+     }
+  }
+
+  f1.x0 = old1x0 = pI830->FirstframeX0;
+  f1.x1 = pI830->FirstframeX1;
+  f1.y0 = old1y0 = pI830->FirstframeY0;
+  f1.y1 = pI830->FirstframeY1;
+  f2.x0 = old2x0 = pScrn2->frameX0;
+  f2.x1 = pScrn2->frameX1;
+  f2.y0 = old2y0 = pScrn2->frameY0;
+  f2.y1 = pScrn2->frameY1;
+
+  /* Define the outer region. Crossing this causes all frames to move */
+  out.x0 = pScrn1->frameX0;
+  out.x1 = pScrn1->frameX1;
+  out.y0 = pScrn1->frameY0;
+  out.y1 = pScrn1->frameY1;
+
+  /*
+   * Define the inner sliding window. Being outsize both frames but
+   * inside the outer clipping window will slide corresponding frame
+   */
+  in1 = out;
+  in2 = out;
+  switch(pos) {
+     case PosLeftOf:
+        in1.x0 = f1.x0;
+        in2.x1 = f2.x1;
+        break;
+     case PosRightOf:
+        in1.x1 = f1.x1;
+        in2.x0 = f2.x0;
+        break;
+     case PosBelow:
+        in1.y1 = f1.y1;
+        in2.y0 = f2.y0;
+        break;
+     case PosAbove:
+        in1.y0 = f1.y0;
+        in2.y1 = f2.y1;
+        break;
+  }
+
+  deltay = 0;
+  deltax = 0;
+
+  if(InRegion(x, y, out)) {	/* inside outer region */
+
+     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
+	REBOUND(f1.x0, f1.x1, x);
+	REBOUND(f1.y0, f1.y1, y);
+	deltax = 1;
+     }
+     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
+	REBOUND(f2.x0, f2.x1, x);
+	REBOUND(f2.y0, f2.y1, y);
+	deltax = 1;
+     }
+
+  } else {			/* outside outer region */
+
+     if(out.x0 > x) {
+	deltax = x - out.x0;
+     }
+     if(out.x1 < x) {
+	deltax = x - out.x1;
+     }
+     if(deltax) {
+	pScrn1->frameX0 += deltax;
+	pScrn1->frameX1 += deltax;
+	f1.x0 += deltax;
+	f1.x1 += deltax;
+	f2.x0 += deltax;
+	f2.x1 += deltax;
+     }
+
+     if(out.y0 > y) {
+	deltay = y - out.y0;
+     }
+     if(out.y1 < y) {
+	deltay = y - out.y1;
+     }
+     if(deltay) {
+	pScrn1->frameY0 += deltay;
+	pScrn1->frameY1 += deltay;
+	f1.y0 += deltay;
+	f1.y1 += deltay;
+	f2.y0 += deltay;
+	f2.y1 += deltay;
+     }
+
+     switch(pos) {
+	case PosLeftOf:
+	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
+	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
+	   break;
+	case PosRightOf:
+	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
+	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
+	   break;
+	case PosBelow:
+	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
+	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
+	   break;
+	case PosAbove:
+	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
+	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
+	   break;
+     }
+
+  }
+
+  if(deltax || deltay) {
+     pI830->FirstframeX0 = f1.x0;
+     pI830->FirstframeY0 = f1.y0;
+     pScrn2->frameX0 = f2.x0;
+     pScrn2->frameY0 = f2.y0;
+
+     switch(pos) {
+	case PosLeftOf:
+	case PosRightOf:
+	   if(FirstYOffs || SecondYOffs || HaveNonRect) {
+	      if(pI830->FirstframeY0 != old1y0) {
+	         if(pI830->FirstframeY0 < FirstYOffs)
+	            pI830->FirstframeY0 = FirstYOffs;
+
+	         temp1 = pI830->FirstframeY0 + CDMPTR.First->VDisplay;
+	         temp2 = min((VVirt - SecondYOffs), (FirstYOffs + pI830->MBXNR1YMAX));
+	         if(temp1 > temp2)
+	            pI830->FirstframeY0 -= (temp1 - temp2);
+	      }
+	      if(pScrn2->frameY0 != old2y0) {
+	         if(pScrn2->frameY0 < SecondYOffs)
+	            pScrn2->frameY0 = SecondYOffs;
+
+	         temp1 = pScrn2->frameY0 + CDMPTR.Second->VDisplay;
+	         temp2 = min((VVirt - FirstYOffs), (SecondYOffs + pI830->MBXNR2YMAX));
+	         if(temp1 > temp2)
+	            pScrn2->frameY0 -= (temp1 - temp2);
+	      }
+	   }
+	   break;
+	case PosBelow:
+	case PosAbove:
+	   if(FirstXOffs || SecondXOffs || HaveNonRect) {
+	      if(pI830->FirstframeX0 != old1x0) {
+	         if(pI830->FirstframeX0 < FirstXOffs)
+	            pI830->FirstframeX0 = FirstXOffs;
+
+	         temp1 = pI830->FirstframeX0 + CDMPTR.First->HDisplay;
+	         temp2 = min((HVirt - SecondXOffs), (FirstXOffs + pI830->MBXNR1XMAX));
+	         if(temp1 > temp2)
+	            pI830->FirstframeX0 -= (temp1 - temp2);
+	      }
+	      if(pScrn2->frameX0 != old2x0) {
+	         if(pScrn2->frameX0 < SecondXOffs)
+	            pScrn2->frameX0 = SecondXOffs;
+
+	         temp1 = pScrn2->frameX0 + CDMPTR.Second->HDisplay;
+	         temp2 = min((HVirt - FirstXOffs), (SecondXOffs + pI830->MBXNR2XMAX));
+	         if(temp1 > temp2)
+	            pScrn2->frameX0 -= (temp1 - temp2);
+	      }
+	   }
+	   break;
+     }
+
+     pI830->FirstframeX1 = pI830->FirstframeX0 + CDMPTR.First->HDisplay - 1;
+     pI830->FirstframeY1 = pI830->FirstframeY0 + CDMPTR.First->VDisplay - 1;
+     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR.Second->HDisplay - 1;
+     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR.Second->VDisplay - 1;
+
+     /* No need to update pScrn1->frame?1, done above */
+    if (!pI830->pipe == 0) {
+       OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp));
+       OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp));
+    } else {
+       OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp));
+       OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp));
+    }
+  }
+}
+
+static void
+I830AdjustFrameMerged(int scrnIndex, int x, int y, int flags)
+{
+    ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
+    I830Ptr pI830 = I830PTR(pScrn1);
+    ScrnInfoPtr pScrn2 = pI830->pScrn_2;
+    int HTotal = pI830->currentMode->HDisplay;
+    int VTotal = pI830->currentMode->VDisplay;
+    int HMax = HTotal;
+    int VMax = VTotal;
+    int HVirt = pScrn1->virtualX;
+    int VVirt = pScrn1->virtualY;
+    int x1 = x, x2 = x;
+    int y1 = y, y2 = y;
+    int FirstXOffs = 0, FirstYOffs = 0, SecondXOffs = 0, SecondYOffs = 0;
+    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
+
+    if(pI830->DGAactive) {
+       HVirt = pScrn1->displayWidth;
+       VVirt = pScrn1->virtualY;
+    } else {
+       FirstXOffs = pI830->FirstXOffs;
+       FirstYOffs = pI830->FirstYOffs;
+       SecondXOffs = pI830->SecondXOffs;
+       SecondYOffs = pI830->SecondYOffs;
+       MBXNR1XMAX = pI830->MBXNR1XMAX;
+       MBXNR1YMAX = pI830->MBXNR1YMAX;
+       MBXNR2XMAX = pI830->MBXNR2XMAX;
+       MBXNR2YMAX = pI830->MBXNR2YMAX;
+    }
+
+    BOUND(x, 0, HVirt - HTotal);
+    BOUND(y, 0, VVirt - VTotal);
+    BOUND(x1, FirstXOffs, min(HVirt, MBXNR1XMAX + FirstXOffs) - min(HTotal, MBXNR1XMAX) - SecondXOffs);
+    BOUND(y1, FirstYOffs, min(VVirt, MBXNR1YMAX + FirstYOffs) - min(VTotal, MBXNR1YMAX) - SecondYOffs);
+    BOUND(x2, SecondXOffs, min(HVirt, MBXNR2XMAX + SecondXOffs) - min(HTotal, MBXNR2XMAX) - FirstXOffs);
+    BOUND(y2, SecondYOffs, min(VVirt, MBXNR2YMAX + SecondYOffs) - min(VTotal, MBXNR2YMAX) - FirstYOffs);
+
+    switch(SDMPTR(pScrn1).SecondPosition) {
+        case PosLeftOf:
+            pScrn2->frameX0 = x2;
+            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR.Second->VDisplay);
+            pI830->FirstframeX0 = x1 + CDMPTR.Second->HDisplay;
+            BOUND(pI830->FirstframeY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR.First->VDisplay);
+            break;
+        case PosRightOf:
+            pI830->FirstframeX0 = x1;
+            BOUND(pI830->FirstframeY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR.First->VDisplay);
+            pScrn2->frameX0 = x2 + CDMPTR.First->HDisplay;
+            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR.Second->VDisplay);
+            break;
+        case PosAbove:
+            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR.Second->HDisplay);
+            pScrn2->frameY0 = y2;
+            BOUND(pI830->FirstframeX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR.First->HDisplay);
+            pI830->FirstframeY0 = y1 + CDMPTR.Second->VDisplay;
+            break;
+        case PosBelow:
+            BOUND(pI830->FirstframeX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR.First->HDisplay);
+            pI830->FirstframeY0 = y1;
+            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR.Second->HDisplay);
+            pScrn2->frameY0 = y2 + CDMPTR.First->VDisplay;
+            break;
+    }
+
+    BOUND(pI830->FirstframeX0, 0, HVirt - CDMPTR.First->HDisplay);
+    BOUND(pI830->FirstframeY0, 0, VVirt - CDMPTR.First->VDisplay);
+    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR.Second->HDisplay);
+    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR.Second->VDisplay);
+
+    pScrn1->frameX0 = x;
+    pScrn1->frameY0 = y;
+
+    pI830->FirstframeX1 = pI830->FirstframeX0 + CDMPTR.First->HDisplay - 1;
+    pI830->FirstframeY1 = pI830->FirstframeY0 + CDMPTR.First->VDisplay - 1;
+    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR.Second->HDisplay - 1;
+    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR.Second->VDisplay - 1;
+
+    pScrn1->frameX1   = pScrn1->frameX0   + pI830->currentMode->HDisplay  - 1;
+    pScrn1->frameY1   = pScrn1->frameY0   + pI830->currentMode->VDisplay  - 1;
+    pScrn1->frameX1 += FirstXOffs + SecondXOffs;
+    pScrn1->frameY1 += FirstYOffs + SecondYOffs;
+
+    if (!pI830->pipe == 0) {
+       OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp));
+       OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp));
+    } else {
+       OUTREG(DSPBBASE, pI830->FrontBuffer.Start + ((pI830->FirstframeY0 * pScrn1->displayWidth + pI830->FirstframeX0) * pI830->cpp));
+       OUTREG(DSPABASE, pI830->FrontBuffer.Start + ((pScrn2->frameY0 * pScrn1->displayWidth + pScrn2->frameX0) * pI830->cpp));
+    }
+}
+
+/* Pseudo-Xinerama extension for MergedFB mode */
+static void
+I830UpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
+{
+    I830Ptr pI830 = I830PTR(pScrn1);
+    int scrnnum1 = 0, scrnnum2 = 1;
+    int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
+    int realvirtX, realvirtY;
+    DisplayModePtr currentMode, firstMode;
+    Bool infochanged = FALSE;
+    Bool usenonrect = pI830->NonRect;
+    const char *rectxine = "\t... setting up rectangular Xinerama layout\n";
+
+    pI830->MBXNR1XMAX = pI830->MBXNR1YMAX = pI830->MBXNR2XMAX = pI830->MBXNR2YMAX = 65536;
+    pI830->HaveNonRect = pI830->HaveOffsRegions = FALSE;
+
+    if(!pI830->MergedFB) return;
+
+    if(I830noPanoramiXExtension) return;
+
+    if(!I830XineramadataPtr) return;
+
+    if(pI830->SecondIsScrn0) {
+       scrnnum1 = 1;
+       scrnnum2 = 0;
+    }
+
+    /* Attention: Usage of RandR may lead to virtual X and Y dimensions
+     * actually smaller than our MetaModes. To avoid this, we calculate
+     * the max* fields here (and not somewhere else, like in CopyNLink)
+     *
+     * *** Note: RandR is disabled if one of CRTxxOffs is non-zero.
+     */
+
+    /* "Real" virtual: Virtual without the Offset */
+    realvirtX = pScrn1->virtualX - pI830->FirstXOffs - pI830->SecondXOffs;
+    realvirtY = pScrn1->virtualY - pI830->FirstYOffs - pI830->SecondYOffs;
+
+    if((pI830->I830XineramaVX != pScrn1->virtualX) || (pI830->I830XineramaVY != pScrn1->virtualY)) {
+
+       if(!(pScrn1->modes)) return;
+
+       pI830->maxFirst_X1 = pI830->maxFirst_X2 = 0;
+       pI830->maxFirst_Y1 = pI830->maxFirst_Y2 = 0;
+       pI830->maxSecond_X1 = pI830->maxSecond_X2 = 0;
+       pI830->maxSecond_Y1 = pI830->maxSecond_Y2 = 0;
+
+       currentMode = firstMode = pScrn1->modes;
+
+       do {
+
+          DisplayModePtr p = currentMode->next;
+          DisplayModePtr i = ((I830ModePrivatePtr)currentMode->Private)->merged.First;
+          DisplayModePtr j = ((I830ModePrivatePtr)currentMode->Private)->merged.Second;
+          int pos = ((I830ModePrivatePtr)currentMode->Private)->merged.SecondPosition;
+
+          if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
+	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
+	     (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
+
+		if(pI830->maxFirst_X1 == i->HDisplay) {
+		   if(pI830->maxFirst_X2 < j->HDisplay) {
+		      pI830->maxFirst_X2 = j->HDisplay;   /* Widest Second mode displayed with widest CRT1 mode */
+		   }
+		} else if(pI830->maxFirst_X1 < i->HDisplay) {
+		   pI830->maxFirst_X1 = i->HDisplay;      /* Widest CRT1 mode */
+		   pI830->maxFirst_X2 = j->HDisplay;
+		}
+		if(pI830->maxSecond_X2 == j->HDisplay) {
+		   if(pI830->maxSecond_X1 < i->HDisplay) {
+		      pI830->maxSecond_X1 = i->HDisplay;   /* Widest First mode displayed with widest Second mode */
+		   }
+		} else if(pI830->maxSecond_X2 < j->HDisplay) {
+		   pI830->maxSecond_X2 = j->HDisplay;      /* Widest Second mode */
+		   pI830->maxSecond_X1 = i->HDisplay;
+		}
+		if(pI830->maxFirst_Y1 == i->VDisplay) {   /* Same as above, but tallest instead of widest */
+		   if(pI830->maxFirst_Y2 < j->VDisplay) {
+		      pI830->maxFirst_Y2 = j->VDisplay;
+		   }
+		} else if(pI830->maxFirst_Y1 < i->VDisplay) {
+		   pI830->maxFirst_Y1 = i->VDisplay;
+		   pI830->maxFirst_Y2 = j->VDisplay;
+		}
+		if(pI830->maxSecond_Y2 == j->VDisplay) {
+		   if(pI830->maxSecond_Y1 < i->VDisplay) {
+		      pI830->maxSecond_Y1 = i->VDisplay;
+		   }
+		} else if(pI830->maxSecond_Y2 < j->VDisplay) {
+		   pI830->maxSecond_Y2 = j->VDisplay;
+		   pI830->maxSecond_Y1 = i->VDisplay;
+		}
+	  }
+	  currentMode = p;
+
+       } while((currentMode) && (currentMode != firstMode));
+
+       pI830->I830XineramaVX = pScrn1->virtualX;
+       pI830->I830XineramaVY = pScrn1->virtualY;
+       infochanged = TRUE;
+
+    }
+
+    if((usenonrect) && pI830->maxFirst_X1) {
+       switch(pI830->SecondPosition) {
+       case PosLeftOf:
+       case PosRightOf:
+	  if((pI830->maxFirst_Y1 != realvirtY) && (pI830->maxSecond_Y2 != realvirtY)) {
+	     usenonrect = FALSE;
+	  }
+	  break;
+       case PosAbove:
+       case PosBelow:
+	  if((pI830->maxFirst_X1 != realvirtX) && (pI830->maxSecond_X2 != realvirtX)) {
+	     usenonrect = FALSE;
+	  }
+	  break;
+       }
+       if(infochanged && !usenonrect) {
+	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+			"Virtual screen size does not match maximum display modes...\n");
+	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
+
+       }
+    } else if(infochanged && usenonrect) {
+       usenonrect = FALSE;
+       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+		"Only clone modes available for this virtual screen size...\n");
+       xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
+    }
+
+    if(pI830->maxFirst_X1) {		/* Means we have at least one non-clone mode */
+       switch(pI830->SecondPosition) {
+       case PosLeftOf:
+	  x1 = min(pI830->maxFirst_X2, pScrn1->virtualX - pI830->maxFirst_X1);
+	  if(x1 < 0) x1 = 0;
+	  y1 = pI830->FirstYOffs;
+	  w1 = pScrn1->virtualX - x1;
+	  h1 = realvirtY;
+	  if((usenonrect) && (pI830->maxFirst_Y1 != realvirtY)) {
+	     h1 = pI830->MBXNR1YMAX = pI830->maxFirst_Y1;
+	     pI830->NonRectDead.x0 = x1;
+	     pI830->NonRectDead.x1 = x1 + w1 - 1;
+	     pI830->NonRectDead.y0 = y1 + h1;
+	     pI830->NonRectDead.y1 = pScrn1->virtualY - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+	  x2 = 0;
+	  y2 = pI830->SecondYOffs;
+	  w2 = max(pI830->maxSecond_X2, pScrn1->virtualX - pI830->maxSecond_X1);
+	  if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
+	  h2 = realvirtY;
+	  if((usenonrect) && (pI830->maxSecond_Y2 != realvirtY)) {
+	     h2 = pI830->MBXNR2YMAX = pI830->maxSecond_Y2;
+	     pI830->NonRectDead.x0 = x2;
+	     pI830->NonRectDead.x1 = x2 + w2 - 1;
+	     pI830->NonRectDead.y0 = y2 + h2;
+	     pI830->NonRectDead.y1 = pScrn1->virtualY - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+	  break;
+       case PosRightOf:
+	  x1 = 0;
+	  y1 = pI830->FirstYOffs;
+	  w1 = max(pI830->maxFirst_X1, pScrn1->virtualX - pI830->maxFirst_X2);
+	  if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
+	  h1 = realvirtY;
+	  if((usenonrect) && (pI830->maxFirst_Y1 != realvirtY)) {
+	     h1 = pI830->MBXNR1YMAX = pI830->maxFirst_Y1;
+	     pI830->NonRectDead.x0 = x1;
+	     pI830->NonRectDead.x1 = x1 + w1 - 1;
+	     pI830->NonRectDead.y0 = y1 + h1;
+	     pI830->NonRectDead.y1 = pScrn1->virtualY - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+	  x2 = min(pI830->maxSecond_X1, pScrn1->virtualX - pI830->maxSecond_X2);
+	  if(x2 < 0) x2 = 0;
+	  y2 = pI830->SecondYOffs;
+	  w2 = pScrn1->virtualX - x2;
+	  h2 = realvirtY;
+	  if((usenonrect) && (pI830->maxSecond_Y2 != realvirtY)) {
+	     h2 = pI830->MBXNR2YMAX = pI830->maxSecond_Y2;
+	     pI830->NonRectDead.x0 = x2;
+	     pI830->NonRectDead.x1 = x2 + w2 - 1;
+	     pI830->NonRectDead.y0 = y2 + h2;
+	     pI830->NonRectDead.y1 = pScrn1->virtualY - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+	  break;
+       case PosAbove:
+	  x1 = pI830->FirstXOffs;
+	  y1 = min(pI830->maxFirst_Y2, pScrn1->virtualY - pI830->maxFirst_Y1);
+	  if(y1 < 0) y1 = 0;
+	  w1 = realvirtX;
+	  h1 = pScrn1->virtualY - y1;
+	  if((usenonrect) && (pI830->maxFirst_X1 != realvirtX)) {
+	     w1 = pI830->MBXNR1XMAX = pI830->maxFirst_X1;
+	     pI830->NonRectDead.x0 = x1 + w1;
+	     pI830->NonRectDead.x1 = pScrn1->virtualX - 1;
+	     pI830->NonRectDead.y0 = y1;
+	     pI830->NonRectDead.y1 = y1 + h1 - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+	  x2 = pI830->SecondXOffs;
+	  y2 = 0;
+	  w2 = realvirtX;
+	  h2 = max(pI830->maxSecond_Y2, pScrn1->virtualY - pI830->maxSecond_Y1);
+	  if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
+	  if((usenonrect) && (pI830->maxSecond_X2 != realvirtX)) {
+	     w2 = pI830->MBXNR2XMAX = pI830->maxSecond_X2;
+	     pI830->NonRectDead.x0 = x2 + w2;
+	     pI830->NonRectDead.x1 = pScrn1->virtualX - 1;
+	     pI830->NonRectDead.y0 = y2;
+	     pI830->NonRectDead.y1 = y2 + h2 - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+	  break;
+       case PosBelow:
+	  x1 = pI830->FirstXOffs;
+	  y1 = 0;
+	  w1 = realvirtX;
+	  h1 = max(pI830->maxFirst_Y1, pScrn1->virtualY - pI830->maxFirst_Y2);
+	  if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
+	  if((usenonrect) && (pI830->maxFirst_X1 != realvirtX)) {
+	     w1 = pI830->MBXNR1XMAX = pI830->maxFirst_X1;
+	     pI830->NonRectDead.x0 = x1 + w1;
+	     pI830->NonRectDead.x1 = pScrn1->virtualX - 1;
+	     pI830->NonRectDead.y0 = y1;
+	     pI830->NonRectDead.y1 = y1 + h1 - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+	  x2 = pI830->SecondXOffs;
+	  y2 = min(pI830->maxSecond_Y1, pScrn1->virtualY - pI830->maxSecond_Y2);
+	  if(y2 < 0) y2 = 0;
+	  w2 = realvirtX;
+	  h2 = pScrn1->virtualY - y2;
+	  if((usenonrect) && (pI830->maxSecond_X2 != realvirtX)) {
+	     w2 = pI830->MBXNR2XMAX = pI830->maxSecond_X2;
+	     pI830->NonRectDead.x0 = x2 + w2;
+	     pI830->NonRectDead.x1 = pScrn1->virtualX - 1;
+	     pI830->NonRectDead.y0 = y2;
+	     pI830->NonRectDead.y1 = y2 + h2 - 1;
+	     pI830->HaveNonRect = TRUE;
+	  }
+       default:
+	  break;
+       }
+
+       switch(pI830->SecondPosition) {
+       case PosLeftOf:
+       case PosRightOf:
+	  if(pI830->FirstYOffs) {
+	     pI830->OffDead1.x0 = x1;
+	     pI830->OffDead1.x1 = x1 + w1 - 1;
+	     pI830->OffDead1.y0 = 0;
+	     pI830->OffDead1.y1 = y1 - 1;
+	     pI830->OffDead2.x0 = x2;
+	     pI830->OffDead2.x1 = x2 + w2 - 1;
+	     pI830->OffDead2.y0 = y2 + h2;
+	     pI830->OffDead2.y1 = pScrn1->virtualY - 1;
+	     pI830->HaveOffsRegions = TRUE;
+	  } else if(pI830->SecondYOffs) {
+	     pI830->OffDead1.x0 = x2;
+	     pI830->OffDead1.x1 = x2 + w2 - 1;
+	     pI830->OffDead1.y0 = 0;
+	     pI830->OffDead1.y1 = y2 - 1;
+	     pI830->OffDead2.x0 = x1;
+	     pI830->OffDead2.x1 = x1 + w1 - 1;
+	     pI830->OffDead2.y0 = y1 + h1;
+	     pI830->OffDead2.y1 = pScrn1->virtualY - 1;
+	     pI830->HaveOffsRegions = TRUE;
+	  }
+	  break;
+       case PosAbove:
+       case PosBelow:
+	  if(pI830->FirstXOffs) {
+	     pI830->OffDead1.x0 = x2 + w2;
+	     pI830->OffDead1.x1 = pScrn1->virtualX - 1;
+	     pI830->OffDead1.y0 = y2;
+	     pI830->OffDead1.y1 = y2 + h2 - 1;
+	     pI830->OffDead2.x0 = 0;
+	     pI830->OffDead2.x1 = x1 - 1;
+	     pI830->OffDead2.y0 = y1;
+	     pI830->OffDead2.y1 = y1 + h1 - 1;
+	     pI830->HaveOffsRegions = TRUE;
+	  } else if(pI830->SecondXOffs) {
+	     pI830->OffDead1.x0 = x1 + w1;
+	     pI830->OffDead1.x1 = pScrn1->virtualX - 1;
+	     pI830->OffDead1.y0 = y1;
+	     pI830->OffDead1.y1 = y1 + h1 - 1;
+	     pI830->OffDead2.x0 = 0;
+	     pI830->OffDead2.x1 = x2 - 1;
+	     pI830->OffDead2.y0 = y2;
+	     pI830->OffDead2.y1 = y2 + h2 - 1;
+	     pI830->HaveOffsRegions = TRUE;
+	  }
+       default:
+	  break;
+       }
+
+    }
+
+    I830XineramadataPtr[scrnnum1].x = x1;
+    I830XineramadataPtr[scrnnum1].y = y1;
+    I830XineramadataPtr[scrnnum1].width = w1;
+    I830XineramadataPtr[scrnnum1].height = h1;
+    I830XineramadataPtr[scrnnum2].x = x2;
+    I830XineramadataPtr[scrnnum2].y = y2;
+    I830XineramadataPtr[scrnnum2].width = w2;
+    I830XineramadataPtr[scrnnum2].height = h2;
+
+    if(infochanged) {
+       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+	  "Pseudo-Xinerama: First (Screen %d) (%d,%d)-(%d,%d)\n",
+	  scrnnum1, x1, y1, w1+x1-1, h1+y1-1);
+       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+	  "Pseudo-Xinerama: Second (Screen %d) (%d,%d)-(%d,%d)\n",
+	  scrnnum2, x2, y2, w2+x2-1, h2+y2-1);
+       if(pI830->HaveNonRect) {
+	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+		"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
+		pI830->NonRectDead.x0, pI830->NonRectDead.y0,
+		pI830->NonRectDead.x1, pI830->NonRectDead.y1);
+       }
+       if(pI830->HaveOffsRegions) {
+	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
+		pI830->OffDead1.x0, pI830->OffDead1.y0,
+		pI830->OffDead1.x1, pI830->OffDead1.y1);
+	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
+		pI830->OffDead2.x0, pI830->OffDead2.y0,
+		pI830->OffDead2.x1, pI830->OffDead2.y1);
+       }
+       if(pI830->HaveNonRect || pI830->HaveOffsRegions) {
+	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
+		"Mouse restriction for inaccessible areas is %s\n",
+		pI830->MouseRestrictions ? "enabled" : "disabled");
+       }
+    }
+}
+
+/* Proc */
+
+int
+I830ProcXineramaQueryVersion(ClientPtr client)
+{
+    xPanoramiXQueryVersionReply	  rep;
+    register int		  n;
+
+    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.majorVersion = 1;
+    rep.minorVersion = 0;
+    if(client->swapped) {
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, n);
+        swaps(&rep.majorVersion, n);
+        swaps(&rep.minorVersion, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
+    return (client->noClientException);
+}
+
+int
+I830ProcXineramaGetState(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetStateReq);
+    WindowPtr			pWin;
+    xPanoramiXGetStateReply	rep;
+    register int		n;
+
+    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
+    pWin = LookupWindow(stuff->window, client);
+    if(!pWin) return BadWindow;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.state = !I830noPanoramiXExtension;
+    if(client->swapped) {
+       swaps (&rep.sequenceNumber, n);
+       swapl (&rep.length, n);
+       swaps (&rep.state, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
+    return client->noClientException;
+}
+
+int
+I830ProcXineramaGetScreenCount(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenCountReq);
+    WindowPtr				pWin;
+    xPanoramiXGetScreenCountReply	rep;
+    register int			n;
+
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
+    pWin = LookupWindow(stuff->window, client);
+    if(!pWin) return BadWindow;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.ScreenCount = I830XineramaNumScreens;
+    if(client->swapped) {
+       swaps(&rep.sequenceNumber, n);
+       swapl(&rep.length, n);
+       swaps(&rep.ScreenCount, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
+    return client->noClientException;
+}
+
+int
+I830ProcXineramaGetScreenSize(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenSizeReq);
+    WindowPtr				pWin;
+    xPanoramiXGetScreenSizeReply	rep;
+    register int			n;
+
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
+    pWin = LookupWindow (stuff->window, client);
+    if(!pWin)  return BadWindow;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.width  = I830XineramadataPtr[stuff->screen].width;
+    rep.height = I830XineramadataPtr[stuff->screen].height;
+    if(client->swapped) {
+       swaps(&rep.sequenceNumber, n);
+       swapl(&rep.length, n);
+       swaps(&rep.width, n);
+       swaps(&rep.height, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
+    return client->noClientException;
+}
+
+int
+I830ProcXineramaIsActive(ClientPtr client)
+{
+    xXineramaIsActiveReply	rep;
+
+    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.state = !I830noPanoramiXExtension;
+    if(client->swapped) {
+	register int n;
+	swaps(&rep.sequenceNumber, n);
+	swapl(&rep.length, n);
+	swapl(&rep.state, n);
+    }
+    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
+    return client->noClientException;
+}
+
+int
+I830ProcXineramaQueryScreens(ClientPtr client)
+{
+    xXineramaQueryScreensReply	rep;
+
+    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
+
+    rep.type = X_Reply;
+    rep.sequenceNumber = client->sequence;
+    rep.number = (I830noPanoramiXExtension) ? 0 : I830XineramaNumScreens;
+    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
+    if(client->swapped) {
+       register int n;
+       swaps(&rep.sequenceNumber, n);
+       swapl(&rep.length, n);
+       swapl(&rep.number, n);
+    }
+    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
+
+    if(!I830noPanoramiXExtension) {
+       xXineramaScreenInfo scratch;
+       int i;
+
+       for(i = 0; i < I830XineramaNumScreens; i++) {
+	  scratch.x_org  = I830XineramadataPtr[i].x;
+	  scratch.y_org  = I830XineramadataPtr[i].y;
+	  scratch.width  = I830XineramadataPtr[i].width;
+	  scratch.height = I830XineramadataPtr[i].height;
+	  if(client->swapped) {
+	     register int n;
+	     swaps(&scratch.x_org, n);
+	     swaps(&scratch.y_org, n);
+	     swaps(&scratch.width, n);
+	     swaps(&scratch.height, n);
+	  }
+	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
+       }
+    }
+
+    return client->noClientException;
+}
+
+static int
+I830ProcXineramaDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+    switch (stuff->data) {
+	case X_PanoramiXQueryVersion:
+	     return I830ProcXineramaQueryVersion(client);
+	case X_PanoramiXGetState:
+	     return I830ProcXineramaGetState(client);
+	case X_PanoramiXGetScreenCount:
+	     return I830ProcXineramaGetScreenCount(client);
+	case X_PanoramiXGetScreenSize:
+	     return I830ProcXineramaGetScreenSize(client);
+	case X_XineramaIsActive:
+	     return I830ProcXineramaIsActive(client);
+	case X_XineramaQueryScreens:
+	     return I830ProcXineramaQueryScreens(client);
+    }
+    return BadRequest;
+}
+
+/* SProc */
+
+static int
+I830SProcXineramaQueryVersion (ClientPtr client)
+{
+    REQUEST(xPanoramiXQueryVersionReq);
+    register int n;
+    swaps(&stuff->length,n);
+    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
+    return I830ProcXineramaQueryVersion(client);
+}
+
+static int
+I830SProcXineramaGetState(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetStateReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
+    return I830ProcXineramaGetState(client);
+}
+
+static int
+I830SProcXineramaGetScreenCount(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenCountReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
+    return I830ProcXineramaGetScreenCount(client);
+}
+
+static int
+I830SProcXineramaGetScreenSize(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenSizeReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
+    return I830ProcXineramaGetScreenSize(client);
+}
+
+static int
+I830SProcXineramaIsActive(ClientPtr client)
+{
+    REQUEST(xXineramaIsActiveReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
+    return I830ProcXineramaIsActive(client);
+}
+
+static int
+I830SProcXineramaQueryScreens(ClientPtr client)
+{
+    REQUEST(xXineramaQueryScreensReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
+    return I830ProcXineramaQueryScreens(client);
+}
+
+int
+I830SProcXineramaDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+    switch (stuff->data) {
+	case X_PanoramiXQueryVersion:
+	     return I830SProcXineramaQueryVersion(client);
+	case X_PanoramiXGetState:
+	     return I830SProcXineramaGetState(client);
+	case X_PanoramiXGetScreenCount:
+	     return I830SProcXineramaGetScreenCount(client);
+	case X_PanoramiXGetScreenSize:
+	     return I830SProcXineramaGetScreenSize(client);
+	case X_XineramaIsActive:
+	     return I830SProcXineramaIsActive(client);
+	case X_XineramaQueryScreens:
+	     return I830SProcXineramaQueryScreens(client);
+    }
+    return BadRequest;
+}
+
+static void
+I830XineramaResetProc(ExtensionEntry* extEntry)
+{
+    /* Called by CloseDownExtensions() */
+    if(I830XineramadataPtr) {
+       Xfree(I830XineramadataPtr);
+       I830XineramadataPtr = NULL;
+    }
+}
+
+static void
+I830XineramaExtensionInit(ScrnInfoPtr pScrn)
+{
+    I830Ptr	pI830 = I830PTR(pScrn);
+    Bool	success = FALSE;
+
+    if(!(I830XineramadataPtr)) {
+
+       if(!pI830->MergedFB) {
+	  I830noPanoramiXExtension = TRUE;
+	  pI830->MouseRestrictions = FALSE;
+	  return;
+       }
+
+#ifdef PANORAMIX
+       if(!noPanoramiXExtension) {
+	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	     "Xinerama active, not initializing Intel Pseudo-Xinerama\n");
+	  I830noPanoramiXExtension = TRUE;
+	  pI830->MouseRestrictions = FALSE;
+	  return;
+       }
+#endif
+
+       if(I830noPanoramiXExtension) {
+	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	      "Intel Pseudo-Xinerama disabled\n");
+	  pI830->MouseRestrictions = FALSE;
+	  return;
+       }
+
+       I830XineramaNumScreens = 2;
+
+       while(I830XineramaGeneration != serverGeneration) {
+
+	  pI830->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
+					I830ProcXineramaDispatch,
+					I830SProcXineramaDispatch,
+					I830XineramaResetProc,
+					StandardMinorOpcode);
+
+	  if(!pI830->XineramaExtEntry) break;
+
+	  if(!(I830XineramadataPtr = (I830XineramaData *)
+	        xcalloc(I830XineramaNumScreens, sizeof(I830XineramaData)))) break;
+
+	  I830XineramaGeneration = serverGeneration;
+	  success = TRUE;
+       }
+
+       if(!success) {
+          xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+	      "Failed to initialize Intel Pseudo-Xinerama extension\n");
+	  I830noPanoramiXExtension = TRUE;
+	  pI830->MouseRestrictions = FALSE;
+	  return;
+       }
+
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	  "Intel Pseudo-Xinerama extension initialized\n");
+
+       pI830->I830XineramaVX = 0;
+       pI830->I830XineramaVY = 0;
+
+    }
+
+    I830UpdateXineramaScreenInfo(pScrn);
+
+}
+
 static void
 I830BIOSProbeDDC(ScrnInfoPtr pScrn, int index)
 {
@@ -926,7 +2556,7 @@ 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 (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone || pI830->MergedFB || pI830->origPipe != pI830->pipe) {
       if (!SetBIOSPipe(pScrn, pI830->pipe))
          return FALSE;
    }
@@ -951,10 +2581,12 @@ I830Set640x480(ScrnInfoPtr pScrn)
 	 m = 0x50;
 	 break;
    }
+
    m |= (1 << 15) | (1 << 14);
    if (VBESetVBEMode(pI830->pVbe, m, NULL))
 	   return TRUE;
 
+
    /* if the first failed, let's try the next - usually 800x600 */
    m = 0x32;
    switch (pScrn->depth) {
@@ -967,6 +2599,7 @@ I830Set640x480(ScrnInfoPtr pScrn)
 	 break;
    }
    m |= (1 << 15) | (1 << 14);
+
    if (VBESetVBEMode(pI830->pVbe, m, NULL))
 	   return TRUE;
 
@@ -1262,7 +2895,7 @@ static const char *displayDevices[] = {
    "TV",
    "DFP (digital flat panel)",
    "LFP (local flat panel)",
-   "CRT2 (second CRT)",
+   "Second (second CRT)",
    "TV2 (second TV)",
    "DFP2 (second digital flat panel)",
    "LFP2 (second local flat panel)",
@@ -2094,6 +3727,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
    int DDCclock = 0;
    char *s;
    DisplayModePtr p, pMon;
+   xf86MonPtr monitor = NULL;
    pointer pDDCModule = NULL, pVBEModule = NULL;
    Bool enable;
    const char *chipname;
@@ -2505,6 +4139,12 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
          pI830->fixedPipe = 1;
    }
 
+   pI830->MergedFB =
+      xf86ReturnOptValBool(pI830->Options, OPTION_MERGEDFB, FALSE);
+
+   pI830->IntelXinerama =
+      xf86ReturnOptValBool(pI830->Options, OPTION_INTELXINERAMA, TRUE);
+
    pI830->MonType1 = PIPE_NONE;
    pI830->MonType2 = PIPE_NONE;
    pI830->specifiedMonitor = FALSE;
@@ -2531,7 +4171,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
                pI830->MonType1 |= PIPE_DFP;
             else if (strcmp(sub, "LFP") == 0)
                pI830->MonType1 |= PIPE_LFP;
-            else if (strcmp(sub, "CRT2") == 0)
+            else if (strcmp(sub, "Second") == 0)
                pI830->MonType1 |= PIPE_CRT2;
             else if (strcmp(sub, "TV2") == 0)
                pI830->MonType1 |= PIPE_TV2;
@@ -2560,7 +4200,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
                pI830->MonType2 |= PIPE_DFP;
             else if (strcmp(sub, "LFP") == 0)
                pI830->MonType2 |= PIPE_LFP;
-            else if (strcmp(sub, "CRT2") == 0)
+            else if (strcmp(sub, "Second") == 0)
                pI830->MonType2 |= PIPE_CRT2;
             else if (strcmp(sub, "TV2") == 0)
                pI830->MonType2 |= PIPE_TV2;
@@ -2591,7 +4231,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       pI830->specifiedMonitor = TRUE;
    }
 
-   if (xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) {
+   if (!pI830->MergedFB &&
+       xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) {
       if (pI830->availablePipes == 1) {
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 
  		 "Can't enable Clone Mode because this is a single pipe device\n");
@@ -2622,17 +4263,18 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       return FALSE;
    }
 
-   if ((pI830->entityPrivate && I830IsPrimary(pScrn)) || pI830->Clone) {
+   if ((pI830->entityPrivate && I830IsPrimary(pScrn)) || pI830->Clone ||
+	pI830->MergedFB) {
       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");
+	 		"defined for use in a DualHead, Clone or MergedFB setup.\n");
          PreInitCleanup(pScrn);
          return FALSE;
       }
          
       if (pI830->MonType1 == PIPE_NONE || pI830->MonType2 == PIPE_NONE) {
          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Monitor 1 or Monitor 2 "
-	 		"cannot be type NONE in Dual or Clone setup.\n");
+	 		"cannot be type NONE in DualHead, Clone or MergedFB setup.\n");
          PreInitCleanup(pScrn);
          return FALSE;
       }
@@ -2860,6 +4502,80 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
    }
 #endif
 
+   if (pI830->MergedFB) {
+      pI830->pScrn_2 = xalloc(sizeof(ScrnInfoRec));
+
+      if(!pI830->pScrn_2) {
+	 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to allocate memory for MergedFB mode. Disabling.\n");
+	 pI830->MergedFB = FALSE;
+      } else {
+         memcpy(pI830->pScrn_2, pScrn, sizeof(ScrnInfoRec));
+      }
+      if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_SECONDPOSITION))) {
+	 int result;
+	 int ival;
+	 Bool valid = FALSE;
+	 char *tempstr = xalloc(strlen(s) + 1);
+	 result = sscanf(s, "%s %d", tempstr, &ival);
+	 if(result >= 1) {
+ 	    if(!xf86NameCmp(tempstr,"LeftOf")) {
+	       pI830->SecondPosition = PosLeftOf;
+	       valid = TRUE;
+	       if(result == 2) {
+	          if(ival < 0) pI830->FirstYOffs = -ival;
+	          else pI830->SecondYOffs = ival;
+	       }
+	       pI830->SecondIsScrn0 = TRUE;
+	    } else if(!xf86NameCmp(tempstr,"RightOf")) {
+	       pI830->SecondPosition = PosRightOf;
+	       valid = TRUE;
+	       if(result == 2) {
+	          if(ival < 0) pI830->FirstYOffs = -ival;
+	          else pI830->SecondYOffs = ival;
+	       }
+	       pI830->SecondIsScrn0 = FALSE;
+ 	    } else if(!xf86NameCmp(tempstr,"Above")) {
+	       pI830->SecondPosition = PosAbove;
+	       valid = TRUE;
+	       if(result == 2) {
+	          if(ival < 0) pI830->FirstXOffs = -ival;
+	          else pI830->SecondXOffs = ival;
+	       }
+	       pI830->SecondIsScrn0 = FALSE;
+	    } else if(!xf86NameCmp(tempstr,"Below")) {
+	       pI830->SecondPosition = PosBelow;
+  	       valid = TRUE;
+	       if(result == 2) {
+	          if(ival < 0) pI830->FirstXOffs = -ival;
+	          else pI830->SecondXOffs = ival;
+	       }
+	       pI830->SecondIsScrn0 = TRUE;
+	    }
+         }
+         if(!valid) {
+  	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		    "Valid parameters are: \"RightOf\", \"LeftOf\", \"Above\" or \"Below\"\n");
+         }
+         xfree(tempstr);
+      }
+      if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_METAMODES))) {
+         pI830->MetaModes = xalloc(strlen(s) + 1);
+	 if(pI830->MetaModes) 
+	    memcpy(pI830->MetaModes, s, strlen(s) + 1);
+      }
+      if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_SECONDHSYNC))) {
+         pI830->SecondHSync = xalloc(strlen(s) + 1);
+	 if(pI830->SecondHSync)
+	    memcpy(pI830->SecondHSync, s, strlen(s) + 1);
+      }
+      if((s = (char *)xf86GetOptValString(pI830->Options, OPTION_SECONDVREFRESH))) {
+	 pI830->SecondVRefresh = xalloc(strlen(s) + 1);
+	 if(pI830->SecondVRefresh) 
+	    memcpy(pI830->SecondVRefresh, s, strlen(s) + 1);
+      }
+   }
+
+
    /*
     * If the driver can do gamma correction, it should call xf86SetGamma() here.
     */
@@ -2927,7 +4643,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
 
       /* Override */
       if (pI830->fixedPipe != -1) {
-         if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) {
+         if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone || 
+	     pI830->MergedFB) {
             pI830->pipe = pI830->fixedPipe; 
             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 	        "Fixed Pipe setting primary to pipe %s.\n", 
@@ -2949,9 +4666,11 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
    
       pI830->operatingDevices = (pI830->MonType2 << 8) | pI830->MonType1;
 
-      if (!xf86IsEntityShared(pScrn->entityList[0]) && !pI830->Clone) {
-	  /* If we're not dual head or clone, turn off the second head,
-          * if monitorlayout is also specified. */
+      if (!xf86IsEntityShared(pScrn->entityList[0]) && !pI830->Clone &&
+	  !pI830->MergedFB) {
+	  /* If we're not dual head, clone or mergedfb, turn off the
+           * second head if monitorlayout is also specified. 
+	   */
 
          if (pI830->pipe == 0)
             pI830->operatingDevices = pI830->MonType1;
@@ -3103,12 +4822,74 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
 
    pDDCModule = xf86LoadSubModule(pScrn, "ddc");
 
-   pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
+   monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
 
-   if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) {
-      xf86PrintEDID(pI830->vesa->monitor);
-      xf86SetDDCproperties(pScrn, pI830->vesa->monitor);
+   if ((pScrn->monitor->DDC = monitor) != NULL) {
+      xf86PrintEDID(monitor);
+      xf86SetDDCproperties(pScrn, monitor);
+   }
+
+   if(pI830->MergedFB) {
+      pI830->pScrn_2->monitor = xalloc(sizeof(MonRec));
+      if(pI830->pScrn_2->monitor) {
+	 DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
+	 memcpy(pI830->pScrn_2->monitor, pScrn->monitor, sizeof(MonRec));
+	 pI830->pScrn_2->monitor->DDC = NULL;
+	 pI830->pScrn_2->monitor->Modes = NULL;
+	 pI830->pScrn_2->monitor->id = (char *)SecondMonitorName;
+	 tempm = pScrn->monitor->Modes;
+	 while(tempm) {
+	    if(!(newm = xalloc(sizeof(DisplayModeRec)))) break;
+	    memcpy(newm, tempm, sizeof(DisplayModeRec));
+	    if(!(newm->name = xalloc(strlen(tempm->name) + 1))) {
+	       xfree(newm);
+	       break;
+	    }
+	    strcpy(newm->name, tempm->name);
+	    if(!pI830->pScrn_2->monitor->Modes) 
+	       pI830->pScrn_2->monitor->Modes = newm;
+	    if(currentm) {
+	       currentm->next = newm;
+	       newm->prev = currentm;
+	    }
+	    currentm = newm;
+	    tempm = tempm->next;
+	 }
+	 if(pI830->SecondHSync) {
+	    pI830->pScrn_2->monitor->nHsync =
+	    	I830StrToRanges(pI830->pScrn_2->monitor->hsync, pI830->SecondHSync, MAX_HSYNC);
+	 }
+	 if(pI830->SecondVRefresh) {
+	    pI830->pScrn_2->monitor->nVrefresh =
+		I830StrToRanges(pI830->pScrn_2->monitor->vrefresh, pI830->SecondVRefresh, MAX_VREFRESH);
+	 }
+         SetBIOSPipe(pScrn, !pI830->pipe);
+         pI830->pVbe->ddc = DDC_UNCHECKED;
+	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		"Probing DDC data for second head\n");
+	 if((monitor = vbeDoEDID(pI830->pVbe, pDDCModule))) {
+	    xf86PrintEDID(monitor);
+	    xf86SetDDCproperties(pI830->pScrn_2, monitor);
+	    pI830->pScrn_2->monitor->DDC = monitor;
+	    /* use DDC data if no ranges in config file */
+	    if(!pI830->SecondHSync) {
+	       pI830->pScrn_2->monitor->nHsync = 0;
+	    }
+	    if(!pI830->SecondVRefresh) {
+	       pI830->pScrn_2->monitor->nVrefresh = 0;
+	    }
+	 }
+	 SetPipeAccess(pScrn);
+      } else {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+	      "Failed to allocate memory for second monitor.\n");
+	 if(pI830->pScrn_2) 
+            xfree(pI830->pScrn_2);
+	 pI830->pScrn_2 = NULL;
+	 pI830->MergedFB = FALSE;
+      }
    }
+
    xf86UnloadSubModule(pDDCModule);
 
    /* XXX Move this to a header. */
@@ -3135,7 +4916,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
 
    pI830->useExtendedRefresh = FALSE;
 
-   if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) {
+   if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone || 
+       pI830->MergedFB) {
       int pipe =
 	  (pI830->operatingDevices >> PIPE_SHIFT(pI830->pipe)) & PIPE_ACTIVE_MASK;
       if (pipe & ~PIPE_CRT_ACTIVE) {
@@ -3227,6 +5009,21 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       return FALSE;
    }
 
+   if (pI830->MergedFB) {
+      SetBIOSPipe(pScrn, !pI830->pipe);
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		 "Retrieving mode pool for second head.\n");
+      pI830->pScrn_2->modePool = I830GetModePool(pI830->pScrn_2, pI830->pVbe, pI830->vbeInfo);
+
+      if (!pI830->pScrn_2->modePool) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		 "No Video BIOS modes for chosen depth.\n");
+         PreInitCleanup(pScrn);
+         return FALSE;
+      }
+      SetPipeAccess(pScrn);
+   }
+
    /* 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 .....
     */
@@ -3244,6 +5041,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
 
    SetPipeAccess(pScrn);
    VBESetModeNames(pScrn->modePool);
+   if (pI830->MergedFB)
+      VBESetModeNames(pI830->pScrn_2->modePool);
+
 
    /*
     * XXX DDC information: There's code in xf86ValidateModes
@@ -3267,6 +5067,20 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       return FALSE;
    }
 
+   if (pI830->MergedFB) {
+      n = VBEValidateModes(pI830->pScrn_2, NULL, pI830->pScrn_2->display->modes, NULL,
+			NULL, 0, MAX_DISPLAY_PITCH, 1,
+			0, MAX_DISPLAY_HEIGHT,
+			pScrn->display->virtualX,
+			pScrn->display->virtualY,
+			memsize, LOOKUP_BEST_REFRESH);
+      if (n <= 0) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
+         PreInitCleanup(pScrn);
+         return FALSE;
+      }
+   }
+
    /* Only use this if we've got DDC available */
    if (DDCclock > 0) {
       p = pScrn->modes;
@@ -3306,14 +5120,43 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       return FALSE;
    }
 
+   if (pI830->MergedFB) {
+      DisplayModePtr old_modes;
+      DisplayModePtr cur_mode;
+
+      xf86PruneDriverModes(pI830->pScrn_2);
+
+      if (pI830->pScrn_2->modes == NULL) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+         PreInitCleanup(pScrn);
+         return FALSE;
+      }
+
+      old_modes = pScrn->modes;
+      cur_mode = pScrn->currentMode;
+
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
+
+      pScrn->modes = I830GenerateModeList(pScrn, pI830->MetaModes,
+					  old_modes, pI830->pScrn_2->modes,
+					  pI830->SecondPosition);
+
+      if(!pScrn->modes) {
+          xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes. Disabling MergedFB.\n");
+	  pScrn->modes = old_modes;
+	  pScrn->currentMode = cur_mode;
+	  pI830->MergedFB = FALSE;
+      }
+   }
+
    /* Now we check the VESA BIOS's displayWidth and reset if necessary */
    p = pScrn->modes;
    do {
-      VbeModeInfoData *data = (VbeModeInfoData *) p->Private;
+      I830ModePrivatePtr mp = (I830ModePrivatePtr) p->Private;
       VbeModeInfoBlock *modeInfo;
 
       /* Get BytesPerScanline so we can reset displayWidth */
-      if ((modeInfo = VBEGetModeInfo(pI830->pVbe, data->mode))) {
+      if ((modeInfo = VBEGetModeInfo(pI830->pVbe, mp->vbeData.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;
@@ -3324,6 +5167,18 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
 
    pScrn->currentMode = pScrn->modes;
 
+   if (pI830->MergedFB) {
+      /* If no virtual dimension was given by the user,
+       * calculate a sane one now. Adapts pScrn->virtualX,
+       * pScrn->virtualY and pScrn->displayWidth.
+       */
+      I830RecalcDefaultVirtualSize(pScrn);
+
+      pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
+      pScrn->currentMode = pScrn->modes;
+      pI830->currentMode = pScrn->currentMode;
+   }
+
 #ifndef USE_PITCHES
 #define USE_PITCHES 1
 #endif
@@ -3953,7 +5808,8 @@ I830VESASetVBEMode(ScrnInfoPtr pScrn, in
 	  pScrn->virtualY * pI830->displayWidth * pI830->cpp);
 #endif
 
-   if (pI830->Clone && pI830->CloneHDisplay && pI830->CloneVDisplay &&
+   if (pI830->Clone && 
+	pI830->CloneHDisplay && pI830->CloneVDisplay &&
        !pI830->preinit && !pI830->closing) {
       VbeCRTCInfoBlock newblock;
       int newmode = mode;
@@ -4087,7 +5943,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
 {
    I830Ptr pI830 = I830PTR(pScrn);
    vbeInfoPtr pVbe = pI830->pVbe;
-   VbeModeInfoData *data = (VbeModeInfoData *) pMode->Private;
+   I830ModePrivatePtr mp = (I830ModePrivatePtr) pMode->Private;
    int mode, i;
    CARD32 planeA, planeB, temp;
    int refresh = 60;
@@ -4098,13 +5954,13 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
    DPRINTF(PFX, "I830VESASetMode\n");
 
    /* Always Enable Linear Addressing */
-   mode = data->mode | (1 << 15) | (1 << 14);
+   mode = mp->vbeData.mode | (1 << 15) | (1 << 14);
 
 #ifdef XF86DRI
    didLock = I830DRILock(pScrn);
 #endif
 
-   if (pI830->Clone) {
+   if (pI830->Clone || pI830->MergedFB) {
       pI830->CloneHDisplay = pMode->HDisplay;
       pI830->CloneVDisplay = pMode->VDisplay;
    }
@@ -4118,9 +5974,24 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
 
    SetPipeAccess(pScrn);
 
-   if (I830VESASetVBEMode(pScrn, mode, data->block) == FALSE) {
-      xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
-      return FALSE;
+   if (!pI830->MergedFB) {
+      if (I830VESASetVBEMode(pScrn, mode, mp->vbeData.block) == FALSE) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
+         return FALSE;
+      }
+   }else {
+      I830ModePrivatePtr s = (I830ModePrivatePtr)mp->merged.Second->Private;
+      I830ModePrivatePtr f = (I830ModePrivatePtr)mp->merged.First->Private;
+      SetBIOSPipe(pScrn, !pI830->pipe);
+      if (I830VESASetVBEMode(pScrn, (f->vbeData.mode | 1<<15 | 1<<14), f->vbeData.block) == FALSE) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
+         return FALSE;
+      }
+      SetPipeAccess(pScrn);
+      if (I830VESASetVBEMode(pScrn, (s->vbeData.mode | 1<<15 | 1<<14), s->vbeData.block) == FALSE) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n");
+         return FALSE;
+      }
    }
 
    /*
@@ -4128,8 +5999,8 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
     * memory than it's aware of.  We check for this later, and set it
     * explicitly if necessary.
     */
-   if (data->data->XResolution != pI830->displayWidth) {
-      if (pI830->Clone) {
+   if (mp->vbeData.data->XResolution != pI830->displayWidth) {
+      if (pI830->Clone || pI830->MergedFB) {
          SetBIOSPipe(pScrn, !pI830->pipe);
          VBESetLogicalScanline(pVbe, pI830->displayWidth);
       }
@@ -4138,7 +6009,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
    }
 
    if (pScrn->bitsPerPixel >= 8 && pI830->vbeInfo->Capabilities[0] & 0x01) {
-      if (pI830->Clone) {
+      if (pI830->Clone || pI830->MergedFB) {
          SetBIOSPipe(pScrn, !pI830->pipe);
          VBESetGetDACPaletteFormat(pVbe, 8);
       }
@@ -4307,7 +6178,16 @@ I830VESASetMode(ScrnInfoPtr pScrn, Displ
 		    (int)(temp / pI830->cpp), pI830->displayWidth);
 	    OUTREG(stridereg, pI830->displayWidth * pI830->cpp);
          }
-         OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16));
+
+#if 0
+	 if (pI830->MergedFB) {
+            if (i == 0)
+               OUTREG(sizereg, (CDMPTR.First->HDisplay - 1) | ((CDMPTR.First->VDisplay - 1) << 16));
+	    else 
+               OUTREG(sizereg, (CDMPTR.Second->HDisplay - 1) | ((CDMPTR.Second->VDisplay - 1) << 16));
+         } else
+            OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16));
+#endif
 	 /* Trigger update */
 	 temp = INREG(basereg);
 	 OUTREG(basereg, temp);
@@ -5160,7 +7040,7 @@ I830BIOSScreenInit(int scrnIndex, Screen
    pI830->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = I830BIOSCloseScreen;
 
-   if (pI830->shadowReq.minorversion >= 1) {
+   if (!pI830->MergedFB && pI830->shadowReq.minorversion >= 1) {
       /* Rotation */
       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RandR enabled, ignore the following RandR disabled message.\n");
       xf86DisableRandR(); /* Disable built-in RandR extension */
@@ -5176,6 +7056,24 @@ I830BIOSScreenInit(int scrnIndex, Screen
       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "libshadow is version %d.%d.%d, required 1.1.0 or greater for rotation.\n",pI830->shadowReq.majorversion,pI830->shadowReq.minorversion,pI830->shadowReq.patchlevel);
    }
 
+   if (pI830->MergedFB) {
+      pI830->PointerMoved = pScrn->PointerMoved;
+      pScrn->PointerMoved = I830MergedPointerMoved;
+
+      if(pI830->IntelXinerama) {
+	  I830noPanoramiXExtension = FALSE;
+	  I830XineramaExtensionInit(pScrn);
+	  if(!I830noPanoramiXExtension) {
+	     if(pI830->HaveNonRect) {
+		/* Reset the viewport (now eventually non-recangular) */
+		I830BIOSAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+	     }
+	  }
+      } else {
+	  pI830->MouseRestrictions = FALSE;
+      }
+   }
+
    if (serverGeneration == 1)
       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
 
@@ -5234,6 +7132,11 @@ I830BIOSAdjustFrame(int scrnIndex, int x
       pI830->AccelInfoRec->NeedToSync = FALSE;
    }
 
+   if (pI830->MergedFB) {
+      I830AdjustFrameMerged(scrnIndex, x, y, flags);
+      return;
+   }
+
    if (I830IsPrimary(pScrn))
       Start = pI830->FrontBuffer.Start;
    else {
@@ -5316,7 +7219,7 @@ I830BIOSLeaveVT(int scrnIndex, int flags
    I830VideoSwitchModeBefore(pScrn, NULL);
 #endif
 
-   if (pI830->Clone) {
+   if (pI830->Clone || pI830->MergedFB) {
       /* Ensure we don't try and setup modes on a clone head */
       pI830->CloneHDisplay = 0;
       pI830->CloneVDisplay = 0;
@@ -5389,6 +7292,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
    int displayWidth = pScrn->displayWidth;
    int curHDisplay = pScrn->currentMode->HDisplay;
    int curVDisplay = pScrn->currentMode->VDisplay;
+   xf86MonPtr monitor = NULL;
 
    DPRINTF(PFX, "Detect Monitor Change\n");
    
@@ -5396,13 +7300,11 @@ I830DetectMonitorChange(ScrnInfoPtr pScr
 
    /* Re-read EDID */
    pDDCModule = xf86LoadSubModule(pScrn, "ddc");
-   if (pI830->vesa->monitor)
-      xfree(pI830->vesa->monitor);
-   pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
+   monitor = vbeDoEDID(pI830->pVbe, pDDCModule);
    xf86UnloadSubModule(pDDCModule);
-   if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) {
-      xf86PrintEDID(pI830->vesa->monitor);
-      xf86SetDDCproperties(pScrn, pI830->vesa->monitor);
+   if ((pScrn->monitor->DDC = monitor) != NULL) {
+      xf86PrintEDID(monitor);
+      xf86SetDDCproperties(pScrn, monitor);
    } else 
       /* No DDC, so get out of here, and continue to use the current settings */
       return FALSE; 
@@ -5745,6 +7647,13 @@ I830BIOSSwitchMode(int scrnIndex, Displa
 #endif
    }
 
+   /* Since RandR (indirectly) uses SwitchMode(), we need to
+    * update our Xinerama info here, too, in case of resizing
+    */
+   if(pI830->MergedFB) {
+      I830UpdateXineramaScreenInfo(pScrn);
+   }
+
    return ret;
 }
 
@@ -5797,7 +7706,7 @@ I830DisplayPowerManagementSet(ScrnInfoPt
    I830Ptr pI830 = I830PTR(pScrn);
    vbeInfoPtr pVbe = pI830->pVbe;
 
-   if (pI830->Clone) {
+   if (pI830->Clone || pI830->MergedFB) {
       SetBIOSPipe(pScrn, !pI830->pipe);
       if (xf86LoaderCheckSymbol("VBEDPMSSet")) {
          VBEDPMSSet(pVbe, PowerManagementMode);
@@ -6257,7 +8166,6 @@ I830CheckDevicesTimer(OsTimerPtr timer, 
          ScreenPtr   pCursorScreen;
          int x = 0, y = 0;
 
-
          pCursorScreen = miPointerCurrentScreen();
          if (pScrn->pScreen == pCursorScreen)
             miPointerPosition(&x, &y);
diff --git a/src/i830_modes.c b/src/i830_modes.c
index 97e40e0..383b23c 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -42,8 +42,6 @@
 #include <string.h>
 
 #include "xf86.h"
-#include "vbe.h"
-#include "vbeModes.h"
 #include "i830.h"
 
 #include <math.h>
@@ -363,7 +361,11 @@ CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr 
     CARD16 major, minor;
     VbeModeInfoBlock *mode;
     DisplayModePtr p = NULL, pMode = NULL;
+#if 0
     VbeModeInfoData *data;
+#else
+    I830ModePrivatePtr data;
+#endif
     Bool modeOK = FALSE;
     ModeStatus status = MODE_OK;
 
@@ -602,12 +604,21 @@ CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr 
     pMode->HDisplay = mode->XResolution;
     pMode->VDisplay = mode->YResolution;
 
+#if 0
     data = xnfcalloc(sizeof(VbeModeInfoData), 1);
     data->mode = id;
     data->data = mode;
     pMode->PrivSize = sizeof(VbeModeInfoData);
     pMode->Private = (INT32*)data;
+#else
+    data = xnfcalloc(sizeof(I830ModePrivateRec), 1);
+    data->vbeData.mode = id;
+    data->vbeData.data = mode;
+    pMode->PrivSize = sizeof(I830ModePrivateRec);
+    pMode->Private = (INT32*)data;
+#endif
     pMode->next = NULL;
+
     return pMode;
 }
 
@@ -664,50 +675,49 @@ void
 I830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe)
 {
     DisplayModePtr pMode;
-    VbeModeInfoData *data;
+    I830ModePrivatePtr mp;
 
     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) |
+	mp->vbeData.block = xcalloc(sizeof(VbeCRTCInfoBlock), 1);
+	mp->vbeData.block->HorizontalTotal = pMode->HTotal;
+	mp->vbeData.block->HorizontalSyncStart = pMode->HSyncStart;
+	mp->vbeData.block->HorizontalSyncEnd = pMode->HSyncEnd;
+	mp->vbeData.block->VerticalTotal = pMode->VTotal;
+	mp->vbeData.block->VerticalSyncStart = pMode->VSyncStart;
+	mp->vbeData.block->VerticalSyncEnd = pMode->VSyncEnd;
+	mp->vbeData.block->Flags = ((pMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
 				 ((pMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
-	data->block->PixelClock = pMode->Clock * 1000;
+	mp->vbeData.block->PixelClock = pMode->Clock * 1000;
 	/* XXX May not have this. */
-	clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock);
+	clock = VBEGetPixelClock(pVbe, mp->vbeData.mode, mp->vbeData.block->PixelClock);
 	if (clock)
-	    data->block->PixelClock = clock;
+	    mp->vbeData.block->PixelClock = clock;
 #ifdef DEBUG
 	ErrorF("Setting clock %.2fMHz, closest is %.2fMHz\n",
-		(double)data->block->PixelClock / 1000000.0, 
+		(double)mp->vbeData.block->PixelClock / 1000000.0, 
 		(double)clock / 1000000.0);
 #endif
-	data->mode |= (1 << 11);
+	mp->vbeData.mode |= (1 << 11);
 	if (pMode->VRefresh != 0) {
-	    data->block->RefreshRate = pMode->VRefresh * 100;
+	    mp->vbeData.block->RefreshRate = pMode->VRefresh * 100;
 	} else {
-	    data->block->RefreshRate = (int)(((double)(data->block->PixelClock)/
+	    mp->vbeData.block->RefreshRate = (int)(((double)(mp->vbeData.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);
+		       (float)(((double)(mp->vbeData.block->PixelClock) / (double)(pMode->HTotal * pMode->VTotal))), pMode->name, mp->vbeData.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,
+	       mp->vbeData.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);
+	       (double)mp->vbeData.block->PixelClock/1000000.0,
+	       (double)mp->vbeData.block->RefreshRate/100);
 #endif
 	pMode = pMode->next;
     } while (pMode != pScrn->modes);



More information about the xorg-commit mailing list