smi_video.c revision 09885543
109885543Smrg/* Header:   //Mercury/Projects/archives/XFree86/4.0/smi_video.c.-arc   1.14   30 Nov 2000 16:51:40   Frido  $ */
209885543Smrg/*
309885543SmrgCopyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
409885543SmrgCopyright (C) 2000 Silicon Motion, Inc.  All Rights Reserved.
509885543SmrgCopyright (C) 2001 Corvin Zahn.  All Rights Reserved.
609885543Smrg
709885543SmrgPermission is hereby granted, free of charge, to any person obtaining a copy of
809885543Smrgthis software and associated documentation files (the "Software"), to deal in
909885543Smrgthe Software without restriction, including without limitation the rights to
1009885543Smrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
1109885543Smrgof the Software, and to permit persons to whom the Software is furnished to do
1209885543Smrgso, subject to the following conditions:
1309885543Smrg
1409885543SmrgThe above copyright notice and this permission notice shall be included in all
1509885543Smrgcopies or substantial portions of the Software.
1609885543Smrg
1709885543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1809885543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
1909885543SmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
2009885543SmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2109885543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2209885543SmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2309885543Smrg
2409885543SmrgExcept as contained in this notice, the names of the XFree86 Project and
2509885543SmrgSilicon Motion shall not be used in advertising or otherwise to promote the
2609885543Smrgsale, use or other dealings in this Software without prior written
2709885543Smrgauthorization from the XFree86 Project and silicon Motion.
2809885543Smrg*/
2909885543Smrg
3009885543Smrg/*
3109885543Smrgthis is a heavy modified version of the V1.2.2 original siliconmotion driver.
3209885543Smrg- SAA7111 support
3309885543Smrg- supports attributes: XV_ENCODING, XV_BRIGHTNESS, XV_CONTRAST,
3409885543Smrg  XV_SATURATION, XV_HUE, XV_COLORKEY, XV_INTERLACED
3509885543Smrg  XV_CAPTURE_BRIGHTNESS can be used to set brightness in the capture device
3609885543Smrg- bug fixes
3709885543Smrg- tries not to use acceleration functions
3809885543Smrg- interlaced video for double vertical resolution
3909885543Smrg
4009885543SmrgAuthor of changes: Corvin Zahn <zahn@zac.de>
4109885543SmrgDate:   2.11.2001
4209885543Smrg*/
4309885543Smrg
4409885543Smrg/* $XdotOrg: driver/xf86-video-siliconmotion/src/smi_video.c,v 1.5 2005/07/11 02:29:59 ajax Exp $ */
4509885543Smrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_video.c,v 1.13 2003/11/10 18:22:26 tsi Exp $ */
4609885543Smrg
4709885543Smrg#ifdef HAVE_CONFIG_H
4809885543Smrg#include "config.h"
4909885543Smrg#endif
5009885543Smrg
5109885543Smrg#include "smi.h"
5209885543Smrg#include "smi_video.h"
5309885543Smrg
5409885543Smrg
5509885543Smrg/*
5609885543Smrg
5709885543Smrgnew attribute:
5809885543Smrg
5909885543SmrgXV_INTERLACED = 0: only one field of an interlaced video signal is displayed:
6009885543Smrg               -> half vertical resolution, but no comb like artifacts from
6109885543Smrg	       moving vertical edges
6209885543SmrgXV_INTERLACED = 1: both fields of an interlaced video signal are displayed:
6309885543Smrg               -> full vertical resolution, but comb like artifacts from
6409885543Smrg	       moving vertical edges
6509885543Smrg
6609885543SmrgThe default value can be set with the driver option Interlaced
6709885543Smrg
6809885543Smrg*/
6909885543Smrg
7009885543Smrg
7109885543Smrg
7209885543Smrg
7309885543Smrg#undef MIN
7409885543Smrg#undef ABS
7509885543Smrg#undef CLAMP
7609885543Smrg#undef ENTRIES
7709885543Smrg
7809885543Smrg#define MIN(a, b) (((a) < (b)) ? (a) : (b))
7909885543Smrg#define ABS(n) (((n) < 0) ? -(n) : (n))
8009885543Smrg#define CLAMP(v, min, max) (((v) < (min)) ? (min) : MIN(v, max))
8109885543Smrg
8209885543Smrg#define ENTRIES(array) (sizeof(array) / sizeof((array)[0]))
8309885543Smrg#define nElems(x)		(sizeof(x) / sizeof(x[0]))
8409885543Smrg
8509885543Smrg#define MAKE_ATOM(a)	MakeAtom(a, sizeof(a) - 1, TRUE)
8609885543Smrg
8709885543Smrg#if SMI_USE_VIDEO
8809885543Smrg#include "dixstruct.h"
8909885543Smrg
9009885543Smrg
9109885543Smrgstatic int SMI_AddEncoding(XF86VideoEncodingPtr enc, int i,
9209885543Smrg			   int norm, int input, int channel);
9309885543Smrgstatic void SMI_BuildEncodings(SMI_PortPtr p);
9409885543Smrg
9509885543Smrgstatic XF86VideoAdaptorPtr SMI_SetupVideo(ScreenPtr pScreen);
9609885543Smrgstatic void SMI_ResetVideo(ScrnInfoPtr pScrn);
9709885543Smrg
9809885543Smrg#if SMI_USE_CAPTURE
9909885543Smrgstatic int SMI_PutVideo(ScrnInfoPtr pScrn,
10009885543Smrg		short vid_x, short vid_y, short drw_x, short drw_y,
10109885543Smrg		short vid_w, short vid_h, short drw_w, short drw_h,
10209885543Smrg		RegionPtr clipBoxes, pointer data, DrawablePtr);
10309885543Smrg#endif
10409885543Smrgstatic void SMI_StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown);
10509885543Smrgstatic int SMI_SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
10609885543Smrg		INT32 value, pointer data);
10709885543Smrgstatic int SMI_GetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
10809885543Smrg		INT32 *value, pointer data);
10909885543Smrgstatic void SMI_QueryBestSize(ScrnInfoPtr pScrn, Bool motion,
11009885543Smrg		short vid_w, short vid_h, short drw_w, short drw_h,
11109885543Smrg		unsigned int *p_w, unsigned int *p_h, pointer data);
11209885543Smrgstatic int SMI_PutImage(ScrnInfoPtr pScrn,
11309885543Smrg		short src_x, short src_y, short drw_x, short drw_y,
11409885543Smrg		short src_w, short src_h, short drw_w, short drw_h,
11509885543Smrg		int id, unsigned char *buf, short width, short height, Bool sync,
11609885543Smrg		RegionPtr clipBoxes, pointer data, DrawablePtr);
11709885543Smrgstatic int SMI_QueryImageAttributes(ScrnInfoPtr pScrn,
11809885543Smrg		int id, unsigned short *width, unsigned short *height,
11909885543Smrg		int *picthes, int *offsets);
12009885543Smrg
12109885543Smrgstatic Bool SMI_ClipVideo(ScrnInfoPtr pScrn, BoxPtr dst,
12209885543Smrg		INT32 *x1, INT32 *y1, INT32 *x2, INT32 *y2,
12309885543Smrg		RegionPtr reg, INT32 width, INT32 height);
12409885543Smrgstatic void SMI_DisplayVideo(ScrnInfoPtr pScrn, int id, int offset,
12509885543Smrg		short width, short height, int pitch, int x1, int y1, int x2, int y2,
12609885543Smrg		BoxPtr dstBox, short vid_w, short vid_h, short drw_w, short drw_h);
12709885543Smrgstatic void SMI_DisplayVideo0730(ScrnInfoPtr pScrn, int id, int offset,
12809885543Smrg		short width, short height, int pitch, int x1, int y1, int x2, int y2,
12909885543Smrg		BoxPtr dstBox, short vid_w, short vid_h, short drw_w, short drw_h);
13009885543Smrgstatic void SMI_BlockHandler(int i, pointer blockData, pointer pTimeout,
13109885543Smrg		pointer pReadMask);
13209885543Smrg#if 0
13309885543Smrgstatic void SMI_WaitForSync(ScrnInfoPtr pScrn);
13409885543Smrg#endif
13509885543Smrg/*static int SMI_SendI2C(ScrnInfoPtr pScrn, CARD8 device, char *devName,
13609885543Smrg        SMI_I2CDataPtr i2cData);*/
13709885543Smrg
13809885543Smrgstatic void SMI_InitOffscreenImages(ScreenPtr pScreen);
13909885543Smrgstatic void SMI_VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area);
14009885543Smrgstatic CARD32 SMI_AllocateMemory(ScrnInfoPtr pScrn, void **mem_struct, int size);
14109885543Smrgstatic void SMI_FreeMemory(ScrnInfoPtr pScrn, void *mem_struct);
14209885543Smrg
14309885543Smrg
14409885543Smrgstatic int SMI_AllocSurface(ScrnInfoPtr pScrn,
14509885543Smrg		int id, unsigned short width, unsigned short height,
14609885543Smrg		XF86SurfacePtr surface);
14709885543Smrgstatic int SMI_FreeSurface(XF86SurfacePtr surface);
14809885543Smrgstatic int SMI_DisplaySurface(XF86SurfacePtr surface,
14909885543Smrg		short vid_x, short vid_y, short drw_x, short drw_y,
15009885543Smrg		short vid_w, short vid_h, short drw_w, short drw_h,
15109885543Smrg		RegionPtr clipBoxes);
15209885543Smrgstatic int SMI_StopSurface(XF86SurfacePtr surface);
15309885543Smrgstatic int SMI_GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value);
15409885543Smrgstatic int SMI_SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value);
15509885543Smrg
15609885543Smrgstatic int SetAttr(ScrnInfoPtr pScrn, int i, int value);
15709885543Smrgstatic int SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value);
15809885543Smrgstatic int SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value);
15909885543Smrgstatic void SetKeyReg(SMIPtr pSmi, int reg, int value);
16009885543Smrg
16109885543Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,0,0)
16209885543Smrgstatic Bool RegionsEqual(RegionPtr A, RegionPtr B);
16309885543Smrg#endif
16409885543Smrg/**
16509885543Smrg * Atoms
16609885543Smrg */
16709885543Smrg
16809885543Smrgstatic Atom xvColorKey;
16909885543Smrgstatic Atom xvEncoding;
17009885543Smrgstatic Atom xvBrightness,xvCapBrightness, xvContrast, xvSaturation, xvHue;
17109885543Smrgstatic Atom xvInterlaced;
17209885543Smrg
17309885543Smrg
17409885543Smrg/******************************************************************************\
17509885543Smrg**																			  **
17609885543Smrg**                           C A P A B I L I T I E S                          **
17709885543Smrg**																			  **
17809885543Smrg\******************************************************************************/
17909885543Smrg
18009885543Smrg
18109885543Smrg/**************************************************************************/
18209885543Smrg/* input channels */
18309885543Smrg
18409885543Smrg#define N_COMPOSITE_CHANNELS 4
18509885543Smrg#define N_SVIDEO_CHANNELS 2
18609885543Smrg
18709885543Smrg#define N_VIDEO_INPUTS 2
18809885543Smrgtypedef enum _VideoInput { VID_COMPOSITE, VID_SVIDEO } VideoInput;
18909885543Smrg
19009885543Smrg
19109885543Smrg/**************************************************************************/
19209885543Smrg/* video input formats */
19309885543Smrg
19409885543Smrgtypedef struct _VideoInputDataRec {
19509885543Smrg    char* name;
19609885543Smrg} VideoInputDataRec;
19709885543Smrg
19809885543Smrgstatic VideoInputDataRec VideoInputs[] = {
19909885543Smrg    { "composite" },
20009885543Smrg    { "svideo" }
20109885543Smrg};
20209885543Smrg
20309885543Smrg
20409885543Smrg/**************************************************************************/
20509885543Smrg/* video norms */
20609885543Smrg
20709885543Smrg#define N_VIDEO_NORMS 3
20809885543Smrgtypedef enum _VideoNorm { PAL, NTSC, SECAM } VideoNorm;
20909885543Smrg
21009885543Smrgtypedef struct _VideoNormDataRec {
21109885543Smrg    char* name;
21209885543Smrg    unsigned long Wt;
21309885543Smrg    unsigned long Wa;
21409885543Smrg    unsigned long Ht;
21509885543Smrg    unsigned long Ha;
21609885543Smrg    unsigned long HStart;
21709885543Smrg    unsigned long VStart;
21809885543Smrg    XvRationalRec rate;
21909885543Smrg} VideoNormDataRec;
22009885543Smrg
22109885543Smrg
22209885543Smrgstatic VideoNormDataRec VideoNorms[] =
22309885543Smrg{
22409885543Smrg    /* PAL-BDGHI */
22509885543Smrg    {"pal", 864, 704, 625, 576, 16, 16, { 1, 50 }},
22609885543Smrg    /* NTSC */
22709885543Smrg    {"ntsc", 858, 704, 525, 480, 21, 8, { 1001, 60000 }},
22809885543Smrg    /* SECAM (not tested) */
22909885543Smrg    {"secam", 864, 7040, 625, 576, 31, 16, { 1, 50 }},
23009885543Smrg};
23109885543Smrg
23209885543Smrg
23309885543Smrg/**************************************************************************/
23409885543Smrg/* number of (generated) XV_ENCODING vaulues */
23509885543Smrg#define N_ENCODINGS ((N_VIDEO_NORMS) * (N_COMPOSITE_CHANNELS + N_SVIDEO_CHANNELS))
23609885543Smrg
23709885543Smrg
23809885543Smrg/**************************************************************************/
23909885543Smrg
24009885543Smrgstatic XF86VideoFormatRec SMI_VideoFormats[] =
24109885543Smrg{
24209885543Smrg    { 15, TrueColor },	/* depth, class				*/
24309885543Smrg    { 16, TrueColor },	/* depth, class				*/
24409885543Smrg    { 24, TrueColor },	/* depth, class				*/
24509885543Smrg};
24609885543Smrg
24709885543Smrg
24809885543Smrg/**************************************************************************/
24909885543Smrg
25009885543Smrg/**
25109885543Smrg * Attributes
25209885543Smrg */
25309885543Smrg
25409885543Smrg#define XV_ENCODING_NAME        "XV_ENCODING"
25509885543Smrg#define XV_BRIGHTNESS_NAME      "XV_BRIGHTNESS"
25609885543Smrg#define XV_CAPTURE_BRIGHTNESS_NAME      "XV_CAPTURE_BRIGHTNESS"
25709885543Smrg#define XV_CONTRAST_NAME        "XV_CONTRAST"
25809885543Smrg#define XV_SATURATION_NAME      "XV_SATURATION"
25909885543Smrg#define XV_HUE_NAME             "XV_HUE"
26009885543Smrg#define XV_COLORKEY_NAME        "XV_COLORKEY"
26109885543Smrg#define XV_INTERLACED_NAME      "XV_INTERLACED"
26209885543Smrg
26309885543Smrg
26409885543Smrg/* fixed order! */
26509885543Smrgstatic XF86AttributeRec SMI_VideoAttributesSAA711x[N_ATTRS] = {
26609885543Smrg    {XvSettable | XvGettable,        0, N_ENCODINGS-1, XV_ENCODING_NAME},
26709885543Smrg    {XvSettable | XvGettable,        0,           255, XV_BRIGHTNESS_NAME},
26809885543Smrg    {XvSettable | XvGettable,        0,           255, XV_CAPTURE_BRIGHTNESS_NAME},
26909885543Smrg    {XvSettable | XvGettable,        0,           127, XV_CONTRAST_NAME},
27009885543Smrg    {XvSettable | XvGettable,        0,           127, XV_SATURATION_NAME},
27109885543Smrg    {XvSettable | XvGettable,     -128,           127, XV_HUE_NAME},
27209885543Smrg    {XvSettable | XvGettable, 0x000000,      0xFFFFFF, XV_COLORKEY_NAME},
27309885543Smrg    {XvSettable | XvGettable,        0,             1, XV_INTERLACED_NAME},
27409885543Smrg};
27509885543Smrg
27609885543Smrgstatic XF86AttributeRec SMI_VideoAttributes[2] = {
27709885543Smrg    {XvSettable | XvGettable,        0,           255, XV_BRIGHTNESS_NAME},
27809885543Smrg    {XvSettable | XvGettable, 0x000000,      0xFFFFFF, XV_COLORKEY_NAME},
27909885543Smrg};
28009885543Smrg
28109885543Smrg
28209885543Smrg/**************************************************************************/
28309885543Smrgstatic XF86ImageRec SMI_VideoImages[] =
28409885543Smrg{
28509885543Smrg    XVIMAGE_YUY2,
28609885543Smrg    XVIMAGE_YV12,
28709885543Smrg    XVIMAGE_I420,
28809885543Smrg    {
28909885543Smrg	FOURCC_RV15,			/* id				*/
29009885543Smrg	XvRGB,				/* type				*/
29109885543Smrg	LSBFirst,			/* byte_order			*/
29209885543Smrg	{ 'R', 'V' ,'1', '5',
29309885543Smrg	  0x00, '5',  0x00, 0x00,
29409885543Smrg	  0x00, 0x00, 0x00, 0x00,
29509885543Smrg	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
29609885543Smrg	16,				/* bits_per_pixel		*/
29709885543Smrg	XvPacked,			/* format			*/
29809885543Smrg	1,				/* num_planes			*/
29909885543Smrg	15,				/* depth			*/
30009885543Smrg	0x001F, 0x03E0, 0x7C00,		/* red_mask, green, blue	*/
30109885543Smrg	0, 0, 0,			/* y_sample_bits, u, v		*/
30209885543Smrg	0, 0, 0,			/* horz_y_period, u, v		*/
30309885543Smrg	0, 0, 0,			/* vert_y_period, u, v		*/
30409885543Smrg	{ 'R', 'V', 'B' },		/* component_order		*/
30509885543Smrg	XvTopToBottom			/* scaline_order		*/
30609885543Smrg    },
30709885543Smrg    {
30809885543Smrg	FOURCC_RV16,			/* id				*/
30909885543Smrg	XvRGB,				/* type				*/
31009885543Smrg	LSBFirst,			/* byte_order			*/
31109885543Smrg	{ 'R', 'V' ,'1', '6',
31209885543Smrg	  0x00, 0x00, 0x00, 0x00,
31309885543Smrg	  0x00, 0x00, 0x00, 0x00,
31409885543Smrg	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
31509885543Smrg	16,				/* bits_per_pixel		*/
31609885543Smrg	XvPacked,			/* format			*/
31709885543Smrg	1,				/* num_planes			*/
31809885543Smrg	16,				/* depth			*/
31909885543Smrg	0x001F, 0x07E0, 0xF800,		/* red_mask, green, blue	*/
32009885543Smrg	0, 0, 0,			/* y_sample_bits, u, v		*/
32109885543Smrg	0, 0, 0,			/* horz_y_period, u, v		*/
32209885543Smrg	0, 0, 0,			/* vert_y_period, u, v		*/
32309885543Smrg	{ 'R', 'V', 'B' },		/* component_order		*/
32409885543Smrg	XvTopToBottom			/* scaline_order		*/
32509885543Smrg    },
32609885543Smrg    {
32709885543Smrg	FOURCC_RV24,			/* id				*/
32809885543Smrg	XvRGB,				/* type				*/
32909885543Smrg	LSBFirst,			/* byte_order			*/
33009885543Smrg	{ 'R', 'V' ,'2', '4',
33109885543Smrg	  0x00, 0x00, 0x00, 0x00,
33209885543Smrg	  0x00, 0x00, 0x00, 0x00,
33309885543Smrg	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
33409885543Smrg	24,				/* bits_per_pixel		*/
33509885543Smrg	XvPacked,			/* format			*/
33609885543Smrg	1,				/* num_planes			*/
33709885543Smrg	24,				/* depth			*/
33809885543Smrg	0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue	*/
33909885543Smrg	0, 0, 0,			/* y_sample_bits, u, v		*/
34009885543Smrg	0, 0, 0,			/* horz_y_period, u, v		*/
34109885543Smrg	0, 0, 0,			/* vert_y_period, u, v		*/
34209885543Smrg	{ 'R', 'V', 'B' },		/* component_order			*/
34309885543Smrg	XvTopToBottom			/* scaline_order			*/
34409885543Smrg    },
34509885543Smrg    {
34609885543Smrg	FOURCC_RV32,			/* id				*/
34709885543Smrg	XvRGB,				/* type				*/
34809885543Smrg	LSBFirst,			/* byte_order			*/
34909885543Smrg	{ 'R', 'V' ,'3', '2',
35009885543Smrg	  0x00, 0x00, 0x00, 0x00,
35109885543Smrg	  0x00, 0x00, 0x00, 0x00,
35209885543Smrg	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
35309885543Smrg	32,				/* bits_per_pixel		*/
35409885543Smrg	XvPacked,			/* format			*/
35509885543Smrg	1,				/* num_planes			*/
35609885543Smrg	24,				/* depth			*/
35709885543Smrg	0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue	*/
35809885543Smrg	0, 0, 0,			/* y_sample_bits, u, v		*/
35909885543Smrg	0, 0, 0,			/* horz_y_period, u, v		*/
36009885543Smrg	0, 0, 0,			/* vert_y_period, u, v		*/
36109885543Smrg	{ 'R', 'V', 'B' },		/* component_order			*/
36209885543Smrg	XvTopToBottom			/* scaline_order			*/
36309885543Smrg    },
36409885543Smrg};
36509885543Smrg
36609885543Smrg
36709885543Smrg/**************************************************************************/
36809885543Smrg
36909885543Smrg/**
37009885543Smrg * SAA7111 video decoder register values
37109885543Smrg */
37209885543Smrg
37309885543Smrg
37409885543Smrg/** SAA7111 control sequences for selecting one out of four
37509885543Smrg    composite input channels */
37609885543Smrgstatic I2CByte SAA7111CompositeChannelSelect[N_COMPOSITE_CHANNELS][4] = {
37709885543Smrg    { 0x02, 0xC0, 0x09, 0x4A}, /* CVBS AI11 */
37809885543Smrg    { 0x02, 0xC1, 0x09, 0x4A}, /* CVBS AI12 */
37909885543Smrg    { 0x02, 0xC2, 0x09, 0x4A}, /* CVBS AI21 */
38009885543Smrg    { 0x02, 0xC3, 0x09, 0x4A}, /* CVBS AI22 */
38109885543Smrg};
38209885543Smrg
38309885543Smrg
38409885543Smrg/** SAA7111 control sequences for selecting one out of two
38509885543Smrg    s-video input channels */
38609885543Smrgstatic I2CByte SAA7111SVideoChannelSelect[N_SVIDEO_CHANNELS][4] = {
38709885543Smrg    { 0x02, 0xC6, 0x09, 0xCA}, /* Y/C AI11/AI21 */
38809885543Smrg    { 0x02, 0xC7, 0x09, 0xCA}, /* Y/C AI12/AI22 */
38909885543Smrg};
39009885543Smrg
39109885543Smrg
39209885543Smrg/** SAA7111 control sequences for selecting one out of three
39309885543Smrg    video norms */
39409885543Smrgstatic I2CByte SAA7111VideoStd[3][8] = {
39509885543Smrg    {0x06, 108, 0x07, 108, 0x08, 0x09, 0x0E, 0x01}, /* PAL */
39609885543Smrg    {0x06, 107, 0x07, 107, 0x08, 0x49, 0x0E, 0x01}, /* NTSC */
39709885543Smrg    {0x06, 108, 0x07, 108, 0x08, 0x01, 0x0E, 0x51}  /* SECAM */
39809885543Smrg};
39909885543Smrg
40009885543Smrg
40109885543Smrg#if 0
40209885543Smrgstatic I2CByte SAA7110InitData[] =
40309885543Smrg{
40409885543Smrg	/* Configuration */
40509885543Smrg    0x00, 0x4C, 0x01, 0x3C, 0x02, 0x00, 0x03, 0xEF,
40609885543Smrg    0x04, 0xBD, 0x05, 0xE2, 0x06, 0x00, 0x07, 0x00,
40709885543Smrg    0x08, 0xF8, 0x09, 0xF8, 0x0A, 0x60, 0x0B, 0x60,
40809885543Smrg    0x0C, 0x00, 0x0D, 0x80, 0x0E, 0x18, 0x0F, 0xD9,
40909885543Smrg    0x10, 0x00, 0x11, 0x2B, 0x12, 0x40, 0x13, 0x40,
41009885543Smrg    0x14, 0x42, 0x15, 0x1A, 0x16, 0xFF, 0x17, 0xDA,
41109885543Smrg    0x18, 0xE6, 0x19, 0x90, 0x20, 0xD9, 0x21, 0x16,
41209885543Smrg    0x22, 0x40, 0x23, 0x40, 0x24, 0x80, 0x25, 0x40,
41309885543Smrg    0x26, 0x80, 0x27, 0x4F, 0x28, 0xFE, 0x29, 0x01,
41409885543Smrg    0x2A, 0xCF, 0x2B, 0x0F, 0x2C, 0x03, 0x2D, 0x01,
41509885543Smrg    0x2E, 0x83, 0x2F, 0x03, 0x30, 0x40, 0x31, 0x35,
41609885543Smrg    0x32, 0x02, 0x33, 0x8C, 0x34, 0x03,
41709885543Smrg
41809885543Smrg	/* NTSC */
41909885543Smrg    0x11, 0x2B, 0x0F, 0xD9,
42009885543Smrg
42109885543Smrg	/* RCA input connector */
42209885543Smrg    0x06, 0x00, 0x0E, 0x18, 0x20, 0xD9, 0x21, 0x16,
42309885543Smrg    0x22, 0x40, 0x2C, 0x03,
42409885543Smrg
42509885543Smrg};
42609885543Smrg#endif
42709885543Smrg
42809885543Smrgstatic I2CByte SAA7111InitData[] =
42909885543Smrg{
43009885543Smrg    0x11, 0x1D, /* 0D D0=1: automatic colour killer off
43109885543Smrg		   D1=0: DMSD data to YUV output
43209885543Smrg		   D2=1: output enable H/V sync on
43309885543Smrg		   D3=1: output enable YUV data on */
43409885543Smrg    0x02, 0xC0, /* Mode 0 */
43509885543Smrg    0x03, 0x23, /* automatic gain */
43609885543Smrg    0x04, 0x00, /*  */
43709885543Smrg    0x05, 0x00, /*  */
43809885543Smrg    0x06, 108,  /* hor sync begin */
43909885543Smrg    0x07, 108,  /* hor sync stop */
44009885543Smrg    0x08, 0x88, /* sync control:
44109885543Smrg		   D1-0=00: VNOI = normal mode
44209885543Smrg		   D2=0: PLL closed
44309885543Smrg		   D3=1: VTR mode
44409885543Smrg		   D7=1: automatic field detection */
44509885543Smrg    0x09, 0x41, /* 4A luminance control */
44609885543Smrg    0x0A, 0x80, /* brightness = 128 (CCIR level) */
44709885543Smrg    0x0B, 0x40, /* contrast = 1.0 */
44809885543Smrg    0x0C, 0x40, /* crominance = 1.0 (CCIR level) */
44909885543Smrg    0x0D, 0x00, /* hue = 0 */
45009885543Smrg    0x0E, 0x01, /* chroma bandwidth = nominal
45109885543Smrg		   fast colour time constant = nominal
45209885543Smrg		   chrom comp filter on
45309885543Smrg		   colour standard PAL BGHI, NTSC M */
45409885543Smrg    0x10, 0x48, /* luminance delay compensation = 0
45509885543Smrg		   VRLN = 1
45609885543Smrg		   fine pos of hs = 0
45709885543Smrg		   output format = YUV 422 */
45809885543Smrg    0x12, 0x00, /* 20 D5=1: VPO in tristate */
45909885543Smrg    0x13, 0x00,
46009885543Smrg    0x15, 0x00,
46109885543Smrg    0x16, 0x00,
46209885543Smrg    0x17, 0x00,
46309885543Smrg
46409885543Smrg};
46509885543Smrg
46609885543Smrg
46709885543Smrg/**************************************************************************/
46809885543Smrg
46909885543Smrg/* To allow this ddx to work on 4_3_0 and above, we need to include this */
47009885543Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,0,0)
47109885543Smrgstatic Bool
47209885543SmrgRegionsEqual(
47309885543Smrg	RegionPtr	A,
47409885543Smrg	RegionPtr	B
47509885543Smrg)
47609885543Smrg{
47709885543Smrg	int *dataA, *dataB;
47809885543Smrg	int num;
47909885543Smrg
48009885543Smrg	ENTER_PROC("RegionsEqual");
48109885543Smrg
48209885543Smrg	num = REGION_NUM_RECTS(A);
48309885543Smrg	if (num != REGION_NUM_RECTS(B))
48409885543Smrg	{
48509885543Smrg		LEAVE_PROC("RegionsEqual");
48609885543Smrg		return(FALSE);
48709885543Smrg	}
48809885543Smrg
48909885543Smrg	if (   (A->extents.x1 != B->extents.x1)
49009885543Smrg		|| (A->extents.y1 != B->extents.y1)
49109885543Smrg		|| (A->extents.x2 != B->extents.x2)
49209885543Smrg		|| (A->extents.y2 != B->extents.y2)
49309885543Smrg	)
49409885543Smrg	{
49509885543Smrg		LEAVE_PROC("RegionsEqual");
49609885543Smrg		return(FALSE);
49709885543Smrg	}
49809885543Smrg
49909885543Smrg	dataA = (int*) REGION_RECTS(A);
50009885543Smrg	dataB = (int*) REGION_RECTS(B);
50109885543Smrg
50209885543Smrg	while (num--)
50309885543Smrg	{
50409885543Smrg		if ((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
50509885543Smrg		{
50609885543Smrg			return(FALSE);
50709885543Smrg		}
50809885543Smrg		dataA += 2;
50909885543Smrg		dataB += 2;
51009885543Smrg	}
51109885543Smrg
51209885543Smrg	LEAVE_PROC("RegionsEqual");
51309885543Smrg	return(TRUE);
51409885543Smrg}
51509885543Smrg#endif
51609885543Smrg
51709885543Smrg
51809885543Smrg/**
51909885543Smrg * generates XF86VideoEncoding[i] with video norm norm, video input format
52009885543Smrg * input and video input channel channel
52109885543Smrg */
52209885543Smrgstatic int
52309885543SmrgSMI_AddEncoding(XF86VideoEncodingPtr enc, int i,
52409885543Smrg		int norm, int input, int channel)
52509885543Smrg{
52609885543Smrg    char* norm_string;
52709885543Smrg    char* input_string;
52809885543Smrg    char channel_string[20];
52909885543Smrg
53009885543Smrg    ENTER_PROC("SMI_AddEncoding");
53109885543Smrg
53209885543Smrg    norm_string = VideoNorms[norm].name;
53309885543Smrg    input_string = VideoInputs[input].name;
53409885543Smrg    sprintf(channel_string, "%d", channel);
53509885543Smrg    enc[i].id     = i;
53609885543Smrg    enc[i].name   = xalloc(strlen(norm_string) +
53709885543Smrg			   strlen(input_string) +
53809885543Smrg			   strlen(channel_string)+3);
53909885543Smrg    if (NULL == enc[i].name) {
54009885543Smrg	LEAVE_PROC("SMI_AddEncoding");
54109885543Smrg	return -1;
54209885543Smrg    }
54309885543Smrg    enc[i].width  = VideoNorms[norm].Wa;
54409885543Smrg    enc[i].height = VideoNorms[norm].Ha;
54509885543Smrg    enc[i].rate   = VideoNorms[norm].rate;
54609885543Smrg    sprintf(enc[i].name,"%s-%s-%s", norm_string, input_string, channel_string);
54709885543Smrg
54809885543Smrg    LEAVE_PROC("SMI_AddEncoding");
54909885543Smrg    return 0;
55009885543Smrg}
55109885543Smrg
55209885543Smrg
55309885543Smrg/**
55409885543Smrg * builds XF86VideoEncodings with all legal combinations of video norm,
55509885543Smrg * video input format and video input channel
55609885543Smrg */
55709885543Smrgstatic void
55809885543SmrgSMI_BuildEncodings(SMI_PortPtr p)
55909885543Smrg{
56009885543Smrg    int ch, n;
56109885543Smrg
56209885543Smrg    ENTER_PROC("SMI_BuildEncodings");
56309885543Smrg
56409885543Smrg    /* allocate memory for encoding array */
56509885543Smrg    p->enc = xalloc(sizeof(XF86VideoEncodingRec) * N_ENCODINGS);
56609885543Smrg    if (NULL == p->enc)
56709885543Smrg	goto fail;
56809885543Smrg    memset(p->enc,0,sizeof(XF86VideoEncodingRec) * N_ENCODINGS);
56909885543Smrg    /* allocate memory for video norm array */
57009885543Smrg    p->norm = xalloc(sizeof(int) * N_ENCODINGS);
57109885543Smrg    if (NULL == p->norm)
57209885543Smrg	goto fail;
57309885543Smrg    memset(p->norm,0,sizeof(int) * N_ENCODINGS);
57409885543Smrg    /* allocate memory for video input format array */
57509885543Smrg    p->input = xalloc(sizeof(int) * N_ENCODINGS);
57609885543Smrg    if (NULL == p->input)
57709885543Smrg	goto fail;
57809885543Smrg    memset(p->input,0,sizeof(int) * N_ENCODINGS);
57909885543Smrg    /* allocate memory for video channel number array */
58009885543Smrg    p->channel = xalloc(sizeof(int) * N_ENCODINGS);
58109885543Smrg    if (NULL == p->channel)
58209885543Smrg	goto fail;
58309885543Smrg    memset(p->channel,0,sizeof(int) * N_ENCODINGS);
58409885543Smrg
58509885543Smrg    /* fill arrays */
58609885543Smrg    p->nenc = 0;
58709885543Smrg    for (ch = 0; ch < N_COMPOSITE_CHANNELS; ch++) {
58809885543Smrg	for (n = 0; n < N_VIDEO_NORMS; n++) {
58909885543Smrg	    SMI_AddEncoding(p->enc, p->nenc, n, VID_COMPOSITE, ch);
59009885543Smrg	    p->norm[p->nenc]  = n;
59109885543Smrg	    p->input[p->nenc] = VID_COMPOSITE;
59209885543Smrg	    p->channel[p->nenc] = ch;
59309885543Smrg	    p->nenc++;
59409885543Smrg	}
59509885543Smrg    }
59609885543Smrg    for (ch = 0; ch < N_SVIDEO_CHANNELS; ch++) {
59709885543Smrg	for (n = 0; n < N_VIDEO_NORMS; n++) {
59809885543Smrg	    SMI_AddEncoding(p->enc, p->nenc, n, VID_SVIDEO, ch);
59909885543Smrg	    p->norm[p->nenc]  = n;
60009885543Smrg	    p->input[p->nenc] = VID_SVIDEO;
60109885543Smrg	    p->channel[p->nenc] = ch;
60209885543Smrg	    p->nenc++;
60309885543Smrg	}
60409885543Smrg    }
60509885543Smrg    LEAVE_PROC("SMI_BuildEncodings");
60609885543Smrg    return;
60709885543Smrg
60809885543Smrg fail:
60909885543Smrg    if (p->input) xfree(p->input);
61009885543Smrg    p->input = NULL;
61109885543Smrg    if (p->norm) xfree(p->norm);
61209885543Smrg    p->norm = NULL;
61309885543Smrg    if (p->channel) xfree(p->channel);
61409885543Smrg    p->channel = NULL;
61509885543Smrg    if (p->enc) xfree(p->enc);
61609885543Smrg    p->enc = NULL;
61709885543Smrg    p->nenc = 0;
61809885543Smrg    LEAVE_PROC("SMI_BuildEncodings");
61909885543Smrg}
62009885543Smrg
62109885543Smrg
62209885543Smrg/******************************************************************************\
62309885543Smrg**                                                                            **
62409885543Smrg**                  X V E X T E N S I O N   I N T E R F A C E                 **
62509885543Smrg**                                                                            **
62609885543Smrg\******************************************************************************/
62709885543Smrg
62809885543Smrgvoid
62909885543SmrgSMI_InitVideo(ScreenPtr pScreen)
63009885543Smrg{
63109885543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
63209885543Smrg    SMIPtr psmi = SMIPTR(pScrn);
63309885543Smrg    XF86VideoAdaptorPtr *ptrAdaptors, *newAdaptors = NULL;
63409885543Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
63509885543Smrg    int numAdaptors;
63609885543Smrg
63709885543Smrg    ENTER_PROC("SMI_InitVideo");
63809885543Smrg
63909885543Smrg    numAdaptors = xf86XVListGenericAdaptors(pScrn, &ptrAdaptors);
64009885543Smrg
64109885543Smrg    DEBUG((VERBLEV, "numAdaptors=%d\n", numAdaptors));
64209885543Smrg
64309885543Smrg    if (psmi->rotate == 0)
64409885543Smrg    {
64509885543Smrg        newAdaptor = SMI_SetupVideo(pScreen);
64609885543Smrg        DEBUG((VERBLEV, "newAdaptor=%p\n", newAdaptor));
64709885543Smrg        SMI_InitOffscreenImages(pScreen);
64809885543Smrg    }
64909885543Smrg
65009885543Smrg    if (newAdaptor != NULL) {
65109885543Smrg        if (numAdaptors == 0) {
65209885543Smrg            numAdaptors = 1;
65309885543Smrg            ptrAdaptors = &newAdaptor;
65409885543Smrg        } else {
65509885543Smrg            newAdaptors = xalloc((numAdaptors + 1) *
65609885543Smrg                    sizeof(XF86VideoAdaptorPtr*));
65709885543Smrg            if (newAdaptors != NULL) {
65809885543Smrg                memcpy(newAdaptors, ptrAdaptors,
65909885543Smrg                        numAdaptors * sizeof(XF86VideoAdaptorPtr));
66009885543Smrg                newAdaptors[numAdaptors++] = newAdaptor;
66109885543Smrg                ptrAdaptors = newAdaptors;
66209885543Smrg            }
66309885543Smrg        }
66409885543Smrg    }
66509885543Smrg
66609885543Smrg    if (numAdaptors != 0) {
66709885543Smrg        DEBUG((VERBLEV, "ScreenInit %i\n",numAdaptors));
66809885543Smrg        xf86XVScreenInit(pScreen, ptrAdaptors, numAdaptors);
66909885543Smrg    }
67009885543Smrg
67109885543Smrg    if (newAdaptors != NULL) {
67209885543Smrg        xfree(newAdaptors);
67309885543Smrg    }
67409885543Smrg
67509885543Smrg    LEAVE_PROC("SMI_InitVideo");
67609885543Smrg}
67709885543Smrg
67809885543Smrg
67909885543Smrg/*************************************************************************/
68009885543Smrg
68109885543Smrg/*
68209885543Smrg *  Video codec controls
68309885543Smrg */
68409885543Smrg
68509885543Smrg#if 0
68609885543Smrg/**
68709885543Smrg * scales value value of attribute i to range min, max
68809885543Smrg */
68909885543Smrgstatic int
69009885543SmrgScale(int i, int value, int min, int max)
69109885543Smrg{
69209885543Smrg    return min + (value - SMI_VideoAttributes[i].min_value) * (max - min) /
69309885543Smrg	(SMI_VideoAttributes[i].max_value - SMI_VideoAttributes[i].min_value);
69409885543Smrg}
69509885543Smrg#endif
69609885543Smrg/**
69709885543Smrg * sets video decoder attributes channel, encoding, brightness, contrast, saturation, hue
69809885543Smrg */
69909885543Smrgstatic int
70009885543SmrgSetAttr(ScrnInfoPtr pScrn, int i, int value)
70109885543Smrg{
70209885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
70309885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
70409885543Smrg
70509885543Smrg    if (i < XV_ENCODING || i > XV_HUE)
70609885543Smrg	return BadMatch;
70709885543Smrg
70809885543Smrg    /* clamps value to attribute range */
70909885543Smrg    value = CLAMP(value, SMI_VideoAttributes[i].min_value,
71009885543Smrg		  SMI_VideoAttributes[i].max_value);
71109885543Smrg
71209885543Smrg    if (i == XV_BRIGHTNESS) {
71309885543Smrg	int my_value = (value <= 128? value + 128 : value - 128);
71409885543Smrg	SetKeyReg(pSmi, 0x5C, 0xEDEDED | (my_value << 24));
71509885543Smrg    } else if (pPort->I2CDev.SlaveAddr == SAA7110) {
71609885543Smrg	return SetAttrSAA7110(pScrn, i, value);
71709885543Smrg    } else if (pPort->I2CDev.SlaveAddr == SAA7111) {
71809885543Smrg	return SetAttrSAA7111(pScrn, i, value);
71909885543Smrg    }
72009885543Smrg#if 0
72109885543Smrg    else {
72209885543Smrg	return XvBadAlloc;
72309885543Smrg    }
72409885543Smrg#endif
72509885543Smrg
72609885543Smrg    return Success;
72709885543Smrg}
72809885543Smrg
72909885543Smrg
73009885543Smrg/**
73109885543Smrg * sets SAA7110 video decoder attributes channel, encoding, brightness, contrast, saturation, hue
73209885543Smrg */
73309885543Smrgstatic int
73409885543SmrgSetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value)
73509885543Smrg{
73609885543Smrg    /* not supported */
73709885543Smrg    return XvBadAlloc;
73809885543Smrg}
73909885543Smrg
74009885543Smrg
74109885543Smrg/**
74209885543Smrg * sets SAA7111 video decoder attributes channel, encoding,
74309885543Smrg * brightness, contrast, saturation, hue
74409885543Smrg */
74509885543Smrgstatic int
74609885543SmrgSetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value)
74709885543Smrg{
74809885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
74909885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
75009885543Smrg
75109885543Smrg    if (i == XV_ENCODING) {
75209885543Smrg	int norm;
75309885543Smrg	int input;
75409885543Smrg	int channel;
75509885543Smrg	norm = pPort->norm[value];
75609885543Smrg	input = pPort->input[value];
75709885543Smrg	channel = pPort->channel[value];
75809885543Smrg
75909885543Smrg	DEBUG((VERBLEV, "SetAttribute XV_ENCODING: %d. norm=%d input=%d channel=%d\n",
76009885543Smrg	       value, norm, input, channel));
76109885543Smrg
76209885543Smrg	/* set video norm */
76309885543Smrg	if (!xf86I2CWriteVec(&(pPort->I2CDev), SAA7111VideoStd[norm],
76409885543Smrg			     ENTRIES(SAA7111VideoStd[norm]) / 2)) {
76509885543Smrg	    return XvBadAlloc;
76609885543Smrg	}
76709885543Smrg	/* set video input format and channel */
76809885543Smrg	if (input == VID_COMPOSITE) {
76909885543Smrg	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
77009885543Smrg				 SAA7111CompositeChannelSelect[channel],
77109885543Smrg				 ENTRIES(SAA7111CompositeChannelSelect[channel]) / 2)) {
77209885543Smrg		return XvBadAlloc;
77309885543Smrg	    }
77409885543Smrg	} else {
77509885543Smrg	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
77609885543Smrg				 SAA7111SVideoChannelSelect[channel],
77709885543Smrg				 ENTRIES(SAA7111SVideoChannelSelect[channel]) / 2)) {
77809885543Smrg		return XvBadAlloc;
77909885543Smrg	    }
78009885543Smrg	}
78109885543Smrg    } else if (i >= XV_CAPTURE_BRIGHTNESS && i <= XV_HUE) {
78209885543Smrg	int slave_adr = 0;
78309885543Smrg
78409885543Smrg	switch (i) {
78509885543Smrg
78609885543Smrg	case XV_CAPTURE_BRIGHTNESS:
78709885543Smrg	    DEBUG((VERBLEV, "SetAttribute XV_BRIGHTNESS: %d\n", value));
78809885543Smrg	    slave_adr = 0x0a;
78909885543Smrg	    break;
79009885543Smrg
79109885543Smrg	case XV_CONTRAST:
79209885543Smrg	    DEBUG((VERBLEV, "SetAttribute XV_CONTRAST: %d\n", value));
79309885543Smrg	    slave_adr = 0x0b;
79409885543Smrg	    break;
79509885543Smrg
79609885543Smrg	case XV_SATURATION:
79709885543Smrg	    DEBUG((VERBLEV, "SetAttribute XV_SATURATION: %d\n", value));
79809885543Smrg	    slave_adr = 0x0c;
79909885543Smrg	    break;
80009885543Smrg
80109885543Smrg	case XV_HUE:
80209885543Smrg	    DEBUG((VERBLEV, "SetAttribute XV_HUE: %d\n", value));
80309885543Smrg	    slave_adr = 0x0d;
80409885543Smrg	    break;
80509885543Smrg
80609885543Smrg	default:
80709885543Smrg	    return XvBadAlloc;
80809885543Smrg	}
80909885543Smrg	if (!xf86I2CWriteByte(&(pPort->I2CDev), slave_adr, (value & 0xff)))
81009885543Smrg	    return XvBadAlloc;
81109885543Smrg    } else {
81209885543Smrg	return BadMatch;
81309885543Smrg    }
81409885543Smrg
81509885543Smrg    /* debug: show registers */
81609885543Smrg    {
81709885543Smrg	I2CByte i2c_bytes[32];
81809885543Smrg	int i;
81909885543Smrg	xf86I2CReadBytes(&(pPort->I2CDev), 0, i2c_bytes, 32);
82009885543Smrg	DEBUG((VERBLEV, "SAA7111 Registers\n"));
82109885543Smrg	for (i=0; i<32; i++) {
82209885543Smrg	    DEBUG((VERBLEV, "%02X=%02X ", i, i2c_bytes[i]));
82309885543Smrg	    if ((i&7) == 7) DEBUG((VERBLEV, "\n"));
82409885543Smrg	}
82509885543Smrg    }
82609885543Smrg
82709885543Smrg    return Success;
82809885543Smrg}
82909885543Smrg
83009885543Smrg
83109885543Smrg/******************************************************************************\
83209885543Smrg**									      **
83309885543Smrg**	V I D E O   M A N A G E M E N T					      **
83409885543Smrg**									      **
83509885543Smrg\******************************************************************************/
83609885543Smrg
83709885543Smrgstatic XF86VideoAdaptorPtr
83809885543SmrgSMI_SetupVideo(ScreenPtr pScreen)
83909885543Smrg{
84009885543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
84109885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
84209885543Smrg    SMI_PortPtr smiPortPtr;
84309885543Smrg    XF86VideoAdaptorPtr ptrAdaptor;
84409885543Smrg
84509885543Smrg    ENTER_PROC("SMI_SetupVideo");
84609885543Smrg
84709885543Smrg    ptrAdaptor = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
84809885543Smrg		 sizeof(DevUnion) + sizeof(SMI_PortRec));
84909885543Smrg    if (ptrAdaptor == NULL) {
85009885543Smrg	LEAVE_PROC("SMI_SetupVideo");
85109885543Smrg	return NULL;
85209885543Smrg    }
85309885543Smrg
85409885543Smrg    ptrAdaptor->type = XvInputMask
85509885543Smrg#if SMI_USE_CAPTURE
85609885543Smrg		     | XvOutputMask
85709885543Smrg		     | XvVideoMask
85809885543Smrg#endif
85909885543Smrg		     | XvImageMask
86009885543Smrg		     | XvWindowMask
86109885543Smrg		     ;
86209885543Smrg
86309885543Smrg    ptrAdaptor->flags = VIDEO_OVERLAID_IMAGES
86409885543Smrg		      | VIDEO_CLIP_TO_VIEWPORT
86509885543Smrg		      ;
86609885543Smrg
86709885543Smrg    ptrAdaptor->name = "Silicon Motion Lynx Series Video Engine";
86809885543Smrg
86909885543Smrg    ptrAdaptor->nPorts = 1;
87009885543Smrg    ptrAdaptor->pPortPrivates = (DevUnion*) &ptrAdaptor[1];
87109885543Smrg    ptrAdaptor->pPortPrivates[0].ptr = (pointer) &ptrAdaptor->pPortPrivates[1];
87209885543Smrg
87309885543Smrg    smiPortPtr = (SMI_PortPtr) ptrAdaptor->pPortPrivates[0].ptr;
87409885543Smrg
87509885543Smrg    SMI_BuildEncodings(smiPortPtr);
87609885543Smrg    ptrAdaptor->nEncodings = smiPortPtr->nenc;
87709885543Smrg    ptrAdaptor->pEncodings = smiPortPtr->enc;
87809885543Smrg#if 0
87909885543Smrg    /* aaa whats this? */
88009885543Smrg	for (i = 0; i < nElems(SMI_VideoEncodings); i++)
88109885543Smrg	{
88209885543Smrg		SMI_VideoEncodings[i].width = pSmi->lcdWidth;
88309885543Smrg		SMI_VideoEncodings[i].height = pSmi->lcdHeight;
88409885543Smrg	}
88509885543Smrg#endif
88609885543Smrg
88709885543Smrg    ptrAdaptor->nFormats = nElems(SMI_VideoFormats);
88809885543Smrg    ptrAdaptor->pFormats = SMI_VideoFormats;
88909885543Smrg
89009885543Smrg    ptrAdaptor->nAttributes = nElems(SMI_VideoAttributes);
89109885543Smrg    ptrAdaptor->pAttributes = SMI_VideoAttributes;
89209885543Smrg
89309885543Smrg    ptrAdaptor->nImages = nElems(SMI_VideoImages);
89409885543Smrg    ptrAdaptor->pImages = SMI_VideoImages;
89509885543Smrg
89609885543Smrg#if SMI_USE_CAPTURE
89709885543Smrg    if (pSmi->Chipset == SMI_COUGAR3DR)
89809885543Smrg	ptrAdaptor->PutVideo = NULL;
89909885543Smrg    else
90009885543Smrg	ptrAdaptor->PutVideo = SMI_PutVideo;
90109885543Smrg    ptrAdaptor->PutStill = NULL;
90209885543Smrg    ptrAdaptor->GetVideo = NULL;
90309885543Smrg    ptrAdaptor->GetStill = NULL;
90409885543Smrg#else
90509885543Smrg    ptrAdaptor->PutVideo = NULL;
90609885543Smrg    ptrAdaptor->PutStill = NULL;
90709885543Smrg    ptrAdaptor->GetVideo = NULL;
90809885543Smrg    ptrAdaptor->GetStill = NULL;
90909885543Smrg#endif
91009885543Smrg    ptrAdaptor->StopVideo = SMI_StopVideo;
91109885543Smrg    ptrAdaptor->SetPortAttribute = SMI_SetPortAttribute;
91209885543Smrg    ptrAdaptor->GetPortAttribute = SMI_GetPortAttribute;
91309885543Smrg    ptrAdaptor->QueryBestSize = SMI_QueryBestSize;
91409885543Smrg    ptrAdaptor->PutImage = SMI_PutImage;
91509885543Smrg    ptrAdaptor->QueryImageAttributes = SMI_QueryImageAttributes;
91609885543Smrg
91709885543Smrg    smiPortPtr->Attribute[XV_COLORKEY] = pSmi->videoKey;
91809885543Smrg    smiPortPtr->Attribute[XV_INTERLACED] = pSmi->interlaced;
91909885543Smrg    smiPortPtr->videoStatus = 0;
92009885543Smrg
92109885543Smrg#if 0
92209885543Smrg    /* aaa does not work ? */
92309885543Smrg    if (xf86I2CProbeAddress(pSmi->I2C, SAA7111))
92409885543Smrg    {
92509885543Smrg        LEAVE_PROC("SMI_SetupVideo");
92609885543Smrg        return(NULL);
92709885543Smrg    }
92809885543Smrg    DEBUG((VERBLEV, "SAA7111 detected\n"));
92909885543Smrg#endif
93009885543Smrg
93109885543Smrg    smiPortPtr->I2CDev.DevName = "SAA 7111A";
93209885543Smrg    smiPortPtr->I2CDev.SlaveAddr = SAA7111;
93309885543Smrg    smiPortPtr->I2CDev.pI2CBus = pSmi->I2C;
93409885543Smrg
93509885543Smrg
93609885543Smrg    if (xf86I2CDevInit(&(smiPortPtr->I2CDev))) {
93709885543Smrg
93809885543Smrg	if (xf86I2CWriteVec(&(smiPortPtr->I2CDev), SAA7111InitData, ENTRIES(SAA7111InitData) / 2)) {
93909885543Smrg	    xvEncoding   = MAKE_ATOM(XV_ENCODING_NAME);
94009885543Smrg	    xvHue        = MAKE_ATOM(XV_HUE_NAME);
94109885543Smrg	    xvSaturation = MAKE_ATOM(XV_SATURATION_NAME);
94209885543Smrg	    xvContrast   = MAKE_ATOM(XV_CONTRAST_NAME);
94309885543Smrg
94409885543Smrg	    xvInterlaced = MAKE_ATOM(XV_INTERLACED_NAME);
94509885543Smrg	    DEBUG((VERBLEV, "SAA7111 intialized\n"));
94609885543Smrg
94709885543Smrg	} else {
94809885543Smrg	    xf86DestroyI2CDevRec(&(smiPortPtr->I2CDev),FALSE);
94909885543Smrg	    smiPortPtr->I2CDev.SlaveAddr = 0;
95009885543Smrg	}
95109885543Smrg    } else
95209885543Smrg	smiPortPtr->I2CDev.SlaveAddr = 0;
95309885543Smrg
95409885543Smrg#if defined(REGION_NULL)
95509885543Smrg    REGION_NULL(pScreen, &smiPortPtr->clip);
95609885543Smrg#else
95709885543Smrg    REGION_INIT(pScreen, &smiPortPtr->clip, NullBox, 0);
95809885543Smrg#endif
95909885543Smrg
96009885543Smrg    pSmi->ptrAdaptor = ptrAdaptor;
96109885543Smrg    pSmi->BlockHandler = pScreen->BlockHandler;
96209885543Smrg    pScreen->BlockHandler = SMI_BlockHandler;
96309885543Smrg
96409885543Smrg    xvColorKey   = MAKE_ATOM(XV_COLORKEY_NAME);
96509885543Smrg    xvBrightness = MAKE_ATOM(XV_BRIGHTNESS_NAME);
96609885543Smrg    xvCapBrightness = MAKE_ATOM(XV_CAPTURE_BRIGHTNESS_NAME);
96709885543Smrg
96809885543Smrg    SMI_ResetVideo(pScrn);
96909885543Smrg    LEAVE_PROC("SMI_SetupVideo");
97009885543Smrg    return ptrAdaptor;
97109885543Smrg}
97209885543Smrg
97309885543Smrg
97409885543Smrgstatic void
97509885543SmrgSMI_ResetVideo(ScrnInfoPtr pScrn)
97609885543Smrg{
97709885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
97809885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
97909885543Smrg    int r, g, b;
98009885543Smrg
98109885543Smrg    ENTER_PROC("SMI_ResetVideo");
98209885543Smrg
98309885543Smrg    SetAttr(pScrn, XV_ENCODING, 0);     /* Encoding = pal-composite-0 */
98409885543Smrg    SetAttr(pScrn, XV_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
98509885543Smrg    SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
98609885543Smrg    SetAttr(pScrn, XV_CONTRAST, 71);    /* Contrast = 71 (CCIR level) */
98709885543Smrg    SetAttr(pScrn, XV_SATURATION, 64);  /* Color saturation = 64 (CCIR level) */
98809885543Smrg    SetAttr(pScrn, XV_HUE, 0);          /* Hue = 0 */
98909885543Smrg
99009885543Smrg    switch (pScrn->depth) {
99109885543Smrg    case 8:
99209885543Smrg	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0x00FF);
99309885543Smrg	SetKeyReg(pSmi, FPR08, 0);
99409885543Smrg	break;
99509885543Smrg    case 15:
99609885543Smrg    case 16:
99709885543Smrg	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0xFFFF);
99809885543Smrg	SetKeyReg(pSmi, FPR08, 0);
99909885543Smrg	break;
100009885543Smrg    default:
100109885543Smrg        r = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.red) >> pScrn->offset.red;
100209885543Smrg        g = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.green) >> pScrn->offset.green;
100309885543Smrg        b = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.blue) >> pScrn->offset.blue;
100409885543Smrg	SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
100509885543Smrg	SetKeyReg(pSmi, FPR08, 0);
100609885543Smrg	break;
100709885543Smrg    }
100809885543Smrg
100909885543Smrg    SetKeyReg(pSmi, FPR5C, 0xEDEDED | (pPort->Attribute[XV_BRIGHTNESS] << 24));
101009885543Smrg
101109885543Smrg    LEAVE_PROC("SMI_ResetVideo");
101209885543Smrg}
101309885543Smrg
101409885543Smrg
101509885543Smrg#if SMI_USE_CAPTURE
101609885543Smrgstatic int
101709885543SmrgSMI_PutVideo(
101809885543Smrg	ScrnInfoPtr	pScrn,
101909885543Smrg	short		vid_x,
102009885543Smrg	short		vid_y,
102109885543Smrg	short		drw_x,
102209885543Smrg	short		drw_y,
102309885543Smrg	short		vid_w,
102409885543Smrg	short		vid_h,
102509885543Smrg	short		drw_w,
102609885543Smrg	short		drw_h,
102709885543Smrg	RegionPtr	clipBoxes,
102809885543Smrg	pointer		data,
102909885543Smrg	DrawablePtr	pDraw
103009885543Smrg)
103109885543Smrg{
103209885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) data;
103309885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
103409885543Smrg    CARD32 vid_pitch, vid_address;
103509885543Smrg    CARD32 vpr00, cpr00;
103609885543Smrg    int xscale, yscale;
103709885543Smrg    BoxRec dstBox;
103809885543Smrg    INT32 x1, y1, x2, y2;
103909885543Smrg    int norm;
104009885543Smrg    int size, width, height, fbPitch;
104109885543Smrg    int top, left;
104209885543Smrg
104309885543Smrg    ENTER_PROC("SMI_PutVideo");
104409885543Smrg
104509885543Smrg    DEBUG((VERBLEV, "Interlaced Video %d\n", pPort->Attribute[XV_INTERLACED]));
104609885543Smrg
104709885543Smrg    if (!pPort->Attribute[XV_INTERLACED]) {
104809885543Smrg	/* no interlace: lines will be doubled */
104909885543Smrg	vid_h /= 2;
105009885543Smrg    }
105109885543Smrg
105209885543Smrg    /* field start aaa*/
105309885543Smrg    norm = pPort->norm[pPort->Attribute[XV_ENCODING]];
105409885543Smrg    vid_x += VideoNorms[norm].HStart;
105509885543Smrg    vid_y += VideoNorms[norm].VStart;
105609885543Smrg    /* only even values allowed (UV-phase) */
105709885543Smrg    vid_x &= ~1;
105809885543Smrg
105909885543Smrg    DEBUG((VERBLEV, "vid_x=%d vid_y=%d drw_x=%d drw_y=%d  "
106009885543Smrg	   "vid_w=%d vid_h=%d drw_w=%d drw_h=%d\n",
106109885543Smrg	   vid_x, vid_y, drw_x, drw_y, vid_w, vid_h, drw_w, drw_h));
106209885543Smrg
106309885543Smrg    x1 = vid_x;
106409885543Smrg    y1 = vid_y;
106509885543Smrg    x2 = vid_x + vid_w;
106609885543Smrg    y2 = vid_y + vid_h;
106709885543Smrg
106809885543Smrg    width = vid_w;
106909885543Smrg    height = vid_h;
107009885543Smrg
107109885543Smrg    dstBox.x1 = drw_x;
107209885543Smrg    dstBox.y1 = drw_y;
107309885543Smrg    dstBox.x2 = drw_x + drw_w;
107409885543Smrg    dstBox.y2 = drw_y + drw_h;
107509885543Smrg
107609885543Smrg#if 1
107709885543Smrg    if (!SMI_ClipVideo(pScrn, &dstBox, &x1, &y1, &x2, &y2, clipBoxes, width, height)) {
107809885543Smrg#else
107909885543Smrg    if (!xf86XVClipVideoHelper(&dstBox, &x1, &y1, &x2, &y2, clipBoxes, width, height)) {
108009885543Smrg#endif
108109885543Smrg        LEAVE_PROC("SMI_PutVideo");
108209885543Smrg	return Success;
108309885543Smrg    }
108409885543Smrg
108509885543Smrg    DEBUG((VERBLEV, "Clip: x1=%d y1=%d x2=%d y2=%d\n",  x1 >> 16, y1 >> 16, x2 >> 16, y2 >> 16));
108609885543Smrg
108709885543Smrg    dstBox.x1 -= pScrn->frameX0;
108809885543Smrg    dstBox.y1 -= pScrn->frameY0;
108909885543Smrg    dstBox.x2 -= pScrn->frameX0;
109009885543Smrg    dstBox.y2 -= pScrn->frameY0;
109109885543Smrg
109209885543Smrg    vid_pitch = (vid_w * 2 + 7) & ~7;
109309885543Smrg
109409885543Smrg    vpr00 = READ_VPR(pSmi, 0x00) & ~0x0FF000FF;
109509885543Smrg    cpr00 = READ_CPR(pSmi, 0x00) & ~0x000FFF00;
109609885543Smrg
109709885543Smrg    /* vpr00:
109809885543Smrg       Bit 2..0   = 6: Video Window I Format                    = YUV4:2:2
109909885543Smrg       Bit 3      = 1: Video Window I Enable                    = enabled
110009885543Smrg       Bit 4      = 0: Video Window I YUV Averaging             = disabled
110109885543Smrg       Bit 5      = 0: Video Window I Hor. Replication          = disabled
110209885543Smrg       Bit 6      = 0: Video Window I data doubling             = disabled
110309885543Smrg       Bit 14..8  = 0: Video Window II                          = disabled
110409885543Smrg       Bit 18..16 = 0: Graphics Data Format                     = 8-bit index
110509885543Smrg       Bit 19     = 0: Top Video Window Select                  = window I
110609885543Smrg       Bit 20     = 1: Color Key for Window I                   = enabled
110709885543Smrg       Bit 21     = 0: Vertical Interpolation                   = s. below
110809885543Smrg       Bit 22     = 0: Flicker Reduction for TV Modes           = disabled
110909885543Smrg       Bit 23     = 0: Fixed Vertical Interpolation             = disabled
111009885543Smrg       Bit 24     = 1: Select Video Window I Source Addr        =
111109885543Smrg       Bit 25     = 0: Enable V0FIFO to fetch 8-Bit color data  = disabled
111209885543Smrg       Bit 26     = 0:
111309885543Smrg       Bit 27     = 1: Color Key for Window II                  = disabled
111409885543Smrg       Bit 31..28 = reserved
111509885543Smrg    */
111609885543Smrg    if (pPort->Attribute[XV_INTERLACED]) {
111709885543Smrg	/*
111809885543Smrg	  Bit 21     = 0: Vertical Interpolation                   = disabled
111909885543Smrg	  Bit 24     = 0: Select Video Window I Source Addr        = 0
112009885543Smrg	*/
112109885543Smrg	vpr00 |= 0x0010000E;
112209885543Smrg    } else {
112309885543Smrg	/*
112409885543Smrg	  Bit 21     = 10: Vertical Interpolation                   = enabled
112509885543Smrg	  Bit 24     = 1: Select Video Window I Source Addr        = 1
112609885543Smrg	  1= Video window I source addr = capture port buffer ?
112709885543Smrg	*/
112809885543Smrg	vpr00 |= 0x0130000E;
112909885543Smrg    }
113009885543Smrg
113109885543Smrg    /* cpr00:
113209885543Smrg       Bit 0      = 1: Video Capture Enable                     = enabled
113309885543Smrg       Bit 8      = 0: Capture Control                          = continous
113409885543Smrg       Bit 9      = 0: Double Buffer Enable                     = s. below
113509885543Smrg       Bit 10     = 0: Interlace Data Capture                   = s. below
113609885543Smrg       Bit 13..11 = 0: Frame Skip Enable                        = s. below
113709885543Smrg       Bit 15..14 = 0: Video Capture Input Format               = YUV4:2:2
113809885543Smrg       Bit 17..16 = 0: Enable Hor. Reduction                    = s. below
113909885543Smrg       Bit 19..18 = 0: Enable Vert. Reduction                   = s. below
114009885543Smrg       Bit 21..20 = 0: Enable Hor. Filtering                    = s. below
114109885543Smrg       Bit 22     = 0: HREF Polarity                            = high active
114209885543Smrg       Bit 23     = 0: VREF Polarity                            = high active
114309885543Smrg       Bit 24     = 1: Field Detection Method VSYNC edge        = rising
114409885543Smrg    */
114509885543Smrg    if (pPort->Attribute[XV_INTERLACED]) {
114609885543Smrg	/*
114709885543Smrg	  Bit 9      = 1: Double Buffer Enable                  = enabled
114809885543Smrg	  Bit 10     = 1: Interlace Data Capture                = enabled
114909885543Smrg	  Bit 13..11 = 0: Frame Skip Enable                     = no skip
115009885543Smrg	*/
115109885543Smrg	cpr00 |= 0x01000601;
115209885543Smrg    } else {
115309885543Smrg	/*
115409885543Smrg	  Bit 9      = 0: Double Buffer Enable                  = disabled
115509885543Smrg	  Bit 10     = 0: Interlace Data Capture                = disabled
115609885543Smrg	  Bit 13..11 = 010: Frame Skip Enable                   = skip every other frame
115709885543Smrg	*/
115809885543Smrg	cpr00 |= 0x01000801;
115909885543Smrg    }
116009885543Smrg
116109885543Smrg    if (pSmi->ByteSwap)
116209885543Smrg	cpr00 |= 0x00004000;
116309885543Smrg
116409885543Smrg    fbPitch = pSmi->Stride;
116509885543Smrg    if (pSmi->Bpp != 3) {
116609885543Smrg	fbPitch *= pSmi->Bpp;
116709885543Smrg    }
116809885543Smrg
116909885543Smrg    if (vid_w <= drw_w) {
117009885543Smrg	xscale = (256 * vid_w / drw_w) & 0xFF;
117109885543Smrg    } else if (vid_w / 2 <= drw_w) {
117209885543Smrg	xscale = (128 * vid_w / drw_w) & 0xFF;
117309885543Smrg	width /= 2;
117409885543Smrg	vid_pitch /= 2;
117509885543Smrg	cpr00 |= 0x00010000;
117609885543Smrg    } else if (vid_w / 4 <= drw_w) {
117709885543Smrg	xscale = (64 * vid_w / drw_w) & 0xFF;
117809885543Smrg	width /= 4;
117909885543Smrg	vid_pitch /= 4;
118009885543Smrg	cpr00 |= 0x00020000;
118109885543Smrg    } else {
118209885543Smrg	xscale = 0;
118309885543Smrg	width /= 4;
118409885543Smrg	vid_pitch /= 4;
118509885543Smrg	cpr00 |= 0x00020000;
118609885543Smrg    }
118709885543Smrg
118809885543Smrg    if (vid_h <= drw_h) {
118909885543Smrg	yscale = (256 * vid_h / drw_h) & 0xFF;
119009885543Smrg    } else if (vid_h / 2 <= drw_h) {
119109885543Smrg	yscale = (128 * vid_h / drw_h) & 0xFF;
119209885543Smrg	height /= 2;
119309885543Smrg	cpr00 |= 0x00040000;
119409885543Smrg    } else if (vid_h / 4 <= drw_h) {
119509885543Smrg	yscale = (64 * vid_h / drw_h) & 0xFF;
119609885543Smrg	height /= 4;
119709885543Smrg	cpr00 |= 0x00080000;
119809885543Smrg    } else {
119909885543Smrg	yscale = 0;
120009885543Smrg	height /= 4;
120109885543Smrg	cpr00 |= 0x00080000;
120209885543Smrg    }
120309885543Smrg
120409885543Smrg    do {
120509885543Smrg	size = vid_pitch * height;
120609885543Smrg	DEBUG((VERBLEV, "SMI_AllocateMemory: vid_pitch=%d height=%d size=%d\n",
120709885543Smrg		vid_pitch, height, size));
120809885543Smrg	pPort->video_offset = SMI_AllocateMemory(pScrn, &pPort->video_memory, size);
120909885543Smrg        if (pPort->video_offset == 0) {
121009885543Smrg	    if ((cpr00 & 0x000C0000) == 0) {
121109885543Smrg		/* height -> 1/2 height */
121209885543Smrg		yscale = (128 * vid_h / drw_h) & 0xFF;
121309885543Smrg		height = vid_h / 2;
121409885543Smrg		cpr00 |= 0x00040000;
121509885543Smrg	    } else if (cpr00 & 0x00040000) {
121609885543Smrg		/* 1/2 height -> 1/4 height */
121709885543Smrg		yscale = (64 * vid_h / drw_h) & 0xFF;
121809885543Smrg		height = vid_h / 4;
121909885543Smrg		cpr00 ^= 0x000C0000;
122009885543Smrg	    } else {
122109885543Smrg		/* 1/4 height */
122209885543Smrg		if ((cpr00 & 0x00030000) == 0) {
122309885543Smrg		    /* width -> 1/2 width */
122409885543Smrg		    xscale = (128 * vid_w / drw_w) & 0xFF;
122509885543Smrg		    width = vid_w / 2;
122609885543Smrg		    cpr00 |= 0x00010000;
122709885543Smrg		} else if (cpr00 & 0x00010000) {
122809885543Smrg		    /* 1/2 width -> 1/4 width */
122909885543Smrg		    xscale = (64 * vid_w / drw_w) & 0xFF;
123009885543Smrg		    width = vid_w / 4;
123109885543Smrg		    cpr00 ^= 0x00030000;
123209885543Smrg		} else {
123309885543Smrg		    DEBUG((VERBLEV, "allocate error\n"));
123409885543Smrg                    LEAVE_PROC("SMI_PutVideo");
123509885543Smrg		    return BadAlloc;
123609885543Smrg		}
123709885543Smrg	    }
123809885543Smrg	}
123909885543Smrg    } while (pPort->video_offset == 0);
124009885543Smrg
124109885543Smrg    DEBUG((VERBLEV, "xscale==%d yscale=%d width=%d height=%d\n",
124209885543Smrg	   xscale, yscale, width, height));
124309885543Smrg
124409885543Smrg    /* aaa whats this                     ----------------------v ?
124509885543Smrg    vid_address = (pPort->area->box.y1 * fbPitch) + ((y1 >> 16) * vid_pitch);*/
124609885543Smrg    vid_address = pPort->video_offset;
124709885543Smrg
124809885543Smrg    DEBUG((VERBLEV, "test RegionsEqual\n"));
124909885543Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,0,0)
125009885543Smrg    if (!RegionsEqual(&pPort->clip, clipBoxes))
125109885543Smrg#else
125209885543Smrg    if (!REGION_EQUAL(pScrn->pScreen, &pPort->clip, clipBoxes))
125309885543Smrg#endif
125409885543Smrg    {
125509885543Smrg	DEBUG((VERBLEV, "RegionCopy\n"));
125609885543Smrg        REGION_COPY(pScrn->pScreen, &pPort->clip, clipBoxes);
125709885543Smrg	DEBUG((VERBLEV, "FillKey\n"));
125809885543Smrg	xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY], clipBoxes);
125909885543Smrg
126009885543Smrg    }
126109885543Smrg
126209885543Smrg    left = x1 >> 16;
126309885543Smrg    top = y1 >> 16;
126409885543Smrg    width = (x2 - x1) >> 16;
126509885543Smrg    height = (y2 - y1) >> 16;
126609885543Smrg
126709885543Smrg    OUT_SEQ(pSmi, 0x21, IN_SEQ(pSmi, 0x21) & ~0x04);
126809885543Smrg    WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) | 0x00200000);
126909885543Smrg#if 0
127009885543Smrg	SMI_WaitForSync(pScrn);
127109885543Smrg#endif
127209885543Smrg    /* Video Window I Left and Top Boundaries */
127309885543Smrg    WRITE_VPR(pSmi, 0x14, dstBox.x1 + (dstBox.y1 << 16));
127409885543Smrg    /* Video Window I Right and Bottom Boundaries */
127509885543Smrg    WRITE_VPR(pSmi, 0x18, dstBox.x2 + (dstBox.y2 << 16));
127609885543Smrg    /* Video Window I Source Width and Offset */
127709885543Smrg    WRITE_VPR(pSmi, 0x20, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
127809885543Smrg    /* Video Window I Stretch Factor */
127909885543Smrg    WRITE_VPR(pSmi, 0x24, (xscale << 8) + yscale);
128009885543Smrg
128109885543Smrg    if (pPort->Attribute[XV_INTERLACED]) {
128209885543Smrg	/* Video Window II Left and Top Boundaries */
128309885543Smrg	WRITE_VPR(pSmi, 0x28, dstBox.x1 + (dstBox.y1 << 16));
128409885543Smrg	/* Video Window II Right and Bottom Boundaries */
128509885543Smrg	WRITE_VPR(pSmi, 0x2C, dstBox.x2 + (dstBox.y2 << 16));
128609885543Smrg	/* Video Window II Source Width and Offset */
128709885543Smrg	WRITE_VPR(pSmi, 0x34, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
128809885543Smrg	/* Video Window II Stretch Factor */
128909885543Smrg	WRITE_VPR(pSmi, 0x38, (xscale << 8) + yscale);
129009885543Smrg
129109885543Smrg	/* Video Window I Source Start Address */
129209885543Smrg	WRITE_VPR(pSmi, 0x1C, vid_address / 8);
129309885543Smrg	/* Video Window II Source Start Address */
129409885543Smrg	WRITE_VPR(pSmi, 0x30, vid_address / 8);
129509885543Smrg
129609885543Smrg	/* Video Window I Source Start Address */
129709885543Smrg	WRITE_VPR(pSmi, 0x48, vid_address / 8);
129809885543Smrg	/* Video Window II Source Start Address */
129909885543Smrg	WRITE_VPR(pSmi, 0x4C, vid_address / 8 + vid_pitch / 8);
130009885543Smrg
130109885543Smrg	/* Video Source Clipping Control */
130209885543Smrg	WRITE_CPR(pSmi, 0x04, left + ((top/2) << 16));
130309885543Smrg	/* Video Source Capture Size Control */
130409885543Smrg	WRITE_CPR(pSmi, 0x08, width + ((height/2) << 16));
130509885543Smrg	/* Capture Port Buffer I Source Start Address */
130609885543Smrg	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
130709885543Smrg	/* Capture Port Buffer II Source Start Address */
130809885543Smrg	WRITE_CPR(pSmi, 0x10, vid_address / 8 + vid_pitch / 8);
130909885543Smrg	/* Capture Port Source Offset Address */
131009885543Smrg	WRITE_CPR(pSmi, 0x14, 2*(vid_pitch / 8) + ((2*(vid_pitch / 8)) << 16));
131109885543Smrg    } else {
131209885543Smrg	/* Video Source Clipping Control */
131309885543Smrg	WRITE_CPR(pSmi, 0x04, left + (top << 16));
131409885543Smrg	/* Video Source Capture Size Control */
131509885543Smrg	WRITE_CPR(pSmi, 0x08, width + (height << 16));
131609885543Smrg	/* Capture Port Buffer I Source Start Address */
131709885543Smrg	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
131809885543Smrg	/* Capture Port Buffer II Source Start Address */
131909885543Smrg	WRITE_CPR(pSmi, 0x10, vid_address / 8);
132009885543Smrg	/* Capture Port Source Offset Address */
132109885543Smrg	WRITE_CPR(pSmi, 0x14, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
132209885543Smrg    }
132309885543Smrg
132409885543Smrg    WRITE_CPR(pSmi, 0x00, cpr00);
132509885543Smrg    WRITE_VPR(pSmi, 0x00, vpr00);
132609885543Smrg
132709885543Smrg    pPort->videoStatus = CLIENT_VIDEO_ON;
132809885543Smrg    DEBUG((VERBLEV, "SMI_PutVideo success\n"));
132909885543Smrg    LEAVE_PROC("SMI_PutVideo");
133009885543Smrg    return Success;
133109885543Smrg}
133209885543Smrg#endif
133309885543Smrg
133409885543Smrg
133509885543Smrgstatic void
133609885543SmrgSMI_StopVideo(
133709885543Smrg	ScrnInfoPtr	pScrn,
133809885543Smrg	pointer		data,
133909885543Smrg	Bool		shutdown
134009885543Smrg)
134109885543Smrg{
134209885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) data;
134309885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
134409885543Smrg
134509885543Smrg    ENTER_PROC("SMI_StopVideo");
134609885543Smrg
134709885543Smrg    REGION_EMPTY(pScrn->pScreen, &pPort->clip);
134809885543Smrg
134909885543Smrg    if (shutdown) {
135009885543Smrg	if (pPort->videoStatus & CLIENT_VIDEO_ON) {
135109885543Smrg	    if (pSmi->Chipset == SMI_COUGAR3DR) {
135209885543Smrg		WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
135309885543Smrg	    } else {
135409885543Smrg		WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x01000008);
135509885543Smrg	    }
135609885543Smrg#if SMI_USE_CAPTURE
135709885543Smrg	    if (pSmi->Chipset != SMI_COUGAR3DR) {
135809885543Smrg		WRITE_CPR(pSmi, 0x00, READ_CPR(pSmi, 0x00) & ~0x00000001);
135909885543Smrg		WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) & ~0x00F00000);
136009885543Smrg	    }
136109885543Smrg/* #864		OUT_SEQ(pSmi, 0x21, IN_SEQ(pSmi, 0x21) | 0x04); */
136209885543Smrg#endif
136309885543Smrg	}
136409885543Smrg        if (pPort->video_memory != NULL) {
136509885543Smrg            SMI_FreeMemory(pScrn, pPort->video_memory);
136609885543Smrg            pPort->video_memory = NULL;
136709885543Smrg	}
136809885543Smrg        pPort->videoStatus = 0;
136909885543Smrg        /* pPort->i2cDevice = 0;aaa*/
137009885543Smrg    } else {
137109885543Smrg        if (pPort->videoStatus & CLIENT_VIDEO_ON) {
137209885543Smrg            pPort->videoStatus |= OFF_TIMER;
137309885543Smrg            pPort->offTime = currentTime.milliseconds + OFF_DELAY;
137409885543Smrg	}
137509885543Smrg    }
137609885543Smrg
137709885543Smrg	LEAVE_PROC("SMI_StopVideo");
137809885543Smrg}
137909885543Smrg
138009885543Smrgstatic int
138109885543SmrgSMI_SetPortAttribute(
138209885543Smrg	ScrnInfoPtr	pScrn,
138309885543Smrg	Atom		attribute,
138409885543Smrg	INT32		value,
138509885543Smrg	pointer		data
138609885543Smrg)
138709885543Smrg{
138809885543Smrg    int res;
138909885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) data;
139009885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
139109885543Smrg
139209885543Smrg    ENTER_PROC("SMI_SetPortAttribute");
139309885543Smrg
139409885543Smrg    if (attribute == xvColorKey) {
139509885543Smrg	int r, g, b;
139609885543Smrg
139709885543Smrg        pPort->Attribute[XV_COLORKEY] = value;
139809885543Smrg	switch (pScrn->depth) {
139909885543Smrg	case 8:
140009885543Smrg	    SetKeyReg(pSmi, FPR04, value & 0x00FF);
140109885543Smrg	    break;
140209885543Smrg	case 15:
140309885543Smrg	case 16:
140409885543Smrg	    SetKeyReg(pSmi, FPR04, value & 0xFFFF);
140509885543Smrg	    break;
140609885543Smrg	default:
140709885543Smrg	    r = (value & pScrn->mask.red) >> pScrn->offset.red;
140809885543Smrg	    g = (value & pScrn->mask.green) >> pScrn->offset.green;
140909885543Smrg	    b = (value & pScrn->mask.blue) >> pScrn->offset.blue;
141009885543Smrg	    SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
141109885543Smrg	    break;
141209885543Smrg	}
141309885543Smrg	res = Success;
141409885543Smrg    } else if (attribute == xvInterlaced) {
141509885543Smrg        pPort->Attribute[XV_INTERLACED] = (value != 0);
141609885543Smrg	res = Success;
141709885543Smrg    } else if (attribute == xvEncoding) {
141809885543Smrg        res = SetAttr(pScrn, XV_ENCODING, value);
141909885543Smrg    } else if (attribute == xvBrightness) {
142009885543Smrg        res = SetAttr(pScrn, XV_BRIGHTNESS, value);
142109885543Smrg    } else if (attribute == xvCapBrightness) {
142209885543Smrg        res = SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, value);
142309885543Smrg    } else if (attribute == xvContrast) {
142409885543Smrg        res = SetAttr(pScrn, XV_CONTRAST, value);
142509885543Smrg    } else if (attribute == xvSaturation) {
142609885543Smrg        res = SetAttr(pScrn, XV_SATURATION, value);
142709885543Smrg    } else if (attribute == xvHue) {
142809885543Smrg        res = SetAttr(pScrn, XV_HUE, value);
142909885543Smrg    } else {
143009885543Smrg        res = BadMatch;
143109885543Smrg    }
143209885543Smrg
143309885543Smrg    LEAVE_PROC("SMI_SetPortAttribute");
143409885543Smrg    return res;
143509885543Smrg}
143609885543Smrg
143709885543Smrg
143809885543Smrgstatic int
143909885543SmrgSMI_GetPortAttribute(
144009885543Smrg	ScrnInfoPtr	pScrn,
144109885543Smrg	Atom		attribute,
144209885543Smrg	INT32		*value,
144309885543Smrg	pointer		data
144409885543Smrg)
144509885543Smrg{
144609885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) data;
144709885543Smrg
144809885543Smrg    ENTER_PROC("SMI_GetPortAttribute");
144909885543Smrg    if (attribute == xvEncoding)
145009885543Smrg        *value = pPort->Attribute[XV_ENCODING];
145109885543Smrg    else if (attribute == xvBrightness)
145209885543Smrg        *value = pPort->Attribute[XV_BRIGHTNESS];
145309885543Smrg    else if (attribute == xvCapBrightness)
145409885543Smrg        *value = pPort->Attribute[XV_CAPTURE_BRIGHTNESS];
145509885543Smrg    else if (attribute == xvContrast)
145609885543Smrg        *value = pPort->Attribute[XV_CONTRAST];
145709885543Smrg    else if (attribute == xvSaturation)
145809885543Smrg        *value = pPort->Attribute[XV_SATURATION];
145909885543Smrg    else if (attribute == xvHue)
146009885543Smrg        *value = pPort->Attribute[XV_HUE];
146109885543Smrg    else if (attribute == xvColorKey)
146209885543Smrg        *value = pPort->Attribute[XV_COLORKEY];
146309885543Smrg    else {
146409885543Smrg	LEAVE_PROC("SMI_GetPortAttribute");
146509885543Smrg	return BadMatch;
146609885543Smrg    }
146709885543Smrg
146809885543Smrg    LEAVE_PROC("SMI_GetPortAttribute");
146909885543Smrg    return Success;
147009885543Smrg}
147109885543Smrg
147209885543Smrg
147309885543Smrgstatic void
147409885543SmrgSMI_QueryBestSize(
147509885543Smrg	ScrnInfoPtr		pScrn,
147609885543Smrg	Bool			motion,
147709885543Smrg	short			vid_w,
147809885543Smrg	short			vid_h,
147909885543Smrg	short			drw_w,
148009885543Smrg	short			drw_h,
148109885543Smrg	unsigned int	*p_w,
148209885543Smrg	unsigned int	*p_h,
148309885543Smrg	pointer			data
148409885543Smrg)
148509885543Smrg{
148609885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
148709885543Smrg
148809885543Smrg    ENTER_PROC("SMI_QueryBestSize");
148909885543Smrg
149009885543Smrg    *p_w = min(drw_w, pSmi->lcdWidth);
149109885543Smrg    *p_h = min(drw_h, pSmi->lcdHeight);
149209885543Smrg
149309885543Smrg    LEAVE_PROC("SMI_QueryBestSize");
149409885543Smrg}
149509885543Smrg
149609885543Smrg
149709885543Smrgstatic int
149809885543SmrgSMI_PutImage(
149909885543Smrg	ScrnInfoPtr		pScrn,
150009885543Smrg	short			src_x,
150109885543Smrg	short			src_y,
150209885543Smrg	short			drw_x,
150309885543Smrg	short			drw_y,
150409885543Smrg	short			src_w,
150509885543Smrg	short			src_h,
150609885543Smrg	short			drw_w,
150709885543Smrg	short			drw_h,
150809885543Smrg	int				id,
150909885543Smrg	unsigned char	*buf,
151009885543Smrg	short			width,
151109885543Smrg	short			height,
151209885543Smrg	Bool			sync,
151309885543Smrg	RegionPtr		clipBoxes,
151409885543Smrg	pointer			data,
151509885543Smrg	DrawablePtr		pDraw
151609885543Smrg)
151709885543Smrg{
151809885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
151909885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
152009885543Smrg    INT32 x1, y1, x2, y2;
152109885543Smrg    int bpp = 0;
152209885543Smrg    int srcPitch, srcPitch2 = 0, dstPitch, size;
152309885543Smrg    BoxRec dstBox;
152409885543Smrg    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
152509885543Smrg    int left, top, nPixels, nLines;
152609885543Smrg    unsigned char *dstStart;
152709885543Smrg
152809885543Smrg    ENTER_PROC("SMI_PutImage");
152909885543Smrg
153009885543Smrg    x1 = src_x;
153109885543Smrg    y1 = src_y;
153209885543Smrg    x2 = src_x + src_w;
153309885543Smrg    y2 = src_y + src_h;
153409885543Smrg
153509885543Smrg    dstBox.x1 = drw_x;
153609885543Smrg    dstBox.y1 = drw_y;
153709885543Smrg    dstBox.x2 = drw_x + drw_w;
153809885543Smrg    dstBox.y2 = drw_y + drw_h;
153909885543Smrg
154009885543Smrg    if (!SMI_ClipVideo(pScrn, &dstBox, &x1, &y1, &x2, &y2, clipBoxes, width, height)) {
154109885543Smrg	LEAVE_PROC("SMI_PutImage");
154209885543Smrg	return Success;
154309885543Smrg    }
154409885543Smrg
154509885543Smrg    dstBox.x1 -= pScrn->frameX0;
154609885543Smrg    dstBox.y1 -= pScrn->frameY0;
154709885543Smrg    dstBox.x2 -= pScrn->frameX0;
154809885543Smrg    dstBox.y2 -= pScrn->frameY0;
154909885543Smrg
155009885543Smrg
155109885543Smrg    switch (id) {
155209885543Smrg    case FOURCC_YV12:
155309885543Smrg	srcPitch  = (width + 3) & ~3;
155409885543Smrg	offset2   = srcPitch * height;
155509885543Smrg	srcPitch2 = ((width >> 1) + 3) & ~3;
155609885543Smrg	offset3   = offset2 + (srcPitch2 * (height >> 1));
155709885543Smrg	dstPitch  = ((width << 1) + 15) & ~15;
155809885543Smrg	break;
155909885543Smrg    case FOURCC_I420:
156009885543Smrg	srcPitch  = (width + 3) & ~3;
156109885543Smrg	offset3   = srcPitch * height;
156209885543Smrg	srcPitch2 = ((width >> 1) + 3) & ~3;
156309885543Smrg	offset2   = offset3 + (srcPitch2 * (height >> 1));
156409885543Smrg	dstPitch  = ((width << 1) + 15) & ~15;
156509885543Smrg	break;
156609885543Smrg    case FOURCC_RV24:
156709885543Smrg	bpp = 3;
156809885543Smrg	srcPitch = width * bpp;
156909885543Smrg	dstPitch = (srcPitch + 15) & ~15;
157009885543Smrg	break;
157109885543Smrg    case FOURCC_RV32:
157209885543Smrg	bpp = 4;
157309885543Smrg	srcPitch = width * bpp;
157409885543Smrg	dstPitch = (srcPitch + 15) & ~15;
157509885543Smrg	break;
157609885543Smrg    case FOURCC_YUY2:
157709885543Smrg    case FOURCC_RV15:
157809885543Smrg    case FOURCC_RV16:
157909885543Smrg    default:
158009885543Smrg	bpp = 2;
158109885543Smrg	srcPitch = width * bpp;
158209885543Smrg	dstPitch = (srcPitch + 15) & ~15;
158309885543Smrg	break;
158409885543Smrg    }
158509885543Smrg
158609885543Smrg    size = dstPitch * height;
158709885543Smrg    pPort->video_offset = SMI_AllocateMemory(pScrn, &pPort->video_memory, size);
158809885543Smrg    if (pPort->video_offset == 0) {
158909885543Smrg	LEAVE_PROC("SMI_PutImage");
159009885543Smrg	return BadAlloc;
159109885543Smrg    }
159209885543Smrg
159309885543Smrg    top = y1 >> 16;
159409885543Smrg    left = (x1 >> 16) & ~1;
159509885543Smrg    nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left;
159609885543Smrg    left *= bpp;
159709885543Smrg
159809885543Smrg    offset = pPort->video_offset + (top * dstPitch);
159909885543Smrg    dstStart = pSmi->FBBase + offset + left;
160009885543Smrg
160109885543Smrg    switch(id) {
160209885543Smrg    case FOURCC_YV12:
160309885543Smrg    case FOURCC_I420:
160409885543Smrg	top &= ~1;
160509885543Smrg	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
160609885543Smrg	offset2 += tmp;
160709885543Smrg	offset3 += tmp;
160809885543Smrg	if (id == FOURCC_I420) {
160909885543Smrg	   tmp = offset2;
161009885543Smrg	   offset2 = offset3;
161109885543Smrg	   offset3 = tmp;
161209885543Smrg	}
161309885543Smrg	nLines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
161409885543Smrg	xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
161509885543Smrg				buf + offset2, buf + offset3, dstStart,
161609885543Smrg				srcPitch, srcPitch2, dstPitch, nLines, nPixels);
161709885543Smrg	break;
161809885543Smrg    case FOURCC_UYVY:
161909885543Smrg    case FOURCC_YUY2:
162009885543Smrg    default:
162109885543Smrg	buf += (top * srcPitch) + left;
162209885543Smrg	nLines = ((y2 + 0xffff) >> 16) - top;
162309885543Smrg	xf86XVCopyPacked(buf, dstStart, srcPitch, dstPitch, nLines, nPixels);
162409885543Smrg        break;
162509885543Smrg    }
162609885543Smrg
162709885543Smrg#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,3,99,0,0)
162809885543Smrg    if (!RegionsEqual(&pPort->clip, clipBoxes))
162909885543Smrg#else
163009885543Smrg    if (!REGION_EQUAL(pScrn->pScreen, &pPort->clip, clipBoxes))
163109885543Smrg#endif
163209885543Smrg    {
163309885543Smrg        REGION_COPY(pScrn->pScreen, &pPort->clip, clipBoxes);
163409885543Smrg	xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY],
163509885543Smrg			    clipBoxes);
163609885543Smrg    }
163709885543Smrg
163809885543Smrg    if (pSmi->Chipset != SMI_COUGAR3DR)
163909885543Smrg	SMI_DisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2,
164009885543Smrg			 &dstBox, src_w, src_h, drw_w, drw_h);
164109885543Smrg    else
164209885543Smrg	SMI_DisplayVideo0730(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2,
164309885543Smrg			     &dstBox, src_w, src_h, drw_w, drw_h);
164409885543Smrg
164509885543Smrg    pPort->videoStatus = CLIENT_VIDEO_ON;
164609885543Smrg    LEAVE_PROC("SMI_PutImage");
164709885543Smrg    return Success;
164809885543Smrg
164909885543Smrg}
165009885543Smrg
165109885543Smrg
165209885543Smrgstatic int
165309885543SmrgSMI_QueryImageAttributes(
165409885543Smrg	ScrnInfoPtr	pScrn,
165509885543Smrg	int		id,
165609885543Smrg	unsigned short	*width,
165709885543Smrg	unsigned short	*height,
165809885543Smrg	int		*pitches,
165909885543Smrg	int		*offsets
166009885543Smrg)
166109885543Smrg{
166209885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
166309885543Smrg    int size, tmp;
166409885543Smrg
166509885543Smrg    ENTER_PROC("SMI_QueryImageAttributes");
166609885543Smrg
166709885543Smrg    if (*width > pSmi->lcdWidth) {
166809885543Smrg	*width = pSmi->lcdWidth;
166909885543Smrg    }
167009885543Smrg    if (*height > pSmi->lcdHeight) {
167109885543Smrg	*height = pSmi->lcdHeight;
167209885543Smrg    }
167309885543Smrg
167409885543Smrg    *width = (*width + 1) & ~1;
167509885543Smrg    if (offsets != NULL) {
167609885543Smrg	offsets[0] = 0;
167709885543Smrg    }
167809885543Smrg
167909885543Smrg    switch (id) {
168009885543Smrg    case FOURCC_YV12:
168109885543Smrg    case FOURCC_I420:
168209885543Smrg	*height = (*height + 1) & ~1;
168309885543Smrg	size = (*width + 3) & ~3;
168409885543Smrg	if (pitches != NULL) {
168509885543Smrg	    pitches[0] = size;
168609885543Smrg	}
168709885543Smrg	size *= *height;
168809885543Smrg	if (offsets != NULL) {
168909885543Smrg	    offsets[1] = size;
169009885543Smrg	}
169109885543Smrg	tmp = ((*width >> 1) + 3) & ~3;
169209885543Smrg	if (pitches != NULL) {
169309885543Smrg	    pitches[1] = pitches[2] = tmp;
169409885543Smrg	}
169509885543Smrg	tmp *= (*height >> 1);
169609885543Smrg	size += tmp;
169709885543Smrg	if (offsets != NULL) {
169809885543Smrg	    offsets[2] = size;
169909885543Smrg	}
170009885543Smrg	size += tmp;
170109885543Smrg	break;
170209885543Smrg    case FOURCC_YUY2:
170309885543Smrg    case FOURCC_RV15:
170409885543Smrg    case FOURCC_RV16:
170509885543Smrg    default:
170609885543Smrg	size = *width * 2;
170709885543Smrg	if (pitches != NULL) {
170809885543Smrg	    pitches[0] = size;
170909885543Smrg	}
171009885543Smrg	size *= *height;
171109885543Smrg	break;
171209885543Smrg    case FOURCC_RV24:
171309885543Smrg	size = *width * 3;
171409885543Smrg	if (pitches != NULL) {
171509885543Smrg	    pitches[0] = size;
171609885543Smrg	}
171709885543Smrg	size *= *height;
171809885543Smrg	break;
171909885543Smrg    case FOURCC_RV32:
172009885543Smrg	size = *width * 4;
172109885543Smrg	if (pitches != NULL) {
172209885543Smrg	    pitches[0] = size;
172309885543Smrg	}
172409885543Smrg	size *= *height;
172509885543Smrg	break;
172609885543Smrg    }
172709885543Smrg
172809885543Smrg    LEAVE_PROC("SMI_QueryImageAttributes");
172909885543Smrg    return size;
173009885543Smrg}
173109885543Smrg
173209885543Smrg
173309885543Smrg/******************************************************************************\
173409885543Smrg**									      **
173509885543Smrg**	S U P P O R T   F U N C T I O N S				      **
173609885543Smrg**									      **
173709885543Smrg\******************************************************************************/
173809885543Smrg#if 0
173909885543Smrgstatic void
174009885543SmrgSMI_WaitForSync(
174109885543Smrg	ScrnInfoPtr	pScrn
174209885543Smrg)
174309885543Smrg{
174409885543Smrg	SMIPtr pSmi = SMIPTR(pScrn);
174509885543Smrg	vgaHWPtr hwp = VGAHWPTR(pScrn);
174609885543Smrg	int vgaIOBase  = hwp->IOBase;
174709885543Smrg	int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
174809885543Smrg	int vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
174909885543Smrg
175009885543Smrg	VerticalRetraceWait();
175109885543Smrg}
175209885543Smrg#endif
175309885543Smrg
175409885543Smrgstatic Bool
175509885543SmrgSMI_ClipVideo(
175609885543Smrg	ScrnInfoPtr	pScrn,
175709885543Smrg	BoxPtr		dst,
175809885543Smrg	INT32		*x1,
175909885543Smrg	INT32		*y1,
176009885543Smrg	INT32		*x2,
176109885543Smrg	INT32		*y2,
176209885543Smrg	RegionPtr	reg,
176309885543Smrg	INT32		width,
176409885543Smrg	INT32		height
176509885543Smrg)
176609885543Smrg{
176709885543Smrg    ScreenPtr pScreen = pScrn->pScreen;
176809885543Smrg    INT32 vscale, hscale;
176909885543Smrg    BoxPtr extents = REGION_EXTENTS(pScreen, reg);
177009885543Smrg    int diff;
177109885543Smrg
177209885543Smrg    ENTER_PROC("SMI_ClipVideo");
177309885543Smrg
177409885543Smrg    DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n",  __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16));
177509885543Smrg    /* PDR#941 */
177609885543Smrg    extents->x1 = max(extents->x1, pScrn->frameX0);
177709885543Smrg    extents->y1 = max(extents->y1, pScrn->frameY0);
177809885543Smrg
177909885543Smrg    hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
178009885543Smrg    vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
178109885543Smrg
178209885543Smrg    *x1 <<= 16; *y1 <<= 16;
178309885543Smrg    *x2 <<= 16; *y2 <<= 16;
178409885543Smrg
178509885543Smrg    DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n",  __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16));
178609885543Smrg
178709885543Smrg    diff = extents->x1 - dst->x1;
178809885543Smrg    if (diff > 0) {
178909885543Smrg	dst->x1 = extents->x1;
179009885543Smrg	*x1 += diff * hscale;
179109885543Smrg    }
179209885543Smrg
179309885543Smrg    diff = extents->y1 - dst->y1;
179409885543Smrg    if (diff > 0) {
179509885543Smrg	dst->y1 = extents->y1;
179609885543Smrg	*y1 += diff * vscale;
179709885543Smrg    }
179809885543Smrg
179909885543Smrg    diff = dst->x2 - extents->x2;
180009885543Smrg    if (diff > 0) {
180109885543Smrg	dst->x2 = extents->x2; /* PDR#687 */
180209885543Smrg	*x2 -= diff * hscale;
180309885543Smrg    }
180409885543Smrg
180509885543Smrg    diff = dst->y2 - extents->y2;
180609885543Smrg    if (diff > 0) {
180709885543Smrg	dst->y2 = extents->y2;
180809885543Smrg	*y2 -= diff * vscale;
180909885543Smrg    }
181009885543Smrg
181109885543Smrg    DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n",  __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16));
181209885543Smrg
181309885543Smrg    if (*x1 < 0) {
181409885543Smrg	diff = (-*x1 + hscale - 1) / hscale;
181509885543Smrg	dst->x1 += diff;
181609885543Smrg	*x1 += diff * hscale;
181709885543Smrg    }
181809885543Smrg
181909885543Smrg    if (*y1 < 0) {
182009885543Smrg	diff = (-*y1 + vscale - 1) / vscale;
182109885543Smrg	dst->y1 += diff;
182209885543Smrg	*y1 += diff * vscale;
182309885543Smrg    }
182409885543Smrg
182509885543Smrg    DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n",  __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16));
182609885543Smrg
182709885543Smrg#if 0 /* aaa was macht dieser code? */
182809885543Smrg	delta = *x2 - (width << 16);
182909885543Smrg	if (delta > 0)
183009885543Smrg	{
183109885543Smrg		diff = (delta + hscale - 1) / hscale;
183209885543Smrg		dst->x2 -= diff;
183309885543Smrg		*x2 -= diff * hscale;
183409885543Smrg	}
183509885543Smrg
183609885543Smrg	delta = *y2 - (height << 16);
183709885543Smrg	if (delta > 0)
183809885543Smrg	{
183909885543Smrg		diff = (delta + vscale - 1) / vscale;
184009885543Smrg		dst->y2 -= diff;
184109885543Smrg		*y2 -= diff * vscale;
184209885543Smrg	}
184309885543Smrg#endif
184409885543Smrg
184509885543Smrg    DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n",  __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16));
184609885543Smrg
184709885543Smrg    if ((*x1 >= *x2) || (*y1 >= *y2)) {
184809885543Smrg	LEAVE_PROC("SMI_ClipVideo");
184909885543Smrg	return FALSE;
185009885543Smrg    }
185109885543Smrg
185209885543Smrg    if ((dst->x1 != extents->x1) || (dst->y1 != extents->y1) ||
185309885543Smrg	(dst->x2 != extents->x2) || (dst->y2 != extents->y2)) {
185409885543Smrg	RegionRec clipReg;
185509885543Smrg	REGION_INIT(pScreen, &clipReg, dst, 1);
185609885543Smrg	REGION_INTERSECT(pScreen, reg, reg, &clipReg);
185709885543Smrg	REGION_UNINIT(pScreen, &clipReg);
185809885543Smrg    }
185909885543Smrg
186009885543Smrg    DEBUG((VERBLEV, "ClipVideo(%d): x1=%d y1=%d x2=%d y2=%d\n",  __LINE__, *x1 >> 16, *y1 >> 16, *x2 >> 16, *y2 >> 16));
186109885543Smrg
186209885543Smrg    LEAVE_PROC("SMI_ClipVideo");
186309885543Smrg    return TRUE;
186409885543Smrg}
186509885543Smrg
186609885543Smrgstatic void
186709885543SmrgSMI_DisplayVideo(
186809885543Smrg	ScrnInfoPtr	pScrn,
186909885543Smrg	int		id,
187009885543Smrg	int		offset,
187109885543Smrg	short		width,
187209885543Smrg	short		height,
187309885543Smrg	int		pitch,
187409885543Smrg	int		x1,
187509885543Smrg	int		y1,
187609885543Smrg	int		x2,
187709885543Smrg	int		y2,
187809885543Smrg	BoxPtr		dstBox,
187909885543Smrg	short		vid_w,
188009885543Smrg	short		vid_h,
188109885543Smrg	short		drw_w,
188209885543Smrg	short		drw_h
188309885543Smrg)
188409885543Smrg{
188509885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
188609885543Smrg    CARD32 vpr00;
188709885543Smrg    int hstretch, vstretch;
188809885543Smrg
188909885543Smrg    ENTER_PROC("SMI_DisplayVideo");
189009885543Smrg
189109885543Smrg    vpr00 = READ_VPR(pSmi, 0x00) & ~0x0CB800FF;
189209885543Smrg
189309885543Smrg    switch (id) {
189409885543Smrg    case FOURCC_YV12:
189509885543Smrg    case FOURCC_I420:
189609885543Smrg    case FOURCC_YUY2:
189709885543Smrg	vpr00 |= 0x6;
189809885543Smrg	break;
189909885543Smrg    case FOURCC_RV15:
190009885543Smrg	vpr00 |= 0x1;
190109885543Smrg	break;
190209885543Smrg    case FOURCC_RV16:
190309885543Smrg	vpr00 |= 0x2;
190409885543Smrg	break;
190509885543Smrg    case FOURCC_RV24:
190609885543Smrg	vpr00 |= 0x4;
190709885543Smrg	break;
190809885543Smrg    case FOURCC_RV32:
190909885543Smrg	vpr00 |= 0x3;
191009885543Smrg	break;
191109885543Smrg    }
191209885543Smrg
191309885543Smrg    if (drw_w > vid_w) {
191409885543Smrg	hstretch = (2560 * vid_w / drw_w + 5) / 10;
191509885543Smrg    } else {
191609885543Smrg	hstretch = 0;
191709885543Smrg    }
191809885543Smrg
191909885543Smrg    if (drw_h > vid_h) {
192009885543Smrg	vstretch = (2560 * vid_h / drw_h + 5) / 10;
192109885543Smrg	vpr00 |= 1 << 21;
192209885543Smrg    } else {
192309885543Smrg	vstretch = 0;
192409885543Smrg    }
192509885543Smrg#if 0
192609885543Smrg    SMI_WaitForSync(pScrn);
192709885543Smrg#endif
192809885543Smrg    WRITE_VPR(pSmi, 0x00, vpr00 | (1 << 3) | (1 << 20));
192909885543Smrg    WRITE_VPR(pSmi, 0x14, (dstBox->x1) | (dstBox->y1 << 16));
193009885543Smrg    WRITE_VPR(pSmi, 0x18, (dstBox->x2) | (dstBox->y2 << 16));
193109885543Smrg    WRITE_VPR(pSmi, 0x1C, offset >> 3);
193209885543Smrg    WRITE_VPR(pSmi, 0x20, (pitch >> 3) | ((pitch >> 3) << 16));
193309885543Smrg    WRITE_VPR(pSmi, 0x24, (hstretch << 8) | vstretch);
193409885543Smrg
193509885543Smrg    LEAVE_PROC("SMI_DisplayVideo");
193609885543Smrg}
193709885543Smrg
193809885543Smrgstatic void
193909885543SmrgSMI_DisplayVideo0730(
194009885543Smrg	ScrnInfoPtr	pScrn,
194109885543Smrg	int		id,
194209885543Smrg	int		offset,
194309885543Smrg	short		width,
194409885543Smrg	short		height,
194509885543Smrg	int		pitch,
194609885543Smrg	int		x1,
194709885543Smrg	int		y1,
194809885543Smrg	int		x2,
194909885543Smrg	int		y2,
195009885543Smrg	BoxPtr		dstBox,
195109885543Smrg	short		vid_w,
195209885543Smrg	short		vid_h,
195309885543Smrg	short		drw_w,
195409885543Smrg	short		drw_h
195509885543Smrg)
195609885543Smrg{
195709885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
195809885543Smrg    CARD32 fpr00;
195909885543Smrg    int hstretch, vstretch;
196009885543Smrg
196109885543Smrg    ENTER_PROC("SMI_DisplayVideo0730");
196209885543Smrg
196309885543Smrg    fpr00 = READ_FPR(pSmi, 0x00) & ~(FPR00_MASKBITS);
196409885543Smrg
196509885543Smrg    switch (id) {
196609885543Smrg    case FOURCC_YV12:
196709885543Smrg    case FOURCC_I420:
196809885543Smrg    case FOURCC_YUY2:
196909885543Smrg	fpr00 |= FPR00_FMT_YUV422;
197009885543Smrg	break;
197109885543Smrg    case FOURCC_RV15:
197209885543Smrg	fpr00 |= FPR00_FMT_15P;
197309885543Smrg	break;
197409885543Smrg    case FOURCC_RV16:
197509885543Smrg	fpr00 |= FPR00_FMT_16P;
197609885543Smrg	break;
197709885543Smrg    case FOURCC_RV24:
197809885543Smrg	fpr00 |= FPR00_FMT_24P;
197909885543Smrg	break;
198009885543Smrg    case FOURCC_RV32:
198109885543Smrg	fpr00 |= FPR00_FMT_32P;
198209885543Smrg	break;
198309885543Smrg    }
198409885543Smrg
198509885543Smrg    /* the formulas for calculating the stretch values do not match the
198609885543Smrg       documentation, but they're the same as the ddraw driver and they work */
198709885543Smrg    if (drw_w > vid_w) {
198809885543Smrg	hstretch = (8192 * vid_w / drw_w);
198909885543Smrg    } else {
199009885543Smrg	hstretch = 0;
199109885543Smrg    }
199209885543Smrg
199309885543Smrg    if (drw_h > vid_h) {
199409885543Smrg	vstretch = (8192 * vid_h / drw_h);
199509885543Smrg    } else {
199609885543Smrg	vstretch = 0;
199709885543Smrg    }
199809885543Smrg
199909885543Smrg    WRITE_FPR(pSmi, FPR00, fpr00 | FPR00_VWIENABLE | FPR00_VWIKEYENABLE);
200009885543Smrg    WRITE_FPR(pSmi, FPR14, (dstBox->x1) | (dstBox->y1 << 16));
200109885543Smrg    WRITE_FPR(pSmi, FPR18, (dstBox->x2) | (dstBox->y2 << 16));
200209885543Smrg    WRITE_FPR(pSmi, FPR1C, offset >> 3);
200309885543Smrg    WRITE_FPR(pSmi, FPR20, (pitch >> 3) | ((pitch >> 3) << 16));
200409885543Smrg    WRITE_FPR(pSmi, FPR24, (hstretch & 0xFF00) | ((vstretch & 0xFF00)>>8));
200509885543Smrg    WRITE_FPR(pSmi, FPR68, ((hstretch & 0x00FF)<<8) | (vstretch & 0x00FF));
200609885543Smrg
200709885543Smrg    LEAVE_PROC("SMI_DisplayVideo0730");
200809885543Smrg}
200909885543Smrg
201009885543Smrgstatic void
201109885543SmrgSMI_BlockHandler(
201209885543Smrg	int	i,
201309885543Smrg	pointer	blockData,
201409885543Smrg	pointer	pTimeout,
201509885543Smrg	pointer	pReadMask
201609885543Smrg)
201709885543Smrg{
201809885543Smrg    ScreenPtr	pScreen = screenInfo.screens[i];
201909885543Smrg    ScrnInfoPtr	pScrn	= xf86Screens[i];
202009885543Smrg    SMIPtr	pSmi    = SMIPTR(pScrn);
202109885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
202209885543Smrg
202309885543Smrg    pScreen->BlockHandler = pSmi->BlockHandler;
202409885543Smrg    (*pScreen->BlockHandler)(i, blockData, pTimeout, pReadMask);
202509885543Smrg    pScreen->BlockHandler = SMI_BlockHandler;
202609885543Smrg
202709885543Smrg    if (pPort->videoStatus & TIMER_MASK) {
202809885543Smrg	UpdateCurrentTime();
202909885543Smrg        if (pPort->videoStatus & OFF_TIMER) {
203009885543Smrg            if (pPort->offTime < currentTime.milliseconds) {
203109885543Smrg		if (pSmi->Chipset == SMI_COUGAR3DR) {
203209885543Smrg		    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
203309885543Smrg		} else {
203409885543Smrg		    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
203509885543Smrg		}
203609885543Smrg                pPort->videoStatus = FREE_TIMER;
203709885543Smrg                pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
203809885543Smrg	    }
203909885543Smrg	} else {
204009885543Smrg            if (pPort->freeTime < currentTime.milliseconds) {
204109885543Smrg		SMI_FreeMemory(pScrn, pPort->video_memory);
204209885543Smrg                pPort->video_memory = NULL;
204309885543Smrg	    }
204409885543Smrg            pPort->videoStatus = 0;
204509885543Smrg	}
204609885543Smrg    }
204709885543Smrg}
204809885543Smrg
204909885543Smrg#if 0
205009885543Smrgstatic int
205109885543SmrgSMI_SendI2C(
205209885543Smrg	ScrnInfoPtr		pScrn,
205309885543Smrg	CARD8			device,
205409885543Smrg	char			*devName,
205509885543Smrg	SMI_I2CDataPtr	i2cData
205609885543Smrg)
205709885543Smrg{
205809885543Smrg	SMIPtr pSmi = SMIPTR(pScrn);
205909885543Smrg	I2CDevPtr dev;
206009885543Smrg	int status = Success;
206109885543Smrg
206209885543Smrg	ENTER_PROC("SMI_SendI2C");
206309885543Smrg
206409885543Smrg	if (pSmi->I2C == NULL)
206509885543Smrg	{
206609885543Smrg		LEAVE_PROC("SMI_SendI2C");
206709885543Smrg		return(BadAlloc);
206809885543Smrg	}
206909885543Smrg
207009885543Smrg	dev = xf86CreateI2CDevRec();
207109885543Smrg	if (dev == NULL)
207209885543Smrg	{
207309885543Smrg		LEAVE_PROC("SMI_SendI2C");
207409885543Smrg		return(BadAlloc);
207509885543Smrg	}
207609885543Smrg	dev->DevName = devName;
207709885543Smrg	dev->SlaveAddr = device;
207809885543Smrg	dev->pI2CBus = pSmi->I2C;
207909885543Smrg
208009885543Smrg	if (!xf86I2CDevInit(dev))
208109885543Smrg	{
208209885543Smrg		status = BadAlloc;
208309885543Smrg	}
208409885543Smrg	else
208509885543Smrg	{
208609885543Smrg		while (i2cData->address != 0xFF || i2cData->data != 0xFF) /* PDR#676 */
208709885543Smrg		{
208809885543Smrg			if (!xf86I2CWriteByte(dev, i2cData->address, i2cData->data))
208909885543Smrg			{
209009885543Smrg				status = BadAlloc;
209109885543Smrg				break;
209209885543Smrg			}
209309885543Smrg			i2cData++;
209409885543Smrg		}
209509885543Smrg	}
209609885543Smrg
209709885543Smrg	xf86DestroyI2CDevRec(dev, TRUE);
209809885543Smrg	LEAVE_PROC("SMI_SendI2C");
209909885543Smrg	return(status);
210009885543Smrg}
210109885543Smrg#endif
210209885543Smrg
210309885543Smrg/******************************************************************************\
210409885543Smrg**									      **
210509885543Smrg**	 O F F S C R E E N   M E M O R Y   M A N A G E R		      **
210609885543Smrg**									      **
210709885543Smrg\******************************************************************************/
210809885543Smrg
210909885543Smrgstatic void
211009885543SmrgSMI_InitOffscreenImages(
211109885543Smrg	ScreenPtr	pScreen
211209885543Smrg)
211309885543Smrg{
211409885543Smrg    XF86OffscreenImagePtr offscreenImages;
211509885543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
211609885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
211709885543Smrg    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
211809885543Smrg
211909885543Smrg    ENTER_PROC("SMI_InitOffscreenImages");
212009885543Smrg
212109885543Smrg    offscreenImages = xalloc(sizeof(XF86OffscreenImageRec));
212209885543Smrg    if (offscreenImages == NULL) {
212309885543Smrg	LEAVE_PROC("SMI_InitOffscreenImages");
212409885543Smrg	return;
212509885543Smrg    }
212609885543Smrg
212709885543Smrg    offscreenImages->image = SMI_VideoImages;
212809885543Smrg    offscreenImages->flags = VIDEO_OVERLAID_IMAGES
212909885543Smrg			   | VIDEO_CLIP_TO_VIEWPORT;
213009885543Smrg    offscreenImages->alloc_surface = SMI_AllocSurface;
213109885543Smrg    offscreenImages->free_surface = SMI_FreeSurface;
213209885543Smrg    offscreenImages->display = SMI_DisplaySurface;
213309885543Smrg    offscreenImages->stop = SMI_StopSurface;
213409885543Smrg    offscreenImages->getAttribute = SMI_GetSurfaceAttribute;
213509885543Smrg    offscreenImages->setAttribute = SMI_SetSurfaceAttribute;
213609885543Smrg    offscreenImages->max_width = pSmi->lcdWidth;
213709885543Smrg    offscreenImages->max_height = pSmi->lcdHeight;
213809885543Smrg    if (!pPort->I2CDev.SlaveAddr) {
213909885543Smrg	offscreenImages->num_attributes = nElems(SMI_VideoAttributes);
214009885543Smrg	offscreenImages->attributes = SMI_VideoAttributes;
214109885543Smrg    } else {
214209885543Smrg	offscreenImages->num_attributes = nElems(SMI_VideoAttributesSAA711x);
214309885543Smrg	offscreenImages->attributes = SMI_VideoAttributesSAA711x;
214409885543Smrg    }
214509885543Smrg    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
214609885543Smrg
214709885543Smrg    LEAVE_PROC("SMI_InitOffscreenImages");
214809885543Smrg}
214909885543Smrg
215009885543Smrgstatic void
215109885543SmrgSMI_VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
215209885543Smrg{
215309885543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
215409885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
215509885543Smrg    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
215609885543Smrg
215709885543Smrg    ENTER_PROC("SMI_VideoSave");
215809885543Smrg
215909885543Smrg    if (pPort->video_memory == area)
216009885543Smrg	pPort->video_memory = NULL;
216109885543Smrg
216209885543Smrg    LEAVE_PROC("SMI_VideoSave");
216309885543Smrg}
216409885543Smrg
216509885543Smrgstatic CARD32
216609885543SmrgSMI_AllocateMemory(
216709885543Smrg	ScrnInfoPtr	pScrn,
216809885543Smrg	void		**mem_struct,
216909885543Smrg	int 		size
217009885543Smrg)
217109885543Smrg{
217209885543Smrg    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
217309885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
217409885543Smrg    int offset = 0;
217509885543Smrg
217609885543Smrg    ENTER_PROC("SMI_AllocateMemory");
217709885543Smrg
217809885543Smrg    if (pSmi->useEXA) {
217909885543Smrg	ExaOffscreenArea *area = *mem_struct;
218009885543Smrg
218109885543Smrg	if (area != NULL) {
218209885543Smrg	    if (area->size >= size)
218309885543Smrg		return area->offset;
218409885543Smrg
218509885543Smrg	    exaOffscreenFree(pScrn->pScreen, area);
218609885543Smrg	}
218709885543Smrg
218809885543Smrg	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, SMI_VideoSave, NULL);
218909885543Smrg
219009885543Smrg	*mem_struct = area;
219109885543Smrg	if (area == NULL)
219209885543Smrg	    return 0;
219309885543Smrg	offset = area->offset;
219409885543Smrg    } else {
219509885543Smrg	FBLinearPtr linear = *mem_struct;
219609885543Smrg
219709885543Smrg	/*  XAA allocates in units of pixels at the screen bpp,
219809885543Smrg	 *  so adjust size appropriately.
219909885543Smrg	 */
220009885543Smrg	size = (size + pSmi->Bpp - 1) / pSmi->Bpp;
220109885543Smrg
220209885543Smrg	if (linear) {
220309885543Smrg	    if (linear->size >= size)
220409885543Smrg		return linear->offset * pSmi->Bpp;
220509885543Smrg
220609885543Smrg	    if (xf86ResizeOffscreenLinear(linear, size))
220709885543Smrg		return linear->offset * pSmi->Bpp;
220809885543Smrg
220909885543Smrg		xf86FreeOffscreenLinear(linear);
221009885543Smrg	    }
221109885543Smrg
221209885543Smrg	    linear = xf86AllocateOffscreenLinear(pScreen, size, 16, NULL, NULL, NULL);
221309885543Smrg	    *mem_struct = linear;
221409885543Smrg
221509885543Smrg	    if (!linear) {
221609885543Smrg		int max_size;
221709885543Smrg
221809885543Smrg		xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16, PRIORITY_EXTREME);
221909885543Smrg		if (max_size < size)
222009885543Smrg		    return 0;
222109885543Smrg
222209885543Smrg		xf86PurgeUnlockedOffscreenAreas(pScreen);
222309885543Smrg
222409885543Smrg		linear = xf86AllocateOffscreenLinear(pScreen, size, 16, NULL, NULL, NULL);
222509885543Smrg		*mem_struct = linear;
222609885543Smrg
222709885543Smrg		if (!linear)
222809885543Smrg		    return 0;
222909885543Smrg	}
223009885543Smrg
223109885543Smrg	DEBUG((VERBLEV, "offset = %p\n", offset));
223209885543Smrg    }
223309885543Smrg
223409885543Smrg    DEBUG((VERBLEV, "area = %p\n", area));
223509885543Smrg    LEAVE_PROC("SMI_AllocateMemory");
223609885543Smrg    return offset;
223709885543Smrg}
223809885543Smrg
223909885543Smrgstatic void
224009885543SmrgSMI_FreeMemory(
224109885543Smrg	ScrnInfoPtr pScrn,
224209885543Smrg	void *mem_struct
224309885543Smrg)
224409885543Smrg{
224509885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
224609885543Smrg
224709885543Smrg    ENTER_PROC("SMI_FreeMemory");
224809885543Smrg
224909885543Smrg    if (pSmi->useEXA) {
225009885543Smrg	ExaOffscreenArea *area = mem_struct;
225109885543Smrg
225209885543Smrg	if (area != NULL)
225309885543Smrg	    exaOffscreenFree(pScrn->pScreen, area);
225409885543Smrg    } else {
225509885543Smrg	FBLinearPtr linear = mem_struct;
225609885543Smrg
225709885543Smrg	if (linear != NULL)
225809885543Smrg	    xf86FreeOffscreenLinear(linear);
225909885543Smrg    }
226009885543Smrg
226109885543Smrg    LEAVE_PROC("SMI_FreeMemory");
226209885543Smrg}
226309885543Smrg
226409885543Smrgstatic int
226509885543SmrgSMI_AllocSurface(
226609885543Smrg	ScrnInfoPtr	pScrn,
226709885543Smrg	int		id,
226809885543Smrg	unsigned short	width,
226909885543Smrg	unsigned short	height,
227009885543Smrg	XF86SurfacePtr	surface
227109885543Smrg)
227209885543Smrg{
227309885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
227409885543Smrg    int pitch, bpp, offset, size;
227509885543Smrg    void *surface_memory = NULL;
227609885543Smrg    SMI_OffscreenPtr ptrOffscreen;
227709885543Smrg
227809885543Smrg    ENTER_PROC("SMI_AllocSurface");
227909885543Smrg
228009885543Smrg    if ((width > pSmi->lcdWidth) || (height > pSmi->lcdHeight)) {
228109885543Smrg	LEAVE_PROC("SMI_AllocSurface");
228209885543Smrg	return BadAlloc;
228309885543Smrg    }
228409885543Smrg
228509885543Smrg    switch (id) {
228609885543Smrg    case FOURCC_YV12:
228709885543Smrg    case FOURCC_I420:
228809885543Smrg    case FOURCC_YUY2:
228909885543Smrg    case FOURCC_RV15:
229009885543Smrg    case FOURCC_RV16:
229109885543Smrg	bpp = 2;
229209885543Smrg	break;
229309885543Smrg    case FOURCC_RV24:
229409885543Smrg	bpp = 3;
229509885543Smrg	break;
229609885543Smrg    case FOURCC_RV32:
229709885543Smrg	bpp = 4;
229809885543Smrg	break;
229909885543Smrg    default:
230009885543Smrg	LEAVE_PROC("SMI_AllocSurface");
230109885543Smrg	return BadAlloc;
230209885543Smrg    }
230309885543Smrg
230409885543Smrg    width = (width + 1) & ~1;
230509885543Smrg    pitch = (width * bpp + 15) & ~15;
230609885543Smrg    size  = pitch * height;
230709885543Smrg
230809885543Smrg    offset = SMI_AllocateMemory(pScrn, &surface_memory, size);
230909885543Smrg    if (offset == 0) {
231009885543Smrg	LEAVE_PROC("SMI_AllocSurface");
231109885543Smrg	return BadAlloc;
231209885543Smrg    }
231309885543Smrg
231409885543Smrg    surface->pitches = xalloc(sizeof(int));
231509885543Smrg    if (surface->pitches == NULL) {
231609885543Smrg	SMI_FreeMemory(pScrn, surface_memory);
231709885543Smrg	LEAVE_PROC("SMI_AllocSurface");
231809885543Smrg	return BadAlloc;
231909885543Smrg    }
232009885543Smrg    surface->offsets = xalloc(sizeof(int));
232109885543Smrg    if (surface->offsets == NULL) {
232209885543Smrg	xfree(surface->pitches);
232309885543Smrg	SMI_FreeMemory(pScrn, surface_memory);
232409885543Smrg	LEAVE_PROC("SMI_AllocSurface");
232509885543Smrg	return BadAlloc;
232609885543Smrg    }
232709885543Smrg
232809885543Smrg    ptrOffscreen = xalloc(sizeof(SMI_OffscreenRec));
232909885543Smrg    if (ptrOffscreen == NULL) {
233009885543Smrg	xfree(surface->offsets);
233109885543Smrg	xfree(surface->pitches);
233209885543Smrg	SMI_FreeMemory(pScrn, surface_memory);
233309885543Smrg	LEAVE_PROC("SMI_AllocSurface");
233409885543Smrg	return BadAlloc;
233509885543Smrg    }
233609885543Smrg
233709885543Smrg    surface->pScrn = pScrn;
233809885543Smrg    surface->id = id;
233909885543Smrg    surface->width = width;
234009885543Smrg    surface->height = height;
234109885543Smrg    surface->pitches[0] = pitch;
234209885543Smrg    surface->offsets[0] = offset;
234309885543Smrg    surface->devPrivate.ptr = (pointer) ptrOffscreen;
234409885543Smrg
234509885543Smrg    ptrOffscreen->surface_memory = surface_memory;
234609885543Smrg    ptrOffscreen->isOn = FALSE;
234709885543Smrg
234809885543Smrg    LEAVE_PROC("SMI_AllocSurface");
234909885543Smrg    return Success;
235009885543Smrg}
235109885543Smrg
235209885543Smrgstatic int
235309885543SmrgSMI_FreeSurface(
235409885543Smrg	XF86SurfacePtr	surface
235509885543Smrg)
235609885543Smrg{
235709885543Smrg    ScrnInfoPtr pScrn = surface->pScrn;
235809885543Smrg    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
235909885543Smrg
236009885543Smrg    ENTER_PROC("SMI_FreeSurface");
236109885543Smrg
236209885543Smrg    if (ptrOffscreen->isOn) {
236309885543Smrg	SMI_StopSurface(surface);
236409885543Smrg    }
236509885543Smrg
236609885543Smrg    SMI_FreeMemory(pScrn, ptrOffscreen->surface_memory);
236709885543Smrg    xfree(surface->pitches);
236809885543Smrg    xfree(surface->offsets);
236909885543Smrg    xfree(surface->devPrivate.ptr);
237009885543Smrg
237109885543Smrg    LEAVE_PROC("SMI_FreeSurface");
237209885543Smrg    return Success;
237309885543Smrg}
237409885543Smrg
237509885543Smrgstatic int
237609885543SmrgSMI_DisplaySurface(
237709885543Smrg	XF86SurfacePtr	surface,
237809885543Smrg	short		vid_x,
237909885543Smrg	short		vid_y,
238009885543Smrg	short		drw_x,
238109885543Smrg	short		drw_y,
238209885543Smrg	short		vid_w,
238309885543Smrg	short		vid_h,
238409885543Smrg	short		drw_w,
238509885543Smrg	short		drw_h,
238609885543Smrg	RegionPtr	clipBoxes
238709885543Smrg)
238809885543Smrg{
238909885543Smrg    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
239009885543Smrg    SMIPtr pSmi = SMIPTR(surface->pScrn);
239109885543Smrg    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
239209885543Smrg    INT32 x1, y1, x2, y2;
239309885543Smrg    BoxRec dstBox;
239409885543Smrg
239509885543Smrg    ENTER_PROC("SMI_DisplaySurface");
239609885543Smrg
239709885543Smrg    x1 = vid_x;
239809885543Smrg    x2 = vid_x + vid_w;
239909885543Smrg    y1 = vid_y;
240009885543Smrg    y2 = vid_y + vid_h;
240109885543Smrg
240209885543Smrg    dstBox.x1 = drw_x;
240309885543Smrg    dstBox.x2 = drw_x + drw_w;
240409885543Smrg    dstBox.y1 = drw_y;
240509885543Smrg    dstBox.y2 = drw_y + drw_h;
240609885543Smrg
240709885543Smrg    if (!SMI_ClipVideo(surface->pScrn, &dstBox, &x1, &y1, &x2, &y2, clipBoxes,
240809885543Smrg			surface->width, surface->height)) {
240909885543Smrg	LEAVE_PROC("SMI_DisplaySurface");
241009885543Smrg	return Success;
241109885543Smrg    }
241209885543Smrg
241309885543Smrg    dstBox.x1 -= surface->pScrn->frameX0;
241409885543Smrg    dstBox.y1 -= surface->pScrn->frameY0;
241509885543Smrg    dstBox.x2 -= surface->pScrn->frameX0;
241609885543Smrg    dstBox.y2 -= surface->pScrn->frameY0;
241709885543Smrg
241809885543Smrg    xf86XVFillKeyHelper(surface->pScrn->pScreen,
241909885543Smrg			pPort->Attribute[XV_COLORKEY], clipBoxes);
242009885543Smrg
242109885543Smrg    if (pSmi->Chipset != SMI_COUGAR3DR) {
242209885543Smrg	SMI_ResetVideo(surface->pScrn);
242309885543Smrg	SMI_DisplayVideo(surface->pScrn, surface->id, surface->offsets[0],
242409885543Smrg			 surface->width, surface->height, surface->pitches[0], x1, y1, x2,
242509885543Smrg			 y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
242609885543Smrg    } else {
242709885543Smrg	SMI_ResetVideo(surface->pScrn);
242809885543Smrg	SMI_DisplayVideo0730(surface->pScrn, surface->id, surface->offsets[0],
242909885543Smrg			     surface->width, surface->height, surface->pitches[0], x1, y1, x2,
243009885543Smrg			     y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
243109885543Smrg    }
243209885543Smrg
243309885543Smrg    ptrOffscreen->isOn = TRUE;
243409885543Smrg    if (pPort->videoStatus & CLIENT_VIDEO_ON) {
243509885543Smrg        REGION_EMPTY(surface->pScrn->pScreen, &pPort->clip);
243609885543Smrg	UpdateCurrentTime();
243709885543Smrg        pPort->videoStatus = FREE_TIMER;
243809885543Smrg        pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
243909885543Smrg    }
244009885543Smrg
244109885543Smrg    LEAVE_PROC("SMI_DisplaySurface");
244209885543Smrg    return Success;
244309885543Smrg}
244409885543Smrg
244509885543Smrgstatic int
244609885543SmrgSMI_StopSurface(
244709885543Smrg	XF86SurfacePtr	surface
244809885543Smrg)
244909885543Smrg{
245009885543Smrg    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
245109885543Smrg
245209885543Smrg    ENTER_PROC("SMI_StopSurface");
245309885543Smrg
245409885543Smrg    if (ptrOffscreen->isOn) {
245509885543Smrg	SMIPtr pSmi = SMIPTR(surface->pScrn);
245609885543Smrg	if (pSmi->Chipset == SMI_COUGAR3DR) {
245709885543Smrg	    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
245809885543Smrg	} else {
245909885543Smrg	    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
246009885543Smrg	}
246109885543Smrg
246209885543Smrg	ptrOffscreen->isOn = FALSE;
246309885543Smrg    }
246409885543Smrg
246509885543Smrg    LEAVE_PROC("SMI_StopSurface");
246609885543Smrg    return Success;
246709885543Smrg}
246809885543Smrg
246909885543Smrgstatic int
247009885543SmrgSMI_GetSurfaceAttribute(
247109885543Smrg	ScrnInfoPtr	pScrn,
247209885543Smrg	Atom		attr,
247309885543Smrg	INT32		*value
247409885543Smrg)
247509885543Smrg{
247609885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
247709885543Smrg
247809885543Smrg    return SMI_GetPortAttribute(pScrn, attr, value,
247909885543Smrg			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
248009885543Smrg}
248109885543Smrg
248209885543Smrgstatic int
248309885543SmrgSMI_SetSurfaceAttribute(
248409885543Smrg	ScrnInfoPtr	pScrn,
248509885543Smrg	Atom		attr,
248609885543Smrg	INT32		value
248709885543Smrg)
248809885543Smrg{
248909885543Smrg    SMIPtr pSmi = SMIPTR(pScrn);
249009885543Smrg
249109885543Smrg    return SMI_SetPortAttribute(pScrn, attr, value,
249209885543Smrg			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
249309885543Smrg}
249409885543Smrg
249509885543Smrgstatic void
249609885543SmrgSetKeyReg(SMIPtr pSmi, int reg, int value)
249709885543Smrg{
249809885543Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
249909885543Smrg	WRITE_FPR(pSmi, reg, value);
250009885543Smrg    } else {
250109885543Smrg	WRITE_VPR(pSmi, reg, value);
250209885543Smrg    }
250309885543Smrg}
250409885543Smrg
250509885543Smrg#else /* SMI_USE_VIDEO */
250609885543Smrgvoid SMI_InitVideo(ScreenPtr pScreen) {}
250709885543Smrg#endif
2508