1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 23713d93aSTakashi Sakamoto /* 33713d93aSTakashi Sakamoto * oxfw_pcm.c - a part of driver for OXFW970/971 based devices 43713d93aSTakashi Sakamoto * 53713d93aSTakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 63713d93aSTakashi Sakamoto */ 73713d93aSTakashi Sakamoto 83713d93aSTakashi Sakamoto #include "oxfw.h" 93713d93aSTakashi Sakamoto 105cd1d3f4STakashi Sakamoto static int hw_rule_rate(struct snd_pcm_hw_params *params, 113713d93aSTakashi Sakamoto struct snd_pcm_hw_rule *rule) 123713d93aSTakashi Sakamoto { 135cd1d3f4STakashi Sakamoto u8 **formats = rule->private; 145cd1d3f4STakashi Sakamoto struct snd_interval *r = 153713d93aSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 165cd1d3f4STakashi Sakamoto const struct snd_interval *c = 175cd1d3f4STakashi Sakamoto hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); 185cd1d3f4STakashi Sakamoto struct snd_interval t = { 195cd1d3f4STakashi Sakamoto .min = UINT_MAX, .max = 0, .integer = 1 203713d93aSTakashi Sakamoto }; 215cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation formation; 225580ba7bSDan Carpenter int i, err; 233713d93aSTakashi Sakamoto 245cd1d3f4STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 255cd1d3f4STakashi Sakamoto if (formats[i] == NULL) 265cd1d3f4STakashi Sakamoto continue; 273713d93aSTakashi Sakamoto 285cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], &formation); 293713d93aSTakashi Sakamoto if (err < 0) 305cd1d3f4STakashi Sakamoto continue; 315cd1d3f4STakashi Sakamoto if (!snd_interval_test(c, formation.pcm)) 325cd1d3f4STakashi Sakamoto continue; 333713d93aSTakashi Sakamoto 345cd1d3f4STakashi Sakamoto t.min = min(t.min, formation.rate); 355cd1d3f4STakashi Sakamoto t.max = max(t.max, formation.rate); 365cd1d3f4STakashi Sakamoto 375cd1d3f4STakashi Sakamoto } 385cd1d3f4STakashi Sakamoto return snd_interval_refine(r, &t); 393713d93aSTakashi Sakamoto } 403713d93aSTakashi Sakamoto 415cd1d3f4STakashi Sakamoto static int hw_rule_channels(struct snd_pcm_hw_params *params, 425cd1d3f4STakashi Sakamoto struct snd_pcm_hw_rule *rule) 433713d93aSTakashi Sakamoto { 445cd1d3f4STakashi Sakamoto u8 **formats = rule->private; 455cd1d3f4STakashi Sakamoto struct snd_interval *c = 465cd1d3f4STakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 475cd1d3f4STakashi Sakamoto const struct snd_interval *r = 485cd1d3f4STakashi Sakamoto hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); 495cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation formation; 505580ba7bSDan Carpenter int i, j, err; 515cd1d3f4STakashi Sakamoto unsigned int count, list[SND_OXFW_STREAM_FORMAT_ENTRIES] = {0}; 523713d93aSTakashi Sakamoto 535cd1d3f4STakashi Sakamoto count = 0; 545cd1d3f4STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 555cd1d3f4STakashi Sakamoto if (formats[i] == NULL) 565cd1d3f4STakashi Sakamoto break; 575cd1d3f4STakashi Sakamoto 585cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], &formation); 595cd1d3f4STakashi Sakamoto if (err < 0) 605cd1d3f4STakashi Sakamoto continue; 615cd1d3f4STakashi Sakamoto if (!snd_interval_test(r, formation.rate)) 625cd1d3f4STakashi Sakamoto continue; 635cd1d3f4STakashi Sakamoto if (list[count] == formation.pcm) 645cd1d3f4STakashi Sakamoto continue; 655cd1d3f4STakashi Sakamoto 665cd1d3f4STakashi Sakamoto for (j = 0; j < ARRAY_SIZE(list); j++) { 675cd1d3f4STakashi Sakamoto if (list[j] == formation.pcm) 685cd1d3f4STakashi Sakamoto break; 695cd1d3f4STakashi Sakamoto } 705cd1d3f4STakashi Sakamoto if (j == ARRAY_SIZE(list)) { 715cd1d3f4STakashi Sakamoto list[count] = formation.pcm; 725cd1d3f4STakashi Sakamoto if (++count == ARRAY_SIZE(list)) 735cd1d3f4STakashi Sakamoto break; 745cd1d3f4STakashi Sakamoto } 755cd1d3f4STakashi Sakamoto } 765cd1d3f4STakashi Sakamoto 775cd1d3f4STakashi Sakamoto return snd_interval_list(c, count, list, 0); 785cd1d3f4STakashi Sakamoto } 795cd1d3f4STakashi Sakamoto 805cd1d3f4STakashi Sakamoto static void limit_channels_and_rates(struct snd_pcm_hardware *hw, u8 **formats) 815cd1d3f4STakashi Sakamoto { 825cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation formation; 835580ba7bSDan Carpenter int i, err; 845cd1d3f4STakashi Sakamoto 855cd1d3f4STakashi Sakamoto hw->channels_min = UINT_MAX; 865cd1d3f4STakashi Sakamoto hw->channels_max = 0; 875cd1d3f4STakashi Sakamoto 885cd1d3f4STakashi Sakamoto hw->rate_min = UINT_MAX; 895cd1d3f4STakashi Sakamoto hw->rate_max = 0; 905cd1d3f4STakashi Sakamoto hw->rates = 0; 915cd1d3f4STakashi Sakamoto 925cd1d3f4STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 935cd1d3f4STakashi Sakamoto if (formats[i] == NULL) 945cd1d3f4STakashi Sakamoto break; 955cd1d3f4STakashi Sakamoto 965cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], &formation); 975cd1d3f4STakashi Sakamoto if (err < 0) 985cd1d3f4STakashi Sakamoto continue; 995cd1d3f4STakashi Sakamoto 1005cd1d3f4STakashi Sakamoto hw->channels_min = min(hw->channels_min, formation.pcm); 1015cd1d3f4STakashi Sakamoto hw->channels_max = max(hw->channels_max, formation.pcm); 1025cd1d3f4STakashi Sakamoto 1035cd1d3f4STakashi Sakamoto hw->rate_min = min(hw->rate_min, formation.rate); 1045cd1d3f4STakashi Sakamoto hw->rate_max = max(hw->rate_max, formation.rate); 1055cd1d3f4STakashi Sakamoto hw->rates |= snd_pcm_rate_to_rate_bit(formation.rate); 1065cd1d3f4STakashi Sakamoto } 1075cd1d3f4STakashi Sakamoto } 1085cd1d3f4STakashi Sakamoto 109216e256fSTakashi Sakamoto static int init_hw_params(struct snd_oxfw *oxfw, 110216e256fSTakashi Sakamoto struct snd_pcm_substream *substream) 1113713d93aSTakashi Sakamoto { 1123713d93aSTakashi Sakamoto struct snd_pcm_runtime *runtime = substream->runtime; 1135cd1d3f4STakashi Sakamoto u8 **formats; 114216e256fSTakashi Sakamoto struct amdtp_stream *stream; 1153713d93aSTakashi Sakamoto int err; 1163713d93aSTakashi Sakamoto 117216e256fSTakashi Sakamoto if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 11849c7b3fcSTakashi Sakamoto runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS; 119216e256fSTakashi Sakamoto stream = &oxfw->tx_stream; 120216e256fSTakashi Sakamoto formats = oxfw->tx_stream_formats; 121216e256fSTakashi Sakamoto } else { 12249c7b3fcSTakashi Sakamoto runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS; 123216e256fSTakashi Sakamoto stream = &oxfw->rx_stream; 124216e256fSTakashi Sakamoto formats = oxfw->rx_stream_formats; 125216e256fSTakashi Sakamoto } 126216e256fSTakashi Sakamoto 1275cd1d3f4STakashi Sakamoto limit_channels_and_rates(&runtime->hw, formats); 1285cd1d3f4STakashi Sakamoto 1295cd1d3f4STakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 1305cd1d3f4STakashi Sakamoto hw_rule_channels, formats, 1315cd1d3f4STakashi Sakamoto SNDRV_PCM_HW_PARAM_RATE, -1); 1323713d93aSTakashi Sakamoto if (err < 0) 1333713d93aSTakashi Sakamoto goto end; 1345cd1d3f4STakashi Sakamoto 1355cd1d3f4STakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 1365cd1d3f4STakashi Sakamoto hw_rule_rate, formats, 1375cd1d3f4STakashi Sakamoto SNDRV_PCM_HW_PARAM_CHANNELS, -1); 1383713d93aSTakashi Sakamoto if (err < 0) 1393713d93aSTakashi Sakamoto goto end; 1403713d93aSTakashi Sakamoto 141bc8500daSTakashi Sakamoto err = amdtp_am824_add_pcm_hw_constraints(stream, runtime); 142216e256fSTakashi Sakamoto end: 143216e256fSTakashi Sakamoto return err; 144216e256fSTakashi Sakamoto } 145216e256fSTakashi Sakamoto 146216e256fSTakashi Sakamoto static int limit_to_current_params(struct snd_pcm_substream *substream) 147216e256fSTakashi Sakamoto { 148216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 149216e256fSTakashi Sakamoto struct snd_oxfw_stream_formation formation; 150216e256fSTakashi Sakamoto enum avc_general_plug_dir dir; 151216e256fSTakashi Sakamoto int err; 152216e256fSTakashi Sakamoto 153216e256fSTakashi Sakamoto if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 154216e256fSTakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_OUT; 155216e256fSTakashi Sakamoto else 156216e256fSTakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_IN; 157216e256fSTakashi Sakamoto 158216e256fSTakashi Sakamoto err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); 1595cd1d3f4STakashi Sakamoto if (err < 0) 1605cd1d3f4STakashi Sakamoto goto end; 1615cd1d3f4STakashi Sakamoto 162216e256fSTakashi Sakamoto substream->runtime->hw.channels_min = formation.pcm; 163216e256fSTakashi Sakamoto substream->runtime->hw.channels_max = formation.pcm; 164216e256fSTakashi Sakamoto substream->runtime->hw.rate_min = formation.rate; 165216e256fSTakashi Sakamoto substream->runtime->hw.rate_max = formation.rate; 166216e256fSTakashi Sakamoto end: 167216e256fSTakashi Sakamoto return err; 168216e256fSTakashi Sakamoto } 169216e256fSTakashi Sakamoto 170216e256fSTakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream) 171216e256fSTakashi Sakamoto { 172216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 173c0ede398STakashi Sakamoto struct amdtp_domain *d = &oxfw->domain; 174216e256fSTakashi Sakamoto int err; 175216e256fSTakashi Sakamoto 1768985f4acSTakashi Sakamoto err = snd_oxfw_stream_lock_try(oxfw); 177216e256fSTakashi Sakamoto if (err < 0) 178c0ede398STakashi Sakamoto return err; 179216e256fSTakashi Sakamoto 1808985f4acSTakashi Sakamoto err = init_hw_params(oxfw, substream); 1818985f4acSTakashi Sakamoto if (err < 0) 1828985f4acSTakashi Sakamoto goto err_locked; 1838985f4acSTakashi Sakamoto 184c0ede398STakashi Sakamoto mutex_lock(&oxfw->mutex); 185c0ede398STakashi Sakamoto 186c0ede398STakashi Sakamoto // When source of clock is not internal or any stream is reserved for 187c0ede398STakashi Sakamoto // transmission of PCM frames, the available sampling rate is limited 188c0ede398STakashi Sakamoto // at current one. 189c0ede398STakashi Sakamoto if (oxfw->substreams_count > 0 && d->events_per_period > 0) { 190c0ede398STakashi Sakamoto unsigned int frames_per_period = d->events_per_period; 1913299d2a0STakashi Sakamoto unsigned int frames_per_buffer = d->events_per_buffer; 192c0ede398STakashi Sakamoto 193216e256fSTakashi Sakamoto err = limit_to_current_params(substream); 194c0ede398STakashi Sakamoto if (err < 0) { 195c0ede398STakashi Sakamoto mutex_unlock(&oxfw->mutex); 196c0ede398STakashi Sakamoto goto err_locked; 197216e256fSTakashi Sakamoto } 198216e256fSTakashi Sakamoto 199c0ede398STakashi Sakamoto if (frames_per_period > 0) { 200c0ede398STakashi Sakamoto err = snd_pcm_hw_constraint_minmax(substream->runtime, 201c0ede398STakashi Sakamoto SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 202c0ede398STakashi Sakamoto frames_per_period, frames_per_period); 203c0ede398STakashi Sakamoto if (err < 0) { 204c0ede398STakashi Sakamoto mutex_unlock(&oxfw->mutex); 205c0ede398STakashi Sakamoto goto err_locked; 206c0ede398STakashi Sakamoto } 2073299d2a0STakashi Sakamoto 2083299d2a0STakashi Sakamoto err = snd_pcm_hw_constraint_minmax(substream->runtime, 2093299d2a0STakashi Sakamoto SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 2103299d2a0STakashi Sakamoto frames_per_buffer, frames_per_buffer); 2113299d2a0STakashi Sakamoto if (err < 0) { 2123299d2a0STakashi Sakamoto mutex_unlock(&oxfw->mutex); 2133299d2a0STakashi Sakamoto goto err_locked; 2143299d2a0STakashi Sakamoto } 215c0ede398STakashi Sakamoto } 216c0ede398STakashi Sakamoto } 217c0ede398STakashi Sakamoto 218c0ede398STakashi Sakamoto mutex_unlock(&oxfw->mutex); 219c0ede398STakashi Sakamoto 2205cd1d3f4STakashi Sakamoto snd_pcm_set_sync(substream); 221c0ede398STakashi Sakamoto 222c0ede398STakashi Sakamoto return 0; 2238985f4acSTakashi Sakamoto err_locked: 2248985f4acSTakashi Sakamoto snd_oxfw_stream_lock_release(oxfw); 2258985f4acSTakashi Sakamoto return err; 2263713d93aSTakashi Sakamoto } 2273713d93aSTakashi Sakamoto 2283713d93aSTakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream) 2293713d93aSTakashi Sakamoto { 2308985f4acSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2318985f4acSTakashi Sakamoto 2328985f4acSTakashi Sakamoto snd_oxfw_stream_lock_release(oxfw); 2333713d93aSTakashi Sakamoto return 0; 2343713d93aSTakashi Sakamoto } 2353713d93aSTakashi Sakamoto 236216e256fSTakashi Sakamoto static int pcm_capture_hw_params(struct snd_pcm_substream *substream, 2373713d93aSTakashi Sakamoto struct snd_pcm_hw_params *hw_params) 2383713d93aSTakashi Sakamoto { 2393713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 24022c103cdSTakashi Sakamoto int err; 2413713d93aSTakashi Sakamoto 24222c103cdSTakashi Sakamoto err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 24322c103cdSTakashi Sakamoto params_buffer_bytes(hw_params)); 24422c103cdSTakashi Sakamoto if (err < 0) 24522c103cdSTakashi Sakamoto return err; 246216e256fSTakashi Sakamoto 247216e256fSTakashi Sakamoto if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 2484f380d00STakashi Sakamoto unsigned int rate = params_rate(hw_params); 2494f380d00STakashi Sakamoto unsigned int channels = params_channels(hw_params); 2501d6a722cSTakashi Sakamoto unsigned int frames_per_period = params_period_size(hw_params); 2513299d2a0STakashi Sakamoto unsigned int frames_per_buffer = params_buffer_size(hw_params); 2524f380d00STakashi Sakamoto 253216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 2544f380d00STakashi Sakamoto err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 2553299d2a0STakashi Sakamoto rate, channels, frames_per_period, 2563299d2a0STakashi Sakamoto frames_per_buffer); 2574f380d00STakashi Sakamoto if (err >= 0) 2584a0a0472STakashi Sakamoto ++oxfw->substreams_count; 259216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 260216e256fSTakashi Sakamoto } 261216e256fSTakashi Sakamoto 2624f380d00STakashi Sakamoto return err; 263216e256fSTakashi Sakamoto } 264216e256fSTakashi Sakamoto static int pcm_playback_hw_params(struct snd_pcm_substream *substream, 265216e256fSTakashi Sakamoto struct snd_pcm_hw_params *hw_params) 266216e256fSTakashi Sakamoto { 267216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 26822c103cdSTakashi Sakamoto int err; 26922c103cdSTakashi Sakamoto 27022c103cdSTakashi Sakamoto err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 27122c103cdSTakashi Sakamoto params_buffer_bytes(hw_params)); 27222c103cdSTakashi Sakamoto if (err < 0) 27322c103cdSTakashi Sakamoto return err; 274216e256fSTakashi Sakamoto 275216e256fSTakashi Sakamoto if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 2764f380d00STakashi Sakamoto unsigned int rate = params_rate(hw_params); 2774f380d00STakashi Sakamoto unsigned int channels = params_channels(hw_params); 2781d6a722cSTakashi Sakamoto unsigned int frames_per_period = params_period_size(hw_params); 2793299d2a0STakashi Sakamoto unsigned int frames_per_buffer = params_buffer_size(hw_params); 2804f380d00STakashi Sakamoto 281216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 2822fd23293STakashi Sakamoto err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 2833299d2a0STakashi Sakamoto rate, channels, frames_per_period, 2843299d2a0STakashi Sakamoto frames_per_buffer); 2854f380d00STakashi Sakamoto if (err >= 0) 2864a0a0472STakashi Sakamoto ++oxfw->substreams_count; 287216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 288216e256fSTakashi Sakamoto } 289216e256fSTakashi Sakamoto 29022c103cdSTakashi Sakamoto return 0; 2913713d93aSTakashi Sakamoto } 2923713d93aSTakashi Sakamoto 293216e256fSTakashi Sakamoto static int pcm_capture_hw_free(struct snd_pcm_substream *substream) 2943713d93aSTakashi Sakamoto { 2953713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2963713d93aSTakashi Sakamoto 2973713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 298216e256fSTakashi Sakamoto 299216e256fSTakashi Sakamoto if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 3004a0a0472STakashi Sakamoto --oxfw->substreams_count; 301216e256fSTakashi Sakamoto 302779f0dbaSTakashi Sakamoto snd_oxfw_stream_stop_duplex(oxfw); 303216e256fSTakashi Sakamoto 304216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 305216e256fSTakashi Sakamoto 306216e256fSTakashi Sakamoto return snd_pcm_lib_free_vmalloc_buffer(substream); 307216e256fSTakashi Sakamoto } 308216e256fSTakashi Sakamoto static int pcm_playback_hw_free(struct snd_pcm_substream *substream) 309216e256fSTakashi Sakamoto { 310216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 311216e256fSTakashi Sakamoto 312216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 313216e256fSTakashi Sakamoto 314216e256fSTakashi Sakamoto if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 3154a0a0472STakashi Sakamoto --oxfw->substreams_count; 316216e256fSTakashi Sakamoto 317779f0dbaSTakashi Sakamoto snd_oxfw_stream_stop_duplex(oxfw); 318216e256fSTakashi Sakamoto 3193713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 3203713d93aSTakashi Sakamoto 3213713d93aSTakashi Sakamoto return snd_pcm_lib_free_vmalloc_buffer(substream); 3223713d93aSTakashi Sakamoto } 3233713d93aSTakashi Sakamoto 324216e256fSTakashi Sakamoto static int pcm_capture_prepare(struct snd_pcm_substream *substream) 325216e256fSTakashi Sakamoto { 326216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 327216e256fSTakashi Sakamoto int err; 328216e256fSTakashi Sakamoto 329216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 3304f380d00STakashi Sakamoto err = snd_oxfw_stream_start_duplex(oxfw); 331216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 332216e256fSTakashi Sakamoto if (err < 0) 333216e256fSTakashi Sakamoto goto end; 334216e256fSTakashi Sakamoto 335216e256fSTakashi Sakamoto amdtp_stream_pcm_prepare(&oxfw->tx_stream); 336216e256fSTakashi Sakamoto end: 337216e256fSTakashi Sakamoto return err; 338216e256fSTakashi Sakamoto } 339216e256fSTakashi Sakamoto static int pcm_playback_prepare(struct snd_pcm_substream *substream) 3403713d93aSTakashi Sakamoto { 3413713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 3423713d93aSTakashi Sakamoto int err; 3433713d93aSTakashi Sakamoto 3443713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 3454f380d00STakashi Sakamoto err = snd_oxfw_stream_start_duplex(oxfw); 346f3699e2cSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 3473713d93aSTakashi Sakamoto if (err < 0) 3483713d93aSTakashi Sakamoto goto end; 3493713d93aSTakashi Sakamoto 3503713d93aSTakashi Sakamoto amdtp_stream_pcm_prepare(&oxfw->rx_stream); 3513713d93aSTakashi Sakamoto end: 3523713d93aSTakashi Sakamoto return err; 3533713d93aSTakashi Sakamoto } 3543713d93aSTakashi Sakamoto 355216e256fSTakashi Sakamoto static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) 356216e256fSTakashi Sakamoto { 357216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 358216e256fSTakashi Sakamoto struct snd_pcm_substream *pcm; 359216e256fSTakashi Sakamoto 360216e256fSTakashi Sakamoto switch (cmd) { 361216e256fSTakashi Sakamoto case SNDRV_PCM_TRIGGER_START: 362216e256fSTakashi Sakamoto pcm = substream; 363216e256fSTakashi Sakamoto break; 364216e256fSTakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP: 365216e256fSTakashi Sakamoto pcm = NULL; 366216e256fSTakashi Sakamoto break; 367216e256fSTakashi Sakamoto default: 368216e256fSTakashi Sakamoto return -EINVAL; 369216e256fSTakashi Sakamoto } 370216e256fSTakashi Sakamoto amdtp_stream_pcm_trigger(&oxfw->tx_stream, pcm); 371216e256fSTakashi Sakamoto return 0; 372216e256fSTakashi Sakamoto } 373216e256fSTakashi Sakamoto static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) 3743713d93aSTakashi Sakamoto { 3753713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 3763713d93aSTakashi Sakamoto struct snd_pcm_substream *pcm; 3773713d93aSTakashi Sakamoto 3783713d93aSTakashi Sakamoto switch (cmd) { 3793713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_START: 3803713d93aSTakashi Sakamoto pcm = substream; 3813713d93aSTakashi Sakamoto break; 3823713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP: 3833713d93aSTakashi Sakamoto pcm = NULL; 3843713d93aSTakashi Sakamoto break; 3853713d93aSTakashi Sakamoto default: 3863713d93aSTakashi Sakamoto return -EINVAL; 3873713d93aSTakashi Sakamoto } 3883713d93aSTakashi Sakamoto amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); 3893713d93aSTakashi Sakamoto return 0; 3903713d93aSTakashi Sakamoto } 3913713d93aSTakashi Sakamoto 392216e256fSTakashi Sakamoto static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm) 3933713d93aSTakashi Sakamoto { 394216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = sbstm->private_data; 395216e256fSTakashi Sakamoto 396f890f9a0STakashi Sakamoto return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->tx_stream); 397216e256fSTakashi Sakamoto } 398216e256fSTakashi Sakamoto static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm) 399216e256fSTakashi Sakamoto { 400216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = sbstm->private_data; 4013713d93aSTakashi Sakamoto 402f890f9a0STakashi Sakamoto return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->rx_stream); 4033713d93aSTakashi Sakamoto } 4043713d93aSTakashi Sakamoto 405875becf8STakashi Sakamoto static int pcm_capture_ack(struct snd_pcm_substream *substream) 406875becf8STakashi Sakamoto { 407875becf8STakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 408875becf8STakashi Sakamoto 409*e6dcc92fSTakashi Sakamoto return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->tx_stream); 410875becf8STakashi Sakamoto } 411875becf8STakashi Sakamoto 412875becf8STakashi Sakamoto static int pcm_playback_ack(struct snd_pcm_substream *substream) 413875becf8STakashi Sakamoto { 414875becf8STakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 415875becf8STakashi Sakamoto 416*e6dcc92fSTakashi Sakamoto return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->rx_stream); 417875becf8STakashi Sakamoto } 418875becf8STakashi Sakamoto 4193713d93aSTakashi Sakamoto int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) 4203713d93aSTakashi Sakamoto { 4215116ffc3SJulia Lawall static const struct snd_pcm_ops capture_ops = { 4223713d93aSTakashi Sakamoto .open = pcm_open, 4233713d93aSTakashi Sakamoto .close = pcm_close, 4243713d93aSTakashi Sakamoto .ioctl = snd_pcm_lib_ioctl, 425216e256fSTakashi Sakamoto .hw_params = pcm_capture_hw_params, 426216e256fSTakashi Sakamoto .hw_free = pcm_capture_hw_free, 427216e256fSTakashi Sakamoto .prepare = pcm_capture_prepare, 428216e256fSTakashi Sakamoto .trigger = pcm_capture_trigger, 429216e256fSTakashi Sakamoto .pointer = pcm_capture_pointer, 430875becf8STakashi Sakamoto .ack = pcm_capture_ack, 431216e256fSTakashi Sakamoto .page = snd_pcm_lib_get_vmalloc_page, 432216e256fSTakashi Sakamoto }; 4335116ffc3SJulia Lawall static const struct snd_pcm_ops playback_ops = { 434216e256fSTakashi Sakamoto .open = pcm_open, 435216e256fSTakashi Sakamoto .close = pcm_close, 436216e256fSTakashi Sakamoto .ioctl = snd_pcm_lib_ioctl, 437216e256fSTakashi Sakamoto .hw_params = pcm_playback_hw_params, 438216e256fSTakashi Sakamoto .hw_free = pcm_playback_hw_free, 439216e256fSTakashi Sakamoto .prepare = pcm_playback_prepare, 440216e256fSTakashi Sakamoto .trigger = pcm_playback_trigger, 441216e256fSTakashi Sakamoto .pointer = pcm_playback_pointer, 442875becf8STakashi Sakamoto .ack = pcm_playback_ack, 4433713d93aSTakashi Sakamoto .page = snd_pcm_lib_get_vmalloc_page, 4443713d93aSTakashi Sakamoto }; 4453713d93aSTakashi Sakamoto struct snd_pcm *pcm; 446216e256fSTakashi Sakamoto unsigned int cap = 0; 4473713d93aSTakashi Sakamoto int err; 4483713d93aSTakashi Sakamoto 449216e256fSTakashi Sakamoto if (oxfw->has_output) 450216e256fSTakashi Sakamoto cap = 1; 451216e256fSTakashi Sakamoto 452216e256fSTakashi Sakamoto err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, cap, &pcm); 4533713d93aSTakashi Sakamoto if (err < 0) 4543713d93aSTakashi Sakamoto return err; 455216e256fSTakashi Sakamoto 4563713d93aSTakashi Sakamoto pcm->private_data = oxfw; 4573713d93aSTakashi Sakamoto strcpy(pcm->name, oxfw->card->shortname); 458216e256fSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); 459216e256fSTakashi Sakamoto if (cap > 0) 460216e256fSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); 461216e256fSTakashi Sakamoto 4623713d93aSTakashi Sakamoto return 0; 4633713d93aSTakashi Sakamoto } 464