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

📄 ainstr_iw.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   IWFFFF - AMD InterWave (tm) - Instrument routines *   Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> * *   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/init.h>#include <linux/sched.h>#include <linux/slab.h>#include <sound/core.h>#include <sound/ainstr_iw.h>#include <sound/initval.h>#include <asm/uaccess.h>MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support.");MODULE_LICENSE("GPL");static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format){	unsigned int result = size;		if (format & IWFFFF_WAVE_16BIT)		result <<= 1;	if (format & IWFFFF_WAVE_STEREO)		result <<= 1;	return result;}static void snd_seq_iwffff_copy_lfo_from_stream(iwffff_lfo_t *fp,						iwffff_xlfo_t *fx){	fp->freq = le16_to_cpu(fx->freq);	fp->depth = le16_to_cpu(fx->depth);	fp->sweep = le16_to_cpu(fx->sweep);	fp->shape = fx->shape;	fp->delay = fx->delay;}static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype,					       iwffff_layer_t *lp,					       iwffff_env_t *ep,					       iwffff_xenv_t *ex,					       char __user **data,					       long *len,					       gfp_t gfp_mask){	__u32 stype;	iwffff_env_record_t *rp, *rp_last;	iwffff_xenv_record_t rx;	iwffff_env_point_t *pp;	iwffff_xenv_point_t px;	int points_size, idx;	ep->flags = ex->flags;	ep->mode = ex->mode;	ep->index = ex->index;	rp_last = NULL;	while (1) {		if (*len < (long)sizeof(__u32))			return -EINVAL;		if (copy_from_user(&stype, *data, sizeof(stype)))			return -EFAULT;		if (stype == IWFFFF_STRU_WAVE)			return 0;		if (req_stype != stype) {			if (stype == IWFFFF_STRU_ENV_RECP ||			    stype == IWFFFF_STRU_ENV_RECV)				return 0;		}		if (*len < (long)sizeof(rx))			return -EINVAL;		if (copy_from_user(&rx, *data, sizeof(rx)))			return -EFAULT;		*data += sizeof(rx);		*len -= sizeof(rx);		points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16);		if (points_size > *len)			return -EINVAL;		rp = kzalloc(sizeof(*rp) + points_size, gfp_mask);		if (rp == NULL)			return -ENOMEM;		rp->nattack = le16_to_cpu(rx.nattack);		rp->nrelease = le16_to_cpu(rx.nrelease);		rp->sustain_offset = le16_to_cpu(rx.sustain_offset);		rp->sustain_rate = le16_to_cpu(rx.sustain_rate);		rp->release_rate = le16_to_cpu(rx.release_rate);		rp->hirange = rx.hirange;		pp = (iwffff_env_point_t *)(rp + 1);		for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {			if (copy_from_user(&px, *data, sizeof(px)))				return -EFAULT;			*data += sizeof(px);			*len -= sizeof(px);			pp->offset = le16_to_cpu(px.offset);			pp->rate = le16_to_cpu(px.rate);		}		if (ep->record == NULL) {			ep->record = rp;		} else {			rp_last = rp;		}		rp_last = rp;	}	return 0;}static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t *ops,						iwffff_layer_t *lp,					        char __user **data,					        long *len,					        int atomic){	iwffff_wave_t *wp, *prev;	iwffff_xwave_t xp;	int err;	gfp_t gfp_mask;	unsigned int real_size;		gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;	if (*len < (long)sizeof(xp))		return -EINVAL;	if (copy_from_user(&xp, *data, sizeof(xp)))		return -EFAULT;	*data += sizeof(xp);	*len -= sizeof(xp);	wp = kzalloc(sizeof(*wp), gfp_mask);	if (wp == NULL)		return -ENOMEM;	wp->share_id[0] = le32_to_cpu(xp.share_id[0]);	wp->share_id[1] = le32_to_cpu(xp.share_id[1]);	wp->share_id[2] = le32_to_cpu(xp.share_id[2]);	wp->share_id[3] = le32_to_cpu(xp.share_id[3]);	wp->format = le32_to_cpu(xp.format);	wp->address.memory = le32_to_cpu(xp.offset);	wp->size = le32_to_cpu(xp.size);	wp->start = le32_to_cpu(xp.start);	wp->loop_start = le32_to_cpu(xp.loop_start);	wp->loop_end = le32_to_cpu(xp.loop_end);	wp->loop_repeat = le16_to_cpu(xp.loop_repeat);	wp->sample_ratio = le32_to_cpu(xp.sample_ratio);	wp->attenuation = xp.attenuation;	wp->low_note = xp.low_note;	wp->high_note = xp.high_note;	real_size = snd_seq_iwffff_size(wp->size, wp->format);	if (!(wp->format & IWFFFF_WAVE_ROM)) {		if ((long)real_size > *len) {			kfree(wp);			return -ENOMEM;		}	}	if (ops->put_sample) {		err = ops->put_sample(ops->private_data, wp,				      *data, real_size, atomic);		if (err < 0) {			kfree(wp);			return err;		}	}	if (!(wp->format & IWFFFF_WAVE_ROM)) {		*data += real_size;		*len -= real_size;	}	prev = lp->wave;	if (prev) {		while (prev->next) prev = prev->next;		prev->next = wp;	} else {		lp->wave = wp;	}	return 0;}static void snd_seq_iwffff_env_free(snd_iwffff_ops_t *ops,				    iwffff_env_t *env,				    int atomic){	iwffff_env_record_t *rec;		while ((rec = env->record) != NULL) {		env->record = rec->next;		kfree(rec);	}}				    static void snd_seq_iwffff_wave_free(snd_iwffff_ops_t *ops,				     iwffff_wave_t *wave,				     int atomic){	if (ops->remove_sample)		ops->remove_sample(ops->private_data, wave, atomic);	kfree(wave);}static void snd_seq_iwffff_instr_free(snd_iwffff_ops_t *ops,                                      iwffff_instrument_t *ip,                                      int atomic){	iwffff_layer_t *layer;	iwffff_wave_t *wave;		while ((layer = ip->layer) != NULL) {		ip->layer = layer->next;		snd_seq_iwffff_env_free(ops, &layer->penv, atomic);		snd_seq_iwffff_env_free(ops, &layer->venv, atomic);		while ((wave = layer->wave) != NULL) {			layer->wave = wave->next;			snd_seq_iwffff_wave_free(ops, wave, atomic);		}		kfree(layer);	}}static int snd_seq_iwffff_put(void *private_data, snd_seq_kinstr_t *instr,			      char __user *instr_data, long len, int atomic,			      int cmd){	snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;	iwffff_instrument_t *ip;	iwffff_xinstrument_t ix;	iwffff_layer_t *lp, *prev_lp;	iwffff_xlayer_t lx;	int err;	gfp_t gfp_mask;	if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)		return -EINVAL;	gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;	/* copy instrument data */	if (len < (long)sizeof(ix))		return -EINVAL;	if (copy_from_user(&ix, instr_data, sizeof(ix)))		return -EFAULT;	if (ix.stype != IWFFFF_STRU_INSTR)		return -EINVAL;	instr_data += sizeof(ix);	len -= sizeof(ix);	ip = (iwffff_instrument_t *)KINSTR_DATA(instr);	ip->exclusion = le16_to_cpu(ix.exclusion);	ip->layer_type = le16_to_cpu(ix.layer_type);	ip->exclusion_group = le16_to_cpu(ix.exclusion_group);	ip->effect1 = ix.effect1;	ip->effect1_depth = ix.effect1_depth;	ip->effect2 = ix.effect2;	ip->effect2_depth = ix.effect2_depth;	/* copy layers */	prev_lp = NULL;	while (len > 0) {		if (len < (long)sizeof(iwffff_xlayer_t)) {			snd_seq_iwffff_instr_free(ops, ip, atomic);			return -EINVAL;		}		if (copy_from_user(&lx, instr_data, sizeof(lx)))			return -EFAULT;		instr_data += sizeof(lx);		len -= sizeof(lx);		if (lx.stype != IWFFFF_STRU_LAYER) {			snd_seq_iwffff_instr_free(ops, ip, atomic);			return -EINVAL;		}		lp = kzalloc(sizeof(*lp), gfp_mask);		if (lp == NULL) {			snd_seq_iwffff_instr_free(ops, ip, atomic);			return -ENOMEM;		}		if (prev_lp) {			prev_lp->next = lp;		} else {			ip->layer = lp;		}		prev_lp = lp;		lp->flags = lx.flags;		lp->velocity_mode = lx.velocity_mode;		lp->layer_event = lx.layer_event;		lp->low_range = lx.low_range;		lp->high_range = lx.high_range;		lp->pan = lx.pan;		lp->pan_freq_scale = lx.pan_freq_scale;		lp->attenuation = lx.attenuation;		snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo);		snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato);		lp->freq_scale = le16_to_cpu(lx.freq_scale);		lp->freq_center = lx.freq_center;		err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP,							  lp,							  &lp->penv, &lx.penv,						          &instr_data, &len,						          gfp_mask);		if (err < 0) {			snd_seq_iwffff_instr_free(ops, ip, atomic);			return err;		}		err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV,							  lp,							  &lp->venv, &lx.venv,						          &instr_data, &len,						          gfp_mask);		if (err < 0) {

⌨️ 快捷键说明

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