]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/video/ivtv/ivtv-queue.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6-omap-h63xx.git] / drivers / media / video / ivtv / ivtv-queue.c
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>
6
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.
11
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.
16
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
20  */
21
22 #include "ivtv-driver.h"
23 #include "ivtv-streams.h"
24 #include "ivtv-queue.h"
25 #include "ivtv-mailbox.h"
26
27 int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
28 {
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;
33         }
34         buf->bytesused += copybytes;
35         return copybytes;
36 }
37
38 void ivtv_buf_swap(struct ivtv_buffer *buf)
39 {
40         int i;
41
42         for (i = 0; i < buf->bytesused; i += 4)
43                 swab32s((u32 *)(buf->buf + i));
44 }
45
46 void ivtv_queue_init(struct ivtv_queue *q)
47 {
48         INIT_LIST_HEAD(&q->list);
49         q->buffers = 0;
50         q->length = 0;
51         q->bytesused = 0;
52 }
53
54 void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
55 {
56         unsigned long flags = 0;
57
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;
63         }
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);
70 }
71
72 struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
73 {
74         struct ivtv_buffer *buf = NULL;
75         unsigned long flags = 0;
76
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;
84         }
85         spin_unlock_irqrestore(&s->qlock, flags);
86         return buf;
87 }
88
89 static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
90                 struct ivtv_queue *to, int clear, int full)
91 {
92         struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
93
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;
106         }
107         to->buffers++;
108         to->length += s->buf_size;
109         to->bytesused += buf->bytesused - buf->readpos;
110 }
111
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.
116
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.
120
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.
125
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)
131 {
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;
137
138         spin_lock_irqsave(&s->qlock, flags);
139         if (needed_bytes == 0) {
140                 from_free = 1;
141                 needed_bytes = from->length;
142         }
143
144         bytes_available = from_free ? from->length : from->bytesused;
145         bytes_available += steal ? steal->length : 0;
146
147         if (bytes_available < needed_bytes) {
148                 spin_unlock_irqrestore(&s->qlock, flags);
149                 return -ENOMEM;
150         }
151         if (from_free) {
152                 u32 old_length = to->length;
153
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);
160                 }
161         }
162         else {
163                 u32 old_bytesused = to->bytesused;
164
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);
171                 }
172         }
173         spin_unlock_irqrestore(&s->qlock, flags);
174         return rc;
175 }
176
177 void ivtv_flush_queues(struct ivtv_stream *s)
178 {
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);
183 }
184
185 int ivtv_stream_alloc(struct ivtv_stream *s)
186 {
187         struct ivtv *itv = s->itv;
188         int SGsize = sizeof(struct ivtv_SG_element) * s->buffers;
189         int i;
190
191         if (s->buffers == 0)
192                 return 0;
193
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);
197
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;
203                 }
204         }
205
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;
213                 }
214                 return -ENOMEM;
215         }
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);
220         }
221
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);
225
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;
232                 }
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);
238                 }
239                 ivtv_enqueue(s, buf, &s->q_free);
240         }
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;
246 }
247
248 void ivtv_stream_free(struct ivtv_stream *s)
249 {
250         struct ivtv_buffer *buf;
251
252         /* move all buffers to q_free */
253         ivtv_flush_queues(s);
254
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);
262         }
263
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;
270                 }
271                 kfree(s->SGarray);
272                 kfree(s->PIOarray);
273                 s->PIOarray = NULL;
274                 s->SGarray = NULL;
275                 s->SG_length = 0;
276         }
277 }