xref: /openbmc/linux/sound/firewire/dice/dice-hwdep.c (revision 75b1a8f9)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
219af57b4STakashi Sakamoto /*
319af57b4STakashi Sakamoto  * dice_hwdep.c - a part of driver for DICE based devices
419af57b4STakashi Sakamoto  *
519af57b4STakashi Sakamoto  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
619af57b4STakashi Sakamoto  * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
719af57b4STakashi Sakamoto  */
819af57b4STakashi Sakamoto 
919af57b4STakashi Sakamoto #include "dice.h"
1019af57b4STakashi Sakamoto 
hwdep_read(struct snd_hwdep * hwdep,char __user * buf,long count,loff_t * offset)1119af57b4STakashi Sakamoto static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
1219af57b4STakashi Sakamoto 			    long count, loff_t *offset)
1319af57b4STakashi Sakamoto {
1419af57b4STakashi Sakamoto 	struct snd_dice *dice = hwdep->private_data;
1519af57b4STakashi Sakamoto 	DEFINE_WAIT(wait);
1619af57b4STakashi Sakamoto 	union snd_firewire_event event;
1719af57b4STakashi Sakamoto 
1819af57b4STakashi Sakamoto 	spin_lock_irq(&dice->lock);
1919af57b4STakashi Sakamoto 
2019af57b4STakashi Sakamoto 	while (!dice->dev_lock_changed && dice->notification_bits == 0) {
2119af57b4STakashi Sakamoto 		prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
2219af57b4STakashi Sakamoto 		spin_unlock_irq(&dice->lock);
2319af57b4STakashi Sakamoto 		schedule();
2419af57b4STakashi Sakamoto 		finish_wait(&dice->hwdep_wait, &wait);
2519af57b4STakashi Sakamoto 		if (signal_pending(current))
2619af57b4STakashi Sakamoto 			return -ERESTARTSYS;
2719af57b4STakashi Sakamoto 		spin_lock_irq(&dice->lock);
2819af57b4STakashi Sakamoto 	}
2919af57b4STakashi Sakamoto 
3019af57b4STakashi Sakamoto 	memset(&event, 0, sizeof(event));
3119af57b4STakashi Sakamoto 	if (dice->dev_lock_changed) {
3219af57b4STakashi Sakamoto 		event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
3319af57b4STakashi Sakamoto 		event.lock_status.status = dice->dev_lock_count > 0;
3419af57b4STakashi Sakamoto 		dice->dev_lock_changed = false;
3519af57b4STakashi Sakamoto 
3619af57b4STakashi Sakamoto 		count = min_t(long, count, sizeof(event.lock_status));
3719af57b4STakashi Sakamoto 	} else {
3819af57b4STakashi Sakamoto 		event.dice_notification.type =
3919af57b4STakashi Sakamoto 					SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
4019af57b4STakashi Sakamoto 		event.dice_notification.notification = dice->notification_bits;
4119af57b4STakashi Sakamoto 		dice->notification_bits = 0;
4219af57b4STakashi Sakamoto 
4319af57b4STakashi Sakamoto 		count = min_t(long, count, sizeof(event.dice_notification));
4419af57b4STakashi Sakamoto 	}
4519af57b4STakashi Sakamoto 
4619af57b4STakashi Sakamoto 	spin_unlock_irq(&dice->lock);
4719af57b4STakashi Sakamoto 
4819af57b4STakashi Sakamoto 	if (copy_to_user(buf, &event, count))
4919af57b4STakashi Sakamoto 		return -EFAULT;
5019af57b4STakashi Sakamoto 
5119af57b4STakashi Sakamoto 	return count;
5219af57b4STakashi Sakamoto }
5319af57b4STakashi Sakamoto 
hwdep_poll(struct snd_hwdep * hwdep,struct file * file,poll_table * wait)54680ef72aSAl Viro static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
5519af57b4STakashi Sakamoto 			       poll_table *wait)
5619af57b4STakashi Sakamoto {
5719af57b4STakashi Sakamoto 	struct snd_dice *dice = hwdep->private_data;
58680ef72aSAl Viro 	__poll_t events;
5919af57b4STakashi Sakamoto 
6019af57b4STakashi Sakamoto 	poll_wait(file, &dice->hwdep_wait, wait);
6119af57b4STakashi Sakamoto 
6219af57b4STakashi Sakamoto 	spin_lock_irq(&dice->lock);
6319af57b4STakashi Sakamoto 	if (dice->dev_lock_changed || dice->notification_bits != 0)
64a9a08845SLinus Torvalds 		events = EPOLLIN | EPOLLRDNORM;
6519af57b4STakashi Sakamoto 	else
6619af57b4STakashi Sakamoto 		events = 0;
6719af57b4STakashi Sakamoto 	spin_unlock_irq(&dice->lock);
6819af57b4STakashi Sakamoto 
6919af57b4STakashi Sakamoto 	return events;
7019af57b4STakashi Sakamoto }
7119af57b4STakashi Sakamoto 
hwdep_get_info(struct snd_dice * dice,void __user * arg)7219af57b4STakashi Sakamoto static int hwdep_get_info(struct snd_dice *dice, void __user *arg)
7319af57b4STakashi Sakamoto {
7419af57b4STakashi Sakamoto 	struct fw_device *dev = fw_parent_device(dice->unit);
7519af57b4STakashi Sakamoto 	struct snd_firewire_get_info info;
7619af57b4STakashi Sakamoto 
7719af57b4STakashi Sakamoto 	memset(&info, 0, sizeof(info));
7819af57b4STakashi Sakamoto 	info.type = SNDRV_FIREWIRE_TYPE_DICE;
7919af57b4STakashi Sakamoto 	info.card = dev->card->index;
8019af57b4STakashi Sakamoto 	*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
8119af57b4STakashi Sakamoto 	*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
82*75b1a8f9SJoe Perches 	strscpy(info.device_name, dev_name(&dev->device),
8319af57b4STakashi Sakamoto 		sizeof(info.device_name));
8419af57b4STakashi Sakamoto 
8519af57b4STakashi Sakamoto 	if (copy_to_user(arg, &info, sizeof(info)))
8619af57b4STakashi Sakamoto 		return -EFAULT;
8719af57b4STakashi Sakamoto 
8819af57b4STakashi Sakamoto 	return 0;
8919af57b4STakashi Sakamoto }
9019af57b4STakashi Sakamoto 
hwdep_lock(struct snd_dice * dice)9119af57b4STakashi Sakamoto static int hwdep_lock(struct snd_dice *dice)
9219af57b4STakashi Sakamoto {
9319af57b4STakashi Sakamoto 	int err;
9419af57b4STakashi Sakamoto 
9519af57b4STakashi Sakamoto 	spin_lock_irq(&dice->lock);
9619af57b4STakashi Sakamoto 
9719af57b4STakashi Sakamoto 	if (dice->dev_lock_count == 0) {
9819af57b4STakashi Sakamoto 		dice->dev_lock_count = -1;
9919af57b4STakashi Sakamoto 		err = 0;
10019af57b4STakashi Sakamoto 	} else {
10119af57b4STakashi Sakamoto 		err = -EBUSY;
10219af57b4STakashi Sakamoto 	}
10319af57b4STakashi Sakamoto 
10419af57b4STakashi Sakamoto 	spin_unlock_irq(&dice->lock);
10519af57b4STakashi Sakamoto 
10619af57b4STakashi Sakamoto 	return err;
10719af57b4STakashi Sakamoto }
10819af57b4STakashi Sakamoto 
hwdep_unlock(struct snd_dice * dice)10919af57b4STakashi Sakamoto static int hwdep_unlock(struct snd_dice *dice)
11019af57b4STakashi Sakamoto {
11119af57b4STakashi Sakamoto 	int err;
11219af57b4STakashi Sakamoto 
11319af57b4STakashi Sakamoto 	spin_lock_irq(&dice->lock);
11419af57b4STakashi Sakamoto 
11519af57b4STakashi Sakamoto 	if (dice->dev_lock_count == -1) {
11619af57b4STakashi Sakamoto 		dice->dev_lock_count = 0;
11719af57b4STakashi Sakamoto 		err = 0;
11819af57b4STakashi Sakamoto 	} else {
11919af57b4STakashi Sakamoto 		err = -EBADFD;
12019af57b4STakashi Sakamoto 	}
12119af57b4STakashi Sakamoto 
12219af57b4STakashi Sakamoto 	spin_unlock_irq(&dice->lock);
12319af57b4STakashi Sakamoto 
12419af57b4STakashi Sakamoto 	return err;
12519af57b4STakashi Sakamoto }
12619af57b4STakashi Sakamoto 
hwdep_release(struct snd_hwdep * hwdep,struct file * file)12719af57b4STakashi Sakamoto static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
12819af57b4STakashi Sakamoto {
12919af57b4STakashi Sakamoto 	struct snd_dice *dice = hwdep->private_data;
13019af57b4STakashi Sakamoto 
13119af57b4STakashi Sakamoto 	spin_lock_irq(&dice->lock);
13219af57b4STakashi Sakamoto 	if (dice->dev_lock_count == -1)
13319af57b4STakashi Sakamoto 		dice->dev_lock_count = 0;
13419af57b4STakashi Sakamoto 	spin_unlock_irq(&dice->lock);
13519af57b4STakashi Sakamoto 
13619af57b4STakashi Sakamoto 	return 0;
13719af57b4STakashi Sakamoto }
13819af57b4STakashi Sakamoto 
hwdep_ioctl(struct snd_hwdep * hwdep,struct file * file,unsigned int cmd,unsigned long arg)13919af57b4STakashi Sakamoto static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
14019af57b4STakashi Sakamoto 		       unsigned int cmd, unsigned long arg)
14119af57b4STakashi Sakamoto {
14219af57b4STakashi Sakamoto 	struct snd_dice *dice = hwdep->private_data;
14319af57b4STakashi Sakamoto 
14419af57b4STakashi Sakamoto 	switch (cmd) {
14519af57b4STakashi Sakamoto 	case SNDRV_FIREWIRE_IOCTL_GET_INFO:
14619af57b4STakashi Sakamoto 		return hwdep_get_info(dice, (void __user *)arg);
14719af57b4STakashi Sakamoto 	case SNDRV_FIREWIRE_IOCTL_LOCK:
14819af57b4STakashi Sakamoto 		return hwdep_lock(dice);
14919af57b4STakashi Sakamoto 	case SNDRV_FIREWIRE_IOCTL_UNLOCK:
15019af57b4STakashi Sakamoto 		return hwdep_unlock(dice);
15119af57b4STakashi Sakamoto 	default:
15219af57b4STakashi Sakamoto 		return -ENOIOCTLCMD;
15319af57b4STakashi Sakamoto 	}
15419af57b4STakashi Sakamoto }
15519af57b4STakashi Sakamoto 
15619af57b4STakashi Sakamoto #ifdef CONFIG_COMPAT
hwdep_compat_ioctl(struct snd_hwdep * hwdep,struct file * file,unsigned int cmd,unsigned long arg)15719af57b4STakashi Sakamoto static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
15819af57b4STakashi Sakamoto 			      unsigned int cmd, unsigned long arg)
15919af57b4STakashi Sakamoto {
16019af57b4STakashi Sakamoto 	return hwdep_ioctl(hwdep, file, cmd,
16119af57b4STakashi Sakamoto 			   (unsigned long)compat_ptr(arg));
16219af57b4STakashi Sakamoto }
16319af57b4STakashi Sakamoto #else
16419af57b4STakashi Sakamoto #define hwdep_compat_ioctl NULL
16519af57b4STakashi Sakamoto #endif
16619af57b4STakashi Sakamoto 
snd_dice_create_hwdep(struct snd_dice * dice)16719af57b4STakashi Sakamoto int snd_dice_create_hwdep(struct snd_dice *dice)
16819af57b4STakashi Sakamoto {
16919af57b4STakashi Sakamoto 	static const struct snd_hwdep_ops ops = {
17019af57b4STakashi Sakamoto 		.read         = hwdep_read,
17119af57b4STakashi Sakamoto 		.release      = hwdep_release,
17219af57b4STakashi Sakamoto 		.poll         = hwdep_poll,
17319af57b4STakashi Sakamoto 		.ioctl        = hwdep_ioctl,
17419af57b4STakashi Sakamoto 		.ioctl_compat = hwdep_compat_ioctl,
17519af57b4STakashi Sakamoto 	};
17619af57b4STakashi Sakamoto 	struct snd_hwdep *hwdep;
17719af57b4STakashi Sakamoto 	int err;
17819af57b4STakashi Sakamoto 
17919af57b4STakashi Sakamoto 	err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
18019af57b4STakashi Sakamoto 	if (err < 0)
18119af57b4STakashi Sakamoto 		return err;
18219af57b4STakashi Sakamoto 	strcpy(hwdep->name, "DICE");
18319af57b4STakashi Sakamoto 	hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
18419af57b4STakashi Sakamoto 	hwdep->ops = ops;
18519af57b4STakashi Sakamoto 	hwdep->private_data = dice;
18619af57b4STakashi Sakamoto 	hwdep->exclusive = true;
18719af57b4STakashi Sakamoto 
18819af57b4STakashi Sakamoto 	return 0;
18919af57b4STakashi Sakamoto }
190