/* * tascam-hwdep.c - a part of driver for TASCAM FireWire series * * Copyright (c) 2015 Takashi Sakamoto * * Licensed under the terms of the GNU General Public License, version 2. */ /* * This codes give three functionality. * * 1.get firewire node information * 2.get notification about starting/stopping stream * 3.lock/unlock stream */ #include "tascam.h" static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, loff_t *offset) { struct snd_tscm *tscm = hwdep->private_data; DEFINE_WAIT(wait); union snd_firewire_event event = { .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS, }; spin_lock_irq(&tscm->lock); while (!tscm->dev_lock_changed) { prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE); spin_unlock_irq(&tscm->lock); schedule(); finish_wait(&tscm->hwdep_wait, &wait); if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irq(&tscm->lock); } event.lock_status.status = (tscm->dev_lock_count > 0); tscm->dev_lock_changed = false; spin_unlock_irq(&tscm->lock); count = min_t(long, count, sizeof(event.lock_status)); if (copy_to_user(buf, &event, count)) return -EFAULT; return count; } static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { struct snd_tscm *tscm = hwdep->private_data; unsigned int events; poll_wait(file, &tscm->hwdep_wait, wait); spin_lock_irq(&tscm->lock); if (tscm->dev_lock_changed) events = POLLIN | POLLRDNORM; else events = 0; spin_unlock_irq(&tscm->lock); return events; } static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg) { struct fw_device *dev = fw_parent_device(tscm->unit); struct snd_firewire_get_info info; memset(&info, 0, sizeof(info)); info.type = SNDRV_FIREWIRE_TYPE_TASCAM; 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]); strlcpy(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_tscm *tscm) { int err; spin_lock_irq(&tscm->lock); if (tscm->dev_lock_count == 0) { tscm->dev_lock_count = -1; err = 0; } else { err = -EBUSY; } spin_unlock_irq(&tscm->lock); return err; } static int hwdep_unlock(struct snd_tscm *tscm) { int err; spin_lock_irq(&tscm->lock); if (tscm->dev_lock_count == -1) { tscm->dev_lock_count = 0; err = 0; } else { err = -EBADFD; } spin_unlock_irq(&tscm->lock); return err; } static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_tscm *tscm = hwdep->private_data; spin_lock_irq(&tscm->lock); if (tscm->dev_lock_count == -1) tscm->dev_lock_count = 0; spin_unlock_irq(&tscm->lock); return 0; } static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, unsigned int cmd, unsigned long arg) { struct snd_tscm *tscm = hwdep->private_data; switch (cmd) { case SNDRV_FIREWIRE_IOCTL_GET_INFO: return hwdep_get_info(tscm, (void __user *)arg); case SNDRV_FIREWIRE_IOCTL_LOCK: return hwdep_lock(tscm); case SNDRV_FIREWIRE_IOCTL_UNLOCK: return hwdep_unlock(tscm); 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 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, }; int snd_tscm_create_hwdep_device(struct snd_tscm *tscm) { struct snd_hwdep *hwdep; int err; err = snd_hwdep_new(tscm->card, "Tascam", 0, &hwdep); if (err < 0) return err; strcpy(hwdep->name, "Tascam"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM; hwdep->ops = hwdep_ops; hwdep->private_data = tscm; hwdep->exclusive = true; return err; } selected='selected'>3space:mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2017-02-01 17:45:02 +0000
committerIngo Molnar <mingo@kernel.org>2017-02-01 21:17:49 +0100
commitc8f325a59cfc718d13a50fbc746ed9b415c25e92 (patch)
treed53fbdac9d0781e39a13b2ac6b2bd258cf3b4140 /sound/firewire/digi00x/Makefile
parentbf29bddf0417a4783da3b24e8c9e017ac649326f (diff)
efi/fdt: Avoid FDT manipulation after ExitBootServices()
Some AArch64 UEFI implementations disable the MMU in ExitBootServices(), after which unaligned accesses to RAM are no longer supported. Commit: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") fixed an issue in the memory map handling of the stub FDT code, but inadvertently created an issue with such firmware, by moving some of the FDT manipulation to after the invocation of ExitBootServices(). Given that the stub's libfdt implementation uses the ordinary, accelerated string functions, which rely on hardware handling of unaligned accesses, manipulating the FDT with the MMU off may result in alignment faults. So fix the situation by moving the update_fdt_memmap() call into the callback function invoked by efi_exit_boot_services() right before it calls the ExitBootServices() UEFI service (which is arguably a better place for it anyway) Note that disabling the MMU in ExitBootServices() is not compliant with the UEFI spec, and carries great risk due to the fact that switching from cached to uncached memory accesses halfway through compiler generated code (i.e., involving a stack) can never be done in a way that is architecturally safe. Fixes: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Tested-by: Riku Voipio <riku.voipio@linaro.org> Cc: <stable@vger.kernel.org> Cc: mark.rutland@arm.com Cc: linux-efi@vger.kernel.org Cc: matt@codeblueprint.co.uk Cc: leif.lindholm@linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1485971102-23330-2-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'sound/firewire/digi00x/Makefile')