]> granicus.if.org Git - strace/blob - v4l2.c
Add PAF_ARRAY_TRUNCATED flag for print_array_ex
[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-2019 The strace developers.
6  * All rights reserved.
7  *
8  * SPDX-License-Identifier: LGPL-2.1-or-later
9  */
10
11 #include "defs.h"
12
13 #include <stdint.h>
14 #include <linux/ioctl.h>
15 #include <linux/types.h>
16 #include <linux/videodev2.h>
17
18 #include DEF_MPERS_TYPE(struct_v4l2_buffer)
19 #include DEF_MPERS_TYPE(struct_v4l2_clip)
20 #ifdef VIDIOC_CREATE_BUFS
21 # include DEF_MPERS_TYPE(struct_v4l2_create_buffers)
22 #endif
23 #include DEF_MPERS_TYPE(struct_v4l2_ext_control)
24 #include DEF_MPERS_TYPE(struct_v4l2_ext_controls)
25 #include DEF_MPERS_TYPE(struct_v4l2_format)
26 #include DEF_MPERS_TYPE(struct_v4l2_framebuffer)
27 #include DEF_MPERS_TYPE(struct_v4l2_input)
28 #include DEF_MPERS_TYPE(struct_v4l2_standard)
29
30 typedef struct v4l2_buffer struct_v4l2_buffer;
31 typedef struct v4l2_clip struct_v4l2_clip;
32 #ifdef VIDIOC_CREATE_BUFS
33 typedef struct v4l2_create_buffers struct_v4l2_create_buffers;
34 #endif
35 typedef struct v4l2_ext_control struct_v4l2_ext_control;
36 typedef struct v4l2_ext_controls struct_v4l2_ext_controls;
37 typedef struct v4l2_format struct_v4l2_format;
38 typedef struct v4l2_framebuffer struct_v4l2_framebuffer;
39 typedef struct v4l2_input struct_v4l2_input;
40 typedef struct v4l2_standard struct_v4l2_standard;
41
42 #include MPERS_DEFS
43
44 #include "print_fields.h"
45 #include "print_utils.h"
46 #include "xstring.h"
47
48 /* v4l2_fourcc_be was added by Linux commit v3.18-rc1~101^2^2~127 */
49 #ifndef v4l2_fourcc_be
50 # define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1U << 31))
51 #endif
52
53 #define FMT_FRACT "%u/%u"
54 #define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
55
56 #define FMT_RECT "{left=%d, top=%d, width=%u, height=%u}"
57 #define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
58
59 #include "xlat/v4l2_pix_fmts.h"
60 #include "xlat/v4l2_sdr_fmts.h"
61
62 static void
63 print_pixelformat(uint32_t fourcc, const struct xlat *xlat)
64 {
65         unsigned char a[] = {
66                 (unsigned char) fourcc,
67                 (unsigned char) (fourcc >> 8),
68                 (unsigned char) (fourcc >> 16),
69                 (unsigned char) (fourcc >> 24),
70         };
71         unsigned int i;
72
73         tprints("v4l2_fourcc(");
74         /* Generic char array printing routine.  */
75         for (i = 0; i < ARRAY_SIZE(a); ++i) {
76                 unsigned char c = a[i];
77
78                 if (i)
79                         tprints(", ");
80                 if (c == '\'' || c == '\\') {
81                         char sym[] = {
82                                 '\'',
83                                 '\\',
84                                 c,
85                                 '\'',
86                                 '\0'
87                         };
88                         tprints(sym);
89                 } else if (is_print(c)) {
90                         char sym[] = {
91                                 '\'',
92                                 c,
93                                 '\'',
94                                 '\0'
95                         };
96                         tprints(sym);
97                 } else {
98                         char hex[] = {
99                                 BYTE_HEX_CHARS_PRINTF_QUOTED(c),
100                                 '\0'
101                         };
102                         tprints(hex);
103                 }
104         }
105         tprints(")");
106
107         if (xlat) {
108                 const char *pixfmt_name = xlookup(xlat, fourcc);
109
110                 if (pixfmt_name)
111                         tprints_comment(pixfmt_name);
112         }
113 }
114
115 #include "xlat/v4l2_device_capabilities_flags.h"
116
117 static int
118 print_v4l2_capability(struct tcb *const tcp, const kernel_ulong_t arg)
119 {
120         struct v4l2_capability caps;
121
122         if (entering(tcp))
123                 return 0;
124         tprints(", ");
125         if (umove_or_printaddr(tcp, arg, &caps))
126                 return RVAL_IOCTL_DECODED;
127         PRINT_FIELD_CSTRING("{", caps, driver);
128         PRINT_FIELD_CSTRING(", ", caps, card);
129         PRINT_FIELD_CSTRING(", ", caps, bus_info);
130         tprintf(", version=%u.%u.%u, capabilities=",
131                 (caps.version >> 16) & 0xFF,
132                 (caps.version >> 8) & 0xFF,
133                 caps.version & 0xFF);
134         printflags(v4l2_device_capabilities_flags, caps.capabilities,
135                    "V4L2_CAP_???");
136 #ifdef V4L2_CAP_DEVICE_CAPS
137         tprints(", device_caps=");
138         printflags(v4l2_device_capabilities_flags, caps.device_caps,
139                    "V4L2_CAP_???");
140 #endif
141         tprints("}");
142         return RVAL_IOCTL_DECODED;
143 }
144
145 #include "xlat/v4l2_buf_types.h"
146 #include "xlat/v4l2_format_description_flags.h"
147
148 static int
149 print_v4l2_fmtdesc(struct tcb *const tcp, const kernel_ulong_t arg)
150 {
151         struct v4l2_fmtdesc f;
152
153         if (entering(tcp)) {
154                 tprints(", ");
155                 if (umove_or_printaddr(tcp, arg, &f))
156                         return RVAL_IOCTL_DECODED;
157                 tprintf("{index=%u, type=", f.index);
158                 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
159                 return 0;
160         }
161
162         if (!syserror(tcp) && !umove(tcp, arg, &f)) {
163                 tprints(", flags=");
164                 printflags(v4l2_format_description_flags, f.flags,
165                            "V4L2_FMT_FLAG_???");
166                 PRINT_FIELD_CSTRING(", ", f, description);
167                 tprints(", pixelformat=");
168                 print_pixelformat(f.pixelformat, v4l2_pix_fmts);
169         }
170         tprints("}");
171         return RVAL_IOCTL_DECODED;
172 }
173
174 #include "xlat/v4l2_fields.h"
175 #include "xlat/v4l2_colorspaces.h"
176 #include "xlat/v4l2_vbi_flags.h"
177 #include "xlat/v4l2_sliced_flags.h"
178
179 static bool
180 print_v4l2_clip(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
181 {
182         const struct_v4l2_clip *p = elem_buf;
183         tprintf(FMT_RECT, ARGS_RECT(p->c));
184         return true;
185 }
186
187 static bool
188 print_v4l2_format_fmt(struct tcb *const tcp, const char *prefix,
189                       const struct_v4l2_format *f)
190 {
191         bool ret = true;
192         switch (f->type) {
193         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
194         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
195                 tprints(prefix);
196                 tprintf("fmt.pix={width=%u, height=%u, pixelformat=",
197                         f->fmt.pix.width, f->fmt.pix.height);
198                 print_pixelformat(f->fmt.pix.pixelformat, v4l2_pix_fmts);
199                 tprints(", field=");
200                 printxval(v4l2_fields, f->fmt.pix.field, "V4L2_FIELD_???");
201                 tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
202                         f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
203                 printxval(v4l2_colorspaces, f->fmt.pix.colorspace,
204                           "V4L2_COLORSPACE_???");
205                 tprints("}");
206                 break;
207 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
208         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
209         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
210                 unsigned int i, max;
211
212                 tprints(prefix);
213                 tprintf("fmt.pix_mp={width=%u, height=%u, pixelformat=",
214                         f->fmt.pix_mp.width, f->fmt.pix_mp.height);
215                 print_pixelformat(f->fmt.pix_mp.pixelformat, v4l2_pix_fmts);
216                 tprints(", field=");
217                 printxval(v4l2_fields, f->fmt.pix_mp.field, "V4L2_FIELD_???");
218                 tprints(", colorspace=");
219                 printxval(v4l2_colorspaces, f->fmt.pix_mp.colorspace,
220                           "V4L2_COLORSPACE_???");
221                 tprints(", plane_fmt=[");
222                 max = f->fmt.pix_mp.num_planes;
223                 if (max > VIDEO_MAX_PLANES)
224                         max = VIDEO_MAX_PLANES;
225                 for (i = 0; i < max; i++) {
226                         if (i > 0)
227                                 tprints(", ");
228                         tprintf("{sizeimage=%u, bytesperline=%u}",
229                                 f->fmt.pix_mp.plane_fmt[i].sizeimage,
230                                 f->fmt.pix_mp.plane_fmt[i].bytesperline);
231                 }
232                 tprintf("], num_planes=%u}",
233                         (unsigned) f->fmt.pix_mp.num_planes);
234                 break;
235         }
236 #endif
237         /* OUTPUT_OVERLAY since Linux v2.6.22-rc1~1118^2~179 */
238 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
239         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
240 #endif
241         case V4L2_BUF_TYPE_VIDEO_OVERLAY: {
242                 struct_v4l2_clip clip;
243                 tprints(prefix);
244                 tprintf("fmt.win={left=%d, top=%d, width=%u, height=%u, field=",
245                         ARGS_RECT(f->fmt.win.w));
246                 printxval(v4l2_fields, f->fmt.win.field, "V4L2_FIELD_???");
247                 tprintf(", chromakey=%#x, clips=", f->fmt.win.chromakey);
248                 ret = print_array(tcp, ptr_to_kulong(f->fmt.win.clips),
249                                   f->fmt.win.clipcount, &clip, sizeof(clip),
250                                   tfetch_mem, print_v4l2_clip, 0);
251                 tprintf(", clipcount=%u, bitmap=", f->fmt.win.clipcount);
252                 printaddr(ptr_to_kulong(f->fmt.win.bitmap));
253 #ifdef HAVE_STRUCT_V4L2_WINDOW_GLOBAL_ALPHA
254                 tprintf(", global_alpha=%#x", f->fmt.win.global_alpha);
255 #endif
256                 tprints("}");
257                 break;
258         }
259         case V4L2_BUF_TYPE_VBI_CAPTURE:
260         case V4L2_BUF_TYPE_VBI_OUTPUT:
261                 tprints(prefix);
262                 tprintf("fmt.vbi={sampling_rate=%u, offset=%u, "
263                         "samples_per_line=%u, sample_format=",
264                         f->fmt.vbi.sampling_rate, f->fmt.vbi.offset,
265                         f->fmt.vbi.samples_per_line);
266                 print_pixelformat(f->fmt.vbi.sample_format, v4l2_pix_fmts);
267                 tprintf(", start=[%u, %u], count=[%u, %u], ",
268                         f->fmt.vbi.start[0], f->fmt.vbi.start[1],
269                         f->fmt.vbi.count[0], f->fmt.vbi.count[1]);
270                 tprints("flags=");
271                 printxval(v4l2_vbi_flags, f->fmt.vbi.flags, "V4L2_VBI_???");
272                 tprints("}");
273                 break;
274         /* both since Linux v2.6.14-rc2~64 */
275 #if HAVE_DECL_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
276         case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
277         case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: {
278                 unsigned int i, j;
279
280                 tprints(prefix);
281                 tprints("fmt.sliced={service_set=");
282                 printxval(v4l2_sliced_flags, f->fmt.sliced.service_set,
283                         "V4L2_SLICED_???");
284                 tprintf(", io_size=%u, service_lines=[",
285                         f->fmt.sliced.io_size);
286                 for (i = 0; i < ARRAY_SIZE(f->fmt.sliced.service_lines); i++) {
287                         if (i > 0)
288                                 tprints(", ");
289                         tprints("[");
290                         for (j = 0;
291                              j < ARRAY_SIZE(f->fmt.sliced.service_lines[0]);
292                              j++) {
293                                 if (j > 0)
294                                         tprints(", ");
295                                 tprintf("%#x",
296                                         f->fmt.sliced.service_lines[i][j]);
297                         }
298                         tprints("]");
299                 }
300                 tprints("]}");
301                 break;
302         }
303 #endif
304         /* since Linux v4.4-rc1~118^2~14 */
305 #if HAVE_DECL_V4L2_BUF_TYPE_SDR_OUTPUT
306         case V4L2_BUF_TYPE_SDR_OUTPUT:
307 #endif
308         /* since Linux v3.15-rc1~85^2~213 */
309 #if HAVE_DECL_V4L2_BUF_TYPE_SDR_CAPTURE
310         case V4L2_BUF_TYPE_SDR_CAPTURE:
311                 tprints(prefix);
312                 tprints("fmt.sdr={pixelformat=");
313                 print_pixelformat(f->fmt.sdr.pixelformat, v4l2_sdr_fmts);
314 # ifdef HAVE_STRUCT_V4L2_SDR_FORMAT_BUFFERSIZE
315                 tprintf(", buffersize=%u",
316                         f->fmt.sdr.buffersize);
317 # endif
318                 tprints("}");
319                 break;
320 #endif
321         }
322         return ret;
323 }
324
325 static int
326 print_v4l2_format(struct tcb *const tcp, const kernel_ulong_t arg,
327                   const bool is_get)
328 {
329         struct_v4l2_format f;
330
331         if (entering(tcp)) {
332                 tprints(", ");
333                 if (umove_or_printaddr(tcp, arg, &f))
334                         return RVAL_IOCTL_DECODED;
335                 tprints("{type=");
336                 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
337                 if (is_get)
338                         return 0;
339                 if (!print_v4l2_format_fmt(tcp, ", ", &f)) {
340                         tprints("}");
341                         return RVAL_IOCTL_DECODED;
342                 }
343
344                 return 0;
345         }
346
347         if (!syserror(tcp) && !umove(tcp, arg, &f))
348                 print_v4l2_format_fmt(tcp, is_get ? ", " : " => ", &f);
349
350         tprints("}");
351
352         return RVAL_IOCTL_DECODED;
353 }
354
355 #include "xlat/v4l2_memories.h"
356
357 static int
358 print_v4l2_requestbuffers(struct tcb *const tcp, const kernel_ulong_t arg)
359 {
360         struct v4l2_requestbuffers reqbufs;
361
362         if (entering(tcp)) {
363                 tprints(", ");
364
365                 if (umove_or_printaddr(tcp, arg, &reqbufs))
366                         return RVAL_IOCTL_DECODED;
367
368                 tprintf("{type=");
369                 printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
370                 tprints(", memory=");
371                 printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
372                 tprintf(", count=%u", reqbufs.count);
373
374                 return 0;
375         }
376
377         if (!syserror(tcp)) {
378                 tprints(" => ");
379
380                 if (!umove(tcp, arg, &reqbufs))
381                         tprintf("%u", reqbufs.count);
382                 else
383                         tprints("???");
384         }
385
386         tprints("}");
387
388         return RVAL_IOCTL_DECODED;
389 }
390
391 #include "xlat/v4l2_buf_flags.h"
392
393 static int
394 print_v4l2_buffer(struct tcb *const tcp, const unsigned int code,
395                   const kernel_ulong_t arg)
396 {
397         struct_v4l2_buffer b;
398
399         if (entering(tcp)) {
400                 tprints(", ");
401                 if (umove_or_printaddr(tcp, arg, &b))
402                         return RVAL_IOCTL_DECODED;
403                 tprints("{type=");
404                 printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???");
405                 if (code != VIDIOC_DQBUF)
406                         tprintf(", index=%u", b.index);
407
408                 return 0;
409         }
410
411         if (!syserror(tcp) && !umove(tcp, arg, &b)) {
412                 if (code == VIDIOC_DQBUF)
413                         tprintf(", index=%u", b.index);
414                 tprints(", memory=");
415                 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
416
417                 if (b.memory == V4L2_MEMORY_MMAP) {
418                         tprintf(", m.offset=%#x", b.m.offset);
419                 } else if (b.memory == V4L2_MEMORY_USERPTR) {
420                         tprints(", m.userptr=");
421                         printaddr(b.m.userptr);
422                 }
423
424                 tprintf(", length=%u, bytesused=%u, flags=",
425                         b.length, b.bytesused);
426                 printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???");
427                 if (code == VIDIOC_DQBUF) {
428                         tprints(", timestamp = ");
429                         MPERS_FUNC_NAME(print_struct_timeval)(&b.timestamp);
430                 }
431                 tprints(", ...");
432         }
433
434         tprints("}");
435
436         return RVAL_IOCTL_DECODED;
437 }
438
439 static int
440 print_v4l2_framebuffer(struct tcb *const tcp, const kernel_ulong_t arg)
441 {
442         struct_v4l2_framebuffer b;
443
444         tprints(", ");
445         if (!umove_or_printaddr(tcp, arg, &b)) {
446                 tprintf("{capability=%#x, flags=%#x, base=",
447                         b.capability, b.flags);
448                 printaddr(ptr_to_kulong(b.base));
449                 tprints("}");
450         }
451
452         return RVAL_IOCTL_DECODED;
453 }
454
455 static int
456 print_v4l2_buf_type(struct tcb *const tcp, const kernel_ulong_t arg)
457 {
458         int type;
459
460         tprints(", ");
461         if (!umove_or_printaddr(tcp, arg, &type)) {
462                 tprints("[");
463                 printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
464                 tprints("]");
465         }
466         return RVAL_IOCTL_DECODED;
467 }
468
469 #include "xlat/v4l2_streaming_capabilities.h"
470 #include "xlat/v4l2_capture_modes.h"
471
472 static int
473 print_v4l2_streamparm(struct tcb *const tcp, const kernel_ulong_t arg,
474                       const bool is_get)
475 {
476         struct v4l2_streamparm s;
477
478         if (entering(tcp)) {
479                 tprints(", ");
480                 if (umove_or_printaddr(tcp, arg, &s))
481                         return RVAL_IOCTL_DECODED;
482                 tprints("{type=");
483                 printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
484                 switch (s.type) {
485                         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
486                         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
487                                 if (is_get)
488                                         return 0;
489                                 tprints(", ");
490                                 break;
491                         default:
492                                 tprints("}");
493                                 return RVAL_IOCTL_DECODED;
494                 }
495         } else {
496                 if (syserror(tcp) || umove(tcp, arg, &s) < 0) {
497                         tprints("}");
498                         return RVAL_IOCTL_DECODED;
499                 }
500                 tprints(is_get ? ", " : " => ");
501         }
502
503         if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
504                 tprints("parm.capture={capability=");
505                 printflags(v4l2_streaming_capabilities,
506                            s.parm.capture.capability, "V4L2_CAP_???");
507
508                 tprints(", capturemode=");
509                 printflags(v4l2_capture_modes,
510                            s.parm.capture.capturemode, "V4L2_MODE_???");
511
512                 tprintf(", timeperframe=" FMT_FRACT,
513                         ARGS_FRACT(s.parm.capture.timeperframe));
514
515                 tprintf(", extendedmode=%u, readbuffers=%u}",
516                         s.parm.capture.extendedmode,
517                         s.parm.capture.readbuffers);
518         } else {
519                 tprints("parm.output={capability=");
520                 printflags(v4l2_streaming_capabilities,
521                            s.parm.output.capability, "V4L2_CAP_???");
522
523                 tprintf(", outputmode=%u", s.parm.output.outputmode);
524
525                 tprintf(", timeperframe=" FMT_FRACT,
526                         ARGS_FRACT(s.parm.output.timeperframe));
527
528                 tprintf(", extendedmode=%u, writebuffers=%u}",
529                         s.parm.output.extendedmode,
530                         s.parm.output.writebuffers);
531         }
532         if (entering(tcp)) {
533                 return 0;
534         } else {
535                 tprints("}");
536                 return RVAL_IOCTL_DECODED;
537         }
538 }
539
540 static int
541 print_v4l2_standard(struct tcb *const tcp, const kernel_ulong_t arg)
542 {
543         struct_v4l2_standard s;
544
545         if (entering(tcp)) {
546                 tprints(", ");
547                 if (umove_or_printaddr(tcp, arg, &s))
548                         return RVAL_IOCTL_DECODED;
549                 tprintf("{index=%u", s.index);
550
551                 return 0;
552         }
553
554         if (!syserror(tcp) && !umove(tcp, arg, &s)) {
555                 PRINT_FIELD_CSTRING(", ", s, name);
556                 tprintf(", frameperiod=" FMT_FRACT,
557                         ARGS_FRACT(s.frameperiod));
558                 tprintf(", framelines=%d", s.framelines);
559         }
560
561         tprints("}");
562
563         return RVAL_IOCTL_DECODED;
564 }
565
566 #include "xlat/v4l2_input_types.h"
567
568 static int
569 print_v4l2_input(struct tcb *const tcp, const kernel_ulong_t arg)
570 {
571         struct_v4l2_input i;
572
573         if (entering(tcp)) {
574                 tprints(", ");
575                 if (umove_or_printaddr(tcp, arg, &i))
576                         return RVAL_IOCTL_DECODED;
577                 tprintf("{index=%u", i.index);
578
579                 return 0;
580         }
581
582         if (!syserror(tcp) && !umove(tcp, arg, &i)) {
583                 PRINT_FIELD_CSTRING(", ", i, name);
584                 tprints(", type=");
585                 printxval(v4l2_input_types, i.type, "V4L2_INPUT_TYPE_???");
586         }
587
588         tprints("}");
589
590         return RVAL_IOCTL_DECODED;
591 }
592
593 /*
594  * We include it here and not before print_v4l2_ext_controls as we need
595  * V4L2_CTRL_CLASS_* definitions for V4L2_CID_*_BASE ones.
596  */
597 #include "xlat/v4l2_control_classes.h"
598 #include "xlat/v4l2_control_id_bases.h"
599 #include "xlat/v4l2_control_ids.h"
600
601 static void
602 print_v4l2_cid(const uint32_t cid)
603 {
604         const char *id_name = xlookup(v4l2_control_ids, cid);
605
606         if (id_name) {
607                 print_xlat_ex(cid, id_name, XLAT_STYLE_DEFAULT);
608                 return;
609         }
610
611         uint64_t class_id = cid;
612         const char *class_str = xlookup_le(v4l2_control_classes, &class_id);
613
614         if (!class_str || (cid - class_id) >= 0x10000) {
615                 print_xlat_ex(cid, "V4L2_CID_???", PXF_DEFAULT_STR);
616                 return;
617         }
618
619         char *tmp_str;
620
621         if (asprintf(&tmp_str, "%s+%#" PRIx64,
622                      class_str, cid - class_id) < 0)
623                 tmp_str = NULL;
624
625         print_xlat_ex(cid, tmp_str, XLAT_STYLE_DEFAULT);
626         free(tmp_str);
627 }
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
640                 tprints("{id=");
641                 print_v4l2_cid(c.id);
642                 if (!is_get)
643                         tprintf(", value=%d", c.value);
644                 return 0;
645         }
646
647         if (!syserror(tcp) && !umove(tcp, arg, &c)) {
648                 tprints(is_get ? ", " : " => ");
649                 tprintf("value=%d", c.value);
650         }
651
652         tprints("}");
653
654         return RVAL_IOCTL_DECODED;
655 }
656
657 #include "xlat/v4l2_tuner_types.h"
658 #include "xlat/v4l2_tuner_capabilities.h"
659 #include "xlat/v4l2_tuner_rxsubchanses.h"
660 #include "xlat/v4l2_tuner_audmodes.h"
661
662 static int
663 print_v4l2_tuner(struct tcb *const tcp, const kernel_ulong_t arg,
664                  const bool is_get)
665 {
666         struct v4l2_tuner c;
667         if (entering(tcp)) {
668                 tprints(", ");
669                 if (umove_or_printaddr(tcp, arg, &c))
670                         return RVAL_IOCTL_DECODED;
671                 tprintf("{index=%u", c.index);
672                 if (is_get)
673                         return 0;
674                 tprints(", ");
675         } else {
676                 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
677                         tprints("}");
678                         return RVAL_IOCTL_DECODED;
679                 }
680                 tprints(is_get ? ", " : " => ");
681         }
682
683         PRINT_FIELD_CSTRING("", c, name);
684         tprints(", type=");
685         printxval(v4l2_tuner_types, c.type, "V4L2_TUNER_TYPE_???");
686         tprints(", capability=");
687         printxval(v4l2_tuner_capabilities, c.capability,
688                   "V4L2_TUNER_CAP_???");
689         tprintf(", rangelow=%u, rangehigh=%u, rxsubchans=",
690                 c.rangelow, c.rangehigh);
691         printxval(v4l2_tuner_rxsubchanses, c.rxsubchans,
692                   "V4L2_TUNER_SUB_???");
693         tprints(", audmode=");
694         printxval(v4l2_tuner_audmodes, c.audmode,
695                   "V4L2_TUNER_MODE_???");
696         tprintf(", signal=%d, afc=%d", c.signal, c.afc);
697
698         if (entering(tcp)) {
699                 return 0;
700         } else {
701                 tprints("}");
702                 return RVAL_IOCTL_DECODED;
703         }
704 }
705
706 #include "xlat/v4l2_control_types.h"
707 #include "xlat/v4l2_control_flags.h"
708
709 static int
710 print_v4l2_queryctrl(struct tcb *const tcp, const kernel_ulong_t arg)
711 {
712         struct v4l2_queryctrl c;
713
714         if (entering(tcp)) {
715                 tprints(", ");
716                 if (umove_or_printaddr(tcp, arg, &c))
717                         return RVAL_IOCTL_DECODED;
718                 tprints("{id=");
719         } else {
720                 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
721                         tprints("}");
722                         return RVAL_IOCTL_DECODED;
723                 }
724                 if (get_tcb_priv_ulong(tcp))
725                         tprints(" => ");
726         }
727
728         if (entering(tcp) || get_tcb_priv_ulong(tcp)) {
729 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
730                 const unsigned long next = c.id & V4L2_CTRL_FLAG_NEXT_CTRL;
731                 set_tcb_priv_ulong(tcp, next);
732                 if (next) {
733                         print_xlat(V4L2_CTRL_FLAG_NEXT_CTRL);
734                         tprints("|");
735                         c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
736                 }
737 #endif
738                 printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
739         }
740
741         if (exiting(tcp)) {
742                 tprints(", type=");
743                 printxval(v4l2_control_types, c.type, "V4L2_CTRL_TYPE_???");
744                 PRINT_FIELD_CSTRING(", ", c, name);
745                 tprintf(", minimum=%d, maximum=%d, step=%d"
746                         ", default_value=%d, flags=",
747                         c.minimum, c.maximum, c.step, c.default_value);
748                 printflags(v4l2_control_flags, c.flags, "V4L2_CTRL_FLAG_???");
749                 tprints("}");
750         }
751         return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
752 }
753
754 static int
755 print_v4l2_cropcap(struct tcb *const tcp, const kernel_ulong_t arg)
756 {
757         struct v4l2_cropcap c;
758
759         if (entering(tcp)) {
760                 tprints(", ");
761                 if (umove_or_printaddr(tcp, arg, &c))
762                         return RVAL_IOCTL_DECODED;
763                 tprints("{type=");
764                 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
765
766                 return 0;
767         }
768
769         if (!syserror(tcp) && !umove(tcp, arg, &c)) {
770                 tprintf(", bounds=" FMT_RECT
771                         ", defrect=" FMT_RECT
772                         ", pixelaspect=" FMT_FRACT,
773                         ARGS_RECT(c.bounds),
774                         ARGS_RECT(c.defrect),
775                         ARGS_FRACT(c.pixelaspect));
776         }
777
778         tprints("}");
779
780         return RVAL_IOCTL_DECODED;
781 }
782
783 static int
784 print_v4l2_crop(struct tcb *const tcp, const kernel_ulong_t arg,
785                 const bool is_get)
786 {
787         struct v4l2_crop c;
788
789         if (entering(tcp)) {
790                 tprints(", ");
791                 if (umove_or_printaddr(tcp, arg, &c))
792                         return RVAL_IOCTL_DECODED;
793                 tprints("{type=");
794                 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
795                 if (is_get)
796                         return 0;
797                 tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
798         } else {
799                 if (!syserror(tcp) && !umove(tcp, arg, &c))
800                         tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
801         }
802
803         tprints("}");
804
805         return RVAL_IOCTL_DECODED;
806 }
807
808 #ifdef VIDIOC_S_EXT_CTRLS
809 static bool
810 print_v4l2_ext_control(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
811 {
812         const struct_v4l2_ext_control *p = elem_buf;
813
814         tprints("{id=");
815         printxval(v4l2_control_ids, p->id, "V4L2_CID_???");
816 # if HAVE_DECL_V4L2_CTRL_TYPE_STRING
817         tprintf(", size=%u", p->size);
818         if (p->size > 0) {
819                 tprints(", string=");
820                 printstrn(tcp, ptr_to_kulong(p->string), p->size);
821         } else
822 # endif
823         tprintf(", value=%d, value64=%" PRId64, p->value, (int64_t) p->value64);
824         tprints("}");
825
826         return true;
827 }
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                                  tfetch_mem_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 }