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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * motu-hwdep.c - a part of driver for MOTU FireWire series
  4  *
  5  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
  6  */
  7 
  8 /*
  9  * This codes have five functionalities.
 10  *
 11  * 1.get information about firewire node
 12  * 2.get notification about starting/stopping stream
 13  * 3.lock/unlock streaming
 14  *
 15  */
 16 
 17 #include "motu.h"
 18 
 19 static bool has_dsp_event(struct snd_motu *motu)
 20 {
 21         if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP)
 22                 return (snd_motu_register_dsp_message_parser_count_event(motu) > 0);
 23         else
 24                 return false;
 25 }
 26 
 27 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
 28                        loff_t *offset)
 29 {
 30         struct snd_motu *motu = hwdep->private_data;
 31         DEFINE_WAIT(wait);
 32         union snd_firewire_event event;
 33 
 34         spin_lock_irq(&motu->lock);
 35 
 36         while (!motu->dev_lock_changed && motu->msg == 0 && !has_dsp_event(motu)) {
 37                 prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
 38                 spin_unlock_irq(&motu->lock);
 39                 schedule();
 40                 finish_wait(&motu->hwdep_wait, &wait);
 41                 if (signal_pending(current))
 42                         return -ERESTARTSYS;
 43                 spin_lock_irq(&motu->lock);
 44         }
 45 
 46         memset(&event, 0, sizeof(event));
 47         if (motu->dev_lock_changed) {
 48                 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
 49                 event.lock_status.status = (motu->dev_lock_count > 0);
 50                 motu->dev_lock_changed = false;
 51                 spin_unlock_irq(&motu->lock);
 52 
 53                 count = min_t(long, count, sizeof(event));
 54                 if (copy_to_user(buf, &event, count))
 55                         return -EFAULT;
 56         } else if (motu->msg > 0) {
 57                 event.motu_notification.type = SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION;
 58                 event.motu_notification.message = motu->msg;
 59                 motu->msg = 0;
 60                 spin_unlock_irq(&motu->lock);
 61 
 62                 count = min_t(long, count, sizeof(event));
 63                 if (copy_to_user(buf, &event, count))
 64                         return -EFAULT;
 65         } else if (has_dsp_event(motu)) {
 66                 size_t consumed = 0;
 67                 u32 __user *ptr;
 68                 u32 ev;
 69 
 70                 spin_unlock_irq(&motu->lock);
 71 
 72                 // Header is filled later.
 73                 consumed += sizeof(event.motu_register_dsp_change);
 74 
 75                 while (consumed < count &&
 76                        snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) {
 77                         ptr = (u32 __user *)(buf + consumed);
 78                         if (put_user(ev, ptr))
 79                                 return -EFAULT;
 80                         consumed += sizeof(ev);
 81                 }
 82 
 83                 event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE;
 84                 event.motu_register_dsp_change.count =
 85                         (consumed - sizeof(event.motu_register_dsp_change)) / 4;
 86                 if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change)))
 87                         return -EFAULT;
 88 
 89                 count = consumed;
 90         } else {
 91                 spin_unlock_irq(&motu->lock);
 92 
 93                 count = 0;
 94         }
 95 
 96         return count;
 97 }
 98 
 99 static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
