ALSA: firewire-lib: transfer rx packets on-the-fly when replaying
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Thu, 27 May 2021 12:26:11 +0000 (21:26 +0900)
committerTakashi Iwai <tiwai@suse.de>
Fri, 28 May 2021 09:06:33 +0000 (11:06 +0200)
Models in below series start transmission of packet after receiving the
sequence of packets:

 * Digidesign Digi00x family
 * RME Fireface series

Additionally, models in Tascam FireWire series start multiplexing PCM
frames into packets enough after receiving packets. It's required to
transfer packets on-the-fly for the above models according to nominal
sampling transfer frequency before starting sequence replay.

This commit allows drivers to decide whether the engine transfers packet
on-the-fly or not.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20210527122611.173711-4-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/firewire/amdtp-stream.c
sound/firewire/amdtp-stream.h
sound/firewire/bebob/bebob_stream.c
sound/firewire/dice/dice-stream.c
sound/firewire/digi00x/digi00x-stream.c
sound/firewire/fireface/ff-stream.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/motu/motu-stream.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/tascam/tascam-stream.c

index 47ea03370858aa48f21dc99030c1894ba2d9a6a4..d0e9b417c019a476452c85b04374c223ea70eb8c 100644 (file)
@@ -577,10 +577,23 @@ static void pool_seq_descs(struct amdtp_stream *s, unsigned int count)
 {
        struct amdtp_domain *d = s->domain;
 
-       if (!d->replay.enable || !s->ctx_data.rx.replay_target)
+       if (!d->replay.enable || !s->ctx_data.rx.replay_target) {
                pool_ideal_seq_descs(s, count);
-       else
-               pool_replayed_seq(s, count);
+       } else {
+               if (!d->replay.on_the_fly) {
+                       pool_replayed_seq(s, count);
+               } else {
+                       struct amdtp_stream *tx = s->ctx_data.rx.replay_target;
+                       const unsigned int cache_size = tx->ctx_data.tx.cache.size;
+                       const unsigned int cache_head = s->ctx_data.rx.cache_head;
+                       unsigned int cached_cycles = calculate_cached_cycle_count(tx, cache_head);
+
+                       if (cached_cycles > count && cached_cycles > cache_size / 2)
+                               pool_replayed_seq(s, count);
+                       else
+                               pool_ideal_seq_descs(s, count);
+               }
+       }
 }
 
 static void update_pcm_pointers(struct amdtp_stream *s,
@@ -1444,7 +1457,7 @@ static void irq_target_callback_skip(struct fw_iso_context *context, u32 tstamp,
        skip_rx_packets(context, tstamp, header_length, header, private_data);
        process_ctxs_in_domain(d);
 
-       if (d->replay.enable) {
+       if (d->replay.enable && !d->replay.on_the_fly) {
                unsigned int rx_count = 0;
                unsigned int rx_ready_count = 0;
                struct amdtp_stream *rx;
@@ -1929,8 +1942,11 @@ static int make_association(struct amdtp_domain *d)
  *                      contexts.
  * @replay_seq: whether to replay the sequence of packet in IR context for the sequence of packet in
  *             IT context.
+ * @replay_on_the_fly: transfer rx packets according to nominal frequency, then begin to replay
+ *                    according to arrival of events in tx packets.
  */
-int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq)
+int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq,
+                      bool replay_on_the_fly)
 {
        unsigned int events_per_buffer = d->events_per_buffer;
        unsigned int events_per_period = d->events_per_period;
@@ -1944,6 +1960,7 @@ int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles,
                        return err;
        }
        d->replay.enable = replay_seq;
+       d->replay.on_the_fly = replay_on_the_fly;
 
        // Select an IT context as IRQ target.
        list_for_each_entry(s, &d->streams, list) {
index 61b6b5ae8b3b33af89cb81091ef9642fac45d975..b25592d5f6af395f0c0c9c9b44305dbe39681301 100644 (file)
@@ -303,7 +303,8 @@ struct amdtp_domain {
        } processing_cycle;
 
        struct {
-               bool enable;
+               bool enable:1;
+               bool on_the_fly:1;
        } replay;
 };
 
@@ -313,7 +314,8 @@ void amdtp_domain_destroy(struct amdtp_domain *d);
 int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s,
                            int channel, int speed);
 
-int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq);
+int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq,
+                      bool replay_on_the_fly);
 void amdtp_domain_stop(struct amdtp_domain *d);
 
 static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
index fb776f871133cd2e147c658d591547945bc22529..47773ca97e465147e7987fa27a7036648617c468 100644 (file)
@@ -652,7 +652,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
                // MEMO: In the early stage of packet streaming, the device transfers NODATA packets.
                // After several hundred cycles, it begins to multiplex event into the packet with
                // syt information.
-               err = amdtp_domain_start(&bebob->domain, tx_init_skip_cycles, false);
+               err = amdtp_domain_start(&bebob->domain, tx_init_skip_cycles, false, false);
                if (err < 0)
                        goto error;
 
index 064f28f1822b729b33275a14f0b43be3739126f1..0fb8b4ae6a0a53610b52a8dcdda170d337f78a7e 100644 (file)
@@ -459,7 +459,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice)
                        goto error;
                }
 
-               err = amdtp_domain_start(&dice->domain, 0, false);
+               err = amdtp_domain_start(&dice->domain, 0, false, false);
                if (err < 0)
                        goto error;
 
index 5daba75a5bf3b132042c7f626981a751f4079d66..2019f653347731daf36ed92b93f16e1a67ea9f02 100644 (file)
@@ -375,7 +375,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&dg00x->domain, 0, false);
+               err = amdtp_domain_start(&dg00x->domain, 0, false, false);
                if (err < 0)
                        goto error;
 
index 12779e7caf22df5e7d6c9fea9ad0726362dc46f0..97c356f2ac04862ebbdf6db150dd0767f85dfb93 100644 (file)
@@ -199,7 +199,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&ff->domain, 0, false);
+               err = amdtp_domain_start(&ff->domain, 0, false, false);
                if (err < 0)
                        goto error;
 
index 0106fa6d1eaf586c9cdc54340f4890e74609f24e..6fc117c3a068477fa3ba923335cdebadd15c9793 100644 (file)
@@ -272,7 +272,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&efw->domain, 0, false);
+               err = amdtp_domain_start(&efw->domain, 0, false, false);
                if (err < 0)
                        goto error;
 
index 5af9d7487cdc521a3bfc6c3b264a2801fde35dbf..5d8d067f366da06e63a2124168b9b1db4a4170f9 100644 (file)
@@ -260,7 +260,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
                if (err < 0)
                        goto stop_streams;
 
-               err = amdtp_domain_start(&motu->domain, 0, false);
+               err = amdtp_domain_start(&motu->domain, 0, false, false);
                if (err < 0)
                        goto stop_streams;
 
index a6e97a37f1295a9993a58f691cd998cd5af599a0..9792d4b4373ced23b785b23ab8f8cef3a67323fc 100644 (file)
@@ -354,7 +354,7 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
                        }
                }
 
-               err = amdtp_domain_start(&oxfw->domain, 0, false);
+               err = amdtp_domain_start(&oxfw->domain, 0, false, false);
                if (err < 0)
                        goto error;
 
index eb4c7c47f8e9163d35ada5f46a4e77f26421161d..4811b60e58236cc305e6bdaaf2511dbc14227f11 100644 (file)
@@ -473,7 +473,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
                if (err < 0)
                        goto error;
 
-               err = amdtp_domain_start(&tscm->domain, 0, false);
+               err = amdtp_domain_start(&tscm->domain, 0, false, false);
                if (err < 0)
                        return err;