/** * struct xvip_graph_entity - Entity in the video graph * @asd: subdev asynchronous registration information * @entity: media entity, from the corresponding V4L2 subdev * @subdev: V4L2 subdev
*/ struct xvip_graph_entity { struct v4l2_async_connection asd; /* must be first */ struct media_entity *entity; struct v4l2_subdev *subdev;
};
ret = v4l2_fwnode_parse_link(ep, &link); if (ret < 0) {
dev_err(xdev->dev, "failed to parse link for %p\n",
ep); continue;
}
/* Skip sink ports, they will be processed from the other end of * the link.
*/ if (link.local_port >= local->num_pads) {
dev_err(xdev->dev, "invalid port number %u for %p\n",
link.local_port, link.local_node);
v4l2_fwnode_put_link(&link);
ret = -EINVAL; break;
}
local_pad = &local->pads[link.local_port];
if (local_pad->flags & MEDIA_PAD_FL_SINK) {
dev_dbg(xdev->dev, "skipping sink port %p:%u\n",
link.local_node, link.local_port);
v4l2_fwnode_put_link(&link); continue;
}
/* Skip DMA engines, they will be processed separately. */ if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) {
dev_dbg(xdev->dev, "skipping DMA port %p:%u\n",
link.local_node, link.local_port);
v4l2_fwnode_put_link(&link); continue;
}
/* Find the remote entity. */
ent = xvip_graph_find_entity(xdev, link.remote_node); if (ent == NULL) {
dev_err(xdev->dev, "no entity found for %p\n",
link.remote_node);
v4l2_fwnode_put_link(&link);
ret = -ENODEV; break;
}
remote = ent->entity;
if (link.remote_port >= remote->num_pads) {
dev_err(xdev->dev, "invalid port number %u on %p\n",
link.remote_port, link.remote_node);
v4l2_fwnode_put_link(&link);
ret = -EINVAL; break;
}
remote_pad = &remote->pads[link.remote_port];
v4l2_fwnode_put_link(&link);
/* Create the media link. */
dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
local->name, local_pad->index,
remote->name, remote_pad->index);
ret = media_create_pad_link(local, local_pad->index,
remote, remote_pad->index,
link_flags); if (ret < 0) {
dev_err(xdev->dev, "failed to create %s:%u -> %s:%u link\n",
local->name, local_pad->index,
remote->name, remote_pad->index); break;
}
}
ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); if (ret < 0) {
dev_err(xdev->dev, "failed to parse link for %pOF\n",
ep); continue;
}
/* Find the DMA engine. */
dma = xvip_graph_find_dma(xdev, link.local_port); if (dma == NULL) {
dev_err(xdev->dev, "no DMA engine found for port %u\n",
link.local_port);
v4l2_fwnode_put_link(&link);
ret = -EINVAL; break;
}
dev_dbg(xdev->dev, "creating link for DMA engine %s\n",
dma->video.name);
/* Find the remote entity. */
ent = xvip_graph_find_entity(xdev, link.remote_node); if (ent == NULL) {
dev_err(xdev->dev, "no entity found for %pOF\n",
to_of_node(link.remote_node));
v4l2_fwnode_put_link(&link);
ret = -ENODEV; break;
}
if (link.remote_port >= ent->entity->num_pads) {
dev_err(xdev->dev, "invalid port number %u on %pOF\n",
link.remote_port,
to_of_node(link.remote_node));
v4l2_fwnode_put_link(&link);
ret = -EINVAL; break;
}
staticint xvip_graph_parse_one(struct xvip_composite_device *xdev, struct fwnode_handle *fwnode)
{ struct fwnode_handle *remote; struct fwnode_handle *ep = NULL; int ret = 0;
dev_dbg(xdev->dev, "parsing node %p\n", fwnode);
while (1) { struct xvip_graph_entity *xge;
ep = fwnode_graph_get_next_endpoint(fwnode, ep); if (ep == NULL) break;
dev_dbg(xdev->dev, "handling endpoint %p\n", ep);
remote = fwnode_graph_get_remote_port_parent(ep); if (remote == NULL) {
ret = -EINVAL; goto err_notifier_cleanup;
}
fwnode_handle_put(ep);
/* Skip entities that we have already processed. */ if (remote == of_fwnode_handle(xdev->dev->of_node) ||
xvip_graph_find_entity(xdev, remote)) {
fwnode_handle_put(remote); continue;
}
xge = v4l2_async_nf_add_fwnode(&xdev->notifier, remote, struct xvip_graph_entity);
fwnode_handle_put(remote); if (IS_ERR(xge)) {
ret = PTR_ERR(xge); goto err_notifier_cleanup;
}
}
/* * Walk the links to parse the full graph. Start by parsing the * composite node and then parse entities in turn. The list_for_each * loop will handle entities added at the end of the list while walking * the links.
*/
ret = xvip_graph_parse_one(xdev, of_fwnode_handle(xdev->dev->of_node)); if (ret < 0) return 0;
list_for_each_entry(asd, &xdev->notifier.waiting_list, asc_entry) {
entity = to_xvip_entity(asd);
ret = xvip_graph_parse_one(xdev, entity->asd.match.fwnode); if (ret < 0) {
v4l2_async_nf_cleanup(&xdev->notifier); break;
}
}
/* Parse the graph to extract a list of subdevice DT nodes. */
ret = xvip_graph_parse(xdev); if (ret < 0) {
dev_err(xdev->dev, "graph parsing failed\n"); goto done;
}
if (list_empty(&xdev->notifier.waiting_list)) {
dev_err(xdev->dev, "no subdev found in graph\n");
ret = -ENOENT; goto done;
}
/* Register the subdevices notifier. */
xdev->notifier.ops = &xvip_graph_notify_ops;
ret = v4l2_async_nf_register(&xdev->notifier); if (ret < 0) {
dev_err(xdev->dev, "notifier registration failed\n"); goto done;
}
ret = 0;
done: if (ret < 0)
xvip_graph_cleanup(xdev);
return ret;
}
/* ----------------------------------------------------------------------------- * Media Controller and V4L2
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.