xref: /linux/sound/firewire/fireworks/fireworks_stream.c (revision b8d312aa075f33282565467662c4628dae0a2aff)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * fireworks_stream.c - a part of driver for Fireworks based devices
4  *
5  * Copyright (c) 2013-2014 Takashi Sakamoto
6  */
7 #include "./fireworks.h"
8 
9 #define CALLBACK_TIMEOUT	100
10 
11 static int
12 init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
13 {
14 	struct cmp_connection *conn;
15 	enum cmp_direction c_dir;
16 	enum amdtp_stream_direction s_dir;
17 	int err;
18 
19 	if (stream == &efw->tx_stream) {
20 		conn = &efw->out_conn;
21 		c_dir = CMP_OUTPUT;
22 		s_dir = AMDTP_IN_STREAM;
23 	} else {
24 		conn = &efw->in_conn;
25 		c_dir = CMP_INPUT;
26 		s_dir = AMDTP_OUT_STREAM;
27 	}
28 
29 	err = cmp_connection_init(conn, efw->unit, c_dir, 0);
30 	if (err < 0)
31 		goto end;
32 
33 	err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING);
34 	if (err < 0) {
35 		amdtp_stream_destroy(stream);
36 		cmp_connection_destroy(conn);
37 	}
38 end:
39 	return err;
40 }
41 
42 static void
43 stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
44 {
45 	amdtp_stream_stop(stream);
46 
47 	if (stream == &efw->tx_stream)
48 		cmp_connection_break(&efw->out_conn);
49 	else
50 		cmp_connection_break(&efw->in_conn);
51 }
52 
53 static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
54 			unsigned int rate)
55 {
56 	struct cmp_connection *conn;
57 	int err;
58 
59 	if (stream == &efw->tx_stream)
60 		conn = &efw->out_conn;
61 	else
62 		conn = &efw->in_conn;
63 
64 	// Establish connection via CMP.
65 	err = cmp_connection_establish(conn);
66 	if (err < 0)
67 		return err;
68 
69 	// Start amdtp stream.
70 	err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
71 	if (err < 0) {
72 		cmp_connection_break(conn);
73 		return err;
74 	}
75 
76 	// Wait first callback.
77 	if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
78 		amdtp_stream_stop(stream);
79 		cmp_connection_break(conn);
80 		return -ETIMEDOUT;
81 	}
82 
83 	return 0;
84 }
85 
86 /*
87  * This function should be called before starting the stream or after stopping
88  * the streams.
89  */
90 static void
91 destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
92 {
93 	struct cmp_connection *conn;
94 
95 	if (stream == &efw->tx_stream)
96 		conn = &efw->out_conn;
97 	else
98 		conn = &efw->in_conn;
99 
100 	amdtp_stream_destroy(stream);
101 	cmp_connection_destroy(conn);
102 }
103 
104 static int
105 check_connection_used_by_others(struct snd_efw *efw, struct amdtp_stream *s)
106 {
107 	struct cmp_connection *conn;
108 	bool used;
109 	int err;
110 
111 	if (s == &efw->tx_stream)
112 		conn = &efw->out_conn;
113 	else
114 		conn = &efw->in_conn;
115 
116 	err = cmp_connection_check_used(conn, &used);
117 	if ((err >= 0) && used && !amdtp_stream_running(s)) {
118 		dev_err(&efw->unit->device,
119 			"Connection established by others: %cPCR[%d]\n",
120 			(conn->direction == CMP_OUTPUT) ? 'o' : 'i',
121 			conn->pcr_index);
122 		err = -EBUSY;
123 	}
124 
125 	return err;
126 }
127 
128 int snd_efw_stream_init_duplex(struct snd_efw *efw)
129 {
130 	int err;
131 
132 	err = init_stream(efw, &efw->tx_stream);
133 	if (err < 0)
134 		goto end;
135 	/* Fireworks transmits NODATA packets with TAG0. */
136 	efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0;
137 	/* Fireworks has its own meaning for dbc. */
138 	efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT;
139 	/* Fireworks reset dbc at bus reset. */
140 	efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK;
141 	/*
142 	 * But Recent firmwares starts packets with non-zero dbc.
143 	 * Driver version 5.7.6 installs firmware version 5.7.3.
144 	 */
145 	if (efw->is_fireworks3 &&
146 	    (efw->firmware_version == 0x5070000 ||
147 	     efw->firmware_version == 0x5070300 ||
148 	     efw->firmware_version == 0x5080000))
149 		efw->tx_stream.ctx_data.tx.first_dbc = 0x02;
150 	/* AudioFire9 always reports wrong dbs. */
151 	if (efw->is_af9)
152 		efw->tx_stream.flags |= CIP_WRONG_DBS;
153 	/* Firmware version 5.5 reports fixed interval for dbc. */
154 	if (efw->firmware_version == 0x5050000)
155 		efw->tx_stream.ctx_data.tx.dbc_interval = 8;
156 
157 	err = init_stream(efw, &efw->rx_stream);
158 	if (err < 0) {
159 		destroy_stream(efw, &efw->tx_stream);
160 		goto end;
161 	}
162 
163 	/* set IEC61883 compliant mode (actually not fully compliant...) */
164 	err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883);
165 	if (err < 0) {
166 		destroy_stream(efw, &efw->tx_stream);
167 		destroy_stream(efw, &efw->rx_stream);
168 	}
169 end:
170 	return err;
171 }
172 
173 static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
174 			  unsigned int rate, unsigned int mode)
175 {
176 	unsigned int pcm_channels;
177 	unsigned int midi_ports;
178 	struct cmp_connection *conn;
179 	int err;
180 
181 	if (stream == &efw->tx_stream) {
182 		pcm_channels = efw->pcm_capture_channels[mode];
183 		midi_ports = efw->midi_out_ports;
184 		conn = &efw->out_conn;
185 	} else {
186 		pcm_channels = efw->pcm_playback_channels[mode];
187 		midi_ports = efw->midi_in_ports;
188 		conn = &efw->in_conn;
189 	}
190 
191 	err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
192 					 midi_ports, false);
193 	if (err < 0)
194 		return err;
195 
196 	return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
197 }
198 
199 int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
200 {
201 	unsigned int curr_rate;
202 	int err;
203 
204 	// Considering JACK/FFADO streaming:
205 	// TODO: This can be removed hwdep functionality becomes popular.
206 	err = check_connection_used_by_others(efw, &efw->rx_stream);
207 	if (err < 0)
208 		return err;
209 
210 	// stop streams if rate is different.
211 	err = snd_efw_command_get_sampling_rate(efw, &curr_rate);
212 	if (err < 0)
213 		return err;
214 	if (rate == 0)
215 		rate = curr_rate;
216 	if (rate != curr_rate) {
217 		stop_stream(efw, &efw->tx_stream);
218 		stop_stream(efw, &efw->rx_stream);
219 
220 		cmp_connection_release(&efw->out_conn);
221 		cmp_connection_release(&efw->in_conn);
222 	}
223 
224 	if (efw->substreams_counter == 0 || rate != curr_rate) {
225 		unsigned int mode;
226 
227 		err = snd_efw_command_set_sampling_rate(efw, rate);
228 		if (err < 0)
229 			return err;
230 
231 		err = snd_efw_get_multiplier_mode(rate, &mode);
232 		if (err < 0)
233 			return err;
234 
235 		err = keep_resources(efw, &efw->tx_stream, rate, mode);
236 		if (err < 0)
237 			return err;
238 
239 		err = keep_resources(efw, &efw->rx_stream, rate, mode);
240 		if (err < 0) {
241 			cmp_connection_release(&efw->in_conn);
242 			return err;
243 		}
244 	}
245 
246 	return 0;
247 }
248 
249 int snd_efw_stream_start_duplex(struct snd_efw *efw)
250 {
251 	unsigned int rate;
252 	int err = 0;
253 
254 	// Need no substreams.
255 	if (efw->substreams_counter == 0)
256 		return -EIO;
257 
258 	err = snd_efw_command_get_sampling_rate(efw, &rate);
259 	if (err < 0)
260 		return err;
261 
262 	if (amdtp_streaming_error(&efw->rx_stream) ||
263 	    amdtp_streaming_error(&efw->tx_stream)) {
264 		stop_stream(efw, &efw->rx_stream);
265 		stop_stream(efw, &efw->tx_stream);
266 	}
267 
268 	/* master should be always running */
269 	if (!amdtp_stream_running(&efw->rx_stream)) {
270 		err = start_stream(efw, &efw->rx_stream, rate);
271 		if (err < 0) {
272 			dev_err(&efw->unit->device,
273 				"fail to start AMDTP master stream:%d\n", err);
274 			goto error;
275 		}
276 	}
277 
278 	if (!amdtp_stream_running(&efw->tx_stream)) {
279 		err = start_stream(efw, &efw->tx_stream, rate);
280 		if (err < 0) {
281 			dev_err(&efw->unit->device,
282 				"fail to start AMDTP slave stream:%d\n", err);
283 			goto error;
284 		}
285 	}
286 
287 	return 0;
288 error:
289 	stop_stream(efw, &efw->rx_stream);
290 	stop_stream(efw, &efw->tx_stream);
291 	return err;
292 }
293 
294 void snd_efw_stream_stop_duplex(struct snd_efw *efw)
295 {
296 	if (efw->substreams_counter == 0) {
297 		stop_stream(efw, &efw->tx_stream);
298 		stop_stream(efw, &efw->rx_stream);
299 
300 		cmp_connection_release(&efw->out_conn);
301 		cmp_connection_release(&efw->in_conn);
302 	}
303 }
304 
305 void snd_efw_stream_update_duplex(struct snd_efw *efw)
306 {
307 	if (cmp_connection_update(&efw->out_conn) < 0 ||
308 	    cmp_connection_update(&efw->in_conn) < 0) {
309 		stop_stream(efw, &efw->rx_stream);
310 		stop_stream(efw, &efw->tx_stream);
311 	} else {
312 		amdtp_stream_update(&efw->rx_stream);
313 		amdtp_stream_update(&efw->tx_stream);
314 	}
315 }
316 
317 void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
318 {
319 	destroy_stream(efw, &efw->rx_stream);
320 	destroy_stream(efw, &efw->tx_stream);
321 }
322 
323 void snd_efw_stream_lock_changed(struct snd_efw *efw)
324 {
325 	efw->dev_lock_changed = true;
326 	wake_up(&efw->hwdep_wait);
327 }
328 
329 int snd_efw_stream_lock_try(struct snd_efw *efw)
330 {
331 	int err;
332 
333 	spin_lock_irq(&efw->lock);
334 
335 	/* user land lock this */
336 	if (efw->dev_lock_count < 0) {
337 		err = -EBUSY;
338 		goto end;
339 	}
340 
341 	/* this is the first time */
342 	if (efw->dev_lock_count++ == 0)
343 		snd_efw_stream_lock_changed(efw);
344 	err = 0;
345 end:
346 	spin_unlock_irq(&efw->lock);
347 	return err;
348 }
349 
350 void snd_efw_stream_lock_release(struct snd_efw *efw)
351 {
352 	spin_lock_irq(&efw->lock);
353 
354 	if (WARN_ON(efw->dev_lock_count <= 0))
355 		goto end;
356 	if (--efw->dev_lock_count == 0)
357 		snd_efw_stream_lock_changed(efw);
358 end:
359 	spin_unlock_irq(&efw->lock);
360 }
361