1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 271c37977STakashi Sakamoto /* 371c37977STakashi Sakamoto * motu-hwdep.c - a part of driver for MOTU FireWire series 471c37977STakashi Sakamoto * 571c37977STakashi Sakamoto * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> 671c37977STakashi Sakamoto */ 771c37977STakashi Sakamoto 871c37977STakashi Sakamoto /* 971c37977STakashi Sakamoto * This codes have five functionalities. 1071c37977STakashi Sakamoto * 1171c37977STakashi Sakamoto * 1.get information about firewire node 1271c37977STakashi Sakamoto * 2.get notification about starting/stopping stream 1371c37977STakashi Sakamoto * 3.lock/unlock streaming 1471c37977STakashi Sakamoto * 1571c37977STakashi Sakamoto */ 1671c37977STakashi Sakamoto 1771c37977STakashi Sakamoto #include "motu.h" 1871c37977STakashi Sakamoto 19*d593f78eSTakashi Sakamoto static bool has_dsp_event(struct snd_motu *motu) 20*d593f78eSTakashi Sakamoto { 21*d593f78eSTakashi Sakamoto if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) 22*d593f78eSTakashi Sakamoto return (snd_motu_register_dsp_message_parser_count_event(motu) > 0); 23*d593f78eSTakashi Sakamoto else 24*d593f78eSTakashi Sakamoto return false; 25*d593f78eSTakashi Sakamoto } 26*d593f78eSTakashi Sakamoto 2771c37977STakashi Sakamoto static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, 2871c37977STakashi Sakamoto loff_t *offset) 2971c37977STakashi Sakamoto { 3071c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 3171c37977STakashi Sakamoto DEFINE_WAIT(wait); 3271c37977STakashi Sakamoto union snd_firewire_event event; 3371c37977STakashi Sakamoto 3471c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 3571c37977STakashi Sakamoto 36*d593f78eSTakashi Sakamoto while (!motu->dev_lock_changed && motu->msg == 0 && !has_dsp_event(motu)) { 3771c37977STakashi Sakamoto prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE); 3871c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 3971c37977STakashi Sakamoto schedule(); 4071c37977STakashi Sakamoto finish_wait(&motu->hwdep_wait, &wait); 4171c37977STakashi Sakamoto if (signal_pending(current)) 4271c37977STakashi Sakamoto return -ERESTARTSYS; 4371c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 4471c37977STakashi Sakamoto } 4571c37977STakashi Sakamoto 4671c37977STakashi Sakamoto memset(&event, 0, sizeof(event)); 4771c37977STakashi Sakamoto if (motu->dev_lock_changed) { 4871c37977STakashi Sakamoto event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; 4971c37977STakashi Sakamoto event.lock_status.status = (motu->dev_lock_count > 0); 5071c37977STakashi Sakamoto motu->dev_lock_changed = false; 51634ec0b2STakashi Sakamoto spin_unlock_irq(&motu->lock); 5271c37977STakashi Sakamoto 53634ec0b2STakashi Sakamoto count = min_t(long, count, sizeof(event)); 54634ec0b2STakashi Sakamoto if (copy_to_user(buf, &event, count)) 55634ec0b2STakashi Sakamoto return -EFAULT; 56634ec0b2STakashi Sakamoto } else if (motu->msg > 0) { 575aaab1bfSTakashi Sakamoto event.motu_notification.type = SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION; 585aaab1bfSTakashi Sakamoto event.motu_notification.message = motu->msg; 595aaab1bfSTakashi Sakamoto motu->msg = 0; 60634ec0b2STakashi Sakamoto spin_unlock_irq(&motu->lock); 615aaab1bfSTakashi Sakamoto 62634ec0b2STakashi Sakamoto count = min_t(long, count, sizeof(event)); 63634ec0b2STakashi Sakamoto if (copy_to_user(buf, &event, count)) 64634ec0b2STakashi Sakamoto return -EFAULT; 65*d593f78eSTakashi Sakamoto } else if (has_dsp_event(motu)) { 66634ec0b2STakashi Sakamoto size_t consumed = 0; 67634ec0b2STakashi Sakamoto u32 __user *ptr; 68634ec0b2STakashi Sakamoto u32 ev; 6971c37977STakashi Sakamoto 7071c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 7171c37977STakashi Sakamoto 72634ec0b2STakashi Sakamoto // Header is filled later. 73634ec0b2STakashi Sakamoto consumed += sizeof(event.motu_register_dsp_change); 74634ec0b2STakashi Sakamoto 75634ec0b2STakashi Sakamoto while (consumed < count && 76634ec0b2STakashi Sakamoto snd_motu_register_dsp_message_parser_copy_event(motu, &ev)) { 77634ec0b2STakashi Sakamoto ptr = (u32 __user *)(buf + consumed); 78634ec0b2STakashi Sakamoto if (put_user(ev, ptr)) 7971c37977STakashi Sakamoto return -EFAULT; 80634ec0b2STakashi Sakamoto consumed += sizeof(ev); 81634ec0b2STakashi Sakamoto } 82634ec0b2STakashi Sakamoto 83634ec0b2STakashi Sakamoto event.motu_register_dsp_change.type = SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE; 84634ec0b2STakashi Sakamoto event.motu_register_dsp_change.count = 85634ec0b2STakashi Sakamoto (consumed - sizeof(event.motu_register_dsp_change)) / 4; 86634ec0b2STakashi Sakamoto if (copy_to_user(buf, &event, sizeof(event.motu_register_dsp_change))) 87634ec0b2STakashi Sakamoto return -EFAULT; 88634ec0b2STakashi Sakamoto 89634ec0b2STakashi Sakamoto count = consumed; 90634ec0b2STakashi Sakamoto } 9171c37977STakashi Sakamoto 9271c37977STakashi Sakamoto return count; 9371c37977STakashi Sakamoto } 9471c37977STakashi Sakamoto 95680ef72aSAl Viro static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, 9671c37977STakashi Sakamoto poll_table *wait) 9771c37977STakashi Sakamoto { 9871c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 99680ef72aSAl Viro __poll_t events; 10071c37977STakashi Sakamoto 10171c37977STakashi Sakamoto poll_wait(file, &motu->hwdep_wait, wait); 10271c37977STakashi Sakamoto 10371c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 104*d593f78eSTakashi Sakamoto if (motu->dev_lock_changed || motu->msg || has_dsp_event(motu)) 105a9a08845SLinus Torvalds events = EPOLLIN | EPOLLRDNORM; 10671c37977STakashi Sakamoto else 10771c37977STakashi Sakamoto events = 0; 10871c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 10971c37977STakashi Sakamoto 110a9a08845SLinus Torvalds return events | EPOLLOUT; 11171c37977STakashi Sakamoto } 11271c37977STakashi Sakamoto 11371c37977STakashi Sakamoto static int hwdep_get_info(struct snd_motu *motu, void __user *arg) 11471c37977STakashi Sakamoto { 11571c37977STakashi Sakamoto struct fw_device *dev = fw_parent_device(motu->unit); 11671c37977STakashi Sakamoto struct snd_firewire_get_info info; 11771c37977STakashi Sakamoto 11871c37977STakashi Sakamoto memset(&info, 0, sizeof(info)); 11971c37977STakashi Sakamoto info.type = SNDRV_FIREWIRE_TYPE_MOTU; 12071c37977STakashi Sakamoto info.card = dev->card->index; 12171c37977STakashi Sakamoto *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); 12271c37977STakashi Sakamoto *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); 12375b1a8f9SJoe Perches strscpy(info.device_name, dev_name(&dev->device), 12471c37977STakashi Sakamoto sizeof(info.device_name)); 12571c37977STakashi Sakamoto 12671c37977STakashi Sakamoto if (copy_to_user(arg, &info, sizeof(info))) 12771c37977STakashi Sakamoto return -EFAULT; 12871c37977STakashi Sakamoto 12971c37977STakashi Sakamoto return 0; 13071c37977STakashi Sakamoto } 13171c37977STakashi Sakamoto 13271c37977STakashi Sakamoto static int hwdep_lock(struct snd_motu *motu) 13371c37977STakashi Sakamoto { 13471c37977STakashi Sakamoto int err; 13571c37977STakashi Sakamoto 13671c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 13771c37977STakashi Sakamoto 13871c37977STakashi Sakamoto if (motu->dev_lock_count == 0) { 13971c37977STakashi Sakamoto motu->dev_lock_count = -1; 14071c37977STakashi Sakamoto err = 0; 14171c37977STakashi Sakamoto } else { 14271c37977STakashi Sakamoto err = -EBUSY; 14371c37977STakashi Sakamoto } 14471c37977STakashi Sakamoto 14571c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 14671c37977STakashi Sakamoto 14771c37977STakashi Sakamoto return err; 14871c37977STakashi Sakamoto } 14971c37977STakashi Sakamoto 15071c37977STakashi Sakamoto static int hwdep_unlock(struct snd_motu *motu) 15171c37977STakashi Sakamoto { 15271c37977STakashi Sakamoto int err; 15371c37977STakashi Sakamoto 15471c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 15571c37977STakashi Sakamoto 15671c37977STakashi Sakamoto if (motu->dev_lock_count == -1) { 15771c37977STakashi Sakamoto motu->dev_lock_count = 0; 15871c37977STakashi Sakamoto err = 0; 15971c37977STakashi Sakamoto } else { 16071c37977STakashi Sakamoto err = -EBADFD; 16171c37977STakashi Sakamoto } 16271c37977STakashi Sakamoto 16371c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 16471c37977STakashi Sakamoto 16571c37977STakashi Sakamoto return err; 16671c37977STakashi Sakamoto } 16771c37977STakashi Sakamoto 16871c37977STakashi Sakamoto static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) 16971c37977STakashi Sakamoto { 17071c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 17171c37977STakashi Sakamoto 17271c37977STakashi Sakamoto spin_lock_irq(&motu->lock); 17371c37977STakashi Sakamoto if (motu->dev_lock_count == -1) 17471c37977STakashi Sakamoto motu->dev_lock_count = 0; 17571c37977STakashi Sakamoto spin_unlock_irq(&motu->lock); 17671c37977STakashi Sakamoto 17771c37977STakashi Sakamoto return 0; 17871c37977STakashi Sakamoto } 17971c37977STakashi Sakamoto 18071c37977STakashi Sakamoto static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, 18171c37977STakashi Sakamoto unsigned int cmd, unsigned long arg) 18271c37977STakashi Sakamoto { 18371c37977STakashi Sakamoto struct snd_motu *motu = hwdep->private_data; 18471c37977STakashi Sakamoto 18571c37977STakashi Sakamoto switch (cmd) { 18671c37977STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_GET_INFO: 18771c37977STakashi Sakamoto return hwdep_get_info(motu, (void __user *)arg); 18871c37977STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_LOCK: 18971c37977STakashi Sakamoto return hwdep_lock(motu); 19071c37977STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_UNLOCK: 19171c37977STakashi Sakamoto return hwdep_unlock(motu); 19258b62ab7STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_METER: 19358b62ab7STakashi Sakamoto { 19458b62ab7STakashi Sakamoto struct snd_firewire_motu_register_dsp_meter *meter; 19558b62ab7STakashi Sakamoto int err; 19658b62ab7STakashi Sakamoto 19758b62ab7STakashi Sakamoto if (!(motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP)) 19858b62ab7STakashi Sakamoto return -ENXIO; 19958b62ab7STakashi Sakamoto 20058b62ab7STakashi Sakamoto meter = kzalloc(sizeof(*meter), GFP_KERNEL); 20158b62ab7STakashi Sakamoto if (!meter) 20258b62ab7STakashi Sakamoto return -ENOMEM; 20358b62ab7STakashi Sakamoto 20458b62ab7STakashi Sakamoto snd_motu_register_dsp_message_parser_copy_meter(motu, meter); 20558b62ab7STakashi Sakamoto 20658b62ab7STakashi Sakamoto err = copy_to_user((void __user *)arg, meter, sizeof(*meter)); 20758b62ab7STakashi Sakamoto kfree(meter); 20858b62ab7STakashi Sakamoto 20958b62ab7STakashi Sakamoto if (err) 21058b62ab7STakashi Sakamoto return -EFAULT; 21158b62ab7STakashi Sakamoto 21258b62ab7STakashi Sakamoto return 0; 21358b62ab7STakashi Sakamoto } 21458b62ab7STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_MOTU_COMMAND_DSP_METER: 21558b62ab7STakashi Sakamoto { 21658b62ab7STakashi Sakamoto struct snd_firewire_motu_command_dsp_meter *meter; 21758b62ab7STakashi Sakamoto int err; 21858b62ab7STakashi Sakamoto 21958b62ab7STakashi Sakamoto if (!(motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP)) 22058b62ab7STakashi Sakamoto return -ENXIO; 22158b62ab7STakashi Sakamoto 22258b62ab7STakashi Sakamoto meter = kzalloc(sizeof(*meter), GFP_KERNEL); 22358b62ab7STakashi Sakamoto if (!meter) 22458b62ab7STakashi Sakamoto return -ENOMEM; 22558b62ab7STakashi Sakamoto 22658b62ab7STakashi Sakamoto snd_motu_command_dsp_message_parser_copy_meter(motu, meter); 22758b62ab7STakashi Sakamoto 22858b62ab7STakashi Sakamoto err = copy_to_user((void __user *)arg, meter, sizeof(*meter)); 22958b62ab7STakashi Sakamoto kfree(meter); 23058b62ab7STakashi Sakamoto 23158b62ab7STakashi Sakamoto if (err) 23258b62ab7STakashi Sakamoto return -EFAULT; 23358b62ab7STakashi Sakamoto 23458b62ab7STakashi Sakamoto return 0; 23558b62ab7STakashi Sakamoto } 236ca15a09cSTakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_MOTU_REGISTER_DSP_PARAMETER: 237ca15a09cSTakashi Sakamoto { 238ca15a09cSTakashi Sakamoto struct snd_firewire_motu_register_dsp_parameter *param; 239ca15a09cSTakashi Sakamoto int err; 240ca15a09cSTakashi Sakamoto 241ca15a09cSTakashi Sakamoto if (!(motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP)) 242ca15a09cSTakashi Sakamoto return -ENXIO; 243ca15a09cSTakashi Sakamoto 244ca15a09cSTakashi Sakamoto param = kzalloc(sizeof(*param), GFP_KERNEL); 245ca15a09cSTakashi Sakamoto if (!param) 246ca15a09cSTakashi Sakamoto return -ENOMEM; 247ca15a09cSTakashi Sakamoto 248ca15a09cSTakashi Sakamoto snd_motu_register_dsp_message_parser_copy_parameter(motu, param); 249ca15a09cSTakashi Sakamoto 250ca15a09cSTakashi Sakamoto err = copy_to_user((void __user *)arg, param, sizeof(*param)); 251ca15a09cSTakashi Sakamoto kfree(param); 252ca15a09cSTakashi Sakamoto if (err) 253ca15a09cSTakashi Sakamoto return -EFAULT; 254ca15a09cSTakashi Sakamoto 255ca15a09cSTakashi Sakamoto return 0; 256ca15a09cSTakashi Sakamoto } 25771c37977STakashi Sakamoto default: 25871c37977STakashi Sakamoto return -ENOIOCTLCMD; 25971c37977STakashi Sakamoto } 26071c37977STakashi Sakamoto } 26171c37977STakashi Sakamoto 26271c37977STakashi Sakamoto #ifdef CONFIG_COMPAT 26371c37977STakashi Sakamoto static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, 26471c37977STakashi Sakamoto unsigned int cmd, unsigned long arg) 26571c37977STakashi Sakamoto { 26671c37977STakashi Sakamoto return hwdep_ioctl(hwdep, file, cmd, 26771c37977STakashi Sakamoto (unsigned long)compat_ptr(arg)); 26871c37977STakashi Sakamoto } 26971c37977STakashi Sakamoto #else 27071c37977STakashi Sakamoto #define hwdep_compat_ioctl NULL 27171c37977STakashi Sakamoto #endif 27271c37977STakashi Sakamoto 27371c37977STakashi Sakamoto int snd_motu_create_hwdep_device(struct snd_motu *motu) 27471c37977STakashi Sakamoto { 27571c37977STakashi Sakamoto static const struct snd_hwdep_ops ops = { 27671c37977STakashi Sakamoto .read = hwdep_read, 27771c37977STakashi Sakamoto .release = hwdep_release, 27871c37977STakashi Sakamoto .poll = hwdep_poll, 27971c37977STakashi Sakamoto .ioctl = hwdep_ioctl, 28071c37977STakashi Sakamoto .ioctl_compat = hwdep_compat_ioctl, 28171c37977STakashi Sakamoto }; 28271c37977STakashi Sakamoto struct snd_hwdep *hwdep; 28371c37977STakashi Sakamoto int err; 28471c37977STakashi Sakamoto 28571c37977STakashi Sakamoto err = snd_hwdep_new(motu->card, motu->card->driver, 0, &hwdep); 28671c37977STakashi Sakamoto if (err < 0) 28771c37977STakashi Sakamoto return err; 28871c37977STakashi Sakamoto 28971c37977STakashi Sakamoto strcpy(hwdep->name, "MOTU"); 29071c37977STakashi Sakamoto hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU; 29171c37977STakashi Sakamoto hwdep->ops = ops; 29271c37977STakashi Sakamoto hwdep->private_data = motu; 29371c37977STakashi Sakamoto hwdep->exclusive = true; 29471c37977STakashi Sakamoto 2954c9eda8fSTakashi Sakamoto motu->hwdep = hwdep; 2964c9eda8fSTakashi Sakamoto 29771c37977STakashi Sakamoto return 0; 29871c37977STakashi Sakamoto } 299