sis6326_video.c revision 1fd23544
1/* 2 * Xv driver for SiS 5597/5598, 6326 and 530/620. 3 * 4 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1) Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2) Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3) The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Author: Thomas Winischhofer <thomas@winischhofer.net> 29 * 30 */ 31 32#ifdef HAVE_CONFIG_H 33#include "config.h" 34#endif 35 36#include "sis.h" 37 38#ifdef SIS_USE_XAA 39#include "xf86fbman.h" 40#endif 41#include "xf86xv.h" 42#include "regionstr.h" 43#include <X11/extensions/Xv.h> 44#include "dixstruct.h" 45#include "fourcc.h" 46 47#define SIS_NEED_inSISREG 48#define SIS_NEED_outSISREG 49#define SIS_NEED_inSISIDXREG 50#define SIS_NEED_outSISIDXREG 51#define SIS_NEED_setSISIDXREGmask 52#include "sis_regs.h" 53 54#define OFF_DELAY 200 /* milliseconds */ 55#define FREE_DELAY 60000 56 57#define OFF_TIMER 0x01 58#define FREE_TIMER 0x02 59#define CLIENT_VIDEO_ON 0x04 60 61#define TIMER_MASK (OFF_TIMER | FREE_TIMER) 62 63#define WATCHDOG_DELAY 500000 /* Watchdog counter for Vertical Restrace waiting */ 64 65static XF86VideoAdaptorPtr SIS6326SetupImageVideo(ScreenPtr); 66static void SIS6326StopVideo(ScrnInfoPtr, pointer, Bool); 67static int SIS6326SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); 68static int SIS6326GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); 69static void SIS6326QueryBestSize(ScrnInfoPtr, Bool, short, short, short, 70 short, unsigned int *,unsigned int *, pointer); 71static int SIS6326PutImage( ScrnInfoPtr, 72 short, short, short, short, short, short, short, short, 73 int, unsigned char*, short, short, Bool, RegionPtr, pointer, 74 DrawablePtr); 75static int SIS6326QueryImageAttributes(ScrnInfoPtr, 76 int, unsigned short *, unsigned short *, int *, int *); 77static void SIS6326VideoTimerCallback(ScrnInfoPtr pScrn, Time now); 78static void SIS6326InitOffscreenImages(ScreenPtr pScrn); 79 80extern unsigned int SISAllocateFBMemory(ScrnInfoPtr pScrn, void **handle, int bytesize); 81extern void SISFreeFBMemory(ScrnInfoPtr pScrn, void **handle); 82 83#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) 84 85static Atom xvBrightness, xvContrast, xvColorKey; 86static Atom xvAutopaintColorKey, xvSetDefaults; 87static Atom xvDisableGfx; 88 89#define IMAGE_MIN_WIDTH 32 /* Minimum and maximum image sizes */ 90#define IMAGE_MIN_HEIGHT 24 91#define IMAGE_MAX_WIDTH 720 /* Are these correct for the chips ? */ 92#define IMAGE_MAX_HEIGHT 576 93#define IMAGE_MAX_WIDTH_5597 384 94#define IMAGE_MAX_HEIGHT_5597 288 95 96#if 0 97static int oldH, oldW; 98#endif 99 100/**************************************************************************** 101 * Raw register access : These routines directly interact with the sis's 102 * control aperature. Must not be called until after 103 * the board's pci memory has been mapped. 104 ****************************************************************************/ 105 106#if 0 107static CARD32 _sisread(SISPtr pSiS, CARD32 reg) 108{ 109 return *(pSiS->IOBase + reg); 110} 111 112static void _siswrite(SISPtr pSiS, CARD32 reg, CARD32 data) 113{ 114 *(pSiS->IOBase + reg) = data; 115} 116#endif 117 118static CARD8 getvideoreg(SISPtr pSiS, CARD8 reg) 119{ 120 CARD8 ret; 121 inSISIDXREG(SISCR, reg, ret); 122 return ret; 123} 124 125static __inline void setvideoreg(SISPtr pSiS, CARD8 reg, CARD8 data) 126{ 127 outSISIDXREG(SISCR, reg, data); 128} 129 130static __inline void setvideoregmask(SISPtr pSiS, CARD8 reg, CARD8 data, CARD8 mask) 131{ 132 setSISIDXREGmask(SISCR, reg, data, mask); 133} 134 135/* VBlank */ 136static CARD8 vblank_active_CRT1(SISPtr pSiS) 137{ 138 return (inSISREG(SISINPSTAT) & 0x08); 139} 140 141/* Scanline - unused */ 142#if 0 143static CARD32 get_scanline_CRT1(SISPtr pSiS) 144{ 145 CARD8 temp; 146 147 temp = getvideoreg(pSiS, 0x20); 148 temp = getvideoreg(pSiS, 0x1b); 149 return((getvideoreg(pSiS, 0x1d) << 8) | getvideoreg(pSiS, 0x1c)); 150} 151#endif 152 153void SIS6326InitVideo(ScreenPtr pScreen) 154{ 155 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 156 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 157 XF86VideoAdaptorPtr newAdaptor = NULL; 158 int num_adaptors; 159 160 newAdaptor = SIS6326SetupImageVideo(pScreen); 161 if(newAdaptor) { 162 SIS6326InitOffscreenImages(pScreen); 163 } 164 165 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 166 167 if(newAdaptor) { 168 if(!num_adaptors) { 169 num_adaptors = 1; 170 adaptors = &newAdaptor; 171 } else { 172 /* need to free this someplace */ 173 newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); 174 if(newAdaptors) { 175 memcpy(newAdaptors, adaptors, num_adaptors * 176 sizeof(XF86VideoAdaptorPtr)); 177 newAdaptors[num_adaptors] = newAdaptor; 178 adaptors = newAdaptors; 179 num_adaptors++; 180 } 181 } 182 } 183 184 if(num_adaptors) 185 xf86XVScreenInit(pScreen, adaptors, num_adaptors); 186 187 if(newAdaptors) 188 xfree(newAdaptors); 189} 190 191/* client libraries expect an encoding */ 192static XF86VideoEncodingRec DummyEncoding = 193{ 194 0, 195 "XV_IMAGE", 196 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 197 {1, 1} 198}; 199 200static XF86VideoEncodingRec DummyEncoding5597 = 201{ 202 0, 203 "XV_IMAGE", 204 IMAGE_MAX_WIDTH_5597, IMAGE_MAX_HEIGHT_5597, 205 {1, 1} 206}; 207 208#define NUM_FORMATS 4 209 210static XF86VideoFormatRec SIS6326Formats[NUM_FORMATS] = 211{ 212 { 8, PseudoColor}, 213 {15, TrueColor}, 214 {16, TrueColor}, 215 {24, TrueColor} 216}; 217 218#define NUM_ATTRIBUTES 6 219 220static XF86AttributeRec SIS6326Attributes[NUM_ATTRIBUTES] = 221{ 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"} 228}; 229 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 238 239static XF86ImageRec SIS6326Images[NUM_IMAGES] = 240{ 241 XVIMAGE_YUY2, /* If order is changed, SIS6326OffscreenImages must be adapted */ 242 XVIMAGE_UYVY, 243 XVIMAGE_YV12, 244 XVIMAGE_I420, 245 { 246 0x35315652, 247 XvRGB, 248 LSBFirst, 249 {'R','V','1','5', 250 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 251 16, 252 XvPacked, 253 1, 254 15, 0x7C00, 0x03E0, 0x001F, 255 0, 0, 0, 256 0, 0, 0, 257 0, 0, 0, 258 {'R', 'V', 'B',0, 259 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}, 260 XvTopToBottom 261 }, 262 { 263 0x36315652, 264 XvRGB, 265 LSBFirst, 266 {'R','V','1','6', 267 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 268 16, 269 XvPacked, 270 1, 271 16, 0xF800, 0x07E0, 0x001F, 272 0, 0, 0, 273 0, 0, 0, 274 0, 0, 0, 275 {'R', 'V', 'B',0, 276 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}, 277 XvTopToBottom 278 } 279}; 280 281static XF86ImageRec SIS6326ImagesNoYV12[NUM_IMAGES_NOYV12] = 282{ 283 XVIMAGE_YUY2, /* If order is changed, SIS6326OffscreenImages must be adapted */ 284 XVIMAGE_UYVY, 285 { 286 0x35315652, 287 XvRGB, 288 LSBFirst, 289 {'R','V','1','5', 290 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 291 16, 292 XvPacked, 293 1, 294 15, 0x7C00, 0x03E0, 0x001F, 295 0, 0, 0, 296 0, 0, 0, 297 0, 0, 0, 298 {'R', 'V', 'B',0, 299 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}, 300 XvTopToBottom 301 }, 302 { 303 0x36315652, 304 XvRGB, 305 LSBFirst, 306 {'R','V','1','6', 307 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 308 16, 309 XvPacked, 310 1, 311 16, 0xF800, 0x07E0, 0x001F, 312 0, 0, 0, 313 0, 0, 0, 314 0, 0, 0, 315 {'R', 'V', 'B',0, 316 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}, 317 XvTopToBottom 318 } 319}; 320 321typedef struct { 322 int pixelFormat; 323 324 CARD16 pitch; 325 326 CARD8 keyOP; 327 328 CARD8 HUSF; 329 CARD8 VUSF; 330 CARD8 HIntBit; 331 CARD8 wHPre; 332 CARD8 PitchMult; 333 334 CARD16 srcW; 335 CARD16 srcH; 336 337 BoxRec dstBox; 338 339 CARD32 PSY; 340 CARD32 PSV; 341 CARD32 PSU; 342 CARD8 YUVEnd; 343 344 CARD8 lineBufSize; 345 346 CARD8 (*VBlankActiveFunc)(SISPtr); 347/* CARD32 (*GetScanLineFunc)(SISPtr pSiS); */ 348 349} SISOverlayRec, *SISOverlayPtr; 350 351typedef struct { 352 void * handle; 353 CARD32 bufAddr[2]; 354 355 unsigned char currentBuf; 356 357 short drw_x, drw_y, drw_w, drw_h; 358 short src_x, src_y, src_w, src_h; 359 int id; 360 short srcPitch, height, width; 361 CARD32 totalSize; 362 363 char brightness; 364 unsigned char contrast; 365 366 RegionRec clip; 367 CARD32 colorKey; 368 Bool autopaintColorKey; 369 370 Bool disablegfx; 371 372 CARD32 videoStatus; 373 Time offTime; 374 Time freeTime; 375 376 short oldx1, oldx2, oldy1, oldy2; 377 int mustwait; 378 379 Bool grabbedByV4L; /* V4L stuff */ 380 int pitch; 381 int offset; 382 383} SISPortPrivRec, *SISPortPrivPtr; 384 385#define GET_PORT_PRIVATE(pScrn) \ 386 (SISPortPrivPtr)((SISPTR(pScrn))->adaptor->pPortPrivates[0].ptr) 387 388static void 389SIS6326SetPortDefaults(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv) 390{ 391 SISPtr pSiS = SISPTR(pScrn); 392 393 pPriv->colorKey = 0x000101fe; 394 pPriv->videoStatus = 0; 395 pPriv->brightness = pSiS->XvDefBri; /* 0; - see sis_opt.c */ 396 pPriv->contrast = pSiS->XvDefCon; /* 4; */ 397 pPriv->autopaintColorKey = TRUE; 398 pPriv->disablegfx = pSiS->XvDefDisableGfx; 399} 400 401static void 402SIS6326ResetVideo(ScrnInfoPtr pScrn) 403{ 404 SISPtr pSiS = SISPTR(pScrn); 405 406 /* Unlock registers */ 407#ifdef UNLOCK_ALWAYS 408 sisSaveUnlockExtRegisterLock(pSiS, NULL, NULL); 409#endif 410 if(getvideoreg(pSiS, Index_VI6326_Passwd) != 0xa1) { 411 setvideoreg(pSiS, Index_VI6326_Passwd, 0x86); 412 if(getvideoreg(pSiS, Index_VI6326_Passwd) != 0xa1) 413 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 414 "Xv: Video password could not unlock video registers\n"); 415 } 416 417 /* Initialize the overlay ----------------------------------- */ 418 419 switch(pSiS->Chipset) { 420 case PCI_CHIP_SIS5597: 421 /* Disable overlay (D[1]) & capture (D[0]) */ 422 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x03); 423 424 /* What do these do? (Datasheet names these bits "reserved") */ 425 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18); 426 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c); 427 428 /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */ 429 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x40, 0xD0); 430 /* No interrupt, no filter, disable dithering */ 431 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x7A); 432 /* Disable Brooktree support (D[6]) and system memory framebuffer (D[7]) */ 433 setvideoregmask(pSiS, Index_VI6326_Control_Misc3, 0x00, 0xC0); 434 /* Disable video decimation (has a really strange effect if enabled) */ 435 setvideoregmask(pSiS, Index_VI6326_Control_Misc6, 0x00, 0x80); 436 break; 437 case PCI_CHIP_SIS6326: 438 /* Disable overlay (D[1]) & capture (D[0]) */ 439 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x03); 440 441 /* What do these do? (Datasheet names these bits "reserved") */ 442 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18); 443 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c); 444 445 /* Select YUV format (D[6]) and "gfx + video" mode (D[4]), odd polarity? (D[7]) */ 446 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x40, 0xD0); 447 /* No interrupt, no filter, disable dithering */ 448 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x7A); 449 /* Disable VMI (D[4:3]), Brooktree support (D[6]) and system memory framebuffer (D[7]) */ 450 setvideoregmask(pSiS, Index_VI6326_Control_Misc3, 0x00, 0xF8); 451 /* Disable video decimation */ 452 setvideoregmask(pSiS, Index_VI6326_Control_Misc6, 0x00, 0x80); 453 break; 454 case PCI_CHIP_SIS530: 455 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40); 456 /* Disable overlay (D[1]) */ 457 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x02); 458 459 /* What do D[3:2] do? (Datasheet names these bits "reserved") */ 460 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18); 461 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c); 462 463 /* Select YUV format (D[6]) and "gfx + video" mode (D[4]) */ 464 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x40, 0x50); 465 break; 466 default: 467 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 468 "Internal error: SiS6326ResetVideo() called with invalid chipset (%x)\n", 469 pSiS->Chipset); 470 return; 471 } 472 473 /* Clear format selection */ 474 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x04); 475 if(pSiS->oldChipset >= OC_SIS5597) { 476 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x00, 0x05); 477 } 478 479 /* Select RGB Chromakey format (D[2]=0), CCIR 601 UV data format (D[1]=0) */ 480 /* D[1]: 1 = 2's complement, 0 = CCIR 601 format */ 481 setvideoregmask(pSiS, Index_VI6326_Control_Misc3, 0x00, 0x06); 482 483 /* Reset contrast control */ 484 setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, 0x04, 0x1F); 485 486 /* Set threshold */ 487 if(pSiS->oldChipset < OC_SIS6326) { 488 CARD8 temp; 489 inSISIDXREG(SISSR, 0x33, temp); /* Synchronous DRAM Timing? */ 490 if(temp & 0x01) temp = 0x50; 491 else temp = 0; 492 setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low, temp); 493 setvideoreg(pSiS, Index_VI6326_Play_Threshold_High, temp); 494 } else { 495 CARD8 temp; 496 setvideoreg(pSiS, Index_VI6326_Play_Threshold_Low, 0x00); 497 setvideoreg(pSiS, Index_VI6326_Play_Threshold_High, 0x00); 498 inSISIDXREG(SISSR, 0x33, temp); /* Are we using SGRAM Timing? */ 499 if(temp & 0x01) temp = 0x10; 500 else temp = 0; 501 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, temp, 0x10); 502 } 503 504 /* set default properties for overlay ------------------------------- */ 505 506 setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, 0x04, 0x07); 507 setvideoreg(pSiS, Index_VI6326_Brightness, 0x20); 508 509 if(pSiS->oldChipset < OC_SIS6205A || pSiS->oldChipset > OC_SIS82204) { 510 setvideoregmask(pSiS, Index_VI6326_AlphaGraph, 0x00, 0xF8); 511 setvideoregmask(pSiS, Index_VI6326_AlphaVideo, 0xF8, 0xF8); 512 } else { 513 setvideoregmask(pSiS, Index_VI6326_AlphaGraph, 0x00, 0xE1); 514 setvideoregmask(pSiS, Index_VI6326_AlphaVideo, 0xE1, 0xE1); 515 } 516 517} 518 519static XF86VideoAdaptorPtr 520SIS6326SetupImageVideo(ScreenPtr pScreen) 521{ 522 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 523 SISPtr pSiS = SISPTR(pScrn); 524 XF86VideoAdaptorPtr adapt; 525 SISPortPrivPtr pPriv; 526 527#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0) 528 XAAInfoRecPtr pXAA = pSiS->AccelInfoPtr; 529 530 if(!pXAA || !pXAA->FillSolidRects) 531 return NULL; 532#endif 533 534 if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + 535 sizeof(SISPortPrivRec) + 536 sizeof(DevUnion)))) 537 return NULL; 538 539 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 540 adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 541 adapt->name = "SIS 5597/5598/6326/530/620 Video Overlay"; 542 adapt->nEncodings = 1; 543 if(pSiS->oldChipset < OC_SIS6326) { 544 adapt->pEncodings = &DummyEncoding5597; 545 } else { 546 adapt->pEncodings = &DummyEncoding; 547 } 548 adapt->nFormats = NUM_FORMATS; 549 adapt->pFormats = SIS6326Formats; 550 adapt->nPorts = 1; 551 adapt->pPortPrivates = (DevUnion*)(&adapt[1]); 552 553 pPriv = (SISPortPrivPtr)(&adapt->pPortPrivates[1]); 554 555 adapt->pPortPrivates[0].ptr = (pointer)(pPriv); 556 adapt->pAttributes = SIS6326Attributes; 557 adapt->nAttributes = NUM_ATTRIBUTES; 558 if(pSiS->NoYV12 == 1) { 559 adapt->nImages = NUM_IMAGES_NOYV12; 560 adapt->pImages = SIS6326ImagesNoYV12; 561 } else { 562 adapt->nImages = NUM_IMAGES; 563 adapt->pImages = SIS6326Images; 564 } 565 adapt->PutVideo = NULL; 566 adapt->PutStill = NULL; 567 adapt->GetVideo = NULL; 568 adapt->GetStill = NULL; 569 adapt->StopVideo = SIS6326StopVideo; 570 adapt->SetPortAttribute = SIS6326SetPortAttribute; 571 adapt->GetPortAttribute = SIS6326GetPortAttribute; 572 adapt->QueryBestSize = SIS6326QueryBestSize; 573 adapt->PutImage = SIS6326PutImage; 574 adapt->QueryImageAttributes = SIS6326QueryImageAttributes; 575 576 pPriv->videoStatus = 0; 577 pPriv->currentBuf = 0; 578 pPriv->handle = NULL; 579 pPriv->grabbedByV4L= FALSE; 580 581 SIS6326SetPortDefaults(pScrn, pPriv); 582 583 /* gotta uninit this someplace */ 584#if defined(REGION_NULL) 585 REGION_NULL(pScreen, &pPriv->clip); 586#else 587 REGION_INIT(pScreen, &pPriv->clip, NullBox, 0); 588#endif 589 590 pSiS->adaptor = adapt; 591 592 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 593 xvContrast = MAKE_ATOM("XV_CONTRAST"); 594 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 595 xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); 596 xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS"); 597 xvDisableGfx = MAKE_ATOM("XV_DISABLE_GRAPHICS"); 598 599 SIS6326ResetVideo(pScrn); 600 pSiS->ResetXv = SIS6326ResetVideo; 601 602 return adapt; 603} 604 605#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0) 606static Bool 607RegionsEqual(RegionPtr A, RegionPtr B) 608{ 609 int *dataA, *dataB; 610 int num; 611 612 num = REGION_NUM_RECTS(A); 613 if(num != REGION_NUM_RECTS(B)) 614 return FALSE; 615 616 if((A->extents.x1 != B->extents.x1) || 617 (A->extents.x2 != B->extents.x2) || 618 (A->extents.y1 != B->extents.y1) || 619 (A->extents.y2 != B->extents.y2)) 620 return FALSE; 621 622 dataA = (int*)REGION_RECTS(A); 623 dataB = (int*)REGION_RECTS(B); 624 625 while(num--) { 626 if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])) 627 return FALSE; 628 dataA += 2; 629 dataB += 2; 630 } 631 632 return TRUE; 633} 634#endif 635 636static int 637SIS6326SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, 638 INT32 value, pointer data) 639{ 640 SISPortPrivPtr pPriv = (SISPortPrivPtr)data; 641 642 if(attribute == xvBrightness) { 643 if((value < -128) || (value > 127)) 644 return BadValue; 645 pPriv->brightness = value; 646 } else if(attribute == xvContrast) { 647 if((value < 0) || (value > 7)) 648 return BadValue; 649 pPriv->contrast = value; 650 } else if(attribute == xvColorKey) { 651 pPriv->colorKey = value; 652 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 653 } else if (attribute == xvAutopaintColorKey) { 654 if((value < 0) || (value > 1)) 655 return BadValue; 656 pPriv->autopaintColorKey = value; 657 } else if(attribute == xvDisableGfx) { 658 if((value < 0) || (value > 1)) 659 return BadValue; 660 pPriv->disablegfx = value; 661 } else if (attribute == xvSetDefaults) { 662 SIS6326SetPortDefaults(pScrn, pPriv); 663 } else return BadMatch; 664 return Success; 665} 666 667static int 668SIS6326GetPortAttribute( 669 ScrnInfoPtr pScrn, 670 Atom attribute, 671 INT32 *value, 672 pointer data 673){ 674 SISPortPrivPtr pPriv = (SISPortPrivPtr)data; 675 676 if(attribute == xvBrightness) { 677 *value = pPriv->brightness; 678 } else if(attribute == xvContrast) { 679 *value = pPriv->contrast; 680 } else if(attribute == xvColorKey) { 681 *value = pPriv->colorKey; 682 } else if (attribute == xvAutopaintColorKey) { 683 *value = (pPriv->autopaintColorKey) ? 1 : 0; 684 } else if (attribute == xvDisableGfx) { 685 *value = (pPriv->disablegfx) ? 1 : 0; 686 } else return BadMatch; 687 return Success; 688} 689 690static void 691SIS6326QueryBestSize( 692 ScrnInfoPtr pScrn, 693 Bool motion, 694 short vid_w, short vid_h, 695 short drw_w, short drw_h, 696 unsigned int *p_w, unsigned int *p_h, 697 pointer data 698){ 699 *p_w = drw_w; 700 *p_h = drw_h; 701 702 /* TODO: report the HW limitation */ 703} 704 705static void /* V 530/6326 */ 706calc_scale_factor(SISPtr pSiS, SISOverlayPtr pOverlay, ScrnInfoPtr pScrn, 707 SISPortPrivPtr pPriv) 708{ 709 CARD32 temp=0; 710 711 int dstW = pOverlay->dstBox.x2 - pOverlay->dstBox.x1; 712 int dstH = pOverlay->dstBox.y2 - pOverlay->dstBox.y1; 713 int srcW = pOverlay->srcW; 714 int srcH = pOverlay->srcH; 715 716 /* For double scan modes, we need to double the height */ 717 if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) { 718 dstH <<= 1; 719 } 720 /* For interlace modes, we need to half the height */ 721 if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) { 722 dstH >>= 1; 723 } 724 725 /* Horizontal */ 726 if(dstW < IMAGE_MIN_WIDTH) dstW = IMAGE_MIN_WIDTH; 727 if(dstW == srcW) { 728 pOverlay->HUSF = 0x00; 729 pOverlay->HIntBit = 0x01; 730 } else if(dstW > srcW) { 731 pOverlay->HIntBit = 0x00; 732 temp = srcW * 64 / (dstW + 1); 733 if(temp > 63) temp = 63; 734 pOverlay->HUSF = temp; 735 } else { 736 /* 6326 can't scale below factor .440 - to check with 530/620 */ 737 if(((dstW * 1000) / srcW) < 440) dstW = ((srcW * 440) / 1000) + 1; 738 temp = srcW / dstW; 739 if(temp > 15) temp = 15; 740 pOverlay->HIntBit = temp; 741 temp = srcW * 64 / dstW; 742 pOverlay->HUSF = temp - (pOverlay->HIntBit * 64); 743 } 744 745 /* Vertical */ 746 if(dstH < IMAGE_MIN_HEIGHT) dstH = IMAGE_MIN_HEIGHT; 747 if(dstH == srcH) { 748 pOverlay->VUSF = 0x00; 749 pOverlay->PitchMult = 1; 750 } else if(dstH > srcH) { 751 temp = srcH * 64 / (dstH + 1); 752 if (temp > 63) temp = 63; 753 pOverlay->VUSF = temp; 754 pOverlay->PitchMult = 1; 755 } else { 756 /* 6326 can't scale below factor .440 - to check with 530/620 */ 757 if(((dstH * 1000) / srcH) < 440) dstH = ((srcH * 440) / 1000) + 1; 758 temp = srcH / dstH; 759 if(srcH % dstH) { 760 temp++; 761 pOverlay->VUSF = (srcH * 64) / (temp * dstH); 762 } else { 763 pOverlay->VUSF = 0x00; 764 } 765 pOverlay->PitchMult = temp; 766 } 767} 768 769static void 770calc_line_buf_size(SISOverlayPtr pOverlay) 771{ 772 CARD32 I; 773 CARD32 line = pOverlay->srcW; 774 775 if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) || 776 (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; 782 } 783 I += 8; 784 I >>= 3; 785 pOverlay->lineBufSize = (CARD8)I; 786} 787 788static void 789merge_line_buf(SISPtr pSiS, SISPortPrivPtr pPriv, Bool enable) 790{ 791 if(enable) { 792 setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x10, 0x10); 793 } else { 794 setvideoregmask(pSiS, Index_VI6326_Control_Misc5, 0x00, 0x10); 795 } 796} 797 798static void 799set_format(SISPtr pSiS, SISOverlayPtr pOverlay) 800{ 801 CARD8 fmt, misc0, misc1, misc4; 802 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; 836 } 837 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); 844 } 845 } else { 846 if(pSiS->oldChipset >= OC_SIS5597) { 847 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, misc4, 0x05); 848 } 849 setvideoregmask(pSiS, Index_VI6326_Control_Misc1, 0x00, 0x04); 850 } 851} 852 853static void 854set_colorkey(SISPtr pSiS, CARD32 colorkey) 855{ 856 CARD8 r, g, b, s; 857 858 b = (CARD8)(colorkey & 0xFF); 859 g = (CARD8)((colorkey >> 8) & 0xFF); 860 r = (CARD8)((colorkey >> 16) & 0xFF); 861 862 if(pSiS->CurrentLayout.bitsPerPixel >= 24) { 863 s = b; 864 b = r; 865 r = s; 866 } 867 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); 871 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); 875} 876 877static __inline void 878set_brightness(SISPtr pSiS, CARD8 brightness) 879{ 880 setvideoreg(pSiS, Index_VI6326_Brightness, brightness); 881} 882 883static __inline void 884set_contrast(SISPtr pSiS, CARD8 contrast) 885{ 886 setvideoregmask(pSiS, Index_VI6326_Contrast_Enh_Ctrl, contrast, 0x07); 887} 888 889static void 890set_contrast_data(SISPtr pSiS, int value) 891{ 892 unsigned long temp; 893 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; 903 } 904 temp <<= 10; 905 temp /= value; 906 setvideoreg(pSiS, Index_VI6326_Contrast_Factor, temp); 907} 908 909static __inline void 910set_disablegfx(SISPtr pSiS, Bool mybool) 911{ 912 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, mybool ? 0x10 : 0x00, 0x10); 913} 914 915static void 916set_overlay(SISPtr pSiS, SISOverlayPtr pOverlay, SISPortPrivPtr pPriv, int index) 917{ 918 ScrnInfoPtr pScrn = pSiS->pScrn; 919 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; 926 927 top = pOverlay->dstBox.y1; 928 bottom = pOverlay->dstBox.y2; 929 if(bottom > screenY) { 930 bottom = screenY; 931 } 932 933 left = pOverlay->dstBox.x1; 934 right = pOverlay->dstBox.x2; 935 if(right > screenX) { 936 right = screenX; 937 } 938 939 /* TW: DoubleScan modes require Y coordinates * 2 */ 940 if(pSiS->CurrentLayout.mode->Flags & V_DBLSCAN) { 941 top <<= 1; 942 bottom <<= 1; 943 } 944 /* TW: Interlace modes require Y coordinates / 2 */ 945 if(pSiS->CurrentLayout.mode->Flags & V_INTERLACE) { 946 top >>= 1; 947 bottom >>= 1; 948 } 949 950 h_over = (((left>>8) & 0x07) | ((right>>4) & 0x70)); 951 v_over = (((top>>8) & 0x07) | ((bottom>>4) & 0x70)); 952 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; 958 } 959 960 /* set color key */ 961 set_colorkey(pSiS, pPriv->colorKey); 962 963 /* set color key mode */ 964 setvideoregmask(pSiS, Index_VI6326_Key_Overlay_OP, pOverlay->keyOP, 0x0f); 965 966 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x0c); 967 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x18); 968 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); 978 } 979 980 /* set line buffer size */ 981 setvideoreg(pSiS, Index_VI6326_Line_Buffer_Size, pOverlay->lineBufSize); 982 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); 987 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"); 994 } 995 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); 1000 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); 1004 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); 1018 } 1019 1020 /* Set U/V start addresses if using plane formats */ 1021 if( (pOverlay->pixelFormat == PIXEL_FMT_YV12) || 1022 (pOverlay->pixelFormat == PIXEL_FMT_I420) ) { 1023 1024 CARD32 PSU = pOverlay->PSU; 1025 CARD32 PSV = pOverlay->PSV; 1026 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)); 1030 1031 setvideoreg(pSiS, Index_VI6326_V_Buf_Start_Low, (CARD8)PSV); 1032 setvideoreg(pSiS, Index_VI6326_V_Buf_Start_Middle,(CARD8)(PSV >> 8)); 1033 1034 setvideoreg(pSiS, Index_VI6326_UV_Buf_Start_High, 1035 (CARD8)(((PSU >> 16) & 0x0F) | ((PSV >> 12) & 0xF0)) ); 1036 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)) ); 1041 } 1042 } 1043 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); 1050 } 1051 1052 /* enable/disable graphics display around overlay */ 1053 set_disablegfx(pSiS, pPriv->disablegfx); 1054 1055 /* set format */ 1056 set_format(pSiS, pOverlay); 1057} 1058 1059/* Overlay MUST NOT be switched off while beam is over it */ 1060static void 1061close_overlay(SISPtr pSiS, SISPortPrivPtr pPriv) 1062{ 1063 CARD32 watchdog; 1064 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); 1070 } 1071 /* disable overlay */ 1072 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x00, 0x02); 1073} 1074 1075static void 1076SIS6326DisplayVideo(ScrnInfoPtr pScrn, SISPortPrivPtr pPriv) 1077{ 1078 SISPtr pSiS = SISPTR(pScrn); 1079 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; 1088 1089 memset(&overlay, 0, sizeof(overlay)); 1090 overlay.pixelFormat = pPriv->id; 1091 overlay.pitch = srcPitch; 1092 overlay.keyOP = VI6326_ROP_DestKey; /* DestKey mode */ 1093 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; 1098 1099 if((overlay.dstBox.x1 > overlay.dstBox.x2) || 1100 (overlay.dstBox.y1 > overlay.dstBox.y2)) 1101 return; 1102 1103 if((overlay.dstBox.x2 < 0) || (overlay.dstBox.y2 < 0)) 1104 return; 1105 1106 if(overlay.dstBox.x1 < 0) { 1107 srcOffsetX = pPriv->src_w * (-overlay.dstBox.x1) / pPriv->drw_w; 1108 overlay.dstBox.x1 = 0; 1109 } 1110 if(overlay.dstBox.y1 < 0) { 1111 srcOffsetY = pPriv->src_h * (-overlay.dstBox.y1) / pPriv->drw_h; 1112 overlay.dstBox.y1 = 0; 1113 } 1114 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; 1148 } 1149 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) 1152 */ 1153 overlay.YUVEnd = (pPriv->bufAddr[pPriv->currentBuf] + pPriv->totalSize) >> 14; 1154 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); 1158 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; 1166 } 1167 1168 /* calculate line buffer length */ 1169 calc_line_buf_size(&overlay); 1170 1171 overlay.VBlankActiveFunc = vblank_active_CRT1; 1172/* overlay.GetScanLineFunc = get_scanline_CRT1; */ 1173 1174 /* calculate scale factor */ 1175 calc_scale_factor(pSiS, &overlay, pScrn, pPriv); 1176 1177 /* set (not only determine) if line buffer is to be merged */ 1178 if(pSiS->oldChipset > OC_SIS5597) { 1179 int temp = 384; 1180 if(pSiS->oldChipset <= OC_SIS6326) temp = 352; 1181 merge_line_buf(pSiS, pPriv, (overlay.srcW > temp)); 1182 } 1183 1184 /* set overlay */ 1185 set_overlay(pSiS, &overlay, pPriv, index); 1186 1187 /* enable overlay */ 1188 if(pSiS->oldChipset > OC_SIS6326) { 1189 setvideoregmask(pSiS, Index_VI6326_Control_Misc4, 0x40, 0x40); 1190 } 1191 setvideoregmask(pSiS, Index_VI6326_Control_Misc0, 0x02, 0x02); 1192 1193 pPriv->mustwait = 0; 1194} 1195 1196static void 1197SIS6326StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown) 1198{ 1199 SISPortPrivPtr pPriv = (SISPortPrivPtr)data; 1200 SISPtr pSiS = SISPTR(pScrn); 1201 1202 if(pPriv->grabbedByV4L) return; 1203 1204 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 1205 1206 if(shutdown) { 1207 if(pPriv->videoStatus & CLIENT_VIDEO_ON) { 1208 close_overlay(pSiS, pPriv); 1209 pPriv->mustwait = 1; 1210 } 1211 SISFreeFBMemory(pScrn, &pPriv->handle); 1212 pPriv->videoStatus = 0; 1213 pSiS->VideoTimerCallback = NULL; 1214 } else { 1215 if(pPriv->videoStatus & CLIENT_VIDEO_ON) { 1216 pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON; 1217 pPriv->offTime = currentTime.milliseconds + OFF_DELAY; 1218 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback; 1219 } 1220 } 1221} 1222 1223static int 1224SIS6326PutImage( 1225 ScrnInfoPtr pScrn, 1226 short src_x, short src_y, 1227 short drw_x, short drw_y, 1228 short src_w, short src_h, 1229 short drw_w, short drw_h, 1230 int id, unsigned char* buf, 1231 short width, short height, 1232 Bool sync, 1233 RegionPtr clipBoxes, pointer data, 1234 DrawablePtr pDraw 1235){ 1236 SISPtr pSiS = SISPTR(pScrn); 1237 SISPortPrivPtr pPriv = (SISPortPrivPtr)data; 1238 int totalSize=0; 1239 CARD32 *src, *dest; 1240 unsigned long i; 1241 1242 if(pPriv->grabbedByV4L) return Success; 1243 1244 pPriv->drw_x = drw_x; 1245 pPriv->drw_y = drw_y; 1246 pPriv->drw_w = drw_w; 1247 pPriv->drw_h = drw_h; 1248 pPriv->src_x = src_x; 1249 pPriv->src_y = src_y; 1250 pPriv->src_w = src_w; 1251 pPriv->src_h = src_h; 1252 pPriv->id = id; 1253 pPriv->height = height; 1254 pPriv->width = width; 1255 1256 /* Pixel formats: 1257 1. YU12: 3 planes: H V 1258 Y sample period 1 1 (8 bit per pixel) 1259 V sample period 2 2 (8 bit per pixel, subsampled) 1260 U sample period 2 2 (8 bit per pixel, subsampled) 1261 1262 Y plane is fully sampled (width*height), U and V planes 1263 are sampled in 2x2 blocks, hence a group of 4 pixels requires 1264 4 + 1 + 1 = 6 bytes. The data is planar, ie in single planes 1265 for Y, U and V. 1266 2. UYVY: 3 planes: H V 1267 Y sample period 1 1 (8 bit per pixel) 1268 V sample period 2 1 (8 bit per pixel, subsampled) 1269 U sample period 2 1 (8 bit per pixel, subsampled) 1270 Y plane is fully sampled (width*height), U and V planes 1271 are sampled in 2x1 blocks, hence a group of 4 pixels requires 1272 4 + 2 + 2 = 8 bytes. The data is bit packed, there are no separate 1273 Y, U or V planes. 1274 Bit order: U0 Y0 V0 Y1 U2 Y2 V2 Y3 ... 1275 3. I420: Like YU12, but planes U and V are in reverse order. 1276 4. YUY2: Like UYVY, but order is 1277 Y0 U0 Y1 V0 Y2 U2 Y3 V2 ... 1278 */ 1279 1280 switch(id){ 1281 case PIXEL_FMT_YV12: 1282 case PIXEL_FMT_I420: 1283 pPriv->srcPitch = (width + 7) & ~7; 1284 /* Size = width * height * 3 / 2 */ 1285 totalSize = (pPriv->srcPitch * height * 3) >> 1; 1286 break; 1287 case PIXEL_FMT_YUY2: 1288 case PIXEL_FMT_UYVY: 1289 case PIXEL_FMT_RGB5: 1290 case PIXEL_FMT_RGB6: 1291 default: 1292 pPriv->srcPitch = ((width << 1) + 3) & ~3; 1293 /* Size = width * 2 * height */ 1294 totalSize = pPriv->srcPitch * height; 1295 } 1296 1297 /* make it a multiple of 16 to simplify to copy loop */ 1298 totalSize += 15; 1299 totalSize &= ~15; /* in bytes */ 1300 1301 pPriv->totalSize = totalSize; 1302 1303 /* allocate memory (we do doublebuffering) - size is in bytes */ 1304 if(!(pPriv->bufAddr[0] = SISAllocateFBMemory(pScrn, &pPriv->handle, totalSize << 1))) 1305 return BadAlloc; 1306 1307 pPriv->bufAddr[1] = pPriv->bufAddr[0] + totalSize; 1308 1309 /* copy data */ 1310 if((pSiS->XvUseMemcpy) || (totalSize < 16)) { 1311 SiSMemCopyToVideoRam(pSiS, pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf], buf, totalSize); 1312 } else { 1313 dest = (CARD32 *)(pSiS->FbBase + pPriv->bufAddr[pPriv->currentBuf]); 1314 src = (CARD32 *)buf; 1315 for(i = 0; i < (totalSize/16); i++) { 1316 *dest++ = *src++; 1317 *dest++ = *src++; 1318 *dest++ = *src++; 1319 *dest++ = *src++; 1320 } 1321 } 1322 1323 SIS6326DisplayVideo(pScrn, pPriv); 1324 1325 /* update cliplist */ 1326 if( pPriv->autopaintColorKey && 1327 (pPriv->grabbedByV4L || 1328#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,3,0) 1329 !RegionsEqual(&pPriv->clip, clipBoxes)) ) { 1330#else 1331 !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) ) { 1332#endif 1333 /* We always paint colorkey for V4L */ 1334 if(!pPriv->grabbedByV4L) 1335 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 1336 /* draw these */ 1337#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0) 1338 (*pSiS->AccelInfoPtr->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0, 1339 REGION_NUM_RECTS(clipBoxes), 1340 REGION_RECTS(clipBoxes)); 1341#else 1342 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); 1343#endif 1344 } 1345 1346 pPriv->currentBuf ^= 1; 1347 1348 pPriv->videoStatus = CLIENT_VIDEO_ON; 1349 1350 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback; 1351 1352 return Success; 1353} 1354 1355static int 1356SIS6326QueryImageAttributes( 1357 ScrnInfoPtr pScrn, 1358 int id, 1359 unsigned short *w, unsigned short *h, 1360 int *pitches, int *offsets 1361){ 1362 SISPtr pSiS = SISPTR(pScrn); 1363 int pitchY, pitchUV; 1364 int size, sizeY, sizeUV; 1365 1366 if(*w < IMAGE_MIN_WIDTH) *w = IMAGE_MIN_WIDTH; 1367 if(*h < IMAGE_MIN_HEIGHT) *h = IMAGE_MIN_HEIGHT; 1368 1369 if(pSiS->oldChipset < OC_SIS6326) { 1370 if(*w > IMAGE_MAX_WIDTH_5597) *w = IMAGE_MAX_WIDTH_5597; 1371 if(*h > IMAGE_MAX_HEIGHT_5597) *h = IMAGE_MAX_HEIGHT_5597; 1372 } else { 1373 if(*w > IMAGE_MAX_WIDTH) *w = IMAGE_MAX_WIDTH; 1374 if(*h > IMAGE_MAX_HEIGHT) *h = IMAGE_MAX_HEIGHT; 1375 } 1376 1377 switch(id) { 1378 case PIXEL_FMT_YV12: 1379 case PIXEL_FMT_I420: 1380 *w = (*w + 7) & ~7; 1381 *h = (*h + 1) & ~1; 1382 pitchY = *w; 1383 pitchUV = *w >> 1; 1384 if(pitches) { 1385 pitches[0] = pitchY; 1386 pitches[1] = pitches[2] = pitchUV; 1387 } 1388 sizeY = pitchY * (*h); 1389 sizeUV = pitchUV * ((*h) >> 1); 1390 if(offsets) { 1391 offsets[0] = 0; 1392 offsets[1] = sizeY; 1393 offsets[2] = sizeY + sizeUV; 1394 } 1395 size = sizeY + (sizeUV << 1); 1396 break; 1397 case PIXEL_FMT_YUY2: 1398 case PIXEL_FMT_UYVY: 1399 case PIXEL_FMT_RGB5: 1400 case PIXEL_FMT_RGB6: 1401 default: 1402 *w = (*w + 1) & ~1; 1403 pitchY = *w << 1; 1404 if(pitches) pitches[0] = pitchY; 1405 if(offsets) offsets[0] = 0; 1406 size = pitchY * (*h); 1407 break; 1408 } 1409 1410 return size; 1411} 1412 1413static void 1414SIS6326VideoTimerCallback(ScrnInfoPtr pScrn, Time now) 1415{ 1416 SISPtr pSiS = SISPTR(pScrn); 1417 SISPortPrivPtr pPriv = NULL; 1418 unsigned char sridx, cridx; 1419 1420 pSiS->VideoTimerCallback = NULL; 1421 1422 if(!pScrn->vtSema) return; 1423 1424 if(pSiS->adaptor) { 1425 pPriv = GET_PORT_PRIVATE(pScrn); 1426 if(!pPriv->videoStatus) pPriv = NULL; 1427 } 1428 1429 if(pPriv) { 1430 if(pPriv->videoStatus & TIMER_MASK) { 1431 if(pPriv->videoStatus & OFF_TIMER) { 1432 if(pPriv->offTime < now) { 1433 /* Turn off the overlay */ 1434 sridx = inSISREG(SISSR); cridx = inSISREG(SISCR); 1435 close_overlay(pSiS, pPriv); 1436 outSISREG(SISSR, sridx); outSISREG(SISCR, cridx); 1437 pPriv->mustwait = 1; 1438 pPriv->videoStatus = FREE_TIMER; 1439 pPriv->freeTime = now + FREE_DELAY; 1440 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback; 1441 } 1442 } else if(pPriv->videoStatus & FREE_TIMER) { 1443 if(pPriv->freeTime < now) { 1444 SISFreeFBMemory(pScrn, &pPriv->handle); 1445 pPriv->mustwait = 1; 1446 pPriv->videoStatus = 0; 1447 } 1448 } else 1449 pSiS->VideoTimerCallback = SIS6326VideoTimerCallback; 1450 } 1451 } 1452} 1453 1454/* Offscreen surface stuff for v4l */ 1455 1456static int 1457SIS6326AllocSurface ( 1458 ScrnInfoPtr pScrn, 1459 int id, 1460 unsigned short w, 1461 unsigned short h, 1462 XF86SurfacePtr surface 1463) 1464{ 1465 SISPtr pSiS = SISPTR(pScrn); 1466 SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); 1467 int size; 1468 1469 if((w < IMAGE_MIN_WIDTH) || (h < IMAGE_MIN_HEIGHT)) 1470 return BadValue; 1471 1472 if(pSiS->oldChipset < OC_SIS6326) { 1473 if((w > IMAGE_MAX_WIDTH_5597) || (h > IMAGE_MAX_HEIGHT_5597)) 1474 return BadValue; 1475 } else { 1476 if((w > IMAGE_MAX_WIDTH) || (h > IMAGE_MAX_HEIGHT)) 1477 return BadValue; 1478 } 1479 1480 if(pPriv->grabbedByV4L) 1481 return BadAlloc; 1482 1483 w = (w + 1) & ~1; 1484 pPriv->pitch = ((w << 1) + 63) & ~63; /* Only packed pixel modes supported */ 1485 size = h * pPriv->pitch; 1486 if(!(pPriv->offset = SISAllocateFBMemory(pScrn, &pPriv->handle, size))) 1487 return BadAlloc; 1488 1489 pPriv->totalSize = size; 1490 1491 surface->width = w; 1492 surface->height = h; 1493 surface->pScrn = pScrn; 1494 surface->id = id; 1495 surface->pitches = &pPriv->pitch; 1496 surface->offsets = &pPriv->offset; 1497 surface->devPrivate.ptr = (pointer)pPriv; 1498 1499 close_overlay(pSiS, pPriv); 1500 pPriv->videoStatus = 0; 1501 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 1502 pSiS->VideoTimerCallback = NULL; 1503 pPriv->grabbedByV4L = TRUE; 1504 return Success; 1505} 1506 1507static int 1508SIS6326StopSurface (XF86SurfacePtr surface) 1509{ 1510 SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr); 1511 SISPtr pSiS = SISPTR(surface->pScrn); 1512 1513 if(pPriv->grabbedByV4L && pPriv->videoStatus) { 1514 close_overlay(pSiS, pPriv); 1515 pPriv->mustwait = 1; 1516 pPriv->videoStatus = 0; 1517 } 1518 return Success; 1519} 1520 1521static int 1522SIS6326FreeSurface (XF86SurfacePtr surface) 1523{ 1524 SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr); 1525 1526 if(pPriv->grabbedByV4L) { 1527 SIS6326StopSurface(surface); 1528 SISFreeFBMemory(surface->pScrn, &pPriv->handle); 1529 pPriv->grabbedByV4L = FALSE; 1530 } 1531 return Success; 1532} 1533 1534static int 1535SIS6326GetSurfaceAttribute ( 1536 ScrnInfoPtr pScrn, 1537 Atom attribute, 1538 INT32 *value 1539) 1540{ 1541 SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); 1542 1543 return SIS6326GetPortAttribute(pScrn, attribute, value, (pointer)pPriv); 1544} 1545 1546static int 1547SIS6326SetSurfaceAttribute( 1548 ScrnInfoPtr pScrn, 1549 Atom attribute, 1550 INT32 value 1551) 1552{ 1553 SISPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);; 1554 1555 return SIS6326SetPortAttribute(pScrn, attribute, value, (pointer)pPriv); 1556} 1557 1558static int 1559SIS6326DisplaySurface ( 1560 XF86SurfacePtr surface, 1561 short src_x, short src_y, 1562 short drw_x, short drw_y, 1563 short src_w, short src_h, 1564 short drw_w, short drw_h, 1565 RegionPtr clipBoxes 1566) 1567{ 1568 ScrnInfoPtr pScrn = surface->pScrn; 1569 SISPortPrivPtr pPriv = (SISPortPrivPtr)(surface->devPrivate.ptr); 1570 1571 if(!pPriv->grabbedByV4L) 1572 return Success; 1573 1574 pPriv->drw_x = drw_x; 1575 pPriv->drw_y = drw_y; 1576 pPriv->drw_w = drw_w; 1577 pPriv->drw_h = drw_h; 1578 pPriv->src_x = src_x; 1579 pPriv->src_y = src_y; 1580 pPriv->src_w = src_w; 1581 pPriv->src_h = src_h; 1582 pPriv->id = surface->id; 1583 pPriv->height = surface->height; 1584 pPriv->bufAddr[0] = surface->offsets[0]; 1585 pPriv->currentBuf = 0; 1586 pPriv->srcPitch = surface->pitches[0]; 1587 1588 SIS6326DisplayVideo(pScrn, pPriv); 1589 1590 if(pPriv->autopaintColorKey) { 1591#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,1,99,1,0) 1592 (*XAAPTR(pScrn)->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy, ~0, 1593 REGION_NUM_RECTS(clipBoxes), 1594 REGION_RECTS(clipBoxes)); 1595#else 1596 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); 1597#endif 1598 } 1599 1600 pPriv->videoStatus = CLIENT_VIDEO_ON; 1601 1602 return Success; 1603} 1604 1605XF86OffscreenImageRec SIS6326OffscreenImages[2] = 1606{ 1607 { 1608 &SIS6326Images[0], /* YUV2 */ 1609 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, 1610 SIS6326AllocSurface, 1611 SIS6326FreeSurface, 1612 SIS6326DisplaySurface, 1613 SIS6326StopSurface, 1614 SIS6326GetSurfaceAttribute, 1615 SIS6326SetSurfaceAttribute, 1616 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 1617 NUM_ATTRIBUTES, 1618 &SIS6326Attributes[0] /* Support all attributes */ 1619 }, 1620 { 1621 &SIS6326Images[1], /* UYVY */ 1622 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, 1623 SIS6326AllocSurface, 1624 SIS6326FreeSurface, 1625 SIS6326DisplaySurface, 1626 SIS6326StopSurface, 1627 SIS6326GetSurfaceAttribute, 1628 SIS6326SetSurfaceAttribute, 1629 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 1630 NUM_ATTRIBUTES, 1631 &SIS6326Attributes[0] /* Support all attributes */ 1632 }, 1633}; 1634 1635static void 1636SIS6326InitOffscreenImages(ScreenPtr pScrn) 1637{ 1638 xf86XVRegisterOffscreenImages(pScrn, SIS6326OffscreenImages, 2); 1639} 1640 1641 1642 1643 1644