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