/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nsc/nsc_gx1_video.c,v 1.7tsi Exp $ */
/*
 * $Workfile: nsc_gx1_video.c $
 * $Revision: 1.1.1.1 $
 * $Author: alanh $
 *
 * File Contents: This file consists of main Xfree video supported routines.
 *
 * Project:       Geode Xfree Frame buffer device driver.
 *
 */

/* 
 * NSC_LIC_ALTERNATIVE_PREAMBLE
 *
 * Revision 1.0
 *
 * National Semiconductor Alternative GPL-BSD License
 *
 * National Semiconductor Corporation licenses this software 
 * ("Software"):
 *
 * National Xfree frame buffer driver
 *
 * under one of the two following licenses, depending on how the 
 * Software is received by the Licensee.
 * 
 * If this Software is received as part of the Linux Framebuffer or
 * other GPL licensed software, then the GPL license designated 
 * NSC_LIC_GPL applies to this Software; in all other circumstances 
 * then the BSD-style license designated NSC_LIC_BSD shall apply.
 *
 * END_NSC_LIC_ALTERNATIVE_PREAMBLE */

/* NSC_LIC_BSD
 *
 * National Semiconductor Corporation Open Source License for 
 *
 * National Xfree frame buffer driver
 *
 * (BSD License with Export Notice)
 *
 * Copyright (c) 1999-2001
 * National Semiconductor Corporation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 *
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer. 
 *
 *   * Redistributions in binary form must reproduce the above 
 *     copyright notice, this list of conditions and the following 
 *     disclaimer in the documentation and/or other materials provided 
 *     with the distribution. 
 *
 *   * Neither the name of the National Semiconductor Corporation nor 
 *     the names of its contributors may be used to endorse or promote 
 *     products derived from this software without specific prior 
 *     written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY 
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF 
 * YOUR JURISDICTION. It is licensee's responsibility to comply with 
 * any export regulations applicable in licensee's jurisdiction. Under 
 * CURRENT (2001) U.S. export regulations this software 
 * is eligible for export from the U.S. and can be downloaded by or 
 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed 
 * destinations which include Cuba, Iraq, Libya, North Korea, Iran, 
 * Syria, Sudan, Afghanistan and any other country to which the U.S. 
 * has embargoed goods and services. 
 *
 * END_NSC_LIC_BSD */

/* NSC_LIC_GPL
 *
 * National Semiconductor Corporation Gnu General Public License for 
 *
 * National Xfree frame buffer driver
 *
 * (GPL License with Export Notice)
 *
 * Copyright (c) 1999-2001
 * National Semiconductor Corporation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted under the terms of the GNU General 
 * Public License as published by the Free Software Foundation; either 
 * version 2 of the License, or (at your option) any later version  
 *
 * In addition to the terms of the GNU General Public License, neither 
 * the name of the National Semiconductor Corporation nor the names of 
 * its contributors may be used to endorse or promote products derived 
 * from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY 
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE, 
 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE. See the GNU General Public License for more details. 
 *
 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF 
 * YOUR JURISDICTION. It is licensee's responsibility to comply with 
 * any export regulations applicable in licensee's jurisdiction. Under 
 * CURRENT (2001) U.S. export regulations this software 
 * is eligible for export from the U.S. and can be downloaded by or 
 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed 
 * destinations which include Cuba, Iraq, Libya, North Korea, Iran, 
 * Syria, Sudan, Afghanistan and any other country to which the U.S. 
 * has embargoed goods and services. 
 *
 * You should have received a copy of the GNU General Public License 
 * along with this file; if not, write to the Free Software Foundation, 
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 *
 * END_NSC_LIC_GPL */

/* 
 * Fixes & Extensions to support Y800 greyscale modes 
 * Alan Hourihane <alanh@fairlite.demon.co.uk>
 */

#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86Resources.h"
#include "xf86_ansic.h"
#include "compiler.h"
#include "xf86PciInfo.h"
#include "xf86Pci.h"
#include "xf86fbman.h"
#include "regionstr.h"

#include "nsc.h"
#include "Xv.h"
#include "xaa.h"
#include "xaalocal.h"
#include "dixstruct.h"
#include "fourcc.h"
#include "nsc_fourcc.h"

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

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

#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
#define XV_PROFILE 0
#define REINIT  1

void GX1InitVideo(ScreenPtr pScreen);
void GX1ResetVideo(ScrnInfoPtr pScrn);

#define DBUF 0

static XF86VideoAdaptorPtr GX1SetupImageVideo(ScreenPtr);
static void GX1InitOffscreenImages(ScreenPtr);
static void GX1StopVideo(ScrnInfoPtr, pointer, Bool);
static int GX1SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
static int GX1GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
static void GX1QueryBestSize(ScrnInfoPtr, Bool,
			     short, short, short, short, unsigned int *,
			     unsigned int *, pointer);
static int GX1PutImage(ScrnInfoPtr,
		       short, short, short, short, short, short,
		       short, short, int, unsigned char *, short, short,
		       Bool, RegionPtr, pointer);
static int GX1QueryImageAttributes(ScrnInfoPtr,
				   int, unsigned short *, unsigned short *,
				   int *, int *);

static void GX1BlockHandler(int, pointer, pointer, pointer);

