Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/dice/dice-pcm.c
29268 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* dice_pcm.c - a part of driver for DICE based devices
4
*
5
* Copyright (c) Clemens Ladisch <[email protected]>
6
* Copyright (c) 2014 Takashi Sakamoto <[email protected]>
7
*/
8
9
#include "dice.h"
10
11
static int dice_rate_constraint(struct snd_pcm_hw_params *params,
12
struct snd_pcm_hw_rule *rule)
13
{
14
struct snd_pcm_substream *substream = rule->private;
15
struct snd_dice *dice = substream->private_data;
16
unsigned int index = substream->pcm->device;
17
18
const struct snd_interval *c =
19
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
20
struct snd_interval *r =
21
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
22
struct snd_interval rates = {
23
.min = UINT_MAX, .max = 0, .integer = 1
24
};
25
unsigned int *pcm_channels;
26
enum snd_dice_rate_mode mode;
27
unsigned int i, rate;
28
29
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
30
pcm_channels = dice->tx_pcm_chs[index];
31
else
32
pcm_channels = dice->rx_pcm_chs[index];
33
34
for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
35
rate = snd_dice_rates[i];
36
if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
37
continue;
38
39
if (!snd_interval_test(c, pcm_channels[mode]))
40
continue;
41
42
rates.min = min(rates.min, rate);
43
rates.max = max(rates.max, rate);
44
}
45
46
return snd_interval_refine(r, &rates);
47
}
48
49
static int dice_channels_constraint(struct snd_pcm_hw_params *params,
50
struct snd_pcm_hw_rule *rule)
51
{
52
struct snd_pcm_substream *substream = rule->private;
53
struct snd_dice *dice = substream->private_data;
54
unsigned int index = substream->pcm->device;
55
56
const struct snd_interval *r =
57
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
58
struct snd_interval *c =
59
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
60
struct snd_interval channels = {
61
.min = UINT_MAX, .max = 0, .integer = 1
62
};
63
unsigned int *pcm_channels;
64
enum snd_dice_rate_mode mode;
65
unsigned int i, rate;
66
67
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
68
pcm_channels = dice->tx_pcm_chs[index];
69
else
70
pcm_channels = dice->rx_pcm_chs[index];
71
72
for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
73
rate = snd_dice_rates[i];
74
if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
75
continue;
76
77
if (!snd_interval_test(r, rate))
78
continue;
79
80
channels.min = min(channels.min, pcm_channels[mode]);
81
channels.max = max(channels.max, pcm_channels[mode]);
82
}
83
84
return snd_interval_refine(c, &channels);
85
}
86
87
static int limit_channels_and_rates(struct snd_dice *dice,
88
struct snd_pcm_runtime *runtime,
89
enum amdtp_stream_direction dir,
90
unsigned int index)
91
{
92
struct snd_pcm_hardware *hw = &runtime->hw;
93
unsigned int *pcm_channels;
94
unsigned int i;
95
96
if (dir == AMDTP_IN_STREAM)
97
pcm_channels = dice->tx_pcm_chs[index];
98
else
99
pcm_channels = dice->rx_pcm_chs[index];
100
101
hw->channels_min = UINT_MAX;
102
hw->channels_max = 0;
103
104
for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
105
enum snd_dice_rate_mode mode;
106
unsigned int rate, channels;
107
108
rate = snd_dice_rates[i];
109
if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
110
continue;
111
hw->rates |= snd_pcm_rate_to_rate_bit(rate);
112
113
channels = pcm_channels[mode];
114
if (channels == 0)
115
continue;
116
hw->channels_min = min(hw->channels_min, channels);
117
hw->channels_max = max(hw->channels_max, channels);
118
}
119
120
snd_pcm_limit_hw_rates(runtime);
121
122
return 0;
123
}
124
125
static int init_hw_info(struct snd_dice *dice,
126
struct snd_pcm_substream *substream)
127
{
128
struct snd_pcm_runtime *runtime = substream->runtime;
129
struct snd_pcm_hardware *hw = &runtime->hw;
130
unsigned int index = substream->pcm->device;
131
enum amdtp_stream_direction dir;
132
struct amdtp_stream *stream;
133
int err;
134
135
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
136
hw->formats = AM824_IN_PCM_FORMAT_BITS;
137
dir = AMDTP_IN_STREAM;
138
stream = &dice->tx_stream[index];
139
} else {
140
hw->formats = AM824_OUT_PCM_FORMAT_BITS;
141
dir = AMDTP_OUT_STREAM;
142
stream = &dice->rx_stream[index];
143
}
144
145
err = limit_channels_and_rates(dice, substream->runtime, dir,
146
index);
147
if (err < 0)
148
return err;
149
150
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
151
dice_rate_constraint, substream,
152
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
153
if (err < 0)
154
return err;
155
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
156
dice_channels_constraint, substream,
157
SNDRV_PCM_HW_PARAM_RATE, -1);
158
if (err < 0)
159
return err;
160
161
return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
162
}
163
164
static int pcm_open(struct snd_pcm_substream *substream)
165
{
166
struct snd_dice *dice = substream->private_data;
167
struct amdtp_domain *d = &dice->domain;
168
unsigned int source;
169
bool internal;
170
int err;
171
172
err = snd_dice_stream_lock_try(dice);
173
if (err < 0)
174
return err;
175
176
err = init_hw_info(dice, substream);
177
if (err < 0)
178
goto err_locked;
179
180
err = snd_dice_transaction_get_clock_source(dice, &source);
181
if (err < 0)
182
goto err_locked;
183
switch (source) {
184
case CLOCK_SOURCE_AES1:
185
case CLOCK_SOURCE_AES2:
186
case CLOCK_SOURCE_AES3:
187
case CLOCK_SOURCE_AES4:
188
case CLOCK_SOURCE_AES_ANY:
189
case CLOCK_SOURCE_ADAT:
190
case CLOCK_SOURCE_TDIF:
191
case CLOCK_SOURCE_WC:
192
internal = false;
193
break;
194
default:
195
internal = true;
196
break;
197
}
198
199
scoped_guard(mutex, &dice->mutex) {
200
// When source of clock is not internal or any stream is reserved for
201
// transmission of PCM frames, the available sampling rate is limited
202
// at current one.
203
if (!internal ||
204
(dice->substreams_counter > 0 && d->events_per_period > 0)) {
205
unsigned int frames_per_period = d->events_per_period;
206
unsigned int frames_per_buffer = d->events_per_buffer;
207
unsigned int rate;
208
209
err = snd_dice_transaction_get_rate(dice, &rate);
210
if (err < 0)
211
goto err_locked;
212
213
substream->runtime->hw.rate_min = rate;
214
substream->runtime->hw.rate_max = rate;
215
216
if (frames_per_period > 0) {
217
// For double_pcm_frame quirk.
218
if (rate > 96000 && !dice->disable_double_pcm_frames) {
219
frames_per_period *= 2;
220
frames_per_buffer *= 2;
221
}
222
223
err = snd_pcm_hw_constraint_minmax(substream->runtime,
224
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
225
frames_per_period, frames_per_period);
226
if (err < 0)
227
goto err_locked;
228
229
err = snd_pcm_hw_constraint_minmax(substream->runtime,
230
SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
231
frames_per_buffer, frames_per_buffer);
232
if (err < 0)
233
goto err_locked;
234
}
235
}
236
}
237
238
snd_pcm_set_sync(substream);
239
240
return 0;
241
err_locked:
242
snd_dice_stream_lock_release(dice);
243
return err;
244
}
245
246
static int pcm_close(struct snd_pcm_substream *substream)
247
{
248
struct snd_dice *dice = substream->private_data;
249
250
snd_dice_stream_lock_release(dice);
251
252
return 0;
253
}
254
255
static int pcm_hw_params(struct snd_pcm_substream *substream,
256
struct snd_pcm_hw_params *hw_params)
257
{
258
struct snd_dice *dice = substream->private_data;
259
int err = 0;
260
261
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
262
unsigned int rate = params_rate(hw_params);
263
unsigned int events_per_period = params_period_size(hw_params);
264
unsigned int events_per_buffer = params_buffer_size(hw_params);
265
266
guard(mutex)(&dice->mutex);
267
// For double_pcm_frame quirk.
268
if (rate > 96000 && !dice->disable_double_pcm_frames) {
269
events_per_period /= 2;
270
events_per_buffer /= 2;
271
}
272
err = snd_dice_stream_reserve_duplex(dice, rate,
273
events_per_period, events_per_buffer);
274
if (err >= 0)
275
++dice->substreams_counter;
276
}
277
278
return err;
279
}
280
281
static int pcm_hw_free(struct snd_pcm_substream *substream)
282
{
283
struct snd_dice *dice = substream->private_data;
284
285
guard(mutex)(&dice->mutex);
286
287
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
288
--dice->substreams_counter;
289
290
snd_dice_stream_stop_duplex(dice);
291
292
return 0;
293
}
294
295
static int capture_prepare(struct snd_pcm_substream *substream)
296
{
297
struct snd_dice *dice = substream->private_data;
298
struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
299
int err;
300
301
scoped_guard(mutex, &dice->mutex) {
302
err = snd_dice_stream_start_duplex(dice);
303
}
304
if (err >= 0)
305
amdtp_stream_pcm_prepare(stream);
306
307
return 0;
308
}
309
static int playback_prepare(struct snd_pcm_substream *substream)
310
{
311
struct snd_dice *dice = substream->private_data;
312
struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
313
int err;
314
315
scoped_guard(mutex, &dice->mutex) {
316
err = snd_dice_stream_start_duplex(dice);
317
}
318
if (err >= 0)
319
amdtp_stream_pcm_prepare(stream);
320
321
return err;
322
}
323
324
static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
325
{
326
struct snd_dice *dice = substream->private_data;
327
struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
328
329
switch (cmd) {
330
case SNDRV_PCM_TRIGGER_START:
331
amdtp_stream_pcm_trigger(stream, substream);
332
break;
333
case SNDRV_PCM_TRIGGER_STOP:
334
amdtp_stream_pcm_trigger(stream, NULL);
335
break;
336
default:
337
return -EINVAL;
338
}
339
340
return 0;
341
}
342
static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
343
{
344
struct snd_dice *dice = substream->private_data;
345
struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
346
347
switch (cmd) {
348
case SNDRV_PCM_TRIGGER_START:
349
amdtp_stream_pcm_trigger(stream, substream);
350
break;
351
case SNDRV_PCM_TRIGGER_STOP:
352
amdtp_stream_pcm_trigger(stream, NULL);
353
break;
354
default:
355
return -EINVAL;
356
}
357
358
return 0;
359
}
360
361
static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
362
{
363
struct snd_dice *dice = substream->private_data;
364
struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
365
366
return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
367
}
368
static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
369
{
370
struct snd_dice *dice = substream->private_data;
371
struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
372
373
return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
374
}
375
376
static int capture_ack(struct snd_pcm_substream *substream)
377
{
378
struct snd_dice *dice = substream->private_data;
379
struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
380
381
return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
382
}
383
384
static int playback_ack(struct snd_pcm_substream *substream)
385
{
386
struct snd_dice *dice = substream->private_data;
387
struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
388
389
return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
390
}
391
392
int snd_dice_create_pcm(struct snd_dice *dice)
393
{
394
static const struct snd_pcm_ops capture_ops = {
395
.open = pcm_open,
396
.close = pcm_close,
397
.hw_params = pcm_hw_params,
398
.hw_free = pcm_hw_free,
399
.prepare = capture_prepare,
400
.trigger = capture_trigger,
401
.pointer = capture_pointer,
402
.ack = capture_ack,
403
};
404
static const struct snd_pcm_ops playback_ops = {
405
.open = pcm_open,
406
.close = pcm_close,
407
.hw_params = pcm_hw_params,
408
.hw_free = pcm_hw_free,
409
.prepare = playback_prepare,
410
.trigger = playback_trigger,
411
.pointer = playback_pointer,
412
.ack = playback_ack,
413
};
414
struct snd_pcm *pcm;
415
unsigned int capture, playback;
416
int i, j;
417
int err;
418
419
for (i = 0; i < MAX_STREAMS; i++) {
420
capture = playback = 0;
421
for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) {
422
if (dice->tx_pcm_chs[i][j] > 0)
423
capture = 1;
424
if (dice->rx_pcm_chs[i][j] > 0)
425
playback = 1;
426
}
427
428
err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
429
&pcm);
430
if (err < 0)
431
return err;
432
pcm->private_data = dice;
433
pcm->nonatomic = true;
434
strscpy(pcm->name, dice->card->shortname);
435
436
if (capture > 0)
437
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
438
&capture_ops);
439
440
if (playback > 0)
441
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
442
&playback_ops);
443
444
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
445
NULL, 0, 0);
446
}
447
448
return 0;
449
}
450
451