#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86Resources.h"
#include "xf86_ansic.h"
#include "compiler.h"
#include "xf86PciInfo.h"
#include "xf86Pci.h"
#include "xf86fbman.h"
#include "regionstr.h"
#include "xf86xv.h"
#include "Xv.h"
#include "xaa.h"
#include "xaalocal.h"
#include "dixstruct.h"
#include "fourcc.h"
#include "vgaHW.h"
#include "i740.h"
#define FOURCC_RV15 0x35315652
#define FOURCC_RV16 0x36315652
#define i740_wc(fb,z,r,v) (pI740->writeControl(pI740,(z),(r),(v)))
#define i740_rc(fb,z,r) (pI740->readControl(pI740,(z),(r)))
#define OFF_DELAY 250
#define FREE_DELAY 15000
#define OFF_TIMER 0x01
#define FREE_TIMER 0x02
#define CLIENT_VIDEO_ON 0x04
#define TIMER_MASK (OFF_TIMER | FREE_TIMER)
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
static Atom xvBrightness, xvContrast, xvColorKey;
#define IMAGE_MAX_PHY_WIDTH 1024
#define IMAGE_MAX_PHY_HEIGHT 1024
#define IMAGE_MAX_LOG_WIDTH 1024
#define IMAGE_MAX_LOG_HEIGHT 1024
typedef struct {
CARD32 YBuf0offset;
CARD32 YBuf1offset;
unsigned char currentBuf;
int brightness;
int contrast;
RegionRec clip;
CARD32 colorKey;
CARD32 videoStatus;
Time offTime;
Time freeTime;
FBLinearPtr linear;
} I740PortPrivRec, *I740PortPrivPtr;
typedef struct {
CARD32 OBUF_0Y;
CARD32 OBUF_1Y;
CARD32 OBUF_0U;
CARD32 OBUF_0V;
CARD32 OBUF_1U;
CARD32 OBUF_1V;
CARD32 OV0STRIDE;
CARD32 YRGB_VPH;
CARD32 UV_VPH;
CARD32 HORZ_PH;
CARD32 INIT_PH;
CARD32 DWINPOS;
CARD32 DWINSZ;
CARD32 SWID;
CARD32 SWIDQW;
CARD32 SHEIGHT;
CARD32 YRGBSCALE;
CARD32 UVSCALE;
CARD32 OV0CLRC0;
CARD32 OV0CLRC1;
CARD32 DCLRKV;
CARD32 DCLRKM;
CARD32 SCLRKVH;
CARD32 SCLRKVL;
CARD32 SCLRKM;
CARD32 OV0CONF;
CARD32 OV0CMD;
} I740OverlayRegRec, *I740OverlayRegPtr;
#define GET_PORT_PRIVATE(pScrn) \
(I740PortPrivPtr)((I740PTR(pScrn))->adaptor->pPortPrivates[0].ptr)
__inline__ static void i740fb_overlay_off(ScrnInfoPtr pScrn)
{
I740Ptr pI740 = I740PTR(pScrn);
i740_wc(fb_p, MRX, 0x3C, (i740_rc(fb_p, MRX, 0x3C) | 0x02));
usleep(50000);
i740_wc(fb_p, XRX, 0xD0, 0x2F);
}
__inline__ static void i740fb_overlay_set(ScrnInfoPtr pScrn, I740PortPrivPtr pPriv, unsigned long mem1,unsigned long mem2,
unsigned long isrc_w,unsigned long isrc_h,
unsigned long idst_w,unsigned long idst_h,
unsigned long ddst_x,unsigned long ddst_y,
unsigned long ddst_w,unsigned long ddst_h,
unsigned long pitch,int flip,
unsigned char vd_mod)
{
I740Ptr pI740 = I740PTR(pScrn);
const int f_dbl=pScrn->currentMode->Flags & V_DBLSCAN;
if(f_dbl) { idst_h*=2; ddst_y*=2; ddst_h*=2; }
ddst_x+=pI740->ov_offset_x;
ddst_y+=pI740->ov_offset_y;
i740_wc(fb_p, MRX, 0x24, mem1>>16);
i740_wc(fb_p, MRX, 0x23, mem1>> 8);
i740_wc(fb_p, MRX, 0x22, mem1>> 0);
i740_wc(fb_p, MRX, 0x27, mem2>>16);
i740_wc(fb_p, MRX, 0x26, mem2>> 8);
i740_wc(fb_p, MRX, 0x25, mem2>> 0);
i740_wc(fb_p, MRX, 0x28, (( pitch >>3)-1) );
{ unsigned short v=ddst_x; i740_wc(fb_p, MRX, 0x2B, v>> 8); i740_wc(fb_p, MRX, 0x2A, v>> 0); }
{ unsigned short v=ddst_x+ddst_w-1; i740_wc(fb_p, MRX, 0x2D, v>> 8); i740_wc(fb_p, MRX, 0x2C, v>> 0); }
{ unsigned short v=ddst_y; i740_wc(fb_p, MRX, 0x2F, v>> 8); i740_wc(fb_p, MRX, 0x2E, v>> 0); }
{ unsigned short v=ddst_y+ddst_h-1; i740_wc(fb_p, MRX, 0x31, v>> 8); i740_wc(fb_p, MRX, 0x30, v>> 0); }
i740_wc(fb_p, MRX, 0x32, (isrc_w<<8)/(idst_w));
i740_wc(fb_p, MRX, 0x33, (isrc_h<<8)/(idst_h));
i740_wc(fb_p, MRX, 0x50, 0);
i740_wc(fb_p, MRX, 0x51, 0);
i740_wc(fb_p, MRX, 0x1E, ( idst_w > isrc_w ? 0x04 : 0x00 ) | ( idst_h > isrc_h ? 0x08 : 0x00 ));
i740_wc(fb_p, MRX, 0x1F, ( idst_w > isrc_w ? 0x20 : 0x00 ) | ( (idst_h > isrc_h) && (pitch <= 720*2) ? 0xC0 : 0x00 ) | (vd_mod & 0x1F));
i740_wc(fb_p, MRX, 0x19, 0x00);
i740_wc(fb_p, XRX, 0xD0, 0x3F);
i740_wc(fb_p, MRX, 0x3C, 0x05 | 0x02);
i740_wc(fb_p, MRX, 0x20, (flip ? 0x34 : 0x24));
}
__inline__ static void i740fb_colorkey(ScrnInfoPtr pScrn,unsigned long key)
{
I740Ptr pI740 = I740PTR(pScrn);
unsigned char r,g,b,rm,gm,bm;
switch(pScrn->depth)
{
case 4: r=0x00; g=0x00; b=key; rm=0xFF; gm=0xFF; bm=0xF0; break;
case 8: r=0x00; g=0x00; b=key; rm=0xFF; gm=0xFF; bm=0x00; break;
case 15: r=(key&0x7C00)>>7; g=(key&0x03E0)>>2; b=(key&0x001F)<<3; rm=0x07; gm=0x07; bm=0x07; break;
case 16: r=(key&0xF800)>>8; g=(key&0x07E0)>>3; b=(key&0x001F)<<3; rm=0x07; gm=0x03; bm=0x07; break;
default: r=(key&0xFF00)>>8; g=(key&0xFF00)>>3; b=(key&0xFF00)<<3; rm=0x00; gm=0x00; bm=0x00; break;
}
i740_wc(fb_p, MRX, 0x3D, r);
i740_wc(fb_p, MRX, 0x3E, g);
i740_wc(fb_p, MRX, 0x3F, b);
i740_wc(fb_p, MRX, 0x40, rm);
i740_wc(fb_p, MRX, 0x41, gm);
i740_wc(fb_p, MRX, 0x42, bm);
}
static void I740ResetVideo(ScrnInfoPtr pScrn)
{
I740Ptr pI740 = I740PTR(pScrn);
I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740ResetVideo entered\n");
i740fb_colorkey(pScrn,pPriv->colorKey);
}
static void I740ClipVideo(
BoxPtr dst,
INT32 *x1,
INT32 *x2,
INT32 *y1,
INT32 *y2,
BoxPtr extents,
INT32 width,
INT32 height
){
INT32 vscale, hscale, delta;
int diff;
hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
*x1 <<= 16; *x2 <<= 16;
*y1 <<= 16; *y2 <<= 16;
diff = extents->x1 - dst->x1;
if(diff > 0) {
dst->x1 = extents->x1;
*x1 += diff * hscale;
}
diff = dst->x2 - extents->x2;
if(diff > 0) {
dst->x2 = extents->x2;
*x2 -= diff * hscale;
}
diff = extents->y1 - dst->y1;
if(diff > 0) {
dst->y1 = extents->y1;
*y1 += diff * vscale;
}
diff = dst->y2 - extents->y2;
if(diff > 0) {
dst->y2 = extents->y2;
*y2 -= diff * vscale;
}
if(*x1 < 0) {
diff = (- *x1 + hscale - 1)/ hscale;
dst->x1 += diff;
*x1 += diff * hscale;
}
delta = *x2 - (width << 16);
if(delta > 0) {
diff = (delta + hscale - 1)/ hscale;
dst->x2 -= diff;
*x2 -= diff * hscale;
}
if(*y1 < 0) {
diff = (- *y1 + vscale - 1)/ vscale;
dst->y1 += diff;
*y1 += diff * vscale;
}
delta = *y2 - (height << 16);
if(delta > 0) {
diff = (delta + vscale - 1)/ vscale;
dst->y2 -= diff;
*y2 -= diff * vscale;
}
}
static void I740StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
{
I740PortPrivPtr pPriv = (I740PortPrivPtr)data;
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
if(exit)
{
if(pPriv->videoStatus & CLIENT_VIDEO_ON)
i740fb_overlay_off(pScrn);
if(pPriv->linear)
{
xf86FreeOffscreenLinear(pPriv->linear);
pPriv->linear = NULL;
}
pPriv->videoStatus = 0;
}
else
{
if(pPriv->videoStatus & CLIENT_VIDEO_ON)
{
pPriv->videoStatus |= OFF_TIMER;
pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
}
}
}
static int I740SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value, pointer data)
{
I740PortPrivPtr pPriv = (I740PortPrivPtr)data;
I740Ptr pI740 = I740PTR(pScrn);
I740OverlayRegPtr overlay = (I740OverlayRegPtr) (pI740->FbBase + pI740->OverlayStart);
if(attribute == xvBrightness)
{
if((value < -128) || (value > 127))
return BadValue;
pPriv->brightness = value;
overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff);
}
else
if(attribute == xvContrast)
{
if((value < 0) || (value > 255))
return BadValue;
pPriv->contrast = value;
overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff);
}
else
if(attribute == xvColorKey)
{
pPriv->colorKey = value;
i740fb_colorkey(pScrn,pPriv->colorKey);
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
}
else
return BadMatch;
return Success;
}
static int I740GetPortAttribute(
ScrnInfoPtr pScrn,
Atom attribute,
INT32 *value,
pointer data
){
I740PortPrivPtr pPriv = (I740PortPrivPtr)data;
if(attribute == xvBrightness) {
*value = pPriv->brightness;
} else
if(attribute == xvContrast) {
*value = pPriv->contrast;
} else
if(attribute == xvColorKey) {
*value = pPriv->colorKey;
} else return BadMatch;
return Success;
}
static void I740QueryBestSize(
ScrnInfoPtr pScrn,
Bool motion,
short vid_w, short vid_h,
short drw_w, short drw_h,
unsigned int *p_w, unsigned int *p_h,
pointer data
){
if(vid_w > (drw_w << 1)) drw_w = vid_w >> 1;
if(vid_h > (drw_h << 1)) drw_h = vid_h >> 1;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740QueryBestSize entered %d %d %d %d\n", (int) vid_w, (int) vid_h, (int) drw_w, (int) drw_h);
fprintf(stderr, "fprintf - I740QueryBestSize entered %d %d %d %d\n", (int) vid_w, (int) vid_h, (int) drw_w, (int) drw_h);
*p_w = drw_w;
*p_h = drw_h;
}
static void I740CopyMungedData(ScrnInfoPtr pScrn,
unsigned char *src1, unsigned char *src2, unsigned char *src3,
int srcPitch,
int srcPitch2,
int dstPitch,
int h,
int w,
long scalex,
long scaley)
{
I740Ptr pI740 = I740PTR(pScrn);
I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr;
CARD32 *dst;
int i, j;
if (pPriv->currentBuf == 0)
dst = (CARD32 *)(pI740->FbBase + pPriv->YBuf0offset);
else
dst = (CARD32 *)(pI740->FbBase + pPriv->YBuf1offset);
dstPitch >>= 2;
w >>= 1;
if (scalex > 0x10000 || scaley > 0x10000) {
int dsth = ((long) h * 0x10000L + scaley - 1) / scaley;
long halfx = scalex/2;
long dstj = 0;
for(j = 0; j < dsth; j++) {
int dstj_rnd = dstj >> 16;
unsigned char* src1_ = src1 + (dstj_rnd * srcPitch);
unsigned char* src2_ = src2 + ((dstj_rnd/2) * srcPitch2);
unsigned char* src3_ = src3 + ((dstj_rnd/2) * srcPitch2);
int dstw = ((long) w * 0x10000L + halfx - 1) / scalex;
long srci = 0;
for(i = 0; i < dstw; i++) {
long srci_rnd = srci >> 16;
long srci2_rnd = (srci + halfx) >> 16;
dst[i] =
(((src1_[srci_rnd << 1] | (src1_[(srci_rnd << 1) + 1] << 16) |
(src3_[srci_rnd] << 8) | (src2_[srci_rnd] << 24))) >> 1 & 0x7F7F7F7FL)
+
(((src1_[srci2_rnd << 1] | (src1_[(srci2_rnd << 1) + 1] << 16) |
(src3_[srci2_rnd] << 8) | (src2_[srci2_rnd] << 24))) >> 1 & 0x7F7F7F7FL);
srci += scalex;
}
dst += dstPitch;
dstj += scaley;
}
}
else {
for(j = 0; j < h; j++) {
for(i = 0; i < w; i++) {
dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
(src3[i] << 8) | (src2[i] << 24);
}
dst += dstPitch;
src1 += srcPitch;
if(j & 1) {
src2 += srcPitch2;
src3 += srcPitch2;
}
}
}
}
__inline__ static void I740CopyPackedData(ScrnInfoPtr pScrn,
unsigned char *buf,
int srcPitch,
int dstPitch,
int top,
int left,
int h,
int w
)
{
I740Ptr pI740 = I740PTR(pScrn);
I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr;
unsigned char *src, *dst;
src = buf + (top*srcPitch) + (left<<1);
if (pPriv->currentBuf == 0)
dst = pI740->FbBase + pPriv->YBuf0offset;
else
dst = pI740->FbBase + pPriv->YBuf1offset;
w <<= 1;
while(h--) {
memcpy(dst, src, w);
src += srcPitch;
dst += dstPitch;
}
}
__inline__ static void I740DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height,
int dstPitch,
int x1, int y1, int x2, int y2,
BoxPtr dstBox,
short src_w, short src_h, short drw_w, short drw_h,
unsigned char vd_mod
)
{
I740Ptr pI740 = I740PTR(pScrn);
I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr;
i740fb_overlay_set(pScrn,pPriv,pPriv->YBuf0offset,pPriv->YBuf1offset,
src_w,src_h,
drw_w,drw_h,
dstBox->x1,dstBox->y1,
dstBox->x2 - dstBox->x1,dstBox->y2 - dstBox->y1,
dstPitch,(pPriv->currentBuf != 0),
vd_mod);
i740fb_colorkey(pScrn,pPriv->colorKey);
}
static FBLinearPtr I740AllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
{
ScreenPtr pScreen;
FBLinearPtr new_linear;
if(linear)
{
if(linear->size >= size)
return linear;
if(xf86ResizeOffscreenLinear(linear, size)) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory resized to %d - %p\n", (int) size, (void *)linear);
return linear;
}
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory free %p - %d < %d\n", (void *)linear, (int) linear->size, (int) size);
xf86FreeOffscreenLinear(linear);
}
pScreen = screenInfo.screens[pScrn->scrnIndex];
new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL);
if(!new_linear)
{
int max_size;
xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4, PRIORITY_EXTREME);
if(max_size < size) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory can't purge %d < %d\n", (int) max_size, (int) size);
return NULL;
}
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory purged %d\n", (int) max_size);
xf86PurgeUnlockedOffscreenAreas(pScreen);
new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4,
NULL, NULL, NULL);
}
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory allocated %d - %p\n", (int) size, (void *)new_linear);
return new_linear;
}
static int I740PutImage(ScrnInfoPtr pScrn,
short src_x, short src_y, short drw_x, short drw_y,
short src_w, short src_h, short drw_w, short drw_h,
int id, unsigned char* buf,
short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data
)
{
ScreenPtr pScreen = pScrn->pScreen;
I740Ptr pI740 = I740PTR(pScrn);
I740PortPrivPtr pPriv = (I740PortPrivPtr)data;
INT32 x1, x2, y1, y2;
int srcPitch, dstPitch, srcPitch2=0;
int top, left, npixels, nlines, size;
BoxRec dstBox;
int offset2=0, offset3=0;
x1 = src_x;
x2 = src_x + src_w;
y1 = src_y;
y2 = src_y + src_h;
dstBox.x1 = drw_x;
dstBox.x2 = drw_x + drw_w;
dstBox.y1 = drw_y;
dstBox.y2 = drw_y + drw_h;
I740ClipVideo(&dstBox, &x1, &x2, &y1, &y2,
REGION_EXTENTS(pScreen, clipBoxes), width, height);
if((x1 >= x2) || (y1 >= y2)) {
return Success;
}
dstBox.x1 -= pScrn->frameX0;
dstBox.x2 -= pScrn->frameX0;
dstBox.y1 -= pScrn->frameY0;
dstBox.y2 -= pScrn->frameY0;
switch(id)
{
case FOURCC_YV12:
case FOURCC_I420:
srcPitch = (width + 3) & ~3;
offset2 = srcPitch * height;
srcPitch2 = ((width >> 1) + 3) & ~3;
offset3 = (srcPitch2 * (height >> 1)) + offset2;
dstPitch = ((width << 1) + 15) & ~15;
size = dstPitch * height;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
srcPitch = (width << 1);
dstPitch = (srcPitch + 7) & ~7;
size = dstPitch * height;
break;
}
{
FBLinearPtr new_linear = I740AllocateMemory(pScrn, pPriv->linear, size);
if (new_linear != pPriv->linear) {
pPriv->linear = new_linear;
}
}
if(!pPriv->linear)
return BadAlloc;
pPriv->YBuf0offset = pPriv->linear->offset*pI740->cpp;
pPriv->YBuf1offset = (pPriv->linear->offset*pI740->cpp) + size;
#if 0
while (((INREG(DOV0STA)&0x00100000)>>20) != pPriv->currentBuf);
#endif
pPriv->currentBuf ^= 1;
top = y1 >> 16;
left = (x1 >> 16) & ~1;
npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
switch(id) {
case FOURCC_YV12:
case FOURCC_I420:
{
CARD32 tmp;
top &= ~1;
tmp = ((top >> 1) * srcPitch2) + (left >> 1);
offset2 += tmp;
offset3 += tmp;
if(id == FOURCC_I420)
{
tmp = offset2;
offset2 = offset3;
offset3 = tmp;
}
nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
{
long scalex = 0x10000, scaley = 0x10000;
if (drw_w < src_w)
scalex = (0x10000L * (long) src_w) / (long) drw_w;
if (drw_h < src_h)
scaley = (0x10000L * (long) src_h) / (long) drw_h;
I740CopyMungedData(pScrn, buf + (top * srcPitch) + left,
buf + offset2, buf + offset3,
srcPitch, srcPitch2, dstPitch, nlines, npixels, scalex, scaley);
}
}
break;
case FOURCC_UYVY: case FOURCC_YUY2: default:
{
nlines = ((y2 + 0xffff) >> 16) - top;
I740CopyPackedData(pScrn, buf, srcPitch, dstPitch, top, left, nlines,
npixels);
}
break;
}
if(!REGION_EQUAL(pScreen, &pPriv->clip, clipBoxes))
{
REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
xf86XVFillKeyHelper(pScreen, pPriv->colorKey, clipBoxes);
}
{
unsigned char vd_mod;
switch(id)
{
case FOURCC_RV15: vd_mod=0x09; break;
case FOURCC_RV16: vd_mod=0x08; break;
default: vd_mod=0x00; break;
}
I740DisplayVideo(pScrn, id, width, height, dstPitch,
x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h,
vd_mod);
}
pPriv->videoStatus = CLIENT_VIDEO_ON;
return Success;
}
static int I740QueryImageAttributes(ScrnInfoPtr pScrn, int id, unsigned short *w, unsigned short *h, int *pitches, int *offsets )
{
int size,tmp;
if(*w > IMAGE_MAX_PHY_WIDTH) *w = IMAGE_MAX_PHY_WIDTH;
if(*h > IMAGE_MAX_PHY_HEIGHT) *h = IMAGE_MAX_PHY_HEIGHT;
*w = (*w + 1) & ~1;
if(offsets) offsets[0] = 0;
switch(id)
{
case FOURCC_YV12:
case FOURCC_I420:
*h = (*h + 1) & ~1;
size = (*w + 3) & ~3;
if(pitches) pitches[0] = size;
size *= *h;
if(offsets) offsets[1] = size;
tmp = ((*w >> 1) + 3) & ~3;
if(pitches) pitches[1] = pitches[2] = tmp;
tmp *= (*h >> 1);
size += tmp;
if(offsets) offsets[2] = size;
size += tmp;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
size = *w << 1;
if(pitches) pitches[0] = size;
size *= *h;
break;
}
return size;
}
static void I740BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
{
ScreenPtr pScreen = screenInfo.screens[i];
ScrnInfoPtr pScrn = xf86Screens[i];
I740Ptr pI740 = I740PTR(pScrn);
I740PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
pScreen->BlockHandler = pI740->BlockHandler;
(*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
pScreen->BlockHandler = I740BlockHandler;
if(pPriv->videoStatus & TIMER_MASK)
{
UpdateCurrentTime();
if(pPriv->videoStatus & OFF_TIMER)
{
if(pPriv->offTime < currentTime.milliseconds)
{
i740fb_overlay_off(pScrn);
pPriv->videoStatus = FREE_TIMER;
pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
}
}
else
{
if(pPriv->freeTime < currentTime.milliseconds)
{
if(pPriv->linear)
{
xf86FreeOffscreenLinear(pPriv->linear);
pPriv->linear = NULL;
}
pPriv->videoStatus = 0;
}
}
}
}
typedef struct {
FBLinearPtr linear;
Bool isOn;
} OffscreenPrivRec, * OffscreenPrivPtr;
static int I740AllocateSurface(
ScrnInfoPtr pScrn,
int id,
unsigned short w,
unsigned short h,
XF86SurfacePtr surface
){
FBLinearPtr linear;
int pitch, size;
OffscreenPrivPtr pPriv;
I740Ptr pI740 = I740PTR(pScrn);
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateSurface entered %d %d\n", (int) w, (int) h);
if((w > IMAGE_MAX_LOG_WIDTH) || (h > IMAGE_MAX_LOG_HEIGHT))
return BadAlloc;
w = (w + 1) & ~1;
pitch = ((w << 1) + 15) & ~15;
size = pitch * h;
if(!(linear = I740AllocateMemory(pScrn, NULL, size)))
return BadAlloc;
surface->width = w;
surface->height = h;
if(!(surface->pitches = xalloc(sizeof(int)))) {
xf86FreeOffscreenLinear(linear);
return BadAlloc;
}
if(!(surface->offsets = xalloc(sizeof(int)))) {
xfree(surface->pitches);
xf86FreeOffscreenLinear(linear);
return BadAlloc;
}
if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
xfree(surface->pitches);
xfree(surface->offsets);
xf86FreeOffscreenLinear(linear);
return BadAlloc;
}
pPriv->linear = linear;
pPriv->isOn = FALSE;
surface->pScrn = pScrn;
surface->id = id;
surface->pitches[0] = pitch;
surface->offsets[0] = linear->offset*pI740->cpp;
surface->devPrivate.ptr = (pointer)pPriv;
return Success;
}
static int I740StopSurface(XF86SurfacePtr surface)
{
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
if(pPriv->isOn)
{
pPriv->isOn = FALSE;
}
return Success;
}
static int I740FreeSurface(XF86SurfacePtr surface)
{
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
if(pPriv->isOn)
{
I740StopSurface(surface);
}
xf86FreeOffscreenLinear(pPriv->linear);
xfree(surface->pitches);
xfree(surface->offsets);
xfree(surface->devPrivate.ptr);
return Success;
}
static int I740GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value)
{
return I740GetPortAttribute(pScrn, attribute, value, 0);
}
static int I740SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
{
return I740SetPortAttribute(pScrn, attribute, value, 0);
}
static int I740DisplaySurface(XF86SurfacePtr surface, short src_x, short src_y,
short drw_x, short drw_y,
short src_w, short src_h,
short drw_w, short drw_h,
RegionPtr clipBoxes)
{
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
ScrnInfoPtr pScrn = surface->pScrn;
I740PortPrivPtr pI740Priv = GET_PORT_PRIVATE(pScrn);
INT32 x1, y1, x2, y2;
BoxRec dstBox;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740DisplaySurface entered\n");
x1 = src_x;
x2 = src_x + src_w;
y1 = src_y;
y2 = src_y + src_h;
dstBox.x1 = drw_x;
dstBox.x2 = drw_x + drw_w;
dstBox.y1 = drw_y;
dstBox.y2 = drw_y + drw_h;
I740ClipVideo(&dstBox, &x1, &x2, &y1, &y2,
REGION_EXTENTS(screenInfo.screens[0], clipBoxes),
surface->width, surface->height);
dstBox.x1 -= pScrn->frameX0;
dstBox.x2 -= pScrn->frameX0;
dstBox.y1 -= pScrn->frameY0;
dstBox.y2 -= pScrn->frameY0;
pI740Priv->YBuf0offset = surface->offsets[0];
pI740Priv->YBuf1offset = pI740Priv->YBuf0offset;
#if 0
while (((INREG(DOV0STA)&0x00100000)>>20) != pI740Priv->currentBuf) {
if(loops == 200000) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Overlay Lockup\n");
break;
}
loops++;
}
#endif
if (pI740Priv->currentBuf == 0)
pI740Priv->currentBuf = 1;
else
pI740Priv->currentBuf = 0;
I740ResetVideo(pScrn);
I740DisplayVideo(pScrn, surface->id, surface->width, surface->height,
surface->pitches[0], x1, y1, x2, y2, &dstBox,
src_w, src_h, drw_w, drw_h,
0x00);
xf86XVFillKeyHelper(pScrn->pScreen, pI740Priv->colorKey, clipBoxes);
pPriv->isOn = TRUE;
if(pI740Priv->videoStatus & CLIENT_VIDEO_ON) {
REGION_EMPTY(pScrn->pScreen, & pI740Priv->clip);
UpdateCurrentTime();
pI740Priv->videoStatus = FREE_TIMER;
pI740Priv->freeTime = currentTime.milliseconds + FREE_DELAY;
pScrn->pScreen->BlockHandler = I740BlockHandler;
}
return Success;
}
#define NUM_IMAGES (sizeof(i740vid_Images)/sizeof(XF86ImageRec))
static XF86ImageRec i740vid_Images[] =
{
XVIMAGE_YUY2,
XVIMAGE_UYVY,
XVIMAGE_YV12,
XVIMAGE_I420,
{
FOURCC_RV15,
XvRGB,
LSBFirst,
{'R','V','1','5',
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
16,
XvPacked,
1,
15, 0x001F, 0x03E0, 0x7C00,
0, 0, 0,
0, 0, 0,
0, 0, 0,
{'R','V','B',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,0},
XvTopToBottom
},
{
FOURCC_RV16,
XvRGB,
LSBFirst,
{'R','V','1','6',
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
16,
XvPacked,
1,
16, 0x001F, 0x07E0, 0xF800,
0, 0, 0,
0, 0, 0,
0, 0, 0,
{'R','V','B',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,0},
XvTopToBottom
},
};
#define NUM_ATTRIBUTES (sizeof(i740vid_Attributes)/sizeof(XF86AttributeRec))
static XF86AttributeRec i740vid_Attributes[] =
{
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
};
static void I740InitOffscreenImages(ScreenPtr pScreen)
{
XF86OffscreenImagePtr offscreenImages;
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740InitOffscreenImages entered\n");
}
if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
{
return;
}
offscreenImages[0].image = &i740vid_Images[0];
offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
offscreenImages[0].alloc_surface = I740AllocateSurface;
offscreenImages[0].free_surface = I740FreeSurface;
offscreenImages[0].display = I740DisplaySurface;
offscreenImages[0].stop = I740StopSurface;
offscreenImages[0].setAttribute = I740SetSurfaceAttribute;
offscreenImages[0].getAttribute = I740GetSurfaceAttribute;
offscreenImages[0].max_width = IMAGE_MAX_LOG_WIDTH;
offscreenImages[0].max_height = IMAGE_MAX_LOG_HEIGHT;
offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
offscreenImages[0].attributes = i740vid_Attributes;
xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
}
static XF86VideoAdaptorPtr I740SetupImageVideo(ScreenPtr pScreen)
{
static XF86VideoEncodingRec DummyEncoding[1] =
{
{
0,
"XV_IMAGE",
IMAGE_MAX_PHY_WIDTH, IMAGE_MAX_PHY_HEIGHT,
{1, 1}
}
};
#define NUM_FORMATS (sizeof(i740vid_Formats)/sizeof(XF86VideoFormatRec))
static XF86VideoFormatRec i740vid_Formats[] =
{
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}, {8, PseudoColor}
};
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I740Ptr pI740 = I740PTR(pScrn);
XF86VideoAdaptorPtr adapt;
I740PortPrivPtr pPriv;
{
const int n=sizeof(XF86VideoAdaptorRec)+sizeof(I740PortPrivRec)+sizeof(DevUnion);
if(!(adapt = xcalloc(1, n)))
return NULL;
}
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
adapt->name = "I740 Video Overlay";
adapt->nEncodings = 1;
adapt->pEncodings = DummyEncoding;
adapt->nFormats = NUM_FORMATS;
adapt->pFormats = i740vid_Formats;
adapt->nPorts = 1;
adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
pPriv = (I740PortPrivPtr)((unsigned char *)(&adapt[1])+sizeof(sizeof(DevUnion)));
adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
adapt->pAttributes = i740vid_Attributes;
adapt->nImages = NUM_IMAGES;
adapt->nAttributes = NUM_ATTRIBUTES;
adapt->pImages = i740vid_Images;
adapt->PutVideo = NULL;
adapt->PutStill = NULL;
adapt->GetVideo = NULL;
adapt->GetStill = NULL;
adapt->StopVideo = I740StopVideo;
adapt->SetPortAttribute = I740SetPortAttribute;
adapt->GetPortAttribute = I740GetPortAttribute;
adapt->QueryBestSize = I740QueryBestSize;
adapt->PutImage = I740PutImage;
adapt->QueryImageAttributes = I740QueryImageAttributes;
pPriv->colorKey = pI740->colorKey & ((1 << pScrn->depth) - 1);
pPriv->videoStatus = 0;
pPriv->brightness = 0;
pPriv->contrast = 64;
pPriv->linear = NULL;
pPriv->currentBuf = 0;
REGION_NULL(pScreen, &pPriv->clip);
pI740->adaptor = adapt;
pI740->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = I740BlockHandler;
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
xvContrast = MAKE_ATOM("XV_CONTRAST");
xvColorKey = MAKE_ATOM("XV_COLORKEY");
I740ResetVideo(pScrn);
return adapt;
}
void I740InitVideo(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
XF86VideoAdaptorPtr newAdaptor = NULL;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740InitVideo entered\n");
#if 0
{
XF86VideoAdaptorPtr *ptr;
int n;
n = xf86XVListGenericAdaptors(pScrn,&ptr);
if (n) {
xf86XVScreenInit(pScreen, ptr, n);
}
return;
}
#endif
{
newAdaptor = I740SetupImageVideo(pScreen);
I740InitOffscreenImages(pScreen);
}
{
XF86VideoAdaptorPtr *adaptors_oldptrs, *adaptors_newptrs = NULL;
int num_adaptors;
num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors_oldptrs);
if(newAdaptor)
{
if(!num_adaptors)
{
xf86XVScreenInit(pScreen, &newAdaptor, 1);
}
else
{
if((adaptors_newptrs = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr))))
{
memcpy(adaptors_newptrs, adaptors_oldptrs, num_adaptors * sizeof(XF86VideoAdaptorPtr));
adaptors_newptrs[num_adaptors] = newAdaptor;
xf86XVScreenInit(pScreen, adaptors_newptrs, num_adaptors+1);
xfree(adaptors_newptrs);
}
}
}
}
}