summaryrefslogtreecommitdiff
path: root/driver/xf86-video-sisusb/src/sisusb_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/xf86-video-sisusb/src/sisusb_video.c')
-rw-r--r--driver/xf86-video-sisusb/src/sisusb_video.c2054
1 files changed, 2054 insertions, 0 deletions
diff --git a/driver/xf86-video-sisusb/src/sisusb_video.c b/driver/xf86-video-sisusb/src/sisusb_video.c
new file mode 100644
index 000000000..e0d05a530
--- /dev/null
+++ b/driver/xf86-video-sisusb/src/sisusb_video.c
@@ -0,0 +1,2054 @@
+/* $XFree86$ */
+/* $XdotOrg: driver/xf86-video-sisusb/src/sisusb_video.c,v 1.9 2006/04/07 23:15:17 aplattner Exp $ */
+/*
+ * Xv driver for SiS 315 USB
+ *
+ * Note: The version of the 315 used in my dongle does not seem
+ * to support Xv at all. The overlay just won't show up. However,
+ * Xv is left enabled since I don't know if other versions of the
+ * dongle support the overlay.
+ *
+ * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sisusb.h"
+
+#ifdef SIS_GLOBAL_ENABLEXV
+
+#include "xf86fbman.h"
+#include "regionstr.h"
+
+#include "xf86xv.h"
+#include <X11/extensions/Xv.h>
+#include "dixstruct.h"
+#include "fourcc.h"
+
+#include "sisusb_regs.h"
+
+#include "sisusb_video.h"
+
+/****************************************************************************
+ * Raw register access : These routines directly interact with the sis's
+ * control aperature. Must not be called until after
+ * the board's pci memory has been mapped.
+ ****************************************************************************/
+
+#ifdef SIS_ENABLEXV
+#if 0
+static CARD32 _sisread(SISUSBPtr pSiSUSB, CARD32 reg)
+{
+ return *(pSiSUSB->IOBase + reg);
+}
+
+static void _siswrite(SISUSBPtr pSiSUSB, CARD32 reg, CARD32 data)
+{
+ *(pSiSUSB->IOBase + reg) = data;
+}
+#endif
+
+static CARD8 getsrreg(SISUSBPtr pSiSUSB, CARD8 reg)
+{
+ CARD8 ret;
+ inSISIDXREG(pSiSUSB, SISSR, reg, ret);
+ return(ret);
+}
+
+static CARD8 getvideoreg(SISUSBPtr pSiSUSB, CARD8 reg)
+{
+ CARD8 ret;
+ inSISIDXREG(pSiSUSB, SISVID, reg, ret);
+ return(ret);
+}
+
+static __inline void setvideoreg(SISUSBPtr pSiSUSB, CARD8 reg, CARD8 data)
+{
+ outSISIDXREG(pSiSUSB, SISVID, reg, data);
+}
+
+static __inline void setvideoregmask(SISUSBPtr pSiSUSB, CARD8 reg, CARD8 data, CARD8 mask)
+{
+ setSISIDXREGmask(pSiSUSB, SISVID, reg, data, mask);
+}
+
+static void setsrregmask(SISUSBPtr pSiSUSB, CARD8 reg, CARD8 data, CARD8 mask)
+{
+ setSISIDXREGmask(pSiSUSB, SISSR, reg, data, mask);
+}
+
+/* VBlank */
+static CARD8 vblank_active_CRT1(SISUSBPtr pSiSUSB, SISUSBPortPrivPtr pPriv)
+{
+ return(inSISREG(pSiSUSB, SISINPSTAT) & 0x08); /* Verified */
+}
+
+/* Scanline - unused */
+#if 0
+static CARD16 get_scanline_CRT1(SISUSBPtr pSiSUSB)
+{
+ CARD32 line;
+
+ _siswrite(pSiSUSB, REG_PRIM_CRT_COUNTER, 0x00000001);
+ line = _sisread(pSiSUSB, REG_PRIM_CRT_COUNTER);
+
+ return((CARD16)((line >> 16) & 0x07FF));
+}
+#endif
+#endif /* SIS_ENABLEXV */
+
+/* Helper: Count attributes */
+static int
+SiSUSBCountAttributes(XF86AttributeRec *attrs)
+{
+ int num = 0;
+
+ while(attrs[num].name) num++;
+
+ return num;
+}
+
+#ifdef SIS_ENABLEXV
+static void
+SiSUSBComputeXvGamma(SISUSBPtr pSiSUSB)
+{
+ int num = 255, i;
+ double red = 1.0 / (double)((double)pSiSUSB->XvGammaRed / 1000);
+ double green = 1.0 / (double)((double)pSiSUSB->XvGammaGreen / 1000);
+ double blue = 1.0 / (double)((double)pSiSUSB->XvGammaBlue / 1000);
+
+ for(i = 0; i <= num; i++) {
+ pSiSUSB->XvGammaRampRed[i] =
+ (red == 1.0) ? i : (CARD8)(pow((double)i / (double)num, red) * (double)num + 0.5);
+
+ pSiSUSB->XvGammaRampGreen[i] =
+ (green == 1.0) ? i : (CARD8)(pow((double)i / (double)num, green) * (double)num + 0.5);
+
+ pSiSUSB->XvGammaRampBlue[i] =
+ (blue == 1.0) ? i : (CARD8)(pow((double)i / (double)num, blue) * (double)num + 0.5);
+ }
+}
+
+static void
+SiSUSBSetXvGamma(SISUSBPtr pSiSUSB)
+{
+ int i;
+ UChar backup = getsrreg(pSiSUSB, 0x1f);
+ setsrregmask(pSiSUSB, 0x1f, 0x08, 0x18);
+ for(i = 0; i <= 255; i++) {
+ SIS_MMIO_OUT32(pSiSUSB, pSiSUSB->IOBase, 0x8570,
+ (i << 24) |
+ (pSiSUSB->XvGammaRampBlue[i] << 16) |
+ (pSiSUSB->XvGammaRampGreen[i] << 8) |
+ pSiSUSB->XvGammaRampRed[i]);
+ }
+ setsrregmask(pSiSUSB, 0x1f, backup, 0xff);
+}
+
+static void
+SiSUSBUpdateXvGamma(SISUSBPtr pSiSUSB, SISUSBPortPrivPtr pPriv)
+{
+ UChar sr7 = getsrreg(pSiSUSB, 0x07);
+
+ if(!pSiSUSB->XvGamma) return;
+ if(!(pSiSUSB->MiscFlags & MISC_CRT1OVERLAYGAMMA)) return;
+
+ if(!(sr7 & 0x04)) return;
+
+ SiSUSBComputeXvGamma(pSiSUSB);
+ SiSUSBSetXvGamma(pSiSUSB);
+}
+
+static void
+SISUSBResetXvGamma(ScrnInfoPtr pScrn)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ SISUSBPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
+
+ SiSUSBUpdateXvGamma(pSiSUSB, pPriv);
+}
+#endif
+
+void SISUSBInitVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
+ XF86VideoAdaptorPtr newAdaptor = NULL;
+ int num_adaptors;
+
+ newAdaptor = SISUSBSetupImageVideo(pScreen);
+
+#ifdef SIS_ENABLEXV
+ if(newAdaptor) {
+ SISUSBInitOffscreenImages(pScreen);
+ }
+#endif
+
+ num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
+
+ if(newAdaptor) {
+ int size = num_adaptors;
+
+ if(newAdaptor) size++;
+
+ newAdaptors = xalloc(size * sizeof(XF86VideoAdaptorPtr*));
+ if(newAdaptors) {
+ if(num_adaptors) {
+ memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
+ }
+ if(newAdaptor) {
+ newAdaptors[num_adaptors] = newAdaptor;
+ num_adaptors++;
+ }
+ adaptors = newAdaptors;
+ }
+ }
+
+ if(num_adaptors) {
+ xf86XVScreenInit(pScreen, adaptors, num_adaptors);
+ }
+
+ if(newAdaptors) {
+ xfree(newAdaptors);
+ }
+}
+
+void
+SISUSBSetPortDefaults(ScrnInfoPtr pScrn, SISUSBPortPrivPtr pPriv)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+
+ pPriv->colorKey = pSiSUSB->colorKey = 0x000101fe;
+ pPriv->brightness = pSiSUSB->XvDefBri;
+ pPriv->contrast = pSiSUSB->XvDefCon;
+ pPriv->hue = pSiSUSB->XvDefHue;
+ pPriv->saturation = pSiSUSB->XvDefSat;
+ pPriv->autopaintColorKey = TRUE;
+ pPriv->disablegfx = pSiSUSB->XvDefDisableGfx;
+ pPriv->disablegfxlr= pSiSUSB->XvDefDisableGfxLR;
+ pSiSUSB->disablecolorkeycurrent = pSiSUSB->XvDisableColorKey;
+ pPriv->usechromakey = pSiSUSB->XvUseChromaKey;
+ pPriv->insidechromakey = pSiSUSB->XvInsideChromaKey;
+ pPriv->yuvchromakey = pSiSUSB->XvYUVChromaKey;
+ pPriv->chromamin = pSiSUSB->XvChromaMin;
+ pPriv->chromamax = pSiSUSB->XvChromaMax;
+ pPriv->crtnum = 0;
+
+ pSiSUSB->XvGammaRed = pSiSUSB->XvGammaRedDef;
+ pSiSUSB->XvGammaGreen = pSiSUSB->XvGammaGreenDef;
+ pSiSUSB->XvGammaBlue = pSiSUSB->XvGammaBlueDef;
+#ifdef SIS_ENABLEXV
+ SiSUSBUpdateXvGamma(pSiSUSB, pPriv);
+#endif
+}
+
+#ifdef SIS_ENABLEXV
+static void
+SISUSBResetVideo(ScrnInfoPtr pScrn)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ SISUSBPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
+
+ /* Unlock registers */
+#ifdef UNLOCK_ALWAYS
+ sisusbSaveUnlockExtRegisterLock(pSiSUSB, NULL, NULL);
+#endif
+ if(getvideoreg(pSiSUSB, Index_VI_Passwd) != 0xa1) {
+ setvideoreg(pSiSUSB, Index_VI_Passwd, 0x86);
+ if(getvideoreg(pSiSUSB, Index_VI_Passwd) != 0xa1)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Xv: Video password could not unlock registers\n");
+ }
+
+ /* Initialize first overlay (CRT1) ------------------------------- */
+
+ /* This bit has obviously a different meaning on 315 series (linebuffer-related) */
+
+ /* Select overlay 2, clear all linebuffer related bits */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc2, 0x00, 0xb1);
+
+ /* Disable overlay */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc0, 0x00, 0x02);
+
+ /* Disable bob de-interlacer and some strange bit */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, 0x00, 0x82);
+
+ /* Reset scale control and contrast */
+ /* (Enable DDA (interpolation)) */
+ setvideoregmask(pSiSUSB, Index_VI_Scale_Control, 0x60, 0x60);
+ setvideoregmask(pSiSUSB, Index_VI_Contrast_Enh_Ctrl, 0x04, 0x1F);
+
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_Buf_Preset_Low, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_Buf_Preset_Middle, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_UV_Buf_Preset_Low, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_UV_Buf_Preset_Middle, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_UV_Buf_Preset_High, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_Play_Threshold_Low, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_Play_Threshold_High, 0x00);
+
+ /* Reset top window position for scanline check */
+ setvideoreg(pSiSUSB, Index_VI_Win_Ver_Disp_Start_Low, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_Win_Ver_Over, 0x00);
+
+ /* set default properties for overlay 1 (CRT1) -------------------------- */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc2, 0x00, 0x01);
+ setvideoregmask(pSiSUSB, Index_VI_Contrast_Enh_Ctrl, 0x04, 0x07);
+ setvideoreg(pSiSUSB, Index_VI_Brightness, 0x20);
+ setvideoreg(pSiSUSB, Index_VI_Hue, 0x00);
+ setvideoreg(pSiSUSB, Index_VI_Saturation, 0x00);
+
+ /* Reset Xv gamma correction */
+ SiSUSBUpdateXvGamma(pSiSUSB, pPriv);
+}
+#endif
+
+/* Set display mode (single CRT1/CRT2, mirror).
+ * MIRROR mode is only available on chipsets with two overlays.
+ * On the other chipsets, if only CRT1 or only CRT2 are used,
+ * the correct display CRT is chosen automatically. If both
+ * CRT1 and CRT2 are connected, the user can choose between CRT1 and
+ * CRT2 by using the option XvOnCRT2.
+ */
+#ifdef SIS_ENABLEXV
+static void
+set_dispmode(ScrnInfoPtr pScrn, SISUSBPortPrivPtr pPriv)
+{
+ pPriv->dualHeadMode = pPriv->bridgeIsSlave = FALSE;
+ pPriv->displayMode = DISPMODE_SINGLE1; /* CRT1 only */
+}
+
+static void
+set_disptype_regs(ScrnInfoPtr pScrn, SISUSBPortPrivPtr pPriv)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+
+#ifdef UNLOCK_ALWAYS
+ sisusbSaveUnlockExtRegisterLock(pSiSUSB, NULL, NULL);
+#endif
+
+ setsrregmask(pSiSUSB, 0x06, 0x00, 0xc0); /* only overlay -> CRT1 */
+ setsrregmask(pSiSUSB, 0x32, 0x00, 0xc0);
+}
+#endif
+
+static void
+set_allowswitchcrt(SISUSBPtr pSiSUSB, SISUSBPortPrivPtr pPriv)
+{
+ pPriv->AllowSwitchCRT = FALSE;
+}
+
+static void
+set_maxencoding(SISUSBPtr pSiSUSB, SISUSBPortPrivPtr pPriv)
+{
+ DummyEncoding.width = IMAGE_MAX_WIDTH_315;
+ DummyEncoding.height = IMAGE_MAX_HEIGHT_315;
+}
+
+static XF86VideoAdaptorPtr
+SISUSBSetupImageVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ XF86VideoAdaptorPtr adapt;
+ SISUSBPortPrivPtr pPriv;
+
+ if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
+ sizeof(SISUSBPortPrivRec) +
+ sizeof(DevUnion))))
+ return NULL;
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+ adapt->name = "SIS 300/315/330 series Video Overlay";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = &DummyEncoding;
+
+ adapt->nFormats = NUM_FORMATS;
+ adapt->pFormats = SISUSBFormats;
+ adapt->nPorts = 1;
+ adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
+
+ pPriv = (SISUSBPortPrivPtr)(&adapt->pPortPrivates[1]);
+
+ /* Setup chipset type helpers */
+
+ pPriv->hasTwoOverlays = FALSE;
+ pPriv->AllowSwitchCRT = FALSE;
+
+ set_allowswitchcrt(pSiSUSB, pPriv);
+
+ adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
+
+ adapt->nImages = NUM_IMAGES_315;
+ adapt->pAttributes = SISUSBAttributes_315;
+ adapt->nAttributes = SiSUSBCountAttributes(&SISUSBAttributes_315[0]);
+ if(pPriv->hasTwoOverlays) adapt->nAttributes--;
+
+ adapt->pImages = SISUSBImages;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+ adapt->GetVideo = NULL;
+ adapt->GetStill = NULL;
+ adapt->StopVideo = SISUSBStopVideo;
+#ifdef SIS_ENABLEXV
+ adapt->PutImage = SISUSBPutImage;
+#else
+ adapt->PutImage = NULL;
+#endif
+ adapt->SetPortAttribute = SISUSBSetPortAttribute;
+ adapt->GetPortAttribute = SISUSBGetPortAttribute;
+ adapt->QueryBestSize = SISUSBQueryBestSize;
+ adapt->QueryImageAttributes = SISUSBQueryImageAttributes;
+
+ pPriv->videoStatus = 0;
+ pPriv->currentBuf = 0;
+ pPriv->linear = NULL;
+ pPriv->grabbedByV4L= FALSE;
+ pPriv->NoOverlay = FALSE;
+ pPriv->PrevOverlay = FALSE;
+ pPriv->is340 = FALSE;
+
+ /* gotta uninit this someplace */
+#if defined(REGION_NULL)
+ REGION_NULL(pScreen, &pPriv->clip);
+#else
+ REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
+#endif
+
+ pSiSUSB->adaptor = adapt;
+
+ pSiSUSB->xvBrightness = MAKE_ATOM(sisxvbrightness);
+ pSiSUSB->xvContrast = MAKE_ATOM(sisxvcontrast);
+ pSiSUSB->xvColorKey = MAKE_ATOM(sisxvcolorkey);
+ pSiSUSB->xvSaturation = MAKE_ATOM(sisxvsaturation);
+ pSiSUSB->xvHue = MAKE_ATOM(sisxvhue);
+ pSiSUSB->xvSwitchCRT = MAKE_ATOM(sisxvswitchcrt);
+ pSiSUSB->xvAutopaintColorKey = MAKE_ATOM(sisxvautopaintcolorkey);
+ pSiSUSB->xvSetDefaults = MAKE_ATOM(sisxvsetdefaults);
+ pSiSUSB->xvDisableGfx = MAKE_ATOM(sisxvdisablegfx);
+ pSiSUSB->xvDisableGfxLR = MAKE_ATOM(sisxvdisablegfxlr);
+ pSiSUSB->xvTVXPosition = MAKE_ATOM(sisxvtvxposition);
+ pSiSUSB->xvTVYPosition = MAKE_ATOM(sisxvtvyposition);
+ pSiSUSB->xvGammaRed = MAKE_ATOM(sisxvgammared);
+ pSiSUSB->xvGammaGreen = MAKE_ATOM(sisxvgammagreen);
+ pSiSUSB->xvGammaBlue = MAKE_ATOM(sisxvgammablue);
+ pSiSUSB->xvDisableColorkey = MAKE_ATOM(sisxvdisablecolorkey);
+ pSiSUSB->xvUseChromakey = MAKE_ATOM(sisxvusechromakey);
+ pSiSUSB->xvInsideChromakey = MAKE_ATOM(sisxvinsidechromakey);
+ pSiSUSB->xvYUVChromakey = MAKE_ATOM(sisxvyuvchromakey);
+ pSiSUSB->xvChromaMin = MAKE_ATOM(sisxvchromamin);
+ pSiSUSB->xvChromaMax = MAKE_ATOM(sisxvchromamax);
+#ifdef XV_SD_DEPRECATED
+ pSiSUSB->xv_QVF = MAKE_ATOM(sisxvqueryvbflags);
+ pSiSUSB->xv_GDV = MAKE_ATOM(sisxvsdgetdriverversion);
+ pSiSUSB->xv_GHI = MAKE_ATOM(sisxvsdgethardwareinfo);
+ pSiSUSB->xv_GBI = MAKE_ATOM(sisxvsdgetbusid);
+ pSiSUSB->xv_QVV = MAKE_ATOM(sisxvsdqueryvbflagsversion);
+ pSiSUSB->xv_GSF = MAKE_ATOM(sisxvsdgetsdflags);
+ pSiSUSB->xv_GSF2 = MAKE_ATOM(sisxvsdgetsdflags2);
+ pSiSUSB->xv_USD = MAKE_ATOM(sisxvsdunlocksisdirect);
+ pSiSUSB->xv_SVF = MAKE_ATOM(sisxvsdsetvbflags);
+ pSiSUSB->xv_QDD = MAKE_ATOM(sisxvsdquerydetecteddevices);
+ pSiSUSB->xv_CT1 = MAKE_ATOM(sisxvsdcrt1status);
+ pSiSUSB->xv_CMD = MAKE_ATOM(sisxvsdcheckmodeindexforcrt2);
+ pSiSUSB->xv_CMDR = MAKE_ATOM(sisxvsdresultcheckmodeindexforcrt2);
+ pSiSUSB->xv_RDT = MAKE_ATOM(sisxvsdredetectcrt2);
+ pSiSUSB->xv_TAF = MAKE_ATOM(sisxvsdsisantiflicker);
+ pSiSUSB->xv_TSA = MAKE_ATOM(sisxvsdsissaturation);
+ pSiSUSB->xv_TEE = MAKE_ATOM(sisxvsdsisedgeenhance);
+ pSiSUSB->xv_COC = MAKE_ATOM(sisxvsdsiscolcalibc);
+ pSiSUSB->xv_COF = MAKE_ATOM(sisxvsdsiscolcalibf);
+ pSiSUSB->xv_CFI = MAKE_ATOM(sisxvsdsiscfilter);
+ pSiSUSB->xv_YFI = MAKE_ATOM(sisxvsdsisyfilter);
+ pSiSUSB->xv_TCO = MAKE_ATOM(sisxvsdchcontrast);
+ pSiSUSB->xv_TTE = MAKE_ATOM(sisxvsdchtextenhance);
+ pSiSUSB->xv_TCF = MAKE_ATOM(sisxvsdchchromaflickerfilter);
+ pSiSUSB->xv_TLF = MAKE_ATOM(sisxvsdchlumaflickerfilter);
+ pSiSUSB->xv_TCC = MAKE_ATOM(sisxvsdchcvbscolor);
+ pSiSUSB->xv_OVR = MAKE_ATOM(sisxvsdchoverscan);
+ pSiSUSB->xv_SGA = MAKE_ATOM(sisxvsdenablegamma);
+ pSiSUSB->xv_TXS = MAKE_ATOM(sisxvsdtvxscale);
+ pSiSUSB->xv_TYS = MAKE_ATOM(sisxvsdtvyscale);
+ pSiSUSB->xv_GSS = MAKE_ATOM(sisxvsdgetscreensize);
+ pSiSUSB->xv_BRR = MAKE_ATOM(sisxvsdstorebrir);
+ pSiSUSB->xv_BRG = MAKE_ATOM(sisxvsdstorebrig);
+ pSiSUSB->xv_BRB = MAKE_ATOM(sisxvsdstorebrib);
+ pSiSUSB->xv_PBR = MAKE_ATOM(sisxvsdstorepbrir);
+ pSiSUSB->xv_PBG = MAKE_ATOM(sisxvsdstorepbrig);
+ pSiSUSB->xv_PBB = MAKE_ATOM(sisxvsdstorepbrib);
+ pSiSUSB->xv_BRR2 = MAKE_ATOM(sisxvsdstorebrir2);
+ pSiSUSB->xv_BRG2 = MAKE_ATOM(sisxvsdstorebrig2);
+ pSiSUSB->xv_BRB2 = MAKE_ATOM(sisxvsdstorebrib2);
+ pSiSUSB->xv_PBR2 = MAKE_ATOM(sisxvsdstorepbrir2);
+ pSiSUSB->xv_PBG2 = MAKE_ATOM(sisxvsdstorepbrig2);
+ pSiSUSB->xv_PBB2 = MAKE_ATOM(sisxvsdstorepbrib2);
+ pSiSUSB->xv_GARC2 = MAKE_ATOM(sisxvsdstoregarc2);
+ pSiSUSB->xv_GAGC2 = MAKE_ATOM(sisxvsdstoregagc2);
+ pSiSUSB->xv_GABC2 = MAKE_ATOM(sisxvsdstoregabc2);
+ pSiSUSB->xv_BRRC2 = MAKE_ATOM(sisxvsdstorebrirc2);
+ pSiSUSB->xv_BRGC2 = MAKE_ATOM(sisxvsdstorebrigc2);
+ pSiSUSB->xv_BRBC2 = MAKE_ATOM(sisxvsdstorebribc2);
+ pSiSUSB->xv_PBRC2 = MAKE_ATOM(sisxvsdstorepbrirc2);
+ pSiSUSB->xv_PBGC2 = MAKE_ATOM(sisxvsdstorepbrigc2);
+ pSiSUSB->xv_PBBC2 = MAKE_ATOM(sisxvsdstorepbribc2);
+ pSiSUSB->xv_SHC = MAKE_ATOM(sisxvsdhidehwcursor);
+ pSiSUSB->xv_PMD = MAKE_ATOM(sisxvsdpanelmode);
+#ifdef TWDEBUG
+ pSiSUSB->xv_STR = MAKE_ATOM(sisxvsetreg);
+#endif
+#endif
+
+ pSiSUSB->xv_sisdirectunlocked = 0;
+ pSiSUSB->xv_sd_result = 0;
+
+ pPriv->shiftValue = 1;
+
+ /* Set displayMode according to VBFlags */
+#ifdef SIS_ENABLEXV
+ set_dispmode(pScrn, pPriv);
+#endif
+
+ pPriv->linebufMergeLimit = LINEBUFLIMIT1;
+
+ set_maxencoding(pSiSUSB, pPriv);
+
+ pPriv->linebufmask = 0xb1;
+ if(!(pPriv->hasTwoOverlays)) {
+ /* On machines with only one overlay, the linebuffers are
+ * generally larger, so our merging-limit is higher, too.
+ */
+ pPriv->linebufMergeLimit = LINEBUFLIMIT2;
+ }
+
+ /* Reset the properties to their defaults */
+ SISUSBSetPortDefaults(pScrn, pPriv);
+
+#ifdef SIS_ENABLEXV
+ /* Set SR(06, 32) registers according to DISPMODE */
+ set_disptype_regs(pScrn, pPriv);
+
+ SISUSBResetVideo(pScrn);
+ pSiSUSB->ResetXv = SISUSBResetVideo;
+ pSiSUSB->ResetXvGamma = SISUSBResetXvGamma;
+#endif
+
+ return adapt;
+}
+
+#ifdef SIS_ENABLEXV
+#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
+static Bool
+RegionsEqual(RegionPtr A, RegionPtr B)
+{
+ int *dataA, *dataB;
+ int num;
+
+ num = REGION_NUM_RECTS(A);
+ if(num != REGION_NUM_RECTS(B))
+ return FALSE;
+
+ if((A->extents.x1 != B->extents.x1) ||
+ (A->extents.x2 != B->extents.x2) ||
+ (A->extents.y1 != B->extents.y1) ||
+ (A->extents.y2 != B->extents.y2))
+ return FALSE;
+
+ dataA = (int*)REGION_RECTS(A);
+ dataB = (int*)REGION_RECTS(B);
+
+ while(num--) {
+ if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
+ return FALSE;
+ dataA += 2;
+ dataB += 2;
+ }
+
+ return TRUE;
+}
+#endif
+#endif
+
+#if 0
+void
+SISUSBUpdateVideoParms(SISUSBPtr pSiSUSB, SISUSBPortPrivPtr pPriv)
+{
+ set_allowswitchcrt(pSiSUSB, pPriv);
+#ifdef SIS_ENABLEXV
+ set_dispmode(pSiSUSB->pScrn, pPriv);
+#endif
+ set_maxencoding(pSiSUSB, pPriv);
+}
+#endif
+
+static int
+SISUSBSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 value, pointer data)
+{
+ SISUSBPortPrivPtr pPriv = (SISUSBPortPrivPtr)data;
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+
+ if(attribute == pSiSUSB->xvBrightness) {
+ if((value < -128) || (value > 127))
+ return BadValue;
+ pPriv->brightness = value;
+ } else if(attribute == pSiSUSB->xvContrast) {
+ if((value < 0) || (value > 7))
+ return BadValue;
+ pPriv->contrast = value;
+ } else if(attribute == pSiSUSB->xvColorKey) {
+ pPriv->colorKey = pSiSUSB->colorKey = value;
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+ } else if(attribute == pSiSUSB->xvAutopaintColorKey) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->autopaintColorKey = value;
+ } else if(attribute == pSiSUSB->xvSetDefaults) {
+ SISUSBSetPortDefaults(pScrn, pPriv);
+ } else if(attribute == pSiSUSB->xvDisableGfx) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->disablegfx = value;
+ } else if(attribute == pSiSUSB->xvDisableGfxLR) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->disablegfxlr = value;
+ } else if(attribute == pSiSUSB->xvTVXPosition) {
+ /* Nop */
+ } else if(attribute == pSiSUSB->xvTVYPosition) {
+ /* Nop */
+ } else if(attribute == pSiSUSB->xvDisableColorkey) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pSiSUSB->disablecolorkeycurrent = value;
+ } else if(attribute == pSiSUSB->xvUseChromakey) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->usechromakey = value;
+ } else if(attribute == pSiSUSB->xvInsideChromakey) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->insidechromakey = value;
+ } else if(attribute == pSiSUSB->xvYUVChromakey) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->yuvchromakey = value;
+ } else if(attribute == pSiSUSB->xvChromaMin) {
+ pPriv->chromamin = value;
+ } else if(attribute == pSiSUSB->xvChromaMax) {
+ pPriv->chromamax = value;
+ } else if(attribute == pSiSUSB->xvHue) {
+ if((value < -8) || (value > 7))
+ return BadValue;
+ pPriv->hue = value;
+ } else if(attribute == pSiSUSB->xvSaturation) {
+ if((value < -7) || (value > 7))
+ return BadValue;
+ pPriv->saturation = value;
+ } else if(attribute == pSiSUSB->xvGammaRed) {
+ if((value < 100) || (value > 10000))
+ return BadValue;
+ pSiSUSB->XvGammaRed = value;
+#ifdef SIS_ENABLEXV
+ SiSUSBUpdateXvGamma(pSiSUSB, pPriv);
+#endif
+ } else if(attribute == pSiSUSB->xvGammaGreen) {
+ if((value < 100) || (value > 10000))
+ return BadValue;
+ pSiSUSB->XvGammaGreen = value;
+#ifdef SIS_ENABLEXV
+ SiSUSBUpdateXvGamma(pSiSUSB, pPriv);
+#endif
+ } else if(attribute == pSiSUSB->xvGammaBlue) {
+ if((value < 100) || (value > 10000))
+ return BadValue;
+ pSiSUSB->XvGammaBlue = value;
+#ifdef SIS_ENABLEXV
+ SiSUSBUpdateXvGamma(pSiSUSB, pPriv);
+#endif
+ } else if(attribute == pSiSUSB->xvSwitchCRT) {
+ if(pPriv->AllowSwitchCRT) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->crtnum = value;
+ }
+ } else {
+#ifdef XV_SD_DEPRECATED
+ return(SISUSBSetPortUtilAttribute(pScrn, attribute, value, pPriv));
+#else
+ return BadMatch;
+#endif
+ }
+ return Success;
+}
+
+static int
+SISUSBGetPortAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value,
+ pointer data
+){
+ SISUSBPortPrivPtr pPriv = (SISUSBPortPrivPtr)data;
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+
+ if(attribute == pSiSUSB->xvBrightness) {
+ *value = pPriv->brightness;
+ } else if(attribute == pSiSUSB->xvContrast) {
+ *value = pPriv->contrast;
+ } else if(attribute == pSiSUSB->xvColorKey) {
+ *value = pPriv->colorKey;
+ } else if(attribute == pSiSUSB->xvAutopaintColorKey) {
+ *value = (pPriv->autopaintColorKey) ? 1 : 0;
+ } else if(attribute == pSiSUSB->xvDisableGfx) {
+ *value = (pPriv->disablegfx) ? 1 : 0;
+ } else if(attribute == pSiSUSB->xvDisableGfxLR) {
+ *value = (pPriv->disablegfxlr) ? 1 : 0;
+ } else if(attribute == pSiSUSB->xvTVXPosition) {
+ *value = 0;
+ } else if(attribute == pSiSUSB->xvTVYPosition) {
+ *value = 0;
+ } else if(attribute == pSiSUSB->xvDisableColorkey) {
+ *value = (pSiSUSB->disablecolorkeycurrent) ? 1 : 0;
+ } else if(attribute == pSiSUSB->xvUseChromakey) {
+ *value = (pPriv->usechromakey) ? 1 : 0;
+ } else if(attribute == pSiSUSB->xvInsideChromakey) {
+ *value = (pPriv->insidechromakey) ? 1 : 0;
+ } else if(attribute == pSiSUSB->xvYUVChromakey) {
+ *value = (pPriv->yuvchromakey) ? 1 : 0;
+ } else if(attribute == pSiSUSB->xvChromaMin) {
+ *value = pPriv->chromamin;
+ } else if(attribute == pSiSUSB->xvChromaMax) {
+ *value = pPriv->chromamax;
+ } else if(attribute == pSiSUSB->xvHue) {
+ *value = pPriv->hue;
+ } else if(attribute == pSiSUSB->xvSaturation) {
+ *value = pPriv->saturation;
+ } else if(attribute == pSiSUSB->xvGammaRed) {
+ *value = pSiSUSB->XvGammaRed;
+ } else if(attribute == pSiSUSB->xvGammaGreen) {
+ *value = pSiSUSB->XvGammaGreen;
+ } else if(attribute == pSiSUSB->xvGammaBlue) {
+ *value = pSiSUSB->XvGammaBlue;
+ } else if(attribute == pSiSUSB->xvSwitchCRT) {
+ *value = 0;
+ } else {
+#ifdef XV_SD_DEPRECATED
+ return(SISUSBGetPortUtilAttribute(pScrn, attribute, value, pPriv));
+#else
+ return BadMatch;
+#endif
+ }
+ return Success;
+}
+
+static void
+SISUSBQueryBestSize(
+ ScrnInfoPtr pScrn,
+ Bool motion,
+ short vid_w, short vid_h,
+ short drw_w, short drw_h,
+ unsigned int *p_w, unsigned int *p_h,
+ pointer data
+){
+ *p_w = drw_w;
+ *p_h = drw_h;
+}
+
+#ifdef SIS_ENABLEXV
+static void
+calc_scale_factor(SISUSBOverlayPtr pOverlay, ScrnInfoPtr pScrn,
+ SISUSBPortPrivPtr pPriv, int index, int iscrt2)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ CARD32 I=0,mult=0;
+ int flag=0;
+
+ int dstW = pOverlay->dstBox.x2 - pOverlay->dstBox.x1;
+ int dstH = pOverlay->dstBox.y2 - pOverlay->dstBox.y1;
+ int srcW = pOverlay->srcW;
+ int srcH = pOverlay->srcH;
+ int srcPitch = pOverlay->origPitch;
+ int origdstH = dstH;
+ int modeflags = pOverlay->currentmode->Flags;
+
+ /* For double scan modes, we need to double the height
+ * On 315 and 550 (?), we need to double the width as well.
+ * Interlace mode vice versa.
+ */
+ if(modeflags & V_DBLSCAN) {
+ dstH = origdstH << 1;
+ flag = 0;
+ if((pSiSUSB->ChipType >= SIS_315H) &&
+ (pSiSUSB->ChipType <= SIS_550)) {
+ dstW <<= 1;
+ }
+ }
+ if(modeflags & V_INTERLACE) {
+ dstH = origdstH >> 1;
+ flag = 0;
+ }
+
+ if(dstW < OVERLAY_MIN_WIDTH) dstW = OVERLAY_MIN_WIDTH;
+ if(dstW == srcW) {
+ pOverlay->HUSF = 0x00;
+ pOverlay->IntBit = 0x05;
+ pOverlay->wHPre = 0;
+ } else if(dstW > srcW) {
+ dstW += 2;
+ pOverlay->HUSF = (srcW << 16) / dstW;
+ pOverlay->IntBit = 0x04;
+ pOverlay->wHPre = 0;
+ } else {
+ int tmpW = dstW;
+
+ /* It seems, the hardware can't scale below factor .125 (=1/8) if the
+ pitch isn't a multiple of 256.
+ TODO: Test this on the 315 series!
+ */
+ if((srcPitch % 256) || (srcPitch < 256)) {
+ if(((dstW * 1000) / srcW) < 125) dstW = tmpW = ((srcW * 125) / 1000) + 1;
+ }
+
+ I = 0;
+ pOverlay->IntBit = 0x01;
+ while(srcW >= tmpW) {
+ tmpW <<= 1;
+ I++;
+ }
+ pOverlay->wHPre = (CARD8)(I - 1);
+ dstW <<= (I - 1);
+ if((srcW % dstW))
+ pOverlay->HUSF = ((srcW - dstW) << 16) / dstW;
+ else
+ pOverlay->HUSF = 0x00;
+ }
+
+ if(dstH < OVERLAY_MIN_HEIGHT) dstH = OVERLAY_MIN_HEIGHT;
+ if(dstH == srcH) {
+ pOverlay->VUSF = 0x00;
+ pOverlay->IntBit |= 0x0A;
+ } else if(dstH > srcH) {
+ dstH += 0x02;
+ pOverlay->VUSF = (srcH << 16) / dstH;
+ pOverlay->IntBit |= 0x08;
+ } else {
+
+ I = srcH / dstH;
+ pOverlay->IntBit |= 0x02;
+
+ if(I < 2) {
+ pOverlay->VUSF = ((srcH - dstH) << 16) / dstH;
+ /* Needed for LCD-scaling modes */
+ if((flag) && (mult = (srcH / origdstH)) >= 2) {
+ pOverlay->pitch /= mult;
+ }
+ } else {
+#if 0
+ if(((pOverlay->bobEnable & 0x08) == 0x00) &&
+ (((srcPitch * I) >> 2) > 0xFFF)){
+ pOverlay->bobEnable |= 0x08;
+ srcPitch >>= 1;
+ }
+#endif
+ if(((srcPitch * I) >> 2) > 0xFFF) {
+ I = (0xFFF * 2 / srcPitch);
+ pOverlay->VUSF = 0xFFFF;
+ } else {
+ dstH = I * dstH;
+ if(srcH % dstH)
+ pOverlay->VUSF = ((srcH - dstH) << 16) / dstH;
+ else
+ pOverlay->VUSF = 0x00;
+ }
+ /* set video frame buffer offset */
+ pOverlay->pitch = (CARD16)(srcPitch * I);
+ }
+ }
+}
+
+static CARD16
+calc_line_buf_size(CARD32 srcW, CARD8 wHPre, CARD8 planar, SISUSBPortPrivPtr pPriv)
+{
+ CARD32 I;
+
+ if(planar) {
+
+ switch(wHPre & 0x07) {
+ case 3:
+ I = (srcW >> 8);
+ if(srcW & 0xff) I++;
+ I <<= 5;
+ break;
+ case 4:
+ I = (srcW >> 9);
+ if(srcW & 0x1ff) I++;
+ I <<= 6;
+ break;
+ case 5:
+ I = (srcW >> 10);
+ if(srcW & 0x3ff) I++;
+ I <<= 7;
+ break;
+ case 6:
+ if(pPriv->is340) {
+ I = (srcW >> 11);
+ if(srcW & 0x7ff) I++;
+ I <<= 8;
+ break;
+ } else {
+ return((CARD16)(255));
+ }
+ default:
+ I = (srcW >> 7);
+ if(srcW & 0x7f) I++;
+ I <<= 4;
+ break;
+ }
+
+ } else { /* packed */
+
+ I = (srcW >> 3);
+ if(srcW & 0x07) I++;
+
+ }
+
+ if(I <= 3) I = 4;
+
+ return((CARD16)(I - 1));
+}
+
+static __inline void
+calc_line_buf_size_1(SISUSBOverlayPtr pOverlay, SISUSBPortPrivPtr pPriv)
+{
+ pOverlay->lineBufSize =
+ calc_line_buf_size(pOverlay->srcW, pOverlay->wHPre, pOverlay->planar, pPriv);
+}
+
+static void
+merge_line_buf(SISUSBPtr pSiSUSB, SISUSBPortPrivPtr pPriv, Bool enable, short width, short limit)
+{
+ UChar misc1, misc2, mask = pPriv->linebufmask;
+
+ if(enable) { /* ----- enable linebuffer merge */
+
+ misc2 = 0x00;
+ misc1 = 0x04;
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc2, misc2, mask);
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, misc1, 0x04);
+
+ } else { /* ----- disable linebuffer merge */
+
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc2, 0x00, mask);
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, 0x00, 0x04);
+
+ }
+}
+
+static __inline void
+set_format(SISUSBPtr pSiSUSB, SISUSBOverlayPtr pOverlay)
+{
+ CARD8 fmt;
+
+ switch (pOverlay->pixelFormat){
+ case PIXEL_FMT_YV12:
+ case PIXEL_FMT_I420:
+ fmt = 0x0c;
+ break;
+ case PIXEL_FMT_YUY2:
+ fmt = 0x28;
+ break;
+ case PIXEL_FMT_UYVY:
+ fmt = 0x08;
+ break;
+ case PIXEL_FMT_YVYU:
+ fmt = 0x38;
+ break;
+ case PIXEL_FMT_NV12:
+ fmt = 0x4c;
+ break;
+ case PIXEL_FMT_NV21:
+ fmt = 0x5c;
+ break;
+ case PIXEL_FMT_RGB5: /* D[5:4] : 00 RGB555, 01 RGB 565 */
+ fmt = 0x00;
+ break;
+ case PIXEL_FMT_RGB6:
+ fmt = 0x10;
+ break;
+ default:
+ fmt = 0x00;
+ break;
+ }
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc0, fmt, 0xfc);
+}
+
+static __inline void
+set_colorkey(SISUSBPtr pSiSUSB, CARD32 colorkey)
+{
+ CARD8 r, g, b;
+
+ b = (CARD8)(colorkey & 0xFF);
+ g = (CARD8)((colorkey>>8) & 0xFF);
+ r = (CARD8)((colorkey>>16) & 0xFF);
+
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ColorKey_Blue_Min ,(CARD8)b);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ColorKey_Green_Min ,(CARD8)g);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ColorKey_Red_Min ,(CARD8)r);
+
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ColorKey_Blue_Max ,(CARD8)b);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ColorKey_Green_Max ,(CARD8)g);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ColorKey_Red_Max ,(CARD8)r);
+}
+
+static __inline void
+set_chromakey(SISUSBPtr pSiSUSB, CARD32 chromamin, CARD32 chromamax)
+{
+ CARD8 r1, g1, b1;
+ CARD8 r2, g2, b2;
+
+ b1 = (CARD8)(chromamin & 0xFF);
+ g1 = (CARD8)((chromamin>>8) & 0xFF);
+ r1 = (CARD8)((chromamin>>16) & 0xFF);
+ b2 = (CARD8)(chromamax & 0xFF);
+ g2 = (CARD8)((chromamax>>8) & 0xFF);
+ r2 = (CARD8)((chromamax>>16) & 0xFF);
+
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ChromaKey_Blue_V_Min ,(CARD8)b1);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ChromaKey_Green_U_Min ,(CARD8)g1);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ChromaKey_Red_Y_Min ,(CARD8)r1);
+
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ChromaKey_Blue_V_Max ,(CARD8)b2);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ChromaKey_Green_U_Max ,(CARD8)g2);
+ setvideoreg(pSiSUSB, Index_VI_Overlay_ChromaKey_Red_Y_Max ,(CARD8)r2);
+}
+
+static __inline void
+set_brightness(SISUSBPtr pSiSUSB, CARD8 brightness)
+{
+ setvideoreg(pSiSUSB, Index_VI_Brightness, brightness);
+}
+
+static __inline void
+set_contrast(SISUSBPtr pSiSUSB, CARD8 contrast)
+{
+ setvideoregmask(pSiSUSB, Index_VI_Contrast_Enh_Ctrl, contrast, 0x07);
+}
+
+/* 315 series and later only */
+static __inline void
+set_saturation(SISUSBPtr pSiSUSB, short saturation)
+{
+ CARD8 temp = 0;
+
+ if(saturation < 0) {
+ temp |= 0x88;
+ saturation = -saturation;
+ }
+ temp |= (saturation & 0x07);
+ temp |= ((saturation & 0x07) << 4);
+
+ setvideoreg(pSiSUSB, Index_VI_Saturation, temp);
+}
+
+/* 315 series and later only */
+static __inline void
+set_hue(SISUSBPtr pSiSUSB, CARD8 hue)
+{
+ setvideoregmask(pSiSUSB, Index_VI_Hue, (hue & 0x08) ? (hue ^ 0x07) : hue, 0x0F);
+}
+
+static __inline void
+set_disablegfx(SISUSBPtr pSiSUSB, Bool mybool, SISUSBOverlayPtr pOverlay)
+{
+ /* This is not supported on M65x, 65x (x>0) or later */
+ /* For CRT1 ONLY!!! */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc2, mybool ? 0x04 : 0x00, 0x04);
+ if(mybool) pOverlay->keyOP = VI_ROP_Always;
+}
+
+static __inline void
+set_disablegfxlr(SISUSBPtr pSiSUSB, Bool mybool, SISUSBOverlayPtr pOverlay)
+{
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, mybool ? 0x01 : 0x00, 0x01);
+ if(mybool) pOverlay->keyOP = VI_ROP_Always;
+}
+
+static void
+set_overlay(SISUSBPtr pSiSUSB, SISUSBOverlayPtr pOverlay, SISUSBPortPrivPtr pPriv, int index, int iscrt2)
+{
+ CARD8 h_over=0, v_over=0;
+ CARD16 top, bottom, left, right, pitch=0;
+ CARD16 screenX, screenY;
+ CARD32 PSY;
+ int modeflags;
+
+ screenX = pOverlay->currentmode->HDisplay;
+ screenY = pOverlay->currentmode->VDisplay;
+ modeflags = pOverlay->currentmode->Flags;
+ top = pOverlay->dstBox.y1;
+ bottom = pOverlay->dstBox.y2;
+ left = pOverlay->dstBox.x1;
+ right = pOverlay->dstBox.x2;
+ pitch = pOverlay->pitch >> pPriv->shiftValue;
+
+ if(bottom > screenY) {
+ bottom = screenY;
+ }
+ if(right > screenX) {
+ right = screenX;
+ }
+
+ /* DoubleScan modes require Y coordinates * 2 */
+ if(modeflags & V_DBLSCAN) {
+ top <<= 1;
+ bottom <<= 1;
+ }
+ /* Interlace modes require Y coordinates / 2 */
+ if(modeflags & V_INTERLACE) {
+ top >>= 1;
+ bottom >>= 1;
+ }
+
+ h_over = (((left>>8) & 0x0f) | ((right>>4) & 0xf0));
+ v_over = (((top>>8) & 0x0f) | ((bottom>>4) & 0xf0));
+
+ /* set line buffer size */
+
+ setvideoreg(pSiSUSB, Index_VI_Line_Buffer_Size, (CARD8)pOverlay->lineBufSize);
+
+ /* set color key mode */
+ setvideoregmask(pSiSUSB, Index_VI_Key_Overlay_OP, pOverlay->keyOP, 0x0f);
+
+ /* Unlock address registers */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, 0x20, 0x20);
+
+ /* set destination window position */
+ setvideoreg(pSiSUSB, Index_VI_Win_Hor_Disp_Start_Low, (CARD8)left);
+ setvideoreg(pSiSUSB, Index_VI_Win_Hor_Disp_End_Low, (CARD8)right);
+ setvideoreg(pSiSUSB, Index_VI_Win_Hor_Over, (CARD8)h_over);
+
+ setvideoreg(pSiSUSB, Index_VI_Win_Ver_Disp_Start_Low, (CARD8)top);
+ setvideoreg(pSiSUSB, Index_VI_Win_Ver_Disp_End_Low, (CARD8)bottom);
+ setvideoreg(pSiSUSB, Index_VI_Win_Ver_Over, (CARD8)v_over);
+
+ /* Set Y buf pitch */
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_Buf_Pitch_Low, (CARD8)(pitch));
+ setvideoregmask(pSiSUSB, Index_VI_Disp_Y_UV_Buf_Pitch_Middle, (CARD8)(pitch >> 8), 0x0f);
+
+ /* Set Y start address */
+ PSY = pOverlay->PSY;
+
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_Buf_Start_Low, (CARD8)(PSY));
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_Buf_Start_Middle, (CARD8)(PSY >> 8));
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_Buf_Start_High, (CARD8)(PSY >> 16));
+
+ /* overflow bits for Y plane */
+ setvideoreg(pSiSUSB, Index_VI_Disp_Y_Buf_Pitch_High, (CARD8)(pitch >> 12));
+ setvideoreg(pSiSUSB, Index_VI_Y_Buf_Start_Over, ((CARD8)(PSY >> 24) & 0x03));
+
+ /* Set U/V data if using planar formats */
+ if(pOverlay->planar) {
+
+ CARD32 PSU = pOverlay->PSU;
+ CARD32 PSV = pOverlay->PSV;
+
+ if(pOverlay->planar_shiftpitch) pitch >>= 1;
+
+ /* Set U/V pitch */
+ setvideoreg(pSiSUSB, Index_VI_Disp_UV_Buf_Pitch_Low, (CARD8)pitch);
+ setvideoregmask(pSiSUSB, Index_VI_Disp_Y_UV_Buf_Pitch_Middle, (CARD8)(pitch >> 4), 0xf0);
+
+ /* set U/V start address */
+ setvideoreg(pSiSUSB, Index_VI_U_Buf_Start_Low, (CARD8)PSU);
+ setvideoreg(pSiSUSB, Index_VI_U_Buf_Start_Middle,(CARD8)(PSU >> 8));
+ setvideoreg(pSiSUSB, Index_VI_U_Buf_Start_High, (CARD8)(PSU >> 16));
+
+ setvideoreg(pSiSUSB, Index_VI_V_Buf_Start_Low, (CARD8)PSV);
+ setvideoreg(pSiSUSB, Index_VI_V_Buf_Start_Middle,(CARD8)(PSV >> 8));
+ setvideoreg(pSiSUSB, Index_VI_V_Buf_Start_High, (CARD8)(PSV >> 16));
+
+ /* overflow bits */
+ setvideoreg(pSiSUSB, Index_VI_Disp_UV_Buf_Pitch_High, (CARD8)(pitch >> 12));
+ setvideoreg(pSiSUSB, Index_VI_U_Buf_Start_Over, ((CARD8)(PSU >> 24) & 0x03));
+ setvideoreg(pSiSUSB, Index_VI_V_Buf_Start_Over, ((CARD8)(PSV >> 24) & 0x03));
+
+
+ }
+
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, pOverlay->bobEnable, 0x1a);
+
+ /* Lock the address registers */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, 0x00, 0x20);
+
+ /* set scale factor */
+ setvideoreg(pSiSUSB, Index_VI_Hor_Post_Up_Scale_Low, (CARD8)(pOverlay->HUSF));
+ setvideoreg(pSiSUSB, Index_VI_Hor_Post_Up_Scale_High,(CARD8)((pOverlay->HUSF) >> 8));
+ setvideoreg(pSiSUSB, Index_VI_Ver_Up_Scale_Low, (CARD8)(pOverlay->VUSF));
+ setvideoreg(pSiSUSB, Index_VI_Ver_Up_Scale_High, (CARD8)((pOverlay->VUSF) >> 8));
+
+ setvideoregmask(pSiSUSB, Index_VI_Scale_Control, (pOverlay->IntBit << 3) |
+ (pOverlay->wHPre), 0x7f);
+
+}
+#endif /* SIS_ENABLEXV */
+
+/* Overlay MUST NOT be switched off while beam is over it */
+#ifdef SIS_ENABLEXV
+static void
+close_overlay(SISUSBPtr pSiSUSB, SISUSBPortPrivPtr pPriv)
+{
+#if 0
+ int watchdog;
+#endif
+
+ if(!(pPriv->overlayStatus)) return;
+ pPriv->overlayStatus = FALSE;
+
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc2, 0x00, 0x05);
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc1, 0x00, 0x01);
+
+#if 0
+ watchdog = WATCHDOG_DELAY;
+ while((!vblank_active_CRT1(pSiSUSB, pPriv)) && --watchdog);
+ watchdog = WATCHDOG_DELAY;
+ while(vblank_active_CRT1(pSiSUSB, pPriv) && --watchdog);
+#endif
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc0, 0x00, 0x02);
+#if 0
+ watchdog = WATCHDOG_DELAY;
+ while((!vblank_active_CRT1(pSiSUSB, pPriv)) && --watchdog);
+ watchdog = WATCHDOG_DELAY;
+ while(vblank_active_CRT1(pSiSUSB, pPriv) && --watchdog);
+#endif
+
+}
+#endif
+
+#ifdef SIS_ENABLEXV
+static void
+SISUSBDisplayVideo(ScrnInfoPtr pScrn, SISUSBPortPrivPtr pPriv)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ short srcPitch = pPriv->srcPitch;
+ short height = pPriv->height;
+ UShort screenwidth;
+ SISUSBOverlayRec overlay;
+ int srcOffsetX = 0, srcOffsetY = 0;
+ int sx = 0, sy = 0;
+ int index = 0, iscrt2 = 0;
+
+ pPriv->NoOverlay = FALSE;
+
+ /* setup dispmode (MIRROR, SINGLEx) */
+ set_dispmode(pScrn, pPriv);
+
+ /* Check if overlay is supported with current mode */
+ if(!(pSiSUSB->MiscFlags & MISC_CRT1OVERLAY)) {
+ if(pPriv->overlayStatus) {
+ close_overlay(pSiSUSB, pPriv);
+ }
+ pPriv->NoOverlay = TRUE;
+ return;
+ }
+
+ memset(&overlay, 0, sizeof(overlay));
+
+ overlay.pixelFormat = pPriv->id;
+ overlay.pitch = overlay.origPitch = srcPitch;
+ if(pPriv->usechromakey) {
+ overlay.keyOP = (pPriv->insidechromakey) ? VI_ROP_ChromaKey : VI_ROP_NotChromaKey;
+ } else {
+ overlay.keyOP = VI_ROP_DestKey;
+ }
+
+ overlay.bobEnable = 0x00; /* Disable BOB de-interlacer */
+
+ overlay.currentmode = pSiSUSB->CurrentLayout.mode;
+ overlay.SCREENheight = overlay.currentmode->VDisplay;
+ screenwidth = overlay.currentmode->HDisplay;
+ overlay.dstBox.x1 = pPriv->drw_x - pScrn->frameX0;
+ overlay.dstBox.x2 = pPriv->drw_x + pPriv->drw_w - pScrn->frameX0;
+ overlay.dstBox.y1 = pPriv->drw_y - pScrn->frameY0;
+ overlay.dstBox.y2 = pPriv->drw_y + pPriv->drw_h - pScrn->frameY0;
+
+ /* Note: x2/y2 is actually real coordinate + 1 */
+
+ if((overlay.dstBox.x1 >= overlay.dstBox.x2) ||
+ (overlay.dstBox.y1 >= overlay.dstBox.y2)) {
+ return;
+ }
+
+ if((overlay.dstBox.x2 <= 0) || (overlay.dstBox.y2 <= 0)) {
+ return;
+ }
+
+ if((overlay.dstBox.x1 >= screenwidth) || (overlay.dstBox.y1 >= overlay.SCREENheight)) {
+ return;
+ }
+
+ if(overlay.dstBox.x1 < 0) {
+ srcOffsetX = pPriv->src_w * (-overlay.dstBox.x1) / pPriv->drw_w;
+ overlay.dstBox.x1 = 0;
+ }
+ if(overlay.dstBox.y1 < 0) {
+ srcOffsetY = pPriv->src_h * (-overlay.dstBox.y1) / pPriv->drw_h;
+ overlay.dstBox.y1 = 0;
+ }
+
+ if((overlay.dstBox.x1 >= overlay.dstBox.x2 - 2) ||
+ (overlay.dstBox.x1 >= screenwidth - 2) ||
+ (overlay.dstBox.y1 >= overlay.dstBox.y2)) {
+ return;
+ }
+
+ switch(pPriv->id) {
+
+ case PIXEL_FMT_YV12:
+ overlay.planar = 1;
+ overlay.planar_shiftpitch = 1;
+ sx = (pPriv->src_x + srcOffsetX) & ~7;
+ sy = (pPriv->src_y + srcOffsetY) & ~1;
+ overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy*srcPitch;
+ overlay.PSV = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx + sy*srcPitch/2) >> 1);
+ overlay.PSU = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch*5/4 + ((sx + sy*srcPitch/2) >> 1);
+ overlay.PSY >>= pPriv->shiftValue;
+ overlay.PSV >>= pPriv->shiftValue;
+ overlay.PSU >>= pPriv->shiftValue;
+ break;
+
+ case PIXEL_FMT_I420:
+ overlay.planar = 1;
+ overlay.planar_shiftpitch = 1;
+ sx = (pPriv->src_x + srcOffsetX) & ~7;
+ sy = (pPriv->src_y + srcOffsetY) & ~1;
+ overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy*srcPitch;
+ overlay.PSV = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch*5/4 + ((sx + sy*srcPitch/2) >> 1);
+ overlay.PSU = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx + sy*srcPitch/2) >> 1);
+ overlay.PSY >>= pPriv->shiftValue;
+ overlay.PSV >>= pPriv->shiftValue;
+ overlay.PSU >>= pPriv->shiftValue;
+ break;
+
+ case PIXEL_FMT_NV12:
+ case PIXEL_FMT_NV21:
+ overlay.planar = 1;
+ overlay.planar_shiftpitch = 0;
+ sx = (pPriv->src_x + srcOffsetX) & ~7;
+ sy = (pPriv->src_y + srcOffsetY) & ~1;
+ overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy*srcPitch;
+ overlay.PSV = pPriv->bufAddr[pPriv->currentBuf] + height*srcPitch + ((sx + sy*srcPitch/2) >> 1);
+ overlay.PSY >>= pPriv->shiftValue;
+ overlay.PSV >>= pPriv->shiftValue;
+ overlay.PSU = overlay.PSV;
+ break;
+
+ case PIXEL_FMT_YUY2:
+ case PIXEL_FMT_UYVY:
+ case PIXEL_FMT_YVYU:
+ case PIXEL_FMT_RGB6:
+ case PIXEL_FMT_RGB5:
+ default:
+ overlay.planar = 0;
+ sx = (pPriv->src_x + srcOffsetX) & ~1;
+ sy = (pPriv->src_y + srcOffsetY);
+ overlay.PSY = (pPriv->bufAddr[pPriv->currentBuf] + sx*2 + sy*srcPitch);
+ overlay.PSY >>= pPriv->shiftValue;
+ break;
+ }
+
+ /* Some clipping checks */
+ overlay.srcW = pPriv->src_w - (sx - pPriv->src_x);
+ overlay.srcH = pPriv->src_h - (sy - pPriv->src_y);
+ if( (pPriv->oldx1 != overlay.dstBox.x1) ||
+ (pPriv->oldx2 != overlay.dstBox.x2) ||
+ (pPriv->oldy1 != overlay.dstBox.y1) ||
+ (pPriv->oldy2 != overlay.dstBox.y2) ) {
+ pPriv->mustwait = 1;
+ pPriv->oldx1 = overlay.dstBox.x1; pPriv->oldx2 = overlay.dstBox.x2;
+ pPriv->oldy1 = overlay.dstBox.y1; pPriv->oldy2 = overlay.dstBox.y2;
+ }
+
+ /* Loop head */
+ /* Note: index can only be 1 for CRT2, ie overlay 1
+ * is only used for CRT2.
+ */
+
+ index = 0; iscrt2 = 0;
+ overlay.VBlankActiveFunc = vblank_active_CRT1;
+
+ /* set display mode SR06,32 (CRT1, CRT2 or mirror) */
+ set_disptype_regs(pScrn, pPriv);
+
+ /* set (not only calc) merge line buffer */
+ merge_line_buf(pSiSUSB, pPriv, (overlay.srcW > pPriv->linebufMergeLimit), overlay.srcW,
+ pPriv->linebufMergeLimit);
+
+ /* calculate (not set!) line buffer length */
+ calc_line_buf_size_1(&overlay, pPriv);
+
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc3, 0x03, 0x03);
+
+ /* calculate scale factor */
+ calc_scale_factor(&overlay, pScrn, pPriv, index, iscrt2);
+
+ /* Select overlay 0 (used for CRT1/or CRT2) or overlay 1 (used for CRT2 only) */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc2, index, 0x01);
+
+ /* set format (before color and chroma keys) */
+ set_format(pSiSUSB, &overlay);
+
+ /* set color key */
+ set_colorkey(pSiSUSB, pPriv->colorKey);
+
+ if(pPriv->usechromakey) {
+ set_chromakey(pSiSUSB, pPriv->chromamin, pPriv->chromamax);
+ }
+
+ /* set brightness, contrast, hue, saturation */
+ set_brightness(pSiSUSB, pPriv->brightness);
+ set_contrast(pSiSUSB, pPriv->contrast);
+ set_hue(pSiSUSB, pPriv->hue);
+ set_saturation(pSiSUSB, pPriv->saturation);
+
+ /* enable/disable graphics display around overlay
+ * (Since disabled overlays don't get treated in this
+ * loop, we omit respective checks here)
+ */
+ if(!iscrt2) set_disablegfx(pSiSUSB, pPriv->disablegfx, &overlay);
+ else if(!pPriv->hasTwoOverlays) {
+ set_disablegfx(pSiSUSB, FALSE, &overlay);
+ }
+ set_disablegfxlr(pSiSUSB, pPriv->disablegfxlr, &overlay);
+
+ /* set remaining overlay parameters */
+ set_overlay(pSiSUSB, &overlay, pPriv, index, iscrt2);
+
+ /* enable overlay */
+ setvideoregmask (pSiSUSB, Index_VI_Control_Misc0, 0x02, 0x02);
+
+ /* Trigger register copy */
+ setvideoregmask(pSiSUSB, Index_VI_Control_Misc3, 0x03, 0x03);
+
+ pPriv->mustwait = 0;
+ pPriv->overlayStatus = TRUE;
+}
+#endif
+
+#ifdef SIS_ENABLEXV
+static FBLinearPtr
+SISUSBAllocateOverlayMemory(
+ ScrnInfoPtr pScrn,
+ FBLinearPtr linear,
+ int size
+){
+ ScreenPtr pScreen;
+ FBLinearPtr new_linear;
+
+ if(linear) {
+ if(linear->size >= size) return linear;
+
+ if(xf86ResizeOffscreenLinear(linear, size)) return linear;
+
+ xf86FreeOffscreenLinear(linear);
+ }
+
+ pScreen = screenInfo.screens[pScrn->scrnIndex];
+
+ new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
+ NULL, NULL, NULL);
+
+ if(!new_linear) {
+ int max_size;
+
+ xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8,
+ PRIORITY_EXTREME);
+
+ if(max_size < size) return NULL;
+
+ xf86PurgeUnlockedOffscreenAreas(pScreen);
+ new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
+ NULL, NULL, NULL);
+ }
+ if(!new_linear)
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Xv: Failed to allocate %d pixels of linear video memory\n", size);
+#ifdef TWDEBUG
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Xv: Allocated %d pixels of linear video memory\n", size);
+#endif
+
+ return new_linear;
+}
+
+static void
+SISUSBFreeOverlayMemory(ScrnInfoPtr pScrn)
+{
+ SISUSBPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
+
+ if(pPriv->linear) {
+ xf86FreeOffscreenLinear(pPriv->linear);
+ pPriv->linear = NULL;
+ }
+}
+#endif
+
+static void
+SISUSBStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
+{
+#ifdef SIS_ENABLEXV
+ SISUSBPortPrivPtr pPriv = (SISUSBPortPrivPtr)data;
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+
+ if(pPriv->grabbedByV4L) return;
+
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+
+ if(shutdown) {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ close_overlay(pSiSUSB, pPriv);
+ pPriv->mustwait = 1;
+ }
+ SISUSBFreeOverlayMemory(pScrn);
+ pPriv->videoStatus = 0;
+ } else {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ UpdateCurrentTime();
+ pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
+ pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
+ pSiSUSB->VideoTimerCallback = SISUSBVideoTimerCallback;
+ }
+ }
+#endif
+}
+
+#ifdef SIS_ENABLEXV
+static int
+SISUSBPutImage(
+ ScrnInfoPtr pScrn,
+ short src_x, short src_y,
+ short drw_x, short drw_y,
+ short src_w, short src_h,
+ short drw_w, short drw_h,
+ int id, UChar *buf,
+ short width, short height,
+ Bool sync,
+ RegionPtr clipBoxes, pointer data,
+ DrawablePtr pDraw
+){
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ SISUSBPortPrivPtr pPriv = (SISUSBPortPrivPtr)data;
+ int totalSize = 0, depth = pSiSUSB->CurrentLayout.bitsPerPixel >> 3;
+
+ if(pPriv->grabbedByV4L) return Success;
+
+ pPriv->drw_x = drw_x;
+ pPriv->drw_y = drw_y;
+ pPriv->drw_w = drw_w;
+ pPriv->drw_h = drw_h;
+ pPriv->src_x = src_x;
+ pPriv->src_y = src_y;
+ pPriv->src_w = src_w;
+ pPriv->src_h = src_h;
+ pPriv->id = id;
+ pPriv->height = height;
+
+ /* Pixel formats:
+ 1. YU12: 3 planes: H V
+ Y sample period 1 1 (8 bit per pixel)
+ V sample period 2 2 (8 bit per pixel, subsampled)
+ U sample period 2 2 (8 bit per pixel, subsampled)
+
+ Y plane is fully sampled (width*height), U and V planes
+ are sampled in 2x2 blocks, hence a group of 4 pixels requires
+ 4 + 1 + 1 = 6 bytes. The data is planar, ie in single planes
+ for Y, U and V.
+ 2. UYVY: 3 planes: H V
+ Y sample period 1 1 (8 bit per pixel)
+ V sample period 2 1 (8 bit per pixel, subsampled)
+ U sample period 2 1 (8 bit per pixel, subsampled)
+ Y plane is fully sampled (width*height), U and V planes
+ are sampled in 2x1 blocks, hence a group of 4 pixels requires
+ 4 + 2 + 2 = 8 bytes. The data is bit packed, there are no separate
+ Y, U or V planes.
+ Bit order: U0 Y0 V0 Y1 U2 Y2 V2 Y3 ...
+ 3. I420: Like YU12, but planes U and V are in reverse order.
+ 4. YUY2: Like UYVY, but order is
+ Y0 U0 Y1 V0 Y2 U2 Y3 V2 ...
+ 5. YVYU: Like YUY2, but order is
+ Y0 V0 Y1 U0 Y2 V2 Y3 U2 ...
+ 6. NV12, NV21: 2 planes H V
+ Y sample period 1 1 (8 bit per pixel)
+ V sample period 2 1 (8 bit per pixel, subsampled)
+ U sample period 2 1 (8 bit per pixel, subsampled)
+ Y plane is fully samples (width*height), U and V planes are
+ interleaved in memory (one byte U, one byte V for NV12, NV21
+ other way round) and sampled in 2x1 blocks. Otherwise such
+ as all other planar formats.
+ */
+
+ switch(id){
+ case PIXEL_FMT_YV12:
+ case PIXEL_FMT_I420:
+ case PIXEL_FMT_NV12:
+ case PIXEL_FMT_NV21:
+ pPriv->srcPitch = (width + 7) & ~7;
+ /* Size = width * height * 3 / 2 */
+ totalSize = (pPriv->srcPitch * height * 3) >> 1; /* Verified */
+ break;
+ case PIXEL_FMT_YUY2:
+ case PIXEL_FMT_UYVY:
+ case PIXEL_FMT_YVYU:
+ case PIXEL_FMT_RGB6:
+ case PIXEL_FMT_RGB5:
+ default:
+ pPriv->srcPitch = ((width << 1) + 3) & ~3; /* Verified */
+ /* Size = width * 2 * height */
+ totalSize = pPriv->srcPitch * height;
+ }
+
+ /* make it a multiple of 16 to simplify to copy loop */
+ totalSize += 15;
+ totalSize &= ~15; /* in bytes */
+
+ /* allocate memory (we do doublebuffering) - size is in pixels! */
+ if(!(pPriv->linear = SISUSBAllocateOverlayMemory(pScrn, pPriv->linear,
+ ((totalSize + depth - 1) / depth) << 1)))
+ return BadAlloc;
+
+ /* fixup pointers */
+ pPriv->bufAddr[0] = (pPriv->linear->offset * depth);
+
+ pPriv->bufAddr[1] = pPriv->bufAddr[0] + totalSize;
+
+ /* copy data */
+ SiSUSBMemCopyToVideoRam(pSiSUSB, pSiSUSB->FbBase + pPriv->bufAddr[pPriv->currentBuf], buf, totalSize);
+
+ SISUSBDisplayVideo(pScrn, pPriv);
+
+ /* update cliplist */
+ if(pPriv->autopaintColorKey &&
+ (pPriv->grabbedByV4L ||
+#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0)
+ (!RegionsEqual(&pPriv->clip, clipBoxes)) ||
+#else
+ (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) ||
+#endif
+ (pPriv->PrevOverlay != pPriv->NoOverlay))) {
+ /* We always paint the colorkey for V4L */
+ if(!pPriv->grabbedByV4L) {
+ REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
+ }
+ /* draw these */
+ pPriv->PrevOverlay = pPriv->NoOverlay;
+
+ if(!pSiSUSB->disablecolorkeycurrent) {
+ xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
+ }
+
+ }
+
+ pPriv->currentBuf ^= 1;
+
+ pPriv->videoStatus = CLIENT_VIDEO_ON;
+
+ pSiSUSB->VideoTimerCallback = SISUSBVideoTimerCallback;
+
+ return Success;
+}
+#endif
+
+static int
+SISUSBQueryImageAttributes(
+ ScrnInfoPtr pScrn,
+ int id,
+ UShort *w, UShort *h,
+ int *pitches, int *offsets
+){
+ int pitchY, pitchUV;
+ int size, sizeY, sizeUV;
+
+ if(*w < IMAGE_MIN_WIDTH) *w = IMAGE_MIN_WIDTH;
+ if(*h < IMAGE_MIN_HEIGHT) *h = IMAGE_MIN_HEIGHT;
+
+ if(*w > DummyEncoding.width) *w = DummyEncoding.width;
+ if(*h > DummyEncoding.height) *h = DummyEncoding.height;
+
+ switch(id) {
+ case PIXEL_FMT_YV12:
+ case PIXEL_FMT_I420:
+ *w = (*w + 7) & ~7;
+ *h = (*h + 1) & ~1;
+ pitchY = *w;
+ pitchUV = *w >> 1;
+ if(pitches) {
+ pitches[0] = pitchY;
+ pitches[1] = pitches[2] = pitchUV;
+ }
+ sizeY = pitchY * (*h);
+ sizeUV = pitchUV * ((*h) >> 1);
+ if(offsets) {
+ offsets[0] = 0;
+ offsets[1] = sizeY;
+ offsets[2] = sizeY + sizeUV;
+ }
+ size = sizeY + (sizeUV << 1);
+ break;
+ case PIXEL_FMT_NV12:
+ case PIXEL_FMT_NV21:
+ *w = (*w + 7) & ~7;
+ *h = (*h + 1) & ~1;
+ pitchY = *w;
+ pitchUV = *w;
+ if(pitches) {
+ pitches[0] = pitchY;
+ pitches[1] = pitchUV;
+ }
+ sizeY = pitchY * (*h);
+ sizeUV = pitchUV * ((*h) >> 1);
+ if(offsets) {
+ offsets[0] = 0;
+ offsets[1] = sizeY;
+ }
+ size = sizeY + (sizeUV << 1);
+ break;
+ case PIXEL_FMT_YUY2:
+ case PIXEL_FMT_UYVY:
+ case PIXEL_FMT_YVYU:
+ case PIXEL_FMT_RGB6:
+ case PIXEL_FMT_RGB5:
+ default:
+ *w = (*w + 1) & ~1;
+ pitchY = *w << 1;
+ if(pitches) pitches[0] = pitchY;
+ if(offsets) offsets[0] = 0;
+ size = pitchY * (*h);
+ break;
+ }
+
+ return size;
+}
+
+/*****************************************************************/
+/* OFFSCREEN SURFACES */
+/*****************************************************************/
+
+#ifdef SIS_ENABLEXV
+static int
+SISUSBAllocSurface(
+ ScrnInfoPtr pScrn,
+ int id,
+ UShort w,
+ UShort h,
+ XF86SurfacePtr surface
+)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ SISUSBPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
+ int size, depth;
+
+#ifdef TWDEBUG
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv: SISUSBAllocSurface called\n");
+#endif
+
+ if((w < IMAGE_MIN_WIDTH) || (h < IMAGE_MIN_HEIGHT))
+ return BadValue;
+ if((w > DummyEncoding.width) || (h > DummyEncoding.height))
+ return BadValue;
+
+ if(pPriv->grabbedByV4L)
+ return BadAlloc;
+
+ depth = pSiSUSB->CurrentLayout.bitsPerPixel >> 3;
+ w = (w + 1) & ~1;
+ pPriv->pitch = ((w << 1) + 63) & ~63; /* Only packed pixel modes supported */
+ size = h * pPriv->pitch;
+ pPriv->linear = SISUSBAllocateOverlayMemory(pScrn, pPriv->linear, ((size + depth - 1) / depth));
+
+ if(!pPriv->linear)
+ return BadAlloc;
+
+ pPriv->offset = pPriv->linear->offset * depth;
+
+ surface->width = w;
+ surface->height = h;
+ surface->pScrn = pScrn;
+ surface->id = id;
+ surface->pitches = &pPriv->pitch;
+ surface->offsets = &pPriv->offset;
+ surface->devPrivate.ptr = (pointer)pPriv;
+
+ close_overlay(pSiSUSB, pPriv);
+ pPriv->videoStatus = 0;
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+ pSiSUSB->VideoTimerCallback = NULL;
+ pPriv->grabbedByV4L = TRUE;
+ return Success;
+}
+
+static int
+SISUSBStopSurface(XF86SurfacePtr surface)
+{
+ SISUSBPortPrivPtr pPriv = (SISUSBPortPrivPtr)(surface->devPrivate.ptr);
+ SISUSBPtr pSiSUSB = SISUSBPTR(surface->pScrn);
+
+ if(pPriv->grabbedByV4L && pPriv->videoStatus) {
+ close_overlay(pSiSUSB, pPriv);
+ pPriv->mustwait = 1;
+ pPriv->videoStatus = 0;
+ }
+ return Success;
+}
+
+static int
+SISUSBFreeSurface(XF86SurfacePtr surface)
+{
+ SISUSBPortPrivPtr pPriv = (SISUSBPortPrivPtr)(surface->devPrivate.ptr);
+
+ if(pPriv->grabbedByV4L) {
+ SISUSBStopSurface(surface);
+ SISUSBFreeOverlayMemory(surface->pScrn);
+ pPriv->grabbedByV4L = FALSE;
+ }
+ return Success;
+}
+
+static int
+SISUSBGetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value
+)
+{
+ SISUSBPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
+
+ return SISUSBGetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
+}
+
+static int
+SISUSBSetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value
+)
+{
+ SISUSBPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);;
+
+ return SISUSBSetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
+}
+
+static int
+SISUSBDisplaySurface(
+ XF86SurfacePtr surface,
+ short src_x, short src_y,
+ short drw_x, short drw_y,
+ short src_w, short src_h,
+ short drw_w, short drw_h,
+ RegionPtr clipBoxes
+)
+{
+ ScrnInfoPtr pScrn = surface->pScrn;
+ SISUSBPortPrivPtr pPriv = (SISUSBPortPrivPtr)(surface->devPrivate.ptr);
+
+#ifdef TWDEBUG
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv: DisplaySurface called\n");
+#endif
+
+ if(!pPriv->grabbedByV4L) return Success;
+
+ pPriv->drw_x = drw_x;
+ pPriv->drw_y = drw_y;
+ pPriv->drw_w = drw_w;
+ pPriv->drw_h = drw_h;
+ pPriv->src_x = src_x;
+ pPriv->src_y = src_y;
+ pPriv->src_w = src_w;
+ pPriv->src_h = src_h;
+ pPriv->id = surface->id;
+ pPriv->height = surface->height;
+ pPriv->bufAddr[0] = surface->offsets[0];
+ pPriv->currentBuf = 0;
+ pPriv->srcPitch = surface->pitches[0];
+
+ SISUSBDisplayVideo(pScrn, pPriv);
+
+ if(pPriv->autopaintColorKey) {
+ xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
+ }
+
+ pPriv->videoStatus = CLIENT_VIDEO_ON;
+
+ return Success;
+}
+
+#define NUMOFFSCRIMAGES_300 4
+#define NUMOFFSCRIMAGES_315 5
+
+static XF86OffscreenImageRec SISUSBOffscreenImages[NUMOFFSCRIMAGES_315] =
+{
+ {
+ &SISUSBImages[0], /* YUV2 */
+ VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
+ SISUSBAllocSurface,
+ SISUSBFreeSurface,
+ SISUSBDisplaySurface,
+ SISUSBStopSurface,
+ SISUSBGetSurfaceAttribute,
+ SISUSBSetSurfaceAttribute,
+ 0, 0, /* Rest will be filled in */
+ 0,
+ NULL
+ },
+ {
+ &SISUSBImages[2], /* UYVY */
+ VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
+ SISUSBAllocSurface,
+ SISUSBFreeSurface,
+ SISUSBDisplaySurface,
+ SISUSBStopSurface,
+ SISUSBGetSurfaceAttribute,
+ SISUSBSetSurfaceAttribute,
+ 0, 0, /* Rest will be filled in */
+ 0,
+ NULL
+ }
+ ,
+ {
+ &SISUSBImages[4], /* RV15 */
+ VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
+ SISUSBAllocSurface,
+ SISUSBFreeSurface,
+ SISUSBDisplaySurface,
+ SISUSBStopSurface,
+ SISUSBGetSurfaceAttribute,
+ SISUSBSetSurfaceAttribute,
+ 0, 0, /* Rest will be filled in */
+ 0,
+ NULL
+ },
+ {
+ &SISUSBImages[5], /* RV16 */
+ VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
+ SISUSBAllocSurface,
+ SISUSBFreeSurface,
+ SISUSBDisplaySurface,
+ SISUSBStopSurface,
+ SISUSBGetSurfaceAttribute,
+ SISUSBSetSurfaceAttribute,
+ 0, 0, /* Rest will be filled in */
+ 0,
+ NULL
+ },
+ {
+ &SISUSBImages[6], /* YVYU */
+ VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
+ SISUSBAllocSurface,
+ SISUSBFreeSurface,
+ SISUSBDisplaySurface,
+ SISUSBStopSurface,
+ SISUSBGetSurfaceAttribute,
+ SISUSBSetSurfaceAttribute,
+ 0, 0, /* Rest will be filled in */
+ 0,
+ NULL
+ }
+};
+
+static void
+SISUSBInitOffscreenImages(ScreenPtr pScreen)
+{
+ int i, num;
+
+ num = NUMOFFSCRIMAGES_315;
+
+ for(i = 0; i < num; i++) {
+ SISUSBOffscreenImages[i].max_width = DummyEncoding.width;
+ SISUSBOffscreenImages[i].max_height = DummyEncoding.height;
+ SISUSBOffscreenImages[i].attributes = &SISUSBAttributes_315[0];
+ SISUSBOffscreenImages[i].num_attributes = SiSUSBCountAttributes(&SISUSBAttributes_315[0]);
+ }
+ xf86XVRegisterOffscreenImages(pScreen, SISUSBOffscreenImages, num);
+}
+#endif
+
+/*****************************************/
+/* TIMER CALLBACK */
+/*****************************************/
+
+#ifdef SIS_ENABLEXV
+static void
+SISUSBVideoTimerCallback(ScrnInfoPtr pScrn, Time now)
+{
+ SISUSBPtr pSiSUSB = SISUSBPTR(pScrn);
+ SISUSBPortPrivPtr pPriv = NULL;
+ UChar sridx, cridx;
+ Bool setcallback = FALSE;
+
+ if(!pScrn->vtSema) return;
+
+ if(pSiSUSB->adaptor) {
+ pPriv = GET_PORT_PRIVATE(pScrn);
+ if(!pPriv->videoStatus) pPriv = NULL;
+ }
+
+ if(pPriv) {
+ if(pPriv->videoStatus & TIMER_MASK) {
+ if(pPriv->videoStatus & OFF_TIMER) {
+ setcallback = TRUE;
+ if(pPriv->offTime < now) {
+ /* Turn off the overlay */
+ sridx = inSISREG(pSiSUSB, SISSR); cridx = inSISREG(pSiSUSB, SISCR);
+ close_overlay(pSiSUSB, pPriv);
+ outSISREG(pSiSUSB, SISSR, sridx); outSISREG(pSiSUSB, SISCR, cridx);
+ pPriv->mustwait = 1;
+ pPriv->videoStatus = FREE_TIMER;
+ pPriv->freeTime = now + FREE_DELAY;
+ }
+ } else if(pPriv->videoStatus & FREE_TIMER) {
+ if(pPriv->freeTime < now) {
+ SISUSBFreeOverlayMemory(pScrn);
+ pPriv->mustwait = 1;
+ pPriv->videoStatus = 0;
+ } else {
+ setcallback = TRUE;
+ }
+ }
+ }
+ }
+
+ pSiSUSB->VideoTimerCallback = (setcallback) ? SISUSBVideoTimerCallback : NULL;
+}
+#endif
+
+#else /* SIS_GLOBAL_ENABLEXV */
+
+ int i;
+
+#endif /* SIS_GLOBAL_ENABLEXV */