Path: blob/master/sound/firewire/digi00x/digi00x-hwdep.c
26442 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;65__poll_t events;6667poll_wait(file, &dg00x->hwdep_wait, wait);6869spin_lock_irq(&dg00x->lock);70if (dg00x->dev_lock_changed || dg00x->msg)71events = EPOLLIN | EPOLLRDNORM;72else73events = 0;74spin_unlock_irq(&dg00x->lock);7576return events;77}7879static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)80{81struct fw_device *dev = fw_parent_device(dg00x->unit);82struct snd_firewire_get_info info;8384memset(&info, 0, sizeof(info));85info.type = SNDRV_FIREWIRE_TYPE_DIGI00X;86info.card = dev->card->index;87*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);88*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);89strscpy(info.device_name, dev_name(&dev->device),90sizeof(info.device_name));9192if (copy_to_user(arg, &info, sizeof(info)))93return -EFAULT;9495return 0;96}9798static int hwdep_lock(struct snd_dg00x *dg00x)99{100int err;101102spin_lock_irq(&dg00x->lock);103104if (dg00x->dev_lock_count == 0) {105dg00x->dev_lock_count = -1;106err = 0;107} else {108err = -EBUSY;109}110111spin_unlock_irq(&dg00x->lock);112113return err;114}115116static int hwdep_unlock(struct snd_dg00x *dg00x)117{118int err;119120spin_lock_irq(&dg00x->lock);121122if (dg00x->dev_lock_count == -1) {123dg00x->dev_lock_count = 0;124err = 0;125} else {126err = -EBADFD;127}128129spin_unlock_irq(&dg00x->lock);130131return err;132}133134static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)135{136struct snd_dg00x *dg00x = hwdep->private_data;137138spin_lock_irq(&dg00x->lock);139if (dg00x->dev_lock_count == -1)140dg00x->dev_lock_count = 0;141spin_unlock_irq(&dg00x->lock);142143return 0;144}145146static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,147unsigned int cmd, unsigned long arg)148{149struct snd_dg00x *dg00x = hwdep->private_data;150151switch (cmd) {152case SNDRV_FIREWIRE_IOCTL_GET_INFO:153return hwdep_get_info(dg00x, (void __user *)arg);154case SNDRV_FIREWIRE_IOCTL_LOCK:155return hwdep_lock(dg00x);156case SNDRV_FIREWIRE_IOCTL_UNLOCK:157return hwdep_unlock(dg00x);158default:159return -ENOIOCTLCMD;160}161}162163#ifdef CONFIG_COMPAT164static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,165unsigned int cmd, unsigned long arg)166{167return hwdep_ioctl(hwdep, file, cmd,168(unsigned long)compat_ptr(arg));169}170#else171#define hwdep_compat_ioctl NULL172#endif173174int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)175{176static const struct snd_hwdep_ops ops = {177.read = hwdep_read,178.release = hwdep_release,179.poll = hwdep_poll,180.ioctl = hwdep_ioctl,181.ioctl_compat = hwdep_compat_ioctl,182};183struct snd_hwdep *hwdep;184int err;185186err = snd_hwdep_new(dg00x->card, "Digi00x", 0, &hwdep);187if (err < 0)188return err;189190strscpy(hwdep->name, "Digi00x");191hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;192hwdep->ops = ops;193hwdep->private_data = dg00x;194hwdep->exclusive = true;195196return err;197}198199200