1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * fireworks_hwdep.c - a part of driver for Fireworks based devices 4 * 5 * Copyright (c) 2013-2014 Takashi Sakamoto 6 */ 7 8 /* 9 * This codes have five functionalities. 10 * 11 * 1.get information about firewire node 12 * 2.get notification about starting/stopping stream 13 * 3.lock/unlock streaming 14 * 4.transmit command of EFW transaction 15 * 5.receive response of EFW transaction 16 * 17 */ 18 19 #include "fireworks.h" 20 21 static long 22 hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained, 23 loff_t *offset) 24 { 25 unsigned int length, till_end, type; 26 struct snd_efw_transaction *t; 27 u8 *pull_ptr; 28 long count = 0; 29 30 if (remained < sizeof(type) + sizeof(struct snd_efw_transaction)) 31 return -ENOSPC; 32 33 /* data type is SNDRV_FIREWIRE_EVENT_EFW_RESPONSE */ 34 type = SNDRV_FIREWIRE_EVENT_EFW_RESPONSE; 35 if (copy_to_user(buf, &type, sizeof(type))) 36 return -EFAULT; 37 count += sizeof(type); 38 remained -= sizeof(type); 39 buf += sizeof(type); 40 41 /* write into buffer as many responses as possible */ 42 spin_lock_irq(&efw->lock); 43 44 /* 45 * When another task reaches here during this task's access to user 46 * space, it picks up current position in buffer and can read the same 47 * series of responses. 48 */ 49 pull_ptr = efw->pull_ptr; 50 51 while (efw->push_ptr != pull_ptr) { 52 t = (struct snd_efw_transaction *)(pull_ptr); 53 length = be32_to_cpu(t->length) * sizeof(__be32); 54 55 /* confirm enough space for this response */ 56 if (remained < length) 57 break; 58 59 /* copy from ring buffer to user buffer */ 60 while (length > 0) { 61 till_end = snd_efw_resp_buf_size - 62 (unsigned int)(pull_ptr - efw->resp_buf); 63 till_end = min_t(unsigned int, length, till_end); 64 65 spin_unlock_irq(&efw->lock); 66 67 if (copy_to_user(buf, pull_ptr, till_end)) 68 return -EFAULT; 69 70 spin_lock_irq(&efw->lock); 71 72 pull_ptr += till_end; 73 if (pull_ptr >= efw->resp_buf + snd_efw_resp_buf_size) 74 pull_ptr -= snd_efw_resp_buf_size; 75 76 length -= till_end; 77 buf += till_end; 78 count += till_end; 79 remained -= till_end; 80 } 81 } 82 83 /* 84 * All of tasks can read from the buffer nearly simultaneously, but the 85 * last position for each task is different depending on the length of 86 * given buffer. Here, for simplicity, a position of buffer is set by 87 * the latest task. It's better for a listening application to allow one 88 * thread to read from the buffer. Unless, each task can read different 89 * sequence of responses depending on variation of buffer length. 90 */ 91 efw->pull_ptr = pull_ptr; 92 93 spin_unlock_irq(&efw->lock); 94 95 return count; 96 } 97 98 static long 99 hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count, 100 loff_t *offset) 101 { 102 union snd_firewire_event event = { 103 .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS, 104 }; 105 106 scoped_guard(spinlock_irq, &efw->lock) { 107 event.lock_status.status = (efw->dev_lock_count > 0); 108 efw->dev_lock_changed = false; 109 } 110 111 count = min_t(long, count, sizeof(event.lock_status)); 112 113 if (copy_to_user(buf, &event, count)) 114 return -EFAULT; 115 116 return count; 117 } 118 119 static long 120 hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, 121 loff_t *offset) 122 { 123 struct snd_efw *efw = hwdep->private_data; 124 DEFINE_WAIT(wait); 125 bool dev_lock_changed; 126 bool queued; 127 128 spin_lock_irq(&efw->lock); 129 130 dev_lock_changed = efw->dev_lock_changed; 131 queued = efw->push_ptr != efw->pull_ptr; 132 133 while (!dev_lock_changed && !queued) { 134 prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE); 135 spin_unlock_irq(&efw->lock); 136 schedule(); 137 finish_wait(&efw->hwdep_wait, &wait); 138 if (signal_pending(current)) 139 return -ERESTARTSYS; 140 spin_lock_irq(&efw->lock); 141 dev_lock_changed = efw->dev_lock_changed; 142 queued = efw->push_ptr != efw->pull_ptr; 143 } 144 145 spin_unlock_irq(&efw->lock); 146 147 if (dev_lock_changed) 148 count = hwdep_read_locked(efw, buf, count, offset); 149 else if (queued) 150 count = hwdep_read_resp_buf(efw, buf, count, offset); 151 152 return count; 153 } 154 155 static long 156 hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count, 157 loff_t *offset) 158 { 159 struct snd_efw *efw = hwdep->private_data; 160 u32 seqnum; 161 u8 *buf; 162 163 if (count < sizeof(struct snd_efw_transaction) || 164 SND_EFW_RESPONSE_MAXIMUM_BYTES < count) 165 return -EINVAL; 166 167 buf = memdup_user(data, count); 168 if (IS_ERR(buf)) 169 return PTR_ERR(buf); 170 171 /* check seqnum is not for kernel-land */ 172 seqnum = be32_to_cpu(((struct snd_efw_transaction *)buf)->seqnum); 173 if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX) { 174 count = -EINVAL; 175 goto end; 176 } 177 178 if (snd_efw_transaction_cmd(efw->unit, buf, count) < 0) 179 count = -EIO; 180 end: 181 kfree(buf); 182 return count; 183 } 184 185 static __poll_t 186 hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) 187 { 188 struct snd_efw *efw = hwdep->private_data; 189 __poll_t events; 190 191 poll_wait(file, &efw->hwdep_wait, wait); 192 193 guard(spinlock_irq)(&efw->lock); 194 if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr) 195 events = EPOLLIN | EPOLLRDNORM; 196 else 197 events = 0; 198 return events | EPOLLOUT; 199 } 200 201 static int 202 hwdep_get_info(struct snd_efw *efw, void __user *arg) 203 { 204 struct fw_device *dev = fw_parent_device(efw->unit); 205 struct snd_firewire_get_info info; 206 207 memset(&info, 0, sizeof(info)); 208 info.type = SNDRV_FIREWIRE_TYPE_FIREWORKS; 209 info.card = dev->card->index; 210 *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); 211 *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); 212 strscpy(info.device_name, dev_name(&dev->device), 213 sizeof(info.device_name)); 214 215 if (copy_to_user(arg, &info, sizeof(info))) 216 return -EFAULT; 217 218 return 0; 219 } 220 221 static int 222 hwdep_lock(struct snd_efw *efw) 223 { 224 guard(spinlock_irq)(&efw->lock); 225 226 if (efw->dev_lock_count == 0) { 227 efw->dev_lock_count = -1; 228 return 0; 229 } else { 230 return -EBUSY; 231 } 232 } 233 234 static int 235 hwdep_unlock(struct snd_efw *efw) 236 { 237 guard(spinlock_irq)(&efw->lock); 238 239 if (efw->dev_lock_count == -1) { 240 efw->dev_lock_count = 0; 241 return 0; 242 } else { 243 return -EBADFD; 244 } 245 } 246 247 static int 248 hwdep_release(struct snd_hwdep *hwdep, struct file *file) 249 { 250 struct snd_efw *efw = hwdep->private_data; 251 252 guard(spinlock_irq)(&efw->lock); 253 if (efw->dev_lock_count == -1) 254 efw->dev_lock_count = 0; 255 256 return 0; 257 } 258 259 static int 260 hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, 261 unsigned int cmd, unsigned long arg) 262 { 263 struct snd_efw *efw = hwdep->private_data; 264 265 switch (cmd) { 266 case SNDRV_FIREWIRE_IOCTL_GET_INFO: 267 return hwdep_get_info(efw, (void __user *)arg); 268 case SNDRV_FIREWIRE_IOCTL_LOCK: 269 return hwdep_lock(efw); 270 case SNDRV_FIREWIRE_IOCTL_UNLOCK: 271 return hwdep_unlock(efw); 272 default: 273 return -ENOIOCTLCMD; 274 } 275 } 276 277 #ifdef CONFIG_COMPAT 278 static int 279 hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, 280 unsigned int cmd, unsigned long arg) 281 { 282 return hwdep_ioctl(hwdep, file, cmd, 283 (unsigned long)compat_ptr(arg)); 284 } 285 #else 286 #define hwdep_compat_ioctl NULL 287 #endif 288 289 int snd_efw_create_hwdep_device(struct snd_efw *efw) 290 { 291 static const struct snd_hwdep_ops ops = { 292 .read = hwdep_read, 293 .write = hwdep_write, 294 .release = hwdep_release, 295 .poll = hwdep_poll, 296 .ioctl = hwdep_ioctl, 297 .ioctl_compat = hwdep_compat_ioctl, 298 }; 299 struct snd_hwdep *hwdep; 300 int err; 301 302 err = snd_hwdep_new(efw->card, "Fireworks", 0, &hwdep); 303 if (err < 0) 304 goto end; 305 strscpy(hwdep->name, "Fireworks"); 306 hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS; 307 hwdep->ops = ops; 308 hwdep->private_data = efw; 309 hwdep->exclusive = true; 310 end: 311 return err; 312 } 313 314