File Index
Files and directories
Sign in
FILE

dice-hwdep.c

File preview with syntax highlighting.

linux-6.19.14/sound/firewire/dice/dice-hwdep.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * dice_hwdep.c - a part of driver for DICE based devices
  4 *
  5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  6 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
  7 */
  8
  9#include "dice.h"
 10
 11static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
 12			    long count, loff_t *offset)
 13{
 14	struct snd_dice *dice = hwdep->private_data;
 15	DEFINE_WAIT(wait);
 16	union snd_firewire_event event;
 17
 18	spin_lock_irq(&dice->lock);
 19
 20	while (!dice->dev_lock_changed && dice->notification_bits == 0) {
 21		prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
 22		spin_unlock_irq(&dice->lock);
 23		schedule();
 24		finish_wait(&dice->hwdep_wait, &wait);
 25		if (signal_pending(current))
 26			return -ERESTARTSYS;
 27		spin_lock_irq(&dice->lock);
 28	}
 29
 30	memset(&event, 0, sizeof(event));
 31	if (dice->dev_lock_changed) {
 32		event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
 33		event.lock_status.status = dice->dev_lock_count > 0;
 34		dice->dev_lock_changed = false;
 35
 36		count = min_t(long, count, sizeof(event.lock_status));
 37	} else {
 38		event.dice_notification.type =
 39					SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
 40		event.dice_notification.notification = dice->notification_bits;
 41		dice->notification_bits = 0;
 42
 43		count = min_t(long, count, sizeof(event.dice_notification));
 44	}
 45
 46	spin_unlock_irq(&dice->lock);
 47
 48	if (copy_to_user(buf, &event, count))
 49		return -EFAULT;
 50
 51	return count;
 52}
 53
 54static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
 55			       poll_table *wait)
 56{
 57	struct snd_dice *dice = hwdep->private_data;
 58
 59	poll_wait(file, &dice->hwdep_wait, wait);
 60
 61	guard(spinlock_irq)(&dice->lock);
 62	if (dice->dev_lock_changed || dice->notification_bits != 0)
 63		return EPOLLIN | EPOLLRDNORM;
 64	else
 65		return 0;
 66}
 67
 68static int hwdep_get_info(struct snd_dice *dice, void __user *arg)
 69{
 70	struct fw_device *dev = fw_parent_device(dice->unit);
 71	struct snd_firewire_get_info info;
 72
 73	memset(&info, 0, sizeof(info));
 74	info.type = SNDRV_FIREWIRE_TYPE_DICE;
 75	info.card = dev->card->index;
 76	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
 77	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
 78	strscpy(info.device_name, dev_name(&dev->device),
 79		sizeof(info.device_name));
 80
 81	if (copy_to_user(arg, &info, sizeof(info)))
 82		return -EFAULT;
 83
 84	return 0;
 85}
 86
 87static int hwdep_lock(struct snd_dice *dice)
 88{
 89	guard(spinlock_irq)(&dice->lock);
 90
 91	if (dice->dev_lock_count == 0) {
 92		dice->dev_lock_count = -1;
 93		return 0;
 94	} else {
 95		return -EBUSY;
 96	}
 97}
 98
 99static int hwdep_unlock(struct snd_dice *dice)
100{
101	guard(spinlock_irq)(&dice->lock);
102
103	if (dice->dev_lock_count == -1) {
104		dice->dev_lock_count = 0;
105		return 0;
106	} else {
107		return -EBADFD;
108	}
109}
110
111static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
112{
113	struct snd_dice *dice = hwdep->private_data;
114
115	guard(spinlock_irq)(&dice->lock);
116	if (dice->dev_lock_count == -1)
117		dice->dev_lock_count = 0;
118
119	return 0;
120}
121
122static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
123		       unsigned int cmd, unsigned long arg)
124{
125	struct snd_dice *dice = hwdep->private_data;
126
127	switch (cmd) {
128	case SNDRV_FIREWIRE_IOCTL_GET_INFO:
129		return hwdep_get_info(dice, (void __user *)arg);
130	case SNDRV_FIREWIRE_IOCTL_LOCK:
131		return hwdep_lock(dice);
132	case SNDRV_FIREWIRE_IOCTL_UNLOCK:
133		return hwdep_unlock(dice);
134	default:
135		return -ENOIOCTLCMD;
136	}
137}
138
139#ifdef CONFIG_COMPAT
140static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
141			      unsigned int cmd, unsigned long arg)
142{
143	return hwdep_ioctl(hwdep, file, cmd,
144			   (unsigned long)compat_ptr(arg));
145}
146#else
147#define hwdep_compat_ioctl NULL
148#endif
149
150int snd_dice_create_hwdep(struct snd_dice *dice)
151{
152	static const struct snd_hwdep_ops ops = {
153		.read         = hwdep_read,
154		.release      = hwdep_release,
155		.poll         = hwdep_poll,
156		.ioctl        = hwdep_ioctl,
157		.ioctl_compat = hwdep_compat_ioctl,
158	};
159	struct snd_hwdep *hwdep;
160	int err;
161
162	err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
163	if (err < 0)
164		return err;
165	strscpy(hwdep->name, "DICE");
166	hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
167	hwdep->ops = ops;
168	hwdep->private_data = dice;
169	hwdep->exclusive = true;
170
171	return 0;
172}
~/ Read-only file preview.