Commit a8c0d132 authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai

ALSA: firewire-tascam: notify events of change of state for userspace applications

In former commits, ALSA firewire-tascam driver queues events to notify
change of state of control surface to userspace via ALSA hwdep
interface.

This commit implements actual notification of the events. The events are
not governed by real time, thus no need to care underrun.
Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent afb8e2da
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475 #define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475
#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c #define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c
#define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479 #define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479
#define SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL 0x7473636d
struct snd_firewire_event_common { struct snd_firewire_event_common {
unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */ unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
...@@ -59,12 +60,18 @@ struct snd_firewire_tascam_change { ...@@ -59,12 +60,18 @@ struct snd_firewire_tascam_change {
__be32 after; __be32 after;
}; };
struct snd_firewire_event_tascam_control {
unsigned int type;
struct snd_firewire_tascam_change changes[0];
};
union snd_firewire_event { union snd_firewire_event {
struct snd_firewire_event_common common; struct snd_firewire_event_common common;
struct snd_firewire_event_lock_status lock_status; struct snd_firewire_event_lock_status lock_status;
struct snd_firewire_event_dice_notification dice_notification; struct snd_firewire_event_dice_notification dice_notification;
struct snd_firewire_event_efw_response efw_response; struct snd_firewire_event_efw_response efw_response;
struct snd_firewire_event_digi00x_message digi00x_message; 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_notification motu_notification;
}; };
......
...@@ -156,6 +156,8 @@ static void read_status_messages(struct amdtp_stream *s, ...@@ -156,6 +156,8 @@ static void read_status_messages(struct amdtp_stream *s,
if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT) if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
tscm->push_pos = 0; tscm->push_pos = 0;
spin_unlock_irq(&tscm->lock); spin_unlock_irq(&tscm->lock);
wake_up(&tscm->hwdep_wait);
} }
} }
......
...@@ -35,6 +35,65 @@ static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf, ...@@ -35,6 +35,65 @@ static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
return count; return count;
} }
static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
long remained, loff_t *offset)
{
char __user *pos = buf;
unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL;
struct snd_firewire_tascam_change *entries = tscm->queue;
long count;
// At least, one control event can be copied.
if (remained < sizeof(type) + sizeof(*entries)) {
spin_unlock_irq(&tscm->lock);
return -EINVAL;
}
// Copy the type field later.
count = sizeof(type);
remained -= sizeof(type);
pos += sizeof(type);
while (true) {
unsigned int head_pos;
unsigned int tail_pos;
unsigned int length;
if (tscm->pull_pos == tscm->push_pos)
break;
else if (tscm->pull_pos < tscm->push_pos)
tail_pos = tscm->push_pos;
else
tail_pos = SND_TSCM_QUEUE_COUNT;
head_pos = tscm->pull_pos;
length = (tail_pos - head_pos) * sizeof(*entries);
if (remained < length)
length = rounddown(remained, sizeof(*entries));
if (length == 0)
break;
spin_unlock_irq(&tscm->lock);
if (copy_to_user(pos, &entries[head_pos], length))
return -EFAULT;
spin_lock_irq(&tscm->lock);
tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT;
count += length;
remained -= length;
pos += length;
}
spin_unlock_irq(&tscm->lock);
if (copy_to_user(buf, &type, sizeof(type)))
return -EFAULT;
return count;
}
static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
loff_t *offset) loff_t *offset)
{ {
...@@ -43,7 +102,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, ...@@ -43,7 +102,7 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
spin_lock_irq(&tscm->lock); spin_lock_irq(&tscm->lock);
while (!tscm->dev_lock_changed) { while (!tscm->dev_lock_changed && tscm->push_pos == tscm->pull_pos) {
prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
spin_unlock_irq(&tscm->lock); spin_unlock_irq(&tscm->lock);
schedule(); schedule();
...@@ -56,6 +115,8 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, ...@@ -56,6 +115,8 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
// NOTE: The acquired lock should be released in callee side. // NOTE: The acquired lock should be released in callee side.
if (tscm->dev_lock_changed) { if (tscm->dev_lock_changed) {
count = tscm_hwdep_read_locked(tscm, buf, count, offset); count = tscm_hwdep_read_locked(tscm, buf, count, offset);
} else if (tscm->push_pos != tscm->pull_pos) {
count = tscm_hwdep_read_queue(tscm, buf, count, offset);
} else { } else {
spin_unlock_irq(&tscm->lock); spin_unlock_irq(&tscm->lock);
count = 0; count = 0;
...@@ -73,7 +134,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, ...@@ -73,7 +134,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_wait(file, &tscm->hwdep_wait, wait); poll_wait(file, &tscm->hwdep_wait, wait);
spin_lock_irq(&tscm->lock); spin_lock_irq(&tscm->lock);
if (tscm->dev_lock_changed) if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos)
events = EPOLLIN | EPOLLRDNORM; events = EPOLLIN | EPOLLRDNORM;
else else
events = 0; events = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment