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