aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv/ivtv-queue.c
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/ivtv-queue.c
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/ivtv-queue.c')
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c54
1 files changed, 32 insertions, 22 deletions
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);