1 // SPDX-License-Identifier: (GPL-2.0-only OR B 1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 2 // 3 // This file is provided under a dual BSD/GPLv 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so und 4 // redistributing this file, you may do so under either license. 5 // 5 // 6 // Copyright(c) 2022 Intel Corporation !! 6 // Copyright(c) 2022 Intel Corporation. All rights reserved. 7 // 7 // 8 // 8 // 9 9 10 #include "sof-priv.h" 10 #include "sof-priv.h" 11 #include "sof-audio.h" 11 #include "sof-audio.h" 12 #include "ipc4-priv.h" 12 #include "ipc4-priv.h" 13 #include "ipc4-topology.h" 13 #include "ipc4-topology.h" 14 14 15 static int sof_ipc4_set_get_kcontrol_data(stru !! 15 static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set) 16 bool << 17 { 16 { 18 struct sof_ipc4_control_data *cdata = 17 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 19 struct snd_soc_component *scomp = scon 18 struct snd_soc_component *scomp = scontrol->scomp; 20 struct snd_sof_dev *sdev = snd_soc_com 19 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 21 const struct sof_ipc_ops *iops = sdev- 20 const struct sof_ipc_ops *iops = sdev->ipc->ops; 22 struct sof_ipc4_msg *msg = &cdata->msg 21 struct sof_ipc4_msg *msg = &cdata->msg; 23 struct snd_sof_widget *swidget; 22 struct snd_sof_widget *swidget; 24 bool widget_found = false; 23 bool widget_found = false; 25 int ret = 0; << 26 24 27 /* find widget associated with the con 25 /* find widget associated with the control */ 28 list_for_each_entry(swidget, &sdev->wi 26 list_for_each_entry(swidget, &sdev->widget_list, list) { 29 if (swidget->comp_id == scontr 27 if (swidget->comp_id == scontrol->comp_id) { 30 widget_found = true; 28 widget_found = true; 31 break; 29 break; 32 } 30 } 33 } 31 } 34 32 35 if (!widget_found) { 33 if (!widget_found) { 36 dev_err(scomp->dev, "Failed to 34 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name); 37 return -ENOENT; 35 return -ENOENT; 38 } 36 } 39 37 40 if (lock) << 41 mutex_lock(&swidget->setup_mut << 42 else << 43 lockdep_assert_held(&swidget-> << 44 << 45 /* 38 /* 46 * Volatile controls should always be !! 39 * Volatile controls should always be part of static pipelines and the widget use_count 47 * widget use_count would always be > !! 40 * would always be > 0 in this case. For the others, just return the cached value if the 48 * just return the cached value if the !! 41 * widget is not set up. 49 */ 42 */ 50 if (!swidget->use_count) 43 if (!swidget->use_count) 51 goto unlock; !! 44 return 0; 52 45 53 msg->primary &= ~SOF_IPC4_MOD_INSTANCE 46 msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; 54 msg->primary |= SOF_IPC4_MOD_INSTANCE( 47 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); 55 48 56 ret = iops->set_get_data(sdev, msg, ms !! 49 return iops->set_get_data(sdev, msg, msg->data_size, set); 57 if (!set) << 58 goto unlock; << 59 << 60 /* It is a set-data operation, and we << 61 if (ret < 0) { << 62 if (!scontrol->old_ipc_control << 63 goto unlock; << 64 /* << 65 * Current ipc_control_data is << 66 * configuration << 67 */ << 68 memcpy(scontrol->ipc_control_d << 69 scontrol->max_size); << 70 kfree(scontrol->old_ipc_contro << 71 scontrol->old_ipc_control_data << 72 /* Send the last known good co << 73 ret = iops->set_get_data(sdev, << 74 if (ret < 0) << 75 goto unlock; << 76 } << 77 << 78 unlock: << 79 if (lock) << 80 mutex_unlock(&swidget->setup_m << 81 << 82 return ret; << 83 } 50 } 84 51 85 static int 52 static int 86 sof_ipc4_set_volume_data(struct snd_sof_dev *s 53 sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 87 struct snd_sof_contro !! 54 struct snd_sof_control *scontrol) 88 { 55 { 89 struct sof_ipc4_control_data *cdata = 56 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 90 struct sof_ipc4_gain *gain = swidget-> 57 struct sof_ipc4_gain *gain = swidget->private; 91 struct sof_ipc4_msg *msg = &cdata->msg 58 struct sof_ipc4_msg *msg = &cdata->msg; 92 struct sof_ipc4_gain_params params; !! 59 struct sof_ipc4_gain_data data; 93 bool all_channels_equal = true; 60 bool all_channels_equal = true; 94 u32 value; 61 u32 value; 95 int ret, i; 62 int ret, i; 96 63 97 /* check if all channel values are equ 64 /* check if all channel values are equal */ 98 value = cdata->chanv[0].value; 65 value = cdata->chanv[0].value; 99 for (i = 1; i < scontrol->num_channels 66 for (i = 1; i < scontrol->num_channels; i++) { 100 if (cdata->chanv[i].value != v 67 if (cdata->chanv[i].value != value) { 101 all_channels_equal = f 68 all_channels_equal = false; 102 break; 69 break; 103 } 70 } 104 } 71 } 105 72 106 /* 73 /* 107 * notify DSP with a single IPC messag 74 * notify DSP with a single IPC message if all channel values are equal. Otherwise send 108 * a separate IPC for each channel. 75 * a separate IPC for each channel. 109 */ 76 */ 110 for (i = 0; i < scontrol->num_channels 77 for (i = 0; i < scontrol->num_channels; i++) { 111 if (all_channels_equal) { 78 if (all_channels_equal) { 112 params.channels = SOF_ !! 79 data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK; 113 params.init_val = cdat !! 80 data.init_val = cdata->chanv[0].value; 114 } else { 81 } else { 115 params.channels = cdat !! 82 data.channels = cdata->chanv[i].channel; 116 params.init_val = cdat !! 83 data.init_val = cdata->chanv[i].value; 117 } 84 } 118 85 119 /* set curve type and duration 86 /* set curve type and duration from topology */ 120 params.curve_duration_l = gain !! 87 data.curve_duration = gain->data.curve_duration; 121 params.curve_duration_h = gain !! 88 data.curve_type = gain->data.curve_type; 122 params.curve_type = gain->data << 123 89 124 msg->data_ptr = ¶ms; !! 90 msg->data_ptr = &data; 125 msg->data_size = sizeof(params !! 91 msg->data_size = sizeof(data); 126 92 127 ret = sof_ipc4_set_get_kcontro !! 93 ret = sof_ipc4_set_get_kcontrol_data(scontrol, true); 128 msg->data_ptr = NULL; 94 msg->data_ptr = NULL; 129 msg->data_size = 0; 95 msg->data_size = 0; 130 if (ret < 0) { 96 if (ret < 0) { 131 dev_err(sdev->dev, "Fa 97 dev_err(sdev->dev, "Failed to set volume update for %s\n", 132 scontrol->name 98 scontrol->name); 133 return ret; 99 return ret; 134 } 100 } 135 101 136 if (all_channels_equal) 102 if (all_channels_equal) 137 break; 103 break; 138 } 104 } 139 105 140 return 0; 106 return 0; 141 } 107 } 142 108 143 static bool sof_ipc4_volume_put(struct snd_sof 109 static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol, 144 struct snd_ctl 110 struct snd_ctl_elem_value *ucontrol) 145 { 111 { 146 struct sof_ipc4_control_data *cdata = 112 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 147 struct snd_soc_component *scomp = scon 113 struct snd_soc_component *scomp = scontrol->scomp; 148 struct snd_sof_dev *sdev = snd_soc_com 114 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 149 unsigned int channels = scontrol->num_ 115 unsigned int channels = scontrol->num_channels; 150 struct snd_sof_widget *swidget; 116 struct snd_sof_widget *swidget; 151 bool widget_found = false; 117 bool widget_found = false; 152 bool change = false; 118 bool change = false; 153 unsigned int i; 119 unsigned int i; 154 int ret; 120 int ret; 155 121 156 /* update each channel */ 122 /* update each channel */ 157 for (i = 0; i < channels; i++) { 123 for (i = 0; i < channels; i++) { 158 u32 value = mixer_to_ipc(ucont 124 u32 value = mixer_to_ipc(ucontrol->value.integer.value[i], 159 scont 125 scontrol->volume_table, scontrol->max + 1); 160 126 161 change = change || (value != c 127 change = change || (value != cdata->chanv[i].value); 162 cdata->chanv[i].channel = i; 128 cdata->chanv[i].channel = i; 163 cdata->chanv[i].value = value; 129 cdata->chanv[i].value = value; 164 } 130 } 165 131 166 if (!pm_runtime_active(scomp->dev)) 132 if (!pm_runtime_active(scomp->dev)) 167 return change; 133 return change; 168 134 169 /* find widget associated with the con 135 /* find widget associated with the control */ 170 list_for_each_entry(swidget, &sdev->wi 136 list_for_each_entry(swidget, &sdev->widget_list, list) { 171 if (swidget->comp_id == scontr 137 if (swidget->comp_id == scontrol->comp_id) { 172 widget_found = true; 138 widget_found = true; 173 break; 139 break; 174 } 140 } 175 } 141 } 176 142 177 if (!widget_found) { 143 if (!widget_found) { 178 dev_err(scomp->dev, "Failed to 144 dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name); 179 return false; 145 return false; 180 } 146 } 181 147 182 ret = sof_ipc4_set_volume_data(sdev, s !! 148 ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol); 183 if (ret < 0) 149 if (ret < 0) 184 return false; 150 return false; 185 151 186 return change; 152 return change; 187 } 153 } 188 154 189 static int sof_ipc4_volume_get(struct snd_sof_ 155 static int sof_ipc4_volume_get(struct snd_sof_control *scontrol, 190 struct snd_ctl_ 156 struct snd_ctl_elem_value *ucontrol) 191 { 157 { 192 struct sof_ipc4_control_data *cdata = 158 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 193 unsigned int channels = scontrol->num_ 159 unsigned int channels = scontrol->num_channels; 194 unsigned int i; 160 unsigned int i; 195 161 196 for (i = 0; i < channels; i++) 162 for (i = 0; i < channels; i++) 197 ucontrol->value.integer.value[ 163 ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value, 198 164 scontrol->volume_table, 199 165 scontrol->max + 1); 200 166 201 return 0; 167 return 0; 202 } 168 } 203 169 204 static int << 205 sof_ipc4_set_generic_control_data(struct snd_s << 206 struct snd_s << 207 struct snd_s << 208 { << 209 struct sof_ipc4_control_data *cdata = << 210 struct sof_ipc4_control_msg_payload *d << 211 struct sof_ipc4_msg *msg = &cdata->msg << 212 size_t data_size; << 213 unsigned int i; << 214 int ret; << 215 << 216 data_size = struct_size(data, chanv, s << 217 data = kzalloc(data_size, GFP_KERNEL); << 218 if (!data) << 219 return -ENOMEM; << 220 << 221 data->id = cdata->index; << 222 data->num_elems = scontrol->num_channe << 223 for (i = 0; i < scontrol->num_channels << 224 data->chanv[i].channel = cdata << 225 data->chanv[i].value = cdata-> << 226 } << 227 << 228 msg->data_ptr = data; << 229 msg->data_size = data_size; << 230 << 231 ret = sof_ipc4_set_get_kcontrol_data(s << 232 msg->data_ptr = NULL; << 233 msg->data_size = 0; << 234 if (ret < 0) << 235 dev_err(sdev->dev, "Failed to << 236 scontrol->name); << 237 << 238 kfree(data); << 239 << 240 return ret; << 241 } << 242 << 243 static void sof_ipc4_refresh_generic_control(s << 244 { << 245 struct sof_ipc4_control_data *cdata = << 246 struct snd_soc_component *scomp = scon << 247 struct sof_ipc4_control_msg_payload *d << 248 struct sof_ipc4_msg *msg = &cdata->msg << 249 size_t data_size; << 250 unsigned int i; << 251 int ret; << 252 << 253 if (!scontrol->comp_data_dirty) << 254 return; << 255 << 256 if (!pm_runtime_active(scomp->dev)) << 257 return; << 258 << 259 data_size = struct_size(data, chanv, s << 260 data = kmalloc(data_size, GFP_KERNEL); << 261 if (!data) << 262 return; << 263 << 264 data->id = cdata->index; << 265 data->num_elems = scontrol->num_channe << 266 msg->data_ptr = data; << 267 msg->data_size = data_size; << 268 << 269 scontrol->comp_data_dirty = false; << 270 ret = sof_ipc4_set_get_kcontrol_data(s << 271 msg->data_ptr = NULL; << 272 msg->data_size = 0; << 273 if (!ret) { << 274 for (i = 0; i < scontrol->num_ << 275 cdata->chanv[i].channe << 276 cdata->chanv[i].value << 277 } << 278 } else { << 279 dev_err(scomp->dev, "Failed to << 280 scontrol->name); << 281 scontrol->comp_data_dirty = tr << 282 } << 283 << 284 kfree(data); << 285 } << 286 << 287 static bool sof_ipc4_switch_put(struct snd_sof << 288 struct snd_ctl << 289 { << 290 struct sof_ipc4_control_data *cdata = << 291 struct snd_soc_component *scomp = scon << 292 struct snd_sof_dev *sdev = snd_soc_com << 293 struct snd_sof_widget *swidget; << 294 bool widget_found = false; << 295 bool change = false; << 296 unsigned int i; << 297 u32 value; << 298 int ret; << 299 << 300 /* update each channel */ << 301 for (i = 0; i < scontrol->num_channels << 302 value = ucontrol->value.intege << 303 change = change || (value != c << 304 cdata->chanv[i].channel = i; << 305 cdata->chanv[i].value = value; << 306 } << 307 << 308 if (!pm_runtime_active(scomp->dev)) << 309 return change; << 310 << 311 /* find widget associated with the con << 312 list_for_each_entry(swidget, &sdev->wi << 313 if (swidget->comp_id == scontr << 314 widget_found = true; << 315 break; << 316 } << 317 } << 318 << 319 if (!widget_found) { << 320 dev_err(scomp->dev, "Failed to << 321 return false; << 322 } << 323 << 324 ret = sof_ipc4_set_generic_control_dat << 325 if (ret < 0) << 326 return false; << 327 << 328 return change; << 329 } << 330 << 331 static int sof_ipc4_switch_get(struct snd_sof_ << 332 struct snd_ctl_ << 333 { << 334 struct sof_ipc4_control_data *cdata = << 335 unsigned int i; << 336 << 337 sof_ipc4_refresh_generic_control(scont << 338 << 339 /* read back each channel */ << 340 for (i = 0; i < scontrol->num_channels << 341 ucontrol->value.integer.value[ << 342 << 343 return 0; << 344 } << 345 << 346 static bool sof_ipc4_enum_put(struct snd_sof_c << 347 struct snd_ctl_e << 348 { << 349 struct sof_ipc4_control_data *cdata = << 350 struct snd_soc_component *scomp = scon << 351 struct snd_sof_dev *sdev = snd_soc_com << 352 struct snd_sof_widget *swidget; << 353 bool widget_found = false; << 354 bool change = false; << 355 unsigned int i; << 356 u32 value; << 357 int ret; << 358 << 359 /* update each channel */ << 360 for (i = 0; i < scontrol->num_channels << 361 value = ucontrol->value.enumer << 362 change = change || (value != c << 363 cdata->chanv[i].channel = i; << 364 cdata->chanv[i].value = value; << 365 } << 366 << 367 if (!pm_runtime_active(scomp->dev)) << 368 return change; << 369 << 370 /* find widget associated with the con << 371 list_for_each_entry(swidget, &sdev->wi << 372 if (swidget->comp_id == scontr << 373 widget_found = true; << 374 break; << 375 } << 376 } << 377 << 378 if (!widget_found) { << 379 dev_err(scomp->dev, "Failed to << 380 return false; << 381 } << 382 << 383 ret = sof_ipc4_set_generic_control_dat << 384 if (ret < 0) << 385 return false; << 386 << 387 return change; << 388 } << 389 << 390 static int sof_ipc4_enum_get(struct snd_sof_co << 391 struct snd_ctl_el << 392 { << 393 struct sof_ipc4_control_data *cdata = << 394 unsigned int i; << 395 << 396 sof_ipc4_refresh_generic_control(scont << 397 << 398 /* read back each channel */ << 399 for (i = 0; i < scontrol->num_channels << 400 ucontrol->value.enumerated.ite << 401 << 402 return 0; << 403 } << 404 << 405 static int sof_ipc4_set_get_bytes_data(struct << 406 struct << 407 bool se << 408 { << 409 struct sof_ipc4_control_data *cdata = << 410 struct sof_abi_hdr *data = cdata->data << 411 struct sof_ipc4_msg *msg = &cdata->msg << 412 int ret = 0; << 413 << 414 /* Send the new data to the firmware o << 415 if (set && !pm_runtime_active(sdev->de << 416 return 0; << 417 << 418 msg->extension = SOF_IPC4_MOD_EXT_MSG_ << 419 << 420 msg->data_ptr = data->data; << 421 msg->data_size = data->size; << 422 << 423 ret = sof_ipc4_set_get_kcontrol_data(s << 424 if (ret < 0) << 425 dev_err(sdev->dev, "Failed to << 426 set ? "set bytes updat << 427 scontrol->name); << 428 << 429 msg->data_ptr = NULL; << 430 msg->data_size = 0; << 431 << 432 return ret; << 433 } << 434 << 435 static int sof_ipc4_bytes_put(struct snd_sof_c << 436 struct snd_ctl_e << 437 { << 438 struct sof_ipc4_control_data *cdata = << 439 struct snd_soc_component *scomp = scon << 440 struct snd_sof_dev *sdev = snd_soc_com << 441 struct sof_abi_hdr *data = cdata->data << 442 size_t size; << 443 << 444 if (scontrol->max_size > sizeof(ucontr << 445 dev_err_ratelimited(scomp->dev << 446 "data max << 447 scontrol-> << 448 return -EINVAL; << 449 } << 450 << 451 /* scontrol->max_size has been verifie << 452 if (data->size > scontrol->max_size - << 453 dev_err_ratelimited(scomp->dev << 454 "data size << 455 data->size << 456 return -EINVAL; << 457 } << 458 << 459 size = data->size + sizeof(*data); << 460 << 461 /* copy from kcontrol */ << 462 memcpy(data, ucontrol->value.bytes.dat << 463 << 464 sof_ipc4_set_get_bytes_data(sdev, scon << 465 << 466 return 0; << 467 } << 468 << 469 static int sof_ipc4_bytes_get(struct snd_sof_c << 470 struct snd_ctl_e << 471 { << 472 struct sof_ipc4_control_data *cdata = << 473 struct snd_soc_component *scomp = scon << 474 struct sof_abi_hdr *data = cdata->data << 475 size_t size; << 476 << 477 if (scontrol->max_size > sizeof(ucontr << 478 dev_err_ratelimited(scomp->dev << 479 scontrol-> << 480 return -EINVAL; << 481 } << 482 << 483 if (data->size > scontrol->max_size - << 484 dev_err_ratelimited(scomp->dev << 485 "%u bytes << 486 data->size << 487 return -EINVAL; << 488 } << 489 << 490 size = data->size + sizeof(*data); << 491 << 492 /* copy back to kcontrol */ << 493 memcpy(ucontrol->value.bytes.data, dat << 494 << 495 return 0; << 496 } << 497 << 498 static int sof_ipc4_bytes_ext_put(struct snd_s << 499 const unsign << 500 unsigned int << 501 { << 502 struct snd_ctl_tlv __user *tlvd = (str << 503 struct sof_ipc4_control_data *cdata = << 504 struct snd_soc_component *scomp = scon << 505 struct snd_sof_dev *sdev = snd_soc_com << 506 struct sof_abi_hdr *data = cdata->data << 507 struct sof_abi_hdr abi_hdr; << 508 struct snd_ctl_tlv header; << 509 << 510 /* << 511 * The beginning of bytes data contain << 512 * the length (as bytes) is needed to << 513 * length of data from tlvd->tlv. << 514 */ << 515 if (copy_from_user(&header, tlvd, size << 516 return -EFAULT; << 517 << 518 /* make sure TLV info is consistent */ << 519 if (header.length + sizeof(struct snd_ << 520 dev_err_ratelimited(scomp->dev << 521 "Inconsist << 522 header.len << 523 return -EINVAL; << 524 } << 525 << 526 /* be->max is coming from topology */ << 527 if (header.length > scontrol->max_size << 528 dev_err_ratelimited(scomp->dev << 529 "Bytes dat << 530 header.len << 531 return -EINVAL; << 532 } << 533 << 534 /* Verify the ABI header first */ << 535 if (copy_from_user(&abi_hdr, tlvd->tlv << 536 return -EFAULT; << 537 << 538 if (abi_hdr.magic != SOF_IPC4_ABI_MAGI << 539 dev_err_ratelimited(scomp->dev << 540 abi_hdr.ma << 541 return -EINVAL; << 542 } << 543 << 544 if (abi_hdr.size > scontrol->max_size << 545 dev_err_ratelimited(scomp->dev << 546 "%u bytes << 547 abi_hdr.si << 548 return -EINVAL; << 549 } << 550 << 551 if (!scontrol->old_ipc_control_data) { << 552 /* Create a backup of the curr << 553 scontrol->old_ipc_control_data << 554 << 555 if (!scontrol->old_ipc_control << 556 return -ENOMEM; << 557 } << 558 << 559 /* Copy the whole binary data which in << 560 if (copy_from_user(data, tlvd->tlv, he << 561 memcpy(scontrol->ipc_control_d << 562 scontrol->max_size); << 563 kfree(scontrol->old_ipc_contro << 564 scontrol->old_ipc_control_data << 565 return -EFAULT; << 566 } << 567 << 568 return sof_ipc4_set_get_bytes_data(sde << 569 } << 570 << 571 static int _sof_ipc4_bytes_ext_get(struct snd_ << 572 const unsig << 573 unsigned in << 574 { << 575 struct snd_ctl_tlv __user *tlvd = (str << 576 struct sof_ipc4_control_data *cdata = << 577 struct snd_soc_component *scomp = scon << 578 struct sof_abi_hdr *data = cdata->data << 579 struct snd_ctl_tlv header; << 580 size_t data_size; << 581 << 582 /* << 583 * Decrement the limit by ext bytes he << 584 * buffer is not exceeded. << 585 */ << 586 if (size < sizeof(struct snd_ctl_tlv)) << 587 return -ENOSPC; << 588 << 589 size -= sizeof(struct snd_ctl_tlv); << 590 << 591 /* get all the component data from DSP << 592 if (from_dsp) { << 593 struct snd_sof_dev *sdev = snd << 594 int ret = sof_ipc4_set_get_byt << 595 << 596 if (ret < 0) << 597 return ret; << 598 << 599 /* Set the ABI magic (if the c << 600 data->magic = SOF_IPC4_ABI_MAG << 601 } << 602 << 603 if (data->size > scontrol->max_size - << 604 dev_err_ratelimited(scomp->dev << 605 "%u bytes << 606 data->size << 607 return -EINVAL; << 608 } << 609 << 610 data_size = data->size + sizeof(struct << 611 << 612 /* make sure we don't exceed size prov << 613 if (data_size > size) << 614 return -ENOSPC; << 615 << 616 header.numid = scontrol->comp_id; << 617 header.length = data_size; << 618 << 619 if (copy_to_user(tlvd, &header, sizeof << 620 return -EFAULT; << 621 << 622 if (copy_to_user(tlvd->tlv, data, data << 623 return -EFAULT; << 624 << 625 return 0; << 626 } << 627 << 628 static int sof_ipc4_bytes_ext_get(struct snd_s << 629 const unsign << 630 unsigned int << 631 { << 632 return _sof_ipc4_bytes_ext_get(scontro << 633 } << 634 << 635 static int sof_ipc4_bytes_ext_volatile_get(str << 636 con << 637 uns << 638 { << 639 return _sof_ipc4_bytes_ext_get(scontro << 640 } << 641 << 642 static int << 643 sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, << 644 struct snd_sof_control *s << 645 { << 646 if (scontrol->max == 1) << 647 return sof_ipc4_set_generic_co << 648 << 649 return sof_ipc4_set_volume_data(sdev, << 650 } << 651 << 652 #define PARAM_ID_FROM_EXTENSION(_ext) (((_ex << 653 >> SO << 654 << 655 static void sof_ipc4_control_update(struct snd << 656 { << 657 struct sof_ipc4_msg *ipc4_msg = ipc_me << 658 struct sof_ipc4_notify_module_data *nd << 659 struct sof_ipc4_control_msg_payload *m << 660 struct sof_ipc4_control_data *cdata; << 661 struct snd_soc_dapm_widget *widget; << 662 struct snd_sof_control *scontrol; << 663 struct snd_sof_widget *swidget; << 664 struct snd_kcontrol *kc = NULL; << 665 bool scontrol_found = false; << 666 u32 event_param_id; << 667 int i, type; << 668 << 669 if (ndata->event_data_size < sizeof(*m << 670 dev_err(sdev->dev, << 671 "%s: Invalid event dat << 672 __func__, ndata->modul << 673 ndata->event_data_size << 674 return; << 675 } << 676 << 677 event_param_id = ndata->event_id & SOF << 678 switch (event_param_id) { << 679 case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: << 680 type = SND_SOC_TPLG_TYPE_MIXER << 681 break; << 682 case SOF_IPC4_ENUM_CONTROL_PARAM_ID: << 683 type = SND_SOC_TPLG_TYPE_ENUM; << 684 break; << 685 default: << 686 dev_err(sdev->dev, << 687 "%s: Invalid control t << 688 __func__, ndata->modul << 689 event_param_id); << 690 return; << 691 } << 692 << 693 /* Find the swidget based on ndata->mo << 694 swidget = sof_ipc4_find_swidget_by_ids << 695 << 696 if (!swidget) { << 697 dev_err(sdev->dev, "%s: Failed << 698 __func__, ndata->modul << 699 return; << 700 } << 701 << 702 /* Find the scontrol which is the sour << 703 msg_data = (struct sof_ipc4_control_ms << 704 list_for_each_entry(scontrol, &sdev->k << 705 if (scontrol->comp_id == swidg << 706 u32 local_param_id; << 707 << 708 cdata = scontrol->ipc_ << 709 /* << 710 * The scontrol's para << 711 * template's extensio << 712 */ << 713 local_param_id = PARAM << 714 if (local_param_id == << 715 msg_data->id == cd << 716 scontrol_found << 717 break; << 718 } << 719 } << 720 } << 721 << 722 if (!scontrol_found) { << 723 dev_err(sdev->dev, << 724 "%s: Failed to find co << 725 __func__, swidget->wid << 726 msg_data->id); << 727 return; << 728 } << 729 << 730 if (msg_data->num_elems) { << 731 /* << 732 * The message includes the up << 733 * control's local cache using << 734 */ << 735 for (i = 0; i < msg_data->num_ << 736 u32 channel = msg_data << 737 << 738 if (channel >= scontro << 739 dev_warn(sdev- << 740 "Inva << 741 scont << 742 << 743 /* << 744 * Mark the sc << 745 * on next rea << 746 */ << 747 scontrol->comp << 748 break; << 749 } << 750 << 751 cdata->chanv[channel]. << 752 } << 753 } else { << 754 /* << 755 * Mark the scontrol as dirty << 756 * in firmware, forcing a refr << 757 */ << 758 scontrol->comp_data_dirty = tr << 759 } << 760 << 761 /* << 762 * Look up the ALSA kcontrol of the sc << 763 * notification to user space << 764 */ << 765 widget = swidget->widget; << 766 for (i = 0; i < widget->num_kcontrols; << 767 /* skip non matching types or << 768 if (widget->dobj.widget.kcontr << 769 widget->kcontrol_news[i].i << 770 kc = widget->kcontrols << 771 break; << 772 } << 773 } << 774 << 775 if (!kc) << 776 return; << 777 << 778 snd_ctl_notify_one(swidget->scomp->car << 779 SNDRV_CTL_EVENT_MAS << 780 } << 781 << 782 /* set up all controls for the widget */ 170 /* set up all controls for the widget */ 783 static int sof_ipc4_widget_kcontrol_setup(stru 171 static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 784 { 172 { 785 struct snd_sof_control *scontrol; 173 struct snd_sof_control *scontrol; 786 int ret = 0; !! 174 int ret; 787 175 788 list_for_each_entry(scontrol, &sdev->k !! 176 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) 789 if (scontrol->comp_id == swidg 177 if (scontrol->comp_id == swidget->comp_id) { 790 switch (scontrol->info !! 178 ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol); 791 case SND_SOC_TPLG_CTL_ << 792 case SND_SOC_TPLG_CTL_ << 793 case SND_SOC_TPLG_CTL_ << 794 ret = sof_ipc4 << 795 break; << 796 case SND_SOC_TPLG_CTL_ << 797 ret = sof_ipc4 << 798 << 799 break; << 800 case SND_SOC_TPLG_CTL_ << 801 case SND_SOC_TPLG_CTL_ << 802 ret = sof_ipc4 << 803 << 804 break; << 805 default: << 806 break; << 807 } << 808 << 809 if (ret < 0) { 179 if (ret < 0) { 810 dev_err(sdev-> !! 180 dev_err(sdev->dev, "%s: kcontrol %d set up failed for widget %s\n", 811 "kcont !! 181 __func__, scontrol->comp_id, swidget->widget->name); 812 scontr << 813 return ret; 182 return ret; 814 } 183 } 815 } 184 } 816 } << 817 185 818 return 0; 186 return 0; 819 } 187 } 820 188 821 static int 189 static int 822 sof_ipc4_set_up_volume_table(struct snd_sof_co 190 sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size) 823 { 191 { 824 int i; 192 int i; 825 193 826 /* init the volume table */ 194 /* init the volume table */ 827 scontrol->volume_table = kcalloc(size, 195 scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL); 828 if (!scontrol->volume_table) 196 if (!scontrol->volume_table) 829 return -ENOMEM; 197 return -ENOMEM; 830 198 831 /* populate the volume table */ 199 /* populate the volume table */ 832 for (i = 0; i < size ; i++) { 200 for (i = 0; i < size ; i++) { 833 u32 val = vol_compute_gain(i, 201 u32 val = vol_compute_gain(i, tlv); 834 u64 q31val = ((u64)val) << 15; 202 u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */ 835 203 836 scontrol->volume_table[i] = q3 204 scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ? 837 205 SOF_IPC4_VOL_ZERO_DB : q31val; 838 } 206 } 839 207 840 return 0; 208 return 0; 841 } 209 } 842 210 843 const struct sof_ipc_tplg_control_ops tplg_ipc 211 const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = { 844 .volume_put = sof_ipc4_volume_put, 212 .volume_put = sof_ipc4_volume_put, 845 .volume_get = sof_ipc4_volume_get, 213 .volume_get = sof_ipc4_volume_get, 846 .switch_put = sof_ipc4_switch_put, << 847 .switch_get = sof_ipc4_switch_get, << 848 .enum_put = sof_ipc4_enum_put, << 849 .enum_get = sof_ipc4_enum_get, << 850 .bytes_put = sof_ipc4_bytes_put, << 851 .bytes_get = sof_ipc4_bytes_get, << 852 .bytes_ext_put = sof_ipc4_bytes_ext_pu << 853 .bytes_ext_get = sof_ipc4_bytes_ext_ge << 854 .bytes_ext_volatile_get = sof_ipc4_byt << 855 .update = sof_ipc4_control_update, << 856 .widget_kcontrol_setup = sof_ipc4_widg 214 .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup, 857 .set_up_volume_table = sof_ipc4_set_up 215 .set_up_volume_table = sof_ipc4_set_up_volume_table, 858 }; 216 }; 859 217
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.