]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
[media] solo6x10: move global fields in solo_enc_fh to solo_enc_dev
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 18 Mar 2013 11:41:13 +0000 (08:41 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 25 Mar 2013 11:45:10 +0000 (08:45 -0300)
All fields in solo_enc_fh do not belong there since they refer to global
properties. After moving all these fields to solo_enc_dev the solo_dev_fh
struct can be removed completely.
Note that this also kills the 'listener' feature of this driver. This
feature (where multiple filehandles can read the video) is illegal in the
V4L2 API. Do this in userspace: it's much more efficient to copy memory
than it is to DMA to every listener.

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

index 830359f3bb165c334e94b244411dc16a4dc9042c..413ee10e691ee915fd5302680e745e6d601d8ef8 100644 (file)
@@ -135,6 +135,11 @@ struct solo_p2m_dev {
 
 #define OSD_TEXT_MAX           44
 
+enum solo_enc_types {
+       SOLO_ENC_TYPE_STD,
+       SOLO_ENC_TYPE_EXT,
+};
+
 struct solo_enc_dev {
        struct solo_dev *solo_dev;
        /* V4L2 Items */
@@ -163,8 +168,16 @@ struct solo_enc_dev {
        unsigned char           jpeg_header[1024];
        int                     jpeg_len;
 
-       /* File handles that are listening for buffers */
-       struct list_head        listeners;
+       u32                     fmt;
+       u8                      enc_on;
+       enum solo_enc_types     type;
+       struct videobuf_queue   vidq;
+       struct list_head        vidq_active;
+       int                     desc_count;
+       int                     desc_nelts;
+       struct solo_p2m_desc    *desc_items;
+       dma_addr_t              desc_dma;
+       spinlock_t              av_lock;
 };
 
 /* The SOLO6x10 PCI Device */
index 7cf3e7b8725f982acdb25d3fb44b4abea49e2418..546a18b31328662490c8f54df8fa803e2bf915ba 100644 (file)
 #define MP4_QS                 16
 #define DMA_ALIGN              4096
 
-enum solo_enc_types {
-       SOLO_ENC_TYPE_STD,
-       SOLO_ENC_TYPE_EXT,
-};
-
-struct solo_enc_fh {
-       struct v4l2_fh          fh;
-       struct solo_enc_dev     *enc;
-       u32                     fmt;
-       u8                      enc_on;
-       enum solo_enc_types     type;
-       struct videobuf_queue   vidq;
-       struct list_head        vidq_active;
-       int                     desc_count;
-       int                     desc_nelts;
-       struct solo_p2m_desc    *desc_items;
-       dma_addr_t              desc_dma;
-       spinlock_t              av_lock;
-       struct list_head        list;
-};
-
 struct solo_videobuf {
        struct videobuf_buffer  vb;
        unsigned int            flags;
@@ -286,16 +265,15 @@ static void solo_update_mode(struct solo_enc_dev *solo_enc)
 }
 
 /* MUST be called with solo_enc->enable_lock held */
-static int __solo_enc_on(struct solo_enc_fh *fh)
+static int __solo_enc_on(struct solo_enc_dev *solo_enc)
 {
-       struct solo_enc_dev *solo_enc = fh->enc;
        u8 ch = solo_enc->ch;
        struct solo_dev *solo_dev = solo_enc->solo_dev;
        u8 interval;
 
        BUG_ON(!mutex_is_locked(&solo_enc->enable_lock));
 
-       if (fh->enc_on)
+       if (solo_enc->enc_on)
                return 0;
 
        solo_update_mode(solo_enc);
@@ -308,15 +286,14 @@ static int __solo_enc_on(struct solo_enc_fh *fh)
                        solo_dev->enc_bw_remain -= solo_enc->bw_weight;
        }
 
-       fh->enc_on = 1;
-       list_add(&fh->list, &solo_enc->listeners);
+       solo_enc->enc_on = 1;
 
-       if (fh->type == SOLO_ENC_TYPE_EXT)
+       if (solo_enc->type == SOLO_ENC_TYPE_EXT)
                solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
 
        /* Reset the encoder if we are the first mpeg reader, else only reset
         * on the first mjpeg reader. */
-       if (fh->fmt == V4L2_PIX_FMT_MPEG) {
+       if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) {
                atomic_inc(&solo_enc->readers);
                if (atomic_inc_return(&solo_enc->mpeg_readers) > 1)
                        return 0;
@@ -352,32 +329,29 @@ static int __solo_enc_on(struct solo_enc_fh *fh)
        return 0;
 }
 
-static int solo_enc_on(struct solo_enc_fh *fh)
+static int solo_enc_on(struct solo_enc_dev *solo_enc)
 {
-       struct solo_enc_dev *solo_enc = fh->enc;
        int ret;
 
        mutex_lock(&solo_enc->enable_lock);
-       ret = __solo_enc_on(fh);
+       ret = __solo_enc_on(solo_enc);
        mutex_unlock(&solo_enc->enable_lock);
 
        return ret;
 }
 
-static void __solo_enc_off(struct solo_enc_fh *fh)
+static void __solo_enc_off(struct solo_enc_dev *solo_enc)
 {
-       struct solo_enc_dev *solo_enc = fh->enc;
        struct solo_dev *solo_dev = solo_enc->solo_dev;
 
        BUG_ON(!mutex_is_locked(&solo_enc->enable_lock));
 
-       if (!fh->enc_on)
+       if (!solo_enc->enc_on)
                return;
 
-       list_del(&fh->list);
-       fh->enc_on = 0;
+       solo_enc->enc_on = 0;
 
-       if (fh->fmt == V4L2_PIX_FMT_MPEG)
+       if (solo_enc->fmt == V4L2_PIX_FMT_MPEG)
                atomic_dec(&solo_enc->mpeg_readers);
 
        if (atomic_dec_return(&solo_enc->readers) > 0)
@@ -389,12 +363,10 @@ static void __solo_enc_off(struct solo_enc_fh *fh)
        solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
 }
 
-static void solo_enc_off(struct solo_enc_fh *fh)
+static void solo_enc_off(struct solo_enc_dev *solo_enc)
 {
-       struct solo_enc_dev *solo_enc = fh->enc;
-
        mutex_lock(&solo_enc->enable_lock);
-       __solo_enc_off(fh);
+       __solo_enc_off(solo_enc);
        mutex_unlock(&solo_enc->enable_lock);
 }
 
@@ -430,11 +402,11 @@ static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma,
 
 /* Build a descriptor queue out of an SG list and send it to the P2M for
  * processing. */
-static int solo_send_desc(struct solo_enc_fh *fh, int skip,
+static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
                          struct videobuf_dmabuf *vbuf, int off, int size,
                          unsigned int base, unsigned int base_size)
 {
-       struct solo_dev *solo_dev = fh->enc->solo_dev;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct scatterlist *sg;
        int i;
        int ret;
@@ -442,7 +414,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip,
        if (WARN_ON_ONCE(size > FRAME_BUF_SIZE))
                return -EINVAL;
 
-       fh->desc_count = 1;
+       solo_enc->desc_count = 1;
 
        for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
                struct solo_p2m_desc *desc;
@@ -450,7 +422,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip,
                int len;
                int left = base_size - off;
 
-               desc = &fh->desc_items[fh->desc_count++];
+               desc = &solo_enc->desc_items[solo_enc->desc_count++];
                dma = sg_dma_address(sg);
                len = sg_dma_len(sg);
 
@@ -486,7 +458,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip,
                        if (ret)
                                return ret;
 
-                       fh->desc_count--;
+                       solo_enc->desc_count--;
                }
 
                size -= len;
@@ -498,27 +470,26 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip,
                        off -= base_size;
 
                /* Because we may use two descriptors per loop */
-               if (fh->desc_count >= (fh->desc_nelts - 1)) {
-                       ret = solo_p2m_dma_desc(solo_dev, fh->desc_items,
-                                               fh->desc_dma,
-                                               fh->desc_count - 1);
+               if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) {
+                       ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
+                                               solo_enc->desc_dma,
+                                               solo_enc->desc_count - 1);
                        if (ret)
                                return ret;
-                       fh->desc_count = 1;
+                       solo_enc->desc_count = 1;
                }
        }
 
-       if (fh->desc_count <= 1)
+       if (solo_enc->desc_count <= 1)
                return 0;
 
-       return solo_p2m_dma_desc(solo_dev, fh->desc_items, fh->desc_dma,
-                                fh->desc_count - 1);
+       return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, solo_enc->desc_dma,
+                                solo_enc->desc_count - 1);
 }
 
