md/raid: only permit hot-add of compatible integrity profiles
[linux/fpc-iii.git] / sound / firewire / tascam / tascam-pcm.c
blob380d3db969a5896e41dc8f8cee973f60efe38c1a
1 /*
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.
7 */
9 #include "tascam.h"
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;
17 hw->periods_min = 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 |
29 SNDRV_PCM_INFO_MMAP |
30 SNDRV_PCM_INFO_MMAP_VALID,
31 .rates = SNDRV_PCM_RATE_44100 |
32 SNDRV_PCM_RATE_48000 |
33 SNDRV_PCM_RATE_88200 |
34 SNDRV_PCM_RATE_96000,
35 .rate_min = 44100,
36 .rate_max = 96000,
37 .channels_min = 10,
38 .channels_max = 18,
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;
50 } else {
51 runtime->hw.formats =
52 SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32;
53 stream = &tscm->rx_stream;
54 pcm_channels = tscm->spec->pcm_playback_analog_channels;
57 if (tscm->spec->has_adat)
58 pcm_channels += 8;
59 if (tscm->spec->has_spdif)
60 pcm_channels += 2;
61 runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels;
63 set_buffer_params(&runtime->hw);
65 return amdtp_tscm_add_pcm_hw_constraints(stream, runtime);
68 static int pcm_open(struct snd_pcm_substream *substream)
70 struct snd_tscm *tscm = substream->private_data;
71 enum snd_tscm_clock clock;
72 unsigned int rate;
73 int err;
75 err = snd_tscm_stream_lock_try(tscm);
76 if (err < 0)
77 goto end;
79 err = pcm_init_hw_params(tscm, substream);
80 if (err < 0)
81 goto err_locked;
83 err = snd_tscm_stream_get_clock(tscm, &clock);
84 if (clock != SND_TSCM_CLOCK_INTERNAL ||
85 amdtp_stream_pcm_running(&tscm->rx_stream) ||
86 amdtp_stream_pcm_running(&tscm->tx_stream)) {
87 err = snd_tscm_stream_get_rate(tscm, &rate);
88 if (err < 0)
89 goto err_locked;
90 substream->runtime->hw.rate_min = rate;
91 substream->runtime->hw.rate_max = rate;
94 snd_pcm_set_sync(substream);
95 end:
96 return err;
97 err_locked:
98 snd_tscm_stream_lock_release(tscm);
99 return err;
102 static int pcm_close(struct snd_pcm_substream *substream)
104 struct snd_tscm *tscm = substream->private_data;
106 snd_tscm_stream_lock_release(tscm);
108 return 0;
111 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
112 struct snd_pcm_hw_params *hw_params)
114 struct snd_tscm *tscm = substream->private_data;
115 int err;
117 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
118 params_buffer_bytes(hw_params));
119 if (err < 0)
120 return err;
122 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
123 mutex_lock(&tscm->mutex);
124 tscm->substreams_counter++;
125 mutex_unlock(&tscm->mutex);
128 amdtp_tscm_set_pcm_format(&tscm->tx_stream, params_format(hw_params));
130 return 0;
133 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
134 struct snd_pcm_hw_params *hw_params)
136 struct snd_tscm *tscm = substream->private_data;
137 int err;
139 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
140 params_buffer_bytes(hw_params));
141 if (err < 0)
142 return err;
144 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
145 mutex_lock(&tscm->mutex);
146 tscm->substreams_counter++;
147 mutex_unlock(&tscm->mutex);
150 amdtp_tscm_set_pcm_format(&tscm->rx_stream, params_format(hw_params));
152 return 0;
155 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
157 struct snd_tscm *tscm = substream->private_data;
159 mutex_lock(&tscm->mutex);
161 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
162 tscm->substreams_counter--;
164 snd_tscm_stream_stop_duplex(tscm);
166 mutex_unlock(&tscm->mutex);
168 return snd_pcm_lib_free_vmalloc_buffer(substream);
171 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
173 struct snd_tscm *tscm = substream->private_data;
175 mutex_lock(&tscm->mutex);
177 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
178 tscm->substreams_counter--;
180 snd_tscm_stream_stop_duplex(tscm);
182 mutex_unlock(&tscm->mutex);
184 return snd_pcm_lib_free_vmalloc_buffer(substream);
187 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
189 struct snd_tscm *tscm = substream->private_data;
190 struct snd_pcm_runtime *runtime = substream->runtime;
191 int err;
193 mutex_lock(&tscm->mutex);
195 err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
196 if (err >= 0)
197 amdtp_stream_pcm_prepare(&tscm->tx_stream);
199 mutex_unlock(&tscm->mutex);
201 return err;
204 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
206 struct snd_tscm *tscm = substream->private_data;
207 struct snd_pcm_runtime *runtime = substream->runtime;
208 int err;
210 mutex_lock(&tscm->mutex);
212 err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
213 if (err >= 0)
214 amdtp_stream_pcm_prepare(&tscm->rx_stream);
216 mutex_unlock(&tscm->mutex);
218 return err;
221 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
223 struct snd_tscm *tscm = substream->private_data;
225 switch (cmd) {
226 case SNDRV_PCM_TRIGGER_START:
227 amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
228 break;
229 case SNDRV_PCM_TRIGGER_STOP:
230 amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
231 break;
232 default:
233 return -EINVAL;
236 return 0;
239 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
241 struct snd_tscm *tscm = substream->private_data;
243 switch (cmd) {
244 case SNDRV_PCM_TRIGGER_START:
245 amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
246 break;
247 case SNDRV_PCM_TRIGGER_STOP:
248 amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
249 break;
250 default:
251 return -EINVAL;
254 return 0;
257 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
259 struct snd_tscm *tscm = sbstrm->private_data;
261 return amdtp_stream_pcm_pointer(&tscm->tx_stream);
264 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
266 struct snd_tscm *tscm = sbstrm->private_data;
268 return amdtp_stream_pcm_pointer(&tscm->rx_stream);
271 static struct snd_pcm_ops pcm_capture_ops = {
272 .open = pcm_open,
273 .close = pcm_close,
274 .ioctl = snd_pcm_lib_ioctl,
275 .hw_params = pcm_capture_hw_params,
276 .hw_free = pcm_capture_hw_free,
277 .prepare = pcm_capture_prepare,
278 .trigger = pcm_capture_trigger,
279 .pointer = pcm_capture_pointer,
280 .page = snd_pcm_lib_get_vmalloc_page,
283 static struct snd_pcm_ops pcm_playback_ops = {
284 .open = pcm_open,
285 .close = pcm_close,
286 .ioctl = snd_pcm_lib_ioctl,
287 .hw_params = pcm_playback_hw_params,
288 .hw_free = pcm_playback_hw_free,
289 .prepare = pcm_playback_prepare,
290 .trigger = pcm_playback_trigger,
291 .pointer = pcm_playback_pointer,
292 .page = snd_pcm_lib_get_vmalloc_page,
293 .mmap = snd_pcm_lib_mmap_vmalloc,
296 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
298 struct snd_pcm *pcm;
299 int err;
301 err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
302 if (err < 0)
303 return err;
305 pcm->private_data = tscm;
306 snprintf(pcm->name, sizeof(pcm->name),
307 "%s PCM", tscm->card->shortname);
308 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
309 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
311 return 0;