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