aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/omap4iss/iss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/omap4iss/iss.c')
-rw-r--r--drivers/staging/media/omap4iss/iss.c111
1 files changed, 63 insertions, 48 deletions
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index cc1dfadd91eb..44b81a2c8b6f 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -560,41 +560,28 @@ static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
*/
/*
- * iss_pipeline_enable - Enable streaming on a pipeline
+ * iss_pipeline_disable - Disable streaming on a pipeline
* @pipe: ISS pipeline
- * @mode: Stream mode (single shot or continuous)
+ * @until: entity at which to stop pipeline walk
*
- * Walk the entities chain starting at the pipeline output video node and start
- * all modules in the chain in the given mode.
+ * Walk the entities chain starting at the pipeline output video node and stop
+ * all modules in the chain. Wait synchronously for the modules to be stopped if
+ * necessary.
*
- * Return 0 if successful, or the return value of the failed video::s_stream
- * operation otherwise.
+ * If the until argument isn't NULL, stop the pipeline walk when reaching the
+ * until entity. This is used to disable a partially started pipeline due to a
+ * subdev start error.
*/
-static int iss_pipeline_enable(struct iss_pipeline *pipe,
- enum iss_pipeline_stream_state mode)
+static int iss_pipeline_disable(struct iss_pipeline *pipe,
+ struct media_entity *until)
{
struct iss_device *iss = pipe->output->iss;
struct media_entity *entity;
struct media_pad *pad;
struct v4l2_subdev *subdev;
- unsigned long flags;
+ int failure = 0;
int ret;
- /* If one of the entities in the pipeline has crashed it will not work
- * properly. Refuse to start streaming in that case. This check must be
- * performed before the loop below to avoid starting entities if the
- * pipeline won't start anyway (those entities would then likely fail to
- * stop, making the problem worse).
- */
- if (pipe->entities & iss->crashed)
- return -EIO;
-
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
- spin_unlock_irqrestore(&pipe->lock, flags);
-
- pipe->do_propagation = false;
-
entity = &pipe->output->video.entity;
while (1) {
pad = &entity->pads[0];
@@ -607,33 +594,62 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe,
break;
entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
+ if (entity == until)
+ break;
- ret = v4l2_subdev_call(subdev, video, s_stream, mode);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
+ subdev = media_entity_to_v4l2_subdev(entity);
+ ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+ if (ret < 0) {
+ dev_dbg(iss->dev, "%s: module stop timeout.\n",
+ subdev->name);
+ /* If the entity failed to stopped, assume it has
+ * crashed. Mark it as such, the ISS will be reset when
+ * applications will release it.
+ */
+ iss->crashed |= 1U << subdev->entity.id;
+ failure = -ETIMEDOUT;
+ }
}
- iss_print_status(pipe->output->iss);
- return 0;
+
+ return failure;
}
/*
- * iss_pipeline_disable - Disable streaming on a pipeline
+ * iss_pipeline_enable - Enable streaming on a pipeline
* @pipe: ISS pipeline
+ * @mode: Stream mode (single shot or continuous)
*
- * Walk the entities chain starting at the pipeline output video node and stop
- * all modules in the chain. Wait synchronously for the modules to be stopped if
- * necessary.
+ * Walk the entities chain starting at the pipeline output video node and start
+ * all modules in the chain in the given mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise.
*/
-static int iss_pipeline_disable(struct iss_pipeline *pipe)
+static int iss_pipeline_enable(struct iss_pipeline *pipe,
+ enum iss_pipeline_stream_state mode)
{
struct iss_device *iss = pipe->output->iss;
struct media_entity *entity;
struct media_pad *pad;
struct v4l2_subdev *subdev;
- int failure = 0;
+ unsigned long flags;
int ret;
+ /* If one of the entities in the pipeline has crashed it will not work
+ * properly. Refuse to start streaming in that case. This check must be
+ * performed before the loop below to avoid starting entities if the
+ * pipeline won't start anyway (those entities would then likely fail to
+ * stop, making the problem worse).
+ */
+ if (pipe->entities & iss->crashed)
+ return -EIO;
+
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
+ spin_unlock_irqrestore(&pipe->lock, flags);
+
+ pipe->do_propagation = false;
+
entity = &pipe->output->video.entity;
while (1) {
pad = &entity->pads[0];
@@ -648,20 +664,19 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe)
entity = pad->entity;
subdev = media_entity_to_v4l2_subdev(entity);
- ret = v4l2_subdev_call(subdev, video, s_stream, 0);
- if (ret < 0) {
- dev_dbg(iss->dev, "%s: module stop timeout.\n",
- subdev->name);
- /* If the entity failed to stopped, assume it has
- * crashed. Mark it as such, the ISS will be reset when
- * applications will release it.
- */
- iss->crashed |= 1U << subdev->entity.id;
- failure = -ETIMEDOUT;
+ ret = v4l2_subdev_call(subdev, video, s_stream, mode);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ iss_pipeline_disable(pipe, entity);
+ return ret;
}
+
+ if (subdev == &iss->csi2a.subdev ||
+ subdev == &iss->csi2b.subdev)
+ pipe->do_propagation = true;
}
- return failure;
+ iss_print_status(pipe->output->iss);
+ return 0;
}
/*
@@ -682,7 +697,7 @@ int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
int ret;
if (state == ISS_PIPELINE_STREAM_STOPPED)
- ret = iss_pipeline_disable(pipe);
+ ret = iss_pipeline_disable(pipe, NULL);
else
ret = iss_pipeline_enable(pipe, state);