xref: /openbmc/linux/sound/firewire/motu/motu-pcm.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2dd49b2d1STakashi Sakamoto /*
3dd49b2d1STakashi Sakamoto  * motu-pcm.c - a part of driver for MOTU FireWire series
4dd49b2d1STakashi Sakamoto  *
5dd49b2d1STakashi Sakamoto  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6dd49b2d1STakashi Sakamoto  */
7dd49b2d1STakashi Sakamoto 
8dd49b2d1STakashi Sakamoto #include <sound/pcm_params.h>
9dd49b2d1STakashi Sakamoto #include "motu.h"
10dd49b2d1STakashi Sakamoto 
motu_rate_constraint(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)11dd49b2d1STakashi Sakamoto static int motu_rate_constraint(struct snd_pcm_hw_params *params,
12dd49b2d1STakashi Sakamoto 				struct snd_pcm_hw_rule *rule)
13dd49b2d1STakashi Sakamoto {
14dd49b2d1STakashi Sakamoto 	struct snd_motu_packet_format *formats = rule->private;
15dd49b2d1STakashi Sakamoto 
16dd49b2d1STakashi Sakamoto 	const struct snd_interval *c =
17dd49b2d1STakashi Sakamoto 		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
18dd49b2d1STakashi Sakamoto 	struct snd_interval *r =
19dd49b2d1STakashi Sakamoto 		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
20dd49b2d1STakashi Sakamoto 	struct snd_interval rates = {
21dd49b2d1STakashi Sakamoto 		.min = UINT_MAX, .max = 0, .integer = 1
22dd49b2d1STakashi Sakamoto 	};
23dd49b2d1STakashi Sakamoto 	unsigned int i, pcm_channels, rate, mode;
24dd49b2d1STakashi Sakamoto 
25dd49b2d1STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
26dd49b2d1STakashi Sakamoto 		rate = snd_motu_clock_rates[i];
27dd49b2d1STakashi Sakamoto 		mode = i / 2;
28dd49b2d1STakashi Sakamoto 
299883b385STakashi Sakamoto 		pcm_channels = formats->pcm_chunks[mode];
30dd49b2d1STakashi Sakamoto 		if (!snd_interval_test(c, pcm_channels))
31dd49b2d1STakashi Sakamoto 			continue;
32dd49b2d1STakashi Sakamoto 
33dd49b2d1STakashi Sakamoto 		rates.min = min(rates.min, rate);
34dd49b2d1STakashi Sakamoto 		rates.max = max(rates.max, rate);
35dd49b2d1STakashi Sakamoto 	}
36dd49b2d1STakashi Sakamoto 
37dd49b2d1STakashi Sakamoto 	return snd_interval_refine(r, &rates);
38dd49b2d1STakashi Sakamoto }
39dd49b2d1STakashi Sakamoto 
motu_channels_constraint(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)40dd49b2d1STakashi Sakamoto static int motu_channels_constraint(struct snd_pcm_hw_params *params,
41dd49b2d1STakashi Sakamoto 				    struct snd_pcm_hw_rule *rule)
42dd49b2d1STakashi Sakamoto {
43dd49b2d1STakashi Sakamoto 	struct snd_motu_packet_format *formats = rule->private;
44dd49b2d1STakashi Sakamoto 
45dd49b2d1STakashi Sakamoto 	const struct snd_interval *r =
46dd49b2d1STakashi Sakamoto 		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
47dd49b2d1STakashi Sakamoto 	struct snd_interval *c =
48dd49b2d1STakashi Sakamoto 		hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
49dd49b2d1STakashi Sakamoto 	struct snd_interval channels = {
50dd49b2d1STakashi Sakamoto 		.min = UINT_MAX, .max = 0, .integer = 1
51dd49b2d1STakashi Sakamoto 	};
52dd49b2d1STakashi Sakamoto 	unsigned int i, pcm_channels, rate, mode;
53dd49b2d1STakashi Sakamoto 
54dd49b2d1STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
55dd49b2d1STakashi Sakamoto 		rate = snd_motu_clock_rates[i];
56dd49b2d1STakashi Sakamoto 		mode = i / 2;
57dd49b2d1STakashi Sakamoto 
58dd49b2d1STakashi Sakamoto 		if (!snd_interval_test(r, rate))
59dd49b2d1STakashi Sakamoto 			continue;
60dd49b2d1STakashi Sakamoto 
619883b385STakashi Sakamoto 		pcm_channels = formats->pcm_chunks[mode];
62dd49b2d1STakashi Sakamoto 		channels.min = min(channels.min, pcm_channels);
63dd49b2d1STakashi Sakamoto 		channels.max = max(channels.max, pcm_channels);
64dd49b2d1STakashi Sakamoto 	}
65dd49b2d1STakashi Sakamoto 
66dd49b2d1STakashi Sakamoto 	return snd_interval_refine(c, &channels);
67dd49b2d1STakashi Sakamoto }
68dd49b2d1STakashi Sakamoto 
limit_channels_and_rates(struct snd_motu * motu,struct snd_pcm_runtime * runtime,struct snd_motu_packet_format * formats)69dd49b2d1STakashi Sakamoto static void limit_channels_and_rates(struct snd_motu *motu,
70dd49b2d1STakashi Sakamoto 				     struct snd_pcm_runtime *runtime,
71dd49b2d1STakashi Sakamoto 				     struct snd_motu_packet_format *formats)
72dd49b2d1STakashi Sakamoto {
73dd49b2d1STakashi Sakamoto 	struct snd_pcm_hardware *hw = &runtime->hw;
74dd49b2d1STakashi Sakamoto 	unsigned int i, pcm_channels, rate, mode;
75dd49b2d1STakashi Sakamoto 
76dd49b2d1STakashi Sakamoto 	hw->channels_min = UINT_MAX;
77dd49b2d1STakashi Sakamoto 	hw->channels_max = 0;
78dd49b2d1STakashi Sakamoto 
79dd49b2d1STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
80dd49b2d1STakashi Sakamoto 		rate = snd_motu_clock_rates[i];
81dd49b2d1STakashi Sakamoto 		mode = i / 2;
82dd49b2d1STakashi Sakamoto 
839883b385STakashi Sakamoto 		pcm_channels = formats->pcm_chunks[mode];
84dd49b2d1STakashi Sakamoto 		if (pcm_channels == 0)
85dd49b2d1STakashi Sakamoto 			continue;
86dd49b2d1STakashi Sakamoto 
87dd49b2d1STakashi Sakamoto 		hw->rates |= snd_pcm_rate_to_rate_bit(rate);
88dd49b2d1STakashi Sakamoto 		hw->channels_min = min(hw->channels_min, pcm_channels);
89dd49b2d1STakashi Sakamoto 		hw->channels_max = max(hw->channels_max, pcm_channels);
90dd49b2d1STakashi Sakamoto 	}
91dd49b2d1STakashi Sakamoto 
92dd49b2d1STakashi Sakamoto 	snd_pcm_limit_hw_rates(runtime);
93dd49b2d1STakashi Sakamoto }
94dd49b2d1STakashi Sakamoto 
init_hw_info(struct snd_motu * motu,struct snd_pcm_substream * substream)95dd49b2d1STakashi Sakamoto static int init_hw_info(struct snd_motu *motu,
96dd49b2d1STakashi Sakamoto 			struct snd_pcm_substream *substream)
97dd49b2d1STakashi Sakamoto {
98dd49b2d1STakashi Sakamoto 	struct snd_pcm_runtime *runtime = substream->runtime;
99dd49b2d1STakashi Sakamoto 	struct snd_pcm_hardware *hw = &runtime->hw;
100dd49b2d1STakashi Sakamoto 	struct amdtp_stream *stream;
101dd49b2d1STakashi Sakamoto 	struct snd_motu_packet_format *formats;
102dd49b2d1STakashi Sakamoto 	int err;
103dd49b2d1STakashi Sakamoto 
104dd49b2d1STakashi Sakamoto 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
105dd49b2d1STakashi Sakamoto 		hw->formats = SNDRV_PCM_FMTBIT_S32;
106dd49b2d1STakashi Sakamoto 		stream = &motu->tx_stream;
107dd49b2d1STakashi Sakamoto 		formats = &motu->tx_packet_formats;
108dd49b2d1STakashi Sakamoto 	} else {
109dd49b2d1STakashi Sakamoto 		hw->formats = SNDRV_PCM_FMTBIT_S32;
110dd49b2d1STakashi Sakamoto 		stream = &motu->rx_stream;
111dd49b2d1STakashi Sakamoto 		formats = &motu->rx_packet_formats;
112dd49b2d1STakashi Sakamoto 	}
113dd49b2d1STakashi Sakamoto 
114dd49b2d1STakashi Sakamoto 	limit_channels_and_rates(motu, runtime, formats);
115dd49b2d1STakashi Sakamoto 
116dd49b2d1STakashi Sakamoto 	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
117dd49b2d1STakashi Sakamoto 				  motu_rate_constraint, formats,
118dd49b2d1STakashi Sakamoto 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
119dd49b2d1STakashi Sakamoto 	if (err < 0)
120dd49b2d1STakashi Sakamoto 		return err;
121dd49b2d1STakashi Sakamoto 	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
122dd49b2d1STakashi Sakamoto 				  motu_channels_constraint, formats,
123dd49b2d1STakashi Sakamoto 				  SNDRV_PCM_HW_PARAM_RATE, -1);
124dd49b2d1STakashi Sakamoto 	if (err < 0)
125dd49b2d1STakashi Sakamoto 		return err;
126dd49b2d1STakashi Sakamoto 
127dd49b2d1STakashi Sakamoto 	return amdtp_motu_add_pcm_hw_constraints(stream, runtime);
128dd49b2d1STakashi Sakamoto }
129dd49b2d1STakashi Sakamoto 
pcm_open(struct snd_pcm_substream * substream)130dd49b2d1STakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream)
131dd49b2d1STakashi Sakamoto {
132dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
1333fd80b20STakashi Sakamoto 	struct amdtp_domain *d = &motu->domain;
134dd49b2d1STakashi Sakamoto 	enum snd_motu_clock_source src;
135dd49b2d1STakashi Sakamoto 	int err;
136dd49b2d1STakashi Sakamoto 
13771c37977STakashi Sakamoto 	err = snd_motu_stream_lock_try(motu);
13871c37977STakashi Sakamoto 	if (err < 0)
13971c37977STakashi Sakamoto 		return err;
14071c37977STakashi Sakamoto 
141dd49b2d1STakashi Sakamoto 	mutex_lock(&motu->mutex);
142dd49b2d1STakashi Sakamoto 
1438b460c76STakashi Sakamoto 	err = snd_motu_stream_cache_packet_formats(motu);
144dd49b2d1STakashi Sakamoto 	if (err < 0)
14571c37977STakashi Sakamoto 		goto err_locked;
146dd49b2d1STakashi Sakamoto 
147dd49b2d1STakashi Sakamoto 	err = init_hw_info(motu, substream);
148dd49b2d1STakashi Sakamoto 	if (err < 0)
14971c37977STakashi Sakamoto 		goto err_locked;
150dd49b2d1STakashi Sakamoto 
151ff222b7eSTakashi Sakamoto 	err = snd_motu_protocol_get_clock_source(motu, &src);
152dd49b2d1STakashi Sakamoto 	if (err < 0)
15371c37977STakashi Sakamoto 		goto err_locked;
1543fd80b20STakashi Sakamoto 
1553fd80b20STakashi Sakamoto 	// When source of clock is not internal or any stream is reserved for
1563fd80b20STakashi Sakamoto 	// transmission of PCM frames, the available sampling rate is limited
1573fd80b20STakashi Sakamoto 	// at current one.
1583f58f004STakashi Sakamoto 	if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL &&
1593f58f004STakashi Sakamoto 	     src != SND_MOTU_CLOCK_SOURCE_SPH) ||
1603fd80b20STakashi Sakamoto 	    (motu->substreams_counter > 0 && d->events_per_period > 0)) {
1613fd80b20STakashi Sakamoto 		unsigned int frames_per_period = d->events_per_period;
1620f5482e7STakashi Sakamoto 		unsigned int frames_per_buffer = d->events_per_buffer;
1633fd80b20STakashi Sakamoto 		unsigned int rate;
1643fd80b20STakashi Sakamoto 
165ff222b7eSTakashi Sakamoto 		err = snd_motu_protocol_get_clock_rate(motu, &rate);
166dd49b2d1STakashi Sakamoto 		if (err < 0)
16771c37977STakashi Sakamoto 			goto err_locked;
1683fd80b20STakashi Sakamoto 
169dd49b2d1STakashi Sakamoto 		substream->runtime->hw.rate_min = rate;
170dd49b2d1STakashi Sakamoto 		substream->runtime->hw.rate_max = rate;
1713fd80b20STakashi Sakamoto 
1723fd80b20STakashi Sakamoto 		if (frames_per_period > 0) {
1733fd80b20STakashi Sakamoto 			err = snd_pcm_hw_constraint_minmax(substream->runtime,
1743fd80b20STakashi Sakamoto 					SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1753fd80b20STakashi Sakamoto 					frames_per_period, frames_per_period);
1769ff3483eSTakashi Sakamoto 			if (err < 0)
1773fd80b20STakashi Sakamoto 				goto err_locked;
1780f5482e7STakashi Sakamoto 
1790f5482e7STakashi Sakamoto 			err = snd_pcm_hw_constraint_minmax(substream->runtime,
1800f5482e7STakashi Sakamoto 					SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
1810f5482e7STakashi Sakamoto 					frames_per_buffer, frames_per_buffer);
1829ff3483eSTakashi Sakamoto 			if (err < 0)
1830f5482e7STakashi Sakamoto 				goto err_locked;
1840f5482e7STakashi Sakamoto 		}
1853fd80b20STakashi Sakamoto 	}
186dd49b2d1STakashi Sakamoto 
187dd49b2d1STakashi Sakamoto 	snd_pcm_set_sync(substream);
188dd49b2d1STakashi Sakamoto 
189dd49b2d1STakashi Sakamoto 	mutex_unlock(&motu->mutex);
190dd49b2d1STakashi Sakamoto 
1913fd80b20STakashi Sakamoto 	return 0;
19271c37977STakashi Sakamoto err_locked:
19371c37977STakashi Sakamoto 	mutex_unlock(&motu->mutex);
19471c37977STakashi Sakamoto 	snd_motu_stream_lock_release(motu);
19571c37977STakashi Sakamoto 	return err;
196dd49b2d1STakashi Sakamoto }
197dd49b2d1STakashi Sakamoto 
pcm_close(struct snd_pcm_substream * substream)198dd49b2d1STakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream)
199dd49b2d1STakashi Sakamoto {
20071c37977STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
20171c37977STakashi Sakamoto 
20271c37977STakashi Sakamoto 	snd_motu_stream_lock_release(motu);
20371c37977STakashi Sakamoto 
204dd49b2d1STakashi Sakamoto 	return 0;
205dd49b2d1STakashi Sakamoto }
206dd49b2d1STakashi Sakamoto 
pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)20715d472ecSTakashi Sakamoto static int pcm_hw_params(struct snd_pcm_substream *substream,
208dd49b2d1STakashi Sakamoto 			 struct snd_pcm_hw_params *hw_params)
209dd49b2d1STakashi Sakamoto {
210dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
2117641d549STakashi Iwai 	int err = 0;
212dd49b2d1STakashi Sakamoto 
213*23cb0767STakashi Iwai 	if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
2148edc56ecSTakashi Sakamoto 		unsigned int rate = params_rate(hw_params);
2150d39cd0eSTakashi Sakamoto 		unsigned int frames_per_period = params_period_size(hw_params);
2160f5482e7STakashi Sakamoto 		unsigned int frames_per_buffer = params_buffer_size(hw_params);
2178edc56ecSTakashi Sakamoto 
218dd49b2d1STakashi Sakamoto 		mutex_lock(&motu->mutex);
2190d39cd0eSTakashi Sakamoto 		err = snd_motu_stream_reserve_duplex(motu, rate,
2200f5482e7STakashi Sakamoto 					frames_per_period, frames_per_buffer);
2218edc56ecSTakashi Sakamoto 		if (err >= 0)
2228edc56ecSTakashi Sakamoto 			++motu->substreams_counter;
223dd49b2d1STakashi Sakamoto 		mutex_unlock(&motu->mutex);
224dd49b2d1STakashi Sakamoto 	}
225dd49b2d1STakashi Sakamoto 
2268edc56ecSTakashi Sakamoto 	return err;
227dd49b2d1STakashi Sakamoto }
228dd49b2d1STakashi Sakamoto 
pcm_hw_free(struct snd_pcm_substream * substream)22915d472ecSTakashi Sakamoto static int pcm_hw_free(struct snd_pcm_substream *substream)
230dd49b2d1STakashi Sakamoto {
231dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
232dd49b2d1STakashi Sakamoto 
233dd49b2d1STakashi Sakamoto 	mutex_lock(&motu->mutex);
234dd49b2d1STakashi Sakamoto 
235*23cb0767STakashi Iwai 	if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
2368edc56ecSTakashi Sakamoto 		--motu->substreams_counter;
237dd49b2d1STakashi Sakamoto 
238dd49b2d1STakashi Sakamoto 	snd_motu_stream_stop_duplex(motu);
239dd49b2d1STakashi Sakamoto 
240dd49b2d1STakashi Sakamoto 	mutex_unlock(&motu->mutex);
241dd49b2d1STakashi Sakamoto 
2427641d549STakashi Iwai 	return 0;
243dd49b2d1STakashi Sakamoto }
244dd49b2d1STakashi Sakamoto 
capture_prepare(struct snd_pcm_substream * substream)245dd49b2d1STakashi Sakamoto static int capture_prepare(struct snd_pcm_substream *substream)
246dd49b2d1STakashi Sakamoto {
247dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
248dd49b2d1STakashi Sakamoto 	int err;
249dd49b2d1STakashi Sakamoto 
250dd49b2d1STakashi Sakamoto 	mutex_lock(&motu->mutex);
2518edc56ecSTakashi Sakamoto 	err = snd_motu_stream_start_duplex(motu);
252dd49b2d1STakashi Sakamoto 	mutex_unlock(&motu->mutex);
253dd49b2d1STakashi Sakamoto 	if (err >= 0)
254dd49b2d1STakashi Sakamoto 		amdtp_stream_pcm_prepare(&motu->tx_stream);
255dd49b2d1STakashi Sakamoto 
256dd49b2d1STakashi Sakamoto 	return 0;
257dd49b2d1STakashi Sakamoto }
playback_prepare(struct snd_pcm_substream * substream)258dd49b2d1STakashi Sakamoto static int playback_prepare(struct snd_pcm_substream *substream)
259dd49b2d1STakashi Sakamoto {
260dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
261dd49b2d1STakashi Sakamoto 	int err;
262dd49b2d1STakashi Sakamoto 
263dd49b2d1STakashi Sakamoto 	mutex_lock(&motu->mutex);
2648edc56ecSTakashi Sakamoto 	err = snd_motu_stream_start_duplex(motu);
265dd49b2d1STakashi Sakamoto 	mutex_unlock(&motu->mutex);
266dd49b2d1STakashi Sakamoto 	if (err >= 0)
267dd49b2d1STakashi Sakamoto 		amdtp_stream_pcm_prepare(&motu->rx_stream);
268dd49b2d1STakashi Sakamoto 
269dd49b2d1STakashi Sakamoto 	return err;
270dd49b2d1STakashi Sakamoto }
271dd49b2d1STakashi Sakamoto 
capture_trigger(struct snd_pcm_substream * substream,int cmd)272dd49b2d1STakashi Sakamoto static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
273dd49b2d1STakashi Sakamoto {
274dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
275dd49b2d1STakashi Sakamoto 
276dd49b2d1STakashi Sakamoto 	switch (cmd) {
277dd49b2d1STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_START:
278dd49b2d1STakashi Sakamoto 		amdtp_stream_pcm_trigger(&motu->tx_stream, substream);
279dd49b2d1STakashi Sakamoto 		break;
280dd49b2d1STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_STOP:
281dd49b2d1STakashi Sakamoto 		amdtp_stream_pcm_trigger(&motu->tx_stream, NULL);
282dd49b2d1STakashi Sakamoto 		break;
283dd49b2d1STakashi Sakamoto 	default:
284dd49b2d1STakashi Sakamoto 		return -EINVAL;
285dd49b2d1STakashi Sakamoto 	}
286dd49b2d1STakashi Sakamoto 
287dd49b2d1STakashi Sakamoto 	return 0;
288dd49b2d1STakashi Sakamoto }
playback_trigger(struct snd_pcm_substream * substream,int cmd)289dd49b2d1STakashi Sakamoto static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
290dd49b2d1STakashi Sakamoto {
291dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
292dd49b2d1STakashi Sakamoto 
293dd49b2d1STakashi Sakamoto 	switch (cmd) {
294dd49b2d1STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_START:
295dd49b2d1STakashi Sakamoto 		amdtp_stream_pcm_trigger(&motu->rx_stream, substream);
296dd49b2d1STakashi Sakamoto 		break;
297dd49b2d1STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_STOP:
298dd49b2d1STakashi Sakamoto 		amdtp_stream_pcm_trigger(&motu->rx_stream, NULL);
299dd49b2d1STakashi Sakamoto 		break;
300dd49b2d1STakashi Sakamoto 	default:
301dd49b2d1STakashi Sakamoto 		return -EINVAL;
302dd49b2d1STakashi Sakamoto 	}
303dd49b2d1STakashi Sakamoto 
304dd49b2d1STakashi Sakamoto 	return 0;
305dd49b2d1STakashi Sakamoto }
306dd49b2d1STakashi Sakamoto 
capture_pointer(struct snd_pcm_substream * substream)307dd49b2d1STakashi Sakamoto static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
308dd49b2d1STakashi Sakamoto {
309dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
310dd49b2d1STakashi Sakamoto 
311f890f9a0STakashi Sakamoto 	return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->tx_stream);
312dd49b2d1STakashi Sakamoto }
playback_pointer(struct snd_pcm_substream * substream)313dd49b2d1STakashi Sakamoto static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
314dd49b2d1STakashi Sakamoto {
315dd49b2d1STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
316dd49b2d1STakashi Sakamoto 
317f890f9a0STakashi Sakamoto 	return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->rx_stream);
318dd49b2d1STakashi Sakamoto }
319dd49b2d1STakashi Sakamoto 
capture_ack(struct snd_pcm_substream * substream)320875becf8STakashi Sakamoto static int capture_ack(struct snd_pcm_substream *substream)
321875becf8STakashi Sakamoto {
322875becf8STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
323875becf8STakashi Sakamoto 
324e6dcc92fSTakashi Sakamoto 	return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->tx_stream);
325875becf8STakashi Sakamoto }
326875becf8STakashi Sakamoto 
playback_ack(struct snd_pcm_substream * substream)327875becf8STakashi Sakamoto static int playback_ack(struct snd_pcm_substream *substream)
328875becf8STakashi Sakamoto {
329875becf8STakashi Sakamoto 	struct snd_motu *motu = substream->private_data;
330875becf8STakashi Sakamoto 
331e6dcc92fSTakashi Sakamoto 	return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->rx_stream);
332875becf8STakashi Sakamoto }
333875becf8STakashi Sakamoto 
snd_motu_create_pcm_devices(struct snd_motu * motu)334dd49b2d1STakashi Sakamoto int snd_motu_create_pcm_devices(struct snd_motu *motu)
335dd49b2d1STakashi Sakamoto {
336b2165f38SArvind Yadav 	static const struct snd_pcm_ops capture_ops = {
337dd49b2d1STakashi Sakamoto 		.open      = pcm_open,
338dd49b2d1STakashi Sakamoto 		.close     = pcm_close,
33915d472ecSTakashi Sakamoto 		.hw_params = pcm_hw_params,
34015d472ecSTakashi Sakamoto 		.hw_free   = pcm_hw_free,
341dd49b2d1STakashi Sakamoto 		.prepare   = capture_prepare,
342dd49b2d1STakashi Sakamoto 		.trigger   = capture_trigger,
343dd49b2d1STakashi Sakamoto 		.pointer   = capture_pointer,
344875becf8STakashi Sakamoto 		.ack       = capture_ack,
345dd49b2d1STakashi Sakamoto 	};
346b2165f38SArvind Yadav 	static const struct snd_pcm_ops playback_ops = {
347dd49b2d1STakashi Sakamoto 		.open      = pcm_open,
348dd49b2d1STakashi Sakamoto 		.close     = pcm_close,
34915d472ecSTakashi Sakamoto 		.hw_params = pcm_hw_params,
35015d472ecSTakashi Sakamoto 		.hw_free   = pcm_hw_free,
351dd49b2d1STakashi Sakamoto 		.prepare   = playback_prepare,
352dd49b2d1STakashi Sakamoto 		.trigger   = playback_trigger,
353dd49b2d1STakashi Sakamoto 		.pointer   = playback_pointer,
354875becf8STakashi Sakamoto 		.ack       = playback_ack,
355dd49b2d1STakashi Sakamoto 	};
356dd49b2d1STakashi Sakamoto 	struct snd_pcm *pcm;
357dd49b2d1STakashi Sakamoto 	int err;
358dd49b2d1STakashi Sakamoto 
359dd49b2d1STakashi Sakamoto 	err = snd_pcm_new(motu->card, motu->card->driver, 0, 1, 1, &pcm);
360dd49b2d1STakashi Sakamoto 	if (err < 0)
361dd49b2d1STakashi Sakamoto 		return err;
362dd49b2d1STakashi Sakamoto 	pcm->private_data = motu;
363dd49b2d1STakashi Sakamoto 	strcpy(pcm->name, motu->card->shortname);
364dd49b2d1STakashi Sakamoto 
365dd49b2d1STakashi Sakamoto 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
366dd49b2d1STakashi Sakamoto 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
3677641d549STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
368dd49b2d1STakashi Sakamoto 
369dd49b2d1STakashi Sakamoto 	return 0;
370dd49b2d1STakashi Sakamoto }
371