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

📄 emu8000.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> *     and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk> *  Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de> * *  Routines for control of EMU8000 chip * *   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/wait.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/delay.h>#include <sound/core.h>#include <sound/emu8000.h>#include <sound/emu8000_reg.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/init.h>#include <sound/control.h>#include <sound/initval.h>/* * emu8000 register controls *//* * The following routines read and write registers on the emu8000.  They * should always be called via the EMU8000*READ/WRITE macros and never * directly.  The macros handle the port number and command word. *//* Write a word */void snd_emu8000_poke(emu8000_t *emu, unsigned int port, unsigned int reg, unsigned int val){	unsigned long flags;	spin_lock_irqsave(&emu->reg_lock, flags);	if (reg != emu->last_reg) {		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */		emu->last_reg = reg;	}	outw((unsigned short)val, port); /* Send data */	spin_unlock_irqrestore(&emu->reg_lock, flags);}/* Read a word */unsigned short snd_emu8000_peek(emu8000_t *emu, unsigned int port, unsigned int reg){	unsigned short res;	unsigned long flags;	spin_lock_irqsave(&emu->reg_lock, flags);	if (reg != emu->last_reg) {		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */		emu->last_reg = reg;	}	res = inw(port);	/* Read data */	spin_unlock_irqrestore(&emu->reg_lock, flags);	return res;}/* Write a double word */void snd_emu8000_poke_dw(emu8000_t *emu, unsigned int port, unsigned int reg, unsigned int val){	unsigned long flags;	spin_lock_irqsave(&emu->reg_lock, flags);	if (reg != emu->last_reg) {		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */		emu->last_reg = reg;	}	outw((unsigned short)val, port); /* Send low word of data */	outw((unsigned short)(val>>16), port+2); /* Send high word of data */	spin_unlock_irqrestore(&emu->reg_lock, flags);}/* Read a double word */unsigned int snd_emu8000_peek_dw(emu8000_t *emu, unsigned int port, unsigned int reg){	unsigned short low;	unsigned int res;	unsigned long flags;	spin_lock_irqsave(&emu->reg_lock, flags);	if (reg != emu->last_reg) {		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */		emu->last_reg = reg;	}	low = inw(port);	/* Read low word of data */	res = low + (inw(port+2) << 16);	spin_unlock_irqrestore(&emu->reg_lock, flags);	return res;}/* * Set up / close a channel to be used for DMA. *//*exported*/ voidsnd_emu8000_dma_chan(emu8000_t *emu, int ch, int mode){	unsigned right_bit = (mode & EMU8000_RAM_RIGHT) ? 0x01000000 : 0;	mode &= EMU8000_RAM_MODE_MASK;	if (mode == EMU8000_RAM_CLOSE) {		EMU8000_CCCA_WRITE(emu, ch, 0);		EMU8000_DCYSUSV_WRITE(emu, ch, 0x807F);		return;	}	EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);	EMU8000_VTFT_WRITE(emu, ch, 0);	EMU8000_CVCF_WRITE(emu, ch, 0);	EMU8000_PTRX_WRITE(emu, ch, 0x40000000);	EMU8000_CPF_WRITE(emu, ch, 0x40000000);	EMU8000_PSST_WRITE(emu, ch, 0);	EMU8000_CSL_WRITE(emu, ch, 0);	if (mode == EMU8000_RAM_WRITE) /* DMA write */		EMU8000_CCCA_WRITE(emu, ch, 0x06000000 | right_bit);	else	   /* DMA read */		EMU8000_CCCA_WRITE(emu, ch, 0x04000000 | right_bit);}/* */static void __initsnd_emu8000_read_wait(emu8000_t *emu){	while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {		schedule_timeout_interruptible(1);		if (signal_pending(current))			break;	}}/* */static void __initsnd_emu8000_write_wait(emu8000_t *emu){	while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {		schedule_timeout_interruptible(1);		if (signal_pending(current))			break;	}}/* * detect a card at the given port */static int __initsnd_emu8000_detect(emu8000_t *emu){	/* Initialise */	EMU8000_HWCF1_WRITE(emu, 0x0059);	EMU8000_HWCF2_WRITE(emu, 0x0020);	EMU8000_HWCF3_WRITE(emu, 0x0000);	/* Check for a recognisable emu8000 */	/*	if ((EMU8000_U1_READ(emu) & 0x000f) != 0x000c)		return -ENODEV;		*/	if ((EMU8000_HWCF1_READ(emu) & 0x007e) != 0x0058)		return -ENODEV;	if ((EMU8000_HWCF2_READ(emu) & 0x0003) != 0x0003)		return -ENODEV;	snd_printdd("EMU8000 [0x%lx]: Synth chip found\n",                    emu->port1);	return 0;}/* * intiailize audio channels */static void __initinit_audio(emu8000_t *emu){	int ch;	/* turn off envelope engines */	for (ch = 0; ch < EMU8000_CHANNELS; ch++)		EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);  	/* reset all other parameters to zero */	for (ch = 0; ch < EMU8000_CHANNELS; ch++) {		EMU8000_ENVVOL_WRITE(emu, ch, 0);		EMU8000_ENVVAL_WRITE(emu, ch, 0);		EMU8000_DCYSUS_WRITE(emu, ch, 0);		EMU8000_ATKHLDV_WRITE(emu, ch, 0);		EMU8000_LFO1VAL_WRITE(emu, ch, 0);		EMU8000_ATKHLD_WRITE(emu, ch, 0);		EMU8000_LFO2VAL_WRITE(emu, ch, 0);		EMU8000_IP_WRITE(emu, ch, 0);		EMU8000_IFATN_WRITE(emu, ch, 0);		EMU8000_PEFE_WRITE(emu, ch, 0);		EMU8000_FMMOD_WRITE(emu, ch, 0);		EMU8000_TREMFRQ_WRITE(emu, ch, 0);		EMU8000_FM2FRQ2_WRITE(emu, ch, 0);		EMU8000_PTRX_WRITE(emu, ch, 0);		EMU8000_VTFT_WRITE(emu, ch, 0);		EMU8000_PSST_WRITE(emu, ch, 0);		EMU8000_CSL_WRITE(emu, ch, 0);		EMU8000_CCCA_WRITE(emu, ch, 0);	}	for (ch = 0; ch < EMU8000_CHANNELS; ch++) {		EMU8000_CPF_WRITE(emu, ch, 0);		EMU8000_CVCF_WRITE(emu, ch, 0);	}}/* * initialize DMA address */static void __initinit_dma(emu8000_t *emu){	EMU8000_SMALR_WRITE(emu, 0);	EMU8000_SMARR_WRITE(emu, 0);	EMU8000_SMALW_WRITE(emu, 0);	EMU8000_SMARW_WRITE(emu, 0);}/* * initialization arrays; from ADIP */static unsigned short init1[128] /*__devinitdata*/ = {	0x03ff, 0x0030,  0x07ff, 0x0130, 0x0bff, 0x0230,  0x0fff, 0x0330,	0x13ff, 0x0430,  0x17ff, 0x0530, 0x1bff, 0x0630,  0x1fff, 0x0730,	0x23ff, 0x0830,  0x27ff, 0x0930, 0x2bff, 0x0a30,  0x2fff, 0x0b30,	0x33ff, 0x0c30,  0x37ff, 0x0d30, 0x3bff, 0x0e30,  0x3fff, 0x0f30,	0x43ff, 0x0030,  0x47ff, 0x0130, 0x4bff, 0x0230,  0x4fff, 0x0330,	0x53ff, 0x0430,  0x57ff, 0x0530, 0x5bff, 0x0630,  0x5fff, 0x0730,	0x63ff, 0x0830,  0x67ff, 0x0930, 0x6bff, 0x0a30,  0x6fff, 0x0b30,	0x73ff, 0x0c30,  0x77ff, 0x0d30, 0x7bff, 0x0e30,  0x7fff, 0x0f30,	0x83ff, 0x0030,  0x87ff, 0x0130, 0x8bff, 0x0230,  0x8fff, 0x0330,	0x93ff, 0x0430,  0x97ff, 0x0530, 0x9bff, 0x0630,  0x9fff, 0x0730,	0xa3ff, 0x0830,  0xa7ff, 0x0930, 0xabff, 0x0a30,  0xafff, 0x0b30,	0xb3ff, 0x0c30,  0xb7ff, 0x0d30, 0xbbff, 0x0e30,  0xbfff, 0x0f30,	0xc3ff, 0x0030,  0xc7ff, 0x0130, 0xcbff, 0x0230,  0xcfff, 0x0330,	0xd3ff, 0x0430,  0xd7ff, 0x0530, 0xdbff, 0x0630,  0xdfff, 0x0730,	0xe3ff, 0x0830,  0xe7ff, 0x0930, 0xebff, 0x0a30,  0xefff, 0x0b30,	0xf3ff, 0x0c30,  0xf7ff, 0x0d30, 0xfbff, 0x0e30,  0xffff, 0x0f30,};static unsigned short init2[128] /*__devinitdata*/ = {	0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,	0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,	0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,	0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,	0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,	0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,	0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,	0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,	0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,	0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,	0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,	0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,	0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,	0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,	0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,	0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,};static unsigned short init3[128] /*__devinitdata*/ = {	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,	0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,	0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,	0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,	0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,	0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,};static unsigned short init4[128] /*__devinitdata*/ = {	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,	0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,	0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,	0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,	0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,	0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,};/* send an initialization array * Taken from the oss driver, not obvious from the doc how this * is meant to work */static void __initsend_array(emu8000_t *emu, unsigned short *data, int size){	int i;	unsigned short *p;	p = data;	for (i = 0; i < size; i++, p++)		EMU8000_INIT1_WRITE(emu, i, *p);	for (i = 0; i < size; i++, p++)		EMU8000_INIT2_WRITE(emu, i, *p);	for (i = 0; i < size; i++, p++)		EMU8000_INIT3_WRITE(emu, i, *p);	for (i = 0; i < size; i++, p++)		EMU8000_INIT4_WRITE(emu, i, *p);}/* * Send initialization arrays to start up, this just follows the * initialisation sequence in the adip. */static void __initinit_arrays(emu8000_t *emu){	send_array(emu, init1, ARRAY_SIZE(init1)/4);	msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */	send_array(emu, init2, ARRAY_SIZE(init2)/4);	send_array(emu, init3, ARRAY_SIZE(init3)/4);	EMU8000_HWCF4_WRITE(emu, 0);	EMU8000_HWCF5_WRITE(emu, 0x83);	EMU8000_HWCF6_WRITE(emu, 0x8000);	send_array(emu, init4, ARRAY_SIZE(init4)/4);}#define UNIQUE_ID1	0xa5b9#define UNIQUE_ID2	0x9d53/* * Size the onboard memory. * This is written so as not to need arbitary delays after the write. It * seems that the only way to do this is to use the one channel and keep * reallocating between read and write. */static void __initsize_dram(emu8000_t *emu){	int i, size;	if (emu->dram_checked)		return;	size = 0;

⌨️ 快捷键说明

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