1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c50fb91fSTakashi Sakamoto /*
3c50fb91fSTakashi Sakamoto * dice_pcm.c - a part of driver for DICE based devices
4c50fb91fSTakashi Sakamoto *
5c50fb91fSTakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
6c50fb91fSTakashi Sakamoto * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
7c50fb91fSTakashi Sakamoto */
8c50fb91fSTakashi Sakamoto
9c50fb91fSTakashi Sakamoto #include "dice.h"
10c50fb91fSTakashi Sakamoto
dice_rate_constraint(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)11bd2b441cSTakashi Sakamoto static int dice_rate_constraint(struct snd_pcm_hw_params *params,
12bd2b441cSTakashi Sakamoto struct snd_pcm_hw_rule *rule)
13bd2b441cSTakashi Sakamoto {
14bd2b441cSTakashi Sakamoto struct snd_pcm_substream *substream = rule->private;
15bd2b441cSTakashi Sakamoto struct snd_dice *dice = substream->private_data;
16bd2b441cSTakashi Sakamoto unsigned int index = substream->pcm->device;
17bd2b441cSTakashi Sakamoto
18bd2b441cSTakashi Sakamoto const struct snd_interval *c =
19bd2b441cSTakashi Sakamoto hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
20bd2b441cSTakashi Sakamoto struct snd_interval *r =
21bd2b441cSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
22bd2b441cSTakashi Sakamoto struct snd_interval rates = {
23bd2b441cSTakashi Sakamoto .min = UINT_MAX, .max = 0, .integer = 1
24bd2b441cSTakashi Sakamoto };
25bd2b441cSTakashi Sakamoto unsigned int *pcm_channels;
26bd2b441cSTakashi Sakamoto enum snd_dice_rate_mode mode;
27bd2b441cSTakashi Sakamoto unsigned int i, rate;
28bd2b441cSTakashi Sakamoto
29bd2b441cSTakashi Sakamoto if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
30bd2b441cSTakashi Sakamoto pcm_channels = dice->tx_pcm_chs[index];
31bd2b441cSTakashi Sakamoto else
32bd2b441cSTakashi Sakamoto pcm_channels = dice->rx_pcm_chs[index];
33bd2b441cSTakashi Sakamoto
34bd2b441cSTakashi Sakamoto for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
35bd2b441cSTakashi Sakamoto rate = snd_dice_rates[i];
36bd2b441cSTakashi Sakamoto if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
37bd2b441cSTakashi Sakamoto continue;
38bd2b441cSTakashi Sakamoto
39bd2b441cSTakashi Sakamoto if (!snd_interval_test(c, pcm_channels[mode]))
40bd2b441cSTakashi Sakamoto continue;
41bd2b441cSTakashi Sakamoto
42bd2b441cSTakashi Sakamoto rates.min = min(rates.min, rate);
43bd2b441cSTakashi Sakamoto rates.max = max(rates.max, rate);
44bd2b441cSTakashi Sakamoto }
45bd2b441cSTakashi Sakamoto
46bd2b441cSTakashi Sakamoto return snd_interval_refine(r, &rates);
47bd2b441cSTakashi Sakamoto }
48bd2b441cSTakashi Sakamoto
dice_channels_constraint(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)49bd2b441cSTakashi Sakamoto static int dice_channels_constraint(struct snd_pcm_hw_params *params,
50bd2b441cSTakashi Sakamoto struct snd_pcm_hw_rule *rule)
51bd2b441cSTakashi Sakamoto {
52bd2b441cSTakashi Sakamoto struct snd_pcm_substream *substream = rule->private;
53bd2b441cSTakashi Sakamoto struct snd_dice *dice = substream->private_data;
54bd2b441cSTakashi Sakamoto unsigned int index = substream->pcm->device;
55bd2b441cSTakashi Sakamoto
56bd2b441cSTakashi Sakamoto const struct snd_interval *r =
57bd2b441cSTakashi Sakamoto hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
58bd2b441cSTakashi Sakamoto struct snd_interval *c =
59bd2b441cSTakashi Sakamoto hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
60bd2b441cSTakashi Sakamoto struct snd_interval channels = {
61bd2b441cSTakashi Sakamoto .min = UINT_MAX, .max = 0, .integer = 1
62bd2b441cSTakashi Sakamoto };
63bd2b441cSTakashi Sakamoto unsigned int *pcm_channels;
64bd2b441cSTakashi Sakamoto enum snd_dice_rate_mode mode;
65bd2b441cSTakashi Sakamoto unsigned int i, rate;
66bd2b441cSTakashi Sakamoto
67bd2b441cSTakashi Sakamoto if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
68bd2b441cSTakashi Sakamoto pcm_channels = dice->tx_pcm_chs[index];
69bd2b441cSTakashi Sakamoto else
70bd2b441cSTakashi Sakamoto pcm_channels = dice->rx_pcm_chs[index];
71bd2b441cSTakashi Sakamoto
72bd2b441cSTakashi Sakamoto for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
73bd2b441cSTakashi Sakamoto rate = snd_dice_rates[i];
74bd2b441cSTakashi Sakamoto if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
75bd2b441cSTakashi Sakamoto continue;
76bd2b441cSTakashi Sakamoto
77bd2b441cSTakashi Sakamoto if (!snd_interval_test(r, rate))
78bd2b441cSTakashi Sakamoto continue;
79bd2b441cSTakashi Sakamoto
80bd2b441cSTakashi Sakamoto channels.min = min(channels.min, pcm_channels[mode]);
81bd2b441cSTakashi Sakamoto channels.max = max(channels.max, pcm_channels[mode]);
82bd2b441cSTakashi Sakamoto }
83bd2b441cSTakashi Sakamoto
84bd2b441cSTakashi Sakamoto return snd_interval_refine(c, &channels);
85bd2b441cSTakashi Sakamoto }
86bd2b441cSTakashi Sakamoto
limit_channels_and_rates(struct snd_dice * dice,struct snd_pcm_runtime * runtime,enum amdtp_stream_direction dir,unsigned int index)870d5ee195STakashi Sakamoto static int limit_channels_and_rates(struct snd_dice *dice,
882c2416c8STakashi Sakamoto struct snd_pcm_runtime *runtime,
894bdc495cSTakashi Sakamoto enum amdtp_stream_direction dir,
90bd2b441cSTakashi Sakamoto unsigned int index)
91c50fb91fSTakashi Sakamoto {
922c2416c8STakashi Sakamoto struct snd_pcm_hardware *hw = &runtime->hw;
93bd2b441cSTakashi Sakamoto unsigned int *pcm_channels;
94bd2b441cSTakashi Sakamoto unsigned int i;
952c2416c8STakashi Sakamoto
96bd2b441cSTakashi Sakamoto if (dir == AMDTP_IN_STREAM)
97bd2b441cSTakashi Sakamoto pcm_channels = dice->tx_pcm_chs[index];
98bd2b441cSTakashi Sakamoto else
99bd2b441cSTakashi Sakamoto pcm_channels = dice->rx_pcm_chs[index];
100bd2b441cSTakashi Sakamoto
101bd2b441cSTakashi Sakamoto hw->channels_min = UINT_MAX;
102bd2b441cSTakashi Sakamoto hw->channels_max = 0;
103bd2b441cSTakashi Sakamoto
104bd2b441cSTakashi Sakamoto for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
105bd2b441cSTakashi Sakamoto enum snd_dice_rate_mode mode;
106bd2b441cSTakashi Sakamoto unsigned int rate, channels;
107bd2b441cSTakashi Sakamoto
108bd2b441cSTakashi Sakamoto rate = snd_dice_rates[i];
109bd2b441cSTakashi Sakamoto if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
110bd2b441cSTakashi Sakamoto continue;
111bd2b441cSTakashi Sakamoto hw->rates |= snd_pcm_rate_to_rate_bit(rate);
112bd2b441cSTakashi Sakamoto
113bd2b441cSTakashi Sakamoto channels = pcm_channels[mode];
114bd2b441cSTakashi Sakamoto if (channels == 0)
115bd2b441cSTakashi Sakamoto continue;
116bd2b441cSTakashi Sakamoto hw->channels_min = min(hw->channels_min, channels);
117bd2b441cSTakashi Sakamoto hw->channels_max = max(hw->channels_max, channels);
1182c2416c8STakashi Sakamoto }
1192c2416c8STakashi Sakamoto
1202c2416c8STakashi Sakamoto snd_pcm_limit_hw_rates(runtime);
1210d5ee195STakashi Sakamoto
1220d5ee195STakashi Sakamoto return 0;
1232c2416c8STakashi Sakamoto }
1242c2416c8STakashi Sakamoto
init_hw_info(struct snd_dice * dice,struct snd_pcm_substream * substream)1252c2416c8STakashi Sakamoto static int init_hw_info(struct snd_dice *dice,
1262c2416c8STakashi Sakamoto struct snd_pcm_substream *substream)
1272c2416c8STakashi Sakamoto {
1282c2416c8STakashi Sakamoto struct snd_pcm_runtime *runtime = substream->runtime;
1292c2416c8STakashi Sakamoto struct snd_pcm_hardware *hw = &runtime->hw;
130bd2b441cSTakashi Sakamoto unsigned int index = substream->pcm->device;
1314bdc495cSTakashi Sakamoto enum amdtp_stream_direction dir;
13269dcf3e4STakashi Sakamoto struct amdtp_stream *stream;
1332c2416c8STakashi Sakamoto int err;
1342c2416c8STakashi Sakamoto
13569dcf3e4STakashi Sakamoto if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
13649c7b3fcSTakashi Sakamoto hw->formats = AM824_IN_PCM_FORMAT_BITS;
1374bdc495cSTakashi Sakamoto dir = AMDTP_IN_STREAM;
138bd2b441cSTakashi Sakamoto stream = &dice->tx_stream[index];
13969dcf3e4STakashi Sakamoto } else {
14049c7b3fcSTakashi Sakamoto hw->formats = AM824_OUT_PCM_FORMAT_BITS;
1414bdc495cSTakashi Sakamoto dir = AMDTP_OUT_STREAM;
142bd2b441cSTakashi Sakamoto stream = &dice->rx_stream[index];
14369dcf3e4STakashi Sakamoto }
14469dcf3e4STakashi Sakamoto
145bd2b441cSTakashi Sakamoto err = limit_channels_and_rates(dice, substream->runtime, dir,
146bd2b441cSTakashi Sakamoto index);
1474bdc495cSTakashi Sakamoto if (err < 0)
1484bdc495cSTakashi Sakamoto return err;
1494bdc495cSTakashi Sakamoto
150bd2b441cSTakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
151bd2b441cSTakashi Sakamoto dice_rate_constraint, substream,
152bd2b441cSTakashi Sakamoto SNDRV_PCM_HW_PARAM_CHANNELS, -1);
153bd2b441cSTakashi Sakamoto if (err < 0)
154bd2b441cSTakashi Sakamoto return err;
155bd2b441cSTakashi Sakamoto err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
156bd2b441cSTakashi Sakamoto dice_channels_constraint, substream,
157bd2b441cSTakashi Sakamoto SNDRV_PCM_HW_PARAM_RATE, -1);
1580d5ee195STakashi Sakamoto if (err < 0)
1590d5ee195STakashi Sakamoto return err;
160c50fb91fSTakashi Sakamoto
1610d5ee195STakashi Sakamoto return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
1622c2416c8STakashi Sakamoto }
1632c2416c8STakashi Sakamoto
pcm_open(struct snd_pcm_substream * substream)1642c2416c8STakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream)
1652c2416c8STakashi Sakamoto {
1662c2416c8STakashi Sakamoto struct snd_dice *dice = substream->private_data;
167a8fb2248STakashi Sakamoto struct amdtp_domain *d = &dice->domain;
168bd2b441cSTakashi Sakamoto unsigned int source;
169bd2b441cSTakashi Sakamoto bool internal;
1702c2416c8STakashi Sakamoto int err;
1712c2416c8STakashi Sakamoto
1722c2416c8STakashi Sakamoto err = snd_dice_stream_lock_try(dice);
173c50fb91fSTakashi Sakamoto if (err < 0)
174a8fb2248STakashi Sakamoto return err;
175c50fb91fSTakashi Sakamoto
1762c2416c8STakashi Sakamoto err = init_hw_info(dice, substream);
1772c2416c8STakashi Sakamoto if (err < 0)
1782c2416c8STakashi Sakamoto goto err_locked;
1798fc01fc0STakashi Sakamoto
180bd2b441cSTakashi Sakamoto err = snd_dice_transaction_get_clock_source(dice, &source);
181bd2b441cSTakashi Sakamoto if (err < 0)
182bd2b441cSTakashi Sakamoto goto err_locked;
183bd2b441cSTakashi Sakamoto switch (source) {
184bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_AES1:
185bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_AES2:
186bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_AES3:
187bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_AES4:
188bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_AES_ANY:
189bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_ADAT:
190bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_TDIF:
191bd2b441cSTakashi Sakamoto case CLOCK_SOURCE_WC:
192bd2b441cSTakashi Sakamoto internal = false;
193bd2b441cSTakashi Sakamoto break;
194bd2b441cSTakashi Sakamoto default:
195bd2b441cSTakashi Sakamoto internal = true;
196bd2b441cSTakashi Sakamoto break;
197bd2b441cSTakashi Sakamoto }
198bd2b441cSTakashi Sakamoto
199a8fb2248STakashi Sakamoto mutex_lock(&dice->mutex);
200a8fb2248STakashi Sakamoto
201a8fb2248STakashi Sakamoto // When source of clock is not internal or any stream is reserved for
202a8fb2248STakashi Sakamoto // transmission of PCM frames, the available sampling rate is limited
203a8fb2248STakashi Sakamoto // at current one.
204bd2b441cSTakashi Sakamoto if (!internal ||
205a8fb2248STakashi Sakamoto (dice->substreams_counter > 0 && d->events_per_period > 0)) {
206a8fb2248STakashi Sakamoto unsigned int frames_per_period = d->events_per_period;
207ecb40fd2STakashi Sakamoto unsigned int frames_per_buffer = d->events_per_buffer;
208bd2b441cSTakashi Sakamoto unsigned int rate;
209bd2b441cSTakashi Sakamoto
210bd2b441cSTakashi Sakamoto err = snd_dice_transaction_get_rate(dice, &rate);
211a8fb2248STakashi Sakamoto if (err < 0) {
212a8fb2248STakashi Sakamoto mutex_unlock(&dice->mutex);
213bd2b441cSTakashi Sakamoto goto err_locked;
214bd2b441cSTakashi Sakamoto }
215bd2b441cSTakashi Sakamoto
216a8fb2248STakashi Sakamoto substream->runtime->hw.rate_min = rate;
217a8fb2248STakashi Sakamoto substream->runtime->hw.rate_max = rate;
218a8fb2248STakashi Sakamoto
219a8fb2248STakashi Sakamoto if (frames_per_period > 0) {
220a8fb2248STakashi Sakamoto // For double_pcm_frame quirk.
2219f079c1bSTakashi Sakamoto if (rate > 96000 && !dice->disable_double_pcm_frames) {
222a8fb2248STakashi Sakamoto frames_per_period *= 2;
223ecb40fd2STakashi Sakamoto frames_per_buffer *= 2;
224ecb40fd2STakashi Sakamoto }
225a8fb2248STakashi Sakamoto
226a8fb2248STakashi Sakamoto err = snd_pcm_hw_constraint_minmax(substream->runtime,
227a8fb2248STakashi Sakamoto SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
228a8fb2248STakashi Sakamoto frames_per_period, frames_per_period);
229a8fb2248STakashi Sakamoto if (err < 0) {
230a8fb2248STakashi Sakamoto mutex_unlock(&dice->mutex);
231a8fb2248STakashi Sakamoto goto err_locked;
232a8fb2248STakashi Sakamoto }
233ecb40fd2STakashi Sakamoto
234ecb40fd2STakashi Sakamoto err = snd_pcm_hw_constraint_minmax(substream->runtime,
235ecb40fd2STakashi Sakamoto SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
236ecb40fd2STakashi Sakamoto frames_per_buffer, frames_per_buffer);
237ecb40fd2STakashi Sakamoto if (err < 0) {
238ecb40fd2STakashi Sakamoto mutex_unlock(&dice->mutex);
239ecb40fd2STakashi Sakamoto goto err_locked;
240ecb40fd2STakashi Sakamoto }
241a8fb2248STakashi Sakamoto }
242a8fb2248STakashi Sakamoto }
243a8fb2248STakashi Sakamoto
244a8fb2248STakashi Sakamoto mutex_unlock(&dice->mutex);
245a8fb2248STakashi Sakamoto
2468fc01fc0STakashi Sakamoto snd_pcm_set_sync(substream);
247a8fb2248STakashi Sakamoto
248a8fb2248STakashi Sakamoto return 0;
2492c2416c8STakashi Sakamoto err_locked:
250c50fb91fSTakashi Sakamoto snd_dice_stream_lock_release(dice);
251c50fb91fSTakashi Sakamoto return err;
252c50fb91fSTakashi Sakamoto }
253c50fb91fSTakashi Sakamoto
pcm_close(struct snd_pcm_substream * substream)254c50fb91fSTakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream)
255c50fb91fSTakashi Sakamoto {
256c50fb91fSTakashi Sakamoto struct snd_dice *dice = substream->private_data;
257c50fb91fSTakashi Sakamoto
258c50fb91fSTakashi Sakamoto snd_dice_stream_lock_release(dice);
259c50fb91fSTakashi Sakamoto
260c50fb91fSTakashi Sakamoto return 0;
261c50fb91fSTakashi Sakamoto }
262c50fb91fSTakashi Sakamoto
pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)2634dbf4f44STakashi Sakamoto static int pcm_hw_params(struct snd_pcm_substream *substream,
264c50fb91fSTakashi Sakamoto struct snd_pcm_hw_params *hw_params)
265c50fb91fSTakashi Sakamoto {
266c50fb91fSTakashi Sakamoto struct snd_dice *dice = substream->private_data;
2677641d549STakashi Iwai int err = 0;
26869dcf3e4STakashi Sakamoto
269*23cb0767STakashi Iwai if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
2703cd2c2d7STakashi Sakamoto unsigned int rate = params_rate(hw_params);
27194c8101aSTakashi Sakamoto unsigned int events_per_period = params_period_size(hw_params);
272ecb40fd2STakashi Sakamoto unsigned int events_per_buffer = params_buffer_size(hw_params);
2733cd2c2d7STakashi Sakamoto
27469dcf3e4STakashi Sakamoto mutex_lock(&dice->mutex);
27594c8101aSTakashi Sakamoto // For double_pcm_frame quirk.
2769f079c1bSTakashi Sakamoto if (rate > 96000 && !dice->disable_double_pcm_frames) {
27794c8101aSTakashi Sakamoto events_per_period /= 2;
278ecb40fd2STakashi Sakamoto events_per_buffer /= 2;
279ecb40fd2STakashi Sakamoto }
28094c8101aSTakashi Sakamoto err = snd_dice_stream_reserve_duplex(dice, rate,
281ecb40fd2STakashi Sakamoto events_per_period, events_per_buffer);
2823cd2c2d7STakashi Sakamoto if (err >= 0)
2833cd2c2d7STakashi Sakamoto ++dice->substreams_counter;
28469dcf3e4STakashi Sakamoto mutex_unlock(&dice->mutex);
28569dcf3e4STakashi Sakamoto }
28669dcf3e4STakashi Sakamoto
2873cd2c2d7STakashi Sakamoto return err;
288c50fb91fSTakashi Sakamoto }
289c50fb91fSTakashi Sakamoto
pcm_hw_free(struct snd_pcm_substream * substream)2904dbf4f44STakashi Sakamoto static int pcm_hw_free(struct snd_pcm_substream *substream)
29169dcf3e4STakashi Sakamoto {
29269dcf3e4STakashi Sakamoto struct snd_dice *dice = substream->private_data;
29369dcf3e4STakashi Sakamoto
29469dcf3e4STakashi Sakamoto mutex_lock(&dice->mutex);
29569dcf3e4STakashi Sakamoto
296*23cb0767STakashi Iwai if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
2973cd2c2d7STakashi Sakamoto --dice->substreams_counter;
29869dcf3e4STakashi Sakamoto
29969dcf3e4STakashi Sakamoto snd_dice_stream_stop_duplex(dice);
30069dcf3e4STakashi Sakamoto
30169dcf3e4STakashi Sakamoto mutex_unlock(&dice->mutex);
30269dcf3e4STakashi Sakamoto
3037641d549STakashi Iwai return 0;
30469dcf3e4STakashi Sakamoto }
30569dcf3e4STakashi Sakamoto
capture_prepare(struct snd_pcm_substream * substream)30669dcf3e4STakashi Sakamoto static int capture_prepare(struct snd_pcm_substream *substream)
30769dcf3e4STakashi Sakamoto {
30869dcf3e4STakashi Sakamoto struct snd_dice *dice = substream->private_data;
3094bdc495cSTakashi Sakamoto struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
31069dcf3e4STakashi Sakamoto int err;
31169dcf3e4STakashi Sakamoto
31269dcf3e4STakashi Sakamoto mutex_lock(&dice->mutex);
3133cd2c2d7STakashi Sakamoto err = snd_dice_stream_start_duplex(dice);
31469dcf3e4STakashi Sakamoto mutex_unlock(&dice->mutex);
31569dcf3e4STakashi Sakamoto if (err >= 0)
3168ae25b76STakashi Sakamoto amdtp_stream_pcm_prepare(stream);
31769dcf3e4STakashi Sakamoto
31869dcf3e4STakashi Sakamoto return 0;
31969dcf3e4STakashi Sakamoto }
playback_prepare(struct snd_pcm_substream * substream)320c50fb91fSTakashi Sakamoto static int playback_prepare(struct snd_pcm_substream *substream)
321c50fb91fSTakashi Sakamoto {
322c50fb91fSTakashi Sakamoto struct snd_dice *dice = substream->private_data;
3234bdc495cSTakashi Sakamoto struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
324c50fb91fSTakashi Sakamoto int err;
325c50fb91fSTakashi Sakamoto
326c50fb91fSTakashi Sakamoto mutex_lock(&dice->mutex);
3273cd2c2d7STakashi Sakamoto err = snd_dice_stream_start_duplex(dice);
328c50fb91fSTakashi Sakamoto mutex_unlock(&dice->mutex);
329288a8d0cSTakashi Sakamoto if (err >= 0)
3308ae25b76STakashi Sakamoto amdtp_stream_pcm_prepare(stream);
331c50fb91fSTakashi Sakamoto
332288a8d0cSTakashi Sakamoto return err;
333c50fb91fSTakashi Sakamoto }
334c50fb91fSTakashi Sakamoto
capture_trigger(struct snd_pcm_substream * substream,int cmd)33569dcf3e4STakashi Sakamoto static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
33669dcf3e4STakashi Sakamoto {
33769dcf3e4STakashi Sakamoto struct snd_dice *dice = substream->private_data;
3384bdc495cSTakashi Sakamoto struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
33969dcf3e4STakashi Sakamoto
34069dcf3e4STakashi Sakamoto switch (cmd) {
34169dcf3e4STakashi Sakamoto case SNDRV_PCM_TRIGGER_START:
3428ae25b76STakashi Sakamoto amdtp_stream_pcm_trigger(stream, substream);
34369dcf3e4STakashi Sakamoto break;
34469dcf3e4STakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP:
3458ae25b76STakashi Sakamoto amdtp_stream_pcm_trigger(stream, NULL);
34669dcf3e4STakashi Sakamoto break;
34769dcf3e4STakashi Sakamoto default:
34869dcf3e4STakashi Sakamoto return -EINVAL;
34969dcf3e4STakashi Sakamoto }
35069dcf3e4STakashi Sakamoto
35169dcf3e4STakashi Sakamoto return 0;
35269dcf3e4STakashi Sakamoto }
playback_trigger(struct snd_pcm_substream * substream,int cmd)353c50fb91fSTakashi Sakamoto static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
354c50fb91fSTakashi Sakamoto {
355c50fb91fSTakashi Sakamoto struct snd_dice *dice = substream->private_data;
3564bdc495cSTakashi Sakamoto struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
357c50fb91fSTakashi Sakamoto
358c50fb91fSTakashi Sakamoto switch (cmd) {
359c50fb91fSTakashi Sakamoto case SNDRV_PCM_TRIGGER_START:
3608ae25b76STakashi Sakamoto amdtp_stream_pcm_trigger(stream, substream);
361c50fb91fSTakashi Sakamoto break;
362c50fb91fSTakashi Sakamoto case SNDRV_PCM_TRIGGER_STOP:
3638ae25b76STakashi Sakamoto amdtp_stream_pcm_trigger(stream, NULL);
364c50fb91fSTakashi Sakamoto break;
365c50fb91fSTakashi Sakamoto default:
366c50fb91fSTakashi Sakamoto return -EINVAL;
367c50fb91fSTakashi Sakamoto }
368c50fb91fSTakashi Sakamoto
369c50fb91fSTakashi Sakamoto return 0;
370c50fb91fSTakashi Sakamoto }
371c50fb91fSTakashi Sakamoto
capture_pointer(struct snd_pcm_substream * substream)37269dcf3e4STakashi Sakamoto static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
37369dcf3e4STakashi Sakamoto {
37469dcf3e4STakashi Sakamoto struct snd_dice *dice = substream->private_data;
3754bdc495cSTakashi Sakamoto struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
37669dcf3e4STakashi Sakamoto
377f890f9a0STakashi Sakamoto return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
37869dcf3e4STakashi Sakamoto }
playback_pointer(struct snd_pcm_substream * substream)379c50fb91fSTakashi Sakamoto static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
380c50fb91fSTakashi Sakamoto {
381c50fb91fSTakashi Sakamoto struct snd_dice *dice = substream->private_data;
3824bdc495cSTakashi Sakamoto struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
383c50fb91fSTakashi Sakamoto
384f890f9a0STakashi Sakamoto return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
385c50fb91fSTakashi Sakamoto }
386c50fb91fSTakashi Sakamoto
capture_ack(struct snd_pcm_substream * substream)387875becf8STakashi Sakamoto static int capture_ack(struct snd_pcm_substream *substream)
388875becf8STakashi Sakamoto {
389875becf8STakashi Sakamoto struct snd_dice *dice = substream->private_data;
390875becf8STakashi Sakamoto struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
391875becf8STakashi Sakamoto
392e6dcc92fSTakashi Sakamoto return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
393875becf8STakashi Sakamoto }
394875becf8STakashi Sakamoto
playback_ack(struct snd_pcm_substream * substream)395875becf8STakashi Sakamoto static int playback_ack(struct snd_pcm_substream *substream)
396875becf8STakashi Sakamoto {
397875becf8STakashi Sakamoto struct snd_dice *dice = substream->private_data;
398875becf8STakashi Sakamoto struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
399875becf8STakashi Sakamoto
400e6dcc92fSTakashi Sakamoto return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
401875becf8STakashi Sakamoto }
402875becf8STakashi Sakamoto
snd_dice_create_pcm(struct snd_dice * dice)403c50fb91fSTakashi Sakamoto int snd_dice_create_pcm(struct snd_dice *dice)
404c50fb91fSTakashi Sakamoto {
4055116ffc3SJulia Lawall static const struct snd_pcm_ops capture_ops = {
40669dcf3e4STakashi Sakamoto .open = pcm_open,
40769dcf3e4STakashi Sakamoto .close = pcm_close,
4084dbf4f44STakashi Sakamoto .hw_params = pcm_hw_params,
4094dbf4f44STakashi Sakamoto .hw_free = pcm_hw_free,
41069dcf3e4STakashi Sakamoto .prepare = capture_prepare,
41169dcf3e4STakashi Sakamoto .trigger = capture_trigger,
41269dcf3e4STakashi Sakamoto .pointer = capture_pointer,
413875becf8STakashi Sakamoto .ack = capture_ack,
41469dcf3e4STakashi Sakamoto };
4155116ffc3SJulia Lawall static const struct snd_pcm_ops playback_ops = {
416c50fb91fSTakashi Sakamoto .open = pcm_open,
417c50fb91fSTakashi Sakamoto .close = pcm_close,
4184dbf4f44STakashi Sakamoto .hw_params = pcm_hw_params,
4194dbf4f44STakashi Sakamoto .hw_free = pcm_hw_free,
420c50fb91fSTakashi Sakamoto .prepare = playback_prepare,
421c50fb91fSTakashi Sakamoto .trigger = playback_trigger,
422c50fb91fSTakashi Sakamoto .pointer = playback_pointer,
423875becf8STakashi Sakamoto .ack = playback_ack,
424c50fb91fSTakashi Sakamoto };
425c50fb91fSTakashi Sakamoto struct snd_pcm *pcm;
4269c367c01STakashi Sakamoto unsigned int capture, playback;
4279c367c01STakashi Sakamoto int i, j;
428c50fb91fSTakashi Sakamoto int err;
429c50fb91fSTakashi Sakamoto
4304bdc495cSTakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) {
4314bdc495cSTakashi Sakamoto capture = playback = 0;
4329c367c01STakashi Sakamoto for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) {
4339c367c01STakashi Sakamoto if (dice->tx_pcm_chs[i][j] > 0)
43469dcf3e4STakashi Sakamoto capture = 1;
4359c367c01STakashi Sakamoto if (dice->rx_pcm_chs[i][j] > 0)
43669dcf3e4STakashi Sakamoto playback = 1;
4379c367c01STakashi Sakamoto }
43869dcf3e4STakashi Sakamoto
4394bdc495cSTakashi Sakamoto err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
4404bdc495cSTakashi Sakamoto &pcm);
441c50fb91fSTakashi Sakamoto if (err < 0)
442c50fb91fSTakashi Sakamoto return err;
443c50fb91fSTakashi Sakamoto pcm->private_data = dice;
444c50fb91fSTakashi Sakamoto strcpy(pcm->name, dice->card->shortname);
44569dcf3e4STakashi Sakamoto
44669dcf3e4STakashi Sakamoto if (capture > 0)
4474bdc495cSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
4484bdc495cSTakashi Sakamoto &capture_ops);
44969dcf3e4STakashi Sakamoto
45069dcf3e4STakashi Sakamoto if (playback > 0)
4514bdc495cSTakashi Sakamoto snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
4524bdc495cSTakashi Sakamoto &playback_ops);
453a3f4f2d5STakashi Iwai
4547641d549STakashi Iwai snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
455a3f4f2d5STakashi Iwai NULL, 0, 0);
4564bdc495cSTakashi Sakamoto }
457c50fb91fSTakashi Sakamoto
458c50fb91fSTakashi Sakamoto return 0;
459c50fb91fSTakashi Sakamoto }
460