diff options
-rw-r--r-- | Documentation/video4linux/v4l2-framework.txt | 12 | ||||
-rw-r--r-- | drivers/media/video/v4l2-subdev.c | 64 | ||||
-rw-r--r-- | include/media/v4l2-subdev.h | 12 |
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 | |||
316 | framework, it must implement format related functionality using | 316 | framework, it must implement format related functionality using |
317 | v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops. | 317 | v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops. |
318 | 318 | ||
319 | In that case, the subdev driver may set the link_validate field to provide | ||
320 | its own link validation function. The link validation function is called for | ||
321 | every link in the pipeline where both of the ends of the links are V4L2 | ||
322 | sub-devices. The driver is still responsible for validating the correctness | ||
323 | of the format configuration between sub-devices and video nodes. | ||
324 | |||
325 | If link_validate op is not set, the default function | ||
326 | v4l2_subdev_link_validate_default() is used instead. This function ensures | ||
327 | that width, height and the media bus pixel code are equal on both source and | ||
328 | sink of the link. Subdev drivers are also free to use this function to | ||
329 | perform the checks mentioned above in addition to their own checks. | ||
330 | |||
319 | A device (bridge) driver needs to register the v4l2_subdev with the | 331 | A device (bridge) driver needs to register the v4l2_subdev with the |
320 | v4l2_device: | 332 | v4l2_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 | ||
391 | int 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 | } | ||
403 | EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); | ||
404 | |||
405 | static int | ||
406 | v4l2_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 | |||
425 | int 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 | } | ||
451 | EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); | ||
452 | #endif /* CONFIG_MEDIA_CONTROLLER */ | ||
453 | |||
390 | void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) | 454 | void 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 | ||
475 | struct v4l2_subdev_ops { | 480 | struct 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 | ||
611 | int 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); | ||
615 | int v4l2_subdev_link_validate(struct media_link *link); | ||
616 | #endif /* CONFIG_MEDIA_CONTROLLER */ | ||
605 | void v4l2_subdev_init(struct v4l2_subdev *sd, | 617 | void v4l2_subdev_init(struct v4l2_subdev *sd, |
606 | const struct v4l2_subdev_ops *ops); | 618 | const struct v4l2_subdev_ops *ops); |
607 | 619 | ||