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