-static int solo_fill_jpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb,
+static int solo_fill_jpeg(struct solo_enc_dev *solo_enc, struct videobuf_buffer *vb,
                          struct videobuf_dmabuf *vbuf, struct vop_header *vh)
 {
-       struct solo_enc_dev *solo_enc = fh->enc;
        struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct solo_videobuf *svb = (struct solo_videobuf *)vb;
        int frame_size;
@@ -539,15 +510,14 @@ static int solo_fill_jpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb,
        frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1))
                & ~(DMA_ALIGN - 1);
 
-       return solo_send_desc(fh, solo_enc->jpeg_len, vbuf, vh->jpeg_off,
+       return solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off,
                              frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
                              SOLO_JPEG_EXT_SIZE(solo_dev));
 }
 
-static int solo_fill_mpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb,
+static int solo_fill_mpeg(struct solo_enc_dev *solo_enc, struct videobuf_buffer *vb,
                          struct videobuf_dmabuf *vbuf, struct vop_header *vh)
 {
-       struct solo_enc_dev *solo_enc = fh->enc;
        struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct solo_videobuf *svb = (struct solo_videobuf *)vb;
        int frame_off, frame_size;
@@ -580,16 +550,15 @@ static int solo_fill_mpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb,
        frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1))
                & ~(DMA_ALIGN - 1);
 
