z4l.c revision 04007eba
1/*
2 * Copyright (c) 2006 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
23 * contributors may be used to endorse or promote products derived from this
24 * software without specific prior written permission.
25 */
26
27/* prototype Xv interface for lxv4l2 driver */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <sys/time.h>
34#include <sys/fcntl.h>
35#include <sys/mman.h>
36#include <sys/ioctl.h>
37#include <errno.h>
38#include <unistd.h>
39#include <string.h>
40#include <ctype.h>
41#include <stdlib.h>
42
43#include "xf86.h"
44#include <X11/extensions/Xv.h>
45#include "xf86_OSproc.h"
46#include "compiler.h"
47#include "xf86xv.h"
48#include "fourcc.h"
49
50#include "compat-api.h"
51
52#define __s64 __s_64
53typedef long long __s64;
54
55#define __u64 __u_64
56typedef unsigned long long __u64;
57
58#define __user
59#include "linux/videodev2.h"
60
61typedef signed long long s64;
62typedef unsigned long long u64;
63
64int debuglvl = 0;
65
66#define NONBLK_IO
67#undef HAVE_SELECT
68
69#define DEBUG 1
70#ifdef DEBUG
71#define DBLOG(n,s...) do { \
72						if ( debuglvl >= (n) ) \
73							xf86Msg(X_INFO, "z4l: " s); \
74					  } while(0)
75#else
76#define DBLOG(n,s...) do {} while(0)
77#endif
78
79#define DEFAULT_COLORKEY 0x010203
80#define DEFAULT_KEYMODE 0
81
82#define MAX_BUFFERS 4
83#define MAX_OVLY_WIDTH  2048
84#define MAX_OVLY_HEIGHT 2048
85
86static char *z4l_dev_paths[] = {
87    "/dev/videox", NULL
88};
89
90#define ATTR_ENCODING "encoding"
91#define ATTR_ENCODING_ID -1
92#define ATTR_KEYMODE "keymode"
93#define ATTR_KEYMODE_ID -2
94#define ATTR_COLORKEY "colorkey"
95#define ATTR_COLORKEY_ID -3
96#define ATTR_MAX_ID 3
97
98#ifdef XvExtension
99
100static XF86VideoFormatRec Formats[] = {
101    {8, PseudoColor},
102    {15, TrueColor},
103    {16, TrueColor},
104    {24, TrueColor}
105};
106
107#define NUM_FORMATS (sizeof(Formats)/sizeof(Formats[0]))
108
109#define FOURCC_Y800 0x30303859
110#define XVIMAGE_Y800 \
111   { \
112        FOURCC_Y800, \
113        XvYUV, \
114        LSBFirst, \
115        {'Y','8','0','0', \
116          0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
117        8, \
118        XvPacked, \
119        1, \
120        0, 0, 0, 0, \
121        8, 0, 0, \
122        1, 0, 0, \
123        1, 0, 0, \
124        {'Y','8','0','0', \
125          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}, \
126        XvTopToBottom \
127   }
128
129static XF86ImageRec pixfmts[] = {
130    XVIMAGE_UYVY, XVIMAGE_YUY2,
131    XVIMAGE_I420, XVIMAGE_YV12,
132    XVIMAGE_Y800,
133};
134
135#define NUM_PIXFMTS (sizeof(pixfmts)/sizeof(pixfmts[0]))
136
137typedef struct s_std_data {
138    int inp;
139    v4l2_std_id std;
140    unsigned int fmt;
141} t_std_data;
142
143typedef struct s_ovly_bfrs {
144    void *start;
145    unsigned long offset;
146    size_t length;
147} t_ovly_bfrs;
148
149typedef struct {
150    int fd;
151    int run;
152    int dir;
153    int nbfrs;
154    int bufno;
155    int bufsz;
156    int last;
157    int width, height;
158    int keymode, colorkey;
159    int src_is_set, src_x, src_y, src_w, src_h;
160    int drw_is_set, drw_x, drw_y, drw_w, drw_h;
161    unsigned int pixfmt;
162    char dev_path[32];
163    t_ovly_bfrs bfrs[MAX_BUFFERS];
164    XF86VideoAdaptorPtr adpt;
165    XF86VideoEncodingPtr enc;
166    RegionRec clips;
167    int attrIds[1];
168} Z4lPortPrivRec;
169
170static int z4l_x_offset = 0;
171static int z4l_y_offset = 0;
172static int Z4l_nAdaptors = 0;
173static XF86VideoAdaptorPtr *Z4l_pAdaptors = NULL;
174
175static int
176IoCtl(int fd, unsigned int fn, void *arg, int flag)
177{
178    int ret;
179
180    errno = 0;
181    ret = ioctl(fd, fn, arg);
182    if (ret != 0 && flag != 0)
183        DBLOG(0, "ioctl(%08x)=%d\n", fn, ret);
184    return ret;
185}
186
187static void
188z4l_ovly_unmap(Z4lPortPrivRec * pPriv)
189{
190    int i, nbfrs;
191
192    nbfrs = pPriv->nbfrs;
193    for (i = 0; i < nbfrs; ++i) {
194        if (pPriv->bfrs[i].start != NULL) {
195            munmap(pPriv->bfrs[i].start, pPriv->bfrs[i].length);
196            pPriv->bfrs[i].start = NULL;
197        }
198    }
199    pPriv->nbfrs = -1;
200    pPriv->bufsz = -1;
201    pPriv->last = -1;
202}
203
204static void
205z4l_ovly_map(Z4lPortPrivRec * pPriv, int dir)
206{
207    long offset, bsz;
208    int i, fd;
209    struct v4l2_buffer bfr;
210    struct v4l2_requestbuffers req;
211    int type = dir >= 0 ?
212        V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VIDEO_OVERLAY;
213    if (pPriv->run > 0) {
214        DBLOG(1, "busy\n");
215        return;
216    }
217    fd = pPriv->fd;
218    memset(&req, 0, sizeof(req));
219    req.type = type;
220    req.memory = V4L2_MEMORY_MMAP;
221    req.count = MAX_BUFFERS;
222    if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
223        goto xit;
224    pPriv->nbfrs = req.count;
225    if (pPriv->nbfrs <= 0) {
226        DBLOG(1, "no vidmem\n");
227        return;
228    }
229    memset(&pPriv->bfrs, 0, sizeof(pPriv->bfrs));
230
231    for (i = 0; i < pPriv->nbfrs; ++i) {
232        memset(&bfr, 0, sizeof(bfr));
233        bfr.type = type;
234        bfr.index = i;
235        if (ioctl(fd, VIDIOC_QUERYBUF, &bfr) < 0)
236            goto xit;
237        offset = bfr.m.offset;
238        pPriv->bfrs[i].offset = offset;
239        pPriv->bfrs[i].length = bfr.length;
240        bsz = offset + bfr.length;
241        if (pPriv->bufsz < bsz)
242            pPriv->bufsz = bsz;
243    }
244
245    for (i = 0; i < pPriv->nbfrs; ++i) {
246        pPriv->bfrs[i].start = mmap(NULL, bfr.length, PROT_READ | PROT_WRITE,
247                                    MAP_SHARED, fd, pPriv->bfrs[i].offset);
248        if (pPriv->bfrs[i].start == MAP_FAILED)
249            goto xit;
250    }
251
252    for (i = 0; i < pPriv->nbfrs; ++i) {
253        DBLOG(3, "bfr %d ofs %#lx adr %p sz %lu\n", i, pPriv->bfrs[i].offset,
254              pPriv->bfrs[i].start, (unsigned long) pPriv->bfrs[i].length);
255        memset(pPriv->bfrs[i].start, 0x80, pPriv->bfrs[i].length);
256    }
257
258    pPriv->last = 0;
259    while (pPriv->last < pPriv->nbfrs - 1) {
260        bfr.index = pPriv->last++;
261        bfr.type = type;
262        if (ioctl(fd, VIDIOC_QBUF, &bfr) < 0)
263            goto xit;
264    }
265    return;
266
267 xit:
268    z4l_ovly_unmap(pPriv);
269}
270
271static int
272z4l_ovly_dqbuf(Z4lPortPrivRec * pPriv)
273{
274    int stat;
275    struct v4l2_buffer bfr;
276    int fd = pPriv->fd;
277
278#ifdef HAVE_SELECT
279    struct timeval tmo;
280    fd_set dqset;
281
282    FD_ZERO(&dqset);
283    FD_SET(pPriv->fd, &dqset);
284    tmo.tv_sec = 0;
285    tmo.tv_usec = 0;
286    if (select(fd + 1, &dqset, NULL, NULL, &tmo) <= 0)
287        return -1;
288#endif
289    memset(&bfr, 0, sizeof(bfr));
290    bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
291    stat = ioctl(fd, VIDIOC_DQBUF, &bfr);
292    DBLOG(3, "dqbuf %d,%d,%d,%d\n", stat, bfr.index, pPriv->last, errno);
293
294    return stat == 0 ? bfr.index : -1;
295}
296
297static int
298z4l_open_device(Z4lPortPrivRec * pPriv)
299{
300    int enable;
301
302    if (pPriv->fd < 0) {
303        pPriv->fd = open(&pPriv->dev_path[0], O_RDWR, 0);
304        DBLOG(1, "open(%s)=%d\n", &pPriv->dev_path[0], pPriv->fd);
305        enable = 1;
306#ifdef NONBLK_IO
307        if (IoCtl(pPriv->fd, FIONBIO, &enable, 1) != 0) {
308            DBLOG(1, "open cant enable nonblocking\n");
309            close(pPriv->fd);
310            pPriv->fd = -1;
311        }
312#endif
313    }
314    return pPriv->fd;
315}
316
317static int
318z4l_close_device(Z4lPortPrivRec * pPriv)
319{
320    int ret = 0;
321
322    if (pPriv->fd >= 0) {
323        ret = close(pPriv->fd);
324        pPriv->fd = -1;
325        DBLOG(1, "close()=%d\n", ret);
326    }
327    if (pPriv->run > 0) {
328        z4l_ovly_unmap(pPriv);
329        pPriv->run = -1;
330    }
331
332    return ret;
333}
334
335static int
336z4l_ovly_reset(Z4lPortPrivRec * pPriv)
337{
338    int ret = 0;
339
340    if (pPriv->run > 0) {
341        z4l_close_device(pPriv);
342        ret = z4l_open_device(pPriv);
343    }
344
345    return ret;
346}
347
348static unsigned int
349z4l_fourcc_pixfmt(int fourcc)
350{
351    unsigned int pixfmt = -1;
352
353    switch (fourcc) {
354    case FOURCC_UYVY:
355        pixfmt = V4L2_PIX_FMT_UYVY;
356        break;
357    case FOURCC_YV12:
358        pixfmt = V4L2_PIX_FMT_YVU420;
359        break;
360    case FOURCC_Y800:
361    case FOURCC_I420:
362        pixfmt = V4L2_PIX_FMT_YUV420;
363        break;
364    case FOURCC_YUY2:
365        pixfmt = V4L2_PIX_FMT_YUYV;
366        break;
367    }
368
369    return pixfmt;
370}
371
372static void
373z4l_ovly_pixfmt(Z4lPortPrivRec * pPriv, unsigned int pixfmt)
374{
375    struct v4l2_framebuffer fbuf;
376
377    DBLOG(1, "pixfmt %4.4s %4.4s\n", (char *) &pPriv->pixfmt, (char *) &pixfmt);
378    memset(&fbuf, 0, sizeof(fbuf));
379    IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1);
380    fbuf.fmt.pixelformat = pixfmt;
381    fbuf.base = NULL;
382    IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1);
383    pPriv->pixfmt = pixfmt;
384}
385
386static void
387z4l_ovly_bfr(Z4lPortPrivRec * pPriv, int width, int height)
388{
389    struct v4l2_format fmt;
390
391    DBLOG(1, "sfmt ovly %dx%d\n", width, height);
392    memset(&fmt, 0, sizeof(fmt));
393    fmt.type = 0x102;
394    IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
395    fmt.fmt.win.field = V4L2_FIELD_NONE;
396    fmt.fmt.win.w.width = pPriv->width = width;
397    fmt.fmt.win.w.height = pPriv->height = height;
398    IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
399}
400
401static void
402z4l_ovly_rect(Z4lPortPrivRec * pPriv,
403              int src_x, int src_y, int src_w, int src_h,
404              int drw_x, int drw_y, int drw_w, int drw_h)
405{
406    int x, dx, w, y, dy, h;
407    struct v4l2_format fmt;
408
409    pPriv->src_x = src_x;
410    pPriv->src_y = src_y;
411    pPriv->src_w = src_w;
412    pPriv->src_h = src_h;
413    pPriv->drw_x = drw_x;
414    pPriv->drw_y = drw_y;
415    pPriv->drw_w = drw_w;
416    pPriv->drw_h = drw_h;
417
418    if ((drw_x -= z4l_x_offset) < 0) {
419        if ((w = pPriv->drw_w) <= 0)
420            w = 1;
421        x = -drw_x;
422        dx = x * pPriv->src_w / w;
423        src_x = pPriv->src_x + dx;
424        src_w = pPriv->src_w - dx;
425        drw_w = pPriv->drw_w - x;
426        drw_x = 0;
427    }
428
429    if ((drw_y -= z4l_y_offset) < 0) {
430        if ((h = pPriv->drw_h) <= 0)
431            h = 1;
432        y = -drw_y;
433        dy = y * pPriv->src_h / h;
434        src_y = pPriv->src_y + dy;
435        src_h = pPriv->src_h - dy;
436        drw_h = pPriv->drw_h - y;
437        drw_y = 0;
438    }
439
440    memset(&fmt, 0, sizeof(fmt));
441    fmt.type = 0x100;
442    IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
443    if (pPriv->src_is_set != 0) {
444        if (src_x != fmt.fmt.win.w.left || src_y != fmt.fmt.win.w.top ||
445            src_w != fmt.fmt.win.w.width || src_h != fmt.fmt.win.w.height)
446            pPriv->src_is_set = 0;
447    }
448    if (pPriv->src_is_set == 0) {
449        pPriv->src_is_set = 1;
450        fmt.fmt.win.w.left = src_x;
451        fmt.fmt.win.w.top = src_y;
452        fmt.fmt.win.w.width = src_w;
453        fmt.fmt.win.w.height = src_h;
454        IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
455        DBLOG(3, "  set src %d,%d %dx%d\n", src_x, src_y, src_w, src_h);
456    }
457    memset(&fmt, 0, sizeof(fmt));
458    fmt.type = 0x101;
459    IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1);
460    if (pPriv->drw_is_set != 0) {
461        if (drw_x != fmt.fmt.win.w.left || drw_y != fmt.fmt.win.w.top ||
462            drw_w != fmt.fmt.win.w.width || drw_h != fmt.fmt.win.w.height)
463            pPriv->drw_is_set = 0;
464    }
465    if (pPriv->drw_is_set == 0) {
466        pPriv->drw_is_set = 1;
467        fmt.fmt.win.w.left = drw_x;
468        fmt.fmt.win.w.top = drw_y;
469        fmt.fmt.win.w.width = drw_w;
470        fmt.fmt.win.w.height = drw_h;
471        IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1);
472        DBLOG(3, "  set drw %d,%d %dx%d\n", drw_x, drw_y, drw_w, drw_h);
473    }
474}
475
476static void
477z4l_ovly_pitch(unsigned int pixfmt, int w, int h, int *py_pitch,
478               int *puv_pitch, int *poffset1, int *poffset2, int *psize)
479{
480    int y_pitch, uv_pitch;
481    int offset1, offset2;
482    int size, is_420;
483
484    switch (pixfmt) {
485    case V4L2_PIX_FMT_YVU420:
486    case V4L2_PIX_FMT_YUV420:
487        is_420 = 1;
488        y_pitch = ((w + 1) / 2) * 2;
489        uv_pitch = (w + 1) / 2;
490        break;
491    default:
492        is_420 = 0;
493        y_pitch = ((w + 1) / 2) * 4;
494        uv_pitch = 0;
495        break;
496    }
497
498    offset1 = y_pitch * h;
499    offset2 = uv_pitch * h;
500
501    if (is_420 != 0)
502        offset2 /= 2;
503
504    size = offset1 + 2 * offset2;
505    *py_pitch = y_pitch;
506    *puv_pitch = uv_pitch;
507    *poffset1 = offset1;
508    *poffset2 = offset2;
509    *psize = size;
510}
511
512static int
513z4l_ovly_set_colorkey(Z4lPortPrivRec * pPriv, int key)
514{
515    struct v4l2_format fmt;
516
517    memset(&fmt, 0, sizeof(fmt));
518    fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
519    if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
520        return 0;
521    fmt.fmt.win.chromakey = key;
522    if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0)
523        return 0;
524    pPriv->colorkey = key;
525
526    return 1;
527}
528
529static int
530z4l_ovly_get_colorkey(Z4lPortPrivRec * pPriv, int *key)
531{
532    struct v4l2_format fmt;
533
534    memset(&fmt, 0, sizeof(fmt));
535    fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
536    if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
537        return 0;
538    *key = fmt.fmt.win.chromakey;
539
540    return 1;
541}
542
543static int
544z4l_ovly_set_keymode(Z4lPortPrivRec * pPriv, int enable)
545{
546    struct v4l2_framebuffer fbuf;
547
548    memset(&fbuf, 0, sizeof(fbuf));
549    if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
550        return 0;
551
552    if (enable != 0)
553        fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
554    else
555        fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
556
557    fbuf.base = NULL;
558    if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0)
559        return 0;
560    pPriv->keymode = enable;
561
562    return 1;
563}
564
565static int
566z4l_ovly_get_keymode(Z4lPortPrivRec * pPriv, int *enable)
567{
568    struct v4l2_framebuffer fbuf;
569
570    memset(&fbuf, 0, sizeof(fbuf));
571    if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
572        return 0;
573    *enable = (fbuf.flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0 ? 1 : 0;
574
575    return 1;
576}
577
578static int
579z4l_ovly_set_encoding(Z4lPortPrivRec * pPriv, int id)
580{
581    int l, n, inp;
582    char *cp;
583    t_std_data *sp;
584    XF86VideoEncodingPtr enc;
585    XF86VideoAdaptorPtr adpt;
586    v4l2_std_id std;
587    struct v4l2_format fmt;
588    struct v4l2_framebuffer fbuf;
589
590    adpt = pPriv->adpt;
591    DBLOG(1, "z4l_ovly_set_encoding(%d)\n", id);
592    if (id < 0 || id >= adpt->nEncodings)
593        return 0;
594    enc = &adpt->pEncodings[id];
595    cp = &enc->name[0];
596    n = sizeof(int) - 1;
597    l = strlen(cp) + 1;
598    l = (l + n) & ~n;
599    sp = (t_std_data *) (cp + l);
600    inp = sp->inp;
601
602    DBLOG(1, " nm %s fmt %4.4s inp %d std %llx\n",
603          cp, (char *) &sp->fmt, sp->inp, sp->std);
604
605    if (IoCtl(pPriv->fd, VIDIOC_S_INPUT, &inp, 1) < 0)
606        return 0;
607
608    std = sp->std;
609    if (IoCtl(pPriv->fd, VIDIOC_S_STD, &std, 1) < 0)
610        return 0;
611
612    memset(&fmt, 0, sizeof(fmt));
613    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
614    if (IoCtl(pPriv->fd, VIDIOC_G_FMT, &fmt, 1) < 0)
615        return 0;
616
617    fmt.fmt.pix.pixelformat = sp->fmt;
618    if (IoCtl(pPriv->fd, VIDIOC_S_FMT, &fmt, 1) < 0)
619        return 0;
620    memset(&fbuf, 0, sizeof(fbuf));
621
622    if (IoCtl(pPriv->fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
623        return 0;
624
625    fbuf.fmt.pixelformat = sp->fmt;
626    fbuf.base = NULL;
627    if (IoCtl(pPriv->fd, VIDIOC_S_FBUF, &fbuf, 1) < 0)
628        return 0;
629    pPriv->pixfmt = sp->fmt;
630    pPriv->enc = enc;
631    pPriv->src_is_set = pPriv->drw_is_set = 0;
632
633    return 1;
634}
635
636static int
637z4l_ovly_get_encoding(Z4lPortPrivRec * pPriv, int *id)
638{
639    XF86VideoEncodingPtr enc = pPriv->enc;
640
641    *id = enc->id;
642    return 1;
643}
644
645static void
646z4l_ovly_stop(Z4lPortPrivRec * pPriv)
647{
648    int type, enable, fd;
649
650    if (pPriv->run < 0)
651        return;
652
653    fd = pPriv->fd;
654    if (pPriv->dir > 0) {
655        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
656        ioctl(fd, VIDIOC_STREAMOFF, &type);
657    }
658
659    if (pPriv->dir <= 0) {
660        enable = 0;
661        ioctl(fd, VIDIOC_OVERLAY, &enable);
662    }
663
664    if (pPriv->dir != 0)
665        z4l_ovly_unmap(pPriv);
666
667    pPriv->run = -1;
668    z4l_close_device(pPriv);
669}
670
671static void
672z4l_ovly_start(Z4lPortPrivRec * pPriv, int dir)
673{
674    int enable;
675
676    if (pPriv->run >= 0)
677        return;
678
679    if ((pPriv->dir = dir) != 0)
680        z4l_ovly_map(pPriv, dir);
681
682    enable = 1;
683
684    if (IoCtl(pPriv->fd, VIDIOC_OVERLAY, &enable, 1) != 0) {
685        z4l_ovly_stop(pPriv);
686        return;
687    }
688
689    pPriv->run = 1;
690}
691
692static int
693z4l_region_equal(RegionPtr ap, RegionPtr bp)
694{
695    int nboxes;
696    BoxPtr abox, bbox;
697
698    if (ap == NULL && bp == NULL)
699        return 1;
700    if (ap == NULL || bp == NULL)
701        return 0;
702
703    if ((nboxes = REGION_NUM_RECTS(ap)) != REGION_NUM_RECTS(bp) ||
704        ap->extents.x1 != bp->extents.x1 ||
705        ap->extents.x2 != bp->extents.x2
706        || ap->extents.y1 != bp->extents.y1 || ap->extents.y2 != bp->extents.y2)
707        return 0;
708
709    abox = REGION_RECTS(ap);
710    bbox = REGION_RECTS(bp);
711
712    while (--nboxes >= 0) {
713        if (abox->x1 != bbox->x1 || abox->y1 != bbox->y1 ||
714            abox->x2 != bbox->x2 || abox->y2 != bbox->y2)
715            return 0;
716        ++abox;
717        ++bbox;
718    }
719
720    return 1;
721}
722
723static void
724z4l_setup_colorkey(Z4lPortPrivRec * pPriv, ScreenPtr pScrn, RegionPtr clipBoxes)
725{
726    if (pPriv->run > 0 && pPriv->dir <= 0 && pPriv->keymode != 0 &&
727        z4l_region_equal(&pPriv->clips, clipBoxes) == 0) {
728        xf86XVFillKeyHelper(pScrn, pPriv->colorkey, clipBoxes);
729        REGION_COPY(pScrn, &pPriv->clips, clipBoxes);
730    }
731}
732
733static void
734Z4lStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
735{
736    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
737
738    DBLOG(1, "Z4lStopVideo()\n");
739
740    if (exit != 0)
741        z4l_ovly_stop(pPriv);
742    else
743        pPriv->src_is_set = pPriv->drw_is_set = 0;
744
745    REGION_EMPTY(pScrni->pScreen, &pPriv->clips);
746}
747
748static void
749Z4lQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
750                 short vid_w, short vid_h, short drw_w, short drw_h,
751                 unsigned int *p_w, unsigned int *p_h, pointer data)
752{
753    if (drw_w > MAX_OVLY_WIDTH)
754        drw_w = MAX_OVLY_WIDTH;
755    if (drw_h > MAX_OVLY_HEIGHT)
756        drw_h = MAX_OVLY_HEIGHT;
757
758    *p_w = drw_w;
759    *p_h = drw_h;
760    DBLOG(1, "Z4lQueryBestSize(%d, src %dx%d dst %dx%d)\n", motion, vid_w,
761          vid_h, drw_w, drw_h);
762}
763
764static int
765Z4lPutImage(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x,
766            short drw_y, short src_w, short src_h, short drw_w, short drw_h,
767            int id, unsigned char *buf, short width, short height,
768            Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
769{
770    int fd, size;
771    int y_pitch, uv_pitch, offset1, offset2;
772    unsigned char *src, *dst;
773    unsigned int pixfmt;
774    struct v4l2_buffer bfr;
775    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
776
777    if (pPriv->run > 0 && pPriv->dir >= 0)
778        return BadMatch;
779    if (pPriv->fd < 0) {
780        z4l_open_device(pPriv);
781        if (pPriv->fd < 0)
782            return BadValue;
783    }
784
785    fd = pPriv->fd;
786    if (pPriv->run < 0) {
787        DBLOG(2, "PutImg id %#x src %d,%d %dx%d drw %d,%d %dx%d bfr %p "
788              "%dx%d data %p\n", id, src_x, src_y, src_w, src_h, drw_x,
789              drw_y, drw_w, drw_h, buf, width, height, data);
790        pPriv->pixfmt = pPriv->height = -1;
791        pPriv->src_is_set = pPriv->drw_is_set = 0;
792    }
793
794    pixfmt = z4l_fourcc_pixfmt(id);
795    if (pixfmt != pPriv->pixfmt) {
796        z4l_ovly_reset(pPriv);
797        z4l_ovly_pixfmt(pPriv, pixfmt);
798    }
799    if (pPriv->width != width || pPriv->height != height) {
800        z4l_ovly_reset(pPriv);
801        z4l_ovly_bfr(pPriv, width, height);
802    }
803
804    if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 ||
805        pPriv->src_x != src_x || pPriv->src_y != src_y ||
806        pPriv->src_w != src_w || pPriv->src_h != src_h ||
807        pPriv->drw_x != drw_x || pPriv->drw_y != drw_y ||
808        pPriv->drw_w != drw_w || pPriv->drw_h != drw_h)
809        z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w,
810                      drw_h);
811
812    if (pPriv->run < 0) {
813        z4l_ovly_start(pPriv, -1);
814        if (pPriv->run < 0)
815            return BadValue;
816    }
817
818    if (pPriv->last < 0 && (pPriv->last = z4l_ovly_dqbuf(pPriv)) < 0)
819        return BadAlloc;
820
821    z4l_ovly_pitch(pixfmt, width, height, &y_pitch, &uv_pitch,
822                   &offset1, &offset2, &size);
823    src = buf;
824    dst = (unsigned char *) pPriv->bfrs[pPriv->last].start;
825    DBLOG(3, "cpy %4.4s src %p dst %p yp %d uvp %d o1 %d o2 %d sz %d\n",
826          (char *) &id, src, dst, y_pitch, uv_pitch, offset1, offset2, size);
827
828    if (id == FOURCC_Y800) {
829        memcpy(dst, src, offset1);
830        src += offset1;
831        dst += offset1;
832        memset(dst, 0x80, 2 * offset2);
833    }
834    else
835        memcpy(dst, src, size);
836
837    memset(&bfr, 0, sizeof(bfr));
838    bfr.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
839    bfr.index = pPriv->last;
840    bfr.timestamp.tv_sec = 0;
841    bfr.timestamp.tv_usec = 0;
842    bfr.flags |= V4L2_BUF_FLAG_TIMECODE;
843    if (IoCtl(fd, VIDIOC_QBUF, &bfr, 1) != 0)
844        return BadAccess;
845
846    pPriv->last = z4l_ovly_dqbuf(pPriv);
847    z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes);
848
849    return Success;
850}
851
852static int
853Z4lQueryImageAttributes(ScrnInfoPtr pScrni, int id, unsigned short *width,
854                        unsigned short *height, int *pitches, int *offsets)
855{
856    int w, h, size;
857    int y_pitch, uv_pitch, offset1, offset2;
858    unsigned int pixfmt = z4l_fourcc_pixfmt(id);
859
860    w = *width;
861    h = *height;
862    if (w > MAX_OVLY_WIDTH)
863        w = MAX_OVLY_WIDTH;
864    if (h > MAX_OVLY_HEIGHT)
865        h = MAX_OVLY_HEIGHT;
866
867    z4l_ovly_pitch(pixfmt, w, h, &y_pitch, &uv_pitch,
868                   &offset1, &offset2, &size);
869
870    if (offsets != NULL)
871        offsets[0] = 0;
872    if (pitches != NULL)
873        pitches[0] = y_pitch;
874
875    switch (pixfmt) {
876    case V4L2_PIX_FMT_YVU420:
877    case V4L2_PIX_FMT_YUV420:
878        if (offsets != NULL) {
879            offsets[1] = offset1;
880            offsets[2] = offset1 + offset2;
881        }
882        if (pitches != NULL)
883            pitches[1] = pitches[2] = uv_pitch;
884        h = (h + 1) & ~1;
885        break;
886    }
887
888    w = (w + 1) & ~1;
889    *width = w;
890    *height = h;
891    DBLOG(1, "Z4lQueryImageAttributes(%4.4s) = %d, %dx%d %d/%d %d/%d\n",
892          (char *) &id, size, w, h, y_pitch, uv_pitch, offset1, offset2);
893
894    return size;
895}
896
897static int
898Z4lPutVideo(ScrnInfoPtr pScrni, short src_x, short src_y, short drw_x,
899            short drw_y, short src_w, short src_h, short drw_w, short drw_h,
900            RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
901{
902    int id;
903    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
904
905    DBLOG(2, "PutVid src %d,%d %dx%d drw %d,%d %dx%d data %p\n",
906          src_x, src_y, src_w, src_h, drw_x, drw_y, drw_w, drw_h, data);
907
908    if (z4l_open_device(pPriv) >= 0) {
909        if (pPriv->run < 0) {
910            DBLOG(2, "PutVid start\n");
911            z4l_ovly_get_encoding(pPriv, &id);
912            z4l_ovly_set_encoding(pPriv, id);
913        }
914        DBLOG(2, "PutVid priv %d,%d %dx%d drw %d,%d %dx%d\n",
915              pPriv->src_x, pPriv->src_y, pPriv->src_w, pPriv->src_h,
916              pPriv->drw_x, pPriv->drw_y, pPriv->drw_w, pPriv->drw_h);
917        if (pPriv->src_is_set == 0 || pPriv->drw_is_set == 0 ||
918            pPriv->src_w != src_w || pPriv->src_h != src_h ||
919            pPriv->drw_x != drw_x || pPriv->drw_y != drw_y ||
920            pPriv->drw_w != drw_w || pPriv->drw_h != drw_h)
921            z4l_ovly_rect(pPriv, src_x, src_y, src_w, src_h, drw_x, drw_y,
922                          drw_w, drw_h);
923        if (pPriv->run < 0)
924            z4l_ovly_start(pPriv, 0);
925
926        z4l_setup_colorkey(pPriv, pScrni->pScreen, clipBoxes);
927    }
928
929    return Success;
930}
931
932static XF86VideoEncodingPtr
933Z4lNewEncoding(XF86VideoEncodingPtr * encs, int *nencs)
934{
935    XF86VideoEncodingPtr enc;
936    XF86VideoEncodingPtr tencs =
937        (XF86VideoEncodingPtr) realloc(*encs, sizeof(*tencs) * (*nencs + 1));
938
939    if (tencs == NULL)
940        return NULL;
941
942    *encs = tencs;
943    enc = &tencs[*nencs];
944    ++*nencs;
945    memset(enc, 0, sizeof(*enc));
946
947    return enc;
948}
949
950static void
951Z4lEncodingName(char *ename, int l, char *inp_name, char *std_name, char *fmt)
952{
953    int i, ch;
954
955    while ((ch = *inp_name++) != 0) {
956        if (isalnum(ch) == 0)
957            continue;
958        if (--l <= 0)
959            goto xit;
960        *ename++ = ch;
961    }
962
963    if (--l <= 0)
964        goto xit;
965
966    *ename++ = '-';
967
968    while ((ch = *std_name++) != 0) {
969        if (isalnum(ch) == 0)
970            continue;
971        if (--l <= 0)
972            goto xit;
973        *ename++ = ch;
974    }
975
976    if (--l <= 0)
977        goto xit;
978
979    *ename++ = '-';
980    i = 4;
981
982    while (--i >= 0 && (ch = *fmt++) != 0) {
983        if (isalnum(ch) == 0)
984            continue;
985        if (--l <= 0)
986            goto xit;
987        *ename++ = ch;
988    }
989
990 xit:
991    *ename = 0;
992}
993
994static int
995Z4lAddEncoding(XF86VideoEncodingPtr enc, char *name, int id, int width,
996               int height, int numer, int denom, int inp, v4l2_std_id std,
997               unsigned int fmt)
998{
999    int l, n;
1000    t_std_data *sp;
1001    char *cp;
1002
1003    n = sizeof(int) - 1;
1004    l = strlen(&name[0]) + 1;
1005    l = (l + n) & ~n;
1006    n = l + sizeof(*sp);
1007    cp = (char *) malloc(n);
1008
1009    if (cp == NULL)
1010        return 0;
1011
1012    sp = (t_std_data *) (cp + l);
1013    enc->id = id;
1014    strcpy(cp, &name[0]);
1015    enc->name = cp;
1016    enc->width = width;
1017    enc->height = height;
1018    enc->rate.numerator = numer;
1019    enc->rate.denominator = denom;
1020    sp->inp = inp;
1021    sp->std = std;
1022    sp->fmt = fmt;
1023    DBLOG(1, "enc %s\n", &name[0]);
1024
1025    return 1;
1026}
1027
1028static XF86ImagePtr
1029Z4lNewImage(XF86ImagePtr * imgs, int *nimgs)
1030{
1031    XF86ImagePtr img;
1032    XF86ImagePtr timgs =
1033        (XF86ImagePtr) realloc(*imgs, sizeof(*timgs) * (*nimgs + 1));
1034
1035    if (timgs == NULL)
1036        return NULL;
1037
1038    *imgs = timgs;
1039    img = &timgs[*nimgs];
1040    ++*nimgs;
1041    memset(img, 0, sizeof(*img));
1042
1043    return img;
1044}
1045
1046static int
1047Z4lAddImage(XF86ImagePtr img, XF86ImagePtr ip)
1048{
1049    *img = *ip;
1050    DBLOG(1, "img %4.4s\n", (char *) &img->id);
1051    return 1;
1052}
1053
1054static XF86AttributePtr
1055Z4lNewAttribute(XF86AttributePtr * attrs, int *nattrs)
1056{
1057    XF86AttributePtr attr;
1058    XF86AttributePtr tattrs =
1059        (XF86AttributePtr) realloc(*attrs, sizeof(*tattrs) * (*nattrs + 1));
1060
1061    if (tattrs == NULL)
1062        return NULL;
1063
1064    *attrs = tattrs;
1065    attr = &tattrs[*nattrs];
1066    ++*nattrs;
1067    memset(attr, 0, sizeof(*attr));
1068
1069    return attr;
1070}
1071
1072static void
1073Z4lAttributeName(char *bp, int l, char *cp)
1074{
1075    int ch;
1076    char *atomNm = bp;
1077
1078    if (l > 0) {
1079        *bp++ = 'X';
1080        --l;
1081    }
1082    if (l > 0) {
1083        *bp++ = 'V';
1084        --l;
1085    }
1086    if (l > 0) {
1087        *bp++ = '_';
1088        --l;
1089    }
1090
1091    while (l > 0 && (ch = *cp++) != 0) {
1092        if (isalnum(ch) == 0)
1093            continue;
1094        *bp++ = toupper(ch);
1095    }
1096
1097    *bp = 0;
1098    MakeAtom(&atomNm[0], strlen(&atomNm[0]), TRUE);
1099}
1100
1101static int
1102Z4lAddAttribute(XF86AttributePtr attr, char *name, int min, int max, int flags)
1103{
1104    char *cp = (char *) malloc(strlen((char *) &name[0]) + 1);
1105
1106    if (cp == NULL)
1107        return 0;
1108
1109    attr->name = cp;
1110    strcpy(&attr->name[0], name);
1111    attr->min_value = min;
1112    attr->max_value = max;
1113    attr->flags = flags;
1114    DBLOG(1, "attr %s\n", attr->name);
1115
1116    return 1;
1117}
1118
1119static XF86VideoAdaptorPtr
1120Z4lNewAdaptor(XF86VideoAdaptorPtr ** adpts, int *nadpts, int nattrs)
1121{
1122    int n;
1123    Z4lPortPrivRec *pPriv;
1124    XF86VideoAdaptorPtr adpt, *tadpts;
1125
1126    tadpts = (XF86VideoAdaptorPtr *) realloc(*adpts,
1127                                             sizeof(*tadpts) * (*nadpts + 1));
1128
1129    if (tadpts == NULL)
1130        return NULL;
1131
1132    *adpts = tadpts;
1133    n = sizeof(*adpt) + sizeof(*pPriv) + 1 * sizeof(*adpt->pPortPrivates);
1134    n += (nattrs - 1) * sizeof(pPriv->attrIds[0]);
1135    adpt = (XF86VideoAdaptorPtr) malloc(n);
1136
1137    if (adpt == NULL)
1138        return NULL;
1139
1140    memset(adpt, 0, n);
1141    tadpts[*nadpts] = adpt;
1142    ++*nadpts;
1143    adpt->pPortPrivates = (DevUnion *) &adpt[1];
1144    pPriv = (Z4lPortPrivRec *) & adpt->pPortPrivates[1];
1145    adpt->pPortPrivates[0].ptr = (pointer) pPriv;
1146    pPriv->adpt = adpt;
1147    adpt->nPorts = 1;
1148
1149    return adpt;
1150}
1151
1152static int
1153Z4lSetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value,
1154                    pointer data)
1155{
1156    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
1157    XF86VideoAdaptorPtr adpt;
1158    XF86AttributePtr attr;
1159    struct v4l2_control ctrl;
1160    int i, nattrs, attrId, val;
1161    const char *name = NameForAtom(attribute);
1162    int old_fd = pPriv->fd;
1163
1164    DBLOG(1, "Z4lSetPortAttribute(%#lx,%d) '%s'\n", (unsigned long) attribute,
1165          (int) value, name != NULL ? name : "_null_");
1166
1167    if (name == NULL)
1168        return BadImplementation;
1169    if (old_fd < 0 && z4l_open_device(pPriv) < 0)
1170        return BadAccess;
1171
1172    adpt = pPriv->adpt;
1173    attr = adpt->pAttributes;
1174    nattrs = adpt->nAttributes;
1175
1176    for (i = 0; i < nattrs; ++i, ++attr)
1177        if (strcmp(attr->name, name) == 0)
1178            break;
1179
1180    if (i >= nattrs)
1181        return BadMatch;
1182
1183    attrId = pPriv->attrIds[i];
1184    val = value;
1185
1186    switch (attrId) {
1187    case ATTR_ENCODING_ID:
1188        z4l_ovly_set_encoding(pPriv, val);
1189        break;
1190    case ATTR_KEYMODE_ID:
1191        z4l_ovly_set_keymode(pPriv, val);
1192        REGION_EMPTY(pScrni->pScreen, &pPriv->clips);
1193        z4l_setup_colorkey(pPriv, pScrni->pScreen, &pPriv->clips);
1194        break;
1195    case ATTR_COLORKEY_ID:
1196        z4l_ovly_set_colorkey(pPriv, val);
1197        break;
1198    default:
1199        memset(&ctrl, 0, sizeof(ctrl));
1200        ctrl.id = attrId + V4L2_CID_BASE;
1201        ctrl.value = val;
1202        if (IoCtl(pPriv->fd, VIDIOC_S_CTRL, &ctrl, 1) != 0)
1203            return BadMatch;
1204        break;
1205    }
1206
1207    if (old_fd < 0)
1208        z4l_close_device(pPriv);
1209
1210    return Success;
1211}
1212
1213static int
1214Z4lGetPortAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 *value,
1215                    pointer data)
1216{
1217    Z4lPortPrivRec *pPriv = (Z4lPortPrivRec *) data;
1218    XF86VideoAdaptorPtr adpt;
1219    XF86AttributePtr attr;
1220    struct v4l2_control ctrl;
1221    int i, nattrs, attrId, val;
1222    const char *name = NameForAtom(attribute);
1223    int old_fd = pPriv->fd;
1224
1225    DBLOG(1, "Z4lGetPortAttribute(%#lx) '%s'\n",
1226          (unsigned long) attribute, name != NULL ? name : "_null_");
1227
1228    if (name == NULL)
1229        return BadImplementation;
1230    if (old_fd < 0 && z4l_open_device(pPriv) < 0)
1231        return BadAccess;
1232
1233    adpt = pPriv->adpt;
1234    attr = adpt->pAttributes;
1235    nattrs = adpt->nAttributes;
1236
1237    for (i = 0; i < nattrs; ++i, ++attr)
1238        if (strcmp(attr->name, name) == 0)
1239            break;
1240
1241    if (i >= nattrs)
1242        return BadMatch;
1243
1244    attrId = pPriv->attrIds[i];
1245    val = 0;
1246
1247    switch (attrId) {
1248    case ATTR_ENCODING_ID:
1249        z4l_ovly_get_encoding(pPriv, &val);
1250        *value = val;
1251        break;
1252    case ATTR_KEYMODE_ID:
1253        z4l_ovly_get_keymode(pPriv, &val);
1254        *value = val;
1255        break;
1256    case ATTR_COLORKEY_ID:
1257        z4l_ovly_get_colorkey(pPriv, &val);
1258        break;
1259    default:
1260        memset(&ctrl, 0, sizeof(ctrl));
1261        ctrl.id = attrId + V4L2_CID_BASE;
1262        if (IoCtl(pPriv->fd, VIDIOC_G_CTRL, &ctrl, 1) != 0)
1263            return BadMatch;
1264        val = ctrl.value;
1265        break;
1266    }
1267
1268    if (old_fd < 0)
1269        z4l_close_device(pPriv);
1270
1271    *value = val;
1272
1273    return Success;
1274}
1275
1276static void (*oldAdjustFrame) (ADJUST_FRAME_ARGS_DECL) = NULL;
1277
1278static void
1279Z4lAdjustFrame(ADJUST_FRAME_ARGS_DECL)
1280{
1281    SCRN_INFO_PTR(arg);
1282    int i;
1283    XF86VideoAdaptorPtr adpt;
1284    Z4lPortPrivRec *pPriv;
1285
1286    DBLOG(3, "Z4lAdjustFrame(%d,%d)\n", x, y);
1287    z4l_x_offset = x;
1288    z4l_y_offset = y;
1289    oldAdjustFrame(ADJUST_FRAME_ARGS(x, y));
1290
1291    /* xv adjust does not handle putvideo case */
1292    for (i = 0; i < Z4l_nAdaptors; ++i) {
1293        adpt = Z4l_pAdaptors[i];
1294        pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr;
1295        if (pPriv->run > 0) {
1296            pPriv->drw_is_set = 0;
1297            z4l_ovly_rect(pPriv,
1298                          pPriv->src_x, pPriv->src_y, pPriv->src_w,
1299                          pPriv->src_h, pPriv->drw_x, pPriv->drw_y,
1300                          pPriv->drw_w, pPriv->drw_h);
1301        }
1302    }
1303}
1304
1305static int
1306Z4lInit(ScrnInfoPtr pScrni, XF86VideoAdaptorPtr ** adaptors)
1307{
1308    int i, id, fd, dev, enable, has_video, has_colorkey;
1309    int ctl, cinp, inp, std, fmt, has_image;
1310    int nadpts, nattrs, nencs, cenc, nimgs;
1311    int numer, denom, width, height;
1312    unsigned int pixfmt, cpixfmt, opixfmt;
1313    XF86VideoAdaptorPtr *adpts, adpt;
1314    XF86AttributePtr attrs, attr;
1315    XF86VideoEncodingPtr encs, enc;
1316    XF86ImagePtr ip, img, imgs;
1317    Z4lPortPrivRec *pPriv;
1318    char *dp, *msg;
1319    char enc_name[256], attr_name[256];
1320    int attrIds[V4L2_CID_LASTP1 - V4L2_CID_BASE + ATTR_MAX_ID];
1321    struct v4l2_capability capability;
1322    v4l2_std_id cstd_id, std_id;
1323    struct v4l2_standard standard;
1324    struct v4l2_format format, cfmt;
1325    struct v4l2_input input;
1326    struct v4l2_fmtdesc fmtdesc;
1327    struct v4l2_queryctrl queryctrl;
1328    struct v4l2_framebuffer fbuf;
1329
1330    DBLOG(1, "Init\n");
1331    if (oldAdjustFrame == NULL) {
1332        oldAdjustFrame = pScrni->AdjustFrame;
1333        pScrni->AdjustFrame = Z4lAdjustFrame;
1334    }
1335
1336    fd = -1;
1337    enc = NULL;
1338    encs = NULL;
1339    nencs = 0;
1340    img = NULL;
1341    imgs = NULL;
1342    nimgs = 0;
1343    attr = NULL;
1344    attrs = NULL;
1345    nattrs = 0;
1346    adpt = NULL;
1347    adpts = NULL;
1348    nadpts = 0;
1349    has_video = has_image = has_colorkey = 0;
1350
1351    for (dev = 0; z4l_dev_paths[dev] != NULL; ++dev) {
1352        fd = open(z4l_dev_paths[dev], O_RDWR, 0);
1353        if (fd < 0)
1354            continue;
1355        DBLOG(1, "%s open ok\n", z4l_dev_paths[dev]);
1356        msg = NULL;
1357        enable = 1;
1358        if (IoCtl(fd, VIDIOC_QUERYCAP, &capability, 1) < 0)
1359            msg = "bad querycap";
1360        else if ((capability.capabilities & V4L2_CAP_VIDEO_OVERLAY) == 0)
1361            msg = "no overlay";
1362        else if ((capability.capabilities & V4L2_CAP_STREAMING) == 0)
1363            msg = "no streaming";
1364#ifdef NONBLK_IO
1365        else if (IoCtl(fd, FIONBIO, &enable, 1) != 0)
1366            msg = "cant enable non-blocking io";
1367#endif
1368        if (msg == NULL) {
1369            memset(&format, 0, sizeof(format));
1370            format.type = 0x100;
1371            if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) != 0)
1372                msg = "no src/dst ovly fmt";
1373        }
1374        if (msg != NULL) {
1375            DBLOG(0, "%s %s\n", z4l_dev_paths[dev], msg);
1376            close(fd);
1377            continue;
1378        }
1379
1380        memset(&cfmt, 0, sizeof(cfmt));
1381        cfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1382        if (IoCtl(fd, VIDIOC_G_FMT, &cfmt, 1) < 0)
1383            goto fail;
1384        if (IoCtl(fd, VIDIOC_G_STD, &cstd_id, 1) < 0)
1385            goto fail;
1386        if (IoCtl(fd, VIDIOC_G_INPUT, &cinp, 1) < 0)
1387            goto fail;
1388        cpixfmt = cfmt.fmt.pix.pixelformat;
1389        cenc = 0;
1390        for (inp = 0;; ++inp) {
1391            memset(&input, 0, sizeof(input));
1392            input.index = inp;
1393            if (IoCtl(fd, VIDIOC_ENUMINPUT, &input, 0) < 0)
1394                break;
1395            id = inp;
1396            if (IoCtl(fd, VIDIOC_S_INPUT, &id, 1) < 0)
1397                goto fail;
1398            for (std = 0;; ++std) {
1399                memset(&standard, 0, sizeof(standard));
1400                standard.index = std;
1401                if (IoCtl(fd, VIDIOC_ENUMSTD, &standard, 0) < 0)
1402                    break;
1403                std_id = standard.id;
1404                denom = standard.frameperiod.denominator;
1405                numer = standard.frameperiod.numerator;
1406                if (IoCtl(fd, VIDIOC_S_STD, &std_id, 1) < 0)
1407                    continue;
1408                memset(&format, 0, sizeof(format));
1409                format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1410                if (IoCtl(fd, VIDIOC_G_FMT, &format, 1) < 0)
1411                    continue;
1412                width = format.fmt.pix.width;
1413                height = format.fmt.pix.height;
1414                for (fmt = 0;; ++fmt) {
1415                    memset(&fmtdesc, 0, sizeof(fmtdesc));
1416                    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1417                    fmtdesc.index = fmt;
1418                    if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0)
1419                        break;
1420                    pixfmt = fmtdesc.pixelformat;
1421                    ip = &pixfmts[0];
1422                    for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0;
1423                         ++ip)
1424                        if (z4l_fourcc_pixfmt(ip->id) == pixfmt)
1425                            break;
1426
1427                    if (i >= 0) {
1428                        id = nencs;
1429                        has_video = 1;
1430                        if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL)
1431                            goto fail;
1432                        Z4lEncodingName(&enc_name[0], sizeof(enc_name),
1433                                        (char *) &input.name[0],
1434                                        (char *) &standard.name[0],
1435                                        (char *) &pixfmt);
1436                        if (Z4lAddEncoding
1437                            (enc, &enc_name[0], id, width, height, denom, numer,
1438                             inp, std_id, pixfmt) == 0)
1439                            goto fail;
1440                        if (std_id == cstd_id && inp == cinp
1441                            && pixfmt == cpixfmt)
1442                            cenc = id;
1443                    }
1444                }
1445            }
1446        }
1447
1448        if (IoCtl(fd, VIDIOC_S_INPUT, &cinp, 1) < 0)
1449            goto fail;
1450        if (IoCtl(fd, VIDIOC_S_STD, &cstd_id, 1) < 0)
1451            goto fail;
1452        if (IoCtl(fd, VIDIOC_S_FMT, &cfmt, 1) < 0)
1453            goto fail;
1454
1455        if (encs == NULL) {
1456            DBLOG(0, "no encodings\n");
1457            goto fail;
1458        }
1459
1460        for (fmt = 0;; ++fmt) {
1461            memset(&fmtdesc, 0, sizeof(fmtdesc));
1462            fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
1463            fmtdesc.index = fmt;
1464            if (IoCtl(fd, VIDIOC_ENUM_FMT, &fmtdesc, 0) < 0)
1465                break;
1466            pixfmt = fmtdesc.pixelformat;
1467            ip = &pixfmts[0];
1468            for (i = sizeof(pixfmts) / sizeof(pixfmts[0]); --i >= 0; ++ip)
1469                if (z4l_fourcc_pixfmt(ip->id) == pixfmt)
1470                    break;
1471
1472            if (i >= 0) {
1473                has_image = 1;
1474                if ((img = Z4lNewImage(&imgs, &nimgs)) == NULL)
1475                    goto fail;
1476                if (Z4lAddImage(img, ip) == 0)
1477                    goto fail;
1478            }
1479        }
1480
1481        if (nimgs > 0) {
1482            id = nencs;
1483            if ((enc = Z4lNewEncoding(&encs, &nencs)) == NULL)
1484                goto fail;
1485            if (Z4lAddEncoding(enc, "XV_IMAGE", id, MAX_OVLY_WIDTH,
1486                               MAX_OVLY_HEIGHT, 0, 0, 0, 0, pixfmt) == 0)
1487                goto fail;
1488        }
1489
1490        ctl = 0;
1491        for (ctl = 0; ctl < (V4L2_CID_LASTP1 - V4L2_CID_BASE); ++ctl) {
1492            memset(&queryctrl, 0, sizeof(queryctrl));
1493            queryctrl.id = V4L2_CID_BASE + ctl;
1494            if (IoCtl(fd, VIDIOC_QUERYCTRL, &queryctrl, 0) < 0)
1495                continue;
1496            if (queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
1497                queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN)
1498                continue;
1499            attrIds[nattrs] = ctl;
1500            if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
1501                goto fail;
1502            Z4lAttributeName(&attr_name[0], sizeof(attr_name),
1503                             (char *) &queryctrl.name[0]);
1504            if (Z4lAddAttribute(attr, &attr_name[0],
1505                                queryctrl.minimum, queryctrl.maximum,
1506                                XvSettable | XvGettable) == 0)
1507                goto fail;
1508        }
1509        attrIds[nattrs] = ATTR_ENCODING_ID;
1510        if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
1511            goto fail;
1512        Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_ENCODING);
1513        if (Z4lAddAttribute(attr, &attr_name[0], 0, nencs - 1,
1514                            XvSettable | XvGettable) == 0)
1515            goto fail;
1516        memset(&fbuf, 0, sizeof(fbuf));
1517        if (IoCtl(fd, VIDIOC_G_FBUF, &fbuf, 1) < 0)
1518            goto fail;
1519        opixfmt = fbuf.fmt.pixelformat;
1520
1521        if ((fbuf.capability & V4L2_FBUF_CAP_CHROMAKEY) != 0) {
1522            attrIds[nattrs] = ATTR_KEYMODE_ID;
1523            if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
1524                goto fail;
1525            Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_KEYMODE);
1526            if (Z4lAddAttribute(attr, &attr_name[0], 0, 1,
1527                                XvSettable | XvGettable) == 0)
1528                goto fail;
1529            attrIds[nattrs] = ATTR_COLORKEY_ID;
1530            if ((attr = Z4lNewAttribute(&attrs, &nattrs)) == NULL)
1531                goto fail;
1532            Z4lAttributeName(&attr_name[0], sizeof(attr_name), ATTR_COLORKEY);
1533            if (Z4lAddAttribute(attr, &attr_name[0], 0, 0xffffff,
1534                                XvSettable | XvGettable) == 0)
1535                goto fail;
1536            has_colorkey = 1;
1537        }
1538
1539        dp = malloc(strlen((char *) &capability.card[0]) + 1);
1540        if (dp == NULL)
1541            goto fail;
1542        strcpy(dp, (char *) &capability.card[0]);
1543        if ((adpt = Z4lNewAdaptor(&adpts, &nadpts, nattrs)) == NULL)
1544            goto fail;
1545        adpt->type = XvWindowMask | XvInputMask;
1546        if (has_video != 0)
1547            adpt->type |= XvVideoMask;
1548        if (has_image != 0)
1549            adpt->type |= XvImageMask;
1550        adpt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
1551        adpt->name = dp;
1552        adpt->type = XvInputMask | XvWindowMask | XvVideoMask | XvImageMask;
1553        adpt->pEncodings = encs;
1554        adpt->nEncodings = nencs;
1555        adpt->pFormats = &Formats[0];
1556        adpt->nFormats = sizeof(Formats) / sizeof(Formats[0]);
1557        adpt->pAttributes = attrs;
1558        adpt->nAttributes = nattrs;
1559        attrs = NULL;
1560        nattrs = 0;
1561        adpt->pImages = imgs;
1562        adpt->nImages = nimgs;
1563        imgs = NULL;
1564        nimgs = 0;
1565        adpt->PutVideo = Z4lPutVideo;
1566        adpt->StopVideo = Z4lStopVideo;
1567        adpt->SetPortAttribute = Z4lSetPortAttribute;
1568        adpt->GetPortAttribute = Z4lGetPortAttribute;
1569        adpt->QueryBestSize = Z4lQueryBestSize;
1570        adpt->PutImage = Z4lPutImage;
1571        adpt->QueryImageAttributes = Z4lQueryImageAttributes;
1572        pPriv = (Z4lPortPrivRec *) adpt->pPortPrivates[0].ptr;
1573        pPriv->fd = fd;
1574        pPriv->run = -1;
1575        pPriv->dir = 0;
1576        pPriv->nbfrs = -1;
1577        pPriv->bufsz = -1;
1578        pPriv->last = -1;
1579        pPriv->pixfmt = opixfmt;
1580#if defined(REGION_NULL)
1581        REGION_NULL(pScrni->pScreen, &pPriv->clips);
1582#else
1583        REGION_INIT(pScrni->pScreen, &pPriv->clips, NullBox, 0);
1584#endif
1585        strncpy(&pPriv->dev_path[0], z4l_dev_paths[dev],
1586                sizeof(pPriv->dev_path));
1587        pPriv->enc = &encs[cenc];
1588        for (i = 0; i < adpt->nAttributes; ++i)
1589            pPriv->attrIds[i] = attrIds[i];
1590        DBLOG(1, "adpt %s\n", dp);
1591        if (has_colorkey != 0) {
1592            z4l_ovly_set_colorkey(pPriv, DEFAULT_COLORKEY);
1593            z4l_ovly_set_keymode(pPriv, DEFAULT_KEYMODE);
1594        }
1595        close(fd);
1596        pPriv->fd = -1;
1597        adpt = NULL;
1598        cenc = 0;
1599        encs = NULL;
1600        nencs = 0;
1601    }
1602
1603    DBLOG(0, "init done, %d device(s) found\n", nadpts);
1604    Z4l_nAdaptors = nadpts;
1605    Z4l_pAdaptors = adpts;
1606    *adaptors = adpts;
1607
1608    return nadpts;
1609
1610 fail:
1611    if (attrs != NULL) {
1612        for (i = 0; i < nattrs; ++i)
1613            if (attrs[i].name != NULL)
1614                free(attrs[i].name);
1615        free(attrs);
1616    }
1617
1618    if (encs != NULL) {
1619        for (i = 0; i < nencs; ++i) {
1620            if (encs[i].name != NULL)
1621                free(encs[i].name);
1622        }
1623        free(encs);
1624    }
1625
1626    if (imgs != NULL)
1627        free(imgs);
1628
1629    if (adpts != NULL) {
1630        for (i = 0; i < nadpts; ++i) {
1631            if ((adpt = adpts[i]) != NULL) {
1632                if (adpt->name != NULL)
1633                    free(adpt->name);
1634                if ((attrs = adpt->pAttributes) != NULL) {
1635                    for (i = 0; i < adpt->nAttributes; ++i)
1636                        if (attrs[i].name != NULL)
1637                            free(attrs[i].name);
1638                    free(attrs);
1639                }
1640                if ((encs = adpt->pEncodings) != NULL) {
1641                    for (i = 0; i < adpt->nEncodings; ++i, ++enc)
1642                        if (encs[i].name != NULL)
1643                            free(encs[i].name);
1644                    free(encs);
1645                }
1646                if ((imgs = adpt->pImages) != NULL)
1647                    free(imgs);
1648                free(adpt);
1649            }
1650        }
1651        free(adpts);
1652    }
1653
1654    if (fd >= 0)
1655        close(fd);
1656
1657    return 0;
1658}
1659
1660static Bool
1661Z4lProbe(DriverPtr drv, int flags)
1662{
1663    DBLOG(1, "Probe\n");
1664    if (flags & PROBE_DETECT)
1665        return TRUE;
1666
1667    xf86XVRegisterGenericAdaptorDriver(Z4lInit);
1668    drv->refCount++;
1669
1670    return TRUE;
1671}
1672
1673static const OptionInfoRec *
1674Z4lAvailableOptions(int chipid, int busid)
1675{
1676    return NULL;
1677}
1678
1679static void
1680Z4lIdentify(int flags)
1681{
1682    xf86Msg(X_INFO, "z4l driver for Video4Linux\n");
1683}
1684
1685_X_EXPORT DriverRec Z4l = {
1686    40001,
1687    "z4l",
1688    Z4lIdentify,
1689    Z4lProbe,
1690    Z4lAvailableOptions,
1691    NULL,
1692    0
1693};
1694
1695#ifdef XFree86LOADER
1696
1697static MODULESETUPPROTO(z4lSetup);
1698
1699static XF86ModuleVersionInfo z4lVersionRec = {
1700    "ztv",
1701    MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2,
1702    XORG_VERSION_CURRENT, 0, 0, 1,
1703    ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_NONE,
1704    {0, 0, 0, 0}
1705};
1706
1707_X_EXPORT XF86ModuleData ztvModuleData = { &z4lVersionRec, z4lSetup, NULL };
1708
1709static pointer
1710z4lSetup(pointer module, pointer opts, int *errmaj, int *errmin)
1711{
1712    const char *osname;
1713    static Bool setupDone = FALSE;
1714
1715    if (setupDone != FALSE) {
1716        if (errmaj != NULL)
1717            *errmaj = LDR_ONCEONLY;
1718        return NULL;
1719    }
1720
1721    setupDone = TRUE;
1722    LoaderGetOS(&osname, NULL, NULL, NULL);
1723
1724    if (osname == NULL || strcmp(osname, "linux") != 0) {
1725        if (errmaj)
1726            *errmaj = LDR_BADOS;
1727        if (errmin)
1728            *errmin = 0;
1729
1730        return NULL;
1731    }
1732
1733    xf86AddDriver(&Z4l, module, 0);
1734
1735    return (pointer) 1;
1736}
1737
1738#endif
1739#endif                          /* !XvExtension */
1740