Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/line6/pcm.c
26425 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Line 6 Linux USB driver
4
*
5
* Copyright (C) 2004-2010 Markus Grabner ([email protected])
6
*/
7
8
#include <linux/slab.h>
9
#include <linux/export.h>
10
#include <sound/core.h>
11
#include <sound/control.h>
12
#include <sound/pcm.h>
13
#include <sound/pcm_params.h>
14
15
#include "capture.h"
16
#include "driver.h"
17
#include "playback.h"
18
19
/* impulse response volume controls */
20
static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
21
struct snd_ctl_elem_info *uinfo)
22
{
23
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
24
uinfo->count = 1;
25
uinfo->value.integer.min = 0;
26
uinfo->value.integer.max = 255;
27
return 0;
28
}
29
30
static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
31
struct snd_ctl_elem_value *ucontrol)
32
{
33
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
34
35
ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
36
return 0;
37
}
38
39
static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
40
struct snd_ctl_elem_value *ucontrol)
41
{
42
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
43
int value = ucontrol->value.integer.value[0];
44
int err;
45
46
if (line6pcm->impulse_volume == value)
47
return 0;
48
49
line6pcm->impulse_volume = value;
50
if (value > 0) {
51
err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE, true);
52
if (err < 0) {
53
line6pcm->impulse_volume = 0;
54
return err;
55
}
56
} else {
57
line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
58
}
59
return 1;
60
}
61
62
/* impulse response period controls */
63
static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
64
struct snd_ctl_elem_info *uinfo)
65
{
66
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
67
uinfo->count = 1;
68
uinfo->value.integer.min = 0;
69
uinfo->value.integer.max = 2000;
70
return 0;
71
}
72
73
static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
74
struct snd_ctl_elem_value *ucontrol)
75
{
76
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
77
78
ucontrol->value.integer.value[0] = line6pcm->impulse_period;
79
return 0;
80
}
81
82
static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
83
struct snd_ctl_elem_value *ucontrol)
84
{
85
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
86
int value = ucontrol->value.integer.value[0];
87
88
if (line6pcm->impulse_period == value)
89
return 0;
90
91
line6pcm->impulse_period = value;
92
return 1;
93
}
94
95
/*
96
Unlink all currently active URBs.
97
*/
98
static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm,
99
struct line6_pcm_stream *pcms)
100
{
101
int i;
102
103
for (i = 0; i < line6pcm->line6->iso_buffers; i++) {
104
if (test_bit(i, &pcms->active_urbs)) {
105
if (!test_and_set_bit(i, &pcms->unlink_urbs))
106
usb_unlink_urb(pcms->urbs[i]);
107
}
108
}
109
}
110
111
/*
112
Wait until unlinking of all currently active URBs has been finished.
113
*/
114
static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,
115
struct line6_pcm_stream *pcms)
116
{
117
int timeout = HZ;
118
int i;
119
int alive;
120
121
do {
122
alive = 0;
123
for (i = 0; i < line6pcm->line6->iso_buffers; i++) {
124
if (test_bit(i, &pcms->active_urbs))
125
alive++;
126
}
127
if (!alive)
128
break;
129
set_current_state(TASK_UNINTERRUPTIBLE);
130
schedule_timeout(1);
131
} while (--timeout > 0);
132
if (alive)
133
dev_err(line6pcm->line6->ifcdev,
134
"timeout: still %d active urbs..\n", alive);
135
}
136
137
static inline struct line6_pcm_stream *
138
get_stream(struct snd_line6_pcm *line6pcm, int direction)
139
{
140
return (direction == SNDRV_PCM_STREAM_PLAYBACK) ?
141
&line6pcm->out : &line6pcm->in;
142
}
143
144
/* allocate a buffer if not opened yet;
145
* call this in line6pcm.state_mutex
146
*/
147
static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm,
148
struct line6_pcm_stream *pstr, int direction, int type)
149
{
150
const int pkt_size =
151
(direction == SNDRV_PCM_STREAM_PLAYBACK) ?
152
line6pcm->max_packet_size_out :
153
line6pcm->max_packet_size_in;
154
155
/* Invoked multiple times in a row so allocate once only */
156
if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) {
157
pstr->buffer =
158
kmalloc(array3_size(line6pcm->line6->iso_buffers,
159
LINE6_ISO_PACKETS, pkt_size),
160
GFP_KERNEL);
161
if (!pstr->buffer)
162
return -ENOMEM;
163
}
164
return 0;
165
}
166
167
/* free a buffer if all streams are closed;
168
* call this in line6pcm.state_mutex
169
*/
170
static void line6_buffer_release(struct snd_line6_pcm *line6pcm,
171
struct line6_pcm_stream *pstr, int type)
172
{
173
clear_bit(type, &pstr->opened);
174
if (!pstr->opened) {
175
line6_wait_clear_audio_urbs(line6pcm, pstr);
176
kfree(pstr->buffer);
177
pstr->buffer = NULL;
178
}
179
}
180
181
/* start a PCM stream */
182
static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,
183
int type)
184
{
185
unsigned long flags;
186
struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
187
int ret = 0;
188
189
spin_lock_irqsave(&pstr->lock, flags);
190
if (!test_and_set_bit(type, &pstr->running) &&
191
!(pstr->active_urbs || pstr->unlink_urbs)) {
192
pstr->count = 0;
193
/* Submit all currently available URBs */
194
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
195
ret = line6_submit_audio_out_all_urbs(line6pcm);
196
else
197
ret = line6_submit_audio_in_all_urbs(line6pcm);
198
}
199
200
if (ret < 0)
201
clear_bit(type, &pstr->running);
202
spin_unlock_irqrestore(&pstr->lock, flags);
203
return ret;
204
}
205
206
/* stop a PCM stream; this doesn't sync with the unlinked URBs */
207
static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
208
int type)
209
{
210
unsigned long flags;
211
struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
212
213
spin_lock_irqsave(&pstr->lock, flags);
214
clear_bit(type, &pstr->running);
215
if (!pstr->running) {
216
spin_unlock_irqrestore(&pstr->lock, flags);
217
line6_unlink_audio_urbs(line6pcm, pstr);
218
spin_lock_irqsave(&pstr->lock, flags);
219
if (direction == SNDRV_PCM_STREAM_CAPTURE) {
220
line6pcm->prev_fbuf = NULL;
221
line6pcm->prev_fsize = 0;
222
}
223
}
224
spin_unlock_irqrestore(&pstr->lock, flags);
225
}
226
227
/* common PCM trigger callback */
228
int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
229
{
230
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
231
struct snd_pcm_substream *s;
232
int err;
233
234
clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags);
235
236
snd_pcm_group_for_each_entry(s, substream) {
237
if (s->pcm->card != substream->pcm->card)
238
continue;
239
240
switch (cmd) {
241
case SNDRV_PCM_TRIGGER_START:
242
case SNDRV_PCM_TRIGGER_RESUME:
243
if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
244
(line6pcm->line6->properties->capabilities &
245
LINE6_CAP_IN_NEEDS_OUT)) {
246
err = line6_stream_start(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
247
LINE6_STREAM_CAPTURE_HELPER);
248
if (err < 0)
249
return err;
250
}
251
err = line6_stream_start(line6pcm, s->stream,
252
LINE6_STREAM_PCM);
253
if (err < 0)
254
return err;
255
break;
256
257
case SNDRV_PCM_TRIGGER_STOP:
258
case SNDRV_PCM_TRIGGER_SUSPEND:
259
if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
260
(line6pcm->line6->properties->capabilities &
261
LINE6_CAP_IN_NEEDS_OUT)) {
262
line6_stream_stop(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
263
LINE6_STREAM_CAPTURE_HELPER);
264
}
265
line6_stream_stop(line6pcm, s->stream,
266
LINE6_STREAM_PCM);
267
break;
268
269
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
270
if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
271
return -EINVAL;
272
set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
273
break;
274
275
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
276
if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
277
return -EINVAL;
278
clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
279
break;
280
281
default:
282
return -EINVAL;
283
}
284
}
285
286
return 0;
287
}
288
289
/* common PCM pointer callback */
290
snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)
291
{
292
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
293
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
294
295
return pstr->pos_done;
296
}
297
298
/* Acquire and optionally start duplex streams:
299
* type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
300
*/
301
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start)
302
{
303
struct line6_pcm_stream *pstr;
304
int ret = 0, dir;
305
306
/* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */
307
mutex_lock(&line6pcm->state_mutex);
308
for (dir = 0; dir < 2; dir++) {
309
pstr = get_stream(line6pcm, dir);
310
ret = line6_buffer_acquire(line6pcm, pstr, dir, type);
311
if (ret < 0)
312
goto error;
313
if (!pstr->running)
314
line6_wait_clear_audio_urbs(line6pcm, pstr);
315
}
316
if (start) {
317
for (dir = 0; dir < 2; dir++) {
318
ret = line6_stream_start(line6pcm, dir, type);
319
if (ret < 0)
320
goto error;
321
}
322
}
323
error:
324
mutex_unlock(&line6pcm->state_mutex);
325
if (ret < 0)
326
line6_pcm_release(line6pcm, type);
327
return ret;
328
}
329
EXPORT_SYMBOL_GPL(line6_pcm_acquire);
330
331
/* Stop and release duplex streams */
332
void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
333
{
334
struct line6_pcm_stream *pstr;
335
int dir;
336
337
mutex_lock(&line6pcm->state_mutex);
338
for (dir = 0; dir < 2; dir++)
339
line6_stream_stop(line6pcm, dir, type);
340
for (dir = 0; dir < 2; dir++) {
341
pstr = get_stream(line6pcm, dir);
342
line6_buffer_release(line6pcm, pstr, type);
343
}
344
mutex_unlock(&line6pcm->state_mutex);
345
}
346
EXPORT_SYMBOL_GPL(line6_pcm_release);
347
348
/* common PCM hw_params callback */
349
int snd_line6_hw_params(struct snd_pcm_substream *substream,
350
struct snd_pcm_hw_params *hw_params)
351
{
352
int ret;
353
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
354
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
355
356
mutex_lock(&line6pcm->state_mutex);
357
ret = line6_buffer_acquire(line6pcm, pstr, substream->stream,
358
LINE6_STREAM_PCM);
359
if (ret < 0)
360
goto error;
361
362
pstr->period = params_period_bytes(hw_params);
363
error:
364
mutex_unlock(&line6pcm->state_mutex);
365
return ret;
366
}
367
368
/* common PCM hw_free callback */
369
int snd_line6_hw_free(struct snd_pcm_substream *substream)
370
{
371
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
372
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
373
374
mutex_lock(&line6pcm->state_mutex);
375
line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
376
mutex_unlock(&line6pcm->state_mutex);
377
return 0;
378
}
379
380
381
/* control info callback */
382
static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
383
struct snd_ctl_elem_info *uinfo)
384
{
385
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
386
uinfo->count = 2;
387
uinfo->value.integer.min = 0;
388
uinfo->value.integer.max = 256;
389
return 0;
390
}
391
392
/* control get callback */
393
static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
394
struct snd_ctl_elem_value *ucontrol)
395
{
396
int i;
397
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
398
399
for (i = 0; i < 2; i++)
400
ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
401
402
return 0;
403
}
404
405
/* control put callback */
406
static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
407
struct snd_ctl_elem_value *ucontrol)
408
{
409
int i, changed = 0;
410
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
411
412
for (i = 0; i < 2; i++)
413
if (line6pcm->volume_playback[i] !=
414
ucontrol->value.integer.value[i]) {
415
line6pcm->volume_playback[i] =
416
ucontrol->value.integer.value[i];
417
changed = 1;
418
}
419
420
return changed;
421
}
422
423
/* control definition */
424
static const struct snd_kcontrol_new line6_controls[] = {
425
{
426
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
427
.name = "PCM Playback Volume",
428
.info = snd_line6_control_playback_info,
429
.get = snd_line6_control_playback_get,
430
.put = snd_line6_control_playback_put
431
},
432
{
433
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
434
.name = "Impulse Response Volume",
435
.info = snd_line6_impulse_volume_info,
436
.get = snd_line6_impulse_volume_get,
437
.put = snd_line6_impulse_volume_put
438
},
439
{
440
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
441
.name = "Impulse Response Period",
442
.info = snd_line6_impulse_period_info,
443
.get = snd_line6_impulse_period_get,
444
.put = snd_line6_impulse_period_put
445
},
446
};
447
448
/*
449
Cleanup the PCM device.
450
*/
451
static void cleanup_urbs(struct line6_pcm_stream *pcms, int iso_buffers)
452
{
453
int i;
454
455
/* Most likely impossible in current code... */
456
if (pcms->urbs == NULL)
457
return;
458
459
for (i = 0; i < iso_buffers; i++) {
460
if (pcms->urbs[i]) {
461
usb_kill_urb(pcms->urbs[i]);
462
usb_free_urb(pcms->urbs[i]);
463
}
464
}
465
kfree(pcms->urbs);
466
pcms->urbs = NULL;
467
}
468
469
static void line6_cleanup_pcm(struct snd_pcm *pcm)
470
{
471
struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
472
473
cleanup_urbs(&line6pcm->out, line6pcm->line6->iso_buffers);
474
cleanup_urbs(&line6pcm->in, line6pcm->line6->iso_buffers);
475
kfree(line6pcm);
476
}
477
478
/* create a PCM device */
479
static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
480
{
481
struct snd_pcm *pcm;
482
int err;
483
484
err = snd_pcm_new(line6->card, (char *)line6->properties->name,
485
0, 1, 1, pcm_ret);
486
if (err < 0)
487
return err;
488
pcm = *pcm_ret;
489
strscpy(pcm->name, line6->properties->name);
490
491
/* set operators */
492
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
493
&snd_line6_playback_ops);
494
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
495
496
/* pre-allocation of buffers */
497
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
498
NULL, 64 * 1024, 128 * 1024);
499
return 0;
500
}
501
502
/*
503
Sync with PCM stream stops.
504
*/
505
void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
506
{
507
line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
508
line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
509
line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
510
line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
511
}
512
513
/*
514
Create and register the PCM device and mixer entries.
515
Create URBs for playback and capture.
516
*/
517
int line6_init_pcm(struct usb_line6 *line6,
518
struct line6_pcm_properties *properties)
519
{
520
int i, err;
521
unsigned ep_read = line6->properties->ep_audio_r;
522
unsigned ep_write = line6->properties->ep_audio_w;
523
struct snd_pcm *pcm;
524
struct snd_line6_pcm *line6pcm;
525
526
if (!(line6->properties->capabilities & LINE6_CAP_PCM))
527
return 0; /* skip PCM initialization and report success */
528
529
err = snd_line6_new_pcm(line6, &pcm);
530
if (err < 0)
531
return err;
532
533
line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
534
if (!line6pcm)
535
return -ENOMEM;
536
537
mutex_init(&line6pcm->state_mutex);
538
line6pcm->pcm = pcm;
539
line6pcm->properties = properties;
540
line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
541
line6pcm->volume_monitor = 255;
542
line6pcm->line6 = line6;
543
544
spin_lock_init(&line6pcm->out.lock);
545
spin_lock_init(&line6pcm->in.lock);
546
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
547
548
line6->line6pcm = line6pcm;
549
550
pcm->private_data = line6pcm;
551
pcm->private_free = line6_cleanup_pcm;
552
553
line6pcm->max_packet_size_in =
554
usb_maxpacket(line6->usbdev,
555
usb_rcvisocpipe(line6->usbdev, ep_read));
556
line6pcm->max_packet_size_out =
557
usb_maxpacket(line6->usbdev,
558
usb_sndisocpipe(line6->usbdev, ep_write));
559
if (!line6pcm->max_packet_size_in || !line6pcm->max_packet_size_out) {
560
dev_err(line6pcm->line6->ifcdev,
561
"cannot get proper max packet size\n");
562
return -EINVAL;
563
}
564
565
err = line6_create_audio_out_urbs(line6pcm);
566
if (err < 0)
567
return err;
568
569
err = line6_create_audio_in_urbs(line6pcm);
570
if (err < 0)
571
return err;
572
573
/* mixer: */
574
for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
575
err = snd_ctl_add(line6->card,
576
snd_ctl_new1(&line6_controls[i], line6pcm));
577
if (err < 0)
578
return err;
579
}
580
581
return 0;
582
}
583
EXPORT_SYMBOL_GPL(line6_init_pcm);
584
585
/* prepare pcm callback */
586
int snd_line6_prepare(struct snd_pcm_substream *substream)
587
{
588
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
589
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
590
591
mutex_lock(&line6pcm->state_mutex);
592
if (!pstr->running)
593
line6_wait_clear_audio_urbs(line6pcm, pstr);
594
595
if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) {
596
line6pcm->out.count = 0;
597
line6pcm->out.pos = 0;
598
line6pcm->out.pos_done = 0;
599
line6pcm->out.bytes = 0;
600
line6pcm->in.count = 0;
601
line6pcm->in.pos_done = 0;
602
line6pcm->in.bytes = 0;
603
}
604
605
mutex_unlock(&line6pcm->state_mutex);
606
return 0;
607
}
608
609