ALSA: firewire-motu: notify event for parameter change in register DSP model
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Fri, 15 Oct 2021 08:08:26 +0000 (17:08 +0900)
committerTakashi Iwai <tiwai@suse.de>
Fri, 15 Oct 2021 15:52:19 +0000 (17:52 +0200)
This commit copies queued event for change of register DSP into
userspace when application operates ALSA hwdep character device.
The notification occurs only when packet streaming is running.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20211015080826.34847-12-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/uapi/sound/firewire.h
sound/firewire/motu/motu-hwdep.c
sound/firewire/motu/motu-register-dsp-message-parser.c
sound/firewire/motu/motu.h

index d526916..76190a0 100644 (file)
@@ -13,6 +13,7 @@
 #define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE   0x746e736c
 #define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479
 #define SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL    0x7473636d
+#define SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE  0x4d545244
 
 struct snd_firewire_event_common {
        unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -65,6 +66,12 @@ struct snd_firewire_event_tascam_control {
        struct snd_firewire_tascam_change changes[0];
 };
 
+struct snd_firewire_event_motu_register_dsp_change {
+       unsigned int type;
+       __u32 count;            // The number of changes.
+       __u32 changes[];        // Encoded event for change of register DSP.
+};
+
 union snd_firewire_event {
        struct snd_firewire_event_common            common;
        struct snd_firewire_event_lock_status       lock_status;
@@ -73,6 +80,7 @@ union snd_firewire_event {
        struct snd_firewire_event_digi00x_message   digi00x_message;
        struct snd_firewire_event_tascam_control    tascam_control;
        struct snd_firewire_event_motu_notification motu_notification;
+       struct snd_firewire_event_motu_register_dsp_change motu_register_dsp_change;
 };
 
 
index 389e59f..9c2e457 100644 (file)
@@ -25,7 +25,8 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
 
        spin_lock_irq(&motu->lock);
 
-       while (!motu->dev_lock_changed && motu->msg == 0) {
+       while (!motu->dev_lock_changed && motu->msg == 0 &&
+                       snd_motu_register_dsp_message_parser_count_event(motu) == 0) {
                prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
                spin_unlock_irq(&motu->lock);
                schedule();
@@ -40,20 +41,46 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
                event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
                event.lock_status.status = (motu->dev_lock_count > 0);
                motu->dev_lock_changed = false;
+               spin_unlock_irq(&motu->lock);
 
-               count = min_t(long, count, sizeof(event.lock_status));
-       } else {
+               count = min_t(long, count, sizeof(event));
+               if (copy_to_user(buf, &event, count))
+                       return -EFAULT;
+       } else if (motu->msg > 0) {
                event.motu_notification.type = SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION;
                event.motu_notification.message = motu->msg;
                motu->msg = 0;
+               spin_unlock_irq(&motu->lock);
 
-               count = min_t(long, count, sizeof(event.motu_notification));
-       }
+               count = min_t(long, count, sizeof(event));
+               if (copy_to_user(buf, &event, count))
+                       return -EFAULT;
+       } else if (snd_motu_register_dsp_message_parser_count_event(motu) > 0) {
+               size_t consumed = 0;
+               u32 __user *ptr;
+               u32 ev;
 
-       spin_unlock_irq(&motu->lock);
+               spin_unlock_irq(&motu->lock);
 
-       if (copy_to_user(buf, &event, count))
-               return -EFAULT;
+               // Header is filled later.
+               consumed += sizeof(event.motu_register_dsp_change);
+
+               while (consumed < count &&
+                      snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) {
+                       ptr = (u32 __user *)(buf + consumed);
+                       if (put_user(ev, ptr))
+                               return -EFAULT;
+                       consumed += sizeof(ev);
+               }
+
+               event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE;
+               event.motu_register_dsp_change.count =
+                       (consumed - sizeof(event.motu_register_dsp_change)) / 4;
+               if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change)))
+                       return -EFAULT;
+
+               count = consumed;
+       }
 
        return count;
 }
@@ -67,7 +94,8 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
        poll_wait(file, &motu->hwdep_wait, wait);
 
        spin_lock_irq(&motu->lock);
-       if (motu->dev_lock_changed || motu->msg)
+       if (motu->dev_lock_changed || motu->msg ||
+           snd_motu_register_dsp_message_parser_count_event(motu) > 0)
                events = EPOLLIN | EPOLLRDNORM;
        else
                events = 0;
index cda8e6d..cbc06b3 100644 (file)
@@ -95,6 +95,7 @@ struct msg_parser {
 
        u32 event_queue[EVENT_QUEUE_SIZE];
        unsigned int push_pos;
+       unsigned int pull_pos;
 };
 
 int snd_motu_register_dsp_message_parser_new(struct snd_motu *motu)
@@ -122,6 +123,7 @@ int snd_motu_register_dsp_message_parser_init(struct snd_motu *motu)
        return 0;
 }
 
+// Rough implementaion of queue without overrun check.
 static void queue_event(struct snd_motu *motu, u8 msg_type, u8 identifier0, u8 identifier1, u8 val)
 {
        struct msg_parser *parser = motu->message_parser;
@@ -145,6 +147,7 @@ void snd_motu_register_dsp_message_parser_parse(struct snd_motu *motu, const str
 {
        struct msg_parser *parser = motu->message_parser;
        bool meter_pos_quirk = parser->meter_pos_quirk;
+       unsigned int pos = parser->push_pos;
        unsigned long flags;
        int i;
 
@@ -351,6 +354,9 @@ void snd_motu_register_dsp_message_parser_parse(struct snd_motu *motu, const str
                }
        }
 
+       if (pos != parser->push_pos)
+               wake_up(&motu->hwdep_wait);
+
        spin_unlock_irqrestore(&parser->lock, flags);
 }
 
@@ -375,3 +381,36 @@ void snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu,
        memcpy(param, &parser->param, sizeof(*param));
        spin_unlock_irqrestore(&parser->lock, flags);
 }
+
+unsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu)
+{
+       struct msg_parser *parser = motu->message_parser;
+
+       if (parser->pull_pos > parser->push_pos)
+               return EVENT_QUEUE_SIZE - parser->pull_pos + parser->push_pos;
+       else
+               return parser->push_pos - parser->pull_pos;
+}
+
+bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event)
+{
+       struct msg_parser *parser = motu->message_parser;
+       unsigned int pos = parser->pull_pos;
+       unsigned long flags;
+
+       if (pos == parser->push_pos)
+               return false;
+
+       spin_lock_irqsave(&parser->lock, flags);
+
+       *event = parser->event_queue[pos];
+
+       ++pos;
+       if (pos >= EVENT_QUEUE_SIZE)
+               pos = 0;
+       parser->pull_pos = pos;
+
+       spin_unlock_irqrestore(&parser->lock, flags);
+
+       return true;
+}
index 9703d3a..79704ae 100644 (file)
@@ -283,6 +283,8 @@ void snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu,
                                        struct snd_firewire_motu_register_dsp_meter *meter);
 void snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu,
                                        struct snd_firewire_motu_register_dsp_parameter *params);
+unsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu);
+bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event);
 
 int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu);
 int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc);