|
@@ -41,27 +41,6 @@
|
|
|
#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);
|
|
|
}
|