DRI XFree86-4_3_99_12-merge import
[xf86-video-sis/mirage.git] / src / sis6326_video.c
blob7c9fdf9da9cd5e734fe2e435f21ae42dfcce9f34
1 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/sis6326_video.c,v 1.9 2003/08/07 12:52:23 twini Exp $ */
2 /*
3 * Xv driver for SiS 5597/5598, 6236 and 530/620.
5 * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria.
7 * Based on sis_video.c which is
8 * Copyright 2002, 2003 by Thomas Winischhofer, Vienna, Austria.
10 * Permission to use, copy, modify, distribute, and sell this software and its
11 * documentation for any purpose is hereby granted without fee, provided that
12 * the above copyright notice appear in all copies and that both that
13 * copyright notice and this permission notice appear in supporting
14 * documentation, and that the name of the copyright holder not be used in
15 * advertising or publicity pertaining to distribution of the software without
16 * specific, written prior permission. The copyright holder makes no representations
17 * about the suitability of this software for any purpose. It is provided
18 * "as is" without express or implied warranty.
20 * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
22 * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
24 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
25 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26 * PERFORMANCE OF THIS SOFTWARE.
28 * Author: Thomas Winischhofer <thomas@winischhofer.net>
31 #include "sis.h"
33 #include "xf86.h"
34 #include "xf86_OSproc.h"
35 #include "xf86Resources.h"
36 #include "xf86_ansic.h"
37 #include "compiler.h"
38 #include "xf86PciInfo.h"
39 #include "xf86Pci.h"
40 #include "xf86fbman.h"
41 #include "regionstr.h"
43 #include "xf86xv.h"
44 #include "Xv.h"
45 #include "xaa.h"
46 #include "xaalocal.h"
47 #include "dixstruct.h"
48 #include "fourcc.h"
50 #include "sis_regs.h"
52 #define OFF_DELAY 200 /* milliseconds */
53 #define FREE_DELAY 60000
55 #define OFF_TIMER 0x01
56 #define FREE_TIMER 0x02
57 #define CLIENT_VIDEO_ON 0x04
59 #define TIMER_MASK (OFF_TIMER | FREE_TIMER)
61 #define WATCHDOG_DELAY 500000 /* Watchdog counter for Vertical Restrace waiting */
63 static XF86VideoAdaptorPtr SIS6326SetupImageVideo(ScreenPtr);
64 static void SIS6326StopVideo(ScrnInfoPtr, pointer, Bool);
65 static int SIS6326SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
66 static int SIS6326GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
67 static void SIS6326QueryBestSize(ScrnInfoPtr, Bool, short, short, short,
68 short, unsigned int *,unsigned int *, pointer);
69 static int SIS6326PutImage( ScrnInfoPtr,
70 short, short, short, short, short, short, short, short,
71 int, unsigned char*, short, short, Bool, RegionPtr, pointer);
72 static int SIS6326QueryImageAttributes(ScrnInfoPtr,
73 int, unsigned short *, unsigned short *, int *, int *);
74 static void SIS6326VideoTimerCallback(ScrnInfoPtr pScrn, Time now);
75 static void SIS6326InitOffscreenImages(ScreenPtr pScrn);
77 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
79 static Atom xvBrightness, xvContrast, xvColorKey;
80 static Atom xvAutopaintColorKey, xvSetDefaults;
81 static Atom xvDisableGfx;
83 #define IMAGE_MIN_WIDTH 32 /* Minimum and maximum image sizes */
84 #define IMAGE_MIN_HEIGHT 24
85 #define IMAGE_MAX_WIDTH 720 /* Are these correct for the chips ? */
86 #define IMAGE_MAX_HEIGHT 576
87 #define IMAGE_MAX_WIDTH_5597 384
88 #define IMAGE_MAX_HEIGHT_5597 288
90 #if 0
91 static int oldH, oldW;
92 #endif
94 /****************************************************************************
95 * Raw register access : These routines directly interact with the sis's
96 * control aperature. Must not be called until after
97 * the board's pci memory has been mapped.
98 ****************************************************************************/
100 #if 0
101 static CARD32 _sisread(SISPtr pSiS, CARD32 reg)
103 return *(pSiS->IOBase + reg);
106 static void _siswrite(SISPtr pSiS, CARD32 reg, CARD32 data)
108 *(pSiS->IOBase + reg) = data;
110 #endif
112 static CARD8 getvideoreg(SISPtr pSiS, CARD8 reg)
114 CARD8 ret;
115 inSISIDXREG(SISCR, reg, ret);
116 return(ret);
119 static __inline void setvideoreg(SISPtr pSiS, CARD8 reg, CARD8 data)
121 outSISIDXREG(SISCR, reg, data);
124 static void setvideoregmask(SISPtr pSiS, CARD8 reg, CARD8 data, CARD8 mask)
126 CARD8 old;
128 inSISIDXREG(SISCR, reg, old);
129 data = (data & mask) | (old & (~mask));
130 outSISIDXREG(SISCR, reg, data);
133 /* VBlank */
134 static CARD8 vblank_active_CRT1(SISPtr pSiS)
136 return (inSISREG(SISINPSTAT) & 0x08);
139 /* Scanline - unused */
140 #if 0
141 static CARD32 get_scanline_CRT1(SISPtr pSiS)
143 CARD8 temp;
145 temp = getvideoreg(pSiS, 0x20);
146 temp = getvideoreg(pSiS, 0x1b);
147 return((getvideoreg(pSiS, 0x1d) << 8) | getvideoreg(pSiS, 0x1c));
149 #endif
151 void SIS6326InitVideo(ScreenPtr pScreen)
153 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
154 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
155 XF86VideoAdaptorPtr newAdaptor = NULL;
156 int num_adaptors;
158 newAdaptor = SIS6326SetupImageVideo(pScreen);
159 if(newAdaptor)
160 SIS6326InitOffscreenImages(pScreen);
162 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
164 if(newAdaptor) {
165 if(!num_adaptors) {
166 num_adaptors = 1;
167 adaptors = &newAdaptor;
168 } else {
169 /* need to free this someplace */
170 newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
171 if(newAdaptors) {
172 memcpy(newAdaptors, adaptors, num_adaptors *
173 sizeof(XF86VideoAdaptorPtr));
174 newAdaptors[num_adaptors] = newAdaptor;
175 adaptors = newAdaptors;
176 num_adaptors++;
181 if(num_adaptors)
182 xf86XVScreenInit(pScreen, adaptors, num_adaptors);
184 if(newAdaptors)
185 xfree(newAdaptors);
186 #if 0
187 oldW = 0; oldH = 0; /* DEBUG */
188 #endif
191 /* client libraries expect an encoding */
192 static XF86VideoEncodingRec DummyEncoding =
195 "XV_IMAGE",
196 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
197 {1, 1}
200 static XF86VideoEncodingRec DummyEncoding5597 =
203 "XV_IMAGE",
204 IMAGE_MAX_WIDTH_5597, IMAGE_MAX_HEIGHT_5597,
205 {1, 1}
208 #define NUM_FORMATS 4
210 static XF86VideoFormatRec SIS6326Formats[NUM_FORMATS] =
212 { 8, PseudoColor},
213 {15, TrueColor},
214 {16, TrueColor},
215 {24, TrueColor}
218 #define NUM_ATTRIBUTES 6
220 static XF86AttributeRec SIS6326Attributes[NUM_ATTRIBUTES] =
222 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
223 {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
224 {XvSettable | XvGettable, 0, 7, "XV_CONTRAST"},
225 {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
226 {XvSettable , 0, 0, "XV_SET_DEFAULTS"},
227 {XvSettable | XvGettable, 0, 1, "XV_DISABLE_GRAPHICS"}
230 #define NUM_IMAGES 6
231 #define NUM_IMAGES_NOYV12 4
232 #define PIXEL_FMT_YV12 FOURCC_YV12 /* 0x32315659 */
233 #define PIXEL_FMT_UYVY FOURCC_UYVY /* 0x59565955 */
234 #define PIXEL_FMT_YUY2 FOURCC_YUY2 /* 0x32595559 */
235 #define PIXEL_FMT_I420 FOURCC_I420 /* 0x30323449 */
236 #define PIXEL_FMT_RGB5 0x35315652
237 #define PIXEL_FMT_RGB6 0x36315652
239 static XF86ImageRec SIS6326Images[NUM_IMAGES] =
241 XVIMAGE_YUY2, /* TW: If order is changed, SIS6326OffscreenImages must be adapted */
242 XVIMAGE_UYVY,
243 XVIMAGE_YV12,
244 XVIMAGE_I420,
246 0x35315652,
247 XvRGB,
248 LSBFirst,
249 {'R','V','1','5',
250 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
252 XvPacked,
254 /* 15, 0x001F, 0x03E0, 0x7C00, - incorrect! */
255 15, 0x7C00, 0x03E0, 0x001F,
256 0, 0, 0,
257 0, 0, 0,
258 0, 0, 0,
259 {'R', 'V', 'B',0,
260 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},
261 XvTopToBottom
264 0x36315652,
265 XvRGB,
266 LSBFirst,
267 {'R','V','1','6',
268 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
270 XvPacked,
272 /* 16, 0x001F, 0x07E0, 0xF800, - incorrect! */
273 16, 0xF800, 0x07E0, 0x001F,
274 0, 0, 0,
275 0, 0, 0,
276 0, 0, 0,
277 {'R', 'V', 'B',0,
278 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},
279 XvTopToBottom
283 static XF86ImageRec SIS6326ImagesNoYV12[NUM_IMAGES_NOYV12] =
285 XVIMAGE_YUY2, /* TW: If order is changed, SIS6326OffscreenImages must be adapted */
286 XVIMAGE_UYVY,
288 0x35315652,
289 XvRGB,
290 LSBFirst,
291 {'R','V','1','5',
292 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
294 XvPacked,
296 /* 15, 0x001F, 0x03E0, 0x7C00, */
297 15, 0x7C00, 0x03E0, 0x001F, /* TW: Should be more correct than the other... */
298 0, 0, 0,
299 0, 0, 0,
300 0, 0, 0,
301 {'R', 'V', 'B',0,
302 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},
303 XvTopToBottom
306 0x36315652,
307 XvRGB,
308 LSBFirst,
309 {'R','V','1','6',
310 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
312 XvPacked,
314 /* 16, 0x001F, 0x07E0, 0xF800, */
315 16, 0xF800, 0x07E0, 0x001F, /* TW: Should be more correct than the other... */
316 0, 0, 0,
317 0, 0, 0,
318 0, 0, 0,
319 {'R', 'V', 'B',0,
320 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},
321 XvTopToBottom
325 typedef struct {
326 int pixelFormat;
328 CARD16 pitch;
330 CARD8 keyOP;
332 CARD8 HUSF;
333 CARD8 VUSF;
334 CARD8 HIntBit;
335 CARD8 wHPre;
336 CARD8 PitchMult;
338 CARD16 srcW;
339 CARD16 srcH;
341 BoxRec dstBox;
343 CARD32 PSY;
344 CARD32 PSV;
345 CARD32 PSU;
346 CARD8 YUVEnd;
348 CARD8 lineBufSize;
350 CARD8 (*VBlankActiveFunc)(SISPtr);
351 /* CARD32 (*GetScanLineFunc)(SISPtr pSiS); */
353 } SISOverlayRec, *SISOverlayPtr;
355 typedef struct {
356 FBLinearPtr linear; /* TW: We now use Linear, not Area */
357 CARD32 bufAddr[2];
359 unsigned char currentBuf;
361 short drw_x, drw_y, drw_w, drw_h;
362 short src_x, src_y, src_w, src_h;
363 int id;
364 short srcPitch, height, width;
365 CARD32 totalSize;
367 char brightness;
368 unsigned char contrast;
370 RegionRec clip;
371 CARD32 colorKey;
372 Bool autopaintColorKey;
374 Bool disablegfx;
376 CARD32 videoStatus;
377 Time offTime;
378 Time freeTime;
380 short oldx1, oldx2, oldy1, oldy2;
381 int mustwait;
383 Bool grabbedByV4L; /* V4L stuff */
384 int pitch;
385 int offset;
387 } SISPortPrivRec, *SISPortPrivPtr;
389 #define GET_PORT_PRIVATE(pScrn) \
390 (SISPortPrivPtr)((SISPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
392 static void
393 SIS6326SetPortDefaults (ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
395 SISPtr pSiS = SISPTR(pScrn);
397 pPriv->colorKey = 0x000101fe;
398 pPriv->videoStatus = 0;
399 pPriv->brightness = pSiS->XvDefBri; /* 0; - see sis_opt.c */
400 pPriv->contrast = pSiS->XvDefCon; /* 4; */
401 pPriv->autopaintColorKey = TRUE;
402 pPriv->disablegfx = pSiS->XvDefDisableGfx;
405 static void
406 SIS6326ResetVideo(ScrnInfoPtr pScrn)
408 SISPtr pSiS = SISPTR(pScrn);
410 /* Unlock registers */
411 #ifdef UNLOCK_ALWAYS
412 sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL);
413 #endif
414 if(getvideoreg (pSiS, Index_VI6326_Passwd) != 0xa1) {
415 setvideoreg (pSiS, Index_VI6326_Passwd, 0x86);
416 if(getvideoreg (pSiS, Index_VI6326_Passwd) != 0xa1)
417 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
418 "Xv: Video password could not unlock video registers\n");
421 /* Initialize the overlay ----------------------------------- */
423 switch(pSiS->Chipset) {
424 case PCI_CHIP_SIS6326:
425 /* Disable overlay (D[1]) & capture (D[0]) */
426 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x03);
428 /* What do these do? (Datasheet names these bits "reserved") */
429 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18);
430 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c);
432 /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */
433 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x40, 0xD0);
434 /* No interrupt, no filter, disable dithering */
435 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x7A);
436 /* Disable VMI (D[4:3]), Brooktree support (D[6]) and system memory framebuffer (D[7]) */
437 setvideoregmask(pSiS, Index_VI6326_Control_Misc3, 0x00, 0xF8);
438 /* Disable video decimation */
439 setvideoregmask(pSiS, Index_VI6326_Control_Misc6, 0x00, 0x80);
440 break;
441 case PCI_CHIP_SIS5597:
442 /* Disable overlay (D[1]) & capture (D[0]) */
443 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x03);
445 /* What do these do? (Datasheet names these bits "reserved") */
446 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18);
447 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c);
449 /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */
450 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x40, 0xD0);
451 /* No interrupt, no filter, disable dithering */
452 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x7A);
453 /* Disable Brooktree support (D[6]) and system memory framebuffer (D[7]) */
454 setvideoregmask(pSiS, Index_VI6326_Control_Misc3, 0x00, 0xC0);
455 /* Disable video decimation (has a really strange effect if enabled) */
456 setvideoregmask(pSiS, Index_VI6326_Control_Misc6, 0x00, 0x80);
457 break;
458 case PCI_CHIP_SIS530:
459 /* What is this? (Bit is "reserved") */
460 setvideoregmask (pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40);
461 /* Disable overlay (D[1]) */
462 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x02);
464 /* What do these do? (Datasheet names these bits "reserved") */
465 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18);
466 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c);
468 /* Select YUV format (D[6]) and "gfx + video" mode (D[4]) */
469 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x40, 0x50);
470 break;
471 default:
472 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
473 "Internal error: SiS6326ResetVideo() called with invalid chipset (%x)\n",
474 pSiS->Chipset);
475 return;
478 /* Clear format selection */
479 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x04);
480 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x00, 0x07);
482 /* Select RGB Chromakey format (D[2]=0), CCIR 601 UV data format (D[1]=0) */
483 /* D[1]: 1 = 2's complement, 0 = CCIR 601 format */
484 setvideoregmask(pSiS, Index_VI6326_Control_Misc3, 0x00, 0x06);
486 /* Reset contrast control */
487 setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, 0x04, 0x1F);
489 /* Set threshold */
490 if(pSiS->oldChipset < OC_SIS6326) {
491 CARD8 temp;
492 inSISIDXREG(SISSR, 0x33, temp); /* Synchronous DRAM Timing? */
493 if(temp & 0x01) temp = 0x50;
494 else temp = 0;
495 setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low, temp);
496 setvideoreg(pSiS, Index_VI6326_Play_Threshold_High, temp);
497 } else {
498 CARD8 temp;
499 setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low, 0x00);
500 setvideoreg(pSiS, Index_VI6326_Play_Threshold_High, 0x00);
501 inSISIDXREG(SISSR, 0x33, temp); /* Are we using SGRAM Timing? */
502 if(temp & 0x01) temp = 0x10;
503 else temp = 0;
504 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, temp, 0x10);
507 /* set default properties for overlay ------------------------------- */
509 setvideoregmask (pSiS, Index_VI6326_Contrast_Enh_Ctrl, 0x04, 0x07);
510 setvideoreg (pSiS, Index_VI6326_Brightness, 0x20);
512 if(pSiS->oldChipset < OC_SIS6205A || pSiS->oldChipset > OC_SIS82204) {
513 setvideoregmask(pSiS, Index_VI6326_AlphaGraph, 0x00, 0xF8);
514 setvideoregmask(pSiS, Index_VI6326_AlphaVideo, 0xF8, 0xF8);
515 } else {
516 setvideoregmask(pSiS, Index_VI6326_AlphaGraph, 0x00, 0xE1);
517 setvideoregmask(pSiS, Index_VI6326_AlphaVideo, 0xE1, 0xE1);
521 static XF86VideoAdaptorPtr
522 SIS6326SetupImageVideo(ScreenPtr pScreen)
524 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
525 SISPtr pSiS = SISPTR(pScrn);
526 XF86VideoAdaptorPtr adapt;
527 SISPortPrivPtr pPriv;
529 if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
530 sizeof(SISPortPrivRec) +
531 sizeof(DevUnion))))
532 return NULL;
534 adapt->type = XvWindowMask | XvInputMask | XvImageMask;
535 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
536 adapt->name = "SIS 5597/5598/6326/530/620 Video Overlay";
537 adapt->nEncodings = 1;
538 if(pSiS->oldChipset < OC_SIS6326) {
539 adapt->pEncodings = &DummyEncoding5597;
540 } else {
541 adapt->pEncodings = &DummyEncoding;
543 adapt->nFormats = NUM_FORMATS;
544 adapt->pFormats = SIS6326Formats;
545 adapt->nPorts = 1;
546 adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
548 pPriv = (SISPortPrivPtr)(&adapt->pPortPrivates[1]);
550 adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
551 adapt->pAttributes = SIS6326Attributes;
552 adapt->nAttributes = NUM_ATTRIBUTES;
553 if(pSiS->NoYV12 == 1) {
554 adapt->nImages = NUM_IMAGES_NOYV12;
555 adapt->pImages = SIS6326ImagesNoYV12;
556 } else {
557 adapt->nImages = NUM_IMAGES;
558 adapt->pImages = SIS6326Images;
560 adapt->PutVideo = NULL;
561 adapt->PutStill = NULL;
562 adapt->GetVideo = NULL;
563 adapt->GetStill = NULL;
564 adapt->StopVideo = SIS6326StopVideo;
565 adapt->SetPortAttribute = SIS6326SetPortAttribute;
566 adapt->GetPortAttribute = SIS6326GetPortAttribute;
567 adapt->QueryBestSize = SIS6326QueryBestSize;
568 adapt->PutImage = SIS6326PutImage;
569 adapt->QueryImageAttributes = SIS6326QueryImageAttributes;
571 pPriv->videoStatus = 0;
572 pPriv->currentBuf = 0;
573 pPriv->linear = NULL;
574 pPriv->grabbedByV4L= FALSE;
576 SIS6326SetPortDefaults(pScrn, pPriv);
578 /* gotta uninit this someplace */
579 REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
581 pSiS->adaptor = adapt;
583 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
584 xvContrast = MAKE_ATOM("XV_CONTRAST");
585 xvColorKey = MAKE_ATOM("XV_COLORKEY");
586 xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
587 xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS");
588 xvDisableGfx = MAKE_ATOM("XV_DISABLE_GRAPHICS");
590 SIS6326ResetVideo(pScrn);
592 return adapt;
595 #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,0,0)
596 static Bool
597 RegionsEqual(RegionPtr A, RegionPtr B)
599 int *dataA, *dataB;
600 int num;
602 num = REGION_NUM_RECTS(A);
603 if(num != REGION_NUM_RECTS(B))
604 return FALSE;
606 if((A->extents.x1 != B->extents.x1) ||
607 (A->extents.x2 != B->extents.x2) ||
608 (A->extents.y1 != B->extents.y1) ||
609 (A->extents.y2 != B->extents.y2))
610 return FALSE;
612 dataA = (int*)REGION_RECTS(A);
613 dataB = (int*)REGION_RECTS(B);
615 while(num--) {
616 if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
617 return FALSE;
618 dataA += 2;
619 dataB += 2;
622 return TRUE;
624 #endif
626 static int
627 SIS6326SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
628 INT32 value, pointer data)
630 SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
632 if(attribute == xvBrightness) {
633 if((value < -128) || (value > 127))
634 return BadValue;
635 pPriv->brightness = value;
636 } else if(attribute == xvContrast) {
637 if((value < 0) || (value > 7))
638 return BadValue;
639 pPriv->contrast = value;
640 } else if(attribute == xvColorKey) {
641 pPriv->colorKey = value;
642 REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
643 } else if (attribute == xvAutopaintColorKey) {
644 if((value < 0) || (value > 1))
645 return BadValue;
646 pPriv->autopaintColorKey = value;
647 } else if(attribute == xvDisableGfx) {
648 if((value < 0) || (value > 1))
649 return BadValue;
650 pPriv->disablegfx = value;
651 } else if (attribute == xvSetDefaults) {
652 SIS6326SetPortDefaults(pScrn, pPriv);
653 } else return BadMatch;
654 return Success;
657 static int
658 SIS6326GetPortAttribute(
659 ScrnInfoPtr pScrn,
660 Atom attribute,
661 INT32 *value,
662 pointer data
664 SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
666 if(attribute == xvBrightness) {
667 *value = pPriv->brightness;
668 } else if(attribute == xvContrast) {
669 *value = pPriv->contrast;
670 } else if(attribute == xvColorKey) {
671 *value = pPriv->colorKey;
672 } else if (attribute == xvAutopaintColorKey) {
673 *value = (pPriv->autopaintColorKey) ? 1 : 0;
674 } else if (attribute == xvDisableGfx) {
675 *value = (pPriv->disablegfx) ? 1 : 0;
676 } else return BadMatch;
677 return Success;
680 static void
681 SIS6326QueryBestSize(
682 ScrnInfoPtr pScrn,
683 Bool motion,
684 short vid_w, short vid_h,
685 short drw_w, short drw_h,
686 unsigned int *p_w, unsigned int *p_h,
687 pointer data
689 *p_w = drw_w;
690 *p_h = drw_h;
692 /* TODO: report the HW limitation */
695 static void /* V 530/6326 */
696 calc_scale_factor(SISPtr pSiS, SISOverlayPtr pOverlay, ScrnInfoPtr pScrn,
697 SISPortPrivPtr pPriv)
699 CARD32 temp=0;
701 int dstW = pOverlay->dstBox.x2 - pOverlay->dstBox.x1;
702 int dstH = pOverlay->dstBox.y2 - pOverlay->dstBox.y1;
703 int srcW = pOverlay->srcW;
704 int srcH = pOverlay->srcH;
706 #if 0
707 /* DEBUG */
708 if((oldH != dstH) || (oldW != dstW)){
709 xf86DrvMsg(0, X_INFO, "Video size %dx%d\n", dstW, dstH);
710 oldH = dstH; oldW = dstW;
712 /* /DEBUG */
713 #endif
715 /* TW: For double scan modes, we need to double the height */
716 if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) {
717 dstH <<= 1;
719 /* TW: For interlace modes, we need to half the height */
720 if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) {
721 dstH >>= 1;
724 /* Horizontal */
725 if(dstW < IMAGE_MIN_WIDTH) dstW = IMAGE_MIN_WIDTH;
726 if(dstW == srcW) {
727 pOverlay->HUSF = 0x00;
728 pOverlay->HIntBit = 0x01;
729 } else if(dstW > srcW) {
730 pOverlay->HIntBit = 0x00;
731 temp = srcW * 64 / (dstW + 1);
732 if(temp > 63) temp = 63;
733 pOverlay->HUSF = temp;
734 } else {
735 /* 6326 can't scale below factor .440 - to check with 530/620 */
736 if(((dstW * 1000) / srcW) < 440) dstW = ((srcW * 440) / 1000) + 1;
737 temp = srcW / dstW;
738 if(temp > 15) temp = 15;
739 pOverlay->HIntBit = temp;
740 temp = srcW * 64 / dstW;
741 pOverlay->HUSF = temp - (pOverlay->HIntBit * 64);
744 /* Vertical */
745 if(dstH < IMAGE_MIN_HEIGHT) dstH = IMAGE_MIN_HEIGHT;
746 if(dstH == srcH) {
747 pOverlay->VUSF = 0x00;
748 pOverlay->PitchMult = 1;
749 } else if(dstH > srcH) {
750 temp = srcH * 64 / (dstH + 1);
751 if (temp > 63) temp = 63;
752 pOverlay->VUSF = temp;
753 pOverlay->PitchMult = 1;
754 } else {
755 /* 6326 can't scale below factor .440 - to check with 530/620 */
756 if(((dstH * 1000) / srcH) < 440) dstH = ((srcH * 440) / 1000) + 1;
757 temp = srcH / dstH;
758 if(srcH % dstH) {
759 temp++;
760 pOverlay->VUSF = (srcH * 64) / (temp * dstH);
761 } else {
762 pOverlay->VUSF = 0x00;
764 pOverlay->PitchMult = temp;
768 static void
769 calc_line_buf_size(SISOverlayPtr pOverlay)
771 CARD32 I;
772 CARD32 line = pOverlay->srcW;
774 if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
775 (pOverlay->pixelFormat == PIXEL_FMT_I420) )
777 I = (line >> 5) + (((line >> 6) * 2)) + 3;
778 I <<= 5;
779 } else { /* YUV2, UYVY, RGB */
780 I = line << 1;
781 if(I & 7) I += 8;
783 I += 8;
784 I >>= 3;
785 pOverlay->lineBufSize = (CARD8)I;
788 static void
789 merge_line_buf(SISPtr pSiS, SISPortPrivPtr pPriv, Bool enable)
791 if(enable) {
792 setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x10, 0x10);
793 } else {
794 setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x00, 0x10);
798 static void
799 set_format(SISPtr pSiS, SISOverlayPtr pOverlay)
801 CARD8 fmt, misc0, misc1, misc4;
803 switch (pOverlay->pixelFormat){
804 case PIXEL_FMT_YV12:
805 case PIXEL_FMT_I420: /* V/530 V/6326 */
806 fmt = 0x80; /* D[7:6] 10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
807 misc0 = 0x40; /* D[6]: 1 = YUV, 0 = RGB */
808 misc4 = 0x05; /* D[1:0] 00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
809 misc1 = 0xff;
810 break;
811 case PIXEL_FMT_UYVY:
812 fmt = 0x00; /* D[7:6] 10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
813 misc0 = 0x40; /* D[6]: 1 = YUV, 0 = RGB */
814 misc4 = 0x00; /* D[1:0] 00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
815 misc1 = 0xff;
816 break;
817 case PIXEL_FMT_YUY2: /* V/530 V/6326 */
818 fmt = 0x80; /* D[7:6] 10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
819 misc0 = 0x40; /* D[6]: 1 = YUV, 0 = RGB */
820 misc4 = 0x00; /* D[1:0] 00 RGB 555, 01 YUV 422, 10 RGB 565; D[2] 1 = YUV420 mode */
821 misc1 = 0xff;
822 break;
823 case PIXEL_FMT_RGB6: /* V/530 V/6326 */
824 fmt = 0x40; /* D[7:6] 10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
825 misc0 = 0x00; /* D[6]: 1 = YUV, 0 = RGB */
826 misc4 = 0xff;
827 misc1 = 0x00; /* D[2] = Capture format selection (DS5597) - WDR sets this */
828 break;
829 case PIXEL_FMT_RGB5: /* V/530 V/6326 */
830 default:
831 fmt = 0x00; /* D[7:6] 10 YUV2(=YUYV), 01 VYUY, 00 UYVY, 11 YVYU / 00 RGB 555, 01 RGB 565 */
832 misc0 = 0x00; /* D[6]: 1 = YUV, 0 = RGB */
833 misc4 = 0xff;
834 misc1 = 0x04; /* D[2] = Capture format selection (DS5597) - WDR sets this */
835 break;
838 setvideoregmask(pSiS, Index_VI6326_VideoFormatSelect, fmt, 0xC0);
839 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, misc0, 0x40);
840 if(misc4 == 0xff) {
841 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, misc1, 0x04);
842 if(pSiS->oldChipset >= OC_SIS5597) {
843 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x00, 0x05);
845 } else {
846 if(pSiS->oldChipset >= OC_SIS5597) {
847 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, misc4, 0x05);
849 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x04);
853 static void
854 set_colorkey(SISPtr pSiS, CARD32 colorkey)
856 CARD8 r, g, b, s;
858 b = (CARD8)(colorkey & 0xFF);
859 g = (CARD8)((colorkey>>8) & 0xFF);
860 r = (CARD8)((colorkey>>16) & 0xFF);
862 if(pSiS->CurrentLayout.bitsPerPixel >= 24) {
863 s = b;
864 b = r;
865 r = s;
868 setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Blue_Min ,(CARD8)b);
869 setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Green_Min ,(CARD8)g);
870 setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Red_Min ,(CARD8)r);
872 setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Blue_Max ,(CARD8)b);
873 setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Green_Max ,(CARD8)g);
874 setvideoreg(pSiS, Index_VI6326_Overlay_ColorKey_Red_Max ,(CARD8)r);
877 static __inline void
878 set_brightness(SISPtr pSiS, CARD8 brightness)
880 setvideoreg(pSiS, Index_VI6326_Brightness, brightness);
883 static __inline void
884 set_contrast(SISPtr pSiS, CARD8 contrast)
886 setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, contrast, 0x07);
889 static void
890 set_contrast_data(SISPtr pSiS, int value)
892 unsigned long temp;
894 if(value < 10000) temp = 0;
895 else temp = (value - 10000) / 20000;
896 if(temp > 3) temp = 3;
897 setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, (temp << 6), 0xC0);
898 switch(temp) {
899 case 0: temp = 2048; break;
900 case 1: temp = 4096; break;
901 case 2: temp = 8192; break;
902 case 3: temp = 16384; break;
904 temp <<= 10;
905 temp /= value;
906 setvideoreg(pSiS, Index_VI6326_Contrast_Factor, temp);
909 static __inline void
910 set_disablegfx(SISPtr pSiS, Bool mybool)
912 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, mybool ? 0x10 : 0x00, 0x10);
915 static void
916 set_overlay(SISPtr pSiS, SISOverlayPtr pOverlay, SISPortPrivPtr pPriv, int index)
918 ScrnInfoPtr pScrn = pSiS->pScrn;
920 CARD16 pitch=0;
921 CARD8 h_over=0, v_over=0;
922 CARD16 top, bottom, left, right;
923 CARD16 screenX = pSiS->CurrentLayout.mode->HDisplay;
924 CARD16 screenY = pSiS->CurrentLayout.mode->VDisplay;
925 CARD32 watchdog;
927 top = pOverlay->dstBox.y1;
928 bottom = pOverlay->dstBox.y2;
929 if(bottom > screenY) {
930 bottom = screenY;
933 left = pOverlay->dstBox.x1;
934 right = pOverlay->dstBox.x2;
935 if(right > screenX) {
936 right = screenX;
939 /* TW: DoubleScan modes require Y coordinates * 2 */
940 if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) {
941 top <<= 1;
942 bottom <<= 1;
944 /* TW: Interlace modes require Y coordinates / 2 */
945 if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) {
946 top >>= 1;
947 bottom >>= 1;
950 h_over = (((left>>8) & 0x07) | ((right>>4) & 0x70));
951 v_over = (((top>>8) & 0x07) | ((bottom>>4) & 0x70));
953 pitch = pOverlay->pitch * pOverlay->PitchMult;
954 pitch >>= 2; /* Datasheet: Unit = double word - verified */
955 if(pitch > 0xfff) {
956 pitch = pOverlay->pitch * (0xFFF * 2 / pOverlay->pitch);
957 pOverlay->VUSF = 0x3F;
960 /* set color key */
961 set_colorkey(pSiS, pPriv->colorKey);
963 /* set color key mode */
964 setvideoregmask(pSiS, Index_VI6326_Key_Overlay_OP, pOverlay->keyOP, 0x0f);
966 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c);
967 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18);
969 /* Set Y buf pitch */ /* Datasheet: Unit = double word - verified */
970 setvideoreg(pSiS, Index_VI6326_Disp_Y_Buf_Pitch_Low, (CARD8)(pitch));
971 setvideoregmask(pSiS, Index_VI6326_Disp_Y_Buf_Pitch_High, (CARD8)(pitch>>8), 0x0f);
972 /* Set U/V pitch if using planar formats */
973 if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
974 (pOverlay->pixelFormat == PIXEL_FMT_I420) ) {
975 /* Set U/V pitch */ /* Datasheet: Unit = double word - verified */
976 setvideoreg(pSiS, Index_VI6326_Disp_UV_Buf_Pitch_Low, (CARD8)pitch >> 1);
977 setvideoregmask(pSiS, Index_VI6326_Disp_UV_Buf_Pitch_High, (CARD8)(pitch >> 9), 0x0f);
980 /* set line buffer size */
981 setvideoreg(pSiS, Index_VI6326_Line_Buffer_Size, pOverlay->lineBufSize);
983 /* set scale factor */
984 setvideoreg(pSiS, Index_VI6326_Hor_Scale, (CARD8)((pOverlay->HUSF) | 0xC0));
985 setvideoregmask(pSiS, Index_VI6326_Hor_Scale_Integer, (CARD8)(pOverlay->HIntBit), 0x0F);
986 setvideoregmask(pSiS, Index_VI6326_Ver_Scale, (CARD8)(pOverlay->VUSF), 0x3F);
988 /* TW: We don't have to wait for vertical retrace in all cases */
989 if(pPriv->mustwait) {
990 watchdog = WATCHDOG_DELAY;
991 while ((!pOverlay->VBlankActiveFunc(pSiS)) && --watchdog);
992 if(!watchdog) xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
993 "Xv: Waiting for vertical retrace timed-out\n");
996 /* set destination window position */
997 setvideoreg(pSiS, Index_VI6326_Win_Hor_Disp_Start_Low, (CARD8)left);
998 setvideoreg(pSiS, Index_VI6326_Win_Hor_Disp_End_Low, (CARD8)right);
999 setvideoreg(pSiS, Index_VI6326_Win_Hor_Over, (CARD8)h_over);
1001 setvideoreg(pSiS, Index_VI6326_Win_Ver_Disp_Start_Low, (CARD8)top);
1002 setvideoreg(pSiS, Index_VI6326_Win_Ver_Disp_End_Low, (CARD8)bottom);
1003 setvideoreg(pSiS, Index_VI6326_Win_Ver_Over, (CARD8)v_over);
1005 /* Set Y start address */
1006 setvideoreg (pSiS, Index_VI6326_Disp_Y_Buf_Start_Low, (CARD8)(pOverlay->PSY));
1007 setvideoreg (pSiS, Index_VI6326_Disp_Y_Buf_Start_Middle, (CARD8)((pOverlay->PSY)>>8));
1008 if(pSiS->oldChipset <= OC_SIS6326) { /* all old chipsets incl 6326 */
1009 /* Set overflow bits */
1010 setvideoregmask (pSiS, Index_VI6326_Disp_Capt_Y_Buf_Start_High,
1011 (CARD8)(((pOverlay->PSY)>>12) & 0xF0), 0xF0);
1012 /* Set framebuffer end address */
1013 setvideoreg (pSiS, Index_VI6326_Disp_Y_End, (CARD8)(pOverlay->YUVEnd));
1014 } else { /* 530/620 */
1015 /* Set overflow bits */
1016 setvideoregmask (pSiS, Index_VI6326_Disp_Capt_Y_Buf_Start_High,
1017 (CARD8)(((pOverlay->PSY)>>13) & 0xF8), 0xF8);
1020 /* Set U/V start addresses if using plane formats */
1021 if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) ||
1022 (pOverlay->pixelFormat == PIXEL_FMT_I420) ) {
1024 CARD32 PSU = pOverlay->PSU;
1025 CARD32 PSV = pOverlay->PSV;
1027 /* set U/V start address */
1028 setvideoreg (pSiS, Index_VI6326_U_Buf_Start_Low, (CARD8)PSU);
1029 setvideoreg (pSiS, Index_VI6326_U_Buf_Start_Middle,(CARD8)(PSU >> 8));
1031 setvideoreg (pSiS, Index_VI6326_V_Buf_Start_Low, (CARD8)PSV);
1032 setvideoreg (pSiS, Index_VI6326_V_Buf_Start_Middle,(CARD8)(PSV >> 8));
1034 setvideoreg (pSiS, Index_VI6326_UV_Buf_Start_High,
1035 (CARD8)(((PSU >> 16) & 0x0F) | ((PSV >> 12) & 0xF0)) );
1037 if(pSiS->oldChipset > OC_SIS6326) {
1038 /* Set bit 20 of the addresses in Misc5 (530/620 only) */
1039 setvideoreg (pSiS, Index_VI6326_Control_Misc5,
1040 (CARD8)(((PSU >> (20-1)) & 0x02) | ((PSV >> (20-2)) & 0x04)) );
1044 /* set brightness and contrast */
1045 set_brightness(pSiS, pPriv->brightness);
1046 if(pSiS->oldChipset > OC_SIS6205C) {
1047 set_contrast_data(pSiS, (pOverlay->dstBox.x2 - pOverlay->dstBox.x1) *
1048 (pOverlay->dstBox.y2 - pOverlay->dstBox.y1));
1049 set_contrast(pSiS, pPriv->contrast);
1052 /* enable/disable graphics display around overlay */
1053 set_disablegfx(pSiS, pPriv->disablegfx);
1055 /* set format */
1056 set_format(pSiS, pOverlay);
1059 /* Overlay MUST NOT be switched off while beam is over it */
1060 static void
1061 close_overlay(SISPtr pSiS, SISPortPrivPtr pPriv)
1063 CARD32 watchdog;
1065 watchdog = WATCHDOG_DELAY;
1066 while((!vblank_active_CRT1(pSiS)) && --watchdog);
1067 if(pSiS->oldChipset > OC_SIS6326) {
1068 /* what is this? */
1069 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40);
1071 /* disable overlay */
1072 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x02);
1075 static void
1076 SIS6326DisplayVideo(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv)
1078 SISPtr pSiS = SISPTR(pScrn);
1080 short srcPitch = pPriv->srcPitch;
1081 short height = pPriv->height;
1082 short width = pPriv->width;
1083 SISOverlayRec overlay;
1084 int srcOffsetX=0, srcOffsetY=0;
1085 int sx, sy;
1086 int index = 0;
1087 int pitch;
1089 memset(&overlay, 0, sizeof(overlay));
1090 overlay.pixelFormat = pPriv->id;
1091 overlay.pitch = srcPitch;
1092 overlay.keyOP = VI6326_ROP_DestKey; /* DestKey mode */
1094 overlay.dstBox.x1 = pPriv->drw_x - pScrn->frameX0;
1095 overlay.dstBox.x2 = pPriv->drw_x + pPriv->drw_w - pScrn->frameX0;
1096 overlay.dstBox.y1 = pPriv->drw_y - pScrn->frameY0;
1097 overlay.dstBox.y2 = pPriv->drw_y + pPriv->drw_h - pScrn->frameY0;
1099 if((overlay.dstBox.x1 > overlay.dstBox.x2) ||
1100 (overlay.dstBox.y1 > overlay.dstBox.y2))
1101 return;
1103 if((overlay.dstBox.x2 < 0) || (overlay.dstBox.y2 < 0))
1104 return;
1106 if(overlay.dstBox.x1 < 0) {
1107 srcOffsetX = pPriv->src_w * (-overlay.dstBox.x1) / pPriv->drw_w;
1108 overlay.dstBox.x1 = 0;
1110 if(overlay.dstBox.y1 < 0) {
1111 srcOffsetY = pPriv->src_h * (-overlay.dstBox.y1) / pPriv->drw_h;
1112 overlay.dstBox.y1 = 0;
1115 switch(pPriv->id){
1116 case PIXEL_FMT_YV12:
1117 sx = (pPriv->src_x + srcOffsetX) & ~7;
1118 sy = (pPriv->src_y + srcOffsetY) & ~1;
1119 pitch = (width + 3) & ~3;
1120 overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy * pitch;
1121 overlay.PSV = overlay.PSY + pitch * height;
1122 overlay.PSU = overlay.PSV + ((((width >> 1) + 3) & ~3) * (height >> 1));
1123 overlay.PSY >>= 2;
1124 overlay.PSV >>= 2;
1125 overlay.PSU >>= 2;
1126 break;
1127 case PIXEL_FMT_I420:
1128 sx = (pPriv->src_x + srcOffsetX) & ~7;
1129 sy = (pPriv->src_y + srcOffsetY) & ~1;
1130 pitch = (width + 3) & ~3;
1131 overlay.PSY = pPriv->bufAddr[pPriv->currentBuf] + sx + sy * pitch;
1132 overlay.PSU = overlay.PSY + pitch * height;
1133 overlay.PSV = overlay.PSU + ((((width >> 1) + 3) & ~3) * (height >> 1));
1134 overlay.PSY >>= 2;
1135 overlay.PSV >>= 2;
1136 overlay.PSU >>= 2;
1137 break;
1138 case PIXEL_FMT_YUY2:
1139 case PIXEL_FMT_UYVY:
1140 case PIXEL_FMT_RGB6:
1141 case PIXEL_FMT_RGB5:
1142 default:
1143 sx = (pPriv->src_x + srcOffsetX) & ~1;
1144 sy = (pPriv->src_y + srcOffsetY);
1145 overlay.PSY = (pPriv->bufAddr[pPriv->currentBuf] + sx*2 + sy*srcPitch);
1146 overlay.PSY >>= 2;
1147 break;
1150 /* FIXME: Is this correct? (Is it required to set the end address?
1151 * Datasheet is not clear) - (reg does not exist on 530/620)
1153 overlay.YUVEnd = (pPriv->bufAddr[pPriv->currentBuf] + pPriv->totalSize) >> 14;
1155 /* FIXME: is it possible that srcW < 0 */
1156 overlay.srcW = pPriv->src_w - (sx - pPriv->src_x);
1157 overlay.srcH = pPriv->src_h - (sy - pPriv->src_y);
1159 if ( (pPriv->oldx1 != overlay.dstBox.x1) ||
1160 (pPriv->oldx2 != overlay.dstBox.x2) ||
1161 (pPriv->oldy1 != overlay.dstBox.y1) ||
1162 (pPriv->oldy2 != overlay.dstBox.y2) ) {
1163 pPriv->mustwait = 1;
1164 pPriv->oldx1 = overlay.dstBox.x1; pPriv->oldx2 = overlay.dstBox.x2;
1165 pPriv->oldy1 = overlay.dstBox.y1; pPriv->oldy2 = overlay.dstBox.y2;
1168 /* calculate line buffer length */
1169 calc_line_buf_size(&overlay);
1171 overlay.VBlankActiveFunc = vblank_active_CRT1;
1172 /* overlay.GetScanLineFunc = get_scanline_CRT1; */
1174 /* calculate scale factor */
1175 calc_scale_factor(pSiS, &overlay, pScrn, pPriv);
1177 /* set (not only determine) if line buffer is to be merged */
1178 if(pSiS->oldChipset > OC_SIS5597) {
1179 int temp;
1180 if(pSiS->oldChipset <= OC_SIS6326) temp = 352;
1181 else temp = 384;
1182 merge_line_buf(pSiS, pPriv, (overlay.srcW > temp));
1185 /* set overlay */
1186 set_overlay(pSiS, &overlay, pPriv, index);
1188 /* enable overlay */
1189 if(pSiS->oldChipset > OC_SIS6326) {
1190 setvideoregmask (pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40);
1192 setvideoregmask (pSiS, Index_VI6326_Control_Misc0, 0x02, 0x02);
1194 pPriv->mustwait = 0;
1197 static FBLinearPtr
1198 SIS6326AllocateOverlayMemory(
1199 ScrnInfoPtr pScrn,
1200 FBLinearPtr linear,
1201 int size
1203 ScreenPtr pScreen;
1204 FBLinearPtr new_linear;
1206 if(linear) {
1207 if(linear->size >= size)
1208 return linear;
1210 if(xf86ResizeOffscreenLinear(linear, size))
1211 return linear;
1213 xf86FreeOffscreenLinear(linear);
1216 pScreen = screenInfo.screens[pScrn->scrnIndex];
1218 new_linear = xf86AllocateOffscreenLinear(pScreen, size, 32,
1219 NULL, NULL, NULL);
1221 if(!new_linear) {
1222 int max_size;
1224 xf86QueryLargestOffscreenLinear(pScreen, &max_size, 32,
1225 PRIORITY_EXTREME);
1227 if(max_size < size) return NULL;
1229 xf86PurgeUnlockedOffscreenAreas(pScreen);
1230 new_linear = xf86AllocateOffscreenLinear(pScreen, size, 32,
1231 NULL, NULL, NULL);
1233 if (!new_linear)
1234 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1235 "Xv: Failed to allocate %dK of video memory\n", size/1024);
1237 return new_linear;
1240 static void
1241 SIS6326FreeOverlayMemory(ScrnInfoPtr pScrn)
1243 SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
1245 if(pPriv->linear) {
1246 xf86FreeOffscreenLinear(pPriv->linear);
1247 pPriv->linear = NULL;
1251 static void
1252 SIS6326StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
1254 SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
1255 SISPtr pSiS = SISPTR(pScrn);
1257 if(pPriv->grabbedByV4L)
1258 return;
1260 REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1262 if(shutdown) {
1263 if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
1264 close_overlay(pSiS, pPriv);
1265 pPriv->mustwait = 1;
1267 SIS6326FreeOverlayMemory(pScrn);
1268 pPriv->videoStatus = 0;
1269 pSiS->VideoTimerCallback = NULL;
1270 } else {
1271 if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
1272 pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
1273 pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
1274 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1279 static int
1280 SIS6326PutImage(
1281 ScrnInfoPtr pScrn,
1282 short src_x, short src_y,
1283 short drw_x, short drw_y,
1284 short src_w, short src_h,
1285 short drw_w, short drw_h,
1286 int id, unsigned char* buf,
1287 short width, short height,
1288 Bool sync,
1289 RegionPtr clipBoxes, pointer data
1291 SISPtr pSiS = SISPTR(pScrn);
1292 SISPortPrivPtr pPriv = (SISPortPrivPtr)data;
1293 int totalSize=0;
1294 int depth = pSiS->CurrentLayout.bitsPerPixel >> 3;
1295 CARD32 *src, *dest;
1296 unsigned long i;
1298 if(pPriv->grabbedByV4L)
1299 return Success;
1301 pPriv->drw_x = drw_x;
1302 pPriv->drw_y = drw_y;
1303 pPriv->drw_w = drw_w;
1304 pPriv->drw_h = drw_h;
1305 pPriv->src_x = src_x;
1306 pPriv->src_y = src_y;
1307 pPriv->src_w = src_w;
1308 pPriv->src_h = src_h;
1309 pPriv->id = id;
1310 pPriv->height = height;
1311 pPriv->width = width;
1313 /* TW: Pixel formats:
1314 1. YU12: 3 planes: H V
1315 Y sample period 1 1 (8 bit per pixel)
1316 V sample period 2 2 (8 bit per pixel, subsampled)
1317 U sample period 2 2 (8 bit per pixel, subsampled)
1319 Y plane is fully sampled (width*height), U and V planes
1320 are sampled in 2x2 blocks, hence a group of 4 pixels requires
1321 4 + 1 + 1 = 6 bytes. The data is planar, ie in single planes
1322 for Y, U and V.
1323 2. UYVY: 3 planes: H V
1324 Y sample period 1 1 (8 bit per pixel)
1325 V sample period 2 1 (8 bit per pixel, subsampled)
1326 U sample period 2 1 (8 bit per pixel, subsampled)
1327 Y plane is fully sampled (width*height), U and V planes
1328 are sampled in 2x1 blocks, hence a group of 4 pixels requires
1329 4 + 2 + 2 = 8 bytes. The data is bit packed, there are no separate
1330 Y, U or V planes.
1331 Bit order: U0 Y0 V0 Y1 U2 Y2 V2 Y3 ...
1332 3. I420: Like YU12, but planes U and V are in reverse order.
1333 4. YUY2: Like UYVY, but order is
1334 Y0 U0 Y1 V0 Y2 U2 Y3 V2 ...
1337 switch(id){
1338 case PIXEL_FMT_YV12:
1339 case PIXEL_FMT_I420:
1340 pPriv->srcPitch = (width + 7) & ~7;
1341 /* Size = width * height * 3 / 2 */
1342 totalSize = (pPriv->srcPitch * height * 3) >> 1;
1343 break;
1344 case PIXEL_FMT_YUY2:
1345 case PIXEL_FMT_UYVY:
1346 case PIXEL_FMT_RGB5:
1347 case PIXEL_FMT_RGB6:
1348 default:
1349 pPriv->srcPitch = ((width << 1) + 3) & ~3;
1350 /* Size = width * 2 * height */
1351 totalSize = pPriv->srcPitch * height;
1354 /* make it a multiple of 16 to simplify to copy loop */
1355 totalSize += 15;
1356 totalSize &= ~15;
1358 pPriv->totalSize = totalSize;
1360 /* allocate memory (we do doublebuffering) */
1361 if(!(pPriv->linear = SIS6326AllocateOverlayMemory(pScrn, pPriv->linear,
1362 totalSize<<1)))
1363 return BadAlloc;
1365 /* fixup pointers */
1366 pPriv->bufAddr[0] = (pPriv->linear->offset * depth);
1367 pPriv->bufAddr[1] = pPriv->bufAddr[0] + totalSize;
1369 /* copy data */
1370 if((pSiS->XvUseMemcpy) || (totalSize < 16)) {
1371 memcpy(pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf], buf, totalSize);
1372 } else {
1373 dest = (CARD32 *)(pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf]);
1374 src = (CARD32 *)buf;
1375 for(i = 0; i < (totalSize/16); i++) {
1376 *dest++ = *src++;
1377 *dest++ = *src++;
1378 *dest++ = *src++;
1379 *dest++ = *src++;
1383 SIS6326DisplayVideo(pScrn, pPriv);
1385 /* update cliplist */
1386 #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,0,0)
1387 if( pPriv->autopaintColorKey &&
1388 (pPriv->grabbedByV4L ||
1389 !RegionsEqual(&pPriv->clip, clipBoxes)) ) {
1390 /* We always paint colorkey for V4L */
1391 if(!pPriv->grabbedByV4L)
1392 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
1393 /* draw these */
1394 XAAFillSolidRects(pScrn, pPriv->colorKey, GXcopy, ~0,
1395 REGION_NUM_RECTS(clipBoxes),
1396 REGION_RECTS(clipBoxes));
1398 #else
1399 if( pPriv->autopaintColorKey &&
1400 (pPriv->grabbedByV4L ||
1401 !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) ) {
1402 /* We always paint colorkey for V4L */
1403 if(!pPriv->grabbedByV4L)
1404 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
1405 /* draw these */
1406 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
1408 #endif
1410 pPriv->currentBuf ^= 1;
1412 pPriv->videoStatus = CLIENT_VIDEO_ON;
1414 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1416 return Success;
1419 static int
1420 SIS6326QueryImageAttributes(
1421 ScrnInfoPtr pScrn,
1422 int id,
1423 unsigned short *w, unsigned short *h,
1424 int *pitches, int *offsets
1426 SISPtr pSiS = SISPTR(pScrn);
1427 int pitchY, pitchUV;
1428 int size, sizeY, sizeUV;
1430 if(*w < IMAGE_MIN_WIDTH) *w = IMAGE_MIN_WIDTH;
1431 if(*h < IMAGE_MIN_HEIGHT) *h = IMAGE_MIN_HEIGHT;
1433 if(pSiS->oldChipset < OC_SIS6326) {
1434 if(*w > IMAGE_MAX_WIDTH_5597) *w = IMAGE_MAX_WIDTH_5597;
1435 if(*h > IMAGE_MAX_HEIGHT_5597) *h = IMAGE_MAX_HEIGHT_5597;
1436 } else {
1437 if(*w > IMAGE_MAX_WIDTH) *w = IMAGE_MAX_WIDTH;
1438 if(*h > IMAGE_MAX_HEIGHT) *h = IMAGE_MAX_HEIGHT;
1441 switch(id) {
1442 case PIXEL_FMT_YV12:
1443 case PIXEL_FMT_I420:
1444 *w = (*w + 7) & ~7;
1445 *h = (*h + 1) & ~1;
1446 pitchY = *w;
1447 pitchUV = *w >> 1;
1448 if(pitches) {
1449 pitches[0] = pitchY;
1450 pitches[1] = pitches[2] = pitchUV;
1452 sizeY = pitchY * (*h);
1453 sizeUV = pitchUV * ((*h) >> 1);
1454 if(offsets) {
1455 offsets[0] = 0;
1456 offsets[1] = sizeY;
1457 offsets[2] = sizeY + sizeUV;
1459 size = sizeY + (sizeUV << 1);
1460 break;
1461 case PIXEL_FMT_YUY2:
1462 case PIXEL_FMT_UYVY:
1463 case PIXEL_FMT_RGB5:
1464 case PIXEL_FMT_RGB6:
1465 default:
1466 *w = (*w + 1) & ~1;
1467 pitchY = *w << 1;
1468 if(pitches) pitches[0] = pitchY;
1469 if(offsets) offsets[0] = 0;
1470 size = pitchY * (*h);
1471 break;
1474 return size;
1477 static void
1478 SIS6326VideoTimerCallback (ScrnInfoPtr pScrn, Time now)
1480 SISPtr pSiS = SISPTR(pScrn);
1481 SISPortPrivPtr pPriv = NULL;
1482 unsigned char sridx, cridx;
1484 pSiS->VideoTimerCallback = NULL;
1486 if(!pScrn->vtSema) return;
1488 if(pSiS->adaptor) {
1489 pPriv = GET_PORT_PRIVATE(pScrn);
1490 if(!pPriv->videoStatus)
1491 pPriv = NULL;
1494 if(pPriv) {
1495 if(pPriv->videoStatus & TIMER_MASK) {
1496 UpdateCurrentTime();
1497 if(pPriv->offTime < currentTime.milliseconds) {
1498 if(pPriv->videoStatus & OFF_TIMER) {
1499 /* Turn off the overlay */
1500 sridx = inSISREG(SISSR); cridx = inSISREG(SISCR);
1501 close_overlay(pSiS, pPriv);
1502 outSISREG(SISSR, sridx); outSISREG(SISCR, cridx);
1503 pPriv->mustwait = 1;
1504 pPriv->videoStatus = FREE_TIMER;
1505 pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1506 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1507 } else
1508 if(pPriv->videoStatus & FREE_TIMER) {
1509 SIS6326FreeOverlayMemory(pScrn);
1510 pPriv->mustwait = 1;
1511 pPriv->videoStatus = 0;
1513 } else
1514 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback;
1519 /* Offscreen surface stuff for v4l */
1521 static int
1522 SIS6326AllocSurface (
1523 ScrnInfoPtr pScrn,
1524 int id,
1525 unsigned short w,
1526 unsigned short h,
1527 XF86SurfacePtr surface
1530 SISPtr pSiS = SISPTR(pScrn);
1531 SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
1532 int size, depth;
1534 if((w < IMAGE_MIN_WIDTH) || (h < IMAGE_MIN_HEIGHT))
1535 return BadValue;
1537 if(pSiS->oldChipset < OC_SIS6326) {
1538 if((w > IMAGE_MAX_WIDTH_5597) || (h > IMAGE_MAX_HEIGHT_5597))
1539 return BadValue;
1540 } else {
1541 if((w > IMAGE_MAX_WIDTH) || (h > IMAGE_MAX_HEIGHT))
1542 return BadValue;
1545 if(pPriv->grabbedByV4L)
1546 return BadAlloc;
1548 depth = pSiS->CurrentLayout.bitsPerPixel >> 3;
1550 w = (w + 1) & ~1;
1551 pPriv->pitch = ((w << 1) + 63) & ~63; /* Only packed pixel modes supported */
1552 size = h * pPriv->pitch;
1553 pPriv->linear = SIS6326AllocateOverlayMemory(pScrn, pPriv->linear, size);
1554 if(!pPriv->linear)
1555 return BadAlloc;
1557 pPriv->totalSize = size;
1559 pPriv->offset = pPriv->linear->offset * depth;
1561 surface->width = w;
1562 surface->height = h;
1563 surface->pScrn = pScrn;
1564 surface->id = id;
1565 surface->pitches = &pPriv->pitch;
1566 surface->offsets = &pPriv->offset;
1567 surface->devPrivate.ptr = (pointer)pPriv;
1569 close_overlay(pSiS, pPriv);
1570 pPriv->videoStatus = 0;
1571 REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1572 pSiS->VideoTimerCallback = NULL;
1573 pPriv->grabbedByV4L = TRUE;
1574 return Success;
1577 static int
1578 SIS6326StopSurface (XF86SurfacePtr surface)
1580 SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
1581 SISPtr pSiS = SISPTR(surface->pScrn);
1583 if(pPriv->grabbedByV4L && pPriv->videoStatus) {
1584 close_overlay(pSiS, pPriv);
1585 pPriv->mustwait = 1;
1586 pPriv->videoStatus = 0;
1588 return Success;
1591 static int
1592 SIS6326FreeSurface (XF86SurfacePtr surface)
1594 SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
1596 if(pPriv->grabbedByV4L) {
1597 SIS6326StopSurface(surface);
1598 SIS6326FreeOverlayMemory(surface->pScrn);
1599 pPriv->grabbedByV4L = FALSE;
1601 return Success;
1604 static int
1605 SIS6326GetSurfaceAttribute (
1606 ScrnInfoPtr pScrn,
1607 Atom attribute,
1608 INT32 *value
1611 SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
1613 return SIS6326GetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
1616 static int
1617 SIS6326SetSurfaceAttribute(
1618 ScrnInfoPtr pScrn,
1619 Atom attribute,
1620 INT32 value
1623 SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);;
1625 return SIS6326SetPortAttribute(pScrn, attribute, value, (pointer)pPriv);
1628 static int
1629 SIS6326DisplaySurface (
1630 XF86SurfacePtr surface,
1631 short src_x, short src_y,
1632 short drw_x, short drw_y,
1633 short src_w, short src_h,
1634 short drw_w, short drw_h,
1635 RegionPtr clipBoxes
1638 ScrnInfoPtr pScrn = surface->pScrn;
1639 SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr);
1641 if(!pPriv->grabbedByV4L)
1642 return Success;
1644 pPriv->drw_x = drw_x;
1645 pPriv->drw_y = drw_y;
1646 pPriv->drw_w = drw_w;
1647 pPriv->drw_h = drw_h;
1648 pPriv->src_x = src_x;
1649 pPriv->src_y = src_y;
1650 pPriv->src_w = src_w;
1651 pPriv->src_h = src_h;
1652 pPriv->id = surface->id;
1653 pPriv->height = surface->height;
1654 pPriv->bufAddr[0] = surface->offsets[0];
1655 pPriv->currentBuf = 0;
1656 pPriv->srcPitch = surface->pitches[0];
1658 SIS6326DisplayVideo(pScrn, pPriv);
1660 if(pPriv->autopaintColorKey) {
1661 #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,0,0)
1662 XAAFillSolidRects(pScrn, pPriv->colorKey, GXcopy, ~0,
1663 REGION_NUM_RECTS(clipBoxes),
1664 REGION_RECTS(clipBoxes));
1665 #else
1666 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
1667 #endif
1670 pPriv->videoStatus = CLIENT_VIDEO_ON;
1672 return Success;
1675 XF86OffscreenImageRec SIS6326OffscreenImages[2] =
1678 &SIS6326Images[0], /* YUV2 */
1679 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1680 SIS6326AllocSurface,
1681 SIS6326FreeSurface,
1682 SIS6326DisplaySurface,
1683 SIS6326StopSurface,
1684 SIS6326GetSurfaceAttribute,
1685 SIS6326SetSurfaceAttribute,
1686 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
1687 NUM_ATTRIBUTES,
1688 &SIS6326Attributes[0] /* Support all attributes */
1691 &SIS6326Images[1], /* UYVY */
1692 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1693 SIS6326AllocSurface,
1694 SIS6326FreeSurface,
1695 SIS6326DisplaySurface,
1696 SIS6326StopSurface,
1697 SIS6326GetSurfaceAttribute,
1698 SIS6326SetSurfaceAttribute,
1699 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
1700 NUM_ATTRIBUTES,
1701 &SIS6326Attributes[0] /* Support all attributes */
1705 static void
1706 SIS6326InitOffscreenImages(ScreenPtr pScrn)
1708 xf86XVRegisterOffscreenImages(pScrn, SIS6326OffscreenImages, 2);