v4l2 vivi驅動分析

v4l2驅動框架相對還是挺複雜的,

 

最好的參考例子有

v4l2-pci-skeleton.c

vivi (Virtual Video)


其中vivi在最新的Linux 4.xx版本也變得非常複雜。

所以採用Linux-3.16.74版本作爲學習...


1. 該版本沒有使用platform_driver框架, 故模塊初始化入口函數vivi_init直接進行video設備的註冊。

(如果使用platform driver的框架, 會在probe函數中進行註冊)

 

2. vivi_init初始化過程, 最主要的動作就是創建vivi實例。

主要函數爲vivi_create_instance

通常的, 裏面會分配好vivi設備描述結構體, vivi_dev

創建v4l2_dev設備, 調用v4l2_device_register註冊一個v4l2設備,  這個相比video_device來說, 相當於一個父節點, 描述的信息更加common, 註冊函數中會對該設備進行一些通用的初始化和資源分配。

 

下一步是構建video_device並註冊該設備。

關於ctrl_handler, 如亮度, 對比度, 透明度等等暫時先不具體研究。

 

4. 創建vb2_queue, video設備內部使用的隊列。

該結構體也很複雜, 直接貼圖...

struct vb2_queue {                                                                                                                                 
›   enum v4l2_buf_type› ›   type;                                                                                                                  
›   unsigned int›   ›   ›   io_modes;                                                                                                              
›   unsigned int›   ›   ›   io_flags;                                                                                                              
›   struct mutex›   ›   ›   *lock;                                                                                                                 
›   struct v4l2_fh› ›   ›   *owner;                                                                                                                
                                                                                                                                                   
›   const struct vb2_ops›   ›   *ops;                                                                                                              
›   const struct vb2_mem_ops›   *mem_ops;                                                                                                          
›   void›   ›   ›   ›   *drv_priv;                                                                                                                 
›   unsigned int›   ›   ›   buf_struct_size;                                                                                                       
›   u32››   ›   ›   timestamp_flags;                                                                                                               
›   gfp_t›  ›   ›   ›   gfp_flags;                                                                                                                 
›   u32››   ›   ›   min_buffers_needed;                                                                                                            
                                                                                                                                                   
/* private: internal use only */                                                                                                                   
›   enum v4l2_memory›   ›   memory;                                                                                                                
›   struct vb2_buffer›  ›   *bufs[VIDEO_MAX_FRAME];                                                                                                
›   unsigned int›   ›   ›   num_buffers;                                                                                                           
                                                                                                                                                   
›   struct list_head›   ›   queued_list;                                                                                                           
›   unsigned int›   ›   ›   queued_count;                                                                                                          
                                                                                                                                                   
›   atomic_t›   ›   ›   owned_by_drv_count;                                                                                                        
›   struct list_head›   ›   done_list;                                                                                                             
›   spinlock_t› ›   ›   done_lock;                                                                                                                 
›   wait_queue_head_t›  ›   done_wq;                                                                                                               
                                                                                                                                                   
›   void›   ›   ›   ›   *alloc_ctx[VIDEO_MAX_PLANES];                                                                                              
›   unsigned int›   ›   ›   plane_sizes[VIDEO_MAX_PLANES];                                                                                         
                                                                                                                                                   
›   unsigned int›   ›   ›   streaming:1;                                                                                                           
›   unsigned int›   ›   ›   start_streaming_called:1;                                                                                              
›   unsigned int›   ›   ›   waiting_for_buffers:1;                                                                                                 
                                                                                                                                                  m
›   struct vb2_fileio_data› ›   *fileio;                                                                                                           
›   struct vb2_threadio_data›   *threadio;         

可以看到vb2_queue內部有兩個隊列, queued_list和done_list

即用戶req bufs並mmap到用戶態後, 調用queue buffer時,  會將這些空buffer放入queued_list,

vivi設備內部線程, 或工作隊列,  或定時器等 隔段時間將要顯示的yuv數據填充到申請的緩存中。

並放入done_list,  即完成隊列中。

如此,  用戶態就能通過dequeue buffer取出done_list中的數據, 進行渲染, 存儲或傳輸等操作了。

 

5. 繼續填充video_device數據結構, 比如file_operations, ioctls等等

1457 ›   vfd = &dev->vdev;                                                                                                                        
1458 ›   *vfd = vivi_template;                                                                                                                    
1459 ›   vfd->debug = debug;                                                                                                                      
1460 ›   vfd->v4l2_dev = &dev->v4l2_dev;                                                                                                          
1461 ›   vfd->queue = q;                                                                                                                                                                                        

 

6. 設備都填充好後, 調用video_register_device即可


 

ok, 是不是很簡單...

是的,  當你對linux設備框架理解後, 它就會變得越來越簡單...

所以我還需不斷實踐加總結, 加深理解...


後面我們跟下代碼, 最關鍵的VIDIOC_QBUF和VIDIOC_DQBUF,

看下內部的buffer是如何流動的。

 

1. VIDIOC_QBUF - >

查看vivi_ioctl_ops

1320 static const struct v4l2_ioctl_ops vivi_ioctl_ops = {                                                                                        
1321 ›   .vidioc_querycap      = vidioc_querycap,                                                                                                 
1322 ›   .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,                                                                                     
1323 ›   .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,                                                                                        
1324 ›   .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,                                                                                      
1325 ›   .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,                                                                                        
1326 ›   .vidioc_enum_framesizes   = vidioc_enum_framesizes,                                                                                      
1327 ›   .vidioc_reqbufs       = vb2_ioctl_reqbufs,                                                                                                
1328 ›   .vidioc_create_bufs   = vb2_ioctl_create_bufs,                                                                                            
1329 ›   .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,                                                                                            
1330 ›   .vidioc_querybuf      = vb2_ioctl_querybuf,                                                                                               
1331 ›   .vidioc_qbuf          = vb2_ioctl_qbuf,                                                                                                   
1332 ›   .vidioc_dqbuf         = vb2_ioctl_dqbuf,                                                                                                  
1333 ›   .vidioc_enum_input    = vidioc_enum_input,                                                                                                
1334 ›   .vidioc_g_input       = vidioc_g_input,                                                                                                   
1335 ›   .vidioc_s_input       = vidioc_s_input,                                                                                                   
1336 ›   .vidioc_enum_frameintervals = vidioc_enum_frameintervals,                                                                                 
1337 ›   .vidioc_g_parm        = vidioc_g_parm,                                                                                                    
1338 ›   .vidioc_s_parm        = vidioc_s_parm,                                                                                                    
1339 ›   .vidioc_streamon      = vb2_ioctl_streamon,                                                                                               
1340 ›   .vidioc_streamoff     = vb2_ioctl_streamoff,                                                                                              
1341 ›   .vidioc_log_status    = v4l2_ctrl_log_status,                                                                                             
1342 ›   .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,                                                                                     m
1343 ›   .vidioc_unsubscribe_event = v4l2_event_unsubscribe,                                                                                       
1344 };                                                                                                                                           
1345                                                                                                                                              
1346 static const struct video_device vivi_template = {                                                                                           
1347 ›   .name›  ›   = "vivi",                                                                                                                    
1348 ›   .fops           = &vivi_fops,                                                                                                            
1349 ›   .ioctl_ops ›= &vivi_ioctl_ops,                                                                                                           
1350 ›   .release›   = video_device_release_empty,                                                                                                
1351 };     

對應實現爲vb2_ioctl_qbuf, 

是的v4l2-core核心層幫忙實現的邏輯越來越多...這個queue buffer的操作也有通用的一些流程了...

 

2. vb2_ioctl_qbuf

-> vb2_qbuf->vb2_internal_qbuf->

1785 static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)                                                                     
1786 {                                                                                                                                            
1787 ›   int ret = vb2_queue_or_prepare_buf(q, b, "qbuf");                                                                                        
1788 ›   struct vb2_buffer *vb;                                                                                                                   
1789                                                                                                                                              
1790 ›   if (ret)                                                                                                                                 
1791 ›   ›   return ret;                                                                                                                          
1792                                                                                                                                              
1793 ›   vb = q->bufs[b->index];                                                                                                                  
1794                                                                                                                                              
1795 ›   switch (vb->state) {                                                                                                                     
1796 ›   case VB2_BUF_STATE_DEQUEUED:                                                                                                             
1797 ›   ›   ret = __buf_prepare(vb, b);                                                                                                          
1798 ›   ›   if (ret)                                                                                                                             
1799 ›   ›   ›   return ret;                                                                                                                      
1800 ›   ›   break;                                                                                                                               
1801 ›   case VB2_BUF_STATE_PREPARED:                                                                                                             
1802 ›   ›   break;                                                                                                                               
1803 ›   case VB2_BUF_STATE_PREPARING:                                                                                                            
1804 ›   ›   dprintk(1, "buffer still being prepared\n");                                                                                         
1805 ›   ›   return -EINVAL;                                                                                                                      
1806 ›   default:                                                                                                                                 
1807 ›   ›   dprintk(1, "invalid buffer state %d\n", vb->state);                                                                                  
1808 ›   ›   return -EINVAL;                                                                                                                      
1809 ›   }                                                                                                                                        
1810                                                                                                                                              
1811 ›   /*                                                                                                                                       
1812 ›    * Add to the queued buffers list, a buffer will stay on it until                                                                        
1813 ›    * dequeued in dqbuf.                                                                                                                    
1814 ›    */                                                                                                                                      
1815 ›   list_add_tail(&vb->queued_entry, &q->queued_list);                                                                                       
1816 ›   q->queued_count++;                                                                                                                       
1817 ›   q->waiting_for_buffers = false;                                                                                                          
1818 ›   vb->state = VB2_BUF_STATE_QUEUED;

首先vb2_queue_or_prepare_buf(q, b, "buf"), 進去看了下, 貌似沒幹啥事, 很多是檢查數據合法性。先不管了。

下面vb = q->bufs[b->index];

即從vb2_buffer中取得當前要入列的幀。 是的, vb2_queue內部使用vb2_buffer來對buffer進行描述。

vb2_buffer中有兩個list_head, 分別是queued_entry和done_entry, 

list_head結構很簡單, 就兩個指針, 分別指向前一個和下一個。(對linux kernel裏的list就是一個雙向鏈表)

struct list_head {                                                                                                                                                                                           
›   struct list_head *next, *prev;                                                                                                                                                                           
};

在reqbufs階段,  會根據用戶需求, 分配好需求的幀緩存, 其中vb2_buffer就是描述幀緩存的信息。

vb2_buffer分配好後,  queued_entry和done_entry同時被分配出來。入隊出隊的就是list_head這個指針。

看到註釋那裏, 就是將vb->queued_entry放入到vb2的queued_list中。 入列就完成了...

ok, queued_list中的buffer 最終是要被vivi設備拿來處理的...嗯 需要填充後丟給done_list..

那queued_list中的buffer如何取出並處理呢?

 

3. 關於queued_list中的數據如何取出並處理?

直接搜索queued_list 貌似沒搜着... (可能又用了一些啥技巧...比如CALL(a, b, op) 啥的)....

但根據常識, 將queued_list中的buffer取出並進行處理的過程(這裏是填充數據), 不應該由v4l2-core核心來實現,

而應該由具體的驅動來實現。 這裏是vivi.c

所以去vivi.c中進行查看...

 677 static void vivi_thread_tick(struct vivi_dev *dev)                                                                                                                                                                      678 {                                                                                                                                                                                                                       679 ›   struct vivi_dmaqueue *dma_q = &dev->vidq;                                                                                                                                                                           680 ›   struct vivi_buffer *buf;                                                                                                                                                                                            681 ›   unsigned long flags = 0;                                                                                                                                                                                            682                                                                                                                                                                                                                         683 ›   dprintk(dev, 1, "Thread tick\n");                                                                                                                                                                                   684                                                                                                                                                                                                                         685 ›   spin_lock_irqsave(&dev->slock, flags);                                                                                                                                                                              686 ›   if (list_empty(&dma_q->active)) {                                                                                                                                                                                   687 ›   ›   dprintk(dev, 1, "No active queue to serve\n");                                                                                                                                                                  688 ›   ›   spin_unlock_irqrestore(&dev->slock, flags);                                                                                                                                                                     689 ›   ›   return;                                                                                                                                                                                                         690 ›   }                                                                                                                                                                                                                   691                                                                                                                                                                                                                        
 692 ›   buf = list_entry(dma_q->active.next, struct vivi_buffer, list);                                                                                                                                                    
 693 ›   list_del(&buf->list);                                                                                                                                                                                              
 694 ›   spin_unlock_irqrestore(&dev->slock, flags);                                                                                                                                                                        
 695                                                                                                                                                                                                                        
 696 ›   v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);                                                                                                                                                                   
 697                                                                                                                                                                                                                        
 698 ›   /* Fill buffer */                                                                                                                                                                                                  
 699 ›   vivi_fillbuff(dev, buf);                                                                                                                                                                                           
 700 ›   dprintk(dev, 1, "filled buffer %p\n", buf);                                                                                                                                                                        
 701                                                                                                                                                                                                                        
 702 ›   vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);                                                                                                                                                                     
 703 ›   dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);                                                                                                                                                    
 704 }                                                                     

