--- Makefile.am | 1 + defs.h | 1 + ioctl.c | 2 + v4l2.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 533 insertions(+) create mode 100644 v4l2.c
diff --git a/Makefile.am b/Makefile.am index 03d310b..c510463 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,6 +49,7 @@ strace_SOURCES = \ term.c \ time.c \ util.c \ + v4l2.c \ vsprintf.c noinst_HEADERS = defs.h diff --git a/defs.h b/defs.h index f457d30..1f80ea1 100644 --- a/defs.h +++ b/defs.h @@ -707,6 +707,7 @@ extern int mtd_ioctl(struct tcb *, long, long); extern int ubi_ioctl(struct tcb *, long, long); extern int loop_ioctl(struct tcb *, long, long); extern int ptp_ioctl(struct tcb *, long, long); +extern int v4l2_ioctl(struct tcb *, unsigned long, long); extern int tv_nz(struct timeval *); extern int tv_cmp(struct timeval *, struct timeval *); diff --git a/ioctl.c b/ioctl.c index 3f6c410..451fe31 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: diff --git a/v4l2.c b/v4l2.c new file mode 100644 index 0000000..1a8c436 --- /dev/null +++ b/v4l2.c @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2014 William Manley <w...@williammanley.net> + * 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" +#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), + XLAT(V4L2_CAP_HW_FREQ_SEEK), + XLAT(V4L2_CAP_RDS_OUTPUT), + XLAT(V4L2_CAP_VIDEO_CAPTURE_MPLANE), + XLAT(V4L2_CAP_VIDEO_OUTPUT_MPLANE), + XLAT(V4L2_CAP_VIDEO_M2M), + XLAT(V4L2_CAP_VIDEO_M2M_MPLANE), + XLAT(V4L2_CAP_TUNER), + XLAT(V4L2_CAP_AUDIO), + XLAT(V4L2_CAP_RADIO), + XLAT(V4L2_CAP_MODULATOR), + XLAT(V4L2_CAP_READWRITE), + XLAT(V4L2_CAP_ASYNCIO), + XLAT(V4L2_CAP_STREAMING), + XLAT(V4L2_CAP_DEVICE_CAPS), + XLAT_END +}; + +static const struct xlat v4l2_formats[] = { + XLAT(V4L2_BUF_TYPE_VIDEO_CAPTURE), + XLAT(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ), + XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT), + XLAT(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ), + 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_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), + XLAT(V4L2_FMT_FLAG_EMULATED), + XLAT_END +}; + +static const struct xlat v4l2_control_ids[] = { + 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), + 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), + XLAT(V4L2_CID_CHROMA_GAIN), + XLAT(V4L2_CID_COLOR_KILLER), + XLAT(V4L2_CID_COLORFX), + XLAT(V4L2_CID_COLORFX_CBCR), + XLAT(V4L2_CID_AUTOBRIGHTNESS), + 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), + XLAT(V4L2_CID_ALPHA_COMPONENT), + XLAT_END +}; + +static const struct xlat v4l2_control_types[] = { + XLAT(V4L2_CTRL_TYPE_INTEGER), + XLAT(V4L2_CTRL_TYPE_BOOLEAN), + XLAT(V4L2_CTRL_TYPE_MENU), + XLAT(V4L2_CTRL_TYPE_INTEGER_MENU), + XLAT(V4L2_CTRL_TYPE_BITMASK), + XLAT(V4L2_CTRL_TYPE_BUTTON), + XLAT(V4L2_CTRL_TYPE_INTEGER64), + XLAT(V4L2_CTRL_TYPE_STRING), + 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), + XLAT(V4L2_CTRL_FLAG_WRITE_ONLY), + XLAT(V4L2_CTRL_FLAG_VOLATILE), + XLAT_END +}; + +static const struct xlat v4l2_control_classes[] = { + XLAT(V4L2_CTRL_CLASS_USER), + XLAT(V4L2_CTRL_CLASS_MPEG), + XLAT(V4L2_CTRL_CLASS_CAMERA), + XLAT(V4L2_CTRL_CLASS_FM_TX), + XLAT(V4L2_CTRL_CLASS_FLASH), + XLAT(V4L2_CTRL_CLASS_JPEG), + XLAT(V4L2_CTRL_CLASS_IMAGE_SOURCE), + XLAT(V4L2_CTRL_CLASS_IMAGE_PROC), + XLAT(V4L2_CTRL_CLASS_FM_RX), + XLAT_END +}; + +#define PRINTF_FOURCC "%c%c%c%c" +#define FOURCC(x) (char) (x), (char) (x>>8), (char) (x>>16), (char) (x>>24) + +#define PRINTF_FRACT "%u/%u" +#define FRACT(x) ((x).numerator), ((x).denominator) + +#define PRINTF_RECT "{left=%i, top=%i, width=%i, height=%i}" +#define RECT(x) (x).left, (x).top, (x).width, (x).height + +static void print_v4l2_format(const struct v4l2_format* fmt) +{ + tprintf("type="); + printxval(v4l2_formats, 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=" PRINTF_FOURCC ", " + "field=", fmt->fmt.pix.width, fmt->fmt.pix.height, + FOURCC(fmt->fmt.pix.pixelformat)); + 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; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + { + int i; + tprintf("pix={width=%u, height=%u, pixelformat=" PRINTF_FOURCC ", " + "field=", fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height, + FOURCC(fmt->fmt.pix_mp.pixelformat)); + 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; + } + + /* 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, unsigned 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_???"); + tprintf(", device_caps="); + printflags(device_capabilities_flags, caps.device_caps, + "V4L2_CAP_???"); + 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=" PRINTF_FOURCC, s.index, + FOURCC(s.pixel_format)); + + if (syserror(tcp)) + return 1; + + 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: + { + struct v4l2_format f; + if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &f) < 0) + return 0; + + tprintf(", "); + print_v4l2_format(&f); + return 1; + } + + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + { + /* TODO: work out how strace deals with inout arguments and + implement */ + return 0; + } + + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc f; + + if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &f) < 0) + return 0; + + tprintf(", index=%u, type=", f.index); + printxval(v4l2_formats, f.type, "V4L2_BUF_TYPE_???"); + tprintf(", flags="); + printflags(v4l2_format_description_flags, f.flags, + "V4L2_FMT_FLAG_???"); + tprintf(", description=\"%s\", pixelformat=" PRINTF_FOURCC, + f.description, FOURCC(f.pixelformat)); + return 1; + } + + case VIDIOC_G_PARM: + { + struct v4l2_streamparm s; + + if (entering(tcp) || umove(tcp, arg, &s) < 0) + return 0; + + tprintf(", type="); + printxval(v4l2_formats, s.type, "V4L2_BUF_TYPE_???"); + + if (syserror(tcp)) + return 1; + + /* TODO: Decode struct v4l2_captureparm/v4l2_outputparm */ + tprintf(", parm={???}"); + return 1; + } + + case VIDIOC_S_PARM: + { + struct v4l2_streamparm s; + + if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &s) < 0) + return 0; + + tprintf(", type="); + printxval(v4l2_formats, s.type, "V4L2_BUF_TYPE_???"); + /* TODO: Decode struct v4l2_captureparm/v4l2_outputparm */ + tprintf(", parm={???}"); + return 1; + } + + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl c; + if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &c) < 0) + return 0; + + tprintf(", "); + printxval(v4l2_control_ids, c.id, "V4L2_CID_???"); + 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) + return 1; + + tprintf(", value=%i", c.value); + 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_???"); + tprintf(", size=%u", ctrl.size); + if (ctrl.size > 0) { + tprintf(", string="); + printstr(tcp, (long) ctrl.string, ctrl.size); + } + else { + tprintf(", value=%i, value64=%lli", ctrl.value, + ctrl.value64); + } + 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=" PRINTF_FOURCC ", width=%u, " + "height=%u", f.index, FOURCC(f.pixel_format), f.width, + f.height); + if (syserror(tcp)) + return 1; + tprintf(", type="); + printxval(v4l2_frameinterval_types, f.type, + "V4L2_FRMIVAL_TYPE_???"); + switch (f.type) + { + case V4L2_FRMIVAL_TYPE_DISCRETE: + tprintf(", discrete=" PRINTF_FRACT, FRACT(f.discrete)); + break; + case V4L2_FRMIVAL_TYPE_STEPWISE: + tprintf(", stepwise={min=" PRINTF_FRACT ", max=" + PRINTF_FRACT ", step=" PRINTF_FRACT "}", + FRACT(f.stepwise.min), FRACT(f.stepwise.max), + FRACT(f.stepwise.step)); + break; + } + return 1; + } + + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap c; + if (entering(tcp) || umove(tcp, arg, &c) < 0) + return 0; + + tprintf(", type="); + printxval(v4l2_formats, c.type, "V4L2_BUF_TYPE_???"); + if (syserror(tcp)) + return 1; + tprintf(", bounds=" PRINTF_RECT ", defrect=" PRINTF_RECT ", " + "pixelaspect=" PRINTF_FRACT, RECT(c.bounds), + RECT(c.defrect), FRACT(c.pixelaspect)); + return 1; + } + + default: /* decode on exit */ + return 0; + } +} -- 1.9.0 ------------------------------------------------------------------------------ Subversion Kills Productivity. Get off Subversion & Make the Move to Perforce. With Perforce, you get hassle-free workflows. Merge that actually works. Faster operations. Version large binaries. Built-in WAN optimization and the freedom to use Git, Perforce or both. Make the move to Perforce. http://pubads.g.doubleclick.net/gampad/clk?id=122218951&iu=/4140/ostg.clktrk _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel