aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/line6/pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/line6/pcm.c')
-rw-r--r--sound/usb/line6/pcm.c487
1 files changed, 487 insertions, 0 deletions
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
new file mode 100644
index 000000000000..8a6059adef69
--- /dev/null
+++ b/sound/usb/line6/pcm.c
@@ -0,0 +1,487 @@
1/*
2 * Line 6 Linux USB driver
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 <linux/slab.h>
13#include <linux/export.h>
14#include <sound/core.h>
15#include <sound/control.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18
19#include "capture.h"
20#include "driver.h"
21#include "playback.h"
22
23/* impulse response volume controls */
24static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
25 struct snd_ctl_elem_info *uinfo)
26{
27 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
28 uinfo->count = 1;
29 uinfo->value.integer.min = 0;
30 uinfo->value.integer.max = 255;
31 return 0;
32}
33
34static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
35 struct snd_ctl_elem_value *ucontrol)
36{
37 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
38
39 ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
40 return 0;
41}
42
43static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
44 struct snd_ctl_elem_value *ucontrol)
45{
46 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
47 int value = ucontrol->value.integer.value[0];
48
49 if (line6pcm->impulse_volume == value)
50 return 0;
51
52 line6pcm->impulse_volume = value;
53 if (value > 0)
54 line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
55 else
56 line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
57 return 1;
58}
59
60/* impulse response period controls */
61static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
62 struct snd_ctl_elem_info *uinfo)
63{
64 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
65 uinfo->count = 1;
66 uinfo->value.integer.min = 0;
67 uinfo->value.integer.max = 2000;
68 return 0;
69}
70
71static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
72 struct snd_ctl_elem_value *ucontrol)
73{
74 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
75
76 ucontrol->value.integer.value[0] = line6pcm->impulse_period;
77 return 0;
78}
79
80static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
81 struct snd_ctl_elem_value *ucontrol)
82{
83 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
84 int value = ucontrol->value.integer.value[0];
85
86 if (line6pcm->impulse_period == value)
87 return 0;
88
89 line6pcm->impulse_period = value;
90 return 1;
91}
92
93static bool test_flags(unsigned long flags0, unsigned long flags1,
94 unsigned long mask)
95{
96 return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
97}
98
99int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
100{
101 unsigned long flags_old, flags_new, flags_final;
102 int err;
103
104 do {
105 flags_old = ACCESS_ONCE(line6pcm->flags);
106 flags_new = flags_old | channels;
107 } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
108
109 flags_final = flags_old;
110
111 line6pcm->prev_fbuf = NULL;
112
113 if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
114 /* Invoked multiple times in a row so allocate once only */
115 if (!line6pcm->buffer_in) {
116 line6pcm->buffer_in =
117 kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
118 line6pcm->max_packet_size, GFP_KERNEL);
119 if (!line6pcm->buffer_in) {
120 err = -ENOMEM;
121 goto pcm_acquire_error;
122 }
123
124 flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
125 }
126 }
127
128 if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
129 /*
130 Waiting for completion of active URBs in the stop handler is
131 a bug, we therefore report an error if capturing is restarted
132 too soon.
133 */
134 if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
135 dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
136 return -EBUSY;
137 }
138
139 line6pcm->count_in = 0;
140 line6pcm->prev_fsize = 0;
141 err = line6_submit_audio_in_all_urbs(line6pcm);
142
143 if (err < 0)
144 goto pcm_acquire_error;
145
146 flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
147 }
148
149 if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
150 /* Invoked multiple times in a row so allocate once only */
151 if (!line6pcm->buffer_out) {
152 line6pcm->buffer_out =
153 kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
154 line6pcm->max_packet_size, GFP_KERNEL);
155 if (!line6pcm->buffer_out) {
156 err = -ENOMEM;
157 goto pcm_acquire_error;
158 }
159
160 flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
161 }
162 }
163
164 if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
165 /*
166 See comment above regarding PCM restart.
167 */
168 if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
169 dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
170 return -EBUSY;
171 }
172
173 line6pcm->count_out = 0;
174 err = line6_submit_audio_out_all_urbs(line6pcm);
175
176 if (err < 0)
177 goto pcm_acquire_error;
178
179 flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
180 }
181
182 return 0;
183
184pcm_acquire_error:
185 /*
186 If not all requested resources/streams could be obtained, release
187 those which were successfully obtained (if any).
188 */
189 line6_pcm_release(line6pcm, flags_final & channels);
190 return err;
191}
192EXPORT_SYMBOL_GPL(line6_pcm_acquire);
193
194int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
195{
196 unsigned long flags_old, flags_new;
197
198 do {
199 flags_old = ACCESS_ONCE(line6pcm->flags);
200 flags_new = flags_old & ~channels;
201 } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
202
203 if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
204 line6_unlink_audio_in_urbs(line6pcm);
205
206 if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
207 line6_wait_clear_audio_in_urbs(line6pcm);
208 line6_free_capture_buffer(line6pcm);
209 }
210
211 if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
212 line6_unlink_audio_out_urbs(line6pcm);
213
214 if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
215 line6_wait_clear_audio_out_urbs(line6pcm);
216 line6_free_playback_buffer(line6pcm);
217 }
218
219 return 0;
220}
221EXPORT_SYMBOL_GPL(line6_pcm_release);
222
223/* trigger callback */
224int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
225{
226 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
227 struct snd_pcm_substream *s;
228 int err;
229
230 spin_lock(&line6pcm->lock_trigger);
231 clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
232
233 snd_pcm_group_for_each_entry(s, substream) {
234 if (s->pcm->card != substream->pcm->card)
235 continue;
236 switch (s->stream) {
237 case SNDRV_PCM_STREAM_PLAYBACK:
238 err = snd_line6_playback_trigger(line6pcm, cmd);
239
240 if (err < 0) {
241 spin_unlock(&line6pcm->lock_trigger);
242 return err;
243 }
244
245 break;
246
247 case SNDRV_PCM_STREAM_CAPTURE:
248 err = snd_line6_capture_trigger(line6pcm, cmd);
249
250 if (err < 0) {
251 spin_unlock(&line6pcm->lock_trigger);
252 return err;
253 }
254
255 break;
256
257 default:
258 dev_err(line6pcm->line6->ifcdev,
259 "Unknown stream direction %d\n", s->stream);
260 }
261 }
262
263 spin_unlock(&line6pcm->lock_trigger);
264 return 0;
265}
266
267/* control info callback */
268static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
269 struct snd_ctl_elem_info *uinfo)
270{
271 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
272 uinfo->count = 2;
273 uinfo->value.integer.min = 0;
274 uinfo->value.integer.max = 256;
275 return 0;
276}
277
278/* control get callback */
279static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
280 struct snd_ctl_elem_value *ucontrol)
281{
282 int i;
283 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
284
285 for (i = 2; i--;)
286 ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
287
288 return 0;
289}
290
291/* control put callback */
292static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
293 struct snd_ctl_elem_value *ucontrol)
294{
295 int i, changed = 0;
296 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
297
298 for (i = 2; i--;)
299 if (line6pcm->volume_playback[i] !=
300 ucontrol->value.integer.value[i]) {
301 line6pcm->volume_playback[i] =
302 ucontrol->value.integer.value[i];
303 changed = 1;
304 }
305
306 return changed;
307}
308
309/* control definition */
310static struct snd_kcontrol_new line6_controls[] = {
311 {
312 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
313 .name = "PCM Playback Volume",
314 .info = snd_line6_control_playback_info,
315 .get = snd_line6_control_playback_get,
316 .put = snd_line6_control_playback_put
317 },
318 {
319 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
320 .name = "Impulse Response Volume",
321 .info = snd_line6_impulse_volume_info,
322 .get = snd_line6_impulse_volume_get,
323 .put = snd_line6_impulse_volume_put
324 },
325 {
326 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
327 .name = "Impulse Response Period",
328 .info = snd_line6_impulse_period_info,
329 .get = snd_line6_impulse_period_get,
330 .put = snd_line6_impulse_period_put
331 },
332};
333
334/*
335 Cleanup the PCM device.
336*/
337static void line6_cleanup_pcm(struct snd_pcm *pcm)
338{
339 int i;
340 struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
341
342 for (i = LINE6_ISO_BUFFERS; i--;) {
343 if (line6pcm->urb_audio_out[i]) {
344 usb_kill_urb(line6pcm->urb_audio_out[i]);
345 usb_free_urb(line6pcm->urb_audio_out[i]);
346 }
347 if (line6pcm->urb_audio_in[i]) {
348 usb_kill_urb(line6pcm->urb_audio_in[i]);
349 usb_free_urb(line6pcm->urb_audio_in[i]);
350 }
351 }
352 kfree(line6pcm);
353}
354
355/* create a PCM device */
356static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
357{
358 struct snd_pcm *pcm;
359 int err;
360
361 err = snd_pcm_new(line6->card, (char *)line6->properties->name,
362 0, 1, 1, pcm_ret);
363 if (err < 0)
364 return err;
365 pcm = *pcm_ret;
366 strcpy(pcm->name, line6->properties->name);
367
368 /* set operators */
369 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
370 &snd_line6_playback_ops);
371 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
372
373 /* pre-allocation of buffers */
374 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
375 snd_dma_continuous_data
376 (GFP_KERNEL), 64 * 1024,
377 128 * 1024);
378 return 0;
379}
380
381/*
382 Sync with PCM stream stops.
383*/
384void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
385{
386 line6_unlink_wait_clear_audio_out_urbs(line6pcm);
387 line6_unlink_wait_clear_audio_in_urbs(line6pcm);
388}
389
390/*
391 Create and register the PCM device and mixer entries.
392 Create URBs for playback and capture.
393*/
394int line6_init_pcm(struct usb_line6 *line6,
395 struct line6_pcm_properties *properties)
396{
397 int i, err;
398 unsigned ep_read = line6->properties->ep_audio_r;
399 unsigned ep_write = line6->properties->ep_audio_w;
400 struct snd_pcm *pcm;
401 struct snd_line6_pcm *line6pcm;
402
403 if (!(line6->properties->capabilities & LINE6_CAP_PCM))
404 return 0; /* skip PCM initialization and report success */
405
406 err = snd_line6_new_pcm(line6, &pcm);
407 if (err < 0)
408 return err;
409
410 line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
411 if (!line6pcm)
412 return -ENOMEM;
413
414 line6pcm->pcm = pcm;
415 line6pcm->properties = properties;
416 line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
417 line6pcm->volume_monitor = 255;
418 line6pcm->line6 = line6;
419
420 /* Read and write buffers are sized identically, so choose minimum */
421 line6pcm->max_packet_size = min(
422 usb_maxpacket(line6->usbdev,
423 usb_rcvisocpipe(line6->usbdev, ep_read), 0),
424 usb_maxpacket(line6->usbdev,
425 usb_sndisocpipe(line6->usbdev, ep_write), 1));
426
427 spin_lock_init(&line6pcm->lock_audio_out);
428 spin_lock_init(&line6pcm->lock_audio_in);
429 spin_lock_init(&line6pcm->lock_trigger);
430 line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
431
432 line6->line6pcm = line6pcm;
433
434 pcm->private_data = line6pcm;
435 pcm->private_free = line6_cleanup_pcm;
436
437 err = line6_create_audio_out_urbs(line6pcm);
438 if (err < 0)
439 return err;
440
441 err = line6_create_audio_in_urbs(line6pcm);
442 if (err < 0)
443 return err;
444
445 /* mixer: */
446 for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
447 err = snd_ctl_add(line6->card,
448 snd_ctl_new1(&line6_controls[i], line6pcm));
449 if (err < 0)
450 return err;
451 }
452
453 return 0;
454}
455EXPORT_SYMBOL_GPL(line6_init_pcm);
456
457/* prepare pcm callback */
458int snd_line6_prepare(struct snd_pcm_substream *substream)
459{
460 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
461
462 switch (substream->stream) {
463 case SNDRV_PCM_STREAM_PLAYBACK:
464 if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
465 line6_unlink_wait_clear_audio_out_urbs(line6pcm);
466
467 break;
468
469 case SNDRV_PCM_STREAM_CAPTURE:
470 if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
471 line6_unlink_wait_clear_audio_in_urbs(line6pcm);
472
473 break;
474 }
475
476 if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
477 line6pcm->count_out = 0;
478 line6pcm->pos_out = 0;
479 line6pcm->pos_out_done = 0;
480 line6pcm->bytes_out = 0;
481 line6pcm->count_in = 0;
482 line6pcm->pos_in_done = 0;
483 line6pcm->bytes_in = 0;
484 }
485
486 return 0;
487}