linux/sound/firewire/bebob/bebob_hwdep.c
<<
>>
Prefs
   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