RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / media / video / ivtv / ivtv-queue.c
bloba04f9387f63df4127668d42dfa9143154ce4e0c1
1 /*
2 buffer queues.
3 Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
4 Copyright (C) 2004 Chris Kennedy <c@groovy.org>
5 Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "ivtv-driver.h"
23 #include "ivtv-streams.h"
24 #include "ivtv-queue.h"
25 #include "ivtv-mailbox.h"
27 int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
29 if (s->buf_size - buf->bytesused < copybytes)
30 copybytes = s->buf_size - buf->bytesused;
31 if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) {
32 return -EFAULT;
34 buf->bytesused += copybytes;
35 return copybytes;
38 void ivtv_buf_swap(struct ivtv_buffer *buf)
40 int i;
42 for (i = 0; i < buf->bytesused; i += 4)
43 swab32s((u32 *)(buf->buf + i));
46 void ivtv_queue_init(struct ivtv_queue *q)
48 INIT_LIST_HEAD(&q->list);
49 q->buffers = 0;
50 q->length = 0;
51 q->bytesused = 0;
54 void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
56 unsigned long flags = 0;
58 /* clear the buffer if it is going to be enqueued to the free queue */
59 if (q == &s->q_free) {
60 buf->bytesused = 0;
61 buf->readpos = 0;
62 buf->b_flags = 0;
64 spin_lock_irqsave(&s->qlock, flags);
65 list_add_tail(&buf->list, &q->list);
66 q->buffers++;
67 q->length += s->buf_size;
68 q->bytesused += buf->bytesused - buf->readpos;
69 spin_unlock_irqrestore(&s->qlock, flags);
72 struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
74 struct ivtv_buffer *buf = NULL;
75 unsigned long flags = 0;
77 spin_lock_irqsave(&s->qlock, flags);
78 if (!list_empty(&q->list)) {
79 buf = list_entry(q->list.next, struct ivtv_buffer, list);
80 list_del_init(q->list.next);
81 q->buffers--;
82 q->length -= s->buf_size;
83 q->bytesused -= buf->bytesused - buf->readpos;
85 spin_unlock_irqrestore(&s->qlock, flags);
86 return buf;
89 static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
90 struct ivtv_queue *to, int clear, int full)
92 struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
94 list_move_tail(from->list.next, &to->list);
95 from->buffers--;
96 from->length -= s->buf_size;
97 from->bytesused -= buf->bytesused - buf->readpos;
98 /* special handling for q_free */
99 if (clear)
100 buf->bytesused = buf->readpos = buf->b_flags = 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;
107 to->buffers++;
108 to->length += s->buf_size;
109 to->bytesused += buf->bytesused - buf->readpos;
112 /* 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'.
114 If 'steal' != NULL, then buffers may also taken from that queue if
115 needed.
117 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
119 the 'from' queue is the free queue.
121 When 'from' is q_free, then needed_bytes is compared to the total
122 available buffer length, otherwise needed_bytes is compared to the
123 bytesused value. For the 'steal' queue the total available buffer
124 length is always used.
126 -ENOMEM is returned if the buffers could not be obtained, 0 if all
127 buffers where obtained from the 'from' list and if non-zero then
128 the number of stolen buffers is returned. */
129 int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
130 struct ivtv_queue *to, int needed_bytes)
132 unsigned long flags;
133 int rc = 0;
134 int from_free = from == &s->q_free;
135 int to_free = to == &s->q_free;
136 int bytes_available;
138 spin_lock_irqsave(&s->qlock, flags);
139 if (needed_bytes == 0) {
140 from_free = 1;
141 needed_bytes = from->length;
144 bytes_available = from_free ? from->length : from->bytesused;
145 bytes_available += steal ? steal->length : 0;
147 if (bytes_available < needed_bytes) {
148 spin_unlock_irqrestore(&s->qlock, flags);
149 return -ENOMEM;
151 if (from_free) {
152 u32 old_length = to->length;
154 while (to->length - old_length < needed_bytes) {
155 if (list_empty(&from->list))
156 from = steal;
157 if (from == steal)
158 rc++; /* keep track of 'stolen' buffers */
159 ivtv_queue_move_buf(s, from, to, 1, 0);
162 else {
163 u32 old_bytesused = to->bytesused;
165 while (to->bytesused - old_bytesused < needed_bytes) {
166 if (list_empty(&from->list))
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);
173 spin_unlock_irqrestore(&s->qlock, flags);
174 return rc;
177 void ivtv_flush_queues(struct ivtv_stream *s)
179 ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
180 ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
181 ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
182 ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
185 int ivtv_stream_alloc(struct ivtv_stream *s)
187 struct ivtv *itv = s->itv;
188 int SGsize = sizeof(struct ivtv_SG_element) * s->buffers;
189 int i;
191 if (s->buffers == 0)
192 return 0;
194 IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n",
195 s->dma != PCI_DMA_NONE ? "DMA " : "",
196 s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
198 if (ivtv_might_use_pio(s)) {
199 s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
200 if (s->PIOarray == NULL) {
201 IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name);
202 return -ENOMEM;
206 /* Allocate DMA SG Arrays */
207 s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
208 if (s->SGarray == NULL) {
209 IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
210 if (ivtv_might_use_pio(s)) {
211 kfree(s->PIOarray);
212 s->PIOarray = NULL;
214 return -ENOMEM;
216 s->SG_length = 0;
217 if (ivtv_might_use_dma(s)) {
218 s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
219 ivtv_stream_sync_for_cpu(s);
222 /* allocate stream buffers. Initially all buffers are in q_free. */
223 for (i = 0; i < s->buffers; i++) {
224 struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
226 if (buf == NULL)
227 break;
228 buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
229 if (buf->buf == NULL) {
230 kfree(buf);
231 break;
233 INIT_LIST_HEAD(&buf->list);
234 if (ivtv_might_use_dma(s)) {
235 buf->dma_handle = pci_map_single(s->itv->dev,
236 buf->buf, s->buf_size + 256, s->dma);
237 ivtv_buf_sync_for_cpu(s, buf);
239 ivtv_enqueue(s, buf, &s->q_free);
241 if (i == s->buffers)
242 return 0;
243 IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
244 ivtv_stream_free(s);
245 return -ENOMEM;
248 void ivtv_stream_free(struct ivtv_stream *s)
250 struct ivtv_buffer *buf;
252 /* move all buffers to q_free */
253 ivtv_flush_queues(s);
255 /* empty q_free */
256 while ((buf = ivtv_dequeue(s, &s->q_free))) {
257 if (ivtv_might_use_dma(s))
258 pci_unmap_single(s->itv->dev, buf->dma_handle,
259 s->buf_size + 256, s->dma);
260 kfree(buf->buf);
261 kfree(buf);
264 /* Free SG Array/Lists */
265 if (s->SGarray != NULL) {
266 if (s->SG_handle != IVTV_DMA_UNMAPPED) {
267 pci_unmap_single(s->itv->dev, s->SG_handle,
268 sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
269 s->SG_handle = IVTV_DMA_UNMAPPED;
271 kfree(s->SGarray);
272 kfree(s->PIOarray);
273 s->PIOarray = NULL;
274 s->SGarray = NULL;
275 s->SG_length = 0;