]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/firewire/tascam/tascam-pcm.c
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / sound / firewire / tascam / tascam-pcm.c
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 void set_buffer_params(struct snd_pcm_hardware *hw)
12 {
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;
16
17         hw->periods_min = 2;
18         hw->periods_max = UINT_MAX;
19 }
20
21 static int pcm_init_hw_params(struct snd_tscm *tscm,
22                               struct snd_pcm_substream *substream)
23 {
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,
39         };
40         struct snd_pcm_runtime *runtime = substream->runtime;
41         struct amdtp_stream *stream;
42         unsigned int pcm_channels;
43
44         runtime->hw = hardware;
45
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;
55         }
56
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;
62
63         set_buffer_params(&runtime->hw);
64
65         return amdtp_tscm_add_pcm_hw_constraints(stream, runtime);
66 }
67
68 static int pcm_open(struct snd_pcm_substream *substream)
69 {
70         struct snd_tscm *tscm = substream->private_data;
71         enum snd_tscm_clock clock;
72         unsigned int rate;
73         int err;
74
75         err = snd_tscm_stream_lock_try(tscm);
76         if (err < 0)
77                 goto end;
78
79         err = pcm_init_hw_params(tscm, substream);
80         if (err < 0)
81                 goto err_locked;
82
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;
92         }
93
94         snd_pcm_set_sync(substream);
95 end:
96         return err;
97 err_locked:
98         snd_tscm_stream_lock_release(tscm);
99         return err;
100 }
101
102 static int pcm_close(struct snd_pcm_substream *substream)
103 {
104         struct snd_tscm *tscm = substream->private_data;
105
106         snd_tscm_stream_lock_release(tscm);
107
108         return 0;
109 }
110
111 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
112                                  struct snd_pcm_hw_params *hw_params)
113 {
114         struct snd_tscm *tscm = substream->private_data;
115         int err;
116
117         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
118                                                params_buffer_bytes(hw_params));
119         if (err < 0)
120                 return err;
121
122         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
123                 mutex_lock(&tscm->mutex);
124                 tscm->substreams_counter++;
125                 mutex_unlock(&tscm->mutex);
126         }
127
128         amdtp_tscm_set_pcm_format(&tscm->tx_stream, params_format(hw_params));
129
130         return 0;
131 }
132
133 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
134                                   struct snd_pcm_hw_params *hw_params)
135 {
136         struct snd_tscm *tscm = substream->private_data;
137         int err;
138
139         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
140                                                params_buffer_bytes(hw_params));
141         if (err < 0)
142                 return err;
143
144         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
145                 mutex_lock(&tscm->mutex);
146                 tscm->substreams_counter++;
147                 mutex_unlock(&tscm->mutex);
148         }
149
150         amdtp_tscm_set_pcm_format(&tscm->rx_stream, params_format(hw_params));
151
152         return 0;
153 }
154
155 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
156 {
157         struct snd_tscm *tscm = substream->private_data;
158
159         mutex_lock(&tscm->mutex);
160
161         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
162                 tscm->substreams_counter--;
163
164         snd_tscm_stream_stop_duplex(tscm);
165
166         mutex_unlock(&tscm->mutex);
167
168         return snd_pcm_lib_free_vmalloc_buffer(substream);
169 }
170
171 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
172 {
173         struct snd_tscm *tscm = substream->private_data;
174
175         mutex_lock(&tscm->mutex);
176
177         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
178                 tscm->substreams_counter--;
179
180         snd_tscm_stream_stop_duplex(tscm);
181
182         mutex_unlock(&tscm->mutex);
183
184         return snd_pcm_lib_free_vmalloc_buffer(substream);
185 }
186
187 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
188 {
189         struct snd_tscm *tscm = substream->private_data;
190         struct snd_pcm_runtime *runtime = substream->runtime;
191         int err;
192
193         mutex_lock(&tscm->mutex);
194
195         err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
196         if (err >= 0)
197                 amdtp_stream_pcm_prepare(&tscm->tx_stream);
198
199         mutex_unlock(&tscm->mutex);
200
201         return err;
202 }
203
204 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
205 {
206         struct snd_tscm *tscm = substream->private_data;
207         struct snd_pcm_runtime *runtime = substream->runtime;
208         int err;
209
210         mutex_lock(&tscm->mutex);
211
212         err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
213         if (err >= 0)
214                 amdtp_stream_pcm_prepare(&tscm->rx_stream);
215
216         mutex_unlock(&tscm->mutex);
217
218         return err;
219 }
220
221 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
222 {
223         struct snd_tscm *tscm = substream->private_data;
224
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;
234         }
235
236         return 0;
237 }
238
239 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
240 {
241         struct snd_tscm *tscm = substream->private_data;
242
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;
252         }
253
254         return 0;
255 }
256
257 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
258 {
259         struct snd_tscm *tscm = sbstrm->private_data;
260
261         return amdtp_stream_pcm_pointer(&tscm->tx_stream);
262 }
263
264 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
265 {
266         struct snd_tscm *tscm = sbstrm->private_data;
267
268         return amdtp_stream_pcm_pointer(&tscm->rx_stream);
269 }
270
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,
281 };
282
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,
294 };
295
296 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
297 {
298         struct snd_pcm *pcm;
299         int err;
300
301         err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
302         if (err < 0)
303                 return err;
304
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);
310
311         return 0;
312 }