void GX1SetVideoPosition(int, int, int, int,
			 short, short, short, short, int, int, ScrnInfoPtr);

extern void GX1AccelSync(ScrnInfoPtr pScreenInfo);

#if !defined(STB_X)
extern int DeltaX, DeltaY;
#else
int DeltaX, DeltaY;
#endif

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

static Atom xvColorKey, xvColorKeyMode, xvFilter
#if DBUF
  , xvDoubleBuffer
#endif
  ;

/*----------------------------------------------------------------------------
 * GX1InitVideo
 *
 * Description	:This is the initialization routine.It creates a new video adapter
 *				 and calls GX1SetupImageVideo to initialize the adaptor by filling
 *				 XF86VideoAdaptorREc.Then it lists the existing adaptors and adds the 
 *				 new one to it. Finally the list of XF86VideoAdaptorPtr pointers are
 *				 passed to the xf86XVScreenInit().
 *
 * Parameters.
 * ScreenPtr
 *		pScreen	:Screen handler pointer having screen information.
 *
 * Returns		:none
 *
 * Comments		:none
 *
*----------------------------------------------------------------------------
*/
void
GX1InitVideo(ScreenPtr pScreen)
{
   GeodePtr pGeode;

   ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum];

   pGeode = GEODEPTR(pScreenInfo);

   if (!pGeode->NoAccel) {
      ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
      XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
      XF86VideoAdaptorPtr newAdaptor = NULL;

      int num_adaptors;

      DEBUGMSG(0, (0, X_NONE, "InitVideo\n"));
      newAdaptor = GX1SetupImageVideo(pScreen);
      GX1InitOffscreenImages(pScreen);

      num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);

      if (newAdaptor) {
	 if (!num_adaptors) {
	    num_adaptors = 1;
	    adaptors = &newAdaptor;
	 } else {
	    newAdaptors =		/* need to free this someplace */
		  xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
	    if (newAdaptors) {
	       memcpy(newAdaptors, adaptors, num_adaptors *
		      sizeof(XF86VideoAdaptorPtr));
	       newAdaptors[num_adaptors] = newAdaptor;
	       adaptors = newAdaptors;
	       num_adaptors++;
	    }
	 }
      }

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

      if (newAdaptors)
	 xfree(newAdaptors);
   }
}

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

#define NUM_FORMATS 4

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

#if DBUF
#define NUM_ATTRIBUTES 4
#else
#define NUM_ATTRIBUTES 3
#endif

static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
#if DBUF
   {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
#endif
   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
   {XvSettable | XvGettable, 0, 1, "XV_FILTER"},
   {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"}
};

#define NUM_IMAGES 7

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

typedef struct
{
   FBAreaPtr area;
   FBLinearPtr linear;
   RegionRec clip;
   CARD32 colorKey;
   CARD32 colorKeyMode;
   CARD32 filter;
   CARD32 videoStatus;
   Time offTime;
   Time freeTime;
#if DBUF
   Bool doubleBuffer;
   int currentBuffer;
#endif
}
GeodePortPrivRec, *GeodePortPrivPtr;

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

/*----------------------------------------------------------------------------
 * GX1SetColorKey
 *
 * Description	:This function reads the color key for the pallete and
 *				  sets the video color key register.
 *
 * Parameters.
 * ScreenInfoPtr
 *		pScrn	:Screen  pointer having screen information.
 *		pPriv	:Video port private data
 *
 * Returns		:none
 *
 * Comments		:none
 *
*----------------------------------------------------------------------------
*/
static INT32
GX1SetColorkey(ScrnInfoPtr pScrn, GeodePortPrivPtr pPriv)
{
   int red, green, blue;
   unsigned long key;

   DEBUGMSG(0, (0, X_NONE, "ColorKey\n"));
   switch (pScrn->depth) {
   case 8:
      GFX(get_display_palette_entry(pPriv->colorKey & 0xFF, &key));
      red = ((key >> 16) & 0xFF);
      green = ((key >> 8) & 0xFF);
      blue = (key & 0xFF);
      break;
   default:
      red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red << (8 -
									 pScrn->
									 weight.
									 red);
      green =
	    (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.
	    green << (8 - pScrn->weight.green);
      blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.
	    blue << (8 - pScrn->weight.blue);
      break;
   }
   GFX(set_video_color_key((blue | (green << 8) | (red << 16)), 0xFCFCFC,
			   (pPriv->colorKeyMode == 0)));
   REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
   return 0;
}

/*----------------------------------------------------------------------------
 * GX1ResetVideo
 *
 * Description	: This function resets the video
 *
 * Parameters.
 * ScreenInfoPtr
 *		pScrn	:Screen  pointer having screen information.
 *
 * Returns		:None
 *
 * Comments		:none
 *
*----------------------------------------------------------------------------
*/

void
GX1ResetVideo(ScrnInfoPtr pScrn)
{
   GeodePtr pGeode = GEODEPTR(pScrn);

   if (!pGeode->NoAccel) {
      GeodePortPrivPtr pPriv = pGeode->adaptor->pPortPrivates[0].ptr;

      DEBUGMSG(0, (0, X_NONE, "ResetVideo\n"));
      GX1AccelSync(pScrn);
      GFX(set_video_palette(NULL));
      GX1SetColorkey(pScrn, pPriv);
      GFX(set_video_filter(pPriv->filter, pPriv->filter));
   }
}

/*----------------------------------------------------------------------------
 * GX1SetupImageVideo
 *
 * Description	: This function allocates space for a Videoadaptor and initializes
 *				  the XF86VideoAdaptorPtr record.
 *
 * Parameters.
 * ScreenPtr
 *		pScreen	:Screen handler pointer having screen information.
 *
 * Returns		:XF86VideoAdaptorPtr :- pointer to the initialized video adaptor record.
 *
 * Comments		:none
 *
*----------------------------------------------------------------------------
*/

static XF86VideoAdaptorPtr
GX1SetupImageVideo(ScreenPtr pScreen)
{
   ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
   GeodePtr pGeode = GEODEPTR(pScrn);
   XF86VideoAdaptorPtr adapt;
   GeodePortPrivPtr pPriv;

   DEBUGMSG(0, (0, X_NONE, "SetupImageVideo\n"));
   if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
			 sizeof(GeodePortPrivRec) + sizeof(DevUnion))))
      return NULL;

   adapt->type = XvWindowMask | XvInputMask | XvImageMask;
   adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
   adapt->name = "National Semiconductor Corporation";
   adapt->nEncodings = 1;
   adapt->pEncodings = DummyEncoding;
   adapt->nFormats = NUM_FORMATS;
   adapt->pFormats = Formats;
   adapt->nPorts = 1;
   adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
   pPriv = (GeodePortPrivPtr) (&adapt->pPortPrivates[1]);
   adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
   adapt->pAttributes = Attributes;
   adapt->nImages = NUM_IMAGES;
   adapt->nAttributes = NUM_ATTRIBUTES;
   adapt->pImages = Images;
   adapt->PutVideo = NULL;
   adapt->PutStill = NULL;
   adapt->GetVideo = NULL;
   adapt->GetStill = NULL;
   adapt->StopVideo = GX1StopVideo;
   adapt->SetPortAttribute = GX1SetPortAttribute;
   adapt->GetPortAttribute = GX1GetPortAttribute;
   adapt->QueryBestSize = GX1QueryBestSize;
   adapt->PutImage = GX1PutImage;
   adapt->QueryImageAttributes = GX1QueryImageAttributes;

   pPriv->colorKey = pGeode->videoKey;
   pPriv->colorKeyMode = 0;
   pPriv->filter = 0;
   pPriv->videoStatus = 0;
