diff options
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 6 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 45 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 128 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 3 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 58 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.h | 6 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.c | 316 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.h | 54 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 50 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.h | 10 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-vbi.c | 35 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-vbi.h | 2 |
12 files changed, 540 insertions, 173 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index e12082b8a08d..ba4c3ceffbb3 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -669,6 +669,12 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) | |||
669 | cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; | 669 | cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; |
670 | cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; | 670 | cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; |
671 | 671 | ||
672 | /* IVTV style VBI insertion into MPEG streams */ | ||
673 | INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list); | ||
674 | INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list); | ||
675 | INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list); | ||
676 | list_add(&cx->vbi.sliced_mpeg_buf.list, | ||
677 | &cx->vbi.sliced_mpeg_mdl.buf_list); | ||
672 | return 0; | 678 | return 0; |
673 | } | 679 | } |
674 | 680 | ||
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 1a899e0773d7..bed8bcc65411 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -246,8 +246,8 @@ struct cx18_options { | |||
246 | int radio; /* enable/disable radio */ | 246 | int radio; /* enable/disable radio */ |
247 | }; | 247 | }; |
248 | 248 | ||
249 | /* per-buffer bit flags */ | 249 | /* per-mdl bit flags */ |
250 | #define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ | 250 | #define CX18_F_M_NEED_SWAP 0 /* mdl buffer data must be endianess swapped */ |
251 | 251 | ||
252 | /* per-stream, s_flags */ | 252 | /* per-stream, s_flags */ |
253 | #define CX18_F_S_CLAIMED 3 /* this stream is claimed */ | 253 | #define CX18_F_S_CLAIMED 3 /* this stream is claimed */ |
@@ -274,15 +274,26 @@ struct cx18_options { | |||
274 | struct cx18_buffer { | 274 | struct cx18_buffer { |
275 | struct list_head list; | 275 | struct list_head list; |
276 | dma_addr_t dma_handle; | 276 | dma_addr_t dma_handle; |
277 | u32 id; | ||
278 | unsigned long b_flags; | ||
279 | unsigned skipped; | ||
280 | char *buf; | 277 | char *buf; |
281 | 278 | ||
282 | u32 bytesused; | 279 | u32 bytesused; |
283 | u32 readpos; | 280 | u32 readpos; |
284 | }; | 281 | }; |
285 | 282 | ||
283 | struct cx18_mdl { | ||
284 | struct list_head list; | ||
285 | u32 id; /* index into cx->scb->cpu_mdl[] of 1st cx18_mdl_ent */ | ||
286 | |||
287 | unsigned int skipped; | ||
288 | unsigned long m_flags; | ||
289 | |||
290 | struct list_head buf_list; | ||
291 | struct cx18_buffer *curr_buf; /* current buffer in list for reading */ | ||
292 | |||
293 | u32 bytesused; | ||
294 | u32 readpos; | ||
295 | }; | ||
296 | |||
286 | struct cx18_queue { | 297 | struct cx18_queue { |
287 | struct list_head list; | 298 | struct list_head list; |
288 | atomic_t depth; | 299 | atomic_t depth; |
@@ -346,14 +357,20 @@ struct cx18_stream { | |||
346 | PCI_DMA_NONE */ | 357 | PCI_DMA_NONE */ |
347 | wait_queue_head_t waitq; | 358 | wait_queue_head_t waitq; |
348 | 359 | ||
349 | /* Buffer Stats */ | 360 | /* Buffers */ |
350 | u32 buffers; | 361 | struct list_head buf_pool; /* buffers not attached to an MDL */ |
351 | u32 buf_size; | 362 | u32 buffers; /* total buffers owned by this stream */ |
363 | u32 buf_size; /* size in bytes of a single buffer */ | ||
364 | |||
365 | /* MDL sizes - all stream MDLs are the same size */ | ||
366 | u32 bufs_per_mdl; | ||
367 | u32 mdl_size; /* total bytes in all buffers in a mdl */ | ||
352 | 368 | ||
353 | /* Buffer Queues */ | 369 | /* MDL Queues */ |
354 | struct cx18_queue q_free; /* free buffers */ | 370 | struct cx18_queue q_free; /* free - in rotation, not committed */ |
355 | struct cx18_queue q_busy; /* busy buffers - in use by firmware */ | 371 | struct cx18_queue q_busy; /* busy - in use by firmware */ |
356 | struct cx18_queue q_full; /* full buffers - data for user apps */ | 372 | struct cx18_queue q_full; /* full - data for user apps */ |
373 | struct cx18_queue q_idle; /* idle - not in rotation */ | ||
357 | 374 | ||
358 | struct work_struct out_work_order; | 375 | struct work_struct out_work_order; |
359 | 376 | ||
@@ -481,10 +498,11 @@ struct vbi_info { | |||
481 | u32 inserted_frame; | 498 | u32 inserted_frame; |
482 | 499 | ||
483 | /* | 500 | /* |
484 | * A dummy driver stream transfer buffer with a copy of the next | 501 | * A dummy driver stream transfer mdl & buffer with a copy of the next |
485 | * sliced_mpeg_data[] buffer for output to userland apps. | 502 | * sliced_mpeg_data[] buffer for output to userland apps. |
486 | * Only used in cx18-fileops.c, but its state needs to persist at times. | 503 | * Only used in cx18-fileops.c, but its state needs to persist at times. |
487 | */ | 504 | */ |
505 | struct cx18_mdl sliced_mpeg_mdl; | ||
488 | struct cx18_buffer sliced_mpeg_buf; | 506 | struct cx18_buffer sliced_mpeg_buf; |
489 | }; | 507 | }; |
490 | 508 | ||
@@ -511,7 +529,6 @@ struct cx18 { | |||
511 | u8 is_60hz; | 529 | u8 is_60hz; |
512 | u8 nof_inputs; /* number of video inputs */ | 530 | u8 nof_inputs; /* number of video inputs */ |
513 | u8 nof_audio_inputs; /* number of audio inputs */ | 531 | u8 nof_audio_inputs; /* number of audio inputs */ |
514 | u16 buffer_id; /* buffer ID counter */ | ||
515 | u32 v4l2_cap; /* V4L2 capabilities of card */ | 532 | u32 v4l2_cap; /* V4L2 capabilities of card */ |
516 | u32 hw_flags; /* Hardware description of the board */ | 533 | u32 hw_flags; /* Hardware description of the board */ |
517 | unsigned int free_mdl_idx; | 534 | unsigned int free_mdl_idx; |
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index e4a3faebff46..4e278db31cc9 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -166,11 +166,12 @@ static void cx18_dualwatch(struct cx18 *cx) | |||
166 | } | 166 | } |
167 | 167 | ||
168 | 168 | ||
169 | static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err) | 169 | static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block, |
170 | int *err) | ||
170 | { | 171 | { |
171 | struct cx18 *cx = s->cx; | 172 | struct cx18 *cx = s->cx; |
172 | struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; | 173 | struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; |
173 | struct cx18_buffer *buf; | 174 | struct cx18_mdl *mdl; |
174 | DEFINE_WAIT(wait); | 175 | DEFINE_WAIT(wait); |
175 | 176 | ||
176 | *err = 0; | 177 | *err = 0; |
@@ -185,32 +186,33 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, | |||
185 | } | 186 | } |
186 | if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && | 187 | if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && |
187 | !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { | 188 | !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { |
188 | while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { | 189 | while ((mdl = cx18_dequeue(s_vbi, |
190 | &s_vbi->q_full))) { | ||
189 | /* byteswap and process VBI data */ | 191 | /* byteswap and process VBI data */ |
190 | cx18_process_vbi_data(cx, buf, | 192 | cx18_process_vbi_data(cx, mdl, |
191 | s_vbi->type); | 193 | s_vbi->type); |
192 | cx18_stream_put_buf_fw(s_vbi, buf); | 194 | cx18_stream_put_mdl_fw(s_vbi, mdl); |
193 | } | 195 | } |
194 | } | 196 | } |
195 | buf = &cx->vbi.sliced_mpeg_buf; | 197 | mdl = &cx->vbi.sliced_mpeg_mdl; |
196 | if (buf->readpos != buf->bytesused) | 198 | if (mdl->readpos != mdl->bytesused) |
197 | return buf; | 199 | return mdl; |
198 | } | 200 | } |
199 | 201 | ||
200 | /* do we have new data? */ | 202 | /* do we have new data? */ |
201 | buf = cx18_dequeue(s, &s->q_full); | 203 | mdl = cx18_dequeue(s, &s->q_full); |
202 | if (buf) { | 204 | if (mdl) { |
203 | if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP, | 205 | if (!test_and_clear_bit(CX18_F_M_NEED_SWAP, |
204 | &buf->b_flags)) | 206 | &mdl->m_flags)) |
205 | return buf; | 207 | return mdl; |
206 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) | 208 | if (s->type == CX18_ENC_STREAM_TYPE_MPG) |
207 | /* byteswap MPG data */ | 209 | /* byteswap MPG data */ |
208 | cx18_buf_swap(buf); | 210 | cx18_mdl_swap(mdl); |
209 | else { | 211 | else { |
210 | /* byteswap and process VBI data */ | 212 | /* byteswap and process VBI data */ |
211 | cx18_process_vbi_data(cx, buf, s->type); | 213 | cx18_process_vbi_data(cx, mdl, s->type); |
212 | } | 214 | } |
213 | return buf; | 215 | return mdl; |
214 | } | 216 | } |
215 | 217 | ||
216 | /* return if end of stream */ | 218 | /* return if end of stream */ |
@@ -241,21 +243,28 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, | |||
241 | } | 243 | } |
242 | } | 244 | } |
243 | 245 | ||
244 | static void cx18_setup_sliced_vbi_buf(struct cx18 *cx) | 246 | static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx) |
245 | { | 247 | { |
248 | struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl; | ||
249 | struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf; | ||
246 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; | 250 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; |
247 | 251 | ||
248 | cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx]; | 252 | buf->buf = cx->vbi.sliced_mpeg_data[idx]; |
249 | cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx]; | 253 | buf->bytesused = cx->vbi.sliced_mpeg_size[idx]; |
250 | cx->vbi.sliced_mpeg_buf.readpos = 0; | 254 | buf->readpos = 0; |
255 | |||
256 | mdl->curr_buf = NULL; | ||
257 | mdl->bytesused = cx->vbi.sliced_mpeg_size[idx]; | ||
258 | mdl->readpos = 0; | ||
251 | } | 259 | } |
252 | 260 | ||
253 | static size_t cx18_copy_buf_to_user(struct cx18_stream *s, | 261 | static size_t cx18_copy_buf_to_user(struct cx18_stream *s, |
254 | struct cx18_buffer *buf, char __user *ubuf, size_t ucount) | 262 | struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop) |
255 | { | 263 | { |
256 | struct cx18 *cx = s->cx; | 264 | struct cx18 *cx = s->cx; |
257 | size_t len = buf->bytesused - buf->readpos; | 265 | size_t len = buf->bytesused - buf->readpos; |
258 | 266 | ||
267 | *stop = false; | ||
259 | if (len > ucount) | 268 | if (len > ucount) |
260 | len = ucount; | 269 | len = ucount; |
261 | if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && | 270 | if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && |
@@ -335,7 +344,8 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, | |||
335 | /* We declare we actually found a Program Pack*/ | 344 | /* We declare we actually found a Program Pack*/ |
336 | cx->search_pack_header = 0; /* expect vid PES */ | 345 | cx->search_pack_header = 0; /* expect vid PES */ |
337 | len = (char *)q - start; | 346 | len = (char *)q - start; |
338 | cx18_setup_sliced_vbi_buf(cx); | 347 | cx18_setup_sliced_vbi_mdl(cx); |
348 | *stop = true; | ||
339 | break; | 349 | break; |
340 | } | 350 | } |
341 | } | 351 | } |
@@ -352,6 +362,60 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, | |||
352 | return len; | 362 | return len; |
353 | } | 363 | } |
354 | 364 | ||
365 | /** | ||
366 | * list_entry_is_past_end - check if a previous loop cursor is off list end | ||
367 | * @pos: the type * previously used as a loop cursor. | ||
368 | * @head: the head for your list. | ||
369 | * @member: the name of the list_struct within the struct. | ||
370 | * | ||
371 | * Check if the entry's list_head is the head of the list, thus it's not a | ||
372 | * real entry but was the loop cursor that walked past the end | ||
373 | */ | ||
374 | #define list_entry_is_past_end(pos, head, member) \ | ||
375 | (&pos->member == (head)) | ||
376 | |||
377 | static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, | ||
378 | struct cx18_mdl *mdl, char __user *ubuf, size_t ucount) | ||
379 | { | ||
380 | size_t tot_written = 0; | ||
381 | int rc; | ||
382 | bool stop = false; | ||
383 | |||
384 | if (mdl->curr_buf == NULL) | ||
385 | mdl->curr_buf = list_first_entry(&mdl->buf_list, | ||
386 | struct cx18_buffer, list); | ||
387 | |||
388 | if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { | ||
389 | /* | ||
390 | * For some reason we've exhausted the buffers, but the MDL | ||
391 | * object still said some data was unread. | ||
392 | * Fix that and bail out. | ||
393 | */ | ||
394 | mdl->readpos = mdl->bytesused; | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { | ||
399 | |||
400 | if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) | ||
401 | continue; | ||
402 | |||
403 | rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written, | ||
404 | ucount - tot_written, &stop); | ||
405 | if (rc < 0) | ||
406 | return rc; | ||
407 | mdl->readpos += rc; | ||
408 | tot_written += rc; | ||
409 | |||
410 | if (stop || /* Forced stopping point for VBI insertion */ | ||
411 | tot_written >= ucount || /* Reader request statisfied */ | ||
412 | mdl->curr_buf->readpos < mdl->curr_buf->bytesused || | ||
413 | mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ | ||
414 | break; | ||
415 | } | ||
416 | return tot_written; | ||
417 | } | ||
418 | |||
355 | static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, | 419 | static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, |
356 | size_t tot_count, int non_block) | 420 | size_t tot_count, int non_block) |
357 | { | 421 | { |
@@ -373,12 +437,12 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, | |||
373 | single_frame = 1; | 437 | single_frame = 1; |
374 | 438 | ||
375 | for (;;) { | 439 | for (;;) { |
376 | struct cx18_buffer *buf; | 440 | struct cx18_mdl *mdl; |
377 | int rc; | 441 | int rc; |
378 | 442 | ||
379 | buf = cx18_get_buffer(s, non_block, &rc); | 443 | mdl = cx18_get_mdl(s, non_block, &rc); |
380 | /* if there is no data available... */ | 444 | /* if there is no data available... */ |
381 | if (buf == NULL) { | 445 | if (mdl == NULL) { |
382 | /* if we got data, then return that regardless */ | 446 | /* if we got data, then return that regardless */ |
383 | if (tot_written) | 447 | if (tot_written) |
384 | break; | 448 | break; |
@@ -392,20 +456,20 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, | |||
392 | return rc; | 456 | return rc; |
393 | } | 457 | } |
394 | 458 | ||
395 | rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written, | 459 | rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written, |
396 | tot_count - tot_written); | 460 | tot_count - tot_written); |
397 | 461 | ||
398 | if (buf != &cx->vbi.sliced_mpeg_buf) { | 462 | if (mdl != &cx->vbi.sliced_mpeg_mdl) { |
399 | if (buf->readpos == buf->bytesused) | 463 | if (mdl->readpos == mdl->bytesused) |
400 | cx18_stream_put_buf_fw(s, buf); | 464 | cx18_stream_put_mdl_fw(s, mdl); |
401 | else | 465 | else |
402 | cx18_push(s, buf, &s->q_full); | 466 | cx18_push(s, mdl, &s->q_full); |
403 | } else if (buf->readpos == buf->bytesused) { | 467 | } else if (mdl->readpos == mdl->bytesused) { |
404 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; | 468 | int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; |
405 | 469 | ||
406 | cx->vbi.sliced_mpeg_size[idx] = 0; | 470 | cx->vbi.sliced_mpeg_size[idx] = 0; |
407 | cx->vbi.inserted_frame++; | 471 | cx->vbi.inserted_frame++; |
408 | cx->vbi_data_inserted += buf->bytesused; | 472 | cx->vbi_data_inserted += mdl->bytesused; |
409 | } | 473 | } |
410 | if (rc < 0) | 474 | if (rc < 0) |
411 | return rc; | 475 | return rc; |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 6539b031b4eb..3e4fc192fdec 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -910,7 +910,8 @@ static int cx18_log_status(struct file *file, void *fh) | |||
910 | continue; | 910 | continue; |
911 | CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", | 911 | CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", |
912 | s->name, s->s_flags, | 912 | s->name, s->s_flags, |
913 | atomic_read(&s->q_full.depth) * 100 / s->buffers, | 913 | atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100 |
914 | / s->buffers, | ||
914 | (s->buffers * s->buf_size) / 1024, s->buffers); | 915 | (s->buffers * s->buf_size) / 1024, s->buffers); |
915 | } | 916 | } |
916 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", | 917 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", |
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 4a1249a7d46a..f231dd09c720 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c | |||
@@ -131,13 +131,39 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) | |||
131 | * Functions that run in a work_queue work handling context | 131 | * Functions that run in a work_queue work handling context |
132 | */ | 132 | */ |
133 | 133 | ||
134 | static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) | ||
135 | { | ||
136 | struct cx18_buffer *buf; | ||
137 | |||
138 | if (!s->dvb.enabled || mdl->bytesused == 0) | ||
139 | return; | ||
140 | |||
141 | /* We ignore mdl and buf readpos accounting here - it doesn't matter */ | ||
142 | |||
143 | /* The likely case */ | ||
144 | if (list_is_singular(&mdl->buf_list)) { | ||
145 | buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, | ||
146 | list); | ||
147 | if (buf->bytesused) | ||
148 | dvb_dmx_swfilter(&s->dvb.demux, | ||
149 | buf->buf, buf->bytesused); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
154 | if (buf->bytesused == 0) | ||
155 | break; | ||
156 | dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused); | ||
157 | } | ||
158 | } | ||
159 | |||
134 | static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | 160 | static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) |
135 | { | 161 | { |
136 | u32 handle, mdl_ack_count, id; | 162 | u32 handle, mdl_ack_count, id; |
137 | struct cx18_mailbox *mb; | 163 | struct cx18_mailbox *mb; |
138 | struct cx18_mdl_ack *mdl_ack; | 164 | struct cx18_mdl_ack *mdl_ack; |
139 | struct cx18_stream *s; | 165 | struct cx18_stream *s; |
140 | struct cx18_buffer *buf; | 166 | struct cx18_mdl *mdl; |
141 | int i; | 167 | int i; |
142 | 168 | ||
143 | mb = &order->mb; | 169 | mb = &order->mb; |
@@ -158,7 +184,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | |||
158 | id = mdl_ack->id; | 184 | id = mdl_ack->id; |
159 | /* | 185 | /* |
160 | * Simple integrity check for processing a stale (and possibly | 186 | * Simple integrity check for processing a stale (and possibly |
161 | * inconsistent mailbox): make sure the buffer id is in the | 187 | * inconsistent mailbox): make sure the MDL id is in the |
162 | * valid range for the stream. | 188 | * valid range for the stream. |
163 | * | 189 | * |
164 | * We go through the trouble of dealing with stale mailboxes | 190 | * We go through the trouble of dealing with stale mailboxes |
@@ -169,44 +195,42 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | |||
169 | * There are occasions when we get a half changed mailbox, | 195 | * There are occasions when we get a half changed mailbox, |
170 | * which this check catches for a handle & id mismatch. If the | 196 | * which this check catches for a handle & id mismatch. If the |
171 | * handle and id do correspond, the worst case is that we | 197 | * handle and id do correspond, the worst case is that we |
172 | * completely lost the old buffer, but pick up the new buffer | 198 | * completely lost the old MDL, but pick up the new MDL |
173 | * early (but the new mdl_ack is guaranteed to be good in this | 199 | * early (but the new mdl_ack is guaranteed to be good in this |
174 | * case as the firmware wouldn't point us to a new mdl_ack until | 200 | * case as the firmware wouldn't point us to a new mdl_ack until |
175 | * it's filled in). | 201 | * it's filled in). |
176 | * | 202 | * |
177 | * cx18_queue_get buf() will detect the lost buffers | 203 | * cx18_queue_get_mdl() will detect the lost MDLs |
178 | * and send them back to q_free for fw rotation eventually. | 204 | * and send them back to q_free for fw rotation eventually. |
179 | */ | 205 | */ |
180 | if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && | 206 | if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && |
181 | !(id >= s->mdl_base_idx && | 207 | !(id >= s->mdl_base_idx && |
182 | id < (s->mdl_base_idx + s->buffers))) { | 208 | id < (s->mdl_base_idx + s->buffers))) { |
183 | CX18_WARN("Fell behind! Ignoring stale mailbox with " | 209 | CX18_WARN("Fell behind! Ignoring stale mailbox with " |
184 | " inconsistent data. Lost buffer for mailbox " | 210 | " inconsistent data. Lost MDL for mailbox " |
185 | "seq no %d\n", mb->request); | 211 | "seq no %d\n", mb->request); |
186 | break; | 212 | break; |
187 | } | 213 | } |
188 | buf = cx18_queue_get_buf(s, id, mdl_ack->data_used); | 214 | mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); |
189 | 215 | ||
190 | CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); | 216 | CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); |
191 | if (buf == NULL) { | 217 | if (mdl == NULL) { |
192 | CX18_WARN("Could not find buf %d for stream %s\n", | 218 | CX18_WARN("Could not find MDL %d for stream %s\n", |
193 | id, s->name); | 219 | id, s->name); |
194 | continue; | 220 | continue; |
195 | } | 221 | } |
196 | 222 | ||
197 | CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", | 223 | CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", |
198 | s->name, buf->bytesused); | 224 | s->name, mdl->bytesused); |
199 | 225 | ||
200 | if (s->type != CX18_ENC_STREAM_TYPE_TS) | 226 | if (s->type != CX18_ENC_STREAM_TYPE_TS) |
201 | cx18_enqueue(s, buf, &s->q_full); | 227 | cx18_enqueue(s, mdl, &s->q_full); |
202 | else { | 228 | else { |
203 | if (s->dvb.enabled) | 229 | cx18_mdl_send_to_dvb(s, mdl); |
204 | dvb_dmx_swfilter(&s->dvb.demux, buf->buf, | 230 | cx18_enqueue(s, mdl, &s->q_free); |
205 | buf->bytesused); | ||
206 | cx18_enqueue(s, buf, &s->q_free); | ||
207 | } | 231 | } |
208 | } | 232 | } |
209 | /* Put as many buffers as possible back into fw use */ | 233 | /* Put as many MDLs as possible back into fw use */ |
210 | cx18_stream_load_fw_queue(s); | 234 | cx18_stream_load_fw_queue(s); |
211 | 235 | ||
212 | wake_up(&cx->dma_waitq); | 236 | wake_up(&cx->dma_waitq); |
@@ -616,7 +640,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) | |||
616 | 640 | ||
617 | /* | 641 | /* |
618 | * Wait for XPU to perform extra actions for the caller in some cases. | 642 | * Wait for XPU to perform extra actions for the caller in some cases. |
619 | * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers | 643 | * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs |
620 | * back in a burst shortly thereafter | 644 | * back in a burst shortly thereafter |
621 | */ | 645 | */ |
622 | if (info->flags & API_SLOW) | 646 | if (info->flags & API_SLOW) |
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index e23aaac5b280..5ea07359904c 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h | |||
@@ -39,14 +39,14 @@ | |||
39 | struct cx18; | 39 | struct cx18; |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * This structure is used by CPU to provide completed buffers information | 42 | * This structure is used by CPU to provide completed MDL & buffers information. |
43 | * Its structure is dictrated by the layout of the SCB, required by the | 43 | * Its structure is dictated by the layout of the SCB, required by the |
44 | * firmware, but its defintion needs to be here, instead of in cx18-scb.h, | 44 | * firmware, but its defintion needs to be here, instead of in cx18-scb.h, |
45 | * for mailbox work order scheduling | 45 | * for mailbox work order scheduling |
46 | */ | 46 | */ |
47 | struct cx18_mdl_ack { | 47 | struct cx18_mdl_ack { |
48 | u32 id; /* ID of a completed MDL */ | 48 | u32 id; /* ID of a completed MDL */ |
49 | u32 data_used; /* Total data filled in the MDL for buffer 'id' */ | 49 | u32 data_used; /* Total data filled in the MDL with 'id' */ |
50 | }; | 50 | }; |
51 | 51 | ||
52 | /* The cx18_mailbox struct is the mailbox structure which is used for passing | 52 | /* The cx18_mailbox struct is the mailbox structure which is used for passing |
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index b9bd4ff5535e..c1a49ecf9d98 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "cx18-queue.h" | 26 | #include "cx18-queue.h" |
27 | #include "cx18-streams.h" | 27 | #include "cx18-streams.h" |
28 | #include "cx18-scb.h" | 28 | #include "cx18-scb.h" |
29 | #include "cx18-io.h" | ||
29 | 30 | ||
30 | void cx18_buf_swap(struct cx18_buffer *buf) | 31 | void cx18_buf_swap(struct cx18_buffer *buf) |
31 | { | 32 | { |
@@ -35,6 +36,17 @@ void cx18_buf_swap(struct cx18_buffer *buf) | |||
35 | swab32s((u32 *)(buf->buf + i)); | 36 | swab32s((u32 *)(buf->buf + i)); |
36 | } | 37 | } |
37 | 38 | ||
39 | void _cx18_mdl_swap(struct cx18_mdl *mdl) | ||
40 | { | ||
41 | struct cx18_buffer *buf; | ||
42 | |||
43 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
44 | if (buf->bytesused == 0) | ||
45 | break; | ||
46 | cx18_buf_swap(buf); | ||
47 | } | ||
48 | } | ||
49 | |||
38 | void cx18_queue_init(struct cx18_queue *q) | 50 | void cx18_queue_init(struct cx18_queue *q) |
39 | { | 51 | { |
40 | INIT_LIST_HEAD(&q->list); | 52 | INIT_LIST_HEAD(&q->list); |
@@ -42,15 +54,16 @@ void cx18_queue_init(struct cx18_queue *q) | |||
42 | q->bytesused = 0; | 54 | q->bytesused = 0; |
43 | } | 55 | } |
44 | 56 | ||
45 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 57 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, |
46 | struct cx18_queue *q, int to_front) | 58 | struct cx18_queue *q, int to_front) |
47 | { | 59 | { |
48 | /* clear the buffer if it is not to be enqueued to the full queue */ | 60 | /* clear the mdl if it is not to be enqueued to the full queue */ |
49 | if (q != &s->q_full) { | 61 | if (q != &s->q_full) { |
50 | buf->bytesused = 0; | 62 | mdl->bytesused = 0; |
51 | buf->readpos = 0; | 63 | mdl->readpos = 0; |
52 | buf->b_flags = 0; | 64 | mdl->m_flags = 0; |
53 | buf->skipped = 0; | 65 | mdl->skipped = 0; |
66 | mdl->curr_buf = NULL; | ||
54 | } | 67 | } |
55 | 68 | ||
56 | /* q_busy is restricted to a max buffer count imposed by firmware */ | 69 | /* q_busy is restricted to a max buffer count imposed by firmware */ |
@@ -61,125 +74,270 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | |||
61 | spin_lock(&q->lock); | 74 | spin_lock(&q->lock); |
62 | 75 | ||
63 | if (to_front) | 76 | if (to_front) |
64 | list_add(&buf->list, &q->list); /* LIFO */ | 77 | list_add(&mdl->list, &q->list); /* LIFO */ |
65 | else | 78 | else |
66 | list_add_tail(&buf->list, &q->list); /* FIFO */ | 79 | list_add_tail(&mdl->list, &q->list); /* FIFO */ |
67 | q->bytesused += buf->bytesused - buf->readpos; | 80 | q->bytesused += mdl->bytesused - mdl->readpos; |
68 | atomic_inc(&q->depth); | 81 | atomic_inc(&q->depth); |
69 | 82 | ||
70 | spin_unlock(&q->lock); | 83 | spin_unlock(&q->lock); |
71 | return q; | 84 | return q; |
72 | } | 85 | } |
73 | 86 | ||
74 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) | 87 | struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) |
75 | { | 88 | { |
76 | struct cx18_buffer *buf = NULL; | 89 | struct cx18_mdl *mdl = NULL; |
77 | 90 | ||
78 | spin_lock(&q->lock); | 91 | spin_lock(&q->lock); |
79 | if (!list_empty(&q->list)) { | 92 | if (!list_empty(&q->list)) { |
80 | buf = list_first_entry(&q->list, struct cx18_buffer, list); | 93 | mdl = list_first_entry(&q->list, struct cx18_mdl, list); |
81 | list_del_init(&buf->list); | 94 | list_del_init(&mdl->list); |
82 | q->bytesused -= buf->bytesused - buf->readpos; | 95 | q->bytesused -= mdl->bytesused - mdl->readpos; |
83 | buf->skipped = 0; | 96 | mdl->skipped = 0; |
84 | atomic_dec(&q->depth); | 97 | atomic_dec(&q->depth); |
85 | } | 98 | } |
86 | spin_unlock(&q->lock); | 99 | spin_unlock(&q->lock); |
87 | return buf; | 100 | return mdl; |
101 | } | ||
102 | |||
103 | static void _cx18_mdl_set_buf_bytesused(struct cx18_stream *s, | ||
104 | struct cx18_mdl *mdl) | ||
105 | { | ||
106 | struct cx18_buffer *buf; | ||
107 | u32 buf_size = s->buf_size; | ||
108 | u32 bytesused = mdl->bytesused; | ||
109 | |||
110 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
111 | buf->readpos = 0; | ||
112 | if (bytesused >= buf_size) { | ||
113 | buf->bytesused = buf_size; | ||
114 | bytesused -= buf_size; | ||
115 | } else { | ||
116 | buf->bytesused = bytesused; | ||
117 | bytesused = 0; | ||
118 | } | ||
119 | } | ||
88 | } | 120 | } |
89 | 121 | ||
90 | struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, | 122 | static inline void cx18_mdl_set_buf_bytesused(struct cx18_stream *s, |
123 | struct cx18_mdl *mdl) | ||
124 | { | ||
125 | struct cx18_buffer *buf; | ||
126 | |||
127 | if (list_is_singular(&mdl->buf_list)) { | ||
128 | buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, | ||
129 | list); | ||
130 | buf->bytesused = mdl->bytesused; | ||
131 | buf->readpos = 0; | ||
132 | } else { | ||
133 | _cx18_mdl_set_buf_bytesused(s, mdl); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, | ||
91 | u32 bytesused) | 138 | u32 bytesused) |
92 | { | 139 | { |
93 | struct cx18 *cx = s->cx; | 140 | struct cx18 *cx = s->cx; |
94 | struct cx18_buffer *buf; | 141 | struct cx18_mdl *mdl; |
95 | struct cx18_buffer *tmp; | 142 | struct cx18_mdl *tmp; |
96 | struct cx18_buffer *ret = NULL; | 143 | struct cx18_mdl *ret = NULL; |
97 | LIST_HEAD(sweep_up); | 144 | LIST_HEAD(sweep_up); |
98 | 145 | ||
99 | /* | 146 | /* |
100 | * We don't have to acquire multiple q locks here, because we are | 147 | * We don't have to acquire multiple q locks here, because we are |
101 | * serialized by the single threaded work handler. | 148 | * serialized by the single threaded work handler. |
102 | * Buffers from the firmware will thus remain in order as | 149 | * MDLs from the firmware will thus remain in order as |
103 | * they are moved from q_busy to q_full or to the dvb ring buffer. | 150 | * they are moved from q_busy to q_full or to the dvb ring buffer. |
104 | */ | 151 | */ |
105 | spin_lock(&s->q_busy.lock); | 152 | spin_lock(&s->q_busy.lock); |
106 | list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) { | 153 | list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) { |
107 | /* | 154 | /* |
108 | * We should find what the firmware told us is done, | 155 | * We should find what the firmware told us is done, |
109 | * right at the front of the queue. If we don't, we likely have | 156 | * right at the front of the queue. If we don't, we likely have |
110 | * missed a buffer done message from the firmware. | 157 | * missed an mdl done message from the firmware. |
111 | * Once we skip a buffer repeatedly, relative to the size of | 158 | * Once we skip an mdl repeatedly, relative to the size of |
112 | * q_busy, we have high confidence we've missed it. | 159 | * q_busy, we have high confidence we've missed it. |
113 | */ | 160 | */ |
114 | if (buf->id != id) { | 161 | if (mdl->id != id) { |
115 | buf->skipped++; | 162 | mdl->skipped++; |
116 | if (buf->skipped >= atomic_read(&s->q_busy.depth)-1) { | 163 | if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) { |
117 | /* buffer must have fallen out of rotation */ | 164 | /* mdl must have fallen out of rotation */ |
118 | CX18_WARN("Skipped %s, buffer %d, %d " | 165 | CX18_WARN("Skipped %s, MDL %d, %d " |
119 | "times - it must have dropped out of " | 166 | "times - it must have dropped out of " |
120 | "rotation\n", s->name, buf->id, | 167 | "rotation\n", s->name, mdl->id, |
121 | buf->skipped); | 168 | mdl->skipped); |
122 | /* Sweep it up to put it back into rotation */ | 169 | /* Sweep it up to put it back into rotation */ |
123 | list_move_tail(&buf->list, &sweep_up); | 170 | list_move_tail(&mdl->list, &sweep_up); |
124 | atomic_dec(&s->q_busy.depth); | 171 | atomic_dec(&s->q_busy.depth); |
125 | } | 172 | } |
126 | continue; | 173 | continue; |
127 | } | 174 | } |
128 | /* | 175 | /* |
129 | * We pull the desired buffer off of the queue here. Something | 176 | * We pull the desired mdl off of the queue here. Something |
130 | * will have to put it back on a queue later. | 177 | * will have to put it back on a queue later. |
131 | */ | 178 | */ |
132 | list_del_init(&buf->list); | 179 | list_del_init(&mdl->list); |
133 | atomic_dec(&s->q_busy.depth); | 180 | atomic_dec(&s->q_busy.depth); |
134 | ret = buf; | 181 | ret = mdl; |
135 | break; | 182 | break; |
136 | } | 183 | } |
137 | spin_unlock(&s->q_busy.lock); | 184 | spin_unlock(&s->q_busy.lock); |
138 | 185 | ||
139 | /* | 186 | /* |
140 | * We found the buffer for which we were looking. Get it ready for | 187 | * We found the mdl for which we were looking. Get it ready for |
141 | * the caller to put on q_full or in the dvb ring buffer. | 188 | * the caller to put on q_full or in the dvb ring buffer. |
142 | */ | 189 | */ |
143 | if (ret != NULL) { | 190 | if (ret != NULL) { |
144 | ret->bytesused = bytesused; | 191 | ret->bytesused = bytesused; |
145 | ret->skipped = 0; | 192 | ret->skipped = 0; |
146 | /* readpos and b_flags were 0'ed when the buf went on q_busy */ | 193 | /* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */ |
147 | cx18_buf_sync_for_cpu(s, ret); | 194 | cx18_mdl_set_buf_bytesused(s, ret); |
195 | cx18_mdl_sync_for_cpu(s, ret); | ||
148 | if (s->type != CX18_ENC_STREAM_TYPE_TS) | 196 | if (s->type != CX18_ENC_STREAM_TYPE_TS) |
149 | set_bit(CX18_F_B_NEED_BUF_SWAP, &ret->b_flags); | 197 | set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags); |
150 | } | 198 | } |
151 | 199 | ||
152 | /* Put any buffers the firmware is ignoring back into normal rotation */ | 200 | /* Put any mdls the firmware is ignoring back into normal rotation */ |
153 | list_for_each_entry_safe(buf, tmp, &sweep_up, list) { | 201 | list_for_each_entry_safe(mdl, tmp, &sweep_up, list) { |
154 | list_del_init(&buf->list); | 202 | list_del_init(&mdl->list); |
155 | cx18_enqueue(s, buf, &s->q_free); | 203 | cx18_enqueue(s, mdl, &s->q_free); |
156 | } | 204 | } |
157 | return ret; | 205 | return ret; |
158 | } | 206 | } |
159 | 207 | ||
160 | /* Move all buffers of a queue to q_free, while flushing the buffers */ | 208 | /* Move all mdls of a queue, while flushing the mdl */ |
161 | static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) | 209 | static void cx18_queue_flush(struct cx18_stream *s, |
210 | struct cx18_queue *q_src, struct cx18_queue *q_dst) | ||
162 | { | 211 | { |
163 | struct cx18_buffer *buf; | 212 | struct cx18_mdl *mdl; |
164 | 213 | ||
165 | if (q == &s->q_free) | 214 | /* It only makes sense to flush to q_free or q_idle */ |
215 | if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy) | ||
166 | return; | 216 | return; |
167 | 217 | ||
168 | spin_lock(&q->lock); | 218 | spin_lock(&q_src->lock); |
169 | while (!list_empty(&q->list)) { | 219 | spin_lock(&q_dst->lock); |
170 | buf = list_first_entry(&q->list, struct cx18_buffer, list); | 220 | while (!list_empty(&q_src->list)) { |
171 | list_move_tail(&buf->list, &s->q_free.list); | 221 | mdl = list_first_entry(&q_src->list, struct cx18_mdl, list); |
172 | buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; | 222 | list_move_tail(&mdl->list, &q_dst->list); |
173 | atomic_inc(&s->q_free.depth); | 223 | mdl->bytesused = 0; |
224 | mdl->readpos = 0; | ||
225 | mdl->m_flags = 0; | ||
226 | mdl->skipped = 0; | ||
227 | mdl->curr_buf = NULL; | ||
228 | atomic_inc(&q_dst->depth); | ||
174 | } | 229 | } |
175 | cx18_queue_init(q); | 230 | cx18_queue_init(q_src); |
176 | spin_unlock(&q->lock); | 231 | spin_unlock(&q_src->lock); |
232 | spin_unlock(&q_dst->lock); | ||
177 | } | 233 | } |
178 | 234 | ||
179 | void cx18_flush_queues(struct cx18_stream *s) | 235 | void cx18_flush_queues(struct cx18_stream *s) |
180 | { | 236 | { |
181 | cx18_queue_flush(s, &s->q_busy); | 237 | cx18_queue_flush(s, &s->q_busy, &s->q_free); |
182 | cx18_queue_flush(s, &s->q_full); | 238 | cx18_queue_flush(s, &s->q_full, &s->q_free); |
239 | } | ||
240 | |||
241 | /* | ||
242 | * Note, s->buf_pool is not protected by a lock, | ||
243 | * the stream better not have *anything* going on when calling this | ||
244 | */ | ||
245 | void cx18_unload_queues(struct cx18_stream *s) | ||
246 | { | ||
247 | struct cx18_queue *q_idle = &s->q_idle; | ||
248 | struct cx18_mdl *mdl; | ||
249 | struct cx18_buffer *buf; | ||
250 | |||
251 | /* Move all MDLS to q_idle */ | ||
252 | cx18_queue_flush(s, &s->q_busy, q_idle); | ||
253 | cx18_queue_flush(s, &s->q_full, q_idle); | ||
254 | cx18_queue_flush(s, &s->q_free, q_idle); | ||
255 | |||
256 | /* Reset MDL id's and move all buffers back to the stream's buf_pool */ | ||
257 | spin_lock(&q_idle->lock); | ||
258 | list_for_each_entry(mdl, &q_idle->list, list) { | ||
259 | while (!list_empty(&mdl->buf_list)) { | ||
260 | buf = list_first_entry(&mdl->buf_list, | ||
261 | struct cx18_buffer, list); | ||
262 | list_move_tail(&buf->list, &s->buf_pool); | ||
263 | buf->bytesused = 0; | ||
264 | buf->readpos = 0; | ||
265 | } | ||
266 | mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */ | ||
267 | /* all other mdl fields were cleared by cx18_queue_flush() */ | ||
268 | } | ||
269 | spin_unlock(&q_idle->lock); | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Note, s->buf_pool is not protected by a lock, | ||
274 | * the stream better not have *anything* going on when calling this | ||
275 | */ | ||
276 | void cx18_load_queues(struct cx18_stream *s) | ||
277 | { | ||
278 | struct cx18 *cx = s->cx; | ||
279 | struct cx18_mdl *mdl; | ||
280 | struct cx18_buffer *buf; | ||
281 | int mdl_id; | ||
282 | int i; | ||
283 | |||
284 | /* | ||
285 | * Attach buffers to MDLs, give the MDLs ids, and add MDLs to q_free | ||
286 | * Excess MDLs are left on q_idle | ||
287 | * Excess buffers are left in buf_pool and/or on an MDL in q_idle | ||
288 | */ | ||
289 | mdl_id = s->mdl_base_idx; | ||
290 | for (mdl = cx18_dequeue(s, &s->q_idle), i = s->bufs_per_mdl; | ||
291 | mdl != NULL && i == s->bufs_per_mdl; | ||
292 | mdl = cx18_dequeue(s, &s->q_idle)) { | ||
293 | |||
294 | mdl->id = mdl_id; | ||
295 | |||
296 | for (i = 0; i < s->bufs_per_mdl; i++) { | ||
297 | if (list_empty(&s->buf_pool)) | ||
298 | break; | ||
299 | |||
300 | buf = list_first_entry(&s->buf_pool, struct cx18_buffer, | ||
301 | list); | ||
302 | list_move_tail(&buf->list, &mdl->buf_list); | ||
303 | |||
304 | /* update the firmware's MDL array with this buffer */ | ||
305 | cx18_writel(cx, buf->dma_handle, | ||
306 | &cx->scb->cpu_mdl[mdl_id + i].paddr); | ||
307 | cx18_writel(cx, s->buf_size, | ||
308 | &cx->scb->cpu_mdl[mdl_id + i].length); | ||
309 | } | ||
310 | |||
311 | if (i == s->bufs_per_mdl) | ||
312 | cx18_enqueue(s, mdl, &s->q_free); | ||
313 | else | ||
314 | cx18_push(s, mdl, &s->q_idle); /* not enough buffers */ | ||
315 | mdl_id += i; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | void _cx18_mdl_sync_for_cpu(struct cx18_stream *s, struct cx18_mdl *mdl) | ||
320 | { | ||
321 | int dma = s->dma; | ||
322 | u32 buf_size = s->buf_size; | ||
323 | struct pci_dev *pci_dev = s->cx->pci_dev; | ||
324 | struct cx18_buffer *buf; | ||
325 | |||
326 | list_for_each_entry(buf, &mdl->buf_list, list) | ||
327 | pci_dma_sync_single_for_cpu(pci_dev, buf->dma_handle, | ||
328 | buf_size, dma); | ||
329 | } | ||
330 | |||
331 | void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl) | ||
332 | { | ||
333 | int dma = s->dma; | ||
334 | u32 buf_size = s->buf_size; | ||
335 | struct pci_dev *pci_dev = s->cx->pci_dev; | ||
336 | struct cx18_buffer *buf; | ||
337 | |||
338 | list_for_each_entry(buf, &mdl->buf_list, list) | ||
339 | pci_dma_sync_single_for_device(pci_dev, buf->dma_handle, | ||
340 | buf_size, dma); | ||
183 | } | 341 | } |
184 | 342 | ||
185 | int cx18_stream_alloc(struct cx18_stream *s) | 343 | int cx18_stream_alloc(struct cx18_stream *s) |
@@ -207,24 +365,40 @@ int cx18_stream_alloc(struct cx18_stream *s) | |||
207 | 365 | ||
208 | s->mdl_base_idx = cx->free_mdl_idx; | 366 | s->mdl_base_idx = cx->free_mdl_idx; |
209 | 367 | ||
210 | /* allocate stream buffers. Initially all buffers are in q_free. */ | 368 | /* allocate stream buffers and MDLs */ |
211 | for (i = 0; i < s->buffers; i++) { | 369 | for (i = 0; i < s->buffers; i++) { |
212 | struct cx18_buffer *buf = kzalloc(sizeof(struct cx18_buffer), | 370 | struct cx18_mdl *mdl; |
213 | GFP_KERNEL|__GFP_NOWARN); | 371 | struct cx18_buffer *buf; |
214 | 372 | ||
215 | if (buf == NULL) | 373 | /* 1 MDL per buffer to handle the worst & also default case */ |
374 | mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN); | ||
375 | if (mdl == NULL) | ||
216 | break; | 376 | break; |
377 | |||
378 | buf = kzalloc(sizeof(struct cx18_buffer), | ||
379 | GFP_KERNEL|__GFP_NOWARN); | ||
380 | if (buf == NULL) { | ||
381 | kfree(mdl); | ||
382 | break; | ||
383 | } | ||
384 | |||
217 | buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); | 385 | buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); |
218 | if (buf->buf == NULL) { | 386 | if (buf->buf == NULL) { |
387 | kfree(mdl); | ||
219 | kfree(buf); | 388 | kfree(buf); |
220 | break; | 389 | break; |
221 | } | 390 | } |
222 | buf->id = cx->buffer_id++; | 391 | |
392 | INIT_LIST_HEAD(&mdl->list); | ||
393 | INIT_LIST_HEAD(&mdl->buf_list); | ||
394 | mdl->id = s->mdl_base_idx; /* a somewhat safe value */ | ||
395 | cx18_enqueue(s, mdl, &s->q_idle); | ||
396 | |||
223 | INIT_LIST_HEAD(&buf->list); | 397 | INIT_LIST_HEAD(&buf->list); |
224 | buf->dma_handle = pci_map_single(s->cx->pci_dev, | 398 | buf->dma_handle = pci_map_single(s->cx->pci_dev, |
225 | buf->buf, s->buf_size, s->dma); | 399 | buf->buf, s->buf_size, s->dma); |
226 | cx18_buf_sync_for_cpu(s, buf); | 400 | cx18_buf_sync_for_cpu(s, buf); |
227 | cx18_enqueue(s, buf, &s->q_free); | 401 | list_add_tail(&buf->list, &s->buf_pool); |
228 | } | 402 | } |
229 | if (i == s->buffers) { | 403 | if (i == s->buffers) { |
230 | cx->free_mdl_idx += s->buffers; | 404 | cx->free_mdl_idx += s->buffers; |
@@ -237,13 +411,21 @@ int cx18_stream_alloc(struct cx18_stream *s) | |||
237 | 411 | ||
238 | void cx18_stream_free(struct cx18_stream *s) | 412 | void cx18_stream_free(struct cx18_stream *s) |
239 | { | 413 | { |
414 | struct cx18_mdl *mdl; | ||
240 | struct cx18_buffer *buf; | 415 | struct cx18_buffer *buf; |
241 | 416 | ||
242 | /* move all buffers to q_free */ | 417 | /* move all buffers to buf_pool and all MDLs to q_idle */ |
243 | cx18_flush_queues(s); | 418 | cx18_unload_queues(s); |
419 | |||
420 | /* empty q_idle */ | ||
421 | while ((mdl = cx18_dequeue(s, &s->q_idle))) | ||
422 | kfree(mdl); | ||
423 | |||
424 | /* empty buf_pool */ | ||
425 | while (!list_empty(&s->buf_pool)) { | ||
426 | buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list); | ||
427 | list_del_init(&buf->list); | ||
244 | 428 | ||
245 | /* empty q_free */ | ||
246 | while ((buf = cx18_dequeue(s, &s->q_free))) { | ||
247 | pci_unmap_single(s->cx->pci_dev, buf->dma_handle, | 429 | pci_unmap_single(s->cx->pci_dev, buf->dma_handle, |
248 | s->buf_size, s->dma); | 430 | s->buf_size, s->dma); |
249 | kfree(buf->buf); | 431 | kfree(buf->buf); |
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h index 4de06269d88f..96747e5e7c3c 100644 --- a/drivers/media/video/cx18/cx18-queue.h +++ b/drivers/media/video/cx18/cx18-queue.h | |||
@@ -33,6 +33,19 @@ static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, | |||
33 | s->buf_size, s->dma); | 33 | s->buf_size, s->dma); |
34 | } | 34 | } |
35 | 35 | ||
36 | void _cx18_mdl_sync_for_cpu(struct cx18_stream *s, struct cx18_mdl *mdl); | ||
37 | |||
38 | static inline void cx18_mdl_sync_for_cpu(struct cx18_stream *s, | ||
39 | struct cx18_mdl *mdl) | ||
40 | { | ||
41 | if (list_is_singular(&mdl->buf_list)) | ||
42 | cx18_buf_sync_for_cpu(s, list_first_entry(&mdl->buf_list, | ||
43 | struct cx18_buffer, | ||
44 | list)); | ||
45 | else | ||
46 | _cx18_mdl_sync_for_cpu(s, mdl); | ||
47 | } | ||
48 | |||
36 | static inline void cx18_buf_sync_for_device(struct cx18_stream *s, | 49 | static inline void cx18_buf_sync_for_device(struct cx18_stream *s, |
37 | struct cx18_buffer *buf) | 50 | struct cx18_buffer *buf) |
38 | { | 51 | { |
@@ -40,32 +53,59 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s, | |||
40 | s->buf_size, s->dma); | 53 | s->buf_size, s->dma); |
41 | } | 54 | } |
42 | 55 | ||
56 | void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl); | ||
57 | |||
58 | static inline void cx18_mdl_sync_for_device(struct cx18_stream *s, | ||
59 | struct cx18_mdl *mdl) | ||
60 | { | ||
61 | if (list_is_singular(&mdl->buf_list)) | ||
62 | cx18_buf_sync_for_device(s, list_first_entry(&mdl->buf_list, | ||
63 | struct cx18_buffer, | ||
64 | list)); | ||
65 | else | ||
66 | _cx18_mdl_sync_for_device(s, mdl); | ||
67 | } | ||
68 | |||
43 | void cx18_buf_swap(struct cx18_buffer *buf); | 69 | void cx18_buf_swap(struct cx18_buffer *buf); |
70 | void _cx18_mdl_swap(struct cx18_mdl *mdl); | ||
71 | |||
72 | static inline void cx18_mdl_swap(struct cx18_mdl *mdl) | ||
73 | { | ||
74 | if (list_is_singular(&mdl->buf_list)) | ||
75 | cx18_buf_swap(list_first_entry(&mdl->buf_list, | ||
76 | struct cx18_buffer, list)); | ||
77 | else | ||
78 | _cx18_mdl_swap(mdl); | ||
79 | } | ||
44 | 80 | ||
45 | /* cx18_queue utility functions */ | 81 | /* cx18_queue utility functions */ |
46 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 82 | struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, |
47 | struct cx18_queue *q, int to_front); | 83 | struct cx18_queue *q, int to_front); |
48 | 84 | ||
49 | static inline | 85 | static inline |
50 | struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | 86 | struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, |
51 | struct cx18_queue *q) | 87 | struct cx18_queue *q) |
52 | { | 88 | { |
53 | return _cx18_enqueue(s, buf, q, 0); /* FIFO */ | 89 | return _cx18_enqueue(s, mdl, q, 0); /* FIFO */ |
54 | } | 90 | } |
55 | 91 | ||
56 | static inline | 92 | static inline |
57 | struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf, | 93 | struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_mdl *mdl, |
58 | struct cx18_queue *q) | 94 | struct cx18_queue *q) |
59 | { | 95 | { |
60 | return _cx18_enqueue(s, buf, q, 1); /* LIFO */ | 96 | return _cx18_enqueue(s, mdl, q, 1); /* LIFO */ |
61 | } | 97 | } |
62 | 98 | ||
63 | void cx18_queue_init(struct cx18_queue *q); | 99 | void cx18_queue_init(struct cx18_queue *q); |
64 | struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); | 100 | struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); |
65 | struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, | 101 | struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, |
66 | u32 bytesused); | 102 | u32 bytesused); |
67 | void cx18_flush_queues(struct cx18_stream *s); | 103 | void cx18_flush_queues(struct cx18_stream *s); |
68 | 104 | ||
105 | /* queue MDL reconfiguration helpers */ | ||
106 | void cx18_unload_queues(struct cx18_stream *s); | ||
107 | void cx18_load_queues(struct cx18_stream *s); | ||
108 | |||
69 | /* cx18_stream utility functions */ | 109 | /* cx18_stream utility functions */ |
70 | int cx18_stream_alloc(struct cx18_stream *s); | 110 | int cx18_stream_alloc(struct cx18_stream *s); |
71 | void cx18_stream_free(struct cx18_stream *s); | 111 | void cx18_stream_free(struct cx18_stream *s); |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 10228c5ca5a0..9f8adda6f261 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -115,6 +115,9 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
115 | s->dma = cx18_stream_info[type].dma; | 115 | s->dma = cx18_stream_info[type].dma; |
116 | s->buffers = cx->stream_buffers[type]; | 116 | s->buffers = cx->stream_buffers[type]; |
117 | s->buf_size = cx->stream_buf_size[type]; | 117 | s->buf_size = cx->stream_buf_size[type]; |
118 | INIT_LIST_HEAD(&s->buf_pool); | ||
119 | s->bufs_per_mdl = 1; | ||
120 | s->mdl_size = s->buf_size * s->bufs_per_mdl; | ||
118 | 121 | ||
119 | init_waitqueue_head(&s->waitq); | 122 | init_waitqueue_head(&s->waitq); |
120 | s->id = -1; | 123 | s->id = -1; |
@@ -124,6 +127,8 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
124 | cx18_queue_init(&s->q_busy); | 127 | cx18_queue_init(&s->q_busy); |
125 | spin_lock_init(&s->q_full.lock); | 128 | spin_lock_init(&s->q_full.lock); |
126 | cx18_queue_init(&s->q_full); | 129 | cx18_queue_init(&s->q_full); |
130 | spin_lock_init(&s->q_idle.lock); | ||
131 | cx18_queue_init(&s->q_idle); | ||
127 | 132 | ||
128 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); | 133 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); |
129 | } | 134 | } |
@@ -441,8 +446,8 @@ static void cx18_vbi_setup(struct cx18_stream *s) | |||
441 | } | 446 | } |
442 | 447 | ||
443 | static | 448 | static |
444 | struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s, | 449 | struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s, |
445 | struct cx18_buffer *buf) | 450 | struct cx18_mdl *mdl) |
446 | { | 451 | { |
447 | struct cx18 *cx = s->cx; | 452 | struct cx18 *cx = s->cx; |
448 | struct cx18_queue *q; | 453 | struct cx18_queue *q; |
@@ -451,16 +456,16 @@ struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s, | |||
451 | if (s->handle == CX18_INVALID_TASK_HANDLE || | 456 | if (s->handle == CX18_INVALID_TASK_HANDLE || |
452 | test_bit(CX18_F_S_STOPPING, &s->s_flags) || | 457 | test_bit(CX18_F_S_STOPPING, &s->s_flags) || |
453 | !test_bit(CX18_F_S_STREAMING, &s->s_flags)) | 458 | !test_bit(CX18_F_S_STREAMING, &s->s_flags)) |
454 | return cx18_enqueue(s, buf, &s->q_free); | 459 | return cx18_enqueue(s, mdl, &s->q_free); |
455 | 460 | ||
456 | q = cx18_enqueue(s, buf, &s->q_busy); | 461 | q = cx18_enqueue(s, mdl, &s->q_busy); |
457 | if (q != &s->q_busy) | 462 | if (q != &s->q_busy) |
458 | return q; /* The firmware has the max buffers it can handle */ | 463 | return q; /* The firmware has the max MDLs it can handle */ |
459 | 464 | ||
460 | cx18_buf_sync_for_device(s, buf); | 465 | cx18_mdl_sync_for_device(s, mdl); |
461 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | 466 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, |
462 | (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | 467 | (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem, |
463 | 1, buf->id, s->buf_size); | 468 | s->bufs_per_mdl, mdl->id, s->mdl_size); |
464 | return q; | 469 | return q; |
465 | } | 470 | } |
466 | 471 | ||
@@ -468,7 +473,7 @@ static | |||
468 | void _cx18_stream_load_fw_queue(struct cx18_stream *s) | 473 | void _cx18_stream_load_fw_queue(struct cx18_stream *s) |
469 | { | 474 | { |
470 | struct cx18_queue *q; | 475 | struct cx18_queue *q; |
471 | struct cx18_buffer *buf; | 476 | struct cx18_mdl *mdl; |
472 | 477 | ||
473 | if (atomic_read(&s->q_free.depth) == 0 || | 478 | if (atomic_read(&s->q_free.depth) == 0 || |
474 | atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM) | 479 | atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM) |
@@ -476,10 +481,10 @@ void _cx18_stream_load_fw_queue(struct cx18_stream *s) | |||
476 | 481 | ||
477 | /* Move from q_free to q_busy notifying the firmware, until the limit */ | 482 | /* Move from q_free to q_busy notifying the firmware, until the limit */ |
478 | do { | 483 | do { |
479 | buf = cx18_dequeue(s, &s->q_free); | 484 | mdl = cx18_dequeue(s, &s->q_free); |
480 | if (buf == NULL) | 485 | if (mdl == NULL) |
481 | break; | 486 | break; |
482 | q = _cx18_stream_put_buf_fw(s, buf); | 487 | q = _cx18_stream_put_mdl_fw(s, mdl); |
483 | } while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM | 488 | } while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM |
484 | && q == &s->q_busy); | 489 | && q == &s->q_busy); |
485 | } | 490 | } |
@@ -492,11 +497,21 @@ void cx18_out_work_handler(struct work_struct *work) | |||
492 | _cx18_stream_load_fw_queue(s); | 497 | _cx18_stream_load_fw_queue(s); |
493 | } | 498 | } |
494 | 499 | ||
500 | static void cx18_stream_configure_mdls(struct cx18_stream *s) | ||
501 | { | ||
502 | cx18_unload_queues(s); | ||
503 | |||
504 | /* For now */ | ||
505 | s->bufs_per_mdl = 1; | ||
506 | s->mdl_size = s->buf_size * s->bufs_per_mdl; | ||
507 | |||
508 | cx18_load_queues(s); | ||
509 | } | ||
510 | |||
495 | int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | 511 | int cx18_start_v4l2_encode_stream(struct cx18_stream *s) |
496 | { | 512 | { |
497 | u32 data[MAX_MB_ARGUMENTS]; | 513 | u32 data[MAX_MB_ARGUMENTS]; |
498 | struct cx18 *cx = s->cx; | 514 | struct cx18 *cx = s->cx; |
499 | struct cx18_buffer *buf; | ||
500 | int captype = 0; | 515 | int captype = 0; |
501 | struct cx18_api_func_private priv; | 516 | struct cx18_api_func_private priv; |
502 | 517 | ||
@@ -619,14 +634,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
619 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); | 634 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); |
620 | 635 | ||
621 | /* Init all the cpu_mdls for this stream */ | 636 | /* Init all the cpu_mdls for this stream */ |
622 | cx18_flush_queues(s); | 637 | cx18_stream_configure_mdls(s); |
623 | spin_lock(&s->q_free.lock); | ||
624 | list_for_each_entry(buf, &s->q_free.list, list) { | ||
625 | cx18_writel(cx, buf->dma_handle, | ||
626 | &cx->scb->cpu_mdl[buf->id].paddr); | ||
627 | cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); | ||
628 | } | ||
629 | spin_unlock(&s->q_free.lock); | ||
630 | _cx18_stream_load_fw_queue(s); | 638 | _cx18_stream_load_fw_queue(s); |
631 | 639 | ||
632 | /* begin_capture */ | 640 | /* begin_capture */ |
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h index 1afc3fd9d822..4a01db5e5a35 100644 --- a/drivers/media/video/cx18/cx18-streams.h +++ b/drivers/media/video/cx18/cx18-streams.h | |||
@@ -28,18 +28,18 @@ int cx18_streams_setup(struct cx18 *cx); | |||
28 | int cx18_streams_register(struct cx18 *cx); | 28 | int cx18_streams_register(struct cx18 *cx); |
29 | void cx18_streams_cleanup(struct cx18 *cx, int unregister); | 29 | void cx18_streams_cleanup(struct cx18 *cx, int unregister); |
30 | 30 | ||
31 | /* Related to submission of buffers to firmware */ | 31 | /* Related to submission of mdls to firmware */ |
32 | static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) | 32 | static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) |
33 | { | 33 | { |
34 | struct cx18 *cx = s->cx; | 34 | struct cx18 *cx = s->cx; |
35 | queue_work(cx->out_work_queue, &s->out_work_order); | 35 | queue_work(cx->out_work_queue, &s->out_work_order); |
36 | } | 36 | } |
37 | 37 | ||
38 | static inline void cx18_stream_put_buf_fw(struct cx18_stream *s, | 38 | static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, |
39 | struct cx18_buffer *buf) | 39 | struct cx18_mdl *mdl) |
40 | { | 40 | { |
41 | /* Put buf on q_free; the out work handler will move buf(s) to q_busy */ | 41 | /* Put mdl on q_free; the out work handler will move mdl(s) to q_busy */ |
42 | cx18_enqueue(s, buf, &s->q_free); | 42 | cx18_enqueue(s, mdl, &s->q_free); |
43 | cx18_stream_load_fw_queue(s); | 43 | cx18_stream_load_fw_queue(s); |
44 | } | 44 | } |
45 | 45 | ||
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c index c2aef4add31d..574c1c6974f8 100644 --- a/drivers/media/video/cx18/cx18-vbi.c +++ b/drivers/media/video/cx18/cx18-vbi.c | |||
@@ -105,6 +105,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) | |||
105 | 105 | ||
106 | /* Compress raw VBI format, removes leading SAV codes and surplus space | 106 | /* Compress raw VBI format, removes leading SAV codes and surplus space |
107 | after the frame. Returns new compressed size. */ | 107 | after the frame. Returns new compressed size. */ |
108 | /* FIXME - this function ignores the input size. */ | ||
108 | static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) | 109 | static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) |
109 | { | 110 | { |
110 | u32 line_size = vbi_active_samples; | 111 | u32 line_size = vbi_active_samples; |
@@ -185,8 +186,7 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, | |||
185 | return line; | 186 | return line; |
186 | } | 187 | } |
187 | 188 | ||
188 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | 189 | static void _cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf) |
189 | int streamtype) | ||
190 | { | 190 | { |
191 | /* | 191 | /* |
192 | * The CX23418 provides a 12 byte header in its raw VBI buffers to us: | 192 | * The CX23418 provides a 12 byte header in its raw VBI buffers to us: |
@@ -203,9 +203,6 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | |||
203 | u32 pts; | 203 | u32 pts; |
204 | int lines; | 204 | int lines; |
205 | 205 | ||
206 | if (streamtype != CX18_ENC_STREAM_TYPE_VBI) | ||
207 | return; | ||
208 | |||
209 | /* | 206 | /* |
210 | * The CX23418 sends us data that is 32 bit little-endian swapped, | 207 | * The CX23418 sends us data that is 32 bit little-endian swapped, |
211 | * but we want the raw VBI bytes in the order they were in the raster | 208 | * but we want the raw VBI bytes in the order they were in the raster |
@@ -250,3 +247,31 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | |||
250 | copy_vbi_data(cx, lines, pts); | 247 | copy_vbi_data(cx, lines, pts); |
251 | cx->vbi.frame++; | 248 | cx->vbi.frame++; |
252 | } | 249 | } |
250 | |||
251 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, | ||
252 | int streamtype) | ||
253 | { | ||
254 | struct cx18_buffer *buf; | ||
255 | u32 orig_used; | ||
256 | |||
257 | if (streamtype != CX18_ENC_STREAM_TYPE_VBI) | ||
258 | return; | ||
259 | |||
260 | /* | ||
261 | * Big assumption here: | ||
262 | * Every buffer hooked to the MDL's buf_list is a complete VBI frame | ||
263 | * that ends at the end of the buffer. | ||
264 | * | ||
265 | * To assume anything else would make the code in this file | ||
266 | * more complex, or require extra memcpy()'s to make the | ||
267 | * buffers satisfy the above assumption. It's just simpler to set | ||
268 | * up the encoder buffer transfers to make the assumption true. | ||
269 | */ | ||
270 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
271 | orig_used = buf->bytesused; | ||
272 | if (orig_used == 0) | ||
273 | break; | ||
274 | _cx18_process_vbi_data(cx, buf); | ||
275 | mdl->bytesused -= (orig_used - buf->bytesused); | ||
276 | } | ||
277 | } | ||
diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h index e7e1ae427f34..b365cf4b4668 100644 --- a/drivers/media/video/cx18/cx18-vbi.h +++ b/drivers/media/video/cx18/cx18-vbi.h | |||
@@ -21,6 +21,6 @@ | |||
21 | * 02111-1307 USA | 21 | * 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, | 24 | void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, |
25 | int streamtype); | 25 | int streamtype); |
26 | int cx18_used_line(struct cx18 *cx, int line, int field); | 26 | int cx18_used_line(struct cx18 *cx, int line, int field); |