Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/hda/common/hwdep.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* HWDEP Interface for HD-audio codec
4
*
5
* Copyright (c) 2007 Takashi Iwai <[email protected]>
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
static 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
35
static 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
*/
60
static 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
78
static 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
85
static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
86
{
87
if (!capable(CAP_SYS_RAWIO))
88
return -EACCES;
89
return 0;
90
}
91
92
int snd_hda_create_hwdep(struct hda_codec *codec)
93
{
94
char hwname[16];
95
struct snd_hwdep *hwdep;
96
int err;
97
98
sprintf(hwname, "HDA Codec %d", codec->addr);
99
err = snd_hwdep_new(codec->card, hwname, codec->addr, &hwdep);
100
if (err < 0)
101
return err;
102
codec->hwdep = hwdep;
103
sprintf(hwdep->name, "HDA Codec %d", codec->addr);
104
hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
105
hwdep->private_data = codec;
106
hwdep->exclusive = 1;
107
108
hwdep->ops.open = hda_hwdep_open;
109
hwdep->ops.ioctl = hda_hwdep_ioctl;
110
#ifdef CONFIG_COMPAT
111
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
112
#endif
113
114
/* for sysfs */
115
hwdep->dev->groups = snd_hda_dev_attr_groups;
116
dev_set_drvdata(hwdep->dev, codec);
117
118
return 0;
119
}
120
121