1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * dice_pcm.c - a part of driver for DICE based devices |
4 | * |
5 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> |
6 | * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> |
7 | */ |
8 | |
9 | #include "dice.h" |
10 | |
11 | static int dice_rate_constraint(struct snd_pcm_hw_params *params, |
12 | struct snd_pcm_hw_rule *rule) |
13 | { |
14 | struct snd_pcm_substream *substream = rule->private; |
15 | struct snd_dice *dice = substream->private_data; |
16 | unsigned int index = substream->pcm->device; |
17 | |
18 | const struct snd_interval *c = |
19 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
20 | struct snd_interval *r = |
21 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
22 | struct snd_interval rates = { |
23 | .min = UINT_MAX, .max = 0, .integer = 1 |
24 | }; |
25 | unsigned int *pcm_channels; |
26 | enum snd_dice_rate_mode mode; |
27 | unsigned int i, rate; |
28 | |
29 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
30 | pcm_channels = dice->tx_pcm_chs[index]; |
31 | else |
32 | pcm_channels = dice->rx_pcm_chs[index]; |
33 | |
34 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { |
35 | rate = snd_dice_rates[i]; |
36 | if (snd_dice_stream_get_rate_mode(dice, rate, mode: &mode) < 0) |
37 | continue; |
38 | |
39 | if (!snd_interval_test(i: c, val: pcm_channels[mode])) |
40 | continue; |
41 | |
42 | rates.min = min(rates.min, rate); |
43 | rates.max = max(rates.max, rate); |
44 | } |
45 | |
46 | return snd_interval_refine(i: r, v: &rates); |
47 | } |
48 | |
49 | static int dice_channels_constraint(struct snd_pcm_hw_params *params, |
50 | struct snd_pcm_hw_rule *rule) |
51 | { |
52 | struct snd_pcm_substream *substream = rule->private; |
53 | struct snd_dice *dice = substream->private_data; |
54 | unsigned int index = substream->pcm->device; |
55 | |
56 | const struct snd_interval *r = |
57 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); |
58 | struct snd_interval *c = |
59 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
60 | struct snd_interval channels = { |
61 | .min = UINT_MAX, .max = 0, .integer = 1 |
62 | }; |
63 | unsigned int *pcm_channels; |
64 | enum snd_dice_rate_mode mode; |
65 | unsigned int i, rate; |
66 | |
67 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
68 | pcm_channels = dice->tx_pcm_chs[index]; |
69 | else |
70 | pcm_channels = dice->rx_pcm_chs[index]; |
71 | |
72 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { |
73 | rate = snd_dice_rates[i]; |
74 | if (snd_dice_stream_get_rate_mode(dice, rate, mode: &mode) < 0) |
75 | continue; |
76 | |
77 | if (!snd_interval_test(i: r, val: rate)) |
78 | continue; |
79 | |
80 | channels.min = min(channels.min, pcm_channels[mode]); |
81 | channels.max = max(channels.max, pcm_channels[mode]); |
82 | } |
83 | |
84 | return snd_interval_refine(i: c, v: &channels); |
85 | } |
86 | |
87 | static int limit_channels_and_rates(struct snd_dice *dice, |
88 | struct snd_pcm_runtime *runtime, |
89 | enum amdtp_stream_direction dir, |
90 | unsigned int index) |
91 | { |
92 | struct snd_pcm_hardware *hw = &runtime->hw; |
93 | unsigned int *pcm_channels; |
94 | unsigned int i; |
95 | |
96 | if (dir == AMDTP_IN_STREAM) |
97 | pcm_channels = dice->tx_pcm_chs[index]; |
98 | else |
99 | pcm_channels = dice->rx_pcm_chs[index]; |
100 | |
101 | hw->channels_min = UINT_MAX; |
102 | hw->channels_max = 0; |
103 | |
104 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { |
105 | enum snd_dice_rate_mode mode; |
106 | unsigned int rate, channels; |
107 | |
108 | rate = snd_dice_rates[i]; |
109 | if (snd_dice_stream_get_rate_mode(dice, rate, mode: &mode) < 0) |
110 | continue; |
111 | hw->rates |= snd_pcm_rate_to_rate_bit(rate); |
112 | |
113 | channels = pcm_channels[mode]; |
114 | if (channels == 0) |
115 | continue; |
116 | hw->channels_min = min(hw->channels_min, channels); |
117 | hw->channels_max = max(hw->channels_max, channels); |
118 | } |
119 | |
120 | snd_pcm_limit_hw_rates(runtime); |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | static int init_hw_info(struct snd_dice *dice, |
126 | struct snd_pcm_substream *substream) |
127 | { |
128 | struct snd_pcm_runtime *runtime = substream->runtime; |
129 | struct snd_pcm_hardware *hw = &runtime->hw; |
130 | unsigned int index = substream->pcm->device; |
131 | enum amdtp_stream_direction dir; |
132 | struct amdtp_stream *stream; |
133 | int err; |
134 | |
135 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
136 | hw->formats = AM824_IN_PCM_FORMAT_BITS; |
137 | dir = AMDTP_IN_STREAM; |
138 | stream = &dice->tx_stream[index]; |
139 | } else { |
140 | hw->formats = AM824_OUT_PCM_FORMAT_BITS; |
141 | dir = AMDTP_OUT_STREAM; |
142 | stream = &dice->rx_stream[index]; |
143 | } |
144 | |
145 | err = limit_channels_and_rates(dice, runtime: substream->runtime, dir, |
146 | index); |
147 | if (err < 0) |
148 | return err; |
149 | |
150 | err = snd_pcm_hw_rule_add(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
151 | func: dice_rate_constraint, private: substream, |
152 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
153 | if (err < 0) |
154 | return err; |
155 | err = snd_pcm_hw_rule_add(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
156 | func: dice_channels_constraint, private: substream, |
157 | SNDRV_PCM_HW_PARAM_RATE, -1); |
158 | if (err < 0) |
159 | return err; |
160 | |
161 | return amdtp_am824_add_pcm_hw_constraints(s: stream, runtime); |
162 | } |
163 | |
164 | static int pcm_open(struct snd_pcm_substream *substream) |
165 | { |
166 | struct snd_dice *dice = substream->private_data; |
167 | struct amdtp_domain *d = &dice->domain; |
168 | unsigned int source; |
169 | bool internal; |
170 | int err; |
171 | |
172 | err = snd_dice_stream_lock_try(dice); |
173 | if (err < 0) |
174 | return err; |
175 | |
176 | err = init_hw_info(dice, substream); |
177 | if (err < 0) |
178 | goto err_locked; |
179 | |
180 | err = snd_dice_transaction_get_clock_source(dice, source: &source); |
181 | if (err < 0) |
182 | goto err_locked; |
183 | switch (source) { |
184 | case CLOCK_SOURCE_AES1: |
185 | case CLOCK_SOURCE_AES2: |
186 | case CLOCK_SOURCE_AES3: |
187 | case CLOCK_SOURCE_AES4: |
188 | case CLOCK_SOURCE_AES_ANY: |
189 | case CLOCK_SOURCE_ADAT: |
190 | case CLOCK_SOURCE_TDIF: |
191 | case CLOCK_SOURCE_WC: |
192 | internal = false; |
193 | break; |
194 | default: |
195 | internal = true; |
196 | break; |
197 | } |
198 | |
199 | mutex_lock(&dice->mutex); |
200 | |
201 | // When source of clock is not internal or any stream is reserved for |
202 | // transmission of PCM frames, the available sampling rate is limited |
203 | // at current one. |
204 | if (!internal || |
205 | (dice->substreams_counter > 0 && d->events_per_period > 0)) { |
206 | unsigned int frames_per_period = d->events_per_period; |
207 | unsigned int frames_per_buffer = d->events_per_buffer; |
208 | unsigned int rate; |
209 | |
210 | err = snd_dice_transaction_get_rate(dice, rate: &rate); |
211 | if (err < 0) { |
212 | mutex_unlock(lock: &dice->mutex); |
213 | goto err_locked; |
214 | } |
215 | |
216 | substream->runtime->hw.rate_min = rate; |
217 | substream->runtime->hw.rate_max = rate; |
218 | |
219 | if (frames_per_period > 0) { |
220 | // For double_pcm_frame quirk. |
221 | if (rate > 96000 && !dice->disable_double_pcm_frames) { |
222 | frames_per_period *= 2; |
223 | frames_per_buffer *= 2; |
224 | } |
225 | |
226 | err = snd_pcm_hw_constraint_minmax(runtime: substream->runtime, |
227 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
228 | min: frames_per_period, max: frames_per_period); |
229 | if (err < 0) { |
230 | mutex_unlock(lock: &dice->mutex); |
231 | goto err_locked; |
232 | } |
233 | |
234 | err = snd_pcm_hw_constraint_minmax(runtime: substream->runtime, |
235 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
236 | min: frames_per_buffer, max: frames_per_buffer); |
237 | if (err < 0) { |
238 | mutex_unlock(lock: &dice->mutex); |
239 | goto err_locked; |
240 | } |
241 | } |
242 | } |
243 | |
244 | mutex_unlock(lock: &dice->mutex); |
245 | |
246 | snd_pcm_set_sync(substream); |
247 | |
248 | return 0; |
249 | err_locked: |
250 | snd_dice_stream_lock_release(dice); |
251 | return err; |
252 | } |
253 | |
254 | static int pcm_close(struct snd_pcm_substream *substream) |
255 | { |
256 | struct snd_dice *dice = substream->private_data; |
257 | |
258 | snd_dice_stream_lock_release(dice); |
259 | |
260 | return 0; |
261 | } |
262 | |
263 | static int pcm_hw_params(struct snd_pcm_substream *substream, |
264 | struct snd_pcm_hw_params *hw_params) |
265 | { |
266 | struct snd_dice *dice = substream->private_data; |
267 | int err = 0; |
268 | |
269 | if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) { |
270 | unsigned int rate = params_rate(p: hw_params); |
271 | unsigned int events_per_period = params_period_size(p: hw_params); |
272 | unsigned int events_per_buffer = params_buffer_size(p: hw_params); |
273 | |
274 | mutex_lock(&dice->mutex); |
275 | // For double_pcm_frame quirk. |
276 | if (rate > 96000 && !dice->disable_double_pcm_frames) { |
277 | events_per_period /= 2; |
278 | events_per_buffer /= 2; |
279 | } |
280 | err = snd_dice_stream_reserve_duplex(dice, rate, |
281 | events_per_period, events_per_buffer); |
282 | if (err >= 0) |
283 | ++dice->substreams_counter; |
284 | mutex_unlock(lock: &dice->mutex); |
285 | } |
286 | |
287 | return err; |
288 | } |
289 | |
290 | static int pcm_hw_free(struct snd_pcm_substream *substream) |
291 | { |
292 | struct snd_dice *dice = substream->private_data; |
293 | |
294 | mutex_lock(&dice->mutex); |
295 | |
296 | if (substream->runtime->state != SNDRV_PCM_STATE_OPEN) |
297 | --dice->substreams_counter; |
298 | |
299 | snd_dice_stream_stop_duplex(dice); |
300 | |
301 | mutex_unlock(lock: &dice->mutex); |
302 | |
303 | return 0; |
304 | } |
305 | |
306 | static int capture_prepare(struct snd_pcm_substream *substream) |
307 | { |
308 | struct snd_dice *dice = substream->private_data; |
309 | struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; |
310 | int err; |
311 | |
312 | mutex_lock(&dice->mutex); |
313 | err = snd_dice_stream_start_duplex(dice); |
314 | mutex_unlock(lock: &dice->mutex); |
315 | if (err >= 0) |
316 | amdtp_stream_pcm_prepare(s: stream); |
317 | |
318 | return 0; |
319 | } |
320 | static int playback_prepare(struct snd_pcm_substream *substream) |
321 | { |
322 | struct snd_dice *dice = substream->private_data; |
323 | struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; |
324 | int err; |
325 | |
326 | mutex_lock(&dice->mutex); |
327 | err = snd_dice_stream_start_duplex(dice); |
328 | mutex_unlock(lock: &dice->mutex); |
329 | if (err >= 0) |
330 | amdtp_stream_pcm_prepare(s: stream); |
331 | |
332 | return err; |
333 | } |
334 | |
335 | static int capture_trigger(struct snd_pcm_substream *substream, int cmd) |
336 | { |
337 | struct snd_dice *dice = substream->private_data; |
338 | struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; |
339 | |
340 | switch (cmd) { |
341 | case SNDRV_PCM_TRIGGER_START: |
342 | amdtp_stream_pcm_trigger(s: stream, pcm: substream); |
343 | break; |
344 | case SNDRV_PCM_TRIGGER_STOP: |
345 | amdtp_stream_pcm_trigger(s: stream, NULL); |
346 | break; |
347 | default: |
348 | return -EINVAL; |
349 | } |
350 | |
351 | return 0; |
352 | } |
353 | static int playback_trigger(struct snd_pcm_substream *substream, int cmd) |
354 | { |
355 | struct snd_dice *dice = substream->private_data; |
356 | struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; |
357 | |
358 | switch (cmd) { |
359 | case SNDRV_PCM_TRIGGER_START: |
360 | amdtp_stream_pcm_trigger(s: stream, pcm: substream); |
361 | break; |
362 | case SNDRV_PCM_TRIGGER_STOP: |
363 | amdtp_stream_pcm_trigger(s: stream, NULL); |
364 | break; |
365 | default: |
366 | return -EINVAL; |
367 | } |
368 | |
369 | return 0; |
370 | } |
371 | |
372 | static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream) |
373 | { |
374 | struct snd_dice *dice = substream->private_data; |
375 | struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; |
376 | |
377 | return amdtp_domain_stream_pcm_pointer(d: &dice->domain, s: stream); |
378 | } |
379 | static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) |
380 | { |
381 | struct snd_dice *dice = substream->private_data; |
382 | struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; |
383 | |
384 | return amdtp_domain_stream_pcm_pointer(d: &dice->domain, s: stream); |
385 | } |
386 | |
387 | static int capture_ack(struct snd_pcm_substream *substream) |
388 | { |
389 | struct snd_dice *dice = substream->private_data; |
390 | struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; |
391 | |
392 | return amdtp_domain_stream_pcm_ack(d: &dice->domain, s: stream); |
393 | } |
394 | |
395 | static int playback_ack(struct snd_pcm_substream *substream) |
396 | { |
397 | struct snd_dice *dice = substream->private_data; |
398 | struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; |
399 | |
400 | return amdtp_domain_stream_pcm_ack(d: &dice->domain, s: stream); |
401 | } |
402 | |
403 | int snd_dice_create_pcm(struct snd_dice *dice) |
404 | { |
405 | static const struct snd_pcm_ops capture_ops = { |
406 | .open = pcm_open, |
407 | .close = pcm_close, |
408 | .hw_params = pcm_hw_params, |
409 | .hw_free = pcm_hw_free, |
410 | .prepare = capture_prepare, |
411 | .trigger = capture_trigger, |
412 | .pointer = capture_pointer, |
413 | .ack = capture_ack, |
414 | }; |
415 | static const struct snd_pcm_ops playback_ops = { |
416 | .open = pcm_open, |
417 | .close = pcm_close, |
418 | .hw_params = pcm_hw_params, |
419 | .hw_free = pcm_hw_free, |
420 | .prepare = playback_prepare, |
421 | .trigger = playback_trigger, |
422 | .pointer = playback_pointer, |
423 | .ack = playback_ack, |
424 | }; |
425 | struct snd_pcm *pcm; |
426 | unsigned int capture, playback; |
427 | int i, j; |
428 | int err; |
429 | |
430 | for (i = 0; i < MAX_STREAMS; i++) { |
431 | capture = playback = 0; |
432 | for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) { |
433 | if (dice->tx_pcm_chs[i][j] > 0) |
434 | capture = 1; |
435 | if (dice->rx_pcm_chs[i][j] > 0) |
436 | playback = 1; |
437 | } |
438 | |
439 | err = snd_pcm_new(card: dice->card, id: "DICE" , device: i, playback_count: playback, capture_count: capture, |
440 | rpcm: &pcm); |
441 | if (err < 0) |
442 | return err; |
443 | pcm->private_data = dice; |
444 | strcpy(p: pcm->name, q: dice->card->shortname); |
445 | |
446 | if (capture > 0) |
447 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, |
448 | ops: &capture_ops); |
449 | |
450 | if (playback > 0) |
451 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_PLAYBACK, |
452 | ops: &playback_ops); |
453 | |
454 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, |
455 | NULL, size: 0, max: 0); |
456 | } |
457 | |
458 | return 0; |
459 | } |
460 | |