/*
 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sub license,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#define XVTRACE	0

#define SAVAGE_VIP 1

#if SAVAGE_VIP
/* add by peterzhu*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/ioctl.h>
#include <linux/types.h> /* for __u32,__s32....*/


#ifndef __s64
typedef __signed__ long long __s64;
typedef unsigned long long __u64;
#endif

#include "videodev2.h"
#include <linux/videodev.h>
#include <fcntl.h> /* for open flags*/

#include "Xv.h"
#include "dix.h"
#include "dixstruct.h"
#include "fourcc.h"
#include "xaalocal.h"
#include "savage_driver.h"
#include "savage_bci.h"
#include "xf86PciInfo.h"
#include "xf86i2c.h"

#else /* SAVAGE_VIP*/

#include "Xv.h"
#include "dix.h"
#include "dixstruct.h"
#include "fourcc.h"
#include "xaalocal.h"
#include "savage_driver.h"
#include "savage_bci.h"

#endif  /* SAVAGE_VIP*/

#define OFF_DELAY 			200  /* milliseconds */
#define FREE_DELAY 			60000

#define OFF_TIMER 			0x01
#define FREE_TIMER			0x02
#define CLIENT_VIDEO_ON		0x04

#define TIMER_MASK      	(OFF_TIMER | FREE_TIMER)

#define HSCALING_Shift    0
#define HSCALING_Mask     (((1L << 16)-1) << HSCALING_Shift)
#define HSCALING(w0,w1)   ((((unsigned int)(((double)w0/(double)w1) * (1 << 15))) \
                               << HSCALING_Shift) \
                           & HSCALING_Mask)

#define VSCALING_Shift    0
#define VSCALING_Mask     (((1L << 20)-1) << VSCALING_Shift)
#define VSCALING(h0,h1)   ((((unsigned int) (((double)h0/(double)h1) * (1 << 15))) \
                               << VSCALING_Shift) \
                           & VSCALING_Mask)

#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)

/* client libraries expect an encoding */
/*
  static XF86VideoEncodingRec DummyEncoding[1] =
  {
  {
  0,
  "XV_IMAGE",
  1024, 1024,
  {1, 1}
  }
  };
*/

typedef struct {
    int		brightness;	/* -128 .. 127 */
    CARD32	contrast;	/* 0 .. 255 */
    CARD32	saturation;	/* 0 .. 255 */
    int		hue;		/* -128 .. 127 */

#if SAVAGE_VIP
    Bool		double_buffer;
    unsigned char currentBuffer;
    int 		encoding;
    CARD32	frequency;
    int		volume;
    int		mute;
    Bool		autopaint_colorkey;
   
    /* add by peterzhu*/
    int  fd;
    int  usecount;
    char devname[16];
    BOOL	overlay;
    int  videoflags;
    /*
     * next fields just for double buffer video in
     * In order not to touch single buffer code for 
     * PutImage & SP,the design is sth urgly 
     */
    FBAreaPtr	sec_area;  
    int		sec_offset;
#endif

    /*
     * add by peterzhu for performance tune
     * only UPDATE_VIDEO is true, SavageAllocateMemory in SavagePutVideo,  Resetting LPB and SP
     * UPDATE_VIDEO is set according to encoding
     * only UPDATE_IMAGE is true, SavageAllocateMemory in SavagePutImage, Resetting SP
     * UPDATE_IMAGE is set according to width and height args in SavagePutImage
     */
    int		update_flags;

    FBAreaPtr	area;
    RegionRec	clip;
    CARD32	colorKey;
    CARD32	videoStatus;
    Time		offTime;
    Time		freeTime;
} SavagePortPrivRec, *SavagePortPrivPtr;
#define GET_PORT_PRIVATE(pScrn) \
   (SavagePortPrivPtr)((SAVPTR(pScrn))->adaptor->pPortPrivates[0].ptr)


#if SAVAGE_VIP

static Atom xvColorKey, xvBrightness, xvContrast, xvSaturation, xvHue,
    /* xvColor, commented by peterzhu */ 		
    xvDoubleBuffer, xvEncoding, xvVolume, xvMute,
    xvFrequency, xv_autopaint_colorkey, xv_set_defaults,
    xvTunerStatus;

