0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "sof-priv.h"
0011 #include "sof-audio.h"
0012 #include "ipc3-priv.h"
0013
0014
0015 static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
0016 {
0017 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp);
0018 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0019 const struct sof_ipc_ops *iops = sdev->ipc->ops;
0020 enum sof_ipc_ctrl_type ctrl_type;
0021 struct snd_sof_widget *swidget;
0022 bool widget_found = false;
0023 u32 ipc_cmd, msg_bytes;
0024
0025 list_for_each_entry(swidget, &sdev->widget_list, list) {
0026 if (swidget->comp_id == scontrol->comp_id) {
0027 widget_found = true;
0028 break;
0029 }
0030 }
0031
0032 if (!widget_found) {
0033 dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__,
0034 scontrol->comp_id);
0035 return -EINVAL;
0036 }
0037
0038
0039
0040
0041
0042
0043 if (!swidget->use_count)
0044 return 0;
0045
0046
0047
0048
0049
0050
0051
0052 if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
0053 ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA;
0054 ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET;
0055 } else {
0056 ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE;
0057 ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET;
0058 }
0059
0060 cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
0061 cdata->type = ctrl_type;
0062 cdata->comp_id = scontrol->comp_id;
0063 cdata->msg_index = 0;
0064
0065
0066 switch (cdata->type) {
0067 case SOF_CTRL_TYPE_VALUE_CHAN_GET:
0068 case SOF_CTRL_TYPE_VALUE_CHAN_SET:
0069 cdata->num_elems = scontrol->num_channels;
0070
0071 msg_bytes = scontrol->num_channels *
0072 sizeof(struct sof_ipc_ctrl_value_chan);
0073 msg_bytes += sizeof(struct sof_ipc_ctrl_data);
0074 break;
0075 case SOF_CTRL_TYPE_DATA_GET:
0076 case SOF_CTRL_TYPE_DATA_SET:
0077 cdata->num_elems = cdata->data->size;
0078
0079 msg_bytes = cdata->data->size;
0080 msg_bytes += sizeof(struct sof_ipc_ctrl_data) +
0081 sizeof(struct sof_abi_hdr);
0082 break;
0083 default:
0084 return -EINVAL;
0085 }
0086
0087 cdata->rhdr.hdr.size = msg_bytes;
0088 cdata->elems_remaining = 0;
0089
0090 return iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set);
0091 }
0092
0093 static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
0094 {
0095 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0096 struct snd_soc_component *scomp = scontrol->scomp;
0097 int ret;
0098
0099 if (!scontrol->comp_data_dirty)
0100 return;
0101
0102 if (!pm_runtime_active(scomp->dev))
0103 return;
0104
0105
0106 cdata->data->magic = SOF_ABI_MAGIC;
0107 cdata->data->abi = SOF_ABI_VERSION;
0108
0109
0110 scontrol->comp_data_dirty = false;
0111 ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
0112 if (ret < 0) {
0113 dev_err(scomp->dev, "Failed to get control data: %d\n", ret);
0114
0115
0116 scontrol->comp_data_dirty = true;
0117 }
0118 }
0119
0120 static int sof_ipc3_volume_get(struct snd_sof_control *scontrol,
0121 struct snd_ctl_elem_value *ucontrol)
0122 {
0123 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0124 unsigned int channels = scontrol->num_channels;
0125 unsigned int i;
0126
0127 snd_sof_refresh_control(scontrol);
0128
0129
0130 for (i = 0; i < channels; i++)
0131 ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
0132 scontrol->volume_table,
0133 scontrol->max + 1);
0134
0135 return 0;
0136 }
0137
0138 static bool sof_ipc3_volume_put(struct snd_sof_control *scontrol,
0139 struct snd_ctl_elem_value *ucontrol)
0140 {
0141 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0142 struct snd_soc_component *scomp = scontrol->scomp;
0143 unsigned int channels = scontrol->num_channels;
0144 unsigned int i;
0145 bool change = false;
0146
0147
0148 for (i = 0; i < channels; i++) {
0149 u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
0150 scontrol->volume_table, scontrol->max + 1);
0151
0152 change = change || (value != cdata->chanv[i].value);
0153 cdata->chanv[i].channel = i;
0154 cdata->chanv[i].value = value;
0155 }
0156
0157
0158 if (pm_runtime_active(scomp->dev)) {
0159 int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
0160
0161 if (ret < 0) {
0162 dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
0163 scontrol->name);
0164 return false;
0165 }
0166 }
0167
0168 return change;
0169 }
0170
0171 static int sof_ipc3_switch_get(struct snd_sof_control *scontrol,
0172 struct snd_ctl_elem_value *ucontrol)
0173 {
0174 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0175 unsigned int channels = scontrol->num_channels;
0176 unsigned int i;
0177
0178 snd_sof_refresh_control(scontrol);
0179
0180
0181 for (i = 0; i < channels; i++)
0182 ucontrol->value.integer.value[i] = cdata->chanv[i].value;
0183
0184 return 0;
0185 }
0186
0187 static bool sof_ipc3_switch_put(struct snd_sof_control *scontrol,
0188 struct snd_ctl_elem_value *ucontrol)
0189 {
0190 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0191 struct snd_soc_component *scomp = scontrol->scomp;
0192 unsigned int channels = scontrol->num_channels;
0193 unsigned int i;
0194 bool change = false;
0195 u32 value;
0196
0197
0198 for (i = 0; i < channels; i++) {
0199 value = ucontrol->value.integer.value[i];
0200 change = change || (value != cdata->chanv[i].value);
0201 cdata->chanv[i].channel = i;
0202 cdata->chanv[i].value = value;
0203 }
0204
0205
0206 if (pm_runtime_active(scomp->dev)) {
0207 int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
0208
0209 if (ret < 0) {
0210 dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
0211 scontrol->name);
0212 return false;
0213 }
0214 }
0215
0216 return change;
0217 }
0218
0219 static int sof_ipc3_enum_get(struct snd_sof_control *scontrol,
0220 struct snd_ctl_elem_value *ucontrol)
0221 {
0222 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0223 unsigned int channels = scontrol->num_channels;
0224 unsigned int i;
0225
0226 snd_sof_refresh_control(scontrol);
0227
0228
0229 for (i = 0; i < channels; i++)
0230 ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
0231
0232 return 0;
0233 }
0234
0235 static bool sof_ipc3_enum_put(struct snd_sof_control *scontrol,
0236 struct snd_ctl_elem_value *ucontrol)
0237 {
0238 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0239 struct snd_soc_component *scomp = scontrol->scomp;
0240 unsigned int channels = scontrol->num_channels;
0241 unsigned int i;
0242 bool change = false;
0243 u32 value;
0244
0245
0246 for (i = 0; i < channels; i++) {
0247 value = ucontrol->value.enumerated.item[i];
0248 change = change || (value != cdata->chanv[i].value);
0249 cdata->chanv[i].channel = i;
0250 cdata->chanv[i].value = value;
0251 }
0252
0253
0254 if (pm_runtime_active(scomp->dev)) {
0255 int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
0256
0257 if (ret < 0) {
0258 dev_err(scomp->dev, "Failed to set enum updates for %s\n",
0259 scontrol->name);
0260 return false;
0261 }
0262 }
0263
0264 return change;
0265 }
0266
0267 static int sof_ipc3_bytes_get(struct snd_sof_control *scontrol,
0268 struct snd_ctl_elem_value *ucontrol)
0269 {
0270 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0271 struct snd_soc_component *scomp = scontrol->scomp;
0272 struct sof_abi_hdr *data = cdata->data;
0273 size_t size;
0274
0275 snd_sof_refresh_control(scontrol);
0276
0277 if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
0278 dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
0279 scontrol->max_size);
0280 return -EINVAL;
0281 }
0282
0283
0284 if (data->size > scontrol->max_size - sizeof(*data)) {
0285 dev_err_ratelimited(scomp->dev,
0286 "%u bytes of control data is invalid, max is %zu\n",
0287 data->size, scontrol->max_size - sizeof(*data));
0288 return -EINVAL;
0289 }
0290
0291 size = data->size + sizeof(*data);
0292
0293
0294 memcpy(ucontrol->value.bytes.data, data, size);
0295
0296 return 0;
0297 }
0298
0299 static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol,
0300 struct snd_ctl_elem_value *ucontrol)
0301 {
0302 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0303 struct snd_soc_component *scomp = scontrol->scomp;
0304 struct sof_abi_hdr *data = cdata->data;
0305 size_t size;
0306
0307 if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
0308 dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
0309 scontrol->max_size);
0310 return -EINVAL;
0311 }
0312
0313
0314 if (data->size > scontrol->max_size - sizeof(*data)) {
0315 dev_err_ratelimited(scomp->dev, "data size too big %u bytes max is %zu\n",
0316 data->size, scontrol->max_size - sizeof(*data));
0317 return -EINVAL;
0318 }
0319
0320 size = data->size + sizeof(*data);
0321
0322
0323 memcpy(data, ucontrol->value.bytes.data, size);
0324
0325
0326 if (pm_runtime_active(scomp->dev))
0327 return sof_ipc3_set_get_kcontrol_data(scontrol, true);
0328
0329 return 0;
0330 }
0331
0332 static int sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
0333 const unsigned int __user *binary_data, unsigned int size)
0334 {
0335 struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
0336 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0337 struct snd_soc_component *scomp = scontrol->scomp;
0338 struct snd_ctl_tlv header;
0339 size_t data_size;
0340
0341 snd_sof_refresh_control(scontrol);
0342
0343
0344
0345
0346
0347 if (size < sizeof(struct snd_ctl_tlv))
0348 return -ENOSPC;
0349
0350 size -= sizeof(struct snd_ctl_tlv);
0351
0352
0353 cdata->data->magic = SOF_ABI_MAGIC;
0354 cdata->data->abi = SOF_ABI_VERSION;
0355
0356
0357 if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
0358 dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
0359 cdata->data->size,
0360 scontrol->max_size - sizeof(struct sof_abi_hdr));
0361 return -EINVAL;
0362 }
0363
0364 data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
0365
0366
0367 if (data_size > size)
0368 return -ENOSPC;
0369
0370 header.numid = cdata->cmd;
0371 header.length = data_size;
0372 if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
0373 return -EFAULT;
0374
0375 if (copy_to_user(tlvd->tlv, cdata->data, data_size))
0376 return -EFAULT;
0377
0378 return 0;
0379 }
0380
0381 static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
0382 const unsigned int __user *binary_data,
0383 unsigned int size)
0384 {
0385 const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data;
0386 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0387 struct snd_soc_component *scomp = scontrol->scomp;
0388 struct snd_ctl_tlv header;
0389
0390
0391
0392
0393
0394
0395 if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
0396 return -EFAULT;
0397
0398
0399 if (header.length + sizeof(struct snd_ctl_tlv) > size) {
0400 dev_err_ratelimited(scomp->dev, "Inconsistent TLV, data %d + header %zu > %d\n",
0401 header.length, sizeof(struct snd_ctl_tlv), size);
0402 return -EINVAL;
0403 }
0404
0405
0406 if (header.length > scontrol->max_size) {
0407 dev_err_ratelimited(scomp->dev, "Bytes data size %d exceeds max %zu\n",
0408 header.length, scontrol->max_size);
0409 return -EINVAL;
0410 }
0411
0412
0413 if (header.numid != cdata->cmd) {
0414 dev_err_ratelimited(scomp->dev, "Incorrect command for bytes put %d\n",
0415 header.numid);
0416 return -EINVAL;
0417 }
0418
0419 if (copy_from_user(cdata->data, tlvd->tlv, header.length))
0420 return -EFAULT;
0421
0422 if (cdata->data->magic != SOF_ABI_MAGIC) {
0423 dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic);
0424 return -EINVAL;
0425 }
0426
0427 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
0428 dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n",
0429 cdata->data->abi);
0430 return -EINVAL;
0431 }
0432
0433
0434 if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
0435 dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
0436 return -EINVAL;
0437 }
0438
0439
0440 if (pm_runtime_active(scomp->dev))
0441 return sof_ipc3_set_get_kcontrol_data(scontrol, true);
0442
0443 return 0;
0444 }
0445
0446 static int sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
0447 const unsigned int __user *binary_data,
0448 unsigned int size)
0449 {
0450 struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
0451 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
0452 struct snd_soc_component *scomp = scontrol->scomp;
0453 struct snd_ctl_tlv header;
0454 size_t data_size;
0455 int ret;
0456
0457
0458
0459
0460
0461 if (size < sizeof(struct snd_ctl_tlv))
0462 return -ENOSPC;
0463
0464 size -= sizeof(struct snd_ctl_tlv);
0465
0466
0467 cdata->data->magic = SOF_ABI_MAGIC;
0468 cdata->data->abi = SOF_ABI_VERSION;
0469
0470
0471 ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
0472 if (ret < 0)
0473 return ret;
0474
0475
0476 if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
0477 dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
0478 cdata->data->size,
0479 scontrol->max_size - sizeof(struct sof_abi_hdr));
0480 return -EINVAL;
0481 }
0482
0483 data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
0484
0485
0486 if (data_size > size)
0487 return -ENOSPC;
0488
0489 header.numid = cdata->cmd;
0490 header.length = data_size;
0491 if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
0492 return -EFAULT;
0493
0494 if (copy_to_user(tlvd->tlv, cdata->data, data_size))
0495 return -EFAULT;
0496
0497 return ret;
0498 }
0499
0500 static void snd_sof_update_control(struct snd_sof_control *scontrol,
0501 struct sof_ipc_ctrl_data *cdata)
0502 {
0503 struct snd_soc_component *scomp = scontrol->scomp;
0504 struct sof_ipc_ctrl_data *local_cdata;
0505 int i;
0506
0507 local_cdata = scontrol->ipc_control_data;
0508
0509 if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
0510 if (cdata->num_elems != local_cdata->data->size) {
0511 dev_err(scomp->dev, "cdata binary size mismatch %u - %u\n",
0512 cdata->num_elems, local_cdata->data->size);
0513 return;
0514 }
0515
0516
0517 memcpy(local_cdata->data, cdata->data, cdata->num_elems);
0518 } else if (cdata->num_elems != scontrol->num_channels) {
0519 dev_err(scomp->dev, "cdata channel count mismatch %u - %d\n",
0520 cdata->num_elems, scontrol->num_channels);
0521 } else {
0522
0523 for (i = 0; i < cdata->num_elems; i++)
0524 local_cdata->chanv[i].value = cdata->chanv[i].value;
0525 }
0526 }
0527
0528 static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_message)
0529 {
0530 struct sof_ipc_ctrl_data *cdata = ipc_control_message;
0531 struct snd_soc_dapm_widget *widget;
0532 struct snd_sof_control *scontrol;
0533 struct snd_sof_widget *swidget;
0534 struct snd_kcontrol *kc = NULL;
0535 struct soc_mixer_control *sm;
0536 struct soc_bytes_ext *be;
0537 size_t expected_size;
0538 struct soc_enum *se;
0539 bool found = false;
0540 int i, type;
0541
0542 if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET ||
0543 cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) {
0544 dev_err(sdev->dev, "Component data is not supported in control notification\n");
0545 return;
0546 }
0547
0548
0549 list_for_each_entry(swidget, &sdev->widget_list, list) {
0550 if (swidget->comp_id == cdata->comp_id) {
0551 found = true;
0552 break;
0553 }
0554 }
0555
0556 if (!found)
0557 return;
0558
0559
0560 switch (cdata->cmd) {
0561 case SOF_CTRL_CMD_VOLUME:
0562 case SOF_CTRL_CMD_SWITCH:
0563 type = SND_SOC_TPLG_TYPE_MIXER;
0564 break;
0565 case SOF_CTRL_CMD_BINARY:
0566 type = SND_SOC_TPLG_TYPE_BYTES;
0567 break;
0568 case SOF_CTRL_CMD_ENUM:
0569 type = SND_SOC_TPLG_TYPE_ENUM;
0570 break;
0571 default:
0572 dev_err(sdev->dev, "Unknown cmd %u in %s\n", cdata->cmd, __func__);
0573 return;
0574 }
0575
0576 widget = swidget->widget;
0577 for (i = 0; i < widget->num_kcontrols; i++) {
0578
0579 if (widget->dobj.widget.kcontrol_type[i] == type &&
0580 widget->kcontrol_news[i].index == cdata->index) {
0581 kc = widget->kcontrols[i];
0582 break;
0583 }
0584 }
0585
0586 if (!kc)
0587 return;
0588
0589 switch (cdata->cmd) {
0590 case SOF_CTRL_CMD_VOLUME:
0591 case SOF_CTRL_CMD_SWITCH:
0592 sm = (struct soc_mixer_control *)kc->private_value;
0593 scontrol = sm->dobj.private;
0594 break;
0595 case SOF_CTRL_CMD_BINARY:
0596 be = (struct soc_bytes_ext *)kc->private_value;
0597 scontrol = be->dobj.private;
0598 break;
0599 case SOF_CTRL_CMD_ENUM:
0600 se = (struct soc_enum *)kc->private_value;
0601 scontrol = se->dobj.private;
0602 break;
0603 default:
0604 return;
0605 }
0606
0607 expected_size = sizeof(struct sof_ipc_ctrl_data);
0608 switch (cdata->type) {
0609 case SOF_CTRL_TYPE_VALUE_CHAN_GET:
0610 case SOF_CTRL_TYPE_VALUE_CHAN_SET:
0611 expected_size += cdata->num_elems *
0612 sizeof(struct sof_ipc_ctrl_value_chan);
0613 break;
0614 case SOF_CTRL_TYPE_DATA_GET:
0615 case SOF_CTRL_TYPE_DATA_SET:
0616 expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr);
0617 break;
0618 default:
0619 return;
0620 }
0621
0622 if (cdata->rhdr.hdr.size != expected_size) {
0623 dev_err(sdev->dev, "Component notification size mismatch\n");
0624 return;
0625 }
0626
0627 if (cdata->num_elems)
0628
0629
0630
0631
0632 snd_sof_update_control(scontrol, cdata);
0633 else
0634
0635 scontrol->comp_data_dirty = true;
0636
0637 snd_ctl_notify_one(swidget->scomp->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
0638 }
0639
0640 static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev,
0641 struct snd_sof_widget *swidget)
0642 {
0643 struct snd_sof_control *scontrol;
0644 int ret;
0645
0646
0647 list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
0648 if (scontrol->comp_id == swidget->comp_id) {
0649
0650 ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
0651 if (ret < 0) {
0652 dev_err(sdev->dev,
0653 "kcontrol %d set up failed for widget %s\n",
0654 scontrol->comp_id, swidget->widget->name);
0655 return ret;
0656 }
0657
0658
0659
0660
0661
0662
0663
0664 if (swidget->dynamic_pipeline_widget)
0665 continue;
0666
0667 ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
0668 if (ret < 0)
0669 dev_warn(sdev->dev,
0670 "kcontrol %d read failed for widget %s\n",
0671 scontrol->comp_id, swidget->widget->name);
0672 }
0673
0674 return 0;
0675 }
0676
0677 static int
0678 sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
0679 {
0680 int i;
0681
0682
0683 scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
0684 if (!scontrol->volume_table)
0685 return -ENOMEM;
0686
0687
0688 for (i = 0; i < size ; i++)
0689 scontrol->volume_table[i] = vol_compute_gain(i, tlv);
0690
0691 return 0;
0692 }
0693
0694 const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
0695 .volume_put = sof_ipc3_volume_put,
0696 .volume_get = sof_ipc3_volume_get,
0697 .switch_put = sof_ipc3_switch_put,
0698 .switch_get = sof_ipc3_switch_get,
0699 .enum_put = sof_ipc3_enum_put,
0700 .enum_get = sof_ipc3_enum_get,
0701 .bytes_put = sof_ipc3_bytes_put,
0702 .bytes_get = sof_ipc3_bytes_get,
0703 .bytes_ext_put = sof_ipc3_bytes_ext_put,
0704 .bytes_ext_get = sof_ipc3_bytes_ext_get,
0705 .bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get,
0706 .update = sof_ipc3_control_update,
0707 .widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup,
0708 .set_up_volume_table = sof_ipc3_set_up_volume_table,
0709 };