0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
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
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 }