]> asedeno.scripts.mit.edu Git - linux.git/blob - sound/firewire/digi00x/digi00x-pcm.c
Merge branch 'next' into for-linus
[linux.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         struct amdtp_domain *d = &dg00x->domain;
104         enum snd_dg00x_clock clock;
105         bool detect;
106         int err;
107
108         err = snd_dg00x_stream_lock_try(dg00x);
109         if (err < 0)
110                 return err;
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         mutex_lock(&dg00x->mutex);
131
132         // When source of clock is not internal or any stream is reserved for
133         // transmission of PCM frames, the available sampling rate is limited
134         // at current one.
135         if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
136             (dg00x->substreams_counter > 0 && d->events_per_period > 0)) {
137                 unsigned int frames_per_period = d->events_per_period;
138                 unsigned int frames_per_buffer = d->events_per_buffer;
139                 unsigned int rate;
140
141                 err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
142                 if (err < 0) {
143                         mutex_unlock(&dg00x->mutex);
144                         goto err_locked;
145                 }
146                 substream->runtime->hw.rate_min = rate;
147                 substream->runtime->hw.rate_max = rate;
148
149                 if (frames_per_period > 0) {
150                         err = snd_pcm_hw_constraint_minmax(substream->runtime,
151                                         SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
152                                         frames_per_period, frames_per_period);
153                         if (err < 0) {
154                                 mutex_unlock(&dg00x->mutex);
155                                 goto err_locked;
156                         }
157
158                         err = snd_pcm_hw_constraint_minmax(substream->runtime,
159                                         SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
160                                         frames_per_buffer, frames_per_buffer);
161                         if (err < 0) {
162                                 mutex_unlock(&dg00x->mutex);
163                                 goto err_locked;
164                         }
165                 }
166         }
167
168         mutex_unlock(&dg00x->mutex);
169
170         snd_pcm_set_sync(substream);
171
172         return 0;
173 err_locked:
174         snd_dg00x_stream_lock_release(dg00x);
175         return err;
176 }
177
178 static int pcm_close(struct snd_pcm_substream *substream)
179 {
180         struct snd_dg00x *dg00x = substream->private_data;
181
182         snd_dg00x_stream_lock_release(dg00x);
183
184         return 0;
185 }
186
187 static int pcm_hw_params(struct snd_pcm_substream *substream,
188                          struct snd_pcm_hw_params *hw_params)
189 {
190         struct snd_dg00x *dg00x = substream->private_data;
191         int err;
192
193         err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
194         if (err < 0)
195                 return err;
196
197         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
198                 unsigned int rate = params_rate(hw_params);
199                 unsigned int frames_per_period = params_period_size(hw_params);
200                 unsigned int frames_per_buffer = params_buffer_size(hw_params);
201
202                 mutex_lock(&dg00x->mutex);
203                 err = snd_dg00x_stream_reserve_duplex(dg00x, rate,
204                                         frames_per_period, frames_per_buffer);
205                 if (err >= 0)
206                         ++dg00x->substreams_counter;
207                 mutex_unlock(&dg00x->mutex);
208         }
209
210         return err;
211 }
212
213 static int pcm_hw_free(struct snd_pcm_substream *substream)
214 {
215         struct snd_dg00x *dg00x = substream->private_data;
216
217         mutex_lock(&dg00x->mutex);
218
219         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
220                 --dg00x->substreams_counter;
221
222         snd_dg00x_stream_stop_duplex(dg00x);
223
224         mutex_unlock(&dg00x->mutex);
225
226         return snd_pcm_lib_free_pages(substream);
227 }
228
229 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
230 {
231         struct snd_dg00x *dg00x = substream->private_data;
232         int err;
233
234         mutex_lock(&dg00x->mutex);
235
236         err = snd_dg00x_stream_start_duplex(dg00x);
237         if (err >= 0)
238                 amdtp_stream_pcm_prepare(&dg00x->tx_stream);
239
240         mutex_unlock(&dg00x->mutex);
241
242         return err;
243 }
244
245 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
246 {
247         struct snd_dg00x *dg00x = substream->private_data;
248         int err;
249
250         mutex_lock(&dg00x->mutex);
251
252         err = snd_dg00x_stream_start_duplex(dg00x);
253         if (err >= 0) {
254                 amdtp_stream_pcm_prepare(&dg00x->rx_stream);
255                 amdtp_dot_reset(&dg00x->rx_stream);
256         }
257
258         mutex_unlock(&dg00x->mutex);
259
260         return err;
261 }
262
263 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
264 {
265         struct snd_dg00x *dg00x = substream->private_data;
266
267         switch (cmd) {
268         case SNDRV_PCM_TRIGGER_START:
269                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
270                 break;
271         case SNDRV_PCM_TRIGGER_STOP:
272                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
273                 break;
274         default:
275                 return -EINVAL;
276         }
277
278         return 0;
279 }
280
281 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
282 {
283         struct snd_dg00x *dg00x = substream->private_data;
284
285         switch (cmd) {
286         case SNDRV_PCM_TRIGGER_START:
287                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
288                 break;
289         case SNDRV_PCM_TRIGGER_STOP:
290                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
291                 break;
292         default:
293                 return -EINVAL;
294         }
295
296         return 0;
297 }
298
299 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
300 {
301         struct snd_dg00x *dg00x = sbstrm->private_data;
302
303         return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->tx_stream);
304 }
305
306 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
307 {
308         struct snd_dg00x *dg00x = sbstrm->private_data;
309
310         return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->rx_stream);
311 }
312
313 static int pcm_capture_ack(struct snd_pcm_substream *substream)
314 {
315         struct snd_dg00x *dg00x = substream->private_data;
316
317         return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->tx_stream);
318 }
319
320 static int pcm_playback_ack(struct snd_pcm_substream *substream)
321 {
322         struct snd_dg00x *dg00x = substream->private_data;
323
324         return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->rx_stream);
325 }
326
327 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
328 {
329         static const struct snd_pcm_ops capture_ops = {
330                 .open           = pcm_open,
331                 .close          = pcm_close,
332                 .ioctl          = snd_pcm_lib_ioctl,
333                 .hw_params      = pcm_hw_params,
334                 .hw_free        = pcm_hw_free,
335                 .prepare        = pcm_capture_prepare,
336                 .trigger        = pcm_capture_trigger,
337                 .pointer        = pcm_capture_pointer,
338                 .ack            = pcm_capture_ack,
339         };
340         static const struct snd_pcm_ops playback_ops = {
341                 .open           = pcm_open,
342                 .close          = pcm_close,
343                 .ioctl          = snd_pcm_lib_ioctl,
344                 .hw_params      = pcm_hw_params,
345                 .hw_free        = pcm_hw_free,
346                 .prepare        = pcm_playback_prepare,
347                 .trigger        = pcm_playback_trigger,
348                 .pointer        = pcm_playback_pointer,
349                 .ack            = pcm_playback_ack,
350         };
351         struct snd_pcm *pcm;
352         int err;
353
354         err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
355         if (err < 0)
356                 return err;
357
358         pcm->private_data = dg00x;
359         snprintf(pcm->name, sizeof(pcm->name),
360                  "%s PCM", dg00x->card->shortname);
361         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
362         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
363         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
364                                               NULL, 0, 0);
365
366         return 0;
367 }