[PATCH] v4l2.c: a new (incomplete) decoder for Video4Linux ioctls args

Philippe De Muyter phdm at macqel.be
Fri May 30 09:44:41 UTC 2014


* v4l2.c: new file.
* ioctl.c, defs.h, Makefile.am: hook v4l2.o:v4l2_ioctl into strace.
* NEWS: spread the news :)

Introduce v4l2.c, a decoder for a subset of the v4l2 ioctl's args.
This is a combination of
- previous work by Peter Zotov <whitequark at whitequark.org>, found at
  https://gist.githubusercontent.com/whitequark/1263207/raw/strace-4.6-v4l2-ioctls.patch
- previous work by William Manley <will at williammanley.net>, found at
  http://marc.info/?l=strace&m=139395588520675&w=2
- additions and fixes by Philippe De Muyter <phdm at macqel.be>

As v4l2 is a moving target, I have made v4l2.c compilable with ancient linux
kernels by testing the availability of some macros.  It as been succesfully
compiled on linux 3.10, 3.1, 2.6.31 and 2.6.22, and succesfully used on
linux 3.10 with a camera device.

Signed-off-by: Philippe De Muyter <phdm at macqel.be>
Cc: Peter Zotov <whitequark at whitequark.org>
Cc: William Manley <will at williammanley.net>
---
 Makefile.am |    1 +
 NEWS        |    1 +
 defs.h      |    1 +
 ioctl.c     |    3 +
 v4l2.c      |  845 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 851 insertions(+)
 create mode 100644 v4l2.c

diff --git a/Makefile.am b/Makefile.am
index a789b8c..1b50277 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -50,6 +50,7 @@ strace_SOURCES =	\
 	term.c		\
 	time.c		\
 	util.c		\
+	v4l2.c		\
 	vsprintf.c
 
 noinst_HEADERS = defs.h
diff --git a/NEWS b/NEWS
index 895649c..a6f088d 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ Noteworthy changes in release ?.? (????-??-??)
 
 * Improvements
   * Added -w option to produce stats on syscall latency
+  * Added a (incomplete) decoder for Video4Linux (v4l2) ioctl args
 
 Noteworthy changes in release 4.8 (2013-06-03)
 ==============================================
diff --git a/defs.h b/defs.h
index 34a8874..b84bf59 100644
--- a/defs.h
+++ b/defs.h
@@ -708,6 +708,7 @@ extern int proc_ioctl(struct tcb *, int, int);
 extern int rtc_ioctl(struct tcb *, long, long);
 extern int scsi_ioctl(struct tcb *, long, long);
 extern int block_ioctl(struct tcb *, long, long);
+extern int v4l2_ioctl(struct tcb *, long, long);
 extern int mtd_ioctl(struct tcb *, long, long);
 extern int ubi_ioctl(struct tcb *, long, long);
 extern int loop_ioctl(struct tcb *, long, long);
diff --git a/ioctl.c b/ioctl.c
index 3f6c410..14bb7ed 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -97,6 +97,8 @@ ioctl_decode(struct tcb *tcp, long code, long arg)
 	case 'o':
 	case 'O':
 		return ubi_ioctl(tcp, code, arg);
+	case 'V':
+		return v4l2_ioctl(tcp, code, arg);
 	case '=':
 		return ptp_ioctl(tcp, code, arg);
 	default:
@@ -149,6 +151,7 @@ ioctl_decode(struct tcb *tcp, long code, long arg)
  *   t	sys/ttycom.h			(possible overlap)
  *   v	sundev/vuid_event.h		*overlap*
  *   v	sys/vcmd.h			*overlap*
+ *   V	linux/videodev2.h
  *
  * End of Registry
  */
