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 <o-takashi@sakamocchi.jp> |
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(i: c, val: 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(i: r, v: &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(i: r, val: 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(i: c, v: &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, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
117 | func: motu_rate_constraint, private: formats, |
118 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
119 | if (err < 0) |
120 | return err; |
121 | err = snd_pcm_hw_rule_add(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
122 | func: motu_channels_constraint, private: formats, |
123 | SNDRV_PCM_HW_PARAM_RATE, -1); |
124 | if (err < 0) |
125 | return err; |
126 | |
127 | return amdtp_motu_add_pcm_hw_constraints(s: 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, source: &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: &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(runtime: substream->runtime, |
174 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
175 | min: frames_per_period, max: frames_per_period); |
176 | if (err < 0) |
177 | goto err_locked; |
178 | |
179 | err = snd_pcm_hw_constraint_minmax(runtime: substream->runtime, |
180 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
181 | min: frames_per_buffer, max: frames_per_buffer); |
182 | if (err < 0) |
183 | goto err_locked; |
184 | } |
185 | } |
186 | |
187 | snd_pcm_set_sync(substream); |
188 | |
189 | mutex_unlock(lock: &motu->mutex); |
190 | |
191 | return 0; |
192 | err_locked: |
193 | mutex_unlock(lock: &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(p: hw_params); |
215 | unsigned int frames_per_period = params_period_size(p: hw_params); |
216 | unsigned int frames_per_buffer = params_buffer_size(p: 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(lock: &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(lock: &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(lock: &motu->mutex); |
253 | if (err >= 0) |
254 | amdtp_stream_pcm_prepare(s: &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(lock: &motu->mutex); |
266 | if (err >= 0) |
267 | amdtp_stream_pcm_prepare(s: &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(s: &motu->tx_stream, pcm: substream); |
279 | break; |
280 | case SNDRV_PCM_TRIGGER_STOP: |
281 | amdtp_stream_pcm_trigger(s: &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(s: &motu->rx_stream, pcm: substream); |
296 | break; |
297 | case SNDRV_PCM_TRIGGER_STOP: |
298 | amdtp_stream_pcm_trigger(s: &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(d: &motu->domain, s: &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(d: &motu->domain, s: &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(d: &motu->domain, s: &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(d: &motu->domain, s: &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(card: motu->card, id: motu->card->driver, device: 0, playback_count: 1, capture_count: 1, rpcm: &pcm); |
360 | if (err < 0) |
361 | return err; |
362 | pcm->private_data = motu; |
363 | strcpy(p: pcm->name, q: motu->card->shortname); |
364 | |
365 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, ops: &capture_ops); |
366 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_PLAYBACK, ops: &playback_ops); |
367 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, size: 0, max: 0); |
368 | |
369 | return 0; |
370 | } |
371 | |