Commit a7eb931d authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 6a2e65d5
...@@ -135,6 +135,11 @@ struct solo_p2m_dev { ...@@ -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 { ...@@ -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 */ u32 fmt;
struct list_head listeners; 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 */
......
...@@ -41,27 +41,6 @@ ...@@ -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) ...@@ -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) ...@@ -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; solo_enc->enc_on = 1;
list_add(&fh->list, &solo_enc->listeners);
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) ...@@ -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); solo_enc->enc_on = 0;
fh->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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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)) { if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) {
ret = solo_p2m_dma_desc(solo_dev, fh->desc_items, ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
fh->desc_dma, solo_enc->desc_dma,
fh->desc_count - 1); 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, return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, solo_enc->desc_dma,
fh->desc_count - 1); 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, ...@@ -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, ...@@ -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, ...@@ -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) if (solo_enc->fmt == V4L2_PIX_FMT_MPEG)
ret = solo_fill_mpeg(fh, vb, vbuf, vh); 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 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh, ...@@ -625,10 +594,10 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh,
if (ret) { if (ret) {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&fh->av_lock, flags); spin_lock_irqsave(&solo_enc->av_lock, flags);
list_add(&vb->queue, &fh->vidq_active); 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 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh, ...@@ -644,34 +613,29 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh,
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) { if (solo_enc->type != enc_buf->type)
struct videobuf_buffer *vb; goto unlock;
unsigned long flags;
if (fh->type != enc_buf->type)
continue;
if (list_empty(&fh->vidq_active))
continue;
spin_lock_irqsave(&fh->av_lock, flags); if (list_empty(&solo_enc->vidq_active))
goto unlock;
vb = list_first_entry(&fh->vidq_active, spin_lock_irqsave(&solo_enc->av_lock, flags);
struct videobuf_buffer, queue);
list_del(&vb->queue); vb = list_first_entry(&solo_enc->vidq_active,
vb->state = VIDEOBUF_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, ...@@ -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 = { ...@@ -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) ...@@ -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 = v4l2_fh_open(file);
int ret;
ret = solo_ring_start(solo_dev);
if (ret) if (ret)
return ret; return ret;
ret = solo_ring_start(solo_dev);
fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (ret) {
if (fh == NULL) { v4l2_fh_release(file);
solo_ring_stop(solo_dev); return ret;
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;
} }
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_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = fh->enc->solo_dev; struct solo_dev *solo_dev = solo_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);
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 = video_drvdata(file);
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;
strcpy(cap->driver, SOLO6X10_NAME); strcpy(cap->driver, SOLO6X10_NAME);
...@@ -976,8 +899,7 @@ static int solo_enc_querycap(struct file *file, void *priv, ...@@ -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 = video_drvdata(file);
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;
if (input->index) if (input->index)
...@@ -1039,8 +961,7 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv, ...@@ -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 = video_drvdata(file);
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 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, ...@@ -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 = video_drvdata(file);
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 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, ...@@ -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, ...@@ -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 = video_drvdata(file);
struct solo_enc_dev *solo_enc = fh->enc;
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, ...@@ -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, ...@@ -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) ...@@ -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_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = fh->enc->solo_dev; 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, ...@@ -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_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = fh->enc->solo_dev; 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, ...@@ -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 = video_drvdata(file);
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 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, ...@@ -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 = video_drvdata(file);
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 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, ...@@ -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); goto hdl_free;
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);
} }
solo_enc->solo_dev = solo_dev; solo_enc->solo_dev = solo_dev;
solo_enc->ch = ch; solo_enc->ch = ch;
spin_lock_init(&solo_enc->av_lock);
*solo_enc->vfd = solo_enc_template; INIT_LIST_HEAD(&solo_enc->vidq_active);
solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; solo_enc->fmt = V4L2_PIX_FMT_MPEG;
solo_enc->vfd->ctrl_handler = hdl; solo_enc->type = SOLO_ENC_TYPE_STD;
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);
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, ...@@ -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) ...@@ -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) ...@@ -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);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment