#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

#include "radeon.h"
#include "radeon_reg.h"
#include "radeon_macros.h"
#include "radeon_probe.h"
#include "radeon_video.h"

#include "xf86.h"
#include "dixstruct.h"
#include "atipciids.h"
#include "xf86fbman.h"

/* DPMS */
#ifdef HAVE_XEXTPROTO_71
#include <X11/extensions/dpmsconst.h>
#else
#define DPMS_SERVER
#include <X11/extensions/dpms.h>
#endif

#include <X11/extensions/Xv.h>
#include "fourcc.h"

#include "theatre_detect.h"
#include "theatre_reg.h"
#include "fi1236.h"
#include "msp3430.h"
#include "tda9885.h"

#define OFF_DELAY       250  /* milliseconds */
#define FREE_DELAY      15000

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

#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)

/* capture config constants */
#define BUF_TYPE_FIELD          0
#define BUF_TYPE_ALTERNATING    1
#define BUF_TYPE_FRAME          2


#define BUF_MODE_SINGLE         0
#define BUF_MODE_DOUBLE         1
#define BUF_MODE_TRIPLE         2
/* CAP0_CONFIG values */

#define FORMAT_BROOKTREE        0
#define FORMAT_CCIR656          1
#define FORMAT_ZV               2
#define FORMAT_VIP16            3
#define FORMAT_TRANSPORT        4

#define ENABLE_RADEON_CAPTURE_WEAVE (RADEON_CAP0_CONFIG_CONTINUOS \
                        | (BUF_MODE_DOUBLE <<7) \
                        | (BUF_TYPE_FRAME << 4) \
                        | ( (pPriv->theatre !=NULL)?(FORMAT_CCIR656<<23):(FORMAT_BROOKTREE<<23)) \
                        | RADEON_CAP0_CONFIG_HORZ_DECIMATOR \
                        | (pPriv->capture_vbi_data ? RADEON_CAP0_CONFIG_VBI_EN : 0) \
                        | RADEON_CAP0_CONFIG_VIDEO_IN_VYUY422)

#define ENABLE_RADEON_CAPTURE_BOB (RADEON_CAP0_CONFIG_CONTINUOS \
                        | (BUF_MODE_SINGLE <<7)  \
                        | (BUF_TYPE_ALTERNATING << 4) \
                        | ( (pPriv->theatre !=NULL)?(FORMAT_CCIR656<<23):(FORMAT_BROOKTREE<<23)) \
                        | RADEON_CAP0_CONFIG_HORZ_DECIMATOR \
                        | (pPriv->capture_vbi_data ? RADEON_CAP0_CONFIG_VBI_EN : 0) \
                        | RADEON_CAP0_CONFIG_VIDEO_IN_VYUY422)


static void RADEONInitOffscreenImages(ScreenPtr);

static XF86VideoAdaptorPtr RADEONSetupImageVideo(ScreenPtr);
static int  RADEONPutImage(ScrnInfoPtr, short, short, short, short, short,
			short, short, short, int, unsigned char*, short,
			short, Bool, RegionPtr, pointer,
			DrawablePtr);
static void RADEONVideoTimerCallback(ScrnInfoPtr pScrn, Time now);
static int RADEONPutVideo(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, DrawablePtr pDraw);

static void RADEON_board_setmisc(RADEONPortPrivPtr pPriv);
static void RADEON_RT_SetEncoding(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv);
static void RADEON_MSP_SetEncoding(RADEONPortPrivPtr pPriv);
static void RADEON_TDA9885_SetEncoding(RADEONPortPrivPtr pPriv);
static void RADEON_FI1236_SetEncoding(RADEONPortPrivPtr pPriv);

static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer;
static Atom xvRedIntensity, xvGreenIntensity, xvBlueIntensity;
static Atom xvContrast, xvHue, xvColor, xvAutopaintColorkey, xvSetDefaults;
static Atom xvGamma, xvColorspace;
static Atom xvCRTC;
static Atom xvEncoding, xvFrequency, xvVolume, xvMute,
	     xvDecBrightness, xvDecContrast, xvDecHue, xvDecColor, xvDecSaturation,
	     xvTunerStatus, xvSAP, xvOverlayDeinterlacingMethod,
	     xvLocationID, xvDeviceID, xvInstanceID, xvDumpStatus,
	     xvAdjustment;
	     
static Atom xvOvAlpha, xvGrAlpha, xvAlphaMode;

#define GET_PORT_PRIVATE(pScrn) \
   (RADEONPortPrivPtr)((RADEONPTR(pScrn))->adaptor->pPortPrivates[0].ptr)

static void
radeon_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
{
    dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
    dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
    dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
    dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;

    if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
	dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
}

static void
radeon_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
{
    if (crtc->enabled) {
	crtc_box->x1 = crtc->x;
	crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
	crtc_box->y1 = crtc->y;
	crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
    } else
	crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
}

static int
radeon_box_area(BoxPtr box)
{
    return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
}

static Bool
radeon_crtc_is_enabled(xf86CrtcPtr crtc)
{
    RADEONCrtcPrivatePtr radeon_crtc;

#ifdef XF86DRM_MODE
    if (RADEONPTR(crtc->scrn)->cs) {
	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
	return drmmode_crtc->dpms_mode == DPMSModeOn;
    }
#endif

    radeon_crtc = crtc->driver_private;
    return radeon_crtc->enabled;
}

xf86CrtcPtr
radeon_pick_best_crtc(ScrnInfoPtr pScrn,
		      int x1, int x2, int y1, int y2)
{
    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
    int			coverage, best_coverage, c;
    BoxRec		box, crtc_box, cover_box;
    RROutputPtr         primary_output = NULL;
    xf86CrtcPtr         best_crtc = NULL, primary_crtc = NULL;

    if (!pScrn->vtSema)
	return NULL;

    box.x1 = x1;
    box.x2 = x2;
    box.y1 = y1;
    box.y2 = y2;
    best_coverage = 0;

    /* Prefer the CRTC of the primary output */
#ifdef HAS_DIXREGISTERPRIVATEKEY
    if (dixPrivateKeyRegistered(rrPrivKey))
#endif
    {
	primary_output = RRFirstOutput(pScrn->pScreen);
    }
    if (primary_output && primary_output->crtc)
	primary_crtc = primary_output->crtc->devPrivate;

    for (c = 0; c < xf86_config->num_crtc; c++) {
	xf86CrtcPtr crtc = xf86_config->crtc[c];

	if (!radeon_crtc_is_enabled(crtc))
	    continue;

	radeon_crtc_box(crtc, &crtc_box);
	radeon_box_intersect(&cover_box, &crtc_box, &box);
	coverage = radeon_box_area(&cover_box);
	if (coverage > best_coverage ||
	    (coverage == best_coverage && crtc == primary_crtc)) {
	    best_crtc = crtc;
	    best_coverage = coverage;
	}
    }
    return best_crtc;
}

#ifndef HAVE_XF86CRTCCLIPVIDEOHELPER
static xf86CrtcPtr
radeon_covering_crtc(ScrnInfoPtr pScrn,
		     BoxPtr	box,
		     xf86CrtcPtr desired,
		     BoxPtr	crtc_box_ret)
{
    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
    xf86CrtcPtr		crtc, best_crtc;
    int			coverage, best_coverage;
    int			c;
    BoxRec		crtc_box, cover_box;

    best_crtc = NULL;
    best_coverage = 0;
    crtc_box_ret->x1 = 0;
    crtc_box_ret->x2 = 0;
    crtc_box_ret->y1 = 0;
    crtc_box_ret->y2 = 0;
    for (c = 0; c < xf86_config->num_crtc; c++) {
	crtc = xf86_config->crtc[c];
	radeon_crtc_box(crtc, &crtc_box);
	radeon_box_intersect(&cover_box, &crtc_box, box);
	coverage = radeon_box_area(&cover_box);
	if (coverage && crtc == desired) {
	    *crtc_box_ret = crtc_box;
	    return crtc;
	} else if (coverage > best_coverage) {
	    *crtc_box_ret = crtc_box;
	    best_crtc = crtc;
	    best_coverage = coverage;
	}
    }
    return best_crtc;
}

static Bool
radeon_crtc_clip_video_helper(ScrnInfoPtr pScrn,
			      xf86CrtcPtr *crtc_ret,
			      xf86CrtcPtr desired_crtc,
			      BoxPtr      dst,
			      INT32	  *xa,
			      INT32	  *xb,
			      INT32	  *ya,
			      INT32	  *yb,
			      RegionPtr   reg,
			      INT32	  width,
			      INT32	  height)
{
    Bool	ret;
    RegionRec	crtc_region_local;
    RegionPtr	crtc_region = reg;
    
    /*
     * For overlay video, compute the relevant CRTC and
     * clip video to that
     */
    if (crtc_ret) {
	BoxRec		crtc_box;
	xf86CrtcPtr	crtc = radeon_covering_crtc(pScrn, dst,
						    desired_crtc,
						    &crtc_box);

	if (crtc) {
	    REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1);
	    crtc_region = &crtc_region_local;
	    REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg);
	}
	*crtc_ret = crtc;
    }

    ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, 
				crtc_region, width, height);

    if (crtc_region != reg)
	REGION_UNINIT (pScreen, &crtc_region_local);

    return ret;
}
#endif

static Bool
radeon_crtc_clip_video(ScrnInfoPtr pScrn,
		       xf86CrtcPtr *crtc_ret,
		       xf86CrtcPtr desired_crtc,
		       BoxPtr      dst,
		       INT32       *xa,
		       INT32       *xb,
		       INT32       *ya,
		       INT32       *yb,
		       RegionPtr   reg,
		       INT32       width,
		       INT32       height)
{
#ifndef HAVE_XF86CRTCCLIPVIDEOHELPER
    return radeon_crtc_clip_video_helper(pScrn, crtc_ret, desired_crtc,
				       dst, xa, xb, ya, yb,
				       reg, width, height);
#else
    return xf86_crtc_clip_video_helper(pScrn, crtc_ret, desired_crtc,
				       dst, xa, xb, ya, yb,
				       reg, width, height);
#endif
}

void RADEONInitVideo(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    RADEONInfoPtr    info = RADEONPTR(pScrn);
    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
    XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL;
    int num_adaptors;

    /* no overlay or 3D on RN50 */
    if (info->ChipFamily == CHIP_FAMILY_RV100 && !pRADEONEnt->HasCRTC2)
	    return;

    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
    newAdaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *));
    if (newAdaptors == NULL)
	return;

    memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
    adaptors = newAdaptors;

    if (!IS_AVIVO_VARIANT && !info->kms_enabled) {
	overlayAdaptor = RADEONSetupImageVideo(pScreen);
	if (overlayAdaptor != NULL) {
	    adaptors[num_adaptors++] = overlayAdaptor;
	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up overlay video\n");
	} else
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set up overlay video\n");
	RADEONInitOffscreenImages(pScreen);
    }

    if ((info->ChipFamily < CHIP_FAMILY_RS400)
#ifdef XF86DRI
	|| (info->directRenderingEnabled)
#endif
	) {
	texturedAdaptor = RADEONSetupImageTexturedVideo(pScreen);
	if (texturedAdaptor != NULL) {
	    adaptors[num_adaptors++] = texturedAdaptor;
	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up textured video\n");
	} else
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set up textured video\n");
    } else
	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Textured video requires CP on R5xx/R6xx/R7xx/IGP\n");

    if(num_adaptors)
	xf86XVScreenInit(pScreen, adaptors, num_adaptors);

    if(texturedAdaptor) {
	XF86MCAdaptorPtr xvmcAdaptor = RADEONCreateAdaptorXvMC(pScreen, texturedAdaptor->name);
	if(xvmcAdaptor) {
	    if(!xf86XvMCScreenInit(pScreen, 1, &xvmcAdaptor))
		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[XvMC] Failed to initialize extension.\n");
	    else
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[XvMC] Extension initialized.\n");
	}
    }

    if(newAdaptors)
	free(newAdaptors);

}

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

 /* the picture is interlaced - hence the half-heights */

