[alsa-devel] [PATCH 00/19] ALSA: bebob/fireworks/oxfw: code refactoring toward rework for reservation of isochronous resources
Hi,
This patchset is a part of patches to reserve/release isochronous resources in pcm.hw_params/hw_free callbacks, like posted patchsets below: https://mailman.alsa-project.org/pipermail/alsa-devel/2019-June/150118.html https://mailman.alsa-project.org/pipermail/alsa-devel/2019-June/150863.html
However, in this patchset, I focus on code refactoring, due to kernel API implementation in firewire-lib.
The target devices supported by ALSA bebob, fireworks and oxfw drivers implements Connection Management Procedure (CMP) in IEC 61883-1. For CMP, the drivers use kernel API in firewire-lib. This API has private data including the data for isochronous resources, and its implementation is tightly-coupled to maintenance of isochronous resources.
This patchset is a preparation for future work to change the CMP implementation.
Takashi Sakamoto (19): ALSA: bebob: configure sampling transfer frequency in pcm.hw_params callback ALSA: bebob: don't set XRUN in stop streaming ALSA: bebob: obsolete useless member of private structure ALSA: bebob: code refactoring to initialize/destroy stream data ALSA: fireworks: unify substream counter ALSA: fireworks: code refactoring for rawmidi.open/close ALSA: fireworks: code refactoring for pcm.hw_params/hw_free ALSA: fireworks: configure sampling transfer frequency in pcm.hw_params callback ALSA: fireworks: configure stream parameters in pcm.hw_params callback ALSA: fireworks: don't set XRUN in stop streaming ALSA: oxfw: code refactoring for stop condition of packet streaming ALSA: oxfw: set packet parameter according to current configuration ALSA: oxfw: start duplex streams if supported ALSA: oxfw: break packet streaming at bus-reset handler ALSA: oxfw: expand stop procedure for packet streaming ALSA: oxfw: rename helper functions for duplex streams ALSA: oxfw: unify substreams counter ALSA: oxfw: configure packet format in pcm.hw_params callback ALSA: oxfw: configure stream parameter in pcm.hw_params callback
sound/firewire/bebob/bebob.h | 5 +- sound/firewire/bebob/bebob_midi.c | 22 +- sound/firewire/bebob/bebob_pcm.c | 22 +- sound/firewire/bebob/bebob_stream.c | 339 ++++++++++---------- sound/firewire/fireworks/fireworks.h | 6 +- sound/firewire/fireworks/fireworks_midi.c | 54 +--- sound/firewire/fireworks/fireworks_pcm.c | 59 +--- sound/firewire/fireworks/fireworks_stream.c | 159 +++++---- sound/firewire/oxfw/oxfw-midi.c | 22 +- sound/firewire/oxfw/oxfw-pcm.c | 34 +- sound/firewire/oxfw/oxfw-stream.c | 335 ++++++++++--------- sound/firewire/oxfw/oxfw.c | 17 +- sound/firewire/oxfw/oxfw.h | 22 +- 13 files changed, 553 insertions(+), 543 deletions(-)
This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks.
At present, several operations are done in pcm.prepare callback. To reduce load of the callback, This commit splits out an operation to set sampling transfer frequency in pcm.hw_params callback.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/bebob/bebob.h | 3 +- sound/firewire/bebob/bebob_midi.c | 22 +-- sound/firewire/bebob/bebob_pcm.c | 22 +-- sound/firewire/bebob/bebob_stream.c | 212 ++++++++++++++-------------- 4 files changed, 136 insertions(+), 123 deletions(-)
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index df1b1e94c43c..c30ed44aced9 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -218,7 +218,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob, enum snd_bebob_clock_type *src); int snd_bebob_stream_discover(struct snd_bebob *bebob); int snd_bebob_stream_init_duplex(struct snd_bebob *bebob); -int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate); +int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate); +int snd_bebob_stream_start_duplex(struct snd_bebob *bebob); void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob); void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index 3befa3eca6ef..e2d3cad39d28 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -15,15 +15,18 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
err = snd_bebob_stream_lock_try(bebob); if (err < 0) - goto end; + return err;
mutex_lock(&bebob->mutex); - bebob->substreams_counter++; - err = snd_bebob_stream_start_duplex(bebob, 0); + err = snd_bebob_stream_reserve_duplex(bebob, 0); + if (err >= 0) { + ++bebob->substreams_counter; + err = snd_bebob_stream_start_duplex(bebob); + } mutex_unlock(&bebob->mutex); if (err < 0) snd_bebob_stream_lock_release(bebob); -end: + return err; }
@@ -34,15 +37,18 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
err = snd_bebob_stream_lock_try(bebob); if (err < 0) - goto end; + return err;
mutex_lock(&bebob->mutex); - bebob->substreams_counter++; - err = snd_bebob_stream_start_duplex(bebob, 0); + err = snd_bebob_stream_reserve_duplex(bebob, 0); + if (err >= 0) { + ++bebob->substreams_counter; + err = snd_bebob_stream_start_duplex(bebob); + } mutex_unlock(&bebob->mutex); if (err < 0) snd_bebob_stream_lock_release(bebob); -end: + return err; }
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index ea9b86450580..71b6ede31bb2 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -198,12 +198,16 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream, return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + unsigned int rate = params_rate(hw_params); + mutex_lock(&bebob->mutex); - bebob->substreams_counter++; + err = snd_bebob_stream_reserve_duplex(bebob, rate); + if (err >= 0) + ++bebob->substreams_counter; mutex_unlock(&bebob->mutex); }
- return 0; + return err; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, @@ -218,12 +222,16 @@ pcm_playback_hw_params(struct snd_pcm_substream *substream, return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + unsigned int rate = params_rate(hw_params); + mutex_lock(&bebob->mutex); - bebob->substreams_counter++; + err = snd_bebob_stream_reserve_duplex(bebob, rate); + if (err >= 0) + ++bebob->substreams_counter; mutex_unlock(&bebob->mutex); }
- return 0; + return err; }
static int @@ -261,10 +269,9 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err;
- err = snd_bebob_stream_start_duplex(bebob, runtime->rate); + err = snd_bebob_stream_start_duplex(bebob); if (err >= 0) amdtp_stream_pcm_prepare(&bebob->tx_stream);
@@ -274,10 +281,9 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err;
- err = snd_bebob_stream_start_duplex(bebob, runtime->rate); + err = snd_bebob_stream_start_duplex(bebob); if (err >= 0) amdtp_stream_pcm_prepare(&bebob->rx_stream);
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 4d3034a68bdf..fcc93156d0b7 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -418,49 +418,28 @@ check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s) return err; }
-static int -make_both_connections(struct snd_bebob *bebob, unsigned int rate) +static int make_both_connections(struct snd_bebob *bebob) { - int index, pcm_channels, midi_channels, err = 0; + int err = 0;
if (bebob->connected) - goto end; - - /* confirm params for both streams */ - err = get_formation_index(rate, &index); - if (err < 0) - goto end; - pcm_channels = bebob->tx_stream_formations[index].pcm; - midi_channels = bebob->tx_stream_formations[index].midi; - err = amdtp_am824_set_parameters(&bebob->tx_stream, rate, - pcm_channels, midi_channels * 8, - false); - if (err < 0) - goto end; - - pcm_channels = bebob->rx_stream_formations[index].pcm; - midi_channels = bebob->rx_stream_formations[index].midi; - err = amdtp_am824_set_parameters(&bebob->rx_stream, rate, - pcm_channels, midi_channels * 8, - false); - if (err < 0) - goto end; + return 0;
- /* establish connections for both streams */ err = cmp_connection_establish(&bebob->out_conn, amdtp_stream_get_max_payload(&bebob->tx_stream)); if (err < 0) - goto end; + return err; + err = cmp_connection_establish(&bebob->in_conn, amdtp_stream_get_max_payload(&bebob->rx_stream)); if (err < 0) { cmp_connection_break(&bebob->out_conn); - goto end; + return err; }
bebob->connected = true; -end: - return err; + + return 0; }
static void @@ -484,8 +463,7 @@ destroy_both_connections(struct snd_bebob *bebob) }
static int -start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream, - unsigned int rate) +start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) { struct cmp_connection *conn; int err = 0; @@ -555,132 +533,154 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) return err; }
-int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate) +static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, + unsigned int rate, unsigned int index) { - const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate; - unsigned int curr_rate; - int err = 0; + struct snd_bebob_stream_formation *formation;
- /* Need no substreams */ - if (bebob->substreams_counter == 0) - goto end; + if (stream == &bebob->tx_stream) + formation = bebob->tx_stream_formations + index; + else + formation = bebob->rx_stream_formations + index;
- /* - * Considering JACK/FFADO streaming: - * TODO: This can be removed hwdep functionality becomes popular. - */ + return amdtp_am824_set_parameters(stream, rate, formation->pcm, + formation->midi, false); +} + +int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) +{ + unsigned int curr_rate; + int err; + + // Considering JACK/FFADO streaming: + // TODO: This can be removed hwdep functionality becomes popular. err = check_connection_used_by_others(bebob, &bebob->rx_stream); if (err < 0) - goto end; + return err;
- /* - * packet queueing error or detecting discontinuity - * - * At bus reset, connections should not be broken here. So streams need - * to be re-started. This is a reason to use SKIP_INIT_DBC_CHECK flag. - */ - if (amdtp_streaming_error(&bebob->rx_stream)) - amdtp_stream_stop(&bebob->rx_stream); - if (amdtp_streaming_error(&bebob->tx_stream)) + err = bebob->spec->rate->get(bebob, &curr_rate); + if (err < 0) + return err; + if (rate == 0) + rate = curr_rate; + if (curr_rate != rate) { amdtp_stream_stop(&bebob->tx_stream); - if (!amdtp_stream_running(&bebob->rx_stream) && - !amdtp_stream_running(&bebob->tx_stream)) + amdtp_stream_stop(&bebob->rx_stream); + break_both_connections(bebob); + }
- /* stop streams if rate is different */ - err = rate_spec->get(bebob, &curr_rate); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get sampling rate: %d\n", err); - goto end; + if (bebob->substreams_counter == 0 || curr_rate != rate) { + unsigned int index; + + // NOTE: + // If establishing connections at first, Yamaha GO46 + // (and maybe Terratec X24) don't generate sound. + // + // For firmware customized by M-Audio, refer to next NOTE. + err = bebob->spec->rate->set(bebob, rate); + if (err < 0) { + dev_err(&bebob->unit->device, + "fail to set sampling rate: %d\n", + err); + return err; + } + + err = get_formation_index(rate, &index); + if (err < 0) + return err; + + err = keep_resources(bebob, &bebob->tx_stream, rate, index); + if (err < 0) + return err; + + err = keep_resources(bebob, &bebob->rx_stream, rate, index); + if (err < 0) + return err; } - if (rate == 0) - rate = curr_rate; - if (rate != curr_rate) { + + return 0; +} + +int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) +{ + int err; + + // Need no substreams. + if (bebob->substreams_counter == 0) + return -EIO; + + // packet queueing error or detecting discontinuity + if (amdtp_streaming_error(&bebob->rx_stream) || + amdtp_streaming_error(&bebob->tx_stream)) { amdtp_stream_stop(&bebob->rx_stream); amdtp_stream_stop(&bebob->tx_stream); + break_both_connections(bebob); }
- /* master should be always running */ if (!amdtp_stream_running(&bebob->rx_stream)) { - /* - * NOTE: - * If establishing connections at first, Yamaha GO46 - * (and maybe Terratec X24) don't generate sound. - * - * For firmware customized by M-Audio, refer to next NOTE. - */ - if (bebob->maudio_special_quirk == NULL) { - err = rate_spec->set(bebob, rate); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to set sampling rate: %d\n", - err); - goto end; - } + unsigned int curr_rate; + + if (bebob->maudio_special_quirk) { + err = bebob->spec->rate->get(bebob, &curr_rate); + if (err < 0) + return err; }
- err = make_both_connections(bebob, rate); + err = make_both_connections(bebob); if (err < 0) - goto end; + return err;
- err = start_stream(bebob, &bebob->rx_stream, rate); + err = start_stream(bebob, &bebob->rx_stream); if (err < 0) { dev_err(&bebob->unit->device, "fail to run AMDTP master stream:%d\n", err); - break_both_connections(bebob); - goto end; + goto error; }
- /* - * NOTE: - * The firmware customized by M-Audio uses these commands to - * start transmitting stream. This is not usual way. - */ - if (bebob->maudio_special_quirk != NULL) { - err = rate_spec->set(bebob, rate); + // NOTE: + // The firmware customized by M-Audio uses these commands to + // start transmitting stream. This is not usual way. + if (bebob->maudio_special_quirk) { + err = bebob->spec->rate->set(bebob, curr_rate); if (err < 0) { dev_err(&bebob->unit->device, "fail to ensure sampling rate: %d\n", err); - amdtp_stream_stop(&bebob->rx_stream); - break_both_connections(bebob); - goto end; + goto error; } }
- /* wait first callback */ if (!amdtp_stream_wait_callback(&bebob->rx_stream, CALLBACK_TIMEOUT)) { amdtp_stream_stop(&bebob->rx_stream); break_both_connections(bebob); err = -ETIMEDOUT; - goto end; + goto error; } }
- /* start slave if needed */ if (!amdtp_stream_running(&bebob->tx_stream)) { - err = start_stream(bebob, &bebob->tx_stream, rate); + err = start_stream(bebob, &bebob->tx_stream); if (err < 0) { dev_err(&bebob->unit->device, "fail to run AMDTP slave stream:%d\n", err); - amdtp_stream_stop(&bebob->rx_stream); - break_both_connections(bebob); - goto end; + goto error; }
- /* wait first callback */ if (!amdtp_stream_wait_callback(&bebob->tx_stream, CALLBACK_TIMEOUT)) { - amdtp_stream_stop(&bebob->tx_stream); - amdtp_stream_stop(&bebob->rx_stream); - break_both_connections(bebob); err = -ETIMEDOUT; + goto error; } } -end: + + return 0; +error: + amdtp_stream_stop(&bebob->tx_stream); + amdtp_stream_stop(&bebob->rx_stream); + break_both_connections(bebob); return err; }
When stopping packet streaming, no need to stop PCM substream with XRUN state. This commit suppresses it.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/bebob/bebob_stream.c | 3 --- 1 file changed, 3 deletions(-)
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index fcc93156d0b7..d6e7f13ef42d 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -687,10 +687,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) { if (bebob->substreams_counter == 0) { - amdtp_stream_pcm_abort(&bebob->rx_stream); amdtp_stream_stop(&bebob->rx_stream); - - amdtp_stream_pcm_abort(&bebob->tx_stream); amdtp_stream_stop(&bebob->tx_stream);
break_both_connections(bebob);
The private structure of this driver has 'connected' member but nowadays it's useless. This commit removes it.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/bebob/bebob.h | 2 -- sound/firewire/bebob/bebob_stream.c | 7 ------- 2 files changed, 9 deletions(-)
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index c30ed44aced9..20ed2dbd8d61 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -93,8 +93,6 @@ struct snd_bebob { unsigned int midi_input_ports; unsigned int midi_output_ports;
- bool connected; - struct amdtp_stream tx_stream; struct amdtp_stream rx_stream; struct cmp_connection out_conn; diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index d6e7f13ef42d..c3cc31df49e0 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -422,9 +422,6 @@ static int make_both_connections(struct snd_bebob *bebob) { int err = 0;
- if (bebob->connected) - return 0; - err = cmp_connection_establish(&bebob->out_conn, amdtp_stream_get_max_payload(&bebob->tx_stream)); if (err < 0) @@ -437,8 +434,6 @@ static int make_both_connections(struct snd_bebob *bebob) return err; }
- bebob->connected = true; - return 0; }
@@ -448,8 +443,6 @@ break_both_connections(struct snd_bebob *bebob) cmp_connection_break(&bebob->in_conn); cmp_connection_break(&bebob->out_conn);
- bebob->connected = false; - /* These models seems to be in transition state for a longer time. */ if (bebob->maudio_special_quirk != NULL) msleep(200);
This commit changes helper functions to initialize/destroy stream data so that it has an argument for direction.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/bebob/bebob_stream.c | 121 ++++++++++++++-------------- 1 file changed, 61 insertions(+), 60 deletions(-)
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index c3cc31df49e0..6aab3dc99bef 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -376,24 +376,6 @@ map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s) return err; }
-static int -init_both_connections(struct snd_bebob *bebob) -{ - int err; - - err = cmp_connection_init(&bebob->in_conn, - bebob->unit, CMP_INPUT, 0); - if (err < 0) - goto end; - - err = cmp_connection_init(&bebob->out_conn, - bebob->unit, CMP_OUTPUT, 0); - if (err < 0) - cmp_connection_destroy(&bebob->in_conn); -end: - return err; -} - static int check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s) { @@ -448,13 +430,6 @@ break_both_connections(struct snd_bebob *bebob) msleep(200); }
-static void -destroy_both_connections(struct snd_bebob *bebob) -{ - cmp_connection_destroy(&bebob->in_conn); - cmp_connection_destroy(&bebob->out_conn); -} - static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) { @@ -481,49 +456,77 @@ start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) return err; }
-int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) +static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) { + enum amdtp_stream_direction dir_stream; + struct cmp_connection *conn; + enum cmp_direction dir_conn; int err;
- err = init_both_connections(bebob); + if (stream == &bebob->tx_stream) { + dir_stream = AMDTP_IN_STREAM; + conn = &bebob->out_conn; + dir_conn = CMP_OUTPUT; + } else { + dir_stream = AMDTP_OUT_STREAM; + conn = &bebob->in_conn; + dir_conn = CMP_INPUT; + } + + err = cmp_connection_init(conn, bebob->unit, dir_conn, 0); if (err < 0) - goto end; + return err;
- err = amdtp_am824_init(&bebob->tx_stream, bebob->unit, - AMDTP_IN_STREAM, CIP_BLOCKING); + err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING); if (err < 0) { - amdtp_stream_destroy(&bebob->tx_stream); - destroy_both_connections(bebob); - goto end; + cmp_connection_destroy(conn); + return err; }
- /* - * BeBoB v3 transfers packets with these qurks: - * - In the beginning of streaming, the value of dbc is incremented - * even if no data blocks are transferred. - * - The value of dbc is reset suddenly. - */ - if (bebob->version > 2) - bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC | - CIP_SKIP_DBC_ZERO_CHECK; + if (stream == &bebob->tx_stream) { + // BeBoB v3 transfers packets with these qurks: + // - In the beginning of streaming, the value of dbc is + // incremented even if no data blocks are transferred. + // - The value of dbc is reset suddenly. + if (bebob->version > 2) + bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC | + CIP_SKIP_DBC_ZERO_CHECK; + + // At high sampling rate, M-Audio special firmware transmits + // empty packet with the value of dbc incremented by 8 but the + // others are valid to IEC 61883-1. + if (bebob->maudio_special_quirk) + bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC; + }
- /* - * At high sampling rate, M-Audio special firmware transmits empty - * packet with the value of dbc incremented by 8 but the others are - * valid to IEC 61883-1. - */ - if (bebob->maudio_special_quirk) - bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC; + return 0; +} + +static void destroy_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) +{ + amdtp_stream_destroy(stream); + + if (stream == &bebob->tx_stream) + cmp_connection_destroy(&bebob->out_conn); + else + cmp_connection_destroy(&bebob->in_conn); +}
- err = amdtp_am824_init(&bebob->rx_stream, bebob->unit, - AMDTP_OUT_STREAM, CIP_BLOCKING); +int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) +{ + int err; + + err = init_stream(bebob, &bebob->tx_stream); + if (err < 0) + return err; + + err = init_stream(bebob, &bebob->rx_stream); if (err < 0) { - amdtp_stream_destroy(&bebob->tx_stream); - amdtp_stream_destroy(&bebob->rx_stream); - destroy_both_connections(bebob); + destroy_stream(bebob, &bebob->tx_stream); + return err; } -end: - return err; + + return 0; }
static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, @@ -693,10 +696,8 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) */ void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) { - amdtp_stream_destroy(&bebob->rx_stream); - amdtp_stream_destroy(&bebob->tx_stream); - - destroy_both_connections(bebob); + destroy_stream(bebob, &bebob->tx_stream); + destroy_stream(bebob, &bebob->rx_stream); }
/*
This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks.
It's inconvenient to handle two isochronous context separately each other. This commit unifies the counters to handle the two at the same time.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks.h | 3 +-- sound/firewire/fireworks/fireworks_midi.c | 8 +++--- sound/firewire/fireworks/fireworks_pcm.c | 8 +++--- sound/firewire/fireworks/fireworks_stream.c | 27 ++++++++------------- 4 files changed, 19 insertions(+), 27 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 9b19c7f05d57..42a73038ba4d 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -89,8 +89,7 @@ struct snd_efw { struct amdtp_stream rx_stream; struct cmp_connection out_conn; struct cmp_connection in_conn; - unsigned int capture_substreams; - unsigned int playback_substreams; + unsigned int substreams_counter;
/* hardware metering parameters */ unsigned int phys_out; diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index f5da2cd4ce42..7e78cdfe699e 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -18,7 +18,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) goto end;
mutex_lock(&efw->mutex); - efw->capture_substreams++; + ++efw->substreams_counter; err = snd_efw_stream_start_duplex(efw, 0); mutex_unlock(&efw->mutex); if (err < 0) @@ -38,7 +38,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) goto end;
mutex_lock(&efw->mutex); - efw->playback_substreams++; + ++efw->substreams_counter; err = snd_efw_stream_start_duplex(efw, 0); mutex_unlock(&efw->mutex); if (err < 0) @@ -52,7 +52,7 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream) struct snd_efw *efw = substream->rmidi->private_data;
mutex_lock(&efw->mutex); - efw->capture_substreams--; + --efw->substreams_counter; snd_efw_stream_stop_duplex(efw); mutex_unlock(&efw->mutex);
@@ -65,7 +65,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) struct snd_efw *efw = substream->rmidi->private_data;
mutex_lock(&efw->mutex); - efw->playback_substreams--; + --efw->substreams_counter; snd_efw_stream_stop_duplex(efw); mutex_unlock(&efw->mutex);
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index aed566d82726..a66f6a381dac 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -232,7 +232,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - efw->capture_substreams++; + ++efw->substreams_counter; mutex_unlock(&efw->mutex); }
@@ -251,7 +251,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - efw->playback_substreams++; + ++efw->substreams_counter; mutex_unlock(&efw->mutex); }
@@ -264,7 +264,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - efw->capture_substreams--; + --efw->substreams_counter; mutex_unlock(&efw->mutex); }
@@ -278,7 +278,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - efw->playback_substreams--; + --efw->substreams_counter; mutex_unlock(&efw->mutex); }
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 74e122e6e68a..2df39befcde0 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -194,9 +194,9 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) unsigned int curr_rate; int err = 0;
- /* Need no substreams */ - if (efw->playback_substreams == 0 && efw->capture_substreams == 0) - goto end; + // Need no substreams. + if (efw->substreams_counter == 0) + return -EIO;
/* * Considering JACK/FFADO streaming: @@ -206,19 +206,15 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) if (err < 0) goto end;
- /* 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); - /* stop streams if rate is different */ err = snd_efw_command_get_sampling_rate(efw, &curr_rate); if (err < 0) goto end; if (rate == 0) rate = curr_rate; - if (rate != curr_rate) { + if (rate != curr_rate || + amdtp_streaming_error(&efw->tx_stream) || + amdtp_streaming_error(&efw->rx_stream)) { stop_stream(efw, &efw->tx_stream); stop_stream(efw, &efw->rx_stream); } @@ -237,13 +233,12 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) } }
- /* 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->tx_stream); stop_stream(efw, &efw->rx_stream); } } @@ -253,11 +248,9 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
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); - - if (efw->playback_substreams == 0) - stop_stream(efw, &efw->rx_stream); + stop_stream(efw, &efw->rx_stream); } }
Two sets of callbacks for rawmidi.open/close but they have the same codes. This commit unifies each of the callbacks.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_midi.c | 45 +++-------------------- 1 file changed, 6 insertions(+), 39 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index 7e78cdfe699e..ee5dc7be70b6 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -8,7 +8,7 @@ */ #include "fireworks.h"
-static int midi_capture_open(struct snd_rawmidi_substream *substream) +static int midi_open(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; int err; @@ -23,44 +23,11 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); - end: return err; }
-static int midi_playback_open(struct snd_rawmidi_substream *substream) -{ - struct snd_efw *efw = substream->rmidi->private_data; - int err; - - err = snd_efw_stream_lock_try(efw); - if (err < 0) - goto end; - - mutex_lock(&efw->mutex); - ++efw->substreams_counter; - err = snd_efw_stream_start_duplex(efw, 0); - mutex_unlock(&efw->mutex); - if (err < 0) - snd_efw_stream_lock_release(efw); -end: - return err; -} - -static int midi_capture_close(struct snd_rawmidi_substream *substream) -{ - struct snd_efw *efw = substream->rmidi->private_data; - - mutex_lock(&efw->mutex); - --efw->substreams_counter; - snd_efw_stream_stop_duplex(efw); - mutex_unlock(&efw->mutex); - - snd_efw_stream_lock_release(efw); - return 0; -} - -static int midi_playback_close(struct snd_rawmidi_substream *substream) +static int midi_close(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data;
@@ -121,13 +88,13 @@ static void set_midi_substream_names(struct snd_efw *efw, int snd_efw_create_midi_devices(struct snd_efw *efw) { static const struct snd_rawmidi_ops capture_ops = { - .open = midi_capture_open, - .close = midi_capture_close, + .open = midi_open, + .close = midi_close, .trigger = midi_capture_trigger, }; static const struct snd_rawmidi_ops playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, + .open = midi_open, + .close = midi_close, .trigger = midi_playback_trigger, }; struct snd_rawmidi *rmidi;
Two sets of callbacks for pcm.hw_params/hw_free but they have the same codes. This commit unifies each of the callbacks.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_pcm.c | 45 ++++-------------------- 1 file changed, 6 insertions(+), 39 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index a66f6a381dac..398a6ad04c5f 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -219,7 +219,7 @@ static int pcm_close(struct snd_pcm_substream *substream) return 0; }
-static int pcm_capture_hw_params(struct snd_pcm_substream *substream, +static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_efw *efw = substream->private_data; @@ -238,41 +238,8 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return 0; } -static int pcm_playback_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_efw *efw = substream->private_data; - int err; - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { - mutex_lock(&efw->mutex); - ++efw->substreams_counter; - mutex_unlock(&efw->mutex); - } - - return 0; -} - -static int pcm_capture_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_efw *efw = substream->private_data;
- if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { - mutex_lock(&efw->mutex); - --efw->substreams_counter; - mutex_unlock(&efw->mutex); - } - - snd_efw_stream_stop_duplex(efw); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} -static int pcm_playback_hw_free(struct snd_pcm_substream *substream) +static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data;
@@ -378,8 +345,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .open = pcm_open, .close = pcm_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_capture_hw_params, - .hw_free = pcm_capture_hw_free, + .hw_params = pcm_hw_params, + .hw_free = pcm_hw_free, .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, @@ -390,8 +357,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .open = pcm_open, .close = pcm_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_playback_hw_params, - .hw_free = pcm_playback_hw_free, + .hw_params = pcm_hw_params, + .hw_free = pcm_hw_free, .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer,
This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks.
At present, several operations are done in pcm.prepare callback. To reduce load of the callback, This commit splits out an operation to set sampling transfer frequency in pcm.hw_params callback.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks.h | 3 +- sound/firewire/fireworks/fireworks_midi.c | 7 ++- sound/firewire/fireworks/fireworks_pcm.c | 14 +++-- sound/firewire/fireworks/fireworks_stream.c | 65 +++++++++++++-------- 4 files changed, 57 insertions(+), 32 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 42a73038ba4d..0c1802aa7923 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -206,7 +206,8 @@ int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate); int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate);
int snd_efw_stream_init_duplex(struct snd_efw *efw); -int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate); +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate); +int snd_efw_stream_start_duplex(struct snd_efw *efw); void snd_efw_stream_stop_duplex(struct snd_efw *efw); void snd_efw_stream_update_duplex(struct snd_efw *efw); void snd_efw_stream_destroy_duplex(struct snd_efw *efw); diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index ee5dc7be70b6..6d3d942e2dce 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -18,8 +18,11 @@ static int midi_open(struct snd_rawmidi_substream *substream) goto end;
mutex_lock(&efw->mutex); - ++efw->substreams_counter; - err = snd_efw_stream_start_duplex(efw, 0); + err = snd_efw_stream_reserve_duplex(efw, 0); + if (err >= 0) { + ++efw->substreams_counter; + err = snd_efw_stream_start_duplex(efw); + } mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 398a6ad04c5f..287fc05d5917 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -231,12 +231,16 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + unsigned int rate = params_rate(hw_params); + mutex_lock(&efw->mutex); - ++efw->substreams_counter; + err = snd_efw_stream_reserve_duplex(efw, rate); + if (err >= 0) + ++efw->substreams_counter; mutex_unlock(&efw->mutex); }
- return 0; + return err; }
static int pcm_hw_free(struct snd_pcm_substream *substream) @@ -257,10 +261,9 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) static int pcm_capture_prepare(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err;
- err = snd_efw_stream_start_duplex(efw, runtime->rate); + err = snd_efw_stream_start_duplex(efw); if (err >= 0) amdtp_stream_pcm_prepare(&efw->tx_stream);
@@ -269,10 +272,9 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) static int pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err;
- err = snd_efw_stream_start_duplex(efw, runtime->rate); + err = snd_efw_stream_start_duplex(efw); if (err >= 0) amdtp_stream_pcm_prepare(&efw->rx_stream);
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 2df39befcde0..e1ebead583e9 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -189,47 +189,63 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw) return err; }
-int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) { unsigned int curr_rate; - int err = 0; - - // Need no substreams. - if (efw->substreams_counter == 0) - return -EIO; + int err;
- /* - * Considering JACK/FFADO streaming: - * TODO: This can be removed hwdep functionality becomes popular. - */ + // 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) - goto end; + return err;
- /* stop streams if rate is different */ + // 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 || - amdtp_streaming_error(&efw->tx_stream) || - amdtp_streaming_error(&efw->rx_stream)) { + if (rate != curr_rate) { stop_stream(efw, &efw->tx_stream); stop_stream(efw, &efw->rx_stream); }
- /* master should be always running */ - if (!amdtp_stream_running(&efw->rx_stream)) { + if (efw->substreams_counter == 0 || rate != curr_rate) { err = snd_efw_command_set_sampling_rate(efw, rate); if (err < 0) - goto end; + 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; } }
@@ -238,11 +254,14 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) if (err < 0) { dev_err(&efw->unit->device, "fail to start AMDTP slave stream:%d\n", err); - stop_stream(efw, &efw->tx_stream); - 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; }
This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks.
This commit splits out an operation to configure stream parameters into pcm.hw_params callback. In pcm.prepare callback, establishing connections and start isochronous contexts.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_stream.c | 82 ++++++++++++--------- 1 file changed, 49 insertions(+), 33 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index e1ebead583e9..1abc15760513 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -52,54 +52,38 @@ 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 */ + // Establish connection via CMP. err = cmp_connection_establish(conn, - amdtp_stream_get_max_payload(stream)); + amdtp_stream_get_max_payload(stream)); 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; }
/* @@ -189,6 +173,24 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw) return err; }
+static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream, + unsigned int rate, unsigned int mode) +{ + unsigned int pcm_channels; + unsigned int midi_ports; + + if (stream == &efw->tx_stream) { + pcm_channels = efw->pcm_capture_channels[mode]; + midi_ports = efw->midi_out_ports; + } else { + pcm_channels = efw->pcm_playback_channels[mode]; + midi_ports = efw->midi_in_ports; + } + + return amdtp_am824_set_parameters(stream, rate, pcm_channels, + midi_ports, false); +} + int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) { unsigned int curr_rate; @@ -212,9 +214,23 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) }
if (efw->substreams_counter == 0 || rate != curr_rate) { + unsigned int mode; + err = snd_efw_command_set_sampling_rate(efw, rate); if (err < 0) 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) + return err; }
return 0;
When stopping packet streaming, no need to stop PCM substream with XRUN state. This commit suppresses it.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_stream.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 1abc15760513..61342c49dc38 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -43,7 +43,6 @@ init_stream(struct snd_efw *efw, struct amdtp_stream *stream) 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)
This commit unifies stop condition due to queueing error and unmatched state of the target device.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index f230a9e44c3c..34ff673e6ff8 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -288,10 +288,6 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, if (err < 0) goto end;
- /* packet queueing error */ - if (amdtp_streaming_error(stream)) - stop_stream(oxfw, stream); - err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); if (err < 0) goto end; @@ -300,7 +296,8 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, if (pcm_channels == 0) pcm_channels = formation.pcm;
- if ((formation.rate != rate) || (formation.pcm != pcm_channels)) { + if (formation.rate != rate || formation.pcm != pcm_channels || + amdtp_streaming_error(stream)) { if (opposite != NULL) { err = check_connection_used_by_others(oxfw, opposite); if (err < 0)
After a call of pcm.hw_params, the state of target device is expected for applications. This commit retrieves the state and start packet streaming.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 34ff673e6ff8..1691fdc1a575 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -112,51 +112,51 @@ static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) cmp_connection_break(&oxfw->in_conn); }
-static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels) +static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { u8 **formats; + enum avc_general_plug_dir dir; struct cmp_connection *conn; struct snd_oxfw_stream_formation formation; - unsigned int i, midi_ports; + int i; int err;
if (stream == &oxfw->rx_stream) { + dir = AVC_GENERAL_PLUG_DIR_IN; formats = oxfw->rx_stream_formats; conn = &oxfw->in_conn; } else { + dir = AVC_GENERAL_PLUG_DIR_OUT; formats = oxfw->tx_stream_formats; conn = &oxfw->out_conn; }
- /* Get stream format */ + err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); + if (err < 0) + return err; + for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { + struct snd_oxfw_stream_formation fmt; + if (formats[i] == NULL) break;
- err = snd_oxfw_stream_parse_format(formats[i], &formation); + err = snd_oxfw_stream_parse_format(formats[i], &fmt); if (err < 0) - goto end; - if (rate != formation.rate) - continue; - if (pcm_channels == 0 || pcm_channels == formation.pcm) + return err; + if (fmt.rate == formation.rate && fmt.pcm == formation.pcm && + fmt.midi == formation.midi) break; } - if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) { - err = -EINVAL; - goto end; - } + if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) + return -EINVAL;
- pcm_channels = formation.pcm; - midi_ports = formation.midi * 8; + // The stream should have one pcm channels at least. + if (formation.pcm == 0) + return -EINVAL;
- /* The stream should have one pcm channels at least */ - if (pcm_channels == 0) { - err = -EINVAL; - goto end; - } - err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports, - false); + err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm, + formation.midi * 8, false); if (err < 0) goto end;
@@ -316,7 +316,7 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, /* Start opposite stream if needed. */ if (opposite && !amdtp_stream_running(opposite) && (opposite_substreams > 0)) { - err = start_stream(oxfw, opposite, rate, 0); + err = start_stream(oxfw, opposite); if (err < 0) { dev_err(&oxfw->unit->device, "fail to restart stream: %d\n", err); @@ -327,7 +327,7 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
/* Start requested stream. */ if (!amdtp_stream_running(stream)) { - err = start_stream(oxfw, stream, rate, pcm_channels); + err = start_stream(oxfw, stream); if (err < 0) dev_err(&oxfw->unit->device, "fail to start stream: %d\n", err);
It's inconvenient to handle two isochronous context separately each other. This commit unifies the counters to handle the two at the same time.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 102 ++++++++++++++---------------- 1 file changed, 49 insertions(+), 53 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 1691fdc1a575..bb4ba6c196ea 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -254,96 +254,92 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, unsigned int rate, unsigned int pcm_channels) { - struct amdtp_stream *opposite; struct snd_oxfw_stream_formation formation; enum avc_general_plug_dir dir; - unsigned int substreams, opposite_substreams; int err = 0;
- if (stream == &oxfw->tx_stream) { - substreams = oxfw->capture_substreams; - opposite = &oxfw->rx_stream; - opposite_substreams = oxfw->playback_substreams; - dir = AVC_GENERAL_PLUG_DIR_OUT; - } else { - substreams = oxfw->playback_substreams; - opposite_substreams = oxfw->capture_substreams; + if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) + return -EIO;
- if (oxfw->has_output) - opposite = &oxfw->rx_stream; - else - opposite = NULL; - - dir = AVC_GENERAL_PLUG_DIR_IN; + // Considering JACK/FFADO streaming: + // TODO: This can be removed hwdep functionality becomes popular. + err = check_connection_used_by_others(oxfw, &oxfw->rx_stream); + if (err < 0) + return err; + if (oxfw->has_output) { + err = check_connection_used_by_others(oxfw, &oxfw->tx_stream); + if (err < 0) + return err; }
- if (substreams == 0) - goto end; - - /* - * Considering JACK/FFADO streaming: - * TODO: This can be removed hwdep functionality becomes popular. - */ - err = check_connection_used_by_others(oxfw, stream); - if (err < 0) - goto end; + if (stream == &oxfw->tx_stream) + dir = AVC_GENERAL_PLUG_DIR_OUT; + else + dir = AVC_GENERAL_PLUG_DIR_IN;
err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); if (err < 0) - goto end; + return err; if (rate == 0) rate = formation.rate; if (pcm_channels == 0) pcm_channels = formation.pcm;
if (formation.rate != rate || formation.pcm != pcm_channels || - amdtp_streaming_error(stream)) { - if (opposite != NULL) { - err = check_connection_used_by_others(oxfw, opposite); - if (err < 0) - goto end; - stop_stream(oxfw, opposite); - } - stop_stream(oxfw, stream); + amdtp_streaming_error(&oxfw->rx_stream) || + amdtp_streaming_error(&oxfw->tx_stream)) { + stop_stream(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + stop_stream(oxfw, &oxfw->tx_stream);
err = set_stream_format(oxfw, stream, rate, pcm_channels); if (err < 0) { dev_err(&oxfw->unit->device, "fail to set stream format: %d\n", err); - goto end; + return err; + } + } + + if (!amdtp_stream_running(&oxfw->rx_stream)) { + err = start_stream(oxfw, &oxfw->rx_stream); + if (err < 0) { + dev_err(&oxfw->unit->device, + "fail to start rx stream: %d\n", err); + goto error; } + }
- /* Start opposite stream if needed. */ - if (opposite && !amdtp_stream_running(opposite) && - (opposite_substreams > 0)) { - err = start_stream(oxfw, opposite); + if (oxfw->has_output) { + if (!amdtp_stream_running(&oxfw->tx_stream)) { + err = start_stream(oxfw, &oxfw->tx_stream); if (err < 0) { dev_err(&oxfw->unit->device, - "fail to restart stream: %d\n", err); - goto end; + "fail to start tx stream: %d\n", err); + goto error; } } }
- /* Start requested stream. */ - if (!amdtp_stream_running(stream)) { - err = start_stream(oxfw, stream); - if (err < 0) - dev_err(&oxfw->unit->device, - "fail to start stream: %d\n", err); + return 0; +error: + stop_stream(oxfw, &oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn); + if (oxfw->has_output) { + stop_stream(oxfw, &oxfw->tx_stream); + cmp_connection_break(&oxfw->out_conn); } -end: return err; }
void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { - if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) || - ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0))) - return; + if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) { + stop_stream(oxfw, &oxfw->rx_stream);
- stop_stream(oxfw, stream); + if (oxfw->has_output) + stop_stream(oxfw, &oxfw->tx_stream); + } }
/*
In most cases, recovery from bus reset is not successful. This commit aborts packet streaming in bus reset handler.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index bb4ba6c196ea..806a7fded99d 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -363,17 +363,10 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { - struct cmp_connection *conn; - - if (stream == &oxfw->tx_stream) - conn = &oxfw->out_conn; - else - conn = &oxfw->in_conn; + stop_stream(oxfw, &oxfw->rx_stream);
- if (cmp_connection_update(conn) < 0) - stop_stream(oxfw, stream); - else - amdtp_stream_update(stream); + if (oxfw->has_output) + stop_stream(oxfw, &oxfw->tx_stream); }
int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
The helper function stop packet streaming is not enough useful. This commit obsoletes it and expands its code.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 68 ++++++++++++++++--------------- 1 file changed, 35 insertions(+), 33 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 806a7fded99d..561ceb09d927 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -101,17 +101,6 @@ static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s, return 0; }
-static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) -{ - amdtp_stream_pcm_abort(stream); - amdtp_stream_stop(stream); - - if (stream == &oxfw->tx_stream) - cmp_connection_break(&oxfw->out_conn); - else - cmp_connection_break(&oxfw->in_conn); -} - static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { u8 **formats; @@ -158,28 +147,27 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm, formation.midi * 8, false); if (err < 0) - goto end; + return err;
err = cmp_connection_establish(conn, amdtp_stream_get_max_payload(stream)); if (err < 0) - goto end; + return err;
- err = amdtp_stream_start(stream, - conn->resources.channel, - conn->speed); + err = amdtp_stream_start(stream, conn->resources.channel, conn->speed); if (err < 0) { cmp_connection_break(conn); - goto end; + return err; }
- /* Wait first packet */ + // Wait first packet. if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { - stop_stream(oxfw, stream); - err = -ETIMEDOUT; + amdtp_stream_stop(stream); + cmp_connection_break(conn); + return -ETIMEDOUT; } -end: - return err; + + return 0; }
static int check_connection_used_by_others(struct snd_oxfw *oxfw, @@ -288,9 +276,13 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, if (formation.rate != rate || formation.pcm != pcm_channels || amdtp_streaming_error(&oxfw->rx_stream) || amdtp_streaming_error(&oxfw->tx_stream)) { - stop_stream(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - stop_stream(oxfw, &oxfw->tx_stream); + amdtp_stream_stop(&oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn); + + if (oxfw->has_output) { + amdtp_stream_stop(&oxfw->tx_stream); + cmp_connection_break(&oxfw->out_conn); + }
err = set_stream_format(oxfw, stream, rate, pcm_channels); if (err < 0) { @@ -322,10 +314,10 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
return 0; error: - stop_stream(oxfw, &oxfw->rx_stream); + amdtp_stream_stop(&oxfw->rx_stream); cmp_connection_break(&oxfw->in_conn); if (oxfw->has_output) { - stop_stream(oxfw, &oxfw->tx_stream); + amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn); } return err; @@ -335,10 +327,13 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) { - stop_stream(oxfw, &oxfw->rx_stream); + amdtp_stream_stop(&oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn);
- if (oxfw->has_output) - stop_stream(oxfw, &oxfw->tx_stream); + if (oxfw->has_output) { + amdtp_stream_stop(&oxfw->tx_stream); + cmp_connection_break(&oxfw->out_conn); + } } }
@@ -363,10 +358,17 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { - stop_stream(oxfw, &oxfw->rx_stream); + amdtp_stream_stop(&oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn);
- if (oxfw->has_output) - stop_stream(oxfw, &oxfw->tx_stream); + amdtp_stream_pcm_abort(&oxfw->rx_stream); + + if (oxfw->has_output) { + amdtp_stream_stop(&oxfw->tx_stream); + cmp_connection_break(&oxfw->out_conn); + + amdtp_stream_pcm_abort(&oxfw->tx_stream); + } }
int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
In former commits, ALSA oxfw driver handles two isochronous contexts at the same time, except for some devices which supports one endpoint of isochronous packet stream.
This commit renames some helper functions so that they handles duplex streams.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-midi.c | 8 ++--- sound/firewire/oxfw/oxfw-pcm.c | 12 +++---- sound/firewire/oxfw/oxfw-stream.c | 60 ++++++++++++++++++++----------- sound/firewire/oxfw/oxfw.c | 17 ++------- sound/firewire/oxfw/oxfw.h | 14 +++----- 5 files changed, 58 insertions(+), 53 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index b7bbd77dfff1..31352cebdfe9 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -20,7 +20,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex);
oxfw->capture_substreams++; - err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, 0, 0); + err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->tx_stream, 0, 0);
mutex_unlock(&oxfw->mutex);
@@ -42,7 +42,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex);
oxfw->playback_substreams++; - err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, 0, 0); + err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->rx_stream, 0, 0);
mutex_unlock(&oxfw->mutex);
@@ -59,7 +59,7 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex);
oxfw->capture_substreams--; - snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream); + snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
@@ -74,7 +74,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) mutex_lock(&oxfw->mutex);
oxfw->playback_substreams--; - snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream); + snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index b3f6503dd34d..253d79607bdf 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -255,7 +255,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) oxfw->capture_substreams--;
- snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream); + snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
@@ -270,7 +270,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) oxfw->playback_substreams--;
- snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream); + snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex);
@@ -284,8 +284,8 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) int err;
mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, - runtime->rate, runtime->channels); + err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->tx_stream, + runtime->rate, runtime->channels); mutex_unlock(&oxfw->mutex); if (err < 0) goto end; @@ -301,8 +301,8 @@ static int pcm_playback_prepare(struct snd_pcm_substream *substream) int err;
mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, - runtime->rate, runtime->channels); + err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->rx_stream, + runtime->rate, runtime->channels); mutex_unlock(&oxfw->mutex); if (err < 0) goto end; diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 561ceb09d927..52cf815c27f7 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -194,8 +194,7 @@ static int check_connection_used_by_others(struct snd_oxfw *oxfw, return err; }
-int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream) +static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { struct cmp_connection *conn; enum cmp_direction c_dir; @@ -214,13 +213,12 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
err = cmp_connection_init(conn, oxfw->unit, c_dir, 0); if (err < 0) - goto end; + return err;
err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING); if (err < 0) { - amdtp_stream_destroy(stream); cmp_connection_destroy(conn); - goto end; + return err; }
/* @@ -234,13 +232,13 @@ int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw, if (oxfw->wrong_dbs) oxfw->tx_stream.flags |= CIP_WRONG_DBS; } -end: - return err; + + return 0; }
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels) +int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, + struct amdtp_stream *stream, + unsigned int rate, unsigned int pcm_channels) { struct snd_oxfw_stream_formation formation; enum avc_general_plug_dir dir; @@ -323,8 +321,7 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, return err; }
-void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream) +void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw) { if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) { amdtp_stream_stop(&oxfw->rx_stream); @@ -337,12 +334,7 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, } }
-/* - * This function should be called before starting the stream or after stopping - * the streams. - */ -void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream) +static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { struct cmp_connection *conn;
@@ -355,8 +347,36 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, cmp_connection_destroy(conn); }
-void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream) +int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw) +{ + int err; + + err = init_stream(oxfw, &oxfw->rx_stream); + if (err < 0) + return err; + + if (oxfw->has_output) { + err = init_stream(oxfw, &oxfw->tx_stream); + if (err < 0) { + destroy_stream(oxfw, &oxfw->rx_stream); + return err; + } + } + + return 0; +} + +// This function should be called before starting the stream or after stopping +// the streams. +void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw) +{ + destroy_stream(oxfw, &oxfw->rx_stream); + + if (oxfw->has_output) + destroy_stream(oxfw, &oxfw->tx_stream); +} + +void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw) { amdtp_stream_stop(&oxfw->rx_stream); cmp_connection_break(&oxfw->in_conn); diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 3d27f3378d5d..2de26a9987f8 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -118,9 +118,7 @@ static void oxfw_card_free(struct snd_card *card) { struct snd_oxfw *oxfw = card->private_data;
- snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); + snd_oxfw_stream_destroy_duplex(oxfw); }
static int detect_quirks(struct snd_oxfw *oxfw) @@ -211,14 +209,9 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error;
- err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream); + err = snd_oxfw_stream_init_duplex(oxfw); if (err < 0) goto error; - if (oxfw->has_output) { - err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream); - if (err < 0) - goto error; - }
err = snd_oxfw_create_pcm(oxfw); if (err < 0) @@ -285,11 +278,7 @@ static void oxfw_bus_reset(struct fw_unit *unit)
if (oxfw->registered) { mutex_lock(&oxfw->mutex); - - snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream); - if (oxfw->has_output) - snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream); - + snd_oxfw_stream_update_duplex(oxfw); mutex_unlock(&oxfw->mutex);
if (oxfw->entry->vendor_id == OUI_STANTON) diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index d54d4a9ac4a1..911a452f94db 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -99,17 +99,13 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate, enum avc_general_plug_dir dir, unsigned short pid);
-int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream); -int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, +int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw); +int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, unsigned int rate, unsigned int pcm_channels); -void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream); -void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream); -void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream); +void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw); +void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw); +void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw);
struct snd_oxfw_stream_formation { unsigned int rate;
In former commits, two isochronous contexts are handles at the same time. This commit unifies stream counters to obsolete them.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-midi.c | 8 ++++---- sound/firewire/oxfw/oxfw-pcm.c | 8 ++++---- sound/firewire/oxfw/oxfw-stream.c | 4 ++-- sound/firewire/oxfw/oxfw.h | 3 +-- 4 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 31352cebdfe9..092493497f1a 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -19,7 +19,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->capture_substreams++; + ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->tx_stream, 0, 0);
mutex_unlock(&oxfw->mutex); @@ -41,7 +41,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->playback_substreams++; + ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->rx_stream, 0, 0);
mutex_unlock(&oxfw->mutex); @@ -58,7 +58,7 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->capture_substreams--; + --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex); @@ -73,7 +73,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- oxfw->playback_substreams--; + --oxfw->substreams_count; snd_oxfw_stream_stop_duplex(oxfw);
mutex_unlock(&oxfw->mutex); diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 253d79607bdf..79c8e514bed9 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -220,7 +220,7 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&oxfw->mutex); - oxfw->capture_substreams++; + ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); }
@@ -239,7 +239,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&oxfw->mutex); - oxfw->playback_substreams++; + ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); }
@@ -253,7 +253,7 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) mutex_lock(&oxfw->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - oxfw->capture_substreams--; + --oxfw->substreams_count;
snd_oxfw_stream_stop_duplex(oxfw);
@@ -268,7 +268,7 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) mutex_lock(&oxfw->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - oxfw->playback_substreams--; + --oxfw->substreams_count;
snd_oxfw_stream_stop_duplex(oxfw);
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 52cf815c27f7..ebfe0777773b 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -244,7 +244,7 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir; int err = 0;
- if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) + if (oxfw->substreams_count == 0) return -EIO;
// Considering JACK/FFADO streaming: @@ -323,7 +323,7 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw,
void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw) { - if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) { + if (oxfw->substreams_count == 0) { amdtp_stream_stop(&oxfw->rx_stream); cmp_connection_break(&oxfw->in_conn);
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 911a452f94db..e0c825288a24 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -52,8 +52,7 @@ struct snd_oxfw { struct cmp_connection in_conn; struct amdtp_stream tx_stream; struct amdtp_stream rx_stream; - unsigned int capture_substreams; - unsigned int playback_substreams; + unsigned int substreams_count;
unsigned int midi_input_ports; unsigned int midi_output_ports;
This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks.
At present, several operations are done in pcm.prepare callback. To reduce load of the callback, This commit splits out an operation to set packet format in pcm.hw_params callback.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-midi.c | 14 +++++++--- sound/firewire/oxfw/oxfw-pcm.c | 26 +++++++++++------- sound/firewire/oxfw/oxfw-stream.c | 44 ++++++++++++++++++++++--------- sound/firewire/oxfw/oxfw.h | 7 ++--- 4 files changed, 62 insertions(+), 29 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 092493497f1a..9ba62778add2 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -19,8 +19,11 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- ++oxfw->substreams_count; - err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->tx_stream, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0); + if (err >= 0) { + ++oxfw->substreams_count; + err = snd_oxfw_stream_start_duplex(oxfw); + }
mutex_unlock(&oxfw->mutex);
@@ -41,8 +44,11 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- ++oxfw->substreams_count; - err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->rx_stream, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0); + if (err >= 0) { + ++oxfw->substreams_count; + err = snd_oxfw_stream_start_duplex(oxfw); + }
mutex_unlock(&oxfw->mutex);
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 79c8e514bed9..b08b850d53ea 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -219,12 +219,18 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + unsigned int rate = params_rate(hw_params); + unsigned int channels = params_channels(hw_params); + mutex_lock(&oxfw->mutex); - ++oxfw->substreams_count; + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, + rate, channels); + if (err >= 0) + ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); }
- return 0; + return err; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) @@ -238,8 +244,14 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + unsigned int rate = params_rate(hw_params); + unsigned int channels = params_channels(hw_params); + mutex_lock(&oxfw->mutex); - ++oxfw->substreams_count; + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, + rate, channels); + if (err >= 0) + ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); }
@@ -280,12 +292,10 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) static int pcm_capture_prepare(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err;
mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->tx_stream, - runtime->rate, runtime->channels); + err = snd_oxfw_stream_start_duplex(oxfw); mutex_unlock(&oxfw->mutex); if (err < 0) goto end; @@ -297,12 +307,10 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) static int pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err;
mutex_lock(&oxfw->mutex); - err = snd_oxfw_stream_start_duplex(oxfw, &oxfw->rx_stream, - runtime->rate, runtime->channels); + err = snd_oxfw_stream_start_duplex(oxfw); mutex_unlock(&oxfw->mutex); if (err < 0) goto end; diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index ebfe0777773b..373154d8ee0e 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -236,16 +236,13 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) return 0; }
-int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels) +int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, + struct amdtp_stream *stream, + unsigned int rate, unsigned int pcm_channels) { struct snd_oxfw_stream_formation formation; enum avc_general_plug_dir dir; - int err = 0; - - if (oxfw->substreams_count == 0) - return -EIO; + int err;
// Considering JACK/FFADO streaming: // TODO: This can be removed hwdep functionality becomes popular. @@ -266,14 +263,11 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); if (err < 0) return err; - if (rate == 0) + if (rate == 0) { rate = formation.rate; - if (pcm_channels == 0) pcm_channels = formation.pcm; - - if (formation.rate != rate || formation.pcm != pcm_channels || - amdtp_streaming_error(&oxfw->rx_stream) || - amdtp_streaming_error(&oxfw->tx_stream)) { + } + if (formation.rate != rate || formation.pcm != pcm_channels) { amdtp_stream_stop(&oxfw->rx_stream); cmp_connection_break(&oxfw->in_conn);
@@ -281,7 +275,10 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn); } + }
+ if (oxfw->substreams_count == 0 || + formation.rate != rate || formation.pcm != pcm_channels) { err = set_stream_format(oxfw, stream, rate, pcm_channels); if (err < 0) { dev_err(&oxfw->unit->device, @@ -290,6 +287,27 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, } }
+ return 0; +} + +int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw) +{ + int err; + + if (oxfw->substreams_count == 0) + return -EIO; + + if (amdtp_streaming_error(&oxfw->rx_stream) || + amdtp_streaming_error(&oxfw->tx_stream)) { + amdtp_stream_stop(&oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn); + + if (oxfw->has_output) { + amdtp_stream_stop(&oxfw->tx_stream); + cmp_connection_break(&oxfw->out_conn); + } + } + if (!amdtp_stream_running(&oxfw->rx_stream)) { err = start_stream(oxfw, &oxfw->rx_stream); if (err < 0) { diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index e0c825288a24..d4d4926c28cf 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -99,9 +99,10 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate, unsigned short pid);
int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw); -int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw, - struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels); +int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, + struct amdtp_stream *stream, + unsigned int rate, unsigned int pcm_channels); +int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw);
This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks.
This commit splits out an operation to configure stream parameters into pcm.hw_params callback. In pcm.prepare callback, establishing connections and start isochronous contexts.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 97 ++++++++++++++++++------------- 1 file changed, 57 insertions(+), 40 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 373154d8ee0e..837733f10736 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -103,51 +103,13 @@ static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) { - u8 **formats; - enum avc_general_plug_dir dir; struct cmp_connection *conn; - struct snd_oxfw_stream_formation formation; - int i; int err;
- if (stream == &oxfw->rx_stream) { - dir = AVC_GENERAL_PLUG_DIR_IN; - formats = oxfw->rx_stream_formats; + if (stream == &oxfw->rx_stream) conn = &oxfw->in_conn; - } else { - dir = AVC_GENERAL_PLUG_DIR_OUT; - formats = oxfw->tx_stream_formats; + else conn = &oxfw->out_conn; - } - - err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); - if (err < 0) - return err; - - for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { - struct snd_oxfw_stream_formation fmt; - - if (formats[i] == NULL) - break; - - err = snd_oxfw_stream_parse_format(formats[i], &fmt); - if (err < 0) - return err; - if (fmt.rate == formation.rate && fmt.pcm == formation.pcm && - fmt.midi == formation.midi) - break; - } - if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) - return -EINVAL; - - // The stream should have one pcm channels at least. - if (formation.pcm == 0) - return -EINVAL; - - err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm, - formation.midi * 8, false); - if (err < 0) - return err;
err = cmp_connection_establish(conn, amdtp_stream_get_max_payload(stream)); @@ -236,6 +198,51 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) return 0; }
+static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream) +{ + enum avc_general_plug_dir dir; + u8 **formats; + struct snd_oxfw_stream_formation formation; + int i; + int err; + + if (stream == &oxfw->rx_stream) { + dir = AVC_GENERAL_PLUG_DIR_IN; + formats = oxfw->rx_stream_formats; + } else { + dir = AVC_GENERAL_PLUG_DIR_OUT; + formats = oxfw->tx_stream_formats; + } + + err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); + if (err < 0) + return err; + + for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { + struct snd_oxfw_stream_formation fmt; + + if (formats[i] == NULL) + break; + + err = snd_oxfw_stream_parse_format(formats[i], &fmt); + if (err < 0) + return err; + + if (fmt.rate == formation.rate && fmt.pcm == formation.pcm && + fmt.midi == formation.midi) + break; + } + if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) + return -EINVAL; + + // The stream should have one pcm channels at least. + if (formation.pcm == 0) + return -EINVAL; + + return amdtp_am824_set_parameters(stream, formation.rate, formation.pcm, + formation.midi * 8, false); +} + int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, unsigned int rate, unsigned int pcm_channels) @@ -285,6 +292,16 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, "fail to set stream format: %d\n", err); return err; } + + err = keep_resources(oxfw, &oxfw->rx_stream); + if (err < 0) + return err; + + if (oxfw->has_output) { + err = keep_resources(oxfw, &oxfw->tx_stream); + if (err < 0) + return err; + } }
return 0;
On Wed, 12 Jun 2019 10:44:03 +0200, Takashi Sakamoto wrote:
Hi,
This patchset is a part of patches to reserve/release isochronous resources in pcm.hw_params/hw_free callbacks, like posted patchsets below: https://mailman.alsa-project.org/pipermail/alsa-devel/2019-June/150118.html https://mailman.alsa-project.org/pipermail/alsa-devel/2019-June/150863.html
However, in this patchset, I focus on code refactoring, due to kernel API implementation in firewire-lib.
The target devices supported by ALSA bebob, fireworks and oxfw drivers implements Connection Management Procedure (CMP) in IEC 61883-1. For CMP, the drivers use kernel API in firewire-lib. This API has private data including the data for isochronous resources, and its implementation is tightly-coupled to maintenance of isochronous resources.
This patchset is a preparation for future work to change the CMP implementation.
Takashi Sakamoto (19): ALSA: bebob: configure sampling transfer frequency in pcm.hw_params callback ALSA: bebob: don't set XRUN in stop streaming ALSA: bebob: obsolete useless member of private structure ALSA: bebob: code refactoring to initialize/destroy stream data ALSA: fireworks: unify substream counter ALSA: fireworks: code refactoring for rawmidi.open/close ALSA: fireworks: code refactoring for pcm.hw_params/hw_free ALSA: fireworks: configure sampling transfer frequency in pcm.hw_params callback ALSA: fireworks: configure stream parameters in pcm.hw_params callback ALSA: fireworks: don't set XRUN in stop streaming ALSA: oxfw: code refactoring for stop condition of packet streaming ALSA: oxfw: set packet parameter according to current configuration ALSA: oxfw: start duplex streams if supported ALSA: oxfw: break packet streaming at bus-reset handler ALSA: oxfw: expand stop procedure for packet streaming ALSA: oxfw: rename helper functions for duplex streams ALSA: oxfw: unify substreams counter ALSA: oxfw: configure packet format in pcm.hw_params callback ALSA: oxfw: configure stream parameter in pcm.hw_params callback
Applied all 19 patches now. Thanks.
Takashi
participants (2)
-
Takashi Iwai
-
Takashi Sakamoto