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