Merge tag 'asoc-v5.3' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[sfrench/cifs-2.6.git] / sound / firewire / tascam / tascam-stream.c
index fc963469f6b033af50e931ae9148e000d8e33c50..e852e46ebe6fa6c9bf77ce579f214c997cb67680 100644 (file)
@@ -1,9 +1,8 @@
+// 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>
@@ -166,7 +165,7 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
        __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,
@@ -174,17 +173,16 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate)
        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,
@@ -269,13 +267,6 @@ static int begin_session(struct snd_tscm *tscm)
                                  &reg, 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)
 {
@@ -332,7 +323,7 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
        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);
@@ -355,37 +346,62 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
        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;
@@ -423,25 +439,19 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
 
        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)