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