trident_video.c revision 14330f12
1/*
2 * Copyright 1992-2003 by Alan Hourihane, North Wales, UK.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Alan Hourihane not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Alan Hourihane makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as is" without express or implied warranty.
13 *
14 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Author:  Alan Hourihane, alanh@fairlite.demon.co.uk
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "xf86.h"
30#include "xf86_OSproc.h"
31#include "compiler.h"
32#include "xf86PciInfo.h"
33#include "xf86Pci.h"
34#include "xf86fbman.h"
35#include "regionstr.h"
36
37#include "trident.h"
38#include "trident_regs.h"
39#include <X11/extensions/Xv.h>
40#include "xaa.h"
41#include "xaalocal.h"
42#include "dixstruct.h"
43#include "fourcc.h"
44
45#define OFF_DELAY 	800  /* milliseconds */
46#define FREE_DELAY 	60000
47
48#define OFF_TIMER 	0x01
49#define FREE_TIMER	0x02
50#define CLIENT_VIDEO_ON	0x04
51
52#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
53
54static XF86VideoAdaptorPtr TRIDENTSetupImageVideo(ScreenPtr);
55static void TRIDENTInitOffscreenImages(ScreenPtr);
56static void TRIDENTStopVideo(ScrnInfoPtr, pointer, Bool);
57static int TRIDENTSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
58static int TRIDENTGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
59static void TRIDENTQueryBestSize(ScrnInfoPtr, Bool,
60	short, short, short, short, unsigned int *, unsigned int *, pointer);
61static int TRIDENTPutImage( ScrnInfoPtr,
62	short, short, short, short, short, short, short, short,
63	int, unsigned char*, short, short, Bool, RegionPtr, pointer,
64	DrawablePtr);
65static int TRIDENTQueryImageAttributes(ScrnInfoPtr,
66	int, unsigned short *, unsigned short *,  int *, int *);
67static void TRIDENTVideoTimerCallback(ScrnInfoPtr pScrn, Time time);
68static void tridentSetVideoContrast(TRIDENTPtr pTrident,int value);
69static void tridentSetVideoParameters(TRIDENTPtr pTrident, int brightness,
70				      int saturation, int hue);
71void tridentFixFrame(ScrnInfoPtr pScrn, int *fixFrame);
72static void WaitForVBlank(ScrnInfoPtr pScrn);
73
74#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
75
76static Atom xvColorKey, xvSaturation, xvBrightness, xvHUE,  xvContrast;
77
78void TRIDENTInitVideo(ScreenPtr pScreen)
79{
80    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
81    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
82    XF86VideoAdaptorPtr newAdaptor = NULL;
83    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
84    int num_adaptors;
85
86    /*
87     * The following has been tested on:
88     *
89     * 9525         : flags: None
90     * Image985     : flags: None
91     * Cyber9397(DVD) : flags: VID_ZOOM_NOMINI
92     * CyberBlade/i7: flags: VID_ZOOM_INV | VID_ZOOM_MINI
93     * CyberBlade/i1: flags: VID_ZOOM_INV | VID_ZOOM_MINI
94     * CyberBlade/Ai1: flags: VID_ZOOM_INV
95     * Cyber 9540   : flags: VID_ZOOM_INV | VID_SHIFT_4
96     * CyberXPm8    : flags: VID_ZOOM_INV | VID_SHIFT_4
97     *
98     * When you make changes make sure not to break these
99     * Add new chipsets to this list.
100     */
101    if (pTrident->Chipset >= BLADE3D) {
102       pTrident->videoFlags = VID_ZOOM_INV ;
103       if (pTrident->Chipset <= CYBERBLADEI1D)
104	 pTrident->videoFlags |= VID_ZOOM_MINI;
105       else if (pTrident->Chipset < CYBERBLADEAI1 /* verified EE */
106		|| pTrident->Chipset > CYBERBLADEAI1D)
107	 pTrident->videoFlags |= VID_OFF_SHIFT_4;
108    }
109    if (pTrident->Chipset == CYBER9397 || pTrident->Chipset == CYBER9397DVD)
110	pTrident->videoFlags = VID_ZOOM_NOMINI;
111
112    if (pTrident->Chipset == CYBER9397DVD ||
113	pTrident->Chipset == CYBER9525DVD ||
114	(pTrident->Chipset >= BLADE3D && pTrident->Chipset < CYBERBLADEXP4))
115		pTrident->videoFlags |= VID_DOUBLE_LINEBUFFER_FOR_WIDE_SRC;
116
117    newAdaptor = TRIDENTSetupImageVideo(pScreen);
118    TRIDENTInitOffscreenImages(pScreen);
119
120    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
121
122    if(newAdaptor) {
123	if(!num_adaptors) {
124	    num_adaptors = 1;
125	    adaptors = &newAdaptor;
126	} else {
127	    newAdaptors =  /* need to free this someplace */
128		malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
129	    if(newAdaptors) {
130		memcpy(newAdaptors, adaptors, num_adaptors *
131					sizeof(XF86VideoAdaptorPtr));
132		newAdaptors[num_adaptors] = newAdaptor;
133		adaptors = newAdaptors;
134		num_adaptors++;
135	    }
136	}
137    }
138
139    if(num_adaptors)
140        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
141
142    if(newAdaptors)
143	free(newAdaptors);
144
145    if (pTrident->videoFlags)
146	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,3,
147		       "Trident Video Flags: %s %s %s %s\n",
148		   pTrident->videoFlags & VID_ZOOM_INV ? "VID_ZOOM_INV" : "",
149		   pTrident->videoFlags & VID_ZOOM_MINI ? "VID_ZOOM_MINI" : "",                   pTrident->videoFlags & VID_OFF_SHIFT_4 ? "VID_OFF_SHIFT_4"
150		   : "",
151		   pTrident->videoFlags & VID_ZOOM_NOMINI ? "VID_ZOOM_NOMINI"
152		   : "");
153
154}
155
156/* client libraries expect an encoding */
157static XF86VideoEncodingRec DummyEncoding[1] =
158{
159 {
160   0,
161   "XV_IMAGE",
162   1024, 1024,
163   {1, 1}
164 }
165};
166
167#define NUM_FORMATS 4
168
169static XF86VideoFormatRec Formats[NUM_FORMATS] =
170{
171  {8, PseudoColor},  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
172};
173
174#define NUM_ATTRIBUTES 5
175
176static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
177{
178    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
179    {XvSettable | XvGettable, 0, 187,           "XV_SATURATION"},
180    {XvSettable | XvGettable, 0, 0x3F,          "XV_BRIGHTNESS"},
181    {XvSettable | XvGettable, 0, 360 ,          "XV_HUE"},
182    {XvSettable | XvGettable, 0, 7,           "XV_CONTRAST"}
183};
184
185#define NUM_IMAGES 3
186
187static XF86ImageRec Images[NUM_IMAGES] =
188{
189   {
190	0x36315652,
191        XvRGB,
192	LSBFirst,
193	{'R','V','1','6',
194	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
195	16,
196	XvPacked,
197	1,
198	16, 0xF800, 0x07E0, 0x001F,
199	0, 0, 0,
200	0, 0, 0,
201	0, 0, 0,
202	{'R','V','B',0,
203	  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},
204	XvTopToBottom
205   },
206   XVIMAGE_YV12,
207   XVIMAGE_YUY2
208};
209
210typedef struct {
211   FBLinearPtr	linear;
212   RegionRec	clip;
213   CARD32	colorKey;
214   CARD8        Saturation;
215   CARD8        Brightness;
216   CARD16       HUE;
217   INT8         Contrast;
218   CARD32	videoStatus;
219   Time		offTime;
220   Time		freeTime;
221   int          fixFrame;
222} TRIDENTPortPrivRec, *TRIDENTPortPrivPtr;
223
224
225#define GET_PORT_PRIVATE(pScrn) \
226   (TRIDENTPortPrivPtr)((TRIDENTPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
227
228void TRIDENTResetVideo(ScrnInfoPtr pScrn)
229{
230    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
231    TRIDENTPortPrivPtr pPriv = pTrident->adaptor->pPortPrivates[0].ptr;
232    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
233    int red, green, blue;
234    int tmp;
235
236    WaitForVBlank(pScrn);
237    OUTW(vgaIOBase + 4, 0x848E);
238
239    if (pTrident->Chipset >= CYBER9388) {
240    	OUTW(vgaIOBase + 4, 0x80B9);
241    	OUTW(vgaIOBase + 4, 0x00BE);
242    	OUTW(0x3C4, 0xC057);
243    	OUTW(0x3C4, 0x3420);
244    	OUTW(0x3C4, 0x3037);
245    } else {
246	if (pTrident->Chipset >= PROVIDIA9682) {
247    	    OUTB(0x83C8, 0x57);
248    	    OUTB(0x83C6, 0xC0);
249    	    OUTW(vgaIOBase + 4, 0x26BE);
250	} else {
251    	    OUTB(0x83C8, 0x37);
252    	    OUTB(0x83C6, 0x01);
253    	    OUTB(0x83C8, 0x00);
254    	    OUTB(0x83C6, 0x00);
255	}
256    }
257
258    if (pTrident->Chipset >= BLADEXP) {
259	OUTW(0x3C4, 0x007A);
260	OUTW(0x3C4, 0x007D);
261    }
262    if (pTrident->Chipset == CYBERBLADEXP4) {
263    	OUTW(0x3CE, 0x0462);
264    }
265    switch (pScrn->depth) {
266    case 8:
267	VIDEOOUT(pPriv->colorKey, pTrident->keyOffset);
268	VIDEOOUT(0x00, (pTrident->keyOffset + 1));
269	VIDEOOUT(0x00, (pTrident->keyOffset + 2));
270	VIDEOOUT(0xFF, (pTrident->keyOffset + 4));
271	VIDEOOUT(0x00, (pTrident->keyOffset + 5));
272	VIDEOOUT(0x00, (pTrident->keyOffset + 6));
273	break;
274    default:
275	red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
276	green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
277	blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
278	switch (pScrn->depth) {
279	case 15:
280	    tmp = (red << 10) | (green << 5) | (blue);
281	    VIDEOOUT((tmp & 0xff), pTrident->keyOffset);
282	    VIDEOOUT((tmp & 0xff00)>>8, (pTrident->keyOffset + 1));
283	    VIDEOOUT(0x00, (pTrident->keyOffset + 2));
284	    VIDEOOUT(0xFF, (pTrident->keyOffset + 4));
285	    VIDEOOUT(0xFF, (pTrident->keyOffset + 5));
286	    VIDEOOUT(0x00, (pTrident->keyOffset + 6));
287	    break;
288	case 16:
289	    tmp = (red << 11) | (green << 5) | (blue);
290	    VIDEOOUT((tmp & 0xff), pTrident->keyOffset);
291	    VIDEOOUT((tmp & 0xff00)>>8, (pTrident->keyOffset + 1));
292	    VIDEOOUT(0x00, (pTrident->keyOffset + 2));
293	    VIDEOOUT(0xFF, (pTrident->keyOffset + 4));
294	    VIDEOOUT(0xFF, (pTrident->keyOffset + 5));
295	    VIDEOOUT(0x00, (pTrident->keyOffset + 6));
296	    break;
297	case 24:
298	    VIDEOOUT(blue, pTrident->keyOffset);
299	    VIDEOOUT(green, (pTrident->keyOffset + 1));
300	    VIDEOOUT(red, (pTrident->keyOffset + 2));
301	    VIDEOOUT(0xFF, (pTrident->keyOffset + 4));
302	    VIDEOOUT(0xFF, (pTrident->keyOffset + 5));
303	    VIDEOOUT(0xFF, (pTrident->keyOffset + 6));
304	    break;
305	}
306    }
307
308    if (pTrident->Chipset >= CYBER9388) {
309    	tridentSetVideoContrast(pTrident,pPriv->Contrast);
310    	tridentSetVideoParameters(pTrident,pPriv->Brightness,pPriv->Saturation,
311                            pPriv->HUE);
312    }
313}
314
315
316static XF86VideoAdaptorPtr
317TRIDENTSetupImageVideo(ScreenPtr pScreen)
318{
319    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
320    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
321    XF86VideoAdaptorPtr adapt;
322    TRIDENTPortPrivPtr pPriv;
323
324    if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
325			    sizeof(TRIDENTPortPrivRec) +
326			    sizeof(DevUnion))))
327	return NULL;
328
329    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
330    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
331    adapt->name = "Trident Backend Scaler";
332    adapt->nEncodings = 1;
333    adapt->pEncodings = DummyEncoding;
334    adapt->nFormats = NUM_FORMATS;
335    adapt->pFormats = Formats;
336    adapt->nPorts = 1;
337    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
338    pPriv = (TRIDENTPortPrivPtr)(&adapt->pPortPrivates[1]);
339    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
340    adapt->pAttributes = Attributes;
341    adapt->nImages = NUM_IMAGES;
342    if (pTrident->Chipset >= CYBER9388) {
343    	adapt->nAttributes = NUM_ATTRIBUTES;
344    } else {
345    	adapt->nAttributes = 1; /* Just colorkey */
346    }
347    adapt->pImages = Images;
348    adapt->PutVideo = NULL;
349    adapt->PutStill = NULL;
350    adapt->GetVideo = NULL;
351    adapt->GetStill = NULL;
352    adapt->StopVideo = TRIDENTStopVideo;
353    adapt->SetPortAttribute = TRIDENTSetPortAttribute;
354    adapt->GetPortAttribute = TRIDENTGetPortAttribute;
355    adapt->QueryBestSize = TRIDENTQueryBestSize;
356    adapt->PutImage = TRIDENTPutImage;
357    adapt->QueryImageAttributes = TRIDENTQueryImageAttributes;
358
359    pPriv->colorKey = pTrident->videoKey & ((1 << pScrn->depth) - 1);
360    pPriv->Brightness = 45;
361    pPriv->Saturation = 80;
362    pPriv->Contrast = 4;
363    pPriv->HUE = 0;
364    pPriv->videoStatus = 0;
365    pPriv->fixFrame = 100;
366
367    /* gotta uninit this someplace */
368    REGION_NULL(pScreen, &pPriv->clip);
369
370    pTrident->adaptor = adapt;
371
372    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
373
374    if (pTrident->Chipset >= CYBER9388) {
375    	xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
376    	xvSaturation = MAKE_ATOM("XV_SATURATION");
377    	xvHUE        = MAKE_ATOM("XV_HUE");
378    	xvContrast   = MAKE_ATOM("XV_CONTRAST");
379    }
380
381    if (pTrident->Chipset >= PROVIDIA9682)
382	pTrident->keyOffset = 0x50;
383    else
384	pTrident->keyOffset = 0x30;
385
386    TRIDENTResetVideo(pScrn);
387
388    return adapt;
389}
390
391
392static void
393TRIDENTStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
394{
395  TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
396  TRIDENTPortPrivPtr pPriv = (TRIDENTPortPrivPtr)data;
397  int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
398
399  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
400
401  if(shutdown) {
402     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
403    	WaitForVBlank(pScrn);
404	OUTW(vgaIOBase + 4, 0x848E);
405	OUTW(vgaIOBase + 4, 0x0091);
406     }
407     if(pPriv->linear) {
408	xf86FreeOffscreenLinear(pPriv->linear);
409	pPriv->linear = NULL;
410     }
411     pPriv->videoStatus = 0;
412  } else {
413     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
414	pPriv->videoStatus |= OFF_TIMER;
415	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
416	pTrident->VideoTimerCallback = TRIDENTVideoTimerCallback;
417     }
418  }
419}
420
421#undef PI
422#define PI 3.14159265
423
424static void
425tridentSetVideoContrast(TRIDENTPtr pTrident,int value)
426{
427  OUTW(0x3C4, (((value & 0x7)|((value & 0x7) << 4)) << 8) | 0xBC);
428}
429
430static void
431tridentSetVideoParameters(TRIDENTPtr pTrident, int brightness,
432			  int saturation, int hue)
433{
434    double dtmp;
435    CARD8 sign, tmp, tmp1;
436
437    if (brightness >= 0x20)
438      brightness -= 0x20;
439    else
440      brightness += 0x20;
441    dtmp = sin((double)hue / 180.0 * PI) * saturation / 12.5;
442    sign = (dtmp < 0) ? 1 << 1 : 0;
443    tmp1 = ((int)fabs(dtmp) >> 4) & 0x1;
444    tmp = brightness << 2 | sign | tmp1;
445    OUTW(0x3C4, tmp << 8 | 0xB1);
446
447    tmp1 = ((int)fabs(dtmp) & 0x7 ) << 5;
448    dtmp = cos((double)hue / 180.0 * PI) * saturation / 12.5;
449    sign = (dtmp < 0) ? 1 << 4 : 0;
450    tmp1 |= (int)fabs(dtmp)  & 0xf;
451    tmp = sign | tmp1;
452    OUTW(0x3C4, tmp << 8 | 0xB0);
453}
454
455static int
456TRIDENTSetPortAttribute(
457  ScrnInfoPtr pScrn,
458  Atom attribute,
459  INT32 value,
460  pointer data
461){
462  TRIDENTPortPrivPtr pPriv = (TRIDENTPortPrivPtr)data;
463  TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
464
465  if(attribute == xvColorKey) {
466	int red, green, blue;
467	int tmp;
468	pPriv->colorKey = value;
469	switch (pScrn->depth) {
470	case 8:
471	    VIDEOOUT(pPriv->colorKey, pTrident->keyOffset);
472	    VIDEOOUT(0x00, (pTrident->keyOffset + 1));
473	    VIDEOOUT(0x00, (pTrident->keyOffset + 2));
474	    break;
475	default:
476	    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
477	    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
478	    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
479	    switch (pScrn->depth) {
480	    case 15:
481	    	tmp = (red << 10) | (green << 5) | (blue);
482	    	VIDEOOUT((tmp&0xff), pTrident->keyOffset);
483	    	VIDEOOUT((tmp&0xff00)>>8, (pTrident->keyOffset + 1));
484	    	VIDEOOUT(0x00, (pTrident->keyOffset + 2));
485		break;
486	    case 16:
487	    	tmp = (red << 11) | (green << 5) | (blue);
488	    	VIDEOOUT((tmp&0xff), pTrident->keyOffset);
489	    	VIDEOOUT((tmp&0xff00)>>8, (pTrident->keyOffset + 1));
490	    	VIDEOOUT(0x00, (pTrident->keyOffset + 2));
491		break;
492	    case 24:
493	    	VIDEOOUT(blue, pTrident->keyOffset);
494	    	VIDEOOUT(green, (pTrident->keyOffset + 1));
495	    	VIDEOOUT(red, (pTrident->keyOffset + 2));
496		break;
497	    }
498	}
499	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
500  } else if (attribute == xvBrightness) {
501    if ((value < 0) || (value > 0x3f))
502      return BadValue;
503    pPriv->Brightness = value;
504    tridentSetVideoParameters(pTrident, pPriv->Brightness, pPriv->Saturation,
505			      pPriv->HUE);
506  } else if (attribute == xvSaturation) {
507    if ((value < 0) || (value > 187))
508      return BadValue;
509    pPriv->Saturation = value;
510    tridentSetVideoParameters(pTrident, pPriv->Brightness, pPriv->Saturation,
511			      pPriv->HUE);
512  } else if (attribute == xvHUE) {
513    if ((value < 0) || (value > 360))
514      return BadValue;
515    pPriv->HUE = value;
516    tridentSetVideoParameters(pTrident, pPriv->Brightness, pPriv->Saturation,
517			      pPriv->HUE);
518  } else if (attribute == xvContrast) {
519    if ((value < 0) || (value > 7))
520      return BadValue;
521    pPriv->Contrast = value;
522    tridentSetVideoContrast(pTrident,value);
523  } else
524    return BadMatch;
525
526  return Success;
527}
528
529static int
530TRIDENTGetPortAttribute(
531  ScrnInfoPtr pScrn,
532  Atom attribute,
533  INT32 *value,
534  pointer data
535){
536  TRIDENTPortPrivPtr pPriv = (TRIDENTPortPrivPtr)data;
537
538  if(attribute == xvColorKey) {
539	*value = pPriv->colorKey;
540  } else if(attribute == xvBrightness) {
541	*value = pPriv->Brightness;
542  } else if(attribute == xvSaturation) {
543	*value = pPriv->Saturation;
544  } else if (attribute == xvHUE) {
545	*value = pPriv->HUE;
546  } else if (attribute == xvContrast) {
547	*value = pPriv->Contrast;
548  } else
549    return BadMatch;
550
551  return Success;
552}
553
554static void
555TRIDENTQueryBestSize(
556  ScrnInfoPtr pScrn,
557  Bool motion,
558  short vid_w, short vid_h,
559  short drw_w, short drw_h,
560  unsigned int *p_w, unsigned int *p_h,
561  pointer data
562){
563  *p_w = drw_w;
564  *p_h = drw_h;
565
566  if(*p_w > 16384) *p_w = 16384;
567}
568
569
570static FBLinearPtr
571TRIDENTAllocateMemory(
572   ScrnInfoPtr pScrn,
573   FBLinearPtr linear,
574   int size
575){
576   ScreenPtr pScreen;
577   FBLinearPtr new_linear;
578
579   if(linear) {
580	if(linear->size >= size)
581	   return linear;
582
583        if(xf86ResizeOffscreenLinear(linear, size))
584	   return linear;
585
586	xf86FreeOffscreenLinear(linear);
587   }
588
589   pScreen = screenInfo.screens[pScrn->scrnIndex];
590
591   new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
592   						NULL, NULL, NULL);
593
594   if(!new_linear) {
595	int max_size;
596
597	xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
598						PRIORITY_EXTREME);
599
600	if(max_size < size)
601	   return NULL;
602
603	xf86PurgeUnlockedOffscreenAreas(pScreen);
604	new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
605						NULL, NULL, NULL);
606   }
607
608   return new_linear;
609}
610
611static void
612TRIDENTDisplayVideo(
613    ScrnInfoPtr pScrn,
614    int id,
615    int offset,
616    short width, short height,
617    int pitch,
618    int x1, int y1, int x2, int y2,
619    BoxPtr dstBox,
620    short src_w, short src_h,
621    short drw_w, short drw_h
622){
623    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
624    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
625    int zoomx1, zoomx2, zoomy1, zoomy2;
626    int tx1,tx2;
627    int ty1,ty2;
628
629    switch(id) {
630    case 0x35315652:		/* RGB15 */
631    case 0x36315652:		/* RGB16 */
632	if (pTrident->Chipset >= CYBER9388) {
633    	    OUTW(vgaIOBase + 4, 0x22BF);
634	    OUTW(vgaIOBase + 4, 0x248F);
635	} else {
636    	    OUTW(vgaIOBase + 4, 0x118F);
637	}
638	break;
639    case FOURCC_YV12:		/* YV12 */
640    case FOURCC_YUY2:		/* YUY2 */
641    default:
642	if (pTrident->Chipset >= CYBER9388) {
643    	    OUTW(vgaIOBase + 4, 0x00BF);
644	    OUTW(vgaIOBase + 4, 0x208F);
645	} else {
646    	    OUTW(vgaIOBase + 4, 0x108F);
647	}
648	break;
649    }
650    tx1 = dstBox->x1 + pTrident->hsync;
651    tx2 = dstBox->x2 + pTrident->hsync + pTrident->hsync_rskew;
652    ty1 = dstBox->y1 + pTrident->vsync - 2;
653    ty2 = dstBox->y2 + pTrident->vsync + 2 + pTrident->vsync_bskew;
654
655    OUTW(vgaIOBase + 4, (tx1 & 0xff) <<8 | 0x86);
656    OUTW(vgaIOBase + 4, (tx1 & 0xff00)   | 0x87);
657    OUTW(vgaIOBase + 4, (ty1 & 0xff) <<8 | 0x88);
658    OUTW(vgaIOBase + 4, (ty1 & 0xff00)   | 0x89);
659    OUTW(vgaIOBase + 4, (tx2 & 0xff) <<8 | 0x8A);
660    OUTW(vgaIOBase + 4, (tx2 & 0xff00)   | 0x8B);
661    OUTW(vgaIOBase + 4, (ty2 & 0xff) <<8 | 0x8C);
662    OUTW(vgaIOBase + 4, (ty2 & 0xff00)   | 0x8D);
663
664    offset += (x1 >> 15) & ~0x01;
665
666    if (pTrident->videoFlags & VID_OFF_SHIFT_4)
667        offset = offset >> 4;
668    else
669        offset = offset >> 3;
670
671    OUTW(vgaIOBase + 4, (((width<<1) & 0xff)<<8)   | 0x90);
672    OUTW(vgaIOBase + 4, ((width<<1) & 0xff00)      | 0x91);
673    OUTW(vgaIOBase + 4, ((offset) & 0xff) << 8     | 0x92);
674    OUTW(vgaIOBase + 4, ((offset) & 0xff00)        | 0x93);
675    if (pTrident->Chipset >= CYBER9397) {
676    	OUTW(vgaIOBase + 4, ((offset) & 0x0f0000) >> 8 | 0x94);
677    } else {
678    	OUTW(vgaIOBase + 4, ((offset) & 0x070000) >> 8 | 0x94);
679    }
680
681    /* Horizontal Zoom */
682    if (pTrident->videoFlags & VID_ZOOM_INV) {
683	if ((pTrident->videoFlags & VID_ZOOM_MINI) && src_w > drw_w)
684	    zoomx2 = (int)((float)drw_w/(float)src_w * 1024)
685		| (((int)((float)src_w/(float)drw_w) - 1)&7)<<10 | 0x8000;
686	else
687	    zoomx2 = (int)(float)src_w/(float)drw_w * 1024;
688
689	OUTW(vgaIOBase + 4, (zoomx2&0xff)<<8 | 0x80);
690	OUTW(vgaIOBase + 4, (zoomx2&0x9f00) | 0x81);
691    } else {
692	if (drw_w == src_w
693	    || ((pTrident->videoFlags & VID_ZOOM_NOMINI) && (src_w > drw_w))) {
694	    OUTW(vgaIOBase + 4, 0x0080);
695	    OUTW(vgaIOBase + 4, 0x0081);
696	} else
697	    if (drw_w > src_w) {
698		float z;
699
700		z = (float)((drw_w)/(float)src_w) - 1.0;
701
702		zoomx1 =  z;
703		zoomx2 = (z - (int)zoomx1 ) * 1024;
704
705		OUTW(vgaIOBase + 4, (zoomx2&0xff)<<8 | 0x80);
706		OUTW(vgaIOBase + 4, (zoomx1&0x0f)<<10 | (zoomx2&0x0300) |0x81);
707	    } else {
708		zoomx1 =   ((float)drw_w/(float)src_w);
709		zoomx2 = ( ((float)drw_w/(float)src_w) - (int)zoomx1 ) * 1024;
710		OUTW(vgaIOBase + 4, (zoomx2&0xff)<<8 |   0x80);
711		OUTW(vgaIOBase + 4, (zoomx2&0x0300)|
712		     (((int)((float)src_w/(float)drw_w)-1)&7)<<10 | 0x8081);
713	    }
714    }
715
716    /* Vertical Zoom */
717    if (pTrident->videoFlags & VID_ZOOM_INV) {
718	if ((pTrident->videoFlags & VID_ZOOM_MINI) && src_h > drw_h)
719	    zoomy2 = (int)(( ((float)drw_h/(float)src_h)) * 1024)
720		| (((int)((float)src_h/(float)drw_h)-1)&7)<<10
721		| 0x8000;
722	else
723	    zoomy2 = ( ((float)src_h/(float)drw_h)) * 1024;
724	OUTW(vgaIOBase + 4, (zoomy2&0xff)<<8 | 0x82);
725	OUTW(vgaIOBase + 4, (zoomy2&0x9f00) | 0x0083);
726    } else {
727	if (drw_h == src_h
728	    || ((pTrident->videoFlags & VID_ZOOM_NOMINI) && (src_h > drw_h))) {
729	    OUTW(vgaIOBase + 4, 0x0082);
730	    OUTW(vgaIOBase + 4, 0x0083);
731	} else
732	    if (drw_h > src_h) {
733		float z;
734
735		z = (float)drw_h/(float)src_h - 1;
736		zoomy1 =  z;
737		zoomy2 = (z - (int)zoomy1 ) * 1024;
738
739		OUTW(vgaIOBase + 4, (zoomy2&0xff)<<8 | 0x82);
740		OUTW(vgaIOBase + 4, (zoomy1&0x0f)<<10 | (zoomy2&0x0300) |0x83);
741	    } else {
742		zoomy1 =   ((float)drw_h/(float)src_h);
743		zoomy2 = ( ((float)drw_h/(float)src_h) - (int)zoomy1 ) * 1024;
744		OUTW(vgaIOBase + 4, (zoomy2&0xff)<<8 | 0x82);
745		OUTW(vgaIOBase + 4, (zoomy2&0x0300)|
746		     (((int)((float)src_h/(float)drw_h)-1)&7)<<10 | 0x8083);
747	    }
748    }
749
750    if (pTrident->Chipset >= CYBER9388) {
751	int lb = (width+2) >> 2;
752
753    	OUTW(vgaIOBase + 4, ((lb & 0x100)>>1) | 0x0895);
754    	OUTW(vgaIOBase + 4,  (lb & 0xFF)<<8   | 0x0096);
755    	if ((pTrident->videoFlags & VID_DOUBLE_LINEBUFFER_FOR_WIDE_SRC)
756	      && (src_w > 384)) {
757    	    OUTW(0x3C4, 0x0497); /* 2x line buffers */
758    	} else {
759    	    OUTW(0x3C4, 0x0097); /* 1x line buffers */
760    	}
761    	OUTW(vgaIOBase + 4, 0x0097);
762    	OUTW(vgaIOBase + 4, 0x00BA);
763    	OUTW(vgaIOBase + 4, 0x00BB);
764    	OUTW(vgaIOBase + 4, 0xFFBC);
765    	OUTW(vgaIOBase + 4, 0xFFBD);
766    	OUTW(vgaIOBase + 4, 0x04BE);
767    	OUTW(vgaIOBase + 4, 0x948E);
768    } else {
769
770    	OUTW(vgaIOBase + 4, ((((id == FOURCC_YV12) || (id == FOURCC_YUY2))
771					? (width >> 2) : (width >> 6)) << 8) | 0x95);
772    	OUTW(vgaIOBase + 4, ((((id == FOURCC_YV12) || (id == FOURCC_YUY2))
773				? ((width+2) >> 2) : ((width+2) >> 6)) << 8) |0x96);
774
775    	OUTW(vgaIOBase + 4, 0x948E);
776	OUTB(0x83C8, 0x00);
777	OUTB(0x83C6, 0x95);
778    }
779}
780
781static int
782TRIDENTPutImage(
783  ScrnInfoPtr pScrn,
784  short src_x, short src_y,
785  short drw_x, short drw_y,
786  short src_w, short src_h,
787  short drw_w, short drw_h,
788  int id, unsigned char* buf,
789  short width, short height,
790  Bool sync,
791  RegionPtr clipBoxes, pointer data,
792  DrawablePtr pDraw
793){
794   TRIDENTPortPrivPtr pPriv = (TRIDENTPortPrivPtr)data;
795   TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
796   INT32 x1, x2, y1, y2;
797   unsigned char *dst_start;
798   int new_size, offset, offset2 = 0, offset3 = 0;
799   int srcPitch, srcPitch2 = 0, dstPitch;
800   int top, left, npixels, nlines, bpp;
801   BoxRec dstBox;
802   CARD32 tmp;
803
804   /* Clip */
805   x1 = src_x;
806   x2 = src_x + src_w;
807   y1 = src_y;
808   y2 = src_y + src_h;
809
810   dstBox.x1 = drw_x;
811   dstBox.x2 = drw_x + drw_w;
812   dstBox.y1 = drw_y;
813   dstBox.y2 = drw_y + drw_h;
814
815   if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
816								width, height))
817	return Success;
818
819   dstBox.x1 -= pScrn->frameX0;
820   dstBox.x2 -= pScrn->frameX0;
821   dstBox.y1 -= pScrn->frameY0;
822   dstBox.y2 -= pScrn->frameY0;
823
824   bpp = pScrn->bitsPerPixel >> 3;
825
826   dstPitch = ((width << 1) + 15) & ~15;
827   new_size = ((dstPitch * height) + bpp - 1) / bpp;
828   switch(id) {
829   case FOURCC_YV12:
830   case FOURCC_I420:
831	srcPitch = (width + 3) & ~3;
832	offset2 = srcPitch * height;
833	srcPitch2 = ((width >> 1) + 3) & ~3;
834	offset3 = (srcPitch2 * (height >> 1)) + offset2;
835	break;
836   case FOURCC_UYVY:
837   case FOURCC_YUY2:
838   default:
839	srcPitch = (width << 1);
840	break;
841   }
842
843   if(!(pPriv->linear = TRIDENTAllocateMemory(pScrn, pPriv->linear, new_size)))
844	return BadAlloc;
845
846    /* copy data */
847   top = y1 >> 16;
848   left = (x1 >> 16) & ~1;
849   npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
850   left <<= 1;
851
852   offset = pPriv->linear->offset * bpp;
853
854   dst_start = pTrident->FbBase + offset + left + (top * dstPitch);
855
856   switch(id) {
857    case FOURCC_YV12:
858    case FOURCC_I420:
859	top &= ~1;
860	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
861	offset2 += tmp;
862	offset3 += tmp;
863	if(id == FOURCC_I420) {
864	   tmp = offset2;
865	   offset2 = offset3;
866	   offset3 = tmp;
867	}
868	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
869	xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
870				buf + offset2, buf + offset3, dst_start,
871				srcPitch, srcPitch2, dstPitch, nlines, npixels);
872	break;
873    case FOURCC_UYVY:
874    case FOURCC_YUY2:
875    default:
876	buf += (top * srcPitch) + left;
877	nlines = ((y2 + 0xffff) >> 16) - top;
878	xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
879        break;
880    }
881
882    /* update cliplist */
883    if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
884    	/* update cliplist */
885        REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
886        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
887    }
888
889    offset += top * dstPitch;
890
891    /* Fix video position when using doublescan */
892    if(pScrn->currentMode->Flags & V_DBLSCAN) {
893	    dstBox.y1 <<= 1;
894	    dstBox.y2 <<= 1;
895	    drw_h <<= 1;
896    }
897
898    tridentFixFrame(pScrn,&pPriv->fixFrame);
899    TRIDENTDisplayVideo(pScrn, id, offset, width, height, dstPitch,
900	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
901
902    pPriv->videoStatus = CLIENT_VIDEO_ON;
903
904    pTrident->VideoTimerCallback = TRIDENTVideoTimerCallback;
905
906    return Success;
907}
908
909static int
910TRIDENTQueryImageAttributes(
911  ScrnInfoPtr pScrn,
912  int id,
913  unsigned short *w, unsigned short *h,
914  int *pitches, int *offsets
915){
916    int size, tmp;
917
918    if(*w > 1024) *w = 1024;
919    if(*h > 1024) *h = 1024;
920
921    *w = (*w + 1) & ~1;
922    if(offsets) offsets[0] = 0;
923
924    switch(id) {
925    case FOURCC_YV12:		/* YV12 */
926	*h = (*h + 1) & ~1;
927	size = (*w + 3) & ~3;
928	if(pitches) pitches[0] = size;
929	size *= *h;
930	if(offsets) offsets[1] = size;
931	tmp = ((*w >> 1) + 3) & ~3;
932	if(pitches) pitches[1] = pitches[2] = tmp;
933	tmp *= (*h >> 1);
934	size += tmp;
935	if(offsets) offsets[2] = size;
936	size += tmp;
937	break;
938    default:			/* RGB15, RGB16, YUY2 */
939	size = *w << 1;
940	if(pitches) pitches[0] = size;
941	size *= *h;
942	break;
943    }
944
945    return size;
946}
947
948/****************** Offscreen stuff ***************/
949
950typedef struct {
951  FBLinearPtr linear;
952  Bool isOn;
953} OffscreenPrivRec, * OffscreenPrivPtr;
954
955static int
956TRIDENTAllocateSurface(
957    ScrnInfoPtr pScrn,
958    int id,
959    unsigned short w,
960    unsigned short h,
961    XF86SurfacePtr surface
962){
963    FBLinearPtr linear;
964    int pitch, size, bpp;
965    OffscreenPrivPtr pPriv;
966
967    if((w > 1024) || (h > 1024))
968	return BadAlloc;
969
970    w = (w + 1) & ~1;
971    pitch = ((w << 1) + 15) & ~15;
972    bpp = pScrn->bitsPerPixel >> 3;
973    size = ((pitch * h) + bpp - 1) / bpp;
974
975    if(!(linear = TRIDENTAllocateMemory(pScrn, NULL, size)))
976	return BadAlloc;
977
978    surface->width = w;
979    surface->height = h;
980
981    if(!(surface->pitches = malloc(sizeof(int)))) {
982	xf86FreeOffscreenLinear(linear);
983	return BadAlloc;
984    }
985    if(!(surface->offsets = malloc(sizeof(int)))) {
986	free(surface->pitches);
987	xf86FreeOffscreenLinear(linear);
988	return BadAlloc;
989    }
990    if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
991	free(surface->pitches);
992	free(surface->offsets);
993	xf86FreeOffscreenLinear(linear);
994	return BadAlloc;
995    }
996
997    pPriv->linear = linear;
998    pPriv->isOn = FALSE;
999
1000    surface->pScrn = pScrn;
1001    surface->id = id;
1002    surface->pitches[0] = pitch;
1003    surface->offsets[0] = linear->offset * bpp;
1004    surface->devPrivate.ptr = (pointer)pPriv;
1005
1006    return Success;
1007}
1008
1009static int
1010TRIDENTStopSurface(
1011    XF86SurfacePtr surface
1012){
1013    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1014
1015    if(pPriv->isOn) {
1016	TRIDENTPtr pTrident = TRIDENTPTR(surface->pScrn);
1017    	int vgaIOBase = VGAHWPTR(surface->pScrn)->IOBase;
1018	WaitForVBlank(surface->pScrn);
1019 	OUTW(vgaIOBase + 4, 0x848E);
1020	OUTW(vgaIOBase + 4, 0x0091);
1021	pPriv->isOn = FALSE;
1022    }
1023
1024    return Success;
1025}
1026
1027
1028static int
1029TRIDENTFreeSurface(
1030    XF86SurfacePtr surface
1031){
1032    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1033
1034    if(pPriv->isOn)
1035	TRIDENTStopSurface(surface);
1036    xf86FreeOffscreenLinear(pPriv->linear);
1037    free(surface->pitches);
1038    free(surface->offsets);
1039    free(surface->devPrivate.ptr);
1040
1041    return Success;
1042}
1043
1044static int
1045TRIDENTGetSurfaceAttribute(
1046    ScrnInfoPtr pScrn,
1047    Atom attribute,
1048    INT32 *value
1049){
1050    return TRIDENTGetPortAttribute(pScrn, attribute, value,
1051			(pointer)(GET_PORT_PRIVATE(pScrn)));
1052}
1053
1054static int
1055TRIDENTSetSurfaceAttribute(
1056    ScrnInfoPtr pScrn,
1057    Atom attribute,
1058    INT32 value
1059){
1060    return TRIDENTSetPortAttribute(pScrn, attribute, value,
1061			(pointer)(GET_PORT_PRIVATE(pScrn)));
1062}
1063
1064static int
1065TRIDENTDisplaySurface(
1066    XF86SurfacePtr surface,
1067    short src_x, short src_y,
1068    short drw_x, short drw_y,
1069    short src_w, short src_h,
1070    short drw_w, short drw_h,
1071    RegionPtr clipBoxes
1072){
1073    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1074    ScrnInfoPtr pScrn = surface->pScrn;
1075    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1076    TRIDENTPortPrivPtr portPriv = pTrident->adaptor->pPortPrivates[0].ptr;
1077    INT32 x1, y1, x2, y2;
1078    BoxRec dstBox;
1079
1080    x1 = src_x;
1081    x2 = src_x + src_w;
1082    y1 = src_y;
1083    y2 = src_y + src_h;
1084
1085    dstBox.x1 = drw_x;
1086    dstBox.x2 = drw_x + drw_w;
1087    dstBox.y1 = drw_y;
1088    dstBox.y2 = drw_y + drw_h;
1089
1090    if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
1091			surface->width, surface->height))
1092    {
1093	return Success;
1094    }
1095
1096    dstBox.x1 -= pScrn->frameX0;
1097    dstBox.x2 -= pScrn->frameX0;
1098    dstBox.y1 -= pScrn->frameY0;
1099    dstBox.y2 -= pScrn->frameY0;
1100
1101    TRIDENTResetVideo(pScrn);
1102
1103    tridentFixFrame(pScrn,&portPriv->fixFrame);
1104    TRIDENTDisplayVideo(pScrn, surface->id, surface->offsets[0],
1105	     surface->width, surface->height, surface->pitches[0],
1106	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1107
1108    xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
1109
1110    pPriv->isOn = TRUE;
1111    /* we've prempted the XvImage stream so set its free timer */
1112    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
1113	REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
1114	UpdateCurrentTime();
1115	portPriv->videoStatus = FREE_TIMER;
1116	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1117	pTrident->VideoTimerCallback = TRIDENTVideoTimerCallback;
1118    }
1119
1120    return Success;
1121}
1122
1123static void
1124TRIDENTInitOffscreenImages(ScreenPtr pScreen)
1125{
1126    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1127    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1128    XF86OffscreenImagePtr offscreenImages;
1129
1130    /* need to free this someplace */
1131    if(!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
1132	return;
1133
1134    offscreenImages[0].image = &Images[0];
1135    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
1136			       VIDEO_CLIP_TO_VIEWPORT;
1137    offscreenImages[0].alloc_surface = TRIDENTAllocateSurface;
1138    offscreenImages[0].free_surface = TRIDENTFreeSurface;
1139    offscreenImages[0].display = TRIDENTDisplaySurface;
1140    offscreenImages[0].stop = TRIDENTStopSurface;
1141    offscreenImages[0].setAttribute = TRIDENTSetSurfaceAttribute;
1142    offscreenImages[0].getAttribute = TRIDENTGetSurfaceAttribute;
1143    offscreenImages[0].max_width = 1024;
1144    offscreenImages[0].max_height = 1024;
1145    if (pTrident->Chipset >= CYBER9388) {
1146    	offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
1147    } else {
1148    	offscreenImages[0].num_attributes = 1; /* just colorkey */
1149    }
1150    offscreenImages[0].attributes = Attributes;
1151
1152    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
1153}
1154
1155static void
1156TRIDENTVideoTimerCallback(ScrnInfoPtr pScrn, Time time)
1157{
1158    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1159    TRIDENTPortPrivPtr pPriv = pTrident->adaptor->pPortPrivates[0].ptr;
1160    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1161
1162    if(pPriv->videoStatus & TIMER_MASK) {
1163	if(pPriv->videoStatus & OFF_TIMER) {
1164	    if(pPriv->offTime < time) {
1165		WaitForVBlank(pScrn);
1166  		OUTW(vgaIOBase + 4, 0x848E);
1167		OUTW(vgaIOBase + 4, 0x0091);
1168		pPriv->videoStatus = FREE_TIMER;
1169		pPriv->freeTime = time + FREE_DELAY;
1170	    }
1171	} else {  /* FREE_TIMER */
1172	    if(pPriv->freeTime < time) {
1173		if(pPriv->linear) {
1174		   xf86FreeOffscreenLinear(pPriv->linear);
1175		   pPriv->linear = NULL;
1176		}
1177		pPriv->videoStatus = 0;
1178	        pTrident->VideoTimerCallback = NULL;
1179	    }
1180        }
1181    } else  /* shouldn't get here */
1182	pTrident->VideoTimerCallback = NULL;
1183}
1184
1185    /* Calculate skew offsets for video overlay */
1186
1187
1188void
1189tridentFixFrame(ScrnInfoPtr pScrn, int *fixFrame)
1190{
1191
1192    TRIDENTPtr pTrident = TRIDENTPTR(pScrn);
1193    int vgaIOBase = VGAHWPTR(pScrn)->IOBase;
1194    int HTotal, HSyncStart;
1195    int VTotal, VSyncStart;
1196    int h_off = 0;
1197    int v_off = 0;
1198    unsigned char CRTC[0x11];
1199    unsigned char hcenter, vcenter;
1200    Bool isShadow;
1201    unsigned char shadow = 0;
1202
1203    if ((*fixFrame)++ < 100)
1204	return;
1205
1206  *fixFrame = 0;
1207
1208  OUTB(0x3CE, CyberControl);
1209  isShadow = ((INB(0x3CF) & 0x81) == 0x81);
1210
1211  if (isShadow)
1212      SHADOW_ENABLE(shadow);
1213
1214    OUTB(vgaIOBase + 4, 0x0);
1215    CRTC[0x0] = INB(vgaIOBase + 5);
1216    OUTB(vgaIOBase + 4, 0x4);
1217    CRTC[0x4] = INB(vgaIOBase + 5);
1218    OUTB(vgaIOBase + 4, 0x5);
1219    CRTC[0x5] = INB(vgaIOBase + 5);
1220    OUTB(vgaIOBase + 4, 0x6);
1221    CRTC[0x6] = INB(vgaIOBase + 5);
1222    OUTB(vgaIOBase + 4, 0x7);
1223    CRTC[0x7] = INB(vgaIOBase + 5);
1224    OUTB(vgaIOBase + 4, 0x10);
1225    CRTC[0x10] = INB(vgaIOBase + 5);
1226    OUTB(0x3CE, HorStretch);
1227    hcenter = INB(0x3CF);
1228    OUTB(0x3CE, VertStretch);
1229    vcenter = INB(0x3CF);
1230
1231    HTotal = CRTC[0] << 3;
1232    VTotal = CRTC[6]
1233	| ((CRTC[7] & (1<<0)) << 8)
1234	| ((CRTC[7] & (1<<5)) << 4);
1235    HSyncStart = (CRTC[4]
1236		  + ((CRTC[5] >> 5) & 0x3)) << 3;
1237    VSyncStart = CRTC[0x10]
1238	| ((CRTC[7] & (1<<2)) << 6)
1239	| ((CRTC[7] & (1<<7)) << 2);
1240
1241    if (isShadow) {
1242	SHADOW_RESTORE(shadow);
1243	if (pTrident->lcdMode != 0xff) {
1244	    if (hcenter & 0x80) {
1245	    h_off = (LCD[pTrident->lcdMode].display_x
1246		     - pScrn->currentMode->HDisplay) >> 1;
1247		switch (pTrident->Chipset) {
1248		    case BLADEXP:
1249			h_off -= 5;
1250		}
1251	    }
1252	    if (vcenter & 0x80) {
1253	    v_off = (LCD[pTrident->lcdMode].display_y
1254		     - pScrn->currentMode->VDisplay) >> 1;
1255	}
1256    }
1257    }
1258
1259    pTrident->hsync = HTotal - HSyncStart + 23 + h_off;
1260    pTrident->vsync = VTotal - VSyncStart - 2 + v_off;
1261    pTrident->hsync_rskew = 0;
1262    pTrident->vsync_bskew = 0;
1263
1264    /*
1265     * HACK !! As awful as this is, it appears to be the only way....Sigh!
1266     * We have XvHsync and XvVsync as options now, which adjust
1267     * at the very end of this function. It'll be helpful for now
1268     * and we can get more data on some of these skew values.
1269     */
1270    switch (pTrident->Chipset) {
1271	case TGUI9680:
1272	    /* Furthur tweaking needed */
1273    	    pTrident->hsync -= 84;
1274	    pTrident->vsync += 2;
1275	    break;
1276	case PROVIDIA9682:
1277	    /* Furthur tweaking needed */
1278	    pTrident->hsync += 7;
1279	    break;
1280	case PROVIDIA9685:
1281	    /* Spot on */
1282	    break;
1283        case BLADEXP:
1284        case CYBERBLADEXPAI1:
1285	    pTrident->hsync -= 15;
1286	    pTrident->hsync_rskew = 3;
1287	    break;
1288	case BLADE3D:
1289	    if (pScrn->depth == 24)
1290		pTrident->hsync -= 8;
1291	    else
1292		pTrident->hsync -= 6;
1293	    break;
1294	case CYBERBLADEI7:
1295	case CYBERBLADEI7D:
1296	case CYBERBLADEI1:
1297	case CYBERBLADEI1D:
1298	    if (pScrn->depth == 24)
1299		pTrident->hsync -= 7;
1300	    else
1301		pTrident->hsync -= 6;
1302	    break;
1303	case CYBERBLADEAI1:
1304	    pTrident->hsync -= 7;
1305	    break;
1306	case CYBERBLADEAI1D:
1307	    pTrident->vsync += 2;
1308	    pTrident->vsync_bskew = -4;
1309	    pTrident->hsync -= 5;
1310	    break;
1311	case CYBERBLADEE4:
1312	    pTrident->hsync -= 8;
1313	    break;
1314	case CYBERBLADEXP4:
1315	    pTrident->hsync -= 24;
1316	    pTrident->hsync_rskew = -1;
1317	    break;
1318	case CYBER9397:
1319	    pTrident->hsync -= 1;
1320  	    pTrident->vsync -= 0;
1321	    pTrident->vsync_bskew = 0;
1322	    break;
1323	case CYBER9397DVD:
1324	    pTrident->hsync_rskew = -1;
1325	    pTrident->vsync_bskew = -1;
1326	    break;
1327    }
1328    pTrident->hsync+=pTrident->OverrideHsync;
1329    pTrident->vsync+=pTrident->OverrideVsync;
1330    pTrident->hsync_rskew += pTrident->OverrideRskew;
1331    pTrident->vsync_bskew += pTrident->OverrideBskew;
1332}
1333
1334static void
1335WaitForVBlank(ScrnInfoPtr pScrn)
1336{
1337    register vgaHWPtr hwp = VGAHWPTR(pScrn);
1338
1339    /* We have to wait for one full VBlank to let the video engine start/stop.
1340     * So the first may be waiting for too short a period as it may already
1341     * be part way through the video frame. So we wait a second time to ensure
1342     * full vblank has passed.
1343     * - Alan.
1344     */
1345#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
1346    if (!xf86IsPc98())
1347#endif
1348    {
1349       WAITFORVSYNC;
1350       WAITFORVSYNC;
1351    }
1352}
1353