1 // SPDX-License-Identifier: GPL-2.0-only
3 * fireworks_stream.c - a part of driver for Fireworks based devices
5 * Copyright (c) 2013-2014 Takashi Sakamoto
7 #include "./fireworks.h"
9 #define CALLBACK_TIMEOUT 100
12 init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
14 struct cmp_connection *conn;
15 enum cmp_direction c_dir;
16 enum amdtp_stream_direction s_dir;
19 if (stream == &efw->tx_stream) {
20 conn = &efw->out_conn;
22 s_dir = AMDTP_IN_STREAM;
26 s_dir = AMDTP_OUT_STREAM;
29 err = cmp_connection_init(conn, efw->unit, c_dir, 0);
33 err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING);
35 amdtp_stream_destroy(stream);
36 cmp_connection_destroy(conn);
43 stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
45 amdtp_stream_stop(stream);
47 if (stream == &efw->tx_stream)
48 cmp_connection_break(&efw->out_conn);
50 cmp_connection_break(&efw->in_conn);
53 static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
56 struct cmp_connection *conn;
59 if (stream == &efw->tx_stream)
60 conn = &efw->out_conn;
64 // Establish connection via CMP.
65 err = cmp_connection_establish(conn);
69 // Start amdtp stream.
70 err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
72 cmp_connection_break(conn);
76 // Wait first callback.
77 if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
78 amdtp_stream_stop(stream);
79 cmp_connection_break(conn);
87 * This function should be called before starting the stream or after stopping
91 destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
93 struct cmp_connection *conn;
95 if (stream == &efw->tx_stream)
96 conn = &efw->out_conn;
100 amdtp_stream_destroy(stream);
101 cmp_connection_destroy(conn);
105 check_connection_used_by_others(struct snd_efw *efw, struct amdtp_stream *s)
107 struct cmp_connection *conn;
111 if (s == &efw->tx_stream)
112 conn = &efw->out_conn;
114 conn = &efw->in_conn;
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',
128 int snd_efw_stream_init_duplex(struct snd_efw *efw)
132 err = init_stream(efw, &efw->tx_stream);
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;
142 * But Recent firmwares starts packets with non-zero dbc.
143 * Driver version 5.7.6 installs firmware version 5.7.3.
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. */
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;
157 err = init_stream(efw, &efw->rx_stream);
159 destroy_stream(efw, &efw->tx_stream);
163 /* set IEC61883 compliant mode (actually not fully compliant...) */
164 err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883);
166 destroy_stream(efw, &efw->tx_stream);
167 destroy_stream(efw, &efw->rx_stream);
173 static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
174 unsigned int rate, unsigned int mode)
176 unsigned int pcm_channels;
177 unsigned int midi_ports;
178 struct cmp_connection *conn;
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;
186 pcm_channels = efw->pcm_playback_channels[mode];
187 midi_ports = efw->midi_in_ports;
188 conn = &efw->in_conn;
191 err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
196 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
199 int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
201 unsigned int curr_rate;
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);
210 // stop streams if rate is different.
211 err = snd_efw_command_get_sampling_rate(efw, &curr_rate);
216 if (rate != curr_rate) {
217 stop_stream(efw, &efw->tx_stream);
218 stop_stream(efw, &efw->rx_stream);
220 cmp_connection_release(&efw->out_conn);
221 cmp_connection_release(&efw->in_conn);
224 if (efw->substreams_counter == 0 || rate != curr_rate) {
227 err = snd_efw_command_set_sampling_rate(efw, rate);
231 err = snd_efw_get_multiplier_mode(rate, &mode);
235 err = keep_resources(efw, &efw->tx_stream, rate, mode);
239 err = keep_resources(efw, &efw->rx_stream, rate, mode);
241 cmp_connection_release(&efw->in_conn);
249 int snd_efw_stream_start_duplex(struct snd_efw *efw)
254 // Need no substreams.
255 if (efw->substreams_counter == 0)
258 err = snd_efw_command_get_sampling_rate(efw, &rate);
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);
268 /* master should be always running */
269 if (!amdtp_stream_running(&efw->rx_stream)) {
270 err = start_stream(efw, &efw->rx_stream, rate);
272 dev_err(&efw->unit->device,
273 "fail to start AMDTP master stream:%d\n", err);
278 if (!amdtp_stream_running(&efw->tx_stream)) {
279 err = start_stream(efw, &efw->tx_stream, rate);
281 dev_err(&efw->unit->device,
282 "fail to start AMDTP slave stream:%d\n", err);
289 stop_stream(efw, &efw->rx_stream);
290 stop_stream(efw, &efw->tx_stream);
294 void snd_efw_stream_stop_duplex(struct snd_efw *efw)
296 if (efw->substreams_counter == 0) {
297 stop_stream(efw, &efw->tx_stream);
298 stop_stream(efw, &efw->rx_stream);
300 cmp_connection_release(&efw->out_conn);
301 cmp_connection_release(&efw->in_conn);
305 void snd_efw_stream_update_duplex(struct snd_efw *efw)
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);
312 amdtp_stream_update(&efw->rx_stream);
313 amdtp_stream_update(&efw->tx_stream);
317 void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
319 destroy_stream(efw, &efw->rx_stream);
320 destroy_stream(efw, &efw->tx_stream);
323 void snd_efw_stream_lock_changed(struct snd_efw *efw)
325 efw->dev_lock_changed = true;
326 wake_up(&efw->hwdep_wait);
329 int snd_efw_stream_lock_try(struct snd_efw *efw)
333 spin_lock_irq(&efw->lock);
335 /* user land lock this */
336 if (efw->dev_lock_count < 0) {
341 /* this is the first time */
342 if (efw->dev_lock_count++ == 0)
343 snd_efw_stream_lock_changed(efw);
346 spin_unlock_irq(&efw->lock);
350 void snd_efw_stream_lock_release(struct snd_efw *efw)
352 spin_lock_irq(&efw->lock);
354 if (WARN_ON(efw->dev_lock_count <= 0))
356 if (--efw->dev_lock_count == 0)
357 snd_efw_stream_lock_changed(efw);
359 spin_unlock_irq(&efw->lock);