summaryrefslogtreecommitdiff
path: root/sound/firewire
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2011-09-05 00:11:14 +0400
committerClemens Ladisch <clemens@ladisch.de>2013-10-21 00:07:57 +0400
commit6abce9e63d44e94b16f08794fb6f5ad6d1025c79 (patch)
treeee7440d227d3fd8f1bd7d5fcc2e9fa47cdab9194 /sound/firewire
parent82fbb4f7b47683077e0716474d4f1ce65a2146cb (diff)
downloadlinux-6abce9e63d44e94b16f08794fb6f5ad6d1025c79.tar.xz
ALSA: dice: optimize bus reset handling
After a bus reset, do not stop the stream completely to avoid having to reconfigure the device when restarting the stream. Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/dice.c148
1 files changed, 93 insertions, 55 deletions
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c
index ac71b2b94eec..b081021064ed 100644
--- a/sound/firewire/dice.c
+++ b/sound/firewire/dice.c
@@ -559,24 +559,92 @@ static int dice_close(struct snd_pcm_substream *substream)
return 0;
}
-static void dice_stop_stream(struct dice *dice)
+static int dice_stream_start_packets(struct dice *dice)
{
- __be32 channel;
+ int err;
+
+ if (dice->stream_running)
+ return 0;
- if (dice->stream_running) {
- dice_enable_clear(dice);
+ err = amdtp_out_stream_start(&dice->stream, dice->resources.channel,
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ return err;
+ err = dice_enable_set(dice);
+ if (err < 0) {
amdtp_out_stream_stop(&dice->stream);
+ return err;
+ }
- channel = cpu_to_be32((u32)-1);
- snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS),
- &channel, 4);
+ dice->stream_running = true;
- fw_iso_resources_free(&dice->resources);
+ return 0;
+}
- dice->stream_running = false;
+static int dice_stream_start(struct dice *dice)
+{
+ __be32 channel;
+ int err;
+
+ if (!dice->resources.allocated) {
+ err = fw_iso_resources_allocate(&dice->resources,
+ amdtp_out_stream_get_max_payload(&dice->stream),
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ goto error;
+
+ channel = cpu_to_be32(dice->resources.channel);
+ err = snd_fw_transaction(dice->unit,
+ TCODE_WRITE_QUADLET_REQUEST,
+ rx_address(dice, RX_ISOCHRONOUS),
+ &channel, 4);
+ if (err < 0)
+ goto err_resources;
}
+
+ err = dice_stream_start_packets(dice);
+ if (err < 0)
+ goto err_rx_channel;
+
+ return 0;
+
+err_rx_channel:
+ channel = cpu_to_be32((u32)-1);
+ snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ rx_address(dice, RX_ISOCHRONOUS), &channel, 4);
+err_resources:
+ fw_iso_resources_free(&dice->resources);
+error:
+ return err;
+}
+
+static void dice_stream_stop_packets(struct dice *dice)
+{
+ if (!dice->stream_running)
+ return;
+
+ dice_enable_clear(dice);
+
+ amdtp_out_stream_stop(&dice->stream);
+
+ dice->stream_running = false;
+}
+
+static void dice_stream_stop(struct dice *dice)
+{
+ __be32 channel;
+
+ dice_stream_stop_packets(dice);
+
+ if (!dice->resources.allocated)
+ return;
+
+ channel = cpu_to_be32((u32)-1);
+ snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ rx_address(dice, RX_ISOCHRONOUS), &channel, 4);
+
+ fw_iso_resources_free(&dice->resources);
}
static int dice_hw_params(struct snd_pcm_substream *substream,
@@ -586,7 +654,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream,
int err;
mutex_lock(&dice->mutex);
- dice_stop_stream(dice);
+ dice_stream_stop(dice);
mutex_unlock(&dice->mutex);
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
@@ -608,7 +676,7 @@ static int dice_hw_free(struct snd_pcm_substream *substream)
struct dice *dice = substream->private_data;
mutex_lock(&dice->mutex);
- dice_stop_stream(dice);
+ dice_stream_stop(dice);
mutex_unlock(&dice->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
@@ -617,42 +685,17 @@ static int dice_hw_free(struct snd_pcm_substream *substream)
static int dice_prepare(struct snd_pcm_substream *substream)
{
struct dice *dice = substream->private_data;
- struct fw_device *device = fw_parent_device(dice->unit);
- __be32 channel;
int err;
mutex_lock(&dice->mutex);
if (amdtp_out_streaming_error(&dice->stream))
- dice_stop_stream(dice);
-
- if (!dice->stream_running) {
- err = fw_iso_resources_allocate(&dice->resources,
- amdtp_out_stream_get_max_payload(&dice->stream),
- device->max_speed);
- if (err < 0)
- goto error;
-
- //TODO: RX_SEQ_START
- channel = cpu_to_be32(dice->resources.channel);
- err = snd_fw_transaction(dice->unit,
- TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS),
- &channel, 4);
- if (err < 0)
- goto err_resources;
-
- err = amdtp_out_stream_start(&dice->stream,
- dice->resources.channel,
- device->max_speed);
- if (err < 0)
- goto err_resources;
-
- err = dice_enable_set(dice);
- if (err < 0)
- goto err_stream;
+ dice_stream_stop_packets(dice);
- dice->stream_running = true;
+ err = dice_stream_start(dice);
+ if (err < 0) {
+ mutex_unlock(&dice->mutex);
+ return err;
}
mutex_unlock(&dice->mutex);
@@ -660,15 +703,6 @@ static int dice_prepare(struct snd_pcm_substream *substream)
amdtp_out_stream_pcm_prepare(&dice->stream);
return 0;
-
-err_stream:
- amdtp_out_stream_stop(&dice->stream);
-err_resources:
- fw_iso_resources_free(&dice->resources);
-error:
- mutex_unlock(&dice->mutex);
-
- return err;
}
static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -941,7 +975,7 @@ static void dice_remove(struct fw_unit *unit)
mutex_lock(&dice->mutex);
amdtp_out_stream_pcm_abort(&dice->stream);
- dice_stop_stream(dice);
+ dice_stream_stop(dice);
dice_owner_clear(dice);
mutex_unlock(&dice->mutex);
@@ -953,8 +987,8 @@ static void dice_bus_reset(struct fw_unit *unit)
struct dice *dice = dev_get_drvdata(&unit->device);
mutex_lock(&dice->mutex);
+
/*
- * XXX is the following true?
* On a bus reset, the DICE firmware disables streaming and then goes
* off contemplating its own navel for hundreds of milliseconds before
* it can react to any of our attempts to reenable streaming. This
@@ -962,9 +996,13 @@ static void dice_bus_reset(struct fw_unit *unit)
* to stop so that the application can restart them in an orderly
* manner.
*/
- dice_owner_update(dice);
amdtp_out_stream_pcm_abort(&dice->stream);
- dice_stop_stream(dice);
+ dice_stream_stop_packets(dice);
+
+ dice_owner_update(dice);
+
+ fw_iso_resources_update(&dice->resources);
+
mutex_unlock(&dice->mutex);
}