lkml.org 
[lkml]   [2005]   [Jan]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 1/3] Conversion to compat_ioctl for ALSA drivers
    This patch modifies Kconfig and Makefile to remove snd-ioctl32.
    It convers to unlocked_ioctl, and adds the compat_ioctl entries.
    New register/unregister functions for compat ioctl are added.

    Signed-off-by: Takashi Iwai <tiwai@suse.de>


    --- linux/sound/core/Kconfig 23 Nov 2004 14:49:03 -0000 1.7
    +++ linux/sound/core/Kconfig 12 Jan 2005 22:49:21 -0000
    @@ -81,20 +81,6 @@
    To compile this driver as a module, choose M here: the module
    will be called snd-seq-oss.

    -config SND_BIT32_EMUL
    - tristate "Emulation for 32-bit applications"
    - depends on SND && COMPAT
    - select SND_PCM
    - select SND_RAWMIDI
    - select SND_TIMER
    - select SND_HWDEP
    - help
    - Say Y here to enable the emulation for 32-bit ALSA-native
    - applications.
    -
    - To compile this driver as a module, choose M here: the module
    - will be called snd-ioctl32.
    -
    config SND_RTCTIMER
    tristate "RTC Timer support"
    depends on SND && RTC
    --- linux/sound/core/Makefile 3 Mar 2004 10:46:16 -0000 1.49
    +++ linux/sound/core/Makefile 12 Jan 2005 22:49:21 -0000
    @@ -31,4 +31,3 @@

    obj-$(CONFIG_SND_OSSEMUL) += oss/
    obj-$(CONFIG_SND_SEQUENCER) += seq/
    -obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
    --- linux/sound/core/control.c 3 Jan 2005 14:27:52 -0000 1.49
    +++ linux/sound/core/control.c 18 Jan 2005 14:52:43 -0000
    @@ -43,6 +43,9 @@

    static DECLARE_RWSEM(snd_ioctl_rwsem);
    static LIST_HEAD(snd_control_ioctls);
    +#ifdef CONFIG_COMPAT
    +static LIST_HEAD(snd_control_compat_ioctls);
    +#endif

    static int snd_ctl_open(struct inode *inode, struct file *file)
    {
    @@ -595,43 +598,51 @@
    return 0;
    }

    -static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
    +static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
    {
    snd_card_t *card = ctl->card;
    - snd_ctl_elem_info_t info;
    snd_kcontrol_t *kctl;
    snd_kcontrol_volatile_t *vd;
    unsigned int index_offset;
    int result;

    - if (copy_from_user(&info, _info, sizeof(info)))
    - return -EFAULT;
    down_read(&card->controls_rwsem);
    - kctl = snd_ctl_find_id(card, &info.id);
    + kctl = snd_ctl_find_id(card, &info->id);
    if (kctl == NULL) {
    up_read(&card->controls_rwsem);
    return -ENOENT;
    }
    #ifdef CONFIG_SND_DEBUG
    - info.access = 0;
    + info->access = 0;
    #endif
    - result = kctl->info(kctl, &info);
    + result = kctl->info(kctl, info);
    if (result >= 0) {
    - snd_assert(info.access == 0, );
    - index_offset = snd_ctl_get_ioff(kctl, &info.id);
    + snd_assert(info->access == 0, );
    + index_offset = snd_ctl_get_ioff(kctl, &info->id);
    vd = &kctl->vd[index_offset];
    - snd_ctl_build_ioff(&info.id, kctl, index_offset);
    - info.access = vd->access;
    + snd_ctl_build_ioff(&info->id, kctl, index_offset);
    + info->access = vd->access;
    if (vd->owner) {
    - info.access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
    + info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
    if (vd->owner == ctl)
    - info.access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
    - info.owner = vd->owner_pid;
    + info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
    + info->owner = vd->owner_pid;
    } else {
    - info.owner = -1;
    + info->owner = -1;
    }
    }
    up_read(&card->controls_rwsem);
    + return result;
    +}
    +
    +static int snd_ctl_elem_info_user(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
    +{
    + snd_ctl_elem_info_t info;
    + int result;
    +
    + if (copy_from_user(&info, _info, sizeof(info)))
    + return -EFAULT;
    + result = snd_ctl_elem_info(ctl, &info);
    if (result >= 0)
    if (copy_to_user(_info, &info, sizeof(info)))
    return -EFAULT;
    @@ -816,14 +827,6 @@
    struct user_element *ue = kcontrol->private_data;

    *uinfo = ue->info;
    - if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
    - uinfo->value.enumerated.items = ue->info.value.enumerated.items;
    - if (uinfo->value.enumerated.item >= ue->info.value.enumerated.items)
    - uinfo->value.enumerated.item = 0;
    - strlcpy(uinfo->value.enumerated.name,
    - (char *)ue->priv_data + uinfo->value.enumerated.item * 64,
    - 64);
    - }
    return 0;
    }

    @@ -851,28 +854,25 @@
    kfree(kcontrol->private_data);
    }

    -static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
    +static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int replace)
    {
    snd_card_t *card = file->card;
    - snd_ctl_elem_info_t info;
    snd_kcontrol_t kctl, *_kctl;
    unsigned int access;
    - long private_size, extra_size;
    + long private_size;
    struct user_element *ue;
    int idx, err;

    if (card->user_ctl_count >= MAX_USER_CONTROLS)
    return -ENOMEM;
    - if (copy_from_user(&info, _info, sizeof(info)))
    - return -EFAULT;
    - if (info.count > 1024)
    + if (info->count > 1024)
    return -EINVAL;
    - access = info.access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
    - (info.access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
    - info.id.numid = 0;
    + access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
    + (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
    + info->id.numid = 0;
    memset(&kctl, 0, sizeof(kctl));
    down_write(&card->controls_rwsem);
    - _kctl = snd_ctl_find_id(card, &info.id);
    + _kctl = snd_ctl_find_id(card, &info->id);
    err = 0;
    if (_kctl) {
    if (replace)
    @@ -886,67 +886,50 @@
    up_write(&card->controls_rwsem);
    if (err < 0)
    return err;
    - memcpy(&kctl.id, &info.id, sizeof(info.id));
    - kctl.count = info.owner ? info.owner : 1;
    + memcpy(&kctl.id, &info->id, sizeof(info->id));
    + kctl.count = info->owner ? info->owner : 1;
    access |= SNDRV_CTL_ELEM_ACCESS_USER;
    kctl.info = snd_ctl_elem_user_info;
    if (access & SNDRV_CTL_ELEM_ACCESS_READ)
    kctl.get = snd_ctl_elem_user_get;
    if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
    kctl.put = snd_ctl_elem_user_put;
    - extra_size = 0;
    - switch (info.type) {
    + switch (info->type) {
    case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
    private_size = sizeof(char);
    - if (info.count > 128)
    + if (info->count > 128)
    return -EINVAL;
    break;
    case SNDRV_CTL_ELEM_TYPE_INTEGER:
    private_size = sizeof(long);
    - if (info.count > 128)
    + if (info->count > 128)
    return -EINVAL;
    break;
    case SNDRV_CTL_ELEM_TYPE_INTEGER64:
    private_size = sizeof(long long);
    - if (info.count > 64)
    + if (info->count > 64)
    return -EINVAL;
    break;
    - case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
    - private_size = sizeof(unsigned int);
    - if (info.count > 128)
    - return -EINVAL;
    - if (info.value.enumerated.items > 128)
    - return -EINVAL;
    - extra_size = info.value.enumerated.items * 64;
    - break;
    case SNDRV_CTL_ELEM_TYPE_BYTES:
    private_size = sizeof(unsigned char);
    - if (info.count > 512)
    + if (info->count > 512)
    return -EINVAL;
    break;
    case SNDRV_CTL_ELEM_TYPE_IEC958:
    private_size = sizeof(struct sndrv_aes_iec958);
    - if (info.count != 1)
    + if (info->count != 1)
    return -EINVAL;
    break;
    default:
    return -EINVAL;
    }
    - private_size *= info.count;
    - ue = kcalloc(1, sizeof(struct user_element) + private_size + extra_size, GFP_KERNEL);
    + private_size *= info->count;
    + ue = kcalloc(1, sizeof(struct user_element) + private_size, GFP_KERNEL);
    if (ue == NULL)
    return -ENOMEM;
    - ue->info = info;
    + ue->info = *info;
    ue->elem_data = (char *)ue + sizeof(ue);
    ue->elem_data_size = private_size;
    - if (extra_size) {
    - ue->priv_data = (char *)ue + sizeof(ue) + private_size;
    - ue->priv_data_size = extra_size;
    - if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
    - if (copy_from_user(ue->priv_data, *(char __user **)info.value.enumerated.name, extra_size))
    - return -EFAULT;
    - }
    - }
    kctl.private_free = snd_ctl_elem_user_free;
    _kctl = snd_ctl_new(&kctl, access);
    if (_kctl == NULL) {
    @@ -969,6 +952,14 @@
    return 0;
    }

    +static int snd_ctl_elem_add_user(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
    +{
    + snd_ctl_elem_info_t info;
    + if (copy_from_user(&info, _info, sizeof(info)))
    + return -EFAULT;
    + return snd_ctl_elem_add(file, &info, replace);
    +}
    +
    static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
    {
    snd_ctl_elem_id_t id;
    @@ -1039,8 +1030,7 @@
    }
    #endif

    -static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file,
    - unsigned int cmd, unsigned long arg)
    +static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
    snd_ctl_file_t *ctl;
    snd_card_t *card;
    @@ -1061,7 +1051,7 @@
    case SNDRV_CTL_IOCTL_ELEM_LIST:
    return snd_ctl_elem_list(ctl->card, argp);
    case SNDRV_CTL_IOCTL_ELEM_INFO:
    - return snd_ctl_elem_info(ctl, argp);
    + return snd_ctl_elem_info_user(ctl, argp);
    case SNDRV_CTL_IOCTL_ELEM_READ:
    return snd_ctl_elem_read_user(ctl->card, argp);
    case SNDRV_CTL_IOCTL_ELEM_WRITE:
    @@ -1071,7 +1061,7 @@
    case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
    return snd_ctl_elem_unlock(ctl, argp);
    case SNDRV_CTL_IOCTL_ELEM_ADD:
    - return snd_ctl_elem_add(ctl, argp, 0);
    + return snd_ctl_elem_add_user(ctl, argp, 0);
    case SNDRV_CTL_IOCTL_ELEM_REPLACE:
    return snd_ctl_elem_add(ctl, argp, 1);
    case SNDRV_CTL_IOCTL_ELEM_REMOVE:
    @@ -1113,17 +1103,6 @@
    return -ENOTTY;
    }

    -/* FIXME: need to unlock BKL to allow preemption */
    -static int snd_ctl_ioctl(struct inode *inode, struct file *file,
    - unsigned int cmd, unsigned long arg)
    -{
    - int err;
    - unlock_kernel();
    - err = _snd_ctl_ioctl(inode, file, cmd, arg);
    - lock_kernel();
    - return err;
    -}
    -
    static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset)
    {
    snd_ctl_file_t *ctl;
    @@ -1199,7 +1178,7 @@
    * register the device-specific control-ioctls.
    * called from each device manager like pcm.c, hwdep.c, etc.
    */
    -int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
    +static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
    {
    snd_kctl_ioctl_t *pn;

    @@ -1208,22 +1187,34 @@
    return -ENOMEM;
    pn->fioctl = fcn;
    down_write(&snd_ioctl_rwsem);
    - list_add_tail(&pn->list, &snd_control_ioctls);
    + list_add_tail(&pn->list, lists);
    up_write(&snd_ioctl_rwsem);
    return 0;
    }

    +int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
    +{
    + return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
    +}
    +
    +#ifdef CONFIG_COMPAT
    +int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
    +{
    + return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
    +}
    +#endif
    +
    /*
    * de-register the device-specific control-ioctls.
    */
    -int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
    +static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
    {
    struct list_head *list;
    snd_kctl_ioctl_t *p;

    snd_runtime_check(fcn != NULL, return -EINVAL);
    down_write(&snd_ioctl_rwsem);
    - list_for_each(list, &snd_control_ioctls) {
    + list_for_each(list, lists) {
    p = list_entry(list, snd_kctl_ioctl_t, list);
    if (p->fioctl == fcn) {
    list_del(&p->list);
    @@ -1237,6 +1228,19 @@
    return -EINVAL;
    }

    +int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
    +{
    + return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
    +}
    +
    +#ifdef CONFIG_COMPAT
    +int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
    +{
    + return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
    +}
    +
    +#endif
    +
    static int snd_ctl_fasync(int fd, struct file * file, int on)
    {
    snd_ctl_file_t *ctl;
    @@ -1249,6 +1253,15 @@
    }

    /*
    + * ioctl32 compat
    + */
    +#ifdef CONFIG_COMPAT
    +#include "control_compat.c"
    +#else
    +#define snd_ctl_ioctl_compat NULL
    +#endif
    +
    +/*
    * INIT PART
    */

    @@ -1259,7 +1272,8 @@
    .open = snd_ctl_open,
    .release = snd_ctl_release,
    .poll = snd_ctl_poll,
    - .ioctl = snd_ctl_ioctl,
    + .unlocked_ioctl = snd_ctl_ioctl,
    + .compat_ioctl = snd_ctl_ioctl_compat,
    .fasync = snd_ctl_fasync,
    };

    --- /dev/null 1 Jan 1970 00:00:00 -0000
    +++ linux/sound/core/control_compat.c 18 Jan 2005 14:52:14 -0000
    @@ -0,0 +1,412 @@
    +/*
    + * compat ioctls for control API
    + *
    + * Copyright (c) by Takashi Iwai <tiwai@suse.de>
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License as published by
    + * the Free Software Foundation; either version 2 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program; if not, write to the Free Software
    + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    + */
    +
    +/* this file included from control.c */
    +
    +#include <linux/compat.h>
    +
    +struct sndrv_ctl_elem_list32 {
    + u32 offset;
    + u32 space;
    + u32 used;
    + u32 count;
    + u32 pids;
    + 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)
    +{
    + struct sndrv_ctl_elem_list __user *data;
    + compat_caddr_t ptr;
    + int err;
    +
    + data = compat_alloc_user_space(sizeof(*data));
    +
    + /* offset, space, used, count */
    + if (copy_in_user(data, data32, 4 * sizeof(u32)))
    + return -EFAULT;
    + /* pids */
    + if (get_user(ptr, &data32->pids) ||
    + put_user(compat_ptr(ptr), &data->pids))
    + return -EFAULT;
    + err = snd_ctl_elem_list(card, data);
    + if (err < 0)
    + return err;
    + /* copy the result */
    + if (copy_in_user(data32, data, 4 * sizeof(u32)))
    + return -EFAULT;
    + return 0;
    +}
    +
    +/*
    + * control element info
    + * 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
    + s32 type;
    + u32 access;
    + u32 count;
    + s32 owner;
    + union {
    + struct {
    + s32 min;
    + s32 max;
    + s32 step;
    + } integer;
    + struct {
    + u64 min;
    + u64 max;
    + u64 step;
    + } integer64;
    + struct {
    + u32 items;
    + u32 item;
    + char name[64];
    + } 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)
    +{
    + struct sndrv_ctl_elem_info *data;
    + int err;
    +
    + data = kcalloc(1, sizeof(*data), GFP_KERNEL);
    + if (! data)
    + return -ENOMEM;
    +
    + err = -EFAULT;
    + /* copy id */
    + if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
    + goto error;
    + /* we need to copy the item index.
    + * hope this doesn't break anything..
    + */
    + if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
    + goto error;
    + err = snd_ctl_elem_info(ctl, data);
    + if (err < 0)
    + goto error;
    + /* restore info to 32bit */
    + err = -EFAULT;
    + /* id, type, access, count */
    + if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
    + copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
    + goto error;
    + if (put_user(data->owner, &data32->owner))
    + goto error;
    + switch (data->type) {
    + case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
    + case SNDRV_CTL_ELEM_TYPE_INTEGER:
    + if (put_user(data->value.integer.min, &data32->value.integer.min) ||
    + put_user(data->value.integer.max, &data32->value.integer.max) ||
    + put_user(data->value.integer.step, &data32->value.integer.step))
    + goto error;
    + break;
    + case SNDRV_CTL_ELEM_TYPE_INTEGER64:
    + if (copy_to_user(&data32->value.integer64,
    + &data->value.integer64,
    + sizeof(data->value.integer64)))
    + goto error;
    + break;
    + case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
    + if (copy_to_user(&data32->value.enumerated,
    + &data->value.enumerated,
    + sizeof(data->value.enumerated)))
    + goto error;
    + break;
    + default:
    + break;
    + }
    + err = 0;
    + error:
    + kfree(data);
    + return err;
    +}
    +
    +/* read / write */
    +struct sndrv_ctl_elem_value32 {
    + struct sndrv_ctl_elem_id id;
    + unsigned int indirect; /* bit-field causes misalignment */
    + union {
    + s32 integer[128];
    + unsigned char data[512];
    +#ifndef CONFIG_X86_64
    + s64 integer64[64];
    +#endif
    + } value;
    + unsigned char reserved[128];
    +};
    +
    +
    +/* 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)
    +{
    + snd_kcontrol_t *kctl;
    + snd_ctl_elem_info_t info;
    + int err;
    +
    + down_read(&card->controls_rwsem);
    + kctl = snd_ctl_find_id(card, id);
    + if (! kctl) {
    + up_read(&card->controls_rwsem);
    + return -ENXIO;
    + }
    + info.id = *id;
    + err = kctl->info(kctl, &info);
    + up_read(&card->controls_rwsem);
    + if (err >= 0) {
    + err = info.type;
    + *countp = info.count;
    + }
    + return err;
    +}
    +
    +static int get_elem_size(int type, int count)
    +{
    + switch (type) {
    + case SNDRV_CTL_ELEM_TYPE_INTEGER64:
    + return sizeof(s64) * count;
    + case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
    + return sizeof(int) * count;
    + case SNDRV_CTL_ELEM_TYPE_BYTES:
    + return 512;
    + case SNDRV_CTL_ELEM_TYPE_IEC958:
    + return sizeof(struct sndrv_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,
    + int *typep, int *countp)
    +{
    + int i, type, count, size;
    + unsigned int indirect;
    +
    + if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
    + return -EFAULT;
    + if (get_user(indirect, &data32->indirect))
    + return -EFAULT;
    + if (indirect)
    + return -EINVAL;
    + type = get_ctl_type(card, &data->id, &count);
    + if (type < 0)
    + return type;
    +
    + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
    + type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
    + for (i = 0; i < count; i++) {
    + int val;
    + if (get_user(val, &data32->value.integer[i]))
    + return -EFAULT;
    + data->value.integer.value[i] = val;
    + }
    + } else {
    + size = get_elem_size(type, count);
    + if (size < 0) {
    + printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
    + return -EINVAL;
    + }
    + if (copy_from_user(data->value.bytes.data,
    + data32->value.data, size))
    + return -EFAULT;
    + }
    +
    + *typep = type;
    + *countp = count;
    + return 0;
    +}
    +
    +/* 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,
    + int type, int count)
    +{
    + int i, size;
    +
    + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
    + type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
    + for (i = 0; i < count; i++) {
    + int val;
    + val = data->value.integer.value[i];
    + if (put_user(val, &data32->value.integer[i]))
    + return -EFAULT;
    + }
    + } else {
    + size = get_elem_size(type, count);
    + if (copy_to_user(data32->value.data,
    + data->value.bytes.data, size))
    + return -EFAULT;
    + }
    + return 0;
    +}
    +
    +static int snd_ctl_elem_read_user_compat(snd_card_t *card,
    + struct sndrv_ctl_elem_value32 __user *data32)
    +{
    + struct sndrv_ctl_elem_value *data;
    + int err, type, count;
    +
    + data = kcalloc(1, sizeof(*data), GFP_KERNEL);
    + if (data == NULL)
    + return -ENOMEM;
    +
    + 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);
    + 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)
    +{
    + struct sndrv_ctl_elem_value *data;
    + int err, type, count;
    +
    + data = kcalloc(1, 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)
    + goto error;
    + 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,
    + int replace)
    +{
    + struct sndrv_ctl_elem_info *data;
    + int err;
    +
    + data = kcalloc(1, sizeof(*data), GFP_KERNEL);
    + if (! data)
    + return -ENOMEM;
    +
    + err = -EFAULT;
    + /* id, type, access, count */ \
    + if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
    + copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
    + goto error;
    + if (get_user(data->owner, &data32->owner) ||
    + get_user(data->type, &data32->type))
    + goto error;
    + switch (data->type) {
    + case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
    + case SNDRV_CTL_ELEM_TYPE_INTEGER:
    + if (get_user(data->value.integer.min, &data32->value.integer.min) ||
    + get_user(data->value.integer.max, &data32->value.integer.max) ||
    + get_user(data->value.integer.step, &data32->value.integer.step))
    + goto error;
    + break;
    + case SNDRV_CTL_ELEM_TYPE_INTEGER64:
    + if (copy_from_user(&data->value.integer64,
    + &data32->value.integer64,
    + sizeof(data->value.integer64)))
    + goto error;
    + break;
    + case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
    + if (copy_from_user(&data->value.enumerated,
    + &data32->value.enumerated,
    + sizeof(data->value.enumerated)))
    + goto error;
    + break;
    + default:
    + break;
    + }
    + err = snd_ctl_elem_add(file, data, replace);
    + error:
    + kfree(data);
    + return err;
    +}
    +
    +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),
    +};
    +
    +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;
    + void __user *argp = compat_ptr(arg);
    + int err;
    +
    + ctl = file->private_data;
    + snd_assert(ctl && ctl->card, return -ENXIO);
    +
    + switch (cmd) {
    + case SNDRV_CTL_IOCTL_PVERSION:
    + case SNDRV_CTL_IOCTL_CARD_INFO:
    + case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
    + case SNDRV_CTL_IOCTL_POWER:
    + case SNDRV_CTL_IOCTL_POWER_STATE:
    + case SNDRV_CTL_IOCTL_ELEM_LOCK:
    + case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
    + return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
    + case SNDRV_CTL_IOCTL_ELEM_LIST32:
    + return snd_ctl_elem_list_compat(ctl->card, argp);
    + case SNDRV_CTL_IOCTL_ELEM_INFO32:
    + return snd_ctl_elem_info_compat(ctl, argp);
    + case SNDRV_CTL_IOCTL_ELEM_READ32:
    + return snd_ctl_elem_read_user_compat(ctl->card, argp);
    + case SNDRV_CTL_IOCTL_ELEM_WRITE32:
    + return snd_ctl_elem_write_user_compat(ctl, argp);
    + case SNDRV_CTL_IOCTL_ELEM_ADD32:
    + return snd_ctl_elem_add_compat(ctl, argp, 0);
    + case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
    + return snd_ctl_elem_add_compat(ctl, argp, 1);
    + }
    +
    + 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);
    + if (p->fioctl) {
    + err = p->fioctl(ctl->card, ctl, cmd, arg);
    + if (err != -ENOIOCTLCMD) {
    + up_read(&snd_ioctl_rwsem);
    + return err;
    + }
    + }
    + }
    + up_read(&snd_ioctl_rwsem);
    + return -ENOIOCTLCMD;
    +}
    --- linux/sound/core/sound.c 22 Dec 2004 15:57:37 -0000 1.66
    +++ linux/sound/core/sound.c 18 Jan 2005 15:37:49 -0000
    @@ -467,6 +467,10 @@
    EXPORT_SYMBOL(snd_ctl_notify);
    EXPORT_SYMBOL(snd_ctl_register_ioctl);
    EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
    +#ifdef CONFIG_COMPAT
    +EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
    +EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
    +#endif
    EXPORT_SYMBOL(snd_ctl_elem_read);
    EXPORT_SYMBOL(snd_ctl_elem_write);
    /* misc.c */
    --- linux/include/sound/control.h 23 Dec 2004 14:49:28 -0000 1.12
    +++ linux/include/sound/control.h 12 Jan 2005 22:49:21 -0000
    @@ -119,6 +119,13 @@

    int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
    int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
    +#ifdef CONFIG_COMPAT
    +int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);
    +int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
    +#else
    +#define snd_ctl_register_ioctl_compat(fcn)
    +#define snd_ctl_unregister_ioctl_compat(fcn)
    +#endif

    int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control);
    int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_value_t *control);
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2005-03-22 14:09    [W:0.069 / U:66.192 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site