ALSA: firewire-motu: add ioctl command to read cached hardware meter
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Fri, 15 Oct 2021 08:08:18 +0000 (17:08 +0900)
committerTakashi Iwai <tiwai@suse.de>
Fri, 15 Oct 2021 15:52:09 +0000 (17:52 +0200)
This patch adds new ioctl commands for userspace applications to read
cached image about hardware meters in register DSP and command DSP models.

The content of image differs depending on models. Model-specific parser
should be implemented in userspace.

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

index 82d4765..a8df8fb 100644 (file)
@@ -80,6 +80,8 @@ union snd_firewire_event {
 #define SNDRV_FIREWIRE_IOCTL_LOCK      _IO('H', 0xf9)
 #define SNDRV_FIREWIRE_IOCTL_UNLOCK    _IO('H', 0xfa)
 #define SNDRV_FIREWIRE_IOCTL_TASCAM_STATE _IOR('H', 0xfb, struct snd_firewire_tascam_state)
+#define SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_METER   _IOR('H', 0xfc, struct snd_firewire_motu_register_dsp_meter)
+#define SNDRV_FIREWIRE_IOCTL_MOTU_COMMAND_DSP_METER    _IOR('H', 0xfd, struct snd_firewire_motu_command_dsp_meter)
 
 #define SNDRV_FIREWIRE_TYPE_DICE       1
 #define SNDRV_FIREWIRE_TYPE_FIREWORKS  2
index 6716074..18689fc 100644 (file)
@@ -23,6 +23,7 @@ enum msg_parser_state {
 };
 
 struct msg_parser {
+       spinlock_t lock;
        enum msg_parser_state state;
        unsigned int interval;
        unsigned int message_count;
@@ -39,6 +40,7 @@ int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)
        parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
        if (!parser)
                return -ENOMEM;
+       spin_lock_init(&parser->lock);
        motu->message_parser = parser;
 
        return 0;
@@ -83,8 +85,11 @@ void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const stru
 {
        struct msg_parser *parser = motu->message_parser;
        unsigned int interval = parser->interval;
+       unsigned long flags;
        int i;
 
+       spin_lock_irqsave(&parser->lock, flags);
+
        for (i = 0; i < desc_count; ++i) {
                const struct pkt_desc *desc = descs + i;
                __be32 *buffer = desc->ctx_payload;
@@ -157,4 +162,17 @@ void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const stru
                        }
                }
        }
+
+       spin_unlock_irqrestore(&parser->lock, flags);
+}
+
+void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
+                                       struct snd_firewire_motu_command_dsp_meter *meter)
+{
+       struct msg_parser *parser = motu->message_parser;
+       unsigned long flags;
+
+       spin_lock_irqsave(&parser->lock, flags);
+       memcpy(meter, &parser->meter, sizeof(*meter));
+       spin_unlock_irqrestore(&parser->lock, flags);
 }
index b5ced5d..7be576f 100644 (file)
@@ -155,6 +155,50 @@ static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
                return hwdep_lock(motu);
        case SNDRV_FIREWIRE_IOCTL_UNLOCK:
                return hwdep_unlock(motu);
+       case SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_METER:
+       {
+               struct snd_firewire_motu_register_dsp_meter *meter;
+               int err;
+
+               if (!(motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP))
+                       return -ENXIO;
+
+               meter = kzalloc(sizeof(*meter), GFP_KERNEL);
+               if (!meter)
+                       return -ENOMEM;
+
+               snd_motu_register_dsp_message_parser_copy_meter(motu, meter);
+
+               err = copy_to_user((void __user *)arg, meter, sizeof(*meter));
+               kfree(meter);
+
+               if (err)
+                       return -EFAULT;
+
+               return 0;
+       }
+       case SNDRV_FIREWIRE_IOCTL_MOTU_COMMAND_DSP_METER:
+       {
+               struct snd_firewire_motu_command_dsp_meter *meter;
+               int err;
+
+               if (!(motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP))
+                       return -ENXIO;
+
+               meter = kzalloc(sizeof(*meter), GFP_KERNEL);
+               if (!meter)
+                       return -ENOMEM;
+
+               snd_motu_command_dsp_message_parser_copy_meter(motu, meter);
+
+               err = copy_to_user((void __user *)arg, meter, sizeof(*meter));
+               kfree(meter);
+
+               if (err)
+                       return -EFAULT;
+
+               return 0;
+       }
        default:
                return -ENOIOCTLCMD;
        }
index efb9708..fe80461 100644 (file)
@@ -79,6 +79,7 @@ enum register_dsp_msg_type {
 };
 
 struct msg_parser {
+       spinlock_t lock;
        struct snd_firewire_motu_register_dsp_meter meter;
        bool meter_pos_quirk;
 };
@@ -89,6 +90,7 @@ int snd_motu_register_dsp_message_parser_new(struct snd_motu *motu)
        parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
        if (!parser)
                return -ENOMEM;
+       spin_lock_init(&parser->lock);
        if (motu->spec == &snd_motu_spec_4pre || motu->spec == &snd_motu_spec_audio_express)
                parser->meter_pos_quirk = true;
        motu->message_parser = parser;
@@ -105,8 +107,11 @@ 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 long flags;
        int i;
 
+       spin_lock_irqsave(&parser->lock, flags);
+
        for (i = 0; i < desc_count; ++i) {
                const struct pkt_desc *desc = descs + i;
                __be32 *buffer = desc->ctx_payload;
@@ -142,4 +147,17 @@ void snd_motu_register_dsp_message_parser_parse(struct snd_motu *motu, const str
                        }
                }
        }
+
+       spin_unlock_irqrestore(&parser->lock, flags);
+}
+
+void snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu,
+                                               struct snd_firewire_motu_register_dsp_meter *meter)
+{
+       struct msg_parser *parser = motu->message_parser;
+       unsigned long flags;
+
+       spin_lock_irqsave(&parser->lock, flags);
+       memcpy(meter, &parser->meter, sizeof(*meter));
+       spin_unlock_irqrestore(&parser->lock, flags);
 }
index d818ce4..4f70036 100644 (file)
@@ -278,11 +278,15 @@ int snd_motu_register_dsp_message_parser_new(struct snd_motu *motu);
 int snd_motu_register_dsp_message_parser_init(struct snd_motu *motu);
 void snd_motu_register_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
                                        unsigned int desc_count, unsigned int data_block_quadlets);
+void snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu,
+                                       struct snd_firewire_motu_register_dsp_meter *meter);
 
 
 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);
 void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
                                        unsigned int desc_count, unsigned int data_block_quadlets);
+void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
+                                       struct snd_firewire_motu_command_dsp_meter *meter);
 
 #endif