/** * vb2_reqbufs() - Initiate streaming * @q: videobuf2 queue * @req: struct passed from userspace to vidioc_reqbufs handler in driver * * Should be called from vidioc_reqbufs ioctl handler of a driver. * This function: * 1) verifies streaming parameters passed from the userspace, * 2) sets up the queue, * 3) negotiates number of buffers and planes per buffer with the driver * to be used during streaming, * 4) allocates internal buffer structures (struct vb2_buffer), according to * the agreed parameters, * 5) for MMAP memory type, allocates actual video memory, using the * memory handling/allocation routines provided during queue initialization * * If req->count is 0, all the memory will be freed instead. * If the queue has been allocated previously (by a previous vb2_reqbufs) call * and the queue is not busy, memory will be reallocated. * * The return values from this function are intended to be directly returned * from vidioc_reqbufs handler in driver. */ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) { unsigned int num_buffers = 0; unsigned int num_planes = 0; unsigned long plane_sizes[VIDEO_MAX_PLANES]; int ret = 0; if (q->fileio) { dprintk(1, "reqbufs: file io in progress\n"); return -EBUSY; } if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR) { dprintk(1, "reqbufs: unsupported memory type\n"); return -EINVAL; } if (req->type != q->type) { dprintk(1, "reqbufs: requested type is incorrect\n"); return -EINVAL; } if (q->streaming) { dprintk(1, "reqbufs: streaming active\n"); return -EBUSY; } /* * Make sure all the required memory ops for given memory type * are available. */ if (req->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { dprintk(1, "reqbufs: MMAP for current setup unsupported\n"); return -EINVAL; } if (req->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { dprintk(1, "reqbufs: USERPTR for current setup unsupported\n"); return -EINVAL; } if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { /* * We already have buffers allocated, so first check if they * are not in use and can be freed. */ if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { dprintk(1, "reqbufs: memory in use, cannot free\n"); return -EBUSY; } __vb2_queue_free(q); /* * In case of REQBUFS(0) return immediately without calling * driver's queue_setup() callback and allocating resources. */ if (req->count == 0) return 0; } /* * Make sure the requested values and current defaults are sane. */ num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); memset(plane_sizes, 0, sizeof(plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = req->memory; /* * Ask the driver how many buffers and planes per buffer it requires. * Driver also sets the size and allocator context for each plane. */ ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, plane_sizes, q->alloc_ctx); if (ret) return ret; /* Finally, allocate buffers and video memory */ ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, plane_sizes); if (ret == 0) { dprintk(1, "Memory allocation failed\n"); return -ENOMEM; } /* * Check if driver can handle the allocated number of buffers. */ if (ret < num_buffers) { unsigned int orig_num_buffers; orig_num_buffers = num_buffers = ret; ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, plane_sizes, q->alloc_ctx); if (ret) goto free_mem; if (orig_num_buffers < num_buffers) { ret = -ENOMEM; goto free_mem; } /* * Ok, driver accepted smaller number of buffers. */ ret = num_buffers; } /* * Return the number of successfully allocated buffers * to the userspace. */ req->count = ret; return 0; free_mem: __vb2_queue_free(q); return ret; }
int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) { unsigned int num_buffers, num_planes; unsigned long plane_sizes[VIDEO_MAX_PLANES]; int ret = 0; num_buffers = 0; num_planes = 0; if (q->fileio) { dprintk(1, "reqbufs: file io in progress\n"); return -EBUSY; } if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR) { dprintk(1, "reqbufs: unsupported memory type\n"); return -EINVAL; } if (req->type != q->type) { dprintk(1, "reqbufs: requested type is incorrect\n"); return -EINVAL; } if (q->streaming) { dprintk(1, "reqbufs: streaming active\n"); return -EBUSY; } if (req->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { dprintk(1, "reqbufs: MMAP for current setup unsupported\n"); return -EINVAL; } if (req->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { dprintk(1, "reqbufs: USERPTR for current setup unsupported\n"); return -EINVAL; } if (q->memory == req->memory && req->count == q->num_buffers) return 0; if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { dprintk(1, "reqbufs: memory in use, cannot free\n"); return -EBUSY; } __vb2_queue_free(q); if (req->count == 0) return 0; } num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); memset(plane_sizes, 0, sizeof(plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = req->memory; ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); if (ret) return ret; ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, plane_sizes); if (ret == 0) { dprintk(1, "Memory allocation failed\n"); return -ENOMEM; } if (ret < num_buffers) { unsigned int orig_num_buffers; orig_num_buffers = num_buffers = ret; ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, q->plane_sizes, q->alloc_ctx); if (ret) goto free_mem; if (orig_num_buffers < num_buffers) { ret = -ENOMEM; goto free_mem; } ret = num_buffers; } req->count = ret; return 0; free_mem: __vb2_queue_free(q); return ret; }