Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * bebob_hwdep.c - a part of driver for BeBoB based devices
0004  *
0005  * Copyright (c) 2013-2014 Takashi Sakamoto
0006  */
0007 
0008 /*
0009  * This codes give three functionality.
0010  *
0011  * 1.get firewire node infomation
0012  * 2.get notification about starting/stopping stream
0013  * 3.lock/unlock stream
0014  */
0015 
0016 #include "bebob.h"
0017 
0018 static long
0019 hwdep_read(struct snd_hwdep *hwdep, char __user *buf,  long count,
0020        loff_t *offset)
0021 {
0022     struct snd_bebob *bebob = hwdep->private_data;
0023     DEFINE_WAIT(wait);
0024     union snd_firewire_event event;
0025 
0026     spin_lock_irq(&bebob->lock);
0027 
0028     while (!bebob->dev_lock_changed) {
0029         prepare_to_wait(&bebob->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
0030         spin_unlock_irq(&bebob->lock);
0031         schedule();
0032         finish_wait(&bebob->hwdep_wait, &wait);
0033         if (signal_pending(current))
0034             return -ERESTARTSYS;
0035         spin_lock_irq(&bebob->lock);
0036     }
0037 
0038     memset(&event, 0, sizeof(event));
0039     count = min_t(long, count, sizeof(event.lock_status));
0040     event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
0041     event.lock_status.status = (bebob->dev_lock_count > 0);
0042     bebob->dev_lock_changed = false;
0043 
0044     spin_unlock_irq(&bebob->lock);
0045 
0046     if (copy_to_user(buf, &event, count))
0047         return -EFAULT;
0048 
0049     return count;
0050 }
0051 
0052 static __poll_t
0053 hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
0054 {
0055     struct snd_bebob *bebob = hwdep->private_data;
0056     __poll_t events;
0057 
0058     poll_wait(file, &bebob->hwdep_wait, wait);
0059 
0060     spin_lock_irq(&bebob->lock);
0061     if (bebob->dev_lock_changed)
0062         events = EPOLLIN | EPOLLRDNORM;
0063     else
0064         events = 0;
0065     spin_unlock_irq(&bebob->lock);
0066 
0067     return events;
0068 }
0069 
0070 static int
0071 hwdep_get_info(struct snd_bebob *bebob, void __user *arg)
0072 {
0073     struct fw_device *dev = fw_parent_device(bebob->unit);
0074     struct snd_firewire_get_info info;
0075 
0076     memset(&info, 0, sizeof(info));
0077     info.type = SNDRV_FIREWIRE_TYPE_BEBOB;
0078     info.card = dev->card->index;
0079     *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
0080     *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
0081     strscpy(info.device_name, dev_name(&dev->device),
0082         sizeof(info.device_name));
0083 
0084     if (copy_to_user(arg, &info, sizeof(info)))
0085         return -EFAULT;
0086 
0087     return 0;
0088 }
0089 
0090 static int
0091 hwdep_lock(struct snd_bebob *bebob)
0092 {
0093     int err;
0094 
0095     spin_lock_irq(&bebob->lock);
0096 
0097     if (bebob->dev_lock_count == 0) {
0098         bebob->dev_lock_count = -1;
0099         err = 0;
0100     } else {
0101         err = -EBUSY;
0102     }
0103 
0104     spin_unlock_irq(&bebob->lock);
0105 
0106     return err;
0107 }
0108 
0109 static int
0110 hwdep_unlock(struct snd_bebob *bebob)
0111 {
0112     int err;
0113 
0114     spin_lock_irq(&bebob->lock);
0115 
0116     if (bebob->dev_lock_count == -1) {
0117         bebob->dev_lock_count = 0;
0118         err = 0;
0119     } else {
0120         err = -EBADFD;
0121     }
0122 
0123     spin_unlock_irq(&bebob->lock);
0124 
0125     return err;
0126 }
0127 
0128 static int
0129 hwdep_release(struct snd_hwdep *hwdep, struct file *file)
0130 {
0131     struct snd_bebob *bebob = hwdep->private_data;
0132 
0133     spin_lock_irq(&bebob->lock);
0134     if (bebob->dev_lock_count == -1)
0135         bebob->dev_lock_count = 0;
0136     spin_unlock_irq(&bebob->lock);
0137 
0138     return 0;
0139 }
0140 
0141 static int
0142 hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
0143         unsigned int cmd, unsigned long arg)
0144 {
0145     struct snd_bebob *bebob = hwdep->private_data;
0146 
0147     switch (cmd) {
0148     case SNDRV_FIREWIRE_IOCTL_GET_INFO:
0149         return hwdep_get_info(bebob, (void __user *)arg);
0150     case SNDRV_FIREWIRE_IOCTL_LOCK:
0151         return hwdep_lock(bebob);
0152     case SNDRV_FIREWIRE_IOCTL_UNLOCK:
0153         return hwdep_unlock(bebob);
0154     default:
0155         return -ENOIOCTLCMD;
0156     }
0157 }
0158 
0159 #ifdef CONFIG_COMPAT
0160 static int
0161 hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
0162            unsigned int cmd, unsigned long arg)
0163 {
0164     return hwdep_ioctl(hwdep, file, cmd,
0165                (unsigned long)compat_ptr(arg));
0166 }
0167 #else
0168 #define hwdep_compat_ioctl NULL
0169 #endif
0170 
0171 int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
0172 {
0173     static const struct snd_hwdep_ops ops = {
0174         .read       = hwdep_read,
0175         .release    = hwdep_release,
0176         .poll       = hwdep_poll,
0177         .ioctl      = hwdep_ioctl,
0178         .ioctl_compat   = hwdep_compat_ioctl,
0179     };
0180     struct snd_hwdep *hwdep;
0181     int err;
0182 
0183     err = snd_hwdep_new(bebob->card, "BeBoB", 0, &hwdep);
0184     if (err < 0)
0185         goto end;
0186     strcpy(hwdep->name, "BeBoB");
0187     hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB;
0188     hwdep->ops = ops;
0189     hwdep->private_data = bebob;
0190     hwdep->exclusive = true;
0191 end:
0192     return err;
0193 }
0194