Merge tag 'media/v4.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[muen/linux.git] / drivers / media / common / videobuf2 / videobuf2-core.c
index 5653e8e..975ff56 100644 (file)
@@ -356,6 +356,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
                        vb->planes[plane].length = plane_sizes[plane];
                        vb->planes[plane].min_length = plane_sizes[plane];
                }
+               call_void_bufop(q, init_buffer, vb);
+
                q->bufs[vb->index] = vb;
 
                /* Allocate video buffer memory for the MMAP type */
@@ -497,8 +499,9 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
                        pr_info("     buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
                                vb->cnt_buf_init, vb->cnt_buf_cleanup,
                                vb->cnt_buf_prepare, vb->cnt_buf_finish);
-                       pr_info("     buf_queue: %u buf_done: %u\n",
-                               vb->cnt_buf_queue, vb->cnt_buf_done);
+                       pr_info("     buf_queue: %u buf_done: %u buf_request_complete: %u\n",
+                               vb->cnt_buf_queue, vb->cnt_buf_done,
+                               vb->cnt_buf_request_complete);
                        pr_info("     alloc: %u put: %u prepare: %u finish: %u mmap: %u\n",
                                vb->cnt_mem_alloc, vb->cnt_mem_put,
                                vb->cnt_mem_prepare, vb->cnt_mem_finish,
@@ -661,6 +664,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
 {
        unsigned int num_buffers, allocated_buffers, num_planes = 0;
        unsigned plane_sizes[VB2_MAX_PLANES] = { };
+       unsigned int i;
        int ret;
 
        if (q->streaming) {
@@ -682,7 +686,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
                }
 
                /*
-                * Call queue_cancel to clean up any buffers in the PREPARED or
+                * Call queue_cancel to clean up any buffers in the
                 * QUEUED state which is possible if buffers were prepared or
                 * queued without ever calling STREAMON.
                 */
@@ -718,6 +722,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
        if (ret)
                return ret;
 
+       /* Check that driver has set sane values */
+       if (WARN_ON(!num_planes))
+               return -EINVAL;
+
+       for (i = 0; i < num_planes; i++)
+               if (WARN_ON(!plane_sizes[i]))
+                       return -EINVAL;
+
        /* Finally, allocate buffers and video memory */
        allocated_buffers =
                __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
@@ -921,6 +933,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
                /* sync buffers */
                for (plane = 0; plane < vb->num_planes; ++plane)
                        call_void_memop(vb, finish, vb->planes[plane].mem_priv);
+               vb->synced = false;
        }
 
        spin_lock_irqsave(&q->done_lock, flags);
@@ -933,6 +946,14 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
                vb->state = state;
        }
        atomic_dec(&q->owned_by_drv_count);
+
+       if (vb->req_obj.req) {
+               /* This is not supported at the moment */
+               WARN_ON(state == VB2_BUF_STATE_REQUEUEING);
+               media_request_object_unbind(&vb->req_obj);
+               media_request_object_put(&vb->req_obj);
+       }
+
        spin_unlock_irqrestore(&q->done_lock, flags);
 
        trace_vb2_buf_done(q, vb);
@@ -967,20 +988,19 @@ EXPORT_SYMBOL_GPL(vb2_discard_done);
 /*
  * __prepare_mmap() - prepare an MMAP buffer
  */
-static int __prepare_mmap(struct vb2_buffer *vb, const void *pb)
+static int __prepare_mmap(struct vb2_buffer *vb)
 {
        int ret = 0;
 
-       if (pb)
-               ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
-                                vb, pb, vb->planes);
+       ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+                        vb, vb->planes);
        return ret ? ret : call_vb_qop(vb, buf_prepare, vb);
 }
 
 /*
  * __prepare_userptr() - prepare a USERPTR buffer
  */
-static int __prepare_userptr(struct vb2_buffer *vb, const void *pb)
+static int __prepare_userptr(struct vb2_buffer *vb)
 {
        struct vb2_plane planes[VB2_MAX_PLANES];
        struct vb2_queue *q = vb->vb2_queue;
@@ -991,12 +1011,10 @@ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb)
 
        memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
        /* Copy relevant information provided by the userspace */
