/** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, unsigned long *plane_sizes) { struct vb2_queue *q = vb->vb2_queue; void *mem_priv; int plane; /* Allocate memory for all planes in this buffer */ for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], plane_sizes[plane]); if (IS_ERR_OR_NULL(mem_priv)) goto free; /* Associate allocator private data with this plane */ vb->planes[plane].mem_priv = mem_priv; vb->v4l2_planes[plane].length = plane_sizes[plane]; } return 0; free: /* Free already allocated memory if one of the allocations failed */ for (; plane > 0; --plane) call_memop(q, plane, put, vb->planes[plane - 1].mem_priv); return -ENOMEM; }
static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, unsigned long *plane_sizes) { struct vb2_queue *q = vb->vb2_queue; void *mem_priv; int plane; for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], plane_sizes[plane]); if (IS_ERR_OR_NULL(mem_priv)) goto free; vb->planes[plane].mem_priv = mem_priv; vb->v4l2_planes[plane].length = plane_sizes[plane]; } return 0; free: for (; plane > 0; --plane) call_memop(q, plane, put, vb->planes[plane - 1].mem_priv); return -ENOMEM; }
/** * vb2_plane_cookie() - Return allocator specific cookie for the given plane * @vb: vb2_buffer to which the plane in question belongs to * @plane_no: plane number for which the cookie is to be returned * * This function returns an allocator specific cookie for a given plane if * available, NULL otherwise. The allocator should provide some simple static * inline function, which would convert this cookie to the allocator specific * type that can be used directly by the driver to access the buffer. This can * be for example physical address, pointer to scatter list or IOMMU mapping. */ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) { struct vb2_queue *q = vb->vb2_queue; if (plane_no > vb->num_planes) return NULL; return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv); }
/** * __vb2_buf_mem_free() - free memory of the given buffer */ static void __vb2_buf_mem_free(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { call_memop(q, plane, put, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; dprintk(3, "Freed plane %d of buffer %d\n", plane, vb->v4l2_buf.index); } }
/** * __vb2_buf_userptr_put() - release userspace memory associated with * a USERPTR buffer */ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { void *mem_priv = vb->planes[plane].mem_priv; if (mem_priv) { call_memop(q, plane, put_userptr, mem_priv); vb->planes[plane].mem_priv = NULL; } } }
static bool __buffers_in_use(struct vb2_queue *q) { unsigned int buffer, plane; struct vb2_buffer *vb; for (buffer = 0; buffer < q->num_buffers; ++buffer) { vb = q->bufs[buffer]; for (plane = 0; plane < vb->num_planes; ++plane) { if (call_memop(q, plane, num_users, vb->planes[plane].mem_priv) > 1) return true; } } return false; }
/** * __buffers_in_use() - return true if any buffers on the queue are in use and * the queue cannot be freed (by the means of REQBUFS(0)) call */ static bool __buffers_in_use(struct vb2_queue *q) { unsigned int buffer, plane; struct vb2_buffer *vb; for (buffer = 0; buffer < q->num_buffers; ++buffer) { vb = q->bufs[buffer]; for (plane = 0; plane < vb->num_planes; ++plane) { /* * If num_users() has not been provided, call_memop * will return 0, apparently nobody cares about this * case anyway. If num_users() returns more than 1, * we are not the only user of the plane's memory. */ if (call_memop(q, plane, num_users, vb->planes[plane].mem_priv) > 1) return true; } } return false; }
/** * __qbuf_userptr() - handle qbuf of a USERPTR buffer */ static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) { struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct vb2_queue *q = vb->vb2_queue; void *mem_priv; unsigned int plane; int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); /* Verify and copy relevant information provided by the userspace */ ret = __fill_vb2_buffer(vb, b, planes); if (ret) return ret; for (plane = 0; plane < vb->num_planes; ++plane) { /* Skip the plane if already verified */ if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr && vb->v4l2_planes[plane].length == planes[plane].length) continue; dprintk(3, "qbuf: userspace address for plane %d changed, " "reacquiring memory\n", plane); /* Release previously acquired memory if present */ if (vb->planes[plane].mem_priv) call_memop(q, plane, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; /* Acquire each plane's memory */ if (q->mem_ops->get_userptr) { mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane], planes[plane].m.userptr, planes[plane].length, write); if (IS_ERR(mem_priv)) { dprintk(1, "qbuf: failed acquiring userspace " "memory for plane %d\n", plane); ret = PTR_ERR(mem_priv); goto err; } vb->planes[plane].mem_priv = mem_priv; } } /* * Call driver-specific initialization on the newly acquired buffer, * if provided. */ ret = call_qop(q, buf_init, vb); if (ret) { dprintk(1, "qbuf: buffer initialization failed\n"); goto err; } /* * Now that everything is in order, copy relevant information * provided by userspace. */ for (plane = 0; plane < vb->num_planes; ++plane) vb->v4l2_planes[plane] = planes[plane]; return 0; err: /* In case of errors, release planes that were already acquired */ for (; plane > 0; --plane) { call_memop(q, plane, put_userptr, vb->planes[plane - 1].mem_priv); vb->planes[plane - 1].mem_priv = NULL; } return ret; }
static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) { struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct vb2_queue *q = vb->vb2_queue; void *mem_priv; unsigned int plane; int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); ret = __fill_vb2_buffer(vb, b, planes); if (ret) return ret; for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr && vb->v4l2_planes[plane].length == planes[plane].length) continue; dprintk(3, "qbuf: userspace address for plane %d changed, " "reacquiring memory\n", plane); if (vb->planes[plane].mem_priv) call_memop(q, plane, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; if (q->mem_ops->get_userptr) { mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane], planes[plane].m.userptr, planes[plane].length, write); if (IS_ERR(mem_priv)) { dprintk(1, "qbuf: failed acquiring userspace " "memory for plane %d\n", plane); ret = PTR_ERR(mem_priv); goto err; } vb->planes[plane].mem_priv = mem_priv; } } ret = call_qop(q, buf_init, vb); if (ret) { dprintk(1, "qbuf: buffer initialization failed\n"); goto err; } for (plane = 0; plane < vb->num_planes; ++plane) vb->v4l2_planes[plane] = planes[plane]; return 0; err: for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->planes[plane].mem_priv) call_memop(q, plane, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; } return ret; }