mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 23:34:05 +08:00
ALSA: control: code refactoring for TLV request handler to user element set
User-defined element set registers own handler to get callbacks from TLV ioctl handler. In the handler, execution path bifurcates depending on requests from user space. At write request, container in given buffer is registered to the element set, or replaced old TLV data. At the read request, the registered data is copied to user space. The command request is not allowed. In current implementation, function of the handler includes codes for the two cases. This commit adds two helper functions for these cases so that readers can easily get the above design. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
450296f305
commit
6d4d41f011
@ -1114,43 +1114,59 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
|
||||
return change;
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
|
||||
int op_flag,
|
||||
unsigned int size,
|
||||
unsigned int __user *tlv)
|
||||
static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
struct user_element *ue = kcontrol->private_data;
|
||||
struct user_element *ue = kctl->private_data;
|
||||
unsigned int *container;
|
||||
int change;
|
||||
|
||||
if (op_flag == SNDRV_CTL_TLV_OP_WRITE) {
|
||||
int change;
|
||||
void *new_data;
|
||||
if (size > 1024 * 128) /* sane value */
|
||||
return -EINVAL;
|
||||
|
||||
if (size > 1024 * 128) /* sane value */
|
||||
return -EINVAL;
|
||||
|
||||
new_data = memdup_user(tlv, size);
|
||||
if (IS_ERR(new_data))
|
||||
return PTR_ERR(new_data);
|
||||
change = ue->tlv_data_size != size;
|
||||
if (!change)
|
||||
change = memcmp(ue->tlv_data, new_data, size);
|
||||
kfree(ue->tlv_data);
|
||||
ue->tlv_data = new_data;
|
||||
ue->tlv_data_size = size;
|
||||
|
||||
return change;
|
||||
} else {
|
||||
if (!ue->tlv_data_size || !ue->tlv_data)
|
||||
return -ENXIO;
|
||||
|
||||
if (size < ue->tlv_data_size)
|
||||
return -ENOSPC;
|
||||
|
||||
if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
|
||||
return -EFAULT;
|
||||
container = memdup_user(buf, size);
|
||||
if (IS_ERR(container))
|
||||
return PTR_ERR(container);
|
||||
|
||||
change = ue->tlv_data_size != size;
|
||||
if (!change)
|
||||
change = memcmp(ue->tlv_data, container, size);
|
||||
if (!change) {
|
||||
kfree(container);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kfree(ue->tlv_data);
|
||||
ue->tlv_data = container;
|
||||
ue->tlv_data_size = size;
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
static int read_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
struct user_element *ue = kctl->private_data;
|
||||
|
||||
if (ue->tlv_data_size == 0 || ue->tlv_data == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
if (size < ue->tlv_data_size)
|
||||
return -ENOSPC;
|
||||
|
||||
if (copy_to_user(buf, ue->tlv_data, ue->tlv_data_size))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag,
|
||||
unsigned int size, unsigned int __user *buf)
|
||||
{
|
||||
if (op_flag == SNDRV_CTL_TLV_OP_WRITE)
|
||||
return replace_user_tlv(kctl, buf, size);
|
||||
else
|
||||
return read_user_tlv(kctl, buf, size);
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_init_enum_names(struct user_element *ue)
|
||||
|
Loading…
Reference in New Issue
Block a user