diff options
| author | Kees Cook <kees+treewide@kernel.org> | 2026-09-02 15:31:14 -0700 |
|---|---|---|
| committer | Kees Cook <kees@kernel.org> | 2026-09-04 21:37:00 -0700 |
| commit | 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d (patch) | |
| tree | c65086f9bdcd48c6360fb7cb4598bca084da1f32 /sound/firewire/fireface/ff-hwdep.c | |
| download | linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.tar.gz linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.zip | |
treewide: refresh kmalloc_obj() conversionsgrafted
This is another run of the Coccinelle script for converting kmalloc()
family of allocations to kmalloc_obj() via the existing rules in
scripts/coccinelle/api/kmalloc_objs.cocci
This catches both the set of kmalloc() uses added since the first
kmalloc_obj() conversions in v7.0 and adds a large group missed in the
first pass due to Coccinelle not interacting well with the cleanup.h
scoped_...() family of macros[1]. I worked around this with spatch's
"--macro-file" argument to a file with all the scoped_...() macros mapped
to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control
flow indicator I could find.
Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc,
riscv, and s390 with no new warnings.
Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1]
Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2]
Signed-off-by: Kees Cook <kees+treewide@kernel.org>
Diffstat (limited to 'sound/firewire/fireface/ff-hwdep.c')
| -rw-r--r-- | sound/firewire/fireface/ff-hwdep.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/sound/firewire/fireface/ff-hwdep.c b/sound/firewire/fireface/ff-hwdep.c new file mode 100644 index 000000000..5976abf2e --- /dev/null +++ b/sound/firewire/fireface/ff-hwdep.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ff-hwdep.c - a part of driver for RME Fireface series + * + * Copyright (c) 2015-2017 Takashi Sakamoto + */ + +/* + * This codes give three functionality. + * + * 1.get firewire node information + * 2.get notification about starting/stopping stream + * 3.lock/unlock stream + */ + +#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); + + spin_lock_irq(&ff->lock); + + while (!ff->dev_lock_changed && !has_msg(ff)) { + prepare_to_wait(&ff->hwdep_wait, &wait, TASK_INTERRUPTIBLE); + spin_unlock_irq(&ff->lock); + schedule(); + finish_wait(&ff->hwdep_wait, &wait); + if (signal_pending(current)) + return -ERESTARTSYS; + spin_lock_irq(&ff->lock); + } + + 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), + }; + + ff->dev_lock_changed = false; + + spin_unlock_irq(&ff->lock); + + 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; +} + +static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, + poll_table *wait) +{ + struct snd_ff *ff = hwdep->private_data; + + poll_wait(file, &ff->hwdep_wait, wait); + + guard(spinlock_irq)(&ff->lock); + if (ff->dev_lock_changed || has_msg(ff)) + return EPOLLIN | EPOLLRDNORM; + else + return 0; +} + +static int hwdep_get_info(struct snd_ff *ff, void __user *arg) +{ + struct fw_device *dev = fw_parent_device(ff->unit); + struct snd_firewire_get_info info; + + memset(&info, 0, sizeof(info)); + info.type = SNDRV_FIREWIRE_TYPE_FIREFACE; + info.card = dev->card->index; + *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); + *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); + strscpy(info.device_name, dev_name(&dev->device), + sizeof(info.device_name)); + + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} + +static int hwdep_lock(struct snd_ff *ff) +{ + guard(spinlock_irq)(&ff->lock); + + if (ff->dev_lock_count == 0) { + ff->dev_lock_count = -1; + return 0; + } else { + return -EBUSY; + } +} + +static int hwdep_unlock(struct snd_ff *ff) +{ + guard(spinlock_irq)(&ff->lock); + + if (ff->dev_lock_count == -1) { + ff->dev_lock_count = 0; + return 0; + } else { + return -EBADFD; + } +} + +static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) +{ + struct snd_ff *ff = hwdep->private_data; + + guard(spinlock_irq)(&ff->lock); + if (ff->dev_lock_count == -1) + ff->dev_lock_count = 0; + + return 0; +} + +static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct snd_ff *ff = hwdep->private_data; + + switch (cmd) { + case SNDRV_FIREWIRE_IOCTL_GET_INFO: + return hwdep_get_info(ff, (void __user *)arg); + case SNDRV_FIREWIRE_IOCTL_LOCK: + return hwdep_lock(ff); + case SNDRV_FIREWIRE_IOCTL_UNLOCK: + return hwdep_unlock(ff); + default: + return -ENOIOCTLCMD; + } +} + +#ifdef CONFIG_COMPAT +static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return hwdep_ioctl(hwdep, file, cmd, + (unsigned long)compat_ptr(arg)); +} +#else +#define hwdep_compat_ioctl NULL +#endif + +int snd_ff_create_hwdep_devices(struct snd_ff *ff) +{ + static const struct snd_hwdep_ops hwdep_ops = { + .read = hwdep_read, + .release = hwdep_release, + .poll = hwdep_poll, + .ioctl = hwdep_ioctl, + .ioctl_compat = hwdep_compat_ioctl, + }; + struct snd_hwdep *hwdep; + int err; + + err = snd_hwdep_new(ff->card, ff->card->driver, 0, &hwdep); + if (err < 0) + return err; + + strscpy(hwdep->name, ff->card->driver); + hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREFACE; + hwdep->ops = hwdep_ops; + hwdep->private_data = ff; + hwdep->exclusive = true; + + return 0; +} |
