Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/line6/pcm.c
29269 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
struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
186
int ret = 0;
187
188
guard(spinlock_irqsave)(&pstr->lock);
189
if (!test_and_set_bit(type, &pstr->running) &&
190
!(pstr->active_urbs || pstr->unlink_urbs)) {
191
pstr->count = 0;
192
/* Submit all currently available URBs */
193
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
194
ret = line6_submit_audio_out_all_urbs(line6pcm);
195
else
196
ret = line6_submit_audio_in_all_urbs(line6pcm);
197
}
198
199
if (ret < 0)
200
clear_bit(type, &pstr->running);
201
return ret;
202
}
203
204
/* stop a PCM stream; this doesn't sync with the unlinked URBs */
205
static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
206
int type)
207
{
208
struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
209
210
scoped_guard(spinlock_irqsave, &pstr->lock) {
211
clear_bit(type, &pstr->running);
212
if (pstr->running)
213
return;
214
}
215
216
line6_unlink_audio_urbs(line6pcm, pstr);
217
if (direction == SNDRV_PCM_STREAM_CAPTURE) {
218
guard(spinlock_irqsave)(&pstr->lock);
219
line6pcm->prev_fbuf = NULL;
220
line6pcm->prev_fsize = 0;
221
}
222
}
223
224
/* common PCM trigger callback */
225
int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
226
{
227
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
228
struct snd_pcm_substream *s;
229
int err;
230
231
clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags);
232
233
snd_pcm_group_for_each_entry(s, substream) {
234
if (s->pcm->card != substream->pcm->card)
235
continue;
236
237
switch (cmd) {
238
case SNDRV_PCM_TRIGGER_START:
239
case SNDRV_PCM_TRIGGER_RESUME:
240
if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
241
(line6pcm->line6->properties->capabilities &
242
LINE6_CAP_IN_NEEDS_OUT)) {
243
err = line6_stream_start(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
244
LINE6_STREAM_CAPTURE_HELPER);
245
if (err < 0)
246
return err;
247
}
248
err = line6_stream_start(line6pcm, s->stream,
249
LINE6_STREAM_PCM);
250
if (err < 0)
251
return err;
252
break;
253
254
case SNDRV_PCM_TRIGGER_STOP:
255
case SNDRV_PCM_TRIGGER_SUSPEND:
256
if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
257
(line6pcm->line6->properties->capabilities &
258
LINE6_CAP_IN_NEEDS_OUT)) {
259
line6_stream_stop(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
260
LINE6_STREAM_CAPTURE_HELPER);
261
}
262
line6_stream_stop(line6pcm, s->stream,
263
LINE6_STREAM_PCM);
264
break;
265
266
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
267
if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
268
return -EINVAL;
269
set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
270
break;
271
272
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
273
if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
274
return -EINVAL;
275
clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
276
break;
277
278
default:
279
return -EINVAL;
280
}
281
}
282
283
return 0;
284
}
285
286
/* common PCM pointer callback */
287
snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)
288
{
289
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
290
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
291
292
return pstr->pos_done;
293
}
294
295
/* Stop and release duplex streams */
296
static void __line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
297
{
298
struct line6_pcm_stream *pstr;
299
int dir;
300
301
for (dir = 0; dir < 2; dir++)
302
line6_stream_stop(line6pcm, dir, type);
303
for (dir = 0; dir < 2; dir++) {
304
pstr = get_stream(line6pcm, dir);
305
line6_buffer_release(line6pcm, pstr, type);
306
}
307
}
308
309
/* Stop and release duplex streams */
310
void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
311
{
312
guard(mutex)(&line6pcm->state_mutex);
313
__line6_pcm_release(line6pcm, type);
314
}
315
EXPORT_SYMBOL_GPL(line6_pcm_release);
316
317
/* Acquire and optionally start duplex streams:
318
* type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
319
*/
320
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start)
321
{
322
struct line6_pcm_stream *pstr;
323
int ret = 0, dir;
324
325
/* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */
326
guard(mutex)(&line6pcm->state_mutex);
327
for (dir = 0; dir < 2; dir++) {
328
pstr = get_stream(line6pcm, dir);
329
ret = line6_buffer_acquire(line6pcm, pstr, dir, type);
330
if (ret < 0)
331
goto error;
332
if (!pstr->running)
333
line6_wait_clear_audio_urbs(line6pcm, pstr);
334
}
335
if (start) {
336
for (dir = 0; dir < 2; dir++) {
337
ret = line6_stream_start(line6pcm, dir, type);
338
if (ret < 0)
339
goto error;
340
}
341
}
342
error:
343
if (ret < 0)
344
__line6_pcm_release(line6pcm, type);
345
return ret;
346
}
347
EXPORT_SYMBOL_GPL(line6_pcm_acquire);
348
349
/* common PCM hw_params callback */
350
int snd_line6_hw_params(struct snd_pcm_substream *substream,
351
struct snd_pcm_hw_params *hw_params)
352
{
353
int ret;
354
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
355
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
356
357
guard(mutex)(&line6pcm->state_mutex);
358
ret = line6_buffer_acquire(line6pcm, pstr, substream->stream,
359
LINE6_STREAM_PCM);
360
if (ret < 0)
361
return ret;
362
363
pstr->period = params_period_bytes(hw_params);
364
return 0;
365
}
366
367
/* common PCM hw_free callback */
368
int snd_line6_hw_free(struct snd_pcm_substream *substream)
369
{
370
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
371
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
372
373
guard(mutex)(&line6pcm->state_mutex);
374
line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
375
return 0;
376
}
377
378
379
/* control info callback */
380
static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
381
struct snd_ctl_elem_info *uinfo)
382
{
383
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
384
uinfo->count = 2;
385
uinfo->value.integer.min = 0;
386
uinfo->value.integer.max = 256;
387
return 0;
388
}
389
390
/* control get callback */
391
static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
392
struct snd_ctl_elem_value *ucontrol)
393
{
394
int i;
395
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
396
397
for (i = 0; i < 2; i++)
398
ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
399
400
return 0;
401
}
402
403
/* control put callback */
404
static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
405
struct snd_ctl_elem_value *ucontrol)
406
{
407
int i, changed = 0;
408
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
409
410
for (i = 0; i < 2; i++)
411
if (line6pcm->volume_playback[i] !=
412
ucontrol->value.integer.value[i]) {
413
line6pcm->volume_playback[i] =
414
ucontrol->value.integer.value[i];
415
changed = 1;
416
}
417
418
return changed;
419
}
420
421
/* control definition */
422
static const struct snd_kcontrol_new line6_controls[] = {
423
{
424
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
425
.name = "PCM Playback Volume",
426
.info = snd_line6_control_playback_info,
427
.get = snd_line6_control_playback_get,
428
.put = snd_line6_control_playback_put
429
},
430
{
431
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
432
.name = "Impulse Response Volume",
433
.info = snd_line6_impulse_volume_info,
434
.get = snd_line6_impulse_volume_get,
435
.put = snd_line6_impulse_volume_put
436
},
437
{
438
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
439
.name = "Impulse Response Period",
440
.info = snd_line6_impulse_period_info,
441
.get = snd_line6_impulse_period_get,
442
.put = snd_line6_impulse_period_put
443
},
444
};
445
446
/*
447
Cleanup the PCM device.
448
*/
449
static void cleanup_urbs(struct line6_pcm_stream *pcms, int iso_buffers)
450
{
451
int i;
452
453
/* Most likely impossible in current code... */
454
if (pcms->urbs == NULL)
455
return;
456
457
for (i = 0; i < iso_buffers; i++) {
458
if (pcms->urbs[i]) {
459
usb_kill_urb(pcms->urbs[i]);
460
usb_free_urb(pcms->urbs[i]);
461
}
462
}
463
kfree(pcms->urbs);
464
pcms->urbs = NULL;
465
}
466
467
static void line6_cleanup_pcm(struct snd_pcm *pcm)
468
{
469
struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
470
471
cleanup_urbs(&line6pcm->out, line6pcm->line6->iso_buffers);
472
cleanup_urbs(&line6pcm->in, line6pcm->line6->iso_buffers);
473
kfree(line6pcm);
474
}
475
476
/* create a PCM device */
477
static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
478
{
479
struct snd_pcm *pcm;
480
int err;
481
482
err = snd_pcm_new(line6->card, (char *)line6->properties->name,
483
0, 1, 1, pcm_ret);
484
if (err < 0)
485
return err;
486
pcm = *pcm_ret;
487
strscpy(pcm->name, line6->properties->name);
488
489
/* set operators */
490
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
491
&snd_line6_playback_ops);
492
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
493
494
/* pre-allocation of buffers */
495
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
496
NULL, 64 * 1024, 128 * 1024);
497
return 0;
498
}
499
500
/*
501
Sync with PCM stream stops.
502
*/
503
void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
504
{
505
line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
506
line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
507
line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
508
line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
509
}
510
511
/*
512
Create and register the PCM device and mixer entries.
513
Create URBs for playback and capture.
514
*/
515
int line6_init_pcm(struct usb_line6 *line6,
516
struct line6_pcm_properties *properties)
517
{
518
int i, err;
519
unsigned ep_read = line6->properties->ep_audio_r;
520
unsigned ep_write = line6->properties->ep_audio_w;
521
struct snd_pcm *pcm;
522
struct snd_line6_pcm *line6pcm;
523
524
if (!(line6->properties->capabilities & LINE6_CAP_PCM))
525
return 0; /* skip PCM initialization and report success */
526
527
err = snd_line6_new_pcm(line6, &pcm);
528
if (err < 0)
529
return err;
530
531
line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
532
if (!line6pcm)
533
return -ENOMEM;
534
535
mutex_init(&line6pcm->state_mutex);
536
line6pcm->pcm = pcm;
537
line6pcm->properties = properties;
538
line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
539
line6pcm->volume_monitor = 255;
540
line6pcm->line6 = line6;
541
542
spin_lock_init(&line6pcm->out.lock);
543
spin_lock_init(&line6pcm->in.lock);
544
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
545
546
line6->line6pcm = line6pcm;
547
548
pcm->private_data = line6pcm;
549
pcm->private_free = line6_cleanup_pcm;
550
551
line6pcm->max_packet_size_in =
552
usb_maxpacket(line6->usbdev,
553
usb_rcvisocpipe(line6->usbdev, ep_read));
554
line6pcm->max_packet_size_out =
555
usb_maxpacket(line6->usbdev,
556
usb_sndisocpipe(line6->usbdev, ep_write));
557
if (!line6pcm->max_packet_size_in || !line6pcm->max_packet_size_out) {
558
dev_err(line6pcm->line6->ifcdev,
559
"cannot get proper max packet size\n");
560
return -EINVAL;
561
}
562
563
err = line6_create_audio_out_urbs(line6pcm);
564
if (err < 0)
565
return err;
566
567
err = line6_create_audio_in_urbs(line6pcm);
568
if (err < 0)
569
return err;
570
571
/* mixer: */
572
for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
573
err = snd_ctl_add(line6->card,
574
snd_ctl_new1(&line6_controls[i], line6pcm));
575
if (err < 0)
576
return err;
577
}
578
579
return 0;
580
}
581
EXPORT_SYMBOL_GPL(line6_init_pcm);
582
583
/* prepare pcm callback */
584
int snd_line6_prepare(struct snd_pcm_substream *substream)
585
{
586
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
587
struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
588
589
guard(mutex)(&line6pcm->state_mutex);
590
if (!pstr->running)
591
line6_wait_clear_audio_urbs(line6pcm, pstr);
592
593
if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) {
594
line6pcm->out.count = 0;
595
line6pcm->out.pos = 0;
596
line6pcm->out.pos_done = 0;
597
line6pcm->out.bytes = 0;
598
line6pcm->in.count = 0;
599
line6pcm->in.pos_done = 0;
600
line6pcm->in.bytes = 0;
601
}
602
603
return 0;
604
}
605
606