Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * motu-hwdep.c - a part of driver for MOTU FireWire series
0004  *
0005  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
0006  */
0007 
0008 /*
0009  * This codes have five functionalities.
0010  *
0011  * 1.get information about firewire node
0012  * 2.get notification about starting/stopping stream
0013  * 3.lock/unlock streaming
0014  *
0015  */
0016 
0017 #include "motu.h"
0018 
0019 static bool has_dsp_event(struct snd_motu *motu)
0020 {
0021     if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP)
0022         return (snd_motu_register_dsp_message_parser_count_event(motu) > 0);
0023     else
0024         return false;
0025 }
0026 
0027 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
0028                loff_t *offset)
0029 {
0030     struct snd_motu *motu = hwdep->private_data;
0031     DEFINE_WAIT(wait);
0032     union snd_firewire_event event;
0033 
0034     spin_lock_irq(&motu->lock);
0035 
0036     while (!motu->dev_lock_changed && motu->msg == 0 && !has_dsp_event(motu)) {
0037         prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
0038         spin_unlock_irq(&motu->lock);
0039         schedule();
0040         finish_wait(&motu->hwdep_wait, &wait);
0041         if (signal_pending(current))
0042             return -ERESTARTSYS;
0043         spin_lock_irq(&motu->lock);
0044     }
0045 
0046     memset(&event, 0, sizeof(event));
0047     if (motu->dev_lock_changed) {
0048         event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
0049         event.lock_status.status = (motu->dev_lock_count > 0);
0050         motu->dev_lock_changed = false;
0051         spin_unlock_irq(&motu->lock);
0052 
0053         count = min_t(long, count, sizeof(event));
0054         if (copy_to_user(buf, &event, count))
0055             return -EFAULT;
0056     } else if (motu->msg > 0) {
0057         event.motu_notification.type = SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION;
0058         event.motu_notification.message = motu->msg;
0059         motu->msg = 0;
0060         spin_unlock_irq(&motu->lock);
0061 
0062         count = min_t(long, count, sizeof(event));
0063         if (copy_to_user(buf, &event, count))
0064             return -EFAULT;
0065     } else if (has_dsp_event(motu)) {
0066         size_t consumed = 0;
0067         u32 __user *ptr;
0068         u32 ev;
0069 
0070         spin_unlock_irq(&motu->lock);
0071 
0072         // Header is filled later.
0073         consumed += sizeof(event.motu_register_dsp_change);
0074 
0075         while (consumed < count &&
0076                snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) {
0077             ptr = (u32 __user *)(buf + consumed);
0078             if (put_user(ev, ptr))
0079                 return -EFAULT;
0080             consumed += sizeof(ev);
0081         }
0082 
0083         event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE;
0084         event.motu_register_dsp_change.count =
0085             (consumed - sizeof(event.motu_register_dsp_change)) / 4;
0086         if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change)))
0087             return -EFAULT;
0088 
0089         count = consumed;
0090     }
0091 
0092     return count;
0093 }
0094 
0095 static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
0096                    poll_table *wait)
0097 {
0098     struct snd_motu *motu = hwdep->private_data;
0099     __poll_t events;
0100 
0101     poll_wait(file, &motu->hwdep_wait, wait);
0102 
0103     spin_lock_irq(&motu->lock);
0104     if (motu->dev_lock_changed || motu->msg || has_dsp_event(motu))
0105         events = EPOLLIN | EPOLLRDNORM;
0106     else
0107         events = 0;
0108     spin_unlock_irq(&motu->lock);
0109 
0110     return events | EPOLLOUT;
0111 }
0112 
0113 static int hwdep_get_info(struct snd_motu *motu, void __user *arg)
0114 {
0115     struct fw_device *dev = fw_parent_device(motu->unit);
0116     struct snd_firewire_get_info info;
0117 
0118     memset(&info, 0, sizeof(info));
0119     info.type = SNDRV_FIREWIRE_TYPE_MOTU;
0120     info.card = dev->card->index;
0121     *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
0122     *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
0123     strscpy(info.device_name, dev_name(&dev->device),
0124         sizeof(info.device_name));
0125 
0126     if (copy_to_user(arg, &info, sizeof(info)))
0127         return -EFAULT;
0128 
0129     return 0;
0130 }
0131 
0132 static int hwdep_lock(struct snd_motu *motu)
0133 {
0134     int err;
0135 
0136     spin_lock_irq(&motu->lock);
0137 
0138     if (motu->dev_lock_count == 0) {
0139         motu->dev_lock_count = -1;
0140         err = 0;
0141     } else {
0142         err = -EBUSY;
0143     }
0144 
0145     spin_unlock_irq(&motu->lock);
0146 
0147     return err;
0148 }
0149 
0150 static int hwdep_unlock(struct snd_motu *motu)
0151 {
0152     int err;
0153 
0154     spin_lock_irq(&motu->lock);
0155 
0156     if (motu->dev_lock_count == -1) {
0157         motu->dev_lock_count = 0;
0158         err = 0;
0159     } else {
0160         err = -EBADFD;
0161     }
0162 
0163     spin_unlock_irq(&motu->lock);
0164 
0165     return err;
0166 }
0167 
0168 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
0169 {
0170     struct snd_motu *motu = hwdep->private_data;
0171 
0172     spin_lock_irq(&motu->lock);
0173     if (motu->dev_lock_count == -1)
0174         motu->dev_lock_count = 0;
0175     spin_unlock_irq(&motu->lock);
0176 
0177     return 0;
0178 }
0179 
0180 static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
0181         unsigned int cmd, unsigned long arg)
0182 {
0183     struct snd_motu *motu = hwdep->private_data;
0184 
0185     switch (cmd) {
0186     case SNDRV_FIREWIRE_IOCTL_GET_INFO:
0187         return hwdep_get_info(motu, (void __user *)arg);
0188     case SNDRV_FIREWIRE_IOCTL_LOCK:
0189         return hwdep_lock(motu);
0190     case SNDRV_FIREWIRE_IOCTL_UNLOCK:
0191         return hwdep_unlock(motu);
0192     case SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_METER:
0193     {
0194         struct snd_firewire_motu_register_dsp_meter *meter;
0195         int err;
0196 
0197         if (!(motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP))
0198             return -ENXIO;
0199 
0200         meter = kzalloc(sizeof(*meter), GFP_KERNEL);
0201         if (!meter)
0202             return -ENOMEM;
0203 
0204         snd_motu_register_dsp_message_parser_copy_meter(motu, meter);
0205 
0206         err = copy_to_user((void __user *)arg, meter, sizeof(*meter));
0207         kfree(meter);
0208 
0209         if (err)
0210             return -EFAULT;
0211 
0212         return 0;
0213     }
0214     case SNDRV_FIREWIRE_IOCTL_MOTU_COMMAND_DSP_METER:
0215     {
0216         struct snd_firewire_motu_command_dsp_meter *meter;
0217         int err;
0218 
0219         if (!(motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP))
0220             return -ENXIO;
0221 
0222         meter = kzalloc(sizeof(*meter), GFP_KERNEL);
0223         if (!meter)
0224             return -ENOMEM;
0225 
0226         snd_motu_command_dsp_message_parser_copy_meter(motu, meter);
0227 
0228         err = copy_to_user((void __user *)arg, meter, sizeof(*meter));
0229         kfree(meter);
0230 
0231         if (err)
0232             return -EFAULT;
0233 
0234         return 0;
0235     }
0236     case SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_PARAMETER:
0237     {
0238         struct snd_firewire_motu_register_dsp_parameter *param;
0239         int err;
0240 
0241         if (!(motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP))
0242             return -ENXIO;
0243 
0244         param = kzalloc(sizeof(*param), GFP_KERNEL);
0245         if (!param)
0246             return -ENOMEM;
0247 
0248         snd_motu_register_dsp_message_parser_copy_parameter(motu, param);
0249 
0250         err = copy_to_user((void __user *)arg, param, sizeof(*param));
0251         kfree(param);
0252         if (err)
0253             return -EFAULT;
0254 
0255         return 0;
0256     }
0257     default:
0258         return -ENOIOCTLCMD;
0259     }
0260 }
0261 
0262 #ifdef CONFIG_COMPAT
0263 static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
0264                   unsigned int cmd, unsigned long arg)
0265 {
0266     return hwdep_ioctl(hwdep, file, cmd,
0267                (unsigned long)compat_ptr(arg));
0268 }
0269 #else
0270 #define hwdep_compat_ioctl NULL
0271 #endif
0272 
0273 int snd_motu_create_hwdep_device(struct snd_motu *motu)
0274 {
0275     static const struct snd_hwdep_ops ops = {
0276         .read       = hwdep_read,
0277         .release    = hwdep_release,
0278         .poll       = hwdep_poll,
0279         .ioctl      = hwdep_ioctl,
0280         .ioctl_compat   = hwdep_compat_ioctl,
0281     };
0282     struct snd_hwdep *hwdep;
0283     int err;
0284 
0285     err = snd_hwdep_new(motu->card, motu->card->driver, 0, &hwdep);
0286     if (err < 0)
0287         return err;
0288 
0289     strcpy(hwdep->name, "MOTU");
0290     hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU;
0291     hwdep->ops = ops;
0292     hwdep->private_data = motu;
0293     hwdep->exclusive = true;
0294 
0295     motu->hwdep = hwdep;
0296 
0297     return 0;
0298 }