diff options
Diffstat (limited to 'sound/firewire/digi00x/digi00x-stream.c')
-rw-r--r-- | sound/firewire/digi00x/digi00x-stream.c | 183 |
1 files changed, 91 insertions, 92 deletions
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index ac8052c66b6f..3e77dbd3ee22 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -124,11 +124,25 @@ int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x, static void finish_session(struct snd_dg00x *dg00x) { - __be32 data = cpu_to_be32(0x00000003); + __be32 data; + + amdtp_stream_stop(&dg00x->tx_stream); + amdtp_stream_stop(&dg00x->rx_stream); + data = cpu_to_be32(0x00000003); snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET, &data, sizeof(data), 0); + + // Unregister isochronous channels for both direction. + data = 0; + snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, + DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS, + &data, sizeof(data), 0); + + // Just after finishing the session, the device may lost transmitting + // functionality for a short time. + msleep(50); } static int begin_session(struct snd_dg00x *dg00x) @@ -137,11 +151,20 @@ static int begin_session(struct snd_dg00x *dg00x) u32 curr; int err; + // Register isochronous channels for both direction. + data = cpu_to_be32((dg00x->tx_resources.channel << 16) | + dg00x->rx_resources.channel); + err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, + DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS, + &data, sizeof(data), 0); + if (err < 0) + return err; + err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST, DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE, &data, sizeof(data), 0); if (err < 0) - goto error; + return err; curr = be32_to_cpu(data); if (curr == 0) @@ -156,39 +179,23 @@ static int begin_session(struct snd_dg00x *dg00x) DG00X_OFFSET_STREAMING_SET, &data, sizeof(data), 0); if (err < 0) - goto error; + break; msleep(20); curr--; } - return 0; -error: - finish_session(dg00x); return err; } -static void release_resources(struct snd_dg00x *dg00x) +static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream, + unsigned int rate) { - __be32 data = 0; - - /* Unregister isochronous channels for both direction. */ - snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, - DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS, - &data, sizeof(data), 0); - - /* 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, unsigned int rate) -{ - unsigned int i; - __be32 data; + struct fw_iso_resources *resources; + int i; int err; - /* Check sampling rate. */ + // Check sampling rate. for (i = 0; i < SND_DG00X_RATE_COUNT; i++) { if (snd_dg00x_stream_rates[i] == rate) break; @@ -196,41 +203,19 @@ static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate) if (i == SND_DG00X_RATE_COUNT) return -EINVAL; - /* Keep resources for out-stream. */ - err = amdtp_dot_set_parameters(&dg00x->rx_stream, rate, - snd_dg00x_stream_pcm_channels[i]); - if (err < 0) - return err; - err = fw_iso_resources_allocate(&dg00x->rx_resources, - amdtp_stream_get_max_payload(&dg00x->rx_stream), - fw_parent_device(dg00x->unit)->max_speed); - if (err < 0) - return err; + if (stream == &dg00x->tx_stream) + resources = &dg00x->tx_resources; + else + resources = &dg00x->rx_resources; - /* Keep resources for in-stream. */ - err = amdtp_dot_set_parameters(&dg00x->tx_stream, rate, + err = amdtp_dot_set_parameters(stream, rate, snd_dg00x_stream_pcm_channels[i]); if (err < 0) return err; - err = fw_iso_resources_allocate(&dg00x->tx_resources, - amdtp_stream_get_max_payload(&dg00x->tx_stream), - fw_parent_device(dg00x->unit)->max_speed); - if (err < 0) - goto error; - /* Register isochronous channels for both direction. */ - data = cpu_to_be32((dg00x->tx_resources.channel << 16) | - dg00x->rx_resources.channel); - err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, - DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS, - &data, sizeof(data), 0); - if (err < 0) - goto error; - - return 0; -error: - release_resources(dg00x); - return err; + return fw_iso_resources_allocate(resources, + amdtp_stream_get_max_payload(stream), + fw_parent_device(dg00x->unit)->max_speed); } int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) @@ -272,43 +257,68 @@ 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); - amdtp_stream_stop(&dg00x->tx_stream); - amdtp_stream_stop(&dg00x->rx_stream); - 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) + return err; + + err = keep_resources(dg00x, &dg00x->rx_stream, rate); + if (err < 0) + return err; + + err = keep_resources(dg00x, &dg00x->tx_stream, rate); + if (err < 0) { + fw_iso_resources_free(&dg00x->rx_resources); + return err; + } + } + + return 0; +} + +int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) +{ + unsigned int generation = dg00x->rx_resources.generation; + 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); + + if (generation != fw_parent_device(dg00x->unit)->card->generation) { + err = fw_iso_resources_update(&dg00x->tx_resources); + if (err < 0) goto error; - err = keep_resources(dg00x, rate); + err = fw_iso_resources_update(&dg00x->rx_resources); if (err < 0) goto error; + } + /* + * 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; @@ -343,33 +353,22 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate) goto error; } } -end: - return err; + + return 0; error: finish_session(dg00x); - amdtp_stream_stop(&dg00x->tx_stream); - amdtp_stream_stop(&dg00x->rx_stream); - release_resources(dg00x); - return err; } void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x) { - if (dg00x->substreams_counter > 0) - return; - - amdtp_stream_stop(&dg00x->tx_stream); - amdtp_stream_stop(&dg00x->rx_stream); - finish_session(dg00x); - release_resources(dg00x); + if (dg00x->substreams_counter == 0) { + finish_session(dg00x); - /* - * Just after finishing the session, the device may lost transmitting - * functionality for a short time. - */ - msleep(50); + fw_iso_resources_free(&dg00x->tx_resources); + fw_iso_resources_free(&dg00x->rx_resources); + } } void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x) |