aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2007-07-28 11:07:12 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:05:32 -0400
commitf4071b85ea0ca3bd06f63c330562b4cfdffa8473 (patch)
tree8390a1bb512949e9520f65de160e1e7291a4c36f /drivers/media/video/ivtv
parent3562c43be8cfd6e300508d7c33acebf3369eacd3 (diff)
V4L/DVB (6046): ivtv: always steal full frames if out of buffers.
When there are no more free buffers, then buffers are stolen from the predma queue. Buffers should be stolen from the head of that queue (which is where the most recently added buffers are) and all buffers belonging to a frame should be stolen. Otherwise 'half-frames' would remain in the queue, which leads to ugly playback and complete sync failure for YUV buffers. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/ivtv')
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h9
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c3
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c5
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c54
4 files changed, 45 insertions, 26 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 0a1c16ad10bb..f5de2fd01b1a 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -356,7 +356,7 @@ struct ivtv_mailbox_data {
356}; 356};
357 357
358/* per-buffer bit flags */ 358/* per-buffer bit flags */
359#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ 359#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */
360 360
361/* per-stream, s_flags */ 361/* per-stream, s_flags */
362#define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ 362#define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */
@@ -437,7 +437,8 @@ struct ivtv_dma_page_info {
437struct ivtv_buffer { 437struct ivtv_buffer {
438 struct list_head list; 438 struct list_head list;
439 dma_addr_t dma_handle; 439 dma_addr_t dma_handle;
440 unsigned long b_flags; 440 unsigned short b_flags;
441 unsigned short dma_xfer_cnt;
441 char *buf; 442 char *buf;
442 443
443 u32 bytesused; 444 u32 bytesused;
@@ -487,6 +488,10 @@ struct ivtv_stream {
487 struct ivtv_queue q_dma; /* waiting for DMA */ 488 struct ivtv_queue q_dma; /* waiting for DMA */
488 struct ivtv_queue q_predma; /* waiting for DMA */ 489 struct ivtv_queue q_predma; /* waiting for DMA */
489 490
491 /* DMA xfer counter, buffers belonging to the same DMA
492 xfer will have the same dma_xfer_cnt. */
493 u16 dma_xfer_cnt;
494
490 /* Base Dev SG Array for cx23415/6 */ 495 /* Base Dev SG Array for cx23415/6 */
491 struct ivtv_SG_element *SGarray; 496 struct ivtv_SG_element *SGarray;
492 struct ivtv_SG_element *PIOarray; 497 struct ivtv_SG_element *PIOarray;
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 908e640c274d..076b0089a2b0 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -247,8 +247,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
247 /* do we have new data? */ 247 /* do we have new data? */
248 buf = ivtv_dequeue(s, &s->q_full); 248 buf = ivtv_dequeue(s, &s->q_full);
249 if (buf) { 249 if (buf) {
250 if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) 250 if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0)
251 return buf; 251 return buf;
252 buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP;
252 if (s->type == IVTV_ENC_STREAM_TYPE_MPG) 253 if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
253 /* byteswap MPG data */ 254 /* byteswap MPG data */
254 ivtv_buf_swap(buf); 255 ivtv_buf_swap(buf);
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index a97d55fd2277..8644f3dda31e 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -214,6 +214,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
214 s->SGarray[idx].src = cpu_to_le32(offset); 214 s->SGarray[idx].src = cpu_to_le32(offset);
215 s->SGarray[idx].size = cpu_to_le32(s->buf_size); 215 s->SGarray[idx].size = cpu_to_le32(s->buf_size);
216 buf->bytesused = (size < s->buf_size) ? size : s->buf_size; 216 buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
217 buf->dma_xfer_cnt = s->dma_xfer_cnt;
217 218
218 s->q_predma.bytesused += buf->bytesused; 219 s->q_predma.bytesused += buf->bytesused;
219 size -= buf->bytesused; 220 size -= buf->bytesused;
@@ -286,7 +287,7 @@ static void dma_post(struct ivtv_stream *s)
286 /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ 287 /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
287 if (s->type == IVTV_ENC_STREAM_TYPE_MPG || 288 if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
288 s->type == IVTV_ENC_STREAM_TYPE_VBI) 289 s->type == IVTV_ENC_STREAM_TYPE_VBI)
289 set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); 290 buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
290 } 291 }
291 if (buf) 292 if (buf)
292 buf->bytesused += s->dma_last_offset; 293 buf->bytesused += s->dma_last_offset;
@@ -396,12 +397,14 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
396 } 397 }
397 itv->vbi.dma_offset = s_vbi->dma_offset; 398 itv->vbi.dma_offset = s_vbi->dma_offset;
398 s_vbi->SG_length = 0; 399 s_vbi->SG_length = 0;
400 s_vbi->dma_xfer_cnt++;
399 set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); 401 set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
400 IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); 402 IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
401 } 403 }
402 404
403 /* Mark last buffer size for Interrupt flag */ 405 /* Mark last buffer size for Interrupt flag */
404 s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); 406 s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
407 s->dma_xfer_cnt++;
405 408
406 if (s->type == IVTV_ENC_STREAM_TYPE_VBI) 409 if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
407 set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); 410 set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index a04f9387f63d..bff75aeee0a0 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -60,6 +60,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu
60 buf->bytesused = 0; 60 buf->bytesused = 0;
61 buf->readpos = 0; 61 buf->readpos = 0;
62 buf->b_flags = 0; 62 buf->b_flags = 0;
63 buf->dma_xfer_cnt = 0;
63 } 64 }
64 spin_lock_irqsave(&s->qlock, flags); 65 spin_lock_irqsave(&s->qlock, flags);
65 list_add_tail(&buf->list, &q->list); 66 list_add_tail(&buf->list, &q->list);
@@ -87,7 +88,7 @@ struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
87} 88}
88 89
89static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, 90static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
90 struct ivtv_queue *to, int clear, int full) 91 struct ivtv_queue *to, int clear)
91{ 92{
92 struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); 93 struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
93 94
@@ -97,13 +98,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
97 from->bytesused -= buf->bytesused - buf->readpos; 98 from->bytesused -= buf->bytesused - buf->readpos;
98 /* special handling for q_free */ 99 /* special handling for q_free */
99 if (clear) 100 if (clear)
100 buf->bytesused = buf->readpos = buf->b_flags = 0; 101 buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
101 else if (full) {
102 /* special handling for stolen buffers, assume
103 all bytes are used. */
104 buf->bytesused = s->buf_size;
105 buf->readpos = buf->b_flags = 0;
106 }
107 to->buffers++; 102 to->buffers++;
108 to->length += s->buf_size; 103 to->length += s->buf_size;
109 to->bytesused += buf->bytesused - buf->readpos; 104 to->bytesused += buf->bytesused - buf->readpos;
@@ -112,7 +107,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
112/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. 107/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
113 If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. 108 If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
114 If 'steal' != NULL, then buffers may also taken from that queue if 109 If 'steal' != NULL, then buffers may also taken from that queue if
115 needed. 110 needed, but only if 'from' is the free queue.
116 111
117 The buffer is automatically cleared if it goes to the free queue. It is 112 The buffer is automatically cleared if it goes to the free queue. It is
118 also cleared if buffers need to be taken from the 'steal' queue and 113 also cleared if buffers need to be taken from the 'steal' queue and
@@ -133,7 +128,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_
133 int rc = 0; 128 int rc = 0;
134 int from_free = from == &s->q_free; 129 int from_free = from == &s->q_free;
135 int to_free = to == &s->q_free; 130 int to_free = to == &s->q_free;
136 int bytes_available; 131 int bytes_available, bytes_steal;
137 132
138 spin_lock_irqsave(&s->qlock, flags); 133 spin_lock_irqsave(&s->qlock, flags);
139 if (needed_bytes == 0) { 134 if (needed_bytes == 0) {
@@ -142,32 +137,47 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_
142 } 137 }
143 138
144 bytes_available = from_free ? from->length : from->bytesused; 139 bytes_available = from_free ? from->length : from->bytesused;
145 bytes_available += steal ? steal->length : 0; 140 bytes_steal = (from_free && steal) ? steal->length : 0;
146 141
147 if (bytes_available < needed_bytes) { 142 if (bytes_available + bytes_steal < needed_bytes) {
148 spin_unlock_irqrestore(&s->qlock, flags); 143 spin_unlock_irqrestore(&s->qlock, flags);
149 return -ENOMEM; 144 return -ENOMEM;
150 } 145 }
146 while (bytes_available < needed_bytes) {
147 struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
148 u16 dma_xfer_cnt = buf->dma_xfer_cnt;
149
150 /* move buffers from the tail of the 'steal' queue to the tail of the
151 'from' queue. Always copy all the buffers with the same dma_xfer_cnt
152 value, this ensures that you do not end up with partial frame data
153 if one frame is stored in multiple buffers. */
154 while (dma_xfer_cnt == buf->dma_xfer_cnt) {
155 list_move_tail(steal->list.prev, &from->list);
156 rc++;
157 steal->buffers--;
158 steal->length -= s->buf_size;
159 steal->bytesused -= buf->bytesused - buf->readpos;
160 buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
161 from->buffers++;
162 from->length += s->buf_size;
163 bytes_available += s->buf_size;
164 if (list_empty(&steal->list))
165 break;
166 buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
167 }
168 }
151 if (from_free) { 169 if (from_free) {
152 u32 old_length = to->length; 170 u32 old_length = to->length;
153 171
154 while (to->length - old_length < needed_bytes) { 172 while (to->length - old_length < needed_bytes) {
155 if (list_empty(&from->list)) 173 ivtv_queue_move_buf(s, from, to, 1);
156 from = steal;
157 if (from == steal)
158 rc++; /* keep track of 'stolen' buffers */
159 ivtv_queue_move_buf(s, from, to, 1, 0);
160 } 174 }
161 } 175 }
162 else { 176 else {
163 u32 old_bytesused = to->bytesused; 177 u32 old_bytesused = to->bytesused;
164 178
165 while (to->bytesused - old_bytesused < needed_bytes) { 179 while (to->bytesused - old_bytesused < needed_bytes) {
166 if (list_empty(&from->list)) 180 ivtv_queue_move_buf(s, from, to, to_free);
167 from = steal;
168 if (from == steal)
169 rc++; /* keep track of 'stolen' buffers */
170 ivtv_queue_move_buf(s, from, to, to_free, rc);
171 } 181 }
172 } 182 }
173 spin_unlock_irqrestore(&s->qlock, flags); 183 spin_unlock_irqrestore(&s->qlock, flags);