162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * compat ioctls for control API 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) by Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* this file included from control.c */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/compat.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistruct snd_ctl_elem_list32 { 1462306a36Sopenharmony_ci u32 offset; 1562306a36Sopenharmony_ci u32 space; 1662306a36Sopenharmony_ci u32 used; 1762306a36Sopenharmony_ci u32 count; 1862306a36Sopenharmony_ci u32 pids; 1962306a36Sopenharmony_ci unsigned char reserved[50]; 2062306a36Sopenharmony_ci} /* don't set packed attribute here */; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic int snd_ctl_elem_list_compat(struct snd_card *card, 2362306a36Sopenharmony_ci struct snd_ctl_elem_list32 __user *data32) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct snd_ctl_elem_list data = {}; 2662306a36Sopenharmony_ci compat_caddr_t ptr; 2762306a36Sopenharmony_ci int err; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* offset, space, used, count */ 3062306a36Sopenharmony_ci if (copy_from_user(&data, data32, 4 * sizeof(u32))) 3162306a36Sopenharmony_ci return -EFAULT; 3262306a36Sopenharmony_ci /* pids */ 3362306a36Sopenharmony_ci if (get_user(ptr, &data32->pids)) 3462306a36Sopenharmony_ci return -EFAULT; 3562306a36Sopenharmony_ci data.pids = compat_ptr(ptr); 3662306a36Sopenharmony_ci err = snd_ctl_elem_list(card, &data); 3762306a36Sopenharmony_ci if (err < 0) 3862306a36Sopenharmony_ci return err; 3962306a36Sopenharmony_ci /* copy the result */ 4062306a36Sopenharmony_ci if (copy_to_user(data32, &data, 4 * sizeof(u32))) 4162306a36Sopenharmony_ci return -EFAULT; 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * control element info 4762306a36Sopenharmony_ci * it uses union, so the things are not easy.. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct snd_ctl_elem_info32 { 5162306a36Sopenharmony_ci struct snd_ctl_elem_id id; // the size of struct is same 5262306a36Sopenharmony_ci s32 type; 5362306a36Sopenharmony_ci u32 access; 5462306a36Sopenharmony_ci u32 count; 5562306a36Sopenharmony_ci s32 owner; 5662306a36Sopenharmony_ci union { 5762306a36Sopenharmony_ci struct { 5862306a36Sopenharmony_ci s32 min; 5962306a36Sopenharmony_ci s32 max; 6062306a36Sopenharmony_ci s32 step; 6162306a36Sopenharmony_ci } integer; 6262306a36Sopenharmony_ci struct { 6362306a36Sopenharmony_ci u64 min; 6462306a36Sopenharmony_ci u64 max; 6562306a36Sopenharmony_ci u64 step; 6662306a36Sopenharmony_ci } integer64; 6762306a36Sopenharmony_ci struct { 6862306a36Sopenharmony_ci u32 items; 6962306a36Sopenharmony_ci u32 item; 7062306a36Sopenharmony_ci char name[64]; 7162306a36Sopenharmony_ci u64 names_ptr; 7262306a36Sopenharmony_ci u32 names_length; 7362306a36Sopenharmony_ci } enumerated; 7462306a36Sopenharmony_ci unsigned char reserved[128]; 7562306a36Sopenharmony_ci } value; 7662306a36Sopenharmony_ci unsigned char reserved[64]; 7762306a36Sopenharmony_ci} __attribute__((packed)); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, 8062306a36Sopenharmony_ci struct snd_ctl_elem_info32 __user *data32) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct snd_ctl_elem_info *data; 8362306a36Sopenharmony_ci int err; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 8662306a36Sopenharmony_ci if (! data) 8762306a36Sopenharmony_ci return -ENOMEM; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci err = -EFAULT; 9062306a36Sopenharmony_ci /* copy id */ 9162306a36Sopenharmony_ci if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) 9262306a36Sopenharmony_ci goto error; 9362306a36Sopenharmony_ci /* we need to copy the item index. 9462306a36Sopenharmony_ci * hope this doesn't break anything.. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) 9762306a36Sopenharmony_ci goto error; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci err = snd_ctl_elem_info(ctl, data); 10062306a36Sopenharmony_ci if (err < 0) 10162306a36Sopenharmony_ci goto error; 10262306a36Sopenharmony_ci /* restore info to 32bit */ 10362306a36Sopenharmony_ci err = -EFAULT; 10462306a36Sopenharmony_ci /* id, type, access, count */ 10562306a36Sopenharmony_ci if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) || 10662306a36Sopenharmony_ci copy_to_user(&data32->type, &data->type, 3 * sizeof(u32))) 10762306a36Sopenharmony_ci goto error; 10862306a36Sopenharmony_ci if (put_user(data->owner, &data32->owner)) 10962306a36Sopenharmony_ci goto error; 11062306a36Sopenharmony_ci switch (data->type) { 11162306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 11262306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_INTEGER: 11362306a36Sopenharmony_ci if (put_user(data->value.integer.min, &data32->value.integer.min) || 11462306a36Sopenharmony_ci put_user(data->value.integer.max, &data32->value.integer.max) || 11562306a36Sopenharmony_ci put_user(data->value.integer.step, &data32->value.integer.step)) 11662306a36Sopenharmony_ci goto error; 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_INTEGER64: 11962306a36Sopenharmony_ci if (copy_to_user(&data32->value.integer64, 12062306a36Sopenharmony_ci &data->value.integer64, 12162306a36Sopenharmony_ci sizeof(data->value.integer64))) 12262306a36Sopenharmony_ci goto error; 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 12562306a36Sopenharmony_ci if (copy_to_user(&data32->value.enumerated, 12662306a36Sopenharmony_ci &data->value.enumerated, 12762306a36Sopenharmony_ci sizeof(data->value.enumerated))) 12862306a36Sopenharmony_ci goto error; 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci default: 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci err = 0; 13462306a36Sopenharmony_ci error: 13562306a36Sopenharmony_ci kfree(data); 13662306a36Sopenharmony_ci return err; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* read / write */ 14062306a36Sopenharmony_cistruct snd_ctl_elem_value32 { 14162306a36Sopenharmony_ci struct snd_ctl_elem_id id; 14262306a36Sopenharmony_ci unsigned int indirect; /* bit-field causes misalignment */ 14362306a36Sopenharmony_ci union { 14462306a36Sopenharmony_ci s32 integer[128]; 14562306a36Sopenharmony_ci unsigned char data[512]; 14662306a36Sopenharmony_ci#ifndef CONFIG_X86_64 14762306a36Sopenharmony_ci s64 integer64[64]; 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci } value; 15062306a36Sopenharmony_ci unsigned char reserved[128]; 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#ifdef CONFIG_X86_X32_ABI 15462306a36Sopenharmony_ci/* x32 has a different alignment for 64bit values from ia32 */ 15562306a36Sopenharmony_cistruct snd_ctl_elem_value_x32 { 15662306a36Sopenharmony_ci struct snd_ctl_elem_id id; 15762306a36Sopenharmony_ci unsigned int indirect; /* bit-field causes misalignment */ 15862306a36Sopenharmony_ci union { 15962306a36Sopenharmony_ci s32 integer[128]; 16062306a36Sopenharmony_ci unsigned char data[512]; 16162306a36Sopenharmony_ci s64 integer64[64]; 16262306a36Sopenharmony_ci } value; 16362306a36Sopenharmony_ci unsigned char reserved[128]; 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci#endif /* CONFIG_X86_X32_ABI */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* get the value type and count of the control */ 16862306a36Sopenharmony_cistatic int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, 16962306a36Sopenharmony_ci int *countp) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct snd_kcontrol *kctl; 17262306a36Sopenharmony_ci struct snd_ctl_elem_info *info; 17362306a36Sopenharmony_ci int err; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci down_read(&card->controls_rwsem); 17662306a36Sopenharmony_ci kctl = snd_ctl_find_id_locked(card, id); 17762306a36Sopenharmony_ci if (! kctl) { 17862306a36Sopenharmony_ci up_read(&card->controls_rwsem); 17962306a36Sopenharmony_ci return -ENOENT; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 18262306a36Sopenharmony_ci if (info == NULL) { 18362306a36Sopenharmony_ci up_read(&card->controls_rwsem); 18462306a36Sopenharmony_ci return -ENOMEM; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci info->id = *id; 18762306a36Sopenharmony_ci err = snd_power_ref_and_wait(card); 18862306a36Sopenharmony_ci if (!err) 18962306a36Sopenharmony_ci err = kctl->info(kctl, info); 19062306a36Sopenharmony_ci snd_power_unref(card); 19162306a36Sopenharmony_ci up_read(&card->controls_rwsem); 19262306a36Sopenharmony_ci if (err >= 0) { 19362306a36Sopenharmony_ci err = info->type; 19462306a36Sopenharmony_ci *countp = info->count; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci kfree(info); 19762306a36Sopenharmony_ci return err; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int get_elem_size(snd_ctl_elem_type_t type, int count) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci switch (type) { 20362306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_INTEGER64: 20462306a36Sopenharmony_ci return sizeof(s64) * count; 20562306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 20662306a36Sopenharmony_ci return sizeof(int) * count; 20762306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_BYTES: 20862306a36Sopenharmony_ci return 512; 20962306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_IEC958: 21062306a36Sopenharmony_ci return sizeof(struct snd_aes_iec958); 21162306a36Sopenharmony_ci default: 21262306a36Sopenharmony_ci return -1; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int copy_ctl_value_from_user(struct snd_card *card, 21762306a36Sopenharmony_ci struct snd_ctl_elem_value *data, 21862306a36Sopenharmony_ci void __user *userdata, 21962306a36Sopenharmony_ci void __user *valuep, 22062306a36Sopenharmony_ci int *typep, int *countp) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct snd_ctl_elem_value32 __user *data32 = userdata; 22362306a36Sopenharmony_ci int i, type, size; 22462306a36Sopenharmony_ci int count; 22562306a36Sopenharmony_ci unsigned int indirect; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) 22862306a36Sopenharmony_ci return -EFAULT; 22962306a36Sopenharmony_ci if (get_user(indirect, &data32->indirect)) 23062306a36Sopenharmony_ci return -EFAULT; 23162306a36Sopenharmony_ci if (indirect) 23262306a36Sopenharmony_ci return -EINVAL; 23362306a36Sopenharmony_ci type = get_ctl_type(card, &data->id, &count); 23462306a36Sopenharmony_ci if (type < 0) 23562306a36Sopenharmony_ci return type; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN || 23862306a36Sopenharmony_ci type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) { 23962306a36Sopenharmony_ci for (i = 0; i < count; i++) { 24062306a36Sopenharmony_ci s32 __user *intp = valuep; 24162306a36Sopenharmony_ci int val; 24262306a36Sopenharmony_ci if (get_user(val, &intp[i])) 24362306a36Sopenharmony_ci return -EFAULT; 24462306a36Sopenharmony_ci data->value.integer.value[i] = val; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci size = get_elem_size((__force snd_ctl_elem_type_t)type, count); 24862306a36Sopenharmony_ci if (size < 0) { 24962306a36Sopenharmony_ci dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); 25062306a36Sopenharmony_ci return -EINVAL; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci if (copy_from_user(data->value.bytes.data, valuep, size)) 25362306a36Sopenharmony_ci return -EFAULT; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci *typep = type; 25762306a36Sopenharmony_ci *countp = count; 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* restore the value to 32bit */ 26262306a36Sopenharmony_cistatic int copy_ctl_value_to_user(void __user *userdata, 26362306a36Sopenharmony_ci void __user *valuep, 26462306a36Sopenharmony_ci struct snd_ctl_elem_value *data, 26562306a36Sopenharmony_ci int type, int count) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct snd_ctl_elem_value32 __user *data32 = userdata; 26862306a36Sopenharmony_ci int i, size; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN || 27162306a36Sopenharmony_ci type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) { 27262306a36Sopenharmony_ci for (i = 0; i < count; i++) { 27362306a36Sopenharmony_ci s32 __user *intp = valuep; 27462306a36Sopenharmony_ci int val; 27562306a36Sopenharmony_ci val = data->value.integer.value[i]; 27662306a36Sopenharmony_ci if (put_user(val, &intp[i])) 27762306a36Sopenharmony_ci return -EFAULT; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } else { 28062306a36Sopenharmony_ci size = get_elem_size((__force snd_ctl_elem_type_t)type, count); 28162306a36Sopenharmony_ci if (copy_to_user(valuep, data->value.bytes.data, size)) 28262306a36Sopenharmony_ci return -EFAULT; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci if (copy_to_user(&data32->id, &data->id, sizeof(data32->id))) 28562306a36Sopenharmony_ci return -EFAULT; 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int ctl_elem_read_user(struct snd_card *card, 29062306a36Sopenharmony_ci void __user *userdata, void __user *valuep) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct snd_ctl_elem_value *data; 29362306a36Sopenharmony_ci int err, type, count; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 29662306a36Sopenharmony_ci if (data == NULL) 29762306a36Sopenharmony_ci return -ENOMEM; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci err = copy_ctl_value_from_user(card, data, userdata, valuep, 30062306a36Sopenharmony_ci &type, &count); 30162306a36Sopenharmony_ci if (err < 0) 30262306a36Sopenharmony_ci goto error; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci err = snd_ctl_elem_read(card, data); 30562306a36Sopenharmony_ci if (err < 0) 30662306a36Sopenharmony_ci goto error; 30762306a36Sopenharmony_ci err = copy_ctl_value_to_user(userdata, valuep, data, type, count); 30862306a36Sopenharmony_ci error: 30962306a36Sopenharmony_ci kfree(data); 31062306a36Sopenharmony_ci return err; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int ctl_elem_write_user(struct snd_ctl_file *file, 31462306a36Sopenharmony_ci void __user *userdata, void __user *valuep) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct snd_ctl_elem_value *data; 31762306a36Sopenharmony_ci struct snd_card *card = file->card; 31862306a36Sopenharmony_ci int err, type, count; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 32162306a36Sopenharmony_ci if (data == NULL) 32262306a36Sopenharmony_ci return -ENOMEM; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci err = copy_ctl_value_from_user(card, data, userdata, valuep, 32562306a36Sopenharmony_ci &type, &count); 32662306a36Sopenharmony_ci if (err < 0) 32762306a36Sopenharmony_ci goto error; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci err = snd_ctl_elem_write(card, file, data); 33062306a36Sopenharmony_ci if (err < 0) 33162306a36Sopenharmony_ci goto error; 33262306a36Sopenharmony_ci err = copy_ctl_value_to_user(userdata, valuep, data, type, count); 33362306a36Sopenharmony_ci error: 33462306a36Sopenharmony_ci kfree(data); 33562306a36Sopenharmony_ci return err; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int snd_ctl_elem_read_user_compat(struct snd_card *card, 33962306a36Sopenharmony_ci struct snd_ctl_elem_value32 __user *data32) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci return ctl_elem_read_user(card, data32, &data32->value); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, 34562306a36Sopenharmony_ci struct snd_ctl_elem_value32 __user *data32) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci return ctl_elem_write_user(file, data32, &data32->value); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci#ifdef CONFIG_X86_X32_ABI 35162306a36Sopenharmony_cistatic int snd_ctl_elem_read_user_x32(struct snd_card *card, 35262306a36Sopenharmony_ci struct snd_ctl_elem_value_x32 __user *data32) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci return ctl_elem_read_user(card, data32, &data32->value); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file, 35862306a36Sopenharmony_ci struct snd_ctl_elem_value_x32 __user *data32) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return ctl_elem_write_user(file, data32, &data32->value); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci#endif /* CONFIG_X86_X32_ABI */ 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/* add or replace a user control */ 36562306a36Sopenharmony_cistatic int snd_ctl_elem_add_compat(struct snd_ctl_file *file, 36662306a36Sopenharmony_ci struct snd_ctl_elem_info32 __user *data32, 36762306a36Sopenharmony_ci int replace) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct snd_ctl_elem_info *data; 37062306a36Sopenharmony_ci int err; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 37362306a36Sopenharmony_ci if (! data) 37462306a36Sopenharmony_ci return -ENOMEM; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci err = -EFAULT; 37762306a36Sopenharmony_ci /* id, type, access, count */ \ 37862306a36Sopenharmony_ci if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || 37962306a36Sopenharmony_ci copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) 38062306a36Sopenharmony_ci goto error; 38162306a36Sopenharmony_ci if (get_user(data->owner, &data32->owner)) 38262306a36Sopenharmony_ci goto error; 38362306a36Sopenharmony_ci switch (data->type) { 38462306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 38562306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_INTEGER: 38662306a36Sopenharmony_ci if (get_user(data->value.integer.min, &data32->value.integer.min) || 38762306a36Sopenharmony_ci get_user(data->value.integer.max, &data32->value.integer.max) || 38862306a36Sopenharmony_ci get_user(data->value.integer.step, &data32->value.integer.step)) 38962306a36Sopenharmony_ci goto error; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_INTEGER64: 39262306a36Sopenharmony_ci if (copy_from_user(&data->value.integer64, 39362306a36Sopenharmony_ci &data32->value.integer64, 39462306a36Sopenharmony_ci sizeof(data->value.integer64))) 39562306a36Sopenharmony_ci goto error; 39662306a36Sopenharmony_ci break; 39762306a36Sopenharmony_ci case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 39862306a36Sopenharmony_ci if (copy_from_user(&data->value.enumerated, 39962306a36Sopenharmony_ci &data32->value.enumerated, 40062306a36Sopenharmony_ci sizeof(data->value.enumerated))) 40162306a36Sopenharmony_ci goto error; 40262306a36Sopenharmony_ci data->value.enumerated.names_ptr = 40362306a36Sopenharmony_ci (uintptr_t)compat_ptr(data->value.enumerated.names_ptr); 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci default: 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci err = snd_ctl_elem_add(file, data, replace); 40962306a36Sopenharmony_ci error: 41062306a36Sopenharmony_ci kfree(data); 41162306a36Sopenharmony_ci return err; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cienum { 41562306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32), 41662306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct snd_ctl_elem_info32), 41762306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct snd_ctl_elem_value32), 41862306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32), 41962306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32), 42062306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32), 42162306a36Sopenharmony_ci#ifdef CONFIG_X86_X32_ABI 42262306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32), 42362306a36Sopenharmony_ci SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32), 42462306a36Sopenharmony_ci#endif /* CONFIG_X86_X32_ABI */ 42562306a36Sopenharmony_ci}; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct snd_ctl_file *ctl; 43062306a36Sopenharmony_ci struct snd_kctl_ioctl *p; 43162306a36Sopenharmony_ci void __user *argp = compat_ptr(arg); 43262306a36Sopenharmony_ci int err; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ctl = file->private_data; 43562306a36Sopenharmony_ci if (snd_BUG_ON(!ctl || !ctl->card)) 43662306a36Sopenharmony_ci return -ENXIO; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci switch (cmd) { 43962306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_PVERSION: 44062306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_CARD_INFO: 44162306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: 44262306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_POWER: 44362306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_POWER_STATE: 44462306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_LOCK: 44562306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_UNLOCK: 44662306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_REMOVE: 44762306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_TLV_READ: 44862306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_TLV_WRITE: 44962306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_TLV_COMMAND: 45062306a36Sopenharmony_ci return snd_ctl_ioctl(file, cmd, (unsigned long)argp); 45162306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_LIST32: 45262306a36Sopenharmony_ci return snd_ctl_elem_list_compat(ctl->card, argp); 45362306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_INFO32: 45462306a36Sopenharmony_ci return snd_ctl_elem_info_compat(ctl, argp); 45562306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_READ32: 45662306a36Sopenharmony_ci return snd_ctl_elem_read_user_compat(ctl->card, argp); 45762306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_WRITE32: 45862306a36Sopenharmony_ci return snd_ctl_elem_write_user_compat(ctl, argp); 45962306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_ADD32: 46062306a36Sopenharmony_ci return snd_ctl_elem_add_compat(ctl, argp, 0); 46162306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_REPLACE32: 46262306a36Sopenharmony_ci return snd_ctl_elem_add_compat(ctl, argp, 1); 46362306a36Sopenharmony_ci#ifdef CONFIG_X86_X32_ABI 46462306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_READ_X32: 46562306a36Sopenharmony_ci return snd_ctl_elem_read_user_x32(ctl->card, argp); 46662306a36Sopenharmony_ci case SNDRV_CTL_IOCTL_ELEM_WRITE_X32: 46762306a36Sopenharmony_ci return snd_ctl_elem_write_user_x32(ctl, argp); 46862306a36Sopenharmony_ci#endif /* CONFIG_X86_X32_ABI */ 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci down_read(&snd_ioctl_rwsem); 47262306a36Sopenharmony_ci list_for_each_entry(p, &snd_control_compat_ioctls, list) { 47362306a36Sopenharmony_ci if (p->fioctl) { 47462306a36Sopenharmony_ci err = p->fioctl(ctl->card, ctl, cmd, arg); 47562306a36Sopenharmony_ci if (err != -ENOIOCTLCMD) { 47662306a36Sopenharmony_ci up_read(&snd_ioctl_rwsem); 47762306a36Sopenharmony_ci return err; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci up_read(&snd_ioctl_rwsem); 48262306a36Sopenharmony_ci return -ENOIOCTLCMD; 48362306a36Sopenharmony_ci} 484