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 * Copyright (c) 2014-2023 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: LGPL-2.1-or-later
9 */
10
11 #include "defs.h"
12
13 #include DEF_MPERS_TYPE(kernel_v4l2_buffer_t)
14 #include DEF_MPERS_TYPE(kernel_v4l2_event_t)
15 #include DEF_MPERS_TYPE(kernel_v4l2_timeval_t)
16 #include DEF_MPERS_TYPE(struct_v4l2_clip)
17 #include DEF_MPERS_TYPE(struct_v4l2_create_buffers)
18 #include DEF_MPERS_TYPE(struct_v4l2_ext_control)
19 #include DEF_MPERS_TYPE(struct_v4l2_ext_controls)
20 #include DEF_MPERS_TYPE(struct_v4l2_format)
21 #include DEF_MPERS_TYPE(struct_v4l2_framebuffer)
22 #include DEF_MPERS_TYPE(struct_v4l2_input)
23 #include DEF_MPERS_TYPE(struct_v4l2_standard)
24 #include DEF_MPERS_TYPE(struct_v4l2_window)
25
26 #include "kernel_v4l2_types.h"
27 typedef struct v4l2_clip struct_v4l2_clip;
28 typedef struct v4l2_create_buffers struct_v4l2_create_buffers;
29 typedef struct v4l2_ext_control struct_v4l2_ext_control;
30 typedef struct v4l2_ext_controls struct_v4l2_ext_controls;
31 typedef struct v4l2_format struct_v4l2_format;
32 typedef struct v4l2_framebuffer struct_v4l2_framebuffer;
33 typedef struct v4l2_input struct_v4l2_input;
34 typedef struct v4l2_standard struct_v4l2_standard;
35 typedef struct v4l2_window struct_v4l2_window;
36
37 #include MPERS_DEFS
38
39 #include "print_utils.h"
40 #include "xstring.h"
41
42 #include "xlat/v4l2_meta_fmts.h"
43 #include "xlat/v4l2_pix_fmts.h"
44 #include "xlat/v4l2_sdr_fmts.h"
45
46 static void
47 print_v4l2_rect(const MPERS_PTR_ARG(struct v4l2_rect *) const arg)
48 {
49 const struct v4l2_rect *const p = arg;
50 tprint_struct_begin();
51 PRINT_FIELD_D(*p, left);
52 tprint_struct_next();
53 PRINT_FIELD_D(*p, top);
54 tprint_struct_next();
55 PRINT_FIELD_U(*p, width);
56 tprint_struct_next();
57 PRINT_FIELD_U(*p, height);
58 tprint_struct_end();
59 }
60
61 #define PRINT_FIELD_FRACT(where_, field_) \
62 do { \
63 tprints_field_name(#field_); \
64 tprintf_string("%u/%u", \
65 (where_).field_.numerator, \
66 (where_).field_.denominator); \
67 } while (0)
68
69 static void
70 print_pixelformat(uint32_t fourcc, const struct xlat *xlat)
71 {
72 if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW) {
73 PRINT_VAL_X(fourcc);
74 return;
75 }
76
77 unsigned char a[] = {
78 (unsigned char) fourcc,
79 (unsigned char) (fourcc >> 8),
80 (unsigned char) (fourcc >> 16),
81 (unsigned char) (fourcc >> 24),
82 };
83
84 tprints_arg_begin("v4l2_fourcc");
85 /* Generic char array printing routine. */
86 for (unsigned int i = 0; i < ARRAY_SIZE(a); ++i) {
87 unsigned char c = a[i];
88
89 if (i)
90 tprint_arg_next();
91
92 print_char(c, SCF_QUOTES);
93 }
94 tprint_arg_end();
95
96 if (xlat) {
97 const char *pixfmt_name = xlookup(xlat, fourcc);
98
99 if (pixfmt_name)
100 tprints_comment(pixfmt_name);
101 }
102 }
103
104 #define PRINT_FIELD_PIXFMT(where_, field_, xlat_) \
105 do { \
106 tprints_field_name(#field_); \
107 print_pixelformat((where_).field_, (xlat_)); \
108 } while (0)
109
110 #include "xlat/v4l2_device_capabilities_flags.h"
111
112 static int
113 print_v4l2_capability(struct tcb *const tcp, const kernel_ulong_t arg)
114 {
115 struct v4l2_capability caps;
116
117 if (entering(tcp))
118 return 0;
119
120 tprint_arg_next();
121 if (umove_or_printaddr(tcp, arg, &caps))
122 return RVAL_IOCTL_DECODED;
123
124 tprint_struct_begin();
125 PRINT_FIELD_CSTRING(caps, driver);
126 tprint_struct_next();
127 PRINT_FIELD_CSTRING(caps, card);
128 tprint_struct_next();
129 PRINT_FIELD_CSTRING(caps, bus_info);
130 tprint_struct_next();
131 PRINT_FIELD_OBJ_VAL(caps, version, print_kernel_version);
132 tprint_struct_next();
133 PRINT_FIELD_FLAGS(caps, capabilities,
134 v4l2_device_capabilities_flags, "V4L2_CAP_???");
135 if (caps.device_caps) {
136 tprint_struct_next();
137 PRINT_FIELD_FLAGS(caps, device_caps,
138 v4l2_device_capabilities_flags,
139 "V4L2_CAP_???");
140 }
141 tprint_struct_end();
142 return RVAL_IOCTL_DECODED;
143 }
144
145 #include "xlat/v4l2_buf_types.h"
146 #include "xlat/v4l2_format_description_flags.h"
147
148 static int
149 print_v4l2_fmtdesc(struct tcb *const tcp, const kernel_ulong_t arg)
150 {
151 struct v4l2_fmtdesc f;
152
153 if (entering(tcp)) {
154 tprint_arg_next();
155 if (umove_or_printaddr(tcp, arg, &f))
156 return RVAL_IOCTL_DECODED;
157
158 tprint_struct_begin();
159 PRINT_FIELD_U(f, index);
160 tprint_struct_next();
161 PRINT_FIELD_XVAL(f, type, v4l2_buf_types,
162 "V4L2_BUF_TYPE_???");
163 return 0;
164 }
165
166 if (!syserror(tcp) && !umove(tcp, arg, &f)) {
167 tprint_struct_next();
168 PRINT_FIELD_FLAGS(f, flags,
169 v4l2_format_description_flags,
170 "V4L2_FMT_FLAG_???");
171 tprint_struct_next();
172 PRINT_FIELD_CSTRING(f, description);
173 tprint_struct_next();
174 PRINT_FIELD_PIXFMT(f, pixelformat, v4l2_pix_fmts);
175 }
176 tprint_struct_end();
177 return RVAL_IOCTL_DECODED;
178 }
179
180 #include "xlat/v4l2_fields.h"
181 #include "xlat/v4l2_colorspaces.h"
182 #include "xlat/v4l2_vbi_flags.h"
183 #include "xlat/v4l2_sliced_flags.h"
184
185 static bool
186 print_v4l2_clip(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
187 {
188 const struct_v4l2_clip *p = elem_buf;
189 tprint_struct_begin();
190 PRINT_FIELD_OBJ_PTR(*p, c, print_v4l2_rect);
191 tprint_struct_end();
192 return true;
193 }
194
195 #define DECL_print_v4l2_format_fmt(name_) \
196 print_v4l2_format_fmt_ ## name_(struct tcb *const tcp, \
197 const typeof_field(struct_v4l2_format, fmt.name_) *const p)
198
199 static bool
200 DECL_print_v4l2_format_fmt(pix)
201 {
202 tprint_struct_begin();
203 PRINT_FIELD_U(*p, width);
204 tprint_struct_next();
205 PRINT_FIELD_U(*p, height);
206 tprint_struct_next();
207 PRINT_FIELD_PIXFMT(*p, pixelformat, v4l2_pix_fmts);
208 tprint_struct_next();
209 PRINT_FIELD_XVAL(*p, field, v4l2_fields, "V4L2_FIELD_???");
210 tprint_struct_next();
211 PRINT_FIELD_U(*p, bytesperline);
212 tprint_struct_next();
213 PRINT_FIELD_U(*p, sizeimage);
214 tprint_struct_next();
215 PRINT_FIELD_XVAL(*p, colorspace, v4l2_colorspaces,
216 "V4L2_COLORSPACE_???");
217 tprint_struct_end();
218 return true;
219 }
220
221 static bool
222 print_v4l2_plane_pix_format_array_member(struct tcb *tcp, void *elem_buf,
223 size_t elem_size, void *data)
224 {
225 struct v4l2_plane_pix_format *p = elem_buf;
226
227 tprint_struct_begin();
228 PRINT_FIELD_U(*p, sizeimage);
229 tprint_struct_next();
230 PRINT_FIELD_U(*p, bytesperline);
231 tprint_struct_end();
232
233 return true;
234 }
235
236 static bool
237 DECL_print_v4l2_format_fmt(pix_mp)
238 {
239 tprint_struct_begin();
240 PRINT_FIELD_U(*p, width);
241 tprint_struct_next();
242 PRINT_FIELD_U(*p, height);
243 tprint_struct_next();
244 PRINT_FIELD_PIXFMT(*p, pixelformat, v4l2_pix_fmts);
245 tprint_struct_next();
246 PRINT_FIELD_XVAL(*p, field, v4l2_fields, "V4L2_FIELD_???");
247 tprint_struct_next();
248 PRINT_FIELD_XVAL(*p, colorspace, v4l2_colorspaces,
249 "V4L2_COLORSPACE_???");
250 tprint_struct_next();
251 PRINT_FIELD_ARRAY_UPTO(*p, plane_fmt, p->num_planes, tcp,
252 print_v4l2_plane_pix_format_array_member);
253 tprint_struct_next();
254 PRINT_FIELD_U(*p, num_planes);
255 tprint_struct_end();
256 return true;
257 }
258
259 static bool
260 DECL_print_v4l2_format_fmt(win)
261 {
262 tprint_struct_begin();
263 PRINT_FIELD_OBJ_PTR(*p, w, print_v4l2_rect);
264 tprint_struct_next();
265 PRINT_FIELD_XVAL(*p, field, v4l2_fields, "V4L2_FIELD_???");
266 tprint_struct_next();
267 PRINT_FIELD_X(*p, chromakey);
268
269 tprint_struct_next();
270 tprints_field_name("clips");
271 struct_v4l2_clip clip;
272 bool rc = print_array(tcp, ptr_to_kulong(p->clips),
273 p->clipcount, &clip, sizeof(clip),
274 tfetch_mem, print_v4l2_clip, 0);
275
276 tprint_struct_next();
277 PRINT_FIELD_U(*p, clipcount);
278 tprint_struct_next();
279 PRINT_FIELD_PTR(*p, bitmap);
280 if (p->global_alpha) {
281 tprint_struct_next();
282 PRINT_FIELD_X(*p, global_alpha);
283 }
284 tprint_struct_end();
285 return rc;
286 }
287
288 static bool
289 DECL_print_v4l2_format_fmt(vbi)
290 {
291 tprint_struct_begin();
292 PRINT_FIELD_U(*p, sampling_rate);
293 tprint_struct_next();
294 PRINT_FIELD_U(*p, offset);
295 tprint_struct_next();
296 PRINT_FIELD_U(*p, samples_per_line);
297 tprint_struct_next();
298 PRINT_FIELD_PIXFMT(*p, sample_format, v4l2_pix_fmts);
299 tprint_struct_next();
300 PRINT_FIELD_D_ARRAY(*p, start);
301 tprint_struct_next();
302 PRINT_FIELD_U_ARRAY(*p, count);
303 tprint_struct_next();
304 PRINT_FIELD_FLAGS(*p, flags, v4l2_vbi_flags, "V4L2_VBI_???");
305 tprint_struct_end();
306 return true;
307 }
308
309 static bool
310 DECL_print_v4l2_format_fmt(sliced)
311 {
312 tprint_struct_begin();
313 PRINT_FIELD_FLAGS(*p, service_set, v4l2_sliced_flags,
314 "V4L2_SLICED_???");
315 tprint_struct_next();
316 PRINT_FIELD_X_ARRAY2D(*p, service_lines);
317 tprint_struct_next();
318 PRINT_FIELD_U(*p, io_size);
319 tprint_struct_end();
320 return true;
321 }
322
323 static bool
324 DECL_print_v4l2_format_fmt(sdr)
325 {
326 tprint_struct_begin();
327 PRINT_FIELD_PIXFMT(*p, pixelformat, v4l2_sdr_fmts);
328 if (p->buffersize) {
329 tprint_struct_next();
330 PRINT_FIELD_U(*p, buffersize);
331 }
332 tprint_struct_end();
333 return true;
334 }
335
336 static bool
337 DECL_print_v4l2_format_fmt(meta)
338 {
339 tprint_struct_begin();
340 PRINT_FIELD_PIXFMT(*p, dataformat, v4l2_meta_fmts);
341 tprint_struct_next();
342 PRINT_FIELD_U(*p, buffersize);
343 tprint_struct_end();
344 return true;
345 }
346
347 #define PRINT_FIELD_V4L2_FORMAT_FMT(where_, fmt_, field_, tcp_, ret_) \
348 do { \
349 tprints_field_name(#fmt_ "." #field_); \
350 (ret_) = (print_v4l2_format_fmt_ ## field_) \
351 ((tcp_), &((where_).fmt_.field_)); \
352 } while (0)
353
354 static bool
355 print_v4l2_format_fmt(struct tcb *const tcp, void (*const prefix_fun)(void),
356 const struct_v4l2_format *const f)
357 {
358 bool ret = true;
359 switch (f->type) {
360 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
361 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
362 prefix_fun();
363 PRINT_FIELD_V4L2_FORMAT_FMT(*f, fmt, pix, tcp, ret);
364 break;
365
366 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
367 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
368 prefix_fun();
369 PRINT_FIELD_V4L2_FORMAT_FMT(*f, fmt, pix_mp, tcp, ret);
370 break;
371
372 /* OUTPUT_OVERLAY since Linux v2.6.22-rc1~1118^2~179 */
373 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
374 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
375 prefix_fun();
376 PRINT_FIELD_V4L2_FORMAT_FMT(*f, fmt, win, tcp, ret);
377 break;
378
379 case V4L2_BUF_TYPE_VBI_CAPTURE:
380 case V4L2_BUF_TYPE_VBI_OUTPUT:
381 prefix_fun();
382 PRINT_FIELD_V4L2_FORMAT_FMT(*f, fmt, vbi, tcp, ret);
383 break;
384
385 /* both since Linux v2.6.14-rc2~64 */
386 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
387 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
388 prefix_fun();
389 PRINT_FIELD_V4L2_FORMAT_FMT(*f, fmt, sliced, tcp, ret);
390 break;
391
392 /* since Linux v4.4-rc1~118^2~14 */
393 case V4L2_BUF_TYPE_SDR_OUTPUT:
394 /* since Linux v3.15-rc1~85^2~213 */
395 case V4L2_BUF_TYPE_SDR_CAPTURE:
396 prefix_fun();
397 PRINT_FIELD_V4L2_FORMAT_FMT(*f, fmt, sdr, tcp, ret);
398 break;
399 /* since Linux v5.0-rc1~181^2~21 */
400 case V4L2_BUF_TYPE_META_OUTPUT:
401 /* since Linux v4.12-rc1~85^2~71 */
402 case V4L2_BUF_TYPE_META_CAPTURE:
403 prefix_fun();
404 PRINT_FIELD_V4L2_FORMAT_FMT(*f, fmt, meta, tcp, ret);
405 break;
406 default:
407 return false;
408 }
409 return ret;
410 }
411
412 static void
413 tprint_struct_end_value_changed_struct_begin(void)
414 {
415 tprint_struct_end();
416 tprint_value_changed();
417 tprint_struct_begin();
418 }
419
420 static int
421 print_v4l2_format(struct tcb *const tcp, const kernel_ulong_t arg,
422 const bool is_get)
423 {
424 struct_v4l2_format f;
425
426 if (entering(tcp)) {
427 tprint_arg_next();
428 if (umove_or_printaddr(tcp, arg, &f))
429 return RVAL_IOCTL_DECODED;
430
431 tprint_struct_begin();
432 PRINT_FIELD_XVAL(f, type, v4l2_buf_types,
433 "V4L2_BUF_TYPE_???");
434 if (is_get)
435 return 0;
436 if (!print_v4l2_format_fmt(tcp, tprint_struct_next, &f)) {
437 tprint_struct_end();
438 return RVAL_IOCTL_DECODED;
439 }
440
441 return 0;
442 }
443
444 if (!syserror(tcp) && !umove(tcp, arg, &f)) {
445 void (*const prefix_fun)(void) =
446 is_get ? tprint_struct_next :
447 tprint_struct_end_value_changed_struct_begin;
448 print_v4l2_format_fmt(tcp, prefix_fun, &f);
449 }
450
451 tprint_struct_end();
452
453 return RVAL_IOCTL_DECODED;
454 }
455
456 #include "xlat/v4l2_memories.h"
457
458 static int
459 print_v4l2_requestbuffers(struct tcb *const tcp, const kernel_ulong_t arg)
460 {
461 struct v4l2_requestbuffers reqbufs;
462
463 if (entering(tcp)) {
464 tprint_arg_next();
465 if (umove_or_printaddr(tcp, arg, &reqbufs))
466 return RVAL_IOCTL_DECODED;
467
468 tprint_struct_begin();
469 PRINT_FIELD_XVAL(reqbufs, type, v4l2_buf_types,
470 "V4L2_BUF_TYPE_???");
471 tprint_struct_next();
472 PRINT_FIELD_XVAL(reqbufs, memory, v4l2_memories,
473 "V4L2_MEMORY_???");
474 tprint_struct_next();
475 PRINT_FIELD_U(reqbufs, count);
476
477 return 0;
478 }
479
480 if (!syserror(tcp) && !umove(tcp, arg, &reqbufs)) {
481 tprint_value_changed();
482 PRINT_VAL_U(reqbufs.count);
483 }
484
485 tprint_struct_end();
486
487 return RVAL_IOCTL_DECODED;
488 }
489
490 #include "xlat/v4l2_buf_flags.h"
491 #include "xlat/v4l2_buf_flags_ts_type.h"
492 #include "xlat/v4l2_buf_flags_ts_src.h"
493
494 static void
495 print_v4l2_buffer_flags(uint32_t val)
496 {
497 const uint32_t ts_type = val & V4L2_BUF_FLAG_TIMESTAMP_MASK;
498 const uint32_t ts_src = val & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
499 const uint32_t flags = val & ~ts_type & ~ts_src;
500
501 if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW) {
502 PRINT_VAL_X(val);
503 return;
504 }
505
506 tprint_flags_begin();
507 if (flags) {
508 printflags_in(v4l2_buf_flags, flags, "V4L2_BUF_FLAG_???");
509 tprint_flags_or();
510 }
511 printxval(v4l2_buf_flags_ts_type, ts_type,
512 "V4L2_BUF_FLAG_TIMESTAMP_???");
513 tprint_flags_or();
514 printxval(v4l2_buf_flags_ts_src, ts_src,
515 "V4L2_BUF_FLAG_TSTAMP_SRC_???");
516 tprint_flags_end();
517 }
518
519 #define PRINT_FIELD_V4L2_BUFFER_FLAGS(where_, field_) \
520 do { \
521 tprints_field_name(#field_); \
522 print_v4l2_buffer_flags((where_).field_); \
523 } while (0)
524
525 static void
526 print_v4l2_timeval(const MPERS_PTR_ARG(kernel_v4l2_timeval_t *) const arg)
527 {
528 const kernel_v4l2_timeval_t *const t = arg;
529 kernel_timeval64_t tv;
530
531 if (sizeof(tv.tv_sec) == sizeof(t->tv_sec) &&
532 sizeof(tv.tv_usec) == sizeof(t->tv_usec)) {
533 print_timeval64_data_size(t, sizeof(*t));
534 } else {
535 tv.tv_sec = sign_extend_unsigned_to_ll(t->tv_sec);
536 tv.tv_usec = zero_extend_signed_to_ull(t->tv_usec);
537 print_timeval64_data_size(&tv, sizeof(tv));
538 }
539 }
540
541 #define PRINT_FIELD_V4L2_TIMEVAL(where_, field_) \
542 do { \
543 tprints_field_name(#field_); \
544 print_v4l2_timeval(&((where_).field_)); \
545 } while (0)
546
547 static int
548 print_v4l2_buffer(struct tcb *const tcp, const unsigned int code,
549 const kernel_ulong_t arg)
550 {
551 kernel_v4l2_buffer_t b;
552
553 if (entering(tcp)) {
554 tprint_arg_next();
555 if (umove_or_printaddr(tcp, arg, &b))
556 return RVAL_IOCTL_DECODED;
557
558 tprint_struct_begin();
559 PRINT_FIELD_XVAL(b, type, v4l2_buf_types,
560 "V4L2_BUF_TYPE_???");
561 if (code != VIDIOC_DQBUF) {
562 tprint_struct_next();
563 PRINT_FIELD_U(b, index);
564 }
565
566 return 0;
567 }
568
569 if (!syserror(tcp) && !umove(tcp, arg, &b)) {
570 if (code == VIDIOC_DQBUF) {
571 tprint_struct_next();
572 PRINT_FIELD_U(b, index);
573 }
574 tprint_struct_next();
575 PRINT_FIELD_XVAL(b, memory, v4l2_memories,
576 "V4L2_MEMORY_???");
577
578 if (b.memory == V4L2_MEMORY_MMAP) {
579 tprint_struct_next();
580 PRINT_FIELD_X(b, m.offset);
581 } else if (b.memory == V4L2_MEMORY_USERPTR) {
582 tprint_struct_next();
583 PRINT_FIELD_PTR(b, m.userptr);
584 }
585
586 tprint_struct_next();
587 PRINT_FIELD_U(b, length);
588 tprint_struct_next();
589 PRINT_FIELD_U(b, bytesused);
590 tprint_struct_next();
591 PRINT_FIELD_V4L2_BUFFER_FLAGS(b, flags);
592 if (code == VIDIOC_DQBUF) {
593 tprint_struct_next();
594 PRINT_FIELD_V4L2_TIMEVAL(b, timestamp);
595 }
596 tprint_struct_next();
597 tprint_more_data_follows();
598 }
599
600 tprint_struct_end();
601
602 return RVAL_IOCTL_DECODED;
603 }
604
605 static int
606 print_v4l2_framebuffer(struct tcb *const tcp, const kernel_ulong_t arg)
607 {
608 struct_v4l2_framebuffer b;
609
610 tprint_arg_next();
611 if (!umove_or_printaddr(tcp, arg, &b)) {
612 tprint_struct_begin();
613 PRINT_FIELD_X(b, capability);
614 tprint_struct_next();
615 PRINT_FIELD_X(b, flags);
616 tprint_struct_next();
617 PRINT_FIELD_PTR(b, base);
618 tprint_struct_end();
619 }
620
621 return RVAL_IOCTL_DECODED;
622 }
623
624 static int
625 print_v4l2_buf_type(struct tcb *const tcp, const kernel_ulong_t arg)
626 {
627 int type;
628
629 tprint_arg_next();
630 if (!umove_or_printaddr(tcp, arg, &type)) {
631 tprint_indirect_begin();
632 printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
633 tprint_indirect_end();
634 }
635 return RVAL_IOCTL_DECODED;
636 }
637
638 #include "xlat/v4l2_streaming_capabilities.h"
639 #include "xlat/v4l2_capture_modes.h"
640
641 static void
642 print_v4l2_streamparm_capture(const struct v4l2_captureparm *const p)
643 {
644 tprint_struct_begin();
645 PRINT_FIELD_FLAGS(*p, capability, v4l2_streaming_capabilities,
646 "V4L2_CAP_???");
647 tprint_struct_next();
648 PRINT_FIELD_FLAGS(*p, capturemode, v4l2_capture_modes,
649 "V4L2_MODE_???");
650 tprint_struct_next();
651 PRINT_FIELD_FRACT(*p, timeperframe);
652 tprint_struct_next();
653 PRINT_FIELD_X(*p, extendedmode);
654 tprint_struct_next();
655 PRINT_FIELD_U(*p, readbuffers);
656 tprint_struct_end();
657 }
658
659 static void
660 print_v4l2_streamparm_output(const struct v4l2_outputparm *const p)
661 {
662 tprint_struct_begin();
663 PRINT_FIELD_FLAGS(*p, capability, v4l2_streaming_capabilities,
664 "V4L2_CAP_???");
665 tprint_struct_next();
666 PRINT_FIELD_FLAGS(*p, outputmode, v4l2_capture_modes,
667 "V4L2_MODE_???");
668 tprint_struct_next();
669 PRINT_FIELD_FRACT(*p, timeperframe);
670 tprint_struct_next();
671 PRINT_FIELD_X(*p, extendedmode);
672 tprint_struct_next();
673 PRINT_FIELD_U(*p, writebuffers);
674 tprint_struct_end();
675 }
676
677 #define PRINT_FIELD_V4L2_STREAMPARM_PARM(where_, parm_, field_) \
678 do { \
679 tprints_field_name(#parm_ "." #field_); \
680 print_v4l2_streamparm_ ## field_(&((where_).parm_.field_)); \
681 } while (0)
682
683 static int
684 print_v4l2_streamparm(struct tcb *const tcp, const kernel_ulong_t arg,
685 const bool is_get)
686 {
687 struct v4l2_streamparm s;
688
689 if (entering(tcp)) {
690 tprint_arg_next();
691 if (umove_or_printaddr(tcp, arg, &s))
692 return RVAL_IOCTL_DECODED;
693
694 tprint_struct_begin();
695 PRINT_FIELD_XVAL(s, type, v4l2_buf_types,
696 "V4L2_BUF_TYPE_???");
697 switch (s.type) {
698 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
699 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
700 if (is_get)
701 return 0;
702 tprint_struct_next();
703 break;
704 default:
705 tprint_struct_end();
706 return RVAL_IOCTL_DECODED;
707 }
708 } else {
709 if (syserror(tcp) || umove(tcp, arg, &s) < 0) {
710 tprint_struct_end();
711 return RVAL_IOCTL_DECODED;
712 }
713 if (is_get) {
714 tprint_struct_next();
715 } else {
716 tprint_struct_end();
717 tprint_value_changed();
718 tprint_struct_begin();
719 }
720 }
721
722 if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
723 PRINT_FIELD_V4L2_STREAMPARM_PARM(s, parm, capture);
724 } else {
725 PRINT_FIELD_V4L2_STREAMPARM_PARM(s, parm, output);
726 }
727
728 if (entering(tcp)) {
729 return 0;
730 } else {
731 tprint_struct_end();
732 return RVAL_IOCTL_DECODED;
733 }
734 }
735
736 static int
737 print_v4l2_standard(struct tcb *const tcp, const kernel_ulong_t arg)
738 {
739 struct_v4l2_standard s;
740
741 if (entering(tcp)) {
742 tprint_arg_next();
743 if (umove_or_printaddr(tcp, arg, &s))
744 return RVAL_IOCTL_DECODED;
745
746 tprint_struct_begin();
747 PRINT_FIELD_U(s, index);
748
749 return 0;
750 }
751
752 if (!syserror(tcp) && !umove(tcp, arg, &s)) {
753 tprint_struct_next();
754 PRINT_FIELD_CSTRING(s, name);
755 tprint_struct_next();
756 PRINT_FIELD_FRACT(s, frameperiod);
757 tprint_struct_next();
758 PRINT_FIELD_U(s, framelines);
759 }
760
761 tprint_struct_end();
762
763 return RVAL_IOCTL_DECODED;
764 }
765
766 #include "xlat/v4l2_input_capabilities_flags.h"
767 #include "xlat/v4l2_input_status_flags.h"
768 #include "xlat/v4l2_input_types.h"
769 #include "xlat/v4l2_std_ids.h"
770
771 static int
772 print_v4l2_input(struct tcb *const tcp, const kernel_ulong_t arg)
773 {
774 struct_v4l2_input i;
775
776 if (entering(tcp)) {
777 tprint_arg_next();
778 if (umove_or_printaddr(tcp, arg, &i))
779 return RVAL_IOCTL_DECODED;
780
781 tprint_struct_begin();
782 PRINT_FIELD_U(i, index);
783
784 return 0;
785 }
786
787 if (!syserror(tcp) && !umove(tcp, arg, &i)) {
788 tprint_struct_next();
789 PRINT_FIELD_CSTRING(i, name);
790 tprint_struct_next();
791 PRINT_FIELD_XVAL(i, type, v4l2_input_types,
792 "V4L2_INPUT_TYPE_???");
793 tprint_struct_next();
794 PRINT_FIELD_X(i, audioset);
795 tprint_struct_next();
796 PRINT_FIELD_U(i, tuner);
797 tprint_struct_next();
798 PRINT_FIELD_FLAGS(i, std, v4l2_std_ids, "V4L2_STD_???");
799 tprint_struct_next();
800 PRINT_FIELD_FLAGS(i, status, v4l2_input_status_flags,
801 "V4L2_IN_ST_???");
802 tprint_struct_next();
803 PRINT_FIELD_FLAGS(i, capabilities,
804 v4l2_input_capabilities_flags,
805 "V4L2_IN_CAP_???");
806 }
807
808 tprint_struct_end();
809
810 return RVAL_IOCTL_DECODED;
811 }
812
813 /*
814 * We include it here and not before print_v4l2_ext_controls as we need
815 * V4L2_CTRL_CLASS_* definitions for V4L2_CID_*_BASE ones.
816 */
817 #include "xlat/v4l2_control_classes.h"
818 #include "xlat/v4l2_control_id_bases.h"
819 #include "xlat/v4l2_control_ids.h"
820 #include "xlat/v4l2_control_query_flags.h"
821
822 static void
823 print_v4l2_cid(uint32_t cid, bool next_flags)
824 {
825 if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW) {
826 PRINT_VAL_X(cid);
827 return;
828 }
829
830 tprint_flags_begin();
831 if (next_flags) {
832 uint32_t flags = cid & v4l2_control_query_flags->flags_mask;
833
834 if (flags) {
835 printflags_in(v4l2_control_query_flags, flags,
836 "V4L2_CTRL_FLAG_NEXT_???");
837 tprint_flags_or();
838 cid &= ~flags;
839 }
840 }
841
842 const char *id_name = xlookup(v4l2_control_ids, cid);
843
844 if (id_name) {
845 print_xlat_ex(cid, id_name, XLAT_STYLE_DEFAULT);
846 tprint_flags_end();
847 return;
848 }
849
850 uint64_t class_id = cid;
851 const char *class_str = xlookup_le(v4l2_control_classes, &class_id);
852
853 if (!class_str || (cid - class_id) >= 0x10000) {
854 print_xlat_ex(cid, "V4L2_CID_???", PXF_DEFAULT_STR);
855 tprint_flags_end();
856 return;
857 }
858
859 /*
860 * As of now, the longest control class name is V4L2_CTRL_CLASS_IMAGE_SOURCE,
861 * of 28 characters long.
862 */
863 char tmp_str[64 + sizeof("+%#") + sizeof(class_id) * 2];
864
865 xsprintf(tmp_str, "%s+%#" PRIx64, class_str, cid - class_id);
866 print_xlat_ex(cid, tmp_str, XLAT_STYLE_DEFAULT);
867 tprint_flags_end();
868 }
869
870 #define PRINT_FIELD_V4L2_CID(where_, field_, next_) \
871 do { \
872 tprints_field_name(#field_); \
873 print_v4l2_cid((where_).field_, (next_)); \
874 } while (0)
875
876 static int
877 print_v4l2_control(struct tcb *const tcp, const kernel_ulong_t arg,
878 const bool is_get)
879 {
880 struct v4l2_control c;
881
882 if (entering(tcp)) {
883 tprint_arg_next();
884 if (umove_or_printaddr(tcp, arg, &c))
885 return RVAL_IOCTL_DECODED;
886
887 tprint_struct_begin();
888 PRINT_FIELD_V4L2_CID(c, id, false);
889 if (!is_get) {
890 tprint_struct_next();
891 PRINT_FIELD_D(c, value);
892 }
893 return 0;
894 }
895
896 if (!syserror(tcp) && !umove(tcp, arg, &c)) {
897 if (is_get) {
898 tprint_struct_next();
899 PRINT_FIELD_D(c, value);
900 } else {
901 tprint_value_changed();
902 PRINT_VAL_D(c.value);
903 }
904 }
905
906 tprint_struct_end();
907
908 return RVAL_IOCTL_DECODED;
909 }
910
911 #include "xlat/v4l2_tuner_types.h"
912 #include "xlat/v4l2_tuner_capabilities.h"
913 #include "xlat/v4l2_tuner_rxsubchanses.h"
914 #include "xlat/v4l2_tuner_audmodes.h"
915
916 static int
917 print_v4l2_tuner(struct tcb *const tcp, const kernel_ulong_t arg,
918 const bool is_get)
919 {
920 struct v4l2_tuner c;
921 if (entering(tcp)) {
922 tprint_arg_next();
923 if (umove_or_printaddr(tcp, arg, &c))
924 return RVAL_IOCTL_DECODED;
925
926 tprint_struct_begin();
927 PRINT_FIELD_U(c, index);
928 if (is_get)
929 return 0;
930 tprint_struct_next();
931 } else {
932 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
933 tprint_struct_end();
934 return RVAL_IOCTL_DECODED;
935 }
936 if (is_get) {
937 tprint_struct_next();
938 } else {
939 tprint_struct_end();
940 tprint_value_changed();
941 tprint_struct_begin();
942 }
943 }
944
945 PRINT_FIELD_CSTRING(c, name);
946 tprint_struct_next();
947 PRINT_FIELD_XVAL(c, type, v4l2_tuner_types, "V4L2_TUNER_???");
948 tprint_struct_next();
949 PRINT_FIELD_FLAGS(c, capability, v4l2_tuner_capabilities,
950 "V4L2_TUNER_CAP_???");
951 tprint_struct_next();
952 PRINT_FIELD_U(c, rangelow);
953 tprint_struct_next();
954 PRINT_FIELD_U(c, rangehigh);
955 tprint_struct_next();
956 PRINT_FIELD_FLAGS(c, rxsubchans, v4l2_tuner_rxsubchanses,
957 "V4L2_TUNER_SUB_???");
958 tprint_struct_next();
959 PRINT_FIELD_XVAL(c, audmode, v4l2_tuner_audmodes,
960 "V4L2_TUNER_MODE_???");
961 tprint_struct_next();
962 PRINT_FIELD_D(c, signal);
963 tprint_struct_next();
964 PRINT_FIELD_D(c, afc);
965
966 if (entering(tcp)) {
967 return 0;
968 } else {
969 tprint_struct_end();
970 return RVAL_IOCTL_DECODED;
971 }
972 }
973
974 #include "xlat/v4l2_control_types.h"
975 #include "xlat/v4l2_control_flags.h"
976
977 static int
978 print_v4l2_queryctrl(struct tcb *const tcp, const kernel_ulong_t arg)
979 {
980 struct v4l2_queryctrl c;
981
982 if (entering(tcp)) {
983 tprint_arg_next();
984 if (umove_or_printaddr(tcp, arg, &c))
985 return RVAL_IOCTL_DECODED;
986
987 set_tcb_priv_ulong(tcp, c.id);
988 tprint_struct_begin();
989 PRINT_FIELD_V4L2_CID(c, id, true);
990
991 return 0;
992 }
993
994 /* exiting */
995 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
996 tprint_struct_end();
997 return RVAL_IOCTL_DECODED;
998 }
999
1000 unsigned long entry_id = get_tcb_priv_ulong(tcp);
1001
1002 if (c.id != entry_id) {
1003 tprint_value_changed();
1004 print_v4l2_cid(c.id, false);
1005 }
1006
1007 tprint_struct_next();
1008 PRINT_FIELD_XVAL(c, type, v4l2_control_types,
1009 "V4L2_CTRL_TYPE_???");
1010 tprint_struct_next();
1011 PRINT_FIELD_CSTRING(c, name);
1012 if (!abbrev(tcp)) {
1013 tprint_struct_next();
1014 PRINT_FIELD_D(c, minimum);
1015 tprint_struct_next();
1016 PRINT_FIELD_D(c, maximum);
1017 tprint_struct_next();
1018 PRINT_FIELD_D(c, step);
1019 tprint_struct_next();
1020 PRINT_FIELD_D(c, default_value);
1021 tprint_struct_next();
1022 PRINT_FIELD_FLAGS(c, flags, v4l2_control_flags,
1023 "V4L2_CTRL_FLAG_???");
1024 if (!IS_ARRAY_ZERO(c.reserved)) {
1025 tprint_struct_next();
1026 PRINT_FIELD_ARRAY(c, reserved, tcp,
1027 print_xint_array_member);
1028 }
1029 } else {
1030 tprint_struct_next();
1031 tprint_more_data_follows();
1032 }
1033 tprint_struct_end();
1034
1035 return RVAL_IOCTL_DECODED;
1036 }
1037
1038 static int
1039 print_v4l2_query_ext_ctrl(struct tcb *const tcp, const kernel_ulong_t arg)
1040 {
1041 struct v4l2_query_ext_ctrl c;
1042
1043 if (entering(tcp)) {
1044 tprint_arg_next();
1045 if (umove_or_printaddr(tcp, arg, &c))
1046 return RVAL_IOCTL_DECODED;
1047
1048 set_tcb_priv_ulong(tcp, c.id);
1049 tprint_struct_begin();
1050 PRINT_FIELD_V4L2_CID(c, id, true);
1051
1052 return 0;
1053 }
1054
1055 /* exiting */
1056 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
1057 tprint_struct_end();
1058 return RVAL_IOCTL_DECODED;
1059 }
1060
1061 unsigned long entry_id = get_tcb_priv_ulong(tcp);
1062
1063 if (c.id != entry_id) {
1064 tprint_value_changed();
1065 print_v4l2_cid(c.id, false);
1066 }
1067
1068 tprint_struct_next();
1069 PRINT_FIELD_XVAL(c, type, v4l2_control_types,
1070 "V4L2_CTRL_TYPE_???");
1071 tprint_struct_next();
1072 PRINT_FIELD_CSTRING(c, name);
1073 if (!abbrev(tcp)) {
1074 tprint_struct_next();
1075 PRINT_FIELD_D(c, minimum);
1076 tprint_struct_next();
1077 PRINT_FIELD_D(c, maximum);
1078 tprint_struct_next();
1079 PRINT_FIELD_U(c, step);
1080 tprint_struct_next();
1081 PRINT_FIELD_D(c, default_value);
1082 tprint_struct_next();
1083 PRINT_FIELD_FLAGS(c, flags, v4l2_control_flags,
1084 "V4L2_CTRL_FLAG_???");
1085 tprint_struct_next();
1086 PRINT_FIELD_U(c, elem_size);
1087 tprint_struct_next();
1088 PRINT_FIELD_U(c, elems);
1089 tprint_struct_next();
1090 PRINT_FIELD_U(c, nr_of_dims);
1091 tprint_struct_next();
1092 PRINT_FIELD_ARRAY_UPTO(c, dims, c.nr_of_dims, tcp,
1093 print_uint_array_member);
1094 if (!IS_ARRAY_ZERO(c.reserved)) {
1095 tprint_struct_next();
1096 PRINT_FIELD_ARRAY(c, reserved, tcp,
1097 print_xint_array_member);
1098 }
1099 } else {
1100 tprint_struct_next();
1101 tprint_more_data_follows();
1102 }
1103 tprint_struct_end();
1104
1105 return RVAL_IOCTL_DECODED;
1106 }
1107
1108 static int
1109 print_v4l2_cropcap(struct tcb *const tcp, const kernel_ulong_t arg)
1110 {
1111 struct v4l2_cropcap c;
1112
1113 if (entering(tcp)) {
1114 tprint_arg_next();
1115 if (umove_or_printaddr(tcp, arg, &c))
1116 return RVAL_IOCTL_DECODED;
1117
1118 tprint_struct_begin();
1119 PRINT_FIELD_XVAL(c, type, v4l2_buf_types,
1120 "V4L2_BUF_TYPE_???");
1121
1122 return 0;
1123 }
1124
1125 if (!syserror(tcp) && !umove(tcp, arg, &c)) {
1126 tprint_struct_next();
1127 PRINT_FIELD_OBJ_PTR(c, bounds, print_v4l2_rect);
1128 tprint_struct_next();
1129 PRINT_FIELD_OBJ_PTR(c, defrect, print_v4l2_rect);
1130 tprint_struct_next();
1131 PRINT_FIELD_FRACT(c, pixelaspect);
1132 }
1133
1134 tprint_struct_end();
1135
1136 return RVAL_IOCTL_DECODED;
1137 }
1138
1139 static int
1140 print_v4l2_crop(struct tcb *const tcp, const kernel_ulong_t arg,
1141 const bool is_get)
1142 {
1143 struct v4l2_crop c;
1144
1145 if (entering(tcp)) {
1146 tprint_arg_next();
1147 if (umove_or_printaddr(tcp, arg, &c))
1148 return RVAL_IOCTL_DECODED;
1149
1150 tprint_struct_begin();
1151 PRINT_FIELD_XVAL(c, type, v4l2_buf_types,
1152 "V4L2_BUF_TYPE_???");
1153 if (is_get)
1154 return 0;
1155 tprint_struct_next();
1156 PRINT_FIELD_OBJ_PTR(c, c, print_v4l2_rect);
1157 } else {
1158 if (!syserror(tcp) && !umove(tcp, arg, &c)) {
1159 tprint_struct_next();
1160 PRINT_FIELD_OBJ_PTR(c, c, print_v4l2_rect);
1161 }
1162 }
1163
1164 tprint_struct_end();
1165
1166 return RVAL_IOCTL_DECODED;
1167 }
1168
1169 static bool
1170 print_v4l2_ext_control(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
1171 {
1172 const struct_v4l2_ext_control *p = elem_buf;
1173
1174 tprint_struct_begin();
1175 PRINT_FIELD_XVAL(*p, id, v4l2_control_ids, "V4L2_CID_???");
1176 tprint_struct_next();
1177 PRINT_FIELD_U(*p, size);
1178 if (p->size > 0) {
1179 tprint_struct_next();
1180 tprints_field_name("string");
1181 printstrn(tcp, ptr_to_kulong(p->string), p->size);
1182 } else {
1183 tprint_struct_next();
1184 PRINT_FIELD_D(*p, value);
1185 tprint_struct_next();
1186 PRINT_FIELD_D(*p, value64);
1187 }
1188 tprint_struct_end();
1189
1190 return true;
1191 }
1192
1193 static int
1194 print_v4l2_ext_controls(struct tcb *const tcp, const kernel_ulong_t arg,
1195 const bool is_get)
1196 {
1197 struct_v4l2_ext_controls c;
1198
1199 if (entering(tcp)) {
1200 tprint_arg_next();
1201 if (umove_or_printaddr(tcp, arg, &c))
1202 return RVAL_IOCTL_DECODED;
1203
1204 tprint_struct_begin();
1205 PRINT_FIELD_XVAL(c, ctrl_class, v4l2_control_classes,
1206 "V4L2_CTRL_CLASS_???");
1207 tprint_struct_next();
1208 PRINT_FIELD_U(c, count);
1209 if (!c.count) {
1210 tprint_struct_end();
1211 return RVAL_IOCTL_DECODED;
1212 }
1213 if (is_get)
1214 return 0;
1215 tprint_struct_next();
1216 } else {
1217 if (umove(tcp, arg, &c) < 0) {
1218 tprint_struct_end();
1219 return RVAL_IOCTL_DECODED;
1220 }
1221 if (is_get) {
1222 tprint_struct_next();
1223 } else {
1224 tprint_struct_end();
1225 tprint_value_changed();
1226 tprint_struct_begin();
1227 }
1228 }
1229
1230 tprints_field_name("controls");
1231 struct_v4l2_ext_control ctrl;
1232 bool fail = !print_array(tcp, ptr_to_kulong(c.controls), c.count,
1233 &ctrl, sizeof(ctrl),
1234 tfetch_mem_ignore_syserror,
1235 print_v4l2_ext_control, 0);
1236
1237 if (exiting(tcp) && syserror(tcp)) {
1238 tprint_struct_next();
1239 PRINT_FIELD_U(c, error_idx);
1240 }
1241
1242 if (exiting(tcp) || fail) {
1243 tprint_struct_end();
1244 return RVAL_IOCTL_DECODED;
1245 }
1246
1247 /* entering */
1248 return 0;
1249 }
1250
1251 #include "xlat/v4l2_framesize_types.h"
1252
1253 static void
1254 print_v4l2_frmsize_discrete(const struct v4l2_frmsize_discrete *const p)
1255 {
1256 tprint_struct_begin();
1257 PRINT_FIELD_U(*p, width);
1258 tprint_struct_next();
1259 PRINT_FIELD_U(*p, height);
1260 tprint_struct_end();
1261 }
1262
1263 static void
1264 print_v4l2_frmsize_stepwise(const struct v4l2_frmsize_stepwise *const p)
1265 {
1266 tprint_struct_begin();
1267 PRINT_FIELD_U(*p, min_width);
1268 tprint_struct_next();
1269 PRINT_FIELD_U(*p, max_width);
1270 tprint_struct_next();
1271 PRINT_FIELD_U(*p, step_width);
1272 tprint_struct_next();
1273 PRINT_FIELD_U(*p, min_height);
1274 tprint_struct_next();
1275 PRINT_FIELD_U(*p, max_height);
1276 tprint_struct_next();
1277 PRINT_FIELD_U(*p, step_height);
1278 tprint_struct_end();
1279 }
1280
1281 #define PRINT_FIELD_V4L2_FRMSIZE_TYPE(where_, field_) \
1282 do { \
1283 tprints_field_name(#field_); \
1284 print_v4l2_frmsize_ ## field_(&((where_).field_)); \
1285 } while (0)
1286
1287 static int
1288 print_v4l2_frmsizeenum(struct tcb *const tcp, const kernel_ulong_t arg)
1289 {
1290 struct v4l2_frmsizeenum s;
1291
1292 if (entering(tcp)) {
1293 tprint_arg_next();
1294 if (umove_or_printaddr(tcp, arg, &s))
1295 return RVAL_IOCTL_DECODED;
1296
1297 tprint_struct_begin();
1298 PRINT_FIELD_U(s, index);
1299 tprint_struct_next();
1300 PRINT_FIELD_PIXFMT(s, pixel_format, v4l2_pix_fmts);
1301 return 0;
1302 }
1303
1304 if (!syserror(tcp) && !umove(tcp, arg, &s)) {
1305 tprint_struct_next();
1306 PRINT_FIELD_XVAL(s, type, v4l2_framesize_types,
1307 "V4L2_FRMSIZE_TYPE_???");
1308 switch (s.type) {
1309 case V4L2_FRMSIZE_TYPE_DISCRETE:
1310 tprint_struct_next();
1311 PRINT_FIELD_V4L2_FRMSIZE_TYPE(s, discrete);
1312 break;
1313 case V4L2_FRMSIZE_TYPE_STEPWISE:
1314 tprint_struct_next();
1315 PRINT_FIELD_V4L2_FRMSIZE_TYPE(s, stepwise);
1316 break;
1317 }
1318 }
1319 tprint_struct_end();
1320 return RVAL_IOCTL_DECODED;
1321 }
1322
1323 #include "xlat/v4l2_frameinterval_types.h"
1324
1325 static void
1326 print_v4l2_frmival_stepwise(const struct v4l2_frmival_stepwise *const p)
1327 {
1328 tprint_struct_begin();
1329 PRINT_FIELD_FRACT(*p, min);
1330 tprint_struct_next();
1331 PRINT_FIELD_FRACT(*p, max);
1332 tprint_struct_next();
1333 PRINT_FIELD_FRACT(*p, step);
1334 tprint_struct_end();
1335 }
1336
1337 #define PRINT_FIELD_V4L2_FRMIVAL_STEPWISE(where_, field_) \
1338 do { \
1339 tprints_field_name(#field_); \
1340 print_v4l2_frmival_stepwise(&((where_).field_)); \
1341 } while (0)
1342
1343 static int
1344 print_v4l2_frmivalenum(struct tcb *const tcp, const kernel_ulong_t arg)
1345 {
1346 struct v4l2_frmivalenum f;
1347
1348 if (entering(tcp)) {
1349 tprint_arg_next();
1350 if (umove_or_printaddr(tcp, arg, &f))
1351 return RVAL_IOCTL_DECODED;
1352
1353 tprint_struct_begin();
1354 PRINT_FIELD_U(f, index);
1355 tprint_struct_next();
1356 PRINT_FIELD_PIXFMT(f, pixel_format, v4l2_pix_fmts);
1357 tprint_struct_next();
1358 PRINT_FIELD_U(f, width);
1359 tprint_struct_next();
1360 PRINT_FIELD_U(f, height);
1361 return 0;
1362 }
1363
1364 if (!syserror(tcp) && !umove(tcp, arg, &f)) {
1365 tprint_struct_next();
1366 PRINT_FIELD_XVAL(f, type, v4l2_frameinterval_types,
1367 "V4L2_FRMIVAL_TYPE_???");
1368 switch (f.type) {
1369 case V4L2_FRMIVAL_TYPE_DISCRETE:
1370 tprint_struct_next();
1371 PRINT_FIELD_FRACT(f, discrete);
1372 break;
1373 case V4L2_FRMIVAL_TYPE_STEPWISE:
1374 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
1375 tprint_struct_next();
1376 PRINT_FIELD_V4L2_FRMIVAL_STEPWISE(f, stepwise);
1377 break;
1378 }
1379 }
1380
1381 tprint_struct_end();
1382
1383 return RVAL_IOCTL_DECODED;
1384 }
1385
1386 static void
1387 print_v4l2_create_buffers_format(const typeof_field(struct_v4l2_create_buffers, format) *const p,
1388 struct tcb *const tcp)
1389 {
1390 tprint_struct_begin();
1391 PRINT_FIELD_XVAL(*p, type, v4l2_buf_types,
1392 "V4L2_BUF_TYPE_???");
1393 print_v4l2_format_fmt(tcp, tprint_struct_next,
1394 (const struct_v4l2_format *) p);
1395 tprint_struct_end();
1396 }
1397
1398 static int
1399 print_v4l2_create_buffers(struct tcb *const tcp, const kernel_ulong_t arg)
1400 {
1401 static const char fmt[] = "{index=%u, count=%u}";
1402 static char outstr[sizeof(fmt) + sizeof(int) * 6];
1403
1404 struct_v4l2_create_buffers b;
1405
1406 if (entering(tcp)) {
1407 tprint_arg_next();
1408 if (umove_or_printaddr(tcp, arg, &b))
1409 return RVAL_IOCTL_DECODED;
1410
1411 tprint_struct_begin();
1412 PRINT_FIELD_U(b, count);
1413 tprint_struct_next();
1414 PRINT_FIELD_XVAL(b, memory, v4l2_memories,
1415 "V4L2_MEMORY_???");
1416 tprint_struct_next();
1417 PRINT_FIELD_OBJ_PTR(b, format,
1418 print_v4l2_create_buffers_format, tcp);
1419 tprint_struct_end();
1420 return 0;
1421 }
1422
1423 if (syserror(tcp) || umove(tcp, arg, &b))
1424 return RVAL_IOCTL_DECODED;
1425
1426 xsprintf(outstr, fmt, b.index, b.count);
1427 tcp->auxstr = outstr;
1428
1429 return RVAL_IOCTL_DECODED | RVAL_STR;
1430 }
1431
1432 MPERS_PRINTER_DECL(int, v4l2_ioctl, struct tcb *const tcp,
1433 const unsigned int code, const kernel_ulong_t arg)
1434 {
1435 if (!verbose(tcp))
1436 return RVAL_DECODED;
1437
1438 switch (code) {
1439 case VIDIOC_QUERYCAP: /* R */
1440 return print_v4l2_capability(tcp, arg);
1441
1442 case VIDIOC_ENUM_FMT: /* RW */
1443 return print_v4l2_fmtdesc(tcp, arg);
1444
1445 case VIDIOC_G_FMT: /* RW */
1446 case VIDIOC_S_FMT: /* RW */
1447 case VIDIOC_TRY_FMT: /* RW */
1448 return print_v4l2_format(tcp, arg, code == VIDIOC_G_FMT);
1449
1450 case VIDIOC_REQBUFS: /* RW */
1451 return print_v4l2_requestbuffers(tcp, arg);
1452
1453 case VIDIOC_QUERYBUF: /* RW */
1454 case VIDIOC_QBUF: /* RW */
1455 case VIDIOC_DQBUF: /* RW */
1456 return print_v4l2_buffer(tcp, code, arg);
1457
1458 case VIDIOC_G_FBUF: /* R */
1459 if (entering(tcp))
1460 return 0;
1461 ATTRIBUTE_FALLTHROUGH;
1462 case VIDIOC_S_FBUF: /* W */
1463 return print_v4l2_framebuffer(tcp, arg);
1464
1465 case VIDIOC_STREAMON: /* W */
1466 case VIDIOC_STREAMOFF: /* W */
1467 return print_v4l2_buf_type(tcp, arg);
1468
1469 case VIDIOC_G_PARM: /* RW */
1470 case VIDIOC_S_PARM: /* RW */
1471 return print_v4l2_streamparm(tcp, arg, code == VIDIOC_G_PARM);
1472
1473 case VIDIOC_G_STD: /* R */
1474 if (entering(tcp))
1475 return 0;
1476 ATTRIBUTE_FALLTHROUGH;
1477 case VIDIOC_S_STD: /* W */
1478 tprint_arg_next();
1479 printnum_int64(tcp, arg, "%#" PRIx64);
1480 break;
1481
1482 case VIDIOC_ENUMSTD: /* RW */
1483 return print_v4l2_standard(tcp, arg);
1484
1485 case VIDIOC_ENUMINPUT: /* RW */
1486 return print_v4l2_input(tcp, arg);
1487
1488 case VIDIOC_G_CTRL: /* RW */
1489 case VIDIOC_S_CTRL: /* RW */
1490 return print_v4l2_control(tcp, arg, code == VIDIOC_G_CTRL);
1491
1492 case VIDIOC_G_TUNER: /* RW */
1493 case VIDIOC_S_TUNER: /* RW */
1494 return print_v4l2_tuner(tcp, arg, code == VIDIOC_G_TUNER);
1495
1496 case VIDIOC_QUERYCTRL: /* RW */
1497 return print_v4l2_queryctrl(tcp, arg);
1498
1499 case VIDIOC_QUERY_EXT_CTRL: /* RW */
1500 return print_v4l2_query_ext_ctrl(tcp, arg);
1501
1502 case VIDIOC_G_INPUT: /* R */
1503 if (entering(tcp))
1504 return 0;
1505 ATTRIBUTE_FALLTHROUGH;
1506 case VIDIOC_S_INPUT: /* RW */
1507 tprint_arg_next();
1508 printnum_int(tcp, arg, "%u");
1509 break;
1510
1511 case VIDIOC_CROPCAP: /* RW */
1512 return print_v4l2_cropcap(tcp, arg);
1513
1514 case VIDIOC_G_CROP: /* RW */
1515 case VIDIOC_S_CROP: /* W */
1516 return print_v4l2_crop(tcp, arg, code == VIDIOC_G_CROP);
1517
1518 case VIDIOC_S_EXT_CTRLS: /* RW */
1519 case VIDIOC_TRY_EXT_CTRLS: /* RW */
1520 case VIDIOC_G_EXT_CTRLS: /* RW */
1521 return print_v4l2_ext_controls(tcp, arg,
1522 code == VIDIOC_G_EXT_CTRLS);
1523
1524 case VIDIOC_ENUM_FRAMESIZES: /* RW */
1525 return print_v4l2_frmsizeenum(tcp, arg);
1526
1527 case VIDIOC_ENUM_FRAMEINTERVALS: /* RW */
1528 return print_v4l2_frmivalenum(tcp, arg);
1529
1530 case VIDIOC_CREATE_BUFS: /* RW */
1531 return print_v4l2_create_buffers(tcp, arg);
1532
1533 default:
1534 return RVAL_DECODED;
1535 }
1536
1537 return RVAL_IOCTL_DECODED;
1538 }