sis_driver.c revision c8409b00
1/*
2 * SiS driver main code
3 *
4 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1) Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2) Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3) The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: Thomas Winischhofer <thomas@winischhofer.net>
29 *	- driver entirely rewritten since 2001, only basic structure taken from
30 *	  old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of
31 *	  sis_dga.c; these were mostly taken over; sis_dri.c was changed for
32 *	  new versions of the DRI layer)
33 *
34 * This notice covers the entire driver code unless indicated otherwise.
35 *
36 * Formerly based on code which was
37 * 	     Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England.
38 * 	     Written by:
39 *           Alan Hourihane <alanh@fairlite.demon.co.uk>,
40 *           Mike Chapman <mike@paranoia.com>,
41 *           Juanjo Santamarta <santamarta@ctv.es>,
42 *           Mitani Hiroshi <hmitani@drl.mei.co.jp>,
43 *           David Thomas <davtom@dream.org.uk>.
44 */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50#include "sis.h"
51
52#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
53#include "xf86RAC.h"
54#endif
55#include "dixstruct.h"
56#include "shadowfb.h"
57#include "fb.h"
58#include "micmap.h"
59#include "mipointer.h"
60#include "mibstore.h"
61#include "edid.h"
62
63#define SIS_NEED_inSISREG
64#define SIS_NEED_inSISIDXREG
65#define SIS_NEED_outSISIDXREG
66#define SIS_NEED_orSISIDXREG
67#define SIS_NEED_andSISIDXREG
68#define SIS_NEED_setSISIDXREG
69#define SIS_NEED_outSISREG
70#define SIS_NEED_MYMMIO
71#define SIS_NEED_sisclearvram
72#include "sis_regs.h"
73#include "sis_dac.h"
74
75#include "sis_driver.h"
76
77#define _XF86DGA_SERVER_
78#include <X11/extensions/xf86dgastr.h>
79
80#include "globals.h"
81
82#ifdef HAVE_XEXTPROTO_71
83#include <X11/extensions/dpmsconst.h>
84#else
85#define DPMS_SERVER
86#include <X11/extensions/dpms.h>
87#endif
88
89#include <inputstr.h>
90
91#ifdef XF86DRI
92#include "dri.h"
93#endif
94
95/* Globals (yes, these ARE really required to be global) */
96
97#ifdef SISUSEDEVPORT
98int 		sisdevport = 0;
99#endif
100
101#ifdef SISDUALHEAD
102static int	SISEntityIndex = -1;
103#endif
104
105#ifdef SISMERGED
106#ifdef SISXINERAMA
107static Bool 		SiSnoPanoramiXExtension = TRUE;
108static int		SiSXineramaNumScreens = 0;
109static SiSXineramaData	*SiSXineramadataPtr = NULL;
110static int		SiSXineramaGeneration;
111
112static int SiSProcXineramaQueryVersion(ClientPtr client);
113static int SiSProcXineramaGetState(ClientPtr client);
114static int SiSProcXineramaGetScreenCount(ClientPtr client);
115static int SiSProcXineramaGetScreenSize(ClientPtr client);
116static int SiSProcXineramaIsActive(ClientPtr client);
117static int SiSProcXineramaQueryScreens(ClientPtr client);
118static int SiSSProcXineramaDispatch(ClientPtr client);
119#endif
120#endif
121
122/*
123 * This is intentionally screen-independent.  It indicates the binding
124 * choice made in the first PreInit.
125 */
126static int pix24bpp = 0;
127
128/*
129 * This contains the functions needed by the server after loading the driver
130 * module.  It must be supplied, and gets passed back by the SetupProc
131 * function in the dynamic case.  In the static case, a reference to this
132 * is compiled in, and this requires that the name of this DriverRec be
133 * an upper-case version of the driver name.
134 */
135
136#ifdef _X_EXPORT
137_X_EXPORT
138#endif
139DriverRec SIS = {
140    SIS_CURRENT_VERSION,
141    SIS_DRIVER_NAME,
142    SISIdentify,
143    SISProbe,
144    SISAvailableOptions,
145    NULL,
146    0
147#ifdef SIS_HAVE_DRIVER_FUNC
148     ,
149    SISDriverFunc
150#endif
151};
152
153static SymTabRec SISChipsets[] = {
154    { PCI_CHIP_SIS5597,     "SIS5597/5598" },
155    { PCI_CHIP_SIS530,      "SIS530/620" },
156    { PCI_CHIP_SIS6326,     "SIS6326/AGP/DVD" },
157    { PCI_CHIP_SIS300,      "SIS300/305" },
158    { PCI_CHIP_SIS630,      "SIS630/730" },
159    { PCI_CHIP_SIS540,      "SIS540" },
160    { PCI_CHIP_SIS315,      "SIS315" },
161    { PCI_CHIP_SIS315H,     "SIS315H" },
162    { PCI_CHIP_SIS315PRO,   "SIS315PRO/E" },
163    { PCI_CHIP_SIS550,	    "SIS550" },
164    { PCI_CHIP_SIS650,      "SIS650/M650/651/740" },
165    { PCI_CHIP_SIS330,      "SIS330(Xabre)" },
166    { PCI_CHIP_SIS660,      "SIS660/[M]661[F|M]X/[M]670/[M]741[GX]/[M]760[GX]/[M]761[GX]/[M]770[GX]" },
167    { PCI_CHIP_SIS340,      "SIS340" },
168    { -1,                   NULL }
169};
170
171static PciChipsets SISPciChipsets[] = {
172    { PCI_CHIP_SIS5597,     PCI_CHIP_SIS5597,   RES_SHARED_VGA },
173    { PCI_CHIP_SIS530,      PCI_CHIP_SIS530,    RES_SHARED_VGA },
174    { PCI_CHIP_SIS6326,     PCI_CHIP_SIS6326,   RES_SHARED_VGA },
175    { PCI_CHIP_SIS300,      PCI_CHIP_SIS300,    RES_SHARED_VGA },
176    { PCI_CHIP_SIS630,      PCI_CHIP_SIS630,    RES_SHARED_VGA },
177    { PCI_CHIP_SIS540,      PCI_CHIP_SIS540,    RES_SHARED_VGA },
178    { PCI_CHIP_SIS550,      PCI_CHIP_SIS550,    RES_SHARED_VGA },
179    { PCI_CHIP_SIS315,      PCI_CHIP_SIS315,    RES_SHARED_VGA },
180    { PCI_CHIP_SIS315H,     PCI_CHIP_SIS315H,   RES_SHARED_VGA },
181    { PCI_CHIP_SIS315PRO,   PCI_CHIP_SIS315PRO, RES_SHARED_VGA },
182    { PCI_CHIP_SIS650,      PCI_CHIP_SIS650,    RES_SHARED_VGA },
183    { PCI_CHIP_SIS330,      PCI_CHIP_SIS330,    RES_SHARED_VGA },
184    { PCI_CHIP_SIS660,      PCI_CHIP_SIS660,    RES_SHARED_VGA },
185    { PCI_CHIP_SIS340,      PCI_CHIP_SIS340,    RES_SHARED_VGA },
186    { -1,                   -1,                 RES_UNDEFINED }
187};
188
189static SymTabRec XGIChipsets[] = {
190    { PCI_CHIP_XGIXG20,     "Volari Z7 (XG20)" },
191    { PCI_CHIP_XGIXG40,     "Volari V3XT/V5/V8/Duo (XG40)" },
192    { -1,                   NULL }
193};
194
195static PciChipsets XGIPciChipsets[] = {
196    { PCI_CHIP_XGIXG20,     PCI_CHIP_XGIXG20,   RES_SHARED_VGA },
197    { PCI_CHIP_XGIXG40,     PCI_CHIP_XGIXG40,   RES_SHARED_VGA },
198    { -1,                   -1,                 RES_UNDEFINED }
199};
200
201#ifdef XFree86LOADER
202
203static MODULESETUPPROTO(sisSetup);
204
205static XF86ModuleVersionInfo sisVersRec =
206{
207    SIS_DRIVER_NAME,
208    MODULEVENDORSTRING,
209    MODINFOSTRING1,
210    MODINFOSTRING2,
211#ifdef XORG_VERSION_CURRENT
212    XORG_VERSION_CURRENT,
213#else
214    XF86_VERSION_CURRENT,
215#endif
216    SIS_MAJOR_VERSION, SIS_MINOR_VERSION, SIS_PATCHLEVEL,
217    ABI_CLASS_VIDEODRV,         /* This is a video driver */
218    ABI_VIDEODRV_VERSION,
219    MOD_CLASS_VIDEODRV,
220    {0,0,0,0}
221};
222
223#ifdef _X_EXPORT
224_X_EXPORT
225#endif
226XF86ModuleData sisModuleData = { &sisVersRec, sisSetup, NULL };
227
228pointer
229sisSetup(pointer module, pointer opts, int *errmaj, int *errmin)
230{
231    static Bool setupDone = FALSE;
232
233    if(!setupDone) {
234       setupDone = TRUE;
235       xf86AddDriver(&SIS, module, SIS_HaveDriverFuncs);
236       return (pointer)TRUE;
237    }
238
239    if(errmaj) *errmaj = LDR_ONCEONLY;
240    return NULL;
241}
242
243#endif /* XFree86LOADER */
244
245/* Mandatory */
246static void
247SISIdentify(int flags)
248{
249    xf86PrintChipsets(SIS_NAME, "driver for SiS chipsets", SISChipsets);
250    xf86PrintChipsets(SIS_NAME, "driver for XGI chipsets", XGIChipsets);
251}
252
253#ifdef SIS_HAVE_DRIVER_FUNC
254static Bool
255SISDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
256{
257    CARD32 *flag;
258
259    switch(op) {
260    case RR_GET_INFO:
261	break;
262    case RR_SET_CONFIG:
263	break;
264    case GET_REQUIRED_HW_INTERFACES:
265	break;
266    }
267    return TRUE;
268}
269#endif
270
271static Bool
272SISGetRec(ScrnInfoPtr pScrn)
273{
274    /* Allocate an SISRec, and hook it into pScrn->driverPrivate.
275     * pScrn->driverPrivate is initialised to NULL, so we can check if
276     * the allocation has already been done.
277     */
278    if(pScrn->driverPrivate != NULL) return TRUE;
279
280    pScrn->driverPrivate = xnfcalloc(sizeof(SISRec), 1);
281
282    /* Initialise it to 0 */
283    memset(pScrn->driverPrivate, 0, sizeof(SISRec));
284
285    return TRUE;
286}
287
288static void
289SISFreeRec(ScrnInfoPtr pScrn)
290{
291    SISPtr pSiS = SISPTR(pScrn);
292#ifdef SISDUALHEAD
293    SISEntPtr pSiSEnt = NULL;
294#endif
295
296    /* Just to make sure... */
297    if(!pSiS) return;
298
299#ifdef SISDUALHEAD
300    pSiSEnt = pSiS->entityPrivate;
301#endif
302
303    if(pSiS->pstate) xfree(pSiS->pstate);
304    pSiS->pstate = NULL;
305    if(pSiS->fonts) xfree(pSiS->fonts);
306    pSiS->fonts = NULL;
307
308#ifdef SISDUALHEAD
309    if(pSiSEnt) {
310       if(!pSiS->SecondHead) {
311	  /* Free memory only if we are first head; in case of an error
312	   * during init of the second head, the server will continue -
313	   * and we need the BIOS image and SiS_Private for the first
314	   * head.
315	   */
316	  if(pSiSEnt->BIOS) xfree(pSiSEnt->BIOS);
317	  pSiSEnt->BIOS = pSiS->BIOS = NULL;
318	  if(pSiSEnt->SiS_Pr) xfree(pSiSEnt->SiS_Pr);
319	  pSiSEnt->SiS_Pr = pSiS->SiS_Pr = NULL;
320	  if(pSiSEnt->RenderAccelArray) xfree(pSiSEnt->RenderAccelArray);
321	  pSiSEnt->RenderAccelArray = pSiS->RenderAccelArray = NULL;
322	  pSiSEnt->pScrn_1 = NULL;
323       } else {
324	  pSiS->BIOS = NULL;
325	  pSiS->SiS_Pr = NULL;
326	  pSiS->RenderAccelArray = NULL;
327	  pSiSEnt->pScrn_2 = NULL;
328       }
329    } else {
330#endif
331       if(pSiS->BIOS) xfree(pSiS->BIOS);
332       pSiS->BIOS = NULL;
333       if(pSiS->SiS_Pr) xfree(pSiS->SiS_Pr);
334       pSiS->SiS_Pr = NULL;
335       if(pSiS->RenderAccelArray) xfree(pSiS->RenderAccelArray);
336       pSiS->RenderAccelArray = NULL;
337#ifdef SISDUALHEAD
338    }
339#endif
340#ifdef SISMERGED
341    if(pSiS->CRT2HSync) xfree(pSiS->CRT2HSync);
342    pSiS->CRT2HSync = NULL;
343    if(pSiS->CRT2VRefresh) xfree(pSiS->CRT2VRefresh);
344    pSiS->CRT2VRefresh = NULL;
345    if(pSiS->MetaModes) xfree(pSiS->MetaModes);
346    pSiS->MetaModes = NULL;
347    if(pSiS->CRT2pScrn) {
348       if(pSiS->CRT2pScrn->modes) {
349	  while(pSiS->CRT2pScrn->modes)
350	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
351       }
352       if(pSiS->CRT2pScrn->monitor) {
353	  if(pSiS->CRT2pScrn->monitor->Modes) {
354	     while(pSiS->CRT2pScrn->monitor->Modes)
355	        xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
356	  }
357	  if(pSiS->CRT2pScrn->monitor->DDC) xfree(pSiS->CRT2pScrn->monitor->DDC);
358	  xfree(pSiS->CRT2pScrn->monitor);
359       }
360       xfree(pSiS->CRT2pScrn);
361       pSiS->CRT2pScrn = NULL;
362    }
363    if(pSiS->CRT1Modes) {
364       if(pSiS->CRT1Modes != pScrn->modes) {
365	  if(pScrn->modes) {
366	     pScrn->currentMode = pScrn->modes;
367	     do {
368	        DisplayModePtr p = pScrn->currentMode->next;
369	        if(pScrn->currentMode->Private)
370	 	  xfree(pScrn->currentMode->Private);
371	        xfree(pScrn->currentMode);
372	        pScrn->currentMode = p;
373	     } while(pScrn->currentMode != pScrn->modes);
374	  }
375	  pScrn->currentMode = pSiS->CRT1CurrentMode;
376	  pScrn->modes = pSiS->CRT1Modes;
377	  pSiS->CRT1CurrentMode = NULL;
378	  pSiS->CRT1Modes = NULL;
379       }
380    }
381#endif
382    while(pSiS->SISVESAModeList) {
383       sisModeInfoPtr mp = pSiS->SISVESAModeList->next;
384       xfree(pSiS->SISVESAModeList);
385       pSiS->SISVESAModeList = mp;
386    }
387    if(pSiS->pVbe) vbeFree(pSiS->pVbe);
388    pSiS->pVbe = NULL;
389
390#ifdef SISUSEDEVPORT
391    if(pSiS->sisdevportopen)   close(sisdevport);
392#endif
393
394    if(pScrn->driverPrivate == NULL)
395        return;
396    xfree(pScrn->driverPrivate);
397    pScrn->driverPrivate = NULL;
398}
399
400static void
401SISErrorLog(ScrnInfoPtr pScrn, const char *format, ...)
402{
403    va_list ap;
404    static const char *str = "**************************************************\n";
405
406    va_start(ap, format);
407    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
408    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
409	"                      ERROR:\n");
410    xf86VDrvMsgVerb(pScrn->scrnIndex, X_ERROR, 1, format, ap);
411    va_end(ap);
412    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
413	"                  END OF MESSAGE\n");
414    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
415}
416
417static void
418SiS_SiSFB_Lock(ScrnInfoPtr pScrn, Bool lock)
419{
420    SISPtr  pSiS = SISPTR(pScrn);
421    int     fd;
422    CARD32  parm;
423
424    if(!pSiS->sisfbfound) return;
425    if(!pSiS->sisfb_havelock) return;
426
427    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
428       parm = lock ? 1 : 0;
429       ioctl(fd, SISFB_SET_LOCK, &parm);
430       close(fd);
431    }
432}
433
434/* Probe()
435 *
436 * Mandatory
437 */
438static Bool
439SISProbe(DriverPtr drv, int flags)
440{
441    int     i;
442    GDevPtr *devSections;
443    int     *usedChipsSiS, *usedChipsXGI;
444    int     numDevSections;
445    int     numUsed, numUsedSiS, numUsedXGI;
446    Bool    foundScreen = FALSE;
447
448    /*
449     * The aim here is to find all cards that this driver can handle,
450     * and for the ones not already claimed by another driver, claim the
451     * slot, and allocate a ScrnInfoRec.
452     *
453     * This should be a minimal probe, and it should under no circumstances
454     * change the state of the hardware.  Because a device is found, don't
455     * assume that it will be used.  Don't do any initialisations other than
456     * the required ScrnInfoRec initialisations.  Don't allocate any new
457     * data structures.
458     *
459     */
460
461    /*
462     * Next we check, if there has been a chipset override in the config file.
463     * For this we must find out if there is an active device section which
464     * is relevant, i.e., which has no driver specified or has THIS driver
465     * specified.
466     */
467
468    if((numDevSections = xf86MatchDevice(SIS_DRIVER_NAME, &devSections)) <= 0) {
469       /*
470        * There's no matching device section in the config file, so quit
471        * now.
472        */
473       return FALSE;
474    }
475
476    /*
477     * We need to probe the hardware first.  We then need to see how this
478     * fits in with what is given in the config file, and allow the config
479     * file info to override any contradictions.
480     */
481
482    /*
483     * All of the cards this driver supports are PCI, so the "probing" just
484     * amounts to checking the PCI data that the server has already collected.
485     */
486#ifndef XSERVER_LIBPCIACCESS
487    if(xf86GetPciVideoInfo() == NULL) {
488       /*
489        * We won't let anything in the config file override finding no
490        * PCI video cards at all.
491        */
492       return FALSE;
493    }
494#endif
495
496    numUsedSiS = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_SIS,
497			SISChipsets, SISPciChipsets, devSections,
498			numDevSections, drv, &usedChipsSiS);
499
500    numUsedXGI = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_XGI,
501			XGIChipsets, XGIPciChipsets, devSections,
502			numDevSections, drv, &usedChipsXGI);
503
504    /* Free it since we don't need that list after this */
505    xfree(devSections);
506
507    numUsed = numUsedSiS + numUsedXGI;
508
509    if(numUsed <= 0)
510       return FALSE;
511
512    if(flags & PROBE_DETECT) {
513
514	foundScreen = TRUE;
515
516    } else for(i = 0; i < numUsed; i++) {
517
518	ScrnInfoPtr pScrn;
519#ifdef SISDUALHEAD
520	EntityInfoPtr pEnt;
521#endif
522
523	/* Allocate a ScrnInfoRec and claim the slot */
524	pScrn = NULL;
525
526	if((pScrn = xf86ConfigPciEntity(pScrn, 0,
527			(i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS],
528			(i < numUsedSiS) ? SISPciChipsets  : XGIPciChipsets,
529			NULL, NULL, NULL, NULL, NULL))) {
530	    /* Fill in what we can of the ScrnInfoRec */
531	    pScrn->driverVersion    = SIS_CURRENT_VERSION;
532	    pScrn->driverName       = SIS_DRIVER_NAME;
533	    pScrn->name             = SIS_NAME;
534	    pScrn->Probe            = SISProbe;
535	    pScrn->PreInit          = SISPreInit;
536	    pScrn->ScreenInit       = SISScreenInit;
537	    pScrn->SwitchMode       = SISSwitchMode;
538	    pScrn->AdjustFrame      = SISAdjustFrame;
539	    pScrn->EnterVT          = SISEnterVT;
540	    pScrn->LeaveVT          = SISLeaveVT;
541	    pScrn->FreeScreen       = SISFreeScreen;
542	    pScrn->ValidMode        = SISValidMode;
543
544	    foundScreen = TRUE;
545	}
546
547#ifdef SISDUALHEAD
548	pEnt = xf86GetEntityInfo((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
549
550	if(pEnt->chipset == PCI_CHIP_SIS630 || pEnt->chipset == PCI_CHIP_SIS540 ||
551	   pEnt->chipset == PCI_CHIP_SIS650 || pEnt->chipset == PCI_CHIP_SIS550 ||
552	   pEnt->chipset == PCI_CHIP_SIS315 || pEnt->chipset == PCI_CHIP_SIS315H ||
553	   pEnt->chipset == PCI_CHIP_SIS315PRO || pEnt->chipset == PCI_CHIP_SIS330 ||
554	   pEnt->chipset == PCI_CHIP_SIS300 || pEnt->chipset == PCI_CHIP_SIS660 ||
555	   pEnt->chipset == PCI_CHIP_SIS340 || pEnt->chipset == PCI_CHIP_XGIXG40) {
556
557	    SISEntPtr pSiSEnt = NULL;
558	    DevUnion  *pPriv;
559
560	    xf86SetEntitySharable((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
561	    if(SISEntityIndex < 0) {
562	       SISEntityIndex = xf86AllocateEntityPrivateIndex();
563	    }
564	    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex);
565	    if(!pPriv->ptr) {
566	       pPriv->ptr = xnfcalloc(sizeof(SISEntRec), 1);
567	       pSiSEnt = pPriv->ptr;
568	       memset(pSiSEnt, 0, sizeof(SISEntRec));
569	       pSiSEnt->lastInstance = -1;
570	    } else {
571	       pSiSEnt = pPriv->ptr;
572	    }
573	    pSiSEnt->lastInstance++;
574	    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
575	                                   pSiSEnt->lastInstance);
576	}
577#endif /* DUALHEAD */
578
579    }
580
581    if(usedChipsSiS) xfree(usedChipsSiS);
582    if(usedChipsXGI) xfree(usedChipsXGI);
583
584    return foundScreen;
585}
586
587/* Various helpers */
588
589static unsigned short
590calcgammaval(int j, int nramp, float invgamma, float bri, float c)
591{
592    float k = (float)j;
593    float nrm1 = (float)(nramp - 1);
594    float con = c * nrm1 / 3.0;
595    float l, v;
596
597    if(con != 0.0) {
598       l = nrm1 / 2.0;
599       if(con <= 0.0) {
600          k -= l;
601          k *= (l + con) / l;
602       } else {
603          l -= 1.0;
604          k -= l;
605          k *= l / (l - con);
606       }
607       k += l;
608       if(k < 0.0) k = 0.0;
609    }
610
611    if(invgamma == 1.0) {
612       v = k / nrm1 * 65535.0;
613    } else {
614       v = pow(k / nrm1, invgamma) * 65535.0 + 0.5;
615    }
616
617    v += (bri * (65535.0 / 3.0)) ;
618
619    if(v < 0.0) v = 0.0;
620    else if(v > 65535.0) v = 65535.0;
621
622    return (unsigned short)v;
623}
624
625#ifdef SISGAMMARAMP
626void
627SISCalculateGammaRamp(ScreenPtr pScreen, ScrnInfoPtr pScrn)
628{
629   SISPtr pSiS = SISPTR(pScrn);
630   int    i, j, nramp;
631   UShort *ramp[3];
632   float  gamma_max[3], framp;
633   Bool   newmethod = FALSE;
634
635   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
636      newmethod = TRUE;
637   } else {
638      gamma_max[0] = (float)pSiS->GammaBriR / 1000;
639      gamma_max[1] = (float)pSiS->GammaBriG / 1000;
640      gamma_max[2] = (float)pSiS->GammaBriB / 1000;
641   }
642
643   if(!(nramp = xf86GetGammaRampSize(pScreen))) return;
644
645   for(i=0; i<3; i++) {
646      ramp[i] = (UShort *)xalloc(nramp * sizeof(UShort));
647      if(!ramp[i]) {
648	 if(ramp[0]) { xfree(ramp[0]); ramp[0] = NULL; }
649	 if(ramp[1]) { xfree(ramp[1]); ramp[1] = NULL; }
650	 return;
651      }
652   }
653
654   if(newmethod) {
655
656      for(i = 0; i < 3; i++) {
657
658         float invgamma = 0.0, bri = 0.0, con = 0.0;
659
660         switch(i) {
661         case 0: invgamma = 1. / pScrn->gamma.red;
662		 bri = pSiS->NewGammaBriR;
663		 con = pSiS->NewGammaConR;
664		 break;
665         case 1: invgamma = 1. / pScrn->gamma.green;
666		 bri = pSiS->NewGammaBriG;
667		 con = pSiS->NewGammaConG;
668		 break;
669         case 2: invgamma = 1. / pScrn->gamma.blue;
670		 bri = pSiS->NewGammaBriB;
671                 con = pSiS->NewGammaConB;
672		 break;
673         }
674
675	 for(j = 0; j < nramp; j++) {
676	    ramp[i][j] = calcgammaval(j, nramp, invgamma, bri, con);
677	 }
678
679      }
680
681   } else {
682
683      for(i = 0; i < 3; i++) {
684         int fullscale = 65535 * gamma_max[i];
685         float dramp = 1. / (nramp - 1);
686         float invgamma = 0.0, v;
687
688         switch(i) {
689         case 0: invgamma = 1. / pScrn->gamma.red; break;
690         case 1: invgamma = 1. / pScrn->gamma.green; break;
691         case 2: invgamma = 1. / pScrn->gamma.blue; break;
692         }
693
694         for(j = 0; j < nramp; j++) {
695	    framp = pow(j * dramp, invgamma);
696
697	    v = (fullscale < 0) ? (65535 + fullscale * framp) :
698			       fullscale * framp;
699	    if(v < 0) v = 0;
700	    else if(v > 65535) v = 65535;
701	    ramp[i][j] = (UShort)v;
702         }
703      }
704
705   }
706
707   xf86ChangeGammaRamp(pScreen, nramp, ramp[0], ramp[1], ramp[2]);
708
709   xfree(ramp[0]);
710   xfree(ramp[1]);
711   xfree(ramp[2]);
712   ramp[0] = ramp[1] = ramp[2] = NULL;
713}
714#endif
715
716void
717SISCalculateGammaRampCRT2(ScrnInfoPtr pScrn)
718{
719   SISPtr pSiS = SISPTR(pScrn);
720   int    i;
721   int    myshift = 16 - pScrn->rgbBits;
722   int    maxvalue = (1 << pScrn->rgbBits) - 1;
723   int    reds = pScrn->mask.red >> pScrn->offset.red;
724   int    greens = pScrn->mask.green >> pScrn->offset.green;
725   int    blues = pScrn->mask.blue >> pScrn->offset.blue;
726   float  framp, invgamma1, invgamma2, invgamma3, v;
727
728   invgamma1  = 1. / pSiS->GammaR2;
729   invgamma2  = 1. / pSiS->GammaG2;
730   invgamma3  = 1. / pSiS->GammaB2;
731
732   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
733
734      for(i = 0; i < pSiS->CRT2ColNum; i++) {
735         pSiS->crt2gcolortable[i].red = calcgammaval(i, pSiS->CRT2ColNum, invgamma1,
736			pSiS->NewGammaBriR2, pSiS->NewGammaConR2) >> myshift;
737         pSiS->crt2gcolortable[i].green = calcgammaval(i, pSiS->CRT2ColNum, invgamma2,
738			pSiS->NewGammaBriG2, pSiS->NewGammaConG2) >> myshift;
739         pSiS->crt2gcolortable[i].blue = calcgammaval(i, pSiS->CRT2ColNum, invgamma3,
740			pSiS->NewGammaBriB2, pSiS->NewGammaConB2) >> myshift;
741      }
742
743   } else {
744
745      int fullscale1 = 65536 * (float)pSiS->GammaBriR2 / 1000;
746      int fullscale2 = 65536 * (float)pSiS->GammaBriG2 / 1000;
747      int fullscale3 = 65536 * (float)pSiS->GammaBriB2 / 1000;
748
749      float dramp = 1. / (pSiS->CRT2ColNum - 1);
750
751      for(i = 0; i < pSiS->CRT2ColNum; i++) {
752         framp = pow(i * dramp, invgamma1);
753         v = (fullscale1 < 0) ? (65535 + fullscale1 * framp) : fullscale1 * framp;
754         if(v < 0) v = 0;
755         else if(v > 65535) v = 65535;
756         pSiS->crt2gcolortable[i].red = ((UShort)v) >> myshift;
757         framp = pow(i * dramp, invgamma2);
758         v = (fullscale2 < 0) ? (65535 + fullscale2 * framp) : fullscale2 * framp;
759         if(v < 0) v = 0;
760         else if(v > 65535) v = 65535;
761         pSiS->crt2gcolortable[i].green = ((UShort)v) >> myshift;
762         framp = pow(i * dramp, invgamma3);
763         v = (fullscale3 < 0) ? (65535 + fullscale3 * framp) : fullscale3 * framp;
764         if(v < 0) v = 0;
765         else if(v > 65535) v = 65535;
766         pSiS->crt2gcolortable[i].blue = ((UShort)v) >> myshift;
767      }
768
769   }
770
771   for(i = 0; i < pSiS->CRT2ColNum; i++) {
772      pSiS->crt2colors[i].red =
773         pSiS->crt2gcolortable[i * maxvalue / reds].red;
774      pSiS->crt2colors[i].green =
775         pSiS->crt2gcolortable[i * maxvalue / greens].green;
776      pSiS->crt2colors[i].blue  =
777         pSiS->crt2gcolortable[i * maxvalue / blues].blue;
778   }
779}
780
781/* If monitor section has no HSync/VRefresh data,
782 * derive it from DDC data.
783 */
784static void
785SiSSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
786{
787   MonPtr      mon = pScrn->monitor;
788   xf86MonPtr  ddc = mon->DDC;
789   float       myhhigh = 0.0, myhlow = 0.0, htest;
790   int         myvhigh = 0, myvlow = 0, vtest, i;
791   UChar temp;
792   const myhddctiming myhtiming[12] = {
793       { 1, 0x20, 31.6 }, /* rounded up by .1 */
794       { 1, 0x80, 31.6 },
795       { 1, 0x02, 35.3 },
796       { 1, 0x04, 37.6 },
797       { 1, 0x08, 38.0 },
798       { 1, 0x01, 38.0 },
799       { 2, 0x40, 47.0 },
800       { 2, 0x80, 48.2 },
801       { 2, 0x08, 48.5 },
802       { 2, 0x04, 56.6 },
803       { 2, 0x02, 60.1 },
804       { 2, 0x01, 80.1 }
805   };
806   const myvddctiming myvtiming[11] = {
807       { 1, 0x02, 56 },
808       { 1, 0x01, 60 },
809       { 2, 0x08, 60 },
810       { 2, 0x04, 70 },
811       { 1, 0x80, 71 },
812       { 1, 0x08, 72 },
813       { 2, 0x80, 72 },
814       { 1, 0x04, 75 },
815       { 2, 0x40, 75 },
816       { 2, 0x02, 75 },
817       { 2, 0x01, 75 }
818   };
819
820   if(flag) { /* HSync */
821
822      for(i = 0; i < 4; i++) {
823	 if(ddc->det_mon[i].type == DS_RANGES) {
824	    mon->nHsync = 1;
825	    mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h;
826	    mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h;
827	    if(mon->hsync[0].lo > 32.0 || mon->hsync[0].hi < 31.0) {
828	       if(ddc->timings1.t1 & 0x80) {
829		  mon->nHsync++;
830		  mon->hsync[1].lo = 31.0;
831		  mon->hsync[1].hi = 32.0;
832	       }
833	    }
834	    return;
835	 }
836      }
837
838      /* If no sync ranges detected in detailed timing table, we
839       * derive them from supported VESA modes.
840       */
841
842      for(i = 0; i < 12; i++) {
843	 if(myhtiming[i].whichone == 1) temp = ddc->timings1.t1;
844	 else                           temp = ddc->timings1.t2;
845	 if(temp & myhtiming[i].mask) {
846	    if((i == 0) || (myhlow > myhtiming[i].rate))
847	       myhlow = myhtiming[i].rate;
848	 }
849	 if(myhtiming[11-i].whichone == 1) temp = ddc->timings1.t1;
850	 else                              temp = ddc->timings1.t2;
851	 if(temp & myhtiming[11-i].mask) {
852	    if((i == 0) || (myhhigh < myhtiming[11-i].rate))
853	       myhhigh = myhtiming[11-i].rate;
854	 }
855      }
856
857      for(i = 0; i < STD_TIMINGS; i++) {
858	 if(ddc->timings2[i].hsize > 256) {
859	    htest = ddc->timings2[i].refresh * 1.05 * ddc->timings2[i].vsize / 1000.0;
860	    if(htest < myhlow)  myhlow  = htest;
861	    if(htest > myhhigh) myhhigh = htest;
862	 }
863      }
864
865      if((myhhigh > 0.0) && (myhlow > 0.0)) {
866	 mon->nHsync = 1;
867	 mon->hsync[0].lo = myhlow - 0.1;
868	 mon->hsync[0].hi = myhhigh;
869      }
870
871
872   } else {  /* Vrefresh */
873
874      for(i = 0; i < 4; i++) {
875         if(ddc->det_mon[i].type == DS_RANGES) {
876	    mon->nVrefresh = 1;
877	    mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v;
878	    mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v;
879	    if(mon->vrefresh[0].lo > 72 || mon->vrefresh[0].hi < 70) {
880	       if(ddc->timings1.t1 & 0x80) {
881		  mon->nVrefresh++;
882		  mon->vrefresh[1].lo = 71;
883		  mon->vrefresh[1].hi = 71;
884	       }
885	    }
886	    return;
887         }
888      }
889
890      for(i = 0; i < 11; i++) {
891	 if(myvtiming[i].whichone == 1) temp = ddc->timings1.t1;
892	 else                           temp = ddc->timings1.t2;
893	 if(temp & myvtiming[i].mask) {
894	    if((i == 0) || (myvlow > myvtiming[i].rate))
895	       myvlow = myvtiming[i].rate;
896	 }
897	 if(myvtiming[10-i].whichone == 1) temp = ddc->timings1.t1;
898	 else                              temp = ddc->timings1.t2;
899	 if(temp & myvtiming[10-i].mask) {
900	    if((i == 0) || (myvhigh < myvtiming[10-i].rate))
901	       myvhigh = myvtiming[10-i].rate;
902	 }
903      }
904
905      for(i = 0; i < STD_TIMINGS; i++) {
906	 if(ddc->timings2[i].hsize > 256) {
907	    vtest = ddc->timings2[i].refresh;
908	    if(vtest < myvlow)  myvlow  = vtest;
909	    if(vtest > myvhigh) myvhigh = vtest;
910	 }
911      }
912
913      if((myvhigh > 0) && (myvlow > 0)) {
914	 mon->nVrefresh = 1;
915	 mon->vrefresh[0].lo = myvlow;
916	 mon->vrefresh[0].hi = myvhigh;
917      }
918
919   }
920}
921
922static Bool
923SiSAllowSyncOverride(SISPtr pSiS, Bool fromDDC)
924{
925   if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
926
927#ifdef SISDUALHEAD
928   if(pSiS->DualHeadMode) {
929      if(pSiS->SecondHead) {
930         if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
931      } else {
932         if((pSiS->VBFlags & CRT2_TV) ||
933	    ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC))) return TRUE;
934      }
935      return FALSE;
936   }
937#endif
938
939#ifdef SISMERGED
940   if(pSiS->MergedFB) {
941      if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
942      return FALSE;
943   }
944#endif
945
946   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
947      if( (pSiS->VBFlags & CRT2_TV) ||
948	  ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) return TRUE;
949   } else if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
950
951   return FALSE;
952}
953
954static Bool
955SiSCheckForH(float hsync, MonPtr monitor)
956{
957   int i;
958   for(i = 0; i < monitor->nHsync; i++) {
959      if((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) &&
960	 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE)))
961	 break;
962   }
963   if(i == monitor->nHsync) return FALSE;
964   return TRUE;
965}
966
967static Bool
968SiSCheckForV(float vrefresh, MonPtr monitor)
969{
970   int i;
971   for(i = 0; i < monitor->nVrefresh; i++) {
972      if((vrefresh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) &&
973	 (vrefresh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE)))
974	 break;
975   }
976   if(i == monitor->nVrefresh) return FALSE;
977   return TRUE;
978}
979
980static Bool
981CheckAndOverruleH(ScrnInfoPtr pScrn, MonPtr monitor)
982{
983   DisplayModePtr mode = monitor->Modes;
984   float mymin = 30.0, mymax = 80.0, hsync;
985   Bool doit = FALSE;
986
987   for(hsync = mymin; hsync <= mymax; hsync += .5) {
988      if(!SiSCheckForH(hsync, monitor)) doit = TRUE;
989   }
990
991   if(mode) {
992      do {
993         if(mode->type & M_T_BUILTIN) {
994	    hsync = (float)mode->Clock / (float)mode->HTotal;
995	    if(!SiSCheckForH(hsync, monitor)) {
996	       doit = TRUE;
997	       if(hsync < mymin) mymin = hsync;
998	       if(hsync > mymax) mymax = hsync;
999	    }
1000	 }
1001      } while((mode = mode->next));
1002   }
1003
1004   if(doit) {
1005      monitor->nHsync = 1;
1006      monitor->hsync[0].lo = mymin;
1007      monitor->hsync[0].hi = mymax;
1008      return TRUE;
1009   }
1010
1011   return FALSE;
1012}
1013
1014static Bool
1015CheckAndOverruleV(ScrnInfoPtr pScrn, MonPtr monitor)
1016{
1017   DisplayModePtr mode = monitor->Modes;
1018   float mymin = 59.0, mymax = 61.0, vrefresh;
1019   Bool doit = FALSE, ret = FALSE;
1020
1021   for(vrefresh = mymin; vrefresh <= mymax; vrefresh += 1.0) {
1022      if(!SiSCheckForV(vrefresh, monitor)) doit = TRUE;
1023   }
1024
1025   if(mode) {
1026      do {
1027         if(mode->type & M_T_BUILTIN) {
1028	    vrefresh = mode->Clock * 1000.0 / (mode->HTotal * mode->VTotal);
1029	    if(mode->Flags & V_INTERLACE) vrefresh *= 2.0;
1030	    if(mode->Flags & V_DBLSCAN) vrefresh /= 2.0;
1031	    if(!SiSCheckForH(vrefresh, monitor)) {
1032	       doit = TRUE;
1033	       if(vrefresh < mymin) mymin = vrefresh;
1034	       if(vrefresh > mymax) mymax = vrefresh;
1035	    }
1036	 }
1037      } while((mode = mode->next));
1038   }
1039
1040   if(doit) {
1041      monitor->nVrefresh = 1;
1042      monitor->vrefresh[0].lo = mymin;
1043      monitor->vrefresh[0].hi = mymax;
1044      ret = TRUE;
1045   }
1046
1047   /* special for 640x400/320x200/@70Hz (VGA/IBM 720x480) */
1048   if( (!SiSCheckForV(71, monitor)) &&
1049       (monitor->nVrefresh < MAX_VREFRESH) ) {
1050      monitor->vrefresh[monitor->nVrefresh].lo = 71;
1051      monitor->vrefresh[monitor->nVrefresh].hi = 71;
1052      monitor->nVrefresh++;
1053      ret = TRUE;
1054   }
1055   return ret;
1056}
1057
1058/* Some helper functions for MergedFB mode */
1059
1060#ifdef SISMERGED
1061
1062/* Helper function for CRT2 monitor vrefresh/hsync options
1063 * (Code base from mga driver)
1064 */
1065static int
1066SiSStrToRanges(range *r, char *s, int max)
1067{
1068   float num = 0.0;
1069   int rangenum = 0;
1070   Bool gotdash = FALSE;
1071   Bool nextdash = FALSE;
1072   char *strnum = NULL;
1073   do {
1074      switch(*s) {
1075      case '0':
1076      case '1':
1077      case '2':
1078      case '3':
1079      case '4':
1080      case '5':
1081      case '6':
1082      case '7':
1083      case '8':
1084      case '9':
1085      case '.':
1086         if(strnum == NULL) {
1087            strnum = s;
1088            gotdash = nextdash;
1089            nextdash = FALSE;
1090         }
1091         break;
1092      case '-':
1093      case ' ':
1094      case 0:
1095         if(strnum == NULL) break;
1096         sscanf(strnum, "%f", &num);
1097	 strnum = NULL;
1098         if(gotdash) {
1099            r[rangenum - 1].hi = num;
1100         } else {
1101            r[rangenum].lo = num;
1102            r[rangenum].hi = num;
1103            rangenum++;
1104         }
1105         if(*s == '-') nextdash = (rangenum != 0);
1106	 else if(rangenum >= max) return rangenum;
1107         break;
1108      default:
1109         return 0;
1110      }
1111
1112   } while(*(s++) != 0);
1113
1114   return rangenum;
1115}
1116
1117/* Copy and link two modes (i, j) for mergedfb mode
1118 * (Code base taken from mga driver)
1119 *
1120 * - Copy mode i, merge j to copy of i, link the result to dest
1121 * - Link i and j in private record.
1122 * - If dest is NULL, return value is copy of i linked to itself.
1123 * - For mergedfb auto-config, we only check the dimension
1124 *   against virtualX/Y, if they were user-provided.
1125 * - No special treatment required for CRTxxOffs.
1126 * - Provide fake dotclock in order to distinguish between similar
1127 *   looking MetaModes (for RandR and VidMode extensions)
1128 * - Set unique VRefresh of dest mode for RandR
1129 */
1130static DisplayModePtr
1131SiSCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
1132                 DisplayModePtr i, DisplayModePtr j,
1133		 SiSScrn2Rel srel)
1134{
1135    SISPtr pSiS = SISPTR(pScrn);
1136    DisplayModePtr mode;
1137    int dx = 0,dy = 0;
1138
1139    if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest;
1140    memcpy(mode, i, sizeof(DisplayModeRec));
1141    if(!((mode->Private = xalloc(sizeof(SiSMergedDisplayModeRec))))) {
1142       xfree(mode);
1143       return dest;
1144    }
1145    ((SiSMergedDisplayModePtr)mode->Private)->CRT1 = i;
1146    ((SiSMergedDisplayModePtr)mode->Private)->CRT2 = j;
1147    ((SiSMergedDisplayModePtr)mode->Private)->CRT2Position = srel;
1148    mode->PrivSize = 0;
1149
1150    switch(srel) {
1151    case sisLeftOf:
1152    case sisRightOf:
1153       if(!(pScrn->display->virtualX)) {
1154          dx = i->HDisplay + j->HDisplay;
1155       } else {
1156          dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
1157       }
1158       dx -= mode->HDisplay;
1159       if(!(pScrn->display->virtualY)) {
1160          dy = max(i->VDisplay, j->VDisplay);
1161       } else {
1162          dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1163       }
1164       dy -= mode->VDisplay;
1165       break;
1166    case sisAbove:
1167    case sisBelow:
1168       if(!(pScrn->display->virtualY)) {
1169          dy = i->VDisplay + j->VDisplay;
1170       } else {
1171          dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
1172       }
1173       dy -= mode->VDisplay;
1174       if(!(pScrn->display->virtualX)) {
1175          dx = max(i->HDisplay, j->HDisplay);
1176       } else {
1177          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1178       }
1179       dx -= mode->HDisplay;
1180       break;
1181    case sisClone:
1182       if(!(pScrn->display->virtualX)) {
1183          dx = max(i->HDisplay, j->HDisplay);
1184       } else {
1185          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1186       }
1187       dx -= mode->HDisplay;
1188       if(!(pScrn->display->virtualY)) {
1189          dy = max(i->VDisplay, j->VDisplay);
1190       } else {
1191	  dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1192       }
1193       dy -= mode->VDisplay;
1194       break;
1195    }
1196    mode->HDisplay += dx;
1197    mode->HSyncStart += dx;
1198    mode->HSyncEnd += dx;
1199    mode->HTotal += dx;
1200    mode->VDisplay += dy;
1201    mode->VSyncStart += dy;
1202    mode->VSyncEnd += dy;
1203    mode->VTotal += dy;
1204
1205    mode->type = M_T_DEFAULT;
1206#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,2,0)
1207    /* Set up as user defined (ie fake that the mode has been named in the
1208     * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+]
1209     * when source mode has not been listed there.)
1210     */
1211    mode->type |= M_T_USERDEF;
1212#endif
1213
1214    /* Set the VRefresh field (in order to make RandR use it for the rates). We
1215     * simply set this to the refresh rate for the CRT1 mode (since CRT2 will
1216     * mostly be LCD or TV anyway).
1217     */
1218    mode->VRefresh = SiSCalcVRate(i);
1219
1220    if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > pSiS->maxxfbmem) ||
1221	(mode->HDisplay > 4088) ||
1222	(mode->VDisplay > 4096) ) {
1223
1224       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1225		"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
1226		mode->name, mode->HDisplay, mode->VDisplay);
1227       xfree(mode->Private);
1228       xfree(mode);
1229
1230       return dest;
1231    }
1232
1233#ifdef SISXINERAMA
1234    if(srel != sisClone) {
1235       pSiS->AtLeastOneNonClone = TRUE;
1236    }
1237#endif
1238
1239    /* Now see if the resulting mode would be discarded as a "size" by the
1240     * RandR extension, and increase its clock by 1000 in case it does.
1241     */
1242    if(dest) {
1243       DisplayModePtr t = dest;
1244       do {
1245          if((t->HDisplay == mode->HDisplay) &&
1246	     (t->VDisplay == mode->VDisplay) &&
1247	     ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) {
1248	     mode->VRefresh += 1000.0;
1249	  }
1250	  t = t->next;
1251       } while((t) && (t != dest));
1252    }
1253
1254    /* Provide a fake but unique DotClock in order to trick the vidmode
1255     * extension to allow selecting among a number of modes whose merged result
1256     * looks identical but consists of different modes for CRT1 and CRT2
1257     */
1258    mode->Clock = (int)(mode->VRefresh * 1000.0);
1259
1260    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1261	"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)%s\n",
1262	i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
1263	mode->HDisplay, mode->VDisplay, (int)mode->VRefresh,
1264	(srel == sisClone) ? " (Clone)" : "");
1265
1266    mode->next = mode;
1267    mode->prev = mode;
1268
1269    if(dest) {
1270       mode->next = dest->next; 	/* Insert node after "dest" */
1271       dest->next->prev = mode;
1272       mode->prev = dest;
1273       dest->next = mode;
1274    }
1275
1276    return mode;
1277}
1278
1279/* Helper function to find a mode from a given name
1280 * (Code base taken from mga driver)
1281 */
1282static DisplayModePtr
1283SiSGetModeFromName(char* str, DisplayModePtr i)
1284{
1285    DisplayModePtr c = i;
1286    if(!i) return NULL;
1287    do {
1288       if(strcmp(str, c->name) == 0) return c;
1289       c = c->next;
1290    } while(c != i);
1291    return NULL;
1292}
1293
1294static DisplayModePtr
1295SiSFindWidestTallestMode(DisplayModePtr i, Bool tallest)
1296{
1297    DisplayModePtr c = i, d = NULL;
1298    int max = 0;
1299    if(!i) return NULL;
1300    do {
1301       if(tallest) {
1302          if(c->VDisplay > max) {
1303	     max = c->VDisplay;
1304	     d = c;
1305          }
1306       } else {
1307          if(c->HDisplay > max) {
1308	     max = c->HDisplay;
1309	     d = c;
1310          }
1311       }
1312       c = c->next;
1313    } while(c != i);
1314    return d;
1315}
1316
1317static void
1318SiSFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
1319				DisplayModePtr *a, DisplayModePtr *b)
1320{
1321    DisplayModePtr c = i, d;
1322    int max = 0;
1323    Bool foundone;
1324
1325    (*a) = (*b) = NULL;
1326
1327    if(!i || !j) return;
1328
1329    do {
1330       d = j;
1331       foundone = FALSE;
1332       do {
1333	  if( (c->HDisplay == d->HDisplay) &&
1334	      (c->VDisplay == d->VDisplay) ) {
1335	     foundone = TRUE;
1336	     break;
1337	  }
1338	  d = d->next;
1339       } while(d != j);
1340       if(foundone) {
1341	  if(tallest) {
1342	     if(c->VDisplay > max) {
1343		max = c->VDisplay;
1344		(*a) = c;
1345		(*b) = d;
1346	     }
1347	  } else {
1348	     if(c->HDisplay > max) {
1349		max = c->HDisplay;
1350		(*a) = c;
1351		(*b) = d;
1352	     }
1353	  }
1354       }
1355       c = c->next;
1356    } while(c != i);
1357}
1358
1359static DisplayModePtr
1360SiSGenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
1361		    DisplayModePtr i, DisplayModePtr j,
1362		    SiSScrn2Rel srel)
1363{
1364#ifdef SISXINERAMA
1365    SISPtr pSiS = SISPTR(pScrn);
1366#endif
1367    DisplayModePtr mode1 = NULL;
1368    DisplayModePtr mode2 = NULL;
1369    DisplayModePtr mode3 = NULL;
1370    DisplayModePtr mode4 = NULL;
1371    DisplayModePtr result = NULL;
1372
1373#ifdef SISXINERAMA
1374    pSiS->AtLeastOneNonClone = FALSE;
1375#endif
1376
1377    /* Now build a default list of MetaModes.
1378     * - Non-clone: If the user enabled NonRectangular, we use the
1379     * largest mode for each CRT1 and CRT2. If not, we use the largest
1380     * common mode for CRT1 and CRT2 (if available). Additionally, and
1381     * regardless if the above, we produce a clone mode consisting of
1382     * the largest common mode (if available) in order to use DGA.
1383     * - Clone: If the (global) CRT2Position is Clone, we use the
1384     * largest common mode if available, otherwise the first two modes
1385     * in each list.
1386     */
1387
1388    switch(srel) {
1389    case sisLeftOf:
1390    case sisRightOf:
1391       mode1 = SiSFindWidestTallestMode(i, FALSE);
1392       mode2 = SiSFindWidestTallestMode(j, FALSE);
1393       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1394       break;
1395    case sisAbove:
1396    case sisBelow:
1397       mode1 = SiSFindWidestTallestMode(i, TRUE);
1398       mode2 = SiSFindWidestTallestMode(j, TRUE);
1399       SiSFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
1400       break;
1401    case sisClone:
1402       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1403       if(mode3 && mode4) {
1404	  mode1 = mode3;
1405	  mode2 = mode4;
1406       } else {
1407	  mode1 = i;
1408	  mode2 = j;
1409       }
1410    }
1411
1412    if(srel != sisClone) {
1413       if(mode3 && mode4 && !pSiS->NonRect) {
1414	  mode1 = mode3;
1415	  mode2 = mode2;
1416       }
1417    }
1418
1419    if(mode1 && mode2) {
1420       result = SiSCopyModeNLink(pScrn, result, mode1, mode2, srel);
1421    }
1422
1423    if(srel != sisClone) {
1424       if(mode3 && mode4) {
1425	  result = SiSCopyModeNLink(pScrn, result, mode3, mode4, sisClone);
1426       }
1427    }
1428
1429    return result;
1430}
1431
1432/* Generate the merged-fb mode modelist
1433 * (Taken from mga driver)
1434 */
1435static DisplayModePtr
1436SiSGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
1437		    DisplayModePtr i, DisplayModePtr j,
1438		    SiSScrn2Rel srel)
1439{
1440#ifdef SISXINERAMA
1441    SISPtr pSiS = SISPTR(pScrn);
1442#endif
1443    char* strmode = str;
1444    char modename[256];
1445    Bool gotdash = FALSE;
1446    char gotsep = 0;
1447    SiSScrn2Rel sr;
1448    DisplayModePtr mode1 = NULL;
1449    DisplayModePtr mode2 = NULL;
1450    DisplayModePtr result = NULL;
1451    int myslen;
1452
1453#ifdef SISXINERAMA
1454    pSiS->AtLeastOneNonClone = FALSE;
1455#endif
1456
1457    do {
1458        switch(*str) {
1459        case 0:
1460        case '-':
1461	case '+':
1462        case ' ':
1463	case ',':
1464	case ';':
1465           if(strmode != str) {
1466
1467              myslen = str - strmode;
1468              if(myslen > 255) myslen = 255;
1469  	      strncpy(modename, strmode, myslen);
1470  	      modename[myslen] = 0;
1471
1472              if(gotdash) {
1473                 if(mode1 == NULL) {
1474  	             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1475  	                        "Error parsing MetaModes parameter\n");
1476  	             return NULL;
1477  	         }
1478                 mode2 = SiSGetModeFromName(modename, j);
1479                 if(!mode2) {
1480                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1481                        "Mode \"%s\" is not a supported mode for CRT2\n", modename);
1482                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1483                        "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
1484                    mode1 = NULL;
1485		    gotsep = 0;
1486                 }
1487              } else {
1488                 mode1 = SiSGetModeFromName(modename, i);
1489                 if(!mode1) {
1490                    char* tmps = str;
1491                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1492                        "Mode \"%s\" is not a supported mode for CRT1\n", modename);
1493                    while(*tmps == ' ' || *tmps == ';') tmps++;
1494                    /* skip the next mode */
1495  	            if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
1496                       tmps++;
1497		       /* skip spaces */
1498		       while(*tmps == ' ' || *tmps == ';') tmps++;
1499		       /* skip modename */
1500		       while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
1501  	               myslen = tmps - strmode;
1502  	               if(myslen > 255) myslen = 255;
1503  	               strncpy(modename,strmode,myslen);
1504  	               modename[myslen] = 0;
1505                       str = tmps - 1;
1506                    }
1507                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1508                        "\t(Skipping metamode \"%s\")\n", modename);
1509                    mode1 = NULL;
1510		    gotsep = 0;
1511                 }
1512              }
1513              gotdash = FALSE;
1514           }
1515           strmode = str + 1;
1516           gotdash |= (*str == '-' || *str == '+' || *str == ',');
1517	   if (*str == '-' || *str == '+' || *str == ',')
1518  	      gotsep = *str;
1519
1520           if(*str != 0) break;
1521	   /* Fall through otherwise */
1522
1523        default:
1524           if(!gotdash && mode1) {
1525              sr = srel;
1526	      if(gotsep == '+') sr = sisClone;
1527              if(!mode2) {
1528                 mode2 = SiSGetModeFromName(mode1->name, j);
1529                 sr = sisClone;
1530              }
1531              if(!mode2) {
1532                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1533                     "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name);
1534                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1535                     "\t(Skipping metamode \"%s\")\n", modename);
1536                 mode1 = NULL;
1537              } else {
1538                 result = SiSCopyModeNLink(pScrn, result, mode1, mode2, sr);
1539                 mode1 = NULL;
1540                 mode2 = NULL;
1541              }
1542	      gotsep = 0;
1543           }
1544           break;
1545
1546        }
1547
1548    } while(*(str++) != 0);
1549
1550    return result;
1551}
1552
1553static DisplayModePtr
1554SiSGenerateModeList(ScrnInfoPtr pScrn, char* str,
1555		    DisplayModePtr i, DisplayModePtr j,
1556		    SiSScrn2Rel srel)
1557{
1558   SISPtr pSiS = SISPTR(pScrn);
1559
1560   if(str != NULL) {
1561      return(SiSGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
1562   } else {
1563      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1564	"No MetaModes given, linking %s modes by default\n",
1565	(srel == sisClone) ? "largest common" :
1566	   (pSiS->NonRect ?
1567		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest" :  "tallest")
1568		:
1569		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest common" :  "tallest common")) );
1570      return(SiSGenerateModeListFromLargestModes(pScrn, i, j, srel));
1571   }
1572}
1573
1574static void
1575SiSRecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
1576{
1577    SISPtr pSiS = SISPTR(pScrn);
1578    DisplayModePtr mode, bmode;
1579    int maxh, maxv;
1580    static const char *str = "MergedFB: Virtual %s %d\n";
1581    static const char *errstr = "Virtual %s to small for given CRT2Position offset\n";
1582
1583    mode = bmode = pScrn->modes;
1584    maxh = maxv = 0;
1585    do {
1586       if(mode->HDisplay > maxh) maxh = mode->HDisplay;
1587       if(mode->VDisplay > maxv) maxv = mode->VDisplay;
1588       mode = mode->next;
1589    } while(mode != bmode);
1590
1591    maxh += pSiS->CRT1XOffs + pSiS->CRT2XOffs;
1592    maxv += pSiS->CRT1YOffs + pSiS->CRT2YOffs;
1593
1594    if(!(pScrn->display->virtualX)) {
1595       if(maxh > 4088) {
1596	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1597		"Virtual width with CRT2Position offset beyond hardware specs\n");
1598	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1599	  maxh -= (pSiS->CRT1XOffs + pSiS->CRT2XOffs);
1600       }
1601       pScrn->virtualX = maxh;
1602       pScrn->displayWidth = maxh;
1603       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
1604    } else {
1605       if(maxh < pScrn->display->virtualX) {
1606	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
1607	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1608       }
1609    }
1610
1611    if(!(pScrn->display->virtualY)) {
1612       pScrn->virtualY = maxv;
1613       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
1614    } else {
1615       if(maxv < pScrn->display->virtualY) {
1616	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
1617	  pSiS->CRT1YOffs = pSiS->CRT2YOffs = 0;
1618       }
1619    }
1620}
1621
1622static void
1623SiSMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, SiSScrn2Rel srel)
1624{
1625   SISPtr pSiS = SISPTR(pScrn1);
1626   MessageType from = X_DEFAULT;
1627   xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC);
1628   xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC);
1629   int ddcWidthmm = 0, ddcHeightmm = 0;
1630   const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n";
1631
1632   /* This sets the DPI for MergedFB mode. The problem is that
1633    * this can never be exact, because the output devices may
1634    * have different dimensions. This function tries to compromise
1635    * through a few assumptions, and it just calculates an average DPI
1636    * value for both monitors.
1637    */
1638
1639   /* Given DisplaySize should regard BOTH monitors */
1640   pScrn1->widthmm = pScrn1->monitor->widthmm;
1641   pScrn1->heightmm = pScrn1->monitor->heightmm;
1642
1643   /* Get DDC display size; if only either CRT1 or CRT2 provided these,
1644    * assume equal dimensions for both, otherwise add dimensions
1645    */
1646   if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) &&
1647       (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) {
1648      ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10;
1649      ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10;
1650      switch(srel) {
1651      case sisLeftOf:
1652      case sisRightOf:
1653	 ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10;
1654	 break;
1655      case sisAbove:
1656      case sisBelow:
1657	 ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10;
1658      default:
1659	 break;
1660      }
1661   } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) {
1662      ddcWidthmm = DDC1->features.hsize * 10;
1663      ddcHeightmm = DDC1->features.vsize * 10;
1664      switch(srel) {
1665      case sisLeftOf:
1666      case sisRightOf:
1667	 ddcWidthmm *= 2;
1668	 break;
1669      case sisAbove:
1670      case sisBelow:
1671	 ddcHeightmm *= 2;
1672      default:
1673	 break;
1674      }
1675   } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) {
1676      ddcWidthmm = DDC2->features.hsize * 10;
1677      ddcHeightmm = DDC2->features.vsize * 10;
1678      switch(srel) {
1679      case sisLeftOf:
1680      case sisRightOf:
1681	 ddcWidthmm *= 2;
1682	 break;
1683      case sisAbove:
1684      case sisBelow:
1685	 ddcHeightmm *= 2;
1686      default:
1687	 break;
1688      }
1689   }
1690
1691   if(monitorResolution > 0) {
1692
1693      /* Set command line given values (overrules given options) */
1694      pScrn1->xDpi = monitorResolution;
1695      pScrn1->yDpi = monitorResolution;
1696      from = X_CMDLINE;
1697
1698   } else if(pSiS->MergedFBXDPI) {
1699
1700      /* Set option-wise given values (overrule DisplaySize) */
1701      pScrn1->xDpi = pSiS->MergedFBXDPI;
1702      pScrn1->yDpi = pSiS->MergedFBYDPI;
1703      from = X_CONFIG;
1704
1705   } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) {
1706
1707      /* Set values calculated from given DisplaySize */
1708      from = X_CONFIG;
1709      if(pScrn1->widthmm > 0) {
1710	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1711      }
1712      if(pScrn1->heightmm > 0) {
1713	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1714      }
1715      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm);
1716
1717    } else if(ddcWidthmm && ddcHeightmm) {
1718
1719      /* Set values from DDC-provided display size */
1720      from = X_PROBED;
1721      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm );
1722      pScrn1->widthmm = ddcWidthmm;
1723      pScrn1->heightmm = ddcHeightmm;
1724      if(pScrn1->widthmm > 0) {
1725	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1726      }
1727      if(pScrn1->heightmm > 0) {
1728	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1729      }
1730
1731    } else {
1732
1733      pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI;
1734
1735    }
1736
1737    /* Sanity check */
1738    if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0)
1739       pScrn1->yDpi = pScrn1->xDpi;
1740    if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0)
1741       pScrn1->xDpi = pScrn1->yDpi;
1742
1743    pScrn2->xDpi = pScrn1->xDpi;
1744    pScrn2->yDpi = pScrn1->yDpi;
1745
1746    xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n",
1747		pScrn1->xDpi, pScrn1->yDpi);
1748}
1749
1750/* Pseudo-Xinerama extension for MergedFB mode */
1751#ifdef SISXINERAMA
1752
1753static void
1754SiSUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
1755{
1756    SISPtr pSiS = SISPTR(pScrn1);
1757    int crt1scrnnum = 0, crt2scrnnum = 1;
1758    int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
1759    int realvirtX, realvirtY;
1760    DisplayModePtr currentMode, firstMode;
1761    Bool infochanged = FALSE;
1762    Bool usenonrect = pSiS->NonRect;
1763    const char *rectxine = "\t... setting up rectangular Xinerama layout\n";
1764
1765    pSiS->MBXNR1XMAX = pSiS->MBXNR1YMAX = pSiS->MBXNR2XMAX = pSiS->MBXNR2YMAX = 65536;
1766    pSiS->HaveNonRect = pSiS->HaveOffsRegions = FALSE;
1767
1768    if(!pSiS->MergedFB) return;
1769
1770    if(SiSnoPanoramiXExtension) return;
1771
1772    if(!SiSXineramadataPtr) return;
1773
1774    if(pSiS->CRT2IsScrn0) {
1775       crt1scrnnum = 1;
1776       crt2scrnnum = 0;
1777    }
1778
1779    /* Attention: Usage of RandR may lead to virtual X and Y dimensions
1780     * actually smaller than our MetaModes. To avoid this, we calculate
1781     * the maxCRT fields here (and not somewhere else, like in CopyNLink)
1782     *
1783     * *** Note: RandR is disabled if one of CRTxxOffs is non-zero.
1784     */
1785
1786    /* "Real" virtual: Virtual without the Offset */
1787    realvirtX = pScrn1->virtualX - pSiS->CRT1XOffs - pSiS->CRT2XOffs;
1788    realvirtY = pScrn1->virtualY - pSiS->CRT1YOffs - pSiS->CRT2YOffs;
1789
1790    if((pSiS->SiSXineramaVX != pScrn1->virtualX) || (pSiS->SiSXineramaVY != pScrn1->virtualY)) {
1791
1792       if(!(pScrn1->modes)) return;
1793
1794       pSiS->maxCRT1_X1 = pSiS->maxCRT1_X2 = 0;
1795       pSiS->maxCRT1_Y1 = pSiS->maxCRT1_Y2 = 0;
1796       pSiS->maxCRT2_X1 = pSiS->maxCRT2_X2 = 0;
1797       pSiS->maxCRT2_Y1 = pSiS->maxCRT2_Y2 = 0;
1798       pSiS->maxClone_X1 = pSiS->maxClone_X2 = 0;
1799       pSiS->maxClone_Y1 = pSiS->maxClone_Y2 = 0;
1800
1801       currentMode = firstMode = pScrn1->modes;
1802
1803       do {
1804
1805          DisplayModePtr p = currentMode->next;
1806          DisplayModePtr i = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT1;
1807          DisplayModePtr j = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2;
1808          SiSScrn2Rel srel = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2Position;
1809
1810          if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
1811	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
1812	     (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
1813
1814	     if(srel != sisClone) {
1815		if(pSiS->maxCRT1_X1 == i->HDisplay) {
1816		   if(pSiS->maxCRT1_X2 < j->HDisplay) {
1817		      pSiS->maxCRT1_X2 = j->HDisplay;   /* Widest CRT2 mode displayed with widest CRT1 mode */
1818		   }
1819		} else if(pSiS->maxCRT1_X1 < i->HDisplay) {
1820		   pSiS->maxCRT1_X1 = i->HDisplay;      /* Widest CRT1 mode */
1821		   pSiS->maxCRT1_X2 = j->HDisplay;
1822		}
1823		if(pSiS->maxCRT2_X2 == j->HDisplay) {
1824		   if(pSiS->maxCRT2_X1 < i->HDisplay) {
1825		      pSiS->maxCRT2_X1 = i->HDisplay;   /* Widest CRT1 mode displayed with widest CRT2 mode */
1826		   }
1827		} else if(pSiS->maxCRT2_X2 < j->HDisplay) {
1828		   pSiS->maxCRT2_X2 = j->HDisplay;      /* Widest CRT2 mode */
1829		   pSiS->maxCRT2_X1 = i->HDisplay;
1830		}
1831		if(pSiS->maxCRT1_Y1 == i->VDisplay) {   /* Same as above, but tallest instead of widest */
1832		   if(pSiS->maxCRT1_Y2 < j->VDisplay) {
1833		      pSiS->maxCRT1_Y2 = j->VDisplay;
1834		   }
1835		} else if(pSiS->maxCRT1_Y1 < i->VDisplay) {
1836		   pSiS->maxCRT1_Y1 = i->VDisplay;
1837		   pSiS->maxCRT1_Y2 = j->VDisplay;
1838		}
1839		if(pSiS->maxCRT2_Y2 == j->VDisplay) {
1840		   if(pSiS->maxCRT2_Y1 < i->VDisplay) {
1841		      pSiS->maxCRT2_Y1 = i->VDisplay;
1842		   }
1843		} else if(pSiS->maxCRT2_Y2 < j->VDisplay) {
1844		   pSiS->maxCRT2_Y2 = j->VDisplay;
1845		   pSiS->maxCRT2_Y1 = i->VDisplay;
1846		}
1847	     } else {
1848		if(pSiS->maxClone_X1 < i->HDisplay) {
1849		   pSiS->maxClone_X1 = i->HDisplay;
1850		}
1851		if(pSiS->maxClone_X2 < j->HDisplay) {
1852		   pSiS->maxClone_X2 = j->HDisplay;
1853		}
1854		if(pSiS->maxClone_Y1 < i->VDisplay) {
1855		   pSiS->maxClone_Y1 = i->VDisplay;
1856		}
1857		if(pSiS->maxClone_Y2 < j->VDisplay) {
1858		   pSiS->maxClone_Y2 = j->VDisplay;
1859		}
1860	     }
1861	  }
1862	  currentMode = p;
1863
1864       } while((currentMode) && (currentMode != firstMode));
1865
1866       pSiS->SiSXineramaVX = pScrn1->virtualX;
1867       pSiS->SiSXineramaVY = pScrn1->virtualY;
1868       infochanged = TRUE;
1869
1870    }
1871
1872    if((usenonrect) && (pSiS->CRT2Position != sisClone) && pSiS->maxCRT1_X1) {
1873       switch(pSiS->CRT2Position) {
1874       case sisLeftOf:
1875       case sisRightOf:
1876	  if((pSiS->maxCRT1_Y1 != realvirtY) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1877	     usenonrect = FALSE;
1878	  }
1879	  break;
1880       case sisAbove:
1881       case sisBelow:
1882	  if((pSiS->maxCRT1_X1 != realvirtX) && (pSiS->maxCRT2_X2 != realvirtX)) {
1883	     usenonrect = FALSE;
1884	  }
1885	  break;
1886       case sisClone:
1887	  break;
1888       }
1889       if(infochanged && !usenonrect) {
1890	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1891			"Virtual screen size does not match maximum display modes...\n");
1892	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
1893
1894       }
1895    } else if(infochanged && usenonrect) {
1896       usenonrect = FALSE;
1897       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
1898		"Only clone modes available for this virtual screen size...\n");
1899       xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
1900    }
1901
1902    if(pSiS->maxCRT1_X1) {		/* Means we have at least one non-clone mode */
1903       switch(pSiS->CRT2Position) {
1904       case sisLeftOf:
1905	  x1 = min(pSiS->maxCRT1_X2, pScrn1->virtualX - pSiS->maxCRT1_X1);
1906	  if(x1 < 0) x1 = 0;
1907	  y1 = pSiS->CRT1YOffs;
1908	  w1 = pScrn1->virtualX - x1;
1909	  h1 = realvirtY;
1910	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1911	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1912	     pSiS->NonRectDead.x0 = x1;
1913	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1914	     pSiS->NonRectDead.y0 = y1 + h1;
1915	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1916	     pSiS->HaveNonRect = TRUE;
1917	  }
1918	  x2 = 0;
1919	  y2 = pSiS->CRT2YOffs;
1920	  w2 = max(pSiS->maxCRT2_X2, pScrn1->virtualX - pSiS->maxCRT2_X1);
1921	  if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
1922	  h2 = realvirtY;
1923	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1924	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1925	     pSiS->NonRectDead.x0 = x2;
1926	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1927	     pSiS->NonRectDead.y0 = y2 + h2;
1928	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1929	     pSiS->HaveNonRect = TRUE;
1930	  }
1931	  break;
1932       case sisRightOf:
1933	  x1 = 0;
1934	  y1 = pSiS->CRT1YOffs;
1935	  w1 = max(pSiS->maxCRT1_X1, pScrn1->virtualX - pSiS->maxCRT1_X2);
1936	  if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
1937	  h1 = realvirtY;
1938	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
1939	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
1940	     pSiS->NonRectDead.x0 = x1;
1941	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
1942	     pSiS->NonRectDead.y0 = y1 + h1;
1943	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1944	     pSiS->HaveNonRect = TRUE;
1945	  }
1946	  x2 = min(pSiS->maxCRT2_X1, pScrn1->virtualX - pSiS->maxCRT2_X2);
1947	  if(x2 < 0) x2 = 0;
1948	  y2 = pSiS->CRT2YOffs;
1949	  w2 = pScrn1->virtualX - x2;
1950	  h2 = realvirtY;
1951	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
1952	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
1953	     pSiS->NonRectDead.x0 = x2;
1954	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
1955	     pSiS->NonRectDead.y0 = y2 + h2;
1956	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
1957	     pSiS->HaveNonRect = TRUE;
1958	  }
1959	  break;
1960       case sisAbove:
1961	  x1 = pSiS->CRT1XOffs;
1962	  y1 = min(pSiS->maxCRT1_Y2, pScrn1->virtualY - pSiS->maxCRT1_Y1);
1963	  if(y1 < 0) y1 = 0;
1964	  w1 = realvirtX;
1965	  h1 = pScrn1->virtualY - y1;
1966	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
1967	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
1968	     pSiS->NonRectDead.x0 = x1 + w1;
1969	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1970	     pSiS->NonRectDead.y0 = y1;
1971	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
1972	     pSiS->HaveNonRect = TRUE;
1973	  }
1974	  x2 = pSiS->CRT2XOffs;
1975	  y2 = 0;
1976	  w2 = realvirtX;
1977	  h2 = max(pSiS->maxCRT2_Y2, pScrn1->virtualY - pSiS->maxCRT2_Y1);
1978	  if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
1979	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
1980	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
1981	     pSiS->NonRectDead.x0 = x2 + w2;
1982	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1983	     pSiS->NonRectDead.y0 = y2;
1984	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
1985	     pSiS->HaveNonRect = TRUE;
1986	  }
1987	  break;
1988       case sisBelow:
1989	  x1 = pSiS->CRT1XOffs;
1990	  y1 = 0;
1991	  w1 = realvirtX;
1992	  h1 = max(pSiS->maxCRT1_Y1, pScrn1->virtualY - pSiS->maxCRT1_Y2);
1993	  if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
1994	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
1995	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
1996	     pSiS->NonRectDead.x0 = x1 + w1;
1997	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
1998	     pSiS->NonRectDead.y0 = y1;
1999	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
2000	     pSiS->HaveNonRect = TRUE;
2001	  }
2002	  x2 = pSiS->CRT2XOffs;
2003	  y2 = min(pSiS->maxCRT2_Y1, pScrn1->virtualY - pSiS->maxCRT2_Y2);
2004	  if(y2 < 0) y2 = 0;
2005	  w2 = realvirtX;
2006	  h2 = pScrn1->virtualY - y2;
2007	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2008	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2009	     pSiS->NonRectDead.x0 = x2 + w2;
2010	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2011	     pSiS->NonRectDead.y0 = y2;
2012	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2013	     pSiS->HaveNonRect = TRUE;
2014	  }
2015       default:
2016	  break;
2017       }
2018
2019       switch(pSiS->CRT2Position) {
2020       case sisLeftOf:
2021       case sisRightOf:
2022	  if(pSiS->CRT1YOffs) {
2023	     pSiS->OffDead1.x0 = x1;
2024	     pSiS->OffDead1.x1 = x1 + w1 - 1;
2025	     pSiS->OffDead1.y0 = 0;
2026	     pSiS->OffDead1.y1 = y1 - 1;
2027	     pSiS->OffDead2.x0 = x2;
2028	     pSiS->OffDead2.x1 = x2 + w2 - 1;
2029	     pSiS->OffDead2.y0 = y2 + h2;
2030	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2031	     pSiS->HaveOffsRegions = TRUE;
2032	  } else if(pSiS->CRT2YOffs) {
2033	     pSiS->OffDead1.x0 = x2;
2034	     pSiS->OffDead1.x1 = x2 + w2 - 1;
2035	     pSiS->OffDead1.y0 = 0;
2036	     pSiS->OffDead1.y1 = y2 - 1;
2037	     pSiS->OffDead2.x0 = x1;
2038	     pSiS->OffDead2.x1 = x1 + w1 - 1;
2039	     pSiS->OffDead2.y0 = y1 + h1;
2040	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2041	     pSiS->HaveOffsRegions = TRUE;
2042	  }
2043	  break;
2044       case sisAbove:
2045       case sisBelow:
2046	  if(pSiS->CRT1XOffs) {
2047	     pSiS->OffDead1.x0 = x2 + w2;
2048	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2049	     pSiS->OffDead1.y0 = y2;
2050	     pSiS->OffDead1.y1 = y2 + h2 - 1;
2051	     pSiS->OffDead2.x0 = 0;
2052	     pSiS->OffDead2.x1 = x1 - 1;
2053	     pSiS->OffDead2.y0 = y1;
2054	     pSiS->OffDead2.y1 = y1 + h1 - 1;
2055	     pSiS->HaveOffsRegions = TRUE;
2056	  } else if(pSiS->CRT2XOffs) {
2057	     pSiS->OffDead1.x0 = x1 + w1;
2058	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2059	     pSiS->OffDead1.y0 = y1;
2060	     pSiS->OffDead1.y1 = y1 + h1 - 1;
2061	     pSiS->OffDead2.x0 = 0;
2062	     pSiS->OffDead2.x1 = x2 - 1;
2063	     pSiS->OffDead2.y0 = y2;
2064	     pSiS->OffDead2.y1 = y2 + h2 - 1;
2065	     pSiS->HaveOffsRegions = TRUE;
2066	  }
2067       default:
2068	  break;
2069       }
2070
2071    } else {	/* Only clone-modes left */
2072
2073       x1 = x2 = 0;
2074       y1 = y2 = 0;
2075       w1 = w2 = max(pSiS->maxClone_X1, pSiS->maxClone_X2);
2076       h1 = h2 = max(pSiS->maxClone_Y1, pSiS->maxClone_Y2);
2077
2078    }
2079
2080    SiSXineramadataPtr[crt1scrnnum].x = x1;
2081    SiSXineramadataPtr[crt1scrnnum].y = y1;
2082    SiSXineramadataPtr[crt1scrnnum].width = w1;
2083    SiSXineramadataPtr[crt1scrnnum].height = h1;
2084    SiSXineramadataPtr[crt2scrnnum].x = x2;
2085    SiSXineramadataPtr[crt2scrnnum].y = y2;
2086    SiSXineramadataPtr[crt2scrnnum].width = w2;
2087    SiSXineramadataPtr[crt2scrnnum].height = h2;
2088
2089    if(infochanged) {
2090       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2091	  "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n",
2092	  crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1);
2093       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2094	  "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n",
2095	  crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1);
2096       if(pSiS->HaveNonRect) {
2097	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2098		"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
2099		pSiS->NonRectDead.x0, pSiS->NonRectDead.y0,
2100		pSiS->NonRectDead.x1, pSiS->NonRectDead.y1);
2101       }
2102       if(pSiS->HaveOffsRegions) {
2103	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2104		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2105		pSiS->OffDead1.x0, pSiS->OffDead1.y0,
2106		pSiS->OffDead1.x1, pSiS->OffDead1.y1);
2107	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2108		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2109		pSiS->OffDead2.x0, pSiS->OffDead2.y0,
2110		pSiS->OffDead2.x1, pSiS->OffDead2.y1);
2111       }
2112       if(pSiS->HaveNonRect || pSiS->HaveOffsRegions) {
2113	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2114		"Mouse restriction for inaccessible areas is %s\n",
2115		pSiS->MouseRestrictions ? "enabled" : "disabled");
2116       }
2117    }
2118}
2119
2120/* Proc */
2121
2122int
2123SiSProcXineramaQueryVersion(ClientPtr client)
2124{
2125    xPanoramiXQueryVersionReply	  rep;
2126    register int		  n;
2127
2128    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
2129    rep.type = X_Reply;
2130    rep.length = 0;
2131    rep.sequenceNumber = client->sequence;
2132    rep.majorVersion = SIS_XINERAMA_MAJOR_VERSION;
2133    rep.minorVersion = SIS_XINERAMA_MINOR_VERSION;
2134    if(client->swapped) {
2135        swaps(&rep.sequenceNumber, n);
2136        swapl(&rep.length, n);
2137        swaps(&rep.majorVersion, n);
2138        swaps(&rep.minorVersion, n);
2139    }
2140    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
2141    return (client->noClientException);
2142}
2143
2144int
2145SiSProcXineramaGetState(ClientPtr client)
2146{
2147    REQUEST(xPanoramiXGetStateReq);
2148    WindowPtr			pWin;
2149    xPanoramiXGetStateReply	rep;
2150    register int		n;
2151
2152    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2153    pWin = LookupWindow(stuff->window, client);
2154    if(!pWin) return BadWindow;
2155
2156    rep.type = X_Reply;
2157    rep.length = 0;
2158    rep.sequenceNumber = client->sequence;
2159    rep.state = !SiSnoPanoramiXExtension;
2160    if(client->swapped) {
2161       swaps (&rep.sequenceNumber, n);
2162       swapl (&rep.length, n);
2163       swaps (&rep.state, n);
2164    }
2165    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
2166    return client->noClientException;
2167}
2168
2169int
2170SiSProcXineramaGetScreenCount(ClientPtr client)
2171{
2172    REQUEST(xPanoramiXGetScreenCountReq);
2173    WindowPtr				pWin;
2174    xPanoramiXGetScreenCountReply	rep;
2175    register int			n;
2176
2177    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2178    pWin = LookupWindow(stuff->window, client);
2179    if(!pWin) return BadWindow;
2180
2181    rep.type = X_Reply;
2182    rep.length = 0;
2183    rep.sequenceNumber = client->sequence;
2184    rep.ScreenCount = SiSXineramaNumScreens;
2185    if(client->swapped) {
2186       swaps(&rep.sequenceNumber, n);
2187       swapl(&rep.length, n);
2188       swaps(&rep.ScreenCount, n);
2189    }
2190    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
2191    return client->noClientException;
2192}
2193
2194int
2195SiSProcXineramaGetScreenSize(ClientPtr client)
2196{
2197    REQUEST(xPanoramiXGetScreenSizeReq);
2198    WindowPtr				pWin;
2199    xPanoramiXGetScreenSizeReply	rep;
2200    register int			n;
2201
2202    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2203    pWin = LookupWindow (stuff->window, client);
2204    if(!pWin)  return BadWindow;
2205
2206    rep.type = X_Reply;
2207    rep.length = 0;
2208    rep.sequenceNumber = client->sequence;
2209    rep.width  = SiSXineramadataPtr[stuff->screen].width;
2210    rep.height = SiSXineramadataPtr[stuff->screen].height;
2211    if(client->swapped) {
2212       swaps(&rep.sequenceNumber, n);
2213       swapl(&rep.length, n);
2214       swaps(&rep.width, n);
2215       swaps(&rep.height, n);
2216    }
2217    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
2218    return client->noClientException;
2219}
2220
2221int
2222SiSProcXineramaIsActive(ClientPtr client)
2223{
2224    xXineramaIsActiveReply	rep;
2225
2226    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2227
2228    rep.type = X_Reply;
2229    rep.length = 0;
2230    rep.sequenceNumber = client->sequence;
2231    rep.state = !SiSnoPanoramiXExtension;
2232    if(client->swapped) {
2233	register int n;
2234	swaps(&rep.sequenceNumber, n);
2235	swapl(&rep.length, n);
2236	swapl(&rep.state, n);
2237    }
2238    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
2239    return client->noClientException;
2240}
2241
2242int
2243SiSProcXineramaQueryScreens(ClientPtr client)
2244{
2245    xXineramaQueryScreensReply	rep;
2246
2247    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2248
2249    rep.type = X_Reply;
2250    rep.sequenceNumber = client->sequence;
2251    rep.number = (SiSnoPanoramiXExtension) ? 0 : SiSXineramaNumScreens;
2252    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
2253    if(client->swapped) {
2254       register int n;
2255       swaps(&rep.sequenceNumber, n);
2256       swapl(&rep.length, n);
2257       swapl(&rep.number, n);
2258    }
2259    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
2260
2261    if(!SiSnoPanoramiXExtension) {
2262       xXineramaScreenInfo scratch;
2263       int i;
2264
2265       for(i = 0; i < SiSXineramaNumScreens; i++) {
2266	  scratch.x_org  = SiSXineramadataPtr[i].x;
2267	  scratch.y_org  = SiSXineramadataPtr[i].y;
2268	  scratch.width  = SiSXineramadataPtr[i].width;
2269	  scratch.height = SiSXineramadataPtr[i].height;
2270	  if(client->swapped) {
2271	     register int n;
2272	     swaps(&scratch.x_org, n);
2273	     swaps(&scratch.y_org, n);
2274	     swaps(&scratch.width, n);
2275	     swaps(&scratch.height, n);
2276	  }
2277	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
2278       }
2279    }
2280
2281    return client->noClientException;
2282}
2283
2284static int
2285SiSProcXineramaDispatch(ClientPtr client)
2286{
2287    REQUEST(xReq);
2288    switch (stuff->data) {
2289	case X_PanoramiXQueryVersion:
2290	     return SiSProcXineramaQueryVersion(client);
2291	case X_PanoramiXGetState:
2292	     return SiSProcXineramaGetState(client);
2293	case X_PanoramiXGetScreenCount:
2294	     return SiSProcXineramaGetScreenCount(client);
2295	case X_PanoramiXGetScreenSize:
2296	     return SiSProcXineramaGetScreenSize(client);
2297	case X_XineramaIsActive:
2298	     return SiSProcXineramaIsActive(client);
2299	case X_XineramaQueryScreens:
2300	     return SiSProcXineramaQueryScreens(client);
2301    }
2302    return BadRequest;
2303}
2304
2305/* SProc */
2306
2307static int
2308SiSSProcXineramaQueryVersion (ClientPtr client)
2309{
2310    REQUEST(xPanoramiXQueryVersionReq);
2311    register int n;
2312    swaps(&stuff->length,n);
2313    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
2314    return SiSProcXineramaQueryVersion(client);
2315}
2316
2317static int
2318SiSSProcXineramaGetState(ClientPtr client)
2319{
2320    REQUEST(xPanoramiXGetStateReq);
2321    register int n;
2322    swaps (&stuff->length, n);
2323    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2324    return SiSProcXineramaGetState(client);
2325}
2326
2327static int
2328SiSSProcXineramaGetScreenCount(ClientPtr client)
2329{
2330    REQUEST(xPanoramiXGetScreenCountReq);
2331    register int n;
2332    swaps (&stuff->length, n);
2333    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2334    return SiSProcXineramaGetScreenCount(client);
2335}
2336
2337static int
2338SiSSProcXineramaGetScreenSize(ClientPtr client)
2339{
2340    REQUEST(xPanoramiXGetScreenSizeReq);
2341    register int n;
2342    swaps (&stuff->length, n);
2343    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2344    return SiSProcXineramaGetScreenSize(client);
2345}
2346
2347static int
2348SiSSProcXineramaIsActive(ClientPtr client)
2349{
2350    REQUEST(xXineramaIsActiveReq);
2351    register int n;
2352    swaps (&stuff->length, n);
2353    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2354    return SiSProcXineramaIsActive(client);
2355}
2356
2357static int
2358SiSSProcXineramaQueryScreens(ClientPtr client)
2359{
2360    REQUEST(xXineramaQueryScreensReq);
2361    register int n;
2362    swaps (&stuff->length, n);
2363    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2364    return SiSProcXineramaQueryScreens(client);
2365}
2366
2367int
2368SiSSProcXineramaDispatch(ClientPtr client)
2369{
2370    REQUEST(xReq);
2371    switch (stuff->data) {
2372	case X_PanoramiXQueryVersion:
2373	     return SiSSProcXineramaQueryVersion(client);
2374	case X_PanoramiXGetState:
2375	     return SiSSProcXineramaGetState(client);
2376	case X_PanoramiXGetScreenCount:
2377	     return SiSSProcXineramaGetScreenCount(client);
2378	case X_PanoramiXGetScreenSize:
2379	     return SiSSProcXineramaGetScreenSize(client);
2380	case X_XineramaIsActive:
2381	     return SiSSProcXineramaIsActive(client);
2382	case X_XineramaQueryScreens:
2383	     return SiSSProcXineramaQueryScreens(client);
2384    }
2385    return BadRequest;
2386}
2387
2388static void
2389SiSXineramaResetProc(ExtensionEntry* extEntry)
2390{
2391    /* Called by CloseDownExtensions() */
2392    if(SiSXineramadataPtr) {
2393       Xfree(SiSXineramadataPtr);
2394       SiSXineramadataPtr = NULL;
2395    }
2396}
2397
2398static void
2399SiSXineramaExtensionInit(ScrnInfoPtr pScrn)
2400{
2401    SISPtr	pSiS = SISPTR(pScrn);
2402    Bool	success = FALSE;
2403
2404    if(!(SiSXineramadataPtr)) {
2405
2406       if(!pSiS->MergedFB) {
2407	  SiSnoPanoramiXExtension = TRUE;
2408	  pSiS->MouseRestrictions = FALSE;
2409	  return;
2410       }
2411
2412#ifdef PANORAMIX
2413       if(!noPanoramiXExtension) {
2414	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2415	     "Xinerama active, not initializing SiS Pseudo-Xinerama\n");
2416	  SiSnoPanoramiXExtension = TRUE;
2417	  pSiS->MouseRestrictions = FALSE;
2418	  return;
2419       }
2420#endif
2421
2422       if(SiSnoPanoramiXExtension) {
2423	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2424	      "SiS Pseudo-Xinerama disabled\n");
2425	  pSiS->MouseRestrictions = FALSE;
2426	  return;
2427       }
2428
2429       if(pSiS->CRT2Position == sisClone) {
2430	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2431	     "Running MergedFB in Clone mode, SiS Pseudo-Xinerama disabled\n");
2432	  SiSnoPanoramiXExtension = TRUE;
2433	  pSiS->MouseRestrictions = FALSE;
2434	  return;
2435       }
2436
2437       if(!(pSiS->AtLeastOneNonClone)) {
2438	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2439	     "Only Clone modes defined, SiS Pseudo-Xinerama disabled\n");
2440	  SiSnoPanoramiXExtension = TRUE;
2441	  pSiS->MouseRestrictions = FALSE;
2442	  return;
2443       }
2444
2445       SiSXineramaNumScreens = 2;
2446
2447       while(SiSXineramaGeneration != serverGeneration) {
2448
2449	  pSiS->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
2450					SiSProcXineramaDispatch,
2451					SiSSProcXineramaDispatch,
2452					SiSXineramaResetProc,
2453					StandardMinorOpcode);
2454
2455	  if(!pSiS->XineramaExtEntry) break;
2456
2457	  if(!(SiSXineramadataPtr = (SiSXineramaData *)
2458	        xcalloc(SiSXineramaNumScreens, sizeof(SiSXineramaData)))) break;
2459
2460	  SiSXineramaGeneration = serverGeneration;
2461	  success = TRUE;
2462       }
2463
2464       if(!success) {
2465	  SISErrorLog(pScrn, "Failed to initialize SiS Pseudo-Xinerama extension\n");
2466	  SiSnoPanoramiXExtension = TRUE;
2467	  pSiS->MouseRestrictions = FALSE;
2468	  return;
2469       }
2470
2471       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2472	  "SiS Pseudo-Xinerama extension initialized\n");
2473
2474       pSiS->SiSXineramaVX = 0;
2475       pSiS->SiSXineramaVY = 0;
2476
2477    }
2478
2479    SiSUpdateXineramaScreenInfo(pScrn);
2480
2481}
2482#endif  /* End of PseudoXinerama */
2483
2484static void
2485SiSFreeCRT2Structs(SISPtr pSiS)
2486{
2487    if(pSiS->CRT2pScrn) {
2488       if(pSiS->CRT2pScrn->modes) {
2489	  while(pSiS->CRT2pScrn->modes)
2490	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
2491       }
2492       if(pSiS->CRT2pScrn->monitor) {
2493	  if(pSiS->CRT2pScrn->monitor->Modes) {
2494	     while(pSiS->CRT2pScrn->monitor->Modes)
2495		xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
2496	  }
2497	  if(pSiS->CRT2pScrn->monitor->DDC) xfree(pSiS->CRT2pScrn->monitor->DDC);
2498	  xfree(pSiS->CRT2pScrn->monitor);
2499       }
2500       xfree(pSiS->CRT2pScrn);
2501       pSiS->CRT2pScrn = NULL;
2502   }
2503}
2504
2505#endif	/* End of MergedFB helpers */
2506
2507static xf86MonPtr
2508SiSInternalDDC(ScrnInfoPtr pScrn, int crtno)
2509{
2510   SISPtr     pSiS = SISPTR(pScrn);
2511   xf86MonPtr pMonitor = NULL;
2512   UShort     temp = 0xffff, temp1, i, realcrtno = crtno;
2513   UChar      buffer[256];
2514
2515   /* If CRT1 is off, skip DDC */
2516   if((pSiS->CRT1off) && (!crtno)) return NULL;
2517
2518   if(crtno) {
2519      if(pSiS->VBFlags & CRT2_LCD)      realcrtno = 1;
2520      else if(pSiS->VBFlags & CRT2_VGA) realcrtno = 2;
2521      else				return NULL;
2522      if(pSiS->SiS_Pr->DDCPortMixup) realcrtno = 0;
2523   } else {
2524      /* If CRT1 is LCDA, skip DDC (except 301C: DDC allowed, but uses CRT2 port!) */
2525      if(pSiS->VBFlags & CRT1_LCDA) {
2526         if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) realcrtno = 1;
2527         else return NULL;
2528      }
2529   }
2530
2531   i = 3; /* Number of retrys */
2532   do {
2533      temp1 = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2534			realcrtno, 0, &buffer[0], pSiS->VBFlags2);
2535      if((temp1) && (temp1 != 0xffff)) temp = temp1;
2536   } while((temp == 0xffff) && i--);
2537   if(temp != 0xffff) {
2538      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1);
2539      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n",
2540	     crtno + 1,
2541	     (temp & 0x1a) ? "" : "[none of the supported]",
2542	     (temp & 0x02) ? "2 " : "",
2543	     (temp & 0x08) ? "D&P" : "",
2544             (temp & 0x10) ? "FPDI-2" : "");
2545      if(temp & 0x02) {
2546	 i = 5;  /* Number of retrys */
2547	 do {
2548	    temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2549				realcrtno, 1, &buffer[0], pSiS->VBFlags2);
2550	 } while((temp) && i--);
2551         if(!temp) {
2552	    if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) {
2553	       int tempvgagamma = 0, templcdgamma = 0;
2554	       if(buffer[0x14] & 0x80) {
2555	          templcdgamma = (buffer[0x17] + 100) * 10;
2556	       } else {
2557	          tempvgagamma = (buffer[0x17] + 100) * 10;;
2558	       }
2559	       if(crtno == 0) {
2560		  if(tempvgagamma) pSiS->CRT1VGAMonitorGamma = tempvgagamma;
2561		  /* LCD never via (demanded) CRT1 DDC port */
2562	       } else {
2563	          if(tempvgagamma) pSiS->CRT2VGAMonitorGamma = tempvgagamma;
2564	          if(templcdgamma) pSiS->CRT2LCDMonitorGamma = templcdgamma;
2565	       }
2566	       return(pMonitor);
2567	    } else {
2568	       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2569	           "CRT%d DDC EDID corrupt\n", crtno + 1);
2570	    }
2571	 } else if(temp == 0xFFFE) {
2572	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2573	    	"CRT%d DDC data is from wrong device type (%s)\n",
2574			crtno + 1,
2575			(realcrtno == 1) ? "analog instead of digital" : "digital instead of analog");
2576	 } else {
2577            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2578	    	"CRT%d DDC reading failed\n", crtno + 1);
2579	 }
2580      } else if(temp & 0x18) {
2581         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2582	      "DDC for VESA D&P and FPDI-2 not supported yet.\n");
2583      }
2584   } else {
2585      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2586                "CRT%d DDC probing failed\n", crtno + 1);
2587   }
2588   return(NULL);
2589}
2590
2591static xf86MonPtr
2592SiSDoPrivateDDC(ScrnInfoPtr pScrn, int *crtnum)
2593{
2594    SISPtr pSiS = SISPTR(pScrn);
2595
2596#ifdef SISDUALHEAD
2597    if(pSiS->DualHeadMode) {
2598       if(pSiS->SecondHead) {
2599          *crtnum = 1;
2600	  return(SiSInternalDDC(pScrn, 0));
2601       } else {
2602          *crtnum = 2;
2603	  return(SiSInternalDDC(pScrn, 1));
2604       }
2605    } else
2606#endif
2607    if((pSiS->CRT1off) || (!pSiS->CRT1Detected)) {
2608       *crtnum = 2;
2609       return(SiSInternalDDC(pScrn, 1));
2610    } else {
2611       *crtnum = 1;
2612       return(SiSInternalDDC(pScrn, 0));
2613    }
2614}
2615
2616static void
2617SiSFindAspect(ScrnInfoPtr pScrn, xf86MonPtr pMonitor, int crtnum)
2618{
2619    SISPtr pSiS = SISPTR(pScrn);
2620    int UseWide = 0;
2621    int aspect = 0;
2622    Bool fromdim = FALSE;
2623
2624    if((pSiS->VGAEngine == SIS_315_VGA) && (!DIGITAL(pMonitor->features.input_type))) {
2625       if(pMonitor->features.hsize && pMonitor->features.vsize) {
2626	  aspect = (pMonitor->features.hsize * 1000) / pMonitor->features.vsize;
2627	  if(aspect >= 1400) UseWide = 1;
2628	  fromdim = TRUE;
2629       } else if((PREFERRED_TIMING_MODE(pMonitor->features.msc)) &&
2630		 (pMonitor->det_mon[0].type == DT)) {
2631	  aspect = (pMonitor->det_mon[0].section.d_timings.h_active * 1000) /
2632			pMonitor->det_mon[0].section.d_timings.v_active;
2633	  if(aspect >= 1400) UseWide = 1;
2634       }
2635       if(aspect) {
2636	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2637		"According to %s, CRT%d aspect ratio is %.2f:1 (%s)\n",
2638		fromdim ? "DDC size" : "preferred mode",
2639		crtnum, (float)aspect / 1000.0, UseWide ? "wide" : "normal");
2640       } else {
2641	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2642		"Unable to determine CRT%d aspect ratio, assuming \"normal\"\n",
2643		crtnum);
2644       }
2645    }
2646
2647    if((crtnum == 1) && (pSiS->SiS_Pr->SiS_UseWide == -1)) {
2648       pSiS->SiS_Pr->SiS_UseWide = UseWide;
2649    } else if((crtnum == 2) && (pSiS->SiS_Pr->SiS_UseWideCRT2 == -1)) {
2650       pSiS->SiS_Pr->SiS_UseWideCRT2 = UseWide;
2651    }
2652}
2653
2654static Bool
2655SiSMakeOwnModeList(ScrnInfoPtr pScrn, Bool acceptcustommodes, Bool includelcdmodes,
2656                   Bool isfordvi, Bool *havecustommodes, Bool fakecrt2modes, Bool IsForCRT2)
2657{
2658    DisplayModePtr tempmode, delmode, mymodes;
2659
2660    if((mymodes = SiSBuildBuiltInModeList(pScrn, includelcdmodes, isfordvi, fakecrt2modes, IsForCRT2))) {
2661       if(!acceptcustommodes) {
2662	  while(pScrn->monitor->Modes)
2663             xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes);
2664	  pScrn->monitor->Modes = mymodes;
2665       } else {
2666	  delmode = pScrn->monitor->Modes;
2667	  while(delmode) {
2668	     if(delmode->type & M_T_DEFAULT) {
2669	        tempmode = delmode->next;
2670	        xf86DeleteMode(&pScrn->monitor->Modes, delmode);
2671	        delmode = tempmode;
2672	     } else {
2673	        delmode = delmode->next;
2674	     }
2675	  }
2676	  /* Link default modes AFTER user ones */
2677	  if((tempmode = pScrn->monitor->Modes)) {
2678	     *havecustommodes = TRUE;
2679	     while(tempmode) {
2680	        if(!tempmode->next) break;
2681	        else tempmode = tempmode->next;
2682	     }
2683	     tempmode->next = mymodes;
2684	     mymodes->prev = tempmode;
2685	  } else {
2686	     pScrn->monitor->Modes = mymodes;
2687	  }
2688#if 0
2689	  pScrn->monitor->Modes = mymodes;
2690	  while(mymodes) {
2691	     if(!mymodes->next) break;
2692	     else mymodes = mymodes->next;
2693	  }
2694	  mymodes->next = tempmode;
2695	  if(tempmode) {
2696	     tempmode->prev = mymodes;
2697	  }
2698#endif
2699       }
2700       return TRUE;
2701    } else
2702       return FALSE;
2703}
2704
2705static void
2706SiSPrintModes(ScrnInfoPtr pScrn)
2707{
2708    DisplayModePtr p;
2709    float hsync, refresh = 0.0;
2710    char *desc, *desc2, *prefix, *uprefix, *output;
2711
2712    xf86DrvMsg(pScrn->scrnIndex, pScrn->virtualFrom, "Virtual size is %dx%d "
2713	       "(pitch %d)\n", pScrn->virtualX, pScrn->virtualY,
2714	       pScrn->displayWidth);
2715
2716    if((p = pScrn->modes) == NULL) return;
2717
2718    do {
2719	desc = desc2 = "";
2720	uprefix = " ";
2721	prefix = "Mode";
2722	output = "For CRT device: ";
2723	if(p->HSync > 0.0)      hsync = p->HSync;
2724	else if (p->HTotal > 0) hsync = (float)p->Clock / (float)p->HTotal;
2725	else	                hsync = 0.0;
2726	refresh = 0.0;
2727        if(p->VRefresh > 0.0)   refresh = p->VRefresh;
2728        else if (p->HTotal > 0 && p->VTotal > 0) {
2729	   refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
2730	   if(p->Flags & V_INTERLACE) refresh *= 2.0;
2731	   if(p->Flags & V_DBLSCAN)   refresh /= 2.0;
2732	   if(p->VScan > 1)  	      refresh /= p->VScan;
2733        }
2734	if(p->Flags & V_INTERLACE) desc = " (I)";
2735	if(p->Flags & V_DBLSCAN)   desc = " (D)";
2736	if(p->VScan > 1) 	   desc2 = " (VScan)";
2737#ifdef M_T_USERDEF
2738	if(p->type & M_T_USERDEF)  uprefix = "*";
2739#endif
2740	if(p->type & M_T_BUILTIN)       {
2741	   prefix = "Built-in mode";
2742	   output = "";
2743	} else if (p->type & M_T_DEFAULT) {
2744	   prefix = "Default mode";
2745	} else {
2746	   output = "";
2747	}
2748
2749	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
2750		"%s%s \"%s\" (%dx%d) (%s%.1f MHz, %.1f kHz, %.1f Hz%s%s)\n",
2751		uprefix, prefix, p->name, p->HDisplay, p->VDisplay, output,
2752		p->Clock / 1000.0, hsync, refresh, desc, desc2);
2753
2754	p = p->next;
2755    } while (p != NULL && p != pScrn->modes);
2756}
2757
2758Bool SISDetermineLCDACap(ScrnInfoPtr pScrn)
2759{
2760    SISPtr pSiS = SISPTR(pScrn);
2761
2762    if( ((pSiS->ChipType == SIS_650)    ||
2763         (pSiS->ChipType == SIS_315PRO) ||
2764         (pSiS->ChipType >= SIS_661))		&&
2765	(pSiS->ChipType != XGI_20)		&&
2766        (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)	&&
2767	(pSiS->VESA != 1) ) {
2768       return TRUE;
2769    }
2770    return FALSE;
2771}
2772
2773void SISSaveDetectedDevices(ScrnInfoPtr pScrn)
2774{
2775    SISPtr  pSiS = SISPTR(pScrn);
2776    /* Backup detected CRT2 devices */
2777    pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD|CRT2_TV|CRT2_VGA|TV_AVIDEO|TV_SVIDEO|
2778                                                 TV_SCART|TV_HIVISION|TV_YPBPR);
2779}
2780
2781static Bool
2782SISCheckBIOS(SISPtr pSiS, UShort mypciid, UShort mypcivendor, int biossize)
2783{
2784    UShort romptr, pciid;
2785
2786    if(!pSiS->BIOS) return FALSE;
2787
2788    if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) return FALSE;
2789
2790    romptr = pSiS->BIOS[0x18] | (pSiS->BIOS[0x19] << 8);
2791    if(romptr > (biossize - 8)) return FALSE;
2792    if((pSiS->BIOS[romptr]   != 'P') || (pSiS->BIOS[romptr+1] != 'C') ||
2793       (pSiS->BIOS[romptr+2] != 'I') || (pSiS->BIOS[romptr+3] != 'R')) return FALSE;
2794
2795    pciid = pSiS->BIOS[romptr+4] | (pSiS->BIOS[romptr+5] << 8);
2796    if(pciid != mypcivendor) return FALSE;
2797
2798    pciid = pSiS->BIOS[romptr+6] | (pSiS->BIOS[romptr+7] << 8);
2799    if(pciid != mypciid) return FALSE;
2800
2801    return TRUE;
2802}
2803
2804static void
2805SiS_LoadInitVBE(ScrnInfoPtr pScrn)
2806{
2807    SISPtr pSiS = SISPTR(pScrn);
2808
2809    /* Don't load the VBE module for secondary
2810     * cards which sisfb POSTed. We don't want
2811     * int10 to overwrite our set up (such as
2812     * disabled a0000 memory address decoding).
2813     * We don't need the VBE anyway because
2814     * the card will never be in text mode,
2815     * and we can restore graphics modes just
2816     * perfectly.
2817     */
2818    if( !pSiS->Primary &&
2819        pSiS->sisfbcardposted)
2820       return;
2821
2822    if(pSiS->pVbe) return;
2823
2824    if(xf86LoadSubModule(pScrn, "vbe")) {
2825#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
2826       pSiS->pVbe = VBEInit(pSiS->pInt, pSiS->pEnt->index);
2827#else
2828       pSiS->pVbe = VBEExtendedInit(pSiS->pInt, pSiS->pEnt->index,
2829	                SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
2830#endif
2831    }
2832
2833    if(!pSiS->pVbe) {
2834       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2835	   "Failed to load/initialize vbe module\n");
2836    }
2837}
2838
2839#ifdef SIS_PC_PLATFORM
2840static void
2841SiS_MapVGAMem(ScrnInfoPtr pScrn)
2842{
2843    SISPtr pSiS = SISPTR(pScrn);
2844
2845    /* Map 64k VGA window for saving/restoring CGA fonts */
2846    pSiS->VGAMapSize = 0x10000;
2847    pSiS->VGAMapPhys = 0;	/* Default */
2848    if((!pSiS->Primary) || (!pSiS->VGADecodingEnabled)) {
2849       /* If card is secondary or if a0000-address decoding
2850        * is disabled, set Phys to beginning of our video RAM.
2851	*/
2852       pSiS->VGAMapPhys = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM);
2853    }
2854    if(!SiSVGAMapMem(pScrn)) {
2855       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2856	  "Failed to map VGA memory (0x%lx), can't save/restore console fonts\n",
2857	  pSiS->VGAMapPhys);
2858    }
2859}
2860#endif
2861
2862static void
2863SiS_CheckKernelFB(ScrnInfoPtr pScrn)
2864{
2865    SISPtr pSiS = SISPTR(pScrn);
2866    int        fd, i;
2867    CARD32     sisfbinfosize = 0, sisfbversion;
2868    sisfb_info *mysisfbinfo;
2869    char       name[16];
2870
2871    pSiS->donttrustpdc = FALSE;
2872    pSiS->sisfbpdc = 0xff;
2873    pSiS->sisfbpdca = 0xff;
2874    pSiS->sisfblcda = 0xff;
2875    pSiS->sisfbscalelcd = -1;
2876    pSiS->sisfbspecialtiming = CUT_NONE;
2877    pSiS->sisfb_haveemi = FALSE;
2878    pSiS->sisfbfound = FALSE;
2879    pSiS->sisfb_tvposvalid = FALSE;
2880    pSiS->sisfbdevname[0] = 0;
2881    pSiS->sisfb_havelock = FALSE;
2882    pSiS->sisfbHaveNewHeapDef = FALSE;
2883    pSiS->sisfbHeapSize = 0;
2884    pSiS->sisfbVideoOffset = 0;
2885    pSiS->sisfbxSTN = FALSE;
2886    pSiS->sisfbcanpost = FALSE;   /* (Old) sisfb can't POST card */
2887    pSiS->sisfbcardposted = TRUE; /* If (old) sisfb is running, card must have been POSTed */
2888    pSiS->sisfbprimary = FALSE;   /* (Old) sisfb doesn't know */
2889
2890    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
2891
2892       i = 0;
2893       do {
2894
2895	  if(i <= 7) {
2896             sprintf(name, "/dev/fb%1d", i);
2897	  } else {
2898	     sprintf(name, "/dev/fb/%1d", (i - 8));
2899	  }
2900
2901          if((fd = open(name, O_RDONLY)) != -1) {
2902
2903	     Bool gotit = FALSE;
2904
2905 	     if(!ioctl(fd, SISFB_GET_INFO_SIZE, &sisfbinfosize)) {
2906 		if((mysisfbinfo = xalloc(sisfbinfosize))) {
2907 		   if(!ioctl(fd, (SISFB_GET_INFO | (sisfbinfosize << 16)), mysisfbinfo)) {
2908 		      gotit = TRUE;
2909 		   } else {
2910 		      xfree(mysisfbinfo);
2911 		      mysisfbinfo = NULL;
2912 		   }
2913 		}
2914 	     } else {
2915 		if((mysisfbinfo = xalloc(sizeof(*mysisfbinfo) + 16))) {
2916 		   if(!ioctl(fd, SISFB_GET_INFO_OLD, mysisfbinfo)) {
2917 		      gotit = TRUE;
2918		      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2919				"Possibly old version of sisfb detected. Please update.\n");
2920		   } else {
2921		      xfree(mysisfbinfo);
2922		      mysisfbinfo = NULL;
2923		   }
2924		}
2925	     }
2926
2927	     if(gotit) {
2928
2929		if(mysisfbinfo->sisfb_id == SISFB_ID) {
2930
2931		   sisfbversion = (mysisfbinfo->sisfb_version << 16) |
2932				  (mysisfbinfo->sisfb_revision << 8) |
2933				  (mysisfbinfo->sisfb_patchlevel);
2934
2935	           if(sisfbversion >= SISFB_VERSION(1, 5, 8)) {
2936		      /* Added PCI bus/slot/func into in sisfb Version 1.5.08.
2937		       * Check this to make sure we run on the same card as sisfb
2938		       */
2939		      if((mysisfbinfo->sisfb_pcibus  == pSiS->PciBus)    &&
2940			 (mysisfbinfo->sisfb_pcislot == pSiS->PciDevice) &&
2941			 (mysisfbinfo->sisfb_pcifunc == pSiS->PciFunc)) {
2942			 pSiS->sisfbfound = TRUE;
2943		      }
2944		   } else pSiS->sisfbfound = TRUE;
2945
2946		   if(pSiS->sisfbfound) {
2947		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2948			     "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI:%02d:%02d.%d)\n",
2949				&name[5],
2950				mysisfbinfo->sisfb_version,
2951				mysisfbinfo->sisfb_revision,
2952				mysisfbinfo->sisfb_patchlevel,
2953				pSiS->PciBus,
2954				pSiS->PciDevice,
2955				pSiS->PciFunc);
2956
2957		      /* Added version/rev/pl in sisfb 1.4.0 */
2958		      if(mysisfbinfo->sisfb_version == 0) {
2959			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2960				"Old version of sisfb found. Please update.\n");
2961		      }
2962		      /* Basically, we can't trust the pdc register if sisfb is loaded */
2963		      pSiS->donttrustpdc = TRUE;
2964		      pSiS->sisfbHeapStart = mysisfbinfo->heapstart;
2965
2966		      if(sisfbversion >= SISFB_VERSION(1, 7, 20)) {
2967			 pSiS->sisfbHeapSize = mysisfbinfo->sisfb_heapsize;
2968			 pSiS->sisfbVideoOffset = mysisfbinfo->sisfb_videooffset;
2969			 pSiS->sisfbHaveNewHeapDef = TRUE;
2970			 pSiS->sisfbFSTN = mysisfbinfo->sisfb_curfstn;
2971			 pSiS->sisfbDSTN = mysisfbinfo->sisfb_curdstn;
2972			 pSiS->sisfbxSTN = TRUE;
2973			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2974				"sisfb: memory heap at %dKB, size %dKB, viewport at %dKB\n",
2975				(int)pSiS->sisfbHeapStart, (int)pSiS->sisfbHeapSize,
2976				(int)pSiS->sisfbVideoOffset/1024);
2977		      } else {
2978			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2979				"sisfb: memory heap at %dKB\n", (int)pSiS->sisfbHeapStart);
2980		      }
2981		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2982				"sisfb: using video mode 0x%02x\n", mysisfbinfo->fbvidmode);
2983		      pSiS->OldMode = mysisfbinfo->fbvidmode;
2984		      if(sisfbversion >= SISFB_VERSION(1, 5, 6)) {
2985			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2986				"sisfb: using %s, reserved %dK\n",
2987				(mysisfbinfo->sisfb_caps & 0x40) ? "SiS300 series Turboqueue" :
2988				   (mysisfbinfo->sisfb_caps & 0x20) ? "SiS315/330/340 series AGP command queue" :
2989				      (mysisfbinfo->sisfb_caps & 0x10) ? "SiS315/330/340 series VRAM command queue" :
2990					(mysisfbinfo->sisfb_caps & 0x08) ? "SiS315/330/340 series MMIO mode" :
2991					   "no command queue",
2992				(int)mysisfbinfo->sisfb_tqlen);
2993		      }
2994		      if(sisfbversion >= SISFB_VERSION(1, 5, 10)) {
2995			 /* We can trust the pdc value if sisfb is of recent version */
2996			 if(pSiS->VGAEngine == SIS_300_VGA) pSiS->donttrustpdc = FALSE;
2997		      }
2998		      if(sisfbversion >= SISFB_VERSION(1, 5, 11)) {
2999			 if(pSiS->VGAEngine == SIS_300_VGA) {
3000			    /* As of 1.5.11, sisfb saved the register for us (300 series) */
3001			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3002			    if(!pSiS->sisfbpdc) pSiS->sisfbpdc = 0xff;
3003			 }
3004		      }
3005		      if(sisfbversion >= SISFB_VERSION(1, 5, 14)) {
3006			 if(pSiS->VGAEngine == SIS_315_VGA) {
3007			    pSiS->sisfblcda = mysisfbinfo->sisfb_lcda;
3008			 }
3009		      }
3010		      if(sisfbversion >= SISFB_VERSION(1, 6, 13)) {
3011			 pSiS->sisfbscalelcd = mysisfbinfo->sisfb_scalelcd;
3012			 pSiS->sisfbspecialtiming = mysisfbinfo->sisfb_specialtiming;
3013		      }
3014		      if(sisfbversion >= SISFB_VERSION(1, 6, 16)) {
3015			 if(pSiS->VGAEngine == SIS_315_VGA) {
3016			    pSiS->donttrustpdc = FALSE;
3017			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3018			    if(sisfbversion >= SISFB_VERSION(1, 6, 24)) {
3019			       pSiS->sisfb_haveemi = mysisfbinfo->sisfb_haveemi ? TRUE : FALSE;
3020			       pSiS->sisfb_haveemilcd = TRUE;  /* will match most cases */
3021			       pSiS->sisfb_emi30 = mysisfbinfo->sisfb_emi30;
3022			       pSiS->sisfb_emi31 = mysisfbinfo->sisfb_emi31;
3023			       pSiS->sisfb_emi32 = mysisfbinfo->sisfb_emi32;
3024			       pSiS->sisfb_emi33 = mysisfbinfo->sisfb_emi33;
3025			    }
3026			    if(sisfbversion >= SISFB_VERSION(1, 6, 25)) {
3027			       pSiS->sisfb_haveemilcd = mysisfbinfo->sisfb_haveemilcd ? TRUE : FALSE;
3028			    }
3029			    if(sisfbversion >= SISFB_VERSION(1, 6, 31)) {
3030			       pSiS->sisfbpdca = mysisfbinfo->sisfb_lcdpdca;
3031			    } else {
3032			       if(pSiS->sisfbpdc) {
3033				  pSiS->sisfbpdca = (pSiS->sisfbpdc & 0xf0) >> 3;
3034				  pSiS->sisfbpdc  = (pSiS->sisfbpdc & 0x0f) << 1;
3035			       } else {
3036				  pSiS->sisfbpdca = pSiS->sisfbpdc = 0xff;
3037			       }
3038			    }
3039			 }
3040		      }
3041		      if(sisfbversion >= SISFB_VERSION(1, 7, 0)) {
3042		         pSiS->sisfb_havelock = TRUE;
3043			 if(sisfbversion >= SISFB_VERSION(1, 7, 1)) {
3044			    pSiS->sisfb_tvxpos = mysisfbinfo->sisfb_tvxpos;
3045			    pSiS->sisfb_tvypos = mysisfbinfo->sisfb_tvypos;
3046			    pSiS->sisfb_tvposvalid = TRUE;
3047			 }
3048		      }
3049		      if(sisfbversion >= SISFB_VERSION(1, 8, 7)) {
3050			 pSiS->sisfbcanpost = (mysisfbinfo->sisfb_can_post) ? TRUE : FALSE;
3051			 pSiS->sisfbcardposted = (mysisfbinfo->sisfb_card_posted) ? TRUE : FALSE;
3052			 pSiS->sisfbprimary = (mysisfbinfo->sisfb_was_boot_device) ? TRUE : FALSE;
3053			 /* Validity check */
3054			 if(!pSiS->sisfbcardposted) {
3055			    pSiS->sisfbprimary = FALSE;
3056			 }
3057		      }
3058		   }
3059	        }
3060		xfree(mysisfbinfo);
3061		mysisfbinfo = NULL;
3062	     }
3063	     close (fd);
3064          }
3065	  i++;
3066       } while((i <= 15) && (!pSiS->sisfbfound));
3067
3068       if(pSiS->sisfbfound) {
3069          strncpy(pSiS->sisfbdevname, name, 15);
3070       } else {
3071          xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb not found\n");
3072       }
3073    }
3074
3075    if(!pSiS->sisfbfound) {
3076       pSiS->sisfbcardposted = FALSE;
3077    }
3078}
3079
3080static void
3081SiSPseudo(ScrnInfoPtr pScrn)
3082{
3083}
3084
3085/* PreInit()
3086 *
3087 * Mandatory
3088 */
3089static Bool
3090SISPreInit(ScrnInfoPtr pScrn, int flags)
3091{
3092    SISPtr pSiS;
3093#ifdef SISDUALHEAD
3094    SISEntPtr pSiSEnt = NULL;
3095#endif
3096    MessageType from;
3097    UChar usScratchCR17, usScratchCR32, usScratchCR63;
3098    UChar usScratchSR1F, srlockReg, crlockReg;
3099    unsigned int i;
3100    int pix24flags, temp;
3101    ClockRangePtr clockRanges;
3102    xf86MonPtr pMonitor = NULL;
3103    Bool didddc2, fromDDC, crt1freqoverruled = FALSE;
3104    UChar CR5F, tempreg;
3105#if defined(SISMERGED) || defined(SISDUALHEAD)
3106    DisplayModePtr first, p, n;
3107#endif
3108#ifdef SISMERGED
3109    Bool crt2freqoverruled = FALSE;
3110#endif
3111
3112    static const char *ddcsstr = "CRT%d DDC monitor info: *******************************************\n";
3113    static const char *ddcestr = "End of CRT%d DDC monitor info *************************************\n";
3114    static const char *subshstr = "Substituting missing CRT%d monitor HSync range by DDC data\n";
3115    static const char *subsvstr = "Substituting missing CRT%d monitor VRefresh range by DDC data\n";
3116    static const char *saneh = "Correcting %s CRT%d monitor HSync range\n";
3117    static const char *sanev = "Correcting %s CRT%d monitor VRefresh range\n";
3118#ifdef SISMERGED
3119    static const char *mergednocrt1 = "CRT1 not detected or forced off. %s.\n";
3120    static const char *mergednocrt2 = "No CRT2 output selected or no video bridge detected. %s.\n";
3121    static const char *mergeddisstr = "MergedFB mode disabled";
3122    static const char *modesforstr = "Modes for CRT%d: **************************************************\n";
3123    static const char *crtsetupstr = "*************************** CRT%d setup ***************************\n";
3124    static const char *crt2monname = "CRT2";
3125#endif
3126#if defined(SISDUALHEAD) || defined(SISMERGED)
3127    static const char *notsuitablestr = "Not using mode \"%s\" (not suitable for %s mode)\n";
3128#endif
3129
3130    if(flags & PROBE_DETECT) {
3131
3132       vbeInfoPtr   pVbe;
3133
3134       if(xf86LoadSubModule(pScrn, "vbe")) {
3135          int index = xf86GetEntityInfo(pScrn->entityList[0])->index;
3136#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3137	  if((pVbe = VBEInit(NULL, index)))
3138#else
3139          if((pVbe = VBEExtendedInit(NULL, index, 0)))
3140#endif
3141          {
3142             ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3143             vbeFree(pVbe);
3144          }
3145       }
3146       return TRUE;
3147    }
3148
3149    /*
3150     * Note: This function is only called once at server startup, and
3151     * not at the start of each server generation.  This means that
3152     * only things that are persistent across server generations can
3153     * be initialised here.  xf86Screens[] is the array of all screens,
3154     * (pScrn is a pointer to one of these).  Privates allocated using
3155     * xf86AllocateScrnInfoPrivateIndex() are too, and should be used
3156     * for data that must persist across server generations.
3157     *
3158     * Per-generation data should be allocated with
3159     * AllocateScreenPrivateIndex() from the ScreenInit() function.
3160     */
3161
3162    /* Check the number of entities, and fail if it isn't one. */
3163    if(pScrn->numEntities != 1) {
3164       SISErrorLog(pScrn, "Number of entities is not 1\n");
3165       return FALSE;
3166    }
3167
3168    /* Due to the liberal license terms this is needed for
3169     * keeping the copyright notice readable and intact in
3170     * binary distributions. Removing this is a copyright
3171     * infringement. Please read the license terms above.
3172     */
3173
3174    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3175	"SiS driver (%d/%02d/%02d-%d, compiled for " SISMYSERVERNAME " %d.%d.%d.%d)\n",
3176	SISDRIVERVERSIONYEAR + 2000, SISDRIVERVERSIONMONTH,
3177	SISDRIVERVERSIONDAY, SISDRIVERREVISION,
3178#ifdef XORG_VERSION_CURRENT
3179	XORG_VERSION_MAJOR, XORG_VERSION_MINOR,
3180	XORG_VERSION_PATCH, XORG_VERSION_SNAP
3181#else
3182	XF86_VERSION_MAJOR, XF86_VERSION_MINOR,
3183	XF86_VERSION_PATCH, XF86_VERSION_SNAP
3184#endif
3185	);
3186    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3187	"Copyright (C) 2001-2005 Thomas Winischhofer <thomas@winischhofer.net> and others\n");
3188    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3189	"*** See http://www.winischhofer.eu/linuxsisvga.shtml\n");
3190    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3191	"*** for documentation and updates.\n");
3192
3193#ifdef XORG_VERSION_CURRENT
3194#if 0  /* no prototype yet */
3195    if(xorgGetVersion() != XORG_VERSION_CURRENT) {
3196       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3197         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3198    }
3199#endif
3200#else
3201#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,0,0)
3202    if(xf86GetVersion() != XF86_VERSION_CURRENT) {
3203       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3204         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3205    }
3206#endif
3207#endif
3208
3209    /* Allocate the SISRec driverPrivate */
3210    if(!SISGetRec(pScrn)) {
3211       SISErrorLog(pScrn, "Could not allocate memory for pSiS private\n");
3212       return FALSE;
3213    }
3214    pSiS = SISPTR(pScrn);
3215    pSiS->pScrn = pScrn;
3216
3217    pSiS->pInt = NULL;
3218
3219    /* Save PCI Domain Base */
3220#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3221    pSiS->IODBase = 0;
3222#else
3223    pSiS->IODBase = pScrn->domainIOBase;
3224#endif
3225
3226    /* Get the entity, and make sure it is PCI. */
3227    pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3228    if(pSiS->pEnt->location.type != BUS_PCI) {
3229       SISErrorLog(pScrn, "Entity's bus type is not PCI\n");
3230       goto my_error_0;
3231    }
3232
3233#ifdef SISDUALHEAD
3234    /* Allocate an entity private if necessary */
3235    if(xf86IsEntityShared(pScrn->entityList[0])) {
3236       pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr;
3237       pSiS->entityPrivate = pSiSEnt;
3238
3239       /* If something went wrong, quit here */
3240       if((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) {
3241	  SISErrorLog(pScrn, "First head encountered fatal error, aborting...\n");
3242	  goto my_error_0;
3243       }
3244    }
3245#endif
3246
3247    /* Find the PCI info for this screen */
3248    pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index);
3249    pSiS->PciBus = PCI_CFG_BUS(pSiS->PciInfo);    /*SIS_PCI_BUS(pSiS->PciInfo);*/
3250    pSiS->PciDevice = PCI_CFG_DEV(pSiS->PciInfo); /*SIS_PCI_DEVICE(pSiS->PciInfo);*/
3251    pSiS->PciFunc = PCI_CFG_FUNC(pSiS->PciInfo);  /*SIS_PCI_FUNC(pSiS->PciInfo);*/
3252
3253    pSiS->PciTag = pciTag(PCI_DEV_BUS(pSiS->PciInfo),
3254			  PCI_DEV_DEV(pSiS->PciInfo),
3255			  PCI_DEV_FUNC(pSiS->PciInfo));
3256
3257#ifdef SIS_NEED_MAP_IOP
3258    /********************************************/
3259    /*     THIS IS BROKEN AND WON'T WORK        */
3260    /* Reasons:                                 */
3261    /* 1) MIPS and ARM have no i/o ports but    */
3262    /* use memory mapped i/o only. The inX/outX */
3263    /* macros in compiler.h are smart enough to */
3264    /* add "IOPortBase" to the port number, but */
3265    /* "IOPortBase" is never initialized.       */
3266    /* 2) IOPortBase is declared in compiler.h  */
3267    /* itself. So until somebody fixes all      */
3268    /* modules that #include compiler.h to set  */
3269    /* IOPortBase, vga support for MIPS and ARM */
3270    /* is unusable.                             */
3271    /* (In this driver this is solvable because */
3272    /* we have our own vgaHW routines. However, */
3273    /* we use /dev/port for now instead.)       */
3274    /********************************************/
3275    pSiS->IOPAddress = pSiS->IODBase + pSiS->PciInfo->ioBase[2];
3276    if(!SISMapIOPMem(pScrn)) {
3277       SISErrorLog(pScrn, "Could not map I/O port area at 0x%x\n", pSiS->IOPAddress);
3278       goto my_error_0;
3279    } else {
3280       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I/O port area mapped to %p, size 128\n", pSiS->IOPBase);
3281#if defined(__mips__) || defined(__arm32__)
3282       /* inX/outX macros on these use IOPortBase as offset */
3283       /* This is entirely skrewed. */
3284       IOPortBase = (unsigned int)pSiS->IOPBase;
3285#endif
3286    }
3287#endif
3288
3289    /* Set up i/o port access (for non-x86) */
3290#ifdef SISUSEDEVPORT
3291    if((sisdevport = open("/dev/port", O_RDWR, 0)) == -1) {
3292       SISErrorLog(pScrn, "Failed to open /dev/port for read/write\n");
3293       goto my_error_0;
3294    }
3295    pSiS->sisdevportopen = TRUE;
3296#endif
3297
3298    /*
3299     * Set the Chipset and ChipRev, allowing config file entries to
3300     * override. DANGEROUS!
3301     */
3302    {
3303       SymTabRec *myChipsets = SISChipsets;
3304
3305       if(PCI_DEV_VENDOR_ID(pSiS->PciInfo) == PCI_VENDOR_XGI) {
3306          myChipsets = XGIChipsets;
3307       }
3308
3309       if(pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) {
3310
3311          pScrn->chipset = pSiS->pEnt->device->chipset;
3312          pSiS->Chipset = xf86StringToToken(myChipsets, pScrn->chipset);
3313
3314       } else if(pSiS->pEnt->device->chipID >= 0) {
3315
3316          pSiS->Chipset = pSiS->pEnt->device->chipID;
3317          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3318
3319          xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
3320								pSiS->Chipset);
3321       } else {
3322
3323          pSiS->Chipset = PCI_DEV_DEVICE_ID(pSiS->PciInfo);
3324          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3325
3326       }
3327    }
3328
3329    if(pSiS->pEnt->device->chipRev >= 0) {
3330
3331       pSiS->ChipRev = pSiS->pEnt->device->chipRev;
3332       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
3333								pSiS->ChipRev);
3334    } else {
3335
3336       pSiS->ChipRev = PCI_DEV_REVISION(pSiS->PciInfo);
3337
3338    }
3339
3340    /*
3341     * This shouldn't happen because such problems should be caught in
3342     * SISProbe(), but check it just in case the user has overridden them.
3343     */
3344    if(pScrn->chipset == NULL) {
3345       SISErrorLog(pScrn, "ChipID 0x%04X is not recognised\n", pSiS->Chipset);
3346       goto my_error_0;
3347    }
3348    if(pSiS->Chipset < 0) {
3349       SISErrorLog(pScrn, "Chipset \"%s\" is not recognised\n", pScrn->chipset);
3350       goto my_error_0;
3351    }
3352
3353    pSiS->SiS6326Flags = 0;
3354
3355    /* Determine VGA engine generation */
3356    switch(pSiS->Chipset) {
3357       case PCI_CHIP_SIS300:
3358       case PCI_CHIP_SIS540:
3359       case PCI_CHIP_SIS630: /* 630 + 730 */
3360          pSiS->VGAEngine = SIS_300_VGA;
3361	  break;
3362       case PCI_CHIP_SIS315H:
3363       case PCI_CHIP_SIS315:
3364       case PCI_CHIP_SIS315PRO:
3365       case PCI_CHIP_SIS550:
3366       case PCI_CHIP_SIS650: /* 650 + 740 */
3367       case PCI_CHIP_SIS330:
3368       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?), 770 */
3369       case PCI_CHIP_SIS340:
3370       case PCI_CHIP_XGIXG20:
3371       case PCI_CHIP_XGIXG40:
3372          pSiS->VGAEngine = SIS_315_VGA;
3373	  break;
3374       case PCI_CHIP_SIS530:
3375          pSiS->VGAEngine = SIS_530_VGA;
3376	  break;
3377       case PCI_CHIP_SIS6326:
3378          /* Determine SiS6326 revision. According to SiS the differences are:
3379	   * Chip name     Chip type      TV-Out       MPEG II decoder
3380	   * 6326 AGP      Rev. G0/H0     no           no
3381	   * 6326 DVD      Rev. D2        yes          yes
3382	   * 6326          Rev. Cx        yes          yes
3383	   */
3384	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3385		"Chipset is SiS6326 %s (revision 0x%02x)\n",
3386		(pSiS->ChipRev == 0xaf) ? "(Ax)" :
3387		   ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" :
3388		      ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" :
3389			 (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx/H0)" :
3390			    (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" :
3391			       (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" :
3392				  "(unknown)"))))),
3393		pSiS->ChipRev);
3394	  if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) {
3395	     pSiS->SiS6326Flags |= SIS6326_HASTV;
3396	  }
3397	  /* fall through */
3398       default:
3399	  pSiS->VGAEngine = SIS_OLD_VGA;
3400    }
3401
3402    /* We don't know about the current mode yet */
3403    pSiS->OldMode = 0;
3404
3405    /* Determine whether this is the primary or a secondary
3406     * display adapter. And right here the problem starts:
3407     * On machines with integrated SiS chipsets, the system BIOS
3408     * usually sets VGA_EN on all PCI-to-PCI bridges in the system
3409     * (of which there usually are two: PCI and AGP). This and
3410     * the fact that any PCI card POSTed by sisfb naturally has
3411     * its PCI resources enabled, leads to X assuming that
3412     * there are more than one "primary" cards in the system.
3413     * In this case, X treats ALL cards as "secondary" -
3414     * which by no means is desireable. If sisfb is running,
3415     * we can determine which card really is "primary" (in
3416     * terms of if it's the one that occupies the A0000 area
3417     * etc.) in a better way (Linux 2.6.12 or later). See below.
3418     */
3419    if(!(pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo))) {
3420       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3421	   SISMYSERVERNAME " assumes this adapter to be secondary\n");
3422    }
3423
3424    /* Now check if sisfb is running, and if so, retrieve
3425     * all possible info from it. This also resets all
3426     * sisfb_* entries in pSiS regardless of the chipset.
3427     */
3428    SiS_CheckKernelFB(pScrn);
3429
3430    /* Now for that primary/secondary mess: Linux kernel
3431     * 2.6.12 and later knows what card is primary, and so
3432     * does any recent version of sisfb. XFree86/X.org takes
3433     * all adapters as "secondary" if more than one card's
3434     * memory and i/o resources are enabled, and more than
3435     * one PCI bridge in the system has VGA_EN set at server
3436     * start. So, let's start thinking: What is this
3437     * primary/secondary classification needed for anyway?
3438     * (This list might be incomplete for the entire server
3439     * infrastructure, but it's complete as regards the driver's
3440     * purposes of primary/secondary classification.)
3441     *    1) VGA/console font restoring: Here it's irrelevant
3442     *       whether more than one card's resources are enabled
3443     *       at server start or not. Relevant is whether the card
3444     *       occupies the A0000 area at this time. Assuming (?)
3445     *       that this does not change during machine up-time,
3446     *       it suffices to know which device was the boot video
3447     *       device (as determined by Linux 2.6.12 and later).
3448     *       Also, this is only relevant if the card is in text
3449     *       mode; if it's in graphics mode, fonts aren't saved
3450     *       or restored anyway.
3451     *       sisfb tells us if that card is considered the boot
3452     *       video device. The hardware registers tell us if
3453     *       the card's A0000 address decoding is enabled, and if
3454     *       the card currently is in text mode. These three bits
3455     *       of information are enough to decide on whether or not
3456     *       to save/restore fonts.
3457     *    2) POSTing. Same here. Relevant is only whether or not
3458     *       the card has been POSTed once before. POSTing cards
3459     *       on every server start is pretty ugly, especially
3460     *       if a framebuffer driver is already handling it.
3461     * SiS/XGI cards POSTed by sisfb can coexist well with other
3462     * active adapters. So we trust sisfb's information more
3463     * than X's (especially as we only use this information for
3464     * console font restoring and eventual POSTing.)
3465     * What we still need is a way to find out about all this if
3466     * sisfb is not running....
3467     */
3468    if(!pSiS->Primary && pSiS->sisfbprimary) {
3469       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3470		"sisfb reports this adapter to be primary. Seems more reliable.\n");
3471       pSiS->Primary = TRUE;
3472    }
3473
3474    /* If the card is "secondary" and has not been
3475     * POSTed by sisfb, POST it now through int10.
3476     * For cards POSTed by sisfb, we definitely don't
3477     * want that as it messes up our set up (eg. the
3478     * disabled A0000 area).
3479     * The int10 module decides on its own if the
3480     * card is primary or secondary. Since it uses
3481     * the generic technique described above, and since
3482     * for "secondary" cards it needs a real PCI BIOS
3483     * ROM, and since integrated chips don't have such
3484     * a PCI BIOS ROM, int10 will naturally fail to
3485     * find/read the BIOS on such machines. Great.
3486     * Using the integrated graphics as "secondary"
3487     * (which it will be as soon as X finds more than
3488     * one card's mem and i/o resources enabled, and more
3489     * than one PCI bridge's VGA_EN bit set during server
3490     * start) will therefore prevent us from restoring
3491     * the mode using the VBE. That means real fun if
3492     * the integrated chip is set up to use the video
3493     * bridge output for text mode (which is something
3494     * the driver doesn't really support since it's done
3495     * pretty much differently on every machine.)
3496     */
3497#if !defined(__alpha__)
3498    if(!pSiS->Primary) {
3499       if(!pSiS->sisfbcardposted) {
3500	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3501		"Initializing adapter through int10\n");
3502	  if(xf86LoadSubModule(pScrn, "int10")) {
3503	     pSiS->pInt = xf86InitInt10(pSiS->pEnt->index);
3504	  } else {
3505	     SISErrorLog(pScrn, "Failed to load int10 module\n");
3506	  }
3507       } else {
3508	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3509		"Adapter already initialized by sisfb\n");
3510       }
3511    }
3512#endif
3513
3514    /* Get the address of our relocated IO registers.
3515     * These are enabled by the hardware during cold boot, and
3516     * by the BIOS. So we can pretty much rely on that these
3517     * are enabled.
3518     */
3519    pSiS->RelIO = (SISIOADDRESS)(PCI_REGION_BASE(pSiS->PciInfo, 2, REGION_IO) + pSiS->IODBase);
3520    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Relocated I/O registers at 0x%lX\n",
3521           (ULong)pSiS->RelIO);
3522
3523    /* Unlock extended registers */
3524    sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg);
3525
3526    /* Is a0000 memory address decoding enabled? */
3527    pSiS->VGADecodingEnabled = TRUE;
3528    switch(pSiS->VGAEngine) {
3529    case SIS_OLD_VGA:
3530       /* n/a */
3531       break;
3532    case SIS_530_VGA:
3533       inSISIDXREG(SISSR, 0x3d, tempreg);
3534       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3535       break;
3536    case SIS_300_VGA:
3537    case SIS_315_VGA:
3538       inSISIDXREG(SISSR, 0x20, tempreg);
3539       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3540       break;
3541    }
3542
3543    if(!pSiS->VGADecodingEnabled) {
3544       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3545		"Standard VGA (0xA0000) memory address decoding is disabled\n");
3546    }
3547
3548#ifdef SIS_PC_PLATFORM
3549    /* Map 64k VGA window for saving/restoring CGA fonts.
3550     * For secondary cards or if A0000 address decoding
3551     * is disabled, this will map the beginning of the
3552     * linear (PCI) video RAM instead.
3553     */
3554    SiS_MapVGAMem(pScrn);
3555#endif
3556
3557#ifndef XSERVER_LIBPCIACCESS
3558    /* Set operating state */
3559
3560    /* 1. memory */
3561    /* [ResUnusedOpr: Resource decoded by hw, but not used]
3562     * [ResDisableOpr: Resource is not decoded by hw]
3563     * So, if a0000 memory decoding is disabled, one could
3564     * argue that we may say so, too. Hm. Quite likely that
3565     * the VBE (via int10) will eventually enable it. So we
3566     * cowardly say unused instead.
3567     */
3568    xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr);
3569
3570    /* 2. i/o */
3571    /* Although we only use the relocated i/o ports, the hardware
3572     * also decodes the standard VGA port range. This could in
3573     * theory be disabled, but I don't dare to do this; in case of
3574     * a server crash, the card would be entirely dead. Also, this
3575     * would prevent int10 and the VBE from working at all. Generic
3576     * access control through the PCI configuration registers does
3577     * nicely anyway.
3578     */
3579    xf86SetOperatingState(resVgaIo, pSiS->pEnt->index, ResUnusedOpr);
3580
3581    /* Operations for which memory access is required */
3582    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3583
3584    /* Operations for which I/O access is required */
3585    pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3586
3587#endif
3588
3589    /* Load ramdac module */
3590    if(!xf86LoadSubModule(pScrn, "ramdac")) {
3591       SISErrorLog(pScrn, "Could not load ramdac module\n");
3592       goto my_error_1;
3593    }
3594
3595    /* Set pScrn->monitor */
3596    pScrn->monitor = pScrn->confScreen->monitor;
3597
3598    /* Reset some entries */
3599    pSiS->SiSFastVidCopy = SiSVidCopyGetDefault();
3600    pSiS->SiSFastMemCopy = SiSVidCopyGetDefault();
3601    pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
3602    pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
3603    pSiS->SiSFastVidCopyDone = FALSE;
3604#ifdef SIS_USE_XAA
3605    pSiS->RenderCallback = NULL;
3606#endif
3607#ifdef SIS_USE_EXA
3608    pSiS->ExaRenderCallback = NULL;
3609#endif
3610    pSiS->InitAccel = SiSPseudo;
3611    pSiS->SyncAccel = SiSPseudo;
3612    pSiS->FillRect  = NULL;
3613    pSiS->BlitRect  = NULL;
3614
3615    /* Always do a ValidMode() inside Switchmode() */
3616    pSiS->skipswitchcheck = FALSE;
3617
3618    /* Determine chipset and its capabilities in detail */
3619    pSiS->ChipFlags = 0;
3620    pSiS->SiS_SD_Flags = pSiS->SiS_SD2_Flags = 0;
3621    pSiS->SiS_SD3_Flags = pSiS->SiS_SD4_Flags = 0;
3622    pSiS->HWCursorMBufNum = pSiS->HWCursorCBufNum = 0;
3623    pSiS->NeedFlush = FALSE;
3624    pSiS->NewCRLayout = FALSE;
3625    pSiS->mmioSize = 64;
3626
3627    switch(pSiS->Chipset) {
3628       case PCI_CHIP_SIS530:
3629	  pSiS->ChipType = SIS_530;
3630	  break;
3631       case PCI_CHIP_SIS300:
3632	  pSiS->ChipType = SIS_300;
3633	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3634	  break;
3635       case PCI_CHIP_SIS540:
3636	  pSiS->ChipType = SIS_540;
3637	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3638	  break;
3639       case PCI_CHIP_SIS630: /* 630 + 730 */
3640	  pSiS->ChipType = SIS_630;
3641	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07301039) {
3642	     pSiS->ChipType = SIS_730;
3643	  }
3644	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3645	  break;
3646       case PCI_CHIP_SIS315H:
3647	  pSiS->ChipType = SIS_315H;
3648	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3649	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3650	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3651	  pSiS->myCR63 = 0x63;
3652	  break;
3653       case PCI_CHIP_SIS315:
3654	  /* Override for simplicity */
3655	  pSiS->Chipset = PCI_CHIP_SIS315H;
3656	  pSiS->ChipType = SIS_315;
3657	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3658	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3659	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3660	  pSiS->myCR63 = 0x63;
3661	  break;
3662       case PCI_CHIP_SIS315PRO:
3663	  /* Override for simplicity */
3664	  pSiS->Chipset = PCI_CHIP_SIS315H;
3665	  pSiS->ChipType = SIS_315PRO;
3666	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3667	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3668	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3669	  pSiS->myCR63 = 0x63;
3670	  break;
3671       case PCI_CHIP_SIS550:
3672	  pSiS->ChipType = SIS_550;
3673	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3674	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3675	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3676	  pSiS->myCR63 = 0x63;
3677	  break;
3678       case PCI_CHIP_SIS650: /* 650 + 740 */
3679	  pSiS->ChipType = SIS_650;
3680	  if(sis_pci_read_host_bridge_u32(0x00) == 0x07401039) {
3681	     pSiS->ChipType = SIS_740;
3682	  }
3683	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_Real256ECore | SiSCF_MMIOPalette);
3684	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3685	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3686	  pSiS->myCR63 = 0x63;
3687	  break;
3688       case PCI_CHIP_SIS330:
3689	  pSiS->ChipType = SIS_330;
3690	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3691	  pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3692	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3693	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN; /* FIXME ? */
3694	  pSiS->myCR63 = 0x53; /* sic! */
3695	  break;
3696       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?) */
3697	  {
3698	     ULong hpciid = sis_pci_read_host_bridge_u32(0x00);
3699	     switch(hpciid) {
3700	     case 0x06601039:
3701		pSiS->ChipType = SIS_660;
3702		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3703		pSiS->NeedFlush = TRUE;
3704		break;
3705	     case 0x07601039:
3706		pSiS->ChipType = SIS_760;
3707		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3708		pSiS->NeedFlush = TRUE;
3709		break;
3710	     case 0x07611039:
3711		pSiS->ChipType = SIS_761;
3712		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3713		pSiS->NeedFlush = TRUE;
3714		break;
3715	     case 0x07701039:
3716		pSiS->ChipType = SIS_770;
3717		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3718		pSiS->NeedFlush = TRUE;
3719		break;
3720	     case 0x07411039:
3721		pSiS->ChipType = SIS_741;
3722		pSiS->ChipFlags |= SiSCF_Real256ECore;
3723		break;
3724	     case 0x06611039:
3725	     default:
3726		pSiS->ChipType = SIS_661;
3727		pSiS->ChipFlags |= SiSCF_Real256ECore;
3728		break;
3729	     case 0x06701039:
3730		pSiS->ChipType = SIS_670;
3731		pSiS->ChipFlags |= SiSCF_Real256ECore;
3732	     }
3733	     /* Detection could also be done by CR5C & 0xf8:
3734	      * 0x10 = 661 (CR5F & 0xc0: 0x00 both A0 and A1)
3735	      * 0x80 = 760 (CR5F & 0xc0: 0x00 A0, 0x40 A1)
3736	      * 0x90 = 741 (CR5F & 0xc0: 0x00 A0,A1 0x40 A2)
3737	      * other: 660 (CR5F & 0xc0: 0x00 A0 0x40 A1) (DOA?)
3738	      */
3739	     pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3740	     pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3741	     pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3742	     pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3743	     pSiS->myCR63 = 0x53; /* sic! */
3744	     pSiS->NewCRLayout = TRUE;
3745	  }
3746	  break;
3747       case PCI_CHIP_SIS340:
3748	  pSiS->ChipType = SIS_340;
3749	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3750	  pSiS->SiS_SD_Flags |= SiS_SD_IS340SERIES;
3751	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3752	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3753	  pSiS->myCR63 = 0x53;
3754	  pSiS->NewCRLayout = TRUE;
3755	  break;
3756       case PCI_CHIP_XGIXG20:
3757	  pSiS->ChipType = XGI_20;
3758	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3759	  pSiS->SiS_SD2_Flags |= (SiS_SD2_NOOVERLAY | SiS_SD2_ISXGI);
3760	  pSiS->myCR63 = 0x53;
3761	  pSiS->NewCRLayout = TRUE;
3762	  break;
3763       case PCI_CHIP_XGIXG40:
3764	  pSiS->ChipType = XGI_40;
3765	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3766	  pSiS->SiS_SD2_Flags |= (SiS_SD2_SUPPORTXVHUESAT | SiS_SD2_ISXGI);
3767	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3768	  pSiS->myCR63 = 0x53;
3769	  pSiS->NewCRLayout = TRUE;
3770	  if(pSiS->ChipRev == 2) pSiS->ChipFlags |= SiSCF_IsXGIV3;
3771	  break;
3772       default:
3773	  pSiS->ChipType = SIS_OLD;
3774	  break;
3775    }
3776
3777    /*
3778     * Now back to real business: Figure out the depth, bpp, etc.
3779     * Set SupportConvert... flags since we use the fb layer which
3780     * supports this conversion. (24to32 seems not implemented though)
3781     * Additionally, determine the size of the HWCursor memory area.
3782     */
3783    switch(pSiS->VGAEngine) {
3784       case SIS_300_VGA:
3785	  pSiS->CursorSize = 4096;
3786	  pix24flags = Support32bppFb;
3787	  break;
3788       case SIS_315_VGA:
3789	  pSiS->CursorSize = 16384;
3790	  pix24flags = Support32bppFb;
3791	  break;
3792       case SIS_530_VGA:
3793	  pSiS->CursorSize = 2048;
3794	  pix24flags = Support32bppFb	  |
3795		       Support24bppFb	  |
3796		       SupportConvert32to24;
3797          break;
3798       default:
3799	  pSiS->CursorSize = 2048;
3800	  pix24flags = Support24bppFb	    |
3801		       SupportConvert32to24 |
3802		       PreferConvert32to24;
3803	  break;
3804    }
3805
3806#ifdef SISDUALHEAD
3807    /* In case of Dual Head, we need to determine if we are the "master" head or
3808     * the "slave" head. In order to do that, we set PrimInit to DONE in the
3809     * shared entity at the end of the first initialization. The second
3810     * initialization then knows that some things have already been done. THIS
3811     * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER!
3812     */
3813    if(xf86IsEntityShared(pScrn->entityList[0])) {
3814       if(pSiSEnt->lastInstance > 0) {
3815	  if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
3816	     /* First Head (always CRT2) */
3817	     pSiS->SecondHead = FALSE;
3818	     pSiSEnt->pScrn_1 = pScrn;
3819	     pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1;
3820	     pSiSEnt->CRT2ModeSet = FALSE;
3821	     pSiS->DualHeadMode = TRUE;
3822	     pSiSEnt->DisableDual = FALSE;
3823	     pSiSEnt->BIOS = NULL;
3824	     pSiSEnt->ROM661New = FALSE;
3825	     pSiSEnt->HaveXGIBIOS = FALSE;
3826	     pSiSEnt->SiS_Pr = NULL;
3827	     pSiSEnt->RenderAccelArray = NULL;
3828	     pSiSEnt->SiSFastVidCopy = pSiSEnt->SiSFastMemCopy = NULL;
3829	     pSiSEnt->SiSFastVidCopyFrom = pSiSEnt->SiSFastMemCopyFrom = NULL;
3830	  } else {
3831	     /* Second Head (always CRT1) */
3832	     pSiS->SecondHead = TRUE;
3833	     pSiSEnt->pScrn_2 = pScrn;
3834	     pSiS->DualHeadMode = TRUE;
3835	  }
3836       } else {
3837	  /* Only one screen in config file - disable dual head mode */
3838	  pSiS->SecondHead = FALSE;
3839	  pSiS->DualHeadMode = FALSE;
3840	  pSiSEnt->DisableDual = TRUE;
3841       }
3842    } else {
3843       /* Entity is not shared - disable dual head mode */
3844       pSiS->SecondHead = FALSE;
3845       pSiS->DualHeadMode = FALSE;
3846    }
3847#endif
3848
3849    /* Save the name of our Device section for SiSCtrl usage */
3850    {
3851       int ttt = 0;
3852       GDevPtr device = xf86GetDevFromEntity(pScrn->entityList[0],
3853						pScrn->entityInstanceList[0]);
3854       if(device && device->identifier) {
3855          if((ttt = strlen(device->identifier)) > 31) ttt = 31;
3856	  strncpy(&pSiS->devsectname[0], device->identifier, 31);
3857       }
3858       pSiS->devsectname[ttt] = 0;
3859    }
3860
3861    pSiS->ForceCursorOff = FALSE;
3862
3863    /* Allocate SiS_Private (for mode switching code) and initialize it */
3864    pSiS->SiS_Pr = NULL;
3865#ifdef SISDUALHEAD
3866    if(pSiSEnt) {
3867       if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr;
3868    }
3869#endif
3870    if(!pSiS->SiS_Pr) {
3871       if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(struct SiS_Private), 1))) {
3872	  SISErrorLog(pScrn, "Could not allocate memory for SiS_Pr structure\n");
3873	  goto my_error_1;
3874       }
3875#ifdef SISDUALHEAD
3876       if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr;
3877#endif
3878       memset(pSiS->SiS_Pr, 0, sizeof(struct SiS_Private));
3879       pSiS->SiS_Pr->PciTag = pSiS->PciTag;
3880       pSiS->SiS_Pr->ChipType = pSiS->ChipType;
3881       pSiS->SiS_Pr->ChipRevision = pSiS->ChipRev;
3882       pSiS->SiS_Pr->SiS_Backup70xx = 0xff;
3883       pSiS->SiS_Pr->SiS_CHOverScan = -1;
3884       pSiS->SiS_Pr->SiS_ChSW = FALSE;
3885       pSiS->SiS_Pr->SiS_CustomT = CUT_NONE;
3886       pSiS->SiS_Pr->SiS_UseWide = -1;
3887       pSiS->SiS_Pr->SiS_UseWideCRT2 = -1;
3888       pSiS->SiS_Pr->SiS_TVBlue = -1;
3889       pSiS->SiS_Pr->PanelSelfDetected = FALSE;
3890       pSiS->SiS_Pr->UsePanelScaler = -1;
3891       pSiS->SiS_Pr->CenterScreen = -1;
3892       pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
3893       pSiS->SiS_Pr->PDC = pSiS->SiS_Pr->PDCA = -1;
3894       pSiS->SiS_Pr->LVDSHL = -1;
3895       pSiS->SiS_Pr->HaveEMI = FALSE;
3896       pSiS->SiS_Pr->HaveEMILCD = FALSE;
3897       pSiS->SiS_Pr->OverruleEMI = FALSE;
3898       pSiS->SiS_Pr->SiS_SensibleSR11 = FALSE;
3899       if(pSiS->ChipType >= SIS_661) {
3900          pSiS->SiS_Pr->SiS_SensibleSR11 = TRUE;
3901       }
3902       pSiS->SiS_Pr->SiS_MyCR63 = pSiS->myCR63;
3903       pSiS->SiS_Pr->DDCPortMixup = FALSE;
3904    }
3905
3906    /* Copy IO address to SiS_Pr and init the structure for
3907     * routines inside init.c/init301.c
3908     */
3909    pSiS->SiS_Pr->IOAddress = (SISIOADDRESS)(pSiS->RelIO + 0x30);
3910    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
3911
3912    /* The following identifies the old chipsets. This is only
3913     * partly used since the really old chips are not supported,
3914     * but I keep it here for future use.
3915     * 205, 215 and 225 are to be treated the same way, 201 and 202
3916     * are different.
3917     */
3918    if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) {
3919       switch(pSiS->Chipset) {
3920       case PCI_CHIP_SG86C201:
3921	  pSiS->oldChipset = OC_SIS86201; break;
3922       case PCI_CHIP_SG86C202:
3923	  pSiS->oldChipset = OC_SIS86202; break;
3924       case PCI_CHIP_SG86C205:
3925	  inSISIDXREG(SISSR, 0x10, tempreg);
3926	  if(tempreg & 0x80) pSiS->oldChipset = OC_SIS6205B;
3927	  else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ?
3928					OC_SIS6205C : OC_SIS6205A;
3929	  break;
3930       case PCI_CHIP_SIS82C204:
3931	  pSiS->oldChipset = OC_SIS82204; break;
3932       case 0x6225:
3933	  pSiS->oldChipset = OC_SIS6225; break;
3934       case PCI_CHIP_SIS5597:
3935	  pSiS->oldChipset = OC_SIS5597; break;
3936       case PCI_CHIP_SIS6326:
3937	  pSiS->oldChipset = OC_SIS6326; break;
3938       case PCI_CHIP_SIS530:
3939	  if(sis_pci_read_host_bridge_u32(0x00) == 0x06201039) {
3940	     pSiS->oldChipset = OC_SIS620;
3941	  } else {
3942	     if((pSiS->ChipRev & 0x0f) < 0x0a)
3943		   pSiS->oldChipset = OC_SIS530A;
3944	     else  pSiS->oldChipset = OC_SIS530B;
3945	  }
3946	  break;
3947       default:
3948	  pSiS->oldChipset = OC_UNKNOWN;
3949       }
3950    }
3951
3952    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, pix24flags)) {
3953       SISErrorLog(pScrn, "xf86SetDepthBpp() error\n");
3954       goto my_error_1;
3955    }
3956
3957    /* Check that the returned depth is one we support */
3958    temp = 0;
3959    switch(pScrn->depth) {
3960       case 8:
3961       case 16:
3962       case 24:
3963          break;
3964       case 15:
3965	  if((pSiS->VGAEngine == SIS_300_VGA) ||
3966	     (pSiS->VGAEngine == SIS_315_VGA)) {
3967	     temp = 1;
3968	  }
3969	  break;
3970       default:
3971	  temp = 1;
3972    }
3973
3974    if(temp) {
3975       SISErrorLog(pScrn,
3976            "Given color depth (%d) is not supported by this driver/chipset\n",
3977            pScrn->depth);
3978       goto my_error_1;
3979    }
3980
3981    xf86PrintDepthBpp(pScrn);
3982
3983    if( (((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
3984         (pScrn->bitsPerPixel == 24)) ||
3985	((pSiS->VGAEngine == SIS_OLD_VGA) && (pScrn->bitsPerPixel == 32)) ) {
3986       SISErrorLog(pScrn,
3987            "Framebuffer bpp %d not supported for this chipset\n", pScrn->bitsPerPixel);
3988       goto my_error_1;
3989    }
3990
3991    /* Get the depth24 pixmap format */
3992    if(pScrn->depth == 24 && pix24bpp == 0) {
3993       pix24bpp = xf86GetBppFromDepth(pScrn, 24);
3994    }
3995
3996    /*
3997     * This must happen after pScrn->display has been set because
3998     * xf86SetWeight references it.
3999     */
4000    if(pScrn->depth > 8) {
4001        /* The defaults are OK for us */
4002        rgb zeros = {0, 0, 0};
4003
4004        if(!xf86SetWeight(pScrn, zeros, zeros)) {
4005	    SISErrorLog(pScrn, "xf86SetWeight() error\n");
4006	    goto my_error_1;
4007        } else {
4008	   Bool ret = FALSE;
4009	   switch(pScrn->depth) {
4010	   case 15:
4011	      if((pScrn->weight.red != 5) ||
4012	         (pScrn->weight.green != 5) ||
4013		 (pScrn->weight.blue != 5)) ret = TRUE;
4014	      break;
4015	   case 16:
4016	      if((pScrn->weight.red != 5) ||
4017	         (pScrn->weight.green != 6) ||
4018		 (pScrn->weight.blue != 5)) ret = TRUE;
4019	      break;
4020	   case 24:
4021	      if((pScrn->weight.red != 8) ||
4022	         (pScrn->weight.green != 8) ||
4023		 (pScrn->weight.blue != 8)) ret = TRUE;
4024	      break;
4025	   }
4026	   if(ret) {
4027	      SISErrorLog(pScrn,
4028		   "RGB weight %d%d%d at depth %d not supported by hardware\n",
4029		   (int)pScrn->weight.red, (int)pScrn->weight.green,
4030		   (int)pScrn->weight.blue, pScrn->depth);
4031	      goto my_error_1;
4032	   }
4033        }
4034    }
4035
4036    /* Set the current layout parameters */
4037    pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
4038    pSiS->CurrentLayout.depth        = pScrn->depth;
4039    /* (Inside this function, we can use pScrn's contents anyway) */
4040
4041    if(!xf86SetDefaultVisual(pScrn, -1)) {
4042       SISErrorLog(pScrn, "xf86SetDefaultVisual() error\n");
4043       goto my_error_1;
4044    } else {
4045       /* We don't support DirectColor at > 8bpp */
4046       if(pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
4047	  SISErrorLog(pScrn,
4048	       "Given default visual (%s) is not supported at depth %d\n",
4049	        xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
4050	  goto my_error_1;
4051       }
4052    }
4053
4054#ifdef SISDUALHEAD
4055    /* Due to palette & timing problems we don't support 8bpp in DHM */
4056    if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel <= 8)) {
4057       SISErrorLog(pScrn, "Color depth %d not supported in Dual Head mode.\n",
4058			pScrn->bitsPerPixel);
4059       goto my_error_1;
4060    }
4061#endif
4062
4063    /* Read BIOS for 300/315/330/340 series customization */
4064    pSiS->SiS_Pr->VirtualRomBase = NULL;
4065    pSiS->BIOS = NULL;
4066    pSiS->SiS_Pr->UseROM = FALSE;
4067    pSiS->ROM661New = FALSE;
4068    pSiS->HaveXGIBIOS = FALSE;
4069
4070    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4071#ifdef SISDUALHEAD
4072       if(pSiSEnt) {
4073	  if(pSiSEnt->BIOS) {
4074	     pSiS->BIOS = pSiSEnt->BIOS;
4075	     pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4076	     pSiS->ROM661New = pSiSEnt->ROM661New;
4077	     pSiS->HaveXGIBIOS = pSiSEnt->HaveXGIBIOS;
4078	  }
4079       }
4080#endif
4081       if(!pSiS->BIOS) {
4082	  if(!(pSiS->BIOS = xcalloc(1, BIOS_SIZE))) {
4083	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4084		"Could not allocate memory for video BIOS image\n");
4085	  } else {
4086	     UShort mypciid = pSiS->Chipset;
4087	     UShort mypcivendor = (pSiS->ChipFlags & SiSCF_IsXGI) ? PCI_VENDOR_XGI : PCI_VENDOR_SIS;
4088	     Bool   found = FALSE, readpci = FALSE;
4089	     int    biossize = BIOS_SIZE;
4090
4091	     switch(pSiS->ChipType) {
4092	     case SIS_315:    mypciid = PCI_CHIP_SIS315;
4093			      readpci = TRUE;
4094			      break;
4095	     case SIS_315PRO: mypciid = PCI_CHIP_SIS315PRO;
4096			      readpci = TRUE;
4097			      break;
4098	     case SIS_300:
4099	     case SIS_315H:
4100	     case SIS_330:
4101	     case SIS_340:
4102	     case SIS_650:
4103	     case SIS_760:
4104	     case XGI_40:     readpci = TRUE;
4105			      break;
4106	     case XGI_20:     readpci = TRUE;
4107			      biossize = 0x8000;
4108			      break;
4109	     }
4110#if XSERVER_LIBPCIACCESS
4111	     if(readpci) {
4112		pSiS->PciInfo->rom_size = biossize;
4113		pci_device_read_rom(pSiS->PciInfo, pSiS->BIOS);
4114		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4115		   found = TRUE;
4116		}
4117	     }
4118#else
4119	     if(readpci) {
4120		xf86ReadPciBIOS(0, pSiS->PciTag, 0, pSiS->BIOS, biossize);
4121		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4122		   found = TRUE;
4123		}
4124	     }
4125
4126	     if(!found) {
4127	        ULong  segstart;
4128		for(segstart = BIOS_BASE; segstart < 0x000f0000; segstart += 0x00001000) {
4129
4130#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
4131		   if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, biossize) != biossize) continue;
4132#else
4133		   if(xf86ReadDomainMemory(pSiS->PciTag, segstart, biossize, pSiS->BIOS) != biossize) continue;
4134#endif
4135
4136		   if(!SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) continue;
4137
4138		   found = TRUE;
4139		   break;
4140		}
4141             }
4142#endif
4143	     if(found) {
4144		UShort romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4145		pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4146		if(pSiS->ChipFlags & SiSCF_IsXGI) {
4147		   pSiS->HaveXGIBIOS = pSiS->SiS_Pr->SiS_XGIROM = TRUE;
4148		   pSiS->SiS_Pr->UseROM = FALSE;
4149		   if(pSiS->ChipFlags & SiSCF_IsXGIV3) {
4150		      if(!(pSiS->BIOS[0x1d1] & 0x01)) {
4151			 pSiS->SiS_Pr->DDCPortMixup = TRUE;
4152		      }
4153	           }
4154	        } else {
4155		   pSiS->ROM661New = SiSDetermineROMLayout661(pSiS->SiS_Pr);
4156		}
4157		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4158			"Video BIOS version \"%7s\" found (%s data layout)\n",
4159			&pSiS->BIOS[romptr], pSiS->ROM661New ? "new SiS" :
4160				(pSiS->HaveXGIBIOS ? "XGI" : "old SiS"));
4161		if(pSiS->SiS_Pr->DDCPortMixup) {
4162		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4163			"*** Buggy XGI V3XT card detected: If VGA and DVI are connected at the\n");
4164		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4165			"*** same time, BIOS and driver will be unable to detect DVI connection.\n");
4166		}
4167#ifdef SISDUALHEAD
4168		if(pSiSEnt) {
4169		   pSiSEnt->BIOS = pSiS->BIOS;
4170		   pSiSEnt->ROM661New = pSiS->ROM661New;
4171		   pSiSEnt->HaveXGIBIOS = pSiS->HaveXGIBIOS;
4172		}
4173#endif
4174	     } else {
4175	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4176			 "Could not find/read video BIOS\n");
4177		xfree(pSiS->BIOS);
4178		pSiS->BIOS = NULL;
4179	     }
4180          }
4181       }
4182
4183       if(!(pSiS->ChipFlags & SiSCF_IsXGI)) {
4184          if(pSiS->BIOS) pSiS->SiS_Pr->UseROM = TRUE;
4185          else           pSiS->SiS_Pr->UseROM = FALSE;
4186       }
4187    }
4188
4189    /* Evaluate options */
4190    SiSOptions(pScrn);
4191
4192#ifdef SISMERGED
4193    /* Due to palette & timing problems we don't support 8bpp in MFBM */
4194    if((pSiS->MergedFB) && (pScrn->bitsPerPixel <= 8)) {
4195       SISErrorLog(pScrn, "MergedFB: Color depth %d not supported, %s\n",
4196			pScrn->bitsPerPixel, mergeddisstr);
4197       pSiS->MergedFB = pSiS->MergedFBAuto = FALSE;
4198    }
4199#endif
4200
4201    /* Probe CPU features */
4202#ifdef SISDUALHEAD
4203    if(pSiS->DualHeadMode) {
4204       pSiS->CPUFlags = pSiSEnt->CPUFlags;
4205    }
4206#endif
4207    if(!pSiS->CPUFlags) {
4208       pSiS->CPUFlags = SiSGetCPUFlags(pScrn);
4209       pSiS->CPUFlags |= SIS_CPUFL_FLAG;
4210#ifdef SISDUALHEAD
4211       if(pSiS->DualHeadMode) pSiSEnt->CPUFlags = pSiS->CPUFlags;
4212#endif
4213    }
4214
4215    /* We use a programamble clock */
4216    pScrn->progClock = TRUE;
4217
4218    /* Set the bits per RGB for 8bpp mode */
4219    if(pScrn->depth == 8) pScrn->rgbBits = 8;
4220
4221#ifdef SISDUALHEAD
4222    if(pSiS->DualHeadMode) {
4223       if(!pSiS->SecondHead) {
4224	  /* Copy some option settings to entity private */
4225	  pSiSEnt->HWCursor = pSiS->HWCursor;
4226	  pSiSEnt->NoAccel = pSiS->NoAccel;
4227	  pSiSEnt->useEXA = pSiS->useEXA;
4228	  pSiSEnt->restorebyset = pSiS->restorebyset;
4229	  pSiSEnt->OptROMUsage = pSiS->OptROMUsage;
4230	  pSiSEnt->OptUseOEM = pSiS->OptUseOEM;
4231	  pSiSEnt->TurboQueue = pSiS->TurboQueue;
4232	  pSiSEnt->forceCRT1 = pSiS->forceCRT1;
4233	  pSiSEnt->ForceCRT1Type = pSiS->ForceCRT1Type;
4234	  pSiSEnt->CRT1TypeForced = pSiS->CRT1TypeForced;
4235	  pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type;
4236	  pSiSEnt->ForceTVType = pSiS->ForceTVType;
4237	  pSiSEnt->ForceYPbPrType = pSiS->ForceYPbPrType;
4238	  pSiSEnt->ForceYPbPrAR = pSiS->ForceYPbPrAR;
4239	  pSiSEnt->UsePanelScaler = pSiS->UsePanelScaler;
4240	  pSiSEnt->CenterLCD = pSiS->CenterLCD;
4241	  pSiSEnt->DSTN = pSiS->DSTN;
4242	  pSiSEnt->FSTN = pSiS->FSTN;
4243	  pSiSEnt->OptTVStand = pSiS->OptTVStand;
4244	  pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL;
4245	  pSiSEnt->NonDefaultNTSC = pSiS->NonDefaultNTSC;
4246	  pSiSEnt->chtvtype = pSiS->chtvtype;
4247	  pSiSEnt->OptTVOver = pSiS->OptTVOver;
4248	  pSiSEnt->OptTVSOver = pSiS->OptTVSOver;
4249	  pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
4250	  pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
4251	  pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
4252	  pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth;
4253	  pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
4254	  pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance;
4255	  pSiSEnt->chtvcontrast = pSiS->chtvcontrast;
4256	  pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
4257	  pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance;
4258	  pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker;
4259	  pSiSEnt->sistvsaturation = pSiS->sistvsaturation;
4260	  pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
4261	  pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
4262	  pSiSEnt->sistvcolcalibc = pSiS->sistvcolcalibc;
4263	  pSiSEnt->sistvcolcalibf = pSiS->sistvcolcalibf;
4264	  pSiSEnt->tvxpos = pSiS->tvxpos;
4265	  pSiSEnt->tvypos = pSiS->tvypos;
4266	  pSiSEnt->tvxscale = pSiS->tvxscale;
4267	  pSiSEnt->tvyscale = pSiS->tvyscale;
4268	  pSiSEnt->siscrt1satgain = pSiS->siscrt1satgain;
4269	  pSiSEnt->crt1satgaingiven = pSiS->crt1satgaingiven;
4270	  pSiSEnt->CRT1gamma = pSiS->CRT1gamma;
4271	  pSiSEnt->CRT1gammaGiven = pSiS->CRT1gammaGiven;
4272	  pSiSEnt->XvGammaRed = pSiS->XvGammaRed;
4273	  pSiSEnt->XvGammaGreen = pSiS->XvGammaGreen;
4274	  pSiSEnt->XvGammaBlue = pSiS->XvGammaBlue;
4275	  pSiSEnt->XvGamma = pSiS->XvGamma;
4276	  pSiSEnt->XvGammaGiven = pSiS->XvGammaGiven;
4277	  pSiSEnt->CRT2gamma = pSiS->CRT2gamma;
4278	  pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2;
4279	  pSiSEnt->AllowHotkey = pSiS->AllowHotkey;
4280	  pSiSEnt->enablesisctrl = pSiS->enablesisctrl;
4281	  pSiSEnt->SenseYPbPr = pSiS->SenseYPbPr;
4282	  pSiSEnt->XvUseMemcpy = pSiS->XvUseMemcpy;
4283	  pSiSEnt->BenchMemCpy = pSiS->BenchMemCpy;
4284#ifdef SIS_CP
4285	  SIS_CP_DRIVER_COPYOPTIONSENT
4286#endif
4287       } else {
4288	  /* We always use same cursor type on both screens */
4289	  pSiS->HWCursor = pSiSEnt->HWCursor;
4290	  /* We need identical NoAccel setting */
4291	  pSiS->NoAccel = pSiSEnt->NoAccel;
4292	  pSiS->useEXA = pSiSEnt->useEXA;
4293	  pSiS->TurboQueue = pSiSEnt->TurboQueue;
4294	  pSiS->restorebyset = pSiSEnt->restorebyset;
4295	  pSiS->AllowHotkey = pSiS->AllowHotkey;
4296	  pSiS->OptROMUsage = pSiSEnt->OptROMUsage;
4297	  pSiS->OptUseOEM = pSiSEnt->OptUseOEM;
4298	  pSiS->forceCRT1 = pSiSEnt->forceCRT1;
4299	  pSiS->nocrt2ddcdetection = FALSE;
4300	  pSiS->forcecrt2redetection = FALSE;
4301	  pSiS->ForceCRT1Type = pSiSEnt->ForceCRT1Type;
4302	  pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type;
4303	  pSiS->CRT1TypeForced = pSiSEnt->CRT1TypeForced;
4304	  pSiS->UsePanelScaler = pSiSEnt->UsePanelScaler;
4305	  pSiS->CenterLCD = pSiSEnt->CenterLCD;
4306	  pSiS->DSTN = pSiSEnt->DSTN;
4307	  pSiS->FSTN = pSiSEnt->FSTN;
4308	  pSiS->OptTVStand = pSiSEnt->OptTVStand;
4309	  pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL;
4310	  pSiS->NonDefaultNTSC = pSiSEnt->NonDefaultNTSC;
4311	  pSiS->chtvtype = pSiSEnt->chtvtype;
4312	  pSiS->ForceTVType = pSiSEnt->ForceTVType;
4313	  pSiS->ForceYPbPrType = pSiSEnt->ForceYPbPrType;
4314	  pSiS->ForceYPbPrAR = pSiSEnt->ForceYPbPrAR;
4315	  pSiS->OptTVOver = pSiSEnt->OptTVOver;
4316	  pSiS->OptTVSOver = pSiSEnt->OptTVSOver;
4317	  pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
4318	  pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
4319	  pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
4320	  pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
4321	  pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
4322	  pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor;
4323	  pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance;
4324	  pSiS->chtvcontrast = pSiSEnt->chtvcontrast;
4325	  pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance;
4326	  pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker;
4327	  pSiS->sistvsaturation = pSiSEnt->sistvsaturation;
4328	  pSiS->sistvcfilter = pSiSEnt->sistvcfilter;
4329	  pSiS->sistvyfilter = pSiSEnt->sistvyfilter;
4330	  pSiS->sistvcolcalibc = pSiSEnt->sistvcolcalibc;
4331	  pSiS->sistvcolcalibf = pSiSEnt->sistvcolcalibf;
4332	  pSiS->tvxpos = pSiSEnt->tvxpos;
4333	  pSiS->tvypos = pSiSEnt->tvypos;
4334	  pSiS->tvxscale = pSiSEnt->tvxscale;
4335	  pSiS->tvyscale = pSiSEnt->tvyscale;
4336	  pSiS->SenseYPbPr = pSiSEnt->SenseYPbPr;
4337	  if(!pSiS->CRT1gammaGiven) {
4338	     if(pSiSEnt->CRT1gammaGiven)
4339	        pSiS->CRT1gamma = pSiSEnt->CRT1gamma;
4340	  }
4341	  pSiS->CRT2gamma = pSiSEnt->CRT2gamma;
4342	  if(!pSiS->XvGammaGiven) {
4343	     if(pSiSEnt->XvGammaGiven) {
4344		pSiS->XvGamma = pSiSEnt->XvGamma;
4345		pSiS->XvGammaRed = pSiS->XvGammaRedDef = pSiSEnt->XvGammaRed;
4346		pSiS->XvGammaGreen = pSiS->XvGammaGreenDef = pSiSEnt->XvGammaGreen;
4347		pSiS->XvGammaBlue = pSiS->XvGammaBlueDef = pSiSEnt->XvGammaBlue;
4348	     }
4349	  }
4350	  if(!pSiS->crt1satgaingiven) {
4351	     if(pSiSEnt->crt1satgaingiven)
4352	        pSiS->siscrt1satgain = pSiSEnt->siscrt1satgain;
4353	  }
4354	  pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2;
4355	  pSiS->enablesisctrl = pSiSEnt->enablesisctrl;
4356	  pSiS->XvUseMemcpy = pSiSEnt->XvUseMemcpy;
4357	  pSiS->BenchMemCpy = pSiSEnt->BenchMemCpy;
4358	  /* Copy gamma brightness to Ent (sic!) for Xinerama */
4359	  pSiSEnt->GammaBriR = pSiS->GammaBriR;
4360	  pSiSEnt->GammaBriG = pSiS->GammaBriG;
4361	  pSiSEnt->GammaBriB = pSiS->GammaBriB;
4362	  pSiSEnt->NewGammaBriR = pSiS->NewGammaBriR;
4363	  pSiSEnt->NewGammaBriG = pSiS->NewGammaBriG;
4364	  pSiSEnt->NewGammaBriB = pSiS->NewGammaBriB;
4365	  pSiSEnt->NewGammaConR = pSiS->NewGammaConR;
4366	  pSiSEnt->NewGammaConG = pSiS->NewGammaConG;
4367	  pSiSEnt->NewGammaConB = pSiS->NewGammaConB;
4368#ifdef SIS_CP
4369	  SIS_CP_DRIVER_COPYOPTIONS
4370#endif
4371       }
4372    }
4373#endif
4374
4375    /* Handle UseROMData, NoOEM and UsePanelScaler options */
4376    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4377       from = X_PROBED;
4378       if(pSiS->OptROMUsage == 0) {
4379	  pSiS->SiS_Pr->UseROM = FALSE;
4380	  from = X_CONFIG;
4381	  xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is disabled\n");
4382       }
4383
4384       if(!pSiS->OptUseOEM) {
4385	  xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV/VGA2 data usage is disabled\n");
4386       }
4387
4388       pSiS->SiS_Pr->UsePanelScaler = pSiS->UsePanelScaler;
4389       pSiS->SiS_Pr->CenterScreen = pSiS->CenterLCD;
4390    }
4391
4392    /* Do some HW configuration detection (memory amount & type, clock, etc) */
4393    SiSSetup(pScrn);
4394
4395    /* Get framebuffer address */
4396    if(pSiS->pEnt->device->MemBase != 0) {
4397       /*
4398	* XXX Should check that the config file value matches one of the
4399	* PCI base address values.
4400	*/
4401       pSiS->FbAddress = pSiS->pEnt->device->MemBase;
4402       from = X_CONFIG;
4403    } else {
4404       pSiS->FbAddress = PCI_REGION_BASE(pSiS->PciInfo, 0, REGION_MEM) & 0xFFFFFFF0;
4405       from = X_PROBED;
4406    }
4407
4408#ifdef SISDUALHEAD
4409    if(pSiS->DualHeadMode)
4410       xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n",
4411	   (ULong)pSiS->FbAddress);
4412    else
4413#endif
4414       xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
4415	   (ULong)pSiS->FbAddress);
4416
4417    pSiS->realFbAddress = pSiS->FbAddress;
4418
4419    /* Get MMIO address */
4420    if(pSiS->pEnt->device->IOBase != 0) {
4421       /*
4422	* XXX Should check that the config file value matches one of the
4423	* PCI base address values.
4424	*/
4425       pSiS->IOAddress = pSiS->pEnt->device->IOBase;
4426       from = X_CONFIG;
4427    } else {
4428       pSiS->IOAddress = PCI_REGION_BASE(pSiS->PciInfo, 1, REGION_MEM) & 0xFFFFFFF0;
4429       from = X_PROBED;
4430    }
4431    xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX (size %ldK)\n",
4432	   (ULong)pSiS->IOAddress, pSiS->mmioSize);
4433
4434#ifndef XSERVER_LIBPCIACCESS
4435    /* Register the PCI-assigned resources */
4436    if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) {
4437       SISErrorLog(pScrn, "PCI resource conflicts detected\n");
4438#ifdef SISDUALHEAD
4439       if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
4440#endif
4441       sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
4442       if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
4443       SISFreeRec(pScrn);
4444       return FALSE;
4445    }
4446#endif
4447
4448    from = X_PROBED;
4449    if(pSiS->pEnt->device->videoRam != 0) {
4450       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
4451	  pScrn->videoRam = pSiS->pEnt->device->videoRam;
4452	  from = X_CONFIG;
4453       } else {
4454	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4455		"Option \"VideoRAM\" ignored\n");
4456       }
4457    }
4458
4459    pSiS->RealVideoRam = pScrn->videoRam;
4460
4461    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4462       (pScrn->videoRam > 4096)            &&
4463       (from != X_CONFIG)) {
4464       pScrn->videoRam = 4096;
4465       xf86DrvMsg(pScrn->scrnIndex, from,
4466	   "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n",
4467	   pSiS->RealVideoRam, pScrn->videoRam);
4468    } else {
4469       xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam);
4470    }
4471
4472    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4473       (pScrn->videoRam > 4096)) {
4474       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4475	   "SiS6326 engines do not support more than 4096KB RAM, therefore\n");
4476       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4477	   "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n");
4478       pSiS->TurboQueue = FALSE;
4479       pSiS->HWCursor   = FALSE;
4480       pSiS->NoXvideo   = TRUE;
4481       pSiS->NoAccel    = TRUE;
4482    }
4483
4484    pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024;
4485
4486    /* Calculate real availMem according to Accel/TurboQueue and
4487     * HWCursur setting. Also, initialize some variables used
4488     * in other modules.
4489     */
4490    pSiS->cursorOffset = 0;
4491    pSiS->CurARGBDest = NULL;
4492    pSiS->CurMonoSrc = NULL;
4493    pSiS->CurFGCol = pSiS->CurBGCol = 0;
4494    pSiS->FbBaseOffset = 0;
4495
4496    switch(pSiS->VGAEngine) {
4497
4498      case SIS_300_VGA:
4499	pSiS->TurboQueueLen = 512;
4500	if(pSiS->TurboQueue) {
4501	   pSiS->availMem -= (pSiS->TurboQueueLen*1024);
4502	   pSiS->cursorOffset = 512;
4503	}
4504	if(pSiS->HWCursor) {
4505	   pSiS->availMem -= pSiS->CursorSize;
4506	   if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize;
4507	}
4508	pSiS->CmdQueLenMask = 0xFFFF;
4509	pSiS->CmdQueLenFix  = 0;
4510	pSiS->cursorBufferNum = 0;
4511#ifdef SISDUALHEAD
4512	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4513#endif
4514	break;
4515
4516      case SIS_315_VGA:
4517#ifdef SISVRAMQ		/* VRAM queue */
4518	pSiS->cmdQueueSizeMask = pSiS->cmdQueueSize - 1;	/* VRAM Command Queue is variable (in therory) */
4519	pSiS->cmdQueueOffset = (pScrn->videoRam * 1024) - pSiS->cmdQueueSize;
4520	pSiS->cmdQueueLen = 0;
4521	pSiS->cmdQueueSize_div2 = pSiS->cmdQueueSize / 2;
4522	pSiS->cmdQueueSize_div4 = pSiS->cmdQueueSize / 4;
4523	pSiS->cmdQueueSize_4_3 = (pSiS->cmdQueueSize / 4) * 3;
4524	pSiS->availMem -= pSiS->cmdQueueSize;
4525	pSiS->cursorOffset = (pSiS->cmdQueueSize / 1024);
4526
4527	/* Set up shared pointer to current offset */
4528#ifdef SISDUALHEAD
4529	if(pSiS->DualHeadMode)
4530	   pSiS->cmdQ_SharedWritePort = &(pSiSEnt->cmdQ_SharedWritePort_2D);
4531	else
4532#endif
4533	   pSiS->cmdQ_SharedWritePort = &(pSiS->cmdQ_SharedWritePort_2D);
4534
4535
4536#else			/* MMIO */
4537	if(pSiS->TurboQueue) {
4538	   pSiS->availMem -= (512*1024);			/* MMIO Command Queue is 512k (variable in theory) */
4539	   pSiS->cursorOffset = 512;
4540	}
4541#endif
4542	if(pSiS->HWCursor) {
4543	   pSiS->availMem -= (pSiS->CursorSize * 2);
4544	   if(pSiS->OptUseColorCursor) pSiS->availMem -= (pSiS->CursorSize * 2);
4545	}
4546	pSiS->cursorBufferNum = 0;
4547#ifdef SISDUALHEAD
4548	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4549#endif
4550
4551	if((pSiS->SiS76xLFBSize) && (pSiS->SiS76xUMASize)) {
4552	   pSiS->availMem -= pSiS->SiS76xUMASize;
4553	   pSiS->FbBaseOffset = pSiS->SiS76xUMASize;
4554	}
4555
4556	break;
4557
4558      default:
4559	/* cursorOffset not used in cursor functions for 530 and
4560	 * older chips, because the cursor is *above* the TQ.
4561	 * On 5597 and older revisions of the 6326, the TQ is
4562	 * max 32K, on newer 6326 revisions and the 530 either 30
4563	 * (or 32?) or 62K (or 64?). However, to make sure, we
4564	 * use only 30K (or 32?), but reduce the available memory
4565	 * by 64, and locate the TQ at the beginning of this last
4566	 * 64K block. (We do this that way even when using the
4567	 * HWCursor, because the cursor only takes 2K and the
4568	 * queue does not seem to last that far anyway.)
4569	 * The TQ must be located at 32KB boundaries.
4570	 */
4571	if(pSiS->RealVideoRam < 3072) {
4572	   if(pSiS->TurboQueue) {
4573	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4574		    "Not enough video RAM for TurboQueue. TurboQueue disabled\n");
4575	      pSiS->TurboQueue = FALSE;
4576	   }
4577	}
4578	pSiS->CmdQueMaxLen = 32;
4579	if(pSiS->TurboQueue) {
4580			      pSiS->availMem -= (64*1024);
4581			      pSiS->CmdQueMaxLen = 900;   /* To make sure; should be 992 */
4582	} else if(pSiS->HWCursor) {
4583			      pSiS->availMem -= pSiS->CursorSize;
4584	}
4585	if(pSiS->Chipset == PCI_CHIP_SIS530) {
4586		/* Check if Flat Panel is enabled */
4587		inSISIDXREG(SISSR, 0x0e, tempreg);
4588		if(!(tempreg & 0x04)) pSiS->availMem -= pSiS->CursorSize;
4589
4590		/* Set up mask for MMIO register */
4591		pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF;
4592	} else {
4593	        /* TQ is never used on 6326/5597, because the accelerator
4594		 * always Syncs. So this is just cosmentic work. (And I
4595		 * am not even sure that 0x7fff is correct. MMIO 0x83a8
4596		 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled.
4597		 * The datasheet has no real explanation on the queue length
4598		 * if the TQ is enabled. Not syncing and waiting for a
4599		 * suitable queue length instead does not work.
4600		 */
4601	        pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F;
4602	}
4603
4604	/* This is to be subtracted from MMIO queue length register contents
4605	 * for getting the real Queue length.
4606	 */
4607	pSiS->CmdQueLenFix  = (pSiS->TurboQueue) ? 32 : 0;
4608    }
4609
4610
4611#ifdef SISDUALHEAD
4612    /* In dual head mode, we share availMem equally - so align it
4613     * to 8KB; this way, the address of the FB of the second
4614     * head is aligned to 4KB for mapping.
4615     */
4616   if(pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000;
4617#endif
4618
4619    /* Check MaxXFBMem setting */
4620#ifdef SISDUALHEAD
4621    if(pSiS->DualHeadMode) {
4622        /* 1. Since DRI is not supported in dual head mode, we
4623	 *    don't need the MaxXFBMem setting - ignore it.
4624	 */
4625	if(pSiS->maxxfbmem) {
4626	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4627		"MaxXFBMem ignored in Dual Head mode\n");
4628	}
4629	pSiS->maxxfbmem = pSiS->availMem;
4630    } else
4631#endif
4632	   if((pSiS->sisfbHeapStart) || (pSiS->sisfbHaveNewHeapDef)) {
4633
4634       /*
4635	* 2. We have memory layout info from sisfb - ignore MaxXFBMem
4636	*/
4637	if(pSiS->maxxfbmem) {
4638	   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4639		"Got memory layout info from sisfb, ignoring MaxXFBMem option\n");
4640	}
4641	if((pSiS->FbBaseOffset) && (!pSiS->sisfbHaveNewHeapDef)) {
4642	   xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4643		"Incompatible sisfb version detected, DRI disabled\n");
4644	   pSiS->loadDRI = FALSE;
4645	   pSiS->maxxfbmem = pSiS->availMem;
4646	} else {
4647	   if(pSiS->FbBaseOffset) {
4648	      /* Revert our changes to FbBaseOffset and availMem; use sisfb's info */
4649	      pSiS->availMem += pSiS->FbBaseOffset;
4650	      pSiS->FbBaseOffset = 0;
4651	   }
4652	   if(pSiS->sisfbVideoOffset) {
4653	      /* a. DRI heap BELOW framebuffer */
4654	      pSiS->FbBaseOffset = pSiS->sisfbVideoOffset;
4655	      pSiS->availMem -= pSiS->FbBaseOffset;
4656	      pSiS->maxxfbmem = pSiS->availMem;
4657	   } else {
4658	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4659	      if(pSiS->availMem < (pSiS->sisfbHeapStart * 1024)) {
4660		 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4661			"Internal error - sisfb memory layout corrupt\n");
4662		 pSiS->loadDRI = FALSE;
4663		 pSiS->maxxfbmem = pSiS->availMem;
4664	      } else {
4665	         pSiS->maxxfbmem = pSiS->sisfbHeapStart * 1024;
4666	      }
4667	   }
4668	}
4669
4670    } else if(pSiS->maxxfbmem) {
4671
4672       /*
4673	* 3. No sisfb, but user gave "MaxXFBMem"
4674	*/
4675	if(pSiS->FbBaseOffset) {
4676	   /* a. DRI heap BELOW framebuffer */
4677	   if(pSiS->maxxfbmem > (pSiS->availMem + pSiS->FbBaseOffset - pSiS->SiS76xUMASize)) {
4678	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4679			"Invalid MaxXFBMem setting\n");
4680	      pSiS->maxxfbmem = pSiS->availMem;
4681	   } else {
4682	      /* Revert our changes */
4683	      pSiS->availMem += pSiS->FbBaseOffset;
4684	      /* Use user's MaxXFBMem setting */
4685	      pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4686	      pSiS->availMem -= pSiS->FbBaseOffset;
4687	   }
4688	} else {
4689	   /* b. DRI heap ABOVE framebuffer (traditional layout) */
4690	   if(pSiS->maxxfbmem > pSiS->availMem) {
4691	      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4692			 "Invalid MaxXFBMem setting.\n");
4693	      pSiS->maxxfbmem = pSiS->availMem;
4694	   }
4695	}
4696
4697    } else {
4698
4699       /*
4700	* 4. No MaxXFBMem, no sisfb: Use all memory
4701	*/
4702	pSiS->maxxfbmem = pSiS->availMem;
4703
4704	/* ... except on chipsets, for which DRI is
4705	 * supported: If DRI is enabled, we now limit
4706	 * ourselves to a reasonable default:
4707	 */
4708
4709	if(pSiS->loadDRI) {
4710	   if(pSiS->FbBaseOffset) {
4711	      /* a. DRI heap BELOW framebuffer */
4712	      /* See how much UMA and LFB memory we have,
4713	       * and calculate a reasonable default. We
4714	       * use more vram for ourselves because these
4715	       * chips are eg. capable of larger Xv
4716	       * overlays, etc.
4717	       */
4718	      unsigned long total = (pSiS->SiS76xLFBSize + pSiS->SiS76xUMASize) / 1024;
4719	      unsigned long mymax;
4720	      if(total <= 16384)			/* <= 16MB: Use 8MB for X */
4721	         mymax = 8192 * 1024;
4722	      else if(total <= 32768)			/* <= 32MB: Use 16MB for X */
4723	         mymax = 16384 * 1024;
4724	      else					/* Otherwise: Use 20MB for X */
4725	         mymax = 20 * 1024 * 1024;
4726	      /* availMem is right now adjusted to not use the UMA
4727	       * area. Make sure that our default doesn't reach
4728	       * into the UMA area either.
4729	       */
4730	      if(pSiS->availMem > mymax) {
4731		 /* Write our default to maxxfbmem */
4732		 pSiS->maxxfbmem = mymax;
4733		 /* Revert our changes to availMem */
4734		 pSiS->availMem += pSiS->FbBaseOffset;
4735		 /* Use our default setting */
4736		 pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4737		 pSiS->availMem -= pSiS->FbBaseOffset;
4738	      }
4739	   } else {
4740	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4741	      /* See how much video memory we have, and calculate
4742	       * a reasonable default.
4743	       * Since DRI is pointless with less than 4MB of total
4744	       * video RAM, we disable it in that case.
4745	       */
4746	      if(pScrn->videoRam <= 4096)
4747	         pSiS->loadDRI = FALSE;
4748	      else if(pScrn->videoRam <= 8192)		/* <= 8MB: Use 4MB for X */
4749	         pSiS->maxxfbmem = 4096 * 1024;
4750	      else if(pScrn->videoRam <= 16384)		/* <= 16MB: Use 8MB for X */
4751	         pSiS->maxxfbmem = 8192 * 1024;
4752#ifdef SISMERGED					/* Otherwise: --- */
4753	      else if(pSiS->MergedFB) {
4754	         if(pScrn->videoRam <= 65536)
4755	            pSiS->maxxfbmem = 16384 * 1024;	/* If MergedFB and <=64MB, use 16MB for X */
4756		 else
4757		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* If MergedFB and > 64MB, use 20MB for X */
4758	      }
4759#endif
4760	        else if(pSiS->VGAEngine == SIS_315_VGA) {
4761	         if(pScrn->videoRam <= 65536)
4762	            pSiS->maxxfbmem = 16384 * 1024;	/* On >=315 series and <=64MB, use 16MB */
4763		 else
4764		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* On >=315 series and > 64MB, use 20MB */
4765	      } else
4766	         pSiS->maxxfbmem = 12288 * 1024;	/* On <315 series, use 12MB */
4767
4768	      /* A final check */
4769	      if(pSiS->maxxfbmem > pSiS->availMem) {
4770		 pSiS->maxxfbmem = pSiS->availMem;
4771		 pSiS->loadDRI = FALSE;
4772	      }
4773	   }
4774
4775	}
4776    }
4777
4778    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory at offset %dK\n",
4779				pSiS->maxxfbmem / 1024, pSiS->FbBaseOffset / 1024);
4780
4781    /* Find out about sub-classes of some chipsets and check
4782     * if the chipset supports two video overlays
4783     */
4784    if(pSiS->VGAEngine == SIS_300_VGA    ||
4785       pSiS->VGAEngine == SIS_315_VGA    ||
4786       pSiS->Chipset == PCI_CHIP_SIS530  ||
4787       pSiS->Chipset == PCI_CHIP_SIS6326 ||
4788       pSiS->Chipset == PCI_CHIP_SIS5597)  {
4789       pSiS->hasTwoOverlays = FALSE;
4790       switch(pSiS->Chipset) {
4791	 case PCI_CHIP_SIS300:
4792	 case PCI_CHIP_SIS540:  /* ? (If not, need to add the SwitchCRT Xv attribute!) */
4793	 case PCI_CHIP_SIS630:
4794	 case PCI_CHIP_SIS550:
4795	   pSiS->hasTwoOverlays = TRUE;
4796	   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4797	   break;
4798	 case PCI_CHIP_SIS315PRO:
4799	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4800	   break;
4801	 case PCI_CHIP_SIS330:
4802	   pSiS->ChipFlags |= (SiSCF_CRT2HWCKaputt | SiSCF_LARGEOVERLAY);
4803	   break;
4804	 case PCI_CHIP_SIS340:
4805	 case PCI_CHIP_XGIXG40: /* Verified: only 1 overlay */
4806	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4807	   break;
4808	 case PCI_CHIP_SIS650:
4809	   {
4810	     UChar tempreg1, tempreg2;
4811	     static const char *id650str[] = {
4812		"650",       "650",       "650",       "650",
4813		"650 A0 AA", "650 A2 CA", "650",       "650",
4814		"M650 A0",   "M650 A1 AA","651 A0 AA", "651 A1 AA",
4815		"M650",      "65?",       "651",       "65?"
4816	     };
4817	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4818	     if(pSiS->ChipType == SIS_650) {
4819		inSISIDXREG(SISCR, 0x5f, CR5F);
4820		CR5F &= 0xf0;
4821		andSISIDXREG(SISCR, 0x5c, 0x07);
4822		inSISIDXREG(SISCR, 0x5c, tempreg1);
4823		tempreg1 &= 0xf8;
4824		orSISIDXREG(SISCR, 0x5c, 0xf8);
4825		inSISIDXREG(SISCR, 0x5c, tempreg2);
4826		tempreg2 &= 0xf8;
4827		if((!tempreg1) || (tempreg2)) {
4828		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4829		      "SiS650 revision ID %x (%s)\n", CR5F, id650str[CR5F >> 4]);
4830		   if(CR5F & 0x80) {
4831		      pSiS->hasTwoOverlays = TRUE;  /* M650 or 651 */
4832		      pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4833		   }
4834		   switch(CR5F) {
4835		      case 0xa0:
4836		      case 0xb0:
4837		      case 0xe0:
4838		         pSiS->ChipFlags |= SiSCF_Is651;
4839		         break;
4840		      case 0x80:
4841		      case 0x90:
4842		      case 0xc0:
4843		         pSiS->ChipFlags |= SiSCF_IsM650;
4844		         break;
4845		   }
4846		} else {
4847		   pSiS->hasTwoOverlays = TRUE;
4848		   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4849		   switch(CR5F) {
4850		      case 0x90:
4851			 inSISIDXREG(SISCR, 0x5c, tempreg1);
4852			 tempreg1 &= 0xf8;
4853			 switch(tempreg1) {
4854			    case 0x00:
4855			       pSiS->ChipFlags |= SiSCF_IsM652;
4856			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4857			           "SiSM652 revision ID %x\n", CR5F);
4858			       break;
4859			    case 0x40:
4860			       pSiS->ChipFlags |= SiSCF_IsM653;
4861			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4862			           "SiSM653 revision ID %x\n", CR5F);
4863			       break;
4864			    default:
4865			       pSiS->ChipFlags |= SiSCF_IsM650;
4866			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4867			           "SiSM650 revision ID %x\n", CR5F);
4868			       break;
4869			 }
4870			 break;
4871		      case 0xb0:
4872			 pSiS->ChipFlags |= SiSCF_Is652;
4873			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4874			     "SiS652 revision ID %x\n", CR5F);
4875			 break;
4876		      default:
4877			 pSiS->ChipFlags |= SiSCF_IsM650;
4878			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4879			     "SiSM650 revision ID %x\n", CR5F);
4880			 break;
4881		   }
4882		}
4883	     }
4884	     break;
4885	   }
4886	 case PCI_CHIP_SIS660:
4887	   {
4888	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4889	     pSiS->hasTwoOverlays = TRUE;
4890	     pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4891	     /* 760/761:  - UMA only: one/two overlays - dotclock dependent
4892			  - UMA+LFB:  two overlays if video data in LFB
4893			  - LFB only: two overlays
4894		If UMA only: Must switch between one/two overlays on the fly (done
4895			     in PostSetMode())
4896		If LFB+UMA:  We use LFB memory only and leave UMA to an eventually
4897			     written DRI driver.
4898	      */
4899	     break;
4900	   }
4901       }
4902
4903       if(!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY)) {
4904          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4905		"Hardware supports %s video overlay%s\n",
4906		pSiS->hasTwoOverlays ? "two" : "one",
4907		pSiS->hasTwoOverlays ? "s" : "");
4908       }
4909
4910       if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {
4911	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4912		"\n\tDear SiS76x user, your machine is using a shared memory framebuffer.\n"
4913		  "\tDue to hardware limitations of the SiS chip in combination with the\n"
4914		  "\tAMD CPU, video overlay support is very limited on this machine. If you\n"
4915		  "\texperience flashing lines in the video and/or the graphics display\n"
4916		  "\tduring video playback, reduce the color depth and/or the resolution\n"
4917		  "\tand/or the refresh rate. Alternatively, use the video blitter.\n");
4918       }
4919
4920    }
4921
4922    /* Backup VB connection and CRT1 on/off register */
4923    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4924       inSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
4925       inSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
4926       inSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
4927       inSISIDXREG(SISCR, 0x36, pSiS->oldCR36);
4928       inSISIDXREG(SISCR, 0x37, pSiS->oldCR37);
4929       if(pSiS->VGAEngine == SIS_315_VGA) {
4930          inSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
4931       }
4932
4933       pSiS->postVBCR32 = pSiS->oldCR32;
4934    }
4935
4936    /* There are some machines out there which require a special
4937     * setup of the GPIO registers in order to make the Chrontel
4938     * work. Try to find out if we're running on such a machine.
4939     * Furthermore, there is some highly customized hardware,
4940     * which requires some non-standard LVDS timing. Since the
4941     * vendors don't seem to care about PCI subsystem ID's we
4942     * need to find out using the BIOS version and date strings.
4943     */
4944    pSiS->SiS_Pr->SiS_ChSW = FALSE;
4945    if(pSiS->Chipset == PCI_CHIP_SIS630) {
4946       int i = 0;
4947       do {
4948	  if(mychswtable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
4949	     mychswtable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
4950	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4951	         "PCI subsystem ID found in list for Chrontel/GPIO setup:\n");
4952	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4953		 "\tVendor/Card: %s %s (ID %04x)\n",
4954		  mychswtable[i].vendorName,
4955		  mychswtable[i].cardName,
4956		  PCI_SUB_DEVICE_ID(pSiS->PciInfo));
4957	     pSiS->SiS_Pr->SiS_ChSW = TRUE;
4958	     break;
4959          }
4960          i++;
4961       } while(mychswtable[i].subsysVendor != 0);
4962    }
4963
4964    if(pSiS->SiS_Pr->SiS_CustomT == CUT_NONE) {
4965       int    i = 0, j;
4966       UShort bversptr = 0;
4967       Bool   footprint;
4968       CARD32 chksum = 0;
4969
4970       if(pSiS->SiS_Pr->UseROM) {
4971          bversptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4972          for(i=0; i<32768; i++) chksum += pSiS->BIOS[i];
4973       }
4974
4975       i = 0;
4976       do {
4977	  if( (SiS_customttable[i].chipID == pSiS->ChipType)                            &&
4978	      ((!strlen(SiS_customttable[i].biosversion)) ||
4979	       (pSiS->SiS_Pr->UseROM &&
4980	       (!strncmp(SiS_customttable[i].biosversion, (char *)&pSiS->BIOS[bversptr],
4981	                strlen(SiS_customttable[i].biosversion)))))                     &&
4982	      ((!strlen(SiS_customttable[i].biosdate)) ||
4983	       (pSiS->SiS_Pr->UseROM &&
4984	       (!strncmp(SiS_customttable[i].biosdate, (char *)&pSiS->BIOS[0x2c],
4985	                strlen(SiS_customttable[i].biosdate)))))			      &&
4986	      ((!SiS_customttable[i].bioschksum) ||
4987	       (pSiS->SiS_Pr->UseROM &&
4988	       (SiS_customttable[i].bioschksum == chksum)))			      &&
4989	      (SiS_customttable[i].pcisubsysvendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo))      &&
4990	      (SiS_customttable[i].pcisubsyscard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) ) {
4991	     footprint = TRUE;
4992	     for(j=0; j<5; j++) {
4993	        if(SiS_customttable[i].biosFootprintAddr[j]) {
4994		   if(pSiS->SiS_Pr->UseROM) {
4995		      if(pSiS->BIOS[SiS_customttable[i].biosFootprintAddr[j]] !=
4996						SiS_customttable[i].biosFootprintData[j])
4997		         footprint = FALSE;
4998		   } else footprint = FALSE;
4999	        }
5000	     }
5001	     if(footprint) {
5002	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5003	           "Identified %s %s, special timing applies\n",
5004		   SiS_customttable[i].vendorName, SiS_customttable[i].cardName);
5005	        pSiS->SiS_Pr->SiS_CustomT = SiS_customttable[i].SpecialID;
5006	        break;
5007	     }
5008          }
5009          i++;
5010       } while(SiS_customttable[i].chipID);
5011    }
5012
5013    /* Handle ForceCRT1 option */
5014    if(pSiS->forceCRT1 != -1) {
5015       if(pSiS->forceCRT1) pSiS->CRT1off = 0;
5016       else                pSiS->CRT1off = 1;
5017    } else                 pSiS->CRT1off = -1;
5018
5019    /* Detect video bridge and sense TV/VGA2 */
5020    SISVGAPreInit(pScrn);
5021
5022    /* Detect CRT1 (via DDC1 and DDC2, hence via VGA port; regardless of LCDA) */
5023    SISCRT1PreInit(pScrn);
5024
5025    /* Detect LCD (connected via CRT2, regardless of LCDA) and LCD resolution */
5026    SISLCDPreInit(pScrn, FALSE);
5027
5028    /* LCDA only supported under these conditions: */
5029    if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5030       if(!SISDetermineLCDACap(pScrn)) {
5031	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5032		"Chipset/Video bridge does not support LCD-via-CRT1\n");
5033	  pSiS->ForceCRT1Type = CRT1_VGA;
5034       } else if(!(pSiS->VBFlags & CRT2_LCD)) {
5035	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5036		"No digital LCD panel found, LCD-via-CRT1 disabled\n");
5037	  pSiS->ForceCRT1Type = CRT1_VGA;
5038       }
5039    }
5040
5041    /* Setup SD flags */
5042    pSiS->SiS_SD_Flags |= SiS_SD_ADDLSUPFLAG;
5043
5044    pSiS->SiS_SD2_Flags |= SiS_SD2_MERGEDUCLOCK;
5045    pSiS->SiS_SD2_Flags |= SiS_SD2_USEVBFLAGS2;
5046    pSiS->SiS_SD2_Flags |= SiS_SD2_VBINVB2ONLY;
5047    pSiS->SiS_SD2_Flags |= SiS_SD2_HAVESD34;
5048    pSiS->SiS_SD2_Flags |= SiS_SD2_NEWGAMMABRICON;
5049
5050    pSiS->SiS_SD3_Flags |= SiS_SD3_MFBALLOWOFFCL;
5051
5052    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5053       pSiS->SiS_SD2_Flags |= SiS_SD2_VIDEOBRIDGE;
5054       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5055	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_SISBRIDGE     |
5056				   SiS_SD2_SUPPORTGAMMA2 );
5057	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5058	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDLVDS    |
5059				      SiS_SD2_SUPPORTLCD );
5060	  } else if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
5061	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
5062		pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDTMDS    |
5063					 SiS_SD2_SUPPORTLCD );
5064	     } else if(pSiS->VBFlags & CRT2_LCD) {
5065		pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5066				         SiS_SD2_SUPPORTLCD );
5067	     }
5068	  }
5069       } else if(pSiS->VBFlags2 & VB2_LVDS) {
5070	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5071				   SiS_SD2_SUPPORTLCD );
5072       }
5073
5074       if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5075	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTV;
5076	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5077	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_SUPPORTTVTYPE |
5078				      SiS_SD2_SUPPORTTVSIZE );
5079	     if(!(pSiS->VBFlags2 & VB2_301)) {
5080		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVSAT;
5081	     } else {
5082		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVEDGE;
5083	     }
5084	  }
5085       }
5086    }
5087
5088#ifdef ENABLE_YPBPR
5089    if((pSiS->VGAEngine == SIS_315_VGA) &&
5090       (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
5091       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPR;
5092       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625I;
5093       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625P;
5094       if(pSiS->VBFlags2 & VB2_SISYPBPRARBRIDGE) {
5095          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5096       }
5097    }
5098    if(pSiS->VBFlags2 & VB2_SISHIVISIONBRIDGE) {
5099       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTHIVISION;
5100    }
5101#endif
5102
5103    if((pSiS->VGAEngine != SIS_300_VGA) || (!(pSiS->VBFlags2 & VB2_TRUMPION))) {
5104       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSCALE;
5105       if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
5106          (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5107          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTCENTER;
5108       }
5109    }
5110
5111#ifdef SISDUALHEAD
5112    if(!pSiS->DualHeadMode) {
5113       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTREDETECT;
5114    }
5115#endif
5116
5117#ifndef SISCHECKOSSSE
5118    pSiS->SiS_SD2_Flags |= SiS_SD2_NEEDUSESSE;
5119#endif
5120
5121#ifdef TWDEBUG	/* FOR TESTING */
5122    pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5123    xf86DrvMsg(0, X_INFO, "TEST: Support Aspect Ratio\n");
5124#endif
5125
5126    /* Detect CRT2-TV and PAL/NTSC mode */
5127    SISTVPreInit(pScrn, FALSE);
5128
5129    /* Detect CRT2-VGA */
5130    SISCRT2PreInit(pScrn, FALSE);
5131
5132    /* Backup detected CRT2 devices */
5133    SISSaveDetectedDevices(pScrn);
5134
5135    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
5136       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_YPBPR)) {
5137	  pSiS->ForceTVType = -1;
5138	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "YPbPr TV output not supported\n");
5139       }
5140    }
5141
5142    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION)) {
5143       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_HIVISION)) {
5144	  pSiS->ForceTVType = -1;
5145	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HiVision TV output not supported\n");
5146       }
5147    }
5148
5149    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5150       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x))) {
5151       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5152    }
5153    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5154       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_700x))) {
5155       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTVPOS;
5156    }
5157    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5158       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTSCART | SiS_SD_SUPPORTVGA2);
5159    }
5160    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5161       pSiS->SiS_SD_Flags  |= SiS_SD_SUPPORTOVERSCAN;
5162       pSiS->SiS_SD2_Flags |= SiS_SD2_CHRONTEL;
5163       if(pSiS->ChrontelType == CHRONTEL_700x) {
5164	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSOVER;
5165       }
5166    }
5167
5168    /* Determine if chipset LCDA-capable */
5169    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
5170    if(SISDetermineLCDACap(pScrn)) {
5171       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
5172    }
5173
5174    /* Default to LCDA if LCD detected and
5175     * - TV detected (hence default to LCDA+TV), or
5176     * - in single head mode, on LCD panels with xres > 1600
5177     *   (Don't do this in MergedFB or DHM; LCDA and CRT1/VGA
5178     *   are mutually exclusive; if no TV is detected, the
5179     *   code below will default to VGA+LCD, so LCD is driven
5180     *   via CRT2.)
5181     *   (TODO: This might need some modification for the
5182     *   307 bridges, if these are capable of driving
5183     *   LCDs > 1600 via channel B)
5184     */
5185    if((pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) &&
5186       (pSiS->VBFlags & CRT2_LCD) &&
5187       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
5188       if((!pSiS->CRT1TypeForced) && (pSiS->ForceCRT2Type == CRT2_DEFAULT)) {
5189	  if(pSiS->VBFlags & CRT2_TV) {
5190	     /* If both LCD and TV present, default to LCDA+TV */
5191	     pSiS->ForceCRT1Type = CRT1_LCDA;
5192	     pSiS->ForceCRT2Type = CRT2_TV;
5193	  } else if(pSiS->LCDwidth > 1600) {
5194	     /* If LCD is > 1600, default to LCDA if we don't need CRT1/VGA for other head */
5195	     Bool NeedCRT1VGA = FALSE;
5196#ifdef SISDUALHEAD
5197	     if(pSiS->DualHeadMode) NeedCRT1VGA = TRUE;
5198#endif
5199#ifdef SISMERGED
5200	     if(pSiS->MergedFB &&
5201		(!pSiS->MergedFBAuto || pSiS->CRT1Detected)) NeedCRT1VGA = TRUE;
5202#endif
5203	     if(!NeedCRT1VGA) {
5204		pSiS->ForceCRT1Type = CRT1_LCDA;
5205	     }
5206	  }
5207       }
5208    }
5209
5210    /* Set up pseudo-panel if LCDA forced on TMDS bridges */
5211    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) {
5212       if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5213          if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
5214	     if(!(pSiS->VBLCDFlags)) {
5215		SiSSetupPseudoPanel(pScrn);
5216		pSiS->detectedCRT2Devices |= CRT2_LCD;
5217	     }
5218	  } else if(!(pSiS->VBLCDFlags)) {
5219	     pSiS->ForceCRT1Type = CRT1_VGA;
5220	  }
5221       }
5222    } else {
5223       pSiS->ForceCRT1Type = CRT1_VGA;
5224    }
5225
5226    pSiS->VBFlags |= pSiS->ForceCRT1Type;
5227
5228#ifdef TWDEBUG
5229    xf86DrvMsg(0, X_INFO, "SDFlags %lx\n", pSiS->SiS_SD_Flags);
5230#endif
5231
5232    /* Eventually overrule detected CRT2 type
5233     * If no type forced, use the detected devices in the order TV->LCD->VGA2
5234     * Since the Chrontel 7005 sometimes delivers wrong detection results,
5235     * we use a different order on such machines (LCD->TV)
5236     */
5237    if(pSiS->ForceCRT2Type == CRT2_DEFAULT) {
5238       if((pSiS->VBFlags & CRT2_TV) && (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VGAEngine == SIS_300_VGA))))
5239	  pSiS->ForceCRT2Type = CRT2_TV;
5240       else if((pSiS->VBFlags & CRT2_LCD) && (pSiS->ForceCRT1Type == CRT1_VGA))
5241	  pSiS->ForceCRT2Type = CRT2_LCD;
5242       else if(pSiS->VBFlags & CRT2_TV)
5243	  pSiS->ForceCRT2Type = CRT2_TV;
5244       else if((pSiS->VBFlags & CRT2_VGA) && (pSiS->ForceCRT1Type == CRT1_VGA))
5245	  pSiS->ForceCRT2Type = CRT2_VGA;
5246    }
5247
5248    switch(pSiS->ForceCRT2Type) {
5249       case CRT2_TV:
5250	  pSiS->VBFlags &= ~(CRT2_LCD | CRT2_VGA);
5251	  if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5252	     pSiS->VBFlags |= CRT2_TV;
5253	  } else {
5254	     pSiS->VBFlags &= ~(CRT2_TV);
5255	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5256		"Hardware does not support TV output\n");
5257	  }
5258	  break;
5259       case CRT2_LCD:
5260	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_VGA);
5261	  if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) {
5262	     pSiS->VBFlags |= CRT2_LCD;
5263	  } else if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5264	     SiSSetupPseudoPanel(pScrn);
5265	     pSiS->detectedCRT2Devices |= CRT2_LCD;
5266	  } else {
5267	     pSiS->VBFlags &= ~(CRT2_LCD);
5268	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5269		"Can't force CRT2 to LCD, no LCD detected\n");
5270	  }
5271	  break;
5272       case CRT2_VGA:
5273	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD);
5274	  if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5275	     pSiS->VBFlags |= CRT2_VGA;
5276	  } else {
5277	     pSiS->VBFlags &= ~(CRT2_VGA);
5278	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5279		 "Hardware does not support secondary VGA\n");
5280	  }
5281	  break;
5282       default:
5283	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
5284    }
5285
5286    /* Setup gamma (the cmap layer needs this to be initialised) */
5287    /* (Do this after evaluating options) */
5288    {
5289       Gamma zeros = {0.0, 0.0, 0.0};
5290       xf86SetGamma(pScrn, zeros);
5291    }
5292
5293#ifdef SISDUALHEAD
5294    if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
5295#endif
5296       xf86DrvMsg(pScrn->scrnIndex, pSiS->CRT1gammaGiven ? X_CONFIG : X_INFO,
5297	     "%samma correction is %s\n",
5298	     (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G",
5299	     pSiS->CRT1gamma ? "enabled" : "disabled");
5300
5301       if((pSiS->VGAEngine == SIS_315_VGA)	&&
5302          (!(pSiS->NoXvideo))			&&
5303	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5304	  xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5305		"Separate Xv gamma correction %sis %s\n",
5306		(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "for CRT1 " : "",
5307		pSiS->XvGamma ? "enabled" : "disabled");
5308	  if(pSiS->XvGamma) {
5309	     xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5310		"Xv gamma correction: %.3f %.3f %.3f\n",
5311		(float)((float)pSiS->XvGammaRed / 1000),
5312		(float)((float)pSiS->XvGammaGreen / 1000),
5313		(float)((float)pSiS->XvGammaBlue / 1000));
5314	     if(!pSiS->CRT1gamma) {
5315		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5316		   "Xv gamma correction requires %samma correction enabled\n",
5317		   (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G");
5318	     }
5319	  }
5320       }
5321#ifdef SISDUALHEAD
5322    }
5323#endif
5324
5325#ifdef SISDUALHEAD
5326    if(pSiS->DualHeadMode) pSiS->CRT2SepGamma = FALSE;
5327#endif
5328
5329#ifdef SISDUALHEAD
5330    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
5331#endif
5332    {
5333       Bool isDH = FALSE;
5334       if(pSiS->CRT2gamma) {
5335          if( ((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) ||
5336              (!(pSiS->VBFlags2 & VB2_SISBRIDGE)) ) {
5337	     if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5338	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5339			"CRT2 gamma correction not supported by hardware\n");
5340	     }
5341	     pSiS->CRT2gamma = pSiS->CRT2SepGamma = FALSE;
5342          } else if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) {
5343	     isDH = TRUE;
5344	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5345			"CRT2 gamma correction not supported for LCD\n");
5346	     /* But leave it on, will be caught in LoadPalette */
5347          }
5348       }
5349       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5350	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT2 gamma correction is %s%s%s\n",
5351		pSiS->CRT2gamma ? "enabled" : "disabled",
5352		isDH ? " (for TV and VGA2) " : "",
5353		pSiS->CRT2SepGamma ? " (separate from CRT1)" : "");
5354       }
5355    }
5356
5357    /* Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART, HIVISION, YPBPR) */
5358    if(pSiS->VBFlags2 & VB2_SISTVBRIDGE) {
5359       if(pSiS->ForceTVType != -1) {
5360	  pSiS->VBFlags &= ~(TV_INTERFACE);
5361	  if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) {
5362	     pSiS->VBFlags &= ~(TV_CHSCART | TV_CHYPBPR525I);
5363	  }
5364	  pSiS->VBFlags |= pSiS->ForceTVType;
5365	  if(pSiS->VBFlags & TV_YPBPR) {
5366	     pSiS->VBFlags &= ~(TV_STANDARD);
5367	     pSiS->VBFlags &= ~(TV_YPBPRAR);
5368	     pSiS->VBFlags |= pSiS->ForceYPbPrType;
5369	     pSiS->VBFlags |= pSiS->ForceYPbPrAR;
5370	  }
5371       }
5372    }
5373
5374    /* Handle ForceCRT1 option (part 2) */
5375    pSiS->CRT1changed = FALSE;
5376    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5377       usScratchCR17 = pSiS->oldCR17;
5378       usScratchCR63 = pSiS->oldCR63;
5379       usScratchSR1F = pSiS->oldSR1F;
5380       usScratchCR32 = pSiS->postVBCR32;
5381       if(pSiS->VESA != 1) {
5382          /* Copy forceCRT1 option to CRT1off if option is given */
5383#ifdef SISDUALHEAD
5384          /* In DHM, handle this option only for master head, not the slave */
5385          if( (pSiS->forceCRT1 != -1) &&
5386	       (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) {
5387#else
5388          if(pSiS->forceCRT1 != -1) {
5389#endif
5390	     xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5391		 "CRT1 detection overruled by ForceCRT1 option\n");
5392	     if(pSiS->forceCRT1) {
5393		 pSiS->CRT1off = 0;
5394		 if(pSiS->VGAEngine == SIS_300_VGA) {
5395		    if(!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE;
5396		 } else {
5397		    if(usScratchCR63 & 0x40) pSiS->CRT1changed = TRUE;
5398		 }
5399		 usScratchCR17 |= 0x80;
5400		 usScratchCR32 |= 0x20;
5401		 usScratchCR63 &= ~0x40;
5402		 usScratchSR1F &= ~0xc0;
5403	     } else {
5404		 if( ! ( (pScrn->bitsPerPixel == 8) &&
5405		         ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5406		           ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5407		    pSiS->CRT1off = 1;
5408		    if(pSiS->VGAEngine == SIS_300_VGA) {
5409		       if(usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE;
5410		    } else {
5411		       if(!(usScratchCR63 & 0x40)) pSiS->CRT1changed = TRUE;
5412		    }
5413		    usScratchCR32 &= ~0x20;
5414		    /* We must not actually switch off CRT1 before we changed the mode! */
5415		 }
5416	     }
5417	     /* Here we can write to CR17 even on 315 series as we only ENABLE
5418	      * the bit here
5419	      */
5420	     outSISIDXREG(SISCR, 0x17, usScratchCR17);
5421	     if(pSiS->VGAEngine == SIS_315_VGA) {
5422		outSISIDXREG(SISCR, pSiS->myCR63, usScratchCR63);
5423	     }
5424	     outSISIDXREG(SISCR, 0x32, usScratchCR32);
5425	     if(pSiS->CRT1changed) {
5426		outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
5427		usleep(10000);
5428		outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
5429		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5430			"CRT1 status changed by ForceCRT1 option\n");
5431	     }
5432	     outSISIDXREG(SISSR, 0x1f, usScratchSR1F);
5433          }
5434       }
5435       /* Store the new VB connection register contents for later mode changes */
5436       pSiS->newCR32 = usScratchCR32;
5437    }
5438
5439    /* Check if CRT1 used (or needed; this eg. if no CRT2 detected) */
5440    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5441
5442        /* No CRT2 output? Then we NEED CRT1!
5443	 * We also need CRT1 if depth = 8 and bridge=LVDS|301B-DH
5444	 */
5445	if( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) ||
5446	    ( (pScrn->bitsPerPixel == 8) &&
5447	      ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5448	        ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5449	    pSiS->CRT1off = 0;
5450	}
5451	/* No CRT2 output? Then we can't use Xv on CRT2 */
5452	if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) {
5453	    pSiS->XvOnCRT2 = FALSE;
5454	}
5455
5456    } else { /* no video bridge? */
5457	/* Then we NEED CRT1... */
5458	pSiS->CRT1off = 0;
5459	/* ... and can't use CRT2 for Xv output */
5460	pSiS->XvOnCRT2 = FALSE;
5461    }
5462
5463    /* LCDA? Then we don't switch off CRT1 */
5464    if(pSiS->VBFlags & CRT1_LCDA) pSiS->CRT1off = 0;
5465
5466    /* Handle TVStandard option */
5467    if((pSiS->NonDefaultPAL != -1) || (pSiS->NonDefaultNTSC != -1)) {
5468       if( (!(pSiS->VBFlags2 & VB2_SISTVBRIDGE)) &&
5469	   (!((pSiS->VBFlags2 & VB2_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) {
5470	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5471	   	"PALM, PALN and NTSCJ not supported on this hardware\n");
5472	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5473	  pSiS->VBFlags &= ~(TV_PALN | TV_PALM | TV_NTSCJ);
5474	  pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5475       }
5476    }
5477    if(pSiS->OptTVStand != -1) {
5478       if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5479	  if( (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART | TV_CHYPBPR525I)))) &&
5480	      (!(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR))) ) {
5481	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5482	     if(pSiS->OptTVStand) {
5483	        pSiS->VBFlags |= TV_PAL;
5484	        if(pSiS->NonDefaultPAL == 1)  pSiS->VBFlags |= TV_PALM;
5485	        else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN;
5486	     } else {
5487	        pSiS->VBFlags |= TV_NTSC;
5488		if(pSiS->NonDefaultNTSC == 1) pSiS->VBFlags |= TV_NTSCJ;
5489	     }
5490	  } else {
5491	     pSiS->OptTVStand = pSiS->NonDefaultPAL = -1;
5492	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5493	    	 "Option TVStandard ignored for YPbPr, HiVision and Chrontel-SCART\n");
5494	  }
5495       } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
5496	  pSiS->SiS6326Flags &= ~SIS6326_TVPAL;
5497	  if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL;
5498       }
5499    }
5500
5501    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5502       /* Default to PAL */
5503       if(pSiS->VBFlags & (TV_SVIDEO | TV_AVIDEO)) {
5504          if(!(pSiS->VBFlags & (TV_PAL | TV_NTSC))) {
5505	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5506	     pSiS->VBFlags |= TV_PAL;
5507	  }
5508       }
5509       /* SCART only supported for PAL */
5510       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & TV_SCART)) {
5511	  pSiS->VBFlags &= ~(TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5512	  pSiS->VBFlags |= TV_PAL;
5513	  pSiS->OptTVStand = 1;
5514	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5515       }
5516    }
5517
5518#ifdef SIS_CP
5519    SIS_CP_DRIVER_RECONFIGOPT
5520#endif
5521
5522    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
5523       if(pSiS->sis6326tvplug != -1) {
5524          pSiS->SiS6326Flags &= ~(SIS6326_TVSVIDEO | SIS6326_TVCVBS);
5525	  pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
5526	  if(pSiS->sis6326tvplug == 1) 	pSiS->SiS6326Flags |= SIS6326_TVCVBS;
5527	  else 				pSiS->SiS6326Flags |= SIS6326_TVSVIDEO;
5528	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5529	      "SiS6326 TV plug type detection overruled by %s\n",
5530	      (pSiS->SiS6326Flags & SIS6326_TVCVBS) ? "COMPOSITE" : "SVIDEO");
5531       }
5532    }
5533
5534    /* Do some checks */
5535    if(pSiS->OptTVOver != -1) {
5536       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5537	  pSiS->UseCHOverScan = pSiS->OptTVOver;
5538       } else {
5539	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5540	      "CHTVOverscan only supported on CHRONTEL 70xx\n");
5541	  pSiS->UseCHOverScan = -1;
5542       }
5543    } else pSiS->UseCHOverScan = -1;
5544
5545    if(pSiS->sistvedgeenhance != -1) {
5546       if(!(pSiS->VBFlags2 & VB2_301)) {
5547	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5548	      "SISTVEdgeEnhance only supported on SiS301\n");
5549	  pSiS->sistvedgeenhance = -1;
5550       }
5551    }
5552    if(pSiS->sistvsaturation != -1) {
5553       if(pSiS->VBFlags2 & VB2_301) {
5554	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5555	      "SISTVSaturation not supported on SiS301\n");
5556	  pSiS->sistvsaturation = -1;
5557       }
5558    }
5559
5560    /* Do some MergedFB mode initialisation */
5561#ifdef SISMERGED
5562    if(pSiS->MergedFB) {
5563       pSiS->CRT2pScrn = xalloc(sizeof(ScrnInfoRec));
5564       if(!pSiS->CRT2pScrn) {
5565          SISErrorLog(pScrn, "Failed to allocate memory for 2nd pScrn, %s\n", mergeddisstr);
5566	  pSiS->MergedFB = FALSE;
5567       } else {
5568          memcpy(pSiS->CRT2pScrn, pScrn, sizeof(ScrnInfoRec));
5569       }
5570    }
5571#endif
5572
5573    /* Determine CRT1<>CRT2 mode
5574     *     Note: When using VESA or if the bridge is in slavemode, display
5575     *           is ALWAYS in MIRROR_MODE!
5576     *           This requires extra checks in functions using this flag!
5577     *           (see sis_video.c for example)
5578     */
5579    if(pSiS->VBFlags & DISPTYPE_DISP2) {
5580        if(pSiS->CRT1off) {	/* CRT2 only ------------------------------- */
5581#ifdef SISDUALHEAD
5582	     if(pSiS->DualHeadMode) {
5583		SISErrorLog(pScrn,
5584		    "CRT1 not detected or forced off. Dual Head mode can't initialize.\n");
5585		if(pSiSEnt) pSiSEnt->DisableDual = TRUE;
5586		goto my_error_1;
5587	     }
5588#endif
5589#ifdef SISMERGED
5590	     if(pSiS->MergedFB) {
5591		if(pSiS->MergedFBAuto) {
5592		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt1, mergeddisstr);
5593		} else {
5594		   SISErrorLog(pScrn, mergednocrt1, mergeddisstr);
5595		}
5596		if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
5597		pSiS->CRT2pScrn = NULL;
5598		pSiS->MergedFB = FALSE;
5599	     }
5600#endif
5601	     pSiS->VBFlags |= VB_DISPMODE_SINGLE;
5602	     /* No CRT1? Then we use the video overlay on CRT2 */
5603	     pSiS->XvOnCRT2 = TRUE;
5604	} else			/* CRT1 and CRT2 - mirror or dual head ----- */
5605#ifdef SISDUALHEAD
5606	     if(pSiS->DualHeadMode) {
5607		pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1);
5608		if(pSiS->VESA != -1) {
5609		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5610			"VESA option not used in Dual Head mode. VESA disabled.\n");
5611		}
5612		if(pSiSEnt) pSiSEnt->DisableDual = FALSE;
5613		pSiS->VESA = 0;
5614	     } else
5615#endif
5616#ifdef SISMERGED
5617		    if(pSiS->MergedFB) {
5618		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5619		 if(pSiS->VESA != -1) {
5620		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5621			"VESA option not used in MergedFB mode. VESA disabled.\n");
5622		 }
5623		 pSiS->VESA = 0;
5624	     } else
5625#endif
5626		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5627    } else {			/* CRT1 only ------------------------------- */
5628#ifdef SISDUALHEAD
5629	     if(pSiS->DualHeadMode) {
5630		SISErrorLog(pScrn,
5631		   "No CRT2 output selected or no bridge detected. "
5632		   "Dual Head mode can't initialize.\n");
5633		goto my_error_1;
5634	     }
5635#endif
5636#ifdef SISMERGED
5637	     if(pSiS->MergedFB) {
5638		if(pSiS->MergedFBAuto) {
5639		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt2, mergeddisstr);
5640		} else {
5641		   SISErrorLog(pScrn, mergednocrt2, mergeddisstr);
5642		}
5643		if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
5644		pSiS->CRT2pScrn = NULL;
5645		pSiS->MergedFB = FALSE;
5646	     }
5647#endif
5648             pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1);
5649    }
5650
5651    if((pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA)) {
5652       if((!pSiS->NoXvideo)		&&
5653          (!pSiS->hasTwoOverlays)	&&
5654	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5655	  xf86DrvMsg(pScrn->scrnIndex, from,
5656	      "Using Xv overlay by default on CRT%d\n",
5657	      pSiS->XvOnCRT2 ? 2 : 1);
5658       }
5659    }
5660
5661    /* Init ptrs for Save/Restore functions and calc MaxClock */
5662    SISDACPreInit(pScrn);
5663
5664    /* ********** end of VBFlags setup ********** */
5665
5666    /* VBFlags are initialized now. Back them up for SlaveMode modes. */
5667    pSiS->VBFlags_backup = pSiS->VBFlags;
5668
5669    /* Backup CR32,36,37 (in order to write them back after a VT switch) */
5670    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5671       inSISIDXREG(SISCR,0x32,pSiS->myCR32);
5672       inSISIDXREG(SISCR,0x36,pSiS->myCR36);
5673       inSISIDXREG(SISCR,0x37,pSiS->myCR37);
5674    }
5675
5676    /* Find out about paneldelaycompensation and evaluate option */
5677#ifdef SISDUALHEAD
5678    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
5679#endif
5680       if(pSiS->VGAEngine == SIS_300_VGA) {
5681
5682          if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
5683
5684	     /* Save the current PDC if the panel is used at the moment.
5685	      * This seems by far the safest way to find out about it.
5686	      * If the system is using an old version of sisfb, we can't
5687	      * trust the pdc register value. If sisfb saved the pdc for
5688	      * us, use it.
5689	      */
5690	     if(pSiS->sisfbpdc != 0xff) {
5691	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5692	     } else {
5693	        if(!(pSiS->donttrustpdc)) {
5694	           UChar tmp;
5695	           inSISIDXREG(SISCR, 0x30, tmp);
5696	           if(tmp & 0x20) {
5697	              inSISIDXREG(SISPART1, 0x13, pSiS->SiS_Pr->PDC);
5698                   } else {
5699	             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5700		          "Unable to detect LCD PanelDelayCompensation, LCD is not active\n");
5701	           }
5702	        } else {
5703	           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5704		        "Unable to detect LCD PanelDelayCompensation, please update sisfb\n");
5705	        }
5706	     }
5707	     if(pSiS->SiS_Pr->PDC != -1) {
5708	        pSiS->SiS_Pr->PDC &= 0x3c;
5709	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5710		     "Detected LCD PanelDelayCompensation 0x%02x\n",
5711		     pSiS->SiS_Pr->PDC);
5712	     }
5713
5714	     /* If we haven't been able to find out, use our other methods */
5715	     if(pSiS->SiS_Pr->PDC == -1) {
5716		int i=0;
5717		do {
5718		   if(mypdctable[i].subsysVendor == PCI_SUB_VENDOR_ID(pSiS->PciInfo) &&
5719		      mypdctable[i].subsysCard == PCI_SUB_DEVICE_ID(pSiS->PciInfo)) {
5720			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5721			    "PCI card/vendor identified for non-default PanelDelayCompensation\n");
5722			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5723			     "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: 0x%02x\n",
5724			     mypdctable[i].vendorName, mypdctable[i].cardName,
5725			     PCI_SUB_DEVICE_ID(pSiS->PciInfo), mypdctable[i].pdc);
5726			 if(pSiS->PDC == -1) {
5727			    pSiS->PDC = mypdctable[i].pdc;
5728			 } else {
5729			    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5730				"PanelDelayCompensation overruled by option\n");
5731			 }
5732			 break;
5733		   }
5734		   i++;
5735		} while(mypdctable[i].subsysVendor != 0);
5736	     }
5737
5738	     if(pSiS->PDC != -1) {
5739		if(pSiS->BIOS) {
5740		   if(pSiS->VBFlags2 & VB2_LVDS) {
5741		      if(pSiS->BIOS[0x220] & 0x80) {
5742			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5743			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5744			     pSiS->BIOS[0x220] & 0x3c);
5745			 pSiS->BIOS[0x220] &= 0x7f;
5746		      }
5747		   }
5748		   if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
5749		      if(pSiS->BIOS[0x220] & 0x80) {
5750			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5751			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5752			       (  (pSiS->VBLCDFlags & VB_LCD_1280x1024) ?
5753			                 pSiS->BIOS[0x223] : pSiS->BIOS[0x224]  ) & 0x3c);
5754			 pSiS->BIOS[0x220] &= 0x7f;
5755		      }
5756		   }
5757		}
5758		pSiS->SiS_Pr->PDC = (pSiS->PDC & 0x3c);
5759		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5760		      "Using LCD Panel Delay Compensation 0x%02x\n", pSiS->SiS_Pr->PDC);
5761	     }
5762	  }
5763
5764       }  /* SIS_300_VGA */
5765
5766       if(pSiS->VGAEngine == SIS_315_VGA) {
5767
5768	  UChar tmp, tmp2;
5769	  inSISIDXREG(SISCR, 0x30, tmp);
5770
5771	  /* Save the current PDC if the panel is used at the moment. */
5772	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5773
5774	     if(pSiS->sisfbpdc != 0xff) {
5775	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5776	     }
5777	     if(pSiS->sisfbpdca != 0xff) {
5778	        pSiS->SiS_Pr->PDCA = pSiS->sisfbpdca;
5779	     }
5780
5781	     if(!pSiS->donttrustpdc) {
5782	        if((pSiS->sisfbpdc == 0xff) && (pSiS->sisfbpdca == 0xff)) {
5783		   CARD16 tempa, tempb;
5784		   inSISIDXREG(SISPART1,0x2d,tmp2);
5785		   tempa = (tmp2 & 0xf0) >> 3;
5786		   tempb = (tmp2 & 0x0f) << 1;
5787		   inSISIDXREG(SISPART1,0x20,tmp2);
5788		   tempa |= ((tmp2 & 0x40) >> 6);
5789		   inSISIDXREG(SISPART1,0x35,tmp2);
5790		   tempb |= ((tmp2 & 0x80) >> 7);
5791		   inSISIDXREG(SISPART1,0x13,tmp2);
5792		   if(!pSiS->ROM661New) {
5793		      if((tmp2 & 0x04) || (tmp & 0x20)) {
5794		         pSiS->SiS_Pr->PDCA = tempa;
5795		         pSiS->SiS_Pr->PDC  = tempb;
5796		      } else {
5797			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5798			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5799		      }
5800		   } else {
5801		      if(tmp2 & 0x04) {
5802		         pSiS->SiS_Pr->PDCA = tempa;
5803		      } else if(tmp & 0x20) {
5804		         pSiS->SiS_Pr->PDC  = tempb;
5805		      } else {
5806			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5807			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5808		      }
5809		   }
5810		}
5811	     } else {
5812		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5813		    "Unable to detect PanelDelayCompensation, please update sisfb\n");
5814	     }
5815	     if(pSiS->SiS_Pr->PDC != -1) {
5816		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5817		     "Detected LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5818		     pSiS->SiS_Pr->PDC);
5819	     }
5820	     if(pSiS->SiS_Pr->PDCA != -1) {
5821		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5822		     "Detected LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5823		     pSiS->SiS_Pr->PDCA);
5824	     }
5825	  }
5826
5827	  /* Let user override (for all bridges) */
5828	  if(pSiS->VBFlags2 & VB2_30xBLV) {
5829	     if(pSiS->PDC != -1) {
5830	        pSiS->SiS_Pr->PDC = pSiS->PDC & 0x1f;
5831		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5832		     "Using LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5833		     pSiS->SiS_Pr->PDC);
5834	     }
5835	     if(pSiS->PDCA != -1) {
5836		pSiS->SiS_Pr->PDCA = pSiS->PDCA & 0x1f;
5837		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5838		     "Using LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5839		     pSiS->SiS_Pr->PDCA);
5840	     }
5841          }
5842
5843 	  /* Read the current EMI (if not overruled) */
5844	  if(pSiS->VBFlags2 & VB2_SISEMIBRIDGE) {
5845	     MessageType from = X_PROBED;
5846	     if(pSiS->EMI != -1) {
5847		pSiS->SiS_Pr->EMI_30 = (pSiS->EMI >> 24) & 0x60;
5848		pSiS->SiS_Pr->EMI_31 = (pSiS->EMI >> 16) & 0xff;
5849		pSiS->SiS_Pr->EMI_32 = (pSiS->EMI >> 8)  & 0xff;
5850		pSiS->SiS_Pr->EMI_33 = pSiS->EMI & 0xff;
5851		pSiS->SiS_Pr->HaveEMI = pSiS->SiS_Pr->HaveEMILCD = TRUE;
5852		pSiS->SiS_Pr->OverruleEMI = TRUE;
5853		from = X_CONFIG;
5854	     } else if((pSiS->sisfbfound) && (pSiS->sisfb_haveemi)) {
5855		pSiS->SiS_Pr->EMI_30 = pSiS->sisfb_emi30;
5856		pSiS->SiS_Pr->EMI_31 = pSiS->sisfb_emi31;
5857		pSiS->SiS_Pr->EMI_32 = pSiS->sisfb_emi32;
5858		pSiS->SiS_Pr->EMI_33 = pSiS->sisfb_emi33;
5859		pSiS->SiS_Pr->HaveEMI = TRUE;
5860		if(pSiS->sisfb_haveemilcd) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5861		pSiS->SiS_Pr->OverruleEMI = FALSE;
5862	     } else {
5863		inSISIDXREG(SISPART4, 0x30, pSiS->SiS_Pr->EMI_30);
5864		inSISIDXREG(SISPART4, 0x31, pSiS->SiS_Pr->EMI_31);
5865		inSISIDXREG(SISPART4, 0x32, pSiS->SiS_Pr->EMI_32);
5866		inSISIDXREG(SISPART4, 0x33, pSiS->SiS_Pr->EMI_33);
5867		pSiS->SiS_Pr->HaveEMI = TRUE;
5868		if(tmp & 0x20) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5869		pSiS->SiS_Pr->OverruleEMI = FALSE;
5870	     }
5871	     xf86DrvMsg(pScrn->scrnIndex, from,
5872		   "302LV/302ELV: Using EMI 0x%02x%02x%02x%02x%s\n",
5873		   pSiS->SiS_Pr->EMI_30,pSiS->SiS_Pr->EMI_31,
5874		   pSiS->SiS_Pr->EMI_32,pSiS->SiS_Pr->EMI_33,
5875		   pSiS->SiS_Pr->HaveEMILCD ? " (LCD)" : "");
5876	  }
5877
5878       } /* SIS_315_VGA */
5879#ifdef SISDUALHEAD
5880    }
5881#endif
5882
5883
5884    /* In dual head mode, both heads (currently) share the maxxfbmem equally.
5885     * If memory sharing is done differently, the following has to be changed;
5886     * the other modules (eg. accel and Xv) use dhmOffset for hardware
5887     * pointer settings relative to VideoRAM start and won't need to be changed.
5888     *
5889     * Addendum: dhmoffset is also used for skipping the UMA area on SiS76x.
5890     */
5891
5892    pSiS->dhmOffset = pSiS->FbBaseOffset;
5893    pSiS->FbAddress += pSiS->dhmOffset;
5894
5895#ifdef SISDUALHEAD
5896    if(pSiS->DualHeadMode) {
5897       pSiS->FbAddress = pSiS->realFbAddress;
5898       if(!pSiS->SecondHead) {
5899	  /* ===== First head (always CRT2) ===== */
5900	  /* We use only half of the memory available */
5901	  pSiS->maxxfbmem /= 2;
5902	  /* dhmOffset is 0 (or LFB-base for SiS76x UMA skipping) */
5903	  pSiS->FbAddress += pSiS->dhmOffset;
5904	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5905	      "%dKB video RAM at 0x%lx available for master head (CRT2)\n",
5906	      pSiS->maxxfbmem/1024, pSiS->FbAddress);
5907       } else {
5908	  /* ===== Second head (always CRT1) ===== */
5909	  /* We use only half of the memory available */
5910	  pSiS->maxxfbmem /= 2;
5911	  /* Initialize dhmOffset */
5912	  pSiS->dhmOffset += pSiS->maxxfbmem;
5913	  /* Adapt FBAddress */
5914	  pSiS->FbAddress += pSiS->dhmOffset;
5915	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5916	     "%dKB video RAM at 0x%lx available for slave head (CRT1)\n",
5917	     pSiS->maxxfbmem/1024,  pSiS->FbAddress);
5918       }
5919    }
5920#endif
5921
5922    /* Note: Do not use availMem for anything from now. Use
5923     * maxxfbmem instead. (availMem does not take dual head
5924     * mode into account.)
5925     */
5926
5927    if(pSiS->FbBaseOffset) {
5928       /* Doubt that the DRM memory manager can deal
5929        * with a heap start of 0...
5930	*/
5931       pSiS->DRIheapstart = 16;
5932       pSiS->DRIheapend = pSiS->FbBaseOffset;
5933    } else {
5934       pSiS->DRIheapstart = pSiS->maxxfbmem;
5935       pSiS->DRIheapend = pSiS->availMem;
5936    }
5937#ifdef SISDUALHEAD
5938    if(pSiS->DualHeadMode) {
5939       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5940    } else
5941#endif
5942           if(pSiS->DRIheapstart >= pSiS->DRIheapend) {
5943#if 0  /* For future use */
5944       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5945	  "No memory for DRI heap. Please set the option \"MaxXFBMem\" to\n"
5946	  "\tlimit the memory X should use and leave the rest to DRI\n");
5947#endif
5948       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
5949    }
5950
5951    /* Now for something completely different: DDC.
5952     * For 300 and 315/330/340 series, we provide our
5953     * own functions (in order to probe CRT2 as well)
5954     * If these fail, use the VBE.
5955     * All other chipsets will use VBE. No need to re-invent
5956     * the wheel there.
5957     */
5958
5959    pSiS->pVbe = NULL;
5960    didddc2 = FALSE;
5961
5962    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5963       if(xf86LoadSubModule(pScrn, "ddc")) {
5964	  int crtnum = 0;
5965	  if((pMonitor = SiSDoPrivateDDC(pScrn, &crtnum))) {
5966	     didddc2 = TRUE;
5967	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, crtnum);
5968	     xf86PrintEDID(pMonitor);
5969	     xf86SetDDCproperties(pScrn, pMonitor);
5970	     pScrn->monitor->DDC = pMonitor;
5971	     /* Now try to find out aspect ratio */
5972	     SiSFindAspect(pScrn, pMonitor, crtnum);
5973	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, crtnum);
5974	  }
5975       }
5976    }
5977
5978#ifdef SISDUALHEAD
5979    /* In dual head mode, probe DDC using VBE only for CRT1 (second head) */
5980    if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) {
5981       didddc2 = TRUE;
5982    }
5983#endif
5984
5985    if(!didddc2) {
5986       /* If CRT1 is off or LCDA, skip DDC via VBE */
5987       if((pSiS->CRT1off) || (pSiS->VBFlags & CRT1_LCDA)) {
5988          didddc2 = TRUE;
5989       }
5990    }
5991
5992    /* Now (re-)load and initialize the DDC module */
5993    if(!didddc2) {
5994
5995       if(xf86LoadSubModule(pScrn, "ddc")) {
5996
5997	  /* Now load and initialize VBE module. */
5998	  SiS_LoadInitVBE(pScrn);
5999
6000	  if(pSiS->pVbe) {
6001	     if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) {
6002		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6003		      "VBE CRT1 DDC monitor info:\n");
6004		xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor));
6005		pScrn->monitor->DDC = pMonitor;
6006		/* Now try to find out aspect ratio */
6007		SiSFindAspect(pScrn, pMonitor, 1);
6008		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6009		      "End of VBE CRT1 DDC monitor info\n");
6010	     }
6011	  } else {
6012	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6013		 "Failed to read DDC data\n");
6014	  }
6015       }
6016    }
6017
6018#ifdef SISMERGED
6019    if(pSiS->MergedFB) {
6020       pSiS->CRT2pScrn->monitor = xalloc(sizeof(MonRec));
6021       if(pSiS->CRT2pScrn->monitor) {
6022	  DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
6023	  memcpy(pSiS->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec));
6024	  pSiS->CRT2pScrn->monitor->DDC = NULL;
6025	  pSiS->CRT2pScrn->monitor->Modes = NULL;
6026	  pSiS->CRT2pScrn->monitor->id = (char *)crt2monname;
6027	  tempm = pScrn->monitor->Modes;
6028	  while(tempm) {
6029	     if(!(newm = xalloc(sizeof(DisplayModeRec)))) break;
6030	     memcpy(newm, tempm, sizeof(DisplayModeRec));
6031	     if(!(newm->name = xalloc(strlen(tempm->name) + 1))) {
6032	        xfree(newm);
6033		break;
6034	     }
6035	     strcpy(newm->name, tempm->name);
6036	     if(!pSiS->CRT2pScrn->monitor->Modes) pSiS->CRT2pScrn->monitor->Modes = newm;
6037	     if(currentm) {
6038	        currentm->next = newm;
6039		newm->prev = currentm;
6040	     }
6041	     currentm = newm;
6042	     tempm = tempm->next;
6043	  }
6044	  if(pSiS->CRT2HSync) {
6045	     pSiS->CRT2pScrn->monitor->nHsync =
6046		SiSStrToRanges(pSiS->CRT2pScrn->monitor->hsync, pSiS->CRT2HSync, MAX_HSYNC);
6047	  }
6048	  if(pSiS->CRT2VRefresh) {
6049	     pSiS->CRT2pScrn->monitor->nVrefresh =
6050		SiSStrToRanges(pSiS->CRT2pScrn->monitor->vrefresh, pSiS->CRT2VRefresh, MAX_VREFRESH);
6051	  }
6052	  if((pMonitor = SiSInternalDDC(pSiS->CRT2pScrn, 1))) {
6053	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, 2);
6054	     xf86PrintEDID(pMonitor);
6055	     xf86SetDDCproperties(pSiS->CRT2pScrn, pMonitor);
6056	     pSiS->CRT2pScrn->monitor->DDC = pMonitor;
6057	     /* Now try to find out aspect ratio */
6058	     SiSFindAspect(pScrn, pMonitor, 2);
6059	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, 2);
6060	     /* use DDC data if no ranges in config file */
6061	     if(!pSiS->CRT2HSync) {
6062	        pSiS->CRT2pScrn->monitor->nHsync = 0;
6063	     }
6064	     if(!pSiS->CRT2VRefresh) {
6065	        pSiS->CRT2pScrn->monitor->nVrefresh = 0;
6066	     }
6067	  } else {
6068	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6069		"Failed to read DDC data for CRT2\n");
6070	  }
6071       } else {
6072	  SISErrorLog(pScrn, "Failed to allocate memory for CRT2 monitor, %s.\n",
6073	  		mergeddisstr);
6074	  if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
6075	  pSiS->CRT2pScrn = NULL;
6076	  pSiS->MergedFB = FALSE;
6077       }
6078    }
6079#endif
6080
6081    /* Copy our detected monitor gammas, part 1. Note that device redetection
6082     * is not supported in DHM, so there is no need to do that anytime later.
6083     */
6084#ifdef SISDUALHEAD
6085    if(pSiS->DualHeadMode) {
6086       if(!pSiS->SecondHead) {
6087          /* CRT2: Got gamma for LCD or VGA2 */
6088	  pSiSEnt->CRT2VGAMonitorGamma = pSiS->CRT2VGAMonitorGamma;
6089       } else {
6090          /* CRT1: Got gamma for LCD or VGA */
6091	  pSiSEnt->CRT1VGAMonitorGamma = pSiS->CRT1VGAMonitorGamma;
6092       }
6093       if(pSiS->CRT2LCDMonitorGamma) pSiSEnt->CRT2LCDMonitorGamma = pSiS->CRT2LCDMonitorGamma;
6094    }
6095#endif
6096
6097    /* end of DDC */
6098
6099    /* From here, we mainly deal with clocks and modes */
6100
6101#ifdef SISMERGED
6102    if(pSiS->MergedFB) xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 1);
6103#endif
6104
6105    /* Set the min pixel clock */
6106    pSiS->MinClock = 5000;
6107    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6108       pSiS->MinClock = 10000;
6109    }
6110    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
6111                pSiS->MinClock / 1000);
6112
6113    /* If the user has specified ramdac speed in the config
6114     * file, we respect that setting.
6115     */
6116    from = X_PROBED;
6117    if(pSiS->pEnt->device->dacSpeeds[0]) {
6118       int speed = 0;
6119       switch(pScrn->bitsPerPixel) {
6120       case 8:  speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8];
6121                break;
6122       case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16];
6123                break;
6124       case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24];
6125                break;
6126       case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32];
6127                break;
6128       }
6129       if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0];
6130       else           pSiS->MaxClock = speed;
6131       from = X_CONFIG;
6132    }
6133    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
6134                pSiS->MaxClock / 1000);
6135
6136    /*
6137     * Setup the ClockRanges, which describe what clock ranges are available,
6138     * and what sort of modes they can be used for.
6139     */
6140    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
6141    clockRanges->next = NULL;
6142    clockRanges->minClock = pSiS->MinClock;
6143    clockRanges->maxClock = pSiS->MaxClock;
6144    clockRanges->clockIndex = -1;               /* programmable */
6145    clockRanges->interlaceAllowed = TRUE;
6146    clockRanges->doubleScanAllowed = TRUE;
6147
6148    /*
6149     * Since we have lots of built-in modes for 300/315/330/340 series
6150     * with vb support, we replace the given default mode list with our
6151     * own. In case the video bridge is to be used, we only allow other
6152     * modes if
6153     *   -) vbtype is 301, 301B, 301C or 302B, and
6154     *   -) crt2 device is not TV, and
6155     *   -) crt1 is not LCDA, unless bridge is TMDS/LCDA capable (301C)
6156     */
6157    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6158       if(!(pSiS->noInternalModes)) {
6159          Bool acceptcustommodes = TRUE;  /* Accept user modelines */
6160	  Bool includelcdmodes   = TRUE;  /* Include modes reported by DDC */
6161	  Bool isfordvi          = FALSE; /* Is for digital DVI output */
6162	  Bool fakecrt2modes     = FALSE; /* Fake some modes for CRT2 */
6163	  Bool IsForCRT2	 = FALSE;
6164	  if(pSiS->UseVESA) {
6165	     acceptcustommodes = FALSE;
6166	     includelcdmodes   = FALSE;
6167	  }
6168#ifdef SISDUALHEAD  /* Dual head is static. Output devices will not change. */
6169	  if(pSiS->DualHeadMode) {
6170	     if(!pSiS->SecondHead) {  /* CRT2: */
6171	        if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6172		   if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6173		      if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6174		      if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6175		      if(pSiS->VBFlags & CRT2_TV)                acceptcustommodes = FALSE;
6176		   } else {
6177		      if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6178		         acceptcustommodes = FALSE;
6179		         includelcdmodes   = FALSE;
6180			 fakecrt2modes = TRUE;
6181		      }
6182		   }
6183		} else {
6184		   acceptcustommodes = FALSE;
6185		   includelcdmodes   = FALSE;
6186		   if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6187		      fakecrt2modes = TRUE;
6188		   }
6189		}
6190		clockRanges->interlaceAllowed = FALSE;
6191		IsForCRT2 = TRUE;
6192	     } else {		/* CRT1: */
6193	        if(pSiS->VBFlags & CRT1_LCDA) {
6194		   if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6195		      acceptcustommodes = FALSE;
6196		      includelcdmodes   = FALSE;
6197		      fakecrt2modes     = TRUE;
6198		      /* Will handle i-lace in mode-switching code */
6199		   } else {
6200		      isfordvi = TRUE;
6201		      /* Don't allow i-lace modes */
6202		      clockRanges->interlaceAllowed = FALSE;
6203		   }
6204		} else {
6205		   includelcdmodes = FALSE;
6206		}
6207	     }
6208	  } else
6209#endif
6210#ifdef SISMERGED  /* MergedFB mode is not static. Output devices may change. */
6211          if(pSiS->MergedFB) {
6212	     if(pSiS->VBFlags & CRT1_LCDA) {
6213	        if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6214		   acceptcustommodes = FALSE;
6215		   includelcdmodes   = FALSE;
6216		   fakecrt2modes     = TRUE;
6217		   /* Will handle i-lace in mode-switching code */
6218		} else {
6219		   isfordvi = TRUE;
6220		   /* Don't allow i-lace custom modes */
6221		   clockRanges->interlaceAllowed = FALSE;
6222		}
6223	     } else {
6224	        includelcdmodes = FALSE;
6225	     }
6226          } else
6227#endif		 /* Mirror mode is not static. Output devices may change. */
6228          if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6229	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6230		if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6231		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes = FALSE;
6232		   if(pSiS->VBFlags & CRT2_LCD)               isfordvi        = TRUE;
6233		} else {
6234		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA|CRT1_LCDA))) includelcdmodes = FALSE;
6235		   if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA))             isfordvi        = TRUE;
6236		}
6237		if((!(pSiS->VBFlags & DISPTYPE_CRT1)) && (!(pSiS->VBFlags & CRT1_LCDA))) {
6238		   IsForCRT2 = TRUE;
6239		}
6240		/* Allow user modes, even if CRT2 is TV. Will be filtered through ValidMode();
6241		 * leaving the user modes here might have the advantage that such a mode, if
6242		 * it matches in resolution with a supported TV mode, allows us to drive eg.
6243		 * non standard panels, and still permits switching to TV. This mode will be
6244		 * "mapped" to a supported mode of identical resolution for TV. All this is
6245		 * taken care of by ValidMode() and ModeInit()/PresetMode().
6246		 */
6247	     } else {
6248		if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6249		   acceptcustommodes = FALSE;
6250		   includelcdmodes   = FALSE;
6251		   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
6252		      fakecrt2modes = TRUE;
6253		      IsForCRT2 = TRUE;
6254		   }
6255		}
6256	     }
6257	  } else if(pSiS->VBFlags & (CRT2_ENABLE | CRT1_LCDA)) {
6258	     acceptcustommodes = FALSE;
6259	     includelcdmodes   = FALSE;
6260	     if((pSiS->VBFlags & CRT1_LCDA) || (!(pSiS->VBFlags & DISPTYPE_CRT1))) {
6261		fakecrt2modes = TRUE;
6262		IsForCRT2 = TRUE;
6263	     }
6264	  } else {
6265	     includelcdmodes   = FALSE;
6266	  }
6267	  /* Ignore interlace, mode switching code will handle this */
6268
6269	  pSiS->HaveCustomModes = FALSE;
6270	  if(SiSMakeOwnModeList(pScrn, acceptcustommodes, includelcdmodes,
6271			isfordvi, &pSiS->HaveCustomModes, FALSE /*fakecrt2modes*/, IsForCRT2)) {
6272	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6273		 "Replaced %s mode list with built-in modes\n",
6274	     pSiS->HaveCustomModes ? "default" : "entire");
6275	     if(pSiS->VGAEngine == SIS_315_VGA) {
6276		int UseWide = pSiS->SiS_Pr->SiS_UseWide;
6277		if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
6278		if((!IsForCRT2) || (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6279		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6280			"Using %s widescreen modes for CRT%d VGA devices\n",
6281			UseWide ? "real" : "fake", IsForCRT2 ? 2 : 1);
6282		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6283			"\tUse option \"ForceCRT%dVGAAspect\" to overrule\n",
6284			IsForCRT2 ? 2 : 1);
6285		}
6286	     }
6287#ifdef TWDEBUG
6288             pScrn->modes = pScrn->monitor->Modes;
6289	     xf86PrintModes(pScrn);
6290	     pScrn->modes = NULL;
6291#endif
6292          } else {
6293	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6294		"Building list of built-in modes failed, using server defaults\n");
6295	  }
6296       } else {
6297          pSiS->HaveCustomModes = TRUE;
6298       }
6299    }
6300
6301    /* Add our built-in hi-res and TV modes on the 6326 */
6302    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
6303       if(pScrn->bitsPerPixel == 8) {
6304	  SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes;
6305	  pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode;
6306	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6307	  	"Adding mode \"SIS1600x1200-60\" (depth 8 only)\n");
6308       }
6309       if(pScrn->bitsPerPixel <= 16) {
6310	  SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes;
6311	  pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode;
6312	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6313	  	"Adding mode \"SIS1280x1024-75\" (depths 8, 15 and 16 only)\n");
6314       }
6315       if((pSiS->SiS6326Flags & SIS6326_HASTV) &&
6316	  (pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
6317	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6318		"Adding %s TV modes to mode list:\n",
6319		(pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC");
6320	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
6321	     SiS6326PAL800x600Mode.next = pScrn->monitor->Modes;
6322	     pScrn->monitor->Modes = &SiS6326PAL640x480Mode;
6323	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6324		"\t\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n");
6325	  } else {
6326	     SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes;
6327	     pScrn->monitor->Modes = &SiS6326NTSC640x400Mode;
6328	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6329		"\t\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n");
6330	  }
6331       }
6332    }
6333
6334   /* If there is no HSync or VRefresh data for the monitor,
6335    * derive it from DDC data. Essentially done by common layer
6336    * since 4.3.99.14, but this is not usable since it is done
6337    * too late (in ValidateModes()).
6338    * Addendum: I overrule the ranges now in any case unless
6339    * it would affect a CRT output device or DDC data is available.
6340    * Hence, for LCD(A) and TV, we always get proper ranges. This
6341    * is entirely harmless. However, option "NoOverruleRanges" will
6342    * disable this behavior.
6343    * This should "fix" the - by far - most common configuration
6344    * mistakes.
6345    */
6346
6347    crt1freqoverruled = FALSE;
6348
6349    fromDDC = FALSE;
6350    if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6351       if((pScrn->monitor->nHsync <= 0) && (pScrn->monitor->DDC)) {
6352	  SiSSetSyncRangeFromEdid(pScrn, 1);
6353	  if(pScrn->monitor->nHsync > 0) {
6354	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr,
6355#ifdef SISDUALHEAD
6356			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6357#endif
6358				pSiS->CRT1off ? 2 : 1);
6359	     fromDDC = TRUE;
6360	  }
6361       }
6362       if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6363	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6364	     Bool HaveNoRanges = (pScrn->monitor->nHsync <= 0);
6365	     /* Set sane ranges for LCD and TV
6366	      * (our strict checking will filter out invalid ones anyway)
6367	      */
6368	     if((crt1freqoverruled = CheckAndOverruleH(pScrn, pScrn->monitor))) {
6369		xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6370			HaveNoRanges ? "missing" : "bogus",
6371#ifdef SISDUALHEAD
6372			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6373#endif
6374				pSiS->CRT1off ? 2 : 1);
6375	     }
6376	  }
6377       }
6378    }
6379
6380    fromDDC = FALSE;
6381    if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6382       if((pScrn->monitor->nVrefresh <= 0) && (pScrn->monitor->DDC)) {
6383	  SiSSetSyncRangeFromEdid(pScrn, 0);
6384	  if(pScrn->monitor->nVrefresh > 0) {
6385	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr,
6386#ifdef SISDUALHEAD
6387			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6388#endif
6389				pSiS->CRT1off ? 2 : 1);
6390	     fromDDC = TRUE;
6391          }
6392       }
6393       if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6394	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6395	     Bool HaveNoRanges = (pScrn->monitor->nVrefresh <= 0);
6396	     /* Set sane ranges for LCD and TV */
6397	     if((crt1freqoverruled = CheckAndOverruleV(pScrn, pScrn->monitor))) {
6398		xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6399			HaveNoRanges ? "missing" : "bogus",
6400#ifdef SISDUALHEAD
6401			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6402#endif
6403				pSiS->CRT1off ? 2 : 1);
6404	     }
6405	  }
6406       }
6407    }
6408
6409    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
6410       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6411	  "\"Unknown reason\" in the following list means that the mode\n");
6412       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6413	  "is not supported on the chipset/bridge/current output device.\n");
6414    }
6415
6416    /*
6417     * xf86ValidateModes will check that the mode HTotal and VTotal values
6418     * don't exceed the chipset's limit if pScrn->maxHValue and
6419     * pScrn->maxVValue are set.  Since our SISValidMode() already takes
6420     * care of this, we don't worry about setting them here.
6421     */
6422
6423    /* Select valid modes from those available */
6424    /*
6425     * Assuming min pitch 256, min height 128
6426     */
6427    {
6428       int minpitch, maxpitch, minheight, maxheight;
6429       pointer backupddc = pScrn->monitor->DDC;
6430
6431       minpitch = 256;
6432       minheight = 128;
6433       switch(pSiS->VGAEngine) {
6434       case SIS_OLD_VGA:
6435       case SIS_530_VGA:
6436          maxpitch = 2040;
6437          maxheight = 2048;
6438          break;
6439       case SIS_300_VGA:
6440       case SIS_315_VGA:
6441          maxpitch = 4088;
6442          maxheight = 4096;
6443          break;
6444       default:
6445          maxpitch = 2048;
6446          maxheight = 2048;
6447          break;
6448       }
6449
6450#ifdef SISMERGED
6451       pSiS->CheckForCRT2 = FALSE;
6452#endif
6453
6454       /* Suppress bogus DDC warning */
6455       if(crt1freqoverruled) pScrn->monitor->DDC = NULL;
6456
6457       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
6458			pScrn->display->modes, clockRanges, NULL,
6459			minpitch, maxpitch,
6460			pScrn->bitsPerPixel * 8,
6461			minheight, maxheight,
6462			pScrn->display->virtualX,
6463			pScrn->display->virtualY,
6464			pSiS->maxxfbmem,
6465			LOOKUP_BEST_REFRESH);
6466
6467       pScrn->monitor->DDC = backupddc;
6468    }
6469
6470    if(i == -1) {
6471       SISErrorLog(pScrn, "xf86ValidateModes() error\n");
6472       goto my_error_1;
6473    }
6474
6475    /* Check the virtual screen against the available memory */
6476    {
6477       ULong memreq = (pScrn->virtualX * ((pScrn->bitsPerPixel + 7) / 8)) * pScrn->virtualY;
6478
6479       if(memreq > pSiS->maxxfbmem) {
6480	  SISErrorLog(pScrn,
6481	     "Virtual screen too big for memory; %ldK needed, %ldK available\n",
6482	     memreq/1024, pSiS->maxxfbmem/1024);
6483	  goto my_error_1;
6484       }
6485    }
6486
6487    /* Dual Head:
6488     * -) Go through mode list and mark all those modes as bad,
6489     *    which are unsuitable for dual head mode.
6490     * -) Find the highest used pixelclock on the master head.
6491     */
6492#ifdef SISDUALHEAD
6493    if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) {
6494
6495       pSiSEnt->maxUsedClock = 0;
6496
6497       if((p = first = pScrn->modes)) {
6498
6499	  do {
6500
6501	     n = p->next;
6502
6503	     /* Modes that require the bridge to operate in SlaveMode
6504	      * are not suitable for Dual Head mode.
6505	      */
6506	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6507		 ( (strcmp(p->name, "320x200") == 0) ||
6508		   (strcmp(p->name, "320x240") == 0) ||
6509		   (strcmp(p->name, "400x300") == 0) ||
6510		   (strcmp(p->name, "512x384") == 0) ||
6511		   (strcmp(p->name, "640x400") == 0) ) )  {
6512		p->status = MODE_BAD;
6513		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "dual head");
6514	     }
6515
6516	     /* Search for the highest clock on first head in order to calculate
6517	      * max clock for second head (CRT1)
6518	      */
6519	     if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) {
6520		pSiSEnt->maxUsedClock = p->Clock;
6521	     }
6522
6523	     p = n;
6524
6525	  } while (p != NULL && p != first);
6526
6527       }
6528    }
6529#endif
6530
6531    /* Prune the modes marked as invalid */
6532    xf86PruneDriverModes(pScrn);
6533
6534    if(i == 0 || pScrn->modes == NULL) {
6535       SISErrorLog(pScrn, "No valid modes found - check VertRefresh/HorizSync\n");
6536       goto my_error_1;
6537    }
6538
6539    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
6540
6541    /* Set the current mode to the first in the list */
6542    pScrn->currentMode = pScrn->modes;
6543
6544    /* Copy to CurrentLayout */
6545    pSiS->CurrentLayout.mode = pScrn->currentMode;
6546    pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6547    pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6548
6549#ifdef SISMERGED
6550    if(pSiS->MergedFB) {
6551       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 1);
6552    }
6553#endif
6554
6555    /* Print the list of modes being used */
6556    {
6557       Bool usemyprint = FALSE;
6558
6559#ifdef SISDUALHEAD
6560       if(pSiS->DualHeadMode) {
6561	  if(pSiS->SecondHead) {
6562	     if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6563	  } else {
6564	     if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) usemyprint = TRUE;
6565	  }
6566       } else
6567#endif
6568#ifdef SISMERGED
6569       if(pSiS->MergedFB) {
6570	  if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6571       } else
6572#endif
6573       {
6574	  if( (pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) &&
6575	      (!(pSiS->VBFlags & DISPTYPE_DISP1)) )
6576	     usemyprint = TRUE;
6577       }
6578
6579       if(usemyprint) {
6580	  SiSPrintModes(pScrn);
6581       } else {
6582	  xf86PrintModes(pScrn);
6583       }
6584    }
6585
6586#ifdef SISMERGED
6587    if(pSiS->MergedFB) {
6588       Bool acceptcustommodes = TRUE;
6589       Bool includelcdmodes   = TRUE;
6590       Bool isfordvi          = FALSE;
6591       Bool fakecrt2modes     = FALSE;
6592
6593       xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 2);
6594
6595       clockRanges->next = NULL;
6596       clockRanges->minClock = pSiS->MinClock;
6597       clockRanges->maxClock = SiSMemBandWidth(pSiS->CRT2pScrn, TRUE);
6598       clockRanges->clockIndex = -1;
6599       clockRanges->interlaceAllowed = FALSE;
6600       clockRanges->doubleScanAllowed = FALSE;
6601       if(pSiS->VGAEngine == SIS_315_VGA) {
6602          clockRanges->doubleScanAllowed = TRUE;
6603       }
6604
6605       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock for CRT2 is %d MHz\n",
6606                clockRanges->minClock / 1000);
6607       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Max pixel clock for CRT2 is %d MHz\n",
6608                clockRanges->maxClock / 1000);
6609
6610       if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6611          if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6612             if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6613	     if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6614	     /* See above for a remark on handling CRT2 = TV */
6615	  } else {
6616	     if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6617		includelcdmodes   = FALSE;
6618		acceptcustommodes = FALSE;
6619		fakecrt2modes     = TRUE;
6620	     }
6621	  }
6622       } else {
6623	  includelcdmodes   = FALSE;
6624	  acceptcustommodes = FALSE;
6625	  if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6626	     fakecrt2modes = TRUE;
6627	  }
6628       }
6629
6630       pSiS->HaveCustomModes2 = FALSE;
6631       if(!SiSMakeOwnModeList(pSiS->CRT2pScrn, acceptcustommodes, includelcdmodes,
6632				isfordvi, &pSiS->HaveCustomModes2, FALSE /* fakecrt2modes */, TRUE )) {
6633
6634	  SISErrorLog(pScrn, "Building list of built-in modes for CRT2 failed, %s\n",
6635				mergeddisstr);
6636	  SiSFreeCRT2Structs(pSiS);
6637	  pSiS->MergedFB = FALSE;
6638
6639       } else {
6640	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6641		 "Replaced %s mode list for CRT2 with built-in modes\n",
6642		 pSiS->HaveCustomModes2 ? "default" : "entire");
6643	  if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6644	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6645		 "Using %s widescreen modes for CRT2 VGA devices\n",
6646		 pSiS->SiS_Pr->SiS_UseWideCRT2 ? "real" : "fake");
6647	  } else pSiS->SiS_Pr->SiS_UseWideCRT2 = 0;
6648       }
6649
6650    }
6651
6652    if(pSiS->MergedFB) {
6653
6654       pointer backupddc;
6655
6656       crt2freqoverruled = FALSE;
6657
6658       fromDDC = FALSE;
6659       if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6660          if((pSiS->CRT2pScrn->monitor->nHsync <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6661	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 1);
6662	     if(pSiS->CRT2pScrn->monitor->nHsync > 0) {
6663		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr, 2);
6664		fromDDC = TRUE;
6665	     }
6666	  }
6667	  if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6668	     if( (pSiS->VBFlags & CRT2_TV) ||
6669	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6670		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nHsync <= 0);
6671		/* Set sane ranges for LCD and TV */
6672		if((crt2freqoverruled = CheckAndOverruleH(pScrn, pSiS->CRT2pScrn->monitor))) {
6673		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6674			HaveNoRanges ? "missing" : "bogus", 2);
6675		}
6676	     }
6677	  }
6678       }
6679
6680       fromDDC = FALSE;
6681       if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6682	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6683	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 0);
6684	     if(pSiS->CRT2pScrn->monitor->nVrefresh > 0) {
6685		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr, 2);
6686		fromDDC = TRUE;
6687	     }
6688          }
6689	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6690	     if( (pSiS->VBFlags & CRT2_TV) ||
6691	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6692		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nVrefresh <= 0);
6693		/* Set sane ranges for LCD and TV */
6694		if((crt2freqoverruled = CheckAndOverruleV(pScrn, pSiS->CRT2pScrn->monitor))) {
6695		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6696			 HaveNoRanges ? "missing" : "bogus", 2);
6697	        }
6698	     }
6699	  }
6700       }
6701
6702       backupddc = pSiS->CRT2pScrn->monitor->DDC;
6703
6704       /* Suppress bogus DDC warning */
6705       if(crt2freqoverruled) pSiS->CRT2pScrn->monitor->DDC = NULL;
6706
6707       pSiS->CheckForCRT2 = TRUE;
6708
6709       i = xf86ValidateModes(pSiS->CRT2pScrn, pSiS->CRT2pScrn->monitor->Modes,
6710			pSiS->CRT2pScrn->display->modes, clockRanges,
6711			NULL, 256, 4088,
6712			pSiS->CRT2pScrn->bitsPerPixel * 8, 128, 4096,
6713			pScrn->display->virtualX ? pScrn->virtualX : 0,
6714			pScrn->display->virtualY ? pScrn->virtualY : 0,
6715			pSiS->maxxfbmem,
6716			LOOKUP_BEST_REFRESH);
6717
6718       pSiS->CheckForCRT2 = FALSE;
6719       pSiS->CRT2pScrn->monitor->DDC = backupddc;
6720
6721       if(i == -1) {
6722	  SISErrorLog(pScrn, "xf86ValidateModes() error, %s.\n", mergeddisstr);
6723	  SiSFreeCRT2Structs(pSiS);
6724	  pSiS->MergedFB = FALSE;
6725       }
6726
6727    }
6728
6729    if(pSiS->MergedFB) {
6730
6731       if((p = first = pSiS->CRT2pScrn->modes)) {
6732          do {
6733	     n = p->next;
6734	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6735		 ( (strcmp(p->name, "320x200") == 0) ||
6736		   (strcmp(p->name, "320x240") == 0) ||
6737		   (strcmp(p->name, "400x300") == 0) ||
6738		   (strcmp(p->name, "512x384") == 0) ||
6739		   (strcmp(p->name, "640x400") == 0) ) )  {
6740		p->status = MODE_BAD;
6741		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "MergedFB");
6742	     }
6743	     p = n;
6744	  } while (p != NULL && p != first);
6745       }
6746
6747       xf86PruneDriverModes(pSiS->CRT2pScrn);
6748
6749       if(i == 0 || pSiS->CRT2pScrn->modes == NULL) {
6750	  SISErrorLog(pScrn, "No valid modes found for CRT2; %s\n", mergeddisstr);
6751	  SiSFreeCRT2Structs(pSiS);
6752	  pSiS->MergedFB = FALSE;
6753       }
6754
6755    }
6756
6757    if(pSiS->MergedFB) {
6758
6759       xf86SetCrtcForModes(pSiS->CRT2pScrn, INTERLACE_HALVE_V);
6760
6761       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 2);
6762
6763       if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) {
6764	  SiSPrintModes(pSiS->CRT2pScrn);
6765       } else {
6766	  xf86PrintModes(pSiS->CRT2pScrn);
6767       }
6768
6769       pSiS->CRT1Modes = pScrn->modes;
6770       pSiS->CRT1CurrentMode = pScrn->currentMode;
6771
6772       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
6773
6774       pScrn->modes = SiSGenerateModeList(pScrn, pSiS->MetaModes,
6775					  pSiS->CRT1Modes, pSiS->CRT2pScrn->modes,
6776					  pSiS->CRT2Position);
6777
6778       if(!pScrn->modes) {
6779
6780	  SISErrorLog(pScrn, "Failed to parse MetaModes or no modes found. %s.\n",
6781			mergeddisstr);
6782	  SiSFreeCRT2Structs(pSiS);
6783	  pScrn->modes = pSiS->CRT1Modes;
6784	  pSiS->CRT1Modes = NULL;
6785	  pSiS->MergedFB = FALSE;
6786
6787       }
6788
6789    }
6790
6791    if(pSiS->MergedFB) {
6792
6793       /* If no virtual dimension was given by the user,
6794	* calculate a sane one now. Adapts pScrn->virtualX,
6795	* pScrn->virtualY and pScrn->displayWidth.
6796	*/
6797       SiSRecalcDefaultVirtualSize(pScrn);
6798
6799       pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
6800       pScrn->currentMode = pScrn->modes;
6801
6802       /* Update CurrentLayout */
6803       pSiS->CurrentLayout.mode = pScrn->currentMode;
6804       pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6805       pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6806
6807    }
6808#endif
6809
6810    /* Set display resolution */
6811#ifdef SISMERGED
6812    if(pSiS->MergedFB) {
6813       SiSMergedFBSetDpi(pScrn, pSiS->CRT2pScrn, pSiS->CRT2Position);
6814    } else
6815#endif
6816       xf86SetDpi(pScrn, 0, 0);
6817
6818    /* Load fb module */
6819    switch(pScrn->bitsPerPixel) {
6820      case 8:
6821      case 16:
6822      case 24:
6823      case 32:
6824	if(!xf86LoadSubModule(pScrn, "fb")) {
6825           SISErrorLog(pScrn, "Failed to load fb module");
6826	   goto my_error_1;
6827	}
6828	break;
6829      default:
6830	SISErrorLog(pScrn, "Unsupported framebuffer bpp (%d)\n", pScrn->bitsPerPixel);
6831	goto my_error_1;
6832    }
6833
6834    /* Load XAA/EXA (if needed) */
6835    if(!pSiS->NoAccel) {
6836#ifdef SIS_USE_XAA
6837       if(!pSiS->useEXA) {
6838	  if (!xf86LoadSubModule(pScrn, "xaa")) {
6839	    SISErrorLog(pScrn, "Could not load xaa module\n");
6840	    goto my_error_1;
6841	  }
6842       }
6843#endif
6844#ifdef SIS_USE_EXA
6845       if(pSiS->useEXA) {
6846	  XF86ModReqInfo req;
6847	  int errmaj, errmin;
6848
6849	  memset(&req, 0, sizeof(req));
6850	  req.majorversion = 2;
6851	  req.minorversion = 0;
6852	  if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
6853	    &errmaj, &errmin)) {
6854	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
6855	    goto my_error_1;
6856	  }
6857       }
6858#endif
6859       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration enabled\n");
6860    }
6861
6862    /* Load shadowfb (if needed) */
6863    if(pSiS->ShadowFB) {
6864       if(!xf86LoadSubModule(pScrn, "shadowfb")) {
6865	  SISErrorLog(pScrn, "Could not load shadowfb module\n");
6866	  goto my_error_1;
6867       }
6868    }
6869
6870    /* Load the dri and glx modules if requested. */
6871#ifdef XF86DRI
6872    if(pSiS->loadDRI) {
6873       if(!xf86LoaderCheckSymbol("DRIScreenInit")) {
6874	  if(xf86LoadSubModule(pScrn, "dri")) {
6875	     if(!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) {
6876	        if(!xf86LoadSubModule(pScrn, "glx")) {
6877		   SISErrorLog(pScrn, "Failed to load glx module\n");
6878		}
6879	     }
6880	  } else {
6881	     SISErrorLog(pScrn, "Failed to load dri module\n");
6882	  }
6883       }
6884    }
6885#endif
6886
6887    /* Now load and initialize VBE module for VESA mode switching */
6888    pSiS->UseVESA = 0;
6889    if(pSiS->VESA == 1) {
6890       SiS_LoadInitVBE(pScrn);
6891       if(pSiS->pVbe) {
6892	  VbeInfoBlock *vbe;
6893	  if((vbe = VBEGetVBEInfo(pSiS->pVbe))) {
6894	     pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8);
6895	     pSiS->vesaminor = vbe->VESAVersion & 0xff;
6896	     SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe);
6897	     VBEFreeVBEInfo(vbe);
6898	     pSiS->UseVESA = 1;
6899	  } else {
6900	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6901	     	 "Failed to read VBE Info Block\n");
6902	  }
6903       }
6904       if(pSiS->UseVESA == 0) {
6905	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6906	      "VESA mode switching disabled.\n");
6907       }
6908    }
6909
6910    if(pSiS->pVbe) {
6911       vbeFree(pSiS->pVbe);
6912       pSiS->pVbe = NULL;
6913    }
6914
6915#ifdef SISDUALHEAD
6916    xf86SetPrimInitDone(pScrn->entityList[0]);
6917#endif
6918
6919    sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
6920
6921    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
6922    pSiS->pInt = NULL;
6923
6924    if(pSiS->VGAEngine == SIS_315_VGA) {
6925       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTXVGAMMA1;
6926    }
6927
6928#ifdef SISDUALHEAD
6929    if(pSiS->DualHeadMode) {
6930	pSiS->SiS_SD_Flags |= SiS_SD_ISDUALHEAD;
6931	if(pSiS->SecondHead) pSiS->SiS_SD_Flags |= SiS_SD_ISDHSECONDHEAD;
6932	else		     pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1);
6933#ifdef PANORAMIX
6934	if(!noPanoramiXExtension) {
6935	   pSiS->SiS_SD_Flags |= SiS_SD_ISDHXINERAMA;
6936	   /* pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1); */
6937	}
6938#endif
6939    }
6940#endif
6941
6942#ifdef SISMERGED
6943    if(pSiS->MergedFB) pSiS->SiS_SD_Flags |= SiS_SD_ISMERGEDFB;
6944#endif
6945
6946    /* Try to determine if this is a laptop   */
6947    /* (only used for SiSCtrl visualisations) */
6948    pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPLTFLAG;
6949    pSiS->SiS_SD2_Flags &= ~SiS_SD2_ISLAPTOP;
6950    if(pSiS->detectedCRT2Devices & CRT2_LCD) {
6951       if(pSiS->VBFlags2 & (VB2_SISLVDSBRIDGE | VB2_LVDS | VB2_30xBDH)) {
6952	  /* 1. By bridge type: LVDS in 99% of all cases;
6953	   * exclude unusual setups like Barco projectors
6954	   * and parallel flat panels. TODO: Exclude
6955	   * Sony W1, V1.
6956	   */
6957	  if((pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
6958	     (pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
6959	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL848)  &&
6960	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL856)  &&
6961	     (pSiS->SiS_Pr->SiS_CustomT != CUT_AOP8060)   &&
6962	     ( (pSiS->ChipType != SIS_550) ||
6963	       (!pSiS->DSTN && !pSiS->FSTN) ) ) {
6964	     pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
6965	  }
6966       } else if((pSiS->VBFlags2 & (VB2_301 | VB2_301C)) &&
6967                 (pSiS->VBLCDFlags & (VB_LCD_1280x960  |
6968				      VB_LCD_1400x1050 |
6969				      VB_LCD_1024x600  |
6970				      VB_LCD_1280x800  |
6971				      VB_LCD_1280x854))) {
6972	  /* 2. By (odd) LCD resolutions on TMDS bridges
6973	   * (eg Averatec). TODO: Exclude IBM Netvista.
6974	   */
6975	  pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
6976       }
6977    }
6978
6979    if(pSiS->enablesisctrl) pSiS->SiS_SD_Flags |= SiS_SD_ENABLED;
6980
6981    pSiS->currentModeLast = pScrn->currentMode;
6982    pSiS->VBFlagsInit = pSiS->VBFlags;
6983
6984    return TRUE;
6985
6986    /* ---- */
6987
6988my_error_1:
6989    sisRestoreExtRegisterLock(pSiS, srlockReg, crlockReg);
6990my_error_0:
6991#ifdef SISDUALHEAD
6992    if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
6993#endif
6994    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
6995    pSiS->pInt = NULL;
6996    SISFreeRec(pScrn);
6997    return FALSE;
6998}
6999
7000/*
7001 * Map I/O port area for non-PC platforms
7002 */
7003#ifdef SIS_NEED_MAP_IOP
7004static Bool
7005SISMapIOPMem(ScrnInfoPtr pScrn)
7006{
7007    SISPtr pSiS = SISPTR(pScrn);
7008#ifdef SISDUALHEAD
7009    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7010
7011    if(pSiS->DualHeadMode) {
7012        pSiSEnt->MapCountIOPBase++;
7013        if(!(pSiSEnt->IOPBase)) {
7014	     /* Only map if not mapped previously */
7015#ifndef XSERVER_LIBPCIACCESS
7016	     pSiSEnt->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7017			pSiS->PciTag, pSiS->IOPAddress, 128);
7018#else
7019	     {
7020	       void **result = (void **)&pSiSEnt->IOPBase;
7021	       int err = pci_device_map_range(pSiS->PciInfo,
7022					      pSiS->IOPAddress,
7023					      128,
7024					      PCI_DEV_MAP_FLAG_WRITABLE,
7025					      result);
7026
7027	       if (err) {
7028                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7029                             "Unable to map IO aperture. %s (%d)\n",
7030                             strerror (err), err);
7031	       }
7032	     }
7033#endif
7034        }
7035        pSiS->IOPBase = pSiSEnt->IOPBase;
7036    } else
7037#endif
7038#ifndef XSERVER_LIBPCIACCESS
7039	     pSiS->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7040					   pSiS->PciTag, pSiS->IOPAddress, 128);
7041#else
7042	     {
7043	       void **result = (void **)&pSiS->IOPBase;
7044	       int err = pci_device_map_range(pSiS->PciInfo,
7045					      pSiS->IOPAddress,
7046					      128,
7047					      PCI_DEV_MAP_FLAG_WRITABLE,
7048					      result);
7049
7050	       if (err) {
7051                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7052                             "Unable to map IO aperture. %s (%d)\n",
7053                             strerror (err), err);
7054	       }
7055	     }
7056#endif
7057    if(pSiS->IOPBase == NULL) {
7058	SISErrorLog(pScrn, "Could not map I/O port area\n");
7059	return FALSE;
7060    }
7061
7062    return TRUE;
7063}
7064
7065static Bool
7066SISUnmapIOPMem(ScrnInfoPtr pScrn)
7067{
7068    SISPtr pSiS = SISPTR(pScrn);
7069#ifdef SISDUALHEAD
7070    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
7071#endif
7072
7073/* In dual head mode, we must not unmap if the other head still
7074 * assumes memory as mapped
7075 */
7076#ifdef SISDUALHEAD
7077    if(pSiS->DualHeadMode) {
7078        if(pSiSEnt->MapCountIOPBase) {
7079	    pSiSEnt->MapCountIOPBase--;
7080	    if((pSiSEnt->MapCountIOPBase == 0) || (pSiSEnt->forceUnmapIOPBase)) {
7081		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOPBase, 2048);
7082		pSiSEnt->IOPBase = NULL;
7083		pSiSEnt->MapCountIOPBase = 0;
7084		pSiSEnt->forceUnmapIOPBase = FALSE;
7085	    }
7086	    pSiS->IOPBase = NULL;
7087	}
7088    } else {
7089#endif
7090	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOPBase, 2048);
7091	pSiS->IOPBase = NULL;
7092#ifdef SISDUALHEAD
7093    }
7094#endif
7095    return TRUE;
7096}
7097#endif
7098
7099/*
7100 * Map the framebuffer and MMIO memory
7101 */
7102
7103static Bool
7104SISMapMem(ScrnInfoPtr pScrn)
7105{
7106    SISPtr pSiS = SISPTR(pScrn);
7107    int mmioFlags = VIDMEM_MMIO;
7108#ifdef SISDUALHEAD
7109    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7110#endif
7111
7112    /*
7113     * Map IO registers to virtual address space
7114     * (For Alpha, we need to map SPARSE memory, since we need
7115     * byte/short access.)
7116     */
7117#if defined(__alpha__)
7118    mmioFlags |= VIDMEM_SPARSE;
7119#endif
7120
7121#ifdef SISDUALHEAD
7122    if(pSiS->DualHeadMode) {
7123        pSiSEnt->MapCountIOBase++;
7124        if(!(pSiSEnt->IOBase)) {
7125	     /* Only map if not mapped previously */
7126#ifndef XSERVER_LIBPCIACCESS
7127    	     pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7128                         pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7129#else
7130	     void **result = (void **)&pSiSEnt->IOBase;
7131	     int err = pci_device_map_range(pSiS->PciInfo,
7132 	                                    pSiS->IOAddress,
7133	                                    (pSiS->mmioSize * 1024),
7134                                            PCI_DEV_MAP_FLAG_WRITABLE,
7135                                            result);
7136
7137             if (err) {
7138                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7139                             "Unable to map IO aperture. %s (%d)\n",
7140                             strerror (err), err);
7141	     }
7142#endif
7143        }
7144        pSiS->IOBase = pSiSEnt->IOBase;
7145    } else
7146#endif
7147#ifndef XSERVER_LIBPCIACCESS
7148    	pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7149                        pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7150#else
7151       {
7152	     void **result = (void **)&pSiS->IOBase;
7153	     int err = pci_device_map_range(pSiS->PciInfo,
7154 	                                    pSiS->IOAddress,
7155	                                    (pSiS->mmioSize * 1024),
7156                                            PCI_DEV_MAP_FLAG_WRITABLE,
7157                                            result);
7158
7159             if (err) {
7160                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7161                             "Unable to map IO aperture. %s (%d)\n",
7162                             strerror (err), err);
7163	     }
7164       }
7165#endif
7166
7167    if(pSiS->IOBase == NULL) {
7168    	SISErrorLog(pScrn, "Could not map MMIO area\n");
7169        return FALSE;
7170    }
7171
7172#ifdef __alpha__
7173    /*
7174     * for Alpha, we need to map DENSE memory as well, for
7175     * setting CPUToScreenColorExpandBase.
7176     */
7177#ifdef SISDUALHEAD
7178    if(pSiS->DualHeadMode) {
7179        pSiSEnt->MapCountIOBaseDense++;
7180        if(!(pSiSEnt->IOBaseDense)) {
7181	     /* Only map if not mapped previously */
7182#ifndef XSERVER_LIBPCIACCESS
7183	     pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7184                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7185#else
7186	     void **result = (void **)&pSiSEnt->IOBaseDense;
7187	     int err = pci_device_map_range(pSiS->PciInfo,
7188 	                                    pSiS->IOAddress,
7189	                                    (pSiS->mmioSize * 1024),
7190                                            PCI_DEV_MAP_FLAG_WRITABLE,
7191                                            result);
7192
7193             if (err) {
7194                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7195                             "Unable to map IO dense aperture. %s (%d)\n",
7196                             strerror (err), err);
7197	     }
7198#endif /* XSERVER_LIBPCIACCESS */
7199	}
7200	pSiS->IOBaseDense = pSiSEnt->IOBaseDense;
7201    } else {
7202#endif /* SISDUALHEAD */
7203#ifndef XSERVER_LIBPCIACCESS
7204	     pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7205                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7206#else
7207	     void **result = (void **)&pSiS->IOBaseDense;
7208	     int err = pci_device_map_range(pSiS->PciInfo,
7209 	                                    pSiS->IOAddress,
7210	                                    (pSiS->mmioSize * 1024),
7211                                            PCI_DEV_MAP_FLAG_WRITABLE,
7212                                            result);
7213
7214             if (err) {
7215                 xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7216                             "Unable to map IO dense aperture. %s (%d)\n",
7217                             strerror (err), err);
7218	     }
7219#endif /* XSERVER_LIBPCIACCESS */
7220#ifdef SISDUALHEAD
7221    }
7222#endif
7223    if(pSiS->IOBaseDense == NULL) {
7224       SISErrorLog(pScrn, "Could not map MMIO dense area\n");
7225       return FALSE;
7226    }
7227#endif /* __alpha__ */
7228
7229#ifdef SISDUALHEAD
7230    if(pSiS->DualHeadMode) {
7231	pSiSEnt->MapCountFbBase++;
7232	if(!(pSiSEnt->FbBase)) {
7233	     /* Only map if not mapped previously */
7234#ifndef XSERVER_LIBPCIACCESS
7235	     pSiSEnt->FbBase = pSiSEnt->RealFbBase =
7236			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7237			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7238			 pSiS->FbMapSize);
7239#else
7240         int err = pci_device_map_range(pSiS->PciInfo,
7241                                   (ULong)pSiS->realFbAddress,
7242                                   pSiS->FbMapSize,
7243                                   PCI_DEV_MAP_FLAG_WRITABLE |
7244                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7245                                   (void *)&pSiSEnt->FbBase);
7246	if (err) {
7247            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7248                        "Unable to map FB aperture. %s (%d)\n",
7249                        strerror (err), err);
7250            return FALSE;
7251        }
7252	pSiSEnt->RealFbBase = pSiSEnt->FbBase;
7253#endif
7254	}
7255	pSiS->FbBase = pSiS->RealFbBase = pSiSEnt->FbBase;
7256	/* Adapt FbBase (for DHM and SiS76x UMA skipping; dhmOffset is 0 otherwise) */
7257	pSiS->FbBase += pSiS->dhmOffset;
7258    } else {
7259#endif
7260
7261#ifndef XSERVER_LIBPCIACCESS
7262      pSiS->FbBase = pSiS->RealFbBase =
7263			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7264			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7265			 pSiS->FbMapSize);
7266#else
7267         int err = pci_device_map_range(pSiS->PciInfo,
7268                                   (ULong)pSiS->realFbAddress,
7269                                   pSiS->FbMapSize,
7270                                   PCI_DEV_MAP_FLAG_WRITABLE |
7271                                   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
7272                                   (void *)&pSiS->FbBase);
7273	if (err) {
7274            xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
7275                        "Unable to map FB aperture. %s (%d)\n",
7276                        strerror (err), err);
7277            return FALSE;
7278        }
7279	pSiS->RealFbBase = pSiS->FbBase;
7280#endif
7281	pSiS->FbBase += pSiS->dhmOffset;
7282
7283#ifdef SISDUALHEAD
7284    }
7285#endif
7286
7287    if(pSiS->FbBase == NULL) {
7288       SISErrorLog(pScrn, "Could not map framebuffer area\n");
7289       return FALSE;
7290    }
7291
7292#ifdef TWDEBUG
7293    xf86DrvMsg(0, 0, "Framebuffer mapped to %p\n", pSiS->FbBase);
7294#endif
7295
7296    return TRUE;
7297}
7298
7299
7300/*
7301 * Unmap the framebuffer and MMIO memory.
7302 */
7303
7304static Bool
7305SISUnmapMem(ScrnInfoPtr pScrn)
7306{
7307    SISPtr pSiS = SISPTR(pScrn);
7308#ifdef SISDUALHEAD
7309    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7310#endif
7311
7312/* In dual head mode, we must not unmap if the other head still
7313 * assumes memory as mapped
7314 */
7315#ifdef SISDUALHEAD
7316    if(pSiS->DualHeadMode) {
7317        if(pSiSEnt->MapCountIOBase) {
7318	    pSiSEnt->MapCountIOBase--;
7319	    if((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) {
7320		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7321		pSiSEnt->IOBase = NULL;
7322		pSiSEnt->MapCountIOBase = 0;
7323		pSiSEnt->forceUnmapIOBase = FALSE;
7324	    }
7325	    pSiS->IOBase = NULL;
7326	}
7327#ifdef __alpha__
7328	if(pSiSEnt->MapCountIOBaseDense) {
7329	    pSiSEnt->MapCountIOBaseDense--;
7330	    if((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) {
7331		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7332		pSiSEnt->IOBaseDense = NULL;
7333		pSiSEnt->MapCountIOBaseDense = 0;
7334		pSiSEnt->forceUnmapIOBaseDense = FALSE;
7335	    }
7336	    pSiS->IOBaseDense = NULL;
7337	}
7338#endif /* __alpha__ */
7339	if(pSiSEnt->MapCountFbBase) {
7340	    pSiSEnt->MapCountFbBase--;
7341	    if((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) {
7342		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7343		pSiSEnt->FbBase = pSiSEnt->RealFbBase = NULL;
7344		pSiSEnt->MapCountFbBase = 0;
7345		pSiSEnt->forceUnmapFbBase = FALSE;
7346
7347	    }
7348	    pSiS->FbBase = pSiS->RealFbBase = NULL;
7349	}
7350    } else {
7351#endif
7352	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7353	pSiS->IOBase = NULL;
7354#ifdef __alpha__
7355	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7356	pSiS->IOBaseDense = NULL;
7357#endif
7358	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7359	pSiS->FbBase = pSiS->RealFbBase = NULL;
7360#ifdef SISDUALHEAD
7361    }
7362#endif
7363    return TRUE;
7364}
7365
7366/*
7367 * This function saves the video state.
7368 */
7369static void
7370SISSave(ScrnInfoPtr pScrn)
7371{
7372    SISPtr pSiS = SISPTR(pScrn);
7373    SISRegPtr sisReg;
7374    int flags;
7375
7376#ifdef SISDUALHEAD
7377    /* We always save master & slave */
7378    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7379#endif
7380
7381    sisReg = &pSiS->SavedReg;
7382
7383    if( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
7384        ((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) ) {
7385       SiSVGASave(pScrn, sisReg, SISVGA_SR_CMAP | SISVGA_SR_MODE);
7386#ifdef SIS_PC_PLATFORM
7387       if(pSiS->VGAMemBase) {
7388          SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7389          SiSSetLVDSetc(pSiS->SiS_Pr, 0);
7390          SiS_GetVBType(pSiS->SiS_Pr);
7391          SiS_DisableBridge(pSiS->SiS_Pr);
7392          SiSVGASave(pScrn, sisReg, SISVGA_SR_FONTS);
7393          SiS_EnableBridge(pSiS->SiS_Pr);
7394       }
7395#endif
7396    } else {
7397       flags = SISVGA_SR_CMAP | SISVGA_SR_MODE;
7398#ifdef SIS_PC_PLATFORM
7399       if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7400#endif
7401       SiSVGASave(pScrn, sisReg, flags);
7402    }
7403
7404    sisSaveUnlockExtRegisterLock(pSiS, &sisReg->sisRegs3C4[0x05], &sisReg->sisRegs3D4[0x80]);
7405
7406    (*pSiS->SiSSave)(pScrn, sisReg);
7407
7408    if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE);
7409
7410    /* "Save" these again as they may have been changed prior to SISSave() call */
7411    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7412       sisReg->sisRegs3C4[0x1f] = pSiS->oldSR1F;
7413       sisReg->sisRegs3D4[0x17] = pSiS->oldCR17;
7414       sisReg->sisRegs3D4[0x32] = pSiS->oldCR32;
7415       sisReg->sisRegs3D4[0x36] = pSiS->oldCR36;
7416       sisReg->sisRegs3D4[0x37] = pSiS->oldCR37;
7417       if(pSiS->VGAEngine == SIS_315_VGA) {
7418	  sisReg->sisRegs3D4[pSiS->myCR63] = pSiS->oldCR63;
7419       }
7420    }
7421}
7422
7423/* VESASaveRestore taken from vesa driver */
7424static void
7425SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
7426{
7427    SISPtr pSiS = SISPTR(pScrn);
7428
7429    /* Query amount of memory to save state */
7430    if((function == MODE_QUERY) ||
7431       (function == MODE_SAVE && pSiS->state == NULL)) {
7432
7433       /* Make sure we save at least this information in case of failure */
7434       (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode);
7435       SiSVGASaveFonts(pScrn);
7436
7437       if(pSiS->vesamajor > 1) {
7438	  if(!VBESaveRestore(pSiS->pVbe, function, (pointer)&pSiS->state,
7439				&pSiS->stateSize, &pSiS->statePage)) {
7440	     return;
7441	  }
7442       }
7443    }
7444
7445    /* Save/Restore Super VGA state */
7446    if(function != MODE_QUERY) {
7447
7448       if(pSiS->vesamajor > 1) {
7449	  if(function == MODE_RESTORE) {
7450	     memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize);
7451	  }
7452
7453	  if(VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state,
7454			    &pSiS->stateSize,&pSiS->statePage) &&
7455	     (function == MODE_SAVE)) {
7456	     /* don't rely on the memory not being touched */
7457	     if(!pSiS->pstate) {
7458		pSiS->pstate = xalloc(pSiS->stateSize);
7459	     }
7460	     memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize);
7461	  }
7462       }
7463
7464       if(function == MODE_RESTORE) {
7465	  VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL);
7466	  SiSVGARestoreFonts(pScrn);
7467       }
7468
7469    }
7470}
7471
7472/*
7473 * Initialise a new mode.  This is currently done using the
7474 * "initialise struct, restore/write struct to HW" model for
7475 * the old chipsets (5597/530/6326). For newer chipsets,
7476 * we use our own mode switching code.
7477 */
7478
7479static Bool
7480SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
7481{
7482    SISPtr pSiS = SISPTR(pScrn);
7483    SISRegPtr sisReg;
7484#ifdef SISDUALHEAD
7485    SISEntPtr pSiSEnt = NULL;
7486#endif
7487
7488    andSISIDXREG(SISCR,0x11,0x7f);	/* Unlock CRTC registers */
7489
7490    SISModifyModeInfo(mode);		/* Quick check of the mode parameters */
7491
7492    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7493       SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7494    }
7495
7496    if(pSiS->UseVESA) {  /* With VESA: */
7497
7498#ifdef SISDUALHEAD
7499       /* No dual head mode when using VESA */
7500       if(pSiS->SecondHead) return TRUE;
7501#endif
7502
7503       pScrn->vtSema = TRUE;
7504
7505       /*
7506	* This order is required:
7507	* The video bridge needs to be adjusted before the
7508	* BIOS is run as the BIOS sets up CRT2 according to
7509	* these register settings.
7510	* After the BIOS is run, the bridges and turboqueue
7511	* registers need to be readjusted as the BIOS may
7512	* very probably have messed them up.
7513	*/
7514       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7515	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7516       }
7517       if(!SiSSetVESAMode(pScrn, mode)) {
7518	  SISErrorLog(pScrn, "SiSSetVESAMode() failed\n");
7519	  return FALSE;
7520       }
7521       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7522       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7523	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7524	  SiSPostSetMode(pScrn, &pSiS->ModeReg);
7525       }
7526#ifdef TWDEBUG
7527       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7528		   "REAL REGISTER CONTENTS AFTER SETMODE:\n");
7529#endif
7530       if(!(*pSiS->ModeInit)(pScrn, mode)) {
7531	  SISErrorLog(pScrn, "ModeInit() failed\n");
7532	  return FALSE;
7533       }
7534
7535       SiSVGAProtect(pScrn, TRUE);
7536       (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg);
7537       SiSVGAProtect(pScrn, FALSE);
7538
7539    } else { /* Without VESA: */
7540
7541#ifdef SISDUALHEAD
7542       if(pSiS->DualHeadMode) {
7543
7544	  if(!(*pSiS->ModeInit)(pScrn, mode)) {
7545	     SISErrorLog(pScrn, "ModeInit() failed\n");
7546	     return FALSE;
7547	  }
7548
7549	  pScrn->vtSema = TRUE;
7550
7551	  pSiSEnt = pSiS->entityPrivate;
7552
7553	  if(!(pSiS->SecondHead)) {
7554	     /* Head 1 (master) is always CRT2 */
7555	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7556	     if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7557		SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7558		return FALSE;
7559	     }
7560	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7561	     if(pSiSEnt->pScrn_2) {
7562		SISAdjustFrame(pSiSEnt->pScrn_2->scrnIndex,
7563			       pSiSEnt->pScrn_2->frameX0,
7564			       pSiSEnt->pScrn_2->frameY0, 0);
7565	     }
7566	  } else {
7567	     /* Head 2 (slave) is always CRT1 */
7568	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7569	     if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7570		SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7571		return FALSE;
7572	     }
7573	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7574	     if(pSiSEnt->pScrn_1) {
7575		SISAdjustFrame(pSiSEnt->pScrn_1->scrnIndex,
7576			       pSiSEnt->pScrn_1->frameX0,
7577			       pSiSEnt->pScrn_1->frameY0, 0);
7578	     }
7579	  }
7580
7581       } else {
7582#endif
7583
7584	  if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7585
7586	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7587		SISErrorLog(pScrn, "ModeInit() failed\n");
7588	        return FALSE;
7589	     }
7590
7591	     pScrn->vtSema = TRUE;
7592
7593#ifdef SISMERGED
7594	     if(pSiS->MergedFB) {
7595
7596		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting MergedFB mode %dx%d\n",
7597				mode->HDisplay, mode->VDisplay);
7598
7599		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7600
7601		if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7602		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
7603				       pSiS->IsCustom)) {
7604		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7605		   return FALSE;
7606		}
7607
7608		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7609
7610		if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7611		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
7612				       pSiS->IsCustom)) {
7613		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7614		   return FALSE;
7615		}
7616
7617	     } else {
7618#endif
7619
7620		if((pSiS->VBFlags & CRT1_LCDA) || (!(mode->type & M_T_DEFAULT))) {
7621
7622		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7623
7624		   if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7625				mode, pSiS->IsCustom)) {
7626		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7627		      return FALSE;
7628		   }
7629
7630		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7631
7632		   if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7633				mode, pSiS->IsCustom)) {
7634		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7635		      return FALSE;
7636		   }
7637
7638		} else {
7639
7640		   SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7641
7642		   if(!SiSBIOSSetMode(pSiS->SiS_Pr, pScrn,
7643				mode, pSiS->IsCustom)) {
7644		      SISErrorLog(pScrn, "SiSBIOSSetMode() failed\n");
7645		      return FALSE;
7646		   }
7647
7648		}
7649
7650#ifdef SISMERGED
7651	     }
7652#endif
7653
7654	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7655
7656#ifdef TWDEBUG
7657	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags %lx\n", pSiS->VBFlags);
7658	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7659			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7660             (*pSiS->ModeInit)(pScrn, mode);
7661#endif
7662
7663	  } else {
7664
7665	     /* For other chipsets, use the old method */
7666
7667	     /* Prepare the register contents */
7668	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7669	        SISErrorLog(pScrn, "ModeInit() failed\n");
7670	        return FALSE;
7671	     }
7672
7673	     pScrn->vtSema = TRUE;
7674
7675	     /* Program the registers */
7676	     SiSVGAProtect(pScrn, TRUE);
7677	     sisReg = &pSiS->ModeReg;
7678
7679	     sisReg->sisRegsATTR[0x10] = 0x01;
7680	     if(pScrn->bitsPerPixel > 8) {
7681		sisReg->sisRegsGR[0x05] = 0x00;
7682	     }
7683
7684	     SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
7685
7686	     (*pSiS->SiSRestore)(pScrn, sisReg);
7687
7688	     if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
7689	        SiS6326PostSetMode(pScrn, &pSiS->ModeReg);
7690	     }
7691
7692#ifdef TWDEBUG
7693	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7694			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7695	     (*pSiS->ModeInit)(pScrn, mode);
7696#endif
7697
7698	     SiSVGAProtect(pScrn, FALSE);
7699
7700	  }
7701
7702#ifdef SISDUALHEAD
7703       }
7704#endif
7705    }
7706
7707    /* Update Currentlayout */
7708    pSiS->CurrentLayout.mode = pSiS->currentModeLast = mode;
7709
7710    return TRUE;
7711}
7712
7713static Bool
7714SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
7715{
7716    SISPtr pSiS;
7717    int mode;
7718
7719    pSiS = SISPTR(pScrn);
7720
7721    if(!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE;
7722
7723    mode |= (1 << 15);	/* Don't clear framebuffer */
7724    mode |= (1 << 14); 	/* Use linear adressing */
7725
7726    if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) {
7727       SISErrorLog(pScrn, "Setting VESA mode 0x%x failed\n",
7728	             	mode & 0x0fff);
7729       return (FALSE);
7730    }
7731
7732    if(pMode->HDisplay != pScrn->virtualX) {
7733       VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX);
7734    }
7735
7736    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
7737    	"Setting VESA mode 0x%x succeeded\n",
7738	mode & 0x0fff);
7739
7740    return (TRUE);
7741}
7742
7743static void
7744SISSpecialRestore(ScrnInfoPtr pScrn)
7745{
7746    SISPtr    pSiS = SISPTR(pScrn);
7747    SISRegPtr sisReg = &pSiS->SavedReg;
7748    UChar temp;
7749    int i;
7750
7751    /* 1.11.04 and later for 651 and 301B(DH) do strange register
7752     * fiddling after the usual mode change. This happens
7753     * depending on the result of a call of int 2f (with
7754     * ax=0x1680) and if modeno <= 0x13. I have no idea if
7755     * that is specific for the 651 or that very machine.
7756     * So this perhaps requires some more checks in the beginning
7757     * (although it should not do any harm on other chipsets/bridges
7758     * etc.) However, even if I call the VBE to restore mode 0x03,
7759     * these registers don't get restored correctly, possibly
7760     * because that int-2f-call for some reason results non-zero. So
7761     * what I do here is to restore these few registers
7762     * manually.
7763     */
7764
7765    if(!(pSiS->ChipFlags & SiSCF_Is65x)) return;
7766    inSISIDXREG(SISCR, 0x34, temp);
7767    temp &= 0x7f;
7768    if(temp > 0x13) return;
7769
7770#ifdef UNLOCK_ALWAYS
7771    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7772#endif
7773
7774    SiS_UnLockCRT2(pSiS->SiS_Pr);
7775
7776    outSISIDXREG(SISCAP, 0x3f, sisReg->sisCapt[0x3f]);
7777    outSISIDXREG(SISCAP, 0x00, sisReg->sisCapt[0x00]);
7778    for(i = 0; i < 0x4f; i++) {
7779       outSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
7780    }
7781    outSISIDXREG(SISVID, 0x32, (sisReg->sisVid[0x32] & ~0x05));
7782    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7783    outSISIDXREG(SISVID, 0x32, ((sisReg->sisVid[0x32] & ~0x04) | 0x01));
7784    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7785
7786    if(!(pSiS->ChipFlags & SiSCF_Is651)) return;
7787    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
7788
7789    inSISIDXREG(SISCR, 0x30, temp);
7790    if(temp & 0x40) {
7791       UChar myregs[] = {
7792       		0x2f, 0x08, 0x09, 0x03, 0x0a, 0x0c,
7793		0x0b, 0x0d, 0x0e, 0x12, 0x0f, 0x10,
7794		0x11, 0x04, 0x05, 0x06, 0x07, 0x00,
7795		0x2e
7796       };
7797       for(i = 0; i <= 18; i++) {
7798          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7799       }
7800    } else if((temp & 0x20) || (temp & 0x9c)) {
7801       UChar myregs[] = {
7802       		0x04, 0x05, 0x06, 0x07, 0x00, 0x2e
7803       };
7804       for(i = 0; i <= 5; i++) {
7805          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7806       }
7807    }
7808}
7809
7810/* Fix SR11 for 661 and later */
7811static void
7812SiSFixupSR11(ScrnInfoPtr pScrn)
7813{
7814    SISPtr pSiS = SISPTR(pScrn);
7815    CARD8  tmpreg;
7816
7817#ifdef UNLOCK_ALWAYS
7818    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7819#endif
7820
7821    if(pSiS->ChipType >= SIS_661) {
7822       inSISIDXREG(SISSR,0x11,tmpreg);
7823       if(tmpreg & 0x20) {
7824          inSISIDXREG(SISSR,0x3e,tmpreg);
7825	  tmpreg = (tmpreg + 1) & 0xff;
7826	  outSISIDXREG(SISSR,0x3e,tmpreg);
7827       }
7828
7829       inSISIDXREG(SISSR,0x11,tmpreg);
7830       if(tmpreg & 0xf0) {
7831          andSISIDXREG(SISSR,0x11,0x0f);
7832       }
7833    }
7834}
7835
7836/* Subroutine for restoring sisfb's TV parameters (used by SiSRestore()) */
7837
7838static void
7839SiSRestore_SiSFB_TVParms(ScrnInfoPtr pScrn)
7840{
7841    SISPtr  pSiS = SISPTR(pScrn);
7842    int     fd;
7843    CARD32  parm;
7844
7845    if(!pSiS->sisfbfound) return;
7846    if(!pSiS->sisfb_tvposvalid) return;
7847    if(!(pSiS->sisfbdevname[0])) return;
7848
7849    if((fd = open(pSiS->sisfbdevname, O_RDONLY)) != -1) {
7850       parm = (CARD32)((pSiS->sisfb_tvxpos << 16) | (pSiS->sisfb_tvypos & 0xffff));
7851       ioctl(fd, SISFB_SET_TVPOSOFFSET, &parm);
7852       close(fd);
7853    }
7854}
7855
7856/*
7857 * Restore the initial mode. To be used internally only!
7858 */
7859static void
7860SISRestore(ScrnInfoPtr pScrn)
7861{
7862    SISPtr    pSiS = SISPTR(pScrn);
7863    SISRegPtr sisReg = &pSiS->SavedReg;
7864    Bool      doit = FALSE, doitlater = FALSE;
7865    Bool      vesasuccess = FALSE;
7866    int	      flags;
7867
7868    /* WARNING: Don't ever touch this. It now seems to work on
7869     * all chipset/bridge combinations - but finding out the
7870     * correct combination was pure hell.
7871     */
7872
7873    /* Wait for the accelerators */
7874    (*pSiS->SyncAccel)(pScrn);
7875
7876    /* Set up restore flags */
7877    flags = SISVGA_SR_MODE | SISVGA_SR_CMAP;
7878#ifdef SIS_PC_PLATFORM
7879    /* We now restore ALL to overcome the vga=extended problem */
7880    if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7881#endif
7882
7883    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7884
7885#ifdef SISDUALHEAD
7886       /* We always restore master AND slave */
7887       if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7888#endif
7889
7890#ifdef UNLOCK_ALWAYS
7891       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7892#endif
7893
7894       /* We must not disable the sequencer if the bridge is in SlaveMode! */
7895       if(!(SiSBridgeIsInSlaveMode(pScrn))) {
7896	  SiSVGAProtect(pScrn, TRUE);
7897       }
7898
7899       /* First, restore CRT1 on/off and VB connection registers */
7900       outSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
7901       if(!(pSiS->oldCR17 & 0x80)) {			/* CRT1 was off */
7902	  if(!(SiSBridgeIsInSlaveMode(pScrn))) {        /* Bridge is NOT in SlaveMode now -> do it */
7903	     doit = TRUE;
7904	  } else {
7905	     doitlater = TRUE;
7906	  }
7907       } else {						/* CRT1 was on -> do it now */
7908	  doit = TRUE;
7909       }
7910
7911       if(doit) {
7912	  outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
7913       }
7914       if(pSiS->VGAEngine == SIS_315_VGA) {
7915	  outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
7916       }
7917
7918       outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
7919
7920       /* For 30xB/LV, restoring the registers does not
7921	* work. We "manually" set the old mode, instead.
7922	* The same applies for SiS730 machines with LVDS.
7923	* Finally, this behavior can be forced by setting
7924	* the option RestoreBySetMode.
7925	*/
7926	if( ( (pSiS->restorebyset) ||
7927	      (pSiS->VBFlags2 & VB2_30xBLV) ||
7928	      ((pSiS->ChipType == SIS_730) && (pSiS->VBFlags2 & VB2_LVDS)) )     &&
7929	    (pSiS->OldMode) ) {
7930
7931	   Bool changedmode = FALSE;
7932
7933	   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7934	         "Restoring by setting old mode 0x%02x\n", pSiS->OldMode);
7935
7936	   if(((pSiS->OldMode <= 0x13) || (!pSiS->sisfbfound)) && (pSiS->pVbe)) {
7937	      int vmode = SiSTranslateToVESA(pScrn, pSiS->OldMode);
7938	      if(vmode > 0) {
7939		 if(vmode > 0x13) vmode |= ((1 << 15) | (1 << 14));
7940		 if(VBESetVBEMode(pSiS->pVbe, vmode, NULL) == TRUE) {
7941		    SISSpecialRestore(pScrn);
7942		    SiS_GetSetModeID(pScrn,pSiS->OldMode);
7943		    vesasuccess = TRUE;
7944		 } else {
7945		    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7946			"VBE failed to restore mode 0x%x\n", pSiS->OldMode);
7947		 }
7948	      } else {
7949		 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7950		 	"Can't identify VESA mode number for mode 0x%x\n", pSiS->OldMode);
7951	      }
7952	   }
7953
7954	   if(vesasuccess == FALSE) {
7955
7956	      int backupscaler = pSiS->SiS_Pr->UsePanelScaler;
7957	      int backupcenter = pSiS->SiS_Pr->CenterScreen;
7958	      ULong backupspecialtiming = pSiS->SiS_Pr->SiS_CustomT;
7959	      int mymode = pSiS->OldMode;
7960
7961	      if((pSiS->VGAEngine == SIS_315_VGA)			&&
7962	         ((pSiS->ROM661New) || (pSiS->ChipFlags & SiSCF_IsXGI)) &&
7963		 (!pSiS->sisfbfound)) {
7964	         /* New SiS BIOS or XGI BIOS has set mode, therefore eventually translate number */
7965	         mymode = SiSTranslateToOldMode(mymode);
7966	      }
7967
7968 	      if((pSiS->VBFlags2 & VB2_30xBLV)) {
7969	        /* !!! REQUIRED for 630+301B-DH, otherwise the text modes
7970	         *     will not be restored correctly !!!
7971	         * !!! Do this ONLY for LCD; VGA2 will not be restored
7972	         *     correctly otherwise.
7973	         */
7974	         UChar temp;
7975	         inSISIDXREG(SISCR, 0x30, temp);
7976	         if(temp & 0x20) {
7977	            if(mymode == 0x03) {
7978		       mymode = 0x13;
7979		       changedmode = TRUE;
7980	            }
7981	         }
7982	      }
7983
7984	      pSiS->SiS_Pr->UseCustomMode = FALSE;
7985	      pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
7986	      pSiS->SiS_Pr->CenterScreen = 0;
7987	      if(pSiS->sisfbfound) {
7988		 pSiS->SiS_Pr->UsePanelScaler = pSiS->sisfbscalelcd;
7989		 pSiS->SiS_Pr->SiS_CustomT = pSiS->sisfbspecialtiming;
7990	      } else {
7991		 pSiS->SiS_Pr->UsePanelScaler = -1;
7992		 /* Leave CustomT as it is */
7993	      }
7994	      SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
7995	      SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
7996	      if((pSiS->ChipType == SIS_550) && (pSiS->sisfbfound)) {
7997		 if(pSiS->sisfbxSTN) {
7998		    SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->sisfbDSTN);
7999		    SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->sisfbFSTN);
8000		 } else if(mymode == 0x5a || mymode == 0x5b) {
8001		    SiS_SetEnableFstn(pSiS->SiS_Pr, TRUE);
8002		 }
8003	      }
8004	      SiSSetMode(pSiS->SiS_Pr, pScrn, mymode, FALSE);
8005	      if(changedmode) {
8006		 outSISIDXREG(SISCR,0x34,0x03);
8007	      }
8008	      SISSpecialRestore(pScrn);
8009	      SiS_GetSetModeID(pScrn, pSiS->OldMode); /* NOT mymode! */
8010	      pSiS->SiS_Pr->UsePanelScaler = backupscaler;
8011	      pSiS->SiS_Pr->CenterScreen = backupcenter;
8012	      pSiS->SiS_Pr->SiS_CustomT = backupspecialtiming;
8013	      SiS_SiSFB_Lock(pScrn, FALSE);
8014	      SiSRestore_SiSFB_TVParms(pScrn);
8015	      SiS_SiSFB_Lock(pScrn, TRUE);
8016
8017	   }
8018
8019	   /* Restore CRT1 status */
8020	   if(pSiS->VGAEngine == SIS_315_VGA) {
8021              outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
8022           }
8023           outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
8024
8025#ifdef SISVRAMQ
8026	   /* Restore queue mode registers on 315/330/340 series */
8027	   /* (This became necessary due to the switch to VRAM queue) */
8028	   SiSRestoreQueueMode(pSiS, sisReg);
8029#endif
8030
8031        } else {
8032
8033	   if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
8034	      /* If a video bridge is present, we need to restore
8035	       * non-extended (=standard VGA) SR and CR registers
8036	       * before restoring the extended ones and the bridge
8037	       * registers.
8038	       */
8039	      if(!(SiSBridgeIsInSlaveMode(pScrn))) {
8040                 SiSVGAProtect(pScrn, TRUE);
8041	         SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
8042              }
8043	   }
8044
8045           (*pSiS->SiSRestore)(pScrn, sisReg);
8046
8047        }
8048
8049	if(doitlater) {
8050           outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
8051	}
8052
8053
8054
8055	if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) {
8056
8057	   /* IMPORTANT: The 30xLV does not handle well being disabled if in
8058	    * LCDA mode! In LCDA mode, the bridge is NOT in slave mode,
8059	    * so this is the only safe way: Disable the bridge ONLY if
8060	    * in Slave Mode, and don't bother if not.
8061	    */
8062
8063	   if(flags & SISVGA_SR_FONTS) {
8064              SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
8065	      SiSSetLVDSetc(pSiS->SiS_Pr, 0);
8066	      SiS_GetVBType(pSiS->SiS_Pr);
8067	      SiS_DisableBridge(pSiS->SiS_Pr);
8068	      SiSVGAProtect(pScrn, TRUE);
8069	   }
8070
8071	   SiSVGARestore(pScrn, sisReg, flags);
8072
8073	   if(flags & SISVGA_SR_FONTS) {
8074	      SiSVGAProtect(pScrn, FALSE);
8075	      SiS_EnableBridge(pSiS->SiS_Pr);
8076	      andSISIDXREG(SISSR, 0x01, ~0x20);  /* Display on */
8077	   }
8078
8079	} else {
8080
8081	   SiSVGAProtect(pScrn, TRUE);
8082	   SiSVGARestore(pScrn, sisReg, flags);
8083           SiSVGAProtect(pScrn, FALSE);
8084
8085	}
8086
8087	SiSFixupSR11(pScrn);
8088
8089#ifdef TWDEBUG
8090	{
8091	  SISRegPtr pReg = &pSiS->ModeReg;
8092	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8093		"REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n");
8094	  (*pSiS->SiSSave)(pScrn, pReg);
8095	}
8096#endif
8097
8098	sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]);
8099
8100    } else {	/* All other chipsets */
8101
8102        SiSVGAProtect(pScrn, TRUE);
8103
8104#ifdef UNLOCK_ALWAYS
8105        sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8106#endif
8107
8108        (*pSiS->SiSRestore)(pScrn, sisReg);
8109
8110        SiSVGAProtect(pScrn, TRUE);
8111
8112	SiSVGARestore(pScrn, sisReg, flags);
8113
8114	/* Restore TV. This is rather complicated, but if we don't do it,
8115	 * TV output will flicker terribly
8116	 */
8117        if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
8118	   if(sisReg->sis6326tv[0] & 0x04) {
8119	      UChar tmp;
8120	      int val;
8121
8122              orSISIDXREG(SISSR, 0x01, 0x20);
8123              tmp = SiS6326GetTVReg(pScrn,0x00);
8124              tmp &= ~0x04;
8125              while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8126              SiS6326SetTVReg(pScrn,0x00,tmp);
8127              for(val=0; val < 2; val++) {
8128                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8129                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8130              }
8131              SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
8132              tmp = inSISREG(SISINPSTAT);
8133              outSISREG(SISAR, 0x20);
8134              tmp = inSISREG(SISINPSTAT);
8135              while(inSISREG(SISINPSTAT) & 0x01);
8136              while(!(inSISREG(SISINPSTAT) & 0x01));
8137              andSISIDXREG(SISSR, 0x01, ~0x20);
8138              for(val=0; val < 10; val++) {
8139                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8140                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8141              }
8142              andSISIDXREG(SISSR, 0x01, ~0x20);
8143	   }
8144        }
8145
8146        sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]);
8147
8148        SiSVGAProtect(pScrn, FALSE);
8149    }
8150}
8151
8152static void
8153SISVESARestore(ScrnInfoPtr pScrn)
8154{
8155   SISPtr pSiS = SISPTR(pScrn);
8156#ifdef SISVRAMQ
8157   SISRegPtr sisReg = &pSiS->SavedReg;
8158#endif
8159
8160   if(pSiS->UseVESA) {
8161      SISVESASaveRestore(pScrn, MODE_RESTORE);
8162#ifdef SISVRAMQ
8163      /* Restore queue mode registers on 315/330/340 series */
8164      /* (This became necessary due to the switch to VRAM queue) */
8165      SiSRestoreQueueMode(pSiS, sisReg);
8166#endif
8167   }
8168}
8169
8170/* Restore bridge config registers - to be called BEFORE VESARestore */
8171static void
8172SISBridgeRestore(ScrnInfoPtr pScrn)
8173{
8174    SISPtr pSiS = SISPTR(pScrn);
8175
8176#ifdef SISDUALHEAD
8177    /* We only restore for master head */
8178    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
8179#endif
8180
8181    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
8182	SiSRestoreBridge(pScrn, &pSiS->SavedReg);
8183    }
8184}
8185
8186/* Our BlockHandler */
8187static void
8188SISBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
8189{
8190    ScreenPtr pScreen = screenInfo.screens[i];
8191    ScrnInfoPtr pScrn = xf86Screens[i];
8192    SISPtr pSiS = SISPTR(pScrn);
8193
8194    pScreen->BlockHandler = pSiS->BlockHandler;
8195    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
8196    pScreen->BlockHandler = SISBlockHandler;
8197
8198#ifdef SISDUALHEAD
8199    if(pSiS->NeedCopyFastVidCpy) {
8200       SISEntPtr pSiSEnt = pSiS->entityPrivate;
8201       if(pSiSEnt->HaveFastVidCpy) {
8202	  pSiS->NeedCopyFastVidCpy = FALSE;
8203	  pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8204	  pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8205	  pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8206	  pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8207       }
8208    }
8209#endif
8210
8211    if(pSiS->VideoTimerCallback) {
8212       (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds);
8213    }
8214
8215#ifdef SIS_USE_XAA
8216    if(pSiS->RenderCallback) {
8217       (*pSiS->RenderCallback)(pScrn);
8218    }
8219#endif
8220#ifdef SIS_USE_EXA
8221    if(pSiS->ExaRenderCallback) {
8222       (*pSiS->ExaRenderCallback)(pScrn);
8223    }
8224#endif
8225}
8226
8227
8228
8229/* Do screen blanking; DPMS handling
8230 *
8231 * Mandatory; latter optional
8232 */
8233
8234static void
8235SiSHandleBackLight(SISPtr pSiS, Bool blon)
8236{
8237    UChar sr11mask = (pSiS->SiS_Pr->SiS_SensibleSR11) ? 0x03 : 0xf3;
8238
8239    if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
8240
8241       if(!blon) {
8242	  SiS_SiS30xBLOff(pSiS->SiS_Pr);
8243       } else {
8244	  SiS_SiS30xBLOn(pSiS->SiS_Pr);
8245       }
8246
8247    } else if( ((pSiS->VGAEngine == SIS_300_VGA) &&
8248	        (pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH))) ||
8249	       ((pSiS->VGAEngine == SIS_315_VGA) &&
8250	        ((pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS)) ) {
8251
8252       if(!blon) {
8253	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x08);
8254       } else {
8255	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x00);
8256       }
8257
8258    } else if((pSiS->VGAEngine == SIS_315_VGA) &&
8259	      (pSiS->VBFlags2 & VB2_CHRONTEL)) {
8260
8261       if(!blon) {
8262	  SiS_Chrontel701xBLOff(pSiS->SiS_Pr);
8263       } else {
8264	  SiS_Chrontel701xBLOn(pSiS->SiS_Pr);
8265       }
8266
8267    }
8268}
8269
8270static Bool
8271SISSaveScreen(ScreenPtr pScreen, int mode)
8272{
8273    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8274    SISPtr pSiS;
8275    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8276
8277    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8278
8279    pSiS = SISPTR(pScrn);
8280
8281#ifdef UNLOCK_ALWAYS
8282    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8283#endif
8284
8285    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
8286       SiSHandleBackLight(pSiS, IsUnblank);
8287    }
8288
8289    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8290       return SiSVGASaveScreen(pScreen, mode);
8291    }
8292
8293    return TRUE;
8294}
8295
8296#ifdef SISDUALHEAD
8297/* SaveScreen for dual head mode */
8298static Bool
8299SISSaveScreenDH(ScreenPtr pScreen, int mode)
8300{
8301    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8302    SISPtr pSiS;
8303    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8304
8305    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8306
8307    pSiS = SISPTR(pScrn);
8308
8309    if( (pSiS->SecondHead) &&
8310        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8311
8312       /* Slave head is always CRT1 */
8313       /* (No backlight handling on TMDS bridges) */
8314       return SiSVGASaveScreen(pScreen, mode);
8315
8316    } else {
8317
8318       /* Master head is always CRT2 */
8319       /* But we land here for LCDA, too (if bridge is SiS LVDS type) */
8320
8321       /* We can only blank LCD, not other CRT2 devices */
8322       if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA)) {
8323
8324#ifdef UNLOCK_ALWAYS
8325	  sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8326#endif
8327	  SiSHandleBackLight(pSiS, IsUnblank);
8328
8329       }
8330
8331    }
8332    return TRUE;
8333}
8334#endif
8335
8336static void
8337SISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
8338{
8339    SISPtr pSiS = SISPTR(pScrn);
8340    Bool   docrt1 = TRUE, docrt2 = TRUE, backlight = TRUE;
8341    UChar  sr1=0, cr17=0, cr63=0, pmreg=0, sr7=0;
8342    UChar  p1_13=0, p2_0=0, oldpmreg=0;
8343
8344    if(!pScrn->vtSema) return;
8345
8346    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
8347          "SISDisplayPowerManagementSet(%d)\n", PowerManagementMode);
8348
8349#ifdef SISDUALHEAD
8350    if(pSiS->DualHeadMode) {
8351       if(pSiS->SecondHead) docrt2 = FALSE;
8352       else                 docrt1 = FALSE;
8353    }
8354#endif
8355
8356    /* FIXME: in old servers, DPMSSet was supposed to be called without open
8357     * the correct PCI bridges before access the hardware. Now we have this
8358     * hook wrapped by the vga arbiter which should do all the work, in
8359     * kernels that implement it. For this case we might not want this hack
8360     * bellow.
8361     */
8362    outSISIDXREG(SISSR,0x05,0x86);
8363    inSISIDXREG(SISSR,0x05,pmreg);
8364    if(pmreg != 0xa1) return;
8365
8366#ifdef UNLOCK_ALWAYS
8367    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8368#endif
8369
8370    switch(PowerManagementMode) {
8371
8372       case DPMSModeOn:      /* HSync: On, VSync: On */
8373	  sr1   = 0x00;
8374	  cr17  = 0x80;
8375	  pmreg = 0x00;
8376	  cr63  = 0x00;
8377	  sr7   = 0x10;
8378	  p2_0  = 0x20;
8379	  p1_13 = 0x00;
8380	  backlight = TRUE;
8381	  break;
8382
8383       case DPMSModeSuspend: /* HSync: On, VSync: Off */
8384	  sr1   = 0x20;
8385	  cr17  = 0x80;
8386	  pmreg = 0x80;
8387	  cr63  = 0x40;
8388	  sr7   = 0x00;
8389	  p2_0  = 0x40;
8390	  p1_13 = 0x80;
8391	  backlight = FALSE;
8392	  break;
8393
8394       case DPMSModeStandby: /* HSync: Off, VSync: On */
8395	  sr1   = 0x20;
8396	  cr17  = 0x80;
8397	  pmreg = 0x40;
8398	  cr63  = 0x40;
8399	  sr7   = 0x00;
8400	  p2_0  = 0x80;
8401	  p1_13 = 0x40;
8402	  backlight = FALSE;
8403	  break;
8404
8405       case DPMSModeOff:     /* HSync: Off, VSync: Off */
8406	  sr1   = 0x20;
8407	  cr17  = 0x00;
8408	  pmreg = 0xc0;
8409	  cr63  = 0x40;
8410	  sr7   = 0x00;
8411	  p2_0  = 0xc0;
8412	  p1_13 = 0xc0;
8413	  backlight = FALSE;
8414	  break;
8415
8416       default:
8417	    return;
8418    }
8419
8420    oldpmreg = pmreg;
8421
8422    if((docrt2 && (pSiS->VBFlags & CRT2_LCD)) ||
8423       (docrt1 && (pSiS->VBFlags & CRT1_LCDA))) {
8424       SiSHandleBackLight(pSiS, backlight);
8425    }
8426
8427    if(docrt1) {
8428       switch(pSiS->VGAEngine) {
8429       case SIS_OLD_VGA:
8430       case SIS_530_VGA:
8431	    setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8432	    inSISIDXREG(SISSR, 0x11, oldpmreg);
8433	    setSISIDXREG(SISCR, 0x17, 0x7f, cr17);
8434	    setSISIDXREG(SISSR, 0x11, 0x3f, pmreg);
8435	    break;
8436       case SIS_315_VGA:
8437	    if( (!pSiS->CRT1off) &&
8438	        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8439	       setSISIDXREG(SISCR, pSiS->myCR63, 0xbf, cr63);
8440	       setSISIDXREG(SISSR, 0x07, 0xef, sr7);
8441	    }
8442	    /* fall through */
8443       default:
8444	    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8445	       setSISIDXREG(SISSR, 0x01, ~0x20, sr1);    /* Set/Clear "Display On" bit */
8446	    }
8447	    if((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
8448	       inSISIDXREG(SISSR, 0x1f, oldpmreg);
8449	       if((!pSiS->CRT1off) && (!SiSBridgeIsInSlaveMode(pScrn))) {
8450		  setSISIDXREG(SISSR, 0x1f, 0x3f, pmreg);
8451	       }
8452	    }
8453       }
8454       oldpmreg &= 0xc0;
8455    }
8456
8457    if(docrt2) {
8458       if(pSiS->VBFlags & CRT2_LCD) {
8459          if((pSiS->VBFlags2 & VB2_SISBRIDGE) &&
8460	     (!(pSiS->VBFlags2 & VB2_30xBDH))) {
8461	     if(pSiS->VGAEngine == SIS_300_VGA) {
8462	        SiS_UnLockCRT2(pSiS->SiS_Pr);
8463	        setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
8464	     }
8465	     if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) p2_0 |= 0x20;
8466	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8467	  }
8468       } else if(pSiS->VBFlags & (CRT2_VGA | CRT2_TV)) {
8469	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
8470	     setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
8471	  }
8472       }
8473    }
8474
8475    if( (docrt1) &&
8476        (pmreg != oldpmreg) &&
8477        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8478       outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
8479       usleep(10000);
8480       outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
8481    }
8482
8483}
8484
8485/* Mandatory
8486 * This gets called at the start of each server generation
8487 *
8488 * We use pScrn and not CurrentLayout here, because the
8489 * properties we use have not changed (displayWidth,
8490 * depth, bitsPerPixel)
8491 */
8492static Bool
8493SISScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
8494{
8495    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8496    SISPtr pSiS = SISPTR(pScrn);
8497    VisualPtr visual;
8498    ULong OnScreenSize;
8499    int ret, height, width, displayWidth;
8500    UChar *FBStart;
8501#ifdef SISDUALHEAD
8502    SISEntPtr pSiSEnt = NULL;
8503#endif
8504
8505#ifdef SISDUALHEAD
8506    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
8507#endif
8508       SiS_LoadInitVBE(pScrn);
8509#ifdef SISDUALHEAD
8510    }
8511#endif
8512
8513#ifdef SISDUALHEAD
8514    if(pSiS->DualHeadMode) {
8515       pSiSEnt = pSiS->entityPrivate;
8516       pSiSEnt->refCount++;
8517    }
8518#endif
8519
8520#ifdef SIS_PC_PLATFORM
8521    /* Map 64k VGA window for saving/restoring CGA fonts */
8522    SiS_MapVGAMem(pScrn);
8523#endif
8524
8525    /* Map the SiS memory and MMIO areas */
8526    if(!SISMapMem(pScrn)) {
8527       SISErrorLog(pScrn, "SiSMapMem() failed\n");
8528       return FALSE;
8529    }
8530
8531    SiS_SiSFB_Lock(pScrn, TRUE);
8532
8533#ifdef UNLOCK_ALWAYS
8534    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8535#endif
8536
8537    /* Enable TurboQueue so that SISSave() saves it in enabled
8538     * state. If we don't do this, X will hang after a restart!
8539     * (Happens for some unknown reason only when using VESA
8540     * for mode switching; assumingly a BIOS issue.)
8541     * This is done on 300 and 315 series only.
8542     */
8543    if(pSiS->UseVESA) {
8544#ifdef SISVRAMQ
8545       if(pSiS->VGAEngine != SIS_315_VGA)
8546#endif
8547          SiSEnableTurboQueue(pScrn);
8548    }
8549
8550    /* Save the current state */
8551    SISSave(pScrn);
8552
8553    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8554
8555       if(!pSiS->OldMode) {
8556
8557          /* Try to find out current (=old) mode number
8558	   * (Do this only if not sisfb has told us its mode yet)
8559	   */
8560
8561	  /* Read 0:449 which the BIOS sets to the current mode number
8562	   * Unfortunately, this not reliable since the int10 emulation
8563	   * does not change this. So if we call the VBE later, this
8564	   * byte won't be touched (which is why we set this manually
8565	   * then).
8566	   */
8567          UChar myoldmode = SiS_GetSetModeID(pScrn, 0xFF);
8568	  UChar cr30, cr31;
8569
8570          /* Read CR34 which the BIOS sets to the current mode number for CRT2
8571	   * This is - of course - not reliable if the machine has no video
8572	   * bridge...
8573	   */
8574          inSISIDXREG(SISCR, 0x34, pSiS->OldMode);
8575	  inSISIDXREG(SISCR, 0x30, cr30);
8576	  inSISIDXREG(SISCR, 0x31, cr31);
8577
8578	  /* What if CR34 is different from the BIOS scratch byte? */
8579	  if(pSiS->OldMode != myoldmode) {
8580	     /* If no bridge output is active, trust the BIOS scratch byte */
8581	     if( (!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) ||
8582	         (pSiS->OldMode == 0)                  ||
8583	         (!cr31 && !cr30)                      ||
8584		 (cr31 & 0x20) ) {
8585		pSiS->OldMode = myoldmode;
8586 	     }
8587	     /* ..else trust CR34 */
8588	  }
8589
8590	  /* Newer 650 BIOSes set CR34 to 0xff if the mode has been
8591	   * "patched", for instance for 80x50 text mode. (That mode
8592	   * has no number of its own, it's 0x03 like 80x25). In this
8593	   * case, we trust the BIOS scratch byte (provided that any
8594	   * of these two is valid).
8595	   */
8596	  if(pSiS->OldMode > 0x7f) {
8597	     pSiS->OldMode = myoldmode;
8598	  }
8599       }
8600#ifdef SISDUALHEAD
8601       if(pSiS->DualHeadMode) {
8602          if(!pSiS->SecondHead) pSiSEnt->OldMode = pSiS->OldMode;
8603          else                  pSiS->OldMode = pSiSEnt->OldMode;
8604       }
8605#endif
8606    }
8607
8608    /* RandR resets screen mode and size in CloseScreen(), hence
8609     * we need to adapt our VBFlags to the initial state if the
8610     * current mode has changed since closescreen() (or Screeninit()
8611     * for the first instance)
8612     */
8613    if(pScrn->currentMode != pSiS->currentModeLast) {
8614       pSiS->VBFlags = pSiS->VBFlags_backup = pSiS->VBFlagsInit;
8615    }
8616
8617    /* Copy our detected monitor gammas, part 2. Note that device redetection
8618     * is not supported in DHM, so there is no need to do that anytime later.
8619     */
8620#ifdef SISDUALHEAD
8621    if(pSiS->DualHeadMode) {
8622       if(!pSiS->SecondHead) {
8623          /* CRT2 */
8624	  pSiS->CRT1VGAMonitorGamma = pSiSEnt->CRT1VGAMonitorGamma;
8625       } else {
8626          /* CRT1 */
8627	  pSiS->CRT2VGAMonitorGamma = pSiSEnt->CRT2VGAMonitorGamma;
8628       }
8629       if(!pSiS->CRT2LCDMonitorGamma) pSiS->CRT2LCDMonitorGamma = pSiSEnt->CRT2LCDMonitorGamma;
8630    }
8631#endif
8632
8633    /* Initialize the first mode */
8634    if(!SISModeInit(pScrn, pScrn->currentMode)) {
8635       SISErrorLog(pScrn, "SiSModeInit() failed\n");
8636       return FALSE;
8637    }
8638
8639    /* Darken the screen for aesthetic reasons */
8640    /* Not using Dual Head variant on purpose; we darken
8641     * the screen for both displays, and un-darken
8642     * it when the second head is finished
8643     */
8644    SISSaveScreen(pScreen, SCREEN_SAVER_ON);
8645
8646    /* Set the viewport */
8647    SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
8648
8649    /* Reset visual list. */
8650    miClearVisualTypes();
8651
8652    /* Setup the visuals we support. */
8653
8654    /*
8655     * For bpp > 8, the default visuals are not acceptable because we only
8656     * support TrueColor and not DirectColor.
8657     */
8658    if(!miSetVisualTypes(pScrn->depth,
8659			 (pScrn->bitsPerPixel > 8) ?
8660				TrueColorMask : miGetDefaultVisualMask(pScrn->depth),
8661			 pScrn->rgbBits, pScrn->defaultVisual)) {
8662       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8663       SISErrorLog(pScrn, "miSetVisualTypes() failed (bpp %d)\n",
8664			pScrn->bitsPerPixel);
8665       return FALSE;
8666    }
8667
8668    width = pScrn->virtualX;
8669    height = pScrn->virtualY;
8670    displayWidth = pScrn->displayWidth;
8671
8672    if(pSiS->Rotate) {
8673       height = pScrn->virtualX;
8674       width = pScrn->virtualY;
8675    }
8676
8677    if(pSiS->ShadowFB) {
8678       pSiS->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
8679       pSiS->ShadowPtr = xalloc(pSiS->ShadowPitch * height);
8680       displayWidth = pSiS->ShadowPitch / (pScrn->bitsPerPixel >> 3);
8681       FBStart = pSiS->ShadowPtr;
8682    } else {
8683       pSiS->ShadowPtr = NULL;
8684       FBStart = pSiS->FbBase;
8685    }
8686
8687    if(!miSetPixmapDepths()) {
8688       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8689       SISErrorLog(pScrn, "miSetPixmapDepths() failed\n");
8690       return FALSE;
8691    }
8692
8693    /* Point cmdQueuePtr to pSiSEnt for shared usage
8694     * (same technique is then eventually used in DRIScreeninit)
8695     * For 315/330 series, this is done in EnableTurboQueue
8696     * which has already been called during ModeInit().
8697     */
8698#ifdef SISDUALHEAD
8699    if(pSiS->SecondHead)
8700       pSiS->cmdQueueLenPtr = &(SISPTR(pSiSEnt->pScrn_1)->cmdQueueLen);
8701    else
8702#endif
8703       pSiS->cmdQueueLenPtr = &(pSiS->cmdQueueLen);
8704
8705    pSiS->cmdQueueLen = 0; /* Force an EngineIdle() at start */
8706
8707#ifdef XF86DRI
8708    if(pSiS->loadDRI) {
8709#ifdef SISDUALHEAD
8710       /* No DRI in dual head mode */
8711       if(pSiS->DualHeadMode) {
8712	  pSiS->directRenderingEnabled = FALSE;
8713	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8714		"DRI not supported in Dual Head mode\n");
8715       } else
8716#endif
8717	      if(pSiS->VGAEngine != SIS_315_VGA) {
8718	  /* Force the initialization of the context */
8719	  pSiS->directRenderingEnabled = SISDRIScreenInit(pScreen);
8720       } else {
8721	  xf86DrvMsg(pScrn->scrnIndex, X_NOT_IMPLEMENTED,
8722		"DRI not supported on this chipset\n");
8723	  pSiS->directRenderingEnabled = FALSE;
8724       }
8725    }
8726#endif
8727
8728    /* Call the framebuffer layer's ScreenInit function and fill in other
8729     * pScreen fields.
8730     */
8731    switch(pScrn->bitsPerPixel) {
8732       case 24:
8733	  if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
8734	     ret = FALSE;
8735	     break;
8736	  }
8737	  /* fall through */
8738       case 8:
8739       case 16:
8740       case 32:
8741	  ret = fbScreenInit(pScreen, FBStart, width,
8742			height, pScrn->xDpi, pScrn->yDpi,
8743			displayWidth, pScrn->bitsPerPixel);
8744	  break;
8745       default:
8746	  ret = FALSE;
8747	  break;
8748    }
8749    if(!ret) {
8750       SISErrorLog(pScrn, "Unsupported bpp (%d) or fbScreenInit() failed\n",
8751			pScrn->bitsPerPixel);
8752       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8753       return FALSE;
8754    }
8755
8756    /* Fixup RGB ordering */
8757    if(pScrn->bitsPerPixel > 8) {
8758       visual = pScreen->visuals + pScreen->numVisuals;
8759       while (--visual >= pScreen->visuals) {
8760          if((visual->class | DynamicClass) == DirectColor) {
8761             visual->offsetRed = pScrn->offset.red;
8762             visual->offsetGreen = pScrn->offset.green;
8763             visual->offsetBlue = pScrn->offset.blue;
8764             visual->redMask = pScrn->mask.red;
8765             visual->greenMask = pScrn->mask.green;
8766             visual->blueMask = pScrn->mask.blue;
8767          }
8768       }
8769    }
8770
8771    /* Initialize RENDER extension (must be after RGB ordering fixed) */
8772    fbPictureInit(pScreen, 0, 0);
8773
8774    /* Hardware cursor needs to wrap this layer */
8775    if(!pSiS->ShadowFB) SISDGAInit(pScreen);
8776
8777    xf86SetBlackWhitePixels(pScreen);
8778
8779    /* Initialize the accelerators */
8780    switch(pSiS->VGAEngine) {
8781    case SIS_530_VGA:
8782    case SIS_300_VGA:
8783       SiS300AccelInit(pScreen);
8784       break;
8785    case SIS_315_VGA:
8786       SiS315AccelInit(pScreen);
8787       break;
8788    default:
8789       SiSAccelInit(pScreen);
8790    }
8791
8792#ifdef TWDEBUG
8793    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CPUFlags %x\n", pSiS->CPUFlags);
8794#endif
8795
8796    /* Benchmark memcpy() methods (needs FB manager initialized) */
8797    /* Dual head: Do this AFTER the mode for CRT1 has been set */
8798    pSiS->NeedCopyFastVidCpy = FALSE;
8799    if(!pSiS->SiSFastVidCopyDone) {
8800#ifdef SISDUALHEAD
8801       if(pSiS->DualHeadMode) {
8802	  if(pSiS->SecondHead) {
8803	     pSiSEnt->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopy, FALSE);
8804	     pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8805	     pSiSEnt->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8806#ifdef SIS_USE_EXA
8807	     if(pSiS->useEXA) {
8808	        pSiSEnt->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiSEnt->SiSFastMemCopyFrom, TRUE);
8809	     }
8810#endif /* EXA */
8811	     pSiSEnt->HaveFastVidCpy = TRUE;
8812	     pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8813	     pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8814	     pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8815	     pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8816	  } else {
8817	     pSiS->NeedCopyFastVidCpy = TRUE;
8818	  }
8819       } else {
8820#endif
8821	  pSiS->SiSFastVidCopy = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopy, FALSE);
8822	  pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
8823	  pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
8824#ifdef SIS_USE_EXA
8825	  if(pSiS->useEXA) {
8826	     pSiS->SiSFastVidCopyFrom = SiSVidCopyInit(pScreen, &pSiS->SiSFastMemCopyFrom, TRUE);
8827	  }
8828#endif /* EXA */
8829#ifdef SISDUALHEAD
8830       }
8831#endif
8832    }
8833    pSiS->SiSFastVidCopyDone = TRUE;
8834
8835    miInitializeBackingStore(pScreen);
8836    xf86SetBackingStore(pScreen);
8837    xf86SetSilkenMouse(pScreen);
8838
8839    /* Initialise cursor functions */
8840    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
8841
8842    if(pSiS->HWCursor) {
8843       SiSHWCursorInit(pScreen);
8844    }
8845
8846#ifdef SISDUALHEAD
8847    if(!pSiS->DualHeadMode) {
8848#endif
8849       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pScrn->depth > 8)) {
8850
8851	  pSiS->CRT2ColNum = 1 << pScrn->rgbBits;
8852
8853	  if((pSiS->crt2gcolortable = xalloc(pSiS->CRT2ColNum * 2 * sizeof(LOCO)))) {
8854	     pSiS->crt2colors = &pSiS->crt2gcolortable[pSiS->CRT2ColNum];
8855	     if((pSiS->crt2cindices = xalloc(256 * sizeof(int)))) {
8856		int i = pSiS->CRT2ColNum;
8857		SISCalculateGammaRampCRT2(pScrn);
8858		while(i--) pSiS->crt2cindices[i] = i;
8859	     } else {
8860		xfree(pSiS->crt2gcolortable);
8861		pSiS->crt2gcolortable = NULL;
8862		pSiS->CRT2SepGamma = FALSE;
8863	     }
8864	  } else {
8865	     pSiS->CRT2SepGamma = FALSE;
8866	  }
8867
8868	  if(!pSiS->crt2cindices) {
8869	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
8870	  	"Failed to allocate cmap for CRT2, separate gamma correction disabled\n");
8871	  }
8872
8873       }
8874#ifdef SISDUALHEAD
8875    } else pSiS->CRT2SepGamma = FALSE;
8876#endif
8877
8878    /* Initialise default colormap */
8879    if(!miCreateDefColormap(pScreen)) {
8880       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8881       SISErrorLog(pScrn, "miCreateDefColormap() failed\n");
8882       return FALSE;
8883    }
8884
8885    if(!xf86HandleColormaps(pScreen, 256, (pScrn->depth == 8) ? 8 : pScrn->rgbBits,
8886                    SISLoadPalette, NULL,
8887                    CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) {
8888       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
8889       SISErrorLog(pScrn, "xf86HandleColormaps() failed\n");
8890       return FALSE;
8891    }
8892
8893    /* Recalculate our gamma ramp for brightness feature */
8894#ifdef SISGAMMARAMP
8895    if((pSiS->GammaBriR != 1000) ||
8896       (pSiS->GammaBriB != 1000) ||
8897       (pSiS->GammaBriG != 1000) ||
8898       (pSiS->NewGammaBriR != 0.0) ||
8899       (pSiS->NewGammaBriG != 0.0) ||
8900       (pSiS->NewGammaBriB != 0.0) ||
8901       (pSiS->NewGammaConR != 0.0) ||
8902       (pSiS->NewGammaConG != 0.0) ||
8903       (pSiS->NewGammaConB != 0.0)) {
8904       SISCalculateGammaRamp(pScreen, pScrn);
8905    }
8906#endif
8907
8908    /* Initialize Shadow framebuffer and screen rotation/reflection */
8909    if(pSiS->ShadowFB) {
8910       RefreshAreaFuncPtr refreshArea = SISRefreshArea;
8911
8912       if(pSiS->Rotate) {
8913	  if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8914	  pScrn->PointerMoved = SISPointerMoved;
8915	  switch(pScrn->bitsPerPixel) {
8916	     case 8:  refreshArea = SISRefreshArea8;  break;
8917	     case 16: refreshArea = SISRefreshArea16; break;
8918	     case 24: refreshArea = SISRefreshArea24; break;
8919	     case 32: refreshArea = SISRefreshArea32; break;
8920	  }
8921#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8922	  xf86DisableRandR();
8923	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8924		"Driver rotation enabled, disabling RandR\n");
8925#endif
8926       } else if(pSiS->Reflect) {
8927          switch(pScrn->bitsPerPixel) {
8928	  case 8:
8929	  case 16:
8930	  case 32:
8931             if(!pSiS->PointerMoved) pSiS->PointerMoved = pScrn->PointerMoved;
8932	     pScrn->PointerMoved = SISPointerMovedReflect;
8933	     refreshArea = SISRefreshAreaReflect;
8934#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
8935	     xf86DisableRandR();
8936	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8937		  "Driver reflection enabled, disabling RandR\n");
8938#endif
8939	     break;
8940	  default:
8941	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
8942	     	  "Reflection not supported at this framebuffer depth\n");
8943	  }
8944       }
8945
8946       ShadowFBInit(pScreen, refreshArea);
8947    }
8948
8949    xf86DPMSInit(pScreen, (DPMSSetProcPtr)SISDisplayPowerManagementSet, 0);
8950
8951    /* Init memPhysBase and fbOffset in pScrn */
8952    pScrn->memPhysBase = pSiS->FbAddress;
8953    pScrn->fbOffset = 0;
8954
8955    /* Initialize Xv */
8956    pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
8957#if (XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,99,0,0)) || (defined(XvExtension))
8958    if((!pSiS->NoXvideo) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
8959
8960       if((pSiS->VGAEngine == SIS_300_VGA) ||
8961	  (pSiS->VGAEngine == SIS_315_VGA)) {
8962
8963	  const char *using = "Using SiS300/315/330/340 series HW Xv";
8964
8965#ifdef SISDUALHEAD
8966	  if(pSiS->DualHeadMode) {
8967	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8968		    "%s on CRT%d\n", using, (pSiS->SecondHead ? 1 : 2));
8969	     if(!pSiS->hasTwoOverlays) {
8970		if( (pSiS->XvOnCRT2 && pSiS->SecondHead) ||
8971		    (!pSiS->XvOnCRT2 && !pSiS->SecondHead) ) {
8972		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8973			   "However, video overlay will by default only be visible on CRT%d\n",
8974			   pSiS->XvOnCRT2 ? 2 : 1);
8975		}
8976	     }
8977	  } else {
8978#endif
8979	     if(pSiS->hasTwoOverlays) {
8980		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s\n", using);
8981	     } else {
8982		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s by default on CRT%d\n",
8983			using, (pSiS->XvOnCRT2 ? 2 : 1));
8984	     }
8985#ifdef SISDUALHEAD
8986	  }
8987#endif
8988
8989	  SISInitVideo(pScreen);
8990
8991	  if(pSiS->blitadaptor) {
8992	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8993		     "Default Xv adaptor is Video %s\n",
8994		     pSiS->XvDefAdaptorBlit ? "Blitter" : "Overlay");
8995	  }
8996
8997       } else if(pSiS->Chipset == PCI_CHIP_SIS530  ||
8998		 pSiS->Chipset == PCI_CHIP_SIS6326 ||
8999		 pSiS->Chipset == PCI_CHIP_SIS5597) {
9000
9001	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9002		        "Using SiS5597/5598/6326/530/620 HW Xv\n" );
9003
9004	  SIS6326InitVideo(pScreen);
9005
9006       } else { /* generic Xv */
9007
9008	  XF86VideoAdaptorPtr *ptr;
9009	  int n = xf86XVListGenericAdaptors(pScrn, &ptr);
9010
9011	  if(n) {
9012	     xf86XVScreenInit(pScreen, ptr, n);
9013	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using generic Xv\n" );
9014          }
9015
9016       }
9017    }
9018#endif
9019
9020#ifdef XF86DRI
9021    if(pSiS->loadDRI) {
9022       if(pSiS->directRenderingEnabled) {
9023          /* Now that mi, drm and others have done their thing,
9024           * complete the DRI setup.
9025           */
9026          pSiS->directRenderingEnabled = SISDRIFinishScreenInit(pScreen);
9027       }
9028       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering %s\n",
9029		pSiS->directRenderingEnabled ? "enabled" : "disabled");
9030       /* TODO */
9031       /* if(pSiS->directRenderingEnabled) SISSetLFBConfig(pSiS); */
9032    }
9033#endif
9034
9035    /* Wrap some funcs, initialize pseudo-Xinerama and setup remaining SD flags */
9036
9037    pSiS->SiS_SD_Flags &= ~(SiS_SD_PSEUDOXINERAMA);
9038#ifdef SISMERGED
9039    if(pSiS->MergedFB) {
9040       pSiS->PointerMoved = pScrn->PointerMoved;
9041       pScrn->PointerMoved = SISMergedPointerMoved;
9042       pSiS->Rotate = 0;
9043       pSiS->Reflect = 0;
9044       pSiS->ShadowFB = FALSE;
9045#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
9046       if(pSiS->CRT1XOffs || pSiS->CRT1YOffs || pSiS->CRT2XOffs || pSiS->CRT2YOffs) {
9047	  xf86DisableRandR();
9048	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
9049		"MergedFB: CRT2Position offset used, disabling RandR\n");
9050       }
9051#endif
9052#ifdef SISXINERAMA
9053       if(pSiS->UseSiSXinerama) {
9054	  SiSnoPanoramiXExtension = FALSE;
9055	  SiSXineramaExtensionInit(pScrn);
9056	  if(!SiSnoPanoramiXExtension) {
9057	     pSiS->SiS_SD_Flags |= SiS_SD_PSEUDOXINERAMA;
9058	     if(pSiS->HaveNonRect) {
9059		/* Reset the viewport (now eventually non-recangular) */
9060		SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
9061	     }
9062	  }
9063       } else {
9064	  pSiS->MouseRestrictions = FALSE;
9065       }
9066#endif
9067    }
9068#endif
9069
9070    /* Wrap CloseScreen and set up SaveScreen */
9071    pSiS->CloseScreen = pScreen->CloseScreen;
9072    pScreen->CloseScreen = SISCloseScreen;
9073#ifdef SISDUALHEAD
9074    if(pSiS->DualHeadMode)
9075       pScreen->SaveScreen = SISSaveScreenDH;
9076    else
9077#endif
9078       pScreen->SaveScreen = SISSaveScreen;
9079
9080    /* Install BlockHandler */
9081    pSiS->BlockHandler = pScreen->BlockHandler;
9082    pScreen->BlockHandler = SISBlockHandler;
9083
9084    /* Report any unused options (only for the first generation) */
9085    if(serverGeneration == 1) {
9086       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
9087    }
9088
9089    /* Clear frame buffer */
9090    /* For CRT2, we don't do that at this point in dual head
9091     * mode since the mode isn't switched at this time (it will
9092     * be reset when setting the CRT1 mode). Hence, we just
9093     * save the necessary data and clear the screen when
9094     * going through this for CRT1.
9095     */
9096
9097    OnScreenSize = pScrn->displayWidth * pScrn->currentMode->VDisplay
9098                               * (pScrn->bitsPerPixel >> 3);
9099
9100    /* Turn on the screen now */
9101    /* We do this in dual head mode after second head is finished */
9102#ifdef SISDUALHEAD
9103    if(pSiS->DualHeadMode) {
9104       if(pSiS->SecondHead) {
9105	  sisclearvram(pSiS->FbBase, OnScreenSize);
9106	  sisclearvram(pSiSEnt->FbBase1, pSiSEnt->OnScreenSize1);
9107	  SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9108       } else {
9109	  pSiSEnt->FbBase1 = pSiS->FbBase;
9110	  pSiSEnt->OnScreenSize1 = OnScreenSize;
9111       }
9112    } else {
9113#endif
9114       SISSaveScreen(pScreen, SCREEN_SAVER_OFF);
9115       sisclearvram(pSiS->FbBase, OnScreenSize);
9116#ifdef SISDUALHEAD
9117    }
9118#endif
9119
9120    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9121#ifdef SISDUALHEAD
9122    if(!pSiS->DualHeadMode) {
9123#endif
9124       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
9125          if((pSiS->crt2cindices) && (pSiS->crt2gcolortable)) {
9126             pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSGRCRT2;
9127	  }
9128       }
9129#ifdef SISDUALHEAD
9130    }
9131#endif
9132
9133    pSiS->SiS_SD_Flags &= ~SiS_SD_ISDEPTH8;
9134    if(pSiS->CurrentLayout.bitsPerPixel == 8) {
9135       pSiS->SiS_SD_Flags |= SiS_SD_ISDEPTH8;
9136       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTXVGAMMA1;
9137       pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTSGRCRT2;
9138    }
9139
9140#ifdef SISGAMMARAMP
9141    pSiS->SiS_SD_Flags |= SiS_SD_CANSETGAMMA;
9142#else
9143    pSiS->SiS_SD_Flags &= ~SiS_SD_CANSETGAMMA;
9144#endif
9145
9146    SiSCtrlExtInit(pScrn);
9147
9148    return TRUE;
9149}
9150
9151/* Usually mandatory */
9152Bool
9153SISSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
9154{
9155    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9156    SISPtr pSiS = SISPTR(pScrn);
9157
9158    if(!pSiS->skipswitchcheck) {
9159       if(SISValidMode(scrnIndex, mode, TRUE, flags) != MODE_OK) {
9160          return FALSE;
9161       }
9162    }
9163
9164    (*pSiS->SyncAccel)(pScrn);
9165
9166    if(!(SISModeInit(xf86Screens[scrnIndex], mode))) return FALSE;
9167
9168    /* Since RandR (indirectly) uses SwitchMode(), we need to
9169     * update our Xinerama info here, too, in case of resizing
9170     */
9171#ifdef SISMERGED
9172#ifdef SISXINERAMA
9173    if(pSiS->MergedFB) {
9174       SiSUpdateXineramaScreenInfo(pScrn);
9175    }
9176#endif
9177#endif
9178    return TRUE;
9179}
9180
9181static void
9182SISSetStartAddressCRT1(SISPtr pSiS, ULong base)
9183{
9184    UChar cr11backup;
9185
9186    inSISIDXREG(SISCR,  0x11, cr11backup);  /* Unlock CRTC registers */
9187    andSISIDXREG(SISCR, 0x11, 0x7F);
9188    outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9189    outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9190    outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
9191    if(pSiS->VGAEngine == SIS_315_VGA) {
9192       setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
9193    }
9194    /* Eventually lock CRTC registers */
9195    setSISIDXREG(SISCR, 0x11, 0x7F,(cr11backup & 0x80));
9196}
9197
9198static void
9199SISSetStartAddressCRT2(SISPtr pSiS, ULong base)
9200{
9201    SiS_UnLockCRT2(pSiS->SiS_Pr);
9202    outSISIDXREG(SISPART1, 0x06, GETVAR8(base));
9203    outSISIDXREG(SISPART1, 0x05, GETBITS(base, 15:8));
9204    outSISIDXREG(SISPART1, 0x04, GETBITS(base, 23:16));
9205    if(pSiS->VGAEngine == SIS_315_VGA) {
9206       setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
9207    }
9208    SiS_LockCRT2(pSiS->SiS_Pr);
9209}
9210
9211#ifdef SISMERGED
9212static Bool
9213InRegion(int x, int y, region r)
9214{
9215    return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1);
9216}
9217
9218static void
9219SISAdjustFrameHW_CRT1(ScrnInfoPtr pScrn, int x, int y)
9220{
9221    SISPtr pSiS = SISPTR(pScrn);
9222    ULong base;
9223
9224    base = y * pSiS->CurrentLayout.displayWidth + x;
9225    switch(pSiS->CurrentLayout.bitsPerPixel) {
9226       case 16:  base >>= 1; 	break;
9227       case 32:  		break;
9228       default:  base >>= 2;
9229    }
9230    base += (pSiS->dhmOffset/4);
9231    SISSetStartAddressCRT1(pSiS, base);
9232}
9233
9234static void
9235SISAdjustFrameHW_CRT2(ScrnInfoPtr pScrn, int x, int y)
9236{
9237    SISPtr pSiS = SISPTR(pScrn);
9238    ULong base;
9239
9240    base = y * pSiS->CurrentLayout.displayWidth + x;
9241    switch(pSiS->CurrentLayout.bitsPerPixel) {
9242       case 16:  base >>= 1; 	break;
9243       case 32:  		break;
9244       default:  base >>= 2;
9245    }
9246    base += (pSiS->dhmOffset/4);
9247    SISSetStartAddressCRT2(pSiS, base);
9248}
9249
9250static void
9251SISMergedPointerMoved(int scrnIndex, int x, int y)
9252{
9253  ScrnInfoPtr	pScrn1 = xf86Screens[scrnIndex];
9254  SISPtr	pSiS = SISPTR(pScrn1);
9255  ScrnInfoPtr	pScrn2 = pSiS->CRT2pScrn;
9256  region	out, in1, in2, f2, f1;
9257  int		deltax, deltay;
9258  int		temp1, temp2;
9259  int		old1x0, old1y0, old2x0, old2y0;
9260  int		CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9261  int		HVirt = pScrn1->virtualX;
9262  int		VVirt = pScrn1->virtualY;
9263  int		sigstate;
9264  Bool		doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE;
9265  SiSScrn2Rel   srel = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2Position;
9266
9267  if(pSiS->DGAactive) {
9268     return;
9269     /* DGA: There is no cursor and no panning while DGA is active. */
9270     /* If it were, we would need to do: */
9271     /* HVirt = pSiS->CurrentLayout.displayWidth;
9272        VVirt = pSiS->CurrentLayout.displayHeight;
9273        BOUND(x, pSiS->CurrentLayout.DGAViewportX, HVirt);
9274        BOUND(y, pSiS->CurrentLayout.DGAViewportY, VVirt); */
9275  } else {
9276     CRT1XOffs = pSiS->CRT1XOffs;
9277     CRT1YOffs = pSiS->CRT1YOffs;
9278     CRT2XOffs = pSiS->CRT2XOffs;
9279     CRT2YOffs = pSiS->CRT2YOffs;
9280     HaveNonRect = pSiS->HaveNonRect;
9281     HaveOffsRegions = pSiS->HaveOffsRegions;
9282  }
9283
9284  /* Check if the pointer is inside our dead areas */
9285  if((pSiS->MouseRestrictions) && (srel != sisClone) && !SiSnoPanoramiXExtension) {
9286     if(HaveNonRect) {
9287	if(InRegion(x, y, pSiS->NonRectDead)) {
9288	   switch(srel) {
9289	   case sisLeftOf:
9290	   case sisRightOf: y = pSiS->NonRectDead.y0 - 1;
9291			    doit = TRUE;
9292			    break;
9293	   case sisAbove:
9294	   case sisBelow:   x = pSiS->NonRectDead.x0 - 1;
9295			    doit = TRUE;
9296	   default:	    break;
9297	   }
9298	}
9299     }
9300     if(HaveOffsRegions) {
9301	if(InRegion(x, y, pSiS->OffDead1)) {
9302	   switch(srel) {
9303	   case sisLeftOf:
9304	   case sisRightOf: y = pSiS->OffDead1.y1;
9305			    doit = TRUE;
9306			    break;
9307	   case sisAbove:
9308	   case sisBelow:   x = pSiS->OffDead1.x1;
9309			    doit = TRUE;
9310	   default:	    break;
9311	   }
9312	} else if(InRegion(x, y, pSiS->OffDead2)) {
9313	   switch(srel) {
9314	   case sisLeftOf:
9315	   case sisRightOf: y = pSiS->OffDead2.y0 - 1;
9316			    doit = TRUE;
9317			    break;
9318	   case sisAbove:
9319	   case sisBelow:   x = pSiS->OffDead2.x0 - 1;
9320			    doit = TRUE;
9321	   default:	    break;
9322	   }
9323	}
9324     }
9325     if(doit) {
9326	sigstate = xf86BlockSIGIO();
9327	miPointerSetPosition(inputInfo.pointer, x, y);
9328	xf86UnblockSIGIO(sigstate);
9329	return;
9330     }
9331  }
9332
9333  f1.x0 = old1x0 = pSiS->CRT1frameX0;
9334  f1.x1 = pSiS->CRT1frameX1;
9335  f1.y0 = old1y0 = pSiS->CRT1frameY0;
9336  f1.y1 = pSiS->CRT1frameY1;
9337  f2.x0 = old2x0 = pScrn2->frameX0;
9338  f2.x1 = pScrn2->frameX1;
9339  f2.y0 = old2y0 = pScrn2->frameY0;
9340  f2.y1 = pScrn2->frameY1;
9341
9342  /* Define the outer region. Crossing this causes all frames to move */
9343  out.x0 = pScrn1->frameX0;
9344  out.x1 = pScrn1->frameX1;
9345  out.y0 = pScrn1->frameY0;
9346  out.y1 = pScrn1->frameY1;
9347
9348  /*
9349   * Define the inner sliding window. Being outsize both frames but
9350   * inside the outer clipping window will slide corresponding frame
9351   */
9352  in1 = out;
9353  in2 = out;
9354  switch(srel) {
9355     case sisLeftOf:
9356        in1.x0 = f1.x0;
9357        in2.x1 = f2.x1;
9358        break;
9359     case sisRightOf:
9360        in1.x1 = f1.x1;
9361        in2.x0 = f2.x0;
9362        break;
9363     case sisBelow:
9364        in1.y1 = f1.y1;
9365        in2.y0 = f2.y0;
9366        break;
9367     case sisAbove:
9368        in1.y0 = f1.y0;
9369        in2.y1 = f2.y1;
9370        break;
9371     case sisClone:
9372        break;
9373  }
9374
9375  deltay = 0;
9376  deltax = 0;
9377
9378  if(InRegion(x, y, out)) {	/* inside outer region */
9379
9380     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
9381	REBOUND(f1.x0, f1.x1, x);
9382	REBOUND(f1.y0, f1.y1, y);
9383	deltax = 1;
9384     }
9385     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
9386	REBOUND(f2.x0, f2.x1, x);
9387	REBOUND(f2.y0, f2.y1, y);
9388	deltax = 1;
9389     }
9390
9391  } else {			/* outside outer region */
9392
9393     if(out.x0 > x) {
9394	deltax = x - out.x0;
9395     }
9396     if(out.x1 < x) {
9397	deltax = x - out.x1;
9398     }
9399     if(deltax) {
9400	pScrn1->frameX0 += deltax;
9401	pScrn1->frameX1 += deltax;
9402	f1.x0 += deltax;
9403	f1.x1 += deltax;
9404	f2.x0 += deltax;
9405	f2.x1 += deltax;
9406     }
9407
9408     if(out.y0 > y) {
9409	deltay = y - out.y0;
9410     }
9411     if(out.y1 < y) {
9412	deltay = y - out.y1;
9413     }
9414     if(deltay) {
9415	pScrn1->frameY0 += deltay;
9416	pScrn1->frameY1 += deltay;
9417	f1.y0 += deltay;
9418	f1.y1 += deltay;
9419	f2.y0 += deltay;
9420	f2.y1 += deltay;
9421     }
9422
9423     switch(srel) {
9424	case sisLeftOf:
9425	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
9426	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
9427	   break;
9428	case sisRightOf:
9429	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
9430	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
9431	   break;
9432	case sisBelow:
9433	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
9434	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
9435	   break;
9436	case sisAbove:
9437	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
9438	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
9439	   break;
9440	case sisClone:
9441	   break;
9442     }
9443
9444  }
9445
9446  if(deltax || deltay) {
9447     pSiS->CRT1frameX0 = f1.x0;
9448     pSiS->CRT1frameY0 = f1.y0;
9449     pScrn2->frameX0 = f2.x0;
9450     pScrn2->frameY0 = f2.y0;
9451
9452     switch(srel) {
9453	case sisLeftOf:
9454	case sisRightOf:
9455	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
9456	      if(pSiS->CRT1frameY0 != old1y0) {
9457	         if(pSiS->CRT1frameY0 < CRT1YOffs)
9458	            pSiS->CRT1frameY0 = CRT1YOffs;
9459
9460	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
9461	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
9462	         if(temp1 > temp2)
9463	            pSiS->CRT1frameY0 -= (temp1 - temp2);
9464	      }
9465	      if(pScrn2->frameY0 != old2y0) {
9466	         if(pScrn2->frameY0 < CRT2YOffs)
9467	            pScrn2->frameY0 = CRT2YOffs;
9468
9469	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
9470	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
9471	         if(temp1 > temp2)
9472	            pScrn2->frameY0 -= (temp1 - temp2);
9473	      }
9474	   }
9475	   break;
9476	case sisBelow:
9477	case sisAbove:
9478	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
9479	      if(pSiS->CRT1frameX0 != old1x0) {
9480	         if(pSiS->CRT1frameX0 < CRT1XOffs)
9481	            pSiS->CRT1frameX0 = CRT1XOffs;
9482
9483	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
9484	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
9485	         if(temp1 > temp2)
9486	            pSiS->CRT1frameX0 -= (temp1 - temp2);
9487	      }
9488	      if(pScrn2->frameX0 != old2x0) {
9489	         if(pScrn2->frameX0 < CRT2XOffs)
9490	            pScrn2->frameX0 = CRT2XOffs;
9491
9492	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
9493	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
9494	         if(temp1 > temp2)
9495	            pScrn2->frameX0 -= (temp1 - temp2);
9496	      }
9497	   }
9498	   break;
9499	case sisClone:
9500	   break;
9501     }
9502
9503     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9504     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9505     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9506     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9507
9508     /* No need to update pScrn1->frame?1, done above */
9509
9510     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9511     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9512  }
9513}
9514
9515static void
9516SISAdjustFrameMerged(int scrnIndex, int x, int y, int flags)
9517{
9518    ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
9519    SISPtr pSiS = SISPTR(pScrn1);
9520    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
9521    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
9522    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
9523    int HMax = HTotal;
9524    int VMax = VTotal;
9525    int HVirt = pScrn1->virtualX;
9526    int VVirt = pScrn1->virtualY;
9527    int x1 = x, x2 = x;
9528    int y1 = y, y2 = y;
9529    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9530    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
9531
9532    if(pSiS->DGAactive) {
9533       HVirt = pSiS->CurrentLayout.displayWidth;
9534       VVirt = pSiS->CurrentLayout.displayHeight;
9535    } else {
9536       CRT1XOffs = pSiS->CRT1XOffs;
9537       CRT1YOffs = pSiS->CRT1YOffs;
9538       CRT2XOffs = pSiS->CRT2XOffs;
9539       CRT2YOffs = pSiS->CRT2YOffs;
9540       MBXNR1XMAX = pSiS->MBXNR1XMAX;
9541       MBXNR1YMAX = pSiS->MBXNR1YMAX;
9542       MBXNR2XMAX = pSiS->MBXNR2XMAX;
9543       MBXNR2YMAX = pSiS->MBXNR2YMAX;
9544    }
9545
9546    BOUND(x, 0, HVirt - HTotal);
9547    BOUND(y, 0, VVirt - VTotal);
9548    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9549       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
9550       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
9551       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
9552       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
9553    }
9554
9555    switch(SDMPTR(pScrn1)->CRT2Position) {
9556        case sisLeftOf:
9557            pScrn2->frameX0 = x2;
9558            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9559            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
9560            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9561            break;
9562        case sisRightOf:
9563            pSiS->CRT1frameX0 = x1;
9564            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9565            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
9566            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9567            break;
9568        case sisAbove:
9569            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9570            pScrn2->frameY0 = y2;
9571            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9572            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
9573            break;
9574        case sisBelow:
9575            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9576            pSiS->CRT1frameY0 = y1;
9577            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9578            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
9579            break;
9580        case sisClone:
9581            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
9582            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
9583            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
9584            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
9585            break;
9586    }
9587
9588    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
9589    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
9590    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
9591    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
9592
9593    pScrn1->frameX0 = x;
9594    pScrn1->frameY0 = y;
9595
9596    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9597    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9598    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9599    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9600
9601    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
9602    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
9603    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9604       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
9605       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
9606    }
9607
9608    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9609    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9610}
9611#endif
9612
9613/*
9614 * This function is used to initialize the Start Address - the first
9615 * displayed location in the video memory.
9616 *
9617 * Usually mandatory
9618 */
9619void
9620SISAdjustFrame(int scrnIndex, int x, int y, int flags)
9621{
9622    ScrnInfoPtr   pScrn = xf86Screens[scrnIndex];
9623    SISPtr        pSiS = SISPTR(pScrn);
9624    ULong base;
9625    UChar temp, cr11backup;
9626
9627#ifdef SISMERGED
9628    if(pSiS->MergedFB) {
9629	SISAdjustFrameMerged(scrnIndex, x, y, flags);
9630	return;
9631    }
9632#endif
9633
9634    if(pSiS->UseVESA) {
9635	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
9636	return;
9637    }
9638
9639    if(pScrn->bitsPerPixel < 8) {
9640       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
9641    } else {
9642       base  = y * pSiS->CurrentLayout.displayWidth + x;
9643
9644       /* calculate base bpp dep. */
9645       switch(pSiS->CurrentLayout.bitsPerPixel) {
9646          case 16:
9647     	     base >>= 1;
9648             break;
9649          case 24:
9650             base = ((base * 3)) >> 2;
9651             base -= base % 6;
9652             break;
9653          case 32:
9654             break;
9655          default:      /* 8bpp */
9656             base >>= 2;
9657             break;
9658       }
9659    }
9660
9661#ifdef UNLOCK_ALWAYS
9662    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9663#endif
9664
9665    base += (pSiS->dhmOffset/4);
9666
9667#ifdef TWDEBUG
9668    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
9669    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
9670#endif
9671
9672#ifdef SISDUALHEAD
9673    if(pSiS->DualHeadMode) {
9674       if(!pSiS->SecondHead) {
9675	  /* Head 1 (master) is always CRT2 */
9676	  SISSetStartAddressCRT2(pSiS, base);
9677       } else {
9678	  /* Head 2 (slave) is always CRT1 */
9679	  SISSetStartAddressCRT1(pSiS, base);
9680       }
9681    } else {
9682#endif
9683       switch(pSiS->VGAEngine) {
9684	  case SIS_300_VGA:
9685	  case SIS_315_VGA:
9686	     SISSetStartAddressCRT1(pSiS, base);
9687	     if(pSiS->VBFlags & CRT2_ENABLE) {
9688		if(!SiSBridgeIsInSlaveMode(pScrn)) {
9689		   SISSetStartAddressCRT2(pSiS, base);
9690		}
9691	     }
9692	     break;
9693	  default:
9694	     /* Unlock CRTC registers */
9695	     inSISIDXREG(SISCR,  0x11, cr11backup);
9696	     andSISIDXREG(SISCR, 0x11, 0x7F);
9697	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9698	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9699	     inSISIDXREG(SISSR,  0x27, temp);
9700	     temp &= 0xF0;
9701	     temp |= (base & 0x0F0000) >> 16;
9702	     outSISIDXREG(SISSR, 0x27, temp);
9703	     /* Eventually lock CRTC registers */
9704	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
9705       }
9706#ifdef SISDUALHEAD
9707    }
9708#endif
9709
9710}
9711
9712/*
9713 * This is called when VT switching back to the X server.  Its job is
9714 * to reinitialise the video mode.
9715 * Mandatory!
9716 */
9717static Bool
9718SISEnterVT(int scrnIndex, int flags)
9719{
9720    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9721    SISPtr pSiS = SISPTR(pScrn);
9722
9723    SiS_SiSFB_Lock(pScrn, TRUE);
9724
9725    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9726
9727    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
9728       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
9729       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
9730       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
9731    }
9732
9733    if(!SISModeInit(pScrn, pScrn->currentMode)) {
9734       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
9735       return FALSE;
9736    }
9737
9738    SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
9739
9740#ifdef XF86DRI
9741    if(pSiS->directRenderingEnabled) {
9742       DRIUnlock(screenInfo.screens[scrnIndex]);
9743    }
9744#endif
9745
9746#ifdef SISDUALHEAD
9747    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
9748#endif
9749       if(pSiS->ResetXv) {
9750          (pSiS->ResetXv)(pScrn);
9751       }
9752
9753    return TRUE;
9754}
9755
9756/*
9757 * This is called when VT switching away from the X server.  Its job is
9758 * to restore the previous (text) mode.
9759 * Mandatory!
9760 */
9761static void
9762SISLeaveVT(int scrnIndex, int flags)
9763{
9764    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9765    SISPtr pSiS = SISPTR(pScrn);
9766#ifdef XF86DRI
9767    ScreenPtr pScreen;
9768
9769    if(pSiS->directRenderingEnabled) {
9770       pScreen = screenInfo.screens[scrnIndex];
9771       DRILock(pScreen, 0);
9772    }
9773#endif
9774
9775#ifdef SISDUALHEAD
9776    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
9777#endif
9778
9779    if(pSiS->CursorInfoPtr) {
9780#ifdef SISDUALHEAD
9781       if(pSiS->DualHeadMode) {
9782          if(!pSiS->SecondHead) {
9783	     pSiS->ForceCursorOff = TRUE;
9784	     pSiS->CursorInfoPtr->HideCursor(pScrn);
9785	     SISWaitVBRetrace(pScrn);
9786	     pSiS->ForceCursorOff = FALSE;
9787	  }
9788       } else {
9789#endif
9790          pSiS->CursorInfoPtr->HideCursor(pScrn);
9791          SISWaitVBRetrace(pScrn);
9792#ifdef SISDUALHEAD
9793       }
9794#endif
9795    }
9796
9797    SISBridgeRestore(pScrn);
9798
9799    if(pSiS->UseVESA) {
9800
9801       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9802    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
9803	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
9804	* can call VBESaveRestore to restore original mode.
9805	*/
9806       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9807	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9808
9809       SISVESARestore(pScrn);
9810
9811    } else {
9812
9813       SISRestore(pScrn);
9814
9815    }
9816
9817    /* We use (otherwise unused) bit 7 to indicate that we are running
9818     * to keep sisfb to change the displaymode (this would result in
9819     * lethal display corruption upon quitting X or changing to a VT
9820     * until a reboot)
9821     */
9822    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
9823       orSISIDXREG(SISCR,0x34,0x80);
9824    }
9825
9826    SISVGALock(pSiS);
9827
9828    SiS_SiSFB_Lock(pScrn, FALSE);
9829}
9830
9831
9832/*
9833 * This is called at the end of each server generation.  It restores the
9834 * original (text) mode.  It should really also unmap the video memory too.
9835 * Mandatory!
9836 */
9837static Bool
9838SISCloseScreen(int scrnIndex, ScreenPtr pScreen)
9839{
9840    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9841    SISPtr pSiS = SISPTR(pScrn);
9842#ifdef SISDUALHEAD
9843    SISEntPtr pSiSEnt = pSiS->entityPrivate;
9844#endif
9845
9846    if(pSiS->SiSCtrlExtEntry) {
9847       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
9848    }
9849
9850#ifdef XF86DRI
9851    if(pSiS->directRenderingEnabled) {
9852       SISDRICloseScreen(pScreen);
9853       pSiS->directRenderingEnabled = FALSE;
9854    }
9855#endif
9856
9857    if(pScrn->vtSema) {
9858
9859        if(pSiS->CursorInfoPtr) {
9860#ifdef SISDUALHEAD
9861           if(pSiS->DualHeadMode) {
9862              if(!pSiS->SecondHead) {
9863	         pSiS->ForceCursorOff = TRUE;
9864	         pSiS->CursorInfoPtr->HideCursor(pScrn);
9865	         SISWaitVBRetrace(pScrn);
9866	         pSiS->ForceCursorOff = FALSE;
9867	      }
9868           } else {
9869#endif
9870             pSiS->CursorInfoPtr->HideCursor(pScrn);
9871             SISWaitVBRetrace(pScrn);
9872#ifdef SISDUALHEAD
9873           }
9874#endif
9875	}
9876
9877        SISBridgeRestore(pScrn);
9878
9879	if(pSiS->UseVESA) {
9880
9881	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9882    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
9883	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
9884	   * can call VBESaveRestore to restore original mode.
9885	   */
9886           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9887	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9888
9889	   SISVESARestore(pScrn);
9890
9891	} else {
9892
9893	   SISRestore(pScrn);
9894
9895	}
9896
9897        SISVGALock(pSiS);
9898
9899    }
9900
9901    SiS_SiSFB_Lock(pScrn, FALSE);
9902
9903    /* We should restore the mode number in case vtsema = false as well,
9904     * but since we haven't register access then we can't do it. I think
9905     * I need to rework the save/restore stuff, like saving the video
9906     * status when returning to the X server and by that save me the
9907     * trouble if sisfb was started from a textmode VT while X was on.
9908     */
9909
9910    SISUnmapMem(pScrn);
9911#ifdef SIS_PC_PLATFORM
9912    SiSVGAUnmapMem(pScrn);
9913#endif
9914
9915#ifdef SISDUALHEAD
9916    if(pSiS->DualHeadMode) {
9917       pSiSEnt = pSiS->entityPrivate;
9918       pSiSEnt->refCount--;
9919    }
9920#endif
9921
9922    if(pSiS->pInt) {
9923       xf86FreeInt10(pSiS->pInt);
9924       pSiS->pInt = NULL;
9925    }
9926
9927#ifdef SIS_USE_XAA
9928    if(!pSiS->useEXA) {
9929       if(pSiS->AccelLinearScratch) {
9930          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
9931          pSiS->AccelLinearScratch = NULL;
9932       }
9933       if(pSiS->AccelInfoPtr) {
9934          XAADestroyInfoRec(pSiS->AccelInfoPtr);
9935          pSiS->AccelInfoPtr = NULL;
9936       }
9937    }
9938#endif
9939
9940#ifdef SIS_USE_EXA
9941    if(pSiS->useEXA) {
9942       if(pSiS->EXADriverPtr) {
9943          exaDriverFini(pScreen);
9944          xfree(pSiS->EXADriverPtr);
9945          pSiS->EXADriverPtr = NULL;
9946          pSiS->exa_scratch = NULL;
9947       }
9948    }
9949#endif
9950
9951    if(pSiS->CursorInfoPtr) {
9952       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
9953       pSiS->CursorInfoPtr = NULL;
9954    }
9955
9956    if(pSiS->ShadowPtr) {
9957       xfree(pSiS->ShadowPtr);
9958       pSiS->ShadowPtr = NULL;
9959    }
9960
9961    if(pSiS->DGAModes) {
9962       xfree(pSiS->DGAModes);
9963       pSiS->DGAModes = NULL;
9964    }
9965
9966    if(pSiS->adaptor) {
9967       xfree(pSiS->adaptor);
9968       pSiS->adaptor = NULL;
9969       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
9970    }
9971
9972    if(pSiS->blitadaptor) {
9973       xfree(pSiS->blitadaptor);
9974       pSiS->blitadaptor = NULL;
9975    }
9976
9977    if(pSiS->crt2gcolortable) {
9978       xfree(pSiS->crt2gcolortable);
9979       pSiS->crt2gcolortable = NULL;
9980    }
9981
9982    if(pSiS->crt2cindices) {
9983       xfree(pSiS->crt2cindices);
9984       pSiS->crt2cindices = NULL;
9985    }
9986
9987    pScrn->vtSema = FALSE;
9988
9989    /* Restore Blockhandler */
9990    pScreen->BlockHandler = pSiS->BlockHandler;
9991
9992    pScreen->CloseScreen = pSiS->CloseScreen;
9993
9994    return(*pScreen->CloseScreen)(scrnIndex, pScreen);
9995}
9996
9997
9998/* Free up any per-generation data structures */
9999
10000/* Optional */
10001static void
10002SISFreeScreen(int scrnIndex, int flags)
10003{
10004#ifdef SIS_NEED_MAP_IOP
10005    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
10006    SISPtr pSiS = SISPTR(pScrn);
10007
10008    if(pSiS) {
10009#ifdef SISDUALHEAD
10010       SISEntPtr pSiSEnt = pSiS->entityPrivate;
10011       if(pSiSEnt) {
10012          pSiSEnt->forceUnmapIOPBase = TRUE;
10013       }
10014#endif
10015       SISUnmapIOPMem(pScrn);
10016    }
10017#endif
10018
10019    SISFreeRec(xf86Screens[scrnIndex]);
10020}
10021
10022
10023/* Checks if a mode is suitable for the selected chipset. */
10024
10025static ModeStatus
10026SISValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
10027{
10028    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
10029    SISPtr pSiS = SISPTR(pScrn);
10030
10031    if(pSiS->UseVESA) {
10032       if(SiSCalcVESAModeIndex(pScrn, mode))
10033	  return(MODE_OK);
10034       else
10035	  return(MODE_BAD);
10036    }
10037
10038    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
10039#ifdef SISDUALHEAD
10040       if(pSiS->DualHeadMode) {
10041          if(pSiS->SecondHead) {
10042	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10043	        return(MODE_BAD);
10044	  } else {
10045	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10046	        return(MODE_BAD);
10047	  }
10048       } else
10049#endif
10050#ifdef SISMERGED
10051       if(pSiS->MergedFB) {
10052	  if(!mode->Private) {
10053	     if(!pSiS->CheckForCRT2) {
10054	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10055	           return(MODE_BAD);
10056	     } else {
10057	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10058	           return(MODE_BAD);
10059	     }
10060	  } else {
10061	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
10062		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10063	        return(MODE_BAD);
10064
10065	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
10066		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10067	        return(MODE_BAD);
10068 	  }
10069       } else
10070#endif
10071       {
10072	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10073	     return(MODE_BAD);
10074
10075	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10076	     return(MODE_BAD);
10077       }
10078    }
10079
10080    return(MODE_OK);
10081}
10082
10083#ifdef DEBUG
10084static void
10085SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
10086{
10087    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
10088    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
10089    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
10090    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
10091    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
10092    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
10093    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
10094    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
10095    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
10096    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
10097    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
10098    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
10099    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
10100    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
10101    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
10102    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
10103}
10104#endif
10105
10106static void
10107SISModifyModeInfo(DisplayModePtr mode)
10108{
10109    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
10110        mode->CrtcHBlankStart++;
10111    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
10112        mode->CrtcHBlankEnd--;
10113    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
10114        mode->CrtcVBlankStart++;
10115    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
10116        mode->CrtcVBlankEnd--;
10117}
10118
10119/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
10120static void
10121SiSEnableTurboQueue(ScrnInfoPtr pScrn)
10122{
10123    SISPtr pSiS = SISPTR(pScrn);
10124    UShort SR26, SR27;
10125    ULong  temp;
10126
10127    switch(pSiS->VGAEngine) {
10128	case SIS_300_VGA:
10129	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
10130		/* TQ size is always 512k */
10131		temp = (pScrn->videoRam/64) - 8;
10132		SR26 = temp & 0xFF;
10133		inSISIDXREG(SISSR, 0x27, SR27);
10134		SR27 &= 0xFC;
10135		SR27 |= (0xF0 | ((temp >> 8) & 3));
10136		outSISIDXREG(SISSR, 0x26, SR26);
10137		outSISIDXREG(SISSR, 0x27, SR27);
10138	   }
10139	   break;
10140
10141	case SIS_315_VGA:
10142	   if(!pSiS->NoAccel) {
10143	      /* On 315/330/340 series, there are three queue modes available
10144	       * which are chosen by setting bits 7:5 in SR26:
10145	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
10146	       *    track of the queue, the FIFO, command parsing and so
10147	       *    on. This is the one comparable to the 300 series.
10148	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
10149	       *    have to do queue management himself.
10150	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
10151	       *    queue in AGP memory space.
10152	       * We go VRAM or MMIO here.
10153	       * SR26 bit 4 is called "Bypass H/W queue".
10154	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
10155	       * SR26 bit 0 resets the queue
10156	       * Size of queue memory is encoded in bits 3:2 like this:
10157	       *    00  (0x00)  512K
10158	       *    01  (0x04)  1M
10159	       *    10  (0x08)  2M
10160	       *    11  (0x0C)  4M
10161	       * The queue location is to be written to 0x85C0.
10162	       */
10163#ifdef SISVRAMQ
10164	      /* We use VRAM Cmd Queue, not MMIO or AGP */
10165	      UChar tempCR55 = 0;
10166
10167	      /* Set Command Queue Threshold to max value 11111b (?) */
10168	      outSISIDXREG(SISSR, 0x27, 0x1F);
10169
10170	      /* Disable queue flipping */
10171	      inSISIDXREG(SISCR, 0x55, tempCR55);
10172	      andSISIDXREG(SISCR, 0x55, 0x33);
10173	      /* Synchronous reset for Command Queue */
10174	      outSISIDXREG(SISSR, 0x26, 0x01);
10175	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10176	      /* Enable VRAM Command Queue mode */
10177	      if(pSiS->ChipType == XGI_20) {
10178		 /* On XGI_20, always 128K */
10179		 SR26 = 0x40 | 0x04 | 0x01;
10180	      } else {
10181	         switch(pSiS->cmdQueueSize) {
10182		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
10183		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
10184		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
10185		    default:
10186		                      pSiS->cmdQueueSize = 512 * 1024;
10187		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
10188	         }
10189	      }
10190	      outSISIDXREG(SISSR, 0x26, SR26);
10191	      SR26 &= 0xfe;
10192	      outSISIDXREG(SISSR, 0x26, SR26);
10193	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
10194	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
10195	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
10196	      temp = (ULong)pSiS->RealFbBase;
10197#ifdef SISDUALHEAD
10198	      if(pSiS->DualHeadMode) {
10199	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
10200	         temp = (ULong)pSiSEnt->RealFbBase;
10201	      }
10202#endif
10203	      temp += pSiS->cmdQueueOffset;
10204	      pSiS->cmdQueueBase = (unsigned int *)temp;
10205	      outSISIDXREG(SISCR, 0x55, tempCR55);
10206#ifdef TWDEBUG
10207	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
10208		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
10209		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
10210#endif
10211#else
10212	      /* For MMIO */
10213	      /* Syncronous reset for Command Queue */
10214	      orSISIDXREG(SISSR, 0x26, 0x01);
10215	      /* Set Command Queue Threshold to max value 11111b */
10216	      outSISIDXREG(SISSR, 0x27, 0x1F);
10217	      /* Do some magic (cp readport to writeport) */
10218	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
10219	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
10220	      /* Enable MMIO Command Queue mode (0x20),
10221	       * Enable_command_queue_auto_correction (0x02)
10222	       *        (no idea, but sounds good, so use it)
10223	       * 512k (0x00) (does this apply to MMIO mode?) */
10224	      outSISIDXREG(SISSR, 0x26, 0x22);
10225	      /* Calc Command Queue position (Q is always 512k)*/
10226	      temp = (pScrn->videoRam - 512) * 1024;
10227	      /* Set Q position */
10228	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
10229#endif
10230	   }
10231	   break;
10232	default:
10233	   break;
10234    }
10235}
10236
10237#ifdef SISVRAMQ
10238static void
10239SiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
10240{
10241    UChar tempCR55=0;
10242
10243    if(pSiS->VGAEngine == SIS_315_VGA) {
10244       inSISIDXREG(SISCR,0x55,tempCR55);
10245       andSISIDXREG(SISCR,0x55,0x33);
10246       outSISIDXREG(SISSR,0x26,0x01);
10247       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10248       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
10249       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
10250       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
10251       outSISIDXREG(SISCR,0x55,tempCR55);
10252    }
10253}
10254#endif
10255
10256/* Things to do before a ModeSwitch. We set up the
10257 * video bridge configuration and the TurboQueue.
10258 */
10259void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
10260{
10261    SISPtr pSiS = SISPTR(pScrn);
10262    UChar  CR30, CR31, CR32, CR33;
10263    UChar  CR39 = 0, CR3B = 0;
10264    UChar  CR17, CR38 = 0;
10265    UChar  CR35 = 0, CR79 = 0;
10266    int    temp = 0, crt1rateindex = 0;
10267    ULong  vbflag = pSiS->VBFlags;
10268    Bool   hcm = pSiS->HaveCustomModes;
10269    DisplayModePtr mymode = mode;
10270
10271    pSiS->IsCustom = FALSE;
10272
10273    /* NEVER call this with viewmode = SIS_MODE_SIMU
10274     * if mode->type is not M_T_DEFAULT!
10275     */
10276
10277#ifdef SISMERGED
10278    if(pSiS->MergedFB) {
10279       switch(viewmode) {
10280       case SIS_MODE_CRT1:
10281	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
10282	  break;
10283       case SIS_MODE_CRT2:
10284	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
10285	  hcm = pSiS->HaveCustomModes2;
10286       }
10287    }
10288#endif
10289
10290    switch(viewmode) {
10291    case SIS_MODE_CRT1:
10292       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10293          pSiS->IsCustom = TRUE;
10294       }
10295       break;
10296    case SIS_MODE_CRT2:
10297       if(vbflag & CRT2_ENABLE) {
10298          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
10299	     pSiS->IsCustom = TRUE;
10300          }
10301       } else {
10302          /* This can only happen in mirror mode */
10303          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10304             pSiS->IsCustom = TRUE;
10305          }
10306       }
10307    }
10308
10309#ifdef UNLOCK_ALWAYS
10310    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
10311#endif
10312
10313    inSISIDXREG(SISCR, 0x30, CR30);
10314    inSISIDXREG(SISCR, 0x31, CR31);
10315    CR32 = pSiS->newCR32;
10316    inSISIDXREG(SISCR, 0x33, CR33);
10317
10318    if(pSiS->NewCRLayout) {
10319
10320       inSISIDXREG(SISCR, 0x35, CR35);
10321       inSISIDXREG(SISCR, 0x38, CR38);
10322       inSISIDXREG(SISCR, 0x39, CR39);
10323
10324       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10325	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
10326              CR30, CR31, CR32, CR33, CR35, CR38);
10327
10328       CR38 &= ~0x07;
10329
10330    } else {
10331
10332       if(pSiS->Chipset != PCI_CHIP_SIS300) {
10333          switch(pSiS->VGAEngine) {
10334             case SIS_300_VGA: temp = 0x35; break;
10335             case SIS_315_VGA: temp = 0x38; break;
10336          }
10337          if(temp) inSISIDXREG(SISCR, temp, CR38);
10338       }
10339       if(pSiS->VGAEngine == SIS_315_VGA) {
10340          inSISIDXREG(SISCR, 0x79, CR79);
10341          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
10342       }
10343       inSISIDXREG(SISCR, 0x3b, CR3B);
10344
10345       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10346	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
10347              CR30, CR31, CR32, CR33, temp, CR38);
10348    }
10349
10350    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
10351
10352    CR30 = 0x00;
10353    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
10354    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
10355    CR35 = 0x00;
10356
10357    if(!pSiS->NewCRLayout) {
10358       if(!pSiS->AllowHotkey) {
10359          CR31 |= 0x80;   /* Disable hotkey-switch */
10360       }
10361       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
10362    }
10363
10364    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
10365    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
10366
10367    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
10368
10369       CR38 |= 0x02;
10370
10371    } else {
10372
10373       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10374
10375       case CRT2_TV:
10376
10377          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
10378
10379          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
10380	     CR30 |= 0x10;
10381	     CR38 |= 0x04;
10382	     CR38 &= ~0x08;
10383	     CR31 |= 0x01;
10384	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
10385	     CR38 |= 0x08;
10386	     CR38 &= ~0x04;
10387	     CR31 &= ~0x01;
10388          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
10389	     if(pSiS->NewCRLayout) {
10390	        CR38 |= 0x04;
10391	        CR35 |= 0x60;
10392	     } else {
10393	        CR30 |= 0x80;
10394		if(pSiS->VGAEngine == SIS_315_VGA) {
10395		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
10396		      CR38 |= (0x08 | 0x30);
10397		   }
10398		}
10399	     }
10400	     CR31 |= 0x01;
10401	     CR35 |= 0x01;
10402	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
10403	     if(pSiS->NewCRLayout) {
10404		CR38 |= 0x04;
10405		CR31 &= ~0x01;
10406		CR35 &= ~0x01;
10407		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
10408		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
10409		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
10410
10411		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
10412		   CR31 |= 0x01;
10413		   CR35 |= 0x01;
10414		}
10415
10416		CR39 &= ~0x03;
10417		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
10418		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
10419		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
10420		else					      CR39 |= 0x03;
10421	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
10422		CR30 |= 0x80;
10423		CR38 |= 0x08;
10424		CR31 &= ~0x01;
10425		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
10426		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
10427		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
10428
10429		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
10430
10431		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
10432		   CR3B &= ~0x03;
10433		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
10434		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
10435		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
10436		   else					         CR3B |= 0x03;
10437		}
10438	     }
10439          } else {								/* All */
10440	     if(vbflag & TV_SCART)  CR30 |= 0x10;
10441	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
10442	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
10443	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
10444
10445	     if(vbflag & TV_PAL) {
10446		CR31 |= 0x01;
10447		CR35 |= 0x01;
10448		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
10449		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
10450		   if(vbflag & TV_PALM) {
10451		      CR38 |= 0x40;
10452		      CR35 |= 0x04;
10453		   } else if(vbflag & TV_PALN) {
10454		      CR38 |= 0x80;
10455		      CR35 |= 0x08;
10456		   }
10457	        }
10458	     } else {
10459		CR31 &= ~0x01;
10460		CR35 &= ~0x01;
10461		if(vbflag & TV_NTSCJ) {
10462		   CR38 |= 0x40;  /* TW, not BIOS */
10463		   CR35 |= 0x02;
10464		}
10465	     }
10466	     if(vbflag & TV_SCART) {
10467		CR31 |= 0x01;
10468		CR35 |= 0x01;
10469	     }
10470	  }
10471
10472	  CR31 &= ~0x04;   /* Clear NotSimuMode */
10473	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
10474	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
10475	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
10476	  } else {
10477	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
10478	  }
10479#ifdef SIS_CP
10480	  SIS_CP_DRIVER_CONFIG
10481#endif
10482	  break;
10483
10484       case CRT2_LCD:
10485	  CR30 |= 0x20;
10486	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
10487	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
10488	  break;
10489
10490       case CRT2_VGA:
10491	  CR30 |= 0x40;
10492	  break;
10493
10494       default:
10495	  CR30 |= 0x00;
10496	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
10497	  if(pSiS->UseVESA) {
10498	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10499	  }
10500       }
10501
10502    }
10503
10504    if(vbflag & CRT1_LCDA) {
10505       switch(viewmode) {
10506       case SIS_MODE_CRT1:
10507	  CR38 |= 0x01;
10508	  break;
10509       case SIS_MODE_CRT2:
10510	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
10511	     CR30 |= 0x02;
10512	     CR38 |= 0x01;
10513	  } else {
10514	     CR38 |= 0x03;
10515	  }
10516	  break;
10517       case SIS_MODE_SIMU:
10518       default:
10519	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10520	     CR30 |= 0x01;
10521	  }
10522	  break;
10523       }
10524    } else {
10525       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10526          CR30 |= 0x01;
10527       }
10528    }
10529
10530    if(pSiS->UseVESA) {
10531       CR31 &= ~0x40;   /* Clear Drivermode */
10532       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
10533#ifdef TWDEBUG
10534       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
10535       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10536#endif
10537    } else {
10538       CR31 |=  0x40;  /* Set Drivermode */
10539       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
10540       if(!pSiS->IsCustom) {
10541          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10542       }
10543    }
10544
10545    switch(viewmode) {
10546	case SIS_MODE_SIMU:
10547	   CR33 = 0;
10548	   if(!(vbflag & CRT1_LCDA)) {
10549	      CR33 |= (crt1rateindex & 0x0f);
10550	   }
10551	   if(vbflag & CRT2_VGA) {
10552	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10553	   }
10554	   break;
10555	case SIS_MODE_CRT1:
10556	   CR33 &= 0xf0;
10557	   if(!(vbflag & CRT1_LCDA)) {
10558	      CR33 |= (crt1rateindex & 0x0f);
10559	   }
10560	   break;
10561	case SIS_MODE_CRT2:
10562	   CR33 &= 0x0f;
10563	   if(vbflag & CRT2_VGA) {
10564	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10565	   }
10566	   break;
10567     }
10568
10569     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
10570	if(pSiS->CRT1off) CR33 &= 0xf0;
10571     }
10572
10573     if(pSiS->NewCRLayout) {
10574
10575	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
10576	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
10577	outSISIDXREG(SISCR, 0x30, CR30);
10578	outSISIDXREG(SISCR, 0x31, CR31);
10579	outSISIDXREG(SISCR, 0x33, CR33);
10580	outSISIDXREG(SISCR, 0x35, CR35);
10581	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
10582	outSISIDXREG(SISCR, 0x39, CR39);
10583
10584	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10585		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
10586		    CR30, CR31, CR33, CR35, CR38);
10587
10588     } else {
10589
10590	outSISIDXREG(SISCR, 0x30, CR30);
10591	outSISIDXREG(SISCR, 0x31, CR31);
10592	outSISIDXREG(SISCR, 0x33, CR33);
10593	if(temp) {
10594	   outSISIDXREG(SISCR, temp, CR38);
10595	}
10596	if(pSiS->VGAEngine == SIS_315_VGA) {
10597	   outSISIDXREG(SISCR, 0x3b, CR3B);
10598	   outSISIDXREG(SISCR, 0x79, CR79);
10599	}
10600
10601	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10602		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
10603		    CR30, CR31, CR33, temp, CR38);
10604     }
10605
10606     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
10607
10608     /* Enable TurboQueue */
10609#ifdef SISVRAMQ
10610     if(pSiS->VGAEngine != SIS_315_VGA)
10611#endif
10612	SiSEnableTurboQueue(pScrn);
10613
10614     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
10615	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
10616	andSISIDXREG(SISSR,0x1f,0x3f);
10617	inSISIDXREG(SISCR, 0x17, CR17);
10618	if(!(CR17 & 0x80)) {
10619	   orSISIDXREG(SISCR, 0x17, 0x80);
10620	   outSISIDXREG(SISSR, 0x00, 0x01);
10621	   usleep(10000);
10622	   outSISIDXREG(SISSR, 0x00, 0x03);
10623	}
10624     }
10625}
10626
10627/* Functions for adjusting various TV settings */
10628
10629/* These are used by the PostSetMode() functions as well as
10630 * the display properties tool SiSCtrl.
10631 *
10632 * There is each a Set and a Get routine. The Set functions
10633 * take a value of the same range as the corresponding option.
10634 * The Get routines return a value of the same range (although
10635 * not necessarily the same value as previously set because
10636 * of the lower resolution of the respective setting compared
10637 * to the valid range).
10638 * The Get routines return -2 on error (eg. hardware does not
10639 * support this setting).
10640 * Note: The x and y positioning routines accept a position
10641 * RELATIVE to the default position. All other routines
10642 * take ABSOLUTE values.
10643 *
10644 * The Set functions will store the property regardless if TV is
10645 * currently used or not and if the hardware supports the property
10646 * or not. The Get routines will return this stored
10647 * value if TV is not currently used (because the register does
10648 * not contain the correct value then) or if the hardware supports
10649 * the respective property. This should make it easier for the
10650 * display property tool because it does not have to know the
10651 * hardware features.
10652 *
10653 * All the routines are dual head aware. It does not matter
10654 * if the function is called from the CRT1 or CRT2 session.
10655 * The values will be in pSiSEnt anyway, and read from there
10656 * if we're running dual head.
10657 */
10658
10659void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
10660{
10661   SISPtr pSiS = SISPTR(pScrn);
10662#ifdef SISDUALHEAD
10663   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10664#endif
10665
10666   pSiS->chtvlumabandwidthcvbs = val;
10667#ifdef SISDUALHEAD
10668   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
10669#endif
10670
10671   if(!(pSiS->VBFlags & CRT2_TV)) return;
10672   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10673
10674#ifdef UNLOCK_ALWAYS
10675   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10676#endif
10677
10678   switch(pSiS->ChrontelType) {
10679       case CHRONTEL_700x:
10680           val /= 8;
10681           if((val == 0) || (val == 1)) {
10682	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
10683           }
10684	   break;
10685       case CHRONTEL_701x:
10686           val /= 4;
10687	   if((val >= 0) && (val <= 3)) {
10688	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
10689	   }
10690           break;
10691   }
10692}
10693
10694int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
10695{
10696   SISPtr pSiS = SISPTR(pScrn);
10697#ifdef SISDUALHEAD
10698   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10699#endif
10700
10701   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10702#ifdef SISDUALHEAD
10703      if(pSiSEnt && pSiS->DualHeadMode)
10704           return (int)pSiSEnt->chtvlumabandwidthcvbs;
10705      else
10706#endif
10707           return (int)pSiS->chtvlumabandwidthcvbs;
10708   } else {
10709#ifdef UNLOCK_ALWAYS
10710      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10711#endif
10712      switch(pSiS->ChrontelType) {
10713      case CHRONTEL_700x:
10714           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
10715      case CHRONTEL_701x:
10716	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
10717      default:
10718           return (int)pSiS->chtvlumabandwidthcvbs;
10719      }
10720   }
10721}
10722
10723void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
10724{
10725   SISPtr pSiS = SISPTR(pScrn);
10726#ifdef SISDUALHEAD
10727   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10728#endif
10729
10730   pSiS->chtvlumabandwidthsvideo = val;
10731#ifdef SISDUALHEAD
10732   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
10733#endif
10734
10735   if(!(pSiS->VBFlags & CRT2_TV)) return;
10736   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10737
10738#ifdef UNLOCK_ALWAYS
10739   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10740#endif
10741
10742   switch(pSiS->ChrontelType) {
10743       case CHRONTEL_700x:
10744           val /= 6;
10745           if((val >= 0) && (val <= 2)) {
10746	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
10747           }
10748	   break;
10749       case CHRONTEL_701x:
10750           val /= 4;
10751	   if((val >= 0) && (val <= 3)) {
10752	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
10753	   }
10754           break;
10755   }
10756}
10757
10758int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
10759{
10760   SISPtr pSiS = SISPTR(pScrn);
10761#ifdef SISDUALHEAD
10762   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10763#endif
10764
10765   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10766#ifdef SISDUALHEAD
10767      if(pSiSEnt && pSiS->DualHeadMode)
10768           return (int)pSiSEnt->chtvlumabandwidthsvideo;
10769      else
10770#endif
10771           return (int)pSiS->chtvlumabandwidthsvideo;
10772   } else {
10773#ifdef UNLOCK_ALWAYS
10774      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10775#endif
10776      switch(pSiS->ChrontelType) {
10777      case CHRONTEL_700x:
10778           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
10779      case CHRONTEL_701x:
10780	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
10781      default:
10782           return (int)pSiS->chtvlumabandwidthsvideo;
10783      }
10784   }
10785}
10786
10787void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
10788{
10789   SISPtr pSiS = SISPTR(pScrn);
10790#ifdef SISDUALHEAD
10791   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10792#endif
10793
10794   pSiS->chtvlumaflickerfilter = val;
10795#ifdef SISDUALHEAD
10796   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
10797#endif
10798
10799   if(!(pSiS->VBFlags & CRT2_TV)) return;
10800   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10801
10802#ifdef UNLOCK_ALWAYS
10803   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10804#endif
10805
10806   switch(pSiS->ChrontelType) {
10807       case CHRONTEL_700x:
10808           val /= 6;
10809           if((val >= 0) && (val <= 2)) {
10810	      UShort reg = 0;
10811	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10812	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
10813              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10814           }
10815	   break;
10816       case CHRONTEL_701x:
10817           val /= 4;
10818	   if((val >= 0) && (val <= 3)) {
10819	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
10820	   }
10821           break;
10822   }
10823}
10824
10825int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
10826{
10827   SISPtr pSiS = SISPTR(pScrn);
10828#ifdef SISDUALHEAD
10829   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10830#endif
10831
10832   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10833#ifdef SISDUALHEAD
10834      if(pSiSEnt && pSiS->DualHeadMode)
10835          return (int)pSiSEnt->chtvlumaflickerfilter;
10836      else
10837#endif
10838          return (int)pSiS->chtvlumaflickerfilter;
10839   } else {
10840#ifdef UNLOCK_ALWAYS
10841      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10842#endif
10843      switch(pSiS->ChrontelType) {
10844      case CHRONTEL_700x:
10845           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
10846      case CHRONTEL_701x:
10847	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
10848      default:
10849           return (int)pSiS->chtvlumaflickerfilter;
10850      }
10851   }
10852}
10853
10854void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
10855{
10856   SISPtr pSiS = SISPTR(pScrn);
10857#ifdef SISDUALHEAD
10858   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10859#endif
10860
10861   pSiS->chtvchromabandwidth = val;
10862#ifdef SISDUALHEAD
10863   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
10864#endif
10865
10866   if(!(pSiS->VBFlags & CRT2_TV)) return;
10867   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10868
10869#ifdef UNLOCK_ALWAYS
10870   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10871#endif
10872
10873   switch(pSiS->ChrontelType) {
10874       case CHRONTEL_700x:
10875           val /= 4;
10876           if((val >= 0) && (val <= 3)) {
10877              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
10878           }
10879	   break;
10880       case CHRONTEL_701x:
10881           val /= 8;
10882	   if((val >= 0) && (val <= 1)) {
10883	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
10884	   }
10885           break;
10886   }
10887}
10888
10889int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
10890{
10891   SISPtr pSiS = SISPTR(pScrn);
10892#ifdef SISDUALHEAD
10893   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10894#endif
10895
10896   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10897#ifdef SISDUALHEAD
10898      if(pSiSEnt && pSiS->DualHeadMode)
10899           return (int)pSiSEnt->chtvchromabandwidth;
10900      else
10901#endif
10902           return (int)pSiS->chtvchromabandwidth;
10903   } else {
10904#ifdef UNLOCK_ALWAYS
10905      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10906#endif
10907      switch(pSiS->ChrontelType) {
10908      case CHRONTEL_700x:
10909           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
10910      case CHRONTEL_701x:
10911	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
10912      default:
10913           return (int)pSiS->chtvchromabandwidth;
10914      }
10915   }
10916}
10917
10918void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
10919{
10920   SISPtr pSiS = SISPTR(pScrn);
10921#ifdef SISDUALHEAD
10922   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10923#endif
10924
10925   pSiS->chtvchromaflickerfilter = val;
10926#ifdef SISDUALHEAD
10927   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
10928#endif
10929
10930   if(!(pSiS->VBFlags & CRT2_TV)) return;
10931   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10932
10933#ifdef UNLOCK_ALWAYS
10934   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10935#endif
10936
10937   switch(pSiS->ChrontelType) {
10938       case CHRONTEL_700x:
10939           val /= 6;
10940           if((val >= 0) && (val <= 2)) {
10941	      UShort reg = 0;
10942	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10943	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
10944              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10945           }
10946	   break;
10947       case CHRONTEL_701x:
10948           val /= 4;
10949	   if((val >= 0) && (val <= 3)) {
10950	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
10951	   }
10952           break;
10953   }
10954}
10955
10956int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
10957{
10958   SISPtr pSiS = SISPTR(pScrn);
10959#ifdef SISDUALHEAD
10960   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10961#endif
10962
10963   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10964#ifdef SISDUALHEAD
10965      if(pSiSEnt && pSiS->DualHeadMode)
10966           return (int)pSiSEnt->chtvchromaflickerfilter;
10967      else
10968#endif
10969           return (int)pSiS->chtvchromaflickerfilter;
10970   } else {
10971#ifdef UNLOCK_ALWAYS
10972      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10973#endif
10974      switch(pSiS->ChrontelType) {
10975      case CHRONTEL_700x:
10976           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
10977      case CHRONTEL_701x:
10978	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
10979      default:
10980           return (int)pSiS->chtvchromaflickerfilter;
10981      }
10982   }
10983}
10984
10985void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
10986{
10987   SISPtr pSiS = SISPTR(pScrn);
10988#ifdef SISDUALHEAD
10989   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10990#endif
10991
10992   pSiS->chtvcvbscolor = val ? 1 : 0;
10993#ifdef SISDUALHEAD
10994   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
10995#endif
10996
10997   if(!(pSiS->VBFlags & CRT2_TV)) return;
10998   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10999
11000#ifdef UNLOCK_ALWAYS
11001   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11002#endif
11003
11004   switch(pSiS->ChrontelType) {
11005       case CHRONTEL_700x:
11006           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
11007           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
11008	   break;
11009       case CHRONTEL_701x:
11010           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
11011	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
11012           break;
11013   }
11014}
11015
11016int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
11017{
11018   SISPtr pSiS = SISPTR(pScrn);
11019#ifdef SISDUALHEAD
11020   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11021#endif
11022
11023   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11024#ifdef SISDUALHEAD
11025      if(pSiSEnt && pSiS->DualHeadMode)
11026           return (int)pSiSEnt->chtvcvbscolor;
11027      else
11028#endif
11029           return (int)pSiS->chtvcvbscolor;
11030   } else {
11031#ifdef UNLOCK_ALWAYS
11032      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11033#endif
11034      switch(pSiS->ChrontelType) {
11035      case CHRONTEL_700x:
11036           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
11037      case CHRONTEL_701x:
11038	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
11039      default:
11040           return (int)pSiS->chtvcvbscolor;
11041      }
11042   }
11043}
11044
11045void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
11046{
11047   SISPtr pSiS = SISPTR(pScrn);
11048#ifdef SISDUALHEAD
11049   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11050#endif
11051
11052   pSiS->chtvtextenhance = val;
11053#ifdef SISDUALHEAD
11054   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
11055#endif
11056
11057   if(!(pSiS->VBFlags & CRT2_TV)) return;
11058   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11059
11060#ifdef UNLOCK_ALWAYS
11061   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11062#endif
11063
11064   switch(pSiS->ChrontelType) {
11065       case CHRONTEL_700x:
11066           val /= 6;
11067           if((val >= 0) && (val <= 2)) {
11068	      UShort reg = 0;
11069	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11070	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
11071              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11072           }
11073	   break;
11074       case CHRONTEL_701x:
11075           val /= 2;
11076	   if((val >= 0) && (val <= 7)) {
11077	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
11078	   }
11079           break;
11080   }
11081}
11082
11083int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
11084{
11085   SISPtr pSiS = SISPTR(pScrn);
11086#ifdef SISDUALHEAD
11087   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11088#endif
11089
11090   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11091#ifdef SISDUALHEAD
11092      if(pSiSEnt && pSiS->DualHeadMode)
11093           return (int)pSiSEnt->chtvtextenhance;
11094      else
11095#endif
11096           return (int)pSiS->chtvtextenhance;
11097   } else {
11098#ifdef UNLOCK_ALWAYS
11099      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11100#endif
11101      switch(pSiS->ChrontelType) {
11102      case CHRONTEL_700x:
11103	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
11104      case CHRONTEL_701x:
11105	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
11106      default:
11107           return (int)pSiS->chtvtextenhance;
11108      }
11109   }
11110}
11111
11112void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
11113{
11114   SISPtr pSiS = SISPTR(pScrn);
11115#ifdef SISDUALHEAD
11116   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11117#endif
11118
11119   pSiS->chtvcontrast = val;
11120#ifdef SISDUALHEAD
11121   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
11122#endif
11123
11124   if(!(pSiS->VBFlags & CRT2_TV)) return;
11125   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11126
11127#ifdef UNLOCK_ALWAYS
11128   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11129#endif
11130
11131   val /= 2;
11132   if((val >= 0) && (val <= 7)) {
11133       switch(pSiS->ChrontelType) {
11134       case CHRONTEL_700x:
11135              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
11136	      break;
11137       case CHRONTEL_701x:
11138	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
11139              break;
11140       }
11141       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
11142   }
11143}
11144
11145int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
11146{
11147   SISPtr pSiS = SISPTR(pScrn);
11148#ifdef SISDUALHEAD
11149   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11150#endif
11151
11152   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11153#ifdef SISDUALHEAD
11154      if(pSiSEnt && pSiS->DualHeadMode)
11155           return (int)pSiSEnt->chtvcontrast;
11156      else
11157#endif
11158           return (int)pSiS->chtvcontrast;
11159   } else {
11160#ifdef UNLOCK_ALWAYS
11161      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11162#endif
11163      switch(pSiS->ChrontelType) {
11164      case CHRONTEL_700x:
11165           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
11166      case CHRONTEL_701x:
11167	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
11168      default:
11169           return (int)pSiS->chtvcontrast;
11170      }
11171   }
11172}
11173
11174void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
11175{
11176   SISPtr pSiS = SISPTR(pScrn);
11177#ifdef SISDUALHEAD
11178   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11179#endif
11180
11181   pSiS->sistvedgeenhance = val;
11182#ifdef SISDUALHEAD
11183   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
11184#endif
11185
11186   if(!(pSiS->VBFlags2 & VB2_301))  return;
11187   if(!(pSiS->VBFlags & CRT2_TV))   return;
11188
11189#ifdef UNLOCK_ALWAYS
11190   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11191#endif
11192
11193   val /= 2;
11194   if((val >= 0) && (val <= 7)) {
11195      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
11196   }
11197}
11198
11199int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
11200{
11201   SISPtr pSiS = SISPTR(pScrn);
11202   int result = pSiS->sistvedgeenhance;
11203   UChar temp;
11204#ifdef SISDUALHEAD
11205   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11206
11207   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
11208#endif
11209
11210   if(!(pSiS->VBFlags2 & VB2_301))  return result;
11211   if(!(pSiS->VBFlags & CRT2_TV))   return result;
11212
11213#ifdef UNLOCK_ALWAYS
11214   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11215#endif
11216   inSISIDXREG(SISPART2, 0x3a, temp);
11217   return(int)(((temp & 0xe0) >> 5) * 2);
11218}
11219
11220void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
11221{
11222   SISPtr pSiS = SISPTR(pScrn);
11223#ifdef SISDUALHEAD
11224   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11225#endif
11226
11227   pSiS->sistvantiflicker = val;
11228#ifdef SISDUALHEAD
11229   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
11230#endif
11231
11232   if(!(pSiS->VBFlags & CRT2_TV))      return;
11233   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11234   if(pSiS->VBFlags & TV_HIVISION)     return;
11235   if((pSiS->VBFlags & TV_YPBPR) &&
11236      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
11237
11238#ifdef UNLOCK_ALWAYS
11239   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11240#endif
11241
11242   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11243   if((val >= 0) && (val <= 4)) {
11244      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
11245   }
11246}
11247
11248int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
11249{
11250   SISPtr pSiS = SISPTR(pScrn);
11251   int result = pSiS->sistvantiflicker;
11252   UChar temp;
11253#ifdef SISDUALHEAD
11254   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11255
11256   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
11257#endif
11258
11259   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11260   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11261   if(pSiS->VBFlags & TV_HIVISION)       return result;
11262   if((pSiS->VBFlags & TV_YPBPR) &&
11263      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
11264
11265#ifdef UNLOCK_ALWAYS
11266   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11267#endif
11268   inSISIDXREG(SISPART2, 0x0a, temp);
11269   return(int)((temp & 0x70) >> 4);
11270}
11271
11272void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
11273{
11274   SISPtr pSiS = SISPTR(pScrn);
11275#ifdef SISDUALHEAD
11276   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11277#endif
11278
11279   pSiS->sistvsaturation = val;
11280#ifdef SISDUALHEAD
11281   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
11282#endif
11283
11284   if(!(pSiS->VBFlags & CRT2_TV)) return;
11285   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11286   if(pSiS->VBFlags2 & VB2_301) return;
11287
11288#ifdef UNLOCK_ALWAYS
11289   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11290#endif
11291
11292   val /= 2;
11293   if((val >= 0) && (val <= 7)) {
11294      setSISIDXREG(SISPART4,0x21,0xF8, val);
11295   }
11296}
11297
11298int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
11299{
11300   SISPtr pSiS = SISPTR(pScrn);
11301   int result = pSiS->sistvsaturation;
11302   UChar temp;
11303#ifdef SISDUALHEAD
11304   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11305
11306   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
11307#endif
11308
11309   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11310   if(pSiS->VBFlags2 & VB2_301)          return result;
11311   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11312
11313#ifdef UNLOCK_ALWAYS
11314   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11315#endif
11316   inSISIDXREG(SISPART4, 0x21, temp);
11317   return(int)((temp & 0x07) * 2);
11318}
11319
11320void SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
11321{
11322   SISPtr pSiS = SISPTR(pScrn);
11323#ifdef SISDUALHEAD
11324   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11325#endif
11326   int ccoarse, cfine, cbase = pSiS->sistvccbase;
11327   /* UChar temp; */
11328
11329#ifdef SISDUALHEAD
11330   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
11331#endif
11332
11333   if(coarse) {
11334      pSiS->sistvcolcalibc = ccoarse = val;
11335      cfine = pSiS->sistvcolcalibf;
11336#ifdef SISDUALHEAD
11337      if(pSiSEnt) {
11338         pSiSEnt->sistvcolcalibc = val;
11339	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
11340      }
11341#endif
11342   } else {
11343      pSiS->sistvcolcalibf = cfine = val;
11344      ccoarse = pSiS->sistvcolcalibc;
11345#ifdef SISDUALHEAD
11346      if(pSiSEnt) {
11347         pSiSEnt->sistvcolcalibf = val;
11348         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
11349      }
11350#endif
11351   }
11352
11353   if(!(pSiS->VBFlags & CRT2_TV))               return;
11354   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11355   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11356
11357#ifdef UNLOCK_ALWAYS
11358   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11359#endif
11360
11361   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
11362      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
11363
11364#if 0
11365      inSISIDXREG(SISPART4,0x1f,temp);
11366      if(!(temp & 0x01)) {
11367         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
11368	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11369	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11370	 else finalcc += 0x2a05d300;
11371      }
11372#endif
11373      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
11374      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
11375      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
11376      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
11377   }
11378}
11379
11380int SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
11381{
11382   SISPtr pSiS = SISPTR(pScrn);
11383#ifdef SISDUALHEAD
11384   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11385
11386   if(pSiSEnt && pSiS->DualHeadMode)
11387      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
11388      else        return (int)pSiSEnt->sistvcolcalibf;
11389   else
11390#endif
11391   if(coarse)     return (int)pSiS->sistvcolcalibc;
11392   else           return (int)pSiS->sistvcolcalibf;
11393}
11394
11395void SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
11396{
11397   SISPtr pSiS = SISPTR(pScrn);
11398#ifdef SISDUALHEAD
11399   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11400#endif
11401
11402   pSiS->sistvcfilter = val ? 1 : 0;
11403#ifdef SISDUALHEAD
11404   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
11405#endif
11406
11407   if(!(pSiS->VBFlags & CRT2_TV))               return;
11408   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11409   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11410
11411#ifdef UNLOCK_ALWAYS
11412   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11413#endif
11414
11415   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
11416}
11417
11418int SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
11419{
11420   SISPtr pSiS = SISPTR(pScrn);
11421   int result = pSiS->sistvcfilter;
11422   UChar temp;
11423#ifdef SISDUALHEAD
11424   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11425
11426   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
11427#endif
11428
11429   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
11430   if(!(pSiS->VBFlags & CRT2_TV))               return result;
11431   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
11432
11433#ifdef UNLOCK_ALWAYS
11434   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11435#endif
11436   inSISIDXREG(SISPART2, 0x30, temp);
11437   return (int)((temp & 0x10) ? 1 : 0);
11438}
11439
11440void SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
11441{
11442   SISPtr pSiS = SISPTR(pScrn);
11443#ifdef SISDUALHEAD
11444   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11445#endif
11446   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
11447   int i,j;
11448
11449   pSiS->sistvyfilter = val;
11450#ifdef SISDUALHEAD
11451   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
11452#endif
11453
11454   if(!(pSiS->VBFlags & CRT2_TV))               return;
11455   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11456   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11457
11458   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
11459   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
11460   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
11461   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
11462#ifdef SISDUALHEAD
11463   if(pSiSEnt && pSiS->DualHeadMode) {
11464      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
11465      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
11466      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
11467      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
11468   }
11469#endif
11470   p30 &= 0x20;
11471
11472#ifdef UNLOCK_ALWAYS
11473   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11474#endif
11475
11476   switch(pSiS->sistvyfilter) {
11477   case 0:
11478      andSISIDXREG(SISPART2,0x30,0xdf);
11479      break;
11480   case 1:
11481      outSISIDXREG(SISPART2,0x35,p35);
11482      outSISIDXREG(SISPART2,0x36,p36);
11483      outSISIDXREG(SISPART2,0x37,p37);
11484      outSISIDXREG(SISPART2,0x38,p38);
11485      if(!(pSiS->VBFlags2 & VB2_301)) {
11486         outSISIDXREG(SISPART2,0x48,p48);
11487         outSISIDXREG(SISPART2,0x49,p49);
11488         outSISIDXREG(SISPART2,0x4a,p4a);
11489      }
11490      setSISIDXREG(SISPART2,0x30,0xdf,p30);
11491      break;
11492   case 2:
11493   case 3:
11494   case 4:
11495   case 5:
11496   case 6:
11497   case 7:
11498   case 8:
11499      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
11500         int yindex301 = -1, yindex301B = -1;
11501	 UChar p3d4_34;
11502
11503	 inSISIDXREG(SISCR,0x34,p3d4_34);
11504
11505	 switch((p3d4_34 & 0x7f)) {
11506	 case 0x59:  /* 320x200 */
11507	 case 0x41:
11508	 case 0x4f:
11509	 case 0x50:  /* 320x240 */
11510	 case 0x56:
11511	 case 0x53:
11512	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11513	    break;
11514	 case 0x2f:  /* 640x400 */
11515	 case 0x5d:
11516	 case 0x5e:
11517	 case 0x2e:  /* 640x480 */
11518	 case 0x44:
11519	 case 0x62:
11520	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11521	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11522	    break;
11523	 case 0x31:   /* 720x480 */
11524	 case 0x33:
11525	 case 0x35:
11526	 case 0x32:   /* 720x576 */
11527	 case 0x34:
11528	 case 0x36:
11529	 case 0x5f:   /* 768x576 */
11530	 case 0x60:
11531	 case 0x61:
11532	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11533	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11534	    break;
11535	 case 0x51:   /* 400x300 */
11536	 case 0x57:
11537	 case 0x54:
11538	 case 0x30:   /* 800x600 */
11539	 case 0x47:
11540	 case 0x63:
11541	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11542	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11543	    break;
11544	 case 0x52:   /* 512x384 */
11545	 case 0x58:
11546	 case 0x5c:
11547	 case 0x38:   /* 1024x768 */
11548	 case 0x4a:
11549	 case 0x64:
11550	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11551	    break;
11552	 }
11553         if(pSiS->VBFlags2 & VB2_301) {
11554            if(yindex301 >= 0) {
11555	       for(i=0, j=0x35; i<=3; i++, j++) {
11556	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
11557	       }
11558	    }
11559         } else {
11560            if(yindex301B >= 0) {
11561	       for(i=0, j=0x35; i<=3; i++, j++) {
11562	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11563	       }
11564	       for(i=4, j=0x48; i<=6; i++, j++) {
11565	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11566	       }
11567	    }
11568         }
11569         orSISIDXREG(SISPART2,0x30,0x20);
11570      }
11571   }
11572}
11573
11574int SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
11575{
11576   SISPtr pSiS = SISPTR(pScrn);
11577#ifdef SISDUALHEAD
11578   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11579
11580   if(pSiSEnt && pSiS->DualHeadMode)
11581      return (int)pSiSEnt->sistvyfilter;
11582   else
11583#endif
11584      return (int)pSiS->sistvyfilter;
11585}
11586
11587void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
11588{
11589   SISPtr pSiS = SISPTR(pScrn);
11590   UChar tmp;
11591
11592   pSiS->sistvantiflicker = val;
11593
11594   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11595
11596#ifdef UNLOCK_ALWAYS
11597   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11598#endif
11599
11600   tmp = SiS6326GetTVReg(pScrn,0x00);
11601   if(!(tmp & 0x04)) return;
11602
11603   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11604   if(val >= 0 && val <= 4) {
11605      tmp &= 0x1f;
11606      tmp |= (val << 5);
11607      SiS6326SetTVReg(pScrn,0x00,tmp);
11608   }
11609}
11610
11611int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
11612{
11613   SISPtr pSiS = SISPTR(pScrn);
11614   UChar tmp;
11615
11616   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11617      return (int)pSiS->sistvantiflicker;
11618   }
11619
11620#ifdef UNLOCK_ALWAYS
11621   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11622#endif
11623
11624   tmp = SiS6326GetTVReg(pScrn,0x00);
11625   if(!(tmp & 0x04)) {
11626      return (int)pSiS->sistvantiflicker;
11627   } else {
11628      return (int)((tmp >> 5) & 0x07);
11629   }
11630}
11631
11632void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
11633{
11634   SISPtr pSiS = SISPTR(pScrn);
11635   UChar tmp;
11636
11637   if(val) val = 1;
11638   pSiS->sis6326enableyfilter = val;
11639
11640   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11641
11642#ifdef UNLOCK_ALWAYS
11643   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11644#endif
11645
11646   tmp = SiS6326GetTVReg(pScrn,0x00);
11647   if(!(tmp & 0x04)) return;
11648
11649   tmp = SiS6326GetTVReg(pScrn,0x43);
11650   tmp &= ~0x10;
11651   tmp |= ((val & 0x01) << 4);
11652   SiS6326SetTVReg(pScrn,0x43,tmp);
11653}
11654
11655int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
11656{
11657   SISPtr pSiS = SISPTR(pScrn);
11658   UChar tmp;
11659
11660   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11661      return (int)pSiS->sis6326enableyfilter;
11662   }
11663
11664#ifdef UNLOCK_ALWAYS
11665   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11666#endif
11667
11668   tmp = SiS6326GetTVReg(pScrn,0x00);
11669   if(!(tmp & 0x04)) {
11670      return (int)pSiS->sis6326enableyfilter;
11671   } else {
11672      tmp = SiS6326GetTVReg(pScrn,0x43);
11673      return (int)((tmp >> 4) & 0x01);
11674   }
11675}
11676
11677void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
11678{
11679   SISPtr pSiS = SISPTR(pScrn);
11680   UChar tmp;
11681
11682   if(val) val = 1;
11683   pSiS->sis6326yfilterstrong = val;
11684
11685   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11686
11687#ifdef UNLOCK_ALWAYS
11688   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11689#endif
11690
11691   tmp = SiS6326GetTVReg(pScrn,0x00);
11692   if(!(tmp & 0x04)) return;
11693
11694   tmp = SiS6326GetTVReg(pScrn,0x43);
11695   if(tmp & 0x10) {
11696      tmp &= ~0x40;
11697      tmp |= ((val & 0x01) << 6);
11698      SiS6326SetTVReg(pScrn,0x43,tmp);
11699   }
11700}
11701
11702int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
11703{
11704   SISPtr pSiS = SISPTR(pScrn);
11705   UChar tmp;
11706
11707   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11708      return (int)pSiS->sis6326yfilterstrong;
11709   }
11710
11711#ifdef UNLOCK_ALWAYS
11712   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11713#endif
11714
11715   tmp = SiS6326GetTVReg(pScrn,0x00);
11716   if(!(tmp & 0x04)) {
11717      return (int)pSiS->sis6326yfilterstrong;
11718   } else {
11719      tmp = SiS6326GetTVReg(pScrn,0x43);
11720      if(!(tmp & 0x10)) {
11721         return (int)pSiS->sis6326yfilterstrong;
11722      } else {
11723         return (int)((tmp >> 6) & 0x01);
11724      }
11725   }
11726}
11727
11728void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
11729{
11730   SISPtr pSiS = SISPTR(pScrn);
11731#ifdef SISDUALHEAD
11732   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11733#endif
11734
11735#ifdef UNLOCK_ALWAYS
11736   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11737#endif
11738
11739   pSiS->tvxpos = val;
11740#ifdef SISDUALHEAD
11741   if(pSiSEnt) pSiSEnt->tvxpos = val;
11742#endif
11743
11744   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11745
11746      if(pSiS->VBFlags & CRT2_TV) {
11747
11748         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11749
11750	    int x = pSiS->tvx;
11751#ifdef SISDUALHEAD
11752	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
11753#endif
11754	    switch(pSiS->ChrontelType) {
11755	    case CHRONTEL_700x:
11756	       if((val >= -32) && (val <= 32)) {
11757		   x += val;
11758		   if(x < 0) x = 0;
11759		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
11760		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
11761	       }
11762	       break;
11763	    case CHRONTEL_701x:
11764	       /* Not supported by hardware */
11765	       break;
11766	    }
11767
11768	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11769
11770	    if((val >= -32) && (val <= 32)) {
11771
11772	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
11773		UShort temp;
11774		int mult;
11775
11776		p2_1f = pSiS->p2_1f;
11777		p2_20 = pSiS->p2_20;
11778		p2_2b = pSiS->p2_2b;
11779		p2_42 = pSiS->p2_42;
11780		p2_43 = pSiS->p2_43;
11781#ifdef SISDUALHEAD
11782	        if(pSiSEnt && pSiS->DualHeadMode) {
11783		   p2_1f = pSiSEnt->p2_1f;
11784		   p2_20 = pSiSEnt->p2_20;
11785		   p2_2b = pSiSEnt->p2_2b;
11786		   p2_42 = pSiSEnt->p2_42;
11787		   p2_43 = pSiSEnt->p2_43;
11788		}
11789#endif
11790		mult = 2;
11791		if(pSiS->VBFlags & TV_YPBPR) {
11792		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
11793		      mult = 4;
11794		   }
11795		}
11796
11797		temp = p2_1f | ((p2_20 & 0xf0) << 4);
11798		temp += (val * mult);
11799		p2_1f = temp & 0xff;
11800		p2_20 = (temp & 0xf00) >> 4;
11801		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
11802		temp = p2_43 | ((p2_42 & 0xf0) << 4);
11803		temp += (val * mult);
11804		p2_43 = temp & 0xff;
11805		p2_42 = (temp & 0xf00) >> 4;
11806		SISWaitRetraceCRT2(pScrn);
11807	        outSISIDXREG(SISPART2,0x1f,p2_1f);
11808		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
11809		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
11810		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
11811		outSISIDXREG(SISPART2,0x43,p2_43);
11812	     }
11813	 }
11814      }
11815
11816   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11817
11818      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11819
11820         UChar tmp;
11821	 UShort temp1, temp2, temp3;
11822
11823         tmp = SiS6326GetTVReg(pScrn,0x00);
11824         if(tmp & 0x04) {
11825
11826	    temp1 = pSiS->tvx1;
11827            temp2 = pSiS->tvx2;
11828            temp3 = pSiS->tvx3;
11829            if((val >= -16) && (val <= 16)) {
11830	       if(val > 0) {
11831	          temp1 += (val * 4);
11832	          temp2 += (val * 4);
11833	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
11834	             temp1 -= 4;
11835		     temp2 -= 4;
11836	          }
11837	       } else {
11838	          val = -val;
11839	          temp3 += (val * 4);
11840	          while(temp3 > 0x03ff) {
11841	     	     temp3 -= 4;
11842	          }
11843	       }
11844            }
11845            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
11846            tmp = SiS6326GetTVReg(pScrn,0x3c);
11847            tmp &= 0xf0;
11848            tmp |= ((temp1 & 0x0f00) >> 8);
11849            SiS6326SetTVReg(pScrn,0x3c,tmp);
11850            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
11851            tmp = SiS6326GetTVReg(pScrn,0x27);
11852            tmp &= 0x0f;
11853            tmp |= ((temp2 & 0x0f00) >> 4);
11854            SiS6326SetTVReg(pScrn,0x27,tmp);
11855            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
11856            tmp = SiS6326GetTVReg(pScrn,0x13);
11857            tmp &= ~0xC0;
11858            tmp |= ((temp3 & 0x0300) >> 2);
11859            SiS6326SetTVReg(pScrn,0x13,tmp);
11860	 }
11861      }
11862   }
11863}
11864
11865int SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
11866{
11867   SISPtr pSiS = SISPTR(pScrn);
11868#ifdef SISDUALHEAD
11869   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11870
11871   if(pSiSEnt && pSiS->DualHeadMode)
11872        return (int)pSiSEnt->tvxpos;
11873   else
11874#endif
11875        return (int)pSiS->tvxpos;
11876}
11877
11878void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
11879{
11880   SISPtr pSiS = SISPTR(pScrn);
11881#ifdef SISDUALHEAD
11882   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11883#endif
11884
11885#ifdef UNLOCK_ALWAYS
11886   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11887#endif
11888
11889   pSiS->tvypos = val;
11890#ifdef SISDUALHEAD
11891   if(pSiSEnt) pSiSEnt->tvypos = val;
11892#endif
11893
11894   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11895
11896      if(pSiS->VBFlags & CRT2_TV) {
11897
11898         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11899
11900	    int y = pSiS->tvy;
11901#ifdef SISDUALHEAD
11902	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
11903#endif
11904	    switch(pSiS->ChrontelType) {
11905	    case CHRONTEL_700x:
11906	       if((val >= -32) && (val <= 32)) {
11907		   y -= val;
11908		   if(y < 0) y = 0;
11909		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
11910		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
11911	       }
11912	       break;
11913	    case CHRONTEL_701x:
11914	       /* Not supported by hardware */
11915	       break;
11916	    }
11917
11918	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11919
11920	    if((val >= -32) && (val <= 32)) {
11921		char p2_01, p2_02;
11922
11923		if( (pSiS->VBFlags & TV_HIVISION) ||
11924		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
11925		   val *= 2;
11926		} else {
11927		   val /= 2;  /* 4 */
11928		}
11929
11930		p2_01 = pSiS->p2_01;
11931		p2_02 = pSiS->p2_02;
11932#ifdef SISDUALHEAD
11933	        if(pSiSEnt && pSiS->DualHeadMode) {
11934		   p2_01 = pSiSEnt->p2_01;
11935		   p2_02 = pSiSEnt->p2_02;
11936		}
11937#endif
11938		p2_01 += val; /* val * 2 */
11939		p2_02 += val; /* val * 2 */
11940		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
11941		   while((p2_01 <= 0) || (p2_02 <= 0)) {
11942		      p2_01 += 2;
11943		      p2_02 += 2;
11944		   }
11945		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
11946		   while(p2_01 <= 8) {
11947		      p2_01 += 2;
11948		      p2_02 += 2;
11949		   }
11950		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
11951		   while(p2_01 <= 10) {
11952		      p2_01 += 2;
11953		      p2_02 += 2;
11954		   }
11955		}
11956
11957		SISWaitRetraceCRT2(pScrn);
11958		outSISIDXREG(SISPART2,0x01,p2_01);
11959		outSISIDXREG(SISPART2,0x02,p2_02);
11960	     }
11961	 }
11962
11963      }
11964
11965   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11966
11967      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11968
11969         UChar tmp;
11970	 int temp1, limit;
11971
11972         tmp = SiS6326GetTVReg(pScrn,0x00);
11973         if(tmp & 0x04) {
11974
11975	    if((val >= -16) && (val <= 16)) {
11976	      temp1 = (UShort)pSiS->tvy1;
11977	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
11978	      if(val > 0) {
11979                temp1 += (val * 4);
11980	        if(temp1 > limit) temp1 -= limit;
11981	      } else {
11982	        val = -val;
11983	        temp1 -= (val * 2);
11984	        if(temp1 <= 0) temp1 += (limit -1);
11985	      }
11986	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
11987	      tmp = SiS6326GetTVReg(pScrn,0x13);
11988	      tmp &= ~0x30;
11989	      tmp |= ((temp1 & 0x300) >> 4);
11990	      SiS6326SetTVReg(pScrn,0x13,tmp);
11991	      if(temp1 == 1)                                 tmp = 0x10;
11992	      else {
11993	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
11994	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
11995	         else if(temp1 < 22)		 	     tmp = 0x02;
11996	         else 					     tmp = 0x04;
11997	       } else {
11998	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
11999	         else if(temp1 < 19)			     tmp = 0x02;
12000	         else 					     tmp = 0x04;
12001	       }
12002	     }
12003	     SiS6326SetTVReg(pScrn,0x21,tmp);
12004           }
12005	 }
12006      }
12007   }
12008}
12009
12010int SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
12011{
12012   SISPtr pSiS = SISPTR(pScrn);
12013#ifdef SISDUALHEAD
12014   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12015
12016   if(pSiSEnt && pSiS->DualHeadMode)
12017        return (int)pSiSEnt->tvypos;
12018   else
12019#endif
12020        return (int)pSiS->tvypos;
12021}
12022
12023void SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
12024{
12025   SISPtr pSiS = SISPTR(pScrn);
12026#ifdef SISDUALHEAD
12027   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12028#endif
12029
12030#ifdef UNLOCK_ALWAYS
12031   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12032#endif
12033
12034   pSiS->tvxscale = val;
12035#ifdef SISDUALHEAD
12036   if(pSiSEnt) pSiSEnt->tvxscale = val;
12037#endif
12038
12039   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12040
12041      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12042
12043	 if((val >= -16) && (val <= 16)) {
12044
12045	    UChar p2_44,p2_45,p2_46;
12046	    int scalingfactor, mult;
12047
12048	    p2_44 = pSiS->p2_44;
12049	    p2_45 = pSiS->p2_45 & 0x3f;
12050	    p2_46 = pSiS->p2_46 & 0x07;
12051#ifdef SISDUALHEAD
12052	    if(pSiSEnt && pSiS->DualHeadMode) {
12053	       p2_44 = pSiSEnt->p2_44;
12054	       p2_45 = pSiSEnt->p2_45 & 0x3f;
12055	       p2_46 = pSiSEnt->p2_46 & 0x07;
12056	    }
12057#endif
12058	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
12059
12060	    mult = 64;
12061	    if(pSiS->VBFlags & TV_YPBPR) {
12062	       if(pSiS->VBFlags & TV_YPBPR1080I) {
12063	          mult = 190;
12064	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
12065	          mult = 360;
12066	       }
12067	    } else if(pSiS->VBFlags & TV_HIVISION) {
12068	       mult = 190;
12069	    }
12070
12071	    if(val < 0) {
12072	       p2_45 &= 0xdf;
12073	       scalingfactor += ((-val) * mult);
12074	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
12075	    } else if(val > 0) {
12076	       p2_45 &= 0xdf;
12077	       scalingfactor -= (val * mult);
12078	       if(scalingfactor < 1) scalingfactor = 1;
12079	    }
12080
12081	    p2_44 = scalingfactor & 0xff;
12082	    p2_45 &= 0xe0;
12083	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
12084	    p2_46 = ((scalingfactor >> 13) & 0x07);
12085
12086	    SISWaitRetraceCRT2(pScrn);
12087	    outSISIDXREG(SISPART2,0x44,p2_44);
12088	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
12089	    if(!(pSiS->VBFlags2 & VB2_301)) {
12090	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
12091	    }
12092
12093	 }
12094
12095      }
12096
12097   }
12098}
12099
12100int SiS_GetTVxscale(ScrnInfoPtr pScrn)
12101{
12102   SISPtr pSiS = SISPTR(pScrn);
12103#ifdef SISDUALHEAD
12104   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12105
12106   if(pSiSEnt && pSiS->DualHeadMode)
12107        return (int)pSiSEnt->tvxscale;
12108   else
12109#endif
12110        return (int)pSiS->tvxscale;
12111}
12112
12113void SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
12114{
12115   SISPtr pSiS = SISPTR(pScrn);
12116#ifdef SISDUALHEAD
12117   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12118#endif
12119
12120#ifdef UNLOCK_ALWAYS
12121   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12122#endif
12123
12124   if(val < -4) val = -4;
12125   if(val > 3)  val = 3;
12126
12127   pSiS->tvyscale = val;
12128#ifdef SISDUALHEAD
12129   if(pSiSEnt) pSiSEnt->tvyscale = val;
12130#endif
12131
12132   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12133
12134      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12135
12136	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
12137	 int hdclk = 0;
12138	 UChar p3d4_34;
12139	 Bool found = FALSE;
12140	 Bool usentsc = FALSE;
12141	 Bool is750p = FALSE;
12142	 Bool is1080i = FALSE;
12143	 Bool skipmoveup = FALSE;
12144
12145	 SiS_UnLockCRT2(pSiS->SiS_Pr);
12146
12147	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
12148	    vlimit = 525 - 7;
12149	    vdediv = 1;
12150	    usentsc = TRUE;
12151	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
12152	    vlimit = 625 - 7;
12153	    vdediv = 1;
12154	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12155	    vlimit = 750 - 7;
12156	    vdediv = 1;
12157	    is750p = TRUE;
12158	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
12159	           (pSiS->VBFlags & TV_HIVISION)) {
12160	    vlimit = (1125 - 7) / 2;
12161	    vdediv = 2;
12162	    is1080i = TRUE;
12163	 } else {
12164	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
12165	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
12166	       usentsc = TRUE;
12167	    }
12168	    vlimit = usentsc ? 259 : 309;
12169	    vdediv = 2;
12170	 }
12171
12172	 inSISIDXREG(SISCR,0x34,p3d4_34);
12173
12174	 switch((p3d4_34 & 0x7f)) {
12175	 case 0x50:   /* 320x240 */
12176	 case 0x56:
12177	 case 0x53:
12178	    hdclk = 1;
12179	    /* fall through */
12180	 case 0x2e:   /* 640x480 */
12181	 case 0x44:
12182	 case 0x62:
12183	    if(is1080i) {
12184	       srindex = 98;
12185	    } else if(is750p) {
12186	       srindex = 42;
12187	    } else {
12188	       srindex  = usentsc ? 0 : 21;
12189	    }
12190	    break;
12191	 case 0x31:   /* 720x480 */
12192	 case 0x33:
12193	 case 0x35:
12194	    if(is1080i) {
12195	       /* n/a */
12196	    } else if(is750p) {
12197	       srindex = 49;
12198	    } else {
12199	       srindex = usentsc ? 7 : 21;
12200	    }
12201	    break;
12202	 case 0x32:   /* 720x576 */
12203	 case 0x34:
12204	 case 0x36:
12205	 case 0x5f:   /* 768x576 */
12206	 case 0x60:
12207	 case 0x61:
12208	    if(is1080i) {
12209	       /* n/a */
12210	    } else if(is750p) {
12211	       srindex = 56;
12212	    } else {
12213	       srindex  = usentsc ? 147 : 28;
12214	    }
12215	    break;
12216	 case 0x70:   /* 800x480 */
12217	 case 0x7a:
12218	 case 0x76:
12219	    if(is1080i) {
12220	       srindex = 105;
12221	    } else if(is750p) {
12222	       srindex = 63;
12223	    } else {
12224	       srindex = usentsc ? 175 : 21;
12225	    }
12226	    break;
12227	 case 0x51:   /* 400x300 - hdclk mode */
12228	 case 0x57:
12229	 case 0x54:
12230	    hdclk = 1;
12231	    /* fall through */
12232	 case 0x30:   /* 800x600 */
12233	 case 0x47:
12234	 case 0x63:
12235	    if(is1080i) {
12236	       srindex = 112;
12237	    } else if(is750p) {
12238	       srindex = 70;
12239	    } else {
12240	       srindex = usentsc ? 14 : 35;
12241	    }
12242	    break;
12243	 case 0x1d:	/* 960x540 */
12244	 case 0x1e:
12245	 case 0x1f:
12246	    if(is1080i) {
12247	       srindex = 196;
12248	       skipmoveup = TRUE;
12249	    }
12250	    break;
12251	 case 0x20:	/* 960x600 */
12252	 case 0x21:
12253	 case 0x22:
12254	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
12255	       srindex = 203;
12256	    }
12257	    break;
12258	 case 0x71:	/* 1024x576 */
12259	 case 0x74:
12260	 case 0x77:
12261	    if(is1080i) {
12262	       srindex = 119;
12263	    } else if(is750p) {
12264	       srindex = 77;
12265	    } else {
12266	       srindex  = usentsc ? 182 : 189;
12267	    }
12268	    break;
12269	 case 0x52:	/* 512x384 */
12270	 case 0x58:
12271	 case 0x5c:
12272	    hdclk = 1;
12273	    /* fall through */
12274	 case 0x38:	/* 1024x768 */
12275	 case 0x4a:
12276	 case 0x64:
12277	    if(is1080i) {
12278	       srindex = 126;
12279	    } else if(is750p) {
12280	       srindex = 84;
12281	    } else if(!usentsc) {
12282	       srindex = 154;
12283	    } else if(vdediv == 1) {
12284	       if(!hdclk) srindex = 168;
12285	    } else {
12286	       if(!hdclk) srindex = 161;
12287	    }
12288	    break;
12289	 case 0x79:	/* 1280x720 */
12290	 case 0x75:
12291	 case 0x78:
12292	    if(is1080i) {
12293	       srindex = 133;
12294	    } else if(is750p) {
12295	       srindex = 91;
12296	    }
12297	    break;
12298	 case 0x3a:	/* 1280x1024 */
12299	 case 0x4d:
12300	 case 0x65:
12301	    if(is1080i) {
12302	       srindex = 140;
12303	    }
12304	    break;
12305	 }
12306
12307	 if(srindex < 0) return;
12308
12309	 if(pSiS->tvyscale != 0) {
12310	    for(j = 0; j <= 1; j++) {
12311	       for(i = 0; i <= 6; i++) {
12312		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
12313		     found = TRUE;
12314		     break;
12315		  }
12316	       }
12317	       if(found) break;
12318	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
12319	       else pSiS->tvyscale++;
12320	    }
12321	 }
12322
12323#ifdef SISDUALHEAD
12324	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
12325#endif
12326
12327	 if(pSiS->tvyscale == 0) {
12328	    UChar p2_0a = pSiS->p2_0a;
12329	    UChar p2_2f = pSiS->p2_2f;
12330	    UChar p2_30 = pSiS->p2_30;
12331	    UChar p2_46 = pSiS->p2_46;
12332	    UChar p2_47 = pSiS->p2_47;
12333	    UChar p1scaling[9], p4scaling[9];
12334	    UChar *p2scaling;
12335
12336	    for(i = 0; i < 9; i++) {
12337	        p1scaling[i] = pSiS->scalingp1[i];
12338		p4scaling[i] = pSiS->scalingp4[i];
12339	    }
12340	    p2scaling = &pSiS->scalingp2[0];
12341
12342#ifdef SISDUALHEAD
12343	    if(pSiSEnt && pSiS->DualHeadMode) {
12344	       p2_0a = pSiSEnt->p2_0a;
12345	       p2_2f = pSiSEnt->p2_2f;
12346	       p2_30 = pSiSEnt->p2_30;
12347	       p2_46 = pSiSEnt->p2_46;
12348	       p2_47 = pSiSEnt->p2_47;
12349	       for(i = 0; i < 9; i++) {
12350		  p1scaling[i] = pSiSEnt->scalingp1[i];
12351		  p4scaling[i] = pSiSEnt->scalingp4[i];
12352	       }
12353	       p2scaling = &pSiSEnt->scalingp2[0];
12354	    }
12355#endif
12356            SISWaitRetraceCRT2(pScrn);
12357	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12358	       for(i = 0; i < 64; i++) {
12359	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
12360	       }
12361	    }
12362	    for(i = 0; i < 9; i++) {
12363	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
12364	    }
12365	    for(i = 0; i < 9; i++) {
12366	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
12367	    }
12368
12369	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
12370	    outSISIDXREG(SISPART2,0x2f,p2_2f);
12371	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
12372	    if(!(pSiS->VBFlags2 & VB2_301)) {
12373	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
12374	       outSISIDXREG(SISPART2,0x47,p2_47);
12375	    }
12376
12377	 } else {
12378
12379	    int realvde, myypos, watchdog = 32;
12380	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
12381	    int p1div = 1;
12382	    ULong calctemp;
12383
12384	    srindex += i;
12385	    newvde = SiSTVVScale[srindex].ScaleVDE;
12386	    realvde = SiSTVVScale[srindex].RealVDE;
12387
12388	    if(vdediv == 1) p1div = 2;
12389
12390	    if(!skipmoveup) {
12391	       do {
12392	          inSISIDXREG(SISPART2,0x01,temp);
12393	          temp = vlimit - ((temp & 0x7f) / p1div);
12394	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
12395	          myypos = pSiS->tvypos - 1;
12396#ifdef SISDUALHEAD
12397	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
12398#endif
12399	          SiS_SetTVyposoffset(pScrn, myypos);
12400	       } while(watchdog--);
12401	    }
12402
12403	    SISWaitRetraceCRT2(pScrn);
12404
12405	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12406	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
12407	    }
12408
12409	    if(!(pSiS->VBFlags2 & VB2_301)) {
12410	       temp = (newvde / vdediv) - 3;
12411	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
12412	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
12413	    }
12414
12415	    inSISIDXREG(SISPART1,0x0a,temp1);
12416	    inSISIDXREG(SISPART1,0x0c,temp2);
12417	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
12418	    if(pSiS->VGAEngine == SIS_300_VGA) {
12419	       vgahde -= 12;
12420	    } else {
12421	       vgahde -= 16;
12422	       if(hdclk) vgahde <<= 1;
12423	    }
12424
12425	    vgaht = SiSTVVScale[srindex].reg[0];
12426	    temp1 = vgaht;
12427	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
12428	    temp1--;
12429	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
12430	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
12431
12432	    temp2 = (vgaht - vgahde) >> 2;
12433	    if(pSiS->VGAEngine == SIS_300_VGA) {
12434	       temp1 = vgahde + 12 + temp2;
12435	       temp2 = temp1 + (temp2 << 1);
12436	    } else {
12437	       temp1 = vgahde;
12438	       if(hdclk) {
12439		  temp1 >>= 1;
12440		  temp2 >>= 1;
12441	       }
12442	       temp2 >>= 1;
12443	       temp1 = temp1 + 16 + temp2;
12444	       temp2 = temp1 + temp2;
12445	    }
12446	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
12447	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
12448	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
12449
12450	    vgavt = SiSTVVScale[srindex].reg[1];
12451	    temp1 = vgavt - 1;
12452	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
12453	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
12454	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
12455	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
12456	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
12457	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
12458	    } else {
12459	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
12460	       temp2 = (temp1 < 4) ? 4 : temp1;
12461	       temp1 += SiSTVVScale[srindex].RealVDE;
12462	       temp2 = (temp2 >> 2) + temp1 + 1;
12463	    }
12464	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
12465	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
12466	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
12467
12468	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
12469	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
12470	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
12471
12472	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
12473	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
12474	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
12475
12476	    temp1 = vgaht - 1;
12477	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
12478	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
12479
12480	    temp1 = vgavt - 1;
12481	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
12482	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
12483
12484	    outSISIDXREG(SISPART4,0x18,0x00);
12485	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
12486
12487	    inSISIDXREG(SISPART4,0x0e,temp1);
12488	    if(is1080i) {
12489	       if(!(temp1 & 0xe0)) newvde >>= 1;
12490	    }
12491
12492	    temp = 0x40;
12493	    if(realvde <= newvde) temp = 0;
12494	    else realvde -= newvde;
12495
12496	    calctemp = (realvde * 256 * 1024) / newvde;
12497	    if((realvde * 256 * 1024) % newvde) calctemp++;
12498	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
12499	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
12500	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
12501	 }
12502
12503      }
12504
12505   }
12506}
12507
12508int SiS_GetTVyscale(ScrnInfoPtr pScrn)
12509{
12510   SISPtr pSiS = SISPTR(pScrn);
12511#ifdef SISDUALHEAD
12512   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12513
12514   if(pSiSEnt && pSiS->DualHeadMode)
12515        return (int)pSiSEnt->tvyscale;
12516   else
12517#endif
12518        return (int)pSiS->tvyscale;
12519}
12520
12521void SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
12522{
12523   SISPtr pSiS = SISPTR(pScrn);
12524#ifdef SISDUALHEAD
12525   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12526#endif
12527
12528   pSiS->siscrt1satgain = val;
12529#ifdef SISDUALHEAD
12530   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
12531#endif
12532
12533   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
12534
12535#ifdef UNLOCK_ALWAYS
12536   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12537#endif
12538
12539   if((val >= 0) && (val <= 7)) {
12540      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
12541   }
12542}
12543
12544int SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
12545{
12546   SISPtr pSiS = SISPTR(pScrn);
12547   int result = pSiS->siscrt1satgain;
12548   UChar temp;
12549#ifdef SISDUALHEAD
12550   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12551
12552   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
12553#endif
12554
12555   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
12556
12557#ifdef UNLOCK_ALWAYS
12558   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12559#endif
12560   inSISIDXREG(SISCR, 0x53, temp);
12561   return (int)((temp >> 2) & 0x07);
12562}
12563
12564/* Calc dotclock from registers */
12565static int
12566SiSGetClockFromRegs(UChar sr2b, UChar sr2c)
12567{
12568   float num, denum, postscalar, divider;
12569   int   myclock;
12570
12571   divider = (sr2b & 0x80) ? 2.0 : 1.0;
12572   postscalar = (sr2c & 0x80) ?
12573              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
12574	      ( ((sr2c >> 5) & 0x03) + 1.0 );
12575   num = (sr2b & 0x7f) + 1.0;
12576   denum = (sr2c & 0x1f) + 1.0;
12577   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
12578   return myclock;
12579}
12580
12581#ifdef SISDUALHEAD
12582static void
12583SiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
12584{
12585   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12586
12587   if(pSiS->DualHeadMode) {
12588      if(pSiSEnt->pScrn_1) {
12589	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
12590	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
12591      }
12592      if(pSiSEnt->pScrn_2) {
12593	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
12594	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
12595      }
12596   }
12597}
12598#endif
12599
12600/* PostSetMode:
12601 * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
12602 *    VESA uses the bridge in SlaveMode and switching CRT1 off while
12603 *    the bridge is in SlaveMode not that clever...
12604 * -) Check if overlay can be used (depending on dotclock)
12605 * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
12606 * -) Save TV registers for further processing
12607 * -) Apply TV settings
12608 */
12609static void
12610SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
12611{
12612    SISPtr pSiS = SISPTR(pScrn);
12613#ifdef SISDUALHEAD
12614    SISEntPtr pSiSEnt = pSiS->entityPrivate;
12615#endif
12616    UChar usScratchCR17, sr2b, sr2c, tmpreg;
12617    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
12618    Bool  flag = FALSE;
12619    Bool  doit = TRUE;
12620    Bool  IsInSlaveMode;
12621
12622#ifdef TWDEBUG
12623    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12624    	"CRT1off is %d\n", pSiS->CRT1off);
12625#endif
12626    pSiS->CRT1isoff = pSiS->CRT1off;
12627
12628#ifdef UNLOCK_ALWAYS
12629    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12630#endif
12631
12632    SiSFixupSR11(pScrn);
12633
12634    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
12635
12636    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
12637
12638	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
12639	   pSiS->VBFlags = pSiS->VBFlags_backup;
12640	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12641			"VBFlags restored to %0x\n", pSiS->VBFlags);
12642	}
12643
12644	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
12645	 * -) If we change to a SlaveMode-Mode (like 512x384), we
12646	 *    need to adapt VBFlags for eg. Xv.
12647	 */
12648#ifdef SISDUALHEAD
12649	if(!pSiS->DualHeadMode) {
12650#endif
12651	   if(IsInSlaveMode) {
12652	      doit = FALSE;
12653	      temp = pSiS->VBFlags;
12654	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
12655	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
12656              if(temp != pSiS->VBFlags) {
12657		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12658		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
12659	      }
12660	   }
12661#ifdef SISDUALHEAD
12662	}
12663#endif
12664
12665	if(pSiS->VGAEngine == SIS_315_VGA) {
12666
12667	   if((pSiS->CRT1off) && (doit)) {
12668	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
12669	      orSISIDXREG(SISSR,0x1f,0xc0);
12670	      andSISIDXREG(SISSR,0x07,~0x10);
12671	      andSISIDXREG(SISSR,0x06,0xe2);
12672	      andSISIDXREG(SISSR,0x31,0xcf);
12673	      outSISIDXREG(SISSR,0x2b,0x1b);
12674	      outSISIDXREG(SISSR,0x2c,0xe1);
12675	      outSISIDXREG(SISSR,0x2d,0x01);
12676	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12677	      usleep(10000);
12678	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12679	   } else {
12680	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
12681	      andSISIDXREG(SISSR,0x1f,0x3f);
12682	      orSISIDXREG(SISSR,0x07,0x10);
12683	   }
12684
12685	} else {
12686
12687	   if(doit) {
12688	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
12689	      if(pSiS->CRT1off) {
12690		 if(usScratchCR17 & 0x80) {
12691		    flag = TRUE;
12692		    usScratchCR17 &= ~0x80;
12693		 }
12694		 orSISIDXREG(SISSR,0x1f,0xc0);
12695	      } else {
12696		 if(!(usScratchCR17 & 0x80)) {
12697		    flag = TRUE;
12698		    usScratchCR17 |= 0x80;
12699		 }
12700		 andSISIDXREG(SISSR,0x1f,0x3f);
12701	      }
12702	      /* Reset only if status changed */
12703	      if(flag) {
12704		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
12705		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12706		 usleep(10000);
12707		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12708	      }
12709	   }
12710	}
12711
12712    }
12713
12714    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
12715    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
12716#ifdef SISDUALHEAD
12717    if(!pSiS->DualHeadMode) {
12718#endif
12719       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
12720	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
12721	     if(!IsInSlaveMode) {
12722	        andSISIDXREG(SISPART4,0x0d,~0x07);
12723	     }
12724	  }
12725       }
12726#ifdef SISDUALHEAD
12727    }
12728#endif
12729
12730    /* Reset flags */
12731    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
12732			  MISC_CRT2OVERLAY      |
12733			  MISC_CRT1OVERLAYGAMMA |
12734			  MISC_SIS760ONEOVERLAY |
12735			  MISC_PANELLINKSCALER  |
12736			  MISC_STNMODE		|
12737			  MISC_TVNTSC1024);
12738
12739    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12740
12741#ifdef SISDUALHEAD
12742    if(pSiS->DualHeadMode) {
12743       if(pSiSEnt->pScrn_1) {
12744	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12745						   MISC_CRT1OVERLAY		|
12746						   MISC_CRT2OVERLAY		|
12747						   MISC_CRT1OVERLAYGAMMA	|
12748						   MISC_PANELLINKSCALER		|
12749						   MISC_STNMODE			|
12750						   MISC_TVNTSC1024);
12751	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12752       }
12753       if(pSiSEnt->pScrn_2) {
12754	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12755						   MISC_CRT1OVERLAY		|
12756						   MISC_CRT2OVERLAY		|
12757						   MISC_CRT1OVERLAYGAMMA	|
12758						   MISC_PANELLINKSCALER		|
12759						   MISC_STNMODE			|
12760						   MISC_TVNTSC1024);
12761	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12762       }
12763    }
12764#endif
12765
12766    /* Determine if the video overlay can be used */
12767    if(!pSiS->NoXvideo) {
12768
12769       int clklimit1=0, clklimit2=0, clklimitg=0;
12770       Bool OverlayHandled = FALSE;
12771
12772       inSISIDXREG(SISSR,0x2b,sr2b);
12773       inSISIDXREG(SISSR,0x2c,sr2c);
12774       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12775       inSISIDXREG(SISSR,0x06,tmpreg);
12776       switch((tmpreg & 0x1c) >> 2) {
12777       case 0:  mycoldepth1 = 1; break;
12778       case 1:
12779       case 2:  mycoldepth1 = 2; break;
12780       default: mycoldepth1 = 4;
12781       }
12782       mycoldepth2 = mycoldepth1;
12783
12784       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
12785	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12786	     inSISIDXREG(SISPART4,0x0a,sr2b);
12787	     inSISIDXREG(SISPART4,0x0b,sr2c);
12788	  } else {
12789	     inSISIDXREG(SISSR,0x2e,sr2b);
12790	     inSISIDXREG(SISSR,0x2f,sr2c);
12791	  }
12792	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12793	  inSISIDXREG(SISPART1,0x00,tmpreg);
12794	  tmpreg &= 0x0f;
12795	  switch(tmpreg) {
12796	  case 8:  mycoldepth2 = 1; break;
12797	  case 4:
12798	  case 2:  mycoldepth2 = 2; break;
12799	  default: mycoldepth2 = 4;
12800	  }
12801       }
12802
12803       switch(pSiS->ChipType) {
12804
12805	 case SIS_300:
12806	 case SIS_540:
12807	 case SIS_630:
12808	 case SIS_730:
12809	    clklimit1 = clklimit2 = clklimitg = 150;
12810	    break;
12811
12812	 case SIS_550:
12813	 case SIS_650:
12814	 case SIS_740:
12815	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
12816	    clklimitg = 166;		  /* ? */
12817	    break;
12818
12819	 case SIS_661:
12820	 case SIS_741:
12821	    clklimit1 = clklimit2 = 190;  /* ? */
12822	    clklimitg = 180;		  /* ? */
12823	    break;
12824
12825	 case SIS_760:
12826	 case SIS_761:
12827	    clklimit1 = clklimit2 = 190;    /* ? */
12828	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
12829	       clklimit1 = clklimit2 = 220; /* ? */
12830	    }
12831	    clklimitg = 200;		    /* ? */
12832
12833	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
12834
12835	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
12836	       int dotclocksum = 0;
12837
12838	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
12839	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
12840
12841	       /* TODO: Find out under what circumstances only one
12842		*	overlay is usable in UMA-only mode.
12843		*	This is not entirely accurate; the overlay
12844		*	scaler also requires some time, so even though
12845		*	the dotclocks are below these values, some
12846		*	distortions in the overlay may occure.
12847		*	Solution: Don't use a 760 with shared memory.
12848		*/
12849	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
12850		   (pSiS->VBFlags & CRT2_ENABLE) &&
12851		   (mycoldepth1 != mycoldepth2) ) {
12852
12853		  /* 0. If coldepths are different (only possible in dual head mode),
12854		   *    I have no idea to calculate the limits; hence, allow only one
12855		   *    overlay in all cases.
12856		   */
12857		  OnlyOne = TRUE;
12858
12859	       } else if(pSiS->MemClock < 150000) {
12860
12861		  /* 1. MCLK <150: If someone seriously considers using such
12862		   *    slow RAM, so be it. Only one overlay in call cases.
12863		   */
12864		  OnlyOne = TRUE;
12865
12866	       } else if(pSiS->MemClock < 170000) {
12867
12868		  /* 2. MCLK 166 */
12869		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12870		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
12871			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
12872			      break;
12873		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
12874			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
12875			      break;
12876		  }
12877
12878	       } else if(pSiS->MemClock < 210000) {
12879
12880		  /* 3. MCLK 200 */
12881		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12882		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
12883			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
12884			      break;
12885		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
12886			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
12887			      break;
12888		  }
12889
12890	       }
12891
12892	       if(OnlyOne || NoOverlay) {
12893
12894		  ULong tmpflags = 0;
12895
12896		  if(!NoOverlay) {
12897		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12898		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12899		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12900		     pSiS->MiscFlags |= tmpflags;
12901		  }
12902		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
12903		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
12904#ifdef SISDUALHEAD
12905		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
12906#endif
12907		  OverlayHandled = TRUE;
12908	       }
12909
12910	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
12911			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
12912			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
12913
12914#ifdef TWDEBUG
12915	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
12916			pSiS->MemClock, myclock1, mycoldepth1,
12917			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
12918#endif
12919	    }
12920	    break;
12921
12922	 case SIS_660:
12923	    clklimit1 = clklimit2 = 200;  /* ? */
12924	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
12925	       clklimit1 = clklimit2 = 220;
12926	    }
12927	    clklimitg = 200;		  /* ? */
12928	    break;
12929
12930	 case SIS_315H:
12931	 case SIS_315:
12932	 case SIS_315PRO:
12933	 case SIS_330:
12934	    clklimit1 = clklimit2 = 180;  /* ? */
12935	    clklimitg = 166;		  /* ? */
12936	    break;
12937
12938	 case SIS_340: /* ? */
12939	 case XGI_20:
12940	 case XGI_40:
12941	    clklimit1 = clklimit2 = 240;  /* ? */
12942	    clklimitg = 200;		  /* ? */
12943	    break;
12944       }
12945
12946       if(!OverlayHandled) {
12947          ULong tmpflags = 0;
12948          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12949          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12950          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12951	  pSiS->MiscFlags |= tmpflags;
12952#ifdef SISDUALHEAD
12953	  SiS_SetDHFlags(pSiS, tmpflags, 0);
12954#endif
12955          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
12956#ifdef SISDUALHEAD
12957             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
12958#endif
12959		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
12960		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
12961		   myclock1);
12962          }
12963          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
12964#ifdef SISDUALHEAD
12965	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
12966#endif
12967		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
12968		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
12969		   myclock2);
12970	  }
12971       }
12972
12973    }
12974
12975    /* Determine if the Panel Link scaler is active */
12976
12977    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
12978       ULong tmpflags = 0;
12979       if(pSiS->VGAEngine == SIS_300_VGA) {
12980	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
12981	     inSISIDXREG(SISPART1,0x1e,tmpreg);
12982	     tmpreg &= 0x3f;
12983	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
12984	  }
12985       } else {
12986	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
12987	     inSISIDXREG(SISPART1,0x35,tmpreg);
12988	     tmpreg &= 0x04;
12989	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
12990	  }
12991       }
12992       pSiS->MiscFlags |= tmpflags;
12993#ifdef SISDUALHEAD
12994       SiS_SetDHFlags(pSiS, tmpflags, 0);
12995#endif
12996    }
12997
12998    /* Determine if STN is active */
12999    if(pSiS->ChipType == SIS_550) {
13000       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
13001	  inSISIDXREG(SISCR,0x34,tmpreg);
13002	  tmpreg &= 0x7f;
13003	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
13004	     pSiS->MiscFlags |= MISC_STNMODE;
13005#ifdef SISDUALHEAD
13006	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
13007#endif
13008	  }
13009       }
13010    }
13011
13012    /* Determine if our very special TV mode is active */
13013    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
13014       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
13015	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
13016	  inSISIDXREG(SISCR,0x34,tmpreg);
13017	  tmpreg &= 0x7f;
13018	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
13019	     pSiS->MiscFlags |= MISC_TVNTSC1024;
13020#ifdef SISDUALHEAD
13021	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
13022#endif
13023	  }
13024       }
13025    }
13026
13027    if(pSiS->VGAEngine == SIS_315_VGA) {
13028       int i;
13029#ifdef SISVRAMQ
13030       /* Re-Enable and reset command queue */
13031       SiSEnableTurboQueue(pScrn);
13032#endif
13033       /* Get HWCursor register contents for backup */
13034       for(i = 0; i < 16; i++) {
13035          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
13036       }
13037       if(pSiS->ChipType >= SIS_330) {
13038          /* Enable HWCursor protection (Y pos as trigger) */
13039          andSISIDXREG(SISCR, 0x5b, ~0x30);
13040       }
13041    }
13042
13043    /* Re-initialize accelerator engine */
13044    /* (We are sync'ed here) */
13045    if(!pSiS->NoAccel) {
13046       if(pSiS->InitAccel) {
13047          (pSiS->InitAccel)(pScrn);
13048       }
13049    }
13050
13051    /* Set display device gamma (for SISCTRL) */
13052    if(pSiS->VBFlags & CRT1_LCDA)
13053       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
13054    else
13055       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
13056
13057    if(pSiS->VBFlags & CRT2_LCD)
13058       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
13059    else if(pSiS->VBFlags & CRT2_TV) {
13060       if(pSiS->VBFlags & TV_YPBPR)
13061          pSiS->CRT2MonGamma = 2200; /* */
13062       else if(pSiS->VBFlags & TV_HIVISION)
13063          pSiS->CRT2MonGamma = 2200; /* ? */
13064       else if(pSiS->VBFlags & TV_NTSC)
13065          pSiS->CRT2MonGamma = 2200; /* NTSC */
13066       else
13067          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
13068    } else if(pSiS->VBFlags & CRT2_VGA)
13069       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
13070    else
13071       pSiS->CRT2MonGamma = 0; /* Unknown */
13072
13073    /* Reset XV display properties (such as number of overlays, etc) */
13074    /* (And copy monitor gamma) */
13075#ifdef SISDUALHEAD
13076    if(pSiS->DualHeadMode) {
13077       if(pSiSEnt->pScrn_1) {
13078	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
13079	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
13080	  }
13081	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
13082	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
13083       }
13084       if(pSiSEnt->pScrn_2) {
13085	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
13086	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
13087	  }
13088	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
13089	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
13090       }
13091    } else {
13092#endif
13093       if(pSiS->ResetXvDisplay) {
13094	  (pSiS->ResetXvDisplay)(pScrn);
13095       }
13096#ifdef SISDUALHEAD
13097    }
13098#endif
13099
13100    /* Reset XV gamma correction */
13101    if(pSiS->ResetXvGamma) {
13102       (pSiS->ResetXvGamma)(pScrn);
13103    }
13104
13105    /* Reset various display parameters */
13106    {
13107       int val = pSiS->siscrt1satgain;
13108#ifdef SISDUALHEAD
13109       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
13110#endif
13111       SiS_SetSISCRT1SaturationGain(pScrn, val);
13112    }
13113
13114    /*  Apply TV settings given by options
13115           Do this even in DualHeadMode:
13116	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
13117	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
13118	   -> Hence, in both cases, the settings must be re-applied.
13119     */
13120
13121    if(pSiS->VBFlags & CRT2_TV) {
13122       int val;
13123       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
13124	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
13125	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
13126	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
13127	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
13128	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
13129	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
13130	  int mychtvtextenhance = pSiS->chtvtextenhance;
13131	  int mychtvcontrast = pSiS->chtvcontrast;
13132	  int mytvxpos = pSiS->tvxpos;
13133	  int mytvypos = pSiS->tvypos;
13134#ifdef SISDUALHEAD
13135	  if(pSiSEnt && pSiS->DualHeadMode) {
13136	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
13137	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
13138	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
13139	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
13140	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
13141	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
13142	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
13143	     mychtvcontrast = pSiSEnt->chtvcontrast;
13144	     mytvxpos = pSiSEnt->tvxpos;
13145	     mytvypos = pSiSEnt->tvypos;
13146	  }
13147#endif
13148	  if((val = mychtvlumabandwidthcvbs) != -1) {
13149	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
13150	  }
13151	  if((val = mychtvlumabandwidthsvideo) != -1) {
13152	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
13153	  }
13154	  if((val = mychtvlumaflickerfilter) != -1) {
13155	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
13156	  }
13157	  if((val = mychtvchromabandwidth) != -1) {
13158	     SiS_SetCHTVchromabandwidth(pScrn, val);
13159	  }
13160	  if((val = mychtvchromaflickerfilter) != -1) {
13161	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
13162	  }
13163	  if((val = mychtvcvbscolor) != -1) {
13164	     SiS_SetCHTVcvbscolor(pScrn, val);
13165	  }
13166	  if((val = mychtvtextenhance) != -1) {
13167	     SiS_SetCHTVtextenhance(pScrn, val);
13168	  }
13169	  if((val = mychtvcontrast) != -1) {
13170	     SiS_SetCHTVcontrast(pScrn, val);
13171	  }
13172	  /* Backup default TV position registers */
13173	  switch(pSiS->ChrontelType) {
13174	  case CHRONTEL_700x:
13175	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
13176	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
13177	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
13178	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
13179#ifdef SISDUALHEAD
13180	     if(pSiSEnt) {
13181		pSiSEnt->tvx = pSiS->tvx;
13182		pSiSEnt->tvy = pSiS->tvy;
13183	     }
13184#endif
13185	     break;
13186	  case CHRONTEL_701x:
13187	     /* Not supported by hardware */
13188	     break;
13189	  }
13190	  if((val = mytvxpos) != 0) {
13191	     SiS_SetTVxposoffset(pScrn, val);
13192	  }
13193	  if((val = mytvypos) != 0) {
13194	     SiS_SetTVyposoffset(pScrn, val);
13195	  }
13196       }
13197       if(pSiS->VBFlags2 & VB2_301) {
13198          int mysistvedgeenhance = pSiS->sistvedgeenhance;
13199#ifdef SISDUALHEAD
13200          if(pSiSEnt && pSiS->DualHeadMode) {
13201	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
13202	  }
13203#endif
13204          if((val = mysistvedgeenhance) != -1) {
13205	     SiS_SetSISTVedgeenhance(pScrn, val);
13206	  }
13207       }
13208       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
13209          int mysistvantiflicker = pSiS->sistvantiflicker;
13210	  int mysistvsaturation = pSiS->sistvsaturation;
13211	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
13212	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
13213	  int mysistvcfilter = pSiS->sistvcfilter;
13214	  int mysistvyfilter = pSiS->sistvyfilter;
13215	  int mytvxpos = pSiS->tvxpos;
13216	  int mytvypos = pSiS->tvypos;
13217	  int mytvxscale = pSiS->tvxscale;
13218	  int mytvyscale = pSiS->tvyscale;
13219	  int i;
13220	  ULong cbase;
13221	  UChar ctemp;
13222#ifdef SISDUALHEAD
13223          if(pSiSEnt && pSiS->DualHeadMode) {
13224	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
13225	     mysistvsaturation = pSiSEnt->sistvsaturation;
13226	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
13227	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
13228	     mysistvcfilter = pSiSEnt->sistvcfilter;
13229	     mysistvyfilter = pSiSEnt->sistvyfilter;
13230	     mytvxpos = pSiSEnt->tvxpos;
13231	     mytvypos = pSiSEnt->tvypos;
13232	     mytvxscale = pSiSEnt->tvxscale;
13233	     mytvyscale = pSiSEnt->tvyscale;
13234	  }
13235#endif
13236          /* Backup default TV position, scale and colcalib registers */
13237	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
13238	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
13239	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
13240	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
13241	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
13242	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
13243	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
13244	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
13245	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
13246	  if(!(pSiS->VBFlags2 & VB2_301)) {
13247	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
13248	  } else {
13249	     pSiS->p2_46 = 0;
13250	  }
13251	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
13252	  inSISIDXREG(SISPART2,0x31,cbase);
13253	  cbase = (cbase & 0x7f) << 8;
13254	  inSISIDXREG(SISPART2,0x32,ctemp);
13255	  cbase = (cbase | ctemp) << 8;
13256	  inSISIDXREG(SISPART2,0x33,ctemp);
13257	  cbase = (cbase | ctemp) << 8;
13258	  inSISIDXREG(SISPART2,0x34,ctemp);
13259	  pSiS->sistvccbase = (cbase | ctemp);
13260	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
13261	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
13262	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
13263	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
13264	  if(!(pSiS->VBFlags2 & VB2_301)) {
13265	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
13266	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
13267	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
13268	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
13269	  }
13270	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
13271	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
13272	  for(i=0; i<9; i++) {
13273	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
13274	  }
13275	  for(i=0; i<9; i++) {
13276	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
13277	  }
13278	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13279	     for(i=0; i<64; i++) {
13280	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
13281  	     }
13282	  }
13283#ifdef SISDUALHEAD
13284	  if(pSiSEnt) {
13285	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
13286	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
13287	     pSiSEnt->p2_2b = pSiS->p2_2b;
13288	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
13289	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
13290	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
13291	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
13292	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
13293	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
13294	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
13295	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
13296	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
13297	     for(i=0; i<9; i++) {
13298	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
13299	     }
13300	     for(i=0; i<9; i++) {
13301	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
13302	     }
13303	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13304	        for(i=0; i<64; i++) {
13305	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
13306  	        }
13307	     }
13308	  }
13309#endif
13310          if((val = mysistvantiflicker) != -1) {
13311	     SiS_SetSISTVantiflicker(pScrn, val);
13312	  }
13313	  if((val = mysistvsaturation) != -1) {
13314	     SiS_SetSISTVsaturation(pScrn, val);
13315	  }
13316	  if((val = mysistvcfilter) != -1) {
13317	     SiS_SetSISTVcfilter(pScrn, val);
13318	  }
13319	  if((val = mysistvyfilter) != 1) {
13320	     SiS_SetSISTVyfilter(pScrn, val);
13321	  }
13322	  if((val = mysistvcolcalibc) != 0) {
13323	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
13324	  }
13325	  if((val = mysistvcolcalibf) != 0) {
13326	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
13327	  }
13328	  if((val = mytvxpos) != 0) {
13329	     SiS_SetTVxposoffset(pScrn, val);
13330	  }
13331	  if((val = mytvypos) != 0) {
13332	     SiS_SetTVyposoffset(pScrn, val);
13333	  }
13334	  if((val = mytvxscale) != 0) {
13335	     SiS_SetTVxscale(pScrn, val);
13336	  }
13337	  if((val = mytvyscale) != 0) {
13338	     SiS_SetTVyscale(pScrn, val);
13339	  }
13340       }
13341    }
13342
13343}
13344
13345/* Post-set SiS6326 TV registers */
13346static void
13347SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
13348{
13349    SISPtr pSiS = SISPTR(pScrn);
13350    UChar tmp;
13351    int val;
13352
13353    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
13354
13355#ifdef UNLOCK_ALWAYS
13356    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
13357#endif
13358
13359    /* Backup default TV position registers */
13360    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
13361    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
13362    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
13363    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
13364    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
13365    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
13366    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
13367    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
13368
13369    /* Handle TVPosOffset options (BEFORE switching on TV) */
13370    if((val = pSiS->tvxpos) != 0) {
13371       SiS_SetTVxposoffset(pScrn, val);
13372    }
13373    if((val = pSiS->tvypos) != 0) {
13374       SiS_SetTVyposoffset(pScrn, val);
13375    }
13376
13377    /* Switch on TV output. This is rather complicated, but
13378     * if we don't do it, TV output will flicker terribly.
13379     */
13380    if(pSiS->SiS6326Flags & SIS6326_TVON) {
13381       orSISIDXREG(SISSR, 0x01, 0x20);
13382       tmp = SiS6326GetTVReg(pScrn,0x00);
13383       tmp &= ~0x04;
13384       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
13385       SiS6326SetTVReg(pScrn,0x00,tmp);
13386       for(val=0; val < 2; val++) {
13387         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13388         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13389       }
13390       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
13391       tmp = inSISREG(SISINPSTAT);
13392       outSISREG(SISAR, 0x20);
13393       tmp = inSISREG(SISINPSTAT);
13394       while(inSISREG(SISINPSTAT) & 0x01);
13395       while(!(inSISREG(SISINPSTAT) & 0x01));
13396       andSISIDXREG(SISSR, 0x01, ~0x20);
13397       for(val=0; val < 10; val++) {
13398         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13399         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13400       }
13401       andSISIDXREG(SISSR, 0x01, ~0x20);
13402    }
13403
13404    tmp = SiS6326GetTVReg(pScrn,0x00);
13405    if(!(tmp & 0x04)) return;
13406
13407    /* Apply TV settings given by options */
13408    if((val = pSiS->sistvantiflicker) != -1) {
13409       SiS_SetSIS6326TVantiflicker(pScrn, val);
13410    }
13411    if((val = pSiS->sis6326enableyfilter) != -1) {
13412       SiS_SetSIS6326TVenableyfilter(pScrn, val);
13413    }
13414    if((val = pSiS->sis6326yfilterstrong) != -1) {
13415       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
13416    }
13417
13418}
13419
13420/* Check if video bridge is in slave mode */
13421Bool
13422SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
13423{
13424    SISPtr pSiS = SISPTR(pScrn);
13425    UChar  usScrP1_00;
13426
13427    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
13428
13429    inSISIDXREG(SISPART1,0x00,usScrP1_00);
13430    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
13431        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
13432       return TRUE;
13433    }
13434
13435    return FALSE;
13436}
13437
13438/* Build a list of the VESA modes the BIOS reports as valid */
13439static void
13440SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
13441{
13442    SISPtr pSiS = SISPTR(pScrn);
13443    int i = 0;
13444
13445    while(vbe->VideoModePtr[i] != 0xffff) {
13446       sisModeInfoPtr m;
13447       VbeModeInfoBlock *mode;
13448       int id = vbe->VideoModePtr[i++];
13449
13450       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
13451	  continue;
13452       }
13453
13454       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
13455       if(!m) {
13456	  VBEFreeModeInfo(mode);
13457	  continue;
13458       }
13459       m->width = mode->XResolution;
13460       m->height = mode->YResolution;
13461       m->bpp = mode->BitsPerPixel;
13462       m->n = id;
13463       m->next = pSiS->SISVESAModeList;
13464
13465       pSiS->SISVESAModeList = m;
13466
13467       VBEFreeModeInfo(mode);
13468
13469       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
13470	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
13471	   m->n, m->width, m->height, m->bpp);
13472    }
13473}
13474
13475/* Get VESA mode number from given resolution/depth */
13476static UShort
13477SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
13478{
13479    SISPtr pSiS = SISPTR(pScrn);
13480    sisModeInfoPtr m = pSiS->SISVESAModeList;
13481    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
13482    UShort ModeNumber = 0;
13483    int j;
13484
13485    while(m) {
13486       if( (pScrn->bitsPerPixel == m->bpp) &&
13487	   (mode->HDisplay == m->width)    &&
13488	   (mode->VDisplay == m->height) )
13489	  return m->n;
13490       m = m->next;
13491    }
13492
13493    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
13494        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
13495        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13496
13497    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
13498       j = 0;
13499       while(VESAModeIndices[j] != 9999) {
13500          if( (mode->HDisplay == VESAModeIndices[j]) &&
13501	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
13502	     ModeNumber = VESAModeIndices[j + 2 + i];
13503	     break;
13504          }
13505          j += 6;
13506       }
13507
13508       if(!ModeNumber) {
13509	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13510	      "No valid mode found for %dx%dx%d in built-in table either.\n",
13511	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13512       }
13513    }
13514
13515    return(ModeNumber);
13516}
13517
13518UShort
13519SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
13520{
13521   SISPtr pSiS = SISPTR(pScrn);
13522   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13523   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
13524
13525#ifdef SISDUALHEAD
13526   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
13527#endif
13528
13529   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13530			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13531}
13532
13533static Bool
13534SiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
13535{
13536   if(mode->Flags & V_INTERLACE) return FALSE;
13537
13538   if(mode->HDisplay > 2048) return FALSE;
13539   if(mode->VDisplay > 1536) return FALSE;
13540
13541   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
13542      if(mode->Clock > 162500) return FALSE;
13543#ifdef VB_FORBID_CRT2LCD_OVER_1600
13544      if(!isforlcda) {
13545         if(mode->HDisplay > 1600) return FALSE;
13546      }
13547#endif
13548   } else { /* 301, 301B, 302B (no LCDA!) */
13549      if(mode->Clock > 130000)  return FALSE;
13550      if(mode->Clock > 111000) {
13551         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
13552	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
13553		mode->Clock / 1000);
13554      }
13555      if(mode->HDisplay > 1600) return FALSE;
13556      if(mode->VDisplay > 1024) return FALSE;
13557   }
13558
13559   return TRUE;
13560}
13561
13562static Bool
13563SiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
13564{
13565   if(mode->Flags & V_INTERLACE) return FALSE;
13566
13567   if(mode->HDisplay > 2048) return FALSE;
13568   if(mode->VDisplay > 1536) return FALSE;
13569
13570   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
13571      if(mode->Clock > 203000) return FALSE;
13572   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
13573      if(mode->Clock > 162500) return FALSE;
13574   } else {
13575      if(mode->Clock > 135500) return FALSE;
13576   }
13577
13578   return TRUE;
13579}
13580
13581UShort
13582SiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13583{
13584   SISPtr pSiS = SISPTR(pScrn);
13585   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13586   int j;
13587
13588   if(!(VBFlags & CRT1_LCDA)) {
13589
13590      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
13591         return 0xfe;
13592      }
13593
13594   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
13595
13596      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
13597         if(!(mode->type & M_T_DEFAULT)) {
13598            if(mode->HTotal > 2055) return 0;
13599	    /* (Default mode will be caught in mode switching code) */
13600	 }
13601      }
13602
13603      if(pSiS->SiS_Pr->CP_HaveCustomData) {
13604         for(j=0; j<7; j++) {
13605            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13606               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13607               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13608               (mode->type & M_T_BUILTIN))
13609               return 0xfe;
13610	 }
13611      }
13612
13613      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13614         return 0xfe;
13615
13616      if((havecustommodes) &&
13617         (pSiS->LCDwidth)  &&	/* = test if LCD present */
13618         (!(mode->type & M_T_DEFAULT)) &&
13619	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
13620         return 0xfe;
13621
13622      if((mode->HDisplay > pSiS->LCDwidth) ||
13623         (mode->VDisplay > pSiS->LCDheight)) {
13624	 return 0;
13625      }
13626
13627   } else {
13628
13629      if((mode->HDisplay > pSiS->LCDwidth) ||
13630         (mode->VDisplay > pSiS->LCDheight)) {
13631	 return 0;
13632      }
13633
13634   }
13635
13636   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13637   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13638}
13639
13640UShort
13641SiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13642{
13643   SISPtr pSiS = SISPTR(pScrn);
13644   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13645   UShort ModeIndex = 0;
13646   int    j;
13647
13648#ifdef TWDEBUG
13649   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
13650	VBFlags,mode->HDisplay, mode->VDisplay);
13651#endif
13652
13653   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
13654
13655      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
13656
13657         if(pSiS->SiS_Pr->CP_HaveCustomData) {
13658            for(j=0; j<7; j++) {
13659               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13660                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13661                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13662#ifdef VB_FORBID_CRT2LCD_OVER_1600
13663		  (mode->HDisplay <= 1600) 			   &&
13664#endif
13665                  (mode->type & M_T_BUILTIN))
13666                  return 0xfe;
13667	    }
13668         }
13669
13670	 /* All plasma modes have HDisplay <= 1600 */
13671         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13672            return 0xfe;
13673
13674         if((havecustommodes) &&
13675            (pSiS->LCDwidth)  &&	/* = test if LCD present */
13676	    (!(mode->type & M_T_DEFAULT)) &&
13677	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
13678            return 0xfe;
13679
13680      }
13681
13682      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
13683           (mode->VDisplay <= pSiS->LCDheight)) ||
13684	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
13685	   (((mode->HDisplay == 1360) && (mode->HDisplay == 768)) ||
13686	    ((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13687	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ||
13688	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
13689	   (((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13690	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ) {
13691
13692	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13693				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
13694				pSiS->VBFlags2);
13695
13696      }
13697
13698   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
13699
13700      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13701					pSiS->VBFlags2);
13702
13703   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
13704
13705      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13706	 return 0xfe;
13707
13708      if((havecustommodes) &&
13709	 (!(mode->type & M_T_DEFAULT)) &&
13710	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
13711         return 0xfe;
13712
13713      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13714					pSiS->VBFlags2);
13715
13716   } else {					/* no CRT2 */
13717
13718      /* Return a valid mode number */
13719      ModeIndex = 0xfe;
13720
13721   }
13722
13723   return(ModeIndex);
13724}
13725
13726/* Calculate the vertical refresh rate from a mode */
13727float
13728SiSCalcVRate(DisplayModePtr mode)
13729{
13730   float hsync, refresh = 0;
13731
13732   if(mode->HSync > 0.0)
13733       	hsync = mode->HSync;
13734   else if(mode->HTotal > 0)
13735       	hsync = (float)mode->Clock / (float)mode->HTotal;
13736   else
13737       	hsync = 0.0;
13738
13739   if(mode->VTotal > 0)
13740       	refresh = hsync * 1000.0 / mode->VTotal;
13741
13742   if(mode->Flags & V_INTERLACE)
13743       	refresh *= 2.0;
13744
13745   if(mode->Flags & V_DBLSCAN)
13746       	refresh /= 2.0;
13747
13748   if(mode->VScan > 1)
13749        refresh /= mode->VScan;
13750
13751   if(mode->VRefresh > 0.0)
13752	refresh = mode->VRefresh;
13753
13754   if(hsync == 0.0 || refresh == 0.0) return 0.0;
13755
13756   return refresh;
13757}
13758
13759/* Calculate CR33 (rate index) for CRT1.
13760 * Calculation is done using currentmode, therefore it is
13761 * recommended to set VertRefresh and HorizSync to correct
13762 * values in config file.
13763 */
13764UChar
13765SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
13766{
13767   SISPtr  pSiS = SISPTR(pScrn);
13768   int     i = 0, irefresh;
13769   UShort  xres = mode->HDisplay;
13770   UShort  yres = mode->VDisplay;
13771   UChar   index, defindex;
13772   Bool    checksis730 = FALSE;
13773
13774   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
13775
13776   irefresh = (int)SiSCalcVRate(mode);
13777   if(!irefresh) return defindex;
13778
13779   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
13780   if( (pSiS->ChipType == SIS_730)        &&
13781       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
13782       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
13783#ifdef SISDUALHEAD
13784      if(pSiS->DualHeadMode) {
13785         if(pSiS->SecondHead) {
13786	    checksis730 = TRUE;
13787	 }
13788      } else
13789#endif
13790      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
13791         checksis730 = TRUE;
13792      }
13793   }
13794
13795#ifdef TWDEBUG
13796   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
13797#endif
13798
13799   /* We need the REAL refresh rate here */
13800   if(mode->Flags & V_INTERLACE) irefresh /= 2;
13801
13802   /* Do not multiply by 2 when DBLSCAN! */
13803
13804#ifdef TWDEBUG
13805   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
13806#endif
13807
13808   index = 0;
13809   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
13810      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
13811	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
13812	    if(sisx_vrate[i].refresh == irefresh) {
13813	       index = sisx_vrate[i].idx;
13814	       break;
13815	    } else if(sisx_vrate[i].refresh > irefresh) {
13816	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
13817		  index = sisx_vrate[i].idx;
13818	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
13819		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
13820			  (sisx_vrate[i].idx != 1) ) {
13821		  index = sisx_vrate[i - 1].idx;
13822	       }
13823	       break;
13824	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
13825	       index = sisx_vrate[i].idx;
13826	       break;
13827	    }
13828	 }
13829      }
13830      i++;
13831   }
13832
13833   if(index > 0) return index;
13834   else          return defindex;
13835}
13836
13837void
13838SISWaitRetraceCRT1(ScrnInfoPtr pScrn)
13839{
13840   SISPtr pSiS = SISPTR(pScrn);
13841   int    watchdog;
13842   UChar  temp;
13843
13844   inSISIDXREG(SISCR,0x17,temp);
13845   if(!(temp & 0x80)) return;
13846
13847   inSISIDXREG(SISSR,0x1f,temp);
13848   if(temp & 0xc0) return;
13849
13850   watchdog = 65536;
13851   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
13852   watchdog = 65536;
13853   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
13854}
13855
13856void
13857SISWaitRetraceCRT2(ScrnInfoPtr pScrn)
13858{
13859   SISPtr pSiS = SISPTR(pScrn);
13860   int    watchdog;
13861   UChar  temp, reg;
13862
13863   if(SiSBridgeIsInSlaveMode(pScrn)) {
13864      SISWaitRetraceCRT1(pScrn);
13865      return;
13866   }
13867
13868   switch(pSiS->VGAEngine) {
13869   case SIS_300_VGA:
13870   	reg = 0x25;
13871	break;
13872   case SIS_315_VGA:
13873   	reg = 0x30;
13874	break;
13875   default:
13876        return;
13877   }
13878
13879   watchdog = 65536;
13880   do {
13881   	inSISIDXREG(SISPART1, reg, temp);
13882	if(!(temp & 0x02)) break;
13883   } while(--watchdog);
13884   watchdog = 65536;
13885   do {
13886   	inSISIDXREG(SISPART1, reg, temp);
13887	if(temp & 0x02) break;
13888   } while(--watchdog);
13889}
13890
13891static void
13892SISWaitVBRetrace(ScrnInfoPtr pScrn)
13893{
13894   SISPtr  pSiS = SISPTR(pScrn);
13895
13896   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
13897#ifdef SISDUALHEAD
13898      if(pSiS->DualHeadMode) {
13899   	 if(pSiS->SecondHead)
13900	    SISWaitRetraceCRT1(pScrn);
13901         else
13902	    SISWaitRetraceCRT2(pScrn);
13903      } else {
13904#endif
13905	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
13906	    SISWaitRetraceCRT1(pScrn);
13907	 }
13908	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
13909	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
13910	       SISWaitRetraceCRT2(pScrn);
13911	    }
13912	 }
13913#ifdef SISDUALHEAD
13914      }
13915#endif
13916   } else {
13917      SISWaitRetraceCRT1(pScrn);
13918   }
13919}
13920
13921#define MODEID_OFF 0x449
13922
13923UChar
13924SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
13925{
13926    UChar ret = 0;
13927#ifdef SIS_USE_BIOS_SCRATCH
13928    UChar *base;
13929#endif
13930
13931    /* For some reasons (like detecting the current display mode),
13932     * we need to read (or write-back) values from the BIOS
13933     * scratch area. This area is only valid for the primary
13934     * graphics card. For the secondary, we just return some
13935     * defaults and ignore requests to write data. As regards
13936     * the display mode: If sisfb is loaded for the secondary
13937     * card, it very probably has set a mode, but in any case
13938     * informed us via its info packet. So this here will not be
13939     * called for mode detection in this case.
13940     */
13941
13942    switch(offset) {
13943    case 0x489:
13944       ret = 0x11;  /* Default VGA Info */
13945       break;
13946    case MODEID_OFF:
13947       ret = 0x03;  /* Default current display mode */
13948       break;
13949    }
13950
13951#ifdef SIS_USE_BIOS_SCRATCH
13952    if(SISPTR(pScrn)->Primary) {
13953       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
13954       if(!base) {
13955          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
13956          return ret;
13957       }
13958
13959       ret = *(base + offset);
13960
13961       /* value != 0xff means: set register */
13962       if(value != 0xff) {
13963          *(base + offset) = value;
13964       }
13965
13966       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
13967    }
13968#endif
13969    return ret;
13970}
13971
13972UChar
13973SiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
13974{
13975    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
13976}
13977
13978void
13979SiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
13980{
13981   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
13982   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
13983}
13984
13985void
13986SiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
13987{
13988   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
13989   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
13990}
13991
13992void
13993sisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
13994{
13995    register UChar val;
13996    ULong mylockcalls;
13997#ifdef TWDEBUG
13998    UChar val1, val2;
13999    int i;
14000#endif
14001
14002    pSiS->lockcalls++;
14003    mylockcalls = pSiS->lockcalls;
14004
14005    /* check if already unlocked */
14006    inSISIDXREG(SISSR, 0x05, val);
14007
14008    if(val != 0xa1) {
14009
14010       /* save State */
14011       if(reg1) *reg1 = val;
14012
14013       /* unlock */
14014       outSISIDXREG(SISSR, 0x05, 0x86);
14015
14016       /* Now check again */
14017       inSISIDXREG(SISSR, 0x05, val);
14018
14019       if(val != 0xA1) {
14020
14021          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
14022               "Failed to unlock SR registers at relocated i/o ports\n");
14023
14024#ifdef TWDEBUG
14025          for(i = 0; i <= 0x3f; i++) {
14026		inSISIDXREG(SISSR, i, val1);
14027		inSISIDXREG(0x3c4, i, val2);
14028		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
14029			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
14030			i, val1, val2, mylockcalls);
14031	  }
14032#endif
14033
14034	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
14035	  switch(pSiS->VGAEngine) {
14036          case SIS_OLD_VGA:
14037	  case SIS_530_VGA:
14038	     outSISIDXREG(0x3c4, 0x05, 0x86);
14039	     andSISIDXREG(0x3c4, 0x33, ~0x20);
14040	     break;
14041	  case SIS_300_VGA:
14042	  case SIS_315_VGA:
14043	     outSISIDXREG(0x3c4, 0x05, 0x86);
14044	     orSISIDXREG(0x3c4, 0x20, 0x20);
14045	     break;
14046          }
14047	  outSISIDXREG(SISSR, 0x05, 0x86);
14048	  inSISIDXREG(SISSR, 0x05, val);
14049	  if(val != 0xa1) {
14050	     SISErrorLog(pSiS->pScrn,
14051			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
14052			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
14053	     /* Now await doom... */
14054	  }
14055       }
14056    }
14057    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14058       inSISIDXREG(SISCR, 0x80, val);
14059       if(val != 0xa1) {
14060          /* save State */
14061          if(reg2) *reg2 = val;
14062          outSISIDXREG(SISCR, 0x80, 0x86);
14063	  inSISIDXREG(SISCR, 0x80, val);
14064	  if(val != 0xA1) {
14065	     SISErrorLog(pSiS->pScrn,
14066	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
14067	       (void *)pSiS, (ULong)pSiS->RelIO, val);
14068	  }
14069       }
14070    }
14071}
14072
14073void
14074sisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
14075{
14076    /* restore lock */
14077#ifndef UNLOCK_ALWAYS
14078    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
14079    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14080       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
14081    }
14082#endif
14083}
14084
14085