很容易找到, vivi.c中拉起了一個內核線程。

主要工作是定時從dma_q->active隊列中取出buffer進行填充。

查看vivi_dmaqueue數據結構,

 192 struct vivi_dmaqueue {                                                                                                                                                                                                 
 193 ›   struct list_head       active;                                                                                                                                                                                     
 194                                                                                                                                                                                                                        
 195 ›   /* thread for generating video stream*/                                                                                                                                                                            
 196 ›   struct task_struct         *kthread;                                                                                                                                                                               
 197 ›   wait_queue_head_t          wq;                                                                                                                                                                                     
 198 ›   /* Counters to control fps rate */                                                                                                                                                                                 
 199 ›   int                        frame;                                                                                                                                                                                  
 200 ›   int                        ini_jiffies;                                                                                                                                                                            
 201 };    

內部有個active隊列。 

即從活躍的隊列中取出數據進行填充。 ok, 繼續...

 875 static void buffer_queue(struct vb2_buffer *vb)                                                                                                                                                                        
 876 {                                                                                                                                                                                                                      
 877 ›   struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);                                                                                                                                                            
 878 ›   struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);                                                                                                                                                
 879 ›   struct vivi_dmaqueue *vidq = &dev->vidq;                                                                                                                                                                           
 880 ›   unsigned long flags = 0;                                                                                                                                                                                           
 881                                                                                                                                                                                                                        
 882 ›   dprintk(dev, 1, "%s\n", __func__);                                                                                                                                                                                 
 883                                                                                                                                                                                                                        
 884 ›   spin_lock_irqsave(&dev->slock, flags);                                                                                                                                                                             
 885 ›   list_add_tail(&buf->list, &vidq->active);                                                                                                                                                                          
 886 ›   spin_unlock_irqrestore(&dev->slock, flags);                                                                                                                                                                        
 887 }

