/* * videobuf2-v4l2.c - V4L2 driver helper framework * * Copyright (C) 2010 Samsung Electronics * * Author: Pawel Osciak <pawel@osciak.com> * Marek Szyprowski <m.szyprowski@samsung.com> * * The vb2_thread implementation was based on code from videobuf-dvb.c: * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs] * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation.
*/
#define dprintk(q, level, fmt, arg...) \ do { \ if (debug >= level) \
pr_info("vb2-v4l2: [%p] %s: " fmt, \
(q)->name, __func__, ## arg); \
} while (0)
/* Flags that are set by us */ #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \
V4L2_BUF_FLAG_PREPARED | \
V4L2_BUF_FLAG_IN_REQUEST | \
V4L2_BUF_FLAG_REQUEST_FD | \
V4L2_BUF_FLAG_TIMESTAMP_MASK) /* Output buffer flags that should be passed on to the driver */ #define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | \
V4L2_BUF_FLAG_BFRAME | \
V4L2_BUF_FLAG_KEYFRAME | \
V4L2_BUF_FLAG_TIMECODE | \
V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF)
/* * __verify_planes_array() - verify that the planes array passed in struct * v4l2_buffer from userspace can be safely used
*/ staticint __verify_planes_array(struct vb2_buffer *vb, conststruct v4l2_buffer *b)
{ if (!V4L2_TYPE_IS_MULTIPLANAR(b->type)) return 0;
/* Is memory for copying plane information present? */ if (b->m.planes == NULL) {
dprintk(vb->vb2_queue, 1, "multi-planar buffer passed but planes array not provided\n"); return -EINVAL;
}
/* * __verify_length() - Verify that the bytesused value for each plane fits in * the plane length and that the data offset doesn't exceed the bytesused value.
*/ staticint __verify_length(struct vb2_buffer *vb, conststruct v4l2_buffer *b)
{ unsignedint length; unsignedint bytesused; unsignedint plane;
if (q->is_output) { /* * For output buffers copy the timestamp if needed, * and the timecode field and flag if needed.
*/ if (q->copy_timestamp)
vb->timestamp = v4l2_buffer_get_timestamp(b);
vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; if (b->flags & V4L2_BUF_FLAG_TIMECODE)
vbuf->timecode = b->timecode;
}
};
pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n"); if (vb->vb2_queue->allow_zero_bytesused)
pr_warn("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n"); else
pr_warn("use the actual size instead.\n");
}
ret = __verify_length(vb, b); if (ret < 0) {
dprintk(q, 1, "plane parameters verification failed: %d\n", ret); return ret;
} if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) { /* * If the format's field is ALTERNATE, then the buffer's field * should be either TOP or BOTTOM, not ALTERNATE since that * makes no sense. The driver has to know whether the * buffer represents a top or a bottom field in order to * program any DMA correctly. Using ALTERNATE is wrong, since * that just says that it is either a top or a bottom field, * but not which of the two it is.
*/
dprintk(q, 1, "the field is incorrectly set to ALTERNATE for an output buffer\n"); return -EINVAL;
}
vbuf->sequence = 0;
vbuf->request_fd = -1;
vbuf->is_held = false;
/* Fill in user-provided information for OUTPUT types */ if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* * Will have to go up to b->length when API starts * accepting variable number of planes. * * If bytesused == 0 for the output buffer, then fall * back to the full buffer size. In that case * userspace clearly never bothered to set it and * it's a safe assumption that they really meant to * use the full plane sizes. * * Some drivers, e.g. old codec drivers, use bytesused == 0 * as a way to indicate that streaming is finished. * In that case, the driver should use the * allow_zero_bytesused flag to keep old userspace * applications working.
*/ for (plane = 0; plane < vb->num_planes; ++plane) { struct vb2_plane *pdst = &planes[plane]; struct v4l2_plane *psrc = &b->m.planes[plane];
if (psrc->bytesused == 0)
vb2_warn_zero_bytesused(vb);
if (vb->vb2_queue->allow_zero_bytesused)
pdst->bytesused = psrc->bytesused; else
pdst->bytesused = psrc->bytesused ?
psrc->bytesused : pdst->length;
pdst->data_offset = psrc->data_offset;
}
}
} else { /* * Single-planar buffers do not use planes array, * so fill in relevant v4l2_buffer struct fields instead. * In vb2 we use our internal V4l2_planes struct for * single-planar buffers as well, for simplicity. * * If bytesused == 0 for the output buffer, then fall back * to the full buffer size as that's a sensible default. * * Some drivers, e.g. old codec drivers, use bytesused == 0 as * a way to indicate that streaming is finished. In that case, * the driver should use the allow_zero_bytesused flag to keep * old userspace applications working.
*/ switch (b->memory) { case VB2_MEMORY_USERPTR:
planes[0].m.userptr = b->m.userptr;
planes[0].length = b->length; break; case VB2_MEMORY_DMABUF:
planes[0].m.fd = b->m.fd;
planes[0].length = b->length; break; default:
planes[0].m.offset = vb->planes[0].m.offset;
planes[0].length = vb->planes[0].length; break;
}
planes[0].data_offset = 0; if (V4L2_TYPE_IS_OUTPUT(b->type)) { if (b->bytesused == 0)
vb2_warn_zero_bytesused(vb);
/* Zero flags that we handle */
vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; if (!vb->vb2_queue->copy_timestamp || V4L2_TYPE_IS_CAPTURE(b->type)) { /* * Non-COPY timestamps and non-OUTPUT queues will get * their timestamp and timestamp source flags from the * queue.
*/
vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
}
if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* * For output buffers mask out the timecode flag: * this will be handled later in vb2_qbuf(). * The 'field' is valid metadata for this output buffer * and so that needs to be copied here.
*/
vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE;
vbuf->field = b->field; if (!(q->subsystem_flags & VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF))
vbuf->flags &= ~V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF;
} else { /* Zero any output buffer flags as this is a capture buffer */
vbuf->flags &= ~V4L2_BUFFER_OUT_FLAGS; /* Zero last flag, this is a signal from driver to userspace */
vbuf->flags &= ~V4L2_BUF_FLAG_LAST;
}
return 0;
}
staticvoid set_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb, struct v4l2_buffer *b)
{ if (!vb2_queue_allows_cache_hints(q)) { /* * Clear buffer cache flags if queue does not support user * space hints. That's to indicate to userspace that these * flags won't work.
*/
b->flags &= ~V4L2_BUF_FLAG_NO_CACHE_INVALIDATE;
b->flags &= ~V4L2_BUF_FLAG_NO_CACHE_CLEAN; return;
}
if (b->flags & V4L2_BUF_FLAG_NO_CACHE_INVALIDATE)
vb->skip_cache_sync_on_finish = 1;
if (b->flags & V4L2_BUF_FLAG_NO_CACHE_CLEAN)
vb->skip_cache_sync_on_prepare = 1;
}
vbuf = to_vb2_v4l2_buffer(vb);
ret = __verify_planes_array(vb, b); if (ret) return ret;
if (!is_prepare && (b->flags & V4L2_BUF_FLAG_REQUEST_FD) &&
vb->state != VB2_BUF_STATE_DEQUEUED) {
dprintk(q, 1, "%s: buffer is not in dequeued state\n", opname); return -EINVAL;
}
if (!vb->prepared) {
set_buffer_cache_hints(q, vb, b); /* Copy relevant information provided by the userspace */
memset(vbuf->planes, 0, sizeof(vbuf->planes[0]) * vb->num_planes);
ret = vb2_fill_vb2_v4l2_buffer(vb, b); if (ret) return ret;
}
if (is_prepare) return 0;
if (!(b->flags & V4L2_BUF_FLAG_REQUEST_FD)) { if (q->requires_requests) {
dprintk(q, 1, "%s: queue requires requests\n", opname); return -EBADR;
} if (q->uses_requests) {
dprintk(q, 1, "%s: queue uses requests\n", opname); return -EBUSY;
} return 0;
} elseif (!q->supports_requests) {
dprintk(q, 1, "%s: queue does not support requests\n", opname); return -EBADR;
} elseif (q->uses_qbuf) {
dprintk(q, 1, "%s: queue does not use requests\n", opname); return -EBUSY;
}
/* * For proper locking when queueing a request you need to be able * to lock access to the vb2 queue, so check that there is a lock * that we can use. In addition p_req must be non-NULL.
*/ if (WARN_ON(!q->lock || !p_req)) return -EINVAL;
/* * Make sure this op is implemented by the driver. It's easy to forget * this callback, but is it important when canceling a buffer in a * queued request.
*/ if (WARN_ON(!q->ops->buf_request_complete)) return -EINVAL; /* * Make sure this op is implemented by the driver for the output queue. * It's easy to forget this callback, but is it important to correctly * validate the 'field' value at QBUF time.
*/ if (WARN_ON((q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
!q->ops->buf_out_validate)) return -EINVAL;
/* * Early sanity check. This is checked again when the buffer * is bound to the request in vb2_core_qbuf().
*/ if (req->state != MEDIA_REQUEST_STATE_IDLE &&
req->state != MEDIA_REQUEST_STATE_UPDATING) {
dprintk(q, 1, "%s: request is not idle\n", opname);
media_request_put(req); return -EBUSY;
}
*p_req = req;
vbuf->request_fd = b->request_fd;
return 0;
}
/* * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace
*/ staticvoid __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
{ struct v4l2_buffer *b = pb; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *q = vb->vb2_queue; unsignedint plane;
/* Copy back data such as timestamp, flags, etc. */
b->index = vb->index;
b->type = vb->type;
b->memory = vb->memory;
b->bytesused = 0;
if (q->is_multiplanar) { /* * Fill in plane-related data if userspace provided an array * for it. The caller has already verified memory and size.
*/
b->length = vb->num_planes; for (plane = 0; plane < vb->num_planes; ++plane) { struct v4l2_plane *pdst = &b->m.planes[plane]; struct vb2_plane *psrc = &vb->planes[plane];
pdst->bytesused = psrc->bytesused;
pdst->length = psrc->length; if (q->memory == VB2_MEMORY_MMAP)
pdst->m.mem_offset = psrc->m.offset; elseif (q->memory == VB2_MEMORY_USERPTR)
pdst->m.userptr = psrc->m.userptr; elseif (q->memory == VB2_MEMORY_DMABUF)
pdst->m.fd = psrc->m.fd;
pdst->data_offset = psrc->data_offset;
memset(pdst->reserved, 0, sizeof(pdst->reserved));
}
} else { /* * We use length and offset in v4l2_planes array even for * single-planar buffers, but userspace does not.
*/
b->length = vb->planes[0].length;
b->bytesused = vb->planes[0].bytesused; if (q->memory == VB2_MEMORY_MMAP)
b->m.offset = vb->planes[0].m.offset; elseif (q->memory == VB2_MEMORY_USERPTR)
b->m.userptr = vb->planes[0].m.userptr; elseif (q->memory == VB2_MEMORY_DMABUF)
b->m.fd = vb->planes[0].m.fd;
}
/* * Clear any buffer state related flags.
*/
b->flags &= ~V4L2_BUFFER_MASK_FLAGS;
b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK; if (!q->copy_timestamp) { /* * For non-COPY timestamps, drop timestamp source bits * and obtain the timestamp source from the queue.
*/
b->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
}
switch (vb->state) { case VB2_BUF_STATE_QUEUED: case VB2_BUF_STATE_ACTIVE:
b->flags |= V4L2_BUF_FLAG_QUEUED; break; case VB2_BUF_STATE_IN_REQUEST:
b->flags |= V4L2_BUF_FLAG_IN_REQUEST; break; case VB2_BUF_STATE_ERROR:
b->flags |= V4L2_BUF_FLAG_ERROR;
fallthrough; case VB2_BUF_STATE_DONE:
b->flags |= V4L2_BUF_FLAG_DONE; break; case VB2_BUF_STATE_PREPARING: case VB2_BUF_STATE_DEQUEUED: /* nothing */ break;
}
if (vb2_buffer_in_use(q, vb))
b->flags |= V4L2_BUF_FLAG_MAPPED; if (vbuf->request_fd >= 0) {
b->flags |= V4L2_BUF_FLAG_REQUEST_FD;
b->request_fd = vbuf->request_fd;
}
}
/* * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a * v4l2_buffer by the userspace. It also verifies that struct * v4l2_buffer has a valid number of planes.
*/ staticint __fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes)
{ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); unsignedint plane;
if (!vb->vb2_queue->copy_timestamp)
vb->timestamp = 0;
/* * This loop doesn't scale if there is a really large number of buffers. * Maybe something more efficient will be needed in this case.
*/ for (i = 0; i < q->max_num_buffers; i++) {
vb2 = vb2_get_buffer(q, i);
/* * vb2_querybuf() - query video buffer information * @q: vb2 queue * @b: buffer struct passed from userspace to vidioc_querybuf handler * in driver * * Should be called from vidioc_querybuf ioctl handler in driver. * This function will verify the passed v4l2_buffer structure and fill the * relevant information for the userspace. * * The return values from this function are intended to be directly returned * from vidioc_querybuf handler in driver.
*/ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
{ struct vb2_buffer *vb; int ret;
vb = vb2_get_buffer(q, b->index); if (!vb) {
dprintk(q, 1, "can't find the requested buffer %u\n", b->index); return -EINVAL;
}
ret = __verify_planes_array(vb, b); if (!ret)
vb2_core_querybuf(q, vb, b); return ret;
}
EXPORT_SYMBOL(vb2_querybuf);
staticvoid vb2_set_flags_and_caps(struct vb2_queue *q, u32 memory,
u32 *flags, u32 *caps, u32 *max_num_bufs)
{ if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) { /* * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only, * but in order to avoid bugs we zero out all bits.
*/
*flags = 0;
} else { /* Clear all unknown flags. */
*flags &= V4L2_MEMORY_FLAG_NON_COHERENT;
}
*caps |= V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS; if (q->io_modes & VB2_MMAP)
*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP; if (q->io_modes & VB2_USERPTR)
*caps |= V4L2_BUF_CAP_SUPPORTS_USERPTR; if (q->io_modes & VB2_DMABUF)
*caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF; if (q->subsystem_flags & VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF)
*caps |= V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF; if (q->allow_cache_hints && q->io_modes & VB2_MMAP)
*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS; if (q->supports_requests)
*caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS; if (max_num_bufs) {
*max_num_bufs = q->max_num_buffers;
*caps |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS;
}
}
int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
{ int ret = vb2_verify_memory_type(q, req->memory, req->type);
u32 flags = req->flags;
vb2_set_flags_and_caps(q, req->memory, &flags,
&req->capabilities, NULL);
req->flags = flags; return ret ? ret : vb2_core_reqbufs(q, req->memory,
req->flags, &req->count);
}
EXPORT_SYMBOL_GPL(vb2_reqbufs);
int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, struct v4l2_buffer *b)
{ struct vb2_buffer *vb; int ret;
if (vb2_fileio_is_active(q)) {
dprintk(q, 1, "file io in progress\n"); return -EBUSY;
}
if (b->flags & V4L2_BUF_FLAG_REQUEST_FD) return -EINVAL;
vb = vb2_get_buffer(q, b->index); if (!vb) {
dprintk(q, 1, "can't find the requested buffer %u\n", b->index); return -EINVAL;
}
ret = vb2_queue_or_prepare_buf(q, mdev, vb, b, true, NULL);
return ret ? ret : vb2_core_prepare_buf(q, vb, b);
}
EXPORT_SYMBOL_GPL(vb2_prepare_buf);
int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
{ unsigned requested_planes = 1; unsigned requested_sizes[VIDEO_MAX_PLANES]; struct v4l2_format *f = &create->format; int ret = vb2_verify_memory_type(q, create->memory, f->type); unsigned i;
create->index = vb2_get_num_buffers(q);
vb2_set_flags_and_caps(q, create->memory, &create->flags,
&create->capabilities, &create->max_num_buffers); if (create->count == 0) return ret != -EBUSY ? ret : 0;
switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
requested_planes = f->fmt.pix_mp.num_planes; if (requested_planes == 0 ||
requested_planes > VIDEO_MAX_PLANES) return -EINVAL; for (i = 0; i < requested_planes; i++)
requested_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT:
requested_sizes[0] = f->fmt.pix.sizeimage; break; case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT:
requested_sizes[0] = f->fmt.vbi.samples_per_line *
(f->fmt.vbi.count[0] + f->fmt.vbi.count[1]); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
requested_sizes[0] = f->fmt.sliced.io_size; break; case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT:
requested_sizes[0] = f->fmt.sdr.buffersize; break; case V4L2_BUF_TYPE_META_CAPTURE: case V4L2_BUF_TYPE_META_OUTPUT:
requested_sizes[0] = f->fmt.meta.buffersize; break; default: return -EINVAL;
} for (i = 0; i < requested_planes; i++) if (requested_sizes[i] == 0) return -EINVAL; if (ret) return ret;
/* Warn that the driver should choose an appropriate timestamp type */
WARN_ON((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN);
if (q->buf_struct_size == 0)
q->buf_struct_size = sizeof(struct vb2_v4l2_buffer);
q->buf_ops = &v4l2_buf_ops;
q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
q->is_output = V4L2_TYPE_IS_OUTPUT(q->type);
q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK)
== V4L2_BUF_FLAG_TIMESTAMP_COPY; /* * For compatibility with vb1: if QBUF hasn't been called yet, then * return EPOLLERR as well. This only affects capture queues, output * queues will always initialize waiting_for_buffers to false.
*/
q->quirk_poll_must_check_waiting_for_buffers = true;
if (name)
strscpy(q->name, name, sizeof(q->name)); else
q->name[0] = '\0';
if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { struct v4l2_fh *fh = file->private_data;
poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh))
res |= EPOLLPRI;
}
return res;
}
EXPORT_SYMBOL_GPL(vb2_poll);
/* * The following functions are not part of the vb2 core API, but are helper * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations * and struct vb2_ops. * They contain boilerplate code that most if not all drivers have to do * and so they simplify the driver code.
*/
int vb2_ioctl_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p)
{ struct video_device *vdev = video_devdata(file); int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
u32 flags = p->flags;
vb2_set_flags_and_caps(vdev->queue, p->memory, &flags,
&p->capabilities, NULL);
p->flags = flags; if (res) return res; if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY;
res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count); /* If count == 0, then the owner has released all buffers and he
is no longer owner of the queue. Otherwise we have a new owner. */ if (res == 0)
vdev->queue->owner = p->count ? file->private_data : NULL; return res;
}
EXPORT_SYMBOL_GPL(vb2_ioctl_reqbufs);
int vb2_ioctl_create_bufs(struct file *file, void *priv, struct v4l2_create_buffers *p)
{ struct video_device *vdev = video_devdata(file); int res = vb2_verify_memory_type(vdev->queue, p->memory, p->format.type);
p->index = vb2_get_num_buffers(vdev->queue);
vb2_set_flags_and_caps(vdev->queue, p->memory, &p->flags,
&p->capabilities, &p->max_num_buffers); /* * If count == 0, then just check if memory and type are valid. * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
*/ if (p->count == 0) return res != -EBUSY ? res : 0; if (res) return res; if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY;
res = vb2_create_bufs(vdev->queue, p); if (res == 0)
vdev->queue->owner = file->private_data; return res;
}
EXPORT_SYMBOL_GPL(vb2_ioctl_create_bufs);
/* * If this helper doesn't know how to lock, then you shouldn't be using * it but you should write your own.
*/
WARN_ON(!lock);
if (lock && mutex_lock_interruptible(lock)) return EPOLLERR;
fileio = q->fileio;
res = vb2_poll(vdev->queue, file, wait);
/* If fileio was started, then we have a new queue owner. */ if (!fileio && q->fileio)
q->owner = file->private_data; if (lock)
mutex_unlock(lock); return res;
}
EXPORT_SYMBOL_GPL(vb2_fop_poll);
void vb2_video_unregister_device(struct video_device *vdev)
{ /* Check if vdev was ever registered at all */ if (!vdev || !video_is_registered(vdev)) return;
/* * Calling this function only makes sense if vdev->queue is set. * If it is NULL, then just call video_unregister_device() instead.
*/
WARN_ON(!vdev->queue);
/* * Take a reference to the device since video_unregister_device() * calls device_unregister(), but we don't want that to release * the device since we want to clean up the queue first.
*/
get_device(&vdev->dev);
video_unregister_device(vdev); if (vdev->queue) { struct mutex *lock = vdev->queue->lock ?
vdev->queue->lock : vdev->lock;
if (lock)
mutex_lock(lock);
vb2_queue_release(vdev->queue);
vdev->queue->owner = NULL; if (lock)
mutex_unlock(lock);
} /* * Now we put the device, and in most cases this will release * everything.
*/
put_device(&vdev->dev);
}
EXPORT_SYMBOL_GPL(vb2_video_unregister_device);
/* vb2_ops helpers. Only use if vq->lock is non-NULL. */
/* * Note that this function is called during validation time and * thus the req_queue_mutex is held to ensure no request objects * can be added or deleted while validating. So there is no need * to protect the objects list.
*/ int vb2_request_validate(struct media_request *req)
{ struct media_request_object *obj; int ret = 0;
if (!vb2_request_buffer_cnt(req)) return -ENOENT;
list_for_each_entry(obj, &req->objects, list) { if (!obj->ops->prepare) continue;
ret = obj->ops->prepare(obj); if (ret) break;
}
if (ret) {
list_for_each_entry_continue_reverse(obj, &req->objects, list) if (obj->ops->unprepare)
obj->ops->unprepare(obj); return ret;
} return 0;
}
EXPORT_SYMBOL_GPL(vb2_request_validate);
/* * Queue all objects. Note that buffer objects are at the end of the * objects list, after all other object types. Once buffer objects * are queued, the driver might delete them immediately (if the driver * processes the buffer at once), so we have to use * list_for_each_entry_safe() to handle the case where the object we * queue is deleted.
*/
list_for_each_entry_safe(obj, obj_safe, &req->objects, list) if (obj->ops->queue)
obj->ops->queue(obj);
}
EXPORT_SYMBOL_GPL(vb2_request_queue);
MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet am 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.