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    const 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    const 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    const char* norm_string;
513    const char* input_string;
514    char channel_string[20];
515    char* name_string;
516
517    ENTER();
518
519    norm_string = VideoNorms[norm].name;
520    input_string = VideoInputs[input].name;
521    snprintf(channel_string, sizeof(channel_string), "%d", channel);
522    enc[i].id     = i;
523#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10
524    if (Xasprintf(&name_string, "%s-%s-%s",
525                  norm_string, input_string, channel_string) < 0)
526        LEAVE(-1);
527#else
528    name_string = Xprintf("%s-%s-%s",
529                          norm_string, input_string, channel_string);
530    if (NULL == name_string)
531	LEAVE(-1);
532#endif
533    enc[i].name   = name_string;
534
535    enc[i].width  = VideoNorms[norm].Wa;
536    enc[i].height = VideoNorms[norm].Ha;
537    enc[i].rate   = VideoNorms[norm].rate;
538
539    LEAVE(0);
540}
541
542
543/**
544 * builds XF86VideoEncodings with all legal combinations of video norm,
545 * video input format and video input channel
546 */
547static void
548SMI_BuildEncodings(SMI_PortPtr p)
549{
550    int ch, n;
551
552    ENTER();
553
554    /* allocate memory for encoding array */
555    p->enc = calloc(N_ENCODINGS, sizeof(XF86VideoEncodingRec));
556    if (NULL == p->enc)
557	goto fail;
558
559    /* allocate memory for video norm array */
560    p->norm = calloc(N_ENCODINGS, sizeof(int));
561    if (NULL == p->norm)
562	goto fail;
563
564    /* allocate memory for video input format array */
565    p->input = calloc(N_ENCODINGS, sizeof(int));
566    if (NULL == p->input)
567	goto fail;
568
569    /* allocate memory for video channel number array */
570    p->channel = calloc(N_ENCODINGS, sizeof(int));
571    if (NULL == p->channel)
572	goto fail;
573
574    /* fill arrays */
575    p->nenc = 0;
576    for (ch = 0; ch < N_COMPOSITE_CHANNELS; ch++) {
577	for (n = 0; n < N_VIDEO_NORMS; n++) {
578	    SMI_AddEncoding(p->enc, p->nenc, n, VID_COMPOSITE, ch);
579	    p->norm[p->nenc]  = n;
580	    p->input[p->nenc] = VID_COMPOSITE;
581	    p->channel[p->nenc] = ch;
582	    p->nenc++;
583	}
584    }
585    for (ch = 0; ch < N_SVIDEO_CHANNELS; ch++) {
586	for (n = 0; n < N_VIDEO_NORMS; n++) {
587	    SMI_AddEncoding(p->enc, p->nenc, n, VID_SVIDEO, ch);
588	    p->norm[p->nenc]  = n;
589	    p->input[p->nenc] = VID_SVIDEO;
590	    p->channel[p->nenc] = ch;
591	    p->nenc++;
592	}
593    }
594    LEAVE();
595
596 fail:
597    free(p->input);
598    p->input = NULL;
599    free(p->norm);
600    p->norm = NULL;
601    free(p->channel);
602    p->channel = NULL;
603    free(p->enc);
604    p->enc = NULL;
605    p->nenc = 0;
606    LEAVE();
607}
608
609
610/******************************************************************************\
611**                                                                            **
612**                  X V E X T E N S I O N   I N T E R F A C E                 **
613**                                                                            **
614\******************************************************************************/
615
616void
617SMI_InitVideo(ScreenPtr pScreen)
618{
619    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
620    XF86VideoAdaptorPtr *ptrAdaptors, *newAdaptors = NULL;
621    XF86VideoAdaptorPtr newAdaptor = NULL;
622    int numAdaptors;
623
624    ENTER();
625
626    numAdaptors = xf86XVListGenericAdaptors(pScrn, &ptrAdaptors);
627
628    DEBUG("numAdaptors=%d\n", numAdaptors);
629
630    newAdaptor = SMI_SetupVideo(pScreen);
631    DEBUG("newAdaptor=%p\n", newAdaptor);
632    SMI_InitOffscreenImages(pScreen);
633
634    if (newAdaptor != NULL) {
635        if (numAdaptors == 0) {
636            numAdaptors = 1;
637            ptrAdaptors = &newAdaptor;
638        } else {
639            newAdaptors = malloc((numAdaptors + 1) *
640                    sizeof(XF86VideoAdaptorPtr*));
641            if (newAdaptors != NULL) {
642                memcpy(newAdaptors, ptrAdaptors,
643                        numAdaptors * sizeof(XF86VideoAdaptorPtr));
644                newAdaptors[numAdaptors++] = newAdaptor;
645                ptrAdaptors = newAdaptors;
646            }
647        }
648    }
649
650    if (numAdaptors != 0) {
651        DEBUG("ScreenInit %i\n",numAdaptors);
652        xf86XVScreenInit(pScreen, ptrAdaptors, numAdaptors);
653    }
654
655    free(newAdaptors);
656
657    LEAVE();
658}
659
660
661/*************************************************************************/
662
663/*
664 *  Video codec controls
665 */
666
667#if 0
668/**
669 * scales value value of attribute i to range min, max
670 */
671static int
672Scale(int i, int value, int min, int max)
673{
674    return min + (value - SMI_VideoAttributes[i].min_value) * (max - min) /
675	(SMI_VideoAttributes[i].max_value - SMI_VideoAttributes[i].min_value);
676}
677#endif
678/**
679 * sets video decoder attributes channel, encoding, brightness, contrast, saturation, hue
680 */
681static int
682SetAttr(ScrnInfoPtr pScrn, int i, int value)
683{
684    SMIPtr pSmi = SMIPTR(pScrn);
685    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
686
687    if (i < XV_ENCODING || i > XV_HUE)
688	return BadMatch;
689
690    /* clamps value to attribute range */
691    value = CLAMP(value, SMI_VideoAttributes[i].min_value,
692		  SMI_VideoAttributes[i].max_value);
693
694    if (i == XV_BRIGHTNESS) {
695	int my_value = (value <= 128? value + 128 : value - 128);
696	SetKeyReg(pSmi, 0x5C, 0xEDEDED | (my_value << 24));
697    } else if (pPort->I2CDev.SlaveAddr == SAA7110) {
698	return SetAttrSAA7110(pScrn, i, value);
699    } else if (pPort->I2CDev.SlaveAddr == SAA7111) {
700	return SetAttrSAA7111(pScrn, i, value);
701    }
702#if 0
703    else {
704	return XvBadAlloc;
705    }
706#endif
707
708    return Success;
709}
710
711
712/**
713 * sets SAA7110 video decoder attributes channel, encoding, brightness, contrast, saturation, hue
714 */
715static int
716SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value)
717{
718    /* not supported */
719    return XvBadAlloc;
720}
721
722
723/**
724 * sets SAA7111 video decoder attributes channel, encoding,
725 * brightness, contrast, saturation, hue
726 */
727static int
728SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value)
729{
730    SMIPtr pSmi = SMIPTR(pScrn);
731    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
732
733    if (i == XV_ENCODING) {
734	int norm;
735	int input;
736	int channel;
737	norm = pPort->norm[value];
738	input = pPort->input[value];
739	channel = pPort->channel[value];
740
741	DEBUG("SetAttribute XV_ENCODING: %d. norm=%d input=%d channel=%d\n",
742	      value, norm, input, channel);
743
744	/* set video norm */
745	if (!xf86I2CWriteVec(&(pPort->I2CDev), SAA7111VideoStd[norm],
746			     ENTRIES(SAA7111VideoStd[norm]) / 2)) {
747	    return XvBadAlloc;
748	}
749	/* set video input format and channel */
750	if (input == VID_COMPOSITE) {
751	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
752				 SAA7111CompositeChannelSelect[channel],
753				 ENTRIES(SAA7111CompositeChannelSelect[channel]) / 2)) {
754		return XvBadAlloc;
755	    }
756	} else {
757	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
758				 SAA7111SVideoChannelSelect[channel],
759				 ENTRIES(SAA7111SVideoChannelSelect[channel]) / 2)) {
760		return XvBadAlloc;
761	    }
762	}
763    } else if (i >= XV_CAPTURE_BRIGHTNESS && i <= XV_HUE) {
764	int slave_adr = 0;
765
766	switch (i) {
767
768	case XV_CAPTURE_BRIGHTNESS:
769	    DEBUG("SetAttribute XV_BRIGHTNESS: %d\n", value);
770	    slave_adr = 0x0a;
771	    break;
772
773	case XV_CONTRAST:
774	    DEBUG("SetAttribute XV_CONTRAST: %d\n", value);
775	    slave_adr = 0x0b;
776	    break;
777
778	case XV_SATURATION:
779	    DEBUG("SetAttribute XV_SATURATION: %d\n", value);
780	    slave_adr = 0x0c;
781	    break;
782
783	case XV_HUE:
784	    DEBUG("SetAttribute XV_HUE: %d\n", value);
785	    slave_adr = 0x0d;
786	    break;
787
788	default:
789	    return XvBadAlloc;
790	}
791	if (!xf86I2CWriteByte(&(pPort->I2CDev), slave_adr, (value & 0xff)))
792	    return XvBadAlloc;
793    } else {
794	return BadMatch;
795    }
796
797    /* debug: show registers */
798    {
799	I2CByte i2c_bytes[32];
800	int j;
801	xf86I2CReadBytes(&(pPort->I2CDev), 0, i2c_bytes, 32);
802	DEBUG("SAA7111 Registers\n");
803	for (j=0; j<32; j++) {
804	    DEBUG("%02X=%02X ", j, i2c_bytes[j]);
805	    if ((j&7) == 7) {
806		DEBUG("\n");
807	    }
808	}
809    }
810
811    return Success;
812}
813
814
815/******************************************************************************\
816**									      **
817**	V I D E O   M A N A G E M E N T					      **
818**									      **
819\******************************************************************************/
820
821static XF86VideoAdaptorPtr
822SMI_SetupVideo(ScreenPtr pScreen)
823{
824    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
825    SMIPtr pSmi = SMIPTR(pScrn);
826    SMI_PortPtr smiPortPtr;
827    XF86VideoAdaptorPtr ptrAdaptor;
828
829    ENTER();
830
831    ptrAdaptor = calloc(1, sizeof(XF86VideoAdaptorRec) +
832		 sizeof(DevUnion) + sizeof(SMI_PortRec));
833    if (ptrAdaptor == NULL)
834	LEAVE(NULL);
835
836    ptrAdaptor->type = XvInputMask
837#if SMI_USE_CAPTURE
838		     | XvOutputMask
839		     | XvVideoMask
840#endif
841		     | XvImageMask
842		     | XvWindowMask
843		     ;
844
845    ptrAdaptor->flags = VIDEO_OVERLAID_IMAGES;
846    if (IS_MSOC(pSmi)) {
847	ptrAdaptor->name = "Silicon Motion MSOC Series Video Engine";
848    }
849    else
850	ptrAdaptor->name = "Silicon Motion Lynx Series Video Engine";
851
852    ptrAdaptor->nPorts = 1;
853    ptrAdaptor->pPortPrivates = (DevUnion*) &ptrAdaptor[1];
854    ptrAdaptor->pPortPrivates[0].ptr = (pointer) &ptrAdaptor->pPortPrivates[1];
855
856    smiPortPtr = (SMI_PortPtr) ptrAdaptor->pPortPrivates[0].ptr;
857
858    SMI_BuildEncodings(smiPortPtr);
859    ptrAdaptor->nEncodings = smiPortPtr->nenc;
860    ptrAdaptor->pEncodings = smiPortPtr->enc;
861#if 0
862    /* aaa what's this? */
863	for (i = 0; i < nElems(SMI_VideoEncodings); i++)
864	{
865		SMI_VideoEncodings[i].width = pSmi->lcdWidth;
866		SMI_VideoEncodings[i].height = pSmi->lcdHeight;
867	}
868#endif
869
870    ptrAdaptor->nFormats = nElems(SMI_VideoFormats);
871    ptrAdaptor->pFormats = SMI_VideoFormats;
872
873    ptrAdaptor->nAttributes = nElems(SMI_VideoAttributes);
874    ptrAdaptor->pAttributes = SMI_VideoAttributes;
875
876    if (IS_MSOC(pSmi)) {
877	ptrAdaptor->nImages = nElems(SMI501_VideoImages);
878	ptrAdaptor->pImages = SMI501_VideoImages;
879    }
880    else {
881	ptrAdaptor->nImages = nElems(SMI_VideoImages);
882	ptrAdaptor->pImages = SMI_VideoImages;
883    }
884
885#if SMI_USE_CAPTURE
886    if (pSmi->Chipset == SMI_COUGAR3DR || IS_MSOC(pSmi))
887	ptrAdaptor->PutVideo = NULL;
888    else
889	ptrAdaptor->PutVideo = SMI_PutVideo;
890    ptrAdaptor->PutStill = NULL;
891    ptrAdaptor->GetVideo = NULL;
892    ptrAdaptor->GetStill = NULL;
893#else
894    ptrAdaptor->PutVideo = NULL;
895    ptrAdaptor->PutStill = NULL;
896    ptrAdaptor->GetVideo = NULL;
897    ptrAdaptor->GetStill = NULL;
898#endif
899    ptrAdaptor->StopVideo = SMI_StopVideo;
900    ptrAdaptor->SetPortAttribute = SMI_SetPortAttribute;
901    ptrAdaptor->GetPortAttribute = SMI_GetPortAttribute;
902    ptrAdaptor->QueryBestSize = SMI_QueryBestSize;
903    ptrAdaptor->PutImage = SMI_PutImage;
904    ptrAdaptor->QueryImageAttributes = SMI_QueryImageAttributes;
905
906    smiPortPtr->Attribute[XV_COLORKEY] = pSmi->videoKey;
907    smiPortPtr->Attribute[XV_INTERLACED] = pSmi->interlaced;
908    smiPortPtr->videoStatus = 0;
909
910#if 0
911    /* aaa does not work ? */
912    if (xf86I2CProbeAddress(pSmi->I2C, SAA7111))
913        LEAVE(NULL);
914    DEBUG("SAA7111 detected\n");
915#endif
916
917    smiPortPtr->I2CDev.DevName = "SAA 7111A";
918    smiPortPtr->I2CDev.SlaveAddr = SAA7111;
919    smiPortPtr->I2CDev.pI2CBus = pSmi->I2C;
920
921
922    if (!IS_MSOC(pSmi) && xf86I2CDevInit(&(smiPortPtr->I2CDev))) {
923
924	if (xf86I2CWriteVec(&(smiPortPtr->I2CDev), SAA7111InitData, ENTRIES(SAA7111InitData) / 2)) {
925	    xvEncoding   = MAKE_ATOM(XV_ENCODING_NAME);
926	    xvHue        = MAKE_ATOM(XV_HUE_NAME);
927	    xvSaturation = MAKE_ATOM(XV_SATURATION_NAME);
928	    xvContrast   = MAKE_ATOM(XV_CONTRAST_NAME);
929
930	    xvInterlaced = MAKE_ATOM(XV_INTERLACED_NAME);
931	    DEBUG("SAA7111 initialized\n");
932
933	} else {
934	    xf86DestroyI2CDevRec(&(smiPortPtr->I2CDev),FALSE);
935	    smiPortPtr->I2CDev.SlaveAddr = 0;
936	}
937    } else
938	smiPortPtr->I2CDev.SlaveAddr = 0;
939
940#if defined(REGION_NULL)
941    REGION_NULL(pScreen, &smiPortPtr->clip);
942#else
943    REGION_INIT(pScreen, &smiPortPtr->clip, NullBox, 0);
944#endif
945
946    pSmi->ptrAdaptor = ptrAdaptor;
947    pSmi->BlockHandler = pScreen->BlockHandler;
948    pScreen->BlockHandler = SMI_BlockHandler;
949
950    xvColorKey   = MAKE_ATOM(XV_COLORKEY_NAME);
951    xvBrightness = MAKE_ATOM(XV_BRIGHTNESS_NAME);
952    xvCapBrightness = MAKE_ATOM(XV_CAPTURE_BRIGHTNESS_NAME);
953
954    SMI_ResetVideo(pScrn);
955
956    LEAVE(ptrAdaptor);
957}
958
959
960static void
961SMI_ResetVideo(ScrnInfoPtr pScrn)
962{
963    SMIPtr pSmi = SMIPTR(pScrn);
964    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
965    int r, g, b;
966
967    ENTER();
968
969    SetAttr(pScrn, XV_ENCODING, 0);     /* Encoding = pal-composite-0 */
970    SetAttr(pScrn, XV_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
971    SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
972    SetAttr(pScrn, XV_CONTRAST, 71);    /* Contrast = 71 (CCIR level) */
973    SetAttr(pScrn, XV_SATURATION, 64);  /* Color saturation = 64 (CCIR level) */
974    SetAttr(pScrn, XV_HUE, 0);          /* Hue = 0 */
975
976    switch (pScrn->depth) {
977    case 8:
978	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0x00FF);
979	SetKeyReg(pSmi, FPR08, 0);
980	break;
981    case 15:
982    case 16:
983	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0xFFFF);
984	SetKeyReg(pSmi, FPR08, 0);
985	break;
986    default:
987        r = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.red) >> pScrn->offset.red;
988        g = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.green) >> pScrn->offset.green;
989        b = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.blue) >> pScrn->offset.blue;
990	SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
991	SetKeyReg(pSmi, FPR08, 0);
992	break;
993    }
994
995    SetKeyReg(pSmi, FPR5C, 0xEDEDED | (pPort->Attribute[XV_BRIGHTNESS] << 24));
996
997    LEAVE();
998}
999
1000
1001#if SMI_USE_CAPTURE
1002static int
1003SMI_PutVideo(
1004	ScrnInfoPtr	pScrn,
1005	short		vid_x,
1006	short		vid_y,
1007	short		drw_x,
1008	short		drw_y,
1009	short		vid_w,
1010	short		vid_h,
1011	short		drw_w,
1012	short		drw_h,
1013	RegionPtr	clipBoxes,
1014	pointer		data,
1015	DrawablePtr	pDraw
1016)
1017{
1018    SMI_PortPtr pPort = (SMI_PortPtr) data;
1019    SMIPtr pSmi = SMIPTR(pScrn);
1020    CARD32 vid_pitch, vid_address;
1021    CARD32 vpr00, cpr00;
1022    int xscale, yscale;
1023    BoxRec dstBox;
1024    INT32 x1, y1, x2, y2;
1025    int norm;
1026    int size, width, height, fbPitch;
1027    int top, left;
1028    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1029    xf86CrtcPtr crtc;
1030
1031    ENTER();
1032
1033    DEBUG("Interlaced Video %d\n", pPort->Attribute[XV_INTERLACED]);
1034
1035    if (!pPort->Attribute[XV_INTERLACED]) {
1036	/* no interlace: lines will be doubled */
1037	vid_h /= 2;
1038    }
1039
1040    /* field start aaa*/
1041    norm = pPort->norm[pPort->Attribute[XV_ENCODING]];
1042    vid_x += VideoNorms[norm].HStart;
1043    vid_y += VideoNorms[norm].VStart;
1044    /* only even values allowed (UV-phase) */
1045    vid_x &= ~1;
1046
1047    DEBUG("vid_x=%d vid_y=%d drw_x=%d drw_y=%d  "
1048	  "vid_w=%d vid_h=%d drw_w=%d drw_h=%d\n",
1049	  vid_x, vid_y, drw_x, drw_y, vid_w, vid_h, drw_w, drw_h);
1050
1051    x1 = vid_x;
1052    y1 = vid_y;
1053    x2 = vid_x + vid_w;
1054    y2 = vid_y + vid_h;
1055
1056    width = vid_w;
1057    height = vid_h;
1058
1059    dstBox.x1 = drw_x;
1060    dstBox.y1 = drw_y;
1061    dstBox.x2 = drw_x + drw_w;
1062    dstBox.y2 = drw_y + drw_h;
1063
1064    if(!xf86_crtc_clip_video_helper(pScrn, &crtc, crtcConf->crtc[0], &dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height))
1065	LEAVE(Success);
1066
1067    if (crtc != crtcConf->crtc[0])
1068	LEAVE(Success);
1069
1070    /* Transform dstBox to the CRTC coordinates */
1071    dstBox.x1 -= crtc->x;
1072    dstBox.y1 -= crtc->y;
1073    dstBox.x2 -= crtc->x;
1074    dstBox.y2 -= crtc->y;
1075
1076    DEBUG("Clip: x1=%d y1=%d x2=%d y2=%d\n",  x1 >> 16, y1 >> 16, x2 >> 16, y2 >> 16);
1077
1078    vid_pitch = (vid_w * 2 + 7) & ~7;
1079
1080    vpr00 = READ_VPR(pSmi, 0x00) & ~0x0FF000FF;
1081    cpr00 = READ_CPR(pSmi, 0x00) & ~0x000FFF00;
1082
1083    /* vpr00:
1084       Bit 2..0   = 6: Video Window I Format                    = YUV4:2:2
1085       Bit 3      = 1: Video Window I Enable                    = enabled
1086       Bit 4      = 0: Video Window I YUV Averaging             = disabled
1087       Bit 5      = 0: Video Window I Hor. Replication          = disabled
1088       Bit 6      = 0: Video Window I data doubling             = disabled
1089       Bit 14..8  = 0: Video Window II                          = disabled
1090       Bit 18..16 = 0: Graphics Data Format                     = 8-bit index
1091       Bit 19     = 0: Top Video Window Select                  = window I
1092       Bit 20     = 1: Color Key for Window I                   = enabled
1093       Bit 21     = 0: Vertical Interpolation                   = s. below
1094       Bit 22     = 0: Flicker Reduction for TV Modes           = disabled
1095       Bit 23     = 0: Fixed Vertical Interpolation             = disabled
1096       Bit 24     = 1: Select Video Window I Source Addr        =
1097       Bit 25     = 0: Enable V0FIFO to fetch 8-Bit color data  = disabled
1098       Bit 26     = 0:
1099       Bit 27     = 1: Color Key for Window II                  = disabled
1100       Bit 31..28 = reserved
1101    */
1102    if (pPort->Attribute[XV_INTERLACED]) {
1103	/*
1104	  Bit 21     = 0: Vertical Interpolation                   = disabled
1105	  Bit 24     = 0: Select Video Window I Source Addr        = 0
1106	*/
1107	vpr00 |= 0x0010000E;
1108    } else {
1109	/*
1110	  Bit 21     = 1: Vertical Interpolation                   = enabled
1111	  Bit 24     = 1: Select Video Window I Source Addr        = 1
1112	  1= Video window I source addr = capture port buffer ?
1113	*/
1114	vpr00 |= 0x0130000E;
1115    }
1116
1117    /* cpr00:
1118       Bit 0      = 1: Video Capture Enable                     = enabled
1119       Bit 8      = 0: Capture Control                          = continuous
1120       Bit 9      = 0: Double Buffer Enable                     = s. below
1121       Bit 10     = 0: Interlace Data Capture                   = s. below
1122       Bit 13..11 = 0: Frame Skip Enable                        = s. below
1123       Bit 15..14 = 0: Video Capture Input Format               = YUV4:2:2
1124       Bit 17..16 = 0: Enable Hor. Reduction                    = s. below
1125       Bit 19..18 = 0: Enable Vert. Reduction                   = s. below
1126       Bit 21..20 = 0: Enable Hor. Filtering                    = s. below
1127       Bit 22     = 0: HREF Polarity                            = high active
1128       Bit 23     = 0: VREF Polarity                            = high active
1129       Bit 24     = 1: Field Detection Method VSYNC edge        = rising
1130    */
1131    if (pPort->Attribute[XV_INTERLACED]) {
1132	/*
1133	  Bit 9      = 1: Double Buffer Enable                  = enabled
1134	  Bit 10     = 1: Interlace Data Capture                = enabled
1135	  Bit 13..11 = 0: Frame Skip Enable                     = no skip
1136	*/
1137	cpr00 |= 0x01000601;
1138    } else {
1139	/*
1140	  Bit 9      = 0: Double Buffer Enable                  = disabled
1141	  Bit 10     = 0: Interlace Data Capture                = disabled
1142	  Bit 13..11 = 010: Frame Skip Enable                   = skip every other frame
1143	*/
1144	cpr00 |= 0x01001001;
1145    }
1146
1147    if (pSmi->ByteSwap)
1148	cpr00 |= 0x00004000;
1149
1150    fbPitch = (pScrn->displayWidth * pSmi->Bpp + 15) & ~15;
1151
1152    if (vid_w <= drw_w) {
1153	xscale = (256 * vid_w / drw_w) & 0xFF;
1154    } else if (vid_w / 2 <= drw_w) {
1155	xscale = (128 * vid_w / drw_w) & 0xFF;
1156	width /= 2;
1157	vid_pitch /= 2;
1158	cpr00 |= 0x00010000;
1159    } else if (vid_w / 4 <= drw_w) {
1160	xscale = (64 * vid_w / drw_w) & 0xFF;
1161	width /= 4;
1162	vid_pitch /= 4;
1163	cpr00 |= 0x00020000;
1164    } else {
1165	xscale = 0;
1166	width /= 4;
1167	vid_pitch /= 4;
1168	cpr00 |= 0x00020000;
1169    }
1170
1171    if (vid_h <= drw_h) {
1172	yscale = (256 * vid_h / drw_h) & 0xFF;
1173    } else if (vid_h / 2 <= drw_h) {
1174	yscale = (128 * vid_h / drw_h) & 0xFF;
1175	height /= 2;
1176	cpr00 |= 0x00040000;
1177    } else if (vid_h / 4 <= drw_h) {
1178	yscale = (64 * vid_h / drw_h) & 0xFF;
1179	height /= 4;
1180	cpr00 |= 0x00080000;
1181    } else {
1182	yscale = 0;
1183	height /= 4;
1184	cpr00 |= 0x00080000;
1185    }
1186
1187    do {
1188	size = vid_pitch * height;
1189	DEBUG("SMI_AllocateMemory: vid_pitch=%d height=%d size=%d\n",
1190	      vid_pitch, height, size);
1191	pPort->video_offset = SMI_AllocateMemory(pScrn, &pPort->video_memory, size);
1192        if (pPort->video_offset == 0) {
1193	    if ((cpr00 & 0x000C0000) == 0) {
1194		/* height -> 1/2 height */
1195		yscale = (128 * vid_h / drw_h) & 0xFF;
1196		height = vid_h / 2;
1197		cpr00 |= 0x00040000;
1198	    } else if (cpr00 & 0x00040000) {
1199		/* 1/2 height -> 1/4 height */
1200		yscale = (64 * vid_h / drw_h) & 0xFF;
1201		height = vid_h / 4;
1202		cpr00 ^= 0x000C0000;
1203	    } else {
1204		/* 1/4 height */
1205		if ((cpr00 & 0x00030000) == 0) {
1206		    /* width -> 1/2 width */
1207		    xscale = (128 * vid_w / drw_w) & 0xFF;
1208		    width = vid_w / 2;
1209		    cpr00 |= 0x00010000;
1210		} else if (cpr00 & 0x00010000) {
1211		    /* 1/2 width -> 1/4 width */
1212		    xscale = (64 * vid_w / drw_w) & 0xFF;
1213		    width = vid_w / 4;
1214		    cpr00 ^= 0x00030000;
1215		} else {
1216		    DEBUG("allocate error\n");
1217		    LEAVE(BadAlloc);
1218		}
1219	    }
1220	}
1221    } while (pPort->video_offset == 0);
1222
1223    DEBUG("xscale==%d yscale=%d width=%d height=%d\n",
1224	  xscale, yscale, width, height);
1225
1226    /* aaa what's this                    ----------------------v ?
1227    vid_address = (pPort->area->box.y1 * fbPitch) + ((y1 >> 16) * vid_pitch);*/
1228    vid_address = pPort->video_offset;
1229
1230    DEBUG("test RegionsEqual\n");
1231    if (!REGION_EQUAL(pScrn->pScreen, &pPort->clip, clipBoxes))
1232    {
1233	DEBUG((VERBLEV, "RegionCopy\n"));
1234        REGION_COPY(pScrn->pScreen, &pPort->clip, clipBoxes);
1235	DEBUG("FillKey\n");
1236	xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY], clipBoxes);
1237
1238    }
1239
1240    left = x1 >> 16;
1241    top = y1 >> 16;
1242    width = (x2 - x1) >> 16;
1243    height = (y2 - y1) >> 16;
1244
1245    if (!IS_MSOC(pSmi))
1246	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1247		      0x21,
1248		      VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1249				   0x21) & ~0x04);
1250    WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) | 0x00200000);
1251    /* Video Window I Left and Top Boundaries */
1252    WRITE_VPR(pSmi, 0x14, dstBox.x1 + (dstBox.y1 << 16));
1253    /* Video Window I Right and Bottom Boundaries */
1254    WRITE_VPR(pSmi, 0x18, dstBox.x2 + (dstBox.y2 << 16));
1255    /* Video Window I Source Width and Offset */
1256    WRITE_VPR(pSmi, 0x20, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1257    /* Video Window I Stretch Factor */
1258    WRITE_VPR(pSmi, 0x24, (xscale << 8) + yscale);
1259
1260    if (pPort->Attribute[XV_INTERLACED]) {
1261	/* Video Window II Left and Top Boundaries */
1262	WRITE_VPR(pSmi, 0x28, dstBox.x1 + (dstBox.y1 << 16));
1263	/* Video Window II Right and Bottom Boundaries */
1264	WRITE_VPR(pSmi, 0x2C, dstBox.x2 + (dstBox.y2 << 16));
1265	/* Video Window II Source Width and Offset */
1266	WRITE_VPR(pSmi, 0x34, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1267	/* Video Window II Stretch Factor */
1268	WRITE_VPR(pSmi, 0x38, (xscale << 8) + yscale);
1269
1270	/* Video Window I Source Start Address */
1271	WRITE_VPR(pSmi, 0x1C, vid_address / 8);
1272	/* Video Window II Source Start Address */
1273	WRITE_VPR(pSmi, 0x30, vid_address / 8);
1274
1275	/* Video Window I Source Start Address */
1276	WRITE_VPR(pSmi, 0x48, vid_address / 8);
1277	/* Video Window II Source Start Address */
1278	WRITE_VPR(pSmi, 0x4C, vid_address / 8 + vid_pitch / 8);
1279
1280	/* Video Source Clipping Control */
1281	WRITE_CPR(pSmi, 0x04, left + ((top/2) << 16));
1282	/* Video Source Capture Size Control */
1283	WRITE_CPR(pSmi, 0x08, width + ((height/2) << 16));
1284	/* Capture Port Buffer I Source Start Address */
1285	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
1286	/* Capture Port Buffer II Source Start Address */
1287	WRITE_CPR(pSmi, 0x10, vid_address / 8 + vid_pitch / 8);
1288	/* Capture Port Source Offset Address */
1289	WRITE_CPR(pSmi, 0x14, 2*(vid_pitch / 8) + ((2*(vid_pitch / 8)) << 16));
1290    } else {
1291	/* Video Source Clipping Control */
1292	WRITE_CPR(pSmi, 0x04, left + (top << 16));
1293	/* Video Source Capture Size Control */
1294	WRITE_CPR(pSmi, 0x08, width + (height << 16));
1295	/* Capture Port Buffer I Source Start Address */
1296	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
1297	/* Capture Port Buffer II Source Start Address */
1298	WRITE_CPR(pSmi, 0x10, vid_address / 8);
1299	/* Capture Port Source Offset Address */
1300	WRITE_CPR(pSmi, 0x14, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1301    }
1302
1303    WRITE_CPR(pSmi, 0x00, cpr00);
1304    WRITE_VPR(pSmi, 0x00, vpr00);
1305
1306    pPort->videoStatus = CLIENT_VIDEO_ON;
1307    DEBUG("SMI_PutVideo success\n");
1308
1309    LEAVE(Success);
1310}
1311#endif
1312
1313
1314static void
1315SMI_StopVideo(
1316	ScrnInfoPtr	pScrn,
1317	pointer		data,
1318	Bool		shutdown
1319)
1320{
1321    SMI_PortPtr pPort = (SMI_PortPtr) data;
1322    SMIPtr pSmi = SMIPTR(pScrn);
1323
1324    ENTER();
1325
1326    REGION_EMPTY(pScrn->pScreen, &pPort->clip);
1327
1328    if (shutdown) {
1329	if (pPort->videoStatus & CLIENT_VIDEO_ON) {
1330	    if (pSmi->Chipset == SMI_COUGAR3DR)
1331		WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
1332	    else if (IS_MSOC(pSmi))
1333		WRITE_DCR(pSmi, 0x0040, READ_DCR(pSmi, 0x0040) & ~0x00000004);
1334	    else
1335		WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x01000008);
1336#if SMI_USE_CAPTURE
1337	    if (!IS_MSOC(pSmi) && pSmi->Chipset != SMI_COUGAR3DR) {
1338		WRITE_CPR(pSmi, 0x00, READ_CPR(pSmi, 0x00) & ~0x00000001);
1339		WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) & ~0x00F00000);
1340	    }
1341#endif
1342	}
1343        if (pPort->video_memory != NULL) {
1344            SMI_FreeMemory(pScrn, pPort->video_memory);
1345            pPort->video_memory = NULL;
1346	}
1347        pPort->videoStatus = 0;
1348        /* pPort->i2cDevice = 0;aaa*/
1349    } else {
1350        if (pPort->videoStatus & CLIENT_VIDEO_ON) {
1351            pPort->videoStatus |= OFF_TIMER;
1352            pPort->offTime = currentTime.milliseconds + OFF_DELAY;
1353	}
1354    }
1355
1356    LEAVE();
1357}
1358
1359static int
1360SMI_SetPortAttribute(
1361	ScrnInfoPtr	pScrn,
1362	Atom		attribute,
1363	INT32		value,
1364	pointer		data
1365)
1366{
1367    int res;
1368    SMI_PortPtr pPort = (SMI_PortPtr) data;
1369    SMIPtr pSmi = SMIPTR(pScrn);
1370
1371    ENTER();
1372
1373    if (attribute == xvColorKey) {
1374	int r, g, b;
1375
1376        pPort->Attribute[XV_COLORKEY] = value;
1377	switch (pScrn->depth) {
1378	case 8:
1379	    SetKeyReg(pSmi, FPR04, value & 0x00FF);
1380	    break;
1381	case 15:
1382	case 16:
1383	    SetKeyReg(pSmi, FPR04, value & 0xFFFF);
1384	    break;
1385	default:
1386	    r = (value & pScrn->mask.red) >> pScrn->offset.red;
1387	    g = (value & pScrn->mask.green) >> pScrn->offset.green;
1388	    b = (value & pScrn->mask.blue) >> pScrn->offset.blue;
1389	    SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
1390	    break;
1391	}
1392	res = Success;
1393    } else if (attribute == xvInterlaced) {
1394        pPort->Attribute[XV_INTERLACED] = (value != 0);
1395	res = Success;
1396    } else if (attribute == xvEncoding) {
1397        res = SetAttr(pScrn, XV_ENCODING, value);
1398    } else if (attribute == xvBrightness) {
1399        res = SetAttr(pScrn, XV_BRIGHTNESS, value);
1400    } else if (attribute == xvCapBrightness) {
1401        res = SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, value);
1402    } else if (attribute == xvContrast) {
1403        res = SetAttr(pScrn, XV_CONTRAST, value);
1404    } else if (attribute == xvSaturation) {
1405        res = SetAttr(pScrn, XV_SATURATION, value);
1406    } else if (attribute == xvHue) {
1407        res = SetAttr(pScrn, XV_HUE, value);
1408    } else {
1409        res = BadMatch;
1410    }
1411
1412    LEAVE(res);
1413}
1414
1415
1416static int
1417SMI_GetPortAttribute(
1418	ScrnInfoPtr	pScrn,
1419	Atom		attribute,
1420	INT32		*value,
1421	pointer		data
1422)
1423{
1424    SMI_PortPtr pPort = (SMI_PortPtr) data;
1425
1426    ENTER();
1427    if (attribute == xvEncoding)
1428        *value = pPort->Attribute[XV_ENCODING];
1429    else if (attribute == xvBrightness)
1430        *value = pPort->Attribute[XV_BRIGHTNESS];
1431    else if (attribute == xvCapBrightness)
1432        *value = pPort->Attribute[XV_CAPTURE_BRIGHTNESS];
1433    else if (attribute == xvContrast)
1434        *value = pPort->Attribute[XV_CONTRAST];
1435    else if (attribute == xvSaturation)
1436        *value = pPort->Attribute[XV_SATURATION];
1437    else if (attribute == xvHue)
1438        *value = pPort->Attribute[XV_HUE];
1439    else if (attribute == xvColorKey)
1440        *value = pPort->Attribute[XV_COLORKEY];
1441    else
1442	LEAVE(BadMatch);
1443
1444    LEAVE(Success);
1445}
1446
1447
1448static void
1449SMI_QueryBestSize(
1450	ScrnInfoPtr		pScrn,
1451	Bool			motion,
1452	short			vid_w,
1453	short			vid_h,
1454	short			drw_w,
1455	short			drw_h,
1456	unsigned int	*p_w,
1457	unsigned int	*p_h,
1458	pointer			data
1459)
1460{
1461    SMIPtr pSmi = SMIPTR(pScrn);
1462
1463    ENTER();
1464
1465    *p_w = min(drw_w, pSmi->lcdWidth);
1466    *p_h = min(drw_h, pSmi->lcdHeight);
1467
1468    LEAVE();
1469}
1470
1471
1472static int
1473SMI_PutImage(
1474	ScrnInfoPtr		pScrn,
1475	short			src_x,
1476	short			src_y,
1477	short			drw_x,
1478	short			drw_y,
1479	short			src_w,
1480	short			src_h,
1481	short			drw_w,
1482	short			drw_h,
1483	int			id,
1484	unsigned char		*buf,
1485	short			width,
1486	short			height,
1487	Bool			sync,
1488	RegionPtr		clipBoxes,
1489	pointer			data,
1490	DrawablePtr		pDraw
1491)
1492{
1493    SMIPtr pSmi = SMIPTR(pScrn);
1494    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
1495    INT32 x1, y1, x2, y2;
1496    int bpp = 0;
1497    int srcPitch, srcPitch2 = 0, dstPitch, size;
1498    BoxRec dstBox;
1499    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
1500    int left, top, nPixels, nLines;
1501    unsigned char *dstStart;
1502    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1503    xf86CrtcPtr crtc;
1504
1505    ENTER();
1506
1507    x1 = src_x;
1508    y1 = src_y;
1509    x2 = src_x + src_w;
1510    y2 = src_y + src_h;
1511
1512    dstBox.x1 = drw_x;
1513    dstBox.y1 = drw_y;
1514    dstBox.x2 = drw_x + drw_w;
1515    dstBox.y2 = drw_y + drw_h;
1516
1517    if (pSmi->CSCVideo) {
1518	if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
1519				   width, height))
1520	    LEAVE(Success);
1521    }
1522    else {
1523	if (!xf86_crtc_clip_video_helper(pScrn, &crtc, crtcConf->crtc[0], &dstBox,
1524					 &x1, &x2, &y1, &y2, clipBoxes,
1525					 width, height))
1526	    LEAVE(Success);
1527
1528	if (!crtc)
1529	    LEAVE(Success);
1530
1531	/* Transform dstBox to the CRTC coordinates */
1532	dstBox.x1 -= crtc->x;
1533	dstBox.y1 -= crtc->y;
1534	dstBox.x2 -= crtc->x;
1535	dstBox.y2 -= crtc->y;
1536    }
1537
1538    switch (id) {
1539    case FOURCC_YV12:
1540    case FOURCC_I420:
1541	srcPitch  = (width + 3) & ~3;
1542	offset2   = srcPitch * height;
1543	srcPitch2 = ((width >> 1) + 3) & ~3;
1544	offset3   = offset2 + (srcPitch2 * (height >> 1));
1545	if (pSmi->CSCVideo)
1546	    dstPitch  = (((width >> 1) + 15) & ~15) << 1;
1547	else
1548	    dstPitch  = ((width << 1) + 15) & ~15;
1549	break;
1550    case FOURCC_RV24:
1551	bpp = 3;
1552	srcPitch = width * bpp;
1553	dstPitch = (srcPitch + 15) & ~15;
1554	break;
1555    case FOURCC_RV32:
1556	bpp = 4;
1557	srcPitch = width * bpp;
1558	dstPitch = (srcPitch + 15) & ~15;
1559	break;
1560    case FOURCC_YUY2:
1561    case FOURCC_RV15:
1562    case FOURCC_RV16:
1563    default:
1564	bpp = 2;
1565	srcPitch = width * bpp;
1566	dstPitch = (srcPitch + 15) & ~15;
1567	break;
1568    }
1569
1570    size = dstPitch * height;
1571    pPort->video_offset = SMI_AllocateMemory(pScrn, &pPort->video_memory, size);
1572    if (pPort->video_memory == NULL)
1573	LEAVE(BadAlloc);
1574
1575    top = y1 >> 16;
1576    left = (x1 >> 16) & ~1;
1577    nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left;
1578    left *= bpp;
1579
1580    offset = pPort->video_offset + (top * dstPitch);
1581    dstStart = pSmi->FBBase + offset + left;
1582
1583    switch(id) {
1584    case FOURCC_YV12:
1585    case FOURCC_I420:
1586	top &= ~1;
1587	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
1588	offset2 += tmp;
1589	offset3 += tmp;
1590	if (pSmi->CSCVideo)
1591	    CopyYV12ToVideoMem(buf,
1592			       buf + offset2, buf + offset3,
1593			       dstStart, srcPitch, srcPitch2, dstPitch,
1594			       height, width);
1595	else {
1596	    if (id == FOURCC_I420) {
1597		tmp = offset2;
1598		offset2 = offset3;
1599		offset3 = tmp;
1600	    }
1601	    nLines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
1602	    xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
1603				    buf + offset2, buf + offset3, dstStart,
1604				    srcPitch, srcPitch2, dstPitch, nLines,
1605				    nPixels);
1606	}
1607	break;
1608    case FOURCC_UYVY:
1609    case FOURCC_YUY2:
1610    default:
1611	buf += (top * srcPitch) + left;
1612	nLines = ((y2 + 0xffff) >> 16) - top;
1613	xf86XVCopyPacked(buf, dstStart, srcPitch, dstPitch, nLines, nPixels);
1614        break;
1615    }
1616
1617    if (IS_MSOC(pSmi) ||
1618	!REGION_EQUAL(pScrn->pScreen, &pPort->clip, clipBoxes)) {
1619	REGION_COPY(pScrn->pScreen, &pPort->clip, clipBoxes);
1620	if (!pSmi->CSCVideo)
1621	    xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY],
1622				clipBoxes);
1623    }
1624
1625    if (pSmi->Chipset == SMI_COUGAR3DR)
1626	SMI_DisplayVideo0730(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2,
1627			     &dstBox, src_w, src_h, drw_w, drw_h);
1628    else if (IS_MSOC(pSmi)) {
1629	if (pSmi->CSCVideo)
1630	    SMI_DisplayVideo0501_CSC(pScrn, id, offset, width, height, dstPitch,
1631				     x1, y1, x2, y2, &dstBox,
1632				     src_w, src_h, drw_w, drw_h, clipBoxes);
1633	else
1634	    SMI_DisplayVideo0501(pScrn, id, offset, width, height, dstPitch,
1635				 x1, y1, x2, y2, &dstBox, src_w, src_h,
1636				 drw_w, drw_h);
1637    }
1638    else{
1639	if(crtc == crtcConf->crtc[0])
1640	    SMI_DisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2,
1641			     &dstBox, src_w, src_h, drw_w, drw_h);
1642    }
1643    pPort->videoStatus = CLIENT_VIDEO_ON;
1644
1645    LEAVE(Success);
1646
1647}
1648
1649
1650static int
1651SMI_QueryImageAttributes(
1652	ScrnInfoPtr	pScrn,
1653	int		id,
1654	unsigned short	*width,
1655	unsigned short	*height,
1656	int		*pitches,
1657	int		*offsets
1658)
1659{
1660    SMIPtr pSmi = SMIPTR(pScrn);
1661    int size, tmp;
1662
1663    ENTER();
1664
1665    if (*width > pSmi->lcdWidth) {
1666	*width = pSmi->lcdWidth;
1667    }
1668    if (*height > pSmi->lcdHeight) {
1669	*height = pSmi->lcdHeight;
1670    }
1671
1672    *width = (*width + 1) & ~1;
1673    if (offsets != NULL) {
1674	offsets[0] = 0;
1675    }
1676
1677    switch (id) {
1678    case FOURCC_YV12:
1679    case FOURCC_I420:
1680	*height = (*height + 1) & ~1;
1681	size = (*width + 3) & ~3;
1682	if (pitches != NULL) {
1683	    pitches[0] = size;
1684	}
1685	size *= *height;
1686	if (offsets != NULL) {
1687	    offsets[1] = size;
1688	}
1689	tmp = ((*width >> 1) + 3) & ~3;
1690	if (pitches != NULL) {
1691	    pitches[1] = pitches[2] = tmp;
1692	}
1693	tmp *= (*height >> 1);
1694	size += tmp;
1695	if (offsets != NULL) {
1696	    offsets[2] = size;
1697	}
1698	size += tmp;
1699	break;
1700    case FOURCC_YUY2:
1701    case FOURCC_RV15:
1702    case FOURCC_RV16:
1703    default:
1704	size = *width * 2;
1705	if (pitches != NULL) {
1706	    pitches[0] = size;
1707	}
1708	size *= *height;
1709	break;
1710    case FOURCC_RV24:
1711	size = *width * 3;
1712	if (pitches != NULL) {
1713	    pitches[0] = size;
1714	}
1715	size *= *height;
1716	break;
1717    case FOURCC_RV32:
1718	size = *width * 4;
1719	if (pitches != NULL) {
1720	    pitches[0] = size;
1721	}
1722	size *= *height;
1723	break;
1724    }
1725
1726    LEAVE(size);
1727}
1728
1729
1730/******************************************************************************\
1731**									      **
1732**	S U P P O R T   F U N C T I O N S				      **
1733**									      **
1734\******************************************************************************/
1735
1736static void
1737SMI_DisplayVideo(
1738	ScrnInfoPtr	pScrn,
1739	int		id,
1740	int		offset,
1741	short		width,
1742	short		height,
1743	int		pitch,
1744	int		x1,
1745	int		y1,
1746	int		x2,
1747	int		y2,
1748	BoxPtr		dstBox,
1749	short		vid_w,
1750	short		vid_h,
1751	short		drw_w,
1752	short		drw_h
1753)
1754{
1755    SMIPtr pSmi = SMIPTR(pScrn);
1756    CARD32 vpr00;
1757    uint32_t hstretch, vstretch;
1758
1759    ENTER();
1760
1761    vpr00 = READ_VPR(pSmi, 0x00) & ~0x0CB800FF;
1762
1763    switch (id) {
1764    case FOURCC_YV12:
1765    case FOURCC_I420:
1766    case FOURCC_YUY2:
1767	vpr00 |= 0x6;
1768	break;
1769    case FOURCC_RV15:
1770	vpr00 |= 0x1;
1771	break;
1772    case FOURCC_RV16:
1773	vpr00 |= 0x2;
1774	break;
1775    case FOURCC_RV24:
1776	vpr00 |= 0x4;
1777	break;
1778    case FOURCC_RV32:
1779	vpr00 |= 0x3;
1780	break;
1781    }
1782
1783    if (drw_w > vid_w) {
1784	hstretch = ((uint32_t)(vid_w - 1) << 16) / (drw_w - 1);
1785    } else {
1786	hstretch = 0;
1787    }
1788
1789    if (drw_h > vid_h) {
1790	vstretch = ((uint32_t)(vid_h - 1) << 16) / (drw_h - 1);
1791	vpr00 |= 1 << 21;
1792    } else {
1793	vstretch = 0;
1794    }
1795
1796    WRITE_VPR(pSmi, 0x00, vpr00 | (1 << 3) | (1 << 20));
1797    WRITE_VPR(pSmi, 0x14, (dstBox->x1) | (dstBox->y1 << 16));
1798    WRITE_VPR(pSmi, 0x18, (dstBox->x2) | (dstBox->y2 << 16));
1799    WRITE_VPR(pSmi, 0x1C, offset >> 3);
1800    WRITE_VPR(pSmi, 0x20, (pitch >> 3) | ((pitch >> 3) << 16));
1801    WRITE_VPR(pSmi, 0x24, (hstretch & 0xff00) | ((vstretch & 0xff00) >> 8));
1802    if (pSmi->Chipset == SMI_LYNXEMplus) {	/* This one can store additional precision */
1803	WRITE_VPR(pSmi, 0x68, ((hstretch & 0xff) << 8) | (vstretch & 0xff));
1804    }
1805
1806    LEAVE();
1807}
1808
1809static void
1810SMI_DisplayVideo0501_CSC(ScrnInfoPtr pScrn, int id, int offset,
1811			 short width, short height, int pitch,
1812			 int x1, int y1, int x2, int y2, BoxPtr dstBox,
1813			 short vid_w, short vid_h, short drw_w, short drw_h,
1814			 RegionPtr clipboxes)
1815{
1816    int32_t	ScaleXn, ScaleXd, ScaleYn, ScaleYd;
1817    int32_t	SrcTn, SrcTd, SrcLn, SrcLd;
1818    int32_t	SrcRn, SrcBn;
1819    int32_t	SrcDimX, SrcDimY;
1820    int32_t	SrcYBase, SrcUBase, SrcVBase, SrcYPitch, SrcUVPitch;
1821    int32_t	DestPitch;
1822    SMIPtr	pSmi = SMIPTR(pScrn);
1823    BoxPtr	pbox = REGION_RECTS(clipboxes);
1824    int		i, nbox = REGION_NUM_RECTS(clipboxes);
1825    int32_t	rect_x, rect_y, rect_w, rect_h, csc;
1826    float	Hscale, Vscale;
1827
1828    ENTER();
1829
1830    SrcYBase = offset;
1831    SrcYPitch = pitch;
1832
1833    DestPitch = (pScrn->displayWidth * pSmi->Bpp + 15) & ~15;
1834
1835    Hscale = (vid_w - 1) / (float)(drw_w - 1);
1836    ScaleXn = Hscale;
1837    ScaleXd = ((vid_w - 1) << 13) / (drw_w - 1) - (ScaleXn << 13);
1838
1839    Vscale = (vid_h - 1) / (float)(drw_h - 1);
1840    ScaleYn = Vscale;
1841    ScaleYd = ((vid_h - 1) << 13) / (drw_h - 1) - (ScaleYn << 13);
1842
1843    /* CSC constants */
1844    WRITE_DPR(pSmi, 0xcc, 0);
1845    /* Use start of framebuffer as base offset */
1846    WRITE_DPR(pSmi, 0xf8, 0);
1847
1848    csc = (1 << 31) | (1 << 25);
1849    if (pSmi->Bpp > 2)
1850	csc |= 1 << 26;
1851
1852    switch (id) {
1853	case FOURCC_YV12:
1854	    SrcUVPitch = SrcYPitch / 2;
1855	    SrcVBase = SrcYBase + SrcYPitch * height;
1856	    SrcUBase = SrcVBase + SrcUVPitch * height / 2;
1857	    csc |= 2 << 28;
1858	    break;
1859
1860	case FOURCC_I420:
1861	    SrcUVPitch = SrcYPitch / 2;
1862	    SrcUBase = SrcYBase + SrcYPitch * height;
1863	    SrcVBase = SrcUBase + SrcUVPitch * height / 2;
1864	    csc |= 2 << 28;
1865	    break;
1866
1867	case FOURCC_YUY2:
1868	case FOURCC_RV16:
1869	case FOURCC_RV32:
1870	    SrcUBase = SrcVBase = SrcYBase;
1871	    SrcUVPitch = SrcYPitch;
1872	    break;
1873
1874	default:
1875	    LEAVE();
1876    }
1877
1878    WRITE_DPR(pSmi, 0xE4, ((SrcYPitch >> 4) << 16) | (SrcUVPitch >> 4));
1879    WRITE_DPR(pSmi, 0xC8, SrcYBase);
1880    WRITE_DPR(pSmi, 0xD8, SrcUBase);
1881    WRITE_DPR(pSmi, 0xDC, SrcVBase);
1882    WRITE_DPR(pSmi, 0xF4, (((ScaleXn << 13) | ScaleXd) << 16) |
1883	      (ScaleYn << 13 | ScaleYd));
1884
1885    for (i = 0; i < nbox; i++, pbox++) {
1886	rect_x = pbox->x1;
1887	rect_y = pbox->y1;
1888	rect_w = pbox->x2 - pbox->x1;
1889	rect_h = pbox->y2 - pbox->y1;
1890
1891	SrcLn = (rect_x - dstBox->x1) * Hscale;
1892	SrcLd = ((rect_x - dstBox->x1) << 13) * Hscale - (SrcLn << 13);
1893	SrcRn = (rect_x + rect_w - dstBox->x1) * Hscale;
1894
1895	SrcTn = (rect_y - dstBox->y1) * Vscale;
1896	SrcTd = ((rect_y - dstBox->y1) << 13) * Vscale - (SrcTn << 13);
1897	SrcBn = (rect_y + rect_h - dstBox->y1) * Vscale;
1898
1899	SrcDimX = SrcRn - SrcLn + 2;
1900	SrcDimY = SrcBn - SrcTn + 2;
1901
1902	WRITE_DPR(pSmi, 0xD0, (SrcLn << 16) | SrcLd);
1903	WRITE_DPR(pSmi, 0xD4, (SrcTn << 16) | SrcTd);
1904	WRITE_DPR(pSmi, 0xE0, (SrcDimX << 16) | SrcDimY);
1905	WRITE_DPR(pSmi, 0xE8, (rect_x << 16) | rect_y);
1906	WRITE_DPR(pSmi, 0xEC, (rect_w << 16) | rect_h);
1907	WRITE_DPR(pSmi, 0xF0, ((DestPitch >> 4) << 16) | rect_h);
1908
1909	while (READ_DPR(pSmi, 0xfc) & (1 << 31))
1910	    ;
1911	WRITE_DPR(pSmi, 0xfc, csc);
1912	/* CSC stop */
1913	while (READ_DPR(pSmi, 0xfc) & (1 << 31))
1914	    ;
1915    }
1916
1917    LEAVE();
1918}
1919
1920static void
1921SMI_DisplayVideo0501(ScrnInfoPtr pScrn,
1922		     int id,
1923		     int offset,
1924		     short width,
1925		     short height,
1926		     int pitch,
1927		     int x1,
1928		     int y1,
1929		     int x2,
1930		     int y2,
1931		     BoxPtr dstBox,
1932		     short vid_w, short vid_h, short drw_w, short drw_h)
1933{
1934    SMIPtr	pSmi = SMIPTR (pScrn);
1935    CARD32	dcr40;
1936    int		hstretch, vstretch;
1937
1938    ENTER();
1939
1940    dcr40 = READ_DCR(pSmi, 0x0040) & ~0x00003FFF;
1941
1942    switch (id) {
1943	case FOURCC_YV12:
1944	case FOURCC_I420:
1945	case FOURCC_YUY2:
1946	    dcr40 |= 0x3;
1947	    break;
1948
1949	case FOURCC_RV16:
1950	    dcr40 |= 0x1;
1951	    break;
1952
1953	case FOURCC_RV32:
1954	    dcr40 |= 0x2;
1955	    break;
1956    }
1957
1958    if (drw_w > vid_w) {	/*  Horizontal Stretch */
1959	hstretch = 4096 * vid_w / drw_w;
1960	dcr40 |= 1 << 8;
1961    }
1962    else {			/*  Horizontal Shrink */
1963	if (drw_w < (vid_w >> 1))
1964	    drw_w = vid_w >> 1;
1965	hstretch = (4096 * drw_w / vid_w) | 0x8000;
1966    }
1967
1968    if (drw_h > vid_h) {	/* Vertical Stretch */
1969	vstretch = 4096 * vid_h / drw_h;
1970	dcr40 |= 1 << 9;
1971    }
1972    else {			/* Vertical Shrink */
1973	if (drw_h < (vid_h >> 1))
1974	    drw_h = vid_h >> 1;
1975	vstretch = (4096 * drw_h / vid_h) | 0x8000;
1976    }
1977
1978    /* Set Color Key Enable bit */
1979
1980    WRITE_DCR(pSmi, 0x0000, READ_DCR(pSmi, 0x0000) | (1 << 9));
1981    WRITE_DCR(pSmi, 0x0050, dstBox->x1 | (dstBox->y1 << 16));
1982    WRITE_DCR(pSmi, 0x0054, dstBox->x2 | (dstBox->y2 << 16));
1983    WRITE_DCR(pSmi, 0x0044, offset);
1984
1985    WRITE_DCR(pSmi, 0x0048, pitch | (pitch << 16));
1986    WRITE_DCR(pSmi, 0x004C, offset + (pitch * height));
1987    WRITE_DCR(pSmi, 0x0058, (vstretch << 16) | hstretch);
1988    WRITE_DCR(pSmi, 0x005C, 0x00000000);
1989    WRITE_DCR(pSmi, 0x0060, 0x00EDEDED);
1990
1991    WRITE_DCR(pSmi, 0x0040, dcr40 | (1 << 2));
1992
1993    LEAVE();
1994}
1995
1996static void
1997SMI_DisplayVideo0730(
1998	ScrnInfoPtr	pScrn,
1999	int		id,
2000	int		offset,
2001	short		width,
2002	short		height,
2003	int		pitch,
2004	int		x1,
2005	int		y1,
2006	int		x2,
2007	int		y2,
2008	BoxPtr		dstBox,
2009	short		vid_w,
2010	short		vid_h,
2011	short		drw_w,
2012	short		drw_h
2013)
2014{
2015    SMIPtr pSmi = SMIPTR(pScrn);
2016    CARD32 fpr00;
2017    int hstretch, vstretch;
2018
2019    ENTER();
2020
2021    fpr00 = READ_FPR(pSmi, 0x00) & ~(FPR00_MASKBITS);
2022
2023    switch (id) {
2024    case FOURCC_YV12:
2025    case FOURCC_I420:
2026    case FOURCC_YUY2:
2027	fpr00 |= FPR00_FMT_YUV422;
2028	break;
2029    case FOURCC_RV15:
2030	fpr00 |= FPR00_FMT_15P;
2031	break;
2032    case FOURCC_RV16:
2033	fpr00 |= FPR00_FMT_16P;
2034	break;
2035    case FOURCC_RV24:
2036	fpr00 |= FPR00_FMT_24P;
2037	break;
2038    case FOURCC_RV32:
2039	fpr00 |= FPR00_FMT_32P;
2040	break;
2041    }
2042
2043    /* the formulas for calculating the stretch values do not match the
2044       documentation, but they're the same as the ddraw driver and they work */
2045    if (drw_w > vid_w) {
2046	hstretch = (8192 * vid_w / drw_w);
2047    } else {
2048	hstretch = 0;
2049    }
2050
2051    if (drw_h > vid_h) {
2052	vstretch = (8192 * vid_h / drw_h);
2053    } else {
2054	vstretch = 0;
2055    }
2056
2057    WRITE_FPR(pSmi, FPR00, fpr00 | FPR00_VWIENABLE | FPR00_VWIKEYENABLE);
2058    WRITE_FPR(pSmi, FPR14, (dstBox->x1) | (dstBox->y1 << 16));
2059    WRITE_FPR(pSmi, FPR18, (dstBox->x2) | (dstBox->y2 << 16));
2060    WRITE_FPR(pSmi, FPR1C, offset >> 3);
2061    WRITE_FPR(pSmi, FPR20, (pitch >> 3) | ((pitch >> 3) << 16));
2062    WRITE_FPR(pSmi, FPR24, (hstretch & 0xFF00) | ((vstretch & 0xFF00)>>8));
2063    WRITE_FPR(pSmi, FPR68, ((hstretch & 0x00FF)<<8) | (vstretch & 0x00FF));
2064
2065    LEAVE();
2066}
2067
2068static void
2069SMI_BlockHandler(BLOCKHANDLER_ARGS_DECL)
2070{
2071    SCREEN_PTR(arg);
2072    ScrnInfoPtr	pScrn	= xf86ScreenToScrn(pScreen);
2073    SMIPtr	pSmi    = SMIPTR(pScrn);
2074    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2075
2076    pScreen->BlockHandler = pSmi->BlockHandler;
2077    (*pScreen->BlockHandler)(BLOCKHANDLER_ARGS);
2078    pScreen->BlockHandler = SMI_BlockHandler;
2079
2080    if (pPort->videoStatus & TIMER_MASK) {
2081	UpdateCurrentTime();
2082        if (pPort->videoStatus & OFF_TIMER) {
2083            if (pPort->offTime < currentTime.milliseconds) {
2084		if (pSmi->Chipset == SMI_COUGAR3DR) {
2085		    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
2086		}
2087		else if (IS_MSOC(pSmi))
2088		    WRITE_DCR(pSmi, 0x0040, READ_DCR(pSmi, 0x0040) & ~0x00000004);
2089		else
2090		    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
2091                pPort->videoStatus = FREE_TIMER;
2092                pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
2093	    }
2094	} else {
2095            if (pPort->freeTime < currentTime.milliseconds) {
2096		SMI_FreeMemory(pScrn, pPort->video_memory);
2097                pPort->video_memory = NULL;
2098	    }
2099            pPort->videoStatus = 0;
2100	}
2101    }
2102}
2103
2104#if 0
2105static int
2106SMI_SendI2C(
2107	ScrnInfoPtr		pScrn,
2108	CARD8			device,
2109	char			*devName,
2110	SMI_I2CDataPtr	i2cData
2111)
2112{
2113    SMIPtr	pSmi = SMIPTR(pScrn);
2114    I2CDevPtr	dev;
2115    int		status = Success;
2116
2117    ENTER();
2118
2119    if (pSmi->I2C == NULL)
2120	LEAVE(BadAlloc);
2121
2122    dev = xf86CreateI2CDevRec();
2123    if (dev == NULL)
2124	LEAVE(BadAlloc);
2125
2126    dev->DevName = devName;
2127    dev->SlaveAddr = device;
2128    dev->pI2CBus = pSmi->I2C;
2129
2130    if (!xf86I2CDevInit(dev))
2131	status = BadAlloc;
2132    else {
2133	while (i2cData->address != 0xFF || i2cData->data != 0xFF) {	/* PDR#676 */
2134	    if (!xf86I2CWriteByte(dev, i2cData->address, i2cData->data)) {
2135		status = BadAlloc;
2136		break;
2137	    }
2138	    i2cData++;
2139	}
2140    }
2141
2142    xf86DestroyI2CDevRec(dev, TRUE);
2143
2144    LEAVE(status);
2145}
2146#endif
2147
2148/******************************************************************************\
2149**									      **
2150**	 O F F S C R E E N   M E M O R Y   M A N A G E R		      **
2151**									      **
2152\******************************************************************************/
2153
2154static void
2155SMI_InitOffscreenImages(
2156	ScreenPtr	pScreen
2157)
2158{
2159    XF86OffscreenImagePtr offscreenImages;
2160    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2161    SMIPtr pSmi = SMIPTR(pScrn);
2162    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2163
2164    ENTER();
2165
2166    offscreenImages = malloc(sizeof(XF86OffscreenImageRec));
2167    if (offscreenImages == NULL) {
2168	LEAVE();
2169    }
2170
2171    offscreenImages->image = SMI_VideoImages;
2172    offscreenImages->flags = VIDEO_OVERLAID_IMAGES;
2173    if (IS_MSOC(pSmi))
2174	offscreenImages->flags |= VIDEO_CLIP_TO_VIEWPORT;
2175    offscreenImages->alloc_surface = SMI_AllocSurface;
2176    offscreenImages->free_surface = SMI_FreeSurface;
2177    offscreenImages->display = SMI_DisplaySurface;
2178    offscreenImages->stop = SMI_StopSurface;
2179    offscreenImages->getAttribute = SMI_GetSurfaceAttribute;
2180    offscreenImages->setAttribute = SMI_SetSurfaceAttribute;
2181    offscreenImages->max_width = pSmi->lcdWidth;
2182    offscreenImages->max_height = pSmi->lcdHeight;
2183    if (!pPort->I2CDev.SlaveAddr) {
2184	offscreenImages->num_attributes = nElems(SMI_VideoAttributes);
2185	offscreenImages->attributes = SMI_VideoAttributes;
2186    } else {
2187	offscreenImages->num_attributes = nElems(SMI_VideoAttributesSAA711x);
2188	offscreenImages->attributes = SMI_VideoAttributesSAA711x;
2189    }
2190    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
2191
2192    LEAVE();
2193}
2194
2195static void
2196SMI_VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
2197{
2198    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2199    SMIPtr pSmi = SMIPTR(pScrn);
2200    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2201
2202    ENTER();
2203
2204    if (pPort->video_memory == area)
2205	pPort->video_memory = NULL;
2206
2207    LEAVE();
2208}
2209
2210CARD32
2211SMI_AllocateMemory(ScrnInfoPtr pScrn, void **mem_struct, int size)
2212{
2213    ScreenPtr	pScreen = xf86ScrnToScreen(pScrn);
2214    SMIPtr	pSmi = SMIPTR(pScrn);
2215    int		offset = 0;
2216
2217    ENTER();
2218
2219    if (pSmi->useEXA) {
2220	ExaOffscreenArea *area = *mem_struct;
2221
2222	if (area != NULL) {
2223	    if (area->size >= size)
2224		LEAVE(area->offset);
2225
2226	    exaOffscreenFree(pScrn->pScreen, area);
2227	}
2228
2229	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE,
2230				 SMI_VideoSave, NULL);
2231
2232	*mem_struct = area;
2233	if (area != NULL)
2234	    offset = area->offset;
2235    }
2236    else {
2237	FBLinearPtr	linear = *mem_struct;
2238
2239	/*  XAA allocates in units of pixels at the screen bpp,
2240	 *  so adjust size appropriately.
2241	 */
2242	size = (size + pSmi->Bpp - 1) / pSmi->Bpp;
2243
2244	if (linear) {
2245	    if (linear->size >= size)
2246		LEAVE(linear->offset * pSmi->Bpp);
2247
2248	    if (xf86ResizeOffscreenLinear(linear, size))
2249		LEAVE(linear->offset * pSmi->Bpp);
2250
2251	    xf86FreeOffscreenLinear(linear);
2252	}
2253	else {
2254	    int max_size;
2255
2256	    xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
2257					    PRIORITY_EXTREME);
2258	    if (max_size < size)
2259		LEAVE(0);
2260
2261	    xf86PurgeUnlockedOffscreenAreas(pScreen);
2262	}
2263
2264	linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
2265					     NULL, NULL, NULL);
2266	if ((*mem_struct = linear) != NULL)
2267	    offset = linear->offset * pSmi->Bpp;
2268
2269	DEBUG("offset = %p\n", offset);
2270    }
2271
2272    LEAVE(offset);
2273}
2274
2275void
2276SMI_FreeMemory(
2277	ScrnInfoPtr pScrn,
2278	void *mem_struct
2279)
2280{
2281    SMIPtr pSmi = SMIPTR(pScrn);
2282
2283    ENTER();
2284
2285    if (pSmi->useEXA) {
2286	ExaOffscreenArea *area = mem_struct;
2287
2288	if (area != NULL)
2289	    exaOffscreenFree(pScrn->pScreen, area);
2290    } else {
2291	FBLinearPtr linear = mem_struct;
2292
2293	if (linear != NULL)
2294	    xf86FreeOffscreenLinear(linear);
2295    }
2296
2297    LEAVE();
2298}
2299
2300static void
2301CopyYV12ToVideoMem(unsigned char *src1, unsigned char *src2,
2302		   unsigned char *src3, unsigned char *dst,
2303		   int src1Pitch, int src23Pitch, int dstPitch,
2304		   int height, int width)
2305{
2306    int		j = height;
2307
2308    ENTER();
2309
2310    /* copy 1 data */
2311    while (j -- > 0) {
2312	memcpy(dst, src1, width);
2313	src1 += src1Pitch;
2314	dst += dstPitch;
2315    }
2316    /* copy 2 data */
2317    j = height / 2;
2318    while (j -- > 0) {
2319	memcpy(dst, src2, width / 2);
2320	src2 += src23Pitch;
2321	dst += dstPitch / 2;
2322    }
2323    /* copy 3 data */
2324    j = height / 2;
2325    while (j -- > 0) {
2326	memcpy(dst, src3, width / 2);
2327	src3 += src23Pitch;
2328	dst += dstPitch / 2;
2329    }
2330
2331    LEAVE();
2332}
2333
2334static int
2335SMI_AllocSurface(
2336	ScrnInfoPtr	pScrn,
2337	int		id,
2338	unsigned short	width,
2339	unsigned short	height,
2340	XF86SurfacePtr	surface
2341)
2342{
2343    SMIPtr pSmi = SMIPTR(pScrn);
2344    int pitch, bpp, offset, size;
2345    void *surface_memory = NULL;
2346    SMI_OffscreenPtr ptrOffscreen;
2347
2348    ENTER();
2349
2350    if (width > pSmi->lcdWidth || height > pSmi->lcdHeight)
2351	LEAVE(BadAlloc);
2352
2353    switch (id) {
2354    case FOURCC_YV12:
2355    case FOURCC_I420:
2356    case FOURCC_YUY2:
2357    case FOURCC_RV15:
2358    case FOURCC_RV16:
2359	bpp = 2;
2360	break;
2361    case FOURCC_RV24:
2362	bpp = 3;
2363	break;
2364    case FOURCC_RV32:
2365	bpp = 4;
2366	break;
2367    default:
2368	LEAVE(BadAlloc);
2369    }
2370
2371    width = (width + 1) & ~1;
2372    pitch = (width * bpp + 15) & ~15;
2373    size  = pitch * height;
2374
2375    offset = SMI_AllocateMemory(pScrn, &surface_memory, size);
2376    if (offset == 0)
2377	LEAVE(BadAlloc);
2378
2379    surface->pitches = malloc(sizeof(int));
2380    if (surface->pitches == NULL) {
2381	SMI_FreeMemory(pScrn, surface_memory);
2382	LEAVE(BadAlloc);
2383    }
2384    surface->offsets = malloc(sizeof(int));
2385    if (surface->offsets == NULL) {
2386	free(surface->pitches);
2387	SMI_FreeMemory(pScrn, surface_memory);
2388	LEAVE(BadAlloc);
2389    }
2390
2391    ptrOffscreen = malloc(sizeof(SMI_OffscreenRec));
2392    if (ptrOffscreen == NULL) {
2393	free(surface->offsets);
2394	free(surface->pitches);
2395	SMI_FreeMemory(pScrn, surface_memory);
2396	LEAVE(BadAlloc);
2397    }
2398
2399    surface->pScrn = pScrn;
2400    surface->id = id;
2401    surface->width = width;
2402    surface->height = height;
2403    surface->pitches[0] = pitch;
2404    surface->offsets[0] = offset;
2405    surface->devPrivate.ptr = (pointer) ptrOffscreen;
2406
2407    ptrOffscreen->surface_memory = surface_memory;
2408    ptrOffscreen->isOn = FALSE;
2409
2410    LEAVE(Success);
2411}
2412
2413static int
2414SMI_FreeSurface(
2415	XF86SurfacePtr	surface
2416)
2417{
2418    ScrnInfoPtr pScrn = surface->pScrn;
2419    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2420
2421    ENTER();
2422
2423    if (ptrOffscreen->isOn) {
2424	SMI_StopSurface(surface);
2425    }
2426
2427    SMI_FreeMemory(pScrn, ptrOffscreen->surface_memory);
2428    free(surface->pitches);
2429    free(surface->offsets);
2430    free(surface->devPrivate.ptr);
2431
2432    LEAVE(Success);
2433}
2434
2435static int
2436SMI_DisplaySurface(
2437	XF86SurfacePtr	surface,
2438	short		vid_x,
2439	short		vid_y,
2440	short		drw_x,
2441	short		drw_y,
2442	short		vid_w,
2443	short		vid_h,
2444	short		drw_w,
2445	short		drw_h,
2446	RegionPtr	clipBoxes
2447)
2448{
2449    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2450    SMIPtr pSmi = SMIPTR(surface->pScrn);
2451    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2452    INT32 x1, y1, x2, y2;
2453    BoxRec dstBox;
2454    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(surface->pScrn);
2455    xf86CrtcPtr crtc;
2456
2457    ENTER();
2458
2459    x1 = vid_x;
2460    x2 = vid_x + vid_w;
2461    y1 = vid_y;
2462    y2 = vid_y + vid_h;
2463
2464    dstBox.x1 = drw_x;
2465    dstBox.x2 = drw_x + drw_w;
2466    dstBox.y1 = drw_y;
2467    dstBox.y2 = drw_y + drw_h;
2468
2469    if(!xf86_crtc_clip_video_helper(surface->pScrn, &crtc, crtcConf->crtc[0], &dstBox,
2470				    &x1, &x2, &y1, &y2, clipBoxes, surface->width, surface->height))
2471	LEAVE(Success);
2472
2473    if (!crtc)
2474	LEAVE(Success);
2475
2476    /* Transform dstBox to the CRTC coordinates */
2477    dstBox.x1 -= crtc->x;
2478    dstBox.y1 -= crtc->y;
2479    dstBox.x2 -= crtc->x;
2480    dstBox.y2 -= crtc->y;
2481
2482    xf86XVFillKeyHelper(surface->pScrn->pScreen,
2483			pPort->Attribute[XV_COLORKEY], clipBoxes);
2484    SMI_ResetVideo(surface->pScrn);
2485
2486    if (pSmi->Chipset == SMI_COUGAR3DR)
2487	SMI_DisplayVideo0730(surface->pScrn, surface->id, surface->offsets[0],
2488			     surface->width, surface->height, surface->pitches[0], x1, y1, x2,
2489			     y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2490    else if (IS_MSOC(pSmi))
2491	SMI_DisplayVideo0501(surface->pScrn, surface->id,
2492			     surface->offsets[0], surface->width,
2493			     surface->height, surface->pitches[0], x1, y1,
2494			     x2, y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2495    else{
2496	if(crtc == crtcConf->crtc[0])
2497	    SMI_DisplayVideo(surface->pScrn, surface->id, surface->offsets[0],
2498			     surface->width, surface->height, surface->pitches[0], x1, y1, x2,
2499			     y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2500    }
2501
2502    ptrOffscreen->isOn = TRUE;
2503    if (pPort->videoStatus & CLIENT_VIDEO_ON) {
2504        REGION_EMPTY(surface->pScrn->pScreen, &pPort->clip);
2505	UpdateCurrentTime();
2506        pPort->videoStatus = FREE_TIMER;
2507        pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
2508    }
2509
2510    LEAVE(Success);
2511}
2512
2513static int
2514SMI_StopSurface(
2515	XF86SurfacePtr	surface
2516)
2517{
2518    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2519
2520    ENTER();
2521
2522    if (ptrOffscreen->isOn) {
2523	SMIPtr pSmi = SMIPTR(surface->pScrn);
2524	if (pSmi->Chipset == SMI_COUGAR3DR) {
2525	    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
2526	} else {
2527	    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
2528	}
2529
2530	ptrOffscreen->isOn = FALSE;
2531    }
2532
2533    LEAVE(Success);
2534}
2535
2536static int
2537SMI_GetSurfaceAttribute(
2538	ScrnInfoPtr	pScrn,
2539	Atom		attr,
2540	INT32		*value
2541)
2542{
2543    SMIPtr pSmi = SMIPTR(pScrn);
2544
2545    return SMI_GetPortAttribute(pScrn, attr, value,
2546			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
2547}
2548
2549static int
2550SMI_SetSurfaceAttribute(
2551	ScrnInfoPtr	pScrn,
2552	Atom		attr,
2553	INT32		value
2554)
2555{
2556    SMIPtr pSmi = SMIPTR(pScrn);
2557
2558    return SMI_SetPortAttribute(pScrn, attr, value,
2559			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
2560}
2561
2562static void
2563SetKeyReg(SMIPtr pSmi, int reg, int value)
2564{
2565    if (pSmi->Chipset == SMI_COUGAR3DR)
2566	WRITE_FPR(pSmi, reg, value);
2567    else if (IS_MSOC(pSmi)) {
2568	/* We don't change the color mask, and we don't do brightness.  IF
2569	 * they write to the colorkey register, we'll write the value to the
2570	 * 501 colorkey register */
2571	if (FPR04 == reg)		   /* Only act on colorkey value writes */
2572	    WRITE_DCR(pSmi, 0x0008, value);/* ColorKey register is DCR08 */
2573    }
2574    else
2575	WRITE_VPR(pSmi, reg, value);
2576}
2577
2578#else /* SMI_USE_VIDEO */
2579void SMI_InitVideo(ScreenPtr pScreen) {}
2580#endif
2581