GNU Linux-libre 4.19.286-gnu1
[releases.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 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 (err < 0)
61                 goto err_locked;
62
63         if (clock != SND_TSCM_CLOCK_INTERNAL ||
64             amdtp_stream_pcm_running(&tscm->rx_stream) ||
65             amdtp_stream_pcm_running(&tscm->tx_stream)) {
66                 err = snd_tscm_stream_get_rate(tscm, &rate);
67                 if (err < 0)
68                         goto err_locked;
69                 substream->runtime->hw.rate_min = rate;
70                 substream->runtime->hw.rate_max = rate;
71         }
72
73         snd_pcm_set_sync(substream);
74 end:
75         return err;
76 err_locked:
77         snd_tscm_stream_lock_release(tscm);
78         return err;
79 }
80
81 static int pcm_close(struct snd_pcm_substream *substream)
82 {
83         struct snd_tscm *tscm = substream->private_data;
84
85         snd_tscm_stream_lock_release(tscm);
86
87         return 0;
88 }
89
90 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
91                                  struct snd_pcm_hw_params *hw_params)
92 {
93         struct snd_tscm *tscm = substream->private_data;
94         int err;
95
96         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
97                                                params_buffer_bytes(hw_params));
98         if (err < 0)
99                 return err;
100
101         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
102                 mutex_lock(&tscm->mutex);
103                 tscm->substreams_counter++;
104                 mutex_unlock(&tscm->mutex);
105         }
106
107         return 0;
108 }
109
110 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
111                                   struct snd_pcm_hw_params *hw_params)
112 {
113         struct snd_tscm *tscm = substream->private_data;
114         int err;
115
116         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
117                                                params_buffer_bytes(hw_params));
118         if (err < 0)
119                 return err;
120
121         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
122                 mutex_lock(&tscm->mutex);
123                 tscm->substreams_counter++;
124                 mutex_unlock(&tscm->mutex);
125         }
126
127         return 0;
128 }
129
130 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
131 {
132         struct snd_tscm *tscm = substream->private_data;
133
134         mutex_lock(&tscm->mutex);
135
136         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
137                 tscm->substreams_counter--;
138
139         snd_tscm_stream_stop_duplex(tscm);
140
141         mutex_unlock(&tscm->mutex);
142
143         return snd_pcm_lib_free_vmalloc_buffer(substream);
144 }
145
146 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
147 {
148         struct snd_tscm *tscm = substream->private_data;
149
150         mutex_lock(&tscm->mutex);
151
152         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
153                 tscm->substreams_counter--;
154
155         snd_tscm_stream_stop_duplex(tscm);
156
157         mutex_unlock(&tscm->mutex);
158
159         return snd_pcm_lib_free_vmalloc_buffer(substream);
160 }
161
162 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
163 {
164         struct snd_tscm *tscm = substream->private_data;
165         struct snd_pcm_runtime *runtime = substream->runtime;
166         int err;
167
168         mutex_lock(&tscm->mutex);
169
170         err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
171         if (err >= 0)
172                 amdtp_stream_pcm_prepare(&tscm->tx_stream);
173
174         mutex_unlock(&tscm->mutex);
175
176         return err;
177 }
178
179 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
180 {
181         struct snd_tscm *tscm = substream->private_data;
182         struct snd_pcm_runtime *runtime = substream->runtime;
183         int err;
184
185         mutex_lock(&tscm->mutex);
186
187         err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
188         if (err >= 0)
189                 amdtp_stream_pcm_prepare(&tscm->rx_stream);
190
191         mutex_unlock(&tscm->mutex);
192
193         return err;
194 }
195
196 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
197 {
198         struct snd_tscm *tscm = substream->private_data;
199
200         switch (cmd) {
201         case SNDRV_PCM_TRIGGER_START:
202                 amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
203                 break;
204         case SNDRV_PCM_TRIGGER_STOP:
205                 amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
206                 break;
207         default:
208                 return -EINVAL;
209         }
210
211         return 0;
212 }
213
214 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
215 {
216         struct snd_tscm *tscm = substream->private_data;
217
218         switch (cmd) {
219         case SNDRV_PCM_TRIGGER_START:
220                 amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
221                 break;
222         case SNDRV_PCM_TRIGGER_STOP:
223                 amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
224                 break;
225         default:
226                 return -EINVAL;
227         }
228
229         return 0;
230 }
231
232 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
233 {
234         struct snd_tscm *tscm = sbstrm->private_data;
235
236         return amdtp_stream_pcm_pointer(&tscm->tx_stream);
237 }
238
239 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
240 {
241         struct snd_tscm *tscm = sbstrm->private_data;
242
243         return amdtp_stream_pcm_pointer(&tscm->rx_stream);
244 }
245
246 static int pcm_capture_ack(struct snd_pcm_substream *substream)
247 {
248         struct snd_tscm *tscm = substream->private_data;
249
250         return amdtp_stream_pcm_ack(&tscm->tx_stream);
251 }
252
253 static int pcm_playback_ack(struct snd_pcm_substream *substream)
254 {
255         struct snd_tscm *tscm = substream->private_data;
256
257         return amdtp_stream_pcm_ack(&tscm->rx_stream);
258 }
259
260 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
261 {
262         static const struct snd_pcm_ops capture_ops = {
263                 .open           = pcm_open,
264                 .close          = pcm_close,
265                 .ioctl          = snd_pcm_lib_ioctl,
266                 .hw_params      = pcm_capture_hw_params,
267                 .hw_free        = pcm_capture_hw_free,
268                 .prepare        = pcm_capture_prepare,
269                 .trigger        = pcm_capture_trigger,
270                 .pointer        = pcm_capture_pointer,
271                 .ack            = pcm_capture_ack,
272                 .page           = snd_pcm_lib_get_vmalloc_page,
273         };
274         static const struct snd_pcm_ops playback_ops = {
275                 .open           = pcm_open,
276                 .close          = pcm_close,
277                 .ioctl          = snd_pcm_lib_ioctl,
278                 .hw_params      = pcm_playback_hw_params,
279                 .hw_free        = pcm_playback_hw_free,
280                 .prepare        = pcm_playback_prepare,
281                 .trigger        = pcm_playback_trigger,
282                 .pointer        = pcm_playback_pointer,
283                 .ack            = pcm_playback_ack,
284                 .page           = snd_pcm_lib_get_vmalloc_page,
285         };
286         struct snd_pcm *pcm;
287         int err;
288
289         err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
290         if (err < 0)
291                 return err;
292
293         pcm->private_data = tscm;
294         snprintf(pcm->name, sizeof(pcm->name),
295                  "%s PCM", tscm->card->shortname);
296         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
297         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
298
299         return 0;
300 }