static XF86VideoEncodingRec InputVideoEncodings[] ={
    {0,"XV_IMAGE",		1024,1024,{1,1}},
    {1,"pal-composite",		720, 288, {1,50}},
    {2,"pal-tuner",		720, 288, {1,50}},
    {3,"pal-svideo",		720, 288, {1,50}},
    {4,"ntsc-composite",		720, 240, {1001,60000}},
    {5,"ntsc-tuner",		720, 240, {1001,60000}},
    {6,"ntsc-svideo",		720, 240, {1001,60000}},
    {7,"secam-composite", 	720, 240, {1,50}},
    {8,"secam-tuner",		720, 240, {1,50}},
    {9,"secam-svideo",		720, 240, {1,50}},
    {10,"pal_60-composite", 	768, 288, {1,50}},
    {11,"pal_60-tuner", 		768, 288, {1,50}},
    {12,"pal_60-svideo", 		768, 288, {1,50}},
};
#define S3_NUM_ATTRIBUTES 14
static XF86AttributeRec Attributes[S3_NUM_ATTRIBUTES+1] ={
    {XvSettable		   , 0, 1, "XV_SET_DEFAULTS"},
    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
    {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
    {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
    {XvSettable | XvGettable, 0, 255, "XV_SATURATION"},
    {XvSettable | XvGettable, -180, 180, "XV_HUE"},
    {XvSettable | XvGettable, 0, 1,  "XV_DOUBLE_BUFFER"},
    {XvSettable | XvGettable, 0, 1,  "XV_AUTOPAINT_COLORKEY"},
    {XvSettable | XvGettable, 0, 12,  "XV_ENCODING"},
    {XvSettable | XvGettable, 0, -1,  "XV_FREQ"},
    {XvSettable | XvGettable, -1000, 1000,  "XV_TUNER_STATUS"},
    /* commented by peterzhu*/ 	
    /*{XvSettable | XvGettable, 0, 255,  "XV_COLOR"},*/
    {XvSettable | XvGettable, 0, 1,  "XV_MUTE"},
    {XvSettable | XvGettable, 0x01, 0x7F,  "XV_VOLUME"},
    {0,0,0,NULL}
};

static int SavagePutVideo(
    ScrnInfoPtr,
    short, short, short, short, short, short, short, short,
    RegionPtr, pointer);
static void SavageProgram7111(ScrnInfoPtr pScrn);
static struct v4l2_standard SavageToV4lStandard(SavagePortPrivPtr pPriv, int encoding);
static int SavageOpenV4l(SavagePortPrivPtr pPriv);
static void SavageCloseV4l(SavagePortPrivPtr pPriv);

#else  /* SAVAGE_VIP */

static Atom xvColorKey, xvBrightness, xvContrast, xvSaturation, xvHue;

#define S3_NUM_ATTRIBUTES 5
static XF86AttributeRec Attributes[S3_NUM_ATTRIBUTES] = {
    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
    {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
    {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
    {XvSettable | XvGettable, 0, 255, "XV_SATURATION"},
    {XvSettable | XvGettable, -180, 180, "XV_HUE"}
};

#endif /* SAVAGE_VIP */

#define S3_NUM_FORMATS 4
static XF86VideoFormatRec Formats[S3_NUM_FORMATS] = {
    {8, PseudoColor},  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
};

/*
 * For completeness sake, here is a cracking of the fourcc's I support.
 *
 * YUY2, packed 4:2:2, byte order: Y0 U0 Y1 V0  Y2 U2 Y3 V2
 * UYVY, packed 4:2:2, byte order: U0 Y0 V0 Y1  U2 Y2 V2 Y3
 * Y211, packed 2:1:1, byte order: Y0 U0 Y2 V0  Y4 U2 Y6 V2
 * YV12, planar 4:1:1, Y plane HxW, V plane H/2xW/2, U plane H/2xW/2
 * I420, planar 4:1:1, Y plane HxW, U plane H/2xW/2, V plane H/2xW/2
 * (I420 is also known as IYUV)
 */
#define FOURCC_RV16	0x36315652
#define FOURCC_RV15	0x35315652
#define FOURCC_Y211	0x31313259
#define FOURCC_UTIL 0x7fffffff 
static XF86ImageRec Images[] = {
    XVIMAGE_YUY2,
    XVIMAGE_YV12,
    XVIMAGE_I420,
    XVIMAGE_UYVY,
    {
        FOURCC_RV16,
        XvRGB,
        LSBFirst,
        {'R','V','1','5',
         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
        16,
        XvPacked,
        1,
        15, 0x001F, 0x03E0, 0x7C00,
        0, 0, 0,
        0, 0, 0,
        0, 0, 0,
        {'R','V','B',0,
         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
        XvTopToBottom
    },
    {
        FOURCC_RV15,
        XvRGB,
        LSBFirst,
        {'R','V','1','6',
         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
        16,
        XvPacked,
        1,
        16, 0x001F, 0x07E0, 0xF800,
        0, 0, 0,
        0, 0, 0,
        0, 0, 0,
        {'R','V','B',0,
         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
        XvTopToBottom
    },
    {
        FOURCC_Y211,
        XvYUV,
        LSBFirst,
        {'Y','2','1','1',
         0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71},
        6,
        XvPacked,
        3,
        0, 0, 0, 0 ,
        8, 8, 8,
        2, 4, 4,
        1, 1, 1,
        {'Y','U','Y','V',
         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
        XvTopToBottom
    },
    { 
        FOURCC_UTIL, 
        XvYUV, 
        LSBFirst, 
        {'Y','U','Y','2', 
         0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, 
        16, 
        XvPacked, 
        1, 
        0, 0, 0, 0, 
        8, 8, 8, 
        1, 2, 2, 
        1, 1, 1, 
        {'Y','U','Y','V', 
         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 
        XvTopToBottom 
    }
    
};
#define S3_NUM_IMAGES (sizeof(Images)/sizeof(Images[0]))

/* add by peterzhu for correct calling V4lOpen & V4lClose*/
#define VIDEO_OFF 			0     /* really off*/
#define VIDEO_ON  			1     /* video on */
#define VIDEO_RECLIP		2     /* temporarily off, window clipping changes*/	      

#define	DEFAULT_NORM		1

/* add by peterzhu for performance tune*/
#define UPDATE_VIDEO		1
#define	UPDATE_IMAGE		2
   

void SavageInitVideo(ScreenPtr pScreen);
void SavageResetVideo(ScrnInfoPtr pScrn);

static int SavageSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
static int SavageGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
static void SavageQueryBestSize(
    ScrnInfoPtr, Bool,
    short, short, short, short, unsigned int *, unsigned int *, pointer);
static int SavageQueryImageAttributes(
    ScrnInfoPtr,
    int, unsigned short *, unsigned short *,  int *, int *);
static int SavagePutImage(
    ScrnInfoPtr,
    short, short, short, short, short, short, short, short,
    int, unsigned char*, short, short, Bool, RegionPtr, pointer);
static void SavageStopVideo(ScrnInfoPtr, pointer, Bool);

static XF86VideoAdaptorPtr SavageSetupImageVideo(ScreenPtr);

void (*SavageInitStreams)(ScrnInfoPtr pScrn) = NULL;
void SavageInitStreamsOld(ScrnInfoPtr pScrn);
void SavageInitStreamsNew(ScrnInfoPtr pScrn);

static FBAreaPtr SavageAllocateMemory(
    ScrnInfoPtr pScrn,
    FBAreaPtr area,
    int numlines);

static void (*SavageSetColorKey)(ScrnInfoPtr pScrn) = NULL;
static void SavageSetColorKeyOld(ScrnInfoPtr pScrn);
static void SavageSetColorKeyNew(ScrnInfoPtr pScrn);

static void (*SavageSetColor)(ScrnInfoPtr pScrn ) = NULL;
static void SavageSetColorOld(ScrnInfoPtr pScrn );
static void SavageSetColorNew(ScrnInfoPtr pScrn );
static void SavageClipVideo(
    BoxPtr dst, 
    INT32 *x1, INT32 *x2, 
    INT32 *y1, INT32 *y2,
    BoxPtr extents,  /* extents of the clip region */
    INT32 width, INT32 height);

static void (*SavageDisplayVideo)(
    ScrnInfoPtr pScrn, int id, int offset,
    short width, short height, int pitch,
    int x1, int y1, int x2, int y2,
    BoxPtr dstBox,
    short src_w, short src_h,
    short drw_w, short drw_h,
    Bool double_buffer
    ) = NULL;
static void SavageDisplayVideoOld(
    ScrnInfoPtr pScrn, int id, int offset,
    short width, short height, int pitch,
    int x1, int y1, int x2, int y2,
    BoxPtr dstBox,
    short src_w, short src_h,
    short drw_w, short drw_h,
    Bool double_buffer);
static void SavageDisplayVideoNew(
    ScrnInfoPtr pScrn, int id, int offset,
    short width, short height, int pitch,
    int x1, int y1, int x2, int y2,
    BoxPtr dstBox,
    short src_w, short src_h,
    short drw_w, short drw_h,
    Bool double_buffer);

static Bool RegionsEqual(RegionPtr A, RegionPtr B);
static unsigned int GetBlendForFourCC(int id);
static void SavageCopyPlanarDataOld(
    ScrnInfoPtr pScrn,
    unsigned char *src1, /* Y */
    unsigned char *src2, /* V */
    unsigned char *src3, /* U */
    unsigned char *dst1,
    int srcPitch, int srcPitch2,
    int dstPitch,
    int h,int w);
static void SavageCopyData(
    unsigned char *src,unsigned char *dst,
    int srcPitch,int dstPitch,
    int h,int w);
static void
SavageCopyPlanarData(
    unsigned char *src1, /* Y */
    unsigned char *src2, /* V */
    unsigned char *src3, /* U */
    unsigned char *dst1,
    int srcPitch,int srcPitch2,int dstPitch,
    int h,int w);

void SavageStreamsOn(ScrnInfoPtr pScrn, int id);
void SavageStreamsOff(ScrnInfoPtr pScrn);

/* offscreen surface functions */
static void SavageInitOffscreenImages(ScreenPtr);
static int  SavageAllocateSurface(
    ScrnInfoPtr pScrn,
    int id,
    unsigned short w, 	
    unsigned short h,
    XF86SurfacePtr surface);
static int SavageFreeSurface(XF86SurfacePtr surface);
static int SavageDisplaySurface(
    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);
static int SavageStopSurface(XF86SurfacePtr surface);
static int SavageGetSurfaceAttribute(
    ScrnInfoPtr pScrn,
    Atom attribute,
    INT32 *value);
static int SavageSetSurfaceAttribute(
    ScrnInfoPtr pScrn,
    Atom attribute,
    INT32 value);

static void OverlayParamInit(ScrnInfoPtr pScrn);
static void OverlayTwisterInit(ScrnInfoPtr pScrn);
static void InitStreamsForExpansion(SavagePtr psav);

Bool SavageDVIInit(ScrnInfoPtr);


void SavageInitVideo(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
    XF86VideoAdaptorPtr newAdaptor = NULL;
    SavagePtr psav = SAVPTR(pScrn);
    int num_adaptors;

    newAdaptor = SavageSetupImageVideo(pScreen);
    SavageInitOffscreenImages(pScreen);

    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
        ||(psav->Chipset == S3_SUPERSAVAGE)
        ||(psav->Chipset == S3_SAVAGE2000)) {
        SavageInitStreams = SavageInitStreamsNew;
        SavageSetColor = SavageSetColorNew;
        SavageSetColorKey = SavageSetColorKeyNew;
        SavageDisplayVideo = SavageDisplayVideoNew;
    }
    else {
        /* Since newAdaptor is still NULL, these are still disabled for now. */
        SavageInitStreams = SavageInitStreamsOld;
        SavageSetColor = SavageSetColorOld;
        SavageSetColorKey = SavageSetColorKeyOld;
        SavageDisplayVideo = SavageDisplayVideoOld;
    }
 
    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
 
    if (newAdaptor) {
        if (!num_adaptors) {
            num_adaptors = 1;
            adaptors = &newAdaptor;
        } else {
            /* need to free this someplace */
            newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
            if (newAdaptors) {
                memcpy(newAdaptors, adaptors, num_adaptors * 
                       sizeof(XF86VideoAdaptorPtr));
                newAdaptors[num_adaptors] = newAdaptor;
                adaptors = newAdaptors;
                num_adaptors++;
            }
        }
    }
 
    if (num_adaptors)
        xf86XVScreenInit(pScreen, adaptors, num_adaptors);

    if (newAdaptors)
        xfree(newAdaptors);

    if (newAdaptor)  {
        SavageInitStreams(pScrn);
    }
}


void SavageResetVideo(ScrnInfoPtr pScrn)
{
    /*
     * SavageSetColorKey(pScrn);
     * SavageSetColor(pScrn);
     */
    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
    xvContrast   = MAKE_ATOM("XV_CONTRAST");
    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
    xvHue        = MAKE_ATOM("XV_HUE");
    xvSaturation = MAKE_ATOM("XV_SATURATION");
    
#if SAVAGE_VIP
    /* commented by peterzhu*/
    /*xvColor        = MAKE_ATOM("XV_COLOR");*/
    xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
    xvEncoding     = MAKE_ATOM("XV_ENCODING");
    xvTunerStatus  = MAKE_ATOM("XV_TUNER_STATUS");
    xvFrequency    = MAKE_ATOM("XV_FREQ");
    xvVolume       = MAKE_ATOM("XV_VOLUME");
    xvMute         = MAKE_ATOM("XV_MUTE");
    xv_autopaint_colorkey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
    xv_set_defaults = MAKE_ATOM("XV_SET_DEFAULTS");
#endif
}


/*
 * This indicates that the driver should take a subsection src_w by src_h
 * at location (src_x,src_y) from the video stream and direct it into the
 * rectangle drw_w by drw_h at location (drw_x,drw_y) on the screen, scaling
 * as necessary.the source of the video is stored in a system memory buffer
 * at buf.The data is in the format indicated by the image descriptor and
 * represents a source of size width by height. If sync is TRUE the driver
 * should not return from this function until it is through reading the data
 * from buf. Returning when sync is TRUE indicates that it is safe for the
 * data at buf to be replaced, freed, or modifie Due to the large variations
 * in capabilities of the various hardware expected to be used with this
 * extension, it is not expected that all hardware will be able to do this
 * exactly as described. In that case the driver should just do ``the best it can,''
 * scaling as closely to the target rectangle as it can without rendering
 * outside of it. In the worst case, the driver can opt to just not turn on the video.
*/
static int
SavagePutImage(
    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, unsigned char * buf,
    short width, short height,
    Bool sync,
    RegionPtr clipBoxes, pointer data)
{
    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
    SavagePtr psav = SAVPTR(pScrn);
    INT32 x1, x2, y1, y2;
    unsigned char *dst_start;
    int offset, offsetV=0, offsetU=0;
    int srcPitch, srcPitch2=0, dstPitch;
    int top, left, npixels, nlines;
    BoxRec dstBox;
    static short last_width, last_height;

    if (id == FOURCC_UTIL) {
        return SavageDoUtilCall(pScrn,(char *)buf);
    }
    
    
    /* Clip */
    x1 = src_x;
    x2 = src_x + src_w;
    y1 = src_y;
    y2 = src_y + src_h;

    dstBox.x1 = drw_x;
    dstBox.x2 = drw_x + drw_w;
    dstBox.y1 = drw_y;
    dstBox.y2 = drw_y + drw_h;

    SavageClipVideo(
        &dstBox, &x1, &x2, &y1, &y2,
        REGION_EXTENTS(pScreen, clipBoxes), width, height);

    if ((x1 >= x2) || (y1 >= y2))
        return Success;

    drw_w = dstBox.x2 - dstBox.x1;
    drw_h = dstBox.y2 - dstBox.y1;
    src_w = (x2 - x1) >> 16;
    src_h = (y2 - y1) >> 16;
    
    dstBox.x1 -= pScrn->frameX0;
    dstBox.x2 -= pScrn->frameX0;
    dstBox.y1 -= pScrn->frameY0;
    dstBox.y2 -= pScrn->frameY0;

    top = y1 >> 16;
    left = (x1 >> 16) & ~1;
    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
    
    switch (id) {
        case FOURCC_Y211:		/* Y211 */
            xf86Msg(X_INFO,"FOURCC_Y211");
            srcPitch = width;
            break;
        case FOURCC_YV12:		/* YV12 */
            xf86Msg(X_INFO,"FOURCC_YV12");
            srcPitch = (width + 3) & ~3;
            srcPitch2 = ((width >> 1) + 3) & ~3;            
            offsetV = srcPitch * height;
            offsetU = offsetV + (srcPitch2 * (height >> 1)) ;
            break;
        case FOURCC_I420:
            xf86Msg(X_INFO,"FOURCC_I420");
            srcPitch = (width + 3) & ~3;
            srcPitch2 = ((width >> 1) + 3) & ~3;            
            offsetU = srcPitch * height;
            offsetV = offsetU + (srcPitch2 * (height >> 1));
            break;
        case FOURCC_RV15:		/* RGB15 */
        case FOURCC_RV16:		/* RGB16 */
        case FOURCC_YUY2:		/* YUY2 */
        case FOURCC_UYVY:		/* YUY2 */
        default:
            srcPitch = (width << 1);
            break;
    }

    /* prepare for copy data from buf to offscreen */
    if (pPriv->videoflags == VIDEO_OFF) {
        last_width = 0;
        last_height = 0;
        pPriv->videoflags = VIDEO_ON;
    }

    dstPitch = ((width << 1) + 15) & ~15;
    if ((last_width != width) || (last_height != height)) {
        int new_h;
        
        /* if client chang the buffer size,we should resize/realloc the buffer */
    	last_width = width;
    	last_height = height;
        /* allocate two buffers to do pixel transfer */       
        new_h = 2 * (((dstPitch * height) + psav->lDelta - 1) / (psav->lDelta));
        if (!(pPriv->area = SavageAllocateMemory(pScrn, pPriv->area, new_h)))
            return BadAlloc;
        pPriv->update_flags |= UPDATE_IMAGE;
    }
    
    offset = pPriv->area->box.y1 * psav->lDelta;
    dst_start = (unsigned char *)(((long)(psav->FBBase + offset + 0xf))&~0xf);
    
    switch (id) {
        case FOURCC_YV12:		/* YV12 */
        case FOURCC_I420:
            nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
            if (S3_SAVAGE4_SERIES(psav->Chipset)) {
                SavageCopyPlanarDataOld(
                    pScrn,
                    buf + (top * srcPitch) + left,
                    buf + offsetV + ((top >> 1) * srcPitch2) + (left >> 1),
                    buf + offsetU + ((top >> 1) * srcPitch2) + (left >> 1),
                    dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
            }
            else {
                SavageCopyPlanarData(
                    buf + (top * srcPitch) + left,
                    buf + offsetV + ((top >> 1) * srcPitch2) + (left >> 1),
                    buf + offsetU + ((top >> 1) * srcPitch2) + (left >> 1),
                    dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
            }
            break;
        case FOURCC_Y211:		/* Y211 */
        case FOURCC_RV15:		/* RGB15 */
        case FOURCC_RV16:		/* RGB16 */
        case FOURCC_YUY2:		/* YUY2 */
        default:
            buf += (top * srcPitch) + (left << 1);
            nlines = ((y2 + 0xffff) >> 16) - top;
            SavageCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
            break;
    }  

    /* update cliplist */
    if (!RegionsEqual(&pPriv->clip, clipBoxes)) {
        REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
        /* draw these */
        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
    }
   
    SavageDisplayVideo(pScrn, id, offset, width, height, dstPitch,
                       x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, FALSE);

    pPriv->videoStatus = CLIENT_VIDEO_ON;
    pPriv->update_flags &= ~UPDATE_IMAGE;
    return Success;
}


static void 
SavageStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
{
    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
    SavagePtr psav = SAVPTR(pScrn);
    int zero = 0;

    if (pPriv->videoflags == VIDEO_OFF)  {
        xf86Msg(X_ERROR,"Xv Stop Video called with video already off\n");
        return; 
    }

    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);   

    if (shutdown) {
        SavageStreamsOff(pScrn);
        if (psav->Chipset==S3_TWISTER) {
            /*updated by peterzhu*/		
            if (!psav->v4l_videoin)
            	OUTREG32(0xFF00, 0x00000000);
            else {
                if (pPriv->fd != -1){
	                ioctl(pPriv->fd, VIDIOC_PREVIEW, &zero);
        	        SavageCloseV4l(pPriv);
                }
            }
        }
        OUTREG32(0x8190, 0x00000000);
        if (pPriv->area) {
            xf86FreeOffscreenArea(pPriv->area);
            pPriv->area = NULL;
        }
        /*add by peterzhu*/
        if (pPriv->double_buffer){
            if (pPriv->sec_area){
                xf86FreeOffscreenArea(pPriv->sec_area);
                pPriv->sec_area = NULL;
            }
        }	
        pPriv->videoflags = VIDEO_OFF;
        pPriv->videoStatus = 0;
    } else {
        if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
            pPriv->videoStatus |= OFF_TIMER;
            pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
        }
        /*add by peterzhu*/
        pPriv->videoflags = VIDEO_RECLIP;
    }
}

/*
 * A port may have particular attributes such as hue, saturation,
 * brightness or contrast. Xv clients set and get these attribute
 * values by sending attribute strings (Atoms) to the server. Such
 * requests end up at these driver functions. It is recommended
 * that the driver provide at least the following attributes mentioned
 * in the Xv client library docs: 
 * 
 *      XV_ENCODING
 *      XV_HUE
 *      XV_SATURATION
 *      XV_BRIGHTNESS
 *      XV_CONTRAST 
 * but the driver may recognize as many atoms as it wishes. If a
 * requested attribute is unknown by the driver it should return BadMatch.
 * XV_ENCODING is the attribute intended to let the client specify which
 * video encoding the particular port should be using (see the description
 * of XF86VideoEncodingRec below). If the requested encoding is unsupported,
 * the driver should return XvBadEncoding. If the value lies outside the
 * advertised range BadValue may be returned. Success should be returned
 * otherwise.
*/
static int
SavageGetPortAttribute(
    ScrnInfoPtr pScrn,
    Atom attribute,INT32 *value,pointer data)
{
    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;

    if(attribute == xvColorKey) {
        *value = pPriv->colorKey;
    }
    else if(attribute == xvBrightness) {
        *value = pPriv->brightness;
    }
    else if(attribute == xvContrast) {
        *value = pPriv->contrast;
    }
    else if(attribute == xvHue) {
        *value = pPriv->hue;
    }
    else if(attribute == xvSaturation) {
        *value = pPriv->saturation;
    }
#if SAVAGE_VIP
    else if(attribute == xvDoubleBuffer) {
        *value = pPriv->double_buffer ? 1:0;
    } else if(attribute == xvEncoding) {
        *value = pPriv->encoding;
    } else if(attribute == xvFrequency) {
        pPriv->frequency=1000;
        *value = pPriv->frequency;
    } else if(attribute == xvMute) {
        pPriv->mute=1;
        *value = pPriv->mute;
    } else if(attribute == xvVolume)  {
        pPriv->volume=0;
        *value = pPriv->volume;
    } else  {
        fprintf(stderr,"GetAttribute:%d\n",attribute);
    }
#else
    else return BadMatch;
#endif

    return Success;
}

static int 
SavageSetPortAttribute(
    ScrnInfoPtr pScrn, 
    Atom attribute,
    INT32 value,
    pointer data)
{
    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
    SavagePtr psav = SAVPTR(pScrn);

    if (attribute == xvColorKey) {
        pPriv->colorKey = value;
        SavageSetColorKey(pScrn);
        REGION_EMPTY(pScrn->pScreen, &pPriv->clip);   
    } 
    else if (attribute == xvBrightness) {
        if ((value < -128) || (value > 127))
            return BadValue;
        pPriv->brightness = value;
        SavageSetColor(pScrn);
    }
    else if (attribute == xvContrast) {
        if ((value < 0) || (value > 255))
            return BadValue;
        pPriv->contrast = value;
        SavageSetColor(pScrn);
    }
    else if (attribute == xvSaturation) {
        if ((value < 0) || (value > 255))
            return BadValue;
        pPriv->saturation = value;
        SavageSetColor(pScrn);
    }
    else if (attribute == xvHue) {
        if ((value < -180) || (value > 180))
            return BadValue;
        pPriv->hue = value;
        SavageSetColor(pScrn);
    }
#if SAVAGE_VIP
    else if (attribute == xvEncoding)
    {
        INT32 temp;
    	struct v4l2_standard standard;
    	
    	if (value == 0 || value >= 
            sizeof(InputVideoEncodings)/sizeof(InputVideoEncodings[0]))
            return BadValue;
        temp = pPriv->encoding;/* bak for v4l use next*/
    	pPriv->encoding = value;

    	pPriv->update_flags |= UPDATE_VIDEO; 

    	if (psav->v4l_videoin) {
    	    if (SavageOpenV4l(pPriv)) {
                pPriv->encoding = temp;
                pPriv->update_flags &= ~UPDATE_VIDEO;
    	    	return Success;
            }
    	    standard = SavageToV4lStandard(pPriv,value);
    	    if (ioctl(pPriv->fd, VIDIOC_S_STD, &standard)<0){
    	      	pPriv->encoding = temp;

    	      	pPriv->update_flags &= ~UPDATE_VIDEO;
    	    	SavageCloseV4l(pPriv);
    	    	return BadValue;
    	    }
    	    SavageCloseV4l(pPriv);
    	}
    }
    else if (attribute == xvFrequency) {
        pPriv->frequency = value;
    } else if (attribute == xvMute){
        pPriv->mute = value;
    } else if (attribute == xvVolume) {
        pPriv->volume = value;
    } 
#else
    else return BadMatch;
#endif
    
    return Success;
}



/*
 * QueryBestSize provides the client with a way to query what
 * the destination dimensions would end up being if they were
 * to request that an area vid_w by vid_h from the video stream
 * be scaled to rectangle of drw_w by drw_h on the screen.
 * Since it is not expected that all hardware will be able to
 * get the target dimensions exactly, it is important that the
 * driver provide this function.
 */
static void
SavageQueryBestSize(
    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)
{
    /* What are the real limits for the Savage? */
    *p_w = drw_w;
    *p_h = drw_h; 

    if (*p_w > 16384) *p_w = 16384;
}



static int
SavageQueryImageAttributes(
    ScrnInfoPtr pScrn,
    int id,
    unsigned short *w, unsigned short *h,
    int *pitches, int *offsets)
{
    int size, tmp;

    if (*w > 1024)
        *w = 1024;
    if (*h > 1024)
        *h = 1024;

    *w = (*w + 1) & ~1;
    if (offsets)
        offsets[0] = 0;

    switch (id) {
        case FOURCC_IA44:
            if (pitches)
                pitches[0]=*w;
            size=(*w)*(*h);
            break;

        case FOURCC_Y211:
            size = *w << 2;
            if (pitches) pitches[0] = size;
            size *= *h;
            break;
        case FOURCC_YV12:
        case FOURCC_I420:
            *h = (*h + 1) & ~1;
            size = (*w + 3) & ~3;
            if (pitches)
                pitches[0] = size;
            size *= *h;
            if (offsets)
                offsets[1] = size;
            tmp = ((*w >> 1) + 3) & ~3;
            if (pitches)
                pitches[1] = pitches[2] = tmp;
            tmp *= (*h >> 1);
            size += tmp;
            if (offsets)
                offsets[2] = size;
            size += tmp;
            break;
        case FOURCC_RV15:		/* RGB15 */
        case FOURCC_RV16:		/* RGB16 */
        case FOURCC_YUY2:
        case FOURCC_UYVY:
        default:
            size = *w << 1;
            if (pitches)
                pitches[0] = size;
            size *= *h;
            break;
    }

    return size;
}


static XF86VideoAdaptorPtr
SavageSetupImageVideo(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    SavagePtr psav = SAVPTR(pScrn);
    XF86VideoAdaptorPtr adapt;
    SavagePortPrivPtr pPriv;
    struct v4l2_capability 	cap;
    struct v4l2_standard 	standard;

    if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec)
                          + sizeof(SavagePortPrivRec)
                          + sizeof(DevUnion))))
        return NULL;

    adapt->name	= "Savage Streams Engine";
    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
    adapt->nFormats = S3_NUM_FORMATS;
    adapt->pFormats = Formats;
    adapt->nPorts = 1;
    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
    pPriv = (SavagePortPrivPtr)(&adapt->pPortPrivates[1]);
    adapt->pPortPrivates[0].ptr	= (pointer)(pPriv);
    adapt->pAttributes = Attributes;
    adapt->nImages = S3_NUM_IMAGES;
    adapt->nAttributes = S3_NUM_ATTRIBUTES;
    adapt->pImages = Images;

    adapt->PutStill	= NULL;
    adapt->GetVideo	= NULL;
    adapt->GetStill	= NULL;
    adapt->StopVideo = SavageStopVideo;
    adapt->SetPortAttribute	= SavageSetPortAttribute;
    adapt->GetPortAttribute	= SavageGetPortAttribute;
    adapt->QueryBestSize = SavageQueryBestSize;
    adapt->PutImage 	= SavagePutImage;
    adapt->QueryImageAttributes	= SavageQueryImageAttributes;
    
#if SAVAGE_VIP
    adapt->type = (XvWindowMask | XvInputMask | XvImageMask
                   | XvVideoMask);
    adapt->nEncodings = 13;
    adapt->pEncodings = InputVideoEncodings;
    if (psav->Chipset == S3_TWISTER) {
        adapt->PutVideo	= SavagePutVideo;
    } else  {
        adapt->PutVideo	= NULL;
    }
    
	pPriv->double_buffer = psav->double_buffer;
    pPriv->frequency = 1000;
    pPriv->encoding = 1;
    pPriv->volume = 0x01;
    pPriv->mute = TRUE;
    pPriv->autopaint_colorkey = TRUE;
        
    if (S3_TWISTER==psav->Chipset) {
        pPriv->fd = -1;	
    	if (!psav->v4l_videoin && psav->SAA7111) 
    		SavageProgram7111(pScrn);
    	if (psav->v4l_videoin) {
    		sprintf(pPriv->devname, "/dev/video%d", psav->v4l_devnum);
            ErrorF("open %s\n", pPriv->devname); 
            /*	#define O_NOIO 0x00000200  */
    		pPriv->fd = open(pPriv->devname, O_NOIO, 0);
            if (-1 == pPriv->fd) {
	    	    ErrorF("%s can't open correctly\n",pPriv->devname);
	    	    /*pPriv->overlay = FALSE;*/
	    	} else {
                ErrorF("%s opened successfully\n", pPriv->devname);	
	    	    if (-1 == ioctl(pPriv->fd,VIDIOC_QUERYCAP,&cap) ||
	    			(V4L2_TYPE_CAPTURE != cap.type ) ||
	    			0 == (cap.flags & V4L2_FLAG_PREVIEW)) {
                    /*pPriv->overlay = FALSE;*/
	    	     	ErrorF("%s: not a capture device or no overlay support \n",pPriv->devname);
	       	    } else {
			
                    ErrorF("%s querycap successfully\n", pPriv->devname);	
	       	    	/*pPriv->overlay = TRUE;*/
	       	    	standard = SavageToV4lStandard(pPriv, DEFAULT_NORM);
	    	    	ioctl(pPriv->fd, VIDIOC_S_STD, &standard);
	    	    		
	    	    }
	    	    close(pPriv->fd);
	    	    pPriv->fd = -1;
	    	}
    	}
    }
    
#else
    adapt->type	= XvWindowMask | XvInputMask | XvImageMask;
    adapt->nEncodings = 1;
    adapt->pEncodings = DummyEncoding;
    adapt->PutVideo	=NULL;
    
#endif

    /* add by peterzhu*/
    pPriv->update_flags = UPDATE_VIDEO | UPDATE_IMAGE;	
    pPriv->videoflags = VIDEO_OFF;	

    pPriv->colorKey =
        (1 << pScrn->offset.red) |
        (1 << pScrn->offset.green) |
        (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
    pPriv->videoStatus = 0;
    pPriv->brightness = 0;
    pPriv->contrast = 128;
    pPriv->saturation = 128;
    pPriv->hue = 0;
    /* gotta uninit this someplace */
    REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
    
    SavageResetVideo(pScrn);
    psav->adaptor = adapt;

#if 0
    psav->BlockHandler = pScreen->BlockHandler;
    pScreen->BlockHandler = SavageBlockHandler;
#endif

    return adapt;
}

void SavageInitStreamsOld(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    unsigned char jStreamsControl,byte;
    unsigned long fWidth,fHeight;
    unsigned long lFormat = -1;

    /* Unlock extended registers. */
    UnLockExtRegs();

    OUTREG8(CRT_ADDRESS_REG,EXT_MISC_CTRL2 );
    jStreamsControl = INREG8(CRT_DATA_REG) | 0x0c;
    /* streams needs to turned on/off during VBLANK. */
    VerticalRetraceWait();
    /* Fire up streams! */
    OUTREG16(CRT_ADDRESS_REG,(jStreamsControl << 8) | EXT_MISC_CTRL2);

    OUTREG8(CRT_ADDRESS_REG,0x90);
    byte = (INREG8(CRT_DATA_REG) & ~0x48) | 0x20;
    OUTREG8(CRT_DATA_REG,byte);

    
    fWidth = pScrn->virtualX;
    fHeight = pScrn->virtualY;

    OUTREG32(PSTREAM_FBADDR0_REG, 0);
    OUTREG32(PSTREAM_FBADDR1_REG, 0);
    OUTREG32(PSTREAM_START_REG, 0x00010001);
    OUTREG32(PSTREAM_WINDOW_SIZE_REG, WH(fWidth,fHeight));
    
    if (!psav->bTiled) {
        OUTREG32(PRI_STREAM_STRIDE,
                 (((psav->lDelta * 2) << 16) & 0x3FFFE000) |
                 (psav->lDelta & 0x00001fff));
    }
    else if (pScrn->bitsPerPixel == 16) {
        /* Scanline-length-in-bytes/128-bytes-per-tile * 256 Qwords/tile */
        OUTREG32(PRI_STREAM_STRIDE,
                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
                 | 0x80000000 | (psav->lDelta & 0x00001fff));
    }
    else if (pScrn->bitsPerPixel == 32) {
        OUTREG32(PRI_STREAM_STRIDE,
                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
                 | 0xC0000000 | (psav->lDelta & 0x00001fff));
    }
    OUTREG32(PSTREAM_FBSIZE_REG, fHeight * fWidth * (pScrn->bitsPerPixel >> 3));
    
    switch (pScrn->bitsPerPixel) {
        case 8:
            lFormat = 0;
            break;
        case 16:
            lFormat = 0x5000000;
            break;
        case 32:
            lFormat = 0x7000000;
            break;
    }
    OUTREG32(PSTREAM_CONTROL_REG,lFormat);
    
    OUTREG32(FIFO_CONTROL, 0x18ffeL);

    OUTREG32(COL_CHROMA_KEY_CONTROL_REG, 0);
    OUTREG32(SSTREAM_CONTROL_REG, 0);
    OUTREG32(CHROMA_KEY_UPPER_BOUND_REG, 0);
    OUTREG32(SSTREAM_STRETCH_REG, 0);
    OUTREG32(COLOR_ADJUSTMENT_REG, 0);
    OUTREG32(BLEND_CONTROL_REG, 0x1000000);
    /* updated by peterzhu,original define is DOUBLE_BUFFER_REG*/
    OUTREG32(MULTIPLE_BUFFER_REG, 0);
    
    OUTREG32(SSTREAM_FBADDR0_REG, 0);
    OUTREG32(SSTREAM_FBADDR1_REG, 0);
    OUTREG32(SSTREAM_FBADDR2_REG, 0);
    OUTREG32(SSTREAM_FBSIZE_REG, 0);
    OUTREG32(SSTREAM_STRIDE_REG, 0);
    OUTREG32(K1_VSCALE_REG, 0);
    OUTREG32(K2_VSCALE_REG, 0);
    OUTREG32(DDA_VERT_REG, 0);

    OUTREG32(SSTREAM_START_REG, 0x00010001);
    OUTREG32(SSTREAM_WINDOW_SIZE_REG, 0x00000001);

    if (S3_MOBILE_TWISTER_SERIES(psav->Chipset) &&
        psav->FPExpansion) {
        OverlayTwisterInit(pScrn);
    }
    psav->videoFlags |= VF_STREAMS_ON;
}


void SavageInitStreamsNew(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);

    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
        && !psav->TvOn) {
        OverlayParamInit(pScrn);
    }

    /* Primary stream reflects the frame buffer. */
    OUTREG32(PRI_STREAM_FBUF_ADDR0, pScrn->fbOffset);
    if (!psav->bTiled) {
        OUTREG32(PRI_STREAM_STRIDE,
                 (((psav->lDelta * 2) << 16) & 0x3FFFE000) |
                 (psav->lDelta & 0x00001fff));
    }
    else if (pScrn->bitsPerPixel == 16) {
        /* Scanline-length-in-bytes/128-bytes-per-tile * 256 Qwords/tile */
        OUTREG32(PRI_STREAM_STRIDE,
                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
                 | 0x80000000 | (psav->lDelta & 0x00001fff));
    }
    else if (pScrn->bitsPerPixel == 32) {
        OUTREG32(PRI_STREAM_STRIDE,
                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
                 | 0xC0000000 | (psav->lDelta & 0x00001fff));
    }
    OUTREG32(PSTREAM_FBSIZE_REG,
             pScrn->virtualX * pScrn->virtualY * (pScrn->bitsPerPixel >> 3));
    
    OUTREG32(SEC_STREAM_CKEY_LOW, 0);
    OUTREG32(SEC_STREAM_CKEY_UPPER, 0);
    OUTREG32(SEC_STREAM_HSCALING, 0);
    OUTREG32(SEC_STREAM_VSCALING, 0);
    OUTREG32(BLEND_CONTROL, 0);
    OUTREG32(SEC_STREAM_FBUF_ADDR0, 0);
    OUTREG32(SEC_STREAM_FBUF_ADDR1, 0);
    OUTREG32(SEC_STREAM_FBUF_ADDR2, 0);
    OUTREG32(SEC_STREAM_WINDOW_START, 0);
    OUTREG32(SEC_STREAM_WINDOW_SZ, 0);
    /* OUTREG32(SEC_STREAM_BUFFERSIZE, 0); */
    OUTREG32(SEC_STREAM_TILE_OFF, 0);
    OUTREG32(SEC_STREAM_OPAQUE_OVERLAY, 0);
    OUTREG32(SEC_STREAM_STRIDE, 0);

    /* These values specify brightness, contrast, saturation and hue. */
    OUTREG32(SEC_STREAM_COLOR_CONVERT1, 0x0000C892);
    OUTREG32(SEC_STREAM_COLOR_CONVERT2, 0x00039F9A);
    OUTREG32(SEC_STREAM_COLOR_CONVERT3, 0x01F1547E);
}

static FBAreaPtr
SavageAllocateMemory(
    ScrnInfoPtr pScrn,
    FBAreaPtr area,
    int numlines)
{
    SavagePtr psav = SAVPTR(pScrn);
    ScreenPtr pScreen;
    FBAreaPtr new_area;

    if (area) {
        /* if area is already allocated,resize it */        
        if((area->box.y2 - area->box.y1) >= numlines)
            return area;

        if (xf86ResizeOffscreenArea(area, psav->cxMemory, numlines))
            return area;

        /* resize failed,free it then allocate it again*/
        xf86FreeOffscreenArea(area);
    }

    pScreen = screenInfo.screens[pScrn->scrnIndex];

    xf86PurgeUnlockedOffscreenAreas(pScreen);
    new_area = xf86AllocateOffscreenArea(pScreen, psav->cxMemory, 
                                         numlines, 0, NULL, NULL, NULL);

    if (!new_area) {
        int max_w, max_h;

        xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
                                      FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);
	
        if ((max_w < psav->cxMemory) || (max_h < numlines))
            return NULL;

        xf86PurgeUnlockedOffscreenAreas(pScreen);
        new_area = xf86AllocateOffscreenArea(pScreen, psav->cxMemory,
                                             numlines, 0, NULL, NULL, NULL);
    }

    return new_area;
}



void SavageSetColorKeyOld(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
    int red, green, blue;

    /* Here, we reset the colorkey and all the controls. */
    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;

	switch (pScrn->depth) {
        case 8:
            OUTREG32(COL_CHROMA_KEY_CONTROL_REG,
                     0x37000000 | (pPriv->colorKey & 0xFF));
            OUTREG32(SEC_STREAM_CKEY_UPPER,
                     0x00000000 | (pPriv->colorKey & 0xFF));
            break;
        case 15:
            OUTREG32(COL_CHROMA_KEY_CONTROL_REG,
                     0x05000000 | (red<<19) | (green<<11) | (blue<<3));
            OUTREG32(SEC_STREAM_CKEY_UPPER,
                     0x00000000 | (red<<19) | (green<<11) | (blue<<3));
            break;
        case 16:
            OUTREG32(COL_CHROMA_KEY_CONTROL_REG,
                     0x16000000 | (red<<19) | (green<<10) | (blue<<3));
            OUTREG32(SEC_STREAM_CKEY_UPPER,
                     0x00000000 | (red<<19) | (green<<10) | (blue<<3));
            break;
        case 24:
            OUTREG32(COL_CHROMA_KEY_CONTROL_REG,
                     0x17000000 | (red<<16) | (green<<8) | (blue));
            OUTREG32(SEC_STREAM_CKEY_UPPER,
                     0x00000000 | (red<<16) | (green<<8) | (blue));
            break;
	}

	/*
     * MM81A0: Blend control register,We use destination colorkey
     *   26~24 = 101: color key on primary stream, secondary stream
     *                overlay on primary stream
     */
	OUTREG32(BLEND_CONTROL_REG, 0x05000000);
}

void SavageSetColorKeyNew(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
    int red, green, blue;

    /* Here, we reset the colorkey and all the controls. */
    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;

    if (!pPriv->colorKey) {
        OUTREG32(SEC_STREAM_CKEY_LOW, 0);
        OUTREG32(SEC_STREAM_CKEY_UPPER, 0);
        OUTREG32(BLEND_CONTROL, psav->blendBase | 0x08);
    }
    else {
        switch (pScrn->depth) {
            case 8:
                OUTREG32(SEC_STREAM_CKEY_LOW, 
                         0x47000000 | (pPriv->colorKey & 0xFF));
                OUTREG32(SEC_STREAM_CKEY_UPPER,
                         0x47000000 | (pPriv->colorKey & 0xFF));
                break;
            case 15:
                OUTREG32(SEC_STREAM_CKEY_LOW, 
                         0x45000000 | (red<<19) | (green<<11) | (blue<<3));
                OUTREG32(SEC_STREAM_CKEY_UPPER, 
                         0x45000000 | (red<<19) | (green<<11) | (blue<<3));
                break;
            case 16:
                OUTREG32(SEC_STREAM_CKEY_LOW, 
                         0x46000000 | (red<<19) | (green<<10) | (blue<<3));
                OUTREG32(SEC_STREAM_CKEY_UPPER, 
                         0x46020002 | (red<<19) | (green<<10) | (blue<<3));
                break;
            case 24:
                OUTREG32(SEC_STREAM_CKEY_LOW, 
                         0x47000000 | (red<<16) | (green<<8) | (blue));
                OUTREG32(SEC_STREAM_CKEY_UPPER, 
                         0x47000000 | (red<<16) | (green<<8) | (blue));
                break;
        }    

        /* We assume destination colorkey */
        OUTREG32(BLEND_CONTROL, psav->blendBase | 0x08);
    }
}


void SavageSetColorOld(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;

    if ((psav->videoFourCC == FOURCC_RV15)
        || (psav->videoFourCC == FOURCC_RV16))  {
        OUTREG32(COLOR_ADJUSTMENT_REG, 0);
    }
    else  {
    	unsigned long b,c;
        unsigned long sat = pPriv->saturation  / 16.0;
        double hue = pPriv->hue * 0.017453292;
        double temp;
        unsigned long hs1, hs2;

        temp = sat * (double)cos(hue);

        if (temp < 0)
            hs1 = ((long)(temp - 0.5)) & 0x1f;
        else
            hs1 = ((long)(temp + 0.5)) & 0x1f;

        temp = sat * (double)sin(hue);

        if (temp < 0)
            hs2 = ((long)(temp - 0.5)) & 0x1f;
        else
            hs2 = ((long)(temp + 0.5)) & 0x1f;

        b = (pPriv->brightness + 128) & 0xff;
        c = (pPriv->contrast / 8) & 0x1f;

        OUTREG32(COLOR_ADJUSTMENT_REG,
                 0x80008000 | (b) | (c << 8)
                 | (hs1 << 16) | (hs2 << 24));

    }
}

void SavageSetColorNew(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;

    /* Brightness/contrast/saturation/hue computations. */
    double k, dk1, dk2, dk3, dk4, dk5, dk6, dk7, dkb;
    int k1, k2, k3, k4, k5, k6, k7, kb;
    double s = pPriv->saturation / 128.0;
    double h = pPriv->hue * 0.017453292;
    unsigned long assembly;

    if(psav->videoFourCC == FOURCC_Y211)
        k = 1.0;	/* YUV */
    else
        k = 1.14;	/* YCrCb */

    /*
     * The S3 documentation must be wrong for k4 and k5.  Their default
     * values, which they hardcode in their Windows driver, have the
     * opposite sign from the results in the register spec.
     */

    dk1 = k * pPriv->contrast;
    dk2 = 64.0 * 1.371 * k * s * cos(h);
    dk3 = -64.0 * 1.371 * k * s * sin(h);
    dk4 = -128.0 * k * s * (0.698 * cos(h) - 0.336 * sin(h));
    dk5 = -128.0 * k * s * (0.698 * sin(h) + 0.336 * cos(h));
    dk6 = 64.0 * 1.732 * k * s * sin(h);	/* == k3 / 1.26331, right? */
    dk7 = 64.0 * 1.732 * k * s * cos(h);	/* == k2 / -1.26331, right? */
    dkb = 128.0 * pPriv->brightness + 64.0;
    if(psav->videoFourCC != FOURCC_Y211)
        dkb -= dk1 * 14.0;

    k1 = (int)(dk1+0.5) & 0x1ff;
    k2 = (int)(dk2+0.5) & 0x1ff;
    k3 = (int)(dk3+0.5) & 0x1ff;
    assembly = (k3<<18) | (k2<<9) | k1;
    xf86ErrorFVerb(XVTRACE+1, "CC1 = %08x  ", assembly);
    OUTREG32(SEC_STREAM_COLOR_CONVERT1, assembly);

    k4 = (int)(dk4+0.5) & 0x1ff;
    k5 = (int)(dk5+0.5) & 0x1ff;
    k6 = (int)(dk6+0.5) & 0x1ff;
    assembly = (k6<<18) | (k5<<9) | k4;
    xf86ErrorFVerb(XVTRACE+1, "CC2 = %08x  ", assembly);
    OUTREG32(SEC_STREAM_COLOR_CONVERT2, assembly);

    k7 = (int)(dk7+0.5) & 0x1ff;
    kb = (int)(dkb+0.5) & 0xffff;
    assembly = (kb<<9) | k7;
    xf86ErrorFVerb(XVTRACE+1, "CC3 = %08x\n", assembly);
    OUTREG32(SEC_STREAM_COLOR_CONVERT3, assembly);
}


/* 
 * SavageClipVideo -
 * Takes the dst box in standard X BoxRec form (top and left
 * edges inclusive, bottom and right exclusive).  The new dst
 * box is returned.  The source boundaries are given (x1, y1
 * inclusive, x2, y2 exclusive) and returned are the new source
 * boundaries in 16.16 fixed point.
 */
static void
SavageClipVideo(
    BoxPtr dst, 
    INT32 *x1, INT32 *x2, 
    INT32 *y1, INT32 *y2,
    BoxPtr extents,  /* extents of the clip region */
    INT32 width, INT32 height)
{
    INT32 vscale, hscale, delta;
    int diff;

    hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
    vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);

    *x1 <<= 16; *x2 <<= 16;
    *y1 <<= 16; *y2 <<= 16;

    diff = extents->x1 - dst->x1;
    if (diff > 0) {
        dst->x1 = extents->x1;
        *x1 += diff * hscale;     
    }
    diff = dst->x2 - extents->x2;
    if (diff > 0) {
        dst->x2 = extents->x2;
        *x2 -= diff * hscale;     
    }
    diff = extents->y1 - dst->y1;
    if (diff > 0) {
        dst->y1 = extents->y1;
        *y1 += diff * vscale;
    }
    diff = dst->y2 - extents->y2;
    if (diff > 0) {
        dst->y2 = extents->y2;
        *y2 -= diff * vscale;     
    }

    if (*x1 < 0) {
        diff =  (- *x1 + hscale - 1)/ hscale;
        dst->x1 += diff;
        *x1 += diff * hscale;
    }
    delta = *x2 - (width << 16);
    if (delta > 0) {
        diff = (delta + hscale - 1)/ hscale;
        dst->x2 -= diff;
        *x2 -= diff * hscale;
    }
    if (*y1 < 0) {
        diff =  (- *y1 + vscale - 1)/ vscale;
        dst->y1 += diff;
        *y1 += diff * vscale;
    }
    delta = *y2 - (height << 16);
    if (delta > 0) {
        diff = (delta + vscale - 1)/ vscale;
        dst->y2 -= diff;
        *y2 -= diff * vscale;
    }
    
} 

static void
SavageDisplayVideoOld(
    ScrnInfoPtr pScrn,
    int id,
    int offset,
    short width, short height,
    int pitch,
    int x1, int y1, int x2, int y2,
    BoxPtr dstBox,
    short src_w, short src_h,
    short drw_w, short drw_h,
    Bool double_buffer)
{
    SavagePtr psav = SAVPTR(pScrn);
    SavagePortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
    unsigned int ssControl;
	int scalratio;

    if (psav->videoFourCC != id) {
        psav->blendBase = GetBlendForFourCC(id);

        OUTREG32(BLEND_CONTROL, psav->blendBase | 0x08);
        if ((psav->Chipset == S3_SAVAGE_MX)
            || (psav->Chipset == S3_SUPERSAVAGE)
            || (psav->Chipset == S3_SAVAGE2000)) {
            /* These values specify brightness,contrast,saturation and hue. */
            OUTREG32(SEC_STREAM_COLOR_CONVERT1, 0x0000C892);
            OUTREG32(SEC_STREAM_COLOR_CONVERT2, 0x00039F9A);
            OUTREG32(SEC_STREAM_COLOR_CONVERT3, 0x01F1547E);
        }

        /* Turn on secondary stream TV flicker filter, once we support TV. */
        /* SR70 |= 0x10 */
        psav->videoFlags |= VF_STREAMS_ON;
        psav->videoFourCC = id;
    }

    /* Calculate horizontal scale factor. */
    if (S3_MOBILE_TWISTER_SERIES(psav->Chipset)
        && psav->FPExpansion) {
        drw_w = (((float)(drw_w * psav->XExp1)/(float)psav->XExp2)+1);
        drw_h = (float)(drw_h * psav->YExp1)/(float)psav->YExp2+1;
        dstBox->x1 = (float)(dstBox->x1 * psav->XExp1)/(float)psav->XExp2;
        dstBox->y1 = (float)(dstBox->y1 * psav->YExp1)/(float)psav->YExp2;

        dstBox->x1 += psav->displayXoffset;
        dstBox->y1 += psav->displayYoffset;
    }

    /*
     * Process horizontal scaling
     *  upscaling and downscaling smaller than 2:1 controled by MM8198
     *  MM8190 controls downscaling mode larger than 2:1
     */
    scalratio = 0;
    ssControl = 0;
    if (src_w >= (drw_w * 2)) {
        if (src_w < (drw_w * 4)) {
            scalratio = HSCALING(2,1);
        } else if (src_w < (drw_w * 8)) {
            ssControl |= HDSCALE_4;
        } else if (src_w < (drw_w * 16)) {
            ssControl |= HDSCALE_8;
        } else if (src_w < (drw_w * 32)) {
            ssControl |= HDSCALE_16;
        }  else if (src_w < (drw_w * 64)) {
            ssControl |= HDSCALE_32;
        } else
            ssControl |= HDSCALE_64;
    } else
        scalratio = HSCALING(src_w,drw_w);
    ssControl |= src_w;
    ssControl |= (1 << 24);

    /* Wait for VBLANK. */
    VerticalRetraceWait();
    
    OUTREG32(SSTREAM_CONTROL_REG,  ssControl);
    if (scalratio)
        OUTREG32(SSTREAM_STRETCH_REG,scalratio);

    /* set vertical scale factor. */
	OUTREG32(K1_VSCALE_REG, VSCALING(src_h,drw_h));
    OUTREG32(K2_VSCALE_REG,	0x00000000);

    if (pPriv->update_flags) {
	    OUTREG32(SSTREAM_FBADDR0_REG, (offset & 0x1fffff0));
        
	    if (!pPriv->double_buffer || FALSE == double_buffer)
	        OUTREG32(SSTREAM_FBADDR1_REG, 0);
	    else {
	    	if (pPriv->sec_area) {
	    		OUTREG32(SSTREAM_FBADDR1_REG, (pPriv->sec_offset & 0x1fffff0));
            }
            else {
                OUTREG32(SSTREAM_FBADDR1_REG, 0);
                OUTREG32(MULTIPLE_BUFFER_REG, 0);
            }
	    }
    }
    
    OUTREG32(SSTREAM_STRIDE_REG, pitch & 0xfff);
    OUTREG32(SSTREAM_START_REG, ((dstBox->x1+1) << 16) | (dstBox->y1+1));
    OUTREG32(SSTREAM_WINDOW_SIZE_REG, (drw_w << 16) | drw_h);
    /*
     * MM91E8:Secondary Stream Source Line Count
     *   bit_0~10: # of lines in the source image (before scaling)
     *   bit_15 = 1: Enable vertical interpolation
     *            0: Line duplicaion
     */
    OUTREG32(DDA_VERT_REG, 0x00008000 | src_h);

    /* Set color key on primary. */
    SavageSetColorKey(pScrn); 

    /* Set FIFO L2 on second stream. */
    pitch = (pitch + 7) / 8 - 1;
    OUTREG8(CRT_ADDRESS_REG, 0x92);
    OUTREG8(CRT_DATA_REG, (pitch >> 8) | 0x80);
    OUTREG8(CRT_ADDRESS_REG, 0x93);
    OUTREG8(CRT_DATA_REG, pitch);
}

static void
SavageDisplayVideoNew(
    ScrnInfoPtr pScrn,
    int id,
    int offset,
    short width, short height,
    int pitch,
    int x1, int y1, int x2, int y2,
    BoxPtr dstBox,
    short src_w, short src_h,
    short drw_w, short drw_h,
    Bool double_buffer)
{
    SavagePtr psav = SAVPTR(pScrn);
    
    if (psav->videoFourCC != id)
        SavageStreamsOff(pScrn);

    if (!(psav->videoFlags & VF_STREAMS_ON)) {
        SavageStreamsOn(pScrn, id);
        SavageResetVideo(pScrn);
    }

    /* Calculate horizontal and vertical scale factors. */
    if (psav->Chipset == S3_SAVAGE2000) {
        OUTREG32(SEC_STREAM_HSCALING,
               (65536 * src_w / drw_w) & 0x1FFFFF);
        if(src_w < drw_w)
            OUTREG32(SEC_STREAM_HSCALE_NORMALIZE,
                   ((2048 * src_w / drw_w) & 0x7ff) << 16);
        else
            OUTREG32(SEC_STREAM_HSCALE_NORMALIZE, 2048 << 16);
        OUTREG32(SEC_STREAM_VSCALING,
               (65536 * src_h / drw_h) & 0x1FFFFF);
    } else  {
        if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
            && !psav->TvOn) {
            drw_w = (float)(drw_w * psav->XExp1)/(float) psav->XExp2 + 1;
            drw_h = (float)(drw_h * psav->YExp1)/(float) psav->YExp2 + 1;
            dstBox->x1 = (float)(dstBox->x1 * psav->XExp1)/(float) psav->XExp2;
            dstBox->y1 = (float)(dstBox->y1 * psav->YExp1)/(float) psav->YExp2;
            dstBox->x1 += psav->displayXoffset;
            dstBox->y1 += psav->displayYoffset;
        }

        OUTREG32(SEC_STREAM_HSCALING,
                 ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF));
        /* BUGBUG need to add 00040000 if src stride > 2048 */
        OUTREG32(SEC_STREAM_VSCALING,
                 ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF));
    }

    /*
     * Set surface location and stride.  We use x1>>15 because all surfaces
     * are 2 bytes/pixel.
     */
    /*OUTREG32(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15)) & 0x3ffff0);*/
    OUTREG32(SEC_STREAM_FBUF_ADDR0, offset & 0x3ffff0);    
    OUTREG32(SEC_STREAM_STRIDE, pitch & 0xfff);
    OUTREG32(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1));

    OUTREG32(SEC_STREAM_WINDOW_SZ, ((drw_w) << 16) | drw_h);

    /* Set color key on primary. */
    SavageSetColorKey(pScrn);

    /* Set FIFO L2 on second stream. */
    pitch = (pitch + 7) / 8 - 4;
    OUTREG8(CRT_ADDRESS_REG, 0x92);
    OUTREG8(CRT_DATA_REG, (pitch >> 8) | 0x80);
    OUTREG8(CRT_ADDRESS_REG, 0x93);
    OUTREG8(CRT_DATA_REG, pitch);
}


