本文共 31491 字,大约阅读时间需要 104 分钟。
以vivi驱动为例,
vb2_buffer为vivi设备内部使用的帧缓存描述, (用户态用v4l2_buffer来描述)
在vb2_queue队列中, 有两个队列, 分别为queued_list和done_list,
前者用于存放用户enqueue的buffer, 后者用于存放处理好等待dequeue的buffer。
Q: 贴段代码...
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 }
list_add_tail的是&buf->list指针, 它是谁?
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 };
它是vivi_buffer的list_head变量。 有一行注释, /* common v4l buffer stuff -- must be first */
这里很奇怪, 搜索vivi_buffer没有找到直接分配的地方....
为什么这里能用struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); 获取到vivi_buffer结构体变量的开头指针??
vb2_buffer不是在reqbufs过程中分配的吗? 为什么能用核心层分配的变量取到vivi驱动中的vivi_buffer结构体指针。。。
A: 没错, vb2_buffer就是reqbufs分配的, 进去看看就明白了....
Q: vb2_buffer什么时候被分配?
A: 在reqbufs时分配, 即用户调用VIDIOC_REQBUFS时, 驱动根据用户需求, 分配对应buffer数。
调用序列: VIDIOC_REQBUFS->vb2_ioctl_reqbufs->__reqbufs->__vb2_queue_alloc
贴下__reqbufs函数注释, 干的活挺多的...
843 /** 844 * __reqbufs() - Initiate streaming 845 * @q:› › videobuf2 queue 846 * @req:› struct passed from userspace to vidioc_reqbufs handler in driver 847 * 848 * Should be called from vidioc_reqbufs ioctl handler of a driver. 849 * This function: 850 * 1) verifies streaming parameters passed from the userspace, 851 * 2) sets up the queue, 852 * 3) negotiates number of buffers and planes per buffer with the driver 853 * to be used during streaming, 854 * 4) allocates internal buffer structures (struct vb2_buffer), according to 855 * the agreed parameters, 856 * 5) for MMAP memory type, allocates actual video memory, using the 857 * memory handling/allocation routines provided during queue initialization 858 * 859 * If req->count is 0, all the memory will be freed instead. 860 * If the queue has been allocated previously (by a previous vb2_reqbufs) call 861 * and the queue is not busy, memory will be reallocated. 862 * 863 * The return values from this function are intended to be directly returned 864 * from vidioc_reqbufs handler in driver. 865 */ 866 static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
其中有两步, sets up the queue 和 allocates internal buffer structures。
913 › /* 914 › * Ask the driver how many buffers and planes per buffer it requires. 915 › * Driver also sets the size and allocator context for each plane. 916 › */ 917 › ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, 918 › › q->plane_sizes, q->alloc_ctx); 919 › if (ret) 920 › › return ret; 921 922 › /* Finally, allocate buffers and video memory */ 923 › allocated_buffers = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); 924 › if (allocated_buffers == 0) { 925 › › dprintk(1, "memory allocation failed\n"); 926 › › return -ENOMEM; 927 › }
即会调用驱动queue_setup函数进行buffer设置, 如该驱动提供的buffer数量, plane层数, 以及buffer大小等。
之后调用__vb2_queue_alloc进行真实的buffer分配。
函数不算长, 直接全贴下。
337 /** 338 * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type) 339 * video buffer memory for all buffers/planes on the queue and initializes the 340 * queue 341 * 342 * Returns the number of buffers successfully allocated. 343 */ 344 static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, 345 › › › unsigned int num_buffers, unsigned int num_planes) 346 { 347 › unsigned int buffer; 348 › struct vb2_buffer *vb; 349 › int ret; 350 351 › for (buffer = 0; buffer < num_buffers; ++buffer) { 352 › › /* Allocate videobuf buffer structures */ 353 › › vb = kzalloc(q->buf_struct_size, GFP_KERNEL); 354 › › if (!vb) { 355 › › › dprintk(1, "memory alloc for buffer struct failed\n"); 356 › › › break; 357 › › } 358 359 › › /* Length stores number of planes for multiplanar buffers */ 360 › › if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) 361 › › › vb->v4l2_buf.length = num_planes; 362 363 › › vb->state = VB2_BUF_STATE_DEQUEUED; 364 › › vb->vb2_queue = q; 365 › › vb->num_planes = num_planes; 366 › › vb->v4l2_buf.index = q->num_buffers + buffer; 367 › › vb->v4l2_buf.type = q->type; 368 › › vb->v4l2_buf.memory = memory; 369 370 › › /* Allocate video buffer memory for the MMAP type */ 371 › › if (memory == V4L2_MEMORY_MMAP) { 372 › › › ret = __vb2_buf_mem_alloc(vb); 373 › › › if (ret) { 374 › › › › dprintk(1, "failed allocating memory for " 375 › › › › › › "buffer %d\n", buffer); 376 › › › › kfree(vb); 377 › › › › break; 378 › › › } 379 › › › /* 380 › › › * Call the driver-provided buffer initialization 381 › › › * callback, if given. An error in initialization 382 › › › * results in queue setup failure. 383 › › › */ 384 › › › ret = call_vb_qop(vb, buf_init, vb); 385 › › › if (ret) { 386 › › › › dprintk(1, "buffer %d %p initialization" 387 › › › › › " failed\n", buffer, vb); 388 › › › › __vb2_buf_mem_free(vb); 389 › › › › kfree(vb); 390 › › › › break; 391 › › › } 392 › › } 393 394 › › q->bufs[q->num_buffers + buffer] = vb; 395 › } 396 397 › __setup_lengths(q, buffer); 398 › if (memory == V4L2_MEMORY_MMAP) 399 › › __setup_offsets(q, buffer); 400 401 › dprintk(1, "allocated %d buffers, %d plane(s) each\n", 402 › › › buffer, num_planes); 403 404 › return buffer; 405 }
这里有个关键点,
struct vb2_buffer *vb;
vb = kzalloc(p->buf_struct_size, GFP_KERNEL);
为什么分配的内存大小是buf_struct_size而不是sizeof(vb2_buffer)??
是的, 这就是问题1的答案, 这里预先分配的其实就是vivi_buffer的内存。
而不是vb2_buffer的内存。
vivi.c里找找, 很容易就找到buf_struct_size了...
1437 › /* initialize queue */ 1438 › q = &dev->vb_vidq; 1439 › q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1440 › q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; 1441 › q->drv_priv = dev; 1442 › q->buf_struct_size = sizeof(struct vivi_buffer); 1443 › q->ops = &vivi_video_qops; 1444 › q->mem_ops = &vb2_vmalloc_memops; 1445 › q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 1446 1447 › ret = vb2_queue_init(q);
q->buf_struct_size = sizeof(struct vivi_buffer);
初始化queue的时候就跟vivi 核心层说了, 我要的buffer不是vb2_buffer, 而是vivi_buffer!!
没那么简单...
转载地址:http://npcrj.baihongyu.com/