diff options
Diffstat (limited to 'driver/xf86-video-sisusb/src/sisusb_video.c')
-rw-r--r-- | driver/xf86-video-sisusb/src/sisusb_video.c | 2054 |
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 */ |