mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
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: Takashi Sakamoto <o-takashi@sakamocchi.jp> Link: https://lore.kernel.org/r/20230112120954.500692-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
ab811cfffa
commit
c31909fa06
4 changed files with 49 additions and 11 deletions
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue