~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/staging/line6/capture.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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