#if DBUF
   pPriv->doubleBuffer = TRUE;
   pPriv->currentBuffer = 0;		/* init to first buffer */
#endif

   /* gotta uninit this someplace */
   REGION_NULL(pScreen, &pPriv->clip);

   pGeode->adaptor = adapt;

   pGeode->BlockHandler = pScreen->BlockHandler;
   pScreen->BlockHandler = GX1BlockHandler;

   xvColorKey = MAKE_ATOM("XV_COLORKEY");
   xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE");
   xvFilter = MAKE_ATOM("XV_FILTER");
#if DBUF
   xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
#endif

   GX1ResetVideo(pScrn);

   return adapt;
}

/*----------------------------------------------------------------------------
 * GX1StopVideo
 *
 * Description	:This function is used to stop input and output video
 *
 * Parameters.
 * pScreenInfo
 *		pScrn		:Screen handler pointer having screen information.
 *		data		:Pointer to the video port's private data
 *		exit		:Flag indicating whether the offscreen areas used for video
 *					 to be deallocated or not.
 * Returns		:none
 *
 * Comments		:none
 *
*----------------------------------------------------------------------------
*/
static void
GX1StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
{
   GeodePortPrivPtr pPriv = (GeodePortPrivPtr) data;
   GeodePtr pGeode = GEODEPTR(pScrn);

   DEBUGMSG(0, (0, X_NONE, "StopVideo\n"));
   REGION_EMPTY(pScrn->pScreen, &pPriv->clip);

   GX1AccelSync(pScrn);
   if (exit) {
      if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
	 GFX(set_video_enable(0));
      }
      if (pPriv->area) {
	 xf86FreeOffscreenArea(pPriv->area);
	 pPriv->area = NULL;
      }
      pPriv->videoStatus = 0;
      pGeode->OverlayON = FALSE;
   } else {
      if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
	 pPriv->videoStatus |= OFF_TIMER;
	 pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
      }
   }
}

/*----------------------------------------------------------------------------
 * GX1SetPortAttribute
 *
 * Description	:This function is used to set the attributes of a port like colorkeymode,
 *				  double buffer support and filter.
 *
 * Parameters.
 * pScreenInfo
 *		Ptr			:Screen handler pointer having screen information.
 *		data		:Pointer to the video port's private data
 *		attribute	:The port attribute to be set
 *		value		:Value of the attribute to be set.  
 *					 
 * Returns		:Sucess if the attribute is supported, else BadMatch
 *
 * Comments		:none
 *
*----------------------------------------------------------------------------
*/
static int
GX1SetPortAttribute(ScrnInfoPtr pScrn,
		    Atom attribute, INT32 value, pointer data)
{
   GeodePortPrivPtr pPriv = (GeodePortPrivPtr) data;

   GX1AccelSync(pScrn);
   if (attribute == xvColorKey) {
      pPriv->colorKey = value;
      GX1SetColorkey(pScrn, pPriv);
   }
#if DBUF
   else if (attribute == xvDoubleBuffer) {
      if ((value < 0) || (value > 1))
	 return BadValue;
      pPriv->doubleBuffer = value;
   }
#endif
   else if (attribute == xvColorKeyMode) {
      pPriv->colorKeyMode = value;
      GX1SetColorkey(pScrn, pPriv);
   } else if (attribute == xvFilter) {
      pPriv->filter = value;
      GFX(set_video_filter(pPriv->filter, pPriv->filter));
   } else
      return BadMatch;

   return Success;
}

