[PATCH 11/11] ALSA: firewire-motu: notify event for parameter change in register DSP model

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxx>
---
 include/uapi/sound/firewire.h                 |  8 ++++
 sound/firewire/motu/motu-hwdep.c              | 46 +++++++++++++++----
 .../motu/motu-register-dsp-message-parser.c   | 39 ++++++++++++++++
 sound/firewire/motu/motu.h                    |  2 +
 4 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h
index d52691655d79..76190a0cb069 100644
--- a/include/uapi/sound/firewire.h
+++ b/include/uapi/sound/firewire.h
@@ -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;
 };
 
 
diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c
index 389e59ff768b..9c2e457ce692 100644
--- a/sound/firewire/motu/motu-hwdep.c
+++ b/sound/firewire/motu/motu-hwdep.c
@@ -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;
diff --git a/sound/firewire/motu/motu-register-dsp-message-parser.c b/sound/firewire/motu/motu-register-dsp-message-parser.c
index cda8e6d987cc..cbc06b3b70f6 100644
--- a/sound/firewire/motu/motu-register-dsp-message-parser.c
+++ b/sound/firewire/motu/motu-register-dsp-message-parser.c
@@ -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;
+}
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index 9703d3af59ec..79704ae6a73e 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -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);
-- 
2.30.2




[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux