apm_video.c revision 17a48c7c
1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/apm/apm_video.c,v 1.11tsi Exp $ */
2
3#ifdef HAVE_CONFIG_H
4#include "config.h"
5#endif
6
7#if PSZ != 24
8#include "dixstruct.h"
9#include "fourcc.h"
10
11/*
12 * Ported from mga_video.c by Loïc Grenié
13 */
14
15#ifndef OFF_DELAY
16#define OFF_DELAY	200
17#endif
18
19static XF86VideoAdaptorPtr A(SetupImageVideo)(ScreenPtr);
20
21static void	A(StopVideo)(ScrnInfoPtr, pointer, Bool);
22static int	A(SetPortAttribute)(ScrnInfoPtr, Atom, INT32, pointer);
23#ifndef IOP_ACCESS
24static int	ApmGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
25static void	ApmQueryBestSize(ScrnInfoPtr, Bool, short, short, short,
26				    short, unsigned int *, unsigned int *,
27				    pointer);
28static int	ApmQueryImageAttributes(ScrnInfoPtr, int,
29					    unsigned short *, unsigned short *,
30					    int *, int *);
31#endif
32static int	A(ReputImage)(ScrnInfoPtr, short, short, RegionPtr, pointer,
33				DrawablePtr);
34static int	A(PutImage)(ScrnInfoPtr, short, short, short, short, short,
35				short, short, short, int, unsigned char*,
36				short, short, Bool, RegionPtr, pointer,
37				DrawablePtr);
38
39static void	A(ResetVideo)(ScrnInfoPtr);
40static void	A(XvMoveCB)(FBAreaPtr, FBAreaPtr);
41static void	A(XvRemoveCB)(FBAreaPtr);
42
43#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
44
45void A(InitVideo)(ScreenPtr pScreen)
46{
47    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
48    XF86VideoAdaptorPtr *adaptors, *newAdaptors;
49    XF86VideoAdaptorPtr newAdaptor;
50    APMDECL(pScrn);
51    int num_adaptors;
52    Bool freeAdaptors = FALSE;
53
54    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
55
56    if (pApm->Chipset >= AT24) {
57	if ((newAdaptor = A(SetupImageVideo)(pScreen))) {
58
59	   newAdaptors = xalloc((num_adaptors + 1) *
60				   sizeof(XF86VideoAdaptorPtr*));
61	   if(newAdaptors) {
62		if(num_adaptors)
63		    memcpy(newAdaptors, adaptors, num_adaptors *
64					sizeof(XF86VideoAdaptorPtr));
65		newAdaptors[num_adaptors] = newAdaptor;
66		adaptors = newAdaptors;
67		num_adaptors++;
68		freeAdaptors = TRUE;
69	   }
70	}
71    }
72
73    if(num_adaptors)
74        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
75
76    if(freeAdaptors)
77	xfree(adaptors);
78}
79
80#ifndef APM_VIDEO_DEFINES
81#define APM_VIDEO_DEFINES
82
83static Atom xvBrightness, xvContrast;
84
85/* client libraries expect an encoding */
86static XF86VideoEncodingRec DummyEncoding[1] =
87{
88    {
89	0,
90	"XV_IMAGE",
91	1024, 1024,
92	{1, 1}
93    }
94};
95
96#define NUM_FORMATS 24
97
98static XF86VideoFormatRec Formats[NUM_FORMATS] =
99{
100    { 8, PseudoColor},
101    {15, PseudoColor},
102    {16, PseudoColor},
103    {24, PseudoColor},
104    {32, PseudoColor},
105    { 8, DirectColor},
106    {15, DirectColor},
107    {16, DirectColor},
108    {24, DirectColor},
109    {32, DirectColor},
110    { 8,   TrueColor},
111    {15,   TrueColor},
112    {16,   TrueColor},
113    {24,   TrueColor},
114    {32,   TrueColor}
115};
116
117#define NUM_ATTRIBUTES 2
118
119static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
120{
121    {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
122    {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
123};
124
125#define NUM_IMAGES 9
126typedef char c8;
127
128static XF86ImageRec Images[NUM_IMAGES] =
129{
130   {
131	0x35315652,
132        XvRGB,
133	LSBFirst,
134	{'R','V','1','5',
135	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
136	16,
137	XvPacked,
138	1,
139	15, 0x001F, 0x03E0, 0x7C00,
140	0, 0, 0,
141	0, 0, 0,
142	0, 0, 0,
143	{'R','V','B',0,
144	  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},
145	XvTopToBottom
146   },
147   {
148	0x36315652,
149        XvRGB,
150	LSBFirst,
151	{'R','V','1','6',
152	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
153	16,
154	XvPacked,
155	1,
156	16, 0x001F, 0x07E0, 0xF800,
157	0, 0, 0,
158	0, 0, 0,
159	0, 0, 0,
160	{'R','V','B',0,
161	  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},
162	XvTopToBottom
163   },
164   {
165	0x32335652,
166        XvRGB,
167	LSBFirst,
168	{'R','V','3','2',
169	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
170	32,
171	XvPacked,
172	1,
173	24, 0x0000FF, 0x00FF00, 0xFF0000,
174	0, 0, 0,
175	0, 0, 0,
176	0, 0, 0,
177	{'R','V','B',0,
178	  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},
179	XvTopToBottom
180   },
181   XVIMAGE_YUY2,
182   {
183	0x59595959,
184        XvYUV,
185	LSBFirst,
186	{0x00,0x00,0x00,0x00,
187	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
188	8,
189	XvPacked,
190	1,
191	0, 0, 0, 0,
192	8, 0, 0,
193	1, 1, 1,
194	1, 1, 1,
195	{'Y','Y','Y','Y',
196	  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},
197	XvTopToBottom
198   },
199   {
200	0x32315659,
201        XvYUV,
202	LSBFirst,
203	{'Y','V','1','2',
204	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
205	12,
206	XvPlanar,
207	3,
208	0, 0, 0, 0 ,
209	8, 8, 8,
210	1, 2, 2,
211	1, 2, 2,
212	{'Y','V','U',
213	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
214	XvTopToBottom
215   },
216   {
217	0x59565955,
218        XvYUV,
219	LSBFirst,
220	{'U','Y','V','Y',
221	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
222	16,
223	XvPlanar,
224	1,
225	0, 0, 0, 0,
226	8, 8, 8,
227	1, 2, 2,
228	1, 1, 1,
229	{'U','Y','V','Y',
230	  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},
231	XvTopToBottom
232   },
233   {
234	0x55595659,
235        XvYUV,
236	LSBFirst,
237	{'Y','V','Y','U',
238	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
239	16,
240	XvPlanar,
241	1,
242	0, 0, 0, 0,
243	8, 8, 8,
244	1, 2, 2,
245	1, 1, 1,
246	{'Y','V','Y','U',
247	  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},
248	XvTopToBottom
249   },
250   {
251	0x59555956,
252        XvYUV,
253	LSBFirst,
254	{'V','Y','U','Y',
255	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
256	16,
257	XvPlanar,
258	1,
259	0, 0, 0, 0,
260	8, 8, 8,
261	1, 2, 2,
262	1, 1, 1,
263	{'V','Y','U','Y',
264	  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},
265	XvTopToBottom
266   }
267};
268
269typedef struct {
270   Bool		on;
271   unsigned char	brightness;
272   unsigned char	contrast;
273   unsigned short	reg, val;
274   ApmPtr	pApm;
275   int		x1, x10, y1, drw_x, drw_y, Bpp, Bps;
276   FBAreaPtr	area;
277   RegionRec	clip;
278   int		xnum, xden, ynum, yden;
279   CARD32	scalex, scaley;
280   CARD32	data;
281} ApmPortPrivRec, *ApmPortPrivPtr;
282#endif
283
284
285static void
286A(ResetVideo)(ScrnInfoPtr pScrn)
287{
288    APMDECL(pScrn);
289
290    A(WaitForFifo)(pApm, 2);
291    ((ApmPortPrivPtr)pApm->adaptor->pPortPrivates[0].ptr)->on = 0;
292    ((ApmPortPrivPtr)pApm->adaptor->pPortPrivates[1].ptr)->on = 0;
293    WRXW(0x82, 0);
294    WRXW(0x92, 0);
295}
296
297
298static XF86VideoAdaptorPtr
299A(SetupImageVideo)(ScreenPtr pScreen)
300{
301    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
302    APMDECL(pScrn);
303    XF86VideoAdaptorPtr adapt;
304    ApmPortPrivPtr pPriv;
305
306    if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
307			    2 * sizeof(ApmPortPrivRec) +
308			    2 * sizeof(DevUnion))))
309	return NULL;
310
311    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
312    adapt->flags = VIDEO_OVERLAID_IMAGES;
313    adapt->name = "Alliance Pro Motion video engine";
314    adapt->nEncodings = 1;
315    adapt->pEncodings = DummyEncoding;
316    adapt->nFormats = NUM_FORMATS;
317    adapt->pFormats = Formats;
318    adapt->nPorts = 2;
319    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
320    pPriv = (ApmPortPrivPtr)(&adapt->pPortPrivates[2]);
321    pPriv->pApm = pApm;
322    pPriv[1].pApm = pApm;
323    pPriv->reg = 0x82;
324    pPriv[1].reg = 0x92;
325    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
326    adapt->pPortPrivates[1].ptr = (pointer)(pPriv + 1);
327    adapt->nAttributes = NUM_ATTRIBUTES;
328    adapt->pAttributes = Attributes;
329    adapt->nImages = NUM_IMAGES;
330    adapt->pImages = Images;
331    adapt->PutVideo = NULL;
332    adapt->PutStill = NULL;
333    adapt->GetVideo = NULL;
334    adapt->GetStill = NULL;
335    adapt->StopVideo = A(StopVideo);
336    adapt->SetPortAttribute = A(SetPortAttribute);
337    adapt->GetPortAttribute = ApmGetPortAttribute;
338    adapt->QueryBestSize = ApmQueryBestSize;
339    adapt->PutImage = A(PutImage);
340    adapt->ReputImage = A(ReputImage);
341    adapt->QueryImageAttributes = ApmQueryImageAttributes;
342
343    pPriv->brightness = 0;
344    pPriv->contrast = 128;
345    pPriv[1].brightness = 0;
346    pPriv[1].contrast = 128;
347
348    /* gotta uninit this someplace */
349    REGION_NULL(pScreen, &pPriv->clip);
350    REGION_NULL(pScreen, &(pPriv + 1)->clip);
351
352    pApm->adaptor = adapt;
353
354    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
355    xvContrast   = MAKE_ATOM("XV_CONTRAST");
356
357    A(ResetVideo)(pScrn);
358
359    return adapt;
360}
361
362#ifndef IOP_ACCESS
363/* ApmClipVideo -
364
365   Takes the dst box in standard X BoxRec form (top and left
366   edges inclusive, bottom and right exclusive).  The new dst
367   box is returned.  The source boundaries are given (x1, y1
368   inclusive, x2, y2 exclusive) and returned are the new source
369   boundaries in 16.16 fixed point.
370
371  extents is the extents of the clip region
372*/
373
374static void
375ApmClipVideo(BoxPtr dst, INT32 *x1, INT32 *x2, INT32 *y1, INT32 *y2,
376	      BoxPtr extents, INT32 width, INT32 height,
377	      CARD32 *scalex, CARD32 *scaley, INT32 mask)
378{
379    INT32 vscale, hscale;
380    int diff;
381
382    if (dst->x2 - dst->x1 < *x2 - *x1)
383	dst->x2 = dst->x1 + *x2 - *x1;
384
385    if (dst->y2 - dst->y1 < *y2 - *y1)
386	dst->y2 = dst->y1 + *y2 - *y1;
387
388    *x1 <<= 12; *x2 <<= 16;
389    *y1 <<= 12; *y2 <<= 16;
390
391    hscale = (*x2 - *x1) / (dst->x2 - dst->x1);
392    vscale = (*y2 - *y1) / (dst->y2 - dst->y1);
393
394    diff = extents->x1 - dst->x1;
395    if(diff > 0) {
396	dst->x1 = extents->x1;
397	*x1 += diff * hscale;
398    }
399    diff = dst->x2 - extents->x2;
400    if(diff > 0) {
401	dst->x2 = extents->x2;
402	*x2 -= diff * hscale;
403    }
404    diff = extents->y1 - dst->y1;
405    if(diff > 0) {
406	dst->y1 = extents->y1;
407	*y1 += diff * vscale;
408    }
409    diff = dst->y2 - extents->y2;
410    if(diff > 0) {
411	dst->y2 = extents->y2;
412	*y2 -= diff * vscale;
413    }
414
415    if (*x2 - *x1 == 0x10000 * (dst->x2 - dst->x1))	/* Shrinking */
416	*scalex = 0;
417    else
418	*scalex = ((*x2 - *x1) / (dst->x2 - dst->x1)) >> 4;
419    if (*y2 - *y1 == 0x10000 * (dst->y2 - dst->y1))	/* Shrinking */
420	*scaley = 0;
421    else
422	*scaley = ((*y2 - *y1) / (dst->y2 - dst->y1)) >> 4;
423}
424#endif
425
426static void
427A(StopVideo)(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
428{
429    ApmPortPrivPtr pPriv = (ApmPortPrivPtr)data;
430    APMDECL(pScrn);
431
432    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
433
434    pPriv->on = 0;
435    A(WaitForFifo)(pApm, 1);
436    WRXB(pPriv->reg, 0);
437}
438
439static int
440A(SetPortAttribute)(ScrnInfoPtr pScrn, Atom attribute, INT32 value,
441		      pointer data)
442{
443  ApmPortPrivPtr pPriv = (ApmPortPrivPtr)data;
444  /*APMDECL(pScrn);*/
445
446  if(attribute == xvBrightness) {
447	if((value < -128) || (value > 127))
448	   return BadValue;
449	pPriv->brightness = value;
450	/* TODO : enable */
451  } else if(attribute == xvContrast) {
452	if((value < 0) || (value > 255))
453	   return BadValue;
454	pPriv->contrast = value;
455	/* TODO : enable */
456  }
457
458  return Success;
459}
460
461#ifndef IOP_ACCESS
462static int
463ApmGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value,
464		      pointer data)
465{
466  ApmPortPrivPtr pPriv = (ApmPortPrivPtr)data;
467
468  if(attribute == xvBrightness) {
469	*value = pPriv->brightness;
470  } else
471  if(attribute == xvContrast) {
472	*value = pPriv->contrast;
473  }
474
475  return Success;
476}
477
478static void
479ApmQueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, short vid_h,
480		  short drw_w, short drw_h,
481		  unsigned int *p_w, unsigned int *p_h, pointer data)
482{
483    APMDECL(pScrn);
484    unsigned short	round = ~pApm->CurrentLayout.mask32;
485
486    *p_w = drw_w & round;
487    *p_h = drw_h & round;
488}
489#endif
490
491static void A(XvMoveCB)(FBAreaPtr area1, FBAreaPtr area2)
492{
493    ApmPortPrivPtr	pPriv = (ApmPortPrivPtr)area1->devPrivate.ptr;
494    ApmPtr		pApm = pPriv->pApm;
495
496    pPriv->on = 0;
497    A(WaitForFifo)(pApm, 1);
498    WRXB(pPriv->reg, 0);	/* Stop video for this port */
499    pPriv->area = area2;
500}
501
502static void A(XvRemoveCB)(FBAreaPtr area)
503{
504    ApmPortPrivPtr	pPriv = (ApmPortPrivPtr)area->devPrivate.ptr;
505    ApmPtr		pApm = pPriv->pApm;
506
507    pPriv->on = 0;
508    A(WaitForFifo)(pApm, 1);
509    WRXB(pPriv->reg, 0);	/* Stop video for this port */
510    pPriv->area = NULL;
511}
512
513static int
514A(ReputImage)(ScrnInfoPtr pScrn, short drw_x, short drw_y,
515		RegionPtr clipBoxes, pointer pdata, DrawablePtr pDraw)
516{
517    ScreenPtr		pScreen = pScrn->pScreen;
518    APMDECL(pScrn);
519    ApmPortPrivPtr	pPriv = pdata, pPriv0, pPriv1;
520    register int	fx, fy;
521    CARD32	mask;
522    RegionRec	Union;
523    RegionPtr	reg0;
524    int		nrects, CurrY, tile;
525    int		X1, X2, Y1, y2, xmax, ymax;
526    BoxPtr	rects;
527    Bool	didit = 0;
528
529    mask = pApm->CurrentLayout.mask32;
530    fx = pScrn->frameX0 & ~mask;
531    fy = pScrn->frameY0 + 1;
532    REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
533    pPriv->x1 += drw_x - pPriv->drw_x;
534    pPriv->x10 = ((pPriv->x1 + mask) & ~mask) - fx;
535    pPriv->y1 += drw_y - pPriv->drw_y;
536    pPriv->drw_x = drw_x;
537    pPriv->drw_y = drw_y;
538    A(WaitForFifo)(pApm, 2);
539    WRXW(pPriv->reg + 0x06, 0xFFF - ((pPriv->scalex * pPriv->x10) & 0xFFF));
540    WRXW(pPriv->reg + 0x0A, 0xFFF - ((pPriv->scaley * pPriv->y1) & 0xFFF));
541    pPriv0 = (ApmPortPrivPtr)pApm->adaptor->pPortPrivates[0].ptr;
542    pPriv1 = (ApmPortPrivPtr)pApm->adaptor->pPortPrivates[1].ptr;
543    reg0 = &pPriv0->clip;
544    bzero(&Union, sizeof Union);
545    REGION_EMPTY(pScreen, &Union);
546    REGION_NULL(pScreen, &Union);
547    REGION_UNION(pScreen, &Union, reg0, &pPriv1->clip);
548    nrects = REGION_NUM_RECTS(&Union);
549    rects = REGION_RECTS(&Union);
550    tile = 0x200;
551    xmax = pScrn->frameX1 - pScrn->frameX0 + 1;
552    ymax = pScrn->frameY1 - pScrn->frameY0;
553    CurrY = -1;
554    goto BEGIN_LOOP_1;
555    do {
556	rects++;
557BEGIN_LOOP_1:
558	X1 = ((rects->x1 + mask) & ~mask) - fx;
559	if (X1 < 0)
560	    X1 = 0;
561	X2 = (rects->x2 & ~mask) - fx;
562	if (X2 > xmax)
563	    X2 = xmax;
564	y2 = rects->y2 - fy;
565    } while ((X2 <= X1 || y2 < -1) && --nrects > 0);
566    Y1 = rects->y1 - fy;
567
568    while (!(STATUS() & 0x800));
569    while (STATUS() & 0x800);
570    while (nrects-- > 0) {
571	CARD32	reg, data;
572	int	x1, x2, y1;
573
574	x1 = X1;
575	x2 = X2;
576	y1 = Y1;
577	if (y1 < -1) y1 = -1;
578	if (y1 > ymax)
579	    break;
580	didit = 1;
581	if (y1 > CurrY) {
582	    A(WaitForFifo)(pApm, 3);
583	    WRXL(tile + 0x00, 0xFFF0011);
584	    WRXL(tile + 0x04, y1 << 16);
585	    WRXL(tile + 0x08, 0);
586	    tile += 16;
587	}
588	if (RECT_IN_REGION(pScreen, reg0, rects)) {
589	    pPriv = pPriv0;
590	    reg = (x1 << 16) | 1;
591	}
592	else {
593	    pPriv = pPriv1;
594	    reg = (x1 << 16) | 2;
595	}
596	CurrY = y2;
597	if (nrects <= 0)
598	    goto BEGIN_LOOP_2;
599	do {
600	    rects++;
601BEGIN_LOOP_2:
602	    X1 = ((rects->x1 + mask) & ~mask) - fx;
603	    if (X1 < 0)
604		X1 = 0;
605	    X2 = (rects->x2 & ~mask) - fx;
606	    if (X2 > xmax)
607		X2 = xmax;
608	} while (X2 <= X1 && --nrects > 0);
609	Y1 = rects->y1 - fy;
610	y2 = rects->y2 - fy;
611	data = pPriv->data + (((x1 - pPriv->x10)
612				* pPriv->xden) / pPriv->xnum) * pPriv->Bpp +
613	    (((y1 - pPriv->y1 + fy) * pPriv->yden) / pPriv->ynum) * pPriv->Bps;
614	A(WaitForFifo)(pApm, 4);
615	if (!nrects || tile == 0x2B0 || y1 < Y1) {
616	    WRXL(tile   , 0x10 | reg);
617	}
618	else {
619	    WRXL(tile   , reg);
620	}
621	WRXL(tile + 0x04, x2 | (CurrY << 16));
622	WRXL(tile + 0x08, (((x2-x1)*pPriv->xden+pPriv->xnum-1) / pPriv->xnum) |
623				(data << 16));
624	WRXB(tile + 0x0C, data >> 16);
625	tile += 16;
626	if (tile == 0x2C0) {
627	    tile = 0x200;
628	    break;
629	}
630    }
631    REGION_UNINIT(pScreen, &Union);
632
633    if (didit) {
634	A(WaitForFifo)(pApm, 1);
635	WRXW(0x8E, tile - 0x200);
636    }
637
638    if (didit ^ ((pPriv0->val | pPriv1->val) & 1)) {
639	if (didit) {
640	    pPriv0->val |= 1;
641	    pPriv1->val |= 1;
642	}
643	else {
644	    pPriv0->val &= 0xFFFE;
645	    pPriv1->val &= 0xFFFE;
646	}
647	if (pPriv0->on) {
648	    A(WaitForFifo)(pApm, 1);
649	    WRXW(0x82, pPriv0->val);
650	}
651	if (pPriv1->on) {
652	    A(WaitForFifo)(pApm, 1);
653	    WRXW(0x92, pPriv1->val);
654	}
655    }
656
657    return Success;
658}
659
660static int
661A(PutImage)(ScrnInfoPtr pScrn, short src_x, short src_y,
662	      short drw_x, short drw_y, short src_w, short src_h,
663	      short drw_w, short drw_h, int id, unsigned char* buf,
664	      short width, short height, Bool sync, RegionPtr clipBoxes,
665	      pointer data, DrawablePtr pDraw)
666{
667    ApmPortPrivPtr	pPriv = (ApmPortPrivPtr)data;
668    ScreenPtr	pScreen = pScrn->pScreen;
669    APMDECL(pScrn);
670    INT32	x1, x2, y1, y2;
671    unsigned char	*dst_start;
672    int		pitch, Bpp, new_h, offset = 0, offset2 = 0, offset3 = 0;
673    CARD32	mask;
674    FBAreaPtr	area;
675    int		srcPitch, dstPitch, srcPitch2 = 0;
676    int		top, left, npixels, nlines;
677    BoxRec	dstBox;
678    CARD32	scalex, scaley, scale;
679    CARD32	tmp;
680    Bool	offscreen;
681
682    offscreen = (buf < (unsigned char *)pApm->FbBase ||
683		    buf > (unsigned char *)pApm->FbBase + 0x400000);
684
685    if(drw_w > 16384) drw_w = 16384;
686
687    /* Clip */
688    x1 = src_x;
689    x2 = src_x + src_w;
690    y1 = src_y;
691    y2 = src_y + src_h;
692
693    dstBox.x1 = drw_x;
694    dstBox.x2 = drw_x + drw_w;
695    dstBox.y1 = drw_y;
696    dstBox.y2 = drw_y + drw_h;
697
698    mask = pApm->CurrentLayout.mask32;
699
700    ApmClipVideo(&dstBox, &x1, &x2, &y1, &y2,
701		REGION_EXTENTS(pScreen, clipBoxes), width, height,
702		&scalex, &scaley, mask);
703
704    pPriv->drw_x = drw_x;
705    pPriv->drw_y = drw_y;
706    pPriv->xnum = drw_w;
707    if (scalex)
708	pPriv->xden = src_w;
709    else
710	pPriv->xden = drw_w;	/* If image is larger than window */
711    pPriv->ynum = drw_h;
712    if (scaley)
713	pPriv->yden = src_h;
714    else
715	pPriv->yden = drw_h;
716    if((x1 - x2 >= 0xFFFF) || (y1 - y2 >= 0xFFFF))
717     return Success;
718
719    Bpp = pScrn->bitsPerPixel >> 3;
720    pitch = Bpp * pScrn->displayWidth;
721
722    switch(id) {
723    case 0x32315659:
724	dstPitch = ((width << 1) + 3) & ~3;
725	srcPitch = (width + 3) & ~3;
726	offset2 = srcPitch * height;
727	srcPitch2 = ((width >> 1) + 3) & ~3;
728	offset = srcPitch2 * (height >> 1);
729	offset3 = offset + offset2;
730	new_h = (2 * offset2 + pitch - 1) / pitch;
731	break;
732    case 0x59595959:
733	srcPitch = width;
734	dstPitch = (srcPitch + 3) & ~3;
735	offset = dstPitch * height;
736	new_h = (offset + pitch - 1) / pitch;
737	break;
738    case 0x32335652:
739	srcPitch = (width << 2);
740	dstPitch = (srcPitch + 3) & ~3;
741	offset = dstPitch * height;
742	new_h = (offset + pitch - 1) / pitch;
743	break;
744    default:
745	if (pApm->PutImageStride)
746	    srcPitch = pApm->PutImageStride;
747	else
748	    srcPitch = (width << 1);
749	dstPitch = (srcPitch + 3) & ~3;
750	offset = dstPitch * height;
751	new_h = (offset + pitch - 1) / pitch;
752	break;
753    }
754
755    area = pPriv->area;
756
757    /* Allocate offscreen memory */
758    if (offscreen && (!area || ((area->box.y2 - area->box.y1) < new_h))) {
759	Bool nukeMem = FALSE;
760	int max_w, max_h;
761
762	xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
763			  FAVOR_WIDTH_THEN_AREA, PRIORITY_LOW);
764	if (max_w == pScrn->displayWidth && max_h >= new_h) {
765	    area = xf86AllocateOffscreenArea(pScreen,
766					pScrn->displayWidth, new_h,
767					4, A(XvMoveCB), A(XvRemoveCB), pPriv);
768	    if (area) {
769		if (pPriv->area)
770		    xf86FreeOffscreenArea(pPriv->area);
771	    }
772	    else
773		area = pPriv->area;	/* Should not happen */
774	}
775	if(!area) {
776	    if(!(area = xf86AllocateOffscreenArea(pScreen,
777					pScrn->displayWidth, new_h, 4,
778					A(XvMoveCB), A(XvRemoveCB), pPriv)))
779	    {
780	       nukeMem = TRUE;
781	    }
782	} else {
783	    if(!xf86ResizeOffscreenArea(area, pScrn->displayWidth, new_h)) {
784	       xf86FreeOffscreenArea(area);
785	       pPriv->area = area = NULL;
786	       nukeMem = TRUE;
787	    }
788	}
789	if(nukeMem) {
790	    xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
791			    FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);
792
793	    if((max_w < pScrn->displayWidth) || (max_h < new_h))
794		return BadAlloc;
795
796	    xf86PurgeUnlockedOffscreenAreas(pScreen);
797
798	    area = xf86AllocateOffscreenArea(pScreen,
799					pScrn->displayWidth, new_h, 4,
800					A(XvMoveCB), A(XvRemoveCB), pPriv);
801	}
802
803	pPriv->area = area;
804    }
805
806    /* copy data */
807    pPriv->x1 = dstBox.x1 /*drw_x*/;
808    pPriv->y1 = dstBox.y1 /*drw_y*/;
809    top = y1 >> 16;
810    left = (x1 >> 16) & ~1;
811    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
812
813    switch(id) {
814    case 0x59595959:
815	pPriv->Bpp = 1;
816	break;
817    default:
818	pPriv->Bpp = 2;
819	left <<= 1;
820	break;
821    case 0x32335652:
822	pPriv->Bpp = 4;
823	left <<= 2;
824	break;
825    }
826    pPriv->Bps = pPriv->Bpp * pPriv->xden;
827    if (offscreen) {
828	offset = (area->box.y1 * pitch) + (top * dstPitch);
829	dst_start = ((unsigned char *)pApm->FbBase) +
830						(pPriv->data = offset + left);
831	switch(id) {
832	case 0x32315659:
833	    top &= ~1;
834	    tmp = ((top >> 1) * srcPitch2) + (left >> 2);
835	    offset2 += tmp;
836	    offset3 += tmp;
837	    nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
838	    xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
839				    buf + offset2, buf + offset3, dst_start,
840				    srcPitch, srcPitch2, dstPitch,
841				    nlines, npixels);
842	    break;
843	default:
844	    if (id == 0x32335652)
845		npixels <<= 1;
846	    else if (id == 0x59595959)
847		npixels >>= 1;
848	    buf += (top * srcPitch) + left;
849	    nlines = ((y2 + 0xffff) >> 16) - top;
850	    if (offscreen)
851		xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch,
852				 nlines, npixels);
853	    break;
854	}
855    }
856    else
857	pPriv->data = buf - (unsigned char *)pApm->FbBase;
858    pPriv->on = 1;
859    A(WaitForFifo)(pApm, 3);
860    WRXW(pPriv->reg + 0x02, dstPitch >> 2);
861    WRXW(pPriv->reg + 0x04, scalex);
862    WRXW(pPriv->reg + 0x08, scaley);
863    pPriv->scalex = scalex;
864    pPriv->scaley = scaley;
865    if (scalex && scaley)
866	scale = 0x0E00;
867    else if (scalex)
868	scale = 0x0600;
869    else if (scaley)
870	scale = 0x0A00;
871    else
872	scale = 0;
873    switch(id) {
874    case 0x59595959:
875	pPriv->val = 0x017B | scale;
876	break;
877    case 0x32335652:
878	pPriv->val = 0x002F | (scale & 0xF7FF);/*Smoothing filter doesn't work*/
879	break;
880    case 0x36315652:
881	pPriv->val = 0x002B | (scale & 0xF7FF);
882	break;
883    case 0x35315652:
884	pPriv->val = 0x0029 | (scale & 0xF7FF);
885	break;
886    case 0x59555956:
887	pPriv->val = 0x013B | scale;
888	break;
889    case 0x55595659:
890	pPriv->val = 0x014B | scale;
891	break;
892    case 0x32315659:
893    case 0x59565955:
894    default:
895	pPriv->val = 0x016B | scale;
896	break;
897    }
898
899    (void) A(ReputImage)(pScrn, drw_x, drw_y, clipBoxes, data, pDraw);
900
901    A(WaitForFifo)(pApm, 1);
902    WRXW(pPriv->reg, pPriv->val);
903
904    return Success;
905}
906
907#ifndef IOP_ACCESS
908static int
909ApmQueryImageAttributes(ScrnInfoPtr pScrn, int id,
910			  unsigned short *w, unsigned short *h,
911			  int *pitches, int *offsets)
912{
913    int size, tmp;
914
915    if(*w > 1024) *w = 1024;
916    if(*h > 1024) *h = 1024;
917
918    *w = (*w + 1) & ~1;
919    if(offsets) offsets[0] = 0;
920
921    switch(id) {
922    case 0x32315659:
923	*h = (*h + 1) & ~1;
924	size = (*w + 3) & ~3;
925	if(pitches) pitches[0] = size;
926	size *= *h;
927	if(offsets) offsets[1] = size;
928	tmp = ((*w >> 1) + 3) & ~3;
929	if(pitches) pitches[1] = pitches[2] = tmp;
930	tmp *= (*h >> 1);
931	size += tmp;
932	if(offsets) offsets[2] = size;
933	size += tmp;
934	break;
935    case 0x59565955:
936    case 0x55595659:
937    case 0x59555956:
938    case 0x32595559:
939	size = *w << 1;
940	goto common;
941    case 0x59595959:
942    default:
943	size = *w;
944common:
945	if (pitches)
946	    pitches[0] = size;
947	size *= *h;
948	break;
949    }
950
951    return size;
952}
953#endif
954#endif
955