Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 //
0003 // This file is provided under a dual BSD/GPLv2 license.  When using or
0004 // redistributing this file, you may do so under either license.
0005 //
0006 // Copyright(c) 2021 Intel Corporation. All rights reserved.
0007 //
0008 //
0009 
0010 #include "sof-priv.h"
0011 #include "sof-audio.h"
0012 #include "ipc3-priv.h"
0013 
0014 /* IPC set()/get() for kcontrols. */
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      * Volatile controls should always be part of static pipelines and the widget use_count
0040      * would always be > 0 in this case. For the others, just return the cached value if the
0041      * widget is not set up.
0042      */
0043     if (!swidget->use_count)
0044         return 0;
0045 
0046     /*
0047      * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the
0048      * direction
0049      * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently
0050      *   for ctrl_type
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     /* calculate header and data size */
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     /* set the ABI header values */
0106     cdata->data->magic = SOF_ABI_MAGIC;
0107     cdata->data->abi = SOF_ABI_VERSION;
0108 
0109     /* refresh the component data from DSP */
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         /* Set the flag to re-try next time to get the data */
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     /* read back each channel */
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     /* update each channel */
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     /* notify DSP of mixer updates */
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     /* read back each channel */
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     /* update each channel */
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     /* notify DSP of mixer updates */
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     /* read back each channel */
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     /* update each channel */
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     /* notify DSP of enum updates */
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     /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
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     /* copy back to kcontrol */
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     /* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
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     /* copy from kcontrol */
0323     memcpy(data, ucontrol->value.bytes.data, size);
0324 
0325     /* notify DSP of byte control updates */
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      * Decrement the limit by ext bytes header size to
0345      * ensure the user space buffer is not exceeded.
0346      */
0347     if (size < sizeof(struct snd_ctl_tlv))
0348         return -ENOSPC;
0349 
0350     size -= sizeof(struct snd_ctl_tlv);
0351 
0352     /* set the ABI header values */
0353     cdata->data->magic = SOF_ABI_MAGIC;
0354     cdata->data->abi = SOF_ABI_VERSION;
0355 
0356     /* check data size doesn't exceed max coming from topology */
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     /* make sure we don't exceed size provided by user space for data */
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      * The beginning of bytes data contains a header from where
0392      * the length (as bytes) is needed to know the correct copy
0393      * length of data from tlvd->tlv.
0394      */
0395     if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
0396         return -EFAULT;
0397 
0398     /* make sure TLV info is consistent */
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     /* be->max is coming from topology */
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     /* Check that header id matches the command */
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     /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
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     /* notify DSP of byte control updates */
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      * Decrement the limit by ext bytes header size to
0459      * ensure the user space buffer is not exceeded.
0460      */
0461     if (size < sizeof(struct snd_ctl_tlv))
0462         return -ENOSPC;
0463 
0464     size -= sizeof(struct snd_ctl_tlv);
0465 
0466     /* set the ABI header values */
0467     cdata->data->magic = SOF_ABI_MAGIC;
0468     cdata->data->abi = SOF_ABI_VERSION;
0469 
0470     /* get all the component data from DSP */
0471     ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
0472     if (ret < 0)
0473         return ret;
0474 
0475     /* check data size doesn't exceed max coming from topology */
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     /* make sure we don't exceed size provided by user space for data */
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         /* copy the new binary data */
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         /* copy the new values */
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     /* Find the swidget first */
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     /* Translate SOF cmd to TPLG type */
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         /* skip non matching types or non matching indexes within type */
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          * The message includes the updated value/data, update the
0630          * control's local cache using the received notification
0631          */
0632         snd_sof_update_control(scontrol, cdata);
0633     else
0634         /* Mark the scontrol that the value/data is changed in SOF */
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     /* set up all controls for the widget */
0647     list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
0648         if (scontrol->comp_id == swidget->comp_id) {
0649             /* set kcontrol data in DSP */
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              * Read back the data from the DSP for static widgets.
0660              * This is particularly useful for binary kcontrols
0661              * associated with static pipeline widgets to initialize
0662              * the data size to match that in the DSP.
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     /* init the volume table */
0683     scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
0684     if (!scontrol->volume_table)
0685         return -ENOMEM;
0686 
0687     /* populate the volume table */
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 };