xref: /OK3568_Linux_fs/kernel/sound/firewire/dice/dice-pcm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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