-       if (pb) {
-               ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
-                                vb, pb, planes);
-               if (ret)
-                       return ret;
-       }
+       ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+                        vb, planes);
+       if (ret)
+               return ret;
 
        for (plane = 0; plane < vb->num_planes; ++plane) {
                /* Skip the plane if already verified */
@@ -1096,7 +1114,7 @@ err:
 /*
  * __prepare_dmabuf() - prepare a DMABUF buffer
  */
-static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb)
+static int __prepare_dmabuf(struct vb2_buffer *vb)
 {
        struct vb2_plane planes[VB2_MAX_PLANES];
        struct vb2_queue *q = vb->vb2_queue;
@@ -1107,12 +1125,10 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb)
 
        memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
        /* Copy relevant information provided by the userspace */
-       if (pb) {
-               ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
-                                vb, pb, planes);
-               if (ret)
-                       return ret;
-       }
+       ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+                        vb, planes);
+       if (ret)
+               return ret;
 
        for (plane = 0; plane < vb->num_planes; ++plane) {
                struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);
@@ -1241,9 +1257,10 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
        call_void_vb_qop(vb, buf_queue, vb);
 }
 
-static int __buf_prepare(struct vb2_buffer *vb, const void *pb)
+static int __buf_prepare(struct vb2_buffer *vb)
 {
        struct vb2_queue *q = vb->vb2_queue;
+       enum vb2_buffer_state orig_state = vb->state;
        unsigned int plane;
        int ret;
 
@@ -1252,26 +1269,31 @@ static int __buf_prepare(struct vb2_buffer *vb, const void *pb)
                return -EIO;
        }
 
+       if (vb->prepared)
+               return 0;
+       WARN_ON(vb->synced);
+
        vb->state = VB2_BUF_STATE_PREPARING;
 
        switch (q->memory) {
        case VB2_MEMORY_MMAP:
-               ret = __prepare_mmap(vb, pb);
+               ret = __prepare_mmap(vb);
                break;
        case VB2_MEMORY_USERPTR:
-               ret = __prepare_userptr(vb, pb);
+               ret = __prepare_userptr(vb);
                break;
        case VB2_MEMORY_DMABUF:
-               ret = __prepare_dmabuf(vb, pb);
+               ret = __prepare_dmabuf(vb);
                break;
        default:
                WARN(1, "Invalid queue type\n");
                ret = -EINVAL;
+               break;
        }
 
        if (ret) {
                dprintk(1, "buffer preparation failed: %d\n", ret);
-               vb->state = VB2_BUF_STATE_DEQUEUED;
+               vb->state = orig_state;
                return ret;
        }
 
@@ -1279,11 +1301,98 @@ static int __buf_prepare(struct vb2_buffer *vb, const void *pb)
        for (plane = 0; plane < vb->num_planes; ++plane)
                call_void_memop(vb, prepare, vb->planes[plane].mem_priv);
 
-       vb->state = VB2_BUF_STATE_PREPARED;
+       vb->synced = true;
+       vb->prepared = true;
+       vb->state = orig_state;
 
        return 0;
 }
 
