18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fireworks_pcm.c - a part of driver for Fireworks based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Clemens Ladisch 68c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include "./fireworks.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * NOTE: 128c2ecf20Sopenharmony_ci * Fireworks changes its AMDTP channels for PCM data according to its sampling 138c2ecf20Sopenharmony_ci * rate. There are three modes. Here _XX is either _rx or _tx. 148c2ecf20Sopenharmony_ci * 0: 32.0- 48.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels applied 158c2ecf20Sopenharmony_ci * 1: 88.2- 96.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_2x applied 168c2ecf20Sopenharmony_ci * 2: 176.4-192.0 kHz then snd_efw_hwinfo.amdtp_XX_pcm_channels_4x applied 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * The number of PCM channels for analog input and output are always fixed but 198c2ecf20Sopenharmony_ci * the number of PCM channels for digital input and output are differed. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Additionally, according to "AudioFire Owner's Manual Version 2.2", in some 228c2ecf20Sopenharmony_ci * model, the number of PCM channels for digital input has more restriction 238c2ecf20Sopenharmony_ci * depending on which digital interface is selected. 248c2ecf20Sopenharmony_ci * - S/PDIF coaxial and optical : use input 1-2 258c2ecf20Sopenharmony_ci * - ADAT optical at 32.0-48.0 kHz : use input 1-8 268c2ecf20Sopenharmony_ci * - ADAT optical at 88.2-96.0 kHz : use input 1-4 (S/MUX format) 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * The data in AMDTP channels for blank PCM channels are zero. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistatic const unsigned int freq_table[] = { 318c2ecf20Sopenharmony_ci /* multiplier mode 0 */ 328c2ecf20Sopenharmony_ci [0] = 32000, 338c2ecf20Sopenharmony_ci [1] = 44100, 348c2ecf20Sopenharmony_ci [2] = 48000, 358c2ecf20Sopenharmony_ci /* multiplier mode 1 */ 368c2ecf20Sopenharmony_ci [3] = 88200, 378c2ecf20Sopenharmony_ci [4] = 96000, 388c2ecf20Sopenharmony_ci /* multiplier mode 2 */ 398c2ecf20Sopenharmony_ci [5] = 176400, 408c2ecf20Sopenharmony_ci [6] = 192000, 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic inline unsigned int 448c2ecf20Sopenharmony_ciget_multiplier_mode_with_index(unsigned int index) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci return ((int)index - 1) / 2; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciint snd_efw_get_multiplier_mode(unsigned int sampling_rate, unsigned int *mode) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci unsigned int i; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(freq_table); i++) { 548c2ecf20Sopenharmony_ci if (freq_table[i] == sampling_rate) { 558c2ecf20Sopenharmony_ci *mode = get_multiplier_mode_with_index(i); 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return -EINVAL; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int 648c2ecf20Sopenharmony_cihw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci unsigned int *pcm_channels = rule->private; 678c2ecf20Sopenharmony_ci struct snd_interval *r = 688c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 698c2ecf20Sopenharmony_ci const struct snd_interval *c = 708c2ecf20Sopenharmony_ci hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); 718c2ecf20Sopenharmony_ci struct snd_interval t = { 728c2ecf20Sopenharmony_ci .min = UINT_MAX, .max = 0, .integer = 1 738c2ecf20Sopenharmony_ci }; 748c2ecf20Sopenharmony_ci unsigned int i, mode; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(freq_table); i++) { 778c2ecf20Sopenharmony_ci mode = get_multiplier_mode_with_index(i); 788c2ecf20Sopenharmony_ci if (!snd_interval_test(c, pcm_channels[mode])) 798c2ecf20Sopenharmony_ci continue; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci t.min = min(t.min, freq_table[i]); 828c2ecf20Sopenharmony_ci t.max = max(t.max, freq_table[i]); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int 898c2ecf20Sopenharmony_cihw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci unsigned int *pcm_channels = rule->private; 928c2ecf20Sopenharmony_ci struct snd_interval *c = 938c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 948c2ecf20Sopenharmony_ci const struct snd_interval *r = 958c2ecf20Sopenharmony_ci hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); 968c2ecf20Sopenharmony_ci struct snd_interval t = { 978c2ecf20Sopenharmony_ci .min = UINT_MAX, .max = 0, .integer = 1 988c2ecf20Sopenharmony_ci }; 998c2ecf20Sopenharmony_ci unsigned int i, mode; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(freq_table); i++) { 1028c2ecf20Sopenharmony_ci mode = get_multiplier_mode_with_index(i); 1038c2ecf20Sopenharmony_ci if (!snd_interval_test(r, freq_table[i])) 1048c2ecf20Sopenharmony_ci continue; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci t.min = min(t.min, pcm_channels[mode]); 1078c2ecf20Sopenharmony_ci t.max = max(t.max, pcm_channels[mode]); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void 1148c2ecf20Sopenharmony_cilimit_channels(struct snd_pcm_hardware *hw, unsigned int *pcm_channels) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci unsigned int i, mode; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci hw->channels_min = UINT_MAX; 1198c2ecf20Sopenharmony_ci hw->channels_max = 0; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(freq_table); i++) { 1228c2ecf20Sopenharmony_ci mode = get_multiplier_mode_with_index(i); 1238c2ecf20Sopenharmony_ci if (pcm_channels[mode] == 0) 1248c2ecf20Sopenharmony_ci continue; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci hw->channels_min = min(hw->channels_min, pcm_channels[mode]); 1278c2ecf20Sopenharmony_ci hw->channels_max = max(hw->channels_max, pcm_channels[mode]); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int 1328c2ecf20Sopenharmony_cipcm_init_hw_params(struct snd_efw *efw, 1338c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 1368c2ecf20Sopenharmony_ci struct amdtp_stream *s; 1378c2ecf20Sopenharmony_ci unsigned int *pcm_channels; 1388c2ecf20Sopenharmony_ci int err; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 1418c2ecf20Sopenharmony_ci runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; 1428c2ecf20Sopenharmony_ci s = &efw->tx_stream; 1438c2ecf20Sopenharmony_ci pcm_channels = efw->pcm_capture_channels; 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS; 1468c2ecf20Sopenharmony_ci s = &efw->rx_stream; 1478c2ecf20Sopenharmony_ci pcm_channels = efw->pcm_playback_channels; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* limit rates */ 1518c2ecf20Sopenharmony_ci runtime->hw.rates = efw->supported_sampling_rate; 1528c2ecf20Sopenharmony_ci snd_pcm_limit_hw_rates(runtime); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci limit_channels(&runtime->hw, pcm_channels); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 1578c2ecf20Sopenharmony_ci hw_rule_channels, pcm_channels, 1588c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 1598c2ecf20Sopenharmony_ci if (err < 0) 1608c2ecf20Sopenharmony_ci goto end; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 1638c2ecf20Sopenharmony_ci hw_rule_rate, pcm_channels, 1648c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 1658c2ecf20Sopenharmony_ci if (err < 0) 1668c2ecf20Sopenharmony_ci goto end; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci err = amdtp_am824_add_pcm_hw_constraints(s, runtime); 1698c2ecf20Sopenharmony_ciend: 1708c2ecf20Sopenharmony_ci return err; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int pcm_open(struct snd_pcm_substream *substream) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 1768c2ecf20Sopenharmony_ci struct amdtp_domain *d = &efw->domain; 1778c2ecf20Sopenharmony_ci enum snd_efw_clock_source clock_source; 1788c2ecf20Sopenharmony_ci int err; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci err = snd_efw_stream_lock_try(efw); 1818c2ecf20Sopenharmony_ci if (err < 0) 1828c2ecf20Sopenharmony_ci return err; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci err = pcm_init_hw_params(efw, substream); 1858c2ecf20Sopenharmony_ci if (err < 0) 1868c2ecf20Sopenharmony_ci goto err_locked; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci err = snd_efw_command_get_clock_source(efw, &clock_source); 1898c2ecf20Sopenharmony_ci if (err < 0) 1908c2ecf20Sopenharmony_ci goto err_locked; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci mutex_lock(&efw->mutex); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci // When source of clock is not internal or any stream is reserved for 1958c2ecf20Sopenharmony_ci // transmission of PCM frames, the available sampling rate is limited 1968c2ecf20Sopenharmony_ci // at current one. 1978c2ecf20Sopenharmony_ci if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) || 1988c2ecf20Sopenharmony_ci (efw->substreams_counter > 0 && d->events_per_period > 0)) { 1998c2ecf20Sopenharmony_ci unsigned int frames_per_period = d->events_per_period; 2008c2ecf20Sopenharmony_ci unsigned int frames_per_buffer = d->events_per_buffer; 2018c2ecf20Sopenharmony_ci unsigned int sampling_rate; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci err = snd_efw_command_get_sampling_rate(efw, &sampling_rate); 2048c2ecf20Sopenharmony_ci if (err < 0) { 2058c2ecf20Sopenharmony_ci mutex_unlock(&efw->mutex); 2068c2ecf20Sopenharmony_ci goto err_locked; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci substream->runtime->hw.rate_min = sampling_rate; 2098c2ecf20Sopenharmony_ci substream->runtime->hw.rate_max = sampling_rate; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (frames_per_period > 0) { 2128c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(substream->runtime, 2138c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2148c2ecf20Sopenharmony_ci frames_per_period, frames_per_period); 2158c2ecf20Sopenharmony_ci if (err < 0) { 2168c2ecf20Sopenharmony_ci mutex_unlock(&efw->mutex); 2178c2ecf20Sopenharmony_ci goto err_locked; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(substream->runtime, 2218c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 2228c2ecf20Sopenharmony_ci frames_per_buffer, frames_per_buffer); 2238c2ecf20Sopenharmony_ci if (err < 0) { 2248c2ecf20Sopenharmony_ci mutex_unlock(&efw->mutex); 2258c2ecf20Sopenharmony_ci goto err_locked; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci mutex_unlock(&efw->mutex); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_cierr_locked: 2368c2ecf20Sopenharmony_ci snd_efw_stream_lock_release(efw); 2378c2ecf20Sopenharmony_ci return err; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int pcm_close(struct snd_pcm_substream *substream) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 2438c2ecf20Sopenharmony_ci snd_efw_stream_lock_release(efw); 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int pcm_hw_params(struct snd_pcm_substream *substream, 2488c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 2518c2ecf20Sopenharmony_ci int err = 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 2548c2ecf20Sopenharmony_ci unsigned int rate = params_rate(hw_params); 2558c2ecf20Sopenharmony_ci unsigned int frames_per_period = params_period_size(hw_params); 2568c2ecf20Sopenharmony_ci unsigned int frames_per_buffer = params_buffer_size(hw_params); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci mutex_lock(&efw->mutex); 2598c2ecf20Sopenharmony_ci err = snd_efw_stream_reserve_duplex(efw, rate, 2608c2ecf20Sopenharmony_ci frames_per_period, frames_per_buffer); 2618c2ecf20Sopenharmony_ci if (err >= 0) 2628c2ecf20Sopenharmony_ci ++efw->substreams_counter; 2638c2ecf20Sopenharmony_ci mutex_unlock(&efw->mutex); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return err; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int pcm_hw_free(struct snd_pcm_substream *substream) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci mutex_lock(&efw->mutex); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 2768c2ecf20Sopenharmony_ci --efw->substreams_counter; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci snd_efw_stream_stop_duplex(efw); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci mutex_unlock(&efw->mutex); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int pcm_capture_prepare(struct snd_pcm_substream *substream) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 2888c2ecf20Sopenharmony_ci int err; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci err = snd_efw_stream_start_duplex(efw); 2918c2ecf20Sopenharmony_ci if (err >= 0) 2928c2ecf20Sopenharmony_ci amdtp_stream_pcm_prepare(&efw->tx_stream); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return err; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_cistatic int pcm_playback_prepare(struct snd_pcm_substream *substream) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 2998c2ecf20Sopenharmony_ci int err; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci err = snd_efw_stream_start_duplex(efw); 3028c2ecf20Sopenharmony_ci if (err >= 0) 3038c2ecf20Sopenharmony_ci amdtp_stream_pcm_prepare(&efw->rx_stream); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return err; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci switch (cmd) { 3138c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 3148c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&efw->tx_stream, substream); 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 3178c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&efw->tx_stream, NULL); 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci default: 3208c2ecf20Sopenharmony_ci return -EINVAL; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_cistatic int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci switch (cmd) { 3308c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 3318c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&efw->rx_stream, substream); 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 3348c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&efw->rx_stream, NULL); 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci default: 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct snd_efw *efw = sbstrm->private_data; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->tx_stream); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct snd_efw *efw = sbstrm->private_data; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->rx_stream); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int pcm_capture_ack(struct snd_pcm_substream *substream) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->tx_stream); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int pcm_playback_ack(struct snd_pcm_substream *substream) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct snd_efw *efw = substream->private_data; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->rx_stream); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ciint snd_efw_create_pcm_devices(struct snd_efw *efw) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci static const struct snd_pcm_ops capture_ops = { 3738c2ecf20Sopenharmony_ci .open = pcm_open, 3748c2ecf20Sopenharmony_ci .close = pcm_close, 3758c2ecf20Sopenharmony_ci .hw_params = pcm_hw_params, 3768c2ecf20Sopenharmony_ci .hw_free = pcm_hw_free, 3778c2ecf20Sopenharmony_ci .prepare = pcm_capture_prepare, 3788c2ecf20Sopenharmony_ci .trigger = pcm_capture_trigger, 3798c2ecf20Sopenharmony_ci .pointer = pcm_capture_pointer, 3808c2ecf20Sopenharmony_ci .ack = pcm_capture_ack, 3818c2ecf20Sopenharmony_ci }; 3828c2ecf20Sopenharmony_ci static const struct snd_pcm_ops playback_ops = { 3838c2ecf20Sopenharmony_ci .open = pcm_open, 3848c2ecf20Sopenharmony_ci .close = pcm_close, 3858c2ecf20Sopenharmony_ci .hw_params = pcm_hw_params, 3868c2ecf20Sopenharmony_ci .hw_free = pcm_hw_free, 3878c2ecf20Sopenharmony_ci .prepare = pcm_playback_prepare, 3888c2ecf20Sopenharmony_ci .trigger = pcm_playback_trigger, 3898c2ecf20Sopenharmony_ci .pointer = pcm_playback_pointer, 3908c2ecf20Sopenharmony_ci .ack = pcm_playback_ack, 3918c2ecf20Sopenharmony_ci }; 3928c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 3938c2ecf20Sopenharmony_ci int err; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci err = snd_pcm_new(efw->card, efw->card->driver, 0, 1, 1, &pcm); 3968c2ecf20Sopenharmony_ci if (err < 0) 3978c2ecf20Sopenharmony_ci goto end; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci pcm->private_data = efw; 4008c2ecf20Sopenharmony_ci snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname); 4018c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); 4028c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); 4038c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); 4048c2ecf20Sopenharmony_ciend: 4058c2ecf20Sopenharmony_ci return err; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 408