1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#include "xf86.h"
7#include "xf86_OSproc.h"
8#include "compiler.h"
9#include "xf86Pci.h"
10#include "xf86fbman.h"
11#include "regionstr.h"
12
13#include "ct_driver.h"
14#include <X11/extensions/Xv.h>
15#include "dixstruct.h"
16#include "fourcc.h"
17
18#define OFF_DELAY 	200  /* milliseconds */
19#define FREE_DELAY 	60000
20
21#define OFF_TIMER 	0x01
22#define FREE_TIMER	0x02
23#define CLIENT_VIDEO_ON	0x04
24
25#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
26
27static XF86VideoAdaptorPtr CHIPSSetupImageVideo(ScreenPtr);
28static void CHIPSInitOffscreenImages(ScreenPtr);
29static void CHIPSStopVideo(ScrnInfoPtr, pointer, Bool);
30static int CHIPSSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
31static int CHIPSGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
32static void CHIPSQueryBestSize(ScrnInfoPtr, Bool,
33	short, short, short, short, unsigned int *, unsigned int *, pointer);
34static int CHIPSPutImage( ScrnInfoPtr,
35	short, short, short, short, short, short, short, short,
36	int, unsigned char*, short, short, Bool, RegionPtr, pointer,
37	DrawablePtr);
38static int CHIPSQueryImageAttributes(ScrnInfoPtr,
39	int, unsigned short *, unsigned short *,  int *, int *);
40static void CHIPSVideoTimerCallback(ScrnInfoPtr pScrn, Time time);
41
42
43#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
44
45static Atom xvColorKey;
46
47void
48CHIPSInitVideo(ScreenPtr pScreen)
49{
50    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
51    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
52    XF86VideoAdaptorPtr newAdaptor = NULL;
53    CHIPSPtr cPtr = CHIPSPTR(pScrn);
54    int num_adaptors;
55
56    if ((cPtr->Flags & ChipsVideoSupport)) {
57	newAdaptor = CHIPSSetupImageVideo(pScreen);
58	CHIPSInitOffscreenImages(pScreen);
59    }
60
61    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
62
63    if(newAdaptor) {
64	if(!num_adaptors) {
65	    num_adaptors = 1;
66	    adaptors = &newAdaptor;
67	} else {
68	    newAdaptors =  /* need to free this someplace */
69		malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
70	    if(newAdaptors) {
71		memcpy(newAdaptors, adaptors, num_adaptors *
72					sizeof(XF86VideoAdaptorPtr));
73		newAdaptors[num_adaptors] = newAdaptor;
74		adaptors = newAdaptors;
75		num_adaptors++;
76	    }
77	}
78    }
79
80    if(num_adaptors)
81        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
82
83    free(newAdaptors);
84}
85
86/* client libraries expect an encoding */
87static
88XF86VideoEncodingRec DummyEncoding[1] =
89{
90 {
91   0,
92   "XV_IMAGE",
93   1024, 1024,
94   {1, 1}
95 }
96};
97
98#define NUM_FORMATS 4
99
100static XF86VideoFormatRec Formats[NUM_FORMATS] =
101{
102  {8, PseudoColor},  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
103};
104
105#define NUM_ATTRIBUTES 1
106
107static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
108{
109   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}
110};
111
112#define NUM_IMAGES 4
113
114static XF86ImageRec Images[NUM_IMAGES] =
115{
116   {
117	0x35315652,
118        XvRGB,
119	LSBFirst,
120	{'R','V','1','5',
121	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
122	16,
123	XvPacked,
124	1,
125	15, 0x7C00, 0x03E0, 0x001F,
126	0, 0, 0,
127	0, 0, 0,
128	0, 0, 0,
129	{'R','V','B',0,
130	  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},
131	XvTopToBottom
132   },
133   {
134	0x36315652,
135        XvRGB,
136	LSBFirst,
137	{'R','V','1','6',
138	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
139	16,
140	XvPacked,
141	1,
142	16, 0xF800, 0x07E0, 0x001F,
143	0, 0, 0,
144	0, 0, 0,
145	0, 0, 0,
146	{'R','V','B',0,
147	  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},
148	XvTopToBottom
149   },
150   XVIMAGE_YV12,
151   XVIMAGE_YUY2
152};
153
154typedef struct {
155   FBLinearPtr	linear;
156   RegionRec	clip;
157   CARD32	colorKey;
158   CARD32	videoStatus;
159   Time		offTime;
160   Time		freeTime;
161   Bool         doubleBuffer;
162   Bool         manualDoubleBuffer;
163   int          currentBuffer;
164} CHIPSPortPrivRec, *CHIPSPortPrivPtr;
165
166
167#define GET_PORT_PRIVATE(pScrn) \
168   (CHIPSPortPrivPtr)((CHIPSPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
169
170void
171CHIPSResetVideo(ScrnInfoPtr pScrn)
172{
173    CHIPSPtr cPtr = CHIPSPTR(pScrn);
174    CHIPSPortPrivPtr pPriv = cPtr->adaptor->pPortPrivates[0].ptr;
175    unsigned char mr3c;
176    int red, green, blue;
177
178#ifdef HAVE_XAA_H
179    if (cPtr->Flags & ChipsAccelSupport)
180	CHIPSHiQVSync(pScrn);
181#endif
182
183    mr3c = cPtr->readMR(cPtr, 0x3C);
184    cPtr->writeMR(cPtr, 0x3C, (mr3c | 0x6));
185    switch (pScrn->depth) {
186    case 8:
187	cPtr->writeMR(cPtr, 0x3D, 0x00);
188	cPtr->writeMR(cPtr, 0x3E, 0x00);
189	cPtr->writeMR(cPtr, 0x3F, (pPriv->colorKey & 0xFF));
190	cPtr->writeMR(cPtr, 0x40, 0xFF);
191	cPtr->writeMR(cPtr, 0x41, 0xFF);
192	cPtr->writeMR(cPtr, 0x42, 0x00);
193	break;
194    default:
195	red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
196	green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
197	blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
198	switch (pScrn->depth) {
199	case 15:
200	    cPtr->writeMR(cPtr, 0x3D, (red << 3));
201	    cPtr->writeMR(cPtr, 0x3E, (green << 3));
202	    cPtr->writeMR(cPtr, 0x3F, (blue << 3));
203	    cPtr->writeMR(cPtr, 0x40, 0x07);
204	    cPtr->writeMR(cPtr, 0x41, 0x07);
205	    cPtr->writeMR(cPtr, 0x42, 0x07);
206	    break;
207	case 16:
208	    cPtr->writeMR(cPtr, 0x3D, (red << 3));
209	    cPtr->writeMR(cPtr, 0x3E, (green << 2));
210	    cPtr->writeMR(cPtr, 0x3F, (blue << 3));
211	    cPtr->writeMR(cPtr, 0x40, 0x07);
212	    cPtr->writeMR(cPtr, 0x41, 0x03);
213	    cPtr->writeMR(cPtr, 0x42, 0x07);
214	    break;
215	case 24:
216	    cPtr->writeMR(cPtr, 0x3D, red);
217	    cPtr->writeMR(cPtr, 0x3E, green);
218	    cPtr->writeMR(cPtr, 0x3F, blue);
219	    cPtr->writeMR(cPtr, 0x40, 0x00);
220	    cPtr->writeMR(cPtr, 0x41, 0x00);
221	    cPtr->writeMR(cPtr, 0x42, 0x00);
222	    break;
223	}
224    }
225}
226
227
228static XF86VideoAdaptorPtr
229CHIPSSetupImageVideo(ScreenPtr pScreen)
230{
231    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
232    CHIPSPtr cPtr = CHIPSPTR(pScrn);
233    XF86VideoAdaptorPtr adapt;
234    CHIPSPortPrivPtr pPriv;
235
236    if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
237			   sizeof(CHIPSPortPrivRec) +
238			   sizeof(DevUnion))))
239	return NULL;
240
241    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
242    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
243    adapt->name = "Chips and Technologies Backend Scaler";
244    adapt->nEncodings = 1;
245    adapt->pEncodings = DummyEncoding;
246    adapt->nFormats = NUM_FORMATS;
247    adapt->pFormats = Formats;
248    adapt->nPorts = 1;
249    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
250    pPriv = (CHIPSPortPrivPtr)(&adapt->pPortPrivates[1]);
251    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
252    adapt->pAttributes = Attributes;
253    adapt->nImages = NUM_IMAGES;
254    adapt->nAttributes = NUM_ATTRIBUTES;
255    adapt->pImages = Images;
256    adapt->PutVideo = NULL;
257    adapt->PutStill = NULL;
258    adapt->GetVideo = NULL;
259    adapt->GetStill = NULL;
260    adapt->StopVideo = CHIPSStopVideo;
261    adapt->SetPortAttribute = CHIPSSetPortAttribute;
262    adapt->GetPortAttribute = CHIPSGetPortAttribute;
263    adapt->QueryBestSize = CHIPSQueryBestSize;
264    adapt->PutImage = CHIPSPutImage;
265    adapt->QueryImageAttributes = CHIPSQueryImageAttributes;
266
267    pPriv->colorKey = cPtr->videoKey;
268    pPriv->videoStatus = 0;
269    pPriv->manualDoubleBuffer = FALSE;
270    pPriv->currentBuffer	= 0;
271
272    /* gotta uninit this someplace */
273    REGION_NULL(pScreen, &pPriv->clip);
274
275    cPtr->adaptor = adapt;
276
277    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
278
279    CHIPSResetVideo(pScrn);
280
281    return adapt;
282}
283
284
285static void
286CHIPSStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shadow)
287{
288  CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
289  CHIPSPtr cPtr = CHIPSPTR(pScrn);
290  unsigned char mr3c, tmp;
291
292  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
293#ifdef HAVE_XAA_H
294  if (cPtr->Flags & ChipsAccelSupport)
295      CHIPSHiQVSync(pScrn);
296#endif
297  if(shadow) {
298     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
299	mr3c = cPtr->readMR(cPtr, 0x3C);
300	cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
301	tmp = cPtr->readXR(cPtr, 0xD0);
302	cPtr->writeXR(cPtr, 0xD0, (tmp & 0xf));
303     }
304     if(pPriv->linear) {
305	xf86FreeOffscreenLinear(pPriv->linear);
306	pPriv->linear = NULL;
307     }
308     pPriv->videoStatus = 0;
309  } else {
310     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
311	pPriv->videoStatus |= OFF_TIMER;
312	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
313	cPtr->VideoTimerCallback = CHIPSVideoTimerCallback;
314     }
315  }
316}
317
318static int
319CHIPSSetPortAttribute(
320  ScrnInfoPtr pScrn,
321  Atom attribute,
322  INT32 value,
323  pointer data
324){
325  CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
326  CHIPSPtr cPtr = CHIPSPTR(pScrn);
327
328#ifdef HAVE_XAA_H
329  if (cPtr->Flags & ChipsAccelSupport)
330      CHIPSHiQVSync(pScrn);
331#endif
332  if(attribute == xvColorKey) {
333	int red, green, blue;
334	pPriv->colorKey = value;
335	switch (pScrn->depth) {
336	case 8:
337	    cPtr->writeMR(cPtr, 0x3D, 0x00);
338	    cPtr->writeMR(cPtr, 0x3E, 0x00);
339	    cPtr->writeMR(cPtr, 0x3F, (pPriv->colorKey & 0xFF));
340	    break;
341	default:
342	    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
343	    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
344	    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
345	    switch (pScrn->depth) {
346	    case 15:
347		cPtr->writeMR(cPtr, 0x3D, (red << 3));
348		cPtr->writeMR(cPtr, 0x3E, (green << 3));
349		cPtr->writeMR(cPtr, 0x3F, (blue << 3));
350		break;
351	    case 16:
352		cPtr->writeMR(cPtr, 0x3D, (red << 3));
353		cPtr->writeMR(cPtr, 0x3E, (green << 2));
354		cPtr->writeMR(cPtr, 0x3F, (blue << 3));
355		break;
356	    case 24:
357		cPtr->writeMR(cPtr, 0x3D, red);
358		cPtr->writeMR(cPtr, 0x3E, green);
359		cPtr->writeMR(cPtr, 0x3F, blue);
360		break;
361	    }
362	}
363	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
364  } else return BadMatch;
365
366  return Success;
367}
368
369static int
370CHIPSGetPortAttribute(
371  ScrnInfoPtr pScrn,
372  Atom attribute,
373  INT32 *value,
374  pointer data
375){
376  CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
377
378  if(attribute == xvColorKey) {
379	*value = pPriv->colorKey;
380  } else return BadMatch;
381
382  return Success;
383}
384
385static void
386CHIPSQueryBestSize(
387  ScrnInfoPtr pScrn,
388  Bool motion,
389  short vid_w, short vid_h,
390  short drw_w, short drw_h,
391  unsigned int *p_w, unsigned int *p_h,
392  pointer data
393){
394  *p_w = drw_w;
395  *p_h = drw_h;
396
397  if(*p_w > 16384) *p_w = 16384;
398}
399
400
401static void
402CHIPSCopyData(
403  unsigned char *src,
404  unsigned char *dst,
405  int srcPitch,
406  int dstPitch,
407  int h,
408  int w
409){
410    w <<= 1;
411    while(h--) {
412	memcpy(dst, src, w);
413	src += srcPitch;
414	dst += dstPitch;
415    }
416}
417
418static void
419CHIPSCopyMungedData(
420   unsigned char *src1,
421   unsigned char *src2,
422   unsigned char *src3,
423   unsigned char *dst1,
424   int srcPitch,
425   int srcPitch2,
426   int dstPitch,
427   int h,
428   int w
429){
430   CARD32 *dst = (CARD32*)dst1;
431   int i, j;
432
433   dstPitch >>= 2;
434   w >>= 1;
435
436   for(j = 0; j < h; j++) {
437	for(i = 0; i < w; i++) {
438	    dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
439		     (src3[i] << 8) | (src2[i] << 24);
440	}
441	dst += dstPitch;
442	src1 += srcPitch;
443	if(j & 1) {
444	    src2 += srcPitch2;
445	    src3 += srcPitch2;
446	}
447   }
448}
449
450static FBLinearPtr
451CHIPSAllocateMemory(
452   ScrnInfoPtr pScrn,
453   FBLinearPtr linear,
454   int size
455){
456   ScreenPtr pScreen;
457   FBLinearPtr new_linear;
458
459   if(linear) {
460	if(linear->size >= size)
461	   return linear;
462
463        if(xf86ResizeOffscreenLinear(linear, size))
464	   return linear;
465
466	xf86FreeOffscreenLinear(linear);
467   }
468
469   pScreen = xf86ScrnToScreen(pScrn);
470
471   new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
472   						NULL, NULL, NULL);
473
474   if(!new_linear) {
475	int max_size;
476
477	xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8,
478						PRIORITY_EXTREME);
479
480	if(max_size < size)
481	   return NULL;
482
483	xf86PurgeUnlockedOffscreenAreas(pScreen);
484	new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
485						NULL, NULL, NULL);
486   }
487
488   return new_linear;
489}
490
491static int
492CHIPSSetCurrentPlaybackBuffer(CHIPSPtr cPtr, int n)
493{
494
495    CARD8 mr20;
496    mr20 = cPtr->readMR(cPtr, 0x20);
497    mr20 &= ~0x1B;
498    if (!n) mr20 |= 0x10;
499    cPtr->writeMR(cPtr, 0x22, mr20);
500    return n;
501}
502
503static int
504CHIPSWaitGetNextFrame(CHIPSPtr cPtr)
505{
506    volatile CARD8 mr20;
507    volatile CARD8 mr21;
508
509    mr20 = cPtr->readMR(cPtr, 0x20);
510    while (1) {
511      mr21 = cPtr->readMR(cPtr, 0x21);
512      if (!(mr20 & (1 << 5)) || !(mr21 & 1))
513	break;
514    }
515    mr20 &= ~0x4;
516    mr20 = cPtr->readMR(cPtr, 0x20);
517    return (mr21 & 2)? 0 : 1;
518}
519
520static void
521CHIPSDisplayVideo(
522    ScrnInfoPtr pScrn,
523    int id,
524    int offset,
525    short width, short height,
526    int pitch,
527    int x1, int y1, int x2, int y2,
528    BoxPtr dstBox,
529    short src_w, short src_h,
530    short drw_w, short drw_h,
531    Bool triggerBufSwitch
532){
533    CHIPSPtr cPtr = CHIPSPTR(pScrn);
534    CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
535    DisplayModePtr mode = pScrn->currentMode;
536    unsigned char tmp, m1f, m1e;
537    int buffer = pPriv->currentBuffer;
538    Bool dblscan = (pScrn->currentMode->Flags & V_DBLSCAN) == V_DBLSCAN;
539    int val;
540
541#ifdef HAVE_XAA_H
542    if (cPtr->Flags & ChipsAccelSupport)
543	CHIPSHiQVSync(pScrn);
544#endif
545    tmp = cPtr->readXR(cPtr, 0xD0);
546    cPtr->writeXR(cPtr, 0xD0, (tmp | 0x10));
547
548    m1e = cPtr->readMR(cPtr, 0x1E);
549    m1e &= 0xE0;		/* Set Zoom and Direction */
550    if ((!(cPtr->PanelType & ChipsLCD)) && (mode->Flags & V_INTERLACE))
551	m1e |= 0x10;
552
553    m1f = cPtr->readMR(cPtr, 0x1F);
554    m1f = (m1f & 0x14); /* Mask reserved bits, unset interpolation */
555    switch(id) {
556    case 0x35315652:		/* RGB15 */
557	m1f |= 0x09;
558	break;
559    case 0x36315652:		/* RGB16 */
560	m1f |= 0x08;
561	break;
562    case FOURCC_YV12:		/* YV12 */
563      /* m1f |= 0x03 */
564	m1f |= 0x00;
565	break;
566    case FOURCC_YUY2:		/* YUY2 */
567    default:
568	m1f |= 0x00;		/* Do nothing here */
569	break;
570    }
571
572    offset += (x1 >> 15) & ~0x01;
573    /* Setup Pointer 1 */
574    if (!buffer || pPriv->manualDoubleBuffer || !pPriv->doubleBuffer) {
575        cPtr->writeMR(cPtr, 0x22, (offset & 0xF8));
576	cPtr->writeMR(cPtr, 0x23, ((offset >> 8) & 0xFF));
577	cPtr->writeMR(cPtr, 0x24, ((offset >> 16) & 0xFF));
578    }
579
580    /* Setup Pointer 2 */
581    if ((buffer && !pPriv->manualDoubleBuffer) || !pPriv->doubleBuffer) {
582        cPtr->writeMR(cPtr, 0x25, (offset & 0xF8));
583	cPtr->writeMR(cPtr, 0x26, ((offset >> 8) & 0xFF));
584	cPtr->writeMR(cPtr, 0x27, ((offset >> 16) & 0xFF));
585    }
586
587    tmp = cPtr->readMR(cPtr, 0x04);
588    if (pPriv->doubleBuffer && !pPriv->manualDoubleBuffer && triggerBufSwitch)
589      tmp |= 0x18;
590    cPtr->writeMR(cPtr, 0x04, tmp);
591
592    tmp = cPtr->readMR(cPtr, 0x20);
593    tmp &= 0xC3;
594
595    if (pPriv->doubleBuffer && !pPriv->manualDoubleBuffer && triggerBufSwitch)
596	tmp |= ((1 << 2  | 1 << 5) | ((buffer) ? (1 << 4) : 0));
597    cPtr->writeMR(cPtr, 0x20, tmp);
598
599    cPtr->writeMR(cPtr, 0x28, ((width >> 2) - 1)); /* Width */
600    cPtr->writeMR(cPtr, 0x34, ((width >> 2) - 1));
601
602    /* Left Edge of Overlay */
603    cPtr->writeMR(cPtr, 0x2A, ((cPtr->OverlaySkewX + dstBox->x1) & 0xFF));
604    tmp = cPtr->readMR(cPtr, 0x2B);
605    tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewX + dstBox->x1) >> 8) & 0x07);
606    cPtr->writeMR(cPtr, 0x2B, tmp);
607    /* Right Edge of Overlay */
608    cPtr->writeMR(cPtr, 0x2C, ((cPtr->OverlaySkewX + dstBox->x2 -1)
609				& 0xFF));
610    tmp = cPtr->readMR(cPtr, 0x2D);
611    tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewX + dstBox->x2 - 1) >> 8) & 0x07);
612    cPtr->writeMR(cPtr, 0x2D, tmp);
613    /* Top Edge of Overlay */
614    val = cPtr->OverlaySkewY + (dstBox->y1 << (dblscan ? 1 : 0));
615    cPtr->writeMR(cPtr, 0x2E, ((val) & 0xFF));
616    tmp = cPtr->readMR(cPtr, 0x2F);
617    tmp = (tmp & 0xF8) + (((val) >> 8) & 0x07);
618    cPtr->writeMR(cPtr, 0x2F, tmp);
619    /* Bottom Edge of Overlay*/
620    val = cPtr->OverlaySkewY + (dstBox->y2 << (dblscan ? 1 : 0));
621    cPtr->writeMR(cPtr, 0x30, ((val - 1) & 0xFF));
622    tmp = cPtr->readMR(cPtr, 0x31);
623    tmp = (tmp & 0xF8) + (((val - 1) >> 8) & 0x07);
624    cPtr->writeMR(cPtr, 0x31, tmp);
625
626    /* Horizontal Zoom */
627    if (drw_w > src_w) {
628        m1f = m1f | 0x20; /* set H-interpolation */
629	m1e = m1e | 0x04;
630	tmp = cPtr->VideoZoomMax * src_w / drw_w;
631	cPtr->writeMR(cPtr, 0x32, tmp);
632    }
633
634    /* Vertical Zoom */
635    if (drw_h > src_h || dblscan) {
636        m1f = m1f | 0x80; /* set V-interpolation */
637	m1e = m1e | 0x08;
638	if (dblscan)
639	    tmp = cPtr->VideoZoomMax >> 1;
640	if (drw_h > src_h)
641           tmp = 256 * src_h / drw_h;
642       cPtr->writeMR(cPtr, 0x33, tmp & 0xFC);
643    }
644    cPtr->writeMR(cPtr, 0x1F, m1f);
645    cPtr->writeMR(cPtr, 0x1E, m1e);
646
647    tmp = cPtr->readMR(cPtr, 0x3C);
648    cPtr->writeMR(cPtr, 0x3C, (tmp | 0x7));
649#ifdef HAVE_XAA_H
650    if (cPtr->Flags & ChipsAccelSupport)
651	CHIPSHiQVSync(pScrn);
652#endif
653}
654
655static int
656CHIPSPutImage(
657  ScrnInfoPtr pScrn,
658  short src_x, short src_y,
659  short drw_x, short drw_y,
660  short src_w, short src_h,
661  short drw_w, short drw_h,
662  int id, unsigned char* buf,
663  short width, short height,
664  Bool sync,
665  RegionPtr clipBoxes, pointer data,
666  DrawablePtr pDraw
667){
668   CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
669   CHIPSPtr cPtr = CHIPSPTR(pScrn);
670   INT32 x1, x2, y1, y2;
671   unsigned char *dst_start;
672   int new_size, offset, offset2 = 0, offset3 = 0;
673   int srcPitch, srcPitch2 = 0, dstPitch;
674   int top, left, npixels, nlines, bpp;
675   BoxRec dstBox;
676   CARD32 tmp;
677
678   if(drw_w > 16384) drw_w = 16384;
679
680   /* Clip */
681   x1 = src_x;
682   x2 = src_x + src_w;
683   y1 = src_y;
684   y2 = src_y + src_h;
685
686   dstBox.x1 = drw_x;
687   dstBox.x2 = drw_x + drw_w;
688   dstBox.y1 = drw_y;
689   dstBox.y2 = drw_y + drw_h;
690
691   if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
692			      clipBoxes, width, height))
693	return Success;
694
695   dstBox.x1 -= pScrn->frameX0 & cPtr->viewportMask;
696   dstBox.x2 -= pScrn->frameX0 & cPtr->viewportMask;
697   dstBox.y1 -= pScrn->frameY0;
698   dstBox.y2 -= pScrn->frameY0;
699
700   bpp = pScrn->bitsPerPixel >> 3;
701
702   dstPitch = ((width << 1) + 15) & ~15;
703   new_size = ((dstPitch * height) + bpp - 1) / bpp;
704
705   pPriv->doubleBuffer = (pScrn->currentMode->Flags & V_DBLSCAN) != V_DBLSCAN;
706
707   if (pPriv->doubleBuffer)
708       new_size <<= 1;
709
710   switch(id) {
711   case FOURCC_YV12:		/* YV12 */
712	srcPitch = (width + 3) & ~3;
713	offset2 = srcPitch * height;
714	srcPitch2 = ((width >> 1) + 3) & ~3;
715	offset3 = (srcPitch2 * (height >> 1)) + offset2;
716	break;
717   default:			/* RGB15, RGB16, YUY2 */
718	srcPitch = (width << 1);
719	break;
720   }
721
722   if(!(pPriv->linear = CHIPSAllocateMemory(pScrn, pPriv->linear, new_size))) {
723       if (pPriv->doubleBuffer
724	   && (pPriv->linear = CHIPSAllocateMemory(pScrn, pPriv->linear,
725					      new_size >> 1))) {
726         new_size >>= 1;
727	 pPriv->doubleBuffer = FALSE;
728   } else
729	return BadAlloc;
730   }
731
732   /* copy data */
733   top = y1 >> 16;
734   left = (x1 >> 16) & ~1;
735   npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
736   left <<= 1;
737
738   offset = pPriv->linear->offset * bpp;
739   if (!pPriv->manualDoubleBuffer)
740     pPriv->currentBuffer = CHIPSWaitGetNextFrame(cPtr);
741   if(pPriv->doubleBuffer && pPriv->currentBuffer)
742	offset += (new_size * bpp) >> 1;
743
744   dst_start = cPtr->FbBase + offset + left + (top * dstPitch);
745
746   switch(id) {
747   case FOURCC_YV12:		/* YV12 */
748        top &= ~1;
749	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
750	offset2 += tmp;
751	offset3 += tmp;
752	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
753	CHIPSCopyMungedData(buf + (top * srcPitch) + (left >> 1),
754			  buf + offset2, buf + offset3, dst_start,
755			  srcPitch, srcPitch2, dstPitch, nlines, npixels);
756	break;
757   default:			/* RGB15, RGB16, YUY2 */
758	buf += (top * srcPitch) + left;
759	nlines = ((y2 + 0xffff) >> 16) - top;
760	CHIPSCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
761	break;
762   }
763
764   /* update cliplist */
765   if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
766	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
767        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
768   }
769
770   offset += top * dstPitch;
771   CHIPSDisplayVideo(pScrn, id, offset, width, height, dstPitch,
772	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, TRUE);
773
774   pPriv->videoStatus = CLIENT_VIDEO_ON;
775
776   if (pPriv->manualDoubleBuffer)
777     pPriv->currentBuffer ^= 1;
778
779   return Success;
780}
781
782static int
783CHIPSQueryImageAttributes(
784  ScrnInfoPtr pScrn,
785  int id,
786  unsigned short *w, unsigned short *h,
787  int *pitches, int *offsets
788){
789    int size, tmp;
790
791    if(*w > 1024) *w = 1024;
792    if(*h > 1024) *h = 1024;
793
794    *w = (*w + 1) & ~1;
795    if(offsets) offsets[0] = 0;
796
797    switch(id) {
798    case FOURCC_YV12:		/* YV12 */
799	*h = (*h + 1) & ~1;
800	size = (*w + 3) & ~3;
801	if(pitches) pitches[0] = size;
802	size *= *h;
803	if(offsets) offsets[1] = size;
804	tmp = ((*w >> 1) + 3) & ~3;
805	if(pitches) pitches[1] = pitches[2] = tmp;
806	tmp *= (*h >> 1);
807	size += tmp;
808	if(offsets) offsets[2] = size;
809	size += tmp;
810	break;
811    default:			/* RGB15, RGB16, YUY2 */
812	size = *w << 1;
813	if(pitches) pitches[0] = size;
814	size *= *h;
815	break;
816    }
817
818    return size;
819}
820
821
822static void
823CHIPSVideoTimerCallback(ScrnInfoPtr pScrn, Time time)
824{
825    CHIPSPtr    cPtr = CHIPSPTR(pScrn);
826    CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
827    unsigned char mr3c;
828
829    if(pPriv->videoStatus & TIMER_MASK) {
830	if(pPriv->videoStatus & OFF_TIMER) {
831	    if(pPriv->offTime < time) {
832#ifdef HAVE_XAA_H
833		if (cPtr->Flags & ChipsAccelSupport)
834		    CHIPSHiQVSync(pScrn);
835#endif
836		mr3c = cPtr->readMR(cPtr, 0x3C);
837		cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
838		pPriv->videoStatus = FREE_TIMER;
839		pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
840	    }
841	} else {  /* FREE_TIMER */
842	    if(pPriv->freeTime < time) {
843		if(pPriv->linear) {
844		   xf86FreeOffscreenLinear(pPriv->linear);
845		   pPriv->linear = NULL;
846		}
847		pPriv->videoStatus = 0;
848	        cPtr->VideoTimerCallback = NULL;
849	    }
850        }
851    } else  /* shouldn't get here */
852	cPtr->VideoTimerCallback = NULL;
853}
854
855
856/****************** Offscreen stuff ***************/
857
858typedef struct {
859  FBLinearPtr linear;
860  Bool isOn;
861} OffscreenPrivRec, * OffscreenPrivPtr;
862
863static int
864CHIPSAllocateSurface(
865    ScrnInfoPtr pScrn,
866    int id,
867    unsigned short w,
868    unsigned short h,
869    XF86SurfacePtr surface
870){
871    FBLinearPtr linear;
872    int pitch, size, bpp;
873    OffscreenPrivPtr pPriv;
874
875    if((w > 1024) || (h > 1024))
876	return BadAlloc;
877
878    w = (w + 1) & ~1;
879    pitch = ((w << 1) + 15) & ~15;
880    bpp = pScrn->bitsPerPixel >> 3;
881    size = ((pitch * h) + bpp - 1) / bpp;
882
883    if(!(linear = CHIPSAllocateMemory(pScrn, NULL, size)))
884	return BadAlloc;
885
886    surface->width = w;
887    surface->height = h;
888
889    if(!(surface->pitches = malloc(sizeof(int)))) {
890	xf86FreeOffscreenLinear(linear);
891	return BadAlloc;
892    }
893    if(!(surface->offsets = malloc(sizeof(int)))) {
894	free(surface->pitches);
895	xf86FreeOffscreenLinear(linear);
896	return BadAlloc;
897    }
898    if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
899	free(surface->pitches);
900	free(surface->offsets);
901	xf86FreeOffscreenLinear(linear);
902	return BadAlloc;
903    }
904
905    pPriv->linear = linear;
906    pPriv->isOn = FALSE;
907
908    surface->pScrn = pScrn;
909    surface->id = id;
910    surface->pitches[0] = pitch;
911    surface->offsets[0] = linear->offset * bpp;
912    surface->devPrivate.ptr = (pointer)pPriv;
913
914    return Success;
915}
916
917static int
918CHIPSStopSurface(
919    XF86SurfacePtr surface
920){
921    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
922
923    if(pPriv->isOn) {
924	CHIPSPtr cPtr = CHIPSPTR(surface->pScrn);
925	unsigned char mr3c, tmp;
926	tmp = cPtr->readXR(cPtr, 0xD0);
927	cPtr->writeXR(cPtr, 0xD0, (tmp & 0xf));
928	mr3c = cPtr->readMR(cPtr, 0x3C);
929	cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
930	pPriv->isOn = FALSE;
931    }
932
933    return Success;
934}
935
936
937static int
938CHIPSFreeSurface(
939    XF86SurfacePtr surface
940){
941    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
942
943    if(pPriv->isOn)
944	CHIPSStopSurface(surface);
945    xf86FreeOffscreenLinear(pPriv->linear);
946    free(surface->pitches);
947    free(surface->offsets);
948    free(surface->devPrivate.ptr);
949
950    return Success;
951}
952
953static int
954CHIPSGetSurfaceAttribute(
955    ScrnInfoPtr pScrn,
956    Atom attribute,
957    INT32 *value
958){
959    return CHIPSGetPortAttribute(pScrn, attribute, value,
960			(pointer)(GET_PORT_PRIVATE(pScrn)));
961}
962
963static int
964CHIPSSetSurfaceAttribute(
965    ScrnInfoPtr pScrn,
966    Atom attribute,
967    INT32 value
968){
969    return CHIPSSetPortAttribute(pScrn, attribute, value,
970			(pointer)(GET_PORT_PRIVATE(pScrn)));
971}
972
973
974static int
975CHIPSDisplaySurface(
976    XF86SurfacePtr surface,
977    short src_x, short src_y,
978    short drw_x, short drw_y,
979    short src_w, short src_h,
980    short drw_w, short drw_h,
981    RegionPtr clipBoxes
982){
983    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
984    ScrnInfoPtr pScrn = surface->pScrn;
985    CHIPSPtr cPtr = CHIPSPTR(pScrn);
986    CHIPSPortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
987    INT32 x1, y1, x2, y2;
988    BoxRec dstBox;
989
990    x1 = src_x;
991    x2 = src_x + src_w;
992    y1 = src_y;
993    y2 = src_y + src_h;
994
995    dstBox.x1 = drw_x;
996    dstBox.x2 = drw_x + drw_w;
997    dstBox.y1 = drw_y;
998    dstBox.y2 = drw_y + drw_h;
999
1000    if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
1001			      surface->width, surface->height))
1002	return Success;
1003
1004    dstBox.x1 -= pScrn->frameX0;
1005    dstBox.x2 -= pScrn->frameX0;
1006    dstBox.y1 -= pScrn->frameY0;
1007    dstBox.y2 -= pScrn->frameY0;
1008
1009    if (portPriv->doubleBuffer)
1010      portPriv->currentBuffer = CHIPSSetCurrentPlaybackBuffer(cPtr,0);
1011    else
1012      portPriv->currentBuffer = 0;
1013
1014    CHIPSDisplayVideo(pScrn, surface->id, surface->offsets[0],
1015	     surface->width, surface->height, surface->pitches[0],
1016	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, FALSE);
1017    xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
1018
1019    pPriv->isOn = TRUE;
1020    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
1021	REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
1022	UpdateCurrentTime();
1023	portPriv->videoStatus = FREE_TIMER;
1024	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1025	cPtr->VideoTimerCallback = CHIPSVideoTimerCallback;
1026    }
1027
1028    return Success;
1029}
1030
1031
1032static void
1033CHIPSInitOffscreenImages(ScreenPtr pScreen)
1034{
1035    XF86OffscreenImagePtr offscreenImages;
1036
1037    /* need to free this someplace */
1038    if(!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
1039	return;
1040
1041    offscreenImages[0].image = &Images[0];
1042    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
1043			       VIDEO_CLIP_TO_VIEWPORT;
1044    offscreenImages[0].alloc_surface = CHIPSAllocateSurface;
1045    offscreenImages[0].free_surface = CHIPSFreeSurface;
1046    offscreenImages[0].display = CHIPSDisplaySurface;
1047    offscreenImages[0].stop = CHIPSStopSurface;
1048    offscreenImages[0].setAttribute = CHIPSSetSurfaceAttribute;
1049    offscreenImages[0].getAttribute = CHIPSGetSurfaceAttribute;
1050    offscreenImages[0].max_width = 1024;
1051    offscreenImages[0].max_height = 1024;
1052    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
1053    offscreenImages[0].attributes = Attributes;
1054
1055    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
1056}
1057