Branch data Line data Source code
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 : : */
21 : 0 : static int verb_write_ioctl(struct hda_codec *codec,
22 : : struct hda_verb_ioctl __user *arg)
23 : : {
24 : 0 : u32 verb, res;
25 : :
26 [ # # ]: 0 : if (get_user(verb, &arg->verb))
27 : : return -EFAULT;
28 : 0 : res = snd_hda_codec_read(codec, verb >> 24, 0,
29 : 0 : (verb >> 8) & 0xffff, verb & 0xff);
30 [ # # ]: 0 : if (put_user(res, &arg->res))
31 : 0 : return -EFAULT;
32 : : return 0;
33 : : }
34 : :
35 : 0 : static int get_wcap_ioctl(struct hda_codec *codec,
36 : : struct hda_verb_ioctl __user *arg)
37 : : {
38 : 0 : u32 verb, res;
39 : :
40 [ # # ]: 0 : if (get_user(verb, &arg->verb))
41 : : return -EFAULT;
42 : : /* open-code get_wcaps(verb>>24) with nospec */
43 : 0 : verb >>= 24;
44 [ # # ]: 0 : if (verb < codec->core.start_nid ||
45 [ # # ]: 0 : verb >= codec->core.start_nid + codec->core.num_nodes) {
46 : : res = 0;
47 : : } else {
48 : 0 : verb -= codec->core.start_nid;
49 : 0 : verb = array_index_nospec(verb, codec->core.num_nodes);
50 : 0 : res = codec->wcaps[verb];
51 : : }
52 [ # # ]: 0 : if (put_user(res, &arg->res))
53 : 0 : return -EFAULT;
54 : : return 0;
55 : : }
56 : :
57 : :
58 : : /*
59 : : */
60 : 0 : static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
61 : : unsigned int cmd, unsigned long arg)
62 : : {
63 : 0 : struct hda_codec *codec = hw->private_data;
64 : 0 : void __user *argp = (void __user *)arg;
65 : :
66 [ # # # # ]: 0 : switch (cmd) {
67 : : case HDA_IOCTL_PVERSION:
68 : 0 : return put_user(HDA_HWDEP_VERSION, (int __user *)argp);
69 : 0 : case HDA_IOCTL_VERB_WRITE:
70 : 0 : return verb_write_ioctl(codec, argp);
71 : 0 : case HDA_IOCTL_GET_WCAP:
72 : 0 : return get_wcap_ioctl(codec, argp);
73 : : }
74 : : return -ENOIOCTLCMD;
75 : : }
76 : :
77 : : #ifdef CONFIG_COMPAT
78 : 0 : static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
79 : : unsigned int cmd, unsigned long arg)
80 : : {
81 : 0 : return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg));
82 : : }
83 : : #endif
84 : :
85 : 0 : static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
86 : : {
87 : : #ifndef CONFIG_SND_DEBUG_VERBOSE
88 [ # # ]: 0 : if (!capable(CAP_SYS_RAWIO))
89 : 0 : return -EACCES;
90 : : #endif
91 : : return 0;
92 : : }
93 : :
94 : 0 : int snd_hda_create_hwdep(struct hda_codec *codec)
95 : : {
96 : 0 : char hwname[16];
97 : 0 : struct snd_hwdep *hwdep;
98 : 0 : int err;
99 : :
100 : 0 : sprintf(hwname, "HDA Codec %d", codec->addr);
101 : 0 : err = snd_hwdep_new(codec->card, hwname, codec->addr, &hwdep);
102 [ # # ]: 0 : if (err < 0)
103 : : return err;
104 : 0 : codec->hwdep = hwdep;
105 : 0 : sprintf(hwdep->name, "HDA Codec %d", codec->addr);
106 : 0 : hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
107 : 0 : hwdep->private_data = codec;
108 : 0 : hwdep->exclusive = 1;
109 : :
110 : 0 : hwdep->ops.open = hda_hwdep_open;
111 : 0 : hwdep->ops.ioctl = hda_hwdep_ioctl;
112 : : #ifdef CONFIG_COMPAT
113 : 0 : hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
114 : : #endif
115 : :
116 : : /* for sysfs */
117 : 0 : hwdep->dev.groups = snd_hda_dev_attr_groups;
118 : 0 : dev_set_drvdata(&hwdep->dev, codec);
119 : :
120 : 0 : return 0;
121 : : }
|