Path: blob/master/sound/firewire/digi00x/digi00x-hwdep.c
29266 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* digi00x-hwdep.c - a part of driver for Digidesign Digi 002/003 family3*4* Copyright (c) 2014-2015 Takashi Sakamoto5*/67/*8* This codes give three functionality.9*10* 1.get firewire node information11* 2.get notification about starting/stopping stream12* 3.lock/unlock stream13* 4.get asynchronous messaging14*/1516#include "digi00x.h"1718static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,19loff_t *offset)20{21struct snd_dg00x *dg00x = hwdep->private_data;22DEFINE_WAIT(wait);23union snd_firewire_event event;2425spin_lock_irq(&dg00x->lock);2627while (!dg00x->dev_lock_changed && dg00x->msg == 0) {28prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);29spin_unlock_irq(&dg00x->lock);30schedule();31finish_wait(&dg00x->hwdep_wait, &wait);32if (signal_pending(current))33return -ERESTARTSYS;34spin_lock_irq(&dg00x->lock);35}3637memset(&event, 0, sizeof(event));38if (dg00x->dev_lock_changed) {39event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;40event.lock_status.status = (dg00x->dev_lock_count > 0);41dg00x->dev_lock_changed = false;4243count = min_t(long, count, sizeof(event.lock_status));44} else {45event.digi00x_message.type =46SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE;47event.digi00x_message.message = dg00x->msg;48dg00x->msg = 0;4950count = min_t(long, count, sizeof(event.digi00x_message));51}5253spin_unlock_irq(&dg00x->lock);5455if (copy_to_user(buf, &event, count))56return -EFAULT;5758return count;59}6061static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,62poll_table *wait)63{64struct snd_dg00x *dg00x = hwdep->private_data;6566poll_wait(file, &dg00x->hwdep_wait, wait);6768guard(spinlock_irq)(&dg00x->lock);69if (dg00x->dev_lock_changed || dg00x->msg)70return EPOLLIN | EPOLLRDNORM;71else72return 0;73}7475static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)76{77struct fw_device *dev = fw_parent_device(dg00x->unit);78struct snd_firewire_get_info info;7980memset(&info, 0, sizeof(info));81info.type = SNDRV_FIREWIRE_TYPE_DIGI00X;82info.card = dev->card->index;83*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);84*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);85strscpy(info.device_name, dev_name(&dev->device),86sizeof(info.device_name));8788if (copy_to_user(arg, &info, sizeof(info)))89return -EFAULT;9091return 0;92}9394static int hwdep_lock(struct snd_dg00x *dg00x)95{96guard(spinlock_irq)(&dg00x->lock);9798if (dg00x->dev_lock_count == 0) {99dg00x->dev_lock_count = -1;100return 0;101} else {102return -EBUSY;103}104}105106static int hwdep_unlock(struct snd_dg00x *dg00x)107{108guard(spinlock_irq)(&dg00x->lock);109110if (dg00x->dev_lock_count == -1) {111dg00x->dev_lock_count = 0;112return 0;113} else {114return -EBADFD;115}116}117118static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)119{120struct snd_dg00x *dg00x = hwdep->private_data;121122guard(spinlock_irq)(&dg00x->lock);123if (dg00x->dev_lock_count == -1)124dg00x->dev_lock_count = 0;125126return 0;127}128129static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,130unsigned int cmd, unsigned long arg)131{132struct snd_dg00x *dg00x = hwdep->private_data;133134switch (cmd) {135case SNDRV_FIREWIRE_IOCTL_GET_INFO:136return hwdep_get_info(dg00x, (void __user *)arg);137case SNDRV_FIREWIRE_IOCTL_LOCK:138return hwdep_lock(dg00x);139case SNDRV_FIREWIRE_IOCTL_UNLOCK:140return hwdep_unlock(dg00x);141default:142return -ENOIOCTLCMD;143}144}145146#ifdef CONFIG_COMPAT147static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,148unsigned int cmd, unsigned long arg)149{150return hwdep_ioctl(hwdep, file, cmd,151(unsigned long)compat_ptr(arg));152}153#else154#define hwdep_compat_ioctl NULL155#endif156157int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)158{159static const struct snd_hwdep_ops ops = {160.read = hwdep_read,161.release = hwdep_release,162.poll = hwdep_poll,163.ioctl = hwdep_ioctl,164.ioctl_compat = hwdep_compat_ioctl,165};166struct snd_hwdep *hwdep;167int err;168169err = snd_hwdep_new(dg00x->card, "Digi00x", 0, &hwdep);170if (err < 0)171return err;172173strscpy(hwdep->name, "Digi00x");174hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;175hwdep->ops = ops;176hwdep->private_data = dg00x;177hwdep->exclusive = true;178179return err;180}181182183