summaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/digi00x/digi00x-midi.c10
-rw-r--r--sound/firewire/digi00x/digi00x-pcm.c28
-rw-r--r--sound/firewire/digi00x/digi00x-stream.c82
-rw-r--r--sound/firewire/digi00x/digi00x.h4
4 files changed, 73 insertions, 51 deletions
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
index 7ab3d0810f6b..cca888cce0d3 100644
--- a/sound/firewire/digi00x/digi00x-midi.c
+++ b/sound/firewire/digi00x/digi00x-midi.c
@@ -18,8 +18,11 @@ static int midi_open(struct snd_rawmidi_substream *substream)
return err;
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter++;
- err = snd_dg00x_stream_start_duplex(dg00x, 0);
+ err = snd_dg00x_stream_reserve_duplex(dg00x, 0);
+ if (err >= 0) {
+ ++dg00x->substreams_counter;
+ err = snd_dg00x_stream_start_duplex(dg00x);
+ }
mutex_unlock(&dg00x->mutex);
if (err < 0)
snd_dg00x_stream_lock_release(dg00x);
@@ -32,8 +35,9 @@ static int midi_close(struct snd_rawmidi_substream *substream)
struct snd_dg00x *dg00x = substream->rmidi->private_data;
mutex_lock(&dg00x->mutex);
- dg00x->substreams_counter--;
+ --dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
+ snd_dg00x_stream_release_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
snd_dg00x_stream_lock_release(dg00x);
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index fdcff0460c53..1c04747f4fcc 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -167,12 +167,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(&dg00x->mutex);
- dg00x->substreams_counter++;
+ err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
+ if (err >= 0)
+ ++dg00x->substreams_counter;
mutex_unlock(&dg00x->mutex);
}
- return 0;
+ return err;
}
static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
@@ -187,12 +191,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(&dg00x->mutex);
- dg00x->substreams_counter++;
+ err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
+ if (err >= 0)
+ ++dg00x->substreams_counter;
mutex_unlock(&dg00x->mutex);
}
- return 0;
+ return err;
}
static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
@@ -202,9 +210,10 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&dg00x->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dg00x->substreams_counter--;
+ --dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
+ snd_dg00x_stream_release_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
@@ -218,9 +227,10 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&dg00x->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- dg00x->substreams_counter--;
+ --dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
+ snd_dg00x_stream_release_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
@@ -230,12 +240,11 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
- err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+ err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0)
amdtp_stream_pcm_prepare(&dg00x->tx_stream);
@@ -247,12 +256,11 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
- err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
+ err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0) {
amdtp_stream_pcm_prepare(&dg00x->rx_stream);
amdtp_dot_reset(&dg00x->rx_stream);
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c
index 2bddeb3e4bf5..3b903e42d29a 100644
--- a/sound/firewire/digi00x/digi00x-stream.c
+++ b/sound/firewire/digi00x/digi00x-stream.c
@@ -189,13 +189,6 @@ static int begin_session(struct snd_dg00x *dg00x)
return err;
}
-static void release_resources(struct snd_dg00x *dg00x)
-{
- /* Release isochronous resources. */
- fw_iso_resources_free(&dg00x->tx_resources);
- fw_iso_resources_free(&dg00x->rx_resources);
-}
-
static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
unsigned int rate)
{
@@ -265,45 +258,65 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
fw_iso_resources_destroy(&dg00x->tx_resources);
}
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
{
unsigned int curr_rate;
- int err = 0;
-
- if (dg00x->substreams_counter == 0)
- goto end;
+ int err;
- /* Check current sampling rate. */
err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
if (err < 0)
- goto error;
+ return err;
if (rate == 0)
rate = curr_rate;
- if (curr_rate != rate ||
- amdtp_streaming_error(&dg00x->tx_stream) ||
- amdtp_streaming_error(&dg00x->rx_stream)) {
+
+ if (dg00x->substreams_counter == 0 || curr_rate != rate) {
finish_session(dg00x);
- release_resources(dg00x);
- }
+ fw_iso_resources_free(&dg00x->tx_resources);
+ fw_iso_resources_free(&dg00x->rx_resources);
- /*
- * No packets are transmitted without receiving packets, reagardless of
- * which source of clock is used.
- */
- if (!amdtp_stream_running(&dg00x->rx_stream)) {
err = snd_dg00x_stream_set_local_rate(dg00x, rate);
if (err < 0)
- goto error;
+ return err;
err = keep_resources(dg00x, &dg00x->rx_stream, rate);
if (err < 0)
- goto error;
+ return err;
err = keep_resources(dg00x, &dg00x->tx_stream, rate);
- if (err < 0)
- goto error;
+ if (err < 0) {
+ fw_iso_resources_free(&dg00x->rx_resources);
+ return err;
+ }
+ }
+
+ return 0;
+}
+void snd_dg00x_stream_release_duplex(struct snd_dg00x *dg00x)
+{
+ if (dg00x->substreams_counter == 0) {
+ fw_iso_resources_free(&dg00x->tx_resources);
+ fw_iso_resources_free(&dg00x->rx_resources);
+ }
+}
+
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
+{
+ int err = 0;
+
+ if (dg00x->substreams_counter == 0)
+ return 0;
+
+ if (amdtp_streaming_error(&dg00x->tx_stream) ||
+ amdtp_streaming_error(&dg00x->rx_stream))
+ finish_session(dg00x);
+
+ /*
+ * No packets are transmitted without receiving packets, reagardless of
+ * which source of clock is used.
+ */
+ if (!amdtp_stream_running(&dg00x->rx_stream)) {
err = begin_session(dg00x);
if (err < 0)
goto error;
@@ -338,23 +351,18 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
goto error;
}
}
-end:
- return err;
+
+ return 0;
error:
finish_session(dg00x);
- release_resources(dg00x);
-
return err;
}
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
{
- if (dg00x->substreams_counter > 0)
- return;
-
- finish_session(dg00x);
- release_resources(dg00x);
+ if (dg00x->substreams_counter == 0)
+ finish_session(dg00x);
}
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index 4dd1bbf2ed3c..3fb1c49f6f9e 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -140,8 +140,10 @@ int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
bool *detect);
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
-int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate);
+int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
+void snd_dg00x_stream_release_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x);