Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/fireworks/fireworks_pcm.c
29269 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* fireworks_pcm.c - a part of driver for Fireworks based devices
4
*
5
* Copyright (c) 2009-2010 Clemens Ladisch
6
* Copyright (c) 2013-2014 Takashi Sakamoto
7
*/
8
#include "./fireworks.h"
9
10
/*
11
* NOTE:
12
* Fireworks changes its AMDTP channels for PCM data according to its sampling
13
* rate. There are three modes. Here _XX is either _rx or _tx.
14
* 0: 32.0- 48.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels applied
15
* 1: 88.2- 96.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_2x applied
16
* 2: 176.4-192.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_4x applied
17
*
18
* The number of PCM channels for analog input and output are always fixed but
19
* the number of PCM channels for digital input and output are differed.
20
*
21
* Additionally, according to "AudioFire Owner's Manual Version 2.2", in some
22
* model, the number of PCM channels for digital input has more restriction
23
* depending on which digital interface is selected.
24
* - S/PDIF coaxial and optical : use input 1-2
25
* - ADAT optical at 32.0-48.0 kHz : use input 1-8
26
* - ADAT optical at 88.2-96.0 kHz : use input 1-4 (S/MUX format)
27
*
28
* The data in AMDTP channels for blank PCM channels are zero.
29
*/
30
static const unsigned int freq_table[] = {
31
/* multiplier mode 0 */
32
[0] = 32000,
33
[1] = 44100,
34
[2] = 48000,
35
/* multiplier mode 1 */
36
[3] = 88200,
37
[4] = 96000,
38
/* multiplier mode 2 */
39
[5] = 176400,
40
[6] = 192000,
41
};
42
43
static inline unsigned int
44
get_multiplier_mode_with_index(unsigned int index)
45
{
46
return ((int)index - 1) / 2;
47
}
48
49
int snd_efw_get_multiplier_mode(unsigned int sampling_rate, unsigned int *mode)
50
{
51
unsigned int i;
52
53
for (i = 0; i < ARRAY_SIZE(freq_table); i++) {
54
if (freq_table[i] == sampling_rate) {
55
*mode = get_multiplier_mode_with_index(i);
56
return 0;
57
}
58
}
59
60
return -EINVAL;
61
}
62
63
static int
64
hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
65
{
66
unsigned int *pcm_channels = rule->private;
67
struct snd_interval *r =
68
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
69
const struct snd_interval *c =
70
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
71
struct snd_interval t = {
72
.min = UINT_MAX, .max = 0, .integer = 1
73
};
74
unsigned int i, mode;
75
76
for (i = 0; i < ARRAY_SIZE(freq_table); i++) {
77
mode = get_multiplier_mode_with_index(i);
78
if (!snd_interval_test(c, pcm_channels[mode]))
79
continue;
80
81
t.min = min(t.min, freq_table[i]);
82
t.max = max(t.max, freq_table[i]);
83
}
84
85
return snd_interval_refine(r, &t);
86
}
87
88
static int
89
hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
90
{
91
unsigned int *pcm_channels = rule->private;
92
struct snd_interval *c =
93
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
94
const struct snd_interval *r =
95
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
96
struct snd_interval t = {
97
.min = UINT_MAX, .max = 0, .integer = 1
98
};
99
unsigned int i, mode;
100
101
for (i = 0; i < ARRAY_SIZE(freq_table); i++) {
102
mode = get_multiplier_mode_with_index(i);
103
if (!snd_interval_test(r, freq_table[i]))
104
continue;
105
106
t.min = min(t.min, pcm_channels[mode]);
107
t.max = max(t.max, pcm_channels[mode]);
108
}
109
110
return snd_interval_refine(c, &t);
111
}
112
113
static void
114
limit_channels(struct snd_pcm_hardware *hw, unsigned int *pcm_channels)
115
{
116
unsigned int i, mode;
117
118
hw->channels_min = UINT_MAX;
119
hw->channels_max = 0;
120
121
for (i = 0; i < ARRAY_SIZE(freq_table); i++) {
122
mode = get_multiplier_mode_with_index(i);
123
if (pcm_channels[mode] == 0)
124
continue;
125
126
hw->channels_min = min(hw->channels_min, pcm_channels[mode]);
127
hw->channels_max = max(hw->channels_max, pcm_channels[mode]);
128
}
129
}
130
131
static int
132
pcm_init_hw_params(struct snd_efw *efw,
133
struct snd_pcm_substream *substream)
134
{
135
struct snd_pcm_runtime *runtime = substream->runtime;
136
struct amdtp_stream *s;
137
unsigned int *pcm_channels;
138
int err;
139
140
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
141
runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
142
s = &efw->tx_stream;
143
pcm_channels = efw->pcm_capture_channels;
144
} else {
145
runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
146
s = &efw->rx_stream;
147
pcm_channels = efw->pcm_playback_channels;
148
}
149
150
/* limit rates */
151
runtime->hw.rates = efw->supported_sampling_rate;
152
snd_pcm_limit_hw_rates(runtime);
153
154
limit_channels(&runtime->hw, pcm_channels);
155
156
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
157
hw_rule_channels, pcm_channels,
158
SNDRV_PCM_HW_PARAM_RATE, -1);
159
if (err < 0)
160
goto end;
161
162
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
163
hw_rule_rate, pcm_channels,
164
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
165
if (err < 0)
166
goto end;
167
168
err = amdtp_am824_add_pcm_hw_constraints(s, runtime);
169
end:
170
return err;
171
}
172
173
static int pcm_open(struct snd_pcm_substream *substream)
174
{
175
struct snd_efw *efw = substream->private_data;
176
struct amdtp_domain *d = &efw->domain;
177
enum snd_efw_clock_source clock_source;
178
int err;
179
180
err = snd_efw_stream_lock_try(efw);
181
if (err < 0)
182
return err;
183
184
err = pcm_init_hw_params(efw, substream);
185
if (err < 0)
186
goto err_locked;
187
188
err = snd_efw_command_get_clock_source(efw, &clock_source);
189
if (err < 0)
190
goto err_locked;
191
192
scoped_guard(mutex, &efw->mutex) {
193
// When source of clock is not internal or any stream is reserved for
194
// transmission of PCM frames, the available sampling rate is limited
195
// at current one.
196
if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) ||
197
(efw->substreams_counter > 0 && d->events_per_period > 0)) {
198
unsigned int frames_per_period = d->events_per_period;
199
unsigned int frames_per_buffer = d->events_per_buffer;
200
unsigned int sampling_rate;
201
202
err = snd_efw_command_get_sampling_rate(efw, &sampling_rate);
203
if (err < 0)
204
goto err_locked;
205
substream->runtime->hw.rate_min = sampling_rate;
206
substream->runtime->hw.rate_max = sampling_rate;
207
208
if (frames_per_period > 0) {
209
err = snd_pcm_hw_constraint_minmax(substream->runtime,
210
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
211
frames_per_period, frames_per_period);
212
if (err < 0)
213
goto err_locked;
214
215
err = snd_pcm_hw_constraint_minmax(substream->runtime,
216
SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
217
frames_per_buffer, frames_per_buffer);
218
if (err < 0)
219
goto err_locked;
220
}
221
}
222
}
223
224
snd_pcm_set_sync(substream);
225
226
return 0;
227
err_locked:
228
snd_efw_stream_lock_release(efw);
229
return err;
230
}
231
232
static int pcm_close(struct snd_pcm_substream *substream)
233
{
234
struct snd_efw *efw = substream->private_data;
235
snd_efw_stream_lock_release(efw);
236
return 0;
237
}
238
239
static int pcm_hw_params(struct snd_pcm_substream *substream,
240
struct snd_pcm_hw_params *hw_params)
241
{
242
struct snd_efw *efw = substream->private_data;
243
int err = 0;
244
245
if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
246
unsigned int rate = params_rate(hw_params);
247
unsigned int frames_per_period = params_period_size(hw_params);
248
unsigned int frames_per_buffer = params_buffer_size(hw_params);
249
250
guard(mutex)(&efw->mutex);
251
err = snd_efw_stream_reserve_duplex(efw, rate,
252
frames_per_period, frames_per_buffer);
253
if (err >= 0)
254
++efw->substreams_counter;
255
}
256
257
return err;
258
}
259
260
static int pcm_hw_free(struct snd_pcm_substream *substream)
261
{
262
struct snd_efw *efw = substream->private_data;
263
264
guard(mutex)(&efw->mutex);
265
266
if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
267
--efw->substreams_counter;
268
269
snd_efw_stream_stop_duplex(efw);
270
271
return 0;
272
}
273
274
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
275
{
276
struct snd_efw *efw = substream->private_data;
277
int err;
278
279
err = snd_efw_stream_start_duplex(efw);
280
if (err >= 0)
281
amdtp_stream_pcm_prepare(&efw->tx_stream);
282
283
return err;
284
}
285
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
286
{
287
struct snd_efw *efw = substream->private_data;
288
int err;
289
290
err = snd_efw_stream_start_duplex(efw);
291
if (err >= 0)
292
amdtp_stream_pcm_prepare(&efw->rx_stream);
293
294
return err;
295
}
296
297
static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
298
{
299
struct snd_efw *efw = substream->private_data;
300
301
switch (cmd) {
302
case SNDRV_PCM_TRIGGER_START:
303
amdtp_stream_pcm_trigger(&efw->tx_stream, substream);
304
break;
305
case SNDRV_PCM_TRIGGER_STOP:
306
amdtp_stream_pcm_trigger(&efw->tx_stream, NULL);
307
break;
308
default:
309
return -EINVAL;
310
}
311
312
return 0;
313
}
314
static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
315
{
316
struct snd_efw *efw = substream->private_data;
317
318
switch (cmd) {
319
case SNDRV_PCM_TRIGGER_START:
320
amdtp_stream_pcm_trigger(&efw->rx_stream, substream);
321
break;
322
case SNDRV_PCM_TRIGGER_STOP:
323
amdtp_stream_pcm_trigger(&efw->rx_stream, NULL);
324
break;
325
default:
326
return -EINVAL;
327
}
328
329
return 0;
330
}
331
332
static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
333
{
334
struct snd_efw *efw = sbstrm->private_data;
335
336
return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->tx_stream);
337
}
338
static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
339
{
340
struct snd_efw *efw = sbstrm->private_data;
341
342
return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->rx_stream);
343
}
344
345
static int pcm_capture_ack(struct snd_pcm_substream *substream)
346
{
347
struct snd_efw *efw = substream->private_data;
348
349
return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->tx_stream);
350
}
351
352
static int pcm_playback_ack(struct snd_pcm_substream *substream)
353
{
354
struct snd_efw *efw = substream->private_data;
355
356
return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->rx_stream);
357
}
358
359
int snd_efw_create_pcm_devices(struct snd_efw *efw)
360
{
361
static const struct snd_pcm_ops capture_ops = {
362
.open = pcm_open,
363
.close = pcm_close,
364
.hw_params = pcm_hw_params,
365
.hw_free = pcm_hw_free,
366
.prepare = pcm_capture_prepare,
367
.trigger = pcm_capture_trigger,
368
.pointer = pcm_capture_pointer,
369
.ack = pcm_capture_ack,
370
};
371
static const struct snd_pcm_ops playback_ops = {
372
.open = pcm_open,
373
.close = pcm_close,
374
.hw_params = pcm_hw_params,
375
.hw_free = pcm_hw_free,
376
.prepare = pcm_playback_prepare,
377
.trigger = pcm_playback_trigger,
378
.pointer = pcm_playback_pointer,
379
.ack = pcm_playback_ack,
380
};
381
struct snd_pcm *pcm;
382
int err;
383
384
err = snd_pcm_new(efw->card, efw->card->driver, 0, 1, 1, &pcm);
385
if (err < 0)
386
goto end;
387
388
pcm->private_data = efw;
389
pcm->nonatomic = true;
390
snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);
391
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
392
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
393
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
394
end:
395
return err;
396
}
397
398
399