/* Return a pointer to the ISP video instance at the far end of the pipeline. */ static int isp_video_get_graph_data(struct isp_video *video, struct isp_pipeline *pipe) { struct media_entity_graph graph; struct media_entity *entity = &video->video.entity; struct media_device *mdev = entity->graph_obj.mdev; struct isp_video *far_end = NULL; int ret; mutex_lock(&mdev->graph_mutex); ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev); if (ret) { mutex_unlock(&mdev->graph_mutex); return ret; } media_entity_graph_walk_start(&graph, entity); while ((entity = media_entity_graph_walk_next(&graph))) { struct isp_video *__video; media_entity_enum_set(&pipe->ent_enum, entity); if (far_end != NULL) continue; if (entity == &video->video.entity) continue; if (!is_media_entity_v4l2_video_device(entity)) continue; __video = to_isp_video(media_entity_to_video_device(entity)); if (__video->type != video->type) far_end = __video; } mutex_unlock(&mdev->graph_mutex); media_entity_graph_walk_cleanup(&graph); if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { pipe->input = far_end; pipe->output = video; } else { if (far_end == NULL) return -EPIPE; pipe->input = video; pipe->output = far_end; } return 0; }
/* Locking: called with entity->graph_obj.mdev->graph_mutex mutex held. */ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable, struct media_entity_graph *graph) { struct media_entity *entity_err = entity; int ret; /* * Walk current graph and call the pipeline open/close routine for each * opened video node that belongs to the graph of entities connected * through active links. This is needed as we cannot power on/off the * subdevs in random order. */ media_entity_graph_walk_start(graph, entity); while ((entity = media_entity_graph_walk_next(graph))) { if (!is_media_entity_v4l2_video_device(entity)) continue; ret = __fimc_md_modify_pipeline(entity, enable); if (ret < 0) goto err; } return 0; err: media_entity_graph_walk_start(graph, entity_err); while ((entity_err = media_entity_graph_walk_next(graph))) { if (!is_media_entity_v4l2_video_device(entity_err)) continue; __fimc_md_modify_pipeline(entity_err, !enable); if (entity_err == entity) break; } return ret; }
/* * pipeline_pm_use_count - Count the number of users of a pipeline * @entity: The entity * * Return the total number of users of all video device nodes in the pipeline. */ static int pipeline_pm_use_count(struct media_entity *entity, struct media_entity_graph *graph) { int use = 0; media_entity_graph_walk_start(graph, entity); while ((entity = media_entity_graph_walk_next(graph))) { if (is_media_entity_v4l2_video_device(entity)) use += entity->use_count; } return use; }
/* make a note of pipeline details */ static int vpfe_prepare_pipeline(struct vpfe_video_device *video) { struct media_graph graph; struct media_entity *entity = &video->video_dev.entity; struct media_device *mdev = entity->graph_obj.mdev; struct vpfe_pipeline *pipe = &video->pipe; struct vpfe_video_device *far_end = NULL; int ret; pipe->input_num = 0; pipe->output_num = 0; if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) pipe->inputs[pipe->input_num++] = video; else pipe->outputs[pipe->output_num++] = video; mutex_lock(&mdev->graph_mutex); ret = media_graph_walk_init(&graph, mdev); if (ret) { mutex_unlock(&mdev->graph_mutex); return -ENOMEM; } media_graph_walk_start(&graph, entity); while ((entity = media_graph_walk_next(&graph))) { if (entity == &video->video_dev.entity) continue; if (!is_media_entity_v4l2_video_device(entity)) continue; far_end = to_vpfe_video(media_entity_to_video_device(entity)); if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) pipe->inputs[pipe->input_num++] = far_end; else pipe->outputs[pipe->output_num++] = far_end; } media_graph_walk_cleanup(&graph); mutex_unlock(&mdev->graph_mutex); return 0; }
static int vdic_link_setup(struct media_entity *entity, const struct media_pad *local, const struct media_pad *remote, u32 flags) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct vdic_priv *priv = v4l2_get_subdevdata(sd); struct v4l2_subdev *remote_sd; int ret = 0; dev_dbg(priv->dev, "link setup %s -> %s", remote->entity->name, local->entity->name); mutex_lock(&priv->lock); if (local->flags & MEDIA_PAD_FL_SOURCE) { if (!is_media_entity_v4l2_subdev(remote->entity)) { ret = -EINVAL; goto out; } remote_sd = media_entity_to_v4l2_subdev(remote->entity); if (flags & MEDIA_LNK_FL_ENABLED) { if (priv->sink_sd) { ret = -EBUSY; goto out; } priv->sink_sd = remote_sd; } else { priv->sink_sd = NULL; } goto out; } /* this is a sink pad */ if (flags & MEDIA_LNK_FL_ENABLED) { if (priv->src) { ret = -EBUSY; goto out; } } else { priv->src = NULL; goto out; } if (local->index == VDIC_SINK_PAD_IDMAC) { struct imx_media_video_dev *vdev = priv->vdev; if (!is_media_entity_v4l2_video_device(remote->entity)) { ret = -EINVAL; goto out; } if (!vdev) { ret = -ENODEV; goto out; } priv->csi_direct = false; } else { if (!is_media_entity_v4l2_subdev(remote->entity)) { ret = -EINVAL; goto out; } remote_sd = media_entity_to_v4l2_subdev(remote->entity); /* direct pad must connect to a CSI */ if (!(remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) || remote->index != CSI_SRC_PAD_DIRECT) { ret = -EINVAL; goto out; } priv->csi_direct = true; } priv->src = remote->entity; /* record which input pad is now active */ priv->active_input_pad = local->index; out: mutex_unlock(&priv->lock); return ret; }