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, struct amdtp_stream *s)
43 {
44 	struct fw_iso_resources *resources;
45 	enum amdtp_stream_direction dir;
46 	int err;
47 
48 	if (s == &ff->tx_stream) {
49 		resources = &ff->tx_resources;
50 		dir = AMDTP_IN_STREAM;
51 	} else {
52 		resources = &ff->rx_resources;
53 		dir = AMDTP_OUT_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(s, 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, struct amdtp_stream *s)
68 {
69 	amdtp_stream_destroy(s);
70 
71 	if (s == &ff->tx_stream)
72 		fw_iso_resources_destroy(&ff->tx_resources);
73 	else
74 		fw_iso_resources_destroy(&ff->rx_resources);
75 }
76 
77 int snd_ff_stream_init_duplex(struct snd_ff *ff)
78 {
79 	int err;
80 
81 	err = init_stream(ff, &ff->rx_stream);
82 	if (err < 0)
83 		return err;
84 
85 	err = init_stream(ff, &ff->tx_stream);
86 	if (err < 0)
87 		destroy_stream(ff, &ff->rx_stream);
88 
89 	return err;
90 }
91 
92 /*
93  * This function should be called before starting streams or after stopping
94  * streams.
95  */
96 void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
97 {
98 	destroy_stream(ff, &ff->rx_stream);
99 	destroy_stream(ff, &ff->tx_stream);
100 }
101 
102 int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
103 {
104 	unsigned int curr_rate;
105 	enum snd_ff_clock_src src;
106 	int err;
107 
108 	err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
109 	if (err < 0)
110 		return err;
111 
112 	if (ff->substreams_counter == 0 || curr_rate != rate) {
113 		enum snd_ff_stream_mode mode;
114 		int i;
115 
116 		finish_session(ff);
117 
118 		fw_iso_resources_free(&ff->tx_resources);
119 		fw_iso_resources_free(&ff->rx_resources);
120 
121 		for (i = 0; i < CIP_SFC_COUNT; ++i) {
122 			if (amdtp_rate_table[i] == rate)
123 				break;
124 		}
125 		if (i >= CIP_SFC_COUNT)
126 			return -EINVAL;
127 
128 		err = snd_ff_stream_get_multiplier_mode(i, &mode);
129 		if (err < 0)
130 			return err;
131 
132 		err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
133 					ff->spec->pcm_capture_channels[mode]);
134 		if (err < 0)
135 			return err;
136 
137 		err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
138 					ff->spec->pcm_playback_channels[mode]);
139 		if (err < 0)
140 			return err;
141 
142 		err = ff->spec->protocol->allocate_resources(ff, rate);
143 		if (err < 0)
144 			return err;
145 	}
146 
147 	return 0;
148 }
149 
150 int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
151 {
152 	int err;
153 
154 	if (ff->substreams_counter == 0)
155 		return 0;
156 
157 	if (amdtp_streaming_error(&ff->tx_stream) ||
158 	    amdtp_streaming_error(&ff->rx_stream))
159 		finish_session(ff);
160 
161 	/*
162 	 * Regardless of current source of clock signal, drivers transfer some
163 	 * packets. Then, the device transfers packets.
164 	 */
165 	if (!amdtp_stream_running(&ff->rx_stream)) {
166 		err = ff->spec->protocol->begin_session(ff, rate);
167 		if (err < 0)
168 			goto error;
169 
170 		err = amdtp_stream_start(&ff->rx_stream,
171 					 ff->rx_resources.channel,
172 					 fw_parent_device(ff->unit)->max_speed);
173 		if (err < 0)
174 			goto error;
175 
176 		if (!amdtp_stream_wait_callback(&ff->rx_stream,
177 						CALLBACK_TIMEOUT_MS)) {
178 			err = -ETIMEDOUT;
179 			goto error;
180 		}
181 
182 		err = ff->spec->protocol->switch_fetching_mode(ff, true);
183 		if (err < 0)
184 			goto error;
185 	}
186 
187 	if (!amdtp_stream_running(&ff->tx_stream)) {
188 		err = amdtp_stream_start(&ff->tx_stream,
189 					 ff->tx_resources.channel,
190 					 fw_parent_device(ff->unit)->max_speed);
191 		if (err < 0)
192 			goto error;
193 
194 		if (!amdtp_stream_wait_callback(&ff->tx_stream,
195 						CALLBACK_TIMEOUT_MS)) {
196 			err = -ETIMEDOUT;
197 			goto error;
198 		}
199 	}
200 
201 	return 0;
202 error:
203 	finish_session(ff);
204 
205 	return err;
206 }
207 
208 void snd_ff_stream_stop_duplex(struct snd_ff *ff)
209 {
210 	if (ff->substreams_counter == 0) {
211 		finish_session(ff);
212 
213 		fw_iso_resources_free(&ff->tx_resources);
214 		fw_iso_resources_free(&ff->rx_resources);
215 	}
216 }
217 
218 void snd_ff_stream_update_duplex(struct snd_ff *ff)
219 {
220 	// The device discontinue to transfer packets.
221 	amdtp_stream_pcm_abort(&ff->tx_stream);
222 	amdtp_stream_stop(&ff->tx_stream);
223 
224 	amdtp_stream_pcm_abort(&ff->rx_stream);
225 	amdtp_stream_stop(&ff->rx_stream);
226 }
227 
228 void snd_ff_stream_lock_changed(struct snd_ff *ff)
229 {
230 	ff->dev_lock_changed = true;
231 	wake_up(&ff->hwdep_wait);
232 }
233 
234 int snd_ff_stream_lock_try(struct snd_ff *ff)
235 {
236 	int err;
237 
238 	spin_lock_irq(&ff->lock);
239 
240 	/* user land lock this */
241 	if (ff->dev_lock_count < 0) {
242 		err = -EBUSY;
243 		goto end;
244 	}
245 
246 	/* this is the first time */
247 	if (ff->dev_lock_count++ == 0)
248 		snd_ff_stream_lock_changed(ff);
249 	err = 0;
250 end:
251 	spin_unlock_irq(&ff->lock);
252 	return err;
253 }
254 
255 void snd_ff_stream_lock_release(struct snd_ff *ff)
256 {
257 	spin_lock_irq(&ff->lock);
258 
259 	if (WARN_ON(ff->dev_lock_count <= 0))
260 		goto end;
261 	if (--ff->dev_lock_count == 0)
262 		snd_ff_stream_lock_changed(ff);
263 end:
264 	spin_unlock_irq(&ff->lock);
265 }
266