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