From b3480638a52adeeb133759fca0a0f89ce403e8ba Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 11 Jun 2019 22:21:14 +0900 Subject: ALSA: dice: code refactoring to stop packet streaming This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks. There're three points to finish packet streaming but no helper functions for common operations for it. This commit adds a helper function for operations to finish packet streaming. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-stream.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'sound/firewire/dice/dice-stream.c') diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index c3c892c5c7ff..8bce923dc4bd 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -230,6 +230,15 @@ static int keep_resources(struct snd_dice *dice, fw_parent_device(dice->unit)->max_speed); } +static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, + struct reg_params *rx_params) +{ + stop_streams(dice, AMDTP_IN_STREAM, tx_params); + stop_streams(dice, AMDTP_OUT_STREAM, rx_params); + + snd_dice_transaction_clear_enable(dice); +} + static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, unsigned int rate, struct reg_params *params) { @@ -328,10 +337,8 @@ static int start_duplex_streams(struct snd_dice *dice, unsigned int rate) if (err < 0) return err; - /* Stop transmission. */ - stop_streams(dice, AMDTP_IN_STREAM, &tx_params); - stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); - snd_dice_transaction_clear_enable(dice); + // Stop transmission. + finish_session(dice, &tx_params, &rx_params); release_resources(dice); err = ensure_phase_lock(dice, rate); @@ -373,9 +380,7 @@ static int start_duplex_streams(struct snd_dice *dice, unsigned int rate) return 0; error: - stop_streams(dice, AMDTP_IN_STREAM, &tx_params); - stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); - snd_dice_transaction_clear_enable(dice); + finish_session(dice, &tx_params, &rx_params); release_resources(dice); return err; } @@ -449,12 +454,8 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice) if (dice->substreams_counter > 0) return; - snd_dice_transaction_clear_enable(dice); - - if (get_register_params(dice, &tx_params, &rx_params) == 0) { - stop_streams(dice, AMDTP_IN_STREAM, &tx_params); - stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); - } + if (get_register_params(dice, &tx_params, &rx_params) >= 0) + finish_session(dice, &tx_params, &rx_params); release_resources(dice); } -- cgit v1.2.3 From c738aed136a74e9fafd90e5c8a0b13bf068a39f7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 11 Jun 2019 22:21:15 +0900 Subject: ALSA: dice: code refactoring to keep isochronous resources This commit is a part of preparation to perform allocation/release of isochronous resources in pcm.hw_params/hw_free callbacks. This commit adds a helper function to allocate isochronous resources, separated from operations to start packet streaming, I note that some dice-based devices have two pair of endpoints for isochronous packet straeming. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-stream.c | 133 +++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 59 deletions(-) (limited to 'sound/firewire/dice/dice-stream.c') diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 8bce923dc4bd..010cbf02de4f 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -175,35 +175,22 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, } } -static int keep_resources(struct snd_dice *dice, - enum amdtp_stream_direction dir, unsigned int index, - unsigned int rate, unsigned int pcm_chs, - unsigned int midi_ports) +static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream, + struct fw_iso_resources *resources, unsigned int rate, + unsigned int pcm_chs, unsigned int midi_ports) { - struct amdtp_stream *stream; - struct fw_iso_resources *resources; bool double_pcm_frames; unsigned int i; int err; - if (dir == AMDTP_IN_STREAM) { - stream = &dice->tx_stream[index]; - resources = &dice->tx_resources[index]; - } else { - stream = &dice->rx_stream[index]; - resources = &dice->rx_resources[index]; - } - - /* - * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in - * one data block of AMDTP packet. Thus sampling transfer frequency is - * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are - * transferred on AMDTP packets at 96 kHz. Two successive samples of a - * channel are stored consecutively in the packet. This quirk is called - * as 'Dual Wire'. - * For this quirk, blocking mode is required and PCM buffer size should - * be aligned to SYT_INTERVAL. - */ + // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in + // one data block of AMDTP packet. Thus sampling transfer frequency is + // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are + // transferred on AMDTP packets at 96 kHz. Two successive samples of a + // channel are stored consecutively in the packet. This quirk is called + // as 'Dual Wire'. + // For this quirk, blocking mode is required and PCM buffer size should + // be aligned to SYT_INTERVAL. double_pcm_frames = rate > 96000; if (double_pcm_frames) { rate /= 2; @@ -230,49 +217,40 @@ static int keep_resources(struct snd_dice *dice, fw_parent_device(dice->unit)->max_speed); } -static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, - struct reg_params *rx_params) +static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, + enum amdtp_stream_direction dir, + struct reg_params *params) { - stop_streams(dice, AMDTP_IN_STREAM, tx_params); - stop_streams(dice, AMDTP_OUT_STREAM, rx_params); - - snd_dice_transaction_clear_enable(dice); -} - -static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, - unsigned int rate, struct reg_params *params) -{ - __be32 reg[2]; enum snd_dice_rate_mode mode; - unsigned int i, pcm_chs, midi_ports; - struct amdtp_stream *streams; - struct fw_iso_resources *resources; - struct fw_device *fw_dev = fw_parent_device(dice->unit); - int err = 0; - - if (dir == AMDTP_IN_STREAM) { - streams = dice->tx_stream; - resources = dice->tx_resources; - } else { - streams = dice->rx_stream; - resources = dice->rx_resources; - } + int i; + int err; err = snd_dice_stream_get_rate_mode(dice, rate, &mode); if (err < 0) return err; - for (i = 0; i < params->count; i++) { + for (i = 0; i < params->count; ++i) { + __be32 reg[2]; + struct amdtp_stream *stream; + struct fw_iso_resources *resources; unsigned int pcm_cache; unsigned int midi_cache; + unsigned int pcm_chs; + unsigned int midi_ports; if (dir == AMDTP_IN_STREAM) { + stream = &dice->tx_stream[i]; + resources = &dice->tx_resources[i]; + pcm_cache = dice->tx_pcm_chs[i][mode]; midi_cache = dice->tx_midi_ports[i]; err = snd_dice_transaction_read_tx(dice, params->size * i + TX_NUMBER_AUDIO, reg, sizeof(reg)); } else { + stream = &dice->rx_stream[i]; + resources = &dice->rx_resources[i]; + pcm_cache = dice->rx_pcm_chs[i][mode]; midi_cache = dice->rx_midi_ports[i]; err = snd_dice_transaction_read_rx(dice, @@ -284,7 +262,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, pcm_chs = be32_to_cpu(reg[0]); midi_ports = be32_to_cpu(reg[1]); - /* These are important for developer of this driver. */ + // These are important for developer of this driver. if (pcm_chs != pcm_cache || midi_ports != midi_cache) { dev_info(&dice->unit->device, "cache mismatch: pcm: %u:%u, midi: %u:%u\n", @@ -292,34 +270,71 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, return -EPROTO; } - err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports); + err = keep_resources(dice, stream, resources, rate, pcm_chs, + midi_ports); if (err < 0) return err; + } + + return 0; +} + +static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, + struct reg_params *rx_params) +{ + stop_streams(dice, AMDTP_IN_STREAM, tx_params); + stop_streams(dice, AMDTP_OUT_STREAM, rx_params); + + snd_dice_transaction_clear_enable(dice); +} + +static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, + unsigned int rate, struct reg_params *params) +{ + unsigned int max_speed = fw_parent_device(dice->unit)->max_speed; + int i; + int err; + + err = keep_dual_resources(dice, rate, dir, params); + if (err < 0) + return err; + + for (i = 0; i < params->count; i++) { + struct amdtp_stream *stream; + struct fw_iso_resources *resources; + __be32 reg; + + if (dir == AMDTP_IN_STREAM) { + stream = dice->tx_stream + i; + resources = dice->tx_resources + i; + } else { + stream = dice->rx_stream + i; + resources = dice->rx_resources + i; + } - reg[0] = cpu_to_be32(resources[i].channel); + reg = cpu_to_be32(resources->channel); if (dir == AMDTP_IN_STREAM) { err = snd_dice_transaction_write_tx(dice, params->size * i + TX_ISOCHRONOUS, - reg, sizeof(reg[0])); + ®, sizeof(reg)); } else { err = snd_dice_transaction_write_rx(dice, params->size * i + RX_ISOCHRONOUS, - reg, sizeof(reg[0])); + ®, sizeof(reg)); } if (err < 0) return err; if (dir == AMDTP_IN_STREAM) { - reg[0] = cpu_to_be32(fw_dev->max_speed); + reg = cpu_to_be32(max_speed); err = snd_dice_transaction_write_tx(dice, params->size * i + TX_SPEED, - reg, sizeof(reg[0])); + ®, sizeof(reg)); if (err < 0) return err; } - err = amdtp_stream_start(&streams[i], resources[i].channel, - fw_dev->max_speed); + err = amdtp_stream_start(stream, resources->channel, max_speed); if (err < 0) return err; } -- cgit v1.2.3 From 3cd2c2d780a23e8b847c9ec22e8bc9dd6e685cbe Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 11 Jun 2019 22:21:16 +0900 Subject: ALSA: dice: reserve/release isochronous resources in pcm.hw_params/hw_free callbacks Once allocated, isochronous resources are available for packet streaming, even if the streaming is cancelled. For this reason, current implementation handles allocation of the resources and starting packet streaming at the same time. However, this brings complicated procedure to start packet streaming. This commit separates the allocation and starting. The allocation is done in pcm.hw_params callback and available till pcm.hw_free callback. Even if any XRUN occurs, pcm.prepare callback is done to restart packet streaming without releasing/allocating the resources. There are two points to stop packet streaming; in pcm.hw_params and pcm.prepare callbacks. The former point is a case that packet streaming is already started for any MIDI substream then packet streaming is requested with different sampling transfer frequency for any PCM substream. The latter point is cases of any XRUN or packet queueing error. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-midi.c | 10 +- sound/firewire/dice/dice-pcm.c | 26 +++-- sound/firewire/dice/dice-stream.c | 218 ++++++++++++++++++++------------------ sound/firewire/dice/dice.h | 4 +- 4 files changed, 143 insertions(+), 115 deletions(-) (limited to 'sound/firewire/dice/dice-stream.c') diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index 84eca8a51a02..6172dad87c4e 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -18,8 +18,11 @@ static int midi_open(struct snd_rawmidi_substream *substream) mutex_lock(&dice->mutex); - dice->substreams_counter++; - err = snd_dice_stream_start_duplex(dice, 0); + err = snd_dice_stream_reserve_duplex(dice, 0); + if (err >= 0) { + ++dice->substreams_counter; + err = snd_dice_stream_start_duplex(dice); + } mutex_unlock(&dice->mutex); @@ -35,8 +38,9 @@ static int midi_close(struct snd_rawmidi_substream *substream) mutex_lock(&dice->mutex); - dice->substreams_counter--; + --dice->substreams_counter; snd_dice_stream_stop_duplex(dice); + snd_dice_stream_release_duplex(dice); mutex_unlock(&dice->mutex); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index bb3ef5ff3488..6c7a6b7ed743 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -243,12 +243,16 @@ static int 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(&dice->mutex); - dice->substreams_counter++; + err = snd_dice_stream_reserve_duplex(dice, rate); + if (err >= 0) + ++dice->substreams_counter; mutex_unlock(&dice->mutex); } - return 0; + return err; } static int playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) @@ -262,12 +266,16 @@ static int 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(&dice->mutex); - dice->substreams_counter++; + err = snd_dice_stream_reserve_duplex(dice, rate); + if (err >= 0) + ++dice->substreams_counter; mutex_unlock(&dice->mutex); } - return 0; + return err; } static int capture_hw_free(struct snd_pcm_substream *substream) @@ -277,9 +285,10 @@ static int capture_hw_free(struct snd_pcm_substream *substream) mutex_lock(&dice->mutex); if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - dice->substreams_counter--; + --dice->substreams_counter; snd_dice_stream_stop_duplex(dice); + snd_dice_stream_release_duplex(dice); mutex_unlock(&dice->mutex); @@ -293,9 +302,10 @@ static int playback_hw_free(struct snd_pcm_substream *substream) mutex_lock(&dice->mutex); if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - dice->substreams_counter--; + --dice->substreams_counter; snd_dice_stream_stop_duplex(dice); + snd_dice_stream_release_duplex(dice); mutex_unlock(&dice->mutex); @@ -309,7 +319,7 @@ static int capture_prepare(struct snd_pcm_substream *substream) int err; mutex_lock(&dice->mutex); - err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); + err = snd_dice_stream_start_duplex(dice); mutex_unlock(&dice->mutex); if (err >= 0) amdtp_stream_pcm_prepare(stream); @@ -323,7 +333,7 @@ static int playback_prepare(struct snd_pcm_substream *substream) int err; mutex_lock(&dice->mutex); - err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); + err = snd_dice_stream_start_duplex(dice); mutex_unlock(&dice->mutex); if (err >= 0) amdtp_stream_pcm_prepare(stream); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 010cbf02de4f..6bbf7421a53c 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -138,18 +138,9 @@ static int get_register_params(struct snd_dice *dice, static void release_resources(struct snd_dice *dice) { - unsigned int i; - - for (i = 0; i < MAX_STREAMS; i++) { - if (amdtp_stream_running(&dice->tx_stream[i])) { - amdtp_stream_pcm_abort(&dice->tx_stream[i]); - amdtp_stream_stop(&dice->tx_stream[i]); - } - if (amdtp_stream_running(&dice->rx_stream[i])) { - amdtp_stream_pcm_abort(&dice->rx_stream[i]); - amdtp_stream_stop(&dice->rx_stream[i]); - } + int i; + for (i = 0; i < MAX_STREAMS; ++i) { fw_iso_resources_free(&dice->tx_resources[i]); fw_iso_resources_free(&dice->rx_resources[i]); } @@ -164,10 +155,14 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, for (i = 0; i < params->count; i++) { reg = cpu_to_be32((u32)-1); if (dir == AMDTP_IN_STREAM) { + amdtp_stream_stop(&dice->tx_stream[i]); + snd_dice_transaction_write_tx(dice, params->size * i + TX_ISOCHRONOUS, ®, sizeof(reg)); } else { + amdtp_stream_stop(&dice->rx_stream[i]); + snd_dice_transaction_write_rx(dice, params->size * i + RX_ISOCHRONOUS, ®, sizeof(reg)); @@ -288,6 +283,65 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, snd_dice_transaction_clear_enable(dice); } +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) +{ + unsigned int curr_rate; + int err; + + // Check sampling transmission frequency. + err = snd_dice_transaction_get_rate(dice, &curr_rate); + if (err < 0) + return err; + if (rate == 0) + rate = curr_rate; + + if (dice->substreams_counter == 0 || curr_rate != rate) { + struct reg_params tx_params, rx_params; + + err = get_register_params(dice, &tx_params, &rx_params); + if (err < 0) + return err; + + finish_session(dice, &tx_params, &rx_params); + + release_resources(dice); + + // Just after owning the unit (GLOBAL_OWNER), the unit can + // return invalid stream formats. Selecting clock parameters + // have an effect for the unit to refine it. + err = ensure_phase_lock(dice, rate); + if (err < 0) + return err; + + // After changing sampling transfer frequency, the value of + // register can be changed. + err = get_register_params(dice, &tx_params, &rx_params); + if (err < 0) + return err; + + err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM, + &tx_params); + if (err < 0) + goto error; + + err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM, + &rx_params); + if (err < 0) + goto error; + } + + return 0; +error: + release_resources(dice); + return err; +} + +void snd_dice_stream_release_duplex(struct snd_dice *dice) +{ + if (dice->substreams_counter == 0) + release_resources(dice); +} + static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, unsigned int rate, struct reg_params *params) { @@ -295,10 +349,6 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, int i; int err; - err = keep_dual_resources(dice, rate, dir, params); - if (err < 0) - return err; - for (i = 0; i < params->count; i++) { struct amdtp_stream *stream; struct fw_iso_resources *resources; @@ -342,102 +392,39 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, return err; } -static int start_duplex_streams(struct snd_dice *dice, unsigned int rate) -{ - struct reg_params tx_params, rx_params; - int i; - int err; - - err = get_register_params(dice, &tx_params, &rx_params); - if (err < 0) - return err; - - // Stop transmission. - finish_session(dice, &tx_params, &rx_params); - release_resources(dice); - - err = ensure_phase_lock(dice, rate); - if (err < 0) { - dev_err(&dice->unit->device, "fail to ensure phase lock\n"); - return err; - } - - /* Likely to have changed stream formats. */ - err = get_register_params(dice, &tx_params, &rx_params); - if (err < 0) - return err; - - /* Start both streams. */ - err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); - if (err < 0) - goto error; - err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); - if (err < 0) - goto error; - - err = snd_dice_transaction_set_enable(dice); - if (err < 0) { - dev_err(&dice->unit->device, "fail to enable interface\n"); - goto error; - } - - for (i = 0; i < MAX_STREAMS; i++) { - if ((i < tx_params.count && - !amdtp_stream_wait_callback(&dice->tx_stream[i], - CALLBACK_TIMEOUT)) || - (i < rx_params.count && - !amdtp_stream_wait_callback(&dice->rx_stream[i], - CALLBACK_TIMEOUT))) { - err = -ETIMEDOUT; - goto error; - } - } - - return 0; -error: - finish_session(dice, &tx_params, &rx_params); - release_resources(dice); - return err; -} - /* * MEMO: After this function, there're two states of streams: * - None streams are running. * - All streams are running. */ -int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) +int snd_dice_stream_start_duplex(struct snd_dice *dice) { - unsigned int curr_rate; + struct reg_params tx_params, rx_params; unsigned int i; + unsigned int rate; enum snd_dice_rate_mode mode; int err; if (dice->substreams_counter == 0) return -EIO; - /* Check sampling transmission frequency. */ - err = snd_dice_transaction_get_rate(dice, &curr_rate); - if (err < 0) { - dev_err(&dice->unit->device, - "fail to get sampling rate\n"); + err = get_register_params(dice, &tx_params, &rx_params); + if (err < 0) return err; - } - if (rate == 0) - rate = curr_rate; - if (rate != curr_rate) - goto restart; - /* Check error of packet streaming. */ + // Check error of packet streaming. for (i = 0; i < MAX_STREAMS; ++i) { - if (amdtp_streaming_error(&dice->tx_stream[i])) - break; - if (amdtp_streaming_error(&dice->rx_stream[i])) + if (amdtp_streaming_error(&dice->tx_stream[i]) || + amdtp_streaming_error(&dice->rx_stream[i])) { + finish_session(dice, &tx_params, &rx_params); break; + } } - if (i < MAX_STREAMS) - goto restart; - /* Check required streams are running or not. */ + // Check required streams are running or not. + err = snd_dice_transaction_get_rate(dice, &rate); + if (err < 0) + return err; err = snd_dice_stream_get_rate_mode(dice, rate, &mode); if (err < 0) return err; @@ -449,12 +436,40 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) !amdtp_stream_running(&dice->rx_stream[i])) break; } - if (i < MAX_STREAMS) - goto restart; + if (i < MAX_STREAMS) { + // Start both streams. + err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); + if (err < 0) + goto error; + + err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); + if (err < 0) + goto error; + + err = snd_dice_transaction_set_enable(dice); + if (err < 0) { + dev_err(&dice->unit->device, + "fail to enable interface\n"); + goto error; + } + + for (i = 0; i < MAX_STREAMS; i++) { + if ((i < tx_params.count && + !amdtp_stream_wait_callback(&dice->tx_stream[i], + CALLBACK_TIMEOUT)) || + (i < rx_params.count && + !amdtp_stream_wait_callback(&dice->rx_stream[i], + CALLBACK_TIMEOUT))) { + err = -ETIMEDOUT; + goto error; + } + } + } return 0; -restart: - return start_duplex_streams(dice, rate); +error: + finish_session(dice, &tx_params, &rx_params); + return err; } /* @@ -466,13 +481,10 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice) { struct reg_params tx_params, rx_params; - if (dice->substreams_counter > 0) - return; - - if (get_register_params(dice, &tx_params, &rx_params) >= 0) - finish_session(dice, &tx_params, &rx_params); - - release_resources(dice); + if (dice->substreams_counter == 0) { + if (get_register_params(dice, &tx_params, &rx_params) >= 0) + finish_session(dice, &tx_params, &rx_params); + } } static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir, diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 9699adc2a96d..f95073b85010 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -205,10 +205,12 @@ extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT]; int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, enum snd_dice_rate_mode *mode); -int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate); +int snd_dice_stream_start_duplex(struct snd_dice *dice); void snd_dice_stream_stop_duplex(struct snd_dice *dice); int snd_dice_stream_init_duplex(struct snd_dice *dice); void snd_dice_stream_destroy_duplex(struct snd_dice *dice); +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate); +void snd_dice_stream_release_duplex(struct snd_dice *dice); void snd_dice_stream_update_duplex(struct snd_dice *dice); int snd_dice_stream_detect_current_formats(struct snd_dice *dice); -- cgit v1.2.3 From d5553026b53a246861d00221a6beb3674a30df03 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 11 Jun 2019 22:21:17 +0900 Subject: ALSA: dice: update isochronous resources when starting packet streaming after bus-reset After bus reset, isochronous resource manager releases all of allocated isochronous resources. The nodes to transfer isochronous packet should request reallocation of the resources. However, between the bus-reset and invocation of 'struct fw_driver.update' handler, ALSA PCM application can detect this situation by XRUN because the target device cancelled to transmit packets once bus-reset occurs. Due to the above mechanism, ALSA fireface driver just stops packet streaming in the update handler, thus pcm.prepare handler should request the reallocation. This commit requests the reallocation in pcm.prepare callback when bus generation is changed. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-stream.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound/firewire/dice/dice-stream.c') diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 6bbf7421a53c..f61b99a72655 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -399,6 +399,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, */ int snd_dice_stream_start_duplex(struct snd_dice *dice) { + unsigned int generation = dice->rx_resources[0].generation; struct reg_params tx_params, rx_params; unsigned int i; unsigned int rate; @@ -421,6 +422,15 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) } } + if (generation != fw_parent_device(dice->unit)->card->generation) { + for (i = 0; i < MAX_STREAMS; ++i) { + if (i < tx_params.count) + fw_iso_resources_update(dice->tx_resources + i); + if (i < rx_params.count) + fw_iso_resources_update(dice->rx_resources + i); + } + } + // Check required streams are running or not. err = snd_dice_transaction_get_rate(dice, &rate); if (err < 0) -- cgit v1.2.3 From c72d3a0a93471b95084339e5cba927d516724b83 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 13 Jun 2019 12:35:22 +0900 Subject: ALSA: dice: fix compiler warning due to returning uninitialized value This commit fixes the warning due to returning uninitialized value from start_streams() helper function. sound/firewire/dice/dice-stream.c: In function 'start_streams.isra.0': >> sound/firewire/dice/dice-stream.c:350:6: warning: 'err' may be used uninitialized in this function [-Wmaybe-uninitialized] int err; ^~~ Reported-by: kbuild test robot Fixes: 3cd2c2d780a2 ("ALSA: dice: reserve/release isochronous resources in pcm.hw_params/hw_free callbacks") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/firewire/dice/dice-stream.c') diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index f61b99a72655..e9e5c5fffb70 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -389,7 +389,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, return err; } - return err; + return 0; } /* -- cgit v1.2.3 From 740680f22d96e078245211b40fc2c141a24c8d1a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 18 Jun 2019 22:26:19 +0900 Subject: ALSA: dice: unify stop and release method for duplex streams >From callbacks for pcm and rawmidi interfaces, the functions to stop and release duplex streams are called at the same time. This commit merges the two functions. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-midi.c | 1 - sound/firewire/dice/dice-pcm.c | 1 - sound/firewire/dice/dice-stream.c | 8 ++------ sound/firewire/dice/dice.h | 1 - 4 files changed, 2 insertions(+), 9 deletions(-) (limited to 'sound/firewire/dice/dice-stream.c') diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index 6172dad87c4e..436f0c3c0fbb 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -40,7 +40,6 @@ static int midi_close(struct snd_rawmidi_substream *substream) --dice->substreams_counter; snd_dice_stream_stop_duplex(dice); - snd_dice_stream_release_duplex(dice); mutex_unlock(&dice->mutex); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 00b55dfc3b2c..8368073f7fa0 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -265,7 +265,6 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) --dice->substreams_counter; snd_dice_stream_stop_duplex(dice); - snd_dice_stream_release_duplex(dice); mutex_unlock(&dice->mutex); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index e9e5c5fffb70..433714a117a0 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -336,12 +336,6 @@ error: return err; } -void snd_dice_stream_release_duplex(struct snd_dice *dice) -{ - if (dice->substreams_counter == 0) - release_resources(dice); -} - static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, unsigned int rate, struct reg_params *params) { @@ -494,6 +488,8 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice) if (dice->substreams_counter == 0) { if (get_register_params(dice, &tx_params, &rx_params) >= 0) finish_session(dice, &tx_params, &rx_params); + + release_resources(dice); } } diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index f95073b85010..fd3f483283d5 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -210,7 +210,6 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice); int snd_dice_stream_init_duplex(struct snd_dice *dice); void snd_dice_stream_destroy_duplex(struct snd_dice *dice); int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate); -void snd_dice_stream_release_duplex(struct snd_dice *dice); void snd_dice_stream_update_duplex(struct snd_dice *dice); int snd_dice_stream_detect_current_formats(struct snd_dice *dice); -- cgit v1.2.3