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

📄 sb16_csp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si> *                        Takashi Iwai <tiwai@suse.de> * *  SB16ASP/AWE32 CSP control * *  CSP microcode loader: *   alsa-tools/sb16_csp/  * *   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/delay.h>#include <linux/init.h>#include <linux/slab.h>#include <sound/core.h>#include <sound/control.h>#include <sound/info.h>#include <sound/sb16_csp.h>#include <sound/initval.h>MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");MODULE_DESCRIPTION("ALSA driver for SB16 Creative Signal Processor");MODULE_LICENSE("GPL");#ifdef SNDRV_LITTLE_ENDIAN#define CSP_HDR_VALUE(a,b,c,d)	((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))#else#define CSP_HDR_VALUE(a,b,c,d)	((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))#endif#define RIFF_HEADER	CSP_HDR_VALUE('R', 'I', 'F', 'F')#define CSP__HEADER	CSP_HDR_VALUE('C', 'S', 'P', ' ')#define LIST_HEADER	CSP_HDR_VALUE('L', 'I', 'S', 'T')#define FUNC_HEADER	CSP_HDR_VALUE('f', 'u', 'n', 'c')#define CODE_HEADER	CSP_HDR_VALUE('c', 'o', 'd', 'e')#define INIT_HEADER	CSP_HDR_VALUE('i', 'n', 'i', 't')#define MAIN_HEADER	CSP_HDR_VALUE('m', 'a', 'i', 'n')/* * RIFF data format */struct riff_header {	__u32 name;	__u32 len;};struct desc_header {	struct riff_header info;	__u16 func_nr;	__u16 VOC_type;	__u16 flags_play_rec;	__u16 flags_16bit_8bit;	__u16 flags_stereo_mono;	__u16 flags_rates;};/* * prototypes */static void snd_sb_csp_free(snd_hwdep_t *hw);static int snd_sb_csp_open(snd_hwdep_t * hw, struct file *file);static int snd_sb_csp_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg);static int snd_sb_csp_release(snd_hwdep_t * hw, struct file *file);static int csp_detect(sb_t *chip, int *version);static int set_codec_parameter(sb_t *chip, unsigned char par, unsigned char val);static int set_register(sb_t *chip, unsigned char reg, unsigned char val);static int read_register(sb_t *chip, unsigned char reg);static int set_mode_register(sb_t *chip, unsigned char mode);static int get_version(sb_t *chip);static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user * code);static int snd_sb_csp_unload(snd_sb_csp_t * p);static int snd_sb_csp_load_user(snd_sb_csp_t * p, const unsigned char __user *buf, int size, int load_flags);static int snd_sb_csp_autoload(snd_sb_csp_t * p, int pcm_sfmt, int play_rec_mode);static int snd_sb_csp_check_version(snd_sb_csp_t * p);static int snd_sb_csp_use(snd_sb_csp_t * p);static int snd_sb_csp_unuse(snd_sb_csp_t * p);static int snd_sb_csp_start(snd_sb_csp_t * p, int sample_width, int channels);static int snd_sb_csp_stop(snd_sb_csp_t * p);static int snd_sb_csp_pause(snd_sb_csp_t * p);static int snd_sb_csp_restart(snd_sb_csp_t * p);static int snd_sb_qsound_build(snd_sb_csp_t * p);static void snd_sb_qsound_destroy(snd_sb_csp_t * p);static int snd_sb_csp_qsound_transfer(snd_sb_csp_t * p);static int init_proc_entry(snd_sb_csp_t * p, int device);static void info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);/* * Detect CSP chip and create a new instance */int snd_sb_csp_new(sb_t *chip, int device, snd_hwdep_t ** rhwdep){	snd_sb_csp_t *p;	int version, err;	snd_hwdep_t *hw;	if (rhwdep)		*rhwdep = NULL;	if (csp_detect(chip, &version))		return -ENODEV;	if ((err = snd_hwdep_new(chip->card, "SB16-CSP", device, &hw)) < 0)		return err;	if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) {		snd_device_free(chip->card, hw);		return -ENOMEM;	}	p->chip = chip;	p->version = version;	/* CSP operators */	p->ops.csp_use = snd_sb_csp_use;	p->ops.csp_unuse = snd_sb_csp_unuse;	p->ops.csp_autoload = snd_sb_csp_autoload;	p->ops.csp_start = snd_sb_csp_start;	p->ops.csp_stop = snd_sb_csp_stop;	p->ops.csp_qsound_transfer = snd_sb_csp_qsound_transfer;	init_MUTEX(&p->access_mutex);	sprintf(hw->name, "CSP v%d.%d", (version >> 4), (version & 0x0f));	hw->iface = SNDRV_HWDEP_IFACE_SB16CSP;	hw->private_data = p;	hw->private_free = snd_sb_csp_free;	/* operators - only write/ioctl */	hw->ops.open = snd_sb_csp_open;	hw->ops.ioctl = snd_sb_csp_ioctl;	hw->ops.release = snd_sb_csp_release;	/* create a proc entry */	init_proc_entry(p, device);	if (rhwdep)		*rhwdep = hw;	return 0;}/* * free_private for hwdep instance */static void snd_sb_csp_free(snd_hwdep_t *hwdep){	snd_sb_csp_t *p = hwdep->private_data;	if (p) {		if (p->running & SNDRV_SB_CSP_ST_RUNNING)			snd_sb_csp_stop(p);		kfree(p);	}}/* ------------------------------ *//* * open the device exclusively */static int snd_sb_csp_open(snd_hwdep_t * hw, struct file *file){	snd_sb_csp_t *p = hw->private_data;	return (snd_sb_csp_use(p));}/* * ioctl for hwdep device: */static int snd_sb_csp_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg){	snd_sb_csp_t *p = hw->private_data;	snd_sb_csp_info_t info;	snd_sb_csp_start_t start_info;	int err;	snd_assert(p != NULL, return -EINVAL);	if (snd_sb_csp_check_version(p))		return -ENODEV;	switch (cmd) {		/* get information */	case SNDRV_SB_CSP_IOCTL_INFO:		*info.codec_name = *p->codec_name;		info.func_nr = p->func_nr;		info.acc_format = p->acc_format;		info.acc_channels = p->acc_channels;		info.acc_width = p->acc_width;		info.acc_rates = p->acc_rates;		info.csp_mode = p->mode;		info.run_channels = p->run_channels;		info.run_width = p->run_width;		info.version = p->version;		info.state = p->running;		if (copy_to_user((void __user *)arg, &info, sizeof(info)))			err = -EFAULT;		else			err = 0;		break;		/* load CSP microcode */	case SNDRV_SB_CSP_IOCTL_LOAD_CODE:		err = (p->running & SNDRV_SB_CSP_ST_RUNNING ?		       -EBUSY : snd_sb_csp_riff_load(p, (snd_sb_csp_microcode_t __user *) arg));		break;	case SNDRV_SB_CSP_IOCTL_UNLOAD_CODE:		err = (p->running & SNDRV_SB_CSP_ST_RUNNING ?		       -EBUSY : snd_sb_csp_unload(p));		break;		/* change CSP running state */	case SNDRV_SB_CSP_IOCTL_START:		if (copy_from_user(&start_info, (void __user *) arg, sizeof(start_info)))			err = -EFAULT;		else			err = snd_sb_csp_start(p, start_info.sample_width, start_info.channels);		break;	case SNDRV_SB_CSP_IOCTL_STOP:		err = snd_sb_csp_stop(p);		break;	case SNDRV_SB_CSP_IOCTL_PAUSE:		err = snd_sb_csp_pause(p);		break;	case SNDRV_SB_CSP_IOCTL_RESTART:		err = snd_sb_csp_restart(p);		break;	default:		err = -ENOTTY;		break;	}	return err;}/* * close the device */static int snd_sb_csp_release(snd_hwdep_t * hw, struct file *file){	snd_sb_csp_t *p = hw->private_data;	return (snd_sb_csp_unuse(p));}/* ------------------------------ *//* * acquire device */static int snd_sb_csp_use(snd_sb_csp_t * p){	down(&p->access_mutex);	if (p->used) {		up(&p->access_mutex);		return -EAGAIN;	}	p->used++;	up(&p->access_mutex);	return 0;}/* * release device */static int snd_sb_csp_unuse(snd_sb_csp_t * p){	down(&p->access_mutex);	p->used--;	up(&p->access_mutex);	return 0;}/* * load microcode via ioctl:  * code is user-space pointer */static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user * mcode){	snd_sb_csp_mc_header_t info;	unsigned char __user *data_ptr;	unsigned char __user *data_end;	unsigned short func_nr = 0;	struct riff_header file_h, item_h, code_h;	__u32 item_type;	struct desc_header funcdesc_h;	unsigned long flags;	int err;	if (copy_from_user(&info, mcode, sizeof(info)))		return -EFAULT;	data_ptr = mcode->data;	if (copy_from_user(&file_h, data_ptr, sizeof(file_h)))		return -EFAULT;	if ((file_h.name != RIFF_HEADER) ||	    (le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {		snd_printd("%s: Invalid RIFF header\n", __FUNCTION__);		return -EINVAL;	}	data_ptr += sizeof(file_h);	data_end = data_ptr + le32_to_cpu(file_h.len);	if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))		return -EFAULT;	if (item_type != CSP__HEADER) {		snd_printd("%s: Invalid RIFF file type\n", __FUNCTION__);		return -EINVAL;	}	data_ptr += sizeof (item_type);	for (; data_ptr < data_end; data_ptr += le32_to_cpu(item_h.len)) {		if (copy_from_user(&item_h, data_ptr, sizeof(item_h)))			return -EFAULT;		data_ptr += sizeof(item_h);		if (item_h.name != LIST_HEADER)			continue;		if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))			 return -EFAULT;		switch (item_type) {		case FUNC_HEADER:			if (copy_from_user(&funcdesc_h, data_ptr + sizeof(item_type), sizeof(funcdesc_h)))				return -EFAULT;			func_nr = le16_to_cpu(funcdesc_h.func_nr);			break;		case CODE_HEADER:			if (func_nr != info.func_req)				break;	/* not required function, try next */			data_ptr += sizeof(item_type);			/* destroy QSound mixer element */			if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {				snd_sb_qsound_destroy(p);			}			/* Clear all flags */			p->running = 0;			p->mode = 0;			/* load microcode blocks */			for (;;) {				if (data_ptr >= data_end)					return -EINVAL;				if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))					return -EFAULT;				/* init microcode blocks */				if (code_h.name != INIT_HEADER)					break;				data_ptr += sizeof(code_h);				err = snd_sb_csp_load_user(p, data_ptr, le32_to_cpu(code_h.len),						      SNDRV_SB_CSP_LOAD_INITBLOCK);				if (err)					return err;				data_ptr += le32_to_cpu(code_h.len);			}			/* main microcode block */			if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))				return -EFAULT;			if (code_h.name != MAIN_HEADER) {				snd_printd("%s: Missing 'main' microcode\n", __FUNCTION__);				return -EINVAL;			}			data_ptr += sizeof(code_h);			err = snd_sb_csp_load_user(p, data_ptr,						   le32_to_cpu(code_h.len), 0);			if (err)				return err;			/* fill in codec header */			strlcpy(p->codec_name, info.codec_name, sizeof(p->codec_name));

⌨️ 快捷键说明

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