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