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