diff --git a/v4l2.c b/v4l2.c
new file mode 100644
index 0000000..d13fff5
--- /dev/null
+++ b/v4l2.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright (c) 2014 Philippe De Muyter <phdm at macqel.be>
+ * Copyright (c) 2014 William Manley <will at williammanley.net>
+ * Copyright (c) 2011 Peter Zotov <whitequark at whitequark.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+
+#ifdef linux
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+
+static const struct xlat device_capabilities_flags[] = {
+	XLAT(V4L2_CAP_VIDEO_CAPTURE),
+	XLAT(V4L2_CAP_VIDEO_OUTPUT),
+	XLAT(V4L2_CAP_VIDEO_OVERLAY),
+	XLAT(V4L2_CAP_VBI_CAPTURE),
+	XLAT(V4L2_CAP_VBI_OUTPUT),
+	XLAT(V4L2_CAP_SLICED_VBI_CAPTURE),
+	XLAT(V4L2_CAP_SLICED_VBI_OUTPUT),
+	XLAT(V4L2_CAP_RDS_CAPTURE),
+	XLAT(V4L2_CAP_VIDEO_OUTPUT_OVERLAY),
+#ifdef V4L2_CAP_HW_FREQ_SEEK
+	XLAT(V4L2_CAP_HW_FREQ_SEEK),
+#endif
+#ifdef V4L2_CAP_RDS_OUTPUT
+	XLAT(V4L2_CAP_RDS_OUTPUT),
+	XLAT(V4L2_CAP_VIDEO_CAPTURE_MPLANE),
+	XLAT(V4L2_CAP_VIDEO_OUTPUT_MPLANE),
+#endif
+#ifdef V4L2_CAP_VIDEO_M2M
+	XLAT(V4L2_CAP_VIDEO_M2M),
+	XLAT(V4L2_CAP_VIDEO_M2M_MPLANE),
+#endif
+	XLAT(V4L2_CAP_TUNER),
+	XLAT(V4L2_CAP_AUDIO),
+	XLAT(V4L2_CAP_RADIO),
+#ifdef V4L2_CAP_MODULATOR
+	XLAT(V4L2_CAP_MODULATOR),
+#endif
+	XLAT(V4L2_CAP_READWRITE),
+	XLAT(V4L2_CAP_ASYNCIO),
+	XLAT(V4L2_CAP_STREAMING),
+#ifdef V4L2_CAP_DEVICE_CAPS
+	XLAT(V4L2_CAP_DEVICE_CAPS),
+	XLAT_END
+#endif
+};
+
+static const struct xlat v4l2_buf_types[] = {
+	XLAT(V4L2_BUF_TYPE_VIDEO_CAPTURE),
+#ifdef V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+	XLAT(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE),
+#endif
+	XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT),
+#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
+	XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE),
+#endif
+	XLAT(V4L2_BUF_TYPE_VIDEO_OVERLAY),
+	XLAT(V4L2_BUF_TYPE_VBI_CAPTURE),
+	XLAT(V4L2_BUF_TYPE_VBI_OUTPUT),
+	XLAT(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE),
+	XLAT(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT),
+	XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY),
+	XLAT_END
+};
+
+static const struct xlat v4l2_buf_flags[] = {
+	XLAT(V4L2_BUF_FLAG_MAPPED),
+	XLAT(V4L2_BUF_FLAG_QUEUED),
+	XLAT(V4L2_BUF_FLAG_DONE),
+	XLAT(V4L2_BUF_FLAG_KEYFRAME),
+	XLAT(V4L2_BUF_FLAG_PFRAME),
+	XLAT(V4L2_BUF_FLAG_BFRAME),
+	XLAT(V4L2_BUF_FLAG_TIMECODE),
+#ifdef V4L2_BUF_FLAG_INPUT
+	XLAT(V4L2_BUF_FLAG_INPUT),
+#endif
+	XLAT_END
+};
+
+static const struct xlat v4l2_framesize_types[] = {
+	XLAT(V4L2_FRMSIZE_TYPE_DISCRETE),
+	XLAT(V4L2_FRMSIZE_TYPE_CONTINUOUS),
+	XLAT(V4L2_FRMSIZE_TYPE_STEPWISE),
+	XLAT_END
+};
+
+static const struct xlat v4l2_frameinterval_types[] = {
+	XLAT(V4L2_FRMIVAL_TYPE_DISCRETE),
+	XLAT(V4L2_FRMIVAL_TYPE_CONTINUOUS),
+	XLAT(V4L2_FRMIVAL_TYPE_STEPWISE),
+	XLAT_END
+};
+
+static const struct xlat v4l2_fields[] = {
+	XLAT(V4L2_FIELD_ANY),
+	XLAT(V4L2_FIELD_NONE),
+	XLAT(V4L2_FIELD_TOP),
+	XLAT(V4L2_FIELD_BOTTOM),
+	XLAT(V4L2_FIELD_INTERLACED),
+	XLAT(V4L2_FIELD_SEQ_TB),
+	XLAT(V4L2_FIELD_SEQ_BT),
+	XLAT(V4L2_FIELD_ALTERNATE),
+	XLAT(V4L2_FIELD_INTERLACED_TB),
+	XLAT(V4L2_FIELD_INTERLACED_BT),
+	XLAT_END
+};
+
+static const struct xlat v4l2_colorspaces[] = {
+	XLAT(V4L2_COLORSPACE_SMPTE170M),
+	XLAT(V4L2_COLORSPACE_SMPTE240M),
+	XLAT(V4L2_COLORSPACE_REC709),
+	XLAT(V4L2_COLORSPACE_BT878),
+	XLAT(V4L2_COLORSPACE_470_SYSTEM_M),
+	XLAT(V4L2_COLORSPACE_470_SYSTEM_BG),
+	XLAT(V4L2_COLORSPACE_JPEG),
+	XLAT(V4L2_COLORSPACE_SRGB),
+	XLAT_END
+};
+
+static const struct xlat v4l2_format_description_flags[] = {
+	XLAT(V4L2_FMT_FLAG_COMPRESSED),
+#ifdef V4L2_FMT_FLAG_EMULATED
+	XLAT(V4L2_FMT_FLAG_EMULATED),
+#endif
+	XLAT_END
+};
+
+static const struct xlat v4l2_memories[] = {
+	XLAT(V4L2_MEMORY_MMAP),
+	XLAT(V4L2_MEMORY_USERPTR),
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_ids[] = {
+	XLAT(0),
+	XLAT(V4L2_CID_BRIGHTNESS),
+	XLAT(V4L2_CID_CONTRAST),
+	XLAT(V4L2_CID_SATURATION),
+	XLAT(V4L2_CID_HUE),
+	XLAT(V4L2_CID_AUDIO_VOLUME),
+	XLAT(V4L2_CID_AUDIO_BALANCE),
+	XLAT(V4L2_CID_AUDIO_BASS),
+	XLAT(V4L2_CID_AUDIO_TREBLE),
+	XLAT(V4L2_CID_AUDIO_MUTE),
+	XLAT(V4L2_CID_AUDIO_LOUDNESS),
+	XLAT(V4L2_CID_BLACK_LEVEL),
+	XLAT(V4L2_CID_AUTO_WHITE_BALANCE),
+	XLAT(V4L2_CID_DO_WHITE_BALANCE),
+	XLAT(V4L2_CID_RED_BALANCE),
+	XLAT(V4L2_CID_BLUE_BALANCE),
+	XLAT(V4L2_CID_GAMMA),
+	XLAT(V4L2_CID_WHITENESS),
+	XLAT(V4L2_CID_EXPOSURE),
+	XLAT(V4L2_CID_AUTOGAIN),
+	XLAT(V4L2_CID_GAIN),
+	XLAT(V4L2_CID_HFLIP),
+	XLAT(V4L2_CID_VFLIP),
+#ifdef V4L2_CID_POWER_LINE_FREQUENCY
+	XLAT(V4L2_CID_POWER_LINE_FREQUENCY),
+	XLAT(V4L2_CID_HUE_AUTO),
+	XLAT(V4L2_CID_WHITE_BALANCE_TEMPERATURE),
+	XLAT(V4L2_CID_SHARPNESS),
+	XLAT(V4L2_CID_BACKLIGHT_COMPENSATION),
+	XLAT(V4L2_CID_CHROMA_AGC),
+#endif
+#ifdef V4L2_CID_CHROMA_GAIN
+	XLAT(V4L2_CID_CHROMA_GAIN),
+#endif
+#ifdef V4L2_CID_COLOR_KILLER
+	XLAT(V4L2_CID_COLOR_KILLER),
+	XLAT(V4L2_CID_COLORFX),
+#endif
+#ifdef V4L2_CID_COLORFX_CBCR
+	XLAT(V4L2_CID_COLORFX_CBCR),
+#endif
+#ifdef V4L2_CID_AUTOBRIGHTNESS
+	XLAT(V4L2_CID_AUTOBRIGHTNESS),
+#endif
+#ifdef V4L2_CID_ROTATE
+	XLAT(V4L2_CID_ROTATE),
+	XLAT(V4L2_CID_BG_COLOR),
+	XLAT(V4L2_CID_ILLUMINATORS_1),
+	XLAT(V4L2_CID_ILLUMINATORS_2),
+	XLAT(V4L2_CID_MIN_BUFFERS_FOR_CAPTURE),
+	XLAT(V4L2_CID_MIN_BUFFERS_FOR_OUTPUT),
+#endif
+#ifdef V4L2_CID_ALPHA_COMPONENT
+	XLAT(V4L2_CID_ALPHA_COMPONENT),
+#endif
+	/*  Camera class control IDs */
+#ifdef V4L2_CID_EXPOSURE_AUTO
+	XLAT(V4L2_CID_EXPOSURE_AUTO),
+	XLAT(V4L2_CID_EXPOSURE_ABSOLUTE),
+	XLAT(V4L2_CID_EXPOSURE_AUTO_PRIORITY),
+	XLAT(V4L2_CID_PAN_RELATIVE),
+	XLAT(V4L2_CID_TILT_RELATIVE),
+	XLAT(V4L2_CID_PAN_RESET),
+	XLAT(V4L2_CID_TILT_RESET),
+	XLAT(V4L2_CID_PAN_ABSOLUTE),
+	XLAT(V4L2_CID_TILT_ABSOLUTE),
+	XLAT(V4L2_CID_FOCUS_ABSOLUTE),
+	XLAT(V4L2_CID_FOCUS_RELATIVE),
+	XLAT(V4L2_CID_FOCUS_AUTO),
+	XLAT(V4L2_CID_ZOOM_ABSOLUTE),
+	XLAT(V4L2_CID_ZOOM_RELATIVE),
+	XLAT(V4L2_CID_ZOOM_CONTINUOUS),
+	XLAT(V4L2_CID_PRIVACY),
+#endif
+#ifdef V4L2_CID_IRIS_ABSOLUTE
+	XLAT(V4L2_CID_IRIS_ABSOLUTE),
+	XLAT(V4L2_CID_IRIS_RELATIVE),
+#endif
+#ifdef V4L2_CID_AUTO_EXPOSURE_BIAS
+	XLAT(V4L2_CID_AUTO_EXPOSURE_BIAS),
+	XLAT(V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE),
+	XLAT(V4L2_CID_WIDE_DYNAMIC_RANGE),
+	XLAT(V4L2_CID_IMAGE_STABILIZATION),
+	XLAT(V4L2_CID_ISO_SENSITIVITY),
+	XLAT(V4L2_CID_ISO_SENSITIVITY_AUTO),
+	XLAT(V4L2_CID_EXPOSURE_METERING),
+	XLAT(V4L2_CID_SCENE_MODE),
+	XLAT(V4L2_CID_3A_LOCK),
+	XLAT(V4L2_CID_AUTO_FOCUS_START),
+	XLAT(V4L2_CID_AUTO_FOCUS_STOP),
+	XLAT(V4L2_CID_AUTO_FOCUS_STATUS),
+	XLAT(V4L2_CID_AUTO_FOCUS_RANGE),
+#endif
+	XLAT(V4L2_CID_PRIVATE_BASE),
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_types[] = {
+	XLAT(V4L2_CTRL_TYPE_INTEGER),
+	XLAT(V4L2_CTRL_TYPE_BOOLEAN),
+	XLAT(V4L2_CTRL_TYPE_MENU),
+#ifdef V4L2_CTRL_TYPE_INTEGER_MENU
+	XLAT(V4L2_CTRL_TYPE_INTEGER_MENU),
+#endif
+#ifdef V4L2_CTRL_TYPE_BITMASK
+	XLAT(V4L2_CTRL_TYPE_BITMASK),
+#endif
+	XLAT(V4L2_CTRL_TYPE_BUTTON),
+	XLAT(V4L2_CTRL_TYPE_INTEGER64),
+#ifdef V4L2_CTRL_TYPE_STRING
+	XLAT(V4L2_CTRL_TYPE_STRING),
+#endif
+	XLAT(V4L2_CTRL_TYPE_CTRL_CLASS),
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_flags[] = {
+	XLAT(V4L2_CTRL_FLAG_DISABLED),
+	XLAT(V4L2_CTRL_FLAG_GRABBED),
+	XLAT(V4L2_CTRL_FLAG_READ_ONLY),
+	XLAT(V4L2_CTRL_FLAG_UPDATE),
+	XLAT(V4L2_CTRL_FLAG_INACTIVE),
+	XLAT(V4L2_CTRL_FLAG_SLIDER),
+#ifdef V4L2_CTRL_FLAG_WRITE_ONLY
+	XLAT(V4L2_CTRL_FLAG_WRITE_ONLY),
+#endif
+#ifdef V4L2_CTRL_FLAG_VOLATILE
+	XLAT(V4L2_CTRL_FLAG_VOLATILE),
+#endif
+	XLAT_END
+};
+
+static const struct xlat v4l2_control_classes[] = {
+	XLAT(V4L2_CTRL_CLASS_USER),
+	XLAT(V4L2_CTRL_CLASS_MPEG),
+#ifdef V4L2_CTRL_CLASS_CAMERA
+	XLAT(V4L2_CTRL_CLASS_CAMERA),
+#endif
+#ifdef V4L2_CTRL_CLASS_FM_TX
+	XLAT(V4L2_CTRL_CLASS_FM_TX),
+	XLAT(V4L2_CTRL_CLASS_FLASH),
+#endif
+#ifdef V4L2_CTRL_CLASS_JPEG
+	XLAT(V4L2_CTRL_CLASS_JPEG),
+	XLAT(V4L2_CTRL_CLASS_IMAGE_SOURCE),
+	XLAT(V4L2_CTRL_CLASS_IMAGE_PROC),
+	XLAT(V4L2_CTRL_CLASS_FM_RX),
+#endif
+	XLAT_END
+};
+
+static const struct xlat v4l2_streaming_capabilities[] = {
+	XLAT(V4L2_CAP_TIMEPERFRAME),
+	XLAT_END
+};
+
+static const struct xlat v4l2_capture_modes[] = {
+	XLAT(V4L2_MODE_HIGHQUALITY),
+	XLAT_END
+};
+
+static const struct xlat v4l2_input_types[] = {
+	XLAT(V4L2_INPUT_TYPE_TUNER),
+	XLAT(V4L2_INPUT_TYPE_CAMERA),
+	XLAT_END
+};
+
+#define FMT_FRACT "%u/%u"
+#define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
+
+#define FMT_RECT "{left=%i, top=%i, width=%i, height=%i}"
+#define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
+
+static void print_pixelformat(__u32 fourcc)
+{
+#if (WORDS_BIGENDIAN == 1)
+	fourcc = htole32(fourcc);
+#endif
+	tprintf("%.4s", (char*)&fourcc);
+}
+
+static void print_v4l2_format(const struct v4l2_format *fmt)
+{
+	tprintf("type=");
+	printxval(v4l2_buf_types, fmt->type, "V4L2_BUF_TYPE_???");
+	tprintf(", fmt={");
+	switch (fmt->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		tprintf("pix={width=%u, height=%u, pixelformat=", fmt->fmt.pix.width, fmt->fmt.pix.height);
+		print_pixelformat(fmt->fmt.pix.pixelformat);
+		tprintf(", field=");
+		printxval(v4l2_fields, fmt->fmt.pix.field, "V4L2_FIELD_???");
+		tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
+			fmt->fmt.pix.bytesperline, fmt->fmt.pix.sizeimage);
+		printxval(v4l2_colorspaces, fmt->fmt.pix.colorspace,
+			  "V4L2_COLORSPACE_???");
+		tprintf("}");
+		break;
+#ifdef V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
+		int i;
+		tprintf("pix_mp={width=%u, height=%u, pixelformat=", fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height);
+		print_pixelformat(fmt->fmt.pix_mp.pixelformat);
+		tprintf(", field=");
+		printxval(v4l2_fields, fmt->fmt.pix_mp.field, "V4L2_FIELD_???");
+		tprintf(", colorspace=");
+		printxval(v4l2_colorspaces, fmt->fmt.pix_mp.colorspace,
+			  "V4L2_COLORSPACE_???");
+		tprintf("plane_fmt=[");
+		for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
+			if (i > 0)
+				tprintf(", ");
+			tprintf("{sizeimage=%u, bytesperline=%u}",
+				fmt->fmt.pix_mp.plane_fmt[i].sizeimage,
+				fmt->fmt.pix_mp.plane_fmt[i].bytesperline);
+		}
+		tprintf("], num_planes=%u", (unsigned) fmt->fmt.pix_mp.num_planes);
+		break;
+	}
+#endif
+
+	/* TODO: Complete this switch statement */
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+		tprintf("win={???}");
+		break;
+
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+		tprintf("vbi={???}");
+		break;
+
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		tprintf("sliced={???}");
+		break;
+
+	default:
+		tprintf("???");
+		break;
+	}
+	tprintf("}");
+}
+
+int
+v4l2_ioctl(struct tcb *tcp, long code, long arg)
+{
+	if (!verbose(tcp))
+		return 0;
+
+	switch (code) {
+	case VIDIOC_QUERYCAP: /* decode on exit */ {
+		struct v4l2_capability caps;
+		if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &caps) < 0)
+			return 0;
+
+		tprintf(", {driver=\"%s\", card=\"%s\", bus_info=\"%s\", "
+			"version=%u.%u.%u, capabilities=", caps.driver, caps.card,
+			caps.bus_info, (caps.version >> 16) & 0xFF,
+			(caps.version >> 8) & 0xFF, caps.version & 0xFF);
+		printflags(device_capabilities_flags, caps.capabilities,
+			   "V4L2_CAP_???");
+#ifdef V4L2_CAP_DEVICE_CAPS
+		tprintf(", device_caps=");
+		printflags(device_capabilities_flags, caps.device_caps,
+			   "V4L2_CAP_???");
+#endif
+		tprintf("}");
+		return 1;
+	}
+
+	case VIDIOC_ENUM_FRAMESIZES: /* decode on exit */ {
+		struct v4l2_frmsizeenum s;
+
+		if (entering(tcp) || umove(tcp, arg, &s) < 0)
+			return 0;
+		tprintf(", {index=%u, pixel_format=", s.index);
+		print_pixelformat(s.pixel_format);
+
+		if (!syserror(tcp)) {
+			tprintf(", type=");
+			printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
+			switch (s.type) {
+			case V4L2_FRMSIZE_TYPE_DISCRETE:
+				tprintf(", discrete={width=%u, height=%u}",
+					s.discrete.width, s.discrete.height);
+				break;
+			case V4L2_FRMSIZE_TYPE_STEPWISE:
+				tprintf(", stepwise={min_width=%u, max_width=%u, "
+					"step_width=%u, min_height=%u, max_height=%u, "
+					"step_height=%u}",
+					s.stepwise.min_width, s.stepwise.max_width,
+					s.stepwise.step_width, s.stepwise.min_height,
+					s.stepwise.max_height, s.stepwise.step_height);
+				break;
+			}
+		}
+		tprintf("}");
+		return 1;
+	}
+
+	case VIDIOC_G_FMT:
+	case VIDIOC_S_FMT:
+	case VIDIOC_TRY_FMT: {
+		struct v4l2_format f;
+
+		if (umove(tcp, arg, &f) < 0) {
+			tprintf(", %#lx", arg);
+		} else {
+			if (entering(tcp)) {
+				tprintf(", {type=");
+				printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
+			}
+			if (code == VIDIOC_G_FMT && entering(tcp)) {
+				tprintf("}");
+				return 1;
+			}
+#if 0
+			if (f.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+				f.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+				struct v4l2_pix_format *pix = &f.fmt.pix;
+
+				tprintf(", pix={width=%u, height=%u"
+					", pixelformat=",
+					pix->width, pix->height);
+
+				print_pixelformat(pix->pixelformat);
+				tprintf(", bytesperline=%u, sizeimage=%u",
+					pix->bytesperline, pix->sizeimage);
+
+				tprintf(", colorspace=");
+				printxval(v4l2_colorspaces, pix->colorspace, "V4L2_COLORSPACE_???");
+			tprintf("}");
+			}
+#else
+			print_v4l2_format(&f);
+#endif
+			tprintf(", ...}");
+		}
+		return 1;
+	}
+
+	case VIDIOC_ENUM_FMT: {
+		struct v4l2_fmtdesc f;
+
+		if (entering(tcp) || umove(tcp, arg, &f) < 0)
+			return 0;
+
+		tprintf(", {index=%u", f.index);
+
+		if (!syserror(tcp)) {
+			tprintf(", type=");
+			printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
+			tprintf(", flags=");
+			printflags(v4l2_format_description_flags, f.flags,
+				   "V4L2_FMT_FLAG_???");
+			tprintf(", description=\"%s\", pixelformat=",
+				f.description);
+			print_pixelformat(f.pixelformat);
+		}
+		tprintf("}");
+		return 1;
+	}
+
+	case VIDIOC_G_PARM:
+	case VIDIOC_S_PARM: {
+		struct v4l2_streamparm s;
+
+		if (entering(tcp))
+			return 1;
+		if (umove(tcp, arg, &s) < 0) {
+			tprintf(", %#lx", arg);
+		} else {
+			tprintf(", {type=");
+			printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
+
+			if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+				struct v4l2_captureparm *cap = &s.parm.capture;
+
+				tprintf(", capability=");
+				printflags(v4l2_streaming_capabilities,
+					cap->capability, "V4L2_CAP_???");
+
+				tprintf(", capturemode=");
+				printflags(v4l2_capture_modes,
+					cap->capturemode, "V4L2_MODE_???");
+
+#if 0
+				tprintf(", timeperframe={"
+					"numerator=%u, "
+					"denominator=%u}",
+					cap->timeperframe.numerator,
+					cap->timeperframe.denominator);
+#else
+				tprintf(", timeperframe=" FMT_FRACT,
+					ARGS_FRACT(cap->timeperframe));
+#endif
+
+				tprintf(", extendedmode=%u, readbuffers=%u}",
+					cap->extendedmode,
+					cap->readbuffers);
+			} else {
+				tprintf(", ...}");
+			}
+		}
+		return 1;
+	}
+
+	case VIDIOC_QUERYCTRL: {
+		struct v4l2_queryctrl c;
+
+		if (umove(tcp, arg, &c) < 0)
+			return 0;
+		/* 'id' field must be printed :
+		* on entering
+		* on exiting iff V4L2_CTRL_FLAG_NEXT_CTRL && !syserror(tcp)
+		*/
+		if (entering(tcp)
+		|| (exiting(tcp) && tcp->auxstr && !syserror(tcp))) {
+			tprintf(exiting(tcp) ? " => " : ", ");
+			tcp->auxstr = (char*)(c.id & V4L2_CTRL_FLAG_NEXT_CTRL);
+			if (tcp->auxstr) {
+				tprintf("V4L2_CTRL_FLAG_NEXT_CTRL|");
+				c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
+			}
+			printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
+		}
+		if (syserror(tcp) || entering(tcp))
+			return 1;
+		tprintf(", type=");
+		printxval(v4l2_control_types, c.type, "V4L2_CTRL_TYPE_???");
+		tprintf(", name=\"%s\", minimum=%i, maximum=%i, step=%i, "
+			"default_value=%i, flags=", c.name, c.minimum,
+			c.maximum, c.step, c.default_value);
+		printflags(v4l2_control_flags, c.flags, "V4L2_CTRL_FLAG_???");
+		return 1;
+	}
+
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL: {
+		struct v4l2_control c;
+
+		if (entering(tcp) || umove(tcp, arg, &c) < 0)
+			return 0;
+		tprintf(", {id=");
+		printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
+		if (!syserror(tcp) || code != VIDIOC_G_CTRL)
+			tprintf(", value=%i", c.value);
+		tprintf("}");
+		return 1;
+	}
+
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS: {
+		struct v4l2_ext_controls c;
+		unsigned n;
+
+		if (entering(tcp) || umove(tcp, arg, &c) < 0)
+			return 0;
+
+		tprintf(", ctrl_class=");
+		printxval(v4l2_control_classes, c.ctrl_class,
+			  "V4L2_CTRL_CLASS_???");
+		tprintf(", count=%u, error_idx=%u, controls=[", c.count,
+			c.error_idx);
+
+		for (n = 0; n < c.count; ++n) {
+			struct v4l2_ext_control ctrl;
+			if (n > 0)
+				tprintf(", ");
+			umove(tcp, (long) (c.controls + n), &ctrl);
+			tprintf("{id=");
+			printxval(v4l2_control_ids, ctrl.id, "V4L2_CID_???");
+#ifdef V4L2_CTRL_TYPE_STRING
+			tprintf(", size=%u", ctrl.size);
+			if (ctrl.size > 0) {
+				tprintf(", string=");
+				printstr(tcp, (long) ctrl.string, ctrl.size);
+			} else
+#endif
+			{
+				tprintf(", value=%i, value64=%lli", ctrl.value,
+					ctrl.value64);
+			}
+			tprintf("}");
+		}
+		return 1;
+	}
+
+	case VIDIOC_ENUMSTD: {
+		struct v4l2_standard s;
+
+		if (umove(tcp, arg, &s) < 0)
+			return 0;
+		if (entering(tcp))
+			tprintf(", {index=%i", s.index);
+		else {
+			if (!syserror(tcp)) {
+				tprintf(", name=\"%s\"", s.name);
+				tprintf(", frameperiod=" FMT_FRACT, ARGS_FRACT(s.frameperiod));
+				tprintf(", framelines=%i", s.framelines);
+			}
+			tprintf("}");
+		}
+		return 1;
+	}
+
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD: {
+		v4l2_std_id s;
+
+		if (code == VIDIOC_G_STD && exiting(tcp) && syserror(tcp))
+			return 0;
+		if (umove(tcp, arg, &s) < 0)
+			return 0;
+		if ((code == VIDIOC_S_STD) == entering(tcp))
+			tprintf(", std=%#llx", s);
+		return 1;
+	}
+
+	case VIDIOC_ENUMINPUT: {
+		struct v4l2_input i;
+
+		if (entering(tcp) || umove(tcp, arg, &i) < 0)
+			return 0;
+		tprintf(", {index=%i", i.index);
+		if (!syserror(tcp)) {
+			tprintf(", name=\"%s\", type=", i.name);
+			printxval(v4l2_input_types, i.type,
+							"V4L2_INPUT_TYPE_???");
+		}
+		tprintf("}");
+		return 1;
+	}
+
+	case VIDIOC_G_INPUT: {
+		int index;
+
+		if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &index) < 0)
+			return 0;
+
+		tprintf(", index=%i", index);
+		return 1;
+	}
+
+	case VIDIOC_ENUM_FRAMEINTERVALS: {
+		struct v4l2_frmivalenum f;
+
+		if (entering(tcp) || umove(tcp, arg, &f) < 0)
+			return 0;
+		tprintf(", {index=%i, pixel_format=", f.index);
+		print_pixelformat(f.pixel_format);
+		tprintf(", width=%u, height=%u", f.width, f.height);
+		if (!syserror(tcp)) {
+			tprintf(", type=");
+			printxval(v4l2_frameinterval_types, f.type,
+				  "V4L2_FRMIVAL_TYPE_???");
+			switch (f.type) {
+			case V4L2_FRMIVAL_TYPE_DISCRETE:
+				tprintf(", discrete=" FMT_FRACT,
+						ARGS_FRACT(f.discrete));
+				break;
+			case V4L2_FRMIVAL_TYPE_STEPWISE:
+			case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+				tprintf(", stepwise={min=" FMT_FRACT ", max="
+					FMT_FRACT ", step=" FMT_FRACT "}",
+					ARGS_FRACT(f.stepwise.min),
+					ARGS_FRACT(f.stepwise.max),
+					ARGS_FRACT(f.stepwise.step));
+				break;
+			}
+		}
+		tprintf("}");
+		return 1;
+	}
+
+	case VIDIOC_CROPCAP: {
+		struct v4l2_cropcap c;
+
+		if (entering(tcp) || umove(tcp, arg, &c) < 0)
+			return 0;
+		tprintf(", type=");
+		printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
+		if (syserror(tcp))
+			return 1;
+		tprintf(", bounds=" FMT_RECT ", defrect=" FMT_RECT ", "
+			"pixelaspect=" FMT_FRACT, ARGS_RECT(c.bounds),
+			ARGS_RECT(c.defrect), ARGS_FRACT(c.pixelaspect));
+		return 1;
+	}
+
+	case VIDIOC_G_FBUF:
+	case VIDIOC_S_FBUF: {
+		struct v4l2_framebuffer b;
+
+		if (entering(tcp) || umove(tcp, arg, &b) < 0)
+			return 0;
+		if (syserror(tcp) && code == VIDIOC_G_FBUF)
+			return 0;
+		tprintf(", {capability=%x", b.capability);
+		tprintf(", flags=%x", b.flags);
+		tprintf(", base=%p", b.base);
+		tprintf("}");
+		return 1;
+	}
+
+	case VIDIOC_REQBUFS: {
+		struct v4l2_requestbuffers reqbufs;
+
+		if (umove(tcp, arg, &reqbufs) < 0)
+			return 0;
+		if (entering(tcp)) {
+			tprintf(", {count=%u, type=", reqbufs.count);
+			printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
+			tprintf(", memory=");
+			printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
+			tprintf("}");
+			return 1;
+		} else {
+			static char outstr[32];
+
+			sprintf(outstr, "{count=%u}", reqbufs.count);
+			tcp->auxstr = outstr;
+			return 1 + RVAL_STR;
+		}
+	}
+
+	case VIDIOC_QUERYBUF:
+	case VIDIOC_QBUF:
+	case VIDIOC_DQBUF: {
+		struct v4l2_buffer buffer;
+
+		if (entering(tcp)) {
+			if (umove(tcp, arg, &buffer) < 0) {
+				tprintf(", %#lx", arg);
+			} else {
+				tprintf(", {type=");
+				printxval(v4l2_buf_types, buffer.type, "V4L2_BUF_TYPE_???");
+				tprintf(", index=%u", buffer.index);
+			}
+		} else {
+			if (umove(tcp, arg, &buffer) < 0) {
+				tprintf(", %#lx", arg);
+			} else {
+				tprintf(", memory=");
+				printxval(v4l2_memories, buffer.memory, "V4L2_MEMORY_???");
+
+				if (buffer.memory == V4L2_MEMORY_MMAP) {
+					tprintf(", m.offset=%#x", buffer.m.offset);
+				} else if (buffer.memory == V4L2_MEMORY_USERPTR) {
+					tprintf(", m.userptr=%#lx", buffer.m.userptr);
+				}
+
+				tprintf(", length=%u, bytesused=%u, flags=",
+					buffer.length, buffer.bytesused);
+				printflags(v4l2_buf_flags, buffer.flags, "V4L2_BUF_FLAG_???");
+				tprintf(", ...}");
+			}
+		}
+		return 1;
+	}
+
+	case VIDIOC_STREAMON:
+	case VIDIOC_STREAMOFF: {
+		int type;
+
+		if (exiting(tcp)) {
+			if (umove(tcp, arg, &type) < 0) {
+				tprintf(", %#lx", arg);
+			} else {
+				tprintf(", ");
+				printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
+			}
+		}
+		return 1;
+	}
+
+	default: /* decode on exit */
+		return 0;
+	}
+}
+#endif
-- 
1.7.10.4





More information about the Strace-devel mailing list