File Index
Files and directories
Sign in
FILE

control.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/intel/avs/control.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// Copyright(c) 2021-2022 Intel Corporation
  4//
  5// Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
  6//          Cezary Rojewski <cezary.rojewski@intel.com>
  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
 16static 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
 24static 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
 50int 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
 84int 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
122int 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
133int 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
167int 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
205int 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}
~/ Read-only file preview.