1428d7b3dSmrg/***************************************************************************
2428d7b3dSmrg
3428d7b3dSmrgCopyright 2000 Intel Corporation.  All Rights Reserved.
4428d7b3dSmrg
5428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a
6428d7b3dSmrgcopy of this software and associated documentation files (the
7428d7b3dSmrg"Software"), to deal in the Software without restriction, including
8428d7b3dSmrgwithout limitation the rights to use, copy, modify, merge, publish,
9428d7b3dSmrgdistribute, sub license, and/or sell copies of the Software, and to
10428d7b3dSmrgpermit persons to whom the Software is furnished to do so, subject to
11428d7b3dSmrgthe following conditions:
12428d7b3dSmrg
13428d7b3dSmrgThe above copyright notice and this permission notice (including the
14428d7b3dSmrgnext paragraph) shall be included in all copies or substantial portions
15428d7b3dSmrgof the Software.
16428d7b3dSmrg
17428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18428d7b3dSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19428d7b3dSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20428d7b3dSmrgIN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21428d7b3dSmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22428d7b3dSmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23428d7b3dSmrgTHE USE OR OTHER DEALINGS IN THE SOFTWARE.
24428d7b3dSmrg
25428d7b3dSmrg**************************************************************************/
26428d7b3dSmrg
27428d7b3dSmrg/*
28428d7b3dSmrg * i810_video.c: i810 Xv driver. Based on the mga Xv driver by Mark Vojkovich.
29428d7b3dSmrg *
30428d7b3dSmrg * Authors:
31428d7b3dSmrg * 	Jonathan Bian <jonathan.bian@intel.com>
32428d7b3dSmrg *      Offscreen Images:
33428d7b3dSmrg *        Matt Sottek <matthew.j.sottek@intel.com>
34428d7b3dSmrg */
35428d7b3dSmrg
36428d7b3dSmrg#ifdef HAVE_CONFIG_H
37428d7b3dSmrg#include "config.h"
38428d7b3dSmrg#endif
39428d7b3dSmrg
40428d7b3dSmrg#include <string.h>
41428d7b3dSmrg
42428d7b3dSmrg#include "xorg-server.h"
43428d7b3dSmrg#include "xf86.h"
44428d7b3dSmrg#include "xf86_OSproc.h"
45428d7b3dSmrg#include "compiler.h"
46428d7b3dSmrg#include "xf86Pci.h"
47428d7b3dSmrg#include "xf86fbman.h"
48428d7b3dSmrg#include "regionstr.h"
49428d7b3dSmrg
50428d7b3dSmrg#include "i810.h"
51428d7b3dSmrg#include "xf86xv.h"
52428d7b3dSmrg#include <X11/extensions/Xv.h>
53428d7b3dSmrg#include "dixstruct.h"
54428d7b3dSmrg#include "fourcc.h"
55428d7b3dSmrg
56428d7b3dSmrg#define OFF_DELAY 	250  /* milliseconds */
57428d7b3dSmrg#define FREE_DELAY 	15000
58428d7b3dSmrg
59428d7b3dSmrg#define OFF_TIMER 	0x01
60428d7b3dSmrg#define FREE_TIMER	0x02
61428d7b3dSmrg#define CLIENT_VIDEO_ON	0x04
62428d7b3dSmrg
63428d7b3dSmrg#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
64428d7b3dSmrg
65428d7b3dSmrgstatic void I810InitOffscreenImages(ScreenPtr);
66428d7b3dSmrg
67428d7b3dSmrgstatic XF86VideoAdaptorPtr I810SetupImageVideo(ScreenPtr);
68428d7b3dSmrgstatic void I810StopVideo(ScrnInfoPtr, pointer, Bool);
69428d7b3dSmrgstatic int I810SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
70428d7b3dSmrgstatic int I810GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
71428d7b3dSmrgstatic void I810QueryBestSize(ScrnInfoPtr, Bool,
72428d7b3dSmrg	short, short, short, short, unsigned int *, unsigned int *, pointer);
73428d7b3dSmrgstatic int I810PutImage( ScrnInfoPtr,
74428d7b3dSmrg	short, short, short, short, short, short, short, short,
75428d7b3dSmrg	int, unsigned char*, short, short, Bool, RegionPtr, pointer,
76428d7b3dSmrg	DrawablePtr);
77428d7b3dSmrgstatic int I810QueryImageAttributes(ScrnInfoPtr,
78428d7b3dSmrg	int, unsigned short *, unsigned short *,  int *, int *);
79428d7b3dSmrg
80428d7b3dSmrgstatic void I810BlockHandler(BLOCKHANDLER_ARGS_DECL);
81428d7b3dSmrg
82428d7b3dSmrg#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
83428d7b3dSmrg
84428d7b3dSmrgstatic Atom xvBrightness, xvContrast, xvColorKey;
85428d7b3dSmrg
86428d7b3dSmrg#define IMAGE_MAX_WIDTH		1440
87428d7b3dSmrg#define IMAGE_FAST_WIDTH	720
88428d7b3dSmrg#define IMAGE_MAX_HEIGHT	1080
89428d7b3dSmrg#define Y_BUF_SIZE		(IMAGE_MAX_WIDTH * IMAGE_MAX_HEIGHT)
90428d7b3dSmrg
91428d7b3dSmrg#define OVERLAY_UPDATE(p)	OUTREG(0x30000, p | 0x80000000);
92428d7b3dSmrg
93428d7b3dSmrg/*
94428d7b3dSmrg * OV0CMD - Overlay Command Register
95428d7b3dSmrg */
96428d7b3dSmrg#define	VERTICAL_CHROMINANCE_FILTER 	0x70000000
97428d7b3dSmrg#define VC_SCALING_OFF		0x00000000
98428d7b3dSmrg#define VC_LINE_REPLICATION	0x10000000
99428d7b3dSmrg#define VC_UP_INTERPOLATION	0x20000000
100428d7b3dSmrg#define VC_PIXEL_DROPPING	0x50000000
101428d7b3dSmrg#define VC_DOWN_INTERPOLATION	0x60000000
102428d7b3dSmrg#define VERTICAL_LUMINANCE_FILTER	0x0E000000
103428d7b3dSmrg#define VL_SCALING_OFF		0x00000000
104428d7b3dSmrg#define VL_LINE_REPLICATION	0x02000000
105428d7b3dSmrg#define VL_UP_INTERPOLATION	0x04000000
106428d7b3dSmrg#define VL_PIXEL_DROPPING	0x0A000000
107428d7b3dSmrg#define VL_DOWN_INTERPOLATION	0x0C000000
108428d7b3dSmrg#define	HORIZONTAL_CHROMINANCE_FILTER 	0x01C00000
109428d7b3dSmrg#define HC_SCALING_OFF		0x00000000
110428d7b3dSmrg#define HC_LINE_REPLICATION	0x00400000
111428d7b3dSmrg#define HC_UP_INTERPOLATION	0x00800000
112428d7b3dSmrg#define HC_PIXEL_DROPPING	0x01400000
113428d7b3dSmrg#define HC_DOWN_INTERPOLATION	0x01800000
114428d7b3dSmrg#define HORIZONTAL_LUMINANCE_FILTER	0x00380000
115428d7b3dSmrg#define HL_SCALING_OFF		0x00000000
116428d7b3dSmrg#define HL_LINE_REPLICATION	0x00080000
117428d7b3dSmrg#define HL_UP_INTERPOLATION	0x00100000
118428d7b3dSmrg#define HL_PIXEL_DROPPING	0x00280000
119428d7b3dSmrg#define HL_DOWN_INTERPOLATION	0x00300000
120428d7b3dSmrg
121428d7b3dSmrg#define Y_ADJUST		0x00010000
122428d7b3dSmrg#define OV_BYTE_ORDER		0x0000C000
123428d7b3dSmrg#define UV_SWAP			0x00004000
124428d7b3dSmrg#define Y_SWAP			0x00008000
125428d7b3dSmrg#define Y_AND_UV_SWAP		0x0000C000
126428d7b3dSmrg#define SOURCE_FORMAT		0x00003C00
127428d7b3dSmrg#define	RGB_555			0x00000800
128428d7b3dSmrg#define	RGB_565			0x00000C00
129428d7b3dSmrg#define	YUV_422			0x00002000
130428d7b3dSmrg#define	YUV_411			0x00002400
131428d7b3dSmrg#define	YUV_420			0x00003000
132428d7b3dSmrg#define	YUV_410			0x00003800
133428d7b3dSmrg#define BUFFER_AND_FIELD	0x00000006
134428d7b3dSmrg#define	BUFFER0_FIELD0		0x00000000
135428d7b3dSmrg#define	BUFFER1_FIELD0		0x00000004
136428d7b3dSmrg#define OVERLAY_ENABLE		0x00000001
137428d7b3dSmrg
138428d7b3dSmrg#define UV_VERT_BUF1 		0x02
139428d7b3dSmrg#define UV_VERT_BUF0 		0x04
140428d7b3dSmrg
141428d7b3dSmrg/*
142428d7b3dSmrg * DOV0STA - Display/Overlay 0 Status Register
143428d7b3dSmrg */
144428d7b3dSmrg#define	DOV0STA 	0x30008
145428d7b3dSmrg
146428d7b3dSmrg#define MINUV_SCALE	0x1
147428d7b3dSmrg
148428d7b3dSmrg#define RGB16ToColorKey(c) \
149428d7b3dSmrg	(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
150428d7b3dSmrg
151428d7b3dSmrg#define RGB15ToColorKey(c) \
152428d7b3dSmrg        (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
153428d7b3dSmrg
154428d7b3dSmrgvoid I810InitVideo(ScreenPtr screen)
155428d7b3dSmrg{
156428d7b3dSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
157428d7b3dSmrg    XF86VideoAdaptorPtr *adaptors = NULL;
158428d7b3dSmrg    int num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
159428d7b3dSmrg
160428d7b3dSmrg    if (pScrn->bitsPerPixel != 8) {
161428d7b3dSmrg	XF86VideoAdaptorPtr newAdaptor;
162428d7b3dSmrg
163428d7b3dSmrg	newAdaptor = I810SetupImageVideo(screen);
164428d7b3dSmrg	I810InitOffscreenImages(screen);
165428d7b3dSmrg
166428d7b3dSmrg	if (newAdaptor) {
167428d7b3dSmrg	    XF86VideoAdaptorPtr *newAdaptors;
168428d7b3dSmrg
169428d7b3dSmrg	    newAdaptors =
170428d7b3dSmrg		realloc(adaptors,
171428d7b3dSmrg			(num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr));
172428d7b3dSmrg	    if (newAdaptors != NULL) {
173428d7b3dSmrg		newAdaptors[num_adaptors++] = newAdaptor;
174428d7b3dSmrg		adaptors = newAdaptors;
175428d7b3dSmrg	    }
176428d7b3dSmrg	}
177428d7b3dSmrg    }
178428d7b3dSmrg
179428d7b3dSmrg    if (num_adaptors)
180428d7b3dSmrg	xf86XVScreenInit(screen, adaptors, num_adaptors);
181428d7b3dSmrg
182428d7b3dSmrg    free(adaptors);
183428d7b3dSmrg}
184428d7b3dSmrg
185428d7b3dSmrg/* *INDENT-OFF* */
186428d7b3dSmrg/* client libraries expect an encoding */
187428d7b3dSmrgstatic XF86VideoEncodingRec DummyEncoding[1] =
188428d7b3dSmrg{
189428d7b3dSmrg {
190428d7b3dSmrg   0,
191428d7b3dSmrg   "XV_IMAGE",
192428d7b3dSmrg   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
193428d7b3dSmrg   {1, 1}
194428d7b3dSmrg }
195428d7b3dSmrg};
196428d7b3dSmrg
197428d7b3dSmrg#define NUM_FORMATS 3
198428d7b3dSmrg
199428d7b3dSmrgstatic XF86VideoFormatRec Formats[NUM_FORMATS] =
200428d7b3dSmrg{
201428d7b3dSmrg  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
202428d7b3dSmrg};
203428d7b3dSmrg
204428d7b3dSmrg#define NUM_ATTRIBUTES 3
205428d7b3dSmrg
206428d7b3dSmrgstatic XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
207428d7b3dSmrg{
208428d7b3dSmrg   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
209428d7b3dSmrg   {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
210428d7b3dSmrg   {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
211428d7b3dSmrg};
212428d7b3dSmrg
213428d7b3dSmrg#define NUM_IMAGES 6
214428d7b3dSmrg
215428d7b3dSmrg#define I810_RV15 0x35315652
216428d7b3dSmrg#define I810_RV16 0x36315652
217428d7b3dSmrg
218428d7b3dSmrgstatic XF86ImageRec Images[NUM_IMAGES] =
219428d7b3dSmrg{
220428d7b3dSmrg   {
221428d7b3dSmrg	I810_RV15,
222428d7b3dSmrg        XvRGB,
223428d7b3dSmrg	LSBFirst,
224428d7b3dSmrg	{'R','V','1','5',
225428d7b3dSmrg	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
226428d7b3dSmrg	16,
227428d7b3dSmrg	XvPacked,
228428d7b3dSmrg	1,
229428d7b3dSmrg	15, 0x7C00, 0x03E0, 0x001F,
230428d7b3dSmrg	0, 0, 0,
231428d7b3dSmrg	0, 0, 0,
232428d7b3dSmrg	0, 0, 0,
233428d7b3dSmrg	{'R','V','B',0,
234428d7b3dSmrg	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
235428d7b3dSmrg	XvTopToBottom
236428d7b3dSmrg   },
237428d7b3dSmrg   {
238428d7b3dSmrg	I810_RV16,
239428d7b3dSmrg        XvRGB,
240428d7b3dSmrg	LSBFirst,
241428d7b3dSmrg	{'R','V','1','6',
242428d7b3dSmrg	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
243428d7b3dSmrg	16,
244428d7b3dSmrg	XvPacked,
245428d7b3dSmrg	1,
246428d7b3dSmrg	16, 0xF800, 0x07E0, 0x001F,
247428d7b3dSmrg	0, 0, 0,
248428d7b3dSmrg	0, 0, 0,
249428d7b3dSmrg	0, 0, 0,
250428d7b3dSmrg	{'R','V','B',0,
251428d7b3dSmrg	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
252428d7b3dSmrg	XvTopToBottom
253428d7b3dSmrg   },
254428d7b3dSmrg	XVIMAGE_YUY2,
255428d7b3dSmrg	XVIMAGE_YV12,
256428d7b3dSmrg	XVIMAGE_I420,
257428d7b3dSmrg	XVIMAGE_UYVY
258428d7b3dSmrg};
259428d7b3dSmrg/* *INDENT-ON* */
260428d7b3dSmrg
261428d7b3dSmrgtypedef struct {
262428d7b3dSmrg    uint32_t OBUF_0Y;
263428d7b3dSmrg    uint32_t OBUF_1Y;
264428d7b3dSmrg    uint32_t OBUF_0U;
265428d7b3dSmrg    uint32_t OBUF_0V;
266428d7b3dSmrg    uint32_t OBUF_1U;
267428d7b3dSmrg    uint32_t OBUF_1V;
268428d7b3dSmrg    uint32_t OV0STRIDE;
269428d7b3dSmrg    uint32_t YRGB_VPH;
270428d7b3dSmrg    uint32_t UV_VPH;
271428d7b3dSmrg    uint32_t HORZ_PH;
272428d7b3dSmrg    uint32_t INIT_PH;
273428d7b3dSmrg    uint32_t DWINPOS;
274428d7b3dSmrg    uint32_t DWINSZ;
275428d7b3dSmrg    uint32_t SWID;
276428d7b3dSmrg    uint32_t SWIDQW;
277428d7b3dSmrg    uint32_t SHEIGHT;
278428d7b3dSmrg    uint32_t YRGBSCALE;
279428d7b3dSmrg    uint32_t UVSCALE;
280428d7b3dSmrg    uint32_t OV0CLRC0;
281428d7b3dSmrg    uint32_t OV0CLRC1;
282428d7b3dSmrg    uint32_t DCLRKV;
283428d7b3dSmrg    uint32_t DCLRKM;
284428d7b3dSmrg    uint32_t SCLRKVH;
285428d7b3dSmrg    uint32_t SCLRKVL;
286428d7b3dSmrg    uint32_t SCLRKM;
287428d7b3dSmrg    uint32_t OV0CONF;
288428d7b3dSmrg    uint32_t OV0CMD;
289428d7b3dSmrg} I810OverlayRegRec, *I810OverlayRegPtr;
290428d7b3dSmrg
291428d7b3dSmrgtypedef struct {
292428d7b3dSmrg	uint32_t     YBuf0offset;
293428d7b3dSmrg	uint32_t     UBuf0offset;
294428d7b3dSmrg	uint32_t     VBuf0offset;
295428d7b3dSmrg
296428d7b3dSmrg	uint32_t     YBuf1offset;
297428d7b3dSmrg	uint32_t     UBuf1offset;
298428d7b3dSmrg	uint32_t     VBuf1offset;
299428d7b3dSmrg
300428d7b3dSmrg	unsigned char currentBuf;
301428d7b3dSmrg
302428d7b3dSmrg	int          brightness;
303428d7b3dSmrg	int          contrast;
304428d7b3dSmrg
305428d7b3dSmrg	RegionRec    clip;
306428d7b3dSmrg	uint32_t     colorKey;
307428d7b3dSmrg
308428d7b3dSmrg	uint32_t     videoStatus;
309428d7b3dSmrg	Time         offTime;
310428d7b3dSmrg	Time         freeTime;
311428d7b3dSmrg	FBLinearPtr  linear;
312428d7b3dSmrg} I810PortPrivRec, *I810PortPrivPtr;
313428d7b3dSmrg
314428d7b3dSmrg#define GET_PORT_PRIVATE(pScrn) \
315428d7b3dSmrg   (I810PortPrivPtr)((I810PTR(pScrn))->adaptor->pPortPrivates[0].ptr)
316428d7b3dSmrg
317428d7b3dSmrgstatic void I810ResetVideo(ScrnInfoPtr pScrn)
318428d7b3dSmrg{
319428d7b3dSmrg    I810Ptr pI810 = I810PTR(pScrn);
320428d7b3dSmrg    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
321428d7b3dSmrg    I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
322428d7b3dSmrg
323428d7b3dSmrg    /*
324428d7b3dSmrg     * Default to maximum image size in YV12
325428d7b3dSmrg     */
326428d7b3dSmrg
327428d7b3dSmrg    overlay->YRGB_VPH = 0;
328428d7b3dSmrg    overlay->UV_VPH = 0;
329428d7b3dSmrg    overlay->HORZ_PH = 0;
330428d7b3dSmrg    overlay->INIT_PH = 0;
331428d7b3dSmrg    overlay->DWINPOS = 0;
332428d7b3dSmrg    overlay->DWINSZ = (IMAGE_MAX_HEIGHT << 16) | IMAGE_MAX_WIDTH;
333428d7b3dSmrg    overlay->SWID =  IMAGE_MAX_WIDTH | (IMAGE_MAX_WIDTH << 15);
334428d7b3dSmrg    overlay->SWIDQW = (IMAGE_MAX_WIDTH >> 3) | (IMAGE_MAX_WIDTH << 12);
335428d7b3dSmrg    overlay->SHEIGHT = IMAGE_MAX_HEIGHT | (IMAGE_MAX_HEIGHT << 15);
336428d7b3dSmrg    overlay->YRGBSCALE = 0x80004000; /* scale factor 1 */
337428d7b3dSmrg    overlay->UVSCALE = 0x80004000; /* scale factor 1 */
338428d7b3dSmrg    overlay->OV0CLRC0 = 0x4000; /* brightness: 0 contrast: 1.0 */
339428d7b3dSmrg    overlay->OV0CLRC1 = 0x80; /* saturation: bypass */
340428d7b3dSmrg
341428d7b3dSmrg    /*
342428d7b3dSmrg     * Enable destination color keying
343428d7b3dSmrg     */
344428d7b3dSmrg    switch(pScrn->depth) {
345428d7b3dSmrg    case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
346428d7b3dSmrg             overlay->DCLRKM = 0x80070307;
347428d7b3dSmrg             break;
348428d7b3dSmrg    case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
349428d7b3dSmrg             overlay->DCLRKM = 0x80070707;
350428d7b3dSmrg             break;
351428d7b3dSmrg    default: overlay->DCLRKV = pPriv->colorKey;
352428d7b3dSmrg             overlay->DCLRKM = 0x80000000;
353428d7b3dSmrg             break;
354428d7b3dSmrg    }
355428d7b3dSmrg
356428d7b3dSmrg    overlay->SCLRKVH = 0;
357428d7b3dSmrg    overlay->SCLRKVL = 0;
358428d7b3dSmrg    overlay->SCLRKM = 0; /* source color key disable */
359428d7b3dSmrg    overlay->OV0CONF = 0; /* two 720 pixel line buffers */
360428d7b3dSmrg
361428d7b3dSmrg    overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST |
362428d7b3dSmrg		      YUV_420;
363428d7b3dSmrg
364428d7b3dSmrg    OVERLAY_UPDATE(pI810->OverlayPhysical);
365428d7b3dSmrg}
366428d7b3dSmrg
367428d7b3dSmrg
368428d7b3dSmrgstatic XF86VideoAdaptorPtr
369428d7b3dSmrgI810SetupImageVideo(ScreenPtr screen)
370428d7b3dSmrg{
371428d7b3dSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
372428d7b3dSmrg    I810Ptr pI810 = I810PTR(pScrn);
373428d7b3dSmrg    XF86VideoAdaptorPtr adapt;
374428d7b3dSmrg    I810PortPrivPtr pPriv;
375428d7b3dSmrg
376428d7b3dSmrg    if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
377428d7b3dSmrg			    sizeof(I810PortPrivRec) +
378428d7b3dSmrg			    sizeof(DevUnion))))
379428d7b3dSmrg	return NULL;
380428d7b3dSmrg
381428d7b3dSmrg    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
382428d7b3dSmrg    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
383428d7b3dSmrg    adapt->name = "I810 Video Overlay";
384428d7b3dSmrg    adapt->nEncodings = 1;
385428d7b3dSmrg    adapt->pEncodings = DummyEncoding;
386428d7b3dSmrg    adapt->nFormats = NUM_FORMATS;
387428d7b3dSmrg    adapt->pFormats = Formats;
388428d7b3dSmrg    adapt->nPorts = 1;
389428d7b3dSmrg    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
390428d7b3dSmrg
391428d7b3dSmrg    pPriv = (I810PortPrivPtr)(&adapt->pPortPrivates[1]);
392428d7b3dSmrg
393428d7b3dSmrg    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
394428d7b3dSmrg    adapt->pAttributes = Attributes;
395428d7b3dSmrg    adapt->nImages = NUM_IMAGES;
396428d7b3dSmrg    adapt->nAttributes = NUM_ATTRIBUTES;
397428d7b3dSmrg    adapt->pImages = Images;
398428d7b3dSmrg    adapt->PutVideo = NULL;
399428d7b3dSmrg    adapt->PutStill = NULL;
400428d7b3dSmrg    adapt->GetVideo = NULL;
401428d7b3dSmrg    adapt->GetStill = NULL;
402428d7b3dSmrg    adapt->StopVideo = I810StopVideo;
403428d7b3dSmrg    adapt->SetPortAttribute = I810SetPortAttribute;
404428d7b3dSmrg    adapt->GetPortAttribute = I810GetPortAttribute;
405428d7b3dSmrg    adapt->QueryBestSize = I810QueryBestSize;
406428d7b3dSmrg    adapt->PutImage = I810PutImage;
407428d7b3dSmrg    adapt->QueryImageAttributes = I810QueryImageAttributes;
408428d7b3dSmrg
409428d7b3dSmrg    pPriv->colorKey = pI810->colorKey & ((1 << pScrn->depth) - 1);
410428d7b3dSmrg    pPriv->videoStatus = 0;
411428d7b3dSmrg    pPriv->brightness = 0;
412428d7b3dSmrg    pPriv->contrast = 64;
413428d7b3dSmrg    pPriv->linear = NULL;
414428d7b3dSmrg    pPriv->currentBuf = 0;
415428d7b3dSmrg
416428d7b3dSmrg    /* gotta uninit this someplace */
417428d7b3dSmrg    REGION_NULL(screen, &pPriv->clip);
418428d7b3dSmrg
419428d7b3dSmrg    pI810->adaptor = adapt;
420428d7b3dSmrg
421428d7b3dSmrg    pI810->BlockHandler = screen->BlockHandler;
422428d7b3dSmrg    screen->BlockHandler = I810BlockHandler;
423428d7b3dSmrg
424428d7b3dSmrg    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
425428d7b3dSmrg    xvContrast   = MAKE_ATOM("XV_CONTRAST");
426428d7b3dSmrg    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
427428d7b3dSmrg
428428d7b3dSmrg    I810ResetVideo(pScrn);
429428d7b3dSmrg
430428d7b3dSmrg    return adapt;
431428d7b3dSmrg}
432428d7b3dSmrg
433428d7b3dSmrg
434428d7b3dSmrg/* I810ClipVideo -
435428d7b3dSmrg
436428d7b3dSmrg   Takes the dst box in standard X BoxRec form (top and left
437428d7b3dSmrg   edges inclusive, bottom and right exclusive).  The new dst
438428d7b3dSmrg   box is returned.  The source boundaries are given (x1, y1
439428d7b3dSmrg   inclusive, x2, y2 exclusive) and returned are the new source
440428d7b3dSmrg   boundaries in 16.16 fixed point.
441428d7b3dSmrg*/
442428d7b3dSmrg
443428d7b3dSmrgstatic void
444428d7b3dSmrgI810ClipVideo(
445428d7b3dSmrg  BoxPtr dst,
446428d7b3dSmrg  INT32 *x1,
447428d7b3dSmrg  INT32 *x2,
448428d7b3dSmrg  INT32 *y1,
449428d7b3dSmrg  INT32 *y2,
450428d7b3dSmrg  BoxPtr extents,            /* extents of the clip region */
451428d7b3dSmrg  INT32 width,
452428d7b3dSmrg  INT32 height
453428d7b3dSmrg){
454428d7b3dSmrg    INT32 vscale, hscale, delta;
455428d7b3dSmrg    int diff;
456428d7b3dSmrg
457428d7b3dSmrg    hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
458428d7b3dSmrg    vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
459428d7b3dSmrg
460428d7b3dSmrg    *x1 <<= 16; *x2 <<= 16;
461428d7b3dSmrg    *y1 <<= 16; *y2 <<= 16;
462428d7b3dSmrg
463428d7b3dSmrg    diff = extents->x1 - dst->x1;
464428d7b3dSmrg    if(diff > 0) {
465428d7b3dSmrg	dst->x1 = extents->x1;
466428d7b3dSmrg	*x1 += diff * hscale;
467428d7b3dSmrg    }
468428d7b3dSmrg    diff = dst->x2 - extents->x2;
469428d7b3dSmrg    if(diff > 0) {
470428d7b3dSmrg	dst->x2 = extents->x2;
471428d7b3dSmrg	*x2 -= diff * hscale;
472428d7b3dSmrg    }
473428d7b3dSmrg    diff = extents->y1 - dst->y1;
474428d7b3dSmrg    if(diff > 0) {
475428d7b3dSmrg	dst->y1 = extents->y1;
476428d7b3dSmrg	*y1 += diff * vscale;
477428d7b3dSmrg    }
478428d7b3dSmrg    diff = dst->y2 - extents->y2;
479428d7b3dSmrg    if(diff > 0) {
480428d7b3dSmrg	dst->y2 = extents->y2;
481428d7b3dSmrg	*y2 -= diff * vscale;
482428d7b3dSmrg    }
483428d7b3dSmrg
484428d7b3dSmrg    if(*x1 < 0) {
485428d7b3dSmrg	diff =  (- *x1 + hscale - 1)/ hscale;
486428d7b3dSmrg	dst->x1 += diff;
487428d7b3dSmrg	*x1 += diff * hscale;
488428d7b3dSmrg    }
489428d7b3dSmrg    delta = *x2 - (width << 16);
490428d7b3dSmrg    if(delta > 0) {
491428d7b3dSmrg	diff = (delta + hscale - 1)/ hscale;
492428d7b3dSmrg	dst->x2 -= diff;
493428d7b3dSmrg	*x2 -= diff * hscale;
494428d7b3dSmrg    }
495428d7b3dSmrg    if(*y1 < 0) {
496428d7b3dSmrg	diff =  (- *y1 + vscale - 1)/ vscale;
497428d7b3dSmrg	dst->y1 += diff;
498428d7b3dSmrg	*y1 += diff * vscale;
499428d7b3dSmrg    }
500428d7b3dSmrg    delta = *y2 - (height << 16);
501428d7b3dSmrg    if(delta > 0) {
502428d7b3dSmrg	diff = (delta + vscale - 1)/ vscale;
503428d7b3dSmrg	dst->y2 -= diff;
504428d7b3dSmrg	*y2 -= diff * vscale;
505428d7b3dSmrg    }
506428d7b3dSmrg}
507428d7b3dSmrg
508428d7b3dSmrgstatic void
509428d7b3dSmrgI810StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
510428d7b3dSmrg{
511428d7b3dSmrg  I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
512428d7b3dSmrg  I810Ptr pI810 = I810PTR(pScrn);
513428d7b3dSmrg
514428d7b3dSmrg  I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
515428d7b3dSmrg
516428d7b3dSmrg  REGION_EMPTY(pScrn->screen, &pPriv->clip);
517428d7b3dSmrg
518428d7b3dSmrg  if(shutdown) {
519428d7b3dSmrg     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
520428d7b3dSmrg	overlay->OV0CMD &= 0xFFFFFFFE;
521428d7b3dSmrg	OVERLAY_UPDATE(pI810->OverlayPhysical);
522428d7b3dSmrg     }
523428d7b3dSmrg     if(pPriv->linear) {
524428d7b3dSmrg	xf86FreeOffscreenLinear(pPriv->linear);
525428d7b3dSmrg	pPriv->linear = NULL;
526428d7b3dSmrg     }
527428d7b3dSmrg     pPriv->videoStatus = 0;
528428d7b3dSmrg  } else {
529428d7b3dSmrg     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
530428d7b3dSmrg	pPriv->videoStatus |= OFF_TIMER;
531428d7b3dSmrg	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
532428d7b3dSmrg     }
533428d7b3dSmrg  }
534428d7b3dSmrg
535428d7b3dSmrg}
536428d7b3dSmrg
537428d7b3dSmrgstatic int
538428d7b3dSmrgI810SetPortAttribute(
539428d7b3dSmrg  ScrnInfoPtr pScrn,
540428d7b3dSmrg  Atom attribute,
541428d7b3dSmrg  INT32 value,
542428d7b3dSmrg  pointer data
543428d7b3dSmrg){
544428d7b3dSmrg  I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
545428d7b3dSmrg  I810Ptr pI810 = I810PTR(pScrn);
546428d7b3dSmrg  I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
547428d7b3dSmrg
548428d7b3dSmrg  if(attribute == xvBrightness) {
549428d7b3dSmrg	if((value < -128) || (value > 127))
550428d7b3dSmrg	   return BadValue;
551428d7b3dSmrg	pPriv->brightness = value;
552428d7b3dSmrg	overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff);
553428d7b3dSmrg	OVERLAY_UPDATE(pI810->OverlayPhysical);
554428d7b3dSmrg  } else
555428d7b3dSmrg  if(attribute == xvContrast) {
556428d7b3dSmrg	if((value < 0) || (value > 255))
557428d7b3dSmrg	   return BadValue;
558428d7b3dSmrg	pPriv->contrast = value;
559428d7b3dSmrg	overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff);
560428d7b3dSmrg	OVERLAY_UPDATE(pI810->OverlayPhysical);
561428d7b3dSmrg  } else
562428d7b3dSmrg  if(attribute == xvColorKey) {
563428d7b3dSmrg	pPriv->colorKey = value;
564428d7b3dSmrg	switch(pScrn->depth) {
565428d7b3dSmrg	case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
566428d7b3dSmrg	         break;
567428d7b3dSmrg	case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
568428d7b3dSmrg                 break;
569428d7b3dSmrg	default: overlay->DCLRKV = pPriv->colorKey;
570428d7b3dSmrg                 break;
571428d7b3dSmrg	}
572428d7b3dSmrg	OVERLAY_UPDATE(pI810->OverlayPhysical);
573428d7b3dSmrg	REGION_EMPTY(pScrn->screen, &pPriv->clip);
574428d7b3dSmrg  } else return BadMatch;
575428d7b3dSmrg
576428d7b3dSmrg  return Success;
577428d7b3dSmrg}
578428d7b3dSmrg
579428d7b3dSmrgstatic int
580428d7b3dSmrgI810GetPortAttribute(
581428d7b3dSmrg  ScrnInfoPtr pScrn,
582428d7b3dSmrg  Atom attribute,
583428d7b3dSmrg  INT32 *value,
584428d7b3dSmrg  pointer data
585428d7b3dSmrg){
586428d7b3dSmrg  I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
587428d7b3dSmrg
588428d7b3dSmrg  if(attribute == xvBrightness) {
589428d7b3dSmrg	*value = pPriv->brightness;
590428d7b3dSmrg  } else
591428d7b3dSmrg  if(attribute == xvContrast) {
592428d7b3dSmrg	*value = pPriv->contrast;
593428d7b3dSmrg  } else
594428d7b3dSmrg  if(attribute == xvColorKey) {
595428d7b3dSmrg	*value = pPriv->colorKey;
596428d7b3dSmrg  } else return BadMatch;
597428d7b3dSmrg
598428d7b3dSmrg  return Success;
599428d7b3dSmrg}
600428d7b3dSmrg
601428d7b3dSmrgstatic void
602428d7b3dSmrgI810QueryBestSize(
603428d7b3dSmrg  ScrnInfoPtr pScrn,
604428d7b3dSmrg  Bool motion,
605428d7b3dSmrg  short vid_w, short vid_h,
606428d7b3dSmrg  short drw_w, short drw_h,
607428d7b3dSmrg  unsigned int *p_w, unsigned int *p_h,
608428d7b3dSmrg  pointer data
609428d7b3dSmrg){
610428d7b3dSmrg   if(vid_w > (drw_w << 1)) drw_w = vid_w >> 1;
611428d7b3dSmrg   if(vid_h > (drw_h << 1)) drw_h = vid_h >> 1;
612428d7b3dSmrg
613428d7b3dSmrg  *p_w = drw_w;
614428d7b3dSmrg  *p_h = drw_h;
615428d7b3dSmrg}
616428d7b3dSmrg
617428d7b3dSmrg
618428d7b3dSmrgstatic void
619428d7b3dSmrgI810CopyPackedData(
620428d7b3dSmrg   ScrnInfoPtr pScrn,
621428d7b3dSmrg   unsigned char *buf,
622428d7b3dSmrg   int srcPitch,
623428d7b3dSmrg   int dstPitch,
624428d7b3dSmrg   int top,
625428d7b3dSmrg   int left,
626428d7b3dSmrg   int h,
627428d7b3dSmrg   int w
628428d7b3dSmrg   )
629428d7b3dSmrg{
630428d7b3dSmrg    I810Ptr pI810 = I810PTR(pScrn);
631428d7b3dSmrg    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
632428d7b3dSmrg    unsigned char *src, *dst;
633428d7b3dSmrg
634428d7b3dSmrg    src = buf + (top*srcPitch) + (left<<1);
635428d7b3dSmrg
636428d7b3dSmrg    if (pPriv->currentBuf == 0)
637428d7b3dSmrg	dst = pI810->FbBase + pPriv->YBuf0offset;
638428d7b3dSmrg    else
639428d7b3dSmrg	dst = pI810->FbBase + pPriv->YBuf1offset;
640428d7b3dSmrg
641428d7b3dSmrg    w <<= 1;
642428d7b3dSmrg    while(h--) {
643428d7b3dSmrg	memcpy(dst, src, w);
644428d7b3dSmrg	src += srcPitch;
645428d7b3dSmrg	dst += dstPitch;
646428d7b3dSmrg    }
647428d7b3dSmrg}
648428d7b3dSmrg
649428d7b3dSmrgstatic void
650428d7b3dSmrgI810CopyPlanarData(
651428d7b3dSmrg   ScrnInfoPtr pScrn,
652428d7b3dSmrg   unsigned char *buf,
653428d7b3dSmrg   int srcPitch,
654428d7b3dSmrg   int dstPitch,  /* of chroma */
655428d7b3dSmrg   int srcH,
656428d7b3dSmrg   int top,
657428d7b3dSmrg   int left,
658428d7b3dSmrg   int h,
659428d7b3dSmrg   int w,
660428d7b3dSmrg   int id
661428d7b3dSmrg   )
662428d7b3dSmrg{
663428d7b3dSmrg    I810Ptr pI810 = I810PTR(pScrn);
664428d7b3dSmrg    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
665428d7b3dSmrg    int i;
666428d7b3dSmrg    unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3;
667428d7b3dSmrg
668428d7b3dSmrg    /* Copy Y data */
669428d7b3dSmrg    src1 = buf + (top*srcPitch) + left;
670428d7b3dSmrg    if (pPriv->currentBuf == 0)
671428d7b3dSmrg	dst1 = pI810->FbBase + pPriv->YBuf0offset;
672428d7b3dSmrg    else
673428d7b3dSmrg	dst1 = pI810->FbBase + pPriv->YBuf1offset;
674428d7b3dSmrg
675428d7b3dSmrg    for (i = 0; i < h; i++) {
676428d7b3dSmrg	memcpy(dst1, src1, w);
677428d7b3dSmrg	src1 += srcPitch;
678428d7b3dSmrg	dst1 += dstPitch << 1;
679428d7b3dSmrg    }
680428d7b3dSmrg
681428d7b3dSmrg    /* Copy V data for YV12, or U data for I420 */
682428d7b3dSmrg    src2 = buf + (srcH*srcPitch) + ((top*srcPitch)>>2) + (left>>1);
683428d7b3dSmrg    if (pPriv->currentBuf == 0) {
684428d7b3dSmrg	if (id == FOURCC_I420)
685428d7b3dSmrg	    dst2 = pI810->FbBase + pPriv->UBuf0offset;
686428d7b3dSmrg	else
687428d7b3dSmrg	    dst2 = pI810->FbBase + pPriv->VBuf0offset;
688428d7b3dSmrg    } else {
689428d7b3dSmrg	if (id == FOURCC_I420)
690428d7b3dSmrg	    dst2 = pI810->FbBase + pPriv->UBuf1offset;
691428d7b3dSmrg	else
692428d7b3dSmrg	    dst2 = pI810->FbBase + pPriv->VBuf1offset;
693428d7b3dSmrg    }
694428d7b3dSmrg
695428d7b3dSmrg    for (i = 0; i < h/2; i++) {
696428d7b3dSmrg	memcpy(dst2, src2, w/2);
697428d7b3dSmrg	src2 += srcPitch>>1;
698428d7b3dSmrg	dst2 += dstPitch;
699428d7b3dSmrg    }
700428d7b3dSmrg
701428d7b3dSmrg    /* Copy U data for YV12, or V data for I420 */
702428d7b3dSmrg    src3 = buf + (srcH*srcPitch) + ((srcH*srcPitch)>>2) + ((top*srcPitch)>>2) + (left>>1);
703428d7b3dSmrg    if (pPriv->currentBuf == 0) {
704428d7b3dSmrg	if (id == FOURCC_I420)
705428d7b3dSmrg	    dst3 = pI810->FbBase + pPriv->VBuf0offset;
706428d7b3dSmrg	else
707428d7b3dSmrg	    dst3 = pI810->FbBase + pPriv->UBuf0offset;
708428d7b3dSmrg    } else {
709428d7b3dSmrg	if (id == FOURCC_I420)
710428d7b3dSmrg	    dst3 = pI810->FbBase + pPriv->VBuf1offset;
711428d7b3dSmrg	else
712428d7b3dSmrg	    dst3 = pI810->FbBase + pPriv->UBuf1offset;
713428d7b3dSmrg    }
714428d7b3dSmrg
715428d7b3dSmrg    for (i = 0; i < h/2; i++) {
716428d7b3dSmrg	memcpy(dst3, src3, w/2);
717428d7b3dSmrg	src3 += srcPitch>>1;
718428d7b3dSmrg	dst3 += dstPitch;
719428d7b3dSmrg    }
720428d7b3dSmrg}
721428d7b3dSmrg
722428d7b3dSmrgstatic void
723428d7b3dSmrgI810DisplayVideo(
724428d7b3dSmrg    ScrnInfoPtr pScrn,
725428d7b3dSmrg    int id,
726428d7b3dSmrg    short width, short height,
727428d7b3dSmrg    int dstPitch,  /* of chroma for 4:2:0 */
728428d7b3dSmrg    int x1, int y1, int x2, int y2,
729428d7b3dSmrg    BoxPtr dstBox,
730428d7b3dSmrg    short src_w, short src_h,
731428d7b3dSmrg    short drw_w, short drw_h
732428d7b3dSmrg){
733428d7b3dSmrg    I810Ptr pI810 = I810PTR(pScrn);
734428d7b3dSmrg    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
735428d7b3dSmrg    I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
736428d7b3dSmrg    int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
737428d7b3dSmrg    int xscaleIntUV = 0, xscaleFractUV = 0, yscaleIntUV = 0, yscaleFractUV = 0;
738428d7b3dSmrg    unsigned int swidth;
739428d7b3dSmrg
740428d7b3dSmrg    switch(id) {
741428d7b3dSmrg    case FOURCC_YV12:
742428d7b3dSmrg    case FOURCC_I420:
743428d7b3dSmrg	swidth = ALIGN(width, 8);
744428d7b3dSmrg	overlay->SWID = (swidth << 15) | swidth;
745428d7b3dSmrg	overlay->SWIDQW = (swidth << 12) | (swidth >> 3);
746428d7b3dSmrg	break;
747428d7b3dSmrg    case FOURCC_UYVY:
748428d7b3dSmrg    case FOURCC_YUY2:
749428d7b3dSmrg    default:
750428d7b3dSmrg	swidth = ALIGN(width, 4) << 1;
751428d7b3dSmrg	overlay->SWID = swidth;
752428d7b3dSmrg	overlay->SWIDQW = swidth >> 3;
753428d7b3dSmrg	break;
754428d7b3dSmrg    }
755428d7b3dSmrg
756428d7b3dSmrg    /* wide video formats (>720 pixels) are special */
757428d7b3dSmrg    if( swidth > IMAGE_FAST_WIDTH ) {
758428d7b3dSmrg	overlay->OV0CONF = 1; /* one 1440 pixel line buffer */
759428d7b3dSmrg    } else {
760428d7b3dSmrg	overlay->OV0CONF = 0; /* two 720 pixel line buffers */
761428d7b3dSmrg    }
762428d7b3dSmrg
763428d7b3dSmrg    overlay->SHEIGHT = height | (height << 15);
764428d7b3dSmrg    overlay->DWINPOS = (dstBox->y1 << 16) | (dstBox->x1);
765428d7b3dSmrg    overlay->DWINSZ = ((dstBox->y2 - dstBox->y1) << 16) |
766428d7b3dSmrg	              (dstBox->x2 - dstBox->x1);
767428d7b3dSmrg
768428d7b3dSmrg    /* buffer locations */
769428d7b3dSmrg    overlay->OBUF_0Y = pPriv->YBuf0offset;
770428d7b3dSmrg    overlay->OBUF_1Y = pPriv->YBuf1offset;
771428d7b3dSmrg    overlay->OBUF_0U = pPriv->UBuf0offset;
772428d7b3dSmrg    overlay->OBUF_0V = pPriv->VBuf0offset;
773428d7b3dSmrg    overlay->OBUF_1U = pPriv->UBuf1offset;
774428d7b3dSmrg    overlay->OBUF_1V = pPriv->VBuf1offset;
775428d7b3dSmrg
776428d7b3dSmrg    /*
777428d7b3dSmrg     * Calculate horizontal and vertical scaling factors, default to 1:1
778428d7b3dSmrg     */
779428d7b3dSmrg    overlay->YRGBSCALE = 0x80004000;
780428d7b3dSmrg    overlay->UVSCALE = 0x80004000;
781428d7b3dSmrg
782428d7b3dSmrg    /*
783428d7b3dSmrg     * Initially, YCbCr and Overlay Enable and
784428d7b3dSmrg     * vertical chrominance up interpolation and horozontal chrominance
785428d7b3dSmrg     * up interpolation
786428d7b3dSmrg     */
787428d7b3dSmrg    overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST |
788428d7b3dSmrg	              OVERLAY_ENABLE;
789428d7b3dSmrg
790428d7b3dSmrg    if ((drw_w != src_w) || (drw_h != src_h))
791428d7b3dSmrg    {
792428d7b3dSmrg	xscaleInt = (src_w / drw_w) & 0x3;
793428d7b3dSmrg	xscaleFract = (src_w << 12) / drw_w;
794428d7b3dSmrg	yscaleInt = (src_h / drw_h) & 0x3;
795428d7b3dSmrg	yscaleFract = (src_h << 12) / drw_h;
796428d7b3dSmrg
797428d7b3dSmrg	overlay->YRGBSCALE = (xscaleInt << 15) |
798428d7b3dSmrg	                     ((xscaleFract & 0xFFF) << 3) |
799428d7b3dSmrg	                     (yscaleInt) |
800428d7b3dSmrg			     ((yscaleFract & 0xFFF) << 20);
801428d7b3dSmrg
802428d7b3dSmrg	if (drw_w > src_w)
803428d7b3dSmrg	{
804428d7b3dSmrg	    /* horizontal up-scaling */
805428d7b3dSmrg	    overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER;
806428d7b3dSmrg	    overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER;
807428d7b3dSmrg	    overlay->OV0CMD |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION);
808428d7b3dSmrg	}
809428d7b3dSmrg
810428d7b3dSmrg	if (drw_h > src_h)
811428d7b3dSmrg	{
812428d7b3dSmrg	    /* vertical up-scaling */
813428d7b3dSmrg	    overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER;
814428d7b3dSmrg	    overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER;
815428d7b3dSmrg	    overlay->OV0CMD |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION);
816428d7b3dSmrg	}
817428d7b3dSmrg
818428d7b3dSmrg	if (drw_w < src_w)
819428d7b3dSmrg	{
820428d7b3dSmrg	    /* horizontal down-scaling */
821428d7b3dSmrg	    overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER;
822428d7b3dSmrg	    overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER;
823428d7b3dSmrg	    overlay->OV0CMD |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION);
824428d7b3dSmrg	}
825428d7b3dSmrg
826428d7b3dSmrg	if (drw_h < src_h)
827428d7b3dSmrg	{
828428d7b3dSmrg	    /* vertical down-scaling */
829428d7b3dSmrg	    overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER;
830428d7b3dSmrg	    overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER;
831428d7b3dSmrg	    overlay->OV0CMD |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION);
832428d7b3dSmrg	}
833428d7b3dSmrg
834428d7b3dSmrg	/* now calculate the UV scaling factor */
835428d7b3dSmrg
836428d7b3dSmrg	if (xscaleFract)
837428d7b3dSmrg	{
838428d7b3dSmrg	    xscaleFractUV = xscaleFract >> MINUV_SCALE;
839428d7b3dSmrg	    overlay->OV0CMD &= ~HC_DOWN_INTERPOLATION;
840428d7b3dSmrg	    overlay->OV0CMD |= HC_UP_INTERPOLATION;
841428d7b3dSmrg	}
842428d7b3dSmrg
843428d7b3dSmrg	if (xscaleInt)
844428d7b3dSmrg	{
845428d7b3dSmrg	    xscaleIntUV = xscaleInt >> MINUV_SCALE;
846428d7b3dSmrg	    if (xscaleIntUV)
847428d7b3dSmrg	    {
848428d7b3dSmrg		overlay->OV0CMD &= ~HC_UP_INTERPOLATION;
849428d7b3dSmrg	    }
850428d7b3dSmrg	}
851428d7b3dSmrg
852428d7b3dSmrg	if (yscaleFract)
853428d7b3dSmrg	{
854428d7b3dSmrg	    yscaleFractUV = yscaleFract >> MINUV_SCALE;
855428d7b3dSmrg	    overlay->OV0CMD &= ~VC_DOWN_INTERPOLATION;
856428d7b3dSmrg	    overlay->OV0CMD |= VC_UP_INTERPOLATION;
857428d7b3dSmrg	}
858428d7b3dSmrg
859428d7b3dSmrg	if (yscaleInt)
860428d7b3dSmrg	{
861428d7b3dSmrg	    yscaleIntUV = yscaleInt >> MINUV_SCALE;
862428d7b3dSmrg	    if (yscaleIntUV)
863428d7b3dSmrg	    {
864428d7b3dSmrg		overlay->OV0CMD &= ~VC_UP_INTERPOLATION;
865428d7b3dSmrg		overlay->OV0CMD |= VC_DOWN_INTERPOLATION;
866428d7b3dSmrg	    }
867428d7b3dSmrg	}
868428d7b3dSmrg
869428d7b3dSmrg	overlay->UVSCALE = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) |
870428d7b3dSmrg	                   ((yscaleFractUV & 0xFFF) << 20);
871428d7b3dSmrg    }
872428d7b3dSmrg
873428d7b3dSmrg    switch(id) {
874428d7b3dSmrg    case FOURCC_YV12:
875428d7b3dSmrg    case FOURCC_I420:
876428d7b3dSmrg	/* set UV vertical phase to -0.25 */
877428d7b3dSmrg	overlay->UV_VPH = 0x30003000;
878428d7b3dSmrg	overlay->INIT_PH = UV_VERT_BUF0 | UV_VERT_BUF1;
879428d7b3dSmrg	overlay->OV0STRIDE = (dstPitch << 1) | (dstPitch << 16);
880428d7b3dSmrg	overlay->OV0CMD &= ~SOURCE_FORMAT;
881428d7b3dSmrg	overlay->OV0CMD |= YUV_420;
882428d7b3dSmrg	break;
883428d7b3dSmrg    case I810_RV15:
884428d7b3dSmrg    case I810_RV16:
885428d7b3dSmrg	overlay->UV_VPH = 0;
886428d7b3dSmrg	overlay->INIT_PH = 0;
887428d7b3dSmrg	overlay->OV0STRIDE = dstPitch;
888428d7b3dSmrg	overlay->OV0CMD &= ~SOURCE_FORMAT;
889428d7b3dSmrg	overlay->OV0CMD |= (id==I810_RV15 ? RGB_555 : RGB_565);
890428d7b3dSmrg	overlay->OV0CMD &= ~OV_BYTE_ORDER;
891428d7b3dSmrg	break;
892428d7b3dSmrg    case FOURCC_UYVY:
893428d7b3dSmrg    case FOURCC_YUY2:
894428d7b3dSmrg    default:
895428d7b3dSmrg	overlay->UV_VPH = 0;
896428d7b3dSmrg	overlay->INIT_PH = 0;
897428d7b3dSmrg	overlay->OV0STRIDE = dstPitch;
898428d7b3dSmrg	overlay->OV0CMD &= ~SOURCE_FORMAT;
899428d7b3dSmrg	overlay->OV0CMD |= YUV_422;
900428d7b3dSmrg	overlay->OV0CMD &= ~OV_BYTE_ORDER;
901428d7b3dSmrg	if (id == FOURCC_UYVY)
902428d7b3dSmrg	    overlay->OV0CMD |= Y_SWAP;
903428d7b3dSmrg	break;
904428d7b3dSmrg    }
905428d7b3dSmrg
906428d7b3dSmrg    overlay->OV0CMD &= ~BUFFER_AND_FIELD;
907428d7b3dSmrg    if (pPriv->currentBuf == 0)
908428d7b3dSmrg	overlay->OV0CMD |= BUFFER0_FIELD0;
909428d7b3dSmrg    else
910428d7b3dSmrg	overlay->OV0CMD |= BUFFER1_FIELD0;
911428d7b3dSmrg
912428d7b3dSmrg    OVERLAY_UPDATE(pI810->OverlayPhysical);
913428d7b3dSmrg
914428d7b3dSmrg}
915428d7b3dSmrg
916428d7b3dSmrgstatic FBLinearPtr
917428d7b3dSmrgI810AllocateMemory(
918428d7b3dSmrg  ScrnInfoPtr pScrn,
919428d7b3dSmrg  FBLinearPtr linear,
920428d7b3dSmrg  int size
921428d7b3dSmrg){
922428d7b3dSmrg   ScreenPtr screen;
923428d7b3dSmrg   FBLinearPtr new_linear;
924428d7b3dSmrg
925428d7b3dSmrg   if(linear) {
926428d7b3dSmrg	if(linear->size >= size)
927428d7b3dSmrg	   return linear;
928428d7b3dSmrg
929428d7b3dSmrg	if(xf86ResizeOffscreenLinear(linear, size))
930428d7b3dSmrg	   return linear;
931428d7b3dSmrg
932428d7b3dSmrg	xf86FreeOffscreenLinear(linear);
933428d7b3dSmrg   }
934428d7b3dSmrg
935428d7b3dSmrg   screen = xf86ScrnToScreen(pScrn);
936428d7b3dSmrg
937428d7b3dSmrg   new_linear = xf86AllocateOffscreenLinear(screen, size, 4,
938428d7b3dSmrg                                            NULL, NULL, NULL);
939428d7b3dSmrg
940428d7b3dSmrg   if(!new_linear) {
941428d7b3dSmrg        int max_size;
942428d7b3dSmrg
943428d7b3dSmrg        xf86QueryLargestOffscreenLinear(screen, &max_size, 4,
944428d7b3dSmrg				       PRIORITY_EXTREME);
945428d7b3dSmrg
946428d7b3dSmrg        if(max_size < size) return NULL;
947428d7b3dSmrg
948428d7b3dSmrg        xf86PurgeUnlockedOffscreenAreas(screen);
949428d7b3dSmrg        new_linear = xf86AllocateOffscreenLinear(screen, size, 4,
950428d7b3dSmrg                                                 NULL, NULL, NULL);
951428d7b3dSmrg   }
952428d7b3dSmrg
953428d7b3dSmrg   return new_linear;
954428d7b3dSmrg}
955428d7b3dSmrg
956428d7b3dSmrgstatic int
957428d7b3dSmrgI810PutImage(
958428d7b3dSmrg  ScrnInfoPtr pScrn,
959428d7b3dSmrg  short src_x, short src_y,
960428d7b3dSmrg  short drw_x, short drw_y,
961428d7b3dSmrg  short src_w, short src_h,
962428d7b3dSmrg  short drw_w, short drw_h,
963428d7b3dSmrg  int id, unsigned char* buf,
964428d7b3dSmrg  short width, short height,
965428d7b3dSmrg  Bool sync,
966428d7b3dSmrg  RegionPtr clipBoxes, pointer data,
967428d7b3dSmrg  DrawablePtr pDraw
968428d7b3dSmrg){
969428d7b3dSmrg    I810Ptr pI810 = I810PTR(pScrn);
970428d7b3dSmrg    I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
971428d7b3dSmrg    INT32 x1, x2, y1, y2;
972428d7b3dSmrg    int srcPitch, dstPitch;
973428d7b3dSmrg    int top, left, npixels, nlines, size, loops;
974428d7b3dSmrg    BoxRec dstBox;
975428d7b3dSmrg
976428d7b3dSmrg
977428d7b3dSmrg    /* Clip */
978428d7b3dSmrg    x1 = src_x;
979428d7b3dSmrg    x2 = src_x + src_w;
980428d7b3dSmrg    y1 = src_y;
981428d7b3dSmrg    y2 = src_y + src_h;
982428d7b3dSmrg
983428d7b3dSmrg    dstBox.x1 = drw_x;
984428d7b3dSmrg    dstBox.x2 = drw_x + drw_w;
985428d7b3dSmrg    dstBox.y1 = drw_y;
986428d7b3dSmrg    dstBox.y2 = drw_y + drw_h;
987428d7b3dSmrg
988428d7b3dSmrg    I810ClipVideo(&dstBox, &x1, &x2, &y1, &y2,
989428d7b3dSmrg		  REGION_EXTENTS(pScrn->screen, clipBoxes), width, height);
990428d7b3dSmrg
991428d7b3dSmrg    if((x1 >= x2) || (y1 >= y2))
992428d7b3dSmrg       return Success;
993428d7b3dSmrg    /*
994428d7b3dSmrg     * Fix for 4 pixel granularity of AdjustFrame
995428d7b3dSmrg     * unless boarder is clipped  by frame
996428d7b3dSmrg     */
997428d7b3dSmrg    dstBox.x1 -= (pScrn->frameX0 &
998428d7b3dSmrg		  ((dstBox.x1 == pScrn->frameX0) ? ~0x0UL : ~0x3UL));
999428d7b3dSmrg    dstBox.x2 -= (pScrn->frameX0 & ~0x3);
1000428d7b3dSmrg    dstBox.y1 -= pScrn->frameY0;
1001428d7b3dSmrg    dstBox.y2 -= pScrn->frameY0;
1002428d7b3dSmrg
1003428d7b3dSmrg    switch(id) {
1004428d7b3dSmrg    case FOURCC_YV12:
1005428d7b3dSmrg    case FOURCC_I420:
1006428d7b3dSmrg	 srcPitch = ALIGN(width, 4);
1007428d7b3dSmrg	 dstPitch = ALIGN((width >> 1), 8);  /* of chroma */
1008428d7b3dSmrg	 size =  dstPitch * height * 3;
1009428d7b3dSmrg	 break;
1010428d7b3dSmrg    case FOURCC_UYVY:
1011428d7b3dSmrg    case FOURCC_YUY2:
1012428d7b3dSmrg    default:
1013428d7b3dSmrg	 srcPitch = (width << 1);
1014428d7b3dSmrg	 dstPitch = ALIGN(srcPitch, 8);
1015428d7b3dSmrg	 size = dstPitch * height;
1016428d7b3dSmrg	 break;
1017428d7b3dSmrg    }
1018428d7b3dSmrg
1019428d7b3dSmrg    if(!(pPriv->linear = I810AllocateMemory(pScrn, pPriv->linear,
1020428d7b3dSmrg		(pScrn->bitsPerPixel == 16) ? size : (size >> 1))))
1021428d7b3dSmrg	return BadAlloc;
1022428d7b3dSmrg
1023428d7b3dSmrg    /* fixup pointers */
1024428d7b3dSmrg    pPriv->YBuf0offset = pPriv->linear->offset * pI810->cpp;
1025428d7b3dSmrg    pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height);
1026428d7b3dSmrg    pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height >> 1);
1027428d7b3dSmrg
1028428d7b3dSmrg    pPriv->YBuf1offset = (pPriv->linear->offset * pI810->cpp) + size;
1029428d7b3dSmrg    pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height);
1030428d7b3dSmrg    pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height >> 1);
1031428d7b3dSmrg
1032428d7b3dSmrg
1033428d7b3dSmrg    /* Make sure this buffer isn't in use */
1034428d7b3dSmrg    loops = 0;
1035428d7b3dSmrg    while (loops < 1000000) {
1036428d7b3dSmrg          if(((INREG(DOV0STA)&0x00100000)>>20) == pPriv->currentBuf) {
1037428d7b3dSmrg            break;
1038428d7b3dSmrg          }
1039428d7b3dSmrg          loops++;
1040428d7b3dSmrg    }
1041428d7b3dSmrg    if(loops >= 1000000) {
1042428d7b3dSmrg      pPriv->currentBuf = !pPriv->currentBuf;
1043428d7b3dSmrg    }
1044428d7b3dSmrg
1045428d7b3dSmrg
1046428d7b3dSmrg    /* buffer swap */
1047428d7b3dSmrg    if (pPriv->currentBuf == 0)
1048428d7b3dSmrg        pPriv->currentBuf = 1;
1049428d7b3dSmrg    else
1050428d7b3dSmrg        pPriv->currentBuf = 0;
1051428d7b3dSmrg
1052428d7b3dSmrg    /* copy data */
1053428d7b3dSmrg    top = y1 >> 16;
1054428d7b3dSmrg    left = (x1 >> 16) & ~1;
1055428d7b3dSmrg    npixels = ALIGN(((x2 + 0xffff) >> 16), 2) - left;
1056428d7b3dSmrg
1057428d7b3dSmrg    switch(id) {
1058428d7b3dSmrg    case FOURCC_YV12:
1059428d7b3dSmrg    case FOURCC_I420:
1060428d7b3dSmrg	top &= ~1;
1061428d7b3dSmrg	nlines = ALIGN(((y2 + 0xffff) >> 16), 2) - top;
1062428d7b3dSmrg	I810CopyPlanarData(pScrn, buf, srcPitch, dstPitch,  height, top, left,
1063428d7b3dSmrg                           nlines, npixels, id);
1064428d7b3dSmrg	break;
1065428d7b3dSmrg    case FOURCC_UYVY:
1066428d7b3dSmrg    case FOURCC_YUY2:
1067428d7b3dSmrg    default:
1068428d7b3dSmrg	nlines = ((y2 + 0xffff) >> 16) - top;
1069428d7b3dSmrg	I810CopyPackedData(pScrn, buf, srcPitch, dstPitch, top, left, nlines,
1070428d7b3dSmrg                                                              npixels);
1071428d7b3dSmrg        break;
1072428d7b3dSmrg    }
1073428d7b3dSmrg
1074428d7b3dSmrg    /* update cliplist */
1075428d7b3dSmrg    if(!REGION_EQUAL(pScrn->screen, &pPriv->clip, clipBoxes)) {
1076428d7b3dSmrg	REGION_COPY(pScrn->screen, &pPriv->clip, clipBoxes);
1077428d7b3dSmrg	/* draw these */
1078428d7b3dSmrg	xf86XVFillKeyHelperDrawable(pDraw, pPriv->colorKey, clipBoxes);
1079428d7b3dSmrg    }
1080428d7b3dSmrg
1081428d7b3dSmrg    I810DisplayVideo(pScrn, id, width, height, dstPitch,
1082428d7b3dSmrg	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1083428d7b3dSmrg
1084428d7b3dSmrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
1085428d7b3dSmrg
1086428d7b3dSmrg    return Success;
1087428d7b3dSmrg}
1088428d7b3dSmrg
1089428d7b3dSmrg
1090428d7b3dSmrgstatic int
1091428d7b3dSmrgI810QueryImageAttributes(
1092428d7b3dSmrg  ScrnInfoPtr pScrn,
1093428d7b3dSmrg  int id,
1094428d7b3dSmrg  unsigned short *w, unsigned short *h,
1095428d7b3dSmrg  int *pitches, int *offsets
1096428d7b3dSmrg){
1097428d7b3dSmrg    int size, tmp;
1098428d7b3dSmrg
1099428d7b3dSmrg    if(*w > IMAGE_MAX_WIDTH) *w = IMAGE_MAX_WIDTH;
1100428d7b3dSmrg    if(*h > IMAGE_MAX_HEIGHT) *h = IMAGE_MAX_HEIGHT;
1101428d7b3dSmrg
1102428d7b3dSmrg    *w = (*w + 1) & ~1;
1103428d7b3dSmrg    if(offsets) offsets[0] = 0;
1104428d7b3dSmrg
1105428d7b3dSmrg    switch(id) {
1106428d7b3dSmrg      /* IA44 is for XvMC only */
1107428d7b3dSmrg    case FOURCC_IA44:
1108428d7b3dSmrg    case FOURCC_AI44:
1109428d7b3dSmrg	if(pitches) pitches[0] = *w;
1110428d7b3dSmrg	size = *w * *h;
1111428d7b3dSmrg	break;
1112428d7b3dSmrg    case FOURCC_YV12:
1113428d7b3dSmrg    case FOURCC_I420:
1114428d7b3dSmrg	*h = (*h + 1) & ~1;
1115428d7b3dSmrg	size = (*w + 3) & ~3;
1116428d7b3dSmrg	if(pitches) pitches[0] = size;
1117428d7b3dSmrg	size *= *h;
1118428d7b3dSmrg	if(offsets) offsets[1] = size;
1119428d7b3dSmrg	tmp = ((*w >> 1) + 3) & ~3;
1120428d7b3dSmrg	if(pitches) pitches[1] = pitches[2] = tmp;
1121428d7b3dSmrg	tmp *= (*h >> 1);
1122428d7b3dSmrg	size += tmp;
1123428d7b3dSmrg	if(offsets) offsets[2] = size;
1124428d7b3dSmrg	size += tmp;
1125428d7b3dSmrg	break;
1126428d7b3dSmrg    case FOURCC_UYVY:
1127428d7b3dSmrg    case FOURCC_YUY2:
1128428d7b3dSmrg    default:
1129428d7b3dSmrg	size = *w << 1;
1130428d7b3dSmrg	if(pitches) pitches[0] = size;
1131428d7b3dSmrg	size *= *h;
1132428d7b3dSmrg	break;
1133428d7b3dSmrg    }
1134428d7b3dSmrg
1135428d7b3dSmrg    return size;
1136428d7b3dSmrg}
1137428d7b3dSmrg
1138428d7b3dSmrgstatic void
1139428d7b3dSmrgI810BlockHandler (BLOCKHANDLER_ARGS_DECL)
1140428d7b3dSmrg{
1141428d7b3dSmrg    SCREEN_PTR(arg);
1142428d7b3dSmrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
1143428d7b3dSmrg    I810Ptr      pI810 = I810PTR(pScrn);
1144428d7b3dSmrg    I810PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
1145428d7b3dSmrg    I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
1146428d7b3dSmrg
1147428d7b3dSmrg    screen->BlockHandler = pI810->BlockHandler;
1148428d7b3dSmrg
1149428d7b3dSmrg    (*screen->BlockHandler) (BLOCKHANDLER_ARGS);
1150428d7b3dSmrg
1151428d7b3dSmrg    screen->BlockHandler = I810BlockHandler;
1152428d7b3dSmrg
1153428d7b3dSmrg    if(pPriv->videoStatus & TIMER_MASK) {
1154428d7b3dSmrg	UpdateCurrentTime();
1155428d7b3dSmrg	if(pPriv->videoStatus & OFF_TIMER) {
1156428d7b3dSmrg	    if(pPriv->offTime < currentTime.milliseconds) {
1157428d7b3dSmrg		/* Turn off the overlay */
1158428d7b3dSmrg		overlay->OV0CMD &= 0xFFFFFFFE;
1159428d7b3dSmrg		OVERLAY_UPDATE(pI810->OverlayPhysical);
1160428d7b3dSmrg
1161428d7b3dSmrg		pPriv->videoStatus = FREE_TIMER;
1162428d7b3dSmrg		pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1163428d7b3dSmrg	    }
1164428d7b3dSmrg	} else {  /* FREE_TIMER */
1165428d7b3dSmrg	    if(pPriv->freeTime < currentTime.milliseconds) {
1166428d7b3dSmrg		if(pPriv->linear) {
1167428d7b3dSmrg		   xf86FreeOffscreenLinear(pPriv->linear);
1168428d7b3dSmrg		   pPriv->linear = NULL;
1169428d7b3dSmrg		}
1170428d7b3dSmrg		pPriv->videoStatus = 0;
1171428d7b3dSmrg	    }
1172428d7b3dSmrg        }
1173428d7b3dSmrg    }
1174428d7b3dSmrg}
1175428d7b3dSmrg
1176428d7b3dSmrg
1177428d7b3dSmrg/***************************************************************************
1178428d7b3dSmrg * Offscreen Images
1179428d7b3dSmrg ***************************************************************************/
1180428d7b3dSmrg
1181428d7b3dSmrgtypedef struct {
1182428d7b3dSmrg  FBLinearPtr linear;
1183428d7b3dSmrg  Bool isOn;
1184428d7b3dSmrg} OffscreenPrivRec, * OffscreenPrivPtr;
1185428d7b3dSmrg
1186428d7b3dSmrgstatic int
1187428d7b3dSmrgI810AllocateSurface(
1188428d7b3dSmrg    ScrnInfoPtr pScrn,
1189428d7b3dSmrg    int id,
1190428d7b3dSmrg    unsigned short w,
1191428d7b3dSmrg    unsigned short h,
1192428d7b3dSmrg    XF86SurfacePtr surface
1193428d7b3dSmrg){
1194428d7b3dSmrg    FBLinearPtr linear;
1195428d7b3dSmrg    int pitch, size, bpp;
1196428d7b3dSmrg    OffscreenPrivPtr pPriv;
1197428d7b3dSmrg    I810Ptr pI810 = I810PTR(pScrn);
1198428d7b3dSmrg
1199428d7b3dSmrg    if((w > 1024) || (h > 1024))
1200428d7b3dSmrg	return BadAlloc;
1201428d7b3dSmrg
1202428d7b3dSmrg    w = ALIGN(w, 2);
1203428d7b3dSmrg    pitch = ALIGN((w << 1), 16);
1204428d7b3dSmrg    bpp = pScrn->bitsPerPixel >> 3;
1205428d7b3dSmrg    size = ((pitch * h) + bpp - 1) / bpp;
1206428d7b3dSmrg
1207428d7b3dSmrg    if(!(linear = I810AllocateMemory(pScrn, NULL, size)))
1208428d7b3dSmrg	return BadAlloc;
1209428d7b3dSmrg
1210428d7b3dSmrg    surface->width = w;
1211428d7b3dSmrg    surface->height = h;
1212428d7b3dSmrg
1213428d7b3dSmrg    if(!(surface->pitches = malloc(sizeof(int)))) {
1214428d7b3dSmrg	xf86FreeOffscreenLinear(linear);
1215428d7b3dSmrg	return BadAlloc;
1216428d7b3dSmrg    }
1217428d7b3dSmrg    if(!(surface->offsets = malloc(sizeof(int)))) {
1218428d7b3dSmrg	free(surface->pitches);
1219428d7b3dSmrg	xf86FreeOffscreenLinear(linear);
1220428d7b3dSmrg	return BadAlloc;
1221428d7b3dSmrg    }
1222428d7b3dSmrg    if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
1223428d7b3dSmrg	free(surface->pitches);
1224428d7b3dSmrg	free(surface->offsets);
1225428d7b3dSmrg	xf86FreeOffscreenLinear(linear);
1226428d7b3dSmrg	return BadAlloc;
1227428d7b3dSmrg    }
1228428d7b3dSmrg
1229428d7b3dSmrg    pPriv->linear = linear;
1230428d7b3dSmrg    pPriv->isOn = FALSE;
1231428d7b3dSmrg
1232428d7b3dSmrg    surface->pScrn = pScrn;
1233428d7b3dSmrg    surface->id = id;
1234428d7b3dSmrg    surface->pitches[0] = pitch;
1235428d7b3dSmrg    surface->offsets[0] = linear->offset * bpp;
1236428d7b3dSmrg    surface->devPrivate.ptr = (pointer)pPriv;
1237428d7b3dSmrg
1238428d7b3dSmrg    memset(pI810->FbBase + surface->offsets[0],0,size);
1239428d7b3dSmrg
1240428d7b3dSmrg    return Success;
1241428d7b3dSmrg}
1242428d7b3dSmrg
1243428d7b3dSmrgstatic int
1244428d7b3dSmrgI810StopSurface(
1245428d7b3dSmrg    XF86SurfacePtr surface
1246428d7b3dSmrg){
1247428d7b3dSmrg    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1248428d7b3dSmrg
1249428d7b3dSmrg    if(pPriv->isOn) {
1250428d7b3dSmrg      I810Ptr pI810 = I810PTR(surface->pScrn);
1251428d7b3dSmrg
1252428d7b3dSmrg      I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
1253428d7b3dSmrg
1254428d7b3dSmrg      overlay->OV0CMD &= 0xFFFFFFFE;
1255428d7b3dSmrg      OVERLAY_UPDATE(pI810->OverlayPhysical);
1256428d7b3dSmrg
1257428d7b3dSmrg      pPriv->isOn = FALSE;
1258428d7b3dSmrg    }
1259428d7b3dSmrg
1260428d7b3dSmrg    return Success;
1261428d7b3dSmrg}
1262428d7b3dSmrg
1263428d7b3dSmrg
1264428d7b3dSmrgstatic int
1265428d7b3dSmrgI810FreeSurface(
1266428d7b3dSmrg    XF86SurfacePtr surface
1267428d7b3dSmrg){
1268428d7b3dSmrg    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1269428d7b3dSmrg
1270428d7b3dSmrg    if(pPriv->isOn) {
1271428d7b3dSmrg	I810StopSurface(surface);
1272428d7b3dSmrg    }
1273428d7b3dSmrg    xf86FreeOffscreenLinear(pPriv->linear);
1274428d7b3dSmrg    free(surface->pitches);
1275428d7b3dSmrg    free(surface->offsets);
1276428d7b3dSmrg    free(surface->devPrivate.ptr);
1277428d7b3dSmrg
1278428d7b3dSmrg    return Success;
1279428d7b3dSmrg}
1280428d7b3dSmrg
1281428d7b3dSmrgstatic int
1282428d7b3dSmrgI810GetSurfaceAttribute(
1283428d7b3dSmrg    ScrnInfoPtr pScrn,
1284428d7b3dSmrg    Atom attribute,
1285428d7b3dSmrg    INT32 *value
1286428d7b3dSmrg){
1287428d7b3dSmrg    return I810GetPortAttribute(pScrn, attribute, value, GET_PORT_PRIVATE(pScrn));
1288428d7b3dSmrg}
1289428d7b3dSmrg
1290428d7b3dSmrgstatic int
1291428d7b3dSmrgI810SetSurfaceAttribute(
1292428d7b3dSmrg    ScrnInfoPtr pScrn,
1293428d7b3dSmrg    Atom attribute,
1294428d7b3dSmrg    INT32 value
1295428d7b3dSmrg){
1296428d7b3dSmrg    return I810SetPortAttribute(pScrn, attribute, value, GET_PORT_PRIVATE(pScrn));
1297428d7b3dSmrg}
1298428d7b3dSmrg
1299428d7b3dSmrg
1300428d7b3dSmrgstatic int
1301428d7b3dSmrgI810DisplaySurface(
1302428d7b3dSmrg    XF86SurfacePtr surface,
1303428d7b3dSmrg    short src_x, short src_y,
1304428d7b3dSmrg    short drw_x, short drw_y,
1305428d7b3dSmrg    short src_w, short src_h,
1306428d7b3dSmrg    short drw_w, short drw_h,
1307428d7b3dSmrg    RegionPtr clipBoxes
1308428d7b3dSmrg){
1309428d7b3dSmrg    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1310428d7b3dSmrg    ScrnInfoPtr pScrn = surface->pScrn;
1311428d7b3dSmrg    I810Ptr      pI810 = I810PTR(pScrn);
1312428d7b3dSmrg    I810PortPrivPtr pI810Priv =  GET_PORT_PRIVATE(pScrn);
1313428d7b3dSmrg
1314428d7b3dSmrg    INT32 x1, y1, x2, y2;
1315428d7b3dSmrg    INT32 loops = 0;
1316428d7b3dSmrg    BoxRec dstBox;
1317428d7b3dSmrg
1318428d7b3dSmrg    x1 = src_x;
1319428d7b3dSmrg    x2 = src_x + src_w;
1320428d7b3dSmrg    y1 = src_y;
1321428d7b3dSmrg    y2 = src_y + src_h;
1322428d7b3dSmrg
1323428d7b3dSmrg    dstBox.x1 = drw_x;
1324428d7b3dSmrg    dstBox.x2 = drw_x + drw_w;
1325428d7b3dSmrg    dstBox.y1 = drw_y;
1326428d7b3dSmrg    dstBox.y2 = drw_y + drw_h;
1327428d7b3dSmrg
1328428d7b3dSmrg    I810ClipVideo(&dstBox, &x1, &x2, &y1, &y2,
1329428d7b3dSmrg		  REGION_EXTENTS(screenInfo.screens[0], clipBoxes),
1330428d7b3dSmrg		  surface->width, surface->height);
1331428d7b3dSmrg
1332428d7b3dSmrg    /*
1333428d7b3dSmrg     * Fix for 4 pixel granularity of AdjustFrame
1334428d7b3dSmrg     * unless boarder is clipped  by frame
1335428d7b3dSmrg     */
1336428d7b3dSmrg    dstBox.x1 -= (pScrn->frameX0 &
1337428d7b3dSmrg		  ((dstBox.x1 == pScrn->frameX0) ? ~0x0UL : ~0x3UL));
1338428d7b3dSmrg    dstBox.x2 -= (pScrn->frameX0 & ~0x3);
1339428d7b3dSmrg    dstBox.y1 -= pScrn->frameY0;
1340428d7b3dSmrg    dstBox.y2 -= pScrn->frameY0;
1341428d7b3dSmrg
1342428d7b3dSmrg    /* fixup pointers */
1343428d7b3dSmrg    pI810Priv->YBuf0offset = surface->offsets[0];
1344428d7b3dSmrg    pI810Priv->YBuf1offset = pI810Priv->YBuf0offset;
1345428d7b3dSmrg
1346428d7b3dSmrg   /* wait for the last rendered buffer to be flipped in */
1347428d7b3dSmrg    while (((INREG(DOV0STA)&0x00100000)>>20) != pI810Priv->currentBuf) {
1348428d7b3dSmrg      if(loops == 200000) {
1349428d7b3dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Overlay Lockup\n");
1350428d7b3dSmrg	break;
1351428d7b3dSmrg      }
1352428d7b3dSmrg      loops++;
1353428d7b3dSmrg    }
1354428d7b3dSmrg
1355428d7b3dSmrg    /* buffer swap */
1356428d7b3dSmrg    if (pI810Priv->currentBuf == 0)
1357428d7b3dSmrg      pI810Priv->currentBuf = 1;
1358428d7b3dSmrg    else
1359428d7b3dSmrg      pI810Priv->currentBuf = 0;
1360428d7b3dSmrg
1361428d7b3dSmrg    I810ResetVideo(pScrn);
1362428d7b3dSmrg
1363428d7b3dSmrg    I810DisplayVideo(pScrn, surface->id, surface->width, surface->height,
1364428d7b3dSmrg		     surface->pitches[0], x1, y1, x2, y2, &dstBox,
1365428d7b3dSmrg		     src_w, src_h, drw_w, drw_h);
1366428d7b3dSmrg
1367428d7b3dSmrg    xf86XVFillKeyHelper(pScrn->pScreen, pI810Priv->colorKey, clipBoxes);
1368428d7b3dSmrg
1369428d7b3dSmrg    pPriv->isOn = TRUE;
1370428d7b3dSmrg    /* we've prempted the XvImage stream so set its free timer */
1371428d7b3dSmrg    if(pI810Priv->videoStatus & CLIENT_VIDEO_ON) {
1372428d7b3dSmrg      REGION_EMPTY(pScrn->screen, & pI810Priv->clip);
1373428d7b3dSmrg      UpdateCurrentTime();
1374428d7b3dSmrg      pI810Priv->videoStatus = FREE_TIMER;
1375428d7b3dSmrg      pI810Priv->freeTime = currentTime.milliseconds + FREE_DELAY;
1376428d7b3dSmrg      pScrn->pScreen->BlockHandler = I810BlockHandler;
1377428d7b3dSmrg    }
1378428d7b3dSmrg
1379428d7b3dSmrg    return Success;
1380428d7b3dSmrg}
1381428d7b3dSmrg
1382428d7b3dSmrg
1383428d7b3dSmrgstatic void
1384428d7b3dSmrgI810InitOffscreenImages(ScreenPtr screen)
1385428d7b3dSmrg{
1386428d7b3dSmrg    XF86OffscreenImagePtr offscreenImages;
1387428d7b3dSmrg
1388428d7b3dSmrg    /* need to free this someplace */
1389428d7b3dSmrg    if(!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec)))) {
1390428d7b3dSmrg      return;
1391428d7b3dSmrg    }
1392428d7b3dSmrg
1393428d7b3dSmrg    offscreenImages[0].image = &Images[0];
1394428d7b3dSmrg    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
1395428d7b3dSmrg			       VIDEO_CLIP_TO_VIEWPORT;
1396428d7b3dSmrg    offscreenImages[0].alloc_surface = I810AllocateSurface;
1397428d7b3dSmrg    offscreenImages[0].free_surface = I810FreeSurface;
1398428d7b3dSmrg    offscreenImages[0].display = I810DisplaySurface;
1399428d7b3dSmrg    offscreenImages[0].stop = I810StopSurface;
1400428d7b3dSmrg    offscreenImages[0].setAttribute = I810SetSurfaceAttribute;
1401428d7b3dSmrg    offscreenImages[0].getAttribute = I810GetSurfaceAttribute;
1402428d7b3dSmrg    offscreenImages[0].max_width = 1024;
1403428d7b3dSmrg    offscreenImages[0].max_height = 1024;
1404428d7b3dSmrg    offscreenImages[0].num_attributes = 1;
1405428d7b3dSmrg    offscreenImages[0].attributes = Attributes;
1406428d7b3dSmrg
1407428d7b3dSmrg    if (!xf86XVRegisterOffscreenImages(screen, offscreenImages, 1))
1408428d7b3dSmrg	    free(offscreenImages);
1409428d7b3dSmrg}
1410428d7b3dSmrg
1411