[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[patch] Xv support for neomagic



Hi,

I used the enclosed file to modify the 4.2.1-1 version of xfree to add the support for Xv in neomagic.

In fact the patch is essentially taken from redhat's package (in rawhide).

I am currently using it in my ThinkPad 600x since yesterday and mplayer & xine are quite happy with it.

Can you add it to a next iteration of your packages ?

Thanks,

yas
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/Imakefile xc/programs/Xserver/hw/xfree86/drivers/neomagic/Imakefile
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/Imakefile	Wed Jan 24 01:06:21 2001
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/Imakefile	Thu Apr  4 16:05:44 2002
@@ -4,10 +4,10 @@
 
 
 SRCS = neo_driver.c neo_bank.c neo_cursor.c neo_2097.c neo_2070.c \
-	neo_2090.c neo_2200.c neo_i2c.c neo_shadow.c neo_dga.c
+	neo_2090.c neo_2200.c neo_i2c.c neo_shadow.c neo_dga.c neo_video.c
 
 OBJS = neo_driver.o neo_bank.o neo_cursor.o neo_2097.o neo_2070.o \
-	neo_2090.o neo_2200.o neo_i2c.o neo_shadow.o neo_dga.o
+	neo_2090.o neo_2200.o neo_i2c.o neo_shadow.o neo_dga.o neo_video.o
 
 DEFINES = -DPSZ=8
 
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/NM-reg.txt xc/programs/Xserver/hw/xfree86/drivers/neomagic/NM-reg.txt
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/NM-reg.txt	Thu Jan  1 01:00:00 1970
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/NM-reg.txt	Thu Apr  4 16:05:44 2002
@@ -0,0 +1,69 @@
+NM2160 Register GUESS  
+   --- Overlay and ZV capture ---
+
+2002,2.3.
+
+1. Overlay
+  GRB0  bit5    Format; 0:YUY2/1:RGB
+        bit1    1
+        bit0    Enable overlay ; 1:enable/0:disable
+  GRB1  bit7:4  X2[11:8]
+        bit3:0  X1[11:8]
+  GRB2          X1[7:0]
+  GRB3          X2[7:0]
+  GRB4  bit7:4  Y2[11:8]
+        bit3:0  Y1[11:8]
+  GRB5          Y1[7:0]
+  GRB6          Y2[7:0]
+  GRB7          VRAM offset[24:17]
+  GRB8          VRAM offset[16:9]
+  GRB9          VRAM offset[8:1]
+  GRBA          Width in byte[15:8]
+  GRBB          Width in byte[7:0]
+  GRBC          0x4f
+  GRBD          -
+  GRBE          -
+  GRBF  bit2    0:normal/1:mirror
+        bit1:0  b'10'
+  GRC0          X scale[15:8] ; x1.0 == 0x1000
+  GRC1          X scale[7:0]
+  GRC2          Y scale[15:8] ; x1.0 == 0x1000
+  GRC3          Y scale[7:0]
+  GRC4          brightness   ; -128 to +127
+  GRC5          Color key(R)
+  GRC6          Color key(G) / Color key(8bpp)
+  GRC7          Color key(B)
+
+2. ZV capture
+  GR0A  bit5    Enable extended SR reg. ; 1:enable/0:disable
+        bit0    1
+
+  SR08  bit7:1  b'1010000'
+        bit0    Enable capture ; 1:enable/0:disable
+  SR09          0x11
+  SR0A          0x00
+  SR0B          -
+  SR0C          VRAM offset[8:1]
+  SR0D          VRAM offset[16:9]
+  SR0E          VRAM offset[24:17]
+  SR0F          -
+  SR10          -
+  SR11          -
+  SR12          -
+  SR13          -
+  SR14          Y1[7:0]
+  SR15          Y2[7:0]
+  SR16  bit7:4  Y2[11:4]
+        bit3:0  Y1[11:4]
+  SR17          X1[7:0]
+  SR18          X2[7:0]
+  SR19  bit7:4  X2[11:8]
+        bit3:0  X1[11:8]
+  SR1A          Width in byte[7:0]
+  SR1B          Width in byte[15:8]
+  SR1C          0xfb
+  SR1D          0x00
+  SR1E          0xe2
+  SR1F          0x02
+
+s.nomura@mba.nifty.ne.jp
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo.h xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo.h
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo.h	Mon Oct  1 15:44:07 2001
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo.h	Thu Apr  4 16:05:44 2002
@@ -60,6 +60,11 @@
 
 #include "xf86i2c.h"
 
+#ifdef XvExtension
+# include "xf86xv.h"
+# include "Xv.h"
+#endif /* XvExtension */
+
 /*
  * Driver data structures.
  */
@@ -121,6 +126,10 @@
 /* in neo_dga.c */
 Bool NEODGAInit(ScreenPtr pScreen);
 
+/* in neo_video.c */
+extern void NEOInitVideo(ScreenPtr pScreen);
+extern void NEOResetVideo(ScrnInfoPtr pScrn);
+
 /* shadow regs */
 
 #define NEO_EXT_CR_MAX 0x85
@@ -199,6 +208,8 @@
     unsigned long NeoMMIOAddr;
     unsigned long NeoLinearAddr;
     unsigned char* NeoMMIOBase;
+    unsigned long NeoMMIOAddr2;
+    unsigned char* NeoMMIOBase2;
     unsigned char* NeoFbBase;
     long NeoFbMapSize;
     unsigned long vgaIOBase;
@@ -249,6 +260,17 @@
     RefreshAreaFuncPtr refreshArea;
     void	(*PointerMoved)(int index, int x, int y);
     int rotate;
+    Bool showcache;
+#ifdef XvExtension
+    Bool video;
+    double videoHZoom;
+    double videoVZoom;
+    XF86VideoAdaptorPtr overlayAdaptor;
+    int overlay;
+    int overlay_offset;
+    int videoKey;
+    int interlace;
+#endif /* XvExtension */
 } NEORec, *NEOPtr;
 
 typedef struct {
@@ -264,18 +286,20 @@
 #define GRAX	0x3CE
 
 /* vga IO functions */
-#define VGArCR(index) hwp->readCrtc(hwp,index)
-#define VGAwCR(index,val) hwp->writeCrtc(hwp,index,val)
-#define VGArGR(index) hwp->readGr(hwp,index)
-#define VGAwGR(index,val) hwp->writeGr(hwp,index,val)
+#define VGArCR(index)		(*hwp->readCrtc)(hwp, index)
+#define VGAwCR(index, val)	(*hwp->writeCrtc)(hwp, index, val)
+#define VGArGR(index)		(*hwp->readGr)(hwp, index)
+#define VGAwGR(index, val)	(*hwp->writeGr)(hwp, index, val)
+#define VGArSR(index)		(*hwp->readSeq)(hwp, index)
+#define VGAwSR(index, val)	(*hwp->writeSeq)(hwp, index, val)
 
 /* memory mapped register access macros */
-#define INREG8(addr) MMIO_IN8(nPtr->NeoMMIOBase, (addr))
-#define INREG16(addr) MMIO_IN16(nPtr->NeoMMIOBase, (addr))
-#define INREG(addr) MMIO_IN32(nPtr->NeoMMIOBase, (addr))
-#define OUTREG8(addr, val) MMIO_OUT8(nPtr->NeoMMIOBase, (addr), (val))
-#define OUTREG16(addr, val) MMIO_OUT16(nPtr->NeoMMIOBase, (addr), (val))
-#define OUTREG(addr, val) MMIO_OUT32(nPtr->NeoMMIOBase, (addr), (val))
+#define INREG8(addr)		MMIO_IN8(nPtr->NeoMMIOBase, addr)
+#define INREG16(addr)		MMIO_IN16(nPtr->NeoMMIOBase, addr)
+#define INREG(addr)		MMIO_IN32(nPtr->NeoMMIOBase, addr)
+#define OUTREG8(addr, val)	MMIO_OUT8(nPtr->NeoMMIOBase, addr, val)
+#define OUTREG16(addr, val)	MMIO_OUT16(nPtr->NeoMMIOBase, addr, val)
+#define OUTREG(addr, val)	MMIO_OUT32(nPtr->NeoMMIOBase, addr, val)
 
 /* This swizzle macro is to support the manipulation of cursor masks when
  * the sprite moves off the left edge of the display.  This code is
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2070.c xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2070.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2070.c	Tue Sep 26 01:57:08 2000
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2070.c	Thu Apr  4 16:05:44 2002
@@ -104,8 +104,6 @@
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
     NEOPtr nPtr = NEOPTR(pScrn);
     NEOACLPtr nAcl = NEOACLPTR(pScrn);
-    BoxRec AvailFBArea;
-    int lines;
 
     nPtr->AccelInfoRec = infoPtr = XAACreateInfoRec();
     if(!infoPtr) return FALSE;
@@ -158,23 +156,7 @@
     default:
 	return FALSE;
     }
-
-    /* Initialize for widths */
-    nAcl->Pitch = pScrn->displayWidth * nAcl->PixelWidth;
-    lines = nAcl->cacheEnd /
-      (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
-    if(lines > 1024) lines = 1024;
-
-    AvailFBArea.x1 = 0;
-    AvailFBArea.y1 = 0;
-    AvailFBArea.x2 = pScrn->displayWidth;
-    AvailFBArea.y2 = lines;
-    xf86InitFBManager(pScreen, &AvailFBArea); 
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
-               "Using %i scanlines of offscreen memory for pixmap caching\n",
-                lines - pScrn->virtualY);
-
+    
     return(XAAInit(pScreen, infoPtr));
 
 }
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2090.c xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2090.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2090.c	Mon Oct  1 15:44:07 2001
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2090.c	Thu Apr  4 16:05:44 2002
@@ -101,8 +101,6 @@
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
     NEOPtr nPtr = NEOPTR(pScrn);
     NEOACLPtr nAcl = NEOACLPTR(pScrn);
