aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18/cx18-queue.c')
-rw-r--r--drivers/media/video/cx18/cx18-queue.c118
1 files changed, 77 insertions, 41 deletions
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index 174682c2582f..8d9441e88c4e 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -4,6 +4,7 @@
4 * Derived from ivtv-queue.c 4 * Derived from ivtv-queue.c
5 * 5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 * Copyright (C) 2008 Andy Walls <awalls@radix.net>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
@@ -41,91 +42,126 @@ void cx18_queue_init(struct cx18_queue *q)
41 q->bytesused = 0; 42 q->bytesused = 0;
42} 43}
43 44
44void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, 45struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
45 struct cx18_queue *q) 46 struct cx18_queue *q, int to_front)
46{ 47{
47 unsigned long flags = 0; 48 /* clear the buffer if it is not to be enqueued to the full queue */
48 49 if (q != &s->q_full) {
49 /* clear the buffer if it is going to be enqueued to the free queue */
50 if (q == &s->q_free) {
51 buf->bytesused = 0; 50 buf->bytesused = 0;
52 buf->readpos = 0; 51 buf->readpos = 0;
53 buf->b_flags = 0; 52 buf->b_flags = 0;
53 buf->skipped = 0;
54 } 54 }
55 spin_lock_irqsave(&s->qlock, flags); 55
56 list_add_tail(&buf->list, &q->list); 56 mutex_lock(&s->qlock);
57 atomic_inc(&q->buffers); 57
58 /* q_busy is restricted to a max buffer count imposed by firmware */
59 if (q == &s->q_busy &&
60 atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
61 q = &s->q_free;
62
63 if (to_front)
64 list_add(&buf->list, &q->list); /* LIFO */
65 else
66 list_add_tail(&buf->list, &q->list); /* FIFO */
58 q->bytesused += buf->bytesused - buf->readpos; 67 q->bytesused += buf->bytesused - buf->readpos;
59 spin_unlock_irqrestore(&s->qlock, flags); 68 atomic_inc(&q->buffers);
69
70 mutex_unlock(&s->qlock);
71 return q;
60} 72}
61 73
62struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) 74struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
63{ 75{
64 struct cx18_buffer *buf = NULL; 76 struct cx18_buffer *buf = NULL;
65 unsigned long flags = 0;
66 77
67 spin_lock_irqsave(&s->qlock, flags); 78 mutex_lock(&s->qlock);
68 if (!list_empty(&q->list)) { 79 if (!list_empty(&q->list)) {
69 buf = list_entry(q->list.next, struct cx18_buffer, list); 80 buf = list_first_entry(&q->list, struct cx18_buffer, list);
70 list_del_init(q->list.next); 81 list_del_init(&buf->list);
71 atomic_dec(&q->buffers);
72 q->bytesused -= buf->bytesused - buf->readpos; 82 q->bytesused -= buf->bytesused - buf->readpos;
83 buf->skipped = 0;
84 atomic_dec(&q->buffers);
73 } 85 }
74 spin_unlock_irqrestore(&s->qlock, flags); 86 mutex_unlock(&s->qlock);
75 return buf; 87 return buf;
76} 88}
77 89
78struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, 90struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
79 u32 bytesused) 91 u32 bytesused)
80{ 92{
81 struct cx18 *cx = s->cx; 93 struct cx18 *cx = s->cx;
82 struct list_head *p; 94 struct cx18_buffer *buf;
83 95 struct cx18_buffer *tmp;
84 spin_lock(&s->qlock); 96 struct cx18_buffer *ret = NULL;
85 list_for_each(p, &s->q_free.list) { 97
86 struct cx18_buffer *buf = 98 mutex_lock(&s->qlock);
87 list_entry(p, struct cx18_buffer, list); 99 list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) {
88 100 if (buf->id != id) {
89 if (buf->id != id) 101 buf->skipped++;
102 if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) {
103 /* buffer must have fallen out of rotation */
104 CX18_WARN("Skipped %s, buffer %d, %d "
105 "times - it must have dropped out of "
106 "rotation\n", s->name, buf->id,
107 buf->skipped);
108 /* move it to q_free */
109 list_move_tail(&buf->list, &s->q_free.list);
110 buf->bytesused = buf->readpos = buf->b_flags =
111 buf->skipped = 0;
112 atomic_dec(&s->q_busy.buffers);
113 atomic_inc(&s->q_free.buffers);
114 }
90 continue; 115 continue;
116 }
91 117
92 buf->bytesused = bytesused; 118 buf->bytesused = bytesused;
93 atomic_dec(&s->q_free.buffers); 119 /* Sync the buffer before we release the qlock */
94 atomic_inc(&s->q_full.buffers); 120 cx18_buf_sync_for_cpu(s, buf);
95 s->q_full.bytesused += buf->bytesused; 121 if (s->type == CX18_ENC_STREAM_TYPE_TS) {
96 list_move_tail(&buf->list, &s->q_full.list); 122 /*
123 * TS doesn't use q_full. As we pull the buffer off of
124 * the queue here, the caller will have to put it back.
125 */
126 list_del_init(&buf->list);
127 } else {
128 /* Move buffer from q_busy to q_full */
129 list_move_tail(&buf->list, &s->q_full.list);
130 set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
131 s->q_full.bytesused += buf->bytesused;
132 atomic_inc(&s->q_full.buffers);
133 }
134 atomic_dec(&s->q_busy.buffers);
97 135
98 spin_unlock(&s->qlock); 136 ret = buf;
99 return buf; 137 break;
100 } 138 }
101 spin_unlock(&s->qlock); 139 mutex_unlock(&s->qlock);
102 CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); 140 return ret;
103 return NULL;
104} 141}
105 142
106/* Move all buffers of a queue to q_free, while flushing the buffers */ 143/* Move all buffers of a queue to q_free, while flushing the buffers */
107static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) 144static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
108{ 145{
109 unsigned long flags;
110 struct cx18_buffer *buf; 146 struct cx18_buffer *buf;
111 147
112 if (q == &s->q_free) 148 if (q == &s->q_free)
113 return; 149 return;
114 150
115 spin_lock_irqsave(&s->qlock, flags); 151 mutex_lock(&s->qlock);
116 while (!list_empty(&q->list)) { 152 while (!list_empty(&q->list)) {
117 buf = list_entry(q->list.next, struct cx18_buffer, list); 153 buf = list_first_entry(&q->list, struct cx18_buffer, list);
118 list_move_tail(q->list.next, &s->q_free.list); 154 list_move_tail(&buf->list, &s->q_free.list);
119 buf->bytesused = buf->readpos = buf->b_flags = 0; 155 buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0;
120 atomic_inc(&s->q_free.buffers); 156 atomic_inc(&s->q_free.buffers);
121 } 157 }
122 cx18_queue_init(q); 158 cx18_queue_init(q);
123 spin_unlock_irqrestore(&s->qlock, flags); 159 mutex_unlock(&s->qlock);
124} 160}
125 161
126void cx18_flush_queues(struct cx18_stream *s) 162void cx18_flush_queues(struct cx18_stream *s)
127{ 163{
128 cx18_queue_flush(s, &s->q_io); 164 cx18_queue_flush(s, &s->q_busy);
129 cx18_queue_flush(s, &s->q_full); 165 cx18_queue_flush(s, &s->q_full);
130} 166}
131 167