]> granicus.if.org Git - strace/blob - v4l2.c
Update copyright headers
[strace] / v4l2.c
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-2019 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 <stdint.h>
14 #include <linux/ioctl.h>
15 #include <linux/types.h>
16 #include <linux/videodev2.h>
17
18 #include DEF_MPERS_TYPE(struct_v4l2_buffer)
19 #include DEF_MPERS_TYPE(struct_v4l2_clip)
20 #ifdef VIDIOC_CREATE_BUFS
21 # include DEF_MPERS_TYPE(struct_v4l2_create_buffers)
22 #endif
23 #include DEF_MPERS_TYPE(struct_v4l2_ext_control)
24 #include DEF_MPERS_TYPE(struct_v4l2_ext_controls)
25 #include DEF_MPERS_TYPE(struct_v4l2_format)
26 #include DEF_MPERS_TYPE(struct_v4l2_framebuffer)
27 #include DEF_MPERS_TYPE(struct_v4l2_input)
28 #include DEF_MPERS_TYPE(struct_v4l2_standard)
29
30 typedef struct v4l2_buffer struct_v4l2_buffer;
31 typedef struct v4l2_clip struct_v4l2_clip;
32 #ifdef VIDIOC_CREATE_BUFS
33 typedef struct v4l2_create_buffers struct_v4l2_create_buffers;
34 #endif
35 typedef struct v4l2_ext_control struct_v4l2_ext_control;
36 typedef struct v4l2_ext_controls struct_v4l2_ext_controls;
37 typedef struct v4l2_format struct_v4l2_format;
38 typedef struct v4l2_framebuffer struct_v4l2_framebuffer;
39 typedef struct v4l2_input struct_v4l2_input;
40 typedef struct v4l2_standard struct_v4l2_standard;
41
42 #include MPERS_DEFS
43
44 #include "print_fields.h"
45 #include "print_utils.h"
46 #include "xstring.h"
47
48 /* v4l2_fourcc_be was added by Linux commit v3.18-rc1~101^2^2~127 */
49 #ifndef v4l2_fourcc_be
50 # define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1 << 31))
51 #endif
52
53 #define FMT_FRACT "%u/%u"
54 #define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
55
56 #define FMT_RECT "{left=%d, top=%d, width=%u, height=%u}"
57 #define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
58
59 #include "xlat/v4l2_pix_fmts.h"
60 #include "xlat/v4l2_sdr_fmts.h"
61
62 static void
63 print_pixelformat(uint32_t fourcc, const struct xlat *xlat)
64 {
65         unsigned char a[] = {
66                 (unsigned char) fourcc,
67                 (unsigned char) (fourcc >> 8),
68                 (unsigned char) (fourcc >> 16),
69                 (unsigned char) (fourcc >> 24),
70         };
71         unsigned int i;
72
73         tprints("v4l2_fourcc(");
74         /* Generic char array printing routine.  */
75         for (i = 0; i < ARRAY_SIZE(a); ++i) {
76                 unsigned char c = a[i];
77
78                 if (i)
79                         tprints(", ");
80                 if (c == '\'' || c == '\\') {
81                         char sym[] = {
82                                 '\'',
83                                 '\\',
84                                 c,
85                                 '\'',
86                                 '\0'
87                         };
88                         tprints(sym);
89                 } else if (is_print(c)) {
90                         char sym[] = {
91                                 '\'',
92                                 c,
93                                 '\'',
94                                 '\0'
95                         };
96                         tprints(sym);
97                 } else {
98                         char hex[] = {
99                                 BYTE_HEX_CHARS_PRINTF_QUOTED(c),
100                                 '\0'
101                         };
102                         tprints(hex);
103                 }
104         }
105         tprints(")");
106
107         if (xlat) {
108                 const char *pixfmt_name = xlookup(xlat, fourcc);
109
110                 if (pixfmt_name)
111                         tprints_comment(pixfmt_name);
112         }
113 }
114
115 #include "xlat/v4l2_device_capabilities_flags.h"
116
117 static int
118 print_v4l2_capability(struct tcb *const tcp, const kernel_ulong_t arg)
119 {
120         struct v4l2_capability caps;
121
122         if (entering(tcp))
123                 return 0;
124         tprints(", ");
125         if (umove_or_printaddr(tcp, arg, &caps))
126                 return RVAL_IOCTL_DECODED;
127         PRINT_FIELD_CSTRING("{", caps, driver);
128         PRINT_FIELD_CSTRING(", ", caps, card);
129         PRINT_FIELD_CSTRING(", ", caps, bus_info);
130         tprintf(", version=%u.%u.%u, capabilities=",
131                 (caps.version >> 16) & 0xFF,
132                 (caps.version >> 8) & 0xFF,
133                 caps.version & 0xFF);
134         printflags(v4l2_device_capabilities_flags, caps.capabilities,
135                    "V4L2_CAP_???");
136 #ifdef V4L2_CAP_DEVICE_CAPS
137         tprints(", device_caps=");
138         printflags(v4l2_device_capabilities_flags, caps.device_caps,
139                    "V4L2_CAP_???");
140 #endif
141         tprints("}");
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                 tprints(", ");
155                 if (umove_or_printaddr(tcp, arg, &f))
156                         return RVAL_IOCTL_DECODED;
157                 tprintf("{index=%u, type=", f.index);
158                 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
159                 return 0;
160         }
161
162         if (!syserror(tcp) && !umove(tcp, arg, &f)) {
163                 tprints(", flags=");
164                 printflags(v4l2_format_description_flags, f.flags,
165                            "V4L2_FMT_FLAG_???");
166                 PRINT_FIELD_CSTRING(", ", f, description);
167                 tprints(", pixelformat=");
168                 print_pixelformat(f.pixelformat, v4l2_pix_fmts);
169         }
170         tprints("}");
171         return RVAL_IOCTL_DECODED;
172 }
173
174 #include "xlat/v4l2_fields.h"
175 #include "xlat/v4l2_colorspaces.h"
176 #include "xlat/v4l2_vbi_flags.h"
177 #include "xlat/v4l2_sliced_flags.h"
178
179 static bool
180 print_v4l2_clip(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
181 {
182         const struct_v4l2_clip *p = elem_buf;
183         tprintf(FMT_RECT, ARGS_RECT(p->c));
184         return true;
185 }
186
187 static bool
188 print_v4l2_format_fmt(struct tcb *const tcp, const char *prefix,
189                       const struct_v4l2_format *f)
190 {
191         bool ret = true;
192         switch (f->type) {
193         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
194         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
195                 tprints(prefix);
196                 tprintf("fmt.pix={width=%u, height=%u, pixelformat=",
197                         f->fmt.pix.width, f->fmt.pix.height);
198                 print_pixelformat(f->fmt.pix.pixelformat, v4l2_pix_fmts);
199                 tprints(", field=");
200                 printxval(v4l2_fields, f->fmt.pix.field, "V4L2_FIELD_???");
201                 tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
202                         f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
203                 printxval(v4l2_colorspaces, f->fmt.pix.colorspace,
204                           "V4L2_COLORSPACE_???");
205                 tprints("}");
206                 break;
207 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
208         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
209         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
210                 unsigned int i, max;
211
212                 tprints(prefix);
213                 tprintf("fmt.pix_mp={width=%u, height=%u, pixelformat=",
214                         f->fmt.pix_mp.width, f->fmt.pix_mp.height);
215                 print_pixelformat(f->fmt.pix_mp.pixelformat, v4l2_pix_fmts);
216                 tprints(", field=");
217                 printxval(v4l2_fields, f->fmt.pix_mp.field, "V4L2_FIELD_???");
218                 tprints(", colorspace=");
219                 printxval(v4l2_colorspaces, f->fmt.pix_mp.colorspace,
220                           "V4L2_COLORSPACE_???");
221                 tprints(", plane_fmt=[");
222                 max = f->fmt.pix_mp.num_planes;
223                 if (max > VIDEO_MAX_PLANES)
224                         max = VIDEO_MAX_PLANES;
225                 for (i = 0; i < max; i++) {
226                         if (i > 0)
227                                 tprints(", ");
228                         tprintf("{sizeimage=%u, bytesperline=%u}",
229                                 f->fmt.pix_mp.plane_fmt[i].sizeimage,
230                                 f->fmt.pix_mp.plane_fmt[i].bytesperline);
231                 }
232                 tprintf("], num_planes=%u}",
233                         (unsigned) f->fmt.pix_mp.num_planes);
234                 break;
235         }
236 #endif
237         /* OUTPUT_OVERLAY since Linux v2.6.22-rc1~1118^2~179 */
238 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
239         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
240 #endif
241         case V4L2_BUF_TYPE_VIDEO_OVERLAY: {
242                 struct_v4l2_clip clip;
243                 tprints(prefix);
244                 tprintf("fmt.win={left=%d, top=%d, width=%u, height=%u, field=",
245                         ARGS_RECT(f->fmt.win.w));
246                 printxval(v4l2_fields, f->fmt.win.field, "V4L2_FIELD_???");
247                 tprintf(", chromakey=%#x, clips=", f->fmt.win.chromakey);
248                 ret = print_array(tcp, ptr_to_kulong(f->fmt.win.clips),
249                                   f->fmt.win.clipcount, &clip, sizeof(clip),
250                                   tfetch_mem, print_v4l2_clip, 0);
251                 tprintf(", clipcount=%u, bitmap=", f->fmt.win.clipcount);
252                 printaddr(ptr_to_kulong(f->fmt.win.bitmap));
253 #ifdef HAVE_STRUCT_V4L2_WINDOW_GLOBAL_ALPHA
254                 tprintf(", global_alpha=%#x", f->fmt.win.global_alpha);
255 #endif
256                 tprints("}");
257                 break;
258         }
259         case V4L2_BUF_TYPE_VBI_CAPTURE:
260         case V4L2_BUF_TYPE_VBI_OUTPUT:
261                 tprints(prefix);
262                 tprintf("fmt.vbi={sampling_rate=%u, offset=%u, "
263                         "samples_per_line=%u, sample_format=",
264                         f->fmt.vbi.sampling_rate, f->fmt.vbi.offset,
265                         f->fmt.vbi.samples_per_line);
266                 print_pixelformat(f->fmt.vbi.sample_format, v4l2_pix_fmts);
267                 tprintf(", start=[%u, %u], count=[%u, %u], ",
268                         f->fmt.vbi.start[0], f->fmt.vbi.start[1],
269                         f->fmt.vbi.count[0], f->fmt.vbi.count[1]);
270                 tprints("flags=");
271                 printxval(v4l2_vbi_flags, f->fmt.vbi.flags, "V4L2_VBI_???");
272                 tprints("}");
273                 break;
274         /* both since Linux v2.6.14-rc2~64 */
275 #if HAVE_DECL_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
276         case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
277         case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: {
278                 unsigned int i, j;
279
280                 tprints(prefix);
281                 tprints("fmt.sliced={service_set=");
282                 printxval(v4l2_sliced_flags, f->fmt.sliced.service_set,
283                         "V4L2_SLICED_???");
284                 tprintf(", io_size=%u, service_lines=[",
285                         f->fmt.sliced.io_size);
286                 for (i = 0; i < ARRAY_SIZE(f->fmt.sliced.service_lines); i++) {
287                         if (i > 0)
288                                 tprints(", ");
289                         tprints("[");
290                         for (j = 0;
291                              j < ARRAY_SIZE(f->fmt.sliced.service_lines[0]);
292                              j++) {
293                                 if (j > 0)
294                                         tprints(", ");
295                                 tprintf("%#x",
296                                         f->fmt.sliced.service_lines[i][j]);
297                         }
298                         tprints("]");
299                 }
300                 tprints("]}");
301                 break;
302         }
303 #endif
304         /* since Linux v4.4-rc1~118^2~14 */
305 #if HAVE_DECL_V4L2_BUF_TYPE_SDR_OUTPUT
306         case V4L2_BUF_TYPE_SDR_OUTPUT:
307 #endif
308         /* since Linux v3.15-rc1~85^2~213 */
309 #if HAVE_DECL_V4L2_BUF_TYPE_SDR_CAPTURE
310         case V4L2_BUF_TYPE_SDR_CAPTURE:
311                 tprints(prefix);
312                 tprints("fmt.sdr={pixelformat=");
313                 print_pixelformat(f->fmt.sdr.pixelformat, v4l2_sdr_fmts);
314 # ifdef HAVE_STRUCT_V4L2_SDR_FORMAT_BUFFERSIZE
315                 tprintf(", buffersize=%u",
316                         f->fmt.sdr.buffersize);
317 # endif
318                 tprints("}");
319                 break;
320 #endif
321         }
322         return ret;
323 }
324
325 static int
326 print_v4l2_format(struct tcb *const tcp, const kernel_ulong_t arg,
327                   const bool is_get)
328 {
329         struct_v4l2_format f;
330
331         if (entering(tcp)) {
332                 tprints(", ");
333                 if (umove_or_printaddr(tcp, arg, &f))
334                         return RVAL_IOCTL_DECODED;
335                 tprints("{type=");
336                 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
337                 if (is_get)
338                         return 0;
339                 if (!print_v4l2_format_fmt(tcp, ", ", &f)) {
340                         tprints("}");
341                         return RVAL_IOCTL_DECODED;
342                 }
343
344                 return 0;
345         }
346
347         if (!syserror(tcp) && !umove(tcp, arg, &f))
348                 print_v4l2_format_fmt(tcp, is_get ? ", " : " => ", &f);
349
350         tprints("}");
351
352         return RVAL_IOCTL_DECODED;
353 }
354
355 #include "xlat/v4l2_memories.h"
356
357 static int
358 print_v4l2_requestbuffers(struct tcb *const tcp, const kernel_ulong_t arg)
359 {
360         struct v4l2_requestbuffers reqbufs;
361
362         if (entering(tcp)) {
363                 tprints(", ");
364
365                 if (umove_or_printaddr(tcp, arg, &reqbufs))
366                         return RVAL_IOCTL_DECODED;
367
368                 tprintf("{type=");
369                 printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
370                 tprints(", memory=");
371                 printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
372                 tprintf(", count=%u", reqbufs.count);
373
374                 return 0;
375         }
376
377         if (!syserror(tcp)) {
378                 tprints(" => ");
379
380                 if (!umove(tcp, arg, &reqbufs))
381                         tprintf("%u", reqbufs.count);
382                 else
383                         tprints("???");
384         }
385
386         tprints("}");
387
388         return RVAL_IOCTL_DECODED;
389 }
390
391 #include "xlat/v4l2_buf_flags.h"
392
393 static int
394 print_v4l2_buffer(struct tcb *const tcp, const unsigned int code,
395                   const kernel_ulong_t arg)
396 {
397         struct_v4l2_buffer b;
398
399         if (entering(tcp)) {
400                 tprints(", ");
401                 if (umove_or_printaddr(tcp, arg, &b))
402                         return RVAL_IOCTL_DECODED;
403                 tprints("{type=");
404                 printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???");
405                 if (code != VIDIOC_DQBUF)
406                         tprintf(", index=%u", b.index);
407
408                 return 0;
409         }
410
411         if (!syserror(tcp) && !umove(tcp, arg, &b)) {
412                 if (code == VIDIOC_DQBUF)
413                         tprintf(", index=%u", b.index);
414                 tprints(", memory=");
415                 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
416
417                 if (b.memory == V4L2_MEMORY_MMAP) {
418                         tprintf(", m.offset=%#x", b.m.offset);
419                 } else if (b.memory == V4L2_MEMORY_USERPTR) {
420                         tprints(", m.userptr=");
421                         printaddr(b.m.userptr);
422                 }
423
424                 tprintf(", length=%u, bytesused=%u, flags=",
425                         b.length, b.bytesused);
426                 printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???");
427                 if (code == VIDIOC_DQBUF) {
428                         tprints(", timestamp = ");
429                         MPERS_FUNC_NAME(print_struct_timeval)(&b.timestamp);
430                 }
431                 tprints(", ...");
432         }
433
434         tprints("}");
435
436         return RVAL_IOCTL_DECODED;
437 }
438
439 static int
440 print_v4l2_framebuffer(struct tcb *const tcp, const kernel_ulong_t arg)
441 {
442         struct_v4l2_framebuffer b;
443
444         tprints(", ");
445         if (!umove_or_printaddr(tcp, arg, &b)) {
446                 tprintf("{capability=%#x, flags=%#x, base=",
447                         b.capability, b.flags);
448                 printaddr(ptr_to_kulong(b.base));
449                 tprints("}");
450         }
451
452         return RVAL_IOCTL_DECODED;
453 }
454
455 static int
456 print_v4l2_buf_type(struct tcb *const tcp, const kernel_ulong_t arg)
457 {
458         int type;
459
460         tprints(", ");
461         if (!umove_or_printaddr(tcp, arg, &type)) {
462                 tprints("[");
463                 printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
464                 tprints("]");
465         }
466         return RVAL_IOCTL_DECODED;
467 }
468
469 #include "xlat/v4l2_streaming_capabilities.h"
470 #include "xlat/v4l2_capture_modes.h"
471
472 static int
473 print_v4l2_streamparm(struct tcb *const tcp, const kernel_ulong_t arg,
474                       const bool is_get)
475 {
476         struct v4l2_streamparm s;
477
478         if (entering(tcp)) {
479                 tprints(", ");
480                 if (umove_or_printaddr(tcp, arg, &s))
481                         return RVAL_IOCTL_DECODED;
482                 tprints("{type=");
483                 printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
484                 switch (s.type) {
485                         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
486                         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
487                                 if (is_get)
488                                         return 0;
489                                 tprints(", ");
490                                 break;
491                         default:
492                                 tprints("}");
493                                 return RVAL_IOCTL_DECODED;
494                 }
495         } else {
496                 if (syserror(tcp) || umove(tcp, arg, &s) < 0) {
497                         tprints("}");
498                         return RVAL_IOCTL_DECODED;
499                 }
500                 tprints(is_get ? ", " : " => ");
501         }
502
503         if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
504                 tprints("parm.capture={capability=");
505                 printflags(v4l2_streaming_capabilities,
506                            s.parm.capture.capability, "V4L2_CAP_???");
507
508                 tprints(", capturemode=");
509                 printflags(v4l2_capture_modes,
510                            s.parm.capture.capturemode, "V4L2_MODE_???");
511
512                 tprintf(", timeperframe=" FMT_FRACT,
513                         ARGS_FRACT(s.parm.capture.timeperframe));
514
515                 tprintf(", extendedmode=%u, readbuffers=%u}",
516                         s.parm.capture.extendedmode,
517                         s.parm.capture.readbuffers);
518         } else {
519                 tprints("parm.output={capability=");
520                 printflags(v4l2_streaming_capabilities,
521                            s.parm.output.capability, "V4L2_CAP_???");
522
523                 tprintf(", outputmode=%u", s.parm.output.outputmode);
524
525                 tprintf(", timeperframe=" FMT_FRACT,
526                         ARGS_FRACT(s.parm.output.timeperframe));
527
528                 tprintf(", extendedmode=%u, writebuffers=%u}",
529                         s.parm.output.extendedmode,
530                         s.parm.output.writebuffers);
531         }
532         if (entering(tcp)) {
533                 return 0;
534         } else {
535                 tprints("}");
536                 return RVAL_IOCTL_DECODED;
537         }
538 }
539
540 static int
541 print_v4l2_standard(struct tcb *const tcp, const kernel_ulong_t arg)
542 {
543         struct_v4l2_standard s;
544
545         if (entering(tcp)) {
546                 tprints(", ");
547                 if (umove_or_printaddr(tcp, arg, &s))
548                         return RVAL_IOCTL_DECODED;
549                 tprintf("{index=%u", s.index);
550
551                 return 0;
552         }
553
554         if (!syserror(tcp) && !umove(tcp, arg, &s)) {
555                 PRINT_FIELD_CSTRING(", ", s, name);
556                 tprintf(", frameperiod=" FMT_FRACT,
557                         ARGS_FRACT(s.frameperiod));
558                 tprintf(", framelines=%d", s.framelines);
559         }
560
561         tprints("}");
562
563         return RVAL_IOCTL_DECODED;
564 }
565
566 #include "xlat/v4l2_input_types.h"
567
568 static int
569 print_v4l2_input(struct tcb *const tcp, const kernel_ulong_t arg)
570 {
571         struct_v4l2_input i;
572
573         if (entering(tcp)) {
574                 tprints(", ");
575                 if (umove_or_printaddr(tcp, arg, &i))
576                         return RVAL_IOCTL_DECODED;
577                 tprintf("{index=%u", i.index);
578
579                 return 0;
580         }
581
582         if (!syserror(tcp) && !umove(tcp, arg, &i)) {
583                 PRINT_FIELD_CSTRING(", ", i, name);
584                 tprints(", type=");
585                 printxval(v4l2_input_types, i.type, "V4L2_INPUT_TYPE_???");
586         }
587
588         tprints("}");
589
590         return RVAL_IOCTL_DECODED;
591 }
592
593 /*
594  * We include it here and not before print_v4l2_ext_controls as we need
595  * V4L2_CTRL_CLASS_* definitions for V4L2_CID_*_BASE ones.
596  */
597 #include "xlat/v4l2_control_classes.h"
598 #include "xlat/v4l2_control_id_bases.h"
599 #include "xlat/v4l2_control_ids.h"
600
601 static int
602 print_v4l2_control(struct tcb *const tcp, const kernel_ulong_t arg,
603                    const bool is_get)
604 {
605         struct v4l2_control c;
606
607         if (entering(tcp)) {
608                 tprints(", ");
609                 if (umove_or_printaddr(tcp, arg, &c))
610                         return RVAL_IOCTL_DECODED;
611                 tprints("{id=");
612                 printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
613                 if (!is_get)
614                         tprintf(", value=%d", c.value);
615                 return 0;
616         }
617
618         if (!syserror(tcp) && !umove(tcp, arg, &c)) {
619                 tprints(is_get ? ", " : " => ");
620                 tprintf("value=%d", c.value);
621         }
622
623         tprints("}");
624
625         return RVAL_IOCTL_DECODED;
626 }
627
628 #include "xlat/v4l2_tuner_types.h"
629 #include "xlat/v4l2_tuner_capabilities.h"
630 #include "xlat/v4l2_tuner_rxsubchanses.h"
631 #include "xlat/v4l2_tuner_audmodes.h"
632
633 static int
634 print_v4l2_tuner(struct tcb *const tcp, const kernel_ulong_t arg,
635                  const bool is_get)
636 {
637         struct v4l2_tuner c;
638         if (entering(tcp)) {
639                 tprints(", ");
640                 if (umove_or_printaddr(tcp, arg, &c))
641                         return RVAL_IOCTL_DECODED;
642                 tprintf("{index=%u", c.index);
643                 if (is_get)
644                         return 0;
645                 tprints(", ");
646         } else {
647                 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
648                         tprints("}");
649                         return RVAL_IOCTL_DECODED;
650                 }
651                 tprints(is_get ? ", " : " => ");
652         }
653
654         PRINT_FIELD_CSTRING("", c, name);
655         tprints(", type=");
656         printxval(v4l2_tuner_types, c.type, "V4L2_TUNER_TYPE_???");
657         tprints(", capability=");
658         printxval(v4l2_tuner_capabilities, c.capability,
659                   "V4L2_TUNER_CAP_???");
660         tprintf(", rangelow=%u, rangehigh=%u, rxsubchans=",
661                 c.rangelow, c.rangehigh);
662         printxval(v4l2_tuner_rxsubchanses, c.rxsubchans,
663                   "V4L2_TUNER_SUB_???");
664         tprints(", audmode=");
665         printxval(v4l2_tuner_audmodes, c.audmode,
666                   "V4L2_TUNER_MODE_???");
667         tprintf(", signal=%d, afc=%d", c.signal, c.afc);
668
669         if (entering(tcp)) {
670                 return 0;
671         } else {
672                 tprints("}");
673                 return RVAL_IOCTL_DECODED;
674         }
675 }
676
677 #include "xlat/v4l2_control_types.h"
678 #include "xlat/v4l2_control_flags.h"
679
680 static int
681 print_v4l2_queryctrl(struct tcb *const tcp, const kernel_ulong_t arg)
682 {
683         struct v4l2_queryctrl c;
684
685         if (entering(tcp)) {
686                 tprints(", ");
687                 if (umove_or_printaddr(tcp, arg, &c))
688                         return RVAL_IOCTL_DECODED;
689                 tprints("{id=");
690         } else {
691                 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
692                         tprints("}");
693                         return RVAL_IOCTL_DECODED;
694                 }
695                 if (get_tcb_priv_ulong(tcp))
696                         tprints(" => ");
697         }
698
699         if (entering(tcp) || get_tcb_priv_ulong(tcp)) {
700 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
701                 const unsigned long next = c.id & V4L2_CTRL_FLAG_NEXT_CTRL;
702                 set_tcb_priv_ulong(tcp, next);
703                 if (next) {
704                         print_xlat(V4L2_CTRL_FLAG_NEXT_CTRL);
705                         tprints("|");
706                         c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
707                 }
708 #endif
709                 printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
710         }
711
712         if (exiting(tcp)) {
713                 tprints(", type=");
714                 printxval(v4l2_control_types, c.type, "V4L2_CTRL_TYPE_???");
715                 PRINT_FIELD_CSTRING(", ", c, name);
716                 tprintf(", minimum=%d, maximum=%d, step=%d"
717                         ", default_value=%d, flags=",
718                         c.minimum, c.maximum, c.step, c.default_value);
719                 printflags(v4l2_control_flags, c.flags, "V4L2_CTRL_FLAG_???");
720                 tprints("}");
721         }
722         return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
723 }
724
725 static int
726 print_v4l2_cropcap(struct tcb *const tcp, const kernel_ulong_t arg)
727 {
728         struct v4l2_cropcap c;
729
730         if (entering(tcp)) {
731                 tprints(", ");
732                 if (umove_or_printaddr(tcp, arg, &c))
733                         return RVAL_IOCTL_DECODED;
734                 tprints("{type=");
735                 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
736
737                 return 0;
738         }
739
740         if (!syserror(tcp) && !umove(tcp, arg, &c)) {
741                 tprintf(", bounds=" FMT_RECT
742                         ", defrect=" FMT_RECT
743                         ", pixelaspect=" FMT_FRACT,
744                         ARGS_RECT(c.bounds),
745                         ARGS_RECT(c.defrect),
746                         ARGS_FRACT(c.pixelaspect));
747         }
748
749         tprints("}");
750
751         return RVAL_IOCTL_DECODED;
752 }
753
754 static int
755 print_v4l2_crop(struct tcb *const tcp, const kernel_ulong_t arg,
756                 const bool is_get)
757 {
758         struct v4l2_crop c;
759
760         if (entering(tcp)) {
761                 tprints(", ");
762                 if (umove_or_printaddr(tcp, arg, &c))
763                         return RVAL_IOCTL_DECODED;
764                 tprints("{type=");
765                 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
766                 if (is_get)
767                         return 0;
768                 tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
769         } else {
770                 if (!syserror(tcp) && !umove(tcp, arg, &c))
771                         tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
772         }
773
774         tprints("}");
775
776         return RVAL_IOCTL_DECODED;
777 }
778
779 #ifdef VIDIOC_S_EXT_CTRLS
780 static bool
781 print_v4l2_ext_control(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
782 {
783         const struct_v4l2_ext_control *p = elem_buf;
784
785         tprints("{id=");
786         printxval(v4l2_control_ids, p->id, "V4L2_CID_???");
787 # if HAVE_DECL_V4L2_CTRL_TYPE_STRING
788         tprintf(", size=%u", p->size);
789         if (p->size > 0) {
790                 tprints(", string=");
791                 printstrn(tcp, ptr_to_kulong(p->string), p->size);
792         } else
793 # endif
794         tprintf(", value=%d, value64=%" PRId64, p->value, (int64_t) p->value64);
795         tprints("}");
796
797         return true;
798 }
799
800 static int
801 print_v4l2_ext_controls(struct tcb *const tcp, const kernel_ulong_t arg,
802                         const bool is_get)
803 {
804         struct_v4l2_ext_controls c;
805
806         if (entering(tcp)) {
807                 tprints(", ");
808                 if (umove_or_printaddr(tcp, arg, &c))
809                         return RVAL_IOCTL_DECODED;
810                 tprints("{ctrl_class=");
811                 printxval(v4l2_control_classes, c.ctrl_class,
812                           "V4L2_CTRL_CLASS_???");
813                 tprintf(", count=%u", c.count);
814                 if (!c.count) {
815                         tprints("}");
816                         return RVAL_IOCTL_DECODED;
817                 }
818                 if (is_get)
819                         return 0;
820                 tprints(", ");
821         } else {
822                 if (umove(tcp, arg, &c) < 0) {
823                         tprints("}");
824                         return RVAL_IOCTL_DECODED;
825                 }
826                 tprints(is_get ? ", " : " => ");
827         }
828
829         tprints("controls=");
830         struct_v4l2_ext_control ctrl;
831         bool fail = !print_array(tcp, ptr_to_kulong(c.controls), c.count,
832                                  &ctrl, sizeof(ctrl),
833                                  tfetch_mem_ignore_syserror,
834                                  print_v4l2_ext_control, 0);
835
836         if (exiting(tcp) && syserror(tcp))
837                 tprintf(", error_idx=%u", c.error_idx);
838
839         if (exiting(tcp) || fail) {
840                 tprints("}");
841                 return RVAL_IOCTL_DECODED;
842         }
843
844         /* entering */
845         return 0;
846 }
847 #endif /* VIDIOC_S_EXT_CTRLS */
848
849 #ifdef VIDIOC_ENUM_FRAMESIZES
850 # include "xlat/v4l2_framesize_types.h"
851
852 static int
853 print_v4l2_frmsizeenum(struct tcb *const tcp, const kernel_ulong_t arg)
854 {
855         struct v4l2_frmsizeenum s;
856
857         if (entering(tcp)) {
858                 tprints(", ");
859                 if (umove_or_printaddr(tcp, arg, &s))
860                         return RVAL_IOCTL_DECODED;
861                 tprintf("{index=%u, pixel_format=", s.index);
862                 print_pixelformat(s.pixel_format, v4l2_pix_fmts);
863                 return 0;
864         }
865
866         if (!syserror(tcp) && !umove(tcp, arg, &s)) {
867                 tprints(", type=");
868                 printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
869                 switch (s.type) {
870                 case V4L2_FRMSIZE_TYPE_DISCRETE:
871                         tprintf(", discrete={width=%u, height=%u}",
872                                 s.discrete.width, s.discrete.height);
873                         break;
874                 case V4L2_FRMSIZE_TYPE_STEPWISE:
875                         tprintf(", stepwise={min_width=%u, max_width=%u, "
876                                 "step_width=%u, min_height=%u, max_height=%u, "
877                                 "step_height=%u}",
878                                 s.stepwise.min_width, s.stepwise.max_width,
879                                 s.stepwise.step_width, s.stepwise.min_height,
880                                 s.stepwise.max_height, s.stepwise.step_height);
881                         break;
882                 }
883         }
884         tprints("}");
885         return RVAL_IOCTL_DECODED;
886 }
887 #endif /* VIDIOC_ENUM_FRAMESIZES */
888
889 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
890 # include "xlat/v4l2_frameinterval_types.h"
891
892 static int
893 print_v4l2_frmivalenum(struct tcb *const tcp, const kernel_ulong_t arg)
894 {
895         struct v4l2_frmivalenum f;
896
897         if (entering(tcp)) {
898                 tprints(", ");
899                 if (umove_or_printaddr(tcp, arg, &f))
900                         return RVAL_IOCTL_DECODED;
901                 tprintf("{index=%u, pixel_format=", f.index);
902                 print_pixelformat(f.pixel_format, v4l2_pix_fmts);
903                 tprintf(", width=%u, height=%u", f.width, f.height);
904                 return 0;
905         }
906
907         if (!syserror(tcp) && !umove(tcp, arg, &f)) {
908                 tprints(", type=");
909                 printxval(v4l2_frameinterval_types, f.type,
910                           "V4L2_FRMIVAL_TYPE_???");
911                 switch (f.type) {
912                 case V4L2_FRMIVAL_TYPE_DISCRETE:
913                         tprintf(", discrete=" FMT_FRACT,
914                                 ARGS_FRACT(f.discrete));
915                         break;
916                 case V4L2_FRMIVAL_TYPE_STEPWISE:
917                 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
918                         tprintf(", stepwise={min=" FMT_FRACT ", max="
919                                 FMT_FRACT ", step=" FMT_FRACT "}",
920                                 ARGS_FRACT(f.stepwise.min),
921                                 ARGS_FRACT(f.stepwise.max),
922                                 ARGS_FRACT(f.stepwise.step));
923                         break;
924                 }
925         }
926
927         tprints("}");
928
929         return RVAL_IOCTL_DECODED;
930 }
931 #endif /* VIDIOC_ENUM_FRAMEINTERVALS */
932
933 #ifdef VIDIOC_CREATE_BUFS
934 static int
935 print_v4l2_create_buffers(struct tcb *const tcp, const kernel_ulong_t arg)
936 {
937         static const char fmt[] = "{index=%u, count=%u}";
938         static char outstr[sizeof(fmt) + sizeof(int) * 6];
939
940         struct_v4l2_create_buffers b;
941
942         if (entering(tcp)) {
943                 tprints(", ");
944                 if (umove_or_printaddr(tcp, arg, &b))
945                         return RVAL_IOCTL_DECODED;
946                 tprintf("{count=%u, memory=", b.count);
947                 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
948                 tprints(", format={type=");
949                 printxval(v4l2_buf_types, b.format.type,
950                           "V4L2_BUF_TYPE_???");
951                 print_v4l2_format_fmt(tcp, ", ",
952                                       (struct_v4l2_format *) &b.format);
953                 tprints("}}");
954                 return 0;
955         }
956
957         if (syserror(tcp) || umove(tcp, arg, &b))
958                 return RVAL_IOCTL_DECODED;
959
960         xsprintf(outstr, fmt, b.index, b.count);
961         tcp->auxstr = outstr;
962
963         return RVAL_IOCTL_DECODED | RVAL_STR;
964 }
965 #endif /* VIDIOC_CREATE_BUFS */
966
967 MPERS_PRINTER_DECL(int, v4l2_ioctl, struct tcb *const tcp,
968                    const unsigned int code, const kernel_ulong_t arg)
969 {
970         if (!verbose(tcp))
971                 return RVAL_DECODED;
972
973         switch (code) {
974         case VIDIOC_QUERYCAP: /* R */
975                 return print_v4l2_capability(tcp, arg);
976
977         case VIDIOC_ENUM_FMT: /* RW */
978                 return print_v4l2_fmtdesc(tcp, arg);
979
980         case VIDIOC_G_FMT: /* RW */
981         case VIDIOC_S_FMT: /* RW */
982         case VIDIOC_TRY_FMT: /* RW */
983                 return print_v4l2_format(tcp, arg, code == VIDIOC_G_FMT);
984
985         case VIDIOC_REQBUFS: /* RW */
986                 return print_v4l2_requestbuffers(tcp, arg);
987
988         case VIDIOC_QUERYBUF: /* RW */
989         case VIDIOC_QBUF: /* RW */
990         case VIDIOC_DQBUF: /* RW */
991                 return print_v4l2_buffer(tcp, code, arg);
992
993         case VIDIOC_G_FBUF: /* R */
994                 if (entering(tcp))
995                         return 0;
996                 ATTRIBUTE_FALLTHROUGH;
997         case VIDIOC_S_FBUF: /* W */
998                 return print_v4l2_framebuffer(tcp, arg);
999
1000         case VIDIOC_STREAMON: /* W */
1001         case VIDIOC_STREAMOFF: /* W */
1002                 return print_v4l2_buf_type(tcp, arg);
1003
1004         case VIDIOC_G_PARM: /* RW */
1005         case VIDIOC_S_PARM: /* RW */
1006                 return print_v4l2_streamparm(tcp, arg, code == VIDIOC_G_PARM);
1007
1008         case VIDIOC_G_STD: /* R */
1009                 if (entering(tcp))
1010                         return 0;
1011                 ATTRIBUTE_FALLTHROUGH;
1012         case VIDIOC_S_STD: /* W */
1013                 tprints(", ");
1014                 printnum_int64(tcp, arg, "%#" PRIx64);
1015                 break;
1016
1017         case VIDIOC_ENUMSTD: /* RW */
1018                 return print_v4l2_standard(tcp, arg);
1019
1020         case VIDIOC_ENUMINPUT: /* RW */
1021                 return print_v4l2_input(tcp, arg);
1022
1023         case VIDIOC_G_CTRL: /* RW */
1024         case VIDIOC_S_CTRL: /* RW */
1025                 return print_v4l2_control(tcp, arg, code == VIDIOC_G_CTRL);
1026
1027         case VIDIOC_G_TUNER: /* RW */
1028         case VIDIOC_S_TUNER: /* RW */
1029                 return print_v4l2_tuner(tcp, arg, code == VIDIOC_G_TUNER);
1030
1031         case VIDIOC_QUERYCTRL: /* RW */
1032                 return print_v4l2_queryctrl(tcp, arg);
1033
1034         case VIDIOC_G_INPUT: /* R */
1035                 if (entering(tcp))
1036                         return 0;
1037                 ATTRIBUTE_FALLTHROUGH;
1038         case VIDIOC_S_INPUT: /* RW */
1039                 tprints(", ");
1040                 printnum_int(tcp, arg, "%u");
1041                 break;
1042
1043         case VIDIOC_CROPCAP: /* RW */
1044                 return print_v4l2_cropcap(tcp, arg);
1045
1046         case VIDIOC_G_CROP: /* RW */
1047         case VIDIOC_S_CROP: /* W */
1048                 return print_v4l2_crop(tcp, arg, code == VIDIOC_G_CROP);
1049
1050 #ifdef VIDIOC_S_EXT_CTRLS
1051         case VIDIOC_S_EXT_CTRLS: /* RW */
1052         case VIDIOC_TRY_EXT_CTRLS: /* RW */
1053         case VIDIOC_G_EXT_CTRLS: /* RW */
1054                 return print_v4l2_ext_controls(tcp, arg,
1055                                                code == VIDIOC_G_EXT_CTRLS);
1056 #endif /* VIDIOC_S_EXT_CTRLS */
1057
1058 #ifdef VIDIOC_ENUM_FRAMESIZES
1059         case VIDIOC_ENUM_FRAMESIZES: /* RW */
1060                 return print_v4l2_frmsizeenum(tcp, arg);
1061 #endif /* VIDIOC_ENUM_FRAMESIZES */
1062
1063 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
1064         case VIDIOC_ENUM_FRAMEINTERVALS: /* RW */
1065                 return print_v4l2_frmivalenum(tcp, arg);
1066 #endif /* VIDIOC_ENUM_FRAMEINTERVALS */
1067
1068 #ifdef VIDIOC_CREATE_BUFS
1069         case VIDIOC_CREATE_BUFS: /* RW */
1070                 return print_v4l2_create_buffers(tcp, arg);
1071 #endif /* VIDIOC_CREATE_BUFS */
1072
1073         default:
1074                 return RVAL_DECODED;
1075         }
1076
1077         return RVAL_IOCTL_DECODED;
1078 }