Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / sound / firewire / bebob / bebob_pcm.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * bebob_pcm.c - a part of driver for BeBoB based devices
4  *
5  * Copyright (c) 2013-2014 Takashi Sakamoto
6  */
7
8 #include "./bebob.h"
9
10 static int
11 hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
12 {
13         struct snd_bebob_stream_formation *formations = rule->private;
14         struct snd_interval *r =
15                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
16         const struct snd_interval *c =
17                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
18         struct snd_interval t = {
19                 .min = UINT_MAX, .max = 0, .integer = 1
20         };
21         unsigned int i;
22
23         for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
24                 /* entry is invalid */
25                 if (formations[i].pcm == 0)
26                         continue;
27
28                 if (!snd_interval_test(c, formations[i].pcm))
29                         continue;
30
31                 t.min = min(t.min, snd_bebob_rate_table[i]);
32                 t.max = max(t.max, snd_bebob_rate_table[i]);
33
34         }
35         return snd_interval_refine(r, &t);
36 }
37
38 static int
39 hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
40 {
41         struct snd_bebob_stream_formation *formations = rule->private;
42         struct snd_interval *c =
43                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
44         const struct snd_interval *r =
45                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
46         struct snd_interval t = {
47                 .min = UINT_MAX, .max = 0, .integer = 1
48         };
49
50         unsigned int i;
51
52         for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
53                 /* entry is invalid */
54                 if (formations[i].pcm == 0)
55                         continue;
56
57                 if (!snd_interval_test(r, snd_bebob_rate_table[i]))
58                         continue;
59
60                 t.min = min(t.min, formations[i].pcm);
61                 t.max = max(t.max, formations[i].pcm);
62         }
63
64         return snd_interval_refine(c, &t);
65 }
66
67 static void
68 limit_channels_and_rates(struct snd_pcm_hardware *hw,
69                          struct snd_bebob_stream_formation *formations)
70 {
71         unsigned int i;
72
73         hw->channels_min = UINT_MAX;
74         hw->channels_max = 0;
75
76         hw->rate_min = UINT_MAX;
77         hw->rate_max = 0;
78         hw->rates = 0;
79
80         for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
81                 /* entry has no PCM channels */
82                 if (formations[i].pcm == 0)
83                         continue;
84
85                 hw->channels_min = min(hw->channels_min, formations[i].pcm);
86                 hw->channels_max = max(hw->channels_max, formations[i].pcm);
87
88                 hw->rate_min = min(hw->rate_min, snd_bebob_rate_table[i]);
89                 hw->rate_max = max(hw->rate_max, snd_bebob_rate_table[i]);
90                 hw->rates |= snd_pcm_rate_to_rate_bit(snd_bebob_rate_table[i]);
91         }
92 }
93
94 static int
95 pcm_init_hw_params(struct snd_bebob *bebob,
96                    struct snd_pcm_substream *substream)
97 {
98         struct snd_pcm_runtime *runtime = substream->runtime;
99         struct amdtp_stream *s;
100         struct snd_bebob_stream_formation *formations;
101         int err;
102
103         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
104                 runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
105                 s = &bebob->tx_stream;
106                 formations = bebob->tx_stream_formations;
107         } else {
108                 runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
109                 s = &bebob->rx_stream;
110                 formations = bebob->rx_stream_formations;
111         }
112
113         limit_channels_and_rates(&runtime->hw, formations);
114
115         err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
116                                   hw_rule_channels, formations,
117                                   SNDRV_PCM_HW_PARAM_RATE, -1);
118         if (err < 0)
119                 goto end;
120
121         err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
122                                   hw_rule_rate, formations,
123                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
124         if (err < 0)
125                 goto end;
126
127         err = amdtp_am824_add_pcm_hw_constraints(s, runtime);
128 end:
129         return err;
130 }
131
132 static int
133 pcm_open(struct snd_pcm_substream *substream)
134 {
135         struct snd_bebob *bebob = substream->private_data;
136         const struct snd_bebob_rate_spec *spec = bebob->spec->rate;
137         unsigned int sampling_rate;
138         enum snd_bebob_clock_type src;
139         int err;
140
141         err = snd_bebob_stream_lock_try(bebob);
142         if (err < 0)
143                 goto end;
144
145         err = pcm_init_hw_params(bebob, substream);
146         if (err < 0)
147                 goto err_locked;
148
149         err = snd_bebob_stream_get_clock_src(bebob, &src);
150         if (err < 0)
151                 goto err_locked;
152
153         /*
154          * When source of clock is internal or any PCM stream are running,
155          * the available sampling rate is limited at current sampling rate.
156          */
157         if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
158             amdtp_stream_pcm_running(&bebob->tx_stream) ||
159             amdtp_stream_pcm_running(&bebob->rx_stream)) {
160                 err = spec->get(bebob, &sampling_rate);
161                 if (err < 0) {
162                         dev_err(&bebob->unit->device,
163                                 "fail to get sampling rate: %d\n", err);
164                         goto err_locked;
165                 }
166
167                 substream->runtime->hw.rate_min = sampling_rate;
168                 substream->runtime->hw.rate_max = sampling_rate;
169         }
170
171         snd_pcm_set_sync(substream);
172 end:
173         return err;
174 err_locked:
175         snd_bebob_stream_lock_release(bebob);
176         return err;
177 }
178
179 static int
180 pcm_close(struct snd_pcm_substream *substream)
181 {
182         struct snd_bebob *bebob = substream->private_data;
183         snd_bebob_stream_lock_release(bebob);
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_bebob *bebob = substream->private_data;
191         int err;
192
193         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
194                                                params_buffer_bytes(hw_params));
195         if (err < 0)
196                 return err;
197
198         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
199                 unsigned int rate = params_rate(hw_params);
200
201                 mutex_lock(&bebob->mutex);
202                 err = snd_bebob_stream_reserve_duplex(bebob, rate);
203                 if (err >= 0)
204                         ++bebob->substreams_counter;
205                 mutex_unlock(&bebob->mutex);
206         }
207
208         return err;
209 }
210
211 static int pcm_hw_free(struct snd_pcm_substream *substream)
212 {
213         struct snd_bebob *bebob = substream->private_data;
214
215         mutex_lock(&bebob->mutex);
216
217         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
218                 bebob->substreams_counter--;
219
220         snd_bebob_stream_stop_duplex(bebob);
221
222         mutex_unlock(&bebob->mutex);
223
224         return snd_pcm_lib_free_vmalloc_buffer(substream);
225 }
226
227 static int
228 pcm_capture_prepare(struct snd_pcm_substream *substream)
229 {
230         struct snd_bebob *bebob = substream->private_data;
231         int err;
232
233         err = snd_bebob_stream_start_duplex(bebob);
234         if (err >= 0)
235                 amdtp_stream_pcm_prepare(&bebob->tx_stream);
236
237         return err;
238 }
239 static int
240 pcm_playback_prepare(struct snd_pcm_substream *substream)
241 {
242         struct snd_bebob *bebob = substream->private_data;
243         int err;
244
245         err = snd_bebob_stream_start_duplex(bebob);
246         if (err >= 0)
247                 amdtp_stream_pcm_prepare(&bebob->rx_stream);
248
249         return err;
250 }
251
252 static int
253 pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
254 {
255         struct snd_bebob *bebob = substream->private_data;
256
257         switch (cmd) {
258         case SNDRV_PCM_TRIGGER_START:
259                 amdtp_stream_pcm_trigger(&bebob->tx_stream, substream);
260                 break;
261         case SNDRV_PCM_TRIGGER_STOP:
262                 amdtp_stream_pcm_trigger(&bebob->tx_stream, NULL);
263                 break;
264         default:
265                 return -EINVAL;
266         }
267
268         return 0;
269 }
270 static int
271 pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
272 {
273         struct snd_bebob *bebob = substream->private_data;
274
275         switch (cmd) {
276         case SNDRV_PCM_TRIGGER_START:
277                 amdtp_stream_pcm_trigger(&bebob->rx_stream, substream);
278                 break;
279         case SNDRV_PCM_TRIGGER_STOP:
280                 amdtp_stream_pcm_trigger(&bebob->rx_stream, NULL);
281                 break;
282         default:
283                 return -EINVAL;
284         }
285
286         return 0;
287 }
288
289 static snd_pcm_uframes_t
290 pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
291 {
292         struct snd_bebob *bebob = sbstrm->private_data;
293         return amdtp_stream_pcm_pointer(&bebob->tx_stream);
294 }
295 static snd_pcm_uframes_t
296 pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
297 {
298         struct snd_bebob *bebob = sbstrm->private_data;
299         return amdtp_stream_pcm_pointer(&bebob->rx_stream);
300 }
301
302 static int pcm_capture_ack(struct snd_pcm_substream *substream)
303 {
304         struct snd_bebob *bebob = substream->private_data;
305
306         return amdtp_stream_pcm_ack(&bebob->tx_stream);
307 }
308
309 static int pcm_playback_ack(struct snd_pcm_substream *substream)
310 {
311         struct snd_bebob *bebob = substream->private_data;
312
313         return amdtp_stream_pcm_ack(&bebob->rx_stream);
314 }
315
316 int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
317 {
318         static const struct snd_pcm_ops capture_ops = {
319                 .open           = pcm_open,
320                 .close          = pcm_close,
321                 .ioctl          = snd_pcm_lib_ioctl,
322                 .hw_params      = pcm_hw_params,
323                 .hw_free        = pcm_hw_free,
324                 .prepare        = pcm_capture_prepare,
325                 .trigger        = pcm_capture_trigger,
326                 .pointer        = pcm_capture_pointer,
327                 .ack            = pcm_capture_ack,
328                 .page           = snd_pcm_lib_get_vmalloc_page,
329         };
330         static const struct snd_pcm_ops playback_ops = {
331                 .open           = pcm_open,
332                 .close          = pcm_close,
333                 .ioctl          = snd_pcm_lib_ioctl,
334                 .hw_params      = pcm_hw_params,
335                 .hw_free        = pcm_hw_free,
336                 .prepare        = pcm_playback_prepare,
337                 .trigger        = pcm_playback_trigger,
338                 .pointer        = pcm_playback_pointer,
339                 .ack            = pcm_playback_ack,
340                 .page           = snd_pcm_lib_get_vmalloc_page,
341         };
342         struct snd_pcm *pcm;
343         int err;
344
345         err = snd_pcm_new(bebob->card, bebob->card->driver, 0, 1, 1, &pcm);
346         if (err < 0)
347                 goto end;
348
349         pcm->private_data = bebob;
350         snprintf(pcm->name, sizeof(pcm->name),
351                  "%s PCM", bebob->card->shortname);
352         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
353         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
354 end:
355         return err;
356 }