-    BoxRec AvailFBArea;
-    int lines;
 
     nPtr->AccelInfoRec = infoPtr = XAACreateInfoRec();
     if(!infoPtr) return FALSE;
@@ -197,20 +195,6 @@
 
     nAcl->BltCntlFlags |= NEO_BC3_FIFO_EN;
 
-    lines =  nAcl->cacheEnd /
-      (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
-    if(lines > 1024) lines = 1024;
-
-    AvailFBArea.x1 = 0;
-    AvailFBArea.y1 = 0;
-    AvailFBArea.x2 = pScrn->displayWidth;
-    AvailFBArea.y2 = lines;
-    xf86InitFBManager(pScreen, &AvailFBArea); 
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
-               "Using %i scanlines of offscreen memory for pixmap caching\n",
-                lines - pScrn->virtualY);
-
     return(XAAInit(pScreen, infoPtr));
 }
 
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2097.c xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2097.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2097.c	Mon Oct  1 15:44:07 2001
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2097.c	Thu Apr  4 16:05:44 2002
@@ -123,8 +123,6 @@
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
     NEOPtr nPtr = NEOPTR(pScrn);
     NEOACLPtr nAcl = NEOACLPTR(pScrn);
-    int lines;
-    BoxRec AvailFBArea;
 
     nPtr->AccelInfoRec = infoPtr = XAACreateInfoRec();
     if(!infoPtr) return FALSE;
@@ -245,21 +243,7 @@
     default:
 	return FALSE;
     }
-
-    lines =  nAcl->cacheEnd /
-      (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
-    if(lines > 1024) lines = 1024;
-
-    AvailFBArea.x1 = 0;
-    AvailFBArea.y1 = 0;
-    AvailFBArea.x2 = pScrn->displayWidth;
-    AvailFBArea.y2 = lines;
-    xf86InitFBManager(pScreen, &AvailFBArea); 
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
-               "Using %i scanlines of offscreen memory for pixmap caching\n",
-	        lines - pScrn->virtualY);
-
+    
     return(XAAInit(pScreen, infoPtr));
 }
 
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2200.c xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2200.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2200.c	Sun Oct 28 04:33:42 2001
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_2200.c	Thu Apr  4 16:05:44 2002
@@ -120,8 +120,6 @@
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
     NEOPtr nPtr = NEOPTR(pScrn);
     NEOACLPtr nAcl = NEOACLPTR(pScrn);
-    BoxRec AvailFBArea;
-    int lines;
 
     nPtr->AccelInfoRec = infoPtr = XAACreateInfoRec();
     if(!infoPtr) return FALSE;
@@ -251,19 +249,6 @@
 	return FALSE;
     }
 
-    lines =  nAcl->cacheEnd /
-      (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
-    if(lines > 1024) lines = 1024;
-
-    AvailFBArea.x1 = 0;
-    AvailFBArea.y1 = 0;
-    AvailFBArea.x2 = pScrn->displayWidth;
-    AvailFBArea.y2 = lines;
-    xf86InitFBManager(pScreen, &AvailFBArea); 
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
-               "Using %i scanlines of offscreen memory for pixmap caching\n",
-                lines - pScrn->virtualY);
 
     return(XAAInit(pScreen, infoPtr));
 }
@@ -482,7 +467,7 @@
     NEOPtr nPtr = NEOPTR(pScrn);
 
     WAIT_ENGINE_IDLE();
-    OUTREG(NEOREG_DSTSTARTOFF, (y<<16) | (x & 0xffff));
+    OUTREG(NEOREG_DSTSTARTOFF, (y <<16) | (x & 0xffff));
     OUTREG(NEOREG_XYEXT, (h<<16) | (w & 0xffff));
 }
 
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_dga.c xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_dga.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_dga.c	Mon Oct  1 15:44:07 2001
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_dga.c	Thu Apr  4 16:05:44 2002
@@ -43,8 +43,10 @@
 static void NEO_SetViewport(ScrnInfoPtr, int, int, int);
 static void NEO_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
 static void NEO_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
+#if 0
 static void NEO_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, 
 					unsigned long);
+#endif
 
 static
 DGAFunctionRec NEODGAFuncs = {
@@ -76,7 +78,7 @@
    imlines =  (pScrn->videoRam * 1024) /
       (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
 
-   pixlines = (imlines > 1024 && !pNEO->noAccel)  ? 1024 : imlines;
+   pixlines =  (imlines > 1024 && !pNEO->noAccel)  ? 1024 : imlines;
 
    pMode = firstMode = pScrn->modes;
 
@@ -184,7 +186,7 @@
 ){
    NEOPtr pNEO = NEOPTR(pScrn);
    vgaHWPtr hwp = VGAHWPTR(pScrn);
-
+   
    NEOAdjustFrame(pScrn->pScreen->myNum, x, y, flags);
    /* wait for retrace */
    while((hwp->readST01(hwp) & 0x08));
@@ -240,7 +242,7 @@
     }
 }
 
-
+#if 0
 static void 
 NEO_BlitTransRect(
    ScrnInfoPtr pScrn, 
@@ -252,7 +254,7 @@
   /* this one should be separate since the XAA function would
      prohibit usage of ~0 as the key */
 }
-
+#endif
 
 static Bool 
 NEO_OpenFramebuffer(
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_driver.c xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_driver.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_driver.c	Fri Nov 30 13:11:57 2001
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_driver.c	Sat Apr  6 19:49:40 2002
@@ -299,7 +307,11 @@
     OPTION_PROG_LCD_MODE_REGS,
     OPTION_PROG_LCD_MODE_STRETCH,
     OPTION_OVERRIDE_VALIDATE_MODE,
+    OPTION_SHOWCACHE,
     OPTION_ROTATE,
+    OPTION_VIDEO_KEY,
+    OPTION_OVERLAYMEM,
+    OPTION_VIDEO_INTERLACE,
     OPTION_DISPLAY_HEIGHT_480,
     OPTION_STRANGE_LOCKUPS
 } NEOOpts;
@@ -314,6 +326,7 @@
     { OPTION_LCD_STRETCH, "NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
     { OPTION_SHADOW_FB,   "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
     { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,   {0}, FALSE },
+    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
     { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
     { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
       OPTV_BOOLEAN, {0}, FALSE },
@@ -321,6 +334,10 @@
       OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
       OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
+    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
+    { OPTION_VIDEO_INTERLACE, "Interlace",
+      OPTV_INTEGER,   {0}, FALSE },
     { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
 };
 
@@ -335,6 +352,7 @@
     { OPTION_SHADOW_FB,  "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
     { OPTION_LCD_STRETCH,"NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
     { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,	{0}, FALSE },
+    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
     { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
     { OPTION_STRANGE_LOCKUPS, "StrangeLockups", OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_DISPLAY_HEIGHT_480, "DisplayHeight480",
@@ -345,6 +363,10 @@
       OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
       OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
+    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
+    { OPTION_VIDEO_INTERLACE, "Interlace",
+      OPTV_INTEGER,   {0}, FALSE },
     { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
 };
 
@@ -979,6 +1001,7 @@
     xf86GetOptValBool(nPtr->Options, OPTION_LCD_CENTER,&nPtr->lcdCenter);
     xf86GetOptValBool(nPtr->Options, OPTION_LCD_STRETCH,&nPtr->noLcdStretch);
     xf86GetOptValBool(nPtr->Options, OPTION_SHADOW_FB,&nPtr->shadowFB);
+    xf86GetOptValBool(nPtr->Options, OPTION_SHOWCACHE,&nPtr->showcache);
     nPtr->onPciBurst = TRUE;
     xf86GetOptValBool(nPtr->Options, OPTION_PCI_BURST,&nPtr->onPciBurst);
     xf86GetOptValBool(nPtr->Options,
@@ -1014,6 +1037,39 @@
 		       "Valid options are \"CW\" or \"CCW\"\n");
       }
     }
+#ifdef XvExtension
+    if(xf86GetOptValInteger(nPtr->Options,
+			    OPTION_VIDEO_KEY, &(nPtr->videoKey))) {
+        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
+		   nPtr->videoKey);
+    } else {
+        nPtr->videoKey = (1 << pScrn->offset.red) | 
+	    (1 << pScrn->offset.green) |
+	    (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
+	     << pScrn->offset.blue); 
+    }
+    if(xf86GetOptValInteger(nPtr->Options, OPTION_OVERLAYMEM,
+			    &(nPtr->overlay))) {
+        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+		   "reserve %d bytes for overlay.\n", nPtr->overlay);
+    } else {
+	nPtr->overlay = 0;
+    }
+    nPtr->interlace = 0;
+    if(xf86GetOptValInteger(nPtr->Options, OPTION_VIDEO_INTERLACE,
+			    &(nPtr->interlace))) {
+	if (nPtr->interlace >= 0  &&  nPtr->interlace <= 2){
+	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "interlace flag = %d\n",
+		       nPtr->interlace);
+	} else {
+	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+		       "\"%s\" is not a valid value for "
+		       "Option \"Interlaced\"\n", s);
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are  0..2\n");
+        }
+    }
+#endif /* XvExtension */
+
 
     if (height_480 && nPtr->NeoPanelWidth == 800) {
 	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
@@ -1069,6 +1125,9 @@
     if (nPtr->strangeLockups)
 	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
 		   "Option StrangeLockups set: disabling some acceleration\n");
+    if (nPtr->showcache)
+	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
+		   "Show chache for debugging\n");
     if (nPtr->shadowFB) {
 	if (nPtr->noLinear) {
     	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
@@ -1096,6 +1155,8 @@
 	nPtr->NeoLinearAddr = 0;
     }
 
+    nPtr->NeoMMIOAddr2 = 0;
+    nPtr->NeoMMIOBase2 = NULL;
     if (nPtr->pEnt->device->IOBase && !nPtr->noMMIO) {
 	/* XXX Check this matches a PCI base address */
 	nPtr->NeoMMIOAddr = nPtr->pEnt->device->IOBase;
@@ -1113,7 +1174,7 @@
 		       "FB base address is set at 0x%X.\n",
 		       nPtr->NeoLinearAddr);
 	}
