瀏覽代碼

[media] solo6x10: move global fields in solo_enc_fh to solo_enc_dev

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>
Hans Verkuil 12 年之前
父節點
當前提交
a7eb931d63
共有 2 個文件被更改,包括 175 次插入221 次删除
  1. 15 2
      drivers/staging/media/solo6x10/solo6x10.h
  2. 160 219
      drivers/staging/media/solo6x10/v4l2-enc.c

+ 15 - 2
drivers/staging/media/solo6x10/solo6x10.h

@@ -135,6 +135,11 @@ struct solo_p2m_dev {
 
 
 #define OSD_TEXT_MAX		44
 #define OSD_TEXT_MAX		44
 
 
+enum solo_enc_types {
+	SOLO_ENC_TYPE_STD,
+	SOLO_ENC_TYPE_EXT,
+};
+
 struct solo_enc_dev {
 struct solo_enc_dev {
 	struct solo_dev	*solo_dev;
 	struct solo_dev	*solo_dev;
 	/* V4L2 Items */
 	/* V4L2 Items */
@@ -163,8 +168,16 @@ struct solo_enc_dev {
 	unsigned char		jpeg_header[1024];
 	unsigned char		jpeg_header[1024];
 	int			jpeg_len;
 	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 */
 /* The SOLO6x10 PCI Device */

+ 160 - 219
drivers/staging/media/solo6x10/v4l2-enc.c

@@ -41,27 +41,6 @@
 #define MP4_QS			16
 #define MP4_QS			16
 #define DMA_ALIGN		4096
 #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 solo_videobuf {
 	struct videobuf_buffer	vb;
 	struct videobuf_buffer	vb;
 	unsigned int		flags;
 	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 */
 /* 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;
 	u8 ch = solo_enc->ch;
 	struct solo_dev *solo_dev = solo_enc->solo_dev;
 	struct solo_dev *solo_dev = solo_enc->solo_dev;
 	u8 interval;
 	u8 interval;
 
 
 	BUG_ON(!mutex_is_locked(&solo_enc->enable_lock));
 	BUG_ON(!mutex_is_locked(&solo_enc->enable_lock));
 
 
-	if (fh->enc_on)
+	if (solo_enc->enc_on)
 		return 0;
 		return 0;
 
 
 	solo_update_mode(solo_enc);
 	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;
 			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);
 		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
 	/* Reset the encoder if we are the first mpeg reader, else only reset
 	 * on the first mjpeg reader. */
 	 * 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);
 		atomic_inc(&solo_enc->readers);
 		if (atomic_inc_return(&solo_enc->mpeg_readers) > 1)
 		if (atomic_inc_return(&solo_enc->mpeg_readers) > 1)
 			return 0;
 			return 0;
@@ -352,32 +329,29 @@ static int __solo_enc_on(struct solo_enc_fh *fh)
 	return 0;
 	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;
 	int ret;
 
 
 	mutex_lock(&solo_enc->enable_lock);
 	mutex_lock(&solo_enc->enable_lock);
-	ret = __solo_enc_on(fh);
+	ret = __solo_enc_on(solo_enc);
 	mutex_unlock(&solo_enc->enable_lock);
 	mutex_unlock(&solo_enc->enable_lock);
 
 
 	return ret;
 	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;
 	struct solo_dev *solo_dev = solo_enc->solo_dev;
 
 
 	BUG_ON(!mutex_is_locked(&solo_enc->enable_lock));
 	BUG_ON(!mutex_is_locked(&solo_enc->enable_lock));
 
 
-	if (!fh->enc_on)
+	if (!solo_enc->enc_on)
 		return;
 		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);
 		atomic_dec(&solo_enc->mpeg_readers);
 
 
 	if (atomic_dec_return(&solo_enc->readers) > 0)
 	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);
 	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);
 	mutex_lock(&solo_enc->enable_lock);