void SavageStreamsOn(ScrnInfoPtr pScrn, int id)
{
    SavagePtr psav = SAVPTR(pScrn);
    unsigned char jStreamsControl;

    /* Unlock extended registers. */
    UnLockExtRegs();

    OUTREG8(CRT_ADDRESS_REG, EXT_MISC_CTRL2);
    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
        || (psav->Chipset == S3_SAVAGE2000)) {
        jStreamsControl = INREG8(CRT_DATA_REG) | ENABLE_STREAM1;
    } else {
        if (S3_MOBILE_TWISTER_SERIES(psav->Chipset)
            && psav->FPExpansion) {
            jStreamsControl = INREG8(CRT_DATA_REG) | 0x8c;
        } else {
            jStreamsControl = INREG8(CRT_DATA_REG) | 0x04;
        }
    }
    
    /* Wait for VBLANK. */
    VerticalRetraceWait();
    /* Fire up streams! */
    OUTREG16(CRT_ADDRESS_REG,(jStreamsControl << 8) | EXT_MISC_CTRL2);

    psav->blendBase = GetBlendForFourCC(id);
    xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", &id, psav->blendBase);
    OUTREG32(BLEND_CONTROL, psav->blendBase | 0x08);
    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
       ||(psav->Chipset == S3_SUPERSAVAGE)
       ||(psav->Chipset == S3_SAVAGE2000)) {
        /* These values specify brightness, contrast, saturation and hue. */
        OUTREG32(SEC_STREAM_COLOR_CONVERT1, 0x0000C892);
        OUTREG32(SEC_STREAM_COLOR_CONVERT2, 0x00039F9A);
        OUTREG32(SEC_STREAM_COLOR_CONVERT3, 0x01F1547E);
    }

    /* Wait for VBLANK. */
    VerticalRetraceWait();
    
    /* Turn on secondary stream TV flicker filter, once we support TV. */
    /* SR70 |= 0x10 */
    psav->videoFlags |= VF_STREAMS_ON;
    psav->videoFourCC = id;
}


