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