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