-       return solo_send_desc(fh, skip, vbuf, frame_off, frame_size,
+       return solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
                              SOLO_MP4E_EXT_ADDR(solo_dev),
                              SOLO_MP4E_EXT_SIZE(solo_dev));
 }
 
-static int solo_enc_fillbuf(struct solo_enc_fh *fh,
+static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
                            struct videobuf_buffer *vb,
                            struct solo_enc_buf *enc_buf)
 {
-       struct solo_enc_dev *solo_enc = fh->enc;
        struct solo_videobuf *svb = (struct solo_videobuf *)vb;
        struct videobuf_dmabuf *vbuf = NULL;
        struct vop_header *vh = enc_buf->vh;
@@ -613,10 +582,10 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh,
                        svb->flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
        }
 
-       if (fh->fmt == V4L2_PIX_FMT_MPEG)
-               ret = solo_fill_mpeg(fh, vb, vbuf, vh);
+       if (solo_enc->fmt == V4L2_PIX_FMT_MPEG)
+               ret = solo_fill_mpeg(solo_enc, vb, vbuf, vh);
        else
-               ret = solo_fill_jpeg(fh, vb, vbuf, vh);
+               ret = solo_fill_jpeg(solo_enc, vb, vbuf, vh);
 
 vbuf_error:
        /* On error, we push this buffer back into the queue. The
@@ -625,10 +594,10 @@ vbuf_error:
        if (ret) {
                unsigned long flags;
 
-               spin_lock_irqsave(&fh->av_lock, flags);
-               list_add(&vb->queue, &fh->vidq_active);
+               spin_lock_irqsave(&solo_enc->av_lock, flags);
+               list_add(&vb->queue, &solo_enc->vidq_active);
                vb->state = VIDEOBUF_QUEUED;
-               spin_unlock_irqrestore(&fh->av_lock, flags);
+               spin_unlock_irqrestore(&solo_enc->av_lock, flags);
        } else {
                vb->state = VIDEOBUF_DONE;
                vb->field_count++;
@@ -644,34 +613,29 @@ vbuf_error:
 static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
                                struct solo_enc_buf *enc_buf)
 {
-       struct solo_enc_fh *fh;
+       struct videobuf_buffer *vb;
+       unsigned long flags;
 
        mutex_lock(&solo_enc->enable_lock);
 
-       list_for_each_entry(fh, &solo_enc->listeners, list) {
-               struct videobuf_buffer *vb;
-               unsigned long flags;
-
-               if (fh->type != enc_buf->type)
-                       continue;
-
-
-               if (list_empty(&fh->vidq_active))
-                       continue;
+       if (solo_enc->type != enc_buf->type)
+               goto unlock;
 
-               spin_lock_irqsave(&fh->av_lock, flags);
+       if (list_empty(&solo_enc->vidq_active))
+               goto unlock;
 
-               vb = list_first_entry(&fh->vidq_active,
-                                     struct videobuf_buffer, queue);
+       spin_lock_irqsave(&solo_enc->av_lock, flags);
 
-               list_del(&vb->queue);
-               vb->state = VIDEOBUF_ACTIVE;
+       vb = list_first_entry(&solo_enc->vidq_active,
+                       struct videobuf_buffer, queue);
 
-               spin_unlock_irqrestore(&fh->av_lock, flags);
+       list_del(&vb->queue);
+       vb->state = VIDEOBUF_ACTIVE;
 
-               solo_enc_fillbuf(fh, vb, enc_buf);
-       }
+       spin_unlock_irqrestore(&solo_enc->av_lock, flags);
 
+       solo_enc_fillbuf(solo_enc, vb, enc_buf);
+unlock:
        mutex_unlock(&solo_enc->enable_lock);
 }
 
@@ -799,10 +763,10 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq,
 static void solo_enc_buf_queue(struct videobuf_queue *vq,
                               struct videobuf_buffer *vb)
 {
-       struct solo_enc_fh *fh = vq->priv_data;
+       struct solo_enc_dev *solo_enc = vq->priv_data;
 
        vb->state = VIDEOBUF_QUEUED;
-       list_add_tail(&vb->queue, &fh->vidq_active);
+       list_add_tail(&vb->queue, &solo_enc->vidq_active);
 }
 
 static void solo_enc_buf_release(struct videobuf_queue *vq,
@@ -824,20 +788,20 @@ static const struct videobuf_queue_ops solo_enc_video_qops = {
 static unsigned int solo_enc_poll(struct file *file,
                                  struct poll_table_struct *wait)
 {
-       struct solo_enc_fh *fh = file->private_data;
+       struct solo_enc_dev *solo_enc = 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 videobuf_poll_stream(file, &fh->vidq, wait);
+       return videobuf_poll_stream(file, &solo_enc->vidq, wait);
 }
 
 static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct solo_enc_fh *fh = file->private_data;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
 
-       return videobuf_mmap_mapper(&fh->vidq, vma);
+       return videobuf_mmap_mapper(&solo_enc->vidq, vma);
 }
 
 static int solo_ring_start(struct solo_dev *solo_dev)
@@ -875,91 +839,50 @@ static int solo_enc_open(struct file *file)
 {
        struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct solo_enc_fh *fh;
-       int ret;
+       int ret = v4l2_fh_open(file);
 
-       ret = solo_ring_start(solo_dev);
        if (ret)
                return ret;
-
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (fh == NULL) {
-               solo_ring_stop(solo_dev);
-               return -ENOMEM;
-       }
-
-       fh->desc_nelts = 32;
-       fh->desc_items = pci_alloc_consistent(solo_dev->pdev,
-                                     sizeof(struct solo_p2m_desc) *
-                                     fh->desc_nelts, &fh->desc_dma);
-       if (fh->desc_items == NULL) {
-               kfree(fh);
-               solo_ring_stop(solo_dev);
-               return -ENOMEM;
+       ret = solo_ring_start(solo_dev);
+       if (ret) {
+               v4l2_fh_release(file);
+               return ret;
        }
-
-       v4l2_fh_init(&fh->fh, video_devdata(file));
-       fh->enc = solo_enc;
-       spin_lock_init(&fh->av_lock);
-       file->private_data = fh;
-       INIT_LIST_HEAD(&fh->vidq_active);
-       fh->fmt = V4L2_PIX_FMT_MPEG;
-       fh->type = SOLO_ENC_TYPE_STD;
-
-       videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops,
-                               &solo_dev->pdev->dev,
-                               &fh->av_lock,
-                               V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                               V4L2_FIELD_INTERLACED,
-                               sizeof(struct solo_videobuf),
-                               fh, NULL);
-       v4l2_fh_add(&fh->fh);
        return 0;
 }
 
 static ssize_t solo_enc_read(struct file *file, char __user *data,
                             size_t count, loff_t *ppos)
 {
-       struct solo_enc_fh *fh = file->private_data;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        int ret;
 
        /* Make sure the encoder is on */