100                                poll_table *wait)
101 {
102         struct snd_motu *motu = hwdep->private_data;
103         __poll_t events;
104 
105         poll_wait(file, &motu->hwdep_wait, wait);
106 
107         spin_lock_irq(&motu->lock);
108         if (motu->dev_lock_changed || motu->msg || has_dsp_event(motu))
109                 events = EPOLLIN | EPOLLRDNORM;
110         else
111                 events = 0;
112         spin_unlock_irq(&motu->lock);
113 
114         return events | EPOLLOUT;
115 }
116 
117 static int hwdep_get_info(struct snd_motu *motu, void __user *arg)
118 {
119         struct fw_device *dev = fw_parent_device(motu->unit);
120         struct snd_firewire_get_info info;
121 
122         memset(&info, 0, sizeof(info));
123         info.type = SNDRV_FIREWIRE_TYPE_MOTU;
124         info.card = dev->card->index;
125         *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
126         *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
127         strscpy(info.device_name, dev_name(&dev->device),
128                 sizeof(info.device_name));
129 
130         if (copy_to_user(arg, &info, sizeof(info)))
131                 return -EFAULT;
132 
133         return 0;
134 }
135 
136 static int hwdep_lock(struct snd_motu *motu)
137 {
138         int err;
139 
140         spin_lock_irq(&motu->lock);
141 
142         if (motu->dev_lock_count == 0) {
143                 motu->dev_lock_count = -1;
144                 err = 0;
145         } else {
146                 err = -EBUSY;
147         }
148 
149         spin_unlock_irq(&motu->lock);
150 
151         return err;
152 }
153 
154 static int hwdep_unlock(struct snd_motu *motu)
155 {
156         int err;
157 
158         spin_lock_irq(&motu->lock);
159 
160         if (motu->dev_lock_count == -1) {
161                 motu->dev_lock_count = 0;
162                 err = 0;
163         } else {
164                 err = -EBADFD;
165         }
166 
167         spin_unlock_irq(&motu->lock);
168 
169         return err;
170 }
171 
172 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
173 {
174         struct snd_motu *motu = hwdep->private_data;
175 
176         spin_lock_irq(&motu->lock);
177         if (motu->dev_lock_count == -1)
178                 motu->dev_lock_count = 0;
179         spin_unlock_irq(&motu->lock);
180 
181         return 0;
182 }
183 
184 static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
185             unsigned int cmd, unsigned long arg)
186 {
187         struct snd_motu *motu = hwdep->private_data;
188 
189         switch (cmd) {
190         case SNDRV_FIREWIRE_IOCTL_GET_INFO:
191                 return hwdep_get_info(motu, (void __user *)arg);
192         case SNDRV_FIREWIRE_IOCTL_LOCK:
193                 return hwdep_lock(motu);
194         case SNDRV_FIREWIRE_IOCTL_UNLOCK:
195                 return hwdep_unlock(motu);
196         case SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_METER:
197         {
198                 struct snd_firewire_motu_register_dsp_meter *meter;
199                 int err;
200 
201                 if (!(motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP))
202                         return -ENXIO;
203 
204                 meter = kzalloc(sizeof(*meter), GFP_KERNEL);
205                 if (!meter)
206                         return -ENOMEM;
207 
208                 snd_motu_register_dsp_message_parser_copy_meter(motu, meter);
209 
210                 err = copy_to_user((void __user *)arg, meter, sizeof(*meter));
211                 kfree(meter);
212 
213                 if (err)
214                         return -EFAULT;
215 
216                 return 0;
217         }
218         case SNDRV_FIREWIRE_IOCTL_MOTU_COMMAND_DSP_METER:
219         {
220                 struct snd_firewire_motu_command_dsp_meter *meter;
221                 int err;
222 
223                 if (!(motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP))
224                         return -ENXIO;
225 
226                 meter = kzalloc(sizeof(*meter), GFP_KERNEL);
227                 if (!meter)
228                         return -ENOMEM;
229 
230                 snd_motu_command_dsp_message_parser_copy_meter(motu, meter);
231 
232                 err = copy_to_user((void __user *)arg, meter, sizeof(*meter));
233                 kfree(meter);
234 
235                 if (err)
236                         return -EFAULT;
237 
238                 return 0;
239         }
240         case SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_PARAMETER:
241         {
242                 struct snd_firewire_motu_register_dsp_parameter *param;
243                 int err;
244 
245                 if (!(motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP))
246                         return -ENXIO;
247 
248                 param = kzalloc(sizeof(*param), GFP_KERNEL);
249                 if (!param)
250                         return -ENOMEM;
251 
252                 snd_motu_register_dsp_message_parser_copy_parameter(motu, param);
253 
254                 err = copy_to_user((void __user *)arg, param, sizeof(*param));
255                 kfree(param);
256                 if (err)
257                         return -EFAULT;
258 
259                 return 0;
260         }
261         default:
262                 return -ENOIOCTLCMD;
263         }
264 }
265 
266 #ifdef CONFIG_COMPAT
267 static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
268                               unsigned int cmd, unsigned long arg)
269 {
270         return hwdep_ioctl(hwdep, file, cmd,
271                            (unsigned long)compat_ptr(arg));
272 }
273 #else
274 #define hwdep_compat_ioctl NULL
275 #endif
276 
277 int snd_motu_create_hwdep_device(struct snd_motu *motu)
278 {
279         static const struct snd_hwdep_ops ops = {
280                 .read           = hwdep_read,
281                 .release        = hwdep_release,
282                 .poll           = hwdep_poll,
283                 .ioctl          = hwdep_ioctl,
284                 .ioctl_compat   = hwdep_compat_ioctl,
285         };
286         struct snd_hwdep *hwdep;
287         int err;
288 
289         err = snd_hwdep_new(motu->card, motu->card->driver, 0, &hwdep);
290         if (err < 0)
291                 return err;
292 
293         strcpy(hwdep->name, "MOTU");
294         hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU;
295         hwdep->ops = ops;
296         hwdep->private_data = motu;
297         hwdep->exclusive = true;
298 
299         motu->hwdep = hwdep;
300 
301         return 0;
302 }
303 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php