return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ unsigned int rate = params_rate(hw_params);
+
mutex_lock(&motu->mutex);
- motu->substreams_counter++;
+ err = snd_motu_stream_reserve_duplex(motu, rate);
+ if (err >= 0)
+ ++motu->substreams_counter;
mutex_unlock(&motu->mutex);
}
- return 0;
+ return err;
}
static int playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ unsigned int rate = params_rate(hw_params);
+
mutex_lock(&motu->mutex);
- motu->substreams_counter++;
+ err = snd_motu_stream_reserve_duplex(motu, rate);
+ if (err >= 0)
+ ++motu->substreams_counter;
mutex_unlock(&motu->mutex);
}
- return 0;
+ return err;
}
static int capture_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&motu->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- motu->substreams_counter--;
+ --motu->substreams_counter;
snd_motu_stream_stop_duplex(motu);
+ snd_motu_stream_release_duplex(motu);
mutex_unlock(&motu->mutex);
mutex_lock(&motu->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- motu->substreams_counter--;
+ --motu->substreams_counter;
snd_motu_stream_stop_duplex(motu);
+ snd_motu_stream_release_duplex(motu);
mutex_unlock(&motu->mutex);
int err;
mutex_lock(&motu->mutex);
- err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+ err = snd_motu_stream_start_duplex(motu);
mutex_unlock(&motu->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(&motu->tx_stream);
int err;
mutex_lock(&motu->mutex);
- err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+ err = snd_motu_stream_start_duplex(motu);
mutex_unlock(&motu->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(&motu->rx_stream);
fw_parent_device(motu->unit)->max_speed);
}
-static int begin_session(struct snd_motu *motu, unsigned int rate)
+static int begin_session(struct snd_motu *motu)
{
__be32 reg;
u32 data;
int err;
- err = keep_resources(motu, rate, &motu->tx_stream);
- if (err < 0)
- return err;
-
- err = keep_resources(motu, rate, &motu->rx_stream);
- if (err < 0)
- return err;
-
// Configure the unit to start isochronous communication.
err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®,
sizeof(reg));
reg = cpu_to_be32(data);
snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, ®,
sizeof(reg));
-
- fw_iso_resources_free(&motu->tx_resources);
- fw_iso_resources_free(&motu->rx_resources);
}
static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
if (err < 0)
return err;
- if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
- amdtp_stream_stop(stream);
- fw_iso_resources_free(resources);
+ if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT))
return -ETIMEDOUT;
- }
return 0;
}
return 0;
}
+int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate)
+{
+ unsigned int curr_rate;
+ int err;
+
+ err = motu->spec->protocol->get_clock_rate(motu, &curr_rate);
+ if (err < 0)
+ return err;
+ if (rate == 0)
+ rate = curr_rate;
+
+ if (motu->substreams_counter == 0 || curr_rate != rate) {
+ finish_session(motu);
+
+ fw_iso_resources_free(&motu->tx_resources);
+ fw_iso_resources_free(&motu->rx_resources);
+
+ err = motu->spec->protocol->set_clock_rate(motu, rate);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to set sampling rate: %d\n", err);
+ return err;
+ }
+
+ err = snd_motu_stream_cache_packet_formats(motu);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(motu, rate, &motu->tx_stream);
+ if (err < 0)
+ return err;
+
+ err = keep_resources(motu, rate, &motu->rx_stream);
+ if (err < 0) {
+ fw_iso_resources_free(&motu->tx_resources);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+void snd_motu_stream_release_duplex(struct snd_motu *motu)
+{
+ if (motu->substreams_counter == 0) {
+ fw_iso_resources_free(&motu->tx_resources);
+ fw_iso_resources_free(&motu->rx_resources);
+ }
+}
+
static int ensure_packet_formats(struct snd_motu *motu)
{
__be32 reg;
sizeof(reg));
}
-int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
+int snd_motu_stream_start_duplex(struct snd_motu *motu)
{
- const struct snd_motu_protocol *protocol = motu->spec->protocol;
- unsigned int curr_rate;
int err = 0;
if (motu->substreams_counter == 0)
return 0;
- err = snd_motu_stream_cache_packet_formats(motu);
- if (err < 0)
- return err;
-
- // Stop stream if rate is different.
- err = protocol->get_clock_rate(motu, &curr_rate);
- if (err < 0) {
- dev_err(&motu->unit->device,
- "fail to get sampling rate: %d\n", err);
- return err;
- }
- if (rate == 0)
- rate = curr_rate;
- if (rate != curr_rate ||
- amdtp_streaming_error(&motu->rx_stream) ||
+ if (amdtp_streaming_error(&motu->rx_stream) ||
amdtp_streaming_error(&motu->tx_stream))
finish_session(motu);
if (!amdtp_stream_running(&motu->rx_stream)) {
- err = protocol->set_clock_rate(motu, rate);
- if (err < 0) {
- dev_err(&motu->unit->device,
- "fail to set sampling rate: %d\n", err);
- return err;
- }
-
err = ensure_packet_formats(motu);
if (err < 0)
return err;
- err = begin_session(motu, rate);
+ err = begin_session(motu);
if (err < 0) {
dev_err(&motu->unit->device,
"fail to start isochronous comm: %d\n", err);
goto stop_streams;
}
- err = protocol->switch_fetching_mode(motu, true);
+ err = motu->spec->protocol->switch_fetching_mode(motu, true);
if (err < 0) {
dev_err(&motu->unit->device,
"fail to enable frame fetching: %d\n", err);
if (err < 0) {
dev_err(&motu->unit->device,
"fail to start IR context: %d", err);
- amdtp_stream_stop(&motu->rx_stream);
goto stop_streams;
}
}