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

📄 trident_main.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  Maintained by Jaroslav Kysela <perex@suse.cz> *  Originated by audio@tridentmicro.com *  Fri Feb 19 15:55:28 MST 1999 *  Routines for control of Trident 4DWave (DX and NX) chip * *  BUGS: * *  TODO: *    --- * *   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 * * *  SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net> */#include <sound/driver.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/gameport.h>#include <sound/core.h>#include <sound/info.h>#include <sound/control.h>#include <sound/trident.h>#include <sound/asoundef.h>#include <asm/io.h>static int snd_trident_pcm_mixer_build(trident_t *trident, snd_trident_voice_t * voice, snd_pcm_substream_t *substream);static int snd_trident_pcm_mixer_free(trident_t *trident, snd_trident_voice_t * voice, snd_pcm_substream_t *substream);static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);#ifdef CONFIG_PMstatic int snd_trident_suspend(snd_card_t *card, pm_message_t state);static int snd_trident_resume(snd_card_t *card);#endifstatic int snd_trident_sis_reset(trident_t *trident);static void snd_trident_clear_voices(trident_t * trident, unsigned short v_min, unsigned short v_max);static int snd_trident_free(trident_t *trident);/* *  common I/O routines */#if 0static void snd_trident_print_voice_regs(trident_t *trident, int voice){	unsigned int val, tmp;	printk("Trident voice %i:\n", voice);	outb(voice, TRID_REG(trident, T4D_LFO_GC_CIR));	val = inl(TRID_REG(trident, CH_LBA));	printk("LBA: 0x%x\n", val);	val = inl(TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));	printk("GVSel: %i\n", val >> 31);	printk("Pan: 0x%x\n", (val >> 24) & 0x7f);	printk("Vol: 0x%x\n", (val >> 16) & 0xff);	printk("CTRL: 0x%x\n", (val >> 12) & 0x0f);	printk("EC: 0x%x\n", val & 0x0fff);	if (trident->device != TRIDENT_DEVICE_ID_NX) {		val = inl(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS));		printk("CSO: 0x%x\n", val >> 16);		printk("Alpha: 0x%x\n", (val >> 4) & 0x0fff);		printk("FMS: 0x%x\n", val & 0x0f);		val = inl(TRID_REG(trident, CH_DX_ESO_DELTA));		printk("ESO: 0x%x\n", val >> 16);		printk("Delta: 0x%x\n", val & 0xffff);		val = inl(TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));	} else {		// TRIDENT_DEVICE_ID_NX		val = inl(TRID_REG(trident, CH_NX_DELTA_CSO));		tmp = (val >> 24) & 0xff;		printk("CSO: 0x%x\n", val & 0x00ffffff);		val = inl(TRID_REG(trident, CH_NX_DELTA_ESO));		tmp |= (val >> 16) & 0xff00;		printk("Delta: 0x%x\n", tmp);		printk("ESO: 0x%x\n", val & 0x00ffffff);		val = inl(TRID_REG(trident, CH_NX_ALPHA_FMS_FMC_RVOL_CVOL));		printk("Alpha: 0x%x\n", val >> 20);		printk("FMS: 0x%x\n", (val >> 16) & 0x0f);	}	printk("FMC: 0x%x\n", (val >> 14) & 3);	printk("RVol: 0x%x\n", (val >> 7) & 0x7f);	printk("CVol: 0x%x\n", val & 0x7f);}#endif/*---------------------------------------------------------------------------   unsigned short snd_trident_codec_read(ac97_t *ac97, unsigned short reg)     Description: This routine will do all of the reading from the external                CODEC (AC97).     Parameters:  ac97 - ac97 codec structure                reg - CODEC register index, from AC97 Hal.    returns:     16 bit value read from the AC97.    ---------------------------------------------------------------------------*/static unsigned short snd_trident_codec_read(ac97_t *ac97, unsigned short reg){	unsigned int data = 0, treg;	unsigned short count = 0xffff;	unsigned long flags;	trident_t *trident = ac97->private_data;	spin_lock_irqsave(&trident->reg_lock, flags);	if (trident->device == TRIDENT_DEVICE_ID_DX) {		data = (DX_AC97_BUSY_READ | (reg & 0x000000ff));		outl(data, TRID_REG(trident, DX_ACR1_AC97_R));		do {			data = inl(TRID_REG(trident, DX_ACR1_AC97_R));			if ((data & DX_AC97_BUSY_READ) == 0)				break;		} while (--count);	} else if (trident->device == TRIDENT_DEVICE_ID_NX) {		data = (NX_AC97_BUSY_READ | (reg & 0x000000ff));		treg = ac97->num == 0 ? NX_ACR2_AC97_R_PRIMARY : NX_ACR3_AC97_R_SECONDARY;		outl(data, TRID_REG(trident, treg));		do {			data = inl(TRID_REG(trident, treg));			if ((data & 0x00000C00) == 0)				break;		} while (--count);	} else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {		data = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY | (reg & 0x000000ff);		if (ac97->num == 1)			data |= SI_AC97_SECONDARY;		outl(data, TRID_REG(trident, SI_AC97_READ));		do {			data = inl(TRID_REG(trident, SI_AC97_READ));			if ((data & (SI_AC97_BUSY_READ)) == 0)				break;		} while (--count);	}	if (count == 0 && !trident->ac97_detect) {		snd_printk(KERN_ERR "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", reg, data);		data = 0;	}	spin_unlock_irqrestore(&trident->reg_lock, flags);	return ((unsigned short) (data >> 16));}/*---------------------------------------------------------------------------   void snd_trident_codec_write(ac97_t *ac97, unsigned short reg, unsigned short wdata)     Description: This routine will do all of the writing to the external                CODEC (AC97).     Parameters:	ac97 - ac97 codec structure   	        reg - CODEC register index, from AC97 Hal.                data  - Lower 16 bits are the data to write to CODEC.     returns:     TRUE if everything went ok, else FALSE.    ---------------------------------------------------------------------------*/static void snd_trident_codec_write(ac97_t *ac97, unsigned short reg, unsigned short wdata){	unsigned int address, data;	unsigned short count = 0xffff;	unsigned long flags;	trident_t *trident = ac97->private_data;	data = ((unsigned long) wdata) << 16;	spin_lock_irqsave(&trident->reg_lock, flags);	if (trident->device == TRIDENT_DEVICE_ID_DX) {		address = DX_ACR0_AC97_W;		/* read AC-97 write register status */		do {			if ((inw(TRID_REG(trident, address)) & DX_AC97_BUSY_WRITE) == 0)				break;		} while (--count);		data |= (DX_AC97_BUSY_WRITE | (reg & 0x000000ff));	} else if (trident->device == TRIDENT_DEVICE_ID_NX) {		address = NX_ACR1_AC97_W;		/* read AC-97 write register status */		do {			if ((inw(TRID_REG(trident, address)) & NX_AC97_BUSY_WRITE) == 0)				break;		} while (--count);		data |= (NX_AC97_BUSY_WRITE | (ac97->num << 8) | (reg & 0x000000ff));	} else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {		address = SI_AC97_WRITE;		/* read AC-97 write register status */		do {			if ((inw(TRID_REG(trident, address)) & (SI_AC97_BUSY_WRITE)) == 0)				break;		} while (--count);		data |= SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY | (reg & 0x000000ff);		if (ac97->num == 1)			data |= SI_AC97_SECONDARY;	} else {		address = 0;	/* keep GCC happy */		count = 0;	/* return */	}	if (count == 0) {		spin_unlock_irqrestore(&trident->reg_lock, flags);		return;	}	outl(data, TRID_REG(trident, address));	spin_unlock_irqrestore(&trident->reg_lock, flags);}/*---------------------------------------------------------------------------   void snd_trident_enable_eso(trident_t *trident)     Description: This routine will enable end of loop interrupts.                End of loop interrupts will occur when a running                channel reaches ESO.                Also enables middle of loop interrupts.     Parameters:  trident - pointer to target device class for 4DWave.    ---------------------------------------------------------------------------*/static void snd_trident_enable_eso(trident_t * trident){	unsigned int val;	val = inl(TRID_REG(trident, T4D_LFO_GC_CIR));	val |= ENDLP_IE;	val |= MIDLP_IE;	if (trident->device == TRIDENT_DEVICE_ID_SI7018)		val |= BANK_B_EN;	outl(val, TRID_REG(trident, T4D_LFO_GC_CIR));}/*---------------------------------------------------------------------------   void snd_trident_disable_eso(trident_t *trident)     Description: This routine will disable end of loop interrupts.                End of loop interrupts will occur when a running                channel reaches ESO.                Also disables middle of loop interrupts.     Parameters:                  trident - pointer to target device class for 4DWave.     returns:     TRUE if everything went ok, else FALSE.    ---------------------------------------------------------------------------*/static void snd_trident_disable_eso(trident_t * trident){	unsigned int tmp;	tmp = inl(TRID_REG(trident, T4D_LFO_GC_CIR));	tmp &= ~ENDLP_IE;	tmp &= ~MIDLP_IE;	outl(tmp, TRID_REG(trident, T4D_LFO_GC_CIR));}/*---------------------------------------------------------------------------   void snd_trident_start_voice(trident_t * trident, unsigned int voice)    Description: Start a voice, any channel 0 thru 63.                 This routine automatically handles the fact that there are                 more than 32 channels available.    Parameters : voice - Voice number 0 thru n.                 trident - pointer to target device class for 4DWave.    Return Value: None.  ---------------------------------------------------------------------------*/void snd_trident_start_voice(trident_t * trident, unsigned int voice){	unsigned int mask = 1 << (voice & 0x1f);	unsigned int reg = (voice & 0x20) ? T4D_START_B : T4D_START_A;	outl(mask, TRID_REG(trident, reg));}/*---------------------------------------------------------------------------   void snd_trident_stop_voice(trident_t * trident, unsigned int voice)    Description: Stop a voice, any channel 0 thru 63.                 This routine automatically handles the fact that there are                 more than 32 channels available.    Parameters : voice - Voice number 0 thru n.                 trident - pointer to target device class for 4DWave.    Return Value: None.  ---------------------------------------------------------------------------*/void snd_trident_stop_voice(trident_t * trident, unsigned int voice){	unsigned int mask = 1 << (voice & 0x1f);	unsigned int reg = (voice & 0x20) ? T4D_STOP_B : T4D_STOP_A;	outl(mask, TRID_REG(trident, reg));}/*---------------------------------------------------------------------------    int snd_trident_allocate_pcm_channel(trident_t *trident)      Description: Allocate hardware channel in Bank B (32-63).      Parameters :  trident - pointer to target device class for 4DWave.      Return Value: hardware channel - 32-63 or -1 when no channel is available    ---------------------------------------------------------------------------*/static int snd_trident_allocate_pcm_channel(trident_t * trident){	int idx;	if (trident->ChanPCMcnt >= trident->ChanPCM)		return -1;	for (idx = 31; idx >= 0; idx--) {		if (!(trident->ChanMap[T4D_BANK_B] & (1 << idx))) {			trident->ChanMap[T4D_BANK_B] |= 1 << idx;			trident->ChanPCMcnt++;			return idx + 32;		}	}	return -1;}/*---------------------------------------------------------------------------    void snd_trident_free_pcm_channel(int channel)      Description: Free hardware channel in Bank B (32-63)      Parameters :  trident - pointer to target device class for 4DWave.	          channel - hardware channel number 0-63      Return Value: none    ---------------------------------------------------------------------------*/static void snd_trident_free_pcm_channel(trident_t *trident, int channel){	if (channel < 32 || channel > 63)		return;	channel &= 0x1f;	if (trident->ChanMap[T4D_BANK_B] & (1 << channel)) {		trident->ChanMap[T4D_BANK_B] &= ~(1 << channel);		trident->ChanPCMcnt--;	}}/*---------------------------------------------------------------------------    unsigned int snd_trident_allocate_synth_channel(void)      Description: Allocate hardware channel in Bank A (0-31).      Parameters :  trident - pointer to target device class for 4DWave.      Return Value: hardware channel - 0-31 or -1 when no channel is available    ---------------------------------------------------------------------------*/static int snd_trident_allocate_synth_channel(trident_t * trident){	int idx;	for (idx = 31; idx >= 0; idx--) {		if (!(trident->ChanMap[T4D_BANK_A] & (1 << idx))) {			trident->ChanMap[T4D_BANK_A] |= 1 << idx;			trident->synth.ChanSynthCount++;			return idx;		}	}	return -1;}/*---------------------------------------------------------------------------    void snd_trident_free_synth_channel( int channel )      Description: Free hardware channel in Bank B (0-31).      Parameters :  trident - pointer to target device class for 4DWave.	          channel - hardware channel number 0-63      Return Value: none    ---------------------------------------------------------------------------*/static void snd_trident_free_synth_channel(trident_t *trident, int channel){	if (channel < 0 || channel > 31)

⌨️ 快捷键说明

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