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

📄 au88x0_core.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  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 Library 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. *//*    Vortex core low level functions.	 Author: Manuel Jander (mjander@users.sourceforge.cl) These functions are mainly the result of translations made from the original disassembly of the au88x0 binary drivers, written by Aureal before they went down. Many thanks to the Jeff Muizelaar, Kester Maddock, and whoever contributed to the OpenVortex project. The author of this file, put the few available pieces together and translated the rest of the riddle (Mix, Src and connection stuff). Some things are still to be discovered, and their meanings are unclear. Some of these functions aren't intended to be really used, rather to help to understand how does the AU88X0 chips work. Keep them in, because they could be used somewhere in the future. This code hasn't been tested or proof read thoroughly. If you wanna help, take a look at the AU88X0 assembly and check if this matches. Functions tested ok so far are (they show the desired effect at least):   vortex_routes(); (1 bug fixed).   vortex_adb_addroute();   vortex_adb_addroutes();   vortex_connect_codecplay();   vortex_src_flushbuffers();   vortex_adbdma_setmode();  note: still some unknown arguments!   vortex_adbdma_startfifo();   vortex_adbdma_stopfifo();   vortex_fifo_setadbctrl(); note: still some unknown arguments!   vortex_mix_setinputvolumebyte();   vortex_mix_enableinput();   vortex_mixer_addWTD(); (fixed)   vortex_connection_adbdma_src_src();   vortex_connection_adbdma_src();   vortex_src_change_convratio();   vortex_src_addWTD(); (fixed) History: 01-03-2003 First revision. 01-21-2003 Some bug fixes. 17-02-2003 many bugfixes after a big versioning mess. 18-02-2003 JAAAAAHHHUUUUUU!!!! The mixer works !! I'm just so happy !			 (2 hours later...) I cant believe it! Im really lucky today.			 Now the SRC is working too! Yeah! XMMS works ! 20-02-2003 First steps into the ALSA world. 28-02-2003 As my birthday present, i discovered how the DMA buffer pages really            work :-). It was all wrong. 12-03-2003 ALSA driver starts working (2 channels). 16-03-2003 More srcblock_setupchannel discoveries. 12-04-2003 AU8830 playback support. Recording in the works. 17-04-2003 vortex_route() and vortex_routes() bug fixes. AU8830 recording 			works now, but chipn' dale effect is still there. 16-05-2003 SrcSetupChannel cleanup. Moved the Src setup stuff entirely            into au88x0_pcm.c . 06-06-2003 Buffer shifter bugfix. Mixer volume fix. 07-12-2003 A3D routing finally fixed. Believed to be OK. 25-03-2004 Many thanks to Claudia, for such valuable bug reports. */#include "au88x0.h"#include "au88x0_a3d.h"#include <linux/delay.h>/*  MIXER (CAsp4Mix.s and CAsp4Mixer.s) */// FIXME: get rid of this.static int mchannels[NR_MIXIN];static int rampchs[NR_MIXIN];static void vortex_mixer_en_sr(vortex_t * vortex, int channel){	hwwrite(vortex->mmio, VORTEX_MIXER_SR,		hwread(vortex->mmio, VORTEX_MIXER_SR) | (0x1 << channel));}static void vortex_mixer_dis_sr(vortex_t * vortex, int channel){	hwwrite(vortex->mmio, VORTEX_MIXER_SR,		hwread(vortex->mmio, VORTEX_MIXER_SR) & ~(0x1 << channel));}#if 0static voidvortex_mix_muteinputgain(vortex_t * vortex, unsigned char mix,			 unsigned char channel){	hwwrite(vortex->mmio, VORTEX_MIX_INVOL_A + ((mix << 5) + channel),		0x80);	hwwrite(vortex->mmio, VORTEX_MIX_INVOL_B + ((mix << 5) + channel),		0x80);}static int vortex_mix_getvolume(vortex_t * vortex, unsigned char mix){	int a;	a = hwread(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2)) & 0xff;	//FP2LinearFrac(a);	return (a);}static intvortex_mix_getinputvolume(vortex_t * vortex, unsigned char mix,			  int channel, int *vol){	int a;	if (!(mchannels[mix] & (1 << channel)))		return 0;	a = hwread(vortex->mmio,		   VORTEX_MIX_INVOL_A + (((mix << 5) + channel) << 2));	/*	   if (rampchs[mix] == 0)	   a = FP2LinearFrac(a);	   else	   a = FP2LinearFracWT(a);	 */	*vol = a;	return (0);}static unsigned int vortex_mix_boost6db(unsigned char vol){	return (vol + 8);	/* WOW! what a complex function! */}static void vortex_mix_rampvolume(vortex_t * vortex, int mix){	int ch;	char a;	// This function is intended for ramping down only (see vortex_disableinput()).	for (ch = 0; ch < 0x20; ch++) {		if (((1 << ch) & rampchs[mix]) == 0)			continue;		a = hwread(vortex->mmio,			   VORTEX_MIX_INVOL_B + (((mix << 5) + ch) << 2));		if (a > -126) {			a -= 2;			hwwrite(vortex->mmio,				VORTEX_MIX_INVOL_A +				(((mix << 5) + ch) << 2), a);			hwwrite(vortex->mmio,				VORTEX_MIX_INVOL_B +				(((mix << 5) + ch) << 2), a);		} else			vortex_mix_killinput(vortex, mix, ch);	}}static intvortex_mix_getenablebit(vortex_t * vortex, unsigned char mix, int mixin){	int addr, temp;	if (mixin >= 0)		addr = mixin;	else		addr = mixin + 3;	addr = ((mix << 3) + (addr >> 2)) << 2;	temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr);	return ((temp >> (mixin & 3)) & 1);}#endifstatic voidvortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,			 unsigned char vol){	int temp;	hwwrite(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2), vol);	if (1) {		/*if (this_10) */		temp = hwread(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2));		if ((temp != 0x80) || (vol == 0x80))			return;	}	hwwrite(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2), vol);}static voidvortex_mix_setinputvolumebyte(vortex_t * vortex, unsigned char mix,			      int mixin, unsigned char vol){	int temp;	hwwrite(vortex->mmio,		VORTEX_MIX_INVOL_A + (((mix << 5) + mixin) << 2), vol);	if (1) {		/* this_10, initialized to 1. */		temp =		    hwread(vortex->mmio,			   VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2));		if ((temp != 0x80) || (vol == 0x80))			return;	}	hwwrite(vortex->mmio,		VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), vol);}static voidvortex_mix_setenablebit(vortex_t * vortex, unsigned char mix, int mixin, int en){	int temp, addr;	if (mixin < 0)		addr = (mixin + 3);	else		addr = mixin;	addr = ((mix << 3) + (addr >> 2)) << 2;	temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr);	if (en)		temp |= (1 << (mixin & 3));	else		temp &= ~(1 << (mixin & 3));	/* Mute input. Astatic void crackling? */	hwwrite(vortex->mmio,		VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), 0x80);	/* Looks like clear buffer. */	hwwrite(vortex->mmio, VORTEX_MIX_SMP + (mixin << 2), 0x0);	hwwrite(vortex->mmio, VORTEX_MIX_SMP + 4 + (mixin << 2), 0x0);	/* Write enable bit. */	hwwrite(vortex->mmio, VORTEX_MIX_ENIN + addr, temp);}static voidvortex_mix_killinput(vortex_t * vortex, unsigned char mix, int mixin){	rampchs[mix] &= ~(1 << mixin);	vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80);	mchannels[mix] &= ~(1 << mixin);	vortex_mix_setenablebit(vortex, mix, mixin, 0);}static voidvortex_mix_enableinput(vortex_t * vortex, unsigned char mix, int mixin){	vortex_mix_killinput(vortex, mix, mixin);	if ((mchannels[mix] & (1 << mixin)) == 0) {		vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80);	/*0x80 : mute */		mchannels[mix] |= (1 << mixin);	}	vortex_mix_setenablebit(vortex, mix, mixin, 1);}static voidvortex_mix_disableinput(vortex_t * vortex, unsigned char mix, int channel,			int ramp){	if (ramp) {		rampchs[mix] |= (1 << channel);		// Register callback.		//vortex_mix_startrampvolume(vortex);		vortex_mix_killinput(vortex, mix, channel);	} else		vortex_mix_killinput(vortex, mix, channel);}static intvortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch){	int temp, lifeboat = 0, prev;	temp = hwread(vortex->mmio, VORTEX_MIXER_SR);	if ((temp & (1 << ch)) == 0) {		hwwrite(vortex->mmio, VORTEX_MIXER_CHNBASE + (ch << 2), mix);		vortex_mixer_en_sr(vortex, ch);		return 1;	}	prev = VORTEX_MIXER_CHNBASE + (ch << 2);	temp = hwread(vortex->mmio, prev);	while (temp & 0x10) {		prev = VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2);		temp = hwread(vortex->mmio, prev);		//printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp);		if ((++lifeboat) > 0xf) {			printk(KERN_ERR			       "vortex_mixer_addWTD: lifeboat overflow\n");			return 0;		}	}	hwwrite(vortex->mmio, VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2), mix);	hwwrite(vortex->mmio, prev, (temp & 0xf) | 0x10);	return 1;}static intvortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch){	int esp14 = -1, esp18, eax, ebx, edx, ebp, esi = 0;	//int esp1f=edi(while)=src, esp10=ch;	eax = hwread(vortex->mmio, VORTEX_MIXER_SR);	if (((1 << ch) & eax) == 0) {		printk(KERN_ERR "mix ALARM %x\n", eax);		return 0;	}	ebp = VORTEX_MIXER_CHNBASE + (ch << 2);	esp18 = hwread(vortex->mmio, ebp);	if (esp18 & 0x10) {		ebx = (esp18 & 0xf);		if (mix == ebx) {			ebx = VORTEX_MIXER_RTBASE + (mix << 2);			edx = hwread(vortex->mmio, ebx);			//7b60			hwwrite(vortex->mmio, ebp, edx);			hwwrite(vortex->mmio, ebx, 0);		} else {			//7ad3			edx =			    hwread(vortex->mmio,				   VORTEX_MIXER_RTBASE + (ebx << 2));			//printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);			while ((edx & 0xf) != mix) {				if ((esi) > 0xf) {					printk(KERN_ERR					       "vortex: mixdelWTD: error lifeboat overflow\n");					return 0;				}				esp14 = ebx;				ebx = edx & 0xf;				ebp = ebx << 2;				edx =				    hwread(vortex->mmio,					   VORTEX_MIXER_RTBASE + ebp);				//printk(KERN_INFO "vortex: mixdelWTD: while addr=%x, val=%x\n", ebp, edx);				esi++;			}			//7b30			ebp = ebx << 2;			if (edx & 0x10) {	/* Delete entry in between others */				ebx = VORTEX_MIXER_RTBASE + ((edx & 0xf) << 2);				edx = hwread(vortex->mmio, ebx);				//7b60				hwwrite(vortex->mmio,					VORTEX_MIXER_RTBASE + ebp, edx);				hwwrite(vortex->mmio, ebx, 0);				//printk(KERN_INFO "vortex mixdelWTD between addr= 0x%x, val= 0x%x\n", ebp, edx);			} else {	/* Delete last entry */				//7b83				if (esp14 == -1)					hwwrite(vortex->mmio,						VORTEX_MIXER_CHNBASE +						(ch << 2), esp18 & 0xef);				else {					ebx = (0xffffffe0 & edx) | (0xf & ebx);					hwwrite(vortex->mmio,						VORTEX_MIXER_RTBASE +						(esp14 << 2), ebx);					//printk(KERN_INFO "vortex mixdelWTD last addr= 0x%x, val= 0x%x\n", esp14, ebx);				}				hwwrite(vortex->mmio,					VORTEX_MIXER_RTBASE + ebp, 0);				return 1;			}		}	} else {		//printk(KERN_INFO "removed last mix\n");		//7be0		vortex_mixer_dis_sr(vortex, ch);		hwwrite(vortex->mmio, ebp, 0);	}	return 1;}static void vortex_mixer_init(vortex_t * vortex){	unsigned long addr;	int x;	// FIXME: get rid of this crap.	memset(mchannels, 0, NR_MIXOUT * sizeof(int));	memset(rampchs, 0, NR_MIXOUT * sizeof(int));	addr = VORTEX_MIX_SMP + 0x17c;	for (x = 0x5f; x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0);		addr -= 4;	}	addr = VORTEX_MIX_ENIN + 0x1fc;	for (x = 0x7f; x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0);		addr -= 4;	}	addr = VORTEX_MIX_SMP + 0x17c;	for (x = 0x5f; x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0);		addr -= 4;	}	addr = VORTEX_MIX_INVOL_A + 0x7fc;	for (x = 0x1ff; x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0x80);		addr -= 4;	}	addr = VORTEX_MIX_VOL_A + 0x3c;	for (x = 0xf; x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0x80);		addr -= 4;	}	addr = VORTEX_MIX_INVOL_B + 0x7fc;	for (x = 0x1ff; x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0x80);		addr -= 4;	}	addr = VORTEX_MIX_VOL_B + 0x3c;	for (x = 0xf; x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0x80);		addr -= 4;	}	addr = VORTEX_MIXER_RTBASE + (MIXER_RTBASE_SIZE - 1) * 4;	for (x = (MIXER_RTBASE_SIZE - 1); x >= 0; x--) {		hwwrite(vortex->mmio, addr, 0x0);		addr -= 4;	}	hwwrite(vortex->mmio, VORTEX_MIXER_SR, 0);	/* Set clipping ceiling (this may be all wrong). */	/*	for (x = 0; x > 0x80; x++) {		hwwrite(vortex->mmio, VORTEX_MIXER_CLIP + (x << 2), 0x3ffff);	}	*/	/*	   call CAsp4Mix__Initialize_CAsp4HwIO____CAsp4Mixer____	   Register ISR callback for volume smooth fade out.	   Maybe this avoids clicks when press "stop" ?	 */}/*  SRC (CAsp4Src.s and CAsp4SrcBlock) */static void vortex_src_en_sr(vortex_t * vortex, int channel){	hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR,		hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) | (0x1 << channel));}static void vortex_src_dis_sr(vortex_t * vortex, int channel){	hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR,		hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) & ~(0x1 << channel));}static void vortex_src_flushbuffers(vortex_t * vortex, unsigned char src){	int i;	for (i = 0x1f; i >= 0; i--)

⌨️ 快捷键说明

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