Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ff-hwdep.c - a part of driver for RME Fireface series
0004  *
0005  * Copyright (c) 2015-2017 Takashi Sakamoto
0006  */
0007 
0008 /*
0009  * This codes give three functionality.
0010  *
0011  * 1.get firewire node information
0012  * 2.get notification about starting/stopping stream
0013  * 3.lock/unlock stream
0014  */
0015 
0016 #include "ff.h"
0017 
0018 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
0019                loff_t *offset)
0020 {
0021     struct snd_ff *ff = hwdep->private_data;
0022     DEFINE_WAIT(wait);
0023     union snd_firewire_event event;
0024 
0025     spin_lock_irq(&ff->lock);
0026 
0027     while (!ff->dev_lock_changed) {
0028         prepare_to_wait(&ff->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
0029         spin_unlock_irq(&ff->lock);
0030         schedule();
0031         finish_wait(&ff->hwdep_wait, &wait);
0032         if (signal_pending(current))
0033             return -ERESTARTSYS;
0034         spin_lock_irq(&ff->lock);
0035     }
0036 
0037     memset(&event, 0, sizeof(event));
0038     event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
0039     event.lock_status.status = (ff->dev_lock_count > 0);
0040     ff->dev_lock_changed = false;
0041 
0042     count = min_t(long, count, sizeof(event.lock_status));
0043 
0044     spin_unlock_irq(&ff->lock);
0045 
0046     if (copy_to_user(buf, &event, count))
0047         return -EFAULT;
0048 
0049     return count;
0050 }
0051 
0052 static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
0053                    poll_table *wait)
0054 {
0055     struct snd_ff *ff = hwdep->private_data;
0056     __poll_t events;
0057 
0058     poll_wait(file, &ff->hwdep_wait, wait);
0059 
0060     spin_lock_irq(&ff->lock);
0061     if (ff->dev_lock_changed)
0062         events = EPOLLIN | EPOLLRDNORM;
0063     else
0064         events = 0;
0065     spin_unlock_irq(&ff->lock);
0066 
0067     return events;
0068 }
0069 
0070 static int hwdep_get_info(struct snd_ff *ff, void __user *arg)
0071 {
0072     struct fw_device *dev = fw_parent_device(ff->unit);
0073     struct snd_firewire_get_info info;
0074 
0075     memset(&info, 0, sizeof(info));
0076     info.type = SNDRV_FIREWIRE_TYPE_FIREFACE;
0077     info.card = dev->card->index;
0078     *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
0079     *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
0080     strscpy(info.device_name, dev_name(&dev->device),
0081         sizeof(info.device_name));
0082 
0083     if (copy_to_user(arg, &info, sizeof(info)))
0084         return -EFAULT;
0085 
0086     return 0;
0087 }
0088 
0089 static int hwdep_lock(struct snd_ff *ff)
0090 {
0091     int err;
0092 
0093     spin_lock_irq(&ff->lock);
0094 
0095     if (ff->dev_lock_count == 0) {
0096         ff->dev_lock_count = -1;
0097         err = 0;
0098     } else {
0099         err = -EBUSY;
0100     }
0101 
0102     spin_unlock_irq(&ff->lock);
0103 
0104     return err;
0105 }
0106 
0107 static int hwdep_unlock(struct snd_ff *ff)
0108 {
0109     int err;
0110 
0111     spin_lock_irq(&ff->lock);
0112 
0113     if (ff->dev_lock_count == -1) {
0114         ff->dev_lock_count = 0;
0115         err = 0;
0116     } else {
0117         err = -EBADFD;
0118     }
0119 
0120     spin_unlock_irq(&ff->lock);
0121 
0122     return err;
0123 }
0124 
0125 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
0126 {
0127     struct snd_ff *ff = hwdep->private_data;
0128 
0129     spin_lock_irq(&ff->lock);
0130     if (ff->dev_lock_count == -1)
0131         ff->dev_lock_count = 0;
0132     spin_unlock_irq(&ff->lock);
0133 
0134     return 0;
0135 }
0136 
0137 static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
0138                unsigned int cmd, unsigned long arg)
0139 {
0140     struct snd_ff *ff = hwdep->private_data;
0141 
0142     switch (cmd) {
0143     case SNDRV_FIREWIRE_IOCTL_GET_INFO:
0144         return hwdep_get_info(ff, (void __user *)arg);
0145     case SNDRV_FIREWIRE_IOCTL_LOCK:
0146         return hwdep_lock(ff);
0147     case SNDRV_FIREWIRE_IOCTL_UNLOCK:
0148         return hwdep_unlock(ff);
0149     default:
0150         return -ENOIOCTLCMD;
0151     }
0152 }
0153 
0154 #ifdef CONFIG_COMPAT
0155 static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
0156                   unsigned int cmd, unsigned long arg)
0157 {
0158     return hwdep_ioctl(hwdep, file, cmd,
0159                (unsigned long)compat_ptr(arg));
0160 }
0161 #else
0162 #define hwdep_compat_ioctl NULL
0163 #endif
0164 
0165 int snd_ff_create_hwdep_devices(struct snd_ff *ff)
0166 {
0167     static const struct snd_hwdep_ops hwdep_ops = {
0168         .read       = hwdep_read,
0169         .release    = hwdep_release,
0170         .poll       = hwdep_poll,
0171         .ioctl      = hwdep_ioctl,
0172         .ioctl_compat   = hwdep_compat_ioctl,
0173     };
0174     struct snd_hwdep *hwdep;
0175     int err;
0176 
0177     err = snd_hwdep_new(ff->card, ff->card->driver, 0, &hwdep);
0178     if (err < 0)
0179         return err;
0180 
0181     strcpy(hwdep->name, ff->card->driver);
0182     hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREFACE;
0183     hwdep->ops = hwdep_ops;
0184     hwdep->private_data = ff;
0185     hwdep->exclusive = true;
0186 
0187     return 0;
0188 }