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