]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/line6/capture.c
fd4890de8dbcd3cf6837099d29d5fa608ec5d40c
[net-next-2.6.git] / drivers / staging / line6 / capture.c
1 /*
2  * Line6 Linux USB driver - 0.8.0
3  *
4  * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License as
8  *      published by the Free Software Foundation, version 2.
9  *
10  */
11
12 #include "driver.h"
13
14 #include <sound/core.h>
15 #include <sound/pcm.h>
16 #include <sound/pcm_params.h>
17
18 #include "audio.h"
19 #include "pcm.h"
20 #include "pod.h"
21 #include "capture.h"
22
23 /*
24         Find a free URB and submit it.
25 */
26 static int submit_audio_in_urb(struct snd_pcm_substream *substream)
27 {
28         unsigned int index;
29         unsigned long flags;
30         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
31         int i, urb_size;
32         struct urb *urb_in;
33
34         spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
35         index =
36             find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
37
38         if (index >= LINE6_ISO_BUFFERS) {
39                 spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
40                 dev_err(s2m(substream), "no free URB found\n");
41                 return -EINVAL;
42         }
43
44         urb_in = line6pcm->urb_audio_in[index];
45         urb_size = 0;
46
47         for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
48                 struct usb_iso_packet_descriptor *fin =
49                     &urb_in->iso_frame_desc[i];
50                 fin->offset = urb_size;
51                 fin->length = line6pcm->max_packet_size;
52                 urb_size += line6pcm->max_packet_size;
53         }
54
55         urb_in->transfer_buffer =
56             line6pcm->buffer_in +
57             index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
58         urb_in->transfer_buffer_length = urb_size;
59         urb_in->context = substream;
60
61         if (usb_submit_urb(urb_in, GFP_ATOMIC) == 0)
62                 set_bit(index, &line6pcm->active_urb_in);
63         else
64                 dev_err(s2m(substream), "URB in #%d submission failed\n",
65                         index);
66
67         spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
68         return 0;
69 }
70
71 /*
72         Submit all currently available capture URBs.
73 */
74 static int submit_audio_in_all_urbs(struct snd_pcm_substream *substream)
75 {
76         int ret, i;
77
78         for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
79                 ret = submit_audio_in_urb(substream);
80                 if (ret < 0)
81                         return ret;
82         }
83
84         return 0;
85 }
86
87 /*
88         Unlink all currently active capture URBs.
89 */
90 static void unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
91 {
92         unsigned int i;
93
94         for (i = LINE6_ISO_BUFFERS; i--;) {
95                 if (test_bit(i, &line6pcm->active_urb_in)) {
96                         if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
97                                 struct urb *u = line6pcm->urb_audio_in[i];
98                                 usb_unlink_urb(u);
99                         }
100                 }
101         }
102 }
103
104 /*
105         Wait until unlinking of all currently active capture URBs has been
106         finished.
107 */
108 static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
109 {
110         int timeout = HZ;
111         unsigned int i;
112         int alive;
113
114         do {
115                 alive = 0;
116                 for (i = LINE6_ISO_BUFFERS; i--;) {
117                         if (test_bit(i, &line6pcm->active_urb_in))
118                                 alive++;
119                 }
120                 if (!alive)
121                         break;
122                 set_current_state(TASK_UNINTERRUPTIBLE);
123                 schedule_timeout(1);
124         } while (--timeout > 0);
125         if (alive)
126                 snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
127
128         line6pcm->active_urb_in = 0;
129         line6pcm->unlink_urb_in = 0;
130 }
131
132 /*
133         Unlink all currently active capture URBs, and wait for finishing.
134 */
135 void unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
136 {
137         unlink_audio_in_urbs(line6pcm);
138         wait_clear_audio_in_urbs(line6pcm);
139 }
140
141 /*
142         Callback for completed capture URB.
143 */
144 static void audio_in_callback(struct urb *urb)
145 {
146         int i, index, length = 0, shutdown = 0;
147         int frames;
148         unsigned long flags;
149
150         struct snd_pcm_substream *substream =
151             (struct snd_pcm_substream *)urb->context;
152         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
153         const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
154         struct snd_pcm_runtime *runtime = substream->runtime;
155
156         /* find index of URB */
157         for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
158                 if (urb == line6pcm->urb_audio_in[index])
159                         break;
160
161 #if DO_DUMP_PCM_RECEIVE
162         for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
163                 struct usb_iso_packet_descriptor *fout =
164                     &urb->iso_frame_desc[i];
165                 line6_write_hexdump(line6pcm->line6, 'C',
166                                     urb->transfer_buffer + fout->offset,
167                                     fout->length);
168         }
169 #endif
170
171         spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
172
173         for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
174                 char *fbuf;
175                 int fsize;
176                 struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
177
178                 if (fin->status == -18) {
179                         shutdown = 1;
180                         break;
181                 }
182
183                 fbuf = urb->transfer_buffer + fin->offset;
184                 fsize = fin->actual_length;
185                 length += fsize;
186
187                 if (fsize > 0) {
188                         frames = fsize / bytes_per_frame;
189
190                         if (line6pcm->pos_in_done + frames >
191                             runtime->buffer_size) {
192                                 /*
193                                    The transferred area goes over buffer
194                                    boundary, copy two separate chunks.
195                                  */
196                                 int len;
197                                 len =
198                                     runtime->buffer_size -
199                                     line6pcm->pos_in_done;
200
201                                 if (len > 0) {
202                                         memcpy(runtime->dma_area +
203                                                line6pcm->pos_in_done *
204                                                bytes_per_frame, fbuf,
205                                                len * bytes_per_frame);
206                                         memcpy(runtime->dma_area,
207                                                fbuf + len * bytes_per_frame,
208                                                (frames -
209                                                 len) * bytes_per_frame);
210                                 } else {
211                                         /* this is somewhat paranoid */
212                                         dev_err(s2m(substream),
213                                                 "driver bug: len = %d\n", len);
214                                 }
215                         } else {
216                                 /* copy single chunk */
217                                 memcpy(runtime->dma_area +
218                                        line6pcm->pos_in_done * bytes_per_frame,
219                                        fbuf, fsize * bytes_per_frame);
220                         }
221
222                         line6pcm->pos_in_done += frames;
223                         if (line6pcm->pos_in_done >= runtime->buffer_size)
224                                 line6pcm->pos_in_done -= runtime->buffer_size;
225                 }
226         }
227
228         clear_bit(index, &line6pcm->active_urb_in);
229
230         if (test_bit(index, &line6pcm->unlink_urb_in))
231                 shutdown = 1;
232
233         spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
234
235         if (!shutdown) {
236                 submit_audio_in_urb(substream);
237
238                 line6pcm->bytes_in += length;
239                 if (line6pcm->bytes_in >= line6pcm->period_in) {
240                         line6pcm->bytes_in -= line6pcm->period_in;
241                         snd_pcm_period_elapsed(substream);
242                 }
243         }
244 }
245
246 /* open capture callback */
247 static int snd_line6_capture_open(struct snd_pcm_substream *substream)
248 {
249         int err;
250         struct snd_pcm_runtime *runtime = substream->runtime;
251         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
252
253         err = snd_pcm_hw_constraint_ratdens(runtime, 0,
254                                             SNDRV_PCM_HW_PARAM_RATE,
255                                             (&line6pcm->properties->
256                                              snd_line6_rates));
257         if (err < 0)
258                 return err;
259
260         runtime->hw = line6pcm->properties->snd_line6_capture_hw;
261         return 0;
262 }
263
264 /* close capture callback */
265 static int snd_line6_capture_close(struct snd_pcm_substream *substream)
266 {
267         return 0;
268 }
269
270 /* hw_params capture callback */
271 static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
272                                        struct snd_pcm_hw_params *hw_params)
273 {
274         int ret;
275         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
276
277         /* -- Florian Demski [FD] */
278         /* don't ask me why, but this fixes the bug on my machine */
279         if (line6pcm == NULL) {
280                 if (substream->pcm == NULL)
281                         return -ENOMEM;
282                 if (substream->pcm->private_data == NULL)
283                         return -ENOMEM;
284                 substream->private_data = substream->pcm->private_data;
285                 line6pcm = snd_pcm_substream_chip(substream);
286         }
287         /* -- [FD] end */
288
289         ret = snd_pcm_lib_malloc_pages(substream,
290                                        params_buffer_bytes(hw_params));
291         if (ret < 0)
292                 return ret;
293
294         line6pcm->period_in = params_period_bytes(hw_params);
295         line6pcm->buffer_in =
296             kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
297                     LINE6_ISO_PACKET_SIZE_MAX, GFP_KERNEL);
298
299         if (!line6pcm->buffer_in) {
300                 dev_err(s2m(substream), "cannot malloc buffer_in\n");
301                 return -ENOMEM;
302         }
303
304         return 0;
305 }
306
307 /* hw_free capture callback */
308 static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
309 {
310         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
311         unlink_wait_clear_audio_in_urbs(line6pcm);
312
313         kfree(line6pcm->buffer_in);
314         line6pcm->buffer_in = NULL;
315
316         return snd_pcm_lib_free_pages(substream);
317 }
318
319 /* trigger callback */
320 int snd_line6_capture_trigger(struct snd_pcm_substream *substream, int cmd)
321 {
322         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
323         int err;
324         line6pcm->count_in = 0;
325
326         switch (cmd) {
327         case SNDRV_PCM_TRIGGER_START:
328                 if (!test_and_set_bit(BIT_RUNNING_CAPTURE, &line6pcm->flags)) {
329                         err = submit_audio_in_all_urbs(substream);
330
331                         if (err < 0) {
332                                 clear_bit(BIT_RUNNING_CAPTURE,
333                                           &line6pcm->flags);
334                                 return err;
335                         }
336                 }
337
338                 break;
339
340         case SNDRV_PCM_TRIGGER_STOP:
341                 if (test_and_clear_bit(BIT_RUNNING_CAPTURE, &line6pcm->flags))
342                         unlink_audio_in_urbs(line6pcm);
343
344                 break;
345
346         default:
347                 return -EINVAL;
348         }
349
350         return 0;
351 }
352
353 /* capture pointer callback */
354 static snd_pcm_uframes_t
355 snd_line6_capture_pointer(struct snd_pcm_substream *substream)
356 {
357         struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
358         return line6pcm->pos_in_done;
359 }
360
361 /* capture operators */
362 struct snd_pcm_ops snd_line6_capture_ops = {
363         .open = snd_line6_capture_open,
364         .close = snd_line6_capture_close,
365         .ioctl = snd_pcm_lib_ioctl,
366         .hw_params = snd_line6_capture_hw_params,
367         .hw_free = snd_line6_capture_hw_free,
368         .prepare = snd_line6_prepare,
369         .trigger = snd_line6_trigger,
370         .pointer = snd_line6_capture_pointer,
371 };
372
373 int create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
374 {
375         int i;
376
377         /* create audio URBs and fill in constant values: */
378         for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
379                 struct urb *urb;
380
381                 /* URB for audio in: */
382                 urb = line6pcm->urb_audio_in[i] =
383                     usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
384
385                 if (urb == NULL) {
386                         dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
387                         return -ENOMEM;
388                 }
389
390                 urb->dev = line6pcm->line6->usbdev;
391                 urb->pipe =
392                     usb_rcvisocpipe(line6pcm->line6->usbdev,
393                                     line6pcm->
394                                     ep_audio_read & USB_ENDPOINT_NUMBER_MASK);
395                 urb->transfer_flags = URB_ISO_ASAP;
396                 urb->start_frame = -1;
397                 urb->number_of_packets = LINE6_ISO_PACKETS;
398                 urb->interval = LINE6_ISO_INTERVAL;
399                 urb->error_count = 0;
400                 urb->complete = audio_in_callback;
401         }
402
403         return 0;
404 }