diff options
Diffstat (limited to 'sound/firewire/fireworks/fireworks_stream.c')
-rw-r--r-- | sound/firewire/fireworks/fireworks_stream.c | 178 |
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); } } |