945 lines
30 KiB
C
945 lines
30 KiB
C
|
#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 separator */
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Copies 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 won't 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 functions. 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 sure 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. being outsize both frames, and inside
|
||
|
* the outer clipping 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 sure 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;
|
||
|
}
|
||
|
|
||
|
|