Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.8 189 lines 4.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * oxfw_hwdep.c - a part of driver for OXFW970/971 based devices 4 * 5 * Copyright (c) 2014 Takashi Sakamoto 6 */ 7 8/* 9 * This codes give three functionality. 10 * 11 * 1.get firewire node information 12 * 2.get notification about starting/stopping stream 13 * 3.lock/unlock stream 14 */ 15 16#include "oxfw.h" 17 18static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, 19 loff_t *offset) 20{ 21 struct snd_oxfw *oxfw = hwdep->private_data; 22 DEFINE_WAIT(wait); 23 union snd_firewire_event event; 24 25 spin_lock_irq(&oxfw->lock); 26 27 while (!oxfw->dev_lock_changed) { 28 prepare_to_wait(&oxfw->hwdep_wait, &wait, TASK_INTERRUPTIBLE); 29 spin_unlock_irq(&oxfw->lock); 30 schedule(); 31 finish_wait(&oxfw->hwdep_wait, &wait); 32 if (signal_pending(current)) 33 return -ERESTARTSYS; 34 spin_lock_irq(&oxfw->lock); 35 } 36 37 memset(&event, 0, sizeof(event)); 38 if (oxfw->dev_lock_changed) { 39 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; 40 event.lock_status.status = (oxfw->dev_lock_count > 0); 41 oxfw->dev_lock_changed = false; 42 43 count = min_t(long, count, sizeof(event.lock_status)); 44 } 45 46 spin_unlock_irq(&oxfw->lock); 47 48 if (copy_to_user(buf, &event, count)) 49 return -EFAULT; 50 51 return count; 52} 53 54static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, 55 poll_table *wait) 56{ 57 struct snd_oxfw *oxfw = hwdep->private_data; 58 __poll_t events; 59 60 poll_wait(file, &oxfw->hwdep_wait, wait); 61 62 spin_lock_irq(&oxfw->lock); 63 if (oxfw->dev_lock_changed) 64 events = EPOLLIN | EPOLLRDNORM; 65 else 66 events = 0; 67 spin_unlock_irq(&oxfw->lock); 68 69 return events; 70} 71 72static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg) 73{ 74 struct fw_device *dev = fw_parent_device(oxfw->unit); 75 struct snd_firewire_get_info info; 76 77 memset(&info, 0, sizeof(info)); 78 info.type = SNDRV_FIREWIRE_TYPE_OXFW; 79 info.card = dev->card->index; 80 *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); 81 *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); 82 strlcpy(info.device_name, dev_name(&dev->device), 83 sizeof(info.device_name)); 84 85 if (copy_to_user(arg, &info, sizeof(info))) 86 return -EFAULT; 87 88 return 0; 89} 90 91static int hwdep_lock(struct snd_oxfw *oxfw) 92{ 93 int err; 94 95 spin_lock_irq(&oxfw->lock); 96 97 if (oxfw->dev_lock_count == 0) { 98 oxfw->dev_lock_count = -1; 99 err = 0; 100 } else { 101 err = -EBUSY; 102 } 103 104 spin_unlock_irq(&oxfw->lock); 105 106 return err; 107} 108 109static int hwdep_unlock(struct snd_oxfw *oxfw) 110{ 111 int err; 112 113 spin_lock_irq(&oxfw->lock); 114 115 if (oxfw->dev_lock_count == -1) { 116 oxfw->dev_lock_count = 0; 117 err = 0; 118 } else { 119 err = -EBADFD; 120 } 121 122 spin_unlock_irq(&oxfw->lock); 123 124 return err; 125} 126 127static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) 128{ 129 struct snd_oxfw *oxfw = hwdep->private_data; 130 131 spin_lock_irq(&oxfw->lock); 132 if (oxfw->dev_lock_count == -1) 133 oxfw->dev_lock_count = 0; 134 spin_unlock_irq(&oxfw->lock); 135 136 return 0; 137} 138 139static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, 140 unsigned int cmd, unsigned long arg) 141{ 142 struct snd_oxfw *oxfw = hwdep->private_data; 143 144 switch (cmd) { 145 case SNDRV_FIREWIRE_IOCTL_GET_INFO: 146 return hwdep_get_info(oxfw, (void __user *)arg); 147 case SNDRV_FIREWIRE_IOCTL_LOCK: 148 return hwdep_lock(oxfw); 149 case SNDRV_FIREWIRE_IOCTL_UNLOCK: 150 return hwdep_unlock(oxfw); 151 default: 152 return -ENOIOCTLCMD; 153 } 154} 155 156#ifdef CONFIG_COMPAT 157static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, 158 unsigned int cmd, unsigned long arg) 159{ 160 return hwdep_ioctl(hwdep, file, cmd, 161 (unsigned long)compat_ptr(arg)); 162} 163#else 164#define hwdep_compat_ioctl NULL 165#endif 166 167int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw) 168{ 169 static const struct snd_hwdep_ops hwdep_ops = { 170 .read = hwdep_read, 171 .release = hwdep_release, 172 .poll = hwdep_poll, 173 .ioctl = hwdep_ioctl, 174 .ioctl_compat = hwdep_compat_ioctl, 175 }; 176 struct snd_hwdep *hwdep; 177 int err; 178 179 err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep); 180 if (err < 0) 181 goto end; 182 strcpy(hwdep->name, oxfw->card->driver); 183 hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW; 184 hwdep->ops = hwdep_ops; 185 hwdep->private_data = oxfw; 186 hwdep->exclusive = true; 187end: 188 return err; 189}