1618eabeaSTakashi Sakamoto /* 2618eabeaSTakashi Sakamoto * bebob_hwdep.c - a part of driver for BeBoB based devices 3618eabeaSTakashi Sakamoto * 4618eabeaSTakashi Sakamoto * Copyright (c) 2013-2014 Takashi Sakamoto 5618eabeaSTakashi Sakamoto * 6618eabeaSTakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 7618eabeaSTakashi Sakamoto */ 8618eabeaSTakashi Sakamoto 9618eabeaSTakashi Sakamoto /* 10618eabeaSTakashi Sakamoto * This codes give three functionality. 11618eabeaSTakashi Sakamoto * 12618eabeaSTakashi Sakamoto * 1.get firewire node infomation 13618eabeaSTakashi Sakamoto * 2.get notification about starting/stopping stream 14618eabeaSTakashi Sakamoto * 3.lock/unlock stream 15618eabeaSTakashi Sakamoto */ 16618eabeaSTakashi Sakamoto 17618eabeaSTakashi Sakamoto #include "bebob.h" 18618eabeaSTakashi Sakamoto 19618eabeaSTakashi Sakamoto static long 20618eabeaSTakashi Sakamoto hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, 21618eabeaSTakashi Sakamoto loff_t *offset) 22618eabeaSTakashi Sakamoto { 23618eabeaSTakashi Sakamoto struct snd_bebob *bebob = hwdep->private_data; 24618eabeaSTakashi Sakamoto DEFINE_WAIT(wait); 25618eabeaSTakashi Sakamoto union snd_firewire_event event; 26618eabeaSTakashi Sakamoto 27618eabeaSTakashi Sakamoto spin_lock_irq(&bebob->lock); 28618eabeaSTakashi Sakamoto 29618eabeaSTakashi Sakamoto while (!bebob->dev_lock_changed) { 30618eabeaSTakashi Sakamoto prepare_to_wait(&bebob->hwdep_wait, &wait, TASK_INTERRUPTIBLE); 31618eabeaSTakashi Sakamoto spin_unlock_irq(&bebob->lock); 32618eabeaSTakashi Sakamoto schedule(); 33618eabeaSTakashi Sakamoto finish_wait(&bebob->hwdep_wait, &wait); 34618eabeaSTakashi Sakamoto if (signal_pending(current)) 35618eabeaSTakashi Sakamoto return -ERESTARTSYS; 36618eabeaSTakashi Sakamoto spin_lock_irq(&bebob->lock); 37618eabeaSTakashi Sakamoto } 38618eabeaSTakashi Sakamoto 39618eabeaSTakashi Sakamoto memset(&event, 0, sizeof(event)); 40618eabeaSTakashi Sakamoto if (bebob->dev_lock_changed) { 41618eabeaSTakashi Sakamoto event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; 42618eabeaSTakashi Sakamoto event.lock_status.status = (bebob->dev_lock_count > 0); 43618eabeaSTakashi Sakamoto bebob->dev_lock_changed = false; 44618eabeaSTakashi Sakamoto 45618eabeaSTakashi Sakamoto count = min_t(long, count, sizeof(event.lock_status)); 46618eabeaSTakashi Sakamoto } 47618eabeaSTakashi Sakamoto 48618eabeaSTakashi Sakamoto spin_unlock_irq(&bebob->lock); 49618eabeaSTakashi Sakamoto 50618eabeaSTakashi Sakamoto if (copy_to_user(buf, &event, count)) 51618eabeaSTakashi Sakamoto return -EFAULT; 52618eabeaSTakashi Sakamoto 53618eabeaSTakashi Sakamoto return count; 54618eabeaSTakashi Sakamoto } 55618eabeaSTakashi Sakamoto 56680ef72aSAl Viro static __poll_t 57618eabeaSTakashi Sakamoto hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) 58618eabeaSTakashi Sakamoto { 59618eabeaSTakashi Sakamoto struct snd_bebob *bebob = hwdep->private_data; 60680ef72aSAl Viro __poll_t events; 61618eabeaSTakashi Sakamoto 62618eabeaSTakashi Sakamoto poll_wait(file, &bebob->hwdep_wait, wait); 63618eabeaSTakashi Sakamoto 64618eabeaSTakashi Sakamoto spin_lock_irq(&bebob->lock); 65618eabeaSTakashi Sakamoto if (bebob->dev_lock_changed) 66a9a08845SLinus Torvalds events = EPOLLIN | EPOLLRDNORM; 67618eabeaSTakashi Sakamoto else 68618eabeaSTakashi Sakamoto events = 0; 69618eabeaSTakashi Sakamoto spin_unlock_irq(&bebob->lock); 70618eabeaSTakashi Sakamoto 71618eabeaSTakashi Sakamoto return events; 72618eabeaSTakashi Sakamoto } 73618eabeaSTakashi Sakamoto 74618eabeaSTakashi Sakamoto static int 75618eabeaSTakashi Sakamoto hwdep_get_info(struct snd_bebob *bebob, void __user *arg) 76618eabeaSTakashi Sakamoto { 77618eabeaSTakashi Sakamoto struct fw_device *dev = fw_parent_device(bebob->unit); 78618eabeaSTakashi Sakamoto struct snd_firewire_get_info info; 79618eabeaSTakashi Sakamoto 80618eabeaSTakashi Sakamoto memset(&info, 0, sizeof(info)); 81618eabeaSTakashi Sakamoto info.type = SNDRV_FIREWIRE_TYPE_BEBOB; 82618eabeaSTakashi Sakamoto info.card = dev->card->index; 83618eabeaSTakashi Sakamoto *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); 84618eabeaSTakashi Sakamoto *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); 85618eabeaSTakashi Sakamoto strlcpy(info.device_name, dev_name(&dev->device), 86618eabeaSTakashi Sakamoto sizeof(info.device_name)); 87618eabeaSTakashi Sakamoto 88618eabeaSTakashi Sakamoto if (copy_to_user(arg, &info, sizeof(info))) 89618eabeaSTakashi Sakamoto return -EFAULT; 90618eabeaSTakashi Sakamoto 91618eabeaSTakashi Sakamoto return 0; 92618eabeaSTakashi Sakamoto } 93618eabeaSTakashi Sakamoto 94618eabeaSTakashi Sakamoto static int 95618eabeaSTakashi Sakamoto hwdep_lock(struct snd_bebob *bebob) 96618eabeaSTakashi Sakamoto { 97618eabeaSTakashi Sakamoto int err; 98618eabeaSTakashi Sakamoto 99618eabeaSTakashi Sakamoto spin_lock_irq(&bebob->lock); 100618eabeaSTakashi Sakamoto 101618eabeaSTakashi Sakamoto if (bebob->dev_lock_count == 0) { 102618eabeaSTakashi Sakamoto bebob->dev_lock_count = -1; 103618eabeaSTakashi Sakamoto err = 0; 104618eabeaSTakashi Sakamoto } else { 105618eabeaSTakashi Sakamoto err = -EBUSY; 106618eabeaSTakashi Sakamoto } 107618eabeaSTakashi Sakamoto 108618eabeaSTakashi Sakamoto spin_unlock_irq(&bebob->lock); 109618eabeaSTakashi Sakamoto 110618eabeaSTakashi Sakamoto return err; 111618eabeaSTakashi Sakamoto } 112618eabeaSTakashi Sakamoto 113618eabeaSTakashi Sakamoto static int 114618eabeaSTakashi Sakamoto hwdep_unlock(struct snd_bebob *bebob) 115618eabeaSTakashi Sakamoto { 116618eabeaSTakashi Sakamoto int err; 117618eabeaSTakashi Sakamoto 118618eabeaSTakashi Sakamoto spin_lock_irq(&bebob->lock); 119618eabeaSTakashi Sakamoto 120618eabeaSTakashi Sakamoto if (bebob->dev_lock_count == -1) { 121618eabeaSTakashi Sakamoto bebob->dev_lock_count = 0; 122618eabeaSTakashi Sakamoto err = 0; 123618eabeaSTakashi Sakamoto } else { 124618eabeaSTakashi Sakamoto err = -EBADFD; 125618eabeaSTakashi Sakamoto } 126618eabeaSTakashi Sakamoto 127618eabeaSTakashi Sakamoto spin_unlock_irq(&bebob->lock); 128618eabeaSTakashi Sakamoto 129618eabeaSTakashi Sakamoto return err; 130618eabeaSTakashi Sakamoto } 131618eabeaSTakashi Sakamoto 132618eabeaSTakashi Sakamoto static int 133618eabeaSTakashi Sakamoto hwdep_release(struct snd_hwdep *hwdep, struct file *file) 134618eabeaSTakashi Sakamoto { 135618eabeaSTakashi Sakamoto struct snd_bebob *bebob = hwdep->private_data; 136618eabeaSTakashi Sakamoto 137618eabeaSTakashi Sakamoto spin_lock_irq(&bebob->lock); 138618eabeaSTakashi Sakamoto if (bebob->dev_lock_count == -1) 139618eabeaSTakashi Sakamoto bebob->dev_lock_count = 0; 140618eabeaSTakashi Sakamoto spin_unlock_irq(&bebob->lock); 141618eabeaSTakashi Sakamoto 142618eabeaSTakashi Sakamoto return 0; 143618eabeaSTakashi Sakamoto } 144618eabeaSTakashi Sakamoto 145618eabeaSTakashi Sakamoto static int 146618eabeaSTakashi Sakamoto hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, 147618eabeaSTakashi Sakamoto unsigned int cmd, unsigned long arg) 148618eabeaSTakashi Sakamoto { 149618eabeaSTakashi Sakamoto struct snd_bebob *bebob = hwdep->private_data; 150618eabeaSTakashi Sakamoto 151618eabeaSTakashi Sakamoto switch (cmd) { 152618eabeaSTakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_GET_INFO: 153618eabeaSTakashi Sakamoto return hwdep_get_info(bebob, (void __user *)arg); 154618eabeaSTakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_LOCK: 155618eabeaSTakashi Sakamoto return hwdep_lock(bebob); 156618eabeaSTakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_UNLOCK: 157618eabeaSTakashi Sakamoto return hwdep_unlock(bebob); 158618eabeaSTakashi Sakamoto default: 159618eabeaSTakashi Sakamoto return -ENOIOCTLCMD; 160618eabeaSTakashi Sakamoto } 161618eabeaSTakashi Sakamoto } 162618eabeaSTakashi Sakamoto 163618eabeaSTakashi Sakamoto #ifdef CONFIG_COMPAT 164618eabeaSTakashi Sakamoto static int 165618eabeaSTakashi Sakamoto hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, 166618eabeaSTakashi Sakamoto unsigned int cmd, unsigned long arg) 167618eabeaSTakashi Sakamoto { 168618eabeaSTakashi Sakamoto return hwdep_ioctl(hwdep, file, cmd, 169618eabeaSTakashi Sakamoto (unsigned long)compat_ptr(arg)); 170618eabeaSTakashi Sakamoto } 171618eabeaSTakashi Sakamoto #else 172618eabeaSTakashi Sakamoto #define hwdep_compat_ioctl NULL 173618eabeaSTakashi Sakamoto #endif 174618eabeaSTakashi Sakamoto 1754780f774STakashi Sakamoto int snd_bebob_create_hwdep_device(struct snd_bebob *bebob) 1764780f774STakashi Sakamoto { 1774780f774STakashi Sakamoto static const struct snd_hwdep_ops ops = { 178618eabeaSTakashi Sakamoto .read = hwdep_read, 179618eabeaSTakashi Sakamoto .release = hwdep_release, 180618eabeaSTakashi Sakamoto .poll = hwdep_poll, 181618eabeaSTakashi Sakamoto .ioctl = hwdep_ioctl, 182618eabeaSTakashi Sakamoto .ioctl_compat = hwdep_compat_ioctl, 183618eabeaSTakashi Sakamoto }; 184618eabeaSTakashi Sakamoto struct snd_hwdep *hwdep; 185618eabeaSTakashi Sakamoto int err; 186618eabeaSTakashi Sakamoto 187618eabeaSTakashi Sakamoto err = snd_hwdep_new(bebob->card, "BeBoB", 0, &hwdep); 188618eabeaSTakashi Sakamoto if (err < 0) 189618eabeaSTakashi Sakamoto goto end; 190618eabeaSTakashi Sakamoto strcpy(hwdep->name, "BeBoB"); 191618eabeaSTakashi Sakamoto hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB; 1924780f774STakashi Sakamoto hwdep->ops = ops; 193618eabeaSTakashi Sakamoto hwdep->private_data = bebob; 194618eabeaSTakashi Sakamoto hwdep->exclusive = true; 195618eabeaSTakashi Sakamoto end: 196618eabeaSTakashi Sakamoto return err; 197618eabeaSTakashi Sakamoto } 198618eabeaSTakashi Sakamoto 199