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

hda_hwdep.c (2809B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * HWDEP Interface for HD-audio codec
      4 *
      5 * Copyright (c) 2007 Takashi Iwai <tiwai@suse.de>
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/slab.h>
     10#include <linux/compat.h>
     11#include <linux/nospec.h>
     12#include <sound/core.h>
     13#include <sound/hda_codec.h>
     14#include "hda_local.h"
     15#include <sound/hda_hwdep.h>
     16#include <sound/minors.h>
     17
     18/*
     19 * write/read an out-of-bound verb
     20 */
     21static int verb_write_ioctl(struct hda_codec *codec,
     22			    struct hda_verb_ioctl __user *arg)
     23{
     24	u32 verb, res;
     25
     26	if (get_user(verb, &arg->verb))
     27		return -EFAULT;
     28	res = snd_hda_codec_read(codec, verb >> 24, 0,
     29				 (verb >> 8) & 0xffff, verb & 0xff);
     30	if (put_user(res, &arg->res))
     31		return -EFAULT;
     32	return 0;
     33}
     34
     35static int get_wcap_ioctl(struct hda_codec *codec,
     36			  struct hda_verb_ioctl __user *arg)
     37{
     38	u32 verb, res;
     39	
     40	if (get_user(verb, &arg->verb))
     41		return -EFAULT;
     42	/* open-code get_wcaps(verb>>24) with nospec */
     43	verb >>= 24;
     44	if (verb < codec->core.start_nid ||
     45	    verb >= codec->core.start_nid + codec->core.num_nodes) {
     46		res = 0;
     47	} else {
     48		verb -= codec->core.start_nid;
     49		verb = array_index_nospec(verb, codec->core.num_nodes);
     50		res = codec->wcaps[verb];
     51	}
     52	if (put_user(res, &arg->res))
     53		return -EFAULT;
     54	return 0;
     55}
     56
     57
     58/*
     59 */
     60static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
     61			   unsigned int cmd, unsigned long arg)
     62{
     63	struct hda_codec *codec = hw->private_data;
     64	void __user *argp = (void __user *)arg;
     65
     66	switch (cmd) {
     67	case HDA_IOCTL_PVERSION:
     68		return put_user(HDA_HWDEP_VERSION, (int __user *)argp);
     69	case HDA_IOCTL_VERB_WRITE:
     70		return verb_write_ioctl(codec, argp);
     71	case HDA_IOCTL_GET_WCAP:
     72		return get_wcap_ioctl(codec, argp);
     73	}
     74	return -ENOIOCTLCMD;
     75}
     76
     77#ifdef CONFIG_COMPAT
     78static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
     79				  unsigned int cmd, unsigned long arg)
     80{
     81	return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg));
     82}
     83#endif
     84
     85static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
     86{
     87#ifndef CONFIG_SND_DEBUG_VERBOSE
     88	if (!capable(CAP_SYS_RAWIO))
     89		return -EACCES;
     90#endif
     91	return 0;
     92}
     93
     94int snd_hda_create_hwdep(struct hda_codec *codec)
     95{
     96	char hwname[16];
     97	struct snd_hwdep *hwdep;
     98	int err;
     99
    100	sprintf(hwname, "HDA Codec %d", codec->addr);
    101	err = snd_hwdep_new(codec->card, hwname, codec->addr, &hwdep);
    102	if (err < 0)
    103		return err;
    104	codec->hwdep = hwdep;
    105	sprintf(hwdep->name, "HDA Codec %d", codec->addr);
    106	hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
    107	hwdep->private_data = codec;
    108	hwdep->exclusive = 1;
    109
    110	hwdep->ops.open = hda_hwdep_open;
    111	hwdep->ops.ioctl = hda_hwdep_ioctl;
    112#ifdef CONFIG_COMPAT
    113	hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
    114#endif
    115
    116	/* for sysfs */
    117	hwdep->dev.groups = snd_hda_dev_attr_groups;
    118	dev_set_drvdata(&hwdep->dev, codec);
    119
    120	return 0;
    121}