-       ret = solo_enc_on(fh);
+       ret = solo_enc_on(solo_enc);
        if (ret)
                return ret;
 
-       return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+       return videobuf_read_stream(&solo_enc->vidq, data, count, ppos, 0,
                                    file->f_flags & O_NONBLOCK);
 }
 
 static int solo_enc_release(struct file *file)
 {
-       struct solo_enc_fh *fh = file->private_data;
-       struct solo_dev *solo_dev = fh->enc->solo_dev;
-
-       solo_enc_off(fh);
-       v4l2_fh_del(&fh->fh);
-       v4l2_fh_exit(&fh->fh);
-
-       videobuf_stop(&fh->vidq);
-       videobuf_mmap_free(&fh->vidq);
-
-       pci_free_consistent(fh->enc->solo_dev->pdev,
-                           sizeof(struct solo_p2m_desc) *
-                           fh->desc_nelts, fh->desc_items, fh->desc_dma);
-
-       kfree(fh);
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
 
+       solo_enc_off(solo_enc);
+       videobuf_stop(&solo_enc->vidq);
+       videobuf_mmap_free(&solo_enc->vidq);
        solo_ring_stop(solo_dev);
 
-       return 0;
+       return v4l2_fh_release(file);
 }
 
 static int solo_enc_querycap(struct file *file, void  *priv,
                             struct v4l2_capability *cap)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_dev *solo_dev = solo_enc->solo_dev;
 
        strcpy(cap->driver, SOLO6X10_NAME);
