brintos

brintos / linux-shallow public Read only

0
0
Text · 2.7 KiB · 727f39a Raw
122 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * HWDEP Interface for HD-audio codec4 *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 verb20 */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_COMPAT78static 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#endif84 85static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)86{87#ifndef CONFIG_SND_DEBUG_VERBOSE88	if (!capable(CAP_SYS_RAWIO))89		return -EACCES;90#endif91	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_COMPAT113	hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;114#endif115 116	/* for sysfs */117	hwdep->dev->groups = snd_hda_dev_attr_groups;118	dev_set_drvdata(hwdep->dev, codec);119 120	return 0;121}122