⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ioctl32.c

📁 h内核
💻 C
字号:
/* *   32bit -> 64bit ioctl wrapper 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 * */#include <sound/driver.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/time.h>#include <linux/slab.h>#include <linux/fs.h>#include <sound/core.h>#include <sound/control.h>#include <sound/minors.h>#include <asm/uaccess.h>#include "ioctl32.h"/* * register/unregister mappers * exported for other modules */MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");MODULE_LICENSE("GPL");int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));int unregister_ioctl32_conversion(unsigned int cmd);int snd_ioctl32_register(struct ioctl32_mapper *mappers){	int err;	struct ioctl32_mapper *m;	for (m = mappers; m->cmd; m++) {		err = register_ioctl32_conversion(m->cmd, m->handler);		if (err >= 0)			m->registered++;	}	return 0;}void snd_ioctl32_unregister(struct ioctl32_mapper *mappers){	struct ioctl32_mapper *m;	for (m = mappers; m->cmd; m++) {		if (m->registered) {			unregister_ioctl32_conversion(m->cmd);			m->registered = 0;		}	}}/* * compatible wrapper */int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp){	if (! filp->f_op || ! filp->f_op->ioctl)		return -ENOTTY;	return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);}/* * Controls */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 inline int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl){	struct sndrv_ctl_elem_list32 __user *data32;	struct sndrv_ctl_elem_list __user *data;	compat_caddr_t ptr;	int err;	data32 = compat_ptr(arg);	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 = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);	if (err < 0)		return err;	/* copy the result */	if (copy_in_user(data32, data, 4 * sizeof(u32)))		return -EFAULT;	return 0;}DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);/* * 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 inline int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl){	struct sndrv_ctl_elem_info __user *data, *src;	struct sndrv_ctl_elem_info32 __user *data32, *dst;	unsigned int type;	int err;	data32 = compat_ptr(arg);	data = compat_alloc_user_space(sizeof(*data));	/* copy id */	if (copy_in_user(&data->id, &data32->id, sizeof(data->id)))		return -EFAULT;	/* we need to copy the item index.	 * hope this doesn't break anything..	 */	if (copy_in_user(&data->value.enumerated.item,			 &data32->value.enumerated.item,			 sizeof(data->value.enumerated.item)))		return -EFAULT;	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);	if (err < 0)		return err;	/* restore info to 32bit */	/* for COPY_CVT macro */	src = data;	dst = data32;	/* id, type, access, count */	if (copy_in_user(&data32->id, &data->id, sizeof(data->id)) ||	    copy_in_user(&data32->type, &data->type, 3 * sizeof(u32)))		return -EFAULT;	COPY_CVT(owner);	__get_user(type, &data->type);	switch (type) {	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:	case SNDRV_CTL_ELEM_TYPE_INTEGER:		COPY_CVT(value.integer.min);		COPY_CVT(value.integer.max);		COPY_CVT(value.integer.step);		break;	case SNDRV_CTL_ELEM_TYPE_INTEGER64:		if (copy_in_user(&data32->value.integer64,				 &data->value.integer64,				 sizeof(data->value.integer64)))			return -EFAULT;		break;	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:		if (copy_in_user(&data32->value.enumerated,				 &data->value.enumerated,				 sizeof(data->value.enumerated)))			return -EFAULT;		break;	default:		break;	}	return 0;}DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);struct sndrv_ctl_elem_value32 {	struct sndrv_ctl_elem_id id;	unsigned int indirect;	/* bit-field causes misalignment */        union {		s32 integer[128];	/* integer and boolean need conversion */#ifndef CONFIG_X86_64		s64 integer64[64];	/* for alignment */#endif		unsigned char data[512];	/* others should be compatible */        } value;        unsigned char reserved[128];	/* not used */};/* hmm, it's so hard to retrieve the value type from the control id.. */static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id){	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;	return err;}extern int snd_major;static inline int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl){	struct sndrv_ctl_elem_value *data;	struct sndrv_ctl_elem_value32 __user *data32;	snd_ctl_file_t *ctl;	int err, i, indirect;	int type;	/* sanity check */	if (imajor(file->f_dentry->d_inode) != snd_major ||	    SNDRV_MINOR_DEVICE(iminor(file->f_dentry->d_inode)) != SNDRV_MINOR_CONTROL)		return -ENOTTY;	if ((ctl = file->private_data) == NULL)		return -ENOTTY;	data32 = compat_ptr(arg);	data = kcalloc(1, sizeof(*data), GFP_KERNEL);	if (data == NULL)		return -ENOMEM;	if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) {		err = -EFAULT;		goto __end;	}	if (__get_user(indirect, &data32->indirect)) {		err = -EFAULT;		goto __end;	}	/* FIXME: indirect access is not supported */	if (indirect) {		err = -EINVAL;		goto __end;	}	type = get_ctl_type(ctl->card, &data->id);	if (type < 0) {		err = type;		goto __end;	}	switch (type) {	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:	case SNDRV_CTL_ELEM_TYPE_INTEGER:		for (i = 0; i < 128; i++) {			int val;			if (__get_user(val, &data32->value.integer[i])) {				err = -EFAULT;				goto __end;			}			data->value.integer.value[i] = val;		}		break;	case SNDRV_CTL_ELEM_TYPE_INTEGER64:	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:	case SNDRV_CTL_ELEM_TYPE_BYTES:	case SNDRV_CTL_ELEM_TYPE_IEC958:		if (__copy_from_user(data->value.bytes.data,				     data32->value.data,				     sizeof(data32->value.data))) {			err = -EFAULT;			goto __end;		}		break;	default:		printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);		err = -EINVAL;		goto __end;	}	if (native_ctl == SNDRV_CTL_IOCTL_ELEM_READ)		err = snd_ctl_elem_read(ctl->card, data);	else		err = snd_ctl_elem_write(ctl->card, ctl, data);	if (err < 0)		goto __end;	/* restore info to 32bit */	switch (type) {	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:	case SNDRV_CTL_ELEM_TYPE_INTEGER:		for (i = 0; i < 128; i++) {			int val;			val = data->value.integer.value[i];			if (__put_user(val, &data32->value.integer[i])) {				err = -EFAULT;				goto __end;			}		}		break;	default:		if (__copy_to_user(data32->value.data,				   data->value.bytes.data,				   sizeof(data32->value.data))) {			err = -EFAULT;			goto __end;		}		break;		break;	}	err = 0;      __end:	kfree(data);	return err;}DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_write, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_WRITE);/* */#define AP(x) snd_ioctl32_##xenum {	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),};static struct ioctl32_mapper control_mappers[] = {	/* controls (without rawmidi, hwdep, timer releated ones) */	MAP_COMPAT(SNDRV_CTL_IOCTL_PVERSION),	MAP_COMPAT(SNDRV_CTL_IOCTL_CARD_INFO),	{ SNDRV_CTL_IOCTL_ELEM_LIST32, AP(ctl_elem_list) },	{ SNDRV_CTL_IOCTL_ELEM_INFO32, AP(ctl_elem_info) },	{ SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_read) },	{ SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_write) },	MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_LOCK),	MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_UNLOCK),	MAP_COMPAT(SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS),	MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_INFO),	MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE),	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE),	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_INFO),	MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE),	MAP_COMPAT(SNDRV_CTL_IOCTL_POWER),	MAP_COMPAT(SNDRV_CTL_IOCTL_POWER_STATE),	{ 0 }};/* */extern struct ioctl32_mapper pcm_mappers[];extern struct ioctl32_mapper rawmidi_mappers[];extern struct ioctl32_mapper timer_mappers[];extern struct ioctl32_mapper hwdep_mappers[];#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))extern struct ioctl32_mapper seq_mappers[];#endifstatic void snd_ioctl32_done(void){#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))	snd_ioctl32_unregister(seq_mappers);#endif	snd_ioctl32_unregister(hwdep_mappers);	snd_ioctl32_unregister(timer_mappers);	snd_ioctl32_unregister(rawmidi_mappers);	snd_ioctl32_unregister(pcm_mappers);	snd_ioctl32_unregister(control_mappers);}static int __init snd_ioctl32_init(void){	snd_ioctl32_register(control_mappers);	snd_ioctl32_register(pcm_mappers);	snd_ioctl32_register(rawmidi_mappers);	snd_ioctl32_register(timer_mappers);	snd_ioctl32_register(hwdep_mappers);#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))	snd_ioctl32_register(seq_mappers);#endif	return 0;}module_init(snd_ioctl32_init)module_exit(snd_ioctl32_done)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -