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

ALSA: fireface: add local framework to message parser

This commit adds local framework to message parser. This is preparation
for future work to pass event of knob control for Fireface 400 to user
space.
Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20230112120954.500692-6-o-takashi@sakamocchi.jpSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent ab811cff
......@@ -15,16 +15,23 @@
#include "ff.h"
static bool has_msg(struct snd_ff *ff)
{
if (ff->spec->protocol->has_msg)
return ff->spec->protocol->has_msg(ff);
else
return 0;
}
static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
loff_t *offset)
{
struct snd_ff *ff = hwdep->private_data;
DEFINE_WAIT(wait);
union snd_firewire_event event;
spin_lock_irq(&ff->lock);
while (!ff->dev_lock_changed) {
while (!ff->dev_lock_changed && !has_msg(ff)) {
prepare_to_wait(&ff->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
spin_unlock_irq(&ff->lock);
schedule();
......@@ -34,17 +41,29 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
spin_lock_irq(&ff->lock);
}
memset(&event, 0, sizeof(event));
event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
event.lock_status.status = (ff->dev_lock_count > 0);
ff->dev_lock_changed = false;
if (ff->dev_lock_changed && count >= sizeof(struct snd_firewire_event_lock_status)) {
struct snd_firewire_event_lock_status ev = {
.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
.status = (ff->dev_lock_count > 0),
};
count = min_t(long, count, sizeof(event.lock_status));
ff->dev_lock_changed = false;
spin_unlock_irq(&ff->lock);
spin_unlock_irq(&ff->lock);
if (copy_to_user(buf, &event, count))
return -EFAULT;
if (copy_to_user(buf, &ev, sizeof(ev)))
return -EFAULT;
count = sizeof(ev);
} else if (has_msg(ff)) {
// NOTE: Acquired spin lock should be released before accessing to user space in the
// callback since the access can cause page fault.
count = ff->spec->protocol->copy_msg_to_user(ff, buf, count);
spin_unlock_irq(&ff->lock);
} else {
spin_unlock_irq(&ff->lock);
count = 0;
}
return count;
}
......@@ -58,7 +77,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
poll_wait(file, &ff->hwdep_wait, wait);
spin_lock_irq(&ff->lock);
if (ff->dev_lock_changed)
if (ff->dev_lock_changed || has_msg(ff))
events = EPOLLIN | EPOLLRDNORM;
else
events = 0;
......
......@@ -132,11 +132,15 @@ static void handle_msg(struct fw_card *card, struct fw_request *request, int tco
struct snd_ff *ff = callback_data;
__le32 *buf = data;
u32 tstamp = fw_request_get_timestamp(request);
unsigned long flag;
fw_send_response(card, request, RCODE_COMPLETE);
offset -= ff->async_handler.offset;
spin_lock_irqsave(&ff->lock, flag);
ff->spec->protocol->handle_msg(ff, (unsigned int)offset, buf, length, tstamp);
spin_unlock_irqrestore(&ff->lock, flag);
}
static int allocate_own_address(struct snd_ff *ff, int i)
......
......@@ -43,6 +43,8 @@ static void ff_card_free(struct snd_card *card)
snd_ff_stream_destroy_duplex(ff);
snd_ff_transaction_unregister(ff);
kfree(ff->msg_parser);
mutex_destroy(&ff->mutex);
fw_unit_put(ff->unit);
}
......@@ -94,6 +96,14 @@ static int snd_ff_probe(struct fw_unit *unit, const struct ieee1394_device_id *e
if (err < 0)
goto error;
if (ff->spec->protocol->msg_parser_size > 0) {
ff->msg_parser = kzalloc(ff->spec->protocol->msg_parser_size, GFP_KERNEL);
if (!ff->msg_parser) {
err = -ENOMEM;
goto error;
}
}
err = snd_card_register(card);
if (err < 0)
goto error;
......
......@@ -97,6 +97,8 @@ struct snd_ff {
wait_queue_head_t hwdep_wait;
struct amdtp_domain domain;
void *msg_parser;
};
enum snd_ff_clock_src {
......@@ -110,6 +112,9 @@ enum snd_ff_clock_src {
};
struct snd_ff_protocol {
size_t msg_parser_size;
bool (*has_msg)(struct snd_ff *ff);
long (*copy_msg_to_user)(struct snd_ff *ff, char __user *buf, long count);
void (*handle_msg)(struct snd_ff *ff, unsigned int offset, const __le32 *buf,
size_t length, u32 tstamp);
int (*fill_midi_msg)(struct snd_ff *ff,
......
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