diff options
author | Andy Walls <awalls@radix.net> | 2008-12-08 21:02:45 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:38:29 -0500 |
commit | 66c2a6b0bc0b394d215768610d96f44cf97052ac (patch) | |
tree | a88946e764eb5a829a920c5027b4d92922cc54ee /drivers/media/video/cx18/cx18-streams.c | |
parent | b80e1074c734416987486b7b76b6479faa73f1e2 (diff) |
V4L/DVB (9801): cx18: Allow more than 63 capture buffers in rotation per stream
cx18: Allow more than 63 capture buffers in rotation per stream. Implement
q_busy to hold buffers the firmware has for use. q_free holds truly unused
buffers in a pool. New buffers are given to the firmware as soon as the
firmware returns one, if there are any to give to the firmware.
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18/cx18-streams.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 77 |
1 files changed, 65 insertions, 12 deletions
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index a1cf434f7975..6b0b7f751f20 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -127,16 +127,11 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
127 | s->buf_size = cx->stream_buf_size[type]; | 127 | s->buf_size = cx->stream_buf_size[type]; |
128 | if (s->buf_size) | 128 | if (s->buf_size) |
129 | s->buffers = max_size / s->buf_size; | 129 | s->buffers = max_size / s->buf_size; |
130 | if (s->buffers > 63) { | ||
131 | /* Each stream has a maximum of 63 buffers, | ||
132 | ensure we do not exceed that. */ | ||
133 | s->buffers = 63; | ||
134 | s->buf_size = (max_size / s->buffers) & ~0xfff; | ||
135 | } | ||
136 | mutex_init(&s->qlock); | 130 | mutex_init(&s->qlock); |
137 | init_waitqueue_head(&s->waitq); | 131 | init_waitqueue_head(&s->waitq); |
138 | s->id = -1; | 132 | s->id = -1; |
139 | cx18_queue_init(&s->q_free); | 133 | cx18_queue_init(&s->q_free); |
134 | cx18_queue_init(&s->q_busy); | ||
140 | cx18_queue_init(&s->q_full); | 135 | cx18_queue_init(&s->q_full); |
141 | } | 136 | } |
142 | 137 | ||
@@ -401,11 +396,61 @@ static void cx18_vbi_setup(struct cx18_stream *s) | |||
401 | cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); | 396 | cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); |
402 | } | 397 | } |
403 | 398 | ||
399 | struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, | ||
400 | struct cx18_buffer *buf) | ||
401 | { | ||
402 | struct cx18 *cx = s->cx; | ||
403 | struct cx18_queue *q; | ||
404 | |||
405 | /* Don't give it to the firmware, if we're not running a capture */ | ||
406 | if (s->handle == CX18_INVALID_TASK_HANDLE || | ||
407 | !test_bit(CX18_F_S_STREAMING, &s->s_flags)) | ||
408 | return cx18_enqueue(s, buf, &s->q_free); | ||
409 | |||
410 | q = cx18_enqueue(s, buf, &s->q_busy); | ||
411 | if (q != &s->q_busy) | ||
412 | return q; /* The firmware has the max buffers it can handle */ | ||
413 | |||
414 | cx18_buf_sync_for_device(s, buf); | ||
415 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | ||
416 | (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | ||
417 | 1, buf->id, s->buf_size); | ||
418 | return q; | ||
419 | } | ||
420 | |||
421 | /* Must hold s->qlock when calling */ | ||
422 | void cx18_stream_load_fw_queue_nolock(struct cx18_stream *s) | ||
423 | { | ||
424 | struct cx18_buffer *buf; | ||
425 | struct cx18 *cx = s->cx; | ||
426 | |||
427 | /* Move from q_free to q_busy notifying the firmware: 63 buf limit */ | ||
428 | while (s->handle != CX18_INVALID_TASK_HANDLE && | ||
429 | test_bit(CX18_F_S_STREAMING, &s->s_flags) && | ||
430 | atomic_read(&s->q_busy.buffers) < 63 && | ||
431 | !list_empty(&s->q_free.list)) { | ||
432 | |||
433 | /* Move from q_free to q_busy */ | ||
434 | buf = list_entry(s->q_free.list.next, struct cx18_buffer, list); | ||
435 | list_move_tail(&buf->list, &s->q_busy.list); | ||
436 | buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; | ||
437 | atomic_dec(&s->q_free.buffers); | ||
438 | atomic_inc(&s->q_busy.buffers); | ||
439 | |||
440 | /* Notify firmware */ | ||
441 | cx18_buf_sync_for_device(s, buf); | ||
442 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | ||
443 | (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | ||
444 | 1, buf->id, s->buf_size); | ||
445 | } | ||
446 | } | ||
447 | |||
404 | int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | 448 | int cx18_start_v4l2_encode_stream(struct cx18_stream *s) |
405 | { | 449 | { |
406 | u32 data[MAX_MB_ARGUMENTS]; | 450 | u32 data[MAX_MB_ARGUMENTS]; |
407 | struct cx18 *cx = s->cx; | 451 | struct cx18 *cx = s->cx; |
408 | struct list_head *p; | 452 | struct list_head *p; |
453 | struct cx18_buffer *buf; | ||
409 | int ts = 0; | 454 | int ts = 0; |
410 | int captype = 0; | 455 | int captype = 0; |
411 | 456 | ||
@@ -488,16 +533,18 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
488 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, | 533 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, |
489 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); | 534 | (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); |
490 | 535 | ||
536 | /* Init all the cpu_mdls for this stream */ | ||
537 | cx18_flush_queues(s); | ||
538 | mutex_lock(&s->qlock); | ||
491 | list_for_each(p, &s->q_free.list) { | 539 | list_for_each(p, &s->q_free.list) { |
492 | struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); | 540 | buf = list_entry(p, struct cx18_buffer, list); |
493 | |||
494 | cx18_writel(cx, buf->dma_handle, | 541 | cx18_writel(cx, buf->dma_handle, |
495 | &cx->scb->cpu_mdl[buf->id].paddr); | 542 | &cx->scb->cpu_mdl[buf->id].paddr); |
496 | cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); | 543 | cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); |
497 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | ||
498 | (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | ||
499 | 1, buf->id, s->buf_size); | ||
500 | } | 544 | } |
545 | cx18_stream_load_fw_queue_nolock(s); | ||
546 | mutex_unlock(&s->qlock); | ||
547 | |||
501 | /* begin_capture */ | 548 | /* begin_capture */ |
502 | if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { | 549 | if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { |
503 | CX18_DEBUG_WARN("Error starting capture!\n"); | 550 | CX18_DEBUG_WARN("Error starting capture!\n"); |
@@ -506,9 +553,15 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
506 | cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); | 553 | cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); |
507 | else | 554 | else |
508 | cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); | 555 | cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); |
556 | clear_bit(CX18_F_S_STREAMING, &s->s_flags); | ||
557 | /* FIXME - CX18_F_S_STREAMOFF as well? */ | ||
509 | cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); | 558 | cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); |
510 | cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); | 559 | cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); |
511 | /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */ | 560 | s->handle = CX18_INVALID_TASK_HANDLE; |
561 | if (atomic_read(&cx->tot_capturing) == 0) { | ||
562 | set_bit(CX18_F_I_EOS, &cx->i_flags); | ||
563 | cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); | ||
564 | } | ||
512 | return -EINVAL; | 565 | return -EINVAL; |
513 | } | 566 | } |
514 | 567 | ||