在buffer_queue函數中找到了, 將vivi_buffer的list_head放入活躍隊列的尾部。

看下vivi_buffer的結構體

 185 /* buffer for one video frame */                                                                                                                                                                                       
 186 struct vivi_buffer {                                                                                                                                                                                                   
 187 ›   /* common v4l buffer stuff -- must be first */                                                                                                                                                                     
 188 ›   struct vb2_buffer›  vb;                                                                                                                                                                                            
 189 ›   struct list_head›   list;                                                                                                                                                                                          
 190 }; 

關於buffer_queue的調用,

 929 static const struct vb2_ops vivi_video_qops = {                                                                                                                                                                        
 930 ›   .queue_setup›   ›   = queue_setup,                                                                                                                                                                                 
 931 ›   .buf_prepare›   ›   = buffer_prepare,                                                                                                                                                                              
 932 ›   .buf_queue› ›   = buffer_queue,                                                                                                                                                                                    
 933 ›   .start_streaming›   = start_streaming,                                                                                                                                                                             
 934 ›   .stop_streaming››   = stop_streaming,                                                                                                                                                                              
 935 ›   .wait_prepare›  ›   = vivi_unlock,                                                                                                                                                                                 
 936 ›   .wait_finish›   ›   = vivi_lock,                                                                                                                                                                                   
 937 }; 

