diff options
author | Sungchun Kang <sungchun.kang@samsung.com> | 2011-02-07 15:59:46 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-22 04:54:13 -0300 |
commit | 8ec737ffccd7fab629e28427b4d0581ce62ffedd (patch) | |
tree | 5f6539a5dad7db0b78f6270e0bafdfe53111777c /drivers/media/video/s5p-fimc/fimc-core.c | |
parent | 4174ebf5ebd7a09589ff8ff3bc3246ea0a9bd356 (diff) |
[media] s5p-fimc: fix ISR and buffer handling for fimc-capture
In some cases fimc H/W did not stop although there were no output
buffers available. So the capture deactivation interrupt routine
is modified and the state of ST_CAPT_RUN is cleared only
in the LAST-IRQ call.
After LAST-IRQ is generated, H/W pointer will be skipped by 1 frame.
(reference by user manual) So, S/W pointer should be increased too.
Reviewed-by Jonghun Han <jonghun.han@samsung.com>
Signed-off-by: Sungchun Kang <sungchun.kang@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/s5p-fimc/fimc-core.c')
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index cd8a3003f1a..fdf4270fcb6 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -327,9 +327,10 @@ static int stop_streaming(struct vb2_queue *q) static void fimc_capture_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; - struct fimc_vid_buffer *v_buf = NULL; + struct fimc_vid_buffer *v_buf; - if (!list_empty(&cap->active_buf_q)) { + if (!list_empty(&cap->active_buf_q) && + test_bit(ST_CAPT_RUN, &fimc->state)) { v_buf = active_queue_pop(cap); vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } @@ -345,9 +346,6 @@ static void fimc_capture_handler(struct fimc_dev *fimc) fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); v_buf->index = cap->buf_index; - dbg("hw ptr: %d, sw ptr: %d", - fimc_hw_get_frame_index(fimc), cap->buf_index); - /* Move the buffer to the capture active queue */ active_queue_add(cap, v_buf); @@ -356,19 +354,25 @@ static void fimc_capture_handler(struct fimc_dev *fimc) if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; + } + + if (cap->active_buf_cnt == 0) { + clear_bit(ST_CAPT_RUN, &fimc->state); - } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) && - cap->active_buf_cnt <= 1) { - fimc_deactivate_capture(fimc); + if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) + cap->buf_index = 0; + } else { + set_bit(ST_CAPT_RUN, &fimc->state); } - dbg("frame: %d, active_buf_cnt= %d", + dbg("frame: %d, active_buf_cnt: %d", fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); } static irqreturn_t fimc_isr(int irq, void *priv) { struct fimc_dev *fimc = priv; + struct fimc_vid_cap *cap = &fimc->vid_cap; BUG_ON(!fimc); fimc_hw_clear_irq(fimc); @@ -396,12 +400,13 @@ static irqreturn_t fimc_isr(int irq, void *priv) } - if (test_bit(ST_CAPT_RUN, &fimc->state)) - fimc_capture_handler(fimc); + if (test_bit(ST_CAPT_PEND, &fimc->state)) { + fimc_capture_irq_handler(fimc); - if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) { - set_bit(ST_CAPT_RUN, &fimc->state); - wake_up(&fimc->irq_queue); + if (cap->active_buf_cnt == 1) { + fimc_deactivate_capture(fimc); + clear_bit(ST_CAPT_STREAM, &fimc->state); + } } isr_unlock: |