diff options
Diffstat (limited to 'drivers/staging/media/omap4iss/iss.c')
-rw-r--r-- | drivers/staging/media/omap4iss/iss.c | 111 |
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); |