1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * tascam-pcm.c - a part of driver for TASCAM FireWire series 4 * 5 * Copyright (c) 2015 Takashi Sakamoto 6 */ 7 8 #include "tascam.h" 9 10 static int pcm_init_hw_params(struct snd_tscm *tscm, 11 struct snd_pcm_substream *substream) 12 { 13 struct snd_pcm_runtime *runtime = substream->runtime; 14 struct snd_pcm_hardware *hw = &runtime->hw; 15 struct amdtp_stream *stream; 16 unsigned int pcm_channels; 17 18 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 19 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; 20 stream = &tscm->tx_stream; 21 pcm_channels = tscm->spec->pcm_capture_analog_channels; 22 } else { 23 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32; 24 stream = &tscm->rx_stream; 25 pcm_channels = tscm->spec->pcm_playback_analog_channels; 26 } 27 28 if (tscm->spec->has_adat) 29 pcm_channels += 8; 30 if (tscm->spec->has_spdif) 31 pcm_channels += 2; 32 runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels; 33 34 hw->rates = SNDRV_PCM_RATE_44100 | 35 SNDRV_PCM_RATE_48000 | 36 SNDRV_PCM_RATE_88200 | 37 SNDRV_PCM_RATE_96000; 38 snd_pcm_limit_hw_rates(runtime); 39 40 return amdtp_tscm_add_pcm_hw_constraints(stream, runtime); 41 } 42 43 static int pcm_open(struct snd_pcm_substream *substream) 44 { 45 struct snd_tscm *tscm = substream->private_data; 46 enum snd_tscm_clock clock; 47 unsigned int rate; 48 int err; 49 50 err = snd_tscm_stream_lock_try(tscm); 51 if (err < 0) 52 goto end; 53 54 err = pcm_init_hw_params(tscm, substream); 55 if (err < 0) 56 goto err_locked; 57 58 err = snd_tscm_stream_get_clock(tscm, &clock); 59 if (err < 0) 60 goto err_locked; 61 62 if (clock != SND_TSCM_CLOCK_INTERNAL || 63 amdtp_stream_pcm_running(&tscm->rx_stream) || 64 amdtp_stream_pcm_running(&tscm->tx_stream)) { 65 err = snd_tscm_stream_get_rate(tscm, &rate); 66 if (err < 0) 67 goto err_locked; 68 substream->runtime->hw.rate_min = rate; 69 substream->runtime->hw.rate_max = rate; 70 } 71 72 snd_pcm_set_sync(substream); 73 end: 74 return err; 75 err_locked: 76 snd_tscm_stream_lock_release(tscm); 77 return err; 78 } 79 80 static int pcm_close(struct snd_pcm_substream *substream) 81 { 82 struct snd_tscm *tscm = substream->private_data; 83 84 snd_tscm_stream_lock_release(tscm); 85 86 return 0; 87 } 88 89 static int pcm_hw_params(struct snd_pcm_substream *substream, 90 struct snd_pcm_hw_params *hw_params) 91 { 92 struct snd_tscm *tscm = substream->private_data; 93 int err; 94 95 err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 96 params_buffer_bytes(hw_params)); 97 if (err < 0) 98 return err; 99 100 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 101 unsigned int rate = params_rate(hw_params); 102 103 mutex_lock(&tscm->mutex); 104 err = snd_tscm_stream_reserve_duplex(tscm, rate); 105 if (err >= 0) 106 ++tscm->substreams_counter; 107 mutex_unlock(&tscm->mutex); 108 } 109 110 return err; 111 } 112 113 static int pcm_hw_free(struct snd_pcm_substream *substream) 114 { 115 struct snd_tscm *tscm = substream->private_data; 116 117 mutex_lock(&tscm->mutex); 118 119 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 120 --tscm->substreams_counter; 121 122 snd_tscm_stream_stop_duplex(tscm); 123 124 mutex_unlock(&tscm->mutex); 125 126 return snd_pcm_lib_free_vmalloc_buffer(substream); 127 } 128 129 static int pcm_capture_prepare(struct snd_pcm_substream *substream) 130 { 131 struct snd_tscm *tscm = substream->private_data; 132 struct snd_pcm_runtime *runtime = substream->runtime; 133 int err; 134 135 mutex_lock(&tscm->mutex); 136 137 err = snd_tscm_stream_start_duplex(tscm, runtime->rate); 138 if (err >= 0) 139 amdtp_stream_pcm_prepare(&tscm->tx_stream); 140 141 mutex_unlock(&tscm->mutex); 142 143 return err; 144 } 145 146 static int pcm_playback_prepare(struct snd_pcm_substream *substream) 147 { 148 struct snd_tscm *tscm = substream->private_data; 149 struct snd_pcm_runtime *runtime = substream->runtime; 150 int err; 151 152 mutex_lock(&tscm->mutex); 153 154 err = snd_tscm_stream_start_duplex(tscm, runtime->rate); 155 if (err >= 0) 156 amdtp_stream_pcm_prepare(&tscm->rx_stream); 157 158 mutex_unlock(&tscm->mutex); 159 160 return err; 161 } 162 163 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) 164 { 165 struct snd_tscm *tscm = substream->private_data; 166 167 switch (cmd) { 168 case SNDRV_PCM_TRIGGER_START: 169 amdtp_stream_pcm_trigger(&tscm->tx_stream, substream); 170 break; 171 case SNDRV_PCM_TRIGGER_STOP: 172 amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL); 173 break; 174 default: 175 return -EINVAL; 176 } 177 178 return 0; 179 } 180 181 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) 182 { 183 struct snd_tscm *tscm = substream->private_data; 184 185 switch (cmd) { 186 case SNDRV_PCM_TRIGGER_START: 187 amdtp_stream_pcm_trigger(&tscm->rx_stream, substream); 188 break; 189 case SNDRV_PCM_TRIGGER_STOP: 190 amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL); 191 break; 192 default: 193 return -EINVAL; 194 } 195 196 return 0; 197 } 198 199 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) 200 { 201 struct snd_tscm *tscm = sbstrm->private_data; 202 203 return amdtp_stream_pcm_pointer(&tscm->tx_stream); 204 } 205 206 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) 207 { 208 struct snd_tscm *tscm = sbstrm->private_data; 209 210 return amdtp_stream_pcm_pointer(&tscm->rx_stream); 211 } 212 213 static int pcm_capture_ack(struct snd_pcm_substream *substream) 214 { 215 struct snd_tscm *tscm = substream->private_data; 216 217 return amdtp_stream_pcm_ack(&tscm->tx_stream); 218 } 219 220 static int pcm_playback_ack(struct snd_pcm_substream *substream) 221 { 222 struct snd_tscm *tscm = substream->private_data; 223 224 return amdtp_stream_pcm_ack(&tscm->rx_stream); 225 } 226 227 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) 228 { 229 static const struct snd_pcm_ops capture_ops = { 230 .open = pcm_open, 231 .close = pcm_close, 232 .ioctl = snd_pcm_lib_ioctl, 233 .hw_params = pcm_hw_params, 234 .hw_free = pcm_hw_free, 235 .prepare = pcm_capture_prepare, 236 .trigger = pcm_capture_trigger, 237 .pointer = pcm_capture_pointer, 238 .ack = pcm_capture_ack, 239 .page = snd_pcm_lib_get_vmalloc_page, 240 }; 241 static const struct snd_pcm_ops playback_ops = { 242 .open = pcm_open, 243 .close = pcm_close, 244 .ioctl = snd_pcm_lib_ioctl, 245 .hw_params = pcm_hw_params, 246 .hw_free = pcm_hw_free, 247 .prepare = pcm_playback_prepare, 248 .trigger = pcm_playback_trigger, 249 .pointer = pcm_playback_pointer, 250 .ack = pcm_playback_ack, 251 .page = snd_pcm_lib_get_vmalloc_page, 252 }; 253 struct snd_pcm *pcm; 254 int err; 255 256 err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm); 257 if (err < 0) 258 return err; 259 260 pcm->private_data = tscm; 261 snprintf(pcm->name, sizeof(pcm->name), 262 "%s PCM", tscm->card->shortname); 263 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); 264 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); 265 266 return 0; 267 } 268