1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2021 Intel Corporation. All rights reserved. 7 // 8 // 9 10 #include "sof-priv.h" 11 #include "sof-audio.h" 12 #include "ipc3-priv.h" 13 14 /* IPC set()/get() for kcontrols. */ 15 static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, 16 bool set, bool lock) 17 { 18 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp); 19 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 20 const struct sof_ipc_ops *iops = sdev->ipc->ops; 21 enum sof_ipc_ctrl_type ctrl_type; 22 struct snd_sof_widget *swidget; 23 bool widget_found = false; 24 u32 ipc_cmd, msg_bytes; 25 int ret = 0; 26 27 list_for_each_entry(swidget, &sdev->widget_list, list) { 28 if (swidget->comp_id == scontrol->comp_id) { 29 widget_found = true; 30 break; 31 } 32 } 33 34 if (!widget_found) { 35 dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__, 36 scontrol->comp_id); 37 return -EINVAL; 38 } 39 40 if (lock) 41 mutex_lock(&swidget->setup_mutex); 42 else 43 lockdep_assert_held(&swidget->setup_mutex); 44 45 /* 46 * Volatile controls should always be part of static pipelines and the 47 * widget use_count would always be > 0 in this case. For the others, 48 * just return the cached value if the widget is not set up. 49 */ 50 if (!swidget->use_count) 51 goto unlock; 52 53 /* 54 * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the 55 * direction 56 * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently 57 * for ctrl_type 58 */ 59 if (cdata->cmd == SOF_CTRL_CMD_BINARY) { 60 ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA; 61 ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET; 62 } else { 63 ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE; 64 ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET; 65 } 66 67 cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; 68 cdata->type = ctrl_type; 69 cdata->comp_id = scontrol->comp_id; 70 cdata->msg_index = 0; 71 72 /* calculate header and data size */ 73 switch (cdata->type) { 74 case SOF_CTRL_TYPE_VALUE_CHAN_GET: 75 case SOF_CTRL_TYPE_VALUE_CHAN_SET: 76 cdata->num_elems = scontrol->num_channels; 77 78 msg_bytes = scontrol->num_channels * 79 sizeof(struct sof_ipc_ctrl_value_chan); 80 msg_bytes += sizeof(struct sof_ipc_ctrl_data); 81 break; 82 case SOF_CTRL_TYPE_DATA_GET: 83 case SOF_CTRL_TYPE_DATA_SET: 84 cdata->num_elems = cdata->data->size; 85 86 msg_bytes = cdata->data->size; 87 msg_bytes += sizeof(struct sof_ipc_ctrl_data) + 88 sizeof(struct sof_abi_hdr); 89 break; 90 default: 91 ret = -EINVAL; 92 goto unlock; 93 } 94 95 cdata->rhdr.hdr.size = msg_bytes; 96 cdata->elems_remaining = 0; 97 98 ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); 99 100 unlock: 101 if (lock) 102 mutex_unlock(&swidget->setup_mutex); 103 104 return ret; 105 } 106 107 static void sof_ipc3_refresh_control(struct snd_sof_control *scontrol) 108 { 109 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 110 struct snd_soc_component *scomp = scontrol->scomp; 111 int ret; 112 113 if (!scontrol->comp_data_dirty) 114 return; 115 116 if (!pm_runtime_active(scomp->dev)) 117 return; 118 119 /* set the ABI header values */ 120 cdata->data->magic = SOF_ABI_MAGIC; 121 cdata->data->abi = SOF_ABI_VERSION; 122 123 /* refresh the component data from DSP */ 124 scontrol->comp_data_dirty = false; 125 ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, true); 126 if (ret < 0) { 127 dev_err(scomp->dev, "Failed to get control data: %d\n", ret); 128 129 /* Set the flag to re-try next time to get the data */ 130 scontrol->comp_data_dirty = true; 131 } 132 } 133 134 static int sof_ipc3_volume_get(struct snd_sof_control *scontrol, 135 struct snd_ctl_elem_value *ucontrol) 136 { 137 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 138 unsigned int channels = scontrol->num_channels; 139 unsigned int i; 140 141 sof_ipc3_refresh_control(scontrol); 142 143 /* read back each channel */ 144 for (i = 0; i < channels; i++) 145 ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value, 146 scontrol->volume_table, 147 scontrol->max + 1); 148 149 return 0; 150 } 151 152 static bool sof_ipc3_volume_put(struct snd_sof_control *scontrol, 153 struct snd_ctl_elem_value *ucontrol) 154 { 155 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 156 struct snd_soc_component *scomp = scontrol->scomp; 157 unsigned int channels = scontrol->num_channels; 158 unsigned int i; 159 bool change = false; 160 161 /* update each channel */ 162 for (i = 0; i < channels; i++) { 163 u32 value = mixer_to_ipc(ucontrol->value.integer.value[i], 164 scontrol->volume_table, scontrol->max + 1); 165 166 change = change || (value != cdata->chanv[i].value); 167 cdata->chanv[i].channel = i; 168 cdata->chanv[i].value = value; 169 } 170 171 /* notify DSP of mixer updates */ 172 if (pm_runtime_active(scomp->dev)) { 173 int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true); 174 175 if (ret < 0) { 176 dev_err(scomp->dev, "Failed to set mixer updates for %s\n", 177 scontrol->name); 178 return false; 179 } 180 } 181 182 return change; 183 } 184 185 static int sof_ipc3_switch_get(struct snd_sof_control *scontrol, 186 struct snd_ctl_elem_value *ucontrol) 187 { 188 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 189 unsigned int channels = scontrol->num_channels; 190 unsigned int i; 191 192 sof_ipc3_refresh_control(scontrol); 193 194 /* read back each channel */ 195 for (i = 0; i < channels; i++) 196 ucontrol->value.integer.value[i] = cdata->chanv[i].value; 197 198 return 0; 199 } 200 201 static bool sof_ipc3_switch_put(struct snd_sof_control *scontrol, 202 struct snd_ctl_elem_value *ucontrol) 203 { 204 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 205 struct snd_soc_component *scomp = scontrol->scomp; 206 unsigned int channels = scontrol->num_channels; 207 unsigned int i; 208 bool change = false; 209 u32 value; 210 211 /* update each channel */ 212 for (i = 0; i < channels; i++) { 213 value = ucontrol->value.integer.value[i]; 214 change = change || (value != cdata->chanv[i].value); 215 cdata->chanv[i].channel = i; 216 cdata->chanv[i].value = value; 217 } 218 219 /* notify DSP of mixer updates */ 220 if (pm_runtime_active(scomp->dev)) { 221 int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true); 222 223 if (ret < 0) { 224 dev_err(scomp->dev, "Failed to set mixer updates for %s\n", 225 scontrol->name); 226 return false; 227 } 228 } 229 230 return change; 231 } 232 233 static int sof_ipc3_enum_get(struct snd_sof_control *scontrol, 234 struct snd_ctl_elem_value *ucontrol) 235 { 236 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 237 unsigned int channels = scontrol->num_channels; 238 unsigned int i; 239 240 sof_ipc3_refresh_control(scontrol); 241 242 /* read back each channel */ 243 for (i = 0; i < channels; i++) 244 ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; 245 246 return 0; 247 } 248 249 static bool sof_ipc3_enum_put(struct snd_sof_control *scontrol, 250 struct snd_ctl_elem_value *ucontrol) 251 { 252 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 253 struct snd_soc_component *scomp = scontrol->scomp; 254 unsigned int channels = scontrol->num_channels; 255 unsigned int i; 256 bool change = false; 257 u32 value; 258 259 /* update each channel */ 260 for (i = 0; i < channels; i++) { 261 value = ucontrol->value.enumerated.item[i]; 262 change = change || (value != cdata->chanv[i].value); 263 cdata->chanv[i].channel = i; 264 cdata->chanv[i].value = value; 265 } 266 267 /* notify DSP of enum updates */ 268 if (pm_runtime_active(scomp->dev)) { 269 int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, true); 270 271 if (ret < 0) { 272 dev_err(scomp->dev, "Failed to set enum updates for %s\n", 273 scontrol->name); 274 return false; 275 } 276 } 277 278 return change; 279 } 280 281 static int sof_ipc3_bytes_get(struct snd_sof_control *scontrol, 282 struct snd_ctl_elem_value *ucontrol) 283 { 284 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 285 struct snd_soc_component *scomp = scontrol->scomp; 286 struct sof_abi_hdr *data = cdata->data; 287 size_t size; 288 289 sof_ipc3_refresh_control(scontrol); 290 291 if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) { 292 dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n", 293 scontrol->max_size); 294 return -EINVAL; 295 } 296 297 /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ 298 if (data->size > scontrol->max_size - sizeof(*data)) { 299 dev_err_ratelimited(scomp->dev, 300 "%u bytes of control data is invalid, max is %zu\n", 301 data->size, scontrol->max_size - sizeof(*data)); 302 return -EINVAL; 303 } 304 305 size = data->size + sizeof(*data); 306 307 /* copy back to kcontrol */ 308 memcpy(ucontrol->value.bytes.data, data, size); 309 310 return 0; 311 } 312 313 static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol, 314 struct snd_ctl_elem_value *ucontrol) 315 { 316 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 317 struct snd_soc_component *scomp = scontrol->scomp; 318 struct sof_abi_hdr *data = cdata->data; 319 size_t size; 320 321 if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) { 322 dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n", 323 scontrol->max_size); 324 return -EINVAL; 325 } 326 327 /* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */ 328 if (data->size > scontrol->max_size - sizeof(*data)) { 329 dev_err_ratelimited(scomp->dev, "data size too big %u bytes max is %zu\n", 330 data->size, scontrol->max_size - sizeof(*data)); 331 return -EINVAL; 332 } 333 334 size = data->size + sizeof(*data); 335 336 /* copy from kcontrol */ 337 memcpy(data, ucontrol->value.bytes.data, size); 338 339 /* notify DSP of byte control updates */ 340 if (pm_runtime_active(scomp->dev)) 341 return sof_ipc3_set_get_kcontrol_data(scontrol, true, true); 342 343 return 0; 344 } 345 346 static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol, 347 const unsigned int __user *binary_data, 348 unsigned int size) 349 { 350 const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data; 351 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 352 struct snd_soc_component *scomp = scontrol->scomp; 353 struct snd_ctl_tlv header; 354 355 /* 356 * The beginning of bytes data contains a header from where 357 * the length (as bytes) is needed to know the correct copy 358 * length of data from tlvd->tlv. 359 */ 360 if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv))) 361 return -EFAULT; 362 363 /* make sure TLV info is consistent */ 364 if (header.length + sizeof(struct snd_ctl_tlv) > size) { 365 dev_err_ratelimited(scomp->dev, "Inconsistent TLV, data %d + header %zu > %d\n", 366 header.length, sizeof(struct snd_ctl_tlv), size); 367 return -EINVAL; 368 } 369 370 /* be->max is coming from topology */ 371 if (header.length > scontrol->max_size) { 372 dev_err_ratelimited(scomp->dev, "Bytes data size %d exceeds max %zu\n", 373 header.length, scontrol->max_size); 374 return -EINVAL; 375 } 376 377 /* Check that header id matches the command */ 378 if (header.numid != cdata->cmd) { 379 dev_err_ratelimited(scomp->dev, "Incorrect command for bytes put %d\n", 380 header.numid); 381 return -EINVAL; 382 } 383 384 if (copy_from_user(cdata->data, tlvd->tlv, header.length)) 385 return -EFAULT; 386 387 if (cdata->data->magic != SOF_ABI_MAGIC) { 388 dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic); 389 return -EINVAL; 390 } 391 392 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { 393 dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n", 394 cdata->data->abi); 395 return -EINVAL; 396 } 397 398 /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ 399 if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) { 400 dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n"); 401 return -EINVAL; 402 } 403 404 /* notify DSP of byte control updates */ 405 if (pm_runtime_active(scomp->dev)) 406 return sof_ipc3_set_get_kcontrol_data(scontrol, true, true); 407 408 return 0; 409 } 410 411 static int _sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol, 412 const unsigned int __user *binary_data, 413 unsigned int size, bool from_dsp) 414 { 415 struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; 416 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 417 struct snd_soc_component *scomp = scontrol->scomp; 418 struct snd_ctl_tlv header; 419 size_t data_size; 420 421 /* 422 * Decrement the limit by ext bytes header size to 423 * ensure the user space buffer is not exceeded. 424 */ 425 if (size < sizeof(struct snd_ctl_tlv)) 426 return -ENOSPC; 427 428 size -= sizeof(struct snd_ctl_tlv); 429 430 /* set the ABI header values */ 431 cdata->data->magic = SOF_ABI_MAGIC; 432 cdata->data->abi = SOF_ABI_VERSION; 433 434 /* get all the component data from DSP */ 435 if (from_dsp) { 436 int ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, true); 437 438 if (ret < 0) 439 return ret; 440 } 441 442 /* check data size doesn't exceed max coming from topology */ 443 if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) { 444 dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n", 445 cdata->data->size, 446 scontrol->max_size - sizeof(struct sof_abi_hdr)); 447 return -EINVAL; 448 } 449 450 data_size = cdata->data->size + sizeof(struct sof_abi_hdr); 451 452 /* make sure we don't exceed size provided by user space for data */ 453 if (data_size > size) 454 return -ENOSPC; 455 456 header.numid = cdata->cmd; 457 header.length = data_size; 458 if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) 459 return -EFAULT; 460 461 if (copy_to_user(tlvd->tlv, cdata->data, data_size)) 462 return -EFAULT; 463 464 return 0; 465 } 466 467 static int sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol, 468 const unsigned int __user *binary_data, unsigned int size) 469 { 470 return _sof_ipc3_bytes_ext_get(scontrol, binary_data, size, false); 471 } 472 473 static int sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control *scontrol, 474 const unsigned int __user *binary_data, 475 unsigned int size) 476 { 477 return _sof_ipc3_bytes_ext_get(scontrol, binary_data, size, true); 478 } 479 480 static void snd_sof_update_control(struct snd_sof_control *scontrol, 481 struct sof_ipc_ctrl_data *cdata) 482 { 483 struct snd_soc_component *scomp = scontrol->scomp; 484 struct sof_ipc_ctrl_data *local_cdata; 485 int i; 486 487 local_cdata = scontrol->ipc_control_data; 488 489 if (cdata->cmd == SOF_CTRL_CMD_BINARY) { 490 if (cdata->num_elems != local_cdata->data->size) { 491 dev_err(scomp->dev, "cdata binary size mismatch %u - %u\n", 492 cdata->num_elems, local_cdata->data->size); 493 return; 494 } 495 496 /* copy the new binary data */ 497 memcpy(local_cdata->data, cdata->data, cdata->num_elems); 498 } else if (cdata->num_elems != scontrol->num_channels) { 499 dev_err(scomp->dev, "cdata channel count mismatch %u - %d\n", 500 cdata->num_elems, scontrol->num_channels); 501 } else { 502 /* copy the new values */ 503 for (i = 0; i < cdata->num_elems; i++) 504 local_cdata->chanv[i].value = cdata->chanv[i].value; 505 } 506 } 507 508 static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_message) 509 { 510 struct sof_ipc_ctrl_data *cdata = ipc_control_message; 511 struct snd_soc_dapm_widget *widget; 512 struct snd_sof_control *scontrol; 513 struct snd_sof_widget *swidget; 514 struct snd_kcontrol *kc = NULL; 515 struct soc_mixer_control *sm; 516 struct soc_bytes_ext *be; 517 size_t expected_size; 518 struct soc_enum *se; 519 bool found = false; 520 int i, type; 521 522 if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET || 523 cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) { 524 dev_err(sdev->dev, "Component data is not supported in control notification\n"); 525 return; 526 } 527 528 /* Find the swidget first */ 529 list_for_each_entry(swidget, &sdev->widget_list, list) { 530 if (swidget->comp_id == cdata->comp_id) { 531 found = true; 532 break; 533 } 534 } 535 536 if (!found) 537 return; 538 539 /* Translate SOF cmd to TPLG type */ 540 switch (cdata->cmd) { 541 case SOF_CTRL_CMD_VOLUME: 542 case SOF_CTRL_CMD_SWITCH: 543 type = SND_SOC_TPLG_TYPE_MIXER; 544 break; 545 case SOF_CTRL_CMD_BINARY: 546 type = SND_SOC_TPLG_TYPE_BYTES; 547 break; 548 case SOF_CTRL_CMD_ENUM: 549 type = SND_SOC_TPLG_TYPE_ENUM; 550 break; 551 default: 552 dev_err(sdev->dev, "Unknown cmd %u in %s\n", cdata->cmd, __func__); 553 return; 554 } 555 556 widget = swidget->widget; 557 for (i = 0; i < widget->num_kcontrols; i++) { 558 /* skip non matching types or non matching indexes within type */ 559 if (widget->dobj.widget.kcontrol_type[i] == type && 560 widget->kcontrol_news[i].index == cdata->index) { 561 kc = widget->kcontrols[i]; 562 break; 563 } 564 } 565 566 if (!kc) 567 return; 568 569 switch (cdata->cmd) { 570 case SOF_CTRL_CMD_VOLUME: 571 case SOF_CTRL_CMD_SWITCH: 572 sm = (struct soc_mixer_control *)kc->private_value; 573 scontrol = sm->dobj.private; 574 break; 575 case SOF_CTRL_CMD_BINARY: 576 be = (struct soc_bytes_ext *)kc->private_value; 577 scontrol = be->dobj.private; 578 break; 579 case SOF_CTRL_CMD_ENUM: 580 se = (struct soc_enum *)kc->private_value; 581 scontrol = se->dobj.private; 582 break; 583 default: 584 return; 585 } 586 587 expected_size = sizeof(struct sof_ipc_ctrl_data); 588 switch (cdata->type) { 589 case SOF_CTRL_TYPE_VALUE_CHAN_GET: 590 case SOF_CTRL_TYPE_VALUE_CHAN_SET: 591 expected_size += cdata->num_elems * 592 sizeof(struct sof_ipc_ctrl_value_chan); 593 break; 594 case SOF_CTRL_TYPE_DATA_GET: 595 case SOF_CTRL_TYPE_DATA_SET: 596 expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr); 597 break; 598 default: 599 return; 600 } 601 602 if (cdata->rhdr.hdr.size != expected_size) { 603 dev_err(sdev->dev, "Component notification size mismatch\n"); 604 return; 605 } 606 607 if (cdata->num_elems) 608 /* 609 * The message includes the updated value/data, update the 610 * control's local cache using the received notification 611 */ 612 snd_sof_update_control(scontrol, cdata); 613 else 614 /* Mark the scontrol that the value/data is changed in SOF */ 615 scontrol->comp_data_dirty = true; 616 617 snd_ctl_notify_one(swidget->scomp->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, kc, 0); 618 } 619 620 static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, 621 struct snd_sof_widget *swidget) 622 { 623 struct snd_sof_control *scontrol; 624 int ret; 625 626 /* set up all controls for the widget */ 627 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) 628 if (scontrol->comp_id == swidget->comp_id) { 629 /* set kcontrol data in DSP */ 630 ret = sof_ipc3_set_get_kcontrol_data(scontrol, true, false); 631 if (ret < 0) { 632 dev_err(sdev->dev, 633 "kcontrol %d set up failed for widget %s\n", 634 scontrol->comp_id, swidget->widget->name); 635 return ret; 636 } 637 638 /* 639 * Read back the data from the DSP for static widgets. 640 * This is particularly useful for binary kcontrols 641 * associated with static pipeline widgets to initialize 642 * the data size to match that in the DSP. 643 */ 644 if (swidget->dynamic_pipeline_widget) 645 continue; 646 647 ret = sof_ipc3_set_get_kcontrol_data(scontrol, false, false); 648 if (ret < 0) 649 dev_warn(sdev->dev, 650 "kcontrol %d read failed for widget %s\n", 651 scontrol->comp_id, swidget->widget->name); 652 } 653 654 return 0; 655 } 656 657 static int 658 sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size) 659 { 660 int i; 661 662 /* init the volume table */ 663 scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL); 664 if (!scontrol->volume_table) 665 return -ENOMEM; 666 667 /* populate the volume table */ 668 for (i = 0; i < size ; i++) 669 scontrol->volume_table[i] = vol_compute_gain(i, tlv); 670 671 return 0; 672 } 673 674 const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = { 675 .volume_put = sof_ipc3_volume_put, 676 .volume_get = sof_ipc3_volume_get, 677 .switch_put = sof_ipc3_switch_put, 678 .switch_get = sof_ipc3_switch_get, 679 .enum_put = sof_ipc3_enum_put, 680 .enum_get = sof_ipc3_enum_get, 681 .bytes_put = sof_ipc3_bytes_put, 682 .bytes_get = sof_ipc3_bytes_get, 683 .bytes_ext_put = sof_ipc3_bytes_ext_put, 684 .bytes_ext_get = sof_ipc3_bytes_ext_get, 685 .bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get, 686 .update = sof_ipc3_control_update, 687 .widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup, 688 .set_up_volume_table = sof_ipc3_set_up_volume_table, 689 }; 690