diff options
-rw-r--r-- | drivers/media/video/videobuf-core.c | 96 | ||||
-rw-r--r-- | include/media/videobuf-core.h | 2 |
2 files changed, 78 insertions, 20 deletions
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 1ba3aaa29dd0..3ab556093ca7 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c | |||
@@ -141,6 +141,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q, | |||
141 | BUG_ON(!q->int_ops); | 141 | BUG_ON(!q->int_ops); |
142 | 142 | ||
143 | mutex_init(&q->vb_lock); | 143 | mutex_init(&q->vb_lock); |
144 | init_waitqueue_head(&q->wait); | ||
144 | INIT_LIST_HEAD(&q->stream); | 145 | INIT_LIST_HEAD(&q->stream); |
145 | } | 146 | } |
146 | 147 | ||
@@ -188,6 +189,10 @@ void videobuf_queue_cancel(struct videobuf_queue *q) | |||
188 | unsigned long flags = 0; | 189 | unsigned long flags = 0; |
189 | int i; | 190 | int i; |
190 | 191 | ||
192 | q->streaming = 0; | ||
193 | q->reading = 0; | ||
194 | wake_up_interruptible_sync(&q->wait); | ||
195 | |||
191 | /* remove queued buffers from list */ | 196 | /* remove queued buffers from list */ |
192 | if (q->irqlock) | 197 | if (q->irqlock) |
193 | spin_lock_irqsave(q->irqlock, flags); | 198 | spin_lock_irqsave(q->irqlock, flags); |
@@ -565,6 +570,7 @@ int videobuf_qbuf(struct videobuf_queue *q, | |||
565 | } | 570 | } |
566 | dprintk(1, "qbuf: succeded\n"); | 571 | dprintk(1, "qbuf: succeded\n"); |
567 | retval = 0; | 572 | retval = 0; |
573 | wake_up_interruptible_sync(&q->wait); | ||
568 | 574 | ||
569 | done: | 575 | done: |
570 | mutex_unlock(&q->vb_lock); | 576 | mutex_unlock(&q->vb_lock); |
@@ -575,37 +581,88 @@ int videobuf_qbuf(struct videobuf_queue *q, | |||
575 | return retval; | 581 | return retval; |
576 | } | 582 | } |
577 | 583 | ||
578 | int videobuf_dqbuf(struct videobuf_queue *q, | 584 | |
579 | struct v4l2_buffer *b, int nonblocking) | 585 | /* Locking: Caller holds q->vb_lock */ |
586 | static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) | ||
580 | { | 587 | { |
581 | struct videobuf_buffer *buf; | ||
582 | int retval; | 588 | int retval; |
583 | 589 | ||
584 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); | 590 | checks: |
585 | 591 | if (!q->streaming) { | |
586 | mutex_lock(&q->vb_lock); | 592 | dprintk(1, "next_buffer: Not streaming\n"); |
587 | retval = -EBUSY; | 593 | retval = -EINVAL; |
588 | if (q->reading) { | ||
589 | dprintk(1, "dqbuf: Reading running...\n"); | ||
590 | goto done; | ||
591 | } | ||
592 | retval = -EINVAL; | ||
593 | if (b->type != q->type) { | ||
594 | dprintk(1, "dqbuf: Wrong type.\n"); | ||
595 | goto done; | 594 | goto done; |
596 | } | 595 | } |
596 | |||
597 | if (list_empty(&q->stream)) { | 597 | if (list_empty(&q->stream)) { |
598 | dprintk(1, "dqbuf: stream running\n"); | 598 | if (noblock) { |
599 | goto done; | 599 | retval = -EAGAIN; |
600 | dprintk(2, "next_buffer: no buffers to dequeue\n"); | ||
601 | goto done; | ||
602 | } else { | ||
603 | dprintk(2, "next_buffer: waiting on buffer\n"); | ||
604 | |||
605 | /* Drop lock to avoid deadlock with qbuf */ | ||
606 | mutex_unlock(&q->vb_lock); | ||
607 | |||
608 | /* Checking list_empty and streaming is safe without | ||
609 | * locks because we goto checks to validate while | ||
610 | * holding locks before proceeding */ | ||
611 | retval = wait_event_interruptible(q->wait, | ||
612 | !list_empty(&q->stream) || !q->streaming); | ||
613 | mutex_lock(&q->vb_lock); | ||
614 | |||
615 | if (retval) | ||
616 | goto done; | ||
617 | |||
618 | goto checks; | ||
619 | } | ||
600 | } | 620 | } |
621 | |||
622 | retval = 0; | ||
623 | |||
624 | done: | ||
625 | return retval; | ||
626 | } | ||
627 | |||
628 | |||
629 | /* Locking: Caller holds q->vb_lock */ | ||
630 | static int stream_next_buffer(struct videobuf_queue *q, | ||
631 | struct videobuf_buffer **vb, int nonblocking) | ||
632 | { | ||
633 | int retval; | ||
634 | struct videobuf_buffer *buf = NULL; | ||
635 | |||
636 | retval = stream_next_buffer_check_queue(q, nonblocking); | ||
637 | if (retval) | ||
638 | goto done; | ||
639 | |||
601 | buf = list_entry(q->stream.next, struct videobuf_buffer, stream); | 640 | buf = list_entry(q->stream.next, struct videobuf_buffer, stream); |
602 | mutex_unlock(&q->vb_lock); | ||
603 | retval = videobuf_waiton(buf, nonblocking, 1); | 641 | retval = videobuf_waiton(buf, nonblocking, 1); |
642 | if (retval < 0) | ||
643 | goto done; | ||
644 | |||
645 | *vb = buf; | ||
646 | done: | ||
647 | return retval; | ||
648 | } | ||
649 | |||
650 | int videobuf_dqbuf(struct videobuf_queue *q, | ||
651 | struct v4l2_buffer *b, int nonblocking) | ||
652 | { | ||
653 | struct videobuf_buffer *buf = NULL; | ||
654 | int retval; | ||
655 | |||
656 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); | ||
657 | |||
604 | mutex_lock(&q->vb_lock); | 658 | mutex_lock(&q->vb_lock); |
659 | |||
660 | retval = stream_next_buffer(q, &buf, nonblocking); | ||
605 | if (retval < 0) { | 661 | if (retval < 0) { |
606 | dprintk(1, "dqbuf: waiton returned %d\n", retval); | 662 | dprintk(1, "dqbuf: next_buffer error: %i\n", retval); |
607 | goto done; | 663 | goto done; |
608 | } | 664 | } |
665 | |||
609 | switch (buf->state) { | 666 | switch (buf->state) { |
610 | case VIDEOBUF_ERROR: | 667 | case VIDEOBUF_ERROR: |
611 | dprintk(1, "dqbuf: state is error\n"); | 668 | dprintk(1, "dqbuf: state is error\n"); |
@@ -654,6 +711,7 @@ int videobuf_streamon(struct videobuf_queue *q) | |||
654 | if (q->irqlock) | 711 | if (q->irqlock) |
655 | spin_unlock_irqrestore(q->irqlock, flags); | 712 | spin_unlock_irqrestore(q->irqlock, flags); |
656 | 713 | ||
714 | wake_up_interruptible_sync(&q->wait); | ||
657 | done: | 715 | done: |
658 | mutex_unlock(&q->vb_lock); | 716 | mutex_unlock(&q->vb_lock); |
659 | return retval; | 717 | return retval; |
@@ -666,7 +724,6 @@ static int __videobuf_streamoff(struct videobuf_queue *q) | |||
666 | return -EINVAL; | 724 | return -EINVAL; |
667 | 725 | ||
668 | videobuf_queue_cancel(q); | 726 | videobuf_queue_cancel(q); |
669 | q->streaming = 0; | ||
670 | 727 | ||
671 | return 0; | 728 | return 0; |
672 | } | 729 | } |
@@ -869,7 +926,6 @@ static void __videobuf_read_stop(struct videobuf_queue *q) | |||
869 | q->bufs[i] = NULL; | 926 | q->bufs[i] = NULL; |
870 | } | 927 | } |
871 | q->read_buf = NULL; | 928 | q->read_buf = NULL; |
872 | q->reading = 0; | ||
873 | 929 | ||
874 | } | 930 | } |
875 | 931 | ||
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index fcdffdd63304..377a6c6e931b 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h | |||
@@ -153,6 +153,8 @@ struct videobuf_queue { | |||
153 | spinlock_t *irqlock; | 153 | spinlock_t *irqlock; |
154 | struct device *dev; | 154 | struct device *dev; |
155 | 155 | ||
156 | wait_queue_head_t wait; /* wait if queue is empty */ | ||
157 | |||
156 | enum v4l2_buf_type type; | 158 | enum v4l2_buf_type type; |
157 | unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ | 159 | unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */ |
158 | unsigned int msize; | 160 | unsigned int msize; |