root/drivers/media/platform/rcar-vin/rcar-v4l2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rvin_format_from_pixel
  2. rvin_format_bytesperline
  3. rvin_format_sizeimage
  4. rvin_format_align
  5. rvin_reset_format
  6. rvin_try_format
  7. rvin_querycap
  8. rvin_try_fmt_vid_cap
  9. rvin_s_fmt_vid_cap
  10. rvin_g_fmt_vid_cap
  11. rvin_enum_fmt_vid_cap
  12. rvin_g_selection
  13. rvin_s_selection
  14. rvin_g_pixelaspect
  15. rvin_enum_input
  16. rvin_g_input
  17. rvin_s_input
  18. rvin_querystd
  19. rvin_s_std
  20. rvin_g_std
  21. rvin_subscribe_event
  22. rvin_enum_dv_timings
  23. rvin_s_dv_timings
  24. rvin_g_dv_timings
  25. rvin_query_dv_timings
  26. rvin_dv_timings_cap
  27. rvin_g_edid
  28. rvin_s_edid
  29. rvin_mc_try_format
  30. rvin_mc_try_fmt_vid_cap
  31. rvin_mc_s_fmt_vid_cap
  32. rvin_mc_enum_input
  33. rvin_power_parallel
  34. rvin_open
  35. rvin_release
  36. rvin_v4l2_unregister
  37. rvin_notify
  38. rvin_v4l2_register

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Driver for Renesas R-Car VIN
   4  *
   5  * Copyright (C) 2016 Renesas Electronics Corp.
   6  * Copyright (C) 2011-2013 Renesas Solutions Corp.
   7  * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
   8  * Copyright (C) 2008 Magnus Damm
   9  *
  10  * Based on the soc-camera rcar_vin driver
  11  */
  12 
  13 #include <linux/pm_runtime.h>
  14 
  15 #include <media/v4l2-event.h>
  16 #include <media/v4l2-ioctl.h>
  17 #include <media/v4l2-mc.h>
  18 #include <media/v4l2-rect.h>
  19 
  20 #include "rcar-vin.h"
  21 
  22 #define RVIN_DEFAULT_FORMAT     V4L2_PIX_FMT_YUYV
  23 #define RVIN_DEFAULT_WIDTH      800
  24 #define RVIN_DEFAULT_HEIGHT     600
  25 #define RVIN_DEFAULT_FIELD      V4L2_FIELD_NONE
  26 #define RVIN_DEFAULT_COLORSPACE V4L2_COLORSPACE_SRGB
  27 
  28 /* -----------------------------------------------------------------------------
  29  * Format Conversions
  30  */
  31 
  32 static const struct rvin_video_format rvin_formats[] = {
  33         {
  34                 .fourcc                 = V4L2_PIX_FMT_NV16,
  35                 .bpp                    = 1,
  36         },
  37         {
  38                 .fourcc                 = V4L2_PIX_FMT_YUYV,
  39                 .bpp                    = 2,
  40         },
  41         {
  42                 .fourcc                 = V4L2_PIX_FMT_UYVY,
  43                 .bpp                    = 2,
  44         },
  45         {
  46                 .fourcc                 = V4L2_PIX_FMT_RGB565,
  47                 .bpp                    = 2,
  48         },
  49         {
  50                 .fourcc                 = V4L2_PIX_FMT_XRGB555,
  51                 .bpp                    = 2,
  52         },
  53         {
  54                 .fourcc                 = V4L2_PIX_FMT_XBGR32,
  55                 .bpp                    = 4,
  56         },
  57         {
  58                 .fourcc                 = V4L2_PIX_FMT_ARGB555,
  59                 .bpp                    = 2,
  60         },
  61         {
  62                 .fourcc                 = V4L2_PIX_FMT_ABGR32,
  63                 .bpp                    = 4,
  64         },
  65 };
  66 
  67 const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
  68                                                        u32 pixelformat)
  69 {
  70         int i;
  71 
  72         if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32)
  73                 return NULL;
  74 
  75         for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
  76                 if (rvin_formats[i].fourcc == pixelformat)
  77                         return rvin_formats + i;
  78 
  79         return NULL;
  80 }
  81 
  82 static u32 rvin_format_bytesperline(struct rvin_dev *vin,
  83                                     struct v4l2_pix_format *pix)
  84 {
  85         const struct rvin_video_format *fmt;
  86         u32 align;
  87 
  88         fmt = rvin_format_from_pixel(vin, pix->pixelformat);
  89 
  90         if (WARN_ON(!fmt))
  91                 return -EINVAL;
  92 
  93         align = pix->pixelformat == V4L2_PIX_FMT_NV16 ? 0x20 : 0x10;
  94 
  95         return ALIGN(pix->width, align) * fmt->bpp;
  96 }
  97 
  98 static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
  99 {
 100         if (pix->pixelformat == V4L2_PIX_FMT_NV16)
 101                 return pix->bytesperline * pix->height * 2;
 102 
 103         return pix->bytesperline * pix->height;
 104 }
 105 
 106 static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
 107 {
 108         u32 walign;
 109 
 110         if (!rvin_format_from_pixel(vin, pix->pixelformat))
 111                 pix->pixelformat = RVIN_DEFAULT_FORMAT;
 112 
 113         switch (pix->field) {
 114         case V4L2_FIELD_TOP:
 115         case V4L2_FIELD_BOTTOM:
 116         case V4L2_FIELD_NONE:
 117         case V4L2_FIELD_INTERLACED_TB:
 118         case V4L2_FIELD_INTERLACED_BT:
 119         case V4L2_FIELD_INTERLACED:
 120                 break;
 121         case V4L2_FIELD_ALTERNATE:
 122                 /*
 123                  * Driver does not (yet) support outputting ALTERNATE to a
 124                  * userspace. It does support outputting INTERLACED so use
 125                  * the VIN hardware to combine the two fields.
 126                  */
 127                 pix->field = V4L2_FIELD_INTERLACED;
 128                 pix->height *= 2;
 129                 break;
 130         default:
 131                 pix->field = RVIN_DEFAULT_FIELD;
 132                 break;
 133         }
 134 
 135         /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */
 136         walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1;
 137 
 138         /* Limit to VIN capabilities */
 139         v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign,
 140                               &pix->height, 4, vin->info->max_height, 2, 0);
 141 
 142         pix->bytesperline = rvin_format_bytesperline(vin, pix);
 143         pix->sizeimage = rvin_format_sizeimage(pix);
 144 
 145         vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
 146                 pix->width, pix->height, pix->bytesperline, pix->sizeimage);
 147 }
 148 
 149 /* -----------------------------------------------------------------------------
 150  * V4L2
 151  */
 152 
 153 static int rvin_reset_format(struct rvin_dev *vin)
 154 {
 155         struct v4l2_subdev_format fmt = {
 156                 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
 157                 .pad = vin->parallel->source_pad,
 158         };
 159         int ret;
 160 
 161         ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
 162         if (ret)
 163                 return ret;
 164 
 165         v4l2_fill_pix_format(&vin->format, &fmt.format);
 166 
 167         rvin_format_align(vin, &vin->format);
 168 
 169         vin->source.top = 0;
 170         vin->source.left = 0;
 171         vin->source.width = vin->format.width;
 172         vin->source.height = vin->format.height;
 173 
 174         vin->crop = vin->source;
 175         vin->compose = vin->source;
 176 
 177         return 0;
 178 }
 179 
 180 static int rvin_try_format(struct rvin_dev *vin, u32 which,
 181                            struct v4l2_pix_format *pix,
 182                            struct v4l2_rect *crop, struct v4l2_rect *compose)
 183 {
 184         struct v4l2_subdev *sd = vin_to_source(vin);
 185         struct v4l2_subdev_pad_config *pad_cfg;
 186         struct v4l2_subdev_format format = {
 187                 .which = which,
 188                 .pad = vin->parallel->source_pad,
 189         };
 190         enum v4l2_field field;
 191         u32 width, height;
 192         int ret;
 193 
 194         pad_cfg = v4l2_subdev_alloc_pad_config(sd);
 195         if (pad_cfg == NULL)
 196                 return -ENOMEM;
 197 
 198         if (!rvin_format_from_pixel(vin, pix->pixelformat))
 199                 pix->pixelformat = RVIN_DEFAULT_FORMAT;
 200 
 201         v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
 202 
 203         /* Allow the video device to override field and to scale */
 204         field = pix->field;
 205         width = pix->width;
 206         height = pix->height;
 207 
 208         ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
 209         if (ret < 0 && ret != -ENOIOCTLCMD)
 210                 goto done;
 211         ret = 0;
 212 
 213         v4l2_fill_pix_format(pix, &format.format);
 214 
 215         if (crop) {
 216                 crop->top = 0;
 217                 crop->left = 0;
 218                 crop->width = pix->width;
 219                 crop->height = pix->height;
 220 
 221                 /*
 222                  * If source is ALTERNATE the driver will use the VIN hardware
 223                  * to INTERLACE it. The crop height then needs to be doubled.
 224                  */
 225                 if (pix->field == V4L2_FIELD_ALTERNATE)
 226                         crop->height *= 2;
 227         }
 228 
 229         if (field != V4L2_FIELD_ANY)
 230                 pix->field = field;
 231 
 232         pix->width = width;
 233         pix->height = height;
 234 
 235         rvin_format_align(vin, pix);
 236 
 237         if (compose) {
 238                 compose->top = 0;
 239                 compose->left = 0;
 240                 compose->width = pix->width;
 241                 compose->height = pix->height;
 242         }
 243 done:
 244         v4l2_subdev_free_pad_config(pad_cfg);
 245 
 246         return ret;
 247 }
 248 
 249 static int rvin_querycap(struct file *file, void *priv,
 250                          struct v4l2_capability *cap)
 251 {
 252         struct rvin_dev *vin = video_drvdata(file);
 253 
 254         strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
 255         strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
 256         snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
 257                  dev_name(vin->dev));
 258         return 0;
 259 }
 260 
 261 static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
 262                                 struct v4l2_format *f)
 263 {
 264         struct rvin_dev *vin = video_drvdata(file);
 265 
 266         return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL,
 267                                NULL);
 268 }
 269 
 270 static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
 271                               struct v4l2_format *f)
 272 {
 273         struct rvin_dev *vin = video_drvdata(file);
 274         struct v4l2_rect crop, compose;
 275         int ret;
 276 
 277         if (vb2_is_busy(&vin->queue))
 278                 return -EBUSY;
 279 
 280         ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
 281                               &crop, &compose);
 282         if (ret)
 283                 return ret;
 284 
 285         vin->format = f->fmt.pix;
 286         vin->crop = crop;
 287         vin->compose = compose;
 288         vin->source = crop;
 289 
 290         return 0;
 291 }
 292 
 293 static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
 294                               struct v4l2_format *f)
 295 {
 296         struct rvin_dev *vin = video_drvdata(file);
 297 
 298         f->fmt.pix = vin->format;
 299 
 300         return 0;
 301 }
 302 
 303 static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
 304                                  struct v4l2_fmtdesc *f)
 305 {
 306         if (f->index >= ARRAY_SIZE(rvin_formats))
 307                 return -EINVAL;
 308 
 309         f->pixelformat = rvin_formats[f->index].fourcc;
 310 
 311         return 0;
 312 }
 313 
 314 static int rvin_g_selection(struct file *file, void *fh,
 315                             struct v4l2_selection *s)
 316 {
 317         struct rvin_dev *vin = video_drvdata(file);
 318 
 319         if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 320                 return -EINVAL;
 321 
 322         switch (s->target) {
 323         case V4L2_SEL_TGT_CROP_BOUNDS:
 324         case V4L2_SEL_TGT_CROP_DEFAULT:
 325                 s->r.left = s->r.top = 0;
 326                 s->r.width = vin->source.width;
 327                 s->r.height = vin->source.height;
 328                 break;
 329         case V4L2_SEL_TGT_CROP:
 330                 s->r = vin->crop;
 331                 break;
 332         case V4L2_SEL_TGT_COMPOSE_BOUNDS:
 333         case V4L2_SEL_TGT_COMPOSE_DEFAULT:
 334                 s->r.left = s->r.top = 0;
 335                 s->r.width = vin->format.width;
 336                 s->r.height = vin->format.height;
 337                 break;
 338         case V4L2_SEL_TGT_COMPOSE:
 339                 s->r = vin->compose;
 340                 break;
 341         default:
 342                 return -EINVAL;
 343         }
 344 
 345         return 0;
 346 }
 347 
 348 static int rvin_s_selection(struct file *file, void *fh,
 349                             struct v4l2_selection *s)
 350 {
 351         struct rvin_dev *vin = video_drvdata(file);
 352         const struct rvin_video_format *fmt;
 353         struct v4l2_rect r = s->r;
 354         struct v4l2_rect max_rect;
 355         struct v4l2_rect min_rect = {
 356                 .width = 6,
 357                 .height = 2,
 358         };
 359 
 360         if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 361                 return -EINVAL;
 362 
 363         v4l2_rect_set_min_size(&r, &min_rect);
 364 
 365         switch (s->target) {
 366         case V4L2_SEL_TGT_CROP:
 367                 /* Can't crop outside of source input */
 368                 max_rect.top = max_rect.left = 0;
 369                 max_rect.width = vin->source.width;
 370                 max_rect.height = vin->source.height;
 371                 v4l2_rect_map_inside(&r, &max_rect);
 372 
 373                 v4l_bound_align_image(&r.width, 6, vin->source.width, 0,
 374                                       &r.height, 2, vin->source.height, 0, 0);
 375 
 376                 r.top  = clamp_t(s32, r.top, 0, vin->source.height - r.height);
 377                 r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width);
 378 
 379                 vin->crop = s->r = r;
 380 
 381                 vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
 382                         r.width, r.height, r.left, r.top,
 383                         vin->source.width, vin->source.height);
 384                 break;
 385         case V4L2_SEL_TGT_COMPOSE:
 386                 /* Make sure compose rect fits inside output format */
 387                 max_rect.top = max_rect.left = 0;
 388                 max_rect.width = vin->format.width;
 389                 max_rect.height = vin->format.height;
 390                 v4l2_rect_map_inside(&r, &max_rect);
 391 
 392                 /*
 393                  * Composing is done by adding a offset to the buffer address,
 394                  * the HW wants this address to be aligned to HW_BUFFER_MASK.
 395                  * Make sure the top and left values meets this requirement.
 396                  */
 397                 while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
 398                         r.top--;
 399 
 400                 fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
 401                 while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
 402                         r.left--;
 403 
 404                 vin->compose = s->r = r;
 405 
 406                 vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
 407                         r.width, r.height, r.left, r.top,
 408                         vin->format.width, vin->format.height);
 409                 break;
 410         default:
 411                 return -EINVAL;
 412         }
 413 
 414         /* HW supports modifying configuration while running */
 415         rvin_crop_scale_comp(vin);
 416 
 417         return 0;
 418 }
 419 
 420 static int rvin_g_pixelaspect(struct file *file, void *priv,
 421                               int type, struct v4l2_fract *f)
 422 {
 423         struct rvin_dev *vin = video_drvdata(file);
 424         struct v4l2_subdev *sd = vin_to_source(vin);
 425 
 426         if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 427                 return -EINVAL;
 428 
 429         return v4l2_subdev_call(sd, video, g_pixelaspect, f);
 430 }
 431 
 432 static int rvin_enum_input(struct file *file, void *priv,
 433                            struct v4l2_input *i)
 434 {
 435         struct rvin_dev *vin = video_drvdata(file);
 436         struct v4l2_subdev *sd = vin_to_source(vin);
 437         int ret;
 438 
 439         if (i->index != 0)
 440                 return -EINVAL;
 441 
 442         ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
 443         if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
 444                 return ret;
 445 
 446         i->type = V4L2_INPUT_TYPE_CAMERA;
 447 
 448         if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
 449                 i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
 450                 i->std = 0;
 451         } else {
 452                 i->capabilities = V4L2_IN_CAP_STD;
 453                 i->std = vin->vdev.tvnorms;
 454         }
 455 
 456         strscpy(i->name, "Camera", sizeof(i->name));
 457 
 458         return 0;
 459 }
 460 
 461 static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
 462 {
 463         *i = 0;
 464         return 0;
 465 }
 466 
 467 static int rvin_s_input(struct file *file, void *priv, unsigned int i)
 468 {
 469         if (i > 0)
 470                 return -EINVAL;
 471         return 0;
 472 }
 473 
 474 static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
 475 {
 476         struct rvin_dev *vin = video_drvdata(file);
 477         struct v4l2_subdev *sd = vin_to_source(vin);
 478 
 479         return v4l2_subdev_call(sd, video, querystd, a);
 480 }
 481 
 482 static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
 483 {
 484         struct rvin_dev *vin = video_drvdata(file);
 485         int ret;
 486 
 487         ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
 488         if (ret < 0)
 489                 return ret;
 490 
 491         vin->std = a;
 492 
 493         /* Changing the standard will change the width/height */
 494         return rvin_reset_format(vin);
 495 }
 496 
 497 static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
 498 {
 499         struct rvin_dev *vin = video_drvdata(file);
 500 
 501         if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
 502                 return -ENOIOCTLCMD;
 503 
 504         *a = vin->std;
 505 
 506         return 0;
 507 }
 508 
 509 static int rvin_subscribe_event(struct v4l2_fh *fh,
 510                                 const struct v4l2_event_subscription *sub)
 511 {
 512         switch (sub->type) {
 513         case V4L2_EVENT_SOURCE_CHANGE:
 514                 return v4l2_event_subscribe(fh, sub, 4, NULL);
 515         }
 516         return v4l2_ctrl_subscribe_event(fh, sub);
 517 }
 518 
 519 static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
 520                                 struct v4l2_enum_dv_timings *timings)
 521 {
 522         struct rvin_dev *vin = video_drvdata(file);
 523         struct v4l2_subdev *sd = vin_to_source(vin);
 524         int ret;
 525 
 526         if (timings->pad)
 527                 return -EINVAL;
 528 
 529         timings->pad = vin->parallel->sink_pad;
 530 
 531         ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
 532 
 533         timings->pad = 0;
 534 
 535         return ret;
 536 }
 537 
 538 static int rvin_s_dv_timings(struct file *file, void *priv_fh,
 539                              struct v4l2_dv_timings *timings)
 540 {
 541         struct rvin_dev *vin = video_drvdata(file);
 542         struct v4l2_subdev *sd = vin_to_source(vin);
 543         int ret;
 544 
 545         ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
 546         if (ret)
 547                 return ret;
 548 
 549         /* Changing the timings will change the width/height */
 550         return rvin_reset_format(vin);
 551 }
 552 
 553 static int rvin_g_dv_timings(struct file *file, void *priv_fh,
 554                              struct v4l2_dv_timings *timings)
 555 {
 556         struct rvin_dev *vin = video_drvdata(file);
 557         struct v4l2_subdev *sd = vin_to_source(vin);
 558 
 559         return v4l2_subdev_call(sd, video, g_dv_timings, timings);
 560 }
 561 
 562 static int rvin_query_dv_timings(struct file *file, void *priv_fh,
 563                                  struct v4l2_dv_timings *timings)
 564 {
 565         struct rvin_dev *vin = video_drvdata(file);
 566         struct v4l2_subdev *sd = vin_to_source(vin);
 567 
 568         return v4l2_subdev_call(sd, video, query_dv_timings, timings);
 569 }
 570 
 571 static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
 572                                struct v4l2_dv_timings_cap *cap)
 573 {
 574         struct rvin_dev *vin = video_drvdata(file);
 575         struct v4l2_subdev *sd = vin_to_source(vin);
 576         int ret;
 577 
 578         if (cap->pad)
 579                 return -EINVAL;
 580 
 581         cap->pad = vin->parallel->sink_pad;
 582 
 583         ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
 584 
 585         cap->pad = 0;
 586 
 587         return ret;
 588 }
 589 
 590 static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
 591 {
 592         struct rvin_dev *vin = video_drvdata(file);
 593         struct v4l2_subdev *sd = vin_to_source(vin);
 594         int ret;
 595 
 596         if (edid->pad)
 597                 return -EINVAL;
 598 
 599         edid->pad = vin->parallel->sink_pad;
 600 
 601         ret = v4l2_subdev_call(sd, pad, get_edid, edid);
 602 
 603         edid->pad = 0;
 604 
 605         return ret;
 606 }
 607 
 608 static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
 609 {
 610         struct rvin_dev *vin = video_drvdata(file);
 611         struct v4l2_subdev *sd = vin_to_source(vin);
 612         int ret;
 613 
 614         if (edid->pad)
 615                 return -EINVAL;
 616 
 617         edid->pad = vin->parallel->sink_pad;
 618 
 619         ret = v4l2_subdev_call(sd, pad, set_edid, edid);
 620 
 621         edid->pad = 0;
 622 
 623         return ret;
 624 }
 625 
 626 static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
 627         .vidioc_querycap                = rvin_querycap,
 628         .vidioc_try_fmt_vid_cap         = rvin_try_fmt_vid_cap,
 629         .vidioc_g_fmt_vid_cap           = rvin_g_fmt_vid_cap,
 630         .vidioc_s_fmt_vid_cap           = rvin_s_fmt_vid_cap,
 631         .vidioc_enum_fmt_vid_cap        = rvin_enum_fmt_vid_cap,
 632 
 633         .vidioc_g_selection             = rvin_g_selection,
 634         .vidioc_s_selection             = rvin_s_selection,
 635 
 636         .vidioc_g_pixelaspect           = rvin_g_pixelaspect,
 637 
 638         .vidioc_enum_input              = rvin_enum_input,
 639         .vidioc_g_input                 = rvin_g_input,
 640         .vidioc_s_input                 = rvin_s_input,
 641 
 642         .vidioc_dv_timings_cap          = rvin_dv_timings_cap,
 643         .vidioc_enum_dv_timings         = rvin_enum_dv_timings,
 644         .vidioc_g_dv_timings            = rvin_g_dv_timings,
 645         .vidioc_s_dv_timings            = rvin_s_dv_timings,
 646         .vidioc_query_dv_timings        = rvin_query_dv_timings,
 647 
 648         .vidioc_g_edid                  = rvin_g_edid,
 649         .vidioc_s_edid                  = rvin_s_edid,
 650 
 651         .vidioc_querystd                = rvin_querystd,
 652         .vidioc_g_std                   = rvin_g_std,
 653         .vidioc_s_std                   = rvin_s_std,
 654 
 655         .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
 656         .vidioc_create_bufs             = vb2_ioctl_create_bufs,
 657         .vidioc_querybuf                = vb2_ioctl_querybuf,
 658         .vidioc_qbuf                    = vb2_ioctl_qbuf,
 659         .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
 660         .vidioc_expbuf                  = vb2_ioctl_expbuf,
 661         .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
 662         .vidioc_streamon                = vb2_ioctl_streamon,
 663         .vidioc_streamoff               = vb2_ioctl_streamoff,
 664 
 665         .vidioc_log_status              = v4l2_ctrl_log_status,
 666         .vidioc_subscribe_event         = rvin_subscribe_event,
 667         .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 668 };
 669 
 670 /* -----------------------------------------------------------------------------
 671  * V4L2 Media Controller
 672  */
 673 
 674 static void rvin_mc_try_format(struct rvin_dev *vin,
 675                                struct v4l2_pix_format *pix)
 676 {
 677         /*
 678          * The V4L2 specification clearly documents the colorspace fields
 679          * as being set by drivers for capture devices. Using the values
 680          * supplied by userspace thus wouldn't comply with the API. Until
 681          * the API is updated force fixed values.
 682          */
 683         pix->colorspace = RVIN_DEFAULT_COLORSPACE;
 684         pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
 685         pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
 686         pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
 687                                                           pix->ycbcr_enc);
 688 
 689         rvin_format_align(vin, pix);
 690 }
 691 
 692 static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
 693                                    struct v4l2_format *f)
 694 {
 695         struct rvin_dev *vin = video_drvdata(file);
 696 
 697         rvin_mc_try_format(vin, &f->fmt.pix);
 698 
 699         return 0;
 700 }
 701 
 702 static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
 703                                  struct v4l2_format *f)
 704 {
 705         struct rvin_dev *vin = video_drvdata(file);
 706 
 707         if (vb2_is_busy(&vin->queue))
 708                 return -EBUSY;
 709 
 710         rvin_mc_try_format(vin, &f->fmt.pix);
 711 
 712         vin->format = f->fmt.pix;
 713 
 714         vin->crop.top = 0;
 715         vin->crop.left = 0;
 716         vin->crop.width = vin->format.width;
 717         vin->crop.height = vin->format.height;
 718         vin->compose = vin->crop;
 719 
 720         return 0;
 721 }
 722 
 723 static int rvin_mc_enum_input(struct file *file, void *priv,
 724                               struct v4l2_input *i)
 725 {
 726         if (i->index != 0)
 727                 return -EINVAL;
 728 
 729         i->type = V4L2_INPUT_TYPE_CAMERA;
 730         strscpy(i->name, "Camera", sizeof(i->name));
 731 
 732         return 0;
 733 }
 734 
 735 static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
 736         .vidioc_querycap                = rvin_querycap,
 737         .vidioc_try_fmt_vid_cap         = rvin_mc_try_fmt_vid_cap,
 738         .vidioc_g_fmt_vid_cap           = rvin_g_fmt_vid_cap,
 739         .vidioc_s_fmt_vid_cap           = rvin_mc_s_fmt_vid_cap,
 740         .vidioc_enum_fmt_vid_cap        = rvin_enum_fmt_vid_cap,
 741 
 742         .vidioc_enum_input              = rvin_mc_enum_input,
 743         .vidioc_g_input                 = rvin_g_input,
 744         .vidioc_s_input                 = rvin_s_input,
 745 
 746         .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
 747         .vidioc_create_bufs             = vb2_ioctl_create_bufs,
 748         .vidioc_querybuf                = vb2_ioctl_querybuf,
 749         .vidioc_qbuf                    = vb2_ioctl_qbuf,
 750         .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
 751         .vidioc_expbuf                  = vb2_ioctl_expbuf,
 752         .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
 753         .vidioc_streamon                = vb2_ioctl_streamon,
 754         .vidioc_streamoff               = vb2_ioctl_streamoff,
 755 
 756         .vidioc_log_status              = v4l2_ctrl_log_status,
 757         .vidioc_subscribe_event         = rvin_subscribe_event,
 758         .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 759 };
 760 
 761 /* -----------------------------------------------------------------------------
 762  * File Operations
 763  */
 764 
 765 static int rvin_power_parallel(struct rvin_dev *vin, bool on)
 766 {
 767         struct v4l2_subdev *sd = vin_to_source(vin);
 768         int power = on ? 1 : 0;
 769         int ret;
 770 
 771         ret = v4l2_subdev_call(sd, core, s_power, power);
 772         if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
 773                 return ret;
 774 
 775         return 0;
 776 }
 777 
 778 static int rvin_open(struct file *file)
 779 {
 780         struct rvin_dev *vin = video_drvdata(file);
 781         int ret;
 782 
 783         ret = pm_runtime_get_sync(vin->dev);
 784         if (ret < 0)
 785                 return ret;
 786 
 787         ret = mutex_lock_interruptible(&vin->lock);
 788         if (ret)
 789                 goto err_pm;
 790 
 791         file->private_data = vin;
 792 
 793         ret = v4l2_fh_open(file);
 794         if (ret)
 795                 goto err_unlock;
 796 
 797         if (vin->info->use_mc)
 798                 ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
 799         else if (v4l2_fh_is_singular_file(file))
 800                 ret = rvin_power_parallel(vin, true);
 801 
 802         if (ret < 0)
 803                 goto err_open;
 804 
 805         ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
 806         if (ret)
 807                 goto err_power;
 808 
 809         mutex_unlock(&vin->lock);
 810 
 811         return 0;
 812 err_power:
 813         if (vin->info->use_mc)
 814                 v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
 815         else if (v4l2_fh_is_singular_file(file))
 816                 rvin_power_parallel(vin, false);
 817 err_open:
 818         v4l2_fh_release(file);
 819 err_unlock:
 820         mutex_unlock(&vin->lock);
 821 err_pm:
 822         pm_runtime_put(vin->dev);
 823 
 824         return ret;
 825 }
 826 
 827 static int rvin_release(struct file *file)
 828 {
 829         struct rvin_dev *vin = video_drvdata(file);
 830         bool fh_singular;
 831         int ret;
 832 
 833         mutex_lock(&vin->lock);
 834 
 835         /* Save the singular status before we call the clean-up helper */
 836         fh_singular = v4l2_fh_is_singular_file(file);
 837 
 838         /* the release helper will cleanup any on-going streaming */
 839         ret = _vb2_fop_release(file, NULL);
 840 
 841         if (vin->info->use_mc) {
 842                 v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
 843         } else {
 844                 if (fh_singular)
 845                         rvin_power_parallel(vin, false);
 846         }
 847 
 848         mutex_unlock(&vin->lock);
 849 
 850         pm_runtime_put(vin->dev);
 851 
 852         return ret;
 853 }
 854 
 855 static const struct v4l2_file_operations rvin_fops = {
 856         .owner          = THIS_MODULE,
 857         .unlocked_ioctl = video_ioctl2,
 858         .open           = rvin_open,
 859         .release        = rvin_release,
 860         .poll           = vb2_fop_poll,
 861         .mmap           = vb2_fop_mmap,
 862         .read           = vb2_fop_read,
 863 };
 864 
 865 void rvin_v4l2_unregister(struct rvin_dev *vin)
 866 {
 867         if (!video_is_registered(&vin->vdev))
 868                 return;
 869 
 870         v4l2_info(&vin->v4l2_dev, "Removing %s\n",
 871                   video_device_node_name(&vin->vdev));
 872 
 873         /* Checks internally if vdev have been init or not */
 874         video_unregister_device(&vin->vdev);
 875 }
 876 
 877 static void rvin_notify(struct v4l2_subdev *sd,
 878                         unsigned int notification, void *arg)
 879 {
 880         struct rvin_dev *vin =
 881                 container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev);
 882 
 883         switch (notification) {
 884         case V4L2_DEVICE_NOTIFY_EVENT:
 885                 v4l2_event_queue(&vin->vdev, arg);
 886                 break;
 887         default:
 888                 break;
 889         }
 890 }
 891 
 892 int rvin_v4l2_register(struct rvin_dev *vin)
 893 {
 894         struct video_device *vdev = &vin->vdev;
 895         int ret;
 896 
 897         vin->v4l2_dev.notify = rvin_notify;
 898 
 899         /* video node */
 900         vdev->v4l2_dev = &vin->v4l2_dev;
 901         vdev->queue = &vin->queue;
 902         snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id);
 903         vdev->release = video_device_release_empty;
 904         vdev->lock = &vin->lock;
 905         vdev->fops = &rvin_fops;
 906         vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
 907                 V4L2_CAP_READWRITE;
 908 
 909         /* Set a default format */
 910         vin->format.pixelformat = RVIN_DEFAULT_FORMAT;
 911         vin->format.width = RVIN_DEFAULT_WIDTH;
 912         vin->format.height = RVIN_DEFAULT_HEIGHT;
 913         vin->format.field = RVIN_DEFAULT_FIELD;
 914         vin->format.colorspace = RVIN_DEFAULT_COLORSPACE;
 915 
 916         if (vin->info->use_mc) {
 917                 vdev->ioctl_ops = &rvin_mc_ioctl_ops;
 918         } else {
 919                 vdev->ioctl_ops = &rvin_ioctl_ops;
 920                 rvin_reset_format(vin);
 921         }
 922 
 923         rvin_format_align(vin, &vin->format);
 924 
 925         ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1);
 926         if (ret) {
 927                 vin_err(vin, "Failed to register video device\n");
 928                 return ret;
 929         }
 930 
 931         video_set_drvdata(&vin->vdev, vin);
 932 
 933         v4l2_info(&vin->v4l2_dev, "Device registered as %s\n",
 934                   video_device_node_name(&vin->vdev));
 935 
 936         return ret;
 937 }

/* [<][>][^][v][top][bottom][index][help] */