/*----------------------------------------------------------------------------
 * GX1GetPortAttribute
 *
 * Description	:This function is used to get the attributes of a port like hue,
 *				 saturation,brightness or contrast.
 *
 * Parameters.
 * pScreenInfo
 *		Ptr			:Screen handler pointer having screen information.
 *		data		:Pointer to the video port's private data
 *		attribute	:The port attribute to be read
 *		value		:Pointer to the value of the attribute to be read.  
 *					 
 * Returns		:Sucess if the attribute is supported, else BadMatch
 *
 * Comments		:none
 *
*----------------------------------------------------------------------------
*/
static int
GX1GetPortAttribute(ScrnInfoPtr pScrn,
		    Atom attribute, INT32 * value, pointer data)
{
   GeodePortPrivPtr pPriv = (GeodePortPrivPtr) data;

   if (attribute == xvColorKey) {
      *value = pPriv->colorKey;
   }
#if DBUF
   else if (attribute == xvDoubleBuffer) {
      *value = (pPriv->doubleBuffer) ? 1 : 0;
   }
#endif
   else if (attribute == xvColorKeyMode) {
      *value = pPriv->colorKeyMode;
   } else if (attribute == xvFilter) {
      *value = pPriv->filter;
   } else
      return BadMatch;

   return Success;
}

/*----------------------------------------------------------------------------
 * GX1QueryBestSize
 *
 * Description	:This function provides a way to query what the destination dimensions
 *				 would end up being if they were to request that an area vid_w by vid_h
 *               from the video stream be scaled to rectangle of drw_w by drw_h on 
 *				 the screen.
 *
 * Parameters.
 * ScreenInfoPtr
 *		pScrn		:Screen handler pointer having screen information.
 *		data		:Pointer to the video port's private data
 *      vid_w,vid_h	:Width and height of the video data.
 *		drw_w,drw_h :Width and height of the scaled rectangle.
 *		p_w,p_h		:Width and height of the destination rectangle. 
 *					 
 * Returns		:None
 *
 * Comments		:None
 *
*----------------------------------------------------------------------------
*/
static void
GX1QueryBestSize(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)
{
   DEBUGMSG(0, (0, X_NONE, "QueryBestSize\n"));
   *p_w = drw_w;
   *p_h = drw_h;

   if (*p_w > 16384)
      *p_w = 16384;
}
static void
GX1CopyGreyscale(unsigned char *src,
		 unsigned char *dst, int srcPitch, int dstPitch, int h, int w)
{
   int i;
   unsigned char *src2 = src;
   unsigned char *dst2 = dst;
   unsigned char *dst3;
   unsigned char *src3;

   dstPitch <<= 1;

   while (h--) {
      dst3 = dst2;
      src3 = src2;
      for (i = 0; i < w; i++) {
	 *dst3++ = *src3++;		/* Copy Y data */
	 *dst3++ = 0x80;		/* Fill UV with 0x80 - greyscale */
      }
      src3 = src2;
      for (i = 0; i < w; i++) {
	 *dst3++ = *src3++;		/* Copy Y data */
	 *dst3++ = 0x80;		/* Fill UV with 0x80 - greyscale */
      }
      dst2 += dstPitch;
      src2 += srcPitch;
   }
}

/*----------------------------------------------------------------------------
 * GX1CopyData
 *
 * Description	: Copies data from src to destination
 *
 * Parameters.
 *		src			: pointer to the source data
 *		dst			: pointer to destination data
 *		srcPitch	: pitch of the srcdata
 *		dstPitch	: pitch of the destination data 
 *		h & w		: height and width of source data
 *					 
 * Returns		:None
 *
 * Comments		:None
 *
*----------------------------------------------------------------------------
*/

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

