171c37977STakashi Sakamoto /* 271c37977STakashi Sakamoto * motu-hwdep.c - a part of driver for MOTU FireWire series 371c37977STakashi Sakamoto * 471c37977STakashi Sakamoto * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> 571c37977STakashi Sakamoto * 671c37977STakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 771c37977STakashi Sakamoto */ 871c37977STakashi Sakamoto 971c37977STakashi Sakamoto /* 1071c37977STakashi Sakamoto * This codes have five functionalities. 1171c37977STakashi Sakamoto * 1271c37977STakashi Sakamoto * 1.get information about firewire node 1371c37977STakashi Sakamoto * 2.get notification about starting/stopping stream 1471c37977STakashi Sakamoto * 3.lock/unlock streaming 1571c37977STakashi Sakamoto * 1671c37977STakashi Sakamoto */ 1771c37977STakashi Sakamoto 1871c37977STakashi Sakamoto #include "motu.h" 1971c37977STakashi Sakamoto 2071c37977STakashi Sakamoto static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, 2171c37977STakashi Sakamoto loff_t *offset) 2271c37977STakashi Sakamoto { 2371c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 2471c37977STakashi Sakamoto DEFINE_WAIT(wait); 2571c37977STakashi Sakamoto union snd_firewire_event event; 2671c37977STakashi Sakamoto 2771c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 2871c37977STakashi Sakamoto 295aaab1bfSTakashi Sakamoto while (!motu->dev_lock_changed && motu->msg == 0) { 3071c37977STakashi Sakamoto prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE); 3171c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 3271c37977STakashi Sakamoto schedule(); 3371c37977STakashi Sakamoto finish_wait(&motu->hwdep_wait, &wait); 3471c37977STakashi Sakamoto if (signal_pending(current)) 3571c37977STakashi Sakamoto return -ERESTARTSYS; 3671c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 3771c37977STakashi Sakamoto } 3871c37977STakashi Sakamoto 3971c37977STakashi Sakamoto memset(&event, 0, sizeof(event)); 4071c37977STakashi Sakamoto if (motu->dev_lock_changed) { 4171c37977STakashi Sakamoto event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; 4271c37977STakashi Sakamoto event.lock_status.status = (motu->dev_lock_count > 0); 4371c37977STakashi Sakamoto motu->dev_lock_changed = false; 4471c37977STakashi Sakamoto 4571c37977STakashi Sakamoto count = min_t(long, count, sizeof(event.lock_status)); 465aaab1bfSTakashi Sakamoto } else { 475aaab1bfSTakashi Sakamoto event.motu_notification.type = SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION; 485aaab1bfSTakashi Sakamoto event.motu_notification.message = motu->msg; 495aaab1bfSTakashi Sakamoto motu->msg = 0; 505aaab1bfSTakashi Sakamoto 515aaab1bfSTakashi Sakamoto count = min_t(long, count, sizeof(event.motu_notification)); 5271c37977STakashi Sakamoto } 5371c37977STakashi Sakamoto 5471c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 5571c37977STakashi Sakamoto 5671c37977STakashi Sakamoto if (copy_to_user(buf, &event, count)) 5771c37977STakashi Sakamoto return -EFAULT; 5871c37977STakashi Sakamoto 5971c37977STakashi Sakamoto return count; 6071c37977STakashi Sakamoto } 6171c37977STakashi Sakamoto 62680ef72aSAl Viro static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, 6371c37977STakashi Sakamoto poll_table *wait) 6471c37977STakashi Sakamoto { 6571c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 66680ef72aSAl Viro __poll_t events; 6771c37977STakashi Sakamoto 6871c37977STakashi Sakamoto poll_wait(file, &motu->hwdep_wait, wait); 6971c37977STakashi Sakamoto 7071c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 715aaab1bfSTakashi Sakamoto if (motu->dev_lock_changed || motu->msg) 7271c37977STakashi Sakamoto events = POLLIN | POLLRDNORM; 7371c37977STakashi Sakamoto else 7471c37977STakashi Sakamoto events = 0; 7571c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 7671c37977STakashi Sakamoto 7771c37977STakashi Sakamoto return events | POLLOUT; 7871c37977STakashi Sakamoto } 7971c37977STakashi Sakamoto 8071c37977STakashi Sakamoto static int hwdep_get_info(struct snd_motu *motu, void __user *arg) 8171c37977STakashi Sakamoto { 8271c37977STakashi Sakamoto struct fw_device *dev = fw_parent_device(motu->unit); 8371c37977STakashi Sakamoto struct snd_firewire_get_info info; 8471c37977STakashi Sakamoto 8571c37977STakashi Sakamoto memset(&info, 0, sizeof(info)); 8671c37977STakashi Sakamoto info.type = SNDRV_FIREWIRE_TYPE_MOTU; 8771c37977STakashi Sakamoto info.card = dev->card->index; 8871c37977STakashi Sakamoto *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); 8971c37977STakashi Sakamoto *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); 9071c37977STakashi Sakamoto strlcpy(info.device_name, dev_name(&dev->device), 9171c37977STakashi Sakamoto sizeof(info.device_name)); 9271c37977STakashi Sakamoto 9371c37977STakashi Sakamoto if (copy_to_user(arg, &info, sizeof(info))) 9471c37977STakashi Sakamoto return -EFAULT; 9571c37977STakashi Sakamoto 9671c37977STakashi Sakamoto return 0; 9771c37977STakashi Sakamoto } 9871c37977STakashi Sakamoto 9971c37977STakashi Sakamoto static int hwdep_lock(struct snd_motu *motu) 10071c37977STakashi Sakamoto { 10171c37977STakashi Sakamoto int err; 10271c37977STakashi Sakamoto 10371c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 10471c37977STakashi Sakamoto 10571c37977STakashi Sakamoto if (motu->dev_lock_count == 0) { 10671c37977STakashi Sakamoto motu->dev_lock_count = -1; 10771c37977STakashi Sakamoto err = 0; 10871c37977STakashi Sakamoto } else { 10971c37977STakashi Sakamoto err = -EBUSY; 11071c37977STakashi Sakamoto } 11171c37977STakashi Sakamoto 11271c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 11371c37977STakashi Sakamoto 11471c37977STakashi Sakamoto return err; 11571c37977STakashi Sakamoto } 11671c37977STakashi Sakamoto 11771c37977STakashi Sakamoto static int hwdep_unlock(struct snd_motu *motu) 11871c37977STakashi Sakamoto { 11971c37977STakashi Sakamoto int err; 12071c37977STakashi Sakamoto 12171c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 12271c37977STakashi Sakamoto 12371c37977STakashi Sakamoto if (motu->dev_lock_count == -1) { 12471c37977STakashi Sakamoto motu->dev_lock_count = 0; 12571c37977STakashi Sakamoto err = 0; 12671c37977STakashi Sakamoto } else { 12771c37977STakashi Sakamoto err = -EBADFD; 12871c37977STakashi Sakamoto } 12971c37977STakashi Sakamoto 13071c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 13171c37977STakashi Sakamoto 13271c37977STakashi Sakamoto return err; 13371c37977STakashi Sakamoto } 13471c37977STakashi Sakamoto 13571c37977STakashi Sakamoto static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) 13671c37977STakashi Sakamoto { 13771c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 13871c37977STakashi Sakamoto 13971c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 14071c37977STakashi Sakamoto if (motu->dev_lock_count == -1) 14171c37977STakashi Sakamoto motu->dev_lock_count = 0; 14271c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 14371c37977STakashi Sakamoto 14471c37977STakashi Sakamoto return 0; 14571c37977STakashi Sakamoto } 14671c37977STakashi Sakamoto 14771c37977STakashi Sakamoto static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, 14871c37977STakashi Sakamoto unsigned int cmd, unsigned long arg) 14971c37977STakashi Sakamoto { 15071c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 15171c37977STakashi Sakamoto 15271c37977STakashi Sakamoto switch (cmd) { 15371c37977STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_GET_INFO: 15471c37977STakashi Sakamoto return hwdep_get_info(motu, (void __user *)arg); 15571c37977STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_LOCK: 15671c37977STakashi Sakamoto return hwdep_lock(motu); 15771c37977STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_UNLOCK: 15871c37977STakashi Sakamoto return hwdep_unlock(motu); 15971c37977STakashi Sakamoto default: 16071c37977STakashi Sakamoto return -ENOIOCTLCMD; 16171c37977STakashi Sakamoto } 16271c37977STakashi Sakamoto } 16371c37977STakashi Sakamoto 16471c37977STakashi Sakamoto #ifdef CONFIG_COMPAT 16571c37977STakashi Sakamoto static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, 16671c37977STakashi Sakamoto unsigned int cmd, unsigned long arg) 16771c37977STakashi Sakamoto { 16871c37977STakashi Sakamoto return hwdep_ioctl(hwdep, file, cmd, 16971c37977STakashi Sakamoto (unsigned long)compat_ptr(arg)); 17071c37977STakashi Sakamoto } 17171c37977STakashi Sakamoto #else 17271c37977STakashi Sakamoto #define hwdep_compat_ioctl NULL 17371c37977STakashi Sakamoto #endif 17471c37977STakashi Sakamoto 17571c37977STakashi Sakamoto int snd_motu_create_hwdep_device(struct snd_motu *motu) 17671c37977STakashi Sakamoto { 17771c37977STakashi Sakamoto static const struct snd_hwdep_ops ops = { 17871c37977STakashi Sakamoto .read = hwdep_read, 17971c37977STakashi Sakamoto .release = hwdep_release, 18071c37977STakashi Sakamoto .poll = hwdep_poll, 18171c37977STakashi Sakamoto .ioctl = hwdep_ioctl, 18271c37977STakashi Sakamoto .ioctl_compat = hwdep_compat_ioctl, 18371c37977STakashi Sakamoto }; 18471c37977STakashi Sakamoto struct snd_hwdep *hwdep; 18571c37977STakashi Sakamoto int err; 18671c37977STakashi Sakamoto 18771c37977STakashi Sakamoto err = snd_hwdep_new(motu->card, motu->card->driver, 0, &hwdep); 18871c37977STakashi Sakamoto if (err < 0) 18971c37977STakashi Sakamoto return err; 19071c37977STakashi Sakamoto 19171c37977STakashi Sakamoto strcpy(hwdep->name, "MOTU"); 19271c37977STakashi Sakamoto hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU; 19371c37977STakashi Sakamoto hwdep->ops = ops; 19471c37977STakashi Sakamoto hwdep->private_data = motu; 19571c37977STakashi Sakamoto hwdep->exclusive = true; 19671c37977STakashi Sakamoto 19771c37977STakashi Sakamoto return 0; 19871c37977STakashi Sakamoto } 199