void SavageStreamsOff(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    unsigned char jStreamsControl;

    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
        || (psav->Chipset == S3_SUPERSAVAGE)
        || (psav->Chipset == S3_SAVAGE2000))  {

        /* Unlock extended registers. */
        UnLockExtRegs();

        OUTREG8(CRT_ADDRESS_REG, EXT_MISC_CTRL2);
        jStreamsControl = INREG8(CRT_DATA_REG) & NO_STREAMS;
        /* Wait for VBLANK. */
        VerticalRetraceWait();
        /* Kill streams. */
        OUTREG16(CRT_ADDRESS_REG, (jStreamsControl << 8) | EXT_MISC_CTRL2);
    }
    else {
        OUTREG32(BLEND_CONTROL_REG, 0x01000000);
        OUTREG32(SEC_STREAM_WINDOW_SZ, (1 << 16) | 1);
        OUTREG32(SSTREAM_CONTROL_REG, INREG(SSTREAM_CONTROL_REG) | 0xfff8ffff);
    }

    psav->videoFlags &= ~VF_STREAMS_ON;
}


static void
SavageCopyPlanarDataOld(
    ScrnInfoPtr pScrn,
    unsigned char *srcY, /* Y */
    unsigned char *srcV, /* V */
    unsigned char *srcU, /* U */
    unsigned char *dst,
    int srcPitch, int srcPitch2,
    int dstPitch,
    int h,int w)
{
    SavagePtr psav = SAVPTR(pScrn);
    /* half of the dest buffer for copying the YVU data to it ??? */
    unsigned char *dstCopy = (unsigned char *)(((unsigned long)dst
                                                + 2 * srcPitch * h
                                                + 0x0f) & ~0x0f);
    /* for pixel transfer */
    unsigned long offsetY = (unsigned long)dstCopy - (unsigned long)psav->FBBase;
    unsigned long offsetV = offsetY +  srcPitch * h;
    unsigned long offsetU = offsetV +  srcPitch2 * (h>>1);
    unsigned long dstOffset  = (unsigned long)dst - (unsigned long)psav->FBBase;
    int i;
    
    BCI_GET_PTR;

    /* copy Y planar */
    for (i=0;i<srcPitch * h;i++) {
        dstCopy[i] = srcY[i];
    }

    /* copy V planar */    
    dstCopy = dstCopy + srcPitch * h;
    for (i=0;i<srcPitch2 * (h>>1);i++) {
        dstCopy[i] = srcV[i];
    }

    /* copy U planar */
    dstCopy = dstCopy + srcPitch2 * (h>>1);    
    for (i=0;i<srcPitch2 * (h>>1);i++) {
        dstCopy[i] = srcU[i];        
    }

    /*
     * Transfer pixel data from one memory location to another loction
     * and reformat the data during the transfer
     * a. program BCI51 to specify the source information
     * b. program BCI52 to specify the destination information
     * c. program BCI53 to specify the source dimensions 
     * d. program BCI54 to specify the destination dimensions
     * e. (if the data is in YCbCr420 format)program BCI55,BCI56,BCI57 to
     *    locations of the Y,Cb,and Cr data
     * f. program BCI50(command=011) to specify the formatting options and
     *    kick off the transfer
     * this command can be used for color space conversion(YCbCr to RGB)
     * or for oversampling, but not for both simultaneously. it can also be
     * used to do mastered image transfer when the source is tiled
     */

    w = (w+0xf)&0xff0;
    psav->WaitQueue(psav,11);
    BCI_SEND(0x96070051);
    BCI_SEND(offsetY);

    BCI_SEND(dstOffset);

    BCI_SEND(((h-1)<<16)|((w-1)>>3));

    BCI_SEND(dstPitch >> 3);


    BCI_SEND(offsetU);
    BCI_SEND(offsetV);

    BCI_SEND((srcPitch2 << 16)| srcPitch2);

    BCI_SEND(0x96010050);
    BCI_SEND(0x00200003 | srcPitch);
    BCI_SEND(0xC0170000);
}

