0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include "tascam.h"
0017
0018 static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
0019 long count, loff_t *offset)
0020 __releases(&tscm->lock)
0021 {
0022 struct snd_firewire_event_lock_status event = {
0023 .type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
0024 };
0025
0026 event.status = (tscm->dev_lock_count > 0);
0027 tscm->dev_lock_changed = false;
0028 count = min_t(long, count, sizeof(event));
0029
0030 spin_unlock_irq(&tscm->lock);
0031
0032 if (copy_to_user(buf, &event, count))
0033 return -EFAULT;
0034
0035 return count;
0036 }
0037
0038 static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
0039 long remained, loff_t *offset)
0040 __releases(&tscm->lock)
0041 {
0042 char __user *pos = buf;
0043 unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL;
0044 struct snd_firewire_tascam_change *entries = tscm->queue;
0045 long count;
0046
0047
0048 if (remained < sizeof(type) + sizeof(*entries)) {
0049 spin_unlock_irq(&tscm->lock);
0050 return -EINVAL;
0051 }
0052
0053
0054 count = sizeof(type);
0055 remained -= sizeof(type);
0056 pos += sizeof(type);
0057
0058 while (true) {
0059 unsigned int head_pos;
0060 unsigned int tail_pos;
0061 unsigned int length;
0062
0063 if (tscm->pull_pos == tscm->push_pos)
0064 break;
0065 else if (tscm->pull_pos < tscm->push_pos)
0066 tail_pos = tscm->push_pos;
0067 else
0068 tail_pos = SND_TSCM_QUEUE_COUNT;
0069 head_pos = tscm->pull_pos;
0070
0071 length = (tail_pos - head_pos) * sizeof(*entries);
0072 if (remained < length)
0073 length = rounddown(remained, sizeof(*entries));
0074 if (length == 0)
0075 break;
0076
0077 spin_unlock_irq(&tscm->lock);
0078 if (copy_to_user(pos, &entries[head_pos], length))
0079 return -EFAULT;
0080
0081 spin_lock_irq(&tscm->lock);
0082
0083 tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT;
0084
0085 count += length;
0086 remained -= length;
0087 pos += length;
0088 }
0089
0090 spin_unlock_irq(&tscm->lock);
0091
0092 if (copy_to_user(buf, &type, sizeof(type)))
0093 return -EFAULT;
0094
0095 return count;
0096 }
0097
0098 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
0099 loff_t *offset)
0100 {
0101 struct snd_tscm *tscm = hwdep->private_data;
0102 DEFINE_WAIT(wait);
0103
0104 spin_lock_irq(&tscm->lock);
0105
0106 while (!tscm->dev_lock_changed && tscm->push_pos == tscm->pull_pos) {
0107 prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
0108 spin_unlock_irq(&tscm->lock);
0109 schedule();
0110 finish_wait(&tscm->hwdep_wait, &wait);
0111 if (signal_pending(current))
0112 return -ERESTARTSYS;
0113 spin_lock_irq(&tscm->lock);
0114 }
0115
0116
0117 if (tscm->dev_lock_changed) {
0118 count = tscm_hwdep_read_locked(tscm, buf, count, offset);
0119 } else if (tscm->push_pos != tscm->pull_pos) {
0120 count = tscm_hwdep_read_queue(tscm, buf, count, offset);
0121 } else {
0122 spin_unlock_irq(&tscm->lock);
0123 count = 0;
0124 }
0125
0126 return count;
0127 }
0128
0129 static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
0130 poll_table *wait)
0131 {
0132 struct snd_tscm *tscm = hwdep->private_data;
0133 __poll_t events;
0134
0135 poll_wait(file, &tscm->hwdep_wait, wait);
0136
0137 spin_lock_irq(&tscm->lock);
0138 if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos)
0139 events = EPOLLIN | EPOLLRDNORM;
0140 else
0141 events = 0;
0142 spin_unlock_irq(&tscm->lock);
0143
0144 return events;
0145 }
0146
0147 static int hwdep_get_info(struct snd_tscm *tscm, void __user *arg)
0148 {
0149 struct fw_device *dev = fw_parent_device(tscm->unit);
0150 struct snd_firewire_get_info info;
0151
0152 memset(&info, 0, sizeof(info));
0153 info.type = SNDRV_FIREWIRE_TYPE_TASCAM;
0154 info.card = dev->card->index;
0155 *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
0156 *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
0157 strscpy(info.device_name, dev_name(&dev->device),
0158 sizeof(info.device_name));
0159
0160 if (copy_to_user(arg, &info, sizeof(info)))
0161 return -EFAULT;
0162
0163 return 0;
0164 }
0165
0166 static int hwdep_lock(struct snd_tscm *tscm)
0167 {
0168 int err;
0169
0170 spin_lock_irq(&tscm->lock);
0171
0172 if (tscm->dev_lock_count == 0) {
0173 tscm->dev_lock_count = -1;
0174 err = 0;
0175 } else {
0176 err = -EBUSY;
0177 }
0178
0179 spin_unlock_irq(&tscm->lock);
0180
0181 return err;
0182 }
0183
0184 static int hwdep_unlock(struct snd_tscm *tscm)
0185 {
0186 int err;
0187
0188 spin_lock_irq(&tscm->lock);
0189
0190 if (tscm->dev_lock_count == -1) {
0191 tscm->dev_lock_count = 0;
0192 err = 0;
0193 } else {
0194 err = -EBADFD;
0195 }
0196
0197 spin_unlock_irq(&tscm->lock);
0198
0199 return err;
0200 }
0201
0202 static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg)
0203 {
0204 if (copy_to_user(arg, tscm->state, sizeof(tscm->state)))
0205 return -EFAULT;
0206
0207 return 0;
0208 }
0209
0210 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
0211 {
0212 struct snd_tscm *tscm = hwdep->private_data;
0213
0214 spin_lock_irq(&tscm->lock);
0215 if (tscm->dev_lock_count == -1)
0216 tscm->dev_lock_count = 0;
0217 spin_unlock_irq(&tscm->lock);
0218
0219 return 0;
0220 }
0221
0222 static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
0223 unsigned int cmd, unsigned long arg)
0224 {
0225 struct snd_tscm *tscm = hwdep->private_data;
0226
0227 switch (cmd) {
0228 case SNDRV_FIREWIRE_IOCTL_GET_INFO:
0229 return hwdep_get_info(tscm, (void __user *)arg);
0230 case SNDRV_FIREWIRE_IOCTL_LOCK:
0231 return hwdep_lock(tscm);
0232 case SNDRV_FIREWIRE_IOCTL_UNLOCK:
0233 return hwdep_unlock(tscm);
0234 case SNDRV_FIREWIRE_IOCTL_TASCAM_STATE:
0235 return tscm_hwdep_state(tscm, (void __user *)arg);
0236 default:
0237 return -ENOIOCTLCMD;
0238 }
0239 }
0240
0241 #ifdef CONFIG_COMPAT
0242 static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
0243 unsigned int cmd, unsigned long arg)
0244 {
0245 return hwdep_ioctl(hwdep, file, cmd,
0246 (unsigned long)compat_ptr(arg));
0247 }
0248 #else
0249 #define hwdep_compat_ioctl NULL
0250 #endif
0251
0252 int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
0253 {
0254 static const struct snd_hwdep_ops ops = {
0255 .read = hwdep_read,
0256 .release = hwdep_release,
0257 .poll = hwdep_poll,
0258 .ioctl = hwdep_ioctl,
0259 .ioctl_compat = hwdep_compat_ioctl,
0260 };
0261 struct snd_hwdep *hwdep;
0262 int err;
0263
0264 err = snd_hwdep_new(tscm->card, "Tascam", 0, &hwdep);
0265 if (err < 0)
0266 return err;
0267
0268 strcpy(hwdep->name, "Tascam");
0269 hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM;
0270 hwdep->ops = ops;
0271 hwdep->private_data = tscm;
0272 hwdep->exclusive = true;
0273
0274 tscm->hwdep = hwdep;
0275
0276 return err;
0277 }