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