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