static void
GX1CopyMungedData(unsigned char *src1,
		  unsigned char *src2,
		  unsigned char *src3,
		  unsigned char *dst1,
		  int srcPitch, int srcPitch2, int dstPitch, int h, int w)
{
   CARD32 *dstCur = (CARD32 *) dst1;
   CARD32 *dstNext = (CARD32 *) dst1;
   int i, j, k, m, n;
   CARD32 crcb;

#if XV_PROFILE
   long oldtime, newtime;
#endif

   DEBUGMSG(0, (0, X_NONE, "CopyMungedData\n"));
   /* dstPitch is in byte count, but we write longs.
    * so divide dstpitch by 4 
    */
   dstPitch >>= 2;
   /* Width is in byte but video data is 16bit
    */
   w >>= 1;
   /* We render 2 scanlines at one shot, handle the odd count */
   m = h & 1;
   /* decrement the height since we write 2 scans */
   h -= 1;
   /* we traverse by 2 bytes in src Y */
   srcPitch <<= 1;
#if XV_PROFILE
   UpdateCurrentTime();
   oldtime = currentTime.milliseconds;
#endif

   for (j = 0; j < h; j += 2) {
      /* calc the next dest scan start */
      dstNext = dstCur + dstPitch;
      for (i = 0; i < w; i++) {
	 /* crcb is same for the x pixel for 2 scans */
	 crcb = (src3[i] << 8) | (src2[i] << 24);

	 n = i << 1;

	 /* write the first scan pixel DWORD */
	 dstCur[i] = src1[n] | (src1[n + 1] << 16) | crcb;

	 /* calc the offset of next pixel */
	 k = n + srcPitch;

	 /* write the 2nd scan pixel DWORD */
	 dstNext[i] = src1[k] | (src1[k + 1] << 16) | crcb;
      }
      /* increment the offsets */

      /* Y */
      src1 += srcPitch;
      /* crcb */
      src2 += srcPitch2;
      src3 += srcPitch2;
      /* processed dest */
      dstCur += (dstPitch << 1);
   }

   /* if any scans remaining */
   if (m) {
      for (i = 0, k = 0; i < w; i++, k += 2) {
	 dstCur[i] = src1[k] | (src1[k + 1] << 16) |
	       (src3[i] << 8) | (src2[i] << 24);
      }
   }
#if XV_PROFILE
   UpdateCurrentTime();
   newtime = currentTime.milliseconds;
   DEBUGMSG(1, (0, X_NONE, "CMD %d\n", newtime - oldtime));
#endif
}

static FBAreaPtr
GX1AllocateMemory(ScrnInfoPtr pScrn, FBAreaPtr area, int numlines)
{
   ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
   FBAreaPtr new_area;

   if (area) {
      if ((area->box.y2 - area->box.y1) >= numlines)
	 return area;

      if (xf86ResizeOffscreenArea(area, pScrn->displayWidth, numlines))
	 return area;

      xf86FreeOffscreenArea(area);
   }

   new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
					numlines, 0, NULL, NULL, NULL);

   if (!new_area) {
      int max_w, max_h;

      xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
				    FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);

      if ((max_w < pScrn->displayWidth) || (max_h < numlines))
	 return NULL;

      xf86PurgeUnlockedOffscreenAreas(pScreen);
      new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
					   numlines, 0, NULL, NULL, NULL);
   }
   return new_area;
}

static BoxRec dstBox;
static int srcPitch = 0, srcPitch2 = 0, dstPitch = 0;
static INT32 Bx1, Bx2, By1, By2;
static int top, left, npixels, nlines;
static int offset, s1offset = 0, s2offset = 0, s3offset = 0;
static unsigned char *dst_start;
static int TVOverScanX;

static Bool
RegionsIntersect(BoxPtr pRcl1, BoxPtr pRcl2, BoxPtr pRclResult)
{
   pRclResult->x1 = max(pRcl1->x1, pRcl2->x1);
   pRclResult->x2 = min(pRcl1->x2, pRcl2->x2);

   if (pRclResult->x1 <= pRclResult->x2) {
      pRclResult->y1 = max(pRcl1->y1, pRcl2->y1);
      pRclResult->y2 = min(pRcl1->y2, pRcl2->y2);

      if (pRclResult->y1 <= pRclResult->y2) {
	 return (TRUE);
      }
   }

   return (FALSE);
}

void
GX1SetVideoPosition(int x, int y, int width, int height,
		    short src_w, short src_h, short drw_w, short drw_h,
		    int id, int offset, ScrnInfoPtr pScrn)
{
   GeodePtr pGeode = GEODEPTR(pScrn);
   long xstart, ystart, xend, yend;
   unsigned long lines = 0;
   unsigned long y_extra = 0;
   unsigned short crop = 0;
   BoxRec ovly, display, result;

#if defined(STB_X)
   unsigned long startAddress = 0;
#endif
   xend = x + drw_w;
   yend = y + drw_h;

   /* Take care of panning when panel is present */

#if defined(STB_X)
   Gal_get_display_offset(&startAddress);
   DeltaY = startAddress / pGeode->Pitch;
   DeltaX = startAddress & (pGeode->Pitch - 1);
   DeltaX /= (pScrn->bitsPerPixel >> 3);
#endif

   if (pGeode->Panel) {
      ovly.x1 = x;
      ovly.x2 = x + pGeode->video_dstw;
      ovly.y1 = y;
      ovly.y2 = y + pGeode->video_dsth;

      display.x1 = DeltaX;
      display.x2 = DeltaX + pGeode->FPBX;
      display.y1 = DeltaY;
      display.y2 = DeltaY + pGeode->FPBY;

      x = xend = 0;

      if (RegionsIntersect(&display, &ovly, &result)) {
	 x = ovly.x1 - DeltaX;
	 xend = ovly.x2 - DeltaX;
	 y = ovly.y1 - DeltaY;
	 yend = ovly.y2 - DeltaY;
      }
   }

   /*  LEFT CLIPPING */

   if (x < 0) {
      if (TVOverScanX)
	 xstart = TVOverScanX;
      else
	 xstart = 0;
   } else {
      if (TVOverScanX)
	 xstart = TVOverScanX;
      else
	 xstart = (unsigned long)x;
   }
   drw_w -= (xstart - x);

   /*  TOP CLIPPING */

   if (y < 0) {
      lines = (-y) * src_h / drw_h;
      ystart = 0;
      drw_h += y;
      y_extra = lines * dstPitch;
   } else {
      ystart = y;
      lines = 0;
      y_extra = 0;
   }

   /* CLIP RIGHT AND BOTTOM FOR TV OVER SCAN */
   if (pGeode->TV_Overscan_On) {
      crop = (pGeode->TVOw + pGeode->TVOx);
      if ((xstart + drw_w) > crop)
	 xend = crop;
      crop = (pGeode->TVOh + pGeode->TVOy);
      if ((ystart + drw_h) > crop)
	 yend = crop;
   }
   GFX(set_video_window(xstart, ystart, xend - xstart, yend - ystart));
   GFX(set_video_offset(offset + y_extra));
   GFX(set_video_left_crop(xstart - x));

}