它是vb2_queue隊列的一個操作回調函數。

它何時會被調用?

搜索下只能在videobuf-core.c中找到...

但我們是vb2... 所以到

videobuf2-core.c中尋找, 果然使用了技巧...

/**
 * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
 */
static void __enqueue_in_driver(struct vb2_buffer *vb)
{
	struct vb2_queue *q = vb->vb2_queue;
	unsigned int plane;

	vb->state = VB2_BUF_STATE_ACTIVE;
	atomic_inc(&q->owned_by_drv_count);

	/* sync buffers */
	for (plane = 0; plane < vb->num_planes; ++plane)
		call_void_memop(vb, prepare, vb->planes[plane].mem_priv);

	call_void_vb_qop(vb, buf_queue, vb);
}

看註釋... __enqueue_in_driver這個函數將最終會利用call_void_vb_qop 調用buf_queue函數, 進行驅動層面的數據處理。

如果是編解碼器, 需要丟給編解碼器進行數據處理。

如果是攝像頭, 需要把攝像頭採集的數據填充給這一個buffer。

我們這裏是vivi驅動, buf_queue函數會將vb2_buffer放入活躍隊列中。

內核線程會從活躍隊列中取數據並填充。最終放入done_list中。


ok, 我們看看__enqueue_in_driver被誰調用了?

很好找,  就在之前描述的v4l2_internel_qbuf中... 之前沒貼全... 我們繼續貼代碼。

