13713d93aSTakashi Sakamoto /* 23713d93aSTakashi Sakamoto * oxfw_pcm.c - a part of driver for OXFW970/971 based devices 33713d93aSTakashi Sakamoto * 43713d93aSTakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 53713d93aSTakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 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; 225cd1d3f4STakashi Sakamoto unsigned 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; 505cd1d3f4STakashi Sakamoto unsigned 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; 835cd1d3f4STakashi Sakamoto unsigned 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 1095cd1d3f4STakashi Sakamoto static void limit_period_and_buffer(struct snd_pcm_hardware *hw) 1105cd1d3f4STakashi Sakamoto { 1115cd1d3f4STakashi Sakamoto hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ 1125cd1d3f4STakashi Sakamoto hw->periods_max = UINT_MAX; 1135cd1d3f4STakashi Sakamoto 1145cd1d3f4STakashi Sakamoto hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */ 1155cd1d3f4STakashi Sakamoto 1165cd1d3f4STakashi Sakamoto /* Just to prevent from allocating much pages. */ 1175cd1d3f4STakashi Sakamoto hw->period_bytes_max = hw->period_bytes_min * 2048; 1185cd1d3f4STakashi Sakamoto hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; 1193713d93aSTakashi Sakamoto } 1203713d93aSTakashi Sakamoto 121*216e256fSTakashi Sakamoto static int init_hw_params(struct snd_oxfw *oxfw, 122*216e256fSTakashi Sakamoto struct snd_pcm_substream *substream) 1233713d93aSTakashi Sakamoto { 1243713d93aSTakashi Sakamoto struct snd_pcm_runtime *runtime = substream->runtime; 1255cd1d3f4STakashi Sakamoto u8 **formats; 126*216e256fSTakashi Sakamoto struct amdtp_stream *stream; 1273713d93aSTakashi Sakamoto int err; 1283713d93aSTakashi Sakamoto 1295cd1d3f4STakashi Sakamoto runtime->hw.info = SNDRV_PCM_INFO_BATCH | 1305cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_BLOCK_TRANSFER | 1315cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_INTERLEAVED | 132*216e256fSTakashi Sakamoto SNDRV_PCM_INFO_JOINT_DUPLEX | 1335cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_MMAP | 1345cd1d3f4STakashi Sakamoto SNDRV_PCM_INFO_MMAP_VALID; 1353713d93aSTakashi Sakamoto 136*216e256fSTakashi Sakamoto if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 137*216e256fSTakashi Sakamoto runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS; 138*216e256fSTakashi Sakamoto stream = &oxfw->tx_stream; 139*216e256fSTakashi Sakamoto formats = oxfw->tx_stream_formats; 140*216e256fSTakashi Sakamoto } else { 141*216e256fSTakashi Sakamoto runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS; 142*216e256fSTakashi Sakamoto stream = &oxfw->rx_stream; 143*216e256fSTakashi Sakamoto formats = oxfw->rx_stream_formats; 144*216e256fSTakashi Sakamoto } 145*216e256fSTakashi Sakamoto 1465cd1d3f4STakashi Sakamoto limit_channels_and_rates(&runtime->hw, formats); 1475cd1d3f4STakashi Sakamoto limit_period_and_buffer(&runtime->hw); 1485cd1d3f4STakashi Sakamoto 1495cd1d3f4STakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 1505cd1d3f4STakashi Sakamoto hw_rule_channels, formats, 1515cd1d3f4STakashi Sakamoto SNDRV_PCM_HW_PARAM_RATE, -1); 1523713d93aSTakashi Sakamoto if (err < 0) 1533713d93aSTakashi Sakamoto goto end; 1545cd1d3f4STakashi Sakamoto 1555cd1d3f4STakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 1565cd1d3f4STakashi Sakamoto hw_rule_rate, formats, 1575cd1d3f4STakashi Sakamoto SNDRV_PCM_HW_PARAM_CHANNELS, -1); 1583713d93aSTakashi Sakamoto if (err < 0) 1593713d93aSTakashi Sakamoto goto end; 1603713d93aSTakashi Sakamoto 161*216e256fSTakashi Sakamoto err = amdtp_stream_add_pcm_hw_constraints(stream, runtime); 162*216e256fSTakashi Sakamoto end: 163*216e256fSTakashi Sakamoto return err; 164*216e256fSTakashi Sakamoto } 165*216e256fSTakashi Sakamoto 166*216e256fSTakashi Sakamoto static int limit_to_current_params(struct snd_pcm_substream *substream) 167*216e256fSTakashi Sakamoto { 168*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 169*216e256fSTakashi Sakamoto struct snd_oxfw_stream_formation formation; 170*216e256fSTakashi Sakamoto enum avc_general_plug_dir dir; 171*216e256fSTakashi Sakamoto int err; 172*216e256fSTakashi Sakamoto 173*216e256fSTakashi Sakamoto if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 174*216e256fSTakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_OUT; 175*216e256fSTakashi Sakamoto else 176*216e256fSTakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_IN; 177*216e256fSTakashi Sakamoto 178*216e256fSTakashi Sakamoto err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); 1795cd1d3f4STakashi Sakamoto if (err < 0) 1805cd1d3f4STakashi Sakamoto goto end; 1815cd1d3f4STakashi Sakamoto 182*216e256fSTakashi Sakamoto substream->runtime->hw.channels_min = formation.pcm; 183*216e256fSTakashi Sakamoto substream->runtime->hw.channels_max = formation.pcm; 184*216e256fSTakashi Sakamoto substream->runtime->hw.rate_min = formation.rate; 185*216e256fSTakashi Sakamoto substream->runtime->hw.rate_max = formation.rate; 186*216e256fSTakashi Sakamoto end: 187*216e256fSTakashi Sakamoto return err; 188*216e256fSTakashi Sakamoto } 189*216e256fSTakashi Sakamoto 190*216e256fSTakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream) 191*216e256fSTakashi Sakamoto { 192*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 193*216e256fSTakashi Sakamoto int err; 194*216e256fSTakashi Sakamoto 195*216e256fSTakashi Sakamoto err = init_hw_params(oxfw, substream); 196*216e256fSTakashi Sakamoto if (err < 0) 197*216e256fSTakashi Sakamoto goto end; 198*216e256fSTakashi Sakamoto 199*216e256fSTakashi Sakamoto /* 200*216e256fSTakashi Sakamoto * When any PCM streams are already running, the available sampling 201*216e256fSTakashi Sakamoto * rate is limited at current value. 202*216e256fSTakashi Sakamoto */ 203*216e256fSTakashi Sakamoto if (amdtp_stream_pcm_running(&oxfw->tx_stream) || 204*216e256fSTakashi Sakamoto amdtp_stream_pcm_running(&oxfw->rx_stream)) { 205*216e256fSTakashi Sakamoto err = limit_to_current_params(substream); 206*216e256fSTakashi Sakamoto if (err < 0) 207*216e256fSTakashi Sakamoto goto end; 208*216e256fSTakashi Sakamoto } 209*216e256fSTakashi Sakamoto 2105cd1d3f4STakashi Sakamoto snd_pcm_set_sync(substream); 2113713d93aSTakashi Sakamoto end: 2123713d93aSTakashi Sakamoto return err; 2133713d93aSTakashi Sakamoto } 2143713d93aSTakashi Sakamoto 2153713d93aSTakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream) 2163713d93aSTakashi Sakamoto { 2173713d93aSTakashi Sakamoto return 0; 2183713d93aSTakashi Sakamoto } 2193713d93aSTakashi Sakamoto 220*216e256fSTakashi Sakamoto static int pcm_capture_hw_params(struct snd_pcm_substream *substream, 2213713d93aSTakashi Sakamoto struct snd_pcm_hw_params *hw_params) 2223713d93aSTakashi Sakamoto { 2233713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2243713d93aSTakashi Sakamoto 225*216e256fSTakashi Sakamoto 226*216e256fSTakashi Sakamoto if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 227*216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 228*216e256fSTakashi Sakamoto oxfw->capture_substreams++; 229*216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 230*216e256fSTakashi Sakamoto } 231*216e256fSTakashi Sakamoto 232*216e256fSTakashi Sakamoto amdtp_stream_set_pcm_format(&oxfw->tx_stream, params_format(hw_params)); 233*216e256fSTakashi Sakamoto 234*216e256fSTakashi Sakamoto return snd_pcm_lib_alloc_vmalloc_buffer(substream, 235*216e256fSTakashi Sakamoto params_buffer_bytes(hw_params)); 236*216e256fSTakashi Sakamoto } 237*216e256fSTakashi Sakamoto static int pcm_playback_hw_params(struct snd_pcm_substream *substream, 238*216e256fSTakashi Sakamoto struct snd_pcm_hw_params *hw_params) 239*216e256fSTakashi Sakamoto { 240*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 241*216e256fSTakashi Sakamoto 242*216e256fSTakashi Sakamoto if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 243*216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 244*216e256fSTakashi Sakamoto oxfw->playback_substreams++; 245*216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 246*216e256fSTakashi Sakamoto } 247*216e256fSTakashi Sakamoto 248f3699e2cSTakashi Sakamoto amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params)); 249*216e256fSTakashi Sakamoto 250f3699e2cSTakashi Sakamoto return snd_pcm_lib_alloc_vmalloc_buffer(substream, 2513713d93aSTakashi Sakamoto params_buffer_bytes(hw_params)); 2523713d93aSTakashi Sakamoto } 2533713d93aSTakashi Sakamoto 254*216e256fSTakashi Sakamoto static int pcm_capture_hw_free(struct snd_pcm_substream *substream) 2553713d93aSTakashi Sakamoto { 2563713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 2573713d93aSTakashi Sakamoto 2583713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 259*216e256fSTakashi Sakamoto 260*216e256fSTakashi Sakamoto if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 261*216e256fSTakashi Sakamoto oxfw->capture_substreams--; 262*216e256fSTakashi Sakamoto 263*216e256fSTakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream); 264*216e256fSTakashi Sakamoto 265*216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 266*216e256fSTakashi Sakamoto 267*216e256fSTakashi Sakamoto return snd_pcm_lib_free_vmalloc_buffer(substream); 268*216e256fSTakashi Sakamoto } 269*216e256fSTakashi Sakamoto static int pcm_playback_hw_free(struct snd_pcm_substream *substream) 270*216e256fSTakashi Sakamoto { 271*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 272*216e256fSTakashi Sakamoto 273*216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 274*216e256fSTakashi Sakamoto 275*216e256fSTakashi Sakamoto if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 276*216e256fSTakashi Sakamoto oxfw->playback_substreams--; 277*216e256fSTakashi Sakamoto 278b0ac0009STakashi Sakamoto snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream); 279*216e256fSTakashi Sakamoto 2803713d93aSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 2813713d93aSTakashi Sakamoto 2823713d93aSTakashi Sakamoto return snd_pcm_lib_free_vmalloc_buffer(substream); 2833713d93aSTakashi Sakamoto } 2843713d93aSTakashi Sakamoto 285*216e256fSTakashi Sakamoto static int pcm_capture_prepare(struct snd_pcm_substream *substream) 286*216e256fSTakashi Sakamoto { 287*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 288*216e256fSTakashi Sakamoto struct snd_pcm_runtime *runtime = substream->runtime; 289*216e256fSTakashi Sakamoto int err; 290*216e256fSTakashi Sakamoto 291*216e256fSTakashi Sakamoto mutex_lock(&oxfw->mutex); 292*216e256fSTakashi Sakamoto err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, 293*216e256fSTakashi Sakamoto runtime->rate, runtime->channels); 294*216e256fSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 295*216e256fSTakashi Sakamoto if (err < 0) 296*216e256fSTakashi Sakamoto goto end; 297*216e256fSTakashi Sakamoto 298*216e256fSTakashi Sakamoto amdtp_stream_pcm_prepare(&oxfw->tx_stream); 299*216e256fSTakashi Sakamoto end: 300*216e256fSTakashi Sakamoto return err; 301*216e256fSTakashi Sakamoto } 302*216e256fSTakashi Sakamoto static int pcm_playback_prepare(struct snd_pcm_substream *substream) 3033713d93aSTakashi Sakamoto { 3043713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 305f3699e2cSTakashi Sakamoto struct snd_pcm_runtime *runtime = substream->runtime; 3063713d93aSTakashi Sakamoto int err; 3073713d93aSTakashi Sakamoto 3083713d93aSTakashi Sakamoto mutex_lock(&oxfw->mutex); 309b0ac0009STakashi Sakamoto err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, 310b0ac0009STakashi Sakamoto runtime->rate, runtime->channels); 311f3699e2cSTakashi Sakamoto mutex_unlock(&oxfw->mutex); 3123713d93aSTakashi Sakamoto if (err < 0) 3133713d93aSTakashi Sakamoto goto end; 3143713d93aSTakashi Sakamoto 3153713d93aSTakashi Sakamoto amdtp_stream_pcm_prepare(&oxfw->rx_stream); 3163713d93aSTakashi Sakamoto end: 3173713d93aSTakashi Sakamoto return err; 3183713d93aSTakashi Sakamoto } 3193713d93aSTakashi Sakamoto 320*216e256fSTakashi Sakamoto static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) 321*216e256fSTakashi Sakamoto { 322*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 323*216e256fSTakashi Sakamoto struct snd_pcm_substream *pcm; 324*216e256fSTakashi Sakamoto 325*216e256fSTakashi Sakamoto switch (cmd) { 326*216e256fSTakashi Sakamoto case SNDRV_PCM_TRIGGER_START: 327*216e256fSTakashi Sakamoto pcm = substream; 328*216e256fSTakashi Sakamoto break; 329*216e256fSTakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP: 330*216e256fSTakashi Sakamoto pcm = NULL; 331*216e256fSTakashi Sakamoto break; 332*216e256fSTakashi Sakamoto default: 333*216e256fSTakashi Sakamoto return -EINVAL; 334*216e256fSTakashi Sakamoto } 335*216e256fSTakashi Sakamoto amdtp_stream_pcm_trigger(&oxfw->tx_stream, pcm); 336*216e256fSTakashi Sakamoto return 0; 337*216e256fSTakashi Sakamoto } 338*216e256fSTakashi Sakamoto static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) 3393713d93aSTakashi Sakamoto { 3403713d93aSTakashi Sakamoto struct snd_oxfw *oxfw = substream->private_data; 3413713d93aSTakashi Sakamoto struct snd_pcm_substream *pcm; 3423713d93aSTakashi Sakamoto 3433713d93aSTakashi Sakamoto switch (cmd) { 3443713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_START: 3453713d93aSTakashi Sakamoto pcm = substream; 3463713d93aSTakashi Sakamoto break; 3473713d93aSTakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP: 3483713d93aSTakashi Sakamoto pcm = NULL; 3493713d93aSTakashi Sakamoto break; 3503713d93aSTakashi Sakamoto default: 3513713d93aSTakashi Sakamoto return -EINVAL; 3523713d93aSTakashi Sakamoto } 3533713d93aSTakashi Sakamoto amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); 3543713d93aSTakashi Sakamoto return 0; 3553713d93aSTakashi Sakamoto } 3563713d93aSTakashi Sakamoto 357*216e256fSTakashi Sakamoto static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm) 3583713d93aSTakashi Sakamoto { 359*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = sbstm->private_data; 360*216e256fSTakashi Sakamoto 361*216e256fSTakashi Sakamoto return amdtp_stream_pcm_pointer(&oxfw->tx_stream); 362*216e256fSTakashi Sakamoto } 363*216e256fSTakashi Sakamoto static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm) 364*216e256fSTakashi Sakamoto { 365*216e256fSTakashi Sakamoto struct snd_oxfw *oxfw = sbstm->private_data; 3663713d93aSTakashi Sakamoto 3673713d93aSTakashi Sakamoto return amdtp_stream_pcm_pointer(&oxfw->rx_stream); 3683713d93aSTakashi Sakamoto } 3693713d93aSTakashi Sakamoto 3703713d93aSTakashi Sakamoto int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) 3713713d93aSTakashi Sakamoto { 372*216e256fSTakashi Sakamoto static struct snd_pcm_ops capture_ops = { 3733713d93aSTakashi Sakamoto .open = pcm_open, 3743713d93aSTakashi Sakamoto .close = pcm_close, 3753713d93aSTakashi Sakamoto .ioctl = snd_pcm_lib_ioctl, 376*216e256fSTakashi Sakamoto .hw_params = pcm_capture_hw_params, 377*216e256fSTakashi Sakamoto .hw_free = pcm_capture_hw_free, 378*216e256fSTakashi Sakamoto .prepare = pcm_capture_prepare, 379*216e256fSTakashi Sakamoto .trigger = pcm_capture_trigger, 380*216e256fSTakashi Sakamoto .pointer = pcm_capture_pointer, 381*216e256fSTakashi Sakamoto .page = snd_pcm_lib_get_vmalloc_page, 382*216e256fSTakashi Sakamoto .mmap = snd_pcm_lib_mmap_vmalloc, 383*216e256fSTakashi Sakamoto }; 384*216e256fSTakashi Sakamoto static struct snd_pcm_ops playback_ops = { 385*216e256fSTakashi Sakamoto .open = pcm_open, 386*216e256fSTakashi Sakamoto .close = pcm_close, 387*216e256fSTakashi Sakamoto .ioctl = snd_pcm_lib_ioctl, 388*216e256fSTakashi Sakamoto .hw_params = pcm_playback_hw_params, 389*216e256fSTakashi Sakamoto .hw_free = pcm_playback_hw_free, 390*216e256fSTakashi Sakamoto .prepare = pcm_playback_prepare, 391*216e256fSTakashi Sakamoto .trigger = pcm_playback_trigger, 392*216e256fSTakashi Sakamoto .pointer = pcm_playback_pointer, 3933713d93aSTakashi Sakamoto .page = snd_pcm_lib_get_vmalloc_page, 3943713d93aSTakashi Sakamoto .mmap = snd_pcm_lib_mmap_vmalloc, 3953713d93aSTakashi Sakamoto }; 3963713d93aSTakashi Sakamoto struct snd_pcm *pcm; 397*216e256fSTakashi Sakamoto unsigned int cap = 0; 3983713d93aSTakashi Sakamoto int err; 3993713d93aSTakashi Sakamoto 400*216e256fSTakashi Sakamoto if (oxfw->has_output) 401*216e256fSTakashi Sakamoto cap = 1; 402*216e256fSTakashi Sakamoto 403*216e256fSTakashi Sakamoto err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, cap, &pcm); 4043713d93aSTakashi Sakamoto if (err < 0) 4053713d93aSTakashi Sakamoto return err; 406*216e256fSTakashi Sakamoto 4073713d93aSTakashi Sakamoto pcm->private_data = oxfw; 4083713d93aSTakashi Sakamoto strcpy(pcm->name, oxfw->card->shortname); 409*216e256fSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); 410*216e256fSTakashi Sakamoto if (cap > 0) 411*216e256fSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); 412*216e256fSTakashi Sakamoto 4133713d93aSTakashi Sakamoto return 0; 4143713d93aSTakashi Sakamoto } 415