+static int vb2_req_prepare(struct media_request_object *obj)
+{
+       struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+       int ret;
+
+       if (WARN_ON(vb->state != VB2_BUF_STATE_IN_REQUEST))
+               return -EINVAL;
+
+       mutex_lock(vb->vb2_queue->lock);
+       ret = __buf_prepare(vb);
+       mutex_unlock(vb->vb2_queue->lock);
+       return ret;
+}
+
+static void __vb2_dqbuf(struct vb2_buffer *vb);
+
+static void vb2_req_unprepare(struct media_request_object *obj)
+{
+       struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+       mutex_lock(vb->vb2_queue->lock);
+       __vb2_dqbuf(vb);
+       vb->state = VB2_BUF_STATE_IN_REQUEST;
+       mutex_unlock(vb->vb2_queue->lock);
+       WARN_ON(!vb->req_obj.req);
+}
+
+int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
+                 struct media_request *req);
+
+static void vb2_req_queue(struct media_request_object *obj)
+{
+       struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+       mutex_lock(vb->vb2_queue->lock);
+       vb2_core_qbuf(vb->vb2_queue, vb->index, NULL, NULL);
+       mutex_unlock(vb->vb2_queue->lock);
+}
+
+static void vb2_req_unbind(struct media_request_object *obj)
+{
+       struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+       if (vb->state == VB2_BUF_STATE_IN_REQUEST)
+               call_void_bufop(vb->vb2_queue, init_buffer, vb);
+}
+
+static void vb2_req_release(struct media_request_object *obj)
+{
+       struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
+
+       if (vb->state == VB2_BUF_STATE_IN_REQUEST)
+               vb->state = VB2_BUF_STATE_DEQUEUED;
+}
+
+static const struct media_request_object_ops vb2_core_req_ops = {
+       .prepare = vb2_req_prepare,
+       .unprepare = vb2_req_unprepare,
+       .queue = vb2_req_queue,
+       .unbind = vb2_req_unbind,
+       .release = vb2_req_release,
+};
+
+bool vb2_request_object_is_buffer(struct media_request_object *obj)
+{
+       return obj->ops == &vb2_core_req_ops;
+}
+EXPORT_SYMBOL_GPL(vb2_request_object_is_buffer);
+
+unsigned int vb2_request_buffer_cnt(struct media_request *req)
+{
+       struct media_request_object *obj;
+       unsigned long flags;
+       unsigned int buffer_cnt = 0;
+
+       spin_lock_irqsave(&req->lock, flags);
+       list_for_each_entry(obj, &req->objects, list)
+               if (vb2_request_object_is_buffer(obj))
+                       buffer_cnt++;
+       spin_unlock_irqrestore(&req->lock, flags);
+
+       return buffer_cnt;
+}
+EXPORT_SYMBOL_GPL(vb2_request_buffer_cnt);
+
 int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
 {
        struct vb2_buffer *vb;
@@ -1295,8 +1404,12 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
                        vb->state);
                return -EINVAL;
        }
+       if (vb->prepared) {
+               dprintk(1, "buffer already prepared\n");
+               return -EINVAL;
+       }
 
-       ret = __buf_prepare(vb, pb);
+       ret = __buf_prepare(vb);
        if (ret)
                return ret;
 
@@ -1305,7 +1418,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
 
        dprintk(2, "prepare of buffer %d succeeded\n", vb->index);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
 
@@ -1372,7 +1485,8 @@ static int vb2_start_streaming(struct vb2_queue *q)
        return ret;
 }
 
-int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
+int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
+                 struct media_request *req)
 {
        struct vb2_buffer *vb;
        int ret;
@@ -1384,13 +1498,57 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
 
        vb = q->bufs[index];
 
-       switch (vb->state) {
-       case VB2_BUF_STATE_DEQUEUED:
-               ret = __buf_prepare(vb, pb);
+       if ((req && q->uses_qbuf) ||
+           (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
+            q->uses_requests)) {
+               dprintk(1, "queue in wrong mode (qbuf vs requests)\n");
+               return -EBUSY;
+       }
+
+       if (req) {
+               int ret;
+
+               q->uses_requests = 1;
+               if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+                       dprintk(1, "buffer %d not in dequeued state\n",
+                               vb->index);
+                       return -EINVAL;
+               }
+
+               media_request_object_init(&vb->req_obj);
+
+               /* Make sure the request is in a safe state for updating. */
+               ret = media_request_lock_for_update(req);
                if (ret)
                        return ret;
-               break;
-       case VB2_BUF_STATE_PREPARED:
+               ret = media_request_object_bind(req, &vb2_core_req_ops,
+                                               q, true, &vb->req_obj);
+               media_request_unlock_for_update(req);
+               if (ret)
+                       return ret;
+
+               vb->state = VB2_BUF_STATE_IN_REQUEST;
+               /* Fill buffer information for the userspace */
+               if (pb) {
+                       call_void_bufop(q, copy_timestamp, vb, pb);
+                       call_void_bufop(q, fill_user_buffer, vb, pb);
+               }
+
+               dprintk(2, "qbuf of buffer %d succeeded\n", vb->index);
+               return 0;
+       }
+
+       if (vb->state != VB2_BUF_STATE_IN_REQUEST)
+               q->uses_qbuf = 1;
+
+       switch (vb->state) {
+       case VB2_BUF_STATE_DEQUEUED:
+       case VB2_BUF_STATE_IN_REQUEST:
+               if (!vb->prepared) {
+                       ret = __buf_prepare(vb);
+                       if (ret)
+                               return ret;
+               }
                break;
        case VB2_BUF_STATE_PREPARING:
                dprintk(1, "buffer still being prepared\n");
@@ -1591,6 +1749,11 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
                        call_void_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
                        vb->planes[i].dbuf_mapped = 0;
                }
+       if (vb->req_obj.req) {
+               media_request_object_unbind(&vb->req_obj);
+               media_request_object_put(&vb->req_obj);
+       }
+       call_void_bufop(q, init_buffer, vb);
 }
 
 int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
