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,
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)
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);
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);
__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)
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;
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)