-	if (!nPtr->NeoMMIOAddr) {
+	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
 	    switch (nPtr->NeoChipset) {
 	    case NM2070 :
 		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
@@ -1129,11 +1190,17 @@
 	    case NM2360:
 	    case NM2380:
 		nPtr->NeoMMIOAddr = nPtr->PciInfo->memBase[1];
+		nPtr->NeoMMIOAddr2 = nPtr->PciInfo->memBase[2];
 		break;
 	    }
 	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
 		       "MMIO base address is set at 0x%X.\n",
 		       nPtr->NeoMMIOAddr);
+	    if (nPtr->NeoMMIOAddr2 != 0){
+	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+		           "MMIO base address2 is set at 0x%X.\n",
+		           nPtr->NeoMMIOAddr2);
+	    }
 	}
 	/* XXX What about VGA resources in OPERATING mode? */
 	if (xf86RegisterResources(nPtr->pEnt->index, NULL, ResExclusive))
@@ -1152,7 +1219,7 @@
 		       "FB base address is set at 0x%X.\n",
 		       nPtr->NeoLinearAddr);
 	}
-	if (!nPtr->NeoMMIOAddr) {
+	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
 	    nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
 	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
 		       "MMIO base address is set at 0x%X.\n",
@@ -1293,6 +1360,10 @@
     /* Should we re-save the text mode on each VT enter? */
     if(!neoModeInit(pScrn, pScrn->currentMode))
       return FALSE;
+#ifdef XvExtension
+    if (nPtr->video)
+	NEOResetVideo(pScrn);
+#endif
     if (nPtr->NeoHWCursorShown) 
 	NeoShowCursor(pScrn);
     NEOAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);    
@@ -1384,12 +1455,12 @@
     /* Map the Neo memory and possible MMIO areas */
     if (!neoMapMem(pScrn))
 	return FALSE;
-
+    
     /*
      * next we save the current state and setup the first mode
      */
     neoSave(pScrn);
-
+    
     if (!neoModeInit(pScrn,pScrn->currentMode))
 	return FALSE;
     vgaHWSaveScreen(pScreen,SCREEN_SAVER_ON);
@@ -1431,7 +1502,7 @@
 	nPtr->ShadowPtr = NULL;
 	FBStart = nPtr->NeoFbBase;
     }
-
+    
     ret = fbScreenInit(pScreen, FBStart,
 			    width, height,
 			    pScrn->xDpi, pScrn->yDpi,
@@ -1509,13 +1580,13 @@
 		   nPtr->NeoLinearAddr);
 	/* Setup pointers to free space in video ram */
 	allocatebase = (pScrn->videoRam << 10);
-	freespace = allocatebase - pScrn->displayWidth * 
+	freespace = allocatebase - pScrn->displayWidth *
 	    pScrn->virtualY * (pScrn->bitsPerPixel >> 3);
 	currentaddr = allocatebase;
 	xf86DrvMsg(scrnIndex, X_PROBED,
 		   "%d bytes off-screen memory available\n", freespace);
 
-	if (nPtr->swCursor || nPtr->noMMIO) {
+	if (nPtr->swCursor || !nPtr->NeoMMIOBase) {
 	    xf86DrvMsg(scrnIndex, X_CONFIG,
 		       "Using Software Cursor.\n");
 	} else if (nPtr->NeoCursorMem <= freespace) {
@@ -1530,19 +1601,52 @@
 	} else xf86DrvMsg(scrnIndex, X_ERROR,
 			  "Too little space for H/W cursor.\n");
 	
-	if (!nPtr->noAccel && nPtr->noMMIO)
+	if (!nPtr->noAccel && !nPtr->NeoMMIOBase)
 	  xf86DrvMsg(pScrn->scrnIndex,X_INFO,
 		     "Acceleration disabled when not using MMIO\n");
-
-	/* Setup the acceleration primitives */
-	if (!nPtr->noAccel && !nPtr->noMMIO) {
+	{
+#ifdef XvExtension
+	    if (nPtr->overlay > 0){
+		if (nPtr->overlay > freespace){
+		    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
+			       "Can not reserve %d bytes for overlay. "
+			       "Resize to %d bytes.\n",
+			       nPtr->overlay, freespace);
+		    nPtr->overlay = freespace;
+		}
+		currentaddr -= nPtr->overlay;
+		freespace -= nPtr->overlay;
+		nPtr->overlay_offset = currentaddr;
+		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Overlay at 0x%x\n",
+			   nPtr->overlay_offset);
+	    }
+#endif /* XvExtension */
 	    nAcl->cacheStart = currentaddr - freespace;
 	    nAcl->cacheEnd = currentaddr;
 	    freespace = 0;
+	    if (nAcl->cacheStart < nAcl->cacheEnd) {
+		BoxRec AvailFBArea;
+		int lines = nAcl->cacheEnd /
+		    (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
+  		if (!nPtr->noAccel && nPtr->NeoMMIOBase && lines > 1024) 
+  		    lines = 1024;
+ 		AvailFBArea.x1 = 0;
+		AvailFBArea.y1 = 0;
+		AvailFBArea.x2 = pScrn->displayWidth;
+		AvailFBArea.y2 = lines;
+		xf86InitFBManager(pScreen, &AvailFBArea); 
+
+		xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
+			   "Using %i scanlines of offscreen memory \n"
+			   , lines - pScrn->virtualY);
+	    }
+	}
+	/* Setup the acceleration primitives */
+	if (!nPtr->noAccel && nPtr->NeoMMIOBase) {
 	    if (nAcl->cacheStart >= nAcl->cacheEnd) {
 		xf86DrvMsg(scrnIndex, X_ERROR,
 			   "Too little space for pixmap cache.\n");
-	    }
+	    } 	    
 	    switch(nPtr->NeoChipset) {
 	    case NM2070 :
 		Neo2070AccelInit(pScreen);
@@ -1624,6 +1728,8 @@
 
     pScrn->racIoFlags = pScrn->racMemFlags = racflag;
 
+    NEOInitVideo(pScreen);
+
     pScreen->SaveScreen = vgaHWSaveScreen;
 
     /* Setup DPMS mode */
@@ -1635,18 +1741,7 @@
         pScrn->memPhysBase = (unsigned long)nPtr->NeoFbBase;
 	pScrn->fbOffset = 0;
     }
-
-#ifdef XvExtension
-    {
-        XF86VideoAdaptorPtr *ptr;
-	int n;
-	
-	n = xf86XVListGenericAdaptors(pScrn,&ptr);
-	if (n)
-	    xf86XVScreenInit(pScreen, ptr, n);
-    }
-#endif
-
+    
     /* Wrap the current CloseScreen function */
     nPtr->CloseScreen = pScreen->CloseScreen;
     pScreen->CloseScreen = NEOCloseScreen;
@@ -1677,11 +1772,21 @@
     int Base; 
 
     pScrn = xf86Screens[scrnIndex];
-    Base = (y * pScrn->displayWidth + x) >> 2;
     hwp = VGAHWPTR(pScrn);
     nPtr = NEOPTR(pScrn);
-    /* Scale Base by the number of bytes per pixel. */
 
+    if (nPtr->showcache && y) {
+	int lastline = nPtr->NeoFbMapSize / 
+	    ((pScrn->displayWidth * pScrn->bitsPerPixel) / 8);
+	
+	lastline -= pScrn->currentMode->VDisplay;
+	y += pScrn->virtualY - 1;
+        if (y > lastline) y = lastline;
+    }
+
+    Base = (y * pScrn->displayWidth + x) >> 2;
+
+    /* Scale Base by the number of bytes per pixel. */
     switch (pScrn->depth) {
     case  8 :
 	break;
@@ -1730,6 +1835,7 @@
 	if (nPtr->NeoHWCursorShown)
 	    NeoHideCursor(pScrn);
 	neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
+
 	neoLock(pScrn);
 	neoUnmapMem(pScrn);
     }
@@ -1845,12 +1951,18 @@
 
     if (!nPtr->noLinear) {
 	if (!nPtr->noMMIO) {
-	    if (nPtr->pEnt->location.type == BUS_PCI)
+	    if (nPtr->pEnt->location.type == BUS_PCI){
 		nPtr->NeoMMIOBase =
 		    xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
 				  nPtr->PciTag, nPtr->NeoMMIOAddr,
 				  0x200000L);
-	    else
+		if (nPtr->NeoMMIOAddr2 != 0){
+		    nPtr->NeoMMIOBase2 =
+		        xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
+				      nPtr->PciTag, nPtr->NeoMMIOAddr2,
+				      0x100000L);
+		}
+	    } else
 		nPtr->NeoMMIOBase =
 		    xf86MapVidMem(pScrn->scrnIndex,
 				  VIDMEM_MMIO, nPtr->NeoMMIOAddr,
@@ -1889,8 +2001,14 @@
     NEOPtr nPtr = NEOPTR(pScrn);
 
     if (!nPtr->noLinear) {
-      xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase, 0x200000L);
+      if (nPtr->NeoMMIOBase)
+	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase,
+			  0x200000L);
       nPtr->NeoMMIOBase = NULL;
+      if (nPtr->NeoMMIOBase2)
+	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase2,
+			  0x100000L);
+      nPtr->NeoMMIOBase2 = NULL;
       xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoFbBase,
 		    nPtr->NeoFbMapSize); 
     }
@@ -2200,7 +2318,7 @@
     unsigned char temp;
     int i;
     Bool clock_hi = FALSE;
-    
+
     vgaHWProtect(pScrn,TRUE);		/* Blank the screen */
     
     VGAwGR(0x09,0x26);
@@ -2220,6 +2338,7 @@
      * any reserved bits.
      */
     temp = VGArGR(0x90);
+
     switch (nPtr->NeoChipset) {
     case NM2070 :
 	temp &= 0xF0; /* Save bits 7:4 */
@@ -2238,6 +2357,7 @@
 	break;
     }
     VGAwGR(0x90,temp);
+
     /*
      * In some rare cases a lockup might occur if we don't delay
      * here. (Reported by Miles Lane)
@@ -2256,7 +2376,6 @@
      * had time to take effect.
      */
     xf86UDelay(200000);
-
     /*
      * This function handles restoring the generic VGA registers.  */
     vgaHWRestore(pScrn, VgaReg,
@@ -2273,6 +2392,7 @@
     VGAwGR(0x11, restore->SysIfaceCntl2);
     VGAwGR(0x15, restore->SingleAddrPage);
     VGAwGR(0x16, restore->DualAddrPage);
+
     temp = VGArGR(0x20);
     switch (nPtr->NeoChipset) {
     case NM2070 :
@@ -2349,7 +2469,7 @@
     }
     if (restore->biosMode)
 	VGAwCR(0x23,restore->biosMode);
-    
+
     if (restore->reg) {
 	VGAwCR(0x23,restore->reg->CR[0x23]);
 	VGAwCR(0x25,restore->reg->CR[0x25]);
@@ -2371,13 +2491,13 @@
 	    VGAwGR(i, restore->reg->GR[i]);
 	}
     }
+
     /* Program vertical extension register */
     if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
 	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
 	VGAwCR(0x70, restore->VerticalExt);
     }
-
-
+    
     vgaHWProtect(pScrn, FALSE);		/* Turn on screen */
 
 }
@@ -2574,7 +2694,7 @@
     NeoNew->PanelHorizCenterReg3 = 0x00;
     NeoNew->PanelHorizCenterReg4 = 0x00;
     NeoNew->PanelHorizCenterReg5 = 0x00;
-
+    
     if (nPtr->lcdCenter &&
 	(NeoNew->PanelDispCntlReg1 & 0x02)) {
 	if (mode->HDisplay == nPtr->NeoPanelWidth) {
@@ -2632,6 +2752,18 @@
 	    }
 	}
     }
+#ifdef XvExtension
+    if (!noLcdStretch)  {
+	if (mode->HDisplay != nPtr->NeoPanelWidth)
+	    nPtr->videoHZoom = (double)nPtr->NeoPanelWidth/mode->HDisplay;
+	if (mode->VDisplay != nPtr->NeoPanelHeight)
+	    nPtr->videoVZoom = (double)nPtr->NeoPanelHeight/mode->VDisplay;
+    } else {
+	nPtr->videoHZoom = 1.0;
+	nPtr->videoVZoom = 1.0;
+    }
+#endif
+    
     NeoNew->biosMode = neoFindMode(mode->HDisplay,mode->VDisplay,pScrn->depth);
     
     /*
@@ -2764,9 +2896,8 @@
     }
 
     /* Turn the screen on/off */
