Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/fireface/ff-pcm.c
26451 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* ff-pcm.c - a part of driver for RME Fireface series
4
*
5
* Copyright (c) 2015-2017 Takashi Sakamoto
6
*/
7
8
#include "ff.h"
9
10
static int hw_rule_rate(struct snd_pcm_hw_params *params,
11
struct snd_pcm_hw_rule *rule)
12
{
13
const unsigned int *pcm_channels = rule->private;
14
struct snd_interval *r =
15
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
16
const struct snd_interval *c =
17
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
18
struct snd_interval t = {
19
.min = UINT_MAX, .max = 0, .integer = 1
20
};
21
unsigned int i;
22
23
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
24
enum snd_ff_stream_mode mode;
25
int err;
26
27
err = snd_ff_stream_get_multiplier_mode(i, &mode);
28
if (err < 0)
29
continue;
30
31
if (!snd_interval_test(c, pcm_channels[mode]))
32
continue;
33
34
t.min = min(t.min, amdtp_rate_table[i]);
35
t.max = max(t.max, amdtp_rate_table[i]);
36
}
37
38
return snd_interval_refine(r, &t);
39
}
40
41
static int hw_rule_channels(struct snd_pcm_hw_params *params,
42
struct snd_pcm_hw_rule *rule)
43
{
44
const unsigned int *pcm_channels = rule->private;
45
struct snd_interval *c =
46
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
47
const struct snd_interval *r =
48
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
49
struct snd_interval t = {
50
.min = UINT_MAX, .max = 0, .integer = 1
51
};
52
unsigned int i;
53
54
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
55
enum snd_ff_stream_mode mode;
56
int err;
57
58
err = snd_ff_stream_get_multiplier_mode(i, &mode);
59
if (err < 0)
60
continue;
61
62
if (!snd_interval_test(r, amdtp_rate_table[i]))
63
continue;
64
65
t.min = min(t.min, pcm_channels[mode]);
66
t.max = max(t.max, pcm_channels[mode]);
67
}
68
69
return snd_interval_refine(c, &t);
70
}
71
72
static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
73
const unsigned int *pcm_channels)
74
{
75
unsigned int rate, channels;
76
int i;
77
78
hw->channels_min = UINT_MAX;
79
hw->channels_max = 0;
80
hw->rate_min = UINT_MAX;
81
hw->rate_max = 0;
82
83
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
84
enum snd_ff_stream_mode mode;
85
int err;
86
87
err = snd_ff_stream_get_multiplier_mode(i, &mode);
88
if (err < 0)
89
continue;
90
91
channels = pcm_channels[mode];
92
if (pcm_channels[mode] == 0)
93
continue;
94
hw->channels_min = min(hw->channels_min, channels);
95
hw->channels_max = max(hw->channels_max, channels);
96
97
rate = amdtp_rate_table[i];
98
hw->rates |= snd_pcm_rate_to_rate_bit(rate);
99
hw->rate_min = min(hw->rate_min, rate);
100
hw->rate_max = max(hw->rate_max, rate);
101
}
102
}
103
104
static int pcm_init_hw_params(struct snd_ff *ff,
105
struct snd_pcm_substream *substream)
106
{
107
struct snd_pcm_runtime *runtime = substream->runtime;
108
struct amdtp_stream *s;
109
const unsigned int *pcm_channels;
110
int err;
111
112
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
113
runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
114
s = &ff->tx_stream;
115
pcm_channels = ff->spec->pcm_capture_channels;
116
} else {
117
runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
118
s = &ff->rx_stream;
119
pcm_channels = ff->spec->pcm_playback_channels;
120
}
121
122
limit_channels_and_rates(&runtime->hw, pcm_channels);
123
124
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
125
hw_rule_channels, (void *)pcm_channels,
126
SNDRV_PCM_HW_PARAM_RATE, -1);
127
if (err < 0)
128
return err;
129
130
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
131
hw_rule_rate, (void *)pcm_channels,
132
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
133
if (err < 0)
134
return err;
135
136
return amdtp_ff_add_pcm_hw_constraints(s, runtime);
137
}
138
139
static int pcm_open(struct snd_pcm_substream *substream)
140
{
141
struct snd_ff *ff = substream->private_data;
142
struct amdtp_domain *d = &ff->domain;
143
unsigned int rate;
144
enum snd_ff_clock_src src;
145
int i, err;
146
147
err = snd_ff_stream_lock_try(ff);
148
if (err < 0)
149
return err;
150
151
err = pcm_init_hw_params(ff, substream);
152
if (err < 0)
153
goto release_lock;
154
155
err = ff->spec->protocol->get_clock(ff, &rate, &src);
156
if (err < 0)
157
goto release_lock;
158
159
mutex_lock(&ff->mutex);
160
161
// When source of clock is not internal or any stream is reserved for
162
// transmission of PCM frames, the available sampling rate is limited
163
// at current one.
164
if (src != SND_FF_CLOCK_SRC_INTERNAL) {
165
for (i = 0; i < CIP_SFC_COUNT; ++i) {
166
if (amdtp_rate_table[i] == rate)
167
break;
168
}
169
170
// The unit is configured at sampling frequency which packet
171
// streaming engine can't support.
172
if (i >= CIP_SFC_COUNT) {
173
mutex_unlock(&ff->mutex);
174
err = -EIO;
175
goto release_lock;
176
}
177
178
substream->runtime->hw.rate_min = rate;
179
substream->runtime->hw.rate_max = rate;
180
} else {
181
if (ff->substreams_counter > 0) {
182
unsigned int frames_per_period = d->events_per_period;
183
unsigned int frames_per_buffer = d->events_per_buffer;
184
185
rate = amdtp_rate_table[ff->rx_stream.sfc];
186
substream->runtime->hw.rate_min = rate;
187
substream->runtime->hw.rate_max = rate;
188
189
err = snd_pcm_hw_constraint_minmax(substream->runtime,
190
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
191
frames_per_period, frames_per_period);
192
if (err < 0) {
193
mutex_unlock(&ff->mutex);
194
goto release_lock;
195
}
196
197
err = snd_pcm_hw_constraint_minmax(substream->runtime,
198
SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
199
frames_per_buffer, frames_per_buffer);
200
if (err < 0) {
201
mutex_unlock(&ff->mutex);
202
goto release_lock;
203
}
204
}
205
}
206
207
mutex_unlock(&ff->mutex);
208
209
snd_pcm_set_sync(substream);
210
211
return 0;
212
213
release_lock:
214
snd_ff_stream_lock_release(ff);
215
return err;
216
}
217
218
static int pcm_close(struct snd_pcm_substream *substream)
219
{
220
struct snd_ff *ff = substream->private_data;
221
222
snd_ff_stream_lock_release(ff);
223
224
return 0;
225
}
226
227
static int pcm_hw_params(struct snd_pcm_substream *substream,
228
struct snd_pcm_hw_params *hw_params)
229
{
230
struct snd_ff *ff = substream->private_data;
231
int err = 0;
232
233
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
234
unsigned int rate = params_rate(hw_params);
235
unsigned int frames_per_period = params_period_size(hw_params);
236
unsigned int frames_per_buffer = params_buffer_size(hw_params);
237
238
mutex_lock(&ff->mutex);
239
err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period,
240
frames_per_buffer);
241
if (err >= 0)
242
++ff->substreams_counter;
243
mutex_unlock(&ff->mutex);
244
}
245
246
return err;
247
}
248
249
static int pcm_hw_free(struct snd_pcm_substream *substream)
250
{
251
struct snd_ff *ff = substream->private_data;
252
253
mutex_lock(&ff->mutex);
254
255
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
256
--ff->substreams_counter;
257
258
snd_ff_stream_stop_duplex(ff);
259
260
mutex_unlock(&ff->mutex);
261
262
return 0;
263
}
264
265
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
266
{
267
struct snd_ff *ff = substream->private_data;
268
struct snd_pcm_runtime *runtime = substream->runtime;
269
int err;
270
271
mutex_lock(&ff->mutex);
272
273
err = snd_ff_stream_start_duplex(ff, runtime->rate);
274
if (err >= 0)
275
amdtp_stream_pcm_prepare(&ff->tx_stream);
276
277
mutex_unlock(&ff->mutex);
278
279
return err;
280
}
281
282
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
283
{
284
struct snd_ff *ff = substream->private_data;
285
struct snd_pcm_runtime *runtime = substream->runtime;
286
int err;
287
288
mutex_lock(&ff->mutex);
289
290
err = snd_ff_stream_start_duplex(ff, runtime->rate);
291
if (err >= 0)
292
amdtp_stream_pcm_prepare(&ff->rx_stream);
293
294
mutex_unlock(&ff->mutex);
295
296
return err;
297
}
298
299
static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
300
{
301
struct snd_ff *ff = substream->private_data;
302
303
switch (cmd) {
304
case SNDRV_PCM_TRIGGER_START:
305
amdtp_stream_pcm_trigger(&ff->tx_stream, substream);
306
break;
307
case SNDRV_PCM_TRIGGER_STOP:
308
amdtp_stream_pcm_trigger(&ff->tx_stream, NULL);
309
break;
310
default:
311
return -EINVAL;
312
}
313
314
return 0;
315
}
316
317
static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
318
{
319
struct snd_ff *ff = substream->private_data;
320
321
switch (cmd) {
322
case SNDRV_PCM_TRIGGER_START:
323
amdtp_stream_pcm_trigger(&ff->rx_stream, substream);
324
break;
325
case SNDRV_PCM_TRIGGER_STOP:
326
amdtp_stream_pcm_trigger(&ff->rx_stream, NULL);
327
break;
328
default:
329
return -EINVAL;
330
}
331
332
return 0;
333
}
334
335
static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
336
{
337
struct snd_ff *ff = sbstrm->private_data;
338
339
return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->tx_stream);
340
}
341
342
static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
343
{
344
struct snd_ff *ff = sbstrm->private_data;
345
346
return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->rx_stream);
347
}
348
349
static int pcm_capture_ack(struct snd_pcm_substream *substream)
350
{
351
struct snd_ff *ff = substream->private_data;
352
353
return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->tx_stream);
354
}
355
356
static int pcm_playback_ack(struct snd_pcm_substream *substream)
357
{
358
struct snd_ff *ff = substream->private_data;
359
360
return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->rx_stream);
361
}
362
363
int snd_ff_create_pcm_devices(struct snd_ff *ff)
364
{
365
static const struct snd_pcm_ops pcm_capture_ops = {
366
.open = pcm_open,
367
.close = pcm_close,
368
.hw_params = pcm_hw_params,
369
.hw_free = pcm_hw_free,
370
.prepare = pcm_capture_prepare,
371
.trigger = pcm_capture_trigger,
372
.pointer = pcm_capture_pointer,
373
.ack = pcm_capture_ack,
374
};
375
static const struct snd_pcm_ops pcm_playback_ops = {
376
.open = pcm_open,
377
.close = pcm_close,
378
.hw_params = pcm_hw_params,
379
.hw_free = pcm_hw_free,
380
.prepare = pcm_playback_prepare,
381
.trigger = pcm_playback_trigger,
382
.pointer = pcm_playback_pointer,
383
.ack = pcm_playback_ack,
384
};
385
struct snd_pcm *pcm;
386
int err;
387
388
err = snd_pcm_new(ff->card, ff->card->driver, 0, 1, 1, &pcm);
389
if (err < 0)
390
return err;
391
392
pcm->private_data = ff;
393
pcm->nonatomic = true;
394
snprintf(pcm->name, sizeof(pcm->name),
395
"%s PCM", ff->card->shortname);
396
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
397
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
398
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
399
400
return 0;
401
}
402
403