/*----------------------------------------------------------------------------
 * GX1DisplayVideo
 *
 * Description		: This function sets up the video registers for playing video
 *					  It sets up the video format,width, height & position of the 
 *					  video window ,video offsets( y,u,v) and video pitches(y,u,v)	
 * Parameters.
 *					 
 * Returns		:None
 *
 * Comments		:None
 *
*----------------------------------------------------------------------------
*/

static void
GX1DisplayVideo(ScrnInfoPtr pScrn,
		int id,
		int offset,
		short width, short height,
		int pitch,
		int x1, int y1, int x2, int y2,
		BoxPtr dstBox,
		short src_w, short src_h, short drw_w, short drw_h)
{
   GeodePtr pGeode = GEODEPTR(pScrn);

   /*    DisplayModePtr mode = pScrn->currentMode; */
   GX1AccelSync(pScrn);

   GFX(set_video_enable(1));

   switch (id) {
   case FOURCC_UYVY:			/* UYVY */
      GFX(set_video_format(VIDEO_FORMAT_UYVY));
      break;
   case FOURCC_Y800:			/* Y800 - greyscale - we munge it! */
   case FOURCC_YV12:
   case FOURCC_I420:
   case FOURCC_YUY2:			/* YUY2 */
      GFX(set_video_format(VIDEO_FORMAT_YUYV));
      break;
   case FOURCC_Y2YU:			/* Y2YU */
      GFX(set_video_format(VIDEO_FORMAT_Y2YU));
      break;
   case FOURCC_YVYU:			/* YVYU */
      GFX(set_video_format(VIDEO_FORMAT_YVYU));
      break;
   }

   if (pGeode->TV_Overscan_On) {
      if (dstBox->x1 < 0)
	 TVOverScanX = pGeode->TVOx;
      else
	 TVOverScanX = 0;
      dstBox->x1 += pGeode->TVOx;
      dstBox->y1 += pGeode->TVOy;
   }
   if (pGeode->Panel) {
      pGeode->video_x = dstBox->x1;
      pGeode->video_y = dstBox->y1;
      pGeode->video_w = width;
      pGeode->video_h = height;
      pGeode->video_srcw = src_w;
      pGeode->video_srch = src_h;
      pGeode->video_dstw = drw_w;
      pGeode->video_dsth = drw_h;
      pGeode->video_offset = offset;
      pGeode->video_id = id;
      pGeode->video_scrnptr = pScrn;
   }

   GFX(set_video_size(width, height));
   GFX(set_video_scale(width, height, drw_w, drw_h));
   GX1SetVideoPosition(dstBox->x1, dstBox->y1, width, height, src_w, src_h,
		       drw_w, drw_h, id, offset, pScrn);
   GFX(set_color_space_YUV(0));
}

/*----------------------------------------------------------------------------
 * GX1PutImage	: This function writes a single frame of video into a drawable.
 *		The position and size of the source rectangle is specified by src_x,src_y,
 *		src_w and src_h. This data is stored in a system memory buffer at buf.  
 *		The position and size of the destination rectangle is specified by drw_x,
 *      drw_y,drw_w,drw_h.The data is in the format indicated by the image descriptor 
 *		and represents a source of size width by height.  If sync is TRUE the driver 
 *		should not return from this function until it is through reading the data from 
 *		buf.  Returning when sync is TRUE indicates that it is safe for the data at buf
 *		to be replaced,freed, or modified.
 *
 *
 * Description		: 
 * Parameters.
 *					 
 * Returns		:None
 *
 * Comments		:None
 *
*----------------------------------------------------------------------------
*/