-	__solo_enc_off(fh);
+	__solo_enc_off(solo_enc);
 	mutex_unlock(&solo_enc->enable_lock);
 	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
 /* Build a descriptor queue out of an SG list and send it to the P2M for
  * processing. */
  * 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,
 			  struct videobuf_dmabuf *vbuf, int off, int size,
 			  unsigned int base, unsigned int base_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;
 	struct scatterlist *sg;
 	int i;
 	int i;
 	int ret;
 	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))
 	if (WARN_ON_ONCE(size > FRAME_BUF_SIZE))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	fh->desc_count = 1;
+	solo_enc->desc_count = 1;
 
 
 	for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
 	for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
 		struct solo_p2m_desc *desc;
 		struct solo_p2m_desc *desc;
@@ -450,7 +422,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip,
 		int len;
 		int len;
 		int left = base_size - off;
 		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);
 		dma = sg_dma_address(sg);
 		len = sg_dma_len(sg);
 		len = sg_dma_len(sg);
 
 
@@ -486,7 +458,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip,
 			if (ret)
 			if (ret)
 				return ret;
 				return ret;
 
 
-			fh->desc_count--;
+			solo_enc->desc_count--;
 		}
 		}
 
 
 		size -= len;
 		size -= len;
@@ -498,27 +470,26 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip,
 			off -= base_size;
 			off -= base_size;
 
 
 		/* Because we may use two descriptors per loop */
 		/* 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)
 			if (ret)
 				return 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 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 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_dev *solo_dev = solo_enc->solo_dev;
 	struct solo_videobuf *svb = (struct solo_videobuf *)vb;
 	struct solo_videobuf *svb = (struct solo_videobuf *)vb;
 	int frame_size;
 	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))
 	frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1))
 		& ~(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),
 			      frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
 			      SOLO_JPEG_EXT_SIZE(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 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_dev *solo_dev = solo_enc->solo_dev;
 	struct solo_videobuf *svb = (struct solo_videobuf *)vb;
 	struct solo_videobuf *svb = (struct solo_videobuf *)vb;
 	int frame_off, frame_size;
 	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))
 	frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1))
 		& ~(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_ADDR(solo_dev),
 			      SOLO_MP4E_EXT_SIZE(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 videobuf_buffer *vb,
 			    struct solo_enc_buf *enc_buf)
 			    struct solo_enc_buf *enc_buf)
 {
 {
-	struct solo_enc_dev *solo_enc = fh->enc;
 	struct solo_videobuf *svb = (struct solo_videobuf *)vb;
 	struct solo_videobuf *svb = (struct solo_videobuf *)vb;
 	struct videobuf_dmabuf *vbuf = NULL;
 	struct videobuf_dmabuf *vbuf = NULL;
 	struct vop_header *vh = enc_buf->vh;
 	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;
 			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
 	else
-		ret = solo_fill_jpeg(fh, vb, vbuf, vh);
+		ret = solo_fill_jpeg(solo_enc, vb, vbuf, vh);
 
 
 vbuf_error:
 vbuf_error:
 	/* On error, we push this buffer back into the queue. The
 	/* On error, we push this buffer back into the queue. The
@@ -625,10 +594,10 @@ vbuf_error:
 	if (ret) {
 	if (ret) {
 		unsigned long flags;
 		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;
 		vb->state = VIDEOBUF_QUEUED;
-		spin_unlock_irqrestore(&fh->av_lock, flags);
+		spin_unlock_irqrestore(&solo_enc->av_lock, flags);
 	} else {
 	} else {
 		vb->state = VIDEOBUF_DONE;
 		vb->state = VIDEOBUF_DONE;
 		vb->field_count++;
 		vb->field_count++;
@@ -644,34 +613,29 @@ vbuf_error:
 static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
 static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
 				struct solo_enc_buf *enc_buf)
 				struct solo_enc_buf *enc_buf)
 {
 {
-	struct solo_enc_fh *fh;
+	struct videobuf_buffer *vb;
+	unsigned long flags;
 
 
 	mutex_lock(&solo_enc->enable_lock);
 	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);
 	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,
 static void solo_enc_buf_queue(struct videobuf_queue *vq,
 			       struct videobuf_buffer *vb)
 			       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;
 	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,
 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,
 static unsigned int solo_enc_poll(struct file *file,
 				  struct poll_table_struct *wait)
 				  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 long req_events = poll_requested_events(wait);
 	unsigned res = v4l2_ctrl_poll(file, wait);
 	unsigned res = v4l2_ctrl_poll(file, wait);
 
 
 	if (!(req_events & (POLLIN | POLLRDNORM)))
 	if (!(req_events & (POLLIN | POLLRDNORM)))
 		return res;
 		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)
 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)
 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_enc_dev *solo_enc = video_drvdata(file);
 	struct solo_dev *solo_dev = solo_enc->solo_dev;
 	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)
 	if (ret)
 		return 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;
 	return 0;
 }
 }
 
 
 static ssize_t solo_enc_read(struct file *file, char __user *data,
 static ssize_t solo_enc_read(struct file *file, char __user *data,
 			     size_t count, loff_t *ppos)
 			     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;
 	int ret;
 
 
 	/* Make sure the encoder is on */
 	/* Make sure the encoder is on */
