smi_video.c revision e4f6584c
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(int i, pointer blockData, pointer pTimeout,
127		pointer pReadMask);
128/*static int SMI_SendI2C(ScrnInfoPtr pScrn, CARD8 device, char *devName,
129        SMI_I2CDataPtr i2cData);*/
130
131static void SMI_InitOffscreenImages(ScreenPtr pScreen);
132static void SMI_VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area);
133
134static void CopyYV12ToVideoMem(unsigned char *src1, unsigned char *src2,
135			       unsigned char *src3, unsigned char *dst,
136			       int src1Pitch, int src23Pitch, int dstPitch,
137			       int height, int width);
138static int SMI_AllocSurface(ScrnInfoPtr pScrn,
139		int id, unsigned short width, unsigned short height,
140		XF86SurfacePtr surface);
141static int SMI_FreeSurface(XF86SurfacePtr surface);
142static int SMI_DisplaySurface(XF86SurfacePtr surface,
143		short vid_x, short vid_y, short drw_x, short drw_y,
144		short vid_w, short vid_h, short drw_w, short drw_h,
145		RegionPtr clipBoxes);
146static int SMI_StopSurface(XF86SurfacePtr surface);
147static int SMI_GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value);
148static int SMI_SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value);
149
150static int SetAttr(ScrnInfoPtr pScrn, int i, int value);
151static int SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value);
152static int SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value);
153static void SetKeyReg(SMIPtr pSmi, int reg, int value);
154
155/**
156 * Atoms
157 */
158
159static Atom xvColorKey;
160static Atom xvEncoding;
161static Atom xvBrightness,xvCapBrightness, xvContrast, xvSaturation, xvHue;
162static Atom xvInterlaced;
163
164
165/******************************************************************************\
166**																			  **
167**                           C A P A B I L I T I E S                          **
168**																			  **
169\******************************************************************************/
170
171
172/**************************************************************************/
173/* input channels */
174
175#define N_COMPOSITE_CHANNELS 4
176#define N_SVIDEO_CHANNELS 2
177
178#define N_VIDEO_INPUTS 2
179typedef enum _VideoInput { VID_COMPOSITE, VID_SVIDEO } VideoInput;
180
181
182/**************************************************************************/
183/* video input formats */
184
185typedef struct _VideoInputDataRec {
186    char* name;
187} VideoInputDataRec;
188
189static VideoInputDataRec VideoInputs[] = {
190    { "composite" },
191    { "svideo" }
192};
193
194
195/**************************************************************************/
196/* video norms */
197
198#define N_VIDEO_NORMS 3
199typedef enum _VideoNorm { PAL, NTSC, SECAM } VideoNorm;
200
201typedef struct _VideoNormDataRec {
202    char* name;
203    unsigned long Wt;
204    unsigned long Wa;
205    unsigned long Ht;
206    unsigned long Ha;
207    unsigned long HStart;
208    unsigned long VStart;
209    XvRationalRec rate;
210} VideoNormDataRec;
211
212
213static VideoNormDataRec VideoNorms[] =
214{
215    /* PAL-BDGHI */
216    {"pal", 864, 704, 625, 576, 16, 16, { 1, 50 }},
217    /* NTSC */
218    {"ntsc", 858, 704, 525, 480, 21, 8, { 1001, 60000 }},
219    /* SECAM (not tested) */
220    {"secam", 864, 7040, 625, 576, 31, 16, { 1, 50 }},
221};
222
223
224/**************************************************************************/
225/* number of (generated) XV_ENCODING vaulues */
226#define N_ENCODINGS ((N_VIDEO_NORMS) * (N_COMPOSITE_CHANNELS + N_SVIDEO_CHANNELS))
227
228
229/**************************************************************************/
230
231static XF86VideoFormatRec SMI_VideoFormats[] =
232{
233    { 15, TrueColor },	/* depth, class				*/
234    { 16, TrueColor },	/* depth, class				*/
235    { 24, TrueColor },	/* depth, class				*/
236};
237
238
239/**************************************************************************/
240
241/**
242 * Attributes
243 */
244
245#define XV_ENCODING_NAME        "XV_ENCODING"
246#define XV_BRIGHTNESS_NAME      "XV_BRIGHTNESS"
247#define XV_CAPTURE_BRIGHTNESS_NAME      "XV_CAPTURE_BRIGHTNESS"
248#define XV_CONTRAST_NAME        "XV_CONTRAST"
249#define XV_SATURATION_NAME      "XV_SATURATION"
250#define XV_HUE_NAME             "XV_HUE"
251#define XV_COLORKEY_NAME        "XV_COLORKEY"
252#define XV_INTERLACED_NAME      "XV_INTERLACED"
253
254
255/* fixed order! */
256static XF86AttributeRec SMI_VideoAttributesSAA711x[N_ATTRS] = {
257    {XvSettable | XvGettable,        0, N_ENCODINGS-1, XV_ENCODING_NAME},
258    {XvSettable | XvGettable,        0,           255, XV_BRIGHTNESS_NAME},
259    {XvSettable | XvGettable,        0,           255, XV_CAPTURE_BRIGHTNESS_NAME},
260    {XvSettable | XvGettable,        0,           127, XV_CONTRAST_NAME},
261    {XvSettable | XvGettable,        0,           127, XV_SATURATION_NAME},
262    {XvSettable | XvGettable,     -128,           127, XV_HUE_NAME},
263    {XvSettable | XvGettable, 0x000000,      0xFFFFFF, XV_COLORKEY_NAME},
264    {XvSettable | XvGettable,        0,             1, XV_INTERLACED_NAME},
265};
266
267static XF86AttributeRec SMI_VideoAttributes[2] = {
268    {XvSettable | XvGettable,        0,           255, XV_BRIGHTNESS_NAME},
269    {XvSettable | XvGettable, 0x000000,      0xFFFFFF, XV_COLORKEY_NAME},
270};
271
272
273/**************************************************************************/
274static XF86ImageRec SMI_VideoImages[] =
275{
276    XVIMAGE_YUY2,
277    XVIMAGE_YV12,
278    XVIMAGE_I420,
279    {
280	FOURCC_RV15,			/* id				*/
281	XvRGB,				/* type				*/
282	LSBFirst,			/* byte_order			*/
283	{ 'R', 'V' ,'1', '5',
284	  0x00, '5',  0x00, 0x00,
285	  0x00, 0x00, 0x00, 0x00,
286	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
287	16,				/* bits_per_pixel		*/
288	XvPacked,			/* format			*/
289	1,				/* num_planes			*/
290	15,				/* depth			*/
291	0x001F, 0x03E0, 0x7C00,		/* red_mask, green, blue	*/
292	0, 0, 0,			/* y_sample_bits, u, v		*/
293	0, 0, 0,			/* horz_y_period, u, v		*/
294	0, 0, 0,			/* vert_y_period, u, v		*/
295	{ 'R', 'V', 'B' },		/* component_order		*/
296	XvTopToBottom			/* scaline_order		*/
297    },
298    {
299	FOURCC_RV16,			/* id				*/
300	XvRGB,				/* type				*/
301	LSBFirst,			/* byte_order			*/
302	{ 'R', 'V' ,'1', '6',
303	  0x00, 0x00, 0x00, 0x00,
304	  0x00, 0x00, 0x00, 0x00,
305	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
306	16,				/* bits_per_pixel		*/
307	XvPacked,			/* format			*/
308	1,				/* num_planes			*/
309	16,				/* depth			*/
310	0x001F, 0x07E0, 0xF800,		/* red_mask, green, blue	*/
311	0, 0, 0,			/* y_sample_bits, u, v		*/
312	0, 0, 0,			/* horz_y_period, u, v		*/
313	0, 0, 0,			/* vert_y_period, u, v		*/
314	{ 'R', 'V', 'B' },		/* component_order		*/
315	XvTopToBottom			/* scaline_order		*/
316    },
317    {
318	FOURCC_RV24,			/* id				*/
319	XvRGB,				/* type				*/
320	LSBFirst,			/* byte_order			*/
321	{ 'R', 'V' ,'2', '4',
322	  0x00, 0x00, 0x00, 0x00,
323	  0x00, 0x00, 0x00, 0x00,
324	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
325	24,				/* bits_per_pixel		*/
326	XvPacked,			/* format			*/
327	1,				/* num_planes			*/
328	24,				/* depth			*/
329	0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue	*/
330	0, 0, 0,			/* y_sample_bits, u, v		*/
331	0, 0, 0,			/* horz_y_period, u, v		*/
332	0, 0, 0,			/* vert_y_period, u, v		*/
333	{ 'R', 'V', 'B' },		/* component_order			*/
334	XvTopToBottom			/* scaline_order			*/
335    },
336    {
337	FOURCC_RV32,			/* id				*/
338	XvRGB,				/* type				*/
339	LSBFirst,			/* byte_order			*/
340	{ 'R', 'V' ,'3', '2',
341	  0x00, 0x00, 0x00, 0x00,
342	  0x00, 0x00, 0x00, 0x00,
343	  0x00, 0x00, 0x00, 0x00 },	/* guid				*/
344	32,				/* bits_per_pixel		*/
345	XvPacked,			/* format			*/
346	1,				/* num_planes			*/
347	24,				/* depth			*/
348	0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue	*/
349	0, 0, 0,			/* y_sample_bits, u, v		*/
350	0, 0, 0,			/* horz_y_period, u, v		*/
351	0, 0, 0,			/* vert_y_period, u, v		*/
352	{ 'R', 'V', 'B' },		/* component_order			*/
353	XvTopToBottom			/* scaline_order			*/
354    },
355};
356
357
358/**************************************************************************/
359static XF86ImageRec SMI501_VideoImages[] = {
360    XVIMAGE_YUY2,
361    XVIMAGE_YV12,
362    XVIMAGE_I420,
363    {
364     FOURCC_RV16,		/* id                                           */
365     XvRGB,			/* type                                         */
366     LSBFirst,			/* byte_order                           */
367     {'R', 'V', '1', '6',
368      0x00, 0x00, 0x00, 0x00,
369      0x00, 0x00, 0x00, 0x00,
370      0x00, 0x00, 0x00, 0x00},	/* guid                                         */
371     16,			/* bits_per_pixel                       */
372     XvPacked,			/* format                                       */
373     1,				/* num_planes                           */
374     16,			/* depth                                        */
375     0x001F, 0x07E0, 0xF800,	/* red_mask, green, blue        */
376     0, 0, 0,			/* y_sample_bits, u, v          */
377     0, 0, 0,			/* horz_y_period, u, v          */
378     0, 0, 0,			/* vert_y_period, u, v          */
379     {'R', 'V', 'B'},		/* component_order                      */
380     XvTopToBottom		/* scaline_order                        */
381     },
382    {
383     FOURCC_RV32,		/* id                                           */
384     XvRGB,			/* type                                         */
385     LSBFirst,			/* byte_order                           */
386     {'R', 'V', '3', '2',
387      0x00, 0x00, 0x00, 0x00,
388      0x00, 0x00, 0x00, 0x00,
389      0x00, 0x00, 0x00, 0x00},	/* guid                                         */
390     32,			/* bits_per_pixel                       */
391     XvPacked,			/* format                                       */
392     1,				/* num_planes                           */
393     24,			/* depth                                        */
394     0x0000FF, 0x00FF00, 0xFF0000,	/* red_mask, green, blue        */
395     0, 0, 0,			/* y_sample_bits, u, v          */
396     0, 0, 0,			/* horz_y_period, u, v          */
397     0, 0, 0,			/* vert_y_period, u, v          */
398     {'R', 'V', 'B'},		/* component_order                      */
399     XvTopToBottom		/* scaline_order                        */
400     },
401};
402
403/**************************************************************************/
404
405/**
406 * SAA7111 video decoder register values
407 */
408
409
410/** SAA7111 control sequences for selecting one out of four
411    composite input channels */
412static I2CByte SAA7111CompositeChannelSelect[N_COMPOSITE_CHANNELS][4] = {
413    { 0x02, 0xC0, 0x09, 0x4A}, /* CVBS AI11 */
414    { 0x02, 0xC1, 0x09, 0x4A}, /* CVBS AI12 */
415    { 0x02, 0xC2, 0x09, 0x4A}, /* CVBS AI21 */
416    { 0x02, 0xC3, 0x09, 0x4A}, /* CVBS AI22 */
417};
418
419
420/** SAA7111 control sequences for selecting one out of two
421    s-video input channels */
422static I2CByte SAA7111SVideoChannelSelect[N_SVIDEO_CHANNELS][4] = {
423    { 0x02, 0xC6, 0x09, 0xCA}, /* Y/C AI11/AI21 */
424    { 0x02, 0xC7, 0x09, 0xCA}, /* Y/C AI12/AI22 */
425};
426
427
428/** SAA7111 control sequences for selecting one out of three
429    video norms */
430static I2CByte SAA7111VideoStd[3][8] = {
431    {0x06, 108, 0x07, 108, 0x08, 0x09, 0x0E, 0x01}, /* PAL */
432    {0x06, 107, 0x07, 107, 0x08, 0x49, 0x0E, 0x01}, /* NTSC */
433    {0x06, 108, 0x07, 108, 0x08, 0x01, 0x0E, 0x51}  /* SECAM */
434};
435
436
437#if 0
438static I2CByte SAA7110InitData[] =
439{
440	/* Configuration */
441    0x00, 0x4C, 0x01, 0x3C, 0x02, 0x00, 0x03, 0xEF,
442    0x04, 0xBD, 0x05, 0xE2, 0x06, 0x00, 0x07, 0x00,
443    0x08, 0xF8, 0x09, 0xF8, 0x0A, 0x60, 0x0B, 0x60,
444    0x0C, 0x00, 0x0D, 0x80, 0x0E, 0x18, 0x0F, 0xD9,
445    0x10, 0x00, 0x11, 0x2B, 0x12, 0x40, 0x13, 0x40,
446    0x14, 0x42, 0x15, 0x1A, 0x16, 0xFF, 0x17, 0xDA,
447    0x18, 0xE6, 0x19, 0x90, 0x20, 0xD9, 0x21, 0x16,
448    0x22, 0x40, 0x23, 0x40, 0x24, 0x80, 0x25, 0x40,
449    0x26, 0x80, 0x27, 0x4F, 0x28, 0xFE, 0x29, 0x01,
450    0x2A, 0xCF, 0x2B, 0x0F, 0x2C, 0x03, 0x2D, 0x01,
451    0x2E, 0x83, 0x2F, 0x03, 0x30, 0x40, 0x31, 0x35,
452    0x32, 0x02, 0x33, 0x8C, 0x34, 0x03,
453
454	/* NTSC */
455    0x11, 0x2B, 0x0F, 0xD9,
456
457	/* RCA input connector */
458    0x06, 0x00, 0x0E, 0x18, 0x20, 0xD9, 0x21, 0x16,
459    0x22, 0x40, 0x2C, 0x03,
460
461};
462#endif
463
464static I2CByte SAA7111InitData[] =
465{
466    0x11, 0x1D, /* 0D D0=1: automatic colour killer off
467		   D1=0: DMSD data to YUV output
468		   D2=1: output enable H/V sync on
469		   D3=1: output enable YUV data on */
470    0x02, 0xC0, /* Mode 0 */
471    0x03, 0x23, /* automatic gain */
472    0x04, 0x00, /*  */
473    0x05, 0x00, /*  */
474    0x06, 108,  /* hor sync begin */
475    0x07, 108,  /* hor sync stop */
476    0x08, 0x88, /* sync control:
477		   D1-0=00: VNOI = normal mode
478		   D2=0: PLL closed
479		   D3=1: VTR mode
480		   D7=1: automatic field detection */
481    0x09, 0x41, /* 4A luminance control */
482    0x0A, 0x80, /* brightness = 128 (CCIR level) */
483    0x0B, 0x40, /* contrast = 1.0 */
484    0x0C, 0x40, /* crominance = 1.0 (CCIR level) */
485    0x0D, 0x00, /* hue = 0 */
486    0x0E, 0x01, /* chroma bandwidth = nominal
487		   fast colour time constant = nominal
488		   chrom comp filter on
489		   colour standard PAL BGHI, NTSC M */
490    0x10, 0x48, /* luminance delay compensation = 0
491		   VRLN = 1
492		   fine pos of hs = 0
493		   output format = YUV 422 */
494    0x12, 0x00, /* 20 D5=1: VPO in tristate */
495    0x13, 0x00,
496    0x15, 0x00,
497    0x16, 0x00,
498    0x17, 0x00,
499
500};
501
502
503/**************************************************************************/
504
505/**
506 * generates XF86VideoEncoding[i] with video norm norm, video input format
507 * input and video input channel channel
508 */
509static int
510SMI_AddEncoding(XF86VideoEncodingPtr enc, int i,
511		int norm, int input, int channel)
512{
513    char* norm_string;
514    char* input_string;
515    char channel_string[20];
516
517    ENTER();
518
519    norm_string = VideoNorms[norm].name;
520    input_string = VideoInputs[input].name;
521    sprintf(channel_string, "%d", channel);
522    enc[i].id     = i;
523    enc[i].name   = xalloc(strlen(norm_string) +
524			   strlen(input_string) +
525			   strlen(channel_string)+3);
526    if (NULL == enc[i].name)
527	LEAVE(-1);
528
529    enc[i].width  = VideoNorms[norm].Wa;
530    enc[i].height = VideoNorms[norm].Ha;
531    enc[i].rate   = VideoNorms[norm].rate;
532    sprintf(enc[i].name,"%s-%s-%s", norm_string, input_string, channel_string);
533
534    LEAVE(0);
535}
536
537
538/**
539 * builds XF86VideoEncodings with all legal combinations of video norm,
540 * video input format and video input channel
541 */
542static void
543SMI_BuildEncodings(SMI_PortPtr p)
544{
545    int ch, n;
546
547    ENTER();
548
549    /* allocate memory for encoding array */
550    p->enc = xalloc(sizeof(XF86VideoEncodingRec) * N_ENCODINGS);
551    if (NULL == p->enc)
552	goto fail;
553    memset(p->enc,0,sizeof(XF86VideoEncodingRec) * N_ENCODINGS);
554    /* allocate memory for video norm array */
555    p->norm = xalloc(sizeof(int) * N_ENCODINGS);
556    if (NULL == p->norm)
557	goto fail;
558    memset(p->norm,0,sizeof(int) * N_ENCODINGS);
559    /* allocate memory for video input format array */
560    p->input = xalloc(sizeof(int) * N_ENCODINGS);
561    if (NULL == p->input)
562	goto fail;
563    memset(p->input,0,sizeof(int) * N_ENCODINGS);
564    /* allocate memory for video channel number array */
565    p->channel = xalloc(sizeof(int) * N_ENCODINGS);
566    if (NULL == p->channel)
567	goto fail;
568    memset(p->channel,0,sizeof(int) * N_ENCODINGS);
569
570    /* fill arrays */
571    p->nenc = 0;
572    for (ch = 0; ch < N_COMPOSITE_CHANNELS; ch++) {
573	for (n = 0; n < N_VIDEO_NORMS; n++) {
574	    SMI_AddEncoding(p->enc, p->nenc, n, VID_COMPOSITE, ch);
575	    p->norm[p->nenc]  = n;
576	    p->input[p->nenc] = VID_COMPOSITE;
577	    p->channel[p->nenc] = ch;
578	    p->nenc++;
579	}
580    }
581    for (ch = 0; ch < N_SVIDEO_CHANNELS; ch++) {
582	for (n = 0; n < N_VIDEO_NORMS; n++) {
583	    SMI_AddEncoding(p->enc, p->nenc, n, VID_SVIDEO, ch);
584	    p->norm[p->nenc]  = n;
585	    p->input[p->nenc] = VID_SVIDEO;
586	    p->channel[p->nenc] = ch;
587	    p->nenc++;
588	}
589    }
590    LEAVE();
591
592 fail:
593    if (p->input) xfree(p->input);
594    p->input = NULL;
595    if (p->norm) xfree(p->norm);
596    p->norm = NULL;
597    if (p->channel) xfree(p->channel);
598    p->channel = NULL;
599    if (p->enc) xfree(p->enc);
600    p->enc = NULL;
601    p->nenc = 0;
602    LEAVE();
603}
604
605
606/******************************************************************************\
607**                                                                            **
608**                  X V E X T E N S I O N   I N T E R F A C E                 **
609**                                                                            **
610\******************************************************************************/
611
612void
613SMI_InitVideo(ScreenPtr pScreen)
614{
615    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
616    XF86VideoAdaptorPtr *ptrAdaptors, *newAdaptors = NULL;
617    XF86VideoAdaptorPtr newAdaptor = NULL;
618    int numAdaptors;
619
620    ENTER();
621
622    numAdaptors = xf86XVListGenericAdaptors(pScrn, &ptrAdaptors);
623
624    DEBUG("numAdaptors=%d\n", numAdaptors);
625
626    newAdaptor = SMI_SetupVideo(pScreen);
627    DEBUG("newAdaptor=%p\n", newAdaptor);
628    SMI_InitOffscreenImages(pScreen);
629
630    if (newAdaptor != NULL) {
631        if (numAdaptors == 0) {
632            numAdaptors = 1;
633            ptrAdaptors = &newAdaptor;
634        } else {
635            newAdaptors = xalloc((numAdaptors + 1) *
636                    sizeof(XF86VideoAdaptorPtr*));
637            if (newAdaptors != NULL) {
638                memcpy(newAdaptors, ptrAdaptors,
639                        numAdaptors * sizeof(XF86VideoAdaptorPtr));
640                newAdaptors[numAdaptors++] = newAdaptor;
641                ptrAdaptors = newAdaptors;
642            }
643        }
644    }
645
646    if (numAdaptors != 0) {
647        DEBUG("ScreenInit %i\n",numAdaptors);
648        xf86XVScreenInit(pScreen, ptrAdaptors, numAdaptors);
649    }
650
651    if (newAdaptors != NULL) {
652        xfree(newAdaptors);
653    }
654
655    LEAVE();
656}
657
658
659/*************************************************************************/
660
661/*
662 *  Video codec controls
663 */
664
665#if 0
666/**
667 * scales value value of attribute i to range min, max
668 */
669static int
670Scale(int i, int value, int min, int max)
671{
672    return min + (value - SMI_VideoAttributes[i].min_value) * (max - min) /
673	(SMI_VideoAttributes[i].max_value - SMI_VideoAttributes[i].min_value);
674}
675#endif
676/**
677 * sets video decoder attributes channel, encoding, brightness, contrast, saturation, hue
678 */
679static int
680SetAttr(ScrnInfoPtr pScrn, int i, int value)
681{
682    SMIPtr pSmi = SMIPTR(pScrn);
683    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
684
685    if (i < XV_ENCODING || i > XV_HUE)
686	return BadMatch;
687
688    /* clamps value to attribute range */
689    value = CLAMP(value, SMI_VideoAttributes[i].min_value,
690		  SMI_VideoAttributes[i].max_value);
691
692    if (i == XV_BRIGHTNESS) {
693	int my_value = (value <= 128? value + 128 : value - 128);
694	SetKeyReg(pSmi, 0x5C, 0xEDEDED | (my_value << 24));
695    } else if (pPort->I2CDev.SlaveAddr == SAA7110) {
696	return SetAttrSAA7110(pScrn, i, value);
697    } else if (pPort->I2CDev.SlaveAddr == SAA7111) {
698	return SetAttrSAA7111(pScrn, i, value);
699    }
700#if 0
701    else {
702	return XvBadAlloc;
703    }
704#endif
705
706    return Success;
707}
708
709
710/**
711 * sets SAA7110 video decoder attributes channel, encoding, brightness, contrast, saturation, hue
712 */
713static int
714SetAttrSAA7110(ScrnInfoPtr pScrn, int i, int value)
715{
716    /* not supported */
717    return XvBadAlloc;
718}
719
720
721/**
722 * sets SAA7111 video decoder attributes channel, encoding,
723 * brightness, contrast, saturation, hue
724 */
725static int
726SetAttrSAA7111(ScrnInfoPtr pScrn, int i, int value)
727{
728    SMIPtr pSmi = SMIPTR(pScrn);
729    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
730
731    if (i == XV_ENCODING) {
732	int norm;
733	int input;
734	int channel;
735	norm = pPort->norm[value];
736	input = pPort->input[value];
737	channel = pPort->channel[value];
738
739	DEBUG("SetAttribute XV_ENCODING: %d. norm=%d input=%d channel=%d\n",
740	      value, norm, input, channel);
741
742	/* set video norm */
743	if (!xf86I2CWriteVec(&(pPort->I2CDev), SAA7111VideoStd[norm],
744			     ENTRIES(SAA7111VideoStd[norm]) / 2)) {
745	    return XvBadAlloc;
746	}
747	/* set video input format and channel */
748	if (input == VID_COMPOSITE) {
749	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
750				 SAA7111CompositeChannelSelect[channel],
751				 ENTRIES(SAA7111CompositeChannelSelect[channel]) / 2)) {
752		return XvBadAlloc;
753	    }
754	} else {
755	    if (!xf86I2CWriteVec(&(pPort->I2CDev),
756				 SAA7111SVideoChannelSelect[channel],
757				 ENTRIES(SAA7111SVideoChannelSelect[channel]) / 2)) {
758		return XvBadAlloc;
759	    }
760	}
761    } else if (i >= XV_CAPTURE_BRIGHTNESS && i <= XV_HUE) {
762	int slave_adr = 0;
763
764	switch (i) {
765
766	case XV_CAPTURE_BRIGHTNESS:
767	    DEBUG("SetAttribute XV_BRIGHTNESS: %d\n", value);
768	    slave_adr = 0x0a;
769	    break;
770
771	case XV_CONTRAST:
772	    DEBUG("SetAttribute XV_CONTRAST: %d\n", value);
773	    slave_adr = 0x0b;
774	    break;
775
776	case XV_SATURATION:
777	    DEBUG("SetAttribute XV_SATURATION: %d\n", value);
778	    slave_adr = 0x0c;
779	    break;
780
781	case XV_HUE:
782	    DEBUG("SetAttribute XV_HUE: %d\n", value);
783	    slave_adr = 0x0d;
784	    break;
785
786	default:
787	    return XvBadAlloc;
788	}
789	if (!xf86I2CWriteByte(&(pPort->I2CDev), slave_adr, (value & 0xff)))
790	    return XvBadAlloc;
791    } else {
792	return BadMatch;
793    }
794
795    /* debug: show registers */
796    {
797	I2CByte i2c_bytes[32];
798	int i;
799	xf86I2CReadBytes(&(pPort->I2CDev), 0, i2c_bytes, 32);
800	DEBUG("SAA7111 Registers\n");
801	for (i=0; i<32; i++) {
802	    DEBUG("%02X=%02X ", i, i2c_bytes[i]);
803	    if ((i&7) == 7) DEBUG("\n");
804	}
805    }
806
807    return Success;
808}
809
810
811/******************************************************************************\
812**									      **
813**	V I D E O   M A N A G E M E N T					      **
814**									      **
815\******************************************************************************/
816
817static XF86VideoAdaptorPtr
818SMI_SetupVideo(ScreenPtr pScreen)
819{
820    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
821    SMIPtr pSmi = SMIPTR(pScrn);
822    SMI_PortPtr smiPortPtr;
823    XF86VideoAdaptorPtr ptrAdaptor;
824
825    ENTER();
826
827    ptrAdaptor = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
828		 sizeof(DevUnion) + sizeof(SMI_PortRec));
829    if (ptrAdaptor == NULL)
830	LEAVE(NULL);
831
832    ptrAdaptor->type = XvInputMask
833#if SMI_USE_CAPTURE
834		     | XvOutputMask
835		     | XvVideoMask
836#endif
837		     | XvImageMask
838		     | XvWindowMask
839		     ;
840
841    ptrAdaptor->flags = VIDEO_OVERLAID_IMAGES;
842    if (IS_MSOC(pSmi)) {
843	ptrAdaptor->name = "Silicon Motion MSOC Series Video Engine";
844    }
845    else
846	ptrAdaptor->name = "Silicon Motion Lynx Series Video Engine";
847
848    ptrAdaptor->nPorts = 1;
849    ptrAdaptor->pPortPrivates = (DevUnion*) &ptrAdaptor[1];
850    ptrAdaptor->pPortPrivates[0].ptr = (pointer) &ptrAdaptor->pPortPrivates[1];
851
852    smiPortPtr = (SMI_PortPtr) ptrAdaptor->pPortPrivates[0].ptr;
853
854    SMI_BuildEncodings(smiPortPtr);
855    ptrAdaptor->nEncodings = smiPortPtr->nenc;
856    ptrAdaptor->pEncodings = smiPortPtr->enc;
857#if 0
858    /* aaa whats this? */
859	for (i = 0; i < nElems(SMI_VideoEncodings); i++)
860	{
861		SMI_VideoEncodings[i].width = pSmi->lcdWidth;
862		SMI_VideoEncodings[i].height = pSmi->lcdHeight;
863	}
864#endif
865
866    ptrAdaptor->nFormats = nElems(SMI_VideoFormats);
867    ptrAdaptor->pFormats = SMI_VideoFormats;
868
869    ptrAdaptor->nAttributes = nElems(SMI_VideoAttributes);
870    ptrAdaptor->pAttributes = SMI_VideoAttributes;
871
872    if (IS_MSOC(pSmi)) {
873	ptrAdaptor->nImages = nElems(SMI501_VideoImages);
874	ptrAdaptor->pImages = SMI501_VideoImages;
875    }
876    else {
877	ptrAdaptor->nImages = nElems(SMI_VideoImages);
878	ptrAdaptor->pImages = SMI_VideoImages;
879    }
880
881#if SMI_USE_CAPTURE
882    if (pSmi->Chipset == SMI_COUGAR3DR || IS_MSOC(pSmi))
883	ptrAdaptor->PutVideo = NULL;
884    else
885	ptrAdaptor->PutVideo = SMI_PutVideo;
886    ptrAdaptor->PutStill = NULL;
887    ptrAdaptor->GetVideo = NULL;
888    ptrAdaptor->GetStill = NULL;
889#else
890    ptrAdaptor->PutVideo = NULL;
891    ptrAdaptor->PutStill = NULL;
892    ptrAdaptor->GetVideo = NULL;
893    ptrAdaptor->GetStill = NULL;
894#endif
895    ptrAdaptor->StopVideo = SMI_StopVideo;
896    ptrAdaptor->SetPortAttribute = SMI_SetPortAttribute;
897    ptrAdaptor->GetPortAttribute = SMI_GetPortAttribute;
898    ptrAdaptor->QueryBestSize = SMI_QueryBestSize;
899    ptrAdaptor->PutImage = SMI_PutImage;
900    ptrAdaptor->QueryImageAttributes = SMI_QueryImageAttributes;
901
902    smiPortPtr->Attribute[XV_COLORKEY] = pSmi->videoKey;
903    smiPortPtr->Attribute[XV_INTERLACED] = pSmi->interlaced;
904    smiPortPtr->videoStatus = 0;
905
906#if 0
907    /* aaa does not work ? */
908    if (xf86I2CProbeAddress(pSmi->I2C, SAA7111))
909        LEAVE(NULL);
910    DEBUG("SAA7111 detected\n");
911#endif
912
913    smiPortPtr->I2CDev.DevName = "SAA 7111A";
914    smiPortPtr->I2CDev.SlaveAddr = SAA7111;
915    smiPortPtr->I2CDev.pI2CBus = pSmi->I2C;
916
917
918    if (!IS_MSOC(pSmi) && xf86I2CDevInit(&(smiPortPtr->I2CDev))) {
919
920	if (xf86I2CWriteVec(&(smiPortPtr->I2CDev), SAA7111InitData, ENTRIES(SAA7111InitData) / 2)) {
921	    xvEncoding   = MAKE_ATOM(XV_ENCODING_NAME);
922	    xvHue        = MAKE_ATOM(XV_HUE_NAME);
923	    xvSaturation = MAKE_ATOM(XV_SATURATION_NAME);
924	    xvContrast   = MAKE_ATOM(XV_CONTRAST_NAME);
925
926	    xvInterlaced = MAKE_ATOM(XV_INTERLACED_NAME);
927	    DEBUG("SAA7111 intialized\n");
928
929	} else {
930	    xf86DestroyI2CDevRec(&(smiPortPtr->I2CDev),FALSE);
931	    smiPortPtr->I2CDev.SlaveAddr = 0;
932	}
933    } else
934	smiPortPtr->I2CDev.SlaveAddr = 0;
935
936#if defined(REGION_NULL)
937    REGION_NULL(pScreen, &smiPortPtr->clip);
938#else
939    REGION_INIT(pScreen, &smiPortPtr->clip, NullBox, 0);
940#endif
941
942    pSmi->ptrAdaptor = ptrAdaptor;
943    pSmi->BlockHandler = pScreen->BlockHandler;
944    pScreen->BlockHandler = SMI_BlockHandler;
945
946    xvColorKey   = MAKE_ATOM(XV_COLORKEY_NAME);
947    xvBrightness = MAKE_ATOM(XV_BRIGHTNESS_NAME);
948    xvCapBrightness = MAKE_ATOM(XV_CAPTURE_BRIGHTNESS_NAME);
949
950    SMI_ResetVideo(pScrn);
951
952    LEAVE(ptrAdaptor);
953}
954
955
956static void
957SMI_ResetVideo(ScrnInfoPtr pScrn)
958{
959    SMIPtr pSmi = SMIPTR(pScrn);
960    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
961    int r, g, b;
962
963    ENTER();
964
965    SetAttr(pScrn, XV_ENCODING, 0);     /* Encoding = pal-composite-0 */
966    SetAttr(pScrn, XV_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
967    SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, 128); /* Brightness = 128 (CCIR level) */
968    SetAttr(pScrn, XV_CONTRAST, 71);    /* Contrast = 71 (CCIR level) */
969    SetAttr(pScrn, XV_SATURATION, 64);  /* Color saturation = 64 (CCIR level) */
970    SetAttr(pScrn, XV_HUE, 0);          /* Hue = 0 */
971
972    switch (pScrn->depth) {
973    case 8:
974	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0x00FF);
975	SetKeyReg(pSmi, FPR08, 0);
976	break;
977    case 15:
978    case 16:
979	SetKeyReg(pSmi, FPR04, pPort->Attribute[XV_COLORKEY] & 0xFFFF);
980	SetKeyReg(pSmi, FPR08, 0);
981	break;
982    default:
983        r = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.red) >> pScrn->offset.red;
984        g = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.green) >> pScrn->offset.green;
985        b = (pPort->Attribute[XV_COLORKEY] & pScrn->mask.blue) >> pScrn->offset.blue;
986	SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
987	SetKeyReg(pSmi, FPR08, 0);
988	break;
989    }
990
991    SetKeyReg(pSmi, FPR5C, 0xEDEDED | (pPort->Attribute[XV_BRIGHTNESS] << 24));
992
993    LEAVE();
994}
995
996
997#if SMI_USE_CAPTURE
998static int
999SMI_PutVideo(
1000	ScrnInfoPtr	pScrn,
1001	short		vid_x,
1002	short		vid_y,
1003	short		drw_x,
1004	short		drw_y,
1005	short		vid_w,
1006	short		vid_h,
1007	short		drw_w,
1008	short		drw_h,
1009	RegionPtr	clipBoxes,
1010	pointer		data,
1011	DrawablePtr	pDraw
1012)
1013{
1014    SMI_PortPtr pPort = (SMI_PortPtr) data;
1015    SMIPtr pSmi = SMIPTR(pScrn);
1016    CARD32 vid_pitch, vid_address;
1017    CARD32 vpr00, cpr00;
1018    int xscale, yscale;
1019    BoxRec dstBox;
1020    INT32 x1, y1, x2, y2;
1021    int norm;
1022    int size, width, height, fbPitch;
1023    int top, left;
1024    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1025    xf86CrtcPtr crtc;
1026
1027    ENTER();
1028
1029    DEBUG("Interlaced Video %d\n", pPort->Attribute[XV_INTERLACED]);
1030
1031    if (!pPort->Attribute[XV_INTERLACED]) {
1032	/* no interlace: lines will be doubled */
1033	vid_h /= 2;
1034    }
1035
1036    /* field start aaa*/
1037    norm = pPort->norm[pPort->Attribute[XV_ENCODING]];
1038    vid_x += VideoNorms[norm].HStart;
1039    vid_y += VideoNorms[norm].VStart;
1040    /* only even values allowed (UV-phase) */
1041    vid_x &= ~1;
1042
1043    DEBUG("vid_x=%d vid_y=%d drw_x=%d drw_y=%d  "
1044	  "vid_w=%d vid_h=%d drw_w=%d drw_h=%d\n",
1045	  vid_x, vid_y, drw_x, drw_y, vid_w, vid_h, drw_w, drw_h);
1046
1047    x1 = vid_x;
1048    y1 = vid_y;
1049    x2 = vid_x + vid_w;
1050    y2 = vid_y + vid_h;
1051
1052    width = vid_w;
1053    height = vid_h;
1054
1055    dstBox.x1 = drw_x;
1056    dstBox.y1 = drw_y;
1057    dstBox.x2 = drw_x + drw_w;
1058    dstBox.y2 = drw_y + drw_h;
1059
1060    if(!xf86_crtc_clip_video_helper(pScrn, &crtc, crtcConf->crtc[0], &dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height))
1061	LEAVE(Success);
1062
1063    if(pSmi->Dualhead && crtc == crtcConf->crtc[1])
1064	LEAVE(Success);
1065
1066    /* Transform dstBox to the CRTC coordinates */
1067    dstBox.x1 -= crtc->x;
1068    dstBox.y1 -= crtc->y;
1069    dstBox.x2 -= crtc->x;
1070    dstBox.y2 -= crtc->y;
1071
1072    DEBUG("Clip: x1=%d y1=%d x2=%d y2=%d\n",  x1 >> 16, y1 >> 16, x2 >> 16, y2 >> 16);
1073
1074    vid_pitch = (vid_w * 2 + 7) & ~7;
1075
1076    vpr00 = READ_VPR(pSmi, 0x00) & ~0x0FF000FF;
1077    cpr00 = READ_CPR(pSmi, 0x00) & ~0x000FFF00;
1078
1079    /* vpr00:
1080       Bit 2..0   = 6: Video Window I Format                    = YUV4:2:2
1081       Bit 3      = 1: Video Window I Enable                    = enabled
1082       Bit 4      = 0: Video Window I YUV Averaging             = disabled
1083       Bit 5      = 0: Video Window I Hor. Replication          = disabled
1084       Bit 6      = 0: Video Window I data doubling             = disabled
1085       Bit 14..8  = 0: Video Window II                          = disabled
1086       Bit 18..16 = 0: Graphics Data Format                     = 8-bit index
1087       Bit 19     = 0: Top Video Window Select                  = window I
1088       Bit 20     = 1: Color Key for Window I                   = enabled
1089       Bit 21     = 0: Vertical Interpolation                   = s. below
1090       Bit 22     = 0: Flicker Reduction for TV Modes           = disabled
1091       Bit 23     = 0: Fixed Vertical Interpolation             = disabled
1092       Bit 24     = 1: Select Video Window I Source Addr        =
1093       Bit 25     = 0: Enable V0FIFO to fetch 8-Bit color data  = disabled
1094       Bit 26     = 0:
1095       Bit 27     = 1: Color Key for Window II                  = disabled
1096       Bit 31..28 = reserved
1097    */
1098    if (pPort->Attribute[XV_INTERLACED]) {
1099	/*
1100	  Bit 21     = 0: Vertical Interpolation                   = disabled
1101	  Bit 24     = 0: Select Video Window I Source Addr        = 0
1102	*/
1103	vpr00 |= 0x0010000E;
1104    } else {
1105	/*
1106	  Bit 21     = 1: Vertical Interpolation                   = enabled
1107	  Bit 24     = 1: Select Video Window I Source Addr        = 1
1108	  1= Video window I source addr = capture port buffer ?
1109	*/
1110	vpr00 |= 0x0130000E;
1111    }
1112
1113    /* cpr00:
1114       Bit 0      = 1: Video Capture Enable                     = enabled
1115       Bit 8      = 0: Capture Control                          = continous
1116       Bit 9      = 0: Double Buffer Enable                     = s. below
1117       Bit 10     = 0: Interlace Data Capture                   = s. below
1118       Bit 13..11 = 0: Frame Skip Enable                        = s. below
1119       Bit 15..14 = 0: Video Capture Input Format               = YUV4:2:2
1120       Bit 17..16 = 0: Enable Hor. Reduction                    = s. below
1121       Bit 19..18 = 0: Enable Vert. Reduction                   = s. below
1122       Bit 21..20 = 0: Enable Hor. Filtering                    = s. below
1123       Bit 22     = 0: HREF Polarity                            = high active
1124       Bit 23     = 0: VREF Polarity                            = high active
1125       Bit 24     = 1: Field Detection Method VSYNC edge        = rising
1126    */
1127    if (pPort->Attribute[XV_INTERLACED]) {
1128	/*
1129	  Bit 9      = 1: Double Buffer Enable                  = enabled
1130	  Bit 10     = 1: Interlace Data Capture                = enabled
1131	  Bit 13..11 = 0: Frame Skip Enable                     = no skip
1132	*/
1133	cpr00 |= 0x01000601;
1134    } else {
1135	/*
1136	  Bit 9      = 0: Double Buffer Enable                  = disabled
1137	  Bit 10     = 0: Interlace Data Capture                = disabled
1138	  Bit 13..11 = 010: Frame Skip Enable                   = skip every other frame
1139	*/
1140	cpr00 |= 0x01001001;
1141    }
1142
1143    if (pSmi->ByteSwap)
1144	cpr00 |= 0x00004000;
1145
1146    fbPitch = (pScrn->displayWidth * pSmi->Bpp + 15) & ~15;
1147
1148    if (vid_w <= drw_w) {
1149	xscale = (256 * vid_w / drw_w) & 0xFF;
1150    } else if (vid_w / 2 <= drw_w) {
1151	xscale = (128 * vid_w / drw_w) & 0xFF;
1152	width /= 2;
1153	vid_pitch /= 2;
1154	cpr00 |= 0x00010000;
1155    } else if (vid_w / 4 <= drw_w) {
1156	xscale = (64 * vid_w / drw_w) & 0xFF;
1157	width /= 4;
1158	vid_pitch /= 4;
1159	cpr00 |= 0x00020000;
1160    } else {
1161	xscale = 0;
1162	width /= 4;
1163	vid_pitch /= 4;
1164	cpr00 |= 0x00020000;
1165    }
1166
1167    if (vid_h <= drw_h) {
1168	yscale = (256 * vid_h / drw_h) & 0xFF;
1169    } else if (vid_h / 2 <= drw_h) {
1170	yscale = (128 * vid_h / drw_h) & 0xFF;
1171	height /= 2;
1172	cpr00 |= 0x00040000;
1173    } else if (vid_h / 4 <= drw_h) {
1174	yscale = (64 * vid_h / drw_h) & 0xFF;
1175	height /= 4;
1176	cpr00 |= 0x00080000;
1177    } else {
1178	yscale = 0;
1179	height /= 4;
1180	cpr00 |= 0x00080000;
1181    }
1182
1183    do {
1184	size = vid_pitch * height;
1185	DEBUG("SMI_AllocateMemory: vid_pitch=%d height=%d size=%d\n",
1186	      vid_pitch, height, size);
1187	pPort->video_offset = SMI_AllocateMemory(pScrn, &pPort->video_memory, size);
1188        if (pPort->video_offset == 0) {
1189	    if ((cpr00 & 0x000C0000) == 0) {
1190		/* height -> 1/2 height */
1191		yscale = (128 * vid_h / drw_h) & 0xFF;
1192		height = vid_h / 2;
1193		cpr00 |= 0x00040000;
1194	    } else if (cpr00 & 0x00040000) {
1195		/* 1/2 height -> 1/4 height */
1196		yscale = (64 * vid_h / drw_h) & 0xFF;
1197		height = vid_h / 4;
1198		cpr00 ^= 0x000C0000;
1199	    } else {
1200		/* 1/4 height */
1201		if ((cpr00 & 0x00030000) == 0) {
1202		    /* width -> 1/2 width */
1203		    xscale = (128 * vid_w / drw_w) & 0xFF;
1204		    width = vid_w / 2;
1205		    cpr00 |= 0x00010000;
1206		} else if (cpr00 & 0x00010000) {
1207		    /* 1/2 width -> 1/4 width */
1208		    xscale = (64 * vid_w / drw_w) & 0xFF;
1209		    width = vid_w / 4;
1210		    cpr00 ^= 0x00030000;
1211		} else {
1212		    DEBUG("allocate error\n");
1213		    LEAVE(BadAlloc);
1214		}
1215	    }
1216	}
1217    } while (pPort->video_offset == 0);
1218
1219    DEBUG("xscale==%d yscale=%d width=%d height=%d\n",
1220	  xscale, yscale, width, height);
1221
1222    /* aaa whats this                     ----------------------v ?
1223    vid_address = (pPort->area->box.y1 * fbPitch) + ((y1 >> 16) * vid_pitch);*/
1224    vid_address = pPort->video_offset;
1225
1226    DEBUG("test RegionsEqual\n");
1227    if (!REGION_EQUAL(pScrn->pScreen, &pPort->clip, clipBoxes))
1228    {
1229	DEBUG((VERBLEV, "RegionCopy\n"));
1230        REGION_COPY(pScrn->pScreen, &pPort->clip, clipBoxes);
1231	DEBUG("FillKey\n");
1232	xf86XVFillKeyHelper(pScrn->pScreen, pPort->Attribute[XV_COLORKEY], clipBoxes);
1233
1234    }
1235
1236    left = x1 >> 16;
1237    top = y1 >> 16;
1238    width = (x2 - x1) >> 16;
1239    height = (y2 - y1) >> 16;
1240
1241    if (!IS_MSOC(pSmi))
1242	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1243		      0x21,
1244		      VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1245				   0x21) & ~0x04);
1246    WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) | 0x00200000);
1247    /* Video Window I Left and Top Boundaries */
1248    WRITE_VPR(pSmi, 0x14, dstBox.x1 + (dstBox.y1 << 16));
1249    /* Video Window I Right and Bottom Boundaries */
1250    WRITE_VPR(pSmi, 0x18, dstBox.x2 + (dstBox.y2 << 16));
1251    /* Video Window I Source Width and Offset */
1252    WRITE_VPR(pSmi, 0x20, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1253    /* Video Window I Stretch Factor */
1254    WRITE_VPR(pSmi, 0x24, (xscale << 8) + yscale);
1255
1256    if (pPort->Attribute[XV_INTERLACED]) {
1257	/* Video Window II Left and Top Boundaries */
1258	WRITE_VPR(pSmi, 0x28, dstBox.x1 + (dstBox.y1 << 16));
1259	/* Video Window II Right and Bottom Boundaries */
1260	WRITE_VPR(pSmi, 0x2C, dstBox.x2 + (dstBox.y2 << 16));
1261	/* Video Window II Source Width and Offset */
1262	WRITE_VPR(pSmi, 0x34, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1263	/* Video Window II Stretch Factor */
1264	WRITE_VPR(pSmi, 0x38, (xscale << 8) + yscale);
1265
1266	/* Video Window I Source Start Address */
1267	WRITE_VPR(pSmi, 0x1C, vid_address / 8);
1268	/* Video Window II Source Start Address */
1269	WRITE_VPR(pSmi, 0x30, vid_address / 8);
1270
1271	/* Video Window I Source Start Address */
1272	WRITE_VPR(pSmi, 0x48, vid_address / 8);
1273	/* Video Window II Source Start Address */
1274	WRITE_VPR(pSmi, 0x4C, vid_address / 8 + vid_pitch / 8);
1275
1276	/* Video Source Clipping Control */
1277	WRITE_CPR(pSmi, 0x04, left + ((top/2) << 16));
1278	/* Video Source Capture Size Control */
1279	WRITE_CPR(pSmi, 0x08, width + ((height/2) << 16));
1280	/* Capture Port Buffer I Source Start Address */
1281	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
1282	/* Capture Port Buffer II Source Start Address */
1283	WRITE_CPR(pSmi, 0x10, vid_address / 8 + vid_pitch / 8);
1284	/* Capture Port Source Offset Address */
1285	WRITE_CPR(pSmi, 0x14, 2*(vid_pitch / 8) + ((2*(vid_pitch / 8)) << 16));
1286    } else {
1287	/* Video Source Clipping Control */
1288	WRITE_CPR(pSmi, 0x04, left + (top << 16));
1289	/* Video Source Capture Size Control */
1290	WRITE_CPR(pSmi, 0x08, width + (height << 16));
1291	/* Capture Port Buffer I Source Start Address */
1292	WRITE_CPR(pSmi, 0x0C, vid_address / 8);
1293	/* Capture Port Buffer II Source Start Address */
1294	WRITE_CPR(pSmi, 0x10, vid_address / 8);
1295	/* Capture Port Source Offset Address */
1296	WRITE_CPR(pSmi, 0x14, (vid_pitch / 8) + ((vid_pitch / 8) << 16));
1297    }
1298
1299    WRITE_CPR(pSmi, 0x00, cpr00);
1300    WRITE_VPR(pSmi, 0x00, vpr00);
1301
1302    pPort->videoStatus = CLIENT_VIDEO_ON;
1303    DEBUG("SMI_PutVideo success\n");
1304
1305    LEAVE(Success);
1306}
1307#endif
1308
1309
1310static void
1311SMI_StopVideo(
1312	ScrnInfoPtr	pScrn,
1313	pointer		data,
1314	Bool		shutdown
1315)
1316{
1317    SMI_PortPtr pPort = (SMI_PortPtr) data;
1318    SMIPtr pSmi = SMIPTR(pScrn);
1319
1320    ENTER();
1321
1322    REGION_EMPTY(pScrn->pScreen, &pPort->clip);
1323
1324    if (shutdown) {
1325	if (pPort->videoStatus & CLIENT_VIDEO_ON) {
1326	    if (pSmi->Chipset == SMI_COUGAR3DR)
1327		WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
1328	    else if (IS_MSOC(pSmi))
1329		WRITE_DCR(pSmi, 0x0040, READ_DCR(pSmi, 0x0040) & ~0x00000004);
1330	    else
1331		WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x01000008);
1332#if SMI_USE_CAPTURE
1333	    if (!IS_MSOC(pSmi) && pSmi->Chipset != SMI_COUGAR3DR) {
1334		WRITE_CPR(pSmi, 0x00, READ_CPR(pSmi, 0x00) & ~0x00000001);
1335		WRITE_VPR(pSmi, 0x54, READ_VPR(pSmi, 0x54) & ~0x00F00000);
1336	    }
1337#endif
1338	}
1339        if (pPort->video_memory != NULL) {
1340            SMI_FreeMemory(pScrn, pPort->video_memory);
1341            pPort->video_memory = NULL;
1342	}
1343        pPort->videoStatus = 0;
1344        /* pPort->i2cDevice = 0;aaa*/
1345    } else {
1346        if (pPort->videoStatus & CLIENT_VIDEO_ON) {
1347            pPort->videoStatus |= OFF_TIMER;
1348            pPort->offTime = currentTime.milliseconds + OFF_DELAY;
1349	}
1350    }
1351
1352    LEAVE();
1353}
1354
1355static int
1356SMI_SetPortAttribute(
1357	ScrnInfoPtr	pScrn,
1358	Atom		attribute,
1359	INT32		value,
1360	pointer		data
1361)
1362{
1363    int res;
1364    SMI_PortPtr pPort = (SMI_PortPtr) data;
1365    SMIPtr pSmi = SMIPTR(pScrn);
1366
1367    ENTER();
1368
1369    if (attribute == xvColorKey) {
1370	int r, g, b;
1371
1372        pPort->Attribute[XV_COLORKEY] = value;
1373	switch (pScrn->depth) {
1374	case 8:
1375	    SetKeyReg(pSmi, FPR04, value & 0x00FF);
1376	    break;
1377	case 15:
1378	case 16:
1379	    SetKeyReg(pSmi, FPR04, value & 0xFFFF);
1380	    break;
1381	default:
1382	    r = (value & pScrn->mask.red) >> pScrn->offset.red;
1383	    g = (value & pScrn->mask.green) >> pScrn->offset.green;
1384	    b = (value & pScrn->mask.blue) >> pScrn->offset.blue;
1385	    SetKeyReg(pSmi, FPR04, ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
1386	    break;
1387	}
1388	res = Success;
1389    } else if (attribute == xvInterlaced) {
1390        pPort->Attribute[XV_INTERLACED] = (value != 0);
1391	res = Success;
1392    } else if (attribute == xvEncoding) {
1393        res = SetAttr(pScrn, XV_ENCODING, value);
1394    } else if (attribute == xvBrightness) {
1395        res = SetAttr(pScrn, XV_BRIGHTNESS, value);
1396    } else if (attribute == xvCapBrightness) {
1397        res = SetAttr(pScrn, XV_CAPTURE_BRIGHTNESS, value);
1398    } else if (attribute == xvContrast) {
1399        res = SetAttr(pScrn, XV_CONTRAST, value);
1400    } else if (attribute == xvSaturation) {
1401        res = SetAttr(pScrn, XV_SATURATION, value);
1402    } else if (attribute == xvHue) {
1403        res = SetAttr(pScrn, XV_HUE, value);
1404    } else {
1405        res = BadMatch;
1406    }
1407
1408    LEAVE(res);
1409}
1410
1411
1412static int
1413SMI_GetPortAttribute(
1414	ScrnInfoPtr	pScrn,
1415	Atom		attribute,
1416	INT32		*value,
1417	pointer		data
1418)
1419{
1420    SMI_PortPtr pPort = (SMI_PortPtr) data;
1421
1422    ENTER();
1423    if (attribute == xvEncoding)
1424        *value = pPort->Attribute[XV_ENCODING];
1425    else if (attribute == xvBrightness)
1426        *value = pPort->Attribute[XV_BRIGHTNESS];
1427    else if (attribute == xvCapBrightness)
1428        *value = pPort->Attribute[XV_CAPTURE_BRIGHTNESS];
1429    else if (attribute == xvContrast)
1430        *value = pPort->Attribute[XV_CONTRAST];
1431    else if (attribute == xvSaturation)
1432        *value = pPort->Attribute[XV_SATURATION];
1433    else if (attribute == xvHue)
1434        *value = pPort->Attribute[XV_HUE];
1435    else if (attribute == xvColorKey)
1436        *value = pPort->Attribute[XV_COLORKEY];
1437    else
1438	LEAVE(BadMatch);
1439
1440    LEAVE(Success);
1441}
1442
1443
1444static void
1445SMI_QueryBestSize(
1446	ScrnInfoPtr		pScrn,
1447	Bool			motion,
1448	short			vid_w,
1449	short			vid_h,
1450	short			drw_w,
1451	short			drw_h,
1452	unsigned int	*p_w,
1453	unsigned int	*p_h,
1454	pointer			data
1455)
1456{
1457    SMIPtr pSmi = SMIPTR(pScrn);
1458
1459    ENTER();
1460
1461    *p_w = min(drw_w, pSmi->lcdWidth);
1462    *p_h = min(drw_h, pSmi->lcdHeight);
1463
1464    LEAVE();
1465}
1466
1467
1468static int
1469SMI_PutImage(
1470	ScrnInfoPtr		pScrn,
1471	short			src_x,
1472	short			src_y,
1473	short			drw_x,
1474	short			drw_y,
1475	short			src_w,
1476	short			src_h,
1477	short			drw_w,
1478	short			drw_h,
1479	int			id,
1480	unsigned char		*buf,
1481	short			width,
1482	short			height,
1483	Bool			sync,
1484	RegionPtr		clipBoxes,
1485	pointer			data,
1486	DrawablePtr		pDraw
1487)
1488{
1489    SMIPtr pSmi = SMIPTR(pScrn);
1490    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
1491    INT32 x1, y1, x2, y2;
1492    int bpp = 0;
1493    int srcPitch, srcPitch2 = 0, dstPitch, size;
1494    BoxRec dstBox;
1495    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
1496    int left, top, nPixels, nLines;
1497    unsigned char *dstStart;
1498    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1499    xf86CrtcPtr crtc;
1500
1501    ENTER();
1502
1503    x1 = src_x;
1504    y1 = src_y;
1505    x2 = src_x + src_w;
1506    y2 = src_y + src_h;
1507
1508    dstBox.x1 = drw_x;
1509    dstBox.y1 = drw_y;
1510    dstBox.x2 = drw_x + drw_w;
1511    dstBox.y2 = drw_y + drw_h;
1512
1513    if (pSmi->CSCVideo) {
1514	if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
1515				   width, height))
1516	    LEAVE(Success);
1517    }
1518    else {
1519	if (!xf86_crtc_clip_video_helper(pScrn, &crtc, crtcConf->crtc[0], &dstBox,
1520					 &x1, &x2, &y1, &y2, clipBoxes,
1521					 width, height))
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(
2063	int	i,
2064	pointer	blockData,
2065	pointer	pTimeout,
2066	pointer	pReadMask
2067)
2068{
2069    ScreenPtr	pScreen = screenInfo.screens[i];
2070    ScrnInfoPtr	pScrn	= xf86Screens[i];
2071    SMIPtr	pSmi    = SMIPTR(pScrn);
2072    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2073
2074    pScreen->BlockHandler = pSmi->BlockHandler;
2075    (*pScreen->BlockHandler)(i, blockData, pTimeout, pReadMask);
2076    pScreen->BlockHandler = SMI_BlockHandler;
2077
2078    if (pPort->videoStatus & TIMER_MASK) {
2079	UpdateCurrentTime();
2080        if (pPort->videoStatus & OFF_TIMER) {
2081            if (pPort->offTime < currentTime.milliseconds) {
2082		if (pSmi->Chipset == SMI_COUGAR3DR) {
2083		    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
2084		}
2085		else if (IS_MSOC(pSmi))
2086		    WRITE_DCR(pSmi, 0x0040, READ_DCR(pSmi, 0x0040) & ~0x00000004);
2087		else
2088		    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
2089                pPort->videoStatus = FREE_TIMER;
2090                pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
2091	    }
2092	} else {
2093            if (pPort->freeTime < currentTime.milliseconds) {
2094		SMI_FreeMemory(pScrn, pPort->video_memory);
2095                pPort->video_memory = NULL;
2096	    }
2097            pPort->videoStatus = 0;
2098	}
2099    }
2100}
2101
2102#if 0
2103static int
2104SMI_SendI2C(
2105	ScrnInfoPtr		pScrn,
2106	CARD8			device,
2107	char			*devName,
2108	SMI_I2CDataPtr	i2cData
2109)
2110{
2111    SMIPtr	pSmi = SMIPTR(pScrn);
2112    I2CDevPtr	dev;
2113    int		status = Success;
2114
2115    ENTER();
2116
2117    if (pSmi->I2C == NULL)
2118	LEAVE(BadAlloc);
2119
2120    dev = xf86CreateI2CDevRec();
2121    if (dev == NULL)
2122	LEAVE(BadAlloc);
2123
2124    dev->DevName = devName;
2125    dev->SlaveAddr = device;
2126    dev->pI2CBus = pSmi->I2C;
2127
2128    if (!xf86I2CDevInit(dev))
2129	status = BadAlloc;
2130    else {
2131	while (i2cData->address != 0xFF || i2cData->data != 0xFF) {	/* PDR#676 */
2132	    if (!xf86I2CWriteByte(dev, i2cData->address, i2cData->data)) {
2133		status = BadAlloc;
2134		break;
2135	    }
2136	    i2cData++;
2137	}
2138    }
2139
2140    xf86DestroyI2CDevRec(dev, TRUE);
2141
2142    LEAVE(status);
2143}
2144#endif
2145
2146/******************************************************************************\
2147**									      **
2148**	 O F F S C R E E N   M E M O R Y   M A N A G E R		      **
2149**									      **
2150\******************************************************************************/
2151
2152static void
2153SMI_InitOffscreenImages(
2154	ScreenPtr	pScreen
2155)
2156{
2157    XF86OffscreenImagePtr offscreenImages;
2158    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2159    SMIPtr pSmi = SMIPTR(pScrn);
2160    SMI_PortPtr pPort = (SMI_PortPtr) pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2161
2162    ENTER();
2163
2164    offscreenImages = xalloc(sizeof(XF86OffscreenImageRec));
2165    if (offscreenImages == NULL) {
2166	LEAVE();
2167    }
2168
2169    offscreenImages->image = SMI_VideoImages;
2170    offscreenImages->flags = VIDEO_OVERLAID_IMAGES;
2171    if (IS_MSOC(pSmi))
2172	offscreenImages->flags |= VIDEO_CLIP_TO_VIEWPORT;
2173    offscreenImages->alloc_surface = SMI_AllocSurface;
2174    offscreenImages->free_surface = SMI_FreeSurface;
2175    offscreenImages->display = SMI_DisplaySurface;
2176    offscreenImages->stop = SMI_StopSurface;
2177    offscreenImages->getAttribute = SMI_GetSurfaceAttribute;
2178    offscreenImages->setAttribute = SMI_SetSurfaceAttribute;
2179    offscreenImages->max_width = pSmi->lcdWidth;
2180    offscreenImages->max_height = pSmi->lcdHeight;
2181    if (!pPort->I2CDev.SlaveAddr) {
2182	offscreenImages->num_attributes = nElems(SMI_VideoAttributes);
2183	offscreenImages->attributes = SMI_VideoAttributes;
2184    } else {
2185	offscreenImages->num_attributes = nElems(SMI_VideoAttributesSAA711x);
2186	offscreenImages->attributes = SMI_VideoAttributesSAA711x;
2187    }
2188    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
2189
2190    LEAVE();
2191}
2192
2193static void
2194SMI_VideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
2195{
2196    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2197    SMIPtr pSmi = SMIPTR(pScrn);
2198    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2199
2200    ENTER();
2201
2202    if (pPort->video_memory == area)
2203	pPort->video_memory = NULL;
2204
2205    LEAVE();
2206}
2207
2208CARD32
2209SMI_AllocateMemory(ScrnInfoPtr pScrn, void **mem_struct, int size)
2210{
2211    ScreenPtr	pScreen = screenInfo.screens[pScrn->scrnIndex];
2212    SMIPtr	pSmi = SMIPTR(pScrn);
2213    int		offset = 0;
2214
2215    ENTER();
2216
2217    if (pSmi->useEXA) {
2218	ExaOffscreenArea *area = *mem_struct;
2219
2220	if (area != NULL) {
2221	    if (area->size >= size)
2222		LEAVE(area->offset);
2223
2224	    exaOffscreenFree(pScrn->pScreen, area);
2225	}
2226
2227	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE,
2228				 SMI_VideoSave, NULL);
2229
2230	*mem_struct = area;
2231	if (area != NULL)
2232	    offset = area->offset;
2233    }
2234    else {
2235	FBLinearPtr	linear = *mem_struct;
2236
2237	/*  XAA allocates in units of pixels at the screen bpp,
2238	 *  so adjust size appropriately.
2239	 */
2240	size = (size + pSmi->Bpp - 1) / pSmi->Bpp;
2241
2242	if (linear) {
2243	    if (linear->size >= size)
2244		LEAVE(linear->offset * pSmi->Bpp);
2245
2246	    if (xf86ResizeOffscreenLinear(linear, size))
2247		LEAVE(linear->offset * pSmi->Bpp);
2248
2249	    xf86FreeOffscreenLinear(linear);
2250	}
2251	else {
2252	    int max_size;
2253
2254	    xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
2255					    PRIORITY_EXTREME);
2256	    if (max_size < size)
2257		LEAVE(0);
2258
2259	    xf86PurgeUnlockedOffscreenAreas(pScreen);
2260	}
2261
2262	linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
2263					     NULL, NULL, NULL);
2264	if ((*mem_struct = linear) != NULL)
2265	    offset = linear->offset * pSmi->Bpp;
2266
2267	DEBUG("offset = %p\n", offset);
2268    }
2269
2270    LEAVE(offset);
2271}
2272
2273void
2274SMI_FreeMemory(
2275	ScrnInfoPtr pScrn,
2276	void *mem_struct
2277)
2278{
2279    SMIPtr pSmi = SMIPTR(pScrn);
2280
2281    ENTER();
2282
2283    if (pSmi->useEXA) {
2284	ExaOffscreenArea *area = mem_struct;
2285
2286	if (area != NULL)
2287	    exaOffscreenFree(pScrn->pScreen, area);
2288    } else {
2289	FBLinearPtr linear = mem_struct;
2290
2291	if (linear != NULL)
2292	    xf86FreeOffscreenLinear(linear);
2293    }
2294
2295    LEAVE();
2296}
2297
2298static void
2299CopyYV12ToVideoMem(unsigned char *src1, unsigned char *src2,
2300		   unsigned char *src3, unsigned char *dst,
2301		   int src1Pitch, int src23Pitch, int dstPitch,
2302		   int height, int width)
2303{
2304    int		j = height;
2305
2306    ENTER();
2307
2308    /* copy 1 data */
2309    while (j -- > 0) {
2310	memcpy(dst, src1, width);
2311	src1 += src1Pitch;
2312	dst += dstPitch;
2313    }
2314    /* copy 2 data */
2315    j = height / 2;
2316    while (j -- > 0) {
2317	memcpy(dst, src2, width / 2);
2318	src2 += src23Pitch;
2319	dst += dstPitch / 2;
2320    }
2321    /* copy 3 data */
2322    j = height / 2;
2323    while (j -- > 0) {
2324	memcpy(dst, src3, width / 2);
2325	src3 += src23Pitch;
2326	dst += dstPitch / 2;
2327    }
2328
2329    LEAVE();
2330}
2331
2332static int
2333SMI_AllocSurface(
2334	ScrnInfoPtr	pScrn,
2335	int		id,
2336	unsigned short	width,
2337	unsigned short	height,
2338	XF86SurfacePtr	surface
2339)
2340{
2341    SMIPtr pSmi = SMIPTR(pScrn);
2342    int pitch, bpp, offset, size;
2343    void *surface_memory = NULL;
2344    SMI_OffscreenPtr ptrOffscreen;
2345
2346    ENTER();
2347
2348    if (width > pSmi->lcdWidth || height > pSmi->lcdHeight)
2349	LEAVE(BadAlloc);
2350
2351    switch (id) {
2352    case FOURCC_YV12:
2353    case FOURCC_I420:
2354    case FOURCC_YUY2:
2355    case FOURCC_RV15:
2356    case FOURCC_RV16:
2357	bpp = 2;
2358	break;
2359    case FOURCC_RV24:
2360	bpp = 3;
2361	break;
2362    case FOURCC_RV32:
2363	bpp = 4;
2364	break;
2365    default:
2366	LEAVE(BadAlloc);
2367    }
2368
2369    width = (width + 1) & ~1;
2370    pitch = (width * bpp + 15) & ~15;
2371    size  = pitch * height;
2372
2373    offset = SMI_AllocateMemory(pScrn, &surface_memory, size);
2374    if (offset == 0)
2375	LEAVE(BadAlloc);
2376
2377    surface->pitches = xalloc(sizeof(int));
2378    if (surface->pitches == NULL) {
2379	SMI_FreeMemory(pScrn, surface_memory);
2380	LEAVE(BadAlloc);
2381    }
2382    surface->offsets = xalloc(sizeof(int));
2383    if (surface->offsets == NULL) {
2384	xfree(surface->pitches);
2385	SMI_FreeMemory(pScrn, surface_memory);
2386	LEAVE(BadAlloc);
2387    }
2388
2389    ptrOffscreen = xalloc(sizeof(SMI_OffscreenRec));
2390    if (ptrOffscreen == NULL) {
2391	xfree(surface->offsets);
2392	xfree(surface->pitches);
2393	SMI_FreeMemory(pScrn, surface_memory);
2394	LEAVE(BadAlloc);
2395    }
2396
2397    surface->pScrn = pScrn;
2398    surface->id = id;
2399    surface->width = width;
2400    surface->height = height;
2401    surface->pitches[0] = pitch;
2402    surface->offsets[0] = offset;
2403    surface->devPrivate.ptr = (pointer) ptrOffscreen;
2404
2405    ptrOffscreen->surface_memory = surface_memory;
2406    ptrOffscreen->isOn = FALSE;
2407
2408    LEAVE(Success);
2409}
2410
2411static int
2412SMI_FreeSurface(
2413	XF86SurfacePtr	surface
2414)
2415{
2416    ScrnInfoPtr pScrn = surface->pScrn;
2417    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2418
2419    ENTER();
2420
2421    if (ptrOffscreen->isOn) {
2422	SMI_StopSurface(surface);
2423    }
2424
2425    SMI_FreeMemory(pScrn, ptrOffscreen->surface_memory);
2426    xfree(surface->pitches);
2427    xfree(surface->offsets);
2428    xfree(surface->devPrivate.ptr);
2429
2430    LEAVE(Success);
2431}
2432
2433static int
2434SMI_DisplaySurface(
2435	XF86SurfacePtr	surface,
2436	short		vid_x,
2437	short		vid_y,
2438	short		drw_x,
2439	short		drw_y,
2440	short		vid_w,
2441	short		vid_h,
2442	short		drw_w,
2443	short		drw_h,
2444	RegionPtr	clipBoxes
2445)
2446{
2447    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2448    SMIPtr pSmi = SMIPTR(surface->pScrn);
2449    SMI_PortPtr pPort = pSmi->ptrAdaptor->pPortPrivates[0].ptr;
2450    INT32 x1, y1, x2, y2;
2451    BoxRec dstBox;
2452    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(surface->pScrn);
2453    xf86CrtcPtr crtc;
2454
2455    ENTER();
2456
2457    x1 = vid_x;
2458    x2 = vid_x + vid_w;
2459    y1 = vid_y;
2460    y2 = vid_y + vid_h;
2461
2462    dstBox.x1 = drw_x;
2463    dstBox.x2 = drw_x + drw_w;
2464    dstBox.y1 = drw_y;
2465    dstBox.y2 = drw_y + drw_h;
2466
2467    if(!xf86_crtc_clip_video_helper(surface->pScrn, &crtc, crtcConf->crtc[0], &dstBox,
2468				    &x1, &x2, &y1, &y2, clipBoxes, surface->width, surface->height))
2469	LEAVE(Success);
2470
2471    /* Transform dstBox to the CRTC coordinates */
2472    dstBox.x1 -= crtc->x;
2473    dstBox.y1 -= crtc->y;
2474    dstBox.x2 -= crtc->x;
2475    dstBox.y2 -= crtc->y;
2476
2477    xf86XVFillKeyHelper(surface->pScrn->pScreen,
2478			pPort->Attribute[XV_COLORKEY], clipBoxes);
2479    SMI_ResetVideo(surface->pScrn);
2480
2481    if (pSmi->Chipset == SMI_COUGAR3DR)
2482	SMI_DisplayVideo0730(surface->pScrn, surface->id, surface->offsets[0],
2483			     surface->width, surface->height, surface->pitches[0], x1, y1, x2,
2484			     y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2485    else if (IS_MSOC(pSmi))
2486	SMI_DisplayVideo0501(surface->pScrn, surface->id,
2487			     surface->offsets[0], surface->width,
2488			     surface->height, surface->pitches[0], x1, y1,
2489			     x2, y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2490    else{
2491	if(crtc == crtcConf->crtc[0])
2492	    SMI_DisplayVideo(surface->pScrn, surface->id, surface->offsets[0],
2493			     surface->width, surface->height, surface->pitches[0], x1, y1, x2,
2494			     y2, &dstBox, vid_w, vid_h, drw_w, drw_h);
2495    }
2496
2497    ptrOffscreen->isOn = TRUE;
2498    if (pPort->videoStatus & CLIENT_VIDEO_ON) {
2499        REGION_EMPTY(surface->pScrn->pScreen, &pPort->clip);
2500	UpdateCurrentTime();
2501        pPort->videoStatus = FREE_TIMER;
2502        pPort->freeTime = currentTime.milliseconds + FREE_DELAY;
2503    }
2504
2505    LEAVE(Success);
2506}
2507
2508static int
2509SMI_StopSurface(
2510	XF86SurfacePtr	surface
2511)
2512{
2513    SMI_OffscreenPtr ptrOffscreen = (SMI_OffscreenPtr) surface->devPrivate.ptr;
2514
2515    ENTER();
2516
2517    if (ptrOffscreen->isOn) {
2518	SMIPtr pSmi = SMIPTR(surface->pScrn);
2519	if (pSmi->Chipset == SMI_COUGAR3DR) {
2520	    WRITE_FPR(pSmi, FPR00, READ_FPR(pSmi, 0x00) & ~(FPR00_VWIENABLE));
2521	} else {
2522	    WRITE_VPR(pSmi, 0x00, READ_VPR(pSmi, 0x00) & ~0x00000008);
2523	}
2524
2525	ptrOffscreen->isOn = FALSE;
2526    }
2527
2528    LEAVE(Success);
2529}
2530
2531static int
2532SMI_GetSurfaceAttribute(
2533	ScrnInfoPtr	pScrn,
2534	Atom		attr,
2535	INT32		*value
2536)
2537{
2538    SMIPtr pSmi = SMIPTR(pScrn);
2539
2540    return SMI_GetPortAttribute(pScrn, attr, value,
2541			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
2542}
2543
2544static int
2545SMI_SetSurfaceAttribute(
2546	ScrnInfoPtr	pScrn,
2547	Atom		attr,
2548	INT32		value
2549)
2550{
2551    SMIPtr pSmi = SMIPTR(pScrn);
2552
2553    return SMI_SetPortAttribute(pScrn, attr, value,
2554			(pointer) pSmi->ptrAdaptor->pPortPrivates[0].ptr);
2555}
2556
2557static void
2558SetKeyReg(SMIPtr pSmi, int reg, int value)
2559{
2560    if (pSmi->Chipset == SMI_COUGAR3DR)
2561	WRITE_FPR(pSmi, reg, value);
2562    else if (IS_MSOC(pSmi)) {
2563	/* We don't change the color mask, and we don't do brightness.  IF
2564	 * they write to the colorkey register, we'll write the value to the
2565	 * 501 colorkey register */
2566	if (FPR04 == reg)		   /* Only act on colorkey value writes */
2567	    WRITE_DCR(pSmi, 0x0008, value);/* ColorKey register is DCR08 */
2568    }
2569    else
2570	WRITE_VPR(pSmi, reg, value);
2571}
2572
2573#else /* SMI_USE_VIDEO */
2574void SMI_InitVideo(ScreenPtr pScreen) {}
2575#endif
2576