Home | History | Annotate | Download | only in strace
      1 /*
      2  * Copyright (c) 2014 Philippe De Muyter <phdm (at) macqel.be>
      3  * Copyright (c) 2014 William Manley <will (at) williammanley.net>
      4  * Copyright (c) 2011 Peter Zotov <whitequark (at) whitequark.org>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "defs.h"
     31 
     32 #include <stdint.h>
     33 #include <sys/ioctl.h>
     34 #include <linux/types.h>
     35 #include <linux/videodev2.h>
     36 /* some historical constants */
     37 #ifndef V4L2_CID_HCENTER
     38 #define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
     39 #endif
     40 #ifndef V4L2_CID_VCENTER
     41 #define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
     42 #endif
     43 #ifndef V4L2_CID_BAND_STOP_FILTER
     44 #define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33)
     45 #endif
     46 
     47 #include "xlat/v4l2_device_capabilities_flags.h"
     48 #include "xlat/v4l2_buf_types.h"
     49 #include "xlat/v4l2_buf_flags.h"
     50 #include "xlat/v4l2_framesize_types.h"
     51 #include "xlat/v4l2_frameinterval_types.h"
     52 #include "xlat/v4l2_fields.h"
     53 #include "xlat/v4l2_colorspaces.h"
     54 #include "xlat/v4l2_format_description_flags.h"
     55 #include "xlat/v4l2_memories.h"
     56 #include "xlat/v4l2_control_ids.h"
     57 #include "xlat/v4l2_control_types.h"
     58 #include "xlat/v4l2_control_flags.h"
     59 #include "xlat/v4l2_control_classes.h"
     60 #include "xlat/v4l2_streaming_capabilities.h"
     61 #include "xlat/v4l2_capture_modes.h"
     62 #include "xlat/v4l2_input_types.h"
     63 
     64 #define FMT_FRACT "%u/%u"
     65 #define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
     66 
     67 #define FMT_RECT "{left=%i, top=%i, width=%i, height=%i}"
     68 #define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
     69 
     70 static void print_pixelformat(uint32_t fourcc)
     71 {
     72 	union {
     73 		uint32_t pixelformat;
     74 		unsigned char cc[sizeof(uint32_t)];
     75 	} u = {
     76 		.pixelformat =
     77 #if WORDS_BIGENDIAN
     78 			htole32(fourcc)
     79 #else
     80 			fourcc
     81 #endif
     82 	};
     83 	unsigned int i;
     84 
     85 	tprints("v4l2_fourcc(");
     86 	for (i = 0; i < sizeof(u.cc); ++i) {
     87 		unsigned int c = u.cc[i];
     88 
     89 		if (i)
     90 			tprints(", ");
     91 		if (c == ' ' ||
     92 		    (c >= '0' && c <= '9') ||
     93 		    (c >= 'A' && c <= 'Z') ||
     94 		    (c >= 'a' && c <= 'z')) {
     95 			char sym[] = {
     96 				'\'',
     97 				u.cc[i],
     98 				'\''
     99 			};
    100 			tprints(sym);
    101 		} else {
    102 			char hex[] = {
    103 				'\'',
    104 				'\\',
    105 				'x',
    106 				"0123456789abcdef"[c >> 4],
    107 				"0123456789abcdef"[c & 0xf],
    108 				'\'',
    109 				'\0'
    110 			};
    111 			tprints(hex);
    112 		}
    113 	}
    114 	tprints(")");
    115 }
    116 
    117 static void print_v4l2_format_fmt(const struct v4l2_format *f)
    118 {
    119 	tprints("fmt.");
    120 	switch (f->type) {
    121 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
    122 	case V4L2_BUF_TYPE_VIDEO_OUTPUT: {
    123 		const struct v4l2_pix_format *pix = &f->fmt.pix;
    124 
    125 		tprintf("pix={width=%u, height=%u, pixelformat=",
    126 			pix->width, pix->height);
    127 		print_pixelformat(pix->pixelformat);
    128 		tprints(", field=");
    129 		printxval(v4l2_fields, pix->field, "V4L2_FIELD_???");
    130 		tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
    131 			pix->bytesperline, pix->sizeimage);
    132 		printxval(v4l2_colorspaces, pix->colorspace,
    133 			  "V4L2_COLORSPACE_???");
    134 		tprints("}");
    135 		break;
    136 	}
    137 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
    138 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
    139 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
    140 		const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
    141 		unsigned int i, max;
    142 
    143 		tprintf("pix_mp={width=%u, height=%u, pixelformat=",
    144 			pix_mp->width, pix_mp->height);
    145 		print_pixelformat(pix_mp->pixelformat);
    146 		tprints(", field=");
    147 		printxval(v4l2_fields, pix_mp->field, "V4L2_FIELD_???");
    148 		tprints(", colorspace=");
    149 		printxval(v4l2_colorspaces, pix_mp->colorspace,
    150 			  "V4L2_COLORSPACE_???");
    151 		tprints("plane_fmt=[");
    152 		max = pix_mp->num_planes;
    153 		if (max > VIDEO_MAX_PLANES)
    154 			max = VIDEO_MAX_PLANES;
    155 		for (i = 0; i < max; i++) {
    156 			if (i > 0)
    157 				tprints(", ");
    158 			tprintf("{sizeimage=%u, bytesperline=%u}",
    159 				pix_mp->plane_fmt[i].sizeimage,
    160 				pix_mp->plane_fmt[i].bytesperline);
    161 		}
    162 		tprintf("], num_planes=%u}", (unsigned) pix_mp->num_planes);
    163 		break;
    164 	}
    165 #endif
    166 
    167 	/* TODO: Complete this switch statement */
    168 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
    169 #if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
    170 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
    171 #endif
    172 		tprints("win={???}");
    173 		break;
    174 
    175 	case V4L2_BUF_TYPE_VBI_CAPTURE:
    176 	case V4L2_BUF_TYPE_VBI_OUTPUT:
    177 		tprints("vbi={???}");
    178 		break;
    179 
    180 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
    181 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
    182 		tprints("sliced={???}");
    183 		break;
    184 
    185 	default:
    186 		tprints("???");
    187 		break;
    188 	}
    189 }
    190 
    191 int
    192 v4l2_ioctl(struct tcb *tcp, const unsigned int code, long arg)
    193 {
    194 	if (!verbose(tcp))
    195 		return 0;
    196 
    197 	switch (code) {
    198 	case VIDIOC_QUERYCAP: /* decode on exit */ {
    199 		struct v4l2_capability caps;
    200 
    201 		if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &caps) < 0)
    202 			return 0;
    203 		tprints(", {driver=");
    204 		print_quoted_string((const char *) caps.driver,
    205 				    sizeof(caps.driver), QUOTE_0_TERMINATED);
    206 		tprints(", card=");
    207 		print_quoted_string((const char *) caps.card,
    208 				    sizeof(caps.card), QUOTE_0_TERMINATED);
    209 		tprints(", bus_info=");
    210 		print_quoted_string((const char *) caps.bus_info,
    211 				    sizeof(caps.bus_info), QUOTE_0_TERMINATED);
    212 		tprintf(", version=%u.%u.%u, capabilities=",
    213 			(caps.version >> 16) & 0xFF,
    214 			(caps.version >> 8) & 0xFF,
    215 			caps.version & 0xFF);
    216 		printflags(v4l2_device_capabilities_flags, caps.capabilities,
    217 			   "V4L2_CAP_???");
    218 #ifdef V4L2_CAP_DEVICE_CAPS
    219 		tprints(", device_caps=");
    220 		printflags(v4l2_device_capabilities_flags, caps.device_caps,
    221 			   "V4L2_CAP_???");
    222 #endif
    223 		tprints("}");
    224 		return 1;
    225 	}
    226 
    227 #ifdef VIDIOC_ENUM_FRAMESIZES
    228 	case VIDIOC_ENUM_FRAMESIZES: /* decode on exit */ {
    229 		struct v4l2_frmsizeenum s;
    230 
    231 		if (entering(tcp) || umove(tcp, arg, &s) < 0)
    232 			return 0;
    233 		tprintf(", {index=%u, pixel_format=", s.index);
    234 		print_pixelformat(s.pixel_format);
    235 
    236 		if (!syserror(tcp)) {
    237 			tprints(", type=");
    238 			printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
    239 			switch (s.type) {
    240 			case V4L2_FRMSIZE_TYPE_DISCRETE:
    241 				tprintf(", discrete={width=%u, height=%u}",
    242 					s.discrete.width, s.discrete.height);
    243 				break;
    244 			case V4L2_FRMSIZE_TYPE_STEPWISE:
    245 				tprintf(", stepwise={min_width=%u, max_width=%u, "
    246 					"step_width=%u, min_height=%u, max_height=%u, "
    247 					"step_height=%u}",
    248 					s.stepwise.min_width, s.stepwise.max_width,
    249 					s.stepwise.step_width, s.stepwise.min_height,
    250 					s.stepwise.max_height, s.stepwise.step_height);
    251 				break;
    252 			}
    253 		}
    254 		tprints("}");
    255 		return 1;
    256 	}
    257 #endif /* VIDIOC_ENUM_FRAMESIZES */
    258 
    259 	case VIDIOC_G_FMT:
    260 	case VIDIOC_S_FMT:
    261 	case VIDIOC_TRY_FMT: {
    262 		struct v4l2_format f;
    263 
    264 		if (umove(tcp, arg, &f) < 0)
    265 			return 0;
    266 		if (entering(tcp)) {
    267 			tprints(", {type=");
    268 			printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
    269 		}
    270 		if ((entering(tcp) && code != VIDIOC_G_FMT)
    271 		    || (exiting(tcp) && !syserror(tcp))) {
    272 			tprints(exiting(tcp) && code != VIDIOC_G_FMT ? " => " : ", ");
    273 			print_v4l2_format_fmt(&f);
    274 		}
    275 		if (exiting(tcp))
    276 			tprints("}");
    277 		return 1;
    278 	}
    279 
    280 	case VIDIOC_ENUM_FMT: {
    281 		struct v4l2_fmtdesc f;
    282 
    283 		if (entering(tcp) || umove(tcp, arg, &f) < 0)
    284 			return 0;
    285 
    286 		tprintf(", {index=%u", f.index);
    287 		if (!syserror(tcp)) {
    288 			tprints(", type=");
    289 			printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
    290 			tprints(", flags=");
    291 			printflags(v4l2_format_description_flags, f.flags,
    292 				   "V4L2_FMT_FLAG_???");
    293 			tprints(", description=");
    294 			print_quoted_string((const char *) f.description,
    295 					    sizeof(f.description),
    296 					    QUOTE_0_TERMINATED);
    297 			tprints(", pixelformat=");
    298 			print_pixelformat(f.pixelformat);
    299 		}
    300 		tprints("}");
    301 		return 1;
    302 	}
    303 
    304 	case VIDIOC_G_PARM:
    305 	case VIDIOC_S_PARM: {
    306 		struct v4l2_streamparm s;
    307 
    308 		if (entering(tcp) && code == VIDIOC_G_PARM)
    309 			return 1;
    310 		if (exiting(tcp) && syserror(tcp))
    311 			return code == VIDIOC_S_PARM;
    312 		if (umove(tcp, arg, &s) < 0)
    313 			return 0;
    314 		if (entering(tcp)) {
    315 			tprints(", {type=");
    316 			printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
    317 		}
    318 
    319 		tprints(exiting(tcp) && code == VIDIOC_S_PARM ? " => {" : ", {");
    320 		if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
    321 			struct v4l2_captureparm *cap = &s.parm.capture;
    322 
    323 			tprints("capability=");
    324 			printflags(v4l2_streaming_capabilities,
    325 				   cap->capability, "V4L2_CAP_???");
    326 
    327 			tprints(", capturemode=");
    328 			printflags(v4l2_capture_modes,
    329 				   cap->capturemode, "V4L2_MODE_???");
    330 
    331 			tprintf(", timeperframe=" FMT_FRACT,
    332 				ARGS_FRACT(cap->timeperframe));
    333 
    334 			tprintf(", extendedmode=%u, readbuffers=%u",
    335 				cap->extendedmode,
    336 				cap->readbuffers);
    337 		} else
    338 			tprints("...");
    339 		tprints("}");
    340 		if (exiting(tcp))
    341 			tprints("}");
    342 		return 1;
    343 	}
    344 
    345 	case VIDIOC_QUERYCTRL: {
    346 		struct v4l2_queryctrl c;
    347 
    348 		if (umove(tcp, arg, &c) < 0)
    349 			return 0;
    350 		/* 'id' field must be printed :
    351 		* on enter
    352 		* on exit if !syserror(tcp) && V4L2_CTRL_FLAG_NEXT_CTRL was set
    353 		*/
    354 		if (entering(tcp)
    355 		    || (exiting(tcp) && tcp->auxstr && !syserror(tcp))) {
    356 			tprints(exiting(tcp) ? " => " : ", {id=");
    357 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
    358 			tcp->auxstr = (c.id & V4L2_CTRL_FLAG_NEXT_CTRL) ? "" : NULL;
    359 			if (tcp->auxstr) {
    360 				tprints("V4L2_CTRL_FLAG_NEXT_CTRL|");
    361 				c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
    362 			}
    363 #endif
    364 			printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
    365 		}
    366 		if (exiting(tcp)) {
    367 			if (!syserror(tcp)) {
    368 				tprints(", type=");
    369 				printxval(v4l2_control_types, c.type,
    370 					  "V4L2_CTRL_TYPE_???");
    371 				tprints(", name=");
    372 				print_quoted_string((const char *) c.name,
    373 						    sizeof(c.name),
    374 						    QUOTE_0_TERMINATED);
    375 				tprintf(", minimum=%i, maximum=%i, step=%i, "
    376 					"default_value=%i, flags=",
    377 					c.minimum, c.maximum,
    378 					c.step, c.default_value);
    379 				printflags(v4l2_control_flags, c.flags,
    380 					   "V4L2_CTRL_FLAG_???");
    381 			}
    382 			tprints("}");
    383 		}
    384 		return 1;
    385 	}
    386 
    387 	case VIDIOC_G_CTRL:
    388 	case VIDIOC_S_CTRL: {
    389 		struct v4l2_control c;
    390 
    391 		if (entering(tcp) || umove(tcp, arg, &c) < 0)
    392 			return 0;
    393 		tprints(", {id=");
    394 		printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
    395 		if (!syserror(tcp) || code != VIDIOC_G_CTRL)
    396 			tprintf(", value=%i", c.value);
    397 		tprints("}");
    398 		return 1;
    399 	}
    400 
    401 #ifdef VIDIOC_S_EXT_CTRLS
    402 	case VIDIOC_S_EXT_CTRLS:
    403 	case VIDIOC_TRY_EXT_CTRLS:
    404 	case VIDIOC_G_EXT_CTRLS: {
    405 		struct v4l2_ext_controls c;
    406 		unsigned int n;
    407 		bool must_print_values;
    408 
    409 		if (entering(tcp) && code == VIDIOC_G_EXT_CTRLS)
    410 			return 0;
    411 		if (exiting(tcp) && syserror(tcp) && code != VIDIOC_G_EXT_CTRLS)
    412 			return 0;
    413 		must_print_values = ((entering(tcp) && code != VIDIOC_G_EXT_CTRLS)
    414 				     || (exiting(tcp) && !syserror(tcp)));
    415 		if (umove(tcp, arg, &c) < 0)
    416 			return 0;
    417 		tprints(code != VIDIOC_G_EXT_CTRLS && exiting(tcp) ? " => " : ", ");
    418 		tprints("{ctrl_class=");
    419 		printxval(v4l2_control_classes, c.ctrl_class,
    420 			  "V4L2_CTRL_CLASS_???");
    421 		tprintf(", count=%u", c.count);
    422 		if (exiting(tcp) && syserror(tcp))
    423 			tprintf(", error_idx=%u", c.error_idx);
    424 		tprints(", controls=[");
    425 		for (n = 0; n < c.count; ++n) {
    426 			struct v4l2_ext_control ctrl;
    427 
    428 			if (n > 0)
    429 				tprints(", ");
    430 			if (umove(tcp, (long) (c.controls + n), &ctrl) < 0)
    431 				break;
    432 			if (abbrev(tcp) && n == 2) {
    433 				tprints("...");
    434 				break;
    435 			}
    436 			tprints("{id=");
    437 			printxval(v4l2_control_ids, ctrl.id, "V4L2_CID_???");
    438 # if HAVE_DECL_V4L2_CTRL_TYPE_STRING
    439 			tprintf(", size=%u", ctrl.size);
    440 			if (ctrl.size > 0) {
    441 				if (must_print_values) {
    442 					tprints(", string=");
    443 					printstr(tcp, (long) ctrl.string, ctrl.size);
    444 				}
    445 			} else
    446 # endif
    447 			{
    448 				if (must_print_values) {
    449 					tprintf(", value=%i, value64=%lld", ctrl.value,
    450 						(long long) ctrl.value64);
    451 				}
    452 			}
    453 			tprints("}");
    454 		}
    455 		tprints("]}");
    456 		return 1;
    457 	}
    458 #endif /* VIDIOC_S_EXT_CTRLS */
    459 
    460 	case VIDIOC_ENUMSTD: {
    461 		struct v4l2_standard s;
    462 
    463 		if (umove(tcp, arg, &s) < 0)
    464 			return 0;
    465 		if (entering(tcp))
    466 			tprintf(", {index=%i", s.index);
    467 		else {
    468 			if (!syserror(tcp)) {
    469 				tprints(", name=");
    470 				print_quoted_string((const char *) s.name,
    471 						    sizeof(s.name),
    472 						    QUOTE_0_TERMINATED);
    473 				tprintf(", frameperiod=" FMT_FRACT, ARGS_FRACT(s.frameperiod));
    474 				tprintf(", framelines=%i", s.framelines);
    475 			}
    476 			tprints("}");
    477 		}
    478 		return 1;
    479 	}
    480 
    481 	case VIDIOC_G_STD:
    482 	case VIDIOC_S_STD: {
    483 		v4l2_std_id s;
    484 
    485 		if (code == VIDIOC_G_STD && exiting(tcp) && syserror(tcp))
    486 			return 0;
    487 		if (umove(tcp, arg, &s) < 0)
    488 			return 0;
    489 		if ((code == VIDIOC_S_STD) == entering(tcp))
    490 			tprintf(", std=%#llx", (unsigned long long) s);
    491 		return 1;
    492 	}
    493 
    494 	case VIDIOC_ENUMINPUT: {
    495 		struct v4l2_input i;
    496 
    497 		if (entering(tcp) || umove(tcp, arg, &i) < 0)
    498 			return 0;
    499 		tprintf(", {index=%i", i.index);
    500 		if (!syserror(tcp)) {
    501 			tprints(", name=");
    502 			print_quoted_string((const char *) i.name,
    503 					    sizeof(i.name), QUOTE_0_TERMINATED);
    504 			tprints(", type=");
    505 			printxval(v4l2_input_types, i.type,
    506 				  "V4L2_INPUT_TYPE_???");
    507 		}
    508 		tprints("}");
    509 		return 1;
    510 	}
    511 
    512 	case VIDIOC_G_INPUT:
    513 	case VIDIOC_S_INPUT: {
    514 		int index;
    515 
    516 		if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &index) < 0)
    517 			return 0;
    518 
    519 		tprintf(", index=%i", index);
    520 		return 1;
    521 	}
    522 
    523 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
    524 	case VIDIOC_ENUM_FRAMEINTERVALS: {
    525 		struct v4l2_frmivalenum f;
    526 
    527 		if (entering(tcp) || umove(tcp, arg, &f) < 0)
    528 			return 0;
    529 		tprintf(", {index=%i, pixel_format=", f.index);
    530 		print_pixelformat(f.pixel_format);
    531 		tprintf(", width=%u, height=%u", f.width, f.height);
    532 		if (!syserror(tcp)) {
    533 			tprints(", type=");
    534 			printxval(v4l2_frameinterval_types, f.type,
    535 				  "V4L2_FRMIVAL_TYPE_???");
    536 			switch (f.type) {
    537 			case V4L2_FRMIVAL_TYPE_DISCRETE:
    538 				tprintf(", discrete=" FMT_FRACT,
    539 					ARGS_FRACT(f.discrete));
    540 				break;
    541 			case V4L2_FRMIVAL_TYPE_STEPWISE:
    542 			case V4L2_FRMSIZE_TYPE_CONTINUOUS:
    543 				tprintf(", stepwise={min=" FMT_FRACT ", max="
    544 					FMT_FRACT ", step=" FMT_FRACT "}",
    545 					ARGS_FRACT(f.stepwise.min),
    546 					ARGS_FRACT(f.stepwise.max),
    547 					ARGS_FRACT(f.stepwise.step));
    548 				break;
    549 			}
    550 		}
    551 		tprints("}");
    552 		return 1;
    553 	}
    554 #endif /* VIDIOC_ENUM_FRAMEINTERVALS */
    555 
    556 	case VIDIOC_CROPCAP: {
    557 		struct v4l2_cropcap c;
    558 
    559 		if (entering(tcp) || umove(tcp, arg, &c) < 0)
    560 			return 0;
    561 		tprints(", {type=");
    562 		printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
    563 		if (!syserror(tcp))
    564 			tprintf(", bounds=" FMT_RECT ", defrect=" FMT_RECT ", "
    565 				"pixelaspect=" FMT_FRACT, ARGS_RECT(c.bounds),
    566 				ARGS_RECT(c.defrect), ARGS_FRACT(c.pixelaspect));
    567 		tprints("}");
    568 		return 1;
    569 	}
    570 
    571 	case VIDIOC_S_CROP: {
    572 		struct v4l2_crop c;
    573 
    574 		if (exiting(tcp) || umove(tcp, arg, &c) < 0)
    575 			return 0;
    576 		tprints(", {type=");
    577 		printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
    578 		tprintf(", c=" FMT_RECT "}", ARGS_RECT(c.c));
    579 		return 1;
    580 	}
    581 
    582 	case VIDIOC_G_FBUF:
    583 	case VIDIOC_S_FBUF: {
    584 		struct v4l2_framebuffer b;
    585 
    586 		if (syserror(tcp) && code == VIDIOC_G_FBUF)
    587 			return 0;
    588 		if (entering(tcp) || umove(tcp, arg, &b) < 0)
    589 			return 0;
    590 		tprintf(", {capability=%x, flags=%x, base=%p}",
    591 			b.capability, b.flags, b.base);
    592 		return 1;
    593 	}
    594 
    595 #ifdef VIDIOC_CREATE_BUFS
    596 	case VIDIOC_CREATE_BUFS: {
    597 		struct v4l2_create_buffers b;
    598 
    599 		if (exiting(tcp) && syserror(tcp))
    600 			return 1;
    601 		if (umove(tcp, arg, &b) < 0)
    602 			return 0;
    603 		if (entering(tcp)) {
    604 			tprintf(", {count=%u, memory=", b.count);
    605 			printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
    606 			tprints(", format={type=");
    607 			printxval(v4l2_buf_types, b.format.type, "V4L2_BUF_TYPE_???");
    608 			tprints(", ");
    609 			print_v4l2_format_fmt(&b.format);
    610 			tprints("}}");
    611 			return 1;
    612 		} else {
    613 			static const char fmt[] = "{index=%u, count=%u}";
    614 			static char outstr[sizeof(fmt) + sizeof(int) * 6];
    615 
    616 			sprintf(outstr, fmt, b.index, b.count);
    617 			tcp->auxstr = outstr;
    618 			return 1 + RVAL_STR;
    619 		}
    620 	}
    621 #endif /* VIDIOC_CREATE_BUFS */
    622 
    623 	case VIDIOC_REQBUFS: {
    624 		struct v4l2_requestbuffers reqbufs;
    625 
    626 		if (umove(tcp, arg, &reqbufs) < 0)
    627 			return 0;
    628 		if (entering(tcp)) {
    629 			tprintf(", {count=%u, type=", reqbufs.count);
    630 			printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
    631 			tprints(", memory=");
    632 			printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
    633 			tprints("}");
    634 			return 1;
    635 		} else if (syserror(tcp))
    636 			return 1;
    637 		else {
    638 			static char outstr[sizeof("{count=}") + sizeof(int) * 3];
    639 
    640 			sprintf(outstr, "{count=%u}", reqbufs.count);
    641 			tcp->auxstr = outstr;
    642 			return 1 + RVAL_STR;
    643 		}
    644 	}
    645 
    646 	case VIDIOC_QUERYBUF:
    647 	case VIDIOC_QBUF:
    648 	case VIDIOC_DQBUF: {
    649 		struct v4l2_buffer b;
    650 
    651 		if (umove(tcp, arg, &b) < 0)
    652 			return 0;
    653 		if (entering(tcp)) {
    654 			tprints(", {type=");
    655 			printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???");
    656 			if (code != VIDIOC_DQBUF)
    657 				tprintf(", index=%u", b.index);
    658 		} else {
    659 			if (!syserror(tcp)) {
    660 				if (code == VIDIOC_DQBUF)
    661 					tprintf(", index=%u", b.index);
    662 				tprints(", memory=");
    663 				printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
    664 
    665 				if (b.memory == V4L2_MEMORY_MMAP) {
    666 					tprintf(", m.offset=%#x", b.m.offset);
    667 				} else if (b.memory == V4L2_MEMORY_USERPTR) {
    668 					tprintf(", m.userptr=%#lx", b.m.userptr);
    669 				}
    670 
    671 				tprintf(", length=%u, bytesused=%u, flags=",
    672 					b.length, b.bytesused);
    673 				printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???");
    674 				if (code == VIDIOC_DQBUF)
    675 					tprintf(", timestamp = {%ju.%06ju}",
    676 						(uintmax_t)b.timestamp.tv_sec,
    677 						(uintmax_t)b.timestamp.tv_usec);
    678 				tprints(", ...");
    679 			}
    680 			tprints("}");
    681 		}
    682 		return 1;
    683 	}
    684 
    685 	case VIDIOC_STREAMON:
    686 	case VIDIOC_STREAMOFF: {
    687 		int type;
    688 
    689 		if (umove(tcp, arg, &type) < 0)
    690 			return 0;
    691 		if (entering(tcp)) {
    692 			tprints(", ");
    693 			printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
    694 		}
    695 		return 1;
    696 	}
    697 
    698 	default: /* decode on exit */
    699 		return 0;
    700 	}
    701 }
    702