-    outb(0x3C4, 0x01);
-    SEQ01 |= inb(0x3C5) & ~0x20;
-    outb(0x3C5, SEQ01);
+    SEQ01 |= VGArSR(0x01) & ~0x20;
+    VGAwSR(0x01, SEQ01);
 
     /* Turn the LCD on/off */
     LCD_on |= VGArGR(0x20) & ~0x02;
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.c xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.c	Thu Jan  1 01:00:00 1970
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.c	Thu Apr  4 16:05:44 2002
@@ -0,0 +1,1232 @@
+/**********************************************************************
+Copyright 2002 by Shigehiro Nomura.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Shigehiro Nomura not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  Shigehiro Nomura
+and its suppliers make no representations about the suitability of this
+software for any purpose.  It is provided "as is" without express or 
+implied warranty.
+
+SHIGEHIRO NOMURA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL SHIGEHIRO NOMURA AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**********************************************************************/
+
+/*
+ * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
+ */
+
+#include "neo.h"
+#include "neo_video.h"
+
+#define nElems(x)		(sizeof(x) / sizeof(x[0]))
+#define MAKE_ATOM(a)	MakeAtom(a, sizeof(a) - 1, TRUE)
+
+#if defined(XvExtension)
+
+#include "dixstruct.h"
+#include "xaa.h"
+#include "xaalocal.h"
+
+static XF86VideoAdaptorPtr NEOSetupVideo(ScreenPtr);
+
+static int NEOPutVideo(ScrnInfoPtr, short, short, short, short, 
+		       short, short, short, short, RegionPtr, pointer);
+
+static void NEOStopVideo(ScrnInfoPtr, pointer, Bool);
+static int NEOSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
+static int NEOGetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
+static void NEOQueryBestSize(ScrnInfoPtr, Bool, short, short, short, 
+			     short, unsigned int *, unsigned int *, pointer);
+static int NEOPutImage(ScrnInfoPtr, short, short, short, short, short, short, 
+		       short, short, int, unsigned char *, short, short, Bool,
+		       RegionPtr, pointer);
+static int NEOQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, 
+				   unsigned short *, int *, int *);
+
+static Bool RegionsEqual(RegionPtr, RegionPtr);
+static void NEODisplayVideo(ScrnInfoPtr, int, int, short, short, int, int, 
+			    int, int, int, BoxPtr, short, short, short, short);
+
+static void NEOInitOffscreenImages(ScreenPtr);
+static FBLinearPtr NEOAllocateMemory(ScrnInfoPtr, FBLinearPtr, int);
+static void NEOCopyData(unsigned char *, unsigned char *, int, int, int, int);
+static void NEOCopyYV12Data(unsigned char *, unsigned char *, unsigned char *,
+			    unsigned char *, int, int, int, int, int);
+
+static int NEOAllocSurface(ScrnInfoPtr, int, unsigned short, unsigned short, 
+			   XF86SurfacePtr);
+static int NEOFreeSurface(XF86SurfacePtr);
+static int NEODisplaySurface(XF86SurfacePtr, short, short, short, short, 
+			     short, short, short, short, RegionPtr clipBoxes);
+static int NEOStopSurface(XF86SurfacePtr);
+static int NEOGetSurfaceAttribute(ScrnInfoPtr, Atom, INT32 *);
+static int NEOSetSurfaceAttribute(ScrnInfoPtr, Atom, INT32);
+
+static Atom xvColorKey, xvBrightness, xvInterlace;
+
+void
+NEOInitVideo(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    NEOPtr nPtr = NEOPTR(pScrn);
+    XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
+    XF86VideoAdaptorPtr newAdaptor = NULL;
+    int numAdaptors;
+
+    numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
+
+    if (nPtr->NeoChipset >= NM2160 
+	&& !nPtr->noLinear 
+	&& nPtr->NeoMMIOBase2 != NULL){
+	nPtr->video = TRUE;
+	newAdaptor = NEOSetupVideo(pScreen);
+	NEOInitOffscreenImages(pScreen);
+    } else
+	nPtr->video = FALSE;
+
+    if (newAdaptor){
+	if (!numAdaptors){
+	    numAdaptors = 1;
+	    overlayAdaptors = &newAdaptor;
+	} else {
+	    newAdaptors = xalloc((numAdaptors + 1) 
+				 * sizeof(XF86VideoAdaptorPtr*));
+	    if (newAdaptors){
+		memcpy(newAdaptors, overlayAdaptors, 
+		       numAdaptors * sizeof(XF86VideoAdaptorPtr));
+		newAdaptors[numAdaptors++] = newAdaptor;
+		overlayAdaptors = newAdaptors;
+	    }
+	}
+    }
+
+    if (numAdaptors)
+	xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors);
+
+    if (newAdaptors)
+	xfree(newAdaptors);
+}
+
+static XF86VideoEncodingRec NEOVideoEncodings[] =
+{
+    {
+	NEO_VIDEO_VIDEO,
+	"XV_VIDEO",
+	1024, 1024,
+	{1, 1}
+    },
+    {
+	NEO_VIDEO_IMAGE,
+	"XV_IMAGE",
+	1024, 1024,
+	{1, 1}
+    }
+};
+
+static XF86VideoFormatRec NEOVideoFormats[] =
+{
+    {  8, PseudoColor },
+    { 15, TrueColor },
+    { 16, TrueColor },
+    { 24, TrueColor },
+};
+
+static XF86AttributeRec NEOVideoAttributes[] =
+{
+    {
+	XvSettable | XvGettable,
+	0x000000, 0xFFFFFF,
+	"XV_COLORKEY"
+    },
+    {
+	XvSettable | XvGettable,
+	-128, 127,
+	"XV_BRIGHTNESS"
+    },
+    {
+	XvSettable | XvGettable,
+	0,2,
+	"XV_INTERLACE"
+    },
+};
+
+static XF86ImageRec NEOVideoImages[] =
+{
+    XVIMAGE_YUY2,
+    XVIMAGE_YV12,
+    XVIMAGE_I420,
+    {
+	FOURCC_RV15,
+	XvRGB,
+	LSBFirst,
+	{ 'R', 'V' ,'1', '5',
+	  0x00,'5',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+	16,
+	XvPacked,
+	1,
+	15, 0x001F, 0x03E0, 0x7C00,
+	0, 0, 0,
+	0, 0, 0,
+	0, 0, 0,
+	{ 'R', 'V', 'B' },
+	XvTopToBottom
+    },
+    {
+	FOURCC_RV16,
+	XvRGB,
+	LSBFirst,
+	{ 'R', 'V' ,'1', '6',
+	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
+	16,
+	XvPacked,
+	1,
+	16, 0x001F, 0x07E0, 0xF800,
+	0, 0, 0,
+	0, 0, 0,
+	0, 0, 0,
+	{ 'R', 'V', 'B' },
+	XvTopToBottom
+    }
+};
+
+static XF86VideoAdaptorPtr
+NEOSetupVideo(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    NEOPtr nPtr = NEOPTR(pScrn);
+    NEOPortPtr pPriv;
+    XF86VideoAdaptorPtr overlayAdaptor;
+    int i;
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetupVideo\n");
+#endif
+    if ((overlayAdaptor = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
+			      sizeof(DevUnion) + 
+			      sizeof(NEOPortRec))) == NULL){
+	return (NULL);
+    }
+
+    overlayAdaptor->type = XvInputMask | XvImageMask | XvWindowMask 
+	| XvOutputMask | XvVideoMask;
+    overlayAdaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+    overlayAdaptor->name = "NeoMagic Video Engine";
+    overlayAdaptor->nEncodings = nElems(NEOVideoEncodings);
+    overlayAdaptor->pEncodings = NEOVideoEncodings;
+    for (i = 0; i < nElems(NEOVideoEncodings); i++){
+	NEOVideoEncodings[i].width = 1024;
+	NEOVideoEncodings[i].height = 1024;
+    }
+    overlayAdaptor->nFormats = nElems(NEOVideoFormats);
+    overlayAdaptor->pFormats = NEOVideoFormats;
+    overlayAdaptor->nPorts = 1;
+    overlayAdaptor->pPortPrivates = (DevUnion*) &overlayAdaptor[1];
+    overlayAdaptor->pPortPrivates[0].ptr = 
+	(pointer) &overlayAdaptor->pPortPrivates[1];
+    overlayAdaptor->nAttributes = nElems(NEOVideoAttributes);
+    overlayAdaptor->pAttributes = NEOVideoAttributes;
+    overlayAdaptor->nImages = nElems(NEOVideoImages);
+    overlayAdaptor->pImages = NEOVideoImages;
+
+    overlayAdaptor->PutVideo = NEOPutVideo;
+    overlayAdaptor->PutStill = NULL;
+    overlayAdaptor->GetVideo = NULL;
+    overlayAdaptor->GetStill = NULL;
+
+    overlayAdaptor->StopVideo = NEOStopVideo;
+    overlayAdaptor->SetPortAttribute = NEOSetPortAttribute;
+    overlayAdaptor->GetPortAttribute = NEOGetPortAttribute;
+    overlayAdaptor->QueryBestSize = NEOQueryBestSize;
+    overlayAdaptor->PutImage = NEOPutImage;
+    overlayAdaptor->QueryImageAttributes = NEOQueryImageAttributes;
+
+    pPriv = (NEOPortPtr)overlayAdaptor->pPortPrivates[0].ptr;
+    pPriv->colorKey = nPtr->videoKey;
+    pPriv->interlace = nPtr->interlace;
+    pPriv->videoStatus = 0;
+    pPriv->brightness = 0;
+    REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
+    nPtr->overlayAdaptor = overlayAdaptor;
+
+    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+    xvColorKey = MAKE_ATOM("XV_COLORKEY");
+    xvInterlace = MAKE_ATOM("XV_INTERLACE");
+    
+    NEOResetVideo(pScrn);
+
+    return (overlayAdaptor);
+}
+
+void
+NEOResetVideo(ScrnInfoPtr pScrn)
+{
+    NEOPtr nPtr = NEOPTR(pScrn);
+    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
+    int r, g, b;
+    VGA_HWP(pScrn);
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOResetVideo\n");
+#endif
+    switch (pScrn->depth){
+    case 8:
+	OUTGR(0xc6, pPriv->colorKey & 0);
+	OUTGR(0xc5, pPriv->colorKey & 0xff);
+	OUTGR(0xc7, pPriv->colorKey & 0);
+	break;
+    default:
+	r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
+	g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
+	b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
+	OUTGR(0xc5, r);
+	OUTGR(0xc6, g);
+	OUTGR(0xc7, b);
+	break;
+    }
+    OUTGR(0xc4, pPriv->brightness);
+}
+
+static int
+NEOPutVideo(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)
+{
+    NEOPortPtr pPriv = (NEOPortPtr)data;
+    NEOPtr nPtr = NEOPTR(pScrn);
+    CARD32 src_pitch, offset;
+    int xscale, yscale;
+    BoxRec dstBox;
+    INT32 x1, y1, x2, y2;
+    int size, bpp;
+    unsigned char capctrl;
+    VGA_HWP(pScrn);
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: src: %d %d %d %d\n", 
+	       src_x, src_y, src_w, src_h);
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: drw: %d %d %d %d\n", 
+	       drw_x, drw_y, drw_w, drw_h);
+#endif
+    if (src_w > 720)
+	src_w = 720;
+    if (src_h > 576)
+        src_h = 576;
+    if (pPriv->interlace != 2)
+	src_h /= 2;
+    x1 = src_x;
+    y1 = src_y;
+    x2 = src_x + src_w;
+    y2 = src_y + src_h;
+
+    dstBox.x1 = drw_x;
+    dstBox.y1 = drw_y;
+    dstBox.x2 = drw_x + drw_w;
+    dstBox.y2 = drw_y + drw_h;
+
+    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
+			       clipBoxes, src_w, src_h)){
+	return(Success);
+    }
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: %d %d %d %d\n", 
+	       x1, y1, x2, y2);
+#endif
+
+    dstBox.x1 -= pScrn->frameX0;
+    dstBox.y1 -= pScrn->frameY0;
+    dstBox.x2 -= pScrn->frameX0;
+    dstBox.y2 -= pScrn->frameY0;
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: dstBox %d %d %d %d\n", 
+	       dstBox.x1, dstBox.y1, dstBox.x2, dstBox.y2);
+#endif
+
+    bpp = (pScrn->bitsPerPixel + 1) >> 3;
+    src_pitch = (src_w + 7) & ~7;
+
+    xscale = 0x1000;
+    if (src_w <= drw_w){
+	xscale = (src_w * 0x1000 / drw_w) & 0xffff;
+    }
+
+    yscale = 0x1000;
+    if (src_h <= drw_h){
+ 	yscale = (src_h * 0x1000 / drw_h) & 0xffff;
+    }
+
+    size = src_h * src_pitch * 2;
+
+    if (size > nPtr->overlay){
+	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size)) 
+	    == NULL){
+	    return (BadAlloc);
+	}
+    } else {
+	pPriv->linear = NULL;
+    }
+    
+    if (pPriv->linear == NULL){
+	offset = nPtr->overlay_offset;
+    } else {
+	offset = pPriv->linear->offset * bpp;
+    }
+    
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: offset=0x%x\n", offset);
+#endif
+     WAIT_ENGINE_IDLE();
+     memset(nPtr->NeoFbBase + offset, 0, size);
+
+    if (!RegionsEqual(&pPriv->clip, clipBoxes)){
+	REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
+	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey,
+			    clipBoxes);
+    }
+
+    x1 >>= 16;
+    y1 >>= 16;
+    x2 >>= 16;
+    y2 >>= 16;
+
+    switch (nPtr->NeoChipset) {
+    default:
+    case NM2160: 
+	offset/=2;
+	OUTGR(0xbc, 0x4f);
+ 	break;
+    case NM2200:
+    case NM2230:
+    case NM2360:
+    case NM2380:
+	OUTGR(0xbc, 0x2e);
+ 	break;
+    }
+ 
+
+    OUTGR(0xb1, (((dstBox.x2-1) >> 4) & 0xf0) | ((dstBox.x1 >> 8) & 0x0f));
+    OUTGR(0xb2, dstBox.x1);
+    OUTGR(0xb3, dstBox.x2 - 1);
+    OUTGR(0xb4, (((dstBox.y2 - 1) >> 4) & 0xf0) | ((dstBox.y1 >> 8) & 0x0f));
+    OUTGR(0xb5, dstBox.y1);
+    OUTGR(0xb6, dstBox.y2 - 1);
+    OUTGR(0xb7, offset >> 16);
+    OUTGR(0xb8, offset >> 8);
+    OUTGR(0xb9, offset );
+    OUTGR(0xba, src_pitch >> 8);
+    OUTGR(0xbb, src_pitch);
+
+    OUTGR(0xc0, xscale >> 8);
+    OUTGR(0xc1, xscale);
+    OUTGR(0xc2, yscale >> 8);
+    OUTGR(0xc3, yscale);
+    OUTGR(0xbf, 0x02);
+
+    OUTGR(0x0a, 0x21);
+
+    OUTSR(0x0c, offset );
+    OUTSR(0x0d, offset >> 8);
+    OUTSR(0x0e, offset >> 16);
+    OUTSR(0x1a, src_pitch);
+    OUTSR(0x1b, src_pitch>>8);
+
+    OUTSR(0x17, 0 + x1);
+    OUTSR(0x18, 0 + x2 -1);
+    OUTSR(0x19, (((0 + x2 - 1) >> 4) & 0xf0) | (((0 + x1) >> 8) & 0x0f));
+
+    OUTSR(0x14, 14 + y1);
+    OUTSR(0x15, 14 + y2 - 2);
+    OUTSR(0x16, (((14 + y2 - 1) >> 4) & 0xf0) | (((14 + y1) >> 8) & 0x0f));
+
+    OUTSR(0x1c, 0xfb);
+    OUTSR(0x1d, 0x00);
+    OUTSR(0x1e, 0xe2);
+    OUTSR(0x1f, 0x02);
+
+    OUTSR(0x09, 0x11);
+    OUTSR(0x0a, 0x00);
+
+    capctrl = 0x21;
+    switch (pPriv->interlace){
+    case 0: /* Combine 2 fields */
+	break;
+    case 1: /* one field only */
+	capctrl |= 0x80;
+	break;
+    case 2: /* Interlaced fields */
+	capctrl |= 0x40;
+	break;
+    }
+    OUTSR(0x08, capctrl);
+
+#if 0
+    OUTGR(0x0a, 0x01);
+#endif
+    OUTGR(0xb0, 0x03);
+
+    pPriv->videoStatus = CLIENT_VIDEO_ON;
+    return (Success);
+}
+
+static void
+NEOStopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
+{
+    NEOPortPtr pPriv = (NEOPortPtr)data;
+    NEOPtr nPtr = NEOPTR(pScrn);
+    VGA_HWP(pScrn);
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo\n");
+#endif
+    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+
+    if (exit){
+	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
+#ifdef DEBUG
+            xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo: stop capture\n");
+#endif
+	    OUTGR(0xb0, 0x02);
+	    OUTGR(0x0a, 0x21);
+	    OUTSR(0x08, 0xa0);
+#if 0
+	    OUTGR(0x0a, 0x01);
+#endif
+	}
+	if (pPriv->linear != NULL){
+	    xf86FreeOffscreenLinear(pPriv->linear);
+	    pPriv->linear = NULL;
+	}
+	pPriv->videoStatus = 0;
+    } else {
+	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
+	    OUTGR(0xb0, 0x02);
+	    OUTGR(0x0a, 0x21);
+	    OUTSR(0x08, 0xa0);
+#if 0
+	    OUTGR(0x0a, 0x01);
+#endif
+	    pPriv->videoStatus |= OFF_TIMER;
+	    pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
+	}
+    }
+}
+
+static int
+NEOSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value, 
+		    pointer data)
+{
+    NEOPortPtr pPriv = (NEOPortPtr)data;
+    NEOPtr nPtr = NEOPTR(pScrn);
+    VGA_HWP(pScrn);
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetPortAttribute\n");
+#endif
+    if (attribute == xvColorKey){
+	int r, g, b;
+
+	pPriv->colorKey = value;
+	switch (pScrn->depth){
+	case 8:
+	    OUTGR(0xc6, pPriv->colorKey & 0xff);
+	    OUTGR(0xc5, 0x00);
+	    OUTGR(0xc7, 0x00);
+	    break;
+	default:
+	    r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
+	    g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
+	    b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
+	    OUTGR(0xc5, r);
+	    OUTGR(0xc6, g);
+	    OUTGR(0xc7, b);
+	}
+    } else if (attribute == xvBrightness){
+	if ((value < -128) || (value > 127)){
+	    return (BadValue);
+	}
+	pPriv->brightness = value;
+	OUTGR(0xc4, value);
+    } else if (attribute == xvInterlace){
+	if (value < 0  ||  value > 2){
+	    return (BadValue);
+	}
+	pPriv->interlace = value;
+    } else {
+	return (BadMatch);
+    }
+    return (Success);
+}
+
+static int
+NEOGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value, 
+		    pointer data)
+{
+    NEOPortPtr pPriv = (NEOPortPtr)data;
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetPortAttribute\n");
+#endif
+    if (attribute == xvColorKey){
+	*value = pPriv->colorKey;
+    } else if (attribute == xvBrightness){
+	*value = pPriv->brightness;
+    } else if (attribute == xvInterlace){
+	*value = pPriv->interlace;
+    } else {
+	return (BadMatch);
+    }
+    return (Success);
+}
+
+static void
+NEOQueryBestSize(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)
+{
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryBestSize\n");
+#endif
+    *p_w = min(drw_w, 1024);
+    *p_h = min(drw_h, 1024);
+}
+
+static int
+NEOPutImage(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)
+{
+    NEOPtr nPtr = NEOPTR(pScrn);
+    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
+    INT32 x1, y1, x2, y2;
+    int bpp;
+    int srcPitch, srcPitch2 = 0, dstPitch, size;
+    BoxRec dstBox;
+    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
+    int left, top, nPixels, nLines;
+    unsigned char *dstStart;
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutImage\n");
+#endif
+
+    x1 = src_x;
+    y1 = src_y;
+    x2 = src_x + src_w;
+    y2 = src_y + src_h;
+    
+    dstBox.x1 = drw_x;
+    dstBox.y1 = drw_y;
+    dstBox.x2 = drw_x + drw_w;
+    dstBox.y2 = drw_y + drw_h;
+
+    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
+			       clipBoxes, width, height)){
+	return (Success);
+    }
+
+    dstBox.x1 -= pScrn->frameX0;
+    dstBox.y1 -= pScrn->frameY0;
+    dstBox.x2 -= pScrn->frameX0;
+    dstBox.y2 -= pScrn->frameY0;    
+    
+    bpp = ((pScrn->bitsPerPixel + 1) >> 3);
+    
+    switch (id){
+    case FOURCC_YV12:
+	srcPitch  = (width + 3) & ~3;
+	offset2   = srcPitch * height;
+	srcPitch2 = ((width >> 1) + 3) & ~3;
+	offset3   = offset2 + (srcPitch2 * (height >> 1));
+  	dstPitch  = ((width << 1) + 15) & ~15; 
+	break;
+    case FOURCC_I420:
+	srcPitch  = (width + 3) & ~3;
+	offset3   = srcPitch * height;
+	srcPitch2 = ((width >> 1) + 3) & ~3;
+	offset2   = offset3 + (srcPitch2 * (height >> 1));
+  	dstPitch  = ((width << 1) + 15) & ~15;
+	break;
+    case FOURCC_YUY2:
+    case FOURCC_RV15:
+    case FOURCC_RV16:
+    default:
+	srcPitch = width << 1;
+  	dstPitch = (srcPitch + 15) & ~15;
+	break;
+    }
+    
+    size = dstPitch * height;
+    if (size > nPtr->overlay){
+	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size)) 
+	    == NULL){
+	    return (BadAlloc);
+	}
+    } else {
+	pPriv->linear = NULL;
+    }
+
+    top = y1 >> 16;
+    left = (x1 >> 16) & ~1;
+    nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left;
+    left <<= 1;
+
+    if (pPriv->linear == NULL){
+	offset = nPtr->overlay_offset;
+    } else {
+	offset =  pPriv->linear->offset * bpp;
+    }
+    
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"offset=%x\n", offset);
+#endif
+
+    dstStart = (unsigned char *)(nPtr->NeoFbBase + offset + left);
+    
+    switch (id){
+    case FOURCC_YV12:
+    case FOURCC_I420:
+	top &= ~1;
+	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
+	offset2 += tmp;
+	offset3 += tmp;
+	nLines = ((((y2 + 0xFFFF) >> 16) + 1) & ~1) - top;
+	NEOCopyYV12Data(buf + (top * srcPitch) + (left >> 1), buf + offset2, 
+			buf + offset3, dstStart, srcPitch, srcPitch2, 
+			dstPitch, nLines, nPixels);
+	break;
+    default:
+	buf += (top * srcPitch) + left;
+	nLines = ((y2 + 0xFFFF) >> 16) - top;
+	NEOCopyData(buf, dstStart, srcPitch, dstPitch, nLines, nPixels << 1);
+    }
+
+    if (!RegionsEqual(&pPriv->clip, clipBoxes)){
+	REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
+        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
+    }
+	NEODisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1,
+			x2, y2,	&dstBox, src_w, src_h, drw_w, drw_h);
+    
+    pPriv->videoStatus = CLIENT_VIDEO_ON;
+    return (Success);
+	
+}
+
+static int
+NEOQueryImageAttributes(ScrnInfoPtr pScrn, int id, 
+			unsigned short *width, unsigned short *height,
+			int *pitches, int *offsets)
+{
+    int size, tmp;
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryImageAttributes\n");
+#endif
+    if (*width > 1024){
+	*width = 1024;
+    }
+    if (*height > 1024){
+	*height = 1024;
+    }
+
+    *width = (*width + 1) & ~1;
+    if (offsets != NULL){
+	offsets[0] = 0;
+    }
+
+    switch (id){
+    case FOURCC_YV12:
+    case FOURCC_I420:
+	*height = (*height + 1) & ~1;
+	size = (*width + 3) & ~3;
+	if (pitches != NULL){
+	    pitches[0] = size;
+	}
+	size *= *height;
+	if (offsets != NULL){
+	    offsets[1] = size;
+	}
+	tmp = ((*width >> 1) + 3) & ~3;
+	if (pitches != NULL){
+	    pitches[1] = pitches[2] = tmp;
+	}
+	tmp *= (*height >> 1);
+	size += tmp;
+	if (offsets != NULL){
+	    offsets[2] = size;
+	}
+	size += tmp;
+	break;
+    case FOURCC_YUY2:
+    case FOURCC_RV15:
+    case FOURCC_RV16:
+    default:
+	size = *width * 2;
+	if (pitches != NULL){
+	    pitches[0] = size;
+	}
+	size *= *height;
+	break;
+    }
+    return (size);
+}
+
+static Bool
+RegionsEqual(RegionPtr A, RegionPtr B)
+{
+    int *dataA, *dataB;
+    int num;
+
+    num = REGION_NUM_RECTS(A);
+    if (num != REGION_NUM_RECTS(B)){
+	return (FALSE);
+    }
+
+    if ((A->extents.x1 != B->extents.x1)
+	|| (A->extents.y1 != B->extents.y1)
+	|| (A->extents.x2 != B->extents.x2)
+	|| (A->extents.y2 != B->extents.y2)){
+	return (FALSE);
+    }
+
+    dataA = (int*) REGION_RECTS(A);
+    dataB = (int*) REGION_RECTS(B);
+
+    while (num--){
+	if ((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])){
+	    return (FALSE);
+	}
+	dataA += 2;
+	dataB += 2;
+    }
+    return (TRUE);
+}
+
+static void
+NEODisplayVideo(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)
+{
+    NEOPtr nPtr = NEOPTR(pScrn);
+    int hstretch, vstretch, fmt;
+    VGA_HWP(pScrn);
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEODisplayVideo\n");
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEODisplayVideo src_w=%d, src_h=%d, pitch=%d, drw_w=%d, drw_h=%d\n", src_w, src_h, pitch, drw_w, drw_h);
+#endif
+#define WIDTH_THRESHOLD 160
+    if (dstBox->x2 >= pScrn->virtualX) {
+	/*
+	 * This is a hack to work around a problem when video is moved
+	 * accross the right border.
+	 */
+	int diff_s = (width - ((x2 - x1) >> 16)) & ~1;
+	int diff_d = (drw_w - dstBox->x2 + dstBox->x1) & ~1;
+
+	offset -= 2 * ((diff_s > diff_d) ? diff_d : diff_s);
+	dstBox->x1 -= diff_d;
+    } else if (dstBox->x2 - dstBox->x1 < WIDTH_THRESHOLD) {
+	/*
+	 * When the video window is less than about 160 pixel wide
+	 * it will be distoreted. We attempt to fix it by actually
+	 * making it wider and relying on the color key to prevent
+	 * it from appearanig outside of the video.
+	 */
+	int pre, post;
+	int scale = 1;
+	
+	if (dstBox->x1 < WIDTH_THRESHOLD) {
+	    pre = dstBox->x1;
+	    post = 160 - pre;
+	} else {
+	    pre = 160;
+	    post = 0;
+	}
+	offset -= 2 * scale * pre;
+	dstBox->x1 -= pre;
+	dstBox->x2 += post;
+    }
+    if (nPtr->videoHZoom != 1.0) {
+	if ((dstBox->x2 += 5) > pScrn->virtualX)
+	    dstBox->x2 = pScrn->virtualX;
+	if (dstBox->x1 > 0) dstBox->x1 += 2;
+    }
+    
+    fmt = 0x00;
+    switch (id){
+    case FOURCC_YV12:
+    case FOURCC_I420:
+    case FOURCC_YUY2:
+	fmt = 0x00;
+	break;
+    case FOURCC_RV15:
+    case FOURCC_RV16:
+	fmt = 0x20;
+	break;
+    }
+
+    offset += (x1 >> 15) & ~0x03;
+    
+    switch (nPtr->NeoChipset) {
+    default:
+    case NM2160: 
+        offset/=2;
+	pitch/=2;
+        OUTGR(0xbc, 0x4f);
+	break;
+    case NM2200:
+    case NM2230:
+    case NM2360:
+    case NM2380:
+        OUTGR(0xbc, 0x2e);
+	break;
+    }
+
+    /* factor 4 for granularity */
+    hstretch = (double)0x1000 * 4 / (int)(nPtr->videoHZoom * 4);
+    if (drw_w > src_w)
+	hstretch = (((int)src_w) * hstretch) / (int) drw_w;
+    
+    vstretch = (double)0x1000 / nPtr->videoVZoom;
+    if (drw_h > src_h)
+	vstretch = (((int)src_h) * vstretch )/ (int) drw_h;
+
+    OUTGR(0xb1, (((dstBox->x2 - 1) >> 4) & 0xf0) | ((dstBox->x1 >> 8) & 0x0f));
+    OUTGR(0xb2, dstBox->x1);
+    OUTGR(0xb3, dstBox->x2 - 1);
+    OUTGR(0xb4, (((dstBox->y2 - 1) >> 4) & 0xf0) | ((dstBox->y1 >> 8) & 0x0f));
+    OUTGR(0xb5, dstBox->y1);
+    OUTGR(0xb6, dstBox->y2 - 1);
+    OUTGR(0xb7, offset >> 16);
+    OUTGR(0xb8, offset >> 8);
+    OUTGR(0xb9, offset );
+    OUTGR(0xba, pitch >> 8);
+    OUTGR(0xbb, pitch);
+     
+    OUTGR(0xbd, 0x02);
+    OUTGR(0xbe, 0x00);
+    OUTGR(0xbf, 0x02);
+
+    OUTGR(0xc0, hstretch >> 8);
+    OUTGR(0xc1, hstretch);
+    OUTGR(0xc2, vstretch >> 8);
+    OUTGR(0xc3, vstretch);
+
+    OUTGR(0xb0, fmt | 0x03);
+
+    OUTGR(0x0a, 0x21);
+    OUTSR(0x08, 0xa0);
+    OUTGR(0x0a, 0x01);
+}
+
+static void
+NEOInitOffscreenImages(ScreenPtr pScreen)
+{
+    XF86OffscreenImagePtr offscreenImages;
+
+#ifdef DEBUG
+    xf86DrvMsg(xf86Screens[pScreen->myNum]->scrnIndex,X_INFO,"NEOInitOffscreenImages\n");
+#endif
+    if ((offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))) == NULL){
+	return;
+    }
+
+    offscreenImages->image = NEOVideoImages;
+    offscreenImages->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+    offscreenImages->alloc_surface = NEOAllocSurface;
+    offscreenImages->free_surface = NEOFreeSurface;
+    offscreenImages->display = NEODisplaySurface;
+    offscreenImages->stop = NEOStopSurface;
+    offscreenImages->getAttribute = NEOGetSurfaceAttribute;
+    offscreenImages->setAttribute = NEOSetSurfaceAttribute;
+    offscreenImages->max_width = 1024;
+    offscreenImages->max_height = 1024;
+    offscreenImages->num_attributes = nElems(NEOVideoAttributes);
+    offscreenImages->attributes = NEOVideoAttributes;
+
+    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
+}
+
+static FBLinearPtr
+NEOAllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
+{
+    ScreenPtr pScreen;
+    FBLinearPtr new_linear;
+    int bytespp = pScrn->bitsPerPixel >> 3;
+
+    /* convert size in bytes into number of pixels */
+    size = (size + bytespp - 1) / bytespp;
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
+	       "NEOAllocateMemory: linear=%x, size=%d\n", linear, size);
+#endif
+    if (linear){
+#ifdef DEBUG
+        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
+		   "NEOAllocateMemory: linear->size=%d\n", linear->size);
+#endif
+	if (linear->size >= size){
+	    return (linear);
+	}
+
+	if (xf86ResizeOffscreenLinear(linear, size)){
+	    return (linear);
+	}
+
+	xf86FreeOffscreenLinear(linear);
+    }
+
+
+    pScreen = screenInfo.screens[pScrn->scrnIndex];
+    if ((new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, NULL,
+						  NULL, NULL)) == NULL){
+	int max_size;
+
+	xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16, 
+					PRIORITY_EXTREME);
+#ifdef DEBUG
+        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
+		   "NEOAllocateMemory: max_size=%d\n", max_size);
+#endif
+	if (max_size < size){
+	    return (NULL);
+	}
+
+	xf86PurgeUnlockedOffscreenAreas(pScreen);
+	new_linear = xf86AllocateOffscreenLinear(pScreen, 
+						 size, 16, NULL, NULL, NULL);
+    }
+    
+    return (new_linear);
+}
+
+static void
+NEOCopyData(unsigned char *src, unsigned char *dst, 
+	    int srcPitch, int dstPitch,
+	    int height, int width)
+{
+    while (height-- > 0){
+	memcpy(dst, src, width);
+	src += srcPitch;
+	dst += dstPitch;
+    }
+}
+
+static void
+NEOCopyYV12Data(unsigned char *src1, unsigned char *src2,
+		unsigned char *src3, unsigned char *dst,
+		int srcPitch1, int srcPitch2, int dstPitch,
+		int height, int width)
+{
+    CARD32 *pDst = (CARD32 *) dst;
+    int i;
+
+    width >>= 1;
+    height >>= 1;
+    dstPitch >>= 2;
+    while (--height >= 0){
+	for (i =0; i < width; i++){
+	    pDst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
+		(src3[i] << 8) | (src2[i] << 24);
+	}
+	pDst += dstPitch;
+	src1 += srcPitch1;
+
+	for (i =0; i < width; i++){
+	    pDst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
+		(src3[i] << 8) | (src2[i] << 24);
+	}
+	pDst += dstPitch;
+	src1 += srcPitch1;
+	    src2 += srcPitch2;
+	    src3 += srcPitch2;
+    }
+}
+
+static int
+NEOAllocSurface(ScrnInfoPtr pScrn, int id, 
+		unsigned short width, unsigned short height,
+		XF86SurfacePtr surface)
+{
+    int pitch, bpp, size;
+    NEOOffscreenPtr pPriv;
+    FBLinearPtr linear;
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOAllocSurface\n");
+#endif
+    if (width > 1024  || height > 1024){
+	return (BadAlloc);
+    }
+
+    width = (width + 1) & ~1;
+    bpp = ((pScrn->bitsPerPixel + 1) >> 3);
+    pitch = ((width << 1) + 15) & ~15;
+    size = pitch * height;
+
+    if ((linear = NEOAllocateMemory(pScrn, NULL, size)) == NULL){
+	return (BadAlloc);
+    }
+
+    surface->width = width;
+    surface->height = height;
+    if ((surface->pitches = xalloc(sizeof(int))) == NULL){
+	xf86FreeOffscreenLinear(linear);
+	return (BadAlloc);
+    }
+    if ((surface->offsets = xalloc(sizeof(int))) == NULL){
+	xfree(surface->pitches);
+	xf86FreeOffscreenLinear(linear);
+	return (BadAlloc);
+    }
+
+    if ((pPriv = xalloc(sizeof(NEOOffscreenRec))) == NULL){
+	xfree(surface->pitches);
+	xfree(surface->offsets);
+	xf86FreeOffscreenLinear(linear);
+	return (BadAlloc);
+    }
+
+    pPriv->linear = linear;
+    pPriv->isOn = FALSE;
+
+    surface->pScrn = pScrn;
+    surface->id = id;
+    surface->pitches[0] = pitch;
+    surface->offsets[0] = linear->offset << 1;
+    surface->devPrivate.ptr = (pointer)pPriv;
+    return (Success);
+}
+
+static int
+NEOFreeSurface(XF86SurfacePtr surface)
+{
+    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
+
+#ifdef DEBUG
+    xf86DrvMsg(0,X_INFO,"NEOFreeSurface\n");
+#endif
+    if (pPriv->isOn)
+	NEOStopSurface(surface);
+
+    xf86FreeOffscreenLinear(pPriv->linear);
+    xfree(surface->pitches);
+    xfree(surface->offsets);
+    xfree(surface->devPrivate.ptr);
+    return (Success);
+}
+
+static int
+NEODisplaySurface(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)
+{
+    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
+    NEOPtr nPtr = NEOPTR(surface->pScrn);
+    NEOPortPtr portPriv = nPtr->overlayAdaptor->pPortPrivates[0].ptr;
+    INT32 x1, y1, x2, y2;
+    BoxRec dstBox;
+
+#ifdef DEBUG
+    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEODisplaySurface\n");
+#endif
+    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 (!xf86XVClipVideoHelper( &dstBox, &x1, &x2, &y1, &y2,
+			       clipBoxes, surface->width, surface->height)){
+	return (Success);
+    }
+
+    dstBox.x1 -= surface->pScrn->frameX0;
+    dstBox.y1 -= surface->pScrn->frameY0;
+    dstBox.x2 -= surface->pScrn->frameX0;
+    dstBox.y2 -= surface->pScrn->frameY0;
+
+    xf86XVFillKeyHelper(surface->pScrn->pScreen, portPriv->colorKey,
+			clipBoxes);
+    NEOResetVideo(surface->pScrn);
+    NEODisplayVideo(surface->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);
+}
+
+static int
+NEOStopSurface(XF86SurfacePtr surface)
+{
+    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
+
+#ifdef DEBUG
+    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEOStopSurface\n");
+#endif
+    if (pPriv->isOn){
+	NEOPtr nPtr = NEOPTR(surface->pScrn);
+	VGA_HWP(surface->pScrn);
+	OUTGR(0xb0, 0x02);
+	pPriv->isOn = FALSE;
+    }
+    return (Success);
+}
+
+static int
+NEOGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value)
+{
+    NEOPtr nPtr = NEOPTR(pScrn);
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetSurfaceAttribute\n");
+#endif
+    return (NEOGetPortAttribute(pScrn, 
+            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
+}
+
+static int
+NEOSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value)
+{
+    NEOPtr nPtr = NEOPTR(pScrn);
+
+#ifdef DEBUG
+    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetSurfaceAttribute\n");
+#endif
+    return (NEOSetPortAttribute(pScrn, 
+            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
+}
+
+#else /* XvExtension */
+
+void NEOInitVideo(ScreenPtr pScreen) {}
+void NEOResetVideo(ScreenPtr pScreen) {}
+
+#endif
diff -x CVS -uNr xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.h xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.h
--- xc.orig/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.h	Thu Jan  1 01:00:00 1970
+++ xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.h	Thu Apr  4 16:05:44 2002
@@ -0,0 +1,83 @@
+/**********************************************************************
+Copyright 2002 by Shigehiro Nomura.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Shigehiro Nomura not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  Shigehiro Nomura
+and its suppliers make no representations about the suitability of this
+software for any purpose.  It is provided "as is" without express or 
+implied warranty.
+
+SHIGEHIRO NOMURA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL SHIGEHIRO NOMURA AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**********************************************************************/
+
+#ifndef _NEO_VIDEO_H
+#define _NEO_VIDEO_H
+
+#define ACC_MMIO
+
+#include "vgaHW.h"
+#include "fourcc.h"
+#include "Xv.h"
+
+#define NEO_VIDEO_VIDEO		0
+#define NEO_VIDEO_IMAGE		1
+
+#define FOURCC_RV15			0x35315652
+#define FOURCC_RV16			0x36315652
+
+#define OFF_DELAY			200		/* milliseconds */
+#define FREE_DELAY			60000	/* milliseconds */
+
+#define OFF_TIMER			0x01
+#define FREE_TIMER			0x02
+#define CLIENT_VIDEO_ON		0x04
+#define TIMER_MASK			(OFF_TIMER | FREE_TIMER)
+
+typedef struct
+{
+    FBLinearPtr	linear;
+    RegionRec	clip;
+    CARD32	colorKey;
+    CARD32	interlace;
+    CARD32	brightness;
+    CARD32	videoStatus;
+    Time	offTime;
+    Time	freeTime;
+} NEOPortRec, *NEOPortPtr;
+
+typedef struct
+{
+    FBLinearPtr	linear;
+    Bool	isOn;
+} NEOOffscreenRec, *NEOOffscreenPtr;
+
+/* I/O Functions */
+# define OUTGR(idx,dat) \
+   if (nPtr->NeoMMIOBase2) \
+     (*(unsigned short *)(nPtr->NeoMMIOBase2+VGA_GRAPH_INDEX)\
+                                                     =(idx)|((dat)<<8));\
+   else \
+      VGAwGR((idx),(dat));
+
+#  define OUTSR(idx,dat) \
+if (nPtr->NeoMMIOBase2) \
+   (*(unsigned short *)(nPtr->NeoMMIOBase2+VGA_SEQ_INDEX)=(idx)|((dat)<<8));\
+else \
+   VGAwSR((idx),(dat));
+
+# define VGA_HWP(x)     vgaHWPtr hwp = VGAHWPTR(x)
+
+#endif /* _NEO_VIDEO_H */

Reply to: