diff options
Diffstat (limited to 'drivers/media/video/ivtv')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.h | 9 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-fileops.c | 3 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-irq.c | 5 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-queue.c | 54 |
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 { | |||
437 | struct ivtv_buffer { | 437 | struct 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 | ||
89 | static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, | 90 | static 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); |