1692f60a7Smrg/**********************************************************************
2692f60a7SmrgCopyright 2002 by Shigehiro Nomura.
3692f60a7Smrg
4692f60a7Smrg                        All Rights Reserved
5692f60a7Smrg
6692f60a7SmrgPermission to use, copy, modify, distribute, and sell this software and
7692f60a7Smrgits documentation for any purpose is hereby granted without fee,
8692f60a7Smrgprovided that the above copyright notice appear in all copies and that
9692f60a7Smrgboth that copyright notice and this permission notice appear in
10692f60a7Smrgsupporting documentation, and that the name of Shigehiro Nomura not be
11692f60a7Smrgused in advertising or publicity pertaining to distribution of the
12692f60a7Smrgsoftware without specific, written prior permission.  Shigehiro Nomura
13692f60a7Smrgand its suppliers make no representations about the suitability of this
14692f60a7Smrgsoftware for any purpose.  It is provided "as is" without express or
15692f60a7Smrgimplied warranty.
16692f60a7Smrg
17692f60a7SmrgSHIGEHIRO NOMURA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18692f60a7SmrgINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19692f60a7SmrgEVENT SHALL SHIGEHIRO NOMURA AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20692f60a7SmrgSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21692f60a7SmrgRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22692f60a7SmrgCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23692f60a7SmrgCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24692f60a7Smrg**********************************************************************/
25692f60a7Smrg
26692f60a7Smrg/*
27692f60a7Smrg * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
28692f60a7Smrg */
29692f60a7Smrg
30692f60a7Smrg#ifdef HAVE_CONFIG_H
31692f60a7Smrg#include "config.h"
32692f60a7Smrg#endif
33692f60a7Smrg
34692f60a7Smrg#include "neo.h"
35692f60a7Smrg#include "neo_video.h"
36692f60a7Smrg
37692f60a7Smrg#define nElems(x)		(sizeof(x) / sizeof(x[0]))
38692f60a7Smrg#define MAKE_ATOM(a)	MakeAtom(a, sizeof(a) - 1, TRUE)
39692f60a7Smrg
40692f60a7Smrg#include "dixstruct.h"
41692f60a7Smrg
42692f60a7Smrgstatic XF86VideoAdaptorPtr NEOSetupVideo(ScreenPtr);
43692f60a7Smrg
44692f60a7Smrgstatic int NEOPutVideo(ScrnInfoPtr, short, short, short, short,
45692f60a7Smrg		       short, short, short, short, RegionPtr, pointer,
46692f60a7Smrg		       DrawablePtr);
47692f60a7Smrg
48692f60a7Smrgstatic void NEOStopVideo(ScrnInfoPtr, pointer, Bool);
49692f60a7Smrgstatic int NEOSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
50692f60a7Smrgstatic int NEOGetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
51692f60a7Smrgstatic void NEOQueryBestSize(ScrnInfoPtr, Bool, short, short, short,
52692f60a7Smrg			     short, unsigned int *, unsigned int *, pointer);
53692f60a7Smrgstatic int NEOPutImage(ScrnInfoPtr, short, short, short, short, short, short,
54692f60a7Smrg		       short, short, int, unsigned char *, short, short, Bool,
55692f60a7Smrg		       RegionPtr, pointer, DrawablePtr);
56692f60a7Smrgstatic int NEOQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
57692f60a7Smrg				   unsigned short *, int *, int *);
58692f60a7Smrg
59692f60a7Smrgstatic void NEODisplayVideo(ScrnInfoPtr, int, int, short, short, int, int,
60692f60a7Smrg			    int, int, int, BoxPtr, short, short, short, short);
61692f60a7Smrg
62692f60a7Smrgstatic void NEOInitOffscreenImages(ScreenPtr);
63692f60a7Smrgstatic FBLinearPtr NEOAllocateMemory(ScrnInfoPtr, FBLinearPtr, int);
64692f60a7Smrg
65692f60a7Smrgstatic int NEOAllocSurface(ScrnInfoPtr, int, unsigned short, unsigned short,
66692f60a7Smrg			   XF86SurfacePtr);
67692f60a7Smrgstatic int NEOFreeSurface(XF86SurfacePtr);
68692f60a7Smrgstatic int NEODisplaySurface(XF86SurfacePtr, short, short, short, short,
69692f60a7Smrg			     short, short, short, short, RegionPtr clipBoxes);
70692f60a7Smrgstatic int NEOStopSurface(XF86SurfacePtr);
71692f60a7Smrgstatic int NEOGetSurfaceAttribute(ScrnInfoPtr, Atom, INT32 *);
72692f60a7Smrgstatic int NEOSetSurfaceAttribute(ScrnInfoPtr, Atom, INT32);
73692f60a7Smrg
74692f60a7Smrgstatic Atom xvColorKey, xvBrightness, xvInterlace;
75692f60a7Smrg
76692f60a7Smrgvoid
77692f60a7SmrgNEOInitVideo(ScreenPtr pScreen)
78692f60a7Smrg{
793f6d0e1dSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
80692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
81692f60a7Smrg    XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
82692f60a7Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
83692f60a7Smrg    int numAdaptors;
84692f60a7Smrg
85692f60a7Smrg    numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
86692f60a7Smrg
87692f60a7Smrg    if (nPtr->NeoChipset > NM2070
88692f60a7Smrg	&& nPtr->NeoMMIOBase2 != NULL){
89692f60a7Smrg	nPtr->video = TRUE;
90692f60a7Smrg	newAdaptor = NEOSetupVideo(pScreen);
91692f60a7Smrg	NEOInitOffscreenImages(pScreen);
92692f60a7Smrg    } else
93692f60a7Smrg	nPtr->video = FALSE;
94692f60a7Smrg
95692f60a7Smrg    if (newAdaptor){
96692f60a7Smrg	if (!numAdaptors){
97692f60a7Smrg	    numAdaptors = 1;
98692f60a7Smrg	    overlayAdaptors = &newAdaptor;
99692f60a7Smrg	} else {
1003f6d0e1dSmrg	    newAdaptors = malloc((numAdaptors + 1)
101692f60a7Smrg				 * sizeof(XF86VideoAdaptorPtr*));
102692f60a7Smrg	    if (newAdaptors){
103692f60a7Smrg		memcpy(newAdaptors, overlayAdaptors,
104692f60a7Smrg		       numAdaptors * sizeof(XF86VideoAdaptorPtr));
105692f60a7Smrg		newAdaptors[numAdaptors++] = newAdaptor;
106692f60a7Smrg		overlayAdaptors = newAdaptors;
107692f60a7Smrg	    }
108692f60a7Smrg	}
109692f60a7Smrg    }
110692f60a7Smrg
111692f60a7Smrg    if (numAdaptors)
112692f60a7Smrg	xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors);
113692f60a7Smrg
114692f60a7Smrg    if (newAdaptors)
1153f6d0e1dSmrg	free(newAdaptors);
116692f60a7Smrg}
117692f60a7Smrg
118692f60a7Smrgstatic XF86VideoEncodingRec NEOVideoEncodings[] =
119692f60a7Smrg{
120692f60a7Smrg    {
121692f60a7Smrg	NEO_VIDEO_VIDEO,
122692f60a7Smrg	"XV_VIDEO",
123692f60a7Smrg	1024, 1024,
124692f60a7Smrg	{1, 1}
125692f60a7Smrg    },
126692f60a7Smrg    {
127692f60a7Smrg	NEO_VIDEO_IMAGE,
128692f60a7Smrg	"XV_IMAGE",
129692f60a7Smrg	1024, 1024,
130692f60a7Smrg	{1, 1}
131692f60a7Smrg    }
132692f60a7Smrg};
133692f60a7Smrg
134692f60a7Smrgstatic XF86VideoFormatRec NEOVideoFormats[] =
135692f60a7Smrg{
136692f60a7Smrg    {  8, PseudoColor },
137692f60a7Smrg    { 15, TrueColor },
138692f60a7Smrg    { 16, TrueColor },
139692f60a7Smrg    { 24, TrueColor },
140692f60a7Smrg};
141692f60a7Smrg
142692f60a7Smrgstatic XF86AttributeRec NEOVideoAttributes[] =
143692f60a7Smrg{
144692f60a7Smrg    {
145692f60a7Smrg	XvSettable | XvGettable,
146692f60a7Smrg	0x000000, 0xFFFFFF,
147692f60a7Smrg	"XV_COLORKEY"
148692f60a7Smrg    },
149692f60a7Smrg    {
150692f60a7Smrg	XvSettable | XvGettable,
151692f60a7Smrg	-128, 127,
152692f60a7Smrg	"XV_BRIGHTNESS"
153692f60a7Smrg    },
154692f60a7Smrg    {
155692f60a7Smrg	XvSettable | XvGettable,
156692f60a7Smrg	0,2,
157692f60a7Smrg	"XV_INTERLACE"
158692f60a7Smrg    },
159692f60a7Smrg};
160692f60a7Smrg
161692f60a7Smrgstatic XF86ImageRec NEOVideoImages[] =
162692f60a7Smrg{
163692f60a7Smrg    XVIMAGE_YUY2,
164692f60a7Smrg    XVIMAGE_YV12,
165692f60a7Smrg    XVIMAGE_I420,
166692f60a7Smrg    {
167692f60a7Smrg	FOURCC_RV15,
168692f60a7Smrg	XvRGB,
169692f60a7Smrg	LSBFirst,
170692f60a7Smrg	{ 'R', 'V' ,'1', '5',
171692f60a7Smrg	  0x00,'5',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
172692f60a7Smrg	16,
173692f60a7Smrg	XvPacked,
174692f60a7Smrg	1,
175692f60a7Smrg	15, 0x001F, 0x03E0, 0x7C00,
176692f60a7Smrg	0, 0, 0,
177692f60a7Smrg	0, 0, 0,
178692f60a7Smrg	0, 0, 0,
179692f60a7Smrg	{ 'R', 'V', 'B' },
180692f60a7Smrg	XvTopToBottom
181692f60a7Smrg    },
182692f60a7Smrg    {
183692f60a7Smrg	FOURCC_RV16,
184692f60a7Smrg	XvRGB,
185692f60a7Smrg	LSBFirst,
186692f60a7Smrg	{ 'R', 'V' ,'1', '6',
187692f60a7Smrg	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
188692f60a7Smrg	16,
189692f60a7Smrg	XvPacked,
190692f60a7Smrg	1,
191692f60a7Smrg	16, 0xF800, 0x07E0, 0x001F,
192692f60a7Smrg	0, 0, 0,
193692f60a7Smrg	0, 0, 0,
194692f60a7Smrg	0, 0, 0,
195692f60a7Smrg	{ 'R', 'V', 'B' },
196692f60a7Smrg	XvTopToBottom
197692f60a7Smrg    }
198692f60a7Smrg};
199692f60a7Smrg
200692f60a7Smrgstatic XF86VideoAdaptorPtr
201692f60a7SmrgNEOSetupVideo(ScreenPtr pScreen)
202692f60a7Smrg{
2033f6d0e1dSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
204692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
205692f60a7Smrg    NEOPortPtr pPriv;
206692f60a7Smrg    XF86VideoAdaptorPtr overlayAdaptor;
207692f60a7Smrg    int i;
208692f60a7Smrg
209692f60a7Smrg#ifdef DEBUG
210692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetupVideo\n");
211692f60a7Smrg#endif
2123f6d0e1dSmrg    if ((overlayAdaptor = calloc(1, sizeof(XF86VideoAdaptorRec) +
213692f60a7Smrg			      sizeof(DevUnion) +
214692f60a7Smrg			      sizeof(NEOPortRec))) == NULL){
215692f60a7Smrg	return (NULL);
216692f60a7Smrg    }
217692f60a7Smrg
218692f60a7Smrg    overlayAdaptor->type = XvInputMask | XvImageMask | XvWindowMask
219692f60a7Smrg	| XvOutputMask | XvVideoMask;
220692f60a7Smrg    overlayAdaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
221692f60a7Smrg    overlayAdaptor->name = "NeoMagic Video Engine";
222692f60a7Smrg    overlayAdaptor->nEncodings = nElems(NEOVideoEncodings);
223692f60a7Smrg    overlayAdaptor->pEncodings = NEOVideoEncodings;
224692f60a7Smrg    for (i = 0; i < nElems(NEOVideoEncodings); i++){
225692f60a7Smrg	NEOVideoEncodings[i].width = 1024;
226692f60a7Smrg	NEOVideoEncodings[i].height = 1024;
227692f60a7Smrg    }
228692f60a7Smrg    overlayAdaptor->nFormats = nElems(NEOVideoFormats);
229692f60a7Smrg    overlayAdaptor->pFormats = NEOVideoFormats;
230692f60a7Smrg    overlayAdaptor->nPorts = 1;
231692f60a7Smrg    overlayAdaptor->pPortPrivates = (DevUnion*) &overlayAdaptor[1];
232692f60a7Smrg    overlayAdaptor->pPortPrivates[0].ptr =
233692f60a7Smrg	(pointer) &overlayAdaptor->pPortPrivates[1];
234692f60a7Smrg    overlayAdaptor->nAttributes = nElems(NEOVideoAttributes);
235692f60a7Smrg    overlayAdaptor->pAttributes = NEOVideoAttributes;
236692f60a7Smrg    overlayAdaptor->nImages = nElems(NEOVideoImages);
237692f60a7Smrg    overlayAdaptor->pImages = NEOVideoImages;
238692f60a7Smrg
239692f60a7Smrg    overlayAdaptor->PutVideo = NEOPutVideo;
240692f60a7Smrg    overlayAdaptor->PutStill = NULL;
241692f60a7Smrg    overlayAdaptor->GetVideo = NULL;
242692f60a7Smrg    overlayAdaptor->GetStill = NULL;
243692f60a7Smrg
244692f60a7Smrg    overlayAdaptor->StopVideo = NEOStopVideo;
245692f60a7Smrg    overlayAdaptor->SetPortAttribute = NEOSetPortAttribute;
246692f60a7Smrg    overlayAdaptor->GetPortAttribute = NEOGetPortAttribute;
247692f60a7Smrg    overlayAdaptor->QueryBestSize = NEOQueryBestSize;
248692f60a7Smrg    overlayAdaptor->PutImage = NEOPutImage;
249692f60a7Smrg    overlayAdaptor->QueryImageAttributes = NEOQueryImageAttributes;
250692f60a7Smrg
251692f60a7Smrg    pPriv = (NEOPortPtr)overlayAdaptor->pPortPrivates[0].ptr;
252692f60a7Smrg    pPriv->colorKey = nPtr->videoKey;
253692f60a7Smrg    pPriv->interlace = nPtr->interlace;
254692f60a7Smrg    pPriv->videoStatus = 0;
255692f60a7Smrg    pPriv->brightness = 0;
256692f60a7Smrg    REGION_NULL(pScreen, &pPriv->clip);
257692f60a7Smrg    nPtr->overlayAdaptor = overlayAdaptor;
258692f60a7Smrg
259692f60a7Smrg    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
260692f60a7Smrg    xvColorKey = MAKE_ATOM("XV_COLORKEY");
261692f60a7Smrg    xvInterlace = MAKE_ATOM("XV_INTERLACE");
262692f60a7Smrg
263692f60a7Smrg    NEOResetVideo(pScrn);
264692f60a7Smrg
265692f60a7Smrg    return (overlayAdaptor);
266692f60a7Smrg}
267692f60a7Smrg
268692f60a7Smrgvoid
269692f60a7SmrgNEOResetVideo(ScrnInfoPtr pScrn)
270692f60a7Smrg{
271692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
272692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
273692f60a7Smrg    int r, g, b;
274692f60a7Smrg    VGA_HWP(pScrn);
275692f60a7Smrg
276692f60a7Smrg#ifdef DEBUG
277692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOResetVideo\n");
278692f60a7Smrg#endif
279692f60a7Smrg    switch (pScrn->depth){
280692f60a7Smrg    case 8:
281692f60a7Smrg	OUTGR(0xc6, pPriv->colorKey & 0);
282692f60a7Smrg	OUTGR(0xc5, pPriv->colorKey & 0xff);
283692f60a7Smrg	OUTGR(0xc7, pPriv->colorKey & 0);
284692f60a7Smrg	break;
285692f60a7Smrg    default:
286692f60a7Smrg	r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
287692f60a7Smrg	g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
288692f60a7Smrg	b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
289692f60a7Smrg	OUTGR(0xc5, r);
290692f60a7Smrg	OUTGR(0xc6, g);
291692f60a7Smrg	OUTGR(0xc7, b);
292692f60a7Smrg	break;
293692f60a7Smrg    }
294692f60a7Smrg    OUTGR(0xc4, pPriv->brightness);
295692f60a7Smrg}
296692f60a7Smrg
297692f60a7Smrgstatic int
298692f60a7SmrgNEOPutVideo(ScrnInfoPtr pScrn,
299692f60a7Smrg	     short src_x, short src_y, short drw_x, short drw_y,
300692f60a7Smrg	     short src_w, short src_h, short drw_w, short drw_h,
301692f60a7Smrg	     RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
302692f60a7Smrg{
303692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
304692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
305692f60a7Smrg    CARD32 src_pitch, offset;
306692f60a7Smrg    int xscale, yscale;
307692f60a7Smrg    BoxRec dstBox;
308692f60a7Smrg    INT32 x1, y1, x2, y2;
309692f60a7Smrg    int size, bpp;
310692f60a7Smrg    unsigned char capctrl;
311692f60a7Smrg    VGA_HWP(pScrn);
312692f60a7Smrg
313692f60a7Smrg#ifdef DEBUG
314692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: src: %d %d %d %d\n",
315692f60a7Smrg	       src_x, src_y, src_w, src_h);
316692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: drw: %d %d %d %d\n",
317692f60a7Smrg	       drw_x, drw_y, drw_w, drw_h);
318692f60a7Smrg#endif
319692f60a7Smrg    if (src_w > 720)
320692f60a7Smrg	src_w = 720;
321692f60a7Smrg    if (src_h > 576)
322692f60a7Smrg        src_h = 576;
323692f60a7Smrg    if (pPriv->interlace != 2)
324692f60a7Smrg	src_h /= 2;
325692f60a7Smrg    x1 = src_x;
326692f60a7Smrg    y1 = src_y;
327692f60a7Smrg    x2 = src_x + src_w;
328692f60a7Smrg    y2 = src_y + src_h;
329692f60a7Smrg
330692f60a7Smrg    dstBox.x1 = drw_x;
331692f60a7Smrg    dstBox.y1 = drw_y;
332692f60a7Smrg    dstBox.x2 = drw_x + drw_w;
333692f60a7Smrg    dstBox.y2 = drw_y + drw_h;
334692f60a7Smrg
335692f60a7Smrg    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
336692f60a7Smrg			       clipBoxes, src_w, src_h)){
337692f60a7Smrg	return(Success);
338692f60a7Smrg    }
339692f60a7Smrg#ifdef DEBUG
340692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: %d %d %d %d\n",
341692f60a7Smrg	       x1, y1, x2, y2);
342692f60a7Smrg#endif
343692f60a7Smrg
344692f60a7Smrg    dstBox.x1 -= pScrn->frameX0;
345692f60a7Smrg    dstBox.y1 -= pScrn->frameY0;
346692f60a7Smrg    dstBox.x2 -= pScrn->frameX0;
347692f60a7Smrg    dstBox.y2 -= pScrn->frameY0;
348692f60a7Smrg#ifdef DEBUG
349692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: dstBox %d %d %d %d\n",
350692f60a7Smrg	       dstBox.x1, dstBox.y1, dstBox.x2, dstBox.y2);
351692f60a7Smrg#endif
352692f60a7Smrg
353692f60a7Smrg    bpp = (pScrn->bitsPerPixel + 1) >> 3;
354692f60a7Smrg    src_pitch = (src_w + 7) & ~7;
355692f60a7Smrg
356692f60a7Smrg    xscale = 0x1000;
357692f60a7Smrg    if (src_w <= drw_w){
358692f60a7Smrg	xscale = (src_w * 0x1000 / drw_w) & 0xffff;
359692f60a7Smrg    }
360692f60a7Smrg
361692f60a7Smrg    yscale = 0x1000;
362692f60a7Smrg    if (src_h <= drw_h){
363692f60a7Smrg 	yscale = (src_h * 0x1000 / drw_h) & 0xffff;
364692f60a7Smrg    }
365692f60a7Smrg
366692f60a7Smrg    size = src_h * src_pitch * 2;
367692f60a7Smrg
368692f60a7Smrg    if (size > nPtr->overlay){
369692f60a7Smrg	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size))
370692f60a7Smrg	    == NULL){
371692f60a7Smrg	    return (BadAlloc);
372692f60a7Smrg	}
373692f60a7Smrg    } else {
374692f60a7Smrg	pPriv->linear = NULL;
375692f60a7Smrg    }
376692f60a7Smrg
377692f60a7Smrg    if (pPriv->linear == NULL){
378692f60a7Smrg	offset = nPtr->overlay_offset;
379692f60a7Smrg    } else {
380692f60a7Smrg	offset = pPriv->linear->offset * bpp;
381692f60a7Smrg    }
382692f60a7Smrg
383692f60a7Smrg#ifdef DEBUG
384692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: offset=0x%x\n", offset);
385692f60a7Smrg#endif
386692f60a7Smrg     WAIT_ENGINE_IDLE();
387692f60a7Smrg     memset(nPtr->NeoFbBase + offset, 0, size);
388692f60a7Smrg
389692f60a7Smrg    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)){
390692f60a7Smrg	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
391692f60a7Smrg	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
392692f60a7Smrg    }
393692f60a7Smrg
394692f60a7Smrg    x1 >>= 16;
395692f60a7Smrg    y1 >>= 16;
396692f60a7Smrg    x2 >>= 16;
397692f60a7Smrg    y2 >>= 16;
398692f60a7Smrg
399692f60a7Smrg    switch (nPtr->NeoChipset) {
400692f60a7Smrg    default:
401692f60a7Smrg    case NM2090:
402692f60a7Smrg    case NM2093:
403692f60a7Smrg    case NM2097:
404692f60a7Smrg    case NM2160:
405692f60a7Smrg	offset/=2;
406692f60a7Smrg	OUTGR(0xbc, 0x4f);
407692f60a7Smrg 	break;
408692f60a7Smrg    case NM2200:
409692f60a7Smrg    case NM2230:
410692f60a7Smrg    case NM2360:
411692f60a7Smrg    case NM2380:
412692f60a7Smrg	OUTGR(0xbc, 0x2e);
413692f60a7Smrg 	break;
414692f60a7Smrg    }
415692f60a7Smrg
416692f60a7Smrg
417692f60a7Smrg    OUTGR(0xb1, (((dstBox.x2-1) >> 4) & 0xf0) | ((dstBox.x1 >> 8) & 0x0f));
418692f60a7Smrg    OUTGR(0xb2, dstBox.x1);
419692f60a7Smrg    OUTGR(0xb3, dstBox.x2 - 1);
420692f60a7Smrg    OUTGR(0xb4, (((dstBox.y2 - 1) >> 4) & 0xf0) | ((dstBox.y1 >> 8) & 0x0f));
421692f60a7Smrg    OUTGR(0xb5, dstBox.y1);
422692f60a7Smrg    OUTGR(0xb6, dstBox.y2 - 1);
423692f60a7Smrg    OUTGR(0xb7, offset >> 16);
424692f60a7Smrg    OUTGR(0xb8, offset >> 8);
425692f60a7Smrg    OUTGR(0xb9, offset );
426692f60a7Smrg    OUTGR(0xba, src_pitch >> 8);
427692f60a7Smrg    OUTGR(0xbb, src_pitch);
428692f60a7Smrg
429692f60a7Smrg    OUTGR(0xc0, xscale >> 8);
430692f60a7Smrg    OUTGR(0xc1, xscale);
431692f60a7Smrg    OUTGR(0xc2, yscale >> 8);
432692f60a7Smrg    OUTGR(0xc3, yscale);
433692f60a7Smrg    OUTGR(0xbf, 0x02);
434692f60a7Smrg
435692f60a7Smrg    OUTGR(0x0a, 0x21);
436692f60a7Smrg
437692f60a7Smrg    OUTSR(0x0c, offset );
438692f60a7Smrg    OUTSR(0x0d, offset >> 8);
439692f60a7Smrg    OUTSR(0x0e, offset >> 16);
440692f60a7Smrg    OUTSR(0x1a, src_pitch);
441692f60a7Smrg    OUTSR(0x1b, src_pitch>>8);
442692f60a7Smrg
443692f60a7Smrg    OUTSR(0x17, 0 + x1);
444692f60a7Smrg    OUTSR(0x18, 0 + x2 -1);
445692f60a7Smrg    OUTSR(0x19, (((0 + x2 - 1) >> 4) & 0xf0) | (((0 + x1) >> 8) & 0x0f));
446692f60a7Smrg
447692f60a7Smrg    OUTSR(0x14, 14 + y1);
448692f60a7Smrg    OUTSR(0x15, 14 + y2 - 2);
449692f60a7Smrg    OUTSR(0x16, (((14 + y2 - 1) >> 4) & 0xf0) | (((14 + y1) >> 8) & 0x0f));
450692f60a7Smrg
451692f60a7Smrg    OUTSR(0x1c, 0xfb);
452692f60a7Smrg    OUTSR(0x1d, 0x00);
453692f60a7Smrg    OUTSR(0x1e, 0xe2);
454692f60a7Smrg    OUTSR(0x1f, 0x02);
455692f60a7Smrg
456692f60a7Smrg    OUTSR(0x09, 0x11);
457692f60a7Smrg    OUTSR(0x0a, 0x00);
458692f60a7Smrg
459692f60a7Smrg    capctrl = 0x21;
460692f60a7Smrg    switch (pPriv->interlace){
461692f60a7Smrg    case 0: /* Combine 2 fields */
462692f60a7Smrg	break;
463692f60a7Smrg    case 1: /* one field only */
464692f60a7Smrg	capctrl |= 0x80;
465692f60a7Smrg	break;
466692f60a7Smrg    case 2: /* Interlaced fields */
467692f60a7Smrg	capctrl |= 0x40;
468692f60a7Smrg	break;
469692f60a7Smrg    }
470692f60a7Smrg    OUTSR(0x08, capctrl);
471692f60a7Smrg
472692f60a7Smrg#if 0
473692f60a7Smrg    OUTGR(0x0a, 0x01);
474692f60a7Smrg#endif
475692f60a7Smrg    OUTGR(0xb0, 0x03);
476692f60a7Smrg
477692f60a7Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
478692f60a7Smrg    return (Success);
479692f60a7Smrg}
480692f60a7Smrg
481692f60a7Smrgstatic void
482692f60a7SmrgNEOStopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
483692f60a7Smrg{
484692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
485692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
486692f60a7Smrg    VGA_HWP(pScrn);
487692f60a7Smrg
488692f60a7Smrg#ifdef DEBUG
489692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo\n");
490692f60a7Smrg#endif
491692f60a7Smrg    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
492692f60a7Smrg
493692f60a7Smrg    if (exit){
494692f60a7Smrg	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
495692f60a7Smrg#ifdef DEBUG
496692f60a7Smrg            xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo: stop capture\n");
497692f60a7Smrg#endif
498692f60a7Smrg	    OUTGR(0xb0, 0x02);
499692f60a7Smrg	    OUTGR(0x0a, 0x21);
500692f60a7Smrg	    OUTSR(0x08, 0xa0);
501692f60a7Smrg#if 0
502692f60a7Smrg	    OUTGR(0x0a, 0x01);
503692f60a7Smrg#endif
504692f60a7Smrg	}
505692f60a7Smrg	if (pPriv->linear != NULL){
506692f60a7Smrg	    xf86FreeOffscreenLinear(pPriv->linear);
507692f60a7Smrg	    pPriv->linear = NULL;
508692f60a7Smrg	}
509692f60a7Smrg	pPriv->videoStatus = 0;
510692f60a7Smrg    } else {
511692f60a7Smrg	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
512692f60a7Smrg	    OUTGR(0xb0, 0x02);
513692f60a7Smrg	    OUTGR(0x0a, 0x21);
514692f60a7Smrg	    OUTSR(0x08, 0xa0);
515692f60a7Smrg#if 0
516692f60a7Smrg	    OUTGR(0x0a, 0x01);
517692f60a7Smrg#endif
518692f60a7Smrg	    pPriv->videoStatus |= OFF_TIMER;
519692f60a7Smrg	    pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
520692f60a7Smrg	}
521692f60a7Smrg    }
522692f60a7Smrg}
523692f60a7Smrg
524692f60a7Smrgstatic int
525692f60a7SmrgNEOSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value,
526692f60a7Smrg		    pointer data)
527692f60a7Smrg{
528692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
529692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
530692f60a7Smrg    VGA_HWP(pScrn);
531692f60a7Smrg
532692f60a7Smrg#ifdef DEBUG
533692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetPortAttribute\n");
534692f60a7Smrg#endif
535692f60a7Smrg    if (attribute == xvColorKey){
536692f60a7Smrg	int r, g, b;
537692f60a7Smrg
538692f60a7Smrg	pPriv->colorKey = value;
539692f60a7Smrg	switch (pScrn->depth){
540692f60a7Smrg	case 8:
541692f60a7Smrg	    OUTGR(0xc6, pPriv->colorKey & 0xff);
542692f60a7Smrg	    OUTGR(0xc5, 0x00);
543692f60a7Smrg	    OUTGR(0xc7, 0x00);
544692f60a7Smrg	    break;
545692f60a7Smrg	default:
546692f60a7Smrg	    r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
547692f60a7Smrg	    g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
548692f60a7Smrg	    b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
549692f60a7Smrg	    OUTGR(0xc5, r);
550692f60a7Smrg	    OUTGR(0xc6, g);
551692f60a7Smrg	    OUTGR(0xc7, b);
552692f60a7Smrg	}
553692f60a7Smrg    } else if (attribute == xvBrightness){
554692f60a7Smrg	if ((value < -128) || (value > 127)){
555692f60a7Smrg	    return (BadValue);
556692f60a7Smrg	}
557692f60a7Smrg	pPriv->brightness = value;
558692f60a7Smrg	OUTGR(0xc4, value);
559692f60a7Smrg    } else if (attribute == xvInterlace){
560692f60a7Smrg	if (value < 0  ||  value > 2){
561692f60a7Smrg	    return (BadValue);
562692f60a7Smrg	}
563692f60a7Smrg	pPriv->interlace = value;
564692f60a7Smrg    } else {
565692f60a7Smrg	return (BadMatch);
566692f60a7Smrg    }
567692f60a7Smrg    return (Success);
568692f60a7Smrg}
569692f60a7Smrg
570692f60a7Smrgstatic int
571692f60a7SmrgNEOGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value,
572692f60a7Smrg		    pointer data)
573692f60a7Smrg{
574692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
575692f60a7Smrg
576692f60a7Smrg#ifdef DEBUG
577692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetPortAttribute\n");
578692f60a7Smrg#endif
579692f60a7Smrg    if (attribute == xvColorKey){
580692f60a7Smrg	*value = pPriv->colorKey;
581692f60a7Smrg    } else if (attribute == xvBrightness){
582692f60a7Smrg	*value = pPriv->brightness;
583692f60a7Smrg    } else if (attribute == xvInterlace){
584692f60a7Smrg	*value = pPriv->interlace;
585692f60a7Smrg    } else {
586692f60a7Smrg	return (BadMatch);
587692f60a7Smrg    }
588692f60a7Smrg    return (Success);
589692f60a7Smrg}
590692f60a7Smrg
591692f60a7Smrgstatic void
592692f60a7SmrgNEOQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
593692f60a7Smrg		 short vid_w, short vid_h, short drw_w, short drw_h,
594692f60a7Smrg		 unsigned int *p_w, unsigned int *p_h,
595692f60a7Smrg		 pointer data)
596692f60a7Smrg{
597692f60a7Smrg#ifdef DEBUG
598692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryBestSize\n");
599692f60a7Smrg#endif
600692f60a7Smrg    *p_w = min(drw_w, 1024);
601692f60a7Smrg    *p_h = min(drw_h, 1024);
602692f60a7Smrg}
603692f60a7Smrg
604692f60a7Smrgstatic int
605692f60a7SmrgNEOPutImage(ScrnInfoPtr pScrn,
606692f60a7Smrg	    short src_x, short src_y, short drw_x, short drw_y,
607692f60a7Smrg	    short src_w, short src_h, short drw_w, short drw_h,
608692f60a7Smrg	    int id, unsigned char *buf, short width, short height,
609692f60a7Smrg	    Bool sync, RegionPtr clipBoxes, pointer data,
610692f60a7Smrg	    DrawablePtr pDraw)
611692f60a7Smrg{
612692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
613692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
614692f60a7Smrg    INT32 x1, y1, x2, y2;
615692f60a7Smrg    int bpp;
616692f60a7Smrg    int srcPitch, srcPitch2 = 0, dstPitch, size;
617692f60a7Smrg    BoxRec dstBox;
618692f60a7Smrg    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
619692f60a7Smrg    int left, top, nPixels, nLines;
620692f60a7Smrg    unsigned char *dstStart;
621692f60a7Smrg
622692f60a7Smrg#ifdef DEBUG
623692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutImage\n");
624692f60a7Smrg#endif
625692f60a7Smrg
626692f60a7Smrg    x1 = src_x;
627692f60a7Smrg    y1 = src_y;
628692f60a7Smrg    x2 = src_x + src_w;
629692f60a7Smrg    y2 = src_y + src_h;
630692f60a7Smrg
631692f60a7Smrg    dstBox.x1 = drw_x;
632692f60a7Smrg    dstBox.y1 = drw_y;
633692f60a7Smrg    dstBox.x2 = drw_x + drw_w;
634692f60a7Smrg    dstBox.y2 = drw_y + drw_h;
635692f60a7Smrg
636692f60a7Smrg    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
637692f60a7Smrg			       clipBoxes, width, height)){
638692f60a7Smrg	return (Success);
639692f60a7Smrg    }
640692f60a7Smrg
641692f60a7Smrg    dstBox.x1 -= pScrn->frameX0;
642692f60a7Smrg    dstBox.y1 -= pScrn->frameY0;
643692f60a7Smrg    dstBox.x2 -= pScrn->frameX0;
644692f60a7Smrg    dstBox.y2 -= pScrn->frameY0;
645692f60a7Smrg
646692f60a7Smrg    bpp = ((pScrn->bitsPerPixel + 1) >> 3);
647692f60a7Smrg
648692f60a7Smrg    switch (id){
649692f60a7Smrg    case FOURCC_YV12:
650692f60a7Smrg	srcPitch  = (width + 3) & ~3;
651692f60a7Smrg	offset2   = srcPitch * height;
652692f60a7Smrg	srcPitch2 = ((width >> 1) + 3) & ~3;
653692f60a7Smrg	offset3   = offset2 + (srcPitch2 * (height >> 1));
654692f60a7Smrg  	dstPitch  = ((width << 1) + 15) & ~15;
655692f60a7Smrg	break;
656692f60a7Smrg    case FOURCC_I420:
657692f60a7Smrg	srcPitch  = (width + 3) & ~3;
658692f60a7Smrg	offset3   = srcPitch * height;
659692f60a7Smrg	srcPitch2 = ((width >> 1) + 3) & ~3;
660692f60a7Smrg	offset2   = offset3 + (srcPitch2 * (height >> 1));
661692f60a7Smrg  	dstPitch  = ((width << 1) + 15) & ~15;
662692f60a7Smrg	break;
663692f60a7Smrg    case FOURCC_YUY2:
664692f60a7Smrg    case FOURCC_RV15:
665692f60a7Smrg    case FOURCC_RV16:
666692f60a7Smrg    default:
667692f60a7Smrg	srcPitch = width << 1;
668692f60a7Smrg  	dstPitch = (srcPitch + 15) & ~15;
669692f60a7Smrg	break;
670692f60a7Smrg    }
671692f60a7Smrg
672692f60a7Smrg    size = dstPitch * height;
673692f60a7Smrg    if (size > nPtr->overlay){
674692f60a7Smrg	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size))
675692f60a7Smrg	    == NULL){
676692f60a7Smrg	    return (BadAlloc);
677692f60a7Smrg	}
678692f60a7Smrg    } else {
679692f60a7Smrg	pPriv->linear = NULL;
680692f60a7Smrg    }
681692f60a7Smrg
682692f60a7Smrg    top = y1 >> 16;
683692f60a7Smrg    left = (x1 >> 16) & ~1;
684692f60a7Smrg    nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left;
685692f60a7Smrg    left <<= 1;
686692f60a7Smrg
687692f60a7Smrg    if (pPriv->linear == NULL){
688692f60a7Smrg	offset = nPtr->overlay_offset;
689692f60a7Smrg    } else {
690692f60a7Smrg	offset =  pPriv->linear->offset * bpp;
691692f60a7Smrg    }
692692f60a7Smrg
693692f60a7Smrg#ifdef DEBUG
694692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"offset=%x\n", offset);
695692f60a7Smrg#endif
696692f60a7Smrg
697692f60a7Smrg    dstStart = (unsigned char *)(nPtr->NeoFbBase + offset + left);
698692f60a7Smrg
699692f60a7Smrg    switch (id){
700692f60a7Smrg    case FOURCC_YV12:
701692f60a7Smrg    case FOURCC_I420:
702692f60a7Smrg	top &= ~1;
703692f60a7Smrg	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
704692f60a7Smrg	offset2 += tmp;
705692f60a7Smrg	offset3 += tmp;
706692f60a7Smrg	nLines = ((((y2 + 0xFFFF) >> 16) + 1) & ~1) - top;
707692f60a7Smrg	xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
708692f60a7Smrg				buf + offset2, buf + offset3,
709692f60a7Smrg				dstStart, srcPitch, srcPitch2,
710692f60a7Smrg				dstPitch, nLines, nPixels);
711692f60a7Smrg	break;
712692f60a7Smrg    default:
713692f60a7Smrg	buf += (top * srcPitch) + left;
714692f60a7Smrg	nLines = ((y2 + 0xFFFF) >> 16) - top;
715692f60a7Smrg	xf86XVCopyPacked(buf, dstStart, srcPitch, dstPitch,
716692f60a7Smrg			 nLines, nPixels << 1);
717692f60a7Smrg    }
718692f60a7Smrg
719692f60a7Smrg    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)){
720692f60a7Smrg	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
721692f60a7Smrg        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
722692f60a7Smrg    }
723692f60a7Smrg	NEODisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1,
724692f60a7Smrg			x2, y2,	&dstBox, src_w, src_h, drw_w, drw_h);
725692f60a7Smrg
726692f60a7Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
727692f60a7Smrg    return (Success);
728692f60a7Smrg
729692f60a7Smrg}
730692f60a7Smrg
731692f60a7Smrgstatic int
732692f60a7SmrgNEOQueryImageAttributes(ScrnInfoPtr pScrn, int id,
733692f60a7Smrg			unsigned short *width, unsigned short *height,
734692f60a7Smrg			int *pitches, int *offsets)
735692f60a7Smrg{
736692f60a7Smrg    int size, tmp;
737692f60a7Smrg
738692f60a7Smrg#ifdef DEBUG
739692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryImageAttributes\n");
740692f60a7Smrg#endif
741692f60a7Smrg    if (*width > 1024){
742692f60a7Smrg	*width = 1024;
743692f60a7Smrg    }
744692f60a7Smrg    if (*height > 1024){
745692f60a7Smrg	*height = 1024;
746692f60a7Smrg    }
747692f60a7Smrg
748692f60a7Smrg    *width = (*width + 1) & ~1;
749692f60a7Smrg    if (offsets != NULL){
750692f60a7Smrg	offsets[0] = 0;
751692f60a7Smrg    }
752692f60a7Smrg
753692f60a7Smrg    switch (id){
754692f60a7Smrg    case FOURCC_YV12:
755692f60a7Smrg    case FOURCC_I420:
756692f60a7Smrg	*height = (*height + 1) & ~1;
757692f60a7Smrg	size = (*width + 3) & ~3;
758692f60a7Smrg	if (pitches != NULL){
759692f60a7Smrg	    pitches[0] = size;
760692f60a7Smrg	}
761692f60a7Smrg	size *= *height;
762692f60a7Smrg	if (offsets != NULL){
763692f60a7Smrg	    offsets[1] = size;
764692f60a7Smrg	}
765692f60a7Smrg	tmp = ((*width >> 1) + 3) & ~3;
766692f60a7Smrg	if (pitches != NULL){
767692f60a7Smrg	    pitches[1] = pitches[2] = tmp;
768692f60a7Smrg	}
769692f60a7Smrg	tmp *= (*height >> 1);
770692f60a7Smrg	size += tmp;
771692f60a7Smrg	if (offsets != NULL){
772692f60a7Smrg	    offsets[2] = size;
773692f60a7Smrg	}
774692f60a7Smrg	size += tmp;
775692f60a7Smrg	break;
776692f60a7Smrg    case FOURCC_YUY2:
777692f60a7Smrg    case FOURCC_RV15:
778692f60a7Smrg    case FOURCC_RV16:
779692f60a7Smrg    default:
780692f60a7Smrg	size = *width * 2;
781692f60a7Smrg	if (pitches != NULL){
782692f60a7Smrg	    pitches[0] = size;
783692f60a7Smrg	}
784692f60a7Smrg	size *= *height;
785692f60a7Smrg	break;
786692f60a7Smrg    }
787692f60a7Smrg    return (size);
788692f60a7Smrg}
789692f60a7Smrg
790692f60a7Smrgstatic void
791692f60a7SmrgNEODisplayVideo(ScrnInfoPtr pScrn, int id, int offset,
792692f60a7Smrg		 short width, short height, int pitch,
793692f60a7Smrg		 int x1, int y1, int x2, int y2, BoxPtr dstBox,
794692f60a7Smrg		 short src_w, short src_h, short drw_w, short drw_h)
795692f60a7Smrg{
796692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
797692f60a7Smrg    int hstretch, vstretch, fmt;
798692f60a7Smrg    VGA_HWP(pScrn);
799692f60a7Smrg#ifdef DEBUG
800692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEODisplayVideo\n");
801692f60a7Smrg    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);
802692f60a7Smrg#endif
803692f60a7Smrg#define WIDTH_THRESHOLD 160
804692f60a7Smrg    if (dstBox->x2 >= pScrn->virtualX) {
805692f60a7Smrg	/*
806692f60a7Smrg	 * This is a hack to work around a problem when video is moved
807efb46889Smrg	 * across the right border.
808692f60a7Smrg	 */
809692f60a7Smrg	int diff_s = (width - ((x2 - x1) >> 16)) & ~1;
810692f60a7Smrg	int diff_d = (drw_w - dstBox->x2 + dstBox->x1) & ~1;
811692f60a7Smrg
812692f60a7Smrg	offset -= 2 * ((diff_s > diff_d) ? diff_d : diff_s);
813692f60a7Smrg	dstBox->x1 -= diff_d;
814692f60a7Smrg    } else if (dstBox->x2 - dstBox->x1 < WIDTH_THRESHOLD) {
815692f60a7Smrg	/*
816692f60a7Smrg	 * When the video window is less than about 160 pixel wide
817692f60a7Smrg	 * it will be distoreted. We attempt to fix it by actually
818692f60a7Smrg	 * making it wider and relying on the color key to prevent
819692f60a7Smrg	 * it from appearing outside of the video.
820692f60a7Smrg	 */
821692f60a7Smrg	int pre, post;
822692f60a7Smrg	int scale = 1;
823692f60a7Smrg
824692f60a7Smrg	if (dstBox->x1 < WIDTH_THRESHOLD) {
825692f60a7Smrg	    pre = dstBox->x1;
826692f60a7Smrg	    post = 160 - pre;
827692f60a7Smrg	} else {
828692f60a7Smrg	    pre = 160;
829692f60a7Smrg	    post = 0;
830692f60a7Smrg	}
831692f60a7Smrg	offset -= 2 * scale * pre;
832692f60a7Smrg	dstBox->x1 -= pre;
833692f60a7Smrg	dstBox->x2 += post;
834692f60a7Smrg    }
835692f60a7Smrg    if (nPtr->videoHZoom != 1.0) {
836692f60a7Smrg	if ((dstBox->x2 += 5) > pScrn->virtualX)
837692f60a7Smrg	    dstBox->x2 = pScrn->virtualX;
838692f60a7Smrg	if (dstBox->x1 > 0) dstBox->x1 += 2;
839692f60a7Smrg    }
840692f60a7Smrg
841692f60a7Smrg    fmt = 0x00;
842692f60a7Smrg    switch (id){
843692f60a7Smrg    case FOURCC_YV12:
844692f60a7Smrg    case FOURCC_I420:
845692f60a7Smrg    case FOURCC_YUY2:
846692f60a7Smrg	fmt = 0x00;
847692f60a7Smrg	break;
848692f60a7Smrg    case FOURCC_RV15:
849692f60a7Smrg    case FOURCC_RV16:
850692f60a7Smrg	fmt = 0x20;
851692f60a7Smrg	break;
852692f60a7Smrg    }
853692f60a7Smrg
854692f60a7Smrg    offset += (x1 >> 15) & ~0x03;
855692f60a7Smrg
856692f60a7Smrg    switch (nPtr->NeoChipset) {
857692f60a7Smrg    default:
858692f60a7Smrg    case NM2090:
859692f60a7Smrg    case NM2093:
860692f60a7Smrg    case NM2097:
861692f60a7Smrg    case NM2160:
862692f60a7Smrg        offset/=2;
863692f60a7Smrg	pitch/=2;
864692f60a7Smrg        OUTGR(0xbc, 0x4f);
865692f60a7Smrg	break;
866692f60a7Smrg    case NM2200:
867692f60a7Smrg    case NM2230:
868692f60a7Smrg    case NM2360:
869692f60a7Smrg    case NM2380:
870692f60a7Smrg        OUTGR(0xbc, 0x2e);
871692f60a7Smrg	break;
872692f60a7Smrg    }
873692f60a7Smrg
874692f60a7Smrg    /* factor 4 for granularity */
875692f60a7Smrg    hstretch = (double)0x1000 * 4 / (int)(nPtr->videoHZoom * 4);
876692f60a7Smrg    if (drw_w > src_w)
877692f60a7Smrg	hstretch = (((int)src_w) * hstretch) / (int) drw_w;
878692f60a7Smrg
879692f60a7Smrg    vstretch = (double)0x1000 / nPtr->videoVZoom;
880692f60a7Smrg    if (drw_h > src_h)
881692f60a7Smrg	vstretch = (((int)src_h) * vstretch )/ (int) drw_h;
882692f60a7Smrg
883692f60a7Smrg    OUTGR(0xb1, (((dstBox->x2 - 1) >> 4) & 0xf0) | ((dstBox->x1 >> 8) & 0x0f));
884692f60a7Smrg    OUTGR(0xb2, dstBox->x1);
885692f60a7Smrg    OUTGR(0xb3, dstBox->x2 - 1);
886692f60a7Smrg    OUTGR(0xb4, (((dstBox->y2 - 1) >> 4) & 0xf0) | ((dstBox->y1 >> 8) & 0x0f));
887692f60a7Smrg    OUTGR(0xb5, dstBox->y1);
888692f60a7Smrg    OUTGR(0xb6, dstBox->y2 - 1);
889692f60a7Smrg    OUTGR(0xb7, offset >> 16);
890692f60a7Smrg    OUTGR(0xb8, offset >> 8);
891692f60a7Smrg    OUTGR(0xb9, offset );
892692f60a7Smrg    OUTGR(0xba, pitch >> 8);
893692f60a7Smrg    OUTGR(0xbb, pitch);
894692f60a7Smrg
895692f60a7Smrg    OUTGR(0xbd, 0x02);
896692f60a7Smrg    OUTGR(0xbe, 0x00);
897692f60a7Smrg    OUTGR(0xbf, 0x02);
898692f60a7Smrg
899692f60a7Smrg    OUTGR(0xc0, hstretch >> 8);
900692f60a7Smrg    OUTGR(0xc1, hstretch);
901692f60a7Smrg    OUTGR(0xc2, vstretch >> 8);
902692f60a7Smrg    OUTGR(0xc3, vstretch);
903692f60a7Smrg
904692f60a7Smrg    OUTGR(0xb0, fmt | 0x03);
905692f60a7Smrg
906692f60a7Smrg    OUTGR(0x0a, 0x21);
907692f60a7Smrg    OUTSR(0x08, 0xa0);
908692f60a7Smrg    OUTGR(0x0a, 0x01);
909692f60a7Smrg}
910692f60a7Smrg
911692f60a7Smrgstatic void
912692f60a7SmrgNEOInitOffscreenImages(ScreenPtr pScreen)
913692f60a7Smrg{
914692f60a7Smrg    XF86OffscreenImagePtr offscreenImages;
915692f60a7Smrg
916692f60a7Smrg#ifdef DEBUG
9173f6d0e1dSmrg    xf86DrvMsg(xf86ScreenToScrn(pScreen)->scrnIndex,X_INFO,"NEOInitOffscreenImages\n");
918692f60a7Smrg#endif
9193f6d0e1dSmrg    if ((offscreenImages = malloc(sizeof(XF86OffscreenImageRec))) == NULL){
920692f60a7Smrg	return;
921692f60a7Smrg    }
922692f60a7Smrg
923692f60a7Smrg    offscreenImages->image = NEOVideoImages;
924692f60a7Smrg    offscreenImages->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
925692f60a7Smrg    offscreenImages->alloc_surface = NEOAllocSurface;
926692f60a7Smrg    offscreenImages->free_surface = NEOFreeSurface;
927692f60a7Smrg    offscreenImages->display = NEODisplaySurface;
928692f60a7Smrg    offscreenImages->stop = NEOStopSurface;
929692f60a7Smrg    offscreenImages->getAttribute = NEOGetSurfaceAttribute;
930692f60a7Smrg    offscreenImages->setAttribute = NEOSetSurfaceAttribute;
931692f60a7Smrg    offscreenImages->max_width = 1024;
932692f60a7Smrg    offscreenImages->max_height = 1024;
933692f60a7Smrg    offscreenImages->num_attributes = nElems(NEOVideoAttributes);
934692f60a7Smrg    offscreenImages->attributes = NEOVideoAttributes;
935692f60a7Smrg
936692f60a7Smrg    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
937692f60a7Smrg}
938692f60a7Smrg
939692f60a7Smrgstatic FBLinearPtr
940692f60a7SmrgNEOAllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
941692f60a7Smrg{
942692f60a7Smrg    ScreenPtr pScreen;
943692f60a7Smrg    FBLinearPtr new_linear;
944692f60a7Smrg    int bytespp = pScrn->bitsPerPixel >> 3;
945692f60a7Smrg
946692f60a7Smrg    /* convert size in bytes into number of pixels */
947692f60a7Smrg    size = (size + bytespp - 1) / bytespp;
948692f60a7Smrg#ifdef DEBUG
949692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
950692f60a7Smrg	       "NEOAllocateMemory: linear=%x, size=%d\n", linear, size);
951692f60a7Smrg#endif
952692f60a7Smrg    if (linear){
953692f60a7Smrg#ifdef DEBUG
954692f60a7Smrg        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
955692f60a7Smrg		   "NEOAllocateMemory: linear->size=%d\n", linear->size);
956692f60a7Smrg#endif
957692f60a7Smrg	if (linear->size >= size){
958692f60a7Smrg	    return (linear);
959692f60a7Smrg	}
960692f60a7Smrg
961692f60a7Smrg	if (xf86ResizeOffscreenLinear(linear, size)){
962692f60a7Smrg	    return (linear);
963692f60a7Smrg	}
964692f60a7Smrg
965692f60a7Smrg	xf86FreeOffscreenLinear(linear);
966692f60a7Smrg    }
967692f60a7Smrg
968692f60a7Smrg
9693f6d0e1dSmrg    pScreen = xf86ScrnToScreen(pScrn);
970692f60a7Smrg    if ((new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, NULL,
971692f60a7Smrg						  NULL, NULL)) == NULL){
972692f60a7Smrg	int max_size;
973692f60a7Smrg
974692f60a7Smrg	xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
975692f60a7Smrg					PRIORITY_EXTREME);
976692f60a7Smrg#ifdef DEBUG
977692f60a7Smrg        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
978692f60a7Smrg		   "NEOAllocateMemory: max_size=%d\n", max_size);
979692f60a7Smrg#endif
980692f60a7Smrg	if (max_size < size){
981692f60a7Smrg	    return (NULL);
982692f60a7Smrg	}
983692f60a7Smrg
984692f60a7Smrg	xf86PurgeUnlockedOffscreenAreas(pScreen);
985692f60a7Smrg	new_linear = xf86AllocateOffscreenLinear(pScreen,
986692f60a7Smrg						 size, 16, NULL, NULL, NULL);
987692f60a7Smrg    }
988692f60a7Smrg
989692f60a7Smrg    return (new_linear);
990692f60a7Smrg}
991692f60a7Smrg
992692f60a7Smrgstatic int
993692f60a7SmrgNEOAllocSurface(ScrnInfoPtr pScrn, int id,
994692f60a7Smrg		unsigned short width, unsigned short height,
995692f60a7Smrg		XF86SurfacePtr surface)
996692f60a7Smrg{
997692f60a7Smrg    int pitch, size;
998692f60a7Smrg    NEOOffscreenPtr pPriv;
999692f60a7Smrg    FBLinearPtr linear;
1000692f60a7Smrg
1001692f60a7Smrg#ifdef DEBUG
1002692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOAllocSurface\n");
1003692f60a7Smrg#endif
1004692f60a7Smrg    if (width > 1024  || height > 1024){
1005692f60a7Smrg	return (BadAlloc);
1006692f60a7Smrg    }
1007692f60a7Smrg
1008692f60a7Smrg    width = (width + 1) & ~1;
1009692f60a7Smrg    pitch = ((width << 1) + 15) & ~15;
1010692f60a7Smrg    size = pitch * height;
1011692f60a7Smrg
1012692f60a7Smrg    if ((linear = NEOAllocateMemory(pScrn, NULL, size)) == NULL){
1013692f60a7Smrg	return (BadAlloc);
1014692f60a7Smrg    }
1015692f60a7Smrg
1016692f60a7Smrg    surface->width = width;
1017692f60a7Smrg    surface->height = height;
10183f6d0e1dSmrg    if ((surface->pitches = malloc(sizeof(int))) == NULL){
1019692f60a7Smrg	xf86FreeOffscreenLinear(linear);
1020692f60a7Smrg	return (BadAlloc);
1021692f60a7Smrg    }
10223f6d0e1dSmrg    if ((surface->offsets = malloc(sizeof(int))) == NULL){
10233f6d0e1dSmrg	free(surface->pitches);
1024692f60a7Smrg	xf86FreeOffscreenLinear(linear);
1025692f60a7Smrg	return (BadAlloc);
1026692f60a7Smrg    }
1027692f60a7Smrg
10283f6d0e1dSmrg    if ((pPriv = malloc(sizeof(NEOOffscreenRec))) == NULL){
10293f6d0e1dSmrg	free(surface->pitches);
10303f6d0e1dSmrg	free(surface->offsets);
1031692f60a7Smrg	xf86FreeOffscreenLinear(linear);
1032692f60a7Smrg	return (BadAlloc);
1033692f60a7Smrg    }
1034692f60a7Smrg
1035692f60a7Smrg    pPriv->linear = linear;
1036692f60a7Smrg    pPriv->isOn = FALSE;
1037692f60a7Smrg
1038692f60a7Smrg    surface->pScrn = pScrn;
1039692f60a7Smrg    surface->id = id;
1040692f60a7Smrg    surface->pitches[0] = pitch;
1041692f60a7Smrg    surface->offsets[0] = linear->offset << 1;
1042692f60a7Smrg    surface->devPrivate.ptr = (pointer)pPriv;
1043692f60a7Smrg    return (Success);
1044692f60a7Smrg}
1045692f60a7Smrg
1046692f60a7Smrgstatic int
1047692f60a7SmrgNEOFreeSurface(XF86SurfacePtr surface)
1048692f60a7Smrg{
1049692f60a7Smrg    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1050692f60a7Smrg
1051692f60a7Smrg#ifdef DEBUG
1052692f60a7Smrg    xf86DrvMsg(0,X_INFO,"NEOFreeSurface\n");
1053692f60a7Smrg#endif
1054692f60a7Smrg    if (pPriv->isOn)
1055692f60a7Smrg	NEOStopSurface(surface);
1056692f60a7Smrg
1057692f60a7Smrg    xf86FreeOffscreenLinear(pPriv->linear);
10583f6d0e1dSmrg    free(surface->pitches);
10593f6d0e1dSmrg    free(surface->offsets);
10603f6d0e1dSmrg    free(surface->devPrivate.ptr);
1061692f60a7Smrg    return (Success);
1062692f60a7Smrg}
1063692f60a7Smrg
1064692f60a7Smrgstatic int
1065692f60a7SmrgNEODisplaySurface(XF86SurfacePtr surface,
1066692f60a7Smrg		  short src_x, short src_y, short drw_x, short drw_y,
1067692f60a7Smrg		  short src_w, short src_h, short drw_w, short drw_h,
1068692f60a7Smrg		  RegionPtr clipBoxes)
1069692f60a7Smrg{
1070692f60a7Smrg    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1071692f60a7Smrg    NEOPtr nPtr = NEOPTR(surface->pScrn);
1072692f60a7Smrg    NEOPortPtr portPriv = nPtr->overlayAdaptor->pPortPrivates[0].ptr;
1073692f60a7Smrg    INT32 x1, y1, x2, y2;
1074692f60a7Smrg    BoxRec dstBox;
1075692f60a7Smrg
1076692f60a7Smrg#ifdef DEBUG
1077692f60a7Smrg    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEODisplaySurface\n");
1078692f60a7Smrg#endif
1079692f60a7Smrg    x1 = src_x;
1080692f60a7Smrg    x2 = src_x + src_w;
1081692f60a7Smrg    y1 = src_y;
1082692f60a7Smrg    y2 = src_y + src_h;
1083692f60a7Smrg
1084692f60a7Smrg    dstBox.x1 = drw_x;
1085692f60a7Smrg    dstBox.x2 = drw_x + drw_w;
1086692f60a7Smrg    dstBox.y1 = drw_y;
1087692f60a7Smrg    dstBox.y2 = drw_y + drw_h;
1088692f60a7Smrg    if (!xf86XVClipVideoHelper( &dstBox, &x1, &x2, &y1, &y2,
1089692f60a7Smrg			       clipBoxes, surface->width, surface->height)){
1090692f60a7Smrg	return (Success);
1091692f60a7Smrg    }
1092692f60a7Smrg
1093692f60a7Smrg    dstBox.x1 -= surface->pScrn->frameX0;
1094692f60a7Smrg    dstBox.y1 -= surface->pScrn->frameY0;
1095692f60a7Smrg    dstBox.x2 -= surface->pScrn->frameX0;
1096692f60a7Smrg    dstBox.y2 -= surface->pScrn->frameY0;
1097692f60a7Smrg
1098692f60a7Smrg    xf86XVFillKeyHelper(surface->pScrn->pScreen, portPriv->colorKey,
1099692f60a7Smrg			clipBoxes);
1100692f60a7Smrg    NEOResetVideo(surface->pScrn);
1101692f60a7Smrg    NEODisplayVideo(surface->pScrn, surface->id, surface->offsets[0],
1102692f60a7Smrg		    surface->width, surface->height, surface->pitches[0],
1103692f60a7Smrg		    x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1104692f60a7Smrg
1105692f60a7Smrg    pPriv->isOn = TRUE;
1106692f60a7Smrg    if (portPriv->videoStatus & CLIENT_VIDEO_ON){
1107692f60a7Smrg	REGION_EMPTY(surface->pScrn->pScreen, &portPriv->clip);
1108692f60a7Smrg	UpdateCurrentTime();
1109692f60a7Smrg	portPriv->videoStatus = FREE_TIMER;
1110692f60a7Smrg	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1111692f60a7Smrg    }
1112692f60a7Smrg    return (Success);
1113692f60a7Smrg}
1114692f60a7Smrg
1115692f60a7Smrgstatic int
1116692f60a7SmrgNEOStopSurface(XF86SurfacePtr surface)
1117692f60a7Smrg{
1118692f60a7Smrg    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1119692f60a7Smrg
1120692f60a7Smrg#ifdef DEBUG
1121692f60a7Smrg    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEOStopSurface\n");
1122692f60a7Smrg#endif
1123692f60a7Smrg    if (pPriv->isOn){
1124692f60a7Smrg	NEOPtr nPtr = NEOPTR(surface->pScrn);
1125692f60a7Smrg	VGA_HWP(surface->pScrn);
1126692f60a7Smrg	OUTGR(0xb0, 0x02);
1127692f60a7Smrg	pPriv->isOn = FALSE;
1128692f60a7Smrg    }
1129692f60a7Smrg    return (Success);
1130692f60a7Smrg}
1131692f60a7Smrg
1132692f60a7Smrgstatic int
1133692f60a7SmrgNEOGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value)
1134692f60a7Smrg{
1135692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1136692f60a7Smrg
1137692f60a7Smrg#ifdef DEBUG
1138692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetSurfaceAttribute\n");
1139692f60a7Smrg#endif
1140692f60a7Smrg    return (NEOGetPortAttribute(pScrn,
1141692f60a7Smrg            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
1142692f60a7Smrg}
1143692f60a7Smrg
1144692f60a7Smrgstatic int
1145692f60a7SmrgNEOSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value)
1146692f60a7Smrg{
1147692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1148692f60a7Smrg
1149692f60a7Smrg#ifdef DEBUG
1150692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetSurfaceAttribute\n");
1151692f60a7Smrg#endif
1152692f60a7Smrg    return (NEOSetPortAttribute(pScrn,
1153692f60a7Smrg            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
1154692f60a7Smrg}
1155