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

bebob_hwdep.c (4106B)


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