@@ -976,8 +899,7 @@ static int solo_enc_querycap(struct file *file, void  *priv,
 static int solo_enc_enum_input(struct file *file, void *priv,
                               struct v4l2_input *input)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_dev *solo_dev = solo_enc->solo_dev;
 
        if (input->index)
@@ -1039,8 +961,7 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
 static int solo_enc_try_fmt_cap(struct file *file, void *priv,
                            struct v4l2_format *f)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct v4l2_pix_format *pix = &f->fmt.pix;
 
@@ -1081,8 +1002,7 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv,
 static int solo_enc_set_fmt_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        int ret;
@@ -1110,10 +1030,10 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv,
                solo_enc->mode = SOLO_ENC_MODE_CIF;
 
        /* This does not change the encoder at all */
-       fh->fmt = pix->pixelformat;
+       solo_enc->fmt = pix->pixelformat;
 
        if (pix->priv)
-               fh->type = SOLO_ENC_TYPE_EXT;
+               solo_enc->type = SOLO_ENC_TYPE_EXT;
 
        mutex_unlock(&solo_enc->enable_lock);
 
@@ -1123,13 +1043,12 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv,
 static int solo_enc_get_fmt_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct v4l2_pix_format *pix = &f->fmt.pix;
 
        pix->width = solo_enc->width;
        pix->height = solo_enc->height;
-       pix->pixelformat = fh->fmt;
+       pix->pixelformat = solo_enc->fmt;
        pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
                     V4L2_FIELD_NONE;
        pix->sizeimage = FRAME_BUF_SIZE;
@@ -1142,45 +1061,45 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv,
 static int solo_enc_reqbufs(struct file *file, void *priv,
                            struct v4l2_requestbuffers *req)
 {
-       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
 
-       return videobuf_reqbufs(&fh->vidq, req);
+       return videobuf_reqbufs(&solo_enc->vidq, req);
 }
 
 static int solo_enc_querybuf(struct file *file, void *priv,
                             struct v4l2_buffer *buf)
 {
-       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
 
-       return videobuf_querybuf(&fh->vidq, buf);
+       return videobuf_querybuf(&solo_enc->vidq, buf);
 }
 
 static int solo_enc_qbuf(struct file *file, void *priv,
                         struct v4l2_buffer *buf)
 {
-       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
 
-       return videobuf_qbuf(&fh->vidq, buf);
+       return videobuf_qbuf(&solo_enc->vidq, buf);
 }
 
 static int solo_enc_dqbuf(struct file *file, void *priv,
                          struct v4l2_buffer *buf)
 {
-       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_videobuf *svb;
        int ret;
 
        /* Make sure the encoder is on */
-       ret = solo_enc_on(fh);
+       ret = solo_enc_on(solo_enc);
        if (ret)
                return ret;
 
-       ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
+       ret = videobuf_dqbuf(&solo_enc->vidq, buf, file->f_flags & O_NONBLOCK);
        if (ret)
                return ret;
 
        /* Copy over the flags */
-       svb = (struct solo_videobuf *)fh->vidq.bufs[buf->index];
+       svb = (struct solo_videobuf *)solo_enc->vidq.bufs[buf->index];
        buf->flags |= svb->flags;
 
        return 0;
@@ -1189,26 +1108,26 @@ static int solo_enc_dqbuf(struct file *file, void *priv,
 static int solo_enc_streamon(struct file *file, void *priv,
                             enum v4l2_buf_type i)
 {
-       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
 
        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       return videobuf_streamon(&fh->vidq);
+       return videobuf_streamon(&solo_enc->vidq);
 }
 
 static int solo_enc_streamoff(struct file *file, void *priv,
                              enum v4l2_buf_type i)
 {
-       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        int ret;
 
        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       ret = videobuf_streamoff(&fh->vidq);
+       ret = videobuf_streamoff(&solo_enc->vidq);
        if (!ret)
-               solo_enc_off(fh);
+               solo_enc_off(solo_enc);
 
        return ret;
 }
@@ -1221,8 +1140,8 @@ static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i)
 static int solo_enum_framesizes(struct file *file, void *priv,
                                struct v4l2_frmsizeenum *fsize)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_dev *solo_dev = fh->enc->solo_dev;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
 
        if (fsize->pixel_format != V4L2_PIX_FMT_MPEG &&
            fsize->pixel_format != V4L2_PIX_FMT_MJPEG)
@@ -1249,8 +1168,8 @@ static int solo_enum_framesizes(struct file *file, void *priv,
 static int solo_enum_frameintervals(struct file *file, void *priv,
                                    struct v4l2_frmivalenum *fintv)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_dev *solo_dev = fh->enc->solo_dev;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
 
        if (fintv->pixel_format != V4L2_PIX_FMT_MPEG &&
            fintv->pixel_format != V4L2_PIX_FMT_MJPEG)
@@ -1280,8 +1199,7 @@ static int solo_enum_frameintervals(struct file *file, void *priv,
 static int solo_g_parm(struct file *file, void *priv,
                       struct v4l2_streamparm *sp)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct v4l2_captureparm *cp = &sp->parm.capture;
 
@@ -1298,8 +1216,7 @@ static int solo_g_parm(struct file *file, void *priv,
 static int solo_s_parm(struct file *file, void *priv,
                       struct v4l2_streamparm *sp)
 {
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
        struct solo_dev *solo_dev = solo_enc->solo_dev;
        struct v4l2_captureparm *cp = &sp->parm.capture;
 
@@ -1512,45 +1429,17 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
        v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
        if (hdl->error) {
                ret = hdl->error;
-               v4l2_ctrl_handler_free(hdl);
-               kfree(solo_enc);
-               return ERR_PTR(ret);
-       }
-
-       solo_enc->vfd = video_device_alloc();
-       if (!solo_enc->vfd) {
-               v4l2_ctrl_handler_free(hdl);
-               kfree(solo_enc);
-               return ERR_PTR(-ENOMEM);
+               goto hdl_free;
        }
 
        solo_enc->solo_dev = solo_dev;
        solo_enc->ch = ch;
-
-       *solo_enc->vfd = solo_enc_template;
-       solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
-       solo_enc->vfd->ctrl_handler = hdl;
-       set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags);
-       ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
-       if (ret < 0) {
-               video_device_release(solo_enc->vfd);
-               v4l2_ctrl_handler_free(hdl);
-               kfree(solo_enc);
-               return ERR_PTR(ret);
-       }
-
-       video_set_drvdata(solo_enc->vfd, solo_enc);
-
-       snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
-                "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
-                solo_enc->vfd->num);
-
-       INIT_LIST_HEAD(&solo_enc->listeners);
-       mutex_init(&solo_enc->enable_lock);
-       spin_lock_init(&solo_enc->motion_lock);
+       spin_lock_init(&solo_enc->av_lock);
+       INIT_LIST_HEAD(&solo_enc->vidq_active);
+       solo_enc->fmt = V4L2_PIX_FMT_MPEG;
+       solo_enc->type = SOLO_ENC_TYPE_STD;
 
        atomic_set(&solo_enc->readers, 0);
-       atomic_set(&solo_enc->mpeg_readers, 0);
 
        solo_enc->qp = SOLO_DEFAULT_QP;
        solo_enc->gop = solo_dev->fps;
@@ -1558,15 +1447,65 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
        solo_enc->mode = SOLO_ENC_MODE_CIF;
        solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
 
-       mutex_lock(&solo_enc->enable_lock);
+       spin_lock(&solo_enc->av_lock);
        solo_update_mode(solo_enc);
-       mutex_unlock(&solo_enc->enable_lock);
+       spin_unlock(&solo_enc->av_lock);
+
+       mutex_init(&solo_enc->enable_lock);
+       spin_lock_init(&solo_enc->motion_lock);
+
+       atomic_set(&solo_enc->readers, 0);
+       atomic_set(&solo_enc->mpeg_readers, 0);
 
        /* Initialize this per encoder */
        solo_enc->jpeg_len = sizeof(jpeg_header);
        memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
 
+       solo_enc->desc_nelts = 32;
+       solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
+                                     sizeof(struct solo_p2m_desc) *
+                                     solo_enc->desc_nelts, &solo_enc->desc_dma);
+       ret = -ENOMEM;
+       if (solo_enc->desc_items == NULL)
+               goto hdl_free;
+
+       videobuf_queue_sg_init(&solo_enc->vidq, &solo_enc_video_qops,
+                               &solo_dev->pdev->dev,
+                               &solo_enc->av_lock,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                               V4L2_FIELD_INTERLACED,
+                               sizeof(struct solo_videobuf),
+                               solo_enc, NULL);
+
+       solo_enc->vfd = video_device_alloc();
+       if (!solo_enc->vfd)
+               goto pci_free;
+
+       *solo_enc->vfd = solo_enc_template;
+       solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
+       solo_enc->vfd->ctrl_handler = hdl;
+       set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags);
+       video_set_drvdata(solo_enc->vfd, solo_enc);
+       ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
+       if (ret < 0)
+               goto vdev_release;
+
+       snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
+                "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
+                solo_enc->vfd->num);
+
        return solo_enc;
+
+vdev_release:
+       video_device_release(solo_enc->vfd);
+pci_free:
+       pci_free_consistent(solo_enc->solo_dev->pdev,
+                       sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
+                       solo_enc->desc_items, solo_enc->desc_dma);
+hdl_free:
+       v4l2_ctrl_handler_free(hdl);
+       kfree(solo_enc);
+       return ERR_PTR(ret);
 }
 
 static void solo_enc_free(struct solo_enc_dev *solo_enc)
@@ -1605,6 +1544,7 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
                        solo_enc_free(solo_dev->v4l2_enc[i]);
                pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
                                    solo_dev->vh_buf, solo_dev->vh_dma);
+               solo_dev->vh_buf = NULL;
                return ret;
        }
 
@@ -1627,6 +1567,7 @@ void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
        for (i = 0; i < solo_dev->nr_chans; i++)
                solo_enc_free(solo_dev->v4l2_enc[i]);
 
-       pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
+       if (solo_dev->vh_buf)
+               pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
                            solo_dev->vh_buf, solo_dev->vh_dma);
 }