Skip to content

Commit 2a28b52

Browse files
ujfalusibroonie
authored andcommitted
ASoC: SOF: ipc4-control: Add support for generic bytes control
The generic byte control can be used in cases when the bytes data can be changed by the firmware and it sends a notification about the change, similarly to the enum and switch controls. The generic control support is needed as from the param_id itself it is not possible to know which control has changed. The needed information is only available via generic control change notification. Generic bytes controls use param_id 202 and their change notification can contain payload with the change embedded or just the header message as notification. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Link: https://patch.msgid.link/20251217143945.2667-9-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 7fd8c21 commit 2a28b52

File tree

1 file changed

+142
-14
lines changed

1 file changed

+142
-14
lines changed

sound/soc/sof/ipc4-control.c

Lines changed: 142 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,105 @@ static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol)
284284
kfree(data);
285285
}
286286

287+
static int
288+
sof_ipc4_set_bytes_control_data(struct snd_sof_control *scontrol, bool lock)
289+
{
290+
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
291+
struct snd_soc_component *scomp = scontrol->scomp;
292+
struct sof_ipc4_control_msg_payload *msg_data;
293+
struct sof_abi_hdr *data = cdata->data;
294+
struct sof_ipc4_msg *msg = &cdata->msg;
295+
size_t data_size;
296+
int ret;
297+
298+
data_size = struct_size(msg_data, data, data->size);
299+
msg_data = kzalloc(data_size, GFP_KERNEL);
300+
if (!msg_data)
301+
return -ENOMEM;
302+
303+
msg_data->id = cdata->index;
304+
msg_data->num_elems = data->size;
305+
memcpy(msg_data->data, data->data, data->size);
306+
307+
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
308+
309+
msg->data_ptr = msg_data;
310+
msg->data_size = data_size;
311+
312+
ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
313+
msg->data_ptr = NULL;
314+
msg->data_size = 0;
315+
if (ret < 0)
316+
dev_err(scomp->dev, "%s: Failed to set control update for %s\n",
317+
__func__, scontrol->name);
318+
319+
kfree(msg_data);
320+
321+
return ret;
322+
}
323+
324+
static int
325+
sof_ipc4_refresh_bytes_control(struct snd_sof_control *scontrol, bool lock)
326+
{
327+
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
328+
struct snd_soc_component *scomp = scontrol->scomp;
329+
struct sof_ipc4_control_msg_payload *msg_data;
330+
struct sof_abi_hdr *data = cdata->data;
331+
struct sof_ipc4_msg *msg = &cdata->msg;
332+
size_t data_size;
333+
int ret = 0;
334+
335+
if (!scontrol->comp_data_dirty)
336+
return 0;
337+
338+
if (!pm_runtime_active(scomp->dev))
339+
return 0;
340+
341+
data_size = scontrol->max_size - sizeof(*data);
342+
if (data_size < sizeof(*msg_data))
343+
data_size = sizeof(*msg_data);
344+
345+
msg_data = kzalloc(data_size, GFP_KERNEL);
346+
if (!msg_data)
347+
return -ENOMEM;
348+
349+
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
350+
351+
msg_data->id = cdata->index;
352+
msg_data->num_elems = 0; /* ignored for bytes */
353+
354+
msg->data_ptr = msg_data;
355+
msg->data_size = data_size;
356+
357+
scontrol->comp_data_dirty = false;
358+
ret = sof_ipc4_set_get_kcontrol_data(scontrol, false, lock);
359+
if (!ret) {
360+
if (msg->data_size > scontrol->max_size - sizeof(*data)) {
361+
dev_err(scomp->dev,
362+
"%s: no space for data in %s (%zu, %zu)\n",
363+
__func__, scontrol->name, msg->data_size,
364+
scontrol->max_size - sizeof(*data));
365+
goto out;
366+
}
367+
368+
data->size = msg->data_size;
369+
scontrol->size = sizeof(*cdata) + sizeof(*data) + data->size;
370+
memcpy(data->data, msg->data_ptr, data->size);
371+
} else {
372+
dev_err(scomp->dev, "Failed to read control data for %s\n",
373+
scontrol->name);
374+
scontrol->comp_data_dirty = true;
375+
}
376+
377+
out:
378+
msg->data_ptr = NULL;
379+
msg->data_size = 0;
380+
381+
kfree(msg_data);
382+
383+
return ret;
384+
}
385+
287386
static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol,
288387
struct snd_ctl_elem_value *ucontrol)
289388
{
@@ -423,6 +522,13 @@ static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
423522
}
424523
}
425524

