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

📄 emu10k1_main.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@perex.cz> *                   Creative Labs, Inc. *  Routines for control of EMU10K1 chips * *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> *      Added support for Audigy 2 Value. *  	Added EMU 1010 support. *  	General bug fixes and enhancements. * * *  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 * */#include <linux/sched.h>#include <linux/kthread.h>#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/mutex.h>#include <sound/core.h>#include <sound/emu10k1.h>#include <linux/firmware.h>#include "p16v.h"#include "tina2.h"#include "p17v.h"#define HANA_FILENAME "emu/hana.fw"#define DOCK_FILENAME "emu/audio_dock.fw"#define EMU1010B_FILENAME "emu/emu1010b.fw"#define MICRO_DOCK_FILENAME "emu/micro_dock.fw"#define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"MODULE_FIRMWARE(HANA_FILENAME);MODULE_FIRMWARE(DOCK_FILENAME);MODULE_FIRMWARE(EMU1010B_FILENAME);MODULE_FIRMWARE(MICRO_DOCK_FILENAME);MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);/************************************************************************* * EMU10K1 init / done *************************************************************************/void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch){	snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0);	snd_emu10k1_ptr_write(emu, IP, ch, 0);	snd_emu10k1_ptr_write(emu, VTFT, ch, 0xffff);	snd_emu10k1_ptr_write(emu, CVCF, ch, 0xffff);	snd_emu10k1_ptr_write(emu, PTRX, ch, 0);	snd_emu10k1_ptr_write(emu, CPF, ch, 0);	snd_emu10k1_ptr_write(emu, CCR, ch, 0);	snd_emu10k1_ptr_write(emu, PSST, ch, 0);	snd_emu10k1_ptr_write(emu, DSL, ch, 0x10);	snd_emu10k1_ptr_write(emu, CCCA, ch, 0);	snd_emu10k1_ptr_write(emu, Z1, ch, 0);	snd_emu10k1_ptr_write(emu, Z2, ch, 0);	snd_emu10k1_ptr_write(emu, FXRT, ch, 0x32100000);	snd_emu10k1_ptr_write(emu, ATKHLDM, ch, 0);	snd_emu10k1_ptr_write(emu, DCYSUSM, ch, 0);	snd_emu10k1_ptr_write(emu, IFATN, ch, 0xffff);	snd_emu10k1_ptr_write(emu, PEFE, ch, 0);	snd_emu10k1_ptr_write(emu, FMMOD, ch, 0);	snd_emu10k1_ptr_write(emu, TREMFRQ, ch, 24);	/* 1 Hz */	snd_emu10k1_ptr_write(emu, FM2FRQ2, ch, 24);	/* 1 Hz */	snd_emu10k1_ptr_write(emu, TEMPENV, ch, 0);	/*** these are last so OFF prevents writing ***/	snd_emu10k1_ptr_write(emu, LFOVAL2, ch, 0);	snd_emu10k1_ptr_write(emu, LFOVAL1, ch, 0);	snd_emu10k1_ptr_write(emu, ATKHLDV, ch, 0);	snd_emu10k1_ptr_write(emu, ENVVOL, ch, 0);	snd_emu10k1_ptr_write(emu, ENVVAL, ch, 0);	/* Audigy extra stuffs */	if (emu->audigy) {		snd_emu10k1_ptr_write(emu, 0x4c, ch, 0); /* ?? */		snd_emu10k1_ptr_write(emu, 0x4d, ch, 0); /* ?? */		snd_emu10k1_ptr_write(emu, 0x4e, ch, 0); /* ?? */		snd_emu10k1_ptr_write(emu, 0x4f, ch, 0); /* ?? */		snd_emu10k1_ptr_write(emu, A_FXRT1, ch, 0x03020100);		snd_emu10k1_ptr_write(emu, A_FXRT2, ch, 0x3f3f3f3f);		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, ch, 0);	}}static unsigned int spi_dac_init[] = {		0x00ff,		0x02ff,		0x0400,		0x0520,		0x0600,		0x08ff,		0x0aff,		0x0cff,		0x0eff,		0x10ff,		0x1200,		0x1400,		0x1480,		0x1800,		0x1aff,		0x1cff,		0x1e00,		0x0530,		0x0602,		0x0622,		0x1400,};static unsigned int i2c_adc_init[][2] = {	{ 0x17, 0x00 }, /* Reset */	{ 0x07, 0x00 }, /* Timeout */	{ 0x0b, 0x22 },  /* Interface control */	{ 0x0c, 0x22 },  /* Master mode control */	{ 0x0d, 0x08 },  /* Powerdown control */	{ 0x0e, 0xcf },  /* Attenuation Left  0x01 = -103dB, 0xff = 24dB */	{ 0x0f, 0xcf },  /* Attenuation Right 0.5dB steps */	{ 0x10, 0x7b },  /* ALC Control 1 */	{ 0x11, 0x00 },  /* ALC Control 2 */	{ 0x12, 0x32 },  /* ALC Control 3 */	{ 0x13, 0x00 },  /* Noise gate control */	{ 0x14, 0xa6 },  /* Limiter control */	{ 0x15, ADC_MUX_2 },  /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */};	static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume){	unsigned int silent_page;	int ch;	u32 tmp;	/* disable audio and lock cache */	outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,	     emu->port + HCFG);	/* reset recording buffers */	snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE);	snd_emu10k1_ptr_write(emu, MICBA, 0, 0);	snd_emu10k1_ptr_write(emu, FXBS, 0, ADCBS_BUFSIZE_NONE);	snd_emu10k1_ptr_write(emu, FXBA, 0, 0);	snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE);	snd_emu10k1_ptr_write(emu, ADCBA, 0, 0);	/* disable channel interrupt */	outl(0, emu->port + INTE);	snd_emu10k1_ptr_write(emu, CLIEL, 0, 0);	snd_emu10k1_ptr_write(emu, CLIEH, 0, 0);	snd_emu10k1_ptr_write(emu, SOLEL, 0, 0);	snd_emu10k1_ptr_write(emu, SOLEH, 0, 0);	if (emu->audigy){		/* set SPDIF bypass mode */		snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT);		/* enable rear left + rear right AC97 slots */		snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT |				      AC97SLOT_REAR_LEFT);	}	/* init envelope engine */	for (ch = 0; ch < NUM_G; ch++)		snd_emu10k1_voice_init(emu, ch);	snd_emu10k1_ptr_write(emu, SPCS0, 0, emu->spdif_bits[0]);	snd_emu10k1_ptr_write(emu, SPCS1, 0, emu->spdif_bits[1]);	snd_emu10k1_ptr_write(emu, SPCS2, 0, emu->spdif_bits[2]);	if (emu->card_capabilities->ca0151_chip) { /* audigy2 */		/* Hacks for Alice3 to work independent of haP16V driver */		//Setup SRCMulti_I2S SamplingRate		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);		tmp &= 0xfffff1ff;		tmp |= (0x2<<9);		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);				/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */		snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14);		/* Setup SRCMulti Input Audio Enable */		/* Use 0xFFFFFFFF to enable P16V sounds. */		snd_emu10k1_ptr20_write(emu, SRCMULTI_ENABLE, 0, 0xFFFFFFFF);		/* Enabled Phased (8-channel) P16V playback */		outl(0x0201, emu->port + HCFG2);		/* Set playback routing. */		snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4);	}	if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */		/* Hacks for Alice3 to work independent of haP16V driver */		snd_printk(KERN_INFO "Audigy2 value: Special config.\n");		//Setup SRCMulti_I2S SamplingRate		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);		tmp &= 0xfffff1ff;		tmp |= (0x2<<9);		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);		/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */		outl(0x600000, emu->port + 0x20);		outl(0x14, emu->port + 0x24);		/* Setup SRCMulti Input Audio Enable */		outl(0x7b0000, emu->port + 0x20);		outl(0xFF000000, emu->port + 0x24);		/* Setup SPDIF Out Audio Enable */		/* The Audigy 2 Value has a separate SPDIF out,		 * so no need for a mixer switch		 */		outl(0x7a0000, emu->port + 0x20);		outl(0xFF000000, emu->port + 0x24);		tmp = inl(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */		outl(tmp, emu->port + A_IOCFG);	}	if (emu->card_capabilities->spi_dac) { /* Audigy 2 ZS Notebook with DAC Wolfson WM8768/WM8568 */		int size, n;		size = ARRAY_SIZE(spi_dac_init);		for (n = 0; n < size; n++)			snd_emu10k1_spi_write(emu, spi_dac_init[n]);		snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10);		/* Enable GPIOs		 * GPIO0: Unknown		 * GPIO1: Speakers-enabled.		 * GPIO2: Unknown		 * GPIO3: Unknown		 * GPIO4: IEC958 Output on.		 * GPIO5: Unknown		 * GPIO6: Unknown		 * GPIO7: Unknown		 */		outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */	}	if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */		int size, n;		snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f);		tmp = inl(emu->port + A_IOCFG);		outl(tmp | 0x4, emu->port + A_IOCFG);  /* Set bit 2 for mic input */		tmp = inl(emu->port + A_IOCFG);		size = ARRAY_SIZE(i2c_adc_init);		for (n = 0; n < size; n++)			snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]);		for (n=0; n < 4; n++) {			emu->i2c_capture_volume[n][0]= 0xcf;			emu->i2c_capture_volume[n][1]= 0xcf;		}	}		snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);	snd_emu10k1_ptr_write(emu, TCB, 0, 0);	/* taken from original driver */	snd_emu10k1_ptr_write(emu, TCBS, 0, 4);	/* taken from original driver */	silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK;	for (ch = 0; ch < NUM_G; ch++) {		snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page);		snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);	}	if (emu->card_capabilities->emu1010) {		outl(HCFG_AUTOMUTE_ASYNC |			HCFG_EMU32_SLAVE |			HCFG_AUDIOENABLE, emu->port + HCFG);	/*	 *  Hokay, setup HCFG	 *   Mute Disable Audio = 0	 *   Lock Tank Memory = 1	 *   Lock Sound Memory = 0	 *   Auto Mute = 1	 */	} else if (emu->audigy) {		if (emu->revision == 4) /* audigy2 */			outl(HCFG_AUDIOENABLE |			     HCFG_AC3ENABLE_CDSPDIF |			     HCFG_AC3ENABLE_GPSPDIF |			     HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);		else			outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);	/* FIXME: Remove all these emu->model and replace it with a card recognition parameter,	 * e.g. card_capabilities->joystick */	} else if (emu->model == 0x20 ||	    emu->model == 0xc400 ||	    (emu->model == 0x21 && emu->revision < 6))		outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG);	else		// With on-chip joystick		outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);	if (enable_ir) {	/* enable IR for SB Live */		if (emu->card_capabilities->emu1010) {			;  /* Disable all access to A_IOCFG for the emu1010 */		} else if (emu->card_capabilities->i2c_adc) {			;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */		} else if (emu->audigy) {			unsigned int reg = inl(emu->port + A_IOCFG);			outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);			udelay(500);			outl(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG);			udelay(100);			outl(reg, emu->port + A_IOCFG);		} else {			unsigned int reg = inl(emu->port + HCFG);			outl(reg | HCFG_GPOUT2, emu->port + HCFG);			udelay(500);			outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG);			udelay(100);			outl(reg, emu->port + HCFG); 		}	}		if (emu->card_capabilities->emu1010) {		;  /* Disable all access to A_IOCFG for the emu1010 */	} else if (emu->card_capabilities->i2c_adc) {		;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */	} else if (emu->audigy) {	/* enable analog output */		unsigned int reg = inl(emu->port + A_IOCFG);		outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);	}	return 0;}static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu){	/*	 *  Enable the audio bit	 */	outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);	/* Enable analog/digital outs on audigy */	if (emu->card_capabilities->emu1010) {		;  /* Disable all access to A_IOCFG for the emu1010 */	} else if (emu->card_capabilities->i2c_adc) {		;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */	} else if (emu->audigy) {		outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); 		if (emu->card_capabilities->ca0151_chip) { /* audigy2 */			/* Unmute Analog now.  Set GPO6 to 1 for Apollo.			 * This has to be done after init ALice3 I2SOut beyond 48KHz.			 * So, sequence is important. */			outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG);		} else if (emu->card_capabilities->ca0108_chip) { /* audigy2 value */			/* Unmute Analog now. */			outl(inl(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG);		} else {			/* Disable routing from AC97 line out to Front speakers */			outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG);		}	}	#if 0	{	unsigned int tmp;	/* FIXME: the following routine disables LiveDrive-II !! */	// TOSLink detection	emu->tos_link = 0;	tmp = inl(emu->port + HCFG);	if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {		outl(tmp|0x800, emu->port + HCFG);		udelay(50);		if (tmp != (inl(emu->port + HCFG) & ~0x800)) {			emu->tos_link = 1;			outl(tmp, emu->port + HCFG);		}

⌨️ 快捷键说明

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