~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/firewire/digi00x/digi00x-hwdep.c

Version: ~ [ linux-5.10-rc1 ] ~ [ linux-5.9.1 ] ~ [ linux-5.8.16 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.72 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.152 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.202 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.240 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.240 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp