xref: /linux/sound/firewire/fireface/ff-pcm.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24b316436STakashi Sakamoto /*
34b316436STakashi Sakamoto  * ff-pcm.c - a part of driver for RME Fireface series
44b316436STakashi Sakamoto  *
54b316436STakashi Sakamoto  * Copyright (c) 2015-2017 Takashi Sakamoto
64b316436STakashi Sakamoto  */
74b316436STakashi Sakamoto 
84b316436STakashi Sakamoto #include "ff.h"
94b316436STakashi Sakamoto 
hw_rule_rate(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)104b316436STakashi Sakamoto static int hw_rule_rate(struct snd_pcm_hw_params *params,
114b316436STakashi Sakamoto 			struct snd_pcm_hw_rule *rule)
124b316436STakashi Sakamoto {
134b316436STakashi Sakamoto 	const unsigned int *pcm_channels = rule->private;
144b316436STakashi Sakamoto 	struct snd_interval *r =
154b316436STakashi Sakamoto 		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
164b316436STakashi Sakamoto 	const struct snd_interval *c =
174b316436STakashi Sakamoto 		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
184b316436STakashi Sakamoto 	struct snd_interval t = {
194b316436STakashi Sakamoto 		.min = UINT_MAX, .max = 0, .integer = 1
204b316436STakashi Sakamoto 	};
2176ea4688STakashi Sakamoto 	unsigned int i;
224b316436STakashi Sakamoto 
234b316436STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
2476ea4688STakashi Sakamoto 		enum snd_ff_stream_mode mode;
2576ea4688STakashi Sakamoto 		int err;
2676ea4688STakashi Sakamoto 
2776ea4688STakashi Sakamoto 		err = snd_ff_stream_get_multiplier_mode(i, &mode);
2876ea4688STakashi Sakamoto 		if (err < 0)
2976ea4688STakashi Sakamoto 			continue;
3076ea4688STakashi Sakamoto 
314b316436STakashi Sakamoto 		if (!snd_interval_test(c, pcm_channels[mode]))
324b316436STakashi Sakamoto 			continue;
334b316436STakashi Sakamoto 
344b316436STakashi Sakamoto 		t.min = min(t.min, amdtp_rate_table[i]);
354b316436STakashi Sakamoto 		t.max = max(t.max, amdtp_rate_table[i]);
364b316436STakashi Sakamoto 	}
374b316436STakashi Sakamoto 
384b316436STakashi Sakamoto 	return snd_interval_refine(r, &t);
394b316436STakashi Sakamoto }
404b316436STakashi Sakamoto 
hw_rule_channels(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)414b316436STakashi Sakamoto static int hw_rule_channels(struct snd_pcm_hw_params *params,
424b316436STakashi Sakamoto 			    struct snd_pcm_hw_rule *rule)
434b316436STakashi Sakamoto {
444b316436STakashi Sakamoto 	const unsigned int *pcm_channels = rule->private;
454b316436STakashi Sakamoto 	struct snd_interval *c =
464b316436STakashi Sakamoto 		hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
474b316436STakashi Sakamoto 	const struct snd_interval *r =
484b316436STakashi Sakamoto 		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
494b316436STakashi Sakamoto 	struct snd_interval t = {
504b316436STakashi Sakamoto 		.min = UINT_MAX, .max = 0, .integer = 1
514b316436STakashi Sakamoto 	};
5276ea4688STakashi Sakamoto 	unsigned int i;
534b316436STakashi Sakamoto 
544b316436STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
5576ea4688STakashi Sakamoto 		enum snd_ff_stream_mode mode;
5676ea4688STakashi Sakamoto 		int err;
5776ea4688STakashi Sakamoto 
5876ea4688STakashi Sakamoto 		err = snd_ff_stream_get_multiplier_mode(i, &mode);
5976ea4688STakashi Sakamoto 		if (err < 0)
6076ea4688STakashi Sakamoto 			continue;
6176ea4688STakashi Sakamoto 
624b316436STakashi Sakamoto 		if (!snd_interval_test(r, amdtp_rate_table[i]))
634b316436STakashi Sakamoto 			continue;
644b316436STakashi Sakamoto 
654b316436STakashi Sakamoto 		t.min = min(t.min, pcm_channels[mode]);
664b316436STakashi Sakamoto 		t.max = max(t.max, pcm_channels[mode]);
674b316436STakashi Sakamoto 	}
684b316436STakashi Sakamoto 
694b316436STakashi Sakamoto 	return snd_interval_refine(c, &t);
704b316436STakashi Sakamoto }
714b316436STakashi Sakamoto 
limit_channels_and_rates(struct snd_pcm_hardware * hw,const unsigned int * pcm_channels)724b316436STakashi Sakamoto static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
734b316436STakashi Sakamoto 				     const unsigned int *pcm_channels)
744b316436STakashi Sakamoto {
754b316436STakashi Sakamoto 	unsigned int rate, channels;
764b316436STakashi Sakamoto 	int i;
774b316436STakashi Sakamoto 
784b316436STakashi Sakamoto 	hw->channels_min = UINT_MAX;
794b316436STakashi Sakamoto 	hw->channels_max = 0;
804b316436STakashi Sakamoto 	hw->rate_min = UINT_MAX;
814b316436STakashi Sakamoto 	hw->rate_max = 0;
824b316436STakashi Sakamoto 
834b316436STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
8476ea4688STakashi Sakamoto 		enum snd_ff_stream_mode mode;
8576ea4688STakashi Sakamoto 		int err;
8676ea4688STakashi Sakamoto 
8776ea4688STakashi Sakamoto 		err = snd_ff_stream_get_multiplier_mode(i, &mode);
8876ea4688STakashi Sakamoto 		if (err < 0)
8976ea4688STakashi Sakamoto 			continue;
904b316436STakashi Sakamoto 
914b316436STakashi Sakamoto 		channels = pcm_channels[mode];
924b316436STakashi Sakamoto 		if (pcm_channels[mode] == 0)
934b316436STakashi Sakamoto 			continue;
944b316436STakashi Sakamoto 		hw->channels_min = min(hw->channels_min, channels);
954b316436STakashi Sakamoto 		hw->channels_max = max(hw->channels_max, channels);
964b316436STakashi Sakamoto 
974b316436STakashi Sakamoto 		rate = amdtp_rate_table[i];
984b316436STakashi Sakamoto 		hw->rates |= snd_pcm_rate_to_rate_bit(rate);
994b316436STakashi Sakamoto 		hw->rate_min = min(hw->rate_min, rate);
1004b316436STakashi Sakamoto 		hw->rate_max = max(hw->rate_max, rate);
1014b316436STakashi Sakamoto 	}
1024b316436STakashi Sakamoto }
1034b316436STakashi Sakamoto 
pcm_init_hw_params(struct snd_ff * ff,struct snd_pcm_substream * substream)1044b316436STakashi Sakamoto static int pcm_init_hw_params(struct snd_ff *ff,
1054b316436STakashi Sakamoto 			      struct snd_pcm_substream *substream)
1064b316436STakashi Sakamoto {
1074b316436STakashi Sakamoto 	struct snd_pcm_runtime *runtime = substream->runtime;
1084b316436STakashi Sakamoto 	struct amdtp_stream *s;
1094b316436STakashi Sakamoto 	const unsigned int *pcm_channels;
1104b316436STakashi Sakamoto 	int err;
1114b316436STakashi Sakamoto 
1124b316436STakashi Sakamoto 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1134b316436STakashi Sakamoto 		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
1144b316436STakashi Sakamoto 		s = &ff->tx_stream;
1154b316436STakashi Sakamoto 		pcm_channels = ff->spec->pcm_capture_channels;
1164b316436STakashi Sakamoto 	} else {
1174b316436STakashi Sakamoto 		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
1184b316436STakashi Sakamoto 		s = &ff->rx_stream;
1194b316436STakashi Sakamoto 		pcm_channels = ff->spec->pcm_playback_channels;
1204b316436STakashi Sakamoto 	}
1214b316436STakashi Sakamoto 
1224b316436STakashi Sakamoto 	limit_channels_and_rates(&runtime->hw, pcm_channels);
1234b316436STakashi Sakamoto 
1244b316436STakashi Sakamoto 	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
1254b316436STakashi Sakamoto 				  hw_rule_channels, (void *)pcm_channels,
1264b316436STakashi Sakamoto 				  SNDRV_PCM_HW_PARAM_RATE, -1);
1274b316436STakashi Sakamoto 	if (err < 0)
1284b316436STakashi Sakamoto 		return err;
1294b316436STakashi Sakamoto 
1304b316436STakashi Sakamoto 	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
1314b316436STakashi Sakamoto 				  hw_rule_rate, (void *)pcm_channels,
1324b316436STakashi Sakamoto 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
1334b316436STakashi Sakamoto 	if (err < 0)
1344b316436STakashi Sakamoto 		return err;
1354b316436STakashi Sakamoto 
1364b316436STakashi Sakamoto 	return amdtp_ff_add_pcm_hw_constraints(s, runtime);
1374b316436STakashi Sakamoto }
1384b316436STakashi Sakamoto 
pcm_open(struct snd_pcm_substream * substream)1394b316436STakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream)
1404b316436STakashi Sakamoto {
1414b316436STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
1423aac3263STakashi Sakamoto 	struct amdtp_domain *d = &ff->domain;
1434b316436STakashi Sakamoto 	unsigned int rate;
1444b316436STakashi Sakamoto 	enum snd_ff_clock_src src;
1454b316436STakashi Sakamoto 	int i, err;
1464b316436STakashi Sakamoto 
147f656edd5STakashi Sakamoto 	err = snd_ff_stream_lock_try(ff);
1484b316436STakashi Sakamoto 	if (err < 0)
1494b316436STakashi Sakamoto 		return err;
1504b316436STakashi Sakamoto 
151f656edd5STakashi Sakamoto 	err = pcm_init_hw_params(ff, substream);
152af43173cSMarkus Elfring 	if (err < 0)
153af43173cSMarkus Elfring 		goto release_lock;
154f656edd5STakashi Sakamoto 
155b1d0cb0aSTakashi Sakamoto 	err = ff->spec->protocol->get_clock(ff, &rate, &src);
156af43173cSMarkus Elfring 	if (err < 0)
157af43173cSMarkus Elfring 		goto release_lock;
1584b316436STakashi Sakamoto 
1593aac3263STakashi Sakamoto 	mutex_lock(&ff->mutex);
1603aac3263STakashi Sakamoto 
1613aac3263STakashi Sakamoto 	// When source of clock is not internal or any stream is reserved for
1623aac3263STakashi Sakamoto 	// transmission of PCM frames, the available sampling rate is limited
1633aac3263STakashi Sakamoto 	// at current one.
1644b316436STakashi Sakamoto 	if (src != SND_FF_CLOCK_SRC_INTERNAL) {
1654b316436STakashi Sakamoto 		for (i = 0; i < CIP_SFC_COUNT; ++i) {
1664b316436STakashi Sakamoto 			if (amdtp_rate_table[i] == rate)
1674b316436STakashi Sakamoto 				break;
1684b316436STakashi Sakamoto 		}
1693aac3263STakashi Sakamoto 
1703aac3263STakashi Sakamoto 		// The unit is configured at sampling frequency which packet
1713aac3263STakashi Sakamoto 		// streaming engine can't support.
172f656edd5STakashi Sakamoto 		if (i >= CIP_SFC_COUNT) {
1733aac3263STakashi Sakamoto 			mutex_unlock(&ff->mutex);
174af43173cSMarkus Elfring 			err = -EIO;
175af43173cSMarkus Elfring 			goto release_lock;
176f656edd5STakashi Sakamoto 		}
1774b316436STakashi Sakamoto 
1784b316436STakashi Sakamoto 		substream->runtime->hw.rate_min = rate;
1794b316436STakashi Sakamoto 		substream->runtime->hw.rate_max = rate;
1804b316436STakashi Sakamoto 	} else {
1813aac3263STakashi Sakamoto 		if (ff->substreams_counter > 0) {
1823aac3263STakashi Sakamoto 			unsigned int frames_per_period = d->events_per_period;
1834de3eb06STakashi Sakamoto 			unsigned int frames_per_buffer = d->events_per_buffer;
1843aac3263STakashi Sakamoto 
1854b316436STakashi Sakamoto 			rate = amdtp_rate_table[ff->rx_stream.sfc];
1864b316436STakashi Sakamoto 			substream->runtime->hw.rate_min = rate;
1874b316436STakashi Sakamoto 			substream->runtime->hw.rate_max = rate;
1883aac3263STakashi Sakamoto 
1893aac3263STakashi Sakamoto 			err = snd_pcm_hw_constraint_minmax(substream->runtime,
1903aac3263STakashi Sakamoto 					SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1913aac3263STakashi Sakamoto 					frames_per_period, frames_per_period);
1923aac3263STakashi Sakamoto 			if (err < 0) {
1933aac3263STakashi Sakamoto 				mutex_unlock(&ff->mutex);
1943aac3263STakashi Sakamoto 				goto release_lock;
1954b316436STakashi Sakamoto 			}
1964de3eb06STakashi Sakamoto 
1974de3eb06STakashi Sakamoto 			err = snd_pcm_hw_constraint_minmax(substream->runtime,
1984de3eb06STakashi Sakamoto 					SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
1994de3eb06STakashi Sakamoto 					frames_per_buffer, frames_per_buffer);
2004de3eb06STakashi Sakamoto 			if (err < 0) {
2014de3eb06STakashi Sakamoto 				mutex_unlock(&ff->mutex);
2024de3eb06STakashi Sakamoto 				goto release_lock;
2034de3eb06STakashi Sakamoto 			}
2044b316436STakashi Sakamoto 		}
2053aac3263STakashi Sakamoto 	}
2063aac3263STakashi Sakamoto 
2073aac3263STakashi Sakamoto 	mutex_unlock(&ff->mutex);
2084b316436STakashi Sakamoto 
2094b316436STakashi Sakamoto 	snd_pcm_set_sync(substream);
2104b316436STakashi Sakamoto 
2114b316436STakashi Sakamoto 	return 0;
212af43173cSMarkus Elfring 
213af43173cSMarkus Elfring release_lock:
214af43173cSMarkus Elfring 	snd_ff_stream_lock_release(ff);
215af43173cSMarkus Elfring 	return err;
2164b316436STakashi Sakamoto }
2174b316436STakashi Sakamoto 
pcm_close(struct snd_pcm_substream * substream)2184b316436STakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream)
2194b316436STakashi Sakamoto {
220f656edd5STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
221f656edd5STakashi Sakamoto 
222f656edd5STakashi Sakamoto 	snd_ff_stream_lock_release(ff);
223f656edd5STakashi Sakamoto 
2244b316436STakashi Sakamoto 	return 0;
2254b316436STakashi Sakamoto }
2264b316436STakashi Sakamoto 
pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)22749f621feSTakashi Sakamoto static int pcm_hw_params(struct snd_pcm_substream *substream,
2284b316436STakashi Sakamoto 			 struct snd_pcm_hw_params *hw_params)
2294b316436STakashi Sakamoto {
2304b316436STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
2317641d549STakashi Iwai 	int err = 0;
2324b316436STakashi Sakamoto 
23323cb0767STakashi Iwai 	if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
23455162d2bSTakashi Sakamoto 		unsigned int rate = params_rate(hw_params);
2359d9ff58cSTakashi Sakamoto 		unsigned int frames_per_period = params_period_size(hw_params);
2364de3eb06STakashi Sakamoto 		unsigned int frames_per_buffer = params_buffer_size(hw_params);
23755162d2bSTakashi Sakamoto 
2384b316436STakashi Sakamoto 		mutex_lock(&ff->mutex);
2394de3eb06STakashi Sakamoto 		err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period,
2404de3eb06STakashi Sakamoto 						   frames_per_buffer);
24155162d2bSTakashi Sakamoto 		if (err >= 0)
24255162d2bSTakashi Sakamoto 			++ff->substreams_counter;
2434b316436STakashi Sakamoto 		mutex_unlock(&ff->mutex);
2444b316436STakashi Sakamoto 	}
2454b316436STakashi Sakamoto 
24648013634STakashi Sakamoto 	return err;
2474b316436STakashi Sakamoto }
2484b316436STakashi Sakamoto 
pcm_hw_free(struct snd_pcm_substream * substream)24949f621feSTakashi Sakamoto static int pcm_hw_free(struct snd_pcm_substream *substream)
2504b316436STakashi Sakamoto {
2514b316436STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
2524b316436STakashi Sakamoto 
2534b316436STakashi Sakamoto 	mutex_lock(&ff->mutex);
2544b316436STakashi Sakamoto 
25523cb0767STakashi Iwai 	if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
25655162d2bSTakashi Sakamoto 		--ff->substreams_counter;
2574b316436STakashi Sakamoto 
2584b316436STakashi Sakamoto 	snd_ff_stream_stop_duplex(ff);
2594b316436STakashi Sakamoto 
2604b316436STakashi Sakamoto 	mutex_unlock(&ff->mutex);
2614b316436STakashi Sakamoto 
2627641d549STakashi Iwai 	return 0;
2634b316436STakashi Sakamoto }
2644b316436STakashi Sakamoto 
pcm_capture_prepare(struct snd_pcm_substream * substream)2654b316436STakashi Sakamoto static int pcm_capture_prepare(struct snd_pcm_substream *substream)
2664b316436STakashi Sakamoto {
2674b316436STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
2684b316436STakashi Sakamoto 	struct snd_pcm_runtime *runtime = substream->runtime;
2694b316436STakashi Sakamoto 	int err;
2704b316436STakashi Sakamoto 
2714b316436STakashi Sakamoto 	mutex_lock(&ff->mutex);
2724b316436STakashi Sakamoto 
2734b316436STakashi Sakamoto 	err = snd_ff_stream_start_duplex(ff, runtime->rate);
2744b316436STakashi Sakamoto 	if (err >= 0)
2754b316436STakashi Sakamoto 		amdtp_stream_pcm_prepare(&ff->tx_stream);
2764b316436STakashi Sakamoto 
2774b316436STakashi Sakamoto 	mutex_unlock(&ff->mutex);
2784b316436STakashi Sakamoto 
2794b316436STakashi Sakamoto 	return err;
2804b316436STakashi Sakamoto }
2814b316436STakashi Sakamoto 
pcm_playback_prepare(struct snd_pcm_substream * substream)2824b316436STakashi Sakamoto static int pcm_playback_prepare(struct snd_pcm_substream *substream)
2834b316436STakashi Sakamoto {
2844b316436STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
2854b316436STakashi Sakamoto 	struct snd_pcm_runtime *runtime = substream->runtime;
2864b316436STakashi Sakamoto 	int err;
2874b316436STakashi Sakamoto 
2884b316436STakashi Sakamoto 	mutex_lock(&ff->mutex);
2894b316436STakashi Sakamoto 
2904b316436STakashi Sakamoto 	err = snd_ff_stream_start_duplex(ff, runtime->rate);
2914b316436STakashi Sakamoto 	if (err >= 0)
2924b316436STakashi Sakamoto 		amdtp_stream_pcm_prepare(&ff->rx_stream);
2934b316436STakashi Sakamoto 
2944b316436STakashi Sakamoto 	mutex_unlock(&ff->mutex);
2954b316436STakashi Sakamoto 
2964b316436STakashi Sakamoto 	return err;
2974b316436STakashi Sakamoto }
2984b316436STakashi Sakamoto 
pcm_capture_trigger(struct snd_pcm_substream * substream,int cmd)2994b316436STakashi Sakamoto static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
3004b316436STakashi Sakamoto {
3014b316436STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
3024b316436STakashi Sakamoto 
3034b316436STakashi Sakamoto 	switch (cmd) {
3044b316436STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_START:
3054b316436STakashi Sakamoto 		amdtp_stream_pcm_trigger(&ff->tx_stream, substream);
3064b316436STakashi Sakamoto 		break;
3074b316436STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_STOP:
3084b316436STakashi Sakamoto 		amdtp_stream_pcm_trigger(&ff->tx_stream, NULL);
3094b316436STakashi Sakamoto 		break;
3104b316436STakashi Sakamoto 	default:
3114b316436STakashi Sakamoto 		return -EINVAL;
3124b316436STakashi Sakamoto 	}
3134b316436STakashi Sakamoto 
3144b316436STakashi Sakamoto 	return 0;
3154b316436STakashi Sakamoto }
3164b316436STakashi Sakamoto 
pcm_playback_trigger(struct snd_pcm_substream * substream,int cmd)3174b316436STakashi Sakamoto static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
3184b316436STakashi Sakamoto {
3194b316436STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
3204b316436STakashi Sakamoto 
3214b316436STakashi Sakamoto 	switch (cmd) {
3224b316436STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_START:
3234b316436STakashi Sakamoto 		amdtp_stream_pcm_trigger(&ff->rx_stream, substream);
3244b316436STakashi Sakamoto 		break;
3254b316436STakashi Sakamoto 	case SNDRV_PCM_TRIGGER_STOP:
3264b316436STakashi Sakamoto 		amdtp_stream_pcm_trigger(&ff->rx_stream, NULL);
3274b316436STakashi Sakamoto 		break;
3284b316436STakashi Sakamoto 	default:
3294b316436STakashi Sakamoto 		return -EINVAL;
3304b316436STakashi Sakamoto 	}
3314b316436STakashi Sakamoto 
3324b316436STakashi Sakamoto 	return 0;
3334b316436STakashi Sakamoto }
3344b316436STakashi Sakamoto 
pcm_capture_pointer(struct snd_pcm_substream * sbstrm)3354b316436STakashi Sakamoto static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
3364b316436STakashi Sakamoto {
3374b316436STakashi Sakamoto 	struct snd_ff *ff = sbstrm->private_data;
3384b316436STakashi Sakamoto 
339f890f9a0STakashi Sakamoto 	return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->tx_stream);
3404b316436STakashi Sakamoto }
3414b316436STakashi Sakamoto 
pcm_playback_pointer(struct snd_pcm_substream * sbstrm)3424b316436STakashi Sakamoto static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
3434b316436STakashi Sakamoto {
3444b316436STakashi Sakamoto 	struct snd_ff *ff = sbstrm->private_data;
3454b316436STakashi Sakamoto 
346f890f9a0STakashi Sakamoto 	return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->rx_stream);
3474b316436STakashi Sakamoto }
3484b316436STakashi Sakamoto 
pcm_capture_ack(struct snd_pcm_substream * substream)349875becf8STakashi Sakamoto static int pcm_capture_ack(struct snd_pcm_substream *substream)
350875becf8STakashi Sakamoto {
351875becf8STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
352875becf8STakashi Sakamoto 
353e6dcc92fSTakashi Sakamoto 	return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->tx_stream);
354875becf8STakashi Sakamoto }
355875becf8STakashi Sakamoto 
pcm_playback_ack(struct snd_pcm_substream * substream)356875becf8STakashi Sakamoto static int pcm_playback_ack(struct snd_pcm_substream *substream)
357875becf8STakashi Sakamoto {
358875becf8STakashi Sakamoto 	struct snd_ff *ff = substream->private_data;
359875becf8STakashi Sakamoto 
360e6dcc92fSTakashi Sakamoto 	return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->rx_stream);
361875becf8STakashi Sakamoto }
362875becf8STakashi Sakamoto 
snd_ff_create_pcm_devices(struct snd_ff * ff)363d2dc2a96STakashi Sakamoto int snd_ff_create_pcm_devices(struct snd_ff *ff)
364d2dc2a96STakashi Sakamoto {
365d2dc2a96STakashi Sakamoto 	static const struct snd_pcm_ops pcm_capture_ops = {
3664b316436STakashi Sakamoto 		.open		= pcm_open,
3674b316436STakashi Sakamoto 		.close		= pcm_close,
36849f621feSTakashi Sakamoto 		.hw_params	= pcm_hw_params,
36949f621feSTakashi Sakamoto 		.hw_free	= pcm_hw_free,
3704b316436STakashi Sakamoto 		.prepare	= pcm_capture_prepare,
3714b316436STakashi Sakamoto 		.trigger	= pcm_capture_trigger,
3724b316436STakashi Sakamoto 		.pointer	= pcm_capture_pointer,
373875becf8STakashi Sakamoto 		.ack		= pcm_capture_ack,
3744b316436STakashi Sakamoto 	};
375d2dc2a96STakashi Sakamoto 	static const struct snd_pcm_ops pcm_playback_ops = {
3764b316436STakashi Sakamoto 		.open		= pcm_open,
3774b316436STakashi Sakamoto 		.close		= pcm_close,
37849f621feSTakashi Sakamoto 		.hw_params	= pcm_hw_params,
37949f621feSTakashi Sakamoto 		.hw_free	= pcm_hw_free,
3804b316436STakashi Sakamoto 		.prepare	= pcm_playback_prepare,
3814b316436STakashi Sakamoto 		.trigger	= pcm_playback_trigger,
3824b316436STakashi Sakamoto 		.pointer	= pcm_playback_pointer,
383875becf8STakashi Sakamoto 		.ack		= pcm_playback_ack,
3844b316436STakashi Sakamoto 	};
3854b316436STakashi Sakamoto 	struct snd_pcm *pcm;
3864b316436STakashi Sakamoto 	int err;
3874b316436STakashi Sakamoto 
3884b316436STakashi Sakamoto 	err = snd_pcm_new(ff->card, ff->card->driver, 0, 1, 1, &pcm);
3894b316436STakashi Sakamoto 	if (err < 0)
3904b316436STakashi Sakamoto 		return err;
3914b316436STakashi Sakamoto 
3924b316436STakashi Sakamoto 	pcm->private_data = ff;
393*5c49cc0eSTakashi Sakamoto 	pcm->nonatomic = true;
3944b316436STakashi Sakamoto 	snprintf(pcm->name, sizeof(pcm->name),
3954b316436STakashi Sakamoto 		 "%s PCM", ff->card->shortname);
3964b316436STakashi Sakamoto 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
3974b316436STakashi Sakamoto 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
3987641d549STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
3994b316436STakashi Sakamoto 
4004b316436STakashi Sakamoto 	return 0;
4014b316436STakashi Sakamoto }
402