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