18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bebob_pcm.c - a part of driver for BeBoB based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "./bebob.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistatic int 118c2ecf20Sopenharmony_cihw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci struct snd_bebob_stream_formation *formations = rule->private; 148c2ecf20Sopenharmony_ci struct snd_interval *r = 158c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 168c2ecf20Sopenharmony_ci const struct snd_interval *c = 178c2ecf20Sopenharmony_ci hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); 188c2ecf20Sopenharmony_ci struct snd_interval t = { 198c2ecf20Sopenharmony_ci .min = UINT_MAX, .max = 0, .integer = 1 208c2ecf20Sopenharmony_ci }; 218c2ecf20Sopenharmony_ci unsigned int i; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) { 248c2ecf20Sopenharmony_ci /* entry is invalid */ 258c2ecf20Sopenharmony_ci if (formations[i].pcm == 0) 268c2ecf20Sopenharmony_ci continue; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (!snd_interval_test(c, formations[i].pcm)) 298c2ecf20Sopenharmony_ci continue; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci t.min = min(t.min, snd_bebob_rate_table[i]); 328c2ecf20Sopenharmony_ci t.max = max(t.max, snd_bebob_rate_table[i]); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci return snd_interval_refine(r, &t); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int 398c2ecf20Sopenharmony_cihw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct snd_bebob_stream_formation *formations = rule->private; 428c2ecf20Sopenharmony_ci struct snd_interval *c = 438c2ecf20Sopenharmony_ci hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 448c2ecf20Sopenharmony_ci const struct snd_interval *r = 458c2ecf20Sopenharmony_ci hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); 468c2ecf20Sopenharmony_ci struct snd_interval t = { 478c2ecf20Sopenharmony_ci .min = UINT_MAX, .max = 0, .integer = 1 488c2ecf20Sopenharmony_ci }; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci unsigned int i; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) { 538c2ecf20Sopenharmony_ci /* entry is invalid */ 548c2ecf20Sopenharmony_ci if (formations[i].pcm == 0) 558c2ecf20Sopenharmony_ci continue; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!snd_interval_test(r, snd_bebob_rate_table[i])) 588c2ecf20Sopenharmony_ci continue; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci t.min = min(t.min, formations[i].pcm); 618c2ecf20Sopenharmony_ci t.max = max(t.max, formations[i].pcm); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return snd_interval_refine(c, &t); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void 688c2ecf20Sopenharmony_cilimit_channels_and_rates(struct snd_pcm_hardware *hw, 698c2ecf20Sopenharmony_ci struct snd_bebob_stream_formation *formations) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci unsigned int i; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci hw->channels_min = UINT_MAX; 748c2ecf20Sopenharmony_ci hw->channels_max = 0; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci hw->rate_min = UINT_MAX; 778c2ecf20Sopenharmony_ci hw->rate_max = 0; 788c2ecf20Sopenharmony_ci hw->rates = 0; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) { 818c2ecf20Sopenharmony_ci /* entry has no PCM channels */ 828c2ecf20Sopenharmony_ci if (formations[i].pcm == 0) 838c2ecf20Sopenharmony_ci continue; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci hw->channels_min = min(hw->channels_min, formations[i].pcm); 868c2ecf20Sopenharmony_ci hw->channels_max = max(hw->channels_max, formations[i].pcm); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci hw->rate_min = min(hw->rate_min, snd_bebob_rate_table[i]); 898c2ecf20Sopenharmony_ci hw->rate_max = max(hw->rate_max, snd_bebob_rate_table[i]); 908c2ecf20Sopenharmony_ci hw->rates |= snd_pcm_rate_to_rate_bit(snd_bebob_rate_table[i]); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int 958c2ecf20Sopenharmony_cipcm_init_hw_params(struct snd_bebob *bebob, 968c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 998c2ecf20Sopenharmony_ci struct amdtp_stream *s; 1008c2ecf20Sopenharmony_ci struct snd_bebob_stream_formation *formations; 1018c2ecf20Sopenharmony_ci int err; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 1048c2ecf20Sopenharmony_ci runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; 1058c2ecf20Sopenharmony_ci s = &bebob->tx_stream; 1068c2ecf20Sopenharmony_ci formations = bebob->tx_stream_formations; 1078c2ecf20Sopenharmony_ci } else { 1088c2ecf20Sopenharmony_ci runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS; 1098c2ecf20Sopenharmony_ci s = &bebob->rx_stream; 1108c2ecf20Sopenharmony_ci formations = bebob->rx_stream_formations; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci limit_channels_and_rates(&runtime->hw, formations); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 1168c2ecf20Sopenharmony_ci hw_rule_channels, formations, 1178c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 1188c2ecf20Sopenharmony_ci if (err < 0) 1198c2ecf20Sopenharmony_ci goto end; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 1228c2ecf20Sopenharmony_ci hw_rule_rate, formations, 1238c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, -1); 1248c2ecf20Sopenharmony_ci if (err < 0) 1258c2ecf20Sopenharmony_ci goto end; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci err = amdtp_am824_add_pcm_hw_constraints(s, runtime); 1288c2ecf20Sopenharmony_ciend: 1298c2ecf20Sopenharmony_ci return err; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int pcm_open(struct snd_pcm_substream *substream) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 1358c2ecf20Sopenharmony_ci const struct snd_bebob_rate_spec *spec = bebob->spec->rate; 1368c2ecf20Sopenharmony_ci struct amdtp_domain *d = &bebob->domain; 1378c2ecf20Sopenharmony_ci enum snd_bebob_clock_type src; 1388c2ecf20Sopenharmony_ci int err; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci err = snd_bebob_stream_lock_try(bebob); 1418c2ecf20Sopenharmony_ci if (err < 0) 1428c2ecf20Sopenharmony_ci return err; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci err = pcm_init_hw_params(bebob, substream); 1458c2ecf20Sopenharmony_ci if (err < 0) 1468c2ecf20Sopenharmony_ci goto err_locked; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci err = snd_bebob_stream_get_clock_src(bebob, &src); 1498c2ecf20Sopenharmony_ci if (err < 0) 1508c2ecf20Sopenharmony_ci goto err_locked; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci mutex_lock(&bebob->mutex); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci // When source of clock is not internal or any stream is reserved for 1558c2ecf20Sopenharmony_ci // transmission of PCM frames, the available sampling rate is limited 1568c2ecf20Sopenharmony_ci // at current one. 1578c2ecf20Sopenharmony_ci if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL || 1588c2ecf20Sopenharmony_ci (bebob->substreams_counter > 0 && d->events_per_period > 0)) { 1598c2ecf20Sopenharmony_ci unsigned int frames_per_period = d->events_per_period; 1608c2ecf20Sopenharmony_ci unsigned int frames_per_buffer = d->events_per_buffer; 1618c2ecf20Sopenharmony_ci unsigned int sampling_rate; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci err = spec->get(bebob, &sampling_rate); 1648c2ecf20Sopenharmony_ci if (err < 0) { 1658c2ecf20Sopenharmony_ci mutex_unlock(&bebob->mutex); 1668c2ecf20Sopenharmony_ci dev_err(&bebob->unit->device, 1678c2ecf20Sopenharmony_ci "fail to get sampling rate: %d\n", err); 1688c2ecf20Sopenharmony_ci goto err_locked; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci substream->runtime->hw.rate_min = sampling_rate; 1728c2ecf20Sopenharmony_ci substream->runtime->hw.rate_max = sampling_rate; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (frames_per_period > 0) { 1758c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(substream->runtime, 1768c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 1778c2ecf20Sopenharmony_ci frames_per_period, frames_per_period); 1788c2ecf20Sopenharmony_ci if (err < 0) { 1798c2ecf20Sopenharmony_ci mutex_unlock(&bebob->mutex); 1808c2ecf20Sopenharmony_ci goto err_locked; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(substream->runtime, 1848c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 1858c2ecf20Sopenharmony_ci frames_per_buffer, frames_per_buffer); 1868c2ecf20Sopenharmony_ci if (err < 0) { 1878c2ecf20Sopenharmony_ci mutex_unlock(&bebob->mutex); 1888c2ecf20Sopenharmony_ci goto err_locked; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci mutex_unlock(&bebob->mutex); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci snd_pcm_set_sync(substream); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_cierr_locked: 1998c2ecf20Sopenharmony_ci snd_bebob_stream_lock_release(bebob); 2008c2ecf20Sopenharmony_ci return err; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int 2048c2ecf20Sopenharmony_cipcm_close(struct snd_pcm_substream *substream) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 2078c2ecf20Sopenharmony_ci snd_bebob_stream_lock_release(bebob); 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int pcm_hw_params(struct snd_pcm_substream *substream, 2128c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 2158c2ecf20Sopenharmony_ci int err = 0; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 2188c2ecf20Sopenharmony_ci unsigned int rate = params_rate(hw_params); 2198c2ecf20Sopenharmony_ci unsigned int frames_per_period = params_period_size(hw_params); 2208c2ecf20Sopenharmony_ci unsigned int frames_per_buffer = params_buffer_size(hw_params); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci mutex_lock(&bebob->mutex); 2238c2ecf20Sopenharmony_ci err = snd_bebob_stream_reserve_duplex(bebob, rate, 2248c2ecf20Sopenharmony_ci frames_per_period, frames_per_buffer); 2258c2ecf20Sopenharmony_ci if (err >= 0) 2268c2ecf20Sopenharmony_ci ++bebob->substreams_counter; 2278c2ecf20Sopenharmony_ci mutex_unlock(&bebob->mutex); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return err; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int pcm_hw_free(struct snd_pcm_substream *substream) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci mutex_lock(&bebob->mutex); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 2408c2ecf20Sopenharmony_ci bebob->substreams_counter--; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci snd_bebob_stream_stop_duplex(bebob); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci mutex_unlock(&bebob->mutex); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int 2508c2ecf20Sopenharmony_cipcm_capture_prepare(struct snd_pcm_substream *substream) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 2538c2ecf20Sopenharmony_ci int err; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci err = snd_bebob_stream_start_duplex(bebob); 2568c2ecf20Sopenharmony_ci if (err >= 0) 2578c2ecf20Sopenharmony_ci amdtp_stream_pcm_prepare(&bebob->tx_stream); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return err; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_cistatic int 2628c2ecf20Sopenharmony_cipcm_playback_prepare(struct snd_pcm_substream *substream) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 2658c2ecf20Sopenharmony_ci int err; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci err = snd_bebob_stream_start_duplex(bebob); 2688c2ecf20Sopenharmony_ci if (err >= 0) 2698c2ecf20Sopenharmony_ci amdtp_stream_pcm_prepare(&bebob->rx_stream); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return err; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int 2758c2ecf20Sopenharmony_cipcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci switch (cmd) { 2808c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2818c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&bebob->tx_stream, substream); 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2848c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&bebob->tx_stream, NULL); 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci default: 2878c2ecf20Sopenharmony_ci return -EINVAL; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_cistatic int 2938c2ecf20Sopenharmony_cipcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci switch (cmd) { 2988c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2998c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&bebob->rx_stream, substream); 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 3028c2ecf20Sopenharmony_ci amdtp_stream_pcm_trigger(&bebob->rx_stream, NULL); 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci default: 3058c2ecf20Sopenharmony_ci return -EINVAL; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct snd_bebob *bebob = sbstrm->private_data; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_pointer(&bebob->domain, 3168c2ecf20Sopenharmony_ci &bebob->tx_stream); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct snd_bebob *bebob = sbstrm->private_data; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_pointer(&bebob->domain, 3238c2ecf20Sopenharmony_ci &bebob->rx_stream); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int pcm_capture_ack(struct snd_pcm_substream *substream) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->tx_stream); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int pcm_playback_ack(struct snd_pcm_substream *substream) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct snd_bebob *bebob = substream->private_data; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->rx_stream); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ciint snd_bebob_create_pcm_devices(struct snd_bebob *bebob) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci static const struct snd_pcm_ops capture_ops = { 3438c2ecf20Sopenharmony_ci .open = pcm_open, 3448c2ecf20Sopenharmony_ci .close = pcm_close, 3458c2ecf20Sopenharmony_ci .hw_params = pcm_hw_params, 3468c2ecf20Sopenharmony_ci .hw_free = pcm_hw_free, 3478c2ecf20Sopenharmony_ci .prepare = pcm_capture_prepare, 3488c2ecf20Sopenharmony_ci .trigger = pcm_capture_trigger, 3498c2ecf20Sopenharmony_ci .pointer = pcm_capture_pointer, 3508c2ecf20Sopenharmony_ci .ack = pcm_capture_ack, 3518c2ecf20Sopenharmony_ci }; 3528c2ecf20Sopenharmony_ci static const struct snd_pcm_ops playback_ops = { 3538c2ecf20Sopenharmony_ci .open = pcm_open, 3548c2ecf20Sopenharmony_ci .close = pcm_close, 3558c2ecf20Sopenharmony_ci .hw_params = pcm_hw_params, 3568c2ecf20Sopenharmony_ci .hw_free = pcm_hw_free, 3578c2ecf20Sopenharmony_ci .prepare = pcm_playback_prepare, 3588c2ecf20Sopenharmony_ci .trigger = pcm_playback_trigger, 3598c2ecf20Sopenharmony_ci .pointer = pcm_playback_pointer, 3608c2ecf20Sopenharmony_ci .ack = pcm_playback_ack, 3618c2ecf20Sopenharmony_ci }; 3628c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 3638c2ecf20Sopenharmony_ci int err; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci err = snd_pcm_new(bebob->card, bebob->card->driver, 0, 1, 1, &pcm); 3668c2ecf20Sopenharmony_ci if (err < 0) 3678c2ecf20Sopenharmony_ci goto end; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci pcm->private_data = bebob; 3708c2ecf20Sopenharmony_ci snprintf(pcm->name, sizeof(pcm->name), 3718c2ecf20Sopenharmony_ci "%s PCM", bebob->card->shortname); 3728c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); 3738c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); 3748c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); 3758c2ecf20Sopenharmony_ciend: 3768c2ecf20Sopenharmony_ci return err; 3778c2ecf20Sopenharmony_ci} 378