(1)
static irqreturn_t jz_camera_irq_handler(int irq, void *data) {
if(status & CIM_STATE_DMA_EOF) { //硬件发送这个EOF给控制器响应中断
/* clear dma interrupt status */
temp = readl(pcdev->base + CIM_STATE);
temp &= (~CIM_STATE_DMA_EOF);
writel(temp, pcdev->base + CIM_STATE);
if(pcdev->active) { //active判断,有数据
struct vb2_buffer *vb2 = &pcdev->active->vb2;
struct jz_buffer *buf = container_of(vb2, struct jz_buffer, vb2);
list_del_init(&buf->list);
v4l2_get_timestamp(&vb2->v4l2_buf.timestamp);
vb2->v4l2_buf.sequence = pcdev->sequence++;
vb2_buffer_done(vb2, VB2_BUF_STATE_DONE); //一帧数据采集完成,这个接口把采集完成的buffer从链表video_buffer_list加进done_list
/* start next dma frame. */
pcdev->active = list_entry(pcdev->video_buffer_list.next, struct jz_buffer, list);
}
void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
{
list_add_tail(&vb->done_entry, &q->done_list);
wake_up(&q->done_wq); //唤醒进程
}
(2)
应用层调用select后,调用我们控制器驱动的接口jz_camera_poll
static unsigned int jz_camera_poll(struct file *file, poll_table *pt)
{
struct soc_camera_device *icd = file->private_data;
return vb2_poll(&icd->vb2_vidq, file, pt);
}
unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
{
if (list_empty(&q->done_list))
poll_wait(file, &q->done_wq, wait); //done_list是空的话,poll_wait等待,等待中断唤醒
}
总结:
把有数据的buffer[0]加进done_list链表后,应用层调用dqbuf就能从视频缓存队列中取出数据