static void iss_video_buf_queue(struct vb2_buffer *vb) { struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue); struct iss_video *video = vfh->video; struct iss_buffer *buffer = container_of(vb, struct iss_buffer, vb); struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); unsigned long flags; bool empty; spin_lock_irqsave(&video->qlock, flags); /* Mark the buffer is faulty and give it back to the queue immediately * if the video node has registered an error. vb2 will perform the same * check when preparing the buffer, but that is inherently racy, so we * need to handle the race condition with an authoritative check here. */ if (unlikely(video->error)) { vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&video->qlock, flags); return; } empty = list_empty(&video->dmaqueue); list_add_tail(&buffer->list, &video->dmaqueue); spin_unlock_irqrestore(&video->qlock, flags); if (empty) { enum iss_pipeline_state state; unsigned int start; if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISS_PIPELINE_QUEUE_OUTPUT; else state = ISS_PIPELINE_QUEUE_INPUT; spin_lock_irqsave(&pipe->lock, flags); pipe->state |= state; video->ops->queue(video, buffer); video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_QUEUED; start = iss_pipeline_ready(pipe); if (start) pipe->state |= ISS_PIPELINE_STREAM; spin_unlock_irqrestore(&pipe->lock, flags); if (start) omap4iss_pipeline_set_stream(pipe, ISS_PIPELINE_STREAM_SINGLESHOT); } }
/* * iss_module_sync_idle - Helper to sync module with its idle state * @me: ISS submodule's media entity * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization * @stopping: flag which tells module wants to stop * * This function checks if ISS submodule needs to wait for next interrupt. If * yes, makes the caller to sleep while waiting for such event. */ int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, atomic_t *stopping) { struct iss_pipeline *pipe = to_iss_pipeline(me); struct iss_video *video = pipe->output; unsigned long flags; if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED || (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT && !iss_pipeline_ready(pipe))) return 0; /* * atomic_set() doesn't include memory barrier on ARM platform for SMP * scenario. We'll call it here to avoid race conditions. */ atomic_set(stopping, 1); smp_wmb(); /* * If module is the last one, it's writing to memory. In this case, * it's necessary to check if the module is already paused due to * DMA queue underrun or if it has to wait for next interrupt to be * idle. * If it isn't the last one, the function won't sleep but *stopping * will still be set to warn next submodule caller's interrupt the * module wants to be idle. */ if (!iss_pipeline_is_last(me)) return 0; spin_lock_irqsave(&video->qlock, flags); if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { spin_unlock_irqrestore(&video->qlock, flags); atomic_set(stopping, 0); smp_wmb(); return 0; } spin_unlock_irqrestore(&video->qlock, flags); if (!wait_event_timeout(*wait, !atomic_read(stopping), msecs_to_jiffies(1000))) { atomic_set(stopping, 0); smp_wmb(); return -ETIMEDOUT; } return 0; }
static void iss_video_buf_queue(struct vb2_buffer *vb) { struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue); struct iss_video *video = vfh->video; struct iss_buffer *buffer = container_of(vb, struct iss_buffer, vb); struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); unsigned long flags; bool empty; spin_lock_irqsave(&video->qlock, flags); if (unlikely(video->error)) { vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&video->qlock, flags); return; } empty = list_empty(&video->dmaqueue); list_add_tail(&buffer->list, &video->dmaqueue); spin_unlock_irqrestore(&video->qlock, flags); if (empty) { enum iss_pipeline_state state; unsigned int start; if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) state = ISS_PIPELINE_QUEUE_OUTPUT; else state = ISS_PIPELINE_QUEUE_INPUT; spin_lock_irqsave(&pipe->lock, flags); pipe->state |= state; video->ops->queue(video, buffer); video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_QUEUED; start = iss_pipeline_ready(pipe); if (start) pipe->state |= ISS_PIPELINE_STREAM; spin_unlock_irqrestore(&pipe->lock, flags); if (start) omap4iss_pipeline_set_stream(pipe, ISS_PIPELINE_STREAM_SINGLESHOT); } }