static void
SavageCopyData(
    unsigned char *src,unsigned char *dst,
    int srcPitch,int dstPitch,
    int h,int w)
{
    w <<= 1;
    while(h--) {
        memcpy(dst, src, w);
        src += srcPitch;
        dst += dstPitch;
    }
}

static void
SavageCopyPlanarData(
    unsigned char *src1, /* Y */
    unsigned char *src2, /* V */
    unsigned char *src3, /* U */
    unsigned char *dst1,
    int srcPitch,int srcPitch2,int dstPitch,
    int h,int w)
{
    CARD32 *dst = (CARD32*)dst1;
    int i, j;

    dstPitch >>= 2;
    w >>= 1;

    for(j = 0; j < h; j++) {
        for(i = 0; i < w; i++) {
            /* Shouldn't this be 'if LITTLEENDIAN'? */
#if 1
            dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
                (src3[i] << 8) | (src2[i] << 24);
#else
            dst[i] = (src1[i << 1] << 24) | (src1[(i << 1) + 1] << 8) |
                (src3[i] << 0) | (src2[i] << 16);
#endif
        }
        dst += dstPitch;
        src1 += srcPitch;
        if(j & 1) {
            src2 += srcPitch2;
            src3 += srcPitch2;
        }
    }
}



static unsigned int GetBlendForFourCC(int id)
{
    switch (id) {
        case FOURCC_YUY2:
        case FOURCC_UYVY:
        case FOURCC_YV12:
        case FOURCC_I420:
            return 1 << 9;
        case FOURCC_Y211:
            return 4 << 9;
        case FOURCC_RV15:
            return 3 << 9;
        case FOURCC_RV16:
            return 5 << 9;
        default:
            return 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;
}

#if SAVAGE_VIP
static int
SavagePutVideo(
    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,
    RegionPtr clipBoxes, pointer data)
{

    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
    SavagePtr psav = SAVPTR(pScrn);
    INT32 x1, x2, y1, y2;
    /*unsigned char *dst_start;*/
    int pitch, new_h, offsetV=0, offsetU=0;
    static int offset; /* change offset var to static peterzhu*/
    int srcPitch, srcPitch2=0, dstPitch;
    int top, left, npixels, nlines;
    BoxRec dstBox;
    CARD32 tmp;
    int width,height,id;
    /* add by peterzhu*/
    struct v4l2_framebuffer	framebuffer;
    struct v4l2_format		fmt;
    static short last_width, last_height;/* add by peterzhu for performance tune*/
    short drw_w_orig = drw_w;
    short drw_h_orig = drw_h;
    int depth;
    int on = 1;
    int ret;


    /*#ifdef SAVAGE_DEBUG*/
    /*ErrorF("SavagePutVideo\n");
      ErrorF("src_w %i; src_h %i; drw_w %i; drw_h %i\n", src_w, src_h,\
      drw_w, drw_h);*/
    /*#endif*/

    /* Set to DEFAULT_NORM when VIDEO_OFF because some app dont set norm as started.
     * Thus if unload and load "intest" again after X startup, with xawtv newly
     * startup, if norm is set, it may leads that new FB addr from 
     * SavageAllocateMemory would not be passed into intest moduel, which 
     * will lead oops as copying framebuffer data within interrupt.
     * For the same reason, UPDATE_VIDEO is still needed as norm is set.
     * peterzhu
     */
    	
    if(VIDEO_OFF == pPriv->videoflags) 
    {	
    	/* force fd to -1 to avoid invalid file descriptor possibly resulted from 
    	 * abnormal quit of app
    	 */
        pPriv->fd = -1;
        ret = SavageSetPortAttribute(pScrn, xvEncoding, DEFAULT_NORM, data);
    	if (Success != ret)
            return ret;
    }

    if(drw_w > 16384) drw_w = 16384;

    /* Clip */
    x1 = src_x;
    x2 = src_x + src_w;
    y1 = src_y;
    y2 = src_y + src_h;

    dstBox.x1 = drw_x;
    dstBox.x2 = drw_x + drw_w;
    dstBox.y1 = drw_y;
    dstBox.y2 = drw_y + drw_h;

    /* updated by peterzhu*/
        {
            width = InputVideoEncodings[pPriv->encoding].width;
            height = InputVideoEncodings[pPriv->encoding].height;
            if (psav->v4l_videoin){	
                if (VIDEO_OFF == pPriv->videoflags) {
                    if (SavageOpenV4l(pPriv))
                        return Success;
                }
                fmt.type = V4L2_BUF_TYPE_CAPTURE;
                /*
                  ErrorF("before G_FMT\n");*/
                if (-1 == ioctl(pPriv->fd, VIDIOC_G_FMT, &fmt))
                    return Success;
                /*ErrorF("after G_FMT\n");*/

                if (width > fmt.fmt.pix.width && fmt.fmt.pix.width)
                    width = fmt.fmt.pix.width;
                if (height > fmt.fmt.pix.height && fmt.fmt.pix.height)
                    height = fmt.fmt.pix.height;
            }
            /*width = 720; height = 288;*/
            if ((last_width != width) || (last_height != height)) 
            {
                pPriv->update_flags |= UPDATE_VIDEO;
                last_width = width;
                last_height = height;
            }
        }

#if 1
        SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
                        REGION_EXTENTS(pScreen, clipBoxes), width, height);


        drw_w = dstBox.x2 - dstBox.x1;
        drw_h = dstBox.y2 - dstBox.y1;
        src_w = (x2 - x1) >> 16;
        src_h = (y2 - y1) >> 16;
#endif

        if((x1 >= x2) || (y1 >= y2))
            return Success;

        dstBox.x1 -= pScrn->frameX0;
        dstBox.x2 -= pScrn->frameX0;
        dstBox.y1 -= pScrn->frameY0;
        dstBox.y2 -= pScrn->frameY0;

        pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;

        dstPitch = ((width << 1) + 15) & ~15;
        new_h = ((dstPitch * height) + pitch - 1) / pitch;

        id = FOURCC_YUY2;



        /* set depth to correct value -- updated by peterzhu*/
        switch(id) {
            case FOURCC_Y211:		/* Y211 */
                xf86Msg(X_INFO,"FOURCC_Y211");
                srcPitch = width;
                depth = 6;
                break;
            case FOURCC_YV12:		/* YV12 */
                xf86Msg(X_INFO,"FOURCC_YV12");
                depth = 12;
                srcPitch = (width + 3) & ~3;
                offsetV = srcPitch * height;
                srcPitch2 = ((width >> 1) + 3) & ~3;
                offsetU = (srcPitch2 * (height >> 1)) + offsetV;
                break;
            case FOURCC_I420:
                xf86Msg(X_INFO,"FOURCC_I420");
                depth = 12;
                srcPitch = (width + 3) & ~3;
                offsetU = srcPitch * height;
                srcPitch2 = ((width >> 1) + 3) & ~3;
                offsetV = (srcPitch2 * (height >> 1)) + offsetU;
                break;
            case FOURCC_RV15:		/* RGB15 */
                depth = 16;
                srcPitch = (width << 1);
                break;
            case FOURCC_RV16:		/* RGB16 */
                depth = 16;
                srcPitch = (width << 1);
                break;
            case FOURCC_YUY2:		/* YUY2 */
                depth = 16;
                srcPitch = (width << 1);
                break;
            case FOURCC_UYVY:		/* YUY2 */
                depth = 16;
                srcPitch = (width << 1);
                break;
            default:
                depth = 16;
                srcPitch = (width << 1);
                break;
        }  

    
        /* copy data */
        top = y1 >> 16;
        left = (x1 >> 16) & ~1;
        npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
        left <<= 1;

        /* add by peterzhu for performance tune */
        /* VIDEO_OFF check is must because some app would not set norm as started*/
        if (pPriv->update_flags & UPDATE_VIDEO
            || VIDEO_OFF == pPriv->videoflags) {
            if(!(pPriv->area = SavageAllocateMemory(pScrn, pPriv->area, new_h))){
                return BadAlloc;
            }
            offset = (pPriv->area->box.y1 * pitch) + (top * dstPitch);
            /* if double_buffer, allocate another overlay buffer for video_in*/
            if (pPriv->double_buffer) {
                if(!(pPriv->sec_area = SavageAllocateMemory(pScrn, \
                                                            pPriv->sec_area, new_h))){
                    return BadAlloc;	
                }
                /*ErrorF("Double Buffer:allocate 2nd overlay  buffer\n");*/
                pPriv->sec_offset = (pPriv->sec_area->box.y1 * pitch) + (top * dstPitch);
            }
        }
    
        /*dst_start = psav->FBBase + offset + left;*/

        /* Jiayo Video16 mode */
#if 0
        OUTREG32(0xFF00, 0x000002c3);
        OUTREG32(0xFF0C, offset);
        OUTREG32(0xFF24, ((((height)-1)<<16)|((width)-1)));
        OUTREG32(0xFF28, 0x00110002);
        OUTREG32(0xFF30, 0x00000000);
        OUTREG32(0xFF34, (width<<1));
#endif

        /* Jiayo Video 8 mode CCIR 656 */
#if 0
        OUTREG32(0xFF00, 0x00000285);
        OUTREG32(0xFF0C, offset);
        OUTREG32(0xFF24, ((((height<<1)-1)<<16)|((width<<1)-1)));
        OUTREG32(0xFF28, 0x000d0010);
        OUTREG32(0xFF30, 0x00000000);
        OUTREG32(0xFF34, (width<<1));
#endif

        /* Jiayo Video 8 mode CCR* 656 , use HREF */
        /* and trying to fixing edge noise*/
        /* updated by peterzhu for v4l processing and performance tune*/
#if 1
            {
	    	
                if (!psav->v4l_videoin) {	
                    if ((VIDEO_OFF == pPriv->videoflags) 
                         || (pPriv->update_flags & UPDATE_VIDEO) 
                        )
                    {	
                        OUTREG32(0xFF00, 0x0000068d);   /*CCIR656 mode*/
                        /*OUTREG32(0xFF00, 0x000002c3);   video 16 mode*/
                        /*OUTREG32(0xFF00, 0x00000285);   video 8 mode*/
                        /*OUTREG32(0xFF00, 0x42100285);*/
                        /*OUTREG32(0xFF00, 0x421002c3);*/
                        OUTREG32(0xFF0C, offset);
                        if (pPriv->double_buffer) {
                            /*ErrorF("Double Buffer:setting 0XFF10 with sec_offset\n");	*/
                            OUTREG32(0xFF10, pPriv->sec_offset);
                        }
                        OUTREG32(0xFF24, ((((height)-1)<<16)|((width<<1)-1)));
                        OUTREG32(0xFF28, 0x00020004);
                        OUTREG32(0xFF30, 0x00000000);
                        OUTREG32(0xFF34, (width<<1));
                    }
                } else {
                    if ((VIDEO_OFF == pPriv->videoflags)    
                        || (pPriv->update_flags & UPDATE_VIDEO))
                    {
                        if (pPriv->update_flags & UPDATE_VIDEO){
                            framebuffer.capability = 0;
                            framebuffer.flags = V4L2_FBUF_FLAG_OVERLAY;
                            framebuffer.base[0] = (void*)(psav->FrameBufferBase + offset);
                            if (pPriv->double_buffer) {
                                /*ErrorF("Double Buffer:Setting base[1] with sec_offset\n");	*/
                                framebuffer.base[1] = (void*)(psav->FrameBufferBase + pPriv->sec_offset);
                            }
                            framebuffer.fmt.width = width;
                            framebuffer.fmt.height = height;
                            framebuffer.fmt.depth = depth;
                            /* just according to id == FOURCC_YUY2*/
                            framebuffer.fmt.pixelformat = V4L2_PIX_FMT_YUYV;
                            if (-1 == ioctl(pPriv->fd, VIDIOC_S_FBUF, &framebuffer)) {
                                ErrorF("S_FBUF failed\n");
                                on = 0;
                            }else {
                                on = 1;
                            }
                        }
                        ioctl(pPriv->fd, VIDIOC_PREVIEW, &on);
                    }
                }
            }   
#endif
            switch(id) {
                case FOURCC_YV12:		/* YV12 */
                case FOURCC_I420:
                    top &= ~1;
                    tmp = ((top >> 1) * srcPitch2) + (left >> 2);
                    offsetU += tmp;
                    offsetV += tmp;
                    nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
                    break;
                case FOURCC_Y211:		/* Y211 */
                case FOURCC_RV15:		/* RGB15 */
                case FOURCC_RV16:		/* RGB16 */
                case FOURCC_YUY2:		/* YUY2 */
                default:
                    break;
            }

            /* update cliplist */
            if(!RegionsEqual(&pPriv->clip, clipBoxes)) {
                REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
                /* draw these */
                XAAFillSolidRects(pScrn, pPriv->colorKey, GXcopy, ~0,
                                  REGION_NUM_RECTS(clipBoxes),
                                  REGION_RECTS(clipBoxes));
            }
            /*
              SavageDisplayVideo(pScrn, id, offset, width, height, dstPitch,
              x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
            */
            SavageDisplayVideo(
                pScrn, id, offset, width, height, dstPitch,
                x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w_orig, drw_h_orig, TRUE);

            pPriv->videoStatus = CLIENT_VIDEO_ON;
            /* updated by peterzhu*/
            pPriv->videoflags = VIDEO_ON;
            pPriv->update_flags &= ~UPDATE_VIDEO;
            
            return Success;
}

