ALSA: firewire-tascam: queue events for change of control surface
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Fri, 23 Nov 2018 04:13:05 +0000 (13:13 +0900)
committerTakashi Iwai <tiwai@suse.de>
Fri, 23 Nov 2018 14:31:12 +0000 (15:31 +0100)
Units of TASCAM FireWire series transfer image of states of the unit in
tx isochronous packets. Demultiplexing of the states from the packets
is done in software interrupt context regardless of any process context.
In a view of userspace applications, it needs to have notification
mechanism to catch change of the states.

This commit implements a queue to store events for the notification. The
image of states includes fluctuating data such as level of gain/volume
for physical input/output and position of knobs. Therefore the events
are queued corresponding to some control features only.

Furthermore, the queued events are planned to be consumed by userspace
applications via ALSA hwdep interface. This commit suppresses event
queueing when no applications open the hwdep interface.

However, the queue is maintained in an optimistic scenario, thus without
any care against overrrun. This is reasonable because target events are
useless just to handle PCM frames. It starts queueing when an usespace
application opens hwdep interface, thus it's expected to read the queued
events steadily.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/uapi/sound/firewire.h
sound/firewire/tascam/amdtp-tascam.c
sound/firewire/tascam/tascam-hwdep.c
sound/firewire/tascam/tascam.h

index 012f81bf47500179e5c55cfa48d42136085a6d6a..bb067efb09c68d05cc4da46d5c9778ee6dc495bd 100644 (file)
@@ -53,6 +53,12 @@ struct snd_firewire_event_motu_notification {
        __u32 message;  /* MOTU-specific bits. */
 };
 
+struct snd_firewire_tascam_change {
+       unsigned int index;
+       __be32 before;
+       __be32 after;
+};
+
 union snd_firewire_event {
        struct snd_firewire_event_common            common;
        struct snd_firewire_event_lock_status       lock_status;
index 516cb931fd5e4cca582bac28559fa5f74e33b0c9..0e8088c9ada93aa2b9cd44ddbedd08d16e2b5efd 100644 (file)
@@ -121,13 +121,45 @@ static void read_status_messages(struct amdtp_stream *s,
                                 __be32 *buffer, unsigned int data_blocks)
 {
        struct snd_tscm *tscm = container_of(s, struct snd_tscm, tx_stream);
+       bool used = READ_ONCE(tscm->hwdep->used);
        int i;
 
        for (i = 0; i < data_blocks; i++) {
                unsigned int index;
+               __be32 before;
+               __be32 after;
 
                index = be32_to_cpu(buffer[0]) % SNDRV_FIREWIRE_TASCAM_STATE_COUNT;
-               tscm->state[index] = buffer[s->data_block_quadlets - 1];
+               before = tscm->state[index];
+               after = buffer[s->data_block_quadlets - 1];
+
+               if (used && index > 4 && index < 16) {
+                       __be32 mask;
+
+                       if (index == 5)
+                               mask = cpu_to_be32(~0x0000ffff);
+                       else if (index == 6)
+                               mask = cpu_to_be32(~0x0000ffff);
+                       else if (index == 8)
+                               mask = cpu_to_be32(~0x000f0f00);
+                       else
+                               mask = cpu_to_be32(~0x00000000);
+
+                       if ((before ^ after) & mask) {
+                               struct snd_firewire_tascam_change *entry =
+                                               &tscm->queue[tscm->push_pos];
+
+                               spin_lock_irq(&tscm->lock);
+                               entry->index = index;
+                               entry->before = before;
+                               entry->after = after;
+                               if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
+                                       tscm->push_pos = 0;
+                               spin_unlock_irq(&tscm->lock);
+                       }
+               }
+
+               tscm->state[index] = after;
                buffer += s->data_block_quadlets;
        }
 }
index a80397116c48dae895e159457adba62f1e0bc0fa..9afa827af05d3b4bc58c70dcebdbf37f1b1080ef 100644 (file)
@@ -195,5 +195,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
        hwdep->private_data = tscm;
        hwdep->exclusive = true;
 
+       tscm->hwdep = hwdep;
+
        return err;
 }
index c710496a99cf610318c86bc93ddb9f9ff8602e43..6a411ee0dcf1ab60f6e701e025ed0b7bfda19ded 100644 (file)
@@ -62,6 +62,8 @@ struct snd_fw_async_midi_port {
        int consume_bytes;
 };
 
+#define SND_TSCM_QUEUE_COUNT   16
+
 struct snd_tscm {
        struct snd_card *card;
        struct fw_unit *unit;
@@ -92,6 +94,10 @@ struct snd_tscm {
 
        // A cache of status information in tx isoc packets.
        __be32 state[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
+       struct snd_hwdep *hwdep;
+       struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT];
+       unsigned int pull_pos;
+       unsigned int push_pos;
 };
 
 #define TSCM_ADDR_BASE                 0xffff00000000ull