@@ -1616,6 +1779,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
        }
 
        call_void_vb_qop(vb, buf_finish, vb);
+       vb->prepared = false;
 
        if (pindex)
                *pindex = vb->index;
@@ -1679,6 +1843,8 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
        q->start_streaming_called = 0;
        q->queued_count = 0;
        q->error = 0;
+       q->uses_requests = 0;
+       q->uses_qbuf = 0;
 
        /*
         * Remove all buffers from videobuf's list...
@@ -1703,19 +1869,38 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
         */
        for (i = 0; i < q->num_buffers; ++i) {
                struct vb2_buffer *vb = q->bufs[i];
+               struct media_request *req = vb->req_obj.req;
+
+               /*
+                * If a request is associated with this buffer, then
+                * call buf_request_cancel() to give the driver to complete()
+                * related request objects. Otherwise those objects would
+                * never complete.
+                */
+               if (req) {
+                       enum media_request_state state;
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&req->lock, flags);
+                       state = req->state;
+                       spin_unlock_irqrestore(&req->lock, flags);
 
-               if (vb->state == VB2_BUF_STATE_PREPARED ||
-                   vb->state == VB2_BUF_STATE_QUEUED) {
+                       if (state == MEDIA_REQUEST_STATE_QUEUED)
+                               call_void_vb_qop(vb, buf_request_complete, vb);
+               }
+
+               if (vb->synced) {
                        unsigned int plane;
 
                        for (plane = 0; plane < vb->num_planes; ++plane)
                                call_void_memop(vb, finish,
                                                vb->planes[plane].mem_priv);
+                       vb->synced = false;
                }
 
-               if (vb->state != VB2_BUF_STATE_DEQUEUED) {
-                       vb->state = VB2_BUF_STATE_PREPARED;
+               if (vb->prepared) {
                        call_void_vb_qop(vb, buf_finish, vb);
+                       vb->prepared = false;
                }
                __vb2_dqbuf(vb);
        }
@@ -2272,7 +2457,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
                 * Queue all buffers.
                 */
                for (i = 0; i < q->num_buffers; i++) {
-                       ret = vb2_core_qbuf(q, i, NULL);
+                       ret = vb2_core_qbuf(q, i, NULL, NULL);
                        if (ret)
                                goto err_reqbufs;
                        fileio->bufs[i].queued = 1;
@@ -2451,7 +2636,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
 
                if (copy_timestamp)
                        b->timestamp = ktime_get_ns();
-               ret = vb2_core_qbuf(q, index, NULL);
+               ret = vb2_core_qbuf(q, index, NULL, NULL);
                dprintk(5, "vb2_dbuf result: %d\n", ret);
                if (ret)
                        return ret;
@@ -2554,7 +2739,7 @@ static int vb2_thread(void *data)
                if (copy_timestamp)
                        vb->timestamp = ktime_get_ns();
                if (!threadio->stop)
-                       ret = vb2_core_qbuf(q, vb->index, NULL);
+                       ret = vb2_core_qbuf(q, vb->index, NULL, NULL);
                call_void_qop(q, wait_prepare, q);
                if (ret || threadio->stop)
                        break;