root/sound/firewire/fireface/ff-hwdep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hwdep_read
  2. hwdep_poll
  3. hwdep_get_info
  4. hwdep_lock
  5. hwdep_unlock
  6. hwdep_release
  7. hwdep_ioctl
  8. hwdep_compat_ioctl
  9. snd_ff_create_hwdep_devices

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * ff-hwdep.c - a part of driver for RME Fireface series
   4  *
   5  * Copyright (c) 2015-2017 Takashi Sakamoto
   6  */
   7 
   8 /*
   9  * This codes give three functionality.
  10  *
  11  * 1.get firewire node information
  12  * 2.get notification about starting/stopping stream
  13  * 3.lock/unlock stream
  14  */
  15 
  16 #include "ff.h"
  17 
  18 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
  19                        loff_t *offset)
  20 {
  21         struct snd_ff *ff = hwdep->private_data;
  22         DEFINE_WAIT(wait);
  23         union snd_firewire_event event;
  24 
  25         spin_lock_irq(&ff->lock);
  26 
  27         while (!ff->dev_lock_changed) {
  28                 prepare_to_wait(&ff->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
  29                 spin_unlock_irq(&ff->lock);
  30                 schedule();
  31                 finish_wait(&ff->hwdep_wait, &wait);
  32                 if (signal_pending(current))
  33                         return -ERESTARTSYS;
  34                 spin_lock_irq(&ff->lock);
  35         }
  36 
  37         memset(&event, 0, sizeof(event));
  38         if (ff->dev_lock_changed) {
  39                 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
  40                 event.lock_status.status = (ff->dev_lock_count > 0);
  41                 ff->dev_lock_changed = false;
  42 
  43                 count = min_t(long, count, sizeof(event.lock_status));
  44         }
  45 
  46         spin_unlock_irq(&ff->lock);
  47 
  48         if (copy_to_user(buf, &event, count))
  49                 return -EFAULT;
  50 
  51         return count;
  52 }
  53 
  54 static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
  55                                poll_table *wait)
  56 {
  57         struct snd_ff *ff = hwdep->private_data;
  58         __poll_t events;
  59 
  60         poll_wait(file, &ff->hwdep_wait, wait);
  61 
  62         spin_lock_irq(&ff->lock);
  63         if (ff->dev_lock_changed)
  64                 events = EPOLLIN | EPOLLRDNORM;
  65         else
  66                 events = 0;
  67         spin_unlock_irq(&ff->lock);
  68 
  69         return events;
  70 }
  71 
  72 static int hwdep_get_info(struct snd_ff *ff, void __user *arg)
  73 {
  74         struct fw_device *dev = fw_parent_device(ff->unit);
  75         struct snd_firewire_get_info info;
  76 
  77         memset(&info, 0, sizeof(info));
  78         info.type = SNDRV_FIREWIRE_TYPE_FIREFACE;
  79         info.card = dev->card->index;
  80         *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
  81         *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
  82         strlcpy(info.device_name, dev_name(&dev->device),
  83                 sizeof(info.device_name));
  84 
  85         if (copy_to_user(arg, &info, sizeof(info)))
  86                 return -EFAULT;
  87 
  88         return 0;
  89 }
  90 
  91 static int hwdep_lock(struct snd_ff *ff)
  92 {
  93         int err;
  94 
  95         spin_lock_irq(&ff->lock);
  96 
  97         if (ff->dev_lock_count == 0) {
  98                 ff->dev_lock_count = -1;
  99                 err = 0;
 100         } else {
 101                 err = -EBUSY;
 102         }
 103 
 104         spin_unlock_irq(&ff->lock);
 105 
 106         return err;
 107 }
 108 
 109 static int hwdep_unlock(struct snd_ff *ff)
 110 {
 111         int err;
 112 
 113         spin_lock_irq(&ff->lock);
 114 
 115         if (ff->dev_lock_count == -1) {
 116                 ff->dev_lock_count = 0;
 117                 err = 0;
 118         } else {
 119                 err = -EBADFD;
 120         }
 121 
 122         spin_unlock_irq(&ff->lock);
 123 
 124         return err;
 125 }
 126 
 127 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
 128 {
 129         struct snd_ff *ff = hwdep->private_data;
 130 
 131         spin_lock_irq(&ff->lock);
 132         if (ff->dev_lock_count == -1)
 133                 ff->dev_lock_count = 0;
 134         spin_unlock_irq(&ff->lock);
 135 
 136         return 0;
 137 }
 138 
 139 static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
 140                        unsigned int cmd, unsigned long arg)
 141 {
 142         struct snd_ff *ff = hwdep->private_data;
 143 
 144         switch (cmd) {
 145         case SNDRV_FIREWIRE_IOCTL_GET_INFO:
 146                 return hwdep_get_info(ff, (void __user *)arg);
 147         case SNDRV_FIREWIRE_IOCTL_LOCK:
 148                 return hwdep_lock(ff);
 149         case SNDRV_FIREWIRE_IOCTL_UNLOCK:
 150                 return hwdep_unlock(ff);
 151         default:
 152                 return -ENOIOCTLCMD;
 153         }
 154 }
 155 
 156 #ifdef CONFIG_COMPAT
 157 static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
 158                               unsigned int cmd, unsigned long arg)
 159 {
 160         return hwdep_ioctl(hwdep, file, cmd,
 161                            (unsigned long)compat_ptr(arg));
 162 }
 163 #else
 164 #define hwdep_compat_ioctl NULL
 165 #endif
 166 
 167 int snd_ff_create_hwdep_devices(struct snd_ff *ff)
 168 {
 169         static const struct snd_hwdep_ops hwdep_ops = {
 170                 .read           = hwdep_read,
 171                 .release        = hwdep_release,
 172                 .poll           = hwdep_poll,
 173                 .ioctl          = hwdep_ioctl,
 174                 .ioctl_compat   = hwdep_compat_ioctl,
 175         };
 176         struct snd_hwdep *hwdep;
 177         int err;
 178 
 179         err = snd_hwdep_new(ff->card, ff->card->driver, 0, &hwdep);
 180         if (err < 0)
 181                 return err;
 182 
 183         strcpy(hwdep->name, ff->card->driver);
 184         hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREFACE;
 185         hwdep->ops = hwdep_ops;
 186         hwdep->private_data = ff;
 187         hwdep->exclusive = true;
 188 
 189         return 0;
 190 }

/* [<][>][^][v][top][bottom][index][help] */