1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28985f4acSTakashi Sakamoto /*
38985f4acSTakashi Sakamoto * oxfw_hwdep.c - a part of driver for OXFW970/971 based devices
48985f4acSTakashi Sakamoto *
58985f4acSTakashi Sakamoto * Copyright (c) 2014 Takashi Sakamoto
68985f4acSTakashi Sakamoto */
78985f4acSTakashi Sakamoto
88985f4acSTakashi Sakamoto /*
98985f4acSTakashi Sakamoto * This codes give three functionality.
108985f4acSTakashi Sakamoto *
118985f4acSTakashi Sakamoto * 1.get firewire node information
128985f4acSTakashi Sakamoto * 2.get notification about starting/stopping stream
138985f4acSTakashi Sakamoto * 3.lock/unlock stream
148985f4acSTakashi Sakamoto */
158985f4acSTakashi Sakamoto
168985f4acSTakashi Sakamoto #include "oxfw.h"
178985f4acSTakashi Sakamoto
hwdep_read(struct snd_hwdep * hwdep,char __user * buf,long count,loff_t * offset)188985f4acSTakashi Sakamoto static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
198985f4acSTakashi Sakamoto loff_t *offset)
208985f4acSTakashi Sakamoto {
218985f4acSTakashi Sakamoto struct snd_oxfw *oxfw = hwdep->private_data;
228985f4acSTakashi Sakamoto DEFINE_WAIT(wait);
238985f4acSTakashi Sakamoto union snd_firewire_event event;
248985f4acSTakashi Sakamoto
258985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
268985f4acSTakashi Sakamoto
278985f4acSTakashi Sakamoto while (!oxfw->dev_lock_changed) {
288985f4acSTakashi Sakamoto prepare_to_wait(&oxfw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
298985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
308985f4acSTakashi Sakamoto schedule();
318985f4acSTakashi Sakamoto finish_wait(&oxfw->hwdep_wait, &wait);
328985f4acSTakashi Sakamoto if (signal_pending(current))
338985f4acSTakashi Sakamoto return -ERESTARTSYS;
348985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
358985f4acSTakashi Sakamoto }
368985f4acSTakashi Sakamoto
378985f4acSTakashi Sakamoto memset(&event, 0, sizeof(event));
388985f4acSTakashi Sakamoto event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
398985f4acSTakashi Sakamoto event.lock_status.status = (oxfw->dev_lock_count > 0);
408985f4acSTakashi Sakamoto oxfw->dev_lock_changed = false;
418985f4acSTakashi Sakamoto
428985f4acSTakashi Sakamoto count = min_t(long, count, sizeof(event.lock_status));
438985f4acSTakashi Sakamoto
448985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
458985f4acSTakashi Sakamoto
468985f4acSTakashi Sakamoto if (copy_to_user(buf, &event, count))
478985f4acSTakashi Sakamoto return -EFAULT;
488985f4acSTakashi Sakamoto
498985f4acSTakashi Sakamoto return count;
508985f4acSTakashi Sakamoto }
518985f4acSTakashi Sakamoto
hwdep_poll(struct snd_hwdep * hwdep,struct file * file,poll_table * wait)52680ef72aSAl Viro static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
538985f4acSTakashi Sakamoto poll_table *wait)
548985f4acSTakashi Sakamoto {
558985f4acSTakashi Sakamoto struct snd_oxfw *oxfw = hwdep->private_data;
56680ef72aSAl Viro __poll_t events;
578985f4acSTakashi Sakamoto
588985f4acSTakashi Sakamoto poll_wait(file, &oxfw->hwdep_wait, wait);
598985f4acSTakashi Sakamoto
608985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
618985f4acSTakashi Sakamoto if (oxfw->dev_lock_changed)
62a9a08845SLinus Torvalds events = EPOLLIN | EPOLLRDNORM;
638985f4acSTakashi Sakamoto else
648985f4acSTakashi Sakamoto events = 0;
658985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
668985f4acSTakashi Sakamoto
678985f4acSTakashi Sakamoto return events;
688985f4acSTakashi Sakamoto }
698985f4acSTakashi Sakamoto
hwdep_get_info(struct snd_oxfw * oxfw,void __user * arg)708985f4acSTakashi Sakamoto static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
718985f4acSTakashi Sakamoto {
728985f4acSTakashi Sakamoto struct fw_device *dev = fw_parent_device(oxfw->unit);
738985f4acSTakashi Sakamoto struct snd_firewire_get_info info;
748985f4acSTakashi Sakamoto
758985f4acSTakashi Sakamoto memset(&info, 0, sizeof(info));
768985f4acSTakashi Sakamoto info.type = SNDRV_FIREWIRE_TYPE_OXFW;
778985f4acSTakashi Sakamoto info.card = dev->card->index;
788985f4acSTakashi Sakamoto *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
798985f4acSTakashi Sakamoto *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
80*75b1a8f9SJoe Perches strscpy(info.device_name, dev_name(&dev->device),
818985f4acSTakashi Sakamoto sizeof(info.device_name));
828985f4acSTakashi Sakamoto
838985f4acSTakashi Sakamoto if (copy_to_user(arg, &info, sizeof(info)))
848985f4acSTakashi Sakamoto return -EFAULT;
858985f4acSTakashi Sakamoto
868985f4acSTakashi Sakamoto return 0;
878985f4acSTakashi Sakamoto }
888985f4acSTakashi Sakamoto
hwdep_lock(struct snd_oxfw * oxfw)898985f4acSTakashi Sakamoto static int hwdep_lock(struct snd_oxfw *oxfw)
908985f4acSTakashi Sakamoto {
918985f4acSTakashi Sakamoto int err;
928985f4acSTakashi Sakamoto
938985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
948985f4acSTakashi Sakamoto
958985f4acSTakashi Sakamoto if (oxfw->dev_lock_count == 0) {
968985f4acSTakashi Sakamoto oxfw->dev_lock_count = -1;
978985f4acSTakashi Sakamoto err = 0;
988985f4acSTakashi Sakamoto } else {
998985f4acSTakashi Sakamoto err = -EBUSY;
1008985f4acSTakashi Sakamoto }
1018985f4acSTakashi Sakamoto
1028985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
1038985f4acSTakashi Sakamoto
1048985f4acSTakashi Sakamoto return err;
1058985f4acSTakashi Sakamoto }
1068985f4acSTakashi Sakamoto
hwdep_unlock(struct snd_oxfw * oxfw)1078985f4acSTakashi Sakamoto static int hwdep_unlock(struct snd_oxfw *oxfw)
1088985f4acSTakashi Sakamoto {
1098985f4acSTakashi Sakamoto int err;
1108985f4acSTakashi Sakamoto
1118985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
1128985f4acSTakashi Sakamoto
1138985f4acSTakashi Sakamoto if (oxfw->dev_lock_count == -1) {
1148985f4acSTakashi Sakamoto oxfw->dev_lock_count = 0;
1158985f4acSTakashi Sakamoto err = 0;
1168985f4acSTakashi Sakamoto } else {
1178985f4acSTakashi Sakamoto err = -EBADFD;
1188985f4acSTakashi Sakamoto }
1198985f4acSTakashi Sakamoto
1208985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
1218985f4acSTakashi Sakamoto
1228985f4acSTakashi Sakamoto return err;
1238985f4acSTakashi Sakamoto }
1248985f4acSTakashi Sakamoto
hwdep_release(struct snd_hwdep * hwdep,struct file * file)1258985f4acSTakashi Sakamoto static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
1268985f4acSTakashi Sakamoto {
1278985f4acSTakashi Sakamoto struct snd_oxfw *oxfw = hwdep->private_data;
1288985f4acSTakashi Sakamoto
1298985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
1308985f4acSTakashi Sakamoto if (oxfw->dev_lock_count == -1)
1318985f4acSTakashi Sakamoto oxfw->dev_lock_count = 0;
1328985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
1338985f4acSTakashi Sakamoto
1348985f4acSTakashi Sakamoto return 0;
1358985f4acSTakashi Sakamoto }
1368985f4acSTakashi Sakamoto
hwdep_ioctl(struct snd_hwdep * hwdep,struct file * file,unsigned int cmd,unsigned long arg)1378985f4acSTakashi Sakamoto static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
1388985f4acSTakashi Sakamoto unsigned int cmd, unsigned long arg)
1398985f4acSTakashi Sakamoto {
1408985f4acSTakashi Sakamoto struct snd_oxfw *oxfw = hwdep->private_data;
1418985f4acSTakashi Sakamoto
1428985f4acSTakashi Sakamoto switch (cmd) {
1438985f4acSTakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_GET_INFO:
1448985f4acSTakashi Sakamoto return hwdep_get_info(oxfw, (void __user *)arg);
1458985f4acSTakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_LOCK:
1468985f4acSTakashi Sakamoto return hwdep_lock(oxfw);
1478985f4acSTakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_UNLOCK:
1488985f4acSTakashi Sakamoto return hwdep_unlock(oxfw);
1498985f4acSTakashi Sakamoto default:
1508985f4acSTakashi Sakamoto return -ENOIOCTLCMD;
1518985f4acSTakashi Sakamoto }
1528985f4acSTakashi Sakamoto }
1538985f4acSTakashi Sakamoto
1548985f4acSTakashi Sakamoto #ifdef CONFIG_COMPAT
hwdep_compat_ioctl(struct snd_hwdep * hwdep,struct file * file,unsigned int cmd,unsigned long arg)1558985f4acSTakashi Sakamoto static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
1568985f4acSTakashi Sakamoto unsigned int cmd, unsigned long arg)
1578985f4acSTakashi Sakamoto {
1588985f4acSTakashi Sakamoto return hwdep_ioctl(hwdep, file, cmd,
1598985f4acSTakashi Sakamoto (unsigned long)compat_ptr(arg));
1608985f4acSTakashi Sakamoto }
1618985f4acSTakashi Sakamoto #else
1628985f4acSTakashi Sakamoto #define hwdep_compat_ioctl NULL
1638985f4acSTakashi Sakamoto #endif
1648985f4acSTakashi Sakamoto
snd_oxfw_create_hwdep(struct snd_oxfw * oxfw)1658985f4acSTakashi Sakamoto int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw)
1668985f4acSTakashi Sakamoto {
1678985f4acSTakashi Sakamoto static const struct snd_hwdep_ops hwdep_ops = {
1688985f4acSTakashi Sakamoto .read = hwdep_read,
1698985f4acSTakashi Sakamoto .release = hwdep_release,
1708985f4acSTakashi Sakamoto .poll = hwdep_poll,
1718985f4acSTakashi Sakamoto .ioctl = hwdep_ioctl,
1728985f4acSTakashi Sakamoto .ioctl_compat = hwdep_compat_ioctl,
1738985f4acSTakashi Sakamoto };
1748985f4acSTakashi Sakamoto struct snd_hwdep *hwdep;
1758985f4acSTakashi Sakamoto int err;
1768985f4acSTakashi Sakamoto
1778985f4acSTakashi Sakamoto err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep);
1788985f4acSTakashi Sakamoto if (err < 0)
1798985f4acSTakashi Sakamoto goto end;
1808985f4acSTakashi Sakamoto strcpy(hwdep->name, oxfw->card->driver);
1818985f4acSTakashi Sakamoto hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW;
1828985f4acSTakashi Sakamoto hwdep->ops = hwdep_ops;
1838985f4acSTakashi Sakamoto hwdep->private_data = oxfw;
1848985f4acSTakashi Sakamoto hwdep->exclusive = true;
1858985f4acSTakashi Sakamoto end:
1868985f4acSTakashi Sakamoto return err;
1878985f4acSTakashi Sakamoto }
188