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