static int
GX1PutImage(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)
{
   GeodePortPrivPtr pPriv = (GeodePortPrivPtr) data;
   GeodePtr pGeode = GEODEPTR(pScrn);
   int pitch, new_h;

#if REINIT
   BOOL ReInitVideo = FALSE;
#endif

#if XV_PROFILE
   long oldtime, newtime;

   UpdateCurrentTime();
   oldtime = currentTime.milliseconds;
#endif

#if REINIT
/* update cliplist */
   if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
      ReInitVideo = TRUE;
   }
   if (ReInitVideo) {
      DEBUGMSG(1, (0, X_NONE, "Regional Not Equal - Init\n"));
#endif

      if (drw_w > 16384)
	 drw_w = 16384;

      /* Clip */
      Bx1 = src_x;
      Bx2 = src_x + src_w;
      By1 = src_y;
      By2 = src_y + src_h;

      if ((Bx1 >= Bx2) || (By1 >= By2))
	 return Success;

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

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

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

      dstPitch = ((width << 1) + 3) & ~3;

      switch (id) {
      case FOURCC_YV12:
      case FOURCC_I420:
	 srcPitch = (width + 3) & ~3;	/* of luma */
	 s2offset = srcPitch * height;
	 srcPitch2 = ((width >> 1) + 3) & ~3;
	 s3offset = (srcPitch2 * (height >> 1)) + s2offset;
	 break;
      case FOURCC_UYVY:
      case FOURCC_YUY2:
      case FOURCC_Y800:
      default:
	 srcPitch = (width << 1);
	 break;
      }

      /* Find how many pitch scanlines required to store the data */
      new_h = ((dstPitch * height) + pitch - 1) / pitch;

#if DBUF
      if (pPriv->doubleBuffer)
	 new_h <<= 1;
#endif

      if (!(pPriv->area = GX1AllocateMemory(pScrn, pPriv->area, new_h)))
	 return BadAlloc;

      /* copy data */
      top = By1;
      left = Bx1 & ~1;
      npixels = ((Bx2 + 1) & ~1) - left;

      switch (id) {
      case FOURCC_YV12:
      case FOURCC_I420:
	 {
	    int tmp;

	    top &= ~1;
	    offset = (pPriv->area->box.y1 * pitch) + (top * dstPitch);

#if DBUF
	    if (pPriv->doubleBuffer && pPriv->currentBuffer)
	       offset += (new_h >> 1) * pitch;
#endif

	    dst_start = pGeode->FBBase + offset + left;
	    tmp = ((top >> 1) * srcPitch2) + (left >> 1);
	    s2offset += tmp;
	    s3offset += tmp;
	    if (id == FOURCC_I420) {
	       tmp = s2offset;
	       s2offset = s3offset;
	       s3offset = tmp;
	    }
	    nlines = ((By2 + 1) & ~1) - top;
	 }
	 break;

      case FOURCC_UYVY:
      case FOURCC_YUY2:
      case FOURCC_Y800:
      default:
	 left <<= 1;
	 buf += (top * srcPitch) + left;
	 nlines = By2 - top;
	 offset = (pPriv->area->box.y1 * pitch) + (top * dstPitch);

#if DBUF
	 if (pPriv->doubleBuffer && pPriv->currentBuffer)
	    offset += (new_h >> 1) * pitch;
#endif

	 dst_start = pGeode->FBBase + offset + left;
	 break;
      }
      s1offset = (top * srcPitch) + left;

#if REINIT
      /* update cliplist */
      REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
      if (pPriv->colorKeyMode == 0) {
	 /* draw these */
	 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
      }
      GX1DisplayVideo(pScrn, id, offset, width, height, dstPitch,
		      Bx1, By1, Bx2, By2, &dstBox, src_w, src_h, drw_w,
		      drw_h);
   }
#endif

   switch (id) {

   case FOURCC_Y800:
      GX1CopyGreyscale(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
      break;
   case FOURCC_YV12:
   case FOURCC_I420:
      GX1CopyMungedData(buf + s1offset, buf + s2offset,
			buf + s3offset, dst_start, srcPitch, srcPitch2,
			dstPitch, nlines, npixels);
      break;
   case FOURCC_UYVY:
   case FOURCC_YUY2:
   default:
      GX1CopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
      break;
   }
#if !REINIT
   /* update cliplist */
   REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
   if (pPriv->colorKeyMode == 0) {
      /* draw these */
      xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
   }
   GX1DisplayVideo(pScrn, id, offset, width, height, dstPitch,
		   Bx1, By1, Bx2, By2, &dstBox, src_w, src_h, drw_w, drw_h);
#endif

#if XV_PROFILE
   UpdateCurrentTime();
   newtime = currentTime.milliseconds;
   DEBUGMSG(1, (0, X_NONE, "PI %d\n", newtime - oldtime));
#endif

#if DBUF
   pPriv->currentBuffer ^= 1;
#endif

   pPriv->videoStatus = CLIENT_VIDEO_ON;
   pGeode->OverlayON = TRUE;
   return Success;
}

/*----------------------------------------------------------------------------
 * GX1QueryImageAttributes
 *
 * Description	:This function is called to let the driver specify how data
 *				 for a particular image of size width by height should be 
 *				 stored. 		
 *
 * Parameters.
 * pScreenInfo
 *		Ptr			:Screen handler pointer having screen information.
 *		id			:Id for the video format
 *		width		:width  of the image (can be modified by the driver)  
 *		height		:height of the image (can be modified by the driver)  
 * Returns		: Size of the memory required for storing this image
 *
 * Comments		:None
 *
*----------------------------------------------------------------------------
*/
static int
GX1QueryImageAttributes(ScrnInfoPtr pScrn,
			int id,
			unsigned short *w, unsigned short *h,
			int *pitches, int *offsets)
{
   int size;
   int tmp;

   DEBUGMSG(0, (0, X_NONE, "QueryImageAttributes %X\n", id));

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

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

   switch (id) {
   case FOURCC_YV12:
   case FOURCC_I420:
      *h = (*h + 1) & ~1;
      size = (*w + 3) & ~3;
      if (pitches)
	 pitches[0] = size;
      size *= *h;
      if (offsets)
	 offsets[1] = size;
      tmp = ((*w >> 1) + 3) & ~3;
      if (pitches)
	 pitches[1] = pitches[2] = tmp;
      tmp *= (*h >> 1);
      size += tmp;
      if (offsets)
	 offsets[2] = size;
      size += tmp;
      break;
   case FOURCC_UYVY:
   case FOURCC_YUY2:
   case FOURCC_Y800:
   default:
      size = *w << 1;
      if (pitches)
	 pitches[0] = size;
      size *= *h;
      break;
   }
   return size;
}

