intvb2_dqbuf(structvb2_queue*q,structv4l2_buffer*b, bool nonblocking){int ret;if(vb2_fileio_is_active(q)){dprintk(1,"file io in progress\n");return-EBUSY;}if(b->type != q->type){dprintk(1,"invalid buffer type\n");return-EINVAL;}
ret =vb2_core_dqbuf(q,NULL, b, nonblocking);/*
* After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
* cleared.
*/
b->flags &=~V4L2_BUF_FLAG_DONE;return ret;}EXPORT_SYMBOL_GPL(vb2_dqbuf);
3.2 vb2_core_dqbuf 函数
intvb2_core_dqbuf(structvb2_queue*q,unsignedint*pindex,void*pb,
bool nonblocking){structvb2_buffer*vb =NULL;int ret;// 非阻塞等待获取vb
ret =__vb2_get_done_vb(q,&vb, pb, nonblocking);if(ret <0)return ret;// 如果状态等DONE.继续switch(vb->state){case VB2_BUF_STATE_DONE:dprintk(3,"returning done buffer\n");break;case VB2_BUF_STATE_ERROR:dprintk(3,"returning done buffer with errors\n");break;default:dprintk(1,"invalid buffer state\n");return-EINVAL;}// 通知特定设备的buf_finish,具体里面干啥的未深入查看???call_void_vb_qop(vb, buf_finish, vb);if(pindex)*pindex = vb->index;// 填充buffer数据到用户空间,应用程序可以通过这个buffer的mmap地址进行读取数据了/* Fill buffer information for the userspace */if(pb)call_void_bufop(q, fill_user_buffer, vb, pb);// 注意“这里涉及到以下成员的含义和元素的转换/*
struct list_head queued_list;
unsigned int queued_count;
atomic_t owned_by_drv_count;
struct list_head done_list;
*/// 从done_list队列中移除/* Remove from videobuf queue */list_del(&vb->queued_entry);// 减少队列数量, 为啥不是owned_by_drv_count???
q->queued_count--;trace_vb2_dqbuf(q, vb);/* go back to dequeued state */__vb2_dqbuf(vb);dprintk(2,"dqbuf of buffer %d, with state %d\n",
vb->index, vb->state);return0;}EXPORT_SYMBOL_GPL(vb2_core_dqbuf);
3.3 __vb2_get_done_vb函数
/**
* __vb2_get_done_vb() - get a buffer ready for dequeuing
*
* Will sleep if required for nonblocking == false.
*/staticint__vb2_get_done_vb(structvb2_queue*q,structvb2_buffer**vb,void*pb,int nonblocking){unsignedlong flags;int ret =0;// 等待至少一帧在完成列表上可用/*
* Wait for at least one buffer to become available on the done_list.
*/
ret =__vb2_wait_for_done_vb(q, nonblocking);if(ret)return ret;// 从done_list队列中获取到该done_entry节点/*
* Driver's lock has been held since we last verified that done_list
* is not empty, so no need for another list_empty(done_list) check.
*/spin_lock_irqsave(&q->done_lock, flags);*vb =list_first_entry(&q->done_list,structvb2_buffer, done_entry);/*
* Only remove the buffer from done_list if all planes can be
* handled. Some cases such as V4L2 file I/O and DVB have pb
* == NULL; skip the check then as there's nothing to verify.
*/if(pb)
ret =call_bufop(q, verify_planes_array,*vb, pb);if(!ret)// 出错从done_list队列中移除list_del(&(*vb)->done_entry);spin_unlock_irqrestore(&q->done_lock, flags);return ret;}