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