static irqreturn_t fimc_isr(int irq, void *priv) { struct fimc_dev *fimc = priv; struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_ctx *ctx; fimc_hw_clear_irq(fimc); if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); if (ctx != NULL) { fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); spin_lock(&ctx->slock); if (ctx->state & FIMC_CTX_SHUT) { ctx->state &= ~FIMC_CTX_SHUT; wake_up(&fimc->irq_queue); } spin_unlock(&ctx->slock); } return IRQ_HANDLED; } spin_lock(&fimc->slock); if (test_bit(ST_CAPT_PEND, &fimc->state)) { fimc_capture_irq_handler(fimc); if (cap->active_buf_cnt == 1) { fimc_deactivate_capture(fimc); clear_bit(ST_CAPT_STREAM, &fimc->state); } } spin_unlock(&fimc->slock); return IRQ_HANDLED; }
void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; struct timeval *tv; struct timespec ts; if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { wake_up(&fimc->irq_queue); goto done; } if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) { ktime_get_real_ts(&ts); v_buf = fimc_active_queue_pop(cap); tv = &v_buf->vb.v4l2_buf.timestamp; tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; v_buf->vb.v4l2_buf.sequence = cap->frame_count++; vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } if (!list_empty(&cap->pending_buf_q)) { v_buf = fimc_pending_queue_pop(cap); fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); v_buf->index = cap->buf_index; /* Move the buffer to the capture active queue */ fimc_active_queue_add(cap, v_buf); dbg("next frame: %d, done frame: %d", fimc_hw_get_frame_index(fimc), v_buf->index); if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } if (cap->active_buf_cnt == 0) { if (deq_buf) clear_bit(ST_CAPT_RUN, &fimc->state); if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } else { set_bit(ST_CAPT_RUN, &fimc->state); } if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) fimc_capture_config_update(cap->ctx); done: if (cap->active_buf_cnt == 1) { fimc_deactivate_capture(fimc); clear_bit(ST_CAPT_STREAM, &fimc->state); } dbg("frame: %d, active_buf_cnt: %d", fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); }