Merge branch 'juju' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux13...
[linux-2.6] / 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         /* Allocate DMA SG Arrays */
199         if (s->dma != PCI_DMA_NONE) {
200                 s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
201                 if (s->SGarray == NULL) {
202                         IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
203                         return -ENOMEM;
204                 }
205                 s->SG_length = 0;
206                 s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
207                 ivtv_stream_sync_for_cpu(s);
208         }
209
210         /* allocate stream buffers. Initially all buffers are in q_free. */
211         for (i = 0; i < s->buffers; i++) {
212                 struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
213
214                 if (buf == NULL)
215                         break;
216                 buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
217                 if (buf->buf == NULL) {
218                         kfree(buf);
219                         break;
220                 }
221                 INIT_LIST_HEAD(&buf->list);
222                 if (s->dma != PCI_DMA_NONE) {
223                         buf->dma_handle = pci_map_single(s->itv->dev,
224                                 buf->buf, s->buf_size + 256, s->dma);
225                         ivtv_buf_sync_for_cpu(s, buf);
226                 }
227                 ivtv_enqueue(s, buf, &s->q_free);
228         }
229         if (i == s->buffers)
230                 return 0;
231         IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
232         ivtv_stream_free(s);
233         return -ENOMEM;
234 }
235
236 void ivtv_stream_free(struct ivtv_stream *s)
237 {
238         struct ivtv_buffer *buf;
239
240         /* move all buffers to q_free */
241         ivtv_flush_queues(s);
242
243         /* empty q_free */
244         while ((buf = ivtv_dequeue(s, &s->q_free))) {
245                 if (s->dma != PCI_DMA_NONE)
246                         pci_unmap_single(s->itv->dev, buf->dma_handle,
247                                 s->buf_size + 256, s->dma);
248                 kfree(buf->buf);
249                 kfree(buf);
250         }
251
252         /* Free SG Array/Lists */
253         if (s->SGarray != NULL) {
254                 if (s->SG_handle != IVTV_DMA_UNMAPPED) {
255                         pci_unmap_single(s->itv->dev, s->SG_handle,
256                                  sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
257                         s->SG_handle = IVTV_DMA_UNMAPPED;
258                 }
259                 s->SGarray = NULL;
260                 s->SG_length = 0;
261         }
262 }