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