[media] solo6x10: convert the display node to vb2
authorHans Verkuil <hans.verkuil@cisco.com>
Fri, 15 Mar 2013 15:11:17 +0000 (12:11 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 25 Mar 2013 11:46:42 +0000 (08:46 -0300)
As a consequence the ioctl op has been replaced by unlocked_ioctl.
Since we are now using the core lock the locking scheme has been
simplified as well.
The main reason for converting this driver to vb2 was that the locking
scheme in v4l2.c was hopeless. It was easier to just convert the driver
then to try and salvage a threading and videobuf nightmare.
The videobuf2 framework is far, far superior compared to the old videobuf.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/staging/media/solo6x10/Kconfig
drivers/staging/media/solo6x10/solo6x10.h
drivers/staging/media/solo6x10/v4l2-enc.c
drivers/staging/media/solo6x10/v4l2.c

index f93b4ca..ec32776 100644 (file)
@@ -1,8 +1,8 @@
 config SOLO6X10
        tristate "Softlogic 6x10 MPEG codec cards"
        depends on PCI && VIDEO_DEV && SND && I2C
-       select VIDEOBUF_DMA_SG
        select VIDEOBUF2_DMA_SG
+       select VIDEOBUF2_DMA_CONTIG
        select SND_PCM
        ---help---
          This driver supports the Softlogic based MPEG-4 and h.264 codec
index d18093f..5181662 100644 (file)
@@ -39,7 +39,6 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
-#include <media/videobuf-core.h>
 #include <media/videobuf2-core.h>
 
 #include "registers.h"
@@ -259,8 +258,6 @@ struct solo_dev {
        /* Ring thread */
        struct task_struct      *ring_thread;
        wait_queue_head_t       ring_thread_wait;
-       atomic_t                enc_users;
-       atomic_t                disp_users;
 
        /* VOP_HEADER handling */
        void                    *vh_buf;
@@ -268,8 +265,10 @@ struct solo_dev {
        int                     vh_size;
 
        /* Buffer handling */
-       struct videobuf_queue   vidq;
+       struct vb2_queue        vidq;
+       struct vb2_alloc_ctx    *alloc_ctx;
        struct task_struct      *kthread;
+       struct mutex            lock;
        spinlock_t              slock;
        int                     old_write;
        struct list_head        vidq_active;
index d7d96ce..4dda6ec 100644 (file)
 #define MP4_QS                 16
 #define DMA_ALIGN              4096
 
-struct solo_videobuf {
-       struct videobuf_buffer  vb;
-       unsigned int            flags;
-};
-
 /* 6010 M4V */
 static unsigned char vop_6010_ntsc_d1[] = {
        0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
@@ -672,9 +667,6 @@ static void solo_enc_buf_queue(struct vb2_buffer *vb)
 
 static int solo_ring_start(struct solo_dev *solo_dev)
 {
-       if (atomic_inc_return(&solo_dev->enc_users) > 1)
-               return 0;
-
        solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
                                            SOLO6X10_NAME "_ring");
        if (IS_ERR(solo_dev->ring_thread)) {
@@ -690,9 +682,6 @@ static int solo_ring_start(struct solo_dev *solo_dev)
 
 static void solo_ring_stop(struct solo_dev *solo_dev)
 {
-       if (atomic_dec_return(&solo_dev->enc_users) > 0)
-               return;
-
        if (solo_dev->ring_thread) {
                kthread_stop(solo_dev->ring_thread);
                solo_dev->ring_thread = NULL;
@@ -1279,7 +1268,6 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
 {
        int i;
 
-       atomic_set(&solo_dev->enc_users, 0);
        init_waitqueue_head(&solo_dev->ring_thread_wait);
 
        solo_dev->vh_size = sizeof(struct vop_header);
index 13b7640..d38a8fe 100644 (file)
@@ -30,7 +30,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-event.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-dma-contig.h>
 
 #include "solo6x10.h"
 #include "tw28.h"
@@ -192,19 +192,19 @@ static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
 }
 
 static void solo_fillbuf(struct solo_dev *solo_dev,
-                        struct videobuf_buffer *vb)
+                        struct vb2_buffer *vb)
 {
        dma_addr_t vbuf;
        unsigned int fdma_addr;
        int error = -1;
        int i;
 
-       vbuf = videobuf_to_dma_contig(vb);
+       vbuf = vb2_dma_contig_plane_dma_addr(vb, 0);
        if (!vbuf)
                goto finish_buf;
 
        if (erase_off(solo_dev)) {
-               void *p = videobuf_queue_to_vaddr(&solo_dev->vidq, vb);
+               void *p = vb2_plane_vaddr(vb, 0);
                int image_size = solo_image_size(solo_dev);
                for (i = 0; i < image_size; i += 2) {
                        ((u8 *)p)[i] = 0x80;
@@ -221,19 +221,19 @@ static void solo_fillbuf(struct solo_dev *solo_dev,
        }
 
 finish_buf:
-       if (error) {
-               vb->state = VIDEOBUF_ERROR;
-       } else {
-               vb->state = VIDEOBUF_DONE;
-               vb->field_count++;
+       if (!error) {
+               vb2_set_plane_payload(vb, 0,
+                       solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
+               vb->v4l2_buf.sequence++;
+               v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
        }
 
-       wake_up(&vb->done);
+       vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
 }
 
 static void solo_thread_try(struct solo_dev *solo_dev)
 {
-       struct videobuf_buffer *vb;
+       struct solo_vb2_buf *vb;
 
        /* Only "break" from this loop if slock is held, otherwise
         * just return. */
@@ -250,19 +250,15 @@ static void solo_thread_try(struct solo_dev *solo_dev)
                if (list_empty(&solo_dev->vidq_active))
                        break;
 
-               vb = list_first_entry(&solo_dev->vidq_active, struct videobuf_buffer,
-                                     queue);
-
-               if (!waitqueue_active(&vb->done))
-                       break;
+               vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf,
+                                     list);
 
                solo_dev->old_write = cur_write;
-               list_del(&vb->queue);
-               vb->state = VIDEOBUF_ACTIVE;
+               list_del(&vb->list);
 
                spin_unlock(&solo_dev->slock);
 
-               solo_fillbuf(solo_dev, vb);
+               solo_fillbuf(solo_dev, &vb->vb);
        }
 
        assert_spin_locked(&solo_dev->slock);
@@ -294,15 +290,14 @@ static int solo_start_thread(struct solo_dev *solo_dev)
 {
        int ret = 0;
 
-       if (atomic_inc_return(&solo_dev->disp_users) == 1)
-               solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
-
        solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp");
 
        if (IS_ERR(solo_dev->kthread)) {
                ret = PTR_ERR(solo_dev->kthread);
                solo_dev->kthread = NULL;
+               return ret;
        }
+       solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
 
        return ret;
 }
@@ -312,116 +307,65 @@ static void solo_stop_thread(struct solo_dev *solo_dev)
        if (!solo_dev->kthread)
                return;
 
+       solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
        kthread_stop(solo_dev->kthread);
        solo_dev->kthread = NULL;
-
-       if (atomic_dec_return(&solo_dev->disp_users) == 0)
-               solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
 }
 
-static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
-                         unsigned int *size)
+static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+                          unsigned int *num_buffers, unsigned int *num_planes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct solo_dev *solo_dev = vq->priv_data;
+       struct solo_dev *solo_dev = vb2_get_drv_priv(q);
 
-       *size = solo_image_size(solo_dev);
+       sizes[0] = solo_image_size(solo_dev);
+       alloc_ctxs[0] = solo_dev->alloc_ctx;
+       *num_planes = 1;
 
-       if (*count < MIN_VID_BUFFERS)
-               *count = MIN_VID_BUFFERS;
+       if (*num_buffers < MIN_VID_BUFFERS)
+               *num_buffers = MIN_VID_BUFFERS;
 
        return 0;
 }
 
-static int solo_buf_prepare(struct videobuf_queue *vq,
-                           struct videobuf_buffer *vb, enum v4l2_field field)
+static int solo_start_streaming(struct vb2_queue *q, unsigned int count)
 {
-       struct solo_dev *solo_dev = vq->priv_data;
+       struct solo_dev *solo_dev = vb2_get_drv_priv(q);
 
-       vb->size = solo_image_size(solo_dev);
-       if (vb->baddr != 0 && vb->bsize < vb->size)
-               return -EINVAL;
+       return solo_start_thread(solo_dev);
+}
 
-       /* XXX: These properties only change when queue is idle */
-       vb->width  = solo_dev->video_hsize;
-       vb->height = solo_vlines(solo_dev);
-       vb->bytesperline = solo_bytesperline(solo_dev);
-       vb->field  = field;
-
-       if (vb->state == VIDEOBUF_NEEDS_INIT) {
-               int rc = videobuf_iolock(vq, vb, NULL);
-               if (rc < 0) {
-                       videobuf_dma_contig_free(vq, vb);
-                       vb->state = VIDEOBUF_NEEDS_INIT;
-                       return rc;
-               }
-       }
-       vb->state = VIDEOBUF_PREPARED;
+static int solo_stop_streaming(struct vb2_queue *q)
+{
+       struct solo_dev *solo_dev = vb2_get_drv_priv(q);
 
+       solo_stop_thread(solo_dev);
+       INIT_LIST_HEAD(&solo_dev->vidq_active);
        return 0;
 }
 
-static void solo_buf_queue(struct videobuf_queue *vq,
-                          struct videobuf_buffer *vb)
+static void solo_buf_queue(struct vb2_buffer *vb)
 {
-       struct solo_dev *solo_dev = vq->priv_data;
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct solo_dev *solo_dev = vb2_get_drv_priv(vq);
+       struct solo_vb2_buf *solo_vb =
+               container_of(vb, struct solo_vb2_buf, vb);
 
-       vb->state = VIDEOBUF_QUEUED;
-       list_add_tail(&vb->queue, &solo_dev->vidq_active);
+       spin_lock(&solo_dev->slock);
+       list_add_tail(&solo_vb->list, &solo_dev->vidq_active);
+       spin_unlock(&solo_dev->slock);
        wake_up_interruptible(&solo_dev->disp_thread_wait);
 }
 
-static void solo_buf_release(struct videobuf_queue *vq,
-                            struct videobuf_buffer *vb)
-{
-       videobuf_dma_contig_free(vq, vb);
-       vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static const struct videobuf_queue_ops solo_video_qops = {
-       .buf_setup      = solo_buf_setup,
-       .buf_prepare    = solo_buf_prepare,
+static const struct vb2_ops solo_video_qops = {
+       .queue_setup    = solo_queue_setup,
        .buf_queue      = solo_buf_queue,
-       .buf_release    = solo_buf_release,
+       .start_streaming = solo_start_streaming,
+       .stop_streaming = solo_stop_streaming,
+       .wait_prepare   = vb2_ops_wait_prepare,
+       .wait_finish    = vb2_ops_wait_finish,
 };
 
-static unsigned int solo_v4l2_poll(struct file *file,
-                                  struct poll_table_struct *wait)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-       unsigned long req_events = poll_requested_events(wait);
-       unsigned res = v4l2_ctrl_poll(file, wait);
-
-       if (!(req_events & (POLLIN | POLLRDNORM)))
-               return res;
-       return res | videobuf_poll_stream(file, &solo_dev->vidq, wait);
-}
-
-static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       return videobuf_mmap_mapper(&solo_dev->vidq, vma);
-}
-
-static ssize_t solo_v4l2_read(struct file *file, char __user *data,
-                             size_t count, loff_t *ppos)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       return videobuf_read_stream(&solo_dev->vidq, data, count, ppos, 0,
-                                   file->f_flags & O_NONBLOCK);
-}
-
-static int solo_v4l2_release(struct file *file)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       solo_stop_thread(solo_dev);
-       videobuf_stop(&solo_dev->vidq);
-       videobuf_mmap_free(&solo_dev->vidq);
-       return v4l2_fh_release(file);
-}
-
 static int solo_querycap(struct file *file, void  *priv,
                         struct v4l2_capability *cap)
 {
@@ -550,7 +494,7 @@ static int solo_set_fmt_cap(struct file *file, void *priv,
 {
        struct solo_dev *solo_dev = video_drvdata(file);
 
-       if (videobuf_queue_is_busy(&solo_dev->vidq))
+       if (vb2_is_busy(&solo_dev->vidq))
                return -EBUSY;
 
        /* For right now, if it doesn't match our running config,
@@ -576,61 +520,6 @@ static int solo_get_fmt_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int solo_reqbufs(struct file *file, void *priv,
-                       struct v4l2_requestbuffers *req)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       return videobuf_reqbufs(&solo_dev->vidq, req);
-}
-
-static int solo_querybuf(struct file *file, void *priv,
-                        struct v4l2_buffer *buf)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       return videobuf_querybuf(&solo_dev->vidq, buf);
-}
-
-static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       return videobuf_qbuf(&solo_dev->vidq, buf);
-}
-
-static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       return videobuf_dqbuf(&solo_dev->vidq, buf, file->f_flags & O_NONBLOCK);
-}
-
-static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-       int ret;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       ret = solo_start_thread(solo_dev);
-       if (ret)
-               return ret;
-
-       return videobuf_streamon(&solo_dev->vidq);
-}
-
-static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       return videobuf_streamoff(&solo_dev->vidq);
-}
-
 static int solo_s_std(struct file *file, void *priv, v4l2_std_id i)
 {
        return 0;
@@ -668,11 +557,11 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
 static const struct v4l2_file_operations solo_v4l2_fops = {
        .owner                  = THIS_MODULE,
        .open                   = v4l2_fh_open,
-       .release                = solo_v4l2_release,
-       .read                   = solo_v4l2_read,
-       .poll                   = solo_v4l2_poll,
-       .mmap                   = solo_v4l2_mmap,
-       .ioctl                  = video_ioctl2,
+       .release                = vb2_fop_release,
+       .read                   = vb2_fop_read,
+       .poll                   = vb2_fop_poll,
+       .mmap                   = vb2_fop_mmap,
+       .unlocked_ioctl         = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
@@ -688,12 +577,12 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
        .vidioc_s_fmt_vid_cap           = solo_set_fmt_cap,
        .vidioc_g_fmt_vid_cap           = solo_get_fmt_cap,
        /* Streaming I/O */
-       .vidioc_reqbufs                 = solo_reqbufs,
-       .vidioc_querybuf                = solo_querybuf,
-       .vidioc_qbuf                    = solo_qbuf,
-       .vidioc_dqbuf                   = solo_dqbuf,
-       .vidioc_streamon                = solo_streamon,
-       .vidioc_streamoff               = solo_streamoff,
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
        /* Logging and events */
        .vidioc_log_status              = v4l2_ctrl_log_status,
        .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
@@ -729,8 +618,10 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
        int ret;
        int i;
 
-       atomic_set(&solo_dev->disp_users, 0);
        init_waitqueue_head(&solo_dev->disp_thread_wait);
+       spin_lock_init(&solo_dev->slock);
+       mutex_init(&solo_dev->lock);
+       INIT_LIST_HEAD(&solo_dev->vidq_active);
 
        solo_dev->vfd = video_device_alloc();
        if (!solo_dev->vfd)
@@ -738,24 +629,37 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
 
        *solo_dev->vfd = solo_v4l2_template;
        solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev;
+       solo_dev->vfd->queue = &solo_dev->vidq;
+       solo_dev->vfd->lock = &solo_dev->lock;
        v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1);
        v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL);
-       if (solo_dev->disp_hdl.error)
-               return solo_dev->disp_hdl.error;
+       if (solo_dev->disp_hdl.error) {
+               ret = solo_dev->disp_hdl.error;
+               goto fail;
+       }
        solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
        set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags);
 
        video_set_drvdata(solo_dev->vfd, solo_dev);
 
-       spin_lock_init(&solo_dev->slock);
-       INIT_LIST_HEAD(&solo_dev->vidq_active);
-
-       videobuf_queue_dma_contig_init(&solo_dev->vidq, &solo_video_qops,
-                                      &solo_dev->pdev->dev, &solo_dev->slock,
-                                      V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                                      V4L2_FIELD_INTERLACED,
-                                      sizeof(struct videobuf_buffer),
-                                      solo_dev, NULL);
+       solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       solo_dev->vidq.ops = &solo_video_qops;
+       solo_dev->vidq.mem_ops = &vb2_dma_contig_memops;
+       solo_dev->vidq.drv_priv = solo_dev;
+       solo_dev->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       solo_dev->vidq.gfp_flags = __GFP_DMA32;
+       solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
+       solo_dev->vidq.lock = &solo_dev->lock;
+       ret = vb2_queue_init(&solo_dev->vidq);
+       if (ret < 0)
+               goto fail;
+
+       solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev);
+       if (IS_ERR(solo_dev->alloc_ctx)) {
+               dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context");
+               return PTR_ERR(solo_dev->alloc_ctx);
+       }
 
        /* Cycle all the channels and clear */
        for (i = 0; i < solo_dev->nr_chans; i++) {
@@ -770,11 +674,8 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
                /* Do nothing */;
 
        ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
-       if (ret < 0) {
-               video_device_release(solo_dev->vfd);
-               solo_dev->vfd = NULL;
-               return ret;
-       }
+       if (ret < 0)
+               goto fail;
 
        snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
                 SOLO6X10_NAME, solo_dev->vfd->num);
@@ -784,6 +685,13 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
                 solo_dev->nr_chans, solo_dev->nr_ext);
 
        return 0;
+
+fail:
+       video_device_release(solo_dev->vfd);
+       vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
+       v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
+       solo_dev->vfd = NULL;
+       return ret;
 }
 
 void solo_v4l2_exit(struct solo_dev *solo_dev)
@@ -792,6 +700,7 @@ void solo_v4l2_exit(struct solo_dev *solo_dev)
                return;
 
        video_unregister_device(solo_dev->vfd);
+       vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
        v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
        solo_dev->vfd = NULL;
 }