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