Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/avs/control.c
51233 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
//
3
// Copyright(c) 2021-2022 Intel Corporation
4
//
5
// Authors: Amadeusz Slawinski <[email protected]>
6
// Cezary Rojewski <[email protected]>
7
//
8
9
#include <linux/cleanup.h>
10
#include <sound/soc.h>
11
#include "avs.h"
12
#include "control.h"
13
#include "messages.h"
14
#include "path.h"
15
16
static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol)
17
{
18
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kcontrol);
19
struct device *dev = snd_soc_dapm_to_dev(dapm);
20
21
return to_avs_dev(dev);
22
}
23
24
static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 id)
25
{
26
struct avs_path *path;
27
struct avs_path_pipeline *ppl;
28
struct avs_path_module *mod;
29
30
spin_lock(&adev->path_list_lock);
31
list_for_each_entry(path, &adev->path_list, node) {
32
list_for_each_entry(ppl, &path->ppl_list, node) {
33
list_for_each_entry(mod, &ppl->mod_list, node) {
34
guid_t *type = &mod->template->cfg_ext->type;
35
36
if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) ||
37
guid_equal(type, &AVS_GAIN_MOD_UUID)) &&
38
mod->template->ctl_id == id) {
39
spin_unlock(&adev->path_list_lock);
40
return mod;
41
}
42
}
43
}
44
}
45
spin_unlock(&adev->path_list_lock);
46
47
return NULL;
48
}
49
50
int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
51
{
52
struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
53
struct avs_control_data *ctl_data = mc->dobj.private;
54
struct avs_path_module *active_module;
55
struct avs_volume_cfg *dspvols;
56
struct avs_dev *adev;
57
size_t num_dspvols;
58
int ret, i;
59
60
adev = avs_get_kcontrol_adev(kctl);
61
62
/* Prevent access to modules while path is being constructed. */
63
guard(mutex)(&adev->path_mutex);
64
65
active_module = avs_get_volume_module(adev, ctl_data->id);
66
if (active_module) {
67
ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id,
68
active_module->instance_id, &dspvols,
69
&num_dspvols);
70
if (ret)
71
return AVS_IPC_RET(ret);
72
73
/* Do not copy more than the control can store. */
74
num_dspvols = min_t(u32, num_dspvols, SND_SOC_TPLG_MAX_CHAN);
75
for (i = 0; i < num_dspvols; i++)
76
ctl_data->values[i] = dspvols[i].target_volume;
77
kfree(dspvols);
78
}
79
80
memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
81
return 0;
82
}
83
84
int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
85
{
86
struct avs_path_module *active_module;
87
struct avs_control_data *ctl_data;
88
struct soc_mixer_control *mc;
89
struct avs_dev *adev;
90
long *input;
91
int ret, i;
92
93
mc = (struct soc_mixer_control *)kctl->private_value;
94
ctl_data = mc->dobj.private;
95
adev = avs_get_kcontrol_adev(kctl);
96
input = uctl->value.integer.value;
97
i = 0;
98
99
/* mc->num_channels can be 0. */
100
do {
101
if (input[i] < mc->min || input[i] > mc->max)
102
return -EINVAL;
103
} while (++i < mc->num_channels);
104
105
if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values)))
106
return 0;
107
108
/* Prevent access to modules while path is being constructed. */
109
guard(mutex)(&adev->path_mutex);
110
111
active_module = avs_get_volume_module(adev, ctl_data->id);
112
if (active_module) {
113
ret = avs_peakvol_set_volume(adev, active_module, mc, input);
114
if (ret)
115
return ret;
116
}
117
118
memcpy(ctl_data->values, input, sizeof(ctl_data->values));
119
return 1;
120
}
121
122
int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
123
{
124
struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
125
126
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
127
uinfo->count = max_t(u32, 1, mc->num_channels);
128
uinfo->value.integer.min = 0;
129
uinfo->value.integer.max = mc->max;
130
return 0;
131
}
132
133
int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
134
{
135
struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
136
struct avs_control_data *ctl_data = mc->dobj.private;
137
struct avs_path_module *active_module;
138
struct avs_mute_cfg *dspmutes;
139
struct avs_dev *adev;
140
size_t num_dspmutes;
141
int ret, i;
142
143
adev = avs_get_kcontrol_adev(kctl);
144
145
/* Prevent access to modules while path is being constructed. */
146
guard(mutex)(&adev->path_mutex);
147
148
active_module = avs_get_volume_module(adev, ctl_data->id);
149
if (active_module) {
150
ret = avs_ipc_peakvol_get_mute(adev, active_module->module_id,
151
active_module->instance_id, &dspmutes,
152
&num_dspmutes);
153
if (ret)
154
return AVS_IPC_RET(ret);
155
156
/* Do not copy more than the control can store. */
157
num_dspmutes = min_t(u32, num_dspmutes, SND_SOC_TPLG_MAX_CHAN);
158
for (i = 0; i < num_dspmutes; i++)
159
ctl_data->values[i] = !dspmutes[i].mute;
160
kfree(dspmutes);
161
}
162
163
memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
164
return 0;
165
}
166
167
int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
168
{
169
struct avs_path_module *active_module;
170
struct avs_control_data *ctl_data;
171
struct soc_mixer_control *mc;
172
struct avs_dev *adev;
173
long *input;
174
int ret, i;
175
176
mc = (struct soc_mixer_control *)kctl->private_value;
177
ctl_data = mc->dobj.private;
178
adev = avs_get_kcontrol_adev(kctl);
179
input = uctl->value.integer.value;
180
i = 0;
181
182
/* mc->num_channels can be 0. */
183
do {
184
if (input[i] < mc->min || input[i] > mc->max)
185
return -EINVAL;
186
} while (++i < mc->num_channels);
187
188
if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values)))
189
return 0;
190
191
/* Prevent access to modules while path is being constructed. */
192
guard(mutex)(&adev->path_mutex);
193
194
active_module = avs_get_volume_module(adev, ctl_data->id);
195
if (active_module) {
196
ret = avs_peakvol_set_mute(adev, active_module, mc, input);
197
if (ret)
198
return ret;
199
}
200
201
memcpy(ctl_data->values, input, sizeof(ctl_data->values));
202
return 1;
203
}
204
205
int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
206
{
207
struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
208
209
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
210
uinfo->count = max_t(u32, 1, mc->num_channels);
211
uinfo->value.integer.min = 0;
212
uinfo->value.integer.max = mc->max;
213
return 0;
214
}
215
216