]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/firewire/fireface/ff-pcm.c
93cee1978e8e36f72f87d2ac5b3083c62e4c71b8
[karo-tx-linux.git] / sound / firewire / fireface / ff-pcm.c
1 /*
2  * ff-pcm.c - a part of driver for RME Fireface series
3  *
4  * Copyright (c) 2015-2017 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8
9 #include "ff.h"
10
11 static inline unsigned int get_multiplier_mode_with_index(unsigned int index)
12 {
13         return ((int)index - 1) / 2;
14 }
15
16 static int hw_rule_rate(struct snd_pcm_hw_params *params,
17                         struct snd_pcm_hw_rule *rule)
18 {
19         const unsigned int *pcm_channels = rule->private;
20         struct snd_interval *r =
21                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
22         const struct snd_interval *c =
23                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
24         struct snd_interval t = {
25                 .min = UINT_MAX, .max = 0, .integer = 1
26         };
27         unsigned int i, mode;
28
29         for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
30                 mode = get_multiplier_mode_with_index(i);
31                 if (!snd_interval_test(c, pcm_channels[mode]))
32                         continue;
33
34                 t.min = min(t.min, amdtp_rate_table[i]);
35                 t.max = max(t.max, amdtp_rate_table[i]);
36         }
37
38         return snd_interval_refine(r, &t);
39 }
40
41 static int hw_rule_channels(struct snd_pcm_hw_params *params,
42                             struct snd_pcm_hw_rule *rule)
43 {
44         const unsigned int *pcm_channels = rule->private;
45         struct snd_interval *c =
46                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
47         const struct snd_interval *r =
48                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
49         struct snd_interval t = {
50                 .min = UINT_MAX, .max = 0, .integer = 1
51         };
52         unsigned int i, mode;
53
54         for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
55                 mode = get_multiplier_mode_with_index(i);
56                 if (!snd_interval_test(r, amdtp_rate_table[i]))
57                         continue;
58
59                 t.min = min(t.min, pcm_channels[mode]);
60                 t.max = max(t.max, pcm_channels[mode]);
61         }
62
63         return snd_interval_refine(c, &t);
64 }
65
66 static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
67                                      const unsigned int *pcm_channels)
68 {
69         unsigned int mode;
70         unsigned int rate, channels;
71         int i;
72
73         hw->channels_min = UINT_MAX;
74         hw->channels_max = 0;
75         hw->rate_min = UINT_MAX;
76         hw->rate_max = 0;
77
78         for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
79                 mode = get_multiplier_mode_with_index(i);
80
81                 channels = pcm_channels[mode];
82                 if (pcm_channels[mode] == 0)
83                         continue;
84                 hw->channels_min = min(hw->channels_min, channels);
85                 hw->channels_max = max(hw->channels_max, channels);
86
87                 rate = amdtp_rate_table[i];
88                 hw->rates |= snd_pcm_rate_to_rate_bit(rate);
89                 hw->rate_min = min(hw->rate_min, rate);
90                 hw->rate_max = max(hw->rate_max, rate);
91         }
92 }
93
94 static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
95 {
96         hw->periods_min = 2;            /* SNDRV_PCM_INFO_BATCH */
97         hw->periods_max = UINT_MAX;
98
99         hw->period_bytes_min = 4 * hw->channels_max;    /* bytes for a frame */
100
101         /* Just to prevent from allocating much pages. */
102         hw->period_bytes_max = hw->period_bytes_min * 2048;
103         hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
104 }
105
106 static int pcm_init_hw_params(struct snd_ff *ff,
107                               struct snd_pcm_substream *substream)
108 {
109         struct snd_pcm_runtime *runtime = substream->runtime;
110         struct amdtp_stream *s;
111         const unsigned int *pcm_channels;
112         int err;
113
114         runtime->hw.info = SNDRV_PCM_INFO_BATCH |
115                            SNDRV_PCM_INFO_BLOCK_TRANSFER |
116                            SNDRV_PCM_INFO_INTERLEAVED |
117                            SNDRV_PCM_INFO_JOINT_DUPLEX |
118                            SNDRV_PCM_INFO_MMAP |
119                            SNDRV_PCM_INFO_MMAP_VALID;
120
121         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
122                 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
123                 s = &ff->tx_stream;
124                 pcm_channels = ff->spec->pcm_capture_channels;
125         } else {
126                 runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
127                 s = &ff->rx_stream;
128                 pcm_channels = ff->spec->pcm_playback_channels;
129         }
130
131         /* limit rates */
132         limit_channels_and_rates(&runtime->hw, pcm_channels);
133         limit_period_and_buffer(&runtime->hw);
134
135         err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
136                                   hw_rule_channels, (void *)pcm_channels,
137                                   SNDRV_PCM_HW_PARAM_RATE, -1);
138         if (err < 0)
139                 return err;
140
141         err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
142                                   hw_rule_rate, (void *)pcm_channels,
143                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
144         if (err < 0)
145                 return err;
146
147         return amdtp_ff_add_pcm_hw_constraints(s, runtime);
148 }
149
150 static int pcm_open(struct snd_pcm_substream *substream)
151 {
152         struct snd_ff *ff = substream->private_data;
153         unsigned int rate;
154         enum snd_ff_clock_src src;
155         int i, err;
156
157         err = snd_ff_stream_lock_try(ff);
158         if (err < 0)
159                 return err;
160
161         err = pcm_init_hw_params(ff, substream);
162         if (err < 0) {
163                 snd_ff_stream_lock_release(ff);
164                 return err;
165         }
166
167         err = ff->spec->protocol->get_clock(ff, &rate, &src);
168         if (err < 0) {
169                 snd_ff_stream_lock_release(ff);
170                 return err;
171         }
172
173         if (src != SND_FF_CLOCK_SRC_INTERNAL) {
174                 for (i = 0; i < CIP_SFC_COUNT; ++i) {
175                         if (amdtp_rate_table[i] == rate)
176                                 break;
177                 }
178                 /*
179                  * The unit is configured at sampling frequency which packet
180                  * streaming engine can't support.
181                  */
182                 if (i >= CIP_SFC_COUNT) {
183                         snd_ff_stream_lock_release(ff);
184                         return -EIO;
185                 }
186
187                 substream->runtime->hw.rate_min = rate;
188                 substream->runtime->hw.rate_max = rate;
189         } else {
190                 if (amdtp_stream_pcm_running(&ff->rx_stream) ||
191                     amdtp_stream_pcm_running(&ff->tx_stream)) {
192                         rate = amdtp_rate_table[ff->rx_stream.sfc];
193                         substream->runtime->hw.rate_min = rate;
194                         substream->runtime->hw.rate_max = rate;
195                 }
196         }
197
198         snd_pcm_set_sync(substream);
199
200         return 0;
201 }
202
203 static int pcm_close(struct snd_pcm_substream *substream)
204 {
205         struct snd_ff *ff = substream->private_data;
206
207         snd_ff_stream_lock_release(ff);
208
209         return 0;
210 }
211
212 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
213                                  struct snd_pcm_hw_params *hw_params)
214 {
215         struct snd_ff *ff = substream->private_data;
216         int err;
217
218         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
219                                                params_buffer_bytes(hw_params));
220         if (err < 0)
221                 return err;
222
223         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
224                 mutex_lock(&ff->mutex);
225                 ff->substreams_counter++;
226                 mutex_unlock(&ff->mutex);
227         }
228
229         return 0;
230 }
231
232 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
233                                   struct snd_pcm_hw_params *hw_params)
234 {
235         struct snd_ff *ff = substream->private_data;
236         int err;
237
238         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
239                                                params_buffer_bytes(hw_params));
240         if (err < 0)
241                 return err;
242
243         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
244                 mutex_lock(&ff->mutex);
245                 ff->substreams_counter++;
246                 mutex_unlock(&ff->mutex);
247         }
248
249         return 0;
250 }
251
252 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
253 {
254         struct snd_ff *ff = substream->private_data;
255
256         mutex_lock(&ff->mutex);
257
258         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
259                 ff->substreams_counter--;
260
261         snd_ff_stream_stop_duplex(ff);
262
263         mutex_unlock(&ff->mutex);
264
265         return snd_pcm_lib_free_vmalloc_buffer(substream);
266 }
267
268 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
269 {
270         struct snd_ff *ff = substream->private_data;
271
272         mutex_lock(&ff->mutex);
273
274         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
275                 ff->substreams_counter--;
276
277         snd_ff_stream_stop_duplex(ff);
278
279         mutex_unlock(&ff->mutex);
280
281         return snd_pcm_lib_free_vmalloc_buffer(substream);
282 }
283
284 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
285 {
286         struct snd_ff *ff = substream->private_data;
287         struct snd_pcm_runtime *runtime = substream->runtime;
288         int err;
289
290         mutex_lock(&ff->mutex);
291
292         err = snd_ff_stream_start_duplex(ff, runtime->rate);
293         if (err >= 0)
294                 amdtp_stream_pcm_prepare(&ff->tx_stream);
295
296         mutex_unlock(&ff->mutex);
297
298         return err;
299 }
300
301 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
302 {
303         struct snd_ff *ff = substream->private_data;
304         struct snd_pcm_runtime *runtime = substream->runtime;
305         int err;
306
307         mutex_lock(&ff->mutex);
308
309         err = snd_ff_stream_start_duplex(ff, runtime->rate);
310         if (err >= 0)
311                 amdtp_stream_pcm_prepare(&ff->rx_stream);
312
313         mutex_unlock(&ff->mutex);
314
315         return err;
316 }
317
318 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
319 {
320         struct snd_ff *ff = substream->private_data;
321
322         switch (cmd) {
323         case SNDRV_PCM_TRIGGER_START:
324                 amdtp_stream_pcm_trigger(&ff->tx_stream, substream);
325                 break;
326         case SNDRV_PCM_TRIGGER_STOP:
327                 amdtp_stream_pcm_trigger(&ff->tx_stream, NULL);
328                 break;
329         default:
330                 return -EINVAL;
331         }
332
333         return 0;
334 }
335
336 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
337 {
338         struct snd_ff *ff = substream->private_data;
339
340         switch (cmd) {
341         case SNDRV_PCM_TRIGGER_START:
342                 amdtp_stream_pcm_trigger(&ff->rx_stream, substream);
343                 break;
344         case SNDRV_PCM_TRIGGER_STOP:
345                 amdtp_stream_pcm_trigger(&ff->rx_stream, NULL);
346                 break;
347         default:
348                 return -EINVAL;
349         }
350
351         return 0;
352 }
353
354 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
355 {
356         struct snd_ff *ff = sbstrm->private_data;
357
358         return amdtp_stream_pcm_pointer(&ff->tx_stream);
359 }
360
361 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
362 {
363         struct snd_ff *ff = sbstrm->private_data;
364
365         return amdtp_stream_pcm_pointer(&ff->rx_stream);
366 }
367
368 static struct snd_pcm_ops pcm_capture_ops = {
369         .open           = pcm_open,
370         .close          = pcm_close,
371         .ioctl          = snd_pcm_lib_ioctl,
372         .hw_params      = pcm_capture_hw_params,
373         .hw_free        = pcm_capture_hw_free,
374         .prepare        = pcm_capture_prepare,
375         .trigger        = pcm_capture_trigger,
376         .pointer        = pcm_capture_pointer,
377         .page           = snd_pcm_lib_get_vmalloc_page,
378 };
379
380 static struct snd_pcm_ops pcm_playback_ops = {
381         .open           = pcm_open,
382         .close          = pcm_close,
383         .ioctl          = snd_pcm_lib_ioctl,
384         .hw_params      = pcm_playback_hw_params,
385         .hw_free        = pcm_playback_hw_free,
386         .prepare        = pcm_playback_prepare,
387         .trigger        = pcm_playback_trigger,
388         .pointer        = pcm_playback_pointer,
389         .page           = snd_pcm_lib_get_vmalloc_page,
390         .mmap           = snd_pcm_lib_mmap_vmalloc,
391 };
392
393 int snd_ff_create_pcm_devices(struct snd_ff *ff)
394 {
395         struct snd_pcm *pcm;
396         int err;
397
398         err = snd_pcm_new(ff->card, ff->card->driver, 0, 1, 1, &pcm);
399         if (err < 0)
400                 return err;
401
402         pcm->private_data = ff;
403         snprintf(pcm->name, sizeof(pcm->name),
404                  "%s PCM", ff->card->shortname);
405         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
406         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
407
408         return 0;
409 }