From da0e5a7cc6dc76cf99879f3ee26a2256c67e4cde Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 27 Nov 2008 22:04:21 -0500 Subject: cx18: Eliminate q_io from stream buffer handling From: Andy Walls Eliminate q_io from stream buffer handling in anticipation of upcoming changes in buffer handling. q_io was a holdover from ivtv and it's function in cx18 was trivial and not necessary. We just push things back onto the front of q_full now, instead of maintaining a 1 buffer q_io queue. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-driver.h | 1 - linux/drivers/media/video/cx18/cx18-fileops.c | 9 ++------- linux/drivers/media/video/cx18/cx18-queue.c | 10 ++++++---- linux/drivers/media/video/cx18/cx18-queue.h | 19 +++++++++++++++++-- linux/drivers/media/video/cx18/cx18-streams.c | 1 - 5 files changed, 25 insertions(+), 15 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 94c196a91..f88d82348 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -290,7 +290,6 @@ struct cx18_stream { /* Buffer Queues */ struct cx18_queue q_free; /* free buffers */ struct cx18_queue q_full; /* full buffers */ - struct cx18_queue q_io; /* waiting for I/O */ /* DVB / Digital Transport */ struct cx18_dvb dvb; diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index 45b5f402e..b298faa59 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -233,11 +233,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, return buf; } - /* do we have leftover data? */ - buf = cx18_dequeue(s, &s->q_io); - if (buf) - return buf; - /* do we have new data? */ buf = cx18_dequeue(s, &s->q_full); if (buf) { @@ -413,7 +408,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, cx->enc_mem, 1, buf->id, s->buf_size); } else - cx18_enqueue(s, buf, &s->q_io); + cx18_push(s, buf, &s->q_full); } else if (buf->readpos == buf->bytesused) { int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; @@ -557,7 +552,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) CX18_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); - if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers)) + if (atomic_read(&s->q_full.buffers)) return POLLIN | POLLRDNORM; if (eof) return POLLHUP; diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 7b09c9a3e..fdfc83ee3 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -42,8 +42,8 @@ void cx18_queue_init(struct cx18_queue *q) q->bytesused = 0; } -void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q) +void _cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q, int to_front) { /* clear the buffer if it is going to be enqueued to the free queue */ if (q == &s->q_free) { @@ -53,7 +53,10 @@ void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, buf->skipped = 0; } mutex_lock(&s->qlock); - list_add_tail(&buf->list, &q->list); + if (to_front) + list_add(&buf->list, &q->list); /* LIFO */ + else + list_add_tail(&buf->list, &q->list); /* FIFO */ atomic_inc(&q->buffers); q->bytesused += buf->bytesused - buf->readpos; mutex_unlock(&s->qlock); @@ -159,7 +162,6 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) void cx18_flush_queues(struct cx18_stream *s) { - cx18_queue_flush(s, &s->q_io); cx18_queue_flush(s, &s->q_full); } diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h index ff50a2b7e..d184e55ce 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.h +++ b/linux/drivers/media/video/cx18/cx18-queue.h @@ -43,9 +43,24 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s, void cx18_buf_swap(struct cx18_buffer *buf); /* cx18_queue utility functions */ -void cx18_queue_init(struct cx18_queue *q); +void _cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q, int to_front); + +static inline void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q); + struct cx18_queue *q) +{ + _cx18_enqueue(s, buf, q, 0); /* FIFO */ +} + +static inline +void cx18_push(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) +{ + _cx18_enqueue(s, buf, q, 1); /* LIFO */ +} + +void cx18_queue_init(struct cx18_queue *q); struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, u32 bytesused); diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index f7a7f38d8..67d20b062 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -138,7 +138,6 @@ static void cx18_stream_init(struct cx18 *cx, int type) s->id = -1; cx18_queue_init(&s->q_free); cx18_queue_init(&s->q_full); - cx18_queue_init(&s->q_io); } static int cx18_prep_dev(struct cx18 *cx, int type) -- cgit v1.2.3 From b358f380079ca3db20d7409c3d39c2f5e80f871c Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Mon, 8 Dec 2008 21:02:45 -0500 Subject: cx18: Allow more than 63 capture buffers in rotation per stream From: Andy Walls cx18: Allow more than 63 capture buffers in rotation per stream. Implement q_busy to hold buffers the firmware has for use. q_free holds truly unused buffers in a pool. New buffers are given to the firmware as soon as the firmware returns one, if there are any to give to the firmware. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-driver.h | 3 +- linux/drivers/media/video/cx18/cx18-fileops.c | 14 ++--- linux/drivers/media/video/cx18/cx18-ioctl.c | 3 +- linux/drivers/media/video/cx18/cx18-mailbox.c | 11 +--- linux/drivers/media/video/cx18/cx18-queue.c | 56 +++++++++---------- linux/drivers/media/video/cx18/cx18-queue.h | 16 +++--- linux/drivers/media/video/cx18/cx18-streams.c | 77 ++++++++++++++++++++++----- linux/drivers/media/video/cx18/cx18-streams.h | 3 ++ 8 files changed, 113 insertions(+), 70 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index f88d82348..4d56d0719 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -289,7 +289,8 @@ struct cx18_stream { /* Buffer Queues */ struct cx18_queue q_free; /* free buffers */ - struct cx18_queue q_full; /* full buffers */ + struct cx18_queue q_busy; /* busy buffers - in use by firmware */ + struct cx18_queue q_full; /* full buffers - data for user apps */ /* DVB / Digital Transport */ struct cx18_dvb dvb; diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index b298faa59..f59525565 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -225,7 +225,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { /* byteswap and process VBI data */ /* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */ - cx18_enqueue(s_vbi, buf, &s_vbi->q_free); + cx18_stream_put_buf_fw(s_vbi, buf); } } buf = &cx->vbi.sliced_mpeg_buf; @@ -399,15 +399,9 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, tot_count - tot_written); if (buf != &cx->vbi.sliced_mpeg_buf) { - if (buf->readpos == buf->bytesused) { - cx18_buf_sync_for_device(s, buf); - cx18_enqueue(s, buf, &s->q_free); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, - s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - - cx->enc_mem, - 1, buf->id, s->buf_size); - } else + if (buf->readpos == buf->bytesused) + cx18_stream_put_buf_fw(s, buf); + else cx18_push(s, buf, &s->q_full); } else if (buf->readpos == buf->bytesused) { int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index 5d9c1146e..85a2e5a3b 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -851,8 +851,7 @@ static int cx18_log_status(struct file *file, void *fh) continue; CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, - (s->buffers - atomic_read(&s->q_free.buffers)) - * 100 / s->buffers, + atomic_read(&s->q_full.buffers) * 100 / s->buffers, (s->buffers * s->buf_size) / 1024, s->buffers); } CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index f62aee719..2f7060cc1 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -189,16 +189,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused); - cx18_buf_sync_for_device(s, buf); - cx18_enqueue(s, buf, &s->q_free); - - if (s->handle != CX18_INVALID_TASK_HANDLE && - test_bit(CX18_F_S_STREAMING, &s->s_flags)) - cx18_vapi(cx, - CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *) - &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); + cx18_stream_put_buf_fw(s, buf); } else set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); } diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index fdfc83ee3..40379d807 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -42,24 +42,32 @@ void cx18_queue_init(struct cx18_queue *q) q->bytesused = 0; } -void _cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q, int to_front) +struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q, int to_front) { - /* clear the buffer if it is going to be enqueued to the free queue */ - if (q == &s->q_free) { + /* clear the buffer if it is not to be enqueued to the full queue */ + if (q != &s->q_full) { buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; buf->skipped = 0; } + mutex_lock(&s->qlock); + + /* q_busy is restricted to 63 buffers to stay within firmware limits */ + if (q == &s->q_busy && atomic_read(&q->buffers) >= 63) + q = &s->q_free; + if (to_front) list_add(&buf->list, &q->list); /* LIFO */ else list_add_tail(&buf->list, &q->list); /* FIFO */ - atomic_inc(&q->buffers); q->bytesused += buf->bytesused - buf->readpos; + atomic_inc(&q->buffers); + mutex_unlock(&s->qlock); + return q; } struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) @@ -70,9 +78,9 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) if (!list_empty(&q->list)) { buf = list_entry(q->list.next, struct cx18_buffer, list); list_del_init(q->list.next); - atomic_dec(&q->buffers); q->bytesused -= buf->bytesused - buf->readpos; buf->skipped = 0; + atomic_dec(&q->buffers); } mutex_unlock(&s->qlock); return buf; @@ -85,28 +93,30 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, struct cx18_buffer *buf; struct cx18_buffer *ret = NULL; struct list_head *p, *t; - LIST_HEAD(r); mutex_lock(&s->qlock); - list_for_each_safe(p, t, &s->q_free.list) { + list_for_each_safe(p, t, &s->q_busy.list) { buf = list_entry(p, struct cx18_buffer, list); if (buf->id != id) { buf->skipped++; - if (buf->skipped >= atomic_read(&s->q_free.buffers)-1) { + if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) { /* buffer must have fallen out of rotation */ - atomic_dec(&s->q_free.buffers); - list_move_tail(&buf->list, &r); CX18_WARN("Skipped %s, buffer %d, %d " "times - it must have dropped out of " "rotation\n", s->name, buf->id, buf->skipped); + /* move it to q_free */ + list_move_tail(&buf->list, &s->q_free.list); + buf->bytesused = buf->readpos = buf->b_flags = + buf->skipped = 0; + atomic_dec(&s->q_busy.buffers); + atomic_inc(&s->q_free.buffers); } continue; } buf->bytesused = bytesused; - atomic_dec(&s->q_free.buffers); if (s->type == CX18_ENC_STREAM_TYPE_TS) { /* * TS doesn't use q_full, but for sweeping up lost @@ -116,28 +126,19 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, */ list_del_init(&buf->list); } else { - atomic_inc(&s->q_full.buffers); - s->q_full.bytesused += buf->bytesused; list_move_tail(&buf->list, &s->q_full.list); + s->q_full.bytesused += buf->bytesused; + atomic_inc(&s->q_full.buffers); } + atomic_dec(&s->q_busy.buffers); ret = buf; break; } - mutex_unlock(&s->qlock); - /* Put lost buffers back into firmware transfer rotation */ - while (!list_empty(&r)) { - buf = list_entry(r.next, struct cx18_buffer, list); - list_del_init(r.next); - cx18_enqueue(s, buf, &s->q_free); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); - CX18_INFO("Returning %s, buffer %d back to transfer rotation\n", - s->name, buf->id); - /* and there was much rejoicing... */ - } + /* Put more buffers into the transfer rotation from q_free, if we can */ + cx18_stream_load_fw_queue_nolock(s); + mutex_unlock(&s->qlock); return ret; } @@ -162,6 +163,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) void cx18_flush_queues(struct cx18_stream *s) { + cx18_queue_flush(s, &s->q_busy); cx18_queue_flush(s, &s->q_full); } diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h index d184e55ce..456cec3bc 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.h +++ b/linux/drivers/media/video/cx18/cx18-queue.h @@ -43,21 +43,21 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s, void cx18_buf_swap(struct cx18_buffer *buf); /* cx18_queue utility functions */ -void _cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q, int to_front); +struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q, int to_front); static inline -void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q) +struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) { - _cx18_enqueue(s, buf, q, 0); /* FIFO */ + return _cx18_enqueue(s, buf, q, 0); /* FIFO */ } static inline -void cx18_push(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q) +struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) { - _cx18_enqueue(s, buf, q, 1); /* LIFO */ + return _cx18_enqueue(s, buf, q, 1); /* LIFO */ } void cx18_queue_init(struct cx18_queue *q); diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 67d20b062..864ce1cf5 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -127,16 +127,11 @@ static void cx18_stream_init(struct cx18 *cx, int type) s->buf_size = cx->stream_buf_size[type]; if (s->buf_size) s->buffers = max_size / s->buf_size; - if (s->buffers > 63) { - /* Each stream has a maximum of 63 buffers, - ensure we do not exceed that. */ - s->buffers = 63; - s->buf_size = (max_size / s->buffers) & ~0xfff; - } mutex_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; cx18_queue_init(&s->q_free); + cx18_queue_init(&s->q_busy); cx18_queue_init(&s->q_full); } @@ -401,11 +396,61 @@ static void cx18_vbi_setup(struct cx18_stream *s) cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); } +struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + struct cx18 *cx = s->cx; + struct cx18_queue *q; + + /* Don't give it to the firmware, if we're not running a capture */ + if (s->handle == CX18_INVALID_TASK_HANDLE || + !test_bit(CX18_F_S_STREAMING, &s->s_flags)) + return cx18_enqueue(s, buf, &s->q_free); + + q = cx18_enqueue(s, buf, &s->q_busy); + if (q != &s->q_busy) + return q; /* The firmware has the max buffers it can handle */ + + cx18_buf_sync_for_device(s, buf); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + return q; +} + +/* Must hold s->qlock when calling */ +void cx18_stream_load_fw_queue_nolock(struct cx18_stream *s) +{ + struct cx18_buffer *buf; + struct cx18 *cx = s->cx; + + /* Move from q_free to q_busy notifying the firmware: 63 buf limit */ + while (s->handle != CX18_INVALID_TASK_HANDLE && + test_bit(CX18_F_S_STREAMING, &s->s_flags) && + atomic_read(&s->q_busy.buffers) < 63 && + !list_empty(&s->q_free.list)) { + + /* Move from q_free to q_busy */ + buf = list_entry(s->q_free.list.next, struct cx18_buffer, list); + list_move_tail(&buf->list, &s->q_busy.list); + buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; + atomic_dec(&s->q_free.buffers); + atomic_inc(&s->q_busy.buffers); + + /* Notify firmware */ + cx18_buf_sync_for_device(s, buf); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } +} + int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; struct list_head *p; + struct cx18_buffer *buf; int ts = 0; int captype = 0; @@ -488,16 +533,18 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); + /* Init all the cpu_mdls for this stream */ + cx18_flush_queues(s); + mutex_lock(&s->qlock); list_for_each(p, &s->q_free.list) { - struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); - + buf = list_entry(p, struct cx18_buffer, list); cx18_writel(cx, buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); } + cx18_stream_load_fw_queue_nolock(s); + mutex_unlock(&s->qlock); + /* begin_capture */ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); @@ -506,9 +553,15 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* FIXME - CX18_F_S_STREAMOFF as well? */ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); - /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */ + s->handle = CX18_INVALID_TASK_HANDLE; + if (atomic_read(&cx->tot_capturing) == 0) { + set_bit(CX18_F_I_EOS, &cx->i_flags); + cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); + } return -EINVAL; } diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h index 7218b1504..635d34b75 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.h +++ b/linux/drivers/media/video/cx18/cx18-streams.h @@ -29,6 +29,9 @@ int cx18_streams_register(struct cx18 *cx); void cx18_streams_cleanup(struct cx18 *cx, int unregister); /* Capture related */ +void cx18_stream_load_fw_queue_nolock(struct cx18_stream *s); +struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf); int cx18_start_v4l2_encode_stream(struct cx18_stream *s); int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); -- cgit v1.2.3 From c5e1c44c0f6bebacab6b4fc91acbe1c60e479523 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 7 Dec 2008 21:30:17 -0500 Subject: cx18: Add module parameters for finer control over buffer allocations From: Andy Walls cx18: Add module parameters for finer control over buffer allocations. User now has the option of setting smaller buffers to get lower latency transfers from the encoder. User can also now set the number of buffers used for a stream explicitly. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-driver.c | 154 +++++++++++++++++++++++--- linux/drivers/media/video/cx18/cx18-driver.h | 12 ++ linux/drivers/media/video/cx18/cx18-dvb.c | 4 + linux/drivers/media/video/cx18/cx18-streams.c | 21 ++-- 4 files changed, 167 insertions(+), 24 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 57fcce84b..a358bcce2 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -83,12 +83,28 @@ static char secam[] = "--"; static char ntsc[] = "-"; /* Buffers */ -static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; +static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; +static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS; static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; +static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE; +static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; +static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; +static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; +/* VBI bufsize based on standards supported by card tuner for now */ +static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; + +static int enc_ts_bufs = -1; +static int enc_mpg_bufs = -1; +static int enc_idx_bufs = -1; +static int enc_yuv_bufs = -1; +static int enc_vbi_bufs = -1; +static int enc_pcm_bufs = -1; + + static int cx18_pci_latency = 1; static int mmio_ndelay; @@ -108,12 +124,27 @@ module_param(retry_mmio, int, 0644); module_param(cx18_pci_latency, int, 0644); module_param(cx18_first_minor, int, 0644); -module_param(enc_mpg_buffers, int, 0644); module_param(enc_ts_buffers, int, 0644); +module_param(enc_mpg_buffers, int, 0644); +module_param(enc_idx_buffers, int, 0644); module_param(enc_yuv_buffers, int, 0644); module_param(enc_vbi_buffers, int, 0644); module_param(enc_pcm_buffers, int, 0644); +module_param(enc_ts_bufsize, int, 0644); +module_param(enc_mpg_bufsize, int, 0644); +module_param(enc_idx_bufsize, int, 0644); +module_param(enc_yuv_bufsize, int, 0644); +/* VBI bufsize based on standards supported by card tuner for now */ +module_param(enc_pcm_bufsize, int, 0644); + +module_param(enc_ts_bufs, int, 0644); +module_param(enc_mpg_bufs, int, 0644); +module_param(enc_idx_bufs, int, 0644); +module_param(enc_yuv_bufs, int, 0644); +module_param(enc_vbi_bufs, int, 0644); +module_param(enc_pcm_bufs, int, 0644); + MODULE_PARM_DESC(tuner, "Tuner type selection,\n" "\t\t\tsee tuner.h for values"); MODULE_PARM_DESC(radio, @@ -154,21 +185,57 @@ MODULE_PARM_DESC(retry_mmio, MODULE_PARM_DESC(mmio_ndelay, "(Deprecated) MMIO accesses are now never purposely delayed\n" "\t\t\tEffectively: 0 ns"); -MODULE_PARM_DESC(enc_mpg_buffers, - "Encoder MPG Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); MODULE_PARM_DESC(enc_ts_buffers, - "Encoder TS Buffers (in MB)\n" + "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); +MODULE_PARM_DESC(enc_ts_bufsize, + "Size of an encoder TS buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE)); +MODULE_PARM_DESC(enc_ts_bufs, + "Number of encoder TS buffers\n" + "\t\t\tDefault is computed from other enc_ts_* parameters"); +MODULE_PARM_DESC(enc_mpg_buffers, + "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); +MODULE_PARM_DESC(enc_mpg_bufsize, + "Size of an encoder MPG buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE)); +MODULE_PARM_DESC(enc_mpg_bufs, + "Number of encoder MPG buffers\n" + "\t\t\tDefault is computed from other enc_mpg_* parameters"); +MODULE_PARM_DESC(enc_idx_buffers, + "Encoder IDX buffer memory (MB). (enc_idx_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFFERS)); +MODULE_PARM_DESC(enc_idx_bufsize, + "Size of an encoder IDX buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFSIZE)); +MODULE_PARM_DESC(enc_idx_bufs, + "Number of encoder IDX buffers\n" + "\t\t\tDefault is computed from other enc_idx_* parameters"); MODULE_PARM_DESC(enc_yuv_buffers, - "Encoder YUV Buffers (in MB)\n" + "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); +MODULE_PARM_DESC(enc_yuv_bufsize, + "Size of an encoder YUV buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE)); +MODULE_PARM_DESC(enc_yuv_bufs, + "Number of encoder YUV buffers\n" + "\t\t\tDefault is computed from other enc_yuv_* parameters"); MODULE_PARM_DESC(enc_vbi_buffers, - "Encoder VBI Buffers (in MB)\n" + "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); +MODULE_PARM_DESC(enc_vbi_bufs, + "Number of encoder VBI buffers\n" + "\t\t\tDefault is computed from enc_vbi_buffers & tuner std"); MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in MB)\n" + "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); +MODULE_PARM_DESC(enc_pcm_bufsize, + "Size of an encoder PCM buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE)); +MODULE_PARM_DESC(enc_pcm_bufs, + "Number of encoder PCM buffers\n" + "\t\t\tDefault is computed from other enc_pcm_* parameters"); MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card"); @@ -361,11 +428,65 @@ static void cx18_process_options(struct cx18 *cx) { int i, j; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */ + + cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */ + + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = 0; /* computed later */ + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ + + /* Except for VBI ensure stream_buffers & stream_buf_size are valid */ + for (i = 0; i < CX18_MAX_STREAMS; i++) { + /* User said to use 0 buffers */ + if (cx->stream_buffers[i] == 0) { + cx->options.megabytes[i] = 0; + cx->stream_buf_size[i] = 0; + continue; + } + /* User said to use 0 MB total */ + if (cx->options.megabytes[i] <= 0) { + cx->options.megabytes[i] = 0; + cx->stream_buffers[i] = 0; + cx->stream_buf_size[i] = 0; + continue; + } + /* VBI is computed later or user said buffer has size 0 */ + if (cx->stream_buf_size[i] <= 0) { + if (i != CX18_ENC_STREAM_TYPE_VBI) { + cx->options.megabytes[i] = 0; + cx->stream_buffers[i] = 0; + cx->stream_buf_size[i] = 0; + } + continue; + } + if (cx->stream_buffers[i] < 0) { + cx->stream_buffers[i] = cx->options.megabytes[i] * 1024 + / cx->stream_buf_size[i]; + } else { + /* N.B. This might round down to 0 */ + cx->options.megabytes[i] = + cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024; + } + cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */ + } + cx->options.cardtype = cardtype[cx->num]; cx->options.tuner = tuner[cx->num]; cx->options.radio = radio[cx->num]; @@ -773,13 +894,18 @@ static int __devinit cx18_probe(struct pci_dev *dev, } cx->params.video_gop_size = cx->is_60hz ? 15 : 12; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000; vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; + if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0) + cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] * 1024 * 1024 + / vbi_buf_size; + else + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = + cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] * vbi_buf_size + / (1024 * 1024); + if (cx->options.radio > 0) cx->v4l2_cap |= V4L2_CAP_RADIO; diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 4d56d0719..29c296f39 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -115,6 +115,17 @@ #define CX18_DEFAULT_ENC_VBI_BUFFERS 1 #define CX18_DEFAULT_ENC_PCM_BUFFERS 1 +/* Maximum firmware DMA buffers per stream */ +#define CX18_MAX_MDLS_PER_STREAM 63 + +/* DMA buffer, default size in kB allocated */ +#define CX18_DEFAULT_ENC_TS_BUFSIZE 32 +#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 +#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32 +#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128 +/* Default VBI bufsize based on standards supported by card tuner for now */ +#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 + /* i2c stuff */ #define I2C_CLIENTS_MAX 16 @@ -408,6 +419,7 @@ struct cx18 { struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ struct cx18_options options; /* User options */ + int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */ int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ unsigned long i_flags; /* global cx18 flags */ diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index 034e09a37..bd5e6f3fd 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -217,6 +217,10 @@ int cx18_dvb_register(struct cx18_stream *stream) dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); CX18_INFO("DVB Frontend registered\n"); + CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n", + stream->dvb.dvb_adapter.num, stream->name, + stream->buffers, stream->buf_size/1024); + mutex_init(&dvb->feedlock); dvb->enabled = 1; return ret; diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 864ce1cf5..c80f361c8 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -111,7 +111,6 @@ static void cx18_stream_init(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; struct video_device *dev = s->v4l2dev; - u32 max_size = cx->options.megabytes[type] * 1024 * 1024; /* we need to keep v4l2dev, so restore it afterwards */ memset(s, 0, sizeof(*s)); @@ -124,9 +123,9 @@ static void cx18_stream_init(struct cx18 *cx, int type) s->handle = CX18_INVALID_TASK_HANDLE; s->dma = cx18_stream_info[type].dma; + s->buffers = cx->stream_buffers[type]; s->buf_size = cx->stream_buf_size[type]; - if (s->buf_size) - s->buffers = max_size / s->buf_size; + mutex_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; @@ -162,7 +161,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (cx18_stream_info[type].dma != PCI_DMA_NONE && - cx->options.megabytes[type] == 0) { + cx->stream_buffers[type] == 0) { CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); return 0; } @@ -262,8 +261,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type) switch (vfl_type) { case VFL_TYPE_GRABBER: - CX18_INFO("Registered device video%d for %s (%d MB)\n", - num, s->name, cx->options.megabytes[type]); + CX18_INFO("Registered device video%d for %s (%d x %d kB)\n", + num, s->name, cx->stream_buffers[type], + cx->stream_buf_size[type]/1024); break; case VFL_TYPE_RADIO: @@ -272,10 +272,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type) break; case VFL_TYPE_VBI: - if (cx->options.megabytes[type]) - CX18_INFO("Registered device vbi%d for %s (%d MB)\n", - num, - s->name, cx->options.megabytes[type]); + if (cx->stream_buffers[type]) + CX18_INFO("Registered device vbi%d for %s " + "(%d x %d bytes)\n", + num, s->name, cx->stream_buffers[type], + cx->stream_buf_size[type]); else CX18_INFO("Registered device vbi%d for %s\n", num, s->name); -- cgit v1.2.3 From e5df23b4a1dac3d29cb3f3713ecebbac3fd550d1 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Mon, 8 Dec 2008 21:14:46 -0500 Subject: cx18: Increment version number due to siginificant buffering changes From: Andy Walls cx18: Increment version number due to siginificant buffering changes. Now version 1.0.4 Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h index eb043d599..84c0ff13b 100644 --- a/linux/drivers/media/video/cx18/cx18-version.h +++ b/linux/drivers/media/video/cx18/cx18-version.h @@ -25,7 +25,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 #define CX18_DRIVER_VERSION_MINOR 0 -#define CX18_DRIVER_VERSION_PATCHLEVEL 3 +#define CX18_DRIVER_VERSION_PATCHLEVEL 4 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ -- cgit v1.2.3 From a00ab36aaa26baf7d88c5763300d06dc47327148 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 12 Dec 2008 13:50:27 -0500 Subject: cx18: Avoid making firmware API calls with the queue lock held From: Andy Walls cx18: Avoid making firmware API calls with the queue lock held. The source of MPEG strem corruption when not holding the queue lock was found to be that the MPEG buffer could be retrieved by the user app before it was sync'ed for the host cpu. Incoming buffers are now sync'ed before being put on q_full and releasing the queue lock. We can thus avoid the sometimes lengthy call to the firmware for CPU_DE_SET_MDL while holding the queue lock, so we can get better performance. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-mailbox.c | 15 ++++++----- linux/drivers/media/video/cx18/cx18-queue.c | 13 +++++----- linux/drivers/media/video/cx18/cx18-streams.c | 37 ++++++++++----------------- linux/drivers/media/video/cx18/cx18-streams.h | 2 +- 4 files changed, 30 insertions(+), 37 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index 2f7060cc1..eb5c31af6 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -163,7 +163,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) * it's filled in). * * cx18_queue_get buf() will detect the lost buffers - * and put them back in rotation eventually. + * and send them back to q_free for fw rotation eventually. */ if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && !(id >= s->mdl_offset && @@ -174,24 +174,27 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) break; } buf = cx18_queue_get_buf(s, id, mdl_ack->data_used); + CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); if (buf == NULL) { CX18_WARN("Could not find buf %d for stream %s\n", id, s->name); + /* Put as many buffers as possible back into fw use */ + cx18_stream_load_fw_queue(s); continue; } - cx18_buf_sync_for_cpu(s, buf); if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", buf->bytesused); - dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused); - + } + /* Put as many buffers as possible back into fw use */ + cx18_stream_load_fw_queue(s); + /* Put back TS buffer, since it was removed from all queues */ + if (s->type == CX18_ENC_STREAM_TYPE_TS) cx18_stream_put_buf_fw(s, buf); - } else - set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); } wake_up(&cx->dma_waitq); if (s->id != -1) diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 40379d807..a6b0666f0 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -117,16 +117,18 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, } buf->bytesused = bytesused; + /* Sync the buffer before we release the qlock */ + cx18_buf_sync_for_cpu(s, buf); if (s->type == CX18_ENC_STREAM_TYPE_TS) { /* - * TS doesn't use q_full, but for sweeping up lost - * buffers, we want the TS to requeue the buffer just - * before sending the MDL back to the firmware, so we - * pull it off the list here. + * TS doesn't use q_full. As we pull the buffer off of + * the queue here, the caller will have to put it back. */ list_del_init(&buf->list); } else { + /* Move buffer from q_busy to q_full */ list_move_tail(&buf->list, &s->q_full.list); + set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); s->q_full.bytesused += buf->bytesused; atomic_inc(&s->q_full.buffers); } @@ -135,9 +137,6 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, ret = buf; break; } - - /* Put more buffers into the transfer rotation from q_free, if we can */ - cx18_stream_load_fw_queue_nolock(s); mutex_unlock(&s->qlock); return ret; } diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index c80f361c8..7dc5b82f1 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -419,31 +419,22 @@ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, return q; } -/* Must hold s->qlock when calling */ -void cx18_stream_load_fw_queue_nolock(struct cx18_stream *s) +void cx18_stream_load_fw_queue(struct cx18_stream *s) { + struct cx18_queue *q; struct cx18_buffer *buf; - struct cx18 *cx = s->cx; - /* Move from q_free to q_busy notifying the firmware: 63 buf limit */ - while (s->handle != CX18_INVALID_TASK_HANDLE && - test_bit(CX18_F_S_STREAMING, &s->s_flags) && - atomic_read(&s->q_busy.buffers) < 63 && - !list_empty(&s->q_free.list)) { - - /* Move from q_free to q_busy */ - buf = list_entry(s->q_free.list.next, struct cx18_buffer, list); - list_move_tail(&buf->list, &s->q_busy.list); - buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; - atomic_dec(&s->q_free.buffers); - atomic_inc(&s->q_busy.buffers); - - /* Notify firmware */ - cx18_buf_sync_for_device(s, buf); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); - } + if (atomic_read(&s->q_free.buffers) == 0 || + atomic_read(&s->q_busy.buffers) >= 63) + return; + + /* Move from q_free to q_busy notifying the firmware, until the limit */ + do { + buf = cx18_dequeue(s, &s->q_free); + if (buf == NULL) + break; + q = cx18_stream_put_buf_fw(s, buf); + } while (atomic_read(&s->q_busy.buffers) < 63 && q == &s->q_busy); } int cx18_start_v4l2_encode_stream(struct cx18_stream *s) @@ -543,8 +534,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) &cx->scb->cpu_mdl[buf->id].paddr); cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); } - cx18_stream_load_fw_queue_nolock(s); mutex_unlock(&s->qlock); + cx18_stream_load_fw_queue(s); /* begin_capture */ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h index 635d34b75..420e0a172 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.h +++ b/linux/drivers/media/video/cx18/cx18-streams.h @@ -29,7 +29,7 @@ int cx18_streams_register(struct cx18 *cx); void cx18_streams_cleanup(struct cx18 *cx, int unregister); /* Capture related */ -void cx18_stream_load_fw_queue_nolock(struct cx18_stream *s); +void cx18_stream_load_fw_queue(struct cx18_stream *s); struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, struct cx18_buffer *buf); int cx18_start_v4l2_encode_stream(struct cx18_stream *s); -- cgit v1.2.3 From 4b1de397a8c3dfe7e1f5e1b3165b70fb0193f099 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 12 Dec 2008 14:24:04 -0500 Subject: cx18: Port fix for raw/sliced VBI mixup from ivtv and cx25840 From: Andy Walls This is a port of the fixes Hans Verkuil made for ivtv/cx25840: The service_set field was used to determine whether raw or sliced VBI was desired. This is incorrect since it is perfectly valid to select sliced VBI with a service_set of 0. Instead the driver should check on VIDIOC_S_FMT whether the type field matches the raw or sliced VBI type. Updated the cx18 driver accordingly, including an additional check in cx18_start_v4l2_encode_stream() that didn't exist in ivtv. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-av-vbi.c | 5 +++-- linux/drivers/media/video/cx18/cx18-driver.c | 2 +- linux/drivers/media/video/cx18/cx18-driver.h | 6 ++++++ linux/drivers/media/video/cx18/cx18-fileops.c | 10 ++++------ linux/drivers/media/video/cx18/cx18-ioctl.c | 11 +++++------ linux/drivers/media/video/cx18/cx18-streams.c | 6 +++--- linux/drivers/media/video/cx18/cx18-vbi.c | 2 +- 7 files changed, 23 insertions(+), 19 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c index 02fdf57bb..1527ea4f6 100644 --- a/linux/drivers/media/video/cx18/cx18-av-vbi.c +++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c @@ -141,10 +141,11 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) u8 lcr[24]; fmt = arg; - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE && + fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE) return -EINVAL; svbi = &fmt->fmt.sliced; - if (svbi->service_set == 0) { + if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { /* raw VBI */ memset(svbi, 0, sizeof(*svbi)); diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index a358bcce2..6f1654945 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -599,7 +599,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) init_waitqueue_head(&cx->dma_waitq); /* VBI */ - cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; cx->vbi.raw_size = 1456; cx->vbi.raw_decoder_line_size = 1456; diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 29c296f39..018d98f94 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -504,4 +504,10 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); /* First-open initialization: load firmware, etc. */ int cx18_init_on_first_open(struct cx18 *cx); +/* Test if the current VBI mode is raw (1) or sliced (0) */ +static inline int cx18_raw_vbi(const struct cx18 *cx) +{ + return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; +} + #endif /* CX18_DRIVER_H */ diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index f59525565..ade4c66ba 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -67,12 +67,11 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type) } s->id = id->open_id; - /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI, - CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI + /* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI (provided VBI insertion is on and sliced VBI is selected), for all other streams we're done */ if (type == CX18_ENC_STREAM_TYPE_MPG && - cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) { + cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) { vbi_type = CX18_ENC_STREAM_TYPE_VBI; } else { return 0; @@ -296,7 +295,7 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, if (len > ucount) len = ucount; if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && - cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) { + !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { const char *start = buf->buf + buf->readpos; const char *p = start + 1; const u8 *q; @@ -371,8 +370,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should arrive one-by-one, so make sure we never output more than one VBI frame at a time */ - if (s->type == CX18_ENC_STREAM_TYPE_VBI && - cx->vbi.sliced_in->service_set) + if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx)) single_frame = 1; for (;;) { diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index 85a2e5a3b..c83fcc0c5 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -284,13 +284,12 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, if (ret) return ret; - if (id->type == CX18_ENC_STREAM_TYPE_VBI && - cx->vbi.sliced_in->service_set && - atomic_read(&cx->ana_capturing) > 0) + if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) return -EBUSY; cx->vbi.sliced_in->service_set = 0; - cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); return cx18_g_fmt_vbi_cap(file, fh, fmt); } @@ -315,9 +314,9 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, if (check_service_set(vbifmt, cx->is_50hz) == 0) return -EINVAL; - if (atomic_read(&cx->ana_capturing) > 0 && - cx->vbi.sliced_in->service_set == 0) + if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) return -EBUSY; + cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); return 0; diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 7dc5b82f1..081131fab 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -340,7 +340,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) static void cx18_vbi_setup(struct cx18_stream *s) { struct cx18 *cx = s->cx; - int raw = cx->vbi.sliced_in->service_set == 0; + int raw = cx18_raw_vbi(cx); u32 data[CX2341X_MBOX_MAX_DATA]; int lines; @@ -471,8 +471,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) captype = CAPTURE_CHANNEL_TYPE_PCM; break; case CX18_ENC_STREAM_TYPE_VBI: - captype = cx->vbi.sliced_in->service_set ? - CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI; + captype = cx18_raw_vbi(cx) ? + CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; cx->vbi.frame = 0; cx->vbi.inserted_frame = 0; memset(cx->vbi.sliced_mpeg_size, diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c index 22e76ee3f..03f0e8130 100644 --- a/linux/drivers/media/video/cx18/cx18-vbi.c +++ b/linux/drivers/media/video/cx18/cx18-vbi.c @@ -160,7 +160,7 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, return; /* Raw VBI data */ - if (cx->vbi.sliced_in->service_set == 0) { + if (cx18_raw_vbi(cx)) { u8 type; cx18_buf_swap(buf); -- cgit v1.2.3 From 61a2de789c256e6a8c6c184ed07b18f06b19e1dd Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 12 Dec 2008 18:00:29 -0500 Subject: cx18: Enable raw VBI capture From: Andy Walls A combined authorship patch from Hans Verkuil and Andy Walls. Raw VBI can now be captured but requires a video capture to be in progress as well. Priority: normal Signed-off-by: Andy Walls Signed-off-by: Hans Verkuil --- linux/drivers/media/video/cx18/cx18-cards.c | 8 ++--- linux/drivers/media/video/cx18/cx18-cards.h | 5 +-- linux/drivers/media/video/cx18/cx18-driver.c | 49 +++++++++++++++++++++++---- linux/drivers/media/video/cx18/cx18-fileops.c | 4 ++- linux/drivers/media/video/cx18/cx18-streams.c | 8 ++--- linux/drivers/media/video/cx18/cx18-vbi.c | 3 ++ 6 files changed, 59 insertions(+), 18 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c index 23bd871b7..10cddba3e 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.c +++ b/linux/drivers/media/video/cx18/cx18-cards.c @@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = { static const struct cx18_card cx18_card_hvr1600_esmt = { .type = CX18_CARD_HVR_1600_ESMT, .name = "Hauppauge HVR-1600", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_muxer = CX18_HW_CS5345, @@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { static const struct cx18_card cx18_card_hvr1600_samsung = { .type = CX18_CARD_HVR_1600_SAMSUNG, .name = "Hauppauge HVR-1600 (Preproduction)", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_muxer = CX18_HW_CS5345, @@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = { static const struct cx18_card cx18_card_h900 = { .type = CX18_CARD_COMPRO_H900, .name = "Compro VideoMate H900", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_all = CX18_HW_TUNER, @@ -249,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = { static const struct cx18_card cx18_card_cnxt_raptor_pal = { .type = CX18_CARD_CNXT_RAPTOR_PAL, .name = "Conexant Raptor PAL/SECAM", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_muxer = CX18_HW_GPIO, diff --git a/linux/drivers/media/video/cx18/cx18-cards.h b/linux/drivers/media/video/cx18/cx18-cards.h index a54aae9ed..6fa7bcb42 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.h +++ b/linux/drivers/media/video/cx18/cx18-cards.h @@ -48,8 +48,9 @@ /* V4L2 capability aliases */ #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE) -/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */ + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \ + V4L2_CAP_VBI_CAPTURE) +/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */ struct cx18_card_video_input { u8 video_type; /* video input type */ diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 6f1654945..cea4735b6 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -601,13 +601,47 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) /* VBI */ cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; - cx->vbi.raw_size = 1456; - cx->vbi.raw_decoder_line_size = 1456; - cx->vbi.raw_decoder_sav_odd_field = 0x20; - cx->vbi.raw_decoder_sav_even_field = 0x60; - cx->vbi.sliced_decoder_line_size = 272; - cx->vbi.sliced_decoder_sav_odd_field = 0xB0; - cx->vbi.sliced_decoder_sav_even_field = 0xF0; + + /* + * The VBI line sizes depend on the pixel clock and the horiz rate + * + * (1/Fh)*(2*Fp) = Samples/line + * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples + * + * Sliced VBI is sent as ancillary data during horizontal blanking + * Raw VBI is sent as active video samples during vertcal blanking + * + * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line + * length of 720 pixels @ 4:2:2 sampling. Thus... + * + * For NTSC: + * + * (1/15,734 kHz) * 2 * 13.5 MHz = 1716 samples/line = + * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples + * + * For PAL: + * + * (1/15,625 kHz) * 2 * 13.5 MHz = 1728 samples/line = + * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples + * + */ + + /* CX18-AV-Core number of VBI samples output per horizontal line */ + cx->vbi.raw_decoder_line_size = 1444; /* 4 byte SAV + 2 * 720 */ + cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */ + + /* CX18-AV-Core VBI samples/line possibly rounded up */ + cx->vbi.raw_size = 1444; /* Real max size is 1444 */ + cx->vbi.sliced_size = 284; /* Real max size is 284 */ + + /* + * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode + * Task Field VerticalBlank HorizontalBlank 0 0 0 0 + */ + cx->vbi.raw_decoder_sav_odd_field = 0x20; /* V */ + cx->vbi.raw_decoder_sav_even_field = 0x60; /* FV */ + cx->vbi.sliced_decoder_sav_odd_field = 0xB0; /* T VH - actually EAV */ + cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */ return 0; } @@ -640,6 +674,7 @@ static void __devinit cx18_init_struct2(struct cx18 *cx) cx->av_state.aud_input = CX18_AV_AUDIO8; cx->av_state.audclk_freq = 48000; cx->av_state.audmode = V4L2_TUNER_MODE_LANG1; + /* FIXME - 8 is NTSC value, investigate */ cx->av_state.vbi_line_offset = 8; } diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index ade4c66ba..ef4589ef6 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -223,7 +223,9 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { /* byteswap and process VBI data */ -/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */ + cx18_process_vbi_data(cx, buf, + s_vbi->dma_pts, + s_vbi->type); cx18_stream_put_buf_fw(s_vbi, buf); } } diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 081131fab..9ed542624 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -358,8 +358,7 @@ static void cx18_vbi_setup(struct cx18_stream *s) cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); /* determine number of lines and total number of VBI bytes. - A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 - The '- 1' byte is probably an unused U or V byte. Or something... + A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720 A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal header, 42 data bytes + checksum (to be confirmed) */ if (raw) { @@ -377,14 +376,15 @@ static void cx18_vbi_setup(struct cx18_stream *s) /* Lines per field */ data[1] = (lines / 2) | ((lines / 2) << 16); /* bytes per line */ - data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + data[2] = (raw ? cx->vbi.raw_decoder_line_size + : cx->vbi.sliced_decoder_line_size); /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ data[3] = 1; /* Setup VBI for the cx25840 digitizer */ if (raw) { data[4] = 0x20602060; - data[5] = 0x30703070; + data[5] = 0x307090d0; } else { data[4] = 0xB0F0B0F0; data[5] = 0xA0E0A0E0; diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c index 03f0e8130..fb595bd54 100644 --- a/linux/drivers/media/video/cx18/cx18-vbi.c +++ b/linux/drivers/media/video/cx18/cx18-vbi.c @@ -165,6 +165,9 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, cx18_buf_swap(buf); + /* Skip 12 bytes of header that gets stuffed in */ + size -= 12; + memcpy(p, &buf->buf[12], size); type = p[3]; size = buf->bytesused = compress_raw_buf(cx, p, size); -- cgit v1.2.3