diff options
Diffstat (limited to 'src/i830_driver.c')
-rw-r--r-- | src/i830_driver.c | 2257 |
1 files changed, 2199 insertions, 58 deletions
diff --git a/src/i830_driver.c b/src/i830_driver.c index 5ce88e14..84fb21a9 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> @@ -178,10 +179,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 +245,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 +273,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 +296,24 @@ static Bool SetPipeAccess(ScrnInfoPtr pScrn); 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 +382,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 +399,6 @@ I830BIOSFreeRec(ScrnInfoPtr pScrn) } pVesa = pI830->vesa; - if (pVesa->monitor) - xfree(pVesa->monitor); if (pVesa->savedPal) xfree(pVesa->savedPal); xfree(pVesa); @@ -383,6 +407,1601 @@ 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. + */ + + 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; +} + +/* 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; + + 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 +2545,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 +2570,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 +2588,7 @@ I830Set640x480(ScrnInfoPtr pScrn) break; } m |= (1 << 15) | (1 << 14); + if (VBESetVBEMode(pI830->pVbe, m, NULL)) return TRUE; @@ -1262,7 +2884,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)", @@ -1864,6 +3486,79 @@ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, 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; @@ -2091,9 +3786,10 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) int flags24; int defmon = 0; int i, n; - int DDCclock = 0; + int DDCclock = 0, DDCclock2 = 0; char *s; DisplayModePtr p, pMon; + xf86MonPtr monitor = NULL; pointer pDDCModule = NULL, pVBEModule = NULL; Bool enable; const char *chipname; @@ -2491,8 +4187,11 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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; @@ -2505,6 +4204,12 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +4236,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +4265,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +4296,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +4328,18 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +4567,80 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #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 +4708,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) /* 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 +4731,11 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +4887,74 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pDDCModule = xf86LoadSubModule(pScrn, "ddc"); - pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule); - - if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) { - xf86PrintEDID(pI830->vesa->monitor); - xf86SetDDCproperties(pScrn, pI830->vesa->monitor); + monitor = vbeDoEDID(pI830->pVbe, pDDCModule); + + 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 +4981,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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) { @@ -3214,6 +5061,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) DDCclock = I830UseDDC(pScrn); + if (pI830->MergedFB) + DDCclock2 = I830UseDDC(pI830->pScrn_2); + /* * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS * functions. @@ -3227,6 +5077,21 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +5109,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) SetPipeAccess(pScrn); VBESetModeNames(pScrn->modePool); + if (pI830->MergedFB) + VBESetModeNames(pI830->pScrn_2->modePool); + /* * XXX DDC information: There's code in xf86ValidateModes @@ -3267,6 +5135,20 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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; @@ -3298,6 +5180,37 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } 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) { @@ -3306,14 +5219,42 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; } + if (pI830->MergedFB) { + DisplayModePtr old_modes, 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 +5265,18 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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 +5906,8 @@ I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block) 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; @@ -4030,12 +5984,18 @@ I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block) 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) @@ -4087,7 +6047,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) { 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,7 +6058,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) 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); @@ -4118,9 +6078,35 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) 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; + int pipe = pI830->pipe; /* save current pipe */ + + SetBIOSPipe(pScrn, !pI830->pipe); + + 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, (f->vbeData.mode | 1<<15 | 1<<14), f->vbeData.block) == FALSE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); + return FALSE; + } } /* @@ -4128,8 +6114,8 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) * 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 +6124,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) } 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 +6293,22 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) (int)(temp / pI830->cpp), pI830->displayWidth); OUTREG(stridereg, pI830->displayWidth * pI830->cpp); } - OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16)); + + if (pI830->MergedFB) { + 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)); /* Trigger update */ temp = INREG(basereg); OUTREG(basereg, temp); @@ -5160,7 +7161,23 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = I830BIOSCloseScreen; - if (pI830->shadowReq.minorversion >= 1) { + 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; + } + } 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 */ @@ -5234,6 +7251,20 @@ I830BIOSAdjustFrame(int scrnIndex, int x, int y, int flags) pI830->AccelInfoRec->NeedToSync = FALSE; } + 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; + } + if (I830IsPrimary(pScrn)) Start = pI830->FrontBuffer.Start; else { @@ -5316,7 +7347,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; @@ -5385,10 +7416,11 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) 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; + xf86MonPtr monitor = NULL; DPRINTF(PFX, "Detect Monitor Change\n"); @@ -5396,19 +7428,29 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) /* Re-read EDID */ pDDCModule = xf86LoadSubModule(pScrn, "ddc"); - if (pI830->vesa->monitor) - xfree(pI830->vesa->monitor); - pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule); + + 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 = pI830->vesa->monitor) != NULL) { - xf86PrintEDID(pI830->vesa->monitor); - xf86SetDDCproperties(pScrn, pI830->vesa->monitor); - } else - /* No DDC, so get out of here, and continue to use the current settings */ - return FALSE; + if ((pScrn->monitor->DDC = monitor) != NULL) { + xf86PrintEDID(monitor); + xf86SetDDCproperties(pScrn, monitor); + } - 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) + DDCclock2 = I830UseDDC(pI830->pScrn_2); /* Revalidate the modes */ @@ -5416,6 +7458,8 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) * 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) { @@ -5426,8 +7470,24 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) return FALSE; } - SetPipeAccess(pScrn); + if (pI830->MergedFB && DDCclock2 > 0) { + 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 && DDCclock2 > 0) + VBESetModeNames(pI830->pScrn_2->modePool); if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64)) memsize = pI830->vbeInfo->TotalMemory * 64; @@ -5441,6 +7501,16 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) pScrn->display->virtualY, memsize, LOOKUP_BEST_REFRESH); + 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, + 0, MAX_DISPLAY_HEIGHT, + pScrn->display->virtualX, + pScrn->display->virtualY, + memsize, LOOKUP_BEST_REFRESH); + } + if (DDCclock > 0) { p = pScrn->modes; if (p == NULL) @@ -5471,9 +7541,71 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) } while (p != NULL && p != pScrn->modes); } + /* Only use this if we've got DDC available */ + if (pI830->MergedFB && 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 && DDCclock2 > 0) { + xf86PruneDriverModes(pI830->pScrn_2); + + if (pI830->pScrn_2->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + } + + if (pI830->MergedFB) { + DisplayModePtr old_modes, cur_mode; + + 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) @@ -5521,6 +7653,9 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) } } + if (pI830->MergedFB) + I830AdjustFrameMerged(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + return TRUE; } @@ -5745,6 +7880,13 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) #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 +7939,7 @@ I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, 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 +8399,6 @@ I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg) ScreenPtr pCursorScreen; int x = 0, y = 0; - pCursorScreen = miPointerCurrentScreen(); if (pScrn->pScreen == pCursorScreen) miPointerPosition(&x, &y); |