summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/firewire/tascam/tascam-pcm.c22
-rw-r--r--sound/firewire/tascam/tascam-stream.c79
-rw-r--r--sound/firewire/tascam/tascam.h2
3 files changed, 66 insertions, 37 deletions
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index e4cc8990e195..962ef1212ac0 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -96,12 +96,16 @@ 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);
+
mutex_lock(&tscm->mutex);
- tscm->substreams_counter++;
+ err = snd_tscm_stream_reserve_duplex(tscm, rate);
+ if (err >= 0)
+ ++tscm->substreams_counter;
mutex_unlock(&tscm->mutex);
}
- return 0;
+ return err;
}
static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
@@ -116,12 +120,16 @@ 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);
+
mutex_lock(&tscm->mutex);
- tscm->substreams_counter++;
+ err = snd_tscm_stream_reserve_duplex(tscm, rate);
+ if (err >= 0)
+ ++tscm->substreams_counter;
mutex_unlock(&tscm->mutex);
}
- return 0;
+ return err;
}
static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
@@ -131,9 +139,10 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&tscm->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- tscm->substreams_counter--;
+ --tscm->substreams_counter;
snd_tscm_stream_stop_duplex(tscm);
+ snd_tscm_stream_release_duplex(tscm);
mutex_unlock(&tscm->mutex);
@@ -147,9 +156,10 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&tscm->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- tscm->substreams_counter--;
+ --tscm->substreams_counter;
snd_tscm_stream_stop_duplex(tscm);
+ snd_tscm_stream_release_duplex(tscm);
mutex_unlock(&tscm->mutex);
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
index 6ad149274050..18d554d46be5 100644
--- a/sound/firewire/tascam/tascam-stream.c
+++ b/sound/firewire/tascam/tascam-stream.c
@@ -166,7 +166,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,11 +174,7 @@ 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)
@@ -348,38 +344,66 @@ 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)) {
- finish_session(tscm);
+ if (tscm->substreams_counter == 0 || rate != curr_rate) {
amdtp_stream_stop(&tscm->rx_stream);
amdtp_stream_stop(&tscm->tx_stream);
+ finish_session(tscm);
+
fw_iso_resources_free(&tscm->tx_resources);
fw_iso_resources_free(&tscm->rx_resources);
- }
- if (!amdtp_stream_running(&tscm->rx_stream)) {
+ err = set_clock(tscm, rate, INT_MAX);
+ if (err < 0)
+ return err;
+
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)
- goto error;
+ if (err < 0) {
+ fw_iso_resources_free(&tscm->tx_resources);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+void snd_tscm_stream_release_duplex(struct snd_tscm *tscm)
+{
+ if (tscm->substreams_counter == 0) {
+ fw_iso_resources_free(&tscm->tx_resources);
+ fw_iso_resources_free(&tscm->rx_resources);
+ }
+}
+
+int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
+{
+ int err;
+
+ if (tscm->substreams_counter == 0)
+ return 0;
+
+ if (amdtp_streaming_error(&tscm->rx_stream) ||
+ amdtp_streaming_error(&tscm->tx_stream)) {
+ amdtp_stream_stop(&tscm->rx_stream);
+ amdtp_stream_stop(&tscm->tx_stream);
+ finish_session(tscm);
+ }
+
+ if (!amdtp_stream_running(&tscm->rx_stream)) {
err = set_stream_formats(tscm, rate);
if (err < 0)
goto error;
@@ -422,24 +446,17 @@ error:
finish_session(tscm);
- fw_iso_resources_free(&tscm->tx_resources);
- fw_iso_resources_free(&tscm->rx_resources);
-
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);
-
- finish_session(tscm);
+ if (tscm->substreams_counter == 0) {
+ amdtp_stream_stop(&tscm->tx_stream);
+ amdtp_stream_stop(&tscm->rx_stream);
- fw_iso_resources_free(&tscm->tx_resources);
- fw_iso_resources_free(&tscm->rx_resources);
+ finish_session(tscm);
+ }
}
void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
index 6a411ee0dcf1..1cb75c374f11 100644
--- a/sound/firewire/tascam/tascam.h
+++ b/sound/firewire/tascam/tascam.h
@@ -147,6 +147,8 @@ int snd_tscm_stream_get_clock(struct snd_tscm *tscm,
int snd_tscm_stream_init_duplex(struct snd_tscm *tscm);
void snd_tscm_stream_update_duplex(struct snd_tscm *tscm);
void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm);
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate);
+void snd_tscm_stream_release_duplex(struct snd_tscm *tscm);
int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate);
void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);