1811 ›   /*                                                                                                                                       
1812 ›    * Add to the queued buffers list, a buffer will stay on it until                                                                        
1813 ›    * dequeued in dqbuf.                                                                                                                    
1814 ›    */                                                                                                                                      
1815 ›   list_add_tail(&vb->queued_entry, &q->queued_list);                                                                                       
1816 ›   q->queued_count++;                                                                                                                       
1817 ›   q->waiting_for_buffers = false;                                                                                                          
1818 ›   vb->state = VB2_BUF_STATE_QUEUED;                                                                                                        
1819 ›   if (V4L2_TYPE_IS_OUTPUT(q->type)) {                                                                                                      
1820 ›   ›   /*                                                                                                                                   
1821 ›   ›    * For output buffers copy the timestamp if needed,                                                                                  
1822 ›   ›    * and the timecode field and flag if needed.                                                                                        
1823 ›   ›    */                                                                                                                                  
1824 ›   ›   if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==                                                                           
1825 ›   ›       V4L2_BUF_FLAG_TIMESTAMP_COPY)                                                                                                    
1826 ›   ›   ›   vb->v4l2_buf.timestamp = b->timestamp;                                                                                           
1827 ›   ›   vb->v4l2_buf.flags |= b->flags & V4L2_BUF_FLAG_TIMECODE;                                                                             
1828 ›   ›   if (b->flags & V4L2_BUF_FLAG_TIMECODE)                                                                                               
1829 ›   ›   ›   vb->v4l2_buf.timecode = b->timecode;                                                                                             
1830 ›   }                                                                                                                                        
1831                                                                                                                                              
1832 ›   /*                                                                                                                                       
1833 ›    * If already streaming, give the buffer to driver for processing.                                                                       
1834 ›    * If not, the buffer will be given to driver on next streamon.                                                                          
1835 ›    */                                                                                                                                      
1836 ›   if (q->start_streaming_called)                                                                                                           
1837 ›   ›   __enqueue_in_driver(vb); 

所以這個數據放入queued_list的同時, 又調用驅動的buf_queue, 放入了vivi驅動中的active隊列。

但這個buffer並沒有從queued_list中刪除, 那具體數據會在什麼時候被刪除呢?

根據註釋的意思, a buffer will stay on it util dequeued in dqbuf。

是的這個buffer會在dqbuf時纔會被刪除...

其實也好理解, 對於用戶態來說, 它並不認爲是對兩個隊列進行操作, dequeue和enqueue的感覺上是同一個隊列。。。

從隊列頭部取一個, 處理完, 放入隊列尾部, 感覺上就是這樣的。

 

所以vivi設備內部的buf雖然已經從queued_list取出並放入活躍隊列, 並最終進行數據填充放入done_list。

但該數據不會從queued_list中刪除, 只有當dequeue buffer成功後, 纔會在queued_list中刪除!!! 

 

後面繼續看dequeue buffer的邏輯.


 

4. VIDIOC_DQBUF

很快找到, vivi驅動中會調用vb2_ioctl_dqbuf

 

5. vb2_ioctl_dqbuf

-> vb2_dqbuf -> vb2_internal_dqbuf -> 

static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
{
	struct vb2_buffer *vb = NULL;
	int ret;

	if (b->type != q->type) {
		dprintk(1, "invalid buffer type\n");
		return -EINVAL;
	}
	ret = __vb2_get_done_vb(q, &vb, b, nonblocking);
	if (ret < 0)
		return ret;

	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;
	}

	call_void_vb_qop(vb, buf_finish, vb);

	/* Fill buffer information for the userspace */
	__fill_v4l2_buffer(vb, b);
	/* Remove from videobuf queue */
	list_del(&vb->queued_entry);
	q->queued_count--;
	/* go back to dequeued state */
	__vb2_dqbuf(vb);

	dprintk(1, "dqbuf of buffer %d, with state %d\n",
			vb->v4l2_buf.index, vb->state);

	/*
	 * After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
	 * cleared.
	 */
	b->flags &= ~V4L2_BUF_FLAG_DONE;
	return 0;
}

代碼不長,  直接全貼了。邏輯很簡單, 從done_list取出一個buffer,  並從done_list中刪除,  填充到v4l2_buffer中給用戶態,

同時刪除queued_entry!!!

 

關鍵函數是 __vb2_get_done_vb

/**
 * __vb2_get_done_vb() - get a buffer ready for dequeuing
 *
 * Will sleep if required for nonblocking == false.
 */
static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
				struct v4l2_buffer *b, int nonblocking)
{
	unsigned long flags;
	int ret;

	/*
	 * 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;

	/*
	 * 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, struct vb2_buffer, done_entry);
	/*
	 * Only remove the buffer from done_list if v4l2_buffer can handle all
	 * the planes.
	 */
	ret = __verify_planes_array(*vb, b);
	if (!ret)
		list_del(&(*vb)->done_entry);
	spin_unlock_irqrestore(&q->done_lock, flags);

	return ret;
}

可以看到,  從done_list中取出一個數據, 並在done_list中刪除該數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章