525+
if (data->type == SOF_IPC4_BYTES_CONTROL_PARAM_ID) {
526+
if (set)
527+
return sof_ipc4_set_bytes_control_data(scontrol, lock);
528+
else
529+
return sof_ipc4_refresh_bytes_control(scontrol, lock);
530+
}
531+
426532
msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type);
427533

428534
msg->data_ptr = data->data;
@@ -507,6 +613,8 @@ static int sof_ipc4_bytes_get(struct snd_sof_control *scontrol,
507613
return -EINVAL;
508614
}
509615

616+
sof_ipc4_refresh_bytes_control(scontrol, true);
617+
510618
size = data->size + sizeof(*data);
511619

512620
/* copy back to kcontrol */
@@ -661,6 +769,8 @@ static int sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
661769
const unsigned int __user *binary_data,
662770
unsigned int size)
663771
{
772+
sof_ipc4_refresh_bytes_control(scontrol, true);
773+
664774
return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, false);
665775
}
666776

@@ -714,6 +824,9 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
714824
case SOF_IPC4_ENUM_CONTROL_PARAM_ID:
715825
type = SND_SOC_TPLG_TYPE_ENUM;
716826
break;
827+
case SOF_IPC4_BYTES_CONTROL_PARAM_ID:
828+
type = SND_SOC_TPLG_TYPE_BYTES;
829+
break;
717830
default:
718831
dev_err(sdev->dev,
719832
"%s: Invalid control type for module %u.%u: %u\n",
@@ -764,23 +877,38 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
764877
* The message includes the updated value/data, update the
765878
* control's local cache using the received notification
766879
*/
767-
for (i = 0; i < msg_data->num_elems; i++) {
768-
u32 channel = msg_data->chanv[i].channel;
880+
if (type == SND_SOC_TPLG_TYPE_BYTES) {
881+
struct sof_abi_hdr *data = cdata->data;
769882

770-
if (channel >= scontrol->num_channels) {
883+
if (msg_data->num_elems > scontrol->max_size - sizeof(*data)) {
771884
dev_warn(sdev->dev,
772-
"Invalid channel index for %s: %u\n",
773-
scontrol->name, i);
774-
775-
/*
776-
* Mark the scontrol as dirty to force a refresh
777-
* on next read
778-
*/
779-
scontrol->comp_data_dirty = true;
780-
break;
885+
"%s: no space for data in %s (%u, %zu)\n",
886+
__func__, scontrol->name, msg_data->num_elems,
887+
scontrol->max_size - sizeof(*data));
888+
} else {
889+
memcpy(data->data, msg_data->data, msg_data->num_elems);
890+
data->size = msg_data->num_elems;
891+
scontrol->size = sizeof(*cdata) + sizeof(*data) + data->size;
892+
}
893+
} else {
894+
for (i = 0; i < msg_data->num_elems; i++) {
895+
u32 channel = msg_data->chanv[i].channel;
896+
897+
if (channel >= scontrol->num_channels) {
898+
dev_warn(sdev->dev,
899+
"Invalid channel index for %s: %u\n",
900+
scontrol->name, i);
901+
902+
/*
903+
* Mark the scontrol as dirty to force a refresh
904+
* on next read
905+
*/
906+
scontrol->comp_data_dirty = true;
907+
break;
908+
}
909+
910+
cdata->chanv[channel].value = msg_data->chanv[i].value;
781911
}
782-
783-
cdata->chanv[channel].value = msg_data->chanv[i].value;
784912
}
785913
} else {
786914
/*

0 commit comments

Comments
 (0)