+// SPDX-License-Identifier: GPL-2.0-only
/*
* tascam-stream.c - a part of driver for TASCAM FireWire series
*
* Copyright (c) 2015 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
*/
#include <linux/delay.h>
__be32 reg;
int err;
- /* Set an option for unknown purpose. */
+ // Set an option for unknown purpose.
reg = cpu_to_be32(0x00200000);
err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
if (err < 0)
return err;
- err = enable_data_channels(tscm);
- if (err < 0)
- return err;
-
- return set_clock(tscm, rate, INT_MAX);
+ return enable_data_channels(tscm);
}
static void finish_session(struct snd_tscm *tscm)
{
__be32 reg;
+ amdtp_stream_stop(&tscm->rx_stream);
+ amdtp_stream_stop(&tscm->tx_stream);
+
reg = 0;
snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING,
®, sizeof(reg), 0);
}
-static void release_resources(struct snd_tscm *tscm)
-{
- // Release isochronous resources.
- fw_iso_resources_free(&tscm->tx_resources);
- fw_iso_resources_free(&tscm->rx_resources);
-}
-
static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
struct amdtp_stream *stream)
{
return err;
}
-/* At bus reset, streaming is stopped and some registers are clear. */
+// At bus reset, streaming is stopped and some registers are clear.
void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
{
amdtp_stream_pcm_abort(&tscm->tx_stream);
fw_iso_resources_destroy(&tscm->tx_resources);
}
-int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)
{
unsigned int curr_rate;
int err;
- if (tscm->substreams_counter == 0)
- return 0;
-
err = snd_tscm_stream_get_rate(tscm, &curr_rate);
if (err < 0)
return err;
- if (curr_rate != rate ||
- amdtp_streaming_error(&tscm->rx_stream) ||
- amdtp_streaming_error(&tscm->tx_stream)) {
+
+ if (tscm->substreams_counter == 0 || rate != curr_rate) {
finish_session(tscm);
- amdtp_stream_stop(&tscm->rx_stream);
- amdtp_stream_stop(&tscm->tx_stream);
+ fw_iso_resources_free(&tscm->tx_resources);
+ fw_iso_resources_free(&tscm->rx_resources);
- release_resources(tscm);
- }
+ err = set_clock(tscm, rate, INT_MAX);
+ if (err < 0)
+ return err;
- if (!amdtp_stream_running(&tscm->rx_stream)) {
err = keep_resources(tscm, rate, &tscm->tx_stream);
if (err < 0)
- goto error;
+ return err;
err = keep_resources(tscm, rate, &tscm->rx_stream);
+ if (err < 0) {
+ fw_iso_resources_free(&tscm->tx_resources);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+{
+ unsigned int generation = tscm->rx_resources.generation;
+ int err;
+
+ if (tscm->substreams_counter == 0)
+ return 0;
+
+ if (amdtp_streaming_error(&tscm->rx_stream) ||
+ amdtp_streaming_error(&tscm->tx_stream))
+ finish_session(tscm);
+
+ if (generation != fw_parent_device(tscm->unit)->card->generation) {
+ err = fw_iso_resources_update(&tscm->tx_resources);
+ if (err < 0)
+ goto error;
+
+ err = fw_iso_resources_update(&tscm->rx_resources);
if (err < 0)
goto error;
+ }
+ if (!amdtp_stream_running(&tscm->rx_stream)) {
err = set_stream_formats(tscm, rate);
if (err < 0)
goto error;
return 0;
error:
- amdtp_stream_stop(&tscm->rx_stream);
- amdtp_stream_stop(&tscm->tx_stream);
-
finish_session(tscm);
- release_resources(tscm);
return err;
}
void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
{
- if (tscm->substreams_counter > 0)
- return;
-
- amdtp_stream_stop(&tscm->tx_stream);
- amdtp_stream_stop(&tscm->rx_stream);
+ if (tscm->substreams_counter == 0) {
+ finish_session(tscm);
- finish_session(tscm);
- release_resources(tscm);
+ fw_iso_resources_free(&tscm->tx_resources);
+ fw_iso_resources_free(&tscm->rx_resources);
+ }
}
void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)