#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
 
 };
 
 struct msg_parser {
+       spinlock_t lock;
        enum msg_parser_state state;
        unsigned int interval;
        unsigned int message_count;
        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;
 {
        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;
                        }
                }
        }
+
+       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);
 }
 
                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;
        }
 
 };
 
 struct msg_parser {
+       spinlock_t lock;
        struct snd_firewire_motu_register_dsp_meter meter;
        bool meter_pos_quirk;
 };
        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;
 {
        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;
                        }
                }
        }
+
+       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);
 }
 
 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