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

📄 sb16_csp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
			p->func_nr = func_nr;			p->mode = le16_to_cpu(funcdesc_h.flags_play_rec);			switch (le16_to_cpu(funcdesc_h.VOC_type)) {			case 0x0001:	/* QSound decoder */				if (le16_to_cpu(funcdesc_h.flags_play_rec) == SNDRV_SB_CSP_MODE_DSP_WRITE) {					if (snd_sb_qsound_build(p) == 0)						/* set QSound flag and clear all other mode flags */						p->mode = SNDRV_SB_CSP_MODE_QSOUND;				}				p->acc_format = 0;				break;			case 0x0006:	/* A Law codec */				p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;				break;			case 0x0007:	/* Mu Law codec */				p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;				break;			case 0x0011:	/* what Creative thinks is IMA ADPCM codec */			case 0x0200:	/* Creative ADPCM codec */				p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;				break;			case    201:	/* Text 2 Speech decoder */				/* TODO: Text2Speech handling routines */				p->acc_format = 0;				break;			case 0x0202:	/* Fast Speech 8 codec */			case 0x0203:	/* Fast Speech 10 codec */				p->acc_format = SNDRV_PCM_FMTBIT_SPECIAL;				break;			default:	/* other codecs are unsupported */				p->acc_format = p->acc_width = p->acc_rates = 0;				p->mode = 0;				snd_printd("%s: Unsupported CSP codec type: 0x%04x\n",					   __FUNCTION__,					   le16_to_cpu(funcdesc_h.VOC_type));				return -EINVAL;			}			p->acc_channels = le16_to_cpu(funcdesc_h.flags_stereo_mono);			p->acc_width = le16_to_cpu(funcdesc_h.flags_16bit_8bit);			p->acc_rates = le16_to_cpu(funcdesc_h.flags_rates);			/* Decouple CSP from IRQ and DMAREQ lines */			spin_lock_irqsave(&p->chip->reg_lock, flags);			set_mode_register(p->chip, 0xfc);			set_mode_register(p->chip, 0x00);			spin_unlock_irqrestore(&p->chip->reg_lock, flags);			/* finished loading successfully */			p->running = SNDRV_SB_CSP_ST_LOADED;	/* set LOADED flag */			return 0;		}	}	snd_printd("%s: Function #%d not found\n", __FUNCTION__, info.func_req);	return -EINVAL;}/* * unload CSP microcode */static int snd_sb_csp_unload(snd_sb_csp_t * p){	if (p->running & SNDRV_SB_CSP_ST_RUNNING)		return -EBUSY;	if (!(p->running & SNDRV_SB_CSP_ST_LOADED))		return -ENXIO;	/* clear supported formats */	p->acc_format = 0;	p->acc_channels = p->acc_width = p->acc_rates = 0;	/* 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;	return 0;}/* * send command sequence to DSP */static inline int command_seq(sb_t *chip, const unsigned char *seq, int size){	int i;	for (i = 0; i < size; i++) {		if (!snd_sbdsp_command(chip, seq[i]))			return -EIO;	}	return 0;}/* * set CSP codec parameter */static int set_codec_parameter(sb_t *chip, unsigned char par, unsigned char val){	unsigned char dsp_cmd[3];	dsp_cmd[0] = 0x05;	/* CSP set codec parameter */	dsp_cmd[1] = val;	/* Parameter value */	dsp_cmd[2] = par;	/* Parameter */	command_seq(chip, dsp_cmd, 3);	snd_sbdsp_command(chip, 0x03);	/* DSP read? */	if (snd_sbdsp_get_byte(chip) != par)		return -EIO;	return 0;}/* * set CSP register */static int set_register(sb_t *chip, unsigned char reg, unsigned char val){	unsigned char dsp_cmd[3];	dsp_cmd[0] = 0x0e;	/* CSP set register */	dsp_cmd[1] = reg;	/* CSP Register */	dsp_cmd[2] = val;	/* value */	return command_seq(chip, dsp_cmd, 3);}/* * read CSP register * return < 0 -> error */static int read_register(sb_t *chip, unsigned char reg){	unsigned char dsp_cmd[2];	dsp_cmd[0] = 0x0f;	/* CSP read register */	dsp_cmd[1] = reg;	/* CSP Register */	command_seq(chip, dsp_cmd, 2);	return snd_sbdsp_get_byte(chip);	/* Read DSP value */}/* * set CSP mode register */static int set_mode_register(sb_t *chip, unsigned char mode){	unsigned char dsp_cmd[2];	dsp_cmd[0] = 0x04;	/* CSP set mode register */	dsp_cmd[1] = mode;	/* mode */	return command_seq(chip, dsp_cmd, 2);}/* * Detect CSP * return 0 if CSP exists. */static int csp_detect(sb_t *chip, int *version){	unsigned char csp_test1, csp_test2;	unsigned long flags;	int result = -ENODEV;	spin_lock_irqsave(&chip->reg_lock, flags);	set_codec_parameter(chip, 0x00, 0x00);	set_mode_register(chip, 0xfc);		/* 0xfc = ?? */	csp_test1 = read_register(chip, 0x83);	set_register(chip, 0x83, ~csp_test1);	csp_test2 = read_register(chip, 0x83);	if (csp_test2 != (csp_test1 ^ 0xff))		goto __fail;	set_register(chip, 0x83, csp_test1);	csp_test2 = read_register(chip, 0x83);	if (csp_test2 != csp_test1)		goto __fail;	set_mode_register(chip, 0x00);		/* 0x00 = ? */	*version = get_version(chip);	snd_sbdsp_reset(chip);	/* reset DSP after getversion! */	if (*version >= 0x10 && *version <= 0x1f)		result = 0;		/* valid version id */      __fail:	spin_unlock_irqrestore(&chip->reg_lock, flags);	return result;}/* * get CSP version number */static int get_version(sb_t *chip){	unsigned char dsp_cmd[2];	dsp_cmd[0] = 0x08;	/* SB_DSP_!something! */	dsp_cmd[1] = 0x03;	/* get chip version id? */	command_seq(chip, dsp_cmd, 2);	return (snd_sbdsp_get_byte(chip));}/* * check if the CSP version is valid */static int snd_sb_csp_check_version(snd_sb_csp_t * p){	if (p->version < 0x10 || p->version > 0x1f) {		snd_printd("%s: Invalid CSP version: 0x%x\n", __FUNCTION__, p->version);		return 1;	}	return 0;}/* * download microcode to CSP (microcode should have one "main" block). */static int snd_sb_csp_load(snd_sb_csp_t * p, const unsigned char *buf, int size, int load_flags){	int status, i;	int err;	int result = -EIO;	unsigned long flags;	spin_lock_irqsave(&p->chip->reg_lock, flags);	snd_sbdsp_command(p->chip, 0x01);	/* CSP download command */	if (snd_sbdsp_get_byte(p->chip)) {		snd_printd("%s: Download command failed\n", __FUNCTION__);		goto __fail;	}	/* Send CSP low byte (size - 1) */	snd_sbdsp_command(p->chip, (unsigned char)(size - 1));	/* Send high byte */	snd_sbdsp_command(p->chip, (unsigned char)((size - 1) >> 8));	/* send microcode sequence */	/* load from kernel space */	while (size--) {		if (!snd_sbdsp_command(p->chip, *buf++))			goto __fail;	}	if (snd_sbdsp_get_byte(p->chip))		goto __fail;	if (load_flags & SNDRV_SB_CSP_LOAD_INITBLOCK) {		i = 0;		/* some codecs (FastSpeech) take some time to initialize */		while (1) {			snd_sbdsp_command(p->chip, 0x03);			status = snd_sbdsp_get_byte(p->chip);			if (status == 0x55 || ++i >= 10)				break;			udelay (10);		}		if (status != 0x55) {			snd_printd("%s: Microcode initialization failed\n", __FUNCTION__);			goto __fail;		}	} else {		/*		 * Read mixer register SB_DSP4_DMASETUP after loading 'main' code.		 * Start CSP chip if no 16bit DMA channel is set - some kind		 * of autorun or perhaps a bugfix?		 */		spin_lock(&p->chip->mixer_lock);		status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP);		spin_unlock(&p->chip->mixer_lock);		if (!(status & (SB_DMASETUP_DMA7 | SB_DMASETUP_DMA6 | SB_DMASETUP_DMA5))) {			err = (set_codec_parameter(p->chip, 0xaa, 0x00) ||			       set_codec_parameter(p->chip, 0xff, 0x00));			snd_sbdsp_reset(p->chip);		/* really! */			if (err)				goto __fail;			set_mode_register(p->chip, 0xc0);	/* c0 = STOP */			set_mode_register(p->chip, 0x70);	/* 70 = RUN */		}	}	result = 0;      __fail:	spin_unlock_irqrestore(&p->chip->reg_lock, flags);	return result;} static int snd_sb_csp_load_user(snd_sb_csp_t * p, const unsigned char __user *buf, int size, int load_flags){	int err = -ENOMEM;	unsigned char *kbuf = kmalloc(size, GFP_KERNEL);	if (kbuf) {		if (copy_from_user(kbuf, buf, size))			err = -EFAULT;		else			err = snd_sb_csp_load(p, kbuf, size, load_flags);		kfree(kbuf);	}	return err;}#include "sb16_csp_codecs.h"/* * autoload hardware codec if necessary * return 0 if CSP is loaded and ready to run (p->running != 0) */static int snd_sb_csp_autoload(snd_sb_csp_t * p, int pcm_sfmt, int play_rec_mode){	unsigned long flags;	int err = 0;	/* if CSP is running or manually loaded then exit */	if (p->running & (SNDRV_SB_CSP_ST_RUNNING | SNDRV_SB_CSP_ST_LOADED)) 		return -EBUSY;	/* autoload microcode only if requested hardware codec is not already loaded */	if (((1 << pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) {		p->running = SNDRV_SB_CSP_ST_AUTO;	} else {		switch (pcm_sfmt) {		case SNDRV_PCM_FORMAT_MU_LAW:			err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0);			p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;			p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;			break;		case SNDRV_PCM_FORMAT_A_LAW:			err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0);			p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;			p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;			break;		case SNDRV_PCM_FORMAT_IMA_ADPCM:			err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init),					      SNDRV_SB_CSP_LOAD_INITBLOCK);			if (err)				break;			if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {				err = snd_sb_csp_load(p, &ima_adpcm_playback[0],						      sizeof(ima_adpcm_playback), 0);				p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;			} else {				err = snd_sb_csp_load(p, &ima_adpcm_capture[0],						      sizeof(ima_adpcm_capture), 0);				p->mode = SNDRV_SB_CSP_MODE_DSP_READ;			}			p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;			break;				  		default:			/* Decouple CSP from IRQ and DMAREQ lines */			if (p->running & SNDRV_SB_CSP_ST_AUTO) {				spin_lock_irqsave(&p->chip->reg_lock, flags);				set_mode_register(p->chip, 0xfc);				set_mode_register(p->chip, 0x00);				spin_unlock_irqrestore(&p->chip->reg_lock, flags);				p->running = 0;			/* clear autoloaded flag */			}			return -EINVAL;		}		if (err) {			p->acc_format = 0;			p->acc_channels = p->acc_width = p->acc_rates = 0;			p->running = 0;				/* clear autoloaded flag */			p->mode = 0;			return (err);		} else {			p->running = SNDRV_SB_CSP_ST_AUTO;	/* set autoloaded flag */			p->acc_width = SNDRV_SB_CSP_SAMPLE_16BIT;	/* only 16 bit data */			p->acc_channels = SNDRV_SB_CSP_MONO | SNDRV_SB_CSP_STEREO;			p->acc_rates = SNDRV_SB_CSP_RATE_ALL;	/* HW codecs accept all rates */		}   	}	return (p->running & SNDRV_SB_CSP_ST_AUTO) ? 0 : -ENXIO;}/* * start CSP */static int snd_sb_csp_start(snd_sb_csp_t * p, int sample_width, int channels){	unsigned char s_type;	/* sample type */	unsigned char mixL, mixR;	int result = -EIO;	unsigned long flags;	if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) {		snd_printd("%s: Microcode not loaded\n", __FUNCTION__);		return -ENXIO;	}	if (p->running & SNDRV_SB_CSP_ST_RUNNING) {		snd_printd("%s: CSP already running\n", __FUNCTION__);		return -EBUSY;	}	if (!(sample_width & p->acc_width)) {		snd_printd("%s: Unsupported PCM sample width\n", __FUNCTION__);		return -EINVAL;	}

⌨️ 快捷键说明

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