172b676d7Smrg/*
272b676d7Smrg * Xv driver for SiS 5597/5598, 6326 and 530/620.
372b676d7Smrg *
472b676d7Smrg * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
572b676d7Smrg *
672b676d7Smrg * Redistribution and use in source and binary forms, with or without
772b676d7Smrg * modification, are permitted provided that the following conditions
872b676d7Smrg * are met:
972b676d7Smrg * 1) Redistributions of source code must retain the above copyright
1072b676d7Smrg *    notice, this list of conditions and the following disclaimer.
1172b676d7Smrg * 2) Redistributions in binary form must reproduce the above copyright
1272b676d7Smrg *    notice, this list of conditions and the following disclaimer in the
1372b676d7Smrg *    documentation and/or other materials provided with the distribution.
1472b676d7Smrg * 3) The name of the author may not be used to endorse or promote products
1572b676d7Smrg *    derived from this software without specific prior written permission.
1672b676d7Smrg *
1772b676d7Smrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1872b676d7Smrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1972b676d7Smrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2072b676d7Smrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2172b676d7Smrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2272b676d7Smrg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2372b676d7Smrg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2472b676d7Smrg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2572b676d7Smrg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2672b676d7Smrg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2772b676d7Smrg *
2872b676d7Smrg * Author:	Thomas Winischhofer <thomas@winischhofer.net>
2972b676d7Smrg *
3072b676d7Smrg */
3172b676d7Smrg
3272b676d7Smrg#ifdef HAVE_CONFIG_H
3372b676d7Smrg#include "config.h"
3472b676d7Smrg#endif
3572b676d7Smrg
3672b676d7Smrg#include "sis.h"
3772b676d7Smrg
3872b676d7Smrg#ifdef SIS_USE_XAA
3972b676d7Smrg#include "xf86fbman.h"
4072b676d7Smrg#endif
4172b676d7Smrg#include "xf86xv.h"
4272b676d7Smrg#include "regionstr.h"
4372b676d7Smrg#include <X11/extensions/Xv.h>
4472b676d7Smrg#include "dixstruct.h"
4572b676d7Smrg#include "fourcc.h"
4672b676d7Smrg
4772b676d7Smrg#define SIS_NEED_inSISREG
4872b676d7Smrg#define SIS_NEED_outSISREG
4972b676d7Smrg#define SIS_NEED_inSISIDXREG
5072b676d7Smrg#define SIS_NEED_outSISIDXREG
5172b676d7Smrg#define SIS_NEED_setSISIDXREGmask
5272b676d7Smrg#include "sis_regs.h"
5372b676d7Smrg
5472b676d7Smrg#define OFF_DELAY   	200  /* milliseconds */
5572b676d7Smrg#define FREE_DELAY  	60000
5672b676d7Smrg
5772b676d7Smrg#define OFF_TIMER   	0x01
5872b676d7Smrg#define FREE_TIMER  	0x02
5972b676d7Smrg#define CLIENT_VIDEO_ON 0x04
6072b676d7Smrg
6172b676d7Smrg#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
6272b676d7Smrg
6372b676d7Smrg#define WATCHDOG_DELAY  500000 /* Watchdog counter for Vertical Restrace waiting */
6472b676d7Smrg
6572b676d7Smrgstatic 		XF86VideoAdaptorPtr SIS6326SetupImageVideo(ScreenPtr);
6672b676d7Smrgstatic void 	SIS6326StopVideo(ScrnInfoPtr, pointer, Bool);
6772b676d7Smrgstatic int 	SIS6326SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
6872b676d7Smrgstatic int 	SIS6326GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
6972b676d7Smrgstatic void 	SIS6326QueryBestSize(ScrnInfoPtr, Bool, short, short, short,
7072b676d7Smrg			short, unsigned int *,unsigned int *, pointer);
7172b676d7Smrgstatic int 	SIS6326PutImage( ScrnInfoPtr,
7272b676d7Smrg			short, short, short, short, short, short, short, short,
7372b676d7Smrg			int, unsigned char*, short, short, Bool, RegionPtr, pointer,
7472b676d7Smrg			DrawablePtr);
7572b676d7Smrgstatic int 	SIS6326QueryImageAttributes(ScrnInfoPtr,
7672b676d7Smrg			int, unsigned short *, unsigned short *, int *, int *);
7772b676d7Smrgstatic void 	SIS6326VideoTimerCallback(ScrnInfoPtr pScrn, Time now);
7872b676d7Smrgstatic void     SIS6326InitOffscreenImages(ScreenPtr pScrn);
7972b676d7Smrg
8072b676d7Smrgextern unsigned int	SISAllocateFBMemory(ScrnInfoPtr pScrn, void **handle, int bytesize);
8172b676d7Smrgextern void		SISFreeFBMemory(ScrnInfoPtr pScrn, void **handle);
8272b676d7Smrg
8372b676d7Smrg#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
8472b676d7Smrg
8572b676d7Smrgstatic Atom xvBrightness, xvContrast, xvColorKey;
8672b676d7Smrgstatic Atom xvAutopaintColorKey, xvSetDefaults;
8772b676d7Smrgstatic Atom xvDisableGfx;
8872b676d7Smrg
8972b676d7Smrg#define IMAGE_MIN_WIDTH        32  /* Minimum and maximum image sizes */
9072b676d7Smrg#define IMAGE_MIN_HEIGHT       24
9172b676d7Smrg#define IMAGE_MAX_WIDTH       720  /* Are these correct for the chips ? */
9272b676d7Smrg#define IMAGE_MAX_HEIGHT      576
9372b676d7Smrg#define IMAGE_MAX_WIDTH_5597  384
9472b676d7Smrg#define IMAGE_MAX_HEIGHT_5597 288
9572b676d7Smrg
9672b676d7Smrg#if 0
9772b676d7Smrgstatic int oldH, oldW;
9872b676d7Smrg#endif
9972b676d7Smrg
10072b676d7Smrg/****************************************************************************
10172b676d7Smrg * Raw register access : These routines directly interact with the sis's
10272b676d7Smrg *                       control aperature.  Must not be called until after
10372b676d7Smrg *                       the board's pci memory has been mapped.
10472b676d7Smrg ****************************************************************************/
10572b676d7Smrg
10672b676d7Smrg#if 0
10772b676d7Smrgstatic CARD32 _sisread(SISPtr pSiS, CARD32 reg)
10872b676d7Smrg{
10972b676d7Smrg    return *(pSiS->IOBase + reg);
11072b676d7Smrg}
11172b676d7Smrg
11272b676d7Smrgstatic void _siswrite(SISPtr pSiS, CARD32 reg, CARD32 data)
11372b676d7Smrg{
11472b676d7Smrg    *(pSiS->IOBase + reg) = data;
11572b676d7Smrg}
11672b676d7Smrg#endif
11772b676d7Smrg
11872b676d7Smrgstatic CARD8 getvideoreg(SISPtr pSiS, CARD8 reg)
11972b676d7Smrg{
12072b676d7Smrg    CARD8 ret;
12172b676d7Smrg    inSISIDXREG(SISCR, reg, ret);
12272b676d7Smrg    return ret;
12372b676d7Smrg}
12472b676d7Smrg
12572b676d7Smrgstatic __inline void setvideoreg(SISPtr pSiS, CARD8 reg, CARD8 data)
12672b676d7Smrg{
12772b676d7Smrg    outSISIDXREG(SISCR, reg, data);
12872b676d7Smrg}
12972b676d7Smrg
13072b676d7Smrgstatic __inline void setvideoregmask(SISPtr pSiS, CARD8 reg, CARD8 data, CARD8 mask)
13172b676d7Smrg{
13272b676d7Smrg    setSISIDXREGmask(SISCR, reg, data, mask);
13372b676d7Smrg}
13472b676d7Smrg
13572b676d7Smrg/* VBlank */
13672b676d7Smrgstatic CARD8 vblank_active_CRT1(SISPtr pSiS)
13772b676d7Smrg{
13872b676d7Smrg    return (inSISREG(SISINPSTAT) & 0x08);
13972b676d7Smrg}
14072b676d7Smrg
14172b676d7Smrg/* Scanline - unused */
14272b676d7Smrg#if 0
14372b676d7Smrgstatic CARD32 get_scanline_CRT1(SISPtr pSiS)
14472b676d7Smrg{
14572b676d7Smrg    CARD8 temp;
14672b676d7Smrg
14772b676d7Smrg    temp = getvideoreg(pSiS, 0x20);
14872b676d7Smrg    temp = getvideoreg(pSiS, 0x1b);
14972b676d7Smrg    return((getvideoreg(pSiS, 0x1d) << 8) | getvideoreg(pSiS, 0x1c));
15072b676d7Smrg}
15172b676d7Smrg#endif
15272b676d7Smrg
15372b676d7Smrgvoid SIS6326InitVideo(ScreenPtr pScreen)
15472b676d7Smrg{
15574c14cd6Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
15672b676d7Smrg    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
15772b676d7Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
15872b676d7Smrg    int num_adaptors;
15972b676d7Smrg
16072b676d7Smrg    newAdaptor = SIS6326SetupImageVideo(pScreen);
16172b676d7Smrg    if(newAdaptor) {
16272b676d7Smrg        SIS6326InitOffscreenImages(pScreen);
16372b676d7Smrg    }
16472b676d7Smrg
16572b676d7Smrg    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
16672b676d7Smrg
16772b676d7Smrg    if(newAdaptor) {
16872b676d7Smrg	if(!num_adaptors) {
16972b676d7Smrg		num_adaptors = 1;
17072b676d7Smrg		adaptors = &newAdaptor;
17172b676d7Smrg	} else {
17272b676d7Smrg		/* need to free this someplace */
17374c14cd6Smrg		newAdaptors = malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
17472b676d7Smrg		if(newAdaptors) {
17572b676d7Smrg			memcpy(newAdaptors, adaptors, num_adaptors *
17672b676d7Smrg				sizeof(XF86VideoAdaptorPtr));
17772b676d7Smrg			newAdaptors[num_adaptors] = newAdaptor;
17872b676d7Smrg			adaptors = newAdaptors;
17972b676d7Smrg			num_adaptors++;
18072b676d7Smrg		}
18172b676d7Smrg	}
18272b676d7Smrg    }
18372b676d7Smrg
18472b676d7Smrg    if(num_adaptors)
18572b676d7Smrg	xf86XVScreenInit(pScreen, adaptors, num_adaptors);
18672b676d7Smrg
18772b676d7Smrg    if(newAdaptors)
18874c14cd6Smrg	free(newAdaptors);
18972b676d7Smrg}
19072b676d7Smrg
19172b676d7Smrg/* client libraries expect an encoding */
19272b676d7Smrgstatic XF86VideoEncodingRec DummyEncoding =
19372b676d7Smrg{
19472b676d7Smrg   0,
19572b676d7Smrg   "XV_IMAGE",
19672b676d7Smrg   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
19772b676d7Smrg   {1, 1}
19872b676d7Smrg};
19972b676d7Smrg
20072b676d7Smrgstatic XF86VideoEncodingRec DummyEncoding5597 =
20172b676d7Smrg{
20272b676d7Smrg   0,
20372b676d7Smrg   "XV_IMAGE",
20472b676d7Smrg   IMAGE_MAX_WIDTH_5597, IMAGE_MAX_HEIGHT_5597,
20572b676d7Smrg   {1, 1}
20672b676d7Smrg};
20772b676d7Smrg
20872b676d7Smrg#define NUM_FORMATS 4
20972b676d7Smrg
21072b676d7Smrgstatic XF86VideoFormatRec SIS6326Formats[NUM_FORMATS] =
21172b676d7Smrg{
21272b676d7Smrg   { 8, PseudoColor},
21372b676d7Smrg   {15, TrueColor},
21472b676d7Smrg   {16, TrueColor},
21572b676d7Smrg   {24, TrueColor}
21672b676d7Smrg};
21772b676d7Smrg
21872b676d7Smrg#define NUM_ATTRIBUTES 6
21972b676d7Smrg
22072b676d7Smrgstatic XF86AttributeRec SIS6326Attributes[NUM_ATTRIBUTES] =
22172b676d7Smrg{
22272b676d7Smrg   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
22372b676d7Smrg   {XvSettable | XvGettable, -128, 127,        "XV_BRIGHTNESS"},
22472b676d7Smrg   {XvSettable | XvGettable, 0, 7,             "XV_CONTRAST"},
22572b676d7Smrg   {XvSettable | XvGettable, 0, 1,             "XV_AUTOPAINT_COLORKEY"},
22672b676d7Smrg   {XvSettable             , 0, 0,             "XV_SET_DEFAULTS"},
22772b676d7Smrg   {XvSettable | XvGettable, 0, 1,             "XV_DISABLE_GRAPHICS"}
22872b676d7Smrg};
22972b676d7Smrg
23072b676d7Smrg#define NUM_IMAGES 6
23172b676d7Smrg#define NUM_IMAGES_NOYV12 4
23272b676d7Smrg#define PIXEL_FMT_YV12 FOURCC_YV12  /* 0x32315659 */
23372b676d7Smrg#define PIXEL_FMT_UYVY FOURCC_UYVY  /* 0x59565955 */
23472b676d7Smrg#define PIXEL_FMT_YUY2 FOURCC_YUY2  /* 0x32595559 */
23572b676d7Smrg#define PIXEL_FMT_I420 FOURCC_I420  /* 0x30323449 */
23672b676d7Smrg#define PIXEL_FMT_RGB5 0x35315652
23772b676d7Smrg#define PIXEL_FMT_RGB6 0x36315652
23872b676d7Smrg
23972b676d7Smrgstatic XF86ImageRec SIS6326Images[NUM_IMAGES] =
24072b676d7Smrg{
24172b676d7Smrg    XVIMAGE_YUY2, /* If order is changed, SIS6326OffscreenImages must be adapted */
24272b676d7Smrg    XVIMAGE_UYVY,
24372b676d7Smrg    XVIMAGE_YV12,
24472b676d7Smrg    XVIMAGE_I420,
24572b676d7Smrg    {
24672b676d7Smrg      0x35315652,
24772b676d7Smrg      XvRGB,
24872b676d7Smrg      LSBFirst,
24972b676d7Smrg      {'R','V','1','5',
25072b676d7Smrg       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
25172b676d7Smrg      16,
25272b676d7Smrg      XvPacked,
25372b676d7Smrg      1,
25472b676d7Smrg      15, 0x7C00, 0x03E0, 0x001F,
25572b676d7Smrg      0, 0, 0,
25672b676d7Smrg      0, 0, 0,
25772b676d7Smrg      0, 0, 0,
25872b676d7Smrg      {'R', 'V', 'B',0,
25972b676d7Smrg       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
26072b676d7Smrg      XvTopToBottom
26172b676d7Smrg    },
26272b676d7Smrg    {
26372b676d7Smrg      0x36315652,
26472b676d7Smrg      XvRGB,
26572b676d7Smrg      LSBFirst,
26672b676d7Smrg      {'R','V','1','6',
26772b676d7Smrg       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
26872b676d7Smrg      16,
26972b676d7Smrg      XvPacked,
27072b676d7Smrg      1,
27172b676d7Smrg      16, 0xF800, 0x07E0, 0x001F,
27272b676d7Smrg      0, 0, 0,
27372b676d7Smrg      0, 0, 0,
27472b676d7Smrg      0, 0, 0,
27572b676d7Smrg      {'R', 'V', 'B',0,
27672b676d7Smrg       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
27772b676d7Smrg      XvTopToBottom
27872b676d7Smrg    }
27972b676d7Smrg};
28072b676d7Smrg
28172b676d7Smrgstatic XF86ImageRec SIS6326ImagesNoYV12[NUM_IMAGES_NOYV12] =
28272b676d7Smrg{
28372b676d7Smrg    XVIMAGE_YUY2, /* If order is changed, SIS6326OffscreenImages must be adapted */
28472b676d7Smrg    XVIMAGE_UYVY,
28572b676d7Smrg    {
28672b676d7Smrg      0x35315652,
28772b676d7Smrg      XvRGB,
28872b676d7Smrg      LSBFirst,
28972b676d7Smrg      {'R','V','1','5',
29072b676d7Smrg       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
29172b676d7Smrg      16,
29272b676d7Smrg      XvPacked,
29372b676d7Smrg      1,
29472b676d7Smrg      15, 0x7C00, 0x03E0, 0x001F,
29572b676d7Smrg      0, 0, 0,
29672b676d7Smrg      0, 0, 0,
29772b676d7Smrg      0, 0, 0,
29872b676d7Smrg      {'R', 'V', 'B',0,
29972b676d7Smrg       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
30072b676d7Smrg      XvTopToBottom
30172b676d7Smrg    },
30272b676d7Smrg    {
30372b676d7Smrg      0x36315652,
30472b676d7Smrg      XvRGB,
30572b676d7Smrg      LSBFirst,
30672b676d7Smrg      {'R','V','1','6',
30772b676d7Smrg       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
30872b676d7Smrg      16,
30972b676d7Smrg      XvPacked,
31072b676d7Smrg      1,
31172b676d7Smrg      16, 0xF800, 0x07E0, 0x001F,
31272b676d7Smrg      0, 0, 0,
31372b676d7Smrg      0, 0, 0,
31472b676d7Smrg      0, 0, 0,
31572b676d7Smrg      {'R', 'V', 'B',0,
31672b676d7Smrg       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
31772b676d7Smrg      XvTopToBottom
31872b676d7Smrg    }
31972b676d7Smrg};
32072b676d7Smrg
32172b676d7Smrgtypedef struct {
32272b676d7Smrg    int pixelFormat;
32372b676d7Smrg
32472b676d7Smrg    CARD16  pitch;
32572b676d7Smrg
32672b676d7Smrg    CARD8   keyOP;
32772b676d7Smrg
32872b676d7Smrg    CARD8   HUSF;
32972b676d7Smrg    CARD8   VUSF;
33072b676d7Smrg    CARD8   HIntBit;
33172b676d7Smrg    CARD8   wHPre;
33272b676d7Smrg    CARD8   PitchMult;
33372b676d7Smrg
33472b676d7Smrg    CARD16  srcW;
33572b676d7Smrg    CARD16  srcH;
33672b676d7Smrg
33772b676d7Smrg    BoxRec  dstBox;
33872b676d7Smrg
33972b676d7Smrg    CARD32  PSY;
34072b676d7Smrg    CARD32  PSV;
34172b676d7Smrg    CARD32  PSU;
34272b676d7Smrg    CARD8   YUVEnd;
34372b676d7Smrg
34472b676d7Smrg    CARD8   lineBufSize;
34572b676d7Smrg
34672b676d7Smrg    CARD8   (*VBlankActiveFunc)(SISPtr);
34772b676d7Smrg/*  CARD32  (*GetScanLineFunc)(SISPtr pSiS); */
34872b676d7Smrg
34972b676d7Smrg} SISOverlayRec, *SISOverlayPtr;
35072b676d7Smrg
35172b676d7Smrgtypedef struct {
35272b676d7Smrg    void *       handle;
35372b676d7Smrg    CARD32       bufAddr[2];
35472b676d7Smrg
35572b676d7Smrg    unsigned char currentBuf;
35672b676d7Smrg
35772b676d7Smrg    short  drw_x, drw_y, drw_w, drw_h;
35872b676d7Smrg    short  src_x, src_y, src_w, src_h;
35972b676d7Smrg    int    id;
36072b676d7Smrg    short  srcPitch, height, width;
36172b676d7Smrg    CARD32 totalSize;
36272b676d7Smrg
36372b676d7Smrg    char          brightness;
36472b676d7Smrg    unsigned char contrast;
36572b676d7Smrg
36672b676d7Smrg    RegionRec    clip;
36772b676d7Smrg    CARD32       colorKey;
36872b676d7Smrg    Bool 	 autopaintColorKey;
36972b676d7Smrg
37072b676d7Smrg    Bool 	 disablegfx;
37172b676d7Smrg
37272b676d7Smrg    CARD32       videoStatus;
37372b676d7Smrg    Time         offTime;
37472b676d7Smrg    Time         freeTime;
37572b676d7Smrg
37672b676d7Smrg    short        oldx1, oldx2, oldy1, oldy2;
37772b676d7Smrg    int          mustwait;
37872b676d7Smrg
37972b676d7Smrg    Bool         grabbedByV4L;	   /* V4L stuff */
38072b676d7Smrg    int          pitch;
38172b676d7Smrg    int          offset;
38272b676d7Smrg
38372b676d7Smrg} SISPortPrivRec, *SISPortPrivPtr;
38472b676d7Smrg
38572b676d7Smrg#define GET_PORT_PRIVATE(pScrn) \
38672b676d7Smrg   (SISPortPrivPtr)((SISPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
38772b676d7Smrg
38872b676d7Smrgstatic void
38972b676d7SmrgSIS6326SetPortDefaults(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
39072b676d7Smrg{
39172b676d7Smrg    SISPtr    pSiS = SISPTR(pScrn);
39272b676d7Smrg
39372b676d7Smrg    pPriv->colorKey    = 0x000101fe;
39472b676d7Smrg    pPriv->videoStatus = 0;
39572b676d7Smrg    pPriv->brightness  = pSiS->XvDefBri; /* 0; - see sis_opt.c */
39672b676d7Smrg    pPriv->contrast    = pSiS->XvDefCon; /* 4; */
39772b676d7Smrg    pPriv->autopaintColorKey = TRUE;
39872b676d7Smrg    pPriv->disablegfx  = pSiS->XvDefDisableGfx;
39972b676d7Smrg}
40072b676d7Smrg
40172b676d7Smrgstatic void
40272b676d7SmrgSIS6326ResetVideo(ScrnInfoPtr pScrn)
40372b676d7Smrg{
40472b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
40572b676d7Smrg
40672b676d7Smrg    /* Unlock registers */
40772b676d7Smrg#ifdef UNLOCK_ALWAYS
40872b676d7Smrg    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
40972b676d7Smrg#endif
41072b676d7Smrg    if(getvideoreg(pSiS, Index_VI6326_Passwd) != 0xa1) {
41172b676d7Smrg       setvideoreg(pSiS, Index_VI6326_Passwd, 0x86);
41272b676d7Smrg       if(getvideoreg(pSiS, Index_VI6326_Passwd) != 0xa1)
41372b676d7Smrg          xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
41472b676d7Smrg                     "Xv: Video password could not unlock video registers\n");
41572b676d7Smrg    }
41672b676d7Smrg
41772b676d7Smrg    /* Initialize the overlay ----------------------------------- */
41872b676d7Smrg
41972b676d7Smrg    switch(pSiS->Chipset) {
42072b676d7Smrg    case PCI_CHIP_SIS5597:
42172b676d7Smrg       /* Disable overlay (D[1]) & capture (D[0]) */
42272b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x03);
42372b676d7Smrg
42472b676d7Smrg       /* What do these do? (Datasheet names these bits "reserved") */
42572b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x18);
42672b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x0c);
42772b676d7Smrg
42872b676d7Smrg       /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */
42972b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x40, 0xD0);
43072b676d7Smrg       /* No interrupt, no filter, disable dithering */
43172b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc1,     0x00, 0x7A);
43272b676d7Smrg       /* Disable Brooktree support (D[6]) and system memory framebuffer (D[7]) */
43372b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc3,     0x00, 0xC0);
43472b676d7Smrg       /* Disable video decimation (has a really strange effect if enabled) */
43572b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc6,     0x00, 0x80);
43672b676d7Smrg       break;
43772b676d7Smrg    case PCI_CHIP_SIS6326:
43872b676d7Smrg       /* Disable overlay (D[1]) & capture (D[0]) */
43972b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x03);
44072b676d7Smrg
44172b676d7Smrg       /* What do these do? (Datasheet names these bits "reserved") */
44272b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x18);
44372b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x0c);
44472b676d7Smrg
44572b676d7Smrg       /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */
44672b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x40, 0xD0);
44772b676d7Smrg       /* No interrupt, no filter, disable dithering */
44872b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc1,     0x00, 0x7A);
44972b676d7Smrg       /* Disable VMI (D[4:3]), Brooktree support (D[6]) and system memory framebuffer (D[7]) */
45072b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc3,     0x00, 0xF8);
45172b676d7Smrg       /* Disable video decimation */
45272b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc6,     0x00, 0x80);
45372b676d7Smrg       break;
45472b676d7Smrg    case PCI_CHIP_SIS530:
45572b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc4,     0x40, 0x40);
45672b676d7Smrg       /* Disable overlay (D[1]) */
45772b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x02);
45872b676d7Smrg
45972b676d7Smrg       /* What do D[3:2] do? (Datasheet names these bits "reserved") */
46072b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x18);
46172b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x0c);
46272b676d7Smrg
46372b676d7Smrg       /* Select YUV format (D[6]) and "gfx + video" mode (D[4]) */
46472b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x40, 0x50);
46572b676d7Smrg       break;
46672b676d7Smrg    default:
46772b676d7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
46872b676d7Smrg		"Internal error: SiS6326ResetVideo() called with invalid chipset (%x)\n",
46972b676d7Smrg		pSiS->Chipset);
47072b676d7Smrg        return;
47172b676d7Smrg    }
47272b676d7Smrg
47372b676d7Smrg    /* Clear format selection */
47472b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Control_Misc1,         0x00, 0x04);
47572b676d7Smrg    if(pSiS->oldChipset >= OC_SIS5597) {
47672b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc4,      0x00, 0x05);
47772b676d7Smrg    }
47872b676d7Smrg
47972b676d7Smrg    /* Select RGB Chromakey format (D[2]=0), CCIR 601 UV data format (D[1]=0) */
48072b676d7Smrg    /* D[1]: 1 = 2's complement, 0 = CCIR 601 format */
48172b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Control_Misc3,         0x00, 0x06);
48272b676d7Smrg
48372b676d7Smrg    /* Reset contrast control */
48472b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl,     0x04, 0x1F);
48572b676d7Smrg
48672b676d7Smrg    /* Set threshold */
48772b676d7Smrg    if(pSiS->oldChipset < OC_SIS6326) {
48872b676d7Smrg       CARD8 temp;
48972b676d7Smrg       inSISIDXREG(SISSR, 0x33, temp);  /* Synchronous DRAM Timing? */
49072b676d7Smrg       if(temp & 0x01) temp = 0x50;
49172b676d7Smrg       else            temp = 0;
49272b676d7Smrg       setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low,     temp);
49372b676d7Smrg       setvideoreg(pSiS, Index_VI6326_Play_Threshold_High,    temp);
49472b676d7Smrg    } else {
49572b676d7Smrg       CARD8 temp;
49672b676d7Smrg       setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low,     0x00);
49772b676d7Smrg       setvideoreg(pSiS, Index_VI6326_Play_Threshold_High,    0x00);
49872b676d7Smrg       inSISIDXREG(SISSR, 0x33, temp);  /* Are we using SGRAM Timing? */
49972b676d7Smrg       if(temp & 0x01) temp = 0x10;
50072b676d7Smrg       else            temp = 0;
50172b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc4,      temp, 0x10);
50272b676d7Smrg    }
50372b676d7Smrg
50472b676d7Smrg    /* set default properties for overlay     ------------------------------- */
50572b676d7Smrg
50672b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl,    0x04, 0x07);
50772b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Brightness,               0x20);
50872b676d7Smrg
50972b676d7Smrg    if(pSiS->oldChipset < OC_SIS6205A || pSiS->oldChipset > OC_SIS82204) {
51072b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_AlphaGraph,         0x00, 0xF8);
51172b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_AlphaVideo,         0xF8, 0xF8);
51272b676d7Smrg    } else {
51372b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_AlphaGraph,         0x00, 0xE1);
51472b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_AlphaVideo,         0xE1, 0xE1);
51572b676d7Smrg    }
51672b676d7Smrg
51772b676d7Smrg}
51872b676d7Smrg
51972b676d7Smrgstatic XF86VideoAdaptorPtr
52072b676d7SmrgSIS6326SetupImageVideo(ScreenPtr pScreen)
52172b676d7Smrg{
52274c14cd6Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
52372b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
52472b676d7Smrg    XF86VideoAdaptorPtr adapt;
52572b676d7Smrg    SISPortPrivPtr pPriv;
52672b676d7Smrg
52772b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
52872b676d7Smrg    XAAInfoRecPtr pXAA = pSiS->AccelInfoPtr;
52972b676d7Smrg
53072b676d7Smrg    if(!pXAA || !pXAA->FillSolidRects)
53172b676d7Smrg       return NULL;
53272b676d7Smrg#endif
53372b676d7Smrg
53474c14cd6Smrg    if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
53572b676d7Smrg                            sizeof(SISPortPrivRec) +
53672b676d7Smrg                            sizeof(DevUnion))))
53772b676d7Smrg       return NULL;
53872b676d7Smrg
53972b676d7Smrg    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
54072b676d7Smrg    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
54172b676d7Smrg    adapt->name = "SIS 5597/5598/6326/530/620 Video Overlay";
54272b676d7Smrg    adapt->nEncodings = 1;
54372b676d7Smrg    if(pSiS->oldChipset < OC_SIS6326) {
54472b676d7Smrg       adapt->pEncodings = &DummyEncoding5597;
54572b676d7Smrg    } else {
54672b676d7Smrg       adapt->pEncodings = &DummyEncoding;
54772b676d7Smrg    }
54872b676d7Smrg    adapt->nFormats = NUM_FORMATS;
54972b676d7Smrg    adapt->pFormats = SIS6326Formats;
55072b676d7Smrg    adapt->nPorts = 1;
55172b676d7Smrg    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
55272b676d7Smrg
55372b676d7Smrg    pPriv = (SISPortPrivPtr)(&adapt->pPortPrivates[1]);
55472b676d7Smrg
55572b676d7Smrg    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
55672b676d7Smrg    adapt->pAttributes = SIS6326Attributes;
55772b676d7Smrg    adapt->nAttributes = NUM_ATTRIBUTES;
55872b676d7Smrg    if(pSiS->NoYV12 == 1) {
55972b676d7Smrg       adapt->nImages = NUM_IMAGES_NOYV12;
56072b676d7Smrg       adapt->pImages = SIS6326ImagesNoYV12;
56172b676d7Smrg    } else {
56272b676d7Smrg       adapt->nImages = NUM_IMAGES;
56372b676d7Smrg       adapt->pImages = SIS6326Images;
56472b676d7Smrg    }
56572b676d7Smrg    adapt->PutVideo = NULL;
56672b676d7Smrg    adapt->PutStill = NULL;
56772b676d7Smrg    adapt->GetVideo = NULL;
56872b676d7Smrg    adapt->GetStill = NULL;
56972b676d7Smrg    adapt->StopVideo = SIS6326StopVideo;
57072b676d7Smrg    adapt->SetPortAttribute = SIS6326SetPortAttribute;
57172b676d7Smrg    adapt->GetPortAttribute = SIS6326GetPortAttribute;
57272b676d7Smrg    adapt->QueryBestSize = SIS6326QueryBestSize;
57372b676d7Smrg    adapt->PutImage = SIS6326PutImage;
57472b676d7Smrg    adapt->QueryImageAttributes = SIS6326QueryImageAttributes;
57572b676d7Smrg
57672b676d7Smrg    pPriv->videoStatus = 0;
57772b676d7Smrg    pPriv->currentBuf  = 0;
57872b676d7Smrg    pPriv->handle      = NULL;
57972b676d7Smrg    pPriv->grabbedByV4L= FALSE;
58072b676d7Smrg
58172b676d7Smrg    SIS6326SetPortDefaults(pScrn, pPriv);
58272b676d7Smrg
58372b676d7Smrg    /* gotta uninit this someplace */
58472b676d7Smrg#if defined(REGION_NULL)
58572b676d7Smrg    REGION_NULL(pScreen, &pPriv->clip);
58672b676d7Smrg#else
58772b676d7Smrg    REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
58872b676d7Smrg#endif
58972b676d7Smrg
59072b676d7Smrg    pSiS->adaptor = adapt;
59172b676d7Smrg
59272b676d7Smrg    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
59372b676d7Smrg    xvContrast   = MAKE_ATOM("XV_CONTRAST");
59472b676d7Smrg    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
59572b676d7Smrg    xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
59672b676d7Smrg    xvSetDefaults       = MAKE_ATOM("XV_SET_DEFAULTS");
59772b676d7Smrg    xvDisableGfx = MAKE_ATOM("XV_DISABLE_GRAPHICS");
59872b676d7Smrg
59972b676d7Smrg    SIS6326ResetVideo(pScrn);
60072b676d7Smrg    pSiS->ResetXv = SIS6326ResetVideo;
60172b676d7Smrg
60272b676d7Smrg    return adapt;
60372b676d7Smrg}
60472b676d7Smrg
60572b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
60672b676d7Smrgstatic Bool
60772b676d7SmrgRegionsEqual(RegionPtr A, RegionPtr B)
60872b676d7Smrg{
60972b676d7Smrg    int *dataA, *dataB;
61072b676d7Smrg    int num;
61172b676d7Smrg
61272b676d7Smrg    num = REGION_NUM_RECTS(A);
61372b676d7Smrg    if(num != REGION_NUM_RECTS(B))
61472b676d7Smrg    return FALSE;
61572b676d7Smrg
61672b676d7Smrg    if((A->extents.x1 != B->extents.x1) ||
61772b676d7Smrg       (A->extents.x2 != B->extents.x2) ||
61872b676d7Smrg       (A->extents.y1 != B->extents.y1) ||
61972b676d7Smrg       (A->extents.y2 != B->extents.y2))
62072b676d7Smrg    return FALSE;
62172b676d7Smrg
62272b676d7Smrg    dataA = (int*)REGION_RECTS(A);
62372b676d7Smrg    dataB = (int*)REGION_RECTS(B);
62472b676d7Smrg
62572b676d7Smrg    while(num--) {
62672b676d7Smrg      if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
62772b676d7Smrg        return FALSE;
62872b676d7Smrg      dataA += 2;
62972b676d7Smrg      dataB += 2;
63072b676d7Smrg    }
63172b676d7Smrg
63272b676d7Smrg    return TRUE;
63372b676d7Smrg}
63472b676d7Smrg#endif
63572b676d7Smrg
63672b676d7Smrgstatic int
63772b676d7SmrgSIS6326SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
63872b676d7Smrg		    INT32 value, pointer data)
63972b676d7Smrg{
64072b676d7Smrg  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
64172b676d7Smrg
64272b676d7Smrg  if(attribute == xvBrightness) {
64372b676d7Smrg     if((value < -128) || (value > 127))
64472b676d7Smrg        return BadValue;
64572b676d7Smrg     pPriv->brightness = value;
64672b676d7Smrg  } else if(attribute == xvContrast) {
64772b676d7Smrg     if((value < 0) || (value > 7))
64872b676d7Smrg        return BadValue;
64972b676d7Smrg     pPriv->contrast = value;
65072b676d7Smrg  } else if(attribute == xvColorKey) {
65172b676d7Smrg     pPriv->colorKey = value;
65272b676d7Smrg     REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
65372b676d7Smrg  } else if (attribute == xvAutopaintColorKey) {
65472b676d7Smrg     if((value < 0) || (value > 1))
65572b676d7Smrg        return BadValue;
65672b676d7Smrg     pPriv->autopaintColorKey = value;
65772b676d7Smrg  } else if(attribute == xvDisableGfx) {
65872b676d7Smrg     if((value < 0) || (value > 1))
65972b676d7Smrg        return BadValue;
66072b676d7Smrg     pPriv->disablegfx = value;
66172b676d7Smrg  } else if (attribute == xvSetDefaults) {
66272b676d7Smrg     SIS6326SetPortDefaults(pScrn, pPriv);
66372b676d7Smrg  } else return BadMatch;
66472b676d7Smrg  return Success;
66572b676d7Smrg}
66672b676d7Smrg
66772b676d7Smrgstatic int
66872b676d7SmrgSIS6326GetPortAttribute(
66972b676d7Smrg  ScrnInfoPtr pScrn,
67072b676d7Smrg  Atom attribute,
67172b676d7Smrg  INT32 *value,
67272b676d7Smrg  pointer data
67372b676d7Smrg){
67472b676d7Smrg  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
67572b676d7Smrg
67672b676d7Smrg  if(attribute == xvBrightness) {
67772b676d7Smrg     *value = pPriv->brightness;
67872b676d7Smrg  } else if(attribute == xvContrast) {
67972b676d7Smrg     *value = pPriv->contrast;
68072b676d7Smrg  } else if(attribute == xvColorKey) {
68172b676d7Smrg     *value = pPriv->colorKey;
68272b676d7Smrg  } else if (attribute == xvAutopaintColorKey) {
68372b676d7Smrg     *value = (pPriv->autopaintColorKey) ? 1 : 0;
68472b676d7Smrg  } else if (attribute == xvDisableGfx) {
68572b676d7Smrg     *value = (pPriv->disablegfx) ? 1 : 0;
68672b676d7Smrg  } else return BadMatch;
68772b676d7Smrg  return Success;
68872b676d7Smrg}
68972b676d7Smrg
69072b676d7Smrgstatic void
69172b676d7SmrgSIS6326QueryBestSize(
69272b676d7Smrg  ScrnInfoPtr pScrn,
69372b676d7Smrg  Bool motion,
69472b676d7Smrg  short vid_w, short vid_h,
69572b676d7Smrg  short drw_w, short drw_h,
69672b676d7Smrg  unsigned int *p_w, unsigned int *p_h,
69772b676d7Smrg  pointer data
69872b676d7Smrg){
69972b676d7Smrg  *p_w = drw_w;
70072b676d7Smrg  *p_h = drw_h;
70172b676d7Smrg
70272b676d7Smrg  /* TODO: report the HW limitation */
70372b676d7Smrg}
70472b676d7Smrg
70572b676d7Smrgstatic void  /* V 530/6326 */
70672b676d7Smrgcalc_scale_factor(SISPtr pSiS, SISOverlayPtr pOverlay, ScrnInfoPtr pScrn,
70772b676d7Smrg                 SISPortPrivPtr pPriv)
70872b676d7Smrg{
70972b676d7Smrg  CARD32 temp=0;
71072b676d7Smrg
71172b676d7Smrg  int dstW = pOverlay->dstBox.x2 - pOverlay->dstBox.x1;
71272b676d7Smrg  int dstH = pOverlay->dstBox.y2 - pOverlay->dstBox.y1;
71372b676d7Smrg  int srcW = pOverlay->srcW;
71472b676d7Smrg  int srcH = pOverlay->srcH;
71572b676d7Smrg
71672b676d7Smrg  /* For double scan modes, we need to double the height */
71772b676d7Smrg  if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) {
71872b676d7Smrg	dstH <<= 1;
71972b676d7Smrg  }
72072b676d7Smrg  /* For interlace modes, we need to half the height */
72172b676d7Smrg  if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) {
72272b676d7Smrg	dstH >>= 1;
72372b676d7Smrg  }
72472b676d7Smrg
72572b676d7Smrg  /* Horizontal */
72672b676d7Smrg  if(dstW < IMAGE_MIN_WIDTH) dstW = IMAGE_MIN_WIDTH;
72772b676d7Smrg  if(dstW == srcW) {
72872b676d7Smrg	pOverlay->HUSF    = 0x00;
72972b676d7Smrg	pOverlay->HIntBit = 0x01;
73072b676d7Smrg  } else if(dstW > srcW) {
73172b676d7Smrg	pOverlay->HIntBit = 0x00;
73272b676d7Smrg	temp = srcW * 64 / (dstW + 1);
73372b676d7Smrg	if(temp > 63) temp = 63;
73472b676d7Smrg	pOverlay->HUSF = temp;
73572b676d7Smrg  } else {
73672b676d7Smrg	/* 6326 can't scale below factor .440 - to check with 530/620 */
73772b676d7Smrg	if(((dstW * 1000) / srcW) < 440) dstW = ((srcW * 440) / 1000) + 1;
73872b676d7Smrg	temp = srcW / dstW;
73972b676d7Smrg	if(temp > 15) temp = 15;
74072b676d7Smrg	pOverlay->HIntBit = temp;
74172b676d7Smrg	temp = srcW * 64 / dstW;
74272b676d7Smrg	pOverlay->HUSF = temp - (pOverlay->HIntBit * 64);
74372b676d7Smrg  }
74472b676d7Smrg
74572b676d7Smrg  /* Vertical */
74672b676d7Smrg  if(dstH < IMAGE_MIN_HEIGHT) dstH = IMAGE_MIN_HEIGHT;
74772b676d7Smrg  if(dstH == srcH) {
74872b676d7Smrg	pOverlay->VUSF = 0x00;
74972b676d7Smrg	pOverlay->PitchMult = 1;
75072b676d7Smrg  } else if(dstH > srcH) {
75172b676d7Smrg	temp = srcH * 64 / (dstH + 1);
75272b676d7Smrg	if (temp > 63) temp = 63;
75372b676d7Smrg	pOverlay->VUSF = temp;
75472b676d7Smrg	pOverlay->PitchMult = 1;
75572b676d7Smrg  } else {
75672b676d7Smrg	/* 6326 can't scale below factor .440 - to check with 530/620 */
75772b676d7Smrg	if(((dstH * 1000) / srcH) < 440) dstH = ((srcH * 440) / 1000) + 1;
75872b676d7Smrg	temp = srcH / dstH;
75972b676d7Smrg	if(srcH % dstH) {
76072b676d7Smrg	   temp++;
76172b676d7Smrg	   pOverlay->VUSF = (srcH * 64) / (temp * dstH);
76272b676d7Smrg	} else {
76372b676d7Smrg	   pOverlay->VUSF = 0x00;
76472b676d7Smrg	}
76572b676d7Smrg	pOverlay->PitchMult = temp;
76672b676d7Smrg  }
76772b676d7Smrg}
76872b676d7Smrg
76972b676d7Smrgstatic void
77072b676d7Smrgcalc_line_buf_size(SISOverlayPtr pOverlay)
77172b676d7Smrg{
77272b676d7Smrg    CARD32 I;
77372b676d7Smrg    CARD32 line = pOverlay->srcW;
77472b676d7Smrg
77572b676d7Smrg    if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
77672b676d7Smrg        (pOverlay->pixelFormat == PIXEL_FMT_I420) ) {
77772b676d7Smrg	I = (line >> 5) + (((line >> 6) * 2)) + 3;
77872b676d7Smrg	I <<= 5;
77972b676d7Smrg    } else { /* YUV2, UYVY, RGB */
78072b676d7Smrg	I = line << 1;
78172b676d7Smrg	if(I & 7)  I += 8;
78272b676d7Smrg    }
78372b676d7Smrg    I += 8;
78472b676d7Smrg    I >>= 3;
78572b676d7Smrg    pOverlay->lineBufSize = (CARD8)I;
78672b676d7Smrg}
78772b676d7Smrg
78872b676d7Smrgstatic void
78972b676d7Smrgmerge_line_buf(SISPtr pSiS, SISPortPrivPtr pPriv, Bool enable)
79072b676d7Smrg{
79172b676d7Smrg  if(enable) {
79272b676d7Smrg     setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x10, 0x10);
79372b676d7Smrg  } else {
79472b676d7Smrg     setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x00, 0x10);
79572b676d7Smrg  }
79672b676d7Smrg}
79772b676d7Smrg
79872b676d7Smrgstatic void
79972b676d7Smrgset_format(SISPtr pSiS, SISOverlayPtr pOverlay)
80072b676d7Smrg{
80172b676d7Smrg    CARD8 fmt, misc0, misc1, misc4;
80272b676d7Smrg
80372b676d7Smrg    switch(pOverlay->pixelFormat) {
80472b676d7Smrg    case PIXEL_FMT_YV12:
80572b676d7Smrg    case PIXEL_FMT_I420: /* V/530 V/6326 */
80672b676d7Smrg	fmt   = 0x80;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
80772b676d7Smrg	misc0 = 0x40;  /* D[6]: 1 = YUV, 0 = RGB */
80872b676d7Smrg	misc4 = 0x05;  /* D[1:0] 00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
80972b676d7Smrg	misc1 = 0xff;
81072b676d7Smrg	break;
81172b676d7Smrg    case PIXEL_FMT_UYVY:
81272b676d7Smrg	fmt   = 0x00;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
81372b676d7Smrg	misc0 = 0x40;  /* D[6]: 1 = YUV, 0 = RGB */
81472b676d7Smrg	misc4 = 0x00;  /* D[1:0] 00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
81572b676d7Smrg	misc1 = 0xff;
81672b676d7Smrg	break;
81772b676d7Smrg    case PIXEL_FMT_YUY2: /* V/530 V/6326 */
81872b676d7Smrg	fmt   = 0x80;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
81972b676d7Smrg	misc0 = 0x40;  /* D[6]: 1 = YUV, 0 = RGB */
82072b676d7Smrg	misc4 = 0x00;  /* D[1:0]  00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
82172b676d7Smrg	misc1 = 0xff;
82272b676d7Smrg	break;
82372b676d7Smrg    case PIXEL_FMT_RGB6: /* V/530 V/6326 */
82472b676d7Smrg	fmt   = 0x40;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
82572b676d7Smrg	misc0 = 0x00;  /* D[6]: 1 = YUV, 0 = RGB */
82672b676d7Smrg	misc4 = 0xff;
82772b676d7Smrg	misc1 = 0x00;  /* D[2] = Capture format selection (DS5597) - WDR sets this */
82872b676d7Smrg	break;
82972b676d7Smrg    case PIXEL_FMT_RGB5: /* V/530 V/6326 */
83072b676d7Smrg    default:
83172b676d7Smrg	fmt   = 0x00;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
83272b676d7Smrg	misc0 = 0x00;  /* D[6]: 1 = YUV, 0 = RGB */
83372b676d7Smrg	misc4 = 0xff;
83472b676d7Smrg	misc1 = 0x04;  /* D[2] = Capture format selection (DS5597) - WDR sets this */
83572b676d7Smrg	break;
83672b676d7Smrg    }
83772b676d7Smrg
83872b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_VideoFormatSelect, fmt,   0xC0);
83972b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     misc0, 0x40);
84072b676d7Smrg    if(misc4 == 0xff) {
84172b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc1, misc1, 0x04);
84272b676d7Smrg       if(pSiS->oldChipset >= OC_SIS5597) {
84372b676d7Smrg	  setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x00, 0x05);
84472b676d7Smrg       }
84572b676d7Smrg    } else {
84672b676d7Smrg       if(pSiS->oldChipset >= OC_SIS5597) {
84772b676d7Smrg	  setvideoregmask(pSiS, Index_VI6326_Control_Misc4, misc4, 0x05);
84872b676d7Smrg       }
84972b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x04);
85072b676d7Smrg    }
85172b676d7Smrg}
85272b676d7Smrg
85372b676d7Smrgstatic void
85472b676d7Smrgset_colorkey(SISPtr pSiS, CARD32 colorkey)
85572b676d7Smrg{
85672b676d7Smrg    CARD8 r, g, b, s;
85772b676d7Smrg
85872b676d7Smrg    b = (CARD8)(colorkey & 0xFF);
85972b676d7Smrg    g = (CARD8)((colorkey >> 8) & 0xFF);
86072b676d7Smrg    r = (CARD8)((colorkey >> 16) & 0xFF);
86172b676d7Smrg
86272b676d7Smrg    if(pSiS->CurrentLayout.bitsPerPixel >= 24) {
86372b676d7Smrg       s = b;
86472b676d7Smrg       b = r;
86572b676d7Smrg       r = s;
86672b676d7Smrg    }
86772b676d7Smrg
86872b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Blue_Min  ,(CARD8)b);
86972b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Green_Min ,(CARD8)g);
87072b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Red_Min   ,(CARD8)r);
87172b676d7Smrg
87272b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Blue_Max  ,(CARD8)b);
87372b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Green_Max ,(CARD8)g);
87472b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Red_Max   ,(CARD8)r);
87572b676d7Smrg}
87672b676d7Smrg
87772b676d7Smrgstatic __inline void
87872b676d7Smrgset_brightness(SISPtr pSiS, CARD8 brightness)
87972b676d7Smrg{
88072b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Brightness, brightness);
88172b676d7Smrg}
88272b676d7Smrg
88372b676d7Smrgstatic __inline void
88472b676d7Smrgset_contrast(SISPtr pSiS, CARD8 contrast)
88572b676d7Smrg{
88672b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, contrast, 0x07);
88772b676d7Smrg}
88872b676d7Smrg
88972b676d7Smrgstatic void
89072b676d7Smrgset_contrast_data(SISPtr pSiS, int value)
89172b676d7Smrg{
89272b676d7Smrg  unsigned long temp;
89372b676d7Smrg
89472b676d7Smrg  if(value < 10000) temp = 0;
89572b676d7Smrg  else temp = (value - 10000) / 20000;
89672b676d7Smrg  if(temp > 3) temp = 3;
89772b676d7Smrg  setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, (temp << 6), 0xC0);
89872b676d7Smrg  switch(temp) {
89972b676d7Smrg     case 0: temp =  2048; break;
90072b676d7Smrg     case 1: temp =  4096; break;
90172b676d7Smrg     case 2: temp =  8192; break;
90272b676d7Smrg     case 3: temp = 16384; break;
90372b676d7Smrg  }
90472b676d7Smrg  temp <<= 10;
90572b676d7Smrg  temp /= value;
90672b676d7Smrg  setvideoreg(pSiS, Index_VI6326_Contrast_Factor, temp);
90772b676d7Smrg}
90872b676d7Smrg
90972b676d7Smrgstatic __inline void
91072b676d7Smrgset_disablegfx(SISPtr pSiS, Bool mybool)
91172b676d7Smrg{
91272b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Control_Misc0, mybool ? 0x10 : 0x00, 0x10);
91372b676d7Smrg}
91472b676d7Smrg
91572b676d7Smrgstatic void
91672b676d7Smrgset_overlay(SISPtr pSiS, SISOverlayPtr pOverlay, SISPortPrivPtr pPriv, int index)
91772b676d7Smrg{
91872b676d7Smrg    ScrnInfoPtr pScrn = pSiS->pScrn;
91972b676d7Smrg
92072b676d7Smrg    CARD16 pitch=0;
92172b676d7Smrg    CARD8  h_over=0, v_over=0;
92272b676d7Smrg    CARD16 top, bottom, left, right;
92372b676d7Smrg    CARD16 screenX = pSiS->CurrentLayout.mode->HDisplay;
92472b676d7Smrg    CARD16 screenY = pSiS->CurrentLayout.mode->VDisplay;
92572b676d7Smrg    CARD32 watchdog;
92672b676d7Smrg
92772b676d7Smrg    top = pOverlay->dstBox.y1;
92872b676d7Smrg    bottom = pOverlay->dstBox.y2;
92972b676d7Smrg    if(bottom > screenY) {
93072b676d7Smrg       bottom = screenY;
93172b676d7Smrg    }
93272b676d7Smrg
93372b676d7Smrg    left = pOverlay->dstBox.x1;
93472b676d7Smrg    right = pOverlay->dstBox.x2;
93572b676d7Smrg    if(right > screenX) {
93672b676d7Smrg       right = screenX;
93772b676d7Smrg    }
93872b676d7Smrg
93972b676d7Smrg    /* TW: DoubleScan modes require Y coordinates * 2 */
94072b676d7Smrg    if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) {
94172b676d7Smrg       top <<= 1;
94272b676d7Smrg       bottom <<= 1;
94372b676d7Smrg    }
94472b676d7Smrg    /* TW: Interlace modes require Y coordinates / 2 */
94572b676d7Smrg    if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) {
94672b676d7Smrg       top >>= 1;
94772b676d7Smrg       bottom >>= 1;
94872b676d7Smrg    }
94972b676d7Smrg
95072b676d7Smrg    h_over = (((left>>8) & 0x07) | ((right>>4) & 0x70));
95172b676d7Smrg    v_over = (((top>>8) & 0x07) | ((bottom>>4) & 0x70));
95272b676d7Smrg
95372b676d7Smrg    pitch = pOverlay->pitch * pOverlay->PitchMult;
95472b676d7Smrg    pitch >>= 2;   /* Datasheet: Unit = double word - verified */
95572b676d7Smrg    if(pitch > 0xfff) {
95672b676d7Smrg       pitch = pOverlay->pitch * (0xFFF * 2 / pOverlay->pitch);
95772b676d7Smrg       pOverlay->VUSF = 0x3F;
95872b676d7Smrg    }
95972b676d7Smrg
96072b676d7Smrg    /* set color key */
96172b676d7Smrg    set_colorkey(pSiS, pPriv->colorKey);
96272b676d7Smrg
96372b676d7Smrg    /* set color key mode */
96472b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Key_Overlay_OP, pOverlay->keyOP, 0x0f);
96572b676d7Smrg
96672b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c);
96772b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18);
96872b676d7Smrg
96972b676d7Smrg    /* Set Y buf pitch */   /* Datasheet: Unit = double word - verified */
97072b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Disp_Y_Buf_Pitch_Low, (CARD8)(pitch));
97172b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Disp_Y_Buf_Pitch_High, (CARD8)(pitch>>8), 0x0f);
97272b676d7Smrg    /* Set U/V pitch if using planar formats */
97372b676d7Smrg    if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
97472b676d7Smrg    	(pOverlay->pixelFormat == PIXEL_FMT_I420) )  {
97572b676d7Smrg       /* Set U/V pitch */  /* Datasheet: Unit = double word - verified */
97672b676d7Smrg       setvideoreg(pSiS, Index_VI6326_Disp_UV_Buf_Pitch_Low, (CARD8)pitch >> 1);
97772b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Disp_UV_Buf_Pitch_High, (CARD8)(pitch >> 9), 0x0f);
97872b676d7Smrg    }
97972b676d7Smrg
98072b676d7Smrg    /* set line buffer size */
98172b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Line_Buffer_Size, pOverlay->lineBufSize);
98272b676d7Smrg
98372b676d7Smrg    /* set scale factor */
98472b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Hor_Scale,             (CARD8)((pOverlay->HUSF) | 0xC0));
98572b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Hor_Scale_Integer, (CARD8)(pOverlay->HIntBit), 0x0F);
98672b676d7Smrg    setvideoregmask(pSiS, Index_VI6326_Ver_Scale,         (CARD8)(pOverlay->VUSF), 0x3F);
98772b676d7Smrg
98872b676d7Smrg    /* TW: We don't have to wait for vertical retrace in all cases */
98972b676d7Smrg    if(pPriv->mustwait) {
99072b676d7Smrg       watchdog = WATCHDOG_DELAY;
99172b676d7Smrg       while ((!pOverlay->VBlankActiveFunc(pSiS)) && --watchdog);
99272b676d7Smrg       if(!watchdog) xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
99372b676d7Smrg		"Xv: Waiting for vertical retrace timed-out\n");
99472b676d7Smrg    }
99572b676d7Smrg
99672b676d7Smrg    /* set destination window position */
99772b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Win_Hor_Disp_Start_Low, (CARD8)left);
99872b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Win_Hor_Disp_End_Low,   (CARD8)right);
99972b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Win_Hor_Over,           (CARD8)h_over);
100072b676d7Smrg
100172b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Win_Ver_Disp_Start_Low, (CARD8)top);
100272b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Win_Ver_Disp_End_Low,   (CARD8)bottom);
100372b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Win_Ver_Over,           (CARD8)v_over);
100472b676d7Smrg
100572b676d7Smrg    /* Set Y start address */
100672b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Disp_Y_Buf_Start_Low,    (CARD8)(pOverlay->PSY));
100772b676d7Smrg    setvideoreg(pSiS, Index_VI6326_Disp_Y_Buf_Start_Middle, (CARD8)((pOverlay->PSY)>>8));
100872b676d7Smrg    if(pSiS->oldChipset <= OC_SIS6326) {  	/* all old chipsets incl 6326 */
100972b676d7Smrg       /* Set overflow bits */
101072b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Disp_Capt_Y_Buf_Start_High,
101172b676d7Smrg                                             (CARD8)(((pOverlay->PSY)>>12) & 0xF0), 0xF0);
101272b676d7Smrg       /* Set framebuffer end address */
101372b676d7Smrg       setvideoreg(pSiS, Index_VI6326_Disp_Y_End,    (CARD8)(pOverlay->YUVEnd));
101472b676d7Smrg    } else {  				/* 530/620 */
101572b676d7Smrg       /* Set overflow bits */
101672b676d7Smrg       setvideoregmask(pSiS, Index_VI6326_Disp_Capt_Y_Buf_Start_High,
101772b676d7Smrg                                             (CARD8)(((pOverlay->PSY)>>13) & 0xF8), 0xF8);
101872b676d7Smrg    }
101972b676d7Smrg
102072b676d7Smrg    /* Set U/V start addresses if using plane formats */
102172b676d7Smrg    if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
102272b676d7Smrg    	(pOverlay->pixelFormat == PIXEL_FMT_I420) )  {
102372b676d7Smrg
102472b676d7Smrg        CARD32 PSU = pOverlay->PSU;
102572b676d7Smrg        CARD32 PSV = pOverlay->PSV;
102672b676d7Smrg
102772b676d7Smrg        /* set U/V start address */
102872b676d7Smrg        setvideoreg(pSiS, Index_VI6326_U_Buf_Start_Low,   (CARD8)PSU);
102972b676d7Smrg        setvideoreg(pSiS, Index_VI6326_U_Buf_Start_Middle,(CARD8)(PSU >> 8));
103072b676d7Smrg
103172b676d7Smrg        setvideoreg(pSiS, Index_VI6326_V_Buf_Start_Low,   (CARD8)PSV);
103272b676d7Smrg        setvideoreg(pSiS, Index_VI6326_V_Buf_Start_Middle,(CARD8)(PSV >> 8));
103372b676d7Smrg
103472b676d7Smrg	setvideoreg(pSiS, Index_VI6326_UV_Buf_Start_High,
103572b676d7Smrg					(CARD8)(((PSU >> 16) & 0x0F) | ((PSV >> 12) & 0xF0)) );
103672b676d7Smrg
103772b676d7Smrg	if(pSiS->oldChipset > OC_SIS6326) {
103872b676d7Smrg	   /* Set bit 20 of the addresses in Misc5 (530/620 only) */
103972b676d7Smrg	   setvideoreg(pSiS, Index_VI6326_Control_Misc5,
104072b676d7Smrg				(CARD8)(((PSU >> (20-1)) & 0x02) | ((PSV >> (20-2)) & 0x04)) );
104172b676d7Smrg	}
104272b676d7Smrg    }
104372b676d7Smrg
104472b676d7Smrg    /* set brightness and contrast */
104572b676d7Smrg    set_brightness(pSiS, pPriv->brightness);
104672b676d7Smrg    if(pSiS->oldChipset > OC_SIS6205C) {
104772b676d7Smrg       set_contrast_data(pSiS, (pOverlay->dstBox.x2 - pOverlay->dstBox.x1) *
104872b676d7Smrg                               (pOverlay->dstBox.y2 - pOverlay->dstBox.y1));
104972b676d7Smrg       set_contrast(pSiS, pPriv->contrast);
105072b676d7Smrg    }
105172b676d7Smrg
105272b676d7Smrg    /* enable/disable graphics display around overlay */
105372b676d7Smrg    set_disablegfx(pSiS, pPriv->disablegfx);
105472b676d7Smrg
105572b676d7Smrg    /* set format */
105672b676d7Smrg    set_format(pSiS, pOverlay);
105772b676d7Smrg}
105872b676d7Smrg
105972b676d7Smrg/* Overlay MUST NOT be switched off while beam is over it */
106072b676d7Smrgstatic void
106172b676d7Smrgclose_overlay(SISPtr pSiS, SISPortPrivPtr pPriv)
106272b676d7Smrg{
106372b676d7Smrg  CARD32 watchdog;
106472b676d7Smrg
106572b676d7Smrg  watchdog = WATCHDOG_DELAY;
106672b676d7Smrg  while((!vblank_active_CRT1(pSiS)) && --watchdog);
106772b676d7Smrg  if(pSiS->oldChipset > OC_SIS6326) {
106872b676d7Smrg     /* what is this? */
106972b676d7Smrg     setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40);
107072b676d7Smrg  }
107172b676d7Smrg  /* disable overlay */
107272b676d7Smrg  setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x02);
107372b676d7Smrg}
107472b676d7Smrg
107572b676d7Smrgstatic void
107672b676d7SmrgSIS6326DisplayVideo(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
107772b676d7Smrg{
107872b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
107972b676d7Smrg
108072b676d7Smrg   short srcPitch = pPriv->srcPitch;
108172b676d7Smrg   short height = pPriv->height;
108272b676d7Smrg   short width = pPriv->width;
108372b676d7Smrg   SISOverlayRec overlay;
108472b676d7Smrg   int srcOffsetX=0, srcOffsetY=0;
108572b676d7Smrg   int sx, sy;
108672b676d7Smrg   int index = 0;
108772b676d7Smrg   int pitch;
108872b676d7Smrg
108972b676d7Smrg   memset(&overlay, 0, sizeof(overlay));
109072b676d7Smrg   overlay.pixelFormat = pPriv->id;
109172b676d7Smrg   overlay.pitch = srcPitch;
109272b676d7Smrg   overlay.keyOP = VI6326_ROP_DestKey;	/* DestKey mode */
109372b676d7Smrg
109472b676d7Smrg   overlay.dstBox.x1 = pPriv->drw_x - pScrn->frameX0;
109572b676d7Smrg   overlay.dstBox.x2 = pPriv->drw_x + pPriv->drw_w - pScrn->frameX0;
109672b676d7Smrg   overlay.dstBox.y1 = pPriv->drw_y - pScrn->frameY0;
109772b676d7Smrg   overlay.dstBox.y2 = pPriv->drw_y + pPriv->drw_h - pScrn->frameY0;
109872b676d7Smrg
109972b676d7Smrg   if((overlay.dstBox.x1 > overlay.dstBox.x2) ||
110072b676d7Smrg      (overlay.dstBox.y1 > overlay.dstBox.y2))
110172b676d7Smrg      return;
110272b676d7Smrg
110372b676d7Smrg   if((overlay.dstBox.x2 < 0) || (overlay.dstBox.y2 < 0))
110472b676d7Smrg      return;
110572b676d7Smrg
110672b676d7Smrg   if(overlay.dstBox.x1 < 0) {
110772b676d7Smrg      srcOffsetX = pPriv->src_w * (-overlay.dstBox.x1) / pPriv->drw_w;
110872b676d7Smrg      overlay.dstBox.x1 = 0;
110972b676d7Smrg   }
111072b676d7Smrg   if(overlay.dstBox.y1 < 0) {
111172b676d7Smrg      srcOffsetY = pPriv->src_h * (-overlay.dstBox.y1) / pPriv->drw_h;
111272b676d7Smrg      overlay.dstBox.y1 = 0;
111372b676d7Smrg   }
111472b676d7Smrg
111572b676d7Smrg   switch(pPriv->id){
111672b676d7Smrg     case PIXEL_FMT_YV12:
111772b676d7Smrg       sx = (pPriv->src_x + srcOffsetX) & ~7;
111872b676d7Smrg       sy = (pPriv->src_y + srcOffsetY) & ~1;
111972b676d7Smrg       pitch = (width + 3) & ~3;
112072b676d7Smrg       overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy * pitch;
112172b676d7Smrg       overlay.PSV = overlay.PSY + pitch * height;
112272b676d7Smrg       overlay.PSU = overlay.PSV + ((((width >> 1) + 3) & ~3) * (height >> 1));
112372b676d7Smrg       overlay.PSY >>= 2;
112472b676d7Smrg       overlay.PSV >>= 2;
112572b676d7Smrg       overlay.PSU >>= 2;
112672b676d7Smrg       break;
112772b676d7Smrg     case PIXEL_FMT_I420:
112872b676d7Smrg       sx = (pPriv->src_x + srcOffsetX) & ~7;
112972b676d7Smrg       sy = (pPriv->src_y + srcOffsetY) & ~1;
113072b676d7Smrg       pitch = (width + 3) & ~3;
113172b676d7Smrg       overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy * pitch;
113272b676d7Smrg       overlay.PSU = overlay.PSY + pitch * height;
113372b676d7Smrg       overlay.PSV = overlay.PSU + ((((width >> 1) + 3) & ~3) * (height >> 1));
113472b676d7Smrg       overlay.PSY >>= 2;
113572b676d7Smrg       overlay.PSV >>= 2;
113672b676d7Smrg       overlay.PSU >>= 2;
113772b676d7Smrg       break;
113872b676d7Smrg     case PIXEL_FMT_YUY2:
113972b676d7Smrg     case PIXEL_FMT_UYVY:
114072b676d7Smrg     case PIXEL_FMT_RGB6:
114172b676d7Smrg     case PIXEL_FMT_RGB5:
114272b676d7Smrg     default:
114372b676d7Smrg       sx = (pPriv->src_x + srcOffsetX) & ~1;
114472b676d7Smrg       sy = (pPriv->src_y + srcOffsetY);
114572b676d7Smrg       overlay.PSY = (pPriv->bufAddr[pPriv->currentBuf] + sx*2 + sy*srcPitch);
114672b676d7Smrg       overlay.PSY >>= 2;
114772b676d7Smrg       break;
114872b676d7Smrg   }
114972b676d7Smrg
115072b676d7Smrg   /* FIXME: Is this correct? (Is it required to set the end address?
115172b676d7Smrg    *        Datasheet is not clear) - (reg does not exist on 530/620)
115272b676d7Smrg    */
115372b676d7Smrg   overlay.YUVEnd = (pPriv->bufAddr[pPriv->currentBuf] + pPriv->totalSize) >> 14;
115472b676d7Smrg
115572b676d7Smrg   /* FIXME: is it possible that srcW < 0 */
115672b676d7Smrg   overlay.srcW = pPriv->src_w - (sx - pPriv->src_x);
115772b676d7Smrg   overlay.srcH = pPriv->src_h - (sy - pPriv->src_y);
115872b676d7Smrg
115972b676d7Smrg   if( (pPriv->oldx1 != overlay.dstBox.x1) ||
116072b676d7Smrg       (pPriv->oldx2 != overlay.dstBox.x2) ||
116172b676d7Smrg       (pPriv->oldy1 != overlay.dstBox.y1) ||
116272b676d7Smrg       (pPriv->oldy2 != overlay.dstBox.y2) ) {
116372b676d7Smrg      pPriv->mustwait = 1;
116472b676d7Smrg      pPriv->oldx1 = overlay.dstBox.x1; pPriv->oldx2 = overlay.dstBox.x2;
116572b676d7Smrg      pPriv->oldy1 = overlay.dstBox.y1; pPriv->oldy2 = overlay.dstBox.y2;
116672b676d7Smrg   }
116772b676d7Smrg
116872b676d7Smrg   /* calculate line buffer length */
116972b676d7Smrg   calc_line_buf_size(&overlay);
117072b676d7Smrg
117172b676d7Smrg   overlay.VBlankActiveFunc = vblank_active_CRT1;
117272b676d7Smrg/* overlay.GetScanLineFunc = get_scanline_CRT1;  */
117372b676d7Smrg
117472b676d7Smrg   /* calculate scale factor */
117572b676d7Smrg   calc_scale_factor(pSiS, &overlay, pScrn, pPriv);
117672b676d7Smrg
117772b676d7Smrg   /* set (not only determine) if line buffer is to be merged */
117872b676d7Smrg   if(pSiS->oldChipset > OC_SIS5597) {
117972b676d7Smrg      int temp = 384;
118072b676d7Smrg      if(pSiS->oldChipset <= OC_SIS6326) temp = 352;
118172b676d7Smrg      merge_line_buf(pSiS, pPriv, (overlay.srcW > temp));
118272b676d7Smrg   }
118372b676d7Smrg
118472b676d7Smrg   /* set overlay */
118572b676d7Smrg   set_overlay(pSiS, &overlay, pPriv, index);
118672b676d7Smrg
118772b676d7Smrg   /* enable overlay */
118872b676d7Smrg   if(pSiS->oldChipset > OC_SIS6326) {
118972b676d7Smrg      setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40);
119072b676d7Smrg   }
119172b676d7Smrg   setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x02, 0x02);
119272b676d7Smrg
119372b676d7Smrg   pPriv->mustwait = 0;
119472b676d7Smrg}
119572b676d7Smrg
119672b676d7Smrgstatic void
119772b676d7SmrgSIS6326StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
119872b676d7Smrg{
119972b676d7Smrg  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
120072b676d7Smrg  SISPtr pSiS = SISPTR(pScrn);
120172b676d7Smrg
120272b676d7Smrg  if(pPriv->grabbedByV4L) return;
120372b676d7Smrg
120472b676d7Smrg  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
120572b676d7Smrg
120672b676d7Smrg  if(shutdown) {
120772b676d7Smrg     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
120872b676d7Smrg        close_overlay(pSiS, pPriv);
120972b676d7Smrg        pPriv->mustwait = 1;
121072b676d7Smrg     }
121172b676d7Smrg     SISFreeFBMemory(pScrn, &pPriv->handle);
121272b676d7Smrg     pPriv->videoStatus = 0;
121372b676d7Smrg     pSiS->VideoTimerCallback = NULL;
121472b676d7Smrg  } else {
121572b676d7Smrg     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
121672b676d7Smrg        pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
121772b676d7Smrg        pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
121872b676d7Smrg        pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
121972b676d7Smrg     }
122072b676d7Smrg  }
122172b676d7Smrg}
122272b676d7Smrg
122372b676d7Smrgstatic int
122472b676d7SmrgSIS6326PutImage(
122572b676d7Smrg  ScrnInfoPtr pScrn,
122672b676d7Smrg  short src_x, short src_y,
122772b676d7Smrg  short drw_x, short drw_y,
122872b676d7Smrg  short src_w, short src_h,
122972b676d7Smrg  short drw_w, short drw_h,
123072b676d7Smrg  int id, unsigned char* buf,
123172b676d7Smrg  short width, short height,
123272b676d7Smrg  Bool sync,
123372b676d7Smrg  RegionPtr clipBoxes, pointer data,
123472b676d7Smrg  DrawablePtr pDraw
123572b676d7Smrg){
123672b676d7Smrg   SISPtr pSiS = SISPTR(pScrn);
123772b676d7Smrg   SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
123872b676d7Smrg   int totalSize=0;
123972b676d7Smrg   CARD32 *src, *dest;
124072b676d7Smrg   unsigned long i;
124172b676d7Smrg
124272b676d7Smrg   if(pPriv->grabbedByV4L) return Success;
124372b676d7Smrg
124472b676d7Smrg   pPriv->drw_x = drw_x;
124572b676d7Smrg   pPriv->drw_y = drw_y;
124672b676d7Smrg   pPriv->drw_w = drw_w;
124772b676d7Smrg   pPriv->drw_h = drw_h;
124872b676d7Smrg   pPriv->src_x = src_x;
124972b676d7Smrg   pPriv->src_y = src_y;
125072b676d7Smrg   pPriv->src_w = src_w;
125172b676d7Smrg   pPriv->src_h = src_h;
125272b676d7Smrg   pPriv->id = id;
125372b676d7Smrg   pPriv->height = height;
125472b676d7Smrg   pPriv->width = width;
125572b676d7Smrg
125672b676d7Smrg   /* Pixel formats:
125772b676d7Smrg      1. YU12:  3 planes:       H    V
125872b676d7Smrg               Y sample period  1    1   (8 bit per pixel)
125972b676d7Smrg	       V sample period  2    2	 (8 bit per pixel, subsampled)
126072b676d7Smrg	       U sample period  2    2   (8 bit per pixel, subsampled)
126172b676d7Smrg
126272b676d7Smrg	 Y plane is fully sampled (width*height), U and V planes
126372b676d7Smrg	 are sampled in 2x2 blocks, hence a group of 4 pixels requires
126472b676d7Smrg	 4 + 1 + 1 = 6 bytes. The data is planar, ie in single planes
126572b676d7Smrg	 for Y, U and V.
126672b676d7Smrg      2. UYVY: 3 planes:        H    V
126772b676d7Smrg               Y sample period  1    1   (8 bit per pixel)
126872b676d7Smrg	       V sample period  2    1	 (8 bit per pixel, subsampled)
126972b676d7Smrg	       U sample period  2    1   (8 bit per pixel, subsampled)
127072b676d7Smrg	 Y plane is fully sampled (width*height), U and V planes
127172b676d7Smrg	 are sampled in 2x1 blocks, hence a group of 4 pixels requires
127272b676d7Smrg	 4 + 2 + 2 = 8 bytes. The data is bit packed, there are no separate
127372b676d7Smrg	 Y, U or V planes.
127472b676d7Smrg	 Bit order:  U0 Y0 V0 Y1  U2 Y2 V2 Y3 ...
127572b676d7Smrg      3. I420: Like YU12, but planes U and V are in reverse order.
127672b676d7Smrg      4. YUY2: Like UYVY, but order is
127772b676d7Smrg                     Y0 U0 Y1 V0  Y2 U2 Y3 V2 ...
127872b676d7Smrg   */
127972b676d7Smrg
128072b676d7Smrg   switch(id){
128172b676d7Smrg     case PIXEL_FMT_YV12:
128272b676d7Smrg     case PIXEL_FMT_I420:
128372b676d7Smrg       pPriv->srcPitch = (width + 7) & ~7;
128472b676d7Smrg       /* Size = width * height * 3 / 2 */
128572b676d7Smrg       totalSize = (pPriv->srcPitch * height * 3) >> 1;
128672b676d7Smrg       break;
128772b676d7Smrg     case PIXEL_FMT_YUY2:
128872b676d7Smrg     case PIXEL_FMT_UYVY:
128972b676d7Smrg     case PIXEL_FMT_RGB5:
129072b676d7Smrg     case PIXEL_FMT_RGB6:
129172b676d7Smrg     default:
129272b676d7Smrg       pPriv->srcPitch = ((width << 1) + 3) & ~3;
129372b676d7Smrg       /* Size = width * 2 * height */
129472b676d7Smrg       totalSize = pPriv->srcPitch * height;
129572b676d7Smrg   }
129672b676d7Smrg
129772b676d7Smrg   /* make it a multiple of 16 to simplify to copy loop */
129872b676d7Smrg   totalSize += 15;
129972b676d7Smrg   totalSize &= ~15; /* in bytes */
130072b676d7Smrg
130172b676d7Smrg   pPriv->totalSize = totalSize;
130272b676d7Smrg
130372b676d7Smrg   /* allocate memory (we do doublebuffering) - size is in bytes */
130472b676d7Smrg   if(!(pPriv->bufAddr[0] = SISAllocateFBMemory(pScrn, &pPriv->handle, totalSize << 1)))
130572b676d7Smrg      return BadAlloc;
130672b676d7Smrg
130772b676d7Smrg   pPriv->bufAddr[1] = pPriv->bufAddr[0] + totalSize;
130872b676d7Smrg
130972b676d7Smrg   /* copy data */
131072b676d7Smrg   if((pSiS->XvUseMemcpy) || (totalSize < 16)) {
131172b676d7Smrg      SiSMemCopyToVideoRam(pSiS, pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf], buf, totalSize);
131272b676d7Smrg   } else {
131372b676d7Smrg      dest = (CARD32 *)(pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf]);
131472b676d7Smrg      src  = (CARD32 *)buf;
131572b676d7Smrg      for(i = 0; i < (totalSize/16); i++) {
131672b676d7Smrg	 *dest++ = *src++;
131772b676d7Smrg	 *dest++ = *src++;
131872b676d7Smrg	 *dest++ = *src++;
131972b676d7Smrg	 *dest++ = *src++;
132072b676d7Smrg      }
132172b676d7Smrg   }
132272b676d7Smrg
132372b676d7Smrg   SIS6326DisplayVideo(pScrn, pPriv);
132472b676d7Smrg
132572b676d7Smrg   /* update cliplist */
132672b676d7Smrg   if(  pPriv->autopaintColorKey &&
132772b676d7Smrg        (pPriv->grabbedByV4L ||
132872b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
132972b676d7Smrg	 !RegionsEqual(&pPriv->clip, clipBoxes)) ) {
133072b676d7Smrg#else
133172b676d7Smrg         !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) ) {
133272b676d7Smrg#endif
133372b676d7Smrg      /* We always paint colorkey for V4L */
133472b676d7Smrg      if(!pPriv->grabbedByV4L)
133572b676d7Smrg     	 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
133672b676d7Smrg      /* draw these */
133772b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
133872b676d7Smrg      (*pSiS->AccelInfoPtr->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0,
133972b676d7Smrg                    REGION_NUM_RECTS(clipBoxes),
134072b676d7Smrg                    REGION_RECTS(clipBoxes));
134172b676d7Smrg#else
134272b676d7Smrg      xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
134372b676d7Smrg#endif
134472b676d7Smrg   }
134572b676d7Smrg
134672b676d7Smrg   pPriv->currentBuf ^= 1;
134772b676d7Smrg
134872b676d7Smrg   pPriv->videoStatus = CLIENT_VIDEO_ON;
134972b676d7Smrg
135072b676d7Smrg   pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
135172b676d7Smrg
135272b676d7Smrg   return Success;
135372b676d7Smrg}
135472b676d7Smrg
135572b676d7Smrgstatic int
135672b676d7SmrgSIS6326QueryImageAttributes(
135772b676d7Smrg  ScrnInfoPtr pScrn,
135872b676d7Smrg  int id,
135972b676d7Smrg  unsigned short *w, unsigned short *h,
136072b676d7Smrg  int *pitches, int *offsets
136172b676d7Smrg){
136272b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
136372b676d7Smrg    int pitchY, pitchUV;
136472b676d7Smrg    int size, sizeY, sizeUV;
136572b676d7Smrg
136672b676d7Smrg    if(*w < IMAGE_MIN_WIDTH) *w = IMAGE_MIN_WIDTH;
136772b676d7Smrg    if(*h < IMAGE_MIN_HEIGHT) *h = IMAGE_MIN_HEIGHT;
136872b676d7Smrg
136972b676d7Smrg    if(pSiS->oldChipset < OC_SIS6326) {
137072b676d7Smrg       if(*w > IMAGE_MAX_WIDTH_5597) *w = IMAGE_MAX_WIDTH_5597;
137172b676d7Smrg       if(*h > IMAGE_MAX_HEIGHT_5597) *h = IMAGE_MAX_HEIGHT_5597;
137272b676d7Smrg    } else {
137372b676d7Smrg       if(*w > IMAGE_MAX_WIDTH) *w = IMAGE_MAX_WIDTH;
137472b676d7Smrg       if(*h > IMAGE_MAX_HEIGHT) *h = IMAGE_MAX_HEIGHT;
137572b676d7Smrg    }
137672b676d7Smrg
137772b676d7Smrg    switch(id) {
137872b676d7Smrg    case PIXEL_FMT_YV12:
137972b676d7Smrg    case PIXEL_FMT_I420:
138072b676d7Smrg	*w = (*w + 7) & ~7;
138172b676d7Smrg	*h = (*h + 1) & ~1;
138272b676d7Smrg	pitchY = *w;
138372b676d7Smrg	pitchUV = *w >> 1;
138472b676d7Smrg	if(pitches) {
138572b676d7Smrg	    pitches[0] = pitchY;
138672b676d7Smrg	    pitches[1] = pitches[2] = pitchUV;
138772b676d7Smrg        }
138872b676d7Smrg	sizeY = pitchY * (*h);
138972b676d7Smrg	sizeUV = pitchUV * ((*h) >> 1);
139072b676d7Smrg	if(offsets) {
139172b676d7Smrg	  offsets[0] = 0;
139272b676d7Smrg	  offsets[1] = sizeY;
139372b676d7Smrg	  offsets[2] = sizeY + sizeUV;
139472b676d7Smrg	}
139572b676d7Smrg	size = sizeY + (sizeUV << 1);
139672b676d7Smrg	break;
139772b676d7Smrg    case PIXEL_FMT_YUY2:
139872b676d7Smrg    case PIXEL_FMT_UYVY:
139972b676d7Smrg    case PIXEL_FMT_RGB5:
140072b676d7Smrg    case PIXEL_FMT_RGB6:
140172b676d7Smrg    default:
140272b676d7Smrg	*w = (*w + 1) & ~1;
140372b676d7Smrg	pitchY = *w << 1;
140472b676d7Smrg	if(pitches) pitches[0] = pitchY;
140572b676d7Smrg	if(offsets) offsets[0] = 0;
140672b676d7Smrg	size = pitchY * (*h);
140772b676d7Smrg	break;
140872b676d7Smrg    }
140972b676d7Smrg
141072b676d7Smrg    return size;
141172b676d7Smrg}
141272b676d7Smrg
141372b676d7Smrgstatic void
141472b676d7SmrgSIS6326VideoTimerCallback(ScrnInfoPtr pScrn, Time now)
141572b676d7Smrg{
141672b676d7Smrg    SISPtr         pSiS = SISPTR(pScrn);
141772b676d7Smrg    SISPortPrivPtr pPriv = NULL;
141872b676d7Smrg    unsigned char  sridx, cridx;
141972b676d7Smrg
142072b676d7Smrg    pSiS->VideoTimerCallback = NULL;
142172b676d7Smrg
142272b676d7Smrg    if(!pScrn->vtSema) return;
142372b676d7Smrg
142472b676d7Smrg    if(pSiS->adaptor) {
142572b676d7Smrg	pPriv = GET_PORT_PRIVATE(pScrn);
142672b676d7Smrg	if(!pPriv->videoStatus) pPriv = NULL;
142772b676d7Smrg    }
142872b676d7Smrg
142972b676d7Smrg    if(pPriv) {
143072b676d7Smrg       if(pPriv->videoStatus & TIMER_MASK) {
143172b676d7Smrg	  if(pPriv->videoStatus & OFF_TIMER) {
143272b676d7Smrg	     if(pPriv->offTime < now) {
143372b676d7Smrg		/* Turn off the overlay */
143472b676d7Smrg		sridx = inSISREG(SISSR); cridx = inSISREG(SISCR);
143572b676d7Smrg		close_overlay(pSiS, pPriv);
143672b676d7Smrg		outSISREG(SISSR, sridx); outSISREG(SISCR, cridx);
143772b676d7Smrg		pPriv->mustwait = 1;
143872b676d7Smrg		pPriv->videoStatus = FREE_TIMER;
143972b676d7Smrg		pPriv->freeTime = now + FREE_DELAY;
144072b676d7Smrg		pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
144172b676d7Smrg	     }
144272b676d7Smrg          } else if(pPriv->videoStatus & FREE_TIMER) {
144372b676d7Smrg             if(pPriv->freeTime < now) {
144472b676d7Smrg		SISFreeFBMemory(pScrn, &pPriv->handle);
144572b676d7Smrg		pPriv->mustwait = 1;
144672b676d7Smrg		pPriv->videoStatus = 0;
144772b676d7Smrg	     }
144872b676d7Smrg	  } else
144972b676d7Smrg	     pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
145072b676d7Smrg       }
145172b676d7Smrg    }
145272b676d7Smrg}
145372b676d7Smrg
145472b676d7Smrg/* Offscreen surface stuff for v4l */
145572b676d7Smrg
145672b676d7Smrgstatic int
145772b676d7SmrgSIS6326AllocSurface (
145872b676d7Smrg    ScrnInfoPtr pScrn,
145972b676d7Smrg    int id,
146072b676d7Smrg    unsigned short w,
146172b676d7Smrg    unsigned short h,
146272b676d7Smrg    XF86SurfacePtr surface
146372b676d7Smrg)
146472b676d7Smrg{
146572b676d7Smrg    SISPtr pSiS = SISPTR(pScrn);
146672b676d7Smrg    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
146772b676d7Smrg    int size;
146872b676d7Smrg
146972b676d7Smrg    if((w < IMAGE_MIN_WIDTH) || (h < IMAGE_MIN_HEIGHT))
147072b676d7Smrg       return BadValue;
147172b676d7Smrg
147272b676d7Smrg    if(pSiS->oldChipset < OC_SIS6326) {
147372b676d7Smrg       if((w > IMAGE_MAX_WIDTH_5597) || (h > IMAGE_MAX_HEIGHT_5597))
147472b676d7Smrg	  return BadValue;
147572b676d7Smrg    } else {
147672b676d7Smrg       if((w > IMAGE_MAX_WIDTH) || (h > IMAGE_MAX_HEIGHT))
147772b676d7Smrg	  return BadValue;
147872b676d7Smrg    }
147972b676d7Smrg
148072b676d7Smrg    if(pPriv->grabbedByV4L)
148172b676d7Smrg       return BadAlloc;
148272b676d7Smrg
148372b676d7Smrg    w = (w + 1) & ~1;
148472b676d7Smrg    pPriv->pitch = ((w << 1) + 63) & ~63; /* Only packed pixel modes supported */
148572b676d7Smrg    size = h * pPriv->pitch;
148672b676d7Smrg    if(!(pPriv->offset = SISAllocateFBMemory(pScrn, &pPriv->handle, size)))
148772b676d7Smrg       return BadAlloc;
148872b676d7Smrg
148972b676d7Smrg    pPriv->totalSize = size;
149072b676d7Smrg
149172b676d7Smrg    surface->width   = w;
149272b676d7Smrg    surface->height  = h;
149372b676d7Smrg    surface->pScrn   = pScrn;
149472b676d7Smrg    surface->id      = id;
149572b676d7Smrg    surface->pitches = &pPriv->pitch;
149672b676d7Smrg    surface->offsets = &pPriv->offset;
149772b676d7Smrg    surface->devPrivate.ptr = (pointer)pPriv;
149872b676d7Smrg
149972b676d7Smrg    close_overlay(pSiS, pPriv);
150072b676d7Smrg    pPriv->videoStatus = 0;
150172b676d7Smrg    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
150272b676d7Smrg    pSiS->VideoTimerCallback = NULL;
150372b676d7Smrg    pPriv->grabbedByV4L = TRUE;
150472b676d7Smrg    return Success;
150572b676d7Smrg}
150672b676d7Smrg
150772b676d7Smrgstatic int
150872b676d7SmrgSIS6326StopSurface (XF86SurfacePtr surface)
150972b676d7Smrg{
151072b676d7Smrg    SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
151172b676d7Smrg    SISPtr pSiS = SISPTR(surface->pScrn);
151272b676d7Smrg
151372b676d7Smrg    if(pPriv->grabbedByV4L && pPriv->videoStatus) {
151472b676d7Smrg       close_overlay(pSiS, pPriv);
151572b676d7Smrg       pPriv->mustwait = 1;
151672b676d7Smrg       pPriv->videoStatus = 0;
151772b676d7Smrg    }
151872b676d7Smrg    return Success;
151972b676d7Smrg}
152072b676d7Smrg
152172b676d7Smrgstatic int
152272b676d7SmrgSIS6326FreeSurface (XF86SurfacePtr surface)
152372b676d7Smrg{
152472b676d7Smrg    SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
152572b676d7Smrg
152672b676d7Smrg    if(pPriv->grabbedByV4L) {
152772b676d7Smrg       SIS6326StopSurface(surface);
152872b676d7Smrg       SISFreeFBMemory(surface->pScrn, &pPriv->handle);
152972b676d7Smrg       pPriv->grabbedByV4L = FALSE;
153072b676d7Smrg    }
153172b676d7Smrg    return Success;
153272b676d7Smrg}
153372b676d7Smrg
153472b676d7Smrgstatic int
153572b676d7SmrgSIS6326GetSurfaceAttribute (
153672b676d7Smrg    ScrnInfoPtr pScrn,
153772b676d7Smrg    Atom attribute,
153872b676d7Smrg    INT32 *value
153972b676d7Smrg)
154072b676d7Smrg{
154172b676d7Smrg    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
154272b676d7Smrg
154372b676d7Smrg    return SIS6326GetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
154472b676d7Smrg}
154572b676d7Smrg
154672b676d7Smrgstatic int
154772b676d7SmrgSIS6326SetSurfaceAttribute(
154872b676d7Smrg    ScrnInfoPtr pScrn,
154972b676d7Smrg    Atom attribute,
155072b676d7Smrg    INT32 value
155172b676d7Smrg)
155272b676d7Smrg{
155372b676d7Smrg    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);;
155472b676d7Smrg
155572b676d7Smrg    return SIS6326SetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
155672b676d7Smrg}
155772b676d7Smrg
155872b676d7Smrgstatic int
155972b676d7SmrgSIS6326DisplaySurface (
156072b676d7Smrg    XF86SurfacePtr surface,
156172b676d7Smrg    short src_x, short src_y,
156272b676d7Smrg    short drw_x, short drw_y,
156372b676d7Smrg    short src_w, short src_h,
156472b676d7Smrg    short drw_w, short drw_h,
156572b676d7Smrg    RegionPtr clipBoxes
156672b676d7Smrg)
156772b676d7Smrg{
156872b676d7Smrg   ScrnInfoPtr pScrn = surface->pScrn;
156972b676d7Smrg   SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
157072b676d7Smrg
157172b676d7Smrg   if(!pPriv->grabbedByV4L)
157272b676d7Smrg      return Success;
157372b676d7Smrg
157472b676d7Smrg   pPriv->drw_x = drw_x;
157572b676d7Smrg   pPriv->drw_y = drw_y;
157672b676d7Smrg   pPriv->drw_w = drw_w;
157772b676d7Smrg   pPriv->drw_h = drw_h;
157872b676d7Smrg   pPriv->src_x = src_x;
157972b676d7Smrg   pPriv->src_y = src_y;
158072b676d7Smrg   pPriv->src_w = src_w;
158172b676d7Smrg   pPriv->src_h = src_h;
158272b676d7Smrg   pPriv->id = surface->id;
158372b676d7Smrg   pPriv->height = surface->height;
158472b676d7Smrg   pPriv->bufAddr[0] = surface->offsets[0];
158572b676d7Smrg   pPriv->currentBuf = 0;
158672b676d7Smrg   pPriv->srcPitch = surface->pitches[0];
158772b676d7Smrg
158872b676d7Smrg   SIS6326DisplayVideo(pScrn, pPriv);
158972b676d7Smrg
159072b676d7Smrg   if(pPriv->autopaintColorKey) {
159172b676d7Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
159272b676d7Smrg      (*XAAPTR(pScrn)->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0,
159372b676d7Smrg                    REGION_NUM_RECTS(clipBoxes),
159472b676d7Smrg                    REGION_RECTS(clipBoxes));
159572b676d7Smrg#else
159672b676d7Smrg      xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
159772b676d7Smrg#endif
159872b676d7Smrg   }
159972b676d7Smrg
160072b676d7Smrg   pPriv->videoStatus = CLIENT_VIDEO_ON;
160172b676d7Smrg
160272b676d7Smrg   return Success;
160372b676d7Smrg}
160472b676d7Smrg
160572b676d7SmrgXF86OffscreenImageRec SIS6326OffscreenImages[2] =
160672b676d7Smrg{
160772b676d7Smrg {
160872b676d7Smrg   &SIS6326Images[0],  	/* YUV2 */
160972b676d7Smrg   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
161072b676d7Smrg   SIS6326AllocSurface,
161172b676d7Smrg   SIS6326FreeSurface,
161272b676d7Smrg   SIS6326DisplaySurface,
161372b676d7Smrg   SIS6326StopSurface,
161472b676d7Smrg   SIS6326GetSurfaceAttribute,
161572b676d7Smrg   SIS6326SetSurfaceAttribute,
161672b676d7Smrg   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
161772b676d7Smrg   NUM_ATTRIBUTES,
161872b676d7Smrg   &SIS6326Attributes[0]  /* Support all attributes */
161972b676d7Smrg  },
162072b676d7Smrg  {
162172b676d7Smrg   &SIS6326Images[1],	/* UYVY */
162272b676d7Smrg   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
162372b676d7Smrg   SIS6326AllocSurface,
162472b676d7Smrg   SIS6326FreeSurface,
162572b676d7Smrg   SIS6326DisplaySurface,
162672b676d7Smrg   SIS6326StopSurface,
162772b676d7Smrg   SIS6326GetSurfaceAttribute,
162872b676d7Smrg   SIS6326SetSurfaceAttribute,
162972b676d7Smrg   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
163072b676d7Smrg   NUM_ATTRIBUTES,
163172b676d7Smrg   &SIS6326Attributes[0]  /* Support all attributes */
163272b676d7Smrg  },
163372b676d7Smrg};
163472b676d7Smrg
163572b676d7Smrgstatic void
163672b676d7SmrgSIS6326InitOffscreenImages(ScreenPtr pScrn)
163772b676d7Smrg{
163872b676d7Smrg    xf86XVRegisterOffscreenImages(pScrn, SIS6326OffscreenImages, 2);
163972b676d7Smrg}
164072b676d7Smrg
164172b676d7Smrg
164272b676d7Smrg
164372b676d7Smrg
1644