smi_video.c revision b12e5c03
1/*
2Copyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
3Copyright (C) 2000,2008 Silicon Motion, Inc.  All Rights Reserved.
4Copyright (C) 2001 Corvin Zahn.  All Rights Reserved.
5Copyright (C) 2008 Mandriva Linux.  All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of
8this software and associated documentation files (the "Software"), to deal in
9the Software without restriction, including without limitation the rights to
10use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11of the Software, and to permit persons to whom the Software is furnished to do
12so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
19NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the names of the XFree86 Project and
25Silicon Motion shall not be used in advertising or otherwise to promote the
26sale, use or other dealings in this Software without prior written
27authorization from the XFree86 Project and silicon Motion.
28*/
29
30
31/*
32  Corvin Zahn <zahn@zac.de>	Date:   2.11.2001
33    - SAA7111 support
34    - supports attributes: XV_ENCODING, XV_BRIGHTNESS, XV_CONTRAST,
35      XV_SATURATION, XV_HUE, XV_COLORKEY, XV_INTERLACED
36      XV_CAPTURE_BRIGHTNESS can be used to set brightness in the capture device
37    - bug fixes
38    - tries not to use acceleration functions
39    - interlaced video for double vertical resolution
40	XV_INTERLACED = 0: only one field of an interlaced video signal is
41			   displayed:
42			-> half vertical resolution, but no comb like artifacts
43			   from moving vertical edges
44	XV_INTERLACED = 1: both fields of an interlaced video signal are
45			   displayed:
46			-> full vertical resolution, but comb like artifacts from
47			   moving vertical edges
48	The default value can be set with the driver option Interlaced
49*/
50
51
52#ifdef HAVE_CONFIG_H
53#include "config.h"
54#endif
55
56#include "smi.h"
57#include "smi_video.h"
58
59#include "xf86Crtc.h"
60
61#undef MIN
62#undef ABS
63#undef CLAMP
64#undef ENTRIES
65
66#define MIN(a, b) (((a) < (b)) ? (a) : (b))
67#define ABS(n) (((n) < 0) ? -(n) : (n))
68#define CLAMP(v, min, max) (((v) < (min)) ? (min) : MIN(v, max))
69
70#define ENTRIES(array) (sizeof(array) / sizeof((array)[0]))
71#define nElems(x)		(sizeof(x) / sizeof(x[0]))
72
73#define MAKE_ATOM(a)	MakeAtom(a, sizeof(a) - 1, TRUE)
74
75#if SMI_USE_VIDEO
76#include "dixstruct.h"
77
78
79static int SMI_AddEncoding(XF86VideoEncodingPtr enc, int i,
80			   int norm, int input, int channel);
81static void SMI_BuildEncodings(SMI_PortPtr p);
82
83static XF86VideoAdaptorPtr SMI_SetupVideo(ScreenPtr pScreen);
84static void SMI_ResetVideo(ScrnInfoPtr pScrn);
85
86#if SMI_USE_CAPTURE
87static int SMI_PutVideo(ScrnInfoPtr pScrn,
88		short vid_x, short vid_y, short drw_x, short drw_y,
89		short vid_w, short vid_h, short drw_w, short drw_h,
90		RegionPtr clipBoxes, pointer data, DrawablePtr);
91#endif
92static void SMI_StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown);
93static int SMI_SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
94		INT32 value, pointer data);
95static int SMI_GetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
96		INT32 *value, pointer data);
97static void SMI_QueryBestSize(ScrnInfoPtr pScrn, Bool motion,
98		short vid_w, short vid_h, short drw_w, short drw_h,
99		unsigned int *p_w, unsigned int *p_h, pointer data);
100static int SMI_PutImage(ScrnInfoPtr pScrn,
101		short src_x, short src_y, short drw_x, short drw_y,
102		short src_w, short src_h, short drw_w, short drw_h,
103		int id, unsigned char *buf, short width, short height, Bool sync,
104		RegionPtr clipBoxes, pointer data, DrawablePtr);
105static int SMI_QueryImageAttributes(ScrnInfoPtr pScrn,
106		int id, unsigned short *width, unsigned short *height,
107		int *picthes, int *offsets);
108
109static void SMI_DisplayVideo(ScrnInfoPtr pScrn, int id, int offset,
110		short width, short height, int pitch, int x1, int y1, int x2, int y2,
111		BoxPtr dstBox, short vid_w, short vid_h, short drw_w, short drw_h);
112static void SMI_DisplayVideo0501_CSC(ScrnInfoPtr pScrn, int id, int offset,
113				     short width, short height, int pitch,
114				     int x1, int y1, int x2, int y2,
115				     BoxPtr dstBox, short vid_w, short vid_h,
116				     short drw_w, short drw_h,
117				     RegionPtr clipboxes);
118static void SMI_DisplayVideo0501(ScrnInfoPtr pScrn, int id, int offset,
119				 short width, short height, int pitch,
120				 int x1, int y1, int x2, int y2,
121				 BoxPtr dstBox, short vid_w, short vid_h,
122				 short drw_w, short drw_h);
123static void SMI_DisplayVideo0730(ScrnInfoPtr pScrn, int id, int offset,
124		short width, short height, int pitch, int x1, int y1, int x2, int y2,
125		BoxPtr dstBox, short vid_w, short vid_h, short drw_w, short drw_h);
126static void SMI_BlockHandler(BLOCKHANDLER_ARGS_DECL);
127/*static int SMI_SendI2C(ScrnInfoPtr pScrn, CARD8 device, char *devName,
128        SMI_I2CDataPtr i2cData);*/
129
130static void SMI_InitOffscreenImages(ScreenPtr pScreen);
131static void SMI_VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area);
132
133static void CopyYV12ToVideoMem(unsigned char *src1, unsigned char *src2,
134			       unsigned char *src3, unsigned char *dst,
135			       int src1Pitch, int src23Pitch, int dstPitch,
136			       int height, int width);
137static int SMI_AllocSurface(ScrnInfoPtr pScrn,
138		int id, unsigned short width, unsigned short height,
139		XF86SurfacePtr surface);
140static int SMI_FreeSurface(XF86SurfacePtr surface);
141static int SMI_DisplaySurface(XF86SurfacePtr surface,
142		short vid_x, short vid_y, short drw_x, short drw_y,
143		short vid_w, short vid_h, short drw_w, short drw_h,
144		RegionPtr clipBoxes);
145static int SMI_StopSurface(XF86SurfacePtr surface);
146static int SMI_GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value);
147static int SMI_SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value);
148
149static int SetAttr(ScrnInfoPtr pScrn, int i, int value);
150static int SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value);
151static int SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value);
152static void SetKeyReg(SMIPtr pSmi, int reg, int value);
153
154/**
155 * Atoms
156 */
157
158static Atom xvColorKey;
159static Atom xvEncoding;
160static Atom xvBrightness,xvCapBrightness, xvContrast, xvSaturation, xvHue;
161static Atom xvInterlaced;
162
163
164/******************************************************************************\
165**																			  **
166**                           C A P A B I L I T I E S                          **
167**																			  **
168\******************************************************************************/
169
170
171/**************************************************************************/
172/* input channels */
173
174#define N_COMPOSITE_CHANNELS 4
175#define N_SVIDEO_CHANNELS 2
176
177#define N_VIDEO_INPUTS 2
178typedef enum _VideoInput { VID_COMPOSITE, VID_SVIDEO } VideoInput;
179
180
181/**************************************************************************/
182/* video input formats */
183
184typedef struct _VideoInputDataRec {
185    char* name;
186} VideoInputDataRec;
187
188static VideoInputDataRec VideoInputs[] = {
189    { "composite" },
190    { "svideo" }
191};
192
193
194/**************************************************************************/
195/* video norms */
196
197#define N_VIDEO_NORMS 3
198typedef enum _VideoNorm { PAL, NTSC, SECAM } VideoNorm;
199
200typedef struct _VideoNormDataRec {
201    char* name;
202    unsigned long Wt;
203    unsigned long Wa;
204    unsigned long Ht;
205    unsigned long Ha;
206    unsigned long HStart;
207    unsigned long VStart;
208    XvRationalRec rate;
209} VideoNormDataRec;
210
211
212static VideoNormDataRec VideoNorms[] =
213{
214    /* PAL-BDGHI */
215    {"pal", 864, 704, 625, 576, 16, 16, { 1, 50 }},
216    /* NTSC */
217    {"ntsc", 858, 704, 525, 480, 21, 8, { 1001, 60000 }},
218    /* SECAM (not tested) */
219    {"secam", 864, 7040, 625, 576, 31, 16, { 1, 50 }},
220};
221
222
223/**************************************************************************/
224/* number of (generated) XV_ENCODING vaulues */
225#define N_ENCODINGS ((N_VIDEO_NORMS) * (N_COMPOSITE_CHANNELS + N_SVIDEO_CHANNELS))
226
227
228/**************************************************************************/
229
230static XF86VideoFormatRec SMI_VideoFormats[] =
231{
232    { 15, TrueColor },	/* depth, class				*/
233    { 16, TrueColor },	/* depth, class				*/
234    { 24, TrueColor },	/* depth, class				*/
235};
236
237
238/**************************************************************************/
239
240/**
241 * Attributes
242 */
243
244#define XV_ENCODING_NAME        "XV_ENCODING"
245#define XV_BRIGHTNESS_NAME      "XV_BRIGHTNESS"
246#define XV_CAPTURE_BRIGHTNESS_NAME      "XV_CAPTURE_BRIGHTNESS"
247#define XV_CONTRAST_NAME        "XV_CONTRAST"
248#define XV_SATURATION_NAME      "XV_SATURATION"
249#define XV_HUE_NAME             "XV_HUE"
250#define XV_COLORKEY_NAME        "XV_COLORKEY"
251#define XV_INTERLACED_NAME      "XV_INTERLACED"
252
253
254/* fixed order! */
255static XF86AttributeRec SMI_VideoAttributesSAA711x[N_ATTRS] = {
256    {XvSettable | XvGettable,        0, N_ENCODINGS-1, XV_ENCODING_NAME},
257    {XvSettable | XvGettable,        0,           255, XV_BRIGHTNESS_NAME},
258    {XvSettable | XvGettable,        0,           255, XV_CAPTURE_BRIGHTNESS_NAME},
259    {XvSettable | XvGettable,        0,           127, XV_CONTRAST_NAME},
260    {XvSettable | XvGettable,        0,           127, XV_SATURATION_NAME},
261    {XvSettable | XvGettable,     -128,           127, XV_HUE_NAME},
262    {XvSettable | XvGettable, 0x000000,      0xFFFFFF, XV_COLORKEY_NAME},
263    {XvSettable | XvGettable,        0,             1, XV_INTERLACED_NAME},
264};
265
266static XF86AttributeRec SMI_VideoAttributes[2] = {
267    {XvSettable | XvGettable,        0,           255, XV_BRIGHTNESS_NAME},
268    {XvSettable | XvGettable, 0x000000,      0xFFFFFF, XV_COLORKEY_NAME},
269};
270
271
272/**************************************************************************/
273static XF86ImageRec SMI_VideoImages[] =
274{
275    XVIMAGE_YUY2,
276    XVIMAGE_YV12,
277    XVIMAGE_I420,
278    {
279	FOURCC_RV15,			/* id				*/
280	XvRGB,				/* type				*/
281	LSBFirst,			/* byte_order			*/
282	{ 'R', 'V' ,'1', '5',
283	  0x00, '5',  0x00, 0x00,
284	  0x00, 0x00, 0x00, 0x00,
285	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
286	16,				/* bits_per_pixel		*/
287	XvPacked,			/* format			*/
288	1,				/* num_planes			*/
289	15,				/* depth			*/
290	0x001F, 0x03E0, 0x7C00,		/* red_mask, green, blue	*/
291	0, 0, 0,			/* y_sample_bits, u, v		*/
292	0, 0, 0,			/* horz_y_period, u, v		*/
293	0, 0, 0,			/* vert_y_period, u, v		*/
294	{ 'R', 'V', 'B' },		/* component_order		*/
295	XvTopToBottom			/* scaline_order		*/
296    },
297    {
298	FOURCC_RV16,			/* id				*/
299	XvRGB,				/* type				*/
300	LSBFirst,			/* byte_order			*/
301	{ 'R', 'V' ,'1', '6',
302	  0x00, 0x00, 0x00, 0x00,
303	  0x00, 0x00, 0x00, 0x00,
304	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
305	16,				/* bits_per_pixel		*/
306	XvPacked,			/* format			*/
307	1,				/* num_planes			*/
308	16,				/* depth			*/
309	0x001F, 0x07E0, 0xF800,		/* red_mask, green, blue	*/
310	0, 0, 0,			/* y_sample_bits, u, v		*/
311	0, 0, 0,			/* horz_y_period, u, v		*/
312	0, 0, 0,			/* vert_y_period, u, v		*/
313	{ 'R', 'V', 'B' },		/* component_order		*/
314	XvTopToBottom			/* scaline_order		*/
315    },
316    {
317	FOURCC_RV24,			/* id				*/
318	XvRGB,				/* type				*/
319	LSBFirst,			/* byte_order			*/
320	{ 'R', 'V' ,'2', '4',
321	  0x00, 0x00, 0x00, 0x00,
322	  0x00, 0x00, 0x00, 0x00,
323	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
324	24,				/* bits_per_pixel		*/
325	XvPacked,			/* format			*/
326	1,				/* num_planes			*/
327	24,				/* depth			*/
328	0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue	*/
329	0, 0, 0,			/* y_sample_bits, u, v		*/
330	0, 0, 0,			/* horz_y_period, u, v		*/
331	0, 0, 0,			/* vert_y_period, u, v		*/
332	{ 'R', 'V', 'B' },		/* component_order			*/
333	XvTopToBottom			/* scaline_order			*/
334    },
335    {
336	FOURCC_RV32,			/* id				*/
337	XvRGB,				/* type				*/
338	LSBFirst,			/* byte_order			*/
339	{ 'R', 'V' ,'3', '2',
340	  0x00, 0x00, 0x00, 0x00,
341	  0x00, 0x00, 0x00, 0x00,
342	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
343	32,				/* bits_per_pixel		*/
344	XvPacked,			/* format			*/
345	1,				/* num_planes			*/
346	24,				/* depth			*/
347	0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue	*/
348	0, 0, 0,			/* y_sample_bits, u, v		*/
349	0, 0, 0,			/* horz_y_period, u, v		*/
350	0, 0, 0,			/* vert_y_period, u, v		*/
351	{ 'R', 'V', 'B' },		/* component_order			*/
352	XvTopToBottom			/* scaline_order			*/
353    },
354};
355
356
357/**************************************************************************/
358static XF86ImageRec SMI501_VideoImages[] = {
359    XVIMAGE_YUY2,
360    XVIMAGE_YV12,
361    XVIMAGE_I420,
362    {
363     FOURCC_RV16,		/* id                                           */
364     XvRGB,			/* type                                         */
365     LSBFirst,			/* byte_order                           */
366     {'R', 'V', '1', '6',
367      0x00, 0x00, 0x00, 0x00,
368      0x00, 0x00, 0x00, 0x00,
369      0x00, 0x00, 0x00, 0x00},	/* guid                                         */
370     16,			/* bits_per_pixel                       */
371     XvPacked,			/* format                                       */
372     1,				/* num_planes                           */
373     16,			/* depth                                        */
374     0x001F, 0x07E0, 0xF800,	/* red_mask, green, blue        */
375     0, 0, 0,			/* y_sample_bits, u, v          */
376     0, 0, 0,			/* horz_y_period, u, v          */
377     0, 0, 0,			/* vert_y_period, u, v          */
378     {'R', 'V', 'B'},		/* component_order                      */
379     XvTopToBottom		/* scaline_order                        */
380     },
381    {
382     FOURCC_RV32,		/* id                                           */
383     XvRGB,			/* type                                         */
384     LSBFirst,			/* byte_order                           */
385     {'R', 'V', '3', '2',
386      0x00, 0x00, 0x00, 0x00,
387      0x00, 0x00, 0x00, 0x00,
388      0x00, 0x00, 0x00, 0x00},	/* guid                                         */
389     32,			/* bits_per_pixel                       */
390     XvPacked,			/* format                                       */
391     1,				/* num_planes                           */
392     24,			/* depth                                        */
393     0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue        */
394     0, 0, 0,			/* y_sample_bits, u, v          */
395     0, 0, 0,			/* horz_y_period, u, v          */
396     0, 0, 0,			/* vert_y_period, u, v          */
397     {'R', 'V', 'B'},		/* component_order                      */
398     XvTopToBottom		/* scaline_order                        */
399     },
400};
401
402/**************************************************************************/
403
404/**
405 * SAA7111 video decoder register values
406 */
407
408
409/** SAA7111 control sequences for selecting one out of four
410    composite input channels */
411static I2CByte SAA7111CompositeChannelSelect[N_COMPOSITE_CHANNELS][4] = {
412    { 0x02, 0xC0, 0x09, 0x4A}, /* CVBS AI11 */
413    { 0x02, 0xC1, 0x09, 0x4A}, /* CVBS AI12 */
414    { 0x02, 0xC2, 0x09, 0x4A}, /* CVBS AI21 */
415    { 0x02, 0xC3, 0x09, 0x4A}, /* CVBS AI22 */
416};
417
418
419/** SAA7111 control sequences for selecting one out of two
420    s-video input channels */
421static I2CByte SAA7111SVideoChannelSelect[N_SVIDEO_CHANNELS][4] = {
422    { 0x02, 0xC6, 0x09, 0xCA}, /* Y/C AI11/AI21 */
423    { 0x02, 0xC7, 0x09, 0xCA}, /* Y/C AI12/AI22 */
424};
425
426
427/** SAA7111 control sequences for selecting one out of three
428    video norms */
429static I2CByte SAA7111VideoStd[3][8] = {
430    {0x06, 108, 0x07, 108, 0x08, 0x09, 0x0E, 0x01}, /* PAL */
431    {0x06, 107, 0x07, 107, 0x08, 0x49, 0x0E, 0x01}, /* NTSC */
432    {0x06, 108, 0x07, 108, 0x08, 0x01, 0x0E, 0x51}  /* SECAM */
433};
434
435
436#if 0
437static I2CByte SAA7110InitData[] =
438{
439	/* Configuration */
440    0x00, 0x4C, 0x01, 0x3C, 0x02, 0x00, 0x03, 0xEF,
441    0x04, 0xBD, 0x05, 0xE2, 0x06, 0x00, 0x07, 0x00,
442    0x08, 0xF8, 0x09, 0xF8, 0x0A, 0x60, 0x0B, 0x60,
443    0x0C, 0x00, 0x0D, 0x80, 0x0E, 0x18, 0x0F, 0xD9,
444    0x10, 0x00, 0x11, 0x2B, 0x12, 0x40, 0x13, 0x40,
445    0x14, 0x42, 0x15, 0x1A, 0x16, 0xFF, 0x17, 0xDA,
446    0x18, 0xE6, 0x19, 0x90, 0x20, 0xD9, 0x21, 0x16,
447    0x22, 0x40, 0x23, 0x40, 0x24, 0x80, 0x25, 0x40,
448    0x26, 0x80, 0x27, 0x4F, 0x28, 0xFE, 0x29, 0x01,
449    0x2A, 0xCF, 0x2B, 0x0F, 0x2C, 0x03, 0x2D, 0x01,
450    0x2E, 0x83, 0x2F, 0x03, 0x30, 0x40, 0x31, 0x35,
451    0x32, 0x02, 0x33, 0x8C, 0x34, 0x03,
452
453	/* NTSC */
454    0x11, 0x2B, 0x0F, 0xD9,
455
456	/* RCA input connector */
457    0x06, 0x00, 0x0E, 0x18, 0x20, 0xD9, 0x21, 0x16,
458    0x22, 0x40, 0x2C, 0x03,
459
460};
461#endif
462
463static I2CByte SAA7111InitData[] =
464{
465    0x11, 0x1D, /* 0D D0=1: automatic colour killer off
466		   D1=0: DMSD data to YUV output
467		   D2=1: output enable H/V sync on
468		   D3=1: output enable YUV data on */
469    0x02, 0xC0, /* Mode 0 */
470    0x03, 0x23, /* automatic gain */
471    0x04, 0x00, /*  */
472    0x05, 0x00, /*  */
473    0x06, 108,  /* hor sync begin */
474    0x07, 108,  /* hor sync stop */
475    0x08, 0x88, /* sync control:
476		   D1-0=00: VNOI = normal mode
477		   D2=0: PLL closed
478		   D3=1: VTR mode
479		   D7=1: automatic field detection */
480    0x09, 0x41, /* 4A luminance control */
481    0x0A, 0x80, /* brightness = 128 (CCIR level) */
482    0x0B, 0x40, /* contrast = 1.0 */
483    0x0C, 0x40, /* crominance = 1.0 (CCIR level) */
484    0x0D, 0x00, /* hue = 0 */
485    0x0E, 0x01, /* chroma bandwidth = nominal
486		   fast colour time constant = nominal
487		   chrom comp filter on
488		   colour standard PAL BGHI, NTSC M */
489    0x10, 0x48, /* luminance delay compensation = 0
490		   VRLN = 1
491		   fine pos of hs = 0
492		   output format = YUV 422 */
493    0x12, 0x00, /* 20 D5=1: VPO in tristate */
494    0x13, 0x00,
495    0x15, 0x00,
496    0x16, 0x00,
497    0x17, 0x00,
498
499};
500
501
502/**************************************************************************/
503
504/**
505 * generates XF86VideoEncoding[i] with video norm norm, video input format
506 * input and video input channel channel
507 */
508static int
509SMI_AddEncoding(XF86VideoEncodingPtr enc, int i,
510		int norm, int input, int channel)
511{
512    char* norm_string;
513    char* input_string;
514    char channel_string[20];
515
516    ENTER();
517
518    norm_string = VideoNorms[norm].name;
519    input_string = VideoInputs[input].name;
520    sprintf(channel_string, "%d", channel);
521    enc[i].id     = i;
522    enc[i].name   = malloc(strlen(norm_string) +
523			   strlen(input_string) +
524			   strlen(channel_string)+3);
525    if (NULL == enc[i].name)
526	LEAVE(-1);
527
528    enc[i].width  = VideoNorms[norm].Wa;
529    enc[i].height = VideoNorms[norm].Ha;
530    enc[i].rate   = VideoNorms[norm].rate;
531    sprintf(enc[i].name,"%s-%s-%s", norm_string, input_string, channel_string);
532
533    LEAVE(0);
534}
535
536
537/**
538 * builds XF86VideoEncodings with all legal combinations of video norm,
539 * video input format and video input channel
540 */
541static void
542SMI_BuildEncodings(SMI_PortPtr p)
543{
544    int ch, n;
545
546    ENTER();
547
548    /* allocate memory for encoding array */
549    p->enc = malloc(sizeof(XF86VideoEncodingRec) * N_ENCODINGS);
550    if (NULL == p->enc)
551	goto fail;
552    memset(p->enc,0,sizeof(XF86VideoEncodingRec) * N_ENCODINGS);
553    /* allocate memory for video norm array */
554    p->norm = malloc(sizeof(int) * N_ENCODINGS);
555    if (NULL == p->norm)
556	goto fail;
557    memset(p->norm,0,sizeof(int) * N_ENCODINGS);
558    /* allocate memory for video input format array */
559    p->input = malloc(sizeof(int) * N_ENCODINGS);
560    if (NULL == p->input)
561	goto fail;
562    memset(p->input,0,sizeof(int) * N_ENCODINGS);
563    /* allocate memory for video channel number array */
564    p->channel = malloc(sizeof(int) * N_ENCODINGS);
565    if (NULL == p->channel)
566	goto fail;
567    memset(p->channel,0,sizeof(int) * N_ENCODINGS);
568
569    /* fill arrays */
570    p->nenc = 0;
571    for (ch = 0; ch < N_COMPOSITE_CHANNELS; ch++) {
572	for (n = 0; n < N_VIDEO_NORMS; n++) {
573	    SMI_AddEncoding(p->enc, p->nenc, n, VID_COMPOSITE, ch);
574	    p->norm[p->nenc]  = n;
575	    p->input[p->nenc] = VID_COMPOSITE;
576	    p->channel[p->nenc] = ch;
577	    p->nenc++;
578	}
579    }
580    for (ch = 0; ch < N_SVIDEO_CHANNELS; ch++) {
581	for (n = 0; n < N_VIDEO_NORMS; n++) {
582	    SMI_AddEncoding(p->enc, p->nenc, n, VID_SVIDEO, ch);
583	    p->norm[p->nenc]  = n;
584	    p->input[p->nenc] = VID_SVIDEO;
585	    p->channel[p->nenc] = ch;
586	    p->nenc++;
587	}
588    }
589    LEAVE();
590
591 fail:
592    free(p->input);
593    p->input = NULL;
594    free(p->norm);
595    p->norm = NULL;
596    free(p->channel);
597    p->channel = NULL;
598    free(p->enc);
599    p->enc = NULL;
600    p->nenc = 0;
601    LEAVE();
602}
603
604
605/******************************************************************************\
606**                                                                            **
607**                  X V E X T E N S I O N   I N T E R F A C E                 **
608**                                                                            **
609\******************************************************************************/
610
611void
612SMI_InitVideo(ScreenPtr pScreen)
613{
614    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
615    XF86VideoAdaptorPtr *ptrAdaptors, *newAdaptors = NULL;
616    XF86VideoAdaptorPtr newAdaptor = NULL;
617    int numAdaptors;
618
619    ENTER();
620
621    numAdaptors = xf86XVListGenericAdaptors(pScrn, &ptrAdaptors);
622
623    DEBUG("numAdaptors=%d\n", numAdaptors);
624
625    newAdaptor = SMI_SetupVideo(pScreen);
626    DEBUG("newAdaptor=%p\n", newAdaptor);
627    SMI_InitOffscreenImages(pScreen);
628
629    if (newAdaptor != NULL) {
630        if (numAdaptors == 0) {
631            numAdaptors = 1;
632            ptrAdaptors = &newAdaptor;
633        } else {
634            newAdaptors = malloc((numAdaptors + 1) *
635                    sizeof(XF86VideoAdaptorPtr*));
636            if (newAdaptors != NULL) {
637                memcpy(newAdaptors, ptrAdaptors,
638                        numAdaptors * sizeof(XF86VideoAdaptorPtr));
639                newAdaptors[numAdaptors++] = newAdaptor;
640                ptrAdaptors = newAdaptors;
641            }
642        }
643    }
644
645    if (numAdaptors != 0) {
646        DEBUG("ScreenInit %i\n",numAdaptors);
647        xf86XVScreenInit(pScreen, ptrAdaptors, numAdaptors);
648    }
649
650    free(newAdaptors);
651
652    LEAVE();
653}
654
655
656/*************************************************************************/
657
658/*
659 *  Video codec controls
660 */
661
662#if 0
663/**
664 * scales value value of attribute i to range min, max
665 */
666static int
667Scale(int i, int value, int min, int max)
668{
669    return min + (value - SMI_VideoAttributes[i].min_value) * (max - min) /
670	(SMI_VideoAttributes[i].max_value - SMI_VideoAttributes[i].min_value);
671}
672#endif
673/**
674 * sets video decoder attributes channel, encoding, brightness, contrast, saturation, hue
675 */
676static int
677SetAttr(ScrnInfoPtr pScrn, int i, int value)
678{
679    SMIPtr pSmi = SMIPTR(pScrn);
680    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
681
682    if (i < XV_ENCODING || i > XV_HUE)
683	return BadMatch;
684
685    /* clamps value to attribute range */
686    value = CLAMP(value, SMI_VideoAttributes[i].min_value,
687		  SMI_VideoAttributes[i].max_value);
688
689    if (i == XV_BRIGHTNESS) {
690	int my_value = (value <= 128? value + 128 : value - 128);
691	SetKeyReg(pSmi, 0x5C, 0xEDEDED | (my_value << 24));
692    } else if (pPort->I2CDev.SlaveAddr == SAA7110) {
693	return SetAttrSAA7110(pScrn, i, value);
694    } else if (pPort->I2CDev.SlaveAddr == SAA7111) {
695	return SetAttrSAA7111(pScrn, i, value);
696    }
697#if 0
698    else {
699	return XvBadAlloc;
700    }
701#endif
702
703    return Success;
704}
705
706
707/**
708 * sets SAA7110 video decoder attributes channel, encoding, brightness, contrast, saturation, hue
709 */
710static int
711SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value)
712{
713    /* not supported */
714    return XvBadAlloc;
715}
716
717
718/**
719 * sets SAA7111 video decoder attributes channel, encoding,
720 * brightness, contrast, saturation, hue
721 */
722static int
723SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value)
724{
725    SMIPtr pSmi = SMIPTR(pScrn);
726    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
727
728    if (i == XV_ENCODING) {
729	int norm;
730	int input;
731	int channel;
732	norm = pPort->norm[value];
733	input = pPort->input[value];
734	channel = pPort->channel[value];
735
736	DEBUG("SetAttribute XV_ENCODING: %d. norm=%d input=%d channel=%d\n",
737	      value, norm, input, channel);
738
739	/* set video norm */
740	if (!xf86I2CWriteVec(&(pPort->I2CDev), SAA7111VideoStd[norm],
741			     ENTRIES(SAA7111VideoStd[norm]) / 2)) {
742	    return XvBadAlloc;
743	}
744	/* set video input format and channel */
745	if (input == VID_COMPOSITE) {
746	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
747				 SAA7111CompositeChannelSelect[channel],
748				 ENTRIES(SAA7111CompositeChannelSelect[channel]) / 2)) {
749		return XvBadAlloc;
750	    }
751	} else {
752	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
753				 SAA7111SVideoChannelSelect[channel],
754				 ENTRIES(SAA7111SVideoChannelSelect[channel]) / 2)) {
755		return XvBadAlloc;
756	    }
757	}
758    } else if (i >= XV_CAPTURE_BRIGHTNESS && i <= XV_HUE) {
759	int slave_adr = 0;
760
761	switch (i) {
762
763	case XV_CAPTURE_BRIGHTNESS:
764	    DEBUG("SetAttribute XV_BRIGHTNESS: %d\n", value);
765	    slave_adr = 0x0a;
766	    break;
767
768	case XV_CONTRAST:
769	    DEBUG("SetAttribute XV_CONTRAST: %d\n", value);
770	    slave_adr = 0x0b;
771	    break;
772
773	case XV_SATURATION:
774	    DEBUG("SetAttribute XV_SATURATION: %d\n", value);
775	    slave_adr = 0x0c;
776	    break;
777
778	case XV_HUE:
779	    DEBUG("SetAttribute XV_HUE: %d\n", value);
780	    slave_adr = 0x0d;
781	    break;
782
783	default:
784	    return XvBadAlloc;
785	}
786	if (!xf86I2CWriteByte(&(pPort->I2CDev), slave_adr, (value & 0xff)))
787	    return XvBadAlloc;
788    } else {
789	return BadMatch;
790    }
791
792    /* debug: show registers */
793    {
794	I2CByte i2c_bytes[32];
795	int i;
796	xf86I2CReadBytes(&(pPort->I2CDev), 0, i2c_bytes, 32);
797	DEBUG("SAA7111 Registers\n");
798	for (i=0; i<32; i++) {
799	    DEBUG("%02X=%02X ", i, i2c_bytes[i]);
800	    if ((i&7) == 7) DEBUG("\n");
801	}
802    }
803
804    return Success;
805}
806
807
808/******************************************************************************\
809**									      **
810**	V I D E O   M A N A G E M E N T					      **
811**									      **
812\******************************************************************************/
813
814static XF86VideoAdaptorPtr
815SMI_SetupVideo(ScreenPtr pScreen)
816{
817    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
818    SMIPtr pSmi = SMIPTR(pScrn);
819    SMI_PortPtr smiPortPtr;
820    XF86VideoAdaptorPtr ptrAdaptor;
821
822    ENTER();
823
824    ptrAdaptor = calloc(1, sizeof(XF86VideoAdaptorRec) +
825		 sizeof(DevUnion) + sizeof(SMI_PortRec));
826    if (ptrAdaptor == NULL)
827	LEAVE(NULL);
828
829    ptrAdaptor->type = XvInputMask
830#if SMI_USE_CAPTURE
831		     | XvOutputMask
832		     | XvVideoMask
833#endif
834		     | XvImageMask
835		     | XvWindowMask
836		     ;
837
838    ptrAdaptor->flags = VIDEO_OVERLAID_IMAGES;
839    if (IS_MSOC(pSmi)) {
840	ptrAdaptor->name = "Silicon Motion MSOC Series Video Engine";
841    }
842    else
843	ptrAdaptor->name = "Silicon Motion Lynx Series Video Engine";
844
845    ptrAdaptor->nPorts = 1;
846    ptrAdaptor->pPortPrivates = (DevUnion*) &ptrAdaptor[1];
847    ptrAdaptor->pPortPrivates[0].ptr = (pointer) &ptrAdaptor->pPortPrivates[1];
848
849    smiPortPtr = (SMI_PortPtr) ptrAdaptor->pPortPrivates[0].ptr;
850
851    SMI_BuildEncodings(smiPortPtr);
852    ptrAdaptor->nEncodings = smiPortPtr->nenc;
853    ptrAdaptor->pEncodings = smiPortPtr->enc;
854#if 0
855    /* aaa whats this? */
856	for (i = 0; i < nElems(SMI_VideoEncodings); i++)
857	{
858		SMI_VideoEncodings[i].width = pSmi->lcdWidth;
859		SMI_VideoEncodings[i].height = pSmi->lcdHeight;
860	}
861#endif
862
863    ptrAdaptor->nFormats = nElems(SMI_VideoFormats);
864    ptrAdaptor->pFormats = SMI_VideoFormats;
865
866    ptrAdaptor->nAttributes = nElems(SMI_VideoAttributes);
867    ptrAdaptor->pAttributes = SMI_VideoAttributes;
868
869    if (IS_MSOC(pSmi)) {
870	ptrAdaptor->nImages = nElems(SMI501_VideoImages);
871	ptrAdaptor->pImages = SMI501_VideoImages;
872    }
873    else {
874	ptrAdaptor->nImages = nElems(SMI_VideoImages);
875	ptrAdaptor->pImages = SMI_VideoImages;
876    }
877
878#if SMI_USE_CAPTURE
879    if (pSmi->Chipset == SMI_COUGAR3DR || IS_MSOC(pSmi))
880	ptrAdaptor->PutVideo = NULL;
881    else
882	ptrAdaptor->PutVideo = SMI_PutVideo;
883    ptrAdaptor->PutStill = NULL;
884    ptrAdaptor->GetVideo = NULL;
885    ptrAdaptor->GetStill = NULL;
886#else
887    ptrAdaptor->PutVideo = NULL;
888    ptrAdaptor->PutStill = NULL;
889    ptrAdaptor->GetVideo = NULL;
890    ptrAdaptor->GetStill = NULL;
891#endif
892    ptrAdaptor->StopVideo = SMI_StopVideo;
893    ptrAdaptor->SetPortAttribute = SMI_SetPortAttribute;
894    ptrAdaptor->GetPortAttribute = SMI_GetPortAttribute;
895    ptrAdaptor->QueryBestSize = SMI_QueryBestSize;
896    ptrAdaptor->PutImage = SMI_PutImage;
897    ptrAdaptor->QueryImageAttributes = SMI_QueryImageAttributes;
898
899    smiPortPtr->Attribute[XV_COLORKEY] = pSmi->videoKey;
900    smiPortPtr->Attribute[XV_INTERLACED] = pSmi->interlaced;
901    smiPortPtr->videoStatus = 0;
902
903#if 0
904    /* aaa does not work ? */
905    if (xf86I2CProbeAddress(pSmi->I2C, SAA7111))
906        LEAVE(NULL);
907    DEBUG("SAA7111 detected\n");
908#endif
909
910    smiPortPtr->I2CDev.DevName = "SAA 7111A";
911    smiPortPtr->I2CDev.SlaveAddr = SAA7111;
912    smiPortPtr->I2CDev.pI2CBus = pSmi->I2C;
913
914
915    if (!IS_MSOC(pSmi) && xf86I2CDevInit(&(smiPortPtr->I2CDev))) {
916
917	if (xf86I2CWriteVec(&(smiPortPtr->I2CDev), SAA7111InitData, ENTRIES(SAA7111InitData) / 2)) {
918	    xvEncoding   = MAKE_ATOM(XV_ENCODING_NAME);
919	    xvHue        = MAKE_ATOM(XV_HUE_NAME);
920	    xvSaturation = MAKE_ATOM(XV_SATURATION_NAME);
921	    xvContrast   = MAKE_ATOM(XV_CONTRAST_NAME);
922
923	    xvInterlaced = MAKE_ATOM(XV_INTERLACED_NAME);
924	    DEBUG("SAA7111 intialized\n");
925
926	} else {
927	    xf86DestroyI2CDevRec(&(smiPortPtr->I2CDev),FALSE);
928	    smiPortPtr->I2CDev.SlaveAddr = 0;
929	}
930    } else
931	smiPortPtr->I2CDev.SlaveAddr = 0;
932
933#if defined(REGION_NULL)
934    REGION_NULL(pScreen, &smiPortPtr->clip);
935#else
936    REGION_INIT(pScreen, &smiPortPtr->clip, NullBox, 0);
937#endif
938
939    pSmi->ptrAdaptor = ptrAdaptor;
940    pSmi->BlockHandler = pScreen->BlockHandler;
941    pScreen->BlockHandler = SMI_BlockHandler;
942
943    xvColorKey   = MAKE_ATOM(XV_COLORKEY_NAME);
944    xvBrightness = MAKE_ATOM(XV_BRIGHTNESS_NAME);
945    xvCapBrightness = MAKE_ATOM(XV_CAPTURE_BRIGHTNESS_NAME);
946
947    SMI_ResetVideo(pScrn);
948
949    LEAVE(ptrAdaptor);
950}
951
952
953static void
954SMI_ResetVideo(ScrnInfoPtr pScrn)
955{
956    SMIPtr pSmi = SMIPTR(pScrn);
957    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
958    int r, g, b;
959
960    ENTER();
961
962    SetAttr(pScrn, XV_ENCODING, 0);     /* Encoding = pal-composite-0 */
963    SetAttr(pScrn, XV_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
964    SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
965    SetAttr(pScrn, XV_CONTRAST, 71);    /* Contrast = 71 (CCIR level) */
966    SetAttr(pScrn, XV_SATURATION, 64);  /* Color saturation = 64 (CCIR level) */
967    SetAttr(pScrn, XV_HUE, 0);          /* Hue = 0 */
968
969    switch (pScrn->depth) {
970    case 8:
971	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0x00FF);
972	SetKeyReg(pSmi, FPR08, 0);
973	break;
974    case 15:
975    case 16:
976	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0xFFFF);
977	SetKeyReg(pSmi, FPR08, 0);
978	break;
979    default:
980        r = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.red) >> pScrn->offset.red;
981        g = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.green) >> pScrn->offset.green;
982        b = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.blue) >> pScrn->offset.blue;
983	SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
984	SetKeyReg(pSmi, FPR08, 0);
985	break;
986    }
987
988    SetKeyReg(pSmi, FPR5C, 0xEDEDED | (pPort->Attribute[XV_BRIGHTNESS] << 24));
989
990    LEAVE();
991}
992
993
994#if SMI_USE_CAPTURE
995static int
996SMI_PutVideo(
997	ScrnInfoPtr	pScrn,
998	short		vid_x,
999	short		vid_y,
1000	short		drw_x,
1001	short		drw_y,
1002	short		vid_w,
1003	short		vid_h,
1004	short		drw_w,
1005	short		drw_h,
1006	RegionPtr	clipBoxes,
1007	pointer		data,
1008	DrawablePtr	pDraw
1009)
1010{
1011    SMI_PortPtr pPort = (SMI_PortPtr) data;
1012    SMIPtr pSmi = SMIPTR(pScrn);
1013    CARD32 vid_pitch, vid_address;
1014    CARD32 vpr00, cpr00;
1015    int xscale, yscale;
1016    BoxRec dstBox;
1017    INT32 x1, y1, x2, y2;
1018    int norm;
1019    int size, width, height, fbPitch;
1020    int top, left;
1021    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1022    xf86CrtcPtr crtc;
1023
1024    ENTER();
1025
1026    DEBUG("Interlaced Video %d\n", pPort->Attribute[XV_INTERLACED]);
1027
1028    if (!pPort->Attribute[XV_INTERLACED]) {
1029	/* no interlace: lines will be doubled */
1030	vid_h /= 2;
1031    }
1032
1033    /* field start aaa*/
1034    norm = pPort->norm[pPort->Attribute[XV_ENCODING]];
1035    vid_x += VideoNorms[norm].HStart;
1036    vid_y += VideoNorms[norm].VStart;
1037    /* only even values allowed (UV-phase) */
1038    vid_x &= ~1;
1039
1040    DEBUG("vid_x=%d vid_y=%d drw_x=%d drw_y=%d  "
1041	  "vid_w=%d vid_h=%d drw_w=%d drw_h=%d\n",
1042	  vid_x, vid_y, drw_x, drw_y, vid_w, vid_h, drw_w, drw_h);
1043
1044    x1 = vid_x;
1045    y1 = vid_y;
1046    x2 = vid_x + vid_w;
1047    y2 = vid_y + vid_h;
1048
1049    width = vid_w;
1050    height = vid_h;
1051
1052    dstBox.x1 = drw_x;
1053    dstBox.y1 = drw_y;
1054    dstBox.x2 = drw_x + drw_w;
1055    dstBox.y2 = drw_y + drw_h;
1056
1057    if(!xf86_crtc_clip_video_helper(pScrn, &crtc, crtcConf->crtc[0], &dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height))
1058	LEAVE(Success);
1059
1060    if (crtc != crtcConf->crtc[0])
1061	LEAVE(Success);
1062
1063    /* Transform dstBox to the CRTC coordinates */
1064    dstBox.x1 -= crtc->x;
1065    dstBox.y1 -= crtc->y;
1066    dstBox.x2 -= crtc->x;
1067    dstBox.y2 -= crtc->y;
1068
1069    DEBUG("Clip: x1=%d y1=%d x2=%d y2=%d\n",  x1 >> 16, y1 >> 16, x2 >> 16, y2 >> 16);
1070
1071    vid_pitch = (vid_w * 2 + 7) & ~7;
1072
1073    vpr00 = READ_VPR(pSmi, 0x00) & ~0x0FF000FF;
1074    cpr00 = READ_CPR(pSmi, 0x00) & ~0x000FFF00;
1075
1076    /* vpr00:
1077       Bit 2..0   = 6: Video Window I Format                    = YUV4:2:2
1078       Bit 3      = 1: Video Window I Enable                    = enabled
1079       Bit 4      = 0: Video Window I YUV Averaging             = disabled
1080       Bit 5      = 0: Video Window I Hor. Replication          = disabled
1081       Bit 6      = 0: Video Window I data doubling             = disabled
1082       Bit 14..8  = 0: Video Window II                          = disabled
1083       Bit 18..16 = 0: Graphics Data Format                     = 8-bit index
1084       Bit 19     = 0: Top Video Window Select                  = window I
1085       Bit 20     = 1: Color Key for Window I                   = enabled
1086       Bit 21     = 0: Vertical Interpolation                   = s. below
1087       Bit 22     = 0: Flicker Reduction for TV Modes           = disabled
1088       Bit 23     = 0: Fixed Vertical Interpolation             = disabled
1089       Bit 24     = 1: Select Video Window I Source Addr        =
1090       Bit 25     = 0: Enable V0FIFO to fetch 8-Bit color data  = disabled
1091       Bit 26     = 0:
1092       Bit 27     = 1: Color Key for Window II                  = disabled
1093       Bit 31..28 = reserved
1094    */
1095    if (pPort->Attribute[XV_INTERLACED]) {
1096	/*
1097	  Bit 21     = 0: Vertical Interpolation                   = disabled
1098	  Bit 24     = 0: Select Video Window I Source Addr        = 0
1099	*/
1100	vpr00 |= 0x0010000E;
1101    } else {
1102	/*
1103	  Bit 21     = 1: Vertical Interpolation                   = enabled
1104	  Bit 24     = 1: Select Video Window I Source Addr        = 1
1105	  1= Video window I source addr = capture port buffer ?
1106	*/
1107	vpr00 |= 0x0130000E;
1108    }
1109
1110    /* cpr00:
1111       Bit 0      = 1: Video Capture Enable                     = enabled
1112       Bit 8      = 0: Capture Control                          = continous
1113       Bit 9      = 0: Double Buffer Enable                     = s. below
1114       Bit 10     = 0: Interlace Data Capture                   = s. below
1115       Bit 13..11 = 0: Frame Skip Enable                        = s. below
1116       Bit 15..14 = 0: Video Capture Input Format               = YUV4:2:2
1117       Bit 17..16 = 0: Enable Hor. Reduction                    = s. below
1118       Bit 19..18 = 0: Enable Vert. Reduction                   = s. below
1119       Bit 21..20 = 0: Enable Hor. Filtering                    = s. below
1120       Bit 22     = 0: HREF Polarity                            = high active
1121       Bit 23     = 0: VREF Polarity                            = high active
1122       Bit 24     = 1: Field Detection Method VSYNC edge        = rising
1123    */
1124    if (pPort->Attribute[XV_INTERLACED]) {
1125	/*
1126	  Bit 9      = 1: Double Buffer Enable                  = enabled
1127	  Bit 10     = 1: Interlace Data Capture                = enabled
1128	  Bit 13..11 = 0: Frame Skip Enable                     = no skip
1129	*/
1130	cpr00 |= 0x01000601;
1131    } else {
1132	/*
1133	  Bit 9      = 0: Double Buffer Enable                  = disabled
1134	  Bit 10     = 0: Interlace Data Capture                = disabled
1135	  Bit 13..11 = 010: Frame Skip Enable                   = skip every other frame
1136	*/
1137	cpr00 |= 0x01001001;
1138    }
1139
1140    if (pSmi->ByteSwap)
1141	cpr00 |= 0x00004000;
1142
1143    fbPitch = (pScrn->displayWidth * pSmi->Bpp + 15) & ~15;
1144
1145    if (vid_w <= drw_w) {
1146	xscale = (256 * vid_w / drw_w) & 0xFF;
1147    } else if (vid_w / 2 <= drw_w) {
1148	xscale = (128 * vid_w / drw_w) & 0xFF;
1149	width /= 2;
1150	vid_pitch /= 2;
1151	cpr00 |= 0x00010000;
1152    } else if (vid_w / 4 <= drw_w) {
1153	xscale = (64 * vid_w / drw_w) & 0xFF;
1154	width /= 4;
1155	vid_pitch /= 4;
1156	cpr00 |= 0x00020000;
1157    } else {
1158	xscale = 0;
1159	width /= 4;
1160	vid_pitch /= 4;
1161	cpr00 |= 0x00020000;
1162    }
1163
1164    if (vid_h <= drw_h) {
1165	yscale = (256 * vid_h / drw_h) & 0xFF;
1166    } else if (vid_h / 2 <= drw_h) {
1167	yscale = (128 * vid_h / drw_h) & 0xFF;
1168	height /= 2;
1169	cpr00 |= 0x00040000;
1170    } else if (vid_h / 4 <= drw_h) {
1171	yscale = (64 * vid_h / drw_h) & 0xFF;
1172	height /= 4;
1173	cpr00 |= 0x00080000;
1174    } else {
1175	yscale = 0;
1176	height /= 4;
1177	cpr00 |= 0x00080000;
1178    }
1179
1180    do {
1181	size = vid_pitch * height;
1182	DEBUG("SMI_AllocateMemory: vid_pitch=%d height=%d size=%d\n",
1183	      vid_pitch, height, size);
1184	pPort->video_offset = SMI_AllocateMemory(pScrn, &pPort->video_memory, size);
1185        if (pPort->video_offset == 0) {
1186	    if ((cpr00 & 0x000C0000) == 0) {
1187		/* height -> 1/2 height */
1188		yscale = (128 * vid_h / drw_h) & 0xFF;
1189		height = vid_h / 2;
1190		cpr00 |= 0x00040000;
1191	    } else if (cpr00 & 0x00040000) {
1192		/* 1/2 height -> 1/4 height */
1193		yscale = (64 * vid_h / drw_h) & 0xFF;
1194		height = vid_h / 4;
1195		cpr00 ^= 0x000C0000;
1196	    } else {
1197		/* 1/4 height */
1198		if ((cpr00 & 0x00030000) == 0) {
1199		    /* width -> 1/2 width */
1200		    xscale = (128 * vid_w / drw_w) & 0xFF;
1201		    width = vid_w / 2;
1202		    cpr00 |= 0x00010000;
1203		} else if (cpr00 & 0x00010000) {
1204		    /* 1/2 width -> 1/4 width */
1205		    xscale = (64 * vid_w / drw_w) & 0xFF;
1206		    width = vid_w / 4;
1207		    cpr00 ^= 0x00030000;
1208		} else {
1209		    DEBUG("allocate error\n");
1210		    LEAVE(BadAlloc);
1211		}
1212	    }
1213	}
1214    } while (pPort->video_offset == 0);
1215
1216    DEBUG("xscale==%d yscale=%d width=%d height=%d\n",
1217	  xscale, yscale, width, height);
1218
1219    /* aaa whats this                     ----------------------v ?
1220    vid_address = (pPort->area->box.y1 * fbPitch) + ((y1 >> 16) * vid_pitch);*/
1221    vid_address = pPort->video_offset;
1222
1223    DEBUG("test RegionsEqual\n");
1224    if (!REGION_EQUAL(pScrn->pScreen, &pPort->clip, clipBoxes))
1225    {
1226	DEBUG((VERBLEV, "RegionCopy\n"));
1227        REGION_COPY(pScrn->pScreen, &pPort->clip, clipBoxes);
1228	DEBUG("FillKey\n");
1229	xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY], clipBoxes);
1230
1231    }
1232
1233    left = x1 >> 16;
1234    top = y1 >> 16;
1235    width = (x2 - x1) >> 16;
1236    height = (y2 - y1) >> 16;
1237
1238    if (!IS_MSOC(pSmi))
1239	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1240		      0x21,
1241		      VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1242				   0x21) & ~0x04);
1243    WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) | 0x00200000);
1244    /* Video Window I Left and Top Boundaries */
1245    WRITE_VPR(pSmi, 0x14, dstBox.x1 + (dstBox.y1 << 16));
1246    /* Video Window I Right and Bottom Boundaries */
1247    WRITE_VPR(pSmi, 0x18, dstBox.x2 + (dstBox.y2 << 16));
1248    /* Video Window I Source Width and Offset */
1249    WRITE_VPR(pSmi, 0x20, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1250    /* Video Window I Stretch Factor */
1251    WRITE_VPR(pSmi, 0x24, (xscale << 8) + yscale);
1252
1253    if (pPort->Attribute[XV_INTERLACED]) {
1254	/* Video Window II Left and Top Boundaries */
1255	WRITE_VPR(pSmi, 0x28, dstBox.x1 + (dstBox.y1 << 16));
1256	/* Video Window II Right and Bottom Boundaries */
1257	WRITE_VPR(pSmi, 0x2C, dstBox.x2 + (dstBox.y2 << 16));
1258	/* Video Window II Source Width and Offset */
1259	WRITE_VPR(pSmi, 0x34, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1260	/* Video Window II Stretch Factor */
1261	WRITE_VPR(pSmi, 0x38, (xscale << 8) + yscale);
1262
1263	/* Video Window I Source Start Address */
1264	WRITE_VPR(pSmi, 0x1C, vid_address / 8);
1265	/* Video Window II Source Start Address */
1266	WRITE_VPR(pSmi, 0x30, vid_address / 8);
1267
1268	/* Video Window I Source Start Address */
1269	WRITE_VPR(pSmi, 0x48, vid_address / 8);
1270	/* Video Window II Source Start Address */
1271	WRITE_VPR(pSmi, 0x4C, vid_address / 8 + vid_pitch / 8);
1272
1273	/* Video Source Clipping Control */
1274	WRITE_CPR(pSmi, 0x04, left + ((top/2) << 16));
1275	/* Video Source Capture Size Control */
1276	WRITE_CPR(pSmi, 0x08, width + ((height/2) << 16));
1277	/* Capture Port Buffer I Source Start Address */
1278	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
1279	/* Capture Port Buffer II Source Start Address */
1280	WRITE_CPR(pSmi, 0x10, vid_address / 8 + vid_pitch / 8);
1281	/* Capture Port Source Offset Address */
1282	WRITE_CPR(pSmi, 0x14, 2*(vid_pitch / 8) + ((2*(vid_pitch / 8)) << 16));
1283    } else {
1284	/* Video Source Clipping Control */
1285	WRITE_CPR(pSmi, 0x04, left + (top << 16));
1286	/* Video Source Capture Size Control */
1287	WRITE_CPR(pSmi, 0x08, width + (height << 16));
1288	/* Capture Port Buffer I Source Start Address */
1289	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
1290	/* Capture Port Buffer II Source Start Address */
1291	WRITE_CPR(pSmi, 0x10, vid_address / 8);
1292	/* Capture Port Source Offset Address */
1293	WRITE_CPR(pSmi, 0x14, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1294    }
1295
1296    WRITE_CPR(pSmi, 0x00, cpr00);
1297    WRITE_VPR(pSmi, 0x00, vpr00);
1298
1299    pPort->videoStatus = CLIENT_VIDEO_ON;
1300    DEBUG("SMI_PutVideo success\n");
1301
1302    LEAVE(Success);
1303}
1304#endif
1305
1306
1307static void
1308SMI_StopVideo(
1309	ScrnInfoPtr	pScrn,
1310	pointer		data,
1311	Bool		shutdown
1312)
1313{
1314    SMI_PortPtr pPort = (SMI_PortPtr) data;
1315    SMIPtr pSmi = SMIPTR(pScrn);
1316
1317    ENTER();
1318
1319    REGION_EMPTY(pScrn->pScreen, &pPort->clip);
1320
1321    if (shutdown) {
1322	if (pPort->videoStatus & CLIENT_VIDEO_ON) {
1323	    if (pSmi->Chipset == SMI_COUGAR3DR)
1324		WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
1325	    else if (IS_MSOC(pSmi))
1326		WRITE_DCR(pSmi, 0x0040, READ_DCR(pSmi, 0x0040) & ~0x00000004);
1327	    else
1328		WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x01000008);
1329#if SMI_USE_CAPTURE
1330	    if (!IS_MSOC(pSmi) && pSmi->Chipset != SMI_COUGAR3DR) {
1331		WRITE_CPR(pSmi, 0x00, READ_CPR(pSmi, 0x00) & ~0x00000001);
1332		WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) & ~0x00F00000);
1333	    }
1334#endif
1335	}
1336        if (pPort->video_memory != NULL) {
1337            SMI_FreeMemory(pScrn, pPort->video_memory);
1338            pPort->video_memory = NULL;
1339	}
1340        pPort->videoStatus = 0;
1341        /* pPort->i2cDevice = 0;aaa*/
1342    } else {
1343        if (pPort->videoStatus & CLIENT_VIDEO_ON) {
1344            pPort->videoStatus |= OFF_TIMER;
1345            pPort->offTime = currentTime.milliseconds + OFF_DELAY;
1346	}
1347    }
1348
1349    LEAVE();
1350}
1351
1352static int
1353SMI_SetPortAttribute(
1354	ScrnInfoPtr	pScrn,
1355	Atom		attribute,
1356	INT32		value,
1357	pointer		data
1358)
1359{
1360    int res;
1361    SMI_PortPtr pPort = (SMI_PortPtr) data;
1362    SMIPtr pSmi = SMIPTR(pScrn);
1363
1364    ENTER();
1365
1366    if (attribute == xvColorKey) {
1367	int r, g, b;
1368
1369        pPort->Attribute[XV_COLORKEY] = value;
1370	switch (pScrn->depth) {
1371	case 8:
1372	    SetKeyReg(pSmi, FPR04, value & 0x00FF);
1373	    break;
1374	case 15:
1375	case 16:
1376	    SetKeyReg(pSmi, FPR04, value & 0xFFFF);
1377	    break;
1378	default:
1379	    r = (value & pScrn->mask.red) >> pScrn->offset.red;
1380	    g = (value & pScrn->mask.green) >> pScrn->offset.green;
1381	    b = (value & pScrn->mask.blue) >> pScrn->offset.blue;
1382	    SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
1383	    break;
1384	}
1385	res = Success;
1386    } else if (attribute == xvInterlaced) {
1387        pPort->Attribute[XV_INTERLACED] = (value != 0);
1388	res = Success;
1389    } else if (attribute == xvEncoding) {
1390        res = SetAttr(pScrn, XV_ENCODING, value);
1391    } else if (attribute == xvBrightness) {
1392        res = SetAttr(pScrn, XV_BRIGHTNESS, value);
1393    } else if (attribute == xvCapBrightness) {
1394        res = SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, value);
1395    } else if (attribute == xvContrast) {
1396        res = SetAttr(pScrn, XV_CONTRAST, value);
1397    } else if (attribute == xvSaturation) {
1398        res = SetAttr(pScrn, XV_SATURATION, value);
1399    } else if (attribute == xvHue) {
1400        res = SetAttr(pScrn, XV_HUE, value);
1401    } else {
1402        res = BadMatch;
1403    }
1404
1405    LEAVE(res);
1406}
1407
1408
1409static int
1410SMI_GetPortAttribute(
1411	ScrnInfoPtr	pScrn,
1412	Atom		attribute,
1413	INT32		*value,
1414	pointer		data
1415)
1416{
1417    SMI_PortPtr pPort = (SMI_PortPtr) data;
1418
1419    ENTER();
1420    if (attribute == xvEncoding)
1421        *value = pPort->Attribute[XV_ENCODING];
1422    else if (attribute == xvBrightness)
1423        *value = pPort->Attribute[XV_BRIGHTNESS];
1424    else if (attribute == xvCapBrightness)
1425        *value = pPort->Attribute[XV_CAPTURE_BRIGHTNESS];
1426    else if (attribute == xvContrast)
1427        *value = pPort->Attribute[XV_CONTRAST];
1428    else if (attribute == xvSaturation)
1429        *value = pPort->Attribute[XV_SATURATION];
1430    else if (attribute == xvHue)
1431        *value = pPort->Attribute[XV_HUE];
1432    else if (attribute == xvColorKey)
1433        *value = pPort->Attribute[XV_COLORKEY];
1434    else
1435	LEAVE(BadMatch);
1436
1437    LEAVE(Success);
1438}
1439
1440
1441static void
1442SMI_QueryBestSize(
1443	ScrnInfoPtr		pScrn,
1444	Bool			motion,
1445	short			vid_w,
1446	short			vid_h,
1447	short			drw_w,
1448	short			drw_h,
1449	unsigned int	*p_w,
1450	unsigned int	*p_h,
1451	pointer			data
1452)
1453{
1454    SMIPtr pSmi = SMIPTR(pScrn);
1455
1456    ENTER();
1457
1458    *p_w = min(drw_w, pSmi->lcdWidth);
1459    *p_h = min(drw_h, pSmi->lcdHeight);
1460
1461    LEAVE();
1462}
1463
1464
1465static int
1466SMI_PutImage(
1467	ScrnInfoPtr		pScrn,
1468	short			src_x,
1469	short			src_y,
1470	short			drw_x,
1471	short			drw_y,
1472	short			src_w,
1473	short			src_h,
1474	short			drw_w,
1475	short			drw_h,
1476	int			id,
1477	unsigned char		*buf,
1478	short			width,
1479	short			height,
1480	Bool			sync,
1481	RegionPtr		clipBoxes,
1482	pointer			data,
1483	DrawablePtr		pDraw
1484)
1485{
1486    SMIPtr pSmi = SMIPTR(pScrn);
1487    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
1488    INT32 x1, y1, x2, y2;
1489    int bpp = 0;
1490    int srcPitch, srcPitch2 = 0, dstPitch, size;
1491    BoxRec dstBox;
1492    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
1493    int left, top, nPixels, nLines;
1494    unsigned char *dstStart;
1495    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1496    xf86CrtcPtr crtc;
1497
1498    ENTER();
1499
1500    x1 = src_x;
1501    y1 = src_y;
1502    x2 = src_x + src_w;
1503    y2 = src_y + src_h;
1504
1505    dstBox.x1 = drw_x;
1506    dstBox.y1 = drw_y;
1507    dstBox.x2 = drw_x + drw_w;
1508    dstBox.y2 = drw_y + drw_h;
1509
1510    if (pSmi->CSCVideo) {
1511	if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
1512				   width, height))
1513	    LEAVE(Success);
1514    }
1515    else {
1516	if (!xf86_crtc_clip_video_helper(pScrn, &crtc, crtcConf->crtc[0], &dstBox,
1517					 &x1, &x2, &y1, &y2, clipBoxes,
1518					 width, height))
1519	    LEAVE(Success);
1520
1521	if (!crtc)
1522	    LEAVE(Success);
1523
1524	/* Transform dstBox to the CRTC coordinates */
1525	dstBox.x1 -= crtc->x;
1526	dstBox.y1 -= crtc->y;
1527	dstBox.x2 -= crtc->x;
1528	dstBox.y2 -= crtc->y;
1529    }
1530
1531    switch (id) {
1532    case FOURCC_YV12:
1533    case FOURCC_I420:
1534	srcPitch  = (width + 3) & ~3;
1535	offset2   = srcPitch * height;
1536	srcPitch2 = ((width >> 1) + 3) & ~3;
1537	offset3   = offset2 + (srcPitch2 * (height >> 1));
1538	if (pSmi->CSCVideo)
1539	    dstPitch  = (((width >> 1) + 15) & ~15) << 1;
1540	else
1541	    dstPitch  = ((width << 1) + 15) & ~15;
1542	break;
1543    case FOURCC_RV24:
1544	bpp = 3;
1545	srcPitch = width * bpp;
1546	dstPitch = (srcPitch + 15) & ~15;
1547	break;
1548    case FOURCC_RV32:
1549	bpp = 4;
1550	srcPitch = width * bpp;
1551	dstPitch = (srcPitch + 15) & ~15;
1552	break;
1553    case FOURCC_YUY2:
1554    case FOURCC_RV15:
1555    case FOURCC_RV16:
1556    default:
1557	bpp = 2;
1558	srcPitch = width * bpp;
1559	dstPitch = (srcPitch + 15) & ~15;
1560	break;
1561    }
1562
1563    size = dstPitch * height;
1564    pPort->video_offset = SMI_AllocateMemory(pScrn, &pPort->video_memory, size);
1565    if (pPort->video_memory == NULL)
1566	LEAVE(BadAlloc);
1567
1568    top = y1 >> 16;
1569    left = (x1 >> 16) & ~1;
1570    nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left;
1571    left *= bpp;
1572
1573    offset = pPort->video_offset + (top * dstPitch);
1574    dstStart = pSmi->FBBase + offset + left;
1575
1576    switch(id) {
1577    case FOURCC_YV12:
1578    case FOURCC_I420:
1579	top &= ~1;
1580	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
1581	offset2 += tmp;
1582	offset3 += tmp;
1583	if (pSmi->CSCVideo)
1584	    CopyYV12ToVideoMem(buf,
1585			       buf + offset2, buf + offset3,
1586			       dstStart, srcPitch, srcPitch2, dstPitch,
1587			       height, width);
1588	else {
1589	    if (id == FOURCC_I420) {
1590		tmp = offset2;
1591		offset2 = offset3;
1592		offset3 = tmp;
1593	    }
1594	    nLines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
1595	    xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
1596				    buf + offset2, buf + offset3, dstStart,
1597				    srcPitch, srcPitch2, dstPitch, nLines,
1598				    nPixels);
1599	}
1600	break;
1601    case FOURCC_UYVY:
1602    case FOURCC_YUY2:
1603    default:
1604	buf += (top * srcPitch) + left;
1605	nLines = ((y2 + 0xffff) >> 16) - top;
1606	xf86XVCopyPacked(buf, dstStart, srcPitch, dstPitch, nLines, nPixels);
1607        break;
1608    }
1609
1610    if (IS_MSOC(pSmi) ||
1611	!REGION_EQUAL(pScrn->pScreen, &pPort->clip, clipBoxes)) {
1612	REGION_COPY(pScrn->pScreen, &pPort->clip, clipBoxes);
1613	if (!pSmi->CSCVideo)
1614	    xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY],
1615				clipBoxes);
1616    }
1617
1618    if (pSmi->Chipset == SMI_COUGAR3DR)
1619	SMI_DisplayVideo0730(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2,
1620			     &dstBox, src_w, src_h, drw_w, drw_h);
1621    else if (IS_MSOC(pSmi)) {
1622	if (pSmi->CSCVideo)
1623	    SMI_DisplayVideo0501_CSC(pScrn, id, offset, width, height, dstPitch,
1624				     x1, y1, x2, y2, &dstBox,
1625				     src_w, src_h, drw_w, drw_h, clipBoxes);
1626	else
1627	    SMI_DisplayVideo0501(pScrn, id, offset, width, height, dstPitch,
1628				 x1, y1, x2, y2, &dstBox, src_w, src_h,
1629				 drw_w, drw_h);
1630    }
1631    else{
1632	if(crtc == crtcConf->crtc[0])
1633	    SMI_DisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2,
1634			     &dstBox, src_w, src_h, drw_w, drw_h);
1635    }
1636    pPort->videoStatus = CLIENT_VIDEO_ON;
1637
1638    LEAVE(Success);
1639
1640}
1641
1642
1643static int
1644SMI_QueryImageAttributes(
1645	ScrnInfoPtr	pScrn,
1646	int		id,
1647	unsigned short	*width,
1648	unsigned short	*height,
1649	int		*pitches,
1650	int		*offsets
1651)
1652{
1653    SMIPtr pSmi = SMIPTR(pScrn);
1654    int size, tmp;
1655
1656    ENTER();
1657
1658    if (*width > pSmi->lcdWidth) {
1659	*width = pSmi->lcdWidth;
1660    }
1661    if (*height > pSmi->lcdHeight) {
1662	*height = pSmi->lcdHeight;
1663    }
1664
1665    *width = (*width + 1) & ~1;
1666    if (offsets != NULL) {
1667	offsets[0] = 0;
1668    }
1669
1670    switch (id) {
1671    case FOURCC_YV12:
1672    case FOURCC_I420:
1673	*height = (*height + 1) & ~1;
1674	size = (*width + 3) & ~3;
1675	if (pitches != NULL) {
1676	    pitches[0] = size;
1677	}
1678	size *= *height;
1679	if (offsets != NULL) {
1680	    offsets[1] = size;
1681	}
1682	tmp = ((*width >> 1) + 3) & ~3;
1683	if (pitches != NULL) {
1684	    pitches[1] = pitches[2] = tmp;
1685	}
1686	tmp *= (*height >> 1);
1687	size += tmp;
1688	if (offsets != NULL) {
1689	    offsets[2] = size;
1690	}
1691	size += tmp;
1692	break;
1693    case FOURCC_YUY2:
1694    case FOURCC_RV15:
1695    case FOURCC_RV16:
1696    default:
1697	size = *width * 2;
1698	if (pitches != NULL) {
1699	    pitches[0] = size;
1700	}
1701	size *= *height;
1702	break;
1703    case FOURCC_RV24:
1704	size = *width * 3;
1705	if (pitches != NULL) {
1706	    pitches[0] = size;
1707	}
1708	size *= *height;
1709	break;
1710    case FOURCC_RV32:
1711	size = *width * 4;
1712	if (pitches != NULL) {
1713	    pitches[0] = size;
1714	}
1715	size *= *height;
1716	break;
1717    }
1718
1719    LEAVE(size);
1720}
1721
1722
1723/******************************************************************************\
1724**									      **
1725**	S U P P O R T   F U N C T I O N S				      **
1726**									      **
1727\******************************************************************************/
1728
1729static void
1730SMI_DisplayVideo(
1731	ScrnInfoPtr	pScrn,
1732	int		id,
1733	int		offset,
1734	short		width,
1735	short		height,
1736	int		pitch,
1737	int		x1,
1738	int		y1,
1739	int		x2,
1740	int		y2,
1741	BoxPtr		dstBox,
1742	short		vid_w,
1743	short		vid_h,
1744	short		drw_w,
1745	short		drw_h
1746)
1747{
1748    SMIPtr pSmi = SMIPTR(pScrn);
1749    CARD32 vpr00;
1750    uint32_t hstretch, vstretch;
1751
1752    ENTER();
1753
1754    vpr00 = READ_VPR(pSmi, 0x00) & ~0x0CB800FF;
1755
1756    switch (id) {
1757    case FOURCC_YV12:
1758    case FOURCC_I420:
1759    case FOURCC_YUY2:
1760	vpr00 |= 0x6;
1761	break;
1762    case FOURCC_RV15:
1763	vpr00 |= 0x1;
1764	break;
1765    case FOURCC_RV16:
1766	vpr00 |= 0x2;
1767	break;
1768    case FOURCC_RV24:
1769	vpr00 |= 0x4;
1770	break;
1771    case FOURCC_RV32:
1772	vpr00 |= 0x3;
1773	break;
1774    }
1775
1776    if (drw_w > vid_w) {
1777	hstretch = ((uint32_t)(vid_w - 1) << 16) / (drw_w - 1);
1778    } else {
1779	hstretch = 0;
1780    }
1781
1782    if (drw_h > vid_h) {
1783	vstretch = ((uint32_t)(vid_h - 1) << 16) / (drw_h - 1);
1784	vpr00 |= 1 << 21;
1785    } else {
1786	vstretch = 0;
1787    }
1788
1789    WRITE_VPR(pSmi, 0x00, vpr00 | (1 << 3) | (1 << 20));
1790    WRITE_VPR(pSmi, 0x14, (dstBox->x1) | (dstBox->y1 << 16));
1791    WRITE_VPR(pSmi, 0x18, (dstBox->x2) | (dstBox->y2 << 16));
1792    WRITE_VPR(pSmi, 0x1C, offset >> 3);
1793    WRITE_VPR(pSmi, 0x20, (pitch >> 3) | ((pitch >> 3) << 16));
1794    WRITE_VPR(pSmi, 0x24, (hstretch & 0xff00) | ((vstretch & 0xff00) >> 8));
1795    if (pSmi->Chipset == SMI_LYNXEMplus) {	/* This one can store additional precision */
1796	WRITE_VPR(pSmi, 0x68, ((hstretch & 0xff) << 8) | (vstretch & 0xff));
1797    }
1798
1799    LEAVE();
1800}
1801
1802static void
1803SMI_DisplayVideo0501_CSC(ScrnInfoPtr pScrn, int id, int offset,
1804			 short width, short height, int pitch,
1805			 int x1, int y1, int x2, int y2, BoxPtr dstBox,
1806			 short vid_w, short vid_h, short drw_w, short drw_h,
1807			 RegionPtr clipboxes)
1808{
1809    int32_t	ScaleXn, ScaleXd, ScaleYn, ScaleYd;
1810    int32_t	SrcTn, SrcTd, SrcLn, SrcLd;
1811    int32_t	SrcRn, SrcBn;
1812    int32_t	SrcDimX, SrcDimY;
1813    int32_t	SrcYBase, SrcUBase, SrcVBase, SrcYPitch, SrcUVPitch;
1814    int32_t	DestPitch;
1815    SMIPtr	pSmi = SMIPTR(pScrn);
1816    BoxPtr	pbox = REGION_RECTS(clipboxes);
1817    int		i, nbox = REGION_NUM_RECTS(clipboxes);
1818    int32_t	rect_x, rect_y, rect_w, rect_h, csc;
1819    float	Hscale, Vscale;
1820
1821    ENTER();
1822
1823    SrcYBase = offset;
1824    SrcYPitch = pitch;
1825
1826    DestPitch = (pScrn->displayWidth * pSmi->Bpp + 15) & ~15;
1827
1828    Hscale = (vid_w - 1) / (float)(drw_w - 1);
1829    ScaleXn = Hscale;
1830    ScaleXd = ((vid_w - 1) << 13) / (drw_w - 1) - (ScaleXn << 13);
1831
1832    Vscale = (vid_h - 1) / (float)(drw_h - 1);
1833    ScaleYn = Vscale;
1834    ScaleYd = ((vid_h - 1) << 13) / (drw_h - 1) - (ScaleYn << 13);
1835
1836    /* CSC constants */
1837    WRITE_DPR(pSmi, 0xcc, 0);
1838    /* Use start of framebuffer as base offset */
1839    WRITE_DPR(pSmi, 0xf8, 0);
1840
1841    csc = (1 << 31) | (1 << 25);
1842    if (pSmi->Bpp > 2)
1843	csc |= 1 << 26;
1844
1845    switch (id) {
1846	case FOURCC_YV12:
1847	    SrcUVPitch = SrcYPitch / 2;
1848	    SrcVBase = SrcYBase + SrcYPitch * height;
1849	    SrcUBase = SrcVBase + SrcUVPitch * height / 2;
1850	    csc |= 2 << 28;
1851	    break;
1852
1853	case FOURCC_I420:
1854	    SrcUVPitch = SrcYPitch / 2;
1855	    SrcUBase = SrcYBase + SrcYPitch * height;
1856	    SrcVBase = SrcUBase + SrcUVPitch * height / 2;
1857	    csc |= 2 << 28;
1858	    break;
1859
1860	case FOURCC_YUY2:
1861	case FOURCC_RV16:
1862	case FOURCC_RV32:
1863	    SrcUBase = SrcVBase = SrcYBase;
1864	    SrcUVPitch = SrcYPitch;
1865	    break;
1866
1867	default:
1868	    LEAVE();
1869    }
1870
1871    WRITE_DPR(pSmi, 0xE4, ((SrcYPitch >> 4) << 16) | (SrcUVPitch >> 4));
1872    WRITE_DPR(pSmi, 0xC8, SrcYBase);
1873    WRITE_DPR(pSmi, 0xD8, SrcUBase);
1874    WRITE_DPR(pSmi, 0xDC, SrcVBase);
1875    WRITE_DPR(pSmi, 0xF4, (((ScaleXn << 13) | ScaleXd) << 16) |
1876	      (ScaleYn << 13 | ScaleYd));
1877
1878    for (i = 0; i < nbox; i++, pbox++) {
1879	rect_x = pbox->x1;
1880	rect_y = pbox->y1;
1881	rect_w = pbox->x2 - pbox->x1;
1882	rect_h = pbox->y2 - pbox->y1;
1883
1884	SrcLn = (rect_x - dstBox->x1) * Hscale;
1885	SrcLd = ((rect_x - dstBox->x1) << 13) * Hscale - (SrcLn << 13);
1886	SrcRn = (rect_x + rect_w - dstBox->x1) * Hscale;
1887
1888	SrcTn = (rect_y - dstBox->y1) * Vscale;
1889	SrcTd = ((rect_y - dstBox->y1) << 13) * Vscale - (SrcTn << 13);
1890	SrcBn = (rect_y + rect_h - dstBox->y1) * Vscale;
1891
1892	SrcDimX = SrcRn - SrcLn + 2;
1893	SrcDimY = SrcBn - SrcTn + 2;
1894
1895	WRITE_DPR(pSmi, 0xD0, (SrcLn << 16) | SrcLd);
1896	WRITE_DPR(pSmi, 0xD4, (SrcTn << 16) | SrcTd);
1897	WRITE_DPR(pSmi, 0xE0, (SrcDimX << 16) | SrcDimY);
1898	WRITE_DPR(pSmi, 0xE8, (rect_x << 16) | rect_y);
1899	WRITE_DPR(pSmi, 0xEC, (rect_w << 16) | rect_h);
1900	WRITE_DPR(pSmi, 0xF0, ((DestPitch >> 4) << 16) | rect_h);
1901
1902	while (READ_DPR(pSmi, 0xfc) & (1 << 31))
1903	    ;
1904	WRITE_DPR(pSmi, 0xfc, csc);
1905	/* CSC stop */
1906	while (READ_DPR(pSmi, 0xfc) & (1 << 31))
1907	    ;
1908    }
1909
1910    LEAVE();
1911}
1912
1913static void
1914SMI_DisplayVideo0501(ScrnInfoPtr pScrn,
1915		     int id,
1916		     int offset,
1917		     short width,
1918		     short height,
1919		     int pitch,
1920		     int x1,
1921		     int y1,
1922		     int x2,
1923		     int y2,
1924		     BoxPtr dstBox,
1925		     short vid_w, short vid_h, short drw_w, short drw_h)
1926{
1927    SMIPtr	pSmi = SMIPTR (pScrn);
1928    CARD32	dcr40;
1929    int		hstretch, vstretch;
1930
1931    ENTER();
1932
1933    dcr40 = READ_DCR(pSmi, 0x0040) & ~0x00003FFF;
1934
1935    switch (id) {
1936	case FOURCC_YV12:
1937	case FOURCC_I420:
1938	case FOURCC_YUY2:
1939	    dcr40 |= 0x3;
1940	    break;
1941
1942	case FOURCC_RV16:
1943	    dcr40 |= 0x1;
1944	    break;
1945
1946	case FOURCC_RV32:
1947	    dcr40 |= 0x2;
1948	    break;
1949    }
1950
1951    if (drw_w > vid_w) {	/*  Horizontal Stretch */
1952	hstretch = 4096 * vid_w / drw_w;
1953	dcr40 |= 1 << 8;
1954    }
1955    else {			/*  Horizontal Shrink */
1956	if (drw_w < (vid_w >> 1))
1957	    drw_w = vid_w >> 1;
1958	hstretch = (4096 * drw_w / vid_w) | 0x8000;
1959    }
1960
1961    if (drw_h > vid_h) {	/* Vertical Stretch */
1962	vstretch = 4096 * vid_h / drw_h;
1963	dcr40 |= 1 << 9;
1964    }
1965    else {			/* Vertical Shrink */
1966	if (drw_h < (vid_h >> 1))
1967	    drw_h = vid_h >> 1;
1968	vstretch = (4096 * drw_h / vid_h) | 0x8000;
1969    }
1970
1971    /* Set Color Key Enable bit */
1972
1973    WRITE_DCR(pSmi, 0x0000, READ_DCR(pSmi, 0x0000) | (1 << 9));
1974    WRITE_DCR(pSmi, 0x0050, dstBox->x1 | (dstBox->y1 << 16));
1975    WRITE_DCR(pSmi, 0x0054, dstBox->x2 | (dstBox->y2 << 16));
1976    WRITE_DCR(pSmi, 0x0044, offset);
1977
1978    WRITE_DCR(pSmi, 0x0048, pitch | (pitch << 16));
1979    WRITE_DCR(pSmi, 0x004C, offset + (pitch * height));
1980    WRITE_DCR(pSmi, 0x0058, (vstretch << 16) | hstretch);
1981    WRITE_DCR(pSmi, 0x005C, 0x00000000);
1982    WRITE_DCR(pSmi, 0x0060, 0x00EDEDED);
1983
1984    WRITE_DCR(pSmi, 0x0040, dcr40 | (1 << 2));
1985
1986    LEAVE();
1987}
1988
1989static void
1990SMI_DisplayVideo0730(
1991	ScrnInfoPtr	pScrn,
1992	int		id,
1993	int		offset,
1994	short		width,
1995	short		height,
1996	int		pitch,
1997	int		x1,
1998	int		y1,
1999	int		x2,
2000	int		y2,
2001	BoxPtr		dstBox,
2002	short		vid_w,
2003	short		vid_h,
2004	short		drw_w,
2005	short		drw_h
2006)
2007{
2008    SMIPtr pSmi = SMIPTR(pScrn);
2009    CARD32 fpr00;
2010    int hstretch, vstretch;
2011
2012    ENTER();
2013
2014    fpr00 = READ_FPR(pSmi, 0x00) & ~(FPR00_MASKBITS);
2015
2016    switch (id) {
2017    case FOURCC_YV12:
2018    case FOURCC_I420:
2019    case FOURCC_YUY2:
2020	fpr00 |= FPR00_FMT_YUV422;
2021	break;
2022    case FOURCC_RV15:
2023	fpr00 |= FPR00_FMT_15P;
2024	break;
2025    case FOURCC_RV16:
2026	fpr00 |= FPR00_FMT_16P;
2027	break;
2028    case FOURCC_RV24:
2029	fpr00 |= FPR00_FMT_24P;
2030	break;
2031    case FOURCC_RV32:
2032	fpr00 |= FPR00_FMT_32P;
2033	break;
2034    }
2035
2036    /* the formulas for calculating the stretch values do not match the
2037       documentation, but they're the same as the ddraw driver and they work */
2038    if (drw_w > vid_w) {
2039	hstretch = (8192 * vid_w / drw_w);
2040    } else {
2041	hstretch = 0;
2042    }
2043
2044    if (drw_h > vid_h) {
2045	vstretch = (8192 * vid_h / drw_h);
2046    } else {
2047	vstretch = 0;
2048    }
2049
2050    WRITE_FPR(pSmi, FPR00, fpr00 | FPR00_VWIENABLE | FPR00_VWIKEYENABLE);
2051    WRITE_FPR(pSmi, FPR14, (dstBox->x1) | (dstBox->y1 << 16));
2052    WRITE_FPR(pSmi, FPR18, (dstBox->x2) | (dstBox->y2 << 16));
2053    WRITE_FPR(pSmi, FPR1C, offset >> 3);
2054    WRITE_FPR(pSmi, FPR20, (pitch >> 3) | ((pitch >> 3) << 16));
2055    WRITE_FPR(pSmi, FPR24, (hstretch & 0xFF00) | ((vstretch & 0xFF00)>>8));
2056    WRITE_FPR(pSmi, FPR68, ((hstretch & 0x00FF)<<8) | (vstretch & 0x00FF));
2057
2058    LEAVE();
2059}
2060
2061static void
2062SMI_BlockHandler(BLOCKHANDLER_ARGS_DECL)
2063{
2064    SCREEN_PTR(arg);
2065    ScrnInfoPtr	pScrn	= xf86ScreenToScrn(pScreen);
2066    SMIPtr	pSmi    = SMIPTR(pScrn);
2067    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2068
2069    pScreen->BlockHandler = pSmi->BlockHandler;
2070    (*pScreen->BlockHandler)(BLOCKHANDLER_ARGS);
2071    pScreen->BlockHandler = SMI_BlockHandler;
2072
2073    if (pPort->videoStatus & TIMER_MASK) {
2074	UpdateCurrentTime();
2075        if (pPort->videoStatus & OFF_TIMER) {
2076            if (pPort->offTime < currentTime.milliseconds) {
2077		if (pSmi->Chipset == SMI_COUGAR3DR) {
2078		    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
2079		}
2080		else if (IS_MSOC(pSmi))
2081		    WRITE_DCR(pSmi, 0x0040, READ_DCR(pSmi, 0x0040) & ~0x00000004);
2082		else
2083		    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
2084                pPort->videoStatus = FREE_TIMER;
2085                pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
2086	    }
2087	} else {
2088            if (pPort->freeTime < currentTime.milliseconds) {
2089		SMI_FreeMemory(pScrn, pPort->video_memory);
2090                pPort->video_memory = NULL;
2091	    }
2092            pPort->videoStatus = 0;
2093	}
2094    }
2095}
2096
2097#if 0
2098static int
2099SMI_SendI2C(
2100	ScrnInfoPtr		pScrn,
2101	CARD8			device,
2102	char			*devName,
2103	SMI_I2CDataPtr	i2cData
2104)
2105{
2106    SMIPtr	pSmi = SMIPTR(pScrn);
2107    I2CDevPtr	dev;
2108    int		status = Success;
2109
2110    ENTER();
2111
2112    if (pSmi->I2C == NULL)
2113	LEAVE(BadAlloc);
2114
2115    dev = xf86CreateI2CDevRec();
2116    if (dev == NULL)
2117	LEAVE(BadAlloc);
2118
2119    dev->DevName = devName;
2120    dev->SlaveAddr = device;
2121    dev->pI2CBus = pSmi->I2C;
2122
2123    if (!xf86I2CDevInit(dev))
2124	status = BadAlloc;
2125    else {
2126	while (i2cData->address != 0xFF || i2cData->data != 0xFF) {	/* PDR#676 */
2127	    if (!xf86I2CWriteByte(dev, i2cData->address, i2cData->data)) {
2128		status = BadAlloc;
2129		break;
2130	    }
2131	    i2cData++;
2132	}
2133    }
2134
2135    xf86DestroyI2CDevRec(dev, TRUE);
2136
2137    LEAVE(status);
2138}
2139#endif
2140
2141/******************************************************************************\
2142**									      **
2143**	 O F F S C R E E N   M E M O R Y   M A N A G E R		      **
2144**									      **
2145\******************************************************************************/
2146
2147static void
2148SMI_InitOffscreenImages(
2149	ScreenPtr	pScreen
2150)
2151{
2152    XF86OffscreenImagePtr offscreenImages;
2153    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2154    SMIPtr pSmi = SMIPTR(pScrn);
2155    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2156
2157    ENTER();
2158
2159    offscreenImages = malloc(sizeof(XF86OffscreenImageRec));
2160    if (offscreenImages == NULL) {
2161	LEAVE();
2162    }
2163
2164    offscreenImages->image = SMI_VideoImages;
2165    offscreenImages->flags = VIDEO_OVERLAID_IMAGES;
2166    if (IS_MSOC(pSmi))
2167	offscreenImages->flags |= VIDEO_CLIP_TO_VIEWPORT;
2168    offscreenImages->alloc_surface = SMI_AllocSurface;
2169    offscreenImages->free_surface = SMI_FreeSurface;
2170    offscreenImages->display = SMI_DisplaySurface;
2171    offscreenImages->stop = SMI_StopSurface;
2172    offscreenImages->getAttribute = SMI_GetSurfaceAttribute;
2173    offscreenImages->setAttribute = SMI_SetSurfaceAttribute;
2174    offscreenImages->max_width = pSmi->lcdWidth;
2175    offscreenImages->max_height = pSmi->lcdHeight;
2176    if (!pPort->I2CDev.SlaveAddr) {
2177	offscreenImages->num_attributes = nElems(SMI_VideoAttributes);
2178	offscreenImages->attributes = SMI_VideoAttributes;
2179    } else {
2180	offscreenImages->num_attributes = nElems(SMI_VideoAttributesSAA711x);
2181	offscreenImages->attributes = SMI_VideoAttributesSAA711x;
2182    }
2183    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
2184
2185    LEAVE();
2186}
2187
2188static void
2189SMI_VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
2190{
2191    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2192    SMIPtr pSmi = SMIPTR(pScrn);
2193    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2194
2195    ENTER();
2196
2197    if (pPort->video_memory == area)
2198	pPort->video_memory = NULL;
2199
2200    LEAVE();
2201}
2202
2203CARD32
2204SMI_AllocateMemory(ScrnInfoPtr pScrn, void **mem_struct, int size)
2205{
2206    ScreenPtr	pScreen = xf86ScrnToScreen(pScrn);
2207    SMIPtr	pSmi = SMIPTR(pScrn);
2208    int		offset = 0;
2209
2210    ENTER();
2211
2212    if (pSmi->useEXA) {
2213	ExaOffscreenArea *area = *mem_struct;
2214
2215	if (area != NULL) {
2216	    if (area->size >= size)
2217		LEAVE(area->offset);
2218
2219	    exaOffscreenFree(pScrn->pScreen, area);
2220	}
2221
2222	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE,
2223				 SMI_VideoSave, NULL);
2224
2225	*mem_struct = area;
2226	if (area != NULL)
2227	    offset = area->offset;
2228    }
2229    else {
2230	FBLinearPtr	linear = *mem_struct;
2231
2232	/*  XAA allocates in units of pixels at the screen bpp,
2233	 *  so adjust size appropriately.
2234	 */
2235	size = (size + pSmi->Bpp - 1) / pSmi->Bpp;
2236
2237	if (linear) {
2238	    if (linear->size >= size)
2239		LEAVE(linear->offset * pSmi->Bpp);
2240
2241	    if (xf86ResizeOffscreenLinear(linear, size))
2242		LEAVE(linear->offset * pSmi->Bpp);
2243
2244	    xf86FreeOffscreenLinear(linear);
2245	}
2246	else {
2247	    int max_size;
2248
2249	    xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
2250					    PRIORITY_EXTREME);
2251	    if (max_size < size)
2252		LEAVE(0);
2253
2254	    xf86PurgeUnlockedOffscreenAreas(pScreen);
2255	}
2256
2257	linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
2258					     NULL, NULL, NULL);
2259	if ((*mem_struct = linear) != NULL)
2260	    offset = linear->offset * pSmi->Bpp;
2261
2262	DEBUG("offset = %p\n", offset);
2263    }
2264
2265    LEAVE(offset);
2266}
2267
2268void
2269SMI_FreeMemory(
2270	ScrnInfoPtr pScrn,
2271	void *mem_struct
2272)
2273{
2274    SMIPtr pSmi = SMIPTR(pScrn);
2275
2276    ENTER();
2277
2278    if (pSmi->useEXA) {
2279	ExaOffscreenArea *area = mem_struct;
2280
2281	if (area != NULL)
2282	    exaOffscreenFree(pScrn->pScreen, area);
2283    } else {
2284	FBLinearPtr linear = mem_struct;
2285
2286	if (linear != NULL)
2287	    xf86FreeOffscreenLinear(linear);
2288    }
2289
2290    LEAVE();
2291}
2292
2293static void
2294CopyYV12ToVideoMem(unsigned char *src1, unsigned char *src2,
2295		   unsigned char *src3, unsigned char *dst,
2296		   int src1Pitch, int src23Pitch, int dstPitch,
2297		   int height, int width)
2298{
2299    int		j = height;
2300
2301    ENTER();
2302
2303    /* copy 1 data */
2304    while (j -- > 0) {
2305	memcpy(dst, src1, width);
2306	src1 += src1Pitch;
2307	dst += dstPitch;
2308    }
2309    /* copy 2 data */
2310    j = height / 2;
2311    while (j -- > 0) {
2312	memcpy(dst, src2, width / 2);
2313	src2 += src23Pitch;
2314	dst += dstPitch / 2;
2315    }
2316    /* copy 3 data */
2317    j = height / 2;
2318    while (j -- > 0) {
2319	memcpy(dst, src3, width / 2);
2320	src3 += src23Pitch;
2321	dst += dstPitch / 2;
2322    }
2323
2324    LEAVE();
2325}
2326
2327static int
2328SMI_AllocSurface(
2329	ScrnInfoPtr	pScrn,
2330	int		id,
2331	unsigned short	width,
2332	unsigned short	height,
2333	XF86SurfacePtr	surface
2334)
2335{
2336    SMIPtr pSmi = SMIPTR(pScrn);
2337    int pitch, bpp, offset, size;
2338    void *surface_memory = NULL;
2339    SMI_OffscreenPtr ptrOffscreen;
2340
2341    ENTER();
2342
2343    if (width > pSmi->lcdWidth || height > pSmi->lcdHeight)
2344	LEAVE(BadAlloc);
2345
2346    switch (id) {
2347    case FOURCC_YV12:
2348    case FOURCC_I420:
2349    case FOURCC_YUY2:
2350    case FOURCC_RV15:
2351    case FOURCC_RV16:
2352	bpp = 2;
2353	break;
2354    case FOURCC_RV24:
2355	bpp = 3;
2356	break;
2357    case FOURCC_RV32:
2358	bpp = 4;
2359	break;
2360    default:
2361	LEAVE(BadAlloc);
2362    }
2363
2364    width = (width + 1) & ~1;
2365    pitch = (width * bpp + 15) & ~15;
2366    size  = pitch * height;
2367
2368    offset = SMI_AllocateMemory(pScrn, &surface_memory, size);
2369    if (offset == 0)
2370	LEAVE(BadAlloc);
2371
2372    surface->pitches = malloc(sizeof(int));
2373    if (surface->pitches == NULL) {
2374	SMI_FreeMemory(pScrn, surface_memory);
2375	LEAVE(BadAlloc);
2376    }
2377    surface->offsets = malloc(sizeof(int));
2378    if (surface->offsets == NULL) {
2379	free(surface->pitches);
2380	SMI_FreeMemory(pScrn, surface_memory);
2381	LEAVE(BadAlloc);
2382    }
2383
2384    ptrOffscreen = malloc(sizeof(SMI_OffscreenRec));
2385    if (ptrOffscreen == NULL) {
2386	free(surface->offsets);
2387	free(surface->pitches);
2388	SMI_FreeMemory(pScrn, surface_memory);
2389	LEAVE(BadAlloc);
2390    }
2391
2392    surface->pScrn = pScrn;
2393    surface->id = id;
2394    surface->width = width;
2395    surface->height = height;
2396    surface->pitches[0] = pitch;
2397    surface->offsets[0] = offset;
2398    surface->devPrivate.ptr = (pointer) ptrOffscreen;
2399
2400    ptrOffscreen->surface_memory = surface_memory;
2401    ptrOffscreen->isOn = FALSE;
2402
2403    LEAVE(Success);
2404}
2405
2406static int
2407SMI_FreeSurface(
2408	XF86SurfacePtr	surface
2409)
2410{
2411    ScrnInfoPtr pScrn = surface->pScrn;
2412    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2413
2414    ENTER();
2415
2416    if (ptrOffscreen->isOn) {
2417	SMI_StopSurface(surface);
2418    }
2419
2420    SMI_FreeMemory(pScrn, ptrOffscreen->surface_memory);
2421    free(surface->pitches);
2422    free(surface->offsets);
2423    free(surface->devPrivate.ptr);
2424
2425    LEAVE(Success);
2426}
2427
2428static int
2429SMI_DisplaySurface(
2430	XF86SurfacePtr	surface,
2431	short		vid_x,
2432	short		vid_y,
2433	short		drw_x,
2434	short		drw_y,
2435	short		vid_w,
2436	short		vid_h,
2437	short		drw_w,
2438	short		drw_h,
2439	RegionPtr	clipBoxes
2440)
2441{
2442    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2443    SMIPtr pSmi = SMIPTR(surface->pScrn);
2444    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2445    INT32 x1, y1, x2, y2;
2446    BoxRec dstBox;
2447    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(surface->pScrn);
2448    xf86CrtcPtr crtc;
2449
2450    ENTER();
2451
2452    x1 = vid_x;
2453    x2 = vid_x + vid_w;
2454    y1 = vid_y;
2455    y2 = vid_y + vid_h;
2456
2457    dstBox.x1 = drw_x;
2458    dstBox.x2 = drw_x + drw_w;
2459    dstBox.y1 = drw_y;
2460    dstBox.y2 = drw_y + drw_h;
2461
2462    if(!xf86_crtc_clip_video_helper(surface->pScrn, &crtc, crtcConf->crtc[0], &dstBox,
2463				    &x1, &x2, &y1, &y2, clipBoxes, surface->width, surface->height))
2464	LEAVE(Success);
2465
2466    if (!crtc)
2467	LEAVE(Success);
2468
2469    /* Transform dstBox to the CRTC coordinates */
2470    dstBox.x1 -= crtc->x;
2471    dstBox.y1 -= crtc->y;
2472    dstBox.x2 -= crtc->x;
2473    dstBox.y2 -= crtc->y;
2474
2475    xf86XVFillKeyHelper(surface->pScrn->pScreen,
2476			pPort->Attribute[XV_COLORKEY], clipBoxes);
2477    SMI_ResetVideo(surface->pScrn);
2478
2479    if (pSmi->Chipset == SMI_COUGAR3DR)
2480	SMI_DisplayVideo0730(surface->pScrn, surface->id, surface->offsets[0],
2481			     surface->width, surface->height, surface->pitches[0], x1, y1, x2,
2482			     y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2483    else if (IS_MSOC(pSmi))
2484	SMI_DisplayVideo0501(surface->pScrn, surface->id,
2485			     surface->offsets[0], surface->width,
2486			     surface->height, surface->pitches[0], x1, y1,
2487			     x2, y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2488    else{
2489	if(crtc == crtcConf->crtc[0])
2490	    SMI_DisplayVideo(surface->pScrn, surface->id, surface->offsets[0],
2491			     surface->width, surface->height, surface->pitches[0], x1, y1, x2,
2492			     y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2493    }
2494
2495    ptrOffscreen->isOn = TRUE;
2496    if (pPort->videoStatus & CLIENT_VIDEO_ON) {
2497        REGION_EMPTY(surface->pScrn->pScreen, &pPort->clip);
2498	UpdateCurrentTime();
2499        pPort->videoStatus = FREE_TIMER;
2500        pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
2501    }
2502
2503    LEAVE(Success);
2504}
2505
2506static int
2507SMI_StopSurface(
2508	XF86SurfacePtr	surface
2509)
2510{
2511    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2512
2513    ENTER();
2514
2515    if (ptrOffscreen->isOn) {
2516	SMIPtr pSmi = SMIPTR(surface->pScrn);
2517	if (pSmi->Chipset == SMI_COUGAR3DR) {
2518	    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
2519	} else {
2520	    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
2521	}
2522
2523	ptrOffscreen->isOn = FALSE;
2524    }
2525
2526    LEAVE(Success);
2527}
2528
2529static int
2530SMI_GetSurfaceAttribute(
2531	ScrnInfoPtr	pScrn,
2532	Atom		attr,
2533	INT32		*value
2534)
2535{
2536    SMIPtr pSmi = SMIPTR(pScrn);
2537
2538    return SMI_GetPortAttribute(pScrn, attr, value,
2539			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
2540}
2541
2542static int
2543SMI_SetSurfaceAttribute(
2544	ScrnInfoPtr	pScrn,
2545	Atom		attr,
2546	INT32		value
2547)
2548{
2549    SMIPtr pSmi = SMIPTR(pScrn);
2550
2551    return SMI_SetPortAttribute(pScrn, attr, value,
2552			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
2553}
2554
2555static void
2556SetKeyReg(SMIPtr pSmi, int reg, int value)
2557{
2558    if (pSmi->Chipset == SMI_COUGAR3DR)
2559	WRITE_FPR(pSmi, reg, value);
2560    else if (IS_MSOC(pSmi)) {
2561	/* We don't change the color mask, and we don't do brightness.  IF
2562	 * they write to the colorkey register, we'll write the value to the
2563	 * 501 colorkey register */
2564	if (FPR04 == reg)		   /* Only act on colorkey value writes */
2565	    WRITE_DCR(pSmi, 0x0008, value);/* ColorKey register is DCR08 */
2566    }
2567    else
2568	WRITE_VPR(pSmi, reg, value);
2569}
2570
2571#else /* SMI_USE_VIDEO */
2572void SMI_InitVideo(ScreenPtr pScreen) {}
2573#endif
2574