1f29dbc25Smrg/*
2f29dbc25Smrg * Copyright (c) 2006 Advanced Micro Devices, Inc.
3f29dbc25Smrg *
4f29dbc25Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5f29dbc25Smrg * copy of this software and associated documentation files (the "Software"),
6f29dbc25Smrg * to deal in the Software without restriction, including without limitation
7f29dbc25Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8f29dbc25Smrg * and/or sell copies of the Software, and to permit persons to whom the
9f29dbc25Smrg * Software is furnished to do so, subject to the following conditions:
10f29dbc25Smrg *
11f29dbc25Smrg * The above copyright notice and this permission notice shall be included in
12f29dbc25Smrg * all copies or substantial portions of the Software.
13f29dbc25Smrg *
14f29dbc25Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15f29dbc25Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16f29dbc25Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17f29dbc25Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18f29dbc25Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19f29dbc25Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20f29dbc25Smrg * DEALINGS IN THE SOFTWARE.
21f29dbc25Smrg *
22f29dbc25Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
23f29dbc25Smrg * contributors may be used to endorse or promote products derived from this
24f29dbc25Smrg * software without specific prior written permission.
25f29dbc25Smrg */
26f29dbc25Smrg
27f29dbc25Smrg/* prototype Xv interface for lxv4l2 driver */
28f29dbc25Smrg
29f29dbc25Smrg#ifdef HAVE_CONFIG_H
30f29dbc25Smrg#include "config.h"
31f29dbc25Smrg#endif
32f29dbc25Smrg
33f29dbc25Smrg#include <sys/time.h>
34f29dbc25Smrg#include <sys/fcntl.h>
35f29dbc25Smrg#include <sys/mman.h>
36f29dbc25Smrg#include <sys/ioctl.h>
37f29dbc25Smrg#include <errno.h>
38f29dbc25Smrg#include <unistd.h>
39f29dbc25Smrg#include <string.h>
40f29dbc25Smrg#include <ctype.h>
41f29dbc25Smrg#include <stdlib.h>
42f29dbc25Smrg
43f29dbc25Smrg#include "xf86.h"
44f29dbc25Smrg#include <X11/extensions/Xv.h>
45f29dbc25Smrg#include "xf86_OSproc.h"
46f29dbc25Smrg#include "compiler.h"
47f29dbc25Smrg#include "xf86xv.h"
48f29dbc25Smrg#include "fourcc.h"
49f29dbc25Smrg
5004007ebaSmrg#include "compat-api.h"
51f29dbc25Smrg
52f29dbc25Smrg#define __s64 __s_64
53f29dbc25Smrgtypedef long long __s64;
54f29dbc25Smrg
55f29dbc25Smrg#define __u64 __u_64
56f29dbc25Smrgtypedef unsigned long long __u64;
57f29dbc25Smrg
58f29dbc25Smrg#define __user
59f29dbc25Smrg#include "linux/videodev2.h"
60f29dbc25Smrg
61f29dbc25Smrgtypedef signed long long s64;
62f29dbc25Smrgtypedef unsigned long long u64;
63f29dbc25Smrg
64f29dbc25Smrgint debuglvl = 0;
65f29dbc25Smrg
66f29dbc25Smrg#define NONBLK_IO
67f29dbc25Smrg#undef HAVE_SELECT
68f29dbc25Smrg
69f29dbc25Smrg#define DEBUG 1
70f29dbc25Smrg#ifdef DEBUG
71f29dbc25Smrg#define DBLOG(n,s...) do { \
72f29dbc25Smrg						if ( debuglvl >= (n) ) \
73f29dbc25Smrg							xf86Msg(X_INFO, "z4l: " s); \
74f29dbc25Smrg					  } while(0)
75f29dbc25Smrg#else
76f29dbc25Smrg#define DBLOG(n,s...) do {} while(0)
77f29dbc25Smrg#endif
78f29dbc25Smrg
79f29dbc25Smrg#define DEFAULT_COLORKEY 0x010203
80f29dbc25Smrg#define DEFAULT_KEYMODE 0
81f29dbc25Smrg
82f29dbc25Smrg#define MAX_BUFFERS 4
83f29dbc25Smrg#define MAX_OVLY_WIDTH  2048
84f29dbc25Smrg#define MAX_OVLY_HEIGHT 2048
85f29dbc25Smrg
86f29dbc25Smrgstatic char *z4l_dev_paths[] = {
87f29dbc25Smrg    "/dev/videox", NULL
88f29dbc25Smrg};
89f29dbc25Smrg
90f29dbc25Smrg#define ATTR_ENCODING "encoding"
91f29dbc25Smrg#define ATTR_ENCODING_ID -1
92f29dbc25Smrg#define ATTR_KEYMODE "keymode"
93f29dbc25Smrg#define ATTR_KEYMODE_ID -2
94f29dbc25Smrg#define ATTR_COLORKEY "colorkey"
95f29dbc25Smrg#define ATTR_COLORKEY_ID -3
96f29dbc25Smrg#define ATTR_MAX_ID 3
97f29dbc25Smrg
98f29dbc25Smrg#ifdef XvExtension
99f29dbc25Smrg
100f29dbc25Smrgstatic XF86VideoFormatRec Formats[] = {
101f29dbc25Smrg    {8, PseudoColor},
102f29dbc25Smrg    {15, TrueColor},
103f29dbc25Smrg    {16, TrueColor},
104f29dbc25Smrg    {24, TrueColor}
105f29dbc25Smrg};
106f29dbc25Smrg
107f29dbc25Smrg#define NUM_FORMATS (sizeof(Formats)/sizeof(Formats[0]))
108f29dbc25Smrg
109f29dbc25Smrg#define FOURCC_Y800 0x30303859
110f29dbc25Smrg#define XVIMAGE_Y800 \
111f29dbc25Smrg   { \
112f29dbc25Smrg        FOURCC_Y800, \
113f29dbc25Smrg        XvYUV, \
114f29dbc25Smrg        LSBFirst, \
115f29dbc25Smrg        {'Y','8','0','0', \
116f29dbc25Smrg          0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
117f29dbc25Smrg        8, \
118f29dbc25Smrg        XvPacked, \
119f29dbc25Smrg        1, \
120f29dbc25Smrg        0, 0, 0, 0, \
121f29dbc25Smrg        8, 0, 0, \
122f29dbc25Smrg        1, 0, 0, \
123f29dbc25Smrg        1, 0, 0, \
124f29dbc25Smrg        {'Y','8','0','0', \
125f29dbc25Smrg          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
126f29dbc25Smrg        XvTopToBottom \
127f29dbc25Smrg   }
128f29dbc25Smrg
129f29dbc25Smrgstatic XF86ImageRec pixfmts[] = {
130f29dbc25Smrg    XVIMAGE_UYVY, XVIMAGE_YUY2,
131f29dbc25Smrg    XVIMAGE_I420, XVIMAGE_YV12,
132f29dbc25Smrg    XVIMAGE_Y800,
133f29dbc25Smrg};
134f29dbc25Smrg
135f29dbc25Smrg#define NUM_PIXFMTS (sizeof(pixfmts)/sizeof(pixfmts[0]))
136f29dbc25Smrg
13704007ebaSmrgtypedef struct s_std_data {
138f29dbc25Smrg    int inp;
139f29dbc25Smrg    v4l2_std_id std;
140f29dbc25Smrg    unsigned int fmt;
141f29dbc25Smrg} t_std_data;
142f29dbc25Smrg
14304007ebaSmrgtypedef struct s_ovly_bfrs {
144f29dbc25Smrg    void *start;
145f29dbc25Smrg    unsigned long offset;
146f29dbc25Smrg    size_t length;
147f29dbc25Smrg} t_ovly_bfrs;
148f29dbc25Smrg
14904007ebaSmrgtypedef struct {
150f29dbc25Smrg    int fd;
151f29dbc25Smrg    int run;
152f29dbc25Smrg    int dir;
153f29dbc25Smrg    int nbfrs;
154f29dbc25Smrg    int bufno;
155f29dbc25Smrg    int bufsz;
156f29dbc25Smrg    int last;
157f29dbc25Smrg    int width, height;
158f29dbc25Smrg    int keymode, colorkey;
159f29dbc25Smrg    int src_is_set, src_x, src_y, src_w, src_h;
160f29dbc25Smrg    int drw_is_set, drw_x, drw_y, drw_w, drw_h;
161f29dbc25Smrg    unsigned int pixfmt;
162f29dbc25Smrg    char dev_path[32];
163f29dbc25Smrg    t_ovly_bfrs bfrs[MAX_BUFFERS];
164f29dbc25Smrg    XF86VideoAdaptorPtr adpt;
165f29dbc25Smrg    XF86VideoEncodingPtr enc;
166f29dbc25Smrg    RegionRec clips;
167f29dbc25Smrg    int attrIds[1];
168f29dbc25Smrg} Z4lPortPrivRec;
169f29dbc25Smrg
170f29dbc25Smrgstatic int z4l_x_offset = 0;
171f29dbc25Smrgstatic int z4l_y_offset = 0;
172f29dbc25Smrgstatic int Z4l_nAdaptors = 0;
173f29dbc25Smrgstatic XF86VideoAdaptorPtr *Z4l_pAdaptors = NULL;
174f29dbc25Smrg
175f29dbc25Smrgstatic int
176f29dbc25SmrgIoCtl(int fd, unsigned int fn, void *arg, int flag)
177f29dbc25Smrg{
178f29dbc25Smrg    int ret;
179f29dbc25Smrg
180f29dbc25Smrg    errno = 0;
181f29dbc25Smrg    ret = ioctl(fd, fn, arg);
182f29dbc25Smrg    if (ret != 0 && flag != 0)
18304007ebaSmrg        DBLOG(0, "ioctl(%08x)=%d\n", fn, ret);
184f29dbc25Smrg    return ret;
185f29dbc25Smrg}
186f29dbc25Smrg
187f29dbc25Smrgstatic void
188f29dbc25Smrgz4l_ovly_unmap(Z4lPortPrivRec * pPriv)
189f29dbc25Smrg{
190f29dbc25Smrg    int i, nbfrs;
191f29dbc25Smrg
192f29dbc25Smrg    nbfrs = pPriv->nbfrs;
193f29dbc25Smrg    for (i = 0; i < nbfrs; ++i) {
19404007ebaSmrg        if (pPriv->bfrs[i].start != NULL) {
19504007ebaSmrg            munmap(pPriv->bfrs[i].start, pPriv->bfrs[i].length);
19604007ebaSmrg            pPriv->bfrs[i].start = NULL;
19704007ebaSmrg        }
198f29dbc25Smrg    }
199f29dbc25Smrg    pPriv->nbfrs = -1;
200f29dbc25Smrg    pPriv->bufsz = -1;
201f29dbc25Smrg    pPriv->last = -1;
202f29dbc25Smrg}
203f29dbc25Smrg
204f29dbc25Smrgstatic void
205f29dbc25Smrgz4l_ovly_map(Z4lPortPrivRec * pPriv, int dir)
206f29dbc25Smrg{
207f29dbc25Smrg    long offset, bsz;
208f29dbc25Smrg    int i, fd;
209f29dbc25Smrg    struct v4l2_buffer bfr;
210f29dbc25Smrg    struct v4l2_requestbuffers req;
211f29dbc25Smrg    int type = dir >= 0 ?
21204007ebaSmrg        V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VIDEO_OVERLAY;
213f29dbc25Smrg    if (pPriv->run > 0) {
21404007ebaSmrg        DBLOG(1, "busy\n");
21504007ebaSmrg        return;
216f29dbc25Smrg    }
217f29dbc25Smrg    fd = pPriv->fd;
218f29dbc25Smrg    memset(&req, 0, sizeof(req));
219f29dbc25Smrg    req.type = type;
220f29dbc25Smrg    req.memory = V4L2_MEMORY_MMAP;
221f29dbc25Smrg    req.count = MAX_BUFFERS;
222f29dbc25Smrg    if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
22304007ebaSmrg        goto xit;
224f29dbc25Smrg    pPriv->nbfrs = req.count;
225f29dbc25Smrg    if (pPriv->nbfrs <= 0) {
22604007ebaSmrg        DBLOG(1, "no vidmem\n");
22704007ebaSmrg        return;
228f29dbc25Smrg    }
229f29dbc25Smrg    memset(&pPriv->bfrs, 0, sizeof(pPriv->bfrs));
230f29dbc25Smrg
231f29dbc25Smrg    for (i = 0; i < pPriv->nbfrs; ++i) {
23204007ebaSmrg        memset(&bfr, 0, sizeof(bfr));
23304007ebaSmrg        bfr.type = type;
23404007ebaSmrg        bfr.index = i;
23504007ebaSmrg        if (ioctl(fd, VIDIOC_QUERYBUF, &bfr) < 0)
23604007ebaSmrg            goto xit;
23704007ebaSmrg        offset = bfr.m.offset;
23804007ebaSmrg        pPriv->bfrs[i].offset = offset;
23904007ebaSmrg        pPriv->bfrs[i].length = bfr.length;
24004007ebaSmrg        bsz = offset + bfr.length;
24104007ebaSmrg        if (pPriv->bufsz < bsz)
24204007ebaSmrg            pPriv->bufsz = bsz;
243f29dbc25Smrg    }
244f29dbc25Smrg
245f29dbc25Smrg    for (i = 0; i < pPriv->nbfrs; ++i) {
24604007ebaSmrg        pPriv->bfrs[i].start = mmap(NULL, bfr.length, PROT_READ | PROT_WRITE,
24704007ebaSmrg                                    MAP_SHARED, fd, pPriv->bfrs[i].offset);
24804007ebaSmrg        if (pPriv->bfrs[i].start == MAP_FAILED)
24904007ebaSmrg            goto xit;
250f29dbc25Smrg    }
251f29dbc25Smrg
252f29dbc25Smrg    for (i = 0; i < pPriv->nbfrs; ++i) {
25304007ebaSmrg        DBLOG(3, "bfr %d ofs %#lx adr %p sz %lu\n", i, pPriv->bfrs[i].offset,
25404007ebaSmrg              pPriv->bfrs[i].start, (unsigned long) pPriv->bfrs[i].length);
25504007ebaSmrg        memset(pPriv->bfrs[i].start, 0x80, pPriv->bfrs[i].length);
256f29dbc25Smrg    }
257f29dbc25Smrg
258f29dbc25Smrg    pPriv->last = 0;
259f29dbc25Smrg    while (pPriv->last < pPriv->nbfrs - 1) {
26004007ebaSmrg        bfr.index = pPriv->last++;
26104007ebaSmrg        bfr.type = type;
26204007ebaSmrg        if (ioctl(fd, VIDIOC_QBUF, &bfr) < 0)
26304007ebaSmrg            goto xit;
264f29dbc25Smrg    }
265f29dbc25Smrg    return;
266f29dbc25Smrg
26704007ebaSmrg xit:
268f29dbc25Smrg    z4l_ovly_unmap(pPriv);
269f29dbc25Smrg}
270f29dbc25Smrg
271f29dbc25Smrgstatic int
272f29dbc25Smrgz4l_ovly_dqbuf(Z4lPortPrivRec * pPriv)
273f29dbc25Smrg{
274f29dbc25Smrg    int stat;
275f29dbc25Smrg    struct v4l2_buffer bfr;
276f29dbc25Smrg    int fd = pPriv->fd;
277f29dbc25Smrg
278f29dbc25Smrg#ifdef HAVE_SELECT
279f29dbc25Smrg    struct timeval tmo;
280f29dbc25Smrg    fd_set dqset;
281f29dbc25Smrg
282f29dbc25Smrg    FD_ZERO(&dqset);
283f29dbc25Smrg    FD_SET(pPriv->fd, &dqset);
284f29dbc25Smrg    tmo.tv_sec = 0;
285f29dbc25Smrg    tmo.tv_usec = 0;
286f29dbc25Smrg    if (select(fd + 1, &dqset, NULL, NULL, &tmo) <= 0)
28704007ebaSmrg        return -1;
288f29dbc25Smrg#endif
289f29dbc25Smrg    memset(&bfr, 0, sizeof(bfr));
290f29dbc25Smrg    bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
291f29dbc25Smrg    stat = ioctl(fd, VIDIOC_DQBUF, &bfr);
292f29dbc25Smrg    DBLOG(3, "dqbuf %d,%d,%d,%d\n", stat, bfr.index, pPriv->last, errno);
293f29dbc25Smrg
294f29dbc25Smrg    return stat == 0 ? bfr.index : -1;
295f29dbc25Smrg}
296f29dbc25Smrg
297f29dbc25Smrgstatic int
298f29dbc25Smrgz4l_open_device(Z4lPortPrivRec * pPriv)
299f29dbc25Smrg{
300f29dbc25Smrg    int enable;
301f29dbc25Smrg
302f29dbc25Smrg    if (pPriv->fd < 0) {
30304007ebaSmrg        pPriv->fd = open(&pPriv->dev_path[0], O_RDWR, 0);
30404007ebaSmrg        DBLOG(1, "open(%s)=%d\n", &pPriv->dev_path[0], pPriv->fd);
30504007ebaSmrg        enable = 1;
306f29dbc25Smrg#ifdef NONBLK_IO
30704007ebaSmrg        if (IoCtl(pPriv->fd, FIONBIO, &enable, 1) != 0) {
30879d5fcd7Smrg            DBLOG(1, "open can't enable nonblocking\n");
30904007ebaSmrg            close(pPriv->fd);
31004007ebaSmrg            pPriv->fd = -1;
31104007ebaSmrg        }
312f29dbc25Smrg#endif
313f29dbc25Smrg    }
314f29dbc25Smrg    return pPriv->fd;
315f29dbc25Smrg}
316f29dbc25Smrg
317f29dbc25Smrgstatic int
318f29dbc25Smrgz4l_close_device(Z4lPortPrivRec * pPriv)
319f29dbc25Smrg{
320f29dbc25Smrg    int ret = 0;
321f29dbc25Smrg
322f29dbc25Smrg    if (pPriv->fd >= 0) {
32304007ebaSmrg        ret = close(pPriv->fd);
32404007ebaSmrg        pPriv->fd = -1;
32504007ebaSmrg        DBLOG(1, "close()=%d\n", ret);
326f29dbc25Smrg    }
327f29dbc25Smrg    if (pPriv->run > 0) {
32804007ebaSmrg        z4l_ovly_unmap(pPriv);
32904007ebaSmrg        pPriv->run = -1;
330f29dbc25Smrg    }
331f29dbc25Smrg
332f29dbc25Smrg    return ret;
333f29dbc25Smrg}
334f29dbc25Smrg
335f29dbc25Smrgstatic int
336f29dbc25Smrgz4l_ovly_reset(Z4lPortPrivRec * pPriv)
337f29dbc25Smrg{
338f29dbc25Smrg    int ret = 0;
339f29dbc25Smrg
340f29dbc25Smrg    if (pPriv->run > 0) {
34104007ebaSmrg        z4l_close_device(pPriv);
34204007ebaSmrg        ret = z4l_open_device(pPriv);
343f29dbc25Smrg    }
344f29dbc25Smrg
345f29dbc25Smrg    return ret;
346f29dbc25Smrg}
347f29dbc25Smrg
348f29dbc25Smrgstatic unsigned int
349f29dbc25Smrgz4l_fourcc_pixfmt(int fourcc)
350f29dbc25Smrg{
351f29dbc25Smrg    unsigned int pixfmt = -1;
352f29dbc25Smrg
353f29dbc25Smrg    switch (fourcc) {
354f29dbc25Smrg    case FOURCC_UYVY:
35504007ebaSmrg        pixfmt = V4L2_PIX_FMT_UYVY;
35604007ebaSmrg        break;
357f29dbc25Smrg    case FOURCC_YV12:
35804007ebaSmrg        pixfmt = V4L2_PIX_FMT_YVU420;
35904007ebaSmrg        break;
360f29dbc25Smrg    case FOURCC_Y800:
361f29dbc25Smrg    case FOURCC_I420:
36204007ebaSmrg        pixfmt = V4L2_PIX_FMT_YUV420;
36304007ebaSmrg        break;
364f29dbc25Smrg    case FOURCC_YUY2:
36504007ebaSmrg        pixfmt = V4L2_PIX_FMT_YUYV;
36604007ebaSmrg        break;
367f29dbc25Smrg    }
368f29dbc25Smrg
369f29dbc25Smrg    return pixfmt;
370f29dbc25Smrg}
37104007ebaSmrg
372f29dbc25Smrgstatic void
373f29dbc25Smrgz4l_ovly_pixfmt(Z4lPortPrivRec * pPriv, unsigned int pixfmt)
374f29dbc25Smrg{
375f29dbc25Smrg    struct v4l2_framebuffer fbuf;
376f29dbc25Smrg
37704007ebaSmrg    DBLOG(1, "pixfmt %4.4s %4.4s\n", (char *) &pPriv->pixfmt, (char *) &pixfmt);
378f29dbc25Smrg    memset(&fbuf, 0, sizeof(fbuf));
379f29dbc25Smrg    IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1);
380f29dbc25Smrg    fbuf.fmt.pixelformat = pixfmt;
381f29dbc25Smrg    fbuf.base = NULL;
382f29dbc25Smrg    IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1);
383f29dbc25Smrg    pPriv->pixfmt = pixfmt;
384f29dbc25Smrg}
385f29dbc25Smrg
386f29dbc25Smrgstatic void
387f29dbc25Smrgz4l_ovly_bfr(Z4lPortPrivRec * pPriv, int width, int height)
388f29dbc25Smrg{
389f29dbc25Smrg    struct v4l2_format fmt;
390f29dbc25Smrg
391f29dbc25Smrg    DBLOG(1, "sfmt ovly %dx%d\n", width, height);
392f29dbc25Smrg    memset(&fmt, 0, sizeof(fmt));
393f29dbc25Smrg    fmt.type = 0x102;
394f29dbc25Smrg    IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
395f29dbc25Smrg    fmt.fmt.win.field = V4L2_FIELD_NONE;
396f29dbc25Smrg    fmt.fmt.win.w.width = pPriv->width = width;
397f29dbc25Smrg    fmt.fmt.win.w.height = pPriv->height = height;
398f29dbc25Smrg    IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
399f29dbc25Smrg}
400f29dbc25Smrg
401f29dbc25Smrgstatic void
402f29dbc25Smrgz4l_ovly_rect(Z4lPortPrivRec * pPriv,
40304007ebaSmrg              int src_x, int src_y, int src_w, int src_h,
40404007ebaSmrg              int drw_x, int drw_y, int drw_w, int drw_h)
405f29dbc25Smrg{
406f29dbc25Smrg    int x, dx, w, y, dy, h;
407f29dbc25Smrg    struct v4l2_format fmt;
408f29dbc25Smrg
409f29dbc25Smrg    pPriv->src_x = src_x;
410f29dbc25Smrg    pPriv->src_y = src_y;
411f29dbc25Smrg    pPriv->src_w = src_w;
412f29dbc25Smrg    pPriv->src_h = src_h;
413f29dbc25Smrg    pPriv->drw_x = drw_x;
414f29dbc25Smrg    pPriv->drw_y = drw_y;
415f29dbc25Smrg    pPriv->drw_w = drw_w;
416f29dbc25Smrg    pPriv->drw_h = drw_h;
417f29dbc25Smrg
418f29dbc25Smrg    if ((drw_x -= z4l_x_offset) < 0) {
41904007ebaSmrg        if ((w = pPriv->drw_w) <= 0)
42004007ebaSmrg            w = 1;
42104007ebaSmrg        x = -drw_x;
42204007ebaSmrg        dx = x * pPriv->src_w / w;
42304007ebaSmrg        src_x = pPriv->src_x + dx;
42404007ebaSmrg        src_w = pPriv->src_w - dx;
42504007ebaSmrg        drw_w = pPriv->drw_w - x;
42604007ebaSmrg        drw_x = 0;
427f29dbc25Smrg    }
428f29dbc25Smrg
429f29dbc25Smrg    if ((drw_y -= z4l_y_offset) < 0) {
43004007ebaSmrg        if ((h = pPriv->drw_h) <= 0)
43104007ebaSmrg            h = 1;
43204007ebaSmrg        y = -drw_y;
43304007ebaSmrg        dy = y * pPriv->src_h / h;
43404007ebaSmrg        src_y = pPriv->src_y + dy;
43504007ebaSmrg        src_h = pPriv->src_h - dy;
43604007ebaSmrg        drw_h = pPriv->drw_h - y;
43704007ebaSmrg        drw_y = 0;
438f29dbc25Smrg    }
439f29dbc25Smrg
440f29dbc25Smrg    memset(&fmt, 0, sizeof(fmt));
441f29dbc25Smrg    fmt.type = 0x100;
442f29dbc25Smrg    IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
443f29dbc25Smrg    if (pPriv->src_is_set != 0) {
44404007ebaSmrg        if (src_x != fmt.fmt.win.w.left || src_y != fmt.fmt.win.w.top ||
44504007ebaSmrg            src_w != fmt.fmt.win.w.width || src_h != fmt.fmt.win.w.height)
44604007ebaSmrg            pPriv->src_is_set = 0;
447f29dbc25Smrg    }
448f29dbc25Smrg    if (pPriv->src_is_set == 0) {
44904007ebaSmrg        pPriv->src_is_set = 1;
45004007ebaSmrg        fmt.fmt.win.w.left = src_x;
45104007ebaSmrg        fmt.fmt.win.w.top = src_y;
45204007ebaSmrg        fmt.fmt.win.w.width = src_w;
45304007ebaSmrg        fmt.fmt.win.w.height = src_h;
45404007ebaSmrg        IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
45504007ebaSmrg        DBLOG(3, "  set src %d,%d %dx%d\n", src_x, src_y, src_w, src_h);
456f29dbc25Smrg    }
457f29dbc25Smrg    memset(&fmt, 0, sizeof(fmt));
458f29dbc25Smrg    fmt.type = 0x101;
459f29dbc25Smrg    IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
460f29dbc25Smrg    if (pPriv->drw_is_set != 0) {
46104007ebaSmrg        if (drw_x != fmt.fmt.win.w.left || drw_y != fmt.fmt.win.w.top ||
46204007ebaSmrg            drw_w != fmt.fmt.win.w.width || drw_h != fmt.fmt.win.w.height)
46304007ebaSmrg            pPriv->drw_is_set = 0;
464f29dbc25Smrg    }
465f29dbc25Smrg    if (pPriv->drw_is_set == 0) {
46604007ebaSmrg        pPriv->drw_is_set = 1;
46704007ebaSmrg        fmt.fmt.win.w.left = drw_x;
46804007ebaSmrg        fmt.fmt.win.w.top = drw_y;
46904007ebaSmrg        fmt.fmt.win.w.width = drw_w;
47004007ebaSmrg        fmt.fmt.win.w.height = drw_h;
47104007ebaSmrg        IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
47204007ebaSmrg        DBLOG(3, "  set drw %d,%d %dx%d\n", drw_x, drw_y, drw_w, drw_h);
473f29dbc25Smrg    }
474f29dbc25Smrg}
475f29dbc25Smrg
476f29dbc25Smrgstatic void
477f29dbc25Smrgz4l_ovly_pitch(unsigned int pixfmt, int w, int h, int *py_pitch,
47804007ebaSmrg               int *puv_pitch, int *poffset1, int *poffset2, int *psize)
479f29dbc25Smrg{
480f29dbc25Smrg    int y_pitch, uv_pitch;
481f29dbc25Smrg    int offset1, offset2;
482f29dbc25Smrg    int size, is_420;
483f29dbc25Smrg
484f29dbc25Smrg    switch (pixfmt) {
485f29dbc25Smrg    case V4L2_PIX_FMT_YVU420:
486f29dbc25Smrg    case V4L2_PIX_FMT_YUV420:
48704007ebaSmrg        is_420 = 1;
48804007ebaSmrg        y_pitch = ((w + 1) / 2) * 2;
48904007ebaSmrg        uv_pitch = (w + 1) / 2;
49004007ebaSmrg        break;
491f29dbc25Smrg    default:
49204007ebaSmrg        is_420 = 0;
49304007ebaSmrg        y_pitch = ((w + 1) / 2) * 4;
49404007ebaSmrg        uv_pitch = 0;
49504007ebaSmrg        break;
496f29dbc25Smrg    }
497f29dbc25Smrg
498f29dbc25Smrg    offset1 = y_pitch * h;
499f29dbc25Smrg    offset2 = uv_pitch * h;
500f29dbc25Smrg
501f29dbc25Smrg    if (is_420 != 0)
50204007ebaSmrg        offset2 /= 2;
503f29dbc25Smrg
504f29dbc25Smrg    size = offset1 + 2 * offset2;
505f29dbc25Smrg    *py_pitch = y_pitch;
506f29dbc25Smrg    *puv_pitch = uv_pitch;
507f29dbc25Smrg    *poffset1 = offset1;
508f29dbc25Smrg    *poffset2 = offset2;
509f29dbc25Smrg    *psize = size;
510f29dbc25Smrg}
511f29dbc25Smrg
512f29dbc25Smrgstatic int
513f29dbc25Smrgz4l_ovly_set_colorkey(Z4lPortPrivRec * pPriv, int key)
514f29dbc25Smrg{
515f29dbc25Smrg    struct v4l2_format fmt;
516f29dbc25Smrg
517f29dbc25Smrg    memset(&fmt, 0, sizeof(fmt));
518f29dbc25Smrg    fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
519f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
52004007ebaSmrg        return 0;
521f29dbc25Smrg    fmt.fmt.win.chromakey = key;
522f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0)
52304007ebaSmrg        return 0;
524f29dbc25Smrg    pPriv->colorkey = key;
525f29dbc25Smrg
526f29dbc25Smrg    return 1;
527f29dbc25Smrg}
528f29dbc25Smrg
529f29dbc25Smrgstatic int
530f29dbc25Smrgz4l_ovly_get_colorkey(Z4lPortPrivRec * pPriv, int *key)
531f29dbc25Smrg{
532f29dbc25Smrg    struct v4l2_format fmt;
533f29dbc25Smrg
534f29dbc25Smrg    memset(&fmt, 0, sizeof(fmt));
535f29dbc25Smrg    fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
536f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
53704007ebaSmrg        return 0;
538f29dbc25Smrg    *key = fmt.fmt.win.chromakey;
539f29dbc25Smrg
540f29dbc25Smrg    return 1;
541f29dbc25Smrg}
542f29dbc25Smrg
543f29dbc25Smrgstatic int
544f29dbc25Smrgz4l_ovly_set_keymode(Z4lPortPrivRec * pPriv, int enable)
545f29dbc25Smrg{
546f29dbc25Smrg    struct v4l2_framebuffer fbuf;
547f29dbc25Smrg
548f29dbc25Smrg    memset(&fbuf, 0, sizeof(fbuf));
549f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
55004007ebaSmrg        return 0;
551f29dbc25Smrg
552f29dbc25Smrg    if (enable != 0)
55304007ebaSmrg        fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
554f29dbc25Smrg    else
55504007ebaSmrg        fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
556f29dbc25Smrg
557f29dbc25Smrg    fbuf.base = NULL;
558f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0)
55904007ebaSmrg        return 0;
560f29dbc25Smrg    pPriv->keymode = enable;
561f29dbc25Smrg
562f29dbc25Smrg    return 1;
563f29dbc25Smrg}
564f29dbc25Smrg
565f29dbc25Smrgstatic int
566f29dbc25Smrgz4l_ovly_get_keymode(Z4lPortPrivRec * pPriv, int *enable)
567f29dbc25Smrg{
568f29dbc25Smrg    struct v4l2_framebuffer fbuf;
569f29dbc25Smrg
570f29dbc25Smrg    memset(&fbuf, 0, sizeof(fbuf));
571f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
57204007ebaSmrg        return 0;
573f29dbc25Smrg    *enable = (fbuf.flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0 ? 1 : 0;
574f29dbc25Smrg
575f29dbc25Smrg    return 1;
576f29dbc25Smrg}
577f29dbc25Smrg
578f29dbc25Smrgstatic int
579f29dbc25Smrgz4l_ovly_set_encoding(Z4lPortPrivRec * pPriv, int id)
580f29dbc25Smrg{
581f29dbc25Smrg    int l, n, inp;
582f29dbc25Smrg    char *cp;
583f29dbc25Smrg    t_std_data *sp;
584f29dbc25Smrg    XF86VideoEncodingPtr enc;
585f29dbc25Smrg    XF86VideoAdaptorPtr adpt;
586f29dbc25Smrg    v4l2_std_id std;
587f29dbc25Smrg    struct v4l2_format fmt;
588f29dbc25Smrg    struct v4l2_framebuffer fbuf;
589f29dbc25Smrg
590f29dbc25Smrg    adpt = pPriv->adpt;
591f29dbc25Smrg    DBLOG(1, "z4l_ovly_set_encoding(%d)\n", id);
592f29dbc25Smrg    if (id < 0 || id >= adpt->nEncodings)
59304007ebaSmrg        return 0;
594f29dbc25Smrg    enc = &adpt->pEncodings[id];
595f29dbc25Smrg    cp = &enc->name[0];
596f29dbc25Smrg    n = sizeof(int) - 1;
597f29dbc25Smrg    l = strlen(cp) + 1;
598f29dbc25Smrg    l = (l + n) & ~n;
599f29dbc25Smrg    sp = (t_std_data *) (cp + l);
600f29dbc25Smrg    inp = sp->inp;
601f29dbc25Smrg
602f29dbc25Smrg    DBLOG(1, " nm %s fmt %4.4s inp %d std %llx\n",
60304007ebaSmrg          cp, (char *) &sp->fmt, sp->inp, sp->std);
604f29dbc25Smrg
605f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_S_INPUT, &inp, 1) < 0)
60604007ebaSmrg        return 0;
607f29dbc25Smrg
608f29dbc25Smrg    std = sp->std;
609f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_S_STD, &std, 1) < 0)
61004007ebaSmrg        return 0;
611f29dbc25Smrg
612f29dbc25Smrg    memset(&fmt, 0, sizeof(fmt));
613f29dbc25Smrg    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
614f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
61504007ebaSmrg        return 0;
616f29dbc25Smrg
617f29dbc25Smrg    fmt.fmt.pix.pixelformat = sp->fmt;
618f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0)
61904007ebaSmrg        return 0;
620f29dbc25Smrg    memset(&fbuf, 0, sizeof(fbuf));
621f29dbc25Smrg
622f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
62304007ebaSmrg        return 0;
624f29dbc25Smrg
625f29dbc25Smrg    fbuf.fmt.pixelformat = sp->fmt;
626f29dbc25Smrg    fbuf.base = NULL;
627f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0)
62804007ebaSmrg        return 0;
629f29dbc25Smrg    pPriv->pixfmt = sp->fmt;
630f29dbc25Smrg    pPriv->enc = enc;
631f29dbc25Smrg    pPriv->src_is_set = pPriv->drw_is_set = 0;
632f29dbc25Smrg
633f29dbc25Smrg    return 1;
634f29dbc25Smrg}
635f29dbc25Smrg
636f29dbc25Smrgstatic int
637f29dbc25Smrgz4l_ovly_get_encoding(Z4lPortPrivRec * pPriv, int *id)
638f29dbc25Smrg{
639f29dbc25Smrg    XF86VideoEncodingPtr enc = pPriv->enc;
640f29dbc25Smrg
641f29dbc25Smrg    *id = enc->id;
642f29dbc25Smrg    return 1;
643f29dbc25Smrg}
644f29dbc25Smrg
645f29dbc25Smrgstatic void
646f29dbc25Smrgz4l_ovly_stop(Z4lPortPrivRec * pPriv)
647f29dbc25Smrg{
648f29dbc25Smrg    int type, enable, fd;
649f29dbc25Smrg
650f29dbc25Smrg    if (pPriv->run < 0)
65104007ebaSmrg        return;
652f29dbc25Smrg
653f29dbc25Smrg    fd = pPriv->fd;
654f29dbc25Smrg    if (pPriv->dir > 0) {
65504007ebaSmrg        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
65604007ebaSmrg        ioctl(fd, VIDIOC_STREAMOFF, &type);
657f29dbc25Smrg    }
658f29dbc25Smrg
659f29dbc25Smrg    if (pPriv->dir <= 0) {
66004007ebaSmrg        enable = 0;
66104007ebaSmrg        ioctl(fd, VIDIOC_OVERLAY, &enable);
662f29dbc25Smrg    }
663f29dbc25Smrg
664f29dbc25Smrg    if (pPriv->dir != 0)
66504007ebaSmrg        z4l_ovly_unmap(pPriv);
666f29dbc25Smrg
667f29dbc25Smrg    pPriv->run = -1;
668f29dbc25Smrg    z4l_close_device(pPriv);
669f29dbc25Smrg}
670f29dbc25Smrg
671f29dbc25Smrgstatic void
672f29dbc25Smrgz4l_ovly_start(Z4lPortPrivRec * pPriv, int dir)
673f29dbc25Smrg{
674f29dbc25Smrg    int enable;
675f29dbc25Smrg
676f29dbc25Smrg    if (pPriv->run >= 0)
67704007ebaSmrg        return;
678f29dbc25Smrg
679f29dbc25Smrg    if ((pPriv->dir = dir) != 0)
68004007ebaSmrg        z4l_ovly_map(pPriv, dir);
681f29dbc25Smrg
682f29dbc25Smrg    enable = 1;
683f29dbc25Smrg
684f29dbc25Smrg    if (IoCtl(pPriv->fd, VIDIOC_OVERLAY, &enable, 1) != 0) {
68504007ebaSmrg        z4l_ovly_stop(pPriv);
68604007ebaSmrg        return;
687f29dbc25Smrg    }
688f29dbc25Smrg
689f29dbc25Smrg    pPriv->run = 1;
690f29dbc25Smrg}
691f29dbc25Smrg
692f29dbc25Smrgstatic int
693f29dbc25Smrgz4l_region_equal(RegionPtr ap, RegionPtr bp)
694f29dbc25Smrg{
695f29dbc25Smrg    int nboxes;
696f29dbc25Smrg    BoxPtr abox, bbox;
697f29dbc25Smrg
698f29dbc25Smrg    if (ap == NULL && bp == NULL)
69904007ebaSmrg        return 1;
700f29dbc25Smrg    if (ap == NULL || bp == NULL)
70104007ebaSmrg        return 0;
702f29dbc25Smrg
703f29dbc25Smrg    if ((nboxes = REGION_NUM_RECTS(ap)) != REGION_NUM_RECTS(bp) ||
70404007ebaSmrg        ap->extents.x1 != bp->extents.x1 ||
70504007ebaSmrg        ap->extents.x2 != bp->extents.x2
70604007ebaSmrg        || ap->extents.y1 != bp->extents.y1 || ap->extents.y2 != bp->extents.y2)
70704007ebaSmrg        return 0;
708f29dbc25Smrg
709f29dbc25Smrg    abox = REGION_RECTS(ap);
710f29dbc25Smrg    bbox = REGION_RECTS(bp);
711f29dbc25Smrg
712f29dbc25Smrg    while (--nboxes >= 0) {
71304007ebaSmrg        if (abox->x1 != bbox->x1 || abox->y1 != bbox->y1 ||
71404007ebaSmrg            abox->x2 != bbox->x2 || abox->y2 != bbox->y2)
71504007ebaSmrg            return 0;
71604007ebaSmrg        ++abox;
71704007ebaSmrg        ++bbox;
718f29dbc25Smrg    }
719f29dbc25Smrg
720f29dbc25Smrg    return 1;
721f29dbc25Smrg}
722f29dbc25Smrg
723f29dbc25Smrgstatic void
72404007ebaSmrgz4l_setup_colorkey(Z4lPortPrivRec * pPriv, ScreenPtr pScrn, RegionPtr clipBoxes)
725f29dbc25Smrg{
726f29dbc25Smrg    if (pPriv->run > 0 && pPriv->dir <= 0 && pPriv->keymode != 0 &&
72704007ebaSmrg        z4l_region_equal(&pPriv->clips, clipBoxes) == 0) {
72804007ebaSmrg        xf86XVFillKeyHelper(pScrn, pPriv->colorkey, clipBoxes);
72904007ebaSmrg        REGION_COPY(pScrn, &pPriv->clips, clipBoxes);
730f29dbc25Smrg    }
731f29dbc25Smrg}
732f29dbc25Smrg
733f29dbc25Smrgstatic void
734f29dbc25SmrgZ4lStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
735f29dbc25Smrg{
736f29dbc25Smrg    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
737f29dbc25Smrg
738f29dbc25Smrg    DBLOG(1, "Z4lStopVideo()\n");
739f29dbc25Smrg
740f29dbc25Smrg    if (exit != 0)
74104007ebaSmrg        z4l_ovly_stop(pPriv);
742f29dbc25Smrg    else
74304007ebaSmrg        pPriv->src_is_set = pPriv->drw_is_set = 0;
744f29dbc25Smrg
745f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clips);
746f29dbc25Smrg}
747f29dbc25Smrg
748f29dbc25Smrgstatic void
749f29dbc25SmrgZ4lQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
75004007ebaSmrg                 short vid_w, short vid_h, short drw_w, short drw_h,
75104007ebaSmrg                 unsigned int *p_w, unsigned int *p_h, pointer data)
752f29dbc25Smrg{
753f29dbc25Smrg    if (drw_w > MAX_OVLY_WIDTH)
75404007ebaSmrg        drw_w = MAX_OVLY_WIDTH;
755f29dbc25Smrg    if (drw_h > MAX_OVLY_HEIGHT)
75604007ebaSmrg        drw_h = MAX_OVLY_HEIGHT;
757f29dbc25Smrg
758f29dbc25Smrg    *p_w = drw_w;
759f29dbc25Smrg    *p_h = drw_h;
760f29dbc25Smrg    DBLOG(1, "Z4lQueryBestSize(%d, src %dx%d dst %dx%d)\n", motion, vid_w,
76104007ebaSmrg          vid_h, drw_w, drw_h);
762f29dbc25Smrg}
763f29dbc25Smrg
764f29dbc25Smrgstatic int
765f29dbc25SmrgZ4lPutImage(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x,
76604007ebaSmrg            short drw_y, short src_w, short src_h, short drw_w, short drw_h,
76704007ebaSmrg            int id, unsigned char *buf, short width, short height,
76804007ebaSmrg            Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
769f29dbc25Smrg{
770f29dbc25Smrg    int fd, size;
771f29dbc25Smrg    int y_pitch, uv_pitch, offset1, offset2;
772f29dbc25Smrg    unsigned char *src, *dst;
773f29dbc25Smrg    unsigned int pixfmt;
774f29dbc25Smrg    struct v4l2_buffer bfr;
775f29dbc25Smrg    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
776f29dbc25Smrg
777f29dbc25Smrg    if (pPriv->run > 0 && pPriv->dir >= 0)
77804007ebaSmrg        return BadMatch;
779f29dbc25Smrg    if (pPriv->fd < 0) {
78004007ebaSmrg        z4l_open_device(pPriv);
78104007ebaSmrg        if (pPriv->fd < 0)
78204007ebaSmrg            return BadValue;
783f29dbc25Smrg    }
784f29dbc25Smrg
785f29dbc25Smrg    fd = pPriv->fd;
786f29dbc25Smrg    if (pPriv->run < 0) {
78704007ebaSmrg        DBLOG(2, "PutImg id %#x src %d,%d %dx%d drw %d,%d %dx%d bfr %p "
78804007ebaSmrg              "%dx%d data %p\n", id, src_x, src_y, src_w, src_h, drw_x,
78904007ebaSmrg              drw_y, drw_w, drw_h, buf, width, height, data);
79004007ebaSmrg        pPriv->pixfmt = pPriv->height = -1;
79104007ebaSmrg        pPriv->src_is_set = pPriv->drw_is_set = 0;
792f29dbc25Smrg    }
793f29dbc25Smrg
794f29dbc25Smrg    pixfmt = z4l_fourcc_pixfmt(id);
795f29dbc25Smrg    if (pixfmt != pPriv->pixfmt) {
79604007ebaSmrg        z4l_ovly_reset(pPriv);
79704007ebaSmrg        z4l_ovly_pixfmt(pPriv, pixfmt);
798f29dbc25Smrg    }
799f29dbc25Smrg    if (pPriv->width != width || pPriv->height != height) {
80004007ebaSmrg        z4l_ovly_reset(pPriv);
80104007ebaSmrg        z4l_ovly_bfr(pPriv, width, height);
802f29dbc25Smrg    }
803f29dbc25Smrg
804f29dbc25Smrg    if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 ||
80504007ebaSmrg        pPriv->src_x != src_x || pPriv->src_y != src_y ||
80604007ebaSmrg        pPriv->src_w != src_w || pPriv->src_h != src_h ||
80704007ebaSmrg        pPriv->drw_x != drw_x || pPriv->drw_y != drw_y ||
80804007ebaSmrg        pPriv->drw_w != drw_w || pPriv->drw_h != drw_h)
80904007ebaSmrg        z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w,
81004007ebaSmrg                      drw_h);
811f29dbc25Smrg
812f29dbc25Smrg    if (pPriv->run < 0) {
81304007ebaSmrg        z4l_ovly_start(pPriv, -1);
81404007ebaSmrg        if (pPriv->run < 0)
81504007ebaSmrg            return BadValue;
816f29dbc25Smrg    }
817f29dbc25Smrg
818f29dbc25Smrg    if (pPriv->last < 0 && (pPriv->last = z4l_ovly_dqbuf(pPriv)) < 0)
81904007ebaSmrg        return BadAlloc;
820f29dbc25Smrg
821f29dbc25Smrg    z4l_ovly_pitch(pixfmt, width, height, &y_pitch, &uv_pitch,
82204007ebaSmrg                   &offset1, &offset2, &size);
823f29dbc25Smrg    src = buf;
82404007ebaSmrg    dst = (unsigned char *) pPriv->bfrs[pPriv->last].start;
825f29dbc25Smrg    DBLOG(3, "cpy %4.4s src %p dst %p yp %d uvp %d o1 %d o2 %d sz %d\n",
82604007ebaSmrg          (char *) &id, src, dst, y_pitch, uv_pitch, offset1, offset2, size);
827f29dbc25Smrg
828f29dbc25Smrg    if (id == FOURCC_Y800) {
82904007ebaSmrg        memcpy(dst, src, offset1);
83004007ebaSmrg        src += offset1;
83104007ebaSmrg        dst += offset1;
83204007ebaSmrg        memset(dst, 0x80, 2 * offset2);
83304007ebaSmrg    }
83404007ebaSmrg    else
83504007ebaSmrg        memcpy(dst, src, size);
836f29dbc25Smrg
837f29dbc25Smrg    memset(&bfr, 0, sizeof(bfr));
838f29dbc25Smrg    bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
839f29dbc25Smrg    bfr.index = pPriv->last;
840f29dbc25Smrg    bfr.timestamp.tv_sec = 0;
841f29dbc25Smrg    bfr.timestamp.tv_usec = 0;
842f29dbc25Smrg    bfr.flags |= V4L2_BUF_FLAG_TIMECODE;
843f29dbc25Smrg    if (IoCtl(fd, VIDIOC_QBUF, &bfr, 1) != 0)
84404007ebaSmrg        return BadAccess;
845f29dbc25Smrg
846f29dbc25Smrg    pPriv->last = z4l_ovly_dqbuf(pPriv);
847f29dbc25Smrg    z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes);
848f29dbc25Smrg
849f29dbc25Smrg    return Success;
850f29dbc25Smrg}
851f29dbc25Smrg
852f29dbc25Smrgstatic int
853f29dbc25SmrgZ4lQueryImageAttributes(ScrnInfoPtr pScrni, int id, unsigned short *width,
85404007ebaSmrg                        unsigned short *height, int *pitches, int *offsets)
855f29dbc25Smrg{
856f29dbc25Smrg    int w, h, size;
857f29dbc25Smrg    int y_pitch, uv_pitch, offset1, offset2;
858f29dbc25Smrg    unsigned int pixfmt = z4l_fourcc_pixfmt(id);
859f29dbc25Smrg
860f29dbc25Smrg    w = *width;
861f29dbc25Smrg    h = *height;
862f29dbc25Smrg    if (w > MAX_OVLY_WIDTH)
86304007ebaSmrg        w = MAX_OVLY_WIDTH;
864f29dbc25Smrg    if (h > MAX_OVLY_HEIGHT)
86504007ebaSmrg        h = MAX_OVLY_HEIGHT;
866f29dbc25Smrg
867f29dbc25Smrg    z4l_ovly_pitch(pixfmt, w, h, &y_pitch, &uv_pitch,
86804007ebaSmrg                   &offset1, &offset2, &size);
869f29dbc25Smrg
870f29dbc25Smrg    if (offsets != NULL)
87104007ebaSmrg        offsets[0] = 0;
872f29dbc25Smrg    if (pitches != NULL)
87304007ebaSmrg        pitches[0] = y_pitch;
874f29dbc25Smrg
875f29dbc25Smrg    switch (pixfmt) {
876f29dbc25Smrg    case V4L2_PIX_FMT_YVU420:
877f29dbc25Smrg    case V4L2_PIX_FMT_YUV420:
87804007ebaSmrg        if (offsets != NULL) {
87904007ebaSmrg            offsets[1] = offset1;
88004007ebaSmrg            offsets[2] = offset1 + offset2;
88104007ebaSmrg        }
88204007ebaSmrg        if (pitches != NULL)
88304007ebaSmrg            pitches[1] = pitches[2] = uv_pitch;
88404007ebaSmrg        h = (h + 1) & ~1;
88504007ebaSmrg        break;
886f29dbc25Smrg    }
887f29dbc25Smrg
888f29dbc25Smrg    w = (w + 1) & ~1;
889f29dbc25Smrg    *width = w;
890f29dbc25Smrg    *height = h;
891f29dbc25Smrg    DBLOG(1, "Z4lQueryImageAttributes(%4.4s) = %d, %dx%d %d/%d %d/%d\n",
89204007ebaSmrg          (char *) &id, size, w, h, y_pitch, uv_pitch, offset1, offset2);
893f29dbc25Smrg
894f29dbc25Smrg    return size;
895f29dbc25Smrg}
896f29dbc25Smrg
897f29dbc25Smrgstatic int
898f29dbc25SmrgZ4lPutVideo(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x,
89904007ebaSmrg            short drw_y, short src_w, short src_h, short drw_w, short drw_h,
90004007ebaSmrg            RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
901f29dbc25Smrg{
902f29dbc25Smrg    int id;
903f29dbc25Smrg    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
904f29dbc25Smrg
905f29dbc25Smrg    DBLOG(2, "PutVid src %d,%d %dx%d drw %d,%d %dx%d data %p\n",
90604007ebaSmrg          src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w, drw_h, data);
907f29dbc25Smrg
908f29dbc25Smrg    if (z4l_open_device(pPriv) >= 0) {
90904007ebaSmrg        if (pPriv->run < 0) {
91004007ebaSmrg            DBLOG(2, "PutVid start\n");
91104007ebaSmrg            z4l_ovly_get_encoding(pPriv, &id);
91204007ebaSmrg            z4l_ovly_set_encoding(pPriv, id);
91304007ebaSmrg        }
91404007ebaSmrg        DBLOG(2, "PutVid priv %d,%d %dx%d drw %d,%d %dx%d\n",
91504007ebaSmrg              pPriv->src_x, pPriv->src_y, pPriv->src_w, pPriv->src_h,
91604007ebaSmrg              pPriv->drw_x, pPriv->drw_y, pPriv->drw_w, pPriv->drw_h);
91704007ebaSmrg        if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 ||
91804007ebaSmrg            pPriv->src_w != src_w || pPriv->src_h != src_h ||
91904007ebaSmrg            pPriv->drw_x != drw_x || pPriv->drw_y != drw_y ||
92004007ebaSmrg            pPriv->drw_w != drw_w || pPriv->drw_h != drw_h)
92104007ebaSmrg            z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y,
92204007ebaSmrg                          drw_w, drw_h);
92304007ebaSmrg        if (pPriv->run < 0)
92404007ebaSmrg            z4l_ovly_start(pPriv, 0);
92504007ebaSmrg
92604007ebaSmrg        z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes);
927f29dbc25Smrg    }
928f29dbc25Smrg
929f29dbc25Smrg    return Success;
930f29dbc25Smrg}
931f29dbc25Smrg
932f29dbc25Smrgstatic XF86VideoEncodingPtr
933f29dbc25SmrgZ4lNewEncoding(XF86VideoEncodingPtr * encs, int *nencs)
934f29dbc25Smrg{
935f29dbc25Smrg    XF86VideoEncodingPtr enc;
936f29dbc25Smrg    XF86VideoEncodingPtr tencs =
93704007ebaSmrg        (XF86VideoEncodingPtr) realloc(*encs, sizeof(*tencs) * (*nencs + 1));
938f29dbc25Smrg
939f29dbc25Smrg    if (tencs == NULL)
94004007ebaSmrg        return NULL;
941f29dbc25Smrg
942f29dbc25Smrg    *encs = tencs;
943f29dbc25Smrg    enc = &tencs[*nencs];
944f29dbc25Smrg    ++*nencs;
945f29dbc25Smrg    memset(enc, 0, sizeof(*enc));
946f29dbc25Smrg
947f29dbc25Smrg    return enc;
948f29dbc25Smrg}
949f29dbc25Smrg
950f29dbc25Smrgstatic void
951f29dbc25SmrgZ4lEncodingName(char *ename, int l, char *inp_name, char *std_name, char *fmt)
952f29dbc25Smrg{
953f29dbc25Smrg    int i, ch;
954f29dbc25Smrg
955f29dbc25Smrg    while ((ch = *inp_name++) != 0) {
95604007ebaSmrg        if (isalnum(ch) == 0)
95704007ebaSmrg            continue;
95804007ebaSmrg        if (--l <= 0)
95904007ebaSmrg            goto xit;
96004007ebaSmrg        *ename++ = ch;
961f29dbc25Smrg    }
962f29dbc25Smrg
963f29dbc25Smrg    if (--l <= 0)
96404007ebaSmrg        goto xit;
965f29dbc25Smrg
966f29dbc25Smrg    *ename++ = '-';
967f29dbc25Smrg
968f29dbc25Smrg    while ((ch = *std_name++) != 0) {
96904007ebaSmrg        if (isalnum(ch) == 0)
97004007ebaSmrg            continue;
97104007ebaSmrg        if (--l <= 0)
97204007ebaSmrg            goto xit;
97304007ebaSmrg        *ename++ = ch;
974f29dbc25Smrg    }
975f29dbc25Smrg
976f29dbc25Smrg    if (--l <= 0)
97704007ebaSmrg        goto xit;
978f29dbc25Smrg
979f29dbc25Smrg    *ename++ = '-';
980f29dbc25Smrg    i = 4;
981f29dbc25Smrg
982f29dbc25Smrg    while (--i >= 0 && (ch = *fmt++) != 0) {
98304007ebaSmrg        if (isalnum(ch) == 0)
98404007ebaSmrg            continue;
98504007ebaSmrg        if (--l <= 0)
98604007ebaSmrg            goto xit;
98704007ebaSmrg        *ename++ = ch;
988f29dbc25Smrg    }
989f29dbc25Smrg
99004007ebaSmrg xit:
991f29dbc25Smrg    *ename = 0;
992f29dbc25Smrg}
993f29dbc25Smrg
994f29dbc25Smrgstatic int
995f29dbc25SmrgZ4lAddEncoding(XF86VideoEncodingPtr enc, char *name, int id, int width,
99604007ebaSmrg               int height, int numer, int denom, int inp, v4l2_std_id std,
99704007ebaSmrg               unsigned int fmt)
998f29dbc25Smrg{
999f29dbc25Smrg    int l, n;
1000f29dbc25Smrg    t_std_data *sp;
1001f29dbc25Smrg    char *cp;
100204007ebaSmrg
1003f29dbc25Smrg    n = sizeof(int) - 1;
1004f29dbc25Smrg    l = strlen(&name[0]) + 1;
1005f29dbc25Smrg    l = (l + n) & ~n;
1006f29dbc25Smrg    n = l + sizeof(*sp);
100704007ebaSmrg    cp = (char *) malloc(n);
1008f29dbc25Smrg
1009f29dbc25Smrg    if (cp == NULL)
101004007ebaSmrg        return 0;
1011f29dbc25Smrg
1012f29dbc25Smrg    sp = (t_std_data *) (cp + l);
1013f29dbc25Smrg    enc->id = id;
1014f29dbc25Smrg    strcpy(cp, &name[0]);
1015f29dbc25Smrg    enc->name = cp;
1016f29dbc25Smrg    enc->width = width;
1017f29dbc25Smrg    enc->height = height;
1018f29dbc25Smrg    enc->rate.numerator = numer;
1019f29dbc25Smrg    enc->rate.denominator = denom;
1020f29dbc25Smrg    sp->inp = inp;
1021f29dbc25Smrg    sp->std = std;
1022f29dbc25Smrg    sp->fmt = fmt;
1023f29dbc25Smrg    DBLOG(1, "enc %s\n", &name[0]);
1024f29dbc25Smrg
1025f29dbc25Smrg    return 1;
1026f29dbc25Smrg}
1027f29dbc25Smrg
1028f29dbc25Smrgstatic XF86ImagePtr
1029f29dbc25SmrgZ4lNewImage(XF86ImagePtr * imgs, int *nimgs)
1030f29dbc25Smrg{
1031f29dbc25Smrg    XF86ImagePtr img;
1032f29dbc25Smrg    XF86ImagePtr timgs =
103304007ebaSmrg        (XF86ImagePtr) realloc(*imgs, sizeof(*timgs) * (*nimgs + 1));
1034f29dbc25Smrg
1035f29dbc25Smrg    if (timgs == NULL)
103604007ebaSmrg        return NULL;
1037f29dbc25Smrg
1038f29dbc25Smrg    *imgs = timgs;
1039f29dbc25Smrg    img = &timgs[*nimgs];
1040f29dbc25Smrg    ++*nimgs;
1041f29dbc25Smrg    memset(img, 0, sizeof(*img));
1042f29dbc25Smrg
1043f29dbc25Smrg    return img;
1044f29dbc25Smrg}
1045f29dbc25Smrg
1046f29dbc25Smrgstatic int
1047f29dbc25SmrgZ4lAddImage(XF86ImagePtr img, XF86ImagePtr ip)
1048f29dbc25Smrg{
1049f29dbc25Smrg    *img = *ip;
105004007ebaSmrg    DBLOG(1, "img %4.4s\n", (char *) &img->id);
1051f29dbc25Smrg    return 1;
1052f29dbc25Smrg}
1053f29dbc25Smrg
1054f29dbc25Smrgstatic XF86AttributePtr
1055f29dbc25SmrgZ4lNewAttribute(XF86AttributePtr * attrs, int *nattrs)
1056f29dbc25Smrg{
1057f29dbc25Smrg    XF86AttributePtr attr;
1058f29dbc25Smrg    XF86AttributePtr tattrs =
105904007ebaSmrg        (XF86AttributePtr) realloc(*attrs, sizeof(*tattrs) * (*nattrs + 1));
1060f29dbc25Smrg
1061f29dbc25Smrg    if (tattrs == NULL)
106204007ebaSmrg        return NULL;
1063f29dbc25Smrg
1064f29dbc25Smrg    *attrs = tattrs;
1065f29dbc25Smrg    attr = &tattrs[*nattrs];
1066f29dbc25Smrg    ++*nattrs;
1067f29dbc25Smrg    memset(attr, 0, sizeof(*attr));
1068f29dbc25Smrg
1069f29dbc25Smrg    return attr;
1070f29dbc25Smrg}
1071f29dbc25Smrg
1072f29dbc25Smrgstatic void
1073f29dbc25SmrgZ4lAttributeName(char *bp, int l, char *cp)
1074f29dbc25Smrg{
1075f29dbc25Smrg    int ch;
1076f29dbc25Smrg    char *atomNm = bp;
1077f29dbc25Smrg
1078f29dbc25Smrg    if (l > 0) {
107904007ebaSmrg        *bp++ = 'X';
108004007ebaSmrg        --l;
1081f29dbc25Smrg    }
1082f29dbc25Smrg    if (l > 0) {
108304007ebaSmrg        *bp++ = 'V';
108404007ebaSmrg        --l;
1085f29dbc25Smrg    }
1086f29dbc25Smrg    if (l > 0) {
108704007ebaSmrg        *bp++ = '_';
108804007ebaSmrg        --l;
1089f29dbc25Smrg    }
1090f29dbc25Smrg
1091f29dbc25Smrg    while (l > 0 && (ch = *cp++) != 0) {
109204007ebaSmrg        if (isalnum(ch) == 0)
109304007ebaSmrg            continue;
109404007ebaSmrg        *bp++ = toupper(ch);
1095f29dbc25Smrg    }
1096f29dbc25Smrg
1097f29dbc25Smrg    *bp = 0;
1098f29dbc25Smrg    MakeAtom(&atomNm[0], strlen(&atomNm[0]), TRUE);
1099f29dbc25Smrg}
1100f29dbc25Smrg
1101f29dbc25Smrgstatic int
110204007ebaSmrgZ4lAddAttribute(XF86AttributePtr attr, char *name, int min, int max, int flags)
1103f29dbc25Smrg{
110404007ebaSmrg    char *cp = (char *) malloc(strlen((char *) &name[0]) + 1);
1105f29dbc25Smrg
1106f29dbc25Smrg    if (cp == NULL)
110704007ebaSmrg        return 0;
1108f29dbc25Smrg
1109f29dbc25Smrg    attr->name = cp;
1110f29dbc25Smrg    strcpy(&attr->name[0], name);
1111f29dbc25Smrg    attr->min_value = min;
1112f29dbc25Smrg    attr->max_value = max;
1113f29dbc25Smrg    attr->flags = flags;
1114f29dbc25Smrg    DBLOG(1, "attr %s\n", attr->name);
1115f29dbc25Smrg
1116f29dbc25Smrg    return 1;
1117f29dbc25Smrg}
1118f29dbc25Smrg
1119f29dbc25Smrgstatic XF86VideoAdaptorPtr
1120f29dbc25SmrgZ4lNewAdaptor(XF86VideoAdaptorPtr ** adpts, int *nadpts, int nattrs)
1121f29dbc25Smrg{
1122f29dbc25Smrg    int n;
1123f29dbc25Smrg    Z4lPortPrivRec *pPriv;
1124f29dbc25Smrg    XF86VideoAdaptorPtr adpt, *tadpts;
1125f29dbc25Smrg
1126170d5fdcSmrg    tadpts = (XF86VideoAdaptorPtr *) realloc(*adpts,
112704007ebaSmrg                                             sizeof(*tadpts) * (*nadpts + 1));
1128f29dbc25Smrg
1129f29dbc25Smrg    if (tadpts == NULL)
113004007ebaSmrg        return NULL;
1131f29dbc25Smrg
1132f29dbc25Smrg    *adpts = tadpts;
1133f29dbc25Smrg    n = sizeof(*adpt) + sizeof(*pPriv) + 1 * sizeof(*adpt->pPortPrivates);
1134f29dbc25Smrg    n += (nattrs - 1) * sizeof(pPriv->attrIds[0]);
1135170d5fdcSmrg    adpt = (XF86VideoAdaptorPtr) malloc(n);
1136f29dbc25Smrg
1137f29dbc25Smrg    if (adpt == NULL)
113804007ebaSmrg        return NULL;
1139f29dbc25Smrg
1140f29dbc25Smrg    memset(adpt, 0, n);
1141f29dbc25Smrg    tadpts[*nadpts] = adpt;
1142f29dbc25Smrg    ++*nadpts;
114304007ebaSmrg    adpt->pPortPrivates = (DevUnion *) &adpt[1];
1144f29dbc25Smrg    pPriv = (Z4lPortPrivRec *) & adpt->pPortPrivates[1];
1145f29dbc25Smrg    adpt->pPortPrivates[0].ptr = (pointer) pPriv;
1146f29dbc25Smrg    pPriv->adpt = adpt;
1147f29dbc25Smrg    adpt->nPorts = 1;
1148f29dbc25Smrg
1149f29dbc25Smrg    return adpt;
1150f29dbc25Smrg}
1151f29dbc25Smrg
1152f29dbc25Smrgstatic int
1153f29dbc25SmrgZ4lSetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value,
115404007ebaSmrg                    pointer data)
1155f29dbc25Smrg{
1156f29dbc25Smrg    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
1157f29dbc25Smrg    XF86VideoAdaptorPtr adpt;
1158f29dbc25Smrg    XF86AttributePtr attr;
1159f29dbc25Smrg    struct v4l2_control ctrl;
1160f29dbc25Smrg    int i, nattrs, attrId, val;
1161170d5fdcSmrg    const char *name = NameForAtom(attribute);
1162f29dbc25Smrg    int old_fd = pPriv->fd;
1163f29dbc25Smrg
116404007ebaSmrg    DBLOG(1, "Z4lSetPortAttribute(%#lx,%d) '%s'\n", (unsigned long) attribute,
116504007ebaSmrg          (int) value, name != NULL ? name : "_null_");
1166f29dbc25Smrg
1167f29dbc25Smrg    if (name == NULL)
116804007ebaSmrg        return BadImplementation;
1169f29dbc25Smrg    if (old_fd < 0 && z4l_open_device(pPriv) < 0)
117004007ebaSmrg        return BadAccess;
1171f29dbc25Smrg
1172f29dbc25Smrg    adpt = pPriv->adpt;
1173f29dbc25Smrg    attr = adpt->pAttributes;
1174f29dbc25Smrg    nattrs = adpt->nAttributes;
1175f29dbc25Smrg
1176f29dbc25Smrg    for (i = 0; i < nattrs; ++i, ++attr)
117704007ebaSmrg        if (strcmp(attr->name, name) == 0)
117804007ebaSmrg            break;
1179f29dbc25Smrg
1180f29dbc25Smrg    if (i >= nattrs)
118104007ebaSmrg        return BadMatch;
1182f29dbc25Smrg
1183f29dbc25Smrg    attrId = pPriv->attrIds[i];
1184f29dbc25Smrg    val = value;
1185f29dbc25Smrg
1186f29dbc25Smrg    switch (attrId) {
1187f29dbc25Smrg    case ATTR_ENCODING_ID:
118804007ebaSmrg        z4l_ovly_set_encoding(pPriv, val);
118904007ebaSmrg        break;
1190f29dbc25Smrg    case ATTR_KEYMODE_ID:
119104007ebaSmrg        z4l_ovly_set_keymode(pPriv, val);
119204007ebaSmrg        REGION_EMPTY(pScrni->pScreen, &pPriv->clips);
119304007ebaSmrg        z4l_setup_colorkey(pPriv, pScrni->pScreen, &pPriv->clips);
119404007ebaSmrg        break;
1195f29dbc25Smrg    case ATTR_COLORKEY_ID:
119604007ebaSmrg        z4l_ovly_set_colorkey(pPriv, val);
119704007ebaSmrg        break;
1198f29dbc25Smrg    default:
119904007ebaSmrg        memset(&ctrl, 0, sizeof(ctrl));
120004007ebaSmrg        ctrl.id = attrId + V4L2_CID_BASE;
120104007ebaSmrg        ctrl.value = val;
120204007ebaSmrg        if (IoCtl(pPriv->fd, VIDIOC_S_CTRL, &ctrl, 1) != 0)
120304007ebaSmrg            return BadMatch;
120404007ebaSmrg        break;
1205f29dbc25Smrg    }
1206f29dbc25Smrg
1207f29dbc25Smrg    if (old_fd < 0)
120804007ebaSmrg        z4l_close_device(pPriv);
1209f29dbc25Smrg
1210f29dbc25Smrg    return Success;
1211f29dbc25Smrg}
1212f29dbc25Smrg
1213f29dbc25Smrgstatic int
121404007ebaSmrgZ4lGetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 *value,
121504007ebaSmrg                    pointer data)
1216f29dbc25Smrg{
1217f29dbc25Smrg    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
1218f29dbc25Smrg    XF86VideoAdaptorPtr adpt;
1219f29dbc25Smrg    XF86AttributePtr attr;
1220f29dbc25Smrg    struct v4l2_control ctrl;
1221f29dbc25Smrg    int i, nattrs, attrId, val;
1222170d5fdcSmrg    const char *name = NameForAtom(attribute);
1223f29dbc25Smrg    int old_fd = pPriv->fd;
1224f29dbc25Smrg
1225f29dbc25Smrg    DBLOG(1, "Z4lGetPortAttribute(%#lx) '%s'\n",
122604007ebaSmrg          (unsigned long) attribute, name != NULL ? name : "_null_");
1227f29dbc25Smrg
1228f29dbc25Smrg    if (name == NULL)
122904007ebaSmrg        return BadImplementation;
1230f29dbc25Smrg    if (old_fd < 0 && z4l_open_device(pPriv) < 0)
123104007ebaSmrg        return BadAccess;
1232f29dbc25Smrg
1233f29dbc25Smrg    adpt = pPriv->adpt;
1234f29dbc25Smrg    attr = adpt->pAttributes;
1235f29dbc25Smrg    nattrs = adpt->nAttributes;
1236f29dbc25Smrg
1237f29dbc25Smrg    for (i = 0; i < nattrs; ++i, ++attr)
123804007ebaSmrg        if (strcmp(attr->name, name) == 0)
123904007ebaSmrg            break;
1240f29dbc25Smrg
1241f29dbc25Smrg    if (i >= nattrs)
124204007ebaSmrg        return BadMatch;
1243f29dbc25Smrg
1244f29dbc25Smrg    attrId = pPriv->attrIds[i];
1245f29dbc25Smrg    val = 0;
1246f29dbc25Smrg
1247f29dbc25Smrg    switch (attrId) {
1248f29dbc25Smrg    case ATTR_ENCODING_ID:
124904007ebaSmrg        z4l_ovly_get_encoding(pPriv, &val);
125004007ebaSmrg        *value = val;
125104007ebaSmrg        break;
1252f29dbc25Smrg    case ATTR_KEYMODE_ID:
125304007ebaSmrg        z4l_ovly_get_keymode(pPriv, &val);
125404007ebaSmrg        *value = val;
125504007ebaSmrg        break;
1256f29dbc25Smrg    case ATTR_COLORKEY_ID:
125704007ebaSmrg        z4l_ovly_get_colorkey(pPriv, &val);
125804007ebaSmrg        break;
1259f29dbc25Smrg    default:
126004007ebaSmrg        memset(&ctrl, 0, sizeof(ctrl));
126104007ebaSmrg        ctrl.id = attrId + V4L2_CID_BASE;
126204007ebaSmrg        if (IoCtl(pPriv->fd, VIDIOC_G_CTRL, &ctrl, 1) != 0)
126304007ebaSmrg            return BadMatch;
126404007ebaSmrg        val = ctrl.value;
126504007ebaSmrg        break;
1266f29dbc25Smrg    }
1267f29dbc25Smrg
1268f29dbc25Smrg    if (old_fd < 0)
126904007ebaSmrg        z4l_close_device(pPriv);
1270f29dbc25Smrg
1271f29dbc25Smrg    *value = val;
1272f29dbc25Smrg
1273f29dbc25Smrg    return Success;
1274f29dbc25Smrg}
1275f29dbc25Smrg
127604007ebaSmrgstatic void (*oldAdjustFrame) (ADJUST_FRAME_ARGS_DECL) = NULL;
1277f29dbc25Smrg
1278f29dbc25Smrgstatic void
127904007ebaSmrgZ4lAdjustFrame(ADJUST_FRAME_ARGS_DECL)
1280f29dbc25Smrg{
128104007ebaSmrg    SCRN_INFO_PTR(arg);
1282f29dbc25Smrg    int i;
1283f29dbc25Smrg    XF86VideoAdaptorPtr adpt;
1284f29dbc25Smrg    Z4lPortPrivRec *pPriv;
1285f29dbc25Smrg
128604007ebaSmrg    DBLOG(3, "Z4lAdjustFrame(%d,%d)\n", x, y);
1287f29dbc25Smrg    z4l_x_offset = x;
1288f29dbc25Smrg    z4l_y_offset = y;
128904007ebaSmrg    oldAdjustFrame(ADJUST_FRAME_ARGS(x, y));
1290f29dbc25Smrg
1291f29dbc25Smrg    /* xv adjust does not handle putvideo case */
1292f29dbc25Smrg    for (i = 0; i < Z4l_nAdaptors; ++i) {
129304007ebaSmrg        adpt = Z4l_pAdaptors[i];
129404007ebaSmrg        pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr;
129504007ebaSmrg        if (pPriv->run > 0) {
129604007ebaSmrg            pPriv->drw_is_set = 0;
129704007ebaSmrg            z4l_ovly_rect(pPriv,
129804007ebaSmrg                          pPriv->src_x, pPriv->src_y, pPriv->src_w,
129904007ebaSmrg                          pPriv->src_h, pPriv->drw_x, pPriv->drw_y,
130004007ebaSmrg                          pPriv->drw_w, pPriv->drw_h);
130104007ebaSmrg        }
1302f29dbc25Smrg    }
1303f29dbc25Smrg}
1304f29dbc25Smrg
1305f29dbc25Smrgstatic int
1306f29dbc25SmrgZ4lInit(ScrnInfoPtr pScrni, XF86VideoAdaptorPtr ** adaptors)
1307f29dbc25Smrg{
1308f29dbc25Smrg    int i, id, fd, dev, enable, has_video, has_colorkey;
1309f29dbc25Smrg    int ctl, cinp, inp, std, fmt, has_image;
1310f29dbc25Smrg    int nadpts, nattrs, nencs, cenc, nimgs;
1311f29dbc25Smrg    int numer, denom, width, height;
1312f29dbc25Smrg    unsigned int pixfmt, cpixfmt, opixfmt;
1313f29dbc25Smrg    XF86VideoAdaptorPtr *adpts, adpt;
1314f29dbc25Smrg    XF86AttributePtr attrs, attr;
1315f29dbc25Smrg    XF86VideoEncodingPtr encs, enc;
1316f29dbc25Smrg    XF86ImagePtr ip, img, imgs;
1317f29dbc25Smrg    Z4lPortPrivRec *pPriv;
1318f29dbc25Smrg    char *dp, *msg;
1319f29dbc25Smrg    char enc_name[256], attr_name[256];
1320f29dbc25Smrg    int attrIds[V4L2_CID_LASTP1 - V4L2_CID_BASE + ATTR_MAX_ID];
1321f29dbc25Smrg    struct v4l2_capability capability;
1322f29dbc25Smrg    v4l2_std_id cstd_id, std_id;
1323f29dbc25Smrg    struct v4l2_standard standard;
1324f29dbc25Smrg    struct v4l2_format format, cfmt;
1325f29dbc25Smrg    struct v4l2_input input;
1326f29dbc25Smrg    struct v4l2_fmtdesc fmtdesc;
1327f29dbc25Smrg    struct v4l2_queryctrl queryctrl;
1328f29dbc25Smrg    struct v4l2_framebuffer fbuf;
1329f29dbc25Smrg
1330f29dbc25Smrg    DBLOG(1, "Init\n");
1331f29dbc25Smrg    if (oldAdjustFrame == NULL) {
133204007ebaSmrg        oldAdjustFrame = pScrni->AdjustFrame;
133304007ebaSmrg        pScrni->AdjustFrame = Z4lAdjustFrame;
1334f29dbc25Smrg    }
1335f29dbc25Smrg
1336f29dbc25Smrg    fd = -1;
1337f29dbc25Smrg    enc = NULL;
1338f29dbc25Smrg    encs = NULL;
1339f29dbc25Smrg    nencs = 0;
1340f29dbc25Smrg    img = NULL;
1341f29dbc25Smrg    imgs = NULL;
1342f29dbc25Smrg    nimgs = 0;
1343f29dbc25Smrg    attr = NULL;
1344f29dbc25Smrg    attrs = NULL;
1345f29dbc25Smrg    nattrs = 0;
1346f29dbc25Smrg    adpt = NULL;
1347f29dbc25Smrg    adpts = NULL;
1348f29dbc25Smrg    nadpts = 0;
1349f29dbc25Smrg    has_video = has_image = has_colorkey = 0;
1350f29dbc25Smrg
1351f29dbc25Smrg    for (dev = 0; z4l_dev_paths[dev] != NULL; ++dev) {
135204007ebaSmrg        fd = open(z4l_dev_paths[dev], O_RDWR, 0);
135304007ebaSmrg        if (fd < 0)
135404007ebaSmrg            continue;
135504007ebaSmrg        DBLOG(1, "%s open ok\n", z4l_dev_paths[dev]);
135604007ebaSmrg        msg = NULL;
135704007ebaSmrg        enable = 1;
135804007ebaSmrg        if (IoCtl(fd, VIDIOC_QUERYCAP, &capability, 1) < 0)
135904007ebaSmrg            msg = "bad querycap";
136004007ebaSmrg        else if ((capability.capabilities & V4L2_CAP_VIDEO_OVERLAY) == 0)
136104007ebaSmrg            msg = "no overlay";
136204007ebaSmrg        else if ((capability.capabilities & V4L2_CAP_STREAMING) == 0)
136304007ebaSmrg            msg = "no streaming";
1364f29dbc25Smrg#ifdef NONBLK_IO
136504007ebaSmrg        else if (IoCtl(fd, FIONBIO, &enable, 1) != 0)
136679d5fcd7Smrg            msg = "can't enable non-blocking io";
1367f29dbc25Smrg#endif
136804007ebaSmrg        if (msg == NULL) {
136904007ebaSmrg            memset(&format, 0, sizeof(format));
137004007ebaSmrg            format.type = 0x100;
137104007ebaSmrg            if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) != 0)
137204007ebaSmrg                msg = "no src/dst ovly fmt";
137304007ebaSmrg        }
137404007ebaSmrg        if (msg != NULL) {
137504007ebaSmrg            DBLOG(0, "%s %s\n", z4l_dev_paths[dev], msg);
137604007ebaSmrg            close(fd);
137704007ebaSmrg            continue;
137804007ebaSmrg        }
137904007ebaSmrg
138004007ebaSmrg        memset(&cfmt, 0, sizeof(cfmt));
138104007ebaSmrg        cfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
138204007ebaSmrg        if (IoCtl(fd, VIDIOC_G_FMT, &cfmt, 1) < 0)
138304007ebaSmrg            goto fail;
138404007ebaSmrg        if (IoCtl(fd, VIDIOC_G_STD, &cstd_id, 1) < 0)
138504007ebaSmrg            goto fail;
138604007ebaSmrg        if (IoCtl(fd, VIDIOC_G_INPUT, &cinp, 1) < 0)
138704007ebaSmrg            goto fail;
138804007ebaSmrg        cpixfmt = cfmt.fmt.pix.pixelformat;
138904007ebaSmrg        cenc = 0;
139004007ebaSmrg        for (inp = 0;; ++inp) {
139104007ebaSmrg            memset(&input, 0, sizeof(input));
139204007ebaSmrg            input.index = inp;
139304007ebaSmrg            if (IoCtl(fd, VIDIOC_ENUMINPUT, &input, 0) < 0)
139404007ebaSmrg                break;
139504007ebaSmrg            id = inp;
139604007ebaSmrg            if (IoCtl(fd, VIDIOC_S_INPUT, &id, 1) < 0)
139704007ebaSmrg                goto fail;
139804007ebaSmrg            for (std = 0;; ++std) {
139904007ebaSmrg                memset(&standard, 0, sizeof(standard));
140004007ebaSmrg                standard.index = std;
140104007ebaSmrg                if (IoCtl(fd, VIDIOC_ENUMSTD, &standard, 0) < 0)
140204007ebaSmrg                    break;
140304007ebaSmrg                std_id = standard.id;
140404007ebaSmrg                denom = standard.frameperiod.denominator;
140504007ebaSmrg                numer = standard.frameperiod.numerator;
140604007ebaSmrg                if (IoCtl(fd, VIDIOC_S_STD, &std_id, 1) < 0)
140704007ebaSmrg                    continue;
140804007ebaSmrg                memset(&format, 0, sizeof(format));
140904007ebaSmrg                format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
141004007ebaSmrg                if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) < 0)
141104007ebaSmrg                    continue;
141204007ebaSmrg                width = format.fmt.pix.width;
141304007ebaSmrg                height = format.fmt.pix.height;
141404007ebaSmrg                for (fmt = 0;; ++fmt) {
141504007ebaSmrg                    memset(&fmtdesc, 0, sizeof(fmtdesc));
141604007ebaSmrg                    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
141704007ebaSmrg                    fmtdesc.index = fmt;
141804007ebaSmrg                    if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0)
141904007ebaSmrg                        break;
142004007ebaSmrg                    pixfmt = fmtdesc.pixelformat;
142104007ebaSmrg                    ip = &pixfmts[0];
142204007ebaSmrg                    for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0;
142304007ebaSmrg                         ++ip)
142404007ebaSmrg                        if (z4l_fourcc_pixfmt(ip->id) == pixfmt)
142504007ebaSmrg                            break;
142604007ebaSmrg
142704007ebaSmrg                    if (i >= 0) {
142804007ebaSmrg                        id = nencs;
142904007ebaSmrg                        has_video = 1;
143004007ebaSmrg                        if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL)
143104007ebaSmrg                            goto fail;
143204007ebaSmrg                        Z4lEncodingName(&enc_name[0], sizeof(enc_name),
143304007ebaSmrg                                        (char *) &input.name[0],
143404007ebaSmrg                                        (char *) &standard.name[0],
143504007ebaSmrg                                        (char *) &pixfmt);
143604007ebaSmrg                        if (Z4lAddEncoding
143704007ebaSmrg                            (enc, &enc_name[0], id, width, height, denom, numer,
143804007ebaSmrg                             inp, std_id, pixfmt) == 0)
143904007ebaSmrg                            goto fail;
144004007ebaSmrg                        if (std_id == cstd_id && inp == cinp
144104007ebaSmrg                            && pixfmt == cpixfmt)
144204007ebaSmrg                            cenc = id;
144304007ebaSmrg                    }
144404007ebaSmrg                }
144504007ebaSmrg            }
144604007ebaSmrg        }
144704007ebaSmrg
144804007ebaSmrg        if (IoCtl(fd, VIDIOC_S_INPUT, &cinp, 1) < 0)
144904007ebaSmrg            goto fail;
145004007ebaSmrg        if (IoCtl(fd, VIDIOC_S_STD, &cstd_id, 1) < 0)
145104007ebaSmrg            goto fail;
145204007ebaSmrg        if (IoCtl(fd, VIDIOC_S_FMT, &cfmt, 1) < 0)
145304007ebaSmrg            goto fail;
145404007ebaSmrg
145504007ebaSmrg        if (encs == NULL) {
145604007ebaSmrg            DBLOG(0, "no encodings\n");
145704007ebaSmrg            goto fail;
145804007ebaSmrg        }
145904007ebaSmrg
146004007ebaSmrg        for (fmt = 0;; ++fmt) {
146104007ebaSmrg            memset(&fmtdesc, 0, sizeof(fmtdesc));
146204007ebaSmrg            fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
146304007ebaSmrg            fmtdesc.index = fmt;
146404007ebaSmrg            if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0)
146504007ebaSmrg                break;
146604007ebaSmrg            pixfmt = fmtdesc.pixelformat;
146704007ebaSmrg            ip = &pixfmts[0];
146804007ebaSmrg            for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0; ++ip)
146904007ebaSmrg                if (z4l_fourcc_pixfmt(ip->id) == pixfmt)
147004007ebaSmrg                    break;
147104007ebaSmrg
147204007ebaSmrg            if (i >= 0) {
147304007ebaSmrg                has_image = 1;
147404007ebaSmrg                if ((img = Z4lNewImage(&imgs, &nimgs)) == NULL)
147504007ebaSmrg                    goto fail;
147604007ebaSmrg                if (Z4lAddImage(img, ip) == 0)
147704007ebaSmrg                    goto fail;
147804007ebaSmrg            }
147904007ebaSmrg        }
148004007ebaSmrg
148104007ebaSmrg        if (nimgs > 0) {
148204007ebaSmrg            id = nencs;
148304007ebaSmrg            if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL)
148404007ebaSmrg                goto fail;
148504007ebaSmrg            if (Z4lAddEncoding(enc, "XV_IMAGE", id, MAX_OVLY_WIDTH,
148604007ebaSmrg                               MAX_OVLY_HEIGHT, 0, 0, 0, 0, pixfmt) == 0)
148704007ebaSmrg                goto fail;
148804007ebaSmrg        }
148904007ebaSmrg
149004007ebaSmrg        ctl = 0;
149104007ebaSmrg        for (ctl = 0; ctl < (V4L2_CID_LASTP1 - V4L2_CID_BASE); ++ctl) {
149204007ebaSmrg            memset(&queryctrl, 0, sizeof(queryctrl));
149304007ebaSmrg            queryctrl.id = V4L2_CID_BASE + ctl;
149404007ebaSmrg            if (IoCtl(fd, VIDIOC_QUERYCTRL, &queryctrl, 0) < 0)
149504007ebaSmrg                continue;
149604007ebaSmrg            if (queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
149704007ebaSmrg                queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN)
149804007ebaSmrg                continue;
149904007ebaSmrg            attrIds[nattrs] = ctl;
150004007ebaSmrg            if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
150104007ebaSmrg                goto fail;
150204007ebaSmrg            Z4lAttributeName(&attr_name[0], sizeof(attr_name),
150304007ebaSmrg                             (char *) &queryctrl.name[0]);
150404007ebaSmrg            if (Z4lAddAttribute(attr, &attr_name[0],
150504007ebaSmrg                                queryctrl.minimum, queryctrl.maximum,
150604007ebaSmrg                                XvSettable | XvGettable) == 0)
150704007ebaSmrg                goto fail;
150804007ebaSmrg        }
150904007ebaSmrg        attrIds[nattrs] = ATTR_ENCODING_ID;
151004007ebaSmrg        if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
151104007ebaSmrg            goto fail;
151204007ebaSmrg        Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_ENCODING);
151304007ebaSmrg        if (Z4lAddAttribute(attr, &attr_name[0], 0, nencs - 1,
151404007ebaSmrg                            XvSettable | XvGettable) == 0)
151504007ebaSmrg            goto fail;
151604007ebaSmrg        memset(&fbuf, 0, sizeof(fbuf));
151704007ebaSmrg        if (IoCtl(fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
151804007ebaSmrg            goto fail;
151904007ebaSmrg        opixfmt = fbuf.fmt.pixelformat;
152004007ebaSmrg
152104007ebaSmrg        if ((fbuf.capability & V4L2_FBUF_CAP_CHROMAKEY) != 0) {
152204007ebaSmrg            attrIds[nattrs] = ATTR_KEYMODE_ID;
152304007ebaSmrg            if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
152404007ebaSmrg                goto fail;
152504007ebaSmrg            Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_KEYMODE);
152604007ebaSmrg            if (Z4lAddAttribute(attr, &attr_name[0], 0, 1,
152704007ebaSmrg                                XvSettable | XvGettable) == 0)
152804007ebaSmrg                goto fail;
152904007ebaSmrg            attrIds[nattrs] = ATTR_COLORKEY_ID;
153004007ebaSmrg            if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
153104007ebaSmrg                goto fail;
153204007ebaSmrg            Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_COLORKEY);
153304007ebaSmrg            if (Z4lAddAttribute(attr, &attr_name[0], 0, 0xffffff,
153404007ebaSmrg                                XvSettable | XvGettable) == 0)
153504007ebaSmrg                goto fail;
153604007ebaSmrg            has_colorkey = 1;
153704007ebaSmrg        }
153804007ebaSmrg
153904007ebaSmrg        dp = malloc(strlen((char *) &capability.card[0]) + 1);
154004007ebaSmrg        if (dp == NULL)
154104007ebaSmrg            goto fail;
154204007ebaSmrg        strcpy(dp, (char *) &capability.card[0]);
154304007ebaSmrg        if ((adpt = Z4lNewAdaptor(&adpts, &nadpts, nattrs)) == NULL)
154404007ebaSmrg            goto fail;
154504007ebaSmrg        adpt->type = XvWindowMask | XvInputMask;
154604007ebaSmrg        if (has_video != 0)
154704007ebaSmrg            adpt->type |= XvVideoMask;
154804007ebaSmrg        if (has_image != 0)
154904007ebaSmrg            adpt->type |= XvImageMask;
155004007ebaSmrg        adpt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
155104007ebaSmrg        adpt->name = dp;
155204007ebaSmrg        adpt->type = XvInputMask | XvWindowMask | XvVideoMask | XvImageMask;
155304007ebaSmrg        adpt->pEncodings = encs;
155404007ebaSmrg        adpt->nEncodings = nencs;
155504007ebaSmrg        adpt->pFormats = &Formats[0];
155604007ebaSmrg        adpt->nFormats = sizeof(Formats) / sizeof(Formats[0]);
155704007ebaSmrg        adpt->pAttributes = attrs;
155804007ebaSmrg        adpt->nAttributes = nattrs;
155904007ebaSmrg        attrs = NULL;
156004007ebaSmrg        nattrs = 0;
156104007ebaSmrg        adpt->pImages = imgs;
156204007ebaSmrg        adpt->nImages = nimgs;
156304007ebaSmrg        imgs = NULL;
156404007ebaSmrg        nimgs = 0;
156504007ebaSmrg        adpt->PutVideo = Z4lPutVideo;
156604007ebaSmrg        adpt->StopVideo = Z4lStopVideo;
156704007ebaSmrg        adpt->SetPortAttribute = Z4lSetPortAttribute;
156804007ebaSmrg        adpt->GetPortAttribute = Z4lGetPortAttribute;
156904007ebaSmrg        adpt->QueryBestSize = Z4lQueryBestSize;
157004007ebaSmrg        adpt->PutImage = Z4lPutImage;
157104007ebaSmrg        adpt->QueryImageAttributes = Z4lQueryImageAttributes;
157204007ebaSmrg        pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr;
157304007ebaSmrg        pPriv->fd = fd;
157404007ebaSmrg        pPriv->run = -1;
157504007ebaSmrg        pPriv->dir = 0;
157604007ebaSmrg        pPriv->nbfrs = -1;
157704007ebaSmrg        pPriv->bufsz = -1;
157804007ebaSmrg        pPriv->last = -1;
157904007ebaSmrg        pPriv->pixfmt = opixfmt;
1580f29dbc25Smrg#if defined(REGION_NULL)
158104007ebaSmrg        REGION_NULL(pScrni->pScreen, &pPriv->clips);
1582f29dbc25Smrg#else
158304007ebaSmrg        REGION_INIT(pScrni->pScreen, &pPriv->clips, NullBox, 0);
1584f29dbc25Smrg#endif
158504007ebaSmrg        strncpy(&pPriv->dev_path[0], z4l_dev_paths[dev],
158604007ebaSmrg                sizeof(pPriv->dev_path));
158704007ebaSmrg        pPriv->enc = &encs[cenc];
158804007ebaSmrg        for (i = 0; i < adpt->nAttributes; ++i)
158904007ebaSmrg            pPriv->attrIds[i] = attrIds[i];
159004007ebaSmrg        DBLOG(1, "adpt %s\n", dp);
159104007ebaSmrg        if (has_colorkey != 0) {
159204007ebaSmrg            z4l_ovly_set_colorkey(pPriv, DEFAULT_COLORKEY);
159304007ebaSmrg            z4l_ovly_set_keymode(pPriv, DEFAULT_KEYMODE);
159404007ebaSmrg        }
159504007ebaSmrg        close(fd);
159604007ebaSmrg        pPriv->fd = -1;
159704007ebaSmrg        adpt = NULL;
159804007ebaSmrg        cenc = 0;
159904007ebaSmrg        encs = NULL;
160004007ebaSmrg        nencs = 0;
1601f29dbc25Smrg    }
1602f29dbc25Smrg
1603f29dbc25Smrg    DBLOG(0, "init done, %d device(s) found\n", nadpts);
1604f29dbc25Smrg    Z4l_nAdaptors = nadpts;
1605f29dbc25Smrg    Z4l_pAdaptors = adpts;
1606f29dbc25Smrg    *adaptors = adpts;
1607f29dbc25Smrg
1608f29dbc25Smrg    return nadpts;
1609f29dbc25Smrg
161004007ebaSmrg fail:
1611f29dbc25Smrg    if (attrs != NULL) {
161204007ebaSmrg        for (i = 0; i < nattrs; ++i)
161304007ebaSmrg            if (attrs[i].name != NULL)
161404007ebaSmrg                free(attrs[i].name);
161504007ebaSmrg        free(attrs);
1616f29dbc25Smrg    }
1617f29dbc25Smrg
1618f29dbc25Smrg    if (encs != NULL) {
161904007ebaSmrg        for (i = 0; i < nencs; ++i) {
162004007ebaSmrg            if (encs[i].name != NULL)
162104007ebaSmrg                free(encs[i].name);
162204007ebaSmrg        }
162304007ebaSmrg        free(encs);
1624f29dbc25Smrg    }
1625f29dbc25Smrg
1626f29dbc25Smrg    if (imgs != NULL)
162704007ebaSmrg        free(imgs);
1628f29dbc25Smrg
1629f29dbc25Smrg    if (adpts != NULL) {
163004007ebaSmrg        for (i = 0; i < nadpts; ++i) {
163104007ebaSmrg            if ((adpt = adpts[i]) != NULL) {
163204007ebaSmrg                if (adpt->name != NULL)
163304007ebaSmrg                    free(adpt->name);
163404007ebaSmrg                if ((attrs = adpt->pAttributes) != NULL) {
163504007ebaSmrg                    for (i = 0; i < adpt->nAttributes; ++i)
163604007ebaSmrg                        if (attrs[i].name != NULL)
163704007ebaSmrg                            free(attrs[i].name);
163804007ebaSmrg                    free(attrs);
163904007ebaSmrg                }
164004007ebaSmrg                if ((encs = adpt->pEncodings) != NULL) {
164104007ebaSmrg                    for (i = 0; i < adpt->nEncodings; ++i, ++enc)
164204007ebaSmrg                        if (encs[i].name != NULL)
164304007ebaSmrg                            free(encs[i].name);
164404007ebaSmrg                    free(encs);
164504007ebaSmrg                }
164604007ebaSmrg                if ((imgs = adpt->pImages) != NULL)
164704007ebaSmrg                    free(imgs);
164804007ebaSmrg                free(adpt);
164904007ebaSmrg            }
165004007ebaSmrg        }
165104007ebaSmrg        free(adpts);
1652f29dbc25Smrg    }
1653f29dbc25Smrg
1654f29dbc25Smrg    if (fd >= 0)
165504007ebaSmrg        close(fd);
1656f29dbc25Smrg
1657f29dbc25Smrg    return 0;
1658f29dbc25Smrg}
1659f29dbc25Smrg
1660f29dbc25Smrgstatic Bool
1661f29dbc25SmrgZ4lProbe(DriverPtr drv, int flags)
1662f29dbc25Smrg{
1663f29dbc25Smrg    DBLOG(1, "Probe\n");
1664f29dbc25Smrg    if (flags & PROBE_DETECT)
166504007ebaSmrg        return TRUE;
1666f29dbc25Smrg
1667f29dbc25Smrg    xf86XVRegisterGenericAdaptorDriver(Z4lInit);
1668f29dbc25Smrg    drv->refCount++;
1669f29dbc25Smrg
1670f29dbc25Smrg    return TRUE;
1671f29dbc25Smrg}
1672f29dbc25Smrg
1673f29dbc25Smrgstatic const OptionInfoRec *
1674f29dbc25SmrgZ4lAvailableOptions(int chipid, int busid)
1675f29dbc25Smrg{
1676f29dbc25Smrg    return NULL;
1677f29dbc25Smrg}
1678f29dbc25Smrg
1679f29dbc25Smrgstatic void
1680f29dbc25SmrgZ4lIdentify(int flags)
1681f29dbc25Smrg{
1682f29dbc25Smrg    xf86Msg(X_INFO, "z4l driver for Video4Linux\n");
1683f29dbc25Smrg}
1684f29dbc25Smrg
1685f29dbc25Smrg_X_EXPORT DriverRec Z4l = {
1686f29dbc25Smrg    40001,
1687f29dbc25Smrg    "z4l",
1688f29dbc25Smrg    Z4lIdentify,
1689f29dbc25Smrg    Z4lProbe,
1690f29dbc25Smrg    Z4lAvailableOptions,
1691f29dbc25Smrg    NULL,
1692f29dbc25Smrg    0
1693f29dbc25Smrg};
1694f29dbc25Smrg
1695f29dbc25Smrg#ifdef XFree86LOADER
1696f29dbc25Smrg
1697f29dbc25Smrgstatic MODULESETUPPROTO(z4lSetup);
1698f29dbc25Smrg
1699f29dbc25Smrgstatic XF86ModuleVersionInfo z4lVersionRec = {
1700f29dbc25Smrg    "ztv",
1701f29dbc25Smrg    MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2,
1702f29dbc25Smrg    XORG_VERSION_CURRENT, 0, 0, 1,
1703f29dbc25Smrg    ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_NONE,
1704f29dbc25Smrg    {0, 0, 0, 0}
1705f29dbc25Smrg};
1706f29dbc25Smrg
1707f29dbc25Smrg_X_EXPORT XF86ModuleData ztvModuleData = { &z4lVersionRec, z4lSetup, NULL };
1708f29dbc25Smrg
1709f29dbc25Smrgstatic pointer
1710f29dbc25Smrgz4lSetup(pointer module, pointer opts, int *errmaj, int *errmin)
1711f29dbc25Smrg{
1712f29dbc25Smrg    static Bool setupDone = FALSE;
1713f29dbc25Smrg
1714f29dbc25Smrg    if (setupDone != FALSE) {
171504007ebaSmrg        if (errmaj != NULL)
171604007ebaSmrg            *errmaj = LDR_ONCEONLY;
171704007ebaSmrg        return NULL;
1718f29dbc25Smrg    }
1719f29dbc25Smrg
1720f29dbc25Smrg    setupDone = TRUE;
1721f29dbc25Smrg    xf86AddDriver(&Z4l, module, 0);
1722f29dbc25Smrg    return (pointer) 1;
1723f29dbc25Smrg}
1724f29dbc25Smrg
1725f29dbc25Smrg#endif
172604007ebaSmrg#endif                          /* !XvExtension */
1727