diff options
Diffstat (limited to 'sound/core/control_compat.c')
| -rw-r--r-- | sound/core/control_compat.c | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 418c6d4e5da..b9c0910fb8c 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -21,6 +21,7 @@ /* this file included from control.c */ #include <linux/compat.h> +#include <linux/slab.h> struct snd_ctl_elem_list32 { u32 offset; @@ -82,6 +83,8 @@ struct snd_ctl_elem_info32 { u32 items; u32 item; char name[64]; + u64 names_ptr; + u32 names_length; } enumerated; unsigned char reserved[128]; } value; @@ -107,7 +110,13 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, */ 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 */ @@ -167,7 +176,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, int *countp) { struct snd_kcontrol *kctl; - struct snd_ctl_elem_info info; + struct snd_ctl_elem_info *info; int err; down_read(&card->controls_rwsem); @@ -176,13 +185,19 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, 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; } @@ -207,7 +222,8 @@ static int copy_ctl_value_from_user(struct snd_card *card, 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))) @@ -231,7 +247,7 @@ static int copy_ctl_value_from_user(struct snd_card *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, @@ -280,9 +296,14 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *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; @@ -292,17 +313,23 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, struct snd_ctl_elem_value32 __user *data32) { 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; @@ -347,6 +374,8 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *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; @@ -369,12 +398,13 @@ enum { static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_ctl_file *ctl; - struct list_head *list; + 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: @@ -384,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); @@ -400,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) { - struct snd_kctl_ioctl *p = list_entry(list, struct snd_kctl_ioctl, 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) { |
