mga_merge.c revision a31a186a
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5/* All drivers should typically include these */
6#include "xf86.h"
7#include "xf86_OSproc.h"
8
9/* All drivers need this */
10
11#include "compiler.h"
12
13/* Drivers for PCI hardware need this */
14#include "xf86PciInfo.h"
15#include "mga.h"
16#include "mga_macros.h"
17#include "mga_reg.h"
18#include "mga_merge.h"
19
20#include "fbdevhw.h"
21
22static int
23StrToRanges(range* r, char* s) {
24    float num=0.0;
25    int rangenum=0;
26    Bool gotdash = FALSE;
27    Bool nextdash = FALSE;
28    char* strnum=NULL;
29    do {
30        switch(*s) {
31            case '0': case '1': case '2': case '3': case '4': case '5':
32            case '6': case '7': case '8': case '9': case '.':
33                if(strnum == NULL) {
34                    strnum = s;
35                    gotdash = nextdash;
36                    nextdash = FALSE;
37                 }
38
39                break;
40            case '-':
41            case ' ': case 0:
42                if(strnum == NULL) break; /*is extra seperator */
43                if(strnum != NULL) sscanf(strnum,"%f",&num);
44                if(gotdash) /*if wasn't singlet: correct. */
45                    r[rangenum-1].hi = num;
46                else { /*first, assume singlet */
47                    r[rangenum].lo = num;
48                    r[rangenum].hi = num;
49                    rangenum++;
50                }
51                strnum = NULL;
52                if(*s == '-')
53                    nextdash = (rangenum != 0); /*ignore dash if before any number.*/
54                break;
55            default :
56                return 0;
57        }
58    } while(*(s++) != 0); /* run loop for every char including null terminator.*/
59
60    return rangenum;
61}
62
63
64/* Copys mode i, links the result to dest, and returns it.
65 * Links i and j in Private record.
66 * if dest is NULL, return value is copy of i linked to itself.
67 */
68static DisplayModePtr
69CopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) {
70    DisplayModePtr mode;
71    int dx = 0,dy = 0;
72    /* start with first node */
73    mode = xalloc(sizeof(DisplayModeRec));
74    memcpy(mode,i, sizeof(DisplayModeRec));
75    mode->Private = xalloc(sizeof(MergedDisplayModeRec));
76    ((MergedDisplayModePtr)mode->Private)->Monitor1 = i;
77    ((MergedDisplayModePtr)mode->Private)->Monitor2 = j;
78    ((MergedDisplayModePtr)mode->Private)->Monitor2Pos = srel;
79    mode->PrivSize = 0;
80
81        switch(srel) {
82            case mgaLeftOf:
83            case mgaRightOf:
84                dx = min(pScrn->virtualX,i->HDisplay + j->HDisplay) -  mode->HDisplay;
85                dy = min(pScrn->virtualY,  max(i->VDisplay,j->VDisplay)) - mode->VDisplay;
86                break;
87            case mgaAbove:
88            case mgaBelow:
89                dy = min(pScrn->virtualY,i->VDisplay + j->VDisplay) - mode->VDisplay;
90                dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay;
91                break;
92            case mgaClone:
93                dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay;
94                dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay;
95                break;
96        }
97    mode->HDisplay += dx;
98    mode->HSyncStart += dx;
99    mode->HSyncEnd += dx;
100    mode->HTotal += dx;
101    mode->VDisplay += dy;
102    mode->VSyncStart += dy;
103    mode->VSyncEnd += dy;
104    mode->VTotal += dy;
105    mode->Clock = 0; /* Shows we're in Merge mode. */
106
107    mode->next = mode;
108    mode->prev = mode;
109
110    if(dest) {
111        /* Insert node after "dest" */
112        mode->next = dest->next;
113        dest->next->prev = mode;
114        mode->prev = dest;
115        dest->next = mode;
116    }
117
118    return mode;
119}
120
121static DisplayModePtr
122GetModeFromName(char* str, DisplayModePtr i)
123{
124    DisplayModePtr c = i;
125    if(!i) return NULL;
126    do {
127        if(strcmp(str,c->name) == 0) return c;
128        c = c->next;
129    } while(c != i);
130    return NULL;
131}
132
133/* takes a config file string of MetaModes and generates a MetaModeList */
134static DisplayModePtr
135GenerateModeList(ScrnInfoPtr pScrn, char* str,
136		 DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) {
137    char* strmode = str;
138    char modename[256];
139    Bool gotdash = FALSE;
140    MgaScrn2Rel sr;
141
142    DisplayModePtr mode1 = NULL;
143    DisplayModePtr mode2 = NULL;
144    DisplayModePtr result = NULL;
145    do {
146        switch(*str) {
147            case 0:
148            case '-':
149            case ' ':
150	    case ',':
151	    case ';':
152                if((strmode != str)) {/*we got a mode */
153                    /* read new entry */
154                    strncpy(modename,strmode,str - strmode);
155                    modename[str - strmode] = 0;
156
157                    if(gotdash) {
158                        if(mode1 == NULL) return NULL;
159                        mode2 = GetModeFromName(modename,j);
160                        if(!mode2) {
161                            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
162                                "Mode: \"%s\" is not a supported mode for monitor 2\n",modename);
163                            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
164                                "Skipping metamode \"%s-%s\".\n",mode1->name,modename);
165                            mode1 = NULL;
166                        }
167                    } else {
168                        mode1 = GetModeFromName(modename,i);
169                        if(!mode1) {
170                            char* tmps = str;
171                            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
172                                "Mode: \"%s\" is not a supported mode for monitor 1\n",modename);
173                            /* find if a monitor2 mode follows */
174                            gotdash = FALSE;
175                            while(*tmps == ' ' || *tmps == ';') tmps++;
176                            if(*tmps == '-' || *tmps == ',') { /* skip the next mode */
177                                tmps++;
178                                while(*tmps == ' ' || *tmps == ';') tmps++; /*skip spaces */
179                                while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != ',') tmps++; /*skip modename */
180                                /* for error message */
181                                strncpy(modename,strmode,tmps - strmode);
182                                modename[tmps - strmode] = 0;
183                                str = tmps-1;
184                            }
185                            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
186                                "Skipping metamode \"%s\".\n",modename);
187                            mode1 = NULL;
188                        }
189                    }
190                    gotdash = FALSE;
191                }
192                strmode = str+1; /* number starts on next char */
193                gotdash |= (*str == '-' || *str == ',');
194
195                if(*str != 0) break; /* if end of string, we wont get a chance to catch a char and run the
196                                        default case. do it now */
197
198            default:
199                if(!gotdash && mode1) { /* complete previous pair */
200                    sr = srel;
201                    if(!mode2) {
202                        mode2 = GetModeFromName(mode1->name,j);
203                        sr = mgaClone;
204                    }
205                    if(!mode2) {
206                        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
207                            "Mode: \"%s\" is not a supported mode for monitor 2\n",mode1->name);
208                        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
209                            "Skipping clone mode \"%s\".\n", mode1->name);
210                        mode1 = NULL;
211                    } else {
212                        result = CopyModeNLink(pScrn,result,mode1,mode2,sr);
213                        mode1 = NULL;
214                        mode2 = NULL;
215                    }
216                }
217                break;
218
219        }
220    } while(*(str++) != 0);
221    return result;
222}
223
224
225/* second CRTC init funcitons. Used to check monitor timings and refreshes.
226 * this function looses lots of maintainability points due to redundancy,
227 * but it still was the cleanest and least-intrusive way I found. */
228
229Bool
230MGAPreInitMergedFB(ScrnInfoPtr pScrn1, int flags)
231{
232    ScrnInfoPtr pScrn;
233    MGAPtr pMga;
234    MGAPtr pMga1;
235    MessageType from;
236    int i;
237    char* s;
238    ClockRangePtr clockRanges;
239#ifdef USEMGAHAL
240    ULONG status;
241#endif
242    MgaScrn2Rel Monitor2Pos;
243
244    xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== Start of second screen initialization ====\n");
245    pScrn = xalloc(sizeof(ScrnInfoRec));
246    memcpy(pScrn,pScrn1,sizeof(ScrnInfoRec));
247
248    pScrn->driverPrivate = NULL;
249    /* Allocate the MGARec driverPrivate */
250    if (!MGAGetRec(pScrn)) {
251	return FALSE;
252    }
253
254    pMga = MGAPTR(pScrn);
255#ifdef USEMGAHAL
256    pMga->pMgaModeInfo = NULL; /*will be allocated later if NULL*/
257#endif
258    pMga1 = MGAPTR(pScrn1);
259    pMga1->pScrn2 = pScrn;
260
261    /* Get the entity, and make sure it is PCI. */
262    pMga->pEnt = pMga1->pEnt;
263
264    /* Set pMga->device to the relevant Device section */
265    pMga->device = pMga1->device;
266
267    if (flags & PROBE_DETECT) {
268	MGAProbeDDC(pScrn, pMga->pEnt->index); /*FIXME make shure this probes second monitor */
269	return TRUE;
270    }
271
272#ifndef XSERVER_LIBPCIACCESS
273    pMga->PciTag = pMga1->PciTag;
274#endif
275    pMga->Primary = pMga1->Primary;
276
277    /* Set pScrn->monitor */
278    {
279        pScrn->monitor = xalloc(sizeof(MonRec));
280        /* copy everything we don't care about */
281        memcpy(pScrn->monitor,pScrn1->monitor,sizeof(MonRec));
282        pScrn->monitor->DDC = NULL;   /*FIXME:have to try this */
283        if ((s = xf86GetOptValString(pMga1->Options, OPTION_HSYNC2))) {
284            pScrn->monitor->nHsync = StrToRanges(pScrn->monitor->hsync,s);
285        }
286        if ((s = xf86GetOptValString(pMga1->Options, OPTION_VREFRESH2))) {
287            pScrn->monitor->nVrefresh = StrToRanges(pScrn->monitor->vrefresh,s);
288        }
289
290
291
292   }
293
294    pMga->SecondCrtc = TRUE;
295    pMga->HWCursor = FALSE;
296    pScrn->AdjustFrame = MGAAdjustMergeFrames;
297    pScrn1->AdjustFrame = MGAAdjustMergeFrames;
298
299/*    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24))   FIXME:have to copy result form scrn1
300  if (!xf86SetWeight(pScrn, zeros, zeros)) {
301*/
302
303    /* We use a programamble clock */
304    pScrn->progClock = TRUE;
305
306    /* Collect all of the relevant option flags (fill in pScrn->options) */
307    pScrn->options = pScrn1->options;
308
309/*   xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pMga->Options);*/
310    pMga->Options = pMga1->Options;
311
312
313    /* Set the bits per RGB for 8bpp mode */
314    if (pScrn->depth == 8)
315	pScrn->rgbBits = 8;
316
317    /*
318     * Set the Chipset and ChipRev, allowing config file entries to
319     * override.
320     */
321    pScrn->chipset = pScrn1->chipset;
322    pMga->Chipset = pMga1->Chipset;
323    pMga->ChipRev = pMga1->ChipRev;
324
325#ifdef XF86DRI
326    pMga->agpMode = pMga1->agpMode;
327#endif
328
329    pMga->NoAccel = pMga1->NoAccel;
330    pMga->UsePCIRetry = pMga1->UsePCIRetry;
331    pMga->SyncOnGreen = pMga1->SyncOnGreen;
332    pMga->ShowCache = pMga1->ShowCache;
333    pMga->HasSDRAM = pMga1->HasSDRAM;
334    pMga->MemClk = pMga1->MemClk;
335    pMga->colorKey = pMga1->colorKey;
336    pScrn->colorKey = pScrn1->colorKey;
337    pScrn->overlayFlags = pScrn1->overlayFlags;
338    pMga->videoKey = pMga1->videoKey;
339    /* unsupported options */
340    pMga->HWCursor = FALSE;
341    pMga->ShadowFB = FALSE;
342    pMga->FBDev = FALSE;
343
344    pMga->OverclockMem = pMga1->OverclockMem;
345    pMga->TexturedVideo = pMga1->TexturedVideo;
346    pMga->MergedFB = TRUE;
347
348    pMga->Rotate = 0;
349
350    switch (pMga->Chipset) {
351    case PCI_CHIP_MGA2064:
352    case PCI_CHIP_MGA2164:
353    case PCI_CHIP_MGA2164_AGP:
354	MGA2064SetupFuncs(pScrn);
355	break;
356    case PCI_CHIP_MGA1064:
357    case PCI_CHIP_MGAG100:
358    case PCI_CHIP_MGAG100_PCI:
359    case PCI_CHIP_MGAG200:
360    case PCI_CHIP_MGAG200_PCI:
361    case PCI_CHIP_MGAG200_SE_A_PCI:
362    case PCI_CHIP_MGAG200_SE_B_PCI:
363    case PCI_CHIP_MGAG200_WINBOND_PCI:
364    case PCI_CHIP_MGAG200_EV_PCI:
365    case PCI_CHIP_MGAG200_EH_PCI:
366    case PCI_CHIP_MGAG400:
367    case PCI_CHIP_MGAG550:
368	MGAGSetupFuncs(pScrn);
369	break;
370    }
371
372    pMga->FbAddress = pMga1->FbAddress;
373    pMga->PciInfo = pMga1->PciInfo;
374#ifndef XSERVER_LIBPCIACCESS
375    pMga->IOAddress = pMga1->IOAddress;
376    pMga->ILOADAddress = pMga1->ILOADAddress;
377    pMga->BiosFrom = pMga1->BiosFrom;
378    pMga->BiosAddress = pMga1->BiosAddress;
379#endif
380
381    /*
382     * Read the BIOS data struct
383     */
384
385    mga_read_and_process_bios( pScrn );
386
387    /* HW bpp matches reported bpp */
388    pMga->HwBpp = pMga1->HwBpp;
389
390    /*
391     * Reset card if it isn't primary one
392     */
393    if ( (!pMga->Primary && !pMga->FBDev) || xf86IsPc98() )
394        MGASoftReset(pScrn);
395
396
397    pScrn->videoRam = pScrn1->videoRam;
398    pMga->FbMapSize = pMga1->FbMapSize;
399    pMga->SrcOrg = pMga1->SrcOrg;
400    pMga->DstOrg = pMga1->DstOrg;
401
402   /* Set the bpp shift value */
403    pMga->BppShifts[0] = 0;
404    pMga->BppShifts[1] = 1;
405    pMga->BppShifts[2] = 0;
406    pMga->BppShifts[3] = 2;
407
408    /*
409     * fill MGAdac struct
410     * Warning: currently, it should be after RAM counting
411     */
412    (*pMga->PreInit)(pScrn);
413
414#if !defined(__powerpc__)
415
416    /* Read and print the Monitor DDC info */
417/*    pScrn->monitor->DDC = MGAdoDDC(pScrn);*/ /*FIXME: have to try this*/
418#endif /* !__powerpc__ */
419
420    /*
421     * If the driver can do gamma correction, it should call xf86SetGamma()
422     * here.
423     */
424    {
425	Gamma zeros = {0.0, 0.0, 0.0};
426
427	if (!xf86SetGamma(pScrn, zeros)) {
428	    return FALSE;
429	}
430    }
431
432
433    /* Set the min pixel clock */
434    pMga->MinClock = pMga1->MinClock;	/* XXX Guess, need to check this */
435    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Min pixel clock is %d MHz\n",
436	       pMga->MinClock / 1000);
437   /* Override on 2nd crtc */
438
439    if (pMga->ChipRev >= 0x80 || (pMga->Chipset == PCI_CHIP_MGAG550)) {
440	/* G450, G550 */
441        pMga->MaxClock = 234000;
442    } else {
443        pMga->MaxClock = 135000;
444    }
445    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Max pixel clock is %d MHz\n",
446	       pMga->MaxClock / 1000);
447    /*
448     * Setup the ClockRanges, which describe what clock ranges are available,
449     * and what sort of modes they can be used for.
450     */
451    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
452    clockRanges->next = NULL;
453    clockRanges->minClock = pMga->MinClock;
454    clockRanges->maxClock = pMga->MaxClock;
455    clockRanges->clockIndex = -1;		/* programmable */
456    clockRanges->interlaceAllowed = TRUE;
457    clockRanges->doubleScanAllowed = TRUE;
458#ifdef USEMGAHAL
459    MGA_HAL(clockRanges->interlaceAllowed = FALSE);
460    MGA_HAL(clockRanges->doubleScanAllowed = FALSE);
461#endif
462    clockRanges->interlaceAllowed = FALSE; /*no interlace on CRTC2 */
463
464    clockRanges->ClockMulFactor = 1;
465    clockRanges->ClockDivFactor = 1;
466    /* Only set MemClk if appropriate for the ramdac */
467    if (pMga->Dac.SetMemClk) {
468	if (pMga->MemClk == 0) {
469	    pMga->MemClk = pMga->Dac.MemoryClock;
470	    from = pMga->Dac.MemClkFrom;
471	} else
472	    from = X_CONFIG;
473	xf86DrvMsg(pScrn->scrnIndex, from, "CRTC2: MCLK used is %.1f MHz\n",
474		   pMga->MemClk / 1000.0);
475    }
476
477    /*
478     * xf86ValidateModes will check that the mode HTotal and VTotal values
479     * don't exceed the chipset's limit if pScrn->maxHValue and
480     * pScrn->maxVValue are set.  Since our MGAValidMode() already takes
481     * care of this, we don't worry about setting them here.
482     */
483    {
484	int Pitches1[] =
485	  {640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0};
486	int Pitches2[] =
487	  {512, 640, 768, 800, 832, 960, 1024, 1152, 1280, 1600, 1664,
488		1920, 2048, 0};
489	int *linePitches = NULL;
490	int minPitch = 256;
491	int maxPitch = 2048;
492
493        switch(pMga->Chipset) {
494	case PCI_CHIP_MGA2064:
495	   if (!pMga->NoAccel) {
496		linePitches = xalloc(sizeof(Pitches1));
497		memcpy(linePitches, Pitches1, sizeof(Pitches1));
498		minPitch = maxPitch = 0;
499	   }
500	   break;
501	case PCI_CHIP_MGA2164:
502	case PCI_CHIP_MGA2164_AGP:
503	case PCI_CHIP_MGA1064:
504	   if (!pMga->NoAccel) {
505		linePitches = xalloc(sizeof(Pitches2));
506		memcpy(linePitches, Pitches2, sizeof(Pitches2));
507		minPitch = maxPitch = 0;
508	   }
509	   break;
510	case PCI_CHIP_MGAG100:
511	case PCI_CHIP_MGAG100_PCI:
512	   maxPitch = 2048;
513	   break;
514	case PCI_CHIP_MGAG200:
515	case PCI_CHIP_MGAG200_PCI:
516	case PCI_CHIP_MGAG200_SE_A_PCI:
517	case PCI_CHIP_MGAG200_SE_B_PCI:
518        case PCI_CHIP_MGAG200_WINBOND_PCI:
519        case PCI_CHIP_MGAG200_EV_PCI:
520        case PCI_CHIP_MGAG200_EH_PCI:
521	case PCI_CHIP_MGAG400:
522	case PCI_CHIP_MGAG550:
523	   maxPitch = 4096;
524	   break;
525	}
526
527        pScrn->modePool=NULL;
528        pScrn->modes = NULL;
529	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
530			      pScrn->display->modes, clockRanges,
531			      linePitches, minPitch, maxPitch,
532			      pMga->Roundings[(pScrn->bitsPerPixel >> 3) - 1] *
533					pScrn->bitsPerPixel, 128, 2048,
534			      pScrn->display->virtualX,
535			      pScrn->display->virtualY,
536			      pMga->FbMapSize,
537			      LOOKUP_BEST_REFRESH);
538
539	if (linePitches)
540	   xfree(linePitches);
541    }
542
543
544    if (i < 1 && pMga->FBDev) {
545	fbdevHWUseBuildinMode(pScrn);
546	pScrn->displayWidth = pScrn->virtualX; /* FIXME: might be wrong */
547	i = 1;
548    }
549    if (i == -1) {
550	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: Validate Modes Failed\n");
551	MGAFreeRec(pScrn);
552	return FALSE;
553    }
554
555    /* Prune the modes marked as invalid */
556    xf86PruneDriverModes(pScrn);
557
558    if (i == 0 || pScrn->modes == NULL) {
559	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: No valid modes found\n");
560	MGAFreeRec(pScrn);
561	return FALSE;
562    }
563#ifdef USEMGAHAL
564    MGA_HAL(
565
566    pMga->pBoard = pMga1->pBoard;
567    pMga->pClientStruct = pMga1->pClientStruct;
568    pMga->pMgaHwInfo = pMga1->pMgaHwInfo;
569
570
571    MGAFillModeInfoStruct(pScrn,NULL);
572    /* Fields usually handled by MGAFillModeInfoStruct, but are unavailable
573     * because no mode is given
574     */
575    pMga->pMgaModeInfo->ulDispWidth = pScrn->virtualX;
576    pMga->pMgaModeInfo->ulDispHeight = pScrn->virtualY;
577
578    if((status = MGAValidateMode(pMga->pBoard,pMga->pMgaModeInfo)) != 0) {
579	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
580		   "MGAValidateMode from HALlib found the mode to be invalid.\n"
581		   "\tError: 0x%lx\n", status);
582        return FALSE;
583    }
584    pScrn->displayWidth = pMga->pMgaModeInfo->ulFBPitch;
585    );	/* MGA_HAL */
586#endif
587
588    /*
589     * Set the CRTC parameters for all of the modes based on the type
590     * of mode, and the chipset's interlace requirements.
591     *
592     * Calling this is required if the mode->Crtc* values are used by the
593     * driver and if the driver doesn't provide code to set them.  They
594     * are not pre-initialised at all.
595     */
596#ifdef USEMGAHAL
597    MGA_HAL(xf86SetCrtcForModes(pScrn, 0));
598#endif
599    MGA_NOT_HAL(xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V));
600
601    /* Set the current mode to the first in the list */
602    pScrn->currentMode = pScrn->modes;
603
604    /* Print the list of modes being used */
605    xf86PrintModes(pScrn);
606
607    /* Set display resolution */
608    xf86SetDpi(pScrn, 0, 0);
609
610    /*
611     * Compute the byte offset into the linear frame buffer where the
612     * frame buffer data should actually begin.  According to DDK misc.c
613     * line 1023, if more than 4MB is to be displayed, YDSTORG must be set
614     * appropriately to align memory bank switching, and this requires a
615     * corresponding offset on linear frame buffer access.
616     * This is only needed for WRAM.
617     */
618
619    pMga->YDstOrg = pMga1->YDstOrg;
620    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "CRTC2: YDstOrg is set to %d\n",
621		   pMga->YDstOrg);
622    pMga->FbUsableSize = pMga1->FbUsableSize;
623    pMga->FbCursorOffset = pMga1->FbCursorOffset;
624
625    pMga->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
626    pMga->CurrentLayout.depth = pScrn->depth;
627    pMga->CurrentLayout.displayWidth = pScrn->displayWidth;
628    pMga->CurrentLayout.weight.red = pScrn->weight.red;
629    pMga->CurrentLayout.weight.green = pScrn->weight.green;
630    pMga->CurrentLayout.weight.blue = pScrn->weight.blue;
631    pMga->CurrentLayout.mode = pScrn->currentMode;
632
633
634    Monitor2Pos = mgaRightOf;
635    if ((s = xf86GetOptValString(pMga1->Options, OPTION_MONITOR2POS))) {
636        switch(s[0]) {
637            case 'L': case 'l': case 'G': case 'g':
638                Monitor2Pos = mgaLeftOf;
639                break;
640            case 'R': case 'r': case 'D': case 'd':
641                Monitor2Pos = mgaRightOf;
642                break;
643
644            case 'A': case 'a': case 'H': case 'h':
645                Monitor2Pos = mgaAbove;
646                break;
647
648            case 'B': case 'b':
649                Monitor2Pos = mgaBelow;
650                break;
651
652            case 'C': case 'c':
653                Monitor2Pos = mgaClone;
654                break;
655            default:
656                Monitor2Pos = mgaRightOf;
657                break;
658        }
659    }
660
661    /* Fool xf86 into thinking we have huge modes */
662    /* Keep the original values somewhere */
663    pMga1->M1modes = pScrn1->modes;
664    pMga1->M1currentMode = pScrn1->currentMode;
665    /* make a copy of the mode list, so we can modify it. */
666    if ((s = xf86GetOptValString(pMga1->Options, OPTION_METAMODES))) {
667        pScrn1->modes = GenerateModeList(pScrn,s,pMga1->M1modes,pScrn->modes,Monitor2Pos); /*FIXME: free this list*/
668        if(!pScrn1->modes) {
669	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Parse Error reading MetaModes, or No modes left.\n");
670            return FALSE;
671        }
672
673        pScrn1->modes = pScrn1->modes->next;
674        pScrn1->currentMode = pScrn1->modes;
675    } else {
676        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MetaModes option missing.\n");
677        return FALSE;
678    }
679    xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== End of second screen initialization ====\n");
680    return TRUE;
681}
682
683void
684MGADisplayPowerManagementSetMerged(ScrnInfoPtr pScrn, int PowerManagementMode,
685				  int flags)
686{
687    MGADisplayPowerManagementSet(pScrn,PowerManagementMode,flags);
688    MGADisplayPowerManagementSetCrtc2(pScrn,PowerManagementMode,flags);
689}
690
691typedef struct _region {
692    int x0,x1,y0,y1;
693    } region;
694
695static Bool
696InRegion(int x, int y, region r) {
697    return (r.x0 <= x) && (x < r.x1) && (r.y0 <= y) && (y < r.y1);
698}
699
700
701#define BOUND(test,low,hi) { \
702    if(test < low) test = low; \
703    if(test > hi) test = hi; }
704#define REBOUND(low,hi,test) { \
705    if(test < low) { \
706        hi += test-low; \
707        low = test; } \
708    if(test > hi) { \
709        low += test-hi; \
710        hi = test; } }
711 void
712MGAMergePointerMoved(int scrnIndex, int x, int y)
713{
714  ScrnInfoPtr   pScr = xf86Screens[scrnIndex];
715  MGAPtr        pMga = MGAPTR(pScr);
716  ScrnInfoPtr   pScr2 = pMga->pScrn2;
717
718  region out,in1,in2,f2,f1;
719
720  int deltax,deltay;
721
722  /* for ease. */
723  f1.x0 = pMga->M1frameX0;
724  f1.x1 = pMga->M1frameX1+1;
725  f1.y0 = pMga->M1frameY0;
726  f1.y1 = pMga->M1frameY1+1;
727  f2.x0 = pScr2->frameX0;
728  f2.x1 = pScr2->frameX1+1;
729  f2.y0 = pScr2->frameY0;
730  f2.y1 = pScr2->frameY1+1;
731
732
733  /*specify outer clipping region. crossing this causes all frames to move*/
734  out.x0 = pScr->frameX0;
735  out.x1 = pScr->frameX1+1;
736  out.y0 = pScr->frameY0;
737  out.y1 = pScr->frameY1+1;
738
739  /*
740   * specify inner sliding window. beeing outsize both frames, and inside
741   * the outer cliping window, causes corresponding frame to slide
742   */
743  in1 = out;
744  in2 = out;
745  switch(((MergedDisplayModePtr)pScr->currentMode->Private)->Monitor2Pos) {
746      case mgaLeftOf :
747          in1.x0 = f1.x0;
748          in2.x1 = f2.x1;
749          break;
750      case mgaRightOf :
751          in1.x1 = f1.x1;
752          in2.x0 = f2.x0;
753          break;
754      case mgaBelow :
755          in1.y1 = f1.y1;
756          in2.y0 = f2.y0;
757          break;
758      case mgaAbove :
759          in1.y0 = f1.y0;
760          in2.y1 = f2.y1;
761          break;
762      case mgaClone :
763          break;
764      }
765
766
767    deltay = 0;
768    deltax = 0;
769
770    if(InRegion(x,y,out)) {
771        if( InRegion(x,y, in1) && !InRegion(x,y, f1) ) {
772            REBOUND(f1.x0,f1.x1,x);
773            REBOUND(f1.y0,f1.y1,y);
774            deltax = 1; /*force frame update */
775        }
776        if( InRegion(x,y, in2) && !InRegion(x,y, f2) ) {
777            REBOUND(f2.x0,f2.x1,x);
778            REBOUND(f2.y0,f2.y1,y);
779            deltax = 1; /*force frame update */
780        }
781    }
782    else {  /*outside outer clipping region*/
783        if ( out.x0 > x) {
784            deltax = x - out.x0;
785        }
786        if ( out.x1 < x) {
787            deltax = x - out.x1;
788        }
789        f1.x0 += deltax;
790        f1.x1 += deltax;
791        f2.x0 += deltax;
792        f2.x1 += deltax;
793        pScr->frameX0 += deltax;
794        pScr->frameX1 += deltax;
795
796
797        if ( out.y0 > y) {
798            deltay = y - out.y0;
799        }
800        if ( out.y1 < y) {
801            deltay = y - out.y1;
802        }
803        f1.y0 += deltay;
804        f1.y1 += deltay;
805        f2.y0 += deltay;
806        f2.y1 += deltay;
807        pScr->frameY0 += deltay;
808        pScr->frameY1 += deltay;
809    }
810
811
812    if (deltax != 0 || deltay != 0) {
813        /* back to reality. */
814        pMga->M1frameX0 = f1.x0;
815        pMga->M1frameY0 = f1.y0;
816        pScr2->frameX0 = f2.x0;
817        pScr2->frameY0 = f2.y0;
818
819        /*Adjust Granularity */
820        MGAAdjustGranularity(pScr,&pMga->M1frameX0,&pMga->M1frameY0);
821        MGAAdjustGranularity(pScr,&pScr2->frameX0,&pScr2->frameY0);
822        MGAAdjustGranularity(pScr,&pScr->frameX0,&pScr->frameY0);
823
824        pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScr)->Monitor1->HDisplay -1;
825        pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScr)->Monitor1->VDisplay -1;
826        pScr2->frameX1 = pScr2->frameX0 + MDMPTR(pScr)->Monitor2->HDisplay -1;
827        pScr2->frameY1 = pScr2->frameY0 + MDMPTR(pScr)->Monitor2->VDisplay -1;
828        pScr->frameX1 = pScr->frameX0 + pScr->currentMode->HDisplay -1;
829        pScr->frameY1 = pScr->frameY0 + pScr->currentMode->VDisplay -1;
830
831        MGAAdjustFrame(pScr->scrnIndex, pMga->M1frameX0, pMga->M1frameY0, 0);
832        MGAAdjustFrameCrtc2(pScr->scrnIndex, pScr2->frameX0, pScr2->frameY0, 0);
833    }
834
835/*  if(pMga->PointerMoved)
836      (*pMga->PointerMoved)(scrnIndex, x, y);  FIXME: do I need to call old func?*/
837
838}
839
840
841void
842MGAAdjustMergeFrames(int scrnIndex, int x, int y, int flags) {
843    ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
844    MGAPtr pMga = MGAPTR(pScrn1);
845    ScrnInfoPtr pScrn2 = pMga->pScrn2;
846    int VTotal = pScrn1->currentMode->VDisplay;
847    int HTotal = pScrn1->currentMode->HDisplay;
848    int VMax = VTotal;
849    int HMax = HTotal;
850
851    BOUND(x,0,pScrn1->virtualX-HTotal);
852    BOUND(y,0,pScrn1->virtualY-VTotal);
853    switch(MDMPTR(pScrn1)->Monitor2Pos) {
854        case mgaLeftOf:
855            pScrn2->frameX0 = x;
856            BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay);
857            pMga->M1frameX0 = x+MDMPTR(pScrn1)->Monitor2->HDisplay;
858            BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay);
859            break;
860        case mgaRightOf:
861            pMga->M1frameX0 = x;
862            BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay);
863            pScrn2->frameX0 = x+MDMPTR(pScrn1)->Monitor1->HDisplay;
864            BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay);
865            break;
866        case mgaAbove:
867            BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay);
868            pScrn2->frameY0 = y;
869            BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay);
870            pMga->M1frameY0 = y+MDMPTR(pScrn1)->Monitor2->VDisplay;
871            break;
872        case mgaBelow:
873            BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay);
874            pMga->M1frameY0 = y;
875            BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay);
876            pScrn2->frameY0 = y+MDMPTR(pScrn1)->Monitor1->VDisplay;
877            break;
878        case mgaClone:
879            BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay);
880            BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay);
881            BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay);
882            BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay);
883            break;
884    }
885    /* sanity checks. Make shure were not out of bounds */
886    BOUND(pMga->M1frameX0,0,pScrn1->virtualX -MDMPTR(pScrn1)->Monitor1->HDisplay);
887    BOUND(pMga->M1frameY0,0,pScrn1->virtualY -MDMPTR(pScrn1)->Monitor1->VDisplay);
888    BOUND(pScrn2->frameX0,0,pScrn2->virtualX -MDMPTR(pScrn1)->Monitor2->HDisplay);
889    BOUND(pScrn2->frameY0,0,pScrn2->virtualY -MDMPTR(pScrn1)->Monitor2->VDisplay);
890
891    pScrn1->frameX0 = x;
892    pScrn1->frameY0 = y;
893
894    /* check granularity */
895    MGAAdjustGranularity(pScrn1,&pMga->M1frameX0,&pMga->M1frameY0);
896    MGAAdjustGranularity(pScrn1,&pScrn2->frameX0,&pScrn2->frameY0);
897    MGAAdjustGranularity(pScrn1,&pScrn1->frameX0,&pScrn1->frameY0);
898
899    /* complete shitty redundant info */
900    pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScrn1)->Monitor1->HDisplay -1;
901    pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScrn1)->Monitor1->VDisplay -1;
902    pScrn2->frameX1 = pScrn2->frameX0 + MDMPTR(pScrn1)->Monitor2->HDisplay -1;
903    pScrn2->frameY1 = pScrn2->frameY0 + MDMPTR(pScrn1)->Monitor2->VDisplay -1;
904    pScrn1->frameX1 = pScrn1->frameX0 + pScrn1->currentMode->HDisplay -1;
905    pScrn1->frameY1 = pScrn1->frameY0 + pScrn1->currentMode->VDisplay -1;
906
907    MGAAdjustFrame(scrnIndex, pMga->M1frameX0, pMga->M1frameY0, flags);
908    MGAAdjustFrameCrtc2(scrnIndex, pScrn2->frameX0, pScrn2->frameY0, flags);
909    return;
910}
911
912Bool
913MGACloseScreenMerged(int scrnIndex, ScreenPtr pScreen) {
914    ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
915    MGAPtr pMga = MGAPTR(pScrn1);
916    ScrnInfoPtr pScrn2 = pMga->pScrn2;
917
918    if(pScrn2) {
919        xfree(pScrn2->monitor);
920        pScrn2->monitor = NULL;
921
922        xfree(pScrn2);
923        pMga->pScrn2 = NULL;
924    }
925
926    if(pScrn1->modes) {
927        pScrn1->currentMode = pScrn1->modes;
928        do {
929            DisplayModePtr p = pScrn1->currentMode->next;
930            if(pScrn1->currentMode->Private)
931                xfree(pScrn1->currentMode->Private);
932            xfree(pScrn1->currentMode);
933            pScrn1->currentMode = p;
934        }while( pScrn1->currentMode != pScrn1->modes);
935    }
936
937    pScrn1->currentMode = pMga->M1currentMode;
938    pScrn1->modes = pMga->M1modes;
939
940    return TRUE;
941}
942
943Bool
944MGASaveScreenMerged(ScreenPtr pScreen, int mode)
945{
946    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
947    MGAPtr pMga = MGAPTR(pScrn);
948    BOOL on = xf86IsUnblank(mode);
949    CARD8 reg;
950
951    if (on) {
952/*        SetTimdeSinceLastInputEvent();*/
953
954        /* power on Dac1 */
955        reg = inMGAdac(MGA1064_MISC_CTL);
956        reg |= MGA1064_MISC_CTL_DAC_EN;
957        outMGAdac(MGA1064_MISC_CTL, reg);
958
959        /* power on Dac2 */
960        reg = inMGAdac(MGA1064_PWR_CTL);
961        reg |= MGA1064_PWR_CTL_DAC2_EN;
962        outMGAdac(MGA1064_PWR_CTL, reg);
963    } else {
964        /* power off Dac1 */
965        reg = inMGAdac(MGA1064_MISC_CTL);
966        reg &= ~MGA1064_MISC_CTL_DAC_EN;
967        outMGAdac(MGA1064_MISC_CTL, reg);
968
969        /* power off Dac2 */
970        reg = inMGAdac(MGA1064_PWR_CTL);
971        reg &= ~MGA1064_PWR_CTL_DAC2_EN;
972        outMGAdac(MGA1064_PWR_CTL, reg);
973    }
974
975    return TRUE;
976}
977
978
979