brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · ffc0b97 Raw
190 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * dice_hwdep.c - a part of driver for DICE based devices4 *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	__poll_t events;59 60	poll_wait(file, &dice->hwdep_wait, wait);61 62	spin_lock_irq(&dice->lock);63	if (dice->dev_lock_changed || dice->notification_bits != 0)64		events = EPOLLIN | EPOLLRDNORM;65	else66		events = 0;67	spin_unlock_irq(&dice->lock);68 69	return events;70}71 72static int hwdep_get_info(struct snd_dice *dice, void __user *arg)73{74	struct fw_device *dev = fw_parent_device(dice->unit);75	struct snd_firewire_get_info info;76 77	memset(&info, 0, sizeof(info));78	info.type = SNDRV_FIREWIRE_TYPE_DICE;79	info.card = dev->card->index;80	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);81	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);82	strscpy(info.device_name, dev_name(&dev->device),83		sizeof(info.device_name));84 85	if (copy_to_user(arg, &info, sizeof(info)))86		return -EFAULT;87 88	return 0;89}90 91static int hwdep_lock(struct snd_dice *dice)92{93	int err;94 95	spin_lock_irq(&dice->lock);96 97	if (dice->dev_lock_count == 0) {98		dice->dev_lock_count = -1;99		err = 0;100	} else {101		err = -EBUSY;102	}103 104	spin_unlock_irq(&dice->lock);105 106	return err;107}108 109static int hwdep_unlock(struct snd_dice *dice)110{111	int err;112 113	spin_lock_irq(&dice->lock);114 115	if (dice->dev_lock_count == -1) {116		dice->dev_lock_count = 0;117		err = 0;118	} else {119		err = -EBADFD;120	}121 122	spin_unlock_irq(&dice->lock);123 124	return err;125}126 127static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)128{129	struct snd_dice *dice = hwdep->private_data;130 131	spin_lock_irq(&dice->lock);132	if (dice->dev_lock_count == -1)133		dice->dev_lock_count = 0;134	spin_unlock_irq(&dice->lock);135 136	return 0;137}138 139static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,140		       unsigned int cmd, unsigned long arg)141{142	struct snd_dice *dice = hwdep->private_data;143 144	switch (cmd) {145	case SNDRV_FIREWIRE_IOCTL_GET_INFO:146		return hwdep_get_info(dice, (void __user *)arg);147	case SNDRV_FIREWIRE_IOCTL_LOCK:148		return hwdep_lock(dice);149	case SNDRV_FIREWIRE_IOCTL_UNLOCK:150		return hwdep_unlock(dice);151	default:152		return -ENOIOCTLCMD;153	}154}155 156#ifdef CONFIG_COMPAT157static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,158			      unsigned int cmd, unsigned long arg)159{160	return hwdep_ioctl(hwdep, file, cmd,161			   (unsigned long)compat_ptr(arg));162}163#else164#define hwdep_compat_ioctl NULL165#endif166 167int snd_dice_create_hwdep(struct snd_dice *dice)168{169	static const struct snd_hwdep_ops ops = {170		.read         = hwdep_read,171		.release      = hwdep_release,172		.poll         = hwdep_poll,173		.ioctl        = hwdep_ioctl,174		.ioctl_compat = hwdep_compat_ioctl,175	};176	struct snd_hwdep *hwdep;177	int err;178 179	err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);180	if (err < 0)181		return err;182	strcpy(hwdep->name, "DICE");183	hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;184	hwdep->ops = ops;185	hwdep->private_data = dice;186	hwdep->exclusive = true;187 188	return 0;189}190