diff options
Diffstat (limited to 'sound/firewire/tascam/tascam-stream.c')
-rw-r--r-- | sound/firewire/tascam/tascam-stream.c | 203 |
1 files changed, 102 insertions, 101 deletions
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index e6fcd9e19961..e852e46ebe6f 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -165,7 +165,7 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate) __be32 reg; int err; - /* Set an option for unknown purpose. */ + // Set an option for unknown purpose. reg = cpu_to_be32(0x00200000); err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION, @@ -173,17 +173,16 @@ static int set_stream_formats(struct snd_tscm *tscm, unsigned int rate) if (err < 0) return err; - err = enable_data_channels(tscm); - if (err < 0) - return err; - - return set_clock(tscm, rate, INT_MAX); + return enable_data_channels(tscm); } static void finish_session(struct snd_tscm *tscm) { __be32 reg; + amdtp_stream_stop(&tscm->rx_stream); + amdtp_stream_stop(&tscm->tx_stream); + reg = 0; snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING, @@ -194,6 +193,19 @@ static void finish_session(struct snd_tscm *tscm) TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON, ®, sizeof(reg), 0); + // Unregister channels. + reg = cpu_to_be32(0x00000000); + snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, + TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH, + ®, sizeof(reg), 0); + reg = cpu_to_be32(0x00000000); + snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, + TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN, + ®, sizeof(reg), 0); + reg = cpu_to_be32(0x00000000); + snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, + TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH, + ®, sizeof(reg), 0); } static int begin_session(struct snd_tscm *tscm) @@ -201,6 +213,30 @@ static int begin_session(struct snd_tscm *tscm) __be32 reg; int err; + // Register the isochronous channel for transmitting stream. + reg = cpu_to_be32(tscm->tx_resources.channel); + err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, + TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH, + ®, sizeof(reg), 0); + if (err < 0) + return err; + + // Unknown. + reg = cpu_to_be32(0x00000002); + err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, + TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN, + ®, sizeof(reg), 0); + if (err < 0) + return err; + + // Register the isochronous channel for receiving stream. + reg = cpu_to_be32(tscm->rx_resources.channel); + err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, + TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH, + ®, sizeof(reg), 0); + if (err < 0) + return err; + reg = cpu_to_be32(0x00000001); err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING, @@ -215,7 +251,7 @@ static int begin_session(struct snd_tscm *tscm) if (err < 0) return err; - /* Set an option for unknown purpose. */ + // Set an option for unknown purpose. reg = cpu_to_be32(0x00002000); err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION, @@ -223,7 +259,7 @@ static int begin_session(struct snd_tscm *tscm) if (err < 0) return err; - /* Start multiplexing PCM samples on packets. */ + // Start multiplexing PCM samples on packets. reg = cpu_to_be32(0x00000001); return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, @@ -231,82 +267,24 @@ static int begin_session(struct snd_tscm *tscm) ®, sizeof(reg), 0); } -static void release_resources(struct snd_tscm *tscm) +static int keep_resources(struct snd_tscm *tscm, unsigned int rate, + struct amdtp_stream *stream) { - __be32 reg; - - /* Unregister channels. */ - reg = cpu_to_be32(0x00000000); - snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, - TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH, - ®, sizeof(reg), 0); - reg = cpu_to_be32(0x00000000); - snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, - TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN, - ®, sizeof(reg), 0); - reg = cpu_to_be32(0x00000000); - snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, - TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH, - ®, sizeof(reg), 0); - - /* Release isochronous resources. */ - fw_iso_resources_free(&tscm->tx_resources); - fw_iso_resources_free(&tscm->rx_resources); -} - -static int keep_resources(struct snd_tscm *tscm, unsigned int rate) -{ - __be32 reg; + struct fw_iso_resources *resources; int err; - /* Keep resources for in-stream. */ - err = amdtp_tscm_set_parameters(&tscm->tx_stream, rate); - if (err < 0) - return err; - err = fw_iso_resources_allocate(&tscm->tx_resources, - amdtp_stream_get_max_payload(&tscm->tx_stream), - fw_parent_device(tscm->unit)->max_speed); - if (err < 0) - goto error; + if (stream == &tscm->tx_stream) + resources = &tscm->tx_resources; + else + resources = &tscm->rx_resources; - /* Keep resources for out-stream. */ - err = amdtp_tscm_set_parameters(&tscm->rx_stream, rate); - if (err < 0) - return err; - err = fw_iso_resources_allocate(&tscm->rx_resources, - amdtp_stream_get_max_payload(&tscm->rx_stream), - fw_parent_device(tscm->unit)->max_speed); + err = amdtp_tscm_set_parameters(stream, rate); if (err < 0) return err; - /* Register the isochronous channel for transmitting stream. */ - reg = cpu_to_be32(tscm->tx_resources.channel); - err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, - TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH, - ®, sizeof(reg), 0); - if (err < 0) - goto error; - - /* Unknown */ - reg = cpu_to_be32(0x00000002); - err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, - TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN, - ®, sizeof(reg), 0); - if (err < 0) - goto error; - - /* Register the isochronous channel for receiving stream. */ - reg = cpu_to_be32(tscm->rx_resources.channel); - err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, - TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH, - ®, sizeof(reg), 0); - if (err < 0) - goto error; - - return 0; -error: - release_resources(tscm); - return err; + return fw_iso_resources_allocate(resources, + amdtp_stream_get_max_payload(stream), + fw_parent_device(tscm->unit)->max_speed); } int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) @@ -345,7 +323,7 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) return err; } -/* At bus reset, streaming is stopped and some registers are clear. */ +// At bus reset, streaming is stopped and some registers are clear. void snd_tscm_stream_update_duplex(struct snd_tscm *tscm) { amdtp_stream_pcm_abort(&tscm->tx_stream); @@ -368,33 +346,62 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) fw_iso_resources_destroy(&tscm->tx_resources); } -int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) +int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) { unsigned int curr_rate; int err; - if (tscm->substreams_counter == 0) - return 0; - err = snd_tscm_stream_get_rate(tscm, &curr_rate); if (err < 0) return err; - if (curr_rate != rate || - amdtp_streaming_error(&tscm->rx_stream) || - amdtp_streaming_error(&tscm->tx_stream)) { + + if (tscm->substreams_counter == 0 || rate != curr_rate) { finish_session(tscm); - amdtp_stream_stop(&tscm->rx_stream); - amdtp_stream_stop(&tscm->tx_stream); + fw_iso_resources_free(&tscm->tx_resources); + fw_iso_resources_free(&tscm->rx_resources); - release_resources(tscm); + err = set_clock(tscm, rate, INT_MAX); + if (err < 0) + return err; + + err = keep_resources(tscm, rate, &tscm->tx_stream); + if (err < 0) + return err; + + err = keep_resources(tscm, rate, &tscm->rx_stream); + if (err < 0) { + fw_iso_resources_free(&tscm->tx_resources); + return err; + } } - if (!amdtp_stream_running(&tscm->rx_stream)) { - err = keep_resources(tscm, rate); + return 0; +} + +int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) +{ + unsigned int generation = tscm->rx_resources.generation; + int err; + + if (tscm->substreams_counter == 0) + return 0; + + if (amdtp_streaming_error(&tscm->rx_stream) || + amdtp_streaming_error(&tscm->tx_stream)) + finish_session(tscm); + + if (generation != fw_parent_device(tscm->unit)->card->generation) { + err = fw_iso_resources_update(&tscm->tx_resources); + if (err < 0) + goto error; + + err = fw_iso_resources_update(&tscm->rx_resources); if (err < 0) goto error; + } + if (!amdtp_stream_running(&tscm->rx_stream)) { err = set_stream_formats(tscm, rate); if (err < 0) goto error; @@ -432,25 +439,19 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) return 0; error: - amdtp_stream_stop(&tscm->rx_stream); - amdtp_stream_stop(&tscm->tx_stream); - finish_session(tscm); - release_resources(tscm); return err; } void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm) { - if (tscm->substreams_counter > 0) - return; - - amdtp_stream_stop(&tscm->tx_stream); - amdtp_stream_stop(&tscm->rx_stream); + if (tscm->substreams_counter == 0) { + finish_session(tscm); - finish_session(tscm); - release_resources(tscm); + fw_iso_resources_free(&tscm->tx_resources); + fw_iso_resources_free(&tscm->rx_resources); + } } void snd_tscm_stream_lock_changed(struct snd_tscm *tscm) |