static void SavageProgram7111(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
    int vgaCRIndex, vgaCRReg, vgaIOBase;

    vgaIOBase = hwp->IOBase;
    vgaCRIndex = vgaIOBase + 4;
    vgaCRReg = vgaIOBase + 5;


    if (SavageDVIInit(pScrn) == TRUE) {
        unsigned char tmp;

        InI2CREG(tmp,psav->I2CPort);
        OutI2CREG(tmp | 0x13,psav->I2CPort);

            {
                I2CDevPtr TVdev;
                unsigned char result;

                TVdev = xf86CreateI2CDevRec();

                TVdev->DevName="SAA7111";
                TVdev->SlaveAddr = 0x48;
                TVdev->ByteTimeout = 2200;
                TVdev->StartTimeout = 550;
                TVdev->BitTimeout = 40;
                TVdev->ByteTimeout = 40;
                TVdev->AcknTimeout = 40;

                TVdev->pI2CBus = psav->DVI;

                if(xf86I2CReadByte(TVdev,0x00,&result) && (result&0xF0))
                {
                    ErrorF("Read SAA7111 sub 0x00:%x\n",result);

                    xf86I2CWriteByte(TVdev,0x02,0xC4);
                    xf86I2CWriteByte(TVdev,0x03,0x37);
                    xf86I2CWriteByte(TVdev,0x04,0x00);
                    xf86I2CWriteByte(TVdev,0x05,0x00);

                    xf86I2CWriteByte(TVdev,0x06,0x00);
                    xf86I2CWriteByte(TVdev,0x07,0xd8);

                    xf86I2CWriteByte(TVdev,0x08,0xa8);
                    xf86I2CWriteByte(TVdev,0x09,0x40);
                    xf86I2CWriteByte(TVdev,0x0A,0x80);
                    xf86I2CWriteByte(TVdev,0x0B,0x47);
                    xf86I2CWriteByte(TVdev,0x0C,0x40);
                    xf86I2CWriteByte(TVdev,0x0D,0x00);
                    xf86I2CWriteByte(TVdev,0x0E,0x03);
                    xf86I2CWriteByte(TVdev,0x0F,0x00);
                    xf86I2CWriteByte(TVdev,0x10,0xF0);
                    xf86I2CWriteByte(TVdev,0x11,0x1c);
                    xf86I2CWriteByte(TVdev,0x12,0x09);
                    xf86I2CWriteByte(TVdev,0x13,0x00);
                    xf86I2CWriteByte(TVdev,0x15,0x00);
                    xf86I2CWriteByte(TVdev,0x16,0x00);
                    xf86I2CWriteByte(TVdev,0x17,0x00);

                    xf86I2CReadByte(TVdev,0x02,&result);
                    ErrorF("Read SAA7111 sub 0x02:%x\n",result);
                    xf86I2CReadByte(TVdev,0x03,&result);
                    ErrorF("Read SAA7111 sub 0x03:%x\n",result);
                    xf86I2CReadByte(TVdev,0x04,&result);
                    ErrorF("Read SAA7111 sub 0x04:%x\n",result);
                    xf86I2CReadByte(TVdev,0x05,&result);
                    ErrorF("Read SAA7111 sub 0x05:%x\n",result);
                    xf86I2CReadByte(TVdev,0x06,&result);
                    ErrorF("Read SAA7111 sub 0x06:%x\n",result);
                    xf86I2CReadByte(TVdev,0x07,&result);
                    ErrorF("Read SAA7111 sub 0x07:%x\n",result);
                    xf86I2CReadByte(TVdev,0x08,&result);
                    ErrorF("Read SAA7111 sub 0x08:%x\n",result);
                    xf86I2CReadByte(TVdev,0x09,&result);
                    ErrorF("Read SAA7111 sub 0x09:%x\n",result);
                    xf86I2CReadByte(TVdev,0x0A,&result);
                    ErrorF("Read SAA7111 sub 0x0A:%x\n",result);
                    xf86I2CReadByte(TVdev,0x0B,&result);
                    ErrorF("Read SAA7111 sub 0x0B:%x\n",result);
                    xf86I2CReadByte(TVdev,0x0C,&result);
                    ErrorF("Read SAA7111 sub 0x0C:%x\n",result);
                    xf86I2CReadByte(TVdev,0x0D,&result);
                    ErrorF("Read SAA7111 sub 0x0D:%x\n",result);
                    xf86I2CReadByte(TVdev,0x0E,&result);
                    ErrorF("Read SAA7111 sub 0x0E:%x\n",result);
                    xf86I2CReadByte(TVdev,0x0F,&result);
                    ErrorF("Read SAA7111 sub 0x0F:%x\n",result);
                    xf86I2CReadByte(TVdev,0x10,&result);
                    ErrorF("Read SAA7111 sub 0x10:%x\n",result);
                    xf86I2CReadByte(TVdev,0x11,&result);
                    ErrorF("Read SAA7111 sub 0x11:%x\n",result);
                    xf86I2CReadByte(TVdev,0x12,&result);
                    ErrorF("Read SAA7111 sub 0x12:%x\n",result);
                    xf86I2CReadByte(TVdev,0x13,&result);
                    ErrorF("Read SAA7111 sub 0x13:%x\n",result);
                    xf86I2CReadByte(TVdev,0x15,&result);
                    ErrorF("Read SAA7111 sub 0x15:%x\n",result);
                    xf86I2CReadByte(TVdev,0x16,&result);
                    ErrorF("Read SAA7111 sub 0x16:%x\n",result);
                    xf86I2CReadByte(TVdev,0x17,&result);
                    ErrorF("Read SAA7111 sub 0x17:%x\n",result);
                }
                else  {
                    ErrorF("Read Fail\n");
                }
            }
            OutI2CREG(tmp,psav->I2CPort);
    }
}

