Skip to content

Commit

Permalink
ALSA: firewire-motu: notify event for parameter change in register DS…
Browse files Browse the repository at this point in the history
…P model

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 <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
takaswie authored and tiwai committed Oct 15, 2021
1 parent 4c9eda8 commit 634ec0b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 9 deletions.
8 changes: 8 additions & 0 deletions include/uapi/sound/firewire.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand All @@ -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;
};


Expand Down
46 changes: 37 additions & 9 deletions sound/firewire/motu/motu-hwdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions sound/firewire/motu/motu-register-dsp-message-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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);
}

Expand All @@ -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;
}
2 changes: 2 additions & 0 deletions sound/firewire/motu/motu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 634ec0b

Please sign in to comment.