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