2020-05-01 09:58:50 -05:00
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2019-04-12 11:05:07 -05:00
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2018 Intel Corporation. All rights reserved.
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
/* Mixer Controls */
# include <linux/pm_runtime.h>
2019-10-08 11:44:43 -05:00
# include <linux/leds.h>
2019-04-12 11:05:07 -05:00
# include "sof-priv.h"
2019-12-04 15:15:51 -06:00
# include "sof-audio.h"
2019-04-12 11:05:07 -05:00
2019-10-08 11:44:43 -05:00
static void update_mute_led ( struct snd_sof_control * scontrol ,
struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2020-04-30 17:11:39 +08:00
int temp = 0 ;
int mask ;
2019-10-08 11:44:43 -05:00
int i ;
mask = 1U < < snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) ;
for ( i = 0 ; i < scontrol - > num_channels ; i + + ) {
if ( ucontrol - > value . integer . value [ i ] ) {
temp | = mask ;
break ;
}
}
if ( temp = = scontrol - > led_ctl . led_value )
return ;
scontrol - > led_ctl . led_value = temp ;
2019-10-14 17:13:08 +08:00
# if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
2019-10-08 11:44:43 -05:00
if ( ! scontrol - > led_ctl . direction )
ledtrig_audio_set ( LED_AUDIO_MUTE , temp ? LED_OFF : LED_ON ) ;
else
ledtrig_audio_set ( LED_AUDIO_MICMUTE , temp ? LED_OFF : LED_ON ) ;
2019-10-14 17:13:08 +08:00
# endif
2019-10-08 11:44:43 -05:00
}
2021-09-03 14:40:18 +03:00
static void snd_sof_refresh_control ( struct snd_sof_control * scontrol )
{
2022-03-14 13:05:18 -07:00
struct sof_ipc_ctrl_data * cdata = scontrol - > ipc_control_data ;
2021-09-03 14:40:18 +03:00
struct snd_soc_component * scomp = scontrol - > scomp ;
int ret ;
if ( ! scontrol - > comp_data_dirty )
return ;
if ( ! pm_runtime_active ( scomp - > dev ) )
return ;
/* set the ABI header values */
cdata - > data - > magic = SOF_ABI_MAGIC ;
cdata - > data - > abi = SOF_ABI_VERSION ;
/* refresh the component data from DSP */
scontrol - > comp_data_dirty = false ;
2021-12-15 10:04:03 -08:00
ret = snd_sof_ipc_set_get_comp_data ( scontrol , false ) ;
2021-09-03 14:40:18 +03:00
if ( ret < 0 ) {
2022-03-17 10:50:31 -07:00
dev_err ( scomp - > dev , " Failed to get control data: %d \n " , ret ) ;
2021-09-03 14:40:18 +03:00
/* Set the flag to re-try next time to get the data */
scontrol - > comp_data_dirty = true ;
}
}
2019-04-12 11:05:07 -05:00
int snd_sof_volume_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:31 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2022-03-17 10:50:31 -07:00
struct snd_soc_component * scomp = scontrol - > scomp ;
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2021-09-03 14:40:18 +03:00
2022-03-17 10:50:31 -07:00
if ( tplg_ops - > control - > volume_get )
return tplg_ops - > control - > volume_get ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
return 0 ;
}
int snd_sof_volume_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:31 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:31 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
if ( tplg_ops - > control - > volume_put )
return tplg_ops - > control - > volume_put ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
2022-03-17 10:50:31 -07:00
return false ;
2019-04-12 11:05:07 -05:00
}
2020-11-11 19:31:05 +02:00
int snd_sof_volume_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
{
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = sm - > dobj . private ;
unsigned int channels = scontrol - > num_channels ;
int platform_max ;
if ( ! sm - > platform_max )
sm - > platform_max = sm - > max ;
platform_max = sm - > platform_max ;
if ( platform_max = = 1 & & ! strstr ( kcontrol - > id . name , " Volume " ) )
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
else
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = channels ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = platform_max - sm - > min ;
return 0 ;
}
2019-04-12 11:05:07 -05:00
int snd_sof_switch_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:32 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2022-03-17 10:50:32 -07:00
struct snd_soc_component * scomp = scontrol - > scomp ;
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2021-09-03 14:40:18 +03:00
2022-03-17 10:50:32 -07:00
if ( tplg_ops - > control - > switch_get )
return tplg_ops - > control - > switch_get ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
return 0 ;
}
int snd_sof_switch_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:32 -07:00
struct soc_mixer_control * sm = ( struct soc_mixer_control * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = sm - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:32 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2019-04-12 11:05:07 -05:00
2019-10-08 11:44:43 -05:00
if ( scontrol - > led_ctl . use_led )
update_mute_led ( scontrol , kcontrol , ucontrol ) ;
2022-03-17 10:50:32 -07:00
if ( tplg_ops - > control - > switch_put )
return tplg_ops - > control - > switch_put ( scontrol , ucontrol ) ;
2019-06-12 12:01:48 -05:00
2022-03-17 10:50:32 -07:00
return false ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_enum_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:33 -07:00
struct soc_enum * se = ( struct soc_enum * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = se - > dobj . private ;
2022-03-17 10:50:33 -07:00
struct snd_soc_component * scomp = scontrol - > scomp ;
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2021-09-03 14:40:18 +03:00
2022-03-17 10:50:33 -07:00
if ( tplg_ops - > control - > enum_get )
return tplg_ops - > control - > enum_get ( scontrol , ucontrol ) ;
2019-04-12 11:05:07 -05:00
return 0 ;
}
int snd_sof_enum_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
2022-03-17 10:50:33 -07:00
struct soc_enum * se = ( struct soc_enum * ) kcontrol - > private_value ;
2019-04-12 11:05:07 -05:00
struct snd_sof_control * scontrol = se - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-17 10:50:33 -07:00
struct snd_sof_dev * sdev = snd_soc_component_get_drvdata ( scomp ) ;
const struct sof_ipc_tplg_ops * tplg_ops = sdev - > ipc - > ops - > tplg ;
2019-04-12 11:05:07 -05:00
2022-03-17 10:50:33 -07:00
if ( tplg_ops - > control - > enum_put )
return tplg_ops - > control - > enum_put ( scontrol , ucontrol ) ;
2019-06-12 12:01:48 -05:00
2022-03-17 10:50:33 -07:00
return false ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_bytes_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct soc_bytes_ext * be =
( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-14 13:05:18 -07:00
struct sof_ipc_ctrl_data * cdata = scontrol - > ipc_control_data ;
2019-04-12 11:05:07 -05:00
struct sof_abi_hdr * data = cdata - > data ;
size_t size ;
2021-09-03 14:40:18 +03:00
snd_sof_refresh_control ( scontrol ) ;
2019-04-12 11:05:07 -05:00
if ( be - > max > sizeof ( ucontrol - > value . bytes . data ) ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev ,
2019-04-12 11:05:07 -05:00
" error: data max %d exceeds ucontrol data array size \n " ,
be - > max ) ;
return - EINVAL ;
}
2020-09-17 13:56:32 +03:00
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
if ( data - > size > be - > max - sizeof ( * data ) ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev ,
2020-09-17 13:56:32 +03:00
" error: %u bytes of control data is invalid, max is %zu \n " ,
data - > size , be - > max - sizeof ( * data ) ) ;
2020-09-17 13:56:30 +03:00
return - EINVAL ;
2019-04-12 11:05:07 -05:00
}
2020-09-17 13:56:32 +03:00
size = data - > size + sizeof ( * data ) ;
2019-04-12 11:05:07 -05:00
/* copy back to kcontrol */
memcpy ( ucontrol - > value . bytes . data , data , size ) ;
2020-09-17 13:56:30 +03:00
return 0 ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_bytes_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct soc_bytes_ext * be =
( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-14 13:05:18 -07:00
struct sof_ipc_ctrl_data * cdata = scontrol - > ipc_control_data ;
2019-04-12 11:05:07 -05:00
struct sof_abi_hdr * data = cdata - > data ;
2020-09-17 13:56:32 +03:00
size_t size ;
2019-04-12 11:05:07 -05:00
if ( be - > max > sizeof ( ucontrol - > value . bytes . data ) ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev ,
2019-04-12 11:05:07 -05:00
" error: data max %d exceeds ucontrol data array size \n " ,
be - > max ) ;
return - EINVAL ;
}
2020-09-17 13:56:32 +03:00
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
if ( data - > size > be - > max - sizeof ( * data ) ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev ,
2020-09-17 13:56:32 +03:00
" error: data size too big %u bytes max is %zu \n " ,
data - > size , be - > max - sizeof ( * data ) ) ;
2019-04-12 11:05:07 -05:00
return - EINVAL ;
}
2020-09-17 13:56:32 +03:00
size = data - > size + sizeof ( * data ) ;
2019-04-12 11:05:07 -05:00
/* copy from kcontrol */
2019-05-24 14:09:22 -05:00
memcpy ( data , ucontrol - > value . bytes . data , size ) ;
2019-04-12 11:05:07 -05:00
/* notify DSP of byte control updates */
2019-12-04 15:15:51 -06:00
if ( pm_runtime_active ( scomp - > dev ) )
2021-12-15 10:04:03 -08:00
snd_sof_ipc_set_get_comp_data ( scontrol , true ) ;
2019-06-12 12:01:48 -05:00
return 0 ;
2019-04-12 11:05:07 -05:00
}
int snd_sof_bytes_ext_put ( struct snd_kcontrol * kcontrol ,
const unsigned int __user * binary_data ,
unsigned int size )
{
struct soc_bytes_ext * be =
( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-14 13:05:18 -07:00
struct sof_ipc_ctrl_data * cdata = scontrol - > ipc_control_data ;
2019-04-12 11:05:07 -05:00
struct snd_ctl_tlv header ;
const struct snd_ctl_tlv __user * tlvd =
( const struct snd_ctl_tlv __user * ) binary_data ;
2020-09-21 14:08:12 +03:00
/* make sure we have at least a header */
if ( size < sizeof ( struct snd_ctl_tlv ) )
return - EINVAL ;
2019-04-12 11:05:07 -05:00
/*
* The beginning of bytes data contains a header from where
* the length ( as bytes ) is needed to know the correct copy
* length of data from tlvd - > tlv .
*/
2020-09-30 18:20:23 +03:00
if ( copy_from_user ( & header , tlvd , sizeof ( struct snd_ctl_tlv ) ) )
2019-04-12 11:05:07 -05:00
return - EFAULT ;
2020-09-21 14:08:12 +03:00
/* make sure TLV info is consistent */
if ( header . length + sizeof ( struct snd_ctl_tlv ) > size ) {
dev_err_ratelimited ( scomp - > dev , " error: inconsistent TLV, data %d + header %zu > %d \n " ,
header . length , sizeof ( struct snd_ctl_tlv ) , size ) ;
return - EINVAL ;
}
2019-04-12 11:05:07 -05:00
/* be->max is coming from topology */
if ( header . length > be - > max ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev , " error: Bytes data size %d exceeds max %d. \n " ,
2019-04-12 11:05:07 -05:00
header . length , be - > max ) ;
return - EINVAL ;
}
/* Check that header id matches the command */
2021-12-15 10:04:01 -08:00
if ( header . numid ! = cdata - > cmd ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev ,
2019-04-12 11:05:07 -05:00
" error: incorrect numid %d \n " ,
header . numid ) ;
return - EINVAL ;
}
if ( copy_from_user ( cdata - > data , tlvd - > tlv , header . length ) )
return - EFAULT ;
if ( cdata - > data - > magic ! = SOF_ABI_MAGIC ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev ,
2019-04-12 11:05:07 -05:00
" error: Wrong ABI magic 0x%08x. \n " ,
cdata - > data - > magic ) ;
return - EINVAL ;
}
if ( SOF_ABI_VERSION_INCOMPATIBLE ( SOF_ABI_VERSION , cdata - > data - > abi ) ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev , " error: Incompatible ABI version 0x%08x. \n " ,
2019-04-12 11:05:07 -05:00
cdata - > data - > abi ) ;
return - EINVAL ;
}
2020-09-17 13:56:32 +03:00
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
2020-09-30 18:20:23 +03:00
if ( cdata - > data - > size > be - > max - sizeof ( struct sof_abi_hdr ) ) {
2019-12-04 15:15:51 -06:00
dev_err_ratelimited ( scomp - > dev , " error: Mismatch in ABI data size (truncated?). \n " ) ;
2019-04-12 11:05:07 -05:00
return - EINVAL ;
}
/* notify DSP of byte control updates */
2019-12-04 15:15:51 -06:00
if ( pm_runtime_active ( scomp - > dev ) )
2021-12-15 10:04:03 -08:00
snd_sof_ipc_set_get_comp_data ( scontrol , true ) ;
2019-04-12 11:05:07 -05:00
2019-06-12 12:01:48 -05:00
return 0 ;
2019-04-12 11:05:07 -05:00
}
2020-09-08 12:28:25 +03:00
int snd_sof_bytes_ext_volatile_get ( struct snd_kcontrol * kcontrol , unsigned int __user * binary_data ,
unsigned int size )
{
struct soc_bytes_ext * be = ( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = be - > dobj . private ;
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-14 13:05:18 -07:00
struct sof_ipc_ctrl_data * cdata = scontrol - > ipc_control_data ;
2020-09-08 12:28:25 +03:00
struct snd_ctl_tlv header ;
struct snd_ctl_tlv __user * tlvd = ( struct snd_ctl_tlv __user * ) binary_data ;
size_t data_size ;
int ret ;
int err ;
2020-09-21 14:08:11 +03:00
/*
* Decrement the limit by ext bytes header size to
* ensure the user space buffer is not exceeded .
*/
if ( size < sizeof ( struct snd_ctl_tlv ) )
return - ENOSPC ;
size - = sizeof ( struct snd_ctl_tlv ) ;
2020-09-08 12:28:25 +03:00
ret = pm_runtime_get_sync ( scomp - > dev ) ;
2020-09-17 13:56:29 +03:00
if ( ret < 0 & & ret ! = - EACCES ) {
2020-09-08 12:28:25 +03:00
dev_err_ratelimited ( scomp - > dev , " error: bytes_ext get failed to resume %d \n " , ret ) ;
pm_runtime_put_noidle ( scomp - > dev ) ;
return ret ;
}
/* set the ABI header values */
cdata - > data - > magic = SOF_ABI_MAGIC ;
cdata - > data - > abi = SOF_ABI_VERSION ;
/* get all the component data from DSP */
2021-12-15 10:04:03 -08:00
ret = snd_sof_ipc_set_get_comp_data ( scontrol , false ) ;
2020-09-08 12:28:25 +03:00
if ( ret < 0 )
goto out ;
/* check data size doesn't exceed max coming from topology */
2020-09-30 18:20:23 +03:00
if ( cdata - > data - > size > be - > max - sizeof ( struct sof_abi_hdr ) ) {
2020-09-08 12:28:25 +03:00
dev_err_ratelimited ( scomp - > dev , " error: user data size %d exceeds max size %zu. \n " ,
cdata - > data - > size ,
2020-09-30 18:20:23 +03:00
be - > max - sizeof ( struct sof_abi_hdr ) ) ;
2020-09-08 12:28:25 +03:00
ret = - EINVAL ;
goto out ;
}
2020-09-30 18:20:23 +03:00
data_size = cdata - > data - > size + sizeof ( struct sof_abi_hdr ) ;
2020-09-08 12:28:25 +03:00
2020-09-21 14:08:11 +03:00
/* make sure we don't exceed size provided by user space for data */
if ( data_size > size ) {
ret = - ENOSPC ;
goto out ;
}
2021-12-15 10:04:01 -08:00
header . numid = cdata - > cmd ;
2020-09-08 12:28:25 +03:00
header . length = data_size ;
2020-09-30 18:20:23 +03:00
if ( copy_to_user ( tlvd , & header , sizeof ( struct snd_ctl_tlv ) ) ) {
2020-09-08 12:28:25 +03:00
ret = - EFAULT ;
goto out ;
}
if ( copy_to_user ( tlvd - > tlv , cdata - > data , data_size ) )
ret = - EFAULT ;
out :
pm_runtime_mark_last_busy ( scomp - > dev ) ;
err = pm_runtime_put_autosuspend ( scomp - > dev ) ;
if ( err < 0 )
dev_err_ratelimited ( scomp - > dev , " error: bytes_ext get failed to idle %d \n " , err ) ;
return ret ;
}
2019-04-12 11:05:07 -05:00
int snd_sof_bytes_ext_get ( struct snd_kcontrol * kcontrol ,
unsigned int __user * binary_data ,
unsigned int size )
{
struct soc_bytes_ext * be =
( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct snd_sof_control * scontrol = be - > dobj . private ;
2019-12-04 15:15:51 -06:00
struct snd_soc_component * scomp = scontrol - > scomp ;
2022-03-14 13:05:18 -07:00
struct sof_ipc_ctrl_data * cdata = scontrol - > ipc_control_data ;
2019-04-12 11:05:07 -05:00
struct snd_ctl_tlv header ;
struct snd_ctl_tlv __user * tlvd =
( struct snd_ctl_tlv __user * ) binary_data ;
2020-09-17 13:56:32 +03:00
size_t data_size ;
2019-04-12 11:05:07 -05:00
2021-09-03 14:40:18 +03:00
snd_sof_refresh_control ( scontrol ) ;
2019-04-12 11:05:07 -05:00
/*
* Decrement the limit by ext bytes header size to
* ensure the user space buffer is not exceeded .
*/
2020-09-21 14:08:10 +03:00
if ( size < sizeof ( struct snd_ctl_tlv ) )
return - ENOSPC ;
size - = sizeof ( struct snd_ctl_tlv ) ;
2019-04-12 11:05:07 -05:00
/* set the ABI header values */
cdata - > data - > magic = SOF_ABI_MAGIC ;
cdata - > data - > abi = SOF_ABI_VERSION ;
/* check data size doesn't exceed max coming from topology */
2020-09-30 18:20:23 +03:00
if ( cdata - > data - > size > be - > max - sizeof ( struct sof_abi_hdr ) ) {
2020-09-17 13:56:32 +03:00
dev_err_ratelimited ( scomp - > dev , " error: user data size %d exceeds max size %zu. \n " ,
cdata - > data - > size ,
2020-09-30 18:20:23 +03:00
be - > max - sizeof ( struct sof_abi_hdr ) ) ;
2020-09-17 13:56:30 +03:00
return - EINVAL ;
2019-04-12 11:05:07 -05:00
}
2020-09-30 18:20:23 +03:00
data_size = cdata - > data - > size + sizeof ( struct sof_abi_hdr ) ;
2020-09-17 13:56:32 +03:00
2020-09-21 14:08:10 +03:00
/* make sure we don't exceed size provided by user space for data */
if ( data_size > size )
return - ENOSPC ;
2021-12-15 10:04:01 -08:00
header . numid = cdata - > cmd ;
2019-04-12 11:05:07 -05:00
header . length = data_size ;
2020-09-30 18:20:23 +03:00
if ( copy_to_user ( tlvd , & header , sizeof ( struct snd_ctl_tlv ) ) )
2020-09-17 13:56:30 +03:00
return - EFAULT ;
2019-04-12 11:05:07 -05:00
if ( copy_to_user ( tlvd - > tlv , cdata - > data , data_size ) )
2020-09-17 13:56:30 +03:00
return - EFAULT ;
2019-04-12 11:05:07 -05:00
2020-09-17 13:56:30 +03:00
return 0 ;
2019-04-12 11:05:07 -05:00
}