aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/fireworks/fireworks_stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/fireworks/fireworks_stream.c')
-rw-r--r--sound/firewire/fireworks/fireworks_stream.c178
1 files changed, 110 insertions, 68 deletions
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index 2d3095412427..e659a0b89ba5 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -42,7 +42,6 @@ end:
static void
stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
{
- amdtp_stream_pcm_abort(stream);
amdtp_stream_stop(stream);
if (stream == &efw->tx_stream)
@@ -51,54 +50,37 @@ stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
cmp_connection_break(&efw->in_conn);
}
-static int
-start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
- unsigned int sampling_rate)
+static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
+ unsigned int rate)
{
struct cmp_connection *conn;
- unsigned int mode, pcm_channels, midi_ports;
int err;
- err = snd_efw_get_multiplier_mode(sampling_rate, &mode);
- if (err < 0)
- goto end;
- if (stream == &efw->tx_stream) {
+ if (stream == &efw->tx_stream)
conn = &efw->out_conn;
- pcm_channels = efw->pcm_capture_channels[mode];
- midi_ports = efw->midi_out_ports;
- } else {
+ else
conn = &efw->in_conn;
- pcm_channels = efw->pcm_playback_channels[mode];
- midi_ports = efw->midi_in_ports;
- }
-
- err = amdtp_am824_set_parameters(stream, sampling_rate,
- pcm_channels, midi_ports, false);
- if (err < 0)
- goto end;
- /* establish connection via CMP */
- err = cmp_connection_establish(conn,
- amdtp_stream_get_max_payload(stream));
+ // Establish connection via CMP.
+ err = cmp_connection_establish(conn);
if (err < 0)
- goto end;
+ return err;
- /* start amdtp stream */
- err = amdtp_stream_start(stream,
- conn->resources.channel,
- conn->speed);
+ // Start amdtp stream.
+ err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
if (err < 0) {
- stop_stream(efw, stream);
- goto end;
+ cmp_connection_break(conn);
+ return err;
}
- /* wait first callback */
+ // Wait first callback.
if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
- stop_stream(efw, stream);
- err = -ETIMEDOUT;
+ amdtp_stream_stop(stream);
+ cmp_connection_break(conn);
+ return -ETIMEDOUT;
}
-end:
- return err;
+
+ return 0;
}
/*
@@ -164,13 +146,13 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw)
(efw->firmware_version == 0x5070000 ||
efw->firmware_version == 0x5070300 ||
efw->firmware_version == 0x5080000))
- efw->tx_stream.tx_first_dbc = 0x02;
+ efw->tx_stream.ctx_data.tx.first_dbc = 0x02;
/* AudioFire9 always reports wrong dbs. */
if (efw->is_af9)
efw->tx_stream.flags |= CIP_WRONG_DBS;
/* Firmware version 5.5 reports fixed interval for dbc. */
if (efw->firmware_version == 0x5050000)
- efw->tx_stream.tx_dbc_interval = 8;
+ efw->tx_stream.ctx_data.tx.dbc_interval = 8;
err = init_stream(efw, &efw->rx_stream);
if (err < 0) {
@@ -188,75 +170,135 @@ end:
return err;
}
-int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
+static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
+ unsigned int rate, unsigned int mode)
{
- unsigned int curr_rate;
- int err = 0;
+ unsigned int pcm_channels;
+ unsigned int midi_ports;
+ struct cmp_connection *conn;
+ int err;
- /* Need no substreams */
- if (efw->playback_substreams == 0 && efw->capture_substreams == 0)
- goto end;
+ if (stream == &efw->tx_stream) {
+ pcm_channels = efw->pcm_capture_channels[mode];
+ midi_ports = efw->midi_out_ports;
+ conn = &efw->out_conn;
+ } else {
+ pcm_channels = efw->pcm_playback_channels[mode];
+ midi_ports = efw->midi_in_ports;
+ conn = &efw->in_conn;
+ }
- /*
- * Considering JACK/FFADO streaming:
- * TODO: This can be removed hwdep functionality becomes popular.
- */
- err = check_connection_used_by_others(efw, &efw->rx_stream);
+ err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
+ midi_ports, false);
if (err < 0)
- goto end;
+ return err;
- /* packet queueing error */
- if (amdtp_streaming_error(&efw->tx_stream))
- stop_stream(efw, &efw->tx_stream);
- if (amdtp_streaming_error(&efw->rx_stream))
- stop_stream(efw, &efw->rx_stream);
+ return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
+}
+
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate)
+{
+ unsigned int curr_rate;
+ int err;
- /* stop streams if rate is different */
+ // Considering JACK/FFADO streaming:
+ // TODO: This can be removed hwdep functionality becomes popular.
+ err = check_connection_used_by_others(efw, &efw->rx_stream);
+ if (err < 0)
+ return err;
+
+ // stop streams if rate is different.
err = snd_efw_command_get_sampling_rate(efw, &curr_rate);
if (err < 0)
- goto end;
+ return err;
if (rate == 0)
rate = curr_rate;
if (rate != curr_rate) {
stop_stream(efw, &efw->tx_stream);
stop_stream(efw, &efw->rx_stream);
+
+ cmp_connection_release(&efw->out_conn);
+ cmp_connection_release(&efw->in_conn);
}
- /* master should be always running */
- if (!amdtp_stream_running(&efw->rx_stream)) {
+ if (efw->substreams_counter == 0 || rate != curr_rate) {
+ unsigned int mode;
+
err = snd_efw_command_set_sampling_rate(efw, rate);
if (err < 0)
- goto end;
+ return err;
+
+ err = snd_efw_get_multiplier_mode(rate, &mode);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(efw, &efw->tx_stream, rate, mode);
+ if (err < 0)
+ return err;
+ err = keep_resources(efw, &efw->rx_stream, rate, mode);
+ if (err < 0) {
+ cmp_connection_release(&efw->in_conn);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int snd_efw_stream_start_duplex(struct snd_efw *efw)
+{
+ unsigned int rate;
+ int err = 0;
+
+ // Need no substreams.
+ if (efw->substreams_counter == 0)
+ return -EIO;
+
+ err = snd_efw_command_get_sampling_rate(efw, &rate);
+ if (err < 0)
+ return err;
+
+ if (amdtp_streaming_error(&efw->rx_stream) ||
+ amdtp_streaming_error(&efw->tx_stream)) {
+ stop_stream(efw, &efw->rx_stream);
+ stop_stream(efw, &efw->tx_stream);
+ }
+
+ /* master should be always running */
+ if (!amdtp_stream_running(&efw->rx_stream)) {
err = start_stream(efw, &efw->rx_stream, rate);
if (err < 0) {
dev_err(&efw->unit->device,
"fail to start AMDTP master stream:%d\n", err);
- goto end;
+ goto error;
}
}
- /* start slave if needed */
- if (efw->capture_substreams > 0 &&
- !amdtp_stream_running(&efw->tx_stream)) {
+ if (!amdtp_stream_running(&efw->tx_stream)) {
err = start_stream(efw, &efw->tx_stream, rate);
if (err < 0) {
dev_err(&efw->unit->device,
"fail to start AMDTP slave stream:%d\n", err);
- stop_stream(efw, &efw->rx_stream);
+ goto error;
}
}
-end:
+
+ return 0;
+error:
+ stop_stream(efw, &efw->rx_stream);
+ stop_stream(efw, &efw->tx_stream);
return err;
}
void snd_efw_stream_stop_duplex(struct snd_efw *efw)
{
- if (efw->capture_substreams == 0) {
+ if (efw->substreams_counter == 0) {
stop_stream(efw, &efw->tx_stream);
+ stop_stream(efw, &efw->rx_stream);
- if (efw->playback_substreams == 0)
- stop_stream(efw, &efw->rx_stream);
+ cmp_connection_release(&efw->out_conn);
+ cmp_connection_release(&efw->in_conn);
}
}