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
11static 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
40static 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
69static 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
95static 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
130static 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;
192err_locked:
193	mutex_unlock(&motu->mutex);
194	snd_motu_stream_lock_release(motu);
195	return err;
196}
197
198static 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
207static 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
229static 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
245static 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}
258static 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
272static 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}
289static 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
307static 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}
313static 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
320static 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
327static 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
334int 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	strcpy(pcm->name, motu->card->shortname);
364
365	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
366	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
367	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
368
369	return 0;
370}
371