diff options
Diffstat (limited to 'drivers/media/v4l2-core/videobuf2-core.c')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 300 |
1 files changed, 297 insertions, 3 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 432df119af27..9f81be23a81f 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -109,6 +109,36 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) | |||
109 | } | 109 | } |
110 | 110 | ||
111 | /** | 111 | /** |
112 | * __vb2_plane_dmabuf_put() - release memory associated with | ||
113 | * a DMABUF shared plane | ||
114 | */ | ||
115 | static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) | ||
116 | { | ||
117 | if (!p->mem_priv) | ||
118 | return; | ||
119 | |||
120 | if (p->dbuf_mapped) | ||
121 | call_memop(q, unmap_dmabuf, p->mem_priv); | ||
122 | |||
123 | call_memop(q, detach_dmabuf, p->mem_priv); | ||
124 | dma_buf_put(p->dbuf); | ||
125 | memset(p, 0, sizeof(*p)); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * __vb2_buf_dmabuf_put() - release memory associated with | ||
130 | * a DMABUF shared buffer | ||
131 | */ | ||
132 | static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) | ||
133 | { | ||
134 | struct vb2_queue *q = vb->vb2_queue; | ||
135 | unsigned int plane; | ||
136 | |||
137 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
138 | __vb2_plane_dmabuf_put(q, &vb->planes[plane]); | ||
139 | } | ||
140 | |||
141 | /** | ||
112 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in | 142 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in |
113 | * every buffer on the queue | 143 | * every buffer on the queue |
114 | */ | 144 | */ |
@@ -230,6 +260,8 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) | |||
230 | /* Free MMAP buffers or release USERPTR buffers */ | 260 | /* Free MMAP buffers or release USERPTR buffers */ |
231 | if (q->memory == V4L2_MEMORY_MMAP) | 261 | if (q->memory == V4L2_MEMORY_MMAP) |
232 | __vb2_buf_mem_free(vb); | 262 | __vb2_buf_mem_free(vb); |
263 | else if (q->memory == V4L2_MEMORY_DMABUF) | ||
264 | __vb2_buf_dmabuf_put(vb); | ||
233 | else | 265 | else |
234 | __vb2_buf_userptr_put(vb); | 266 | __vb2_buf_userptr_put(vb); |
235 | } | 267 | } |
@@ -362,6 +394,8 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
362 | b->m.offset = vb->v4l2_planes[0].m.mem_offset; | 394 | b->m.offset = vb->v4l2_planes[0].m.mem_offset; |
363 | else if (q->memory == V4L2_MEMORY_USERPTR) | 395 | else if (q->memory == V4L2_MEMORY_USERPTR) |
364 | b->m.userptr = vb->v4l2_planes[0].m.userptr; | 396 | b->m.userptr = vb->v4l2_planes[0].m.userptr; |
397 | else if (q->memory == V4L2_MEMORY_DMABUF) | ||
398 | b->m.fd = vb->v4l2_planes[0].m.fd; | ||
365 | } | 399 | } |
366 | 400 | ||
367 | /* | 401 | /* |
@@ -454,13 +488,28 @@ static int __verify_mmap_ops(struct vb2_queue *q) | |||
454 | } | 488 | } |
455 | 489 | ||
456 | /** | 490 | /** |
491 | * __verify_dmabuf_ops() - verify that all memory operations required for | ||
492 | * DMABUF queue type have been provided | ||
493 | */ | ||
494 | static int __verify_dmabuf_ops(struct vb2_queue *q) | ||
495 | { | ||
496 | if (!(q->io_modes & VB2_DMABUF) || !q->mem_ops->attach_dmabuf || | ||
497 | !q->mem_ops->detach_dmabuf || !q->mem_ops->map_dmabuf || | ||
498 | !q->mem_ops->unmap_dmabuf) | ||
499 | return -EINVAL; | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /** | ||
457 | * __verify_memory_type() - Check whether the memory type and buffer type | 505 | * __verify_memory_type() - Check whether the memory type and buffer type |
458 | * passed to a buffer operation are compatible with the queue. | 506 | * passed to a buffer operation are compatible with the queue. |
459 | */ | 507 | */ |
460 | static int __verify_memory_type(struct vb2_queue *q, | 508 | static int __verify_memory_type(struct vb2_queue *q, |
461 | enum v4l2_memory memory, enum v4l2_buf_type type) | 509 | enum v4l2_memory memory, enum v4l2_buf_type type) |
462 | { | 510 | { |
463 | if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR) { | 511 | if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR && |
512 | memory != V4L2_MEMORY_DMABUF) { | ||
464 | dprintk(1, "reqbufs: unsupported memory type\n"); | 513 | dprintk(1, "reqbufs: unsupported memory type\n"); |
465 | return -EINVAL; | 514 | return -EINVAL; |
466 | } | 515 | } |
@@ -484,6 +533,11 @@ static int __verify_memory_type(struct vb2_queue *q, | |||
484 | return -EINVAL; | 533 | return -EINVAL; |
485 | } | 534 | } |
486 | 535 | ||
536 | if (memory == V4L2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) { | ||
537 | dprintk(1, "reqbufs: DMABUF for current setup unsupported\n"); | ||
538 | return -EINVAL; | ||
539 | } | ||
540 | |||
487 | /* | 541 | /* |
488 | * Place the busy tests at the end: -EBUSY can be ignored when | 542 | * Place the busy tests at the end: -EBUSY can be ignored when |
489 | * create_bufs is called with count == 0, but count == 0 should still | 543 | * create_bufs is called with count == 0, but count == 0 should still |
@@ -790,6 +844,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) | |||
790 | { | 844 | { |
791 | struct vb2_queue *q = vb->vb2_queue; | 845 | struct vb2_queue *q = vb->vb2_queue; |
792 | unsigned long flags; | 846 | unsigned long flags; |
847 | unsigned int plane; | ||
793 | 848 | ||
794 | if (vb->state != VB2_BUF_STATE_ACTIVE) | 849 | if (vb->state != VB2_BUF_STATE_ACTIVE) |
795 | return; | 850 | return; |
@@ -800,6 +855,10 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) | |||
800 | dprintk(4, "Done processing on buffer %d, state: %d\n", | 855 | dprintk(4, "Done processing on buffer %d, state: %d\n", |
801 | vb->v4l2_buf.index, vb->state); | 856 | vb->v4l2_buf.index, vb->state); |
802 | 857 | ||
858 | /* sync buffers */ | ||
859 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
860 | call_memop(q, finish, vb->planes[plane].mem_priv); | ||
861 | |||
803 | /* Add the buffer to the done buffers list */ | 862 | /* Add the buffer to the done buffers list */ |
804 | spin_lock_irqsave(&q->done_lock, flags); | 863 | spin_lock_irqsave(&q->done_lock, flags); |
805 | vb->state = state; | 864 | vb->state = state; |
@@ -845,6 +904,16 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b | |||
845 | b->m.planes[plane].length; | 904 | b->m.planes[plane].length; |
846 | } | 905 | } |
847 | } | 906 | } |
907 | if (b->memory == V4L2_MEMORY_DMABUF) { | ||
908 | for (plane = 0; plane < vb->num_planes; ++plane) { | ||
909 | v4l2_planes[plane].m.fd = | ||
910 | b->m.planes[plane].m.fd; | ||
911 | v4l2_planes[plane].length = | ||
912 | b->m.planes[plane].length; | ||
913 | v4l2_planes[plane].data_offset = | ||
914 | b->m.planes[plane].data_offset; | ||
915 | } | ||
916 | } | ||
848 | } else { | 917 | } else { |
849 | /* | 918 | /* |
850 | * Single-planar buffers do not use planes array, | 919 | * Single-planar buffers do not use planes array, |
@@ -859,6 +928,13 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b | |||
859 | v4l2_planes[0].m.userptr = b->m.userptr; | 928 | v4l2_planes[0].m.userptr = b->m.userptr; |
860 | v4l2_planes[0].length = b->length; | 929 | v4l2_planes[0].length = b->length; |
861 | } | 930 | } |
931 | |||
932 | if (b->memory == V4L2_MEMORY_DMABUF) { | ||
933 | v4l2_planes[0].m.fd = b->m.fd; | ||
934 | v4l2_planes[0].length = b->length; | ||
935 | v4l2_planes[0].data_offset = 0; | ||
936 | } | ||
937 | |||
862 | } | 938 | } |
863 | 939 | ||
864 | vb->v4l2_buf.field = b->field; | 940 | vb->v4l2_buf.field = b->field; |
@@ -959,14 +1035,121 @@ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
959 | } | 1035 | } |
960 | 1036 | ||
961 | /** | 1037 | /** |
1038 | * __qbuf_dmabuf() - handle qbuf of a DMABUF buffer | ||
1039 | */ | ||
1040 | static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) | ||
1041 | { | ||
1042 | struct v4l2_plane planes[VIDEO_MAX_PLANES]; | ||
1043 | struct vb2_queue *q = vb->vb2_queue; | ||
1044 | void *mem_priv; | ||
1045 | unsigned int plane; | ||
1046 | int ret; | ||
1047 | int write = !V4L2_TYPE_IS_OUTPUT(q->type); | ||
1048 | |||
1049 | /* Verify and copy relevant information provided by the userspace */ | ||
1050 | __fill_vb2_buffer(vb, b, planes); | ||
1051 | |||
1052 | for (plane = 0; plane < vb->num_planes; ++plane) { | ||
1053 | struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); | ||
1054 | |||
1055 | if (IS_ERR_OR_NULL(dbuf)) { | ||
1056 | dprintk(1, "qbuf: invalid dmabuf fd for plane %d\n", | ||
1057 | plane); | ||
1058 | ret = -EINVAL; | ||
1059 | goto err; | ||
1060 | } | ||
1061 | |||
1062 | /* use DMABUF size if length is not provided */ | ||
1063 | if (planes[plane].length == 0) | ||
1064 | planes[plane].length = dbuf->size; | ||
1065 | |||
1066 | if (planes[plane].length < planes[plane].data_offset + | ||
1067 | q->plane_sizes[plane]) { | ||
1068 | ret = -EINVAL; | ||
1069 | goto err; | ||
1070 | } | ||
1071 | |||
1072 | /* Skip the plane if already verified */ | ||
1073 | if (dbuf == vb->planes[plane].dbuf && | ||
1074 | vb->v4l2_planes[plane].length == planes[plane].length) { | ||
1075 | dma_buf_put(dbuf); | ||
1076 | continue; | ||
1077 | } | ||
1078 | |||
1079 | dprintk(1, "qbuf: buffer for plane %d changed\n", plane); | ||
1080 | |||
1081 | /* Release previously acquired memory if present */ | ||
1082 | __vb2_plane_dmabuf_put(q, &vb->planes[plane]); | ||
1083 | memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); | ||
1084 | |||
1085 | /* Acquire each plane's memory */ | ||
1086 | mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane], | ||
1087 | dbuf, planes[plane].length, write); | ||
1088 | if (IS_ERR(mem_priv)) { | ||
1089 | dprintk(1, "qbuf: failed to attach dmabuf\n"); | ||
1090 | ret = PTR_ERR(mem_priv); | ||
1091 | dma_buf_put(dbuf); | ||
1092 | goto err; | ||
1093 | } | ||
1094 | |||
1095 | vb->planes[plane].dbuf = dbuf; | ||
1096 | vb->planes[plane].mem_priv = mem_priv; | ||
1097 | } | ||
1098 | |||
1099 | /* TODO: This pins the buffer(s) with dma_buf_map_attachment()).. but | ||
1100 | * really we want to do this just before the DMA, not while queueing | ||
1101 | * the buffer(s).. | ||
1102 | */ | ||
1103 | for (plane = 0; plane < vb->num_planes; ++plane) { | ||
1104 | ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv); | ||
1105 | if (ret) { | ||
1106 | dprintk(1, "qbuf: failed to map dmabuf for plane %d\n", | ||
1107 | plane); | ||
1108 | goto err; | ||
1109 | } | ||
1110 | vb->planes[plane].dbuf_mapped = 1; | ||
1111 | } | ||
1112 | |||
1113 | /* | ||
1114 | * Call driver-specific initialization on the newly acquired buffer, | ||
1115 | * if provided. | ||
1116 | */ | ||
1117 | ret = call_qop(q, buf_init, vb); | ||
1118 | if (ret) { | ||
1119 | dprintk(1, "qbuf: buffer initialization failed\n"); | ||
1120 | goto err; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Now that everything is in order, copy relevant information | ||
1125 | * provided by userspace. | ||
1126 | */ | ||
1127 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
1128 | vb->v4l2_planes[plane] = planes[plane]; | ||
1129 | |||
1130 | return 0; | ||
1131 | err: | ||
1132 | /* In case of errors, release planes that were already acquired */ | ||
1133 | __vb2_buf_dmabuf_put(vb); | ||
1134 | |||
1135 | return ret; | ||
1136 | } | ||
1137 | |||
1138 | /** | ||
962 | * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing | 1139 | * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing |
963 | */ | 1140 | */ |
964 | static void __enqueue_in_driver(struct vb2_buffer *vb) | 1141 | static void __enqueue_in_driver(struct vb2_buffer *vb) |
965 | { | 1142 | { |
966 | struct vb2_queue *q = vb->vb2_queue; | 1143 | struct vb2_queue *q = vb->vb2_queue; |
1144 | unsigned int plane; | ||
967 | 1145 | ||
968 | vb->state = VB2_BUF_STATE_ACTIVE; | 1146 | vb->state = VB2_BUF_STATE_ACTIVE; |
969 | atomic_inc(&q->queued_count); | 1147 | atomic_inc(&q->queued_count); |
1148 | |||
1149 | /* sync buffers */ | ||
1150 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
1151 | call_memop(q, prepare, vb->planes[plane].mem_priv); | ||
1152 | |||
970 | q->ops->buf_queue(vb); | 1153 | q->ops->buf_queue(vb); |
971 | } | 1154 | } |
972 | 1155 | ||
@@ -982,6 +1165,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
982 | case V4L2_MEMORY_USERPTR: | 1165 | case V4L2_MEMORY_USERPTR: |
983 | ret = __qbuf_userptr(vb, b); | 1166 | ret = __qbuf_userptr(vb, b); |
984 | break; | 1167 | break; |
1168 | case V4L2_MEMORY_DMABUF: | ||
1169 | ret = __qbuf_dmabuf(vb, b); | ||
1170 | break; | ||
985 | default: | 1171 | default: |
986 | WARN(1, "Invalid queue type\n"); | 1172 | WARN(1, "Invalid queue type\n"); |
987 | ret = -EINVAL; | 1173 | ret = -EINVAL; |
@@ -1303,6 +1489,30 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q) | |||
1303 | EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); | 1489 | EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); |
1304 | 1490 | ||
1305 | /** | 1491 | /** |
1492 | * __vb2_dqbuf() - bring back the buffer to the DEQUEUED state | ||
1493 | */ | ||
1494 | static void __vb2_dqbuf(struct vb2_buffer *vb) | ||
1495 | { | ||
1496 | struct vb2_queue *q = vb->vb2_queue; | ||
1497 | unsigned int i; | ||
1498 | |||
1499 | /* nothing to do if the buffer is already dequeued */ | ||
1500 | if (vb->state == VB2_BUF_STATE_DEQUEUED) | ||
1501 | return; | ||
1502 | |||
1503 | vb->state = VB2_BUF_STATE_DEQUEUED; | ||
1504 | |||
1505 | /* unmap DMABUF buffer */ | ||
1506 | if (q->memory == V4L2_MEMORY_DMABUF) | ||
1507 | for (i = 0; i < vb->num_planes; ++i) { | ||
1508 | if (!vb->planes[i].dbuf_mapped) | ||
1509 | continue; | ||
1510 | call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv); | ||
1511 | vb->planes[i].dbuf_mapped = 0; | ||
1512 | } | ||
1513 | } | ||
1514 | |||
1515 | /** | ||
1306 | * vb2_dqbuf() - Dequeue a buffer to the userspace | 1516 | * vb2_dqbuf() - Dequeue a buffer to the userspace |
1307 | * @q: videobuf2 queue | 1517 | * @q: videobuf2 queue |
1308 | * @b: buffer structure passed from userspace to vidioc_dqbuf handler | 1518 | * @b: buffer structure passed from userspace to vidioc_dqbuf handler |
@@ -1363,11 +1573,12 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) | |||
1363 | __fill_v4l2_buffer(vb, b); | 1573 | __fill_v4l2_buffer(vb, b); |
1364 | /* Remove from videobuf queue */ | 1574 | /* Remove from videobuf queue */ |
1365 | list_del(&vb->queued_entry); | 1575 | list_del(&vb->queued_entry); |
1576 | /* go back to dequeued state */ | ||
1577 | __vb2_dqbuf(vb); | ||
1366 | 1578 | ||
1367 | dprintk(1, "dqbuf of buffer %d, with state %d\n", | 1579 | dprintk(1, "dqbuf of buffer %d, with state %d\n", |
1368 | vb->v4l2_buf.index, vb->state); | 1580 | vb->v4l2_buf.index, vb->state); |
1369 | 1581 | ||
1370 | vb->state = VB2_BUF_STATE_DEQUEUED; | ||
1371 | return 0; | 1582 | return 0; |
1372 | } | 1583 | } |
1373 | EXPORT_SYMBOL_GPL(vb2_dqbuf); | 1584 | EXPORT_SYMBOL_GPL(vb2_dqbuf); |
@@ -1406,7 +1617,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) | |||
1406 | * Reinitialize all buffers for next use. | 1617 | * Reinitialize all buffers for next use. |
1407 | */ | 1618 | */ |
1408 | for (i = 0; i < q->num_buffers; ++i) | 1619 | for (i = 0; i < q->num_buffers; ++i) |
1409 | q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED; | 1620 | __vb2_dqbuf(q->bufs[i]); |
1410 | } | 1621 | } |
1411 | 1622 | ||
1412 | /** | 1623 | /** |
@@ -1540,6 +1751,79 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, | |||
1540 | } | 1751 | } |
1541 | 1752 | ||
1542 | /** | 1753 | /** |
1754 | * vb2_expbuf() - Export a buffer as a file descriptor | ||
1755 | * @q: videobuf2 queue | ||
1756 | * @eb: export buffer structure passed from userspace to vidioc_expbuf | ||
1757 | * handler in driver | ||
1758 | * | ||
1759 | * The return values from this function are intended to be directly returned | ||
1760 | * from vidioc_expbuf handler in driver. | ||
1761 | */ | ||
1762 | int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) | ||
1763 | { | ||
1764 | struct vb2_buffer *vb = NULL; | ||
1765 | struct vb2_plane *vb_plane; | ||
1766 | int ret; | ||
1767 | struct dma_buf *dbuf; | ||
1768 | |||
1769 | if (q->memory != V4L2_MEMORY_MMAP) { | ||
1770 | dprintk(1, "Queue is not currently set up for mmap\n"); | ||
1771 | return -EINVAL; | ||
1772 | } | ||
1773 | |||
1774 | if (!q->mem_ops->get_dmabuf) { | ||
1775 | dprintk(1, "Queue does not support DMA buffer exporting\n"); | ||
1776 | return -EINVAL; | ||
1777 | } | ||
1778 | |||
1779 | if (eb->flags & ~O_CLOEXEC) { | ||
1780 | dprintk(1, "Queue does support only O_CLOEXEC flag\n"); | ||
1781 | return -EINVAL; | ||
1782 | } | ||
1783 | |||
1784 | if (eb->type != q->type) { | ||
1785 | dprintk(1, "qbuf: invalid buffer type\n"); | ||
1786 | return -EINVAL; | ||
1787 | } | ||
1788 | |||
1789 | if (eb->index >= q->num_buffers) { | ||
1790 | dprintk(1, "buffer index out of range\n"); | ||
1791 | return -EINVAL; | ||
1792 | } | ||
1793 | |||
1794 | vb = q->bufs[eb->index]; | ||
1795 | |||
1796 | if (eb->plane >= vb->num_planes) { | ||
1797 | dprintk(1, "buffer plane out of range\n"); | ||
1798 | return -EINVAL; | ||
1799 | } | ||
1800 | |||
1801 | vb_plane = &vb->planes[eb->plane]; | ||
1802 | |||
1803 | dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv); | ||
1804 | if (IS_ERR_OR_NULL(dbuf)) { | ||
1805 | dprintk(1, "Failed to export buffer %d, plane %d\n", | ||
1806 | eb->index, eb->plane); | ||
1807 | return -EINVAL; | ||
1808 | } | ||
1809 | |||
1810 | ret = dma_buf_fd(dbuf, eb->flags); | ||
1811 | if (ret < 0) { | ||
1812 | dprintk(3, "buffer %d, plane %d failed to export (%d)\n", | ||
1813 | eb->index, eb->plane, ret); | ||
1814 | dma_buf_put(dbuf); | ||
1815 | return ret; | ||
1816 | } | ||
1817 | |||
1818 | dprintk(3, "buffer %d, plane %d exported as %d descriptor\n", | ||
1819 | eb->index, eb->plane, ret); | ||
1820 | eb->fd = ret; | ||
1821 | |||
1822 | return 0; | ||
1823 | } | ||
1824 | EXPORT_SYMBOL_GPL(vb2_expbuf); | ||
1825 | |||
1826 | /** | ||
1543 | * vb2_mmap() - map video buffers into application address space | 1827 | * vb2_mmap() - map video buffers into application address space |
1544 | * @q: videobuf2 queue | 1828 | * @q: videobuf2 queue |
1545 | * @vma: vma passed to the mmap file operation handler in the driver | 1829 | * @vma: vma passed to the mmap file operation handler in the driver |
@@ -2245,6 +2529,16 @@ int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | |||
2245 | } | 2529 | } |
2246 | EXPORT_SYMBOL_GPL(vb2_ioctl_streamoff); | 2530 | EXPORT_SYMBOL_GPL(vb2_ioctl_streamoff); |
2247 | 2531 | ||
2532 | int vb2_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *p) | ||
2533 | { | ||
2534 | struct video_device *vdev = video_devdata(file); | ||
2535 | |||
2536 | if (vb2_queue_is_busy(vdev, file)) | ||
2537 | return -EBUSY; | ||
2538 | return vb2_expbuf(vdev->queue, p); | ||
2539 | } | ||
2540 | EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf); | ||
2541 | |||
2248 | /* v4l2_file_operations helpers */ | 2542 | /* v4l2_file_operations helpers */ |
2249 | 2543 | ||
2250 | int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) | 2544 | int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) |