以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!!
没那么简单...