sis6326_video.c revision 1fd23544
1/*
2 * Xv driver for SiS 5597/5598, 6326 and 530/620.
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 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include "sis.h"
37
38#ifdef SIS_USE_XAA
39#include "xf86fbman.h"
40#endif
41#include "xf86xv.h"
42#include "regionstr.h"
43#include <X11/extensions/Xv.h>
44#include "dixstruct.h"
45#include "fourcc.h"
46
47#define SIS_NEED_inSISREG
48#define SIS_NEED_outSISREG
49#define SIS_NEED_inSISIDXREG
50#define SIS_NEED_outSISIDXREG
51#define SIS_NEED_setSISIDXREGmask
52#include "sis_regs.h"
53
54#define OFF_DELAY   	200  /* milliseconds */
55#define FREE_DELAY  	60000
56
57#define OFF_TIMER   	0x01
58#define FREE_TIMER  	0x02
59#define CLIENT_VIDEO_ON 0x04
60
61#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
62
63#define WATCHDOG_DELAY  500000 /* Watchdog counter for Vertical Restrace waiting */
64
65static 		XF86VideoAdaptorPtr SIS6326SetupImageVideo(ScreenPtr);
66static void 	SIS6326StopVideo(ScrnInfoPtr, pointer, Bool);
67static int 	SIS6326SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
68static int 	SIS6326GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
69static void 	SIS6326QueryBestSize(ScrnInfoPtr, Bool, short, short, short,
70			short, unsigned int *,unsigned int *, pointer);
71static int 	SIS6326PutImage( ScrnInfoPtr,
72			short, short, short, short, short, short, short, short,
73			int, unsigned char*, short, short, Bool, RegionPtr, pointer,
74			DrawablePtr);
75static int 	SIS6326QueryImageAttributes(ScrnInfoPtr,
76			int, unsigned short *, unsigned short *, int *, int *);
77static void 	SIS6326VideoTimerCallback(ScrnInfoPtr pScrn, Time now);
78static void     SIS6326InitOffscreenImages(ScreenPtr pScrn);
79
80extern unsigned int	SISAllocateFBMemory(ScrnInfoPtr pScrn, void **handle, int bytesize);
81extern void		SISFreeFBMemory(ScrnInfoPtr pScrn, void **handle);
82
83#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
84
85static Atom xvBrightness, xvContrast, xvColorKey;
86static Atom xvAutopaintColorKey, xvSetDefaults;
87static Atom xvDisableGfx;
88
89#define IMAGE_MIN_WIDTH        32  /* Minimum and maximum image sizes */
90#define IMAGE_MIN_HEIGHT       24
91#define IMAGE_MAX_WIDTH       720  /* Are these correct for the chips ? */
92#define IMAGE_MAX_HEIGHT      576
93#define IMAGE_MAX_WIDTH_5597  384
94#define IMAGE_MAX_HEIGHT_5597 288
95
96#if 0
97static int oldH, oldW;
98#endif
99
100/****************************************************************************
101 * Raw register access : These routines directly interact with the sis's
102 *                       control aperature.  Must not be called until after
103 *                       the board's pci memory has been mapped.
104 ****************************************************************************/
105
106#if 0
107static CARD32 _sisread(SISPtr pSiS, CARD32 reg)
108{
109    return *(pSiS->IOBase + reg);
110}
111
112static void _siswrite(SISPtr pSiS, CARD32 reg, CARD32 data)
113{
114    *(pSiS->IOBase + reg) = data;
115}
116#endif
117
118static CARD8 getvideoreg(SISPtr pSiS, CARD8 reg)
119{
120    CARD8 ret;
121    inSISIDXREG(SISCR, reg, ret);
122    return ret;
123}
124
125static __inline void setvideoreg(SISPtr pSiS, CARD8 reg, CARD8 data)
126{
127    outSISIDXREG(SISCR, reg, data);
128}
129
130static __inline void setvideoregmask(SISPtr pSiS, CARD8 reg, CARD8 data, CARD8 mask)
131{
132    setSISIDXREGmask(SISCR, reg, data, mask);
133}
134
135/* VBlank */
136static CARD8 vblank_active_CRT1(SISPtr pSiS)
137{
138    return (inSISREG(SISINPSTAT) & 0x08);
139}
140
141/* Scanline - unused */
142#if 0
143static CARD32 get_scanline_CRT1(SISPtr pSiS)
144{
145    CARD8 temp;
146
147    temp = getvideoreg(pSiS, 0x20);
148    temp = getvideoreg(pSiS, 0x1b);
149    return((getvideoreg(pSiS, 0x1d) << 8) | getvideoreg(pSiS, 0x1c));
150}
151#endif
152
153void SIS6326InitVideo(ScreenPtr pScreen)
154{
155    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
156    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
157    XF86VideoAdaptorPtr newAdaptor = NULL;
158    int num_adaptors;
159
160    newAdaptor = SIS6326SetupImageVideo(pScreen);
161    if(newAdaptor) {
162        SIS6326InitOffscreenImages(pScreen);
163    }
164
165    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
166
167    if(newAdaptor) {
168	if(!num_adaptors) {
169		num_adaptors = 1;
170		adaptors = &newAdaptor;
171	} else {
172		/* need to free this someplace */
173		newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
174		if(newAdaptors) {
175			memcpy(newAdaptors, adaptors, num_adaptors *
176				sizeof(XF86VideoAdaptorPtr));
177			newAdaptors[num_adaptors] = newAdaptor;
178			adaptors = newAdaptors;
179			num_adaptors++;
180		}
181	}
182    }
183
184    if(num_adaptors)
185	xf86XVScreenInit(pScreen, adaptors, num_adaptors);
186
187    if(newAdaptors)
188	xfree(newAdaptors);
189}
190
191/* client libraries expect an encoding */
192static XF86VideoEncodingRec DummyEncoding =
193{
194   0,
195   "XV_IMAGE",
196   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
197   {1, 1}
198};
199
200static XF86VideoEncodingRec DummyEncoding5597 =
201{
202   0,
203   "XV_IMAGE",
204   IMAGE_MAX_WIDTH_5597, IMAGE_MAX_HEIGHT_5597,
205   {1, 1}
206};
207
208#define NUM_FORMATS 4
209
210static XF86VideoFormatRec SIS6326Formats[NUM_FORMATS] =
211{
212   { 8, PseudoColor},
213   {15, TrueColor},
214   {16, TrueColor},
215   {24, TrueColor}
216};
217
218#define NUM_ATTRIBUTES 6
219
220static XF86AttributeRec SIS6326Attributes[NUM_ATTRIBUTES] =
221{
222   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
223   {XvSettable | XvGettable, -128, 127,        "XV_BRIGHTNESS"},
224   {XvSettable | XvGettable, 0, 7,             "XV_CONTRAST"},
225   {XvSettable | XvGettable, 0, 1,             "XV_AUTOPAINT_COLORKEY"},
226   {XvSettable             , 0, 0,             "XV_SET_DEFAULTS"},
227   {XvSettable | XvGettable, 0, 1,             "XV_DISABLE_GRAPHICS"}
228};
229
230#define NUM_IMAGES 6
231#define NUM_IMAGES_NOYV12 4
232#define PIXEL_FMT_YV12 FOURCC_YV12  /* 0x32315659 */
233#define PIXEL_FMT_UYVY FOURCC_UYVY  /* 0x59565955 */
234#define PIXEL_FMT_YUY2 FOURCC_YUY2  /* 0x32595559 */
235#define PIXEL_FMT_I420 FOURCC_I420  /* 0x30323449 */
236#define PIXEL_FMT_RGB5 0x35315652
237#define PIXEL_FMT_RGB6 0x36315652
238
239static XF86ImageRec SIS6326Images[NUM_IMAGES] =
240{
241    XVIMAGE_YUY2, /* If order is changed, SIS6326OffscreenImages must be adapted */
242    XVIMAGE_UYVY,
243    XVIMAGE_YV12,
244    XVIMAGE_I420,
245    {
246      0x35315652,
247      XvRGB,
248      LSBFirst,
249      {'R','V','1','5',
250       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
251      16,
252      XvPacked,
253      1,
254      15, 0x7C00, 0x03E0, 0x001F,
255      0, 0, 0,
256      0, 0, 0,
257      0, 0, 0,
258      {'R', 'V', 'B',0,
259       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},
260      XvTopToBottom
261    },
262    {
263      0x36315652,
264      XvRGB,
265      LSBFirst,
266      {'R','V','1','6',
267       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
268      16,
269      XvPacked,
270      1,
271      16, 0xF800, 0x07E0, 0x001F,
272      0, 0, 0,
273      0, 0, 0,
274      0, 0, 0,
275      {'R', 'V', 'B',0,
276       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},
277      XvTopToBottom
278    }
279};
280
281static XF86ImageRec SIS6326ImagesNoYV12[NUM_IMAGES_NOYV12] =
282{
283    XVIMAGE_YUY2, /* If order is changed, SIS6326OffscreenImages must be adapted */
284    XVIMAGE_UYVY,
285    {
286      0x35315652,
287      XvRGB,
288      LSBFirst,
289      {'R','V','1','5',
290       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
291      16,
292      XvPacked,
293      1,
294      15, 0x7C00, 0x03E0, 0x001F,
295      0, 0, 0,
296      0, 0, 0,
297      0, 0, 0,
298      {'R', 'V', 'B',0,
299       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},
300      XvTopToBottom
301    },
302    {
303      0x36315652,
304      XvRGB,
305      LSBFirst,
306      {'R','V','1','6',
307       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
308      16,
309      XvPacked,
310      1,
311      16, 0xF800, 0x07E0, 0x001F,
312      0, 0, 0,
313      0, 0, 0,
314      0, 0, 0,
315      {'R', 'V', 'B',0,
316       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},
317      XvTopToBottom
318    }
319};
320
321typedef struct {
322    int pixelFormat;
323
324    CARD16  pitch;
325
326    CARD8   keyOP;
327
328    CARD8   HUSF;
329    CARD8   VUSF;
330    CARD8   HIntBit;
331    CARD8   wHPre;
332    CARD8   PitchMult;
333
334    CARD16  srcW;
335    CARD16  srcH;
336
337    BoxRec  dstBox;
338
339    CARD32  PSY;
340    CARD32  PSV;
341    CARD32  PSU;
342    CARD8   YUVEnd;
343
344    CARD8   lineBufSize;
345
346    CARD8   (*VBlankActiveFunc)(SISPtr);
347/*  CARD32  (*GetScanLineFunc)(SISPtr pSiS); */
348
349} SISOverlayRec, *SISOverlayPtr;
350
351typedef struct {
352    void *       handle;
353    CARD32       bufAddr[2];
354
355    unsigned char currentBuf;
356
357    short  drw_x, drw_y, drw_w, drw_h;
358    short  src_x, src_y, src_w, src_h;
359    int    id;
360    short  srcPitch, height, width;
361    CARD32 totalSize;
362
363    char          brightness;
364    unsigned char contrast;
365
366    RegionRec    clip;
367    CARD32       colorKey;
368    Bool 	 autopaintColorKey;
369
370    Bool 	 disablegfx;
371
372    CARD32       videoStatus;
373    Time         offTime;
374    Time         freeTime;
375
376    short        oldx1, oldx2, oldy1, oldy2;
377    int          mustwait;
378
379    Bool         grabbedByV4L;	   /* V4L stuff */
380    int          pitch;
381    int          offset;
382
383} SISPortPrivRec, *SISPortPrivPtr;
384
385#define GET_PORT_PRIVATE(pScrn) \
386   (SISPortPrivPtr)((SISPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
387
388static void
389SIS6326SetPortDefaults(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
390{
391    SISPtr    pSiS = SISPTR(pScrn);
392
393    pPriv->colorKey    = 0x000101fe;
394    pPriv->videoStatus = 0;
395    pPriv->brightness  = pSiS->XvDefBri; /* 0; - see sis_opt.c */
396    pPriv->contrast    = pSiS->XvDefCon; /* 4; */
397    pPriv->autopaintColorKey = TRUE;
398    pPriv->disablegfx  = pSiS->XvDefDisableGfx;
399}
400
401static void
402SIS6326ResetVideo(ScrnInfoPtr pScrn)
403{
404    SISPtr pSiS = SISPTR(pScrn);
405
406    /* Unlock registers */
407#ifdef UNLOCK_ALWAYS
408    sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
409#endif
410    if(getvideoreg(pSiS, Index_VI6326_Passwd) != 0xa1) {
411       setvideoreg(pSiS, Index_VI6326_Passwd, 0x86);
412       if(getvideoreg(pSiS, Index_VI6326_Passwd) != 0xa1)
413          xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
414                     "Xv: Video password could not unlock video registers\n");
415    }
416
417    /* Initialize the overlay ----------------------------------- */
418
419    switch(pSiS->Chipset) {
420    case PCI_CHIP_SIS5597:
421       /* Disable overlay (D[1]) & capture (D[0]) */
422       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x03);
423
424       /* What do these do? (Datasheet names these bits "reserved") */
425       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x18);
426       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x0c);
427
428       /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */
429       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x40, 0xD0);
430       /* No interrupt, no filter, disable dithering */
431       setvideoregmask(pSiS, Index_VI6326_Control_Misc1,     0x00, 0x7A);
432       /* Disable Brooktree support (D[6]) and system memory framebuffer (D[7]) */
433       setvideoregmask(pSiS, Index_VI6326_Control_Misc3,     0x00, 0xC0);
434       /* Disable video decimation (has a really strange effect if enabled) */
435       setvideoregmask(pSiS, Index_VI6326_Control_Misc6,     0x00, 0x80);
436       break;
437    case PCI_CHIP_SIS6326:
438       /* Disable overlay (D[1]) & capture (D[0]) */
439       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x03);
440
441       /* What do these do? (Datasheet names these bits "reserved") */
442       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x18);
443       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x0c);
444
445       /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */
446       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x40, 0xD0);
447       /* No interrupt, no filter, disable dithering */
448       setvideoregmask(pSiS, Index_VI6326_Control_Misc1,     0x00, 0x7A);
449       /* Disable VMI (D[4:3]), Brooktree support (D[6]) and system memory framebuffer (D[7]) */
450       setvideoregmask(pSiS, Index_VI6326_Control_Misc3,     0x00, 0xF8);
451       /* Disable video decimation */
452       setvideoregmask(pSiS, Index_VI6326_Control_Misc6,     0x00, 0x80);
453       break;
454    case PCI_CHIP_SIS530:
455       setvideoregmask(pSiS, Index_VI6326_Control_Misc4,     0x40, 0x40);
456       /* Disable overlay (D[1]) */
457       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x02);
458
459       /* What do D[3:2] do? (Datasheet names these bits "reserved") */
460       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x18);
461       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x00, 0x0c);
462
463       /* Select YUV format (D[6]) and "gfx + video" mode (D[4]) */
464       setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     0x40, 0x50);
465       break;
466    default:
467	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
468		"Internal error: SiS6326ResetVideo() called with invalid chipset (%x)\n",
469		pSiS->Chipset);
470        return;
471    }
472
473    /* Clear format selection */
474    setvideoregmask(pSiS, Index_VI6326_Control_Misc1,         0x00, 0x04);
475    if(pSiS->oldChipset >= OC_SIS5597) {
476       setvideoregmask(pSiS, Index_VI6326_Control_Misc4,      0x00, 0x05);
477    }
478
479    /* Select RGB Chromakey format (D[2]=0), CCIR 601 UV data format (D[1]=0) */
480    /* D[1]: 1 = 2's complement, 0 = CCIR 601 format */
481    setvideoregmask(pSiS, Index_VI6326_Control_Misc3,         0x00, 0x06);
482
483    /* Reset contrast control */
484    setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl,     0x04, 0x1F);
485
486    /* Set threshold */
487    if(pSiS->oldChipset < OC_SIS6326) {
488       CARD8 temp;
489       inSISIDXREG(SISSR, 0x33, temp);  /* Synchronous DRAM Timing? */
490       if(temp & 0x01) temp = 0x50;
491       else            temp = 0;
492       setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low,     temp);
493       setvideoreg(pSiS, Index_VI6326_Play_Threshold_High,    temp);
494    } else {
495       CARD8 temp;
496       setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low,     0x00);
497       setvideoreg(pSiS, Index_VI6326_Play_Threshold_High,    0x00);
498       inSISIDXREG(SISSR, 0x33, temp);  /* Are we using SGRAM Timing? */
499       if(temp & 0x01) temp = 0x10;
500       else            temp = 0;
501       setvideoregmask(pSiS, Index_VI6326_Control_Misc4,      temp, 0x10);
502    }
503
504    /* set default properties for overlay     ------------------------------- */
505
506    setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl,    0x04, 0x07);
507    setvideoreg(pSiS, Index_VI6326_Brightness,               0x20);
508
509    if(pSiS->oldChipset < OC_SIS6205A || pSiS->oldChipset > OC_SIS82204) {
510       setvideoregmask(pSiS, Index_VI6326_AlphaGraph,         0x00, 0xF8);
511       setvideoregmask(pSiS, Index_VI6326_AlphaVideo,         0xF8, 0xF8);
512    } else {
513       setvideoregmask(pSiS, Index_VI6326_AlphaGraph,         0x00, 0xE1);
514       setvideoregmask(pSiS, Index_VI6326_AlphaVideo,         0xE1, 0xE1);
515    }
516
517}
518
519static XF86VideoAdaptorPtr
520SIS6326SetupImageVideo(ScreenPtr pScreen)
521{
522    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
523    SISPtr pSiS = SISPTR(pScrn);
524    XF86VideoAdaptorPtr adapt;
525    SISPortPrivPtr pPriv;
526
527#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
528    XAAInfoRecPtr pXAA = pSiS->AccelInfoPtr;
529
530    if(!pXAA || !pXAA->FillSolidRects)
531       return NULL;
532#endif
533
534    if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
535                            sizeof(SISPortPrivRec) +
536                            sizeof(DevUnion))))
537       return NULL;
538
539    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
540    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
541    adapt->name = "SIS 5597/5598/6326/530/620 Video Overlay";
542    adapt->nEncodings = 1;
543    if(pSiS->oldChipset < OC_SIS6326) {
544       adapt->pEncodings = &DummyEncoding5597;
545    } else {
546       adapt->pEncodings = &DummyEncoding;
547    }
548    adapt->nFormats = NUM_FORMATS;
549    adapt->pFormats = SIS6326Formats;
550    adapt->nPorts = 1;
551    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
552
553    pPriv = (SISPortPrivPtr)(&adapt->pPortPrivates[1]);
554
555    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
556    adapt->pAttributes = SIS6326Attributes;
557    adapt->nAttributes = NUM_ATTRIBUTES;
558    if(pSiS->NoYV12 == 1) {
559       adapt->nImages = NUM_IMAGES_NOYV12;
560       adapt->pImages = SIS6326ImagesNoYV12;
561    } else {
562       adapt->nImages = NUM_IMAGES;
563       adapt->pImages = SIS6326Images;
564    }
565    adapt->PutVideo = NULL;
566    adapt->PutStill = NULL;
567    adapt->GetVideo = NULL;
568    adapt->GetStill = NULL;
569    adapt->StopVideo = SIS6326StopVideo;
570    adapt->SetPortAttribute = SIS6326SetPortAttribute;
571    adapt->GetPortAttribute = SIS6326GetPortAttribute;
572    adapt->QueryBestSize = SIS6326QueryBestSize;
573    adapt->PutImage = SIS6326PutImage;
574    adapt->QueryImageAttributes = SIS6326QueryImageAttributes;
575
576    pPriv->videoStatus = 0;
577    pPriv->currentBuf  = 0;
578    pPriv->handle      = NULL;
579    pPriv->grabbedByV4L= FALSE;
580
581    SIS6326SetPortDefaults(pScrn, pPriv);
582
583    /* gotta uninit this someplace */
584#if defined(REGION_NULL)
585    REGION_NULL(pScreen, &pPriv->clip);
586#else
587    REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
588#endif
589
590    pSiS->adaptor = adapt;
591
592    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
593    xvContrast   = MAKE_ATOM("XV_CONTRAST");
594    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
595    xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
596    xvSetDefaults       = MAKE_ATOM("XV_SET_DEFAULTS");
597    xvDisableGfx = MAKE_ATOM("XV_DISABLE_GRAPHICS");
598
599    SIS6326ResetVideo(pScrn);
600    pSiS->ResetXv = SIS6326ResetVideo;
601
602    return adapt;
603}
604
605#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
606static Bool
607RegionsEqual(RegionPtr A, RegionPtr B)
608{
609    int *dataA, *dataB;
610    int num;
611
612    num = REGION_NUM_RECTS(A);
613    if(num != REGION_NUM_RECTS(B))
614    return FALSE;
615
616    if((A->extents.x1 != B->extents.x1) ||
617       (A->extents.x2 != B->extents.x2) ||
618       (A->extents.y1 != B->extents.y1) ||
619       (A->extents.y2 != B->extents.y2))
620    return FALSE;
621
622    dataA = (int*)REGION_RECTS(A);
623    dataB = (int*)REGION_RECTS(B);
624
625    while(num--) {
626      if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
627        return FALSE;
628      dataA += 2;
629      dataB += 2;
630    }
631
632    return TRUE;
633}
634#endif
635
636static int
637SIS6326SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
638		    INT32 value, pointer data)
639{
640  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
641
642  if(attribute == xvBrightness) {
643     if((value < -128) || (value > 127))
644        return BadValue;
645     pPriv->brightness = value;
646  } else if(attribute == xvContrast) {
647     if((value < 0) || (value > 7))
648        return BadValue;
649     pPriv->contrast = value;
650  } else if(attribute == xvColorKey) {
651     pPriv->colorKey = value;
652     REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
653  } else if (attribute == xvAutopaintColorKey) {
654     if((value < 0) || (value > 1))
655        return BadValue;
656     pPriv->autopaintColorKey = value;
657  } else if(attribute == xvDisableGfx) {
658     if((value < 0) || (value > 1))
659        return BadValue;
660     pPriv->disablegfx = value;
661  } else if (attribute == xvSetDefaults) {
662     SIS6326SetPortDefaults(pScrn, pPriv);
663  } else return BadMatch;
664  return Success;
665}
666
667static int
668SIS6326GetPortAttribute(
669  ScrnInfoPtr pScrn,
670  Atom attribute,
671  INT32 *value,
672  pointer data
673){
674  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
675
676  if(attribute == xvBrightness) {
677     *value = pPriv->brightness;
678  } else if(attribute == xvContrast) {
679     *value = pPriv->contrast;
680  } else if(attribute == xvColorKey) {
681     *value = pPriv->colorKey;
682  } else if (attribute == xvAutopaintColorKey) {
683     *value = (pPriv->autopaintColorKey) ? 1 : 0;
684  } else if (attribute == xvDisableGfx) {
685     *value = (pPriv->disablegfx) ? 1 : 0;
686  } else return BadMatch;
687  return Success;
688}
689
690static void
691SIS6326QueryBestSize(
692  ScrnInfoPtr pScrn,
693  Bool motion,
694  short vid_w, short vid_h,
695  short drw_w, short drw_h,
696  unsigned int *p_w, unsigned int *p_h,
697  pointer data
698){
699  *p_w = drw_w;
700  *p_h = drw_h;
701
702  /* TODO: report the HW limitation */
703}
704
705static void  /* V 530/6326 */
706calc_scale_factor(SISPtr pSiS, SISOverlayPtr pOverlay, ScrnInfoPtr pScrn,
707                 SISPortPrivPtr pPriv)
708{
709  CARD32 temp=0;
710
711  int dstW = pOverlay->dstBox.x2 - pOverlay->dstBox.x1;
712  int dstH = pOverlay->dstBox.y2 - pOverlay->dstBox.y1;
713  int srcW = pOverlay->srcW;
714  int srcH = pOverlay->srcH;
715
716  /* For double scan modes, we need to double the height */
717  if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) {
718	dstH <<= 1;
719  }
720  /* For interlace modes, we need to half the height */
721  if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) {
722	dstH >>= 1;
723  }
724
725  /* Horizontal */
726  if(dstW < IMAGE_MIN_WIDTH) dstW = IMAGE_MIN_WIDTH;
727  if(dstW == srcW) {
728	pOverlay->HUSF    = 0x00;
729	pOverlay->HIntBit = 0x01;
730  } else if(dstW > srcW) {
731	pOverlay->HIntBit = 0x00;
732	temp = srcW * 64 / (dstW + 1);
733	if(temp > 63) temp = 63;
734	pOverlay->HUSF = temp;
735  } else {
736	/* 6326 can't scale below factor .440 - to check with 530/620 */
737	if(((dstW * 1000) / srcW) < 440) dstW = ((srcW * 440) / 1000) + 1;
738	temp = srcW / dstW;
739	if(temp > 15) temp = 15;
740	pOverlay->HIntBit = temp;
741	temp = srcW * 64 / dstW;
742	pOverlay->HUSF = temp - (pOverlay->HIntBit * 64);
743  }
744
745  /* Vertical */
746  if(dstH < IMAGE_MIN_HEIGHT) dstH = IMAGE_MIN_HEIGHT;
747  if(dstH == srcH) {
748	pOverlay->VUSF = 0x00;
749	pOverlay->PitchMult = 1;
750  } else if(dstH > srcH) {
751	temp = srcH * 64 / (dstH + 1);
752	if (temp > 63) temp = 63;
753	pOverlay->VUSF = temp;
754	pOverlay->PitchMult = 1;
755  } else {
756	/* 6326 can't scale below factor .440 - to check with 530/620 */
757	if(((dstH * 1000) / srcH) < 440) dstH = ((srcH * 440) / 1000) + 1;
758	temp = srcH / dstH;
759	if(srcH % dstH) {
760	   temp++;
761	   pOverlay->VUSF = (srcH * 64) / (temp * dstH);
762	} else {
763	   pOverlay->VUSF = 0x00;
764	}
765	pOverlay->PitchMult = temp;
766  }
767}
768
769static void
770calc_line_buf_size(SISOverlayPtr pOverlay)
771{
772    CARD32 I;
773    CARD32 line = pOverlay->srcW;
774
775    if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
776        (pOverlay->pixelFormat == PIXEL_FMT_I420) ) {
777	I = (line >> 5) + (((line >> 6) * 2)) + 3;
778	I <<= 5;
779    } else { /* YUV2, UYVY, RGB */
780	I = line << 1;
781	if(I & 7)  I += 8;
782    }
783    I += 8;
784    I >>= 3;
785    pOverlay->lineBufSize = (CARD8)I;
786}
787
788static void
789merge_line_buf(SISPtr pSiS, SISPortPrivPtr pPriv, Bool enable)
790{
791  if(enable) {
792     setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x10, 0x10);
793  } else {
794     setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x00, 0x10);
795  }
796}
797
798static void
799set_format(SISPtr pSiS, SISOverlayPtr pOverlay)
800{
801    CARD8 fmt, misc0, misc1, misc4;
802
803    switch(pOverlay->pixelFormat) {
804    case PIXEL_FMT_YV12:
805    case PIXEL_FMT_I420: /* V/530 V/6326 */
806	fmt   = 0x80;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
807	misc0 = 0x40;  /* D[6]: 1 = YUV, 0 = RGB */
808	misc4 = 0x05;  /* D[1:0] 00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
809	misc1 = 0xff;
810	break;
811    case PIXEL_FMT_UYVY:
812	fmt   = 0x00;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
813	misc0 = 0x40;  /* D[6]: 1 = YUV, 0 = RGB */
814	misc4 = 0x00;  /* D[1:0] 00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
815	misc1 = 0xff;
816	break;
817    case PIXEL_FMT_YUY2: /* V/530 V/6326 */
818	fmt   = 0x80;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
819	misc0 = 0x40;  /* D[6]: 1 = YUV, 0 = RGB */
820	misc4 = 0x00;  /* D[1:0]  00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
821	misc1 = 0xff;
822	break;
823    case PIXEL_FMT_RGB6: /* V/530 V/6326 */
824	fmt   = 0x40;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
825	misc0 = 0x00;  /* D[6]: 1 = YUV, 0 = RGB */
826	misc4 = 0xff;
827	misc1 = 0x00;  /* D[2] = Capture format selection (DS5597) - WDR sets this */
828	break;
829    case PIXEL_FMT_RGB5: /* V/530 V/6326 */
830    default:
831	fmt   = 0x00;  /* D[7:6]  10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
832	misc0 = 0x00;  /* D[6]: 1 = YUV, 0 = RGB */
833	misc4 = 0xff;
834	misc1 = 0x04;  /* D[2] = Capture format selection (DS5597) - WDR sets this */
835	break;
836    }
837
838    setvideoregmask(pSiS, Index_VI6326_VideoFormatSelect, fmt,   0xC0);
839    setvideoregmask(pSiS, Index_VI6326_Control_Misc0,     misc0, 0x40);
840    if(misc4 == 0xff) {
841       setvideoregmask(pSiS, Index_VI6326_Control_Misc1, misc1, 0x04);
842       if(pSiS->oldChipset >= OC_SIS5597) {
843	  setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x00, 0x05);
844       }
845    } else {
846       if(pSiS->oldChipset >= OC_SIS5597) {
847	  setvideoregmask(pSiS, Index_VI6326_Control_Misc4, misc4, 0x05);
848       }
849       setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x04);
850    }
851}
852
853static void
854set_colorkey(SISPtr pSiS, CARD32 colorkey)
855{
856    CARD8 r, g, b, s;
857
858    b = (CARD8)(colorkey & 0xFF);
859    g = (CARD8)((colorkey >> 8) & 0xFF);
860    r = (CARD8)((colorkey >> 16) & 0xFF);
861
862    if(pSiS->CurrentLayout.bitsPerPixel >= 24) {
863       s = b;
864       b = r;
865       r = s;
866    }
867
868    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Blue_Min  ,(CARD8)b);
869    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Green_Min ,(CARD8)g);
870    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Red_Min   ,(CARD8)r);
871
872    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Blue_Max  ,(CARD8)b);
873    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Green_Max ,(CARD8)g);
874    setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Red_Max   ,(CARD8)r);
875}
876
877static __inline void
878set_brightness(SISPtr pSiS, CARD8 brightness)
879{
880    setvideoreg(pSiS, Index_VI6326_Brightness, brightness);
881}
882
883static __inline void
884set_contrast(SISPtr pSiS, CARD8 contrast)
885{
886    setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, contrast, 0x07);
887}
888
889static void
890set_contrast_data(SISPtr pSiS, int value)
891{
892  unsigned long temp;
893
894  if(value < 10000) temp = 0;
895  else temp = (value - 10000) / 20000;
896  if(temp > 3) temp = 3;
897  setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, (temp << 6), 0xC0);
898  switch(temp) {
899     case 0: temp =  2048; break;
900     case 1: temp =  4096; break;
901     case 2: temp =  8192; break;
902     case 3: temp = 16384; break;
903  }
904  temp <<= 10;
905  temp /= value;
906  setvideoreg(pSiS, Index_VI6326_Contrast_Factor, temp);
907}
908
909static __inline void
910set_disablegfx(SISPtr pSiS, Bool mybool)
911{
912    setvideoregmask(pSiS, Index_VI6326_Control_Misc0, mybool ? 0x10 : 0x00, 0x10);
913}
914
915static void
916set_overlay(SISPtr pSiS, SISOverlayPtr pOverlay, SISPortPrivPtr pPriv, int index)
917{
918    ScrnInfoPtr pScrn = pSiS->pScrn;
919
920    CARD16 pitch=0;
921    CARD8  h_over=0, v_over=0;
922    CARD16 top, bottom, left, right;
923    CARD16 screenX = pSiS->CurrentLayout.mode->HDisplay;
924    CARD16 screenY = pSiS->CurrentLayout.mode->VDisplay;
925    CARD32 watchdog;
926
927    top = pOverlay->dstBox.y1;
928    bottom = pOverlay->dstBox.y2;
929    if(bottom > screenY) {
930       bottom = screenY;
931    }
932
933    left = pOverlay->dstBox.x1;
934    right = pOverlay->dstBox.x2;
935    if(right > screenX) {
936       right = screenX;
937    }
938
939    /* TW: DoubleScan modes require Y coordinates * 2 */
940    if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) {
941       top <<= 1;
942       bottom <<= 1;
943    }
944    /* TW: Interlace modes require Y coordinates / 2 */
945    if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) {
946       top >>= 1;
947       bottom >>= 1;
948    }
949
950    h_over = (((left>>8) & 0x07) | ((right>>4) & 0x70));
951    v_over = (((top>>8) & 0x07) | ((bottom>>4) & 0x70));
952
953    pitch = pOverlay->pitch * pOverlay->PitchMult;
954    pitch >>= 2;   /* Datasheet: Unit = double word - verified */
955    if(pitch > 0xfff) {
956       pitch = pOverlay->pitch * (0xFFF * 2 / pOverlay->pitch);
957       pOverlay->VUSF = 0x3F;
958    }
959
960    /* set color key */
961    set_colorkey(pSiS, pPriv->colorKey);
962
963    /* set color key mode */
964    setvideoregmask(pSiS, Index_VI6326_Key_Overlay_OP, pOverlay->keyOP, 0x0f);
965
966    setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c);
967    setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18);
968
969    /* Set Y buf pitch */   /* Datasheet: Unit = double word - verified */
970    setvideoreg(pSiS, Index_VI6326_Disp_Y_Buf_Pitch_Low, (CARD8)(pitch));
971    setvideoregmask(pSiS, Index_VI6326_Disp_Y_Buf_Pitch_High, (CARD8)(pitch>>8), 0x0f);
972    /* Set U/V pitch if using planar formats */
973    if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
974    	(pOverlay->pixelFormat == PIXEL_FMT_I420) )  {
975       /* Set U/V pitch */  /* Datasheet: Unit = double word - verified */
976       setvideoreg(pSiS, Index_VI6326_Disp_UV_Buf_Pitch_Low, (CARD8)pitch >> 1);
977       setvideoregmask(pSiS, Index_VI6326_Disp_UV_Buf_Pitch_High, (CARD8)(pitch >> 9), 0x0f);
978    }
979
980    /* set line buffer size */
981    setvideoreg(pSiS, Index_VI6326_Line_Buffer_Size, pOverlay->lineBufSize);
982
983    /* set scale factor */
984    setvideoreg(pSiS, Index_VI6326_Hor_Scale,             (CARD8)((pOverlay->HUSF) | 0xC0));
985    setvideoregmask(pSiS, Index_VI6326_Hor_Scale_Integer, (CARD8)(pOverlay->HIntBit), 0x0F);
986    setvideoregmask(pSiS, Index_VI6326_Ver_Scale,         (CARD8)(pOverlay->VUSF), 0x3F);
987
988    /* TW: We don't have to wait for vertical retrace in all cases */
989    if(pPriv->mustwait) {
990       watchdog = WATCHDOG_DELAY;
991       while ((!pOverlay->VBlankActiveFunc(pSiS)) && --watchdog);
992       if(!watchdog) xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
993		"Xv: Waiting for vertical retrace timed-out\n");
994    }
995
996    /* set destination window position */
997    setvideoreg(pSiS, Index_VI6326_Win_Hor_Disp_Start_Low, (CARD8)left);
998    setvideoreg(pSiS, Index_VI6326_Win_Hor_Disp_End_Low,   (CARD8)right);
999    setvideoreg(pSiS, Index_VI6326_Win_Hor_Over,           (CARD8)h_over);
1000
1001    setvideoreg(pSiS, Index_VI6326_Win_Ver_Disp_Start_Low, (CARD8)top);
1002    setvideoreg(pSiS, Index_VI6326_Win_Ver_Disp_End_Low,   (CARD8)bottom);
1003    setvideoreg(pSiS, Index_VI6326_Win_Ver_Over,           (CARD8)v_over);
1004
1005    /* Set Y start address */
1006    setvideoreg(pSiS, Index_VI6326_Disp_Y_Buf_Start_Low,    (CARD8)(pOverlay->PSY));
1007    setvideoreg(pSiS, Index_VI6326_Disp_Y_Buf_Start_Middle, (CARD8)((pOverlay->PSY)>>8));
1008    if(pSiS->oldChipset <= OC_SIS6326) {  	/* all old chipsets incl 6326 */
1009       /* Set overflow bits */
1010       setvideoregmask(pSiS, Index_VI6326_Disp_Capt_Y_Buf_Start_High,
1011                                             (CARD8)(((pOverlay->PSY)>>12) & 0xF0), 0xF0);
1012       /* Set framebuffer end address */
1013       setvideoreg(pSiS, Index_VI6326_Disp_Y_End,    (CARD8)(pOverlay->YUVEnd));
1014    } else {  				/* 530/620 */
1015       /* Set overflow bits */
1016       setvideoregmask(pSiS, Index_VI6326_Disp_Capt_Y_Buf_Start_High,
1017                                             (CARD8)(((pOverlay->PSY)>>13) & 0xF8), 0xF8);
1018    }
1019
1020    /* Set U/V start addresses if using plane formats */
1021    if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
1022    	(pOverlay->pixelFormat == PIXEL_FMT_I420) )  {
1023
1024        CARD32 PSU = pOverlay->PSU;
1025        CARD32 PSV = pOverlay->PSV;
1026
1027        /* set U/V start address */
1028        setvideoreg(pSiS, Index_VI6326_U_Buf_Start_Low,   (CARD8)PSU);
1029        setvideoreg(pSiS, Index_VI6326_U_Buf_Start_Middle,(CARD8)(PSU >> 8));
1030
1031        setvideoreg(pSiS, Index_VI6326_V_Buf_Start_Low,   (CARD8)PSV);
1032        setvideoreg(pSiS, Index_VI6326_V_Buf_Start_Middle,(CARD8)(PSV >> 8));
1033
1034	setvideoreg(pSiS, Index_VI6326_UV_Buf_Start_High,
1035					(CARD8)(((PSU >> 16) & 0x0F) | ((PSV >> 12) & 0xF0)) );
1036
1037	if(pSiS->oldChipset > OC_SIS6326) {
1038	   /* Set bit 20 of the addresses in Misc5 (530/620 only) */
1039	   setvideoreg(pSiS, Index_VI6326_Control_Misc5,
1040				(CARD8)(((PSU >> (20-1)) & 0x02) | ((PSV >> (20-2)) & 0x04)) );
1041	}
1042    }
1043
1044    /* set brightness and contrast */
1045    set_brightness(pSiS, pPriv->brightness);
1046    if(pSiS->oldChipset > OC_SIS6205C) {
1047       set_contrast_data(pSiS, (pOverlay->dstBox.x2 - pOverlay->dstBox.x1) *
1048                               (pOverlay->dstBox.y2 - pOverlay->dstBox.y1));
1049       set_contrast(pSiS, pPriv->contrast);
1050    }
1051
1052    /* enable/disable graphics display around overlay */
1053    set_disablegfx(pSiS, pPriv->disablegfx);
1054
1055    /* set format */
1056    set_format(pSiS, pOverlay);
1057}
1058
1059/* Overlay MUST NOT be switched off while beam is over it */
1060static void
1061close_overlay(SISPtr pSiS, SISPortPrivPtr pPriv)
1062{
1063  CARD32 watchdog;
1064
1065  watchdog = WATCHDOG_DELAY;
1066  while((!vblank_active_CRT1(pSiS)) && --watchdog);
1067  if(pSiS->oldChipset > OC_SIS6326) {
1068     /* what is this? */
1069     setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40);
1070  }
1071  /* disable overlay */
1072  setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x02);
1073}
1074
1075static void
1076SIS6326DisplayVideo(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
1077{
1078   SISPtr pSiS = SISPTR(pScrn);
1079
1080   short srcPitch = pPriv->srcPitch;
1081   short height = pPriv->height;
1082   short width = pPriv->width;
1083   SISOverlayRec overlay;
1084   int srcOffsetX=0, srcOffsetY=0;
1085   int sx, sy;
1086   int index = 0;
1087   int pitch;
1088
1089   memset(&overlay, 0, sizeof(overlay));
1090   overlay.pixelFormat = pPriv->id;
1091   overlay.pitch = srcPitch;
1092   overlay.keyOP = VI6326_ROP_DestKey;	/* DestKey mode */
1093
1094   overlay.dstBox.x1 = pPriv->drw_x - pScrn->frameX0;
1095   overlay.dstBox.x2 = pPriv->drw_x + pPriv->drw_w - pScrn->frameX0;
1096   overlay.dstBox.y1 = pPriv->drw_y - pScrn->frameY0;
1097   overlay.dstBox.y2 = pPriv->drw_y + pPriv->drw_h - pScrn->frameY0;
1098
1099   if((overlay.dstBox.x1 > overlay.dstBox.x2) ||
1100      (overlay.dstBox.y1 > overlay.dstBox.y2))
1101      return;
1102
1103   if((overlay.dstBox.x2 < 0) || (overlay.dstBox.y2 < 0))
1104      return;
1105
1106   if(overlay.dstBox.x1 < 0) {
1107      srcOffsetX = pPriv->src_w * (-overlay.dstBox.x1) / pPriv->drw_w;
1108      overlay.dstBox.x1 = 0;
1109   }
1110   if(overlay.dstBox.y1 < 0) {
1111      srcOffsetY = pPriv->src_h * (-overlay.dstBox.y1) / pPriv->drw_h;
1112      overlay.dstBox.y1 = 0;
1113   }
1114
1115   switch(pPriv->id){
1116     case PIXEL_FMT_YV12:
1117       sx = (pPriv->src_x + srcOffsetX) & ~7;
1118       sy = (pPriv->src_y + srcOffsetY) & ~1;
1119       pitch = (width + 3) & ~3;
1120       overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy * pitch;
1121       overlay.PSV = overlay.PSY + pitch * height;
1122       overlay.PSU = overlay.PSV + ((((width >> 1) + 3) & ~3) * (height >> 1));
1123       overlay.PSY >>= 2;
1124       overlay.PSV >>= 2;
1125       overlay.PSU >>= 2;
1126       break;
1127     case PIXEL_FMT_I420:
1128       sx = (pPriv->src_x + srcOffsetX) & ~7;
1129       sy = (pPriv->src_y + srcOffsetY) & ~1;
1130       pitch = (width + 3) & ~3;
1131       overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy * pitch;
1132       overlay.PSU = overlay.PSY + pitch * height;
1133       overlay.PSV = overlay.PSU + ((((width >> 1) + 3) & ~3) * (height >> 1));
1134       overlay.PSY >>= 2;
1135       overlay.PSV >>= 2;
1136       overlay.PSU >>= 2;
1137       break;
1138     case PIXEL_FMT_YUY2:
1139     case PIXEL_FMT_UYVY:
1140     case PIXEL_FMT_RGB6:
1141     case PIXEL_FMT_RGB5:
1142     default:
1143       sx = (pPriv->src_x + srcOffsetX) & ~1;
1144       sy = (pPriv->src_y + srcOffsetY);
1145       overlay.PSY = (pPriv->bufAddr[pPriv->currentBuf] + sx*2 + sy*srcPitch);
1146       overlay.PSY >>= 2;
1147       break;
1148   }
1149
1150   /* FIXME: Is this correct? (Is it required to set the end address?
1151    *        Datasheet is not clear) - (reg does not exist on 530/620)
1152    */
1153   overlay.YUVEnd = (pPriv->bufAddr[pPriv->currentBuf] + pPriv->totalSize) >> 14;
1154
1155   /* FIXME: is it possible that srcW < 0 */
1156   overlay.srcW = pPriv->src_w - (sx - pPriv->src_x);
1157   overlay.srcH = pPriv->src_h - (sy - pPriv->src_y);
1158
1159   if( (pPriv->oldx1 != overlay.dstBox.x1) ||
1160       (pPriv->oldx2 != overlay.dstBox.x2) ||
1161       (pPriv->oldy1 != overlay.dstBox.y1) ||
1162       (pPriv->oldy2 != overlay.dstBox.y2) ) {
1163      pPriv->mustwait = 1;
1164      pPriv->oldx1 = overlay.dstBox.x1; pPriv->oldx2 = overlay.dstBox.x2;
1165      pPriv->oldy1 = overlay.dstBox.y1; pPriv->oldy2 = overlay.dstBox.y2;
1166   }
1167
1168   /* calculate line buffer length */
1169   calc_line_buf_size(&overlay);
1170
1171   overlay.VBlankActiveFunc = vblank_active_CRT1;
1172/* overlay.GetScanLineFunc = get_scanline_CRT1;  */
1173
1174   /* calculate scale factor */
1175   calc_scale_factor(pSiS, &overlay, pScrn, pPriv);
1176
1177   /* set (not only determine) if line buffer is to be merged */
1178   if(pSiS->oldChipset > OC_SIS5597) {
1179      int temp = 384;
1180      if(pSiS->oldChipset <= OC_SIS6326) temp = 352;
1181      merge_line_buf(pSiS, pPriv, (overlay.srcW > temp));
1182   }
1183
1184   /* set overlay */
1185   set_overlay(pSiS, &overlay, pPriv, index);
1186
1187   /* enable overlay */
1188   if(pSiS->oldChipset > OC_SIS6326) {
1189      setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40);
1190   }
1191   setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x02, 0x02);
1192
1193   pPriv->mustwait = 0;
1194}
1195
1196static void
1197SIS6326StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
1198{
1199  SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
1200  SISPtr pSiS = SISPTR(pScrn);
1201
1202  if(pPriv->grabbedByV4L) return;
1203
1204  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1205
1206  if(shutdown) {
1207     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
1208        close_overlay(pSiS, pPriv);
1209        pPriv->mustwait = 1;
1210     }
1211     SISFreeFBMemory(pScrn, &pPriv->handle);
1212     pPriv->videoStatus = 0;
1213     pSiS->VideoTimerCallback = NULL;
1214  } else {
1215     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
1216        pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
1217        pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
1218        pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1219     }
1220  }
1221}
1222
1223static int
1224SIS6326PutImage(
1225  ScrnInfoPtr pScrn,
1226  short src_x, short src_y,
1227  short drw_x, short drw_y,
1228  short src_w, short src_h,
1229  short drw_w, short drw_h,
1230  int id, unsigned char* buf,
1231  short width, short height,
1232  Bool sync,
1233  RegionPtr clipBoxes, pointer data,
1234  DrawablePtr pDraw
1235){
1236   SISPtr pSiS = SISPTR(pScrn);
1237   SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
1238   int totalSize=0;
1239   CARD32 *src, *dest;
1240   unsigned long i;
1241
1242   if(pPriv->grabbedByV4L) return Success;
1243
1244   pPriv->drw_x = drw_x;
1245   pPriv->drw_y = drw_y;
1246   pPriv->drw_w = drw_w;
1247   pPriv->drw_h = drw_h;
1248   pPriv->src_x = src_x;
1249   pPriv->src_y = src_y;
1250   pPriv->src_w = src_w;
1251   pPriv->src_h = src_h;
1252   pPriv->id = id;
1253   pPriv->height = height;
1254   pPriv->width = width;
1255
1256   /* Pixel formats:
1257      1. YU12:  3 planes:       H    V
1258               Y sample period  1    1   (8 bit per pixel)
1259	       V sample period  2    2	 (8 bit per pixel, subsampled)
1260	       U sample period  2    2   (8 bit per pixel, subsampled)
1261
1262	 Y plane is fully sampled (width*height), U and V planes
1263	 are sampled in 2x2 blocks, hence a group of 4 pixels requires
1264	 4 + 1 + 1 = 6 bytes. The data is planar, ie in single planes
1265	 for Y, U and V.
1266      2. UYVY: 3 planes:        H    V
1267               Y sample period  1    1   (8 bit per pixel)
1268	       V sample period  2    1	 (8 bit per pixel, subsampled)
1269	       U sample period  2    1   (8 bit per pixel, subsampled)
1270	 Y plane is fully sampled (width*height), U and V planes
1271	 are sampled in 2x1 blocks, hence a group of 4 pixels requires
1272	 4 + 2 + 2 = 8 bytes. The data is bit packed, there are no separate
1273	 Y, U or V planes.
1274	 Bit order:  U0 Y0 V0 Y1  U2 Y2 V2 Y3 ...
1275      3. I420: Like YU12, but planes U and V are in reverse order.
1276      4. YUY2: Like UYVY, but order is
1277                     Y0 U0 Y1 V0  Y2 U2 Y3 V2 ...
1278   */
1279
1280   switch(id){
1281     case PIXEL_FMT_YV12:
1282     case PIXEL_FMT_I420:
1283       pPriv->srcPitch = (width + 7) & ~7;
1284       /* Size = width * height * 3 / 2 */
1285       totalSize = (pPriv->srcPitch * height * 3) >> 1;
1286       break;
1287     case PIXEL_FMT_YUY2:
1288     case PIXEL_FMT_UYVY:
1289     case PIXEL_FMT_RGB5:
1290     case PIXEL_FMT_RGB6:
1291     default:
1292       pPriv->srcPitch = ((width << 1) + 3) & ~3;
1293       /* Size = width * 2 * height */
1294       totalSize = pPriv->srcPitch * height;
1295   }
1296
1297   /* make it a multiple of 16 to simplify to copy loop */
1298   totalSize += 15;
1299   totalSize &= ~15; /* in bytes */
1300
1301   pPriv->totalSize = totalSize;
1302
1303   /* allocate memory (we do doublebuffering) - size is in bytes */
1304   if(!(pPriv->bufAddr[0] = SISAllocateFBMemory(pScrn, &pPriv->handle, totalSize << 1)))
1305      return BadAlloc;
1306
1307   pPriv->bufAddr[1] = pPriv->bufAddr[0] + totalSize;
1308
1309   /* copy data */
1310   if((pSiS->XvUseMemcpy) || (totalSize < 16)) {
1311      SiSMemCopyToVideoRam(pSiS, pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf], buf, totalSize);
1312   } else {
1313      dest = (CARD32 *)(pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf]);
1314      src  = (CARD32 *)buf;
1315      for(i = 0; i < (totalSize/16); i++) {
1316	 *dest++ = *src++;
1317	 *dest++ = *src++;
1318	 *dest++ = *src++;
1319	 *dest++ = *src++;
1320      }
1321   }
1322
1323   SIS6326DisplayVideo(pScrn, pPriv);
1324
1325   /* update cliplist */
1326   if(  pPriv->autopaintColorKey &&
1327        (pPriv->grabbedByV4L ||
1328#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
1329	 !RegionsEqual(&pPriv->clip, clipBoxes)) ) {
1330#else
1331         !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) ) {
1332#endif
1333      /* We always paint colorkey for V4L */
1334      if(!pPriv->grabbedByV4L)
1335     	 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
1336      /* draw these */
1337#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
1338      (*pSiS->AccelInfoPtr->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0,
1339                    REGION_NUM_RECTS(clipBoxes),
1340                    REGION_RECTS(clipBoxes));
1341#else
1342      xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
1343#endif
1344   }
1345
1346   pPriv->currentBuf ^= 1;
1347
1348   pPriv->videoStatus = CLIENT_VIDEO_ON;
1349
1350   pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1351
1352   return Success;
1353}
1354
1355static int
1356SIS6326QueryImageAttributes(
1357  ScrnInfoPtr pScrn,
1358  int id,
1359  unsigned short *w, unsigned short *h,
1360  int *pitches, int *offsets
1361){
1362    SISPtr pSiS = SISPTR(pScrn);
1363    int pitchY, pitchUV;
1364    int size, sizeY, sizeUV;
1365
1366    if(*w < IMAGE_MIN_WIDTH) *w = IMAGE_MIN_WIDTH;
1367    if(*h < IMAGE_MIN_HEIGHT) *h = IMAGE_MIN_HEIGHT;
1368
1369    if(pSiS->oldChipset < OC_SIS6326) {
1370       if(*w > IMAGE_MAX_WIDTH_5597) *w = IMAGE_MAX_WIDTH_5597;
1371       if(*h > IMAGE_MAX_HEIGHT_5597) *h = IMAGE_MAX_HEIGHT_5597;
1372    } else {
1373       if(*w > IMAGE_MAX_WIDTH) *w = IMAGE_MAX_WIDTH;
1374       if(*h > IMAGE_MAX_HEIGHT) *h = IMAGE_MAX_HEIGHT;
1375    }
1376
1377    switch(id) {
1378    case PIXEL_FMT_YV12:
1379    case PIXEL_FMT_I420:
1380	*w = (*w + 7) & ~7;
1381	*h = (*h + 1) & ~1;
1382	pitchY = *w;
1383	pitchUV = *w >> 1;
1384	if(pitches) {
1385	    pitches[0] = pitchY;
1386	    pitches[1] = pitches[2] = pitchUV;
1387        }
1388	sizeY = pitchY * (*h);
1389	sizeUV = pitchUV * ((*h) >> 1);
1390	if(offsets) {
1391	  offsets[0] = 0;
1392	  offsets[1] = sizeY;
1393	  offsets[2] = sizeY + sizeUV;
1394	}
1395	size = sizeY + (sizeUV << 1);
1396	break;
1397    case PIXEL_FMT_YUY2:
1398    case PIXEL_FMT_UYVY:
1399    case PIXEL_FMT_RGB5:
1400    case PIXEL_FMT_RGB6:
1401    default:
1402	*w = (*w + 1) & ~1;
1403	pitchY = *w << 1;
1404	if(pitches) pitches[0] = pitchY;
1405	if(offsets) offsets[0] = 0;
1406	size = pitchY * (*h);
1407	break;
1408    }
1409
1410    return size;
1411}
1412
1413static void
1414SIS6326VideoTimerCallback(ScrnInfoPtr pScrn, Time now)
1415{
1416    SISPtr         pSiS = SISPTR(pScrn);
1417    SISPortPrivPtr pPriv = NULL;
1418    unsigned char  sridx, cridx;
1419
1420    pSiS->VideoTimerCallback = NULL;
1421
1422    if(!pScrn->vtSema) return;
1423
1424    if(pSiS->adaptor) {
1425	pPriv = GET_PORT_PRIVATE(pScrn);
1426	if(!pPriv->videoStatus) pPriv = NULL;
1427    }
1428
1429    if(pPriv) {
1430       if(pPriv->videoStatus & TIMER_MASK) {
1431	  if(pPriv->videoStatus & OFF_TIMER) {
1432	     if(pPriv->offTime < now) {
1433		/* Turn off the overlay */
1434		sridx = inSISREG(SISSR); cridx = inSISREG(SISCR);
1435		close_overlay(pSiS, pPriv);
1436		outSISREG(SISSR, sridx); outSISREG(SISCR, cridx);
1437		pPriv->mustwait = 1;
1438		pPriv->videoStatus = FREE_TIMER;
1439		pPriv->freeTime = now + FREE_DELAY;
1440		pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1441	     }
1442          } else if(pPriv->videoStatus & FREE_TIMER) {
1443             if(pPriv->freeTime < now) {
1444		SISFreeFBMemory(pScrn, &pPriv->handle);
1445		pPriv->mustwait = 1;
1446		pPriv->videoStatus = 0;
1447	     }
1448	  } else
1449	     pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1450       }
1451    }
1452}
1453
1454/* Offscreen surface stuff for v4l */
1455
1456static int
1457SIS6326AllocSurface (
1458    ScrnInfoPtr pScrn,
1459    int id,
1460    unsigned short w,
1461    unsigned short h,
1462    XF86SurfacePtr surface
1463)
1464{
1465    SISPtr pSiS = SISPTR(pScrn);
1466    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
1467    int size;
1468
1469    if((w < IMAGE_MIN_WIDTH) || (h < IMAGE_MIN_HEIGHT))
1470       return BadValue;
1471
1472    if(pSiS->oldChipset < OC_SIS6326) {
1473       if((w > IMAGE_MAX_WIDTH_5597) || (h > IMAGE_MAX_HEIGHT_5597))
1474	  return BadValue;
1475    } else {
1476       if((w > IMAGE_MAX_WIDTH) || (h > IMAGE_MAX_HEIGHT))
1477	  return BadValue;
1478    }
1479
1480    if(pPriv->grabbedByV4L)
1481       return BadAlloc;
1482
1483    w = (w + 1) & ~1;
1484    pPriv->pitch = ((w << 1) + 63) & ~63; /* Only packed pixel modes supported */
1485    size = h * pPriv->pitch;
1486    if(!(pPriv->offset = SISAllocateFBMemory(pScrn, &pPriv->handle, size)))
1487       return BadAlloc;
1488
1489    pPriv->totalSize = size;
1490
1491    surface->width   = w;
1492    surface->height  = h;
1493    surface->pScrn   = pScrn;
1494    surface->id      = id;
1495    surface->pitches = &pPriv->pitch;
1496    surface->offsets = &pPriv->offset;
1497    surface->devPrivate.ptr = (pointer)pPriv;
1498
1499    close_overlay(pSiS, pPriv);
1500    pPriv->videoStatus = 0;
1501    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1502    pSiS->VideoTimerCallback = NULL;
1503    pPriv->grabbedByV4L = TRUE;
1504    return Success;
1505}
1506
1507static int
1508SIS6326StopSurface (XF86SurfacePtr surface)
1509{
1510    SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
1511    SISPtr pSiS = SISPTR(surface->pScrn);
1512
1513    if(pPriv->grabbedByV4L && pPriv->videoStatus) {
1514       close_overlay(pSiS, pPriv);
1515       pPriv->mustwait = 1;
1516       pPriv->videoStatus = 0;
1517    }
1518    return Success;
1519}
1520
1521static int
1522SIS6326FreeSurface (XF86SurfacePtr surface)
1523{
1524    SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
1525
1526    if(pPriv->grabbedByV4L) {
1527       SIS6326StopSurface(surface);
1528       SISFreeFBMemory(surface->pScrn, &pPriv->handle);
1529       pPriv->grabbedByV4L = FALSE;
1530    }
1531    return Success;
1532}
1533
1534static int
1535SIS6326GetSurfaceAttribute (
1536    ScrnInfoPtr pScrn,
1537    Atom attribute,
1538    INT32 *value
1539)
1540{
1541    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
1542
1543    return SIS6326GetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
1544}
1545
1546static int
1547SIS6326SetSurfaceAttribute(
1548    ScrnInfoPtr pScrn,
1549    Atom attribute,
1550    INT32 value
1551)
1552{
1553    SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);;
1554
1555    return SIS6326SetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
1556}
1557
1558static int
1559SIS6326DisplaySurface (
1560    XF86SurfacePtr surface,
1561    short src_x, short src_y,
1562    short drw_x, short drw_y,
1563    short src_w, short src_h,
1564    short drw_w, short drw_h,
1565    RegionPtr clipBoxes
1566)
1567{
1568   ScrnInfoPtr pScrn = surface->pScrn;
1569   SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
1570
1571   if(!pPriv->grabbedByV4L)
1572      return Success;
1573
1574   pPriv->drw_x = drw_x;
1575   pPriv->drw_y = drw_y;
1576   pPriv->drw_w = drw_w;
1577   pPriv->drw_h = drw_h;
1578   pPriv->src_x = src_x;
1579   pPriv->src_y = src_y;
1580   pPriv->src_w = src_w;
1581   pPriv->src_h = src_h;
1582   pPriv->id = surface->id;
1583   pPriv->height = surface->height;
1584   pPriv->bufAddr[0] = surface->offsets[0];
1585   pPriv->currentBuf = 0;
1586   pPriv->srcPitch = surface->pitches[0];
1587
1588   SIS6326DisplayVideo(pScrn, pPriv);
1589
1590   if(pPriv->autopaintColorKey) {
1591#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0)
1592      (*XAAPTR(pScrn)->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0,
1593                    REGION_NUM_RECTS(clipBoxes),
1594                    REGION_RECTS(clipBoxes));
1595#else
1596      xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
1597#endif
1598   }
1599
1600   pPriv->videoStatus = CLIENT_VIDEO_ON;
1601
1602   return Success;
1603}
1604
1605XF86OffscreenImageRec SIS6326OffscreenImages[2] =
1606{
1607 {
1608   &SIS6326Images[0],  	/* YUV2 */
1609   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1610   SIS6326AllocSurface,
1611   SIS6326FreeSurface,
1612   SIS6326DisplaySurface,
1613   SIS6326StopSurface,
1614   SIS6326GetSurfaceAttribute,
1615   SIS6326SetSurfaceAttribute,
1616   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
1617   NUM_ATTRIBUTES,
1618   &SIS6326Attributes[0]  /* Support all attributes */
1619  },
1620  {
1621   &SIS6326Images[1],	/* UYVY */
1622   VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1623   SIS6326AllocSurface,
1624   SIS6326FreeSurface,
1625   SIS6326DisplaySurface,
1626   SIS6326StopSurface,
1627   SIS6326GetSurfaceAttribute,
1628   SIS6326SetSurfaceAttribute,
1629   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
1630   NUM_ATTRIBUTES,
1631   &SIS6326Attributes[0]  /* Support all attributes */
1632  },
1633};
1634
1635static void
1636SIS6326InitOffscreenImages(ScreenPtr pScrn)
1637{
1638    xf86XVRegisterOffscreenImages(pScrn, SIS6326OffscreenImages, 2);
1639}
1640
1641
1642
1643
1644