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