1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * ff-stream.c - a part of driver for RME Fireface series
4  *
5  * Copyright (c) 2015-2017 Takashi Sakamoto
6  */
7 
8 #include "ff.h"
9 
10 #define CALLBACK_TIMEOUT_MS	200
11 
12 int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
13 				      enum snd_ff_stream_mode *mode)
14 {
15 	static const enum snd_ff_stream_mode modes[] = {
16 		[CIP_SFC_32000] = SND_FF_STREAM_MODE_LOW,
17 		[CIP_SFC_44100] = SND_FF_STREAM_MODE_LOW,
18 		[CIP_SFC_48000] = SND_FF_STREAM_MODE_LOW,
19 		[CIP_SFC_88200] = SND_FF_STREAM_MODE_MID,
20 		[CIP_SFC_96000] = SND_FF_STREAM_MODE_MID,
21 		[CIP_SFC_176400] = SND_FF_STREAM_MODE_HIGH,
22 		[CIP_SFC_192000] = SND_FF_STREAM_MODE_HIGH,
23 	};
24 
25 	if (sfc >= CIP_SFC_COUNT)
26 		return -EINVAL;
27 
28 	*mode = modes[sfc];
29 
30 	return 0;
31 }
32 
33 static inline void finish_session(struct snd_ff *ff)
34 {
35 	amdtp_stream_stop(&ff->tx_stream);
36 	amdtp_stream_stop(&ff->rx_stream);
37 
38 	ff->spec->protocol->finish_session(ff);
39 	ff->spec->protocol->switch_fetching_mode(ff, false);
40 }
41 
42 static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
43 {
44 	int err;
45 	struct fw_iso_resources *resources;
46 	struct amdtp_stream *stream;
47 
48 	if (dir == AMDTP_IN_STREAM) {
49 		resources = &ff->tx_resources;
50 		stream = &ff->tx_stream;
51 	} else {
52 		resources = &ff->rx_resources;
53 		stream = &ff->rx_stream;
54 	}
55 
56 	err = fw_iso_resources_init(resources, ff->unit);
57 	if (err < 0)
58 		return err;
59 
60 	err = amdtp_ff_init(stream, ff->unit, dir);
61 	if (err < 0)
62 		fw_iso_resources_destroy(resources);
63 
64 	return err;
65 }
66 
67 static void destroy_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
68 {
69 	if (dir == AMDTP_IN_STREAM) {
70 		amdtp_stream_destroy(&ff->tx_stream);
71 		fw_iso_resources_destroy(&ff->tx_resources);
72 	} else {
73 		amdtp_stream_destroy(&ff->rx_stream);
74 		fw_iso_resources_destroy(&ff->rx_resources);
75 	}
76 }
77 
78 int snd_ff_stream_init_duplex(struct snd_ff *ff)
79 {
80 	int err;
81 
82 	err = init_stream(ff, AMDTP_OUT_STREAM);
83 	if (err < 0)
84 		goto end;
85 
86 	err = init_stream(ff, AMDTP_IN_STREAM);
87 	if (err < 0)
88 		destroy_stream(ff, AMDTP_OUT_STREAM);
89 end:
90 	return err;
91 }
92 
93 /*
94  * This function should be called before starting streams or after stopping
95  * streams.
96  */
97 void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
98 {
99 	destroy_stream(ff, AMDTP_IN_STREAM);
100 	destroy_stream(ff, AMDTP_OUT_STREAM);
101 }
102 
103 int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
104 {
105 	unsigned int curr_rate;
106 	enum snd_ff_clock_src src;
107 	int err;
108 
109 	err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
110 	if (err < 0)
111 		return err;
112 
113 	if (ff->substreams_counter == 0 || curr_rate != rate) {
114 		enum snd_ff_stream_mode mode;
115 		int i;
116 
117 		finish_session(ff);
118 
119 		fw_iso_resources_free(&ff->tx_resources);
120 		fw_iso_resources_free(&ff->rx_resources);
121 
122 		for (i = 0; i < CIP_SFC_COUNT; ++i) {
123 			if (amdtp_rate_table[i] == rate)
124 				break;
125 		}
126 		if (i >= CIP_SFC_COUNT)
127 			return -EINVAL;
128 
129 		err = snd_ff_stream_get_multiplier_mode(i, &mode);
130 		if (err < 0)
131 			return err;
132 
133 		err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
134 					ff->spec->pcm_capture_channels[mode]);
135 		if (err < 0)
136 			return err;
137 
138 		err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
139 					ff->spec->pcm_playback_channels[mode]);
140 		if (err < 0)
141 			return err;
142 
143 		err = ff->spec->protocol->allocate_resources(ff, rate);
144 		if (err < 0)
145 			return err;
146 	}
147 
148 	return 0;
149 }
150 
151 int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
152 {
153 	int err;
154 
155 	if (ff->substreams_counter == 0)
156 		return 0;
157 
158 	if (amdtp_streaming_error(&ff->tx_stream) ||
159 	    amdtp_streaming_error(&ff->rx_stream))
160 		finish_session(ff);
161 
162 	/*
163 	 * Regardless of current source of clock signal, drivers transfer some
164 	 * packets. Then, the device transfers packets.
165 	 */
166 	if (!amdtp_stream_running(&ff->rx_stream)) {
167 		err = ff->spec->protocol->begin_session(ff, rate);
168 		if (err < 0)
169 			goto error;
170 
171 		err = amdtp_stream_start(&ff->rx_stream,
172 					 ff->rx_resources.channel,
173 					 fw_parent_device(ff->unit)->max_speed);
174 		if (err < 0)
175 			goto error;
176 
177 		if (!amdtp_stream_wait_callback(&ff->rx_stream,
178 						CALLBACK_TIMEOUT_MS)) {
179 			err = -ETIMEDOUT;
180 			goto error;
181 		}
182 
183 		err = ff->spec->protocol->switch_fetching_mode(ff, true);
184 		if (err < 0)
185 			goto error;
186 	}
187 
188 	if (!amdtp_stream_running(&ff->tx_stream)) {
189 		err = amdtp_stream_start(&ff->tx_stream,
190 					 ff->tx_resources.channel,
191 					 fw_parent_device(ff->unit)->max_speed);
192 		if (err < 0)
193 			goto error;
194 
195 		if (!amdtp_stream_wait_callback(&ff->tx_stream,
196 						CALLBACK_TIMEOUT_MS)) {
197 			err = -ETIMEDOUT;
198 			goto error;
199 		}
200 	}
201 
202 	return 0;
203 error:
204 	finish_session(ff);
205 
206 	return err;
207 }
208 
209 void snd_ff_stream_stop_duplex(struct snd_ff *ff)
210 {
211 	if (ff->substreams_counter == 0) {
212 		finish_session(ff);
213 
214 		fw_iso_resources_free(&ff->tx_resources);
215 		fw_iso_resources_free(&ff->rx_resources);
216 	}
217 }
218 
219 void snd_ff_stream_update_duplex(struct snd_ff *ff)
220 {
221 	// The device discontinue to transfer packets.
222 	amdtp_stream_pcm_abort(&ff->tx_stream);
223 	amdtp_stream_stop(&ff->tx_stream);
224 
225 	amdtp_stream_pcm_abort(&ff->rx_stream);
226 	amdtp_stream_stop(&ff->rx_stream);
227 }
228 
229 void snd_ff_stream_lock_changed(struct snd_ff *ff)
230 {
231 	ff->dev_lock_changed = true;
232 	wake_up(&ff->hwdep_wait);
233 }
234 
235 int snd_ff_stream_lock_try(struct snd_ff *ff)
236 {
237 	int err;
238 
239 	spin_lock_irq(&ff->lock);
240 
241 	/* user land lock this */
242 	if (ff->dev_lock_count < 0) {
243 		err = -EBUSY;
244 		goto end;
245 	}
246 
247 	/* this is the first time */
248 	if (ff->dev_lock_count++ == 0)
249 		snd_ff_stream_lock_changed(ff);
250 	err = 0;
251 end:
252 	spin_unlock_irq(&ff->lock);
253 	return err;
254 }
255 
256 void snd_ff_stream_lock_release(struct snd_ff *ff)
257 {
258 	spin_lock_irq(&ff->lock);
259 
260 	if (WARN_ON(ff->dev_lock_count <= 0))
261 		goto end;
262 	if (--ff->dev_lock_count == 0)
263 		snd_ff_stream_lock_changed(ff);
264 end:
265 	spin_unlock_irq(&ff->lock);
266 }
267