-	ret = solo_enc_on(fh);
+	ret = solo_enc_on(solo_enc);
 	if (ret)
 	if (ret)
 		return 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);
 				    file->f_flags & O_NONBLOCK);
 }
 }
 
 
 static int solo_enc_release(struct file *file)
 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);
 	solo_ring_stop(solo_dev);
 
 
-	return 0;
+	return v4l2_fh_release(file);
 }
 }
 
 
 static int solo_enc_querycap(struct file *file, void  *priv,
 static int solo_enc_querycap(struct file *file, void  *priv,
 			     struct v4l2_capability *cap)
 			     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;
 	struct solo_dev *solo_dev = solo_enc->solo_dev;
 
 
 	strcpy(cap->driver, SOLO6X10_NAME);
 	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,
 static int solo_enc_enum_input(struct file *file, void *priv,
 			       struct v4l2_input *input)
 			       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;
 	struct solo_dev *solo_dev = solo_enc->solo_dev;
 
 
 	if (input->index)
 	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,
 static int solo_enc_try_fmt_cap(struct file *file, void *priv,
 			    struct v4l2_format *f)
 			    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 solo_dev *solo_dev = solo_enc->solo_dev;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	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,
 static int solo_enc_set_fmt_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 				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 solo_dev *solo_dev = solo_enc->solo_dev;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 	int ret;
 	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;
 		solo_enc->mode = SOLO_ENC_MODE_CIF;
 
 
 	/* This does not change the encoder at all */
 	/* This does not change the encoder at all */
-	fh->fmt = pix->pixelformat;
+	solo_enc->fmt = pix->pixelformat;
 
 
 	if (pix->priv)
 	if (pix->priv)
-		fh->type = SOLO_ENC_TYPE_EXT;
+		solo_enc->type = SOLO_ENC_TYPE_EXT;
 
 
 	mutex_unlock(&solo_enc->enable_lock);
 	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,
 static int solo_enc_get_fmt_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 				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;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
 
 
 	pix->width = solo_enc->width;
 	pix->width = solo_enc->width;
 	pix->height = solo_enc->height;
 	pix->height = solo_enc->height;
-	pix->pixelformat = fh->fmt;
+	pix->pixelformat = solo_enc->fmt;
 	pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
 	pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
 		     V4L2_FIELD_NONE;
 		     V4L2_FIELD_NONE;
 	pix->sizeimage = FRAME_BUF_SIZE;
 	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,
 static int solo_enc_reqbufs(struct file *file, void *priv,
 			    struct v4l2_requestbuffers *req)
 			    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,
 static int solo_enc_querybuf(struct file *file, void *priv,
 			     struct v4l2_buffer *buf)
 			     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,
 static int solo_enc_qbuf(struct file *file, void *priv,
 			 struct v4l2_buffer *buf)
 			 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,
 static int solo_enc_dqbuf(struct file *file, void *priv,
 			  struct v4l2_buffer *buf)
 			  struct v4l2_buffer *buf)
 {
 {
-	struct solo_enc_fh *fh = priv;
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
 	struct solo_videobuf *svb;
 	struct solo_videobuf *svb;
 	int ret;
 	int ret;
 
 
 	/* Make sure the encoder is on */
 	/* Make sure the encoder is on */
-	ret = solo_enc_on(fh);
+	ret = solo_enc_on(solo_enc);
 	if (ret)
 	if (ret)
 		return 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)
 	if (ret)
 		return ret;
 		return ret;
 
 
 	/* Copy over the flags */
 	/* 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;
 	buf->flags |= svb->flags;
 
 
 	return 0;
 	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,
 static int solo_enc_streamon(struct file *file, void *priv,
 			     enum v4l2_buf_type i)
 			     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)
 	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	return videobuf_streamon(&fh->vidq);
+	return videobuf_streamon(&solo_enc->vidq);
 }
 }
 
 
 static int solo_enc_streamoff(struct file *file, void *priv,
 static int solo_enc_streamoff(struct file *file, void *priv,
 			      enum v4l2_buf_type i)
 			      enum v4l2_buf_type i)
 {
 {
-	struct solo_enc_fh *fh = priv;
+	struct solo_enc_dev *solo_enc = video_drvdata(file);
 	int ret;
 	int ret;
 
 
 	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 	if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	ret = videobuf_streamoff(&fh->vidq);
+	ret = videobuf_streamoff(&solo_enc->vidq);
 	if (!ret)
 	if (!ret)
-		solo_enc_off(fh);
+		solo_enc_off(solo_enc);
 
 
 	return ret;
 	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,
 static int solo_enum_framesizes(struct file *file, void *priv,
 				struct v4l2_frmsizeenum *fsize)
 				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 &&
 	if (fsize->pixel_format != V4L2_PIX_FMT_MPEG &&
 	    fsize->pixel_format != V4L2_PIX_FMT_MJPEG)
 	    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,
 static int solo_enum_frameintervals(struct file *file, void *priv,
 				    struct v4l2_frmivalenum *fintv)
 				    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 &&
 	if (fintv->pixel_format != V4L2_PIX_FMT_MPEG &&
 	    fintv->pixel_format != V4L2_PIX_FMT_MJPEG)
 	    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,
 static int solo_g_parm(struct file *file, void *priv,
 		       struct v4l2_streamparm *sp)
 		       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 solo_dev *solo_dev = solo_enc->solo_dev;
 	struct v4l2_captureparm *cp = &sp->parm.capture;
 	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,
 static int solo_s_parm(struct file *file, void *priv,
 		       struct v4l2_streamparm *sp)
 		       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 solo_dev *solo_dev = solo_enc->solo_dev;
 	struct v4l2_captureparm *cp = &sp->parm.capture;
 	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);
 	v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
 	if (hdl->error) {
 	if (hdl->error) {
 		ret = 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->solo_dev = solo_dev;
 	solo_enc->ch = ch;
 	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->readers, 0);
-	atomic_set(&solo_enc->mpeg_readers, 0);
 
 
 	solo_enc->qp = SOLO_DEFAULT_QP;
 	solo_enc->qp = SOLO_DEFAULT_QP;
 	solo_enc->gop = solo_dev->fps;
 	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->mode = SOLO_ENC_MODE_CIF;
 	solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
 	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);
 	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 */
 	/* Initialize this per encoder */
 	solo_enc->jpeg_len = sizeof(jpeg_header);
 	solo_enc->jpeg_len = sizeof(jpeg_header);
 	memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
 	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;
 	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)
 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]);
 			solo_enc_free(solo_dev->v4l2_enc[i]);
 		pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
 		pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
 				    solo_dev->vh_buf, solo_dev->vh_dma);
 				    solo_dev->vh_buf, solo_dev->vh_dma);
+		solo_dev->vh_buf = NULL;
 		return ret;
 		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++)
 	for (i = 0; i < solo_dev->nr_chans; i++)
 		solo_enc_free(solo_dev->v4l2_enc[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);
 			    solo_dev->vh_buf, solo_dev->vh_dma);
 }
 }