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