Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * oxfw_hwdep.c - a part of driver for OXFW970/971 based devices
0004  *
0005  * Copyright (c) 2014 Takashi Sakamoto
0006  */
0007 
0008 /*
0009  * This codes give three functionality.
0010  *
0011  * 1.get firewire node information
0012  * 2.get notification about starting/stopping stream
0013  * 3.lock/unlock stream
0014  */
0015 
0016 #include "oxfw.h"
0017 
0018 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
0019                loff_t *offset)
0020 {
0021     struct snd_oxfw *oxfw = hwdep->private_data;
0022     DEFINE_WAIT(wait);
0023     union snd_firewire_event event;
0024 
0025     spin_lock_irq(&oxfw->lock);
0026 
0027     while (!oxfw->dev_lock_changed) {
0028         prepare_to_wait(&oxfw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
0029         spin_unlock_irq(&oxfw->lock);
0030         schedule();
0031         finish_wait(&oxfw->hwdep_wait, &wait);
0032         if (signal_pending(current))
0033             return -ERESTARTSYS;
0034         spin_lock_irq(&oxfw->lock);
0035     }
0036 
0037     memset(&event, 0, sizeof(event));
0038     event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
0039     event.lock_status.status = (oxfw->dev_lock_count > 0);
0040     oxfw->dev_lock_changed = false;
0041 
0042     count = min_t(long, count, sizeof(event.lock_status));
0043 
0044     spin_unlock_irq(&oxfw->lock);
0045 
0046     if (copy_to_user(buf, &event, count))
0047         return -EFAULT;
0048 
0049     return count;
0050 }
0051 
0052 static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
0053                    poll_table *wait)
0054 {
0055     struct snd_oxfw *oxfw = hwdep->private_data;
0056     __poll_t events;
0057 
0058     poll_wait(file, &oxfw->hwdep_wait, wait);
0059 
0060     spin_lock_irq(&oxfw->lock);
0061     if (oxfw->dev_lock_changed)
0062         events = EPOLLIN | EPOLLRDNORM;
0063     else
0064         events = 0;
0065     spin_unlock_irq(&oxfw->lock);
0066 
0067     return events;
0068 }
0069 
0070 static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
0071 {
0072     struct fw_device *dev = fw_parent_device(oxfw->unit);
0073     struct snd_firewire_get_info info;
0074 
0075     memset(&info, 0, sizeof(info));
0076     info.type = SNDRV_FIREWIRE_TYPE_OXFW;
0077     info.card = dev->card->index;
0078     *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
0079     *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
0080     strscpy(info.device_name, dev_name(&dev->device),
0081         sizeof(info.device_name));
0082 
0083     if (copy_to_user(arg, &info, sizeof(info)))
0084         return -EFAULT;
0085 
0086     return 0;
0087 }
0088 
0089 static int hwdep_lock(struct snd_oxfw *oxfw)
0090 {
0091     int err;
0092 
0093     spin_lock_irq(&oxfw->lock);
0094 
0095     if (oxfw->dev_lock_count == 0) {
0096         oxfw->dev_lock_count = -1;
0097         err = 0;
0098     } else {
0099         err = -EBUSY;
0100     }
0101 
0102     spin_unlock_irq(&oxfw->lock);
0103 
0104     return err;
0105 }
0106 
0107 static int hwdep_unlock(struct snd_oxfw *oxfw)
0108 {
0109     int err;
0110 
0111     spin_lock_irq(&oxfw->lock);
0112 
0113     if (oxfw->dev_lock_count == -1) {
0114         oxfw->dev_lock_count = 0;
0115         err = 0;
0116     } else {
0117         err = -EBADFD;
0118     }
0119 
0120     spin_unlock_irq(&oxfw->lock);
0121 
0122     return err;
0123 }
0124 
0125 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
0126 {
0127     struct snd_oxfw *oxfw = hwdep->private_data;
0128 
0129     spin_lock_irq(&oxfw->lock);
0130     if (oxfw->dev_lock_count == -1)
0131         oxfw->dev_lock_count = 0;
0132     spin_unlock_irq(&oxfw->lock);
0133 
0134     return 0;
0135 }
0136 
0137 static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
0138                unsigned int cmd, unsigned long arg)
0139 {
0140     struct snd_oxfw *oxfw = hwdep->private_data;
0141 
0142     switch (cmd) {
0143     case SNDRV_FIREWIRE_IOCTL_GET_INFO:
0144         return hwdep_get_info(oxfw, (void __user *)arg);
0145     case SNDRV_FIREWIRE_IOCTL_LOCK:
0146         return hwdep_lock(oxfw);
0147     case SNDRV_FIREWIRE_IOCTL_UNLOCK:
0148         return hwdep_unlock(oxfw);
0149     default:
0150         return -ENOIOCTLCMD;
0151     }
0152 }
0153 
0154 #ifdef CONFIG_COMPAT
0155 static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
0156                   unsigned int cmd, unsigned long arg)
0157 {
0158     return hwdep_ioctl(hwdep, file, cmd,
0159                (unsigned long)compat_ptr(arg));
0160 }
0161 #else
0162 #define hwdep_compat_ioctl NULL
0163 #endif
0164 
0165 int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw)
0166 {
0167     static const struct snd_hwdep_ops hwdep_ops = {
0168         .read       = hwdep_read,
0169         .release    = hwdep_release,
0170         .poll       = hwdep_poll,
0171         .ioctl      = hwdep_ioctl,
0172         .ioctl_compat   = hwdep_compat_ioctl,
0173     };
0174     struct snd_hwdep *hwdep;
0175     int err;
0176 
0177     err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep);
0178     if (err < 0)
0179         goto end;
0180     strcpy(hwdep->name, oxfw->card->driver);
0181     hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW;
0182     hwdep->ops = hwdep_ops;
0183     hwdep->private_data = oxfw;
0184     hwdep->exclusive = true;
0185 end:
0186     return err;
0187 }