1/* 2 * vivid-vid-common.c - common video support functions. 3 * 4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 5 * 6 * This program is free software; you may redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 11 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 12 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 13 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 14 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 15 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 * SOFTWARE. 18 */ 19 20#include <linux/errno.h> 21#include <linux/kernel.h> 22#include <linux/sched.h> 23#include <linux/videodev2.h> 24#include <linux/v4l2-dv-timings.h> 25#include <media/v4l2-common.h> 26#include <media/v4l2-event.h> 27#include <media/v4l2-dv-timings.h> 28 29#include "vivid-core.h" 30#include "vivid-vid-common.h" 31 32const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { 33 .type = V4L2_DV_BT_656_1120, 34 /* keep this initialization for compatibility with GCC < 4.4.6 */ 35 .reserved = { 0 }, 36 V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000, 37 V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 38 V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, 39 V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) 40}; 41 42/* ------------------------------------------------------------------ 43 Basic structures 44 ------------------------------------------------------------------*/ 45 46struct vivid_fmt vivid_formats[] = { 47 { 48 .name = "4:2:2, packed, YUYV", 49 .fourcc = V4L2_PIX_FMT_YUYV, 50 .vdownsampling = { 1 }, 51 .bit_depth = { 16 }, 52 .is_yuv = true, 53 .planes = 1, 54 .buffers = 1, 55 .data_offset = { PLANE0_DATA_OFFSET }, 56 }, 57 { 58 .name = "4:2:2, packed, UYVY", 59 .fourcc = V4L2_PIX_FMT_UYVY, 60 .vdownsampling = { 1 }, 61 .bit_depth = { 16 }, 62 .is_yuv = true, 63 .planes = 1, 64 .buffers = 1, 65 }, 66 { 67 .name = "4:2:2, packed, YVYU", 68 .fourcc = V4L2_PIX_FMT_YVYU, 69 .vdownsampling = { 1 }, 70 .bit_depth = { 16 }, 71 .is_yuv = true, 72 .planes = 1, 73 .buffers = 1, 74 }, 75 { 76 .name = "4:2:2, packed, VYUY", 77 .fourcc = V4L2_PIX_FMT_VYUY, 78 .vdownsampling = { 1 }, 79 .bit_depth = { 16 }, 80 .is_yuv = true, 81 .planes = 1, 82 .buffers = 1, 83 }, 84 { 85 .name = "YUV 4:2:2 triplanar", 86 .fourcc = V4L2_PIX_FMT_YUV422P, 87 .vdownsampling = { 1, 1, 1 }, 88 .bit_depth = { 8, 4, 4 }, 89 .is_yuv = true, 90 .planes = 3, 91 .buffers = 1, 92 }, 93 { 94 .name = "YUV 4:2:0 triplanar", 95 .fourcc = V4L2_PIX_FMT_YUV420, 96 .vdownsampling = { 1, 2, 2 }, 97 .bit_depth = { 8, 4, 4 }, 98 .is_yuv = true, 99 .planes = 3, 100 .buffers = 1, 101 }, 102 { 103 .name = "YVU 4:2:0 triplanar", 104 .fourcc = V4L2_PIX_FMT_YVU420, 105 .vdownsampling = { 1, 2, 2 }, 106 .bit_depth = { 8, 4, 4 }, 107 .is_yuv = true, 108 .planes = 3, 109 .buffers = 1, 110 }, 111 { 112 .name = "YUV 4:2:0 biplanar", 113 .fourcc = V4L2_PIX_FMT_NV12, 114 .vdownsampling = { 1, 2 }, 115 .bit_depth = { 8, 8 }, 116 .is_yuv = true, 117 .planes = 2, 118 .buffers = 1, 119 }, 120 { 121 .name = "YVU 4:2:0 biplanar", 122 .fourcc = V4L2_PIX_FMT_NV21, 123 .vdownsampling = { 1, 2 }, 124 .bit_depth = { 8, 8 }, 125 .is_yuv = true, 126 .planes = 2, 127 .buffers = 1, 128 }, 129 { 130 .name = "YUV 4:2:2 biplanar", 131 .fourcc = V4L2_PIX_FMT_NV16, 132 .vdownsampling = { 1, 1 }, 133 .bit_depth = { 8, 8 }, 134 .is_yuv = true, 135 .planes = 2, 136 .buffers = 1, 137 }, 138 { 139 .name = "YVU 4:2:2 biplanar", 140 .fourcc = V4L2_PIX_FMT_NV61, 141 .vdownsampling = { 1, 1 }, 142 .bit_depth = { 8, 8 }, 143 .is_yuv = true, 144 .planes = 2, 145 .buffers = 1, 146 }, 147 { 148 .name = "YUV 4:4:4 biplanar", 149 .fourcc = V4L2_PIX_FMT_NV24, 150 .vdownsampling = { 1, 1 }, 151 .bit_depth = { 8, 16 }, 152 .is_yuv = true, 153 .planes = 2, 154 .buffers = 1, 155 }, 156 { 157 .name = "YVU 4:4:4 biplanar", 158 .fourcc = V4L2_PIX_FMT_NV42, 159 .vdownsampling = { 1, 1 }, 160 .bit_depth = { 8, 16 }, 161 .is_yuv = true, 162 .planes = 2, 163 .buffers = 1, 164 }, 165 { 166 .name = "YUV555 (LE)", 167 .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */ 168 .vdownsampling = { 1 }, 169 .bit_depth = { 16 }, 170 .planes = 1, 171 .buffers = 1, 172 .alpha_mask = 0x8000, 173 }, 174 { 175 .name = "YUV565 (LE)", 176 .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */ 177 .vdownsampling = { 1 }, 178 .bit_depth = { 16 }, 179 .planes = 1, 180 .buffers = 1, 181 }, 182 { 183 .name = "YUV444", 184 .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */ 185 .vdownsampling = { 1 }, 186 .bit_depth = { 16 }, 187 .planes = 1, 188 .buffers = 1, 189 .alpha_mask = 0xf000, 190 }, 191 { 192 .name = "YUV32 (LE)", 193 .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */ 194 .vdownsampling = { 1 }, 195 .bit_depth = { 32 }, 196 .planes = 1, 197 .buffers = 1, 198 .alpha_mask = 0x000000ff, 199 }, 200 { 201 .name = "Monochrome", 202 .fourcc = V4L2_PIX_FMT_GREY, 203 .vdownsampling = { 1 }, 204 .bit_depth = { 8 }, 205 .is_yuv = true, 206 .planes = 1, 207 .buffers = 1, 208 }, 209 { 210 .name = "RGB332", 211 .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */ 212 .vdownsampling = { 1 }, 213 .bit_depth = { 8 }, 214 .planes = 1, 215 .buffers = 1, 216 }, 217 { 218 .name = "RGB565 (LE)", 219 .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ 220 .vdownsampling = { 1 }, 221 .bit_depth = { 16 }, 222 .planes = 1, 223 .buffers = 1, 224 .can_do_overlay = true, 225 }, 226 { 227 .name = "RGB565 (BE)", 228 .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ 229 .vdownsampling = { 1 }, 230 .bit_depth = { 16 }, 231 .planes = 1, 232 .buffers = 1, 233 .can_do_overlay = true, 234 }, 235 { 236 .name = "RGB444", 237 .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */ 238 .vdownsampling = { 1 }, 239 .bit_depth = { 16 }, 240 .planes = 1, 241 .buffers = 1, 242 }, 243 { 244 .name = "XRGB444", 245 .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */ 246 .vdownsampling = { 1 }, 247 .bit_depth = { 16 }, 248 .planes = 1, 249 .buffers = 1, 250 }, 251 { 252 .name = "ARGB444", 253 .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */ 254 .vdownsampling = { 1 }, 255 .bit_depth = { 16 }, 256 .planes = 1, 257 .buffers = 1, 258 .alpha_mask = 0x00f0, 259 }, 260 { 261 .name = "RGB555 (LE)", 262 .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */ 263 .vdownsampling = { 1 }, 264 .bit_depth = { 16 }, 265 .planes = 1, 266 .buffers = 1, 267 .can_do_overlay = true, 268 }, 269 { 270 .name = "XRGB555 (LE)", 271 .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */ 272 .vdownsampling = { 1 }, 273 .bit_depth = { 16 }, 274 .planes = 1, 275 .buffers = 1, 276 .can_do_overlay = true, 277 }, 278 { 279 .name = "ARGB555 (LE)", 280 .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ 281 .vdownsampling = { 1 }, 282 .bit_depth = { 16 }, 283 .planes = 1, 284 .buffers = 1, 285 .can_do_overlay = true, 286 .alpha_mask = 0x8000, 287 }, 288 { 289 .name = "RGB555 (BE)", 290 .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ 291 .vdownsampling = { 1 }, 292 .bit_depth = { 16 }, 293 .planes = 1, 294 .buffers = 1, 295 }, 296 { 297 .name = "XRGB555 (BE)", 298 .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */ 299 .vdownsampling = { 1 }, 300 .bit_depth = { 16 }, 301 .planes = 1, 302 .buffers = 1, 303 }, 304 { 305 .name = "ARGB555 (BE)", 306 .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */ 307 .vdownsampling = { 1 }, 308 .bit_depth = { 16 }, 309 .planes = 1, 310 .buffers = 1, 311 .alpha_mask = 0x0080, 312 }, 313 { 314 .name = "RGB24 (LE)", 315 .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ 316 .vdownsampling = { 1 }, 317 .bit_depth = { 24 }, 318 .planes = 1, 319 .buffers = 1, 320 }, 321 { 322 .name = "RGB24 (BE)", 323 .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ 324 .vdownsampling = { 1 }, 325 .bit_depth = { 24 }, 326 .planes = 1, 327 .buffers = 1, 328 }, 329 { 330 .name = "BGR666", 331 .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */ 332 .vdownsampling = { 1 }, 333 .bit_depth = { 32 }, 334 .planes = 1, 335 .buffers = 1, 336 }, 337 { 338 .name = "RGB32 (LE)", 339 .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ 340 .vdownsampling = { 1 }, 341 .bit_depth = { 32 }, 342 .planes = 1, 343 .buffers = 1, 344 }, 345 { 346 .name = "RGB32 (BE)", 347 .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */ 348 .vdownsampling = { 1 }, 349 .bit_depth = { 32 }, 350 .planes = 1, 351 .buffers = 1, 352 }, 353 { 354 .name = "XRGB32 (LE)", 355 .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */ 356 .vdownsampling = { 1 }, 357 .bit_depth = { 32 }, 358 .planes = 1, 359 .buffers = 1, 360 }, 361 { 362 .name = "XRGB32 (BE)", 363 .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */ 364 .vdownsampling = { 1 }, 365 .bit_depth = { 32 }, 366 .planes = 1, 367 .buffers = 1, 368 }, 369 { 370 .name = "ARGB32 (LE)", 371 .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ 372 .vdownsampling = { 1 }, 373 .bit_depth = { 32 }, 374 .planes = 1, 375 .buffers = 1, 376 .alpha_mask = 0x000000ff, 377 }, 378 { 379 .name = "ARGB32 (BE)", 380 .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ 381 .vdownsampling = { 1 }, 382 .bit_depth = { 32 }, 383 .planes = 1, 384 .buffers = 1, 385 .alpha_mask = 0xff000000, 386 }, 387 { 388 .name = "Bayer BG/GR", 389 .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ 390 .vdownsampling = { 1 }, 391 .bit_depth = { 8 }, 392 .planes = 1, 393 .buffers = 1, 394 }, 395 { 396 .name = "Bayer GB/RG", 397 .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */ 398 .vdownsampling = { 1 }, 399 .bit_depth = { 8 }, 400 .planes = 1, 401 .buffers = 1, 402 }, 403 { 404 .name = "Bayer GR/BG", 405 .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */ 406 .vdownsampling = { 1 }, 407 .bit_depth = { 8 }, 408 .planes = 1, 409 .buffers = 1, 410 }, 411 { 412 .name = "Bayer RG/GB", 413 .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */ 414 .vdownsampling = { 1 }, 415 .bit_depth = { 8 }, 416 .planes = 1, 417 .buffers = 1, 418 }, 419 { 420 .name = "4:2:2, biplanar, YUV", 421 .fourcc = V4L2_PIX_FMT_NV16M, 422 .vdownsampling = { 1, 1 }, 423 .bit_depth = { 8, 8 }, 424 .is_yuv = true, 425 .planes = 2, 426 .buffers = 2, 427 .data_offset = { PLANE0_DATA_OFFSET, 0 }, 428 }, 429 { 430 .name = "4:2:2, biplanar, YVU", 431 .fourcc = V4L2_PIX_FMT_NV61M, 432 .vdownsampling = { 1, 1 }, 433 .bit_depth = { 8, 8 }, 434 .is_yuv = true, 435 .planes = 2, 436 .buffers = 2, 437 .data_offset = { 0, PLANE0_DATA_OFFSET }, 438 }, 439 { 440 .name = "4:2:0, triplanar, YUV", 441 .fourcc = V4L2_PIX_FMT_YUV420M, 442 .vdownsampling = { 1, 2, 2 }, 443 .bit_depth = { 8, 4, 4 }, 444 .is_yuv = true, 445 .planes = 3, 446 .buffers = 3, 447 }, 448 { 449 .name = "4:2:0, triplanar, YVU", 450 .fourcc = V4L2_PIX_FMT_YVU420M, 451 .vdownsampling = { 1, 2, 2 }, 452 .bit_depth = { 8, 4, 4 }, 453 .is_yuv = true, 454 .planes = 3, 455 .buffers = 3, 456 }, 457 { 458 .name = "4:2:0, biplanar, YUV", 459 .fourcc = V4L2_PIX_FMT_NV12M, 460 .vdownsampling = { 1, 2 }, 461 .bit_depth = { 8, 8 }, 462 .is_yuv = true, 463 .planes = 2, 464 .buffers = 2, 465 }, 466 { 467 .name = "4:2:0, biplanar, YVU", 468 .fourcc = V4L2_PIX_FMT_NV21M, 469 .vdownsampling = { 1, 2 }, 470 .bit_depth = { 8, 8 }, 471 .is_yuv = true, 472 .planes = 2, 473 .buffers = 2, 474 }, 475}; 476 477/* There are 6 multiplanar formats in the list */ 478#define VIVID_MPLANAR_FORMATS 6 479 480const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) 481{ 482 const struct vivid_fmt *fmt; 483 unsigned k; 484 485 for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { 486 fmt = &vivid_formats[k]; 487 if (fmt->fourcc == pixelformat) 488 if (fmt->buffers == 1 || dev->multiplanar) 489 return fmt; 490 } 491 492 return NULL; 493} 494 495bool vivid_vid_can_loop(struct vivid_dev *dev) 496{ 497 if (dev->src_rect.width != dev->sink_rect.width || 498 dev->src_rect.height != dev->sink_rect.height) 499 return false; 500 if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc) 501 return false; 502 if (dev->field_cap != dev->field_out) 503 return false; 504 /* 505 * While this can be supported, it is just too much work 506 * to actually implement. 507 */ 508 if (dev->field_cap == V4L2_FIELD_SEQ_TB || 509 dev->field_cap == V4L2_FIELD_SEQ_BT) 510 return false; 511 if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { 512 if (!(dev->std_cap & V4L2_STD_525_60) != 513 !(dev->std_out & V4L2_STD_525_60)) 514 return false; 515 return true; 516 } 517 if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev)) 518 return true; 519 return false; 520} 521 522void vivid_send_source_change(struct vivid_dev *dev, unsigned type) 523{ 524 struct v4l2_event ev = { 525 .type = V4L2_EVENT_SOURCE_CHANGE, 526 .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 527 }; 528 unsigned i; 529 530 for (i = 0; i < dev->num_inputs; i++) { 531 ev.id = i; 532 if (dev->input_type[i] == type) { 533 if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap) 534 v4l2_event_queue(&dev->vid_cap_dev, &ev); 535 if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap) 536 v4l2_event_queue(&dev->vbi_cap_dev, &ev); 537 } 538 } 539} 540 541/* 542 * Conversion function that converts a single-planar format to a 543 * single-plane multiplanar format. 544 */ 545void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt) 546{ 547 struct v4l2_pix_format_mplane *mp = &mp_fmt->fmt.pix_mp; 548 struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; 549 const struct v4l2_pix_format *pix = &sp_fmt->fmt.pix; 550 bool is_out = sp_fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT; 551 552 memset(mp->reserved, 0, sizeof(mp->reserved)); 553 mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : 554 V4L2_CAP_VIDEO_CAPTURE_MPLANE; 555 mp->width = pix->width; 556 mp->height = pix->height; 557 mp->pixelformat = pix->pixelformat; 558 mp->field = pix->field; 559 mp->colorspace = pix->colorspace; 560 mp->ycbcr_enc = pix->ycbcr_enc; 561 mp->quantization = pix->quantization; 562 mp->num_planes = 1; 563 mp->flags = pix->flags; 564 ppix->sizeimage = pix->sizeimage; 565 ppix->bytesperline = pix->bytesperline; 566 memset(ppix->reserved, 0, sizeof(ppix->reserved)); 567} 568 569int fmt_sp2mp_func(struct file *file, void *priv, 570 struct v4l2_format *f, fmtfunc func) 571{ 572 struct v4l2_format fmt; 573 struct v4l2_pix_format_mplane *mp = &fmt.fmt.pix_mp; 574 struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; 575 struct v4l2_pix_format *pix = &f->fmt.pix; 576 int ret; 577 578 /* Converts to a mplane format */ 579 fmt_sp2mp(f, &fmt); 580 /* Passes it to the generic mplane format function */ 581 ret = func(file, priv, &fmt); 582 /* Copies back the mplane data to the single plane format */ 583 pix->width = mp->width; 584 pix->height = mp->height; 585 pix->pixelformat = mp->pixelformat; 586 pix->field = mp->field; 587 pix->colorspace = mp->colorspace; 588 pix->ycbcr_enc = mp->ycbcr_enc; 589 pix->quantization = mp->quantization; 590 pix->sizeimage = ppix->sizeimage; 591 pix->bytesperline = ppix->bytesperline; 592 pix->flags = mp->flags; 593 return ret; 594} 595 596/* v4l2_rect helper function: copy the width/height values */ 597void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size) 598{ 599 r->width = size->width; 600 r->height = size->height; 601} 602 603/* v4l2_rect helper function: width and height of r should be >= min_size */ 604void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size) 605{ 606 if (r->width < min_size->width) 607 r->width = min_size->width; 608 if (r->height < min_size->height) 609 r->height = min_size->height; 610} 611 612/* v4l2_rect helper function: width and height of r should be <= max_size */ 613void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size) 614{ 615 if (r->width > max_size->width) 616 r->width = max_size->width; 617 if (r->height > max_size->height) 618 r->height = max_size->height; 619} 620 621/* v4l2_rect helper function: r should be inside boundary */ 622void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary) 623{ 624 rect_set_max_size(r, boundary); 625 if (r->left < boundary->left) 626 r->left = boundary->left; 627 if (r->top < boundary->top) 628 r->top = boundary->top; 629 if (r->left + r->width > boundary->width) 630 r->left = boundary->width - r->width; 631 if (r->top + r->height > boundary->height) 632 r->top = boundary->height - r->height; 633} 634 635/* v4l2_rect helper function: return true if r1 has the same size as r2 */ 636bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2) 637{ 638 return r1->width == r2->width && r1->height == r2->height; 639} 640 641/* v4l2_rect helper function: calculate the intersection of two rects */ 642struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b) 643{ 644 struct v4l2_rect r; 645 int right, bottom; 646 647 r.top = max(a->top, b->top); 648 r.left = max(a->left, b->left); 649 bottom = min(a->top + a->height, b->top + b->height); 650 right = min(a->left + a->width, b->left + b->width); 651 r.height = max(0, bottom - r.top); 652 r.width = max(0, right - r.left); 653 return r; 654} 655 656/* 657 * v4l2_rect helper function: scale rect r by to->width / from->width and 658 * to->height / from->height. 659 */ 660void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from, 661 const struct v4l2_rect *to) 662{ 663 if (from->width == 0 || from->height == 0) { 664 r->left = r->top = r->width = r->height = 0; 665 return; 666 } 667 r->left = (((r->left - from->left) * to->width) / from->width) & ~1; 668 r->width = ((r->width * to->width) / from->width) & ~1; 669 r->top = ((r->top - from->top) * to->height) / from->height; 670 r->height = (r->height * to->height) / from->height; 671} 672 673bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2) 674{ 675 /* 676 * IF the left side of r1 is to the right of the right side of r2 OR 677 * the left side of r2 is to the right of the right side of r1 THEN 678 * they do not overlap. 679 */ 680 if (r1->left >= r2->left + r2->width || 681 r2->left >= r1->left + r1->width) 682 return false; 683 /* 684 * IF the top side of r1 is below the bottom of r2 OR 685 * the top side of r2 is below the bottom of r1 THEN 686 * they do not overlap. 687 */ 688 if (r1->top >= r2->top + r2->height || 689 r2->top >= r1->top + r1->height) 690 return false; 691 return true; 692} 693int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) 694{ 695 unsigned w = r->width; 696 unsigned h = r->height; 697 698 /* sanitize w and h in case someone passes ~0 as the value */ 699 w &= 0xffff; 700 h &= 0xffff; 701 if (!(flags & V4L2_SEL_FLAG_LE)) { 702 w++; 703 h++; 704 if (w < 2) 705 w = 2; 706 if (h < 2) 707 h = 2; 708 } 709 if (!(flags & V4L2_SEL_FLAG_GE)) { 710 if (w > MAX_WIDTH) 711 w = MAX_WIDTH; 712 if (h > MAX_HEIGHT) 713 h = MAX_HEIGHT; 714 } 715 w = w & ~1; 716 h = h & ~1; 717 if (w < 2 || h < 2) 718 return -ERANGE; 719 if (w > MAX_WIDTH || h > MAX_HEIGHT) 720 return -ERANGE; 721 if (r->top < 0) 722 r->top = 0; 723 if (r->left < 0) 724 r->left = 0; 725 /* sanitize left and top in case someone passes ~0 as the value */ 726 r->left &= 0xfffe; 727 r->top &= 0xfffe; 728 if (r->left + w > MAX_WIDTH) 729 r->left = MAX_WIDTH - w; 730 if (r->top + h > MAX_HEIGHT) 731 r->top = MAX_HEIGHT - h; 732 if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) == 733 (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) && 734 (r->width != w || r->height != h)) 735 return -ERANGE; 736 r->width = w; 737 r->height = h; 738 return 0; 739} 740 741int vivid_enum_fmt_vid(struct file *file, void *priv, 742 struct v4l2_fmtdesc *f) 743{ 744 struct vivid_dev *dev = video_drvdata(file); 745 const struct vivid_fmt *fmt; 746 747 if (f->index >= ARRAY_SIZE(vivid_formats) - 748 (dev->multiplanar ? 0 : VIVID_MPLANAR_FORMATS)) 749 return -EINVAL; 750 751 fmt = &vivid_formats[f->index]; 752 753 strlcpy(f->description, fmt->name, sizeof(f->description)); 754 f->pixelformat = fmt->fourcc; 755 return 0; 756} 757 758int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, 759 struct v4l2_fmtdesc *f) 760{ 761 struct vivid_dev *dev = video_drvdata(file); 762 763 if (!dev->multiplanar) 764 return -ENOTTY; 765 return vivid_enum_fmt_vid(file, priv, f); 766} 767 768int vidioc_enum_fmt_vid(struct file *file, void *priv, 769 struct v4l2_fmtdesc *f) 770{ 771 struct vivid_dev *dev = video_drvdata(file); 772 773 if (dev->multiplanar) 774 return -ENOTTY; 775 return vivid_enum_fmt_vid(file, priv, f); 776} 777 778int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) 779{ 780 struct vivid_dev *dev = video_drvdata(file); 781 struct video_device *vdev = video_devdata(file); 782 783 if (vdev->vfl_dir == VFL_DIR_RX) { 784 if (!vivid_is_sdtv_cap(dev)) 785 return -ENODATA; 786 *id = dev->std_cap; 787 } else { 788 if (!vivid_is_svid_out(dev)) 789 return -ENODATA; 790 *id = dev->std_out; 791 } 792 return 0; 793} 794 795int vidioc_g_dv_timings(struct file *file, void *_fh, 796 struct v4l2_dv_timings *timings) 797{ 798 struct vivid_dev *dev = video_drvdata(file); 799 struct video_device *vdev = video_devdata(file); 800 801 if (vdev->vfl_dir == VFL_DIR_RX) { 802 if (!vivid_is_hdmi_cap(dev)) 803 return -ENODATA; 804 *timings = dev->dv_timings_cap; 805 } else { 806 if (!vivid_is_hdmi_out(dev)) 807 return -ENODATA; 808 *timings = dev->dv_timings_out; 809 } 810 return 0; 811} 812 813int vidioc_enum_dv_timings(struct file *file, void *_fh, 814 struct v4l2_enum_dv_timings *timings) 815{ 816 struct vivid_dev *dev = video_drvdata(file); 817 struct video_device *vdev = video_devdata(file); 818 819 if (vdev->vfl_dir == VFL_DIR_RX) { 820 if (!vivid_is_hdmi_cap(dev)) 821 return -ENODATA; 822 } else { 823 if (!vivid_is_hdmi_out(dev)) 824 return -ENODATA; 825 } 826 return v4l2_enum_dv_timings_cap(timings, &vivid_dv_timings_cap, 827 NULL, NULL); 828} 829 830int vidioc_dv_timings_cap(struct file *file, void *_fh, 831 struct v4l2_dv_timings_cap *cap) 832{ 833 struct vivid_dev *dev = video_drvdata(file); 834 struct video_device *vdev = video_devdata(file); 835 836 if (vdev->vfl_dir == VFL_DIR_RX) { 837 if (!vivid_is_hdmi_cap(dev)) 838 return -ENODATA; 839 } else { 840 if (!vivid_is_hdmi_out(dev)) 841 return -ENODATA; 842 } 843 *cap = vivid_dv_timings_cap; 844 return 0; 845} 846 847int vidioc_g_edid(struct file *file, void *_fh, 848 struct v4l2_edid *edid) 849{ 850 struct vivid_dev *dev = video_drvdata(file); 851 struct video_device *vdev = video_devdata(file); 852 853 memset(edid->reserved, 0, sizeof(edid->reserved)); 854 if (vdev->vfl_dir == VFL_DIR_RX) { 855 if (edid->pad >= dev->num_inputs) 856 return -EINVAL; 857 if (dev->input_type[edid->pad] != HDMI) 858 return -EINVAL; 859 } else { 860 if (edid->pad >= dev->num_outputs) 861 return -EINVAL; 862 if (dev->output_type[edid->pad] != HDMI) 863 return -EINVAL; 864 } 865 if (edid->start_block == 0 && edid->blocks == 0) { 866 edid->blocks = dev->edid_blocks; 867 return 0; 868 } 869 if (dev->edid_blocks == 0) 870 return -ENODATA; 871 if (edid->start_block >= dev->edid_blocks) 872 return -EINVAL; 873 if (edid->start_block + edid->blocks > dev->edid_blocks) 874 edid->blocks = dev->edid_blocks - edid->start_block; 875 memcpy(edid->edid, dev->edid, edid->blocks * 128); 876 return 0; 877} 878