return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ unsigned int rate = params_rate(hw_params);
+
mutex_lock(&ff->mutex);
- ff->substreams_counter++;
+ err = snd_ff_stream_reserve_duplex(ff, rate);
+ if (err >= 0)
+ ++ff->substreams_counter;
mutex_unlock(&ff->mutex);
}
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ unsigned int rate = params_rate(hw_params);
+
mutex_lock(&ff->mutex);
- ff->substreams_counter++;
+ err = snd_ff_stream_reserve_duplex(ff, rate);
+ if (err >= 0)
+ ++ff->substreams_counter;
mutex_unlock(&ff->mutex);
}
mutex_lock(&ff->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- ff->substreams_counter--;
+ --ff->substreams_counter;
snd_ff_stream_stop_duplex(ff);
+ snd_ff_stream_release_duplex(ff);
mutex_unlock(&ff->mutex);
mutex_lock(&ff->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- ff->substreams_counter--;
+ --ff->substreams_counter;
snd_ff_stream_stop_duplex(ff);
+ snd_ff_stream_release_duplex(ff);
mutex_unlock(&ff->mutex);
return 0;
}
-static void release_resources(struct snd_ff *ff)
-{
- fw_iso_resources_free(&ff->tx_resources);
- fw_iso_resources_free(&ff->rx_resources);
-}
-
static inline void finish_session(struct snd_ff *ff)
{
ff->spec->protocol->finish_session(ff);
destroy_stream(ff, AMDTP_OUT_STREAM);
}
-int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)
{
unsigned int curr_rate;
enum snd_ff_clock_src src;
int err;
- if (ff->substreams_counter == 0)
- return 0;
-
err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
if (err < 0)
return err;
- if (curr_rate != rate ||
- amdtp_streaming_error(&ff->tx_stream) ||
- amdtp_streaming_error(&ff->rx_stream)) {
- finish_session(ff);
+
+ if (ff->substreams_counter == 0 || curr_rate != rate) {
+ enum snd_ff_stream_mode mode;
+ int i;
amdtp_stream_stop(&ff->tx_stream);
amdtp_stream_stop(&ff->rx_stream);
- release_resources(ff);
- }
+ finish_session(ff);
- /*
- * Regardless of current source of clock signal, drivers transfer some
- * packets. Then, the device transfers packets.
- */
- if (!amdtp_stream_running(&ff->rx_stream)) {
- enum snd_ff_stream_mode mode;
- int i;
+ fw_iso_resources_free(&ff->tx_resources);
+ fw_iso_resources_free(&ff->rx_resources);
for (i = 0; i < CIP_SFC_COUNT; ++i) {
if (amdtp_rate_table[i] == rate)
err = ff->spec->protocol->allocate_resources(ff, rate);
if (err < 0)
- goto error;
+ return err;
+ }
+
+ return 0;
+}
+
+void snd_ff_stream_release_duplex(struct snd_ff *ff)
+{
+ if (ff->substreams_counter == 0) {
+ fw_iso_resources_free(&ff->tx_resources);
+ fw_iso_resources_free(&ff->rx_resources);
+ }
+}
+
+int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
+{
+ int err;
+
+ if (ff->substreams_counter == 0)
+ return 0;
+ if (amdtp_streaming_error(&ff->tx_stream) ||
+ amdtp_streaming_error(&ff->rx_stream)) {
+ amdtp_stream_stop(&ff->tx_stream);
+ amdtp_stream_stop(&ff->rx_stream);
+
+ finish_session(ff);
+ }
+
+ /*
+ * Regardless of current source of clock signal, drivers transfer some
+ * packets. Then, the device transfers packets.
+ */
+ if (!amdtp_stream_running(&ff->rx_stream)) {
err = ff->spec->protocol->begin_session(ff, rate);
if (err < 0)
goto error;
amdtp_stream_stop(&ff->rx_stream);
finish_session(ff);
- release_resources(ff);
return err;
}
amdtp_stream_stop(&ff->tx_stream);
amdtp_stream_stop(&ff->rx_stream);
finish_session(ff);
- release_resources(ff);
}
void snd_ff_stream_update_duplex(struct snd_ff *ff)