• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014 Philippe De Muyter <phdm@macqel.be>
3  * Copyright (c) 2014 William Manley <will@williammanley.net>
4  * Copyright (c) 2011 Peter Zotov <whitequark@whitequark.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "defs.h"
31 
32 #include DEF_MPERS_TYPE(struct_v4l2_buffer)
33 #include DEF_MPERS_TYPE(struct_v4l2_create_buffers)
34 #include DEF_MPERS_TYPE(struct_v4l2_ext_control)
35 #include DEF_MPERS_TYPE(struct_v4l2_ext_controls)
36 #include DEF_MPERS_TYPE(struct_v4l2_format)
37 #include DEF_MPERS_TYPE(struct_v4l2_framebuffer)
38 #include DEF_MPERS_TYPE(struct_v4l2_input)
39 #include DEF_MPERS_TYPE(struct_v4l2_standard)
40 
41 #include <stdint.h>
42 #include <linux/ioctl.h>
43 #include <linux/types.h>
44 #include <linux/videodev2.h>
45 
46 typedef struct v4l2_buffer struct_v4l2_buffer;
47 typedef struct v4l2_create_buffers struct_v4l2_create_buffers;
48 typedef struct v4l2_ext_control struct_v4l2_ext_control;
49 typedef struct v4l2_ext_controls struct_v4l2_ext_controls;
50 typedef struct v4l2_format struct_v4l2_format;
51 typedef struct v4l2_framebuffer struct_v4l2_framebuffer;
52 typedef struct v4l2_input struct_v4l2_input;
53 typedef struct v4l2_standard struct_v4l2_standard;
54 
55 #include MPERS_DEFS
56 
57 /* some historical constants */
58 #ifndef V4L2_CID_HCENTER
59 #define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
60 #endif
61 #ifndef V4L2_CID_VCENTER
62 #define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
63 #endif
64 #ifndef V4L2_CID_BAND_STOP_FILTER
65 #define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33)
66 #endif
67 
68 #define FMT_FRACT "%u/%u"
69 #define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
70 
71 #define FMT_RECT "{left=%d, top=%d, width=%u, height=%u}"
72 #define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
73 
74 static void
print_pixelformat(uint32_t fourcc)75 print_pixelformat(uint32_t fourcc)
76 {
77 	const union {
78 		uint32_t pixelformat;
79 		unsigned char cc[sizeof(uint32_t)];
80 	} u = {
81 #if WORDS_BIGENDIAN
82 		.cc = {
83 			(unsigned char) (fourcc >> 24),
84 			(unsigned char) (fourcc >> 16),
85 			(unsigned char) (fourcc >> 8),
86 			(unsigned char) fourcc
87 		}
88 #else
89 		.pixelformat = fourcc
90 #endif
91 	};
92 	unsigned int i;
93 
94 	tprints("v4l2_fourcc(");
95 	for (i = 0; i < sizeof(u.cc); ++i) {
96 		unsigned char c = u.cc[i];
97 
98 		if (i)
99 			tprints(", ");
100 		if (c == '\'' || c == '\\') {
101 			char sym[] = {
102 				'\'',
103 				'\\',
104 				c,
105 				'\'',
106 				'\0'
107 			};
108 			tprints(sym);
109 		} else if (c >= ' ' && c <= 0x7e) {
110 			char sym[] = {
111 				'\'',
112 				c,
113 				'\'',
114 				'\0'
115 			};
116 			tprints(sym);
117 		} else {
118 			char hex[] = {
119 				'\'',
120 				'\\',
121 				'x',
122 				"0123456789abcdef"[c >> 4],
123 				"0123456789abcdef"[c & 0xf],
124 				'\'',
125 				'\0'
126 			};
127 			tprints(hex);
128 		}
129 	}
130 	tprints(")");
131 }
132 
133 #include "xlat/v4l2_device_capabilities_flags.h"
134 
135 static int
print_v4l2_capability(struct tcb * const tcp,const kernel_ulong_t arg)136 print_v4l2_capability(struct tcb *const tcp, const kernel_ulong_t arg)
137 {
138 	struct v4l2_capability caps;
139 
140 	if (entering(tcp))
141 		return 0;
142 	tprints(", ");
143 	if (umove_or_printaddr(tcp, arg, &caps))
144 		return 1;
145 	tprints("{driver=");
146 	print_quoted_string((const char *) caps.driver,
147 			    sizeof(caps.driver), QUOTE_0_TERMINATED);
148 	tprints(", card=");
149 	print_quoted_string((const char *) caps.card,
150 			    sizeof(caps.card), QUOTE_0_TERMINATED);
151 	tprints(", bus_info=");
152 	print_quoted_string((const char *) caps.bus_info,
153 			    sizeof(caps.bus_info), QUOTE_0_TERMINATED);
154 	tprintf(", version=%u.%u.%u, capabilities=",
155 		(caps.version >> 16) & 0xFF,
156 		(caps.version >> 8) & 0xFF,
157 		caps.version & 0xFF);
158 	printflags(v4l2_device_capabilities_flags, caps.capabilities,
159 		   "V4L2_CAP_???");
160 #ifdef V4L2_CAP_DEVICE_CAPS
161 	tprints(", device_caps=");
162 	printflags(v4l2_device_capabilities_flags, caps.device_caps,
163 		   "V4L2_CAP_???");
164 #endif
165 	tprints("}");
166 	return 1;
167 }
168 
169 #include "xlat/v4l2_buf_types.h"
170 #include "xlat/v4l2_format_description_flags.h"
171 
172 static int
print_v4l2_fmtdesc(struct tcb * const tcp,const kernel_ulong_t arg)173 print_v4l2_fmtdesc(struct tcb *const tcp, const kernel_ulong_t arg)
174 {
175 	struct v4l2_fmtdesc f;
176 
177 	if (entering(tcp)) {
178 		tprints(", ");
179 		if (umove_or_printaddr(tcp, arg, &f))
180 			return RVAL_DECODED | 1;
181 		tprintf("{index=%u, type=", f.index);
182 		printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
183 		return 0;
184 	}
185 
186 	if (!syserror(tcp) && !umove(tcp, arg, &f)) {
187 		tprints(", flags=");
188 		printflags(v4l2_format_description_flags, f.flags,
189 			   "V4L2_FMT_FLAG_???");
190 		tprints(", description=");
191 		print_quoted_string((const char *) f.description,
192 				    sizeof(f.description),
193 				    QUOTE_0_TERMINATED);
194 		tprints(", pixelformat=");
195 		print_pixelformat(f.pixelformat);
196 	}
197 	tprints("}");
198 	return 1;
199 }
200 
201 #include "xlat/v4l2_fields.h"
202 #include "xlat/v4l2_colorspaces.h"
203 
204 static void
print_v4l2_format_fmt(const char * prefix,const struct_v4l2_format * f)205 print_v4l2_format_fmt(const char *prefix, const struct_v4l2_format *f)
206 {
207 	switch (f->type) {
208 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
209 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
210 		tprints(prefix);
211 		tprintf("fmt.pix={width=%u, height=%u, pixelformat=",
212 			f->fmt.pix.width, f->fmt.pix.height);
213 		print_pixelformat(f->fmt.pix.pixelformat);
214 		tprints(", field=");
215 		printxval(v4l2_fields, f->fmt.pix.field, "V4L2_FIELD_???");
216 		tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
217 			f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
218 		printxval(v4l2_colorspaces, f->fmt.pix.colorspace,
219 			  "V4L2_COLORSPACE_???");
220 		tprints("}");
221 		break;
222 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
223 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
224 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
225 		unsigned int i, max;
226 
227 		tprints(prefix);
228 		tprintf("fmt.pix_mp={width=%u, height=%u, pixelformat=",
229 			f->fmt.pix_mp.width, f->fmt.pix_mp.height);
230 		print_pixelformat(f->fmt.pix_mp.pixelformat);
231 		tprints(", field=");
232 		printxval(v4l2_fields, f->fmt.pix_mp.field, "V4L2_FIELD_???");
233 		tprints(", colorspace=");
234 		printxval(v4l2_colorspaces, f->fmt.pix_mp.colorspace,
235 			  "V4L2_COLORSPACE_???");
236 		tprints(", plane_fmt=[");
237 		max = f->fmt.pix_mp.num_planes;
238 		if (max > VIDEO_MAX_PLANES)
239 			max = VIDEO_MAX_PLANES;
240 		for (i = 0; i < max; i++) {
241 			if (i > 0)
242 				tprints(", ");
243 			tprintf("{sizeimage=%u, bytesperline=%u}",
244 				f->fmt.pix_mp.plane_fmt[i].sizeimage,
245 				f->fmt.pix_mp.plane_fmt[i].bytesperline);
246 		}
247 		tprintf("], num_planes=%u}", (unsigned) f->fmt.pix_mp.num_planes);
248 		break;
249 	}
250 #endif
251 
252 	/* TODO: Complete this switch statement */
253 #if 0
254 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
255 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
256 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
257 #endif
258 		tprints(prefix);
259 		tprints("fmt.win={???}");
260 		break;
261 
262 	case V4L2_BUF_TYPE_VBI_CAPTURE:
263 	case V4L2_BUF_TYPE_VBI_OUTPUT:
264 		tprints(prefix);
265 		tprints("fmt.vbi={???}");
266 		break;
267 
268 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
269 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
270 		tprints(prefix);
271 		tprints("fmt.sliced={???}");
272 		break;
273 
274 #if HAVE_DECL_V4L2_BUF_TYPE_SDR_CAPTURE
275 	case V4L2_BUF_TYPE_SDR_CAPTURE:
276 	case V4L2_BUF_TYPE_SDR_OUTPUT:
277 		tprints(prefix);
278 		tprints("fmt.sdr={???}");
279 		break;
280 #endif
281 #endif
282 	}
283 }
284 
285 static int
print_v4l2_format(struct tcb * const tcp,const kernel_ulong_t arg,const bool is_get)286 print_v4l2_format(struct tcb *const tcp, const kernel_ulong_t arg,
287 		  const bool is_get)
288 {
289 	struct_v4l2_format f;
290 
291 	if (entering(tcp)) {
292 		tprints(", ");
293 		if (umove_or_printaddr(tcp, arg, &f))
294 			return RVAL_DECODED | 1;
295 		tprints("{type=");
296 		printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
297 		if (is_get)
298 			return 0;
299 		print_v4l2_format_fmt(", ", &f);
300 	} else {
301 		if (!syserror(tcp) && !umove(tcp, arg, &f)) {
302 			const char *delim = is_get ? ", " : " => ";
303 			print_v4l2_format_fmt(delim, &f);
304 		}
305 		tprints("}");
306 	}
307 	return 1;
308 }
309 
310 #include "xlat/v4l2_memories.h"
311 
312 static int
print_v4l2_requestbuffers(struct tcb * const tcp,const kernel_ulong_t arg)313 print_v4l2_requestbuffers(struct tcb *const tcp, const kernel_ulong_t arg)
314 {
315 	struct v4l2_requestbuffers reqbufs;
316 
317 	if (entering(tcp)) {
318 		tprints(", ");
319 		if (umove_or_printaddr(tcp, arg, &reqbufs))
320 			return RVAL_DECODED | 1;
321 		tprintf("{count=%u, type=", reqbufs.count);
322 		printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
323 		tprints(", memory=");
324 		printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
325 		tprints("}");
326 		return 0;
327 	} else {
328 		static char outstr[sizeof("{count=}") + sizeof(int) * 3];
329 
330 		if (syserror(tcp) || umove(tcp, arg, &reqbufs) < 0)
331 			return 1;
332 		sprintf(outstr, "{count=%u}", reqbufs.count);
333 		tcp->auxstr = outstr;
334 		return 1 + RVAL_STR;
335 	}
336 }
337 
338 #include "xlat/v4l2_buf_flags.h"
339 
340 static int
print_v4l2_buffer(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)341 print_v4l2_buffer(struct tcb *const tcp, const unsigned int code,
342 		  const kernel_ulong_t arg)
343 {
344 	struct_v4l2_buffer b;
345 
346 	if (entering(tcp)) {
347 		tprints(", ");
348 		if (umove_or_printaddr(tcp, arg, &b))
349 			return RVAL_DECODED | 1;
350 		tprints("{type=");
351 		printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???");
352 		if (code != VIDIOC_DQBUF)
353 			tprintf(", index=%u", b.index);
354 	} else {
355 		if (!syserror(tcp) && umove(tcp, arg, &b) == 0) {
356 			if (code == VIDIOC_DQBUF)
357 				tprintf(", index=%u", b.index);
358 			tprints(", memory=");
359 			printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
360 
361 			if (b.memory == V4L2_MEMORY_MMAP) {
362 				tprintf(", m.offset=%#x", b.m.offset);
363 			} else if (b.memory == V4L2_MEMORY_USERPTR) {
364 				tprints(", m.userptr=");
365 				printaddr(b.m.userptr);
366 			}
367 
368 			tprintf(", length=%u, bytesused=%u, flags=",
369 				b.length, b.bytesused);
370 			printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???");
371 			if (code == VIDIOC_DQBUF) {
372 				tprints(", timestamp = ");
373 				MPERS_FUNC_NAME(print_struct_timeval)(&b.timestamp);
374 			}
375 			tprints(", ...");
376 		}
377 		tprints("}");
378 	}
379 	return 1;
380 }
381 
382 static int
print_v4l2_framebuffer(struct tcb * const tcp,const kernel_ulong_t arg)383 print_v4l2_framebuffer(struct tcb *const tcp, const kernel_ulong_t arg)
384 {
385 	struct_v4l2_framebuffer b;
386 
387 	tprints(", ");
388 	if (!umove_or_printaddr(tcp, arg, &b)) {
389 		tprintf("{capability=%#x, flags=%#x, base=",
390 			b.capability, b.flags);
391 		printaddr(ptr_to_kulong(b.base));
392 		tprints("}");
393 	}
394 
395 	return RVAL_DECODED | 1;
396 }
397 
398 static int
print_v4l2_buf_type(struct tcb * const tcp,const kernel_ulong_t arg)399 print_v4l2_buf_type(struct tcb *const tcp, const kernel_ulong_t arg)
400 {
401 	int type;
402 
403 	tprints(", ");
404 	if (!umove_or_printaddr(tcp, arg, &type)) {
405 		tprints("[");
406 		printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
407 		tprints("]");
408 	}
409 	return RVAL_DECODED | 1;
410 }
411 
412 #include "xlat/v4l2_streaming_capabilities.h"
413 #include "xlat/v4l2_capture_modes.h"
414 
415 static int
print_v4l2_streamparm(struct tcb * const tcp,const kernel_ulong_t arg,const bool is_get)416 print_v4l2_streamparm(struct tcb *const tcp, const kernel_ulong_t arg,
417 		      const bool is_get)
418 {
419 	struct v4l2_streamparm s;
420 
421 	if (entering(tcp)) {
422 		tprints(", ");
423 		if (umove_or_printaddr(tcp, arg, &s))
424 			return RVAL_DECODED | 1;
425 		tprints("{type=");
426 		printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
427 		switch (s.type) {
428 			case V4L2_BUF_TYPE_VIDEO_CAPTURE:
429 			case V4L2_BUF_TYPE_VIDEO_OUTPUT:
430 				if (is_get)
431 					return 0;
432 				tprints(", ");
433 				break;
434 			default:
435 				tprints("}");
436 				return RVAL_DECODED | 1;
437 		}
438 	} else {
439 		if (syserror(tcp) || umove(tcp, arg, &s) < 0) {
440 			tprints("}");
441 			return 1;
442 		}
443 		tprints(is_get ? ", " : " => ");
444 	}
445 
446 	if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
447 		tprints("parm.capture={capability=");
448 		printflags(v4l2_streaming_capabilities,
449 			   s.parm.capture.capability, "V4L2_CAP_???");
450 
451 		tprints(", capturemode=");
452 		printflags(v4l2_capture_modes,
453 			   s.parm.capture.capturemode, "V4L2_MODE_???");
454 
455 		tprintf(", timeperframe=" FMT_FRACT,
456 			ARGS_FRACT(s.parm.capture.timeperframe));
457 
458 		tprintf(", extendedmode=%u, readbuffers=%u}",
459 			s.parm.capture.extendedmode,
460 			s.parm.capture.readbuffers);
461 	} else {
462 		tprints("parm.output={capability=");
463 		printflags(v4l2_streaming_capabilities,
464 			   s.parm.output.capability, "V4L2_CAP_???");
465 
466 		tprintf(", outputmode=%u", s.parm.output.outputmode);
467 
468 		tprintf(", timeperframe=" FMT_FRACT,
469 			ARGS_FRACT(s.parm.output.timeperframe));
470 
471 		tprintf(", extendedmode=%u, writebuffers=%u}",
472 			s.parm.output.extendedmode,
473 			s.parm.output.writebuffers);
474 	}
475 	if (exiting(tcp))
476 		tprints("}");
477 	return 1;
478 }
479 
480 static int
print_v4l2_standard(struct tcb * const tcp,const kernel_ulong_t arg)481 print_v4l2_standard(struct tcb *const tcp, const kernel_ulong_t arg)
482 {
483 	struct_v4l2_standard s;
484 
485 	if (entering(tcp)) {
486 		tprints(", ");
487 		if (umove_or_printaddr(tcp, arg, &s))
488 			return RVAL_DECODED | 1;
489 		tprintf("{index=%u", s.index);
490 	} else {
491 		if (!syserror(tcp) && !umove(tcp, arg, &s)) {
492 			tprints(", name=");
493 			print_quoted_string((const char *) s.name,
494 					    sizeof(s.name),
495 					    QUOTE_0_TERMINATED);
496 			tprintf(", frameperiod=" FMT_FRACT,
497 				ARGS_FRACT(s.frameperiod));
498 			tprintf(", framelines=%d", s.framelines);
499 		}
500 		tprints("}");
501 	}
502 	return 1;
503 }
504 
505 #include "xlat/v4l2_input_types.h"
506 
507 static int
print_v4l2_input(struct tcb * const tcp,const kernel_ulong_t arg)508 print_v4l2_input(struct tcb *const tcp, const kernel_ulong_t arg)
509 {
510 	struct_v4l2_input i;
511 
512 	if (entering(tcp)) {
513 		tprints(", ");
514 		if (umove_or_printaddr(tcp, arg, &i))
515 			return RVAL_DECODED | 1;
516 		tprintf("{index=%u", i.index);
517 	} else {
518 		if (!syserror(tcp) && !umove(tcp, arg, &i)) {
519 			tprints(", name=");
520 			print_quoted_string((const char *) i.name,
521 					    sizeof(i.name),
522 					    QUOTE_0_TERMINATED);
523 			tprints(", type=");
524 			printxval(v4l2_input_types, i.type,
525 				  "V4L2_INPUT_TYPE_???");
526 		}
527 		tprints("}");
528 	}
529 	return 1;
530 }
531 
532 #include "xlat/v4l2_control_ids.h"
533 
534 static int
print_v4l2_control(struct tcb * const tcp,const kernel_ulong_t arg,const bool is_get)535 print_v4l2_control(struct tcb *const tcp, const kernel_ulong_t arg,
536 		   const bool is_get)
537 {
538 	struct v4l2_control c;
539 
540 	if (entering(tcp)) {
541 		tprints(", ");
542 		if (umove_or_printaddr(tcp, arg, &c))
543 			return RVAL_DECODED | 1;
544 		tprints("{id=");
545 		printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
546 		if (!is_get)
547 			tprintf(", value=%d", c.value);
548 		return 0;
549 	}
550 
551 	if (!syserror(tcp) && !umove(tcp, arg, &c)) {
552 		tprints(is_get ? ", " : " => ");
553 		tprintf("value=%d", c.value);
554 	}
555 
556 	tprints("}");
557 	return 1;
558 }
559 
560 #include "xlat/v4l2_control_types.h"
561 #include "xlat/v4l2_control_flags.h"
562 
563 static int
print_v4l2_queryctrl(struct tcb * const tcp,const kernel_ulong_t arg)564 print_v4l2_queryctrl(struct tcb *const tcp, const kernel_ulong_t arg)
565 {
566 	struct v4l2_queryctrl c;
567 
568 	if (entering(tcp)) {
569 		tprints(", ");
570 		if (umove_or_printaddr(tcp, arg, &c))
571 			return RVAL_DECODED | 1;
572 		tprints("{id=");
573 	} else {
574 		if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
575 			tprints("}");
576 			return 1;
577 		}
578 		if (get_tcb_priv_ulong(tcp))
579 			tprints(" => ");
580 	}
581 
582 	if (entering(tcp) || get_tcb_priv_ulong(tcp)) {
583 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
584 		const unsigned long next = c.id & V4L2_CTRL_FLAG_NEXT_CTRL;
585 		set_tcb_priv_ulong(tcp, next);
586 		if (next) {
587 			tprints("V4L2_CTRL_FLAG_NEXT_CTRL|");
588 			c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
589 		}
590 #endif
591 		printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
592 	}
593 
594 	if (exiting(tcp)) {
595 		tprints(", type=");
596 		printxval(v4l2_control_types, c.type, "V4L2_CTRL_TYPE_???");
597 		tprints(", name=");
598 		print_quoted_string((const char *) c.name,
599 				    sizeof(c.name),
600 				    QUOTE_0_TERMINATED);
601 		tprintf(", minimum=%d, maximum=%d, step=%d"
602 			", default_value=%d, flags=",
603 			c.minimum, c.maximum, c.step, c.default_value);
604 		printflags(v4l2_control_flags, c.flags, "V4L2_CTRL_FLAG_???");
605 		tprints("}");
606 	}
607 	return 1;
608 }
609 
610 static int
print_v4l2_cropcap(struct tcb * const tcp,const kernel_ulong_t arg)611 print_v4l2_cropcap(struct tcb *const tcp, const kernel_ulong_t arg)
612 {
613 	struct v4l2_cropcap c;
614 
615 	if (entering(tcp)) {
616 		tprints(", ");
617 		if (umove_or_printaddr(tcp, arg, &c))
618 			return RVAL_DECODED | 1;
619 		tprints("{type=");
620 		printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
621 		return 0;
622 	}
623 	if (!syserror(tcp) && !umove(tcp, arg, &c)) {
624 		tprintf(", bounds=" FMT_RECT
625 			", defrect=" FMT_RECT
626 			", pixelaspect=" FMT_FRACT,
627 			ARGS_RECT(c.bounds),
628 			ARGS_RECT(c.defrect),
629 			ARGS_FRACT(c.pixelaspect));
630 	}
631 	tprints("}");
632 	return 1;
633 }
634 
635 static int
print_v4l2_crop(struct tcb * const tcp,const kernel_ulong_t arg,const bool is_get)636 print_v4l2_crop(struct tcb *const tcp, const kernel_ulong_t arg,
637 		const bool is_get)
638 {
639 	struct v4l2_crop c;
640 
641 	if (entering(tcp)) {
642 		tprints(", ");
643 		if (umove_or_printaddr(tcp, arg, &c))
644 			return RVAL_DECODED | 1;
645 		tprints("{type=");
646 		printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
647 		if (is_get)
648 			return 0;
649 		tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
650 	} else {
651 		if (!syserror(tcp) && !umove(tcp, arg, &c))
652 			tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
653 	}
654 
655 	tprints("}");
656 	return RVAL_DECODED | 1;
657 }
658 
659 #ifdef VIDIOC_S_EXT_CTRLS
660 static bool
print_v4l2_ext_control(struct tcb * tcp,void * elem_buf,size_t elem_size,void * data)661 print_v4l2_ext_control(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
662 {
663 	const struct_v4l2_ext_control *p = elem_buf;
664 
665 	tprints("{id=");
666 	printxval(v4l2_control_ids, p->id, "V4L2_CID_???");
667 # if HAVE_DECL_V4L2_CTRL_TYPE_STRING
668 	tprintf(", size=%u", p->size);
669 	if (p->size > 0) {
670 		tprints(", string=");
671 		printstrn(tcp, ptr_to_kulong(p->string), p->size);
672 	} else
673 # endif
674 	tprintf(", value=%d, value64=%" PRId64, p->value, (int64_t) p->value64);
675 	tprints("}");
676 
677 	return true;
678 }
679 
680 #include "xlat/v4l2_control_classes.h"
681 
682 static int
print_v4l2_ext_controls(struct tcb * const tcp,const kernel_ulong_t arg,const bool is_get)683 print_v4l2_ext_controls(struct tcb *const tcp, const kernel_ulong_t arg,
684 			const bool is_get)
685 {
686 	struct_v4l2_ext_controls c;
687 
688 	if (entering(tcp)) {
689 		tprints(", ");
690 		if (umove_or_printaddr(tcp, arg, &c))
691 			return RVAL_DECODED | 1;
692 		tprints("{ctrl_class=");
693 		printxval(v4l2_control_classes, c.ctrl_class,
694 			  "V4L2_CTRL_CLASS_???");
695 		tprintf(", count=%u", c.count);
696 		if (!c.count) {
697 			tprints("}");
698 			return RVAL_DECODED | 1;
699 		}
700 		if (is_get)
701 			return 0;
702 		tprints(", ");
703 	} else {
704 		if (umove(tcp, arg, &c) < 0) {
705 			tprints("}");
706 			return 1;
707 		}
708 		tprints(is_get ? ", " : " => ");
709 	}
710 
711 	tprints("controls=");
712 	struct_v4l2_ext_control ctrl;
713 	bool fail = !print_array(tcp, ptr_to_kulong(c.controls), c.count,
714 				 &ctrl, sizeof(ctrl),
715 				 umoven_or_printaddr_ignore_syserror,
716 				 print_v4l2_ext_control, 0);
717 
718 	if (exiting(tcp) && syserror(tcp))
719 		tprintf(", error_idx=%u", c.error_idx);
720 
721 	if (exiting(tcp) || fail) {
722 		tprints("}");
723 		return RVAL_DECODED | 1;
724 	}
725 	return 1;
726 }
727 #endif /* VIDIOC_S_EXT_CTRLS */
728 
729 #ifdef VIDIOC_ENUM_FRAMESIZES
730 # include "xlat/v4l2_framesize_types.h"
731 
732 static int
print_v4l2_frmsizeenum(struct tcb * const tcp,const kernel_ulong_t arg)733 print_v4l2_frmsizeenum(struct tcb *const tcp, const kernel_ulong_t arg)
734 {
735 	struct v4l2_frmsizeenum s;
736 
737 	if (entering(tcp)) {
738 		tprints(", ");
739 		if (umove_or_printaddr(tcp, arg, &s))
740 			return RVAL_DECODED | 1;
741 		tprintf("{index=%u, pixel_format=", s.index);
742 		print_pixelformat(s.pixel_format);
743 		return 0;
744 	}
745 
746 	if (!syserror(tcp) && !umove(tcp, arg, &s)) {
747 		tprints(", type=");
748 		printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
749 		switch (s.type) {
750 		case V4L2_FRMSIZE_TYPE_DISCRETE:
751 			tprintf(", discrete={width=%u, height=%u}",
752 				s.discrete.width, s.discrete.height);
753 			break;
754 		case V4L2_FRMSIZE_TYPE_STEPWISE:
755 			tprintf(", stepwise={min_width=%u, max_width=%u, "
756 				"step_width=%u, min_height=%u, max_height=%u, "
757 				"step_height=%u}",
758 				s.stepwise.min_width, s.stepwise.max_width,
759 				s.stepwise.step_width, s.stepwise.min_height,
760 				s.stepwise.max_height, s.stepwise.step_height);
761 			break;
762 		}
763 	}
764 	tprints("}");
765 	return 1;
766 }
767 #endif /* VIDIOC_ENUM_FRAMESIZES */
768 
769 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
770 # include "xlat/v4l2_frameinterval_types.h"
771 
772 static int
print_v4l2_frmivalenum(struct tcb * const tcp,const kernel_ulong_t arg)773 print_v4l2_frmivalenum(struct tcb *const tcp, const kernel_ulong_t arg)
774 {
775 	struct v4l2_frmivalenum f;
776 
777 	if (entering(tcp)) {
778 		tprints(", ");
779 		if (umove_or_printaddr(tcp, arg, &f))
780 			return RVAL_DECODED | 1;
781 		tprintf("{index=%u, pixel_format=", f.index);
782 		print_pixelformat(f.pixel_format);
783 		tprintf(", width=%u, height=%u", f.width, f.height);
784 		return 0;
785 	}
786 	if (!syserror(tcp) && !umove(tcp, arg, &f)) {
787 		tprints(", type=");
788 		printxval(v4l2_frameinterval_types, f.type,
789 			  "V4L2_FRMIVAL_TYPE_???");
790 		switch (f.type) {
791 		case V4L2_FRMIVAL_TYPE_DISCRETE:
792 			tprintf(", discrete=" FMT_FRACT,
793 				ARGS_FRACT(f.discrete));
794 			break;
795 		case V4L2_FRMIVAL_TYPE_STEPWISE:
796 		case V4L2_FRMSIZE_TYPE_CONTINUOUS:
797 			tprintf(", stepwise={min=" FMT_FRACT ", max="
798 				FMT_FRACT ", step=" FMT_FRACT "}",
799 				ARGS_FRACT(f.stepwise.min),
800 				ARGS_FRACT(f.stepwise.max),
801 				ARGS_FRACT(f.stepwise.step));
802 			break;
803 		}
804 	}
805 	tprints("}");
806 	return 1;
807 }
808 #endif /* VIDIOC_ENUM_FRAMEINTERVALS */
809 
810 #ifdef VIDIOC_CREATE_BUFS
811 static int
print_v4l2_create_buffers(struct tcb * const tcp,const kernel_ulong_t arg)812 print_v4l2_create_buffers(struct tcb *const tcp, const kernel_ulong_t arg)
813 {
814 	struct_v4l2_create_buffers b;
815 
816 	if (entering(tcp)) {
817 		tprints(", ");
818 		if (umove_or_printaddr(tcp, arg, &b))
819 			return RVAL_DECODED | 1;
820 		tprintf("{count=%u, memory=", b.count);
821 		printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
822 		tprints(", format={type=");
823 		printxval(v4l2_buf_types, b.format.type,
824 			  "V4L2_BUF_TYPE_???");
825 		print_v4l2_format_fmt(", ",
826 				      (struct_v4l2_format *) &b.format);
827 		tprints("}}");
828 		return 0;
829 	} else {
830 		static const char fmt[] = "{index=%u, count=%u}";
831 		static char outstr[sizeof(fmt) + sizeof(int) * 6];
832 
833 		if (syserror(tcp) || umove(tcp, arg, &b) < 0)
834 			return 1;
835 		sprintf(outstr, fmt, b.index, b.count);
836 		tcp->auxstr = outstr;
837 		return 1 + RVAL_STR;
838 	}
839 }
840 #endif /* VIDIOC_CREATE_BUFS */
841 
MPERS_PRINTER_DECL(int,v4l2_ioctl,struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)842 MPERS_PRINTER_DECL(int, v4l2_ioctl, struct tcb *const tcp,
843 		   const unsigned int code, const kernel_ulong_t arg)
844 {
845 	if (!verbose(tcp))
846 		return RVAL_DECODED;
847 
848 	switch (code) {
849 	case VIDIOC_QUERYCAP: /* R */
850 		return print_v4l2_capability(tcp, arg);
851 
852 	case VIDIOC_ENUM_FMT: /* RW */
853 		return print_v4l2_fmtdesc(tcp, arg);
854 
855 	case VIDIOC_G_FMT: /* RW */
856 	case VIDIOC_S_FMT: /* RW */
857 	case VIDIOC_TRY_FMT: /* RW */
858 		return print_v4l2_format(tcp, arg, code == VIDIOC_G_FMT);
859 
860 	case VIDIOC_REQBUFS: /* RW */
861 		return print_v4l2_requestbuffers(tcp, arg);
862 
863 	case VIDIOC_QUERYBUF: /* RW */
864 	case VIDIOC_QBUF: /* RW */
865 	case VIDIOC_DQBUF: /* RW */
866 		return print_v4l2_buffer(tcp, code, arg);
867 
868 	case VIDIOC_G_FBUF: /* R */
869 		if (entering(tcp))
870 			return 0;
871 		/* fall through */
872 	case VIDIOC_S_FBUF: /* W */
873 		return print_v4l2_framebuffer(tcp, arg);
874 
875 	case VIDIOC_STREAMON: /* W */
876 	case VIDIOC_STREAMOFF: /* W */
877 		return print_v4l2_buf_type(tcp, arg);
878 
879 	case VIDIOC_G_PARM: /* RW */
880 	case VIDIOC_S_PARM: /* RW */
881 		return print_v4l2_streamparm(tcp, arg, code == VIDIOC_G_PARM);
882 
883 	case VIDIOC_G_STD: /* R */
884 		if (entering(tcp))
885 			return 0;
886 		/* fall through */
887 	case VIDIOC_S_STD: /* W */
888 		tprints(", ");
889 		printnum_int64(tcp, arg, "%#" PRIx64);
890 		return RVAL_DECODED | 1;
891 
892 	case VIDIOC_ENUMSTD: /* RW */
893 		return print_v4l2_standard(tcp, arg);
894 
895 	case VIDIOC_ENUMINPUT: /* RW */
896 		return print_v4l2_input(tcp, arg);
897 
898 	case VIDIOC_G_CTRL: /* RW */
899 	case VIDIOC_S_CTRL: /* RW */
900 		return print_v4l2_control(tcp, arg, code == VIDIOC_G_CTRL);
901 
902 	case VIDIOC_QUERYCTRL: /* RW */
903 		return print_v4l2_queryctrl(tcp, arg);
904 
905 	case VIDIOC_G_INPUT: /* R */
906 		if (entering(tcp))
907 			return 0;
908 		/* fall through */
909 	case VIDIOC_S_INPUT: /* RW */
910 		tprints(", ");
911 		printnum_int(tcp, arg, "%u");
912 		return RVAL_DECODED | 1;
913 
914 	case VIDIOC_CROPCAP: /* RW */
915 		return print_v4l2_cropcap(tcp, arg);
916 
917 	case VIDIOC_G_CROP: /* RW */
918 	case VIDIOC_S_CROP: /* W */
919 		return print_v4l2_crop(tcp, arg, code == VIDIOC_G_CROP);
920 
921 #ifdef VIDIOC_S_EXT_CTRLS
922 	case VIDIOC_S_EXT_CTRLS: /* RW */
923 	case VIDIOC_TRY_EXT_CTRLS: /* RW */
924 	case VIDIOC_G_EXT_CTRLS: /* RW */
925 		return print_v4l2_ext_controls(tcp, arg,
926 					       code == VIDIOC_G_EXT_CTRLS);
927 #endif /* VIDIOC_S_EXT_CTRLS */
928 
929 #ifdef VIDIOC_ENUM_FRAMESIZES
930 	case VIDIOC_ENUM_FRAMESIZES: /* RW */
931 		return print_v4l2_frmsizeenum(tcp, arg);
932 #endif /* VIDIOC_ENUM_FRAMESIZES */
933 
934 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
935 	case VIDIOC_ENUM_FRAMEINTERVALS: /* RW */
936 		return print_v4l2_frmivalenum(tcp, arg);
937 #endif /* VIDIOC_ENUM_FRAMEINTERVALS */
938 
939 #ifdef VIDIOC_CREATE_BUFS
940 	case VIDIOC_CREATE_BUFS: /* RW */
941 		return print_v4l2_create_buffers(tcp, arg);
942 #endif /* VIDIOC_CREATE_BUFS */
943 
944 	default:
945 		return RVAL_DECODED;
946 	}
947 }
948