9ced309d61facb9824fc3e0d49ad119e012110a8
[linux-2.6-block.git] / sound / firewire / digi00x / digi00x-pcm.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
4  *
5  * Copyright (c) 2014-2015 Takashi Sakamoto
6  */
7
8 #include "digi00x.h"
9
10 static int hw_rule_rate(struct snd_pcm_hw_params *params,
11                         struct snd_pcm_hw_rule *rule)
12 {
13         struct snd_interval *r =
14                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
15         const struct snd_interval *c =
16                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
17         struct snd_interval t = {
18                 .min = UINT_MAX, .max = 0, .integer = 1,
19         };
20         unsigned int i;
21
22         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
23                 if (!snd_interval_test(c,
24                                        snd_dg00x_stream_pcm_channels[i]))
25                         continue;
26
27                 t.min = min(t.min, snd_dg00x_stream_rates[i]);
28                 t.max = max(t.max, snd_dg00x_stream_rates[i]);
29         }
30
31         return snd_interval_refine(r, &t);
32 }
33
34 static int hw_rule_channels(struct snd_pcm_hw_params *params,
35                             struct snd_pcm_hw_rule *rule)
36 {
37         struct snd_interval *c =
38                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
39         const struct snd_interval *r =
40                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
41         struct snd_interval t = {
42                 .min = UINT_MAX, .max = 0, .integer = 1,
43         };
44         unsigned int i;
45
46         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
47                 if (!snd_interval_test(r, snd_dg00x_stream_rates[i]))
48                         continue;
49
50                 t.min = min(t.min, snd_dg00x_stream_pcm_channels[i]);
51                 t.max = max(t.max, snd_dg00x_stream_pcm_channels[i]);
52         }
53
54         return snd_interval_refine(c, &t);
55 }
56
57 static int pcm_init_hw_params(struct snd_dg00x *dg00x,
58                               struct snd_pcm_substream *substream)
59 {
60         struct snd_pcm_runtime *runtime = substream->runtime;
61         struct snd_pcm_hardware *hw = &runtime->hw;
62         struct amdtp_stream *s;
63         int err;
64
65
66         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
67                 substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
68                 s = &dg00x->tx_stream;
69         } else {
70                 substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
71                 s = &dg00x->rx_stream;
72         }
73
74         hw->channels_min = 10;
75         hw->channels_max = 18;
76
77         hw->rates = SNDRV_PCM_RATE_44100 |
78                     SNDRV_PCM_RATE_48000 |
79                     SNDRV_PCM_RATE_88200 |
80                     SNDRV_PCM_RATE_96000;
81         snd_pcm_limit_hw_rates(runtime);
82
83         err = snd_pcm_hw_rule_add(substream->runtime, 0,
84                                   SNDRV_PCM_HW_PARAM_CHANNELS,
85                                   hw_rule_channels, NULL,
86                                   SNDRV_PCM_HW_PARAM_RATE, -1);
87         if (err < 0)
88                 return err;
89
90         err = snd_pcm_hw_rule_add(substream->runtime, 0,
91                                   SNDRV_PCM_HW_PARAM_RATE,
92                                   hw_rule_rate, NULL,
93                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
94         if (err < 0)
95                 return err;
96
97         return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
98 }
99
100 static int pcm_open(struct snd_pcm_substream *substream)
101 {
102         struct snd_dg00x *dg00x = substream->private_data;
103         enum snd_dg00x_clock clock;
104         bool detect;
105         unsigned int rate;
106         int err;
107
108         err = snd_dg00x_stream_lock_try(dg00x);
109         if (err < 0)
110                 goto end;
111
112         err = pcm_init_hw_params(dg00x, substream);
113         if (err < 0)
114                 goto err_locked;
115
116         /* Check current clock source. */
117         err = snd_dg00x_stream_get_clock(dg00x, &clock);
118         if (err < 0)
119                 goto err_locked;
120         if (clock != SND_DG00X_CLOCK_INTERNAL) {
121                 err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
122                 if (err < 0)
123                         goto err_locked;
124                 if (!detect) {
125                         err = -EBUSY;
126                         goto err_locked;
127                 }
128         }
129
130         if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
131             amdtp_stream_pcm_running(&dg00x->rx_stream) ||
132             amdtp_stream_pcm_running(&dg00x->tx_stream)) {
133                 err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
134                 if (err < 0)
135                         goto err_locked;
136                 substream->runtime->hw.rate_min = rate;
137                 substream->runtime->hw.rate_max = rate;
138         }
139
140         snd_pcm_set_sync(substream);
141 end:
142         return err;
143 err_locked:
144         snd_dg00x_stream_lock_release(dg00x);
145         return err;
146 }
147
148 static int pcm_close(struct snd_pcm_substream *substream)
149 {
150         struct snd_dg00x *dg00x = substream->private_data;
151
152         snd_dg00x_stream_lock_release(dg00x);
153
154         return 0;
155 }
156
157 static int pcm_hw_params(struct snd_pcm_substream *substream,
158                          struct snd_pcm_hw_params *hw_params)
159 {
160         struct snd_dg00x *dg00x = substream->private_data;
161         int err;
162
163         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
164                                                params_buffer_bytes(hw_params));
165         if (err < 0)
166                 return err;
167
168         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
169                 unsigned int rate = params_rate(hw_params);
170                 unsigned int frames_per_period = params_period_size(hw_params);
171
172                 mutex_lock(&dg00x->mutex);
173                 err = snd_dg00x_stream_reserve_duplex(dg00x, rate,
174                                                       frames_per_period);
175                 if (err >= 0)
176                         ++dg00x->substreams_counter;
177                 mutex_unlock(&dg00x->mutex);
178         }
179
180         return err;
181 }
182
183 static int pcm_hw_free(struct snd_pcm_substream *substream)
184 {
185         struct snd_dg00x *dg00x = substream->private_data;
186
187         mutex_lock(&dg00x->mutex);
188
189         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
190                 --dg00x->substreams_counter;
191
192         snd_dg00x_stream_stop_duplex(dg00x);
193
194         mutex_unlock(&dg00x->mutex);
195
196         return snd_pcm_lib_free_vmalloc_buffer(substream);
197 }
198
199 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
200 {
201         struct snd_dg00x *dg00x = substream->private_data;
202         int err;
203
204         mutex_lock(&dg00x->mutex);
205
206         err = snd_dg00x_stream_start_duplex(dg00x);
207         if (err >= 0)
208                 amdtp_stream_pcm_prepare(&dg00x->tx_stream);
209
210         mutex_unlock(&dg00x->mutex);
211
212         return err;
213 }
214
215 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
216 {
217         struct snd_dg00x *dg00x = substream->private_data;
218         int err;
219
220         mutex_lock(&dg00x->mutex);
221
222         err = snd_dg00x_stream_start_duplex(dg00x);
223         if (err >= 0) {
224                 amdtp_stream_pcm_prepare(&dg00x->rx_stream);
225                 amdtp_dot_reset(&dg00x->rx_stream);
226         }
227
228         mutex_unlock(&dg00x->mutex);
229
230         return err;
231 }
232
233 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
234 {
235         struct snd_dg00x *dg00x = substream->private_data;
236
237         switch (cmd) {
238         case SNDRV_PCM_TRIGGER_START:
239                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
240                 break;
241         case SNDRV_PCM_TRIGGER_STOP:
242                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
243                 break;
244         default:
245                 return -EINVAL;
246         }
247
248         return 0;
249 }
250
251 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
252 {
253         struct snd_dg00x *dg00x = substream->private_data;
254
255         switch (cmd) {
256         case SNDRV_PCM_TRIGGER_START:
257                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
258                 break;
259         case SNDRV_PCM_TRIGGER_STOP:
260                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
261                 break;
262         default:
263                 return -EINVAL;
264         }
265
266         return 0;
267 }
268
269 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
270 {
271         struct snd_dg00x *dg00x = sbstrm->private_data;
272
273         return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
274 }
275
276 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
277 {
278         struct snd_dg00x *dg00x = sbstrm->private_data;
279
280         return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
281 }
282
283 static int pcm_capture_ack(struct snd_pcm_substream *substream)
284 {
285         struct snd_dg00x *dg00x = substream->private_data;
286
287         return amdtp_stream_pcm_ack(&dg00x->tx_stream);
288 }
289
290 static int pcm_playback_ack(struct snd_pcm_substream *substream)
291 {
292         struct snd_dg00x *dg00x = substream->private_data;
293
294         return amdtp_stream_pcm_ack(&dg00x->rx_stream);
295 }
296
297 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
298 {
299         static const struct snd_pcm_ops capture_ops = {
300                 .open           = pcm_open,
301                 .close          = pcm_close,
302                 .ioctl          = snd_pcm_lib_ioctl,
303                 .hw_params      = pcm_hw_params,
304                 .hw_free        = pcm_hw_free,
305                 .prepare        = pcm_capture_prepare,
306                 .trigger        = pcm_capture_trigger,
307                 .pointer        = pcm_capture_pointer,
308                 .ack            = pcm_capture_ack,
309                 .page           = snd_pcm_lib_get_vmalloc_page,
310         };
311         static const struct snd_pcm_ops playback_ops = {
312                 .open           = pcm_open,
313                 .close          = pcm_close,
314                 .ioctl          = snd_pcm_lib_ioctl,
315                 .hw_params      = pcm_hw_params,
316                 .hw_free        = pcm_hw_free,
317                 .prepare        = pcm_playback_prepare,
318                 .trigger        = pcm_playback_trigger,
319                 .pointer        = pcm_playback_pointer,
320                 .ack            = pcm_playback_ack,
321                 .page           = snd_pcm_lib_get_vmalloc_page,
322         };
323         struct snd_pcm *pcm;
324         int err;
325
326         err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
327         if (err < 0)
328                 return err;
329
330         pcm->private_data = dg00x;
331         snprintf(pcm->name, sizeof(pcm->name),
332                  "%s PCM", dg00x->card->shortname);
333         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
334         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
335
336         return 0;
337 }