aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/video4linux/v4l2-framework.txt12
-rw-r--r--drivers/media/video/v4l2-subdev.c64
-rw-r--r--include/media/v4l2-subdev.h12
3 files changed, 88 insertions, 0 deletions
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 493ffd1b1cf5..fe53177f0d3c 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -316,6 +316,18 @@ If the subdev driver intends to process video and integrate with the media
316framework, it must implement format related functionality using 316framework, it must implement format related functionality using
317v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops. 317v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops.
318 318
319In that case, the subdev driver may set the link_validate field to provide
320its own link validation function. The link validation function is called for
321every link in the pipeline where both of the ends of the links are V4L2
322sub-devices. The driver is still responsible for validating the correctness
323of the format configuration between sub-devices and video nodes.
324
325If link_validate op is not set, the default function
326v4l2_subdev_link_validate_default() is used instead. This function ensures
327that width, height and the media bus pixel code are equal on both source and
328sink of the link. Subdev drivers are also free to use this function to
329perform the checks mentioned above in addition to their own checks.
330
319A device (bridge) driver needs to register the v4l2_subdev with the 331A device (bridge) driver needs to register the v4l2_subdev with the
320v4l2_device: 332v4l2_device:
321 333
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 268d80584101..db6e859b93d4 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -387,6 +387,70 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
387 .poll = subdev_poll, 387 .poll = subdev_poll,
388}; 388};
389 389
390#ifdef CONFIG_MEDIA_CONTROLLER
391int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
392 struct media_link *link,
393 struct v4l2_subdev_format *source_fmt,
394 struct v4l2_subdev_format *sink_fmt)
395{
396 if (source_fmt->format.width != sink_fmt->format.width
397 || source_fmt->format.height != sink_fmt->format.height
398 || source_fmt->format.code != sink_fmt->format.code)
399 return -EINVAL;
400
401 return 0;
402}
403EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
404
405static int
406v4l2_subdev_link_validate_get_format(struct media_pad *pad,
407 struct v4l2_subdev_format *fmt)
408{
409 switch (media_entity_type(pad->entity)) {
410 case MEDIA_ENT_T_V4L2_SUBDEV:
411 fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
412 fmt->pad = pad->index;
413 return v4l2_subdev_call(media_entity_to_v4l2_subdev(
414 pad->entity),
415 pad, get_fmt, NULL, fmt);
416 default:
417 WARN(1, "Driver bug! Wrong media entity type %d, entity %s\n",
418 media_entity_type(pad->entity), pad->entity->name);
419 /* Fall through */
420 case MEDIA_ENT_T_DEVNODE_V4L:
421 return -EINVAL;
422 }
423}
424
425int v4l2_subdev_link_validate(struct media_link *link)
426{
427 struct v4l2_subdev *sink;
428 struct v4l2_subdev_format sink_fmt, source_fmt;
429 int rval;
430
431 rval = v4l2_subdev_link_validate_get_format(
432 link->source, &source_fmt);
433 if (rval < 0)
434 return 0;
435
436 rval = v4l2_subdev_link_validate_get_format(
437 link->sink, &sink_fmt);
438 if (rval < 0)
439 return 0;
440
441 sink = media_entity_to_v4l2_subdev(link->sink->entity);
442
443 rval = v4l2_subdev_call(sink, pad, link_validate, link,
444 &source_fmt, &sink_fmt);
445 if (rval != -ENOIOCTLCMD)
446 return rval;
447
448 return v4l2_subdev_link_validate_default(
449 sink, link, &source_fmt, &sink_fmt);
450}
451EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
452#endif /* CONFIG_MEDIA_CONTROLLER */
453
390void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) 454void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
391{ 455{
392 INIT_LIST_HEAD(&sd->list); 456 INIT_LIST_HEAD(&sd->list);
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 7e850355a6f0..1c2318b15bd2 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -470,6 +470,11 @@ struct v4l2_subdev_pad_ops {
470 struct v4l2_subdev_selection *sel); 470 struct v4l2_subdev_selection *sel);
471 int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 471 int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
472 struct v4l2_subdev_selection *sel); 472 struct v4l2_subdev_selection *sel);
473#ifdef CONFIG_MEDIA_CONTROLLER
474 int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link,
475 struct v4l2_subdev_format *source_fmt,
476 struct v4l2_subdev_format *sink_fmt);
477#endif /* CONFIG_MEDIA_CONTROLLER */
473}; 478};
474 479
475struct v4l2_subdev_ops { 480struct v4l2_subdev_ops {
@@ -602,6 +607,13 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
602 return sd->host_priv; 607 return sd->host_priv;
603} 608}
604 609
610#ifdef CONFIG_MEDIA_CONTROLLER
611int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
612 struct media_link *link,
613 struct v4l2_subdev_format *source_fmt,
614 struct v4l2_subdev_format *sink_fmt);
615int v4l2_subdev_link_validate(struct media_link *link);
616#endif /* CONFIG_MEDIA_CONTROLLER */
605void v4l2_subdev_init(struct v4l2_subdev *sd, 617void v4l2_subdev_init(struct v4l2_subdev *sd,
606 const struct v4l2_subdev_ops *ops); 618 const struct v4l2_subdev_ops *ops);
607 619