linux/sound/soc/sof/control.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 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 "sof-priv.h"
  15
  16static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
  17{
  18        if (value >= size)
  19                return volume_map[size - 1];
  20
  21        return volume_map[value];
  22}
  23
  24static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
  25{
  26        int i;
  27
  28        for (i = 0; i < size; i++) {
  29                if (volume_map[i] >= value)
  30                        return i;
  31        }
  32
  33        return i - 1;
  34}
  35
  36int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
  37                       struct snd_ctl_elem_value *ucontrol)
  38{
  39        struct soc_mixer_control *sm =
  40                (struct soc_mixer_control *)kcontrol->private_value;
  41        struct snd_sof_control *scontrol = sm->dobj.private;
  42        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
  43        unsigned int i, channels = scontrol->num_channels;
  44
  45        /* read back each channel */
  46        for (i = 0; i < channels; i++)
  47                ucontrol->value.integer.value[i] =
  48                        ipc_to_mixer(cdata->chanv[i].value,
  49                                     scontrol->volume_table, sm->max + 1);
  50
  51        return 0;
  52}
  53
  54int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
  55                       struct snd_ctl_elem_value *ucontrol)
  56{
  57        struct soc_mixer_control *sm =
  58                (struct soc_mixer_control *)kcontrol->private_value;
  59        struct snd_sof_control *scontrol = sm->dobj.private;
  60        struct snd_sof_dev *sdev = scontrol->sdev;
  61        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
  62        unsigned int i, channels = scontrol->num_channels;
  63
  64        /* update each channel */
  65        for (i = 0; i < channels; i++) {
  66                cdata->chanv[i].value =
  67                        mixer_to_ipc(ucontrol->value.integer.value[i],
  68                                     scontrol->volume_table, sm->max + 1);
  69                cdata->chanv[i].channel = i;
  70        }
  71
  72        /* notify DSP of mixer updates */
  73        if (pm_runtime_active(sdev->dev))
  74                snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
  75                                              SOF_IPC_COMP_SET_VALUE,
  76                                              SOF_CTRL_TYPE_VALUE_CHAN_GET,
  77                                              SOF_CTRL_CMD_VOLUME,
  78                                              true);
  79
  80        return 0;
  81}
  82
  83int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
  84                       struct snd_ctl_elem_value *ucontrol)
  85{
  86        struct soc_mixer_control *sm =
  87                (struct soc_mixer_control *)kcontrol->private_value;
  88        struct snd_sof_control *scontrol = sm->dobj.private;
  89        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
  90        unsigned int i, channels = scontrol->num_channels;
  91
  92        /* read back each channel */
  93        for (i = 0; i < channels; i++)
  94                ucontrol->value.integer.value[i] = cdata->chanv[i].value;
  95
  96        return 0;
  97}
  98
  99int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
 100                       struct snd_ctl_elem_value *ucontrol)
 101{
 102        struct soc_mixer_control *sm =
 103                (struct soc_mixer_control *)kcontrol->private_value;
 104        struct snd_sof_control *scontrol = sm->dobj.private;
 105        struct snd_sof_dev *sdev = scontrol->sdev;
 106        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 107        unsigned int i, channels = scontrol->num_channels;
 108
 109        /* update each channel */
 110        for (i = 0; i < channels; i++) {
 111                cdata->chanv[i].value = ucontrol->value.integer.value[i];
 112                cdata->chanv[i].channel = i;
 113        }
 114
 115        /* notify DSP of mixer updates */
 116        if (pm_runtime_active(sdev->dev))
 117                snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
 118                                              SOF_IPC_COMP_SET_VALUE,
 119                                              SOF_CTRL_TYPE_VALUE_CHAN_GET,
 120                                              SOF_CTRL_CMD_SWITCH,
 121                                              true);
 122
 123        return 0;
 124}
 125
 126int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
 127                     struct snd_ctl_elem_value *ucontrol)
 128{
 129        struct soc_enum *se =
 130                (struct soc_enum *)kcontrol->private_value;
 131        struct snd_sof_control *scontrol = se->dobj.private;
 132        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 133        unsigned int i, channels = scontrol->num_channels;
 134
 135        /* read back each channel */
 136        for (i = 0; i < channels; i++)
 137                ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
 138
 139        return 0;
 140}
 141
 142int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
 143                     struct snd_ctl_elem_value *ucontrol)
 144{
 145        struct soc_enum *se =
 146                (struct soc_enum *)kcontrol->private_value;
 147        struct snd_sof_control *scontrol = se->dobj.private;
 148        struct snd_sof_dev *sdev = scontrol->sdev;
 149        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 150        unsigned int i, channels = scontrol->num_channels;
 151
 152        /* update each channel */
 153        for (i = 0; i < channels; i++) {
 154                cdata->chanv[i].value = ucontrol->value.enumerated.item[i];
 155                cdata->chanv[i].channel = i;
 156        }
 157
 158        /* notify DSP of enum updates */
 159        if (pm_runtime_active(sdev->dev))
 160                snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
 161                                              SOF_IPC_COMP_SET_VALUE,
 162                                              SOF_CTRL_TYPE_VALUE_CHAN_GET,
 163                                              SOF_CTRL_CMD_ENUM,
 164                                              true);
 165
 166        return 0;
 167}
 168
 169int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
 170                      struct snd_ctl_elem_value *ucontrol)
 171{
 172        struct soc_bytes_ext *be =
 173                (struct soc_bytes_ext *)kcontrol->private_value;
 174        struct snd_sof_control *scontrol = be->dobj.private;
 175        struct snd_sof_dev *sdev = scontrol->sdev;
 176        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 177        struct sof_abi_hdr *data = cdata->data;
 178        size_t size;
 179        int ret = 0;
 180
 181        if (be->max > sizeof(ucontrol->value.bytes.data)) {
 182                dev_err_ratelimited(sdev->dev,
 183                                    "error: data max %d exceeds ucontrol data array size\n",
 184                                    be->max);
 185                return -EINVAL;
 186        }
 187
 188        size = data->size + sizeof(*data);
 189        if (size > be->max) {
 190                dev_err_ratelimited(sdev->dev,
 191                                    "error: DSP sent %zu bytes max is %d\n",
 192                                    size, be->max);
 193                ret = -EINVAL;
 194                goto out;
 195        }
 196
 197        /* copy back to kcontrol */
 198        memcpy(ucontrol->value.bytes.data, data, size);
 199
 200out:
 201        return ret;
 202}
 203
 204int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
 205                      struct snd_ctl_elem_value *ucontrol)
 206{
 207        struct soc_bytes_ext *be =
 208                (struct soc_bytes_ext *)kcontrol->private_value;
 209        struct snd_sof_control *scontrol = be->dobj.private;
 210        struct snd_sof_dev *sdev = scontrol->sdev;
 211        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 212        struct sof_abi_hdr *data = cdata->data;
 213        size_t size = data->size + sizeof(*data);
 214
 215        if (be->max > sizeof(ucontrol->value.bytes.data)) {
 216                dev_err_ratelimited(sdev->dev,
 217                                    "error: data max %d exceeds ucontrol data array size\n",
 218                                    be->max);
 219                return -EINVAL;
 220        }
 221
 222        if (size > be->max) {
 223                dev_err_ratelimited(sdev->dev,
 224                                    "error: size too big %zu bytes max is %d\n",
 225                                    size, be->max);
 226                return -EINVAL;
 227        }
 228
 229        /* copy from kcontrol */
 230        memcpy(data, ucontrol->value.bytes.data, size);
 231
 232        /* notify DSP of byte control updates */
 233        if (pm_runtime_active(sdev->dev))
 234                snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
 235                                              SOF_IPC_COMP_SET_DATA,
 236                                              SOF_CTRL_TYPE_DATA_SET,
 237                                              scontrol->cmd,
 238                                              true);
 239
 240        return 0;
 241}
 242
 243int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
 244                          const unsigned int __user *binary_data,
 245                          unsigned int size)
 246{
 247        struct soc_bytes_ext *be =
 248                (struct soc_bytes_ext *)kcontrol->private_value;
 249        struct snd_sof_control *scontrol = be->dobj.private;
 250        struct snd_sof_dev *sdev = scontrol->sdev;
 251        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 252        struct snd_ctl_tlv header;
 253        const struct snd_ctl_tlv __user *tlvd =
 254                (const struct snd_ctl_tlv __user *)binary_data;
 255
 256        /*
 257         * The beginning of bytes data contains a header from where
 258         * the length (as bytes) is needed to know the correct copy
 259         * length of data from tlvd->tlv.
 260         */
 261        if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv)))
 262                return -EFAULT;
 263
 264        /* be->max is coming from topology */
 265        if (header.length > be->max) {
 266                dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n",
 267                                    header.length, be->max);
 268                return -EINVAL;
 269        }
 270
 271        /* Check that header id matches the command */
 272        if (header.numid != scontrol->cmd) {
 273                dev_err_ratelimited(sdev->dev,
 274                                    "error: incorrect numid %d\n",
 275                                    header.numid);
 276                return -EINVAL;
 277        }
 278
 279        if (copy_from_user(cdata->data, tlvd->tlv, header.length))
 280                return -EFAULT;
 281
 282        if (cdata->data->magic != SOF_ABI_MAGIC) {
 283                dev_err_ratelimited(sdev->dev,
 284                                    "error: Wrong ABI magic 0x%08x.\n",
 285                                    cdata->data->magic);
 286                return -EINVAL;
 287        }
 288
 289        if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
 290                dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n",
 291                                    cdata->data->abi);
 292                return -EINVAL;
 293        }
 294
 295        if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) {
 296                dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n");
 297                return -EINVAL;
 298        }
 299
 300        /* notify DSP of byte control updates */
 301        if (pm_runtime_active(sdev->dev))
 302                snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
 303                                              SOF_IPC_COMP_SET_DATA,
 304                                              SOF_CTRL_TYPE_DATA_SET,
 305                                              scontrol->cmd,
 306                                              true);
 307
 308        return 0;
 309}
 310
 311int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
 312                          unsigned int __user *binary_data,
 313                          unsigned int size)
 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_sof_dev *sdev = scontrol->sdev;
 319        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
 320        struct snd_ctl_tlv header;
 321        struct snd_ctl_tlv __user *tlvd =
 322                (struct snd_ctl_tlv __user *)binary_data;
 323        int data_size;
 324        int ret = 0;
 325
 326        /*
 327         * Decrement the limit by ext bytes header size to
 328         * ensure the user space buffer is not exceeded.
 329         */
 330        size -= sizeof(const struct snd_ctl_tlv);
 331
 332        /* set the ABI header values */
 333        cdata->data->magic = SOF_ABI_MAGIC;
 334        cdata->data->abi = SOF_ABI_VERSION;
 335
 336        /* Prevent read of other kernel data or possibly corrupt response */
 337        data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
 338
 339        /* check data size doesn't exceed max coming from topology */
 340        if (data_size > be->max) {
 341                dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n",
 342                                    data_size, be->max);
 343                ret = -EINVAL;
 344                goto out;
 345        }
 346
 347        header.numid = scontrol->cmd;
 348        header.length = data_size;
 349        if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) {
 350                ret = -EFAULT;
 351                goto out;
 352        }
 353
 354        if (copy_to_user(tlvd->tlv, cdata->data, data_size))
 355                ret = -EFAULT;
 356
 357out:
 358        return ret;
 359}
 360