pm2_video.c revision 4f6cd06f
1/*
2 *  Permedia 2 Xv Driver
3 *
4 *  Copyright (C) 1998-2000 Michael H. Schimek <m.schimek@netway.at>
5 *
6 *  Permission is hereby granted, free of charge, to any person obtaining a copy
7 *  of this software and associated documentation files (the "Software"), to deal
8 *  in the Software without restriction, including without limitation the rights
9 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 *  copies of the Software, and to permit persons to whom the Software is
11 *  furnished to do so, subject to the following conditions:
12 *
13 *  The above copyright notice and this permission notice shall be included in
14 *  all copies or substantial portions of the Software.
15 *
16 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 */
23
24/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/glint/pm2_video.c,v 1.25tsi Exp $ */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "xf86.h"
31#include "xf86_OSproc.h"
32#include "xf86Pci.h"
33#include "xf86PciInfo.h"
34#include "xf86fbman.h"
35#include "xf86i2c.h"
36#include "xf86xv.h"
37#include <X11/extensions/Xv.h>
38
39#include "glint_regs.h"
40#include "glint.h"
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <fcntl.h>
44#include <sys/ioctl.h>
45#include <unistd.h>
46
47#undef MIN
48#undef ABS
49#undef CLAMP
50#undef ENTRIES
51
52#define MIN(a, b) (((a) < (b)) ? (a) : (b))
53#define ABS(n) (((n) < 0) ? -(n) : (n))
54#define CLAMP(v, min, max) (((v) < (min)) ? (min) : MIN(v, max))
55#define ENTRIES(array) (sizeof(array) / sizeof((array)[0]))
56
57#define ADAPTORS 3
58#define PORTS 6
59
60#define PCI_SUBSYSTEM_ID_WINNER_2000_P2C	0x0a311048
61#define PCI_SUBSYSTEM_ID_GLORIA_SYNERGY_P2C	0x0a321048
62#define PCI_SUBSYSTEM_ID_GLORIA_SYNERGY_P2A	0x0a351048
63#define PCI_SUBSYSTEM_ID_WINNER_2000_P2A	0x0a441048
64
65/*
66 *  Proprietary kernel backbone interface
67 */
68
69#define XVIPC_MAGIC		0x6A5D70E6
70#define XVIPC_VERSION		1
71#define VIDIOC_PM2_XVIPC	0x00007F7F
72
73typedef enum {
74    OP_ATTR = 0,
75    OP_RESET = 8,	/* unused */
76    OP_START,
77    OP_STOP,
78    OP_PLUG,
79    OP_VIDEOSTD,
80    OP_WINDOW,		/* unused */
81    OP_CONNECT,
82    OP_EVENT,
83    OP_ALLOC,
84    OP_FREE,
85    OP_UPDATE,
86    OP_NOP,		/* ignored */
87    OP_ENTER,
88    OP_LEAVE,
89    OP_DISCONNECT
90} xvipc_op;
91
92typedef struct _pm2_xvipc {
93    int			magic;
94    void 		*pm2p, *pAPriv;
95    int			port, op, time, block;
96    int			a, b, c, d, e, f;
97} pm2_xvipc;
98
99static pm2_xvipc xvipc;
100static int xvipc_fd = -1;
101
102
103#define MAX_BUFFERS 2
104
105typedef struct {
106    CARD32			xy, wh;				/* 16.0 16.0 */
107    INT32			s, t;				/* 12.20 fp */
108    short			y1, y2;
109} CookieRec, *CookiePtr;
110
111typedef struct _PortPrivRec {
112    struct _AdaptorPrivRec *    pAdaptor;
113    I2CDevRec                   I2CDev;
114
115    INT32			Attribute[8];			/* Brig, Con, Sat, Hue, Int, Filt, BkgCol, Alpha */
116
117    int				BuffersRequested;
118    int				BuffersAllocated;
119    FBAreaPtr			pFBArea[MAX_BUFFERS];
120    CARD32			BufferBase[MAX_BUFFERS];	/* FB byte offset */
121    CARD32			BufferStride;			/* bytes */
122    CARD32			BufferPProd;			/* PProd(BufferStride in buffer pixels) */
123
124    INT32			vx, vy, vw, vh;			/* 12.10 fp */
125    int				dx, dy, dw, dh;
126    int				fw, fh;
127
128    CookiePtr			pCookies;
129    int				nCookies;
130    INT32			dS, dT;				/* 12.20 fp */
131
132    int				Id, Bpp;			/* Scaler */
133
134    int                         Plug;
135    int				BkgCol;				/* RGB 5:6:5; 5:6:5 */
136    Bool			StreamOn;			/* buffer <-> hardware */
137    int				VideoOn;			/* buffer <-> screen */
138    int				VideoStdReq;
139
140    int				StopDelay;
141
142    int				FramesPerSec, FrameAcc;
143
144} PortPrivRec, *PortPrivPtr;
145
146enum { VIDEO_OFF, VIDEO_ONE_SHOT, VIDEO_ON };
147
148typedef struct _LFBAreaRec {
149    struct _LFBAreaRec *	Next;
150    int				Linear;
151    FBAreaPtr			pFBArea;
152} LFBAreaRec, *LFBAreaPtr;
153
154typedef struct _AdaptorPrivRec {
155    struct _AdaptorPrivRec *	Next;
156    ScrnInfoPtr			pScrn;
157
158    void *			pm2p;
159    LFBAreaPtr			LFBList;
160
161    CARD32			dFifoControl;
162    CARD32			dDitherMode;
163    CARD32			dAlphaBlendMode;
164    CARD32			dTextureDataFormat;
165
166    OsTimerPtr			Timer;
167    int				TimerUsers;
168    int				Delay, Instant;
169
170    int				FramesPerSec;
171    int				FrameLines;
172    int				IntLine;			/* Frame, not field */
173    int				LinePer;			/* nsec */
174
175    Bool			VideoIO;
176    int                         VideoStd;
177
178    PortPrivRec                 Port[PORTS];
179
180} AdaptorPrivRec, *AdaptorPrivPtr;
181
182static AdaptorPrivPtr AdaptorPrivList = NULL;
183
184#define FreeCookies(pPPriv)		\
185do {					\
186    if ((pPPriv)->pCookies) {		\
187        xfree((pPPriv)->pCookies);	\
188	(pPPriv)->pCookies = NULL;	\
189    }					\
190} while (0)
191
192#define PORTNUM(p) ((int)((p) - &pAPriv->Port[0]))
193#define BPPSHIFT(g) (2 - (g)->BppShift)	/* Bytes per pixel = 1 << BPPSHIFT(pGlint) */
194
195#define DEBUG(x)
196
197static const Bool ColorBars = FALSE;
198
199
200/*
201 *  XF86Config VideoAdaptor options
202 */
203
204typedef enum {
205    OPTION_DEVICE,
206    OPTION_FPS,
207    OPTION_BUFFERS,
208    OPTION_ENCODING,
209    OPTION_EXPOSE	/* obsolete, ignored */
210} OptToken;
211
212/* XXX These should be made const, and per-screen/adaptor copies processed. */
213static OptionInfoRec AdaptorOptions[] = {
214    { OPTION_DEVICE,		"Device",	OPTV_STRING,	{0}, FALSE },
215    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
216};
217static OptionInfoRec InputOptions[] = {
218    { OPTION_BUFFERS,		"Buffers",	OPTV_INTEGER,	{0}, FALSE },
219    { OPTION_FPS,		"FramesPerSec", OPTV_INTEGER,	{0}, FALSE },
220    { OPTION_ENCODING,		"Encoding",	OPTV_STRING,	{0}, FALSE },
221    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
222};
223static OptionInfoRec OutputOptions[] = {
224    { OPTION_BUFFERS,		"Buffers",	OPTV_INTEGER,	{0}, FALSE },
225    { OPTION_EXPOSE,		"Expose",	OPTV_BOOLEAN,	{0}, FALSE },
226    { OPTION_FPS,		"FramesPerSec", OPTV_INTEGER,	{0}, FALSE },
227    { OPTION_ENCODING,		"Encoding",	OPTV_STRING,	{0}, FALSE },
228    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
229};
230
231
232/*
233 *  Attributes
234 */
235
236#define XV_ENCODING	"XV_ENCODING"
237#define XV_BRIGHTNESS	"XV_BRIGHTNESS"
238#define XV_CONTRAST 	"XV_CONTRAST"
239#define XV_SATURATION	"XV_SATURATION"
240#define XV_HUE		"XV_HUE"
241
242/* Proprietary */
243
244#define XV_INTERLACE	"XV_INTERLACE"	/* Interlaced (bool) */
245#define XV_FILTER	"XV_FILTER"	/* Bilinear filter (bool) */
246#define XV_BKGCOLOR	"XV_BKGCOLOR"	/* Output background (0x00RRGGBB) */
247#define XV_ALPHA	"XV_ALPHA"	/* Scaler alpha channel (bool) */
248
249#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
250
251static Atom xvEncoding, xvBrightness, xvContrast, xvSaturation, xvHue;
252static Atom xvInterlace, xvFilter, xvBkgColor, xvAlpha;
253
254/* Input */
255
256static XF86VideoEncodingRec
257InputVideoEncodings[] =
258{
259    { 0, "pal-composite",		704, 576, { 1, 50 }},
260    { 1, "pal-composite_adaptor",	704, 576, { 1, 50 }},
261    { 2, "pal-svideo",			704, 576, { 1, 50 }},
262    { 3, "ntsc-composite",		704, 480, { 1001, 60000 }},
263    { 4, "ntsc-composite_adaptor",	704, 480, { 1001, 60000 }},
264    { 5, "ntsc-svideo",			704, 480, { 1001, 60000 }},
265    { 6, "secam-composite",		704, 576, { 1, 50 }},
266    { 7, "secam-composite_adaptor",	704, 576, { 1, 50 }},
267    { 8, "secam-svideo",		704, 576, { 1, 50 }},
268};
269
270static XF86AttributeRec
271InputVideoAttributes[] =
272{
273    { XvSettable | XvGettable, -1000, +1000, XV_BRIGHTNESS },
274    { XvSettable | XvGettable, -3000, +1000, XV_CONTRAST },
275    { XvSettable | XvGettable, -3000, +1000, XV_SATURATION },
276    { XvSettable | XvGettable, -1000, +1000, XV_HUE },
277    { XvSettable | XvGettable, 0, 2, XV_INTERLACE },
278    { XvSettable | XvGettable, 0, 1, XV_FILTER },
279};
280
281static XF86VideoFormatRec
282InputVideoFormats[] =
283{
284    { 8,  TrueColor }, /* Dithered */
285    { 15, TrueColor },
286    { 16, TrueColor },
287    { 24, TrueColor },
288};
289
290/* Output */
291
292static XF86VideoEncodingRec
293OutputVideoEncodings[] =
294{
295    { 0, "pal-composite_adaptor",	704, 576, { 1, 50 }},
296    { 1, "pal-svideo",			704, 576, { 1, 50 }},
297    { 2, "ntsc-composite_adaptor",	704, 480, { 1001, 60000 }},
298    { 3, "ntsc-svideo",			704, 480, { 1001, 60000 }},
299};
300
301static XF86AttributeRec
302OutputVideoAttributes[] =
303{
304    { XvSettable | XvGettable, 0, 2, XV_INTERLACE },
305    { XvSettable | XvGettable, 0, 1, XV_FILTER },
306    { XvSettable | XvGettable, 0x000000, 0xFFFFFF, XV_BKGCOLOR },
307};
308
309static XF86VideoFormatRec
310OutputVideoFormats[] =
311{
312    { 8,  TrueColor },
313    { 8,  PseudoColor }, /* Using .. */
314    { 8,  StaticColor },
315    { 8,  GrayScale },
316    { 8,  StaticGray }, /* .. TexelLUT */
317    { 15, TrueColor },
318    { 16, TrueColor },
319    { 24, TrueColor },
320};
321
322/* Scaler */
323
324static XF86VideoEncodingRec
325ScalerEncodings[] =
326{
327    { 0, "XV_IMAGE", 2047, 2047, { 1, 1 }},
328};
329
330static XF86AttributeRec
331ScalerAttributes[] =
332{
333    { XvSettable | XvGettable, 0, 1, XV_FILTER },
334    { XvSettable | XvGettable, 0, 1, XV_ALPHA },
335};
336
337#define ScalerVideoFormats InputVideoFormats
338
339/*
340 *  FOURCC from http://www.webartz.com/fourcc
341 *  Generic GUID for legacy FOURCC XXXXXXXX-0000-0010-8000-00AA00389B71
342 */
343#define LE4CC(a,b,c,d) (((CARD32)(a)&0xFF)|(((CARD32)(b)&0xFF)<<8)|(((CARD32)(c)&0xFF)<<16)|(((CARD32)(d)&0xFF)<<24))
344#define GUID4CC(a,b,c,d) { a,b,c,d,0,0,0,0x10,0x80,0,0,0xAA,0,0x38,0x9B,0x71 }
345
346#define NoOrder LSBFirst
347
348static XF86ImageRec
349ScalerImages[] =
350{
351    /* Planar YVU 4:2:0 (emulated) */
352    { LE4CC('Y','V','1','2'), XvYUV, NoOrder, GUID4CC('Y','V','1','2'),
353      12, XvPlanar, 3, 0, 0, 0, 0,
354      8, 8, 8,  1, 2, 2,  1, 2, 2, "YVU", XvTopToBottom },
355
356    /* Packed YUYV 4:2:2 */
357    { LE4CC('Y','U','Y','2'), XvYUV, NoOrder, GUID4CC('Y','U','Y','2'),
358      16, XvPacked, 1, 0, 0, 0, 0,
359      8, 8, 8,  1, 2, 2,  1, 1, 1, "YUYV", XvTopToBottom },
360
361    /* Packed UYVY 4:2:2 */
362    { LE4CC('U','Y','V','Y'), XvYUV, NoOrder, GUID4CC('U','Y','V','Y'),
363      16, XvPacked, 1, 0, 0, 0, 0,
364      8, 8, 8,  1, 2, 2,  1, 1, 1, "UYVY", XvTopToBottom },
365
366    /* Packed YUVA 4:4:4 */
367    { LE4CC('Y','U','V','A') /* XXX not registered */, XvYUV, LSBFirst, { 0 },
368      32, XvPacked, 1, 0, 0, 0, 0,
369      8, 8, 8,  1, 1, 1,  1, 1, 1, "YUVA", XvTopToBottom },
370
371    /* Packed VUYA 4:4:4 */
372    { LE4CC('V','U','Y','A') /* XXX not registered */, XvYUV, LSBFirst, { 0 },
373      32, XvPacked, 1, 0, 0, 0, 0,
374      8, 8, 8,  1, 1, 1,  1, 1, 1, "VUYA", XvTopToBottom },
375
376    /* RGBA 8:8:8:8 */
377    { 0x41, XvRGB, LSBFirst, { 0 },
378      32, XvPacked, 1, 24, 0x0000FF, 0x00FF00, 0xFF0000,
379      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGBA", XvTopToBottom },
380
381    /* RGB 5:6:5 */
382    { 0x42, XvRGB, LSBFirst, { 0 },
383      16, XvPacked, 1, 16, 0x001F, 0x07E0, 0xF800,
384      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGB", XvTopToBottom },
385
386    /* RGBA 5:5:5:1 */
387    { 0x43, XvRGB, LSBFirst, { 0 },
388      16, XvPacked, 1, 15, 0x001F, 0x03E0, 0x7C00,
389      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGBA", XvTopToBottom },
390
391    /* RGBA 4:4:4:4 */
392    { 0x44, XvRGB, LSBFirst, { 0 },
393      16, XvPacked, 1, 12, 0x000F, 0x00F0, 0x0F00,
394      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGBA", XvTopToBottom },
395
396    /* RGBA 2:3:2:1 */
397    { 0x45, XvRGB, NoOrder, { 0 },
398      8, XvPacked, 1, 7, 0x03, 0x1C, 0x60,
399      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGBA", XvTopToBottom },
400
401    /* RGB 3:3:2 */
402    { 0x46, XvRGB, NoOrder, { 0 },
403      8, XvPacked, 1, 8, 0x07, 0x38, 0xC0,
404      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGB", XvTopToBottom },
405
406    /* BGRA 8:8:8:8 */
407    { 0x47, XvRGB, LSBFirst, { 0 },
408      32, XvPacked, 1, 24, 0xFF0000, 0x00FF00, 0x0000FF,
409      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGRA", XvTopToBottom },
410
411    /* BGR 5:6:5 */
412    { 0x48, XvRGB, LSBFirst, { 0 },
413      16, XvPacked, 1, 16, 0xF800, 0x07E0, 0x001F,
414      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGR", XvTopToBottom },
415
416    /* BGRA 5:5:5:1 */
417    { 0x49, XvRGB, LSBFirst, { 0 },
418      16, XvPacked, 1, 15, 0x7C00, 0x03E0, 0x001F,
419      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGRA", XvTopToBottom },
420
421    /* BGRA 4:4:4:4 */
422    { 0x4A, XvRGB, LSBFirst, { 0 },
423      16, XvPacked, 1, 12, 0x0F00, 0x00F0, 0x000F,
424      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGRA", XvTopToBottom },
425
426    /* BGRA 2:3:2:1 */
427    { 0x4B, XvRGB, NoOrder, { 0 },
428      8, XvPacked, 1, 7, 0x60, 0x1C, 0x03,
429      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGRA", XvTopToBottom },
430
431    /* BGR 2:3:3 */
432    { 0x4C, XvRGB, NoOrder, { 0 },
433      8, XvPacked, 1, 8, 0xC0, 0x38, 0x07,
434      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGR", XvTopToBottom },
435};
436
437
438/*
439 *  Video codec tables
440 */
441
442#define SAA7111_SLAVE_ADDRESS 0x48
443#define SAA7125_SLAVE_ADDRESS 0x88
444
445static I2CByte
446DecInitVec[] =
447{
448    0x11, 0x00,
449    0x02, 0xC1, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00,
450    0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x4A,
451    0x0A, 0x80, 0x0B, 0x40, 0x0C, 0x40, 0x0D, 0x00,
452    0x0E, 0x01, 0x10, 0xC8, 0x12, 0x20,
453    0x13, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
454};
455
456static I2CByte
457EncInitVec[] =
458{
459    0x3A, 0x83, 0x61, 0xC2,
460    0x5A, 119,  0x5B, 0x7D,
461    0x5C, 0xAF, 0x5D, 0x3C, 0x5E, 0x3F, 0x5F, 0x3F,
462    0x60, 0x70, 0x62, 0x4B, 0x67, 0x00,
463    0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, 0x20,
464    0x6C, 0x03, 0x6D, 0x30, 0x6E, 0xA0, 0x6F, 0x00,
465    0x70, 0x80, 0x71, 0xE8, 0x72, 0x10,
466    0x7A, 0x13, 0x7B, 0xFB, 0x7C, 0x00, 0x7D, 0x00,
467};
468
469static I2CByte Dec02[3] = { 0xC1, 0xC0, 0xC4 };
470static I2CByte Dec09[3] = { 0x4A, 0x4A, 0xCA };
471static I2CByte Enc3A[3] = { 0x03, 0x03, 0x23 };
472static I2CByte Enc61[3] = { 0x06, 0x01, 0xC2 };
473
474static I2CByte
475DecVS[3][8] =
476{
477    { 0x06, 108, 0x07, 108, 0x08, 0x09, 0x0E, 0x01 },
478    { 0x06, 107, 0x07, 107, 0x08, 0x49, 0x0E, 0x01 },
479    { 0x06, 108, 0x07, 108, 0x08, 0x01, 0x0E, 0x51 }
480};
481
482#define FSC(n) ((CARD32)((n) / 27e6 * 4294967296.0 + .5))
483#define SUBCARRIER_FREQ_PAL  (4.433619e6)
484#define SUBCARRIER_FREQ_NTSC (3.579545e6)
485
486static I2CByte
487EncVS[2][14] =
488{
489    { 0x62, 0x4B, 0x6B, 0x28, 0x6E, 0xA0,
490      0x63, (I2CByte)(FSC(SUBCARRIER_FREQ_PAL) >> 0),
491      0x64, (I2CByte)(FSC(SUBCARRIER_FREQ_PAL) >> 8),
492      0x65, (I2CByte)(FSC(SUBCARRIER_FREQ_PAL) >> 16),
493      0x66, (I2CByte)(FSC(SUBCARRIER_FREQ_PAL) >> 24) },
494    { 0x62, 0x6A, 0x6B, 0x20, 0x6E, 0x20,
495      0x63, (I2CByte)(FSC(SUBCARRIER_FREQ_NTSC) >> 0),
496      0x64, (I2CByte)(FSC(SUBCARRIER_FREQ_NTSC) >> 8),
497      0x65, (I2CByte)(FSC(SUBCARRIER_FREQ_NTSC) >> 16),
498      0x66, (I2CByte)(FSC(SUBCARRIER_FREQ_NTSC) >> 24) }
499};
500
501/* Forward */
502static void StopVideoStream(PortPrivPtr pPPriv, Bool shutdown);
503static void RestoreVideoStd(AdaptorPrivPtr pAPriv);
504static Bool xvipcHandshake(PortPrivPtr pPPriv, int op, Bool block);
505
506
507/*
508 *  Video codec controls
509 */
510
511static int
512SetAttr(PortPrivPtr pPPriv, int i, int value)
513{
514    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
515    int v;
516
517    if (value < InputVideoAttributes[i].min_value)
518	value = InputVideoAttributes[i].min_value;
519    else
520    if (value > InputVideoAttributes[i].max_value)
521	value = InputVideoAttributes[i].max_value;
522
523    switch (i) {
524    case 0:
525        v = 128 + (MIN(value, 999) * 128) / 1000;
526        break;
527
528    case 1:
529    case 2:
530        v = 64 + (MIN(value, 999) * 64) / 1000;
531        break;
532
533    default:
534        v = (MIN(value, 999) * 128) / 1000;
535        break;
536    }
537
538    if (pAPriv->pm2p) {
539	xvipc.a = v << 8;
540
541	if (!xvipcHandshake(pPPriv, OP_ATTR + i, TRUE))
542	    return XvBadAlloc;
543    } else
544	if (!xf86I2CWriteByte(&pPPriv->I2CDev, 0x0A + i, v))
545	    return XvBadAlloc;
546
547    pPPriv->Attribute[i] = value;
548
549    return Success;
550}
551
552static int
553SetPlug(PortPrivPtr pPPriv, int Plug)
554{
555    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
556
557    if (pAPriv->pm2p) {
558	xvipc.a = Plug - (pPPriv == &pAPriv->Port[1]);
559
560	if (!xvipcHandshake(pPPriv, OP_PLUG, TRUE))
561	    return XvBadAlloc;
562    } else {
563	if (pPPriv == &pAPriv->Port[0]) {
564	    if (!xf86I2CWriteByte(&pPPriv->I2CDev, 0x02, Dec02[Plug]) ||
565		!xf86I2CWriteByte(&pPPriv->I2CDev, 0x09, Dec09[Plug]))
566		return XvBadAlloc;
567	} else {
568	    if (pPPriv->StreamOn) {
569		if (!xf86I2CWriteByte(&pPPriv->I2CDev, 0x3A, Enc3A[Plug]))
570		    return XvBadAlloc;
571	    } else
572		if (ColorBars)
573		    xf86I2CWriteByte(&pPPriv->I2CDev, 0x3A, 0x83);
574	}
575    }
576
577    pPPriv->Plug = Plug;
578
579    return Success;
580}
581
582enum { PAL, NTSC, SECAM };
583
584static int
585SetVideoStd(PortPrivPtr pPPriv, int VideoStd)
586{
587    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
588    int r = Success;
589
590    if (pAPriv->pm2p) {
591	xvipc.a = VideoStd;
592
593	if (!xvipcHandshake(&pAPriv->Port[0], OP_VIDEOSTD, TRUE))
594	    return XvBadAlloc;
595
596	VideoStd = xvipc.a; /* Actual */
597    } else {
598	if (VideoStd == SECAM)
599	    xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x61, 0xC2);
600	    /* Disable output, SECAM not supported */
601
602	if (!xf86I2CWriteVec(&pAPriv->Port[0].I2CDev, &DecVS[VideoStd][0], 4)) {
603	    pAPriv->VideoStd = -1;
604	    return XvBadAlloc;
605	}
606
607	if (VideoStd != SECAM)
608	    if (!xf86I2CWriteVec(&pAPriv->Port[1].I2CDev, &EncVS[VideoStd][0], 7)) {
609		pAPriv->VideoStd = -1;
610		return XvBadAlloc;
611	    }
612    }
613
614    pAPriv->VideoStd = VideoStd;
615    pPPriv->VideoStdReq = VideoStd;
616
617    if (VideoStd == NTSC) {
618	pAPriv->FramesPerSec = 30;
619	pAPriv->FrameLines = 525;
620	pAPriv->IntLine = 513;
621	pAPriv->LinePer = 63555;
622    } else {
623	pAPriv->FramesPerSec = 25;
624	pAPriv->FrameLines = 625;
625	pAPriv->IntLine = 613;
626	pAPriv->LinePer = 64000;
627    }
628
629#if 0 /* XF86Config option */
630
631    pAPriv->Port[0].FramesPerSec = pAPriv->FramesPerSec;
632    pAPriv->Port[1].FramesPerSec = pAPriv->FramesPerSec;
633
634#endif
635
636    return r;
637}
638
639
640/*
641 *  Buffer management
642 */
643
644static void
645RemoveAreaCallback(FBAreaPtr pFBArea)
646{
647    PortPrivPtr pPPriv = (PortPrivPtr) pFBArea->devPrivate.ptr;
648    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
649    DEBUG(ScrnInfoPtr pScrn = pAPriv->pScrn;)
650    int i;
651
652    for (i = 0; i < MAX_BUFFERS && pPPriv->pFBArea[i] != pFBArea; i++);
653
654    if (i >= MAX_BUFFERS)
655	return;
656
657    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
658	"RemoveAreaCallback port #%d, buffer #%d, pFB=%p, off=0x%08x\n",
659	PORTNUM(pPPriv), i, pPPriv->pFBArea[i], pPPriv->BufferBase[i]));
660
661    if (pAPriv->VideoIO && PORTNUM(pPPriv) < 2) {
662        StopVideoStream(pPPriv, FALSE);
663    }
664
665    for (; i < MAX_BUFFERS - 1; i++)
666	pPPriv->pFBArea[i] = pPPriv->pFBArea[i + 1];
667
668    pPPriv->pFBArea[MAX_BUFFERS - 1] = NULL;
669
670    pPPriv->BuffersAllocated--;
671}
672
673static void
674RemoveableBuffers(PortPrivPtr pPPriv, Bool remove)
675{
676    int i;
677
678    for (i = 0; i < MAX_BUFFERS; i++)
679	if (pPPriv->pFBArea[i])
680	    pPPriv->pFBArea[i]->RemoveAreaCallback =
681		remove ? RemoveAreaCallback : NULL;
682}
683
684static void
685FreeBuffers(PortPrivPtr pPPriv)
686{
687    DEBUG(AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;)
688    DEBUG(ScrnInfoPtr pScrn = pAPriv->pScrn;)
689    int i;
690
691    RemoveableBuffers(pPPriv, FALSE);
692
693    for (i = MAX_BUFFERS - 1; i >= 0; i--)
694	if (pPPriv->pFBArea[i]) {
695	    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
696		"FreeBuffers port #%d, buffer #%d, pFB=%p, off=0x%08x\n",
697		PORTNUM(pPPriv), i, pPPriv->pFBArea[i], pPPriv->BufferBase[i]));
698
699	    xf86FreeOffscreenArea(pPPriv->pFBArea[i]);
700
701	    pPPriv->pFBArea[i] = NULL;
702	}
703
704    pPPriv->BuffersAllocated = 0;
705}
706
707enum { FORCE_LINEAR = 1, FORCE_RECT };
708
709static int
710AllocateBuffers(PortPrivPtr pPPriv,
711    int w, int h, int bytespp,
712    int num, int force)
713{
714    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
715    ScrnInfoPtr pScrn = pAPriv->pScrn;
716    GLINTPtr pGlint = GLINTPTR(pScrn);
717    Bool linear = (force != FORCE_RECT);
718    int i, j, retry = 0;
719
720    FreeBuffers(pPPriv);
721
722    for (i = 0; i < num; i++) {
723	if (linear) {
724	    for (j = (w + 31) >> 5; partprodPermedia[j] < 0; j++);
725
726	    pPPriv->BufferStride = j * bytespp * 32;
727	    pPPriv->BufferPProd = partprodPermedia[j];
728
729	    pPPriv->pFBArea[i] = xf86AllocateLinearOffscreenArea(pScrn->pScreen,
730    		(pPPriv->BufferStride * h + (1 << BPPSHIFT(pGlint)) - 1) >> BPPSHIFT(pGlint),
731		8 >> BPPSHIFT(pGlint), NULL, NULL, (pointer) pPPriv);
732
733	    if (pPPriv->pFBArea[i])
734		/* pPPriv->BufferBase[i] = pPPriv->pFBArea[i].linear; */
735		pPPriv->BufferBase[i] =
736		    ((pPPriv->pFBArea[i]->box.y1 * pScrn->displayWidth) +
737		     pPPriv->pFBArea[i]->box.x1) << BPPSHIFT(pGlint);
738
739	    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
740		"New linear buffer %dx%d, rec %dx%d -> pFB=%p, off=0x%08x\n",
741		w, h, pPPriv->BufferStride, h, pPPriv->pFBArea[i], pPPriv->BufferBase[i]));
742	} else {
743	    pPPriv->BufferStride = pScrn->displayWidth << BPPSHIFT(pGlint);
744
745	    j = pPPriv->BufferStride / bytespp;
746
747	    if (j <= w && j <= 2048 && (j & 31) == 0 &&
748		partprodPermedia[j >> 5] >= 0)
749	    {
750		pPPriv->BufferPProd = partprodPermedia[j >> 5];
751		pPPriv->pFBArea[i] = xf86AllocateOffscreenArea(pScrn->pScreen,
752    		    w, h, 8 >> BPPSHIFT(pGlint), NULL, NULL, (pointer) pPPriv);
753
754		if (pPPriv->pFBArea[i])
755		    pPPriv->BufferBase[i] =
756			((pPPriv->pFBArea[i]->box.y1 * pScrn->displayWidth) +
757		         pPPriv->pFBArea[i]->box.x1) << BPPSHIFT(pGlint);
758
759		DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 4,
760		    "New rect buffer %dx%d, stride %d, %d -> pFB=%p, off=0x%08x\n",
761		    w, h, pPPriv->BufferStride, j, pPPriv->pFBArea[i], pPPriv->BufferBase[i]));
762	    }
763	}
764
765	if (pPPriv->pFBArea[i])
766	    continue;
767
768	if (!force && i == 0 && retry++ < 1) {
769	    linear ^= TRUE;
770	    i = -1;
771	} else
772	    break;
773    }
774
775    return pPPriv->BuffersAllocated = i;
776}
777
778
779/*
780 *  Blitter
781 */
782
783static Bool
784RemakePutCookies(PortPrivPtr pPPriv, RegionPtr pRegion)
785{
786    BoxPtr pBox;
787    CookiePtr pCookie;
788    int nBox;
789
790    if (!pRegion) {
791	pBox = (BoxPtr) NULL;
792	nBox = pPPriv->nCookies;
793    } else {
794	pBox = REGION_RECTS(pRegion);
795	nBox = REGION_NUM_RECTS(pRegion);
796
797	if (!pPPriv->pCookies || pPPriv->nCookies < nBox) {
798	    if (!(pCookie = (CookiePtr) xrealloc(pPPriv->pCookies, nBox * sizeof(CookieRec))))
799    		return FALSE;
800
801	    pPPriv->pCookies = pCookie;
802	}
803    }
804
805    pPPriv->dS = (pPPriv->vw << 10) / pPPriv->dw;
806    pPPriv->dT = (pPPriv->vh << 10) / pPPriv->dh;
807
808    for (pCookie = pPPriv->pCookies; nBox--; pCookie++, pBox++) {
809	if (pRegion) {
810	    pCookie->y1 = pBox->y1;
811	    pCookie->y2 = pBox->x1;
812	    pCookie->xy = (pBox->y1 << 16) | pBox->x1;
813	    pCookie->wh = ((pBox->y2 - pBox->y1) << 16) |
814			   (pBox->x2 - pBox->x1);
815	}
816
817	pCookie->s = (pPPriv->vx << 10) + (pCookie->y2 - pPPriv->dx) * pPPriv->dS;
818	pCookie->t = (pPPriv->vy << 10) + (pCookie->y1 - pPPriv->dy) * pPPriv->dT;
819    }
820
821    pPPriv->nCookies = pCookie - pPPriv->pCookies;
822
823    return TRUE;
824}
825
826#define FORMAT_YUYV ((0 << 5) + (1 << 4) + ((19 & 0x10) << 2) + ((19 & 0x0F) << 0))
827#define FORMAT_UYVY ((1 << 5) + (1 << 4) + ((19 & 0x10) << 2) + ((19 & 0x0F) << 0))
828#define FORMAT_YUVA ((0 << 5) + ((18 & 0x10) << 2) + ((18 & 0x0F) << 0))
829#define FORMAT_VUYA ((1 << 5) + ((18 & 0x10) << 2) + ((18 & 0x0F) << 0))
830
831static void
832PutYUV(PortPrivPtr pPPriv, int BufferBase,
833    int format, int bptshift, int alpha)
834{
835    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
836    ScrnInfoPtr pScrn = pAPriv->pScrn;
837    GLINTPtr pGlint = GLINTPTR(pScrn);
838    CookiePtr pCookie = pPPriv->pCookies;
839    int nCookies = pPPriv->nCookies;
840
841    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 5, "PutYUV %08x %08x\n",
842	BufferBase, format));
843
844    if (!nCookies || (GLINT_READ_REG(InFIFOSpace) < 200))
845	return; /* Denial of service fix, N/A for scaler */
846
847    CHECKCLIPPING;
848
849    GLINT_WRITE_REG(1 << 16, dY);
850    GLINT_WRITE_REG(0, RasterizerMode);
851    GLINT_WRITE_REG(UNIT_DISABLE, AreaStippleMode);
852    GLINT_WRITE_REG(UNIT_ENABLE, TextureAddressMode);
853    GLINT_WRITE_REG(pPPriv->dS, dSdx);
854    GLINT_WRITE_REG(0, dSdyDom);
855    GLINT_WRITE_REG(0, dTdx);
856    GLINT_WRITE_REG(pPPriv->dT, dTdyDom);
857    GLINT_WRITE_REG(BufferBase >> bptshift, PMTextureBaseAddress);
858    GLINT_WRITE_REG((bptshift << 19) | pPPriv->BufferPProd, PMTextureMapFormat);
859    GLINT_WRITE_REG(format, PMTextureDataFormat);
860    GLINT_WRITE_REG((pPPriv->Attribute[5] << 17) | /* FilterMode */
861		    (11 << 13) | (11 << 9) | /* TextureSize log2 */
862		    UNIT_ENABLE, PMTextureReadMode);
863    GLINT_WRITE_REG((0 << 4) /* RGB */ |
864		    (3 << 1) /* Copy */ |
865		    UNIT_ENABLE, TextureColorMode);
866    if (alpha)
867	GLINT_WRITE_REG(pAPriv->dAlphaBlendMode, AlphaBlendMode);
868    GLINT_WRITE_REG(pAPriv->dDitherMode, DitherMode);
869    GLINT_WRITE_REG(UNIT_DISABLE, LogicalOpMode);
870    GLINT_WRITE_REG((alpha << 10) | /* ReadDestination */
871		    pGlint->pprod, FBReadMode);
872    GLINT_WRITE_REG(0xFFFFFFFF, FBHardwareWriteMask);
873    GLINT_WRITE_REG(UNIT_ENABLE, YUVMode);
874
875    for (; nCookies--; pCookie++) {
876	GLINT_WAIT(5);
877	GLINT_WRITE_REG(pCookie->xy, RectangleOrigin);
878	GLINT_WRITE_REG(pCookie->wh, RectangleSize);
879	GLINT_WRITE_REG(pCookie->s, SStart);
880	GLINT_WRITE_REG(pCookie->t, TStart);
881        GLINT_WRITE_REG(PrimitiveRectangle |
882			XPositive |
883			YPositive |
884			TextureEnable, Render);
885    }
886
887    pGlint->x = pGlint->y = -1; /* Force reload */
888    pGlint->w = pGlint->h = -1;
889    pGlint->ROP = 0xFF;
890    pGlint->planemask = 0xFFFFFFFF;
891
892    GLINT_WAIT(8);
893    GLINT_WRITE_REG(UNIT_DISABLE, TextureAddressMode);
894    GLINT_WRITE_REG(pGlint->TexMapFormat, PMTextureMapFormat);
895    GLINT_WRITE_REG(UNIT_DISABLE, PMTextureReadMode);
896    GLINT_WRITE_REG(UNIT_DISABLE, TextureColorMode);
897    GLINT_WRITE_REG(UNIT_DISABLE, DitherMode);
898    if (alpha) {
899	GLINT_WRITE_REG(UNIT_DISABLE, AlphaBlendMode);
900	GLINT_WRITE_REG(pGlint->pprod, FBReadMode);
901    }
902    GLINT_WRITE_REG(UNIT_DISABLE, YUVMode);
903}
904
905#define FORMAT_RGB8888 ((0 << 5) + (0 << 4) + ((0 & 0x10) << 2) + ((0 & 0x0F) << 0))
906#define FORMAT_RGB565  ((0 << 5) + (1 << 4) + ((16 & 0x10) << 2) + ((16 & 0x0F) << 0))
907#define FORMAT_RGB5551 ((0 << 5) + (0 << 4) + ((1 & 0x10) << 2) + ((1 & 0x0F) << 0))
908#define FORMAT_RGB4444 ((0 << 5) + (0 << 4) + ((2 & 0x10) << 2) + ((2 & 0x0F) << 0))
909#define FORMAT_RGB332  ((0 << 5) + (1 << 4) + ((5 & 0x10) << 2) + ((5 & 0x0F) << 0))
910#define FORMAT_RGB2321 ((0 << 5) + (0 << 4) + ((9 & 0x10) << 2) + ((9 & 0x0F) << 0))
911#define FORMAT_BGR8888 ((1 << 5) + (0 << 4) + ((0 & 0x10) << 2) + ((0 & 0x0F) << 0))
912#define FORMAT_BGR565  ((1 << 5) + (1 << 4) + ((16 & 0x10) << 2) + ((16 & 0x0F) << 0))
913#define FORMAT_BGR5551 ((1 << 5) + (0 << 4) + ((1 & 0x10) << 2) + ((1 & 0x0F) << 0))
914#define FORMAT_BGR4444 ((1 << 5) + (0 << 4) + ((2 & 0x10) << 2) + ((2 & 0x0F) << 0))
915#define FORMAT_BGR332  ((1 << 5) + (1 << 4) + ((5 & 0x10) << 2) + ((5 & 0x0F) << 0))
916#define FORMAT_BGR2321 ((1 << 5) + (0 << 4) + ((9 & 0x10) << 2) + ((9 & 0x0F) << 0))
917
918static void
919PutRGB(PortPrivPtr pPPriv, int BufferBase, int format, int bptshift, int alpha)
920{
921    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
922    ScrnInfoPtr pScrn = pAPriv->pScrn;
923    GLINTPtr pGlint = GLINTPTR(pScrn);
924    CookiePtr pCookie = pPPriv->pCookies;
925    int nCookies = pPPriv->nCookies;
926
927    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 5, "PutRGB %08x %08x\n",
928	BufferBase, format));
929
930    if (!nCookies)
931	return;
932
933    CHECKCLIPPING;
934
935    GLINT_WRITE_REG(1 << 16, dY);
936    GLINT_WRITE_REG(0, RasterizerMode);
937    GLINT_WRITE_REG(UNIT_DISABLE, AreaStippleMode);
938    GLINT_WRITE_REG(UNIT_ENABLE, TextureAddressMode);
939    GLINT_WRITE_REG(pPPriv->dS, dSdx);
940    GLINT_WRITE_REG(0, dSdyDom);
941    GLINT_WRITE_REG(0, dTdx);
942    GLINT_WRITE_REG(pPPriv->dT, dTdyDom);
943    GLINT_WRITE_REG(BufferBase >> bptshift, PMTextureBaseAddress);
944    GLINT_WRITE_REG((bptshift << 19) | pPPriv->BufferPProd, PMTextureMapFormat);
945    GLINT_WRITE_REG(format, PMTextureDataFormat);
946    GLINT_WRITE_REG((pPPriv->Attribute[5] << 17) | /* FilterMode */
947		    (11 << 13) | (11 << 9) | /* TextureSize log2 */
948		    UNIT_ENABLE, PMTextureReadMode);
949    GLINT_WRITE_REG((0 << 4) /* RGB */ |
950		    (3 << 1) /* Copy */ |
951		    UNIT_ENABLE, TextureColorMode);
952    if (alpha)
953	GLINT_WRITE_REG(pAPriv->dAlphaBlendMode, AlphaBlendMode);
954    GLINT_WRITE_REG(pAPriv->dDitherMode, DitherMode);
955    GLINT_WRITE_REG(UNIT_DISABLE, LogicalOpMode);
956    GLINT_WRITE_REG((alpha << 10) | /* ReadDestination */
957		    pGlint->pprod, FBReadMode);
958    GLINT_WRITE_REG(0xFFFFFFFF, FBHardwareWriteMask);
959
960    for (; nCookies--; pCookie++) {
961	GLINT_WAIT(5);
962	GLINT_WRITE_REG(pCookie->xy, RectangleOrigin);
963	GLINT_WRITE_REG(pCookie->wh, RectangleSize);
964	GLINT_WRITE_REG(pCookie->s, SStart);
965	GLINT_WRITE_REG(pCookie->t, TStart);
966        GLINT_WRITE_REG(PrimitiveRectangle |
967			XPositive |
968			YPositive |
969			TextureEnable, Render);
970    }
971
972    pGlint->x = pGlint->y = -1; /* Force reload */
973    pGlint->w = pGlint->h = -1;
974    pGlint->ROP = 0xFF;
975    pGlint->planemask = 0xFFFFFFFF;
976
977    GLINT_WAIT(7);
978    GLINT_WRITE_REG(UNIT_DISABLE, TextureAddressMode);
979    GLINT_WRITE_REG(pGlint->TexMapFormat, PMTextureMapFormat);
980    GLINT_WRITE_REG(UNIT_DISABLE, PMTextureReadMode);
981    GLINT_WRITE_REG(UNIT_DISABLE, TextureColorMode);
982    GLINT_WRITE_REG(UNIT_DISABLE, DitherMode);
983    if (alpha) {
984	GLINT_WRITE_REG(UNIT_DISABLE, AlphaBlendMode);
985	GLINT_WRITE_REG(pGlint->pprod, FBReadMode);
986    }
987}
988
989static void
990BlackOut(PortPrivPtr pPPriv, RegionPtr pRegion)
991{
992    ScrnInfoPtr pScrn = pPPriv->pAdaptor->pScrn;
993    ScreenPtr pScreen = pScrn->pScreen;
994    GLINTPtr pGlint = GLINTPTR(pScrn);
995    RegionRec DRegion;
996    BoxRec DBox;
997    BoxPtr pBox;
998    int nBox;
999
1000    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 5,
1001	"BlackOut %d,%d,%d,%d -- %d,%d,%d,%d\n",
1002	pPPriv->vx, pPPriv->vy, pPPriv->vw, pPPriv->vh,
1003	pPPriv->dx, pPPriv->dy, pPPriv->dw, pPPriv->dh));
1004
1005    DBox.x1 = pPPriv->dx - (pPPriv->vx * pPPriv->dw) / pPPriv->vw;
1006    DBox.y1 = pPPriv->dy - (pPPriv->vy * pPPriv->dh) / pPPriv->vh;
1007    DBox.x2 = DBox.x1 + (pPPriv->fw * pPPriv->dw) / pPPriv->vw;
1008    DBox.y2 = DBox.y1 + (pPPriv->fh * pPPriv->dh) / pPPriv->vh;
1009
1010    REGION_INIT(pScreen, &DRegion, &DBox, 1);
1011
1012    if (pRegion)
1013	REGION_SUBTRACT(pScreen, &DRegion, &DRegion, pRegion);
1014
1015    nBox = REGION_NUM_RECTS(&DRegion);
1016    pBox = REGION_RECTS(&DRegion);
1017
1018    GLINT_WAIT(15);
1019    CHECKCLIPPING;
1020
1021    GLINT_WRITE_REG(UNIT_DISABLE, ColorDDAMode);
1022    GLINT_WRITE_REG(pPPriv->BufferPProd, FBReadMode);
1023    GLINT_WRITE_REG(0x1, FBReadPixel); /* 16 */
1024    GLINT_WRITE_REG(pPPriv->BkgCol, FBBlockColor);
1025    GLINT_WRITE_REG(pPPriv->BufferBase[0] >> 1 /* 16 */, FBWindowBase);
1026    GLINT_WRITE_REG(UNIT_DISABLE, LogicalOpMode);
1027
1028    for (; nBox--; pBox++) {
1029        int w = ((pBox->x2 - pBox->x1) * pPPriv->vw + pPPriv->dw) / pPPriv->dw + 1;
1030	int h = ((pBox->y2 - pBox->y1) * pPPriv->vh + pPPriv->dh) / pPPriv->dh + 1;
1031	int x = ((pBox->x1 - DBox.x1) * pPPriv->vw + (pPPriv->dw >> 1)) / pPPriv->dw;
1032	int y = ((pBox->y1 - DBox.y1) * pPPriv->vh + (pPPriv->dh >> 1)) / pPPriv->dh;
1033
1034	if ((x + w) > pPPriv->fw)
1035	    w = pPPriv->fw - x;
1036	if ((y + h) > pPPriv->fh)
1037	    h = pPPriv->fh - y;
1038
1039	GLINT_WAIT(3);
1040	GLINT_WRITE_REG((y << 16) | x, RectangleOrigin);
1041	GLINT_WRITE_REG((h << 16) | w, RectangleSize);
1042	GLINT_WRITE_REG(PrimitiveRectangle |
1043	    XPositive | YPositive | FastFillEnable, Render);
1044    }
1045
1046    REGION_UNINIT(pScreen, &DRegion);
1047
1048    pGlint->x = pGlint->y = -1; /* Force reload */
1049    pGlint->w = pGlint->h = -1;
1050    pGlint->ROP = 0xFF;
1051    GLINT_WAIT(3);
1052    GLINT_WRITE_REG(0, FBWindowBase);
1053    GLINT_WRITE_REG(pGlint->pprod, FBReadMode);
1054    GLINT_WRITE_REG(pGlint->PixelWidth, FBReadPixel);
1055}
1056
1057static Bool
1058RemakeGetCookies(PortPrivPtr pPPriv, RegionPtr pRegion)
1059{
1060    BoxPtr pBox;
1061    CookiePtr pCookie;
1062    int nBox;
1063    int dw1 = pPPriv->dw - 1;
1064    int dh1 = pPPriv->dh - 1;
1065
1066    if (!pRegion) {
1067	pBox = (BoxPtr) NULL;
1068	nBox = pPPriv->nCookies;
1069    } else {
1070	pBox = REGION_RECTS(pRegion);
1071	nBox = REGION_NUM_RECTS(pRegion);
1072
1073	if (!pPPriv->pCookies || pPPriv->nCookies < nBox) {
1074	    if (!(pCookie = (CookiePtr) xrealloc(pPPriv->pCookies, nBox * sizeof(CookieRec))))
1075    		return FALSE;
1076
1077	    pPPriv->pCookies = pCookie;
1078	}
1079    }
1080
1081    pPPriv->dS = (pPPriv->dw << 20) / pPPriv->vw;
1082    pPPriv->dT = (pPPriv->dh << 20) / pPPriv->vh;
1083
1084    for (pCookie = pPPriv->pCookies; nBox--; pBox++) {
1085	int n1, n2;
1086
1087	if (pRegion) {
1088	    n1 = ((pBox->x1 - pPPriv->dx) * pPPriv->vw + dw1) / pPPriv->dw;
1089            n2 = ((pBox->x2 - pPPriv->dx) * pPPriv->vw - 1) / pPPriv->dw;
1090
1091	    if (n1 > n2)
1092		continue; /* Clip is subpixel */
1093
1094	    pCookie->xy = n1 + pPPriv->vx;
1095	    pCookie->wh = n2 - n1 + 1;
1096	    pCookie->s = n1 * pPPriv->dS + (pPPriv->dx << 20);
1097	    pCookie->y1 = pBox->y1;
1098	    pCookie->y2 = pBox->y2;
1099	}
1100
1101	n1 = ((pCookie->y1 - pPPriv->dy) * pPPriv->vh + dh1) / pPPriv->dh;
1102	n2 = ((pCookie->y2 - pPPriv->dy) * pPPriv->vh - 1) / pPPriv->dh;
1103	pCookie->xy = (pCookie->xy & 0xFFFF) | ((n1 + pPPriv->vy) << 16);
1104	pCookie->wh = (pCookie->wh & 0xFFFF) | ((n2 - n1 + 1) << 16);
1105	pCookie->t = n1 * pPPriv->dT + (pPPriv->dy << 20);
1106	if (n1 > n2) pCookie->t = -1;
1107
1108	pCookie++;
1109    }
1110
1111    pPPriv->nCookies = pCookie - pPPriv->pCookies;
1112    return TRUE;
1113}
1114
1115static void
1116GetYUV(PortPrivPtr pPPriv)
1117{
1118    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1119    ScrnInfoPtr pScrn = pAPriv->pScrn;
1120    GLINTPtr pGlint = GLINTPTR(pScrn);
1121    CookiePtr pCookie = pPPriv->pCookies;
1122    int nCookies = pPPriv->nCookies;
1123
1124    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 5, "GetYUV\n"));
1125
1126    if (!nCookies || (GLINT_READ_REG(InFIFOSpace) < 200))
1127	return;
1128
1129    GLINT_WAIT(25);
1130    CHECKCLIPPING;
1131
1132    GLINT_WRITE_REG(1 << 16, dY);
1133    GLINT_WRITE_REG(0, RasterizerMode);
1134    GLINT_WRITE_REG(UNIT_DISABLE, AreaStippleMode);
1135    GLINT_WRITE_REG(UNIT_ENABLE, TextureAddressMode);
1136    GLINT_WRITE_REG(pPPriv->dS, dSdx);
1137    GLINT_WRITE_REG(0, dSdyDom);
1138    GLINT_WRITE_REG(0, dTdx);
1139    GLINT_WRITE_REG(pPPriv->dT, dTdyDom);
1140    GLINT_WRITE_REG(0, PMTextureBaseAddress);
1141    GLINT_WRITE_REG(pAPriv->dTextureDataFormat, PMTextureDataFormat);
1142    GLINT_WRITE_REG((pPPriv->Attribute[5] << 17) | /* FilterMode */
1143		    (11 << 13) | (11 << 9) | /* TextureSize log2 */
1144		    UNIT_ENABLE, PMTextureReadMode);
1145    if (pScrn->depth == 8)
1146	GLINT_WRITE_REG(UNIT_ENABLE, TexelLUTMode);
1147    GLINT_WRITE_REG((0 << 4) /* RGB */ |
1148		    (3 << 1) /* Copy */ |
1149		    UNIT_ENABLE, TextureColorMode);
1150    GLINT_WRITE_REG((1 << 10) |			/* RGB */
1151		    ((16 & 0x10) << 12) |
1152		    ((16 & 0x0F) << 2) |	/* 5:6:5f */
1153		    UNIT_ENABLE, DitherMode);
1154    GLINT_WRITE_REG(UNIT_DISABLE, LogicalOpMode);
1155    GLINT_WRITE_REG(pPPriv->BufferPProd, FBReadMode);
1156    GLINT_WRITE_REG(pPPriv->BufferBase[0] >> 1 /* 16 */, FBWindowBase);
1157    GLINT_WRITE_REG(0x1, FBReadPixel); /* 16 */
1158    GLINT_WRITE_REG(UNIT_DISABLE, YUVMode);
1159
1160    for (; nCookies--; pCookie++)
1161	if (pCookie->t >= 0) {
1162	    GLINT_WAIT(5);
1163	    GLINT_WRITE_REG(pCookie->xy, RectangleOrigin);
1164	    GLINT_WRITE_REG(pCookie->wh, RectangleSize);
1165	    GLINT_WRITE_REG(pCookie->s, SStart);
1166	    GLINT_WRITE_REG(pCookie->t, TStart);
1167    	    GLINT_WRITE_REG(PrimitiveRectangle |
1168			    XPositive |
1169			    YPositive |
1170			    TextureEnable, Render);
1171	}
1172
1173    pGlint->x = pGlint->y = -1; /* Force reload */
1174    pGlint->w = pGlint->h = -1;
1175    pGlint->ROP = 0xFF;
1176
1177    GLINT_WAIT(9);
1178    GLINT_WRITE_REG(UNIT_DISABLE, TextureAddressMode);
1179    GLINT_WRITE_REG(UNIT_DISABLE, TextureColorMode);
1180    GLINT_WRITE_REG(UNIT_DISABLE, DitherMode);
1181    if (pScrn->depth == 8)
1182	GLINT_WRITE_REG(UNIT_DISABLE, TexelLUTMode);
1183    GLINT_WRITE_REG(UNIT_DISABLE, PMTextureReadMode);
1184    GLINT_WRITE_REG(pGlint->pprod, FBReadMode);
1185    GLINT_WRITE_REG(0, FBWindowBase);
1186    GLINT_WRITE_REG(pGlint->PixelWidth, FBReadPixel);
1187    GLINT_WRITE_REG(UNIT_DISABLE, YUVMode);
1188}
1189
1190static int
1191SetBkgCol(PortPrivPtr pPPriv, int value)
1192{
1193    pPPriv->Attribute[6] = value;
1194
1195    pPPriv->BkgCol = ((value & 0xF80000) >> 8) |
1196		     ((value & 0x00FC00) >> 5) |
1197		     ((value & 0x0000F8) >> 3);
1198
1199    pPPriv->BkgCol += pPPriv->BkgCol << 16;
1200
1201    if (pPPriv->VideoOn) {
1202	BlackOut(pPPriv, NULL);
1203	GetYUV(pPPriv);
1204    }
1205
1206    return Success;
1207}
1208
1209/* os/WaitFor.c */
1210
1211static CARD32
1212TimerCallback(OsTimerPtr pTim, CARD32 now, pointer p)
1213{
1214    AdaptorPrivPtr pAPriv = (AdaptorPrivPtr) p;
1215    GLINTPtr pGlint = GLINTPTR(pAPriv->pScrn);
1216    PortPrivPtr pPPriv;
1217    int i, delay;
1218
1219    if (!pAPriv->pm2p) {
1220	pPPriv = &pAPriv->Port[0];
1221
1222	if (pPPriv->VideoOn > VIDEO_OFF) {
1223	    pPPriv->FrameAcc += pPPriv->FramesPerSec;
1224
1225	    if (pPPriv->FrameAcc >= pAPriv->FramesPerSec) {
1226		pPPriv->FrameAcc -= pAPriv->FramesPerSec;
1227
1228		PutYUV(pPPriv, (!pPPriv->pFBArea[1]) ?
1229		    pPPriv->BufferBase[0] : pPPriv->BufferBase[1 -
1230			GLINT_READ_REG(VSABase + VSVideoAddressIndex)], FORMAT_YUYV, 1, 0);
1231	    }
1232	} else
1233	    if (pPPriv->StopDelay >= 0 && !(pPPriv->StopDelay--)) {
1234		StopVideoStream(pPPriv, TRUE);
1235		RestoreVideoStd(pAPriv);
1236	    }
1237
1238	pPPriv = &pAPriv->Port[1];
1239
1240	if (pPPriv->VideoOn > VIDEO_OFF) {
1241	    pPPriv->FrameAcc += pPPriv->FramesPerSec;
1242
1243	    if (pPPriv->FrameAcc >= pAPriv->FramesPerSec) {
1244		pPPriv->FrameAcc -= pAPriv->FramesPerSec;
1245
1246		GetYUV(pPPriv);
1247	    }
1248	} else
1249	    if (pPPriv->StopDelay >= 0 && !(pPPriv->StopDelay--)) {
1250		StopVideoStream(pPPriv, TRUE);
1251		RestoreVideoStd(pAPriv);
1252	    }
1253    }
1254
1255    for (i = 2; i <= 5; i++) {
1256	if (pAPriv->Port[i].StopDelay >= 0) {
1257	    if (!(pAPriv->Port[i].StopDelay--)) {
1258		FreeBuffers(&pAPriv->Port[i]);
1259		FreeCookies(&pAPriv->Port[i]);
1260		pAPriv->TimerUsers &= ~(1 << i);
1261	    }
1262	}
1263    }
1264
1265    if (!pAPriv->pm2p) {
1266	if (pAPriv->Port[0].StreamOn) {
1267	    delay = GLINT_READ_REG(VSABase + VSCurrentLine);
1268
1269	    if (!(GLINT_READ_REG(VSStatus) & VS_FieldOne0A))
1270		delay += pAPriv->FrameLines >> 1;
1271
1272	    if (delay > (pAPriv->IntLine - 16))
1273		delay -= pAPriv->FrameLines;
1274
1275	    return (((pAPriv->IntLine - delay) * pAPriv->LinePer) + 999999) / 1000000;
1276	} else if (pAPriv->Port[1].StreamOn) {
1277	    delay = GLINT_READ_REG(VSBBase + VSCurrentLine);
1278
1279	    if (!(GLINT_READ_REG(VSStatus) & VS_FieldOne0B))
1280		delay += pAPriv->FrameLines >> 1;
1281
1282	    if (delay > (pAPriv->IntLine - 16))
1283		delay -= pAPriv->FrameLines;
1284
1285	    return (((pAPriv->IntLine - delay) * pAPriv->LinePer) + 999999) / 1000000;
1286	}
1287    }
1288
1289    if (pAPriv->TimerUsers)
1290	return pAPriv->Instant;
1291
1292    return 0; /* Cancel */
1293}
1294
1295
1296/*
1297 *  Video stream (bounce buffer <-> hardware)
1298 */
1299
1300static void
1301StopVideoStream(PortPrivPtr pPPriv, Bool shutdown)
1302{
1303    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1304    GLINTPtr pGlint = GLINTPTR(pAPriv->pScrn);
1305    int VideoOn;
1306
1307    pPPriv->StopDelay = -1;
1308
1309    VideoOn = pPPriv->VideoOn;
1310    pPPriv->VideoOn = VIDEO_OFF;
1311
1312    if (!pPPriv->StreamOn)
1313	return;
1314
1315    if (pAPriv->pm2p) {
1316	xvipcHandshake(pPPriv, OP_STOP, TRUE);
1317
1318	pPPriv->StreamOn = FALSE;
1319
1320	if (shutdown)
1321	    FreeCookies(pPPriv);
1322
1323	if (VideoOn > VIDEO_OFF && pGlint->NoAccel)
1324	    Permedia2Sync(pAPriv->pScrn);
1325
1326	return;
1327    }
1328
1329    if (pPPriv == &pAPriv->Port[0]) {
1330	int line, eeek = 0;
1331
1332	do {
1333	    if (eeek++ > 1000000) break;
1334	    line = GLINT_READ_REG(VSABase + VSCurrentLine);
1335	} while (line > 15);
1336
1337	GLINT_WRITE_REG(0, VSABase + VSControl);
1338
1339	pAPriv->Port[0].StreamOn = FALSE;
1340
1341	usleep(80000);
1342    } else {
1343    	xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x3A, 0x83);
1344	if (!ColorBars)
1345	    xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x61, 0xC2);
1346
1347	GLINT_WRITE_REG(0, VSBBase + VSControl);
1348
1349	pAPriv->Port[1].StreamOn = FALSE;
1350    }
1351
1352    if (!pAPriv->Port[0].StreamOn && !pAPriv->Port[1].StreamOn) {
1353	if (shutdown)
1354	    xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x61, 0xC2);
1355	xf86I2CWriteByte(&pAPriv->Port[0].I2CDev, 0x11, 0x00);
1356    }
1357
1358    if (shutdown) {
1359	FreeBuffers(pPPriv);
1360	FreeCookies(pPPriv);
1361
1362	if (pAPriv->TimerUsers) {
1363	    pAPriv->TimerUsers &= ~PORTNUM(pPPriv);
1364	    if (!pAPriv->TimerUsers)
1365		TimerCancel(pAPriv->Timer);
1366	}
1367
1368	if (VideoOn > VIDEO_OFF && pGlint->NoAccel)
1369	    Permedia2Sync(pAPriv->pScrn);
1370    }
1371}
1372
1373static Bool
1374StartVideoStream(PortPrivPtr pPPriv, RegionPtr pRegion)
1375{
1376    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1377    GLINTPtr pGlint = GLINTPTR(pAPriv->pScrn);
1378
1379    if (pAPriv->VideoStd < 0)
1380	return FALSE;
1381
1382    pPPriv->StopDelay = -1;
1383
1384    if (pAPriv->pm2p) {
1385	if (pPPriv == &pAPriv->Port[0]) {
1386	    if (!RemakePutCookies(pPPriv, pRegion))
1387		return FALSE;
1388	    if (pPPriv->StreamOn)
1389		return TRUE;
1390	} else {
1391	    if (!RemakeGetCookies(pPPriv, pRegion))
1392		return FALSE;
1393	    if (pPPriv->StreamOn) {
1394		BlackOut(pPPriv, pRegion);
1395		return TRUE;
1396	    }
1397	}
1398
1399	xvipc.a = pPPriv->BuffersRequested;
1400	xvipc.b = !pPPriv->Attribute[4];
1401	xvipc.c = 1 + (pPPriv->Attribute[4] & 2);
1402
1403	if (!xvipcHandshake(pPPriv, OP_START, TRUE))
1404		return FALSE;
1405
1406	if (pPPriv == &pAPriv->Port[1]) {
1407	    pPPriv->BufferBase[0] = xvipc.d;
1408	    BlackOut(pPPriv, pRegion);
1409	}
1410
1411	return pPPriv->StreamOn = TRUE;
1412    } else {
1413	CARD32 Base = (pPPriv == &pAPriv->Port[0]) ? VSABase : VSBBase;
1414
1415        if (pPPriv->BuffersAllocated < pPPriv->BuffersRequested) {
1416	    int height = ((pAPriv->VideoStd == NTSC) ? 512 : 608) >> (!pPPriv->Attribute[4]);
1417
1418    	    if (!AllocateBuffers(pPPriv, 704, height, 2, pPPriv->BuffersRequested, 0))
1419		return FALSE;
1420
1421	    pPPriv->fw = 704;
1422	    pPPriv->fh = InputVideoEncodings[pAPriv->VideoStd * 3].height >>
1423			(!pPPriv->Attribute[4]);
1424	}
1425
1426	if (pPPriv == &pAPriv->Port[0]) {
1427	    if (!RemakePutCookies(pPPriv, pRegion))
1428		return FALSE;
1429	} else {
1430	    if (!RemakeGetCookies(pPPriv, pRegion))
1431		return FALSE;
1432
1433	    BlackOut(pPPriv, pRegion);
1434	}
1435
1436	if (pPPriv->StreamOn)
1437	    return TRUE;
1438
1439	GLINT_WRITE_REG(pPPriv->BufferBase[0] / 8, Base + VSVideoAddress0);
1440	if (pPPriv->pFBArea[1])
1441	    GLINT_WRITE_REG(pPPriv->BufferBase[1] / 8, Base + VSVideoAddress1);
1442	else
1443	    GLINT_WRITE_REG(pPPriv->BufferBase[0] / 8, Base + VSVideoAddress1);
1444	GLINT_WRITE_REG(pPPriv->BufferStride / 8, Base + VSVideoStride);
1445
1446	GLINT_WRITE_REG(0, Base + VSCurrentLine);
1447
1448	if (pAPriv->VideoStd == NTSC) {
1449	    GLINT_WRITE_REG(16, Base + VSVideoStartLine);
1450	    GLINT_WRITE_REG(16 + 240, Base + VSVideoEndLine);
1451	    GLINT_WRITE_REG(288 + (8 & ~3) * 2, Base + VSVideoStartData);
1452	    GLINT_WRITE_REG(288 + ((8 & ~3) + 704) * 2, Base + VSVideoEndData);
1453	} else {
1454	    GLINT_WRITE_REG(16, Base + VSVideoStartLine);
1455	    GLINT_WRITE_REG(16 + 288, Base + VSVideoEndLine);
1456	    GLINT_WRITE_REG(288 + (8 & ~3) * 2, Base + VSVideoStartData);
1457	    GLINT_WRITE_REG(288 + ((8 & ~3) + 704) * 2, Base + VSVideoEndData);
1458	}
1459
1460	GLINT_WRITE_REG(2, Base + VSVideoAddressHost);
1461	GLINT_WRITE_REG(0, Base + VSVideoAddressIndex);
1462
1463	if (pPPriv == &pAPriv->Port[0]) {
1464	    int line, eeek = 0;
1465
1466	    xf86I2CWriteByte(&pAPriv->Port[0].I2CDev, 0x11, 0x0D);
1467
1468	    do {
1469		if (eeek++ > 1000000) break;
1470		line = GLINT_READ_REG(VSABase + VSCurrentLine);
1471	    } while (line > 15);
1472
1473	    GLINT_WRITE_REG(VSA_Video |
1474			    (pPPriv->Attribute[4] ?
1475				VSA_CombineFields : VSA_Discard_FieldTwo),
1476			    VSABase + VSControl);
1477	    if (ColorBars)
1478		if (!pAPriv->Port[1].StreamOn) {
1479		    xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x3A, 0x83);
1480		    xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x61, Enc61[pAPriv->VideoStd]);
1481		}
1482	} else {
1483	    GLINT_WRITE_REG(VSB_Video |
1484			    (pPPriv->Attribute[4] ? VSB_CombineFields : 0) |
1485			  /* VSB_GammaCorrect | */
1486			    (16 << 4) | /* 5:6:5 */
1487			    (1 << 9) | /* 16 */
1488			    VSB_RGBOrder, VSBBase + VSControl);
1489	    xf86I2CWriteByte(&pAPriv->Port[0].I2CDev, 0x11, 0x0D);
1490	    xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x3A, Enc3A[pPPriv->Plug]);
1491	    xf86I2CWriteByte(&pAPriv->Port[1].I2CDev, 0x61, Enc61[pAPriv->VideoStd]);
1492	}
1493
1494	pAPriv->TimerUsers |= 1 << PORTNUM(pPPriv);
1495	TimerSet(pAPriv->Timer, 0, 80, TimerCallback, pAPriv);
1496
1497	return pPPriv->StreamOn = TRUE;
1498    }
1499
1500    return FALSE;
1501}
1502
1503
1504/*
1505 *  Xv interface
1506 */
1507
1508static int
1509Permedia2PutVideo(ScrnInfoPtr pScrn,
1510    short vid_x, short vid_y, short drw_x, short drw_y,
1511    short vid_w, short vid_h, short drw_w, short drw_h,
1512    RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
1513{
1514    PortPrivPtr pPPriv = (PortPrivPtr) data;
1515    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1516    int sw, sh;
1517
1518    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1519	"PutVideo %d,%d,%d,%d -> %d,%d,%d,%d\n",
1520	vid_x, vid_y, vid_w, vid_h, drw_x, drw_y, drw_w, drw_h));
1521
1522    sw = InputVideoEncodings[pAPriv->VideoStd * 3].width;
1523    sh = InputVideoEncodings[pAPriv->VideoStd * 3].height;
1524
1525    if ((vid_x + vid_w) > sw ||
1526        (vid_y + vid_h) > sh)
1527        return BadValue;
1528
1529    pPPriv->VideoOn = VIDEO_OFF;
1530
1531    pPPriv->vx = ((vid_x << 10) * pPPriv->fw) / sw;
1532    pPPriv->vy = ((vid_y << 10) * pPPriv->fh) / sh;
1533    pPPriv->vw = ((vid_w << 10) * pPPriv->fw) / sw;
1534    pPPriv->vh = ((vid_h << 10) * pPPriv->fh) / sh;
1535
1536    pPPriv->dx = drw_x;
1537    pPPriv->dy = drw_y;
1538    pPPriv->dw = drw_w;
1539    pPPriv->dh = drw_h;
1540
1541    pPPriv->FrameAcc = pAPriv->FramesPerSec;
1542
1543    if (!StartVideoStream(pPPriv, clipBoxes))
1544        return XvBadAlloc;
1545
1546    pPPriv->VideoOn = VIDEO_ON;
1547
1548    return Success;
1549}
1550
1551static int
1552Permedia2PutStill(ScrnInfoPtr pScrn,
1553    short vid_x, short vid_y, short drw_x, short drw_y,
1554    short vid_w, short vid_h, short drw_w, short drw_h,
1555    RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
1556{
1557    PortPrivPtr pPPriv = (PortPrivPtr) data;
1558    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1559    GLINTPtr pGlint = GLINTPTR(pScrn);
1560    int sw, sh, r = Success;
1561
1562    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1563	"PutStill %d,%d,%d,%d -> %d,%d,%d,%d\n",
1564	vid_x, vid_y, vid_w, vid_h, drw_x, drw_y, drw_w, drw_h));
1565
1566    sw = InputVideoEncodings[pAPriv->VideoStd * 3].width;
1567    sh = InputVideoEncodings[pAPriv->VideoStd * 3].height;
1568
1569    if ((vid_x + vid_w) > sw ||
1570        (vid_y + vid_h) > sh)
1571        return BadValue;
1572
1573    pPPriv->VideoOn = VIDEO_OFF;
1574
1575    pPPriv->vx = ((vid_x << 10) * pPPriv->fw) / sw;
1576    pPPriv->vy = ((vid_y << 10) * pPPriv->fh) / sh;
1577    pPPriv->vw = ((vid_w << 10) * pPPriv->fw) / sw;
1578    pPPriv->vh = ((vid_h << 10) * pPPriv->fh) / sh;
1579
1580    pPPriv->dx = drw_x;
1581    pPPriv->dy = drw_y;
1582    pPPriv->dw = drw_w;
1583    pPPriv->dh = drw_h;
1584
1585    pPPriv->FrameAcc = pAPriv->FramesPerSec;
1586
1587    if (!StartVideoStream(pPPriv, clipBoxes))
1588        return XvBadAlloc;
1589
1590    if (pAPriv->pm2p) {
1591	/* Sleep, not busy wait, until the very next frame is ready.
1592	   Accept memory requests and other window's update events
1593	   in the meantime. */
1594	for (pPPriv->VideoOn = VIDEO_ONE_SHOT; pPPriv->VideoOn;)
1595	    if (!xvipcHandshake(pPPriv, OP_UPDATE, TRUE)) {
1596		r = FALSE;
1597		break;
1598	    }
1599    } else {
1600        usleep(80000);
1601
1602        PutYUV(pPPriv, (!pPPriv->pFBArea[1]) ?
1603            pPPriv->BufferBase[0] : pPPriv->BufferBase[1 -
1604		GLINT_READ_REG(VSABase + VSVideoAddressIndex)], FORMAT_YUYV, 1, 0);
1605    }
1606
1607    pPPriv->StopDelay = 125;
1608
1609    return r;
1610}
1611
1612static int
1613Permedia2GetVideo(ScrnInfoPtr pScrn,
1614    short vid_x, short vid_y, short drw_x, short drw_y,
1615    short vid_w, short vid_h, short drw_w, short drw_h,
1616    RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
1617{
1618    PortPrivPtr pPPriv = (PortPrivPtr) data;
1619    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1620    int sw, sh;
1621
1622    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1623	"GetVideo %d,%d,%d,%d <- %d,%d,%d,%d\n",
1624	vid_x, vid_y, vid_w, vid_h, drw_x, drw_y, drw_w, drw_h));
1625
1626    sw = InputVideoEncodings[pAPriv->VideoStd * 3].width;
1627    sh = InputVideoEncodings[pAPriv->VideoStd * 3].height;
1628
1629    if ((vid_x + vid_w) > sw ||
1630        (vid_y + vid_h) > sh) {
1631        return BadValue;
1632    }
1633
1634    pPPriv->VideoOn = VIDEO_OFF;
1635
1636    pPPriv->vx = (vid_x * pPPriv->fw) / sw;
1637    pPPriv->vy = (vid_y * pPPriv->fh) / sh;
1638    pPPriv->vw = (vid_w * pPPriv->fw) / sw;
1639    pPPriv->vh = (vid_h * pPPriv->fh) / sh;
1640
1641    pPPriv->dx = drw_x;
1642    pPPriv->dy = drw_y;
1643    pPPriv->dw = drw_w;
1644    pPPriv->dh = drw_h;
1645
1646    pPPriv->FrameAcc = pAPriv->FramesPerSec;
1647
1648    if (!StartVideoStream(pPPriv, clipBoxes)) {
1649        return XvBadAlloc;
1650    }
1651
1652    GetYUV(pPPriv);
1653
1654    pPPriv->VideoOn = VIDEO_ON;
1655
1656    return Success;
1657}
1658
1659static int
1660Permedia2GetStill(ScrnInfoPtr pScrn,
1661    short vid_x, short vid_y, short drw_x, short drw_y,
1662    short vid_w, short vid_h, short drw_w, short drw_h,
1663    RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
1664{
1665    PortPrivPtr pPPriv = (PortPrivPtr) data;
1666    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1667    int sw, sh;
1668
1669    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1670	"GetStill %d,%d,%d,%d <- %d,%d,%d,%d\n",
1671	vid_x, vid_y, vid_w, vid_h, drw_x, drw_y, drw_w, drw_h));
1672
1673    sw = InputVideoEncodings[pAPriv->VideoStd * 3].width;
1674    sh = InputVideoEncodings[pAPriv->VideoStd * 3].height;
1675
1676    if ((vid_x + vid_w) > sw ||
1677        (vid_y + vid_h) > sh)
1678        return BadValue;
1679
1680    pPPriv->VideoOn = VIDEO_OFF;
1681
1682    pPPriv->vx = (vid_x * pPPriv->fw) / sw;
1683    pPPriv->vy = (vid_y * pPPriv->fh) / sh;
1684    pPPriv->vw = (vid_w * pPPriv->fw) / sw;
1685    pPPriv->vh = (vid_h * pPPriv->fh) / sh;
1686
1687    pPPriv->dx = drw_x;
1688    pPPriv->dy = drw_y;
1689    pPPriv->dw = drw_w;
1690    pPPriv->dh = drw_h;
1691
1692    pPPriv->FrameAcc = pAPriv->FramesPerSec;
1693
1694    if (!StartVideoStream(pPPriv, clipBoxes))
1695        return XvBadAlloc;
1696
1697    GetYUV(pPPriv);
1698
1699    return Success;
1700}
1701
1702static void
1703CopyYV12LE(CARD8 *Y, CARD32 *dst, int width, int height, int pitch)
1704{
1705    int Y_size = width * height;
1706    CARD8 *V = Y + Y_size;
1707    CARD8 *U = V + (Y_size >> 2);
1708    int pad = (pitch >> 2) - (width >> 1);
1709    int x;
1710
1711    width >>= 1;
1712
1713    for (height >>= 1; height > 0; height--) {
1714	for (x = 0; x < width; Y += 2, x++)
1715	    *dst++ = Y[0] + (U[x] << 8) + (Y[1] << 16) + (V[x] << 24);
1716	dst += pad;
1717	for (x = 0; x < width; Y += 2, x++)
1718	    *dst++ = Y[0] + (U[x] << 8) + (Y[1] << 16) + (V[x] << 24);
1719	dst += pad;
1720	U += width;
1721	V += width;
1722    }
1723}
1724
1725#if X_BYTE_ORDER == X_BIG_ENDIAN
1726
1727static void
1728CopyYV12BE(CARD8 *Y, CARD32 *dst, int width, int height, int pitch)
1729{
1730    int Y_size = width * height;
1731    CARD8 *V = Y + Y_size;
1732    CARD8 *U = V + (Y_size >> 2);
1733    int pad = (pitch >> 2) - (width >> 1);
1734    int x;
1735
1736    width >>= 1;
1737
1738    for (height >>= 1; height > 0; height--) {
1739	for (x = 0; x < width; Y += 2, x++)
1740	    *dst++ = V[x] + (Y[1] << 8) + (U[x] << 16) + (Y[0] << 24);
1741	dst += pad;
1742	for (x = 0; x < width; Y += 2, x++)
1743	    *dst++ = V[x] + (Y[1] << 8) + (U[x] << 16) + (Y[0] << 24);
1744	dst += pad;
1745	U += width;
1746	V += width;
1747    }
1748}
1749
1750#endif /* X_BYTE_ORDER == X_BIG_ENDIAN */
1751
1752static void
1753CopyFlat(CARD8 *src, CARD8 *dst, int width, int height, int pitch)
1754{
1755    if (width == pitch) {
1756	memcpy(dst, src, width * height);
1757	return;
1758    }
1759
1760    while (height > 0) {
1761	memcpy(dst, src, width);
1762	dst += pitch;
1763	src += width;
1764	height--;
1765    }
1766}
1767
1768static int
1769Permedia2PutImage(ScrnInfoPtr pScrn,
1770    short src_x, short src_y, short drw_x, short drw_y,
1771    short src_w, short src_h, short drw_w, short drw_h,
1772    int id, unsigned char *buf, short width, short height,
1773    Bool sync, RegionPtr clipBoxes, pointer data,
1774    DrawablePtr pDraw)
1775{
1776    PortPrivPtr pPPriv = (PortPrivPtr) data;
1777    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1778    GLINTPtr pGlint = GLINTPTR(pScrn);
1779    int i;
1780
1781    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1782	"PutImage %d,%d,%d,%d -> %d,%d,%d,%d id=0x%08x buf=%p w=%d h=%d sync=%d\n",
1783	src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w, drw_h,
1784	id, buf, width, height, sync));
1785
1786    if ((src_x + src_w) > width ||
1787        (src_y + src_h) > height)
1788        return BadValue;
1789
1790    pPPriv->vx = src_x << 10;
1791    pPPriv->vy = src_y << 10;
1792    pPPriv->vw = src_w << 10;
1793    pPPriv->vh = src_h << 10;
1794
1795    pPPriv->dx = drw_x;
1796    pPPriv->dy = drw_y;
1797    pPPriv->dw = drw_w;
1798    pPPriv->dh = drw_h;
1799
1800    if (!RemakePutCookies(pPPriv, clipBoxes))
1801	return XvBadAlloc;
1802
1803    if (pPPriv->BuffersAllocated <= 0 ||
1804	id != pPPriv->Id || /* same bpp */
1805	width != pPPriv->fw ||
1806	height != pPPriv->fh)
1807    {
1808	for (i = 0; i < ENTRIES(ScalerImages); i++)
1809	    if (id == ScalerImages[i].id)
1810		break;
1811
1812	if (i >= ENTRIES(ScalerImages))
1813	    return XvBadAlloc;
1814#if 0
1815	if (pPPriv->BuffersAllocated <= 0 ||
1816	    pPPriv->Bpp != ScalerImages[i].bits_per_pixel ||
1817	    width > pPPriv->fw || height > pPPriv->fw ||
1818	    pPPriv->fw * pPPriv->fh > width * height * 2)
1819#else
1820	if (1)
1821#endif
1822	{
1823	    Permedia2Sync(pScrn);
1824
1825	    if (!AllocateBuffers(pPPriv, width, height,
1826		(ScalerImages[i].bits_per_pixel + 7) >> 3, 1, 0)) {
1827		pPPriv->Id = 0;
1828		pPPriv->Bpp = 0;
1829		pPPriv->fw = 0;
1830		pPPriv->fh = 0;
1831
1832		return XvBadAlloc;
1833	    }
1834
1835	    pPPriv->Id = id;
1836	    pPPriv->Bpp = ScalerImages[i].bits_per_pixel;
1837	    pPPriv->fw = width;
1838	    pPPriv->fh = height;
1839
1840	    RemoveableBuffers(pPPriv, TRUE);
1841	} else
1842	    Permedia2Sync(pScrn);
1843    } else
1844	Permedia2Sync(pScrn);
1845
1846    switch (id) {
1847    case LE4CC('Y','V','1','2'):
1848#if X_BYTE_ORDER == X_LITTLE_ENDIAN
1849	CopyYV12LE(buf, (CARD32 *)((CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0]),
1850	    width, height, pPPriv->BufferStride);
1851#else
1852	if (pGlint->FBDev)
1853	    CopyYV12LE(buf, (CARD32 *)((CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0]),
1854		width, height, pPPriv->BufferStride);
1855	else
1856	    CopyYV12BE(buf, (CARD32 *)((CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0]),
1857		width, height, pPPriv->BufferStride);
1858#endif
1859	PutYUV(pPPriv, pPPriv->BufferBase[0], FORMAT_YUYV, 1, 0);
1860	break;
1861
1862    case LE4CC('Y','U','Y','2'):
1863	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1864	    width << 1, height, pPPriv->BufferStride);
1865	PutYUV(pPPriv, pPPriv->BufferBase[0], FORMAT_YUYV, 1, 0);
1866	break;
1867
1868    case LE4CC('U','Y','V','Y'):
1869	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1870	    width << 1, height, pPPriv->BufferStride);
1871	PutYUV(pPPriv, pPPriv->BufferBase[0], FORMAT_UYVY, 1, 0);
1872	break;
1873
1874    case LE4CC('Y','U','V','A'):
1875	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1876	    width << 2, height, pPPriv->BufferStride);
1877	PutYUV(pPPriv, pPPriv->BufferBase[0], FORMAT_YUVA, 2, pPPriv->Attribute[7]);
1878	break;
1879
1880    case LE4CC('V','U','Y','A'):
1881	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1882	    width << 2, height, pPPriv->BufferStride);
1883	PutYUV(pPPriv, pPPriv->BufferBase[0], FORMAT_VUYA, 2, pPPriv->Attribute[7]);
1884	break;
1885
1886    case 0x41: /* RGBA 8:8:8:8 */
1887	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1888	    width << 2, height, pPPriv->BufferStride);
1889	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_RGB8888, 2, pPPriv->Attribute[7]);
1890	break;
1891
1892    case 0x42: /* RGB 5:6:5 */
1893	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1894	    width << 1, height, pPPriv->BufferStride);
1895	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_RGB565, 1, 0);
1896	break;
1897
1898    case 0x43: /* RGB 1:5:5:5 */
1899	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1900	    width << 1, height, pPPriv->BufferStride);
1901	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_RGB5551, 1, pPPriv->Attribute[7]);
1902	break;
1903
1904    case 0x44: /* RGB 4:4:4:4 */
1905	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1906	    width << 1, height, pPPriv->BufferStride);
1907	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_RGB4444, 1, pPPriv->Attribute[7]);
1908	break;
1909
1910    case 0x45: /* RGB 1:2:3:2 */
1911	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1912	    width, height, pPPriv->BufferStride);
1913	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_RGB2321, 0, pPPriv->Attribute[7]);
1914	break;
1915
1916    case 0x46: /* RGB 2:3:3 */
1917	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1918	    width, height, pPPriv->BufferStride);
1919	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_RGB332, 0, 0);
1920	break;
1921
1922    case 0x47: /* BGRA 8:8:8:8 */
1923	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1924	    width << 2, height, pPPriv->BufferStride);
1925	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_BGR8888, 2, pPPriv->Attribute[7]);
1926	break;
1927
1928    case 0x48: /* BGR 5:6:5 */
1929	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1930	    width << 1, height, pPPriv->BufferStride);
1931	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_BGR565, 1, 0);
1932	break;
1933
1934    case 0x49: /* BGR 1:5:5:5 */
1935	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1936	    width << 1, height, pPPriv->BufferStride);
1937	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_BGR5551, 1, pPPriv->Attribute[7]);
1938	break;
1939
1940    case 0x4A: /* BGR 4:4:4:4 */
1941	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1942	    width << 1, height, pPPriv->BufferStride);
1943	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_BGR4444, 1, pPPriv->Attribute[7]);
1944	break;
1945
1946    case 0x4B: /* BGR 1:2:3:2 */
1947	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1948	    width << 0, height, pPPriv->BufferStride);
1949	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_BGR2321, 0, pPPriv->Attribute[7]);
1950	break;
1951
1952    case 0x4C: /* BGR 2:3:3 */
1953	CopyFlat(buf, (CARD8 *) pGlint->FbBase + pPPriv->BufferBase[0],
1954	    width << 0, height, pPPriv->BufferStride);
1955	PutRGB(pPPriv, pPPriv->BufferBase[0], FORMAT_BGR332, 0, 0);
1956	break;
1957
1958    default:
1959	return XvBadAlloc;
1960    }
1961
1962    pPPriv->StopDelay = pAPriv->Delay;
1963
1964    if (!pAPriv->TimerUsers) {
1965	pAPriv->TimerUsers |= 1 << PORTNUM(pPPriv);
1966	TimerSet(pAPriv->Timer, 0, 80, TimerCallback, pAPriv);
1967    }
1968
1969    if (sync) /* sched_yield? */
1970	Permedia2Sync(pScrn);
1971
1972    return Success;
1973}
1974
1975static void
1976Permedia2StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
1977{
1978    PortPrivPtr pPPriv = (PortPrivPtr) data;
1979    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
1980    GLINTPtr pGlint = GLINTPTR(pScrn);
1981
1982    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
1983	"StopVideo port=%d, shutdown=%d\n", PORTNUM(pPPriv), shutdown));
1984
1985    if (shutdown) {
1986	if (PORTNUM(pPPriv) < 2) {
1987	    StopVideoStream(pPPriv, TRUE);
1988	    RestoreVideoStd(pAPriv);
1989	} else {
1990	    FreeBuffers(pPPriv);
1991	    FreeCookies(pPPriv);
1992	    if (pAPriv->TimerUsers) {
1993		pAPriv->TimerUsers &= ~PORTNUM(pPPriv);
1994		if (!pAPriv->TimerUsers)
1995		    TimerCancel(pAPriv->Timer);
1996	    }
1997	}
1998    } else {
1999	pPPriv->VideoOn = VIDEO_OFF;
2000	pPPriv->StopDelay = 750; /* appx. 30 sec */
2001
2002	if (pGlint->NoAccel)
2003	    Permedia2Sync(pScrn);
2004    }
2005}
2006
2007static void
2008RestartVideo(PortPrivPtr pPPriv, int old_VideoOn)
2009{
2010    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
2011    int new_fh;
2012
2013    if (pPPriv->VideoOn > VIDEO_OFF ||
2014	pAPriv->VideoStd < 0 /* invalid */)
2015	return;
2016
2017    new_fh = InputVideoEncodings[pAPriv->VideoStd * 3].height >>
2018	(1 - (pPPriv->Attribute[4] & 1));
2019
2020    if (new_fh != pPPriv->fh) {
2021	pPPriv->vy = (pPPriv->vy * new_fh) / pPPriv->fh;
2022	pPPriv->vh = (pPPriv->vh * new_fh) / pPPriv->fh;
2023
2024	pPPriv->fh = new_fh;
2025    }
2026
2027    if (old_VideoOn) {
2028	if (StartVideoStream(pPPriv, NULL)) {
2029	    pPPriv->VideoOn = old_VideoOn;
2030
2031	    if (pPPriv == &pAPriv->Port[1])
2032		GetYUV(pPPriv);
2033	} else {
2034	    DEBUG(xf86DrvMsgVerb(pAPriv->pScrn->scrnIndex, X_INFO, 4,
2035		"RestartVideo port=%d suspend\n", PORTNUM(pPPriv)));
2036	    pPPriv->VideoOn = -old_VideoOn; /* suspend (not off) */
2037	}
2038    }
2039}
2040
2041static int
2042Permedia2SetPortAttribute(ScrnInfoPtr pScrn,
2043    Atom attribute, INT32 value, pointer data)
2044{
2045    PortPrivPtr pPPriv = (PortPrivPtr) data;
2046    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
2047    int old_VideoStd, old_Plug;
2048    int VideoStd = -1, Plug = 0;
2049    int r;
2050
2051    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
2052	"SPA attr=%d val=%d port=%d\n",
2053	attribute, value, PORTNUM(pPPriv)));
2054
2055    if (attribute == xvFilter) {
2056	pPPriv->Attribute[5] = !!value;
2057	return Success;
2058    } else if (attribute == xvAlpha) {
2059	pPPriv->Attribute[7] = !!value;
2060	return Success;
2061    }
2062
2063    if (PORTNUM(pPPriv) >= 2)
2064	return BadMatch;
2065
2066    if (attribute == xvInterlace) {
2067	int old_value = pPPriv->Attribute[4];
2068
2069	value %= 3;
2070
2071	if (value != old_value) {
2072	    int old_VideoOn = ABS(pPPriv->VideoOn);
2073#if 0
2074	    if (old_VideoOn)
2075		return XvBadAlloc;
2076#endif
2077	    StopVideoStream(pPPriv, FALSE);
2078	    FreeBuffers(pPPriv);
2079	    pPPriv->Attribute[4] = value;
2080	    RestartVideo(pPPriv, old_VideoOn);
2081
2082	    if (pPPriv->VideoOn < 0 /* suspended */) {
2083		pPPriv->Attribute[4] = old_value;
2084		RestartVideo(pPPriv, old_VideoOn);
2085		return XvBadAlloc;
2086	    }
2087	}
2088
2089	return Success;
2090    }
2091
2092    if (pPPriv == &pAPriv->Port[0]) {
2093	/*
2094	 *  Input
2095	 */
2096	if (attribute == xvEncoding) {
2097	    if (value < 0 || value > ENTRIES(InputVideoEncodings))
2098		return XvBadEncoding;
2099
2100	    VideoStd = value / 3;
2101	    Plug = value % 3;
2102
2103	    /* Fall through */
2104
2105	} else if (attribute == xvBrightness)
2106	    return SetAttr(&pAPriv->Port[0], 0, value);
2107	else if (attribute == xvContrast)
2108	    return SetAttr(&pAPriv->Port[0], 1, value);
2109   	else if (attribute == xvSaturation)
2110	    return SetAttr(&pAPriv->Port[0], 2, value);
2111	else if (attribute == xvHue)
2112	    return SetAttr(&pAPriv->Port[0], 3, value);
2113    } else {
2114	/*
2115	 *  Output
2116	 */
2117	if (attribute == xvEncoding) {
2118	    if (value < 0 || value > ENTRIES(OutputVideoEncodings))
2119		return XvBadEncoding;
2120
2121	    VideoStd = value / 2;
2122	    Plug = (value % 2) + 1;
2123
2124	    /* Fall through */
2125
2126	} else if (attribute == xvBkgColor)
2127	    return SetBkgCol(pPPriv, value);
2128#if 1
2129	else if (attribute == xvBrightness ||
2130		 attribute == xvContrast ||
2131		 attribute == xvSaturation ||
2132		 attribute == xvHue)
2133	    return Success;
2134#endif
2135    }
2136
2137    if (attribute != xvEncoding)
2138	return BadMatch;
2139
2140    old_VideoStd = pAPriv->VideoStd;
2141    old_Plug = pPPriv->Plug;
2142
2143#if 0
2144    if (pAPriv->Port[0].VideoOn ||
2145	pAPriv->Port[1].VideoOn)
2146	return XvBadAlloc;
2147#endif
2148
2149    if (Plug != old_Plug)
2150	if ((r = SetPlug(pPPriv, Plug)) != Success)
2151	    return r;
2152
2153    if (VideoStd != old_VideoStd) {
2154	int old_VideoOn0 = ABS(pAPriv->Port[0].VideoOn);
2155	int old_VideoOn1 = ABS(pAPriv->Port[1].VideoOn);
2156
2157	StopVideoStream(&pAPriv->Port[0], FALSE);
2158	StopVideoStream(&pAPriv->Port[1], FALSE);
2159
2160	if (VideoStd == NTSC || pAPriv->VideoStd == NTSC) {
2161	    FreeBuffers(&pAPriv->Port[0]);
2162	    FreeBuffers(&pAPriv->Port[1]);
2163	}
2164
2165	if (SetVideoStd(pPPriv, VideoStd) == Success) {
2166	    RestartVideo(&pAPriv->Port[0], old_VideoOn0);
2167	    RestartVideo(&pAPriv->Port[1], old_VideoOn1);
2168	}
2169
2170	if (pAPriv->Port[0].VideoOn < 0 ||
2171	    pAPriv->Port[1].VideoOn < 0 ||
2172	    VideoStd != pAPriv->VideoStd) {
2173	    if (SetVideoStd(pPPriv, old_VideoStd) == Success) {
2174		RestartVideo(&pAPriv->Port[0], old_VideoOn0);
2175		RestartVideo(&pAPriv->Port[1], old_VideoOn1);
2176	    }
2177
2178	    if (Plug != old_Plug)
2179		SetPlug(pPPriv, old_Plug);
2180
2181	    return XvBadAlloc;
2182	}
2183    }
2184
2185    return Success;
2186}
2187
2188static void
2189RestoreVideoStd(AdaptorPrivPtr pAPriv)
2190{
2191    if (pAPriv->Port[0].VideoOn && !pAPriv->Port[1].VideoOn &&
2192	pAPriv->Port[0].VideoStdReq != pAPriv->VideoStd)
2193	Permedia2SetPortAttribute(pAPriv->pScrn, xvEncoding,
2194	    pAPriv->Port[0].VideoStdReq * 3 + pAPriv->Port[0].Plug,
2195	    (pointer) &pAPriv->Port[0]);
2196    else
2197    if (pAPriv->Port[1].VideoOn && !pAPriv->Port[0].VideoOn &&
2198	pAPriv->Port[1].VideoStdReq != pAPriv->VideoStd)
2199	Permedia2SetPortAttribute(pAPriv->pScrn, xvEncoding,
2200	    pAPriv->Port[2].VideoStdReq * 2 + pAPriv->Port[1].Plug - 1,
2201	    (pointer) &pAPriv->Port[1]);
2202}
2203
2204static int
2205Permedia2GetPortAttribute(ScrnInfoPtr pScrn,
2206    Atom attribute, INT32 *value, pointer data)
2207{
2208    PortPrivPtr pPPriv = (PortPrivPtr) data;
2209    AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
2210
2211    if (PORTNUM(pPPriv) >= 2 &&
2212	attribute != xvFilter &&
2213	attribute != xvAlpha)
2214	return BadMatch;
2215
2216    if (attribute == xvEncoding) {
2217	if (pAPriv->VideoStd < 0)
2218	    return XvBadAlloc;
2219	else
2220	    if (pPPriv == &pAPriv->Port[0])
2221		*value = pAPriv->VideoStd * 3 + pPPriv->Plug;
2222	    else
2223		*value = pAPriv->VideoStd * 2 + pPPriv->Plug - 1;
2224    } else if (attribute == xvBrightness)
2225	*value = pPPriv->Attribute[0];
2226    else if (attribute == xvContrast)
2227	*value = pPPriv->Attribute[1];
2228    else if (attribute == xvSaturation)
2229	*value = pPPriv->Attribute[2];
2230    else if (attribute == xvHue)
2231	*value = pPPriv->Attribute[3];
2232    else if (attribute == xvInterlace)
2233	*value = pPPriv->Attribute[4];
2234    else if (attribute == xvFilter)
2235	*value = pPPriv->Attribute[5];
2236    else if (attribute == xvBkgColor)
2237	*value = pPPriv->Attribute[6];
2238    else if (attribute == xvAlpha)
2239	*value = pPPriv->Attribute[7];
2240    else
2241	return BadMatch;
2242
2243    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
2244	"GPA attr=%d val=%d port=%d\n",
2245	attribute, *value, PORTNUM(pPPriv)));
2246
2247    return Success;
2248}
2249
2250static void
2251Permedia2QueryBestSize(ScrnInfoPtr pScrn, Bool motion,
2252    short vid_w, short vid_h, short drw_w, short drw_h,
2253    unsigned int *p_w, unsigned int *p_h, pointer data)
2254{
2255    *p_w = drw_w;
2256    *p_h = drw_h;
2257}
2258
2259static int
2260Permedia2QueryImageAttributes(ScrnInfoPtr pScrn,
2261    int id, unsigned short *width, unsigned short *height,
2262    int *pitches, int *offsets)
2263{
2264    int i, pitch;
2265
2266    *width = CLAMP(*width, 1, 2047);
2267    *height = CLAMP(*height, 1, 2047);
2268
2269    if (offsets)
2270	offsets[0] = 0;
2271
2272    switch (id) {
2273    case LE4CC('Y','V','1','2'): /* Planar YVU 4:2:0 (emulated) */
2274	*width = CLAMP((*width + 1) & ~1, 2, 2046);
2275	*height = CLAMP((*height + 1) & ~1, 2, 2046);
2276
2277	pitch = *width; /* luma component */
2278
2279	if (offsets) {
2280	    offsets[1] = pitch * *height;
2281	    offsets[2] = offsets[1] + (offsets[1] >> 2);
2282	}
2283
2284	if (pitches) {
2285	    pitches[0] = pitch;
2286	    pitches[1] = pitches[2] = pitch >> 1;
2287	}
2288
2289	return pitch * *height * 3 / 2;
2290
2291    case LE4CC('Y','U','Y','2'): /* Packed YUYV 4:2:2 */
2292    case LE4CC('U','Y','V','Y'): /* Packed UYVY 4:2:2 */
2293	*width = CLAMP((*width + 1) & ~1, 2, 2046);
2294
2295	pitch = *width * 2;
2296
2297	if (pitches)
2298	    pitches[0] = pitch;
2299
2300	return pitch * *height;
2301
2302    default:
2303	for (i = 0; i < ENTRIES(ScalerImages); i++)
2304	    if (ScalerImages[i].id == id)
2305		break;
2306
2307	if (i >= ENTRIES(ScalerImages))
2308	    break;
2309
2310	pitch = *width * (ScalerImages[i].bits_per_pixel >> 3);
2311
2312	if (pitches)
2313	    pitches[0] = pitch;
2314
2315	return pitch * *height;
2316    }
2317
2318    return 0;
2319}
2320
2321static void
2322RestoreVideo(AdaptorPrivPtr pAPriv)
2323{
2324    GLINTPtr pGlint = GLINTPTR(pAPriv->pScrn);
2325
2326    GLINT_WRITE_REG(pAPriv->dFifoControl, PMFifoControl);
2327    GLINT_WRITE_REG(0, VSABase + VSControl);
2328    GLINT_WRITE_REG(0, VSBBase + VSControl);
2329    usleep(160000);
2330    GLINT_MASK_WRITE_REG(VS_UnitMode_ROM, ~VS_UnitMode_Mask, VSConfiguration);
2331}
2332
2333static void
2334InitializeVideo(AdaptorPrivPtr pAPriv)
2335{
2336    GLINTPtr pGlint = GLINTPTR(pAPriv->pScrn);
2337    int i;
2338
2339    GLINT_WRITE_REG(0, VSABase + VSControl);
2340    GLINT_WRITE_REG(0, VSBBase + VSControl);
2341
2342#if 0
2343    GLINT_MASK_WRITE_REG(0, ~(VSAIntFlag | VSBIntFlag), IntEnable);
2344    GLINT_WRITE_REG(VSAIntFlag | VSBIntFlag, IntFlags); /* Reset */
2345#endif
2346
2347    for (i = 0x0018; i <= 0x00B0; i += 8) {
2348        GLINT_WRITE_REG(0, VSABase + i);
2349        GLINT_WRITE_REG(0, VSBBase + i);
2350    }
2351
2352    GLINT_WRITE_REG((0 << 8) | (132 << 0), VSABase + VSFifoControl);
2353    GLINT_WRITE_REG((0 << 8) | (132 << 0), VSBBase + VSFifoControl);
2354
2355    GLINT_MASK_WRITE_REG(
2356        VS_UnitMode_AB8 |
2357        VS_GPBusMode_A |
2358     /* VS_HRefPolarityA | */
2359        VS_VRefPolarityA |
2360        VS_VActivePolarityA |
2361     /* VS_UseFieldA | */
2362        VS_FieldPolarityA |
2363     /* VS_FieldEdgeA | */
2364     /* VS_VActiveVBIA | */
2365	VS_InterlaceA |
2366	VS_ReverseDataA |
2367
2368     /* VS_HRefPolarityB | */
2369        VS_VRefPolarityB |
2370        VS_VActivePolarityB |
2371     /* VS_UseFieldB | */
2372        VS_FieldPolarityB |
2373     /* VS_FieldEdgeB | */
2374     /* VS_VActiveVBIB | */
2375        VS_InterlaceB |
2376     /* VS_ColorSpaceB_RGB | */
2377     /* VS_ReverseDataB | */
2378     /* VS_DoubleEdgeB | */
2379        0, ~0x1FFFFE0F, VSConfiguration);
2380
2381    pAPriv->dFifoControl = GLINT_READ_REG(PMFifoControl);
2382    GLINT_WRITE_REG((12 << 8) | 8, PMFifoControl);
2383}
2384
2385static Bool
2386xvipcHandshake(PortPrivPtr pPPriv, int op, Bool block)
2387{
2388    int r;
2389    int brake = 150;
2390
2391    xvipc.magic = XVIPC_MAGIC;
2392    xvipc.op = op;
2393    xvipc.block = block;
2394
2395    if (pPPriv) {
2396	AdaptorPrivPtr pAPriv = pPPriv->pAdaptor;
2397
2398	xvipc.pm2p = pAPriv->pm2p;
2399	xvipc.pAPriv = pAPriv;
2400	xvipc.port = PORTNUM(pPPriv);
2401    } else {
2402	xvipc.pm2p = (void *) -1;
2403	xvipc.pAPriv = NULL;
2404	xvipc.port = -1;
2405    }
2406
2407    for (;;) {
2408	if (brake-- <= 0)
2409	    return FALSE; /* I brake for bugs. */
2410
2411	DEBUG(xf86MsgVerb(X_INFO, 4,
2412	    "PM2 XVIPC send op=%d bl=%d po=%d a=%d b=%d c=%d\n",
2413	    xvipc.op, xvipc.block, xvipc.port, xvipc.a, xvipc.b, xvipc.c));
2414
2415	r = ioctl(xvipc_fd, VIDIOC_PM2_XVIPC, (void *) &xvipc);
2416
2417	DEBUG(xf86MsgVerb(X_INFO, 4,
2418	    "PM2 XVIPC recv op=%d bl=%d po=%d a=%d b=%d c=%d err=%d/%d\n",
2419	    xvipc.op, xvipc.block, xvipc.port, xvipc.a, xvipc.b, xvipc.c, r, errno));
2420
2421	switch (xvipc.op) {
2422	case OP_ALLOC:
2423	{
2424	    AdaptorPrivPtr pAPriv = xvipc.pAPriv;
2425	    ScrnInfoPtr pScrn = pAPriv->pScrn;
2426	    GLINTPtr pGlint = GLINTPTR(pScrn);
2427	    FBAreaPtr pFBArea = NULL;
2428	    LFBAreaPtr pLFBArea;
2429
2430	    xvipc.a = -1;
2431
2432	    pLFBArea = xalloc(sizeof(LFBAreaRec));
2433
2434	    if (pLFBArea) {
2435		pLFBArea->pFBArea = pFBArea =
2436		    xf86AllocateLinearOffscreenArea(pScrn->pScreen,
2437		        xvipc.b >> BPPSHIFT(pGlint), 2, NULL, NULL, NULL);
2438
2439		if (pFBArea) {
2440		    /* xvipc.a = pFBArea->linear; */
2441		    pLFBArea->Linear = xvipc.a =
2442			((pFBArea->box.y1 * pScrn->displayWidth) +
2443			    pFBArea->box.x1) << BPPSHIFT(pGlint);
2444		} else
2445		    xfree(pLFBArea);
2446	    }
2447
2448	    /* Report results */
2449
2450	    if (ioctl(xvipc_fd, VIDIOC_PM2_XVIPC, (void *) &xvipc) != 0)
2451		if (pFBArea) {
2452		    xf86FreeOffscreenArea(pFBArea);
2453		    xfree(pLFBArea);
2454		    pFBArea = NULL;
2455		}
2456
2457	    if (pFBArea) {
2458		pLFBArea->Next = pAPriv->LFBList;
2459		pAPriv->LFBList = pLFBArea;
2460	    }
2461
2462	    DEBUG(xf86MsgVerb(X_INFO, 3, "PM2 XVIPC alloc addr=%d=0x%08x pFB=%p\n",
2463		xvipc.a, xvipc.a, pFBArea));
2464
2465	    goto event;
2466	}
2467
2468	case OP_FREE:
2469	{
2470	    AdaptorPrivPtr pAPriv = xvipc.pAPriv;
2471	    LFBAreaPtr pLFBArea, *ppLFBArea;
2472
2473	    for (ppLFBArea = &pAPriv->LFBList; (pLFBArea = *ppLFBArea);
2474		ppLFBArea = &pLFBArea->Next)
2475		if (pLFBArea->Linear == xvipc.a)
2476		    break;
2477
2478	    if (!pLFBArea)
2479		xvipc.a = -1;
2480
2481	    DEBUG(xf86MsgVerb(X_INFO, 3, "PM2 XVIPC free addr=%d=0x%08x pFB=%p\n",
2482		xvipc.a, xvipc.a, pLFBArea ? pLFBArea->pFBArea : NULL));
2483
2484	    if (ioctl(xvipc_fd, VIDIOC_PM2_XVIPC, (void *) &xvipc) == 0 && pLFBArea) {
2485		xf86FreeOffscreenArea(pLFBArea->pFBArea);
2486		*ppLFBArea = pLFBArea->Next;
2487		xfree(pLFBArea);
2488	    }
2489
2490	    goto event;
2491	}
2492
2493	case OP_UPDATE:
2494	{
2495	    AdaptorPrivPtr pAPriv = xvipc.pAPriv;
2496	    PortPrivPtr pPPriv;
2497
2498	    pPPriv = &pAPriv->Port[0];
2499
2500	    if (pPPriv->VideoOn > VIDEO_OFF && xvipc.a > 0) {
2501	        pPPriv->FrameAcc += pPPriv->FramesPerSec;
2502	        if (pPPriv->FrameAcc >= pAPriv->FramesPerSec) {
2503		    pPPriv->FrameAcc -= pAPriv->FramesPerSec;
2504
2505		    /* Asynchronous resizing caused by kernel app */
2506
2507		    if (xvipc.c != pPPriv->fw ||
2508		        xvipc.d != pPPriv->fh) {
2509			pPPriv->vx = (pPPriv->vx * xvipc.c) / pPPriv->fw;
2510			pPPriv->vw = (pPPriv->vw * xvipc.c) / pPPriv->fw;
2511			pPPriv->vy = (pPPriv->vy * xvipc.d) / pPPriv->fh;
2512			pPPriv->vh = (pPPriv->vh * xvipc.d) / pPPriv->fh;
2513
2514			pPPriv->fw = xvipc.c;
2515			pPPriv->fh = xvipc.d;
2516			pPPriv->BufferPProd = xvipc.e;
2517
2518			RemakePutCookies(pPPriv, NULL);
2519		    }
2520
2521		    PutYUV(pPPriv, xvipc.a, FORMAT_YUYV, 1, 0);
2522
2523		    if (pPPriv->VideoOn == VIDEO_ONE_SHOT)
2524			pPPriv->VideoOn = VIDEO_OFF;
2525		}
2526	    } else
2527		if (pPPriv->StopDelay >= 0 && !(pPPriv->StopDelay--)) {
2528		    StopVideoStream(pPPriv, TRUE);
2529		    RestoreVideoStd(pAPriv);
2530		}
2531
2532	    pPPriv = &pAPriv->Port[1];
2533
2534	    if (pPPriv->VideoOn > VIDEO_OFF && xvipc.b > 0) {
2535	        pPPriv->FrameAcc += pPPriv->FramesPerSec;
2536		if (pPPriv->FrameAcc >= pAPriv->FramesPerSec) {
2537		    pPPriv->FrameAcc -= pAPriv->FramesPerSec;
2538
2539		    pPPriv->BufferBase[0] = xvipc.b;
2540
2541		    /* Output is always exclusive, no async resizing */
2542
2543		    GetYUV(pPPriv);
2544
2545		    if (pPPriv->VideoOn == VIDEO_ONE_SHOT)
2546			pPPriv->VideoOn = VIDEO_OFF;
2547		}
2548	    } else
2549		if (pPPriv->StopDelay >= 0 && !(pPPriv->StopDelay--)) {
2550		    StopVideoStream(pPPriv, TRUE);
2551		    RestoreVideoStd(pAPriv);
2552		}
2553
2554	    /* Fall through */
2555	}
2556
2557	default:
2558	event:
2559	    if (xvipc.op == op)
2560		return r == 0;
2561
2562	    xvipc.op = OP_EVENT;
2563	    xvipc.block = block;
2564	}
2565    }
2566
2567    return TRUE;
2568}
2569
2570static void
2571Permedia2ReadInput(int fd, pointer unused)
2572{
2573    xvipcHandshake(NULL, OP_EVENT, FALSE);
2574}
2575
2576static Bool
2577xvipcOpen(char *name, ScrnInfoPtr pScrn)
2578{
2579    const char *osname;
2580
2581    if (xvipc_fd >= 0)
2582	return TRUE;
2583
2584    xf86GetOS(&osname, NULL, NULL, NULL);
2585
2586    if (!osname || strcmp(osname, "linux"))
2587	return FALSE;
2588
2589    for (;;) {
2590	DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2,
2591	    "XVIPC probing device %s\n", name));
2592
2593    	if ((xvipc_fd = open(name, O_RDWR /* | O_TRUNC */, 0)) < 0)
2594	    break;
2595
2596	xvipc.magic = XVIPC_MAGIC;
2597	xvipc.pm2p = (void *) -1;
2598	xvipc.pAPriv = NULL;
2599	xvipc.op = OP_CONNECT;
2600	xvipc.a = 0;
2601	xvipc.b = 0;
2602	xvipc.c = 0;
2603	xvipc.d = 0;
2604
2605	if (ioctl(xvipc_fd, VIDIOC_PM2_XVIPC, (void *) &xvipc) < 0 || xvipc.pm2p)
2606	    break;
2607
2608	if (xvipc.c != XVIPC_VERSION) {
2609	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2610		       "Your Permedia 2 kernel driver %d.%d uses XVIPC protocol "
2611		       "V.%d while this Xv driver expects V.%d. Please update.\n",
2612		       xvipc.a, xvipc.b, xvipc.c, XVIPC_VERSION);
2613	    break;
2614	}
2615
2616	xf86AddInputHandler(xvipc_fd, Permedia2ReadInput, NULL);
2617
2618	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv driver opened %s\n", name);
2619
2620	return TRUE;
2621    }
2622
2623    if (xvipc_fd >= 0)
2624	close(xvipc_fd);
2625
2626    xvipc_fd = -1;
2627
2628    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Cannot find Permedia 2 kernel driver.\n");
2629
2630    return FALSE;
2631}
2632
2633static void
2634DeleteAdaptorPriv(AdaptorPrivPtr pAPriv)
2635{
2636    int i;
2637
2638    if (pAPriv->VideoIO) {
2639	StopVideoStream(&pAPriv->Port[0], TRUE);
2640	StopVideoStream(&pAPriv->Port[1], TRUE);
2641    }
2642
2643    for (i = 0; i < 6; i++) {
2644        FreeBuffers(&pAPriv->Port[i]);
2645	FreeCookies(&pAPriv->Port[i]);
2646    }
2647
2648    TimerFree(pAPriv->Timer);
2649
2650    if (pAPriv->VideoIO) {
2651	if (pAPriv->pm2p)
2652	    xvipcHandshake(&pAPriv->Port[0], OP_DISCONNECT, TRUE);
2653	else {
2654	    xf86DestroyI2CDevRec(&pAPriv->Port[0].I2CDev, FALSE);
2655	    xf86DestroyI2CDevRec(&pAPriv->Port[1].I2CDev, FALSE);
2656
2657	    RestoreVideo(pAPriv);
2658	}
2659    }
2660
2661    xfree(pAPriv);
2662}
2663
2664static AdaptorPrivPtr
2665NewAdaptorPriv(ScrnInfoPtr pScrn, Bool VideoIO)
2666{
2667    GLINTPtr pGlint = GLINTPTR(pScrn);
2668    AdaptorPrivPtr pAPriv = (AdaptorPrivPtr) xcalloc(1, sizeof(AdaptorPrivRec));
2669    int i;
2670
2671    if (!pAPriv)
2672	return NULL;
2673
2674    pAPriv->pScrn = pScrn;
2675
2676    for (i = 0; i < PORTS; i++)
2677	pAPriv->Port[i].pAdaptor = pAPriv;
2678
2679    switch (pScrn->depth) {
2680    case 8:
2681        pAPriv->dDitherMode =
2682	    (0 << 10) |			/* BGR */
2683	    (1 << 1) |			/* Dither */
2684	    ((5 & 0x10) << 12) |
2685	    ((5 & 0x0F) << 2) |		/* 3:3:2f */
2686	    UNIT_ENABLE;
2687        pAPriv->dAlphaBlendMode =
2688	    (0 << 13) |
2689	    ((5 & 0x10) << 12) |
2690	    ((5 & 0x0F) << 8) |
2691	    (84 << 1) |			/* Blend (decal) RGB */
2692	    UNIT_ENABLE;
2693	pAPriv->dTextureDataFormat =
2694	    (1 << 4) |			/* No alpha */
2695	    ((14 & 0x10) << 2) |
2696	    ((14 & 0x0F) << 0);		/* CI8 */
2697	break;
2698
2699    case 15:
2700        pAPriv->dDitherMode =
2701	    (1 << 10) |			/* RGB */
2702	    ((1 & 0x10) << 12) |
2703	    ((1 & 0x0F) << 2) |		/* 5:5:5:1f */
2704	    UNIT_ENABLE;
2705        pAPriv->dAlphaBlendMode =
2706	    (1 << 13) |
2707	    ((1 & 0x10) << 12) |
2708	    ((1 & 0x0F) << 8) |
2709	    (84 << 1) |
2710	    UNIT_ENABLE;
2711	pAPriv->dTextureDataFormat =
2712    	    (1 << 5) |			/* RGB */
2713	    (1 << 4) |
2714	    ((1 & 0x10) << 2) |
2715	    ((1 & 0x0F) << 0);
2716	break;
2717
2718    case 16:
2719        pAPriv->dDitherMode =
2720	    (1 << 10) |			/* RGB */
2721	    ((16 & 0x10) << 12) |
2722	    ((16 & 0x0F) << 2) |	/* 5:6:5f */
2723	    UNIT_ENABLE;
2724        pAPriv->dAlphaBlendMode =
2725	    (1 << 13) |
2726	    ((16 & 0x10) << 12) |
2727	    ((16 & 0x0F) << 8) |
2728	    (84 << 1) |
2729	    UNIT_ENABLE;
2730	pAPriv->dTextureDataFormat =
2731	    (1 << 5) |
2732	    (1 << 4) |
2733	    ((16 & 0x10) << 2) |
2734	    ((16 & 0x0F) << 0);
2735	break;
2736
2737    case 24:
2738        pAPriv->dDitherMode =
2739	    (1 << 10) |			/* RGB */
2740	    ((0 & 0x10) << 12) |
2741	    ((0 & 0x0F) << 2) |		/* 8:8:8:8 */
2742	    UNIT_ENABLE;
2743        pAPriv->dAlphaBlendMode =
2744	    (1 << 13) |
2745	    ((0 & 0x10) << 12) |
2746	    ((0 & 0x0F) << 8) |
2747	    (84 << 1) |
2748	    UNIT_ENABLE;
2749	pAPriv->dTextureDataFormat =
2750	    (1 << 5) |
2751	    (1 << 4) |
2752	    ((0 & 0x10) << 2) |
2753	    ((0 & 0x0F) << 0);
2754	break;
2755
2756    default:
2757	xfree(pAPriv);
2758	return NULL;
2759    }
2760
2761    pAPriv->VideoIO = VideoIO;
2762
2763    if (VideoIO) {
2764	if (xvipc_fd >= 0) {
2765	    /* Initial handshake, take over control of this head */
2766
2767	    xvipc.magic = XVIPC_MAGIC;
2768	    xvipc.pm2p = (void *) -1;		/* Kernel head ID */
2769	    xvipc.pAPriv = pAPriv;		/* Server head ID */
2770	    xvipc.op = OP_CONNECT;
2771
2772	    xvipc.a = PCI_DEV_BUS(pGlint->PciInfo);
2773	    xvipc.b = PCI_DEV_DEV(pGlint->PciInfo);
2774	    xvipc.c = PCI_DEV_FUNC(pGlint->PciInfo);
2775
2776	    xvipc.d = pScrn->videoRam << 10;	/* XF86Config overrides probing */
2777
2778	    if (ioctl(xvipc_fd, VIDIOC_PM2_XVIPC, (void *) &xvipc) < 0) {
2779		if (errno == EBUSY)
2780		    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2781			       "Another application already opened the Permedia 2 "
2782			       "kernel driver for this board. To enable "
2783			       "shared access please start the server first.\n");
2784		else
2785		    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2786			       "Failed to initialize kernel backbone "
2787			       "due to error %d: %s.\n", errno, strerror(errno));
2788		goto failed;
2789	    }
2790
2791	    pAPriv->pm2p = xvipc.pm2p;
2792	} else {
2793	    InitializeVideo(pAPriv);
2794
2795	    if (!xf86I2CProbeAddress(pGlint->VSBus, SAA7111_SLAVE_ADDRESS))
2796    		goto failed;
2797
2798	    pAPriv->Port[0].I2CDev.DevName = "Decoder SAA 7111A";
2799    	    pAPriv->Port[0].I2CDev.SlaveAddr = SAA7111_SLAVE_ADDRESS;
2800	    pAPriv->Port[0].I2CDev.pI2CBus = pGlint->VSBus;
2801
2802	    if (!xf86I2CDevInit(&pAPriv->Port[0].I2CDev))
2803		goto failed;
2804
2805	    if (!xf86I2CWriteVec(&pAPriv->Port[0].I2CDev, DecInitVec, ENTRIES(DecInitVec) / 2))
2806		goto failed;
2807
2808	    if (!xf86I2CProbeAddress(pGlint->VSBus, SAA7125_SLAVE_ADDRESS))
2809		goto failed;
2810
2811	    pAPriv->Port[1].I2CDev.DevName = "Encoder SAA 7125";
2812	    pAPriv->Port[1].I2CDev.SlaveAddr = SAA7125_SLAVE_ADDRESS;
2813    	    pAPriv->Port[1].I2CDev.pI2CBus = pGlint->VSBus;
2814
2815	    if (!xf86I2CDevInit(&pAPriv->Port[1].I2CDev))
2816		goto failed;
2817
2818	    if (!xf86I2CWriteVec(&pAPriv->Port[1].I2CDev, EncInitVec, ENTRIES(EncInitVec) / 2))
2819		goto failed;
2820	}
2821
2822	if (SetVideoStd(&pAPriv->Port[0], PAL) != Success ||
2823	    SetPlug(&pAPriv->Port[0], 0) != Success ||  /* composite */
2824	    SetPlug(&pAPriv->Port[1], 1) != Success)    /* composite-adaptor */
2825	    goto failed;
2826
2827	pAPriv->Port[1].VideoStdReq = pAPriv->Port[0].VideoStdReq;
2828
2829	pAPriv->Port[0].BuffersRequested = 2;
2830	pAPriv->Port[1].BuffersRequested = 1;
2831
2832	for (i = 0; i < 2; i++) {
2833    	    pAPriv->Port[i].fw = 704;
2834    	    pAPriv->Port[i].fh = 576;
2835    	    pAPriv->Port[i].FramesPerSec = 30;
2836    	    pAPriv->Port[i].BufferPProd = partprodPermedia[704 >> 5];
2837	}
2838
2839	SetAttr(&pAPriv->Port[0], 0, 0);	/* Brightness (-1000..+1000) */
2840	SetAttr(&pAPriv->Port[0], 1, 0);	/* Contrast (-3000..+1000) */
2841	SetAttr(&pAPriv->Port[0], 2, 0);	/* Color saturation (-3000..+1000) */
2842	SetAttr(&pAPriv->Port[0], 3, 0);	/* Hue (-1000..+1000) */
2843
2844	pAPriv->Port[0].Attribute[4] = 1;	/* Interlaced (0 = not, 1 = yes,
2845						    2 = double scan 50/60 Hz) */
2846	pAPriv->Port[0].Attribute[5] = 0;	/* Bilinear Filter (Bool) */
2847
2848	pAPriv->Port[1].Attribute[4] = 1;	/* Interlaced (Bool) */
2849	pAPriv->Port[1].Attribute[5] = 0;	/* Bilinear Filter (Bool) */
2850
2851	SetBkgCol(&pAPriv->Port[1], 0x000000);	/* BkgColor 0x00RRGGBB */
2852    } /* VideoIO */
2853
2854    if (!(pAPriv->Timer = TimerSet(NULL, 0, 0, TimerCallback, pAPriv)))
2855        goto failed;
2856
2857    for (i = 0; i < PORTS; i++)
2858    	pAPriv->Port[i].StopDelay = -1;
2859
2860    /* Frontend scaler */
2861
2862    for (i = 2; i < 6; i++) {
2863	pAPriv->Port[i].fw = 0;
2864	pAPriv->Port[i].fh = 0;
2865	pAPriv->Port[i].BuffersRequested = 1;
2866	pAPriv->Delay = 125;
2867	pAPriv->Instant = 1000 / 25;
2868
2869	if (!VideoIO || pAPriv->pm2p) {
2870	    pAPriv->Delay = 5;
2871	    pAPriv->Instant = 1000;
2872	}
2873
2874	pAPriv->Port[i].Attribute[5] = 0;	/* Bilinear Filter (Bool) */
2875	pAPriv->Port[i].Attribute[7] = 0;	/* Alpha Enable (Bool) */
2876    }
2877
2878    return pAPriv;
2879
2880failed:
2881
2882    DeleteAdaptorPriv(pAPriv);
2883
2884    return NULL;
2885}
2886
2887
2888/*
2889 *  Glint interface
2890 */
2891
2892void
2893Permedia2VideoEnterVT(ScrnInfoPtr pScrn)
2894{
2895    GLINTPtr pGlint = GLINTPTR(pScrn);
2896    AdaptorPrivPtr pAPriv;
2897
2898    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv enter VT\n"));
2899
2900    for (pAPriv = AdaptorPrivList; pAPriv != NULL; pAPriv = pAPriv->Next)
2901	if (pAPriv->pScrn == pScrn) {
2902	    if (pAPriv->VideoIO) {
2903		if (pAPriv->pm2p)
2904		    xvipcHandshake(&pAPriv->Port[0], OP_ENTER, TRUE);
2905		else {
2906		    InitializeVideo(pAPriv);
2907
2908		    xf86I2CWriteVec(&pAPriv->Port[1].I2CDev, EncInitVec, ENTRIES(EncInitVec) / 2);
2909		}
2910
2911		SetVideoStd(&pAPriv->Port[0], pAPriv->VideoStd);
2912		SetPlug(&pAPriv->Port[0], pAPriv->Port[0].Plug);
2913		SetPlug(&pAPriv->Port[1], pAPriv->Port[1].Plug);
2914	    }
2915
2916	    if (pGlint->NoAccel)
2917		Permedia2InitializeEngine(pScrn);
2918
2919	    break;
2920	}
2921}
2922
2923void
2924Permedia2VideoLeaveVT(ScrnInfoPtr pScrn)
2925{
2926    AdaptorPrivPtr pAPriv;
2927
2928    for (pAPriv = AdaptorPrivList; pAPriv != NULL; pAPriv = pAPriv->Next)
2929	if (pAPriv->pScrn == pScrn) {
2930	    if (pAPriv->VideoIO) {
2931		StopVideoStream(&pAPriv->Port[0], TRUE);
2932		StopVideoStream(&pAPriv->Port[1], TRUE);
2933
2934		if (pAPriv->pm2p)
2935		    xvipcHandshake(&pAPriv->Port[0], OP_LEAVE, TRUE);
2936		else
2937		    RestoreVideo(pAPriv);
2938	    }
2939	    break;
2940	}
2941
2942    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Elvis left the building\n"));
2943}
2944
2945void
2946Permedia2VideoUninit(ScrnInfoPtr pScrn)
2947{
2948    AdaptorPrivPtr pAPriv, *ppAPriv;
2949
2950    for (ppAPriv = &AdaptorPrivList; (pAPriv = *ppAPriv); ppAPriv = &(pAPriv->Next))
2951	if (pAPriv->pScrn == pScrn) {
2952	    *ppAPriv = pAPriv->Next;
2953	    DeleteAdaptorPriv(pAPriv);
2954	    break;
2955	}
2956
2957    if (xvipc_fd >= 0) {
2958	close(xvipc_fd);
2959	xvipc_fd = -1;
2960    }
2961
2962    DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "Xv cleanup\n"));
2963}
2964
2965void
2966Permedia2VideoInit(ScreenPtr pScreen)
2967{
2968    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2969    GLINTPtr pGlint = GLINTPTR(pScrn);
2970    AdaptorPrivPtr pAPriv;
2971    pointer options[3];
2972    DevUnion Private[PORTS];
2973    XF86VideoAdaptorRec VAR[ADAPTORS];
2974    XF86VideoAdaptorPtr VARPtrs[ADAPTORS];
2975    Bool VideoIO = TRUE;
2976    int i;
2977
2978    switch (pGlint->Chipset) {
2979    case PCI_VENDOR_TI_CHIP_PERMEDIA2:
2980    case PCI_VENDOR_3DLABS_CHIP_PERMEDIA2:
2981    case PCI_VENDOR_3DLABS_CHIP_PERMEDIA2V:
2982        break;
2983
2984    default:
2985        return;
2986    }
2987
2988    options[0] = NULL;	/* VideoAdaptor "input" subsection options */
2989    options[1] = NULL;	/* VideoAdaptor "output" subsection options */
2990    options[2] = NULL;	/* VideoAdaptor options */
2991
2992    for (i = 0;; i++) {
2993	char *adaptor = NULL; /* receives VideoAdaptor section identifier */
2994
2995	if (!options[0])
2996	    options[0] = xf86FindXvOptions(pScreen->myNum, i, "input", &adaptor, options[2] ? NULL : &options[2]);
2997
2998	if (!options[1])
2999	    options[1] = xf86FindXvOptions(pScreen->myNum, i, "output", &adaptor, options[2] ? NULL : &options[2]);
3000
3001	if (!adaptor) {
3002	    if (!i) /* VideoAdaptor reference enables Xv vio driver */
3003		VideoIO = FALSE;
3004	    break;
3005	} else if (options[0] && options[1])
3006	    break;
3007    }
3008
3009    if (VideoIO) {
3010      unsigned int temp;
3011      PCI_READ_LONG(pGlint->PciInfo, &temp, PCI_SUBSYSTEM_ID_REG);
3012      switch (temp) {
3013	case PCI_SUBSYSTEM_ID_WINNER_2000_P2A:
3014	case PCI_SUBSYSTEM_ID_WINNER_2000_P2C:
3015	case PCI_SUBSYSTEM_ID_GLORIA_SYNERGY_P2A:
3016	case PCI_SUBSYSTEM_ID_GLORIA_SYNERGY_P2C:
3017	    break;
3018
3019	default:
3020	    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 1, "No Xv vio support for this board\n");
3021	    VideoIO = FALSE;
3022	}
3023    }
3024    if (pGlint->NoAccel && !VideoIO)
3025	return;
3026
3027    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 1, "Initializing Xv driver rev. 4\n");
3028
3029    if (VideoIO) {
3030	for (i = 0; i <= 2; i++) {
3031	    xf86ProcessOptions(pScrn->scrnIndex, options[i],
3032		(i == 0) ? InputOptions :
3033		(i == 1) ? OutputOptions :
3034			   AdaptorOptions);
3035
3036	    xf86ShowUnusedOptions(pScrn->scrnIndex, options[i]);
3037	}
3038
3039	if (xf86IsOptionSet(AdaptorOptions, OPTION_DEVICE)) {
3040    	    if (!xvipcOpen(xf86GetOptValString(AdaptorOptions, OPTION_DEVICE), pScrn))
3041		VideoIO = FALSE;
3042	}
3043    }
3044
3045    if (!(pAPriv = NewAdaptorPriv(pScrn, VideoIO))) {
3046	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Xv driver initialization failed\n");
3047	return;
3048    }
3049
3050    if (VideoIO) {
3051	int n;
3052
3053	if (xf86GetOptValInteger(InputOptions, OPTION_BUFFERS, &n))
3054	    pAPriv->Port[0].BuffersRequested = CLAMP(n, 1, 2);
3055	if (xf86GetOptValInteger(InputOptions, OPTION_FPS, &n))
3056	    pAPriv->Port[0].FramesPerSec = CLAMP(n, 1, 30);
3057
3058	if (xf86GetOptValInteger(OutputOptions, OPTION_BUFFERS, &n))
3059	    pAPriv->Port[1].BuffersRequested = 1;
3060	if (xf86GetOptValInteger(OutputOptions, OPTION_FPS, &n))
3061	    pAPriv->Port[1].FramesPerSec = CLAMP(n, 1, 30);
3062    }
3063
3064    if (pGlint->NoAccel) {
3065	BoxRec AvailFBArea;
3066
3067	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Xv driver overrides NoAccel option\n");
3068
3069	Permedia2InitializeEngine(pScrn);
3070
3071	AvailFBArea.x1 = 0;
3072	AvailFBArea.y1 = 0;
3073	AvailFBArea.x2 = pScrn->displayWidth;
3074	AvailFBArea.y2 = pGlint->FbMapSize /
3075	    (pScrn->displayWidth * pScrn->bitsPerPixel / 8);
3076
3077	xf86InitFBManager(pScreen, &AvailFBArea);
3078    }
3079
3080#if defined(XFree86LOADER) && 0
3081    if (xf86LoaderCheckSymbol("xf86InitLinearFBManagerRegion")) {
3082	int last = pGlint->FbMapSize / (pScrn->bitsPerPixel / 8) - 1;
3083	BoxRec AvailFBArea;
3084	RegionPtr Region;
3085
3086	AvailFBArea.x1 = 0;
3087	AvailFBArea.y1 = pScrn->virtualY;
3088	AvailFBArea.x2 = last % pScrn->displayWidth + 1;
3089	AvailFBArea.y2 = last / pScrn->displayWidth + 1;
3090
3091	DEBUG(xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2,
3092	    "Using linear FB %d,%d-%d,%d pitch %d (%dk)\n",
3093	    AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2, AvailFBArea.y2,
3094	    pScrn->displayWidth, (((AvailFBArea.y2 - AvailFBArea.y1)
3095	    * pScrn->displayWidth) << BPPSHIFT(pGlint)) / 1024));
3096
3097	Region = xf86LinearFBRegion(pScreen, &AvailFBArea, pScrn->displayWidth);
3098	xf86InitLinearFBManagerRegion(pScreen, Region);
3099	REGION_DESTROY(pScreen, Region);
3100    }
3101#endif
3102
3103    memset(VAR, 0, sizeof(VAR));
3104
3105    for (i = 0; i < PORTS; i++)
3106	Private[i].ptr = (pointer) &pAPriv->Port[i];
3107
3108    for (i = 0; i < ADAPTORS; i++) {
3109	VARPtrs[i] = &VAR[i];
3110	switch (i) {
3111	case 0:
3112	    VAR[i].name = "Permedia 2 Video Input";
3113	    VAR[i].type = XvInputMask | XvWindowMask | XvVideoMask | XvStillMask;
3114	    VAR[i].nPorts = 1;
3115	    VAR[i].pPortPrivates = &Private[0];
3116	    VAR[i].nAttributes	= ENTRIES(InputVideoAttributes);
3117	    VAR[i].pAttributes	= InputVideoAttributes;
3118	    VAR[i].nEncodings	= ENTRIES(InputVideoEncodings);
3119	    VAR[i].pEncodings	= InputVideoEncodings;
3120	    VAR[i].nFormats	= ENTRIES(InputVideoFormats);
3121	    VAR[i].pFormats	= InputVideoFormats;
3122	    break;
3123
3124	case 1:
3125	    VAR[i].name = "Permedia 2 Video Output";
3126	    VAR[i].type = XvOutputMask | XvWindowMask | XvVideoMask | XvStillMask;
3127	    VAR[i].nPorts = 1;
3128	    VAR[i].pPortPrivates = &Private[1];
3129	    VAR[i].nAttributes	= ENTRIES(OutputVideoAttributes);
3130	    VAR[i].pAttributes	= OutputVideoAttributes;
3131	    VAR[i].nEncodings	= ENTRIES(OutputVideoEncodings);
3132	    VAR[i].pEncodings	= OutputVideoEncodings;
3133	    VAR[i].nFormats	= ENTRIES(OutputVideoFormats);
3134	    VAR[i].pFormats	= OutputVideoFormats;
3135	    break;
3136
3137	case 2:
3138	    VAR[i].name = "Permedia 2 Frontend Scaler";
3139	    VAR[i].type = XvInputMask | XvWindowMask | XvImageMask;
3140	    VAR[i].nPorts = 3;
3141	    VAR[i].pPortPrivates = &Private[2];
3142	    VAR[i].nAttributes	= ENTRIES(ScalerAttributes);
3143	    VAR[i].pAttributes	= ScalerAttributes;
3144	    VAR[i].nEncodings	= ENTRIES(ScalerEncodings);
3145	    VAR[i].pEncodings	= ScalerEncodings;
3146	    VAR[i].nFormats	= ENTRIES(ScalerVideoFormats);
3147	    VAR[i].pFormats	= ScalerVideoFormats;
3148	    VAR[i].nImages	= ENTRIES(ScalerImages);
3149	    VAR[i].pImages	= ScalerImages;
3150	    break;
3151	}
3152
3153	VAR[i].PutVideo = Permedia2PutVideo;
3154	VAR[i].PutStill = Permedia2PutStill;
3155	VAR[i].GetVideo = Permedia2GetVideo;
3156	VAR[i].GetStill = Permedia2GetStill;
3157	VAR[i].StopVideo = Permedia2StopVideo;
3158	VAR[i].SetPortAttribute = Permedia2SetPortAttribute;
3159	VAR[i].GetPortAttribute = Permedia2GetPortAttribute;
3160	VAR[i].QueryBestSize = Permedia2QueryBestSize;
3161	VAR[i].PutImage = Permedia2PutImage;
3162	VAR[i].QueryImageAttributes = Permedia2QueryImageAttributes;
3163    }
3164
3165    if (VideoIO ? xf86XVScreenInit(pScreen, &VARPtrs[0], 3) :
3166		  xf86XVScreenInit(pScreen, &VARPtrs[2], 1)) {
3167	char *s;
3168
3169	xvEncoding	= MAKE_ATOM(XV_ENCODING);
3170	xvHue		= MAKE_ATOM(XV_HUE);
3171	xvSaturation	= MAKE_ATOM(XV_SATURATION);
3172	xvBrightness	= MAKE_ATOM(XV_BRIGHTNESS);
3173	xvContrast	= MAKE_ATOM(XV_CONTRAST);
3174	xvInterlace	= MAKE_ATOM(XV_INTERLACE);
3175	xvFilter	= MAKE_ATOM(XV_FILTER);
3176	xvBkgColor	= MAKE_ATOM(XV_BKGCOLOR);
3177	xvAlpha		= MAKE_ATOM(XV_ALPHA);
3178
3179	pAPriv->Next = AdaptorPrivList;
3180	AdaptorPrivList = pAPriv;
3181
3182	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv frontend scaler enabled\n");
3183
3184	if (VideoIO) {
3185	    if ((s = xf86GetOptValString(InputOptions, OPTION_ENCODING)))
3186	        for (i = 0; i < ENTRIES(InputVideoEncodings); i++)
3187		    if (!strncmp(s, InputVideoEncodings[i].name, strlen(s))) {
3188			Permedia2SetPortAttribute(pScrn, xvEncoding, i, (pointer) &pAPriv->Port[0]);
3189			break;
3190		    }
3191
3192	    if ((s = xf86GetOptValString(OutputOptions, OPTION_ENCODING)))
3193		for (i = 0; i < ENTRIES(OutputVideoEncodings); i++)
3194		    if (!strncmp(s, OutputVideoEncodings[i].name, strlen(s))) {
3195			Permedia2SetPortAttribute(pScrn, xvEncoding, i, (pointer) &pAPriv->Port[1]);
3196			break;
3197		    }
3198
3199	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv vio driver %senabled\n",
3200		pAPriv->pm2p ? "with kernel backbone " : "");
3201	}
3202    } else {
3203	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Xv initialization failed\n");
3204	DeleteAdaptorPriv(pAPriv);
3205    }
3206}
3207