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