diff options
Diffstat (limited to 'sound/core/control_compat.c')
| -rw-r--r-- | sound/core/control_compat.c | 140 |
1 files changed, 88 insertions, 52 deletions
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 207c7de5129..b9c0910fb8c 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -21,8 +21,9 @@ /* this file included from control.c */ #include <linux/compat.h> +#include <linux/slab.h> -struct sndrv_ctl_elem_list32 { +struct snd_ctl_elem_list32 { u32 offset; u32 space; u32 used; @@ -31,9 +32,10 @@ struct sndrv_ctl_elem_list32 { unsigned char reserved[50]; } /* don't set packed attribute here */; -static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list32 __user *data32) +static int snd_ctl_elem_list_compat(struct snd_card *card, + struct snd_ctl_elem_list32 __user *data32) { - struct sndrv_ctl_elem_list __user *data; + struct snd_ctl_elem_list __user *data; compat_caddr_t ptr; int err; @@ -60,8 +62,8 @@ static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list * it uses union, so the things are not easy.. */ -struct sndrv_ctl_elem_info32 { - struct sndrv_ctl_elem_id id; // the size of struct is same +struct snd_ctl_elem_info32 { + struct snd_ctl_elem_id id; // the size of struct is same s32 type; u32 access; u32 count; @@ -81,15 +83,18 @@ struct sndrv_ctl_elem_info32 { u32 items; u32 item; char name[64]; + u64 names_ptr; + u32 names_length; } enumerated; unsigned char reserved[128]; } value; unsigned char reserved[64]; } __attribute__((packed)); -static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_info32 __user *data32) +static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, + struct snd_ctl_elem_info32 __user *data32) { - struct sndrv_ctl_elem_info *data; + struct snd_ctl_elem_info *data; int err; data = kzalloc(sizeof(*data), GFP_KERNEL); @@ -105,7 +110,13 @@ static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_i */ if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) goto error; - err = snd_ctl_elem_info(ctl, data); + + snd_power_lock(ctl->card); + err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); + if (err >= 0) + err = snd_ctl_elem_info(ctl, data); + snd_power_unlock(ctl->card); + if (err < 0) goto error; /* restore info to 32bit */ @@ -146,8 +157,8 @@ static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_i } /* read / write */ -struct sndrv_ctl_elem_value32 { - struct sndrv_ctl_elem_id id; +struct snd_ctl_elem_value32 { + struct snd_ctl_elem_id id; unsigned int indirect; /* bit-field causes misalignment */ union { s32 integer[128]; @@ -161,10 +172,11 @@ struct sndrv_ctl_elem_value32 { /* get the value type and count of the control */ -static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp) +static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, + int *countp) { - snd_kcontrol_t *kctl; - snd_ctl_elem_info_t info; + struct snd_kcontrol *kctl; + struct snd_ctl_elem_info *info; int err; down_read(&card->controls_rwsem); @@ -173,13 +185,19 @@ static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp) up_read(&card->controls_rwsem); return -ENXIO; } - info.id = *id; - err = kctl->info(kctl, &info); + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + up_read(&card->controls_rwsem); + return -ENOMEM; + } + info->id = *id; + err = kctl->info(kctl, info); up_read(&card->controls_rwsem); if (err >= 0) { - err = info.type; - *countp = info.count; + err = info->type; + *countp = info->count; } + kfree(info); return err; } @@ -193,18 +211,19 @@ static int get_elem_size(int type, int count) case SNDRV_CTL_ELEM_TYPE_BYTES: return 512; case SNDRV_CTL_ELEM_TYPE_IEC958: - return sizeof(struct sndrv_aes_iec958); + return sizeof(struct snd_aes_iec958); default: return -1; } } -static int copy_ctl_value_from_user(snd_card_t *card, - struct sndrv_ctl_elem_value *data, - struct sndrv_ctl_elem_value32 __user *data32, +static int copy_ctl_value_from_user(struct snd_card *card, + struct snd_ctl_elem_value *data, + struct snd_ctl_elem_value32 __user *data32, int *typep, int *countp) { - int i, type, count, size; + int i, type, size; + int uninitialized_var(count); unsigned int indirect; if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) @@ -228,7 +247,7 @@ static int copy_ctl_value_from_user(snd_card_t *card, } else { size = get_elem_size(type, count); if (size < 0) { - printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); + dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); return -EINVAL; } if (copy_from_user(data->value.bytes.data, @@ -242,8 +261,8 @@ static int copy_ctl_value_from_user(snd_card_t *card, } /* restore the value to 32bit */ -static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32, - struct sndrv_ctl_elem_value *data, +static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, + struct snd_ctl_elem_value *data, int type, int count) { int i, size; @@ -265,10 +284,10 @@ static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32, return 0; } -static int snd_ctl_elem_read_user_compat(snd_card_t *card, - struct sndrv_ctl_elem_value32 __user *data32) +static int snd_ctl_elem_read_user_compat(struct snd_card *card, + struct snd_ctl_elem_value32 __user *data32) { - struct sndrv_ctl_elem_value *data; + struct snd_ctl_elem_value *data; int err, type, count; data = kzalloc(sizeof(*data), GFP_KERNEL); @@ -277,40 +296,51 @@ static int snd_ctl_elem_read_user_compat(snd_card_t *card, if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) goto error; - if ((err = snd_ctl_elem_read(card, data)) < 0) - goto error; - err = copy_ctl_value_to_user(data32, data, type, count); + + snd_power_lock(card); + err = snd_power_wait(card, SNDRV_CTL_POWER_D0); + if (err >= 0) + err = snd_ctl_elem_read(card, data); + snd_power_unlock(card); + if (err >= 0) + err = copy_ctl_value_to_user(data32, data, type, count); error: kfree(data); return err; } -static int snd_ctl_elem_write_user_compat(snd_ctl_file_t *file, - struct sndrv_ctl_elem_value32 __user *data32) +static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, + struct snd_ctl_elem_value32 __user *data32) { - struct sndrv_ctl_elem_value *data; + struct snd_ctl_elem_value *data; + struct snd_card *card = file->card; int err, type, count; data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - if ((err = copy_ctl_value_from_user(file->card, data, data32, &type, &count)) < 0) - goto error; - if ((err = snd_ctl_elem_write(file->card, file, data)) < 0) + if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) goto error; - err = copy_ctl_value_to_user(data32, data, type, count); + + snd_power_lock(card); + err = snd_power_wait(card, SNDRV_CTL_POWER_D0); + if (err >= 0) + err = snd_ctl_elem_write(card, file, data); + snd_power_unlock(card); + if (err >= 0) + err = copy_ctl_value_to_user(data32, data, type, count); error: kfree(data); return err; } /* add or replace a user control */ -static int snd_ctl_elem_add_compat(snd_ctl_file_t *file, - struct sndrv_ctl_elem_info32 __user *data32, +static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, + struct snd_ctl_elem_info32 __user *data32, int replace) { - struct sndrv_ctl_elem_info *data; + struct snd_ctl_elem_info *data; int err; data = kzalloc(sizeof(*data), GFP_KERNEL); @@ -344,6 +374,8 @@ static int snd_ctl_elem_add_compat(snd_ctl_file_t *file, &data32->value.enumerated, sizeof(data->value.enumerated))) goto error; + data->value.enumerated.names_ptr = + (uintptr_t)compat_ptr(data->value.enumerated.names_ptr); break; default: break; @@ -355,23 +387,24 @@ static int snd_ctl_elem_add_compat(snd_ctl_file_t *file, } enum { - SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32), - SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32), - SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32), - SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32), - SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct sndrv_ctl_elem_info32), - SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct sndrv_ctl_elem_info32), + SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32), + SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct snd_ctl_elem_info32), + SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct snd_ctl_elem_value32), + SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32), + SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32), + SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32), }; static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { - snd_ctl_file_t *ctl; - struct list_head *list; + struct snd_ctl_file *ctl; + struct snd_kctl_ioctl *p; void __user *argp = compat_ptr(arg); int err; ctl = file->private_data; - snd_assert(ctl && ctl->card, return -ENXIO); + if (snd_BUG_ON(!ctl || !ctl->card)) + return -ENXIO; switch (cmd) { case SNDRV_CTL_IOCTL_PVERSION: @@ -381,6 +414,10 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns case SNDRV_CTL_IOCTL_POWER_STATE: case SNDRV_CTL_IOCTL_ELEM_LOCK: case SNDRV_CTL_IOCTL_ELEM_UNLOCK: + case SNDRV_CTL_IOCTL_ELEM_REMOVE: + case SNDRV_CTL_IOCTL_TLV_READ: + case SNDRV_CTL_IOCTL_TLV_WRITE: + case SNDRV_CTL_IOCTL_TLV_COMMAND: return snd_ctl_ioctl(file, cmd, (unsigned long)argp); case SNDRV_CTL_IOCTL_ELEM_LIST32: return snd_ctl_elem_list_compat(ctl->card, argp); @@ -397,8 +434,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns } down_read(&snd_ioctl_rwsem); - list_for_each(list, &snd_control_compat_ioctls) { - snd_kctl_ioctl_t *p = list_entry(list, snd_kctl_ioctl_t, list); + list_for_each_entry(p, &snd_control_compat_ioctls, list) { if (p->fioctl) { err = p->fioctl(ctl->card, ctl, cmd, arg); if (err != -ENOIOCTLCMD) { |
