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