1 /*
2 # libv4l1 userspace v4l1 api emulation for v4l2 devices
3 
4 #             (C) 2008-2010 Hans de Goede <hdegoede@redhat.com>
5 
6 # Based in part on the kernels v4l1 ioctl compatibility code which is:
7 
8 #             (C) 2003-2009 Bill Dirks <bill@thedirks.org>, et al.
9 
10 # The code taken from the kernel has been relicensed from GPLv2+ to LGPLv2+
11 # with permission from the authors see libv4l1-kernelcode-license.txt
12 
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU Lesser General Public License as published by
15 # the Free Software Foundation; either version 2.1 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 # GNU Lesser General Public License for more details.
22 #
23 # You should have received a copy of the GNU Lesser General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
26 */
27 
28 /* MAKING CHANGES TO THIS FILE??   READ THIS FIRST!!!
29 
30    Important note to people making changes to this file: All functions
31    (v4l1_close, v4l1_ioctl, etc.) are designed to function as their regular
32    counterpart when they get passed a fd that is not "registered" by libv4l1,
33    there are 2 reasons for this:
34    1) This allows us to get completely out of the way when dealing with non
35       capture only devices, or non v4l2 devices.
36    2) libv4l1 is the base of the v4l1compat.so wrapper lib, which is a .so
37       which can be LD_PRELOAD-ed and the overrules the libc's open/close/etc,
38       and when opening /dev/videoX or /dev/v4l/ calls v4l1_open. Because we
39       behave as the regular counterpart when the fd is not known (instead of
40       say throwing an error), v4l1compat.so can simply call the v4l1_ prefixed
41       function for all wrapped functions. This way the wrapper does not have
42       to keep track of which fd's are being handled by libv4l1, as libv4l1
43       already keeps track of this itself.
44 
45       This also means that libv4l1 may not use any of the regular functions
46       it mimics, as for example open could be a symbol in v4l1compat.so, which
47       in turn will call v4l1_open, so therefor v4l1_open (for example) may not
48       use the regular open()!
49 */
50 #include <config.h>
51 #include <errno.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <fcntl.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <sys/types.h>
59 #include <sys/mman.h>
60 #include "../libv4lconvert/libv4lsyscall-priv.h"
61 #if defined(__OpenBSD__)
62 #include <sys/videoio.h>
63 #else
64 #include <linux/videodev2.h>
65 #endif
66 #include <libv4l2.h>
67 #include "libv4l1.h"
68 #include "libv4l1-priv.h"
69 
70 #define V4L1_SUPPORTS_ENUMINPUT 0x01
71 #define V4L1_SUPPORTS_ENUMSTD   0x02
72 #define V4L1_PIX_FMT_TOUCHED    0x04
73 #define V4L1_PIX_SIZE_TOUCHED   0x08
74 
75 static pthread_mutex_t v4l1_open_mutex = PTHREAD_MUTEX_INITIALIZER;
76 static struct v4l1_dev_info devices[V4L1_MAX_DEVICES] = {
77 	{ .fd = -1 },
78 	{ .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
79 	{ .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 },
80 	{ .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }, { .fd = -1 }
81 };
82 static int devices_used;
83 
palette_to_pixelformat(unsigned int palette)84 static unsigned int palette_to_pixelformat(unsigned int palette)
85 {
86 	switch (palette) {
87 	case VIDEO_PALETTE_GREY:
88 		return V4L2_PIX_FMT_GREY;
89 	case VIDEO_PALETTE_RGB555:
90 		return V4L2_PIX_FMT_RGB555;
91 	case VIDEO_PALETTE_RGB565:
92 		return V4L2_PIX_FMT_RGB565;
93 	case VIDEO_PALETTE_RGB24:
94 	        /* Yes v4l1 RGB24 really is BGR24, this is a weirdness in the
95 	           V4L1 API. Which unfortunately some V4L1 apps get wrong.
96 	           If you have an app which has r and b swapped and end up here
97 	           fix the app, this is not a libv4l1 bug */
98 		return V4L2_PIX_FMT_BGR24;
99 	case VIDEO_PALETTE_RGB32:
100 		return V4L2_PIX_FMT_BGR32;
101 	case VIDEO_PALETTE_YUYV:
102 		return V4L2_PIX_FMT_YUYV;
103 	case VIDEO_PALETTE_YUV422:
104 		return V4L2_PIX_FMT_YUYV;
105 	case VIDEO_PALETTE_UYVY:
106 		return V4L2_PIX_FMT_UYVY;
107 	case VIDEO_PALETTE_YUV410P:
108 		return V4L2_PIX_FMT_YUV410;
109 	case VIDEO_PALETTE_YUV420:
110 	case VIDEO_PALETTE_YUV420P:
111 		return V4L2_PIX_FMT_YUV420;
112 	case VIDEO_PALETTE_YUV411P:
113 		return V4L2_PIX_FMT_YUV411P;
114 	case VIDEO_PALETTE_YUV422P:
115 		return V4L2_PIX_FMT_YUV422P;
116 	}
117 	return 0;
118 }
119 
pixelformat_to_palette(unsigned int pixelformat)120 static unsigned int pixelformat_to_palette(unsigned int pixelformat)
121 {
122 	switch (pixelformat) {
123 	case V4L2_PIX_FMT_GREY:
124 		return VIDEO_PALETTE_GREY;
125 	case V4L2_PIX_FMT_RGB555:
126 		return VIDEO_PALETTE_RGB555;
127 	case V4L2_PIX_FMT_RGB565:
128 		return VIDEO_PALETTE_RGB565;
129 	case V4L2_PIX_FMT_BGR24:
130 	        /* See the comment in palette_to_pixelformat above */
131 		return VIDEO_PALETTE_RGB24;
132 	case V4L2_PIX_FMT_BGR32:
133 		return VIDEO_PALETTE_RGB32;
134 	case V4L2_PIX_FMT_YUYV:
135 		return VIDEO_PALETTE_YUYV;
136 	case V4L2_PIX_FMT_UYVY:
137 		return VIDEO_PALETTE_UYVY;
138 	case V4L2_PIX_FMT_YUV410:
139 	case V4L2_PIX_FMT_YUV420:
140 		return VIDEO_PALETTE_YUV420P;
141 	case V4L2_PIX_FMT_YUV411P:
142 		return VIDEO_PALETTE_YUV411P;
143 	case V4L2_PIX_FMT_YUV422P:
144 		return VIDEO_PALETTE_YUV422P;
145 	}
146 	return 0;
147 }
148 
count_inputs(int fd)149 static int count_inputs(int fd)
150 {
151 	struct v4l2_input input2;
152 	int i;
153 	for (i = 0;; i++) {
154 		memset(&input2, 0, sizeof(input2));
155 		input2.index = i;
156 		if (0 != v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2))
157 			break;
158 		}
159 	return i;
160 }
161 
v4l1_set_format(int index,unsigned int width,unsigned int height,int v4l1_pal,int width_height_may_differ)162 static int v4l1_set_format(int index, unsigned int width,
163 		unsigned int height, int v4l1_pal, int width_height_may_differ)
164 {
165 	int result;
166 	unsigned int v4l2_pixfmt;
167 	struct v4l2_format fmt2 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
168 
169 	if (v4l1_pal != -1) {
170 		v4l2_pixfmt = palette_to_pixelformat(v4l1_pal);
171 		if (!v4l2_pixfmt) {
172 			V4L1_LOG("Unknown v4l1 palette number: %d\n", v4l1_pal);
173 			errno = EINVAL;
174 			return -1;
175 		}
176 	} else {
177 		v4l2_pixfmt = devices[index].v4l2_pixfmt;
178 		v4l1_pal = devices[index].v4l1_pal;
179 	}
180 
181 	/* Do we need to change the resolution / format ? */
182 	if (width == devices[index].width && height == devices[index].height &&
183 			v4l2_pixfmt == devices[index].v4l2_pixfmt) {
184 		devices[index].v4l1_pal = v4l1_pal;
185 		return 0;
186 	}
187 
188 	/* Get current settings, apply our changes and try the new setting */
189 	result = v4l2_ioctl(devices[index].fd, VIDIOC_G_FMT, &fmt2);
190 	if (result) {
191 		int saved_err = errno;
192 
193 		V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno));
194 		errno = saved_err;
195 		return result;
196 	}
197 
198 	fmt2.fmt.pix.pixelformat = v4l2_pixfmt;
199 	fmt2.fmt.pix.width  = width;
200 	fmt2.fmt.pix.height = height;
201 	result = v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, &fmt2);
202 	if (result) {
203 		int saved_err = errno;
204 
205 		V4L1_LOG("error trying pixformat: %s\n", strerror(errno));
206 		errno = saved_err;
207 		return result;
208 	}
209 
210 	/* Check if we get what we asked for */
211 	if (fmt2.fmt.pix.pixelformat != v4l2_pixfmt || (!width_height_may_differ &&
212 				(fmt2.fmt.pix.width != width || fmt2.fmt.pix.height != height))) {
213 		V4L1_LOG("requested fmt, width, height combo not available\n");
214 		errno = EINVAL;
215 		return -1;
216 	}
217 
218 	/* Maybe after the TRY_FMT things haven't changed after all ? */
219 	if (fmt2.fmt.pix.width  == devices[index].width &&
220 			fmt2.fmt.pix.height == devices[index].height &&
221 			fmt2.fmt.pix.pixelformat == devices[index].v4l2_pixfmt) {
222 		devices[index].v4l1_pal = v4l1_pal;
223 		return 0;
224 	}
225 
226 	result = v4l2_ioctl(devices[index].fd, VIDIOC_S_FMT, &fmt2);
227 	if (result) {
228 		int saved_err = errno;
229 
230 		V4L1_LOG_ERR("setting pixformat: %s\n", strerror(errno));
231 		errno = saved_err;
232 		return result;
233 	}
234 
235 	devices[index].width  = fmt2.fmt.pix.width;
236 	devices[index].height = fmt2.fmt.pix.height;
237 	devices[index].v4l2_pixfmt = v4l2_pixfmt;
238 	devices[index].v4l1_pal = v4l1_pal;
239 	devices[index].depth = ((fmt2.fmt.pix.bytesperline << 3) +
240 			(fmt2.fmt.pix.width - 1)) / fmt2.fmt.pix.width;
241 
242 	return result;
243 }
244 
v4l1_find_min_and_max_size(int index,struct v4l2_format * fmt2)245 static void v4l1_find_min_and_max_size(int index, struct v4l2_format *fmt2)
246 {
247 	int i;
248 	struct v4l2_fmtdesc fmtdesc2 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
249 
250 	devices[index].min_width = -1;
251 	devices[index].min_height = -1;
252 	devices[index].max_width = 0;
253 	devices[index].max_height = 0;
254 
255 	for (i = 0; ; i++) {
256 		fmtdesc2.index = i;
257 
258 		if (v4l2_ioctl(devices[index].fd, VIDIOC_ENUM_FMT, &fmtdesc2))
259 			break;
260 
261 		fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat;
262 		fmt2->fmt.pix.width = 48;
263 		fmt2->fmt.pix.height = 32;
264 
265 		if (v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
266 			if (fmt2->fmt.pix.width < devices[index].min_width)
267 				devices[index].min_width = fmt2->fmt.pix.width;
268 			if (fmt2->fmt.pix.height < devices[index].min_height)
269 				devices[index].min_height = fmt2->fmt.pix.height;
270 		}
271 
272 		fmt2->fmt.pix.pixelformat = fmtdesc2.pixelformat;
273 		fmt2->fmt.pix.width = 100000;
274 		fmt2->fmt.pix.height = 100000;
275 
276 		if (v4l2_ioctl(devices[index].fd, VIDIOC_TRY_FMT, fmt2) == 0) {
277 			if (fmt2->fmt.pix.width > devices[index].max_width)
278 				devices[index].max_width = fmt2->fmt.pix.width;
279 			if (fmt2->fmt.pix.height > devices[index].max_height)
280 				devices[index].max_height = fmt2->fmt.pix.height;
281 		}
282 	}
283 }
284 
285 
v4l1_open(const char * file,int oflag,...)286 int v4l1_open(const char *file, int oflag, ...)
287 {
288 	int index, fd;
289 	char *lfname;
290 	struct v4l2_capability cap2;
291 	struct v4l2_format fmt2;
292 	struct v4l2_input input2;
293 	struct v4l2_standard standard2;
294 	int v4l_device = 0;
295 
296 	/* check if we're opening a video4linux2 device */
297 	if (!strncmp(file, "/dev/video", 10) || !strncmp(file, "/dev/v4l/", 9)) {
298 		/* Some apps open the device read only, but we need rw rights as the
299 		   buffers *MUST* be mapped rw */
300 		oflag = (oflag & ~O_ACCMODE) | O_RDWR;
301 		v4l_device = 1;
302 	}
303 
304 	/* original open code */
305 	if (oflag & O_CREAT) {
306 		va_list ap;
307 		mode_t mode;
308 
309 		va_start(ap, oflag);
310 		mode = va_arg(ap, PROMOTED_MODE_T);
311 
312 		fd = SYS_OPEN(file, oflag, mode);
313 
314 		va_end(ap);
315 	} else {
316 		fd = SYS_OPEN(file, oflag, 0);
317 	}
318 
319 	/* end of original open code */
320 
321 	if (fd == -1 || !v4l_device)
322 		return fd;
323 
324 	/* check that this is an v4l2 device, no need to emulate v4l1 on
325 	   a v4l1 device */
326 	if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap2))
327 		return fd;
328 
329 	/* If no log file was set by the app, see if one was specified through the
330 	   environment */
331 	if (!v4l1_log_file) {
332 		lfname = getenv("LIBV4L1_LOG_FILENAME");
333 		if (lfname)
334 			v4l1_log_file = fopen(lfname, "w");
335 	}
336 
337 	/* redirect libv4l2 log messages to our logfile if no libv4l2 logfile is
338 	   specified */
339 	if (!v4l2_log_file)
340 		v4l2_log_file = v4l1_log_file;
341 
342 	/* Register with libv4l2, as we use that todo format conversion and read()
343 	   emulation for us */
344 	if (v4l2_fd_open(fd, 0) == -1) {
345 		int saved_err = errno;
346 
347 		SYS_CLOSE(fd);
348 		errno = saved_err;
349 		return -1;
350 	}
351 
352 	/* Get initial width, height and pixelformat */
353 	fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
354 	if (v4l2_ioctl(fd, VIDIOC_G_FMT, &fmt2)) {
355 		int saved_err = errno;
356 
357 		SYS_CLOSE(fd);
358 		errno = saved_err;
359 		return -1;
360 	}
361 
362 	/* So we have a device on which we can (and want to) emulate v4l1, register
363 	   it in our devices array */
364 	pthread_mutex_lock(&v4l1_open_mutex);
365 	for (index = 0; index < V4L1_MAX_DEVICES; index++)
366 		if (devices[index].fd == -1) {
367 			devices[index].fd = fd;
368 			break;
369 		}
370 	pthread_mutex_unlock(&v4l1_open_mutex);
371 
372 	if (index == V4L1_MAX_DEVICES) {
373 		V4L1_LOG_ERR("attempting to open more than %d video devices\n",
374 				V4L1_MAX_DEVICES);
375 		v4l2_close(fd);
376 		errno = EBUSY;
377 		return -1;
378 	}
379 
380 	if (index >= devices_used)
381 		devices_used = index + 1;
382 
383 	devices[index].flags = 0;
384 	devices[index].open_count = 1;
385 	devices[index].v4l1_frame_buf_map_count = 0;
386 	devices[index].v4l1_frame_pointer = MAP_FAILED;
387 	devices[index].width  = fmt2.fmt.pix.width;
388 	devices[index].height = fmt2.fmt.pix.height;
389 	devices[index].v4l2_pixfmt = fmt2.fmt.pix.pixelformat;
390 	devices[index].v4l1_pal = pixelformat_to_palette(fmt2.fmt.pix.pixelformat);
391 	devices[index].depth = ((fmt2.fmt.pix.bytesperline << 3) +
392 			(fmt2.fmt.pix.width - 1)) / fmt2.fmt.pix.width;
393 
394 	v4l1_find_min_and_max_size(index, &fmt2);
395 
396 	/* Check ENUM_INPUT and ENUM_STD support */
397 	input2.index = 0;
398 	if (v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2) == 0)
399 		devices[index].flags |= V4L1_SUPPORTS_ENUMINPUT;
400 
401 	standard2.index = 0;
402 	if (v4l2_ioctl(fd, VIDIOC_ENUMSTD, &standard2) == 0)
403 		devices[index].flags |= V4L1_SUPPORTS_ENUMSTD;
404 
405 	V4L1_LOG("open: %d\n", fd);
406 
407 	return fd;
408 }
409 
410 /* Is this an fd for which we are emulating v4l1 ? */
v4l1_get_index(int fd)411 static int v4l1_get_index(int fd)
412 {
413 	int index;
414 
415 	/* We never handle fd -1 */
416 	if (fd == -1)
417 		return -1;
418 
419 	for (index = 0; index < devices_used; index++)
420 		if (devices[index].fd == fd)
421 			break;
422 
423 	if (index == devices_used)
424 		return -1;
425 
426 	return index;
427 }
428 
v4l1_close(int fd)429 int v4l1_close(int fd)
430 {
431 	int index, result;
432 
433 	index = v4l1_get_index(fd);
434 	if (index == -1)
435 		return SYS_CLOSE(fd);
436 
437 	/* Abuse stream_lock to stop 2 closes from racing and trying to free the
438 	   resources twice */
439 	pthread_mutex_lock(&devices[index].stream_lock);
440 	devices[index].open_count--;
441 	result = devices[index].open_count != 0;
442 	pthread_mutex_unlock(&devices[index].stream_lock);
443 
444 	if (result)
445 		return v4l2_close(fd);
446 
447 	/* Free resources */
448 	if (devices[index].v4l1_frame_pointer != MAP_FAILED) {
449 		if (devices[index].v4l1_frame_buf_map_count)
450 			V4L1_LOG("v4l1 capture buffer still mapped: %d times on close()\n",
451 					devices[index].v4l1_frame_buf_map_count);
452 		else
453 			SYS_MUNMAP(devices[index].v4l1_frame_pointer,
454 					V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE);
455 		devices[index].v4l1_frame_pointer = MAP_FAILED;
456 	}
457 
458 	/* Remove the fd from our list of managed fds before closing it, because as
459 	   soon as we've done the actual close the fd maybe returned by an open in
460 	   another thread and we don't want to intercept calls to this new fd. */
461 	devices[index].fd = -1;
462 
463 	result = v4l2_close(fd);
464 
465 	V4L1_LOG("close: %d\n", fd);
466 
467 	return result;
468 }
469 
v4l1_dup(int fd)470 int v4l1_dup(int fd)
471 {
472 	int index = v4l1_get_index(fd);
473 
474 	if (index == -1)
475 		return syscall(SYS_dup, fd);
476 
477 	devices[index].open_count++;
478 
479 	return v4l2_dup(fd);
480 }
481 
v4l1_ioctl(int fd,unsigned long int request,...)482 int v4l1_ioctl(int fd, unsigned long int request, ...)
483 {
484 	void *arg;
485 	va_list ap;
486 	int result, index, saved_err, stream_locked = 0;
487 
488 	va_start(ap, request);
489 	arg = va_arg(ap, void *);
490 	va_end(ap);
491 
492 	index = v4l1_get_index(fd);
493 	if (index == -1)
494 		return SYS_IOCTL(fd, request, arg);
495 
496 	/* Appearantly the kernel and / or glibc ignore the 32 most significant bits
497 	   when long = 64 bits, and some applications pass an int holding the req to
498 	   ioctl, causing it to get sign extended, depending upon this behavior */
499 	request = (unsigned int)request;
500 
501 	/* do we need to take the stream lock for this ioctl? */
502 	switch (request) {
503 	case VIDIOCSPICT:
504 	case VIDIOCGPICT:
505 	case VIDIOCSWIN:
506 	case VIDIOCGWIN:
507 	case VIDIOCGMBUF:
508 	case VIDIOCMCAPTURE:
509 	case VIDIOCSYNC:
510 	case VIDIOC_S_FMT:
511 		pthread_mutex_lock(&devices[index].stream_lock);
512 		stream_locked = 1;
513 	}
514 
515 	switch (request) {
516 	case VIDIOCGCAP: {
517 		struct video_capability *cap = arg;
518 		struct v4l2_framebuffer fbuf = { 0, };
519 		struct v4l2_capability cap2 = { { 0 }, };
520 
521 		result = v4l2_ioctl(fd, VIDIOC_QUERYCAP, &cap2);
522 		if (result < 0)
523 			break;
524 
525 		if (cap2.capabilities & V4L2_CAP_DEVICE_CAPS)
526 			cap2.capabilities = cap2.device_caps;
527 		if (cap2.capabilities & V4L2_CAP_VIDEO_OVERLAY) {
528 			result = v4l2_ioctl(fd, VIDIOC_G_FBUF, &fbuf);
529 			if (result < 0)
530 				memset(&fbuf, 0, sizeof(fbuf));
531 			result = 0;
532 		}
533 
534 		memcpy(cap->name, cap2.card,
535 		       min(sizeof(cap->name), sizeof(cap2.card)));
536 
537 		cap->name[sizeof(cap->name) - 1] = 0;
538 
539 		if (cap2.capabilities & V4L2_CAP_VIDEO_CAPTURE)
540 			cap->type |= VID_TYPE_CAPTURE;
541 		if (cap2.capabilities & V4L2_CAP_TUNER)
542 			cap->type |= VID_TYPE_TUNER;
543 		if (cap2.capabilities & V4L2_CAP_VBI_CAPTURE)
544 			cap->type |= VID_TYPE_TELETEXT;
545 		if (cap2.capabilities & V4L2_CAP_VIDEO_OVERLAY)
546 			cap->type |= VID_TYPE_OVERLAY;
547 		if (fbuf.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
548 			cap->type |= VID_TYPE_CLIPPING;
549 
550 		cap->channels  = count_inputs(fd);
551 		cap->minwidth  = devices[index].min_width;
552 		cap->minheight = devices[index].min_height;
553 		cap->maxwidth  = devices[index].max_width;
554 		cap->maxheight = devices[index].max_height;
555 		break;
556 	}
557 
558 	case VIDIOCSPICT: {
559 		struct video_picture *pic = arg;
560 
561 		devices[index].flags |= V4L1_PIX_FMT_TOUCHED;
562 
563 		v4l2_set_control(fd, V4L2_CID_BRIGHTNESS, pic->brightness);
564 		v4l2_set_control(fd, V4L2_CID_HUE, pic->hue);
565 		v4l2_set_control(fd, V4L2_CID_CONTRAST, pic->contrast);
566 		v4l2_set_control(fd, V4L2_CID_SATURATION, pic->colour);
567 		v4l2_set_control(fd, V4L2_CID_WHITENESS, pic->whiteness);
568 
569 		result = v4l1_set_format(index, devices[index].width,
570 				devices[index].height, pic->palette, 0);
571 		break;
572 	}
573 
574 	case VIDIOCGPICT: {
575 		struct video_picture *pic = arg;
576 		int i;
577 
578 		/* If our v4l2 pixformat has no corresponding v4l1 palette, and
579 		   the app has not touched the pixformat sofar, try setting a
580 		   palette which does (and which we emulate when necessary) so
581 		   that applications which just query the current format and
582 		   then take whatever they get will work */
583 		if (!(devices[index].flags & V4L1_PIX_FMT_TOUCHED) &&
584 		    !pixelformat_to_palette(devices[index].v4l2_pixfmt))
585 			v4l1_set_format(index, devices[index].width,
586 					devices[index].height,
587 					VIDEO_PALETTE_RGB24,
588 					(devices[index].flags &
589 					 V4L1_PIX_SIZE_TOUCHED) ? 0 : 1);
590 
591 		devices[index].flags |= V4L1_PIX_FMT_TOUCHED;
592 
593 		memset(pic, 0, sizeof(*pic));
594 		pic->depth = devices[index].depth;
595 		pic->palette = devices[index].v4l1_pal;
596 		i = v4l2_get_control(devices[index].fd, V4L2_CID_HUE);
597 		if (i >= 0)
598 			pic->hue = i;
599 		i = v4l2_get_control(devices[index].fd, V4L2_CID_SATURATION);
600 		if (i >= 0)
601 			pic->colour = i;
602 		i = v4l2_get_control(devices[index].fd, V4L2_CID_CONTRAST);
603 		if (i >= 0)
604 			pic->contrast = i;
605 		i = v4l2_get_control(devices[index].fd, V4L2_CID_WHITENESS);
606 		if (i >= 0)
607 			pic->whiteness = i;
608 		i = v4l2_get_control(devices[index].fd, V4L2_CID_BRIGHTNESS);
609 		if (i >= 0)
610 			pic->brightness = i;
611 
612 		result = 0;
613 		break;
614 	}
615 
616 	case VIDIOCSWIN:
617 	case VIDIOCGWIN: {
618 		struct video_window *win = arg;
619 
620 		devices[index].flags |= V4L1_PIX_SIZE_TOUCHED;
621 
622 		if (request == VIDIOCSWIN)
623 			result = v4l1_set_format(index, win->width, win->height, -1, 1);
624 		else
625 			result = 0;
626 
627 		if (result == 0) {
628 			win->x = 0;
629 			win->y = 0;
630 			win->width  = devices[index].width;
631 			win->height = devices[index].height;
632 			win->flags = 0;
633 		}
634 		break;
635 	}
636 
637 	case VIDIOCGCHAN: {
638 		struct video_channel *chan = arg;
639 
640 		/* Set some defaults */
641 		chan->tuners = 0;
642 		chan->flags = 0;
643 		chan->type = VIDEO_TYPE_CAMERA;
644 		chan->norm = 0;
645 
646 		if (devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) {
647 			struct v4l2_input input2 = { .index = chan->channel };
648 
649 			result = v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2);
650 			if (result < 0)
651 				break;
652 
653 			snprintf(chan->name, sizeof(chan->name), "%s",
654 				 (char *)input2.name);
655 			if (input2.type == V4L2_INPUT_TYPE_TUNER) {
656 				chan->tuners = 1;
657 				chan->type = VIDEO_TYPE_TV;
658 				chan->flags = VIDEO_VC_TUNER;
659 			}
660 		} else {
661 			/* No ENUMINPUT support, fake it. */
662 			if (chan->channel == 0) {
663 				snprintf(chan->name, sizeof(chan->name),
664 					 "Camera");
665 				result = 0;
666 			} else {
667 				errno  = EINVAL;
668 				result = -1;
669 				break;
670 			}
671 		}
672 
673 		/* In case of no ENUMSTD support, ignore the norm member of the
674 		   channel struct */
675 		if (devices[index].flags & V4L1_SUPPORTS_ENUMSTD) {
676 			v4l2_std_id sid;
677 
678 			result = v4l2_ioctl(fd, VIDIOC_G_STD, &sid);
679 			if (result < 0)
680 				break;
681 
682 			if (sid & V4L2_STD_PAL)
683 				chan->norm = VIDEO_MODE_PAL;
684 			if (sid & V4L2_STD_NTSC)
685 				chan->norm = VIDEO_MODE_NTSC;
686 			if (sid & V4L2_STD_SECAM)
687 				chan->norm = VIDEO_MODE_SECAM;
688 			if (sid == V4L2_STD_ALL)
689 				chan->norm = VIDEO_MODE_AUTO;
690 		}
691 		break;
692 	}
693 
694 	case VIDIOCSCHAN: {
695 		struct video_channel *chan = arg;
696 
697 		if (devices[index].flags & V4L1_SUPPORTS_ENUMINPUT) {
698 			result = v4l2_ioctl(fd, VIDIOC_S_INPUT, &chan->channel);
699 			if (result < 0)
700 				break;
701 		} else {
702 			/* No ENUMINPUT support, assume a single input */
703 			if (chan->channel != 0) {
704 				errno  = EINVAL;
705 				result = -1;
706 				break;
707 			}
708 			result = 0;
709 		}
710 
711 		/* In case of no ENUMSTD support, ignore the norm member of the
712 		   channel struct */
713 		if (devices[index].flags & V4L1_SUPPORTS_ENUMSTD) {
714 			v4l2_std_id sid = 0;
715 
716 			switch (chan->norm) {
717 			case VIDEO_MODE_PAL:
718 				sid = V4L2_STD_PAL;
719 				break;
720 			case VIDEO_MODE_NTSC:
721 				sid = V4L2_STD_NTSC;
722 				break;
723 			case VIDEO_MODE_SECAM:
724 				sid = V4L2_STD_SECAM;
725 				break;
726 			case VIDEO_MODE_AUTO:
727 				sid = V4L2_STD_ALL;
728 				break;
729 			}
730 
731 			if (sid)
732 				result = v4l2_ioctl(fd, VIDIOC_S_STD, &sid);
733 		}
734 		break;
735 	}
736 
737 	case VIDIOCGMBUF: {
738 		/* When VIDIOCGMBUF is done, we don't necessarrily know the format the
739 		   application wants yet (with some apps this is passed for the first
740 		   time through VIDIOCMCAPTURE), so we just create an anonymous mapping
741 		   that should be large enough to hold any sort of frame. Note this only
742 		   takes virtual memory, and does not use memory until actually used. */
743 		int i;
744 		struct video_mbuf *mbuf = arg;
745 
746 		mbuf->size = V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE;
747 		mbuf->frames = V4L1_NO_FRAMES;
748 		for (i = 0; i < mbuf->frames; i++)
749 			mbuf->offsets[i] = i * V4L1_FRAME_BUF_SIZE;
750 
751 		if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
752 			devices[index].v4l1_frame_pointer = (void *)SYS_MMAP(NULL,
753 					(size_t)mbuf->size,
754 					PROT_READ | PROT_WRITE,
755 					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
756 			if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
757 				saved_err = errno;
758 				V4L1_LOG_ERR("allocating v4l1 buffer: %s\n", strerror(errno));
759 				errno = saved_err;
760 				result = -1;
761 				break;
762 			}
763 			V4L1_LOG("allocated v4l1 buffer @ %p\n",
764 					devices[index].v4l1_frame_pointer);
765 		}
766 		result = 0;
767 		break;
768 	}
769 
770 	case VIDIOCMCAPTURE: {
771 		struct video_mmap *map = arg;
772 
773 		devices[index].flags |= V4L1_PIX_FMT_TOUCHED |
774 			V4L1_PIX_SIZE_TOUCHED;
775 
776 		result = v4l1_set_format(index, map->width, map->height,
777 				map->format, 0);
778 		break;
779 	}
780 
781 	case VIDIOCSYNC: {
782 		int *frame_index = arg;
783 
784 		if (devices[index].v4l1_frame_pointer == MAP_FAILED ||
785 				*frame_index < 0 || *frame_index >= V4L1_NO_FRAMES) {
786 			errno = EINVAL;
787 			result = -1;
788 			break;
789 		}
790 
791 		result = v4l2_read(devices[index].fd,
792 				devices[index].v4l1_frame_pointer +
793 				*frame_index * V4L1_FRAME_BUF_SIZE,
794 				V4L1_FRAME_BUF_SIZE);
795 		result = (result > 0) ? 0 : result;
796 		break;
797 	}
798 
799 		/* We are passing through v4l2 calls to libv4l2 for applications which are
800 		   using v4l2 through libv4l1 (possible with the v4l1compat.so wrapper).
801 
802 		   So the application could be calling VIDIOC_S_FMT, in this case update
803 		   our own bookkeeping of the cam's format. Note that this really only is
804 		   relevant if an application is mixing and matching v4l1 and v4l2 calls,
805 		   which is crazy, but better safe than sorry. */
806 	case VIDIOC_S_FMT: {
807 		struct v4l2_format *fmt2 = arg;
808 
809 		result = v4l2_ioctl(fd, request, arg);
810 
811 		if (result == 0 && fmt2->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
812 			if (devices[index].v4l2_pixfmt != fmt2->fmt.pix.pixelformat) {
813 				devices[index].v4l2_pixfmt = fmt2->fmt.pix.pixelformat;
814 				devices[index].v4l1_pal =
815 					pixelformat_to_palette(fmt2->fmt.pix.pixelformat);
816 			}
817 			devices[index].width  = fmt2->fmt.pix.width;
818 			devices[index].height = fmt2->fmt.pix.height;
819 		}
820 		break;
821 	}
822 
823 	case VIDIOCGFBUF: {
824 		struct video_buffer *buffer = arg;
825 		struct v4l2_framebuffer fbuf = { 0, };
826 
827 		result = v4l2_ioctl(fd, VIDIOC_G_FBUF, &fbuf);
828 		if (result < 0)
829 			break;
830 
831 		buffer->base = fbuf.base;
832 		buffer->height = fbuf.fmt.height;
833 		buffer->width = fbuf.fmt.width;
834 
835 		switch (fbuf.fmt.pixelformat) {
836 		case V4L2_PIX_FMT_RGB332:
837 			buffer->depth = 8;
838 			break;
839 		case V4L2_PIX_FMT_RGB555:
840 			buffer->depth = 15;
841 			break;
842 		case V4L2_PIX_FMT_RGB565:
843 			buffer->depth = 16;
844 			break;
845 		case V4L2_PIX_FMT_BGR24:
846 			buffer->depth = 24;
847 			break;
848 		case V4L2_PIX_FMT_BGR32:
849 			buffer->depth = 32;
850 			break;
851 		default:
852 			buffer->depth = 0;
853 		}
854 
855 		if (fbuf.fmt.bytesperline) {
856 			buffer->bytesperline = fbuf.fmt.bytesperline;
857 			if (!buffer->depth && buffer->width)
858 				buffer->depth = ((fbuf.fmt.bytesperline << 3)
859 						+ (buffer->width - 1))
860 						/ buffer->width;
861 		} else {
862 			buffer->bytesperline =
863 				(buffer->width * buffer->depth + 7) & 7;
864 			buffer->bytesperline >>= 3;
865 		}
866 		break;
867 	}
868 
869 	case VIDIOCSFBUF: {
870 		struct video_buffer *buffer = arg;
871 		struct v4l2_framebuffer fbuf = { 0, };
872 
873 		fbuf.base = buffer->base;
874 		fbuf.fmt.height = buffer->height;
875 		fbuf.fmt.width = buffer->width;
876 
877 		switch (buffer->depth) {
878 		case 8:
879 			fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB332;
880 			break;
881 		case 15:
882 			fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB555;
883 			break;
884 		case 16:
885 			fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
886 			break;
887 		case 24:
888 			fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR24;
889 			break;
890 		case 32:
891 			fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR32;
892 			break;
893 		}
894 
895 		fbuf.fmt.bytesperline = buffer->bytesperline;
896 		result = v4l2_ioctl(fd, VIDIOC_S_FBUF, &fbuf);
897 		break;
898 	}
899 
900 	case VIDIOCSTUNER: {
901 		struct video_tuner *tun = arg;
902 		struct v4l2_tuner t = { 0, };
903 
904 		t.index = tun->tuner;
905 		result = v4l2_ioctl(fd, VIDIOC_S_TUNER, &t);
906 
907 		break;
908 	}
909 
910 	case VIDIOCGTUNER: {
911 		int i;
912 		struct video_tuner *tun = arg;
913 		struct v4l2_tuner tun2 = { 0, };
914 		struct v4l2_standard std2 = { 0, };
915 		v4l2_std_id sid;
916 
917 		result = v4l2_ioctl(fd, VIDIOC_G_TUNER, &tun2);
918 		if (result < 0)
919 			break;
920 
921 		memcpy(tun->name, tun2.name,
922 			min(sizeof(tun->name), sizeof(tun2.name)));
923 		tun->name[sizeof(tun->name) - 1] = 0;
924 		tun->rangelow = tun2.rangelow;
925 		tun->rangehigh = tun2.rangehigh;
926 		tun->flags = 0;
927 		tun->mode = VIDEO_MODE_AUTO;
928 
929 		for (i = 0; i < 64; i++) {
930 			std2.index = i;
931 			if (0 != v4l2_ioctl(fd, VIDIOC_ENUMSTD, &std2))
932 				break;
933 			if (std2.id & V4L2_STD_PAL)
934 				tun->flags |= VIDEO_TUNER_PAL;
935 			if (std2.id & V4L2_STD_NTSC)
936 				tun->flags |= VIDEO_TUNER_NTSC;
937 			if (std2.id & V4L2_STD_SECAM)
938 				tun->flags |= VIDEO_TUNER_SECAM;
939 		}
940 
941 		if (v4l2_ioctl(fd, VIDIOC_G_STD, &sid) == 0) {
942 			if (sid & V4L2_STD_PAL)
943 				tun->mode = VIDEO_MODE_PAL;
944 			if (sid & V4L2_STD_NTSC)
945 				tun->mode = VIDEO_MODE_NTSC;
946 			if (sid & V4L2_STD_SECAM)
947 				tun->mode = VIDEO_MODE_SECAM;
948 		}
949 		if (tun2.capability & V4L2_TUNER_CAP_LOW)
950 			tun->flags |= VIDEO_TUNER_LOW;
951 		if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
952 			tun->flags |= VIDEO_TUNER_STEREO_ON;
953 		tun->signal = tun2.signal;
954 
955 		break;
956 	}
957 
958 	case VIDIOCSFREQ: {
959 		unsigned long *freq = arg;
960 		struct v4l2_frequency freq2 = { 0, };
961 
962 		result = v4l2_ioctl(fd, VIDIOC_G_FREQUENCY, &freq2);
963 		if (result < 0)
964 			break;
965 
966 		freq2.frequency = *freq;
967 
968 		result = v4l2_ioctl(fd, VIDIOC_S_FREQUENCY, &freq2);
969 
970 		break;
971 	}
972 
973 	case VIDIOCGFREQ: {
974 		unsigned long *freq = arg;
975 		struct v4l2_frequency freq2 = { 0, };
976 
977 		freq2.tuner = 0;
978 		result = v4l2_ioctl(fd, VIDIOC_G_FREQUENCY, &freq2);
979 		if (result < 0)
980 			break;
981 		if (0 == result)
982 			*freq = freq2.frequency;
983 
984 		break;
985 	}
986 
987 	case VIDIOCCAPTURE: {
988 		int *on = arg;
989 		enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
990 
991 		if (0 == *on) {
992 		/* dirty hack time.  But v4l1 has no STREAMOFF
993 		* equivalent in the API, and this one at
994 		* least comes close ... */
995 			v4l2_ioctl(fd, VIDIOC_STREAMOFF, &captype);
996 		}
997 
998 		result = v4l2_ioctl(fd, VIDIOC_OVERLAY, on);
999 
1000 		break;
1001 	}
1002 
1003 	case VIDIOCSAUDIO: {
1004 		struct video_audio *aud = arg;
1005 		struct v4l2_audio aud2 = { 0, };
1006 		struct v4l2_tuner tun2 = { 0, };
1007 
1008 		aud2.index = aud->audio;
1009 		result = v4l2_ioctl(fd, VIDIOC_S_AUDIO, &aud2);
1010 		if (result < 0)
1011 			break;
1012 
1013 		v4l2_set_control(fd, V4L2_CID_AUDIO_VOLUME,
1014 			aud->volume);
1015 		v4l2_set_control(fd, V4L2_CID_AUDIO_BASS,
1016 			aud->bass);
1017 		v4l2_set_control(fd, V4L2_CID_AUDIO_TREBLE,
1018 			aud->treble);
1019 		v4l2_set_control(fd, V4L2_CID_AUDIO_BALANCE,
1020 			aud->balance);
1021 		v4l2_set_control(fd, V4L2_CID_AUDIO_MUTE,
1022 			!!(aud->flags & VIDEO_AUDIO_MUTE));
1023 
1024 		result = v4l2_ioctl(fd, VIDIOC_G_TUNER, &tun2);
1025 		if (result == 0) {
1026 			switch (aud->mode) {
1027 			default:
1028 			case VIDEO_SOUND_MONO:
1029 			case VIDEO_SOUND_LANG1:
1030 				tun2.audmode = V4L2_TUNER_MODE_MONO;
1031 				break;
1032 			case VIDEO_SOUND_STEREO:
1033 				tun2.audmode = V4L2_TUNER_MODE_STEREO;
1034 				break;
1035 			case VIDEO_SOUND_LANG2:
1036 				tun2.audmode = V4L2_TUNER_MODE_LANG2;
1037 				break;
1038 			}
1039 			result = v4l2_ioctl(fd, VIDIOC_S_TUNER, &tun2);
1040 		}
1041 		/* Ignore errors modifying the tuner settings. */
1042 		result = 0;
1043 		break;
1044 	}
1045 
1046 	case VIDIOCGAUDIO: {
1047 		int i;
1048 		struct video_audio *aud = arg;
1049 		struct v4l2_queryctrl qctrl2;
1050 		struct v4l2_audio aud2 = { 0, };
1051 		struct v4l2_tuner tun2;
1052 
1053 		result = v4l2_ioctl(fd, VIDIOC_G_AUDIO, &aud2);
1054 		if (result < 0)
1055 			break;
1056 
1057 		memcpy(aud->name, aud2.name,
1058 			min(sizeof(aud->name), sizeof(aud2.name)));
1059 		aud->name[sizeof(aud->name) - 1] = 0;
1060 		aud->audio = aud2.index;
1061 		aud->flags = 0;
1062 		i = v4l2_get_control(fd, V4L2_CID_AUDIO_VOLUME);
1063 		if (i >= 0) {
1064 			aud->volume = i;
1065 			aud->flags |= VIDEO_AUDIO_VOLUME;
1066 		}
1067 		i = v4l2_get_control(fd, V4L2_CID_AUDIO_BASS);
1068 		if (i >= 0) {
1069 			aud->bass = i;
1070 			aud->flags |= VIDEO_AUDIO_BASS;
1071 		}
1072 		i = v4l2_get_control(fd, V4L2_CID_AUDIO_TREBLE);
1073 		if (i >= 0) {
1074 			aud->treble = i;
1075 			aud->flags |= VIDEO_AUDIO_TREBLE;
1076 		}
1077 		i = v4l2_get_control(fd, V4L2_CID_AUDIO_BALANCE);
1078 		if (i >= 0) {
1079 			aud->balance = i;
1080 			aud->flags |= VIDEO_AUDIO_BALANCE;
1081 		}
1082 		i = v4l2_get_control(fd, V4L2_CID_AUDIO_MUTE);
1083 		if (i >= 0) {
1084 			if (i)
1085 				aud->flags |= VIDEO_AUDIO_MUTE;
1086 
1087 			aud->flags |= VIDEO_AUDIO_MUTABLE;
1088 		}
1089 		aud->step = 1;
1090 		qctrl2.id = V4L2_CID_AUDIO_VOLUME;
1091 		if (v4l2_ioctl(fd, VIDIOC_QUERYCTRL, &qctrl2) == 0 &&
1092 			!(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
1093 			aud->step = qctrl2.step;
1094 		aud->mode = 0;
1095 
1096 		result = v4l2_ioctl(fd, VIDIOC_G_TUNER, &tun2);
1097 		if (result < 0) {
1098 			result = 0;
1099 			break;
1100 		}
1101 
1102 		if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2)
1103 			aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
1104 		else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
1105 			aud->mode = VIDEO_SOUND_STEREO;
1106 		else if (tun2.rxsubchans & V4L2_TUNER_SUB_MONO)
1107 			aud->mode = VIDEO_SOUND_MONO;
1108 
1109 		break;
1110 	}
1111 
1112 	case VIDIOCSVBIFMT: {
1113 		struct vbi_format *fmt = arg;
1114 		struct v4l2_format fmt2;
1115 
1116 		if (VIDEO_PALETTE_RAW != fmt->sample_format) {
1117 			result = -EINVAL;
1118 			break;
1119 		}
1120 
1121 		fmt2.type = V4L2_BUF_TYPE_VBI_CAPTURE;
1122 		fmt2.fmt.vbi.samples_per_line = fmt->samples_per_line;
1123 		fmt2.fmt.vbi.sampling_rate    = fmt->sampling_rate;
1124 		fmt2.fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
1125 		fmt2.fmt.vbi.start[0]         = fmt->start[0];
1126 		fmt2.fmt.vbi.count[0]         = fmt->count[0];
1127 		fmt2.fmt.vbi.start[1]         = fmt->start[1];
1128 		fmt2.fmt.vbi.count[1]         = fmt->count[1];
1129 		fmt2.fmt.vbi.flags            = fmt->flags;
1130 
1131 		result  = v4l2_ioctl(fd, VIDIOC_TRY_FMT, fmt2);
1132 		if (result < 0)
1133 			break;
1134 
1135 		if (fmt2.fmt.vbi.samples_per_line != fmt->samples_per_line ||
1136 		    fmt2.fmt.vbi.sampling_rate    != fmt->sampling_rate    ||
1137 		    fmt2.fmt.vbi.sample_format    != V4L2_PIX_FMT_GREY     ||
1138 		    fmt2.fmt.vbi.start[0]         != fmt->start[0]         ||
1139 		    fmt2.fmt.vbi.count[0]         != fmt->count[0]         ||
1140 		    fmt2.fmt.vbi.start[1]         != fmt->start[1]         ||
1141 		    fmt2.fmt.vbi.count[1]         != fmt->count[1]         ||
1142 		    fmt2.fmt.vbi.flags            != fmt->flags) {
1143 			result = -EINVAL;
1144 			break;
1145 		}
1146 		result = v4l2_ioctl(fd, VIDIOC_S_FMT, fmt2);
1147 		break;
1148 	}
1149 
1150 	case VIDIOCGVBIFMT: {
1151 		struct vbi_format *fmt = arg;
1152 		struct v4l2_format fmt2 = { 0, };
1153 
1154 		fmt2.type = V4L2_BUF_TYPE_VBI_CAPTURE;
1155 		result = v4l2_ioctl(fd, VIDIOC_G_FMT, &fmt2);
1156 
1157 		if (result < 0)
1158 			break;
1159 
1160 		if (fmt2.fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
1161 			result = -EINVAL;
1162 			break;
1163 		}
1164 
1165 		fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
1166 		fmt->sampling_rate    = fmt2.fmt.vbi.sampling_rate;
1167 		fmt->sample_format    = VIDEO_PALETTE_RAW;
1168 		fmt->start[0]         = fmt2.fmt.vbi.start[0];
1169 		fmt->count[0]         = fmt2.fmt.vbi.count[0];
1170 		fmt->start[1]         = fmt2.fmt.vbi.start[1];
1171 		fmt->count[1]         = fmt2.fmt.vbi.count[1];
1172 		fmt->flags            = fmt2.fmt.vbi.flags & 0x03;
1173 
1174 		break;
1175 	}
1176 
1177 	default:
1178 		/* Pass through libv4l2 for applications which are using v4l2 through
1179 		   libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
1180 		result = v4l2_ioctl(fd, request, arg);
1181 		break;
1182 	}
1183 
1184 	if (stream_locked)
1185 		pthread_mutex_unlock(&devices[index].stream_lock);
1186 
1187 	saved_err = errno;
1188 	v4l1_log_ioctl(request, arg, result);
1189 	errno = saved_err;
1190 
1191 	return result;
1192 }
1193 
1194 
v4l1_read(int fd,void * buffer,size_t n)1195 ssize_t v4l1_read(int fd, void *buffer, size_t n)
1196 {
1197 	int index = v4l1_get_index(fd);
1198 	ssize_t result;
1199 
1200 	if (index == -1)
1201 		return SYS_READ(fd, buffer, n);
1202 
1203 	pthread_mutex_lock(&devices[index].stream_lock);
1204 	result = v4l2_read(fd, buffer, n);
1205 	pthread_mutex_unlock(&devices[index].stream_lock);
1206 
1207 	return result;
1208 }
1209 
1210 
v4l1_mmap(void * start,size_t length,int prot,int flags,int fd,int64_t offset)1211 void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd,
1212 		int64_t offset)
1213 {
1214 	int index;
1215 	void *result;
1216 
1217 	/* Check if the mmap data matches our answer to VIDIOCGMBUF, if not
1218 	   pass through libv4l2 for applications which are using v4l2 through
1219 	   libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
1220 	index = v4l1_get_index(fd);
1221 	if (index == -1 || start || offset ||
1222 			length != (V4L1_NO_FRAMES * V4L1_FRAME_BUF_SIZE))
1223 		return v4l2_mmap(start, length, prot, flags, fd, offset);
1224 
1225 
1226 	pthread_mutex_lock(&devices[index].stream_lock);
1227 
1228 	/* It could be that we get called with an mmap which seems to match what
1229 	   we expect, but no VIDIOCGMBUF has been done yet, then it is certainly not
1230 	   for us so pass it through */
1231 	if (devices[index].v4l1_frame_pointer == MAP_FAILED) {
1232 		result = v4l2_mmap(start, length, prot, flags, fd, offset);
1233 		goto leave;
1234 	}
1235 
1236 	devices[index].v4l1_frame_buf_map_count++;
1237 
1238 	V4L1_LOG("v4l1 buffer @ %p mapped by application\n",
1239 			devices[index].v4l1_frame_pointer);
1240 
1241 	result = devices[index].v4l1_frame_pointer;
1242 
1243 leave:
1244 	pthread_mutex_unlock(&devices[index].stream_lock);
1245 
1246 	return result;
1247 }
1248 
v4l1_munmap(void * _start,size_t length)1249 int v4l1_munmap(void *_start, size_t length)
1250 {
1251 	int index;
1252 	unsigned char *start = _start;
1253 
1254 	/* Is this memory ours? */
1255 	if (start != MAP_FAILED &&
1256 			length == (V4L1_FRAME_BUF_SIZE * V4L1_NO_FRAMES)) {
1257 		for (index = 0; index < devices_used; index++)
1258 			if (devices[index].fd != -1 &&
1259 					start == devices[index].v4l1_frame_pointer)
1260 				break;
1261 
1262 		if (index != devices_used) {
1263 			int unmapped = 0;
1264 
1265 			pthread_mutex_lock(&devices[index].stream_lock);
1266 
1267 			/* Redo our checks now that we have the lock, things may have changed */
1268 			if (start == devices[index].v4l1_frame_pointer) {
1269 				if (devices[index].v4l1_frame_buf_map_count > 0)
1270 					devices[index].v4l1_frame_buf_map_count--;
1271 
1272 				unmapped = 1;
1273 			}
1274 
1275 			pthread_mutex_unlock(&devices[index].stream_lock);
1276 
1277 			if (unmapped) {
1278 				V4L1_LOG("v4l1 buffer munmap %p, %d\n", start, (int)length);
1279 				return 0;
1280 			}
1281 		}
1282 	}
1283 
1284 	V4L1_LOG("v4l1 unknown munmap %p, %d\n", start, (int)length);
1285 
1286 	/* If not pass through libv4l2 for applications which are using v4l2 through
1287 	   libv4l1 (this can happen with the v4l1compat.so wrapper preloaded */
1288 	return v4l2_munmap(start, length);
1289 }
1290