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

📄 sb16_main.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> *  Routines for control of 16-bit SoundBlaster cards and clones *  Note: This is very ugly hardware which uses one 8-bit DMA channel and *        second 16-bit DMA channel. Unfortunately 8-bit DMA channel can't *        transfer 16-bit samples and 16-bit DMA channels can't transfer *        8-bit samples. This make full duplex more complicated than *        can be... People, don't buy these soundcards for full 16-bit *        duplex!!! *  Note: 16-bit wide is assigned to first direction which made request. *        With full duplex - playback is preferred with abstract layer. * *  Note: Some chip revisions have hardware bug. Changing capture *        channel from full-duplex 8bit DMA to 16bit DMA will block *        16bit DMA transfers from DSP chip (capture) until 8bit transfer *        to DSP chip (playback) starts. This bug can be avoided with *        "16bit DMA Allocation" setting set to Playback or Capture. * * *   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 <asm/io.h>#include <asm/dma.h>#include <linux/init.h>#include <linux/time.h>#include <sound/core.h>#include <sound/sb.h>#include <sound/sb16_csp.h>#include <sound/mpu401.h>#include <sound/control.h>#include <sound/info.h>MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones");MODULE_LICENSE("GPL");#ifdef CONFIG_SND_SB16_CSPstatic void snd_sb16_csp_playback_prepare(sb_t *chip, snd_pcm_runtime_t *runtime){	if (chip->hardware == SB_HW_16CSP) {		snd_sb_csp_t *csp = chip->csp;		if (csp->running & SNDRV_SB_CSP_ST_LOADED) {			/* manually loaded codec */			if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) &&			    ((1U << runtime->format) == csp->acc_format)) {				/* Supported runtime PCM format for playback */				if (csp->ops.csp_use(csp) == 0) {					/* If CSP was successfully acquired */					goto __start_CSP;				}			} else if ((csp->mode & SNDRV_SB_CSP_MODE_QSOUND) && (csp->q_enabled)) {				/* QSound decoder is loaded and enabled */				if ((1 << runtime->format) & (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |							      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE)) {					/* Only for simple PCM formats */					if (csp->ops.csp_use(csp) == 0) {						/* If CSP was successfully acquired */						goto __start_CSP;					}				}			}		} else if (csp->ops.csp_use(csp) == 0) {			/* Acquire CSP and try to autoload hardware codec */			if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_WRITE)) {				/* Unsupported format, release CSP */				csp->ops.csp_unuse(csp);			} else {		      __start_CSP:				/* Try to start CSP */				if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_PLAYBACK_16) ?						       SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT,						       (runtime->channels > 1) ?						       SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) {					/* Failed, release CSP */					csp->ops.csp_unuse(csp);				} else {					/* Success, CSP acquired and running */					chip->open = SNDRV_SB_CSP_MODE_DSP_WRITE;				}			}		}	}}static void snd_sb16_csp_capture_prepare(sb_t *chip, snd_pcm_runtime_t *runtime){	if (chip->hardware == SB_HW_16CSP) {		snd_sb_csp_t *csp = chip->csp;		if (csp->running & SNDRV_SB_CSP_ST_LOADED) {			/* manually loaded codec */			if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) &&			    ((1U << runtime->format) == csp->acc_format)) {				/* Supported runtime PCM format for capture */				if (csp->ops.csp_use(csp) == 0) {					/* If CSP was successfully acquired */					goto __start_CSP;				}			}		} else if (csp->ops.csp_use(csp) == 0) {			/* Acquire CSP and try to autoload hardware codec */			if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_READ)) {				/* Unsupported format, release CSP */				csp->ops.csp_unuse(csp);			} else {		      __start_CSP:				/* Try to start CSP */				if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_CAPTURE_16) ?						       SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT,						       (runtime->channels > 1) ?						       SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) {					/* Failed, release CSP */					csp->ops.csp_unuse(csp);				} else {					/* Success, CSP acquired and running */					chip->open = SNDRV_SB_CSP_MODE_DSP_READ;				}			}		}	}}static void snd_sb16_csp_update(sb_t *chip){	if (chip->hardware == SB_HW_16CSP) {		snd_sb_csp_t *csp = chip->csp;		if (csp->qpos_changed) {			spin_lock(&chip->reg_lock);			csp->ops.csp_qsound_transfer (csp);			spin_unlock(&chip->reg_lock);		}	}}static void snd_sb16_csp_playback_open(sb_t *chip, snd_pcm_runtime_t *runtime){	/* CSP decoders (QSound excluded) support only 16bit transfers */	if (chip->hardware == SB_HW_16CSP) {		snd_sb_csp_t *csp = chip->csp;		if (csp->running & SNDRV_SB_CSP_ST_LOADED) {			/* manually loaded codec */			if (csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) {				runtime->hw.formats |= csp->acc_format;			}		} else {			/* autoloaded codecs */			runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |					       SNDRV_PCM_FMTBIT_IMA_ADPCM;		}	}}static void snd_sb16_csp_playback_close(sb_t *chip){	if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_WRITE)) {		snd_sb_csp_t *csp = chip->csp;		if (csp->ops.csp_stop(csp) == 0) {			csp->ops.csp_unuse(csp);			chip->open = 0;		}	}}static void snd_sb16_csp_capture_open(sb_t *chip, snd_pcm_runtime_t *runtime){	/* CSP coders support only 16bit transfers */	if (chip->hardware == SB_HW_16CSP) {		snd_sb_csp_t *csp = chip->csp;		if (csp->running & SNDRV_SB_CSP_ST_LOADED) {			/* manually loaded codec */			if (csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) {				runtime->hw.formats |= csp->acc_format;			}		} else {			/* autoloaded codecs */			runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |					       SNDRV_PCM_FMTBIT_IMA_ADPCM;		}	}}static void snd_sb16_csp_capture_close(sb_t *chip){	if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_READ)) {		snd_sb_csp_t *csp = chip->csp;		if (csp->ops.csp_stop(csp) == 0) {			csp->ops.csp_unuse(csp);			chip->open = 0;		}	}}#else#define snd_sb16_csp_playback_prepare(chip, runtime)	/*nop*/#define snd_sb16_csp_capture_prepare(chip, runtime)	/*nop*/#define snd_sb16_csp_update(chip)			/*nop*/#define snd_sb16_csp_playback_open(chip, runtime)	/*nop*/#define snd_sb16_csp_playback_close(chip)		/*nop*/#define snd_sb16_csp_capture_open(chip, runtime)	/*nop*/#define snd_sb16_csp_capture_close(chip)      	 	/*nop*/#endifstatic void snd_sb16_setup_rate(sb_t *chip,				unsigned short rate,				int channel){	unsigned long flags;	spin_lock_irqsave(&chip->reg_lock, flags);	if (chip->mode & (channel == SNDRV_PCM_STREAM_PLAYBACK ? SB_MODE_PLAYBACK_16 : SB_MODE_CAPTURE_16))		snd_sb_ack_16bit(chip);	else		snd_sb_ack_8bit(chip);	if (!(chip->mode & SB_RATE_LOCK)) {		chip->locked_rate = rate;		snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_IN);		snd_sbdsp_command(chip, rate >> 8);		snd_sbdsp_command(chip, rate & 0xff);		snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_OUT);		snd_sbdsp_command(chip, rate >> 8);		snd_sbdsp_command(chip, rate & 0xff);	}	spin_unlock_irqrestore(&chip->reg_lock, flags);}static int snd_sb16_hw_params(snd_pcm_substream_t * substream,			      snd_pcm_hw_params_t * hw_params){	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_sb16_hw_free(snd_pcm_substream_t * substream){	snd_pcm_lib_free_pages(substream);	return 0;}static int snd_sb16_playback_prepare(snd_pcm_substream_t * substream){	unsigned long flags;	sb_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	unsigned char format;	unsigned int size, count, dma;	snd_sb16_csp_playback_prepare(chip, runtime);	if (snd_pcm_format_unsigned(runtime->format) > 0) {		format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO;	} else {		format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO;	}	snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_PLAYBACK);	size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);	dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16;	snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);	count = snd_pcm_lib_period_bytes(substream);	spin_lock_irqsave(&chip->reg_lock, flags);	if (chip->mode & SB_MODE_PLAYBACK_16) {		count >>= 1;		count--;		snd_sbdsp_command(chip, SB_DSP4_OUT16_AI);		snd_sbdsp_command(chip, format);		snd_sbdsp_command(chip, count & 0xff);		snd_sbdsp_command(chip, count >> 8);		snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);	} else {		count--;		snd_sbdsp_command(chip, SB_DSP4_OUT8_AI);		snd_sbdsp_command(chip, format);		snd_sbdsp_command(chip, count & 0xff);		snd_sbdsp_command(chip, count >> 8);		snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);	}	spin_unlock_irqrestore(&chip->reg_lock, flags);	return 0;}static int snd_sb16_playback_trigger(snd_pcm_substream_t * substream,				     int cmd){	sb_t *chip = snd_pcm_substream_chip(substream);	int result = 0;	spin_lock(&chip->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		chip->mode |= SB_RATE_LOCK_PLAYBACK;		snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);		break;	case SNDRV_PCM_TRIGGER_STOP:		snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF);		/* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */		if (chip->mode & SB_RATE_LOCK_CAPTURE)			snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);		chip->mode &= ~SB_RATE_LOCK_PLAYBACK;		break;	default:		result = -EINVAL;	}	spin_unlock(&chip->reg_lock);	return result;}static int snd_sb16_capture_prepare(snd_pcm_substream_t * substream){	unsigned long flags;	sb_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	unsigned char format;	unsigned int size, count, dma;	snd_sb16_csp_capture_prepare(chip, runtime);	if (snd_pcm_format_unsigned(runtime->format) > 0) {		format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO;	} else {		format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO;	}	snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_CAPTURE);	size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);	dma = (chip->mode & SB_MODE_CAPTURE_8) ? chip->dma8 : chip->dma16;	snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);	count = snd_pcm_lib_period_bytes(substream);	spin_lock_irqsave(&chip->reg_lock, flags);	if (chip->mode & SB_MODE_CAPTURE_16) {		count >>= 1;		count--;		snd_sbdsp_command(chip, SB_DSP4_IN16_AI);		snd_sbdsp_command(chip, format);		snd_sbdsp_command(chip, count & 0xff);		snd_sbdsp_command(chip, count >> 8);		snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);	} else {		count--;		snd_sbdsp_command(chip, SB_DSP4_IN8_AI);		snd_sbdsp_command(chip, format);		snd_sbdsp_command(chip, count & 0xff);		snd_sbdsp_command(chip, count >> 8);		snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);	}	spin_unlock_irqrestore(&chip->reg_lock, flags);	return 0;}static int snd_sb16_capture_trigger(snd_pcm_substream_t * substream,				    int cmd){	sb_t *chip = snd_pcm_substream_chip(substream);	int result = 0;	spin_lock(&chip->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		chip->mode |= SB_RATE_LOCK_CAPTURE;		snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);		break;	case SNDRV_PCM_TRIGGER_STOP:		snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF);		/* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */		if (chip->mode & SB_RATE_LOCK_PLAYBACK)			snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);		chip->mode &= ~SB_RATE_LOCK_CAPTURE;		break;	default:		result = -EINVAL;	}	spin_unlock(&chip->reg_lock);	return result;}irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs){	sb_t *chip = dev_id;	unsigned char status;	int ok;	spin_lock(&chip->mixer_lock);	status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);	spin_unlock(&chip->mixer_lock);	if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback)		chip->rmidi_callback(irq, chip->rmidi->private_data, regs);	if (status & SB_IRQTYPE_8BIT) {		ok = 0;		if (chip->mode & SB_MODE_PLAYBACK_8) {			snd_pcm_period_elapsed(chip->playback_substream);			snd_sb16_csp_update(chip);			ok++;		}		if (chip->mode & SB_MODE_CAPTURE_8) {			snd_pcm_period_elapsed(chip->capture_substream);			ok++;		}		spin_lock(&chip->reg_lock);		if (!ok)			snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);		snd_sb_ack_8bit(chip);		spin_unlock(&chip->reg_lock);	}	if (status & SB_IRQTYPE_16BIT) {		ok = 0;		if (chip->mode & SB_MODE_PLAYBACK_16) {			snd_pcm_period_elapsed(chip->playback_substream);			snd_sb16_csp_update(chip);			ok++;		}		if (chip->mode & SB_MODE_CAPTURE_16) {			snd_pcm_period_elapsed(chip->capture_substream);			ok++;		}		spin_lock(&chip->reg_lock);		if (!ok)			snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);		snd_sb_ack_16bit(chip);		spin_unlock(&chip->reg_lock);	}	return IRQ_HANDLED;}/* */static snd_pcm_uframes_t snd_sb16_playback_pointer(snd_pcm_substream_t * substream){	sb_t *chip = snd_pcm_substream_chip(substream);	unsigned int dma;	size_t ptr;	dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16;	ptr = snd_dma_pointer(dma, chip->p_dma_size);	return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_sb16_capture_pointer(snd_pcm_substream_t * substream){	sb_t *chip = snd_pcm_substream_chip(substream);

⌨️ 快捷键说明

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