2 * tascam-pcm.c - a part of driver for TASCAM FireWire series
4 * Copyright (c) 2015 Takashi Sakamoto
6 * Licensed under the terms of the GNU General Public License, version 2.
11 static void set_buffer_params(struct snd_pcm_hardware *hw)
13 hw->period_bytes_min = 4 * hw->channels_min;
14 hw->period_bytes_max = hw->period_bytes_min * 2048;
15 hw->buffer_bytes_max = hw->period_bytes_max * 2;
18 hw->periods_max = UINT_MAX;
21 static int pcm_init_hw_params(struct snd_tscm *tscm,
22 struct snd_pcm_substream *substream)
24 static const struct snd_pcm_hardware hardware = {
25 .info = SNDRV_PCM_INFO_BATCH |
26 SNDRV_PCM_INFO_BLOCK_TRANSFER |
27 SNDRV_PCM_INFO_INTERLEAVED |
28 SNDRV_PCM_INFO_JOINT_DUPLEX |
30 SNDRV_PCM_INFO_MMAP_VALID,
31 .rates = SNDRV_PCM_RATE_44100 |
32 SNDRV_PCM_RATE_48000 |
33 SNDRV_PCM_RATE_88200 |
40 struct snd_pcm_runtime *runtime = substream->runtime;
41 struct amdtp_stream *stream;
42 unsigned int pcm_channels;
44 runtime->hw = hardware;
46 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
47 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
48 stream = &tscm->tx_stream;
49 pcm_channels = tscm->spec->pcm_capture_analog_channels;
51 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
52 stream = &tscm->rx_stream;
53 pcm_channels = tscm->spec->pcm_playback_analog_channels;
56 if (tscm->spec->has_adat)
58 if (tscm->spec->has_spdif)
60 runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels;
62 set_buffer_params(&runtime->hw);
64 return amdtp_tscm_add_pcm_hw_constraints(stream, runtime);
67 static int pcm_open(struct snd_pcm_substream *substream)
69 struct snd_tscm *tscm = substream->private_data;
70 enum snd_tscm_clock clock;
74 err = snd_tscm_stream_lock_try(tscm);
78 err = pcm_init_hw_params(tscm, substream);
82 err = snd_tscm_stream_get_clock(tscm, &clock);
83 if (clock != SND_TSCM_CLOCK_INTERNAL ||
84 amdtp_stream_pcm_running(&tscm->rx_stream) ||
85 amdtp_stream_pcm_running(&tscm->tx_stream)) {
86 err = snd_tscm_stream_get_rate(tscm, &rate);
89 substream->runtime->hw.rate_min = rate;
90 substream->runtime->hw.rate_max = rate;
93 snd_pcm_set_sync(substream);
97 snd_tscm_stream_lock_release(tscm);
101 static int pcm_close(struct snd_pcm_substream *substream)
103 struct snd_tscm *tscm = substream->private_data;
105 snd_tscm_stream_lock_release(tscm);
110 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
111 struct snd_pcm_hw_params *hw_params)
113 struct snd_tscm *tscm = substream->private_data;
116 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
117 params_buffer_bytes(hw_params));
121 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
122 mutex_lock(&tscm->mutex);
123 tscm->substreams_counter++;
124 mutex_unlock(&tscm->mutex);
130 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
131 struct snd_pcm_hw_params *hw_params)
133 struct snd_tscm *tscm = substream->private_data;
136 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
137 params_buffer_bytes(hw_params));
141 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
142 mutex_lock(&tscm->mutex);
143 tscm->substreams_counter++;
144 mutex_unlock(&tscm->mutex);
150 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
152 struct snd_tscm *tscm = substream->private_data;
154 mutex_lock(&tscm->mutex);
156 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
157 tscm->substreams_counter--;
159 snd_tscm_stream_stop_duplex(tscm);
161 mutex_unlock(&tscm->mutex);
163 return snd_pcm_lib_free_vmalloc_buffer(substream);
166 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
168 struct snd_tscm *tscm = substream->private_data;
170 mutex_lock(&tscm->mutex);
172 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
173 tscm->substreams_counter--;
175 snd_tscm_stream_stop_duplex(tscm);
177 mutex_unlock(&tscm->mutex);
179 return snd_pcm_lib_free_vmalloc_buffer(substream);
182 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
184 struct snd_tscm *tscm = substream->private_data;
185 struct snd_pcm_runtime *runtime = substream->runtime;
188 mutex_lock(&tscm->mutex);
190 err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
192 amdtp_stream_pcm_prepare(&tscm->tx_stream);
194 mutex_unlock(&tscm->mutex);
199 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
201 struct snd_tscm *tscm = substream->private_data;
202 struct snd_pcm_runtime *runtime = substream->runtime;
205 mutex_lock(&tscm->mutex);
207 err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
209 amdtp_stream_pcm_prepare(&tscm->rx_stream);
211 mutex_unlock(&tscm->mutex);
216 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
218 struct snd_tscm *tscm = substream->private_data;
221 case SNDRV_PCM_TRIGGER_START:
222 amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
224 case SNDRV_PCM_TRIGGER_STOP:
225 amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
234 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
236 struct snd_tscm *tscm = substream->private_data;
239 case SNDRV_PCM_TRIGGER_START:
240 amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
242 case SNDRV_PCM_TRIGGER_STOP:
243 amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
252 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
254 struct snd_tscm *tscm = sbstrm->private_data;
256 return amdtp_stream_pcm_pointer(&tscm->tx_stream);
259 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
261 struct snd_tscm *tscm = sbstrm->private_data;
263 return amdtp_stream_pcm_pointer(&tscm->rx_stream);
266 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
268 static const struct snd_pcm_ops capture_ops = {
271 .ioctl = snd_pcm_lib_ioctl,
272 .hw_params = pcm_capture_hw_params,
273 .hw_free = pcm_capture_hw_free,
274 .prepare = pcm_capture_prepare,
275 .trigger = pcm_capture_trigger,
276 .pointer = pcm_capture_pointer,
277 .page = snd_pcm_lib_get_vmalloc_page,
279 static const struct snd_pcm_ops playback_ops = {
282 .ioctl = snd_pcm_lib_ioctl,
283 .hw_params = pcm_playback_hw_params,
284 .hw_free = pcm_playback_hw_free,
285 .prepare = pcm_playback_prepare,
286 .trigger = pcm_playback_trigger,
287 .pointer = pcm_playback_pointer,
288 .page = snd_pcm_lib_get_vmalloc_page,
289 .mmap = snd_pcm_lib_mmap_vmalloc,
294 err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
298 pcm->private_data = tscm;
299 snprintf(pcm->name, sizeof(pcm->name),
300 "%s PCM", tscm->card->shortname);
301 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
302 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);