cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dice-hwdep.c (4347B)


      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	__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	else
     66		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_COMPAT
    157static 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#else
    164#define hwdep_compat_ioctl NULL
    165#endif
    166
    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}