/* add by peterzhu*/
static struct v4l2_standard SavageToV4lStandard(SavagePortPrivPtr pPriv, int encoding)
{
	
	struct v4l2_enumstd enumstd;
	struct v4l2_standard standard;
	
	if (encoding >= 1 && encoding <=3) { /*pal*/
		enumstd.index = 0; /* according to capture driver definition,urgly*/
		if (-1 == ioctl(pPriv->fd, VIDIOC_ENUMSTD, &enumstd))
			goto ret;
		standard = enumstd.std;
	} else if(encoding >= 4 && encoding <=6) { /*ntsc*/
		enumstd.index = 1; /* according to capture driver definition,urgly*/
		if (-1 == ioctl(pPriv->fd, VIDIOC_ENUMSTD, &enumstd))
			goto ret;
		standard = enumstd.std;
	} else if(encoding >= 7 && encoding <=9) { /*secam*/
		enumstd.index = 2; /* according to capture driver definition,urgly*/
		if (-1 == ioctl(pPriv->fd, VIDIOC_ENUMSTD, &enumstd))
			goto ret;
		standard = enumstd.std;
	} if(encoding >= 10 && encoding <=12) { /*pal60*/
		enumstd.index = 3; /* according to capture driver definition,urgly*/
		if (-1 == ioctl(pPriv->fd, VIDIOC_ENUMSTD, &enumstd))
			goto ret;
		standard = enumstd.std;
	}
  ret:
	return standard;
}

/* add by peterzhu*/
static int SavageOpenV4l(SavagePortPrivPtr pPriv)
{
    struct v4l2_capability 	cap;
    /*if (pPriv->overlay == TRUE) */
        {
            if (-1 == pPriv->fd) {
                pPriv->fd = open(pPriv->devname, O_NOIO, 0);
            }
	
            if (-1 == pPriv->fd){
                ErrorF("name %s can't opened peterzhu!!!\n", pPriv->devname);
                return errno;
            }
            if (-1 == ioctl(pPriv->fd,VIDIOC_QUERYCAP,&cap) ||
                (V4L2_TYPE_CAPTURE != cap.type ) ||
                0 == (cap.flags & V4L2_FLAG_PREVIEW)) {
                ErrorF("%s: not a capture device or no overlay support \n",pPriv->devname);
                close(pPriv->fd);
                pPriv->fd = -1;
                return errno;
            } 
	    
            pPriv->usecount++;
            ErrorF("Savage Xv open V4l: refcount=%d\n",pPriv->usecount);
            return 0;
        }
        /*return -EINVAL;*/
}


/* add by peterzhu*/
static void SavageCloseV4l(SavagePortPrivPtr pPriv)
{
    pPriv->usecount--;
    ErrorF("Savage Xv close V4l: refcount=%d\n",pPriv->usecount);
    if (0 == pPriv->usecount && -1 != pPriv->fd) {
        close(pPriv->fd);
        pPriv->fd = -1;
    }
}

#endif /* SAVAGE_VIP */

#if 0

