xref: /openbmc/linux/sound/soc/sof/control.c (revision 0c888baba8e041c92c5c1882f25b8df5c29bff9f)
1c3078f53SLiam Girdwood // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2c3078f53SLiam Girdwood //
3c3078f53SLiam Girdwood // This file is provided under a dual BSD/GPLv2 license.  When using or
4c3078f53SLiam Girdwood // redistributing this file, you may do so under either license.
5c3078f53SLiam Girdwood //
6c3078f53SLiam Girdwood // Copyright(c) 2018 Intel Corporation. All rights reserved.
7c3078f53SLiam Girdwood //
8c3078f53SLiam Girdwood // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9c3078f53SLiam Girdwood //
10c3078f53SLiam Girdwood 
11c3078f53SLiam Girdwood /* Mixer Controls */
12c3078f53SLiam Girdwood 
13c3078f53SLiam Girdwood #include <linux/pm_runtime.h>
14c3078f53SLiam Girdwood #include "sof-priv.h"
15c3078f53SLiam Girdwood 
16c3078f53SLiam Girdwood static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
17c3078f53SLiam Girdwood {
18c3078f53SLiam Girdwood 	if (value >= size)
19c3078f53SLiam Girdwood 		return volume_map[size - 1];
20c3078f53SLiam Girdwood 
21c3078f53SLiam Girdwood 	return volume_map[value];
22c3078f53SLiam Girdwood }
23c3078f53SLiam Girdwood 
24c3078f53SLiam Girdwood static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
25c3078f53SLiam Girdwood {
26c3078f53SLiam Girdwood 	int i;
27c3078f53SLiam Girdwood 
28c3078f53SLiam Girdwood 	for (i = 0; i < size; i++) {
29c3078f53SLiam Girdwood 		if (volume_map[i] >= value)
30c3078f53SLiam Girdwood 			return i;
31c3078f53SLiam Girdwood 	}
32c3078f53SLiam Girdwood 
33c3078f53SLiam Girdwood 	return i - 1;
34c3078f53SLiam Girdwood }
35c3078f53SLiam Girdwood 
36c3078f53SLiam Girdwood int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
37c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
38c3078f53SLiam Girdwood {
39c3078f53SLiam Girdwood 	struct soc_mixer_control *sm =
40c3078f53SLiam Girdwood 		(struct soc_mixer_control *)kcontrol->private_value;
41c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
42c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
43c3078f53SLiam Girdwood 	unsigned int i, channels = scontrol->num_channels;
44c3078f53SLiam Girdwood 
45c3078f53SLiam Girdwood 	/* read back each channel */
46c3078f53SLiam Girdwood 	for (i = 0; i < channels; i++)
47c3078f53SLiam Girdwood 		ucontrol->value.integer.value[i] =
48c3078f53SLiam Girdwood 			ipc_to_mixer(cdata->chanv[i].value,
49c3078f53SLiam Girdwood 				     scontrol->volume_table, sm->max + 1);
50c3078f53SLiam Girdwood 
51c3078f53SLiam Girdwood 	return 0;
52c3078f53SLiam Girdwood }
53c3078f53SLiam Girdwood 
54c3078f53SLiam Girdwood int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
55c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
56c3078f53SLiam Girdwood {
57c3078f53SLiam Girdwood 	struct soc_mixer_control *sm =
58c3078f53SLiam Girdwood 		(struct soc_mixer_control *)kcontrol->private_value;
59c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
60c3078f53SLiam Girdwood 	struct snd_sof_dev *sdev = scontrol->sdev;
61c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
62c3078f53SLiam Girdwood 	unsigned int i, channels = scontrol->num_channels;
63c3078f53SLiam Girdwood 
64c3078f53SLiam Girdwood 	/* update each channel */
65c3078f53SLiam Girdwood 	for (i = 0; i < channels; i++) {
66c3078f53SLiam Girdwood 		cdata->chanv[i].value =
67c3078f53SLiam Girdwood 			mixer_to_ipc(ucontrol->value.integer.value[i],
68c3078f53SLiam Girdwood 				     scontrol->volume_table, sm->max + 1);
69c3078f53SLiam Girdwood 		cdata->chanv[i].channel = i;
70c3078f53SLiam Girdwood 	}
71c3078f53SLiam Girdwood 
72c3078f53SLiam Girdwood 	/* notify DSP of mixer updates */
73*0c888babSBard Liao 	if (pm_runtime_active(sdev->dev))
74c3078f53SLiam Girdwood 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
75c3078f53SLiam Girdwood 					      SOF_IPC_COMP_SET_VALUE,
76c3078f53SLiam Girdwood 					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
77c3078f53SLiam Girdwood 					      SOF_CTRL_CMD_VOLUME,
78c3078f53SLiam Girdwood 					      true);
79c3078f53SLiam Girdwood 
80c3078f53SLiam Girdwood 	return 0;
81c3078f53SLiam Girdwood }
82c3078f53SLiam Girdwood 
83c3078f53SLiam Girdwood int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
84c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
85c3078f53SLiam Girdwood {
86c3078f53SLiam Girdwood 	struct soc_mixer_control *sm =
87c3078f53SLiam Girdwood 		(struct soc_mixer_control *)kcontrol->private_value;
88c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
89c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
90c3078f53SLiam Girdwood 	unsigned int i, channels = scontrol->num_channels;
91c3078f53SLiam Girdwood 
92c3078f53SLiam Girdwood 	/* read back each channel */
93c3078f53SLiam Girdwood 	for (i = 0; i < channels; i++)
94c3078f53SLiam Girdwood 		ucontrol->value.integer.value[i] = cdata->chanv[i].value;
95c3078f53SLiam Girdwood 
96c3078f53SLiam Girdwood 	return 0;
97c3078f53SLiam Girdwood }
98c3078f53SLiam Girdwood 
99c3078f53SLiam Girdwood int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
100c3078f53SLiam Girdwood 		       struct snd_ctl_elem_value *ucontrol)
101c3078f53SLiam Girdwood {
102c3078f53SLiam Girdwood 	struct soc_mixer_control *sm =
103c3078f53SLiam Girdwood 		(struct soc_mixer_control *)kcontrol->private_value;
104c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = sm->dobj.private;
105c3078f53SLiam Girdwood 	struct snd_sof_dev *sdev = scontrol->sdev;
106c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
107c3078f53SLiam Girdwood 	unsigned int i, channels = scontrol->num_channels;
108c3078f53SLiam Girdwood 
109c3078f53SLiam Girdwood 	/* update each channel */
110c3078f53SLiam Girdwood 	for (i = 0; i < channels; i++) {
111c3078f53SLiam Girdwood 		cdata->chanv[i].value = ucontrol->value.integer.value[i];
112c3078f53SLiam Girdwood 		cdata->chanv[i].channel = i;
113c3078f53SLiam Girdwood 	}
114c3078f53SLiam Girdwood 
115c3078f53SLiam Girdwood 	/* notify DSP of mixer updates */
116*0c888babSBard Liao 	if (pm_runtime_active(sdev->dev))
117c3078f53SLiam Girdwood 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
118c3078f53SLiam Girdwood 					      SOF_IPC_COMP_SET_VALUE,
119c3078f53SLiam Girdwood 					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
120c3078f53SLiam Girdwood 					      SOF_CTRL_CMD_SWITCH,
121c3078f53SLiam Girdwood 					      true);
122c3078f53SLiam Girdwood 
123c3078f53SLiam Girdwood 	return 0;
124c3078f53SLiam Girdwood }
125c3078f53SLiam Girdwood 
126c3078f53SLiam Girdwood int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
127c3078f53SLiam Girdwood 		     struct snd_ctl_elem_value *ucontrol)
128c3078f53SLiam Girdwood {
129c3078f53SLiam Girdwood 	struct soc_enum *se =
130c3078f53SLiam Girdwood 		(struct soc_enum *)kcontrol->private_value;
131c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = se->dobj.private;
132c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
133c3078f53SLiam Girdwood 	unsigned int i, channels = scontrol->num_channels;
134c3078f53SLiam Girdwood 
135c3078f53SLiam Girdwood 	/* read back each channel */
136c3078f53SLiam Girdwood 	for (i = 0; i < channels; i++)
137c3078f53SLiam Girdwood 		ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
138c3078f53SLiam Girdwood 
139c3078f53SLiam Girdwood 	return 0;
140c3078f53SLiam Girdwood }
141c3078f53SLiam Girdwood 
142c3078f53SLiam Girdwood int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
143c3078f53SLiam Girdwood 		     struct snd_ctl_elem_value *ucontrol)
144c3078f53SLiam Girdwood {
145c3078f53SLiam Girdwood 	struct soc_enum *se =
146c3078f53SLiam Girdwood 		(struct soc_enum *)kcontrol->private_value;
147c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = se->dobj.private;
148c3078f53SLiam Girdwood 	struct snd_sof_dev *sdev = scontrol->sdev;
149c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
150c3078f53SLiam Girdwood 	unsigned int i, channels = scontrol->num_channels;
151c3078f53SLiam Girdwood 
152c3078f53SLiam Girdwood 	/* update each channel */
153c3078f53SLiam Girdwood 	for (i = 0; i < channels; i++) {
154c3078f53SLiam Girdwood 		cdata->chanv[i].value = ucontrol->value.enumerated.item[i];
155c3078f53SLiam Girdwood 		cdata->chanv[i].channel = i;
156c3078f53SLiam Girdwood 	}
157c3078f53SLiam Girdwood 
158c3078f53SLiam Girdwood 	/* notify DSP of enum updates */
159*0c888babSBard Liao 	if (pm_runtime_active(sdev->dev))
160c3078f53SLiam Girdwood 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
161c3078f53SLiam Girdwood 					      SOF_IPC_COMP_SET_VALUE,
162c3078f53SLiam Girdwood 					      SOF_CTRL_TYPE_VALUE_CHAN_GET,
163c3078f53SLiam Girdwood 					      SOF_CTRL_CMD_ENUM,
164c3078f53SLiam Girdwood 					      true);
165c3078f53SLiam Girdwood 
166c3078f53SLiam Girdwood 	return 0;
167c3078f53SLiam Girdwood }
168c3078f53SLiam Girdwood 
169c3078f53SLiam Girdwood int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
170c3078f53SLiam Girdwood 		      struct snd_ctl_elem_value *ucontrol)
171c3078f53SLiam Girdwood {
172c3078f53SLiam Girdwood 	struct soc_bytes_ext *be =
173c3078f53SLiam Girdwood 		(struct soc_bytes_ext *)kcontrol->private_value;
174c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
175c3078f53SLiam Girdwood 	struct snd_sof_dev *sdev = scontrol->sdev;
176c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
177c3078f53SLiam Girdwood 	struct sof_abi_hdr *data = cdata->data;
178c3078f53SLiam Girdwood 	size_t size;
179*0c888babSBard Liao 	int ret = 0;
180c3078f53SLiam Girdwood 
181c3078f53SLiam Girdwood 	if (be->max > sizeof(ucontrol->value.bytes.data)) {
182c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev,
183c3078f53SLiam Girdwood 				    "error: data max %d exceeds ucontrol data array size\n",
184c3078f53SLiam Girdwood 				    be->max);
185c3078f53SLiam Girdwood 		return -EINVAL;
186c3078f53SLiam Girdwood 	}
187c3078f53SLiam Girdwood 
188c3078f53SLiam Girdwood 	size = data->size + sizeof(*data);
189c3078f53SLiam Girdwood 	if (size > be->max) {
190c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev,
191c3078f53SLiam Girdwood 				    "error: DSP sent %zu bytes max is %d\n",
192c3078f53SLiam Girdwood 				    size, be->max);
193c3078f53SLiam Girdwood 		ret = -EINVAL;
194c3078f53SLiam Girdwood 		goto out;
195c3078f53SLiam Girdwood 	}
196c3078f53SLiam Girdwood 
197c3078f53SLiam Girdwood 	/* copy back to kcontrol */
198c3078f53SLiam Girdwood 	memcpy(ucontrol->value.bytes.data, data, size);
199c3078f53SLiam Girdwood 
200c3078f53SLiam Girdwood out:
201c3078f53SLiam Girdwood 	return ret;
202c3078f53SLiam Girdwood }
203c3078f53SLiam Girdwood 
204c3078f53SLiam Girdwood int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
205c3078f53SLiam Girdwood 		      struct snd_ctl_elem_value *ucontrol)
206c3078f53SLiam Girdwood {
207c3078f53SLiam Girdwood 	struct soc_bytes_ext *be =
208c3078f53SLiam Girdwood 		(struct soc_bytes_ext *)kcontrol->private_value;
209c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
210c3078f53SLiam Girdwood 	struct snd_sof_dev *sdev = scontrol->sdev;
211c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
212c3078f53SLiam Girdwood 	struct sof_abi_hdr *data = cdata->data;
2135661ad94SKeyon Jie 	size_t size = data->size + sizeof(*data);
214c3078f53SLiam Girdwood 
215c3078f53SLiam Girdwood 	if (be->max > sizeof(ucontrol->value.bytes.data)) {
216c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev,
217c3078f53SLiam Girdwood 				    "error: data max %d exceeds ucontrol data array size\n",
218c3078f53SLiam Girdwood 				    be->max);
219c3078f53SLiam Girdwood 		return -EINVAL;
220c3078f53SLiam Girdwood 	}
221c3078f53SLiam Girdwood 
2225661ad94SKeyon Jie 	if (size > be->max) {
223c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev,
2245661ad94SKeyon Jie 				    "error: size too big %zu bytes max is %d\n",
2255661ad94SKeyon Jie 				    size, be->max);
226c3078f53SLiam Girdwood 		return -EINVAL;
227c3078f53SLiam Girdwood 	}
228c3078f53SLiam Girdwood 
229c3078f53SLiam Girdwood 	/* copy from kcontrol */
2305661ad94SKeyon Jie 	memcpy(data, ucontrol->value.bytes.data, size);
231c3078f53SLiam Girdwood 
232c3078f53SLiam Girdwood 	/* notify DSP of byte control updates */
233*0c888babSBard Liao 	if (pm_runtime_active(sdev->dev))
234c3078f53SLiam Girdwood 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
235c3078f53SLiam Girdwood 					      SOF_IPC_COMP_SET_DATA,
236c3078f53SLiam Girdwood 					      SOF_CTRL_TYPE_DATA_SET,
237c3078f53SLiam Girdwood 					      scontrol->cmd,
238c3078f53SLiam Girdwood 					      true);
239c3078f53SLiam Girdwood 
240*0c888babSBard Liao 	return 0;
241c3078f53SLiam Girdwood }
242c3078f53SLiam Girdwood 
243c3078f53SLiam Girdwood int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
244c3078f53SLiam Girdwood 			  const unsigned int __user *binary_data,
245c3078f53SLiam Girdwood 			  unsigned int size)
246c3078f53SLiam Girdwood {
247c3078f53SLiam Girdwood 	struct soc_bytes_ext *be =
248c3078f53SLiam Girdwood 		(struct soc_bytes_ext *)kcontrol->private_value;
249c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
250c3078f53SLiam Girdwood 	struct snd_sof_dev *sdev = scontrol->sdev;
251c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
252c3078f53SLiam Girdwood 	struct snd_ctl_tlv header;
253c3078f53SLiam Girdwood 	const struct snd_ctl_tlv __user *tlvd =
254c3078f53SLiam Girdwood 		(const struct snd_ctl_tlv __user *)binary_data;
255c3078f53SLiam Girdwood 
256c3078f53SLiam Girdwood 	/*
257c3078f53SLiam Girdwood 	 * The beginning of bytes data contains a header from where
258c3078f53SLiam Girdwood 	 * the length (as bytes) is needed to know the correct copy
259c3078f53SLiam Girdwood 	 * length of data from tlvd->tlv.
260c3078f53SLiam Girdwood 	 */
261c3078f53SLiam Girdwood 	if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv)))
262c3078f53SLiam Girdwood 		return -EFAULT;
263c3078f53SLiam Girdwood 
264c3078f53SLiam Girdwood 	/* be->max is coming from topology */
265c3078f53SLiam Girdwood 	if (header.length > be->max) {
266c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n",
267c3078f53SLiam Girdwood 				    header.length, be->max);
268c3078f53SLiam Girdwood 		return -EINVAL;
269c3078f53SLiam Girdwood 	}
270c3078f53SLiam Girdwood 
271c3078f53SLiam Girdwood 	/* Check that header id matches the command */
272c3078f53SLiam Girdwood 	if (header.numid != scontrol->cmd) {
273c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev,
274c3078f53SLiam Girdwood 				    "error: incorrect numid %d\n",
275c3078f53SLiam Girdwood 				    header.numid);
276c3078f53SLiam Girdwood 		return -EINVAL;
277c3078f53SLiam Girdwood 	}
278c3078f53SLiam Girdwood 
279c3078f53SLiam Girdwood 	if (copy_from_user(cdata->data, tlvd->tlv, header.length))
280c3078f53SLiam Girdwood 		return -EFAULT;
281c3078f53SLiam Girdwood 
282c3078f53SLiam Girdwood 	if (cdata->data->magic != SOF_ABI_MAGIC) {
283c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev,
284c3078f53SLiam Girdwood 				    "error: Wrong ABI magic 0x%08x.\n",
285c3078f53SLiam Girdwood 				    cdata->data->magic);
286c3078f53SLiam Girdwood 		return -EINVAL;
287c3078f53SLiam Girdwood 	}
288c3078f53SLiam Girdwood 
289c3078f53SLiam Girdwood 	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
290c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n",
291c3078f53SLiam Girdwood 				    cdata->data->abi);
292c3078f53SLiam Girdwood 		return -EINVAL;
293c3078f53SLiam Girdwood 	}
294c3078f53SLiam Girdwood 
295c3078f53SLiam Girdwood 	if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) {
296c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n");
297c3078f53SLiam Girdwood 		return -EINVAL;
298c3078f53SLiam Girdwood 	}
299c3078f53SLiam Girdwood 
300c3078f53SLiam Girdwood 	/* notify DSP of byte control updates */
301*0c888babSBard Liao 	if (pm_runtime_active(sdev->dev))
302c3078f53SLiam Girdwood 		snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
303c3078f53SLiam Girdwood 					      SOF_IPC_COMP_SET_DATA,
304c3078f53SLiam Girdwood 					      SOF_CTRL_TYPE_DATA_SET,
305c3078f53SLiam Girdwood 					      scontrol->cmd,
306c3078f53SLiam Girdwood 					      true);
307c3078f53SLiam Girdwood 
308*0c888babSBard Liao 	return 0;
309c3078f53SLiam Girdwood }
310c3078f53SLiam Girdwood 
311c3078f53SLiam Girdwood int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
312c3078f53SLiam Girdwood 			  unsigned int __user *binary_data,
313c3078f53SLiam Girdwood 			  unsigned int size)
314c3078f53SLiam Girdwood {
315c3078f53SLiam Girdwood 	struct soc_bytes_ext *be =
316c3078f53SLiam Girdwood 		(struct soc_bytes_ext *)kcontrol->private_value;
317c3078f53SLiam Girdwood 	struct snd_sof_control *scontrol = be->dobj.private;
318c3078f53SLiam Girdwood 	struct snd_sof_dev *sdev = scontrol->sdev;
319c3078f53SLiam Girdwood 	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
320c3078f53SLiam Girdwood 	struct snd_ctl_tlv header;
321c3078f53SLiam Girdwood 	struct snd_ctl_tlv __user *tlvd =
322c3078f53SLiam Girdwood 		(struct snd_ctl_tlv __user *)binary_data;
323c3078f53SLiam Girdwood 	int data_size;
324*0c888babSBard Liao 	int ret = 0;
325c3078f53SLiam Girdwood 
326c3078f53SLiam Girdwood 	/*
327c3078f53SLiam Girdwood 	 * Decrement the limit by ext bytes header size to
328c3078f53SLiam Girdwood 	 * ensure the user space buffer is not exceeded.
329c3078f53SLiam Girdwood 	 */
330c3078f53SLiam Girdwood 	size -= sizeof(const struct snd_ctl_tlv);
331c3078f53SLiam Girdwood 
332c3078f53SLiam Girdwood 	/* set the ABI header values */
333c3078f53SLiam Girdwood 	cdata->data->magic = SOF_ABI_MAGIC;
334c3078f53SLiam Girdwood 	cdata->data->abi = SOF_ABI_VERSION;
335c3078f53SLiam Girdwood 
336c3078f53SLiam Girdwood 	/* Prevent read of other kernel data or possibly corrupt response */
337c3078f53SLiam Girdwood 	data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
338c3078f53SLiam Girdwood 
339c3078f53SLiam Girdwood 	/* check data size doesn't exceed max coming from topology */
340c3078f53SLiam Girdwood 	if (data_size > be->max) {
341c3078f53SLiam Girdwood 		dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n",
342c3078f53SLiam Girdwood 				    data_size, be->max);
343c3078f53SLiam Girdwood 		ret = -EINVAL;
344c3078f53SLiam Girdwood 		goto out;
345c3078f53SLiam Girdwood 	}
346c3078f53SLiam Girdwood 
347c3078f53SLiam Girdwood 	header.numid = scontrol->cmd;
348c3078f53SLiam Girdwood 	header.length = data_size;
349c3078f53SLiam Girdwood 	if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) {
350c3078f53SLiam Girdwood 		ret = -EFAULT;
351c3078f53SLiam Girdwood 		goto out;
352c3078f53SLiam Girdwood 	}
353c3078f53SLiam Girdwood 
354c3078f53SLiam Girdwood 	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
355c3078f53SLiam Girdwood 		ret = -EFAULT;
356c3078f53SLiam Girdwood 
357c3078f53SLiam Girdwood out:
358c3078f53SLiam Girdwood 	return ret;
359c3078f53SLiam Girdwood }
360