diff options
Diffstat (limited to 'drivers/media/platform/video-mux.c')
-rw-r--r-- | drivers/media/platform/video-mux.c | 70 |
1 files changed, 46 insertions, 24 deletions
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index ddd0e338f9e4..7b6c96a29aa5 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -21,6 +21,7 @@ struct video_mux { struct v4l2_subdev subdev; + struct v4l2_async_notifier notifier; struct media_pad *pads; struct v4l2_mbus_framefmt *format_mbus; struct mux_control *mux; @@ -330,36 +331,49 @@ static const struct v4l2_subdev_ops video_mux_subdev_ops = { .video = &video_mux_subdev_video_ops, }; -static int video_mux_parse_endpoint(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd) -{ - /* - * it's not an error if remote is missing on a video-mux - * input port, return -ENOTCONN to skip this endpoint with - * no error. - */ - return fwnode_device_is_available(asd->match.fwnode) ? 0 : -ENOTCONN; -} - static int video_mux_async_register(struct video_mux *vmux, unsigned int num_input_pads) { - unsigned int i, *ports; + unsigned int i; int ret; - ports = kcalloc(num_input_pads, sizeof(*ports), GFP_KERNEL); - if (!ports) - return -ENOMEM; - for (i = 0; i < num_input_pads; i++) - ports[i] = i; + v4l2_async_notifier_init(&vmux->notifier); - ret = v4l2_async_register_fwnode_subdev( - &vmux->subdev, sizeof(struct v4l2_async_subdev), - ports, num_input_pads, video_mux_parse_endpoint); + for (i = 0; i < num_input_pads; i++) { + struct v4l2_async_subdev *asd; + struct fwnode_handle *ep; - kfree(ports); - return ret; + ep = fwnode_graph_get_endpoint_by_id( + dev_fwnode(vmux->subdev.dev), i, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) + continue; + + asd = kzalloc(sizeof(*asd), GFP_KERNEL); + if (!asd) { + fwnode_handle_put(ep); + return -ENOMEM; + } + + ret = v4l2_async_notifier_add_fwnode_remote_subdev( + &vmux->notifier, ep, asd); + + fwnode_handle_put(ep); + + if (ret) { + kfree(asd); + /* OK if asd already exists */ + if (ret != -EEXIST) + return ret; + } + } + + ret = v4l2_async_subdev_notifier_register(&vmux->subdev, + &vmux->notifier); + if (ret) + return ret; + + return v4l2_async_register_subdev(&vmux->subdev); } static int video_mux_probe(struct platform_device *pdev) @@ -434,7 +448,13 @@ static int video_mux_probe(struct platform_device *pdev) vmux->subdev.entity.ops = &video_mux_ops; - return video_mux_async_register(vmux, num_pads - 1); + ret = video_mux_async_register(vmux, num_pads - 1); + if (ret) { + v4l2_async_notifier_unregister(&vmux->notifier); + v4l2_async_notifier_cleanup(&vmux->notifier); + } + + return ret; } static int video_mux_remove(struct platform_device *pdev) @@ -442,6 +462,8 @@ static int video_mux_remove(struct platform_device *pdev) struct video_mux *vmux = platform_get_drvdata(pdev); struct v4l2_subdev *sd = &vmux->subdev; + v4l2_async_notifier_unregister(&vmux->notifier); + v4l2_async_notifier_cleanup(&vmux->notifier); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); |