]> granicus.if.org Git - strace/blob - v4l2.c
mem: handle potential error from sysconf(_SC_PAGESIZE)
[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                         print_xlat(V4L2_CTRL_FLAG_NEXT_CTRL);
733                         tprints("|");
734                         c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
735                 }
736 #endif
737                 printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
738         }
739
740         if (exiting(tcp)) {
741                 tprints(", type=");
742                 printxval(v4l2_control_types, c.type, "V4L2_CTRL_TYPE_???");
743                 PRINT_FIELD_CSTRING(", ", c, name);
744                 tprintf(", minimum=%d, maximum=%d, step=%d"
745                         ", default_value=%d, flags=",
746                         c.minimum, c.maximum, c.step, c.default_value);
747                 printflags(v4l2_control_flags, c.flags, "V4L2_CTRL_FLAG_???");
748                 tprints("}");
749         }
750         return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
751 }
752
753 static int
754 print_v4l2_cropcap(struct tcb *const tcp, const kernel_ulong_t arg)
755 {
756         struct v4l2_cropcap c;
757
758         if (entering(tcp)) {
759                 tprints(", ");
760                 if (umove_or_printaddr(tcp, arg, &c))
761                         return RVAL_IOCTL_DECODED;
762                 tprints("{type=");
763                 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
764
765                 return 0;
766         }
767
768         if (!syserror(tcp) && !umove(tcp, arg, &c)) {
769                 tprintf(", bounds=" FMT_RECT
770                         ", defrect=" FMT_RECT
771                         ", pixelaspect=" FMT_FRACT,
772                         ARGS_RECT(c.bounds),
773                         ARGS_RECT(c.defrect),
774                         ARGS_FRACT(c.pixelaspect));
775         }
776
777         tprints("}");
778
779         return RVAL_IOCTL_DECODED;
780 }
781
782 static int
783 print_v4l2_crop(struct tcb *const tcp, const kernel_ulong_t arg,
784                 const bool is_get)
785 {
786         struct v4l2_crop c;
787
788         if (entering(tcp)) {
789                 tprints(", ");
790                 if (umove_or_printaddr(tcp, arg, &c))
791                         return RVAL_IOCTL_DECODED;
792                 tprints("{type=");
793                 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
794                 if (is_get)
795                         return 0;
796                 tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
797         } else {
798                 if (!syserror(tcp) && !umove(tcp, arg, &c))
799                         tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
800         }
801
802         tprints("}");
803
804         return RVAL_IOCTL_DECODED;
805 }
806
807 #ifdef VIDIOC_S_EXT_CTRLS
808 static bool
809 print_v4l2_ext_control(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
810 {
811         const struct_v4l2_ext_control *p = elem_buf;
812
813         tprints("{id=");
814         printxval(v4l2_control_ids, p->id, "V4L2_CID_???");
815 # if HAVE_DECL_V4L2_CTRL_TYPE_STRING
816         tprintf(", size=%u", p->size);
817         if (p->size > 0) {
818                 tprints(", string=");
819                 printstrn(tcp, ptr_to_kulong(p->string), p->size);
820         } else
821 # endif
822         tprintf(", value=%d, value64=%" PRId64, p->value, (int64_t) p->value64);
823         tprints("}");
824
825         return true;
826 }
827
828 #include "xlat/v4l2_control_classes.h"
829
830 static int
831 print_v4l2_ext_controls(struct tcb *const tcp, const kernel_ulong_t arg,
832                         const bool is_get)
833 {
834         struct_v4l2_ext_controls c;
835
836         if (entering(tcp)) {
837                 tprints(", ");
838                 if (umove_or_printaddr(tcp, arg, &c))
839                         return RVAL_IOCTL_DECODED;
840                 tprints("{ctrl_class=");
841                 printxval(v4l2_control_classes, c.ctrl_class,
842                           "V4L2_CTRL_CLASS_???");
843                 tprintf(", count=%u", c.count);
844                 if (!c.count) {
845                         tprints("}");
846                         return RVAL_IOCTL_DECODED;
847                 }
848                 if (is_get)
849                         return 0;
850                 tprints(", ");
851         } else {
852                 if (umove(tcp, arg, &c) < 0) {
853                         tprints("}");
854                         return RVAL_IOCTL_DECODED;
855                 }
856                 tprints(is_get ? ", " : " => ");
857         }
858
859         tprints("controls=");
860         struct_v4l2_ext_control ctrl;
861         bool fail = !print_array(tcp, ptr_to_kulong(c.controls), c.count,
862                                  &ctrl, sizeof(ctrl),
863                                  umoven_or_printaddr_ignore_syserror,
864                                  print_v4l2_ext_control, 0);
865
866         if (exiting(tcp) && syserror(tcp))
867                 tprintf(", error_idx=%u", c.error_idx);
868
869         if (exiting(tcp) || fail) {
870                 tprints("}");
871                 return RVAL_IOCTL_DECODED;
872         }
873
874         /* entering */
875         return 0;
876 }
877 #endif /* VIDIOC_S_EXT_CTRLS */
878
879 #ifdef VIDIOC_ENUM_FRAMESIZES
880 # include "xlat/v4l2_framesize_types.h"
881
882 static int
883 print_v4l2_frmsizeenum(struct tcb *const tcp, const kernel_ulong_t arg)
884 {
885         struct v4l2_frmsizeenum s;
886
887         if (entering(tcp)) {
888                 tprints(", ");
889                 if (umove_or_printaddr(tcp, arg, &s))
890                         return RVAL_IOCTL_DECODED;
891                 tprintf("{index=%u, pixel_format=", s.index);
892                 print_pixelformat(s.pixel_format, v4l2_pix_fmts);
893                 return 0;
894         }
895
896         if (!syserror(tcp) && !umove(tcp, arg, &s)) {
897                 tprints(", type=");
898                 printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
899                 switch (s.type) {
900                 case V4L2_FRMSIZE_TYPE_DISCRETE:
901                         tprintf(", discrete={width=%u, height=%u}",
902                                 s.discrete.width, s.discrete.height);
903                         break;
904                 case V4L2_FRMSIZE_TYPE_STEPWISE:
905                         tprintf(", stepwise={min_width=%u, max_width=%u, "
906                                 "step_width=%u, min_height=%u, max_height=%u, "
907                                 "step_height=%u}",
908                                 s.stepwise.min_width, s.stepwise.max_width,
909                                 s.stepwise.step_width, s.stepwise.min_height,
910                                 s.stepwise.max_height, s.stepwise.step_height);
911                         break;
912                 }
913         }
914         tprints("}");
915         return RVAL_IOCTL_DECODED;
916 }
917 #endif /* VIDIOC_ENUM_FRAMESIZES */
918
919 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
920 # include "xlat/v4l2_frameinterval_types.h"
921
922 static int
923 print_v4l2_frmivalenum(struct tcb *const tcp, const kernel_ulong_t arg)
924 {
925         struct v4l2_frmivalenum f;
926
927         if (entering(tcp)) {
928                 tprints(", ");
929                 if (umove_or_printaddr(tcp, arg, &f))
930                         return RVAL_IOCTL_DECODED;
931                 tprintf("{index=%u, pixel_format=", f.index);
932                 print_pixelformat(f.pixel_format, v4l2_pix_fmts);
933                 tprintf(", width=%u, height=%u", f.width, f.height);
934                 return 0;
935         }
936
937         if (!syserror(tcp) && !umove(tcp, arg, &f)) {
938                 tprints(", type=");
939                 printxval(v4l2_frameinterval_types, f.type,
940                           "V4L2_FRMIVAL_TYPE_???");
941                 switch (f.type) {
942                 case V4L2_FRMIVAL_TYPE_DISCRETE:
943                         tprintf(", discrete=" FMT_FRACT,
944                                 ARGS_FRACT(f.discrete));
945                         break;
946                 case V4L2_FRMIVAL_TYPE_STEPWISE:
947                 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
948                         tprintf(", stepwise={min=" FMT_FRACT ", max="
949                                 FMT_FRACT ", step=" FMT_FRACT "}",
950                                 ARGS_FRACT(f.stepwise.min),
951                                 ARGS_FRACT(f.stepwise.max),
952                                 ARGS_FRACT(f.stepwise.step));
953                         break;
954                 }
955         }
956
957         tprints("}");
958
959         return RVAL_IOCTL_DECODED;
960 }
961 #endif /* VIDIOC_ENUM_FRAMEINTERVALS */
962
963 #ifdef VIDIOC_CREATE_BUFS
964 static int
965 print_v4l2_create_buffers(struct tcb *const tcp, const kernel_ulong_t arg)
966 {
967         static const char fmt[] = "{index=%u, count=%u}";
968         static char outstr[sizeof(fmt) + sizeof(int) * 6];
969
970         struct_v4l2_create_buffers b;
971
972         if (entering(tcp)) {
973                 tprints(", ");
974                 if (umove_or_printaddr(tcp, arg, &b))
975                         return RVAL_IOCTL_DECODED;
976                 tprintf("{count=%u, memory=", b.count);
977                 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
978                 tprints(", format={type=");
979                 printxval(v4l2_buf_types, b.format.type,
980                           "V4L2_BUF_TYPE_???");
981                 print_v4l2_format_fmt(tcp, ", ",
982                                       (struct_v4l2_format *) &b.format);
983                 tprints("}}");
984                 return 0;
985         }
986
987         if (syserror(tcp) || umove(tcp, arg, &b))
988                 return RVAL_IOCTL_DECODED;
989
990         xsprintf(outstr, fmt, b.index, b.count);
991         tcp->auxstr = outstr;
992
993         return RVAL_IOCTL_DECODED | RVAL_STR;
994 }
995 #endif /* VIDIOC_CREATE_BUFS */
996
997 MPERS_PRINTER_DECL(int, v4l2_ioctl, struct tcb *const tcp,
998                    const unsigned int code, const kernel_ulong_t arg)
999 {
1000         if (!verbose(tcp))
1001                 return RVAL_DECODED;
1002
1003         switch (code) {
1004         case VIDIOC_QUERYCAP: /* R */
1005                 return print_v4l2_capability(tcp, arg);
1006
1007         case VIDIOC_ENUM_FMT: /* RW */
1008                 return print_v4l2_fmtdesc(tcp, arg);
1009
1010         case VIDIOC_G_FMT: /* RW */
1011         case VIDIOC_S_FMT: /* RW */
1012         case VIDIOC_TRY_FMT: /* RW */
1013                 return print_v4l2_format(tcp, arg, code == VIDIOC_G_FMT);
1014
1015         case VIDIOC_REQBUFS: /* RW */
1016                 return print_v4l2_requestbuffers(tcp, arg);
1017
1018         case VIDIOC_QUERYBUF: /* RW */
1019         case VIDIOC_QBUF: /* RW */
1020         case VIDIOC_DQBUF: /* RW */
1021                 return print_v4l2_buffer(tcp, code, arg);
1022
1023         case VIDIOC_G_FBUF: /* R */
1024                 if (entering(tcp))
1025                         return 0;
1026                 ATTRIBUTE_FALLTHROUGH;
1027         case VIDIOC_S_FBUF: /* W */
1028                 return print_v4l2_framebuffer(tcp, arg);
1029
1030         case VIDIOC_STREAMON: /* W */
1031         case VIDIOC_STREAMOFF: /* W */
1032                 return print_v4l2_buf_type(tcp, arg);
1033
1034         case VIDIOC_G_PARM: /* RW */
1035         case VIDIOC_S_PARM: /* RW */
1036                 return print_v4l2_streamparm(tcp, arg, code == VIDIOC_G_PARM);
1037
1038         case VIDIOC_G_STD: /* R */
1039                 if (entering(tcp))
1040                         return 0;
1041                 ATTRIBUTE_FALLTHROUGH;
1042         case VIDIOC_S_STD: /* W */
1043                 tprints(", ");
1044                 printnum_int64(tcp, arg, "%#" PRIx64);
1045                 break;
1046
1047         case VIDIOC_ENUMSTD: /* RW */
1048                 return print_v4l2_standard(tcp, arg);
1049
1050         case VIDIOC_ENUMINPUT: /* RW */
1051                 return print_v4l2_input(tcp, arg);
1052
1053         case VIDIOC_G_CTRL: /* RW */
1054         case VIDIOC_S_CTRL: /* RW */
1055                 return print_v4l2_control(tcp, arg, code == VIDIOC_G_CTRL);
1056
1057         case VIDIOC_G_TUNER: /* RW */
1058         case VIDIOC_S_TUNER: /* RW */
1059                 return print_v4l2_tuner(tcp, arg, code == VIDIOC_G_TUNER);
1060
1061         case VIDIOC_QUERYCTRL: /* RW */
1062                 return print_v4l2_queryctrl(tcp, arg);
1063
1064         case VIDIOC_G_INPUT: /* R */
1065                 if (entering(tcp))
1066                         return 0;
1067                 ATTRIBUTE_FALLTHROUGH;
1068         case VIDIOC_S_INPUT: /* RW */
1069                 tprints(", ");
1070                 printnum_int(tcp, arg, "%u");
1071                 break;
1072
1073         case VIDIOC_CROPCAP: /* RW */
1074                 return print_v4l2_cropcap(tcp, arg);
1075
1076         case VIDIOC_G_CROP: /* RW */
1077         case VIDIOC_S_CROP: /* W */
1078                 return print_v4l2_crop(tcp, arg, code == VIDIOC_G_CROP);
1079
1080 #ifdef VIDIOC_S_EXT_CTRLS
1081         case VIDIOC_S_EXT_CTRLS: /* RW */
1082         case VIDIOC_TRY_EXT_CTRLS: /* RW */
1083         case VIDIOC_G_EXT_CTRLS: /* RW */
1084                 return print_v4l2_ext_controls(tcp, arg,
1085                                                code == VIDIOC_G_EXT_CTRLS);
1086 #endif /* VIDIOC_S_EXT_CTRLS */
1087
1088 #ifdef VIDIOC_ENUM_FRAMESIZES
1089         case VIDIOC_ENUM_FRAMESIZES: /* RW */
1090                 return print_v4l2_frmsizeenum(tcp, arg);
1091 #endif /* VIDIOC_ENUM_FRAMESIZES */
1092
1093 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
1094         case VIDIOC_ENUM_FRAMEINTERVALS: /* RW */
1095                 return print_v4l2_frmivalenum(tcp, arg);
1096 #endif /* VIDIOC_ENUM_FRAMEINTERVALS */
1097
1098 #ifdef VIDIOC_CREATE_BUFS
1099         case VIDIOC_CREATE_BUFS: /* RW */
1100                 return print_v4l2_create_buffers(tcp, arg);
1101 #endif /* VIDIOC_CREATE_BUFS */
1102
1103         default:
1104                 return RVAL_DECODED;
1105         }
1106
1107         return RVAL_IOCTL_DECODED;
1108 }