static XF86VideoEncodingRec
InputVideoEncodings[] =
{
    { 0, "XV_IMAGE",			2047,2047,{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",		640, 240, { 1001, 60000 }},
    { 5, "ntsc-tuner",			640, 240, { 1001, 60000 }},
    { 6, "ntsc-svideo",			640, 240, { 1001, 60000 }},
    { 7, "secam-composite",		720, 288, { 1, 50 }},
    { 8, "secam-tuner",			720, 288, { 1, 50 }},
    { 9, "secam-svideo",		720, 288, { 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 NUM_FORMATS 12

static XF86VideoFormatRec Formats[NUM_FORMATS] =
{
   {8, TrueColor}, {8, DirectColor}, {8, PseudoColor},
   {8, GrayScale}, {8, StaticGray}, {8, StaticColor},
   {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
   {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
};


#if 0
#define NUM_ATTRIBUTES 9+6

static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
{
   {XvSettable             ,     0,    1, "XV_SET_DEFAULTS"},
   {XvSettable | XvGettable,     0,    1, "XV_AUTOPAINT_COLORKEY"},
   {XvSettable | XvGettable,     0,   ~0, "XV_COLORKEY"},
   {XvSettable | XvGettable,     0,    1, "XV_DOUBLE_BUFFER"},
   {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
   {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
   {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
   {XvSettable | XvGettable, -1000, 1000, "XV_COLOR"},
   {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
   {XvSettable | XvGettable, -1000, 1000, "XV_RED_INTENSITY"},
   {XvSettable | XvGettable, -1000, 1000, "XV_GREEN_INTENSITY"},
   {XvSettable | XvGettable, -1000, 1000, "XV_BLUE_INTENSITY"},
   {XvSettable | XvGettable,     -1,    1, "XV_CRTC"},
   {XvSettable | XvGettable,   100, 10000, "XV_GAMMA"},
   {XvSettable | XvGettable,     0,    1, "XV_COLORSPACE"},
};

#endif

#define NUM_ATTRIBUTES 22
#define NUM_DEC_ATTRIBUTES (NUM_ATTRIBUTES+12)

static XF86AttributeRec Attributes[NUM_DEC_ATTRIBUTES+1] =
{
   {             XvGettable, 0, ~0, "XV_DEVICE_ID"},
   {             XvGettable, 0, ~0, "XV_LOCATION_ID"},
   {             XvGettable, 0, ~0, "XV_INSTANCE_ID"},
   {XvSettable		   , 0, 1, "XV_DUMP_STATUS"},
   {XvSettable             , 0, 1, "XV_SET_DEFAULTS"},
   {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
   {XvSettable | XvGettable, 0, ~0,"XV_COLORKEY"},
   {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
   {XvSettable | XvGettable,     0,  255, "XV_OVERLAY_ALPHA"},
   {XvSettable | XvGettable,     0,  255, "XV_GRAPHICS_ALPHA"},
   {XvSettable | XvGettable,     0,    1, "XV_ALPHA_MODE"},
   {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
   {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
   {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
   {XvSettable | XvGettable, -1000, 1000, "XV_COLOR"},
   {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
   {XvSettable | XvGettable, -1000, 1000, "XV_RED_INTENSITY"},
   {XvSettable | XvGettable, -1000, 1000, "XV_GREEN_INTENSITY"},
   {XvSettable | XvGettable, -1000, 1000, "XV_BLUE_INTENSITY"},
   {XvSettable | XvGettable,     -1,    1, "XV_CRTC"},
   {XvSettable | XvGettable,   100, 10000, "XV_GAMMA"},
   {XvSettable | XvGettable,     0,    1, "XV_COLORSPACE"},
   
   {XvSettable | XvGettable, -1000, 1000, "XV_DEC_BRIGHTNESS"},
   {XvSettable | XvGettable, -1000, 1000, "XV_DEC_CONTRAST"},
   {XvSettable | XvGettable, -1000, 1000, "XV_DEC_SATURATION"},
   {XvSettable | XvGettable, -1000, 1000, "XV_DEC_HUE"},
   {XvSettable | XvGettable, 0, 2, "XV_OVERLAY_DEINTERLACING_METHOD"},
   {XvSettable | XvGettable, 0, 12, "XV_ENCODING"},
   {XvSettable | XvGettable, 0, -1, "XV_FREQ"},
   {             XvGettable, -1000, 1000, "XV_TUNER_STATUS"},
   {XvSettable | XvGettable, -1000, 1000, "XV_VOLUME"},
   {XvSettable | XvGettable, 0, 1, "XV_MUTE"},
   {XvSettable | XvGettable, 0, 1, "XV_SAP"},
   {XvSettable | XvGettable, 0, 0x1F, "XV_DEBUG_ADJUSTMENT"},   
   { 0, 0, 0, NULL}  /* just a place holder so I don't have to be fancy with commas */
};


#define INCLUDE_RGB_FORMATS 1

#if INCLUDE_RGB_FORMATS

#define NUM_IMAGES 8

/* Note: GUIDs are bogus... - but nothing uses them anyway */

#define FOURCC_RGBA32   0x41424752

#define XVIMAGE_RGBA32(byte_order)   \
        { \
                FOURCC_RGBA32, \
                XvRGB, \
                byte_order, \
                { 'R', 'G', 'B', 'A', \
                  0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
                32, \
                XvPacked, \
                1, \
                32, 0x00FF0000, 0x0000FF00, 0x000000FF, \
                0, 0, 0, 0, 0, 0, 0, 0, 0, \
                {'A', 'R', 'G', '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}, \
                XvTopToBottom \
        }               

#define FOURCC_RGB24    0x00000000

#define XVIMAGE_RGB24   \
        { \
                FOURCC_RGB24, \
                XvRGB, \
                LSBFirst, \
                { 'R', 'G', 'B', 0, \
                  0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
                24, \
                XvPacked, \
                1, \
                24, 0x00FF0000, 0x0000FF00, 0x000000FF, \
                0, 0, 0, 0, 0, 0, 0, 0, 0, \
                { 'R', 'G', '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 \
        }

#define FOURCC_RGBT16   0x54424752

#define XVIMAGE_RGBT16(byte_order)   \
        { \
                FOURCC_RGBT16, \
                XvRGB, \
                byte_order, \
                { 'R', 'G', 'B', 'T', \
                  0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
                16, \
                XvPacked, \
                1, \
                16, 0x00007C00, 0x000003E0, 0x0000001F, \
                0, 0, 0, 0, 0, 0, 0, 0, 0, \
                {'A', 'R', 'G', '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}, \
                XvTopToBottom \
        }               

#define FOURCC_RGB16    0x32424752

#define XVIMAGE_RGB16(byte_order)   \
        { \
                FOURCC_RGB16, \
                XvRGB, \
                byte_order, \
                { 'R', 'G', 'B', 0x00, \
                  0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
                16, \
                XvPacked, \
                1, \
                16, 0x0000F800, 0x000007E0, 0x0000001F, \
                0, 0, 0, 0, 0, 0, 0, 0, 0, \
                {'R', 'G', '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 \
        }               

static XF86ImageRec Images[NUM_IMAGES] =
{
#if X_BYTE_ORDER == X_BIG_ENDIAN
        XVIMAGE_RGBA32(MSBFirst),
        XVIMAGE_RGBT16(MSBFirst),
        XVIMAGE_RGB16(MSBFirst),
#else
        XVIMAGE_RGBA32(LSBFirst),
        XVIMAGE_RGBT16(LSBFirst),
        XVIMAGE_RGB16(LSBFirst),
#endif
        XVIMAGE_RGB24,
        XVIMAGE_YUY2,
        XVIMAGE_UYVY,
        XVIMAGE_YV12,
        XVIMAGE_I420
};

#else

#define NUM_IMAGES 4

static XF86ImageRec Images[NUM_IMAGES] =
{
    XVIMAGE_YUY2,
    XVIMAGE_UYVY,
    XVIMAGE_YV12,
    XVIMAGE_I420
};

#endif

/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces */
static REF_TRANSFORM trans[2] =
{
    {1.1678, 0.0, 1.6007, -0.3929, -0.8154, 2.0232, 0.0}, /* BT.601 */
    {1.1678, 0.0, 1.7980, -0.2139, -0.5345, 2.1186, 0.0}  /* BT.709 */
};

/* Gamma curve definition for preset gammas */
typedef struct tagGAMMA_CURVE_R100
{
    uint32_t GAMMA_0_F_SLOPE;
    uint32_t GAMMA_0_F_OFFSET;
    uint32_t GAMMA_10_1F_SLOPE;
    uint32_t GAMMA_10_1F_OFFSET;
    uint32_t GAMMA_20_3F_SLOPE;
    uint32_t GAMMA_20_3F_OFFSET;
    uint32_t GAMMA_40_7F_SLOPE;
    uint32_t GAMMA_40_7F_OFFSET;
    uint32_t GAMMA_380_3BF_SLOPE;
    uint32_t GAMMA_380_3BF_OFFSET;
    uint32_t GAMMA_3C0_3FF_SLOPE;
    uint32_t GAMMA_3C0_3FF_OFFSET;
    float OvGammaCont;
} GAMMA_CURVE_R100;

typedef struct tagGAMMA_CURVE_R200
{
    uint32_t GAMMA_0_F_SLOPE;
    uint32_t GAMMA_0_F_OFFSET;
    uint32_t GAMMA_10_1F_SLOPE;
    uint32_t GAMMA_10_1F_OFFSET;
    uint32_t GAMMA_20_3F_SLOPE;
    uint32_t GAMMA_20_3F_OFFSET;
    uint32_t GAMMA_40_7F_SLOPE;
    uint32_t GAMMA_40_7F_OFFSET;
    uint32_t GAMMA_80_BF_SLOPE;
    uint32_t GAMMA_80_BF_OFFSET;
    uint32_t GAMMA_C0_FF_SLOPE;
    uint32_t GAMMA_C0_FF_OFFSET;
    uint32_t GAMMA_100_13F_SLOPE;
    uint32_t GAMMA_100_13F_OFFSET;
    uint32_t GAMMA_140_17F_SLOPE;
    uint32_t GAMMA_140_17F_OFFSET;
    uint32_t GAMMA_180_1BF_SLOPE;
    uint32_t GAMMA_180_1BF_OFFSET;
    uint32_t GAMMA_1C0_1FF_SLOPE;
    uint32_t GAMMA_1C0_1FF_OFFSET;
    uint32_t GAMMA_200_23F_SLOPE;
    uint32_t GAMMA_200_23F_OFFSET;
    uint32_t GAMMA_240_27F_SLOPE;
    uint32_t GAMMA_240_27F_OFFSET;
    uint32_t GAMMA_280_2BF_SLOPE;
    uint32_t GAMMA_280_2BF_OFFSET;
    uint32_t GAMMA_2C0_2FF_SLOPE;
    uint32_t GAMMA_2C0_2FF_OFFSET;
    uint32_t GAMMA_300_33F_SLOPE;
    uint32_t GAMMA_300_33F_OFFSET;
    uint32_t GAMMA_340_37F_SLOPE;
    uint32_t GAMMA_340_37F_OFFSET;
    uint32_t GAMMA_380_3BF_SLOPE;
    uint32_t GAMMA_380_3BF_OFFSET;
    uint32_t GAMMA_3C0_3FF_SLOPE;
    uint32_t GAMMA_3C0_3FF_OFFSET;
    float OvGammaCont;
} GAMMA_CURVE_R200;


/* Preset gammas */
static GAMMA_CURVE_R100 gamma_curve_r100[8] = 
{
	/* Gamma 1.0 */
	{0x100, 0x0, 
	 0x100, 0x20, 
	 0x100, 0x40, 
	 0x100, 0x80, 
	 0x100, 0x100, 
	 0x100, 0x100, 
	 1.0},
	/* Gamma 0.85 */
	{0x75,  0x0, 
	 0xA2,  0xF,  
	 0xAC,  0x23, 
	 0xC6,  0x4E, 
	 0x129, 0xD6, 
	 0x12B, 0xD5, 
	 1.0},
	/* Gamma 1.1 */
	{0x180, 0x0, 
	 0x13C, 0x30, 
	 0x13C, 0x57, 
	 0x123, 0xA5, 
	 0xEA,  0x116, 
	 0xEA, 0x116, 
	 0.9913},
	/* Gamma 1.2 */
	{0x21B, 0x0, 
	 0x16D, 0x43, 
	 0x172, 0x71, 
	 0x13D, 0xCD, 
	 0xD9,  0x128, 
	 0xD6, 0x12A, 
	 0.9827},
	/* Gamma 1.45 */
	{0x404, 0x0, 
	 0x1B9, 0x81, 
	 0x1EE, 0xB8, 
	 0x16A, 0x133, 
	 0xB7, 0x14B, 
	 0xB2, 0x14E, 
	 0.9567},
	/* Gamma 1.7 */
	{0x658, 0x0, 
	 0x1B5, 0xCB, 
	 0x25F, 0x102, 
	 0x181, 0x199, 
	 0x9C,  0x165, 
	 0x98, 0x167, 
	 0.9394},
	/* Gamma 2.2 */
	{0x7FF, 0x0, 
	 0x625, 0x100, 
	 0x1E4, 0x1C4, 
	 0x1BD, 0x23D, 
	 0x79,  0x187, 
	 0x76,  0x188, 
	 0.9135},
	/* Gamma 2.5 */
	{0x7FF, 0x0, 
	 0x7FF, 0x100, 
	 0x2AD, 0x200, 
	 0x1A2, 0x2AB, 
	 0x6E,  0x194, 
	 0x67,  0x197, 
	 0.9135}
};

static GAMMA_CURVE_R200 gamma_curve_r200[8] =
 {
	/* Gamma 1.0 */
      {0x00000100, 0x00000000,
       0x00000100, 0x00000020,
       0x00000100, 0x00000040,
       0x00000100, 0x00000080,
       0x00000100, 0x00000100,
       0x00000100, 0x00000100,
       0x00000100, 0x00000200,
       0x00000100, 0x00000200,
       0x00000100, 0x00000300,
       0x00000100, 0x00000300,
       0x00000100, 0x00000400,
       0x00000100, 0x00000400,
       0x00000100, 0x00000500,
       0x00000100, 0x00000500,
       0x00000100, 0x00000600,
       0x00000100, 0x00000600,
       0x00000100, 0x00000700,
       0x00000100, 0x00000700,
       1.0},
	/* Gamma 0.85 */
      {0x0000001D, 0x00000000,
       0x00000028, 0x0000000F,
       0x00000056, 0x00000023,
       0x000000C5, 0x0000004E,
       0x000000DA, 0x000000B0,
       0x000000E6, 0x000000AA,
       0x000000F1, 0x00000190,
       0x000000F9, 0x0000018C,
       0x00000101, 0x00000286,
       0x00000108, 0x00000282,
       0x0000010D, 0x0000038A,
       0x00000113, 0x00000387,
       0x00000118, 0x0000049A,
       0x0000011C, 0x00000498,
       0x00000120, 0x000005B4,
       0x00000124, 0x000005B2,
       0x00000128, 0x000006D6,
       0x0000012C, 0x000006D5,
       1.0},
	/* Gamma 1.1 */
      {0x00000060, 0x00000000,
       0x0000004F, 0x00000030,
       0x0000009C, 0x00000057,
       0x00000121, 0x000000A5,
       0x00000113, 0x00000136,
       0x0000010B, 0x0000013A,
       0x00000105, 0x00000245,
       0x00000100, 0x00000247,
       0x000000FD, 0x00000348,
       0x000000F9, 0x00000349,
       0x000000F6, 0x00000443,
       0x000000F4, 0x00000444,
       0x000000F2, 0x00000538,
       0x000000F0, 0x00000539,
       0x000000EE, 0x00000629,
       0x000000EC, 0x00000629,
       0x000000EB, 0x00000716,
       0x000000E9, 0x00000717,
       0.9913},
	/* Gamma 1.2 */
      {0x00000087, 0x00000000,
       0x0000005B, 0x00000043,
       0x000000B7, 0x00000071,
       0x0000013D, 0x000000CD,
       0x00000121, 0x0000016B,
       0x00000113, 0x00000172,
       0x00000107, 0x00000286,
       0x000000FF, 0x0000028A,
       0x000000F8, 0x00000389,
       0x000000F2, 0x0000038B,
       0x000000ED, 0x0000047D,
       0x000000E9, 0x00000480,
       0x000000E5, 0x00000568,
       0x000000E1, 0x0000056A,
       0x000000DE, 0x0000064B,
       0x000000DB, 0x0000064D,
       0x000000D9, 0x00000728,
       0x000000D6, 0x00000729,
       0.9827},
	/* Gamma 1.45 */
      {0x00000101, 0x00000000,
       0x0000006E, 0x00000081,
       0x000000F7, 0x000000B8,
       0x0000016E, 0x00000133,
       0x00000139, 0x000001EA,
       0x0000011B, 0x000001F9,
       0x00000105, 0x00000314,
       0x000000F6, 0x0000031C,
       0x000000E9, 0x00000411,
       0x000000DF, 0x00000417,
       0x000000D7, 0x000004F6,
       0x000000CF, 0x000004F9,
       0x000000C9, 0x000005C9,
       0x000000C4, 0x000005CC,
       0x000000BF, 0x0000068F,
       0x000000BA, 0x00000691,
       0x000000B6, 0x0000074B,
       0x000000B2, 0x0000074D,
       0.9567},
	/* Gamma 1.7 */
      {0x00000196, 0x00000000,
       0x0000006D, 0x000000CB,
       0x0000012F, 0x00000102,
       0x00000187, 0x00000199,
       0x00000144, 0x0000025b,
       0x00000118, 0x00000273,
       0x000000FE, 0x0000038B,
       0x000000E9, 0x00000395,
       0x000000DA, 0x0000047E,
       0x000000CE, 0x00000485,
       0x000000C3, 0x00000552,
       0x000000BB, 0x00000556,
       0x000000B3, 0x00000611,
       0x000000AC, 0x00000614,
       0x000000A7, 0x000006C1,
       0x000000A1, 0x000006C3,
       0x0000009D, 0x00000765,
       0x00000098, 0x00000767,
       0.9394},
	/* Gamma 2.2 */
      {0x000001FF, 0x00000000,
       0x0000018A, 0x00000100,
       0x000000F1, 0x000001C5,
       0x000001D6, 0x0000023D,
       0x00000124, 0x00000328,
       0x00000116, 0x0000032F,
       0x000000E2, 0x00000446,
       0x000000D3, 0x0000044D,
       0x000000BC, 0x00000520,
       0x000000B0, 0x00000526,
       0x000000A4, 0x000005D6,
       0x0000009B, 0x000005DB,
       0x00000092, 0x00000676,
       0x0000008B, 0x00000679,
       0x00000085, 0x00000704,
       0x00000080, 0x00000707,
       0x0000007B, 0x00000787,
       0x00000076, 0x00000789,
       0.9135},
	/* Gamma 2.5 */
      {0x000001FF, 0x00000000,
       0x000001FF, 0x00000100,
       0x00000159, 0x000001FF,
       0x000001AC, 0x000002AB,
       0x0000012F, 0x00000381,
       0x00000101, 0x00000399,
       0x000000D9, 0x0000049A,
       0x000000C3, 0x000004A5,
       0x000000AF, 0x00000567,
       0x000000A1, 0x0000056E,
       0x00000095, 0x00000610,
       0x0000008C, 0x00000614,
       0x00000084, 0x000006A0,
       0x0000007D, 0x000006A4,
       0x00000077, 0x00000721,
       0x00000071, 0x00000723,
       0x0000006D, 0x00000795,
       0x00000068, 0x00000797,
       0.9135}
};

static void
RADEONSetOverlayGamma(ScrnInfoPtr pScrn, uint32_t gamma)
{
    RADEONInfoPtr    info = RADEONPTR(pScrn);
    unsigned char   *RADEONMMIO = info->MMIO;

    /* Set gamma */
    RADEONWaitForIdleMMIO(pScrn);

    if (info->ChipFamily < CHIP_FAMILY_R200) {
	uint32_t ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL) & ~RADEON_SCALER_GAMMA_SEL_MASK;
	OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl | (gamma << 5));
    }

    /* Load gamma curve adjustments */
    if (info->ChipFamily >= CHIP_FAMILY_R200) {
    	OUTREG(RADEON_OV0_GAMMA_000_00F,
	    (gamma_curve_r200[gamma].GAMMA_0_F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_0_F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_010_01F,
	    (gamma_curve_r200[gamma].GAMMA_10_1F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_10_1F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_020_03F,
	    (gamma_curve_r200[gamma].GAMMA_20_3F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_20_3F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_040_07F,
	    (gamma_curve_r200[gamma].GAMMA_40_7F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_40_7F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_080_0BF,
	    (gamma_curve_r200[gamma].GAMMA_80_BF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_80_BF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_0C0_0FF,
	    (gamma_curve_r200[gamma].GAMMA_C0_FF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_C0_FF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_100_13F,
	    (gamma_curve_r200[gamma].GAMMA_100_13F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_100_13F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_140_17F,
	    (gamma_curve_r200[gamma].GAMMA_140_17F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_140_17F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_180_1BF,
	    (gamma_curve_r200[gamma].GAMMA_180_1BF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_180_1BF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_1C0_1FF,
	    (gamma_curve_r200[gamma].GAMMA_1C0_1FF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_1C0_1FF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_200_23F,
	    (gamma_curve_r200[gamma].GAMMA_200_23F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_200_23F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_240_27F,
	    (gamma_curve_r200[gamma].GAMMA_240_27F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_240_27F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_280_2BF,
	    (gamma_curve_r200[gamma].GAMMA_280_2BF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_280_2BF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_2C0_2FF,
	    (gamma_curve_r200[gamma].GAMMA_2C0_2FF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_2C0_2FF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_300_33F,
	    (gamma_curve_r200[gamma].GAMMA_300_33F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_300_33F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_340_37F,
	    (gamma_curve_r200[gamma].GAMMA_340_37F_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_340_37F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_380_3BF,
	    (gamma_curve_r200[gamma].GAMMA_380_3BF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_380_3BF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_3C0_3FF,
	    (gamma_curve_r200[gamma].GAMMA_3C0_3FF_OFFSET << 0x00000000) |
	    (gamma_curve_r200[gamma].GAMMA_3C0_3FF_SLOPE << 0x00000010));
    } else {
    	OUTREG(RADEON_OV0_GAMMA_000_00F,
	    (gamma_curve_r100[gamma].GAMMA_0_F_OFFSET << 0x00000000) |
	    (gamma_curve_r100[gamma].GAMMA_0_F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_010_01F,
	    (gamma_curve_r100[gamma].GAMMA_10_1F_OFFSET << 0x00000000) |
	    (gamma_curve_r100[gamma].GAMMA_10_1F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_020_03F,
	    (gamma_curve_r100[gamma].GAMMA_20_3F_OFFSET << 0x00000000) |
	    (gamma_curve_r100[gamma].GAMMA_20_3F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_040_07F,
	    (gamma_curve_r100[gamma].GAMMA_40_7F_OFFSET << 0x00000000) |
	    (gamma_curve_r100[gamma].GAMMA_40_7F_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_380_3BF,
	    (gamma_curve_r100[gamma].GAMMA_380_3BF_OFFSET << 0x00000000) |
	    (gamma_curve_r100[gamma].GAMMA_380_3BF_SLOPE << 0x00000010));
    	OUTREG(RADEON_OV0_GAMMA_3C0_3FF,
	    (gamma_curve_r100[gamma].GAMMA_3C0_3FF_OFFSET << 0x00000000) |
	    (gamma_curve_r100[gamma].GAMMA_3C0_3FF_SLOPE << 0x00000010));
    }

}

static uint32_t
RADEONTranslateUserGamma(uint32_t user_gamma)
{
    /* translate from user_gamma (gamma x 1000) to radeon gamma table index value */
    if (user_gamma <= 925)       /* 0.85 */
	return 1;
    else if (user_gamma <= 1050) /* 1.0  */
	return 0;
    else if (user_gamma <= 1150) /* 1.1  */
	return 2;
    else if (user_gamma <= 1325) /* 1.2  */
	return 3;
    else if (user_gamma <= 1575) /* 1.45 */
	return 4;
    else if (user_gamma <= 1950) /* 1.7  */
	return 5;
    else if (user_gamma <= 2350) /* 2.2  */
	return 6;
    else if (user_gamma > 2350)  /* 2.5  */
	return 7;
    else
	return 0;
}


/****************************************************************************
 * SetTransform                                                             *
 *  Function: Calculates and sets color space transform from supplied       *
 *            reference transform, gamma, brightness, contrast, hue and     *
 *            saturation.                                                   *
 *    Inputs: bright - brightness                                           *
 *            cont - contrast                                               *
 *            sat - saturation                                              *
 *            hue - hue                                                     *
 *            red_intensity - intensity of red component                    *
 *            green_intensity - intensity of green component                *
 *            blue_intensity - intensity of blue component                  *
 *            ref - index to the table of refernce transforms               *
 *            user_gamma - gamma value x 1000 (e.g., 1200 = gamma of 1.2)   *
 *   Outputs: NONE                                                          *
 ****************************************************************************/

static void RADEONSetTransform (ScrnInfoPtr pScrn,
				float	    bright,
				float	    cont,
				float	    sat,
				float	    hue,
				float	    red_intensity,
				float	    green_intensity,
				float	    blue_intensity,
				uint32_t    ref,
				uint32_t    user_gamma)
{
    RADEONInfoPtr    info = RADEONPTR(pScrn);
    unsigned char   *RADEONMMIO = info->MMIO;
    float	    OvHueSin, OvHueCos;
    float	    CAdjLuma, CAdjOff;
    float	    CAdjRCb, CAdjRCr;
    float	    CAdjGCb, CAdjGCr;
    float	    CAdjBCb, CAdjBCr;
    float	    RedAdj,GreenAdj,BlueAdj;
    float	    OvLuma, OvROff, OvGOff, OvBOff;
    float	    OvRCb, OvRCr;
    float	    OvGCb, OvGCr;
    float	    OvBCb, OvBCr;
    float	    Loff = 64.0;
    float	    Coff = 512.0f;

    uint32_t	    dwOvLuma, dwOvROff, dwOvGOff, dwOvBOff;
    uint32_t	    dwOvRCb, dwOvRCr;
    uint32_t	    dwOvGCb, dwOvGCr;
    uint32_t	    dwOvBCb, dwOvBCr;
    uint32_t	    gamma = 0;

    if (ref >= 2)
	return;

    /* translate from user_gamma (gamma x 1000) to radeon gamma table index value */
    gamma = RADEONTranslateUserGamma(user_gamma);

    if (gamma >= 8) 
	return;

    OvHueSin = sin(hue);
    OvHueCos = cos(hue);

    CAdjLuma = cont * trans[ref].RefLuma;
    CAdjOff = cont * trans[ref].RefLuma * bright * 1023.0;
    RedAdj = cont * trans[ref].RefLuma * red_intensity * 1023.0;
    GreenAdj = cont * trans[ref].RefLuma * green_intensity * 1023.0;
    BlueAdj = cont * trans[ref].RefLuma * blue_intensity * 1023.0;

    CAdjRCb = sat * -OvHueSin * trans[ref].RefRCr;
    CAdjRCr = sat * OvHueCos * trans[ref].RefRCr;
    CAdjGCb = sat * (OvHueCos * trans[ref].RefGCb - OvHueSin * trans[ref].RefGCr);
    CAdjGCr = sat * (OvHueSin * trans[ref].RefGCb + OvHueCos * trans[ref].RefGCr);
    CAdjBCb = sat * OvHueCos * trans[ref].RefBCb;
    CAdjBCr = sat * OvHueSin * trans[ref].RefBCb;

#if 0 /* default constants */
    CAdjLuma = 1.16455078125;

    CAdjRCb = 0.0;
    CAdjRCr = 1.59619140625;
    CAdjGCb = -0.39111328125;
    CAdjGCr = -0.8125;
    CAdjBCb = 2.01708984375;
    CAdjBCr = 0;
#endif

    OvLuma = CAdjLuma * gamma_curve_r100[gamma].OvGammaCont;
    OvRCb = CAdjRCb * gamma_curve_r100[gamma].OvGammaCont;
    OvRCr = CAdjRCr * gamma_curve_r100[gamma].OvGammaCont;
    OvGCb = CAdjGCb * gamma_curve_r100[gamma].OvGammaCont;
    OvGCr = CAdjGCr * gamma_curve_r100[gamma].OvGammaCont;
    OvBCb = CAdjBCb * gamma_curve_r100[gamma].OvGammaCont;
    OvBCr = CAdjBCr * gamma_curve_r100[gamma].OvGammaCont;
    OvROff = RedAdj + CAdjOff * gamma_curve_r100[gamma].OvGammaCont - 
	OvLuma * Loff - (OvRCb + OvRCr) * Coff;
    OvGOff = GreenAdj + CAdjOff * gamma_curve_r100[gamma].OvGammaCont - 
	OvLuma * Loff - (OvGCb + OvGCr) * Coff;
    OvBOff = BlueAdj + CAdjOff * gamma_curve_r100[gamma].OvGammaCont - 
	OvLuma * Loff - (OvBCb + OvBCr) * Coff;
#if 0 /* default constants */
    OvROff = -888.5;
    OvGOff = 545;
    OvBOff = -1104;
#endif

    OvROff = ClipValue(OvROff, -2048.0, 2047.5);
    OvGOff = ClipValue(OvGOff, -2048.0, 2047.5);
    OvBOff = ClipValue(OvBOff, -2048.0, 2047.5);
    dwOvROff = ((INT32)(OvROff * 2.0)) & 0x1fff;
    dwOvGOff = ((INT32)(OvGOff * 2.0)) & 0x1fff;
    dwOvBOff = ((INT32)(OvBOff * 2.0)) & 0x1fff;

    if(info->ChipFamily == CHIP_FAMILY_RADEON)
    {
	dwOvLuma =(((INT32)(OvLuma * 2048.0))&0x7fff)<<17;
	dwOvRCb = (((INT32)(OvRCb * 2048.0))&0x7fff)<<1;
	dwOvRCr = (((INT32)(OvRCr * 2048.0))&0x7fff)<<17;
	dwOvGCb = (((INT32)(OvGCb * 2048.0))&0x7fff)<<1;
	dwOvGCr = (((INT32)(OvGCr * 2048.0))&0x7fff)<<17;
	dwOvBCb = (((INT32)(OvBCb * 2048.0))&0x7fff)<<1;
	dwOvBCr = (((INT32)(OvBCr * 2048.0))&0x7fff)<<17;
    }
    else
    {
	dwOvLuma = (((INT32)(OvLuma * 256.0))&0xfff)<<20;
	dwOvRCb = (((INT32)(OvRCb * 256.0))&0xfff)<<4;
	dwOvRCr = (((INT32)(OvRCr * 256.0))&0xfff)<<20;
	dwOvGCb = (((INT32)(OvGCb * 256.0))&0xfff)<<4;
	dwOvGCr = (((INT32)(OvGCr * 256.0))&0xfff)<<20;
	dwOvBCb = (((INT32)(OvBCb * 256.0))&0xfff)<<4;
	dwOvBCr = (((INT32)(OvBCr * 256.0))&0xfff)<<20;
    }

    /* set gamma */
    RADEONSetOverlayGamma(pScrn, gamma);

    /* color transforms */
    OUTREG(RADEON_OV0_LIN_TRANS_A, dwOvRCb | dwOvLuma);
    OUTREG(RADEON_OV0_LIN_TRANS_B, dwOvROff | dwOvRCr);
    OUTREG(RADEON_OV0_LIN_TRANS_C, dwOvGCb | dwOvLuma);
    OUTREG(RADEON_OV0_LIN_TRANS_D, dwOvGOff | dwOvGCr);
    OUTREG(RADEON_OV0_LIN_TRANS_E, dwOvBCb | dwOvLuma);
    OUTREG(RADEON_OV0_LIN_TRANS_F, dwOvBOff | dwOvBCr);
}

static void RADEONSetOverlayAlpha(ScrnInfoPtr pScrn, int ov_alpha, int gr_alpha, int alpha_mode)
{
    RADEONInfoPtr info = RADEONPTR(pScrn);
    unsigned char *RADEONMMIO = info->MMIO;

    if (alpha_mode == 0) { /* key mode */
    	OUTREG(RADEON_OV0_KEY_CNTL, 
		RADEON_GRAPHIC_KEY_FN_EQ | /* what does this do? */
		RADEON_VIDEO_KEY_FN_FALSE | /* what does this do? */
		RADEON_CMP_MIX_OR);
    	/* crtc 1 */
    	OUTREG(RADEON_DISP_MERGE_CNTL,
		(RADEON_DISP_ALPHA_MODE_KEY & 
		RADEON_DISP_ALPHA_MODE_MASK) |
		((gr_alpha << 0x00000010) & 
		RADEON_DISP_GRPH_ALPHA_MASK) |
		((ov_alpha << 0x00000018) & 
		RADEON_DISP_OV0_ALPHA_MASK));
    	/* crtc 2 */
    	OUTREG(RADEON_DISP2_MERGE_CNTL,
		(RADEON_DISP_ALPHA_MODE_KEY & 
		RADEON_DISP_ALPHA_MODE_MASK) |
		((gr_alpha << 0x00000010) & 
		RADEON_DISP_GRPH_ALPHA_MASK) |
		((ov_alpha << 0x00000018) & 
		RADEON_DISP_OV0_ALPHA_MASK));
    } else { /* global mode */
    	OUTREG(RADEON_OV0_KEY_CNTL, 
		RADEON_GRAPHIC_KEY_FN_FALSE |   /* what does this do? */
		RADEON_VIDEO_KEY_FN_FALSE |   /* what does this do? */
		RADEON_CMP_MIX_AND);
    	/* crtc 2 */
    	OUTREG(RADEON_DISP2_MERGE_CNTL,
		(RADEON_DISP_ALPHA_MODE_GLOBAL & 
		RADEON_DISP_ALPHA_MODE_MASK) |
		((gr_alpha << 0x00000010) & 
		RADEON_DISP_GRPH_ALPHA_MASK) |
		((ov_alpha << 0x00000018) & 
		RADEON_DISP_OV0_ALPHA_MASK));
    	/* crtc 1 */
    	OUTREG(RADEON_DISP_MERGE_CNTL,
		(RADEON_DISP_ALPHA_MODE_GLOBAL & 
		RADEON_DISP_ALPHA_MODE_MASK) |
		((gr_alpha << 0x00000010) & 
		RADEON_DISP_GRPH_ALPHA_MASK) |
		((ov_alpha << 0x00000018) & 
		RADEON_DISP_OV0_ALPHA_MASK));
    }
     /* per-pixel mode - RADEON_DISP_ALPHA_MODE_PER_PIXEL */
     /* not yet supported */
}

static void RADEONSetColorKey(ScrnInfoPtr pScrn, uint32_t colorKey)
{
    RADEONInfoPtr info = RADEONPTR(pScrn);
    unsigned char *RADEONMMIO = info->MMIO;
    uint32_t min, max;
    uint8_t r, g, b;

    if (info->CurrentLayout.depth > 8)
    {
	uint32_t	rbits, gbits, bbits;

	rbits = (colorKey & pScrn->mask.red) >> pScrn->offset.red;
	gbits = (colorKey & pScrn->mask.green) >> pScrn->offset.green;
	bbits = (colorKey & pScrn->mask.blue) >> pScrn->offset.blue;

	r = rbits << (8 - pScrn->weight.red);
	g = gbits << (8 - pScrn->weight.green);
	b = bbits << (8 - pScrn->weight.blue);
    }
    else
    {
	uint32_t	bits;

	bits = colorKey & ((1 << info->CurrentLayout.depth) - 1);
	r = bits;
	g = bits;
	b = bits;
    }
    min = (r << 16) | (g << 8) | (b);
    max = (0xff << 24) | (r << 16) | (g << 8) | (b);

    RADEONWaitForFifo(pScrn, 2);
    OUTREG(RADEON_OV0_GRAPHICS_KEY_CLR_HIGH, max);
    OUTREG(RADEON_OV0_GRAPHICS_KEY_CLR_LOW, min);
}

void
RADEONResetVideo(ScrnInfoPtr pScrn)
{
    RADEONInfoPtr   info      = RADEONPTR(pScrn);
    unsigned char *RADEONMMIO = info->MMIO;
    RADEONPortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
    char tmp[200];

    /* this function is called from ScreenInit. pScreen is used 
       by XAA internally, but not valid until ScreenInit finishs.
    */
    if (info->accelOn && pScrn->pScreen)
	RADEON_SYNC(info, pScrn);

    /* this is done here because each time the server is reset these
       could change.. Otherwise they remain constant */
    xvInstanceID = MAKE_ATOM("XV_INSTANCE_ID");
    xvDeviceID = MAKE_ATOM("XV_DEVICE_ID");
    xvLocationID = MAKE_ATOM("XV_LOCATION_ID");
    xvDumpStatus = MAKE_ATOM("XV_DUMP_STATUS");
 
    xvBrightness   = MAKE_ATOM("XV_BRIGHTNESS");
    xvSaturation   = MAKE_ATOM("XV_SATURATION");
    xvColor        = MAKE_ATOM("XV_COLOR");
    xvContrast     = MAKE_ATOM("XV_CONTRAST");
    xvColorKey     = MAKE_ATOM("XV_COLORKEY");
    xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
    xvHue          = MAKE_ATOM("XV_HUE");
    xvRedIntensity   = MAKE_ATOM("XV_RED_INTENSITY");
    xvGreenIntensity = MAKE_ATOM("XV_GREEN_INTENSITY");
    xvBlueIntensity  = MAKE_ATOM("XV_BLUE_INTENSITY");
    xvGamma          = MAKE_ATOM("XV_GAMMA");
    xvColorspace     = MAKE_ATOM("XV_COLORSPACE");

    xvAutopaintColorkey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
    xvSetDefaults       = MAKE_ATOM("XV_SET_DEFAULTS");
    xvCRTC              = MAKE_ATOM("XV_CRTC");

    xvOvAlpha	      = MAKE_ATOM("XV_OVERLAY_ALPHA");
    xvGrAlpha	      = MAKE_ATOM("XV_GRAPHICS_ALPHA");
    xvAlphaMode       = MAKE_ATOM("XV_ALPHA_MODE");

    xvOverlayDeinterlacingMethod = MAKE_ATOM("XV_OVERLAY_DEINTERLACING_METHOD");

    xvDecBrightness   = MAKE_ATOM("XV_DEC_BRIGHTNESS");
    xvDecSaturation   = MAKE_ATOM("XV_DEC_SATURATION");
    xvDecColor        = MAKE_ATOM("XV_DEC_COLOR");
    xvDecContrast     = MAKE_ATOM("XV_DEC_CONTRAST");
    xvDecHue          = MAKE_ATOM("XV_DEC_HUE");

    xvEncoding        = MAKE_ATOM("XV_ENCODING");
    xvFrequency       = MAKE_ATOM("XV_FREQ");
    xvTunerStatus     = MAKE_ATOM("XV_TUNER_STATUS");
    xvVolume          = MAKE_ATOM("XV_VOLUME");
    xvMute            = MAKE_ATOM("XV_MUTE");
    xvSAP             = MAKE_ATOM("XV_SAP");

    xvAdjustment      = MAKE_ATOM("XV_DEBUG_ADJUSTMENT");

    sprintf(tmp, "RXXX:%d.%d.%d", PCI_DEV_VENDOR_ID(info->PciInfo),
	    PCI_DEV_DEVICE_ID(info->PciInfo), PCI_DEV_REVISION(info->PciInfo));
    pPriv->device_id = MAKE_ATOM(tmp);
    sprintf(tmp, "PCI:%02d:%02d.%d", PCI_DEV_BUS(info->PciInfo),
	    PCI_DEV_DEV(info->PciInfo), PCI_DEV_FUNC(info->PciInfo));
    pPriv->location_id = MAKE_ATOM(tmp);
    sprintf(tmp, "INSTANCE:%d", pScrn->scrnIndex);
    pPriv->instance_id = MAKE_ATOM(tmp);

    OUTREG(RADEON_OV0_SCALE_CNTL, RADEON_SCALER_SOFT_RESET);
    OUTREG(RADEON_OV0_AUTO_FLIP_CNTL, 0);   /* maybe */
    OUTREG(RADEON_OV0_EXCLUSIVE_HORZ, 0);
    OUTREG(RADEON_OV0_FILTER_CNTL, RADEON_FILTER_PROGRAMMABLE_COEF);
    OUTREG(RADEON_OV0_KEY_CNTL, RADEON_GRAPHIC_KEY_FN_EQ |
				RADEON_VIDEO_KEY_FN_FALSE |
				RADEON_CMP_MIX_OR);
    OUTREG(RADEON_OV0_TEST, 0);
    OUTREG(RADEON_FCP_CNTL, RADEON_FCP0_SRC_GND);
    OUTREG(RADEON_CAP0_TRIG_CNTL, 0);
    RADEONSetColorKey(pScrn, pPriv->colorKey);

    if (info->ChipFamily == CHIP_FAMILY_RADEON) {

	OUTREG(RADEON_OV0_LIN_TRANS_A, 0x12a00000);
	OUTREG(RADEON_OV0_LIN_TRANS_B, 0x1990190e);
	OUTREG(RADEON_OV0_LIN_TRANS_C, 0x12a0f9c0);
	OUTREG(RADEON_OV0_LIN_TRANS_D, 0xf3000442);
	OUTREG(RADEON_OV0_LIN_TRANS_E, 0x12a02040);
	OUTREG(RADEON_OV0_LIN_TRANS_F, 0x175f);

    } else {

	OUTREG(RADEON_OV0_LIN_TRANS_A, 0x12a20000);
	OUTREG(RADEON_OV0_LIN_TRANS_B, 0x198a190e);
	OUTREG(RADEON_OV0_LIN_TRANS_C, 0x12a2f9da);
	OUTREG(RADEON_OV0_LIN_TRANS_D, 0xf2fe0442);
	OUTREG(RADEON_OV0_LIN_TRANS_E, 0x12a22046);
	OUTREG(RADEON_OV0_LIN_TRANS_F, 0x175f);
    }
	/*
	 * Set default Gamma ramp:
	 *
	 * Of 18 segments for gamma curve, all segments in R200 (and
	 * newer) are programmable, while only lower 4 and upper 2
	 * segments are programmable in the older Radeons.
	 */

    RADEONSetOverlayGamma(pScrn, 0); /* gamma = 1.0 */

    if(pPriv->VIP!=NULL){
        RADEONVIP_reset(pScrn,pPriv);
        }
    
    if(pPriv->theatre != NULL) {
        xf86_InitTheatre(pPriv->theatre);
/*      xf86_ResetTheatreRegsForNoTVout(pPriv->theatre); */
        }
    
    if(pPriv->i2c != NULL){
        RADEONResetI2C(pScrn, pPriv);
        }
}

static void RADEONSetupTheatre(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
{
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RADEONPLLPtr  pll = &(info->pll);
    TheatrePtr t;

    uint8_t a;
    int i;
              
    pPriv->theatre = NULL;

    if(!info->MM_TABLE_valid && 
       !((info->RageTheatreCrystal>=0) &&
           (info->RageTheatreTunerPort>=0) && (info->RageTheatreCompositePort>=0) &&
           (info->RageTheatreSVideoPort>=0)))
    {
       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "no multimedia table present, disabling Rage Theatre.\n");
       return;
    }

    /* Go and find Rage Theatre, if it exists */
    
    if (info->IsMobility)
	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Detected Radeon Mobility, not scanning for Rage Theatre\n");
    else
	pPriv->theatre=xf86_DetectTheatre(pPriv->VIP);

    if(pPriv->theatre==NULL)return;
    
    /* just a matter of convenience */
    t=pPriv->theatre; 
        
    t->video_decoder_type=info->video_decoder_type;
        
    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "video decoder type is 0x%04x (BIOS value) versus 0x%04x (current PLL setting)\n",
         t->video_decoder_type, pll->xclk);
        
    if(info->MM_TABLE_valid){
         for(i=0;i<5;i++){
                a=info->MM_TABLE.input[i];
                
                switch(a & 0x3){
                        case 1:
                                t->wTunerConnector=i;
                                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Tuner is on port %d\n",i);
                                break;
                        case 2:  if(a & 0x4){
                                   t->wComp0Connector=RT_COMP2;
                                   } else {
                                   t->wComp0Connector=RT_COMP1;
                                   }
                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Composite connector is port %u\n", (unsigned)t->wComp0Connector);
                                  break;
                        case 3:  if(a & 0x4){
                                   t->wSVideo0Connector=RT_YCR_COMP4;
                                   } else {
                                   t->wSVideo0Connector=RT_YCF_COMP4;
                                   }
                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SVideo connector is port %u\n", (unsigned)t->wSVideo0Connector);
                                   break;
                        default:
                                break;
                        }
                }
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Rage Theatre: Connectors (detected): tuner=%u, composite=%u, svideo=%u\n",
    	     (unsigned)t->wTunerConnector, (unsigned)t->wComp0Connector, (unsigned)t->wSVideo0Connector);
        
         }

    if(info->RageTheatreTunerPort>=0)t->wTunerConnector=info->RageTheatreTunerPort;
    if(info->RageTheatreCompositePort>=0)t->wComp0Connector=info->RageTheatreCompositePort;
    if(info->RageTheatreSVideoPort>=0)t->wSVideo0Connector=info->RageTheatreSVideoPort;
        
    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RageTheatre: Connectors (using): tuner=%u, composite=%u, svideo=%u\n",
    	(unsigned)t->wTunerConnector, (unsigned)t->wComp0Connector, (unsigned)t->wSVideo0Connector);

    switch((info->RageTheatreCrystal>=0)?info->RageTheatreCrystal:pll->reference_freq){
                case 2700:
                        t->video_decoder_type=RT_FREF_2700;
                        break;
                case 2950:
                        t->video_decoder_type=RT_FREF_2950;
                        break;
                default:
                        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                                "Unsupported reference clock frequency, Rage Theatre disabled\n");
                        t->theatre_num=-1;
			free(pPriv->theatre);
			pPriv->theatre = NULL;
			return;
                }
    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "video decoder type used: 0x%04x\n", t->video_decoder_type);
}

static XF86VideoAdaptorPtr
RADEONAllocAdaptor(ScrnInfoPtr pScrn)
{
    XF86VideoAdaptorPtr adapt;
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RADEONPortPrivPtr pPriv;
    uint32_t dot_clock;
    int ecp;

    if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
	return NULL;

    if(!(pPriv = calloc(1, sizeof(RADEONPortPrivRec) + sizeof(DevUnion))))
    {
	free(adapt);
	return NULL;
    }

    adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
    adapt->pPortPrivates[0].ptr = (pointer)pPriv;

    pPriv->colorKey = info->videoKey;
    pPriv->doubleBuffer = TRUE;
    pPriv->videoStatus = 0;
    pPriv->brightness = 0;
    pPriv->transform_index = 0;
    pPriv->saturation = 0;
    pPriv->contrast = 0;
    pPriv->red_intensity = 0;
    pPriv->green_intensity = 0;
    pPriv->blue_intensity = 0;
    pPriv->hue = 0;
    pPriv->currentBuffer = 0;
    pPriv->autopaint_colorkey = TRUE;
    pPriv->gamma = 1000;
    pPriv->desired_crtc = NULL;

    pPriv->ov_alpha = 255;
    pPriv->gr_alpha = 255;
    pPriv->alpha_mode = 0;

       /* TV-in stuff */
    pPriv->video_stream_active = FALSE;
    pPriv->encoding = 4;
    pPriv->frequency = 1000;
    pPriv->volume = -1000;
    pPriv->mute = TRUE;
    pPriv->v = 0;
    pPriv->overlay_deinterlacing_method = METHOD_BOB;
    pPriv->capture_vbi_data = 0;
    pPriv->dec_brightness = 0;
    pPriv->dec_saturation = 0;
    pPriv->dec_contrast = 0;
    pPriv->dec_hue = 0;


    /*
     * Unlike older Mach64 chips, RADEON has only two ECP settings:
     * 0 for PIXCLK < 175Mhz, and 1 (divide by 2)
     * for higher clocks, sure makes life nicer
     */
    dot_clock = info->ModeReg->dot_clock_freq;

    if (dot_clock < 17500)
        info->ecp_div = 0;
    else
        info->ecp_div = 1;
    ecp = (INPLL(pScrn, RADEON_VCLK_ECP_CNTL) & 0xfffffCff) | (info->ecp_div << 8);

    if (info->IsIGP) {
        /* Force the overlay clock on for integrated chips
	 */
        ecp |= (1<<18);
    }

    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, ecp);


    /* Decide on tuner type */
    if((info->tunerType<0) && (info->MM_TABLE_valid)) {
        pPriv->tuner_type = info->MM_TABLE.tuner_type;
    	} else
        pPriv->tuner_type = info->tunerType;
        
    /* Initialize I2C bus */
    RADEONInitI2C(pScrn, pPriv);
    if(pPriv->i2c != NULL)RADEON_board_setmisc(pPriv);
    

    #if 0  /* this is just here for easy debugging - normally off */
    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Scanning I2C Bus\n");
    for(i=0;i<255;i+=2)
        if(RADEONProbeAddress(pPriv->i2c, i))
                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "     found device at address 0x%02x\n", i);
    #endif

    /* resetting the VIP bus causes problems with some mobility chips.
     * we don't support video in on any mobility chips at the moment anyway
     */
    /* Initialize VIP bus */
    if (!info->IsMobility)
	RADEONVIP_init(pScrn, pPriv);

    info->adaptor = adapt;
    info->xv_max_width = 2047;
    info->xv_max_height = 2047;

	if(!xf86LoadSubModule(pScrn,"theatre_detect")) 
	{
		xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Unable to load Rage Theatre detect module\n");
		goto skip_theatre;
    }
	RADEONSetupTheatre(pScrn, pPriv);

	/*
	 * Now load the correspondind theatre chip based on what has been detected. 
	 */
	if (pPriv->theatre)
	{
		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Going to load the corresponding theatre module\n");
		switch (pPriv->theatre->theatre_id)
		{
			case RT100_ATI_ID:
			{
				if(!xf86LoadSubModule(pScrn,"theatre")) 
				{
					xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Unable to load Rage Theatre module\n");
					free(pPriv->theatre);
					goto skip_theatre;
				}
				break;
			}
			case RT200_ATI_ID:
			{
				if(!xf86LoadSubModule(pScrn,"theatre200")) 
				{
					xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Unable to load Rage Theatre module\n");
					free(pPriv->theatre);
					goto skip_theatre;
				}
				pPriv->theatre->microc_path = info->RageTheatreMicrocPath;
				pPriv->theatre->microc_type = info->RageTheatreMicrocType;
				break;
			}
			default:
			{
				xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Unknown Theatre chip\n");
				free(pPriv->theatre);
				goto skip_theatre;
			}
		}
	}
    
	if(pPriv->theatre!=NULL)
	{
		xf86_InitTheatre(pPriv->theatre);
		if(pPriv->theatre->mode == MODE_UNINITIALIZED)
		{
			free(pPriv->theatre);
			pPriv->theatre = NULL;
			xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Rage Theatre disabled\n");
			/* Here the modules must be unloaded */
			goto skip_theatre;
		}
	}
  
    if(pPriv->theatre!=NULL){	
        xf86_ResetTheatreRegsForNoTVout(pPriv->theatre);
        xf86_RT_SetTint(pPriv->theatre, pPriv->dec_hue);
        xf86_RT_SetSaturation(pPriv->theatre, pPriv->dec_saturation);
        xf86_RT_SetSharpness(pPriv->theatre, RT_NORM_SHARPNESS);
        xf86_RT_SetContrast(pPriv->theatre, pPriv->dec_contrast);
        xf86_RT_SetBrightness(pPriv->theatre, pPriv->dec_brightness);  
	
        RADEON_RT_SetEncoding(pScrn, pPriv);	
	}
	
skip_theatre:

    return adapt;
}

static XF86VideoAdaptorPtr
RADEONSetupImageVideo(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    RADEONPortPrivPtr pPriv;
    XF86VideoAdaptorPtr adapt;

    if(!(adapt = RADEONAllocAdaptor(pScrn)))
	return NULL;

    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
    adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT*/;
    adapt->name = "ATI Radeon Video Overlay";
    adapt->nEncodings = 1;
    adapt->pEncodings = &DummyEncoding;
    adapt->nFormats = NUM_FORMATS;
    adapt->pFormats = Formats;
    adapt->nPorts = 1;
    adapt->nAttributes = NUM_ATTRIBUTES;
    adapt->pAttributes = Attributes;
    adapt->nImages = NUM_IMAGES;
    adapt->pImages = Images;
    adapt->PutVideo = NULL;
    adapt->PutStill = NULL;
    adapt->GetVideo = NULL;
    adapt->GetStill = NULL;
    adapt->StopVideo = RADEONStopVideo;
    adapt->SetPortAttribute = RADEONSetPortAttribute;
    adapt->GetPortAttribute = RADEONGetPortAttribute;
    adapt->QueryBestSize = RADEONQueryBestSize;
    adapt->PutImage = RADEONPutImage;
    adapt->QueryImageAttributes = RADEONQueryImageAttributes;

    pPriv = (RADEONPortPrivPtr)(adapt->pPortPrivates[0].ptr);
    REGION_NULL(pScreen, &(pPriv->clip));

    pPriv->textured = FALSE;

    if(pPriv->theatre != NULL) {
	/* video decoder is present, extend capabilities */
       adapt->nEncodings = 13;
       adapt->pEncodings = InputVideoEncodings;
       adapt->type |= XvVideoMask;
       adapt->nAttributes = NUM_DEC_ATTRIBUTES;
       adapt->PutVideo = RADEONPutVideo;
    }

    RADEONResetVideo(pScrn);

    return adapt;
}

void
RADEONFreeVideoMemory(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
{
    RADEONInfoPtr info = RADEONPTR(pScrn);

    if (pPriv->video_memory != NULL) {
	radeon_legacy_free_memory(pScrn, pPriv->video_memory);
	pPriv->video_memory = NULL;

	if (info->cs && pPriv->textured) {
	    pPriv->src_bo[0] = NULL;
	    radeon_legacy_free_memory(pScrn, pPriv->src_bo[1]);
	    pPriv->src_bo[1] = NULL;
	}
    }
}

void
RADEONStopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
{
  RADEONInfoPtr info = RADEONPTR(pScrn);
  unsigned char *RADEONMMIO = info->MMIO;
  RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;

  if (pPriv->textured) {
      if (cleanup) {
	  RADEONFreeVideoMemory(pScrn, pPriv);
      }
      return;
  }

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

  if(cleanup) {
     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
	RADEONWaitForFifo(pScrn, 2);
	OUTREG(RADEON_OV0_SCALE_CNTL, 0);
     }
     if(pPriv->video_stream_active){
        RADEONWaitForFifo(pScrn, 2);
        OUTREG(RADEON_FCP_CNTL, RADEON_FCP0_SRC_GND);
        OUTREG(RADEON_CAP0_TRIG_CNTL, 0);
        RADEONResetVideo(pScrn);
        pPriv->video_stream_active = FALSE;
        if(pPriv->msp3430 != NULL) xf86_MSP3430SetVolume(pPriv->msp3430, MSP3430_FAST_MUTE);
		if(pPriv->uda1380 != NULL) xf86_uda1380_mute(pPriv->uda1380, TRUE);
        if(pPriv->i2c != NULL) RADEON_board_setmisc(pPriv);
     }
     RADEONFreeVideoMemory(pScrn, pPriv);
     pPriv->videoStatus = 0;
  } else {
     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
	pPriv->videoStatus |= OFF_TIMER;
	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
     }
  }
}

int
RADEONSetPortAttribute(ScrnInfoPtr  pScrn,
		       Atom	    attribute,
		       INT32	    value,
		       pointer	    data)
{
    RADEONInfoPtr	info = RADEONPTR(pScrn);
    RADEONPortPrivPtr	pPriv = (RADEONPortPrivPtr)data;
    Bool		setTransform = FALSE;
    Bool		setAlpha = FALSE;
    unsigned char *RADEONMMIO = info->MMIO;

    RADEON_SYNC(info, pScrn);

    if(attribute == xvAutopaintColorkey)
    {
	pPriv->autopaint_colorkey = ClipValue (value, 0, 1);
    }
    else if(attribute == xvSetDefaults)
    {
	pPriv->autopaint_colorkey = TRUE;
	pPriv->brightness = 0;
	pPriv->saturation = 0;
	pPriv->contrast = 0;
	pPriv->hue = 0;
	pPriv->red_intensity = 0;
	pPriv->green_intensity = 0;
	pPriv->blue_intensity = 0;
	pPriv->gamma = 1000;
	pPriv->transform_index = 0;
	pPriv->doubleBuffer = FALSE;
	pPriv->ov_alpha = 255;
	pPriv->gr_alpha = 255;
	pPriv->alpha_mode = 0;

        /* It is simpler to call itself */
        RADEONSetPortAttribute(pScrn, xvDecBrightness, 0, data);
        RADEONSetPortAttribute(pScrn, xvDecSaturation, 0, data);
        RADEONSetPortAttribute(pScrn, xvDecContrast,   0, data);
        RADEONSetPortAttribute(pScrn, xvDecHue,   0, data);

        RADEONSetPortAttribute(pScrn, xvVolume,   -1000, data);
        RADEONSetPortAttribute(pScrn, xvMute,   1, data);
        RADEONSetPortAttribute(pScrn, xvSAP,   0, data);
        RADEONSetPortAttribute(pScrn, xvDoubleBuffer,   1, data);

	setTransform = TRUE;
	setAlpha = TRUE;
    }
    else if(attribute == xvBrightness)
    {
	pPriv->brightness = ClipValue (value, -1000, 1000);
	setTransform = TRUE;
    }
    else if((attribute == xvSaturation) || (attribute == xvColor))
    {
	pPriv->saturation = ClipValue (value, -1000, 1000);
	setTransform = TRUE;
    }
    else if(attribute == xvContrast)
    {
	pPriv->contrast = ClipValue (value, -1000, 1000);
	setTransform = TRUE;
    }
    else if(attribute == xvHue)
    {
	pPriv->hue = ClipValue (value, -1000, 1000);
	setTransform = TRUE;
    }
    else if(attribute == xvRedIntensity)
    {
	pPriv->red_intensity = ClipValue (value, -1000, 1000);
	setTransform = TRUE;
    }
    else if(attribute == xvGreenIntensity)
    {
	pPriv->green_intensity = ClipValue (value, -1000, 1000);
	setTransform = TRUE;
    }
    else if(attribute == xvBlueIntensity)
    {
	pPriv->blue_intensity = ClipValue (value, -1000, 1000);
	setTransform = TRUE;
    }
    else if(attribute == xvGamma) 
    {
	pPriv->gamma = ClipValue (value, 100, 10000);
	setTransform = TRUE;
    } 
    else if(attribute == xvColorspace) 
    {
	pPriv->transform_index = ClipValue (value, 0, 1);
	setTransform = TRUE;
    } 
    else if(attribute == xvDoubleBuffer)
    {
	pPriv->doubleBuffer = ClipValue (value, 0, 1);
    }
    else if(attribute == xvColorKey)
    {
	pPriv->colorKey = value;
	RADEONSetColorKey (pScrn, pPriv->colorKey);
	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
    } 
    else if(attribute == xvCRTC) 
    {
	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
	if ((value < -1) || (value > xf86_config->num_crtc))
	    return BadValue;
	if (value < 0)
	    pPriv->desired_crtc = NULL;
	else
	    pPriv->desired_crtc = xf86_config->crtc[value];
    }
    else if(attribute == xvOvAlpha) 
    {
	pPriv->ov_alpha = ClipValue (value, 0, 255);
	setAlpha = TRUE;
    }
    else if(attribute == xvGrAlpha) 
    {
	pPriv->gr_alpha = ClipValue (value, 0, 255);
	setAlpha = TRUE;
    } 
    else if(attribute == xvAlphaMode) 
    {
	pPriv->alpha_mode = ClipValue (value, 0, 1);
	setAlpha = TRUE;
    } 
    else if(attribute == xvDecBrightness) 
    {
        pPriv->dec_brightness = value;
        if(pPriv->theatre!=NULL) xf86_RT_SetBrightness(pPriv->theatre, pPriv->dec_brightness);  
    } 
    else if((attribute == xvDecSaturation) || (attribute == xvDecColor)) 
    {
        if(value<-1000)value = -1000;
        if(value>1000)value = 1000;
        pPriv->dec_saturation = value;
        if(pPriv->theatre != NULL)xf86_RT_SetSaturation(pPriv->theatre, value);
    } 
    else if(attribute == xvDecContrast) 
    {
        pPriv->dec_contrast = value;
        if(pPriv->theatre != NULL)xf86_RT_SetContrast(pPriv->theatre, value);
    } 
    else if(attribute == xvDecHue) 
    {
        pPriv->dec_hue = value;
        if(pPriv->theatre != NULL)xf86_RT_SetTint(pPriv->theatre, value);
    } 
    else if(attribute == xvEncoding) 
    {
        pPriv->encoding = value;
        if(pPriv->video_stream_active)
        {
           if(pPriv->theatre != NULL) RADEON_RT_SetEncoding(pScrn, pPriv);
           if(pPriv->msp3430 != NULL) RADEON_MSP_SetEncoding(pPriv);
           if(pPriv->tda9885 != NULL) RADEON_TDA9885_SetEncoding(pPriv);
	   if(pPriv->fi1236 != NULL) RADEON_FI1236_SetEncoding(pPriv);
           if(pPriv->i2c != NULL) RADEON_board_setmisc(pPriv);
        /* put more here to actually change it */
        }
   } 
   else if(attribute == xvFrequency) 
   {
        pPriv->frequency = value;
        /* mute volume if it was not muted before */
        if((pPriv->msp3430!=NULL)&& !pPriv->mute)xf86_MSP3430SetVolume(pPriv->msp3430, MSP3430_FAST_MUTE);
		if((pPriv->uda1380!=NULL)&& !pPriv->mute)xf86_uda1380_mute(pPriv->uda1380, TRUE);
        if(pPriv->fi1236 != NULL) xf86_TUNER_set_frequency(pPriv->fi1236, value);
/*        if(pPriv->theatre != NULL) RADEON_RT_SetEncoding(pScrn, pPriv);  */
        if((pPriv->msp3430 != NULL) && (pPriv->msp3430->recheck))
                xf86_InitMSP3430(pPriv->msp3430);
        if((pPriv->msp3430 != NULL)&& !pPriv->mute) xf86_MSP3430SetVolume(pPriv->msp3430, MSP3430_VOLUME(pPriv->volume));
		if((pPriv->uda1380 != NULL)&& !pPriv->mute) xf86_uda1380_setvolume(pPriv->uda1380, pPriv->volume);
   } 
   else if(attribute == xvMute) 
   {
        pPriv->mute = value;
        if(pPriv->msp3430 != NULL) xf86_MSP3430SetVolume(pPriv->msp3430, pPriv->mute ? MSP3430_FAST_MUTE : MSP3430_VOLUME(pPriv->volume));
        if(pPriv->i2c != NULL) RADEON_board_setmisc(pPriv);
		if(pPriv->uda1380 != NULL) xf86_uda1380_mute(pPriv->uda1380, pPriv->mute);
   } 
   else if(attribute == xvSAP) 
   {
        pPriv->sap_channel = value;
        if(pPriv->msp3430 != NULL) xf86_MSP3430SetSAP(pPriv->msp3430, pPriv->sap_channel?4:3);
   } 
   else if(attribute == xvVolume) 
   {
        if(value<-1000)value = -1000;
        if(value>1000)value = 1000;
        pPriv->volume = value;  
        pPriv->mute = FALSE;
        if(pPriv->msp3430 != NULL) xf86_MSP3430SetVolume(pPriv->msp3430, MSP3430_VOLUME(value));
        if(pPriv->i2c != NULL) RADEON_board_setmisc(pPriv);
		if(pPriv->uda1380 != NULL) xf86_uda1380_setvolume(pPriv->uda1380, value);
   } 
   else if(attribute == xvOverlayDeinterlacingMethod) 
   {
        if(value<0)value = 0;
        if(value>2)value = 2;
        pPriv->overlay_deinterlacing_method = value;    
        switch(pPriv->overlay_deinterlacing_method){
                case METHOD_BOB:
                        OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0xAAAAA);
                        break;
                case METHOD_SINGLE:
                        OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0xEEEEE | (9<<28));
                        break;
                case METHOD_WEAVE:
                        OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0x0);
                        break;
                default:
                        OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0xAAAAA);
                }                       
   } 
   else if(attribute == xvDumpStatus) 
   {
  	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Current mode flags 0x%08x: %s%s\n",
		pScrn->currentMode->Flags,
		pScrn->currentMode->Flags & V_INTERLACE ? " interlaced" : "" ,
		pScrn->currentMode->Flags & V_DBLSCAN ? " doublescan" : ""
		);
	if(pPriv->tda9885 != NULL){
		xf86_tda9885_getstatus(pPriv->tda9885);
		xf86_tda9885_dumpstatus(pPriv->tda9885);
		}
	if(pPriv->fi1236!=NULL){
		xf86_fi1236_dump_status(pPriv->fi1236);
		}
   }
   else if(attribute == xvAdjustment) 
   {
  	pPriv->adjustment=value;
        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Setting pPriv->adjustment to %u\n",
		   (unsigned)pPriv->adjustment);
  	if(pPriv->tda9885!=0){
		pPriv->tda9885->top_adjustment=value;
		RADEON_TDA9885_SetEncoding(pPriv);
		}
   }
   else 
	return BadMatch;

    if (setTransform)
    {
	RADEONSetTransform(pScrn,
			   RTFBrightness(pPriv->brightness),
			   RTFContrast(pPriv->contrast),
			   RTFSaturation(pPriv->saturation),
			   RTFHue(pPriv->hue),
			   RTFIntensity(pPriv->red_intensity),
			   RTFIntensity(pPriv->green_intensity),
			   RTFIntensity(pPriv->blue_intensity),
			   pPriv->transform_index,
			   pPriv->gamma);
    }

    if (setAlpha)
    {
	RADEONSetOverlayAlpha(pScrn, pPriv->ov_alpha, pPriv->gr_alpha, pPriv->alpha_mode);
    }
	
    return Success;
}

int
RADEONGetPortAttribute(ScrnInfoPtr  pScrn,
		       Atom	    attribute,
		       INT32	    *value,
		       pointer	    data)
{
    RADEONInfoPtr	info = RADEONPTR(pScrn);
    RADEONPortPrivPtr	pPriv = (RADEONPortPrivPtr)data;

    if (info->accelOn) RADEON_SYNC(info, pScrn);

    if(attribute == xvAutopaintColorkey)
	*value = pPriv->autopaint_colorkey;
    else if(attribute == xvBrightness)
	*value = pPriv->brightness;
    else if((attribute == xvSaturation) || (attribute == xvColor))
	*value = pPriv->saturation;
    else if(attribute == xvContrast)
	*value = pPriv->contrast;
    else if(attribute == xvHue)
	*value = pPriv->hue;
    else if(attribute == xvRedIntensity)
	*value = pPriv->red_intensity;
    else if(attribute == xvGreenIntensity)
	*value = pPriv->green_intensity;
    else if(attribute == xvBlueIntensity)
	*value = pPriv->blue_intensity;
    else if(attribute == xvGamma)
	*value = pPriv->gamma;
    else if(attribute == xvColorspace)
	*value = pPriv->transform_index;
    else if(attribute == xvDoubleBuffer)
	*value = pPriv->doubleBuffer ? 1 : 0;
    else if(attribute == xvColorKey)
	*value = pPriv->colorKey;
    else if(attribute == xvCRTC) {
	int		c;
	xf86CrtcConfigPtr	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
	for (c = 0; c < xf86_config->num_crtc; c++)
	    if (xf86_config->crtc[c] == pPriv->desired_crtc)
		break;
	if (c == xf86_config->num_crtc)
	    c = -1;
	*value = c;
    }
    else if(attribute == xvOvAlpha)
	*value = pPriv->ov_alpha;
    else if(attribute == xvGrAlpha)
	*value = pPriv->gr_alpha;
    else if(attribute == xvAlphaMode)
	*value = pPriv->alpha_mode;
    else if(attribute == xvDecBrightness)
        *value = pPriv->dec_brightness;
    else if((attribute == xvDecSaturation) || (attribute == xvDecColor))
        *value = pPriv->dec_saturation;
    else if(attribute == xvDecContrast)
        *value = pPriv->dec_contrast;
    else if(attribute == xvDecHue)
        *value = pPriv->dec_hue;
    else if(attribute == xvEncoding)
        *value = pPriv->encoding;
    else if(attribute == xvFrequency)
        *value = pPriv->frequency;
    else 
    if(attribute == xvTunerStatus) {
        if(pPriv->fi1236==NULL){
                *value=TUNER_OFF;
                } else
                {
                *value = xf86_TUNER_get_afc_hint(pPriv->fi1236);
                }
       } 
    else if(attribute == xvMute)
        *value = pPriv->mute;
    else if(attribute == xvSAP)
        *value = pPriv->sap_channel;
    else if(attribute == xvVolume)
        *value = pPriv->volume;
    else if(attribute == xvOverlayDeinterlacingMethod)
        *value = pPriv->overlay_deinterlacing_method;
    else if(attribute == xvDeviceID)
        *value = pPriv->device_id;
    else if(attribute == xvLocationID)
        *value = pPriv->location_id;
    else if(attribute == xvInstanceID)
        *value = pPriv->instance_id;
    else if(attribute == xvAdjustment)
  	*value = pPriv->adjustment;
    else
	return BadMatch;

    return Success;
}

void
RADEONQueryBestSize(
  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
){
    RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;

    if (!pPriv->textured) {
	if (vid_w > (drw_w << 4))
	    drw_w = vid_w >> 4;
	if (vid_h > (drw_h << 4))
	    drw_h = vid_h >> 4;
    }

  *p_w = drw_w;
  *p_h = drw_h;
}

static struct {
	double range;
	signed char coeff[5][4];
	} TapCoeffs[]=
	{
        {0.25, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13,   13,    3}, }},
        {0.26, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.27, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.28, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.29, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.30, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.31, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.32, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.33, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.34, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.35, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.36, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.37, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.38, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.39, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.40, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.41, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.42, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.43, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.44, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.45, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.46, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.47, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.48, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.49, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.50, {{ 7,    16,  9,  0}, { 7,   16,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 3,   13, 13,  3}, }},
        {0.51, {{ 7,    17,  8,  0}, { 6,   17,  9,  0}, { 5,   15, 11,  1}, { 4,   15, 12,  1}, { 2,   14, 14,  2}, }},
        {0.52, {{ 7,    17,  8,  0}, { 6,   17,  9,  0}, { 5,   16, 11,  0}, { 3,   15, 13,  1}, { 2,   14, 14,  2}, }},
        {0.53, {{ 7,    17,  8,  0}, { 6,   17,  9,  0}, { 5,   16, 11,  0}, { 3,   15, 13,  1}, { 2,   14, 14,  2}, }},
        {0.54, {{ 7,    17,  8,  0}, { 6,   17,  9,  0}, { 4,   17, 11,  0}, { 3,   15, 13,  1}, { 2,   14, 14,  2}, }},
        {0.55, {{ 7,    18,  7,  0}, { 6,   17,  9,  0}, { 4,   17, 11,  0}, { 3,   15, 13,  1}, { 1,   15, 15,  1}, }},
        {0.56, {{ 7,    18,  7,  0}, { 5,   18,  9,  0}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.57, {{ 7,    18,  7,  0}, { 5,   18,  9,  0}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.58, {{ 7,    18,  7,  0}, { 5,   18,  9,  0}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.59, {{ 7,    18,  7,  0}, { 5,   18,  9,  0}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.60, {{ 7,    18,  8, -1}, { 6,   17, 10, -1}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.61, {{ 7,    18,  8, -1}, { 6,   17, 10, -1}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.62, {{ 7,    18,  8, -1}, { 6,   17, 10, -1}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.63, {{ 7,    18,  8, -1}, { 6,   17, 10, -1}, { 4,   17, 11,  0}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.64, {{ 7,    18,  8, -1}, { 6,   17, 10, -1}, { 4,   17, 12, -1}, { 2,   17, 13,  0}, { 1,   15, 15,  1}, }},
        {0.65, {{ 7,    18,  8, -1}, { 6,   17, 10, -1}, { 4,   17, 12, -1}, { 2,   17, 13,  0}, { 0,   16, 16,  0}, }},
        {0.66, {{ 7,    18,  8, -1}, { 6,   18, 10, -2}, { 4,   17, 12, -1}, { 2,   17, 13,  0}, { 0,   16, 16,  0}, }},
        {0.67, {{ 7,    20,  7, -2}, { 5,   19, 10, -2}, { 3,   18, 12, -1}, { 2,   17, 13,  0}, { 0,   16, 16,  0}, }},
        {0.68, {{ 7,    20,  7, -2}, { 5,   19, 10, -2}, { 3,   19, 12, -2}, { 1,   18, 14, -1}, { 0,   16, 16,  0}, }},
        {0.69, {{ 7,    20,  7, -2}, { 5,   19, 10, -2}, { 3,   19, 12, -2}, { 1,   18, 14, -1}, { 0,   16, 16,  0}, }},
        {0.70, {{ 7,    20,  7, -2}, { 5,   20,  9, -2}, { 3,   19, 12, -2}, { 1,   18, 14, -1}, { 0,   16, 16,  0}, }},
        {0.71, {{ 7,    20,  7, -2}, { 5,   20,  9, -2}, { 3,   19, 12, -2}, { 1,   18, 14, -1}, { 0,   16, 16,  0}, }},
        {0.72, {{ 7,    20,  7, -2}, { 5,   20,  9, -2}, { 2,   20, 12, -2}, { 0,   19, 15, -2}, {-1,   17, 17, -1}, }},
        {0.73, {{ 7,    20,  7, -2}, { 4,   21,  9, -2}, { 2,   20, 12, -2}, { 0,   19, 15, -2}, {-1,   17, 17, -1}, }},
        {0.74, {{ 6,    22,  6, -2}, { 4,   21,  9, -2}, { 2,   20, 12, -2}, { 0,   19, 15, -2}, {-1,   17, 17, -1}, }},
        {0.75, {{ 6,    22,  6, -2}, { 4,   21,  9, -2}, { 1,   21, 12, -2}, { 0,   19, 15, -2}, {-1,   17, 17, -1}, }},
        {0.76, {{ 6,    22,  6, -2}, { 4,   21,  9, -2}, { 1,   21, 12, -2}, { 0,   19, 15, -2}, {-1,   17, 17, -1}, }},
        {0.77, {{ 6,    22,  6, -2}, { 3,   22,  9, -2}, { 1,   22, 12, -3}, { 0,   19, 15, -2}, {-2,   18, 18, -2}, }},
        {0.78, {{ 6,    21,  6, -1}, { 3,   22,  9, -2}, { 1,   22, 12, -3}, { 0,   19, 15, -2}, {-2,   18, 18, -2}, }},
        {0.79, {{ 5,    23,  5, -1}, { 3,   22,  9, -2}, { 0,   23, 12, -3}, {-1,   21, 15, -3}, {-2,   18, 18, -2}, }},
        {0.80, {{ 5,    23,  5, -1}, { 3,   23,  8, -2}, { 0,   23, 12, -3}, {-1,   21, 15, -3}, {-2,   18, 18, -2}, }},
        {0.81, {{ 5,    23,  5, -1}, { 2,   24,  8, -2}, { 0,   23, 12, -3}, {-1,   21, 15, -3}, {-2,   18, 18, -2}, }},
        {0.82, {{ 5,    23,  5, -1}, { 2,   24,  8, -2}, { 0,   23, 12, -3}, {-1,   21, 15, -3}, {-3,   19, 19, -3}, }},
        {0.83, {{ 5,    23,  5, -1}, { 2,   24,  8, -2}, { 0,   23, 11, -2}, {-2,   22, 15, -3}, {-3,   19, 19, -3}, }},
        {0.84, {{ 4,    25,  4, -1}, { 1,   25,  8, -2}, { 0,   23, 11, -2}, {-2,   22, 15, -3}, {-3,   19, 19, -3}, }},
        {0.85, {{ 4,    25,  4, -1}, { 1,   25,  8, -2}, { 0,   23, 11, -2}, {-2,   22, 15, -3}, {-3,   19, 19, -3}, }},
        {0.86, {{ 4,    24,  4,  0}, { 1,   25,  7, -1}, {-1,   24, 11, -2}, {-2,   22, 15, -3}, {-3,   19, 19, -3}, }},
        {0.87, {{ 4,    24,  4,  0}, { 1,   25,  7, -1}, {-1,   24, 11, -2}, {-2,   22, 15, -3}, {-3,   19, 19, -3}, }},
        {0.88, {{ 3,    26,  3,  0}, { 0,   26,  7, -1}, {-1,   24, 11, -2}, {-3,   23, 15, -3}, {-3,   19, 19, -3}, }},
        {0.89, {{ 3,    26,  3,  0}, { 0,   26,  7, -1}, {-1,   24, 11, -2}, {-3,   23, 15, -3}, {-3,   19, 19, -3}, }},
        {0.90, {{ 3,    26,  3,  0}, { 0,   26,  7, -1}, {-2,   25, 11, -2}, {-3,   23, 15, -3}, {-3,   19, 19, -3}, }},
        {0.91, {{ 3,    26,  3,  0}, { 0,   27,  6, -1}, {-2,   25, 11, -2}, {-3,   23, 15, -3}, {-3,   19, 19, -3}, }},
        {0.92, {{ 2,    28,  2,  0}, { 0,   27,  6, -1}, {-2,   25, 11, -2}, {-3,   23, 15, -3}, {-3,   19, 19, -3}, }},
        {0.93, {{ 2,    28,  2,  0}, { 0,   26,  6,  0}, {-2,   25, 10, -1}, {-3,   23, 15, -3}, {-3,   19, 19, -3}, }},
        {0.94, {{ 2,    28,  2,  0}, { 0,   26,  6,  0}, {-2,   25, 10, -1}, {-3,   23, 15, -3}, {-3,   19, 19, -3}, }},
        {0.95, {{ 1,    30,  1,  0}, {-1,   28,  5,  0}, {-3,   26, 10, -1}, {-3,   23, 14, -2}, {-3,   19, 19, -3}, }},
        {0.96, {{ 1,    30,  1,  0}, {-1,   28,  5,  0}, {-3,   26, 10, -1}, {-3,   23, 14, -2}, {-3,   19, 19, -3}, }},
        {0.97, {{ 1,    30,  1,  0}, {-1,   28,  5,  0}, {-3,   26, 10, -1}, {-3,   23, 14, -2}, {-3,   19, 19, -3}, }},
        {0.98, {{ 1,    30,  1,  0}, {-2,   29,  5,  0}, {-3,   27,  9, -1}, {-3,   23, 14, -2}, {-3,   19, 19, -3}, }},
        {0.99, {{ 0,    32,  0,  0}, {-2,   29,  5,  0}, {-3,   27,  9, -1}, {-4,   24, 14, -2}, {-3,   19, 19, -3}, }},
        {1.00, {{ 0,    32,  0,  0}, {-2,   29,  5,  0}, {-3,   27,  9, -1}, {-4,   24, 14, -2}, {-3,   19, 19, -3}, }}
    };

void
RADEONCopyData(
  ScrnInfoPtr pScrn,
  unsigned char *src,
  unsigned char *dst,
  unsigned int srcPitch,
  unsigned int dstPitch,
  unsigned int h,
  unsigned int w,
  unsigned int bpp
){
    RADEONInfoPtr info = RADEONPTR(pScrn);

    /* Get the byte-swapping right for big endian systems */
    if ( bpp == 2 ) {
	w *= 2;
	bpp = 1;
    }

#ifdef XF86DRI

    if ( info->directRenderingEnabled && info->DMAForXv )
    {
	uint8_t *buf;
	uint32_t bufPitch, dstPitchOff;
	int x, y;
	unsigned int hpass;

	RADEONHostDataParams( pScrn, dst, dstPitch, bpp, &dstPitchOff, &x, &y );

	while ( (buf = RADEONHostDataBlit( pScrn, bpp, w, dstPitchOff, &bufPitch,
					   x, &y, &h, &hpass )) )
	{
	    RADEONHostDataBlitCopyPass( pScrn, bpp, buf, src, hpass, bufPitch,
					srcPitch );
	    src += hpass * srcPitch;
	}

	FLUSH_RING();

	return;
    }
    else
#endif /* XF86DRI */
    {
	int swap = RADEON_HOST_DATA_SWAP_NONE;

#if X_BYTE_ORDER == X_BIG_ENDIAN
	if (info->kms_enabled) {
	    switch(bpp) {
	    case 2:
		swap = RADEON_HOST_DATA_SWAP_16BIT;
		break;
	    case 4:
		swap = RADEON_HOST_DATA_SWAP_32BIT;
		break;
	    }
	} else {
	    switch (pScrn->bitsPerPixel) {
	    case 16:
		swap = RADEON_HOST_DATA_SWAP_16BIT;
		break;
	    case 32:
		swap = RADEON_HOST_DATA_SWAP_32BIT;
		break;
	    }
	}
#endif

	w *= bpp;

	if (dstPitch == w && dstPitch == srcPitch)
	    RADEONCopySwap(dst, src, h * dstPitch, swap);
	else {
	    while (h--) {
		RADEONCopySwap(dst, src, w, swap);
		src += srcPitch;
		dst += dstPitch;
	    }
	}
    }
}

static void
RADEONCopyRGB24Data(
  ScrnInfoPtr pScrn,
  unsigned char *src,
  unsigned char *dst,
  unsigned int srcPitch,
  unsigned int dstPitch,
  unsigned int h,
  unsigned int w
){
    uint32_t *dptr;
    uint8_t *sptr;
    int i,j;
    RADEONInfoPtr info = RADEONPTR(pScrn);
#ifdef XF86DRI

    if ( info->directRenderingEnabled && info->DMAForXv )
    {
	uint32_t bufPitch, dstPitchOff;
	int x, y;
	unsigned int hpass;

	RADEONHostDataParams( pScrn, dst, dstPitch, 4, &dstPitchOff, &x, &y );

	while ( (dptr = ( uint32_t* )RADEONHostDataBlit( pScrn, 4, w, dstPitchOff,
						       &bufPitch, x, &y, &h,
						       &hpass )) )
	{
	    for( j = 0; j < hpass; j++ )
	    {
		sptr = src;

		for ( i = 0 ; i < w; i++, sptr += 3 )
		{
		    dptr[i] = (sptr[2] << 16) | (sptr[1] << 8) | sptr[0];
		}

		src += srcPitch;
		dptr += bufPitch / 4;
	    }
	}

	FLUSH_RING();

	return;
    }
    else
#endif /* XF86DRI */
    {
#if X_BYTE_ORDER == X_BIG_ENDIAN
	unsigned char *RADEONMMIO = info->MMIO;

	if (!info->kms_enabled)
	    OUTREG(RADEON_SURFACE_CNTL, info->ModeReg->surface_cntl &
		   ~(RADEON_NONSURF_AP0_SWP_16BPP | RADEON_NONSURF_AP0_SWP_32BPP));
#endif

	for (j = 0; j < h; j++) {
	    dptr = (uint32_t *)(dst + j * dstPitch);
	    sptr = src + j * srcPitch;

	    for (i = 0; i < w; i++, sptr += 3) {
		dptr[i] = cpu_to_le32((sptr[2] << 16) | (sptr[1] << 8) | sptr[0]);
	    }
	}

#if X_BYTE_ORDER == X_BIG_ENDIAN
	if (!info->kms_enabled) {
	    /* restore byte swapping */
	    OUTREG(RADEON_SURFACE_CNTL, info->ModeReg->surface_cntl);
	}
#endif
    }
}


#ifdef XF86DRI
static void RADEON_420_422(
    unsigned int *d,
    unsigned char *s1,
    unsigned char *s2,
    unsigned char *s3,
    unsigned int n
)
{
    while ( n ) {
	*(d++) = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
	s1+=2; s2++; s3++;
	n--;
    }
}
#endif

void
RADEONCopyMungedData(
   ScrnInfoPtr pScrn,
   unsigned char *src1,
   unsigned char *src2,
   unsigned char *src3,
   unsigned char *dst1,
   unsigned int srcPitch,
   unsigned int srcPitch2,
   unsigned int dstPitch,
   unsigned int h,
   unsigned int w
){
    RADEONInfoPtr info = RADEONPTR(pScrn);
#ifdef XF86DRI

    if ( info->directRenderingEnabled && info->DMAForXv )
    {
	uint8_t *buf;
	uint32_t y = 0, bufPitch, dstPitchOff;
	int blitX, blitY;
	unsigned int hpass;

	/* XXX Fix endian flip on R300 */

	RADEONHostDataParams( pScrn, dst1, dstPitch, 4, &dstPitchOff, &blitX, &blitY );

	while ( (buf = RADEONHostDataBlit( pScrn, 4, w/2, dstPitchOff, &bufPitch,
					   blitX, &blitY, &h, &hpass )) )
	{
	    while ( hpass-- )
	    {
		RADEON_420_422( (unsigned int *) buf, src1, src2, src3,
				bufPitch / 4 );
		src1 += srcPitch;
		if ( y & 1 )
		{
		    src2 += srcPitch2;
		    src3 += srcPitch2;
		}
		buf += bufPitch;
		y++;
	    }
	}

	FLUSH_RING();
    }
    else
#endif /* XF86DRI */
    {
	uint32_t *dst;
	uint8_t *s1, *s2, *s3;
	int i, j;

#if X_BYTE_ORDER == X_BIG_ENDIAN
	unsigned char *RADEONMMIO = info->MMIO;

	if (!info->kms_enabled)
	    OUTREG(RADEON_SURFACE_CNTL, info->ModeReg->surface_cntl &
		   ~(RADEON_NONSURF_AP0_SWP_16BPP | RADEON_NONSURF_AP0_SWP_32BPP));
#endif

	w /= 2;

	for( j = 0; j < h; j++ )
	{
	    dst = (pointer)dst1;
	    s1 = src1;  s2 = src2;  s3 = src3;
	    i = w;
	    while( i > 4 )
	    {
		dst[0] = cpu_to_le32(s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24));
		dst[1] = cpu_to_le32(s1[2] | (s1[3] << 16) | (s3[1] << 8) | (s2[1] << 24));
		dst[2] = cpu_to_le32(s1[4] | (s1[5] << 16) | (s3[2] << 8) | (s2[2] << 24));
		dst[3] = cpu_to_le32(s1[6] | (s1[7] << 16) | (s3[3] << 8) | (s2[3] << 24));
		dst += 4; s2 += 4; s3 += 4; s1 += 8;
		i -= 4;
	    }
	    while( i-- )
	    {
		dst[0] = cpu_to_le32(s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24));
		dst++; s2++; s3++;
		s1 += 2;
	    }

	    dst1 += dstPitch;
	    src1 += srcPitch;
	    if( j & 1 )
	    {
		src2 += srcPitch2;
		src3 += srcPitch2;
	    }	
	}
#if X_BYTE_ORDER == X_BIG_ENDIAN
	if (!info->kms_enabled) {
	    /* restore byte swapping */
	    OUTREG(RADEON_SURFACE_CNTL, info->ModeReg->surface_cntl);
	}
#endif
    }
}

static void
RADEONDisplayVideo(
    ScrnInfoPtr pScrn,
    xf86CrtcPtr crtc,
    RADEONPortPrivPtr pPriv,
    int id,
    int base_offset,
    int offset1, int offset2,
    int offset3, int offset4,
    int offset5, int offset6,
    short width, short height,
    int pitch,
    int left, int right, int top,
    BoxPtr dstBox,
    short src_w, short src_h,
    short drw_w, short drw_h,
    int deinterlacing_method
){
    RADEONInfoPtr info = RADEONPTR(pScrn);
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
    unsigned char *RADEONMMIO = info->MMIO;
    uint32_t v_inc, h_inc, h_inc_uv, step_by_y, step_by_uv, tmp;
    double h_inc_d;
    int p1_h_accum_init, p23_h_accum_init;
    int p1_v_accum_init, p23_v_accum_init;
    int p23_blank_lines;
    int ecp_div;
    int v_inc_shift;
    int y_mult;
    int x_off;
    int y_off;
    uint32_t scaler_src;
    uint32_t dot_clock;
    int is_rgb;
    int is_planar;
    int i;
    uint32_t scale_cntl;
    double dsr;
    int tap_set;
    int predownscale=0;
    int src_w_d;
    int leftuv = 0;
    DisplayModePtr mode;
    RADEONOutputPrivatePtr radeon_output;
    xf86OutputPtr output;
    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;

    is_rgb=0; is_planar=0;
    switch(id){
        case FOURCC_I420:
        case FOURCC_YV12:
            is_planar=1;
            break;
        case FOURCC_RGBA32:
        case FOURCC_RGB24:
        case FOURCC_RGBT16:
        case FOURCC_RGB16:
            is_rgb=1;
            break;
        default:
	    break;
    }

    /* Here we need to find ecp_div again, as the user may have switched resolutions
       but only call OUTPLL/INPLL if needed since it may cause a 10ms delay due to
       workarounds for chip erratas */

    /* Figure out which head we are on for dot clock */
    if (radeon_crtc->crtc_id == 1)
        dot_clock = info->ModeReg->dot_clock_freq_2;
    else
        dot_clock = info->ModeReg->dot_clock_freq;

    if (dot_clock < 17500)
        ecp_div = 0;
    else
	ecp_div = 1;

    if (ecp_div != info->ecp_div) {
	info->ecp_div = ecp_div;
	OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL,
	   (INPLL(pScrn, RADEON_VCLK_ECP_CNTL) & 0xfffffCff) | (ecp_div << 8));
    }

    /* I suspect we may need a usleep after writing to the PLL.  if you play a video too soon
       after switching crtcs in mergedfb clone mode you get a temporary one pixel line of colorkey 
       on the right edge video output.
       Is this still the case? Might have been chips which need the errata,
       there is now plenty of usleep after INPLL/OUTPLL for those...*/

    v_inc_shift = 20;
    y_mult = 1;

    mode = &crtc->mode;

    if (mode->Flags & V_INTERLACE)
	v_inc_shift++;
    if (mode->Flags & V_DBLSCAN) {
	v_inc_shift--;
	y_mult = 2;
    }

    v_inc = (src_h << v_inc_shift) / drw_h;

    for (i = 0; i < xf86_config->num_output; i++) {
	output = xf86_config->output[i];
	if (output->crtc == crtc) {
	    radeon_output = output->driver_private;
	    if (radeon_output->Flags & RADEON_USE_RMX)
		v_inc = ((src_h * mode->CrtcVDisplay /
			  radeon_output->native_mode.PanelYRes) << v_inc_shift) / drw_h;
	    break;
	}
    }

    h_inc = (1 << (12 + ecp_div));

    step_by_y = 1;
    step_by_uv = step_by_y;

    src_w_d = src_w;
#if 0
    /* XXX this does not appear to work */
    /* if the source width was larger than what would fit in overlay scaler increase step_by values */
    i=src_w;
    while(i>info->overlay_scaler_buffer_width){
	step_by_y++;
	step_by_uv++;
	h_inc >>=1;
	i=i/2;
	}
#else
    /* predownscale instead (yes this hurts quality) - will only work for widths up
       to 2 times the overlay_scaler_buffer_width, should be enough */
    if (src_w_d > info->overlay_scaler_buffer_width) {
	src_w_d /= 2; /* odd widths? */
	predownscale = 1;
    }
#endif

    h_inc_d = src_w_d;
    h_inc_d = h_inc_d/drw_w;
    /* we could do a tad better  - but why
       bother when this concerns downscaling and the code is so much more
       hairy */
    while(h_inc*h_inc_d >= (2 << 12)) {
        if(!is_rgb && (((h_inc+h_inc/2)*h_inc_d)<(2<<12))){
                step_by_uv = step_by_y+1;
                break;
                }
        step_by_y++;
        step_by_uv = step_by_y;
        h_inc >>= 1;
    }

    h_inc_uv = h_inc>>(step_by_uv-step_by_y);
    h_inc = h_inc * h_inc_d;
    h_inc_uv = h_inc_uv * h_inc_d;
    /* info->overlay_scaler_buffer_width is magic number - maximum line length the overlay scaler can fit 
       in the buffer for 2 tap filtering */
    /* the only place it is documented in is in ATI source code */
    /* we need twice as much space for 4 tap filtering.. */
    /* under special circumstances turn on 4 tap filtering */
    /* disable this code for now as it has a DISASTROUS effect on image quality when upscaling
       at least on rv250 (only as long as the drw_w*2 <=... requirement is still met of course) */
#if 0
    if(!is_rgb && (step_by_y==1) && (step_by_uv==1) && (h_inc < (1<<12))
       && (deinterlacing_method!=METHOD_WEAVE)
       && (drw_w*2 <= info->overlay_scaler_buffer_width)){
        step_by_y=0;
        step_by_uv=1;
        h_inc_uv = h_inc;
        }
#endif

    /* Make the overlay base address as close to the buffers as possible to
     * prevent the buffer offsets from exceeding the hardware limit of 128 MB.
     * The base address must be aligned to a multiple of 4 MB.
     */
    base_offset = ((info->fbLocation + base_offset) & (~0U << 22)) -
	info->fbLocation;

    offset1 -= base_offset;
    offset2 -= base_offset;
    offset3 -= base_offset;
    offset4 -= base_offset;
    offset5 -= base_offset;
    offset6 -= base_offset;

    /* keep everything in 16.16 */

    if (is_planar) {
	offset1 += ((left >> 16) & ~15);
	offset2 += ((left >> 16) & ~31) >> 1;
	offset3 += ((left >> 16) & ~31) >> 1;
	offset4 += ((left >> 16) & ~15);
	offset5 += ((left >> 16) & ~31) >> 1;
	offset6 += ((left >> 16) & ~31) >> 1;
	offset2 |= RADEON_VIF_BUF0_PITCH_SEL;
	offset3 |= RADEON_VIF_BUF0_PITCH_SEL;
	offset5 |= RADEON_VIF_BUF0_PITCH_SEL;
	offset6 |= RADEON_VIF_BUF0_PITCH_SEL;
    }
    else {
	/* is this really correct for non-2-byte formats? */
	offset1 += ((left >> 16) & ~7) << 1;
	offset2 += ((left >> 16) & ~7) << 1;
	offset3 += ((left >> 16) & ~7) << 1;
	offset4 += ((left >> 16) & ~7) << 1;
	offset5 += ((left >> 16) & ~7) << 1;
	offset6 += ((left >> 16) & ~7) << 1;
    }

    tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
    p1_h_accum_init = ((tmp <<  4) & 0x000f8000) |
		      ((tmp << 12) & 0xf0000000);

    tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc_uv << 2);
    p23_h_accum_init = ((tmp <<  4) & 0x000f8000) |
		       ((tmp << 12) & 0x70000000);

    tmp = (top & 0x0000ffff) + 0x00018000;
    p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 
    	(((deinterlacing_method!=METHOD_WEAVE)&&!is_rgb)?0x03:0x01);

    if (is_planar) {
	p23_v_accum_init = ((tmp << 4) & 0x03ff8000) |
	    ((deinterlacing_method != METHOD_WEAVE) ? 0x03 : 0x01);
	p23_blank_lines = (((src_h >> 1) - 1) << 16);
    }
    else {
	p23_v_accum_init = 0;
	p23_blank_lines = 0;
    }

    if (is_planar) {
	leftuv = ((left >> 16) >> 1) & 15;
	left = (left >> 16) & 15;
    }
    else {
	left = (left >> 16) & 7;
	if (!is_rgb)
	    leftuv = left >> 1;
    }

    RADEONWaitForFifo(pScrn, 2);
    OUTREG(RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK);
    if (info->accelOn) RADEON_SYNC(info, pScrn);
    while(!(INREG(RADEON_OV0_REG_LOAD_CNTL) & RADEON_REG_LD_CTL_LOCK_READBACK));

    RADEONWaitForFifo(pScrn, 10);
    OUTREG(RADEON_OV0_H_INC, h_inc | ((is_rgb? h_inc_uv: (h_inc_uv >> 1)) << 16));
    OUTREG(RADEON_OV0_STEP_BY, step_by_y | (step_by_uv << 8) |
	predownscale << 4 | predownscale << 12);

    x_off = 8;
    y_off = 0;

    if (IS_R300_VARIANT ||
        (info->ChipFamily == CHIP_FAMILY_R200))
	x_off = 0;

    /* needed to make the overlay work on crtc1 in leftof and above modes */
    /* XXX: may need to adjust x_off/y_off for dualhead like mergedfb -- need to test */
    /*
    if (srel == radeonLeftOf) {
	x_off -= mode->CrtcHDisplay;
    }
    if (srel == radeonAbove) {
	y_off -= mode->CrtcVDisplay;
    }
    */

    /* Put the hardware overlay on CRTC2:
     *
     * Since one hardware overlay can not be displayed on two heads
     * at the same time, we might need to consider using software
     * rendering for the second head.
     */

    if (radeon_crtc->crtc_id == 1) {
        x_off = 0;
        OUTREG(RADEON_OV1_Y_X_START, ((dstBox->x1 + x_off) |
                                      ((dstBox->y1*y_mult) << 16)));
        OUTREG(RADEON_OV1_Y_X_END,   ((dstBox->x2 + x_off) |
                                      ((dstBox->y2*y_mult) << 16)));
        scaler_src = RADEON_SCALER_CRTC_SEL;
    } else {
	OUTREG(RADEON_OV0_Y_X_START, ((dstBox->x1 + x_off) |
				      (((dstBox->y1*y_mult) + y_off) << 16)));
	OUTREG(RADEON_OV0_Y_X_END,   ((dstBox->x2 + x_off) |
				      (((dstBox->y2*y_mult) + y_off) << 16)));
	scaler_src = 0;
    }

    /* program the tap coefficients for better downscaling quality.
       Could do slightly better by using hardcoded coefficients for one axis
       in case only the other axis is downscaled (see RADEON_OV0_FILTER_CNTL) */
    dsr=(double)(1<<0xC)/h_inc;
    if(dsr<0.25)dsr=0.25;
    if(dsr>1.0)dsr=1.0;
    tap_set=(int)((dsr-0.25)*100);
    for(i=0;i<5;i++){
	    OUTREG(RADEON_OV0_FOUR_TAP_COEF_0+i*4, (TapCoeffs[tap_set].coeff[i][0] &0xf) | 
	    	((TapCoeffs[tap_set].coeff[i][1] &0x7f)<<8) | 
	    	((TapCoeffs[tap_set].coeff[i][2] &0x7f)<<16) | 
	    	((TapCoeffs[tap_set].coeff[i][3] &0xf)<<24));
		}

    RADEONWaitForFifo(pScrn, 11);
    OUTREG(RADEON_OV0_V_INC, v_inc);
    OUTREG(RADEON_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
    OUTREG(RADEON_OV0_P23_BLANK_LINES_AT_TOP, 0x000007ff | p23_blank_lines);
    OUTREG(RADEON_OV0_VID_BUF_PITCH0_VALUE, pitch);
    OUTREG(RADEON_OV0_VID_BUF_PITCH1_VALUE, is_planar ? pitch >> 1 : pitch);
    OUTREG(RADEON_OV0_P1_X_START_END, (src_w + left - 1) | (left << 16));
    if (!is_rgb)
	src_w >>= 1;
    OUTREG(RADEON_OV0_P2_X_START_END, (src_w + leftuv - 1) | (leftuv << 16));
    OUTREG(RADEON_OV0_P3_X_START_END, (src_w + leftuv - 1) | (leftuv << 16));
    if (info->ModeReg->ov0_base_addr != (info->fbLocation + base_offset)) {
	ErrorF("Changing OV0_BASE_ADDR from 0x%08x to 0x%08x\n",
	       info->ModeReg->ov0_base_addr, (uint32_t)info->fbLocation + base_offset);
	info->ModeReg->ov0_base_addr = info->fbLocation + base_offset;
	OUTREG(RADEON_OV0_BASE_ADDR, info->ModeReg->ov0_base_addr);
    }
    OUTREG(RADEON_OV0_VID_BUF0_BASE_ADRS, offset1);
    OUTREG(RADEON_OV0_VID_BUF1_BASE_ADRS, offset2);
    OUTREG(RADEON_OV0_VID_BUF2_BASE_ADRS, offset3);

    RADEONWaitForFifo(pScrn, 9);
    OUTREG(RADEON_OV0_VID_BUF3_BASE_ADRS, offset4);
    OUTREG(RADEON_OV0_VID_BUF4_BASE_ADRS, offset5);
    OUTREG(RADEON_OV0_VID_BUF5_BASE_ADRS, offset6);
    OUTREG(RADEON_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
    OUTREG(RADEON_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
    OUTREG(RADEON_OV0_P23_V_ACCUM_INIT, p23_v_accum_init);
    OUTREG(RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);

   scale_cntl = RADEON_SCALER_ADAPTIVE_DEINT | RADEON_SCALER_DOUBLE_BUFFER 
        | RADEON_SCALER_ENABLE | RADEON_SCALER_SMART_SWITCH | (0x7f<<16) | scaler_src;
   switch(id){
        case FOURCC_UYVY:
		scale_cntl |= RADEON_SCALER_SOURCE_YVYU422;
		break;
        case FOURCC_RGB24:
        case FOURCC_RGBA32:
		scale_cntl |= RADEON_SCALER_SOURCE_32BPP | RADEON_SCALER_LIN_TRANS_BYPASS;
		break;
        case FOURCC_RGB16:
		scale_cntl |= RADEON_SCALER_SOURCE_16BPP | RADEON_SCALER_LIN_TRANS_BYPASS;
		break;
        case FOURCC_RGBT16:
		scale_cntl |= RADEON_SCALER_SOURCE_15BPP | RADEON_SCALER_LIN_TRANS_BYPASS;
		break;
        case FOURCC_YV12:
        case FOURCC_I420:
		scale_cntl |= RADEON_SCALER_SOURCE_YUV12;
		break;
        case FOURCC_YUY2:
        default:
		scale_cntl |= RADEON_SCALER_SOURCE_VYUY422
			| ((info->ChipFamily >= CHIP_FAMILY_R200) ? RADEON_SCALER_TEMPORAL_DEINT : 0);
		break;
    }

    if (info->ChipFamily < CHIP_FAMILY_R200) {
	scale_cntl &= ~RADEON_SCALER_GAMMA_SEL_MASK;
	scale_cntl |= ((RADEONTranslateUserGamma(pPriv->gamma)) << 5);
    }

    OUTREG(RADEON_OV0_SCALE_CNTL, scale_cntl);
    OUTREG(RADEON_OV0_REG_LOAD_CNTL, 0);
}


static void
RADEONFillKeyHelper(DrawablePtr pDraw, uint32_t colorKey, RegionPtr clipBoxes)
{
#if HAVE_XV_DRAWABLE_HELPER
    xf86XVFillKeyHelperDrawable(pDraw, colorKey, clipBoxes);
#else
    xf86XVFillKeyHelper(pDraw->pScreen, colorKey, clipBoxes);
#endif
}


static int
RADEONPutImage(
  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,
  DrawablePtr pDraw
){
   RADEONInfoPtr info = RADEONPTR(pScrn);
   RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
   INT32 xa, xb, ya, yb;
   unsigned char *dst_start;
   int new_size, offset, s2offset, s3offset;
   int srcPitch, srcPitch2, dstPitch;
   int d2line, d3line;
   int top, left, npixels, nlines, bpp;
   int idconv = id;
   BoxRec dstBox;
   uint32_t tmp;
   xf86CrtcPtr crtc;

   /*
    * s2offset, s3offset - byte offsets into U and V plane of the
    *                      source where copying starts.  Y plane is
    *                      done by editing "buf".
    *
    * offset - byte offset to the first line of the destination.
    *
    * dst_start - byte address to the first displayed pel.
    *
    */

   /* make the compiler happy */
   s2offset = s3offset = srcPitch2 = 0;
   d2line = d3line = 0;

   if(src_w > (drw_w << 4))
	drw_w = src_w >> 4;
   if(src_h > (drw_h << 4))
	drw_h = src_h >> 4;

   /* Clip */
   xa = src_x;
   xb = src_x + src_w;
   ya = src_y;
   yb = src_y + src_h;

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

   if (!radeon_crtc_clip_video(pScrn, &crtc, pPriv->desired_crtc,
			       &dstBox, &xa, &xb, &ya, &yb,
			       clipBoxes, width, height))
       return Success;

   if (!crtc) {
       if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
	   unsigned char *RADEONMMIO = info->MMIO;
	   OUTREG(RADEON_OV0_SCALE_CNTL, 0);
	   pPriv->videoStatus &= ~CLIENT_VIDEO_ON;
       }
       return Success;
   }

   dstBox.x1 -= crtc->x;
   dstBox.x2 -= crtc->x;
   dstBox.y1 -= crtc->y;
   dstBox.y2 -= crtc->y;

   bpp = pScrn->bitsPerPixel >> 3;

   switch(id) {
   case FOURCC_RGB24:
	dstPitch = width * 4;
	srcPitch = width * 3;
	break;
   case FOURCC_RGBA32:
	dstPitch = width * 4;
	srcPitch = width * 4;
	break;
   case FOURCC_RGB16:
   case FOURCC_RGBT16:
	dstPitch = width * 2;
	srcPitch = RADEON_ALIGN(width * 2, 4);
	break;
   case FOURCC_YV12:
   case FOURCC_I420:
	/* it seems rs4xx chips (all of them???) either can't handle planar
	   yuv at all or would need some unknown different setup. */
       if ((info->ChipFamily != CHIP_FAMILY_RS400) &&
	   (info->ChipFamily != CHIP_FAMILY_RS480)) {
	    /* need 16bytes alignment for u,v plane, so 2 times that for width
	       but blitter needs 64bytes alignment. 128byte is a waste but dstpitch
	       for uv planes needs to be dstpitch yplane >> 1 for now. */
	    dstPitch = (RADEON_ALIGN(width, 128));
	    srcPitch = RADEON_ALIGN(width, 4);
	}
	else {
	    dstPitch = width * 2;
	    srcPitch = RADEON_ALIGN(width, 4);
	    idconv = FOURCC_YUY2;
	}
	break;
   case FOURCC_UYVY:
   case FOURCC_YUY2:
   default:
	dstPitch = width * 2;
	srcPitch = width * 2;
	break;
   }

#ifdef XF86DRI
   if (info->directRenderingEnabled && info->DMAForXv) {
       /* The upload blit only supports multiples of 64 bytes */
       dstPitch = RADEON_ALIGN(dstPitch, 64);
   } else
#endif
       /* The overlay only supports multiples of 16 bytes */
       dstPitch = RADEON_ALIGN(dstPitch, 16);

   new_size = dstPitch * height;
   if (idconv == FOURCC_YV12 || id == FOURCC_I420) {
      new_size += (dstPitch >> 1) * (RADEON_ALIGN(height, 2));
   }
   pPriv->video_offset = radeon_legacy_allocate_memory(pScrn, &pPriv->video_memory,
						       (pPriv->doubleBuffer ?
						       (new_size * 2) : new_size), 64,
						       RADEON_GEM_DOMAIN_VRAM);
   if (pPriv->video_offset == 0)
      return BadAlloc;

   pPriv->currentBuffer ^= 1;

    /* copy data */
   top = ya >> 16;
   left = (xa >> 16) & ~1;
   npixels = ((xb + 0xffff) >> 16) - left;

   offset = (pPriv->video_offset) + (top * dstPitch);

   if(pPriv->doubleBuffer) {
	unsigned char *RADEONMMIO = info->MMIO;

	/* Wait for last flip to take effect */
	while(!(INREG(RADEON_OV0_REG_LOAD_CNTL) & RADEON_REG_LD_CTL_FLIP_READBACK));

	offset += pPriv->currentBuffer * new_size;
   }

   dst_start = info->FB + offset;

   switch(id) {
   case FOURCC_YV12:
   case FOURCC_I420:
	if (id == idconv) {
	    /* meh. Such a mess just for someone who wants to watch half the video clipped */
	    top &= ~1;
	    /* odd number of pixels? That may not work correctly */
	    srcPitch2 = RADEON_ALIGN(width >> 1, 4);
	    /* odd number of lines? Maybe... */
	    s2offset = srcPitch * (RADEON_ALIGN(height, 2));
	    s3offset = s2offset + srcPitch2 * ((height + 1) >> 1);
	    s2offset += (top >> 1) * srcPitch2 + (left >> 1);
	    s3offset += (top >> 1) * srcPitch2 + (left >> 1);
	    d2line = (height * dstPitch);
	    d3line = d2line + ((height + 1) >> 1) * (dstPitch >> 1);
	    nlines = ((yb + 0xffff) >> 16) - top;
	    d2line += (top >> 1) * (dstPitch >> 1) - (top * dstPitch);
	    d3line += (top >> 1) * (dstPitch >> 1) - (top * dstPitch);
	    if(id == FOURCC_YV12) {
		tmp = s2offset;
		s2offset = s3offset;
		s3offset = tmp;
	    }
	    RADEONCopyData(pScrn, buf + (top * srcPitch) + left, dst_start + left,
		srcPitch, dstPitch, nlines, npixels, 1);
	    RADEONCopyData(pScrn, buf + s2offset, dst_start + d2line + (left >> 1),
		srcPitch2, dstPitch >> 1, (nlines + 1) >> 1, npixels >> 1, 1);
	    RADEONCopyData(pScrn, buf + s3offset, dst_start + d3line + (left >> 1),
		srcPitch2, dstPitch >> 1, (nlines + 1) >> 1, npixels >> 1, 1);
	}
	else {
	    s2offset = srcPitch * height;
	    srcPitch2 = RADEON_ALIGN(width >> 1, 4);
	    s3offset = (srcPitch2 * (height >> 1)) + s2offset;
	    top &= ~1;
	    dst_start += left << 1;
	    tmp = ((top >> 1) * srcPitch2) + (left >> 1);
	    s2offset += tmp;
	    s3offset += tmp;
	    if(id == FOURCC_I420) {
		tmp = s2offset;
		s2offset = s3offset;
		s3offset = tmp;
	    }
	    nlines = ((yb + 0xffff) >> 16) - top;
	    RADEONCopyMungedData(pScrn, buf + (top * srcPitch) + left,
				 buf + s2offset, buf + s3offset, dst_start,
				 srcPitch, srcPitch2, dstPitch, nlines, npixels);
	}
	break;
    case FOURCC_RGBT16:
    case FOURCC_RGB16:
    case FOURCC_UYVY:
    case FOURCC_YUY2:
    default:
	left <<= 1;
	buf += (top * srcPitch) + left;
	nlines = ((yb + 0xffff) >> 16) - top;
	dst_start += left;
	RADEONCopyData(pScrn, buf, dst_start, srcPitch, dstPitch, nlines, npixels, 2);
	break;
    case FOURCC_RGBA32:
	buf += (top * srcPitch) + left*4;
	nlines = ((yb + 0xffff) >> 16) - top;
	dst_start += left*4;
	RADEONCopyData(pScrn, buf, dst_start, srcPitch, dstPitch, nlines, npixels, 4);
    	break;
    case FOURCC_RGB24:
	buf += (top * srcPitch) + left*3;
	nlines = ((yb + 0xffff) >> 16) - top;
	dst_start += left*4;
	RADEONCopyRGB24Data(pScrn, buf, dst_start, srcPitch, dstPitch, nlines, npixels);
    	break;
    }

    /* update cliplist */
    if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes))
    {
	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
	/* draw these */
	if(pPriv->autopaint_colorkey)
	    RADEONFillKeyHelper(pDraw, pPriv->colorKey, clipBoxes);
    }

    /* FIXME: someone should look at these offsets, I don't think it makes sense how
              they are handled throughout the source. */
    RADEONDisplayVideo(pScrn, crtc, pPriv, idconv, pPriv->video_offset, offset,
		       offset + d2line, offset + d3line, offset, offset + d2line,
		       offset + d3line, width, height, dstPitch, xa, xb, ya,
		       &dstBox, src_w, src_h, drw_w, drw_h, METHOD_BOB);

    pPriv->videoStatus = CLIENT_VIDEO_ON;

    info->VideoTimerCallback = RADEONVideoTimerCallback;

    return Success;
}


int
RADEONQueryImageAttributes(
    ScrnInfoPtr pScrn,
    int id,
    unsigned short *w, unsigned short *h,
    int *pitches, int *offsets
){
    const RADEONInfoRec * const info = RADEONPTR(pScrn);
    int size, tmp;

    if(*w > info->xv_max_width) *w = info->xv_max_width;
    if(*h > info->xv_max_height) *h = info->xv_max_height;

    *w = RADEON_ALIGN(*w, 2);
    if(offsets) offsets[0] = 0;

    switch(id) {
    case FOURCC_YV12:
    case FOURCC_I420:
	*h = RADEON_ALIGN(*h, 2);
	size = RADEON_ALIGN(*w, 4);
	if(pitches) pitches[0] = size;
	size *= *h;
	if(offsets) offsets[1] = size;
	tmp = RADEON_ALIGN(*w >> 1, 4);
	if(pitches) pitches[1] = pitches[2] = tmp;
	tmp *= (*h >> 1);
	size += tmp;
	if(offsets) offsets[2] = size;
	size += tmp;
	break;
    case FOURCC_RGBA32:
	size = *w << 2;
	if(pitches) pitches[0] = size;
	size *= *h;
	break;
    case FOURCC_RGB24:
	size = *w * 3;
	if(pitches) pitches[0] = size;
	size *= *h;
	break;
    case FOURCC_RGBT16:
    case FOURCC_RGB16:
    case FOURCC_UYVY:
    case FOURCC_YUY2:
    default:
	size = *w << 1;
	if(pitches) pitches[0] = size;
	size *= *h;
	break;
    }

    return size;
}

static void
RADEONVideoTimerCallback(ScrnInfoPtr pScrn, Time now)
{
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RADEONPortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;

    if(pPriv->videoStatus & TIMER_MASK) {
	if(pPriv->videoStatus & OFF_TIMER) {
	    if(pPriv->offTime < now) {
		unsigned char *RADEONMMIO = info->MMIO;
		OUTREG(RADEON_OV0_SCALE_CNTL, 0);
		pPriv->videoStatus = FREE_TIMER;
		pPriv->freeTime = now + FREE_DELAY;
	    }
	} else {  /* FREE_TIMER */
	    if(pPriv->freeTime < now) {
		RADEONFreeVideoMemory(pScrn, pPriv);
		pPriv->videoStatus = 0;
		info->VideoTimerCallback = NULL;
	    }
	}
    } else  /* shouldn't get here */
	info->VideoTimerCallback = NULL;
}

/****************** Offscreen stuff ***************/
typedef struct {
  void *surface_memory;
  Bool isOn;
} OffscreenPrivRec, * OffscreenPrivPtr;

static int
RADEONAllocateSurface(
    ScrnInfoPtr pScrn,
    int id,
    unsigned short w,
    unsigned short h,
    XF86SurfacePtr surface
){
    int offset, pitch, size;
    OffscreenPrivPtr pPriv;
    void *surface_memory = NULL;
    if((w > 1024) || (h > 1024))
	return BadAlloc;

    w = RADEON_ALIGN(w, 2);
    pitch = RADEON_ALIGN(w << 1, 16);
    size = pitch * h;

    offset = radeon_legacy_allocate_memory(pScrn, &surface_memory, size, 64,
		    RADEON_GEM_DOMAIN_VRAM);
    if (offset == 0)
	return BadAlloc;

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

    if(!(surface->pitches = malloc(sizeof(int)))) {
	radeon_legacy_free_memory(pScrn, surface_memory);
	return BadAlloc;
    }
    if(!(surface->offsets = malloc(sizeof(int)))) {
	free(surface->pitches);
	radeon_legacy_free_memory(pScrn, surface_memory);
	return BadAlloc;
    }
    if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
	free(surface->pitches);
	free(surface->offsets);
	radeon_legacy_free_memory(pScrn, surface_memory);
	return BadAlloc;
    }

    pPriv->surface_memory = surface_memory;
    pPriv->isOn = FALSE;

    surface->pScrn = pScrn;
    surface->id = id;
    surface->pitches[0] = pitch;
    surface->offsets[0] = offset;
    surface->devPrivate.ptr = (pointer)pPriv;

    return Success;
}

static int
RADEONStopSurface(
    XF86SurfacePtr surface
){
  OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
  RADEONInfoPtr info = RADEONPTR(surface->pScrn);
  unsigned char *RADEONMMIO = info->MMIO;

  if(pPriv->isOn) {
	OUTREG(RADEON_OV0_SCALE_CNTL, 0);
	pPriv->isOn = FALSE;
  }
  return Success;
}


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

    if(pPriv->isOn)
	RADEONStopSurface(surface);
    radeon_legacy_free_memory(pScrn, pPriv->surface_memory);
    pPriv->surface_memory = NULL;
    free(surface->pitches);
    free(surface->offsets);
    free(surface->devPrivate.ptr);

    return Success;
}

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

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


static int
RADEONDisplaySurface(
    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;
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RADEONPortPrivPtr portPriv = info->adaptor->pPortPrivates[0].ptr;

    INT32 xa, ya, xb, yb;
    BoxRec dstBox;
    xf86CrtcPtr crtc;

    if (src_w > (drw_w << 4))
	drw_w = src_w >> 4;
    if (src_h > (drw_h << 4))
	drw_h = src_h >> 4;

    xa = src_x;
    xb = src_x + src_w;
    ya = src_y;
    yb = src_y + src_h;

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

    if (!radeon_crtc_clip_video(pScrn, &crtc, portPriv->desired_crtc,
				&dstBox, &xa, &xb, &ya, &yb, clipBoxes,
				surface->width, surface->height))
        return Success;

   if (!crtc) {
       if (pPriv->isOn) {
	   unsigned char *RADEONMMIO = info->MMIO;
	   OUTREG(RADEON_OV0_SCALE_CNTL, 0);
	   pPriv->isOn = FALSE;
       }
       return Success;
   }

    dstBox.x1 -= crtc->x;
    dstBox.x2 -= crtc->x;
    dstBox.y1 -= crtc->y;
    dstBox.y2 -= crtc->y;

#if 0
    /* this isn't needed */
    RADEONResetVideo(pScrn);
#endif
    RADEONDisplayVideo(pScrn, crtc, portPriv, surface->id,
		       surface->offsets[0], surface->offsets[0],
		       surface->offsets[0], surface->offsets[0],
		       surface->offsets[0], surface->offsets[0],
		       surface->offsets[0], surface->width, surface->height,
		       surface->pitches[0], xa, xb, ya, &dstBox, src_w, src_h,
		       drw_w, drw_h, METHOD_BOB);

    if (portPriv->autopaint_colorkey)
	xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);

    pPriv->isOn = TRUE;
    /* we've prempted the XvImage stream so set its free timer */
    if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
	REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
	UpdateCurrentTime();
	portPriv->videoStatus = FREE_TIMER;
	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
	info->VideoTimerCallback = RADEONVideoTimerCallback;
    }

    return Success;
}


static void
RADEONInitOffscreenImages(ScreenPtr pScreen)
{
/*  ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
    RADEONInfoPtr info = RADEONPTR(pScrn); */
    XF86OffscreenImagePtr offscreenImages;
    /* need to free this someplace */

    if (!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
	return;

    offscreenImages[0].image = &Images[0];
    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES /*|
			       VIDEO_CLIP_TO_VIEWPORT*/;
    offscreenImages[0].alloc_surface = RADEONAllocateSurface;
    offscreenImages[0].free_surface = RADEONFreeSurface;
    offscreenImages[0].display = RADEONDisplaySurface;
    offscreenImages[0].stop = RADEONStopSurface;
    offscreenImages[0].setAttribute = RADEONSetSurfaceAttribute;
    offscreenImages[0].getAttribute = RADEONGetSurfaceAttribute;
    offscreenImages[0].max_width = 2047;
    offscreenImages[0].max_height = 2047;
    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
    offscreenImages[0].attributes = Attributes;

    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
}

         /* TV-in functions */

static int
RADEONPutVideo(
  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,
  DrawablePtr pDraw
){
   RADEONInfoPtr info = RADEONPTR(pScrn);
   RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
   unsigned char *RADEONMMIO = info->MMIO;
   INT32 xa, xb, ya, yb, top;
   unsigned int pitch, new_size, alloc_size;
   unsigned int offset1, offset2, offset3, offset4, s2offset, s3offset;
   unsigned int vbi_offset0, vbi_offset1;
   int srcPitch, srcPitch2, dstPitch;
   int bpp;
   BoxRec dstBox;
   uint32_t id, display_base;
   int width, height;
   int mult;
   int vbi_line_width, vbi_start, vbi_end;
   xf86CrtcPtr crtc;

    RADEON_SYNC(info, pScrn);
   /*
    * s2offset, s3offset - byte offsets into U and V plane of the
    *                      source where copying starts.  Y plane is
    *                      done by editing "buf".
    *
    * offset - byte offset to the first line of the destination.
    *
    * dst_start - byte address to the first displayed pel.
    *
    */

   /* make the compiler happy */
   s2offset = s3offset = srcPitch2 = 0;

   if(src_w > (drw_w << 4))
        drw_w = src_w >> 4;
   if(src_h > (drw_h << 4))
        drw_h = src_h >> 4;

   /* Clip */
   xa = src_x;
   xb = src_x + src_w;
   ya = src_y;
   yb = src_y + src_h;

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

   width = InputVideoEncodings[pPriv->encoding].width;
   height = InputVideoEncodings[pPriv->encoding].height;

   vbi_line_width = 798*2;
   if(width<=640)
       vbi_line_width = 0x640; /* 1600 actually */
   else
       vbi_line_width = 2000; /* might need adjustment */

   if (!radeon_crtc_clip_video(pScrn, &crtc, pPriv->desired_crtc,
			       &dstBox, &xa, &xb, &ya, &yb,
			       clipBoxes, width, height))
       return Success;

   if (!crtc) {
       if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
	   unsigned char *RADEONMMIO = info->MMIO;
	   OUTREG(RADEON_OV0_SCALE_CNTL, 0);
	   pPriv->videoStatus &= ~CLIENT_VIDEO_ON;
       }
       return Success;
   }

   dstBox.x1 -= crtc->x;
   dstBox.x2 -= crtc->x;
   dstBox.y1 -= crtc->y;
   dstBox.y2 -= crtc->y;

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

   switch(pPriv->overlay_deinterlacing_method){
        case METHOD_BOB:
        case METHOD_SINGLE:
                mult=2;
                break;
        case METHOD_WEAVE:
        case METHOD_ADAPTIVE:
                mult=4;
                break;
        default:
                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Internal error: PutVideo\n");
                mult=4;
        }

   id = FOURCC_YUY2;
   
   top = ya>>16;
#if 0
   /* setting the ID above makes this useful - needs revisiting */
   switch(id) {
   case FOURCC_YV12:
   case FOURCC_I420:
        top &= ~1;
        dstPitch = RADEON_ALIGN(width << 1, 16);
        srcPitch = RADEON_ALIGN(width, 4);
        s2offset = srcPitch * height;
        srcPitch2 = RADEON_ALIGN(width >> 1, 4);
        s3offset = (srcPitch2 * (height >> 1)) + s2offset;
        break;
   case FOURCC_UYVY:
   case FOURCC_YUY2:
   default:
        dstPitch = RADEON_ALIGN(width<<1, 16);
        srcPitch = (width<<1);
        break;
   }
#else
   dstPitch = RADEON_ALIGN(width << 1, 16);
   srcPitch = (width<<1);
#endif

   new_size = dstPitch * height;
   new_size = new_size + 0x1f; /* for aligning */
   alloc_size = new_size * mult;
   if (pPriv->capture_vbi_data)
      alloc_size += 2 * 2 * vbi_line_width * 21;

   pPriv->video_offset = radeon_legacy_allocate_memory(pScrn, &pPriv->video_memory,
						      (pPriv->doubleBuffer ?
						      (new_size * 2) : new_size), 64,
						      RADEON_GEM_DOMAIN_GTT);
   if (pPriv->video_offset == 0)
      return BadAlloc;

/* I have suspicion that capture engine must be active _before_ Rage Theatre
   is being manipulated with.. */

   RADEONWaitForIdleMMIO(pScrn);
   display_base=INREG(RADEON_DISPLAY_BASE_ADDR);   

/*   RADEONWaitForFifo(pScrn, 15); */

   switch(pPriv->overlay_deinterlacing_method){
        case METHOD_BOB:
        case METHOD_SINGLE:
           offset1 = RADEON_ALIGN(pPriv->video_offset, 0x10);
           offset2 = RADEON_ALIGN(pPriv->video_offset + new_size, 0x10);
           offset3 = offset1;
           offset4 = offset2;
           break;
        case METHOD_WEAVE:
           offset1 = RADEON_ALIGN(pPriv->video_offset, 0x10);
           offset2 = offset1+dstPitch;
           offset3 = RADEON_ALIGN(pPriv->video_offset + 2 * new_size, 0x10);
           offset4 = offset3+dstPitch;
           break;
        default:
           offset1 = RADEON_ALIGN(pPriv->video_offset, 0x10);
           offset2 = RADEON_ALIGN(pPriv->video_offset + new_size, 0x10);
           offset3 = offset1;
           offset4 = offset2;
        }

   OUTREG(RADEON_CAP0_BUF0_OFFSET,        offset1+display_base);
   OUTREG(RADEON_CAP0_BUF0_EVEN_OFFSET,   offset2+display_base);
   OUTREG(RADEON_CAP0_BUF1_OFFSET,        offset3+display_base);
   OUTREG(RADEON_CAP0_BUF1_EVEN_OFFSET,   offset4+display_base);

   OUTREG(RADEON_CAP0_ONESHOT_BUF_OFFSET, offset1+display_base);

   if(pPriv->capture_vbi_data){
        if ((pPriv->encoding==2)||(pPriv->encoding==8)) {
            /* PAL, SECAM */
            vbi_start = 5;
            vbi_end = 21;
        } else {
            /* NTSC */
            vbi_start = 8;
            vbi_end = 20;
        }

        vbi_offset0 = RADEON_ALIGN(pPriv->video_offset + mult * new_size * bpp, 0x10);
        vbi_offset1 = vbi_offset0 + dstPitch*20;
        OUTREG(RADEON_CAP0_VBI0_OFFSET, vbi_offset0+display_base);
        OUTREG(RADEON_CAP0_VBI1_OFFSET, vbi_offset1+display_base);
        OUTREG(RADEON_CAP0_VBI2_OFFSET, 0);
        OUTREG(RADEON_CAP0_VBI3_OFFSET, 0);
        OUTREG(RADEON_CAP0_VBI_V_WINDOW, vbi_start | (vbi_end<<16));
        OUTREG(RADEON_CAP0_VBI_H_WINDOW, 0 | (vbi_line_width)<<16);
        }
   
   OUTREG(RADEON_CAP0_BUF_PITCH, dstPitch*mult/2);
   OUTREG(RADEON_CAP0_H_WINDOW, (2*width)<<16);
   OUTREG(RADEON_CAP0_V_WINDOW, (((height)+pPriv->v-1)<<16)|(pPriv->v-1));
   if(mult==2){
           OUTREG(RADEON_CAP0_CONFIG, ENABLE_RADEON_CAPTURE_BOB);
           } else {
           OUTREG(RADEON_CAP0_CONFIG, ENABLE_RADEON_CAPTURE_WEAVE);
           }
   OUTREG(RADEON_CAP0_DEBUG, 0);
   
   OUTREG(RADEON_VID_BUFFER_CONTROL, (1<<16) | 0x01);
   OUTREG(RADEON_TEST_DEBUG_CNTL, 0);
   
   if(! pPriv->video_stream_active)
   {

      RADEONWaitForIdleMMIO(pScrn);
      OUTREG(RADEON_VIDEOMUX_CNTL, INREG(RADEON_VIDEOMUX_CNTL)|1 ); 
      OUTREG(RADEON_CAP0_PORT_MODE_CNTL, (pPriv->theatre!=NULL)? 1: 0);
      OUTREG(RADEON_FCP_CNTL, RADEON_FCP0_SRC_PCLK);
      OUTREG(RADEON_CAP0_TRIG_CNTL, 0x11);
      if(pPriv->theatre != NULL) 
      {
         RADEON_RT_SetEncoding(pScrn, pPriv); 
      }
      if(pPriv->msp3430 != NULL) RADEON_MSP_SetEncoding(pPriv);
      if(pPriv->tda9885 != NULL) RADEON_TDA9885_SetEncoding(pPriv);
      if(pPriv->fi1236 != NULL) RADEON_FI1236_SetEncoding(pPriv);
      if(pPriv->i2c != NULL)RADEON_board_setmisc(pPriv);
   }

   
   /* update cliplist */
   if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
        REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
        /* draw these */
        if(pPriv->autopaint_colorkey)
	    RADEONFillKeyHelper(pDraw, pPriv->colorKey, clipBoxes);
   }

   RADEONDisplayVideo(pScrn, crtc, pPriv, id, pPriv->video_offset,
		      offset1+top*srcPitch, offset2+top*srcPitch,
		      offset3+top*srcPitch, offset4+top*srcPitch,
		      offset1+top*srcPitch, offset2+top*srcPitch, width, height,
		      dstPitch*mult/2, xa, xb, ya, &dstBox, src_w, src_h*mult/2,
		      drw_w, drw_h, pPriv->overlay_deinterlacing_method);

   RADEONWaitForFifo(pScrn, 1);
   OUTREG(RADEON_OV0_REG_LOAD_CNTL,  RADEON_REG_LD_CTL_LOCK);
   RADEONWaitForIdleMMIO(pScrn);
   while(!(INREG(RADEON_OV0_REG_LOAD_CNTL) & RADEON_REG_LD_CTL_LOCK_READBACK));


   switch(pPriv->overlay_deinterlacing_method){
        case METHOD_BOB:
           OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0xAAAAA);
           OUTREG(RADEON_OV0_AUTO_FLIP_CNTL,0 /*| RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD*/
                |RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN);
           break;
        case METHOD_SINGLE:
           OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0xEEEEE | (9<<28));
           OUTREG(RADEON_OV0_AUTO_FLIP_CNTL, RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD
                |RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN);
           break;
        case METHOD_WEAVE:
           OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0x11111 | (9<<28));
           OUTREG(RADEON_OV0_AUTO_FLIP_CNTL, 0  |RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD 
                | RADEON_OV0_AUTO_FLIP_CNTL_P1_FIRST_LINE_EVEN 
                /* |RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN */
                /*|RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_EVEN_DOWN */
                |RADEON_OV0_AUTO_FLIP_CNTL_FIELD_POL_SOURCE);
           break;
        default:
           OUTREG(RADEON_OV0_DEINTERLACE_PATTERN, 0xAAAAA);
           OUTREG(RADEON_OV0_AUTO_FLIP_CNTL, RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD
                |RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN);
        }
                
   
   RADEONWaitForIdleMMIO(pScrn);
   OUTREG (RADEON_OV0_AUTO_FLIP_CNTL, (INREG (RADEON_OV0_AUTO_FLIP_CNTL) ^ RADEON_OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE ));
   OUTREG (RADEON_OV0_AUTO_FLIP_CNTL, (INREG (RADEON_OV0_AUTO_FLIP_CNTL) ^ RADEON_OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE ));

   OUTREG(RADEON_OV0_REG_LOAD_CNTL, 0);

#if 0
   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "OV0_FLAG_CNTL=0x%08x\n", INREG(RADEON_OV0_FLAG_CNTL));
/*   OUTREG(RADEON_OV0_FLAG_CNTL, 8); */
   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "OV0_VID_BUFFER_CNTL=0x%08x\n", INREG(RADEON_VID_BUFFER_CONTROL));
   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CAP0_BUF_STATUS=0x%08x\n", INREG(RADEON_CAP0_BUF_STATUS));

/*   OUTREG(RADEON_OV0_SCALE_CNTL, 0x417f1B00); */
#endif

   pPriv->videoStatus = CLIENT_VIDEO_ON;
   pPriv->video_stream_active = TRUE;

   info->VideoTimerCallback = RADEONVideoTimerCallback;

   return Success;
}
        /* miscellaneous TV-in helper functions */

static void RADEON_board_setmisc(RADEONPortPrivPtr pPriv)
{
    /* Adjust PAL/SECAM constants for FI1216MF tuner */
    if((((pPriv->tuner_type & 0xf)==5) ||
        ((pPriv->tuner_type & 0xf)==11)||
        ((pPriv->tuner_type & 0xf)==14))
        && (pPriv->fi1236!=NULL))
    {
        if((pPriv->encoding>=1)&&(pPriv->encoding<=3)) /*PAL*/
        {
           pPriv->fi1236->parm.band_low = 0xA1;
           pPriv->fi1236->parm.band_mid = 0x91;
           pPriv->fi1236->parm.band_high = 0x31;
        }
        if((pPriv->encoding>=7)&&(pPriv->encoding<=9)) /*SECAM*/
        {
           pPriv->fi1236->parm.band_low = 0xA3;
           pPriv->fi1236->parm.band_mid = 0x93;
           pPriv->fi1236->parm.band_high = 0x33;
        }
    }
    
}

static void RADEON_RT_SetEncoding(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv)
{
int width, height;
RADEONWaitForIdleMMIO(pScrn);

/* Disable VBI capture for anything but TV tuner */
switch(pPriv->encoding){
	case 2:
	case 5:
	case 8:
		pPriv->capture_vbi_data=1;
		break;
	default:
		pPriv->capture_vbi_data=0;
	}

switch(pPriv->encoding){
        case 1:
                xf86_RT_SetConnector(pPriv->theatre,DEC_COMPOSITE, 0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_PAL | extPAL);
                pPriv->v=25;
                break;
        case 2:
                xf86_RT_SetConnector(pPriv->theatre,DEC_TUNER,0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_PAL | extPAL);
                pPriv->v=25;
                break;
        case 3:
                xf86_RT_SetConnector(pPriv->theatre,DEC_SVIDEO,0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_PAL | extPAL);
                pPriv->v=25;
                break;
        case 4:
                xf86_RT_SetConnector(pPriv->theatre, DEC_COMPOSITE,0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_NTSC | extNONE);
                pPriv->v=23;
                break;
        case 5:
                xf86_RT_SetConnector(pPriv->theatre, DEC_TUNER, 0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_NTSC | extNONE);
                pPriv->v=23;
                break;
        case 6:
                xf86_RT_SetConnector(pPriv->theatre, DEC_SVIDEO, 0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_NTSC | extNONE);
                pPriv->v=23;
                break;
        case 7:
                xf86_RT_SetConnector(pPriv->theatre, DEC_COMPOSITE, 0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_SECAM | extNONE);
                pPriv->v=25;
                break;
        case 8:
                xf86_RT_SetConnector(pPriv->theatre, DEC_TUNER, 0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_SECAM | extNONE);
                pPriv->v=25;
                break;
        case 9:
                xf86_RT_SetConnector(pPriv->theatre, DEC_SVIDEO, 0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_SECAM | extNONE);
                pPriv->v=25;
                break;
        case 10:
                xf86_RT_SetConnector(pPriv->theatre,DEC_COMPOSITE, 0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_PAL | extPAL_60);
                pPriv->v=25;
                break;
        case 11:
                xf86_RT_SetConnector(pPriv->theatre,DEC_TUNER,0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_PAL | extPAL_60);
                pPriv->v=25;
                break;
        case 12:
                xf86_RT_SetConnector(pPriv->theatre,DEC_SVIDEO,0);
                xf86_RT_SetStandard(pPriv->theatre,DEC_PAL | extPAL_60);
                pPriv->v=25;
                break;
        default:
                pPriv->v=0;
                return;
        }       
xf86_RT_SetInterlace(pPriv->theatre, 1);
width = InputVideoEncodings[pPriv->encoding].width;
height = InputVideoEncodings[pPriv->encoding].height;
xf86_RT_SetOutputVideoSize(pPriv->theatre, width, height*2, 0, pPriv->capture_vbi_data);   
}

static void RADEON_MSP_SetEncoding(RADEONPortPrivPtr pPriv)
{
xf86_MSP3430SetVolume(pPriv->msp3430, MSP3430_FAST_MUTE);
switch(pPriv->encoding){
        case 1:
                pPriv->msp3430->standard = MSP3430_PAL;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_3;
                break;
        case 2:
                pPriv->msp3430->standard = MSP3430_PAL;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_1;
                break;
        case 3:
                pPriv->msp3430->standard = MSP3430_PAL;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_2;
                break;
        case 4:
                pPriv->msp3430->standard = MSP3430_NTSC;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_3;
                break;
        case 5:
                pPriv->msp3430->standard = MSP3430_NTSC;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_1;
                break;
        case 6:
                pPriv->msp3430->standard = MSP3430_NTSC;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_2;
                break;
        case 7:
                pPriv->msp3430->standard = MSP3430_SECAM;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_3;
                break;
        case 8:
                pPriv->msp3430->standard = MSP3430_SECAM;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_1;
                break;
        case 9:
                pPriv->msp3430->standard = MSP3430_SECAM;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_2;
                break;
        case 10:
                pPriv->msp3430->standard = MSP3430_SECAM;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_3;
                break;
        case 11:
                pPriv->msp3430->standard = MSP3430_SECAM;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_1;
                break;
        case 12:
                pPriv->msp3430->standard = MSP3430_SECAM;
                pPriv->msp3430->connector = MSP3430_CONNECTOR_2;
                break;
        default:
                return;
        }
xf86_InitMSP3430(pPriv->msp3430);
xf86_MSP3430SetVolume(pPriv->msp3430, pPriv->mute ? MSP3430_FAST_MUTE : MSP3430_VOLUME(pPriv->volume));
}

static void RADEON_TDA9885_SetEncoding(RADEONPortPrivPtr pPriv)
{
TDA9885Ptr t=pPriv->tda9885;

switch(pPriv->encoding){
                /* PAL */
        case 1:
        case 2:
        case 3:
                t->standard_video_if=2;
                t->standard_sound_carrier=1;
					 t->modulation=2; /* negative FM */
                break;
                /* NTSC */
        case 4:
        case 5:
        case 6:
                t->standard_video_if=1;
                t->standard_sound_carrier=0;
					 t->modulation=2; /* negative FM */
                break;
                /* SECAM */
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
                t->standard_video_if=0;
                t->standard_sound_carrier=3;
                t->modulation=0; /* positive AM */
                break;
        default:
                return;
        }       
xf86_tda9885_setparameters(pPriv->tda9885); 
xf86_tda9885_getstatus(pPriv->tda9885);
xf86_tda9885_dumpstatus(pPriv->tda9885);
}

static void RADEON_FI1236_SetEncoding(RADEONPortPrivPtr pPriv)
{
/* at the moment this only affect MT2032 */
switch(pPriv->encoding){
                /* PAL */
        case 1:
        case 2:
        case 3:
		pPriv->fi1236->video_if=38.900;
                break;
                /* NTSC */
        case 4:
        case 5:
        case 6:
		pPriv->fi1236->video_if=45.7812;
		pPriv->fi1236->video_if=45.750;
		pPriv->fi1236->video_if=45.125;
                break;
                /* SECAM */
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
		pPriv->fi1236->video_if=58.7812;
                break;
        default:
                return;
        }       
}