v4l2.c revision 0cc961440b527ff8c16954fc411a1529072edb92
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 * 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/videodev2.h> 35/* some historical constants */ 36#ifndef V4L2_CID_HCENTER 37#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) 38#endif 39#ifndef V4L2_CID_VCENTER 40#define V4L2_CID_VCENTER (V4L2_CID_BASE+23) 41#endif 42#ifndef V4L2_CID_BAND_STOP_FILTER 43#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33) 44#endif 45 46#include "xlat/v4l2_device_capabilities_flags.h" 47#include "xlat/v4l2_buf_types.h" 48#include "xlat/v4l2_buf_flags.h" 49#include "xlat/v4l2_framesize_types.h" 50#include "xlat/v4l2_frameinterval_types.h" 51#include "xlat/v4l2_fields.h" 52#include "xlat/v4l2_colorspaces.h" 53#include "xlat/v4l2_format_description_flags.h" 54#include "xlat/v4l2_memories.h" 55#include "xlat/v4l2_control_ids.h" 56#include "xlat/v4l2_control_types.h" 57#include "xlat/v4l2_control_flags.h" 58#include "xlat/v4l2_control_classes.h" 59#include "xlat/v4l2_streaming_capabilities.h" 60#include "xlat/v4l2_capture_modes.h" 61#include "xlat/v4l2_input_types.h" 62 63#define FMT_FRACT "%u/%u" 64#define ARGS_FRACT(x) ((x).numerator), ((x).denominator) 65 66#define FMT_RECT "{left=%i, top=%i, width=%i, height=%i}" 67#define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height 68 69static void print_pixelformat(uint32_t fourcc) 70{ 71#if WORDS_BIGENDIAN 72 fourcc = htole32(fourcc); 73#endif 74 tprintf("%.4s", (char*)&fourcc); 75} 76 77static void print_v4l2_format_fmt(const struct v4l2_format *f) 78{ 79 tprints("fmt."); 80 switch (f->type) { 81 case V4L2_BUF_TYPE_VIDEO_CAPTURE: 82 case V4L2_BUF_TYPE_VIDEO_OUTPUT: { 83 const struct v4l2_pix_format *pix = &f->fmt.pix; 84 85 tprintf("pix={width=%u, height=%u, pixelformat=", 86 pix->width, pix->height); 87 print_pixelformat(pix->pixelformat); 88 tprints(", field="); 89 printxval(v4l2_fields, pix->field, "V4L2_FIELD_???"); 90 tprintf(", bytesperline=%u, sizeimage=%u, colorspace=", 91 pix->bytesperline, pix->sizeimage); 92 printxval(v4l2_colorspaces, pix->colorspace, 93 "V4L2_COLORSPACE_???"); 94 tprints("}"); 95 break; 96 } 97#if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE 98 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 99 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: { 100 const struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 101 unsigned int i, max; 102 103 tprintf("pix_mp={width=%u, height=%u, pixelformat=", 104 pix_mp->width, pix_mp->height); 105 print_pixelformat(pix_mp->pixelformat); 106 tprints(", field="); 107 printxval(v4l2_fields, pix_mp->field, "V4L2_FIELD_???"); 108 tprints(", colorspace="); 109 printxval(v4l2_colorspaces, pix_mp->colorspace, 110 "V4L2_COLORSPACE_???"); 111 tprints("plane_fmt=["); 112 max = pix_mp->num_planes; 113 if (max > VIDEO_MAX_PLANES) 114 max = VIDEO_MAX_PLANES; 115 for (i = 0; i < max; i++) { 116 if (i > 0) 117 tprints(", "); 118 tprintf("{sizeimage=%u, bytesperline=%u}", 119 pix_mp->plane_fmt[i].sizeimage, 120 pix_mp->plane_fmt[i].bytesperline); 121 } 122 tprintf("], num_planes=%u}", (unsigned) pix_mp->num_planes); 123 break; 124 } 125#endif 126 127 /* TODO: Complete this switch statement */ 128 case V4L2_BUF_TYPE_VIDEO_OVERLAY: 129 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: 130 tprints("win={???}"); 131 break; 132 133 case V4L2_BUF_TYPE_VBI_CAPTURE: 134 case V4L2_BUF_TYPE_VBI_OUTPUT: 135 tprints("vbi={???}"); 136 break; 137 138 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: 139 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: 140 tprints("sliced={???}"); 141 break; 142 143 default: 144 tprints("???"); 145 break; 146 } 147} 148 149int 150v4l2_ioctl(struct tcb *tcp, unsigned long code, long arg) 151{ 152 if (!verbose(tcp)) 153 return 0; 154 155 switch (code) { 156 case VIDIOC_QUERYCAP: /* decode on exit */ { 157 struct v4l2_capability caps; 158 159 if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &caps) < 0) 160 return 0; 161 tprintf(", {driver=\"%s\", card=\"%s\", bus_info=\"%s\", " 162 "version=%u.%u.%u, capabilities=", caps.driver, caps.card, 163 caps.bus_info, (caps.version >> 16) & 0xFF, 164 (caps.version >> 8) & 0xFF, caps.version & 0xFF); 165 printflags(v4l2_device_capabilities_flags, caps.capabilities, 166 "V4L2_CAP_???"); 167#ifdef V4L2_CAP_DEVICE_CAPS 168 tprints(", device_caps="); 169 printflags(v4l2_device_capabilities_flags, caps.device_caps, 170 "V4L2_CAP_???"); 171#endif 172 tprints("}"); 173 return 1; 174 } 175 176 case VIDIOC_ENUM_FRAMESIZES: /* decode on exit */ { 177 struct v4l2_frmsizeenum s; 178 179 if (entering(tcp) || umove(tcp, arg, &s) < 0) 180 return 0; 181 tprintf(", {index=%u, pixel_format=", s.index); 182 print_pixelformat(s.pixel_format); 183 184 if (!syserror(tcp)) { 185 tprints(", type="); 186 printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???"); 187 switch (s.type) { 188 case V4L2_FRMSIZE_TYPE_DISCRETE: 189 tprintf(", discrete={width=%u, height=%u}", 190 s.discrete.width, s.discrete.height); 191 break; 192 case V4L2_FRMSIZE_TYPE_STEPWISE: 193 tprintf(", stepwise={min_width=%u, max_width=%u, " 194 "step_width=%u, min_height=%u, max_height=%u, " 195 "step_height=%u}", 196 s.stepwise.min_width, s.stepwise.max_width, 197 s.stepwise.step_width, s.stepwise.min_height, 198 s.stepwise.max_height, s.stepwise.step_height); 199 break; 200 } 201 } 202 tprints("}"); 203 return 1; 204 } 205 206 case VIDIOC_G_FMT: 207 case VIDIOC_S_FMT: 208 case VIDIOC_TRY_FMT: { 209 struct v4l2_format f; 210 211 if (umove(tcp, arg, &f) < 0) 212 return 0; 213 if (entering(tcp)) { 214 tprints(", {type="); 215 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???"); 216 } 217 if ((entering(tcp) && code != VIDIOC_G_FMT) 218 || (exiting(tcp) && !syserror(tcp))) { 219 tprints(exiting(tcp) && code != VIDIOC_G_FMT ? " => " : ", "); 220 print_v4l2_format_fmt(&f); 221 } 222 if (exiting(tcp)) 223 tprints("}"); 224 return 1; 225 } 226 227 case VIDIOC_ENUM_FMT: { 228 struct v4l2_fmtdesc f; 229 230 if (entering(tcp) || umove(tcp, arg, &f) < 0) 231 return 0; 232 233 tprintf(", {index=%u", f.index); 234 if (!syserror(tcp)) { 235 tprints(", type="); 236 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???"); 237 tprints(", flags="); 238 printflags(v4l2_format_description_flags, f.flags, 239 "V4L2_FMT_FLAG_???"); 240 tprintf(", description=\"%s\", pixelformat=", 241 f.description); 242 print_pixelformat(f.pixelformat); 243 } 244 tprints("}"); 245 return 1; 246 } 247 248 case VIDIOC_G_PARM: 249 case VIDIOC_S_PARM: { 250 struct v4l2_streamparm s; 251 252 if (entering(tcp) && code == VIDIOC_G_PARM) 253 return 1; 254 if (exiting(tcp) && syserror(tcp)) 255 return code == VIDIOC_S_PARM; 256 if (umove(tcp, arg, &s) < 0) 257 return 0; 258 if (entering(tcp)) { 259 tprints(", {type="); 260 printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???"); 261 } 262 263 tprints(exiting(tcp) && code == VIDIOC_S_PARM ? " => {" : ", {"); 264 if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 265 struct v4l2_captureparm *cap = &s.parm.capture; 266 267 tprints("capability="); 268 printflags(v4l2_streaming_capabilities, 269 cap->capability, "V4L2_CAP_???"); 270 271 tprints(", capturemode="); 272 printflags(v4l2_capture_modes, 273 cap->capturemode, "V4L2_MODE_???"); 274 275 tprintf(", timeperframe=" FMT_FRACT, 276 ARGS_FRACT(cap->timeperframe)); 277 278 tprintf(", extendedmode=%u, readbuffers=%u", 279 cap->extendedmode, 280 cap->readbuffers); 281 } else 282 tprints("..."); 283 tprints("}"); 284 if (exiting(tcp)) 285 tprints("}"); 286 return 1; 287 } 288 289 case VIDIOC_QUERYCTRL: { 290 struct v4l2_queryctrl c; 291 292 if (umove(tcp, arg, &c) < 0) 293 return 0; 294 /* 'id' field must be printed : 295 * on enter 296 * on exit if !syserror(tcp) && V4L2_CTRL_FLAG_NEXT_CTRL was set 297 */ 298 if (entering(tcp) 299 || (exiting(tcp) && tcp->auxstr && !syserror(tcp))) { 300 tprints(exiting(tcp) ? " => " : ", {id="); 301 tcp->auxstr = (c.id & V4L2_CTRL_FLAG_NEXT_CTRL) ? "" : NULL; 302 if (tcp->auxstr) { 303 tprints("V4L2_CTRL_FLAG_NEXT_CTRL|"); 304 c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL; 305 } 306 printxval(v4l2_control_ids, c.id, "V4L2_CID_???"); 307 } 308 if (exiting(tcp)) { 309 if (!syserror(tcp)) { 310 tprints(", type="); 311 printxval(v4l2_control_types, c.type, 312 "V4L2_CTRL_TYPE_???"); 313 tprintf(", name=\"%s\", minimum=%i, maximum=%i, step=%i, " 314 "default_value=%i, flags=", 315 c.name, c.minimum, c.maximum, 316 c.step, c.default_value); 317 printflags(v4l2_control_flags, c.flags, 318 "V4L2_CTRL_FLAG_???"); 319 } 320 tprints("}"); 321 } 322 return 1; 323 } 324 325 case VIDIOC_G_CTRL: 326 case VIDIOC_S_CTRL: { 327 struct v4l2_control c; 328 329 if (entering(tcp) || umove(tcp, arg, &c) < 0) 330 return 0; 331 tprints(", {id="); 332 printxval(v4l2_control_ids, c.id, "V4L2_CID_???"); 333 if (!syserror(tcp) || code != VIDIOC_G_CTRL) 334 tprintf(", value=%i", c.value); 335 tprints("}"); 336 return 1; 337 } 338 339 case VIDIOC_S_EXT_CTRLS: 340 case VIDIOC_TRY_EXT_CTRLS: 341 case VIDIOC_G_EXT_CTRLS: { 342 struct v4l2_ext_controls c; 343 unsigned int n; 344 bool must_print_values; 345 346 if (entering(tcp) && code == VIDIOC_G_EXT_CTRLS) 347 return 0; 348 if (exiting(tcp) && syserror(tcp) && code != VIDIOC_G_EXT_CTRLS) 349 return 0; 350 must_print_values = ((entering(tcp) && code != VIDIOC_G_EXT_CTRLS) 351 || (exiting(tcp) && !syserror(tcp))); 352 if (umove(tcp, arg, &c) < 0) 353 return 0; 354 tprints(code != VIDIOC_G_EXT_CTRLS && exiting(tcp) ? " => " : ", "); 355 tprints("{ctrl_class="); 356 printxval(v4l2_control_classes, c.ctrl_class, 357 "V4L2_CTRL_CLASS_???"); 358 tprintf(", count=%u", c.count); 359 if (exiting(tcp) && syserror(tcp)) 360 tprintf(", error_idx=%u", c.error_idx); 361 tprints(", controls=["); 362 for (n = 0; n < c.count; ++n) { 363 struct v4l2_ext_control ctrl; 364 365 if (n > 0) 366 tprints(", "); 367 if (umove(tcp, (long) (c.controls + n), &ctrl) < 0) 368 break; 369 if (abbrev(tcp) && n == 2) { 370 tprints("..."); 371 break; 372 } 373 tprints("{id="); 374 printxval(v4l2_control_ids, ctrl.id, "V4L2_CID_???"); 375#if HAVE_DECL_V4L2_CTRL_TYPE_STRING 376 tprintf(", size=%u", ctrl.size); 377 if (ctrl.size > 0) { 378 if (must_print_values) { 379 tprints(", string="); 380 printstr(tcp, (long) ctrl.string, ctrl.size); 381 } 382 } else 383#endif 384 { 385 if (must_print_values) { 386 tprintf(", value=%i, value64=%lli", ctrl.value, 387 ctrl.value64); 388 } 389 } 390 tprints("}"); 391 } 392 tprints("]}"); 393 return 1; 394 } 395 396 case VIDIOC_ENUMSTD: { 397 struct v4l2_standard s; 398 399 if (umove(tcp, arg, &s) < 0) 400 return 0; 401 if (entering(tcp)) 402 tprintf(", {index=%i", s.index); 403 else { 404 if (!syserror(tcp)) { 405 tprintf(", name=\"%s\"", s.name); 406 tprintf(", frameperiod=" FMT_FRACT, ARGS_FRACT(s.frameperiod)); 407 tprintf(", framelines=%i", s.framelines); 408 } 409 tprints("}"); 410 } 411 return 1; 412 } 413 414 case VIDIOC_G_STD: 415 case VIDIOC_S_STD: { 416 v4l2_std_id s; 417 418 if (code == VIDIOC_G_STD && exiting(tcp) && syserror(tcp)) 419 return 0; 420 if (umove(tcp, arg, &s) < 0) 421 return 0; 422 if ((code == VIDIOC_S_STD) == entering(tcp)) 423 tprintf(", std=%#llx", s); 424 return 1; 425 } 426 427 case VIDIOC_ENUMINPUT: { 428 struct v4l2_input i; 429 430 if (entering(tcp) || umove(tcp, arg, &i) < 0) 431 return 0; 432 tprintf(", {index=%i", i.index); 433 if (!syserror(tcp)) { 434 tprintf(", name=\"%s\", type=", i.name); 435 printxval(v4l2_input_types, i.type, 436 "V4L2_INPUT_TYPE_???"); 437 } 438 tprints("}"); 439 return 1; 440 } 441 442 case VIDIOC_G_INPUT: 443 case VIDIOC_S_INPUT: { 444 int index; 445 446 if (entering(tcp) || syserror(tcp) || umove(tcp, arg, &index) < 0) 447 return 0; 448 449 tprintf(", index=%i", index); 450 return 1; 451 } 452 453 case VIDIOC_ENUM_FRAMEINTERVALS: { 454 struct v4l2_frmivalenum f; 455 456 if (entering(tcp) || umove(tcp, arg, &f) < 0) 457 return 0; 458 tprintf(", {index=%i, pixel_format=", f.index); 459 print_pixelformat(f.pixel_format); 460 tprintf(", width=%u, height=%u", f.width, f.height); 461 if (!syserror(tcp)) { 462 tprints(", type="); 463 printxval(v4l2_frameinterval_types, f.type, 464 "V4L2_FRMIVAL_TYPE_???"); 465 switch (f.type) { 466 case V4L2_FRMIVAL_TYPE_DISCRETE: 467 tprintf(", discrete=" FMT_FRACT, 468 ARGS_FRACT(f.discrete)); 469 break; 470 case V4L2_FRMIVAL_TYPE_STEPWISE: 471 case V4L2_FRMSIZE_TYPE_CONTINUOUS: 472 tprintf(", stepwise={min=" FMT_FRACT ", max=" 473 FMT_FRACT ", step=" FMT_FRACT "}", 474 ARGS_FRACT(f.stepwise.min), 475 ARGS_FRACT(f.stepwise.max), 476 ARGS_FRACT(f.stepwise.step)); 477 break; 478 } 479 } 480 tprints("}"); 481 return 1; 482 } 483 484 case VIDIOC_CROPCAP: { 485 struct v4l2_cropcap c; 486 487 if (entering(tcp) || umove(tcp, arg, &c) < 0) 488 return 0; 489 tprints(", type="); 490 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???"); 491 if (syserror(tcp)) 492 return 1; 493 tprintf(", bounds=" FMT_RECT ", defrect=" FMT_RECT ", " 494 "pixelaspect=" FMT_FRACT, ARGS_RECT(c.bounds), 495 ARGS_RECT(c.defrect), ARGS_FRACT(c.pixelaspect)); 496 return 1; 497 } 498 499 case VIDIOC_G_FBUF: 500 case VIDIOC_S_FBUF: { 501 struct v4l2_framebuffer b; 502 503 if (syserror(tcp) && code == VIDIOC_G_FBUF) 504 return 0; 505 if (entering(tcp) || umove(tcp, arg, &b) < 0) 506 return 0; 507 tprintf(", {capability=%x, flags=%x, base=%p}", 508 b.capability, b.flags, b.base); 509 return 1; 510 } 511 512 case VIDIOC_REQBUFS: { 513 struct v4l2_requestbuffers reqbufs; 514 515 if (umove(tcp, arg, &reqbufs) < 0) 516 return 0; 517 if (entering(tcp)) { 518 tprintf(", {count=%u, type=", reqbufs.count); 519 printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???"); 520 tprints(", memory="); 521 printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???"); 522 tprints("}"); 523 return 1; 524 } else if (syserror(tcp)) 525 return 1; 526 else { 527 static char outstr[sizeof("{count=}") + sizeof(int) * 3]; 528 529 sprintf(outstr, "{count=%u}", reqbufs.count); 530 tcp->auxstr = outstr; 531 return 1 + RVAL_STR; 532 } 533 } 534 535 case VIDIOC_QUERYBUF: 536 case VIDIOC_QBUF: 537 case VIDIOC_DQBUF: { 538 struct v4l2_buffer b; 539 540 if (umove(tcp, arg, &b) < 0) 541 return 0; 542 if (entering(tcp)) { 543 tprints(", {type="); 544 printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???"); 545 if (code != VIDIOC_DQBUF) 546 tprintf(", index=%u", b.index); 547 } else { 548 if (!syserror(tcp)) { 549 if (code == VIDIOC_DQBUF) 550 tprintf(", index=%u", b.index); 551 tprints(", memory="); 552 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???"); 553 554 if (b.memory == V4L2_MEMORY_MMAP) { 555 tprintf(", m.offset=%#x", b.m.offset); 556 } else if (b.memory == V4L2_MEMORY_USERPTR) { 557 tprintf(", m.userptr=%#lx", b.m.userptr); 558 } 559 560 tprintf(", length=%u, bytesused=%u, flags=", 561 b.length, b.bytesused); 562 printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???"); 563 if (code == VIDIOC_DQBUF) 564 tprintf(", timestamp = {%lu.%06lu}", 565 b.timestamp.tv_sec, 566 b.timestamp.tv_usec); 567 tprints(", ..."); 568 } 569 tprints("}"); 570 } 571 return 1; 572 } 573 574 case VIDIOC_STREAMON: 575 case VIDIOC_STREAMOFF: { 576 int type; 577 578 if (umove(tcp, arg, &type) < 0) 579 return 0; 580 if (entering(tcp)) { 581 tprints(", "); 582 printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???"); 583 } 584 return 1; 585 } 586 587 default: /* decode on exit */ 588 return 0; 589 } 590} 591