static void
CHIPSBlockHandler (
    int i,
    pointer     blockData,
    pointer     pTimeout,
    pointer     pReadmask)
{
    ScreenPtr   pScreen = screenInfo.screens[i];
    ScrnInfoPtr pScrn = xf86Screens[i];
    CHIPSPtr    cPtr = CHIPSPTR(pScrn);
    CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
    unsigned char mr3c;
    
    pScreen->BlockHandler = cPtr->BlockHandler;
    
    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);

    pScreen->BlockHandler = CHIPSBlockHandler;

    CHIPSHiQVSync(pScrn);
    if (pPriv->videoStatus & TIMER_MASK) {
        UpdateCurrentTime();
        if (pPriv->videoStatus & OFF_TIMER) {
            if (pPriv->offTime < currentTime.milliseconds) {
                mr3c = cPtr->readMR(cPtr, 0x3C);
                cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
                pPriv->videoStatus = FREE_TIMER;
                pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
            }
        } else {  /* FREE_TIMER */
            if (pPriv->freeTime < currentTime.milliseconds) {
                if (pPriv->area) {
                    xf86FreeOffscreenArea(pPriv->area);
                    pPriv->area = NULL;
                }
                pPriv->videoStatus = 0;
            }
        }
    }
}
#endif



/***** Offscreen stuff *****/
typedef struct {
    FBAreaPtr area;
    Bool isOn;
} OffscreenPrivRec, * OffscreenPrivPtr;

static void 
SavageInitOffscreenImages(ScreenPtr pScreen)
{
    XF86OffscreenImagePtr offscreenImages;
    SavagePtr psav = SAVPTR(xf86Screens[pScreen->myNum]);

    /* need to free this someplace */
    if (!psav->offscreenImages) {
        if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
            return;
        psav->offscreenImages = offscreenImages;
    } else 
        offscreenImages = psav->offscreenImages;
    offscreenImages[0].image = &Images[0];
    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
    offscreenImages[0].alloc_surface = SavageAllocateSurface;
    offscreenImages[0].free_surface = SavageFreeSurface;
    offscreenImages[0].display = SavageDisplaySurface;
    offscreenImages[0].stop = SavageStopSurface;
    offscreenImages[0].setAttribute = SavageSetSurfaceAttribute;
    offscreenImages[0].getAttribute = SavageGetSurfaceAttribute;
    offscreenImages[0].max_width = 1024;
    offscreenImages[0].max_height = 1024;
    offscreenImages[0].num_attributes = S3_NUM_ATTRIBUTES;
    offscreenImages[0].attributes = Attributes;

    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
}


static int 
SavageAllocateSurface(
    ScrnInfoPtr pScrn,
    int id,
    unsigned short w, 	
    unsigned short h,
    XF86SurfacePtr surface)
{
    FBAreaPtr area;
    int pitch, fbpitch, numlines;
    OffscreenPrivPtr pPriv;
    
    if ((w > 1024) || (h > 1024))
        return BadAlloc;

    w = (w + 1) & ~1;
    pitch = ((w << 1) + 15) & ~15;
    fbpitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
    numlines = ((pitch * h) + fbpitch - 1) / fbpitch;

    if (!(area = SavageAllocateMemory(pScrn, NULL, numlines)))
        return BadAlloc;

    surface->width = w;
    surface->height = h;

    if (!(surface->pitches = xalloc(sizeof(int))))
        return BadAlloc;
    if (!(surface->offsets = xalloc(sizeof(int)))) {
        xfree(surface->pitches);
        return BadAlloc;
    }
    if (!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
        xfree(surface->pitches);
        xfree(surface->offsets);
        return BadAlloc;
    }

    pPriv->area = area;
    pPriv->isOn = FALSE;

    surface->pScrn = pScrn;
    surface->id = id;   
    surface->pitches[0] = pitch;
    surface->offsets[0] = area->box.y1 * fbpitch;
    surface->devPrivate.ptr = (pointer)pPriv;

    return Success;
}

static int 
SavageFreeSurface(XF86SurfacePtr surface)
{
    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
    
    if (pPriv->isOn)
        SavageStopSurface(surface);
    xf86FreeOffscreenArea(pPriv->area);
    xfree(surface->pitches);
    xfree(surface->offsets);
    xfree(surface->devPrivate.ptr);

    return Success;
}



static int 
SavageDisplaySurface(
    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)
{
    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
    ScrnInfoPtr pScrn = surface->pScrn;
    SavagePortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
    INT32 x1, y1, x2, y2;
    BoxRec dstBox;
    
    x1 = src_x;
    x2 = src_x + src_w;
    y1 = src_y;
    y2 = src_y + src_h;

    dstBox.x1 = drw_x;
    dstBox.x2 = drw_x + drw_w;
    dstBox.y1 = drw_y;
    dstBox.y2 = drw_y + drw_h;

    SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
                	REGION_EXTENTS(pScreen, clipBoxes), 
                    surface->width, surface->height);

    if((x1 >= x2) || (y1 >= y2))
        return Success;

    dstBox.x1 -= pScrn->frameX0;
    dstBox.x2 -= pScrn->frameX0;
    dstBox.y1 -= pScrn->frameY0;
    dstBox.y2 -= pScrn->frameY0;

    XAAFillSolidRects(pScrn, portPriv->colorKey, GXcopy, ~0, 
                      REGION_NUM_RECTS(clipBoxes),
                      REGION_RECTS(clipBoxes));

    SavageDisplayVideo(pScrn, surface->id, surface->offsets[0], 
                       surface->width, surface->height, surface->pitches[0],
                       x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, FALSE);

    pPriv->isOn = TRUE;
    
#if 0
    if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
        REGION_EMPTY(pScrn->pScreen, &portPriv->clip);   
        UpdateCurrentTime();
        portPriv->videoStatus = FREE_TIMER;
        portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
    }
#endif

    return Success;
}



static int 
SavageStopSurface(XF86SurfacePtr surface)
{
    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;

    if(pPriv->isOn) {
        /*SavagePtr psav = SAVPTR(surface->pScrn);*/
        SavageStreamsOff(surface->pScrn);
        pPriv->isOn = FALSE;
    }

    return Success;
}

static int
SavageGetSurfaceAttribute(
    ScrnInfoPtr pScrn,
    Atom attribute,
    INT32 *value)
{
    return SavageGetPortAttribute(pScrn, attribute, value, 
                                  (pointer)(GET_PORT_PRIVATE(pScrn)));
}

static int
SavageSetSurfaceAttribute(
    ScrnInfoPtr pScrn,
    Atom attribute,
    INT32 value)
{
    return SavageSetPortAttribute(pScrn, attribute, value, 
                                  (pointer)(GET_PORT_PRIVATE(pScrn)));
}


static
void PatchEnableSPofPanel(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);

    UnLockExtRegs();

    if (pScrn->bitsPerPixel == 8) {
        OUTREG8(CRT_ADDRESS_REG,0x90);
        OUTREG8(CRT_DATA_REG,INREG8(CRT_DATA_REG)|0x40);
    }
    else  {
        OUTREG8(CRT_ADDRESS_REG,0x90);
        OUTREG8(CRT_DATA_REG,INREG8(CRT_DATA_REG)|0x48);
    }

    VerticalRetraceWait();

    OUTREG8(CRT_ADDRESS_REG,0x67);
    OUTREG8(CRT_DATA_REG,(INREG8(CRT_DATA_REG)&0xf3)|0x04);

    OUTREG8(CRT_ADDRESS_REG,0x65);
    OUTREG8(CRT_DATA_REG,INREG8(CRT_DATA_REG)|0xC0);
    
    if (pScrn->bitsPerPixel == 8) {
        OUTREG32(PSTREAM_CONTROL_REG,0x00000000);
    } else {
        OUTREG32(PSTREAM_CONTROL_REG,0x02000000);
    }
    OUTREG32(PSTREAM_WINDOW_SIZE_REG, 0x0);
    
}


/*
 * Function to get lcd factor, display offset for overlay use
 * Input: pScrn; Output: x,yfactor, displayoffset in pScrn
 */
static void OverlayTwisterInit(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);

    psav->cxScreen = psav->iResX;
    InitStreamsForExpansion(psav);
    PatchEnableSPofPanel(pScrn);
}

/*
 * Function to get lcd factor, display offset for overlay use
 * Input: pScrn; Output: x,yfactor, displayoffset in pScrn
 */
static void OverlayParamInit(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);

    psav->cxScreen = psav->iResX;
    InitStreamsForExpansion(psav);
}

/* Function to calculate lcd expansion x,yfactor and offset for overlay */
static void InitStreamsForExpansion(SavagePtr psav)
{
    int		PanelSizeX,PanelSizeY;
    int		ViewPortWidth,ViewPortHeight;
    int		XFactor, YFactor;

    PanelSizeX = psav->PanelX;
    PanelSizeY = psav->PanelY;
    ViewPortWidth = psav->iResX;
    ViewPortHeight = psav->iResY;
    if (PanelSizeX == 1408)
        PanelSizeX = 1400;

    VGAOUT8(0x3C4, HZEXP_FACTOR_IGA1);
    XFactor = VGAIN8(0x3C5);
    VGAOUT8(0x3C4, VTEXP_FACTOR_IGA1);
    YFactor = VGAIN8(0x3C5);
    XFactor >>= 4;
    YFactor >>= 4;

    switch (XFactor) {
        case 1:
            psav->XExpansion = 0x00010001;
            psav->displayXoffset =
                (((PanelSizeX - ViewPortWidth) / 2) + 0x7) & 0xFFF8;
            break;

        case 3:
            psav->XExpansion = 0x00090008;
            psav->displayXoffset =
                (((PanelSizeX - ((9 * ViewPortWidth)/8)) / 2) + 0x7) & 0xFFF8;
            break;

        case 4:
            psav->XExpansion = 0x00050004;

            if ((psav->cxScreen == 800) && (PanelSizeX !=1400))
            {
                psav->displayXoffset =
                    (((PanelSizeX - ((5 * ViewPortWidth)/4)) / 2)) & 0xFFF8;
            }
            else
            {
                psav->displayXoffset =
                    (((PanelSizeX - ((5 * ViewPortWidth)/4)) / 2) +0x7) & 0xFFF8;
            }
            break;

        case 6:
            psav->XExpansion = 0x00030002;
            psav->displayXoffset =
                (((PanelSizeX - ((3 * ViewPortWidth)/2)) / 2) + 0x7) & 0xFFF8;
            break;

        case 7:
            psav->XExpansion = 0x00020001;
            psav->displayXoffset =
                (((PanelSizeX - (2 * ViewPortWidth)) / 2) + 0x7) & 0xFFF8;
            break;
    }
    switch (YFactor) {
        case 0:
            psav->YExpansion = 0x00010001;
            psav->displayYoffset = (PanelSizeY - ViewPortHeight) / 2;
            break;
        case 1:
            psav->YExpansion = 0x00010001;
            psav->displayYoffset = (PanelSizeY - ViewPortHeight) / 2;
            break;
        case 2:
            psav->YExpansion = 0x00040003;
            psav->displayYoffset = (PanelSizeY - ((4 * ViewPortHeight)/3)) / 2;
            break;
        case 4:
            psav->YExpansion = 0x00050004;
            psav->displayYoffset = (PanelSizeY - ((5 * ViewPortHeight)/4)) / 2;
            break;
        case 5:
            psav->YExpansion = 0x00040003;

            if ((psav->cxScreen == 1024)&&(PanelSizeX ==1400)) {
                psav->displayYoffset =
                    ((PanelSizeY - ((4 * ViewPortHeight)/3)) / 2) - 0x1 ;
            } else  {
                psav->displayYoffset = (PanelSizeY - ((4 * ViewPortHeight)/3)) / 2;
            }
            break;
        case 6:
            psav->YExpansion = 0x00050004;
            psav->displayYoffset = (PanelSizeY - ((5 * ViewPortHeight)/4)) / 2;
            break;
        case 7:
            psav->YExpansion = 0x00030002;
            psav->displayYoffset = (PanelSizeY - ((3 * ViewPortHeight)/2)) / 2;
            break;
        case 8:
            psav->YExpansion = 0x00020001;
            psav->displayYoffset = (PanelSizeY - (2 * ViewPortHeight)) /2;
            break;
        case 9:
            psav->YExpansion = 0x00090004;
            psav->displayYoffset = (PanelSizeY - ((9 * ViewPortHeight)/4)) /2;
            break;
        case 11:
            psav->YExpansion = 0x00110005;
            psav->displayYoffset = (PanelSizeY - ((11 * ViewPortHeight)/5)) /2;
            break;
        case 12:
            psav->YExpansion = 0x00070003;
            psav->displayYoffset = (PanelSizeY - ((7 * ViewPortHeight)/3)) /2;
            break;
        case 14:
            psav->YExpansion = 0x00050002;
            psav->displayYoffset = (PanelSizeY - ((5 * ViewPortHeight)/2)) /2;
            break;
        case 15:
            psav->YExpansion = 0x00040001;
            psav->displayYoffset = (PanelSizeY - (4 * ViewPortHeight)) /2;
            break;
    }

    psav->XExp1 = psav->XExpansion >> 16;
    psav->XExp2 = psav->XExpansion & 0xFFFF;
    psav->YExp1 = psav->YExpansion >> 16;
    psav->YExp2 = psav->YExpansion & 0xFFFF;
}  /* InitStreamsForExpansionPM */

