1/*
2 * Xv driver for SiS 300, 315 and 330 series.
3 *
4 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1) Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2) Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3) The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author:    Thomas Winischhofer <thomas@winischhofer.net>
29 *
30 * Formerly based on a mostly non-working code fragment for the 630 by
31 * Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan which is
32 * Copyright (C) 2000 Silicon Integrated Systems Corp, Inc.
33 *
34 * Basic structure based on the mga Xv driver by Mark Vojkovich
35 * and i810 Xv driver by Jonathan Bian <jonathan.bian@intel.com>.
36 *
37 * All comments in this file are by Thomas Winischhofer.
38 *
39 * The overlay adaptor supports the following chipsets:
40 *  SiS300: No registers >0x65, two overlays (one used for CRT1, one for CRT2)
41 *  SiS630/730: No registers >0x6b, two overlays (one used for CRT1, one for CRT2)
42 *  SiS550: Full register range, two overlays (one used for CRT1, one for CRT2)
43 *  SiS315: Full register range, one overlay (used for both CRT1 and CRT2 alt.)
44 *  SiS650/740: Full register range, one overlay (used for both CRT1 and CRT2 alt.)
45 *  SiSM650/651: Full register range, two overlays (one used for CRT1, one for CRT2)
46 *  SiS330: Full register range, one overlay (used for both CRT1 and CRT2 alt.)
47 *  SiS661/741/760: Full register range, two overlays (one used for CRT1, one for CRT2)
48 *  SiS340: - ? overlays. Extended registers for DDA.
49 *  SiS761: - ? overlays. Extended registers for DDA.
50 *  XGI Volari V3XT/V5/V8: 1 Overlay. Extended registers for DDA.
51 *
52 * Help for reading the code:
53 * 315/550/650/740/M650/651/330/661/741/76x/340/XGI = SIS_315_VGA
54 * 300/630/730                                      = SIS_300_VGA
55 * For chipsets with 2 overlays, hasTwoOverlays will be true
56 *
57 * Notes on display modes:
58 *
59 * -) dual head mode:
60 *    DISPMODE is either SINGLE1 or SINGLE2, hence you need to check dualHeadMode flag
61 *    DISPMODE is _never_ MIRROR.
62 *    a) Chipsets with 2 overlays:
63 *       315/330 series: Only half sized overlays available (width 960), 660: 1536
64 *       Overlay 1 is used on CRT1, overlay 2 for CRT2.
65 *    b) Chipsets with 1 overlay:
66 *       Full size overlays available.
67 *       Overlay is used for either CRT1 or CRT2
68 * -) merged fb mode:
69 *    a) Chipsets with 2 overlays:
70 *       315/330 series: Only half sized overlays available (width 960), 660: 1536
71 *       DISPMODE is always MIRROR. Overlay 1 is used for CRT1, overlay 2 for CRT2.
72 *    b) Chipsets with 1 overlay:
73 *       Full size overlays available.
74 *       DISPMODE is either SINGLE1 or SINGLE2. Overlay is used accordingly on either
75 *       CRT1 or CRT2 (automatically, where it is located)
76 * -) mirror mode (without dualhead or mergedfb)
77 *    a) Chipsets with 2 overlays:
78 *       315/330 series: Only half sized overlays available (width 960), 660: 1536
79 *       DISPMODE is MIRROR. Overlay 1 is used for CRT1, overlay 2 for CRT2.
80 *    b) Chipsets with 1 overlay:
81 *       Full size overlays available.
82 *       DISPMODE is either SINGLE1 or SINGLE2. Overlay is used depending on
83 * 	 XvOnCRT2 flag.
84 *
85 * About the video blitter:
86 * The video blitter adaptor supports 16 ports. By default, adaptor 0 will
87 * be the overlay adaptor, adaptor 1 the video blitter. The option XvDefaultAdaptor
88 * allows reversing this.
89 * Since SiS does not provide information on the 3D engine, I could not
90 * implement scaling. Instead, the driver paints a black border around the unscaled
91 * video if the destination area is bigger than the video.
92 *
93 */
94
95#ifdef HAVE_CONFIG_H
96#include "config.h"
97#endif
98
99#include "sis.h"
100#ifdef SIS_USE_XAA
101#include "xf86fbman.h"
102#endif
103#include "regionstr.h"
104
105#include "xf86xv.h"
106#include <X11/extensions/Xv.h>
107#include "dixstruct.h"
108#include "fourcc.h"
109
110#define SIS_NEED_inSISREG
111#define SIS_NEED_outSISREG
112#define SIS_NEED_inSISIDXREG
113#define SIS_NEED_outSISIDXREG
114#define SIS_NEED_setSISIDXREGmask
115#define SIS_NEED_MYMMIO
116#include "sis_regs.h"
117
118#ifdef INCL_YUV_BLIT_ADAPTOR
119#include "sis310_accel.h"
120#endif
121
122#include "sis_video.h"
123
124/*********************************
125 *       Raw register access     *
126 *********************************/
127
128#if 0
129static CARD32 _sisread(SISPtr pSiS, CARD32 reg)
130{
131    return *(pSiS->IOBase + reg);
132}
133
134static void _siswrite(SISPtr pSiS, CARD32 reg, CARD32 data)
135{
136    *(pSiS->IOBase + reg) = data;
137}
138#endif
139
140static CARD8 getsrreg(SISPtr pSiS, CARD8 reg)
141{
142    CARD8 ret;
143    inSISIDXREG(SISSR, reg, ret);
144    return ret;
145}
146
147static CARD8 getvideoreg(SISPtr pSiS, CARD8 reg)
148{
149    CARD8 ret;
150    inSISIDXREG(SISVID, reg, ret);
151    return ret;
152}
153
154static __inline void setvideoreg(SISPtr pSiS, CARD8 reg, CARD8 data)
155{
156    outSISIDXREG(SISVID, reg, data);
157}
158
159static __inline void setvideoregmask(SISPtr pSiS, CARD8 reg, CARD8 data, CARD8 mask)
160{
161    setSISIDXREGmask(SISVID, reg, data, mask);
162}
163
164static void setsrregmask(SISPtr pSiS, CARD8 reg, CARD8 data, CARD8 mask)
165{
166    setSISIDXREGmask(SISSR, reg, data, mask);
167}
168
169/* VBlank */
170static CARD8 vblank_active_CRT1(SISPtr pSiS, SISPortPrivPtr pPriv)
171{
172    return(inSISREG(SISINPSTAT) & 0x08); /* Verified */
173}
174
175static CARD8 vblank_active_CRT2(SISPtr pSiS, SISPortPrivPtr pPriv)
176{
177    CARD8 ret;
178
179    if(pPriv->bridgeIsSlave) return(vblank_active_CRT1(pSiS, pPriv));
180
181    if(pSiS->VGAEngine == SIS_315_VGA) {
182       inSISIDXREG(SISPART1, 0x30, ret);
183    } else {
184       inSISIDXREG(SISPART1, 0x25, ret);
185    }
186    return(ret & 0x02);  /* Verified */
187}
188
189/* Scanline - unused */
190#if 0
191static CARD16 get_scanline_CRT1(SISPtr pSiS)
192{
193    CARD32 line;
194
195    _siswrite(pSiS, REG_PRIM_CRT_COUNTER, 0x00000001);
196    line = _sisread(pSiS, REG_PRIM_CRT_COUNTER);
197
198    return((CARD16)((line >> 16) & 0x07FF));
199}
200#endif
201
202static CARD16 get_scanline_CRT2(SISPtr pSiS, SISPortPrivPtr pPriv)
203{
204    CARD8 reg1, reg2;
205
206    if(pSiS->VGAEngine == SIS_315_VGA) {
207       inSISIDXREG(SISPART1, 0x32, reg1);
208       inSISIDXREG(SISPART1, 0x33, reg2);
209    } else {
210       inSISIDXREG(SISPART1, 0x27, reg1);
211       inSISIDXREG(SISPART1, 0x28, reg2);
212    }
213
214    return((CARD16)(reg1 | ((reg2 & 0x70) << 4)));
215}
216
217/* Helper: Count attributes */
218static int
219SiSCountAttributes(XF86AttributeRec *attrs)
220{
221   int num = 0;
222
223   while(attrs[num].name) num++;
224
225   return num;
226}
227
228/*********************************
229 *          Video gamma          *
230 *********************************/
231
232static void
233SiSComputeXvGamma(SISPtr pSiS)
234{
235    int num = 255, i;
236    double red = 1.0 / (double)((double)pSiS->XvGammaRed / 1000);
237    double green = 1.0 / (double)((double)pSiS->XvGammaGreen / 1000);
238    double blue = 1.0 / (double)((double)pSiS->XvGammaBlue / 1000);
239
240    for(i = 0; i <= num; i++) {
241        pSiS->XvGammaRampRed[i] =
242	    (red == 1.0) ? i : (CARD8)(pow((double)i / (double)num, red) * (double)num + 0.5);
243
244	pSiS->XvGammaRampGreen[i] =
245	    (green == 1.0) ? i : (CARD8)(pow((double)i / (double)num, green) * (double)num + 0.5);
246
247	pSiS->XvGammaRampBlue[i] =
248	    (blue == 1.0) ? i : (CARD8)(pow((double)i / (double)num, blue) * (double)num + 0.5);
249    }
250}
251
252static void
253SiSSetXvGamma(SISPtr pSiS)
254{
255    int i;
256    UChar backup = getsrreg(pSiS, 0x1f);
257    setsrregmask(pSiS, 0x1f, 0x08, 0x18);
258    for(i = 0; i <= 255; i++) {
259       SIS_MMIO_OUT32(pSiS->IOBase, 0x8570,
260			(i << 24)			 |
261			(pSiS->XvGammaRampBlue[i] << 16) |
262			(pSiS->XvGammaRampGreen[i] << 8) |
263			pSiS->XvGammaRampRed[i]);
264    }
265    setsrregmask(pSiS, 0x1f, backup, 0xff);
266}
267
268void
269SiSUpdateXvGamma(SISPtr pSiS, SISPortPrivPtr pPriv)
270{
271    UChar sr7 = getsrreg(pSiS, 0x07);
272
273    if(!pSiS->XvGamma) return;
274    if(!(pSiS->MiscFlags & MISC_CRT1OVERLAYGAMMA)) return;
275
276#ifdef SISDUALHEAD
277    if((pPriv->dualHeadMode) && (!pSiS->SecondHead)) return;
278#endif
279
280    if(!(sr7 & 0x04)) return;
281
282    SiSComputeXvGamma(pSiS);
283    SiSSetXvGamma(pSiS);
284}
285
286static void
287SISResetXvGamma(ScrnInfoPtr pScrn)
288{
289    SISPtr pSiS = SISPTR(pScrn);
290    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
291
292    SiSUpdateXvGamma(pSiS, pPriv);
293}
294
295/*********************************
296 *          InitVideo()          *
297 *********************************/
298
299void
300SISInitVideo(ScreenPtr pScreen)
301{
302    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
303    SISPtr pSiS = SISPTR(pScrn);
304    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
305    XF86VideoAdaptorPtr newAdaptor = NULL, newBlitAdaptor = NULL;
306    int num_adaptors;
307
308    newAdaptor = SISSetupImageVideo(pScreen);
309    if(newAdaptor) {
310       SISInitOffscreenImages(pScreen);
311    }
312
313#ifdef INCL_YUV_BLIT_ADAPTOR
314    if( ( (pSiS->ChipFlags & SiSCF_Is65x) ||
315          (pSiS->ChipType >= SIS_330) ) &&
316        (pScrn->bitsPerPixel != 8) ) {
317       newBlitAdaptor = SISSetupBlitVideo(pScreen);
318    }
319#endif
320
321    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
322
323    if(newAdaptor || newBlitAdaptor) {
324       int size = num_adaptors;
325
326       if(newAdaptor)     size++;
327       if(newBlitAdaptor) size++;
328
329       newAdaptors = malloc(size * sizeof(XF86VideoAdaptorPtr*));
330       if(newAdaptors) {
331          if(num_adaptors) {
332             memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
333	  }
334	  if(pSiS->XvDefAdaptorBlit) {
335	     if(newBlitAdaptor) {
336                newAdaptors[num_adaptors] = newBlitAdaptor;
337                num_adaptors++;
338             }
339	  }
340	  if(newAdaptor) {
341             newAdaptors[num_adaptors] = newAdaptor;
342             num_adaptors++;
343          }
344	  if(!pSiS->XvDefAdaptorBlit) {
345	     if(newBlitAdaptor) {
346                newAdaptors[num_adaptors] = newBlitAdaptor;
347                num_adaptors++;
348             }
349	  }
350	  adaptors = newAdaptors;
351       }
352    }
353
354    if(num_adaptors) {
355       xf86XVScreenInit(pScreen, adaptors, num_adaptors);
356    }
357
358    if(newAdaptors) {
359       free(newAdaptors);
360    }
361}
362
363/*********************************
364 *       SetPortsDefault()       *
365 *********************************/
366
367void
368SISSetPortDefaults(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
369{
370    SISPtr    pSiS = SISPTR(pScrn);
371#ifdef SISDUALHEAD
372    SISEntPtr pSiSEnt = pSiS->entityPrivate;;
373#endif
374
375    pPriv->colorKey    = pSiS->colorKey = 0x000101fe;
376    pPriv->brightness  = pSiS->XvDefBri;
377    pPriv->contrast    = pSiS->XvDefCon;
378    pPriv->hue         = pSiS->XvDefHue;
379    pPriv->saturation  = pSiS->XvDefSat;
380    pPriv->autopaintColorKey = TRUE;
381    pPriv->disablegfx  = pSiS->XvDefDisableGfx;
382    pPriv->disablegfxlr= pSiS->XvDefDisableGfxLR;
383    pSiS->disablecolorkeycurrent = pSiS->XvDisableColorKey;
384    pPriv->usechromakey    = pSiS->XvUseChromaKey;
385    pPriv->insidechromakey = pSiS->XvInsideChromaKey;
386    pPriv->yuvchromakey    = pSiS->XvYUVChromaKey;
387    pPriv->chromamin       = pSiS->XvChromaMin;
388    pPriv->chromamax       = pSiS->XvChromaMax;
389    if(pPriv->dualHeadMode) {
390#ifdef SISDUALHEAD
391       if(!pSiS->SecondHead) {
392          pPriv->tvxpos      = pSiS->tvxpos;
393          pPriv->tvypos      = pSiS->tvypos;
394	  pPriv->updatetvxpos = TRUE;
395          pPriv->updatetvypos = TRUE;
396       }
397#endif
398    } else {
399       pPriv->tvxpos      = pSiS->tvxpos;
400       pPriv->tvypos      = pSiS->tvypos;
401       pPriv->updatetvxpos = TRUE;
402       pPriv->updatetvypos = TRUE;
403    }
404#ifdef SIS_CP
405    SIS_CP_VIDEO_DEF
406#endif
407    if(pPriv->dualHeadMode) {
408#ifdef SISDUALHEAD
409       pPriv->crtnum =
410	  pSiSEnt->curxvcrtnum =
411	     pSiSEnt->XvOnCRT2 ? 1 : 0;
412#endif
413    } else
414       pPriv->crtnum = pSiS->XvOnCRT2 ? 1 : 0;
415
416    pSiS->XvGammaRed = pSiS->XvGammaRedDef;
417    pSiS->XvGammaGreen = pSiS->XvGammaGreenDef;
418    pSiS->XvGammaBlue = pSiS->XvGammaBlueDef;
419    SiSUpdateXvGamma(pSiS, pPriv);
420}
421
422/*********************************
423 *          ResetVideo()         *
424 *********************************/
425
426static void
427SISResetVideo(ScrnInfoPtr pScrn)
428{
429    SISPtr pSiS = SISPTR(pScrn);
430    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
431
432    /* Unlock registers */
433#ifdef UNLOCK_ALWAYS
434    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
435#endif
436    if(getvideoreg (pSiS, Index_VI_Passwd) != 0xa1) {
437       setvideoreg (pSiS, Index_VI_Passwd, 0x86);
438       if(getvideoreg (pSiS, Index_VI_Passwd) != 0xa1)
439	  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
440		 "Xv: Video password could not unlock registers\n");
441    }
442
443    /* Initialize first overlay (CRT1) ------------------------------- */
444
445    /* This bit has obviously a different meaning on 315 series (linebuffer-related) */
446    if(pSiS->VGAEngine == SIS_300_VGA) {
447       /* Write-enable video registers */
448       setvideoregmask(pSiS, Index_VI_Control_Misc2,      0x80, 0x81);
449    } else {
450       /* Select overlay 2, clear all linebuffer related bits */
451       setvideoregmask(pSiS, Index_VI_Control_Misc2,      0x00, 0xb1);
452    }
453
454    /* Disable overlay */
455    setvideoregmask(pSiS, Index_VI_Control_Misc0,         0x00, 0x02);
456
457    /* Disable bob de-interlacer and some strange bit */
458    setvideoregmask(pSiS, Index_VI_Control_Misc1,         0x00, 0x82);
459
460    /* Select RGB chroma key format (300 series only) */
461    if(pSiS->VGAEngine == SIS_300_VGA) {
462       setvideoregmask(pSiS, Index_VI_Control_Misc0,      0x00, 0x40);
463    }
464
465    /* Reset scale control and contrast */
466    /* (Enable DDA (interpolation)) */
467    setvideoregmask(pSiS, Index_VI_Scale_Control,         0x60, 0x60);
468    setvideoregmask(pSiS, Index_VI_Contrast_Enh_Ctrl,     0x04, 0x1F);
469
470    setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Preset_Low,     0x00);
471    setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Preset_Middle,  0x00);
472    setvideoreg(pSiS, Index_VI_UV_Buf_Preset_Low,         0x00);
473    setvideoreg(pSiS, Index_VI_UV_Buf_Preset_Middle,      0x00);
474    setvideoreg(pSiS, Index_VI_Disp_Y_UV_Buf_Preset_High, 0x00);
475    setvideoreg(pSiS, Index_VI_Play_Threshold_Low,        0x00);
476    setvideoreg(pSiS, Index_VI_Play_Threshold_High,       0x00);
477    if(pSiS->Chipset == PCI_CHIP_SIS330) {
478       /* Disable contrast enhancement (?) */
479       setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x00, 0x10);
480    } else if(pPriv->is661741760) {
481       setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x00, 0xE0);
482       if(pPriv->is760) {
483          setvideoregmask(pSiS, Index_VI_V_Buf_Start_Over, 0x3c, 0x3c);
484       } else { /* 661, 741 */
485          setvideoregmask(pSiS, Index_VI_V_Buf_Start_Over, 0x2c, 0x3c);
486       }
487    } else if((pSiS->Chipset == PCI_CHIP_SIS340) ||
488	      (pSiS->Chipset == PCI_CHIP_XGIXG20) ||
489	      (pSiS->Chipset == PCI_CHIP_XGIXG40)) {
490       /* Disable contrast enhancement (?) */
491       setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x00, 0x10);
492       /* Threshold high */
493       setvideoregmask(pSiS, 0xb5, 0x00, 0x01);
494       setvideoregmask(pSiS, 0xb6, 0x00, 0x01);
495       /* Enable horizontal, disable vertical 4-tap DDA scaler */
496       setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x40, 0xc0);
497       set_dda_regs(pSiS, 1.0);
498       /* Enable software-flip */
499       setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x20, 0x20);
500       /* "Disable video processor" */
501       setsrregmask(pSiS, 0x3f, 0x00, 0x02);
502    } else if(pPriv->is761) {
503       /* Disable contrast enhancement (?) */
504       setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x00, 0x10);
505       /* Threshold high */
506       setvideoregmask(pSiS, 0xb5, 0x00, 0x01);
507       setvideoregmask(pSiS, 0xb6, 0x00, 0x01);
508       /* Enable horizontal, disable vertical 4-tap DDA scaler */
509       setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x40, 0xC0);
510       /* ? */
511       setvideoregmask(pSiS, 0xb6, 0x02, 0x02);
512       set_dda_regs(pSiS, 1.0);
513       setvideoregmask(pSiS, Index_VI_V_Buf_Start_Over, 0x00, 0x3c);
514    }
515
516    if((pSiS->ChipFlags & SiSCF_Is65x) || (pPriv->is661741760)) {
517       setvideoregmask(pSiS, Index_VI_Control_Misc2,  0x00, 0x04);
518    }
519
520    /* Reset top window position for scanline check */
521    setvideoreg(pSiS, Index_VI_Win_Ver_Disp_Start_Low, 0x00);
522    setvideoreg(pSiS, Index_VI_Win_Ver_Over, 0x00);
523
524    /* Initialize second overlay (CRT2) - only for 300, 630/730, 550, M650/651, 661/741/660/760 */
525    if(pSiS->hasTwoOverlays) {
526
527	if(pSiS->VGAEngine == SIS_300_VGA) {
528	   /* Write-enable video registers */
529	   setvideoregmask(pSiS, Index_VI_Control_Misc2,      0x81, 0x81);
530	} else {
531	   /* Select overlay 2, clear all linebuffer related bits */
532	   setvideoregmask(pSiS, Index_VI_Control_Misc2,      0x01, 0xb1);
533	}
534
535	/* Disable overlay */
536	setvideoregmask(pSiS, Index_VI_Control_Misc0,         0x00, 0x02);
537
538	/* Disable bob de-interlacer and some strange bit */
539	setvideoregmask(pSiS, Index_VI_Control_Misc1,         0x00, 0x82);
540
541	/* Select RGB chroma key format */
542	if(pSiS->VGAEngine == SIS_300_VGA) {
543	   setvideoregmask(pSiS, Index_VI_Control_Misc0,      0x00, 0x40);
544	}
545
546	/* Reset scale control and contrast */
547	/* (Enable DDA (interpolation)) */
548	setvideoregmask(pSiS, Index_VI_Scale_Control,         0x60, 0x60);
549	setvideoregmask(pSiS, Index_VI_Contrast_Enh_Ctrl,     0x04, 0x1F);
550
551	setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Preset_Low,     0x00);
552	setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Preset_Middle,  0x00);
553	setvideoreg(pSiS, Index_VI_UV_Buf_Preset_Low,         0x00);
554	setvideoreg(pSiS, Index_VI_UV_Buf_Preset_Middle,      0x00);
555	setvideoreg(pSiS, Index_VI_Disp_Y_UV_Buf_Preset_High, 0x00);
556	setvideoreg(pSiS, Index_VI_Play_Threshold_Low,        0x00);
557	setvideoreg(pSiS, Index_VI_Play_Threshold_High,       0x00);
558
559	if(pPriv->is661741760) {
560	   CARD8 temp;
561	   setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x00, 0xE0);
562	   switch(pSiS->ChipType) {
563	   case SIS_661: temp = 0x24; break;
564	   case SIS_741: temp = 0x2c; break;
565	   default: 	 temp = 0x3c;
566	   }
567	   setvideoregmask(pSiS, Index_VI_V_Buf_Start_Over, temp, 0x3c);
568	} else if(pPriv->is761) {
569	   setvideoregmask(pSiS, Index_VI_V_Buf_Start_Over, 0x00, 0x3c);
570	} else if(pSiS->Chipset == PCI_CHIP_SIS340) {  /* 2 overlays? */
571	   setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x00, 0x10);
572	   setvideoregmask(pSiS, 0xb5, 0x00, 0x01);
573	   setvideoregmask(pSiS, 0xb6, 0x00, 0x01);
574	   setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x40, 0xC0);
575	   set_dda_regs(pSiS, 1.0);
576           setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, 0x20, 0x20);
577	}
578
579	setvideoreg(pSiS, Index_VI_Win_Ver_Disp_Start_Low, 0x00);
580	setvideoreg(pSiS, Index_VI_Win_Ver_Over, 0x00);
581
582    }
583
584    /* set default properties for overlay 1 (CRT1) -------------------------- */
585    setvideoregmask(pSiS, Index_VI_Control_Misc2,         0x00, 0x01);
586    setvideoregmask(pSiS, Index_VI_Contrast_Enh_Ctrl,     0x04, 0x07);
587    setvideoreg(pSiS, Index_VI_Brightness,                0x20);
588    if(pSiS->VGAEngine == SIS_315_VGA) {
589       setvideoreg(pSiS, Index_VI_Hue,          	  0x00);
590       setvideoreg(pSiS, Index_VI_Saturation,             0x00);
591    }
592
593    /* set default properties for overlay 2(CRT2)  -------------------------- */
594    if(pSiS->hasTwoOverlays) {
595       setvideoregmask(pSiS, Index_VI_Control_Misc2,      0x01, 0x01);
596       setvideoregmask(pSiS, Index_VI_Contrast_Enh_Ctrl,  0x04, 0x07);
597       setvideoreg(pSiS, Index_VI_Brightness,             0x20);
598       if(pSiS->VGAEngine == SIS_315_VGA) {
599          setvideoreg(pSiS, Index_VI_Hue,                 0x00);
600          setvideoreg(pSiS, Index_VI_Saturation,    	  0x00);
601       }
602    }
603
604    /* Reset Xv gamma correction */
605    if(pSiS->VGAEngine == SIS_315_VGA) {
606       SiSUpdateXvGamma(pSiS, pPriv);
607    }
608
609    pPriv->mustresettap = TRUE;
610#ifdef SISMERGED
611    pPriv->mustresettap2 = TRUE;
612#endif
613}
614
615/*********************************
616 *       Set displaymode         *
617 *********************************/
618
619/* Set display mode (single CRT1/CRT2, mirror).
620 * MIRROR mode is only available on chipsets with two overlays.
621 * On the other chipsets, if only CRT1 or only CRT2 are used,
622 * the correct display CRT is chosen automatically. If both
623 * CRT1 and CRT2 are connected, the user can choose between CRT1 and
624 * CRT2 by using the option XvOnCRT2.
625 */
626
627static void
628set_dispmode(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
629{
630    SISPtr pSiS = SISPTR(pScrn);
631
632    pPriv->dualHeadMode = pPriv->bridgeIsSlave = FALSE;
633
634    if(SiSBridgeIsInSlaveMode(pScrn)) {
635       pPriv->bridgeIsSlave = TRUE;
636    }
637
638    if( (pSiS->VBFlags & VB_DISPMODE_MIRROR) ||
639        ((pPriv->bridgeIsSlave) && (pSiS->VBFlags & DISPTYPE_DISP2)) )  {
640       if(pPriv->hasTwoOverlays)
641	   pPriv->displayMode = DISPMODE_MIRROR;     /* CRT1+CRT2 (2 overlays) */
642       else if(pPriv->crtnum)
643	  pPriv->displayMode = DISPMODE_SINGLE2;    /* CRT2 only */
644       else
645	  pPriv->displayMode = DISPMODE_SINGLE1;    /* CRT1 only */
646    } else {
647#ifdef SISDUALHEAD
648       if(pSiS->DualHeadMode) {
649	  pPriv->dualHeadMode = TRUE;
650	  if(pSiS->SecondHead)
651	     pPriv->displayMode = DISPMODE_SINGLE1; /* CRT1 only */
652	  else
653	     pPriv->displayMode = DISPMODE_SINGLE2; /* CRT2 only */
654       } else
655#endif
656       if(pSiS->VBFlags & DISPTYPE_DISP1) {
657	  pPriv->displayMode = DISPMODE_SINGLE1;    /* CRT1 only */
658       } else {
659	  pPriv->displayMode = DISPMODE_SINGLE2;    /* CRT2 only */
660       }
661    }
662}
663
664static void
665set_disptype_regs(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
666{
667    SISPtr pSiS = SISPTR(pScrn);
668#ifdef SISDUALHEAD
669    SISEntPtr pSiSEnt = pSiS->entityPrivate;
670    int crtnum = 0;
671
672    if(pPriv->dualHeadMode) crtnum = pSiSEnt->curxvcrtnum;
673#endif
674
675    /*
676     *     SR06[7:6]
677     *	      Bit 7: Enable overlay 1 on CRT2
678     *	      Bit 6: Enable overlay 0 on CRT2
679     *     SR32[7:6]
680     *        Bit 7: DCLK/TCLK overlay 1
681     *               0=DCLK (overlay on CRT1)
682     *               1=TCLK (overlay on CRT2)
683     *        Bit 6: DCLK/TCLK overlay 0
684     *               0=DCLK (overlay on CRT1)
685     *               1=TCLK (overlay on CRT2)
686     *
687     * On chipsets with two overlays, we can freely select and also
688     * have a mirror mode. However, we use overlay 0 for CRT1 and
689     * overlay 1 for CRT2.
690     * ATTENTION: CRT2 can only take up to 1 (one) overlay. Setting
691     * SR06/32 to 0xc0 DOES NOT WORK. THAT'S CONFIRMED.
692     * Therefore, we use overlay 0 on CRT2 if in SINGLE2 mode.
693     *
694     * For chipsets with only one overlay, user must choose whether
695     * to display the overlay on CRT1 or CRT2 by setting XvOnCRT2
696     * to TRUE (CRT2) or FALSE (CRT1). The driver does this auto-
697     * matically if only CRT1 or only CRT2 is used.
698     */
699#ifdef UNLOCK_ALWAYS
700    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
701#endif
702
703    switch (pPriv->displayMode)
704    {
705       case DISPMODE_SINGLE1:				/* CRT1-only mode: */
706	  if(pPriv->hasTwoOverlays) {
707	      if(pPriv->dualHeadMode) {
708		 setsrregmask(pSiS, 0x06, 0x00, 0x40);  /* overlay 0 -> CRT1 */
709		 setsrregmask(pSiS, 0x32, 0x00, 0x40);
710	      } else {
711		 setsrregmask(pSiS, 0x06, 0x00, 0xc0);  /* both overlays -> CRT1 */
712		 setsrregmask(pSiS, 0x32, 0x00, 0xc0);
713	      }
714	  } else {
715#ifdef SISDUALHEAD
716	      if((!pPriv->dualHeadMode) || (crtnum == 0)) {
717#endif
718		 setsrregmask(pSiS, 0x06, 0x00, 0xc0);  /* only overlay -> CRT1 */
719		 setsrregmask(pSiS, 0x32, 0x00, 0xc0);
720#ifdef SISDUALHEAD
721	      }
722#endif
723	  }
724	  break;
725
726       case DISPMODE_SINGLE2:			/* CRT2-only mode: */
727	  if(pPriv->hasTwoOverlays) {
728	      if(pPriv->dualHeadMode) {
729		 setsrregmask(pSiS, 0x06, 0x80, 0x80);  /* overlay 1 -> CRT2 */
730		 setsrregmask(pSiS, 0x32, 0x80, 0x80);
731	      } else {
732		 setsrregmask(pSiS, 0x06, 0x40, 0xc0);  /* overlay 0 -> CRT2 */
733		 setsrregmask(pSiS, 0x32, 0xc0, 0xc0);  /* (although both clocks for CRT2!) */
734	      }
735	  } else {
736#ifdef SISDUALHEAD
737	      if((!pPriv->dualHeadMode) || (crtnum == 1)) {
738#endif
739		 if(pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) {
740		    setsrregmask(pSiS, 0x06, 0x40, 0xc0);  /* overlay 0 -> CRT2 */
741		    setsrregmask(pSiS, 0x32, 0xc0, 0xc0);  /* (although both clocks for CRT2!) */
742		 } else {
743		    setsrregmask(pSiS, 0x06, 0x40, 0xc0);  /* only overlay -> CRT2 */
744		    setsrregmask(pSiS, 0x32, 0x40, 0xc0);
745		 }
746#ifdef SISDUALHEAD
747              }
748#endif
749	  }
750	  break;
751
752       case DISPMODE_MIRROR:				/* CRT1+CRT2-mode: (only on chips with 2 overlays) */
753       default:
754	  setsrregmask(pSiS, 0x06, 0x80, 0xc0);         /* overlay 0 -> CRT1, overlay 1 -> CRT2 */
755	  setsrregmask(pSiS, 0x32, 0x80, 0xc0);
756	  break;
757    }
758}
759
760static void
761set_hastwooverlays(SISPtr pSiS, SISPortPrivPtr pPriv)
762{
763    int temp, watchdog;
764
765    if(pSiS->hasTwoOverlays) {
766       if(pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) {
767          if(pPriv->hasTwoOverlays) {
768	     /* Disable overlay 1 on change */
769	     setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x01, 0x01);
770	     setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x01);
771	     temp = getvideoreg(pSiS,Index_VI_Control_Misc0);
772	     if(temp & 0x02) {
773	        watchdog = WATCHDOG_DELAY;
774	        while((!vblank_active_CRT2(pSiS, pPriv)) && --watchdog);
775	        watchdog = WATCHDOG_DELAY;
776	        while(vblank_active_CRT2(pSiS, pPriv) && --watchdog);
777	        setvideoregmask(pSiS, Index_VI_Control_Misc0, 0x00, 0x02);
778	     }
779	  }
780          pPriv->hasTwoOverlays = FALSE;
781       } else {
782          pPriv->hasTwoOverlays = TRUE;
783       }
784    } else {
785       pPriv->hasTwoOverlays = FALSE;
786    }
787}
788
789static void
790set_allowswitchcrt(SISPtr pSiS, SISPortPrivPtr pPriv)
791{
792    if(pPriv->hasTwoOverlays) {
793       pPriv->AllowSwitchCRT = FALSE;
794    } else if((!(pSiS->VBFlags & DISPTYPE_DISP1)) || (!(pSiS->VBFlags & DISPTYPE_DISP2))) {
795       pPriv->AllowSwitchCRT = FALSE;
796       if(!(pSiS->VBFlags & DISPTYPE_DISP1)) pPriv->crtnum = 1;
797       else                                  pPriv->crtnum = 0;
798    } else {
799       pPriv->AllowSwitchCRT = TRUE;
800    }
801}
802
803static void
804set_maxencoding(SISPtr pSiS, SISPortPrivPtr pPriv)
805{
806    int half;
807
808    if(pSiS->VGAEngine == SIS_300_VGA) {
809       DummyEncoding.width = IMAGE_MAX_WIDTH_300;
810       DummyEncoding.height = IMAGE_MAX_HEIGHT_300;
811    } else {
812       DummyEncoding.width = IMAGE_MAX_WIDTH_315;
813       DummyEncoding.height = IMAGE_MAX_HEIGHT_315;
814       half = IMAGE_MAX_WIDTH_315 >> 1;
815       if(pPriv->is661741760) {
816          half = 768 * 2;
817       } else if(pPriv->is340) { /* 2 overlays? */
818          DummyEncoding.width = IMAGE_MAX_WIDTH_340;
819	  half = 1280; /* ? */
820       } else if(pPriv->is761) {
821          DummyEncoding.width = IMAGE_MAX_WIDTH_761;
822          half = 1920; /* ? */
823       }
824       if(pPriv->hasTwoOverlays) {
825#ifdef SISDUALHEAD
826          if(pSiS->DualHeadMode) {
827	     DummyEncoding.width = half;
828          } else
829#endif
830#ifdef SISMERGED
831          if(pSiS->MergedFB) {
832	     DummyEncoding.width = half;
833          } else
834#endif
835          if(pPriv->displayMode == DISPMODE_MIRROR) {
836	     DummyEncoding.width = half;
837          }
838       }
839    }
840}
841
842/*********************************
843 *       ResetXvDisplay()        *
844 *********************************/
845
846static void
847SISResetXvDisplay(ScrnInfoPtr pScrn)
848{
849   SISPtr pSiS = SISPTR(pScrn);
850   SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
851
852   if(!pPriv) return;
853
854   set_hastwooverlays(pSiS, pPriv);
855   set_allowswitchcrt(pSiS, pPriv);
856   set_dispmode(pScrn, pPriv);
857   set_maxencoding(pSiS, pPriv);
858}
859
860/*********************************
861 *       SetupImageVideo()       *
862 *********************************/
863
864static XF86VideoAdaptorPtr
865SISSetupImageVideo(ScreenPtr pScreen)
866{
867    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
868    SISPtr pSiS = SISPTR(pScrn);
869    XF86VideoAdaptorPtr adapt;
870    SISPortPrivPtr pPriv;
871
872#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
873    XAAInfoRecPtr pXAA = pSiS->AccelInfoPtr;
874
875    if(!pXAA || !pXAA->FillSolidRects) {
876       return NULL;
877    }
878#endif
879
880    if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
881                            sizeof(SISPortPrivRec) +
882                            sizeof(DevUnion)))) {
883       return NULL;
884    }
885
886    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
887    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
888    adapt->name = "SIS 300/315/330 series Video Overlay";
889    adapt->nEncodings = 1;
890    adapt->pEncodings = &DummyEncoding;
891
892    adapt->nFormats = NUM_FORMATS;
893    adapt->pFormats = SISFormats;
894    adapt->nPorts = 1;
895    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
896
897    pPriv = (SISPortPrivPtr)(&adapt->pPortPrivates[1]);
898
899    pPriv->videoStatus = 0;
900    pPriv->currentBuf  = 0;
901    pPriv->handle      = NULL;
902    pPriv->grabbedByV4L= FALSE;
903    pPriv->NoOverlay   = FALSE;
904    pPriv->PrevOverlay = FALSE;
905    pPriv->is661741760 = ((pSiS->ChipType >= SIS_661) &&
906			  (pSiS->ChipType <= SIS_760)) ? TRUE : FALSE;
907    pPriv->is760       = (pSiS->ChipType == SIS_760)   ? TRUE : FALSE;
908    pPriv->is761       = (pSiS->ChipType == SIS_761)   ? TRUE : FALSE;
909    pPriv->is340       = (pSiS->Chipset == PCI_CHIP_SIS340) ? TRUE : FALSE;
910    pPriv->isXGI       = (pSiS->Chipset == PCI_CHIP_XGIXG20 ||
911			  pSiS->Chipset == PCI_CHIP_XGIXG40) ? TRUE : FALSE;
912
913    /* Setup chipset type helpers */
914    set_hastwooverlays(pSiS, pPriv);
915    set_allowswitchcrt(pSiS, pPriv);
916
917    pPriv->havetapscaler = FALSE;
918    if(pPriv->is340 || pPriv->is761 || pPriv->isXGI) {
919       pPriv->havetapscaler = TRUE;
920    }
921
922    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
923    if(pSiS->VGAEngine == SIS_300_VGA) {
924       adapt->nImages = NUM_IMAGES_300;
925       adapt->pAttributes = SISAttributes_300;
926       adapt->nAttributes = SiSCountAttributes(&SISAttributes_300[0]);
927    } else {
928       if(pSiS->ChipType >= SIS_330) {
929          adapt->nImages = NUM_IMAGES_330;
930       } else {
931          adapt->nImages = NUM_IMAGES_315;
932       }
933       adapt->pAttributes = SISAttributes_315;
934       adapt->nAttributes = SiSCountAttributes(&SISAttributes_315[0]);
935       if((pSiS->hasTwoOverlays) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO))) {
936          adapt->nAttributes--;
937       }
938    }
939
940    adapt->pImages = SISImages;
941    adapt->PutVideo = NULL;
942    adapt->PutStill = NULL;
943    adapt->GetVideo = NULL;
944    adapt->GetStill = NULL;
945    adapt->StopVideo = SISStopVideo;
946    adapt->SetPortAttribute = SISSetPortAttribute;
947    adapt->GetPortAttribute = SISGetPortAttribute;
948    adapt->QueryBestSize = SISQueryBestSize;
949    adapt->PutImage = SISPutImage;
950    adapt->QueryImageAttributes = SISQueryImageAttributes;
951
952    /* gotta uninit this someplace */
953#if defined(REGION_NULL)
954    REGION_NULL(pScreen, &pPriv->clip);
955#else
956    REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
957#endif
958
959    pSiS->adaptor = adapt;
960
961    pSiS->xvBrightness        = MAKE_ATOM(sisxvbrightness);
962    pSiS->xvContrast          = MAKE_ATOM(sisxvcontrast);
963    pSiS->xvColorKey          = MAKE_ATOM(sisxvcolorkey);
964    pSiS->xvSaturation        = MAKE_ATOM(sisxvsaturation);
965    pSiS->xvHue               = MAKE_ATOM(sisxvhue);
966    pSiS->xvSwitchCRT  	      = MAKE_ATOM(sisxvswitchcrt);
967    pSiS->xvAutopaintColorKey = MAKE_ATOM(sisxvautopaintcolorkey);
968    pSiS->xvSetDefaults       = MAKE_ATOM(sisxvsetdefaults);
969    pSiS->xvDisableGfx        = MAKE_ATOM(sisxvdisablegfx);
970    pSiS->xvDisableGfxLR      = MAKE_ATOM(sisxvdisablegfxlr);
971    pSiS->xvTVXPosition       = MAKE_ATOM(sisxvtvxposition);
972    pSiS->xvTVYPosition       = MAKE_ATOM(sisxvtvyposition);
973    pSiS->xvGammaRed	      = MAKE_ATOM(sisxvgammared);
974    pSiS->xvGammaGreen	      = MAKE_ATOM(sisxvgammagreen);
975    pSiS->xvGammaBlue	      = MAKE_ATOM(sisxvgammablue);
976    pSiS->xvDisableColorkey   = MAKE_ATOM(sisxvdisablecolorkey);
977    pSiS->xvUseChromakey      = MAKE_ATOM(sisxvusechromakey);
978    pSiS->xvInsideChromakey   = MAKE_ATOM(sisxvinsidechromakey);
979    pSiS->xvYUVChromakey      = MAKE_ATOM(sisxvyuvchromakey);
980    pSiS->xvChromaMin	      = MAKE_ATOM(sisxvchromamin);
981    pSiS->xvChromaMax         = MAKE_ATOM(sisxvchromamax);
982#ifdef SISDEINT
983    pSiS->xvdeintmeth	      = MAKE_ATOM(sisxvdeinterlace);
984#endif
985#ifdef XV_SD_DEPRECATED
986    pSiS->xv_QVF              = MAKE_ATOM(sisxvqueryvbflags);
987    pSiS->xv_GDV	      = MAKE_ATOM(sisxvsdgetdriverversion);
988    pSiS->xv_GHI	      = MAKE_ATOM(sisxvsdgethardwareinfo);
989    pSiS->xv_GBI	      = MAKE_ATOM(sisxvsdgetbusid);
990    pSiS->xv_QVV              = MAKE_ATOM(sisxvsdqueryvbflagsversion);
991    pSiS->xv_GSF              = MAKE_ATOM(sisxvsdgetsdflags);
992    pSiS->xv_GSF2             = MAKE_ATOM(sisxvsdgetsdflags2);
993    pSiS->xv_USD              = MAKE_ATOM(sisxvsdunlocksisdirect);
994    pSiS->xv_SVF              = MAKE_ATOM(sisxvsdsetvbflags);
995    pSiS->xv_QDD	      = MAKE_ATOM(sisxvsdquerydetecteddevices);
996    pSiS->xv_CT1	      = MAKE_ATOM(sisxvsdcrt1status);
997    pSiS->xv_CMD	      = MAKE_ATOM(sisxvsdcheckmodeindexforcrt2);
998    pSiS->xv_CMDR	      = MAKE_ATOM(sisxvsdresultcheckmodeindexforcrt2);
999    pSiS->xv_RDT	      = MAKE_ATOM(sisxvsdredetectcrt2);
1000    pSiS->xv_TAF	      = MAKE_ATOM(sisxvsdsisantiflicker);
1001    pSiS->xv_TSA	      = MAKE_ATOM(sisxvsdsissaturation);
1002    pSiS->xv_TEE	      = MAKE_ATOM(sisxvsdsisedgeenhance);
1003    pSiS->xv_COC	      = MAKE_ATOM(sisxvsdsiscolcalibc);
1004    pSiS->xv_COF	      = MAKE_ATOM(sisxvsdsiscolcalibf);
1005    pSiS->xv_CFI	      = MAKE_ATOM(sisxvsdsiscfilter);
1006    pSiS->xv_YFI	      = MAKE_ATOM(sisxvsdsisyfilter);
1007    pSiS->xv_TCO	      = MAKE_ATOM(sisxvsdchcontrast);
1008    pSiS->xv_TTE	      = MAKE_ATOM(sisxvsdchtextenhance);
1009    pSiS->xv_TCF	      = MAKE_ATOM(sisxvsdchchromaflickerfilter);
1010    pSiS->xv_TLF	      = MAKE_ATOM(sisxvsdchlumaflickerfilter);
1011    pSiS->xv_TCC	      = MAKE_ATOM(sisxvsdchcvbscolor);
1012    pSiS->xv_OVR	      = MAKE_ATOM(sisxvsdchoverscan);
1013    pSiS->xv_SGA	      = MAKE_ATOM(sisxvsdenablegamma);
1014    pSiS->xv_TXS	      = MAKE_ATOM(sisxvsdtvxscale);
1015    pSiS->xv_TYS	      = MAKE_ATOM(sisxvsdtvyscale);
1016    pSiS->xv_GSS	      = MAKE_ATOM(sisxvsdgetscreensize);
1017    pSiS->xv_BRR	      = MAKE_ATOM(sisxvsdstorebrir);
1018    pSiS->xv_BRG	      = MAKE_ATOM(sisxvsdstorebrig);
1019    pSiS->xv_BRB	      = MAKE_ATOM(sisxvsdstorebrib);
1020    pSiS->xv_PBR	      = MAKE_ATOM(sisxvsdstorepbrir);
1021    pSiS->xv_PBG	      = MAKE_ATOM(sisxvsdstorepbrig);
1022    pSiS->xv_PBB	      = MAKE_ATOM(sisxvsdstorepbrib);
1023    pSiS->xv_BRR2	      = MAKE_ATOM(sisxvsdstorebrir2);
1024    pSiS->xv_BRG2	      = MAKE_ATOM(sisxvsdstorebrig2);
1025    pSiS->xv_BRB2	      = MAKE_ATOM(sisxvsdstorebrib2);
1026    pSiS->xv_PBR2	      = MAKE_ATOM(sisxvsdstorepbrir2);
1027    pSiS->xv_PBG2	      = MAKE_ATOM(sisxvsdstorepbrig2);
1028    pSiS->xv_PBB2	      = MAKE_ATOM(sisxvsdstorepbrib2);
1029    pSiS->xv_GARC2	      = MAKE_ATOM(sisxvsdstoregarc2);
1030    pSiS->xv_GAGC2	      = MAKE_ATOM(sisxvsdstoregagc2);
1031    pSiS->xv_GABC2	      = MAKE_ATOM(sisxvsdstoregabc2);
1032    pSiS->xv_BRRC2	      = MAKE_ATOM(sisxvsdstorebrirc2);
1033    pSiS->xv_BRGC2	      = MAKE_ATOM(sisxvsdstorebrigc2);
1034    pSiS->xv_BRBC2	      = MAKE_ATOM(sisxvsdstorebribc2);
1035    pSiS->xv_PBRC2	      = MAKE_ATOM(sisxvsdstorepbrirc2);
1036    pSiS->xv_PBGC2	      = MAKE_ATOM(sisxvsdstorepbrigc2);
1037    pSiS->xv_PBBC2	      = MAKE_ATOM(sisxvsdstorepbribc2);
1038    pSiS->xv_SHC	      = MAKE_ATOM(sisxvsdhidehwcursor);
1039    pSiS->xv_PMD	      = MAKE_ATOM(sisxvsdpanelmode);
1040#ifdef TWDEBUG
1041    pSiS->xv_STR	      = MAKE_ATOM(sisxvsetreg);
1042#endif
1043#endif /* XV_SD_DEPRECATED */
1044#ifdef SIS_CP
1045    SIS_CP_VIDEO_ATOMS
1046#endif
1047
1048    pSiS->xv_sisdirectunlocked = 0;
1049#ifdef XV_SD_DEPRECATED
1050    pSiS->xv_sd_result = 0;
1051#endif
1052
1053    /* 300 series require double words for addresses and pitches,
1054     * 315/330 series require word.
1055     */
1056    switch (pSiS->VGAEngine) {
1057    case SIS_315_VGA:
1058	pPriv->shiftValue = 1;
1059	break;
1060    case SIS_300_VGA:
1061    default:
1062	pPriv->shiftValue = 2;
1063	break;
1064    }
1065
1066    /* Set displayMode according to VBFlags */
1067    set_dispmode(pScrn, pPriv);
1068
1069    /* Now for the linebuffer stuff.
1070     * All chipsets have a certain number of linebuffers, each of a certain
1071     * size. The number of buffers is per overlay.
1072     * Chip        number      size     	  max video size
1073     *  300          2		 ?		     720x576
1074     *  630/730      2		 ?		     720x576
1075     *  315          2		960?		    1920x1080
1076     *  550	     2?		960?		    1920x1080?
1077     *  650/740      2		960 ("120x128")	    1920x1080
1078     *  M650/651..   4		480		    1920x1080
1079     *  330          2		960		    1920x1080
1080     *  661/741/760  4		768 		    1920x1080
1081     *  340          4	       1280?		    1920x1080?
1082     *  761          4         1536?		    1920x1080?
1083     * The unit of size is unknown; I just know that a size of 480 limits
1084     * the video source width to 384. Beyond that, line buffers must be
1085     * merged (otherwise the video output is garbled).
1086     * To use the maximum width (eg 1920x1080 on the 315 series, including
1087     * the M650, 651 and later), *all* line buffers must be merged. Hence,
1088     * we can only use one overlay. This should be set up for modes where
1089     * either only CRT1 or only CRT2 is used.
1090     * If both overlays are going to be used (such as in modes were both
1091     * CRT1 and CRT2 are active), we are limited to the half of the
1092     * maximum width, or 1536 on 661/741/760.
1093     * There is a known hardware problem with the 760 and 761 if the video
1094     * data is in the UMA area: The memory access latency is too big to
1095     * allow two overlays under some circumstances. Therefore, we must
1096     * support switching between hasTwoOverlays and !hasTwoOverlays on
1097     * the fly.
1098     */
1099
1100    if(pSiS->VGAEngine == SIS_300_VGA) {
1101       pPriv->linebufmask = 0x11;
1102       pPriv->linebufMergeLimit = 384;
1103    } else {
1104       pPriv->linebufmask = 0xb1;
1105       pPriv->linebufMergeLimit = 384;			/* should be 480 */
1106       if(pPriv->is661741760) {
1107          pPriv->linebufMergeLimit = 576;		/* should be 768 */
1108       } else if(pPriv->is340) {
1109          pPriv->linebufMergeLimit = 1280;		/* should be 1280 */
1110       } else if(pPriv->is761) {
1111          pPriv->linebufMergeLimit = 1280;		/* should be 1536 */
1112       } else if(pPriv->isXGI) {
1113          pPriv->linebufMergeLimit = 1280;		/* FIXME */
1114       } else if(!(pPriv->hasTwoOverlays)) {
1115          pPriv->linebufMergeLimit = 720;		/* should be 960 */
1116       }
1117       /* No special treatment for 760/761 required */
1118    }
1119
1120    set_maxencoding(pSiS, pPriv);
1121
1122    /* Reset the properties to their defaults */
1123    SISSetPortDefaults(pScrn, pPriv);
1124
1125    /* Set SR(06, 32) registers according to DISPMODE */
1126    set_disptype_regs(pScrn, pPriv);
1127
1128    SISResetVideo(pScrn);
1129    pSiS->ResetXv = SISResetVideo;
1130    pSiS->ResetXvDisplay = SISResetXvDisplay;
1131    if(pSiS->VGAEngine == SIS_315_VGA) {
1132       pSiS->ResetXvGamma = SISResetXvGamma;
1133    }
1134
1135    return adapt;
1136}
1137
1138#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
1139static Bool
1140RegionsEqual(RegionPtr A, RegionPtr B)
1141{
1142    int *dataA, *dataB;
1143    int num;
1144
1145    num = REGION_NUM_RECTS(A);
1146    if(num != REGION_NUM_RECTS(B))
1147       return FALSE;
1148
1149    if((A->extents.x1 != B->extents.x1) ||
1150       (A->extents.x2 != B->extents.x2) ||
1151       (A->extents.y1 != B->extents.y1) ||
1152       (A->extents.y2 != B->extents.y2))
1153       return FALSE;
1154
1155    dataA = (int*)REGION_RECTS(A);
1156    dataB = (int*)REGION_RECTS(B);
1157
1158    while(num--) {
1159      if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
1160         return FALSE;
1161      dataA += 2;
1162      dataB += 2;
1163    }
1164
1165    return TRUE;
1166}
1167#endif
1168
1169/*********************************
1170 *       SetPortAttribute()      *
1171 *********************************/
1172
1173void
1174SISUpdateVideoParms(SISPtr pSiS, SISPortPrivPtr pPriv)
1175{
1176  set_hastwooverlays(pSiS, pPriv);
1177  set_allowswitchcrt(pSiS, pPriv);
1178  set_dispmode(pSiS->pScrn, pPriv);
1179  set_maxencoding(pSiS, pPriv);
1180}
1181
1182static int
1183SISSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
1184		    INT32 value, pointer data)
1185{
1186  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
1187  SISPtr pSiS = SISPTR(pScrn);
1188#ifdef SISDUALHEAD
1189  SISEntPtr pSiSEnt = pSiS->entityPrivate;;
1190#endif
1191
1192  if(attribute == pSiS->xvBrightness) {
1193     if((value < -128) || (value > 127))
1194        return BadValue;
1195     pPriv->brightness = value;
1196  } else if(attribute == pSiS->xvContrast) {
1197     if((value < 0) || (value > 7))
1198        return BadValue;
1199     pPriv->contrast = value;
1200  } else if(attribute == pSiS->xvColorKey) {
1201     pPriv->colorKey = pSiS->colorKey = value;
1202     REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1203  } else if(attribute == pSiS->xvAutopaintColorKey) {
1204     if((value < 0) || (value > 1))
1205        return BadValue;
1206     pPriv->autopaintColorKey = value;
1207  } else if(attribute == pSiS->xvSetDefaults) {
1208     SISSetPortDefaults(pScrn, pPriv);
1209  } else if(attribute == pSiS->xvDisableGfx) {
1210     if((value < 0) || (value > 1))
1211        return BadValue;
1212     pPriv->disablegfx = value;
1213  } else if(attribute == pSiS->xvDisableGfxLR) {
1214     if((value < 0) || (value > 1))
1215        return BadValue;
1216     pPriv->disablegfxlr = value;
1217  } else if(attribute == pSiS->xvTVXPosition) {
1218     if((value < -32) || (value > 32))
1219        return BadValue;
1220     pPriv->tvxpos = value;
1221     if(pSiS->xv_sisdirectunlocked) {
1222        SiS_SetTVxposoffset(pScrn, pPriv->tvxpos);
1223        pPriv->updatetvxpos = FALSE;
1224     } else {
1225        pSiS->tvxpos = pPriv->tvxpos;
1226#ifdef SISDUALHEAD
1227        if(pPriv->dualHeadMode) pSiSEnt->tvxpos = pPriv->tvxpos;
1228#endif
1229        pPriv->updatetvxpos = TRUE;
1230     }
1231  } else if(attribute == pSiS->xvTVYPosition) {
1232     if((value < -32) || (value > 32)) return BadValue;
1233     pPriv->tvypos = value;
1234     if(pSiS->xv_sisdirectunlocked) {
1235        SiS_SetTVyposoffset(pScrn, pPriv->tvypos);
1236        pPriv->updatetvypos = FALSE;
1237     } else {
1238        pSiS->tvypos = pPriv->tvypos;
1239#ifdef SISDUALHEAD
1240        if(pPriv->dualHeadMode) pSiSEnt->tvypos = pPriv->tvypos;
1241#endif
1242        pPriv->updatetvypos = TRUE;
1243     }
1244  } else if(attribute == pSiS->xvDisableColorkey) {
1245     if((value < 0) || (value > 1)) return BadValue;
1246     pSiS->disablecolorkeycurrent = value;
1247  } else if(attribute == pSiS->xvUseChromakey) {
1248     if((value < 0) || (value > 1)) return BadValue;
1249     pPriv->usechromakey = value;
1250  } else if(attribute == pSiS->xvInsideChromakey) {
1251     if((value < 0) || (value > 1)) return BadValue;
1252     pPriv->insidechromakey = value;
1253  } else if(attribute == pSiS->xvYUVChromakey) {
1254     if((value < 0) || (value > 1)) return BadValue;
1255     pPriv->yuvchromakey = value;
1256  } else if(attribute == pSiS->xvChromaMin) {
1257     pPriv->chromamin = value;
1258  } else if(attribute == pSiS->xvChromaMax) {
1259     pPriv->chromamax = value;
1260#ifdef SISDEINT
1261  } else if(attribute == pSiS->xvdeintmeth) {
1262     if(value < 0) value = 0;
1263     if(value > 4) value = 4;
1264     pPriv->deinterlacemethod = value;
1265#endif
1266#ifdef SIS_CP
1267  SIS_CP_VIDEO_SETATTRIBUTE
1268#endif
1269  } else if(attribute == pSiS->xvHue) {
1270     if(pSiS->VGAEngine == SIS_315_VGA) {
1271        if((value < -8) || (value > 7)) return BadValue;
1272        pPriv->hue = value;
1273     } else return BadMatch;
1274  } else if(attribute == pSiS->xvSaturation) {
1275     if(pSiS->VGAEngine == SIS_315_VGA) {
1276        if((value < -7) || (value > 7)) return BadValue;
1277        pPriv->saturation = value;
1278     } else return BadMatch;
1279  } else if(attribute == pSiS->xvGammaRed) {
1280     if(pSiS->VGAEngine == SIS_315_VGA) {
1281        if((value < 100) || (value > 10000))  return BadValue;
1282        pSiS->XvGammaRed = value;
1283        SiSUpdateXvGamma(pSiS, pPriv);
1284     } else return BadMatch;
1285  } else if(attribute == pSiS->xvGammaGreen) {
1286     if(pSiS->VGAEngine == SIS_315_VGA) {
1287        if((value < 100) || (value > 10000)) return BadValue;
1288        pSiS->XvGammaGreen = value;
1289        SiSUpdateXvGamma(pSiS, pPriv);
1290     } else return BadMatch;
1291  } else if(attribute == pSiS->xvGammaBlue) {
1292     if(pSiS->VGAEngine == SIS_315_VGA) {
1293        if((value < 100) || (value > 10000)) return BadValue;
1294        pSiS->XvGammaBlue = value;
1295        SiSUpdateXvGamma(pSiS, pPriv);
1296     } else return BadMatch;
1297  } else if(attribute == pSiS->xvSwitchCRT) {
1298     if(pSiS->VGAEngine == SIS_315_VGA) {
1299        if(pPriv->AllowSwitchCRT) {
1300           if((value < 0) || (value > 1))
1301              return BadValue;
1302	   pPriv->crtnum = value;
1303#ifdef SISDUALHEAD
1304           if(pPriv->dualHeadMode) pSiSEnt->curxvcrtnum = value;
1305#endif
1306        }
1307     } else return BadMatch;
1308  } else {
1309#ifdef XV_SD_DEPRECATED
1310     return(SISSetPortUtilAttribute(pScrn, attribute, value, pPriv));
1311#else
1312     return BadMatch;
1313#endif
1314  }
1315  return Success;
1316}
1317
1318/*********************************
1319 *       GetPortAttribute()      *
1320 *********************************/
1321
1322static int
1323SISGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
1324			INT32 *value, pointer data)
1325{
1326  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
1327  SISPtr pSiS = SISPTR(pScrn);
1328#ifdef SISDUALHEAD
1329  SISEntPtr pSiSEnt = pSiS->entityPrivate;;
1330#endif
1331
1332  if(attribute == pSiS->xvBrightness) {
1333     *value = pPriv->brightness;
1334  } else if(attribute == pSiS->xvContrast) {
1335     *value = pPriv->contrast;
1336  } else if(attribute == pSiS->xvColorKey) {
1337     *value = pPriv->colorKey;
1338  } else if(attribute == pSiS->xvAutopaintColorKey) {
1339     *value = (pPriv->autopaintColorKey) ? 1 : 0;
1340  } else if(attribute == pSiS->xvDisableGfx) {
1341     *value = (pPriv->disablegfx) ? 1 : 0;
1342  } else if(attribute == pSiS->xvDisableGfxLR) {
1343     *value = (pPriv->disablegfxlr) ? 1 : 0;
1344  } else if(attribute == pSiS->xvTVXPosition) {
1345     *value = SiS_GetTVxposoffset(pScrn);
1346  } else if(attribute == pSiS->xvTVYPosition) {
1347     *value = SiS_GetTVyposoffset(pScrn);
1348  } else if(attribute == pSiS->xvDisableColorkey) {
1349     *value = (pSiS->disablecolorkeycurrent) ? 1 : 0;
1350  } else if(attribute == pSiS->xvUseChromakey) {
1351     *value = (pPriv->usechromakey) ? 1 : 0;
1352  } else if(attribute == pSiS->xvInsideChromakey) {
1353     *value = (pPriv->insidechromakey) ? 1 : 0;
1354  } else if(attribute == pSiS->xvYUVChromakey) {
1355     *value = (pPriv->yuvchromakey) ? 1 : 0;
1356  } else if(attribute == pSiS->xvChromaMin) {
1357     *value = pPriv->chromamin;
1358  } else if(attribute == pSiS->xvChromaMax) {
1359     *value = pPriv->chromamax;
1360#ifdef SISDEINT
1361  } else if(attribute == pSiS->xvdeintmeth) {
1362     *value = pPriv->deinterlacemethod;
1363#endif
1364#ifdef SIS_CP
1365  SIS_CP_VIDEO_GETATTRIBUTE
1366#endif
1367  } else if(attribute == pSiS->xvHue) {
1368     if(pSiS->VGAEngine == SIS_315_VGA) {
1369        *value = pPriv->hue;
1370     } else return BadMatch;
1371  } else if(attribute == pSiS->xvSaturation) {
1372     if(pSiS->VGAEngine == SIS_315_VGA) {
1373        *value = pPriv->saturation;
1374     } else return BadMatch;
1375  } else if(attribute == pSiS->xvGammaRed) {
1376     if(pSiS->VGAEngine == SIS_315_VGA) {
1377        *value = pSiS->XvGammaRed;
1378     } else return BadMatch;
1379  } else if(attribute == pSiS->xvGammaGreen) {
1380     if(pSiS->VGAEngine == SIS_315_VGA) {
1381        *value = pSiS->XvGammaGreen;
1382     } else return BadMatch;
1383  } else if(attribute == pSiS->xvGammaBlue) {
1384     if(pSiS->VGAEngine == SIS_315_VGA) {
1385        *value = pSiS->XvGammaBlue;
1386     } else return BadMatch;
1387  } else if(attribute == pSiS->xvSwitchCRT) {
1388     if(pSiS->VGAEngine == SIS_315_VGA) {
1389#ifdef SISDUALHEAD
1390        if(pPriv->dualHeadMode)
1391           *value = pSiSEnt->curxvcrtnum;
1392        else
1393#endif
1394           *value = pPriv->crtnum;
1395     } else return BadMatch;
1396  } else {
1397#ifdef XV_SD_DEPRECATED
1398     return(SISGetPortUtilAttribute(pScrn, attribute, value, pPriv));
1399#else
1400     return BadMatch;
1401#endif
1402  }
1403  return Success;
1404}
1405
1406/*********************************
1407 *         QueryBestSize()       *
1408 *********************************/
1409
1410static void
1411SISQueryBestSize(
1412  ScrnInfoPtr pScrn,
1413  Bool motion,
1414  short vid_w, short vid_h,
1415  short drw_w, short drw_h,
1416  unsigned int *p_w, unsigned int *p_h,
1417  pointer data
1418){
1419  *p_w = drw_w;
1420  *p_h = drw_h;
1421}
1422
1423/*********************************
1424 *       Calc scaling factor     *
1425 *********************************/
1426
1427static void
1428calc_scale_factor(SISOverlayPtr pOverlay, ScrnInfoPtr pScrn,
1429                 SISPortPrivPtr pPriv, int index, int iscrt2)
1430{
1431  SISPtr pSiS = SISPTR(pScrn);
1432  CARD32 I=0,mult=0;
1433  int flag=0, flag2=0;
1434
1435  int dstW = pOverlay->dstBox.x2 - pOverlay->dstBox.x1;
1436  int dstH = pOverlay->dstBox.y2 - pOverlay->dstBox.y1;
1437  int srcW = pOverlay->srcW;
1438  int srcH = pOverlay->srcH;
1439  CARD16 LCDheight = pSiS->LCDheight;
1440  int srcPitch = pOverlay->origPitch;
1441  int origdstH = dstH;
1442  int modeflags = pOverlay->currentmode->Flags;
1443
1444  /* Stretch image due to panel link scaling */
1445  if(pSiS->VBFlags & (CRT2_LCD | CRT1_LCDA)) {
1446     if(pPriv->bridgeIsSlave) {
1447	if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
1448	   if(pSiS->MiscFlags & MISC_PANELLINKSCALER) {
1449	      dstH = (dstH * LCDheight) / pOverlay->SCREENheight;
1450	   }
1451	}
1452     } else if((iscrt2 && (pSiS->VBFlags & CRT2_LCD)) ||
1453	       (!iscrt2 && (pSiS->VBFlags & CRT1_LCDA))) {
1454	if((pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) || (pSiS->VBFlags & CRT1_LCDA)) {
1455	   if(pSiS->MiscFlags & MISC_PANELLINKSCALER) {
1456	      dstH = (dstH * LCDheight) / pOverlay->SCREENheight;
1457	      if(pPriv->displayMode == DISPMODE_MIRROR) flag = 1;
1458	   }
1459	}
1460     }
1461     if((pPriv->bridgeIsSlave || iscrt2) &&
1462        (pSiS->MiscFlags & MISC_STNMODE)) {
1463	flag2 = 1;
1464     }
1465  }
1466
1467  /* For double scan modes, we need to double the height
1468   * On 315 and 550 (?), we need to double the width as well.
1469   * Interlace mode vice versa.
1470   */
1471  if((modeflags & V_DBLSCAN) && !flag2) {
1472     dstH = origdstH << 1;
1473     flag = 0;
1474     if((pSiS->ChipType >= SIS_315H) &&
1475	(pSiS->ChipType <= SIS_550)) {
1476	dstW <<= 1;
1477     }
1478  } else if(modeflags & V_INTERLACE) {
1479     dstH = origdstH >> 1;
1480     flag = 0;
1481  }
1482
1483  pOverlay->tap_scale = 1.0;
1484
1485  if(dstW < OVERLAY_MIN_WIDTH) dstW = OVERLAY_MIN_WIDTH;
1486
1487  if(dstW == srcW) {
1488
1489     pOverlay->HUSF   = 0x00;
1490     pOverlay->IntBit = 0x05;
1491     pOverlay->wHPre  = 0;
1492
1493  } else if(dstW > srcW) {
1494
1495     pOverlay->IntBit = 0x04;
1496     pOverlay->wHPre  = 0;
1497
1498     if(pPriv->havetapscaler) {
1499        if((dstW > 2) && (srcW > 2)) {
1500           pOverlay->HUSF = (((srcW - 2) << 16) + dstW - 3) / (dstW - 2);
1501        } else {
1502           pOverlay->HUSF = ((srcW << 16) + dstW - 1) / dstW;
1503        }
1504     } else {
1505        dstW += 2;
1506        pOverlay->HUSF = (srcW << 16) / dstW;
1507     }
1508
1509  } else {
1510
1511     int tmpW = dstW;
1512
1513     /* It seems, the hardware can't scale below factor .125 (=1/8) if the
1514        pitch isn't a multiple of 256.
1515	TODO: Test this on the 315 series!
1516      */
1517     if((srcPitch % 256) || (srcPitch < 256)) {
1518        if(((dstW * 1000) / srcW) < 125) dstW = tmpW = ((srcW * 125) / 1000) + 1;
1519     }
1520
1521     I = 0;
1522     pOverlay->IntBit = 0x01;
1523     while(srcW >= tmpW) {
1524        tmpW <<= 1;
1525        I++;
1526     }
1527     pOverlay->wHPre = (CARD8)(I - 1);
1528     dstW <<= (I - 1);
1529
1530     pOverlay->tap_scale = (float)srcW / (float)dstW;
1531     if(pOverlay->tap_scale < 1.0) pOverlay->tap_scale = 1.0;
1532
1533     if((srcW % dstW))
1534        pOverlay->HUSF = ((srcW - dstW) << 16) / dstW;
1535     else
1536        pOverlay->HUSF = 0;
1537  }
1538
1539  if(dstH < OVERLAY_MIN_HEIGHT) dstH = OVERLAY_MIN_HEIGHT;
1540
1541  if(dstH == srcH) {
1542
1543     pOverlay->VUSF   = 0x00;
1544     pOverlay->IntBit |= 0x0A;
1545
1546  } else if(dstH > srcH) {
1547
1548     dstH += 2;
1549     pOverlay->IntBit |= 0x08;
1550
1551     if(pPriv->havetapscaler) {
1552        if((dstH > 2) && (srcH > 2)) {
1553           pOverlay->VUSF = (((srcH - 2) << 16) - 32768 + dstH - 3) / (dstH - 2);
1554        } else {
1555           pOverlay->VUSF = ((srcH << 16) + dstH - 1) / dstH;
1556        }
1557     } else {
1558        pOverlay->VUSF = (srcH << 16) / dstH;
1559     }
1560
1561  } else {
1562
1563     I = srcH / dstH;
1564     pOverlay->IntBit |= 0x02;
1565
1566     if(I < 2) {
1567	pOverlay->VUSF = ((srcH - dstH) << 16) / dstH;
1568	/* Needed for LCD-scaling modes */
1569	if((flag) && (mult = (srcH / origdstH)) >= 2) {
1570	   pOverlay->pitch /= mult;
1571	}
1572     } else {
1573#if 0
1574	if(((pOverlay->bobEnable & 0x08) == 0x00) &&
1575	   (((srcPitch * I) >> 2) > 0xFFF)){
1576	   pOverlay->bobEnable |= 0x08;
1577	   srcPitch >>= 1;
1578	}
1579#endif
1580	if(((srcPitch * I) >> 2) > 0xFFF) {
1581	   I = (0xFFF * 2 / srcPitch);
1582	   pOverlay->VUSF = 0xFFFF;
1583	} else {
1584	   dstH = I * dstH;
1585	   if(srcH % dstH)
1586	      pOverlay->VUSF = ((srcH - dstH) << 16) / dstH;
1587	   else
1588	      pOverlay->VUSF = 0;
1589	}
1590	/* set video frame buffer offset */
1591	pOverlay->pitch = (CARD16)(srcPitch * I);
1592     }
1593  }
1594}
1595
1596#ifdef SISMERGED
1597static void
1598calc_scale_factor_2(SISOverlayPtr pOverlay, ScrnInfoPtr pScrn,
1599                 SISPortPrivPtr pPriv, int index, int iscrt2)
1600{
1601  SISPtr pSiS = SISPTR(pScrn);
1602  CARD32 I=0,mult=0;
1603  int flag=0, flag2=0;
1604
1605  int dstW = pOverlay->dstBox2.x2 - pOverlay->dstBox2.x1;
1606  int dstH = pOverlay->dstBox2.y2 - pOverlay->dstBox2.y1;
1607  int srcW = pOverlay->srcW2;
1608  int srcH = pOverlay->srcH2;
1609  CARD16 LCDheight = pSiS->LCDheight;
1610  int srcPitch = pOverlay->origPitch;
1611  int origdstH = dstH;
1612  int modeflags = pOverlay->currentmode2->Flags;
1613
1614  /* Stretch image due to panel link scaling */
1615  if(pSiS->VBFlags & CRT2_LCD) {
1616     if(pSiS->VBFlags2 & (VB2_LVDS | VB2_30xBDH)) {
1617	if(pSiS->MiscFlags & MISC_PANELLINKSCALER) {
1618	   dstH = (dstH * LCDheight) / pOverlay->SCREENheight2;
1619	   flag = 1;
1620	}
1621	if(pSiS->MiscFlags & MISC_STNMODE) flag2 = 1;
1622     }
1623  }
1624  /* For double scan modes, we need to double the height
1625   * On 315 and 550 (?), we need to double the width as well.
1626   * Interlace mode vice versa.
1627   */
1628  if((modeflags & V_DBLSCAN) && !flag2) {
1629     dstH = origdstH << 1;
1630     flag = 0;
1631     if((pSiS->ChipType >= SIS_315H) &&
1632	(pSiS->ChipType <= SIS_550)) {
1633	dstW <<= 1;
1634     }
1635  }
1636  if(modeflags & V_INTERLACE) {
1637     dstH = origdstH >> 1;
1638     flag = 0;
1639  }
1640
1641  pOverlay->tap_scale2 = 1.0;
1642
1643  if(dstW < OVERLAY_MIN_WIDTH) dstW = OVERLAY_MIN_WIDTH;
1644
1645  if(dstW == srcW) {
1646
1647     pOverlay->HUSF2   = 0x00;
1648     pOverlay->IntBit2 = 0x05;
1649     pOverlay->wHPre2  = 0;
1650
1651  } else if(dstW > srcW) {
1652
1653     pOverlay->IntBit2 = 0x04;
1654     pOverlay->wHPre2  = 0;
1655
1656     if(pPriv->havetapscaler) {
1657        if((dstW > 2) && (srcW > 2)) {
1658           pOverlay->HUSF2 = (((srcW - 2) << 16) + dstW - 3) / (dstW - 2);
1659        } else {
1660           pOverlay->HUSF2 = ((srcW << 16) + dstW - 1) / dstW;
1661        }
1662     } else {
1663        dstW += 2;
1664        pOverlay->HUSF2 = (srcW << 16) / dstW;
1665     }
1666
1667  } else {
1668
1669     int tmpW = dstW;
1670
1671     /* It seems, the hardware can't scale below factor .125 (=1/8) if the
1672	pitch isn't a multiple of 256.
1673	TODO: Test this on the 315 series!
1674      */
1675     if((srcPitch % 256) || (srcPitch < 256)) {
1676	if(((dstW * 1000) / srcW) < 125) dstW = tmpW = ((srcW * 125) / 1000) + 1;
1677     }
1678
1679     I = 0;
1680     pOverlay->IntBit2 = 0x01;
1681     while(srcW >= tmpW) {
1682        tmpW <<= 1;
1683        I++;
1684     }
1685     pOverlay->wHPre2 = (CARD8)(I - 1);
1686     dstW <<= (I - 1);
1687
1688     pOverlay->tap_scale2 = (float)srcW / (float)dstW;
1689     if(pOverlay->tap_scale2 < 1.0) pOverlay->tap_scale2 = 1.0;
1690
1691     if((srcW % dstW))
1692        pOverlay->HUSF2 = ((srcW - dstW) << 16) / dstW;
1693     else
1694        pOverlay->HUSF2 = 0x00;
1695  }
1696
1697  if(dstH < OVERLAY_MIN_HEIGHT) dstH = OVERLAY_MIN_HEIGHT;
1698
1699  if(dstH == srcH) {
1700
1701     pOverlay->VUSF2   = 0x00;
1702     pOverlay->IntBit2 |= 0x0A;
1703
1704  } else if(dstH > srcH) {
1705
1706     dstH += 2;
1707     pOverlay->IntBit2 |= 0x08;
1708
1709     if(pPriv->havetapscaler) {
1710        if((dstH > 2) && (srcH > 2)) {
1711           pOverlay->VUSF2 = (((srcH - 2) << 16) - 32768 + dstH - 3) / (dstH - 2);
1712        } else {
1713           pOverlay->VUSF2 = ((srcH << 16) + dstH - 1) / dstH;
1714        }
1715     } else {
1716        pOverlay->VUSF2 = (srcH << 16) / dstH;
1717     }
1718
1719  } else {
1720
1721     I = srcH / dstH;
1722     pOverlay->IntBit2 |= 0x02;
1723
1724     if(I < 2) {
1725	pOverlay->VUSF2 = ((srcH - dstH) << 16) / dstH;
1726	/* Needed for LCD-scaling modes */
1727	if(flag && ((mult = (srcH / origdstH)) >= 2)) {
1728	   pOverlay->pitch2 /= mult;
1729	}
1730     } else {
1731#if 0
1732	if(((pOverlay->bobEnable & 0x08) == 0x00) &&
1733	   (((srcPitch * I)>>2) > 0xFFF)){
1734	   pOverlay->bobEnable |= 0x08;
1735	   srcPitch >>= 1;
1736	}
1737#endif
1738	if(((srcPitch * I) >> 2) > 0xFFF) {
1739	   I = (0xFFF * 2 / srcPitch);
1740	   pOverlay->VUSF2 = 0xFFFF;
1741	} else {
1742	   dstH = I * dstH;
1743	   if(srcH % dstH)
1744	      pOverlay->VUSF2 = ((srcH - dstH) << 16) / dstH;
1745	   else
1746	      pOverlay->VUSF2 = 0x00;
1747	}
1748	/* set video frame buffer offset */
1749	pOverlay->pitch2 = (CARD16)(srcPitch * I);
1750     }
1751  }
1752}
1753#endif
1754
1755/*********************************
1756 *    Handle 4-tap scaler (340)  *
1757 *********************************/
1758
1759static float
1760tap_dda_func(float x)
1761{
1762    double pi = 3.14159265358979;
1763    float  r = 0.5, y;
1764
1765    if(x == 0.0) {
1766       y = 1.0;
1767    } else if(x == -1.0 || x == 1.0) {
1768       y = 0.0;
1769       /* case ((x == -1.0 / (r * 2.0)) || (x == 1.0 / (r * 2.0))): */
1770       /* y = (float)(r / 2.0 * sin(pi / (2.0 * r))); = 0.013700916287197;    */
1771    } else {
1772       y = sin(pi * x) / (pi * x) * cos(r * pi * x) / (1 - x * x);
1773       /* y = sin(pi * x) / (pi * x) * cos(r * pi * x) / (1 - 4 * r * r * x * x); */
1774    }
1775
1776    return y;
1777}
1778
1779static void
1780set_dda_regs(SISPtr pSiS, float scale)
1781{
1782    float W[4], WS, myadd;
1783    int   *temp[4], *wm1, *wm2, *wm3, *wm4;
1784    int   i, j, w, tidx, weightmatrix[16][4];
1785
1786    for(i = 0; i < 16; i++) {
1787
1788       myadd = ((float)i) / 16.0;
1789       WS = W[0] = tap_dda_func((myadd + 1.0) / scale);
1790       W[1] = tap_dda_func(myadd / scale);
1791       WS += W[1];
1792       W[2] = tap_dda_func((myadd - 1.0) / scale);
1793       WS += W[2];
1794       W[3] = tap_dda_func((myadd - 2.0) / scale);
1795       WS += W[3];
1796
1797       w = 0;
1798       for(j = 0; j < 4; j++) {
1799	  weightmatrix[i][j] = (int)(((float)((W[j] * 16.0 / WS) + 0.5)));
1800	  w += weightmatrix[i][j];
1801       }
1802
1803       if(w == 12) {
1804
1805	  weightmatrix[i][0]++;
1806	  weightmatrix[i][1]++;
1807	  weightmatrix[i][2]++;
1808	  weightmatrix[i][3]++;
1809
1810       } else if(w == 20) {
1811
1812	  weightmatrix[i][0]--;
1813	  weightmatrix[i][1]--;
1814	  weightmatrix[i][2]--;
1815	  weightmatrix[i][3]--;
1816
1817       } else if(w != 16) {
1818
1819	  tidx = (weightmatrix[i][0] > weightmatrix[i][1]) ? 0 : 1;
1820	  temp[0] = &weightmatrix[i][tidx];
1821	  temp[1] = &weightmatrix[i][tidx ^ 1];
1822
1823	  tidx = (weightmatrix[i][2] > weightmatrix[i][3]) ? 2 : 3;
1824	  temp[2] = &weightmatrix[i][tidx];
1825	  temp[3] = &weightmatrix[i][tidx ^ 1];
1826
1827	  tidx = (*(temp[0]) > *(temp[2])) ? 0 : 2;
1828	  wm1 = temp[tidx];
1829	  wm2 = temp[tidx ^ 2];
1830
1831	  tidx = (*(temp[1]) > *(temp[3])) ? 1 : 3;
1832	  wm3 = temp[tidx];
1833	  wm4 = temp[tidx ^ 2];
1834
1835	  switch(w) {
1836	     case 13:
1837		(*wm1)++;
1838		(*wm4)++;
1839		if(*wm2 > *wm3) (*wm2)++;
1840		else            (*wm3)++;
1841		break;
1842	     case 14:
1843		(*wm1)++;
1844		(*wm4)++;
1845		break;
1846	     case 15:
1847		(*wm1)++;
1848		break;
1849	     case 17:
1850		(*wm4)--;
1851		break;
1852	     case 18:
1853		(*wm1)--;
1854		(*wm4)--;
1855		break;
1856	     case 19:
1857		(*wm1)--;
1858		(*wm4)--;
1859		if(*wm2 > *wm3) (*wm3)--;
1860		else            (*wm2)--;
1861	  }
1862       }
1863    }
1864
1865    /* Set 4-tap scaler video regs 0x75-0xb4 */
1866    w = 0x75;
1867    for(i = 0; i < 16; i++) {
1868       for(j = 0; j < 4; j++, w++) {
1869          setvideoregmask(pSiS, w, weightmatrix[i][j], 0x3f);
1870       }
1871    }
1872}
1873
1874/*********************************
1875 *     Calc line buffer size     *
1876 *********************************/
1877
1878static CARD16
1879calc_line_buf_size(CARD32 srcW, CARD8 wHPre, CARD8 planar, SISPortPrivPtr pPriv)
1880{
1881    CARD32 I, mask = 0xffffffff, shift = pPriv->is761 ? 1 : 0;
1882
1883    if(planar) {
1884
1885	switch(wHPre & 0x07) {
1886	    case 3:
1887		shift += 8;
1888		mask <<= shift;
1889		I = srcW >> shift;
1890		if((mask & srcW) != srcW) I++;
1891		I <<= 5;
1892		break;
1893	    case 4:
1894		shift += 9;
1895		mask <<= shift;
1896		I = srcW >> shift;
1897		if((mask & srcW) != srcW) I++;
1898		I <<= 6;
1899		break;
1900	    case 5:
1901		shift += 10;
1902		mask <<= shift;
1903		I = srcW >> shift;
1904		if((mask & srcW) != srcW) I++;
1905		I <<= 7;
1906		break;
1907	    case 6:
1908		if(pPriv->is340 || pPriv->isXGI || pPriv->is761) {
1909		   shift += 11;
1910		   mask <<= shift;
1911		   I = srcW >> shift;
1912		   if((mask & srcW) != srcW) I++;
1913		   I <<= 8;
1914		   break;
1915		} else {
1916		   return((CARD16)(255));
1917		}
1918	    default:
1919		shift += 7;
1920		mask <<= shift;
1921		I = srcW >> shift;
1922		if((mask & srcW) != srcW) I++;
1923		I <<= 4;
1924		break;
1925	}
1926
1927    } else { /* packed */
1928
1929	shift += 3;
1930	mask <<= shift;
1931	I = srcW >> shift;
1932	if((mask & srcW) != srcW) I++;
1933
1934    }
1935
1936    if(I <= 3) I = 4;
1937
1938    return((CARD16)(I - 1));
1939}
1940
1941static __inline void
1942calc_line_buf_size_1(SISOverlayPtr pOverlay, SISPortPrivPtr pPriv)
1943{
1944    pOverlay->lineBufSize =
1945	calc_line_buf_size(pOverlay->srcW, pOverlay->wHPre, pOverlay->planar, pPriv);
1946}
1947
1948#ifdef SISMERGED
1949static __inline void
1950calc_line_buf_size_2(SISOverlayPtr pOverlay, SISPortPrivPtr pPriv)
1951{
1952    pOverlay->lineBufSize2 =
1953	calc_line_buf_size(pOverlay->srcW2, pOverlay->wHPre2, pOverlay->planar, pPriv);
1954}
1955
1956/**********************************
1957 *En/Disable merging of linebuffer*
1958 **********************************/
1959
1960static void
1961merge_line_buf_mfb(SISPtr pSiS, SISPortPrivPtr pPriv, Bool enable1, Bool enable2,
1962                   short width1, short width2, short limit)
1963{
1964    UChar misc1, misc2, mask = pPriv->linebufmask;
1965
1966    if(pPriv->hasTwoOverlays) {     /* This means we are in MIRROR mode */
1967
1968       misc2 = 0x00;
1969       if(enable1) misc1 = 0x04;
1970       else 	   misc1 = 0x00;
1971       setvideoregmask(pSiS, Index_VI_Control_Misc2, misc2, mask);
1972       setvideoregmask(pSiS, Index_VI_Control_Misc1, misc1, 0x04);
1973
1974       misc2 = 0x01;
1975       if(enable2) misc1 = 0x04;
1976       else        misc1 = 0x00;
1977       setvideoregmask(pSiS, Index_VI_Control_Misc2, misc2, mask);
1978       setvideoregmask(pSiS, Index_VI_Control_Misc1, misc1, 0x04);
1979
1980    } else {			/* This means we are either in SINGLE1 or SINGLE2 mode */
1981
1982       misc2 = 0x00;
1983       if(enable1 || enable2) {
1984          if(pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) {
1985	     if((width1 > (limit * 2)) || (width2 > (limit * 2))) {
1986		 misc2 = 0x20;
1987	      } else {
1988		 misc2 = 0x10;
1989	      }
1990	      misc1 = 0x00;
1991	  } else {
1992             misc1 = 0x04;
1993	  }
1994       } else {
1995          misc1 = 0x00;
1996       }
1997
1998       setvideoregmask(pSiS, Index_VI_Control_Misc2, misc2, mask);
1999       setvideoregmask(pSiS, Index_VI_Control_Misc1, misc1, 0x04);
2000
2001    }
2002}
2003#endif
2004
2005/* About linebuffer merging:
2006 *
2007 * For example the 651:
2008 * Each overlay has 4 line buffers, 384 bytes each (<-- Is that really correct? 1920 / 384 = 5 !!!)
2009 * If the source width is greater than 384, line buffers must be merged.
2010 * Dual merge: Only O1 usable (uses overlay 2's linebuffer), maximum width 384*2
2011 * Individual merge: Both overlays available, maximum width 384*2
2012 * All merge: Only overlay 1 available, maximum width = 384*4 (<--- should be 1920, is 1536...)
2013 *
2014 *
2015 *        Normally:                  Dual merge:                 Individual merge
2016 *  Overlay 1    Overlay 2         Overlay 1 only!                Both overlays
2017 *  ___1___      ___5___           ___1___ ___2___ -\         O1  ___1___ ___2___
2018 *  ___2___      ___6___           ___3___ ___4___   \_ O 1   O1  ___3___ ___4___
2019 *  ___3___      ___7___	   ___5___ ___6___   /        O2  ___5___ ___6___
2020 *  ___4___      ___8___           ___7___ ___8___ -/         O2  ___7___ ___8___
2021 *
2022 *
2023 * All merge:          ___1___ ___2___ ___3___ ___4___
2024 * (Overlay 1 only!)   ___5___ ___6___ ___7___ ___8___
2025 *
2026 * Individual merge is supported on all chipsets.
2027 * Dual merge is only supported on the 300 series and M650/651 and later.
2028 * All merge is only supported on the M650/651 and later.
2029 * Single-Overlay-chipsets only support Individual merge.
2030 *
2031 */
2032
2033static void
2034merge_line_buf(SISPtr pSiS, SISPortPrivPtr pPriv, Bool enable, short width, short limit)
2035{
2036  UChar misc1, misc2, mask = pPriv->linebufmask;
2037
2038  if(enable) { 		/* ----- enable linebuffer merge */
2039
2040    switch(pPriv->displayMode){
2041    case DISPMODE_SINGLE1:
2042        if(pSiS->VGAEngine == SIS_300_VGA) {
2043           if(pPriv->dualHeadMode) {
2044	       misc2 = 0x00;
2045	       misc1 = 0x04;
2046	   } else {
2047	       misc2 = 0x10;
2048	       misc1 = 0x00;
2049	   }
2050        } else {
2051	   if(pPriv->hasTwoOverlays) {
2052	      if(pPriv->dualHeadMode) {
2053		 misc2 = 0x00;
2054		 misc1 = 0x04;
2055	      } else {
2056		 if(width > (limit * 2)) {
2057		    misc2 = 0x20;
2058		 } else {
2059		    misc2 = 0x10;
2060		 }
2061		 misc1 = 0x00;
2062	      }
2063	   } else if(pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) {
2064	      if(width > (limit * 2)) {
2065		 misc2 = 0x20;
2066	      } else {
2067		 misc2 = 0x10;
2068	      }
2069	      misc1 = 0x00;
2070	   } else {
2071	      misc2 = 0x00;
2072	      misc1 = 0x04;
2073	   }
2074	}
2075	setvideoregmask(pSiS, Index_VI_Control_Misc2, misc2, mask);
2076	setvideoregmask(pSiS, Index_VI_Control_Misc1, misc1, 0x04);
2077      	break;
2078
2079    case DISPMODE_SINGLE2:
2080        if(pSiS->VGAEngine == SIS_300_VGA) {
2081	   if(pPriv->dualHeadMode) {
2082	      misc2 = 0x01;
2083	      misc1 = 0x04;
2084	   } else {
2085	      misc2 = 0x10;
2086	      misc1 = 0x00;
2087	   }
2088	} else {
2089	   if(pPriv->hasTwoOverlays) {
2090	      if(pPriv->dualHeadMode) {
2091		 misc2 = 0x01;
2092		 misc1 = 0x04;
2093	      } else {
2094		 if(width > (limit * 2)) {
2095		    misc2 = 0x20;
2096		 } else {
2097		    misc2 = 0x10;
2098		 }
2099		 misc1 = 0x00;
2100	      }
2101	   } else if(pSiS->MiscFlags & MISC_SIS760ONEOVERLAY) {
2102	      if(width > (limit * 2)) {
2103		 misc2 = 0x20;
2104	      } else {
2105		 misc2 = 0x10;
2106	      }
2107	      misc1 = 0x00;
2108	   } else {
2109	      misc2 = 0x00;
2110	      misc1 = 0x04;
2111	   }
2112	}
2113	setvideoregmask(pSiS, Index_VI_Control_Misc2, misc2, mask);
2114	setvideoregmask(pSiS, Index_VI_Control_Misc1, misc1, 0x04);
2115     	break;
2116
2117    case DISPMODE_MIRROR:   /* This can only be on chips with 2 overlays */
2118    default:
2119        setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, mask);
2120      	setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x04, 0x04);
2121	setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x01, mask);
2122      	setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x04, 0x04);
2123        break;
2124    }
2125
2126  } else {		/* ----- disable linebuffer merge */
2127
2128    switch(pPriv->displayMode) {
2129
2130    case DISPMODE_SINGLE1:
2131	setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, mask);
2132	setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x04);
2133	break;
2134
2135    case DISPMODE_SINGLE2:
2136	if(pSiS->VGAEngine == SIS_300_VGA) {
2137	   if(pPriv->dualHeadMode) misc2 = 0x01;
2138	   else       		   misc2 = 0x00;
2139	} else {
2140	   if(pPriv->hasTwoOverlays) {
2141	      if(pPriv->dualHeadMode) misc2 = 0x01;
2142	      else                    misc2 = 0x00;
2143	   } else {
2144	      misc2 = 0x00;
2145	   }
2146	}
2147	setvideoregmask(pSiS, Index_VI_Control_Misc2, misc2, mask);
2148	setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x04);
2149	break;
2150
2151    case DISPMODE_MIRROR:   /* This can only be on chips with 2 overlays */
2152    default:
2153	setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, mask);
2154	setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x04);
2155	setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x01, mask);
2156	setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x04);
2157	break;
2158    }
2159  }
2160}
2161
2162/*********************************
2163 *      Select video format      *
2164 *********************************/
2165
2166static __inline void
2167set_format(SISPtr pSiS, SISOverlayPtr pOverlay)
2168{
2169    CARD8 fmt;
2170
2171    switch (pOverlay->pixelFormat){
2172    case PIXEL_FMT_YV12:
2173    case PIXEL_FMT_I420:
2174	fmt = 0x0c;
2175	break;
2176    case PIXEL_FMT_YUY2:
2177	fmt = 0x28;
2178	break;
2179    case PIXEL_FMT_UYVY:
2180	fmt = 0x08;
2181	break;
2182    case PIXEL_FMT_YVYU:
2183	fmt = 0x38;
2184	break;
2185    case PIXEL_FMT_NV12:
2186	fmt = 0x4c;
2187	break;
2188    case PIXEL_FMT_NV21:
2189	fmt = 0x5c;
2190	break;
2191    case PIXEL_FMT_RGB5:   /* D[5:4] : 00 RGB555, 01 RGB 565 */
2192	fmt = 0x00;
2193	break;
2194    case PIXEL_FMT_RGB6:
2195	fmt = 0x10;
2196	break;
2197    default:
2198	fmt = 0x00;
2199    }
2200    setvideoregmask(pSiS, Index_VI_Control_Misc0, fmt, 0xfc);
2201}
2202
2203/*********************************
2204 *  Set various video registers  *
2205 *********************************/
2206
2207static __inline void
2208set_colorkey(SISPtr pSiS, CARD32 colorkey)
2209{
2210    CARD8 r, g, b;
2211
2212    b = (CARD8)(colorkey & 0xFF);
2213    g = (CARD8)((colorkey >> 8) & 0xFF);
2214    r = (CARD8)((colorkey >> 16) & 0xFF);
2215
2216    setvideoreg(pSiS, Index_VI_Overlay_ColorKey_Blue_Min  ,(CARD8)b);
2217    setvideoreg(pSiS, Index_VI_Overlay_ColorKey_Green_Min ,(CARD8)g);
2218    setvideoreg(pSiS, Index_VI_Overlay_ColorKey_Red_Min   ,(CARD8)r);
2219
2220    setvideoreg(pSiS, Index_VI_Overlay_ColorKey_Blue_Max  ,(CARD8)b);
2221    setvideoreg(pSiS, Index_VI_Overlay_ColorKey_Green_Max ,(CARD8)g);
2222    setvideoreg(pSiS, Index_VI_Overlay_ColorKey_Red_Max   ,(CARD8)r);
2223}
2224
2225static __inline void
2226set_chromakey(SISPtr pSiS, CARD32 chromamin, CARD32 chromamax)
2227{
2228    CARD8 r1, g1, b1;
2229    CARD8 r2, g2, b2;
2230
2231    b1 = (CARD8)(chromamin & 0xFF);
2232    g1 = (CARD8)((chromamin >> 8) & 0xFF);
2233    r1 = (CARD8)((chromamin >> 16) & 0xFF);
2234    b2 = (CARD8)(chromamax & 0xFF);
2235    g2 = (CARD8)((chromamax >> 8) & 0xFF);
2236    r2 = (CARD8)((chromamax >> 16) & 0xFF);
2237
2238    setvideoreg(pSiS, Index_VI_Overlay_ChromaKey_Blue_V_Min  ,(CARD8)b1);
2239    setvideoreg(pSiS, Index_VI_Overlay_ChromaKey_Green_U_Min ,(CARD8)g1);
2240    setvideoreg(pSiS, Index_VI_Overlay_ChromaKey_Red_Y_Min   ,(CARD8)r1);
2241
2242    setvideoreg(pSiS, Index_VI_Overlay_ChromaKey_Blue_V_Max  ,(CARD8)b2);
2243    setvideoreg(pSiS, Index_VI_Overlay_ChromaKey_Green_U_Max ,(CARD8)g2);
2244    setvideoreg(pSiS, Index_VI_Overlay_ChromaKey_Red_Y_Max   ,(CARD8)r2);
2245}
2246
2247static __inline void
2248set_brightness(SISPtr pSiS, CARD8 brightness)
2249{
2250    setvideoreg(pSiS, Index_VI_Brightness, brightness);
2251}
2252
2253static __inline void
2254set_contrast(SISPtr pSiS, CARD8 contrast)
2255{
2256    setvideoregmask(pSiS, Index_VI_Contrast_Enh_Ctrl, contrast, 0x07);
2257}
2258
2259/* 315 series and later only */
2260static __inline void
2261set_saturation(SISPtr pSiS, short saturation)
2262{
2263    CARD8 temp = 0;
2264
2265    if(saturation < 0) {
2266    	temp |= 0x88;
2267	saturation = -saturation;
2268    }
2269    temp |= (saturation & 0x07);
2270    temp |= ((saturation & 0x07) << 4);
2271
2272    setvideoreg(pSiS, Index_VI_Saturation, temp);
2273}
2274
2275/* 315 series and later only */
2276static __inline void
2277set_hue(SISPtr pSiS, CARD8 hue)
2278{
2279    setvideoregmask(pSiS, Index_VI_Hue, (hue & 0x08) ? (hue ^ 0x07) : hue, 0x0F);
2280}
2281
2282static __inline void
2283set_disablegfx(SISPtr pSiS, Bool mybool, SISOverlayPtr pOverlay)
2284{
2285    /* This is not supported on M65x, 65x (x>0) or later */
2286    /* For CRT1 ONLY!!! */
2287    if((!(pSiS->ChipFlags & SiSCF_Is65x)) &&
2288       (pSiS->Chipset != PCI_CHIP_SIS660) &&
2289       (pSiS->Chipset != PCI_CHIP_SIS340) &&
2290       (pSiS->Chipset != PCI_CHIP_XGIXG20) &&
2291       (pSiS->Chipset != PCI_CHIP_XGIXG40)) {
2292       setvideoregmask(pSiS, Index_VI_Control_Misc2, mybool ? 0x04 : 0x00, 0x04);
2293       if(mybool) pOverlay->keyOP = VI_ROP_Always;
2294    }
2295}
2296
2297static __inline void
2298set_disablegfxlr(SISPtr pSiS, Bool mybool, SISOverlayPtr pOverlay)
2299{
2300    setvideoregmask(pSiS, Index_VI_Control_Misc1, mybool ? 0x01 : 0x00, 0x01);
2301    if(mybool) pOverlay->keyOP = VI_ROP_Always;
2302}
2303
2304#ifdef SIS_CP
2305    SIS_CP_VIDEO_SUBS
2306#endif
2307
2308/*********************************
2309 *   Set main overlay registers  *
2310 *********************************/
2311
2312static void
2313set_overlay(SISPtr pSiS, SISOverlayPtr pOverlay, SISPortPrivPtr pPriv, int index, int iscrt2)
2314{
2315    CARD8  h_over, v_over;
2316    CARD16 top, bottom, left, right, pitch = 0;
2317    CARD16 screenX, screenY;
2318    CARD32 PSY;
2319    int    modeflags, totalPixels, confactor, sample, watchdog = 0;
2320
2321#ifdef SISMERGED
2322    if(pSiS->MergedFB && iscrt2) {
2323       screenX = pOverlay->currentmode2->HDisplay;
2324       screenY = pOverlay->currentmode2->VDisplay;
2325       modeflags = pOverlay->currentmode2->Flags;
2326       top = pOverlay->dstBox2.y1;
2327       bottom = pOverlay->dstBox2.y2;
2328       left = pOverlay->dstBox2.x1;
2329       right = pOverlay->dstBox2.x2;
2330       pitch = pOverlay->pitch2 >> pPriv->shiftValue;
2331    } else {
2332#endif
2333       screenX = pOverlay->currentmode->HDisplay;
2334       screenY = pOverlay->currentmode->VDisplay;
2335       modeflags = pOverlay->currentmode->Flags;
2336       top = pOverlay->dstBox.y1;
2337       bottom = pOverlay->dstBox.y2;
2338       left = pOverlay->dstBox.x1;
2339       right = pOverlay->dstBox.x2;
2340       pitch = pOverlay->pitch >> pPriv->shiftValue;
2341#ifdef SISMERGED
2342    }
2343#endif
2344
2345    if(bottom > screenY) bottom = screenY;
2346    if(right  > screenX) right  = screenX;
2347
2348    /* calculate contrast factor */
2349    totalPixels = (right - left) * (bottom - top);
2350    confactor = (totalPixels - 10000) / 20000;
2351    if(confactor > 3) confactor = 3;
2352    switch(confactor) {
2353    case 1:  sample = 4096 << 10; break;
2354    case 2:
2355    case 3:  sample = 8192 << 10; break;
2356    default: sample = 2048 << 10;
2357    }
2358    sample /= totalPixels;
2359    confactor <<= 6;
2360
2361    /* Correct coordinates for doublescan/interlace modes */
2362    if( (modeflags & V_DBLSCAN) &&
2363        (!((pPriv->bridgeIsSlave || iscrt2) && (pSiS->MiscFlags & MISC_STNMODE))) ) {
2364       /* DoubleScan modes require Y coordinates * 2 */
2365       top <<= 1;
2366       bottom <<= 1;
2367    } else if(modeflags & V_INTERLACE) {
2368       /* Interlace modes require Y coordinates / 2 */
2369       top >>= 1;
2370       bottom >>= 1;
2371    }
2372
2373    h_over = (((left >> 8) & 0x0f) | ((right >> 4) & 0xf0));
2374    v_over = (((top >> 8) & 0x0f) | ((bottom >> 4) & 0xf0));
2375
2376    /* set line buffer size */
2377#ifdef SISMERGED
2378    if(pSiS->MergedFB && iscrt2) {
2379       setvideoreg(pSiS, Index_VI_Line_Buffer_Size, (CARD8)pOverlay->lineBufSize2);
2380       if(pPriv->is340 || pPriv->is761 || pPriv->isXGI) {
2381          setvideoreg(pSiS, Index_VI_Line_Buffer_Size_High, (CARD8)(pOverlay->lineBufSize2 >> 8));
2382       }
2383    } else {
2384#endif
2385       setvideoreg(pSiS, Index_VI_Line_Buffer_Size, (CARD8)pOverlay->lineBufSize);
2386       if(pPriv->is340 || pPriv->is761 || pPriv->isXGI) {
2387          setvideoreg(pSiS, Index_VI_Line_Buffer_Size_High, (CARD8)(pOverlay->lineBufSize >> 8));
2388       }
2389#ifdef SISMERGED
2390    }
2391#endif
2392
2393    /* set color key mode */
2394    setvideoregmask(pSiS, Index_VI_Key_Overlay_OP, pOverlay->keyOP, 0x0f);
2395
2396    /* We don't have to wait for vertical retrace in all cases */
2397    if(pPriv->mustwait) {
2398       if(pSiS->VGAEngine == SIS_315_VGA) {
2399
2400          if(index) {
2401	     CARD16 mytop = getvideoreg(pSiS, Index_VI_Win_Ver_Disp_Start_Low);
2402	     mytop |= ((getvideoreg(pSiS, Index_VI_Win_Ver_Over) & 0x0f) << 8);
2403	     pOverlay->oldtop = mytop;
2404	     watchdog = 0xffff;
2405	     if(mytop < screenY - 2) {
2406		do {
2407		   watchdog = get_scanline_CRT2(pSiS, pPriv);
2408		} while((watchdog <= mytop) || (watchdog >= screenY));
2409	     }
2410	     pOverlay->oldLine = watchdog;
2411	  }
2412
2413       } else {
2414
2415	  watchdog = WATCHDOG_DELAY;
2416	  while(pOverlay->VBlankActiveFunc(pSiS, pPriv) && --watchdog);
2417	  watchdog = WATCHDOG_DELAY;
2418	  while((!pOverlay->VBlankActiveFunc(pSiS, pPriv)) && --watchdog);
2419
2420       }
2421    }
2422
2423    /* Unlock address registers */
2424    setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x20, 0x20);
2425
2426    /* Set destination window position */
2427    setvideoreg(pSiS, Index_VI_Win_Hor_Disp_Start_Low, (CARD8)left);
2428    setvideoreg(pSiS, Index_VI_Win_Hor_Disp_End_Low,   (CARD8)right);
2429    setvideoreg(pSiS, Index_VI_Win_Hor_Over,           (CARD8)h_over);
2430
2431    setvideoreg(pSiS, Index_VI_Win_Ver_Disp_Start_Low, (CARD8)top);
2432    setvideoreg(pSiS, Index_VI_Win_Ver_Disp_End_Low,   (CARD8)bottom);
2433    setvideoreg(pSiS, Index_VI_Win_Ver_Over,           (CARD8)v_over);
2434
2435    /* Contrast factor */
2436    setvideoregmask(pSiS, Index_VI_Contrast_Enh_Ctrl,  (CARD8)confactor, 0xc0);
2437    setvideoreg(pSiS, Index_VI_Contrast_Factor,        sample);
2438
2439    /* Set Y buf pitch */
2440    setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Pitch_Low, (CARD8)(pitch));
2441    setvideoregmask(pSiS, Index_VI_Disp_Y_UV_Buf_Pitch_Middle, (CARD8)(pitch >> 8), 0x0f);
2442
2443    /* Set Y start address */
2444#ifdef SISMERGED
2445    if(pSiS->MergedFB && iscrt2) {
2446       PSY = pOverlay->PSY2;
2447    } else
2448#endif
2449       PSY = pOverlay->PSY;
2450
2451    setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Start_Low,    (CARD8)(PSY));
2452    setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Start_Middle, (CARD8)(PSY >> 8));
2453    setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Start_High,   (CARD8)(PSY >> 16));
2454
2455    /* Set 315 series overflow bits for Y plane */
2456    if(pSiS->VGAEngine == SIS_315_VGA) {
2457       setvideoreg(pSiS, Index_VI_Disp_Y_Buf_Pitch_High, (CARD8)(pitch >> 12));
2458       setvideoreg(pSiS, Index_VI_Y_Buf_Start_Over, ((CARD8)(PSY >> 24) & 0x03));
2459    }
2460
2461    /* Set U/V data if using planar formats */
2462    if(pOverlay->planar) {
2463
2464	CARD32  PSU = pOverlay->PSU;
2465	CARD32  PSV = pOverlay->PSV;
2466
2467#ifdef SISMERGED
2468	if(pSiS->MergedFB && iscrt2) {
2469	   PSU = pOverlay->PSU2;
2470	   PSV = pOverlay->PSV2;
2471	}
2472#endif
2473
2474	if(pOverlay->planar_shiftpitch) pitch >>= 1;
2475
2476	/* Set U/V pitch */
2477	setvideoreg(pSiS, Index_VI_Disp_UV_Buf_Pitch_Low, (CARD8)pitch);
2478	setvideoregmask(pSiS, Index_VI_Disp_Y_UV_Buf_Pitch_Middle, (CARD8)(pitch >> 4), 0xf0);
2479
2480	/* Set U/V start address */
2481	setvideoreg(pSiS, Index_VI_U_Buf_Start_Low,   (CARD8)PSU);
2482	setvideoreg(pSiS, Index_VI_U_Buf_Start_Middle,(CARD8)(PSU >> 8));
2483	setvideoreg(pSiS, Index_VI_U_Buf_Start_High,  (CARD8)(PSU >> 16));
2484
2485	setvideoreg(pSiS, Index_VI_V_Buf_Start_Low,   (CARD8)PSV);
2486	setvideoreg(pSiS, Index_VI_V_Buf_Start_Middle,(CARD8)(PSV >> 8));
2487	setvideoreg(pSiS, Index_VI_V_Buf_Start_High,  (CARD8)(PSV >> 16));
2488
2489	/* 315 series overflow bits */
2490	if(pSiS->VGAEngine == SIS_315_VGA) {
2491	   setvideoreg(pSiS, Index_VI_Disp_UV_Buf_Pitch_High, (CARD8)(pitch >> 12));
2492	   setvideoreg(pSiS, Index_VI_U_Buf_Start_Over, ((CARD8)(PSU >> 24) & 0x03));
2493	   if(pPriv->is661741760) {
2494	      setvideoregmask(pSiS, Index_VI_V_Buf_Start_Over, ((CARD8)(PSV >> 24) & 0x03), 0xc3);
2495	   } else {
2496	      setvideoreg(pSiS, Index_VI_V_Buf_Start_Over, ((CARD8)(PSV >> 24) & 0x03));
2497	   }
2498	}
2499    }
2500
2501    setvideoregmask(pSiS, Index_VI_Control_Misc1, pOverlay->bobEnable, 0x1a);
2502
2503    /* Lock the address registers */
2504    setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x20);
2505
2506    /* Set scale factor */
2507#ifdef SISMERGED
2508    if(pSiS->MergedFB && iscrt2) {
2509       setvideoreg(pSiS, Index_VI_Hor_Post_Up_Scale_Low, (CARD8)(pOverlay->HUSF2));
2510       setvideoreg(pSiS, Index_VI_Hor_Post_Up_Scale_High,(CARD8)((pOverlay->HUSF2) >> 8));
2511       setvideoreg(pSiS, Index_VI_Ver_Up_Scale_Low,      (CARD8)(pOverlay->VUSF2));
2512       setvideoreg(pSiS, Index_VI_Ver_Up_Scale_High,     (CARD8)((pOverlay->VUSF2) >> 8));
2513
2514       setvideoregmask(pSiS, Index_VI_Scale_Control,     (pOverlay->IntBit2 << 3) |
2515                                                         (pOverlay->wHPre2), 0x7f);
2516
2517       if(pPriv->havetapscaler) {
2518	  if((pOverlay->tap_scale2 != pOverlay->tap_scale2_old) || pPriv->mustresettap2) {
2519	     set_dda_regs(pSiS, pOverlay->tap_scale2);
2520	     pOverlay->tap_scale2_old = pOverlay->tap_scale2;
2521	     pPriv->mustresettap2 = FALSE;
2522	  }
2523       }
2524    } else {
2525#endif
2526       setvideoreg(pSiS, Index_VI_Hor_Post_Up_Scale_Low, (CARD8)(pOverlay->HUSF));
2527       setvideoreg(pSiS, Index_VI_Hor_Post_Up_Scale_High,(CARD8)((pOverlay->HUSF) >> 8));
2528       setvideoreg(pSiS, Index_VI_Ver_Up_Scale_Low,      (CARD8)(pOverlay->VUSF));
2529       setvideoreg(pSiS, Index_VI_Ver_Up_Scale_High,     (CARD8)((pOverlay->VUSF) >> 8));
2530
2531       setvideoregmask(pSiS, Index_VI_Scale_Control,     (pOverlay->IntBit << 3) |
2532                                                         (pOverlay->wHPre), 0x7f);
2533       if(pPriv->havetapscaler) {
2534	  if((pOverlay->tap_scale != pOverlay->tap_scale_old) || pPriv->mustresettap) {
2535	     set_dda_regs(pSiS, pOverlay->tap_scale);
2536	     pOverlay->tap_scale_old = pOverlay->tap_scale;
2537	     pPriv->mustresettap = FALSE;
2538	  }
2539       }
2540#ifdef SISMERGED
2541    }
2542#endif
2543
2544}
2545
2546/*********************************
2547 *       Shut down overlay       *
2548 *********************************/
2549
2550/* Overlay MUST NOT be switched off while beam is over it */
2551static void
2552close_overlay(SISPtr pSiS, SISPortPrivPtr pPriv)
2553{
2554  int watchdog;
2555
2556  if(!pPriv->overlayStatus) return;
2557
2558  pPriv->overlayStatus = FALSE;
2559
2560  pPriv->mustresettap = TRUE;
2561#ifdef SISMERGED
2562  pPriv->mustresettap2 = TRUE;
2563#endif
2564
2565  if(pPriv->displayMode & (DISPMODE_MIRROR | DISPMODE_SINGLE2)) {
2566
2567     /* CRT2: MIRROR or SINGLE2
2568      * 1 overlay:  Uses overlay 0
2569      * 2 overlays: Uses Overlay 1 if MIRROR or DUAL HEAD
2570      *             Uses Overlay 0 if SINGLE2 and not DUAL HEAD
2571      */
2572
2573     if(pPriv->hasTwoOverlays) {
2574
2575	if((pPriv->dualHeadMode) || (pPriv->displayMode == DISPMODE_MIRROR)) {
2576	   setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x01, 0x01);
2577	} else {
2578	   setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, 0x01);
2579	}
2580
2581     } else if(pPriv->displayMode == DISPMODE_SINGLE2) {
2582
2583#ifdef SISDUALHEAD
2584	if(pPriv->dualHeadMode) {
2585	   /* Check if overlay already grabbed by other head */
2586	   if(!(getsrreg(pSiS, 0x06) & 0x40)) return;
2587	}
2588#endif
2589	setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, 0x01);
2590
2591     }
2592
2593     setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x01);
2594
2595     watchdog = WATCHDOG_DELAY;
2596     while((!vblank_active_CRT2(pSiS, pPriv)) && --watchdog);
2597     watchdog = WATCHDOG_DELAY;
2598     while(vblank_active_CRT2(pSiS, pPriv) && --watchdog);
2599     setvideoregmask(pSiS, Index_VI_Control_Misc0, 0x00, 0x02);
2600     watchdog = WATCHDOG_DELAY;
2601     while((!vblank_active_CRT2(pSiS, pPriv)) && --watchdog);
2602     watchdog = WATCHDOG_DELAY;
2603     while(vblank_active_CRT2(pSiS, pPriv) && --watchdog);
2604
2605#ifdef SIS_CP
2606     SIS_CP_RESET_CP
2607#endif
2608
2609  }
2610
2611  if(pPriv->displayMode & (DISPMODE_SINGLE1 | DISPMODE_MIRROR)) {
2612
2613     /* CRT1: Always uses overlay 0
2614      */
2615
2616#ifdef SISDUALHEAD
2617     if(pPriv->dualHeadMode) {
2618	if(!pPriv->hasTwoOverlays) {
2619	   /* Check if overlay already grabbed by other head */
2620	   if(getsrreg(pSiS, 0x06) & 0x40) return;
2621	}
2622     }
2623#endif
2624
2625     setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, 0x05);
2626     setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x01);
2627
2628     watchdog = WATCHDOG_DELAY;
2629     while((!vblank_active_CRT1(pSiS, pPriv)) && --watchdog);
2630     watchdog = WATCHDOG_DELAY;
2631     while(vblank_active_CRT1(pSiS, pPriv) && --watchdog);
2632     setvideoregmask(pSiS, Index_VI_Control_Misc0, 0x00, 0x02);
2633     watchdog = WATCHDOG_DELAY;
2634     while((!vblank_active_CRT1(pSiS, pPriv)) && --watchdog);
2635     watchdog = WATCHDOG_DELAY;
2636     while(vblank_active_CRT1(pSiS, pPriv) && --watchdog);
2637
2638  }
2639}
2640
2641/*********************************
2642 *         DisplayVideo()        *
2643 *********************************/
2644
2645static void
2646SISDisplayVideo(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
2647{
2648   SISPtr pSiS = SISPTR(pScrn);
2649#ifdef SISDUALHEAD
2650   SISEntPtr pSiSEnt = pSiS->entityPrivate;
2651#endif
2652   short  srcPitch = pPriv->srcPitch;
2653   short  height = pPriv->height;
2654   UShort screenwidth;
2655   SISOverlayRec overlay;
2656   int    srcOffsetX = 0, srcOffsetY = 0;
2657   int    sx = 0, sy = 0, watchdog;
2658   int    index = 0, iscrt2 = 0;
2659#ifdef SISMERGED
2660   UChar  temp;
2661   UShort screen2width = 0;
2662   int    srcOffsetX2 = 0, srcOffsetY2 = 0;
2663   int    sx2 = 0, sy2 = 0;
2664#endif
2665
2666   /* Determine whether we have two overlays or only one */
2667   set_hastwooverlays(pSiS, pPriv);
2668
2669   pPriv->NoOverlay = FALSE;
2670#ifdef SISDUALHEAD
2671   if(pPriv->dualHeadMode) {
2672      if(!pPriv->hasTwoOverlays) {
2673	 if(pSiS->SecondHead) {
2674	    if(pSiSEnt->curxvcrtnum != 0) {
2675	       if(pPriv->overlayStatus) {
2676		  close_overlay(pSiS, pPriv);
2677	       }
2678	       pPriv->NoOverlay = TRUE;
2679	       return;
2680	    }
2681	 } else {
2682	    if(pSiSEnt->curxvcrtnum != 1) {
2683	       if(pPriv->overlayStatus) {
2684		  close_overlay(pSiS, pPriv);
2685	       }
2686	       pPriv->NoOverlay = TRUE;
2687	       return;
2688	    }
2689	 }
2690      }
2691   }
2692#endif
2693
2694   /* setup dispmode (MIRROR, SINGLEx) */
2695   set_dispmode(pScrn, pPriv);
2696
2697   /* Check if overlay is supported with current mode */
2698#ifdef SISMERGED
2699   if(!pSiS->MergedFB) {
2700#endif
2701      if( ((pPriv->displayMode & DISPMODE_MIRROR) &&
2702           ((pSiS->MiscFlags & (MISC_CRT1OVERLAY|MISC_CRT2OVERLAY)) != (MISC_CRT1OVERLAY|MISC_CRT2OVERLAY))) ||
2703	  ((pPriv->displayMode & DISPMODE_SINGLE1) &&
2704	   (!(pSiS->MiscFlags & MISC_CRT1OVERLAY))) ||
2705	  ((pPriv->displayMode & DISPMODE_SINGLE2) &&
2706	   (!(pSiS->MiscFlags & MISC_CRT2OVERLAY))) ) {
2707	 if(pPriv->overlayStatus) {
2708	    close_overlay(pSiS, pPriv);
2709	 }
2710	 pPriv->NoOverlay = TRUE;
2711	 return;
2712      }
2713#ifdef SISMERGED
2714   }
2715#endif
2716
2717   memset(&overlay, 0, sizeof(overlay));
2718
2719   overlay.pixelFormat = pPriv->id;
2720   overlay.pitch = overlay.origPitch = srcPitch;
2721   if(pPriv->usechromakey) {
2722      overlay.keyOP = (pPriv->insidechromakey) ? VI_ROP_ChromaKey : VI_ROP_NotChromaKey;
2723   } else {
2724      overlay.keyOP = VI_ROP_DestKey;
2725   }
2726
2727#ifdef SISDEINT
2728   switch(pPriv->deinterlacemethod) {
2729   case 1:
2730      overlay.bobEnable = 0x02;
2731      /* overlay.bobEnable |= (pPriv->currentBuf) ? 0x00 : 0x10; */
2732      break;
2733   case 2:
2734      overlay.bobEnable = 0x08;
2735      /* overlay.bobEnable |= (pPriv->currentBuf) ? 0x00 : 0x10; */
2736      break;
2737   case 3:
2738      overlay.bobEnable = 0x0a;
2739      /* overlay.bobEnable |= (pPriv->currentBuf) ? 0x00 : 0x10; */
2740      break;
2741   default:
2742#endif
2743      overlay.bobEnable = 0x00;    /* Disable BOB de-interlacer */
2744#ifdef SISDEINT
2745   }
2746#endif
2747
2748#ifdef SISMERGED
2749   if(pSiS->MergedFB) {
2750      overlay.DoFirst = TRUE;
2751      overlay.DoSecond = TRUE;
2752      overlay.pitch2 = overlay.origPitch;
2753      overlay.currentmode = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT1;
2754      overlay.currentmode2 = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2;
2755      overlay.SCREENheight  = overlay.currentmode->VDisplay;
2756      overlay.SCREENheight2 = overlay.currentmode2->VDisplay;
2757      screenwidth = overlay.currentmode->HDisplay;
2758      screen2width = overlay.currentmode2->HDisplay;
2759      overlay.dstBox.x1  = pPriv->drw_x - pSiS->CRT1frameX0;
2760      overlay.dstBox.x2  = overlay.dstBox.x1 + pPriv->drw_w;
2761      overlay.dstBox.y1  = pPriv->drw_y - pSiS->CRT1frameY0;
2762      overlay.dstBox.y2  = overlay.dstBox.y1 + pPriv->drw_h;
2763      overlay.dstBox2.x1 = pPriv->drw_x - pSiS->CRT2pScrn->frameX0;
2764      overlay.dstBox2.x2 = overlay.dstBox2.x1 + pPriv->drw_w;
2765      overlay.dstBox2.y1 = pPriv->drw_y - pSiS->CRT2pScrn->frameY0;
2766      overlay.dstBox2.y2 = overlay.dstBox2.y1 + pPriv->drw_h;
2767   } else {
2768#endif
2769      overlay.currentmode = pSiS->CurrentLayout.mode;
2770      overlay.SCREENheight = overlay.currentmode->VDisplay;
2771      screenwidth = overlay.currentmode->HDisplay;
2772      overlay.dstBox.x1 = pPriv->drw_x - pScrn->frameX0;
2773      overlay.dstBox.x2 = pPriv->drw_x + pPriv->drw_w - pScrn->frameX0;
2774      overlay.dstBox.y1 = pPriv->drw_y - pScrn->frameY0;
2775      overlay.dstBox.y2 = pPriv->drw_y + pPriv->drw_h - pScrn->frameY0;
2776#ifdef SISMERGED
2777   }
2778#endif
2779
2780   /* Note: x2/y2 is actually real coordinate + 1 */
2781
2782   if((overlay.dstBox.x1 >= overlay.dstBox.x2) ||
2783      (overlay.dstBox.y1 >= overlay.dstBox.y2)) {
2784#ifdef SISMERGED
2785      if(pSiS->MergedFB) overlay.DoFirst = FALSE;
2786      else
2787#endif
2788           return;
2789   }
2790
2791   if((overlay.dstBox.x2 <= 0) || (overlay.dstBox.y2 <= 0)) {
2792#ifdef SISMERGED
2793      if(pSiS->MergedFB) overlay.DoFirst = FALSE;
2794      else
2795#endif
2796           return;
2797   }
2798
2799   if((overlay.dstBox.x1 >= screenwidth) || (overlay.dstBox.y1 >= overlay.SCREENheight)) {
2800#ifdef SISMERGED
2801      if(pSiS->MergedFB) overlay.DoFirst = FALSE;
2802      else
2803#endif
2804           return;
2805   }
2806
2807#ifdef SISMERGED
2808   if(pSiS->MergedFB) {
2809      /* Check if dotclock is within limits for CRT1 */
2810      if(pPriv->displayMode & (DISPMODE_SINGLE1 | DISPMODE_MIRROR)) {
2811         if(!(pSiS->MiscFlags & MISC_CRT1OVERLAY)) {
2812            overlay.DoFirst = FALSE;
2813         }
2814      }
2815   }
2816#endif
2817
2818   if(overlay.dstBox.x1 < 0) {
2819      srcOffsetX = pPriv->src_w * (-overlay.dstBox.x1) / pPriv->drw_w;
2820      overlay.dstBox.x1 = 0;
2821   }
2822   if(overlay.dstBox.y1 < 0) {
2823      srcOffsetY = pPriv->src_h * (-overlay.dstBox.y1) / pPriv->drw_h;
2824      overlay.dstBox.y1 = 0;
2825   }
2826
2827   if((overlay.dstBox.x1 >= overlay.dstBox.x2 - 2) ||
2828      (overlay.dstBox.x1 >= screenwidth - 2)       ||
2829      (overlay.dstBox.y1 >= overlay.dstBox.y2)) {
2830#ifdef SISMERGED
2831      if(pSiS->MergedFB) overlay.DoFirst = FALSE;
2832      else
2833#endif
2834           return;
2835   }
2836
2837#ifdef SISMERGED
2838   if(pSiS->MergedFB) {
2839      if((overlay.dstBox2.x2 <= 0) || (overlay.dstBox2.y2 <= 0))
2840	 overlay.DoSecond = FALSE;
2841
2842      if((overlay.dstBox2.x1 >= screen2width) || (overlay.dstBox2.y1 >= overlay.SCREENheight2))
2843	 overlay.DoSecond = FALSE;
2844
2845      if(overlay.dstBox2.x1 < 0) {
2846	 srcOffsetX2 = pPriv->src_w * (-overlay.dstBox2.x1) / pPriv->drw_w;
2847	 overlay.dstBox2.x1 = 0;
2848      }
2849
2850      if(overlay.dstBox2.y1 < 0) {
2851	 srcOffsetY2 = pPriv->src_h * (-overlay.dstBox2.y1) / pPriv->drw_h;
2852	 overlay.dstBox2.y1 = 0;
2853      }
2854
2855      if((overlay.dstBox2.x1 >= overlay.dstBox2.x2 - 2) ||
2856	 (overlay.dstBox2.x1 >= screen2width - 2)       ||
2857	 (overlay.dstBox2.y1 >= overlay.dstBox2.y2))
2858	 overlay.DoSecond = FALSE;
2859
2860      /* Check if dotclock is within limits for CRT2 */
2861      if(pPriv->displayMode & (DISPMODE_SINGLE2 | DISPMODE_MIRROR)) {
2862	 if(!(pSiS->MiscFlags & MISC_CRT2OVERLAY)) {
2863	    overlay.DoSecond = FALSE;
2864	 }
2865      }
2866
2867      /* If neither overlay is to be displayed, disable them if they are currently enabled */
2868      if((!overlay.DoFirst) && (!overlay.DoSecond)) {
2869	 setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, 0x05);
2870	 setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x01);
2871	 temp = getvideoreg(pSiS,Index_VI_Control_Misc0);
2872	 if(temp & 0x02) {
2873	    watchdog = WATCHDOG_DELAY;
2874	    if(pPriv->hasTwoOverlays) {
2875	       while((!vblank_active_CRT1(pSiS, pPriv)) && --watchdog);
2876	       watchdog = WATCHDOG_DELAY;
2877	       while(vblank_active_CRT1(pSiS, pPriv) && --watchdog);
2878	    } else {
2879	       temp = getsrreg(pSiS, 0x06);
2880	       if(!(temp & 0x40)) {
2881		  while((!vblank_active_CRT1(pSiS, pPriv)) && --watchdog);
2882		  watchdog = WATCHDOG_DELAY;
2883		  while(vblank_active_CRT1(pSiS, pPriv) && --watchdog);
2884	       } else {
2885		  while((!vblank_active_CRT2(pSiS, pPriv)) && --watchdog);
2886		  watchdog = WATCHDOG_DELAY;
2887		  while(vblank_active_CRT2(pSiS, pPriv) && --watchdog);
2888	       }
2889	    }
2890	    setvideoregmask(pSiS, Index_VI_Control_Misc0, 0x00, 0x02);
2891	 }
2892	 if(pPriv->hasTwoOverlays) {
2893	    setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x01, 0x01);
2894	    setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x01);
2895	    temp = getvideoreg(pSiS,Index_VI_Control_Misc0);
2896	    if(temp & 0x02) {
2897	       watchdog = WATCHDOG_DELAY;
2898	       while((!vblank_active_CRT2(pSiS, pPriv)) && --watchdog);
2899	       watchdog = WATCHDOG_DELAY;
2900	       while(vblank_active_CRT2(pSiS, pPriv) && --watchdog);
2901	       setvideoregmask(pSiS, Index_VI_Control_Misc0, 0x00, 0x02);
2902	    }
2903	 }
2904	 pPriv->overlayStatus = FALSE;
2905         return;
2906      }
2907   }
2908#endif
2909
2910   switch(pPriv->id) {
2911
2912     case PIXEL_FMT_YV12:
2913       overlay.planar = 1;
2914       overlay.planar_shiftpitch = 1;
2915#ifdef SISMERGED
2916       if((!pSiS->MergedFB) || (overlay.DoFirst)) {
2917#endif
2918          sx = (pPriv->src_x + srcOffsetX) & ~7;
2919          sy = (pPriv->src_y + srcOffsetY) & ~1;
2920          overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy*srcPitch;
2921          overlay.PSV = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx + sy*srcPitch/2) >> 1);
2922          overlay.PSU = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch*5/4 + ((sx + sy*srcPitch/2) >> 1);
2923          overlay.PSY += FBOFFSET;
2924          overlay.PSV += FBOFFSET;
2925          overlay.PSU += FBOFFSET;
2926          overlay.PSY >>= pPriv->shiftValue;
2927          overlay.PSV >>= pPriv->shiftValue;
2928          overlay.PSU >>= pPriv->shiftValue;
2929#ifdef SISMERGED
2930       }
2931       if((pSiS->MergedFB) && (overlay.DoSecond)) {
2932          sx2 = (pPriv->src_x + srcOffsetX2) & ~7;
2933          sy2 = (pPriv->src_y + srcOffsetY2) & ~1;
2934          overlay.PSY2 = pPriv->bufAddr[pPriv->currentBuf] + sx2 + sy2*srcPitch;
2935          overlay.PSV2 = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx2 + sy2*srcPitch/2) >> 1);
2936          overlay.PSU2 = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch*5/4 + ((sx2 + sy2*srcPitch/2) >> 1);
2937          overlay.PSY2 += FBOFFSET;
2938          overlay.PSV2 += FBOFFSET;
2939          overlay.PSU2 += FBOFFSET;
2940          overlay.PSY2 >>= pPriv->shiftValue;
2941          overlay.PSV2 >>= pPriv->shiftValue;
2942          overlay.PSU2 >>= pPriv->shiftValue;
2943       }
2944#endif
2945       break;
2946
2947     case PIXEL_FMT_I420:
2948       overlay.planar = 1;
2949       overlay.planar_shiftpitch = 1;
2950#ifdef SISMERGED
2951       if((!pSiS->MergedFB) || (overlay.DoFirst)) {
2952#endif
2953          sx = (pPriv->src_x + srcOffsetX) & ~7;
2954          sy = (pPriv->src_y + srcOffsetY) & ~1;
2955          overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy*srcPitch;
2956          overlay.PSV = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch*5/4 + ((sx + sy*srcPitch/2) >> 1);
2957          overlay.PSU = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx + sy*srcPitch/2) >> 1);
2958          overlay.PSY += FBOFFSET;
2959          overlay.PSV += FBOFFSET;
2960          overlay.PSU += FBOFFSET;
2961          overlay.PSY >>= pPriv->shiftValue;
2962          overlay.PSV >>= pPriv->shiftValue;
2963          overlay.PSU >>= pPriv->shiftValue;
2964#ifdef SISMERGED
2965       }
2966       if((pSiS->MergedFB) && (overlay.DoSecond)) {
2967          sx2 = (pPriv->src_x + srcOffsetX2) & ~7;
2968          sy2 = (pPriv->src_y + srcOffsetY2) & ~1;
2969          overlay.PSY2 = pPriv->bufAddr[pPriv->currentBuf] + sx2 + sy2*srcPitch;
2970          overlay.PSV2 = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch*5/4 + ((sx2 + sy2*srcPitch/2) >> 1);
2971          overlay.PSU2 = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx2 + sy2*srcPitch/2) >> 1);
2972          overlay.PSY2 += FBOFFSET;
2973          overlay.PSV2 += FBOFFSET;
2974          overlay.PSU2 += FBOFFSET;
2975          overlay.PSY2 >>= pPriv->shiftValue;
2976          overlay.PSV2 >>= pPriv->shiftValue;
2977          overlay.PSU2 >>= pPriv->shiftValue;
2978       }
2979#endif
2980       break;
2981
2982     case PIXEL_FMT_NV12:
2983     case PIXEL_FMT_NV21:
2984       overlay.planar = 1;
2985       overlay.planar_shiftpitch = 0;
2986#ifdef SISMERGED
2987       if((!pSiS->MergedFB) || (overlay.DoFirst)) {
2988#endif
2989          sx = (pPriv->src_x + srcOffsetX) & ~7;
2990          sy = (pPriv->src_y + srcOffsetY) & ~1;
2991          overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy*srcPitch;
2992          overlay.PSV =	pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx + sy*srcPitch/2) >> 1);
2993          overlay.PSY += FBOFFSET;
2994          overlay.PSV += FBOFFSET;
2995          overlay.PSY >>= pPriv->shiftValue;
2996          overlay.PSV >>= pPriv->shiftValue;
2997          overlay.PSU = overlay.PSV;
2998#ifdef SISMERGED
2999       }
3000       if((pSiS->MergedFB) && (overlay.DoSecond)) {
3001          sx2 = (pPriv->src_x + srcOffsetX2) & ~7;
3002          sy2 = (pPriv->src_y + srcOffsetY2) & ~1;
3003          overlay.PSY2 = pPriv->bufAddr[pPriv->currentBuf] + sx2 + sy2*srcPitch;
3004          overlay.PSV2 = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx2 + sy2*srcPitch/2) >> 1);
3005          overlay.PSY2 += FBOFFSET;
3006          overlay.PSV2 += FBOFFSET;
3007          overlay.PSY2 >>= pPriv->shiftValue;
3008          overlay.PSV2 >>= pPriv->shiftValue;
3009          overlay.PSU2 = overlay.PSV2;
3010       }
3011#endif
3012       break;
3013
3014     case PIXEL_FMT_YUY2:
3015     case PIXEL_FMT_UYVY:
3016     case PIXEL_FMT_YVYU:
3017     case PIXEL_FMT_RGB6:
3018     case PIXEL_FMT_RGB5:
3019     default:
3020       overlay.planar = 0;
3021#ifdef SISMERGED
3022       if((!pSiS->MergedFB) || (overlay.DoFirst)) {
3023#endif
3024          sx = (pPriv->src_x + srcOffsetX) & ~1;
3025          sy = (pPriv->src_y + srcOffsetY);
3026          overlay.PSY = (pPriv->bufAddr[pPriv->currentBuf] + sx*2 + sy*srcPitch);
3027          overlay.PSY += FBOFFSET;
3028          overlay.PSY >>= pPriv->shiftValue;
3029#ifdef SISMERGED
3030       }
3031       if((pSiS->MergedFB) && (overlay.DoSecond)) {
3032          sx2 = (pPriv->src_x + srcOffsetX2) & ~1;
3033          sy2 = (pPriv->src_y + srcOffsetY2);
3034          overlay.PSY2 = (pPriv->bufAddr[pPriv->currentBuf] + sx2*2 + sy2*srcPitch);
3035          overlay.PSY2 += FBOFFSET;
3036          overlay.PSY2 >>= pPriv->shiftValue;
3037       }
3038#endif
3039       break;
3040   }
3041
3042   /* Some clipping checks */
3043#ifdef SISMERGED
3044   if((!pSiS->MergedFB) || (overlay.DoFirst)) {
3045#endif
3046      overlay.srcW = pPriv->src_w - (sx - pPriv->src_x);
3047      overlay.srcH = pPriv->src_h - (sy - pPriv->src_y);
3048      if( (pPriv->oldx1 != overlay.dstBox.x1) ||
3049	  (pPriv->oldx2 != overlay.dstBox.x2) ||
3050	  (pPriv->oldy1 != overlay.dstBox.y1) ||
3051	  (pPriv->oldy2 != overlay.dstBox.y2) ) {
3052	 pPriv->mustwait = 1;
3053	 pPriv->oldx1 = overlay.dstBox.x1; pPriv->oldx2 = overlay.dstBox.x2;
3054	 pPriv->oldy1 = overlay.dstBox.y1; pPriv->oldy2 = overlay.dstBox.y2;
3055      }
3056#ifdef SISMERGED
3057   }
3058   if((pSiS->MergedFB) && (overlay.DoSecond)) {
3059      overlay.srcW2 = pPriv->src_w - (sx2 - pPriv->src_x);
3060      overlay.srcH2 = pPriv->src_h - (sy2 - pPriv->src_y);
3061      if( (pPriv->oldx1_2 != overlay.dstBox2.x1) ||
3062	  (pPriv->oldx2_2 != overlay.dstBox2.x2) ||
3063	  (pPriv->oldy1_2 != overlay.dstBox2.y1) ||
3064	  (pPriv->oldy2_2 != overlay.dstBox2.y2) ) {
3065	 pPriv->mustwait = 1;
3066	 pPriv->oldx1_2 = overlay.dstBox2.x1; pPriv->oldx2_2 = overlay.dstBox2.x2;
3067	 pPriv->oldy1_2 = overlay.dstBox2.y1; pPriv->oldy2_2 = overlay.dstBox2.y2;
3068      }
3069   }
3070#endif
3071
3072#ifdef SISMERGED
3073   /* Disable an overlay if it is not to be displayed (but enabled currently) */
3074   if((pSiS->MergedFB) && (pPriv->hasTwoOverlays)) {
3075      if(!overlay.DoFirst) {
3076	 setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x00, 0x05);
3077	 setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x01);
3078	 temp = getvideoreg(pSiS,Index_VI_Control_Misc0);
3079	 if(temp & 0x02) {
3080	    watchdog = WATCHDOG_DELAY;
3081	    while((!vblank_active_CRT1(pSiS, pPriv)) && --watchdog);
3082	    watchdog = WATCHDOG_DELAY;
3083	    while(vblank_active_CRT1(pSiS, pPriv) && --watchdog);
3084	    setvideoregmask(pSiS, Index_VI_Control_Misc0, 0x00, 0x02);
3085	 }
3086      } else if(!overlay.DoSecond) {
3087	 setvideoregmask(pSiS, Index_VI_Control_Misc2, 0x01, 0x01);
3088	 setvideoregmask(pSiS, Index_VI_Control_Misc1, 0x00, 0x01);
3089	 temp = getvideoreg(pSiS,Index_VI_Control_Misc0);
3090	 if(temp & 0x02) {
3091	    watchdog = WATCHDOG_DELAY;
3092	    while((!vblank_active_CRT2(pSiS, pPriv)) && --watchdog);
3093	    watchdog = WATCHDOG_DELAY;
3094	    while(vblank_active_CRT2(pSiS, pPriv) && --watchdog);
3095	    setvideoregmask(pSiS, Index_VI_Control_Misc0, 0x00, 0x02);
3096	 }
3097      }
3098   }
3099#endif
3100
3101   /* Loop head */
3102   /* Note: index can only be 1 for CRT2, ie overlay 1
3103    * is only used for CRT2.
3104    */
3105   if(pPriv->displayMode & DISPMODE_SINGLE2) {
3106      if(pPriv->hasTwoOverlays) {			/* We have 2 overlays: */
3107	 if(pPriv->dualHeadMode) {
3108	    /* Dual head: We use overlay 2 for CRT2 */
3109	    index = 1; iscrt2 = 1;
3110	 } else {
3111	    /* Single head: We use overlay 1 for CRT2 */
3112	    index = 0; iscrt2 = 1;
3113	 }
3114      } else {						/* We have 1 overlay */
3115	 /* We use that only overlay for CRT2 */
3116	 index = 0; iscrt2 = 1;
3117      }
3118      overlay.VBlankActiveFunc = vblank_active_CRT2;
3119#ifdef SISMERGED
3120      if(!pPriv->hasTwoOverlays) {
3121	 if((pSiS->MergedFB) && (!overlay.DoSecond)) {
3122	    index = 0; iscrt2 = 0;
3123	    overlay.VBlankActiveFunc = vblank_active_CRT1;
3124	    pPriv->displayMode = DISPMODE_SINGLE1;
3125	 }
3126      }
3127#endif
3128   } else {
3129      index = 0; iscrt2 = 0;
3130      overlay.VBlankActiveFunc = vblank_active_CRT1;
3131#ifdef SISMERGED
3132      if((pSiS->MergedFB) && (!overlay.DoFirst)) {
3133	 if(pPriv->hasTwoOverlays) index = 1;
3134	 iscrt2 = 1;
3135	 overlay.VBlankActiveFunc = vblank_active_CRT2;
3136	 if(!pPriv->hasTwoOverlays) {
3137	    pPriv->displayMode = DISPMODE_SINGLE2;
3138	 }
3139      }
3140#endif
3141   }
3142
3143   /* set display mode SR06,32 (CRT1, CRT2 or mirror) */
3144   set_disptype_regs(pScrn, pPriv);
3145
3146   /* set (not only calc) merge line buffer */
3147#ifdef SISMERGED
3148   if(!pSiS->MergedFB) {
3149#endif
3150      merge_line_buf(pSiS, pPriv, (overlay.srcW > pPriv->linebufMergeLimit), overlay.srcW,
3151      		     pPriv->linebufMergeLimit);
3152#ifdef SISMERGED
3153   } else {
3154      Bool temp1 = FALSE, temp2 = FALSE;
3155      if(overlay.DoFirst) {
3156         if(overlay.srcW > pPriv->linebufMergeLimit)  temp1 = TRUE;
3157      }
3158      if(overlay.DoSecond) {
3159         if(overlay.srcW2 > pPriv->linebufMergeLimit) temp2 = TRUE;
3160      }
3161      merge_line_buf_mfb(pSiS, pPriv, temp1, temp2, overlay.srcW, overlay.srcW2,
3162			 pPriv->linebufMergeLimit);
3163   }
3164#endif
3165
3166   /* calculate (not set!) line buffer length */
3167#ifdef SISMERGED
3168   if((!pSiS->MergedFB) || (overlay.DoFirst))
3169#endif
3170      calc_line_buf_size_1(&overlay, pPriv);
3171#ifdef SISMERGED
3172   if((pSiS->MergedFB) && (overlay.DoSecond))
3173      calc_line_buf_size_2(&overlay, pPriv);
3174#endif
3175
3176   if(pPriv->dualHeadMode) {
3177#ifdef SISDUALHEAD
3178      if(!pSiS->SecondHead) {
3179         if(pPriv->updatetvxpos) {
3180            SiS_SetTVxposoffset(pScrn, pPriv->tvxpos);
3181            pPriv->updatetvxpos = FALSE;
3182         }
3183         if(pPriv->updatetvypos) {
3184            SiS_SetTVyposoffset(pScrn, pPriv->tvypos);
3185            pPriv->updatetvypos = FALSE;
3186         }
3187      }
3188#endif
3189   } else {
3190      if(pPriv->updatetvxpos) {
3191         SiS_SetTVxposoffset(pScrn, pPriv->tvxpos);
3192         pPriv->updatetvxpos = FALSE;
3193      }
3194      if(pPriv->updatetvypos) {
3195         SiS_SetTVyposoffset(pScrn, pPriv->tvypos);
3196         pPriv->updatetvypos = FALSE;
3197      }
3198   }
3199
3200#if 0 /* Clearing this does not seem to be required */
3201      /* and might even be dangerous. */
3202   if(pSiS->VGAEngine == SIS_315_VGA) {
3203      watchdog = WATCHDOG_DELAY;
3204      while(overlay.VBlankActiveFunc(pSiS, pPriv) && --watchdog);
3205      setvideoregmask(pSiS, Index_VI_Control_Misc3, 0x00, 0x03);
3206   }
3207#endif
3208   setvideoregmask(pSiS, Index_VI_Control_Misc3, 0x03, 0x03);
3209
3210   /* Do the following in a loop for CRT1 and CRT2 ----------------- */
3211MIRROR:
3212
3213   /* calculate scale factor */
3214#ifdef SISMERGED
3215   if(pSiS->MergedFB && iscrt2)
3216      calc_scale_factor_2(&overlay, pScrn, pPriv, index, iscrt2);
3217   else
3218#endif
3219      calc_scale_factor(&overlay, pScrn, pPriv, index, iscrt2);
3220
3221   /* Select overlay 0 (used for CRT1/or CRT2) or overlay 1 (used for CRT2 only) */
3222   setvideoregmask(pSiS, Index_VI_Control_Misc2, index, 0x01);
3223
3224   /* set format (before color and chroma keys) */
3225   set_format(pSiS, &overlay);
3226
3227   /* set color key */
3228   set_colorkey(pSiS, pPriv->colorKey);
3229
3230   if(pPriv->usechromakey) {
3231      /* Select chroma key format (300 series only) */
3232      if(pSiS->VGAEngine == SIS_300_VGA) {
3233	 setvideoregmask(pSiS, Index_VI_Control_Misc0,
3234	                 (pPriv->yuvchromakey ? 0x40 : 0x00), 0x40);
3235      }
3236      set_chromakey(pSiS, pPriv->chromamin, pPriv->chromamax);
3237   }
3238
3239   /* set brightness, contrast, hue, saturation */
3240   set_brightness(pSiS, pPriv->brightness);
3241   set_contrast(pSiS, pPriv->contrast);
3242   if(pSiS->VGAEngine == SIS_315_VGA) {
3243      set_hue(pSiS, pPriv->hue);
3244      set_saturation(pSiS, pPriv->saturation);
3245   }
3246
3247   /* enable/disable graphics display around overlay
3248    * (Since disabled overlays don't get treated in this
3249    * loop, we omit respective checks here)
3250    */
3251   if(!iscrt2) {
3252     set_disablegfx(pSiS, pPriv->disablegfx, &overlay);
3253   } else if(!pSiS->hasTwoOverlays) {
3254     set_disablegfx(pSiS, FALSE, &overlay);
3255   }
3256   set_disablegfxlr(pSiS, pPriv->disablegfxlr, &overlay);
3257
3258#ifdef SIS_CP
3259   SIS_CP_VIDEO_SET_CP
3260#endif
3261
3262   /* set remaining overlay parameters */
3263   set_overlay(pSiS, &overlay, pPriv, index, iscrt2);
3264
3265   /* enable overlay */
3266   setvideoregmask (pSiS, Index_VI_Control_Misc0, 0x02, 0x02);
3267
3268   /* loop foot */
3269   if(pPriv->displayMode & DISPMODE_MIRROR &&
3270      index == 0			   &&
3271      pPriv->hasTwoOverlays) {
3272#ifdef SISMERGED
3273      if((!pSiS->MergedFB) || overlay.DoSecond) {
3274#endif
3275	 index = 1; iscrt2 = 1;
3276	 overlay.VBlankActiveFunc = vblank_active_CRT2;
3277	 goto MIRROR;
3278#ifdef SISMERGED
3279      }
3280#endif
3281   }
3282
3283   /* Now for the trigger: This is a bad hack to work-around
3284    * an obvious hardware bug: Overlay 1 (which is ONLY used
3285    * for CRT2 in this driver) does not always update its
3286    * window position and some other stuff. Earlier, this was
3287    * solved be disabling the overlay, but this took forever
3288    * and was ugly on the screen.
3289    * Now: We write 0x03 to 0x74 from the beginning. This is
3290    * meant as a "lock" - the driver is supposed to write 0
3291    * to this register, bit 0 for overlay 0, bit 1 for over-
3292    * lay 1, then change buffer addresses, pitches, window
3293    * position, scaler registers, format, etc., then write
3294    * 1 to 0x74. The hardware then reads the registers into
3295    * its internal engine and clears these bits.
3296    * All this works for overlay 0, but not 1. Overlay 1
3297    * has assumingly the following restrictions:
3298    * - New data written to the registers is only read
3299    *   correctly by the engine if the registers are written
3300    *   when the current scanline is beyond the current
3301    *   overlay position and below the maximum visible
3302    *   scanline (vertical screen resolution)
3303    * - If a vertical retrace occures during writing the
3304    *   registers, the registers written BEFORE this re-
3305    *   trace happened, are not being read into the
3306    *   engine if the trigger is set after the retrace.
3307    * Therefore: We write the overlay registers above in
3308    * set_overlay only if the scanline matches, and save
3309    * the then current scanline. If this scanline is higher
3310    * than the now current scanline, we assume a retrace,
3311    * wait for the scanline to match the criteria above again,
3312    * and rewrite all relevant registers.
3313    * I have no idea if this is meant that way, but after
3314    * fiddling three entire days with this crap, I found this
3315    * to be the only solution.
3316    */
3317   if(pSiS->VGAEngine == SIS_315_VGA) {
3318      if((pPriv->mustwait) && index) {
3319	 watchdog = get_scanline_CRT2(pSiS, pPriv);
3320	 if(watchdog <= overlay.oldLine) {
3321	    int i, mytop = overlay.oldtop;
3322	    int screenHeight = overlay.SCREENheight;
3323#ifdef SISMERGED
3324	    if(pSiS->MergedFB) {
3325	       screenHeight = overlay.SCREENheight2;
3326	    }
3327#endif
3328	    if(mytop < screenHeight - 2) {
3329	       do {
3330	          watchdog = get_scanline_CRT2(pSiS, pPriv);
3331	       } while((watchdog <= mytop) || (watchdog >= screenHeight));
3332	    }
3333	    for(i=0x02; i<=0x12; i++) {
3334	       setvideoreg(pSiS, i, getvideoreg(pSiS, i));
3335	    }
3336	    for(i=0x18; i<=0x1c; i++) {
3337	       setvideoreg(pSiS, i, getvideoreg(pSiS, i));
3338	    }
3339	    for(i=0x2c; i<=0x2e; i++) {
3340	       setvideoreg(pSiS, i, getvideoreg(pSiS, i));
3341	    }
3342	    for(i=0x6b; i<=0x6f; i++) {
3343	       setvideoreg(pSiS, i, getvideoreg(pSiS, i));
3344	    }
3345	 }
3346      }
3347      /* Trigger register copy for 315/330 series */
3348      setvideoregmask(pSiS, Index_VI_Control_Misc3, 0x03, 0x03);
3349   }
3350
3351   pPriv->mustwait = 0;
3352   pPriv->overlayStatus = TRUE;
3353}
3354
3355/*********************************
3356 *        Memory management      *
3357 *********************************/
3358
3359#ifdef SIS_USE_EXA
3360static void
3361SiSDestroyArea(ScreenPtr pScreen, ExaOffscreenArea *area)
3362{
3363   void **handle = (void *)area->privData;
3364   *handle = NULL;
3365}
3366#endif
3367
3368unsigned int
3369SISAllocateFBMemory(
3370  ScrnInfoPtr pScrn,
3371  void **handle,
3372  int bytesize
3373){
3374   SISPtr pSiS = SISPTR(pScrn);
3375   ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
3376
3377#ifdef SIS_USE_XAA
3378   if(!pSiS->useEXA) {
3379      FBLinearPtr linear = (FBLinearPtr)(*handle);
3380      FBLinearPtr new_linear;
3381      int depth = pSiS->CurrentLayout.bitsPerPixel >> 3;
3382      int size = ((bytesize + depth - 1) / depth);
3383
3384      if(linear) {
3385         if(linear->size >= size) {
3386	    return (unsigned int)(linear->offset * depth);
3387	 }
3388
3389         if(xf86ResizeOffscreenLinear(linear, size)) {
3390	    return (unsigned int)(linear->offset * depth);
3391	 }
3392
3393         xf86FreeOffscreenLinear(linear);
3394	 *handle = NULL;
3395      }
3396
3397      new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8, NULL, NULL, NULL);
3398
3399      if(!new_linear) {
3400         int max_size;
3401
3402         xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8, PRIORITY_EXTREME);
3403
3404         if(max_size < size)
3405	    return 0;
3406
3407         xf86PurgeUnlockedOffscreenAreas(pScreen);
3408         new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8, NULL, NULL, NULL);
3409      }
3410      if(!new_linear) {
3411         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3412	           "Xv: Failed to allocate %d pixels of linear video memory\n", size);
3413	 return 0;
3414      } else {
3415         *handle = (void *)new_linear;
3416	 return (unsigned int)(new_linear->offset * depth);
3417      }
3418   }
3419#endif
3420#ifdef SIS_USE_EXA
3421   if(pSiS->useEXA && !pSiS->NoAccel) {
3422      ExaOffscreenArea *area = (ExaOffscreenArea *)(*handle);
3423
3424      if(area) {
3425	 if(area->size >= bytesize) return (unsigned int)(area->offset);
3426
3427	 exaOffscreenFree(pScreen, area);
3428	 *handle = NULL;
3429      }
3430
3431      if(!(area = exaOffscreenAlloc(pScreen, bytesize, 8, TRUE, SiSDestroyArea, (pointer)handle))) {
3432	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3433	           "Xv: Failed to allocate %d bytes of video memory\n", bytesize);
3434	 return 0;
3435      } else {
3436	 *handle = (void *)area;
3437	 return (unsigned int)(area->offset);
3438      }
3439   }
3440#endif
3441
3442   return 0;
3443}
3444
3445void
3446SISFreeFBMemory(ScrnInfoPtr pScrn, void **handle)
3447{
3448    SISPtr pSiS = SISPTR(pScrn);
3449#ifdef SIS_USE_EXA
3450    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
3451#endif
3452
3453#ifdef SIS_USE_XAA
3454    if(!pSiS->useEXA) {
3455       if(*handle) {
3456          xf86FreeOffscreenLinear((FBLinearPtr)(*handle));
3457       }
3458    }
3459#endif
3460#ifdef SIS_USE_EXA
3461   if(pSiS->useEXA && !pSiS->NoAccel) {
3462      if(*handle) {
3463         exaOffscreenFree(pScreen, (ExaOffscreenArea *)(*handle));
3464      }
3465   }
3466#endif
3467   *handle = NULL;
3468}
3469
3470/*********************************
3471 *           StopVideo()         *
3472 *********************************/
3473
3474static void
3475SISStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
3476{
3477  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
3478  SISPtr pSiS = SISPTR(pScrn);
3479
3480  if(pPriv->grabbedByV4L) return;
3481
3482  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
3483
3484  if(shutdown) {
3485     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
3486        close_overlay(pSiS, pPriv);
3487        pPriv->mustwait = 1;
3488     }
3489     SISFreeFBMemory(pScrn, &pPriv->handle);
3490     pPriv->videoStatus = 0;
3491  } else {
3492     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
3493        UpdateCurrentTime();
3494        pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
3495        pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
3496        pSiS->VideoTimerCallback = SISVideoTimerCallback;
3497     }
3498  }
3499}
3500
3501/*********************************
3502 *          PutImage()           *
3503 *********************************/
3504
3505static int
3506SISPutImage(
3507  ScrnInfoPtr pScrn,
3508  short src_x, short src_y,
3509  short drw_x, short drw_y,
3510  short src_w, short src_h,
3511  short drw_w, short drw_h,
3512  int id, UChar *buf,
3513  short width, short height,
3514  Bool sync,
3515  RegionPtr clipBoxes, pointer data,
3516  DrawablePtr pDraw
3517){
3518   SISPtr pSiS = SISPTR(pScrn);
3519   SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
3520#ifdef SIS_USE_XAA
3521   XAAInfoRecPtr pXAA = pSiS->AccelInfoPtr;
3522   int depth = pSiS->CurrentLayout.bitsPerPixel >> 3;
3523   int myreds[] = { 0x000000ff, 0x0000f800, 0, 0x00ff0000 };
3524#endif
3525   int totalSize = 0;
3526#ifdef SISDEINT
3527   Bool	deintfm = (pPriv->deinterlacemethod > 1) ? TRUE : FALSE;
3528#endif
3529
3530#if 0
3531   xf86DrvMsg(0, X_INFO, "PutImage: src %dx%d-%dx%d, drw %dx%d-%dx%d, id %x, w %d h %d, buf %p\n",
3532	src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w, drw_h, id, width, height, buf);
3533#endif
3534
3535   if(pPriv->grabbedByV4L) return Success;
3536
3537   pPriv->drw_x = drw_x;
3538   pPriv->drw_y = drw_y;
3539   pPriv->drw_w = drw_w;
3540   pPriv->drw_h = drw_h;
3541   pPriv->src_x = src_x;
3542   pPriv->src_y = src_y;
3543   pPriv->src_w = src_w;
3544   pPriv->src_h = src_h;
3545   pPriv->id = id;
3546   pPriv->height = height;
3547
3548   /* Pixel formats:
3549      1. YU12:  3 planes:       H    V
3550               Y sample period  1    1   (8 bit per pixel)
3551	       V sample period  2    2	 (8 bit per pixel, subsampled)
3552	       U sample period  2    2   (8 bit per pixel, subsampled)
3553
3554	 Y plane is fully sampled (width*height), U and V planes
3555	 are sampled in 2x2 blocks, hence a group of 4 pixels requires
3556	 4 + 1 + 1 = 6 bytes. The data is planar, ie in single planes
3557	 for Y, U and V.
3558      2. UYVY: 3 planes:        H    V
3559	       Y sample period  1    1   (8 bit per pixel)
3560	       V sample period  2    1	 (8 bit per pixel, subsampled)
3561	       U sample period  2    1   (8 bit per pixel, subsampled)
3562	 Y plane is fully sampled (width*height), U and V planes
3563	 are sampled in 2x1 blocks, hence a group of 4 pixels requires
3564	 4 + 2 + 2 = 8 bytes. The data is bit packed, there are no separate
3565	 Y, U or V planes.
3566	 Bit order:  U0 Y0 V0 Y1  U2 Y2 V2 Y3 ...
3567      3. I420: Like YU12, but planes U and V are in reverse order.
3568      4. YUY2: Like UYVY, but order is
3569		     Y0 U0 Y1 V0  Y2 U2 Y3 V2 ...
3570      5. YVYU: Like YUY2, but order is
3571		     Y0 V0 Y1 U0  Y2 V2 Y3 U2 ...
3572      6. NV12, NV21: 2 planes   H    V
3573	       Y sample period  1    1   (8 bit per pixel)
3574	       V sample period  2    1	 (8 bit per pixel, subsampled)
3575	       U sample period  2    1   (8 bit per pixel, subsampled)
3576	 Y plane is fully samples (width*height), U and V planes are
3577	 interleaved in memory (one byte U, one byte V for NV12, NV21
3578	 other way round) and sampled in 2x1 blocks. Otherwise such
3579	 as all other planar formats.
3580   */
3581
3582   switch(id){
3583     case PIXEL_FMT_YV12:
3584     case PIXEL_FMT_I420:
3585     case PIXEL_FMT_NV12:
3586     case PIXEL_FMT_NV21:
3587       pPriv->srcPitch = (width + 7) & ~7;
3588       /* Size = width * height * 3 / 2 */
3589       totalSize = (pPriv->srcPitch * height * 3) >> 1; /* Verified */
3590       break;
3591     case PIXEL_FMT_YUY2:
3592     case PIXEL_FMT_UYVY:
3593     case PIXEL_FMT_YVYU:
3594     case PIXEL_FMT_RGB6:
3595     case PIXEL_FMT_RGB5:
3596     default:
3597       pPriv->srcPitch = ((width << 1) + 3) & ~3;	/* Verified */
3598       /* Size = width * 2 * height */
3599       totalSize = pPriv->srcPitch * height;
3600   }
3601
3602   /* make it a multiple of 16 to simplify to copy loop */
3603   totalSize += 15;
3604   totalSize &= ~15; /* in bytes */
3605
3606   /* allocate memory (we do doublebuffering) - size is in bytes */
3607   if(!(pPriv->bufAddr[0] = SISAllocateFBMemory(pScrn, &pPriv->handle, totalSize << 1)))
3608      return BadAlloc;
3609
3610#ifdef SISDEINT
3611   if(deintfm) {
3612      pPriv->bufAddr[1] = pPriv->bufAddr[0] + pPriv->srcPitch;
3613
3614      {
3615         CARD8 *src = (CARD8 *)buf;
3616         CARD8 *dest = (CARD8 *)(pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf]);
3617         int i = height;
3618         while(i--) {
3619	    SiSMemCopyToVideoRam(pSiS, dest, src, pPriv->srcPitch);
3620	    src += pPriv->srcPitch;
3621	    dest += (pPriv->srcPitch << 1);
3622         }
3623      }
3624
3625   } else {
3626#endif
3627      pPriv->bufAddr[1] = pPriv->bufAddr[0] + totalSize;
3628
3629      /* copy data */
3630      if((pSiS->XvUseMemcpy) || (totalSize < 16)) {
3631         SiSMemCopyToVideoRam(pSiS, pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf], buf, totalSize);
3632      } else {
3633         ULong i;
3634         CARD32 *src = (CARD32 *)buf;
3635         CARD32 *dest = (CARD32 *)(pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf]);
3636         for(i = 0; i < (totalSize/16); i++) {
3637            *dest++ = *src++;
3638	    *dest++ = *src++;
3639	    *dest++ = *src++;
3640	    *dest++ = *src++;
3641         }
3642      }
3643#ifdef SISDEINT
3644   }
3645#endif
3646
3647   SISDisplayVideo(pScrn, pPriv);
3648
3649   /* update cliplist */
3650   if(pPriv->autopaintColorKey &&
3651      (pPriv->grabbedByV4L ||
3652#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
3653       (!RegionsEqual(&pPriv->clip, clipBoxes)) ||
3654#else
3655       (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) ||
3656#endif
3657       (pPriv->PrevOverlay != pPriv->NoOverlay))) {
3658     /* We always paint the colorkey for V4L */
3659     if(!pPriv->grabbedByV4L) {
3660     	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
3661     }
3662     /* draw these */
3663     pPriv->PrevOverlay = pPriv->NoOverlay;
3664#ifdef SIS_USE_XAA
3665     if((pPriv->NoOverlay) && pXAA && pXAA->FillMono8x8PatternRects) {
3666        (*pXAA->FillMono8x8PatternRects)(pScrn, myreds[depth-1],
3667			0x000000, GXcopy, ~0,
3668			REGION_NUM_RECTS(clipBoxes),
3669			REGION_RECTS(clipBoxes),
3670			0x00422418, 0x18244200, 0, 0);
3671     } else {
3672#endif
3673        if(!pSiS->disablecolorkeycurrent) {
3674#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
3675           (*pXAA->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0,
3676                           REGION_NUM_RECTS(clipBoxes),
3677                           REGION_RECTS(clipBoxes));
3678#else
3679	   xf86XVFillKeyHelper(pScrn->pScreen, (pPriv->NoOverlay) ? 0x00ff0000 : pPriv->colorKey, clipBoxes);
3680#endif
3681	}
3682#ifdef SIS_USE_XAA
3683     }
3684#endif
3685
3686   }
3687
3688   pPriv->currentBuf ^= 1;
3689
3690   pPriv->videoStatus = CLIENT_VIDEO_ON;
3691
3692   pSiS->VideoTimerCallback = SISVideoTimerCallback;
3693
3694   return Success;
3695}
3696
3697/*********************************
3698 *     QueryImageAttributes()    *
3699 *********************************/
3700
3701static int
3702SISQueryImageAttributes(
3703  ScrnInfoPtr pScrn,
3704  int id,
3705  UShort *w, UShort *h,
3706  int *pitches, int *offsets
3707){
3708    int    pitchY, pitchUV;
3709    int    size, sizeY, sizeUV;
3710
3711    if(*w < IMAGE_MIN_WIDTH) *w = IMAGE_MIN_WIDTH;
3712    if(*h < IMAGE_MIN_HEIGHT) *h = IMAGE_MIN_HEIGHT;
3713
3714    if(*w > DummyEncoding.width) *w = DummyEncoding.width;
3715    if(*h > DummyEncoding.height) *h = DummyEncoding.height;
3716
3717    switch(id) {
3718    case PIXEL_FMT_YV12:
3719    case PIXEL_FMT_I420:
3720        *w = (*w + 7) & ~7;
3721        *h = (*h + 1) & ~1;
3722        pitchY = *w;
3723    	pitchUV = *w >> 1;
3724    	if(pitches) {
3725      	    pitches[0] = pitchY;
3726            pitches[1] = pitches[2] = pitchUV;
3727        }
3728    	sizeY = pitchY * (*h);
3729    	sizeUV = pitchUV * ((*h) >> 1);
3730    	if(offsets) {
3731          offsets[0] = 0;
3732          offsets[1] = sizeY;
3733          offsets[2] = sizeY + sizeUV;
3734        }
3735        size = sizeY + (sizeUV << 1);
3736    	break;
3737    case PIXEL_FMT_NV12:
3738    case PIXEL_FMT_NV21:
3739        *w = (*w + 7) & ~7;
3740        *h = (*h + 1) & ~1;
3741	pitchY = *w;
3742    	pitchUV = *w;
3743    	if(pitches) {
3744      	    pitches[0] = pitchY;
3745            pitches[1] = pitchUV;
3746        }
3747    	sizeY = pitchY * (*h);
3748    	sizeUV = pitchUV * ((*h) >> 1);
3749    	if(offsets) {
3750          offsets[0] = 0;
3751          offsets[1] = sizeY;
3752        }
3753        size = sizeY + (sizeUV << 1);
3754        break;
3755    case PIXEL_FMT_YUY2:
3756    case PIXEL_FMT_UYVY:
3757    case PIXEL_FMT_YVYU:
3758    case PIXEL_FMT_RGB6:
3759    case PIXEL_FMT_RGB5:
3760    default:
3761        *w = (*w + 1) & ~1;
3762        pitchY = *w << 1;
3763    	if(pitches) pitches[0] = pitchY;
3764    	if(offsets) offsets[0] = 0;
3765    	size = pitchY * (*h);
3766    	break;
3767    }
3768
3769    return size;
3770}
3771
3772
3773/*********************************
3774 *      OFFSCREEN SURFACES       *
3775 *********************************/
3776
3777static int
3778SISAllocSurface (
3779    ScrnInfoPtr pScrn,
3780    int id,
3781    UShort w,
3782    UShort h,
3783    XF86SurfacePtr surface
3784)
3785{
3786    SISPtr pSiS = SISPTR(pScrn);
3787    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
3788    int size;
3789
3790    if((w < IMAGE_MIN_WIDTH) || (h < IMAGE_MIN_HEIGHT))
3791       return BadValue;
3792
3793    if((w > DummyEncoding.width) || (h > DummyEncoding.height))
3794       return BadValue;
3795
3796    if(pPriv->grabbedByV4L)
3797       return BadAlloc;
3798
3799    w = (w + 1) & ~1;
3800    pPriv->pitch = ((w << 1) + 63) & ~63; /* Only packed pixel modes supported */
3801    size = h * pPriv->pitch;
3802    if(!(pPriv->offset = SISAllocateFBMemory(pScrn, &pPriv->handle, size)))
3803       return BadAlloc;
3804
3805    surface->width   = w;
3806    surface->height  = h;
3807    surface->pScrn   = pScrn;
3808    surface->id      = id;
3809    surface->pitches = &pPriv->pitch;
3810    surface->offsets = &pPriv->offset;
3811    surface->devPrivate.ptr = (pointer)pPriv;
3812
3813    close_overlay(pSiS, pPriv);
3814    pPriv->videoStatus = 0;
3815    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
3816    pSiS->VideoTimerCallback = NULL;
3817    pPriv->grabbedByV4L = TRUE;
3818    return Success;
3819}
3820
3821static int
3822SISStopSurface (XF86SurfacePtr surface)
3823{
3824    SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
3825    SISPtr pSiS = SISPTR(surface->pScrn);
3826
3827    if(pPriv->grabbedByV4L && pPriv->videoStatus) {
3828       close_overlay(pSiS, pPriv);
3829       pPriv->mustwait = 1;
3830       pPriv->videoStatus = 0;
3831    }
3832    return Success;
3833}
3834
3835static int
3836SISFreeSurface (XF86SurfacePtr surface)
3837{
3838    SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
3839
3840    if(pPriv->grabbedByV4L) {
3841       SISStopSurface(surface);
3842       SISFreeFBMemory(surface->pScrn, &pPriv->handle);
3843       pPriv->grabbedByV4L = FALSE;
3844    }
3845    return Success;
3846}
3847
3848static int
3849SISGetSurfaceAttribute (
3850    ScrnInfoPtr pScrn,
3851    Atom attribute,
3852    INT32 *value
3853)
3854{
3855    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
3856
3857    return SISGetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
3858}
3859
3860static int
3861SISSetSurfaceAttribute(
3862    ScrnInfoPtr pScrn,
3863    Atom attribute,
3864    INT32 value
3865)
3866{
3867    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);;
3868
3869    return SISSetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
3870}
3871
3872static int
3873SISDisplaySurface (
3874    XF86SurfacePtr surface,
3875    short src_x, short src_y,
3876    short drw_x, short drw_y,
3877    short src_w, short src_h,
3878    short drw_w, short drw_h,
3879    RegionPtr clipBoxes
3880)
3881{
3882   ScrnInfoPtr pScrn = surface->pScrn;
3883   SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
3884#ifdef SIS_USE_XAA
3885   SISPtr pSiS = SISPTR(pScrn);
3886   int myreds[] = { 0x000000ff, 0x0000f800, 0, 0x00ff0000 };
3887#endif
3888
3889   if(!pPriv->grabbedByV4L) return Success;
3890
3891   pPriv->drw_x = drw_x;
3892   pPriv->drw_y = drw_y;
3893   pPriv->drw_w = drw_w;
3894   pPriv->drw_h = drw_h;
3895   pPriv->src_x = src_x;
3896   pPriv->src_y = src_y;
3897   pPriv->src_w = src_w;
3898   pPriv->src_h = src_h;
3899   pPriv->id = surface->id;
3900   pPriv->height = surface->height;
3901   pPriv->bufAddr[0] = surface->offsets[0];
3902   pPriv->currentBuf = 0;
3903   pPriv->srcPitch = surface->pitches[0];
3904
3905   SISDisplayVideo(pScrn, pPriv);
3906
3907   if(pPriv->autopaintColorKey) {
3908#ifdef SIS_USE_XAA
3909      XAAInfoRecPtr pXAA = pSiS->AccelInfoPtr;
3910
3911      if((pPriv->NoOverlay) && pXAA && pXAA->FillMono8x8PatternRects) {
3912         (*pXAA->FillMono8x8PatternRects)(pScrn,
3913	  		myreds[(pSiS->CurrentLayout.bitsPerPixel >> 3) - 1],
3914	 		0x000000, GXcopy, ~0,
3915			REGION_NUM_RECTS(clipBoxes),
3916			REGION_RECTS(clipBoxes),
3917			0x00422418, 0x18244200, 0, 0);
3918
3919      } else {
3920#endif
3921#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
3922   	 (*pXAA->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0,
3923                        REGION_NUM_RECTS(clipBoxes),
3924                        REGION_RECTS(clipBoxes));
3925#else
3926         xf86XVFillKeyHelper(pScrn->pScreen, (pPriv->NoOverlay) ? 0x00ff0000 : pPriv->colorKey, clipBoxes);
3927#endif
3928#ifdef SIS_USE_XAA
3929      }
3930#endif
3931   }
3932
3933   pPriv->videoStatus = CLIENT_VIDEO_ON;
3934
3935   return Success;
3936}
3937
3938#define NUMOFFSCRIMAGES_300 4
3939#define NUMOFFSCRIMAGES_315 5
3940
3941static XF86OffscreenImageRec SISOffscreenImages[NUMOFFSCRIMAGES_315] =
3942{
3943 {
3944   &SISImages[0],  	/* YUV2 */
3945   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
3946   SISAllocSurface,
3947   SISFreeSurface,
3948   SISDisplaySurface,
3949   SISStopSurface,
3950   SISGetSurfaceAttribute,
3951   SISSetSurfaceAttribute,
3952   0, 0,  			/* Rest will be filled in */
3953   0,
3954   NULL
3955 },
3956 {
3957   &SISImages[2],	/* UYVY */
3958   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
3959   SISAllocSurface,
3960   SISFreeSurface,
3961   SISDisplaySurface,
3962   SISStopSurface,
3963   SISGetSurfaceAttribute,
3964   SISSetSurfaceAttribute,
3965   0, 0,  			/* Rest will be filled in */
3966   0,
3967   NULL
3968 }
3969 ,
3970 {
3971   &SISImages[4],	/* RV15 */
3972   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
3973   SISAllocSurface,
3974   SISFreeSurface,
3975   SISDisplaySurface,
3976   SISStopSurface,
3977   SISGetSurfaceAttribute,
3978   SISSetSurfaceAttribute,
3979   0, 0,  			/* Rest will be filled in */
3980   0,
3981   NULL
3982 },
3983 {
3984   &SISImages[5],	/* RV16 */
3985   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
3986   SISAllocSurface,
3987   SISFreeSurface,
3988   SISDisplaySurface,
3989   SISStopSurface,
3990   SISGetSurfaceAttribute,
3991   SISSetSurfaceAttribute,
3992   0, 0,  			/* Rest will be filled in */
3993   0,
3994   NULL
3995 },
3996 {
3997   &SISImages[6],	/* YVYU */
3998   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
3999   SISAllocSurface,
4000   SISFreeSurface,
4001   SISDisplaySurface,
4002   SISStopSurface,
4003   SISGetSurfaceAttribute,
4004   SISSetSurfaceAttribute,
4005   0, 0,  			/* Rest will be filled in */
4006   0,
4007   NULL
4008 }
4009};
4010
4011static void
4012SISInitOffscreenImages(ScreenPtr pScreen)
4013{
4014    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
4015    SISPtr pSiS = SISPTR(pScrn);
4016    int i, num;
4017
4018    if(pSiS->VGAEngine == SIS_300_VGA)	num = NUMOFFSCRIMAGES_300;
4019    else 				num = NUMOFFSCRIMAGES_315;
4020
4021    for(i = 0; i < num; i++) {
4022       SISOffscreenImages[i].max_width  = DummyEncoding.width;
4023       SISOffscreenImages[i].max_height = DummyEncoding.height;
4024       if(pSiS->VGAEngine == SIS_300_VGA) {
4025          SISOffscreenImages[i].attributes = &SISAttributes_300[0];
4026	  SISOffscreenImages[i].num_attributes = SiSCountAttributes(&SISAttributes_300[0]);
4027       } else {
4028          SISOffscreenImages[i].attributes = &SISAttributes_315[0];
4029	  SISOffscreenImages[i].num_attributes = SiSCountAttributes(&SISAttributes_315[0]);
4030	  if((pSiS->hasTwoOverlays) && (!(pSiS->SiS_SD2_Flags & SiS_SD2_SUPPORT760OO))) {
4031	     SISOffscreenImages[i].num_attributes--;
4032	  }
4033       }
4034    }
4035    xf86XVRegisterOffscreenImages(pScreen, SISOffscreenImages, num);
4036}
4037
4038/*****************************************************************/
4039/*                         BLIT ADAPTORS                         */
4040/*****************************************************************/
4041#ifdef INCL_YUV_BLIT_ADAPTOR
4042
4043static void
4044SISSetPortDefaultsBlit(ScrnInfoPtr pScrn, SISBPortPrivPtr pPriv)
4045{
4046    /* Default: Don't sync. */
4047    pPriv->vsync  = 0;
4048}
4049
4050static void
4051SISResetVideoBlit(ScrnInfoPtr pScrn)
4052{
4053}
4054
4055static XF86VideoAdaptorPtr
4056SISSetupBlitVideo(ScreenPtr pScreen)
4057{
4058   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
4059   SISPtr pSiS = SISPTR(pScrn);
4060   XF86VideoAdaptorPtr adapt;
4061   SISBPortPrivPtr pPriv;
4062   int i;
4063
4064#ifdef SIS_USE_XAA
4065   if(!pSiS->useEXA) {
4066      if(!pSiS->AccelInfoPtr) return NULL;
4067   }
4068#endif
4069
4070   if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
4071    			   (sizeof(DevUnion) * NUM_BLIT_PORTS) +
4072                           sizeof(SISBPortPrivRec)))) {
4073      return NULL;
4074   }
4075
4076   adapt->type = XvWindowMask | XvInputMask | XvImageMask;
4077   adapt->flags = 0;
4078   adapt->name = "SIS 315/330 series Video Blitter";
4079   adapt->nEncodings = 1;
4080   adapt->pEncodings = &DummyEncodingBlit;
4081   adapt->nFormats = NUM_FORMATS;
4082   adapt->pFormats = SISFormats;
4083   adapt->nImages = NUM_IMAGES_BLIT;
4084   adapt->pImages = SISImagesBlit;
4085   adapt->pAttributes = SISAttributes_Blit;
4086   adapt->nAttributes = NUM_ATTRIBUTES_BLIT;
4087   adapt->nPorts = NUM_BLIT_PORTS;
4088   adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
4089
4090   pSiS->blitPriv = (void *)(&adapt->pPortPrivates[NUM_BLIT_PORTS]);
4091   pPriv = (SISBPortPrivPtr)(pSiS->blitPriv);
4092
4093   for(i = 0; i < NUM_BLIT_PORTS; i++) {
4094      adapt->pPortPrivates[i].uval = (ULong)(i);
4095#if defined(REGION_NULL)
4096      REGION_NULL(pScreen, &pPriv->blitClip[i]);
4097#else
4098      REGION_INIT(pScreen, &pPriv->blitClip[i], NullBox, 0);
4099#endif
4100      pPriv->videoStatus[i] = 0;
4101      pPriv->currentBuf[i]  = 0;
4102      pPriv->handle[i]      = NULL;
4103   }
4104
4105   /* Scanline trigger not implemented by hardware! */
4106   pPriv->VBlankTriggerCRT1 = 0; /* SCANLINE_TRIGGER_ENABLE | SCANLINE_TR_CRT1; */
4107   pPriv->VBlankTriggerCRT2 = 0; /* SCANLINE_TRIGGER_ENABLE | SCANLINE_TR_CRT2; */
4108   if(pSiS->ChipType >= SIS_330) {
4109      pPriv->AccelCmd = YUVRGB_BLIT_330;
4110   } else {
4111      pPriv->AccelCmd = YUVRGB_BLIT_325;
4112   }
4113
4114   adapt->PutVideo = NULL;
4115   adapt->PutStill = NULL;
4116   adapt->GetVideo = NULL;
4117   adapt->GetStill = NULL;
4118   adapt->StopVideo = (StopVideoFuncPtr)SISStopVideoBlit;
4119   adapt->SetPortAttribute = (SetPortAttributeFuncPtr)SISSetPortAttributeBlit;
4120   adapt->GetPortAttribute = (GetPortAttributeFuncPtr)SISGetPortAttributeBlit;
4121   adapt->QueryBestSize = (QueryBestSizeFuncPtr)SISQueryBestSizeBlit;
4122   adapt->PutImage = (PutImageFuncPtr)SISPutImageBlit;
4123   adapt->QueryImageAttributes = SISQueryImageAttributesBlit;
4124
4125   pSiS->blitadaptor = adapt;
4126
4127   pSiS->xvVSync = MAKE_ATOM(sisxvvsync);
4128   pSiS->xvSetDefaults = MAKE_ATOM(sisxvsetdefaults);
4129
4130   SISResetVideoBlit(pScrn);
4131
4132   /* Reset the properties to their defaults */
4133   SISSetPortDefaultsBlit(pScrn, pPriv);
4134
4135   return adapt;
4136}
4137
4138static int
4139SISGetPortAttributeBlit(ScrnInfoPtr pScrn, Atom attribute,
4140  			INT32 *value, ULong index)
4141{
4142   SISPtr pSiS = SISPTR(pScrn);
4143   SISBPortPrivPtr pPriv = (SISBPortPrivPtr)(pSiS->blitPriv);
4144
4145   if(attribute == pSiS->xvVSync) {
4146      *value = pPriv->vsync;
4147   } else return BadMatch;
4148   return Success;
4149}
4150
4151static int
4152SISSetPortAttributeBlit(ScrnInfoPtr pScrn, Atom attribute,
4153  		    	INT32 value, ULong index)
4154{
4155   SISPtr pSiS = SISPTR(pScrn);
4156   SISBPortPrivPtr pPriv = (SISBPortPrivPtr)(pSiS->blitPriv);
4157
4158   if(attribute == pSiS->xvVSync) {
4159      if((value < 0) || (value > 1)) return BadValue;
4160      pPriv->vsync = value;
4161   } else if(attribute == pSiS->xvSetDefaults) {
4162      SISSetPortDefaultsBlit(pScrn, pPriv);
4163   } else return BadMatch;
4164   return Success;
4165}
4166
4167static void
4168SISStopVideoBlit(ScrnInfoPtr pScrn, ULong index, Bool shutdown)
4169{
4170   SISPtr pSiS = SISPTR(pScrn);
4171   SISBPortPrivPtr pPriv = (SISBPortPrivPtr)(pSiS->blitPriv);
4172
4173   /* This shouldn't be called for blitter adaptors due to
4174    * adapt->flags but we provide it anyway.
4175    */
4176
4177   if(index >= NUM_BLIT_PORTS) return;
4178
4179   REGION_EMPTY(pScrn->pScreen, &pPriv->blitClip[index]);
4180
4181   if(shutdown) {
4182      (*pSiS->SyncAccel)(pScrn);
4183      pPriv->videoStatus[index] = 0;
4184      SISFreeFBMemory(pScrn, &pPriv->handle[(int)index]);
4185   }
4186}
4187
4188static int
4189SISPutImageBlit(
4190  ScrnInfoPtr pScrn,
4191  short src_x, short src_y,
4192  short drw_x, short drw_y,
4193  short src_w, short src_h,
4194  short drw_w, short drw_h,
4195  int id, UChar *buf,
4196  short width, short height,
4197  Bool sync,
4198  RegionPtr clipBoxes, ULong index,
4199  DrawablePtr pDraw
4200){
4201   SISPtr pSiS = SISPTR(pScrn);
4202   SISBPortPrivPtr pPriv = (SISBPortPrivPtr)(pSiS->blitPriv);
4203#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
4204   XAAInfoRecPtr pXAA = pSiS->AccelInfoPtr;
4205#endif
4206   BoxPtr pbox = REGION_RECTS(clipBoxes);
4207   int    nbox = REGION_NUM_RECTS(clipBoxes);
4208   CARD32 dstbase = 0, offsety, offsetuv, temp;
4209   int    totalSize, bytesize=0, h, w, wb, srcPitch;
4210   int 	  xoffset = 0, yoffset = 0, left, right, top, bottom;
4211   UChar  *ybases, *ubases = NULL, *vbases = NULL, *myubases, *myvbases;
4212   UChar  *ybased, *uvbased, packed;
4213   CARD16 *myuvbased;
4214   SiS_Packet12_YUV MyPacket;
4215#if 0
4216#ifdef SISMERGED
4217   Bool first;
4218#endif
4219#endif
4220
4221   if(index >= NUM_BLIT_PORTS) return BadMatch;
4222
4223   if(!height || !width) return Success;
4224
4225   switch(id) {
4226     case PIXEL_FMT_YV12:
4227     case PIXEL_FMT_I420:
4228     case PIXEL_FMT_NV12:
4229     case PIXEL_FMT_NV21:
4230       srcPitch = (width + 7) & ~7;  /* Should come this way anyway */
4231       bytesize = srcPitch * height;
4232       totalSize = (bytesize * 3) >> 1;
4233       break;
4234     case PIXEL_FMT_YUY2:
4235     case PIXEL_FMT_UYVY:
4236     case PIXEL_FMT_YVYU:
4237       srcPitch = ((width << 1) + 3) & ~3;
4238       /* Size = width * 2 * height */
4239       totalSize = srcPitch * height;
4240       bytesize = 0;
4241       break;
4242     default:
4243       return BadMatch;
4244   }
4245
4246   /* allocate memory (we do doublebuffering) */
4247   if(!(pPriv->bufAddr[index][0] = SISAllocateFBMemory(pScrn, &pPriv->handle[index], totalSize << 1)))
4248      return BadAlloc;
4249
4250   pPriv->bufAddr[index][1] = pPriv->bufAddr[index][0] + totalSize;
4251
4252   if(drw_w > width) {
4253      xoffset = (drw_w - width) >> 1;
4254   }
4255   if(drw_h > (height & ~1)) {
4256      yoffset = (drw_h - height) >> 1;
4257   }
4258
4259   if(xoffset || yoffset) {
4260#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
4261      if(!RegionsEqual(&pPriv->blitClip[index], clipBoxes)) {
4262#else
4263      if(!REGION_EQUAL(pScrn->pScreen, &pPriv->blitClip[index], clipBoxes)) {
4264#endif
4265#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
4266         (*pXAA->FillSolidRects)(pScrn, 0x00000000, GXcopy, ~0,
4267                              REGION_NUM_RECTS(clipBoxes),
4268                              REGION_RECTS(clipBoxes));
4269#else
4270         xf86XVFillKeyHelper(pScrn->pScreen, 0x00000000, clipBoxes);
4271#endif
4272         REGION_COPY(pScrn->pScreen, &pPriv->blitClip[index], clipBoxes);
4273      }
4274   }
4275
4276   memset(&MyPacket, 0, sizeof(MyPacket));
4277
4278   ybased = pSiS->FbBase + pPriv->bufAddr[index][pPriv->currentBuf[index]];
4279   uvbased = pSiS->FbBase + pPriv->bufAddr[index][pPriv->currentBuf[index]] + bytesize;
4280
4281   ybases = buf;
4282   packed = 0;
4283
4284   switch(id) {
4285     case PIXEL_FMT_YV12:
4286	vbases = buf + bytesize;
4287	ubases = buf + bytesize*5/4;
4288	break;
4289     case PIXEL_FMT_I420:
4290	ubases = buf + bytesize;
4291	vbases = buf + bytesize*5/4;
4292	break;
4293     case PIXEL_FMT_NV12:
4294        MyPacket.P12_Command = YUV_FORMAT_NV12;
4295        break;
4296     case PIXEL_FMT_NV21:
4297        MyPacket.P12_Command = YUV_FORMAT_NV21;
4298        break;
4299     case PIXEL_FMT_YUY2:
4300        MyPacket.P12_Command = YUV_FORMAT_YUY2;
4301	packed = 1;
4302        break;
4303     case PIXEL_FMT_UYVY:
4304        MyPacket.P12_Command = YUV_FORMAT_UYVY;
4305	packed = 1;
4306        break;
4307     case PIXEL_FMT_YVYU:
4308        MyPacket.P12_Command = YUV_FORMAT_YVYU;
4309	packed = 1;
4310        break;
4311     default:
4312        return BadMatch;
4313   }
4314
4315   switch(id) {
4316   case PIXEL_FMT_YV12:
4317   case PIXEL_FMT_I420:
4318      MyPacket.P12_Command = YUV_FORMAT_NV12;
4319      /* Copy y plane */
4320      SiSMemCopyToVideoRam(pSiS, ybased, ybases, bytesize);
4321      /* Copy u/v planes */
4322      wb = srcPitch >> 1;
4323      h = height >> 1;
4324      while(h--) {
4325         myuvbased = (CARD16*)uvbased;
4326         myubases = ubases;
4327         myvbases = vbases;
4328	 w = wb;
4329	 while(w--) {
4330#if X_BYTE_ORDER == X_BIG_ENDIAN
4331 	    temp =  (*myubases++) << 8;
4332	    temp |= (*myvbases++);
4333#else
4334	    temp =  (*myvbases++) << 8;
4335	    temp |= (*myubases++);
4336#endif
4337	    *myuvbased++ = temp;
4338	 }
4339	 uvbased += srcPitch;
4340	 ubases += wb;
4341	 vbases += wb;
4342      }
4343      break;
4344   default:
4345      SiSMemCopyToVideoRam(pSiS, ybased, ybases, totalSize);
4346   }
4347
4348   dstbase += FBOFFSET;
4349
4350   MyPacket.P12_Header0 = SIS_PACKET12_HEADER0;
4351   MyPacket.P12_Header1 = SIS_PACKET12_HEADER1;
4352   MyPacket.P12_Null1 = SIS_NIL_CMD;
4353   MyPacket.P12_Null2 = SIS_NIL_CMD;
4354   MyPacket.P12_YPitch = MyPacket.P12_UVPitch = srcPitch;
4355   MyPacket.P12_DstAddr = dstbase;
4356   MyPacket.P12_DstPitch = pSiS->scrnOffset;
4357   MyPacket.P12_DstHeight = 0x0fff;
4358
4359   MyPacket.P12_Command |= pPriv->AccelCmd		|
4360			   SRCVIDEO			|
4361			   PATFG			|
4362			   pSiS->SiS310_AccelDepth	|
4363			   YUV_CMD_YUV			|
4364			   DSTVIDEO;
4365
4366
4367#if 0 /* Not implemented by hardware! */
4368   if(pPriv->vsync) {
4369#ifdef SISMERGED
4370      if(!pSiS->MergedFB) {
4371#endif
4372#ifdef SISDUALHEAD
4373         if(pSiS->DualHeadMode) {
4374	    if(pSiS->SecondHead) {
4375	       MyPacket.P12_Command |= pPriv->VBlankTriggerCRT1;
4376	    } else {
4377	       MyPacket.P12_Command |= pPriv->VBlankTriggerCRT2;
4378	    }
4379	 } else {
4380#endif
4381            Bool IsSlaveMode = SiSBridgeIsInSlaveMode(pScrn);
4382            if((pSiS->VBFlags & DISPTYPE_DISP2) && !IsSlaveMode)
4383	       MyPacket.P12_Command |= pPriv->VBlankTriggerCRT2;
4384	    else if((pSiS->VBFlags & DISPTYPE_DISP1) || IsSlaveMode)
4385	       MyPacket.P12_Command |= pPriv->VBlankTriggerCRT1;
4386#ifdef SISDUALHEAD
4387         }
4388#endif
4389#ifdef SISMERGED
4390      }
4391#endif
4392   }
4393#endif
4394
4395#if 0
4396#ifdef SISMERGED
4397   first = TRUE;
4398#endif
4399#endif
4400   while(nbox--) {
4401      left = pbox->x1;
4402      if(left >= drw_x + xoffset + width) goto mycont;
4403
4404      right = pbox->x2;
4405      if(right <= drw_x + xoffset) goto mycont;
4406
4407      top = pbox->y1;
4408      if(top >= drw_y + yoffset + height) goto mycont;
4409
4410      bottom = pbox->y2;
4411      if(bottom <= drw_y + yoffset) goto mycont;
4412
4413      if(left < (drw_x + xoffset)) left = drw_x + xoffset;
4414      if(right > (drw_x + xoffset + width)) right = drw_x + xoffset + width;
4415      if(top < (drw_y + yoffset)) top = drw_y + yoffset;
4416      if(bottom > (drw_y + yoffset + height)) bottom = drw_y + yoffset + height;
4417
4418      MyPacket.P12_DstX = left;
4419      MyPacket.P12_DstY = top;
4420      MyPacket.P12_RectWidth = right - left;
4421      MyPacket.P12_RectHeight = bottom - top;
4422
4423#if 0
4424#ifdef SISMERGED
4425      if((first) && (pSiS->MergedFB)) {
4426         int scrwidth = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2->HDisplay;
4427	 int scrheight = ((SiSMergedDisplayModePtr)pSiS->CurrentLayout.mode->Private)->CRT2->VDisplay;
4428	 if( (right < pSiS->CRT2pScrn->frameX0) ||
4429	     (left >= pSiS->CRT2pScrn->frameX0 + scrwidth) ||
4430	     (bottom < pSiS->CRT2pScrn->frameY0) ||
4431	     (top >= pSiS->CRT2pScrn->frameY0 + scrheight) ) {
4432	    MyPacket.P12_Command |= pPriv->VBlankTriggerCRT1;
4433	 } else {
4434	    MyPacket.P12_Command |= pPriv->VBlankTriggerCRT2;
4435	 }
4436      }
4437#endif
4438#endif
4439
4440      offsety = offsetuv = 0;
4441      if(packed) {
4442         if(pbox->y1 > drw_y + yoffset) {
4443            offsetuv  = (pbox->y1 - drw_y - yoffset) * srcPitch;
4444         }
4445         if(pbox->x1 > drw_x + xoffset) {
4446            offsetuv += ((pbox->x1 - drw_x - xoffset) << 1);
4447	    if(offsetuv & 3) {
4448#if 0	       /* Paint over covering object - no */
4449	       if(MyPacket.P12_DstX > 0) {
4450	          offsetuv &= ~3;
4451	          MyPacket.P12_DstX--;
4452	          MyPacket.P12_RectWidth++;
4453	       } else {
4454#endif
4455	          offsetuv = (offsetuv + 3) & ~3;
4456	          MyPacket.P12_DstX++;
4457	          MyPacket.P12_RectWidth--;
4458#if 0
4459	       }
4460#endif
4461	    }
4462         }
4463      } else {
4464         if(pbox->y1 > drw_y + yoffset) {
4465            offsety  = (pbox->y1 - drw_y - yoffset) * srcPitch;
4466	    offsetuv = ((pbox->y1 - drw_y - yoffset) >> 1) * srcPitch;
4467         }
4468         if(pbox->x1 > drw_x + xoffset) {
4469            offsety += (pbox->x1 - drw_x - xoffset);
4470	    offsetuv += (pbox->x1 - drw_x - xoffset);
4471	    if(offsetuv & 1) {
4472	       offsety++;
4473	       offsetuv++;
4474	       MyPacket.P12_DstX++;
4475	       MyPacket.P12_RectWidth--;
4476	    }
4477         }
4478      }
4479
4480      if(!MyPacket.P12_RectWidth) continue;
4481
4482      MyPacket.P12_YSrcAddr  = pPriv->bufAddr[index][pPriv->currentBuf[index]] + offsety + FBOFFSET;
4483      MyPacket.P12_UVSrcAddr = pPriv->bufAddr[index][pPriv->currentBuf[index]] + bytesize + offsetuv + FBOFFSET;
4484      SISWriteBlitPacket(pSiS, (CARD32*)&MyPacket);
4485#if 0
4486      MyPacket.P12_Command &= ~(pPriv->VBlankTriggerCRT1 | pPriv->VBlankTriggerCRT2);
4487#endif
4488#if 0
4489#ifdef SISMERGED
4490      first = FALSE;
4491#endif
4492#endif
4493mycont:
4494      pbox++;
4495   }
4496
4497#if 0
4498   {
4499   int debug = 0;
4500   while( (SIS_MMIO_IN16(pSiS->IOBase, Q_STATUS+2) & 0x8000) != 0x8000) { debug++; };
4501   while( (SIS_MMIO_IN16(pSiS->IOBase, Q_STATUS+2) & 0x8000) != 0x8000) { debug++; };
4502   xf86DrvMsg(0, X_INFO, "vsync %d, debug %d\n", pPriv->vsync, debug);
4503   }
4504#endif
4505
4506   pPriv->currentBuf[index] ^= 1;
4507
4508   UpdateCurrentTime();
4509   pPriv->freeTime[index] = currentTime.milliseconds + FREE_DELAY;
4510   pPriv->videoStatus[index] = FREE_TIMER;
4511
4512   pSiS->VideoTimerCallback = SISVideoTimerCallback;
4513
4514   return Success;
4515}
4516
4517static int
4518SISQueryImageAttributesBlit(
4519  ScrnInfoPtr pScrn,
4520  int id,
4521  UShort *w, UShort *h,
4522  int *pitches, int *offsets
4523){
4524    int    pitchY, pitchUV;
4525    int    size, sizeY, sizeUV;
4526
4527    if(*w > DummyEncodingBlit.width) *w = DummyEncodingBlit.width;
4528    if(*h > DummyEncodingBlit.height) *h = DummyEncodingBlit.height;
4529
4530    switch(id) {
4531    case PIXEL_FMT_YV12:
4532    case PIXEL_FMT_I420:
4533	*w = (*w + 7) & ~7;
4534	*h = (*h + 1) & ~1;
4535	pitchY = *w;
4536	pitchUV = *w >> 1;
4537	if(pitches) {
4538	   pitches[0] = pitchY;
4539	   pitches[1] = pitches[2] = pitchUV;
4540	}
4541	sizeY = pitchY * (*h);
4542	sizeUV = pitchUV * ((*h) >> 1);
4543	if(offsets) {
4544	   offsets[0] = 0;
4545	   offsets[1] = sizeY;
4546	   offsets[2] = sizeY + sizeUV;
4547	}
4548	size = sizeY + (sizeUV << 1);
4549	break;
4550    case PIXEL_FMT_NV12:
4551    case PIXEL_FMT_NV21:
4552	*w = (*w + 7) & ~7;
4553	pitchY = *w;
4554	pitchUV = *w;
4555	if(pitches) {
4556	   pitches[0] = pitchY;
4557	   pitches[1] = pitchUV;
4558	}
4559	sizeY = pitchY * (*h);
4560	sizeUV = pitchUV * ((*h) >> 1);
4561	if(offsets) {
4562	   offsets[0] = 0;
4563	   offsets[1] = sizeY;
4564	}
4565	size = sizeY + (sizeUV << 1);
4566	break;
4567    case PIXEL_FMT_YUY2:
4568    case PIXEL_FMT_UYVY:
4569    case PIXEL_FMT_YVYU:
4570    default:
4571	*w = (*w + 1) & ~1;
4572	pitchY = *w << 1;
4573	if(pitches) pitches[0] = pitchY;
4574	if(offsets) offsets[0] = 0;
4575	size = pitchY * (*h);
4576	break;
4577    }
4578
4579    return size;
4580}
4581
4582static void
4583SISQueryBestSizeBlit(
4584  ScrnInfoPtr pScrn,
4585  Bool motion,
4586  short vid_w, short vid_h,
4587  short drw_w, short drw_h,
4588  unsigned int *p_w, unsigned int *p_h,
4589  ULong index
4590){
4591  /* We cannot scale */
4592  *p_w = vid_w;
4593  *p_h = vid_h;
4594}
4595#endif /* INCL_YUV */
4596
4597/*****************************************/
4598/*            TIMER CALLBACK             */
4599/*****************************************/
4600
4601static void
4602SISVideoTimerCallback(ScrnInfoPtr pScrn, Time now)
4603{
4604    SISPtr          pSiS = SISPTR(pScrn);
4605    SISPortPrivPtr  pPriv = NULL;
4606#ifdef INCL_YUV_BLIT_ADAPTOR
4607    SISBPortPrivPtr pPrivBlit = NULL;
4608#endif
4609    UChar           sridx, cridx;
4610    Bool	    setcallback = FALSE;
4611
4612    if(!pScrn->vtSema) return;
4613
4614    if(pSiS->adaptor) {
4615       pPriv = GET_PORT_PRIVATE(pScrn);
4616       if(!pPriv->videoStatus) pPriv = NULL;
4617    }
4618
4619    if(pPriv) {
4620       if(pPriv->videoStatus & TIMER_MASK) {
4621          if(pPriv->videoStatus & OFF_TIMER) {
4622	     setcallback = TRUE;
4623	     if(pPriv->offTime < now) {
4624                /* Turn off the overlay */
4625	        sridx = inSISREG(SISSR); cridx = inSISREG(SISCR);
4626                close_overlay(pSiS, pPriv);
4627	        outSISREG(SISSR, sridx); outSISREG(SISCR, cridx);
4628	        pPriv->mustwait = 1;
4629                pPriv->videoStatus = FREE_TIMER;
4630                pPriv->freeTime = now + FREE_DELAY;
4631	     }
4632          } else if(pPriv->videoStatus & FREE_TIMER) {
4633	     if(pPriv->freeTime < now) {
4634                SISFreeFBMemory(pScrn, &pPriv->handle);
4635	        pPriv->mustwait = 1;
4636                pPriv->videoStatus = 0;
4637             } else {
4638	        setcallback = TRUE;
4639	     }
4640          }
4641       }
4642    }
4643
4644#ifdef INCL_YUV_BLIT_ADAPTOR
4645    if(pSiS->blitadaptor) {
4646       int i;
4647       pPrivBlit = (SISBPortPrivPtr)(pSiS->blitPriv);
4648       for(i = 0; i < NUM_BLIT_PORTS; i++) {
4649          if(pPrivBlit->videoStatus[i] & FREE_TIMER) {
4650	     if(pPrivBlit->freeTime[i] < now) {
4651                SISFreeFBMemory(pScrn, &pPrivBlit->handle[i]);
4652                pPrivBlit->videoStatus[i] = 0;
4653	     } else {
4654	        setcallback = TRUE;
4655	     }
4656          }
4657       }
4658    }
4659#endif
4660
4661    pSiS->VideoTimerCallback = (setcallback) ? SISVideoTimerCallback : NULL;
4662}
4663
4664