static void
GX1BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
{
   ScreenPtr pScreen = screenInfo.screens[i];
   ScrnInfoPtr pScrn = xf86Screens[i];
   GeodePtr pGeode = GEODEPTR(pScrn);
   GeodePortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);

   DEBUGMSG(0, (0, X_NONE, "BlockHandler\n"));
   pScreen->BlockHandler = pGeode->BlockHandler;
   (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
   pScreen->BlockHandler = GX1BlockHandler;

   GX1AccelSync(pScrn);
   if (pPriv->videoStatus & TIMER_MASK) {
      UpdateCurrentTime();
      if (pPriv->videoStatus & OFF_TIMER) {
	 if (pPriv->offTime < currentTime.milliseconds) {
	    GFX(set_video_enable(0));
	    pPriv->videoStatus = FREE_TIMER;
	    pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
	 }
      } else {				/* FREE_TIMER */
	 if (pPriv->freeTime < currentTime.milliseconds) {
	    if (pPriv->area) {
	       xf86FreeOffscreenArea(pPriv->area);
	       pPriv->area = NULL;
	    }
	    pPriv->videoStatus = 0;
	 }
      }
   }
}

/****************** Offscreen stuff ***************/

typedef struct
{
   FBAreaPtr area;
   FBLinearPtr linear;
   Bool isOn;
}
OffscreenPrivRec, *OffscreenPrivPtr;

/*----------------------------------------------------------------------------
 * GX1AllocateSurface
 *
 * Description	:This function allocates an area of w by h in the offscreen
 * Parameters.
 * ScreenPtr
 *		pScreen	:Screen handler pointer having screen information.
 * 
 * Returns		:None
 *
 * Comments		:None
 *
*----------------------------------------------------------------------------
*/

static int
GX1AllocateSurface(ScrnInfoPtr pScrn,
		   int id,
		   unsigned short w, unsigned short h, XF86SurfacePtr surface)
{
   FBAreaPtr area;
   int pitch, fbpitch, numlines;
   OffscreenPrivPtr pPriv;

   DEBUGMSG(0, (0, X_NONE, "AllocateSurface %x\n", id));
   if ((w > 1024) || (h > 1024))
      return BadAlloc;

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

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

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

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

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

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

   return Success;
}

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

   if (pPriv->isOn) {
      pPriv->isOn = FALSE;
   }

   return Success;
}

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

   DEBUGMSG(0, (0, X_NONE, "FreeSurface\n"));

   if (pPriv->isOn)
      GX1StopSurface(surface);
   xf86FreeOffscreenArea(pPriv->area);
   xfree(surface->pitches);
   xfree(surface->offsets);
   xfree(surface->devPrivate.ptr);

   return Success;
}

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

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

static int
GX1DisplaySurface(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;
   GeodePortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
   INT32 x1, y1, x2, y2;
   BoxRec dstBox;

   DEBUGMSG(0, (0, X_NONE, "DisplaySuface\n"));
   x1 = src_x;
   x2 = src_x + src_w;
   y1 = src_y;
   y2 = src_y + src_h;

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

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

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

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

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

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

   return Success;
}

/*----------------------------------------------------------------------------
 * GX1InitOffscreenImages
 *
 * Description	:This function sets up the offscreen memory management.It fills 
 *				 in the XF86OffscreenImagePtr structure with functions to handle
 *				 offscreen memory operations. 	
 *
 * Parameters.
 * ScreenPtr
 *		pScreen	:Screen handler pointer having screen information.
 * 
 * Returns		: None
 *
 * Comments		:None
 *
*----------------------------------------------------------------------------
*/
static void
GX1InitOffscreenImages(ScreenPtr pScreen)
{
   XF86OffscreenImagePtr offscreenImages;

   DEBUGMSG(0, (0, X_NONE, "InitOffscreenImages\n"));
   /* need to free this someplace */
   if (!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
      return;

   offscreenImages[0].image = &Images[0];
   offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
   offscreenImages[0].alloc_surface = GX1AllocateSurface;
   offscreenImages[0].free_surface = GX1FreeSurface;
   offscreenImages[0].display = GX1DisplaySurface;
   offscreenImages[0].stop = GX1StopSurface;
   offscreenImages[0].setAttribute = GX1SetSurfaceAttribute;
   offscreenImages[0].getAttribute = GX1GetSurfaceAttribute;
   offscreenImages[0].max_width = 1024;
   offscreenImages[0].max_height = 1024;
   offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
   offscreenImages[0].attributes = Attributes;

   xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
}
