#ifdef HAVE_CONFIG_H #include "config.h" #endif /* All drivers should typically include these */ #include "xf86.h" #include "xf86_OSproc.h" /* All drivers need this */ #include "compiler.h" #include "mga.h" #include "mga_macros.h" #include "mga_reg.h" #include "mga_merge.h" #include "fbdevhw.h" static int StrToRanges(range* r, const char* s) { float num=0.0; int rangenum=0; Bool gotdash = FALSE; Bool nextdash = FALSE; const 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; /*is extra seperator */ if(strnum != NULL) sscanf(strnum,"%f",&num); if(gotdash) /*if wasn't singlet: correct. */ r[rangenum-1].hi = num; else { /*first, assume singlet */ r[rangenum].lo = num; r[rangenum].hi = num; rangenum++; } strnum = NULL; if(*s == '-') nextdash = (rangenum != 0); /*ignore dash if before any number.*/ break; default : return 0; } } while(*(s++) != 0); /* run loop for every char including null terminator.*/ return rangenum; } /* Copys mode i, links the result to dest, and returns it. * Links i and j in Private record. * if dest is NULL, return value is copy of i linked to itself. */ static DisplayModePtr CopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) { DisplayModePtr mode; int dx = 0,dy = 0; /* start with first node */ mode = malloc(sizeof(DisplayModeRec)); memcpy(mode,i, sizeof(DisplayModeRec)); mode->Private = malloc(sizeof(MergedDisplayModeRec)); ((MergedDisplayModePtr)mode->Private)->Monitor1 = i; ((MergedDisplayModePtr)mode->Private)->Monitor2 = j; ((MergedDisplayModePtr)mode->Private)->Monitor2Pos = srel; mode->PrivSize = 0; switch(srel) { case mgaLeftOf: case mgaRightOf: dx = min(pScrn->virtualX,i->HDisplay + j->HDisplay) - mode->HDisplay; dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; break; case mgaAbove: case mgaBelow: dy = min(pScrn->virtualY,i->VDisplay + j->VDisplay) - mode->VDisplay; dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; break; case mgaClone: dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; 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->Clock = 0; /* Shows we're in Merge mode. */ mode->next = mode; mode->prev = mode; if(dest) { /* Insert node after "dest" */ mode->next = dest->next; dest->next->prev = mode; mode->prev = dest; dest->next = mode; } return mode; } static DisplayModePtr GetModeFromName(const 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; } /* takes a config file string of MetaModes and generates a MetaModeList */ static DisplayModePtr GenerateModeList(ScrnInfoPtr pScrn, const char* str, DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) { const char* strmode = str; char modename[256]; Bool gotdash = FALSE; MgaScrn2Rel sr; DisplayModePtr mode1 = NULL; DisplayModePtr mode2 = NULL; DisplayModePtr result = NULL; do { switch(*str) { case 0: case '-': case ' ': case ',': case ';': if((strmode != str)) {/*we got a mode */ /* read new entry */ strncpy(modename,strmode,str - strmode); modename[str - strmode] = 0; if(gotdash) { if(mode1 == NULL) return NULL; mode2 = GetModeFromName(modename,j); if(!mode2) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Mode: \"%s\" is not a supported mode for monitor 2\n",modename); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Skipping metamode \"%s-%s\".\n",mode1->name,modename); mode1 = NULL; } } else { mode1 = GetModeFromName(modename,i); if(!mode1) { const char* tmps = str; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Mode: \"%s\" is not a supported mode for monitor 1\n",modename); /* find if a monitor2 mode follows */ gotdash = FALSE; while(*tmps == ' ' || *tmps == ';') tmps++; if(*tmps == '-' || *tmps == ',') { /* skip the next mode */ tmps++; while(*tmps == ' ' || *tmps == ';') tmps++; /*skip spaces */ while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != ',') tmps++; /*skip modename */ /* for error message */ strncpy(modename,strmode,tmps - strmode); modename[tmps - strmode] = 0; str = tmps-1; } xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Skipping metamode \"%s\".\n",modename); mode1 = NULL; } } gotdash = FALSE; } strmode = str+1; /* number starts on next char */ gotdash |= (*str == '-' || *str == ','); if(*str != 0) break; /* if end of string, we wont get a chance to catch a char and run the default case. do it now */ default: if(!gotdash && mode1) { /* complete previous pair */ sr = srel; if(!mode2) { mode2 = GetModeFromName(mode1->name,j); sr = mgaClone; } if(!mode2) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Mode: \"%s\" is not a supported mode for monitor 2\n",mode1->name); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Skipping clone mode \"%s\".\n", mode1->name); mode1 = NULL; } else { result = CopyModeNLink(pScrn,result,mode1,mode2,sr); mode1 = NULL; mode2 = NULL; } } break; } } while(*(str++) != 0); return result; } /* second CRTC init funcitons. Used to check monitor timings and refreshes. * this function looses lots of maintainability points due to redundancy, * but it still was the cleanest and least-intrusive way I found. */ Bool MGAPreInitMergedFB(ScrnInfoPtr pScrn1, int flags) { ScrnInfoPtr pScrn; MGAPtr pMga; MGAPtr pMga1; MessageType from; int i; const char* s; ClockRangePtr clockRanges; MgaScrn2Rel Monitor2Pos; xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== Start of second screen initialization ====\n"); pScrn = malloc(sizeof(ScrnInfoRec)); memcpy(pScrn,pScrn1,sizeof(ScrnInfoRec)); pScrn->driverPrivate = NULL; /* Allocate the MGARec driverPrivate */ if (!MGAGetRec(pScrn)) { return FALSE; } pMga = MGAPTR(pScrn); pMga1 = MGAPTR(pScrn1); pMga1->pScrn2 = pScrn; /* Get the entity, and make sure it is PCI. */ pMga->pEnt = pMga1->pEnt; /* Set pMga->device to the relevant Device section */ pMga->device = pMga1->device; if (flags & PROBE_DETECT) { MGAProbeDDC(pScrn, pMga->pEnt->index); /*FIXME make shure this probes second monitor */ return TRUE; } #ifndef XSERVER_LIBPCIACCESS pMga->PciTag = pMga1->PciTag; #endif pMga->Primary = pMga1->Primary; /* Set pScrn->monitor */ { pScrn->monitor = malloc(sizeof(MonRec)); /* copy everything we don't care about */ memcpy(pScrn->monitor,pScrn1->monitor,sizeof(MonRec)); pScrn->monitor->DDC = NULL; /*FIXME:have to try this */ if ((s = xf86GetOptValString(pMga1->Options, OPTION_HSYNC2))) { pScrn->monitor->nHsync = StrToRanges(pScrn->monitor->hsync,s); } if ((s = xf86GetOptValString(pMga1->Options, OPTION_VREFRESH2))) { pScrn->monitor->nVrefresh = StrToRanges(pScrn->monitor->vrefresh,s); } } pMga->SecondCrtc = TRUE; pMga->HWCursor = FALSE; pScrn->AdjustFrame = MGAAdjustMergeFrames; pScrn1->AdjustFrame = MGAAdjustMergeFrames; /* if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24)) FIXME:have to copy result form scrn1 if (!xf86SetWeight(pScrn, zeros, zeros)) { */ /* We use a programamble clock */ pScrn->progClock = TRUE; /* Collect all of the relevant option flags (fill in pScrn->options) */ pScrn->options = pScrn1->options; /* xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pMga->Options);*/ pMga->Options = pMga1->Options; /* Set the bits per RGB for 8bpp mode */ if (pScrn->depth == 8) pScrn->rgbBits = 8; /* * Set the Chipset and ChipRev, allowing config file entries to * override. */ pScrn->chipset = pScrn1->chipset; pMga->Chipset = pMga1->Chipset; pMga->ChipRev = pMga1->ChipRev; #ifdef MGADRI pMga->agpMode = pMga1->agpMode; #endif pMga->NoAccel = pMga1->NoAccel; pMga->UsePCIRetry = pMga1->UsePCIRetry; pMga->SyncOnGreen = pMga1->SyncOnGreen; pMga->ShowCache = pMga1->ShowCache; pMga->HasSDRAM = pMga1->HasSDRAM; pMga->MemClk = pMga1->MemClk; pMga->colorKey = pMga1->colorKey; pScrn->colorKey = pScrn1->colorKey; pScrn->overlayFlags = pScrn1->overlayFlags; pMga->videoKey = pMga1->videoKey; /* unsupported options */ pMga->HWCursor = FALSE; pMga->ShadowFB = FALSE; pMga->FBDev = FALSE; pMga->OverclockMem = pMga1->OverclockMem; pMga->TexturedVideo = pMga1->TexturedVideo; pMga->MergedFB = TRUE; pMga->Rotate = 0; switch (pMga->Chipset) { case PCI_CHIP_MGA2064: case PCI_CHIP_MGA2164: case PCI_CHIP_MGA2164_AGP: MGA2064SetupFuncs(pScrn); break; case PCI_CHIP_MGA1064: case PCI_CHIP_MGAG100: case PCI_CHIP_MGAG100_PCI: case PCI_CHIP_MGAG200: case PCI_CHIP_MGAG200_PCI: case PCI_CHIP_MGAG200_SE_A_PCI: case PCI_CHIP_MGAG200_SE_B_PCI: case PCI_CHIP_MGAG200_WINBOND_PCI: case PCI_CHIP_MGAG200_EW3_PCI: case PCI_CHIP_MGAG200_EV_PCI: case PCI_CHIP_MGAG200_EH_PCI: case PCI_CHIP_MGAG200_ER_PCI: case PCI_CHIP_MGAG200_EH3_PCI: case PCI_CHIP_MGAG400: case PCI_CHIP_MGAG550: MGAGSetupFuncs(pScrn); break; } pMga->FbAddress = pMga1->FbAddress; pMga->PciInfo = pMga1->PciInfo; #ifndef XSERVER_LIBPCIACCESS pMga->IOAddress = pMga1->IOAddress; pMga->ILOADAddress = pMga1->ILOADAddress; pMga->BiosFrom = pMga1->BiosFrom; pMga->BiosAddress = pMga1->BiosAddress; #endif /* * Read the BIOS data struct */ mga_read_and_process_bios( pScrn ); /* HW bpp matches reported bpp */ pMga->HwBpp = pMga1->HwBpp; /* * Reset card if it isn't primary one */ if ( (!pMga->Primary && !pMga->FBDev) ) MGASoftReset(pScrn); pScrn->videoRam = pScrn1->videoRam; pMga->FbMapSize = pMga1->FbMapSize; pMga->SrcOrg = pMga1->SrcOrg; pMga->DstOrg = pMga1->DstOrg; /* Set the bpp shift value */ pMga->BppShifts[0] = 0; pMga->BppShifts[1] = 1; pMga->BppShifts[2] = 0; pMga->BppShifts[3] = 2; /* * fill MGAdac struct * Warning: currently, it should be after RAM counting */ (*pMga->PreInit)(pScrn); #if !defined(__powerpc__) /* Read and print the Monitor DDC info */ /* pScrn->monitor->DDC = MGAdoDDC(pScrn);*/ /*FIXME: have to try this*/ #endif /* !__powerpc__ */ /* * If the driver can do gamma correction, it should call xf86SetGamma() * here. */ { Gamma zeros = {0.0, 0.0, 0.0}; if (!xf86SetGamma(pScrn, zeros)) { return FALSE; } } /* Set the min pixel clock */ pMga->MinClock = pMga1->MinClock; /* XXX Guess, need to check this */ xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Min pixel clock is %d MHz\n", pMga->MinClock / 1000); /* Override on 2nd crtc */ if (pMga->ChipRev >= 0x80 || (pMga->Chipset == PCI_CHIP_MGAG550)) { /* G450, G550 */ pMga->MaxClock = 234000; } else { pMga->MaxClock = 135000; } xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Max pixel clock is %d MHz\n", pMga->MaxClock / 1000); /* * Setup the ClockRanges, which describe what clock ranges are available, * and what sort of modes they can be used for. */ clockRanges = xnfcalloc(sizeof(ClockRange), 1); clockRanges->next = NULL; clockRanges->minClock = pMga->MinClock; clockRanges->maxClock = pMga->MaxClock; clockRanges->clockIndex = -1; /* programmable */ clockRanges->interlaceAllowed = TRUE; clockRanges->doubleScanAllowed = TRUE; clockRanges->interlaceAllowed = FALSE; /*no interlace on CRTC2 */ clockRanges->ClockMulFactor = 1; clockRanges->ClockDivFactor = 1; /* Only set MemClk if appropriate for the ramdac */ if (pMga->Dac.SetMemClk) { if (pMga->MemClk == 0) { pMga->MemClk = pMga->Dac.MemoryClock; from = pMga->Dac.MemClkFrom; } else from = X_CONFIG; xf86DrvMsg(pScrn->scrnIndex, from, "CRTC2: MCLK used is %.1f MHz\n", pMga->MemClk / 1000.0); } /* * xf86ValidateModes will check that the mode HTotal and VTotal values * don't exceed the chipset's limit if pScrn->maxHValue and * pScrn->maxVValue are set. Since our MGAValidMode() already takes * care of this, we don't worry about setting them here. */ { int Pitches1[] = {640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0}; int Pitches2[] = {512, 640, 768, 800, 832, 960, 1024, 1152, 1280, 1600, 1664, 1920, 2048, 0}; int *linePitches = NULL; int minPitch = 256; int maxPitch = 2048; switch(pMga->Chipset) { case PCI_CHIP_MGA2064: if (!pMga->NoAccel) { linePitches = malloc(sizeof(Pitches1)); memcpy(linePitches, Pitches1, sizeof(Pitches1)); minPitch = maxPitch = 0; } break; case PCI_CHIP_MGA2164: case PCI_CHIP_MGA2164_AGP: case PCI_CHIP_MGA1064: if (!pMga->NoAccel) { linePitches = malloc(sizeof(Pitches2)); memcpy(linePitches, Pitches2, sizeof(Pitches2)); minPitch = maxPitch = 0; } break; case PCI_CHIP_MGAG100: case PCI_CHIP_MGAG100_PCI: maxPitch = 2048; break; case PCI_CHIP_MGAG200: case PCI_CHIP_MGAG200_PCI: case PCI_CHIP_MGAG200_SE_A_PCI: case PCI_CHIP_MGAG200_SE_B_PCI: case PCI_CHIP_MGAG200_WINBOND_PCI: case PCI_CHIP_MGAG200_EW3_PCI: case PCI_CHIP_MGAG200_EV_PCI: case PCI_CHIP_MGAG200_EH_PCI: case PCI_CHIP_MGAG200_ER_PCI: case PCI_CHIP_MGAG200_EH3_PCI: case PCI_CHIP_MGAG400: case PCI_CHIP_MGAG550: maxPitch = 4096; break; } pScrn->modePool=NULL; pScrn->modes = NULL; i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, linePitches, minPitch, maxPitch, pMga->Roundings[(pScrn->bitsPerPixel >> 3) - 1] * pScrn->bitsPerPixel, 128, 2048, pScrn->display->virtualX, pScrn->display->virtualY, pMga->FbMapSize, LOOKUP_BEST_REFRESH); free(linePitches); } if (i < 1 && pMga->FBDev) { fbdevHWUseBuildinMode(pScrn); pScrn->displayWidth = pScrn->virtualX; /* FIXME: might be wrong */ i = 1; } if (i == -1) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: Validate Modes Failed\n"); MGAFreeRec(pScrn); return FALSE; } /* Prune the modes marked as invalid */ xf86PruneDriverModes(pScrn); if (i == 0 || pScrn->modes == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: No valid modes found\n"); MGAFreeRec(pScrn); return FALSE; } /* * Set the CRTC parameters for all of the modes based on the type * of mode, and the chipset's interlace requirements. * * Calling this is required if the mode->Crtc* values are used by the * driver and if the driver doesn't provide code to set them. They * are not pre-initialised at all. */ MGA_NOT_HAL(xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V)); /* Set the current mode to the first in the list */ pScrn->currentMode = pScrn->modes; /* Print the list of modes being used */ xf86PrintModes(pScrn); /* Set display resolution */ xf86SetDpi(pScrn, 0, 0); /* * Compute the byte offset into the linear frame buffer where the * frame buffer data should actually begin. According to DDK misc.c * line 1023, if more than 4MB is to be displayed, YDSTORG must be set * appropriately to align memory bank switching, and this requires a * corresponding offset on linear frame buffer access. * This is only needed for WRAM. */ pMga->YDstOrg = pMga1->YDstOrg; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "CRTC2: YDstOrg is set to %d\n", pMga->YDstOrg); pMga->FbUsableSize = pMga1->FbUsableSize; pMga->FbCursorOffset = pMga1->FbCursorOffset; pMga->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; pMga->CurrentLayout.depth = pScrn->depth; pMga->CurrentLayout.displayWidth = pScrn->displayWidth; pMga->CurrentLayout.weight.red = pScrn->weight.red; pMga->CurrentLayout.weight.green = pScrn->weight.green; pMga->CurrentLayout.weight.blue = pScrn->weight.blue; pMga->CurrentLayout.mode = pScrn->currentMode; Monitor2Pos = mgaRightOf; if ((s = xf86GetOptValString(pMga1->Options, OPTION_MONITOR2POS))) { switch(s[0]) { case 'L': case 'l': case 'G': case 'g': Monitor2Pos = mgaLeftOf; break; case 'R': case 'r': case 'D': case 'd': Monitor2Pos = mgaRightOf; break; case 'A': case 'a': case 'H': case 'h': Monitor2Pos = mgaAbove; break; case 'B': case 'b': Monitor2Pos = mgaBelow; break; case 'C': case 'c': Monitor2Pos = mgaClone; break; default: Monitor2Pos = mgaRightOf; break; } } /* Fool xf86 into thinking we have huge modes */ /* Keep the original values somewhere */ pMga1->M1modes = pScrn1->modes; pMga1->M1currentMode = pScrn1->currentMode; /* make a copy of the mode list, so we can modify it. */ if ((s = xf86GetOptValString(pMga1->Options, OPTION_METAMODES))) { pScrn1->modes = GenerateModeList(pScrn,s,pMga1->M1modes,pScrn->modes,Monitor2Pos); /*FIXME: free this list*/ if(!pScrn1->modes) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Parse Error reading MetaModes, or No modes left.\n"); return FALSE; } pScrn1->modes = pScrn1->modes->next; pScrn1->currentMode = pScrn1->modes; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MetaModes option missing.\n"); return FALSE; } xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== End of second screen initialization ====\n"); return TRUE; } void MGADisplayPowerManagementSetMerged(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { MGADisplayPowerManagementSet(pScrn,PowerManagementMode,flags); MGADisplayPowerManagementSetCrtc2(pScrn,PowerManagementMode,flags); } typedef struct _region { int x0,x1,y0,y1; } region; static Bool InRegion(int x, int y, region r) { return (r.x0 <= x) && (x < r.x1) && (r.y0 <= y) && (y < r.y1); } #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; } } void MGAMergePointerMoved(SCRN_ARG_TYPE arg, int x, int y) { SCRN_INFO_PTR(arg); MGAPtr pMga = MGAPTR(pScrn); ScrnInfoPtr pScr2 = pMga->pScrn2; region out,in1,in2,f2,f1; int deltax,deltay; /* for ease. */ f1.x0 = pMga->M1frameX0; f1.x1 = pMga->M1frameX1+1; f1.y0 = pMga->M1frameY0; f1.y1 = pMga->M1frameY1+1; f2.x0 = pScr2->frameX0; f2.x1 = pScr2->frameX1+1; f2.y0 = pScr2->frameY0; f2.y1 = pScr2->frameY1+1; /*specify outer clipping region. crossing this causes all frames to move*/ out.x0 = pScrn->frameX0; out.x1 = pScrn->frameX1+1; out.y0 = pScrn->frameY0; out.y1 = pScrn->frameY1+1; /* * specify inner sliding window. beeing outsize both frames, and inside * the outer cliping window, causes corresponding frame to slide */ in1 = out; in2 = out; switch(((MergedDisplayModePtr)pScrn->currentMode->Private)->Monitor2Pos) { case mgaLeftOf : in1.x0 = f1.x0; in2.x1 = f2.x1; break; case mgaRightOf : in1.x1 = f1.x1; in2.x0 = f2.x0; break; case mgaBelow : in1.y1 = f1.y1; in2.y0 = f2.y0; break; case mgaAbove : in1.y0 = f1.y0; in2.y1 = f2.y1; break; case mgaClone : break; } deltay = 0; deltax = 0; if(InRegion(x,y,out)) { if( InRegion(x,y, in1) && !InRegion(x,y, f1) ) { REBOUND(f1.x0,f1.x1,x); REBOUND(f1.y0,f1.y1,y); deltax = 1; /*force frame update */ } if( InRegion(x,y, in2) && !InRegion(x,y, f2) ) { REBOUND(f2.x0,f2.x1,x); REBOUND(f2.y0,f2.y1,y); deltax = 1; /*force frame update */ } } else { /*outside outer clipping region*/ if ( out.x0 > x) { deltax = x - out.x0; } if ( out.x1 < x) { deltax = x - out.x1; } f1.x0 += deltax; f1.x1 += deltax; f2.x0 += deltax; f2.x1 += deltax; pScrn->frameX0 += deltax; pScrn->frameX1 += deltax; if ( out.y0 > y) { deltay = y - out.y0; } if ( out.y1 < y) { deltay = y - out.y1; } f1.y0 += deltay; f1.y1 += deltay; f2.y0 += deltay; f2.y1 += deltay; pScrn->frameY0 += deltay; pScrn->frameY1 += deltay; } if (deltax != 0 || deltay != 0) { /* back to reality. */ pMga->M1frameX0 = f1.x0; pMga->M1frameY0 = f1.y0; pScr2->frameX0 = f2.x0; pScr2->frameY0 = f2.y0; /*Adjust Granularity */ MGAAdjustGranularity(pScrn,&pMga->M1frameX0,&pMga->M1frameY0); MGAAdjustGranularity(pScrn,&pScr2->frameX0,&pScr2->frameY0); MGAAdjustGranularity(pScrn,&pScrn->frameX0,&pScrn->frameY0); pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScrn)->Monitor1->HDisplay -1; pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScrn)->Monitor1->VDisplay -1; pScr2->frameX1 = pScr2->frameX0 + MDMPTR(pScrn)->Monitor2->HDisplay -1; pScr2->frameY1 = pScr2->frameY0 + MDMPTR(pScrn)->Monitor2->VDisplay -1; pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay -1; pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay -1; MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pMga->M1frameX0, pMga->M1frameY0)); MGAAdjustFrameCrtc2(ADJUST_FRAME_ARGS(pScrn, pScr2->frameX0, pScr2->frameY0)); } /* if(pMga->PointerMoved) (*pMga->PointerMoved)(scrnIndex, x, y); FIXME: do I need to call old func?*/ } void MGAAdjustMergeFrames(ADJUST_FRAME_ARGS_DECL) { SCRN_INFO_PTR(arg); ScrnInfoPtr pScrn1 = pScrn; MGAPtr pMga = MGAPTR(pScrn1); ScrnInfoPtr pScrn2 = pMga->pScrn2; int VTotal = pScrn1->currentMode->VDisplay; int HTotal = pScrn1->currentMode->HDisplay; int VMax = VTotal; int HMax = HTotal; BOUND(x,0,pScrn1->virtualX-HTotal); BOUND(y,0,pScrn1->virtualY-VTotal); switch(MDMPTR(pScrn1)->Monitor2Pos) { case mgaLeftOf: pScrn2->frameX0 = x; BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); pMga->M1frameX0 = x+MDMPTR(pScrn1)->Monitor2->HDisplay; BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); break; case mgaRightOf: pMga->M1frameX0 = x; BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); pScrn2->frameX0 = x+MDMPTR(pScrn1)->Monitor1->HDisplay; BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); break; case mgaAbove: BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); pScrn2->frameY0 = y; BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); pMga->M1frameY0 = y+MDMPTR(pScrn1)->Monitor2->VDisplay; break; case mgaBelow: BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); pMga->M1frameY0 = y; BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); pScrn2->frameY0 = y+MDMPTR(pScrn1)->Monitor1->VDisplay; break; case mgaClone: BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); break; } /* sanity checks. Make shure were not out of bounds */ BOUND(pMga->M1frameX0,0,pScrn1->virtualX -MDMPTR(pScrn1)->Monitor1->HDisplay); BOUND(pMga->M1frameY0,0,pScrn1->virtualY -MDMPTR(pScrn1)->Monitor1->VDisplay); BOUND(pScrn2->frameX0,0,pScrn2->virtualX -MDMPTR(pScrn1)->Monitor2->HDisplay); BOUND(pScrn2->frameY0,0,pScrn2->virtualY -MDMPTR(pScrn1)->Monitor2->VDisplay); pScrn1->frameX0 = x; pScrn1->frameY0 = y; /* check granularity */ MGAAdjustGranularity(pScrn1,&pMga->M1frameX0,&pMga->M1frameY0); MGAAdjustGranularity(pScrn1,&pScrn2->frameX0,&pScrn2->frameY0); MGAAdjustGranularity(pScrn1,&pScrn1->frameX0,&pScrn1->frameY0); /* complete shitty redundant info */ pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScrn1)->Monitor1->HDisplay -1; pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScrn1)->Monitor1->VDisplay -1; pScrn2->frameX1 = pScrn2->frameX0 + MDMPTR(pScrn1)->Monitor2->HDisplay -1; pScrn2->frameY1 = pScrn2->frameY0 + MDMPTR(pScrn1)->Monitor2->VDisplay -1; pScrn1->frameX1 = pScrn1->frameX0 + pScrn1->currentMode->HDisplay -1; pScrn1->frameY1 = pScrn1->frameY0 + pScrn1->currentMode->VDisplay -1; MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pMga->M1frameX0, pMga->M1frameY0)); MGAAdjustFrameCrtc2(ADJUST_FRAME_ARGS(pScrn, pScrn2->frameX0, pScrn2->frameY0)); return; } Bool MGACloseScreenMerged(ScreenPtr pScreen) { ScrnInfoPtr pScrn1 = xf86ScreenToScrn(pScreen); MGAPtr pMga = MGAPTR(pScrn1); ScrnInfoPtr pScrn2 = pMga->pScrn2; if(pScrn2) { free(pScrn2->monitor); pScrn2->monitor = NULL; free(pScrn2); pMga->pScrn2 = NULL; } if(pScrn1->modes) { pScrn1->currentMode = pScrn1->modes; do { DisplayModePtr p = pScrn1->currentMode->next; free(pScrn1->currentMode->Private); free(pScrn1->currentMode); pScrn1->currentMode = p; }while( pScrn1->currentMode != pScrn1->modes); } pScrn1->currentMode = pMga->M1currentMode; pScrn1->modes = pMga->M1modes; return TRUE; } Bool MGASaveScreenMerged(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); MGAPtr pMga = MGAPTR(pScrn); BOOL on = xf86IsUnblank(mode); CARD8 reg; if (on) { /* SetTimdeSinceLastInputEvent();*/ /* power on Dac1 */ reg = inMGAdac(MGA1064_MISC_CTL); reg |= MGA1064_MISC_CTL_DAC_EN; outMGAdac(MGA1064_MISC_CTL, reg); /* power on Dac2 */ reg = inMGAdac(MGA1064_PWR_CTL); reg |= MGA1064_PWR_CTL_DAC2_EN; outMGAdac(MGA1064_PWR_CTL, reg); } else { /* power off Dac1 */ reg = inMGAdac(MGA1064_MISC_CTL); reg &= ~MGA1064_MISC_CTL_DAC_EN; outMGAdac(MGA1064_MISC_CTL, reg); /* power off Dac2 */ reg = inMGAdac(MGA1064_PWR_CTL); reg &= ~MGA1064_PWR_CTL_DAC2_EN; outMGAdac(MGA1064_PWR_CTL, reg); } return TRUE; }