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