sis_driver.c revision 72b676d7
1/* $XFree86$ */
2/* $XdotOrg: driver/xf86-video-sis/src/sis_driver.c,v 1.72 2006/03/09 06:06:25 anholt Exp $ */
3/*
4 * SiS driver main code
5 *
6 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1) Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2) Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3) The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Author: Thomas Winischhofer <thomas@winischhofer.net>
31 *	- driver entirely rewritten since 2001, only basic structure taken from
32 *	  old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of
33 *	  sis_dga.c; these were mostly taken over; sis_dri.c was changed for
34 *	  new versions of the DRI layer)
35 *
36 * This notice covers the entire driver code unless indicated otherwise.
37 *
38 * Formerly based on code which was
39 * 	     Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England.
40 * 	     Written by:
41 *           Alan Hourihane <alanh@fairlite.demon.co.uk>,
42 *           Mike Chapman <mike@paranoia.com>,
43 *           Juanjo Santamarta <santamarta@ctv.es>,
44 *           Mitani Hiroshi <hmitani@drl.mei.co.jp>,
45 *           David Thomas <davtom@dream.org.uk>.
46 */
47
48#ifdef HAVE_CONFIG_H
49#include "config.h"
50#endif
51
52#include "sis.h"
53
54#include "xf86RAC.h"
55#include "dixstruct.h"
56#include "shadowfb.h"
57#include "fb.h"
58#include "micmap.h"
59#include "mibank.h"
60#include "mipointer.h"
61#include "mibstore.h"
62#define _XF86MISC_SERVER_
63#include <X11/extensions/xf86misc.h>
64#include "edid.h"
65
66#define SIS_NEED_inSISREG
67#define SIS_NEED_inSISIDXREG
68#define SIS_NEED_outSISIDXREG
69#define SIS_NEED_orSISIDXREG
70#define SIS_NEED_andSISIDXREG
71#define SIS_NEED_setSISIDXREG
72#define SIS_NEED_outSISREG
73#define SIS_NEED_MYMMIO
74#define SIS_NEED_sisclearvram
75#include "sis_regs.h"
76#include "sis_dac.h"
77
78#include "sis_driver.h"
79
80#define _XF86DGA_SERVER_
81#include <X11/extensions/xf86dgastr.h>
82
83#include "globals.h"
84
85#define DPMS_SERVER
86#include <X11/extensions/dpms.h>
87
88#ifdef XF86DRI
89#include "dri.h"
90#endif
91
92/* Globals (yes, these ARE really required to be global) */
93
94#ifdef SISUSEDEVPORT
95int 		sisdevport = 0;
96#endif
97
98#ifdef SISDUALHEAD
99static int	SISEntityIndex = -1;
100#endif
101
102#ifdef SISMERGED
103#ifdef SISXINERAMA
104static Bool 		SiSnoPanoramiXExtension = TRUE;
105static int		SiSXineramaNumScreens = 0;
106static SiSXineramaData	*SiSXineramadataPtr = NULL;
107static int		SiSXineramaGeneration;
108
109static int SiSProcXineramaQueryVersion(ClientPtr client);
110static int SiSProcXineramaGetState(ClientPtr client);
111static int SiSProcXineramaGetScreenCount(ClientPtr client);
112static int SiSProcXineramaGetScreenSize(ClientPtr client);
113static int SiSProcXineramaIsActive(ClientPtr client);
114static int SiSProcXineramaQueryScreens(ClientPtr client);
115static int SiSSProcXineramaDispatch(ClientPtr client);
116#endif
117#endif
118
119/*
120 * This is intentionally screen-independent.  It indicates the binding
121 * choice made in the first PreInit.
122 */
123static int pix24bpp = 0;
124
125/*
126 * This contains the functions needed by the server after loading the driver
127 * module.  It must be supplied, and gets passed back by the SetupProc
128 * function in the dynamic case.  In the static case, a reference to this
129 * is compiled in, and this requires that the name of this DriverRec be
130 * an upper-case version of the driver name.
131 */
132
133#ifdef _X_EXPORT
134_X_EXPORT
135#endif
136DriverRec SIS = {
137    SIS_CURRENT_VERSION,
138    SIS_DRIVER_NAME,
139    SISIdentify,
140    SISProbe,
141    SISAvailableOptions,
142    NULL,
143    0
144#ifdef SIS_HAVE_DRIVER_FUNC
145     ,
146    SISDriverFunc
147#endif
148};
149
150static SymTabRec SISChipsets[] = {
151    { PCI_CHIP_SIS5597,     "SIS5597/5598" },
152    { PCI_CHIP_SIS530,      "SIS530/620" },
153    { PCI_CHIP_SIS6326,     "SIS6326/AGP/DVD" },
154    { PCI_CHIP_SIS300,      "SIS300/305" },
155    { PCI_CHIP_SIS630,      "SIS630/730" },
156    { PCI_CHIP_SIS540,      "SIS540" },
157    { PCI_CHIP_SIS315,      "SIS315" },
158    { PCI_CHIP_SIS315H,     "SIS315H" },
159    { PCI_CHIP_SIS315PRO,   "SIS315PRO/E" },
160    { PCI_CHIP_SIS550,	    "SIS550" },
161    { PCI_CHIP_SIS650,      "SIS650/M650/651/740" },
162    { PCI_CHIP_SIS330,      "SIS330(Xabre)" },
163    { PCI_CHIP_SIS660,      "SIS660/[M]661[F|M]X/[M]670/[M]741[GX]/[M]760[GX]/[M]761[GX]/[M]770[GX]" },
164    { PCI_CHIP_SIS340,      "SIS340" },
165    { -1,                   NULL }
166};
167
168static PciChipsets SISPciChipsets[] = {
169    { PCI_CHIP_SIS5597,     PCI_CHIP_SIS5597,   RES_SHARED_VGA },
170    { PCI_CHIP_SIS530,      PCI_CHIP_SIS530,    RES_SHARED_VGA },
171    { PCI_CHIP_SIS6326,     PCI_CHIP_SIS6326,   RES_SHARED_VGA },
172    { PCI_CHIP_SIS300,      PCI_CHIP_SIS300,    RES_SHARED_VGA },
173    { PCI_CHIP_SIS630,      PCI_CHIP_SIS630,    RES_SHARED_VGA },
174    { PCI_CHIP_SIS540,      PCI_CHIP_SIS540,    RES_SHARED_VGA },
175    { PCI_CHIP_SIS550,      PCI_CHIP_SIS550,    RES_SHARED_VGA },
176    { PCI_CHIP_SIS315,      PCI_CHIP_SIS315,    RES_SHARED_VGA },
177    { PCI_CHIP_SIS315H,     PCI_CHIP_SIS315H,   RES_SHARED_VGA },
178    { PCI_CHIP_SIS315PRO,   PCI_CHIP_SIS315PRO, RES_SHARED_VGA },
179    { PCI_CHIP_SIS650,      PCI_CHIP_SIS650,    RES_SHARED_VGA },
180    { PCI_CHIP_SIS330,      PCI_CHIP_SIS330,    RES_SHARED_VGA },
181    { PCI_CHIP_SIS660,      PCI_CHIP_SIS660,    RES_SHARED_VGA },
182    { PCI_CHIP_SIS340,      PCI_CHIP_SIS340,    RES_SHARED_VGA },
183    { -1,                   -1,                 RES_UNDEFINED }
184};
185
186static SymTabRec XGIChipsets[] = {
187    { PCI_CHIP_XGIXG20,     "Volari Z7 (XG20)" },
188    { PCI_CHIP_XGIXG40,     "Volari V3XT/V5/V8/Duo (XG40)" },
189    { -1,                   NULL }
190};
191
192static PciChipsets XGIPciChipsets[] = {
193    { PCI_CHIP_XGIXG20,     PCI_CHIP_XGIXG20,   RES_SHARED_VGA },
194    { PCI_CHIP_XGIXG40,     PCI_CHIP_XGIXG40,   RES_SHARED_VGA },
195    { -1,                   -1,                 RES_UNDEFINED }
196};
197
198#ifdef SIS_USE_XAA
199static const char *xaaSymbols[] = {
200    "XAACreateInfoRec",
201    "XAADestroyInfoRec",
202    "XAAHelpPatternROP",
203    "XAAInit",
204    NULL
205};
206#endif
207
208#ifdef SIS_USE_EXA
209static const char *exaSymbols[] = {
210    "exaDriverAccel",
211    "exaDriverInit",
212    "exaDriverFini",
213    "exaOffscreenAlloc",
214    "exaOffscreenFree",
215    NULL
216};
217#endif
218
219static const char *fbSymbols[] = {
220    "fbPictureInit",
221    "fbScreenInit",
222    NULL
223};
224
225static const char *shadowSymbols[] = {
226    "ShadowFBInit",
227    NULL
228};
229
230static const char *ramdacSymbols[] = {
231    "xf86CreateCursorInfoRec",
232    "xf86DestroyCursorInfoRec",
233    "xf86InitCursor",
234    NULL
235};
236
237static const char *ddcSymbols[] = {
238    "xf86PrintEDID",
239    "xf86SetDDCproperties",
240    "xf86InterpretEDID",
241    NULL
242};
243
244static const char *int10Symbols[] = {
245    "xf86FreeInt10",
246    "xf86InitInt10",
247    NULL
248};
249
250static const char *vbeSymbols[] = {
251#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
252    "VBEInit",
253#else
254    "VBEExtendedInit",
255#endif
256    "vbeDoEDID",
257    "vbeFree",
258    "VBEGetVBEInfo",
259    "VBEFreeVBEInfo",
260    "VBEGetModeInfo",
261    "VBEFreeModeInfo",
262    "VBESaveRestore",
263    "VBESetVBEMode",
264    "VBEGetVBEMode",
265    "VBESetDisplayStart",
266    "VBESetGetLogicalScanlineLength",
267    NULL
268};
269
270#ifdef XF86DRI
271static const char *drmSymbols[] = {
272    "drmAddMap",
273    "drmAgpAcquire",
274    "drmAgpRelease",
275    "drmAgpAlloc",
276    "drmAgpFree",
277    "drmAgpBase",
278    "drmAgpBind",
279    "drmAgpUnbind",
280    "drmAgpEnable",
281    "drmAgpGetMode",
282    "drmCtlInstHandler",
283    "drmCtlUninstHandler",
284    "drmGetInterruptFromBusID",
285#ifndef SISHAVEDRMWRITE
286    "drmSiSAgpInit",
287#else
288    "drmCommandWrite",
289#endif
290#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,3,0,0,0)
291    "drmGetVersion",
292    "drmFreeVersion",
293#endif
294    NULL
295};
296
297static const char *driSymbols[] = {
298    "DRICreateInfoRec",
299    "DRIScreenInit",
300    "DRIFinishScreenInit",
301    "DRIDestroyInfoRec",
302    "DRICloseScreen",
303    "DRIGetSAREAPrivate",
304    "DRILock",
305    "DRIUnlock",
306    "DRIQueryVersion",
307    "GlxSetVisualConfigs",
308    NULL
309};
310
311#ifdef XFree86LOADER
312static const char *driRefSymbols[] = {
313    "DRICreatePCIBusID",  /* not REQUIRED, but eventually referenced */
314    NULL
315};
316#endif
317#endif  /* XF86DRI */
318
319#ifdef XFree86LOADER
320
321static MODULESETUPPROTO(sisSetup);
322
323static XF86ModuleVersionInfo sisVersRec =
324{
325    SIS_DRIVER_NAME,
326    MODULEVENDORSTRING,
327    MODINFOSTRING1,
328    MODINFOSTRING2,
329#ifdef XORG_VERSION_CURRENT
330    XORG_VERSION_CURRENT,
331#else
332    XF86_VERSION_CURRENT,
333#endif
334    SIS_MAJOR_VERSION, SIS_MINOR_VERSION, SIS_PATCHLEVEL,
335    ABI_CLASS_VIDEODRV,         /* This is a video driver */
336    ABI_VIDEODRV_VERSION,
337    MOD_CLASS_VIDEODRV,
338    {0,0,0,0}
339};
340
341#ifdef _X_EXPORT
342_X_EXPORT
343#endif
344XF86ModuleData sisModuleData = { &sisVersRec, sisSetup, NULL };
345
346pointer
347sisSetup(pointer module, pointer opts, int *errmaj, int *errmin)
348{
349    static Bool setupDone = FALSE;
350
351    if(!setupDone) {
352       setupDone = TRUE;
353       xf86AddDriver(&SIS, module, SIS_HaveDriverFuncs);
354       LoaderRefSymLists(fbSymbols,
355#ifdef SIS_USE_XAA
356			 xaaSymbols,
357#endif
358#ifdef SIS_USE_EXA
359			 exaSymbols,
360#endif
361			 shadowSymbols, ramdacSymbols,
362			 vbeSymbols, int10Symbols,
363#ifdef XF86DRI
364			 drmSymbols, driSymbols, driRefSymbols,
365#endif
366			 NULL);
367       return (pointer)TRUE;
368    }
369
370    if(errmaj) *errmaj = LDR_ONCEONLY;
371    return NULL;
372}
373
374#endif /* XFree86LOADER */
375
376/* Mandatory */
377static void
378SISIdentify(int flags)
379{
380    xf86PrintChipsets(SIS_NAME, "driver for SiS chipsets", SISChipsets);
381    xf86PrintChipsets(SIS_NAME, "driver for XGI chipsets", XGIChipsets);
382}
383
384#ifdef SIS_HAVE_DRIVER_FUNC
385static Bool
386SISDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
387{
388    CARD32 *flag;
389
390    switch(op) {
391    case RR_GET_INFO:
392	break;
393    case RR_SET_CONFIG:
394	break;
395    case GET_REQUIRED_HW_INTERFACES:
396	break;
397    }
398    return TRUE;
399}
400#endif
401
402static Bool
403SISGetRec(ScrnInfoPtr pScrn)
404{
405    /* Allocate an SISRec, and hook it into pScrn->driverPrivate.
406     * pScrn->driverPrivate is initialised to NULL, so we can check if
407     * the allocation has already been done.
408     */
409    if(pScrn->driverPrivate != NULL) return TRUE;
410
411    pScrn->driverPrivate = xnfcalloc(sizeof(SISRec), 1);
412
413    /* Initialise it to 0 */
414    memset(pScrn->driverPrivate, 0, sizeof(SISRec));
415
416    return TRUE;
417}
418
419static void
420SISFreeRec(ScrnInfoPtr pScrn)
421{
422    SISPtr pSiS = SISPTR(pScrn);
423#ifdef SISDUALHEAD
424    SISEntPtr pSiSEnt = NULL;
425#endif
426
427    /* Just to make sure... */
428    if(!pSiS) return;
429
430#ifdef SISDUALHEAD
431    pSiSEnt = pSiS->entityPrivate;
432#endif
433
434    if(pSiS->pstate) xfree(pSiS->pstate);
435    pSiS->pstate = NULL;
436    if(pSiS->fonts) xfree(pSiS->fonts);
437    pSiS->fonts = NULL;
438
439#ifdef SISDUALHEAD
440    if(pSiSEnt) {
441       if(!pSiS->SecondHead) {
442	  /* Free memory only if we are first head; in case of an error
443	   * during init of the second head, the server will continue -
444	   * and we need the BIOS image and SiS_Private for the first
445	   * head.
446	   */
447	  if(pSiSEnt->BIOS) xfree(pSiSEnt->BIOS);
448	  pSiSEnt->BIOS = pSiS->BIOS = NULL;
449	  if(pSiSEnt->SiS_Pr) xfree(pSiSEnt->SiS_Pr);
450	  pSiSEnt->SiS_Pr = pSiS->SiS_Pr = NULL;
451	  if(pSiSEnt->RenderAccelArray) xfree(pSiSEnt->RenderAccelArray);
452	  pSiSEnt->RenderAccelArray = pSiS->RenderAccelArray = NULL;
453	  pSiSEnt->pScrn_1 = NULL;
454       } else {
455	  pSiS->BIOS = NULL;
456	  pSiS->SiS_Pr = NULL;
457	  pSiS->RenderAccelArray = NULL;
458	  pSiSEnt->pScrn_2 = NULL;
459       }
460    } else {
461#endif
462       if(pSiS->BIOS) xfree(pSiS->BIOS);
463       pSiS->BIOS = NULL;
464       if(pSiS->SiS_Pr) xfree(pSiS->SiS_Pr);
465       pSiS->SiS_Pr = NULL;
466       if(pSiS->RenderAccelArray) xfree(pSiS->RenderAccelArray);
467       pSiS->RenderAccelArray = NULL;
468#ifdef SISDUALHEAD
469    }
470#endif
471#ifdef SISMERGED
472    if(pSiS->CRT2HSync) xfree(pSiS->CRT2HSync);
473    pSiS->CRT2HSync = NULL;
474    if(pSiS->CRT2VRefresh) xfree(pSiS->CRT2VRefresh);
475    pSiS->CRT2VRefresh = NULL;
476    if(pSiS->MetaModes) xfree(pSiS->MetaModes);
477    pSiS->MetaModes = NULL;
478    if(pSiS->CRT2pScrn) {
479       if(pSiS->CRT2pScrn->modes) {
480	  while(pSiS->CRT2pScrn->modes)
481	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
482       }
483       if(pSiS->CRT2pScrn->monitor) {
484	  if(pSiS->CRT2pScrn->monitor->Modes) {
485	     while(pSiS->CRT2pScrn->monitor->Modes)
486	        xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
487	  }
488	  if(pSiS->CRT2pScrn->monitor->DDC) xfree(pSiS->CRT2pScrn->monitor->DDC);
489	  xfree(pSiS->CRT2pScrn->monitor);
490       }
491       xfree(pSiS->CRT2pScrn);
492       pSiS->CRT2pScrn = NULL;
493    }
494    if(pSiS->CRT1Modes) {
495       if(pSiS->CRT1Modes != pScrn->modes) {
496	  if(pScrn->modes) {
497	     pScrn->currentMode = pScrn->modes;
498	     do {
499	        DisplayModePtr p = pScrn->currentMode->next;
500	        if(pScrn->currentMode->Private)
501	 	  xfree(pScrn->currentMode->Private);
502	        xfree(pScrn->currentMode);
503	        pScrn->currentMode = p;
504	     } while(pScrn->currentMode != pScrn->modes);
505	  }
506	  pScrn->currentMode = pSiS->CRT1CurrentMode;
507	  pScrn->modes = pSiS->CRT1Modes;
508	  pSiS->CRT1CurrentMode = NULL;
509	  pSiS->CRT1Modes = NULL;
510       }
511    }
512#endif
513    while(pSiS->SISVESAModeList) {
514       sisModeInfoPtr mp = pSiS->SISVESAModeList->next;
515       xfree(pSiS->SISVESAModeList);
516       pSiS->SISVESAModeList = mp;
517    }
518    if(pSiS->pVbe) vbeFree(pSiS->pVbe);
519    pSiS->pVbe = NULL;
520
521#ifdef SISUSEDEVPORT
522    if(pSiS->sisdevportopen)   close(sisdevport);
523#endif
524
525    if(pScrn->driverPrivate == NULL)
526        return;
527    xfree(pScrn->driverPrivate);
528    pScrn->driverPrivate = NULL;
529}
530
531static void
532SISErrorLog(ScrnInfoPtr pScrn, const char *format, ...)
533{
534    va_list ap;
535    static const char *str = "**************************************************\n";
536
537    va_start(ap, format);
538    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
539    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
540	"                      ERROR:\n");
541    xf86VDrvMsgVerb(pScrn->scrnIndex, X_ERROR, 1, format, ap);
542    va_end(ap);
543    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
544	"                  END OF MESSAGE\n");
545    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, str);
546}
547
548static void
549SiS_SiSFB_Lock(ScrnInfoPtr pScrn, Bool lock)
550{
551    SISPtr  pSiS = SISPTR(pScrn);
552    int     fd;
553    CARD32  parm;
554
555    if(!pSiS->sisfbfound) return;
556    if(!pSiS->sisfb_havelock) return;
557
558    if((fd = open(pSiS->sisfbdevname, 'r')) != -1) {
559       parm = lock ? 1 : 0;
560       ioctl(fd, SISFB_SET_LOCK, &parm);
561       close(fd);
562    }
563}
564
565/* Probe()
566 *
567 * Mandatory
568 */
569static Bool
570SISProbe(DriverPtr drv, int flags)
571{
572    int     i;
573    GDevPtr *devSections;
574    int     *usedChipsSiS, *usedChipsXGI;
575    int     numDevSections;
576    int     numUsed, numUsedSiS, numUsedXGI;
577    Bool    foundScreen = FALSE;
578
579    /*
580     * The aim here is to find all cards that this driver can handle,
581     * and for the ones not already claimed by another driver, claim the
582     * slot, and allocate a ScrnInfoRec.
583     *
584     * This should be a minimal probe, and it should under no circumstances
585     * change the state of the hardware.  Because a device is found, don't
586     * assume that it will be used.  Don't do any initialisations other than
587     * the required ScrnInfoRec initialisations.  Don't allocate any new
588     * data structures.
589     *
590     */
591
592    /*
593     * Next we check, if there has been a chipset override in the config file.
594     * For this we must find out if there is an active device section which
595     * is relevant, i.e., which has no driver specified or has THIS driver
596     * specified.
597     */
598
599    if((numDevSections = xf86MatchDevice(SIS_DRIVER_NAME, &devSections)) <= 0) {
600       /*
601        * There's no matching device section in the config file, so quit
602        * now.
603        */
604       return FALSE;
605    }
606
607    /*
608     * We need to probe the hardware first.  We then need to see how this
609     * fits in with what is given in the config file, and allow the config
610     * file info to override any contradictions.
611     */
612
613    /*
614     * All of the cards this driver supports are PCI, so the "probing" just
615     * amounts to checking the PCI data that the server has already collected.
616     */
617    if(xf86GetPciVideoInfo() == NULL) {
618       /*
619        * We won't let anything in the config file override finding no
620        * PCI video cards at all.
621        */
622       return FALSE;
623    }
624
625    numUsedSiS = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_SIS,
626			SISChipsets, SISPciChipsets, devSections,
627			numDevSections, drv, &usedChipsSiS);
628
629    numUsedXGI = xf86MatchPciInstances(SIS_NAME, PCI_VENDOR_XGI,
630			XGIChipsets, XGIPciChipsets, devSections,
631			numDevSections, drv, &usedChipsXGI);
632
633    /* Free it since we don't need that list after this */
634    xfree(devSections);
635
636    numUsed = numUsedSiS + numUsedXGI;
637
638    if(numUsed <= 0)
639       return FALSE;
640
641    if(flags & PROBE_DETECT) {
642
643	foundScreen = TRUE;
644
645    } else for(i = 0; i < numUsed; i++) {
646
647	ScrnInfoPtr pScrn;
648#ifdef SISDUALHEAD
649	EntityInfoPtr pEnt;
650#endif
651
652	/* Allocate a ScrnInfoRec and claim the slot */
653	pScrn = NULL;
654
655	if((pScrn = xf86ConfigPciEntity(pScrn, 0,
656			(i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS],
657			(i < numUsedSiS) ? SISPciChipsets  : XGIPciChipsets,
658			NULL, NULL, NULL, NULL, NULL))) {
659	    /* Fill in what we can of the ScrnInfoRec */
660	    pScrn->driverVersion    = SIS_CURRENT_VERSION;
661	    pScrn->driverName       = SIS_DRIVER_NAME;
662	    pScrn->name             = SIS_NAME;
663	    pScrn->Probe            = SISProbe;
664	    pScrn->PreInit          = SISPreInit;
665	    pScrn->ScreenInit       = SISScreenInit;
666	    pScrn->SwitchMode       = SISSwitchMode;
667	    pScrn->AdjustFrame      = SISAdjustFrame;
668	    pScrn->EnterVT          = SISEnterVT;
669	    pScrn->LeaveVT          = SISLeaveVT;
670	    pScrn->FreeScreen       = SISFreeScreen;
671	    pScrn->ValidMode        = SISValidMode;
672#ifdef X_XF86MiscPassMessage
673	    if(xf86GetVersion() >= XF86_VERSION_NUMERIC(4,3,99,2,0)) {
674	       pScrn->HandleMessage = SISHandleMessage;
675	    }
676#endif
677	    foundScreen = TRUE;
678	}
679
680#ifdef SISDUALHEAD
681	pEnt = xf86GetEntityInfo((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
682
683	if(pEnt->chipset == PCI_CHIP_SIS630 || pEnt->chipset == PCI_CHIP_SIS540 ||
684	   pEnt->chipset == PCI_CHIP_SIS650 || pEnt->chipset == PCI_CHIP_SIS550 ||
685	   pEnt->chipset == PCI_CHIP_SIS315 || pEnt->chipset == PCI_CHIP_SIS315H ||
686	   pEnt->chipset == PCI_CHIP_SIS315PRO || pEnt->chipset == PCI_CHIP_SIS330 ||
687	   pEnt->chipset == PCI_CHIP_SIS300 || pEnt->chipset == PCI_CHIP_SIS660 ||
688	   pEnt->chipset == PCI_CHIP_SIS340 || pEnt->chipset == PCI_CHIP_XGIXG40) {
689
690	    SISEntPtr pSiSEnt = NULL;
691	    DevUnion  *pPriv;
692
693	    xf86SetEntitySharable((i < numUsedSiS) ? usedChipsSiS[i] : usedChipsXGI[i-numUsedSiS]);
694	    if(SISEntityIndex < 0) {
695	       SISEntityIndex = xf86AllocateEntityPrivateIndex();
696	    }
697	    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex);
698	    if(!pPriv->ptr) {
699	       pPriv->ptr = xnfcalloc(sizeof(SISEntRec), 1);
700	       pSiSEnt = pPriv->ptr;
701	       memset(pSiSEnt, 0, sizeof(SISEntRec));
702	       pSiSEnt->lastInstance = -1;
703	    } else {
704	       pSiSEnt = pPriv->ptr;
705	    }
706	    pSiSEnt->lastInstance++;
707	    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
708	                                   pSiSEnt->lastInstance);
709	}
710#endif /* DUALHEAD */
711
712    }
713
714    if(usedChipsSiS) xfree(usedChipsSiS);
715    if(usedChipsXGI) xfree(usedChipsXGI);
716
717    return foundScreen;
718}
719
720/* Various helpers */
721
722static unsigned short
723calcgammaval(int j, int nramp, float invgamma, float bri, float c)
724{
725    float k = (float)j;
726    float nrm1 = (float)(nramp - 1);
727    float con = c * nrm1 / 3.0;
728    float l, v;
729
730    if(con != 0.0) {
731       l = nrm1 / 2.0;
732       if(con <= 0.0) {
733          k -= l;
734          k *= (l + con) / l;
735       } else {
736          l -= 1.0;
737          k -= l;
738          k *= l / (l - con);
739       }
740       k += l;
741       if(k < 0.0) k = 0.0;
742    }
743
744    if(invgamma == 1.0) {
745       v = k / nrm1 * 65535.0;
746    } else {
747       v = pow(k / nrm1, invgamma) * 65535.0 + 0.5;
748    }
749
750    v += (bri * (65535.0 / 3.0)) ;
751
752    if(v < 0.0) v = 0.0;
753    else if(v > 65535.0) v = 65535.0;
754
755    return (unsigned short)v;
756}
757
758#ifdef SISGAMMARAMP
759void
760SISCalculateGammaRamp(ScreenPtr pScreen, ScrnInfoPtr pScrn)
761{
762   SISPtr pSiS = SISPTR(pScrn);
763   int    i, j, nramp;
764   UShort *ramp[3];
765   float  gamma_max[3], framp;
766   Bool   newmethod = FALSE;
767
768   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
769      newmethod = TRUE;
770   } else {
771      gamma_max[0] = (float)pSiS->GammaBriR / 1000;
772      gamma_max[1] = (float)pSiS->GammaBriG / 1000;
773      gamma_max[2] = (float)pSiS->GammaBriB / 1000;
774   }
775
776   if(!(nramp = xf86GetGammaRampSize(pScreen))) return;
777
778   for(i=0; i<3; i++) {
779      ramp[i] = (UShort *)xalloc(nramp * sizeof(UShort));
780      if(!ramp[i]) {
781	 if(ramp[0]) { xfree(ramp[0]); ramp[0] = NULL; }
782	 if(ramp[1]) { xfree(ramp[1]); ramp[1] = NULL; }
783	 return;
784      }
785   }
786
787   if(newmethod) {
788
789      for(i = 0; i < 3; i++) {
790
791         float invgamma = 0.0, bri = 0.0, con = 0.0;
792
793         switch(i) {
794         case 0: invgamma = 1. / pScrn->gamma.red;
795		 bri = pSiS->NewGammaBriR;
796		 con = pSiS->NewGammaConR;
797		 break;
798         case 1: invgamma = 1. / pScrn->gamma.green;
799		 bri = pSiS->NewGammaBriG;
800		 con = pSiS->NewGammaConG;
801		 break;
802         case 2: invgamma = 1. / pScrn->gamma.blue;
803		 bri = pSiS->NewGammaBriB;
804                 con = pSiS->NewGammaConB;
805		 break;
806         }
807
808	 for(j = 0; j < nramp; j++) {
809	    ramp[i][j] = calcgammaval(j, nramp, invgamma, bri, con);
810	 }
811
812      }
813
814   } else {
815
816      for(i = 0; i < 3; i++) {
817         int fullscale = 65535 * gamma_max[i];
818         float dramp = 1. / (nramp - 1);
819         float invgamma = 0.0, v;
820
821         switch(i) {
822         case 0: invgamma = 1. / pScrn->gamma.red; break;
823         case 1: invgamma = 1. / pScrn->gamma.green; break;
824         case 2: invgamma = 1. / pScrn->gamma.blue; break;
825         }
826
827         for(j = 0; j < nramp; j++) {
828	    framp = pow(j * dramp, invgamma);
829
830	    v = (fullscale < 0) ? (65535 + fullscale * framp) :
831			       fullscale * framp;
832	    if(v < 0) v = 0;
833	    else if(v > 65535) v = 65535;
834	    ramp[i][j] = (UShort)v;
835         }
836      }
837
838   }
839
840   xf86ChangeGammaRamp(pScreen, nramp, ramp[0], ramp[1], ramp[2]);
841
842   xfree(ramp[0]);
843   xfree(ramp[1]);
844   xfree(ramp[2]);
845   ramp[0] = ramp[1] = ramp[2] = NULL;
846}
847#endif
848
849void
850SISCalculateGammaRampCRT2(ScrnInfoPtr pScrn)
851{
852   SISPtr pSiS = SISPTR(pScrn);
853   int    i;
854   int    myshift = 16 - pScrn->rgbBits;
855   int    maxvalue = (1 << pScrn->rgbBits) - 1;
856   int    reds = pScrn->mask.red >> pScrn->offset.red;
857   int    greens = pScrn->mask.green >> pScrn->offset.green;
858   int    blues = pScrn->mask.blue >> pScrn->offset.blue;
859   float  framp, invgamma1, invgamma2, invgamma3, v;
860
861   invgamma1  = 1. / pSiS->GammaR2;
862   invgamma2  = 1. / pSiS->GammaG2;
863   invgamma3  = 1. / pSiS->GammaB2;
864
865   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_OLDGAMMAINUSE)) {
866
867      for(i = 0; i < pSiS->CRT2ColNum; i++) {
868         pSiS->crt2gcolortable[i].red = calcgammaval(i, pSiS->CRT2ColNum, invgamma1,
869			pSiS->NewGammaBriR2, pSiS->NewGammaConR2) >> myshift;
870         pSiS->crt2gcolortable[i].green = calcgammaval(i, pSiS->CRT2ColNum, invgamma2,
871			pSiS->NewGammaBriG2, pSiS->NewGammaConG2) >> myshift;
872         pSiS->crt2gcolortable[i].blue = calcgammaval(i, pSiS->CRT2ColNum, invgamma3,
873			pSiS->NewGammaBriB2, pSiS->NewGammaConB2) >> myshift;
874      }
875
876   } else {
877
878      int fullscale1 = 65536 * (float)pSiS->GammaBriR2 / 1000;
879      int fullscale2 = 65536 * (float)pSiS->GammaBriG2 / 1000;
880      int fullscale3 = 65536 * (float)pSiS->GammaBriB2 / 1000;
881
882      float dramp = 1. / (pSiS->CRT2ColNum - 1);
883
884      for(i = 0; i < pSiS->CRT2ColNum; i++) {
885         framp = pow(i * dramp, invgamma1);
886         v = (fullscale1 < 0) ? (65535 + fullscale1 * framp) : fullscale1 * framp;
887         if(v < 0) v = 0;
888         else if(v > 65535) v = 65535;
889         pSiS->crt2gcolortable[i].red = ((UShort)v) >> myshift;
890         framp = pow(i * dramp, invgamma2);
891         v = (fullscale2 < 0) ? (65535 + fullscale2 * framp) : fullscale2 * framp;
892         if(v < 0) v = 0;
893         else if(v > 65535) v = 65535;
894         pSiS->crt2gcolortable[i].green = ((UShort)v) >> myshift;
895         framp = pow(i * dramp, invgamma3);
896         v = (fullscale3 < 0) ? (65535 + fullscale3 * framp) : fullscale3 * framp;
897         if(v < 0) v = 0;
898         else if(v > 65535) v = 65535;
899         pSiS->crt2gcolortable[i].blue = ((UShort)v) >> myshift;
900      }
901
902   }
903
904   for(i = 0; i < pSiS->CRT2ColNum; i++) {
905      pSiS->crt2colors[i].red =
906         pSiS->crt2gcolortable[i * maxvalue / reds].red;
907      pSiS->crt2colors[i].green =
908         pSiS->crt2gcolortable[i * maxvalue / greens].green;
909      pSiS->crt2colors[i].blue  =
910         pSiS->crt2gcolortable[i * maxvalue / blues].blue;
911   }
912}
913
914/* If monitor section has no HSync/VRefresh data,
915 * derive it from DDC data.
916 */
917static void
918SiSSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
919{
920   MonPtr      mon = pScrn->monitor;
921   xf86MonPtr  ddc = mon->DDC;
922   float       myhhigh = 0.0, myhlow = 0.0, htest;
923   int         myvhigh = 0, myvlow = 0, vtest, i;
924   UChar temp;
925   const myhddctiming myhtiming[12] = {
926       { 1, 0x20, 31.6 }, /* rounded up by .1 */
927       { 1, 0x80, 31.6 },
928       { 1, 0x02, 35.3 },
929       { 1, 0x04, 37.6 },
930       { 1, 0x08, 38.0 },
931       { 1, 0x01, 38.0 },
932       { 2, 0x40, 47.0 },
933       { 2, 0x80, 48.2 },
934       { 2, 0x08, 48.5 },
935       { 2, 0x04, 56.6 },
936       { 2, 0x02, 60.1 },
937       { 2, 0x01, 80.1 }
938   };
939   const myvddctiming myvtiming[11] = {
940       { 1, 0x02, 56 },
941       { 1, 0x01, 60 },
942       { 2, 0x08, 60 },
943       { 2, 0x04, 70 },
944       { 1, 0x80, 71 },
945       { 1, 0x08, 72 },
946       { 2, 0x80, 72 },
947       { 1, 0x04, 75 },
948       { 2, 0x40, 75 },
949       { 2, 0x02, 75 },
950       { 2, 0x01, 75 }
951   };
952
953   if(flag) { /* HSync */
954
955      for(i = 0; i < 4; i++) {
956	 if(ddc->det_mon[i].type == DS_RANGES) {
957	    mon->nHsync = 1;
958	    mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h;
959	    mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h;
960	    if(mon->hsync[0].lo > 32.0 || mon->hsync[0].hi < 31.0) {
961	       if(ddc->timings1.t1 & 0x80) {
962		  mon->nHsync++;
963		  mon->hsync[1].lo = 31.0;
964		  mon->hsync[1].hi = 32.0;
965	       }
966	    }
967	    return;
968	 }
969      }
970
971      /* If no sync ranges detected in detailed timing table, we
972       * derive them from supported VESA modes.
973       */
974
975      for(i = 0; i < 12; i++) {
976	 if(myhtiming[i].whichone == 1) temp = ddc->timings1.t1;
977	 else                           temp = ddc->timings1.t2;
978	 if(temp & myhtiming[i].mask) {
979	    if((i == 0) || (myhlow > myhtiming[i].rate))
980	       myhlow = myhtiming[i].rate;
981	 }
982	 if(myhtiming[11-i].whichone == 1) temp = ddc->timings1.t1;
983	 else                              temp = ddc->timings1.t2;
984	 if(temp & myhtiming[11-i].mask) {
985	    if((i == 0) || (myhhigh < myhtiming[11-i].rate))
986	       myhhigh = myhtiming[11-i].rate;
987	 }
988      }
989
990      for(i = 0; i < STD_TIMINGS; i++) {
991	 if(ddc->timings2[i].hsize > 256) {
992	    htest = ddc->timings2[i].refresh * 1.05 * ddc->timings2[i].vsize / 1000.0;
993	    if(htest < myhlow)  myhlow  = htest;
994	    if(htest > myhhigh) myhhigh = htest;
995	 }
996      }
997
998      if((myhhigh > 0.0) && (myhlow > 0.0)) {
999	 mon->nHsync = 1;
1000	 mon->hsync[0].lo = myhlow - 0.1;
1001	 mon->hsync[0].hi = myhhigh;
1002      }
1003
1004
1005   } else {  /* Vrefresh */
1006
1007      for(i = 0; i < 4; i++) {
1008         if(ddc->det_mon[i].type == DS_RANGES) {
1009	    mon->nVrefresh = 1;
1010	    mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v;
1011	    mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v;
1012	    if(mon->vrefresh[0].lo > 72 || mon->vrefresh[0].hi < 70) {
1013	       if(ddc->timings1.t1 & 0x80) {
1014		  mon->nVrefresh++;
1015		  mon->vrefresh[1].lo = 71;
1016		  mon->vrefresh[1].hi = 71;
1017	       }
1018	    }
1019	    return;
1020         }
1021      }
1022
1023      for(i = 0; i < 11; i++) {
1024	 if(myvtiming[i].whichone == 1) temp = ddc->timings1.t1;
1025	 else                           temp = ddc->timings1.t2;
1026	 if(temp & myvtiming[i].mask) {
1027	    if((i == 0) || (myvlow > myvtiming[i].rate))
1028	       myvlow = myvtiming[i].rate;
1029	 }
1030	 if(myvtiming[10-i].whichone == 1) temp = ddc->timings1.t1;
1031	 else                              temp = ddc->timings1.t2;
1032	 if(temp & myvtiming[10-i].mask) {
1033	    if((i == 0) || (myvhigh < myvtiming[10-i].rate))
1034	       myvhigh = myvtiming[10-i].rate;
1035	 }
1036      }
1037
1038      for(i = 0; i < STD_TIMINGS; i++) {
1039	 if(ddc->timings2[i].hsize > 256) {
1040	    vtest = ddc->timings2[i].refresh;
1041	    if(vtest < myvlow)  myvlow  = vtest;
1042	    if(vtest > myvhigh) myvhigh = vtest;
1043	 }
1044      }
1045
1046      if((myvhigh > 0) && (myvlow > 0)) {
1047	 mon->nVrefresh = 1;
1048	 mon->vrefresh[0].lo = myvlow;
1049	 mon->vrefresh[0].hi = myvhigh;
1050      }
1051
1052   }
1053}
1054
1055static Bool
1056SiSAllowSyncOverride(SISPtr pSiS, Bool fromDDC)
1057{
1058   if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
1059
1060#ifdef SISDUALHEAD
1061   if(pSiS->DualHeadMode) {
1062      if(pSiS->SecondHead) {
1063         if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
1064      } else {
1065         if((pSiS->VBFlags & CRT2_TV) ||
1066	    ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC))) return TRUE;
1067      }
1068      return FALSE;
1069   }
1070#endif
1071
1072#ifdef SISMERGED
1073   if(pSiS->MergedFB) {
1074      if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
1075      return FALSE;
1076   }
1077#endif
1078
1079   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
1080      if( (pSiS->VBFlags & CRT2_TV) ||
1081	  ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) return TRUE;
1082   } else if((pSiS->VBFlags & CRT1_LCDA) && (!fromDDC)) return TRUE;
1083
1084   return FALSE;
1085}
1086
1087static Bool
1088SiSCheckForH(float hsync, MonPtr monitor)
1089{
1090   int i;
1091   for(i = 0; i < monitor->nHsync; i++) {
1092      if((hsync > monitor->hsync[i].lo * (1.0 - SYNC_TOLERANCE)) &&
1093	 (hsync < monitor->hsync[i].hi * (1.0 + SYNC_TOLERANCE)))
1094	 break;
1095   }
1096   if(i == monitor->nHsync) return FALSE;
1097   return TRUE;
1098}
1099
1100static Bool
1101SiSCheckForV(float vrefresh, MonPtr monitor)
1102{
1103   int i;
1104   for(i = 0; i < monitor->nVrefresh; i++) {
1105      if((vrefresh > monitor->vrefresh[i].lo * (1.0 - SYNC_TOLERANCE)) &&
1106	 (vrefresh < monitor->vrefresh[i].hi * (1.0 + SYNC_TOLERANCE)))
1107	 break;
1108   }
1109   if(i == monitor->nVrefresh) return FALSE;
1110   return TRUE;
1111}
1112
1113static Bool
1114CheckAndOverruleH(ScrnInfoPtr pScrn, MonPtr monitor)
1115{
1116   DisplayModePtr mode = monitor->Modes;
1117   float mymin = 30.0, mymax = 80.0, hsync;
1118   Bool doit = FALSE;
1119
1120   for(hsync = mymin; hsync <= mymax; hsync += .5) {
1121      if(!SiSCheckForH(hsync, monitor)) doit = TRUE;
1122   }
1123
1124   if(mode) {
1125      do {
1126         if(mode->type & M_T_BUILTIN) {
1127	    hsync = (float)mode->Clock / (float)mode->HTotal;
1128	    if(!SiSCheckForH(hsync, monitor)) {
1129	       doit = TRUE;
1130	       if(hsync < mymin) mymin = hsync;
1131	       if(hsync > mymax) mymax = hsync;
1132	    }
1133	 }
1134      } while((mode = mode->next));
1135   }
1136
1137   if(doit) {
1138      monitor->nHsync = 1;
1139      monitor->hsync[0].lo = mymin;
1140      monitor->hsync[0].hi = mymax;
1141      return TRUE;
1142   }
1143
1144   return FALSE;
1145}
1146
1147static Bool
1148CheckAndOverruleV(ScrnInfoPtr pScrn, MonPtr monitor)
1149{
1150   DisplayModePtr mode = monitor->Modes;
1151   float mymin = 59.0, mymax = 61.0, vrefresh;
1152   Bool doit = FALSE, ret = FALSE;
1153
1154   for(vrefresh = mymin; vrefresh <= mymax; vrefresh += 1.0) {
1155      if(!SiSCheckForV(vrefresh, monitor)) doit = TRUE;
1156   }
1157
1158   if(mode) {
1159      do {
1160         if(mode->type & M_T_BUILTIN) {
1161	    vrefresh = mode->Clock * 1000.0 / (mode->HTotal * mode->VTotal);
1162	    if(mode->Flags & V_INTERLACE) vrefresh *= 2.0;
1163	    if(mode->Flags & V_DBLSCAN) vrefresh /= 2.0;
1164	    if(!SiSCheckForH(vrefresh, monitor)) {
1165	       doit = TRUE;
1166	       if(vrefresh < mymin) mymin = vrefresh;
1167	       if(vrefresh > mymax) mymax = vrefresh;
1168	    }
1169	 }
1170      } while((mode = mode->next));
1171   }
1172
1173   if(doit) {
1174      monitor->nVrefresh = 1;
1175      monitor->vrefresh[0].lo = mymin;
1176      monitor->vrefresh[0].hi = mymax;
1177      ret = TRUE;
1178   }
1179
1180   /* special for 640x400/320x200/@70Hz (VGA/IBM 720x480) */
1181   if( (!SiSCheckForV(71, monitor)) &&
1182       (monitor->nVrefresh < MAX_VREFRESH) ) {
1183      monitor->vrefresh[monitor->nVrefresh].lo = 71;
1184      monitor->vrefresh[monitor->nVrefresh].hi = 71;
1185      monitor->nVrefresh++;
1186      ret = TRUE;
1187   }
1188   return ret;
1189}
1190
1191/* Some helper functions for MergedFB mode */
1192
1193#ifdef SISMERGED
1194
1195/* Helper function for CRT2 monitor vrefresh/hsync options
1196 * (Code base from mga driver)
1197 */
1198static int
1199SiSStrToRanges(range *r, char *s, int max)
1200{
1201   float num = 0.0;
1202   int rangenum = 0;
1203   Bool gotdash = FALSE;
1204   Bool nextdash = FALSE;
1205   char *strnum = NULL;
1206   do {
1207      switch(*s) {
1208      case '0':
1209      case '1':
1210      case '2':
1211      case '3':
1212      case '4':
1213      case '5':
1214      case '6':
1215      case '7':
1216      case '8':
1217      case '9':
1218      case '.':
1219         if(strnum == NULL) {
1220            strnum = s;
1221            gotdash = nextdash;
1222            nextdash = FALSE;
1223         }
1224         break;
1225      case '-':
1226      case ' ':
1227      case 0:
1228         if(strnum == NULL) break;
1229         sscanf(strnum, "%f", &num);
1230	 strnum = NULL;
1231         if(gotdash) {
1232            r[rangenum - 1].hi = num;
1233         } else {
1234            r[rangenum].lo = num;
1235            r[rangenum].hi = num;
1236            rangenum++;
1237         }
1238         if(*s == '-') nextdash = (rangenum != 0);
1239	 else if(rangenum >= max) return rangenum;
1240         break;
1241      default:
1242         return 0;
1243      }
1244
1245   } while(*(s++) != 0);
1246
1247   return rangenum;
1248}
1249
1250/* Copy and link two modes (i, j) for mergedfb mode
1251 * (Code base taken from mga driver)
1252 *
1253 * - Copy mode i, merge j to copy of i, link the result to dest
1254 * - Link i and j in private record.
1255 * - If dest is NULL, return value is copy of i linked to itself.
1256 * - For mergedfb auto-config, we only check the dimension
1257 *   against virtualX/Y, if they were user-provided.
1258 * - No special treatment required for CRTxxOffs.
1259 * - Provide fake dotclock in order to distinguish between similar
1260 *   looking MetaModes (for RandR and VidMode extensions)
1261 * - Set unique VRefresh of dest mode for RandR
1262 */
1263static DisplayModePtr
1264SiSCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest,
1265                 DisplayModePtr i, DisplayModePtr j,
1266		 SiSScrn2Rel srel)
1267{
1268    SISPtr pSiS = SISPTR(pScrn);
1269    DisplayModePtr mode;
1270    int dx = 0,dy = 0;
1271
1272    if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest;
1273    memcpy(mode, i, sizeof(DisplayModeRec));
1274    if(!((mode->Private = xalloc(sizeof(SiSMergedDisplayModeRec))))) {
1275       xfree(mode);
1276       return dest;
1277    }
1278    ((SiSMergedDisplayModePtr)mode->Private)->CRT1 = i;
1279    ((SiSMergedDisplayModePtr)mode->Private)->CRT2 = j;
1280    ((SiSMergedDisplayModePtr)mode->Private)->CRT2Position = srel;
1281    mode->PrivSize = 0;
1282
1283    switch(srel) {
1284    case sisLeftOf:
1285    case sisRightOf:
1286       if(!(pScrn->display->virtualX)) {
1287          dx = i->HDisplay + j->HDisplay;
1288       } else {
1289          dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay);
1290       }
1291       dx -= mode->HDisplay;
1292       if(!(pScrn->display->virtualY)) {
1293          dy = max(i->VDisplay, j->VDisplay);
1294       } else {
1295          dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1296       }
1297       dy -= mode->VDisplay;
1298       break;
1299    case sisAbove:
1300    case sisBelow:
1301       if(!(pScrn->display->virtualY)) {
1302          dy = i->VDisplay + j->VDisplay;
1303       } else {
1304          dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay);
1305       }
1306       dy -= mode->VDisplay;
1307       if(!(pScrn->display->virtualX)) {
1308          dx = max(i->HDisplay, j->HDisplay);
1309       } else {
1310          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1311       }
1312       dx -= mode->HDisplay;
1313       break;
1314    case sisClone:
1315       if(!(pScrn->display->virtualX)) {
1316          dx = max(i->HDisplay, j->HDisplay);
1317       } else {
1318          dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay));
1319       }
1320       dx -= mode->HDisplay;
1321       if(!(pScrn->display->virtualY)) {
1322          dy = max(i->VDisplay, j->VDisplay);
1323       } else {
1324	  dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay));
1325       }
1326       dy -= mode->VDisplay;
1327       break;
1328    }
1329    mode->HDisplay += dx;
1330    mode->HSyncStart += dx;
1331    mode->HSyncEnd += dx;
1332    mode->HTotal += dx;
1333    mode->VDisplay += dy;
1334    mode->VSyncStart += dy;
1335    mode->VSyncEnd += dy;
1336    mode->VTotal += dy;
1337
1338    mode->type = M_T_DEFAULT;
1339#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,2,0)
1340    /* Set up as user defined (ie fake that the mode has been named in the
1341     * Modes-list in the screen section; corrects cycling with CTRL-ALT-[-+]
1342     * when source mode has not been listed there.)
1343     */
1344    mode->type |= M_T_USERDEF;
1345#endif
1346
1347    /* Set the VRefresh field (in order to make RandR use it for the rates). We
1348     * simply set this to the refresh rate for the CRT1 mode (since CRT2 will
1349     * mostly be LCD or TV anyway).
1350     */
1351    mode->VRefresh = SiSCalcVRate(i);
1352
1353    if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > pSiS->maxxfbmem) ||
1354	(mode->HDisplay > 4088) ||
1355	(mode->VDisplay > 4096) ) {
1356
1357       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1358		"Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n",
1359		mode->name, mode->HDisplay, mode->VDisplay);
1360       xfree(mode->Private);
1361       xfree(mode);
1362
1363       return dest;
1364    }
1365
1366#ifdef SISXINERAMA
1367    if(srel != sisClone) {
1368       pSiS->AtLeastOneNonClone = TRUE;
1369    }
1370#endif
1371
1372    /* Now see if the resulting mode would be discarded as a "size" by the
1373     * RandR extension, and increase its clock by 1000 in case it does.
1374     */
1375    if(dest) {
1376       DisplayModePtr t = dest;
1377       do {
1378          if((t->HDisplay == mode->HDisplay) &&
1379	     (t->VDisplay == mode->VDisplay) &&
1380	     ((int)(t->VRefresh + .5) == (int)(mode->VRefresh + .5))) {
1381	     mode->VRefresh += 1000.0;
1382	  }
1383	  t = t->next;
1384       } while((t) && (t != dest));
1385    }
1386
1387    /* Provide a fake but unique DotClock in order to trick the vidmode
1388     * extension to allow selecting among a number of modes whose merged result
1389     * looks identical but consists of different modes for CRT1 and CRT2
1390     */
1391    mode->Clock = (int)(mode->VRefresh * 1000.0);
1392
1393    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1394	"Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d (%d)%s\n",
1395	i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay,
1396	mode->HDisplay, mode->VDisplay, (int)mode->VRefresh,
1397	(srel == sisClone) ? " (Clone)" : "");
1398
1399    mode->next = mode;
1400    mode->prev = mode;
1401
1402    if(dest) {
1403       mode->next = dest->next; 	/* Insert node after "dest" */
1404       dest->next->prev = mode;
1405       mode->prev = dest;
1406       dest->next = mode;
1407    }
1408
1409    return mode;
1410}
1411
1412/* Helper function to find a mode from a given name
1413 * (Code base taken from mga driver)
1414 */
1415static DisplayModePtr
1416SiSGetModeFromName(char* str, DisplayModePtr i)
1417{
1418    DisplayModePtr c = i;
1419    if(!i) return NULL;
1420    do {
1421       if(strcmp(str, c->name) == 0) return c;
1422       c = c->next;
1423    } while(c != i);
1424    return NULL;
1425}
1426
1427static DisplayModePtr
1428SiSFindWidestTallestMode(DisplayModePtr i, Bool tallest)
1429{
1430    DisplayModePtr c = i, d = NULL;
1431    int max = 0;
1432    if(!i) return NULL;
1433    do {
1434       if(tallest) {
1435          if(c->VDisplay > max) {
1436	     max = c->VDisplay;
1437	     d = c;
1438          }
1439       } else {
1440          if(c->HDisplay > max) {
1441	     max = c->HDisplay;
1442	     d = c;
1443          }
1444       }
1445       c = c->next;
1446    } while(c != i);
1447    return d;
1448}
1449
1450static void
1451SiSFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest,
1452				DisplayModePtr *a, DisplayModePtr *b)
1453{
1454    DisplayModePtr c = i, d;
1455    int max = 0;
1456    Bool foundone;
1457
1458    (*a) = (*b) = NULL;
1459
1460    if(!i || !j) return;
1461
1462    do {
1463       d = j;
1464       foundone = FALSE;
1465       do {
1466	  if( (c->HDisplay == d->HDisplay) &&
1467	      (c->VDisplay == d->VDisplay) ) {
1468	     foundone = TRUE;
1469	     break;
1470	  }
1471	  d = d->next;
1472       } while(d != j);
1473       if(foundone) {
1474	  if(tallest) {
1475	     if(c->VDisplay > max) {
1476		max = c->VDisplay;
1477		(*a) = c;
1478		(*b) = d;
1479	     }
1480	  } else {
1481	     if(c->HDisplay > max) {
1482		max = c->HDisplay;
1483		(*a) = c;
1484		(*b) = d;
1485	     }
1486	  }
1487       }
1488       c = c->next;
1489    } while(c != i);
1490}
1491
1492static DisplayModePtr
1493SiSGenerateModeListFromLargestModes(ScrnInfoPtr pScrn,
1494		    DisplayModePtr i, DisplayModePtr j,
1495		    SiSScrn2Rel srel)
1496{
1497#ifdef SISXINERAMA
1498    SISPtr pSiS = SISPTR(pScrn);
1499#endif
1500    DisplayModePtr mode1 = NULL;
1501    DisplayModePtr mode2 = NULL;
1502    DisplayModePtr mode3 = NULL;
1503    DisplayModePtr mode4 = NULL;
1504    DisplayModePtr result = NULL;
1505
1506#ifdef SISXINERAMA
1507    pSiS->AtLeastOneNonClone = FALSE;
1508#endif
1509
1510    /* Now build a default list of MetaModes.
1511     * - Non-clone: If the user enabled NonRectangular, we use the
1512     * largest mode for each CRT1 and CRT2. If not, we use the largest
1513     * common mode for CRT1 and CRT2 (if available). Additionally, and
1514     * regardless if the above, we produce a clone mode consisting of
1515     * the largest common mode (if available) in order to use DGA.
1516     * - Clone: If the (global) CRT2Position is Clone, we use the
1517     * largest common mode if available, otherwise the first two modes
1518     * in each list.
1519     */
1520
1521    switch(srel) {
1522    case sisLeftOf:
1523    case sisRightOf:
1524       mode1 = SiSFindWidestTallestMode(i, FALSE);
1525       mode2 = SiSFindWidestTallestMode(j, FALSE);
1526       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1527       break;
1528    case sisAbove:
1529    case sisBelow:
1530       mode1 = SiSFindWidestTallestMode(i, TRUE);
1531       mode2 = SiSFindWidestTallestMode(j, TRUE);
1532       SiSFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4);
1533       break;
1534    case sisClone:
1535       SiSFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4);
1536       if(mode3 && mode4) {
1537	  mode1 = mode3;
1538	  mode2 = mode4;
1539       } else {
1540	  mode1 = i;
1541	  mode2 = j;
1542       }
1543    }
1544
1545    if(srel != sisClone) {
1546       if(mode3 && mode4 && !pSiS->NonRect) {
1547	  mode1 = mode3;
1548	  mode2 = mode2;
1549       }
1550    }
1551
1552    if(mode1 && mode2) {
1553       result = SiSCopyModeNLink(pScrn, result, mode1, mode2, srel);
1554    }
1555
1556    if(srel != sisClone) {
1557       if(mode3 && mode4) {
1558	  result = SiSCopyModeNLink(pScrn, result, mode3, mode4, sisClone);
1559       }
1560    }
1561
1562    return result;
1563}
1564
1565/* Generate the merged-fb mode modelist
1566 * (Taken from mga driver)
1567 */
1568static DisplayModePtr
1569SiSGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str,
1570		    DisplayModePtr i, DisplayModePtr j,
1571		    SiSScrn2Rel srel)
1572{
1573#ifdef SISXINERAMA
1574    SISPtr pSiS = SISPTR(pScrn);
1575#endif
1576    char* strmode = str;
1577    char modename[256];
1578    Bool gotdash = FALSE;
1579    char gotsep = 0;
1580    SiSScrn2Rel sr;
1581    DisplayModePtr mode1 = NULL;
1582    DisplayModePtr mode2 = NULL;
1583    DisplayModePtr result = NULL;
1584    int myslen;
1585
1586#ifdef SISXINERAMA
1587    pSiS->AtLeastOneNonClone = FALSE;
1588#endif
1589
1590    do {
1591        switch(*str) {
1592        case 0:
1593        case '-':
1594	case '+':
1595        case ' ':
1596	case ',':
1597	case ';':
1598           if(strmode != str) {
1599
1600              myslen = str - strmode;
1601              if(myslen > 255) myslen = 255;
1602  	      strncpy(modename, strmode, myslen);
1603  	      modename[myslen] = 0;
1604
1605              if(gotdash) {
1606                 if(mode1 == NULL) {
1607  	             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1608  	                        "Error parsing MetaModes parameter\n");
1609  	             return NULL;
1610  	         }
1611                 mode2 = SiSGetModeFromName(modename, j);
1612                 if(!mode2) {
1613                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1614                        "Mode \"%s\" is not a supported mode for CRT2\n", modename);
1615                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1616                        "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename);
1617                    mode1 = NULL;
1618		    gotsep = 0;
1619                 }
1620              } else {
1621                 mode1 = SiSGetModeFromName(modename, i);
1622                 if(!mode1) {
1623                    char* tmps = str;
1624                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1625                        "Mode \"%s\" is not a supported mode for CRT1\n", modename);
1626                    while(*tmps == ' ' || *tmps == ';') tmps++;
1627                    /* skip the next mode */
1628  	            if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
1629                       tmps++;
1630		       /* skip spaces */
1631		       while(*tmps == ' ' || *tmps == ';') tmps++;
1632		       /* skip modename */
1633		       while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++;
1634  	               myslen = tmps - strmode;
1635  	               if(myslen > 255) myslen = 255;
1636  	               strncpy(modename,strmode,myslen);
1637  	               modename[myslen] = 0;
1638                       str = tmps - 1;
1639                    }
1640                    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1641                        "\t(Skipping metamode \"%s\")\n", modename);
1642                    mode1 = NULL;
1643		    gotsep = 0;
1644                 }
1645              }
1646              gotdash = FALSE;
1647           }
1648           strmode = str + 1;
1649           gotdash |= (*str == '-' || *str == '+' || *str == ',');
1650	   if (*str == '-' || *str == '+' || *str == ',')
1651  	      gotsep = *str;
1652
1653           if(*str != 0) break;
1654	   /* Fall through otherwise */
1655
1656        default:
1657           if(!gotdash && mode1) {
1658              sr = srel;
1659	      if(gotsep == '+') sr = sisClone;
1660              if(!mode2) {
1661                 mode2 = SiSGetModeFromName(mode1->name, j);
1662                 sr = sisClone;
1663              }
1664              if(!mode2) {
1665                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1666                     "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name);
1667                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1668                     "\t(Skipping metamode \"%s\")\n", modename);
1669                 mode1 = NULL;
1670              } else {
1671                 result = SiSCopyModeNLink(pScrn, result, mode1, mode2, sr);
1672                 mode1 = NULL;
1673                 mode2 = NULL;
1674              }
1675	      gotsep = 0;
1676           }
1677           break;
1678
1679        }
1680
1681    } while(*(str++) != 0);
1682
1683    return result;
1684}
1685
1686static DisplayModePtr
1687SiSGenerateModeList(ScrnInfoPtr pScrn, char* str,
1688		    DisplayModePtr i, DisplayModePtr j,
1689		    SiSScrn2Rel srel)
1690{
1691   SISPtr pSiS = SISPTR(pScrn);
1692
1693   if(str != NULL) {
1694      return(SiSGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
1695   } else {
1696      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1697	"No MetaModes given, linking %s modes by default\n",
1698	(srel == sisClone) ? "largest common" :
1699	   (pSiS->NonRect ?
1700		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest" :  "tallest")
1701		:
1702		(((srel == sisLeftOf) || (srel == sisRightOf)) ? "widest common" :  "tallest common")) );
1703      return(SiSGenerateModeListFromLargestModes(pScrn, i, j, srel));
1704   }
1705}
1706
1707static void
1708SiSRecalcDefaultVirtualSize(ScrnInfoPtr pScrn)
1709{
1710    SISPtr pSiS = SISPTR(pScrn);
1711    DisplayModePtr mode, bmode;
1712    int maxh, maxv;
1713    static const char *str = "MergedFB: Virtual %s %d\n";
1714    static const char *errstr = "Virtual %s to small for given CRT2Position offset\n";
1715
1716    mode = bmode = pScrn->modes;
1717    maxh = maxv = 0;
1718    do {
1719       if(mode->HDisplay > maxh) maxh = mode->HDisplay;
1720       if(mode->VDisplay > maxv) maxv = mode->VDisplay;
1721       mode = mode->next;
1722    } while(mode != bmode);
1723
1724    maxh += pSiS->CRT1XOffs + pSiS->CRT2XOffs;
1725    maxv += pSiS->CRT1YOffs + pSiS->CRT2YOffs;
1726
1727    if(!(pScrn->display->virtualX)) {
1728       if(maxh > 4088) {
1729	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1730		"Virtual width with CRT2Position offset beyond hardware specs\n");
1731	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1732	  maxh -= (pSiS->CRT1XOffs + pSiS->CRT2XOffs);
1733       }
1734       pScrn->virtualX = maxh;
1735       pScrn->displayWidth = maxh;
1736       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh);
1737    } else {
1738       if(maxh < pScrn->display->virtualX) {
1739	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width");
1740	  pSiS->CRT1XOffs = pSiS->CRT2XOffs = 0;
1741       }
1742    }
1743
1744    if(!(pScrn->display->virtualY)) {
1745       pScrn->virtualY = maxv;
1746       xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv);
1747    } else {
1748       if(maxv < pScrn->display->virtualY) {
1749	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height");
1750	  pSiS->CRT1YOffs = pSiS->CRT2YOffs = 0;
1751       }
1752    }
1753}
1754
1755static void
1756SiSMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, SiSScrn2Rel srel)
1757{
1758   SISPtr pSiS = SISPTR(pScrn1);
1759   MessageType from = X_DEFAULT;
1760   xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC);
1761   xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC);
1762   int ddcWidthmm = 0, ddcHeightmm = 0;
1763   const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n";
1764
1765   /* This sets the DPI for MergedFB mode. The problem is that
1766    * this can never be exact, because the output devices may
1767    * have different dimensions. This function tries to compromise
1768    * through a few assumptions, and it just calculates an average DPI
1769    * value for both monitors.
1770    */
1771
1772   /* Given DisplaySize should regard BOTH monitors */
1773   pScrn1->widthmm = pScrn1->monitor->widthmm;
1774   pScrn1->heightmm = pScrn1->monitor->heightmm;
1775
1776   /* Get DDC display size; if only either CRT1 or CRT2 provided these,
1777    * assume equal dimensions for both, otherwise add dimensions
1778    */
1779   if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) &&
1780       (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) {
1781      ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10;
1782      ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10;
1783      switch(srel) {
1784      case sisLeftOf:
1785      case sisRightOf:
1786	 ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10;
1787	 break;
1788      case sisAbove:
1789      case sisBelow:
1790	 ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10;
1791      default:
1792	 break;
1793      }
1794   } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) {
1795      ddcWidthmm = DDC1->features.hsize * 10;
1796      ddcHeightmm = DDC1->features.vsize * 10;
1797      switch(srel) {
1798      case sisLeftOf:
1799      case sisRightOf:
1800	 ddcWidthmm *= 2;
1801	 break;
1802      case sisAbove:
1803      case sisBelow:
1804	 ddcHeightmm *= 2;
1805      default:
1806	 break;
1807      }
1808   } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) {
1809      ddcWidthmm = DDC2->features.hsize * 10;
1810      ddcHeightmm = DDC2->features.vsize * 10;
1811      switch(srel) {
1812      case sisLeftOf:
1813      case sisRightOf:
1814	 ddcWidthmm *= 2;
1815	 break;
1816      case sisAbove:
1817      case sisBelow:
1818	 ddcHeightmm *= 2;
1819      default:
1820	 break;
1821      }
1822   }
1823
1824   if(monitorResolution > 0) {
1825
1826      /* Set command line given values (overrules given options) */
1827      pScrn1->xDpi = monitorResolution;
1828      pScrn1->yDpi = monitorResolution;
1829      from = X_CMDLINE;
1830
1831   } else if(pSiS->MergedFBXDPI) {
1832
1833      /* Set option-wise given values (overrule DisplaySize) */
1834      pScrn1->xDpi = pSiS->MergedFBXDPI;
1835      pScrn1->yDpi = pSiS->MergedFBYDPI;
1836      from = X_CONFIG;
1837
1838   } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) {
1839
1840      /* Set values calculated from given DisplaySize */
1841      from = X_CONFIG;
1842      if(pScrn1->widthmm > 0) {
1843	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1844      }
1845      if(pScrn1->heightmm > 0) {
1846	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1847      }
1848      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm);
1849
1850    } else if(ddcWidthmm && ddcHeightmm) {
1851
1852      /* Set values from DDC-provided display size */
1853      from = X_PROBED;
1854      xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm );
1855      pScrn1->widthmm = ddcWidthmm;
1856      pScrn1->heightmm = ddcHeightmm;
1857      if(pScrn1->widthmm > 0) {
1858	 pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm);
1859      }
1860      if(pScrn1->heightmm > 0) {
1861	 pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm);
1862      }
1863
1864    } else {
1865
1866      pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI;
1867
1868    }
1869
1870    /* Sanity check */
1871    if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0)
1872       pScrn1->yDpi = pScrn1->xDpi;
1873    if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0)
1874       pScrn1->xDpi = pScrn1->yDpi;
1875
1876    pScrn2->xDpi = pScrn1->xDpi;
1877    pScrn2->yDpi = pScrn1->yDpi;
1878
1879    xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n",
1880		pScrn1->xDpi, pScrn1->yDpi);
1881}
1882
1883/* Pseudo-Xinerama extension for MergedFB mode */
1884#ifdef SISXINERAMA
1885
1886static void
1887SiSUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1)
1888{
1889    SISPtr pSiS = SISPTR(pScrn1);
1890    int crt1scrnnum = 0, crt2scrnnum = 1;
1891    int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0;
1892    int realvirtX, realvirtY;
1893    DisplayModePtr currentMode, firstMode;
1894    Bool infochanged = FALSE;
1895    Bool usenonrect = pSiS->NonRect;
1896    const char *rectxine = "\t... setting up rectangular Xinerama layout\n";
1897
1898    pSiS->MBXNR1XMAX = pSiS->MBXNR1YMAX = pSiS->MBXNR2XMAX = pSiS->MBXNR2YMAX = 65536;
1899    pSiS->HaveNonRect = pSiS->HaveOffsRegions = FALSE;
1900
1901    if(!pSiS->MergedFB) return;
1902
1903    if(SiSnoPanoramiXExtension) return;
1904
1905    if(!SiSXineramadataPtr) return;
1906
1907    if(pSiS->CRT2IsScrn0) {
1908       crt1scrnnum = 1;
1909       crt2scrnnum = 0;
1910    }
1911
1912    /* Attention: Usage of RandR may lead to virtual X and Y dimensions
1913     * actually smaller than our MetaModes. To avoid this, we calculate
1914     * the maxCRT fields here (and not somewhere else, like in CopyNLink)
1915     *
1916     * *** Note: RandR is disabled if one of CRTxxOffs is non-zero.
1917     */
1918
1919    /* "Real" virtual: Virtual without the Offset */
1920    realvirtX = pScrn1->virtualX - pSiS->CRT1XOffs - pSiS->CRT2XOffs;
1921    realvirtY = pScrn1->virtualY - pSiS->CRT1YOffs - pSiS->CRT2YOffs;
1922
1923    if((pSiS->SiSXineramaVX != pScrn1->virtualX) || (pSiS->SiSXineramaVY != pScrn1->virtualY)) {
1924
1925       if(!(pScrn1->modes)) return;
1926
1927       pSiS->maxCRT1_X1 = pSiS->maxCRT1_X2 = 0;
1928       pSiS->maxCRT1_Y1 = pSiS->maxCRT1_Y2 = 0;
1929       pSiS->maxCRT2_X1 = pSiS->maxCRT2_X2 = 0;
1930       pSiS->maxCRT2_Y1 = pSiS->maxCRT2_Y2 = 0;
1931       pSiS->maxClone_X1 = pSiS->maxClone_X2 = 0;
1932       pSiS->maxClone_Y1 = pSiS->maxClone_Y2 = 0;
1933
1934       currentMode = firstMode = pScrn1->modes;
1935
1936       do {
1937
1938          DisplayModePtr p = currentMode->next;
1939          DisplayModePtr i = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT1;
1940          DisplayModePtr j = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2;
1941          SiSScrn2Rel srel = ((SiSMergedDisplayModePtr)currentMode->Private)->CRT2Position;
1942
1943          if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) &&
1944	     (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) &&
1945	     (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) {
1946
1947	     if(srel != sisClone) {
1948		if(pSiS->maxCRT1_X1 == i->HDisplay) {
1949		   if(pSiS->maxCRT1_X2 < j->HDisplay) {
1950		      pSiS->maxCRT1_X2 = j->HDisplay;   /* Widest CRT2 mode displayed with widest CRT1 mode */
1951		   }
1952		} else if(pSiS->maxCRT1_X1 < i->HDisplay) {
1953		   pSiS->maxCRT1_X1 = i->HDisplay;      /* Widest CRT1 mode */
1954		   pSiS->maxCRT1_X2 = j->HDisplay;
1955		}
1956		if(pSiS->maxCRT2_X2 == j->HDisplay) {
1957		   if(pSiS->maxCRT2_X1 < i->HDisplay) {
1958		      pSiS->maxCRT2_X1 = i->HDisplay;   /* Widest CRT1 mode displayed with widest CRT2 mode */
1959		   }
1960		} else if(pSiS->maxCRT2_X2 < j->HDisplay) {
1961		   pSiS->maxCRT2_X2 = j->HDisplay;      /* Widest CRT2 mode */
1962		   pSiS->maxCRT2_X1 = i->HDisplay;
1963		}
1964		if(pSiS->maxCRT1_Y1 == i->VDisplay) {   /* Same as above, but tallest instead of widest */
1965		   if(pSiS->maxCRT1_Y2 < j->VDisplay) {
1966		      pSiS->maxCRT1_Y2 = j->VDisplay;
1967		   }
1968		} else if(pSiS->maxCRT1_Y1 < i->VDisplay) {
1969		   pSiS->maxCRT1_Y1 = i->VDisplay;
1970		   pSiS->maxCRT1_Y2 = j->VDisplay;
1971		}
1972		if(pSiS->maxCRT2_Y2 == j->VDisplay) {
1973		   if(pSiS->maxCRT2_Y1 < i->VDisplay) {
1974		      pSiS->maxCRT2_Y1 = i->VDisplay;
1975		   }
1976		} else if(pSiS->maxCRT2_Y2 < j->VDisplay) {
1977		   pSiS->maxCRT2_Y2 = j->VDisplay;
1978		   pSiS->maxCRT2_Y1 = i->VDisplay;
1979		}
1980	     } else {
1981		if(pSiS->maxClone_X1 < i->HDisplay) {
1982		   pSiS->maxClone_X1 = i->HDisplay;
1983		}
1984		if(pSiS->maxClone_X2 < j->HDisplay) {
1985		   pSiS->maxClone_X2 = j->HDisplay;
1986		}
1987		if(pSiS->maxClone_Y1 < i->VDisplay) {
1988		   pSiS->maxClone_Y1 = i->VDisplay;
1989		}
1990		if(pSiS->maxClone_Y2 < j->VDisplay) {
1991		   pSiS->maxClone_Y2 = j->VDisplay;
1992		}
1993	     }
1994	  }
1995	  currentMode = p;
1996
1997       } while((currentMode) && (currentMode != firstMode));
1998
1999       pSiS->SiSXineramaVX = pScrn1->virtualX;
2000       pSiS->SiSXineramaVY = pScrn1->virtualY;
2001       infochanged = TRUE;
2002
2003    }
2004
2005    if((usenonrect) && (pSiS->CRT2Position != sisClone) && pSiS->maxCRT1_X1) {
2006       switch(pSiS->CRT2Position) {
2007       case sisLeftOf:
2008       case sisRightOf:
2009	  if((pSiS->maxCRT1_Y1 != realvirtY) && (pSiS->maxCRT2_Y2 != realvirtY)) {
2010	     usenonrect = FALSE;
2011	  }
2012	  break;
2013       case sisAbove:
2014       case sisBelow:
2015	  if((pSiS->maxCRT1_X1 != realvirtX) && (pSiS->maxCRT2_X2 != realvirtX)) {
2016	     usenonrect = FALSE;
2017	  }
2018	  break;
2019       case sisClone:
2020	  break;
2021       }
2022       if(infochanged && !usenonrect) {
2023	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2024			"Virtual screen size does not match maximum display modes...\n");
2025	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
2026
2027       }
2028    } else if(infochanged && usenonrect) {
2029       usenonrect = FALSE;
2030       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2031		"Only clone modes available for this virtual screen size...\n");
2032       xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine);
2033    }
2034
2035    if(pSiS->maxCRT1_X1) {		/* Means we have at least one non-clone mode */
2036       switch(pSiS->CRT2Position) {
2037       case sisLeftOf:
2038	  x1 = min(pSiS->maxCRT1_X2, pScrn1->virtualX - pSiS->maxCRT1_X1);
2039	  if(x1 < 0) x1 = 0;
2040	  y1 = pSiS->CRT1YOffs;
2041	  w1 = pScrn1->virtualX - x1;
2042	  h1 = realvirtY;
2043	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
2044	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
2045	     pSiS->NonRectDead.x0 = x1;
2046	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
2047	     pSiS->NonRectDead.y0 = y1 + h1;
2048	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
2049	     pSiS->HaveNonRect = TRUE;
2050	  }
2051	  x2 = 0;
2052	  y2 = pSiS->CRT2YOffs;
2053	  w2 = max(pSiS->maxCRT2_X2, pScrn1->virtualX - pSiS->maxCRT2_X1);
2054	  if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX;
2055	  h2 = realvirtY;
2056	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
2057	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
2058	     pSiS->NonRectDead.x0 = x2;
2059	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
2060	     pSiS->NonRectDead.y0 = y2 + h2;
2061	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
2062	     pSiS->HaveNonRect = TRUE;
2063	  }
2064	  break;
2065       case sisRightOf:
2066	  x1 = 0;
2067	  y1 = pSiS->CRT1YOffs;
2068	  w1 = max(pSiS->maxCRT1_X1, pScrn1->virtualX - pSiS->maxCRT1_X2);
2069	  if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX;
2070	  h1 = realvirtY;
2071	  if((usenonrect) && (pSiS->maxCRT1_Y1 != realvirtY)) {
2072	     h1 = pSiS->MBXNR1YMAX = pSiS->maxCRT1_Y1;
2073	     pSiS->NonRectDead.x0 = x1;
2074	     pSiS->NonRectDead.x1 = x1 + w1 - 1;
2075	     pSiS->NonRectDead.y0 = y1 + h1;
2076	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
2077	     pSiS->HaveNonRect = TRUE;
2078	  }
2079	  x2 = min(pSiS->maxCRT2_X1, pScrn1->virtualX - pSiS->maxCRT2_X2);
2080	  if(x2 < 0) x2 = 0;
2081	  y2 = pSiS->CRT2YOffs;
2082	  w2 = pScrn1->virtualX - x2;
2083	  h2 = realvirtY;
2084	  if((usenonrect) && (pSiS->maxCRT2_Y2 != realvirtY)) {
2085	     h2 = pSiS->MBXNR2YMAX = pSiS->maxCRT2_Y2;
2086	     pSiS->NonRectDead.x0 = x2;
2087	     pSiS->NonRectDead.x1 = x2 + w2 - 1;
2088	     pSiS->NonRectDead.y0 = y2 + h2;
2089	     pSiS->NonRectDead.y1 = pScrn1->virtualY - 1;
2090	     pSiS->HaveNonRect = TRUE;
2091	  }
2092	  break;
2093       case sisAbove:
2094	  x1 = pSiS->CRT1XOffs;
2095	  y1 = min(pSiS->maxCRT1_Y2, pScrn1->virtualY - pSiS->maxCRT1_Y1);
2096	  if(y1 < 0) y1 = 0;
2097	  w1 = realvirtX;
2098	  h1 = pScrn1->virtualY - y1;
2099	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
2100	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
2101	     pSiS->NonRectDead.x0 = x1 + w1;
2102	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2103	     pSiS->NonRectDead.y0 = y1;
2104	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
2105	     pSiS->HaveNonRect = TRUE;
2106	  }
2107	  x2 = pSiS->CRT2XOffs;
2108	  y2 = 0;
2109	  w2 = realvirtX;
2110	  h2 = max(pSiS->maxCRT2_Y2, pScrn1->virtualY - pSiS->maxCRT2_Y1);
2111	  if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY;
2112	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2113	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2114	     pSiS->NonRectDead.x0 = x2 + w2;
2115	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2116	     pSiS->NonRectDead.y0 = y2;
2117	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2118	     pSiS->HaveNonRect = TRUE;
2119	  }
2120	  break;
2121       case sisBelow:
2122	  x1 = pSiS->CRT1XOffs;
2123	  y1 = 0;
2124	  w1 = realvirtX;
2125	  h1 = max(pSiS->maxCRT1_Y1, pScrn1->virtualY - pSiS->maxCRT1_Y2);
2126	  if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY;
2127	  if((usenonrect) && (pSiS->maxCRT1_X1 != realvirtX)) {
2128	     w1 = pSiS->MBXNR1XMAX = pSiS->maxCRT1_X1;
2129	     pSiS->NonRectDead.x0 = x1 + w1;
2130	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2131	     pSiS->NonRectDead.y0 = y1;
2132	     pSiS->NonRectDead.y1 = y1 + h1 - 1;
2133	     pSiS->HaveNonRect = TRUE;
2134	  }
2135	  x2 = pSiS->CRT2XOffs;
2136	  y2 = min(pSiS->maxCRT2_Y1, pScrn1->virtualY - pSiS->maxCRT2_Y2);
2137	  if(y2 < 0) y2 = 0;
2138	  w2 = realvirtX;
2139	  h2 = pScrn1->virtualY - y2;
2140	  if((usenonrect) && (pSiS->maxCRT2_X2 != realvirtX)) {
2141	     w2 = pSiS->MBXNR2XMAX = pSiS->maxCRT2_X2;
2142	     pSiS->NonRectDead.x0 = x2 + w2;
2143	     pSiS->NonRectDead.x1 = pScrn1->virtualX - 1;
2144	     pSiS->NonRectDead.y0 = y2;
2145	     pSiS->NonRectDead.y1 = y2 + h2 - 1;
2146	     pSiS->HaveNonRect = TRUE;
2147	  }
2148       default:
2149	  break;
2150       }
2151
2152       switch(pSiS->CRT2Position) {
2153       case sisLeftOf:
2154       case sisRightOf:
2155	  if(pSiS->CRT1YOffs) {
2156	     pSiS->OffDead1.x0 = x1;
2157	     pSiS->OffDead1.x1 = x1 + w1 - 1;
2158	     pSiS->OffDead1.y0 = 0;
2159	     pSiS->OffDead1.y1 = y1 - 1;
2160	     pSiS->OffDead2.x0 = x2;
2161	     pSiS->OffDead2.x1 = x2 + w2 - 1;
2162	     pSiS->OffDead2.y0 = y2 + h2;
2163	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2164	     pSiS->HaveOffsRegions = TRUE;
2165	  } else if(pSiS->CRT2YOffs) {
2166	     pSiS->OffDead1.x0 = x2;
2167	     pSiS->OffDead1.x1 = x2 + w2 - 1;
2168	     pSiS->OffDead1.y0 = 0;
2169	     pSiS->OffDead1.y1 = y2 - 1;
2170	     pSiS->OffDead2.x0 = x1;
2171	     pSiS->OffDead2.x1 = x1 + w1 - 1;
2172	     pSiS->OffDead2.y0 = y1 + h1;
2173	     pSiS->OffDead2.y1 = pScrn1->virtualY - 1;
2174	     pSiS->HaveOffsRegions = TRUE;
2175	  }
2176	  break;
2177       case sisAbove:
2178       case sisBelow:
2179	  if(pSiS->CRT1XOffs) {
2180	     pSiS->OffDead1.x0 = x2 + w2;
2181	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2182	     pSiS->OffDead1.y0 = y2;
2183	     pSiS->OffDead1.y1 = y2 + h2 - 1;
2184	     pSiS->OffDead2.x0 = 0;
2185	     pSiS->OffDead2.x1 = x1 - 1;
2186	     pSiS->OffDead2.y0 = y1;
2187	     pSiS->OffDead2.y1 = y1 + h1 - 1;
2188	     pSiS->HaveOffsRegions = TRUE;
2189	  } else if(pSiS->CRT2XOffs) {
2190	     pSiS->OffDead1.x0 = x1 + w1;
2191	     pSiS->OffDead1.x1 = pScrn1->virtualX - 1;
2192	     pSiS->OffDead1.y0 = y1;
2193	     pSiS->OffDead1.y1 = y1 + h1 - 1;
2194	     pSiS->OffDead2.x0 = 0;
2195	     pSiS->OffDead2.x1 = x2 - 1;
2196	     pSiS->OffDead2.y0 = y2;
2197	     pSiS->OffDead2.y1 = y2 + h2 - 1;
2198	     pSiS->HaveOffsRegions = TRUE;
2199	  }
2200       default:
2201	  break;
2202       }
2203
2204    } else {	/* Only clone-modes left */
2205
2206       x1 = x2 = 0;
2207       y1 = y2 = 0;
2208       w1 = w2 = max(pSiS->maxClone_X1, pSiS->maxClone_X2);
2209       h1 = h2 = max(pSiS->maxClone_Y1, pSiS->maxClone_Y2);
2210
2211    }
2212
2213    SiSXineramadataPtr[crt1scrnnum].x = x1;
2214    SiSXineramadataPtr[crt1scrnnum].y = y1;
2215    SiSXineramadataPtr[crt1scrnnum].width = w1;
2216    SiSXineramadataPtr[crt1scrnnum].height = h1;
2217    SiSXineramadataPtr[crt2scrnnum].x = x2;
2218    SiSXineramadataPtr[crt2scrnnum].y = y2;
2219    SiSXineramadataPtr[crt2scrnnum].width = w2;
2220    SiSXineramadataPtr[crt2scrnnum].height = h2;
2221
2222    if(infochanged) {
2223       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2224	  "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n",
2225	  crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1);
2226       xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2227	  "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n",
2228	  crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1);
2229       if(pSiS->HaveNonRect) {
2230	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2231		"Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n",
2232		pSiS->NonRectDead.x0, pSiS->NonRectDead.y0,
2233		pSiS->NonRectDead.x1, pSiS->NonRectDead.y1);
2234       }
2235       if(pSiS->HaveOffsRegions) {
2236	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2237		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2238		pSiS->OffDead1.x0, pSiS->OffDead1.y0,
2239		pSiS->OffDead1.x1, pSiS->OffDead1.y1);
2240	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2241		"Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n",
2242		pSiS->OffDead2.x0, pSiS->OffDead2.y0,
2243		pSiS->OffDead2.x1, pSiS->OffDead2.y1);
2244       }
2245       if(pSiS->HaveNonRect || pSiS->HaveOffsRegions) {
2246	  xf86DrvMsg(pScrn1->scrnIndex, X_INFO,
2247		"Mouse restriction for inaccessible areas is %s\n",
2248		pSiS->MouseRestrictions ? "enabled" : "disabled");
2249       }
2250    }
2251}
2252
2253/* Proc */
2254
2255int
2256SiSProcXineramaQueryVersion(ClientPtr client)
2257{
2258    xPanoramiXQueryVersionReply	  rep;
2259    register int		  n;
2260
2261    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
2262    rep.type = X_Reply;
2263    rep.length = 0;
2264    rep.sequenceNumber = client->sequence;
2265    rep.majorVersion = SIS_XINERAMA_MAJOR_VERSION;
2266    rep.minorVersion = SIS_XINERAMA_MINOR_VERSION;
2267    if(client->swapped) {
2268        swaps(&rep.sequenceNumber, n);
2269        swapl(&rep.length, n);
2270        swaps(&rep.majorVersion, n);
2271        swaps(&rep.minorVersion, n);
2272    }
2273    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
2274    return (client->noClientException);
2275}
2276
2277int
2278SiSProcXineramaGetState(ClientPtr client)
2279{
2280    REQUEST(xPanoramiXGetStateReq);
2281    WindowPtr			pWin;
2282    xPanoramiXGetStateReply	rep;
2283    register int		n;
2284
2285    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2286    pWin = LookupWindow(stuff->window, client);
2287    if(!pWin) return BadWindow;
2288
2289    rep.type = X_Reply;
2290    rep.length = 0;
2291    rep.sequenceNumber = client->sequence;
2292    rep.state = !SiSnoPanoramiXExtension;
2293    if(client->swapped) {
2294       swaps (&rep.sequenceNumber, n);
2295       swapl (&rep.length, n);
2296       swaps (&rep.state, n);
2297    }
2298    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
2299    return client->noClientException;
2300}
2301
2302int
2303SiSProcXineramaGetScreenCount(ClientPtr client)
2304{
2305    REQUEST(xPanoramiXGetScreenCountReq);
2306    WindowPtr				pWin;
2307    xPanoramiXGetScreenCountReply	rep;
2308    register int			n;
2309
2310    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2311    pWin = LookupWindow(stuff->window, client);
2312    if(!pWin) return BadWindow;
2313
2314    rep.type = X_Reply;
2315    rep.length = 0;
2316    rep.sequenceNumber = client->sequence;
2317    rep.ScreenCount = SiSXineramaNumScreens;
2318    if(client->swapped) {
2319       swaps(&rep.sequenceNumber, n);
2320       swapl(&rep.length, n);
2321       swaps(&rep.ScreenCount, n);
2322    }
2323    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
2324    return client->noClientException;
2325}
2326
2327int
2328SiSProcXineramaGetScreenSize(ClientPtr client)
2329{
2330    REQUEST(xPanoramiXGetScreenSizeReq);
2331    WindowPtr				pWin;
2332    xPanoramiXGetScreenSizeReply	rep;
2333    register int			n;
2334
2335    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2336    pWin = LookupWindow (stuff->window, client);
2337    if(!pWin)  return BadWindow;
2338
2339    rep.type = X_Reply;
2340    rep.length = 0;
2341    rep.sequenceNumber = client->sequence;
2342    rep.width  = SiSXineramadataPtr[stuff->screen].width;
2343    rep.height = SiSXineramadataPtr[stuff->screen].height;
2344    if(client->swapped) {
2345       swaps(&rep.sequenceNumber, n);
2346       swapl(&rep.length, n);
2347       swaps(&rep.width, n);
2348       swaps(&rep.height, n);
2349    }
2350    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
2351    return client->noClientException;
2352}
2353
2354int
2355SiSProcXineramaIsActive(ClientPtr client)
2356{
2357    xXineramaIsActiveReply	rep;
2358
2359    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2360
2361    rep.type = X_Reply;
2362    rep.length = 0;
2363    rep.sequenceNumber = client->sequence;
2364    rep.state = !SiSnoPanoramiXExtension;
2365    if(client->swapped) {
2366	register int n;
2367	swaps(&rep.sequenceNumber, n);
2368	swapl(&rep.length, n);
2369	swapl(&rep.state, n);
2370    }
2371    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
2372    return client->noClientException;
2373}
2374
2375int
2376SiSProcXineramaQueryScreens(ClientPtr client)
2377{
2378    xXineramaQueryScreensReply	rep;
2379
2380    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2381
2382    rep.type = X_Reply;
2383    rep.sequenceNumber = client->sequence;
2384    rep.number = (SiSnoPanoramiXExtension) ? 0 : SiSXineramaNumScreens;
2385    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
2386    if(client->swapped) {
2387       register int n;
2388       swaps(&rep.sequenceNumber, n);
2389       swapl(&rep.length, n);
2390       swapl(&rep.number, n);
2391    }
2392    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
2393
2394    if(!SiSnoPanoramiXExtension) {
2395       xXineramaScreenInfo scratch;
2396       int i;
2397
2398       for(i = 0; i < SiSXineramaNumScreens; i++) {
2399	  scratch.x_org  = SiSXineramadataPtr[i].x;
2400	  scratch.y_org  = SiSXineramadataPtr[i].y;
2401	  scratch.width  = SiSXineramadataPtr[i].width;
2402	  scratch.height = SiSXineramadataPtr[i].height;
2403	  if(client->swapped) {
2404	     register int n;
2405	     swaps(&scratch.x_org, n);
2406	     swaps(&scratch.y_org, n);
2407	     swaps(&scratch.width, n);
2408	     swaps(&scratch.height, n);
2409	  }
2410	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
2411       }
2412    }
2413
2414    return client->noClientException;
2415}
2416
2417static int
2418SiSProcXineramaDispatch(ClientPtr client)
2419{
2420    REQUEST(xReq);
2421    switch (stuff->data) {
2422	case X_PanoramiXQueryVersion:
2423	     return SiSProcXineramaQueryVersion(client);
2424	case X_PanoramiXGetState:
2425	     return SiSProcXineramaGetState(client);
2426	case X_PanoramiXGetScreenCount:
2427	     return SiSProcXineramaGetScreenCount(client);
2428	case X_PanoramiXGetScreenSize:
2429	     return SiSProcXineramaGetScreenSize(client);
2430	case X_XineramaIsActive:
2431	     return SiSProcXineramaIsActive(client);
2432	case X_XineramaQueryScreens:
2433	     return SiSProcXineramaQueryScreens(client);
2434    }
2435    return BadRequest;
2436}
2437
2438/* SProc */
2439
2440static int
2441SiSSProcXineramaQueryVersion (ClientPtr client)
2442{
2443    REQUEST(xPanoramiXQueryVersionReq);
2444    register int n;
2445    swaps(&stuff->length,n);
2446    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
2447    return SiSProcXineramaQueryVersion(client);
2448}
2449
2450static int
2451SiSSProcXineramaGetState(ClientPtr client)
2452{
2453    REQUEST(xPanoramiXGetStateReq);
2454    register int n;
2455    swaps (&stuff->length, n);
2456    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
2457    return SiSProcXineramaGetState(client);
2458}
2459
2460static int
2461SiSSProcXineramaGetScreenCount(ClientPtr client)
2462{
2463    REQUEST(xPanoramiXGetScreenCountReq);
2464    register int n;
2465    swaps (&stuff->length, n);
2466    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
2467    return SiSProcXineramaGetScreenCount(client);
2468}
2469
2470static int
2471SiSSProcXineramaGetScreenSize(ClientPtr client)
2472{
2473    REQUEST(xPanoramiXGetScreenSizeReq);
2474    register int n;
2475    swaps (&stuff->length, n);
2476    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
2477    return SiSProcXineramaGetScreenSize(client);
2478}
2479
2480static int
2481SiSSProcXineramaIsActive(ClientPtr client)
2482{
2483    REQUEST(xXineramaIsActiveReq);
2484    register int n;
2485    swaps (&stuff->length, n);
2486    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
2487    return SiSProcXineramaIsActive(client);
2488}
2489
2490static int
2491SiSSProcXineramaQueryScreens(ClientPtr client)
2492{
2493    REQUEST(xXineramaQueryScreensReq);
2494    register int n;
2495    swaps (&stuff->length, n);
2496    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
2497    return SiSProcXineramaQueryScreens(client);
2498}
2499
2500int
2501SiSSProcXineramaDispatch(ClientPtr client)
2502{
2503    REQUEST(xReq);
2504    switch (stuff->data) {
2505	case X_PanoramiXQueryVersion:
2506	     return SiSSProcXineramaQueryVersion(client);
2507	case X_PanoramiXGetState:
2508	     return SiSSProcXineramaGetState(client);
2509	case X_PanoramiXGetScreenCount:
2510	     return SiSSProcXineramaGetScreenCount(client);
2511	case X_PanoramiXGetScreenSize:
2512	     return SiSSProcXineramaGetScreenSize(client);
2513	case X_XineramaIsActive:
2514	     return SiSSProcXineramaIsActive(client);
2515	case X_XineramaQueryScreens:
2516	     return SiSSProcXineramaQueryScreens(client);
2517    }
2518    return BadRequest;
2519}
2520
2521static void
2522SiSXineramaResetProc(ExtensionEntry* extEntry)
2523{
2524    /* Called by CloseDownExtensions() */
2525    if(SiSXineramadataPtr) {
2526       Xfree(SiSXineramadataPtr);
2527       SiSXineramadataPtr = NULL;
2528    }
2529}
2530
2531static void
2532SiSXineramaExtensionInit(ScrnInfoPtr pScrn)
2533{
2534    SISPtr	pSiS = SISPTR(pScrn);
2535    Bool	success = FALSE;
2536
2537    if(!(SiSXineramadataPtr)) {
2538
2539       if(!pSiS->MergedFB) {
2540	  SiSnoPanoramiXExtension = TRUE;
2541	  pSiS->MouseRestrictions = FALSE;
2542	  return;
2543       }
2544
2545#ifdef PANORAMIX
2546       if(!noPanoramiXExtension) {
2547	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2548	     "Xinerama active, not initializing SiS Pseudo-Xinerama\n");
2549	  SiSnoPanoramiXExtension = TRUE;
2550	  pSiS->MouseRestrictions = FALSE;
2551	  return;
2552       }
2553#endif
2554
2555       if(SiSnoPanoramiXExtension) {
2556	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2557	      "SiS Pseudo-Xinerama disabled\n");
2558	  pSiS->MouseRestrictions = FALSE;
2559	  return;
2560       }
2561
2562       if(pSiS->CRT2Position == sisClone) {
2563	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2564	     "Running MergedFB in Clone mode, SiS Pseudo-Xinerama disabled\n");
2565	  SiSnoPanoramiXExtension = TRUE;
2566	  pSiS->MouseRestrictions = FALSE;
2567	  return;
2568       }
2569
2570       if(!(pSiS->AtLeastOneNonClone)) {
2571	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2572	     "Only Clone modes defined, SiS Pseudo-Xinerama disabled\n");
2573	  SiSnoPanoramiXExtension = TRUE;
2574	  pSiS->MouseRestrictions = FALSE;
2575	  return;
2576       }
2577
2578       SiSXineramaNumScreens = 2;
2579
2580       while(SiSXineramaGeneration != serverGeneration) {
2581
2582	  pSiS->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
2583					SiSProcXineramaDispatch,
2584					SiSSProcXineramaDispatch,
2585					SiSXineramaResetProc,
2586					StandardMinorOpcode);
2587
2588	  if(!pSiS->XineramaExtEntry) break;
2589
2590	  if(!(SiSXineramadataPtr = (SiSXineramaData *)
2591	        xcalloc(SiSXineramaNumScreens, sizeof(SiSXineramaData)))) break;
2592
2593	  SiSXineramaGeneration = serverGeneration;
2594	  success = TRUE;
2595       }
2596
2597       if(!success) {
2598	  SISErrorLog(pScrn, "Failed to initialize SiS Pseudo-Xinerama extension\n");
2599	  SiSnoPanoramiXExtension = TRUE;
2600	  pSiS->MouseRestrictions = FALSE;
2601	  return;
2602       }
2603
2604       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2605	  "SiS Pseudo-Xinerama extension initialized\n");
2606
2607       pSiS->SiSXineramaVX = 0;
2608       pSiS->SiSXineramaVY = 0;
2609
2610    }
2611
2612    SiSUpdateXineramaScreenInfo(pScrn);
2613
2614}
2615#endif  /* End of PseudoXinerama */
2616
2617static void
2618SiSFreeCRT2Structs(SISPtr pSiS)
2619{
2620    if(pSiS->CRT2pScrn) {
2621       if(pSiS->CRT2pScrn->modes) {
2622	  while(pSiS->CRT2pScrn->modes)
2623	     xf86DeleteMode(&pSiS->CRT2pScrn->modes, pSiS->CRT2pScrn->modes);
2624       }
2625       if(pSiS->CRT2pScrn->monitor) {
2626	  if(pSiS->CRT2pScrn->monitor->Modes) {
2627	     while(pSiS->CRT2pScrn->monitor->Modes)
2628		xf86DeleteMode(&pSiS->CRT2pScrn->monitor->Modes, pSiS->CRT2pScrn->monitor->Modes);
2629	  }
2630	  if(pSiS->CRT2pScrn->monitor->DDC) xfree(pSiS->CRT2pScrn->monitor->DDC);
2631	  xfree(pSiS->CRT2pScrn->monitor);
2632       }
2633       xfree(pSiS->CRT2pScrn);
2634       pSiS->CRT2pScrn = NULL;
2635   }
2636}
2637
2638#endif	/* End of MergedFB helpers */
2639
2640static xf86MonPtr
2641SiSInternalDDC(ScrnInfoPtr pScrn, int crtno)
2642{
2643   SISPtr     pSiS = SISPTR(pScrn);
2644   xf86MonPtr pMonitor = NULL;
2645   UShort     temp = 0xffff, temp1, i, realcrtno = crtno;
2646   UChar      buffer[256];
2647
2648   /* If CRT1 is off, skip DDC */
2649   if((pSiS->CRT1off) && (!crtno)) return NULL;
2650
2651   if(crtno) {
2652      if(pSiS->VBFlags & CRT2_LCD)      realcrtno = 1;
2653      else if(pSiS->VBFlags & CRT2_VGA) realcrtno = 2;
2654      else				return NULL;
2655      if(pSiS->SiS_Pr->DDCPortMixup) realcrtno = 0;
2656   } else {
2657      /* If CRT1 is LCDA, skip DDC (except 301C: DDC allowed, but uses CRT2 port!) */
2658      if(pSiS->VBFlags & CRT1_LCDA) {
2659         if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) realcrtno = 1;
2660         else return NULL;
2661      }
2662   }
2663
2664   i = 3; /* Number of retrys */
2665   do {
2666      temp1 = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2667			realcrtno, 0, &buffer[0], pSiS->VBFlags2);
2668      if((temp1) && (temp1 != 0xffff)) temp = temp1;
2669   } while((temp == 0xffff) && i--);
2670   if(temp != 0xffff) {
2671      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC supported\n", crtno + 1);
2672      xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "CRT%d DDC level: %s%s%s%s\n",
2673	     crtno + 1,
2674	     (temp & 0x1a) ? "" : "[none of the supported]",
2675	     (temp & 0x02) ? "2 " : "",
2676	     (temp & 0x08) ? "D&P" : "",
2677             (temp & 0x10) ? "FPDI-2" : "");
2678      if(temp & 0x02) {
2679	 i = 5;  /* Number of retrys */
2680	 do {
2681	    temp = SiS_HandleDDC(pSiS->SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine,
2682				realcrtno, 1, &buffer[0], pSiS->VBFlags2);
2683	 } while((temp) && i--);
2684         if(!temp) {
2685	    if((pMonitor = xf86InterpretEDID(pScrn->scrnIndex, &buffer[0]))) {
2686	       int tempvgagamma = 0, templcdgamma = 0;
2687	       if(buffer[0x14] & 0x80) {
2688	          templcdgamma = (buffer[0x17] + 100) * 10;
2689	       } else {
2690	          tempvgagamma = (buffer[0x17] + 100) * 10;;
2691	       }
2692	       if(crtno == 0) {
2693		  if(tempvgagamma) pSiS->CRT1VGAMonitorGamma = tempvgagamma;
2694		  /* LCD never via (demanded) CRT1 DDC port */
2695	       } else {
2696	          if(tempvgagamma) pSiS->CRT2VGAMonitorGamma = tempvgagamma;
2697	          if(templcdgamma) pSiS->CRT2LCDMonitorGamma = templcdgamma;
2698	       }
2699	       return(pMonitor);
2700	    } else {
2701	       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2702	           "CRT%d DDC EDID corrupt\n", crtno + 1);
2703	    }
2704	 } else if(temp == 0xFFFE) {
2705	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2706	    	"CRT%d DDC data is from wrong device type (%s)\n",
2707			crtno + 1,
2708			(realcrtno == 1) ? "analog instead of digital" : "digital instead of analog");
2709	 } else {
2710            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2711	    	"CRT%d DDC reading failed\n", crtno + 1);
2712	 }
2713      } else if(temp & 0x18) {
2714         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2715	      "DDC for VESA D&P and FPDI-2 not supported yet.\n");
2716      }
2717   } else {
2718      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2719                "CRT%d DDC probing failed\n", crtno + 1);
2720   }
2721   return(NULL);
2722}
2723
2724static xf86MonPtr
2725SiSDoPrivateDDC(ScrnInfoPtr pScrn, int *crtnum)
2726{
2727    SISPtr pSiS = SISPTR(pScrn);
2728
2729#ifdef SISDUALHEAD
2730    if(pSiS->DualHeadMode) {
2731       if(pSiS->SecondHead) {
2732          *crtnum = 1;
2733	  return(SiSInternalDDC(pScrn, 0));
2734       } else {
2735          *crtnum = 2;
2736	  return(SiSInternalDDC(pScrn, 1));
2737       }
2738    } else
2739#endif
2740    if((pSiS->CRT1off) || (!pSiS->CRT1Detected)) {
2741       *crtnum = 2;
2742       return(SiSInternalDDC(pScrn, 1));
2743    } else {
2744       *crtnum = 1;
2745       return(SiSInternalDDC(pScrn, 0));
2746    }
2747}
2748
2749static void
2750SiSFindAspect(ScrnInfoPtr pScrn, xf86MonPtr pMonitor, int crtnum)
2751{
2752    SISPtr pSiS = SISPTR(pScrn);
2753    int UseWide = 0;
2754    int aspect = 0;
2755    Bool fromdim = FALSE;
2756
2757    if((pSiS->VGAEngine == SIS_315_VGA) && (!DIGITAL(pMonitor->features.input_type))) {
2758       if(pMonitor->features.hsize && pMonitor->features.vsize) {
2759	  aspect = (pMonitor->features.hsize * 1000) / pMonitor->features.vsize;
2760	  if(aspect >= 1400) UseWide = 1;
2761	  fromdim = TRUE;
2762       } else if((PREFERRED_TIMING_MODE(pMonitor->features.msc)) &&
2763		 (pMonitor->det_mon[0].type == DT)) {
2764	  aspect = (pMonitor->det_mon[0].section.d_timings.h_active * 1000) /
2765			pMonitor->det_mon[0].section.d_timings.v_active;
2766	  if(aspect >= 1400) UseWide = 1;
2767       }
2768       if(aspect) {
2769	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2770		"According to %s, CRT%d aspect ratio is %.2f:1 (%s)\n",
2771		fromdim ? "DDC size" : "preferred mode",
2772		crtnum, (float)aspect / 1000.0, UseWide ? "wide" : "normal");
2773       } else {
2774	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2775		"Unable to determine CRT%d aspect ratio, assuming \"normal\"\n",
2776		crtnum);
2777       }
2778    }
2779
2780    if((crtnum == 1) && (pSiS->SiS_Pr->SiS_UseWide == -1)) {
2781       pSiS->SiS_Pr->SiS_UseWide = UseWide;
2782    } else if((crtnum == 2) && (pSiS->SiS_Pr->SiS_UseWideCRT2 == -1)) {
2783       pSiS->SiS_Pr->SiS_UseWideCRT2 = UseWide;
2784    }
2785}
2786
2787static Bool
2788SiSMakeOwnModeList(ScrnInfoPtr pScrn, Bool acceptcustommodes, Bool includelcdmodes,
2789                   Bool isfordvi, Bool *havecustommodes, Bool fakecrt2modes, Bool IsForCRT2)
2790{
2791    DisplayModePtr tempmode, delmode, mymodes;
2792
2793    if((mymodes = SiSBuildBuiltInModeList(pScrn, includelcdmodes, isfordvi, fakecrt2modes, IsForCRT2))) {
2794       if(!acceptcustommodes) {
2795	  while(pScrn->monitor->Modes)
2796             xf86DeleteMode(&pScrn->monitor->Modes, pScrn->monitor->Modes);
2797	  pScrn->monitor->Modes = mymodes;
2798       } else {
2799	  delmode = pScrn->monitor->Modes;
2800	  while(delmode) {
2801	     if(delmode->type & M_T_DEFAULT) {
2802	        tempmode = delmode->next;
2803	        xf86DeleteMode(&pScrn->monitor->Modes, delmode);
2804	        delmode = tempmode;
2805	     } else {
2806	        delmode = delmode->next;
2807	     }
2808	  }
2809	  /* Link default modes AFTER user ones */
2810	  if((tempmode = pScrn->monitor->Modes)) {
2811	     *havecustommodes = TRUE;
2812	     while(tempmode) {
2813	        if(!tempmode->next) break;
2814	        else tempmode = tempmode->next;
2815	     }
2816	     tempmode->next = mymodes;
2817	     mymodes->prev = tempmode;
2818	  } else {
2819	     pScrn->monitor->Modes = mymodes;
2820	  }
2821#if 0
2822	  pScrn->monitor->Modes = mymodes;
2823	  while(mymodes) {
2824	     if(!mymodes->next) break;
2825	     else mymodes = mymodes->next;
2826	  }
2827	  mymodes->next = tempmode;
2828	  if(tempmode) {
2829	     tempmode->prev = mymodes;
2830	  }
2831#endif
2832       }
2833       return TRUE;
2834    } else
2835       return FALSE;
2836}
2837
2838static void
2839SiSPrintModes(ScrnInfoPtr pScrn)
2840{
2841    DisplayModePtr p;
2842    float hsync, refresh = 0.0;
2843    char *desc, *desc2, *prefix, *uprefix, *output;
2844
2845    xf86DrvMsg(pScrn->scrnIndex, pScrn->virtualFrom, "Virtual size is %dx%d "
2846	       "(pitch %d)\n", pScrn->virtualX, pScrn->virtualY,
2847	       pScrn->displayWidth);
2848
2849    if((p = pScrn->modes) == NULL) return;
2850
2851    do {
2852	desc = desc2 = "";
2853	uprefix = " ";
2854	prefix = "Mode";
2855	output = "For CRT device: ";
2856	if(p->HSync > 0.0)      hsync = p->HSync;
2857	else if (p->HTotal > 0) hsync = (float)p->Clock / (float)p->HTotal;
2858	else	                hsync = 0.0;
2859	refresh = 0.0;
2860        if(p->VRefresh > 0.0)   refresh = p->VRefresh;
2861        else if (p->HTotal > 0 && p->VTotal > 0) {
2862	   refresh = p->Clock * 1000.0 / p->HTotal / p->VTotal;
2863	   if(p->Flags & V_INTERLACE) refresh *= 2.0;
2864	   if(p->Flags & V_DBLSCAN)   refresh /= 2.0;
2865	   if(p->VScan > 1)  	      refresh /= p->VScan;
2866        }
2867	if(p->Flags & V_INTERLACE) desc = " (I)";
2868	if(p->Flags & V_DBLSCAN)   desc = " (D)";
2869	if(p->VScan > 1) 	   desc2 = " (VScan)";
2870#ifdef M_T_USERDEF
2871	if(p->type & M_T_USERDEF)  uprefix = "*";
2872#endif
2873	if(p->type & M_T_BUILTIN)       {
2874	   prefix = "Built-in mode";
2875	   output = "";
2876	} else if (p->type & M_T_DEFAULT) {
2877	   prefix = "Default mode";
2878	} else {
2879	   output = "";
2880	}
2881
2882	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
2883		"%s%s \"%s\" (%dx%d) (%s%.1f MHz, %.1f kHz, %.1f Hz%s%s)\n",
2884		uprefix, prefix, p->name, p->HDisplay, p->VDisplay, output,
2885		p->Clock / 1000.0, hsync, refresh, desc, desc2);
2886
2887	p = p->next;
2888    } while (p != NULL && p != pScrn->modes);
2889}
2890
2891Bool SISDetermineLCDACap(ScrnInfoPtr pScrn)
2892{
2893    SISPtr pSiS = SISPTR(pScrn);
2894
2895    if( ((pSiS->ChipType == SIS_650)    ||
2896         (pSiS->ChipType == SIS_315PRO) ||
2897         (pSiS->ChipType >= SIS_661))		&&
2898	(pSiS->ChipType != XGI_20)		&&
2899        (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)	&&
2900	(pSiS->VESA != 1) ) {
2901       return TRUE;
2902    }
2903    return FALSE;
2904}
2905
2906void SISSaveDetectedDevices(ScrnInfoPtr pScrn)
2907{
2908    SISPtr  pSiS = SISPTR(pScrn);
2909    /* Backup detected CRT2 devices */
2910    pSiS->detectedCRT2Devices = pSiS->VBFlags & (CRT2_LCD|CRT2_TV|CRT2_VGA|TV_AVIDEO|TV_SVIDEO|
2911                                                 TV_SCART|TV_HIVISION|TV_YPBPR);
2912}
2913
2914static Bool
2915SISCheckBIOS(SISPtr pSiS, UShort mypciid, UShort mypcivendor, int biossize)
2916{
2917    UShort romptr, pciid;
2918
2919    if(!pSiS->BIOS) return FALSE;
2920
2921    if((pSiS->BIOS[0] != 0x55) || (pSiS->BIOS[1] != 0xaa)) return FALSE;
2922
2923    romptr = pSiS->BIOS[0x18] | (pSiS->BIOS[0x19] << 8);
2924    if(romptr > (biossize - 8)) return FALSE;
2925    if((pSiS->BIOS[romptr]   != 'P') || (pSiS->BIOS[romptr+1] != 'C') ||
2926       (pSiS->BIOS[romptr+2] != 'I') || (pSiS->BIOS[romptr+3] != 'R')) return FALSE;
2927
2928    pciid = pSiS->BIOS[romptr+4] | (pSiS->BIOS[romptr+5] << 8);
2929    if(pciid != mypcivendor) return FALSE;
2930
2931    pciid = pSiS->BIOS[romptr+6] | (pSiS->BIOS[romptr+7] << 8);
2932    if(pciid != mypciid) return FALSE;
2933
2934    return TRUE;
2935}
2936
2937static void
2938SiS_LoadInitVBE(ScrnInfoPtr pScrn)
2939{
2940    SISPtr pSiS = SISPTR(pScrn);
2941
2942    /* Don't load the VBE module for secondary
2943     * cards which sisfb POSTed. We don't want
2944     * int10 to overwrite our set up (such as
2945     * disabled a0000 memory address decoding).
2946     * We don't need the VBE anyway because
2947     * the card will never be in text mode,
2948     * and we can restore graphics modes just
2949     * perfectly.
2950     */
2951    if( !pSiS->Primary &&
2952        pSiS->sisfbcardposted)
2953       return;
2954
2955    if(pSiS->pVbe) return;
2956
2957    if(xf86LoadSubModule(pScrn, "vbe")) {
2958       xf86LoaderReqSymLists(vbeSymbols, NULL);
2959#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
2960       pSiS->pVbe = VBEInit(pSiS->pInt, pSiS->pEnt->index);
2961#else
2962       pSiS->pVbe = VBEExtendedInit(pSiS->pInt, pSiS->pEnt->index,
2963	                SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
2964#endif
2965    }
2966
2967    if(!pSiS->pVbe) {
2968       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2969	   "Failed to load/initialize vbe module\n");
2970    }
2971}
2972
2973#ifdef SIS_PC_PLATFORM
2974static void
2975SiS_MapVGAMem(ScrnInfoPtr pScrn)
2976{
2977    SISPtr pSiS = SISPTR(pScrn);
2978
2979    /* Map 64k VGA window for saving/restoring CGA fonts */
2980    pSiS->VGAMapSize = 0x10000;
2981    pSiS->VGAMapPhys = 0;	/* Default */
2982    if((!pSiS->Primary) || (!pSiS->VGADecodingEnabled)) {
2983       /* If card is secondary or if a0000-address decoding
2984        * is disabled, set Phys to beginning of our video RAM.
2985	*/
2986       pSiS->VGAMapPhys = pSiS->PciInfo->memBase[0];
2987    }
2988    if(!SiSVGAMapMem(pScrn)) {
2989       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2990	  "Failed to map VGA memory (0x%lx), can't save/restore console fonts\n",
2991	  pSiS->VGAMapPhys);
2992    }
2993}
2994#endif
2995
2996static void
2997SiS_CheckKernelFB(ScrnInfoPtr pScrn)
2998{
2999    SISPtr pSiS = SISPTR(pScrn);
3000    int        fd, i;
3001    CARD32     sisfbinfosize = 0, sisfbversion;
3002    sisfb_info *mysisfbinfo;
3003    char       name[16];
3004
3005    pSiS->donttrustpdc = FALSE;
3006    pSiS->sisfbpdc = 0xff;
3007    pSiS->sisfbpdca = 0xff;
3008    pSiS->sisfblcda = 0xff;
3009    pSiS->sisfbscalelcd = -1;
3010    pSiS->sisfbspecialtiming = CUT_NONE;
3011    pSiS->sisfb_haveemi = FALSE;
3012    pSiS->sisfbfound = FALSE;
3013    pSiS->sisfb_tvposvalid = FALSE;
3014    pSiS->sisfbdevname[0] = 0;
3015    pSiS->sisfb_havelock = FALSE;
3016    pSiS->sisfbHaveNewHeapDef = FALSE;
3017    pSiS->sisfbHeapSize = 0;
3018    pSiS->sisfbVideoOffset = 0;
3019    pSiS->sisfbxSTN = FALSE;
3020    pSiS->sisfbcanpost = FALSE;   /* (Old) sisfb can't POST card */
3021    pSiS->sisfbcardposted = TRUE; /* If (old) sisfb is running, card must have been POSTed */
3022    pSiS->sisfbprimary = FALSE;   /* (Old) sisfb doesn't know */
3023
3024    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
3025
3026       i = 0;
3027       do {
3028
3029	  if(i <= 7) {
3030             sprintf(name, "/dev/fb%1d", i);
3031	  } else {
3032	     sprintf(name, "/dev/fb/%1d", (i - 8));
3033	  }
3034
3035          if((fd = open(name, 'r')) != -1) {
3036
3037	     Bool gotit = FALSE;
3038
3039 	     if(!ioctl(fd, SISFB_GET_INFO_SIZE, &sisfbinfosize)) {
3040 		if((mysisfbinfo = xalloc(sisfbinfosize))) {
3041 		   if(!ioctl(fd, (SISFB_GET_INFO | (sisfbinfosize << 16)), mysisfbinfo)) {
3042 		      gotit = TRUE;
3043 		   } else {
3044 		      xfree(mysisfbinfo);
3045 		      mysisfbinfo = NULL;
3046 		   }
3047 		}
3048 	     } else {
3049 		if((mysisfbinfo = xalloc(sizeof(*mysisfbinfo) + 16))) {
3050 		   if(!ioctl(fd, SISFB_GET_INFO_OLD, mysisfbinfo)) {
3051 		      gotit = TRUE;
3052		      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3053				"Possibly old version of sisfb detected. Please update.\n");
3054		   } else {
3055		      xfree(mysisfbinfo);
3056		      mysisfbinfo = NULL;
3057		   }
3058		}
3059	     }
3060
3061	     if(gotit) {
3062
3063		if(mysisfbinfo->sisfb_id == SISFB_ID) {
3064
3065		   sisfbversion = (mysisfbinfo->sisfb_version << 16) |
3066				  (mysisfbinfo->sisfb_revision << 8) |
3067				  (mysisfbinfo->sisfb_patchlevel);
3068
3069	           if(sisfbversion >= SISFB_VERSION(1, 5, 8)) {
3070		      /* Added PCI bus/slot/func into in sisfb Version 1.5.08.
3071		       * Check this to make sure we run on the same card as sisfb
3072		       */
3073		      if((mysisfbinfo->sisfb_pcibus  == pSiS->PciBus)    &&
3074			 (mysisfbinfo->sisfb_pcislot == pSiS->PciDevice) &&
3075			 (mysisfbinfo->sisfb_pcifunc == pSiS->PciFunc)) {
3076			 pSiS->sisfbfound = TRUE;
3077		      }
3078		   } else pSiS->sisfbfound = TRUE;
3079
3080		   if(pSiS->sisfbfound) {
3081		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3082			     "%s: SiS kernel fb driver (sisfb) %d.%d.%d detected (PCI:%02d:%02d.%d)\n",
3083				&name[5],
3084				mysisfbinfo->sisfb_version,
3085				mysisfbinfo->sisfb_revision,
3086				mysisfbinfo->sisfb_patchlevel,
3087				pSiS->PciBus,
3088				pSiS->PciDevice,
3089				pSiS->PciFunc);
3090
3091		      /* Added version/rev/pl in sisfb 1.4.0 */
3092		      if(mysisfbinfo->sisfb_version == 0) {
3093			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3094				"Old version of sisfb found. Please update.\n");
3095		      }
3096		      /* Basically, we can't trust the pdc register if sisfb is loaded */
3097		      pSiS->donttrustpdc = TRUE;
3098		      pSiS->sisfbHeapStart = mysisfbinfo->heapstart;
3099
3100		      if(sisfbversion >= SISFB_VERSION(1, 7, 20)) {
3101			 pSiS->sisfbHeapSize = mysisfbinfo->sisfb_heapsize;
3102			 pSiS->sisfbVideoOffset = mysisfbinfo->sisfb_videooffset;
3103			 pSiS->sisfbHaveNewHeapDef = TRUE;
3104			 pSiS->sisfbFSTN = mysisfbinfo->sisfb_curfstn;
3105			 pSiS->sisfbDSTN = mysisfbinfo->sisfb_curdstn;
3106			 pSiS->sisfbxSTN = TRUE;
3107			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3108				"sisfb: memory heap at %dKB, size %dKB, viewport at %dKB\n",
3109				(int)pSiS->sisfbHeapStart, (int)pSiS->sisfbHeapSize,
3110				(int)pSiS->sisfbVideoOffset/1024);
3111		      } else {
3112			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3113				"sisfb: memory heap at %dKB\n", (int)pSiS->sisfbHeapStart);
3114		      }
3115		      xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3116				"sisfb: using video mode 0x%02x\n", mysisfbinfo->fbvidmode);
3117		      pSiS->OldMode = mysisfbinfo->fbvidmode;
3118		      if(sisfbversion >= SISFB_VERSION(1, 5, 6)) {
3119			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3120				"sisfb: using %s, reserved %dK\n",
3121				(mysisfbinfo->sisfb_caps & 0x40) ? "SiS300 series Turboqueue" :
3122				   (mysisfbinfo->sisfb_caps & 0x20) ? "SiS315/330/340 series AGP command queue" :
3123				      (mysisfbinfo->sisfb_caps & 0x10) ? "SiS315/330/340 series VRAM command queue" :
3124					(mysisfbinfo->sisfb_caps & 0x08) ? "SiS315/330/340 series MMIO mode" :
3125					   "no command queue",
3126				(int)mysisfbinfo->sisfb_tqlen);
3127		      }
3128		      if(sisfbversion >= SISFB_VERSION(1, 5, 10)) {
3129			 /* We can trust the pdc value if sisfb is of recent version */
3130			 if(pSiS->VGAEngine == SIS_300_VGA) pSiS->donttrustpdc = FALSE;
3131		      }
3132		      if(sisfbversion >= SISFB_VERSION(1, 5, 11)) {
3133			 if(pSiS->VGAEngine == SIS_300_VGA) {
3134			    /* As of 1.5.11, sisfb saved the register for us (300 series) */
3135			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3136			    if(!pSiS->sisfbpdc) pSiS->sisfbpdc = 0xff;
3137			 }
3138		      }
3139		      if(sisfbversion >= SISFB_VERSION(1, 5, 14)) {
3140			 if(pSiS->VGAEngine == SIS_315_VGA) {
3141			    pSiS->sisfblcda = mysisfbinfo->sisfb_lcda;
3142			 }
3143		      }
3144		      if(sisfbversion >= SISFB_VERSION(1, 6, 13)) {
3145			 pSiS->sisfbscalelcd = mysisfbinfo->sisfb_scalelcd;
3146			 pSiS->sisfbspecialtiming = mysisfbinfo->sisfb_specialtiming;
3147		      }
3148		      if(sisfbversion >= SISFB_VERSION(1, 6, 16)) {
3149			 if(pSiS->VGAEngine == SIS_315_VGA) {
3150			    pSiS->donttrustpdc = FALSE;
3151			    pSiS->sisfbpdc = mysisfbinfo->sisfb_lcdpdc;
3152			    if(sisfbversion >= SISFB_VERSION(1, 6, 24)) {
3153			       pSiS->sisfb_haveemi = mysisfbinfo->sisfb_haveemi ? TRUE : FALSE;
3154			       pSiS->sisfb_haveemilcd = TRUE;  /* will match most cases */
3155			       pSiS->sisfb_emi30 = mysisfbinfo->sisfb_emi30;
3156			       pSiS->sisfb_emi31 = mysisfbinfo->sisfb_emi31;
3157			       pSiS->sisfb_emi32 = mysisfbinfo->sisfb_emi32;
3158			       pSiS->sisfb_emi33 = mysisfbinfo->sisfb_emi33;
3159			    }
3160			    if(sisfbversion >= SISFB_VERSION(1, 6, 25)) {
3161			       pSiS->sisfb_haveemilcd = mysisfbinfo->sisfb_haveemilcd ? TRUE : FALSE;
3162			    }
3163			    if(sisfbversion >= SISFB_VERSION(1, 6, 31)) {
3164			       pSiS->sisfbpdca = mysisfbinfo->sisfb_lcdpdca;
3165			    } else {
3166			       if(pSiS->sisfbpdc) {
3167				  pSiS->sisfbpdca = (pSiS->sisfbpdc & 0xf0) >> 3;
3168				  pSiS->sisfbpdc  = (pSiS->sisfbpdc & 0x0f) << 1;
3169			       } else {
3170				  pSiS->sisfbpdca = pSiS->sisfbpdc = 0xff;
3171			       }
3172			    }
3173			 }
3174		      }
3175		      if(sisfbversion >= SISFB_VERSION(1, 7, 0)) {
3176		         pSiS->sisfb_havelock = TRUE;
3177			 if(sisfbversion >= SISFB_VERSION(1, 7, 1)) {
3178			    pSiS->sisfb_tvxpos = mysisfbinfo->sisfb_tvxpos;
3179			    pSiS->sisfb_tvypos = mysisfbinfo->sisfb_tvypos;
3180			    pSiS->sisfb_tvposvalid = TRUE;
3181			 }
3182		      }
3183		      if(sisfbversion >= SISFB_VERSION(1, 8, 7)) {
3184			 pSiS->sisfbcanpost = (mysisfbinfo->sisfb_can_post) ? TRUE : FALSE;
3185			 pSiS->sisfbcardposted = (mysisfbinfo->sisfb_card_posted) ? TRUE : FALSE;
3186			 pSiS->sisfbprimary = (mysisfbinfo->sisfb_was_boot_device) ? TRUE : FALSE;
3187			 /* Validity check */
3188			 if(!pSiS->sisfbcardposted) {
3189			    pSiS->sisfbprimary = FALSE;
3190			 }
3191		      }
3192		   }
3193	        }
3194		xfree(mysisfbinfo);
3195		mysisfbinfo = NULL;
3196	     }
3197	     close (fd);
3198          }
3199	  i++;
3200       } while((i <= 15) && (!pSiS->sisfbfound));
3201
3202       if(pSiS->sisfbfound) {
3203          strncpy(pSiS->sisfbdevname, name, 15);
3204       } else {
3205          xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "sisfb not found\n");
3206       }
3207    }
3208
3209    if(!pSiS->sisfbfound) {
3210       pSiS->sisfbcardposted = FALSE;
3211    }
3212}
3213
3214static void
3215SiSPseudo(ScrnInfoPtr pScrn)
3216{
3217}
3218
3219/* PreInit()
3220 *
3221 * Mandatory
3222 */
3223static Bool
3224SISPreInit(ScrnInfoPtr pScrn, int flags)
3225{
3226    SISPtr pSiS;
3227#ifdef SISDUALHEAD
3228    SISEntPtr pSiSEnt = NULL;
3229#endif
3230    MessageType from;
3231    UChar usScratchCR17, usScratchCR32, usScratchCR63;
3232    UChar usScratchSR1F, srlockReg, crlockReg;
3233    unsigned int i;
3234    int pix24flags, temp;
3235    ClockRangePtr clockRanges;
3236    xf86MonPtr pMonitor = NULL;
3237    Bool didddc2, fromDDC, crt1freqoverruled = FALSE;
3238    UChar CR5F, tempreg;
3239#if defined(SISMERGED) || defined(SISDUALHEAD)
3240    DisplayModePtr first, p, n;
3241#endif
3242#ifdef SISMERGED
3243    Bool crt2freqoverruled = FALSE;
3244#endif
3245
3246    static const char *ddcsstr = "CRT%d DDC monitor info: *******************************************\n";
3247    static const char *ddcestr = "End of CRT%d DDC monitor info *************************************\n";
3248    static const char *subshstr = "Substituting missing CRT%d monitor HSync range by DDC data\n";
3249    static const char *subsvstr = "Substituting missing CRT%d monitor VRefresh range by DDC data\n";
3250    static const char *saneh = "Correcting %s CRT%d monitor HSync range\n";
3251    static const char *sanev = "Correcting %s CRT%d monitor VRefresh range\n";
3252#ifdef SISMERGED
3253    static const char *mergednocrt1 = "CRT1 not detected or forced off. %s.\n";
3254    static const char *mergednocrt2 = "No CRT2 output selected or no video bridge detected. %s.\n";
3255    static const char *mergeddisstr = "MergedFB mode disabled";
3256    static const char *modesforstr = "Modes for CRT%d: **************************************************\n";
3257    static const char *crtsetupstr = "*************************** CRT%d setup ***************************\n";
3258    static const char *crt2monname = "CRT2";
3259#endif
3260#if defined(SISDUALHEAD) || defined(SISMERGED)
3261    static const char *notsuitablestr = "Not using mode \"%s\" (not suitable for %s mode)\n";
3262#endif
3263
3264    if(flags & PROBE_DETECT) {
3265
3266       vbeInfoPtr   pVbe;
3267
3268       if(xf86LoadSubModule(pScrn, "vbe")) {
3269          int index = xf86GetEntityInfo(pScrn->entityList[0])->index;
3270#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3271	  if((pVbe = VBEInit(NULL, index)))
3272#else
3273          if((pVbe = VBEExtendedInit(NULL, index, 0)))
3274#endif
3275          {
3276             ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3277             vbeFree(pVbe);
3278          }
3279       }
3280       return TRUE;
3281    }
3282
3283    /*
3284     * Note: This function is only called once at server startup, and
3285     * not at the start of each server generation.  This means that
3286     * only things that are persistent across server generations can
3287     * be initialised here.  xf86Screens[] is the array of all screens,
3288     * (pScrn is a pointer to one of these).  Privates allocated using
3289     * xf86AllocateScrnInfoPrivateIndex() are too, and should be used
3290     * for data that must persist across server generations.
3291     *
3292     * Per-generation data should be allocated with
3293     * AllocateScreenPrivateIndex() from the ScreenInit() function.
3294     */
3295
3296    /* Check the number of entities, and fail if it isn't one. */
3297    if(pScrn->numEntities != 1) {
3298       SISErrorLog(pScrn, "Number of entities is not 1\n");
3299       return FALSE;
3300    }
3301
3302    /* Due to the liberal license terms this is needed for
3303     * keeping the copyright notice readable and intact in
3304     * binary distributions. Removing this is a copyright
3305     * infringement. Please read the license terms above.
3306     */
3307
3308    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3309	"SiS driver (%d/%02d/%02d-%d, compiled for " SISMYSERVERNAME " %d.%d.%d.%d)\n",
3310	SISDRIVERVERSIONYEAR + 2000, SISDRIVERVERSIONMONTH,
3311	SISDRIVERVERSIONDAY, SISDRIVERREVISION,
3312#ifdef XORG_VERSION_CURRENT
3313	XORG_VERSION_MAJOR, XORG_VERSION_MINOR,
3314	XORG_VERSION_PATCH, XORG_VERSION_SNAP
3315#else
3316	XF86_VERSION_MAJOR, XF86_VERSION_MINOR,
3317	XF86_VERSION_PATCH, XF86_VERSION_SNAP
3318#endif
3319	);
3320    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3321	"Copyright (C) 2001-2005 Thomas Winischhofer <thomas@winischhofer.net> and others\n");
3322    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3323	"*** See http://www.winischhofer.at/linuxsisvga.shtml\n");
3324    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3325	"*** for documentation and updates.\n");
3326
3327#ifdef XORG_VERSION_CURRENT
3328#if 0  /* no prototype yet */
3329    if(xorgGetVersion() != XORG_VERSION_CURRENT) {
3330       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3331         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3332    }
3333#endif
3334#else
3335#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(4,2,99,0,0)
3336    if(xf86GetVersion() != XF86_VERSION_CURRENT) {
3337       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3338         "This driver binary is not compiled for this version of " SISMYSERVERNAME "\n");
3339    }
3340#endif
3341#endif
3342
3343    /* Allocate the SISRec driverPrivate */
3344    if(!SISGetRec(pScrn)) {
3345       SISErrorLog(pScrn, "Could not allocate memory for pSiS private\n");
3346       return FALSE;
3347    }
3348    pSiS = SISPTR(pScrn);
3349    pSiS->pScrn = pScrn;
3350
3351    pSiS->pInt = NULL;
3352
3353    /* Save PCI Domain Base */
3354#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
3355    pSiS->IODBase = 0;
3356#else
3357    pSiS->IODBase = pScrn->domainIOBase;
3358#endif
3359
3360    /* Get the entity, and make sure it is PCI. */
3361    pSiS->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3362    if(pSiS->pEnt->location.type != BUS_PCI) {
3363       SISErrorLog(pScrn, "Entity's bus type is not PCI\n");
3364       goto my_error_0;
3365    }
3366
3367#ifdef SISDUALHEAD
3368    /* Allocate an entity private if necessary */
3369    if(xf86IsEntityShared(pScrn->entityList[0])) {
3370       pSiSEnt = xf86GetEntityPrivate(pScrn->entityList[0], SISEntityIndex)->ptr;
3371       pSiS->entityPrivate = pSiSEnt;
3372
3373       /* If something went wrong, quit here */
3374       if((pSiSEnt->DisableDual) || (pSiSEnt->ErrorAfterFirst)) {
3375	  SISErrorLog(pScrn, "First head encountered fatal error, aborting...\n");
3376	  goto my_error_0;
3377       }
3378    }
3379#endif
3380
3381    /* Find the PCI info for this screen */
3382    pSiS->PciInfo = xf86GetPciInfoForEntity(pSiS->pEnt->index);
3383    pSiS->PciBus = ((pciConfigPtr)pSiS->PciInfo->thisCard)->busnum;    /*SIS_PCI_BUS(pSiS->PciInfo);*/
3384    pSiS->PciDevice = ((pciConfigPtr)pSiS->PciInfo->thisCard)->devnum; /*SIS_PCI_DEVICE(pSiS->PciInfo);*/
3385    pSiS->PciFunc = ((pciConfigPtr)pSiS->PciInfo->thisCard)->funcnum;  /*SIS_PCI_FUNC(pSiS->PciInfo);*/
3386    pSiS->PciTag = ((pciConfigPtr)pSiS->PciInfo->thisCard)->tag;       /*SIS_PCI_TAG(pSiS->PciInfo);*/
3387
3388#ifdef SIS_NEED_MAP_IOP
3389    /********************************************/
3390    /*     THIS IS BROKEN AND WON'T WORK        */
3391    /* Reasons:                                 */
3392    /* 1) MIPS and ARM have no i/o ports but    */
3393    /* use memory mapped i/o only. The inX/outX */
3394    /* macros in compiler.h are smart enough to */
3395    /* add "IOPortBase" to the port number, but */
3396    /* "IOPortBase" is never initialized.       */
3397    /* 2) IOPortBase is declared in compiler.h  */
3398    /* itself. So until somebody fixes all      */
3399    /* modules that #include compiler.h to set  */
3400    /* IOPortBase, vga support for MIPS and ARM */
3401    /* is unusable.                             */
3402    /* (In this driver this is solvable because */
3403    /* we have our own vgaHW routines. However, */
3404    /* we use /dev/port for now instead.)       */
3405    /********************************************/
3406    pSiS->IOPAddress = pSiS->IODBase + pSiS->PciInfo->ioBase[2];
3407    if(!SISMapIOPMem(pScrn)) {
3408       SISErrorLog(pScrn, "Could not map I/O port area at 0x%x\n", pSiS->IOPAddress);
3409       goto my_error_0;
3410    } else {
3411       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I/O port area mapped to %p, size 128\n", pSiS->IOPBase);
3412#if defined(__mips__) || defined(__arm32__)
3413       /* inX/outX macros on these use IOPortBase as offset */
3414       /* This is entirely skrewed. */
3415       IOPortBase = (unsigned int)pSiS->IOPBase;
3416#endif
3417    }
3418#endif
3419
3420    /* Set up i/o port access (for non-x86) */
3421#ifdef SISUSEDEVPORT
3422    if((sisdevport = open("/dev/port", O_RDWR, 0)) == -1) {
3423       SISErrorLog(pScrn, "Failed to open /dev/port for read/write\n");
3424       goto my_error_0;
3425    }
3426    pSiS->sisdevportopen = TRUE;
3427#endif
3428
3429    /*
3430     * Set the Chipset and ChipRev, allowing config file entries to
3431     * override. DANGEROUS!
3432     */
3433    {
3434       SymTabRec *myChipsets = SISChipsets;
3435
3436       if(pSiS->PciInfo->vendor == PCI_VENDOR_XGI) {
3437          myChipsets = XGIChipsets;
3438       }
3439
3440       if(pSiS->pEnt->device->chipset && *pSiS->pEnt->device->chipset) {
3441
3442          pScrn->chipset = pSiS->pEnt->device->chipset;
3443          pSiS->Chipset = xf86StringToToken(myChipsets, pScrn->chipset);
3444
3445       } else if(pSiS->pEnt->device->chipID >= 0) {
3446
3447          pSiS->Chipset = pSiS->pEnt->device->chipID;
3448          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3449
3450          xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
3451								pSiS->Chipset);
3452       } else {
3453
3454          pSiS->Chipset = pSiS->PciInfo->chipType;
3455          pScrn->chipset = (char *)xf86TokenToString(myChipsets, pSiS->Chipset);
3456
3457       }
3458    }
3459
3460    if(pSiS->pEnt->device->chipRev >= 0) {
3461
3462       pSiS->ChipRev = pSiS->pEnt->device->chipRev;
3463       xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
3464								pSiS->ChipRev);
3465    } else {
3466
3467       pSiS->ChipRev = pSiS->PciInfo->chipRev;
3468
3469    }
3470
3471    /*
3472     * This shouldn't happen because such problems should be caught in
3473     * SISProbe(), but check it just in case the user has overridden them.
3474     */
3475    if(pScrn->chipset == NULL) {
3476       SISErrorLog(pScrn, "ChipID 0x%04X is not recognised\n", pSiS->Chipset);
3477       goto my_error_0;
3478    }
3479    if(pSiS->Chipset < 0) {
3480       SISErrorLog(pScrn, "Chipset \"%s\" is not recognised\n", pScrn->chipset);
3481       goto my_error_0;
3482    }
3483
3484    pSiS->SiS6326Flags = 0;
3485
3486    /* Determine VGA engine generation */
3487    switch(pSiS->Chipset) {
3488       case PCI_CHIP_SIS300:
3489       case PCI_CHIP_SIS540:
3490       case PCI_CHIP_SIS630: /* 630 + 730 */
3491          pSiS->VGAEngine = SIS_300_VGA;
3492	  break;
3493       case PCI_CHIP_SIS315H:
3494       case PCI_CHIP_SIS315:
3495       case PCI_CHIP_SIS315PRO:
3496       case PCI_CHIP_SIS550:
3497       case PCI_CHIP_SIS650: /* 650 + 740 */
3498       case PCI_CHIP_SIS330:
3499       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?), 770 */
3500       case PCI_CHIP_SIS340:
3501       case PCI_CHIP_XGIXG20:
3502       case PCI_CHIP_XGIXG40:
3503          pSiS->VGAEngine = SIS_315_VGA;
3504	  break;
3505       case PCI_CHIP_SIS530:
3506          pSiS->VGAEngine = SIS_530_VGA;
3507	  break;
3508       case PCI_CHIP_SIS6326:
3509          /* Determine SiS6326 revision. According to SiS the differences are:
3510	   * Chip name     Chip type      TV-Out       MPEG II decoder
3511	   * 6326 AGP      Rev. G0/H0     no           no
3512	   * 6326 DVD      Rev. D2        yes          yes
3513	   * 6326          Rev. Cx        yes          yes
3514	   */
3515	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3516		"Chipset is SiS6326 %s (revision 0x%02x)\n",
3517		(pSiS->ChipRev == 0xaf) ? "(Ax)" :
3518		   ((pSiS->ChipRev == 0x0a) ? "AGP (G0)" :
3519		      ((pSiS->ChipRev == 0x0b) ? "AGP (H0)" :
3520			 (((pSiS->ChipRev & 0xf0) == 0xd0) ? "DVD (Dx/H0)" :
3521			    (((pSiS->ChipRev & 0xf0) == 0x90) ? "(9x)" :
3522			       (((pSiS->ChipRev & 0xf0) == 0xc0) ? "(Cx)" :
3523				  "(unknown)"))))),
3524		pSiS->ChipRev);
3525	  if((pSiS->ChipRev != 0x0a) && (pSiS->ChipRev != 0x0b)) {
3526	     pSiS->SiS6326Flags |= SIS6326_HASTV;
3527	  }
3528	  /* fall through */
3529       default:
3530	  pSiS->VGAEngine = SIS_OLD_VGA;
3531    }
3532
3533    /* We don't know about the current mode yet */
3534    pSiS->OldMode = 0;
3535
3536    /* Determine whether this is the primary or a secondary
3537     * display adapter. And right here the problem starts:
3538     * On machines with integrated SiS chipsets, the system BIOS
3539     * usually sets VGA_EN on all PCI-to-PCI bridges in the system
3540     * (of which there usually are two: PCI and AGP). This and
3541     * the fact that any PCI card POSTed by sisfb naturally has
3542     * its PCI resources enabled, leads to X assuming that
3543     * there are more than one "primary" cards in the system.
3544     * In this case, X treats ALL cards as "secondary" -
3545     * which by no means is desireable. If sisfb is running,
3546     * we can determine which card really is "primary" (in
3547     * terms of if it's the one that occupies the A0000 area
3548     * etc.) in a better way (Linux 2.6.12 or later). See below.
3549     */
3550    if(!(pSiS->Primary = xf86IsPrimaryPci(pSiS->PciInfo))) {
3551       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3552	   SISMYSERVERNAME " assumes this adapter to be secondary\n");
3553    }
3554
3555    /* Now check if sisfb is running, and if so, retrieve
3556     * all possible info from it. This also resets all
3557     * sisfb_* entries in pSiS regardless of the chipset.
3558     */
3559    SiS_CheckKernelFB(pScrn);
3560
3561    /* Now for that primary/secondary mess: Linux kernel
3562     * 2.6.12 and later knows what card is primary, and so
3563     * does any recent version of sisfb. XFree86/X.org takes
3564     * all adapters as "secondary" if more than one card's
3565     * memory and i/o resources are enabled, and more than
3566     * one PCI bridge in the system has VGA_EN set at server
3567     * start. So, let's start thinking: What is this
3568     * primary/secondary classification needed for anyway?
3569     * (This list might be incomplete for the entire server
3570     * infrastructure, but it's complete as regards the driver's
3571     * purposes of primary/secondary classification.)
3572     *    1) VGA/console font restoring: Here it's irrelevant
3573     *       whether more than one card's resources are enabled
3574     *       at server start or not. Relevant is whether the card
3575     *       occupies the A0000 area at this time. Assuming (?)
3576     *       that this does not change during machine up-time,
3577     *       it suffices to know which device was the boot video
3578     *       device (as determined by Linux 2.6.12 and later).
3579     *       Also, this is only relevant if the card is in text
3580     *       mode; if it's in graphics mode, fonts aren't saved
3581     *       or restored anyway.
3582     *       sisfb tells us if that card is considered the boot
3583     *       video device. The hardware registers tell us if
3584     *       the card's A0000 address decoding is enabled, and if
3585     *       the card currently is in text mode. These three bits
3586     *       of information are enough to decide on whether or not
3587     *       to save/restore fonts.
3588     *    2) POSTing. Same here. Relevant is only whether or not
3589     *       the card has been POSTed once before. POSTing cards
3590     *       on every server start is pretty ugly, especially
3591     *       if a framebuffer driver is already handling it.
3592     * SiS/XGI cards POSTed by sisfb can coexist well with other
3593     * active adapters. So we trust sisfb's information more
3594     * than X's (especially as we only use this information for
3595     * console font restoring and eventual POSTing.)
3596     * What we still need is a way to find out about all this if
3597     * sisfb is not running....
3598     */
3599    if(!pSiS->Primary && pSiS->sisfbprimary) {
3600       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3601		"sisfb reports this adapter to be primary. Seems more reliable.\n");
3602       pSiS->Primary = TRUE;
3603    }
3604
3605    /* If the card is "secondary" and has not been
3606     * POSTed by sisfb, POST it now through int10.
3607     * For cards POSTed by sisfb, we definitely don't
3608     * want that as it messes up our set up (eg. the
3609     * disabled A0000 area).
3610     * The int10 module decides on its own if the
3611     * card is primary or secondary. Since it uses
3612     * the generic technique described above, and since
3613     * for "secondary" cards it needs a real PCI BIOS
3614     * ROM, and since integrated chips don't have such
3615     * a PCI BIOS ROM, int10 will naturally fail to
3616     * find/read the BIOS on such machines. Great.
3617     * Using the integrated graphics as "secondary"
3618     * (which it will be as soon as X finds more than
3619     * one card's mem and i/o resources enabled, and more
3620     * than one PCI bridge's VGA_EN bit set during server
3621     * start) will therefore prevent us from restoring
3622     * the mode using the VBE. That means real fun if
3623     * the integrated chip is set up to use the video
3624     * bridge output for text mode (which is something
3625     * the driver doesn't really support since it's done
3626     * pretty much differently on every machine.)
3627     */
3628#if !defined(__alpha__)
3629    if(!pSiS->Primary) {
3630       if(!pSiS->sisfbcardposted) {
3631	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3632		"Initializing adapter through int10\n");
3633	  if(xf86LoadSubModule(pScrn, "int10")) {
3634	     xf86LoaderReqSymLists(int10Symbols, NULL);
3635	     pSiS->pInt = xf86InitInt10(pSiS->pEnt->index);
3636	  } else {
3637	     SISErrorLog(pScrn, "Failed to load int10 module\n");
3638	  }
3639       } else {
3640	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3641		"Adapter already initialized by sisfb\n");
3642       }
3643    }
3644#endif
3645
3646    /* Get the address of our relocated IO registers.
3647     * These are enabled by the hardware during cold boot, and
3648     * by the BIOS. So we can pretty much rely on that these
3649     * are enabled.
3650     */
3651    pSiS->RelIO = (SISIOADDRESS)(pSiS->PciInfo->ioBase[2] + pSiS->IODBase);
3652    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Relocated I/O registers at 0x%lX\n",
3653           (ULong)pSiS->RelIO);
3654
3655    /* Unlock extended registers */
3656    sisSaveUnlockExtRegisterLock(pSiS, &srlockReg, &crlockReg);
3657
3658    /* Is a0000 memory address decoding enabled? */
3659    pSiS->VGADecodingEnabled = TRUE;
3660    switch(pSiS->VGAEngine) {
3661    case SIS_OLD_VGA:
3662       /* n/a */
3663       break;
3664    case SIS_530_VGA:
3665       inSISIDXREG(SISSR, 0x3d, tempreg);
3666       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3667       break;
3668    case SIS_300_VGA:
3669    case SIS_315_VGA:
3670       inSISIDXREG(SISSR, 0x20, tempreg);
3671       if(tempreg & 0x04) pSiS->VGADecodingEnabled = FALSE;
3672       break;
3673    }
3674
3675    if(!pSiS->VGADecodingEnabled) {
3676       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
3677		"Standard VGA (0xA0000) memory address decoding is disabled\n");
3678    }
3679
3680#ifdef SIS_PC_PLATFORM
3681    /* Map 64k VGA window for saving/restoring CGA fonts.
3682     * For secondary cards or if A0000 address decoding
3683     * is disabled, this will map the beginning of the
3684     * linear (PCI) video RAM instead.
3685     */
3686    SiS_MapVGAMem(pScrn);
3687#endif
3688
3689    /* Set operating state */
3690
3691    /* 1. memory */
3692    /* [ResUnusedOpr: Resource decoded by hw, but not used]
3693     * [ResDisableOpr: Resource is not decoded by hw]
3694     * So, if a0000 memory decoding is disabled, one could
3695     * argue that we may say so, too. Hm. Quite likely that
3696     * the VBE (via int10) will eventually enable it. So we
3697     * cowardly say unused instead.
3698     */
3699    xf86SetOperatingState(resVgaMem, pSiS->pEnt->index, ResUnusedOpr);
3700
3701    /* 2. i/o */
3702    /* Although we only use the relocated i/o ports, the hardware
3703     * also decodes the standard VGA port range. This could in
3704     * theory be disabled, but I don't dare to do this; in case of
3705     * a server crash, the card would be entirely dead. Also, this
3706     * would prevent int10 and the VBE from working at all. Generic
3707     * access control through the PCI configuration registers does
3708     * nicely anyway.
3709     */
3710    xf86SetOperatingState(resVgaIo, pSiS->pEnt->index, ResUnusedOpr);
3711
3712    /* Operations for which memory access is required */
3713    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3714
3715    /* Operations for which I/O access is required */
3716    pScrn->racIoFlags = RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
3717
3718    /* Load ramdac module */
3719    if(!xf86LoadSubModule(pScrn, "ramdac")) {
3720       SISErrorLog(pScrn, "Could not load ramdac module\n");
3721       goto my_error_1;
3722    }
3723
3724    xf86LoaderReqSymLists(ramdacSymbols, NULL);
3725
3726    /* Set pScrn->monitor */
3727    pScrn->monitor = pScrn->confScreen->monitor;
3728
3729    /* Reset some entries */
3730    pSiS->SiSFastVidCopy = SiSVidCopyGetDefault();
3731    pSiS->SiSFastMemCopy = SiSVidCopyGetDefault();
3732    pSiS->SiSFastVidCopyFrom = SiSVidCopyGetDefault();
3733    pSiS->SiSFastMemCopyFrom = SiSVidCopyGetDefault();
3734    pSiS->SiSFastVidCopyDone = FALSE;
3735#ifdef SIS_USE_XAA
3736    pSiS->RenderCallback = NULL;
3737#endif
3738#ifdef SIS_USE_EXA
3739    pSiS->ExaRenderCallback = NULL;
3740#endif
3741    pSiS->InitAccel = SiSPseudo;
3742    pSiS->SyncAccel = SiSPseudo;
3743    pSiS->FillRect  = NULL;
3744    pSiS->BlitRect  = NULL;
3745
3746    /* Always do a ValidMode() inside Switchmode() */
3747    pSiS->skipswitchcheck = FALSE;
3748
3749    /* Determine chipset and its capabilities in detail */
3750    pSiS->ChipFlags = 0;
3751    pSiS->SiS_SD_Flags = pSiS->SiS_SD2_Flags = 0;
3752    pSiS->SiS_SD3_Flags = pSiS->SiS_SD4_Flags = 0;
3753    pSiS->HWCursorMBufNum = pSiS->HWCursorCBufNum = 0;
3754    pSiS->NeedFlush = FALSE;
3755    pSiS->NewCRLayout = FALSE;
3756    pSiS->mmioSize = 64;
3757
3758    switch(pSiS->Chipset) {
3759       case PCI_CHIP_SIS530:
3760	  pSiS->ChipType = SIS_530;
3761	  break;
3762       case PCI_CHIP_SIS300:
3763	  pSiS->ChipType = SIS_300;
3764	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3765	  break;
3766       case PCI_CHIP_SIS540:
3767	  pSiS->ChipType = SIS_540;
3768	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3769	  break;
3770       case PCI_CHIP_SIS630: /* 630 + 730 */
3771	  pSiS->ChipType = SIS_630;
3772	  if(pciReadLong(0x00000000, 0x00) == 0x07301039) {
3773	     pSiS->ChipType = SIS_730;
3774	  }
3775	  pSiS->SiS_SD_Flags |= SiS_SD_IS300SERIES;
3776	  break;
3777       case PCI_CHIP_SIS315H:
3778	  pSiS->ChipType = SIS_315H;
3779	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3780	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3781	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3782	  pSiS->myCR63 = 0x63;
3783	  break;
3784       case PCI_CHIP_SIS315:
3785	  /* Override for simplicity */
3786	  pSiS->Chipset = PCI_CHIP_SIS315H;
3787	  pSiS->ChipType = SIS_315;
3788	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3789	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3790	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3791	  pSiS->myCR63 = 0x63;
3792	  break;
3793       case PCI_CHIP_SIS315PRO:
3794	  /* Override for simplicity */
3795	  pSiS->Chipset = PCI_CHIP_SIS315H;
3796	  pSiS->ChipType = SIS_315PRO;
3797	  pSiS->ChipFlags |= (SiSCF_315Core | SiSCF_MMIOPalette);
3798	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3799	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3800	  pSiS->myCR63 = 0x63;
3801	  break;
3802       case PCI_CHIP_SIS550:
3803	  pSiS->ChipType = SIS_550;
3804	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3805	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3806	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3807	  pSiS->myCR63 = 0x63;
3808	  break;
3809       case PCI_CHIP_SIS650: /* 650 + 740 */
3810	  pSiS->ChipType = SIS_650;
3811	  if(pciReadLong(0x00000000, 0x00) == 0x07401039) {
3812	     pSiS->ChipType = SIS_740;
3813	  }
3814	  pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_Real256ECore | SiSCF_MMIOPalette);
3815	  pSiS->SiS_SD_Flags |= SiS_SD_IS315SERIES;
3816	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3817	  pSiS->myCR63 = 0x63;
3818	  break;
3819       case PCI_CHIP_SIS330:
3820	  pSiS->ChipType = SIS_330;
3821	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3822	  pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3823	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3824	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN; /* FIXME ? */
3825	  pSiS->myCR63 = 0x53; /* sic! */
3826	  break;
3827       case PCI_CHIP_SIS660: /* 660, 661, 741, 760, 761, 670(?) */
3828	  {
3829	     ULong hpciid = pciReadLong(0x00000000, 0x00);
3830	     switch(hpciid) {
3831	     case 0x06601039:
3832		pSiS->ChipType = SIS_660;
3833		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3834		pSiS->NeedFlush = TRUE;
3835		break;
3836	     case 0x07601039:
3837		pSiS->ChipType = SIS_760;
3838		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3839		pSiS->NeedFlush = TRUE;
3840		break;
3841	     case 0x07611039:
3842		pSiS->ChipType = SIS_761;
3843		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3844		pSiS->NeedFlush = TRUE;
3845		break;
3846	     case 0x07701039:
3847		pSiS->ChipType = SIS_770;
3848		pSiS->ChipFlags |= SiSCF_Ultra256Core;
3849		pSiS->NeedFlush = TRUE;
3850		break;
3851	     case 0x07411039:
3852		pSiS->ChipType = SIS_741;
3853		pSiS->ChipFlags |= SiSCF_Real256ECore;
3854		break;
3855	     case 0x06611039:
3856	     default:
3857		pSiS->ChipType = SIS_661;
3858		pSiS->ChipFlags |= SiSCF_Real256ECore;
3859		break;
3860	     case 0x06701039:
3861		pSiS->ChipType = SIS_670;
3862		pSiS->ChipFlags |= SiSCF_Real256ECore;
3863	     }
3864	     /* Detection could also be done by CR5C & 0xf8:
3865	      * 0x10 = 661 (CR5F & 0xc0: 0x00 both A0 and A1)
3866	      * 0x80 = 760 (CR5F & 0xc0: 0x00 A0, 0x40 A1)
3867	      * 0x90 = 741 (CR5F & 0xc0: 0x00 A0,A1 0x40 A2)
3868	      * other: 660 (CR5F & 0xc0: 0x00 A0 0x40 A1) (DOA?)
3869	      */
3870	     pSiS->ChipFlags |= (SiSCF_Integrated | SiSCF_MMIOPalette);
3871	     pSiS->SiS_SD_Flags |= SiS_SD_IS330SERIES;
3872	     pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3873	     pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3874	     pSiS->myCR63 = 0x53; /* sic! */
3875	     pSiS->NewCRLayout = TRUE;
3876	  }
3877	  break;
3878       case PCI_CHIP_SIS340:
3879	  pSiS->ChipType = SIS_340;
3880	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette);
3881	  pSiS->SiS_SD_Flags |= SiS_SD_IS340SERIES;
3882	  pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORTXVHUESAT;
3883	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3884	  pSiS->myCR63 = 0x53;
3885	  pSiS->NewCRLayout = TRUE;
3886	  break;
3887       case PCI_CHIP_XGIXG20:
3888	  pSiS->ChipType = XGI_20;
3889	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3890	  pSiS->SiS_SD2_Flags |= (SiS_SD2_NOOVERLAY | SiS_SD2_ISXGI);
3891	  pSiS->myCR63 = 0x53;
3892	  pSiS->NewCRLayout = TRUE;
3893	  break;
3894       case PCI_CHIP_XGIXG40:
3895	  pSiS->ChipType = XGI_40;
3896	  pSiS->ChipFlags |= (SiSCF_XabreCore | SiSCF_MMIOPalette | SiSCF_IsXGI);
3897	  pSiS->SiS_SD2_Flags |= (SiS_SD2_SUPPORTXVHUESAT | SiS_SD2_ISXGI);
3898	  pSiS->SiS_SD3_Flags |= SiS_SD3_CRT1SATGAIN;
3899	  pSiS->myCR63 = 0x53;
3900	  pSiS->NewCRLayout = TRUE;
3901	  if(pSiS->ChipRev == 2) pSiS->ChipFlags |= SiSCF_IsXGIV3;
3902	  break;
3903       default:
3904	  pSiS->ChipType = SIS_OLD;
3905	  break;
3906    }
3907
3908    /*
3909     * Now back to real business: Figure out the depth, bpp, etc.
3910     * Set SupportConvert... flags since we use the fb layer which
3911     * supports this conversion. (24to32 seems not implemented though)
3912     * Additionally, determine the size of the HWCursor memory area.
3913     */
3914    switch(pSiS->VGAEngine) {
3915       case SIS_300_VGA:
3916	  pSiS->CursorSize = 4096;
3917	  pix24flags = Support32bppFb;
3918	  break;
3919       case SIS_315_VGA:
3920	  pSiS->CursorSize = 16384;
3921	  pix24flags = Support32bppFb;
3922	  break;
3923       case SIS_530_VGA:
3924	  pSiS->CursorSize = 2048;
3925	  pix24flags = Support32bppFb	  |
3926		       Support24bppFb	  |
3927		       SupportConvert32to24;
3928          break;
3929       default:
3930	  pSiS->CursorSize = 2048;
3931	  pix24flags = Support24bppFb	    |
3932		       SupportConvert32to24 |
3933		       PreferConvert32to24;
3934	  break;
3935    }
3936
3937#ifdef SISDUALHEAD
3938    /* In case of Dual Head, we need to determine if we are the "master" head or
3939     * the "slave" head. In order to do that, we set PrimInit to DONE in the
3940     * shared entity at the end of the first initialization. The second
3941     * initialization then knows that some things have already been done. THIS
3942     * ALWAYS ASSUMES THAT THE FIRST DEVICE INITIALIZED IS THE MASTER!
3943     */
3944    if(xf86IsEntityShared(pScrn->entityList[0])) {
3945       if(pSiSEnt->lastInstance > 0) {
3946	  if(!xf86IsPrimInitDone(pScrn->entityList[0])) {
3947	     /* First Head (always CRT2) */
3948	     pSiS->SecondHead = FALSE;
3949	     pSiSEnt->pScrn_1 = pScrn;
3950	     pSiSEnt->CRT1ModeNo = pSiSEnt->CRT2ModeNo = -1;
3951	     pSiSEnt->CRT2ModeSet = FALSE;
3952	     pSiS->DualHeadMode = TRUE;
3953	     pSiSEnt->DisableDual = FALSE;
3954	     pSiSEnt->BIOS = NULL;
3955	     pSiSEnt->ROM661New = FALSE;
3956	     pSiSEnt->HaveXGIBIOS = FALSE;
3957	     pSiSEnt->SiS_Pr = NULL;
3958	     pSiSEnt->RenderAccelArray = NULL;
3959	     pSiSEnt->SiSFastVidCopy = pSiSEnt->SiSFastMemCopy = NULL;
3960	     pSiSEnt->SiSFastVidCopyFrom = pSiSEnt->SiSFastMemCopyFrom = NULL;
3961	  } else {
3962	     /* Second Head (always CRT1) */
3963	     pSiS->SecondHead = TRUE;
3964	     pSiSEnt->pScrn_2 = pScrn;
3965	     pSiS->DualHeadMode = TRUE;
3966	  }
3967       } else {
3968	  /* Only one screen in config file - disable dual head mode */
3969	  pSiS->SecondHead = FALSE;
3970	  pSiS->DualHeadMode = FALSE;
3971	  pSiSEnt->DisableDual = TRUE;
3972       }
3973    } else {
3974       /* Entity is not shared - disable dual head mode */
3975       pSiS->SecondHead = FALSE;
3976       pSiS->DualHeadMode = FALSE;
3977    }
3978#endif
3979
3980    /* Save the name of our Device section for SiSCtrl usage */
3981    {
3982       int ttt = 0;
3983       GDevPtr device = xf86GetDevFromEntity(pScrn->entityList[0],
3984						pScrn->entityInstanceList[0]);
3985       if(device && device->identifier) {
3986          if((ttt = strlen(device->identifier)) > 31) ttt = 31;
3987	  strncpy(&pSiS->devsectname[0], device->identifier, 31);
3988       }
3989       pSiS->devsectname[ttt] = 0;
3990    }
3991
3992    pSiS->ForceCursorOff = FALSE;
3993
3994    /* Allocate SiS_Private (for mode switching code) and initialize it */
3995    pSiS->SiS_Pr = NULL;
3996#ifdef SISDUALHEAD
3997    if(pSiSEnt) {
3998       if(pSiSEnt->SiS_Pr) pSiS->SiS_Pr = pSiSEnt->SiS_Pr;
3999    }
4000#endif
4001    if(!pSiS->SiS_Pr) {
4002       if(!(pSiS->SiS_Pr = xnfcalloc(sizeof(struct SiS_Private), 1))) {
4003	  SISErrorLog(pScrn, "Could not allocate memory for SiS_Pr structure\n");
4004	  goto my_error_1;
4005       }
4006#ifdef SISDUALHEAD
4007       if(pSiSEnt) pSiSEnt->SiS_Pr = pSiS->SiS_Pr;
4008#endif
4009       memset(pSiS->SiS_Pr, 0, sizeof(struct SiS_Private));
4010       pSiS->SiS_Pr->PciTag = pSiS->PciTag;
4011       pSiS->SiS_Pr->ChipType = pSiS->ChipType;
4012       pSiS->SiS_Pr->ChipRevision = pSiS->ChipRev;
4013       pSiS->SiS_Pr->SiS_Backup70xx = 0xff;
4014       pSiS->SiS_Pr->SiS_CHOverScan = -1;
4015       pSiS->SiS_Pr->SiS_ChSW = FALSE;
4016       pSiS->SiS_Pr->SiS_CustomT = CUT_NONE;
4017       pSiS->SiS_Pr->SiS_UseWide = -1;
4018       pSiS->SiS_Pr->SiS_UseWideCRT2 = -1;
4019       pSiS->SiS_Pr->SiS_TVBlue = -1;
4020       pSiS->SiS_Pr->PanelSelfDetected = FALSE;
4021       pSiS->SiS_Pr->UsePanelScaler = -1;
4022       pSiS->SiS_Pr->CenterScreen = -1;
4023       pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
4024       pSiS->SiS_Pr->PDC = pSiS->SiS_Pr->PDCA = -1;
4025       pSiS->SiS_Pr->LVDSHL = -1;
4026       pSiS->SiS_Pr->HaveEMI = FALSE;
4027       pSiS->SiS_Pr->HaveEMILCD = FALSE;
4028       pSiS->SiS_Pr->OverruleEMI = FALSE;
4029       pSiS->SiS_Pr->SiS_SensibleSR11 = FALSE;
4030       if(pSiS->ChipType >= SIS_661) {
4031          pSiS->SiS_Pr->SiS_SensibleSR11 = TRUE;
4032       }
4033       pSiS->SiS_Pr->SiS_MyCR63 = pSiS->myCR63;
4034       pSiS->SiS_Pr->DDCPortMixup = FALSE;
4035    }
4036
4037    /* Copy IO address to SiS_Pr and init the structure for
4038     * routines inside init.c/init301.c
4039     */
4040    pSiS->SiS_Pr->IOAddress = (SISIOADDRESS)(pSiS->RelIO + 0x30);
4041    SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO + 0x30);
4042
4043    /* The following identifies the old chipsets. This is only
4044     * partly used since the really old chips are not supported,
4045     * but I keep it here for future use.
4046     * 205, 215 and 225 are to be treated the same way, 201 and 202
4047     * are different.
4048     */
4049    if(pSiS->VGAEngine == SIS_OLD_VGA || pSiS->VGAEngine == SIS_530_VGA) {
4050       switch(pSiS->Chipset) {
4051       case PCI_CHIP_SG86C201:
4052	  pSiS->oldChipset = OC_SIS86201; break;
4053       case PCI_CHIP_SG86C202:
4054	  pSiS->oldChipset = OC_SIS86202; break;
4055       case PCI_CHIP_SG86C205:
4056	  inSISIDXREG(SISSR, 0x10, tempreg);
4057	  if(tempreg & 0x80) pSiS->oldChipset = OC_SIS6205B;
4058	  else pSiS->oldChipset = (pSiS->ChipRev == 0x11) ?
4059					OC_SIS6205C : OC_SIS6205A;
4060	  break;
4061       case PCI_CHIP_SIS82C204:
4062	  pSiS->oldChipset = OC_SIS82204; break;
4063       case 0x6225:
4064	  pSiS->oldChipset = OC_SIS6225; break;
4065       case PCI_CHIP_SIS5597:
4066	  pSiS->oldChipset = OC_SIS5597; break;
4067       case PCI_CHIP_SIS6326:
4068	  pSiS->oldChipset = OC_SIS6326; break;
4069       case PCI_CHIP_SIS530:
4070	  if(pciReadLong(0x00000000, 0x00) == 0x06201039) {
4071	     pSiS->oldChipset = OC_SIS620;
4072	  } else {
4073	     if((pSiS->ChipRev & 0x0f) < 0x0a)
4074		   pSiS->oldChipset = OC_SIS530A;
4075	     else  pSiS->oldChipset = OC_SIS530B;
4076	  }
4077	  break;
4078       default:
4079	  pSiS->oldChipset = OC_UNKNOWN;
4080       }
4081    }
4082
4083    if(!xf86SetDepthBpp(pScrn, 0, 0, 0, pix24flags)) {
4084       SISErrorLog(pScrn, "xf86SetDepthBpp() error\n");
4085       goto my_error_1;
4086    }
4087
4088    /* Check that the returned depth is one we support */
4089    temp = 0;
4090    switch(pScrn->depth) {
4091       case 8:
4092       case 16:
4093       case 24:
4094          break;
4095       case 15:
4096	  if((pSiS->VGAEngine == SIS_300_VGA) ||
4097	     (pSiS->VGAEngine == SIS_315_VGA)) {
4098	     temp = 1;
4099	  }
4100	  break;
4101       default:
4102	  temp = 1;
4103    }
4104
4105    if(temp) {
4106       SISErrorLog(pScrn,
4107            "Given color depth (%d) is not supported by this driver/chipset\n",
4108            pScrn->depth);
4109       goto my_error_1;
4110    }
4111
4112    xf86PrintDepthBpp(pScrn);
4113
4114    if( (((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
4115         (pScrn->bitsPerPixel == 24)) ||
4116	((pSiS->VGAEngine == SIS_OLD_VGA) && (pScrn->bitsPerPixel == 32)) ) {
4117       SISErrorLog(pScrn,
4118            "Framebuffer bpp %d not supported for this chipset\n", pScrn->bitsPerPixel);
4119       goto my_error_1;
4120    }
4121
4122    /* Get the depth24 pixmap format */
4123    if(pScrn->depth == 24 && pix24bpp == 0) {
4124       pix24bpp = xf86GetBppFromDepth(pScrn, 24);
4125    }
4126
4127    /*
4128     * This must happen after pScrn->display has been set because
4129     * xf86SetWeight references it.
4130     */
4131    if(pScrn->depth > 8) {
4132        /* The defaults are OK for us */
4133        rgb zeros = {0, 0, 0};
4134
4135        if(!xf86SetWeight(pScrn, zeros, zeros)) {
4136	    SISErrorLog(pScrn, "xf86SetWeight() error\n");
4137	    goto my_error_1;
4138        } else {
4139	   Bool ret = FALSE;
4140	   switch(pScrn->depth) {
4141	   case 15:
4142	      if((pScrn->weight.red != 5) ||
4143	         (pScrn->weight.green != 5) ||
4144		 (pScrn->weight.blue != 5)) ret = TRUE;
4145	      break;
4146	   case 16:
4147	      if((pScrn->weight.red != 5) ||
4148	         (pScrn->weight.green != 6) ||
4149		 (pScrn->weight.blue != 5)) ret = TRUE;
4150	      break;
4151	   case 24:
4152	      if((pScrn->weight.red != 8) ||
4153	         (pScrn->weight.green != 8) ||
4154		 (pScrn->weight.blue != 8)) ret = TRUE;
4155	      break;
4156	   }
4157	   if(ret) {
4158	      SISErrorLog(pScrn,
4159		   "RGB weight %d%d%d at depth %d not supported by hardware\n",
4160		   (int)pScrn->weight.red, (int)pScrn->weight.green,
4161		   (int)pScrn->weight.blue, pScrn->depth);
4162	      goto my_error_1;
4163	   }
4164        }
4165    }
4166
4167    /* Set the current layout parameters */
4168    pSiS->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
4169    pSiS->CurrentLayout.depth        = pScrn->depth;
4170    /* (Inside this function, we can use pScrn's contents anyway) */
4171
4172    if(!xf86SetDefaultVisual(pScrn, -1)) {
4173       SISErrorLog(pScrn, "xf86SetDefaultVisual() error\n");
4174       goto my_error_1;
4175    } else {
4176       /* We don't support DirectColor at > 8bpp */
4177       if(pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
4178	  SISErrorLog(pScrn,
4179	       "Given default visual (%s) is not supported at depth %d\n",
4180	        xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
4181	  goto my_error_1;
4182       }
4183    }
4184
4185#ifdef SISDUALHEAD
4186    /* Due to palette & timing problems we don't support 8bpp in DHM */
4187    if((pSiS->DualHeadMode) && (pScrn->bitsPerPixel <= 8)) {
4188       SISErrorLog(pScrn, "Color depth %d not supported in Dual Head mode.\n",
4189			pScrn->bitsPerPixel);
4190       goto my_error_1;
4191    }
4192#endif
4193
4194    /* Read BIOS for 300/315/330/340 series customization */
4195    pSiS->SiS_Pr->VirtualRomBase = NULL;
4196    pSiS->BIOS = NULL;
4197    pSiS->SiS_Pr->UseROM = FALSE;
4198    pSiS->ROM661New = FALSE;
4199    pSiS->HaveXGIBIOS = FALSE;
4200
4201    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4202#ifdef SISDUALHEAD
4203       if(pSiSEnt) {
4204	  if(pSiSEnt->BIOS) {
4205	     pSiS->BIOS = pSiSEnt->BIOS;
4206	     pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4207	     pSiS->ROM661New = pSiSEnt->ROM661New;
4208	     pSiS->HaveXGIBIOS = pSiSEnt->HaveXGIBIOS;
4209	  }
4210       }
4211#endif
4212       if(!pSiS->BIOS) {
4213	  if(!(pSiS->BIOS = xcalloc(1, BIOS_SIZE))) {
4214	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4215		"Could not allocate memory for video BIOS image\n");
4216	  } else {
4217	     ULong  segstart;
4218	     UShort mypciid = pSiS->Chipset;
4219	     UShort mypcivendor = (pSiS->ChipFlags & SiSCF_IsXGI) ? PCI_VENDOR_XGI : PCI_VENDOR_SIS;
4220	     Bool   found = FALSE, readpci = FALSE;
4221	     int    biossize = BIOS_SIZE;
4222
4223	     switch(pSiS->ChipType) {
4224	     case SIS_315:    mypciid = PCI_CHIP_SIS315;
4225			      readpci = TRUE;
4226			      break;
4227	     case SIS_315PRO: mypciid = PCI_CHIP_SIS315PRO;
4228			      readpci = TRUE;
4229			      break;
4230	     case SIS_300:
4231	     case SIS_315H:
4232	     case SIS_330:
4233	     case SIS_340:
4234	     case XGI_40:     readpci = TRUE;
4235			      break;
4236	     case XGI_20:     readpci = TRUE;
4237			      biossize = 0x8000;
4238			      break;
4239	     }
4240
4241	     if(readpci) {
4242		xf86ReadPciBIOS(0, pSiS->PciTag, 0, pSiS->BIOS, biossize);
4243		if(SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) {
4244		   found = TRUE;
4245		}
4246	     }
4247
4248	     if(!found) {
4249		for(segstart = BIOS_BASE; segstart < 0x000f0000; segstart += 0x00001000) {
4250
4251#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,99,0,0)
4252		   if(xf86ReadBIOS(segstart, 0, pSiS->BIOS, biossize) != biossize) continue;
4253#else
4254		   if(xf86ReadDomainMemory(pSiS->PciTag, segstart, biossize, pSiS->BIOS) != biossize) continue;
4255#endif
4256
4257		   if(!SISCheckBIOS(pSiS, mypciid, mypcivendor, biossize)) continue;
4258
4259		   found = TRUE;
4260		   break;
4261		}
4262             }
4263
4264	     if(found) {
4265		UShort romptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
4266		pSiS->SiS_Pr->VirtualRomBase = pSiS->BIOS;
4267		if(pSiS->ChipFlags & SiSCF_IsXGI) {
4268		   pSiS->HaveXGIBIOS = pSiS->SiS_Pr->SiS_XGIROM = TRUE;
4269		   pSiS->SiS_Pr->UseROM = FALSE;
4270		   if(pSiS->ChipFlags & SiSCF_IsXGIV3) {
4271		      if(!(pSiS->BIOS[0x1d1] & 0x01)) {
4272			 pSiS->SiS_Pr->DDCPortMixup = TRUE;
4273		      }
4274	           }
4275	        } else {
4276		   pSiS->ROM661New = SiSDetermineROMLayout661(pSiS->SiS_Pr);
4277		}
4278		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4279			"Video BIOS version \"%7s\" found (%s data layout)\n",
4280			&pSiS->BIOS[romptr], pSiS->ROM661New ? "new SiS" :
4281				(pSiS->HaveXGIBIOS ? "XGI" : "old SiS"));
4282		if(pSiS->SiS_Pr->DDCPortMixup) {
4283		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4284			"*** Buggy XGI V3XT card detected: If VGA and DVI are connected at the\n");
4285		   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4286			"*** same time, BIOS and driver will be unable to detect DVI connection.\n");
4287		}
4288#ifdef SISDUALHEAD
4289		if(pSiSEnt) {
4290		   pSiSEnt->BIOS = pSiS->BIOS;
4291		   pSiSEnt->ROM661New = pSiS->ROM661New;
4292		   pSiSEnt->HaveXGIBIOS = pSiS->HaveXGIBIOS;
4293		}
4294#endif
4295	     } else {
4296	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4297			 "Could not find/read video BIOS\n");
4298		xfree(pSiS->BIOS);
4299		pSiS->BIOS = NULL;
4300	     }
4301          }
4302       }
4303
4304       if(!(pSiS->ChipFlags & SiSCF_IsXGI)) {
4305          if(pSiS->BIOS) pSiS->SiS_Pr->UseROM = TRUE;
4306          else           pSiS->SiS_Pr->UseROM = FALSE;
4307       }
4308    }
4309
4310    /* Evaluate options */
4311    SiSOptions(pScrn);
4312
4313#ifdef SISMERGED
4314    /* Due to palette & timing problems we don't support 8bpp in MFBM */
4315    if((pSiS->MergedFB) && (pScrn->bitsPerPixel <= 8)) {
4316       SISErrorLog(pScrn, "MergedFB: Color depth %d not supported, %s\n",
4317			pScrn->bitsPerPixel, mergeddisstr);
4318       pSiS->MergedFB = pSiS->MergedFBAuto = FALSE;
4319    }
4320#endif
4321
4322    /* Probe CPU features */
4323#ifdef SISDUALHEAD
4324    if(pSiS->DualHeadMode) {
4325       pSiS->CPUFlags = pSiSEnt->CPUFlags;
4326    }
4327#endif
4328    if(!pSiS->CPUFlags) {
4329       pSiS->CPUFlags = SiSGetCPUFlags(pScrn);
4330       pSiS->CPUFlags |= SIS_CPUFL_FLAG;
4331#ifdef SISDUALHEAD
4332       if(pSiS->DualHeadMode) pSiSEnt->CPUFlags = pSiS->CPUFlags;
4333#endif
4334    }
4335
4336    /* We use a programamble clock */
4337    pScrn->progClock = TRUE;
4338
4339    /* Set the bits per RGB for 8bpp mode */
4340    if(pScrn->depth == 8) pScrn->rgbBits = 8;
4341
4342#ifdef SISDUALHEAD
4343    if(pSiS->DualHeadMode) {
4344       if(!pSiS->SecondHead) {
4345	  /* Copy some option settings to entity private */
4346	  pSiSEnt->HWCursor = pSiS->HWCursor;
4347	  pSiSEnt->NoAccel = pSiS->NoAccel;
4348	  pSiSEnt->useEXA = pSiS->useEXA;
4349	  pSiSEnt->restorebyset = pSiS->restorebyset;
4350	  pSiSEnt->OptROMUsage = pSiS->OptROMUsage;
4351	  pSiSEnt->OptUseOEM = pSiS->OptUseOEM;
4352	  pSiSEnt->TurboQueue = pSiS->TurboQueue;
4353	  pSiSEnt->forceCRT1 = pSiS->forceCRT1;
4354	  pSiSEnt->ForceCRT1Type = pSiS->ForceCRT1Type;
4355	  pSiSEnt->CRT1TypeForced = pSiS->CRT1TypeForced;
4356	  pSiSEnt->ForceCRT2Type = pSiS->ForceCRT2Type;
4357	  pSiSEnt->ForceTVType = pSiS->ForceTVType;
4358	  pSiSEnt->ForceYPbPrType = pSiS->ForceYPbPrType;
4359	  pSiSEnt->ForceYPbPrAR = pSiS->ForceYPbPrAR;
4360	  pSiSEnt->UsePanelScaler = pSiS->UsePanelScaler;
4361	  pSiSEnt->CenterLCD = pSiS->CenterLCD;
4362	  pSiSEnt->DSTN = pSiS->DSTN;
4363	  pSiSEnt->FSTN = pSiS->FSTN;
4364	  pSiSEnt->OptTVStand = pSiS->OptTVStand;
4365	  pSiSEnt->NonDefaultPAL = pSiS->NonDefaultPAL;
4366	  pSiSEnt->NonDefaultNTSC = pSiS->NonDefaultNTSC;
4367	  pSiSEnt->chtvtype = pSiS->chtvtype;
4368	  pSiSEnt->OptTVOver = pSiS->OptTVOver;
4369	  pSiSEnt->OptTVSOver = pSiS->OptTVSOver;
4370	  pSiSEnt->chtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
4371	  pSiSEnt->chtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
4372	  pSiSEnt->chtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
4373	  pSiSEnt->chtvchromabandwidth = pSiS->chtvchromabandwidth;
4374	  pSiSEnt->chtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
4375	  pSiSEnt->chtvtextenhance = pSiS->chtvtextenhance;
4376	  pSiSEnt->chtvcontrast = pSiS->chtvcontrast;
4377	  pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
4378	  pSiSEnt->sistvedgeenhance = pSiS->sistvedgeenhance;
4379	  pSiSEnt->sistvantiflicker = pSiS->sistvantiflicker;
4380	  pSiSEnt->sistvsaturation = pSiS->sistvsaturation;
4381	  pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
4382	  pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
4383	  pSiSEnt->sistvcolcalibc = pSiS->sistvcolcalibc;
4384	  pSiSEnt->sistvcolcalibf = pSiS->sistvcolcalibf;
4385	  pSiSEnt->tvxpos = pSiS->tvxpos;
4386	  pSiSEnt->tvypos = pSiS->tvypos;
4387	  pSiSEnt->tvxscale = pSiS->tvxscale;
4388	  pSiSEnt->tvyscale = pSiS->tvyscale;
4389	  pSiSEnt->siscrt1satgain = pSiS->siscrt1satgain;
4390	  pSiSEnt->crt1satgaingiven = pSiS->crt1satgaingiven;
4391	  pSiSEnt->CRT1gamma = pSiS->CRT1gamma;
4392	  pSiSEnt->CRT1gammaGiven = pSiS->CRT1gammaGiven;
4393	  pSiSEnt->XvGammaRed = pSiS->XvGammaRed;
4394	  pSiSEnt->XvGammaGreen = pSiS->XvGammaGreen;
4395	  pSiSEnt->XvGammaBlue = pSiS->XvGammaBlue;
4396	  pSiSEnt->XvGamma = pSiS->XvGamma;
4397	  pSiSEnt->XvGammaGiven = pSiS->XvGammaGiven;
4398	  pSiSEnt->CRT2gamma = pSiS->CRT2gamma;
4399	  pSiSEnt->XvOnCRT2 = pSiS->XvOnCRT2;
4400	  pSiSEnt->AllowHotkey = pSiS->AllowHotkey;
4401	  pSiSEnt->enablesisctrl = pSiS->enablesisctrl;
4402	  pSiSEnt->SenseYPbPr = pSiS->SenseYPbPr;
4403	  pSiSEnt->XvUseMemcpy = pSiS->XvUseMemcpy;
4404	  pSiSEnt->BenchMemCpy = pSiS->BenchMemCpy;
4405#ifdef SIS_CP
4406	  SIS_CP_DRIVER_COPYOPTIONSENT
4407#endif
4408       } else {
4409	  /* We always use same cursor type on both screens */
4410	  pSiS->HWCursor = pSiSEnt->HWCursor;
4411	  /* We need identical NoAccel setting */
4412	  pSiS->NoAccel = pSiSEnt->NoAccel;
4413	  pSiS->useEXA = pSiSEnt->useEXA;
4414	  pSiS->TurboQueue = pSiSEnt->TurboQueue;
4415	  pSiS->restorebyset = pSiSEnt->restorebyset;
4416	  pSiS->AllowHotkey = pSiS->AllowHotkey;
4417	  pSiS->OptROMUsage = pSiSEnt->OptROMUsage;
4418	  pSiS->OptUseOEM = pSiSEnt->OptUseOEM;
4419	  pSiS->forceCRT1 = pSiSEnt->forceCRT1;
4420	  pSiS->nocrt2ddcdetection = FALSE;
4421	  pSiS->forcecrt2redetection = FALSE;
4422	  pSiS->ForceCRT1Type = pSiSEnt->ForceCRT1Type;
4423	  pSiS->ForceCRT2Type = pSiSEnt->ForceCRT2Type;
4424	  pSiS->CRT1TypeForced = pSiSEnt->CRT1TypeForced;
4425	  pSiS->UsePanelScaler = pSiSEnt->UsePanelScaler;
4426	  pSiS->CenterLCD = pSiSEnt->CenterLCD;
4427	  pSiS->DSTN = pSiSEnt->DSTN;
4428	  pSiS->FSTN = pSiSEnt->FSTN;
4429	  pSiS->OptTVStand = pSiSEnt->OptTVStand;
4430	  pSiS->NonDefaultPAL = pSiSEnt->NonDefaultPAL;
4431	  pSiS->NonDefaultNTSC = pSiSEnt->NonDefaultNTSC;
4432	  pSiS->chtvtype = pSiSEnt->chtvtype;
4433	  pSiS->ForceTVType = pSiSEnt->ForceTVType;
4434	  pSiS->ForceYPbPrType = pSiSEnt->ForceYPbPrType;
4435	  pSiS->ForceYPbPrAR = pSiSEnt->ForceYPbPrAR;
4436	  pSiS->OptTVOver = pSiSEnt->OptTVOver;
4437	  pSiS->OptTVSOver = pSiSEnt->OptTVSOver;
4438	  pSiS->chtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
4439	  pSiS->chtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
4440	  pSiS->chtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
4441	  pSiS->chtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
4442	  pSiS->chtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
4443	  pSiS->chtvcvbscolor = pSiSEnt->chtvcvbscolor;
4444	  pSiS->chtvtextenhance = pSiSEnt->chtvtextenhance;
4445	  pSiS->chtvcontrast = pSiSEnt->chtvcontrast;
4446	  pSiS->sistvedgeenhance = pSiSEnt->sistvedgeenhance;
4447	  pSiS->sistvantiflicker = pSiSEnt->sistvantiflicker;
4448	  pSiS->sistvsaturation = pSiSEnt->sistvsaturation;
4449	  pSiS->sistvcfilter = pSiSEnt->sistvcfilter;
4450	  pSiS->sistvyfilter = pSiSEnt->sistvyfilter;
4451	  pSiS->sistvcolcalibc = pSiSEnt->sistvcolcalibc;
4452	  pSiS->sistvcolcalibf = pSiSEnt->sistvcolcalibf;
4453	  pSiS->tvxpos = pSiSEnt->tvxpos;
4454	  pSiS->tvypos = pSiSEnt->tvypos;
4455	  pSiS->tvxscale = pSiSEnt->tvxscale;
4456	  pSiS->tvyscale = pSiSEnt->tvyscale;
4457	  pSiS->SenseYPbPr = pSiSEnt->SenseYPbPr;
4458	  if(!pSiS->CRT1gammaGiven) {
4459	     if(pSiSEnt->CRT1gammaGiven)
4460	        pSiS->CRT1gamma = pSiSEnt->CRT1gamma;
4461	  }
4462	  pSiS->CRT2gamma = pSiSEnt->CRT2gamma;
4463	  if(!pSiS->XvGammaGiven) {
4464	     if(pSiSEnt->XvGammaGiven) {
4465		pSiS->XvGamma = pSiSEnt->XvGamma;
4466		pSiS->XvGammaRed = pSiS->XvGammaRedDef = pSiSEnt->XvGammaRed;
4467		pSiS->XvGammaGreen = pSiS->XvGammaGreenDef = pSiSEnt->XvGammaGreen;
4468		pSiS->XvGammaBlue = pSiS->XvGammaBlueDef = pSiSEnt->XvGammaBlue;
4469	     }
4470	  }
4471	  if(!pSiS->crt1satgaingiven) {
4472	     if(pSiSEnt->crt1satgaingiven)
4473	        pSiS->siscrt1satgain = pSiSEnt->siscrt1satgain;
4474	  }
4475	  pSiS->XvOnCRT2 = pSiSEnt->XvOnCRT2;
4476	  pSiS->enablesisctrl = pSiSEnt->enablesisctrl;
4477	  pSiS->XvUseMemcpy = pSiSEnt->XvUseMemcpy;
4478	  pSiS->BenchMemCpy = pSiSEnt->BenchMemCpy;
4479	  /* Copy gamma brightness to Ent (sic!) for Xinerama */
4480	  pSiSEnt->GammaBriR = pSiS->GammaBriR;
4481	  pSiSEnt->GammaBriG = pSiS->GammaBriG;
4482	  pSiSEnt->GammaBriB = pSiS->GammaBriB;
4483	  pSiSEnt->NewGammaBriR = pSiS->NewGammaBriR;
4484	  pSiSEnt->NewGammaBriG = pSiS->NewGammaBriG;
4485	  pSiSEnt->NewGammaBriB = pSiS->NewGammaBriB;
4486	  pSiSEnt->NewGammaConR = pSiS->NewGammaConR;
4487	  pSiSEnt->NewGammaConG = pSiS->NewGammaConG;
4488	  pSiSEnt->NewGammaConB = pSiS->NewGammaConB;
4489#ifdef SIS_CP
4490	  SIS_CP_DRIVER_COPYOPTIONS
4491#endif
4492       }
4493    }
4494#endif
4495
4496    /* Handle UseROMData, NoOEM and UsePanelScaler options */
4497    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
4498       from = X_PROBED;
4499       if(pSiS->OptROMUsage == 0) {
4500	  pSiS->SiS_Pr->UseROM = FALSE;
4501	  from = X_CONFIG;
4502	  xf86DrvMsg(pScrn->scrnIndex, from, "Video ROM data usage is disabled\n");
4503       }
4504
4505       if(!pSiS->OptUseOEM) {
4506	  xf86DrvMsg(pScrn->scrnIndex, from, "Internal OEM LCD/TV/VGA2 data usage is disabled\n");
4507       }
4508
4509       pSiS->SiS_Pr->UsePanelScaler = pSiS->UsePanelScaler;
4510       pSiS->SiS_Pr->CenterScreen = pSiS->CenterLCD;
4511    }
4512
4513    /* Do some HW configuration detection (memory amount & type, clock, etc) */
4514    SiSSetup(pScrn);
4515
4516    /* Get framebuffer address */
4517    if(pSiS->pEnt->device->MemBase != 0) {
4518       /*
4519	* XXX Should check that the config file value matches one of the
4520	* PCI base address values.
4521	*/
4522       pSiS->FbAddress = pSiS->pEnt->device->MemBase;
4523       from = X_CONFIG;
4524    } else {
4525       pSiS->FbAddress = pSiS->PciInfo->memBase[0] & 0xFFFFFFF0;
4526       from = X_PROBED;
4527    }
4528
4529#ifdef SISDUALHEAD
4530    if(pSiS->DualHeadMode)
4531       xf86DrvMsg(pScrn->scrnIndex, from, "Global linear framebuffer at 0x%lX\n",
4532	   (ULong)pSiS->FbAddress);
4533    else
4534#endif
4535       xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
4536	   (ULong)pSiS->FbAddress);
4537
4538    pSiS->realFbAddress = pSiS->FbAddress;
4539
4540    /* Get MMIO address */
4541    if(pSiS->pEnt->device->IOBase != 0) {
4542       /*
4543	* XXX Should check that the config file value matches one of the
4544	* PCI base address values.
4545	*/
4546       pSiS->IOAddress = pSiS->pEnt->device->IOBase;
4547       from = X_CONFIG;
4548    } else {
4549       pSiS->IOAddress = pSiS->PciInfo->memBase[1] & 0xFFFFFFF0;
4550       from = X_PROBED;
4551    }
4552    xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at 0x%lX (size %ldK)\n",
4553	   (ULong)pSiS->IOAddress, pSiS->mmioSize);
4554
4555    /* Register the PCI-assigned resources */
4556    if(xf86RegisterResources(pSiS->pEnt->index, NULL, ResExclusive)) {
4557       SISErrorLog(pScrn, "PCI resource conflicts detected\n");
4558#ifdef SISDUALHEAD
4559       if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
4560#endif
4561       sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
4562       if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
4563       SISFreeRec(pScrn);
4564       return FALSE;
4565    }
4566
4567    from = X_PROBED;
4568    if(pSiS->pEnt->device->videoRam != 0) {
4569       if(pSiS->Chipset == PCI_CHIP_SIS6326) {
4570	  pScrn->videoRam = pSiS->pEnt->device->videoRam;
4571	  from = X_CONFIG;
4572       } else {
4573	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4574		"Option \"VideoRAM\" ignored\n");
4575       }
4576    }
4577
4578    pSiS->RealVideoRam = pScrn->videoRam;
4579
4580    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4581       (pScrn->videoRam > 4096)            &&
4582       (from != X_CONFIG)) {
4583       pScrn->videoRam = 4096;
4584       xf86DrvMsg(pScrn->scrnIndex, from,
4585	   "SiS6326: Detected %d KB VideoRAM, limiting to %d KB\n",
4586	   pSiS->RealVideoRam, pScrn->videoRam);
4587    } else {
4588       xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d KB\n", pScrn->videoRam);
4589    }
4590
4591    if((pSiS->Chipset == PCI_CHIP_SIS6326) &&
4592       (pScrn->videoRam > 4096)) {
4593       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4594	   "SiS6326 engines do not support more than 4096KB RAM, therefore\n");
4595       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4596	   "TurboQueue, HWCursor, 2D acceleration and XVideo are disabled.\n");
4597       pSiS->TurboQueue = FALSE;
4598       pSiS->HWCursor   = FALSE;
4599       pSiS->NoXvideo   = TRUE;
4600       pSiS->NoAccel    = TRUE;
4601    }
4602
4603    pSiS->FbMapSize = pSiS->availMem = pScrn->videoRam * 1024;
4604
4605    /* Calculate real availMem according to Accel/TurboQueue and
4606     * HWCursur setting. Also, initialize some variables used
4607     * in other modules.
4608     */
4609    pSiS->cursorOffset = 0;
4610    pSiS->CurARGBDest = NULL;
4611    pSiS->CurMonoSrc = NULL;
4612    pSiS->CurFGCol = pSiS->CurBGCol = 0;
4613    pSiS->FbBaseOffset = 0;
4614
4615    switch(pSiS->VGAEngine) {
4616
4617      case SIS_300_VGA:
4618	pSiS->TurboQueueLen = 512;
4619	if(pSiS->TurboQueue) {
4620	   pSiS->availMem -= (pSiS->TurboQueueLen*1024);
4621	   pSiS->cursorOffset = 512;
4622	}
4623	if(pSiS->HWCursor) {
4624	   pSiS->availMem -= pSiS->CursorSize;
4625	   if(pSiS->OptUseColorCursor) pSiS->availMem -= pSiS->CursorSize;
4626	}
4627	pSiS->CmdQueLenMask = 0xFFFF;
4628	pSiS->CmdQueLenFix  = 0;
4629	pSiS->cursorBufferNum = 0;
4630#ifdef SISDUALHEAD
4631	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4632#endif
4633	break;
4634
4635      case SIS_315_VGA:
4636#ifdef SISVRAMQ		/* VRAM queue */
4637	pSiS->cmdQueueSizeMask = pSiS->cmdQueueSize - 1;	/* VRAM Command Queue is variable (in therory) */
4638	pSiS->cmdQueueOffset = (pScrn->videoRam * 1024) - pSiS->cmdQueueSize;
4639	pSiS->cmdQueueLen = 0;
4640	pSiS->cmdQueueSize_div2 = pSiS->cmdQueueSize / 2;
4641	pSiS->cmdQueueSize_div4 = pSiS->cmdQueueSize / 4;
4642	pSiS->cmdQueueSize_4_3 = (pSiS->cmdQueueSize / 4) * 3;
4643	pSiS->availMem -= pSiS->cmdQueueSize;
4644	pSiS->cursorOffset = (pSiS->cmdQueueSize / 1024);
4645
4646	/* Set up shared pointer to current offset */
4647#ifdef SISDUALHEAD
4648	if(pSiS->DualHeadMode)
4649	   pSiS->cmdQ_SharedWritePort = &(pSiSEnt->cmdQ_SharedWritePort_2D);
4650	else
4651#endif
4652	   pSiS->cmdQ_SharedWritePort = &(pSiS->cmdQ_SharedWritePort_2D);
4653
4654
4655#else			/* MMIO */
4656	if(pSiS->TurboQueue) {
4657	   pSiS->availMem -= (512*1024);			/* MMIO Command Queue is 512k (variable in theory) */
4658	   pSiS->cursorOffset = 512;
4659	}
4660#endif
4661	if(pSiS->HWCursor) {
4662	   pSiS->availMem -= (pSiS->CursorSize * 2);
4663	   if(pSiS->OptUseColorCursor) pSiS->availMem -= (pSiS->CursorSize * 2);
4664	}
4665	pSiS->cursorBufferNum = 0;
4666#ifdef SISDUALHEAD
4667	if(pSiSEnt) pSiSEnt->cursorBufferNum = 0;
4668#endif
4669
4670	if((pSiS->SiS76xLFBSize) && (pSiS->SiS76xUMASize)) {
4671	   pSiS->availMem -= pSiS->SiS76xUMASize;
4672	   pSiS->FbBaseOffset = pSiS->SiS76xUMASize;
4673	}
4674
4675	break;
4676
4677      default:
4678	/* cursorOffset not used in cursor functions for 530 and
4679	 * older chips, because the cursor is *above* the TQ.
4680	 * On 5597 and older revisions of the 6326, the TQ is
4681	 * max 32K, on newer 6326 revisions and the 530 either 30
4682	 * (or 32?) or 62K (or 64?). However, to make sure, we
4683	 * use only 30K (or 32?), but reduce the available memory
4684	 * by 64, and locate the TQ at the beginning of this last
4685	 * 64K block. (We do this that way even when using the
4686	 * HWCursor, because the cursor only takes 2K and the
4687	 * queue does not seem to last that far anyway.)
4688	 * The TQ must be located at 32KB boundaries.
4689	 */
4690	if(pSiS->RealVideoRam < 3072) {
4691	   if(pSiS->TurboQueue) {
4692	      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4693		    "Not enough video RAM for TurboQueue. TurboQueue disabled\n");
4694	      pSiS->TurboQueue = FALSE;
4695	   }
4696	}
4697	pSiS->CmdQueMaxLen = 32;
4698	if(pSiS->TurboQueue) {
4699			      pSiS->availMem -= (64*1024);
4700			      pSiS->CmdQueMaxLen = 900;   /* To make sure; should be 992 */
4701	} else if(pSiS->HWCursor) {
4702			      pSiS->availMem -= pSiS->CursorSize;
4703	}
4704	if(pSiS->Chipset == PCI_CHIP_SIS530) {
4705		/* Check if Flat Panel is enabled */
4706		inSISIDXREG(SISSR, 0x0e, tempreg);
4707		if(!(tempreg & 0x04)) pSiS->availMem -= pSiS->CursorSize;
4708
4709		/* Set up mask for MMIO register */
4710		pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x1FFF : 0x00FF;
4711	} else {
4712	        /* TQ is never used on 6326/5597, because the accelerator
4713		 * always Syncs. So this is just cosmentic work. (And I
4714		 * am not even sure that 0x7fff is correct. MMIO 0x83a8
4715		 * holds 0xec0 if (30k) TQ is enabled, 0x20 if TQ disabled.
4716		 * The datasheet has no real explanation on the queue length
4717		 * if the TQ is enabled. Not syncing and waiting for a
4718		 * suitable queue length instead does not work.
4719		 */
4720	        pSiS->CmdQueLenMask = (pSiS->TurboQueue) ? 0x7FFF : 0x003F;
4721	}
4722
4723	/* This is to be subtracted from MMIO queue length register contents
4724	 * for getting the real Queue length.
4725	 */
4726	pSiS->CmdQueLenFix  = (pSiS->TurboQueue) ? 32 : 0;
4727    }
4728
4729
4730#ifdef SISDUALHEAD
4731    /* In dual head mode, we share availMem equally - so align it
4732     * to 8KB; this way, the address of the FB of the second
4733     * head is aligned to 4KB for mapping.
4734     */
4735   if(pSiS->DualHeadMode) pSiS->availMem &= 0xFFFFE000;
4736#endif
4737
4738    /* Check MaxXFBMem setting */
4739#ifdef SISDUALHEAD
4740    if(pSiS->DualHeadMode) {
4741        /* 1. Since DRI is not supported in dual head mode, we
4742	 *    don't need the MaxXFBMem setting - ignore it.
4743	 */
4744	if(pSiS->maxxfbmem) {
4745	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4746		"MaxXFBMem ignored in Dual Head mode\n");
4747	}
4748	pSiS->maxxfbmem = pSiS->availMem;
4749    } else
4750#endif
4751	   if((pSiS->sisfbHeapStart) || (pSiS->sisfbHaveNewHeapDef)) {
4752
4753       /*
4754	* 2. We have memory layout info from sisfb - ignore MaxXFBMem
4755	*/
4756	if(pSiS->maxxfbmem) {
4757	   xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4758		"Got memory layout info from sisfb, ignoring MaxXFBMem option\n");
4759	}
4760	if((pSiS->FbBaseOffset) && (!pSiS->sisfbHaveNewHeapDef)) {
4761	   xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4762		"Incompatible sisfb version detected, DRI disabled\n");
4763	   pSiS->loadDRI = FALSE;
4764	   pSiS->maxxfbmem = pSiS->availMem;
4765	} else {
4766	   if(pSiS->FbBaseOffset) {
4767	      /* Revert our changes to FbBaseOffset and availMem; use sisfb's info */
4768	      pSiS->availMem += pSiS->FbBaseOffset;
4769	      pSiS->FbBaseOffset = 0;
4770	   }
4771	   if(pSiS->sisfbVideoOffset) {
4772	      /* a. DRI heap BELOW framebuffer */
4773	      pSiS->FbBaseOffset = pSiS->sisfbVideoOffset;
4774	      pSiS->availMem -= pSiS->FbBaseOffset;
4775	      pSiS->maxxfbmem = pSiS->availMem;
4776	   } else {
4777	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4778	      if(pSiS->availMem < (pSiS->sisfbHeapStart * 1024)) {
4779		 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4780			"Internal error - sisfb memory layout corrupt\n");
4781		 pSiS->loadDRI = FALSE;
4782		 pSiS->maxxfbmem = pSiS->availMem;
4783	      } else {
4784	         pSiS->maxxfbmem = pSiS->sisfbHeapStart * 1024;
4785	      }
4786	   }
4787	}
4788
4789    } else if(pSiS->maxxfbmem) {
4790
4791       /*
4792	* 3. No sisfb, but user gave "MaxXFBMem"
4793	*/
4794	if(pSiS->FbBaseOffset) {
4795	   /* a. DRI heap BELOW framebuffer */
4796	   if(pSiS->maxxfbmem > (pSiS->availMem + pSiS->FbBaseOffset - pSiS->SiS76xUMASize)) {
4797	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4798			"Invalid MaxXFBMem setting\n");
4799	      pSiS->maxxfbmem = pSiS->availMem;
4800	   } else {
4801	      /* Revert our changes */
4802	      pSiS->availMem += pSiS->FbBaseOffset;
4803	      /* Use user's MaxXFBMem setting */
4804	      pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4805	      pSiS->availMem -= pSiS->FbBaseOffset;
4806	   }
4807	} else {
4808	   /* b. DRI heap ABOVE framebuffer (traditional layout) */
4809	   if(pSiS->maxxfbmem > pSiS->availMem) {
4810	      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4811			 "Invalid MaxXFBMem setting.\n");
4812	      pSiS->maxxfbmem = pSiS->availMem;
4813	   }
4814	}
4815
4816    } else {
4817
4818       /*
4819	* 4. No MaxXFBMem, no sisfb: Use all memory
4820	*/
4821	pSiS->maxxfbmem = pSiS->availMem;
4822
4823	/* ... except on chipsets, for which DRI is
4824	 * supported: If DRI is enabled, we now limit
4825	 * ourselves to a reasonable default:
4826	 */
4827
4828	if(pSiS->loadDRI) {
4829	   if(pSiS->FbBaseOffset) {
4830	      /* a. DRI heap BELOW framebuffer */
4831	      /* See how much UMA and LFB memory we have,
4832	       * and calculate a reasonable default. We
4833	       * use more vram for ourselves because these
4834	       * chips are eg. capable of larger Xv
4835	       * overlays, etc.
4836	       */
4837	      unsigned long total = (pSiS->SiS76xLFBSize + pSiS->SiS76xUMASize) / 1024;
4838	      unsigned long mymax;
4839	      if(total <= 16384)			/* <= 16MB: Use 8MB for X */
4840	         mymax = 8192 * 1024;
4841	      else if(total <= 32768)			/* <= 32MB: Use 16MB for X */
4842	         mymax = 16384 * 1024;
4843	      else					/* Otherwise: Use 20MB for X */
4844	         mymax = 20 * 1024 * 1024;
4845	      /* availMem is right now adjusted to not use the UMA
4846	       * area. Make sure that our default doesn't reach
4847	       * into the UMA area either.
4848	       */
4849	      if(pSiS->availMem > mymax) {
4850		 /* Write our default to maxxfbmem */
4851		 pSiS->maxxfbmem = mymax;
4852		 /* Revert our changes to availMem */
4853		 pSiS->availMem += pSiS->FbBaseOffset;
4854		 /* Use our default setting */
4855		 pSiS->FbBaseOffset = pSiS->availMem - pSiS->maxxfbmem;
4856		 pSiS->availMem -= pSiS->FbBaseOffset;
4857	      }
4858	   } else {
4859	      /* b. DRI heap ABOVE framebuffer (traditional layout) */
4860	      /* See how much video memory we have, and calculate
4861	       * a reasonable default.
4862	       * Since DRI is pointless with less than 4MB of total
4863	       * video RAM, we disable it in that case.
4864	       */
4865	      if(pScrn->videoRam <= 4096)
4866	         pSiS->loadDRI = FALSE;
4867	      else if(pScrn->videoRam <= 8192)		/* <= 8MB: Use 4MB for X */
4868	         pSiS->maxxfbmem = 4096 * 1024;
4869	      else if(pScrn->videoRam <= 16384)		/* <= 16MB: Use 8MB for X */
4870	         pSiS->maxxfbmem = 8192 * 1024;
4871#ifdef SISMERGED					/* Otherwise: --- */
4872	      else if(pSiS->MergedFB) {
4873	         if(pScrn->videoRam <= 65536)
4874	            pSiS->maxxfbmem = 16384 * 1024;	/* If MergedFB and <=64MB, use 16MB for X */
4875		 else
4876		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* If MergedFB and > 64MB, use 20MB for X */
4877	      }
4878#endif
4879	        else if(pSiS->VGAEngine == SIS_315_VGA) {
4880	         if(pScrn->videoRam <= 65536)
4881	            pSiS->maxxfbmem = 16384 * 1024;	/* On >=315 series and <=64MB, use 16MB */
4882		 else
4883		    pSiS->maxxfbmem = 20 * 1024 * 1024;	/* On >=315 series and > 64MB, use 20MB */
4884	      } else
4885	         pSiS->maxxfbmem = 12288 * 1024;	/* On <315 series, use 12MB */
4886
4887	      /* A final check */
4888	      if(pSiS->maxxfbmem > pSiS->availMem) {
4889		 pSiS->maxxfbmem = pSiS->availMem;
4890		 pSiS->loadDRI = FALSE;
4891	      }
4892	   }
4893
4894	}
4895    }
4896
4897    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %dK of framebuffer memory at offset %dK\n",
4898				pSiS->maxxfbmem / 1024, pSiS->FbBaseOffset / 1024);
4899
4900    /* Find out about sub-classes of some chipsets and check
4901     * if the chipset supports two video overlays
4902     */
4903    if(pSiS->VGAEngine == SIS_300_VGA    ||
4904       pSiS->VGAEngine == SIS_315_VGA    ||
4905       pSiS->Chipset == PCI_CHIP_SIS530  ||
4906       pSiS->Chipset == PCI_CHIP_SIS6326 ||
4907       pSiS->Chipset == PCI_CHIP_SIS5597)  {
4908       pSiS->hasTwoOverlays = FALSE;
4909       switch(pSiS->Chipset) {
4910	 case PCI_CHIP_SIS300:
4911	 case PCI_CHIP_SIS540:  /* ? (If not, need to add the SwitchCRT Xv attribute!) */
4912	 case PCI_CHIP_SIS630:
4913	 case PCI_CHIP_SIS550:
4914	   pSiS->hasTwoOverlays = TRUE;
4915	   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4916	   break;
4917	 case PCI_CHIP_SIS315PRO:
4918	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4919	   break;
4920	 case PCI_CHIP_SIS330:
4921	   pSiS->ChipFlags |= (SiSCF_CRT2HWCKaputt | SiSCF_LARGEOVERLAY);
4922	   break;
4923	 case PCI_CHIP_SIS340:
4924	 case PCI_CHIP_XGIXG40: /* Verified: only 1 overlay */
4925	   pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4926	   break;
4927	 case PCI_CHIP_SIS650:
4928	   {
4929	     UChar tempreg1, tempreg2;
4930	     static const char *id650str[] = {
4931		"650",       "650",       "650",       "650",
4932		"650 A0 AA", "650 A2 CA", "650",       "650",
4933		"M650 A0",   "M650 A1 AA","651 A0 AA", "651 A1 AA",
4934		"M650",      "65?",       "651",       "65?"
4935	     };
4936	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
4937	     if(pSiS->ChipType == SIS_650) {
4938		inSISIDXREG(SISCR, 0x5f, CR5F);
4939		CR5F &= 0xf0;
4940		andSISIDXREG(SISCR, 0x5c, 0x07);
4941		inSISIDXREG(SISCR, 0x5c, tempreg1);
4942		tempreg1 &= 0xf8;
4943		orSISIDXREG(SISCR, 0x5c, 0xf8);
4944		inSISIDXREG(SISCR, 0x5c, tempreg2);
4945		tempreg2 &= 0xf8;
4946		if((!tempreg1) || (tempreg2)) {
4947		   xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4948		      "SiS650 revision ID %x (%s)\n", CR5F, id650str[CR5F >> 4]);
4949		   if(CR5F & 0x80) {
4950		      pSiS->hasTwoOverlays = TRUE;  /* M650 or 651 */
4951		      pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4952		   }
4953		   switch(CR5F) {
4954		      case 0xa0:
4955		      case 0xb0:
4956		      case 0xe0:
4957		         pSiS->ChipFlags |= SiSCF_Is651;
4958		         break;
4959		      case 0x80:
4960		      case 0x90:
4961		      case 0xc0:
4962		         pSiS->ChipFlags |= SiSCF_IsM650;
4963		         break;
4964		   }
4965		} else {
4966		   pSiS->hasTwoOverlays = TRUE;
4967		   pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
4968		   switch(CR5F) {
4969		      case 0x90:
4970			 inSISIDXREG(SISCR, 0x5c, tempreg1);
4971			 tempreg1 &= 0xf8;
4972			 switch(tempreg1) {
4973			    case 0x00:
4974			       pSiS->ChipFlags |= SiSCF_IsM652;
4975			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4976			           "SiSM652 revision ID %x\n", CR5F);
4977			       break;
4978			    case 0x40:
4979			       pSiS->ChipFlags |= SiSCF_IsM653;
4980			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4981			           "SiSM653 revision ID %x\n", CR5F);
4982			       break;
4983			    default:
4984			       pSiS->ChipFlags |= SiSCF_IsM650;
4985			       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4986			           "SiSM650 revision ID %x\n", CR5F);
4987			       break;
4988			 }
4989			 break;
4990		      case 0xb0:
4991			 pSiS->ChipFlags |= SiSCF_Is652;
4992			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4993			     "SiS652 revision ID %x\n", CR5F);
4994			 break;
4995		      default:
4996			 pSiS->ChipFlags |= SiSCF_IsM650;
4997			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
4998			     "SiSM650 revision ID %x\n", CR5F);
4999			 break;
5000		   }
5001		}
5002	     }
5003	     break;
5004	   }
5005	 case PCI_CHIP_SIS660:
5006	   {
5007	     pSiS->ChipFlags |= SiSCF_LARGEOVERLAY;
5008	     pSiS->hasTwoOverlays = TRUE;
5009	     pSiS->SiS_SD_Flags |= SiS_SD_SUPPORT2OVL;
5010	     /* 760/761:  - UMA only: one/two overlays - dotclock dependent
5011			  - UMA+LFB:  two overlays if video data in LFB
5012			  - LFB only: two overlays
5013		If UMA only: Must switch between one/two overlays on the fly (done
5014			     in PostSetMode())
5015		If LFB+UMA:  We use LFB memory only and leave UMA to an eventually
5016			     written DRI driver.
5017	      */
5018	     break;
5019	   }
5020       }
5021
5022       if(!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY)) {
5023          xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5024		"Hardware supports %s video overlay%s\n",
5025		pSiS->hasTwoOverlays ? "two" : "one",
5026		pSiS->hasTwoOverlays ? "s" : "");
5027       }
5028
5029       if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {
5030	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5031		"\n\tDear SiS76x user, your machine is using a shared memory framebuffer.\n"
5032		  "\tDue to hardware limitations of the SiS chip in combination with the\n"
5033		  "\tAMD CPU, video overlay support is very limited on this machine. If you\n"
5034		  "\texperience flashing lines in the video and/or the graphics display\n"
5035		  "\tduring video playback, reduce the color depth and/or the resolution\n"
5036		  "\tand/or the refresh rate. Alternatively, use the video blitter.\n");
5037       }
5038
5039    }
5040
5041    /* Backup VB connection and CRT1 on/off register */
5042    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5043       inSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
5044       inSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
5045       inSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
5046       inSISIDXREG(SISCR, 0x36, pSiS->oldCR36);
5047       inSISIDXREG(SISCR, 0x37, pSiS->oldCR37);
5048       if(pSiS->VGAEngine == SIS_315_VGA) {
5049          inSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
5050       }
5051
5052       pSiS->postVBCR32 = pSiS->oldCR32;
5053    }
5054
5055    /* There are some machines out there which require a special
5056     * setup of the GPIO registers in order to make the Chrontel
5057     * work. Try to find out if we're running on such a machine.
5058     * Furthermore, there is some highly customized hardware,
5059     * which requires some non-standard LVDS timing. Since the
5060     * vendors don't seem to care about PCI subsystem ID's we
5061     * need to find out using the BIOS version and date strings.
5062     */
5063    pSiS->SiS_Pr->SiS_ChSW = FALSE;
5064    if(pSiS->Chipset == PCI_CHIP_SIS630) {
5065       int i = 0;
5066       do {
5067	  if(mychswtable[i].subsysVendor == pSiS->PciInfo->subsysVendor &&
5068	     mychswtable[i].subsysCard == pSiS->PciInfo->subsysCard) {
5069	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5070	         "PCI subsystem ID found in list for Chrontel/GPIO setup:\n");
5071	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5072		 "\tVendor/Card: %s %s (ID %04x)\n",
5073		  mychswtable[i].vendorName,
5074		  mychswtable[i].cardName,
5075		  pSiS->PciInfo->subsysCard);
5076	     pSiS->SiS_Pr->SiS_ChSW = TRUE;
5077	     break;
5078          }
5079          i++;
5080       } while(mychswtable[i].subsysVendor != 0);
5081    }
5082
5083    if(pSiS->SiS_Pr->SiS_CustomT == CUT_NONE) {
5084       int    i = 0, j;
5085       UShort bversptr = 0;
5086       Bool   footprint;
5087       CARD32 chksum = 0;
5088
5089       if(pSiS->SiS_Pr->UseROM) {
5090          bversptr = pSiS->BIOS[0x16] | (pSiS->BIOS[0x17] << 8);
5091          for(i=0; i<32768; i++) chksum += pSiS->BIOS[i];
5092       }
5093
5094       i = 0;
5095       do {
5096	  if( (SiS_customttable[i].chipID == pSiS->ChipType)                            &&
5097	      ((!strlen(SiS_customttable[i].biosversion)) ||
5098	       (pSiS->SiS_Pr->UseROM &&
5099	       (!strncmp(SiS_customttable[i].biosversion, (char *)&pSiS->BIOS[bversptr],
5100	                strlen(SiS_customttable[i].biosversion)))))                     &&
5101	      ((!strlen(SiS_customttable[i].biosdate)) ||
5102	       (pSiS->SiS_Pr->UseROM &&
5103	       (!strncmp(SiS_customttable[i].biosdate, (char *)&pSiS->BIOS[0x2c],
5104	                strlen(SiS_customttable[i].biosdate)))))			      &&
5105	      ((!SiS_customttable[i].bioschksum) ||
5106	       (pSiS->SiS_Pr->UseROM &&
5107	       (SiS_customttable[i].bioschksum == chksum)))			      &&
5108	      (SiS_customttable[i].pcisubsysvendor == pSiS->PciInfo->subsysVendor)      &&
5109	      (SiS_customttable[i].pcisubsyscard == pSiS->PciInfo->subsysCard) ) {
5110	     footprint = TRUE;
5111	     for(j=0; j<5; j++) {
5112	        if(SiS_customttable[i].biosFootprintAddr[j]) {
5113		   if(pSiS->SiS_Pr->UseROM) {
5114		      if(pSiS->BIOS[SiS_customttable[i].biosFootprintAddr[j]] !=
5115						SiS_customttable[i].biosFootprintData[j])
5116		         footprint = FALSE;
5117		   } else footprint = FALSE;
5118	        }
5119	     }
5120	     if(footprint) {
5121	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5122	           "Identified %s %s, special timing applies\n",
5123		   SiS_customttable[i].vendorName, SiS_customttable[i].cardName);
5124	        pSiS->SiS_Pr->SiS_CustomT = SiS_customttable[i].SpecialID;
5125	        break;
5126	     }
5127          }
5128          i++;
5129       } while(SiS_customttable[i].chipID);
5130    }
5131
5132    /* Handle ForceCRT1 option */
5133    if(pSiS->forceCRT1 != -1) {
5134       if(pSiS->forceCRT1) pSiS->CRT1off = 0;
5135       else                pSiS->CRT1off = 1;
5136    } else                 pSiS->CRT1off = -1;
5137
5138    /* Detect video bridge and sense TV/VGA2 */
5139    SISVGAPreInit(pScrn);
5140
5141    /* Detect CRT1 (via DDC1 and DDC2, hence via VGA port; regardless of LCDA) */
5142    SISCRT1PreInit(pScrn);
5143
5144    /* Detect LCD (connected via CRT2, regardless of LCDA) and LCD resolution */
5145    SISLCDPreInit(pScrn, FALSE);
5146
5147    /* LCDA only supported under these conditions: */
5148    if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5149       if(!SISDetermineLCDACap(pScrn)) {
5150	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5151		"Chipset/Video bridge does not support LCD-via-CRT1\n");
5152	  pSiS->ForceCRT1Type = CRT1_VGA;
5153       } else if(!(pSiS->VBFlags & CRT2_LCD)) {
5154	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5155		"No digital LCD panel found, LCD-via-CRT1 disabled\n");
5156	  pSiS->ForceCRT1Type = CRT1_VGA;
5157       }
5158    }
5159
5160    /* Setup SD flags */
5161    pSiS->SiS_SD_Flags |= SiS_SD_ADDLSUPFLAG;
5162
5163    pSiS->SiS_SD2_Flags |= SiS_SD2_MERGEDUCLOCK;
5164    pSiS->SiS_SD2_Flags |= SiS_SD2_USEVBFLAGS2;
5165    pSiS->SiS_SD2_Flags |= SiS_SD2_VBINVB2ONLY;
5166    pSiS->SiS_SD2_Flags |= SiS_SD2_HAVESD34;
5167    pSiS->SiS_SD2_Flags |= SiS_SD2_NEWGAMMABRICON;
5168
5169    pSiS->SiS_SD3_Flags |= SiS_SD3_MFBALLOWOFFCL;
5170
5171    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5172       pSiS->SiS_SD2_Flags |= SiS_SD2_VIDEOBRIDGE;
5173       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5174	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_SISBRIDGE     |
5175				   SiS_SD2_SUPPORTGAMMA2 );
5176	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5177	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDLVDS    |
5178				      SiS_SD2_SUPPORTLCD );
5179	  } else if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
5180	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
5181		pSiS->SiS_SD2_Flags |= ( SiS_SD2_LCDTMDS    |
5182					 SiS_SD2_SUPPORTLCD );
5183	     } else if(pSiS->VBFlags & CRT2_LCD) {
5184		pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5185				         SiS_SD2_SUPPORTLCD );
5186	     }
5187	  }
5188       } else if(pSiS->VBFlags2 & VB2_LVDS) {
5189	  pSiS->SiS_SD2_Flags |= ( SiS_SD2_THIRDPARTYLVDS |
5190				   SiS_SD2_SUPPORTLCD );
5191       }
5192
5193       if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5194	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTV;
5195	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5196	     pSiS->SiS_SD2_Flags |= ( SiS_SD2_SUPPORTTVTYPE |
5197				      SiS_SD2_SUPPORTTVSIZE );
5198	     if(!(pSiS->VBFlags2 & VB2_301)) {
5199		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVSAT;
5200	     } else {
5201		pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPTVEDGE;
5202	     }
5203	  }
5204       }
5205    }
5206
5207#ifdef ENABLE_YPBPR
5208    if((pSiS->VGAEngine == SIS_315_VGA) &&
5209       (pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE)) {
5210       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPR;
5211       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625I;
5212       pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPORT625P;
5213       if(pSiS->VBFlags2 & VB2_SISYPBPRARBRIDGE) {
5214          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5215       }
5216    }
5217    if(pSiS->VBFlags2 & VB2_SISHIVISIONBRIDGE) {
5218       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTHIVISION;
5219    }
5220#endif
5221
5222    if((pSiS->VGAEngine != SIS_300_VGA) || (!(pSiS->VBFlags2 & VB2_TRUMPION))) {
5223       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSCALE;
5224       if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) &&
5225          (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5226          pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTCENTER;
5227       }
5228    }
5229
5230#ifdef SISDUALHEAD
5231    if(!pSiS->DualHeadMode) {
5232       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTREDETECT;
5233    }
5234#endif
5235
5236#ifndef SISCHECKOSSSE
5237    pSiS->SiS_SD2_Flags |= SiS_SD2_NEEDUSESSE;
5238#endif
5239
5240#ifdef TWDEBUG	/* FOR TESTING */
5241    pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTYPBPRAR;
5242    xf86DrvMsg(0, X_INFO, "TEST: Support Aspect Ratio\n");
5243#endif
5244
5245    /* Detect CRT2-TV and PAL/NTSC mode */
5246    SISTVPreInit(pScrn, FALSE);
5247
5248    /* Detect CRT2-VGA */
5249    SISCRT2PreInit(pScrn, FALSE);
5250
5251    /* Backup detected CRT2 devices */
5252    SISSaveDetectedDevices(pScrn);
5253
5254    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR)) {
5255       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_YPBPR)) {
5256	  pSiS->ForceTVType = -1;
5257	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "YPbPr TV output not supported\n");
5258       }
5259    }
5260
5261    if(!(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTHIVISION)) {
5262       if((pSiS->ForceTVType != -1) && (pSiS->ForceTVType & TV_HIVISION)) {
5263	  pSiS->ForceTVType = -1;
5264	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HiVision TV output not supported\n");
5265       }
5266    }
5267
5268    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5269       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x))) {
5270       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5271    }
5272    if((pSiS->VBFlags2 & VB2_SISTVBRIDGE) ||
5273       ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_700x))) {
5274       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTTVPOS;
5275    }
5276    if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5277       pSiS->SiS_SD_Flags |= (SiS_SD_SUPPORTSCART | SiS_SD_SUPPORTVGA2);
5278    }
5279    if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5280       pSiS->SiS_SD_Flags  |= SiS_SD_SUPPORTOVERSCAN;
5281       pSiS->SiS_SD2_Flags |= SiS_SD2_CHRONTEL;
5282       if(pSiS->ChrontelType == CHRONTEL_700x) {
5283	  pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTSOVER;
5284       }
5285    }
5286
5287    /* Determine if chipset LCDA-capable */
5288    pSiS->SiS_SD_Flags &= ~SiS_SD_SUPPORTLCDA;
5289    if(SISDetermineLCDACap(pScrn)) {
5290       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTLCDA;
5291    }
5292
5293    /* Default to LCDA if LCD detected and
5294     * - TV detected (hence default to LCDA+TV), or
5295     * - in single head mode, on LCD panels with xres > 1600
5296     *   (Don't do this in MergedFB or DHM; LCDA and CRT1/VGA
5297     *   are mutually exclusive; if no TV is detected, the
5298     *   code below will default to VGA+LCD, so LCD is driven
5299     *   via CRT2.)
5300     *   (TODO: This might need some modification for the
5301     *   307 bridges, if these are capable of driving
5302     *   LCDs > 1600 via channel B)
5303     */
5304    if((pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) &&
5305       (pSiS->VBFlags & CRT2_LCD) &&
5306       (pSiS->SiS_Pr->SiS_CustomT != CUT_UNKNOWNLCD)) {
5307       if((!pSiS->CRT1TypeForced) && (pSiS->ForceCRT2Type == CRT2_DEFAULT)) {
5308	  if(pSiS->VBFlags & CRT2_TV) {
5309	     /* If both LCD and TV present, default to LCDA+TV */
5310	     pSiS->ForceCRT1Type = CRT1_LCDA;
5311	     pSiS->ForceCRT2Type = CRT2_TV;
5312	  } else if(pSiS->LCDwidth > 1600) {
5313	     /* If LCD is > 1600, default to LCDA if we don't need CRT1/VGA for other head */
5314	     Bool NeedCRT1VGA = FALSE;
5315#ifdef SISDUALHEAD
5316	     if(pSiS->DualHeadMode) NeedCRT1VGA = TRUE;
5317#endif
5318#ifdef SISMERGED
5319	     if(pSiS->MergedFB &&
5320		(!pSiS->MergedFBAuto || pSiS->CRT1Detected)) NeedCRT1VGA = TRUE;
5321#endif
5322	     if(!NeedCRT1VGA) {
5323		pSiS->ForceCRT1Type = CRT1_LCDA;
5324	     }
5325	  }
5326       }
5327    }
5328
5329    /* Set up pseudo-panel if LCDA forced on TMDS bridges */
5330    if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTLCDA) {
5331       if(pSiS->ForceCRT1Type == CRT1_LCDA) {
5332          if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
5333	     if(!(pSiS->VBLCDFlags)) {
5334		SiSSetupPseudoPanel(pScrn);
5335		pSiS->detectedCRT2Devices |= CRT2_LCD;
5336	     }
5337	  } else if(!(pSiS->VBLCDFlags)) {
5338	     pSiS->ForceCRT1Type = CRT1_VGA;
5339	  }
5340       }
5341    } else {
5342       pSiS->ForceCRT1Type = CRT1_VGA;
5343    }
5344
5345    pSiS->VBFlags |= pSiS->ForceCRT1Type;
5346
5347#ifdef TWDEBUG
5348    xf86DrvMsg(0, X_INFO, "SDFlags %lx\n", pSiS->SiS_SD_Flags);
5349#endif
5350
5351    /* Eventually overrule detected CRT2 type
5352     * If no type forced, use the detected devices in the order TV->LCD->VGA2
5353     * Since the Chrontel 7005 sometimes delivers wrong detection results,
5354     * we use a different order on such machines (LCD->TV)
5355     */
5356    if(pSiS->ForceCRT2Type == CRT2_DEFAULT) {
5357       if((pSiS->VBFlags & CRT2_TV) && (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VGAEngine == SIS_300_VGA))))
5358	  pSiS->ForceCRT2Type = CRT2_TV;
5359       else if((pSiS->VBFlags & CRT2_LCD) && (pSiS->ForceCRT1Type == CRT1_VGA))
5360	  pSiS->ForceCRT2Type = CRT2_LCD;
5361       else if(pSiS->VBFlags & CRT2_TV)
5362	  pSiS->ForceCRT2Type = CRT2_TV;
5363       else if((pSiS->VBFlags & CRT2_VGA) && (pSiS->ForceCRT1Type == CRT1_VGA))
5364	  pSiS->ForceCRT2Type = CRT2_VGA;
5365    }
5366
5367    switch(pSiS->ForceCRT2Type) {
5368       case CRT2_TV:
5369	  pSiS->VBFlags &= ~(CRT2_LCD | CRT2_VGA);
5370	  if(pSiS->VBFlags2 & (VB2_SISTVBRIDGE | VB2_CHRONTEL)) {
5371	     pSiS->VBFlags |= CRT2_TV;
5372	  } else {
5373	     pSiS->VBFlags &= ~(CRT2_TV);
5374	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5375		"Hardware does not support TV output\n");
5376	  }
5377	  break;
5378       case CRT2_LCD:
5379	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_VGA);
5380	  if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (pSiS->VBLCDFlags)) {
5381	     pSiS->VBFlags |= CRT2_LCD;
5382	  } else if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
5383	     SiSSetupPseudoPanel(pScrn);
5384	     pSiS->detectedCRT2Devices |= CRT2_LCD;
5385	  } else {
5386	     pSiS->VBFlags &= ~(CRT2_LCD);
5387	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5388		"Can't force CRT2 to LCD, no LCD detected\n");
5389	  }
5390	  break;
5391       case CRT2_VGA:
5392	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD);
5393	  if(pSiS->VBFlags2 & VB2_SISVGA2BRIDGE) {
5394	     pSiS->VBFlags |= CRT2_VGA;
5395	  } else {
5396	     pSiS->VBFlags &= ~(CRT2_VGA);
5397	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5398		 "Hardware does not support secondary VGA\n");
5399	  }
5400	  break;
5401       default:
5402	  pSiS->VBFlags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
5403    }
5404
5405    /* Setup gamma (the cmap layer needs this to be initialised) */
5406    /* (Do this after evaluating options) */
5407    {
5408       Gamma zeros = {0.0, 0.0, 0.0};
5409       xf86SetGamma(pScrn, zeros);
5410    }
5411
5412#ifdef SISDUALHEAD
5413    if((!pSiS->DualHeadMode) || (pSiS->SecondHead)) {
5414#endif
5415       xf86DrvMsg(pScrn->scrnIndex, pSiS->CRT1gammaGiven ? X_CONFIG : X_INFO,
5416	     "%samma correction is %s\n",
5417	     (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G",
5418	     pSiS->CRT1gamma ? "enabled" : "disabled");
5419
5420       if((pSiS->VGAEngine == SIS_315_VGA)	&&
5421          (!(pSiS->NoXvideo))			&&
5422	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5423	  xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5424		"Separate Xv gamma correction %sis %s\n",
5425		(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "for CRT1 " : "",
5426		pSiS->XvGamma ? "enabled" : "disabled");
5427	  if(pSiS->XvGamma) {
5428	     xf86DrvMsg(pScrn->scrnIndex, pSiS->XvGammaGiven ? X_CONFIG : X_INFO,
5429		"Xv gamma correction: %.3f %.3f %.3f\n",
5430		(float)((float)pSiS->XvGammaRed / 1000),
5431		(float)((float)pSiS->XvGammaGreen / 1000),
5432		(float)((float)pSiS->XvGammaBlue / 1000));
5433	     if(!pSiS->CRT1gamma) {
5434		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5435		   "Xv gamma correction requires %samma correction enabled\n",
5436		   (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) ? "CRT1 g" : "G");
5437	     }
5438	  }
5439       }
5440#ifdef SISDUALHEAD
5441    }
5442#endif
5443
5444#ifdef SISDUALHEAD
5445    if(pSiS->DualHeadMode) pSiS->CRT2SepGamma = FALSE;
5446#endif
5447
5448#ifdef SISDUALHEAD
5449    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
5450#endif
5451    {
5452       Bool isDH = FALSE;
5453       if(pSiS->CRT2gamma) {
5454          if( ((pSiS->VGAEngine != SIS_300_VGA) && (pSiS->VGAEngine != SIS_315_VGA)) ||
5455              (!(pSiS->VBFlags2 & VB2_SISBRIDGE)) ) {
5456	     if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5457	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5458			"CRT2 gamma correction not supported by hardware\n");
5459	     }
5460	     pSiS->CRT2gamma = pSiS->CRT2SepGamma = FALSE;
5461          } else if((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) {
5462	     isDH = TRUE;
5463	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5464			"CRT2 gamma correction not supported for LCD\n");
5465	     /* But leave it on, will be caught in LoadPalette */
5466          }
5467       }
5468       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
5469	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT2 gamma correction is %s%s%s\n",
5470		pSiS->CRT2gamma ? "enabled" : "disabled",
5471		isDH ? " (for TV and VGA2) " : "",
5472		pSiS->CRT2SepGamma ? " (separate from CRT1)" : "");
5473       }
5474    }
5475
5476    /* Eventually overrule TV Type (SVIDEO, COMPOSITE, SCART, HIVISION, YPBPR) */
5477    if(pSiS->VBFlags2 & VB2_SISTVBRIDGE) {
5478       if(pSiS->ForceTVType != -1) {
5479	  pSiS->VBFlags &= ~(TV_INTERFACE);
5480	  if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) {
5481	     pSiS->VBFlags &= ~(TV_CHSCART | TV_CHYPBPR525I);
5482	  }
5483	  pSiS->VBFlags |= pSiS->ForceTVType;
5484	  if(pSiS->VBFlags & TV_YPBPR) {
5485	     pSiS->VBFlags &= ~(TV_STANDARD);
5486	     pSiS->VBFlags &= ~(TV_YPBPRAR);
5487	     pSiS->VBFlags |= pSiS->ForceYPbPrType;
5488	     pSiS->VBFlags |= pSiS->ForceYPbPrAR;
5489	  }
5490       }
5491    }
5492
5493    /* Handle ForceCRT1 option (part 2) */
5494    pSiS->CRT1changed = FALSE;
5495    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5496       usScratchCR17 = pSiS->oldCR17;
5497       usScratchCR63 = pSiS->oldCR63;
5498       usScratchSR1F = pSiS->oldSR1F;
5499       usScratchCR32 = pSiS->postVBCR32;
5500       if(pSiS->VESA != 1) {
5501          /* Copy forceCRT1 option to CRT1off if option is given */
5502#ifdef SISDUALHEAD
5503          /* In DHM, handle this option only for master head, not the slave */
5504          if( (pSiS->forceCRT1 != -1) &&
5505	       (!(pSiS->DualHeadMode && pSiS->SecondHead)) ) {
5506#else
5507          if(pSiS->forceCRT1 != -1) {
5508#endif
5509	     xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5510		 "CRT1 detection overruled by ForceCRT1 option\n");
5511	     if(pSiS->forceCRT1) {
5512		 pSiS->CRT1off = 0;
5513		 if(pSiS->VGAEngine == SIS_300_VGA) {
5514		    if(!(usScratchCR17 & 0x80)) pSiS->CRT1changed = TRUE;
5515		 } else {
5516		    if(usScratchCR63 & 0x40) pSiS->CRT1changed = TRUE;
5517		 }
5518		 usScratchCR17 |= 0x80;
5519		 usScratchCR32 |= 0x20;
5520		 usScratchCR63 &= ~0x40;
5521		 usScratchSR1F &= ~0xc0;
5522	     } else {
5523		 if( ! ( (pScrn->bitsPerPixel == 8) &&
5524		         ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5525		           ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5526		    pSiS->CRT1off = 1;
5527		    if(pSiS->VGAEngine == SIS_300_VGA) {
5528		       if(usScratchCR17 & 0x80) pSiS->CRT1changed = TRUE;
5529		    } else {
5530		       if(!(usScratchCR63 & 0x40)) pSiS->CRT1changed = TRUE;
5531		    }
5532		    usScratchCR32 &= ~0x20;
5533		    /* We must not actually switch off CRT1 before we changed the mode! */
5534		 }
5535	     }
5536	     /* Here we can write to CR17 even on 315 series as we only ENABLE
5537	      * the bit here
5538	      */
5539	     outSISIDXREG(SISCR, 0x17, usScratchCR17);
5540	     if(pSiS->VGAEngine == SIS_315_VGA) {
5541		outSISIDXREG(SISCR, pSiS->myCR63, usScratchCR63);
5542	     }
5543	     outSISIDXREG(SISCR, 0x32, usScratchCR32);
5544	     if(pSiS->CRT1changed) {
5545		outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
5546		usleep(10000);
5547		outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
5548		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5549			"CRT1 status changed by ForceCRT1 option\n");
5550	     }
5551	     outSISIDXREG(SISSR, 0x1f, usScratchSR1F);
5552          }
5553       }
5554       /* Store the new VB connection register contents for later mode changes */
5555       pSiS->newCR32 = usScratchCR32;
5556    }
5557
5558    /* Check if CRT1 used (or needed; this eg. if no CRT2 detected) */
5559    if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
5560
5561        /* No CRT2 output? Then we NEED CRT1!
5562	 * We also need CRT1 if depth = 8 and bridge=LVDS|301B-DH
5563	 */
5564	if( (!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) ||
5565	    ( (pScrn->bitsPerPixel == 8) &&
5566	      ( (pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) ||
5567	        ((pSiS->VBFlags2 & VB2_30xBDH) && (pSiS->VBFlags & CRT2_LCD)) ) ) ) {
5568	    pSiS->CRT1off = 0;
5569	}
5570	/* No CRT2 output? Then we can't use Xv on CRT2 */
5571	if(!(pSiS->VBFlags & (CRT2_VGA | CRT2_LCD | CRT2_TV))) {
5572	    pSiS->XvOnCRT2 = FALSE;
5573	}
5574
5575    } else { /* no video bridge? */
5576	/* Then we NEED CRT1... */
5577	pSiS->CRT1off = 0;
5578	/* ... and can't use CRT2 for Xv output */
5579	pSiS->XvOnCRT2 = FALSE;
5580    }
5581
5582    /* LCDA? Then we don't switch off CRT1 */
5583    if(pSiS->VBFlags & CRT1_LCDA) pSiS->CRT1off = 0;
5584
5585    /* Handle TVStandard option */
5586    if((pSiS->NonDefaultPAL != -1) || (pSiS->NonDefaultNTSC != -1)) {
5587       if( (!(pSiS->VBFlags2 & VB2_SISTVBRIDGE)) &&
5588	   (!((pSiS->VBFlags2 & VB2_CHRONTEL)) && (pSiS->ChrontelType == CHRONTEL_701x)) ) {
5589	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5590	   	"PALM, PALN and NTSCJ not supported on this hardware\n");
5591	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5592	  pSiS->VBFlags &= ~(TV_PALN | TV_PALM | TV_NTSCJ);
5593	  pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTPALMN | SiS_SD_SUPPORTNTSCJ);
5594       }
5595    }
5596    if(pSiS->OptTVStand != -1) {
5597       if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5598	  if( (!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & (TV_CHSCART | TV_CHYPBPR525I)))) &&
5599	      (!(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR))) ) {
5600	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5601	     if(pSiS->OptTVStand) {
5602	        pSiS->VBFlags |= TV_PAL;
5603	        if(pSiS->NonDefaultPAL == 1)  pSiS->VBFlags |= TV_PALM;
5604	        else if(!pSiS->NonDefaultPAL) pSiS->VBFlags |= TV_PALN;
5605	     } else {
5606	        pSiS->VBFlags |= TV_NTSC;
5607		if(pSiS->NonDefaultNTSC == 1) pSiS->VBFlags |= TV_NTSCJ;
5608	     }
5609	  } else {
5610	     pSiS->OptTVStand = pSiS->NonDefaultPAL = -1;
5611	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5612	    	 "Option TVStandard ignored for YPbPr, HiVision and Chrontel-SCART\n");
5613	  }
5614       } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
5615	  pSiS->SiS6326Flags &= ~SIS6326_TVPAL;
5616	  if(pSiS->OptTVStand) pSiS->SiS6326Flags |= SIS6326_TVPAL;
5617       }
5618    }
5619
5620    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5621       /* Default to PAL */
5622       if(pSiS->VBFlags & (TV_SVIDEO | TV_AVIDEO)) {
5623          if(!(pSiS->VBFlags & (TV_PAL | TV_NTSC))) {
5624	     pSiS->VBFlags &= ~(TV_PAL | TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5625	     pSiS->VBFlags |= TV_PAL;
5626	  }
5627       }
5628       /* SCART only supported for PAL */
5629       if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & TV_SCART)) {
5630	  pSiS->VBFlags &= ~(TV_NTSC | TV_PALN | TV_PALM | TV_NTSCJ);
5631	  pSiS->VBFlags |= TV_PAL;
5632	  pSiS->OptTVStand = 1;
5633	  pSiS->NonDefaultPAL = pSiS->NonDefaultNTSC = -1;
5634       }
5635    }
5636
5637#ifdef SIS_CP
5638    SIS_CP_DRIVER_RECONFIGOPT
5639#endif
5640
5641    if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
5642       if(pSiS->sis6326tvplug != -1) {
5643          pSiS->SiS6326Flags &= ~(SIS6326_TVSVIDEO | SIS6326_TVCVBS);
5644	  pSiS->SiS6326Flags |= SIS6326_TVDETECTED;
5645	  if(pSiS->sis6326tvplug == 1) 	pSiS->SiS6326Flags |= SIS6326_TVCVBS;
5646	  else 				pSiS->SiS6326Flags |= SIS6326_TVSVIDEO;
5647	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5648	      "SiS6326 TV plug type detection overruled by %s\n",
5649	      (pSiS->SiS6326Flags & SIS6326_TVCVBS) ? "COMPOSITE" : "SVIDEO");
5650       }
5651    }
5652
5653    /* Do some checks */
5654    if(pSiS->OptTVOver != -1) {
5655       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
5656	  pSiS->UseCHOverScan = pSiS->OptTVOver;
5657       } else {
5658	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5659	      "CHTVOverscan only supported on CHRONTEL 70xx\n");
5660	  pSiS->UseCHOverScan = -1;
5661       }
5662    } else pSiS->UseCHOverScan = -1;
5663
5664    if(pSiS->sistvedgeenhance != -1) {
5665       if(!(pSiS->VBFlags2 & VB2_301)) {
5666	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5667	      "SISTVEdgeEnhance only supported on SiS301\n");
5668	  pSiS->sistvedgeenhance = -1;
5669       }
5670    }
5671    if(pSiS->sistvsaturation != -1) {
5672       if(pSiS->VBFlags2 & VB2_301) {
5673	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5674	      "SISTVSaturation not supported on SiS301\n");
5675	  pSiS->sistvsaturation = -1;
5676       }
5677    }
5678
5679    /* Do some MergedFB mode initialisation */
5680#ifdef SISMERGED
5681    if(pSiS->MergedFB) {
5682       pSiS->CRT2pScrn = xalloc(sizeof(ScrnInfoRec));
5683       if(!pSiS->CRT2pScrn) {
5684          SISErrorLog(pScrn, "Failed to allocate memory for 2nd pScrn, %s\n", mergeddisstr);
5685	  pSiS->MergedFB = FALSE;
5686       } else {
5687          memcpy(pSiS->CRT2pScrn, pScrn, sizeof(ScrnInfoRec));
5688       }
5689    }
5690#endif
5691
5692    /* Determine CRT1<>CRT2 mode
5693     *     Note: When using VESA or if the bridge is in slavemode, display
5694     *           is ALWAYS in MIRROR_MODE!
5695     *           This requires extra checks in functions using this flag!
5696     *           (see sis_video.c for example)
5697     */
5698    if(pSiS->VBFlags & DISPTYPE_DISP2) {
5699        if(pSiS->CRT1off) {	/* CRT2 only ------------------------------- */
5700#ifdef SISDUALHEAD
5701	     if(pSiS->DualHeadMode) {
5702		SISErrorLog(pScrn,
5703		    "CRT1 not detected or forced off. Dual Head mode can't initialize.\n");
5704		if(pSiSEnt) pSiSEnt->DisableDual = TRUE;
5705		goto my_error_1;
5706	     }
5707#endif
5708#ifdef SISMERGED
5709	     if(pSiS->MergedFB) {
5710		if(pSiS->MergedFBAuto) {
5711		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt1, mergeddisstr);
5712		} else {
5713		   SISErrorLog(pScrn, mergednocrt1, mergeddisstr);
5714		}
5715		if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
5716		pSiS->CRT2pScrn = NULL;
5717		pSiS->MergedFB = FALSE;
5718	     }
5719#endif
5720	     pSiS->VBFlags |= VB_DISPMODE_SINGLE;
5721	     /* No CRT1? Then we use the video overlay on CRT2 */
5722	     pSiS->XvOnCRT2 = TRUE;
5723	} else			/* CRT1 and CRT2 - mirror or dual head ----- */
5724#ifdef SISDUALHEAD
5725	     if(pSiS->DualHeadMode) {
5726		pSiS->VBFlags |= (VB_DISPMODE_DUAL | DISPTYPE_CRT1);
5727		if(pSiS->VESA != -1) {
5728		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5729			"VESA option not used in Dual Head mode. VESA disabled.\n");
5730		}
5731		if(pSiSEnt) pSiSEnt->DisableDual = FALSE;
5732		pSiS->VESA = 0;
5733	     } else
5734#endif
5735#ifdef SISMERGED
5736		    if(pSiS->MergedFB) {
5737		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5738		 if(pSiS->VESA != -1) {
5739		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5740			"VESA option not used in MergedFB mode. VESA disabled.\n");
5741		 }
5742		 pSiS->VESA = 0;
5743	     } else
5744#endif
5745		 pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_CRT1);
5746    } else {			/* CRT1 only ------------------------------- */
5747#ifdef SISDUALHEAD
5748	     if(pSiS->DualHeadMode) {
5749		SISErrorLog(pScrn,
5750		   "No CRT2 output selected or no bridge detected. "
5751		   "Dual Head mode can't initialize.\n");
5752		goto my_error_1;
5753	     }
5754#endif
5755#ifdef SISMERGED
5756	     if(pSiS->MergedFB) {
5757		if(pSiS->MergedFBAuto) {
5758		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, mergednocrt2, mergeddisstr);
5759		} else {
5760		   SISErrorLog(pScrn, mergednocrt2, mergeddisstr);
5761		}
5762		if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
5763		pSiS->CRT2pScrn = NULL;
5764		pSiS->MergedFB = FALSE;
5765	     }
5766#endif
5767             pSiS->VBFlags |= (VB_DISPMODE_SINGLE | DISPTYPE_CRT1);
5768    }
5769
5770    if((pSiS->VGAEngine == SIS_315_VGA) || (pSiS->VGAEngine == SIS_300_VGA)) {
5771       if((!pSiS->NoXvideo)		&&
5772          (!pSiS->hasTwoOverlays)	&&
5773	  (!(pSiS->SiS_SD2_Flags & SiS_SD2_NOOVERLAY))) {
5774	  xf86DrvMsg(pScrn->scrnIndex, from,
5775	      "Using Xv overlay by default on CRT%d\n",
5776	      pSiS->XvOnCRT2 ? 2 : 1);
5777       }
5778    }
5779
5780    /* Init ptrs for Save/Restore functions and calc MaxClock */
5781    SISDACPreInit(pScrn);
5782
5783    /* ********** end of VBFlags setup ********** */
5784
5785    /* VBFlags are initialized now. Back them up for SlaveMode modes. */
5786    pSiS->VBFlags_backup = pSiS->VBFlags;
5787
5788    /* Backup CR32,36,37 (in order to write them back after a VT switch) */
5789    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
5790       inSISIDXREG(SISCR,0x32,pSiS->myCR32);
5791       inSISIDXREG(SISCR,0x36,pSiS->myCR36);
5792       inSISIDXREG(SISCR,0x37,pSiS->myCR37);
5793    }
5794
5795    /* Find out about paneldelaycompensation and evaluate option */
5796#ifdef SISDUALHEAD
5797    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead)) {
5798#endif
5799       if(pSiS->VGAEngine == SIS_300_VGA) {
5800
5801          if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
5802
5803	     /* Save the current PDC if the panel is used at the moment.
5804	      * This seems by far the safest way to find out about it.
5805	      * If the system is using an old version of sisfb, we can't
5806	      * trust the pdc register value. If sisfb saved the pdc for
5807	      * us, use it.
5808	      */
5809	     if(pSiS->sisfbpdc != 0xff) {
5810	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5811	     } else {
5812	        if(!(pSiS->donttrustpdc)) {
5813	           UChar tmp;
5814	           inSISIDXREG(SISCR, 0x30, tmp);
5815	           if(tmp & 0x20) {
5816	              inSISIDXREG(SISPART1, 0x13, pSiS->SiS_Pr->PDC);
5817                   } else {
5818	             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5819		          "Unable to detect LCD PanelDelayCompensation, LCD is not active\n");
5820	           }
5821	        } else {
5822	           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5823		        "Unable to detect LCD PanelDelayCompensation, please update sisfb\n");
5824	        }
5825	     }
5826	     if(pSiS->SiS_Pr->PDC != -1) {
5827	        pSiS->SiS_Pr->PDC &= 0x3c;
5828	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5829		     "Detected LCD PanelDelayCompensation 0x%02x\n",
5830		     pSiS->SiS_Pr->PDC);
5831	     }
5832
5833	     /* If we haven't been able to find out, use our other methods */
5834	     if(pSiS->SiS_Pr->PDC == -1) {
5835		int i=0;
5836		do {
5837		   if(mypdctable[i].subsysVendor == pSiS->PciInfo->subsysVendor &&
5838		      mypdctable[i].subsysCard == pSiS->PciInfo->subsysCard) {
5839			 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
5840			    "PCI card/vendor identified for non-default PanelDelayCompensation\n");
5841			 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5842			     "Vendor: %s, card: %s (ID %04x), PanelDelayCompensation: 0x%02x\n",
5843			     mypdctable[i].vendorName, mypdctable[i].cardName,
5844			     pSiS->PciInfo->subsysCard, mypdctable[i].pdc);
5845			 if(pSiS->PDC == -1) {
5846			    pSiS->PDC = mypdctable[i].pdc;
5847			 } else {
5848			    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5849				"PanelDelayCompensation overruled by option\n");
5850			 }
5851			 break;
5852		   }
5853		   i++;
5854		} while(mypdctable[i].subsysVendor != 0);
5855	     }
5856
5857	     if(pSiS->PDC != -1) {
5858		if(pSiS->BIOS) {
5859		   if(pSiS->VBFlags2 & VB2_LVDS) {
5860		      if(pSiS->BIOS[0x220] & 0x80) {
5861			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5862			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5863			     pSiS->BIOS[0x220] & 0x3c);
5864			 pSiS->BIOS[0x220] &= 0x7f;
5865		      }
5866		   }
5867		   if(pSiS->VBFlags2 & (VB2_301B | VB2_302B)) {
5868		      if(pSiS->BIOS[0x220] & 0x80) {
5869			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5870			     "BIOS uses OEM LCD Panel Delay Compensation 0x%02x\n",
5871			       (  (pSiS->VBLCDFlags & VB_LCD_1280x1024) ?
5872			                 pSiS->BIOS[0x223] : pSiS->BIOS[0x224]  ) & 0x3c);
5873			 pSiS->BIOS[0x220] &= 0x7f;
5874		      }
5875		   }
5876		}
5877		pSiS->SiS_Pr->PDC = (pSiS->PDC & 0x3c);
5878		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5879		      "Using LCD Panel Delay Compensation 0x%02x\n", pSiS->SiS_Pr->PDC);
5880	     }
5881	  }
5882
5883       }  /* SIS_300_VGA */
5884
5885       if(pSiS->VGAEngine == SIS_315_VGA) {
5886
5887	  UChar tmp, tmp2;
5888	  inSISIDXREG(SISCR, 0x30, tmp);
5889
5890	  /* Save the current PDC if the panel is used at the moment. */
5891	  if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
5892
5893	     if(pSiS->sisfbpdc != 0xff) {
5894	        pSiS->SiS_Pr->PDC = pSiS->sisfbpdc;
5895	     }
5896	     if(pSiS->sisfbpdca != 0xff) {
5897	        pSiS->SiS_Pr->PDCA = pSiS->sisfbpdca;
5898	     }
5899
5900	     if(!pSiS->donttrustpdc) {
5901	        if((pSiS->sisfbpdc == 0xff) && (pSiS->sisfbpdca == 0xff)) {
5902		   CARD16 tempa, tempb;
5903		   inSISIDXREG(SISPART1,0x2d,tmp2);
5904		   tempa = (tmp2 & 0xf0) >> 3;
5905		   tempb = (tmp2 & 0x0f) << 1;
5906		   inSISIDXREG(SISPART1,0x20,tmp2);
5907		   tempa |= ((tmp2 & 0x40) >> 6);
5908		   inSISIDXREG(SISPART1,0x35,tmp2);
5909		   tempb |= ((tmp2 & 0x80) >> 7);
5910		   inSISIDXREG(SISPART1,0x13,tmp2);
5911		   if(!pSiS->ROM661New) {
5912		      if((tmp2 & 0x04) || (tmp & 0x20)) {
5913		         pSiS->SiS_Pr->PDCA = tempa;
5914		         pSiS->SiS_Pr->PDC  = tempb;
5915		      } else {
5916			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5917			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5918		      }
5919		   } else {
5920		      if(tmp2 & 0x04) {
5921		         pSiS->SiS_Pr->PDCA = tempa;
5922		      } else if(tmp & 0x20) {
5923		         pSiS->SiS_Pr->PDC  = tempb;
5924		      } else {
5925			 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5926			     "Unable to detect PanelDelayCompensation, LCD is not active\n");
5927		      }
5928		   }
5929		}
5930	     } else {
5931		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
5932		    "Unable to detect PanelDelayCompensation, please update sisfb\n");
5933	     }
5934	     if(pSiS->SiS_Pr->PDC != -1) {
5935		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5936		     "Detected LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5937		     pSiS->SiS_Pr->PDC);
5938	     }
5939	     if(pSiS->SiS_Pr->PDCA != -1) {
5940		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
5941		     "Detected LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5942		     pSiS->SiS_Pr->PDCA);
5943	     }
5944	  }
5945
5946	  /* Let user override (for all bridges) */
5947	  if(pSiS->VBFlags2 & VB2_30xBLV) {
5948	     if(pSiS->PDC != -1) {
5949	        pSiS->SiS_Pr->PDC = pSiS->PDC & 0x1f;
5950		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5951		     "Using LCD PanelDelayCompensation 0x%02x (for LCD=CRT2)\n",
5952		     pSiS->SiS_Pr->PDC);
5953	     }
5954	     if(pSiS->PDCA != -1) {
5955		pSiS->SiS_Pr->PDCA = pSiS->PDCA & 0x1f;
5956		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
5957		     "Using LCD PanelDelayCompensation1 0x%02x (for LCD=CRT1)\n",
5958		     pSiS->SiS_Pr->PDCA);
5959	     }
5960          }
5961
5962 	  /* Read the current EMI (if not overruled) */
5963	  if(pSiS->VBFlags2 & VB2_SISEMIBRIDGE) {
5964	     MessageType from = X_PROBED;
5965	     if(pSiS->EMI != -1) {
5966		pSiS->SiS_Pr->EMI_30 = (pSiS->EMI >> 24) & 0x60;
5967		pSiS->SiS_Pr->EMI_31 = (pSiS->EMI >> 16) & 0xff;
5968		pSiS->SiS_Pr->EMI_32 = (pSiS->EMI >> 8)  & 0xff;
5969		pSiS->SiS_Pr->EMI_33 = pSiS->EMI & 0xff;
5970		pSiS->SiS_Pr->HaveEMI = pSiS->SiS_Pr->HaveEMILCD = TRUE;
5971		pSiS->SiS_Pr->OverruleEMI = TRUE;
5972		from = X_CONFIG;
5973	     } else if((pSiS->sisfbfound) && (pSiS->sisfb_haveemi)) {
5974		pSiS->SiS_Pr->EMI_30 = pSiS->sisfb_emi30;
5975		pSiS->SiS_Pr->EMI_31 = pSiS->sisfb_emi31;
5976		pSiS->SiS_Pr->EMI_32 = pSiS->sisfb_emi32;
5977		pSiS->SiS_Pr->EMI_33 = pSiS->sisfb_emi33;
5978		pSiS->SiS_Pr->HaveEMI = TRUE;
5979		if(pSiS->sisfb_haveemilcd) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5980		pSiS->SiS_Pr->OverruleEMI = FALSE;
5981	     } else {
5982		inSISIDXREG(SISPART4, 0x30, pSiS->SiS_Pr->EMI_30);
5983		inSISIDXREG(SISPART4, 0x31, pSiS->SiS_Pr->EMI_31);
5984		inSISIDXREG(SISPART4, 0x32, pSiS->SiS_Pr->EMI_32);
5985		inSISIDXREG(SISPART4, 0x33, pSiS->SiS_Pr->EMI_33);
5986		pSiS->SiS_Pr->HaveEMI = TRUE;
5987		if(tmp & 0x20) pSiS->SiS_Pr->HaveEMILCD = TRUE;
5988		pSiS->SiS_Pr->OverruleEMI = FALSE;
5989	     }
5990	     xf86DrvMsg(pScrn->scrnIndex, from,
5991		   "302LV/302ELV: Using EMI 0x%02x%02x%02x%02x%s\n",
5992		   pSiS->SiS_Pr->EMI_30,pSiS->SiS_Pr->EMI_31,
5993		   pSiS->SiS_Pr->EMI_32,pSiS->SiS_Pr->EMI_33,
5994		   pSiS->SiS_Pr->HaveEMILCD ? " (LCD)" : "");
5995	  }
5996
5997       } /* SIS_315_VGA */
5998#ifdef SISDUALHEAD
5999    }
6000#endif
6001
6002
6003    /* In dual head mode, both heads (currently) share the maxxfbmem equally.
6004     * If memory sharing is done differently, the following has to be changed;
6005     * the other modules (eg. accel and Xv) use dhmOffset for hardware
6006     * pointer settings relative to VideoRAM start and won't need to be changed.
6007     *
6008     * Addendum: dhmoffset is also used for skipping the UMA area on SiS76x.
6009     */
6010
6011    pSiS->dhmOffset = pSiS->FbBaseOffset;
6012    pSiS->FbAddress += pSiS->dhmOffset;
6013
6014#ifdef SISDUALHEAD
6015    if(pSiS->DualHeadMode) {
6016       pSiS->FbAddress = pSiS->realFbAddress;
6017       if(!pSiS->SecondHead) {
6018	  /* ===== First head (always CRT2) ===== */
6019	  /* We use only half of the memory available */
6020	  pSiS->maxxfbmem /= 2;
6021	  /* dhmOffset is 0 (or LFB-base for SiS76x UMA skipping) */
6022	  pSiS->FbAddress += pSiS->dhmOffset;
6023	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6024	      "%dKB video RAM at 0x%lx available for master head (CRT2)\n",
6025	      pSiS->maxxfbmem/1024, pSiS->FbAddress);
6026       } else {
6027	  /* ===== Second head (always CRT1) ===== */
6028	  /* We use only half of the memory available */
6029	  pSiS->maxxfbmem /= 2;
6030	  /* Initialize dhmOffset */
6031	  pSiS->dhmOffset += pSiS->maxxfbmem;
6032	  /* Adapt FBAddress */
6033	  pSiS->FbAddress += pSiS->dhmOffset;
6034	  xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6035	     "%dKB video RAM at 0x%lx available for slave head (CRT1)\n",
6036	     pSiS->maxxfbmem/1024,  pSiS->FbAddress);
6037       }
6038    }
6039#endif
6040
6041    /* Note: Do not use availMem for anything from now. Use
6042     * maxxfbmem instead. (availMem does not take dual head
6043     * mode into account.)
6044     */
6045
6046    if(pSiS->FbBaseOffset) {
6047       /* Doubt that the DRM memory manager can deal
6048        * with a heap start of 0...
6049	*/
6050       pSiS->DRIheapstart = 16;
6051       pSiS->DRIheapend = pSiS->FbBaseOffset;
6052    } else {
6053       pSiS->DRIheapstart = pSiS->maxxfbmem;
6054       pSiS->DRIheapend = pSiS->availMem;
6055    }
6056#ifdef SISDUALHEAD
6057    if(pSiS->DualHeadMode) {
6058       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
6059    } else
6060#endif
6061           if(pSiS->DRIheapstart >= pSiS->DRIheapend) {
6062#if 0  /* For future use */
6063       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6064	  "No memory for DRI heap. Please set the option \"MaxXFBMem\" to\n"
6065	  "\tlimit the memory X should use and leave the rest to DRI\n");
6066#endif
6067       pSiS->DRIheapstart = pSiS->DRIheapend = 0;
6068    }
6069
6070    /* Now for something completely different: DDC.
6071     * For 300 and 315/330/340 series, we provide our
6072     * own functions (in order to probe CRT2 as well)
6073     * If these fail, use the VBE.
6074     * All other chipsets will use VBE. No need to re-invent
6075     * the wheel there.
6076     */
6077
6078    pSiS->pVbe = NULL;
6079    didddc2 = FALSE;
6080
6081    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6082       if(xf86LoadSubModule(pScrn, "ddc")) {
6083	  int crtnum = 0;
6084	  xf86LoaderReqSymLists(ddcSymbols, NULL);
6085	  if((pMonitor = SiSDoPrivateDDC(pScrn, &crtnum))) {
6086	     didddc2 = TRUE;
6087	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, crtnum);
6088	     xf86PrintEDID(pMonitor);
6089	     xf86SetDDCproperties(pScrn, pMonitor);
6090	     pScrn->monitor->DDC = pMonitor;
6091	     /* Now try to find out aspect ratio */
6092	     SiSFindAspect(pScrn, pMonitor, crtnum);
6093	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, crtnum);
6094	  }
6095       }
6096    }
6097
6098#ifdef SISDUALHEAD
6099    /* In dual head mode, probe DDC using VBE only for CRT1 (second head) */
6100    if((pSiS->DualHeadMode) && (!didddc2) && (!pSiS->SecondHead)) {
6101       didddc2 = TRUE;
6102    }
6103#endif
6104
6105    if(!didddc2) {
6106       /* If CRT1 is off or LCDA, skip DDC via VBE */
6107       if((pSiS->CRT1off) || (pSiS->VBFlags & CRT1_LCDA)) {
6108          didddc2 = TRUE;
6109       }
6110    }
6111
6112    /* Now (re-)load and initialize the DDC module */
6113    if(!didddc2) {
6114
6115       if(xf86LoadSubModule(pScrn, "ddc")) {
6116
6117	  xf86LoaderReqSymLists(ddcSymbols, NULL);
6118
6119	  /* Now load and initialize VBE module. */
6120	  SiS_LoadInitVBE(pScrn);
6121
6122	  if(pSiS->pVbe) {
6123	     if((pMonitor = vbeDoEDID(pSiS->pVbe,NULL))) {
6124		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6125		      "VBE CRT1 DDC monitor info:\n");
6126		xf86SetDDCproperties(pScrn, xf86PrintEDID(pMonitor));
6127		pScrn->monitor->DDC = pMonitor;
6128		/* Now try to find out aspect ratio */
6129		SiSFindAspect(pScrn, pMonitor, 1);
6130		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6131		      "End of VBE CRT1 DDC monitor info\n");
6132	     }
6133	  } else {
6134	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6135		 "Failed to read DDC data\n");
6136	  }
6137       }
6138    }
6139
6140#ifdef SISMERGED
6141    if(pSiS->MergedFB) {
6142       pSiS->CRT2pScrn->monitor = xalloc(sizeof(MonRec));
6143       if(pSiS->CRT2pScrn->monitor) {
6144	  DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL;
6145	  memcpy(pSiS->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec));
6146	  pSiS->CRT2pScrn->monitor->DDC = NULL;
6147	  pSiS->CRT2pScrn->monitor->Modes = NULL;
6148	  pSiS->CRT2pScrn->monitor->id = (char *)crt2monname;
6149	  tempm = pScrn->monitor->Modes;
6150	  while(tempm) {
6151	     if(!(newm = xalloc(sizeof(DisplayModeRec)))) break;
6152	     memcpy(newm, tempm, sizeof(DisplayModeRec));
6153	     if(!(newm->name = xalloc(strlen(tempm->name) + 1))) {
6154	        xfree(newm);
6155		break;
6156	     }
6157	     strcpy(newm->name, tempm->name);
6158	     if(!pSiS->CRT2pScrn->monitor->Modes) pSiS->CRT2pScrn->monitor->Modes = newm;
6159	     if(currentm) {
6160	        currentm->next = newm;
6161		newm->prev = currentm;
6162	     }
6163	     currentm = newm;
6164	     tempm = tempm->next;
6165	  }
6166	  if(pSiS->CRT2HSync) {
6167	     pSiS->CRT2pScrn->monitor->nHsync =
6168		SiSStrToRanges(pSiS->CRT2pScrn->monitor->hsync, pSiS->CRT2HSync, MAX_HSYNC);
6169	  }
6170	  if(pSiS->CRT2VRefresh) {
6171	     pSiS->CRT2pScrn->monitor->nVrefresh =
6172		SiSStrToRanges(pSiS->CRT2pScrn->monitor->vrefresh, pSiS->CRT2VRefresh, MAX_VREFRESH);
6173	  }
6174	  if((pMonitor = SiSInternalDDC(pSiS->CRT2pScrn, 1))) {
6175	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcsstr, 2);
6176	     xf86PrintEDID(pMonitor);
6177	     xf86SetDDCproperties(pSiS->CRT2pScrn, pMonitor);
6178	     pSiS->CRT2pScrn->monitor->DDC = pMonitor;
6179	     /* Now try to find out aspect ratio */
6180	     SiSFindAspect(pScrn, pMonitor, 2);
6181	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED, ddcestr, 2);
6182	     /* use DDC data if no ranges in config file */
6183	     if(!pSiS->CRT2HSync) {
6184	        pSiS->CRT2pScrn->monitor->nHsync = 0;
6185	     }
6186	     if(!pSiS->CRT2VRefresh) {
6187	        pSiS->CRT2pScrn->monitor->nVrefresh = 0;
6188	     }
6189	  } else {
6190	     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
6191		"Failed to read DDC data for CRT2\n");
6192	  }
6193       } else {
6194	  SISErrorLog(pScrn, "Failed to allocate memory for CRT2 monitor, %s.\n",
6195	  		mergeddisstr);
6196	  if(pSiS->CRT2pScrn) xfree(pSiS->CRT2pScrn);
6197	  pSiS->CRT2pScrn = NULL;
6198	  pSiS->MergedFB = FALSE;
6199       }
6200    }
6201#endif
6202
6203    /* Copy our detected monitor gammas, part 1. Note that device redetection
6204     * is not supported in DHM, so there is no need to do that anytime later.
6205     */
6206#ifdef SISDUALHEAD
6207    if(pSiS->DualHeadMode) {
6208       if(!pSiS->SecondHead) {
6209          /* CRT2: Got gamma for LCD or VGA2 */
6210	  pSiSEnt->CRT2VGAMonitorGamma = pSiS->CRT2VGAMonitorGamma;
6211       } else {
6212          /* CRT1: Got gamma for LCD or VGA */
6213	  pSiSEnt->CRT1VGAMonitorGamma = pSiS->CRT1VGAMonitorGamma;
6214       }
6215       if(pSiS->CRT2LCDMonitorGamma) pSiSEnt->CRT2LCDMonitorGamma = pSiS->CRT2LCDMonitorGamma;
6216    }
6217#endif
6218
6219    /* end of DDC */
6220
6221    /* From here, we mainly deal with clocks and modes */
6222
6223#ifdef SISMERGED
6224    if(pSiS->MergedFB) xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 1);
6225#endif
6226
6227    /* Set the min pixel clock */
6228    pSiS->MinClock = 5000;
6229    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6230       pSiS->MinClock = 10000;
6231    }
6232    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock is %d MHz\n",
6233                pSiS->MinClock / 1000);
6234
6235    /* If the user has specified ramdac speed in the config
6236     * file, we respect that setting.
6237     */
6238    from = X_PROBED;
6239    if(pSiS->pEnt->device->dacSpeeds[0]) {
6240       int speed = 0;
6241       switch(pScrn->bitsPerPixel) {
6242       case 8:  speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP8];
6243                break;
6244       case 16: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP16];
6245                break;
6246       case 24: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP24];
6247                break;
6248       case 32: speed = pSiS->pEnt->device->dacSpeeds[DAC_BPP32];
6249                break;
6250       }
6251       if(speed == 0) pSiS->MaxClock = pSiS->pEnt->device->dacSpeeds[0];
6252       else           pSiS->MaxClock = speed;
6253       from = X_CONFIG;
6254    }
6255    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
6256                pSiS->MaxClock / 1000);
6257
6258    /*
6259     * Setup the ClockRanges, which describe what clock ranges are available,
6260     * and what sort of modes they can be used for.
6261     */
6262    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
6263    clockRanges->next = NULL;
6264    clockRanges->minClock = pSiS->MinClock;
6265    clockRanges->maxClock = pSiS->MaxClock;
6266    clockRanges->clockIndex = -1;               /* programmable */
6267    clockRanges->interlaceAllowed = TRUE;
6268    clockRanges->doubleScanAllowed = TRUE;
6269
6270    /*
6271     * Since we have lots of built-in modes for 300/315/330/340 series
6272     * with vb support, we replace the given default mode list with our
6273     * own. In case the video bridge is to be used, we only allow other
6274     * modes if
6275     *   -) vbtype is 301, 301B, 301C or 302B, and
6276     *   -) crt2 device is not TV, and
6277     *   -) crt1 is not LCDA, unless bridge is TMDS/LCDA capable (301C)
6278     */
6279    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
6280       if(!(pSiS->noInternalModes)) {
6281          Bool acceptcustommodes = TRUE;  /* Accept user modelines */
6282	  Bool includelcdmodes   = TRUE;  /* Include modes reported by DDC */
6283	  Bool isfordvi          = FALSE; /* Is for digital DVI output */
6284	  Bool fakecrt2modes     = FALSE; /* Fake some modes for CRT2 */
6285	  Bool IsForCRT2	 = FALSE;
6286	  if(pSiS->UseVESA) {
6287	     acceptcustommodes = FALSE;
6288	     includelcdmodes   = FALSE;
6289	  }
6290#ifdef SISDUALHEAD  /* Dual head is static. Output devices will not change. */
6291	  if(pSiS->DualHeadMode) {
6292	     if(!pSiS->SecondHead) {  /* CRT2: */
6293	        if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6294		   if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6295		      if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6296		      if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6297		      if(pSiS->VBFlags & CRT2_TV)                acceptcustommodes = FALSE;
6298		   } else {
6299		      if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6300		         acceptcustommodes = FALSE;
6301		         includelcdmodes   = FALSE;
6302			 fakecrt2modes = TRUE;
6303		      }
6304		   }
6305		} else {
6306		   acceptcustommodes = FALSE;
6307		   includelcdmodes   = FALSE;
6308		   if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6309		      fakecrt2modes = TRUE;
6310		   }
6311		}
6312		clockRanges->interlaceAllowed = FALSE;
6313		IsForCRT2 = TRUE;
6314	     } else {		/* CRT1: */
6315	        if(pSiS->VBFlags & CRT1_LCDA) {
6316		   if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6317		      acceptcustommodes = FALSE;
6318		      includelcdmodes   = FALSE;
6319		      fakecrt2modes     = TRUE;
6320		      /* Will handle i-lace in mode-switching code */
6321		   } else {
6322		      isfordvi = TRUE;
6323		      /* Don't allow i-lace modes */
6324		      clockRanges->interlaceAllowed = FALSE;
6325		   }
6326		} else {
6327		   includelcdmodes = FALSE;
6328		}
6329	     }
6330	  } else
6331#endif
6332#ifdef SISMERGED  /* MergedFB mode is not static. Output devices may change. */
6333          if(pSiS->MergedFB) {
6334	     if(pSiS->VBFlags & CRT1_LCDA) {
6335	        if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6336		   acceptcustommodes = FALSE;
6337		   includelcdmodes   = FALSE;
6338		   fakecrt2modes     = TRUE;
6339		   /* Will handle i-lace in mode-switching code */
6340		} else {
6341		   isfordvi = TRUE;
6342		   /* Don't allow i-lace custom modes */
6343		   clockRanges->interlaceAllowed = FALSE;
6344		}
6345	     } else {
6346	        includelcdmodes = FALSE;
6347	     }
6348          } else
6349#endif		 /* Mirror mode is not static. Output devices may change. */
6350          if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6351	     if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6352		if(!(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) {
6353		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes = FALSE;
6354		   if(pSiS->VBFlags & CRT2_LCD)               isfordvi        = TRUE;
6355		} else {
6356		   if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA|CRT1_LCDA))) includelcdmodes = FALSE;
6357		   if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA))             isfordvi        = TRUE;
6358		}
6359		if((!(pSiS->VBFlags & DISPTYPE_CRT1)) && (!(pSiS->VBFlags & CRT1_LCDA))) {
6360		   IsForCRT2 = TRUE;
6361		}
6362		/* Allow user modes, even if CRT2 is TV. Will be filtered through ValidMode();
6363		 * leaving the user modes here might have the advantage that such a mode, if
6364		 * it matches in resolution with a supported TV mode, allows us to drive eg.
6365		 * non standard panels, and still permits switching to TV. This mode will be
6366		 * "mapped" to a supported mode of identical resolution for TV. All this is
6367		 * taken care of by ValidMode() and ModeInit()/PresetMode().
6368		 */
6369	     } else {
6370		if(pSiS->VBFlags & (CRT2_TV|CRT2_LCD)) {
6371		   acceptcustommodes = FALSE;
6372		   includelcdmodes   = FALSE;
6373		   if(!(pSiS->VBFlags & DISPTYPE_CRT1)) {
6374		      fakecrt2modes = TRUE;
6375		      IsForCRT2 = TRUE;
6376		   }
6377		}
6378	     }
6379	  } else if(pSiS->VBFlags & (CRT2_ENABLE | CRT1_LCDA)) {
6380	     acceptcustommodes = FALSE;
6381	     includelcdmodes   = FALSE;
6382	     if((pSiS->VBFlags & CRT1_LCDA) || (!(pSiS->VBFlags & DISPTYPE_CRT1))) {
6383		fakecrt2modes = TRUE;
6384		IsForCRT2 = TRUE;
6385	     }
6386	  } else {
6387	     includelcdmodes   = FALSE;
6388	  }
6389	  /* Ignore interlace, mode switching code will handle this */
6390
6391	  pSiS->HaveCustomModes = FALSE;
6392	  if(SiSMakeOwnModeList(pScrn, acceptcustommodes, includelcdmodes,
6393			isfordvi, &pSiS->HaveCustomModes, FALSE /*fakecrt2modes*/, IsForCRT2)) {
6394	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6395		 "Replaced %s mode list with built-in modes\n",
6396	     pSiS->HaveCustomModes ? "default" : "entire");
6397	     if(pSiS->VGAEngine == SIS_315_VGA) {
6398		int UseWide = pSiS->SiS_Pr->SiS_UseWide;
6399		if(IsForCRT2) UseWide = pSiS->SiS_Pr->SiS_UseWideCRT2;
6400		if((!IsForCRT2) || (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6401		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6402			"Using %s widescreen modes for CRT%d VGA devices\n",
6403			UseWide ? "real" : "fake", IsForCRT2 ? 2 : 1);
6404		   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6405			"\tUse option \"ForceCRT%dVGAAspect\" to overrule\n",
6406			IsForCRT2 ? 2 : 1);
6407		}
6408	     }
6409#ifdef TWDEBUG
6410             pScrn->modes = pScrn->monitor->Modes;
6411	     xf86PrintModes(pScrn);
6412	     pScrn->modes = NULL;
6413#endif
6414          } else {
6415	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
6416		"Building list of built-in modes failed, using server defaults\n");
6417	  }
6418       } else {
6419          pSiS->HaveCustomModes = TRUE;
6420       }
6421    }
6422
6423    /* Add our built-in hi-res and TV modes on the 6326 */
6424    if(pSiS->Chipset == PCI_CHIP_SIS6326) {
6425       if(pScrn->bitsPerPixel == 8) {
6426	  SiS6326SIS1600x1200_60Mode.next = pScrn->monitor->Modes;
6427	  pScrn->monitor->Modes = &SiS6326SIS1600x1200_60Mode;
6428	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6429	  	"Adding mode \"SIS1600x1200-60\" (depth 8 only)\n");
6430       }
6431       if(pScrn->bitsPerPixel <= 16) {
6432	  SiS6326SIS1280x1024_75Mode.next = pScrn->monitor->Modes;
6433	  pScrn->monitor->Modes = &SiS6326SIS1280x1024_75Mode;
6434	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6435	  	"Adding mode \"SIS1280x1024-75\" (depths 8, 15 and 16 only)\n");
6436       }
6437       if((pSiS->SiS6326Flags & SIS6326_HASTV) &&
6438	  (pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
6439	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6440		"Adding %s TV modes to mode list:\n",
6441		(pSiS->SiS6326Flags & SIS6326_TVPAL) ? "PAL" : "NTSC");
6442	  if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
6443	     SiS6326PAL800x600Mode.next = pScrn->monitor->Modes;
6444	     pScrn->monitor->Modes = &SiS6326PAL640x480Mode;
6445	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6446		"\t\"PAL800x600\" \"PAL800x600U\" \"PAL720x540\" \"PAL640x480\"\n");
6447	  } else {
6448	     SiS6326NTSC640x480Mode.next = pScrn->monitor->Modes;
6449	     pScrn->monitor->Modes = &SiS6326NTSC640x400Mode;
6450	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6451		"\t\"NTSC640x480\" \"NTSC640x480U\" \"NTSC640x400\"\n");
6452	  }
6453       }
6454    }
6455
6456   /* If there is no HSync or VRefresh data for the monitor,
6457    * derive it from DDC data. Essentially done by common layer
6458    * since 4.3.99.14, but this is not usable since it is done
6459    * too late (in ValidateModes()).
6460    * Addendum: I overrule the ranges now in any case unless
6461    * it would affect a CRT output device or DDC data is available.
6462    * Hence, for LCD(A) and TV, we always get proper ranges. This
6463    * is entirely harmless. However, option "NoOverruleRanges" will
6464    * disable this behavior.
6465    * This should "fix" the - by far - most common configuration
6466    * mistakes.
6467    */
6468
6469    crt1freqoverruled = FALSE;
6470
6471    fromDDC = FALSE;
6472    if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6473       if((pScrn->monitor->nHsync <= 0) && (pScrn->monitor->DDC)) {
6474	  SiSSetSyncRangeFromEdid(pScrn, 1);
6475	  if(pScrn->monitor->nHsync > 0) {
6476	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr,
6477#ifdef SISDUALHEAD
6478			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6479#endif
6480				pSiS->CRT1off ? 2 : 1);
6481	     fromDDC = TRUE;
6482	  }
6483       }
6484       if((pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6485	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6486	     Bool HaveNoRanges = (pScrn->monitor->nHsync <= 0);
6487	     /* Set sane ranges for LCD and TV
6488	      * (our strict checking will filter out invalid ones anyway)
6489	      */
6490	     if((crt1freqoverruled = CheckAndOverruleH(pScrn, pScrn->monitor))) {
6491		xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6492			HaveNoRanges ? "missing" : "bogus",
6493#ifdef SISDUALHEAD
6494			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6495#endif
6496				pSiS->CRT1off ? 2 : 1);
6497	     }
6498	  }
6499       }
6500    }
6501
6502    fromDDC = FALSE;
6503    if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6504       if((pScrn->monitor->nVrefresh <= 0) && (pScrn->monitor->DDC)) {
6505	  SiSSetSyncRangeFromEdid(pScrn, 0);
6506	  if(pScrn->monitor->nVrefresh > 0) {
6507	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr,
6508#ifdef SISDUALHEAD
6509			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6510#endif
6511				pSiS->CRT1off ? 2 : 1);
6512	     fromDDC = TRUE;
6513          }
6514       }
6515       if((pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6516	  if(SiSAllowSyncOverride(pSiS, fromDDC)) {
6517	     Bool HaveNoRanges = (pScrn->monitor->nVrefresh <= 0);
6518	     /* Set sane ranges for LCD and TV */
6519	     if((crt1freqoverruled = CheckAndOverruleV(pScrn, pScrn->monitor))) {
6520		xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6521			HaveNoRanges ? "missing" : "bogus",
6522#ifdef SISDUALHEAD
6523			pSiS->DualHeadMode ? (pSiS->SecondHead ? 1 : 2) :
6524#endif
6525				pSiS->CRT1off ? 2 : 1);
6526	     }
6527	  }
6528       }
6529    }
6530
6531    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
6532       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6533	  "\"Unknown reason\" in the following list means that the mode\n");
6534       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6535	  "is not supported on the chipset/bridge/current output device.\n");
6536    }
6537
6538    /*
6539     * xf86ValidateModes will check that the mode HTotal and VTotal values
6540     * don't exceed the chipset's limit if pScrn->maxHValue and
6541     * pScrn->maxVValue are set.  Since our SISValidMode() already takes
6542     * care of this, we don't worry about setting them here.
6543     */
6544
6545    /* Select valid modes from those available */
6546    /*
6547     * Assuming min pitch 256, min height 128
6548     */
6549    {
6550       int minpitch, maxpitch, minheight, maxheight;
6551       pointer backupddc = pScrn->monitor->DDC;
6552
6553       minpitch = 256;
6554       minheight = 128;
6555       switch(pSiS->VGAEngine) {
6556       case SIS_OLD_VGA:
6557       case SIS_530_VGA:
6558          maxpitch = 2040;
6559          maxheight = 2048;
6560          break;
6561       case SIS_300_VGA:
6562       case SIS_315_VGA:
6563          maxpitch = 4088;
6564          maxheight = 4096;
6565          break;
6566       default:
6567          maxpitch = 2048;
6568          maxheight = 2048;
6569          break;
6570       }
6571
6572#ifdef SISMERGED
6573       pSiS->CheckForCRT2 = FALSE;
6574#endif
6575
6576       /* Suppress bogus DDC warning */
6577       if(crt1freqoverruled) pScrn->monitor->DDC = NULL;
6578
6579       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
6580			pScrn->display->modes, clockRanges, NULL,
6581			minpitch, maxpitch,
6582			pScrn->bitsPerPixel * 8,
6583			minheight, maxheight,
6584			pScrn->display->virtualX,
6585			pScrn->display->virtualY,
6586			pSiS->maxxfbmem,
6587			LOOKUP_BEST_REFRESH);
6588
6589       pScrn->monitor->DDC = backupddc;
6590    }
6591
6592    if(i == -1) {
6593       SISErrorLog(pScrn, "xf86ValidateModes() error\n");
6594       goto my_error_1;
6595    }
6596
6597    /* Check the virtual screen against the available memory */
6598    {
6599       ULong memreq = (pScrn->virtualX * ((pScrn->bitsPerPixel + 7) / 8)) * pScrn->virtualY;
6600
6601       if(memreq > pSiS->maxxfbmem) {
6602	  SISErrorLog(pScrn,
6603	     "Virtual screen too big for memory; %ldK needed, %ldK available\n",
6604	     memreq/1024, pSiS->maxxfbmem/1024);
6605	  goto my_error_1;
6606       }
6607    }
6608
6609    /* Dual Head:
6610     * -) Go through mode list and mark all those modes as bad,
6611     *    which are unsuitable for dual head mode.
6612     * -) Find the highest used pixelclock on the master head.
6613     */
6614#ifdef SISDUALHEAD
6615    if((pSiS->DualHeadMode) && (!pSiS->SecondHead)) {
6616
6617       pSiSEnt->maxUsedClock = 0;
6618
6619       if((p = first = pScrn->modes)) {
6620
6621	  do {
6622
6623	     n = p->next;
6624
6625	     /* Modes that require the bridge to operate in SlaveMode
6626	      * are not suitable for Dual Head mode.
6627	      */
6628	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6629		 ( (strcmp(p->name, "320x200") == 0) ||
6630		   (strcmp(p->name, "320x240") == 0) ||
6631		   (strcmp(p->name, "400x300") == 0) ||
6632		   (strcmp(p->name, "512x384") == 0) ||
6633		   (strcmp(p->name, "640x400") == 0) ) )  {
6634		p->status = MODE_BAD;
6635		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "dual head");
6636	     }
6637
6638	     /* Search for the highest clock on first head in order to calculate
6639	      * max clock for second head (CRT1)
6640	      */
6641	     if((p->status == MODE_OK) && (p->Clock > pSiSEnt->maxUsedClock)) {
6642		pSiSEnt->maxUsedClock = p->Clock;
6643	     }
6644
6645	     p = n;
6646
6647	  } while (p != NULL && p != first);
6648
6649       }
6650    }
6651#endif
6652
6653    /* Prune the modes marked as invalid */
6654    xf86PruneDriverModes(pScrn);
6655
6656    if(i == 0 || pScrn->modes == NULL) {
6657       SISErrorLog(pScrn, "No valid modes found - check VertRefresh/HorizSync\n");
6658       goto my_error_1;
6659    }
6660
6661    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
6662
6663    /* Set the current mode to the first in the list */
6664    pScrn->currentMode = pScrn->modes;
6665
6666    /* Copy to CurrentLayout */
6667    pSiS->CurrentLayout.mode = pScrn->currentMode;
6668    pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6669    pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6670
6671#ifdef SISMERGED
6672    if(pSiS->MergedFB) {
6673       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 1);
6674    }
6675#endif
6676
6677    /* Print the list of modes being used */
6678    {
6679       Bool usemyprint = FALSE;
6680
6681#ifdef SISDUALHEAD
6682       if(pSiS->DualHeadMode) {
6683	  if(pSiS->SecondHead) {
6684	     if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6685	  } else {
6686	     if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) usemyprint = TRUE;
6687	  }
6688       } else
6689#endif
6690#ifdef SISMERGED
6691       if(pSiS->MergedFB) {
6692	  if(pSiS->VBFlags & CRT1_LCDA) usemyprint = TRUE;
6693       } else
6694#endif
6695       {
6696	  if( (pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) &&
6697	      (!(pSiS->VBFlags & DISPTYPE_DISP1)) )
6698	     usemyprint = TRUE;
6699       }
6700
6701       if(usemyprint) {
6702	  SiSPrintModes(pScrn);
6703       } else {
6704	  xf86PrintModes(pScrn);
6705       }
6706    }
6707
6708#ifdef SISMERGED
6709    if(pSiS->MergedFB) {
6710       Bool acceptcustommodes = TRUE;
6711       Bool includelcdmodes   = TRUE;
6712       Bool isfordvi          = FALSE;
6713       Bool fakecrt2modes     = FALSE;
6714
6715       xf86DrvMsg(pScrn->scrnIndex, X_INFO, crtsetupstr, 2);
6716
6717       clockRanges->next = NULL;
6718       clockRanges->minClock = pSiS->MinClock;
6719       clockRanges->maxClock = SiSMemBandWidth(pSiS->CRT2pScrn, TRUE);
6720       clockRanges->clockIndex = -1;
6721       clockRanges->interlaceAllowed = FALSE;
6722       clockRanges->doubleScanAllowed = FALSE;
6723       if(pSiS->VGAEngine == SIS_315_VGA) {
6724          clockRanges->doubleScanAllowed = TRUE;
6725       }
6726
6727       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock for CRT2 is %d MHz\n",
6728                clockRanges->minClock / 1000);
6729       xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Max pixel clock for CRT2 is %d MHz\n",
6730                clockRanges->maxClock / 1000);
6731
6732       if(pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) {
6733          if(!(pSiS->VBFlags2 & VB2_30xBDH)) {
6734             if(!(pSiS->VBFlags & (CRT2_LCD|CRT2_VGA))) includelcdmodes   = FALSE;
6735	     if(pSiS->VBFlags & CRT2_LCD)               isfordvi          = TRUE;
6736	     /* See above for a remark on handling CRT2 = TV */
6737	  } else {
6738	     if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6739		includelcdmodes   = FALSE;
6740		acceptcustommodes = FALSE;
6741		fakecrt2modes     = TRUE;
6742	     }
6743	  }
6744       } else {
6745	  includelcdmodes   = FALSE;
6746	  acceptcustommodes = FALSE;
6747	  if(pSiS->VBFlags & (CRT2_LCD|CRT2_TV)) {
6748	     fakecrt2modes = TRUE;
6749	  }
6750       }
6751
6752       pSiS->HaveCustomModes2 = FALSE;
6753       if(!SiSMakeOwnModeList(pSiS->CRT2pScrn, acceptcustommodes, includelcdmodes,
6754				isfordvi, &pSiS->HaveCustomModes2, FALSE /* fakecrt2modes */, TRUE )) {
6755
6756	  SISErrorLog(pScrn, "Building list of built-in modes for CRT2 failed, %s\n",
6757				mergeddisstr);
6758	  SiSFreeCRT2Structs(pSiS);
6759	  pSiS->MergedFB = FALSE;
6760
6761       } else {
6762	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6763		 "Replaced %s mode list for CRT2 with built-in modes\n",
6764		 pSiS->HaveCustomModes2 ? "default" : "entire");
6765	  if((pSiS->VGAEngine == SIS_315_VGA) && (pSiS->VBFlags2 & VB2_SISVGA2BRIDGE)) {
6766	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
6767		 "Using %s widescreen modes for CRT2 VGA devices\n",
6768		 pSiS->SiS_Pr->SiS_UseWideCRT2 ? "real" : "fake");
6769	  } else pSiS->SiS_Pr->SiS_UseWideCRT2 = 0;
6770       }
6771
6772    }
6773
6774    if(pSiS->MergedFB) {
6775
6776       pointer backupddc;
6777
6778       crt2freqoverruled = FALSE;
6779
6780       fromDDC = FALSE;
6781       if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6782          if((pSiS->CRT2pScrn->monitor->nHsync <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6783	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 1);
6784	     if(pSiS->CRT2pScrn->monitor->nHsync > 0) {
6785		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subshstr, 2);
6786		fromDDC = TRUE;
6787	     }
6788	  }
6789	  if((pSiS->CRT2pScrn->monitor->nHsync <= 0) || (pSiS->OverruleRanges)) {
6790	     if( (pSiS->VBFlags & CRT2_TV) ||
6791	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6792		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nHsync <= 0);
6793		/* Set sane ranges for LCD and TV */
6794		if((crt2freqoverruled = CheckAndOverruleH(pScrn, pSiS->CRT2pScrn->monitor))) {
6795		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, saneh,
6796			HaveNoRanges ? "missing" : "bogus", 2);
6797		}
6798	     }
6799	  }
6800       }
6801
6802       fromDDC = FALSE;
6803       if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6804	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) && (pSiS->CRT2pScrn->monitor->DDC)) {
6805	     SiSSetSyncRangeFromEdid(pSiS->CRT2pScrn, 0);
6806	     if(pSiS->CRT2pScrn->monitor->nVrefresh > 0) {
6807		xf86DrvMsg(pScrn->scrnIndex, X_INFO, subsvstr, 2);
6808		fromDDC = TRUE;
6809	     }
6810          }
6811	  if((pSiS->CRT2pScrn->monitor->nVrefresh <= 0) || (pSiS->OverruleRanges)) {
6812	     if( (pSiS->VBFlags & CRT2_TV) ||
6813	         ((pSiS->VBFlags & CRT2_LCD) && (!fromDDC)) ) {
6814		Bool HaveNoRanges = (pSiS->CRT2pScrn->monitor->nVrefresh <= 0);
6815		/* Set sane ranges for LCD and TV */
6816		if((crt2freqoverruled = CheckAndOverruleV(pScrn, pSiS->CRT2pScrn->monitor))) {
6817		   xf86DrvMsg(pScrn->scrnIndex, X_INFO, sanev,
6818			 HaveNoRanges ? "missing" : "bogus", 2);
6819	        }
6820	     }
6821	  }
6822       }
6823
6824       backupddc = pSiS->CRT2pScrn->monitor->DDC;
6825
6826       /* Suppress bogus DDC warning */
6827       if(crt2freqoverruled) pSiS->CRT2pScrn->monitor->DDC = NULL;
6828
6829       pSiS->CheckForCRT2 = TRUE;
6830
6831       i = xf86ValidateModes(pSiS->CRT2pScrn, pSiS->CRT2pScrn->monitor->Modes,
6832			pSiS->CRT2pScrn->display->modes, clockRanges,
6833			NULL, 256, 4088,
6834			pSiS->CRT2pScrn->bitsPerPixel * 8, 128, 4096,
6835			pScrn->display->virtualX ? pScrn->virtualX : 0,
6836			pScrn->display->virtualY ? pScrn->virtualY : 0,
6837			pSiS->maxxfbmem,
6838			LOOKUP_BEST_REFRESH);
6839
6840       pSiS->CheckForCRT2 = FALSE;
6841       pSiS->CRT2pScrn->monitor->DDC = backupddc;
6842
6843       if(i == -1) {
6844	  SISErrorLog(pScrn, "xf86ValidateModes() error, %s.\n", mergeddisstr);
6845	  SiSFreeCRT2Structs(pSiS);
6846	  pSiS->MergedFB = FALSE;
6847       }
6848
6849    }
6850
6851    if(pSiS->MergedFB) {
6852
6853       if((p = first = pSiS->CRT2pScrn->modes)) {
6854          do {
6855	     n = p->next;
6856	     if( (pSiS->VGAEngine == SIS_300_VGA) &&
6857		 ( (strcmp(p->name, "320x200") == 0) ||
6858		   (strcmp(p->name, "320x240") == 0) ||
6859		   (strcmp(p->name, "400x300") == 0) ||
6860		   (strcmp(p->name, "512x384") == 0) ||
6861		   (strcmp(p->name, "640x400") == 0) ) )  {
6862		p->status = MODE_BAD;
6863		xf86DrvMsg(pScrn->scrnIndex, X_INFO, notsuitablestr, p->name, "MergedFB");
6864	     }
6865	     p = n;
6866	  } while (p != NULL && p != first);
6867       }
6868
6869       xf86PruneDriverModes(pSiS->CRT2pScrn);
6870
6871       if(i == 0 || pSiS->CRT2pScrn->modes == NULL) {
6872	  SISErrorLog(pScrn, "No valid modes found for CRT2; %s\n", mergeddisstr);
6873	  SiSFreeCRT2Structs(pSiS);
6874	  pSiS->MergedFB = FALSE;
6875       }
6876
6877    }
6878
6879    if(pSiS->MergedFB) {
6880
6881       xf86SetCrtcForModes(pSiS->CRT2pScrn, INTERLACE_HALVE_V);
6882
6883       xf86DrvMsg(pScrn->scrnIndex, X_INFO, modesforstr, 2);
6884
6885       if(pSiS->VBFlags & (CRT2_LCD | CRT2_TV)) {
6886	  SiSPrintModes(pSiS->CRT2pScrn);
6887       } else {
6888	  xf86PrintModes(pSiS->CRT2pScrn);
6889       }
6890
6891       pSiS->CRT1Modes = pScrn->modes;
6892       pSiS->CRT1CurrentMode = pScrn->currentMode;
6893
6894       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MergedFB: Generating mode list\n");
6895
6896       pScrn->modes = SiSGenerateModeList(pScrn, pSiS->MetaModes,
6897					  pSiS->CRT1Modes, pSiS->CRT2pScrn->modes,
6898					  pSiS->CRT2Position);
6899
6900       if(!pScrn->modes) {
6901
6902	  SISErrorLog(pScrn, "Failed to parse MetaModes or no modes found. %s.\n",
6903			mergeddisstr);
6904	  SiSFreeCRT2Structs(pSiS);
6905	  pScrn->modes = pSiS->CRT1Modes;
6906	  pSiS->CRT1Modes = NULL;
6907	  pSiS->MergedFB = FALSE;
6908
6909       }
6910
6911    }
6912
6913    if(pSiS->MergedFB) {
6914
6915       /* If no virtual dimension was given by the user,
6916	* calculate a sane one now. Adapts pScrn->virtualX,
6917	* pScrn->virtualY and pScrn->displayWidth.
6918	*/
6919       SiSRecalcDefaultVirtualSize(pScrn);
6920
6921       pScrn->modes = pScrn->modes->next;  /* We get the last from GenerateModeList(), skip to first */
6922       pScrn->currentMode = pScrn->modes;
6923
6924       /* Update CurrentLayout */
6925       pSiS->CurrentLayout.mode = pScrn->currentMode;
6926       pSiS->CurrentLayout.displayWidth = pScrn->displayWidth;
6927       pSiS->CurrentLayout.displayHeight = pScrn->virtualY;
6928
6929    }
6930#endif
6931
6932    /* Set display resolution */
6933#ifdef SISMERGED
6934    if(pSiS->MergedFB) {
6935       SiSMergedFBSetDpi(pScrn, pSiS->CRT2pScrn, pSiS->CRT2Position);
6936    } else
6937#endif
6938       xf86SetDpi(pScrn, 0, 0);
6939
6940    /* Load fb module */
6941    switch(pScrn->bitsPerPixel) {
6942      case 8:
6943      case 16:
6944      case 24:
6945      case 32:
6946	if(!xf86LoadSubModule(pScrn, "fb")) {
6947           SISErrorLog(pScrn, "Failed to load fb module");
6948	   goto my_error_1;
6949	}
6950	break;
6951      default:
6952	SISErrorLog(pScrn, "Unsupported framebuffer bpp (%d)\n", pScrn->bitsPerPixel);
6953	goto my_error_1;
6954    }
6955    xf86LoaderReqSymLists(fbSymbols, NULL);
6956
6957    /* Load XAA/EXA (if needed) */
6958    if(!pSiS->NoAccel) {
6959       const char **symNames = NULL;
6960#ifdef SIS_USE_XAA
6961       if(!pSiS->useEXA) {
6962	  if (!xf86LoadSubModule(pScrn, "xaa")) {
6963	    SISErrorLog(pScrn, "Could not load xaa module\n");
6964	    goto my_error_1;
6965	  }
6966	  symNames = xaaSymbols;
6967       }
6968#endif
6969#ifdef SIS_USE_EXA
6970       if(pSiS->useEXA) {
6971	  XF86ModReqInfo req;
6972	  int errmaj, errmin;
6973
6974	  memset(&req, 0, sizeof(req));
6975	  req.majorversion = 2;
6976	  req.minorversion = 0;
6977	  if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &req,
6978	    &errmaj, &errmin)) {
6979	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
6980	    goto my_error_1;
6981	  }
6982	  symNames = exaSymbols;
6983       }
6984#endif
6985       if(symNames) {
6986	  xf86LoaderReqSymLists(symNames, NULL);
6987	  xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration enabled\n");
6988       }
6989    }
6990
6991    /* Load shadowfb (if needed) */
6992    if(pSiS->ShadowFB) {
6993       if(!xf86LoadSubModule(pScrn, "shadowfb")) {
6994	  SISErrorLog(pScrn, "Could not load shadowfb module\n");
6995	  goto my_error_1;
6996       }
6997       xf86LoaderReqSymLists(shadowSymbols, NULL);
6998    }
6999
7000    /* Load the dri and glx modules if requested. */
7001#ifdef XF86DRI
7002    if(pSiS->loadDRI) {
7003       if(!xf86LoaderCheckSymbol("DRIScreenInit")) {
7004	  if(xf86LoadSubModule(pScrn, "dri")) {
7005	     if(!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) {
7006	        if(xf86LoadSubModule(pScrn, "glx")) {
7007		   xf86LoaderReqSymLists(driSymbols, drmSymbols, NULL);
7008		} else {
7009		   SISErrorLog(pScrn, "Failed to load glx module\n");
7010		}
7011	     }
7012	  } else {
7013	     SISErrorLog(pScrn, "Failed to load dri module\n");
7014	  }
7015       }
7016    }
7017#endif
7018
7019    /* Now load and initialize VBE module for VESA mode switching */
7020    pSiS->UseVESA = 0;
7021    if(pSiS->VESA == 1) {
7022       SiS_LoadInitVBE(pScrn);
7023       if(pSiS->pVbe) {
7024	  VbeInfoBlock *vbe;
7025	  if((vbe = VBEGetVBEInfo(pSiS->pVbe))) {
7026	     pSiS->vesamajor = (unsigned)(vbe->VESAVersion >> 8);
7027	     pSiS->vesaminor = vbe->VESAVersion & 0xff;
7028	     SiSBuildVesaModeList(pScrn, pSiS->pVbe, vbe);
7029	     VBEFreeVBEInfo(vbe);
7030	     pSiS->UseVESA = 1;
7031	  } else {
7032	     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
7033	     	 "Failed to read VBE Info Block\n");
7034	  }
7035       }
7036       if(pSiS->UseVESA == 0) {
7037	  xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
7038	      "VESA mode switching disabled.\n");
7039       }
7040    }
7041
7042    if(pSiS->pVbe) {
7043       vbeFree(pSiS->pVbe);
7044       pSiS->pVbe = NULL;
7045    }
7046
7047#ifdef SISDUALHEAD
7048    xf86SetPrimInitDone(pScrn->entityList[0]);
7049#endif
7050
7051    sisRestoreExtRegisterLock(pSiS,srlockReg,crlockReg);
7052
7053    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
7054    pSiS->pInt = NULL;
7055
7056    if(pSiS->VGAEngine == SIS_315_VGA) {
7057       pSiS->SiS_SD_Flags |= SiS_SD_SUPPORTXVGAMMA1;
7058    }
7059
7060#ifdef SISDUALHEAD
7061    if(pSiS->DualHeadMode) {
7062	pSiS->SiS_SD_Flags |= SiS_SD_ISDUALHEAD;
7063	if(pSiS->SecondHead) pSiS->SiS_SD_Flags |= SiS_SD_ISDHSECONDHEAD;
7064	else		     pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1);
7065#ifdef PANORAMIX
7066	if(!noPanoramiXExtension) {
7067	   pSiS->SiS_SD_Flags |= SiS_SD_ISDHXINERAMA;
7068	   /* pSiS->SiS_SD_Flags &= ~(SiS_SD_SUPPORTXVGAMMA1); */
7069	}
7070#endif
7071    }
7072#endif
7073
7074#ifdef SISMERGED
7075    if(pSiS->MergedFB) pSiS->SiS_SD_Flags |= SiS_SD_ISMERGEDFB;
7076#endif
7077
7078    /* Try to determine if this is a laptop   */
7079    /* (only used for SiSCtrl visualisations) */
7080    pSiS->SiS_SD2_Flags |= SiS_SD2_SUPPLTFLAG;
7081    pSiS->SiS_SD2_Flags &= ~SiS_SD2_ISLAPTOP;
7082    if(pSiS->detectedCRT2Devices & CRT2_LCD) {
7083       if(pSiS->VBFlags2 & (VB2_SISLVDSBRIDGE | VB2_LVDS | VB2_30xBDH)) {
7084	  /* 1. By bridge type: LVDS in 99% of all cases;
7085	   * exclude unusual setups like Barco projectors
7086	   * and parallel flat panels. TODO: Exclude
7087	   * Sony W1, V1.
7088	   */
7089	  if((pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
7090	     (pSiS->SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
7091	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL848)  &&
7092	     (pSiS->SiS_Pr->SiS_CustomT != CUT_PANEL856)  &&
7093	     (pSiS->SiS_Pr->SiS_CustomT != CUT_AOP8060)   &&
7094	     ( (pSiS->ChipType != SIS_550) ||
7095	       (!pSiS->DSTN && !pSiS->FSTN) ) ) {
7096	     pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
7097	  }
7098       } else if((pSiS->VBFlags2 & (VB2_301 | VB2_301C)) &&
7099                 (pSiS->VBLCDFlags & (VB_LCD_1280x960  |
7100				      VB_LCD_1400x1050 |
7101				      VB_LCD_1024x600  |
7102				      VB_LCD_1280x800  |
7103				      VB_LCD_1280x854))) {
7104	  /* 2. By (odd) LCD resolutions on TMDS bridges
7105	   * (eg Averatec). TODO: Exclude IBM Netvista.
7106	   */
7107	  pSiS->SiS_SD2_Flags |= SiS_SD2_ISLAPTOP;
7108       }
7109    }
7110
7111    if(pSiS->enablesisctrl) pSiS->SiS_SD_Flags |= SiS_SD_ENABLED;
7112
7113    pSiS->currentModeLast = pScrn->currentMode;
7114    pSiS->VBFlagsInit = pSiS->VBFlags;
7115
7116    return TRUE;
7117
7118    /* ---- */
7119
7120my_error_1:
7121    sisRestoreExtRegisterLock(pSiS, srlockReg, crlockReg);
7122my_error_0:
7123#ifdef SISDUALHEAD
7124    if(pSiSEnt) pSiSEnt->ErrorAfterFirst = TRUE;
7125#endif
7126    if(pSiS->pInt) xf86FreeInt10(pSiS->pInt);
7127    pSiS->pInt = NULL;
7128    SISFreeRec(pScrn);
7129    return FALSE;
7130}
7131
7132/*
7133 * Map I/O port area for non-PC platforms
7134 */
7135#ifdef SIS_NEED_MAP_IOP
7136static Bool
7137SISMapIOPMem(ScrnInfoPtr pScrn)
7138{
7139    SISPtr pSiS = SISPTR(pScrn);
7140#ifdef SISDUALHEAD
7141    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7142
7143    if(pSiS->DualHeadMode) {
7144        pSiSEnt->MapCountIOPBase++;
7145        if(!(pSiSEnt->IOPBase)) {
7146	     /* Only map if not mapped previously */
7147	     pSiSEnt->IOPBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7148			pSiS->PciTag, pSiS->IOPAddress, 128);
7149        }
7150        pSiS->IOPBase = pSiSEnt->IOPBase;
7151    } else
7152#endif
7153	pSiS->IOPBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7154			pSiS->PciTag, pSiS->IOPAddress, 128);
7155
7156    if(pSiS->IOPBase == NULL) {
7157	SISErrorLog(pScrn, "Could not map I/O port area\n");
7158	return FALSE;
7159    }
7160
7161    return TRUE;
7162}
7163
7164static Bool
7165SISUnmapIOPMem(ScrnInfoPtr pScrn)
7166{
7167    SISPtr pSiS = SISPTR(pScrn);
7168#ifdef SISDUALHEAD
7169    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
7170#endif
7171
7172/* In dual head mode, we must not unmap if the other head still
7173 * assumes memory as mapped
7174 */
7175#ifdef SISDUALHEAD
7176    if(pSiS->DualHeadMode) {
7177        if(pSiSEnt->MapCountIOPBase) {
7178	    pSiSEnt->MapCountIOPBase--;
7179	    if((pSiSEnt->MapCountIOPBase == 0) || (pSiSEnt->forceUnmapIOPBase)) {
7180		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOPBase, 2048);
7181		pSiSEnt->IOPBase = NULL;
7182		pSiSEnt->MapCountIOPBase = 0;
7183		pSiSEnt->forceUnmapIOPBase = FALSE;
7184	    }
7185	    pSiS->IOPBase = NULL;
7186	}
7187    } else {
7188#endif
7189	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOPBase, 2048);
7190	pSiS->IOPBase = NULL;
7191#ifdef SISDUALHEAD
7192    }
7193#endif
7194    return TRUE;
7195}
7196#endif
7197
7198/*
7199 * Map the framebuffer and MMIO memory
7200 */
7201
7202static Bool
7203SISMapMem(ScrnInfoPtr pScrn)
7204{
7205    SISPtr pSiS = SISPTR(pScrn);
7206    int mmioFlags = VIDMEM_MMIO;
7207#ifdef SISDUALHEAD
7208    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7209#endif
7210
7211    /*
7212     * Map IO registers to virtual address space
7213     * (For Alpha, we need to map SPARSE memory, since we need
7214     * byte/short access.)
7215     */
7216#if defined(__alpha__)
7217    mmioFlags |= VIDMEM_SPARSE;
7218#endif
7219
7220#ifdef SISDUALHEAD
7221    if(pSiS->DualHeadMode) {
7222        pSiSEnt->MapCountIOBase++;
7223        if(!(pSiSEnt->IOBase)) {
7224	     /* Only map if not mapped previously */
7225    	     pSiSEnt->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7226                         pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7227        }
7228        pSiS->IOBase = pSiSEnt->IOBase;
7229    } else
7230#endif
7231    	pSiS->IOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags,
7232                        pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7233
7234    if(pSiS->IOBase == NULL) {
7235    	SISErrorLog(pScrn, "Could not map MMIO area\n");
7236        return FALSE;
7237    }
7238
7239#ifdef __alpha__
7240    /*
7241     * for Alpha, we need to map DENSE memory as well, for
7242     * setting CPUToScreenColorExpandBase.
7243     */
7244#ifdef SISDUALHEAD
7245    if(pSiS->DualHeadMode) {
7246        pSiSEnt->MapCountIOBaseDense++;
7247        if(!(pSiSEnt->IOBaseDense)) {
7248	     /* Only map if not mapped previously */
7249	     pSiSEnt->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7250                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7251	}
7252	pSiS->IOBaseDense = pSiSEnt->IOBaseDense;
7253    } else
7254#endif
7255    	pSiS->IOBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
7256                    pSiS->PciTag, pSiS->IOAddress, (pSiS->mmioSize * 1024));
7257
7258    if(pSiS->IOBaseDense == NULL) {
7259       SISErrorLog(pScrn, "Could not map MMIO dense area\n");
7260       return FALSE;
7261    }
7262#endif /* __alpha__ */
7263
7264#ifdef SISDUALHEAD
7265    if(pSiS->DualHeadMode) {
7266	pSiSEnt->MapCountFbBase++;
7267	if(!(pSiSEnt->FbBase)) {
7268	     /* Only map if not mapped previously */
7269	     pSiSEnt->FbBase = pSiSEnt->RealFbBase =
7270			xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7271			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7272			 pSiS->FbMapSize);
7273	}
7274	pSiS->FbBase = pSiS->RealFbBase = pSiSEnt->FbBase;
7275	/* Adapt FbBase (for DHM and SiS76x UMA skipping; dhmOffset is 0 otherwise) */
7276	pSiS->FbBase += pSiS->dhmOffset;
7277    } else {
7278#endif
7279	pSiS->FbBase = pSiS->RealFbBase =
7280		xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
7281			 pSiS->PciTag, (ULong)pSiS->realFbAddress,
7282			 pSiS->FbMapSize);
7283	pSiS->FbBase += pSiS->dhmOffset;
7284#ifdef SISDUALHEAD
7285    }
7286#endif
7287
7288    if(pSiS->FbBase == NULL) {
7289       SISErrorLog(pScrn, "Could not map framebuffer area\n");
7290       return FALSE;
7291    }
7292
7293#ifdef TWDEBUG
7294    xf86DrvMsg(0, 0, "Framebuffer mapped to %p\n", pSiS->FbBase);
7295#endif
7296
7297    return TRUE;
7298}
7299
7300
7301/*
7302 * Unmap the framebuffer and MMIO memory.
7303 */
7304
7305static Bool
7306SISUnmapMem(ScrnInfoPtr pScrn)
7307{
7308    SISPtr pSiS = SISPTR(pScrn);
7309#ifdef SISDUALHEAD
7310    SISEntPtr pSiSEnt = pSiS->entityPrivate;
7311#endif
7312
7313/* In dual head mode, we must not unmap if the other head still
7314 * assumes memory as mapped
7315 */
7316#ifdef SISDUALHEAD
7317    if(pSiS->DualHeadMode) {
7318        if(pSiSEnt->MapCountIOBase) {
7319	    pSiSEnt->MapCountIOBase--;
7320	    if((pSiSEnt->MapCountIOBase == 0) || (pSiSEnt->forceUnmapIOBase)) {
7321		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBase, (pSiS->mmioSize * 1024));
7322		pSiSEnt->IOBase = NULL;
7323		pSiSEnt->MapCountIOBase = 0;
7324		pSiSEnt->forceUnmapIOBase = FALSE;
7325	    }
7326	    pSiS->IOBase = NULL;
7327	}
7328#ifdef __alpha__
7329	if(pSiSEnt->MapCountIOBaseDense) {
7330	    pSiSEnt->MapCountIOBaseDense--;
7331	    if((pSiSEnt->MapCountIOBaseDense == 0) || (pSiSEnt->forceUnmapIOBaseDense)) {
7332		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->IOBaseDense, (pSiS->mmioSize * 1024));
7333		pSiSEnt->IOBaseDense = NULL;
7334		pSiSEnt->MapCountIOBaseDense = 0;
7335		pSiSEnt->forceUnmapIOBaseDense = FALSE;
7336	    }
7337	    pSiS->IOBaseDense = NULL;
7338	}
7339#endif /* __alpha__ */
7340	if(pSiSEnt->MapCountFbBase) {
7341	    pSiSEnt->MapCountFbBase--;
7342	    if((pSiSEnt->MapCountFbBase == 0) || (pSiSEnt->forceUnmapFbBase)) {
7343		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiSEnt->RealFbBase, pSiS->FbMapSize);
7344		pSiSEnt->FbBase = pSiSEnt->RealFbBase = NULL;
7345		pSiSEnt->MapCountFbBase = 0;
7346		pSiSEnt->forceUnmapFbBase = FALSE;
7347
7348	    }
7349	    pSiS->FbBase = pSiS->RealFbBase = NULL;
7350	}
7351    } else {
7352#endif
7353	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBase, (pSiS->mmioSize * 1024));
7354	pSiS->IOBase = NULL;
7355#ifdef __alpha__
7356	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->IOBaseDense, (pSiS->mmioSize * 1024));
7357	pSiS->IOBaseDense = NULL;
7358#endif
7359	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSiS->RealFbBase, pSiS->FbMapSize);
7360	pSiS->FbBase = pSiS->RealFbBase = NULL;
7361#ifdef SISDUALHEAD
7362    }
7363#endif
7364    return TRUE;
7365}
7366
7367/*
7368 * This function saves the video state.
7369 */
7370static void
7371SISSave(ScrnInfoPtr pScrn)
7372{
7373    SISPtr pSiS = SISPTR(pScrn);
7374    SISRegPtr sisReg;
7375    int flags;
7376
7377#ifdef SISDUALHEAD
7378    /* We always save master & slave */
7379    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7380#endif
7381
7382    sisReg = &pSiS->SavedReg;
7383
7384    if( ((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) &&
7385        ((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) ) {
7386       SiSVGASave(pScrn, sisReg, SISVGA_SR_CMAP | SISVGA_SR_MODE);
7387#ifdef SIS_PC_PLATFORM
7388       if(pSiS->VGAMemBase) {
7389          SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7390          SiSSetLVDSetc(pSiS->SiS_Pr, 0);
7391          SiS_GetVBType(pSiS->SiS_Pr);
7392          SiS_DisableBridge(pSiS->SiS_Pr);
7393          SiSVGASave(pScrn, sisReg, SISVGA_SR_FONTS);
7394          SiS_EnableBridge(pSiS->SiS_Pr);
7395       }
7396#endif
7397    } else {
7398       flags = SISVGA_SR_CMAP | SISVGA_SR_MODE;
7399#ifdef SIS_PC_PLATFORM
7400       if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7401#endif
7402       SiSVGASave(pScrn, sisReg, flags);
7403    }
7404
7405    sisSaveUnlockExtRegisterLock(pSiS, &sisReg->sisRegs3C4[0x05], &sisReg->sisRegs3D4[0x80]);
7406
7407    (*pSiS->SiSSave)(pScrn, sisReg);
7408
7409    if(pSiS->UseVESA) SISVESASaveRestore(pScrn, MODE_SAVE);
7410
7411    /* "Save" these again as they may have been changed prior to SISSave() call */
7412    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7413       sisReg->sisRegs3C4[0x1f] = pSiS->oldSR1F;
7414       sisReg->sisRegs3D4[0x17] = pSiS->oldCR17;
7415       sisReg->sisRegs3D4[0x32] = pSiS->oldCR32;
7416       sisReg->sisRegs3D4[0x36] = pSiS->oldCR36;
7417       sisReg->sisRegs3D4[0x37] = pSiS->oldCR37;
7418       if(pSiS->VGAEngine == SIS_315_VGA) {
7419	  sisReg->sisRegs3D4[pSiS->myCR63] = pSiS->oldCR63;
7420       }
7421    }
7422}
7423
7424/* VESASaveRestore taken from vesa driver */
7425static void
7426SISVESASaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
7427{
7428    SISPtr pSiS = SISPTR(pScrn);
7429
7430    /* Query amount of memory to save state */
7431    if((function == MODE_QUERY) ||
7432       (function == MODE_SAVE && pSiS->state == NULL)) {
7433
7434       /* Make sure we save at least this information in case of failure */
7435       (void)VBEGetVBEMode(pSiS->pVbe, &pSiS->stateMode);
7436       SiSVGASaveFonts(pScrn);
7437
7438       if(pSiS->vesamajor > 1) {
7439	  if(!VBESaveRestore(pSiS->pVbe, function, (pointer)&pSiS->state,
7440				&pSiS->stateSize, &pSiS->statePage)) {
7441	     return;
7442	  }
7443       }
7444    }
7445
7446    /* Save/Restore Super VGA state */
7447    if(function != MODE_QUERY) {
7448
7449       if(pSiS->vesamajor > 1) {
7450	  if(function == MODE_RESTORE) {
7451	     memcpy(pSiS->state, pSiS->pstate, pSiS->stateSize);
7452	  }
7453
7454	  if(VBESaveRestore(pSiS->pVbe,function,(pointer)&pSiS->state,
7455			    &pSiS->stateSize,&pSiS->statePage) &&
7456	     (function == MODE_SAVE)) {
7457	     /* don't rely on the memory not being touched */
7458	     if(!pSiS->pstate) {
7459		pSiS->pstate = xalloc(pSiS->stateSize);
7460	     }
7461	     memcpy(pSiS->pstate, pSiS->state, pSiS->stateSize);
7462	  }
7463       }
7464
7465       if(function == MODE_RESTORE) {
7466	  VBESetVBEMode(pSiS->pVbe, pSiS->stateMode, NULL);
7467	  SiSVGARestoreFonts(pScrn);
7468       }
7469
7470    }
7471}
7472
7473/*
7474 * Initialise a new mode.  This is currently done using the
7475 * "initialise struct, restore/write struct to HW" model for
7476 * the old chipsets (5597/530/6326). For newer chipsets,
7477 * we use our own mode switching code.
7478 */
7479
7480static Bool
7481SISModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
7482{
7483    SISPtr pSiS = SISPTR(pScrn);
7484    SISRegPtr sisReg;
7485#ifdef SISDUALHEAD
7486    SISEntPtr pSiSEnt = NULL;
7487#endif
7488
7489    andSISIDXREG(SISCR,0x11,0x7f);	/* Unlock CRTC registers */
7490
7491    SISModifyModeInfo(mode);		/* Quick check of the mode parameters */
7492
7493    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7494       SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
7495    }
7496
7497    if(pSiS->UseVESA) {  /* With VESA: */
7498
7499#ifdef SISDUALHEAD
7500       /* No dual head mode when using VESA */
7501       if(pSiS->SecondHead) return TRUE;
7502#endif
7503
7504       pScrn->vtSema = TRUE;
7505
7506       /*
7507	* This order is required:
7508	* The video bridge needs to be adjusted before the
7509	* BIOS is run as the BIOS sets up CRT2 according to
7510	* these register settings.
7511	* After the BIOS is run, the bridges and turboqueue
7512	* registers need to be readjusted as the BIOS may
7513	* very probably have messed them up.
7514	*/
7515       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7516	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7517       }
7518       if(!SiSSetVESAMode(pScrn, mode)) {
7519	  SISErrorLog(pScrn, "SiSSetVESAMode() failed\n");
7520	  return FALSE;
7521       }
7522       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7523       if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7524	  SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7525	  SiSPostSetMode(pScrn, &pSiS->ModeReg);
7526       }
7527#ifdef TWDEBUG
7528       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7529		   "REAL REGISTER CONTENTS AFTER SETMODE:\n");
7530#endif
7531       if(!(*pSiS->ModeInit)(pScrn, mode)) {
7532	  SISErrorLog(pScrn, "ModeInit() failed\n");
7533	  return FALSE;
7534       }
7535
7536       SiSVGAProtect(pScrn, TRUE);
7537       (*pSiS->SiSRestore)(pScrn, &pSiS->ModeReg);
7538       SiSVGAProtect(pScrn, FALSE);
7539
7540    } else { /* Without VESA: */
7541
7542#ifdef SISDUALHEAD
7543       if(pSiS->DualHeadMode) {
7544
7545	  if(!(*pSiS->ModeInit)(pScrn, mode)) {
7546	     SISErrorLog(pScrn, "ModeInit() failed\n");
7547	     return FALSE;
7548	  }
7549
7550	  pScrn->vtSema = TRUE;
7551
7552	  pSiSEnt = pSiS->entityPrivate;
7553
7554	  if(!(pSiS->SecondHead)) {
7555	     /* Head 1 (master) is always CRT2 */
7556	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7557	     if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7558		SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7559		return FALSE;
7560	     }
7561	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7562	     if(pSiSEnt->pScrn_2) {
7563		SISAdjustFrame(pSiSEnt->pScrn_2->scrnIndex,
7564			       pSiSEnt->pScrn_2->frameX0,
7565			       pSiSEnt->pScrn_2->frameY0, 0);
7566	     }
7567	  } else {
7568	     /* Head 2 (slave) is always CRT1 */
7569	     SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7570	     if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn, mode, pSiS->IsCustom)) {
7571		SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7572		return FALSE;
7573	     }
7574	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7575	     if(pSiSEnt->pScrn_1) {
7576		SISAdjustFrame(pSiSEnt->pScrn_1->scrnIndex,
7577			       pSiSEnt->pScrn_1->frameX0,
7578			       pSiSEnt->pScrn_1->frameY0, 0);
7579	     }
7580	  }
7581
7582       } else {
7583#endif
7584
7585	  if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
7586
7587	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7588		SISErrorLog(pScrn, "ModeInit() failed\n");
7589	        return FALSE;
7590	     }
7591
7592	     pScrn->vtSema = TRUE;
7593
7594#ifdef SISMERGED
7595	     if(pSiS->MergedFB) {
7596
7597		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting MergedFB mode %dx%d\n",
7598				mode->HDisplay, mode->VDisplay);
7599
7600		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7601
7602		if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7603		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
7604				       pSiS->IsCustom)) {
7605		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7606		   return FALSE;
7607		}
7608
7609		SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7610
7611		if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7612		                       ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
7613				       pSiS->IsCustom)) {
7614		   SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7615		   return FALSE;
7616		}
7617
7618	     } else {
7619#endif
7620
7621		if((pSiS->VBFlags & CRT1_LCDA) || (!(mode->type & M_T_DEFAULT))) {
7622
7623		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT1);
7624
7625		   if(!SiSBIOSSetModeCRT1(pSiS->SiS_Pr, pScrn,
7626				mode, pSiS->IsCustom)) {
7627		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT1() failed\n");
7628		      return FALSE;
7629		   }
7630
7631		   SiSPreSetMode(pScrn, mode, SIS_MODE_CRT2);
7632
7633		   if(!SiSBIOSSetModeCRT2(pSiS->SiS_Pr, pScrn,
7634				mode, pSiS->IsCustom)) {
7635		      SISErrorLog(pScrn, "SiSBIOSSetModeCRT2() failed\n");
7636		      return FALSE;
7637		   }
7638
7639		} else {
7640
7641		   SiSPreSetMode(pScrn, mode, SIS_MODE_SIMU);
7642
7643		   if(!SiSBIOSSetMode(pSiS->SiS_Pr, pScrn,
7644				mode, pSiS->IsCustom)) {
7645		      SISErrorLog(pScrn, "SiSBIOSSetMode() failed\n");
7646		      return FALSE;
7647		   }
7648
7649		}
7650
7651#ifdef SISMERGED
7652	     }
7653#endif
7654
7655	     SiSPostSetMode(pScrn, &pSiS->ModeReg);
7656
7657#ifdef TWDEBUG
7658	     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBFlags %lx\n", pSiS->VBFlags);
7659	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7660			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7661             (*pSiS->ModeInit)(pScrn, mode);
7662#endif
7663
7664	  } else {
7665
7666	     /* For other chipsets, use the old method */
7667
7668	     /* Prepare the register contents */
7669	     if(!(*pSiS->ModeInit)(pScrn, mode)) {
7670	        SISErrorLog(pScrn, "ModeInit() failed\n");
7671	        return FALSE;
7672	     }
7673
7674	     pScrn->vtSema = TRUE;
7675
7676	     /* Program the registers */
7677	     SiSVGAProtect(pScrn, TRUE);
7678	     sisReg = &pSiS->ModeReg;
7679
7680	     sisReg->sisRegsATTR[0x10] = 0x01;
7681	     if(pScrn->bitsPerPixel > 8) {
7682		sisReg->sisRegsGR[0x05] = 0x00;
7683	     }
7684
7685	     SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
7686
7687	     (*pSiS->SiSRestore)(pScrn, sisReg);
7688
7689	     if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
7690	        SiS6326PostSetMode(pScrn, &pSiS->ModeReg);
7691	     }
7692
7693#ifdef TWDEBUG
7694	     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
7695			"REAL REGISTER CONTENTS AFTER SETMODE:\n");
7696	     (*pSiS->ModeInit)(pScrn, mode);
7697#endif
7698
7699	     SiSVGAProtect(pScrn, FALSE);
7700
7701	  }
7702
7703#ifdef SISDUALHEAD
7704       }
7705#endif
7706    }
7707
7708    /* Update Currentlayout */
7709    pSiS->CurrentLayout.mode = pSiS->currentModeLast = mode;
7710
7711    return TRUE;
7712}
7713
7714static Bool
7715SiSSetVESAMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
7716{
7717    SISPtr pSiS;
7718    int mode;
7719
7720    pSiS = SISPTR(pScrn);
7721
7722    if(!(mode = SiSCalcVESAModeIndex(pScrn, pMode))) return FALSE;
7723
7724    mode |= (1 << 15);	/* Don't clear framebuffer */
7725    mode |= (1 << 14); 	/* Use linear adressing */
7726
7727    if(VBESetVBEMode(pSiS->pVbe, mode, NULL) == FALSE) {
7728       SISErrorLog(pScrn, "Setting VESA mode 0x%x failed\n",
7729	             	mode & 0x0fff);
7730       return (FALSE);
7731    }
7732
7733    if(pMode->HDisplay != pScrn->virtualX) {
7734       VBESetLogicalScanline(pSiS->pVbe, pScrn->virtualX);
7735    }
7736
7737    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
7738    	"Setting VESA mode 0x%x succeeded\n",
7739	mode & 0x0fff);
7740
7741    return (TRUE);
7742}
7743
7744static void
7745SISSpecialRestore(ScrnInfoPtr pScrn)
7746{
7747    SISPtr    pSiS = SISPTR(pScrn);
7748    SISRegPtr sisReg = &pSiS->SavedReg;
7749    UChar temp;
7750    int i;
7751
7752    /* 1.11.04 and later for 651 and 301B(DH) do strange register
7753     * fiddling after the usual mode change. This happens
7754     * depending on the result of a call of int 2f (with
7755     * ax=0x1680) and if modeno <= 0x13. I have no idea if
7756     * that is specific for the 651 or that very machine.
7757     * So this perhaps requires some more checks in the beginning
7758     * (although it should not do any harm on other chipsets/bridges
7759     * etc.) However, even if I call the VBE to restore mode 0x03,
7760     * these registers don't get restored correctly, possibly
7761     * because that int-2f-call for some reason results non-zero. So
7762     * what I do here is to restore these few registers
7763     * manually.
7764     */
7765
7766    if(!(pSiS->ChipFlags & SiSCF_Is65x)) return;
7767    inSISIDXREG(SISCR, 0x34, temp);
7768    temp &= 0x7f;
7769    if(temp > 0x13) return;
7770
7771#ifdef UNLOCK_ALWAYS
7772    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7773#endif
7774
7775    SiS_UnLockCRT2(pSiS->SiS_Pr);
7776
7777    outSISIDXREG(SISCAP, 0x3f, sisReg->sisCapt[0x3f]);
7778    outSISIDXREG(SISCAP, 0x00, sisReg->sisCapt[0x00]);
7779    for(i = 0; i < 0x4f; i++) {
7780       outSISIDXREG(SISCAP, i, sisReg->sisCapt[i]);
7781    }
7782    outSISIDXREG(SISVID, 0x32, (sisReg->sisVid[0x32] & ~0x05));
7783    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7784    outSISIDXREG(SISVID, 0x32, ((sisReg->sisVid[0x32] & ~0x04) | 0x01));
7785    outSISIDXREG(SISVID, 0x30, sisReg->sisVid[0x30]);
7786
7787    if(!(pSiS->ChipFlags & SiSCF_Is651)) return;
7788    if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
7789
7790    inSISIDXREG(SISCR, 0x30, temp);
7791    if(temp & 0x40) {
7792       UChar myregs[] = {
7793       		0x2f, 0x08, 0x09, 0x03, 0x0a, 0x0c,
7794		0x0b, 0x0d, 0x0e, 0x12, 0x0f, 0x10,
7795		0x11, 0x04, 0x05, 0x06, 0x07, 0x00,
7796		0x2e
7797       };
7798       for(i = 0; i <= 18; i++) {
7799          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7800       }
7801    } else if((temp & 0x20) || (temp & 0x9c)) {
7802       UChar myregs[] = {
7803       		0x04, 0x05, 0x06, 0x07, 0x00, 0x2e
7804       };
7805       for(i = 0; i <= 5; i++) {
7806          outSISIDXREG(SISPART1, myregs[i], sisReg->VBPart1[myregs[i]]);
7807       }
7808    }
7809}
7810
7811/* Fix SR11 for 661 and later */
7812static void
7813SiSFixupSR11(ScrnInfoPtr pScrn)
7814{
7815    SISPtr pSiS = SISPTR(pScrn);
7816    CARD8  tmpreg;
7817
7818#ifdef UNLOCK_ALWAYS
7819    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7820#endif
7821
7822    if(pSiS->ChipType >= SIS_661) {
7823       inSISIDXREG(SISSR,0x11,tmpreg);
7824       if(tmpreg & 0x20) {
7825          inSISIDXREG(SISSR,0x3e,tmpreg);
7826	  tmpreg = (tmpreg + 1) & 0xff;
7827	  outSISIDXREG(SISSR,0x3e,tmpreg);
7828       }
7829
7830       inSISIDXREG(SISSR,0x11,tmpreg);
7831       if(tmpreg & 0xf0) {
7832          andSISIDXREG(SISSR,0x11,0x0f);
7833       }
7834    }
7835}
7836
7837/* Subroutine for restoring sisfb's TV parameters (used by SiSRestore()) */
7838
7839static void
7840SiSRestore_SiSFB_TVParms(ScrnInfoPtr pScrn)
7841{
7842    SISPtr  pSiS = SISPTR(pScrn);
7843    int     fd;
7844    CARD32  parm;
7845
7846    if(!pSiS->sisfbfound) return;
7847    if(!pSiS->sisfb_tvposvalid) return;
7848    if(!(pSiS->sisfbdevname[0])) return;
7849
7850    if((fd = open(pSiS->sisfbdevname, 'r')) != -1) {
7851       parm = (CARD32)((pSiS->sisfb_tvxpos << 16) | (pSiS->sisfb_tvypos & 0xffff));
7852       ioctl(fd, SISFB_SET_TVPOSOFFSET, &parm);
7853       close(fd);
7854    }
7855}
7856
7857/*
7858 * Restore the initial mode. To be used internally only!
7859 */
7860static void
7861SISRestore(ScrnInfoPtr pScrn)
7862{
7863    SISPtr    pSiS = SISPTR(pScrn);
7864    SISRegPtr sisReg = &pSiS->SavedReg;
7865    Bool      doit = FALSE, doitlater = FALSE;
7866    Bool      vesasuccess = FALSE;
7867    int	      flags;
7868
7869    /* WARNING: Don't ever touch this. It now seems to work on
7870     * all chipset/bridge combinations - but finding out the
7871     * correct combination was pure hell.
7872     */
7873
7874    /* Wait for the accelerators */
7875    (*pSiS->SyncAccel)(pScrn);
7876
7877    /* Set up restore flags */
7878    flags = SISVGA_SR_MODE | SISVGA_SR_CMAP;
7879#ifdef SIS_PC_PLATFORM
7880    /* We now restore ALL to overcome the vga=extended problem */
7881    if(pSiS->VGAMemBase) flags |= SISVGA_SR_FONTS;
7882#endif
7883
7884    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
7885
7886#ifdef SISDUALHEAD
7887       /* We always restore master AND slave */
7888       if(pSiS->DualHeadMode && pSiS->SecondHead) return;
7889#endif
7890
7891#ifdef UNLOCK_ALWAYS
7892       sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
7893#endif
7894
7895       /* We must not disable the sequencer if the bridge is in SlaveMode! */
7896       if(!(SiSBridgeIsInSlaveMode(pScrn))) {
7897	  SiSVGAProtect(pScrn, TRUE);
7898       }
7899
7900       /* First, restore CRT1 on/off and VB connection registers */
7901       outSISIDXREG(SISCR, 0x32, pSiS->oldCR32);
7902       if(!(pSiS->oldCR17 & 0x80)) {			/* CRT1 was off */
7903	  if(!(SiSBridgeIsInSlaveMode(pScrn))) {        /* Bridge is NOT in SlaveMode now -> do it */
7904	     doit = TRUE;
7905	  } else {
7906	     doitlater = TRUE;
7907	  }
7908       } else {						/* CRT1 was on -> do it now */
7909	  doit = TRUE;
7910       }
7911
7912       if(doit) {
7913	  outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
7914       }
7915       if(pSiS->VGAEngine == SIS_315_VGA) {
7916	  outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
7917       }
7918
7919       outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
7920
7921       /* For 30xB/LV, restoring the registers does not
7922	* work. We "manually" set the old mode, instead.
7923	* The same applies for SiS730 machines with LVDS.
7924	* Finally, this behavior can be forced by setting
7925	* the option RestoreBySetMode.
7926	*/
7927	if( ( (pSiS->restorebyset) ||
7928	      (pSiS->VBFlags2 & VB2_30xBLV) ||
7929	      ((pSiS->ChipType == SIS_730) && (pSiS->VBFlags2 & VB2_LVDS)) )     &&
7930	    (pSiS->OldMode) ) {
7931
7932	   Bool changedmode = FALSE;
7933
7934	   xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7935	         "Restoring by setting old mode 0x%02x\n", pSiS->OldMode);
7936
7937	   if(((pSiS->OldMode <= 0x13) || (!pSiS->sisfbfound)) && (pSiS->pVbe)) {
7938	      int vmode = SiSTranslateToVESA(pScrn, pSiS->OldMode);
7939	      if(vmode > 0) {
7940		 if(vmode > 0x13) vmode |= ((1 << 15) | (1 << 14));
7941		 if(VBESetVBEMode(pSiS->pVbe, vmode, NULL) == TRUE) {
7942		    SISSpecialRestore(pScrn);
7943		    SiS_GetSetModeID(pScrn,pSiS->OldMode);
7944		    vesasuccess = TRUE;
7945		 } else {
7946		    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7947			"VBE failed to restore mode 0x%x\n", pSiS->OldMode);
7948		 }
7949	      } else {
7950		 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
7951		 	"Can't identify VESA mode number for mode 0x%x\n", pSiS->OldMode);
7952	      }
7953	   }
7954
7955	   if(vesasuccess == FALSE) {
7956
7957	      int backupscaler = pSiS->SiS_Pr->UsePanelScaler;
7958	      int backupcenter = pSiS->SiS_Pr->CenterScreen;
7959	      ULong backupspecialtiming = pSiS->SiS_Pr->SiS_CustomT;
7960	      int mymode = pSiS->OldMode;
7961
7962	      if((pSiS->VGAEngine == SIS_315_VGA)			&&
7963	         ((pSiS->ROM661New) || (pSiS->ChipFlags & SiSCF_IsXGI)) &&
7964		 (!pSiS->sisfbfound)) {
7965	         /* New SiS BIOS or XGI BIOS has set mode, therefore eventually translate number */
7966	         mymode = SiSTranslateToOldMode(mymode);
7967	      }
7968
7969 	      if((pSiS->VBFlags2 & VB2_30xBLV)) {
7970	        /* !!! REQUIRED for 630+301B-DH, otherwise the text modes
7971	         *     will not be restored correctly !!!
7972	         * !!! Do this ONLY for LCD; VGA2 will not be restored
7973	         *     correctly otherwise.
7974	         */
7975	         UChar temp;
7976	         inSISIDXREG(SISCR, 0x30, temp);
7977	         if(temp & 0x20) {
7978	            if(mymode == 0x03) {
7979		       mymode = 0x13;
7980		       changedmode = TRUE;
7981	            }
7982	         }
7983	      }
7984
7985	      pSiS->SiS_Pr->UseCustomMode = FALSE;
7986	      pSiS->SiS_Pr->CRT1UsesCustomMode = FALSE;
7987	      pSiS->SiS_Pr->CenterScreen = 0;
7988	      if(pSiS->sisfbfound) {
7989		 pSiS->SiS_Pr->UsePanelScaler = pSiS->sisfbscalelcd;
7990		 pSiS->SiS_Pr->SiS_CustomT = pSiS->sisfbspecialtiming;
7991	      } else {
7992		 pSiS->SiS_Pr->UsePanelScaler = -1;
7993		 /* Leave CustomT as it is */
7994	      }
7995	      SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
7996	      SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
7997	      if((pSiS->ChipType == SIS_550) && (pSiS->sisfbfound)) {
7998		 if(pSiS->sisfbxSTN) {
7999		    SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->sisfbDSTN);
8000		    SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->sisfbFSTN);
8001		 } else if(mymode == 0x5a || mymode == 0x5b) {
8002		    SiS_SetEnableFstn(pSiS->SiS_Pr, TRUE);
8003		 }
8004	      }
8005	      SiSSetMode(pSiS->SiS_Pr, pScrn, mymode, FALSE);
8006	      if(changedmode) {
8007		 outSISIDXREG(SISCR,0x34,0x03);
8008	      }
8009	      SISSpecialRestore(pScrn);
8010	      SiS_GetSetModeID(pScrn, pSiS->OldMode); /* NOT mymode! */
8011	      pSiS->SiS_Pr->UsePanelScaler = backupscaler;
8012	      pSiS->SiS_Pr->CenterScreen = backupcenter;
8013	      pSiS->SiS_Pr->SiS_CustomT = backupspecialtiming;
8014	      SiS_SiSFB_Lock(pScrn, FALSE);
8015	      SiSRestore_SiSFB_TVParms(pScrn);
8016	      SiS_SiSFB_Lock(pScrn, TRUE);
8017
8018	   }
8019
8020	   /* Restore CRT1 status */
8021	   if(pSiS->VGAEngine == SIS_315_VGA) {
8022              outSISIDXREG(SISCR, pSiS->myCR63, pSiS->oldCR63);
8023           }
8024           outSISIDXREG(SISSR, 0x1f, pSiS->oldSR1F);
8025
8026#ifdef SISVRAMQ
8027	   /* Restore queue mode registers on 315/330/340 series */
8028	   /* (This became necessary due to the switch to VRAM queue) */
8029	   SiSRestoreQueueMode(pSiS, sisReg);
8030#endif
8031
8032        } else {
8033
8034	   if(pSiS->VBFlags2 & VB2_VIDEOBRIDGE) {
8035	      /* If a video bridge is present, we need to restore
8036	       * non-extended (=standard VGA) SR and CR registers
8037	       * before restoring the extended ones and the bridge
8038	       * registers.
8039	       */
8040	      if(!(SiSBridgeIsInSlaveMode(pScrn))) {
8041                 SiSVGAProtect(pScrn, TRUE);
8042	         SiSVGARestore(pScrn, sisReg, SISVGA_SR_MODE);
8043              }
8044	   }
8045
8046           (*pSiS->SiSRestore)(pScrn, sisReg);
8047
8048        }
8049
8050	if(doitlater) {
8051           outSISIDXREG(SISCR, 0x17, pSiS->oldCR17);
8052	}
8053
8054
8055
8056	if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (SiSBridgeIsInSlaveMode(pScrn))) {
8057
8058	   /* IMPORTANT: The 30xLV does not handle well being disabled if in
8059	    * LCDA mode! In LCDA mode, the bridge is NOT in slave mode,
8060	    * so this is the only safe way: Disable the bridge ONLY if
8061	    * in Slave Mode, and don't bother if not.
8062	    */
8063
8064	   if(flags & SISVGA_SR_FONTS) {
8065              SiSRegInit(pSiS->SiS_Pr, pSiS->RelIO+0x30);
8066	      SiSSetLVDSetc(pSiS->SiS_Pr, 0);
8067	      SiS_GetVBType(pSiS->SiS_Pr);
8068	      SiS_DisableBridge(pSiS->SiS_Pr);
8069	      SiSVGAProtect(pScrn, TRUE);
8070	   }
8071
8072	   SiSVGARestore(pScrn, sisReg, flags);
8073
8074	   if(flags & SISVGA_SR_FONTS) {
8075	      SiSVGAProtect(pScrn, FALSE);
8076	      SiS_EnableBridge(pSiS->SiS_Pr);
8077	      andSISIDXREG(SISSR, 0x01, ~0x20);  /* Display on */
8078	   }
8079
8080	} else {
8081
8082	   SiSVGAProtect(pScrn, TRUE);
8083	   SiSVGARestore(pScrn, sisReg, flags);
8084           SiSVGAProtect(pScrn, FALSE);
8085
8086	}
8087
8088	SiSFixupSR11(pScrn);
8089
8090#ifdef TWDEBUG
8091	{
8092	  SISRegPtr pReg = &pSiS->ModeReg;
8093	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
8094		"REAL REGISTER CONTENTS AFTER RESTORE BY SETMODE:\n");
8095	  (*pSiS->SiSSave)(pScrn, pReg);
8096	}
8097#endif
8098
8099	sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[0x05],sisReg->sisRegs3D4[0x80]);
8100
8101    } else {	/* All other chipsets */
8102
8103        SiSVGAProtect(pScrn, TRUE);
8104
8105#ifdef UNLOCK_ALWAYS
8106        sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8107#endif
8108
8109        (*pSiS->SiSRestore)(pScrn, sisReg);
8110
8111        SiSVGAProtect(pScrn, TRUE);
8112
8113	SiSVGARestore(pScrn, sisReg, flags);
8114
8115	/* Restore TV. This is rather complicated, but if we don't do it,
8116	 * TV output will flicker terribly
8117	 */
8118        if((pSiS->Chipset == PCI_CHIP_SIS6326) && (pSiS->SiS6326Flags & SIS6326_HASTV)) {
8119	   if(sisReg->sis6326tv[0] & 0x04) {
8120	      UChar tmp;
8121	      int val;
8122
8123              orSISIDXREG(SISSR, 0x01, 0x20);
8124              tmp = SiS6326GetTVReg(pScrn,0x00);
8125              tmp &= ~0x04;
8126              while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8127              SiS6326SetTVReg(pScrn,0x00,tmp);
8128              for(val=0; val < 2; val++) {
8129                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8130                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8131              }
8132              SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
8133              tmp = inSISREG(SISINPSTAT);
8134              outSISREG(SISAR, 0x20);
8135              tmp = inSISREG(SISINPSTAT);
8136              while(inSISREG(SISINPSTAT) & 0x01);
8137              while(!(inSISREG(SISINPSTAT) & 0x01));
8138              andSISIDXREG(SISSR, 0x01, ~0x20);
8139              for(val=0; val < 10; val++) {
8140                 while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
8141                 while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
8142              }
8143              andSISIDXREG(SISSR, 0x01, ~0x20);
8144	   }
8145        }
8146
8147        sisRestoreExtRegisterLock(pSiS,sisReg->sisRegs3C4[5],sisReg->sisRegs3D4[0x80]);
8148
8149        SiSVGAProtect(pScrn, FALSE);
8150    }
8151}
8152
8153static void
8154SISVESARestore(ScrnInfoPtr pScrn)
8155{
8156   SISPtr pSiS = SISPTR(pScrn);
8157#ifdef SISVRAMQ
8158   SISRegPtr sisReg = &pSiS->SavedReg;
8159#endif
8160
8161   if(pSiS->UseVESA) {
8162      SISVESASaveRestore(pScrn, MODE_RESTORE);
8163#ifdef SISVRAMQ
8164      /* Restore queue mode registers on 315/330/340 series */
8165      /* (This became necessary due to the switch to VRAM queue) */
8166      SiSRestoreQueueMode(pSiS, sisReg);
8167#endif
8168   }
8169}
8170
8171/* Restore bridge config registers - to be called BEFORE VESARestore */
8172static void
8173SISBridgeRestore(ScrnInfoPtr pScrn)
8174{
8175    SISPtr pSiS = SISPTR(pScrn);
8176
8177#ifdef SISDUALHEAD
8178    /* We only restore for master head */
8179    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
8180#endif
8181
8182    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
8183	SiSRestoreBridge(pScrn, &pSiS->SavedReg);
8184    }
8185}
8186
8187/* Our BlockHandler */
8188static void
8189SISBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
8190{
8191    ScreenPtr pScreen = screenInfo.screens[i];
8192    ScrnInfoPtr pScrn = xf86Screens[i];
8193    SISPtr pSiS = SISPTR(pScrn);
8194
8195    pScreen->BlockHandler = pSiS->BlockHandler;
8196    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
8197    pScreen->BlockHandler = SISBlockHandler;
8198
8199#ifdef SISDUALHEAD
8200    if(pSiS->NeedCopyFastVidCpy) {
8201       SISEntPtr pSiSEnt = pSiS->entityPrivate;
8202       if(pSiSEnt->HaveFastVidCpy) {
8203	  pSiS->NeedCopyFastVidCpy = FALSE;
8204	  pSiS->SiSFastVidCopy = pSiSEnt->SiSFastVidCopy;
8205	  pSiS->SiSFastMemCopy = pSiSEnt->SiSFastMemCopy;
8206	  pSiS->SiSFastVidCopyFrom = pSiSEnt->SiSFastVidCopyFrom;
8207	  pSiS->SiSFastMemCopyFrom = pSiSEnt->SiSFastMemCopyFrom;
8208       }
8209    }
8210#endif
8211
8212    if(pSiS->VideoTimerCallback) {
8213       (*pSiS->VideoTimerCallback)(pScrn, currentTime.milliseconds);
8214    }
8215
8216#ifdef SIS_USE_XAA
8217    if(pSiS->RenderCallback) {
8218       (*pSiS->RenderCallback)(pScrn);
8219    }
8220#endif
8221#ifdef SIS_USE_EXA
8222    if(pSiS->ExaRenderCallback) {
8223       (*pSiS->ExaRenderCallback)(pScrn);
8224    }
8225#endif
8226}
8227
8228
8229
8230/* Do screen blanking; DPMS handling
8231 *
8232 * Mandatory; latter optional
8233 */
8234
8235static void
8236SiSHandleBackLight(SISPtr pSiS, Bool blon)
8237{
8238    UChar sr11mask = (pSiS->SiS_Pr->SiS_SensibleSR11) ? 0x03 : 0xf3;
8239
8240    if(pSiS->VBFlags2 & VB2_SISLVDSBRIDGE) {
8241
8242       if(!blon) {
8243	  SiS_SiS30xBLOff(pSiS->SiS_Pr);
8244       } else {
8245	  SiS_SiS30xBLOn(pSiS->SiS_Pr);
8246       }
8247
8248    } else if( ((pSiS->VGAEngine == SIS_300_VGA) &&
8249	        (pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH))) ||
8250	       ((pSiS->VGAEngine == SIS_315_VGA) &&
8251	        ((pSiS->VBFlags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS)) ) {
8252
8253       if(!blon) {
8254	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x08);
8255       } else {
8256	  setSISIDXREG(SISSR, 0x11, sr11mask, 0x00);
8257       }
8258
8259    } else if((pSiS->VGAEngine == SIS_315_VGA) &&
8260	      (pSiS->VBFlags2 & VB2_CHRONTEL)) {
8261
8262       if(!blon) {
8263	  SiS_Chrontel701xBLOff(pSiS->SiS_Pr);
8264       } else {
8265	  SiS_Chrontel701xBLOn(pSiS->SiS_Pr);
8266       }
8267
8268    }
8269}
8270
8271static Bool
8272SISSaveScreen(ScreenPtr pScreen, int mode)
8273{
8274    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8275    SISPtr pSiS;
8276    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8277
8278    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8279
8280    pSiS = SISPTR(pScrn);
8281
8282#ifdef UNLOCK_ALWAYS
8283    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8284#endif
8285
8286    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
8287       SiSHandleBackLight(pSiS, IsUnblank);
8288    }
8289
8290    if(!SiSBridgeIsInSlaveMode(pScrn)) {
8291       return SiSVGASaveScreen(pScreen, mode);
8292    }
8293
8294    return TRUE;
8295}
8296
8297#ifdef SISDUALHEAD
8298/* SaveScreen for dual head mode */
8299static Bool
8300SISSaveScreenDH(ScreenPtr pScreen, int mode)
8301{
8302    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
8303    SISPtr pSiS;
8304    Bool IsUnblank = xf86IsUnblank(mode) ? TRUE : FALSE;
8305
8306    if((pScrn == NULL) || (!pScrn->vtSema)) return TRUE;
8307
8308    pSiS = SISPTR(pScrn);
8309
8310    if( (pSiS->SecondHead) &&
8311        ((!(pSiS->VBFlags & CRT1_LCDA)) || (pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE)) ) {
8312
8313       /* Slave head is always CRT1 */
8314       /* (No backlight handling on TMDS bridges) */
8315       return SiSVGASaveScreen(pScreen, mode);
8316
8317    } else {
8318
8319       /* Master head is always CRT2 */
8320       /* But we land here for LCDA, too (if bridge is SiS LVDS type) */
8321
8322       /* We can only blank LCD, not other CRT2 devices */
8323       if(pSiS->VBFlags & (CRT2_LCD|CRT1_LCDA)) {
8324
8325#ifdef UNLOCK_ALWAYS
8326	  sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
8327#endif
8328	  SiSHandleBackLight(pSiS, IsUnblank);
8329
8330       }
8331
8332    }
8333    return TRUE;
8334}
8335#endif
8336
8337static void
8338SISDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags)
8339{
8340    SISPtr pSiS = SISPTR(pScrn);
8341    Bool   docrt1 = TRUE, docrt2 = TRUE, backlight = TRUE;
8342    UChar  sr1=0, cr17=0, cr63=0, pmreg=0, sr7=0;
8343    UChar  p1_13=0, p2_0=0, oldpmreg=0;
8344
8345    if(!pScrn->vtSema) return;
8346
8347    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
8348          "SISDisplayPowerManagementSet(%d)\n", PowerManagementMode);
8349
8350#ifdef SISDUALHEAD
8351    if(pSiS->DualHeadMode) {
8352       if(pSiS->SecondHead) docrt2 = FALSE;
8353       else                 docrt1 = FALSE;
8354    }
8355#endif
8356
8357    /* Work around a bug in xf86Event.c:
8358     * pScrn->DPMSSet is being called without a previous
8359     * call to xf86EnableAccess(). So we have no hardware
8360     * access here.
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	UpdateCurrentTime();
9327	sigstate = xf86BlockSIGIO();
9328	miPointerAbsoluteCursor(x, y, currentTime.milliseconds);
9329	xf86UnblockSIGIO(sigstate);
9330	return;
9331     }
9332  }
9333
9334  f1.x0 = old1x0 = pSiS->CRT1frameX0;
9335  f1.x1 = pSiS->CRT1frameX1;
9336  f1.y0 = old1y0 = pSiS->CRT1frameY0;
9337  f1.y1 = pSiS->CRT1frameY1;
9338  f2.x0 = old2x0 = pScrn2->frameX0;
9339  f2.x1 = pScrn2->frameX1;
9340  f2.y0 = old2y0 = pScrn2->frameY0;
9341  f2.y1 = pScrn2->frameY1;
9342
9343  /* Define the outer region. Crossing this causes all frames to move */
9344  out.x0 = pScrn1->frameX0;
9345  out.x1 = pScrn1->frameX1;
9346  out.y0 = pScrn1->frameY0;
9347  out.y1 = pScrn1->frameY1;
9348
9349  /*
9350   * Define the inner sliding window. Being outsize both frames but
9351   * inside the outer clipping window will slide corresponding frame
9352   */
9353  in1 = out;
9354  in2 = out;
9355  switch(srel) {
9356     case sisLeftOf:
9357        in1.x0 = f1.x0;
9358        in2.x1 = f2.x1;
9359        break;
9360     case sisRightOf:
9361        in1.x1 = f1.x1;
9362        in2.x0 = f2.x0;
9363        break;
9364     case sisBelow:
9365        in1.y1 = f1.y1;
9366        in2.y0 = f2.y0;
9367        break;
9368     case sisAbove:
9369        in1.y0 = f1.y0;
9370        in2.y1 = f2.y1;
9371        break;
9372     case sisClone:
9373        break;
9374  }
9375
9376  deltay = 0;
9377  deltax = 0;
9378
9379  if(InRegion(x, y, out)) {	/* inside outer region */
9380
9381     if(InRegion(x, y, in1) && !InRegion(x, y, f1)) {
9382	REBOUND(f1.x0, f1.x1, x);
9383	REBOUND(f1.y0, f1.y1, y);
9384	deltax = 1;
9385     }
9386     if(InRegion(x, y, in2) && !InRegion(x, y, f2)) {
9387	REBOUND(f2.x0, f2.x1, x);
9388	REBOUND(f2.y0, f2.y1, y);
9389	deltax = 1;
9390     }
9391
9392  } else {			/* outside outer region */
9393
9394     if(out.x0 > x) {
9395	deltax = x - out.x0;
9396     }
9397     if(out.x1 < x) {
9398	deltax = x - out.x1;
9399     }
9400     if(deltax) {
9401	pScrn1->frameX0 += deltax;
9402	pScrn1->frameX1 += deltax;
9403	f1.x0 += deltax;
9404	f1.x1 += deltax;
9405	f2.x0 += deltax;
9406	f2.x1 += deltax;
9407     }
9408
9409     if(out.y0 > y) {
9410	deltay = y - out.y0;
9411     }
9412     if(out.y1 < y) {
9413	deltay = y - out.y1;
9414     }
9415     if(deltay) {
9416	pScrn1->frameY0 += deltay;
9417	pScrn1->frameY1 += deltay;
9418	f1.y0 += deltay;
9419	f1.y1 += deltay;
9420	f2.y0 += deltay;
9421	f2.y1 += deltay;
9422     }
9423
9424     switch(srel) {
9425	case sisLeftOf:
9426	   if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); }
9427	   if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); }
9428	   break;
9429	case sisRightOf:
9430	   if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); }
9431	   if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); }
9432	   break;
9433	case sisBelow:
9434	   if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); }
9435	   if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); }
9436	   break;
9437	case sisAbove:
9438	   if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); }
9439	   if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); }
9440	   break;
9441	case sisClone:
9442	   break;
9443     }
9444
9445  }
9446
9447  if(deltax || deltay) {
9448     pSiS->CRT1frameX0 = f1.x0;
9449     pSiS->CRT1frameY0 = f1.y0;
9450     pScrn2->frameX0 = f2.x0;
9451     pScrn2->frameY0 = f2.y0;
9452
9453     switch(srel) {
9454	case sisLeftOf:
9455	case sisRightOf:
9456	   if(CRT1YOffs || CRT2YOffs || HaveNonRect) {
9457	      if(pSiS->CRT1frameY0 != old1y0) {
9458	         if(pSiS->CRT1frameY0 < CRT1YOffs)
9459	            pSiS->CRT1frameY0 = CRT1YOffs;
9460
9461	         temp1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay;
9462	         temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + pSiS->MBXNR1YMAX));
9463	         if(temp1 > temp2)
9464	            pSiS->CRT1frameY0 -= (temp1 - temp2);
9465	      }
9466	      if(pScrn2->frameY0 != old2y0) {
9467	         if(pScrn2->frameY0 < CRT2YOffs)
9468	            pScrn2->frameY0 = CRT2YOffs;
9469
9470	         temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay;
9471	         temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + pSiS->MBXNR2YMAX));
9472	         if(temp1 > temp2)
9473	            pScrn2->frameY0 -= (temp1 - temp2);
9474	      }
9475	   }
9476	   break;
9477	case sisBelow:
9478	case sisAbove:
9479	   if(CRT1XOffs || CRT2XOffs || HaveNonRect) {
9480	      if(pSiS->CRT1frameX0 != old1x0) {
9481	         if(pSiS->CRT1frameX0 < CRT1XOffs)
9482	            pSiS->CRT1frameX0 = CRT1XOffs;
9483
9484	         temp1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay;
9485	         temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + pSiS->MBXNR1XMAX));
9486	         if(temp1 > temp2)
9487	            pSiS->CRT1frameX0 -= (temp1 - temp2);
9488	      }
9489	      if(pScrn2->frameX0 != old2x0) {
9490	         if(pScrn2->frameX0 < CRT2XOffs)
9491	            pScrn2->frameX0 = CRT2XOffs;
9492
9493	         temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay;
9494	         temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + pSiS->MBXNR2XMAX));
9495	         if(temp1 > temp2)
9496	            pScrn2->frameX0 -= (temp1 - temp2);
9497	      }
9498	   }
9499	   break;
9500	case sisClone:
9501	   break;
9502     }
9503
9504     pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9505     pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9506     pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9507     pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9508
9509     /* No need to update pScrn1->frame?1, done above */
9510
9511     SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9512     SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9513  }
9514}
9515
9516static void
9517SISAdjustFrameMerged(int scrnIndex, int x, int y, int flags)
9518{
9519    ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex];
9520    SISPtr pSiS = SISPTR(pScrn1);
9521    ScrnInfoPtr pScrn2 = pSiS->CRT2pScrn;
9522    int HTotal = pSiS->CurrentLayout.mode->HDisplay;
9523    int VTotal = pSiS->CurrentLayout.mode->VDisplay;
9524    int HMax = HTotal;
9525    int VMax = VTotal;
9526    int HVirt = pScrn1->virtualX;
9527    int VVirt = pScrn1->virtualY;
9528    int x1 = x, x2 = x;
9529    int y1 = y, y2 = y;
9530    int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0;
9531    int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536;
9532
9533    if(pSiS->DGAactive) {
9534       HVirt = pSiS->CurrentLayout.displayWidth;
9535       VVirt = pSiS->CurrentLayout.displayHeight;
9536    } else {
9537       CRT1XOffs = pSiS->CRT1XOffs;
9538       CRT1YOffs = pSiS->CRT1YOffs;
9539       CRT2XOffs = pSiS->CRT2XOffs;
9540       CRT2YOffs = pSiS->CRT2YOffs;
9541       MBXNR1XMAX = pSiS->MBXNR1XMAX;
9542       MBXNR1YMAX = pSiS->MBXNR1YMAX;
9543       MBXNR2XMAX = pSiS->MBXNR2XMAX;
9544       MBXNR2YMAX = pSiS->MBXNR2YMAX;
9545    }
9546
9547    BOUND(x, 0, HVirt - HTotal);
9548    BOUND(y, 0, VVirt - VTotal);
9549    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9550       BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs);
9551       BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs);
9552       BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs);
9553       BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs);
9554    }
9555
9556    switch(SDMPTR(pScrn1)->CRT2Position) {
9557        case sisLeftOf:
9558            pScrn2->frameX0 = x2;
9559            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9560            pSiS->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay;
9561            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9562            break;
9563        case sisRightOf:
9564            pSiS->CRT1frameX0 = x1;
9565            BOUND(pSiS->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay);
9566            pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay;
9567            BOUND(pScrn2->frameY0,   y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay);
9568            break;
9569        case sisAbove:
9570            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9571            pScrn2->frameY0 = y2;
9572            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9573            pSiS->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay;
9574            break;
9575        case sisBelow:
9576            BOUND(pSiS->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay);
9577            pSiS->CRT1frameY0 = y1;
9578            BOUND(pScrn2->frameX0,   x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay);
9579            pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay;
9580            break;
9581        case sisClone:
9582            BOUND(pSiS->CRT1frameX0, x,  x + HMax - CDMPTR->CRT1->HDisplay);
9583            BOUND(pSiS->CRT1frameY0, y,  y + VMax - CDMPTR->CRT1->VDisplay);
9584            BOUND(pScrn2->frameX0,   x,  x + HMax - CDMPTR->CRT2->HDisplay);
9585            BOUND(pScrn2->frameY0,   y,  y + VMax - CDMPTR->CRT2->VDisplay);
9586            break;
9587    }
9588
9589    BOUND(pSiS->CRT1frameX0, 0, HVirt - CDMPTR->CRT1->HDisplay);
9590    BOUND(pSiS->CRT1frameY0, 0, VVirt - CDMPTR->CRT1->VDisplay);
9591    BOUND(pScrn2->frameX0,   0, HVirt - CDMPTR->CRT2->HDisplay);
9592    BOUND(pScrn2->frameY0,   0, VVirt - CDMPTR->CRT2->VDisplay);
9593
9594    pScrn1->frameX0 = x;
9595    pScrn1->frameY0 = y;
9596
9597    pSiS->CRT1frameX1 = pSiS->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1;
9598    pSiS->CRT1frameY1 = pSiS->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1;
9599    pScrn2->frameX1   = pScrn2->frameX0   + CDMPTR->CRT2->HDisplay - 1;
9600    pScrn2->frameY1   = pScrn2->frameY0   + CDMPTR->CRT2->VDisplay - 1;
9601
9602    pScrn1->frameX1   = pScrn1->frameX0   + pSiS->CurrentLayout.mode->HDisplay  - 1;
9603    pScrn1->frameY1   = pScrn1->frameY0   + pSiS->CurrentLayout.mode->VDisplay  - 1;
9604    if(SDMPTR(pScrn1)->CRT2Position != sisClone) {
9605       pScrn1->frameX1 += CRT1XOffs + CRT2XOffs;
9606       pScrn1->frameY1 += CRT1YOffs + CRT2YOffs;
9607    }
9608
9609    SISAdjustFrameHW_CRT1(pScrn1, pSiS->CRT1frameX0, pSiS->CRT1frameY0);
9610    SISAdjustFrameHW_CRT2(pScrn1, pScrn2->frameX0, pScrn2->frameY0);
9611}
9612#endif
9613
9614/*
9615 * This function is used to initialize the Start Address - the first
9616 * displayed location in the video memory.
9617 *
9618 * Usually mandatory
9619 */
9620void
9621SISAdjustFrame(int scrnIndex, int x, int y, int flags)
9622{
9623    ScrnInfoPtr   pScrn = xf86Screens[scrnIndex];
9624    SISPtr        pSiS = SISPTR(pScrn);
9625    ULong base;
9626    UChar temp, cr11backup;
9627
9628#ifdef SISMERGED
9629    if(pSiS->MergedFB) {
9630	SISAdjustFrameMerged(scrnIndex, x, y, flags);
9631	return;
9632    }
9633#endif
9634
9635    if(pSiS->UseVESA) {
9636	VBESetDisplayStart(pSiS->pVbe, x, y, TRUE);
9637	return;
9638    }
9639
9640    if(pScrn->bitsPerPixel < 8) {
9641       base = (y * pSiS->CurrentLayout.displayWidth + x + 3) >> 3;
9642    } else {
9643       base  = y * pSiS->CurrentLayout.displayWidth + x;
9644
9645       /* calculate base bpp dep. */
9646       switch(pSiS->CurrentLayout.bitsPerPixel) {
9647          case 16:
9648     	     base >>= 1;
9649             break;
9650          case 24:
9651             base = ((base * 3)) >> 2;
9652             base -= base % 6;
9653             break;
9654          case 32:
9655             break;
9656          default:      /* 8bpp */
9657             base >>= 2;
9658             break;
9659       }
9660    }
9661
9662#ifdef UNLOCK_ALWAYS
9663    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9664#endif
9665
9666    base += (pSiS->dhmOffset/4);
9667
9668#ifdef TWDEBUG
9669    xf86DrvMsg(0, 0, "AdjustFrame: x %d y %d bpp %d dw %d base %d, dhmOffset %d\n",
9670    			x, y, pSiS->CurrentLayout.bitsPerPixel, pSiS->CurrentLayout.displayWidth, base, pSiS->dhmOffset);
9671#endif
9672
9673#ifdef SISDUALHEAD
9674    if(pSiS->DualHeadMode) {
9675       if(!pSiS->SecondHead) {
9676	  /* Head 1 (master) is always CRT2 */
9677	  SISSetStartAddressCRT2(pSiS, base);
9678       } else {
9679	  /* Head 2 (slave) is always CRT1 */
9680	  SISSetStartAddressCRT1(pSiS, base);
9681       }
9682    } else {
9683#endif
9684       switch(pSiS->VGAEngine) {
9685	  case SIS_300_VGA:
9686	  case SIS_315_VGA:
9687	     SISSetStartAddressCRT1(pSiS, base);
9688	     if(pSiS->VBFlags & CRT2_ENABLE) {
9689		if(!SiSBridgeIsInSlaveMode(pScrn)) {
9690		   SISSetStartAddressCRT2(pSiS, base);
9691		}
9692	     }
9693	     break;
9694	  default:
9695	     /* Unlock CRTC registers */
9696	     inSISIDXREG(SISCR,  0x11, cr11backup);
9697	     andSISIDXREG(SISCR, 0x11, 0x7F);
9698	     outSISIDXREG(SISCR, 0x0D, base & 0xFF);
9699	     outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
9700	     inSISIDXREG(SISSR,  0x27, temp);
9701	     temp &= 0xF0;
9702	     temp |= (base & 0x0F0000) >> 16;
9703	     outSISIDXREG(SISSR, 0x27, temp);
9704	     /* Eventually lock CRTC registers */
9705	     setSISIDXREG(SISCR, 0x11, 0x7F, (cr11backup & 0x80));
9706       }
9707#ifdef SISDUALHEAD
9708    }
9709#endif
9710
9711}
9712
9713/*
9714 * This is called when VT switching back to the X server.  Its job is
9715 * to reinitialise the video mode.
9716 * Mandatory!
9717 */
9718static Bool
9719SISEnterVT(int scrnIndex, int flags)
9720{
9721    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9722    SISPtr pSiS = SISPTR(pScrn);
9723
9724    SiS_SiSFB_Lock(pScrn, TRUE);
9725
9726    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
9727
9728    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
9729       outSISIDXREG(SISCR,0x32,pSiS->myCR32);
9730       outSISIDXREG(SISCR,0x36,pSiS->myCR36);
9731       outSISIDXREG(SISCR,0x37,pSiS->myCR37);
9732    }
9733
9734    if(!SISModeInit(pScrn, pScrn->currentMode)) {
9735       SISErrorLog(pScrn, "SiSEnterVT: SISModeInit() failed\n");
9736       return FALSE;
9737    }
9738
9739    SISAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
9740
9741#ifdef XF86DRI
9742    if(pSiS->directRenderingEnabled) {
9743       DRIUnlock(screenInfo.screens[scrnIndex]);
9744    }
9745#endif
9746
9747#ifdef SISDUALHEAD
9748    if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
9749#endif
9750       if(pSiS->ResetXv) {
9751          (pSiS->ResetXv)(pScrn);
9752       }
9753
9754    return TRUE;
9755}
9756
9757/*
9758 * This is called when VT switching away from the X server.  Its job is
9759 * to restore the previous (text) mode.
9760 * Mandatory!
9761 */
9762static void
9763SISLeaveVT(int scrnIndex, int flags)
9764{
9765    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9766    SISPtr pSiS = SISPTR(pScrn);
9767#ifdef XF86DRI
9768    ScreenPtr pScreen;
9769
9770    if(pSiS->directRenderingEnabled) {
9771       pScreen = screenInfo.screens[scrnIndex];
9772       DRILock(pScreen, 0);
9773    }
9774#endif
9775
9776#ifdef SISDUALHEAD
9777    if(pSiS->DualHeadMode && pSiS->SecondHead) return;
9778#endif
9779
9780    if(pSiS->CursorInfoPtr) {
9781#ifdef SISDUALHEAD
9782       if(pSiS->DualHeadMode) {
9783          if(!pSiS->SecondHead) {
9784	     pSiS->ForceCursorOff = TRUE;
9785	     pSiS->CursorInfoPtr->HideCursor(pScrn);
9786	     SISWaitVBRetrace(pScrn);
9787	     pSiS->ForceCursorOff = FALSE;
9788	  }
9789       } else {
9790#endif
9791          pSiS->CursorInfoPtr->HideCursor(pScrn);
9792          SISWaitVBRetrace(pScrn);
9793#ifdef SISDUALHEAD
9794       }
9795#endif
9796    }
9797
9798    SISBridgeRestore(pScrn);
9799
9800    if(pSiS->UseVESA) {
9801
9802       /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9803    	* VBESaveRestore() does not restore CRT1. So we set any mode now,
9804	* because VBESetVBEMode correctly restores CRT1. Afterwards, we
9805	* can call VBESaveRestore to restore original mode.
9806	*/
9807       if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9808	  VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9809
9810       SISVESARestore(pScrn);
9811
9812    } else {
9813
9814       SISRestore(pScrn);
9815
9816    }
9817
9818    /* We use (otherwise unused) bit 7 to indicate that we are running
9819     * to keep sisfb to change the displaymode (this would result in
9820     * lethal display corruption upon quitting X or changing to a VT
9821     * until a reboot)
9822     */
9823    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
9824       orSISIDXREG(SISCR,0x34,0x80);
9825    }
9826
9827    SISVGALock(pSiS);
9828
9829    SiS_SiSFB_Lock(pScrn, FALSE);
9830}
9831
9832
9833/*
9834 * This is called at the end of each server generation.  It restores the
9835 * original (text) mode.  It should really also unmap the video memory too.
9836 * Mandatory!
9837 */
9838static Bool
9839SISCloseScreen(int scrnIndex, ScreenPtr pScreen)
9840{
9841    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
9842    SISPtr pSiS = SISPTR(pScrn);
9843#ifdef SISDUALHEAD
9844    SISEntPtr pSiSEnt = pSiS->entityPrivate;
9845#endif
9846
9847    if(pSiS->SiSCtrlExtEntry) {
9848       SiSCtrlExtUnregister(pSiS, pScrn->scrnIndex);
9849    }
9850
9851#ifdef XF86DRI
9852    if(pSiS->directRenderingEnabled) {
9853       SISDRICloseScreen(pScreen);
9854       pSiS->directRenderingEnabled = FALSE;
9855    }
9856#endif
9857
9858    if(pScrn->vtSema) {
9859
9860        if(pSiS->CursorInfoPtr) {
9861#ifdef SISDUALHEAD
9862           if(pSiS->DualHeadMode) {
9863              if(!pSiS->SecondHead) {
9864	         pSiS->ForceCursorOff = TRUE;
9865	         pSiS->CursorInfoPtr->HideCursor(pScrn);
9866	         SISWaitVBRetrace(pScrn);
9867	         pSiS->ForceCursorOff = FALSE;
9868	      }
9869           } else {
9870#endif
9871             pSiS->CursorInfoPtr->HideCursor(pScrn);
9872             SISWaitVBRetrace(pScrn);
9873#ifdef SISDUALHEAD
9874           }
9875#endif
9876	}
9877
9878        SISBridgeRestore(pScrn);
9879
9880	if(pSiS->UseVESA) {
9881
9882	  /* This is a q&d work-around for a BIOS bug. In case we disabled CRT2,
9883    	   * VBESaveRestore() does not restore CRT1. So we set any mode now,
9884	   * because VBESetVBEMode correctly restores CRT1. Afterwards, we
9885	   * can call VBESaveRestore to restore original mode.
9886	   */
9887           if((pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && (!(pSiS->VBFlags & DISPTYPE_DISP2)))
9888	      VBESetVBEMode(pSiS->pVbe, (pSiS->SISVESAModeList->n) | 0xc000, NULL);
9889
9890	   SISVESARestore(pScrn);
9891
9892	} else {
9893
9894	   SISRestore(pScrn);
9895
9896	}
9897
9898        SISVGALock(pSiS);
9899
9900    }
9901
9902    SiS_SiSFB_Lock(pScrn, FALSE);
9903
9904    /* We should restore the mode number in case vtsema = false as well,
9905     * but since we haven't register access then we can't do it. I think
9906     * I need to rework the save/restore stuff, like saving the video
9907     * status when returning to the X server and by that save me the
9908     * trouble if sisfb was started from a textmode VT while X was on.
9909     */
9910
9911    SISUnmapMem(pScrn);
9912#ifdef SIS_PC_PLATFORM
9913    SiSVGAUnmapMem(pScrn);
9914#endif
9915
9916#ifdef SISDUALHEAD
9917    if(pSiS->DualHeadMode) {
9918       pSiSEnt = pSiS->entityPrivate;
9919       pSiSEnt->refCount--;
9920    }
9921#endif
9922
9923    if(pSiS->pInt) {
9924       xf86FreeInt10(pSiS->pInt);
9925       pSiS->pInt = NULL;
9926    }
9927
9928#ifdef SIS_USE_XAA
9929    if(!pSiS->useEXA) {
9930       if(pSiS->AccelLinearScratch) {
9931          xf86FreeOffscreenLinear(pSiS->AccelLinearScratch);
9932          pSiS->AccelLinearScratch = NULL;
9933       }
9934       if(pSiS->AccelInfoPtr) {
9935          XAADestroyInfoRec(pSiS->AccelInfoPtr);
9936          pSiS->AccelInfoPtr = NULL;
9937       }
9938    }
9939#endif
9940
9941#ifdef SIS_USE_EXA
9942    if(pSiS->useEXA) {
9943       if(pSiS->EXADriverPtr) {
9944          exaDriverFini(pScreen);
9945          xfree(pSiS->EXADriverPtr);
9946          pSiS->EXADriverPtr = NULL;
9947          pSiS->exa_scratch = NULL;
9948       }
9949    }
9950#endif
9951
9952    if(pSiS->CursorInfoPtr) {
9953       xf86DestroyCursorInfoRec(pSiS->CursorInfoPtr);
9954       pSiS->CursorInfoPtr = NULL;
9955    }
9956
9957    if(pSiS->ShadowPtr) {
9958       xfree(pSiS->ShadowPtr);
9959       pSiS->ShadowPtr = NULL;
9960    }
9961
9962    if(pSiS->DGAModes) {
9963       xfree(pSiS->DGAModes);
9964       pSiS->DGAModes = NULL;
9965    }
9966
9967    if(pSiS->adaptor) {
9968       xfree(pSiS->adaptor);
9969       pSiS->adaptor = NULL;
9970       pSiS->ResetXv = pSiS->ResetXvGamma = pSiS->ResetXvDisplay = NULL;
9971    }
9972
9973    if(pSiS->blitadaptor) {
9974       xfree(pSiS->blitadaptor);
9975       pSiS->blitadaptor = NULL;
9976    }
9977
9978    if(pSiS->crt2gcolortable) {
9979       xfree(pSiS->crt2gcolortable);
9980       pSiS->crt2gcolortable = NULL;
9981    }
9982
9983    if(pSiS->crt2cindices) {
9984       xfree(pSiS->crt2cindices);
9985       pSiS->crt2cindices = NULL;
9986    }
9987
9988    pScrn->vtSema = FALSE;
9989
9990    /* Restore Blockhandler */
9991    pScreen->BlockHandler = pSiS->BlockHandler;
9992
9993    pScreen->CloseScreen = pSiS->CloseScreen;
9994
9995    return(*pScreen->CloseScreen)(scrnIndex, pScreen);
9996}
9997
9998
9999/* Free up any per-generation data structures */
10000
10001/* Optional */
10002static void
10003SISFreeScreen(int scrnIndex, int flags)
10004{
10005#ifdef SIS_NEED_MAP_IOP
10006    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
10007    SISPtr pSiS = SISPTR(pScrn);
10008
10009    if(pSiS) {
10010#ifdef SISDUALHEAD
10011       SISEntPtr pSiSEnt = pSiS->entityPrivate;
10012       if(pSiSEnt) {
10013          pSiSEnt->forceUnmapIOPBase = TRUE;
10014       }
10015#endif
10016       SISUnmapIOPMem(pScrn);
10017    }
10018#endif
10019
10020    SISFreeRec(xf86Screens[scrnIndex]);
10021}
10022
10023
10024/* Checks if a mode is suitable for the selected chipset. */
10025
10026static ModeStatus
10027SISValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
10028{
10029    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
10030    SISPtr pSiS = SISPTR(pScrn);
10031
10032    if(pSiS->UseVESA) {
10033       if(SiSCalcVESAModeIndex(pScrn, mode))
10034	  return(MODE_OK);
10035       else
10036	  return(MODE_BAD);
10037    }
10038
10039    if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
10040#ifdef SISDUALHEAD
10041       if(pSiS->DualHeadMode) {
10042          if(pSiS->SecondHead) {
10043	     if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10044	        return(MODE_BAD);
10045	  } else {
10046	     if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10047	        return(MODE_BAD);
10048	  }
10049       } else
10050#endif
10051#ifdef SISMERGED
10052       if(pSiS->MergedFB) {
10053	  if(!mode->Private) {
10054	     if(!pSiS->CheckForCRT2) {
10055	        if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10056	           return(MODE_BAD);
10057	     } else {
10058	        if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10059	           return(MODE_BAD);
10060	     }
10061	  } else {
10062	     if(SiS_CheckModeCRT1(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT1,
10063		                  pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10064	        return(MODE_BAD);
10065
10066	     if(SiS_CheckModeCRT2(pScrn, ((SiSMergedDisplayModePtr)mode->Private)->CRT2,
10067		                  pSiS->VBFlags, pSiS->HaveCustomModes2) < 0x14)
10068	        return(MODE_BAD);
10069 	  }
10070       } else
10071#endif
10072       {
10073	  if(SiS_CheckModeCRT1(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10074	     return(MODE_BAD);
10075
10076	  if(SiS_CheckModeCRT2(pScrn, mode, pSiS->VBFlags, pSiS->HaveCustomModes) < 0x14)
10077	     return(MODE_BAD);
10078       }
10079    }
10080
10081    return(MODE_OK);
10082}
10083
10084#ifdef DEBUG
10085static void
10086SiSDumpModeInfo(ScrnInfoPtr pScrn, DisplayModePtr mode)
10087{
10088    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock);
10089    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay);
10090    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart);
10091    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart);
10092    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd);
10093    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd);
10094    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal);
10095    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew);
10096    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted);
10097    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay);
10098    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart);
10099    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart);
10100    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd);
10101    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd);
10102    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal);
10103    xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted);
10104}
10105#endif
10106
10107static void
10108SISModifyModeInfo(DisplayModePtr mode)
10109{
10110    if(mode->CrtcHBlankStart == mode->CrtcHDisplay)
10111        mode->CrtcHBlankStart++;
10112    if(mode->CrtcHBlankEnd == mode->CrtcHTotal)
10113        mode->CrtcHBlankEnd--;
10114    if(mode->CrtcVBlankStart == mode->CrtcVDisplay)
10115        mode->CrtcVBlankStart++;
10116    if(mode->CrtcVBlankEnd == mode->CrtcVTotal)
10117        mode->CrtcVBlankEnd--;
10118}
10119
10120/* Enable the Turboqueue/Commandqueue (For 300 and 315/330/340 series only) */
10121static void
10122SiSEnableTurboQueue(ScrnInfoPtr pScrn)
10123{
10124    SISPtr pSiS = SISPTR(pScrn);
10125    UShort SR26, SR27;
10126    ULong  temp;
10127
10128    switch(pSiS->VGAEngine) {
10129	case SIS_300_VGA:
10130	   if((!pSiS->NoAccel) && (pSiS->TurboQueue)) {
10131		/* TQ size is always 512k */
10132		temp = (pScrn->videoRam/64) - 8;
10133		SR26 = temp & 0xFF;
10134		inSISIDXREG(SISSR, 0x27, SR27);
10135		SR27 &= 0xFC;
10136		SR27 |= (0xF0 | ((temp >> 8) & 3));
10137		outSISIDXREG(SISSR, 0x26, SR26);
10138		outSISIDXREG(SISSR, 0x27, SR27);
10139	   }
10140	   break;
10141
10142	case SIS_315_VGA:
10143	   if(!pSiS->NoAccel) {
10144	      /* On 315/330/340 series, there are three queue modes available
10145	       * which are chosen by setting bits 7:5 in SR26:
10146	       * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
10147	       *    track of the queue, the FIFO, command parsing and so
10148	       *    on. This is the one comparable to the 300 series.
10149	       * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
10150	       *    have to do queue management himself.
10151	       * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
10152	       *    queue in AGP memory space.
10153	       * We go VRAM or MMIO here.
10154	       * SR26 bit 4 is called "Bypass H/W queue".
10155	       * SR26 bit 1 is called "Enable Command Queue Auto Correction"
10156	       * SR26 bit 0 resets the queue
10157	       * Size of queue memory is encoded in bits 3:2 like this:
10158	       *    00  (0x00)  512K
10159	       *    01  (0x04)  1M
10160	       *    10  (0x08)  2M
10161	       *    11  (0x0C)  4M
10162	       * The queue location is to be written to 0x85C0.
10163	       */
10164#ifdef SISVRAMQ
10165	      /* We use VRAM Cmd Queue, not MMIO or AGP */
10166	      UChar tempCR55 = 0;
10167
10168	      /* Set Command Queue Threshold to max value 11111b (?) */
10169	      outSISIDXREG(SISSR, 0x27, 0x1F);
10170
10171	      /* Disable queue flipping */
10172	      inSISIDXREG(SISCR, 0x55, tempCR55);
10173	      andSISIDXREG(SISCR, 0x55, 0x33);
10174	      /* Synchronous reset for Command Queue */
10175	      outSISIDXREG(SISSR, 0x26, 0x01);
10176	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10177	      /* Enable VRAM Command Queue mode */
10178	      if(pSiS->ChipType == XGI_20) {
10179		 /* On XGI_20, always 128K */
10180		 SR26 = 0x40 | 0x04 | 0x01;
10181	      } else {
10182	         switch(pSiS->cmdQueueSize) {
10183		    case 1*1024*1024: SR26 = (0x40 | 0x04 | 0x01); break;
10184		    case 2*1024*1024: SR26 = (0x40 | 0x08 | 0x01); break;
10185		    case 4*1024*1024: SR26 = (0x40 | 0x0C | 0x01); break;
10186		    default:
10187		                      pSiS->cmdQueueSize = 512 * 1024;
10188		    case    512*1024: SR26 = (0x40 | 0x00 | 0x01);
10189	         }
10190	      }
10191	      outSISIDXREG(SISSR, 0x26, SR26);
10192	      SR26 &= 0xfe;
10193	      outSISIDXREG(SISSR, 0x26, SR26);
10194	      *(pSiS->cmdQ_SharedWritePort) = (unsigned int)(SIS_MMIO_IN32(pSiS->IOBase, 0x85c8));
10195	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, (CARD32)(*(pSiS->cmdQ_SharedWritePort)));
10196	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, pSiS->cmdQueueOffset);
10197	      temp = (ULong)pSiS->RealFbBase;
10198#ifdef SISDUALHEAD
10199	      if(pSiS->DualHeadMode) {
10200	         SISEntPtr pSiSEnt = pSiS->entityPrivate;
10201	         temp = (ULong)pSiSEnt->RealFbBase;
10202	      }
10203#endif
10204	      temp += pSiS->cmdQueueOffset;
10205	      pSiS->cmdQueueBase = (unsigned int *)temp;
10206	      outSISIDXREG(SISCR, 0x55, tempCR55);
10207#ifdef TWDEBUG
10208	      xf86DrvMsg(0, 0, "CmdQueueOffs 0x%x, CmdQueueAdd %p, shwrp 0x%x, status %x, base %p\n",
10209		pSiS->cmdQueueOffset, pSiS->cmdQueueBase, *(pSiS->cmdQ_SharedWritePort),
10210		SIS_MMIO_IN32(pSiS->IOBase, 0x85cc), (ULong *)temp);
10211#endif
10212#else
10213	      /* For MMIO */
10214	      /* Syncronous reset for Command Queue */
10215	      orSISIDXREG(SISSR, 0x26, 0x01);
10216	      /* Set Command Queue Threshold to max value 11111b */
10217	      outSISIDXREG(SISSR, 0x27, 0x1F);
10218	      /* Do some magic (cp readport to writeport) */
10219	      temp = SIS_MMIO_IN32(pSiS->IOBase, 0x85C8);
10220	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C4, temp);
10221	      /* Enable MMIO Command Queue mode (0x20),
10222	       * Enable_command_queue_auto_correction (0x02)
10223	       *        (no idea, but sounds good, so use it)
10224	       * 512k (0x00) (does this apply to MMIO mode?) */
10225	      outSISIDXREG(SISSR, 0x26, 0x22);
10226	      /* Calc Command Queue position (Q is always 512k)*/
10227	      temp = (pScrn->videoRam - 512) * 1024;
10228	      /* Set Q position */
10229	      SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, temp);
10230#endif
10231	   }
10232	   break;
10233	default:
10234	   break;
10235    }
10236}
10237
10238#ifdef SISVRAMQ
10239static void
10240SiSRestoreQueueMode(SISPtr pSiS, SISRegPtr sisReg)
10241{
10242    UChar tempCR55=0;
10243
10244    if(pSiS->VGAEngine == SIS_315_VGA) {
10245       inSISIDXREG(SISCR,0x55,tempCR55);
10246       andSISIDXREG(SISCR,0x55,0x33);
10247       outSISIDXREG(SISSR,0x26,0x01);
10248       SIS_MMIO_OUT32(pSiS->IOBase, 0x85c4, 0);
10249       outSISIDXREG(SISSR,0x27,sisReg->sisRegs3C4[0x27]);
10250       outSISIDXREG(SISSR,0x26,sisReg->sisRegs3C4[0x26]);
10251       SIS_MMIO_OUT32(pSiS->IOBase, 0x85C0, sisReg->sisMMIO85C0);
10252       outSISIDXREG(SISCR,0x55,tempCR55);
10253    }
10254}
10255#endif
10256
10257/* Things to do before a ModeSwitch. We set up the
10258 * video bridge configuration and the TurboQueue.
10259 */
10260void SiSPreSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int viewmode)
10261{
10262    SISPtr pSiS = SISPTR(pScrn);
10263    UChar  CR30, CR31, CR32, CR33;
10264    UChar  CR39 = 0, CR3B = 0;
10265    UChar  CR17, CR38 = 0;
10266    UChar  CR35 = 0, CR79 = 0;
10267    int    temp = 0, crt1rateindex = 0;
10268    ULong  vbflag = pSiS->VBFlags;
10269    Bool   hcm = pSiS->HaveCustomModes;
10270    DisplayModePtr mymode = mode;
10271
10272    pSiS->IsCustom = FALSE;
10273
10274    /* NEVER call this with viewmode = SIS_MODE_SIMU
10275     * if mode->type is not M_T_DEFAULT!
10276     */
10277
10278#ifdef SISMERGED
10279    if(pSiS->MergedFB) {
10280       switch(viewmode) {
10281       case SIS_MODE_CRT1:
10282	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT1;
10283	  break;
10284       case SIS_MODE_CRT2:
10285	  mymode = ((SiSMergedDisplayModePtr)mode->Private)->CRT2;
10286	  hcm = pSiS->HaveCustomModes2;
10287       }
10288    }
10289#endif
10290
10291    switch(viewmode) {
10292    case SIS_MODE_CRT1:
10293       if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10294          pSiS->IsCustom = TRUE;
10295       }
10296       break;
10297    case SIS_MODE_CRT2:
10298       if(vbflag & CRT2_ENABLE) {
10299          if(SiS_CheckModeCRT2(pScrn, mymode, vbflag, hcm) == 0xfe) {
10300	     pSiS->IsCustom = TRUE;
10301          }
10302       } else {
10303          /* This can only happen in mirror mode */
10304          if(SiS_CheckModeCRT1(pScrn, mymode, vbflag, hcm) == 0xfe) {
10305             pSiS->IsCustom = TRUE;
10306          }
10307       }
10308    }
10309
10310#ifdef UNLOCK_ALWAYS
10311    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);    /* Unlock Registers */
10312#endif
10313
10314    inSISIDXREG(SISCR, 0x30, CR30);
10315    inSISIDXREG(SISCR, 0x31, CR31);
10316    CR32 = pSiS->newCR32;
10317    inSISIDXREG(SISCR, 0x33, CR33);
10318
10319    if(pSiS->NewCRLayout) {
10320
10321       inSISIDXREG(SISCR, 0x35, CR35);
10322       inSISIDXREG(SISCR, 0x38, CR38);
10323       inSISIDXREG(SISCR, 0x39, CR39);
10324
10325       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10326	   "Before: CR30=0x%02x,CR31=0x%02x,CR32=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=0x%02x\n",
10327              CR30, CR31, CR32, CR33, CR35, CR38);
10328
10329       CR38 &= ~0x07;
10330
10331    } else {
10332
10333       if(pSiS->Chipset != PCI_CHIP_SIS300) {
10334          switch(pSiS->VGAEngine) {
10335             case SIS_300_VGA: temp = 0x35; break;
10336             case SIS_315_VGA: temp = 0x38; break;
10337          }
10338          if(temp) inSISIDXREG(SISCR, temp, CR38);
10339       }
10340       if(pSiS->VGAEngine == SIS_315_VGA) {
10341          inSISIDXREG(SISCR, 0x79, CR79);
10342          CR38 &= ~0x3b;   			/* Clear LCDA/DualEdge and YPbPr bits */
10343       }
10344       inSISIDXREG(SISCR, 0x3b, CR3B);
10345
10346       xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, SISVERBLEVEL,
10347	   "Before: CR30=0x%02x, CR31=0x%02x, CR32=0x%02x, CR33=0x%02x, CR%02x=0x%02x\n",
10348              CR30, CR31, CR32, CR33, temp, CR38);
10349    }
10350
10351    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL, "VBFlags=0x%x\n", pSiS->VBFlags);
10352
10353    CR30 = 0x00;
10354    CR31 &= ~0x60;  /* Clear VB_Drivermode & VB_OutputDisable */
10355    CR31 |= 0x04;   /* Set VB_NotSimuMode (not for 30xB/1400x1050?) */
10356    CR35 = 0x00;
10357
10358    if(!pSiS->NewCRLayout) {
10359       if(!pSiS->AllowHotkey) {
10360          CR31 |= 0x80;   /* Disable hotkey-switch */
10361       }
10362       CR79 &= ~0x10;     /* Enable Backlight control on 315 series */
10363    }
10364
10365    SiS_SetEnableDstn(pSiS->SiS_Pr, FALSE);
10366    SiS_SetEnableFstn(pSiS->SiS_Pr, FALSE);
10367
10368    if((vbflag & CRT1_LCDA) && (viewmode == SIS_MODE_CRT1)) {
10369
10370       CR38 |= 0x02;
10371
10372    } else {
10373
10374       switch(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10375
10376       case CRT2_TV:
10377
10378          CR38 &= ~0xC0; 	/* Clear Pal M/N bits */
10379
10380          if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHSCART)) {		/* Chrontel */
10381	     CR30 |= 0x10;
10382	     CR38 |= 0x04;
10383	     CR38 &= ~0x08;
10384	     CR31 |= 0x01;
10385	  } else if((pSiS->VBFlags2 & VB2_CHRONTEL) && (vbflag & TV_CHYPBPR525I)) {	/* Chrontel */
10386	     CR38 |= 0x08;
10387	     CR38 &= ~0x04;
10388	     CR31 &= ~0x01;
10389          } else if(vbflag & TV_HIVISION) {	/* SiS bridge */
10390	     if(pSiS->NewCRLayout) {
10391	        CR38 |= 0x04;
10392	        CR35 |= 0x60;
10393	     } else {
10394	        CR30 |= 0x80;
10395		if(pSiS->VGAEngine == SIS_315_VGA) {
10396		   if(pSiS->VBFlags2 & VB2_SISYPBPRBRIDGE) {
10397		      CR38 |= (0x08 | 0x30);
10398		   }
10399		}
10400	     }
10401	     CR31 |= 0x01;
10402	     CR35 |= 0x01;
10403	  } else if(vbflag & TV_YPBPR) {					/* SiS bridge */
10404	     if(pSiS->NewCRLayout) {
10405		CR38 |= 0x04;
10406		CR31 &= ~0x01;
10407		CR35 &= ~0x01;
10408		if(vbflag & (TV_YPBPR525P | TV_YPBPR625P)) CR35 |= 0x20;
10409		else if(vbflag & TV_YPBPR750P)             CR35 |= 0x40;
10410		else if(vbflag & TV_YPBPR1080I)            CR35 |= 0x60;
10411
10412		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) {
10413		   CR31 |= 0x01;
10414		   CR35 |= 0x01;
10415		}
10416
10417		CR39 &= ~0x03;
10418		if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR39 |= 0x00;
10419		else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR39 |= 0x01;
10420		else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR39 |= 0x02;
10421		else					      CR39 |= 0x03;
10422	     } else if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPR) {
10423		CR30 |= 0x80;
10424		CR38 |= 0x08;
10425		CR31 &= ~0x01;
10426		if(vbflag & (TV_YPBPR525P|TV_YPBPR625P)) CR38 |= 0x10;
10427		else if(vbflag & TV_YPBPR750P)  	 CR38 |= 0x20;
10428		else if(vbflag & TV_YPBPR1080I)		 CR38 |= 0x30;
10429
10430		if(vbflag & (TV_YPBPR625I | TV_YPBPR625P)) CR31 |= 0x01;
10431
10432		if(pSiS->SiS_SD_Flags & SiS_SD_SUPPORTYPBPRAR) {
10433		   CR3B &= ~0x03;
10434		   if((vbflag & TV_YPBPRAR) == TV_YPBPR43LB)     CR3B |= 0x00;
10435		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR43)  CR3B |= 0x03;
10436		   else if((vbflag & TV_YPBPRAR) == TV_YPBPR169) CR3B |= 0x01;
10437		   else					         CR3B |= 0x03;
10438		}
10439	     }
10440          } else {								/* All */
10441	     if(vbflag & TV_SCART)  CR30 |= 0x10;
10442	     if(vbflag & TV_SVIDEO) CR30 |= 0x08;
10443	     if(vbflag & TV_AVIDEO) CR30 |= 0x04;
10444	     if(!(CR30 & 0x1C))	    CR30 |= 0x08;    /* default: SVIDEO */
10445
10446	     if(vbflag & TV_PAL) {
10447		CR31 |= 0x01;
10448		CR35 |= 0x01;
10449		if( (pSiS->VBFlags2 & VB2_SISBRIDGE) ||
10450		    ((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->ChrontelType == CHRONTEL_701x)) )  {
10451		   if(vbflag & TV_PALM) {
10452		      CR38 |= 0x40;
10453		      CR35 |= 0x04;
10454		   } else if(vbflag & TV_PALN) {
10455		      CR38 |= 0x80;
10456		      CR35 |= 0x08;
10457		   }
10458	        }
10459	     } else {
10460		CR31 &= ~0x01;
10461		CR35 &= ~0x01;
10462		if(vbflag & TV_NTSCJ) {
10463		   CR38 |= 0x40;  /* TW, not BIOS */
10464		   CR35 |= 0x02;
10465		}
10466	     }
10467	     if(vbflag & TV_SCART) {
10468		CR31 |= 0x01;
10469		CR35 |= 0x01;
10470	     }
10471	  }
10472
10473	  CR31 &= ~0x04;   /* Clear NotSimuMode */
10474	  pSiS->SiS_Pr->SiS_CHOverScan = pSiS->UseCHOverScan;
10475	  if((pSiS->OptTVSOver == 1) && (pSiS->ChrontelType == CHRONTEL_700x)) {
10476	     pSiS->SiS_Pr->SiS_CHSOverScan = TRUE;
10477	  } else {
10478	     pSiS->SiS_Pr->SiS_CHSOverScan = FALSE;
10479	  }
10480#ifdef SIS_CP
10481	  SIS_CP_DRIVER_CONFIG
10482#endif
10483	  break;
10484
10485       case CRT2_LCD:
10486	  CR30 |= 0x20;
10487	  SiS_SetEnableDstn(pSiS->SiS_Pr, pSiS->DSTN);
10488	  SiS_SetEnableFstn(pSiS->SiS_Pr, pSiS->FSTN);
10489	  break;
10490
10491       case CRT2_VGA:
10492	  CR30 |= 0x40;
10493	  break;
10494
10495       default:
10496	  CR30 |= 0x00;
10497	  CR31 |= 0x20;    /* VB_OUTPUT_DISABLE */
10498	  if(pSiS->UseVESA) {
10499	     crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10500	  }
10501       }
10502
10503    }
10504
10505    if(vbflag & CRT1_LCDA) {
10506       switch(viewmode) {
10507       case SIS_MODE_CRT1:
10508	  CR38 |= 0x01;
10509	  break;
10510       case SIS_MODE_CRT2:
10511	  if(vbflag & (CRT2_TV|CRT2_VGA)) {
10512	     CR30 |= 0x02;
10513	     CR38 |= 0x01;
10514	  } else {
10515	     CR38 |= 0x03;
10516	  }
10517	  break;
10518       case SIS_MODE_SIMU:
10519       default:
10520	  if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10521	     CR30 |= 0x01;
10522	  }
10523	  break;
10524       }
10525    } else {
10526       if(vbflag & (CRT2_TV|CRT2_LCD|CRT2_VGA)) {
10527          CR30 |= 0x01;
10528       }
10529    }
10530
10531    if(pSiS->UseVESA) {
10532       CR31 &= ~0x40;   /* Clear Drivermode */
10533       CR31 |= 0x06;    /* Set SlaveMode, Enable SimuMode in Slavemode */
10534#ifdef TWDEBUG
10535       CR31 |= 0x40;    /* DEBUG (for non-slave mode VESA) */
10536       crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10537#endif
10538    } else {
10539       CR31 |=  0x40;  /* Set Drivermode */
10540       CR31 &=  ~0x06; /* Disable SlaveMode, disable SimuMode in SlaveMode */
10541       if(!pSiS->IsCustom) {
10542          crt1rateindex = SISSearchCRT1Rate(pScrn, mymode);
10543       }
10544    }
10545
10546    switch(viewmode) {
10547	case SIS_MODE_SIMU:
10548	   CR33 = 0;
10549	   if(!(vbflag & CRT1_LCDA)) {
10550	      CR33 |= (crt1rateindex & 0x0f);
10551	   }
10552	   if(vbflag & CRT2_VGA) {
10553	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10554	   }
10555	   break;
10556	case SIS_MODE_CRT1:
10557	   CR33 &= 0xf0;
10558	   if(!(vbflag & CRT1_LCDA)) {
10559	      CR33 |= (crt1rateindex & 0x0f);
10560	   }
10561	   break;
10562	case SIS_MODE_CRT2:
10563	   CR33 &= 0x0f;
10564	   if(vbflag & CRT2_VGA) {
10565	      CR33 |= ((crt1rateindex & 0x0f) << 4);
10566	   }
10567	   break;
10568     }
10569
10570     if((!pSiS->UseVESA) && (vbflag & CRT2_ENABLE)) {
10571	if(pSiS->CRT1off) CR33 &= 0xf0;
10572     }
10573
10574     if(pSiS->NewCRLayout) {
10575
10576	CR31 &= 0xfe;   /* Clear PAL flag (now in CR35) */
10577	CR38 &= 0x07;   /* Use only LCDA and HiVision/YPbPr bits */
10578	outSISIDXREG(SISCR, 0x30, CR30);
10579	outSISIDXREG(SISCR, 0x31, CR31);
10580	outSISIDXREG(SISCR, 0x33, CR33);
10581	outSISIDXREG(SISCR, 0x35, CR35);
10582	setSISIDXREG(SISCR, 0x38, 0xf8, CR38);
10583	outSISIDXREG(SISCR, 0x39, CR39);
10584
10585	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10586		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR35=0x%02x,CR38=%02x\n",
10587		    CR30, CR31, CR33, CR35, CR38);
10588
10589     } else {
10590
10591	outSISIDXREG(SISCR, 0x30, CR30);
10592	outSISIDXREG(SISCR, 0x31, CR31);
10593	outSISIDXREG(SISCR, 0x33, CR33);
10594	if(temp) {
10595	   outSISIDXREG(SISCR, temp, CR38);
10596	}
10597	if(pSiS->VGAEngine == SIS_315_VGA) {
10598	   outSISIDXREG(SISCR, 0x3b, CR3B);
10599	   outSISIDXREG(SISCR, 0x79, CR79);
10600	}
10601
10602	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, SISVERBLEVEL,
10603		"After:  CR30=0x%02x,CR31=0x%02x,CR33=0x%02x,CR%02x=%02x\n",
10604		    CR30, CR31, CR33, temp, CR38);
10605     }
10606
10607     pSiS->SiS_Pr->SiS_UseOEM = pSiS->OptUseOEM;
10608
10609     /* Enable TurboQueue */
10610#ifdef SISVRAMQ
10611     if(pSiS->VGAEngine != SIS_315_VGA)
10612#endif
10613	SiSEnableTurboQueue(pScrn);
10614
10615     if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
10616	/* Switch on CRT1 for modes that require the bridge in SlaveMode */
10617	andSISIDXREG(SISSR,0x1f,0x3f);
10618	inSISIDXREG(SISCR, 0x17, CR17);
10619	if(!(CR17 & 0x80)) {
10620	   orSISIDXREG(SISCR, 0x17, 0x80);
10621	   outSISIDXREG(SISSR, 0x00, 0x01);
10622	   usleep(10000);
10623	   outSISIDXREG(SISSR, 0x00, 0x03);
10624	}
10625     }
10626}
10627
10628/* Functions for adjusting various TV settings */
10629
10630/* These are used by the PostSetMode() functions as well as
10631 * the display properties tool SiSCtrl.
10632 *
10633 * There is each a Set and a Get routine. The Set functions
10634 * take a value of the same range as the corresponding option.
10635 * The Get routines return a value of the same range (although
10636 * not necessarily the same value as previously set because
10637 * of the lower resolution of the respective setting compared
10638 * to the valid range).
10639 * The Get routines return -2 on error (eg. hardware does not
10640 * support this setting).
10641 * Note: The x and y positioning routines accept a position
10642 * RELATIVE to the default position. All other routines
10643 * take ABSOLUTE values.
10644 *
10645 * The Set functions will store the property regardless if TV is
10646 * currently used or not and if the hardware supports the property
10647 * or not. The Get routines will return this stored
10648 * value if TV is not currently used (because the register does
10649 * not contain the correct value then) or if the hardware supports
10650 * the respective property. This should make it easier for the
10651 * display property tool because it does not have to know the
10652 * hardware features.
10653 *
10654 * All the routines are dual head aware. It does not matter
10655 * if the function is called from the CRT1 or CRT2 session.
10656 * The values will be in pSiSEnt anyway, and read from there
10657 * if we're running dual head.
10658 */
10659
10660void SiS_SetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn, int val)
10661{
10662   SISPtr pSiS = SISPTR(pScrn);
10663#ifdef SISDUALHEAD
10664   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10665#endif
10666
10667   pSiS->chtvlumabandwidthcvbs = val;
10668#ifdef SISDUALHEAD
10669   if(pSiSEnt) pSiSEnt->chtvlumabandwidthcvbs = val;
10670#endif
10671
10672   if(!(pSiS->VBFlags & CRT2_TV)) return;
10673   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10674
10675#ifdef UNLOCK_ALWAYS
10676   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10677#endif
10678
10679   switch(pSiS->ChrontelType) {
10680       case CHRONTEL_700x:
10681           val /= 8;
10682           if((val == 0) || (val == 1)) {
10683	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xFE);
10684           }
10685	   break;
10686       case CHRONTEL_701x:
10687           val /= 4;
10688	   if((val >= 0) && (val <= 3)) {
10689	       SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, val, 0xFC);
10690	   }
10691           break;
10692   }
10693}
10694
10695int SiS_GetCHTVlumabandwidthcvbs(ScrnInfoPtr pScrn)
10696{
10697   SISPtr pSiS = SISPTR(pScrn);
10698#ifdef SISDUALHEAD
10699   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10700#endif
10701
10702   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10703#ifdef SISDUALHEAD
10704      if(pSiSEnt && pSiS->DualHeadMode)
10705           return (int)pSiSEnt->chtvlumabandwidthcvbs;
10706      else
10707#endif
10708           return (int)pSiS->chtvlumabandwidthcvbs;
10709   } else {
10710#ifdef UNLOCK_ALWAYS
10711      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10712#endif
10713      switch(pSiS->ChrontelType) {
10714      case CHRONTEL_700x:
10715           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x01) * 8);
10716      case CHRONTEL_701x:
10717	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x03) * 4);
10718      default:
10719           return (int)pSiS->chtvlumabandwidthcvbs;
10720      }
10721   }
10722}
10723
10724void SiS_SetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn, int val)
10725{
10726   SISPtr pSiS = SISPTR(pScrn);
10727#ifdef SISDUALHEAD
10728   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10729#endif
10730
10731   pSiS->chtvlumabandwidthsvideo = val;
10732#ifdef SISDUALHEAD
10733   if(pSiSEnt) pSiSEnt->chtvlumabandwidthsvideo = val;
10734#endif
10735
10736   if(!(pSiS->VBFlags & CRT2_TV)) return;
10737   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10738
10739#ifdef UNLOCK_ALWAYS
10740   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10741#endif
10742
10743   switch(pSiS->ChrontelType) {
10744       case CHRONTEL_700x:
10745           val /= 6;
10746           if((val >= 0) && (val <= 2)) {
10747	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 1), 0xF9);
10748           }
10749	   break;
10750       case CHRONTEL_701x:
10751           val /= 4;
10752	   if((val >= 0) && (val <= 3)) {
10753	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 2), 0xF3);
10754	   }
10755           break;
10756   }
10757}
10758
10759int SiS_GetCHTVlumabandwidthsvideo(ScrnInfoPtr pScrn)
10760{
10761   SISPtr pSiS = SISPTR(pScrn);
10762#ifdef SISDUALHEAD
10763   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10764#endif
10765
10766   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10767#ifdef SISDUALHEAD
10768      if(pSiSEnt && pSiS->DualHeadMode)
10769           return (int)pSiSEnt->chtvlumabandwidthsvideo;
10770      else
10771#endif
10772           return (int)pSiS->chtvlumabandwidthsvideo;
10773   } else {
10774#ifdef UNLOCK_ALWAYS
10775      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10776#endif
10777      switch(pSiS->ChrontelType) {
10778      case CHRONTEL_700x:
10779           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x06) >> 1) * 6);
10780      case CHRONTEL_701x:
10781	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x0c) >> 2) * 4);
10782      default:
10783           return (int)pSiS->chtvlumabandwidthsvideo;
10784      }
10785   }
10786}
10787
10788void SiS_SetCHTVlumaflickerfilter(ScrnInfoPtr pScrn, int val)
10789{
10790   SISPtr pSiS = SISPTR(pScrn);
10791#ifdef SISDUALHEAD
10792   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10793#endif
10794
10795   pSiS->chtvlumaflickerfilter = val;
10796#ifdef SISDUALHEAD
10797   if(pSiSEnt) pSiSEnt->chtvlumaflickerfilter = val;
10798#endif
10799
10800   if(!(pSiS->VBFlags & CRT2_TV)) return;
10801   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10802
10803#ifdef UNLOCK_ALWAYS
10804   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10805#endif
10806
10807   switch(pSiS->ChrontelType) {
10808       case CHRONTEL_700x:
10809           val /= 6;
10810           if((val >= 0) && (val <= 2)) {
10811	      UShort reg = 0;
10812	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10813	      reg = (reg & 0xf0) | ((reg & 0x0c) >> 2) | (val << 2);
10814              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10815           }
10816	   break;
10817       case CHRONTEL_701x:
10818           val /= 4;
10819	   if((val >= 0) && (val <= 3)) {
10820	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 2), 0xF3);
10821	   }
10822           break;
10823   }
10824}
10825
10826int SiS_GetCHTVlumaflickerfilter(ScrnInfoPtr pScrn)
10827{
10828   SISPtr pSiS = SISPTR(pScrn);
10829#ifdef SISDUALHEAD
10830   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10831#endif
10832
10833   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10834#ifdef SISDUALHEAD
10835      if(pSiSEnt && pSiS->DualHeadMode)
10836          return (int)pSiSEnt->chtvlumaflickerfilter;
10837      else
10838#endif
10839          return (int)pSiS->chtvlumaflickerfilter;
10840   } else {
10841#ifdef UNLOCK_ALWAYS
10842      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10843#endif
10844      switch(pSiS->ChrontelType) {
10845      case CHRONTEL_700x:
10846           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x03) * 6);
10847      case CHRONTEL_701x:
10848	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 4);
10849      default:
10850           return (int)pSiS->chtvlumaflickerfilter;
10851      }
10852   }
10853}
10854
10855void SiS_SetCHTVchromabandwidth(ScrnInfoPtr pScrn, int val)
10856{
10857   SISPtr pSiS = SISPTR(pScrn);
10858#ifdef SISDUALHEAD
10859   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10860#endif
10861
10862   pSiS->chtvchromabandwidth = val;
10863#ifdef SISDUALHEAD
10864   if(pSiSEnt) pSiSEnt->chtvchromabandwidth = val;
10865#endif
10866
10867   if(!(pSiS->VBFlags & CRT2_TV)) return;
10868   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10869
10870#ifdef UNLOCK_ALWAYS
10871   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10872#endif
10873
10874   switch(pSiS->ChrontelType) {
10875       case CHRONTEL_700x:
10876           val /= 4;
10877           if((val >= 0) && (val <= 3)) {
10878              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, (val << 4), 0xCF);
10879           }
10880	   break;
10881       case CHRONTEL_701x:
10882           val /= 8;
10883	   if((val >= 0) && (val <= 1)) {
10884	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, (val << 4), 0xEF);
10885	   }
10886           break;
10887   }
10888}
10889
10890int SiS_GetCHTVchromabandwidth(ScrnInfoPtr pScrn)
10891{
10892   SISPtr pSiS = SISPTR(pScrn);
10893#ifdef SISDUALHEAD
10894   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10895#endif
10896
10897   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10898#ifdef SISDUALHEAD
10899      if(pSiSEnt && pSiS->DualHeadMode)
10900           return (int)pSiSEnt->chtvchromabandwidth;
10901      else
10902#endif
10903           return (int)pSiS->chtvchromabandwidth;
10904   } else {
10905#ifdef UNLOCK_ALWAYS
10906      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10907#endif
10908      switch(pSiS->ChrontelType) {
10909      case CHRONTEL_700x:
10910           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x30) >> 4) * 4);
10911      case CHRONTEL_701x:
10912	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x10) >> 4) * 8);
10913      default:
10914           return (int)pSiS->chtvchromabandwidth;
10915      }
10916   }
10917}
10918
10919void SiS_SetCHTVchromaflickerfilter(ScrnInfoPtr pScrn, int val)
10920{
10921   SISPtr pSiS = SISPTR(pScrn);
10922#ifdef SISDUALHEAD
10923   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10924#endif
10925
10926   pSiS->chtvchromaflickerfilter = val;
10927#ifdef SISDUALHEAD
10928   if(pSiSEnt) pSiSEnt->chtvchromaflickerfilter = val;
10929#endif
10930
10931   if(!(pSiS->VBFlags & CRT2_TV)) return;
10932   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
10933
10934#ifdef UNLOCK_ALWAYS
10935   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10936#endif
10937
10938   switch(pSiS->ChrontelType) {
10939       case CHRONTEL_700x:
10940           val /= 6;
10941           if((val >= 0) && (val <= 2)) {
10942	      UShort reg = 0;
10943	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
10944	      reg = (reg & 0xc0) | ((reg & 0x0c) >> 2) | ((reg & 0x03) << 2) | (val << 4);
10945              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
10946           }
10947	   break;
10948       case CHRONTEL_701x:
10949           val /= 4;
10950	   if((val >= 0) && (val <= 3)) {
10951	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x01, (val << 4), 0xCF);
10952	   }
10953           break;
10954   }
10955}
10956
10957int SiS_GetCHTVchromaflickerfilter(ScrnInfoPtr pScrn)
10958{
10959   SISPtr pSiS = SISPTR(pScrn);
10960#ifdef SISDUALHEAD
10961   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10962#endif
10963
10964   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
10965#ifdef SISDUALHEAD
10966      if(pSiSEnt && pSiS->DualHeadMode)
10967           return (int)pSiSEnt->chtvchromaflickerfilter;
10968      else
10969#endif
10970           return (int)pSiS->chtvchromaflickerfilter;
10971   } else {
10972#ifdef UNLOCK_ALWAYS
10973      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
10974#endif
10975      switch(pSiS->ChrontelType) {
10976      case CHRONTEL_700x:
10977           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 6);
10978      case CHRONTEL_701x:
10979	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x30) >> 4) * 4);
10980      default:
10981           return (int)pSiS->chtvchromaflickerfilter;
10982      }
10983   }
10984}
10985
10986void SiS_SetCHTVcvbscolor(ScrnInfoPtr pScrn, int val)
10987{
10988   SISPtr pSiS = SISPTR(pScrn);
10989#ifdef SISDUALHEAD
10990   SISEntPtr pSiSEnt = pSiS->entityPrivate;
10991#endif
10992
10993   pSiS->chtvcvbscolor = val ? 1 : 0;
10994#ifdef SISDUALHEAD
10995   if(pSiSEnt) pSiSEnt->chtvcvbscolor = pSiS->chtvcvbscolor;
10996#endif
10997
10998   if(!(pSiS->VBFlags & CRT2_TV)) return;
10999   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11000
11001#ifdef UNLOCK_ALWAYS
11002   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11003#endif
11004
11005   switch(pSiS->ChrontelType) {
11006       case CHRONTEL_700x:
11007           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x40, 0x00);
11008           else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, 0x00, ~0x40);
11009	   break;
11010       case CHRONTEL_701x:
11011           if(!val)  SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x00, ~0x20);
11012	   else      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x02, 0x20, 0x00);
11013           break;
11014   }
11015}
11016
11017int SiS_GetCHTVcvbscolor(ScrnInfoPtr pScrn)
11018{
11019   SISPtr pSiS = SISPTR(pScrn);
11020#ifdef SISDUALHEAD
11021   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11022#endif
11023
11024   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11025#ifdef SISDUALHEAD
11026      if(pSiSEnt && pSiS->DualHeadMode)
11027           return (int)pSiSEnt->chtvcvbscolor;
11028      else
11029#endif
11030           return (int)pSiS->chtvcvbscolor;
11031   } else {
11032#ifdef UNLOCK_ALWAYS
11033      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11034#endif
11035      switch(pSiS->ChrontelType) {
11036      case CHRONTEL_700x:
11037           return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x40) >> 6) ^ 0x01);
11038      case CHRONTEL_701x:
11039	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x02) & 0x20) >> 5) ^ 0x01);
11040      default:
11041           return (int)pSiS->chtvcvbscolor;
11042      }
11043   }
11044}
11045
11046void SiS_SetCHTVtextenhance(ScrnInfoPtr pScrn, int val)
11047{
11048   SISPtr pSiS = SISPTR(pScrn);
11049#ifdef SISDUALHEAD
11050   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11051#endif
11052
11053   pSiS->chtvtextenhance = val;
11054#ifdef SISDUALHEAD
11055   if(pSiSEnt) pSiSEnt->chtvtextenhance = val;
11056#endif
11057
11058   if(!(pSiS->VBFlags & CRT2_TV)) return;
11059   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11060
11061#ifdef UNLOCK_ALWAYS
11062   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11063#endif
11064
11065   switch(pSiS->ChrontelType) {
11066       case CHRONTEL_700x:
11067           val /= 6;
11068           if((val >= 0) && (val <= 2)) {
11069	      UShort reg = 0;
11070	      reg = SiS_GetCH70xx(pSiS->SiS_Pr, 0x01);
11071	      reg = (reg & 0xf0) | ((reg & 0x03) << 2) | val;
11072              SiS_SetCH70xx(pSiS->SiS_Pr, 0x01, reg);
11073           }
11074	   break;
11075       case CHRONTEL_701x:
11076           val /= 2;
11077	   if((val >= 0) && (val <= 7)) {
11078	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x03, val, 0xF8);
11079	   }
11080           break;
11081   }
11082}
11083
11084int SiS_GetCHTVtextenhance(ScrnInfoPtr pScrn)
11085{
11086   SISPtr pSiS = SISPTR(pScrn);
11087#ifdef SISDUALHEAD
11088   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11089#endif
11090
11091   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11092#ifdef SISDUALHEAD
11093      if(pSiSEnt && pSiS->DualHeadMode)
11094           return (int)pSiSEnt->chtvtextenhance;
11095      else
11096#endif
11097           return (int)pSiS->chtvtextenhance;
11098   } else {
11099#ifdef UNLOCK_ALWAYS
11100      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11101#endif
11102      switch(pSiS->ChrontelType) {
11103      case CHRONTEL_700x:
11104	   return (int)(((SiS_GetCH70xx(pSiS->SiS_Pr, 0x01) & 0x0c) >> 2) * 6);
11105      case CHRONTEL_701x:
11106	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x03) & 0x07) * 2);
11107      default:
11108           return (int)pSiS->chtvtextenhance;
11109      }
11110   }
11111}
11112
11113void SiS_SetCHTVcontrast(ScrnInfoPtr pScrn, int val)
11114{
11115   SISPtr pSiS = SISPTR(pScrn);
11116#ifdef SISDUALHEAD
11117   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11118#endif
11119
11120   pSiS->chtvcontrast = val;
11121#ifdef SISDUALHEAD
11122   if(pSiSEnt) pSiSEnt->chtvcontrast = val;
11123#endif
11124
11125   if(!(pSiS->VBFlags & CRT2_TV)) return;
11126   if(!(pSiS->VBFlags2 & VB2_CHRONTEL)) return;
11127
11128#ifdef UNLOCK_ALWAYS
11129   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11130#endif
11131
11132   val /= 2;
11133   if((val >= 0) && (val <= 7)) {
11134       switch(pSiS->ChrontelType) {
11135       case CHRONTEL_700x:
11136              SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x11, val, 0xF8);
11137	      break;
11138       case CHRONTEL_701x:
11139	      SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, val, 0xF8);
11140              break;
11141       }
11142       SiS_DDC2Delay(pSiS->SiS_Pr, 1000);
11143   }
11144}
11145
11146int SiS_GetCHTVcontrast(ScrnInfoPtr pScrn)
11147{
11148   SISPtr pSiS = SISPTR(pScrn);
11149#ifdef SISDUALHEAD
11150   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11151#endif
11152
11153   if(!((pSiS->VBFlags2 & VB2_CHRONTEL) && (pSiS->VBFlags & CRT2_TV))) {
11154#ifdef SISDUALHEAD
11155      if(pSiSEnt && pSiS->DualHeadMode)
11156           return (int)pSiSEnt->chtvcontrast;
11157      else
11158#endif
11159           return (int)pSiS->chtvcontrast;
11160   } else {
11161#ifdef UNLOCK_ALWAYS
11162      sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11163#endif
11164      switch(pSiS->ChrontelType) {
11165      case CHRONTEL_700x:
11166           return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x11) & 0x07) * 2);
11167      case CHRONTEL_701x:
11168	   return (int)((SiS_GetCH70xx(pSiS->SiS_Pr, 0x08) & 0x07) * 2);
11169      default:
11170           return (int)pSiS->chtvcontrast;
11171      }
11172   }
11173}
11174
11175void SiS_SetSISTVedgeenhance(ScrnInfoPtr pScrn, int val)
11176{
11177   SISPtr pSiS = SISPTR(pScrn);
11178#ifdef SISDUALHEAD
11179   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11180#endif
11181
11182   pSiS->sistvedgeenhance = val;
11183#ifdef SISDUALHEAD
11184   if(pSiSEnt) pSiSEnt->sistvedgeenhance = val;
11185#endif
11186
11187   if(!(pSiS->VBFlags2 & VB2_301))  return;
11188   if(!(pSiS->VBFlags & CRT2_TV))   return;
11189
11190#ifdef UNLOCK_ALWAYS
11191   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11192#endif
11193
11194   val /= 2;
11195   if((val >= 0) && (val <= 7)) {
11196      setSISIDXREG(SISPART2,0x3A, 0x1F, (val << 5));
11197   }
11198}
11199
11200int SiS_GetSISTVedgeenhance(ScrnInfoPtr pScrn)
11201{
11202   SISPtr pSiS = SISPTR(pScrn);
11203   int result = pSiS->sistvedgeenhance;
11204   UChar temp;
11205#ifdef SISDUALHEAD
11206   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11207
11208   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvedgeenhance;
11209#endif
11210
11211   if(!(pSiS->VBFlags2 & VB2_301))  return result;
11212   if(!(pSiS->VBFlags & CRT2_TV))   return result;
11213
11214#ifdef UNLOCK_ALWAYS
11215   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11216#endif
11217   inSISIDXREG(SISPART2, 0x3a, temp);
11218   return(int)(((temp & 0xe0) >> 5) * 2);
11219}
11220
11221void SiS_SetSISTVantiflicker(ScrnInfoPtr pScrn, int val)
11222{
11223   SISPtr pSiS = SISPTR(pScrn);
11224#ifdef SISDUALHEAD
11225   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11226#endif
11227
11228   pSiS->sistvantiflicker = val;
11229#ifdef SISDUALHEAD
11230   if(pSiSEnt) pSiSEnt->sistvantiflicker = val;
11231#endif
11232
11233   if(!(pSiS->VBFlags & CRT2_TV))      return;
11234   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11235   if(pSiS->VBFlags & TV_HIVISION)     return;
11236   if((pSiS->VBFlags & TV_YPBPR) &&
11237      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return;
11238
11239#ifdef UNLOCK_ALWAYS
11240   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11241#endif
11242
11243   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11244   if((val >= 0) && (val <= 4)) {
11245      setSISIDXREG(SISPART2,0x0A,0x8F, (val << 4));
11246   }
11247}
11248
11249int SiS_GetSISTVantiflicker(ScrnInfoPtr pScrn)
11250{
11251   SISPtr pSiS = SISPTR(pScrn);
11252   int result = pSiS->sistvantiflicker;
11253   UChar temp;
11254#ifdef SISDUALHEAD
11255   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11256
11257   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvantiflicker;
11258#endif
11259
11260   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11261   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11262   if(pSiS->VBFlags & TV_HIVISION)       return result;
11263   if((pSiS->VBFlags & TV_YPBPR) &&
11264      (pSiS->VBFlags & (TV_YPBPR525P | TV_YPBPR625P | TV_YPBPR750P | TV_YPBPR1080I))) return result;
11265
11266#ifdef UNLOCK_ALWAYS
11267   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11268#endif
11269   inSISIDXREG(SISPART2, 0x0a, temp);
11270   return(int)((temp & 0x70) >> 4);
11271}
11272
11273void SiS_SetSISTVsaturation(ScrnInfoPtr pScrn, int val)
11274{
11275   SISPtr pSiS = SISPTR(pScrn);
11276#ifdef SISDUALHEAD
11277   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11278#endif
11279
11280   pSiS->sistvsaturation = val;
11281#ifdef SISDUALHEAD
11282   if(pSiSEnt) pSiSEnt->sistvsaturation = val;
11283#endif
11284
11285   if(!(pSiS->VBFlags & CRT2_TV)) return;
11286   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return;
11287   if(pSiS->VBFlags2 & VB2_301) return;
11288
11289#ifdef UNLOCK_ALWAYS
11290   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11291#endif
11292
11293   val /= 2;
11294   if((val >= 0) && (val <= 7)) {
11295      setSISIDXREG(SISPART4,0x21,0xF8, val);
11296   }
11297}
11298
11299int SiS_GetSISTVsaturation(ScrnInfoPtr pScrn)
11300{
11301   SISPtr pSiS = SISPTR(pScrn);
11302   int result = pSiS->sistvsaturation;
11303   UChar temp;
11304#ifdef SISDUALHEAD
11305   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11306
11307   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->sistvsaturation;
11308#endif
11309
11310   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE)) return result;
11311   if(pSiS->VBFlags2 & VB2_301)          return result;
11312   if(!(pSiS->VBFlags & CRT2_TV))        return result;
11313
11314#ifdef UNLOCK_ALWAYS
11315   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11316#endif
11317   inSISIDXREG(SISPART4, 0x21, temp);
11318   return(int)((temp & 0x07) * 2);
11319}
11320
11321void SiS_SetSISTVcolcalib(ScrnInfoPtr pScrn, int val, Bool coarse)
11322{
11323   SISPtr pSiS = SISPTR(pScrn);
11324#ifdef SISDUALHEAD
11325   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11326#endif
11327   int ccoarse, cfine, cbase = pSiS->sistvccbase;
11328   /* UChar temp; */
11329
11330#ifdef SISDUALHEAD
11331   if(pSiSEnt && pSiS->DualHeadMode) cbase = pSiSEnt->sistvccbase;
11332#endif
11333
11334   if(coarse) {
11335      pSiS->sistvcolcalibc = ccoarse = val;
11336      cfine = pSiS->sistvcolcalibf;
11337#ifdef SISDUALHEAD
11338      if(pSiSEnt) {
11339         pSiSEnt->sistvcolcalibc = val;
11340	 if(pSiS->DualHeadMode) cfine = pSiSEnt->sistvcolcalibf;
11341      }
11342#endif
11343   } else {
11344      pSiS->sistvcolcalibf = cfine = val;
11345      ccoarse = pSiS->sistvcolcalibc;
11346#ifdef SISDUALHEAD
11347      if(pSiSEnt) {
11348         pSiSEnt->sistvcolcalibf = val;
11349         if(pSiS->DualHeadMode) ccoarse = pSiSEnt->sistvcolcalibc;
11350      }
11351#endif
11352   }
11353
11354   if(!(pSiS->VBFlags & CRT2_TV))               return;
11355   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11356   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11357
11358#ifdef UNLOCK_ALWAYS
11359   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11360#endif
11361
11362   if((cfine >= -128) && (cfine <= 127) && (ccoarse >= -120) && (ccoarse <= 120)) {
11363      long finalcc = cbase + (((ccoarse * 256) + cfine) * 256);
11364
11365#if 0
11366      inSISIDXREG(SISPART4,0x1f,temp);
11367      if(!(temp & 0x01)) {
11368         if(pSiS->VBFlags & TV_NTSC) finalcc += 0x21ed8620;
11369	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11370	 else if(pSiS->VBFlags & TV_PALM) finalcc += ?;
11371	 else finalcc += 0x2a05d300;
11372      }
11373#endif
11374      setSISIDXREG(SISPART2,0x31,0x80,((finalcc >> 24) & 0x7f));
11375      outSISIDXREG(SISPART2,0x32,((finalcc >> 16) & 0xff));
11376      outSISIDXREG(SISPART2,0x33,((finalcc >> 8) & 0xff));
11377      outSISIDXREG(SISPART2,0x34,(finalcc & 0xff));
11378   }
11379}
11380
11381int SiS_GetSISTVcolcalib(ScrnInfoPtr pScrn, Bool coarse)
11382{
11383   SISPtr pSiS = SISPTR(pScrn);
11384#ifdef SISDUALHEAD
11385   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11386
11387   if(pSiSEnt && pSiS->DualHeadMode)
11388      if(coarse)  return (int)pSiSEnt->sistvcolcalibc;
11389      else        return (int)pSiSEnt->sistvcolcalibf;
11390   else
11391#endif
11392   if(coarse)     return (int)pSiS->sistvcolcalibc;
11393   else           return (int)pSiS->sistvcolcalibf;
11394}
11395
11396void SiS_SetSISTVcfilter(ScrnInfoPtr pScrn, int val)
11397{
11398   SISPtr pSiS = SISPTR(pScrn);
11399#ifdef SISDUALHEAD
11400   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11401#endif
11402
11403   pSiS->sistvcfilter = val ? 1 : 0;
11404#ifdef SISDUALHEAD
11405   if(pSiSEnt) pSiSEnt->sistvcfilter = pSiS->sistvcfilter;
11406#endif
11407
11408   if(!(pSiS->VBFlags & CRT2_TV))               return;
11409   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11410   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11411
11412#ifdef UNLOCK_ALWAYS
11413   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11414#endif
11415
11416   setSISIDXREG(SISPART2,0x30,~0x10,((pSiS->sistvcfilter << 4) & 0x10));
11417}
11418
11419int SiS_GetSISTVcfilter(ScrnInfoPtr pScrn)
11420{
11421   SISPtr pSiS = SISPTR(pScrn);
11422   int result = pSiS->sistvcfilter;
11423   UChar temp;
11424#ifdef SISDUALHEAD
11425   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11426
11427   if(pSiSEnt && pSiS->DualHeadMode) result = pSiSEnt->sistvcfilter;
11428#endif
11429
11430   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return result;
11431   if(!(pSiS->VBFlags & CRT2_TV))               return result;
11432   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return result;
11433
11434#ifdef UNLOCK_ALWAYS
11435   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11436#endif
11437   inSISIDXREG(SISPART2, 0x30, temp);
11438   return (int)((temp & 0x10) ? 1 : 0);
11439}
11440
11441void SiS_SetSISTVyfilter(ScrnInfoPtr pScrn, int val)
11442{
11443   SISPtr pSiS = SISPTR(pScrn);
11444#ifdef SISDUALHEAD
11445   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11446#endif
11447   UChar p35,p36,p37,p38,p48,p49,p4a,p30;
11448   int i,j;
11449
11450   pSiS->sistvyfilter = val;
11451#ifdef SISDUALHEAD
11452   if(pSiSEnt) pSiSEnt->sistvyfilter = pSiS->sistvyfilter;
11453#endif
11454
11455   if(!(pSiS->VBFlags & CRT2_TV))               return;
11456   if(!(pSiS->VBFlags2 & VB2_SISBRIDGE))        return;
11457   if(pSiS->VBFlags & (TV_HIVISION | TV_YPBPR)) return;
11458
11459   p35 = pSiS->p2_35; p36 = pSiS->p2_36;
11460   p37 = pSiS->p2_37; p38 = pSiS->p2_38;
11461   p48 = pSiS->p2_48; p49 = pSiS->p2_49;
11462   p4a = pSiS->p2_4a; p30 = pSiS->p2_30;
11463#ifdef SISDUALHEAD
11464   if(pSiSEnt && pSiS->DualHeadMode) {
11465      p35 = pSiSEnt->p2_35; p36 = pSiSEnt->p2_36;
11466      p37 = pSiSEnt->p2_37; p38 = pSiSEnt->p2_38;
11467      p48 = pSiSEnt->p2_48; p49 = pSiSEnt->p2_49;
11468      p4a = pSiSEnt->p2_4a; p30 = pSiSEnt->p2_30;
11469   }
11470#endif
11471   p30 &= 0x20;
11472
11473#ifdef UNLOCK_ALWAYS
11474   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11475#endif
11476
11477   switch(pSiS->sistvyfilter) {
11478   case 0:
11479      andSISIDXREG(SISPART2,0x30,0xdf);
11480      break;
11481   case 1:
11482      outSISIDXREG(SISPART2,0x35,p35);
11483      outSISIDXREG(SISPART2,0x36,p36);
11484      outSISIDXREG(SISPART2,0x37,p37);
11485      outSISIDXREG(SISPART2,0x38,p38);
11486      if(!(pSiS->VBFlags2 & VB2_301)) {
11487         outSISIDXREG(SISPART2,0x48,p48);
11488         outSISIDXREG(SISPART2,0x49,p49);
11489         outSISIDXREG(SISPART2,0x4a,p4a);
11490      }
11491      setSISIDXREG(SISPART2,0x30,0xdf,p30);
11492      break;
11493   case 2:
11494   case 3:
11495   case 4:
11496   case 5:
11497   case 6:
11498   case 7:
11499   case 8:
11500      if(!(pSiS->VBFlags & (TV_PALM | TV_PALN | TV_NTSCJ))) {
11501         int yindex301 = -1, yindex301B = -1;
11502	 UChar p3d4_34;
11503
11504	 inSISIDXREG(SISCR,0x34,p3d4_34);
11505
11506	 switch((p3d4_34 & 0x7f)) {
11507	 case 0x59:  /* 320x200 */
11508	 case 0x41:
11509	 case 0x4f:
11510	 case 0x50:  /* 320x240 */
11511	 case 0x56:
11512	 case 0x53:
11513	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11514	    break;
11515	 case 0x2f:  /* 640x400 */
11516	 case 0x5d:
11517	 case 0x5e:
11518	 case 0x2e:  /* 640x480 */
11519	 case 0x44:
11520	 case 0x62:
11521	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11522	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 0 : 4;
11523	    break;
11524	 case 0x31:   /* 720x480 */
11525	 case 0x33:
11526	 case 0x35:
11527	 case 0x32:   /* 720x576 */
11528	 case 0x34:
11529	 case 0x36:
11530	 case 0x5f:   /* 768x576 */
11531	 case 0x60:
11532	 case 0x61:
11533	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11534	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 1 : 5;
11535	    break;
11536	 case 0x51:   /* 400x300 */
11537	 case 0x57:
11538	 case 0x54:
11539	 case 0x30:   /* 800x600 */
11540	 case 0x47:
11541	 case 0x63:
11542	    yindex301  = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11543	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 2 : 6;
11544	    break;
11545	 case 0x52:   /* 512x384 */
11546	 case 0x58:
11547	 case 0x5c:
11548	 case 0x38:   /* 1024x768 */
11549	 case 0x4a:
11550	 case 0x64:
11551	    yindex301B = (pSiS->VBFlags & TV_NTSC) ? 3 : 7;
11552	    break;
11553	 }
11554         if(pSiS->VBFlags2 & VB2_301) {
11555            if(yindex301 >= 0) {
11556	       for(i=0, j=0x35; i<=3; i++, j++) {
11557	          outSISIDXREG(SISPART2,j,(SiSTVFilter301[yindex301].filter[pSiS->sistvyfilter-2][i]));
11558	       }
11559	    }
11560         } else {
11561            if(yindex301B >= 0) {
11562	       for(i=0, j=0x35; i<=3; i++, j++) {
11563	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11564	       }
11565	       for(i=4, j=0x48; i<=6; i++, j++) {
11566	          outSISIDXREG(SISPART2,j,(SiSTVFilter301B[yindex301B].filter[pSiS->sistvyfilter-2][i]));
11567	       }
11568	    }
11569         }
11570         orSISIDXREG(SISPART2,0x30,0x20);
11571      }
11572   }
11573}
11574
11575int SiS_GetSISTVyfilter(ScrnInfoPtr pScrn)
11576{
11577   SISPtr pSiS = SISPTR(pScrn);
11578#ifdef SISDUALHEAD
11579   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11580
11581   if(pSiSEnt && pSiS->DualHeadMode)
11582      return (int)pSiSEnt->sistvyfilter;
11583   else
11584#endif
11585      return (int)pSiS->sistvyfilter;
11586}
11587
11588void SiS_SetSIS6326TVantiflicker(ScrnInfoPtr pScrn, int val)
11589{
11590   SISPtr pSiS = SISPTR(pScrn);
11591   UChar tmp;
11592
11593   pSiS->sistvantiflicker = val;
11594
11595   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11596
11597#ifdef UNLOCK_ALWAYS
11598   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11599#endif
11600
11601   tmp = SiS6326GetTVReg(pScrn,0x00);
11602   if(!(tmp & 0x04)) return;
11603
11604   /* Valid values: 0=off, 1=low, 2=med, 3=high, 4=adaptive */
11605   if(val >= 0 && val <= 4) {
11606      tmp &= 0x1f;
11607      tmp |= (val << 5);
11608      SiS6326SetTVReg(pScrn,0x00,tmp);
11609   }
11610}
11611
11612int SiS_GetSIS6326TVantiflicker(ScrnInfoPtr pScrn)
11613{
11614   SISPtr pSiS = SISPTR(pScrn);
11615   UChar tmp;
11616
11617   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11618      return (int)pSiS->sistvantiflicker;
11619   }
11620
11621#ifdef UNLOCK_ALWAYS
11622   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11623#endif
11624
11625   tmp = SiS6326GetTVReg(pScrn,0x00);
11626   if(!(tmp & 0x04)) {
11627      return (int)pSiS->sistvantiflicker;
11628   } else {
11629      return (int)((tmp >> 5) & 0x07);
11630   }
11631}
11632
11633void SiS_SetSIS6326TVenableyfilter(ScrnInfoPtr pScrn, int val)
11634{
11635   SISPtr pSiS = SISPTR(pScrn);
11636   UChar tmp;
11637
11638   if(val) val = 1;
11639   pSiS->sis6326enableyfilter = val;
11640
11641   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11642
11643#ifdef UNLOCK_ALWAYS
11644   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11645#endif
11646
11647   tmp = SiS6326GetTVReg(pScrn,0x00);
11648   if(!(tmp & 0x04)) return;
11649
11650   tmp = SiS6326GetTVReg(pScrn,0x43);
11651   tmp &= ~0x10;
11652   tmp |= ((val & 0x01) << 4);
11653   SiS6326SetTVReg(pScrn,0x43,tmp);
11654}
11655
11656int SiS_GetSIS6326TVenableyfilter(ScrnInfoPtr pScrn)
11657{
11658   SISPtr pSiS = SISPTR(pScrn);
11659   UChar tmp;
11660
11661   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11662      return (int)pSiS->sis6326enableyfilter;
11663   }
11664
11665#ifdef UNLOCK_ALWAYS
11666   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11667#endif
11668
11669   tmp = SiS6326GetTVReg(pScrn,0x00);
11670   if(!(tmp & 0x04)) {
11671      return (int)pSiS->sis6326enableyfilter;
11672   } else {
11673      tmp = SiS6326GetTVReg(pScrn,0x43);
11674      return (int)((tmp >> 4) & 0x01);
11675   }
11676}
11677
11678void SiS_SetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn, int val)
11679{
11680   SISPtr pSiS = SISPTR(pScrn);
11681   UChar tmp;
11682
11683   if(val) val = 1;
11684   pSiS->sis6326yfilterstrong = val;
11685
11686   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
11687
11688#ifdef UNLOCK_ALWAYS
11689   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11690#endif
11691
11692   tmp = SiS6326GetTVReg(pScrn,0x00);
11693   if(!(tmp & 0x04)) return;
11694
11695   tmp = SiS6326GetTVReg(pScrn,0x43);
11696   if(tmp & 0x10) {
11697      tmp &= ~0x40;
11698      tmp |= ((val & 0x01) << 6);
11699      SiS6326SetTVReg(pScrn,0x43,tmp);
11700   }
11701}
11702
11703int SiS_GetSIS6326TVyfilterstrong(ScrnInfoPtr pScrn)
11704{
11705   SISPtr pSiS = SISPTR(pScrn);
11706   UChar tmp;
11707
11708   if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) {
11709      return (int)pSiS->sis6326yfilterstrong;
11710   }
11711
11712#ifdef UNLOCK_ALWAYS
11713   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11714#endif
11715
11716   tmp = SiS6326GetTVReg(pScrn,0x00);
11717   if(!(tmp & 0x04)) {
11718      return (int)pSiS->sis6326yfilterstrong;
11719   } else {
11720      tmp = SiS6326GetTVReg(pScrn,0x43);
11721      if(!(tmp & 0x10)) {
11722         return (int)pSiS->sis6326yfilterstrong;
11723      } else {
11724         return (int)((tmp >> 6) & 0x01);
11725      }
11726   }
11727}
11728
11729void SiS_SetTVxposoffset(ScrnInfoPtr pScrn, int val)
11730{
11731   SISPtr pSiS = SISPTR(pScrn);
11732#ifdef SISDUALHEAD
11733   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11734#endif
11735
11736#ifdef UNLOCK_ALWAYS
11737   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11738#endif
11739
11740   pSiS->tvxpos = val;
11741#ifdef SISDUALHEAD
11742   if(pSiSEnt) pSiSEnt->tvxpos = val;
11743#endif
11744
11745   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11746
11747      if(pSiS->VBFlags & CRT2_TV) {
11748
11749         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11750
11751	    int x = pSiS->tvx;
11752#ifdef SISDUALHEAD
11753	    if(pSiSEnt && pSiS->DualHeadMode) x = pSiSEnt->tvx;
11754#endif
11755	    switch(pSiS->ChrontelType) {
11756	    case CHRONTEL_700x:
11757	       if((val >= -32) && (val <= 32)) {
11758		   x += val;
11759		   if(x < 0) x = 0;
11760		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0a, (x & 0xff));
11761		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
11762	       }
11763	       break;
11764	    case CHRONTEL_701x:
11765	       /* Not supported by hardware */
11766	       break;
11767	    }
11768
11769	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11770
11771	    if((val >= -32) && (val <= 32)) {
11772
11773	        UChar p2_1f,p2_20,p2_2b,p2_42,p2_43;
11774		UShort temp;
11775		int mult;
11776
11777		p2_1f = pSiS->p2_1f;
11778		p2_20 = pSiS->p2_20;
11779		p2_2b = pSiS->p2_2b;
11780		p2_42 = pSiS->p2_42;
11781		p2_43 = pSiS->p2_43;
11782#ifdef SISDUALHEAD
11783	        if(pSiSEnt && pSiS->DualHeadMode) {
11784		   p2_1f = pSiSEnt->p2_1f;
11785		   p2_20 = pSiSEnt->p2_20;
11786		   p2_2b = pSiSEnt->p2_2b;
11787		   p2_42 = pSiSEnt->p2_42;
11788		   p2_43 = pSiSEnt->p2_43;
11789		}
11790#endif
11791		mult = 2;
11792		if(pSiS->VBFlags & TV_YPBPR) {
11793		   if(pSiS->VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)) {
11794		      mult = 4;
11795		   }
11796		}
11797
11798		temp = p2_1f | ((p2_20 & 0xf0) << 4);
11799		temp += (val * mult);
11800		p2_1f = temp & 0xff;
11801		p2_20 = (temp & 0xf00) >> 4;
11802		p2_2b = ((p2_2b & 0x0f) + (val * mult)) & 0x0f;
11803		temp = p2_43 | ((p2_42 & 0xf0) << 4);
11804		temp += (val * mult);
11805		p2_43 = temp & 0xff;
11806		p2_42 = (temp & 0xf00) >> 4;
11807		SISWaitRetraceCRT2(pScrn);
11808	        outSISIDXREG(SISPART2,0x1f,p2_1f);
11809		setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
11810		setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
11811		setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
11812		outSISIDXREG(SISPART2,0x43,p2_43);
11813	     }
11814	 }
11815      }
11816
11817   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11818
11819      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11820
11821         UChar tmp;
11822	 UShort temp1, temp2, temp3;
11823
11824         tmp = SiS6326GetTVReg(pScrn,0x00);
11825         if(tmp & 0x04) {
11826
11827	    temp1 = pSiS->tvx1;
11828            temp2 = pSiS->tvx2;
11829            temp3 = pSiS->tvx3;
11830            if((val >= -16) && (val <= 16)) {
11831	       if(val > 0) {
11832	          temp1 += (val * 4);
11833	          temp2 += (val * 4);
11834	          while((temp1 > 0x0fff) || (temp2 > 0x0fff)) {
11835	             temp1 -= 4;
11836		     temp2 -= 4;
11837	          }
11838	       } else {
11839	          val = -val;
11840	          temp3 += (val * 4);
11841	          while(temp3 > 0x03ff) {
11842	     	     temp3 -= 4;
11843	          }
11844	       }
11845            }
11846            SiS6326SetTVReg(pScrn,0x3a,(temp1 & 0xff));
11847            tmp = SiS6326GetTVReg(pScrn,0x3c);
11848            tmp &= 0xf0;
11849            tmp |= ((temp1 & 0x0f00) >> 8);
11850            SiS6326SetTVReg(pScrn,0x3c,tmp);
11851            SiS6326SetTVReg(pScrn,0x26,(temp2 & 0xff));
11852            tmp = SiS6326GetTVReg(pScrn,0x27);
11853            tmp &= 0x0f;
11854            tmp |= ((temp2 & 0x0f00) >> 4);
11855            SiS6326SetTVReg(pScrn,0x27,tmp);
11856            SiS6326SetTVReg(pScrn,0x12,(temp3 & 0xff));
11857            tmp = SiS6326GetTVReg(pScrn,0x13);
11858            tmp &= ~0xC0;
11859            tmp |= ((temp3 & 0x0300) >> 2);
11860            SiS6326SetTVReg(pScrn,0x13,tmp);
11861	 }
11862      }
11863   }
11864}
11865
11866int SiS_GetTVxposoffset(ScrnInfoPtr pScrn)
11867{
11868   SISPtr pSiS = SISPTR(pScrn);
11869#ifdef SISDUALHEAD
11870   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11871
11872   if(pSiSEnt && pSiS->DualHeadMode)
11873        return (int)pSiSEnt->tvxpos;
11874   else
11875#endif
11876        return (int)pSiS->tvxpos;
11877}
11878
11879void SiS_SetTVyposoffset(ScrnInfoPtr pScrn, int val)
11880{
11881   SISPtr pSiS = SISPTR(pScrn);
11882#ifdef SISDUALHEAD
11883   SISEntPtr pSiSEnt = pSiS->entityPrivate;
11884#endif
11885
11886#ifdef UNLOCK_ALWAYS
11887   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
11888#endif
11889
11890   pSiS->tvypos = val;
11891#ifdef SISDUALHEAD
11892   if(pSiSEnt) pSiSEnt->tvypos = val;
11893#endif
11894
11895   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
11896
11897      if(pSiS->VBFlags & CRT2_TV) {
11898
11899         if(pSiS->VBFlags2 & VB2_CHRONTEL) {
11900
11901	    int y = pSiS->tvy;
11902#ifdef SISDUALHEAD
11903	    if(pSiSEnt && pSiS->DualHeadMode) y = pSiSEnt->tvy;
11904#endif
11905	    switch(pSiS->ChrontelType) {
11906	    case CHRONTEL_700x:
11907	       if((val >= -32) && (val <= 32)) {
11908		   y -= val;
11909		   if(y < 0) y = 0;
11910		   SiS_SetCH700x(pSiS->SiS_Pr, 0x0b, (y & 0xff));
11911		   SiS_SetCH70xxANDOR(pSiS->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
11912	       }
11913	       break;
11914	    case CHRONTEL_701x:
11915	       /* Not supported by hardware */
11916	       break;
11917	    }
11918
11919	 } else if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
11920
11921	    if((val >= -32) && (val <= 32)) {
11922		char p2_01, p2_02;
11923
11924		if( (pSiS->VBFlags & TV_HIVISION) ||
11925		    ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & (TV_YPBPR1080I|TV_YPBPR750P))) ) {
11926		   val *= 2;
11927		} else {
11928		   val /= 2;  /* 4 */
11929		}
11930
11931		p2_01 = pSiS->p2_01;
11932		p2_02 = pSiS->p2_02;
11933#ifdef SISDUALHEAD
11934	        if(pSiSEnt && pSiS->DualHeadMode) {
11935		   p2_01 = pSiSEnt->p2_01;
11936		   p2_02 = pSiSEnt->p2_02;
11937		}
11938#endif
11939		p2_01 += val; /* val * 2 */
11940		p2_02 += val; /* val * 2 */
11941		if(!(pSiS->VBFlags & (TV_YPBPR | TV_HIVISION))) {
11942		   while((p2_01 <= 0) || (p2_02 <= 0)) {
11943		      p2_01 += 2;
11944		      p2_02 += 2;
11945		   }
11946		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) {
11947		   while(p2_01 <= 8) {
11948		      p2_01 += 2;
11949		      p2_02 += 2;
11950		   }
11951		} else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
11952		   while(p2_01 <= 10) {
11953		      p2_01 += 2;
11954		      p2_02 += 2;
11955		   }
11956		}
11957
11958		SISWaitRetraceCRT2(pScrn);
11959		outSISIDXREG(SISPART2,0x01,p2_01);
11960		outSISIDXREG(SISPART2,0x02,p2_02);
11961	     }
11962	 }
11963
11964      }
11965
11966   } else if(pSiS->Chipset == PCI_CHIP_SIS6326) {
11967
11968      if(pSiS->SiS6326Flags & SIS6326_TVDETECTED) {
11969
11970         UChar tmp;
11971	 int temp1, limit;
11972
11973         tmp = SiS6326GetTVReg(pScrn,0x00);
11974         if(tmp & 0x04) {
11975
11976	    if((val >= -16) && (val <= 16)) {
11977	      temp1 = (UShort)pSiS->tvy1;
11978	      limit = (pSiS->SiS6326Flags & SIS6326_TVPAL) ? 625 : 525;
11979	      if(val > 0) {
11980                temp1 += (val * 4);
11981	        if(temp1 > limit) temp1 -= limit;
11982	      } else {
11983	        val = -val;
11984	        temp1 -= (val * 2);
11985	        if(temp1 <= 0) temp1 += (limit -1);
11986	      }
11987	      SiS6326SetTVReg(pScrn,0x11,(temp1 & 0xff));
11988	      tmp = SiS6326GetTVReg(pScrn,0x13);
11989	      tmp &= ~0x30;
11990	      tmp |= ((temp1 & 0x300) >> 4);
11991	      SiS6326SetTVReg(pScrn,0x13,tmp);
11992	      if(temp1 == 1)                                 tmp = 0x10;
11993	      else {
11994	       if(pSiS->SiS6326Flags & SIS6326_TVPAL) {
11995	         if((temp1 <= 3) || (temp1 >= (limit - 2)))  tmp = 0x08;
11996	         else if(temp1 < 22)		 	     tmp = 0x02;
11997	         else 					     tmp = 0x04;
11998	       } else {
11999	         if((temp1 <= 5) || (temp1 >= (limit - 4)))  tmp = 0x08;
12000	         else if(temp1 < 19)			     tmp = 0x02;
12001	         else 					     tmp = 0x04;
12002	       }
12003	     }
12004	     SiS6326SetTVReg(pScrn,0x21,tmp);
12005           }
12006	 }
12007      }
12008   }
12009}
12010
12011int SiS_GetTVyposoffset(ScrnInfoPtr pScrn)
12012{
12013   SISPtr pSiS = SISPTR(pScrn);
12014#ifdef SISDUALHEAD
12015   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12016
12017   if(pSiSEnt && pSiS->DualHeadMode)
12018        return (int)pSiSEnt->tvypos;
12019   else
12020#endif
12021        return (int)pSiS->tvypos;
12022}
12023
12024void SiS_SetTVxscale(ScrnInfoPtr pScrn, int val)
12025{
12026   SISPtr pSiS = SISPTR(pScrn);
12027#ifdef SISDUALHEAD
12028   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12029#endif
12030
12031#ifdef UNLOCK_ALWAYS
12032   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12033#endif
12034
12035   pSiS->tvxscale = val;
12036#ifdef SISDUALHEAD
12037   if(pSiSEnt) pSiSEnt->tvxscale = val;
12038#endif
12039
12040   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12041
12042      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12043
12044	 if((val >= -16) && (val <= 16)) {
12045
12046	    UChar p2_44,p2_45,p2_46;
12047	    int scalingfactor, mult;
12048
12049	    p2_44 = pSiS->p2_44;
12050	    p2_45 = pSiS->p2_45 & 0x3f;
12051	    p2_46 = pSiS->p2_46 & 0x07;
12052#ifdef SISDUALHEAD
12053	    if(pSiSEnt && pSiS->DualHeadMode) {
12054	       p2_44 = pSiSEnt->p2_44;
12055	       p2_45 = pSiSEnt->p2_45 & 0x3f;
12056	       p2_46 = pSiSEnt->p2_46 & 0x07;
12057	    }
12058#endif
12059	    scalingfactor = (p2_46 << 13) | ((p2_45 & 0x1f) << 8) | p2_44;
12060
12061	    mult = 64;
12062	    if(pSiS->VBFlags & TV_YPBPR) {
12063	       if(pSiS->VBFlags & TV_YPBPR1080I) {
12064	          mult = 190;
12065	       } else if(pSiS->VBFlags & TV_YPBPR750P) {
12066	          mult = 360;
12067	       }
12068	    } else if(pSiS->VBFlags & TV_HIVISION) {
12069	       mult = 190;
12070	    }
12071
12072	    if(val < 0) {
12073	       p2_45 &= 0xdf;
12074	       scalingfactor += ((-val) * mult);
12075	       if(scalingfactor > 0xffff) scalingfactor = 0xffff;
12076	    } else if(val > 0) {
12077	       p2_45 &= 0xdf;
12078	       scalingfactor -= (val * mult);
12079	       if(scalingfactor < 1) scalingfactor = 1;
12080	    }
12081
12082	    p2_44 = scalingfactor & 0xff;
12083	    p2_45 &= 0xe0;
12084	    p2_45 |= ((scalingfactor >> 8) & 0x1f);
12085	    p2_46 = ((scalingfactor >> 13) & 0x07);
12086
12087	    SISWaitRetraceCRT2(pScrn);
12088	    outSISIDXREG(SISPART2,0x44,p2_44);
12089	    setSISIDXREG(SISPART2,0x45,0xC0,p2_45);
12090	    if(!(pSiS->VBFlags2 & VB2_301)) {
12091	       setSISIDXREG(SISPART2,0x46,0xF8,p2_46);
12092	    }
12093
12094	 }
12095
12096      }
12097
12098   }
12099}
12100
12101int SiS_GetTVxscale(ScrnInfoPtr pScrn)
12102{
12103   SISPtr pSiS = SISPTR(pScrn);
12104#ifdef SISDUALHEAD
12105   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12106
12107   if(pSiSEnt && pSiS->DualHeadMode)
12108        return (int)pSiSEnt->tvxscale;
12109   else
12110#endif
12111        return (int)pSiS->tvxscale;
12112}
12113
12114void SiS_SetTVyscale(ScrnInfoPtr pScrn, int val)
12115{
12116   SISPtr pSiS = SISPTR(pScrn);
12117#ifdef SISDUALHEAD
12118   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12119#endif
12120
12121#ifdef UNLOCK_ALWAYS
12122   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12123#endif
12124
12125   if(val < -4) val = -4;
12126   if(val > 3)  val = 3;
12127
12128   pSiS->tvyscale = val;
12129#ifdef SISDUALHEAD
12130   if(pSiSEnt) pSiSEnt->tvyscale = val;
12131#endif
12132
12133   if(pSiS->VGAEngine == SIS_300_VGA || pSiS->VGAEngine == SIS_315_VGA) {
12134
12135      if((pSiS->VBFlags & CRT2_TV) && (pSiS->VBFlags2 & VB2_SISBRIDGE)) {
12136
12137	 int srindex = -1, newvde, i = 0, j, vlimit, temp, vdediv;
12138	 int hdclk = 0;
12139	 UChar p3d4_34;
12140	 Bool found = FALSE;
12141	 Bool usentsc = FALSE;
12142	 Bool is750p = FALSE;
12143	 Bool is1080i = FALSE;
12144	 Bool skipmoveup = FALSE;
12145
12146	 SiS_UnLockCRT2(pSiS->SiS_Pr);
12147
12148	 if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525P)) {
12149	    vlimit = 525 - 7;
12150	    vdediv = 1;
12151	    usentsc = TRUE;
12152	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR625P)) {
12153	    vlimit = 625 - 7;
12154	    vdediv = 1;
12155	 } else if((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR750P)) {
12156	    vlimit = 750 - 7;
12157	    vdediv = 1;
12158	    is750p = TRUE;
12159	 } else if(((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR1080I)) ||
12160	           (pSiS->VBFlags & TV_HIVISION)) {
12161	    vlimit = (1125 - 7) / 2;
12162	    vdediv = 2;
12163	    is1080i = TRUE;
12164	 } else {
12165	    if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
12166	        ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
12167	       usentsc = TRUE;
12168	    }
12169	    vlimit = usentsc ? 259 : 309;
12170	    vdediv = 2;
12171	 }
12172
12173	 inSISIDXREG(SISCR,0x34,p3d4_34);
12174
12175	 switch((p3d4_34 & 0x7f)) {
12176	 case 0x50:   /* 320x240 */
12177	 case 0x56:
12178	 case 0x53:
12179	    hdclk = 1;
12180	    /* fall through */
12181	 case 0x2e:   /* 640x480 */
12182	 case 0x44:
12183	 case 0x62:
12184	    if(is1080i) {
12185	       srindex = 98;
12186	    } else if(is750p) {
12187	       srindex = 42;
12188	    } else {
12189	       srindex  = usentsc ? 0 : 21;
12190	    }
12191	    break;
12192	 case 0x31:   /* 720x480 */
12193	 case 0x33:
12194	 case 0x35:
12195	    if(is1080i) {
12196	       /* n/a */
12197	    } else if(is750p) {
12198	       srindex = 49;
12199	    } else {
12200	       srindex = usentsc ? 7 : 21;
12201	    }
12202	    break;
12203	 case 0x32:   /* 720x576 */
12204	 case 0x34:
12205	 case 0x36:
12206	 case 0x5f:   /* 768x576 */
12207	 case 0x60:
12208	 case 0x61:
12209	    if(is1080i) {
12210	       /* n/a */
12211	    } else if(is750p) {
12212	       srindex = 56;
12213	    } else {
12214	       srindex  = usentsc ? 147 : 28;
12215	    }
12216	    break;
12217	 case 0x70:   /* 800x480 */
12218	 case 0x7a:
12219	 case 0x76:
12220	    if(is1080i) {
12221	       srindex = 105;
12222	    } else if(is750p) {
12223	       srindex = 63;
12224	    } else {
12225	       srindex = usentsc ? 175 : 21;
12226	    }
12227	    break;
12228	 case 0x51:   /* 400x300 - hdclk mode */
12229	 case 0x57:
12230	 case 0x54:
12231	    hdclk = 1;
12232	    /* fall through */
12233	 case 0x30:   /* 800x600 */
12234	 case 0x47:
12235	 case 0x63:
12236	    if(is1080i) {
12237	       srindex = 112;
12238	    } else if(is750p) {
12239	       srindex = 70;
12240	    } else {
12241	       srindex = usentsc ? 14 : 35;
12242	    }
12243	    break;
12244	 case 0x1d:	/* 960x540 */
12245	 case 0x1e:
12246	 case 0x1f:
12247	    if(is1080i) {
12248	       srindex = 196;
12249	       skipmoveup = TRUE;
12250	    }
12251	    break;
12252	 case 0x20:	/* 960x600 */
12253	 case 0x21:
12254	 case 0x22:
12255	    if(pSiS->VGAEngine == SIS_315_VGA && is1080i) {
12256	       srindex = 203;
12257	    }
12258	    break;
12259	 case 0x71:	/* 1024x576 */
12260	 case 0x74:
12261	 case 0x77:
12262	    if(is1080i) {
12263	       srindex = 119;
12264	    } else if(is750p) {
12265	       srindex = 77;
12266	    } else {
12267	       srindex  = usentsc ? 182 : 189;
12268	    }
12269	    break;
12270	 case 0x52:	/* 512x384 */
12271	 case 0x58:
12272	 case 0x5c:
12273	    hdclk = 1;
12274	    /* fall through */
12275	 case 0x38:	/* 1024x768 */
12276	 case 0x4a:
12277	 case 0x64:
12278	    if(is1080i) {
12279	       srindex = 126;
12280	    } else if(is750p) {
12281	       srindex = 84;
12282	    } else if(!usentsc) {
12283	       srindex = 154;
12284	    } else if(vdediv == 1) {
12285	       if(!hdclk) srindex = 168;
12286	    } else {
12287	       if(!hdclk) srindex = 161;
12288	    }
12289	    break;
12290	 case 0x79:	/* 1280x720 */
12291	 case 0x75:
12292	 case 0x78:
12293	    if(is1080i) {
12294	       srindex = 133;
12295	    } else if(is750p) {
12296	       srindex = 91;
12297	    }
12298	    break;
12299	 case 0x3a:	/* 1280x1024 */
12300	 case 0x4d:
12301	 case 0x65:
12302	    if(is1080i) {
12303	       srindex = 140;
12304	    }
12305	    break;
12306	 }
12307
12308	 if(srindex < 0) return;
12309
12310	 if(pSiS->tvyscale != 0) {
12311	    for(j = 0; j <= 1; j++) {
12312	       for(i = 0; i <= 6; i++) {
12313		  if(SiSTVVScale[srindex+i].sindex == pSiS->tvyscale) {
12314		     found = TRUE;
12315		     break;
12316		  }
12317	       }
12318	       if(found) break;
12319	       if(pSiS->tvyscale > 0) pSiS->tvyscale--;
12320	       else pSiS->tvyscale++;
12321	    }
12322	 }
12323
12324#ifdef SISDUALHEAD
12325	 if(pSiSEnt) pSiSEnt->tvyscale = pSiS->tvyscale;
12326#endif
12327
12328	 if(pSiS->tvyscale == 0) {
12329	    UChar p2_0a = pSiS->p2_0a;
12330	    UChar p2_2f = pSiS->p2_2f;
12331	    UChar p2_30 = pSiS->p2_30;
12332	    UChar p2_46 = pSiS->p2_46;
12333	    UChar p2_47 = pSiS->p2_47;
12334	    UChar p1scaling[9], p4scaling[9];
12335	    UChar *p2scaling;
12336
12337	    for(i = 0; i < 9; i++) {
12338	        p1scaling[i] = pSiS->scalingp1[i];
12339		p4scaling[i] = pSiS->scalingp4[i];
12340	    }
12341	    p2scaling = &pSiS->scalingp2[0];
12342
12343#ifdef SISDUALHEAD
12344	    if(pSiSEnt && pSiS->DualHeadMode) {
12345	       p2_0a = pSiSEnt->p2_0a;
12346	       p2_2f = pSiSEnt->p2_2f;
12347	       p2_30 = pSiSEnt->p2_30;
12348	       p2_46 = pSiSEnt->p2_46;
12349	       p2_47 = pSiSEnt->p2_47;
12350	       for(i = 0; i < 9; i++) {
12351		  p1scaling[i] = pSiSEnt->scalingp1[i];
12352		  p4scaling[i] = pSiSEnt->scalingp4[i];
12353	       }
12354	       p2scaling = &pSiSEnt->scalingp2[0];
12355	    }
12356#endif
12357            SISWaitRetraceCRT2(pScrn);
12358	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12359	       for(i = 0; i < 64; i++) {
12360	          outSISIDXREG(SISPART2,(0xc0 + i),p2scaling[i]);
12361	       }
12362	    }
12363	    for(i = 0; i < 9; i++) {
12364	       outSISIDXREG(SISPART1,SiSScalingP1Regs[i],p1scaling[i]);
12365	    }
12366	    for(i = 0; i < 9; i++) {
12367	       outSISIDXREG(SISPART4,SiSScalingP4Regs[i],p4scaling[i]);
12368	    }
12369
12370	    setSISIDXREG(SISPART2,0x0a,0x7f,(p2_0a & 0x80));
12371	    outSISIDXREG(SISPART2,0x2f,p2_2f);
12372	    setSISIDXREG(SISPART2,0x30,0x3f,(p2_30 & 0xc0));
12373	    if(!(pSiS->VBFlags2 & VB2_301)) {
12374	       setSISIDXREG(SISPART2,0x46,0x9f,(p2_46 & 0x60));
12375	       outSISIDXREG(SISPART2,0x47,p2_47);
12376	    }
12377
12378	 } else {
12379
12380	    int realvde, myypos, watchdog = 32;
12381	    unsigned short temp1, temp2, vgahde, vgaht, vgavt;
12382	    int p1div = 1;
12383	    ULong calctemp;
12384
12385	    srindex += i;
12386	    newvde = SiSTVVScale[srindex].ScaleVDE;
12387	    realvde = SiSTVVScale[srindex].RealVDE;
12388
12389	    if(vdediv == 1) p1div = 2;
12390
12391	    if(!skipmoveup) {
12392	       do {
12393	          inSISIDXREG(SISPART2,0x01,temp);
12394	          temp = vlimit - ((temp & 0x7f) / p1div);
12395	          if((temp - (((newvde / vdediv) - 2) + 9)) > 0) break;
12396	          myypos = pSiS->tvypos - 1;
12397#ifdef SISDUALHEAD
12398	          if(pSiSEnt && pSiS->DualHeadMode) myypos = pSiSEnt->tvypos - 1;
12399#endif
12400	          SiS_SetTVyposoffset(pScrn, myypos);
12401	       } while(watchdog--);
12402	    }
12403
12404	    SISWaitRetraceCRT2(pScrn);
12405
12406	    if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
12407	       SiS_CalcXTapScaler(pSiS->SiS_Pr, realvde, newvde, 4, FALSE);
12408	    }
12409
12410	    if(!(pSiS->VBFlags2 & VB2_301)) {
12411	       temp = (newvde / vdediv) - 3;
12412	       setSISIDXREG(SISPART2,0x46,0x9f,((temp & 0x0300) >> 3));
12413	       outSISIDXREG(SISPART2,0x47,(temp & 0xff));
12414	    }
12415
12416	    inSISIDXREG(SISPART1,0x0a,temp1);
12417	    inSISIDXREG(SISPART1,0x0c,temp2);
12418	    vgahde = ((temp2 & 0xf0) << 4) | temp1;
12419	    if(pSiS->VGAEngine == SIS_300_VGA) {
12420	       vgahde -= 12;
12421	    } else {
12422	       vgahde -= 16;
12423	       if(hdclk) vgahde <<= 1;
12424	    }
12425
12426	    vgaht = SiSTVVScale[srindex].reg[0];
12427	    temp1 = vgaht;
12428	    if((pSiS->VGAEngine == SIS_315_VGA) && hdclk) temp1 >>= 1;
12429	    temp1--;
12430	    outSISIDXREG(SISPART1,0x08,(temp1 & 0xff));
12431	    setSISIDXREG(SISPART1,0x09,0x0f,((temp1 >> 4) & 0xf0));
12432
12433	    temp2 = (vgaht - vgahde) >> 2;
12434	    if(pSiS->VGAEngine == SIS_300_VGA) {
12435	       temp1 = vgahde + 12 + temp2;
12436	       temp2 = temp1 + (temp2 << 1);
12437	    } else {
12438	       temp1 = vgahde;
12439	       if(hdclk) {
12440		  temp1 >>= 1;
12441		  temp2 >>= 1;
12442	       }
12443	       temp2 >>= 1;
12444	       temp1 = temp1 + 16 + temp2;
12445	       temp2 = temp1 + temp2;
12446	    }
12447	    outSISIDXREG(SISPART1,0x0b,(temp1 & 0xff));
12448	    setSISIDXREG(SISPART1,0x0c,0xf0,((temp1 >> 8) & 0x0f));
12449	    outSISIDXREG(SISPART1,0x0d,(temp2 & 0xff));
12450
12451	    vgavt = SiSTVVScale[srindex].reg[1];
12452	    temp1 = vgavt - 1;
12453	    if(pSiS->VGAEngine == SIS_315_VGA) temp1--;
12454	    outSISIDXREG(SISPART1,0x0e,(temp1 & 0xff));
12455	    setSISIDXREG(SISPART1,0x12,0xf8,((temp1 >> 8 ) & 0x07));
12456	    if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->ChipType >= SIS_661)) {
12457	       temp1 = (vgavt + SiSTVVScale[srindex].RealVDE) >> 1;
12458	       temp2 = ((vgavt - SiSTVVScale[srindex].RealVDE) >> 4) + temp1 + 1;
12459	    } else {
12460	       temp1 = (vgavt - SiSTVVScale[srindex].RealVDE) >> 2;
12461	       temp2 = (temp1 < 4) ? 4 : temp1;
12462	       temp1 += SiSTVVScale[srindex].RealVDE;
12463	       temp2 = (temp2 >> 2) + temp1 + 1;
12464	    }
12465	    outSISIDXREG(SISPART1,0x10,(temp1 & 0xff));
12466	    setSISIDXREG(SISPART1,0x11,0x8f,((temp1 >> 4) & 0x70));
12467	    setSISIDXREG(SISPART1,0x11,0xf0,(temp2 & 0x0f));
12468
12469	    setSISIDXREG(SISPART2,0x0a,0x7f,((SiSTVVScale[srindex].reg[2] >> 8) & 0x80));
12470	    outSISIDXREG(SISPART2,0x2f,((newvde / vdediv) - 2));
12471	    setSISIDXREG(SISPART2,0x30,0x3f,((((newvde / vdediv) - 2) >> 2) & 0xc0));
12472
12473	    outSISIDXREG(SISPART4,0x13,(SiSTVVScale[srindex].reg[2] & 0xff));
12474	    outSISIDXREG(SISPART4,0x14,(SiSTVVScale[srindex].reg[3] & 0xff));
12475	    setSISIDXREG(SISPART4,0x15,0x7f,((SiSTVVScale[srindex].reg[3] >> 1) & 0x80));
12476
12477	    temp1 = vgaht - 1;
12478	    outSISIDXREG(SISPART4,0x16,(temp1 & 0xff));
12479	    setSISIDXREG(SISPART4,0x15,0x87,((temp1 >> 5) & 0x78));
12480
12481	    temp1 = vgavt - 1;
12482	    outSISIDXREG(SISPART4,0x17,(temp1 & 0xff));
12483	    setSISIDXREG(SISPART4,0x15,0xf8,((temp1 >> 8) & 0x07));
12484
12485	    outSISIDXREG(SISPART4,0x18,0x00);
12486	    setSISIDXREG(SISPART4,0x19,0xf0,0x00);
12487
12488	    inSISIDXREG(SISPART4,0x0e,temp1);
12489	    if(is1080i) {
12490	       if(!(temp1 & 0xe0)) newvde >>= 1;
12491	    }
12492
12493	    temp = 0x40;
12494	    if(realvde <= newvde) temp = 0;
12495	    else realvde -= newvde;
12496
12497	    calctemp = (realvde * 256 * 1024) / newvde;
12498	    if((realvde * 256 * 1024) % newvde) calctemp++;
12499	    outSISIDXREG(SISPART4,0x1b,(calctemp & 0xff));
12500	    outSISIDXREG(SISPART4,0x1a,((calctemp >> 8) & 0xff));
12501	    setSISIDXREG(SISPART4,0x19,0x8f,(((calctemp >> 12) & 0x70) | temp));
12502	 }
12503
12504      }
12505
12506   }
12507}
12508
12509int SiS_GetTVyscale(ScrnInfoPtr pScrn)
12510{
12511   SISPtr pSiS = SISPTR(pScrn);
12512#ifdef SISDUALHEAD
12513   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12514
12515   if(pSiSEnt && pSiS->DualHeadMode)
12516        return (int)pSiSEnt->tvyscale;
12517   else
12518#endif
12519        return (int)pSiS->tvyscale;
12520}
12521
12522void SiS_SetSISCRT1SaturationGain(ScrnInfoPtr pScrn, int val)
12523{
12524   SISPtr pSiS = SISPTR(pScrn);
12525#ifdef SISDUALHEAD
12526   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12527#endif
12528
12529   pSiS->siscrt1satgain = val;
12530#ifdef SISDUALHEAD
12531   if(pSiSEnt) pSiSEnt->siscrt1satgain = val;
12532#endif
12533
12534   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return;
12535
12536#ifdef UNLOCK_ALWAYS
12537   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12538#endif
12539
12540   if((val >= 0) && (val <= 7)) {
12541      setSISIDXREG(SISCR,0x53,0xE3, (val << 2));
12542   }
12543}
12544
12545int SiS_GetSISCRT1SaturationGain(ScrnInfoPtr pScrn)
12546{
12547   SISPtr pSiS = SISPTR(pScrn);
12548   int result = pSiS->siscrt1satgain;
12549   UChar temp;
12550#ifdef SISDUALHEAD
12551   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12552
12553   if(pSiSEnt && pSiS->DualHeadMode)  result = pSiSEnt->siscrt1satgain;
12554#endif
12555
12556   if(!(pSiS->SiS_SD3_Flags & SiS_SD3_CRT1SATGAIN)) return result;
12557
12558#ifdef UNLOCK_ALWAYS
12559   sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12560#endif
12561   inSISIDXREG(SISCR, 0x53, temp);
12562   return (int)((temp >> 2) & 0x07);
12563}
12564
12565/* Calc dotclock from registers */
12566static int
12567SiSGetClockFromRegs(UChar sr2b, UChar sr2c)
12568{
12569   float num, denum, postscalar, divider;
12570   int   myclock;
12571
12572   divider = (sr2b & 0x80) ? 2.0 : 1.0;
12573   postscalar = (sr2c & 0x80) ?
12574              ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0 ) :
12575	      ( ((sr2c >> 5) & 0x03) + 1.0 );
12576   num = (sr2b & 0x7f) + 1.0;
12577   denum = (sr2c & 0x1f) + 1.0;
12578   myclock = (int)((14318 * (divider / postscalar) * (num / denum)) / 1000);
12579   return myclock;
12580}
12581
12582#ifdef SISDUALHEAD
12583static void
12584SiS_SetDHFlags(SISPtr pSiS, unsigned int misc, unsigned int sd2)
12585{
12586   SISEntPtr pSiSEnt = pSiS->entityPrivate;
12587
12588   if(pSiS->DualHeadMode) {
12589      if(pSiSEnt->pScrn_1) {
12590	 SISPTR(pSiSEnt->pScrn_1)->MiscFlags |= misc;
12591	 SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags |= sd2;
12592      }
12593      if(pSiSEnt->pScrn_2) {
12594	 SISPTR(pSiSEnt->pScrn_2)->MiscFlags |= misc;
12595	 SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags |= sd2;
12596      }
12597   }
12598}
12599#endif
12600
12601/* PostSetMode:
12602 * -) Disable CRT1 for saving bandwidth. This doesn't work with VESA;
12603 *    VESA uses the bridge in SlaveMode and switching CRT1 off while
12604 *    the bridge is in SlaveMode not that clever...
12605 * -) Check if overlay can be used (depending on dotclock)
12606 * -) Check if Panel Scaler is active on LVDS for overlay re-scaling
12607 * -) Save TV registers for further processing
12608 * -) Apply TV settings
12609 */
12610static void
12611SiSPostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
12612{
12613    SISPtr pSiS = SISPTR(pScrn);
12614#ifdef SISDUALHEAD
12615    SISEntPtr pSiSEnt = pSiS->entityPrivate;
12616#endif
12617    UChar usScratchCR17, sr2b, sr2c, tmpreg;
12618    int   myclock1, myclock2, mycoldepth1, mycoldepth2, temp;
12619    Bool  flag = FALSE;
12620    Bool  doit = TRUE;
12621    Bool  IsInSlaveMode;
12622
12623#ifdef TWDEBUG
12624    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12625    	"CRT1off is %d\n", pSiS->CRT1off);
12626#endif
12627    pSiS->CRT1isoff = pSiS->CRT1off;
12628
12629#ifdef UNLOCK_ALWAYS
12630    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
12631#endif
12632
12633    SiSFixupSR11(pScrn);
12634
12635    IsInSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
12636
12637    if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE)) {
12638
12639	if(pSiS->VBFlags != pSiS->VBFlags_backup) {
12640	   pSiS->VBFlags = pSiS->VBFlags_backup;
12641	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12642			"VBFlags restored to %0x\n", pSiS->VBFlags);
12643	}
12644
12645	/* -) We can't switch off CRT1 if bridge is in SlaveMode.
12646	 * -) If we change to a SlaveMode-Mode (like 512x384), we
12647	 *    need to adapt VBFlags for eg. Xv.
12648	 */
12649#ifdef SISDUALHEAD
12650	if(!pSiS->DualHeadMode) {
12651#endif
12652	   if(IsInSlaveMode) {
12653	      doit = FALSE;
12654	      temp = pSiS->VBFlags;
12655	      pSiS->VBFlags &= (~VB_DISPMODE_SINGLE);
12656	      pSiS->VBFlags |= (VB_DISPMODE_MIRROR | DISPTYPE_DISP1);
12657              if(temp != pSiS->VBFlags) {
12658		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
12659		 	"VBFlags changed to 0x%0x\n", pSiS->VBFlags);
12660	      }
12661	   }
12662#ifdef SISDUALHEAD
12663	}
12664#endif
12665
12666	if(pSiS->VGAEngine == SIS_315_VGA) {
12667
12668	   if((pSiS->CRT1off) && (doit)) {
12669	      orSISIDXREG(SISCR,pSiS->myCR63,0x40);
12670	      orSISIDXREG(SISSR,0x1f,0xc0);
12671	      andSISIDXREG(SISSR,0x07,~0x10);
12672	      andSISIDXREG(SISSR,0x06,0xe2);
12673	      andSISIDXREG(SISSR,0x31,0xcf);
12674	      outSISIDXREG(SISSR,0x2b,0x1b);
12675	      outSISIDXREG(SISSR,0x2c,0xe1);
12676	      outSISIDXREG(SISSR,0x2d,0x01);
12677	      outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12678	      usleep(10000);
12679	      outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12680	   } else {
12681	      andSISIDXREG(SISCR,pSiS->myCR63,0xBF);
12682	      andSISIDXREG(SISSR,0x1f,0x3f);
12683	      orSISIDXREG(SISSR,0x07,0x10);
12684	   }
12685
12686	} else {
12687
12688	   if(doit) {
12689	      inSISIDXREG(SISCR, 0x17, usScratchCR17);
12690	      if(pSiS->CRT1off) {
12691		 if(usScratchCR17 & 0x80) {
12692		    flag = TRUE;
12693		    usScratchCR17 &= ~0x80;
12694		 }
12695		 orSISIDXREG(SISSR,0x1f,0xc0);
12696	      } else {
12697		 if(!(usScratchCR17 & 0x80)) {
12698		    flag = TRUE;
12699		    usScratchCR17 |= 0x80;
12700		 }
12701		 andSISIDXREG(SISSR,0x1f,0x3f);
12702	      }
12703	      /* Reset only if status changed */
12704	      if(flag) {
12705		 outSISIDXREG(SISCR, 0x17, usScratchCR17);
12706		 outSISIDXREG(SISSR, 0x00, 0x01);    /* Synchronous Reset */
12707		 usleep(10000);
12708		 outSISIDXREG(SISSR, 0x00, 0x03);    /* End Reset */
12709	      }
12710	   }
12711	}
12712
12713    }
12714
12715    /* Set bridge to "disable CRT2" mode if CRT2 is disabled, LCD-A is enabled */
12716    /* (Not needed for CRT1=VGA since CRT2 will really be disabled then) */
12717#ifdef SISDUALHEAD
12718    if(!pSiS->DualHeadMode) {
12719#endif
12720       if((pSiS->VGAEngine == SIS_315_VGA)  && (pSiS->VBFlags2 & VB2_SISLCDABRIDGE)) {
12721	  if((!pSiS->UseVESA) && (!(pSiS->VBFlags & CRT2_ENABLE)) && (pSiS->VBFlags & CRT1_LCDA)) {
12722	     if(!IsInSlaveMode) {
12723	        andSISIDXREG(SISPART4,0x0d,~0x07);
12724	     }
12725	  }
12726       }
12727#ifdef SISDUALHEAD
12728    }
12729#endif
12730
12731    /* Reset flags */
12732    pSiS->MiscFlags &= ~( MISC_CRT1OVERLAY      |
12733			  MISC_CRT2OVERLAY      |
12734			  MISC_CRT1OVERLAYGAMMA |
12735			  MISC_SIS760ONEOVERLAY |
12736			  MISC_PANELLINKSCALER  |
12737			  MISC_STNMODE		|
12738			  MISC_TVNTSC1024);
12739
12740    pSiS->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12741
12742#ifdef SISDUALHEAD
12743    if(pSiS->DualHeadMode) {
12744       if(pSiSEnt->pScrn_1) {
12745	  SISPTR(pSiSEnt->pScrn_1)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12746						   MISC_CRT1OVERLAY		|
12747						   MISC_CRT2OVERLAY		|
12748						   MISC_CRT1OVERLAYGAMMA	|
12749						   MISC_PANELLINKSCALER		|
12750						   MISC_STNMODE			|
12751						   MISC_TVNTSC1024);
12752	  SISPTR(pSiSEnt->pScrn_1)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12753       }
12754       if(pSiSEnt->pScrn_2) {
12755	  SISPTR(pSiSEnt->pScrn_2)->MiscFlags &= ~(MISC_SIS760ONEOVERLAY	|
12756						   MISC_CRT1OVERLAY		|
12757						   MISC_CRT2OVERLAY		|
12758						   MISC_CRT1OVERLAYGAMMA	|
12759						   MISC_PANELLINKSCALER		|
12760						   MISC_STNMODE			|
12761						   MISC_TVNTSC1024);
12762	  SISPTR(pSiSEnt->pScrn_2)->SiS_SD2_Flags &= ~SiS_SD2_SIS760ONEOVL;
12763       }
12764    }
12765#endif
12766
12767    /* Determine if the video overlay can be used */
12768    if(!pSiS->NoXvideo) {
12769
12770       int clklimit1=0, clklimit2=0, clklimitg=0;
12771       Bool OverlayHandled = FALSE;
12772
12773       inSISIDXREG(SISSR,0x2b,sr2b);
12774       inSISIDXREG(SISSR,0x2c,sr2c);
12775       myclock1 = myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12776       inSISIDXREG(SISSR,0x06,tmpreg);
12777       switch((tmpreg & 0x1c) >> 2) {
12778       case 0:  mycoldepth1 = 1; break;
12779       case 1:
12780       case 2:  mycoldepth1 = 2; break;
12781       default: mycoldepth1 = 4;
12782       }
12783       mycoldepth2 = mycoldepth1;
12784
12785       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) {
12786	  if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
12787	     inSISIDXREG(SISPART4,0x0a,sr2b);
12788	     inSISIDXREG(SISPART4,0x0b,sr2c);
12789	  } else {
12790	     inSISIDXREG(SISSR,0x2e,sr2b);
12791	     inSISIDXREG(SISSR,0x2f,sr2c);
12792	  }
12793	  myclock2 = SiSGetClockFromRegs(sr2b, sr2c);
12794	  inSISIDXREG(SISPART1,0x00,tmpreg);
12795	  tmpreg &= 0x0f;
12796	  switch(tmpreg) {
12797	  case 8:  mycoldepth2 = 1; break;
12798	  case 4:
12799	  case 2:  mycoldepth2 = 2; break;
12800	  default: mycoldepth2 = 4;
12801	  }
12802       }
12803
12804       switch(pSiS->ChipType) {
12805
12806	 case SIS_300:
12807	 case SIS_540:
12808	 case SIS_630:
12809	 case SIS_730:
12810	    clklimit1 = clklimit2 = clklimitg = 150;
12811	    break;
12812
12813	 case SIS_550:
12814	 case SIS_650:
12815	 case SIS_740:
12816	    clklimit1 = clklimit2 = 175;  /* verified for 65x */
12817	    clklimitg = 166;		  /* ? */
12818	    break;
12819
12820	 case SIS_661:
12821	 case SIS_741:
12822	    clklimit1 = clklimit2 = 190;  /* ? */
12823	    clklimitg = 180;		  /* ? */
12824	    break;
12825
12826	 case SIS_760:
12827	 case SIS_761:
12828	    clklimit1 = clklimit2 = 190;    /* ? */
12829	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only or hybrid */
12830	       clklimit1 = clklimit2 = 220; /* ? */
12831	    }
12832	    clklimitg = 200;		    /* ? */
12833
12834	    if(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO) {	/* UMA only */
12835
12836	       Bool OnlyOne = FALSE, NoOverlay = FALSE;
12837	       int dotclocksum = 0;
12838
12839	       if(pSiS->VBFlags & DISPTYPE_CRT1)                     dotclocksum += myclock1;
12840	       if((!IsInSlaveMode) && (pSiS->VBFlags & CRT2_ENABLE)) dotclocksum += myclock2;
12841
12842	       /* TODO: Find out under what circumstances only one
12843		*	overlay is usable in UMA-only mode.
12844		*	This is not entirely accurate; the overlay
12845		*	scaler also requires some time, so even though
12846		*	the dotclocks are below these values, some
12847		*	distortions in the overlay may occure.
12848		*	Solution: Don't use a 760 with shared memory.
12849		*/
12850	       if( (pSiS->VBFlags & DISPTYPE_CRT1) &&
12851		   (pSiS->VBFlags & CRT2_ENABLE) &&
12852		   (mycoldepth1 != mycoldepth2) ) {
12853
12854		  /* 0. If coldepths are different (only possible in dual head mode),
12855		   *    I have no idea to calculate the limits; hence, allow only one
12856		   *    overlay in all cases.
12857		   */
12858		  OnlyOne = TRUE;
12859
12860	       } else if(pSiS->MemClock < 150000) {
12861
12862		  /* 1. MCLK <150: If someone seriously considers using such
12863		   *    slow RAM, so be it. Only one overlay in call cases.
12864		   */
12865		  OnlyOne = TRUE;
12866
12867	       } else if(pSiS->MemClock < 170000) {
12868
12869		  /* 2. MCLK 166 */
12870		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12871		     case 32: if(dotclocksum > 133) OnlyOne = TRUE;		/* One overlay; verified */
12872			      if(dotclocksum > 180) NoOverlay = TRUE;		/* No overlay; verified */
12873			      break;
12874		     case 16: if(dotclocksum > 175) OnlyOne = TRUE;		/* One overlay; verified */
12875			      if(dotclocksum > 260) NoOverlay = TRUE;;		/* No overlay; FIXME */
12876			      break;
12877		  }
12878
12879	       } else if(pSiS->MemClock < 210000) {
12880
12881		  /* 3. MCLK 200 */
12882		  switch(pSiS->CurrentLayout.bitsPerPixel) {
12883		     case 32: if(dotclocksum > 160) OnlyOne = TRUE;		/* One overlay; FIXME */
12884			      if(dotclocksum > 216) NoOverlay = TRUE;;		/* No overlay; FIXME */
12885			      break;
12886		     case 16: if(dotclocksum > 210) OnlyOne = TRUE;		/* One overlay; FIXME */
12887			      if(dotclocksum > 312) NoOverlay = TRUE;;		/* No overlay; FIXME */
12888			      break;
12889		  }
12890
12891	       }
12892
12893	       if(OnlyOne || NoOverlay) {
12894
12895		  ULong tmpflags = 0;
12896
12897		  if(!NoOverlay) {
12898		     if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12899		     if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12900		     if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12901		     pSiS->MiscFlags |= tmpflags;
12902		  }
12903		  pSiS->MiscFlags |= MISC_SIS760ONEOVERLAY;
12904		  pSiS->SiS_SD2_Flags |= SiS_SD2_SIS760ONEOVL;
12905#ifdef SISDUALHEAD
12906		  SiS_SetDHFlags(pSiS, (tmpflags | MISC_SIS760ONEOVERLAY), SiS_SD2_SIS760ONEOVL);
12907#endif
12908		  OverlayHandled = TRUE;
12909	       }
12910
12911	       xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
12912			"SiS76x/UMA: %s video overlay(s) available in current mode\n",
12913			NoOverlay ? "no" : ((pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) ? "one" : "two"));
12914
12915#ifdef TWDEBUG
12916	       xf86DrvMsg(0, 0, "SiS760: Memclock %d, c1 %d/%d c2 %d/%d, sum %d / %x\n",
12917			pSiS->MemClock, myclock1, mycoldepth1,
12918			myclock2, mycoldepth2, dotclocksum, pSiS->SiS_SD2_Flags);
12919#endif
12920	    }
12921	    break;
12922
12923	 case SIS_660:
12924	    clklimit1 = clklimit2 = 200;  /* ? */
12925	    if(pSiS->ChipFlags & SiSCF_760LFB) {		/* LFB only */
12926	       clklimit1 = clklimit2 = 220;
12927	    }
12928	    clklimitg = 200;		  /* ? */
12929	    break;
12930
12931	 case SIS_315H:
12932	 case SIS_315:
12933	 case SIS_315PRO:
12934	 case SIS_330:
12935	    clklimit1 = clklimit2 = 180;  /* ? */
12936	    clklimitg = 166;		  /* ? */
12937	    break;
12938
12939	 case SIS_340: /* ? */
12940	 case XGI_20:
12941	 case XGI_40:
12942	    clklimit1 = clklimit2 = 240;  /* ? */
12943	    clklimitg = 200;		  /* ? */
12944	    break;
12945       }
12946
12947       if(!OverlayHandled) {
12948          ULong tmpflags = 0;
12949          if(myclock1 <= clklimit1) tmpflags |= MISC_CRT1OVERLAY;
12950          if(myclock2 <= clklimit2) tmpflags |= MISC_CRT2OVERLAY;
12951          if(myclock1 <= clklimitg) tmpflags |= MISC_CRT1OVERLAYGAMMA;
12952	  pSiS->MiscFlags |= tmpflags;
12953#ifdef SISDUALHEAD
12954	  SiS_SetDHFlags(pSiS, tmpflags, 0);
12955#endif
12956          if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
12957#ifdef SISDUALHEAD
12958             if((!pSiS->DualHeadMode) || (pSiS->SecondHead))
12959#endif
12960		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
12961		   "Current dotclock (%dMhz) too high for video overlay on CRT1\n",
12962		   myclock1);
12963          }
12964          if((pSiS->VBFlags & CRT2_ENABLE) && (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) {
12965#ifdef SISDUALHEAD
12966	     if((!pSiS->DualHeadMode) || (!pSiS->SecondHead))
12967#endif
12968		xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 3,
12969		   "Current dotclock (%dMhz) too high for video overlay on CRT2\n",
12970		   myclock2);
12971	  }
12972       }
12973
12974    }
12975
12976    /* Determine if the Panel Link scaler is active */
12977
12978    if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
12979       ULong tmpflags = 0;
12980       if(pSiS->VGAEngine == SIS_300_VGA) {
12981	  if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
12982	     inSISIDXREG(SISPART1,0x1e,tmpreg);
12983	     tmpreg &= 0x3f;
12984	     if(tmpreg) tmpflags |= MISC_PANELLINKSCALER;
12985	  }
12986       } else {
12987	  if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
12988	     inSISIDXREG(SISPART1,0x35,tmpreg);
12989	     tmpreg &= 0x04;
12990	     if(!tmpreg)  tmpflags |= MISC_PANELLINKSCALER;
12991	  }
12992       }
12993       pSiS->MiscFlags |= tmpflags;
12994#ifdef SISDUALHEAD
12995       SiS_SetDHFlags(pSiS, tmpflags, 0);
12996#endif
12997    }
12998
12999    /* Determine if STN is active */
13000    if(pSiS->ChipType == SIS_550) {
13001       if((pSiS->VBFlags & CRT2_LCD) && (pSiS->FSTN || pSiS->DSTN)) {
13002	  inSISIDXREG(SISCR,0x34,tmpreg);
13003	  tmpreg &= 0x7f;
13004	  if(tmpreg == 0x5a || tmpreg == 0x5b) {
13005	     pSiS->MiscFlags |= MISC_STNMODE;
13006#ifdef SISDUALHEAD
13007	     SiS_SetDHFlags(pSiS, MISC_STNMODE, 0);
13008#endif
13009	  }
13010       }
13011    }
13012
13013    /* Determine if our very special TV mode is active */
13014    if((pSiS->VBFlags2 & VB2_SISBRIDGE) && (pSiS->VBFlags & CRT2_TV) && (!(pSiS->VBFlags & TV_HIVISION))) {
13015       if( ((pSiS->VBFlags & TV_YPBPR) && (pSiS->VBFlags & TV_YPBPR525I)) ||
13016	   ((!(pSiS->VBFlags & TV_YPBPR)) && (pSiS->VBFlags & (TV_NTSC | TV_PALM))) ) {
13017	  inSISIDXREG(SISCR,0x34,tmpreg);
13018	  tmpreg &= 0x7f;
13019	  if((tmpreg == 0x64) || (tmpreg == 0x4a) || (tmpreg == 0x38)) {
13020	     pSiS->MiscFlags |= MISC_TVNTSC1024;
13021#ifdef SISDUALHEAD
13022	     SiS_SetDHFlags(pSiS, MISC_TVNTSC1024, 0);
13023#endif
13024	  }
13025       }
13026    }
13027
13028    if(pSiS->VGAEngine == SIS_315_VGA) {
13029       int i;
13030#ifdef SISVRAMQ
13031       /* Re-Enable and reset command queue */
13032       SiSEnableTurboQueue(pScrn);
13033#endif
13034       /* Get HWCursor register contents for backup */
13035       for(i = 0; i < 16; i++) {
13036          pSiS->HWCursorBackup[i] = SIS_MMIO_IN32(pSiS->IOBase, 0x8500 + (i << 2));
13037       }
13038       if(pSiS->ChipType >= SIS_330) {
13039          /* Enable HWCursor protection (Y pos as trigger) */
13040          andSISIDXREG(SISCR, 0x5b, ~0x30);
13041       }
13042    }
13043
13044    /* Re-initialize accelerator engine */
13045    /* (We are sync'ed here) */
13046    if(!pSiS->NoAccel) {
13047       if(pSiS->InitAccel) {
13048          (pSiS->InitAccel)(pScrn);
13049       }
13050    }
13051
13052    /* Set display device gamma (for SISCTRL) */
13053    if(pSiS->VBFlags & CRT1_LCDA)
13054       pSiS->CRT1MonGamma = pSiS->CRT2LCDMonitorGamma;
13055    else
13056       pSiS->CRT1MonGamma = pSiS->CRT1VGAMonitorGamma;
13057
13058    if(pSiS->VBFlags & CRT2_LCD)
13059       pSiS->CRT2MonGamma = pSiS->CRT2LCDMonitorGamma;
13060    else if(pSiS->VBFlags & CRT2_TV) {
13061       if(pSiS->VBFlags & TV_YPBPR)
13062          pSiS->CRT2MonGamma = 2200; /* */
13063       else if(pSiS->VBFlags & TV_HIVISION)
13064          pSiS->CRT2MonGamma = 2200; /* ? */
13065       else if(pSiS->VBFlags & TV_NTSC)
13066          pSiS->CRT2MonGamma = 2200; /* NTSC */
13067       else
13068          pSiS->CRT2MonGamma = 2800; /* All PAL modes? */
13069    } else if(pSiS->VBFlags & CRT2_VGA)
13070       pSiS->CRT2MonGamma = pSiS->CRT2VGAMonitorGamma;
13071    else
13072       pSiS->CRT2MonGamma = 0; /* Unknown */
13073
13074    /* Reset XV display properties (such as number of overlays, etc) */
13075    /* (And copy monitor gamma) */
13076#ifdef SISDUALHEAD
13077    if(pSiS->DualHeadMode) {
13078       if(pSiSEnt->pScrn_1) {
13079	  if(SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay) {
13080	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_1);
13081	  }
13082	  SISPTR(pSiSEnt->pScrn_1)->CRT1MonGamma = pSiS->CRT1MonGamma;
13083	  SISPTR(pSiSEnt->pScrn_1)->CRT2MonGamma = pSiS->CRT2MonGamma;
13084       }
13085       if(pSiSEnt->pScrn_2) {
13086	  if(SISPTR(pSiSEnt->pScrn_2)->ResetXvDisplay) {
13087	     (SISPTR(pSiSEnt->pScrn_1)->ResetXvDisplay)(pSiSEnt->pScrn_2);
13088	  }
13089	  SISPTR(pSiSEnt->pScrn_2)->CRT1MonGamma = pSiS->CRT1MonGamma;
13090	  SISPTR(pSiSEnt->pScrn_2)->CRT2MonGamma = pSiS->CRT2MonGamma;
13091       }
13092    } else {
13093#endif
13094       if(pSiS->ResetXvDisplay) {
13095	  (pSiS->ResetXvDisplay)(pScrn);
13096       }
13097#ifdef SISDUALHEAD
13098    }
13099#endif
13100
13101    /* Reset XV gamma correction */
13102    if(pSiS->ResetXvGamma) {
13103       (pSiS->ResetXvGamma)(pScrn);
13104    }
13105
13106    /* Reset various display parameters */
13107    {
13108       int val = pSiS->siscrt1satgain;
13109#ifdef SISDUALHEAD
13110       if(pSiS->DualHeadMode && pSiSEnt) val = pSiSEnt->siscrt1satgain;
13111#endif
13112       SiS_SetSISCRT1SaturationGain(pScrn, val);
13113    }
13114
13115    /*  Apply TV settings given by options
13116           Do this even in DualHeadMode:
13117	   - if this is called by SetModeCRT1, CRT2 mode has been reset by SetModeCRT1
13118	   - if this is called by SetModeCRT2, CRT2 mode has changed (duh!)
13119	   -> Hence, in both cases, the settings must be re-applied.
13120     */
13121
13122    if(pSiS->VBFlags & CRT2_TV) {
13123       int val;
13124       if(pSiS->VBFlags2 & VB2_CHRONTEL) {
13125	  int mychtvlumabandwidthcvbs = pSiS->chtvlumabandwidthcvbs;
13126	  int mychtvlumabandwidthsvideo = pSiS->chtvlumabandwidthsvideo;
13127	  int mychtvlumaflickerfilter = pSiS->chtvlumaflickerfilter;
13128	  int mychtvchromabandwidth = pSiS->chtvchromabandwidth;
13129	  int mychtvchromaflickerfilter = pSiS->chtvchromaflickerfilter;
13130	  int mychtvcvbscolor = pSiS->chtvcvbscolor;
13131	  int mychtvtextenhance = pSiS->chtvtextenhance;
13132	  int mychtvcontrast = pSiS->chtvcontrast;
13133	  int mytvxpos = pSiS->tvxpos;
13134	  int mytvypos = pSiS->tvypos;
13135#ifdef SISDUALHEAD
13136	  if(pSiSEnt && pSiS->DualHeadMode) {
13137	     mychtvlumabandwidthcvbs = pSiSEnt->chtvlumabandwidthcvbs;
13138	     mychtvlumabandwidthsvideo = pSiSEnt->chtvlumabandwidthsvideo;
13139	     mychtvlumaflickerfilter = pSiSEnt->chtvlumaflickerfilter;
13140	     mychtvchromabandwidth = pSiSEnt->chtvchromabandwidth;
13141	     mychtvchromaflickerfilter = pSiSEnt->chtvchromaflickerfilter;
13142	     mychtvcvbscolor = pSiSEnt->chtvcvbscolor;
13143	     mychtvtextenhance = pSiSEnt->chtvtextenhance;
13144	     mychtvcontrast = pSiSEnt->chtvcontrast;
13145	     mytvxpos = pSiSEnt->tvxpos;
13146	     mytvypos = pSiSEnt->tvypos;
13147	  }
13148#endif
13149	  if((val = mychtvlumabandwidthcvbs) != -1) {
13150	     SiS_SetCHTVlumabandwidthcvbs(pScrn, val);
13151	  }
13152	  if((val = mychtvlumabandwidthsvideo) != -1) {
13153	     SiS_SetCHTVlumabandwidthsvideo(pScrn, val);
13154	  }
13155	  if((val = mychtvlumaflickerfilter) != -1) {
13156	     SiS_SetCHTVlumaflickerfilter(pScrn, val);
13157	  }
13158	  if((val = mychtvchromabandwidth) != -1) {
13159	     SiS_SetCHTVchromabandwidth(pScrn, val);
13160	  }
13161	  if((val = mychtvchromaflickerfilter) != -1) {
13162	     SiS_SetCHTVchromaflickerfilter(pScrn, val);
13163	  }
13164	  if((val = mychtvcvbscolor) != -1) {
13165	     SiS_SetCHTVcvbscolor(pScrn, val);
13166	  }
13167	  if((val = mychtvtextenhance) != -1) {
13168	     SiS_SetCHTVtextenhance(pScrn, val);
13169	  }
13170	  if((val = mychtvcontrast) != -1) {
13171	     SiS_SetCHTVcontrast(pScrn, val);
13172	  }
13173	  /* Backup default TV position registers */
13174	  switch(pSiS->ChrontelType) {
13175	  case CHRONTEL_700x:
13176	     pSiS->tvx = SiS_GetCH700x(pSiS->SiS_Pr, 0x0a);
13177	     pSiS->tvx |= (((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
13178	     pSiS->tvy = SiS_GetCH700x(pSiS->SiS_Pr, 0x0b);
13179	     pSiS->tvy |= ((SiS_GetCH700x(pSiS->SiS_Pr, 0x08) & 0x01) << 8);
13180#ifdef SISDUALHEAD
13181	     if(pSiSEnt) {
13182		pSiSEnt->tvx = pSiS->tvx;
13183		pSiSEnt->tvy = pSiS->tvy;
13184	     }
13185#endif
13186	     break;
13187	  case CHRONTEL_701x:
13188	     /* Not supported by hardware */
13189	     break;
13190	  }
13191	  if((val = mytvxpos) != 0) {
13192	     SiS_SetTVxposoffset(pScrn, val);
13193	  }
13194	  if((val = mytvypos) != 0) {
13195	     SiS_SetTVyposoffset(pScrn, val);
13196	  }
13197       }
13198       if(pSiS->VBFlags2 & VB2_301) {
13199          int mysistvedgeenhance = pSiS->sistvedgeenhance;
13200#ifdef SISDUALHEAD
13201          if(pSiSEnt && pSiS->DualHeadMode) {
13202	     mysistvedgeenhance = pSiSEnt->sistvedgeenhance;
13203	  }
13204#endif
13205          if((val = mysistvedgeenhance) != -1) {
13206	     SiS_SetSISTVedgeenhance(pScrn, val);
13207	  }
13208       }
13209       if(pSiS->VBFlags2 & VB2_SISBRIDGE) {
13210          int mysistvantiflicker = pSiS->sistvantiflicker;
13211	  int mysistvsaturation = pSiS->sistvsaturation;
13212	  int mysistvcolcalibf = pSiS->sistvcolcalibf;
13213	  int mysistvcolcalibc = pSiS->sistvcolcalibc;
13214	  int mysistvcfilter = pSiS->sistvcfilter;
13215	  int mysistvyfilter = pSiS->sistvyfilter;
13216	  int mytvxpos = pSiS->tvxpos;
13217	  int mytvypos = pSiS->tvypos;
13218	  int mytvxscale = pSiS->tvxscale;
13219	  int mytvyscale = pSiS->tvyscale;
13220	  int i;
13221	  ULong cbase;
13222	  UChar ctemp;
13223#ifdef SISDUALHEAD
13224          if(pSiSEnt && pSiS->DualHeadMode) {
13225	     mysistvantiflicker = pSiSEnt->sistvantiflicker;
13226	     mysistvsaturation = pSiSEnt->sistvsaturation;
13227	     mysistvcolcalibf = pSiSEnt->sistvcolcalibf;
13228	     mysistvcolcalibc = pSiSEnt->sistvcolcalibc;
13229	     mysistvcfilter = pSiSEnt->sistvcfilter;
13230	     mysistvyfilter = pSiSEnt->sistvyfilter;
13231	     mytvxpos = pSiSEnt->tvxpos;
13232	     mytvypos = pSiSEnt->tvypos;
13233	     mytvxscale = pSiSEnt->tvxscale;
13234	     mytvyscale = pSiSEnt->tvyscale;
13235	  }
13236#endif
13237          /* Backup default TV position, scale and colcalib registers */
13238	  inSISIDXREG(SISPART2,0x1f,pSiS->p2_1f);
13239	  inSISIDXREG(SISPART2,0x20,pSiS->p2_20);
13240	  inSISIDXREG(SISPART2,0x2b,pSiS->p2_2b);
13241	  inSISIDXREG(SISPART2,0x42,pSiS->p2_42);
13242	  inSISIDXREG(SISPART2,0x43,pSiS->p2_43);
13243	  inSISIDXREG(SISPART2,0x01,pSiS->p2_01);
13244	  inSISIDXREG(SISPART2,0x02,pSiS->p2_02);
13245	  inSISIDXREG(SISPART2,0x44,pSiS->p2_44);
13246	  inSISIDXREG(SISPART2,0x45,pSiS->p2_45);
13247	  if(!(pSiS->VBFlags2 & VB2_301)) {
13248	     inSISIDXREG(SISPART2,0x46,pSiS->p2_46);
13249	  } else {
13250	     pSiS->p2_46 = 0;
13251	  }
13252	  inSISIDXREG(SISPART2,0x0a,pSiS->p2_0a);
13253	  inSISIDXREG(SISPART2,0x31,cbase);
13254	  cbase = (cbase & 0x7f) << 8;
13255	  inSISIDXREG(SISPART2,0x32,ctemp);
13256	  cbase = (cbase | ctemp) << 8;
13257	  inSISIDXREG(SISPART2,0x33,ctemp);
13258	  cbase = (cbase | ctemp) << 8;
13259	  inSISIDXREG(SISPART2,0x34,ctemp);
13260	  pSiS->sistvccbase = (cbase | ctemp);
13261	  inSISIDXREG(SISPART2,0x35,pSiS->p2_35);
13262	  inSISIDXREG(SISPART2,0x36,pSiS->p2_36);
13263	  inSISIDXREG(SISPART2,0x37,pSiS->p2_37);
13264	  inSISIDXREG(SISPART2,0x38,pSiS->p2_38);
13265	  if(!(pSiS->VBFlags2 & VB2_301)) {
13266	     inSISIDXREG(SISPART2,0x47,pSiS->p2_47);
13267	     inSISIDXREG(SISPART2,0x48,pSiS->p2_48);
13268	     inSISIDXREG(SISPART2,0x49,pSiS->p2_49);
13269	     inSISIDXREG(SISPART2,0x4a,pSiS->p2_4a);
13270	  }
13271	  inSISIDXREG(SISPART2,0x2f,pSiS->p2_2f);
13272	  inSISIDXREG(SISPART2,0x30,pSiS->p2_30);
13273	  for(i=0; i<9; i++) {
13274	     inSISIDXREG(SISPART1,SiSScalingP1Regs[i],pSiS->scalingp1[i]);
13275	  }
13276	  for(i=0; i<9; i++) {
13277	     inSISIDXREG(SISPART4,SiSScalingP4Regs[i],pSiS->scalingp4[i]);
13278	  }
13279	  if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13280	     for(i=0; i<64; i++) {
13281	        inSISIDXREG(SISPART2,(0xc0 + i),pSiS->scalingp2[i]);
13282  	     }
13283	  }
13284#ifdef SISDUALHEAD
13285	  if(pSiSEnt) {
13286	     pSiSEnt->p2_1f = pSiS->p2_1f; pSiSEnt->p2_20 = pSiS->p2_20;
13287	     pSiSEnt->p2_42 = pSiS->p2_42; pSiSEnt->p2_43 = pSiS->p2_43;
13288	     pSiSEnt->p2_2b = pSiS->p2_2b;
13289	     pSiSEnt->p2_01 = pSiS->p2_01; pSiSEnt->p2_02 = pSiS->p2_02;
13290	     pSiSEnt->p2_44 = pSiS->p2_44; pSiSEnt->p2_45 = pSiS->p2_45;
13291	     pSiSEnt->p2_46 = pSiS->p2_46; pSiSEnt->p2_0a = pSiS->p2_0a;
13292	     pSiSEnt->sistvccbase = pSiS->sistvccbase;
13293	     pSiSEnt->p2_35 = pSiS->p2_35; pSiSEnt->p2_36 = pSiS->p2_36;
13294	     pSiSEnt->p2_37 = pSiS->p2_37; pSiSEnt->p2_38 = pSiS->p2_38;
13295	     pSiSEnt->p2_48 = pSiS->p2_48; pSiSEnt->p2_49 = pSiS->p2_49;
13296	     pSiSEnt->p2_4a = pSiS->p2_4a; pSiSEnt->p2_2f = pSiS->p2_2f;
13297	     pSiSEnt->p2_30 = pSiS->p2_30; pSiSEnt->p2_47 = pSiS->p2_47;
13298	     for(i=0; i<9; i++) {
13299	        pSiSEnt->scalingp1[i] = pSiS->scalingp1[i];
13300	     }
13301	     for(i=0; i<9; i++) {
13302	        pSiSEnt->scalingp4[i] = pSiS->scalingp4[i];
13303	     }
13304	     if(pSiS->VBFlags2 & VB2_SISTAP4SCALER) {
13305	        for(i=0; i<64; i++) {
13306	           pSiSEnt->scalingp2[i] = pSiS->scalingp2[i];
13307  	        }
13308	     }
13309	  }
13310#endif
13311          if((val = mysistvantiflicker) != -1) {
13312	     SiS_SetSISTVantiflicker(pScrn, val);
13313	  }
13314	  if((val = mysistvsaturation) != -1) {
13315	     SiS_SetSISTVsaturation(pScrn, val);
13316	  }
13317	  if((val = mysistvcfilter) != -1) {
13318	     SiS_SetSISTVcfilter(pScrn, val);
13319	  }
13320	  if((val = mysistvyfilter) != 1) {
13321	     SiS_SetSISTVyfilter(pScrn, val);
13322	  }
13323	  if((val = mysistvcolcalibc) != 0) {
13324	     SiS_SetSISTVcolcalib(pScrn, val, TRUE);
13325	  }
13326	  if((val = mysistvcolcalibf) != 0) {
13327	     SiS_SetSISTVcolcalib(pScrn, val, FALSE);
13328	  }
13329	  if((val = mytvxpos) != 0) {
13330	     SiS_SetTVxposoffset(pScrn, val);
13331	  }
13332	  if((val = mytvypos) != 0) {
13333	     SiS_SetTVyposoffset(pScrn, val);
13334	  }
13335	  if((val = mytvxscale) != 0) {
13336	     SiS_SetTVxscale(pScrn, val);
13337	  }
13338	  if((val = mytvyscale) != 0) {
13339	     SiS_SetTVyscale(pScrn, val);
13340	  }
13341       }
13342    }
13343
13344}
13345
13346/* Post-set SiS6326 TV registers */
13347static void
13348SiS6326PostSetMode(ScrnInfoPtr pScrn, SISRegPtr sisReg)
13349{
13350    SISPtr pSiS = SISPTR(pScrn);
13351    UChar tmp;
13352    int val;
13353
13354    if(!(pSiS->SiS6326Flags & SIS6326_TVDETECTED)) return;
13355
13356#ifdef UNLOCK_ALWAYS
13357    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
13358#endif
13359
13360    /* Backup default TV position registers */
13361    pSiS->tvx1 = SiS6326GetTVReg(pScrn,0x3a);
13362    pSiS->tvx1 |= ((SiS6326GetTVReg(pScrn,0x3c) & 0x0f) << 8);
13363    pSiS->tvx2 = SiS6326GetTVReg(pScrn,0x26);
13364    pSiS->tvx2 |= ((SiS6326GetTVReg(pScrn,0x27) & 0xf0) << 4);
13365    pSiS->tvx3 = SiS6326GetTVReg(pScrn,0x12);
13366    pSiS->tvx3 |= ((SiS6326GetTVReg(pScrn,0x13) & 0xC0) << 2);
13367    pSiS->tvy1 = SiS6326GetTVReg(pScrn,0x11);
13368    pSiS->tvy1 |= ((SiS6326GetTVReg(pScrn,0x13) & 0x30) << 4);
13369
13370    /* Handle TVPosOffset options (BEFORE switching on TV) */
13371    if((val = pSiS->tvxpos) != 0) {
13372       SiS_SetTVxposoffset(pScrn, val);
13373    }
13374    if((val = pSiS->tvypos) != 0) {
13375       SiS_SetTVyposoffset(pScrn, val);
13376    }
13377
13378    /* Switch on TV output. This is rather complicated, but
13379     * if we don't do it, TV output will flicker terribly.
13380     */
13381    if(pSiS->SiS6326Flags & SIS6326_TVON) {
13382       orSISIDXREG(SISSR, 0x01, 0x20);
13383       tmp = SiS6326GetTVReg(pScrn,0x00);
13384       tmp &= ~0x04;
13385       while(!(inSISREG(SISINPSTAT) & 0x08));    /* Wait while NOT vb */
13386       SiS6326SetTVReg(pScrn,0x00,tmp);
13387       for(val=0; val < 2; val++) {
13388         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13389         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13390       }
13391       SiS6326SetTVReg(pScrn, 0x00, sisReg->sis6326tv[0]);
13392       tmp = inSISREG(SISINPSTAT);
13393       outSISREG(SISAR, 0x20);
13394       tmp = inSISREG(SISINPSTAT);
13395       while(inSISREG(SISINPSTAT) & 0x01);
13396       while(!(inSISREG(SISINPSTAT) & 0x01));
13397       andSISIDXREG(SISSR, 0x01, ~0x20);
13398       for(val=0; val < 10; val++) {
13399         while(!(inSISREG(SISINPSTAT) & 0x08));  /* Wait while NOT vb */
13400         while(inSISREG(SISINPSTAT) & 0x08);     /* wait while vb     */
13401       }
13402       andSISIDXREG(SISSR, 0x01, ~0x20);
13403    }
13404
13405    tmp = SiS6326GetTVReg(pScrn,0x00);
13406    if(!(tmp & 0x04)) return;
13407
13408    /* Apply TV settings given by options */
13409    if((val = pSiS->sistvantiflicker) != -1) {
13410       SiS_SetSIS6326TVantiflicker(pScrn, val);
13411    }
13412    if((val = pSiS->sis6326enableyfilter) != -1) {
13413       SiS_SetSIS6326TVenableyfilter(pScrn, val);
13414    }
13415    if((val = pSiS->sis6326yfilterstrong) != -1) {
13416       SiS_SetSIS6326TVyfilterstrong(pScrn, val);
13417    }
13418
13419}
13420
13421/* Check if video bridge is in slave mode */
13422Bool
13423SiSBridgeIsInSlaveMode(ScrnInfoPtr pScrn)
13424{
13425    SISPtr pSiS = SISPTR(pScrn);
13426    UChar  usScrP1_00;
13427
13428    if(!(pSiS->VBFlags2 & VB2_VIDEOBRIDGE)) return FALSE;
13429
13430    inSISIDXREG(SISPART1,0x00,usScrP1_00);
13431    if( ((pSiS->VGAEngine == SIS_300_VGA) && (usScrP1_00 & 0xa0) == 0x20) ||
13432        ((pSiS->VGAEngine == SIS_315_VGA) && (usScrP1_00 & 0x50) == 0x10) ) {
13433       return TRUE;
13434    }
13435
13436    return FALSE;
13437}
13438
13439/* Build a list of the VESA modes the BIOS reports as valid */
13440static void
13441SiSBuildVesaModeList(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe)
13442{
13443    SISPtr pSiS = SISPTR(pScrn);
13444    int i = 0;
13445
13446    while(vbe->VideoModePtr[i] != 0xffff) {
13447       sisModeInfoPtr m;
13448       VbeModeInfoBlock *mode;
13449       int id = vbe->VideoModePtr[i++];
13450
13451       if((mode = VBEGetModeInfo(pVbe, id)) == NULL) {
13452	  continue;
13453       }
13454
13455       m = xnfcalloc(sizeof(sisModeInfoRec), 1);
13456       if(!m) {
13457	  VBEFreeModeInfo(mode);
13458	  continue;
13459       }
13460       m->width = mode->XResolution;
13461       m->height = mode->YResolution;
13462       m->bpp = mode->BitsPerPixel;
13463       m->n = id;
13464       m->next = pSiS->SISVESAModeList;
13465
13466       pSiS->SISVESAModeList = m;
13467
13468       VBEFreeModeInfo(mode);
13469
13470       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
13471	   "VESA BIOS supports mode number 0x%x: %ix%i (%i bpp)\n",
13472	   m->n, m->width, m->height, m->bpp);
13473    }
13474}
13475
13476/* Get VESA mode number from given resolution/depth */
13477static UShort
13478SiSCalcVESAModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
13479{
13480    SISPtr pSiS = SISPTR(pScrn);
13481    sisModeInfoPtr m = pSiS->SISVESAModeList;
13482    UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
13483    UShort ModeNumber = 0;
13484    int j;
13485
13486    while(m) {
13487       if( (pScrn->bitsPerPixel == m->bpp) &&
13488	   (mode->HDisplay == m->width)    &&
13489	   (mode->VDisplay == m->height) )
13490	  return m->n;
13491       m = m->next;
13492    }
13493
13494    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
13495        "No valid VESA BIOS mode found for %dx%d (%d bpp)\n",
13496        mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13497
13498    if(!pSiS->ROM661New) {  /* VESA numbers changed! */
13499       j = 0;
13500       while(VESAModeIndices[j] != 9999) {
13501          if( (mode->HDisplay == VESAModeIndices[j]) &&
13502	      (mode->VDisplay == VESAModeIndices[j+1]) ) {
13503	     ModeNumber = VESAModeIndices[j + 2 + i];
13504	     break;
13505          }
13506          j += 6;
13507       }
13508
13509       if(!ModeNumber) {
13510	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
13511	      "No valid mode found for %dx%dx%d in built-in table either.\n",
13512	      mode->HDisplay, mode->VDisplay, pScrn->bitsPerPixel);
13513       }
13514    }
13515
13516    return(ModeNumber);
13517}
13518
13519UShort
13520SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags)
13521{
13522   SISPtr pSiS = SISPTR(pScrn);
13523   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13524   BOOLEAN FSTN = pSiS->FSTN ? TRUE : FALSE;
13525
13526#ifdef SISDUALHEAD
13527   if(pSiS->DualHeadMode && pSiS->SecondHead) FSTN = FALSE;
13528#endif
13529
13530   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13531			i, FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13532}
13533
13534static Bool
13535SiSValidLCDUserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode, Bool isforlcda)
13536{
13537   if(mode->Flags & V_INTERLACE) return FALSE;
13538
13539   if(mode->HDisplay > 2048) return FALSE;
13540   if(mode->VDisplay > 1536) return FALSE;
13541
13542   if(pSiS->VBFlags2 & VB2_LCD162MHZBRIDGE) {
13543      if(mode->Clock > 162500) return FALSE;
13544#ifdef VB_FORBID_CRT2LCD_OVER_1600
13545      if(!isforlcda) {
13546         if(mode->HDisplay > 1600) return FALSE;
13547      }
13548#endif
13549   } else { /* 301, 301B, 302B (no LCDA!) */
13550      if(mode->Clock > 130000)  return FALSE;
13551      if(mode->Clock > 111000) {
13552         xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
13553	 	"WARNING: Mode clock beyond video bridge specs (%dMHz). Hardware damage might occure.\n",
13554		mode->Clock / 1000);
13555      }
13556      if(mode->HDisplay > 1600) return FALSE;
13557      if(mode->VDisplay > 1024) return FALSE;
13558   }
13559
13560   return TRUE;
13561}
13562
13563static Bool
13564SiSValidVGA2UserMode(SISPtr pSiS, unsigned int VBFlags, DisplayModePtr mode)
13565{
13566   if(mode->Flags & V_INTERLACE) return FALSE;
13567
13568   if(mode->HDisplay > 2048) return FALSE;
13569   if(mode->VDisplay > 1536) return FALSE;
13570
13571   if(pSiS->VBFlags2 & VB2_RAMDAC202MHZBRIDGE) {
13572      if(mode->Clock > 203000) return FALSE;
13573   } else if(pSiS->VBFlags2 & VB2_30xBLV) {
13574      if(mode->Clock > 162500) return FALSE;
13575   } else {
13576      if(mode->Clock > 135500) return FALSE;
13577   }
13578
13579   return TRUE;
13580}
13581
13582UShort
13583SiS_CheckModeCRT1(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13584{
13585   SISPtr pSiS = SISPTR(pScrn);
13586   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13587   int j;
13588
13589   if(!(VBFlags & CRT1_LCDA)) {
13590
13591      if((havecustommodes) && (!(mode->type & M_T_DEFAULT))) {
13592         return 0xfe;
13593      }
13594
13595   } else if(pSiS->VBFlags2 & VB2_SISTMDSLCDABRIDGE) {
13596
13597      if(pSiS->ChipType < SIS_661) {  /* < 661 only? */
13598         if(!(mode->type & M_T_DEFAULT)) {
13599            if(mode->HTotal > 2055) return 0;
13600	    /* (Default mode will be caught in mode switching code) */
13601	 }
13602      }
13603
13604      if(pSiS->SiS_Pr->CP_HaveCustomData) {
13605         for(j=0; j<7; j++) {
13606            if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13607               (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13608               (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13609               (mode->type & M_T_BUILTIN))
13610               return 0xfe;
13611	 }
13612      }
13613
13614      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13615         return 0xfe;
13616
13617      if((havecustommodes) &&
13618         (pSiS->LCDwidth)  &&	/* = test if LCD present */
13619         (!(mode->type & M_T_DEFAULT)) &&
13620	 (SiSValidLCDUserMode(pSiS, VBFlags, mode, TRUE)))
13621         return 0xfe;
13622
13623      if((mode->HDisplay > pSiS->LCDwidth) ||
13624         (mode->VDisplay > pSiS->LCDheight)) {
13625	 return 0;
13626      }
13627
13628   } else {
13629
13630      if((mode->HDisplay > pSiS->LCDwidth) ||
13631         (mode->VDisplay > pSiS->LCDheight)) {
13632	 return 0;
13633      }
13634
13635   }
13636
13637   return(SiS_GetModeID(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay,
13638   			i, pSiS->FSTN, pSiS->LCDwidth, pSiS->LCDheight));
13639}
13640
13641UShort
13642SiS_CheckModeCRT2(ScrnInfoPtr pScrn, DisplayModePtr mode, unsigned int VBFlags, Bool havecustommodes)
13643{
13644   SISPtr pSiS = SISPTR(pScrn);
13645   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
13646   UShort ModeIndex = 0;
13647   int    j;
13648
13649#ifdef TWDEBUG
13650   xf86DrvMsg(0, X_INFO, "Inside CheckCalcModeIndex (VBFlags %lx, mode %dx%d)\n",
13651	VBFlags,mode->HDisplay, mode->VDisplay);
13652#endif
13653
13654   if(VBFlags & CRT2_LCD) {			/* CRT2 is LCD */
13655
13656      if((pSiS->VBFlags2 & VB2_SISTMDSBRIDGE) && (!(pSiS->VBFlags2 & VB2_30xBDH))) {
13657
13658         if(pSiS->SiS_Pr->CP_HaveCustomData) {
13659            for(j=0; j<7; j++) {
13660               if((pSiS->SiS_Pr->CP_DataValid[j]) &&
13661                  (mode->HDisplay == pSiS->SiS_Pr->CP_HDisplay[j]) &&
13662                  (mode->VDisplay == pSiS->SiS_Pr->CP_VDisplay[j]) &&
13663#ifdef VB_FORBID_CRT2LCD_OVER_1600
13664		  (mode->HDisplay <= 1600) 			   &&
13665#endif
13666                  (mode->type & M_T_BUILTIN))
13667                  return 0xfe;
13668	    }
13669         }
13670
13671	 /* All plasma modes have HDisplay <= 1600 */
13672         if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13673            return 0xfe;
13674
13675         if((havecustommodes) &&
13676            (pSiS->LCDwidth)  &&	/* = test if LCD present */
13677	    (!(mode->type & M_T_DEFAULT)) &&
13678	    (SiSValidLCDUserMode(pSiS, VBFlags, mode, FALSE)))
13679            return 0xfe;
13680
13681      }
13682
13683      if( ((mode->HDisplay <= pSiS->LCDwidth) &&
13684           (mode->VDisplay <= pSiS->LCDheight)) ||
13685	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL848) &&
13686	   (((mode->HDisplay == 1360) && (mode->HDisplay == 768)) ||
13687	    ((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13688	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ||
13689	  ((pSiS->SiS_Pr->SiS_CustomT == CUT_PANEL856) &&
13690	   (((mode->HDisplay == 1024) && (mode->HDisplay == 768)) ||
13691	    ((mode->HDisplay ==  800) && (mode->HDisplay == 600)))) ) {
13692
13693	 ModeIndex = SiS_GetModeID_LCD(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13694				pSiS->FSTN, pSiS->SiS_Pr->SiS_CustomT, pSiS->LCDwidth, pSiS->LCDheight,
13695				pSiS->VBFlags2);
13696
13697      }
13698
13699   } else if(VBFlags & CRT2_TV) {		/* CRT2 is TV */
13700
13701      ModeIndex = SiS_GetModeID_TV(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13702					pSiS->VBFlags2);
13703
13704   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
13705
13706      if((pSiS->AddedPlasmaModes) && (mode->type & M_T_BUILTIN))
13707	 return 0xfe;
13708
13709      if((havecustommodes) &&
13710	 (!(mode->type & M_T_DEFAULT)) &&
13711	 (SiSValidVGA2UserMode(pSiS, VBFlags, mode)))
13712         return 0xfe;
13713
13714      ModeIndex = SiS_GetModeID_VGA2(pSiS->VGAEngine, VBFlags, mode->HDisplay, mode->VDisplay, i,
13715					pSiS->VBFlags2);
13716
13717   } else {					/* no CRT2 */
13718
13719      /* Return a valid mode number */
13720      ModeIndex = 0xfe;
13721
13722   }
13723
13724   return(ModeIndex);
13725}
13726
13727/* Calculate the vertical refresh rate from a mode */
13728float
13729SiSCalcVRate(DisplayModePtr mode)
13730{
13731   float hsync, refresh = 0;
13732
13733   if(mode->HSync > 0.0)
13734       	hsync = mode->HSync;
13735   else if(mode->HTotal > 0)
13736       	hsync = (float)mode->Clock / (float)mode->HTotal;
13737   else
13738       	hsync = 0.0;
13739
13740   if(mode->VTotal > 0)
13741       	refresh = hsync * 1000.0 / mode->VTotal;
13742
13743   if(mode->Flags & V_INTERLACE)
13744       	refresh *= 2.0;
13745
13746   if(mode->Flags & V_DBLSCAN)
13747       	refresh /= 2.0;
13748
13749   if(mode->VScan > 1)
13750        refresh /= mode->VScan;
13751
13752   if(mode->VRefresh > 0.0)
13753	refresh = mode->VRefresh;
13754
13755   if(hsync == 0.0 || refresh == 0.0) return 0.0;
13756
13757   return refresh;
13758}
13759
13760/* Calculate CR33 (rate index) for CRT1.
13761 * Calculation is done using currentmode, therefore it is
13762 * recommended to set VertRefresh and HorizSync to correct
13763 * values in config file.
13764 */
13765UChar
13766SISSearchCRT1Rate(ScrnInfoPtr pScrn, DisplayModePtr mode)
13767{
13768   SISPtr  pSiS = SISPTR(pScrn);
13769   int     i = 0, irefresh;
13770   UShort  xres = mode->HDisplay;
13771   UShort  yres = mode->VDisplay;
13772   UChar   index, defindex;
13773   Bool    checksis730 = FALSE;
13774
13775   defindex = (xres == 800 || xres == 1024 || xres == 1280) ? 0x02 : 0x01;
13776
13777   irefresh = (int)SiSCalcVRate(mode);
13778   if(!irefresh) return defindex;
13779
13780   /* SiS730 has troubles on CRT2 if CRT1 is at 32bpp */
13781   if( (pSiS->ChipType == SIS_730)        &&
13782       (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
13783       (pSiS->CurrentLayout.bitsPerPixel == 32) ) {
13784#ifdef SISDUALHEAD
13785      if(pSiS->DualHeadMode) {
13786         if(pSiS->SecondHead) {
13787	    checksis730 = TRUE;
13788	 }
13789      } else
13790#endif
13791      if((!pSiS->UseVESA) && (pSiS->VBFlags & CRT2_ENABLE) && (!pSiS->CRT1off)) {
13792         checksis730 = TRUE;
13793      }
13794   }
13795
13796#ifdef TWDEBUG
13797   xf86DrvMsg(0, X_INFO, "Debug: CalcVRate returned %d\n", irefresh);
13798#endif
13799
13800   /* We need the REAL refresh rate here */
13801   if(mode->Flags & V_INTERLACE) irefresh /= 2;
13802
13803   /* Do not multiply by 2 when DBLSCAN! */
13804
13805#ifdef TWDEBUG
13806   xf86DrvMsg(0, X_INFO, "Debug: Rate after correction = %d\n", irefresh);
13807#endif
13808
13809   index = 0;
13810   while((sisx_vrate[i].idx != 0) && (sisx_vrate[i].xres <= xres)) {
13811      if((sisx_vrate[i].xres == xres) && (sisx_vrate[i].yres == yres)) {
13812	 if((checksis730 == FALSE) || (sisx_vrate[i].SiS730valid32bpp == TRUE)) {
13813	    if(sisx_vrate[i].refresh == irefresh) {
13814	       index = sisx_vrate[i].idx;
13815	       break;
13816	    } else if(sisx_vrate[i].refresh > irefresh) {
13817	       if((sisx_vrate[i].refresh - irefresh) <= 3) {
13818		  index = sisx_vrate[i].idx;
13819	       } else if( ((checksis730 == FALSE) || (sisx_vrate[i - 1].SiS730valid32bpp == TRUE)) &&
13820		          ((irefresh - sisx_vrate[i - 1].refresh) <=  2) &&
13821			  (sisx_vrate[i].idx != 1) ) {
13822		  index = sisx_vrate[i - 1].idx;
13823	       }
13824	       break;
13825	    } else if((irefresh - sisx_vrate[i].refresh) <= 2) {
13826	       index = sisx_vrate[i].idx;
13827	       break;
13828	    }
13829	 }
13830      }
13831      i++;
13832   }
13833
13834   if(index > 0) return index;
13835   else          return defindex;
13836}
13837
13838void
13839SISWaitRetraceCRT1(ScrnInfoPtr pScrn)
13840{
13841   SISPtr pSiS = SISPTR(pScrn);
13842   int    watchdog;
13843   UChar  temp;
13844
13845   inSISIDXREG(SISCR,0x17,temp);
13846   if(!(temp & 0x80)) return;
13847
13848   inSISIDXREG(SISSR,0x1f,temp);
13849   if(temp & 0xc0) return;
13850
13851   watchdog = 65536;
13852   while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
13853   watchdog = 65536;
13854   while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
13855}
13856
13857void
13858SISWaitRetraceCRT2(ScrnInfoPtr pScrn)
13859{
13860   SISPtr pSiS = SISPTR(pScrn);
13861   int    watchdog;
13862   UChar  temp, reg;
13863
13864   if(SiSBridgeIsInSlaveMode(pScrn)) {
13865      SISWaitRetraceCRT1(pScrn);
13866      return;
13867   }
13868
13869   switch(pSiS->VGAEngine) {
13870   case SIS_300_VGA:
13871   	reg = 0x25;
13872	break;
13873   case SIS_315_VGA:
13874   	reg = 0x30;
13875	break;
13876   default:
13877        return;
13878   }
13879
13880   watchdog = 65536;
13881   do {
13882   	inSISIDXREG(SISPART1, reg, temp);
13883	if(!(temp & 0x02)) break;
13884   } while(--watchdog);
13885   watchdog = 65536;
13886   do {
13887   	inSISIDXREG(SISPART1, reg, temp);
13888	if(temp & 0x02) break;
13889   } while(--watchdog);
13890}
13891
13892static void
13893SISWaitVBRetrace(ScrnInfoPtr pScrn)
13894{
13895   SISPtr  pSiS = SISPTR(pScrn);
13896
13897   if((pSiS->VGAEngine == SIS_300_VGA) || (pSiS->VGAEngine == SIS_315_VGA)) {
13898#ifdef SISDUALHEAD
13899      if(pSiS->DualHeadMode) {
13900   	 if(pSiS->SecondHead)
13901	    SISWaitRetraceCRT1(pScrn);
13902         else
13903	    SISWaitRetraceCRT2(pScrn);
13904      } else {
13905#endif
13906	 if(pSiS->VBFlags & DISPTYPE_DISP1) {
13907	    SISWaitRetraceCRT1(pScrn);
13908	 }
13909	 if(pSiS->VBFlags & DISPTYPE_DISP2) {
13910	    if(!(SiSBridgeIsInSlaveMode(pScrn))) {
13911	       SISWaitRetraceCRT2(pScrn);
13912	    }
13913	 }
13914#ifdef SISDUALHEAD
13915      }
13916#endif
13917   } else {
13918      SISWaitRetraceCRT1(pScrn);
13919   }
13920}
13921
13922#define MODEID_OFF 0x449
13923
13924UChar
13925SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, UShort offset, UChar value)
13926{
13927    UChar ret = 0;
13928#ifdef SIS_USE_BIOS_SCRATCH
13929    UChar *base;
13930#endif
13931
13932    /* For some reasons (like detecting the current display mode),
13933     * we need to read (or write-back) values from the BIOS
13934     * scratch area. This area is only valid for the primary
13935     * graphics card. For the secondary, we just return some
13936     * defaults and ignore requests to write data. As regards
13937     * the display mode: If sisfb is loaded for the secondary
13938     * card, it very probably has set a mode, but in any case
13939     * informed us via its info packet. So this here will not be
13940     * called for mode detection in this case.
13941     */
13942
13943    switch(offset) {
13944    case 0x489:
13945       ret = 0x11;  /* Default VGA Info */
13946       break;
13947    case MODEID_OFF:
13948       ret = 0x03;  /* Default current display mode */
13949       break;
13950    }
13951
13952#ifdef SIS_USE_BIOS_SCRATCH
13953    if(SISPTR(pScrn)->Primary) {
13954       base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
13955       if(!base) {
13956          SISErrorLog(pScrn, "(Could not map BIOS scratch area)\n");
13957          return ret;
13958       }
13959
13960       ret = *(base + offset);
13961
13962       /* value != 0xff means: set register */
13963       if(value != 0xff) {
13964          *(base + offset) = value;
13965       }
13966
13967       xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
13968    }
13969#endif
13970    return ret;
13971}
13972
13973UChar
13974SiS_GetSetModeID(ScrnInfoPtr pScrn, UChar id)
13975{
13976    return(SiS_GetSetBIOSScratch(pScrn, MODEID_OFF, id));
13977}
13978
13979void
13980SiSMemCopyToVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
13981{
13982   if((ULong)to & 15) (*pSiS->SiSFastMemCopy)(to, from, size);
13983   else       	      (*pSiS->SiSFastVidCopy)(to, from, size);
13984}
13985
13986void
13987SiSMemCopyFromVideoRam(SISPtr pSiS, UChar *to, UChar *from, int size)
13988{
13989   if((ULong)to & 15) (*pSiS->SiSFastMemCopyFrom)(to, from, size);
13990   else       	      (*pSiS->SiSFastVidCopyFrom)(to, from, size);
13991}
13992
13993void
13994sisSaveUnlockExtRegisterLock(SISPtr pSiS, UChar *reg1, UChar *reg2)
13995{
13996    register UChar val;
13997    ULong mylockcalls;
13998#ifdef TWDEBUG
13999    UChar val1, val2;
14000    int i;
14001#endif
14002
14003    pSiS->lockcalls++;
14004    mylockcalls = pSiS->lockcalls;
14005
14006    /* check if already unlocked */
14007    inSISIDXREG(SISSR, 0x05, val);
14008
14009    if(val != 0xa1) {
14010
14011       /* save State */
14012       if(reg1) *reg1 = val;
14013
14014       /* unlock */
14015       outSISIDXREG(SISSR, 0x05, 0x86);
14016
14017       /* Now check again */
14018       inSISIDXREG(SISSR, 0x05, val);
14019
14020       if(val != 0xA1) {
14021
14022          xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING,
14023               "Failed to unlock SR registers at relocated i/o ports\n");
14024
14025#ifdef TWDEBUG
14026          for(i = 0; i <= 0x3f; i++) {
14027		inSISIDXREG(SISSR, i, val1);
14028		inSISIDXREG(0x3c4, i, val2);
14029		xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO,
14030			"SR%02d: RelIO=0x%02x 0x3c4=0x%02x (%ld)\n",
14031			i, val1, val2, mylockcalls);
14032	  }
14033#endif
14034
14035	  /* Emergency measure: unlock at 0x3c4, and try to enable relocated IO ports */
14036	  switch(pSiS->VGAEngine) {
14037          case SIS_OLD_VGA:
14038	  case SIS_530_VGA:
14039	     outSISIDXREG(0x3c4, 0x05, 0x86);
14040	     andSISIDXREG(0x3c4, 0x33, ~0x20);
14041	     break;
14042	  case SIS_300_VGA:
14043	  case SIS_315_VGA:
14044	     outSISIDXREG(0x3c4, 0x05, 0x86);
14045	     orSISIDXREG(0x3c4, 0x20, 0x20);
14046	     break;
14047          }
14048	  outSISIDXREG(SISSR, 0x05, 0x86);
14049	  inSISIDXREG(SISSR, 0x05, val);
14050	  if(val != 0xa1) {
14051	     SISErrorLog(pSiS->pScrn,
14052			"Failed to unlock SR registers (%p, %lx, 0x%02x; %ld)\n",
14053			(void *)pSiS, (ULong)pSiS->RelIO, val, mylockcalls);
14054	     /* Now await doom... */
14055	  }
14056       }
14057    }
14058    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14059       inSISIDXREG(SISCR, 0x80, val);
14060       if(val != 0xa1) {
14061          /* save State */
14062          if(reg2) *reg2 = val;
14063          outSISIDXREG(SISCR, 0x80, 0x86);
14064	  inSISIDXREG(SISCR, 0x80, val);
14065	  if(val != 0xA1) {
14066	     SISErrorLog(pSiS->pScrn,
14067	        "Failed to unlock cr registers (%p, %lx, 0x%02x)\n",
14068	       (void *)pSiS, (ULong)pSiS->RelIO, val);
14069	  }
14070       }
14071    }
14072}
14073
14074void
14075sisRestoreExtRegisterLock(SISPtr pSiS, UChar reg1, UChar reg2)
14076{
14077    /* restore lock */
14078#ifndef UNLOCK_ALWAYS
14079    outSISIDXREG(SISSR, 0x05, reg1 == 0xA1 ? 0x86 : 0x00);
14080    if((pSiS->VGAEngine == SIS_OLD_VGA) || (pSiS->VGAEngine == SIS_530_VGA)) {
14081       outSISIDXREG(SISCR, 0x80, reg2 == 0xA1 ? 0x86 : 0x00);
14082    }
14083#endif
14084}
14085
14086