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