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

📄 sb_ess.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
#undef FKS_LOGGING#undef FKS_TEST/* * tabs should be 4 spaces, in vi(m): set tabstop=4 * * TODO: 	consistency speed calculations!! *			cleanup! * ????:	Did I break MIDI support? * * History: * * Rolf Fokkens	 (Dec 20 1998):	ES188x recording level support on a per * fokkensr@vertis.nl			input basis. *				 (Dec 24 1998):	Recognition of ES1788, ES1887, ES1888, *								ES1868, ES1869 and ES1878. Could be used for *								specific handling in the future. All except *								ES1887 and ES1888 and ES688 are handled like *								ES1688. *				 (Dec 27 1998):	RECLEV for all (?) ES1688+ chips. ES188x now *								have the "Dec 20" support + RECLEV *				 (Jan  2 1999):	Preparation for Full Duplex. This means *								Audio 2 is now used for playback when dma16 *								is specified. The next step would be to use *								Audio 1 and Audio 2 at the same time. *				 (Jan  9 1999):	Put all ESS stuff into sb_ess.[ch], this *								includes both the ESS stuff that has been in *								sb_*[ch] before I touched it and the ESS support *								I added later *				 (Jan 23 1999):	Full Duplex seems to work. I wrote a small *								test proggy which works OK. Haven't found *								any applications to test it though. So why did *								I bother to create it anyway?? :) Just for *								fun. *				 (May  2 1999):	I tried to be too smart by "introducing" *								ess_calc_best_speed (). The idea was that two *								dividers could be used to setup a samplerate, *								ess_calc_best_speed () would choose the best. *								This works for playback, but results in *								recording problems for high samplerates. I *								fixed this by removing ess_calc_best_speed () *								and just doing what the documentation says.  * Andy Sloane   (Jun  4 1999): Stole some code from ALSA to fix the playback * andy@guildsoftware.com		speed on ES1869, ES1879, ES1887, and ES1888. * 								1879's were previously ignored by this driver; * 								added (untested) support for those. * Cvetan Ivanov (Oct 27 1999): Fixed ess_dsp_init to call ess_set_dma_hw for * zezo@inet.bg					_ALL_ ESS models, not only ES1887 * * This files contains ESS chip specifics. It's based on the existing ESS * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This * file adds features like: * - Chip Identification (as shown in /proc/sound) * - RECLEV support for ES1688 and later * - 6 bits playback level support chips later than ES1688 * - Recording level support on a per-device basis for ES1887 * - Full-Duplex for ES1887 * * Full duplex is enabled by specifying dma16. While the normal dma must * be one of 0, 1 or 3, dma16 can be one of 0, 1, 3 or 5. DMA 5 is a 16 bit * DMA channel, while the others are 8 bit.. * * ESS detection isn't full proof (yet). If it fails an additional module * parameter esstype can be specified to be one of the following: * -1, 0, 688, 1688, 1868, 1869, 1788, 1887, 1888 * -1 means: mimic 2.0 behaviour,  *  0 means: auto detect. *   others: explicitly specify chip * -1 is default, cause auto detect still doesn't work. *//* * About the documentation * * I don't know if the chips all are OK, but the documentation is buggy. 'cause * I don't have all the cips myself, there's a lot I cannot verify. I'll try to * keep track of my latest insights about his here. If you have additional info, * please enlighten me (fokkensr@vertis.nl)! * * I had the impression that ES1688 also has 6 bit master volume control. The * documentation about ES1888 (rev C, october '95) claims that ES1888 has * the following features ES1688 doesn't have: * - 6 bit master volume * - Full Duplex * So ES1688 apparently doesn't have 6 bit master volume control, but the * ES1688 does have RECLEV control. Makes me wonder: does ES688 have it too? * Without RECLEV ES688 won't be much fun I guess. * * From the ES1888 (rev C, october '95) documentation I got the impression * that registers 0x68 to 0x6e don't exist which means: no recording volume * controls. To my surprise the ES888 documentation (1/14/96) claims that * ES888 does have these record mixer registers, but that ES1888 doesn't have * 0x69 and 0x6b. So the rest should be there. * * I'm trying to get ES1887 Full Duplex. Audio 2 is playback only, while Audio 2 * is both record and playback. I think I should use Audio 2 for all playback. * * The documentation is an adventure: it's close but not fully accurate. I * found out that after a reset some registers are *NOT* reset, though the * docs say the would be. Interresting ones are 0x7f, 0x7d and 0x7a. They are * related to the Audio 2 channel. I also was suprised about the consequenses * of writing 0x00 to 0x7f (which should be done by reset): The ES1887 moves * into ES1888 mode. This means that it claims IRQ 11, which happens to be my * ISDN adapter. Needless to say it no longer worked. I now understand why * after rebooting 0x7f already was 0x05, the value of my choice: the BIOS * did it. * * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is decribed * as if it's exactly the same as register 0xa1. This is *NOT* true. The * description of 0x70 in ES1869 docs is accurate however. * Well, the assumption about ES1869 was wrong: register 0x70 is very much * like register 0xa1, except that bit 7 is allways 1, whatever you want * it to be. * * When using audio 2 mixer register 0x72 seems te be meaningless. Only 0xa2 * has effect. * * Software reset not being able to reset all registers is great! Especially * the fact that register 0x78 isn't reset is great when you wanna change back * to single dma operation (simplex): audio 2 is still operation, and uses the * same dma as audio 1: your ess changes into a funny echo machine. * * Received the new that ES1688 is detected as a ES1788. Did some thinking: * the ES1887 detection scheme suggests in step 2 to try if bit 3 of register * 0x64 can be changed. This is inaccurate, first I inverted the * check: "If * can be modified, it's a 1688", which lead to a correct detection * of my ES1887. It resulted however in bad detection of 1688 (reported by mail) * and 1868 (if no PnP detection first): they result in a 1788 being detected. * I don't have docs on 1688, but I do have docs on 1868: The documentation is * probably inaccurate in the fact that I should check bit 2, not bit 3. This * is what I do now. *//* * About recognition of ESS chips * * The distinction of ES688, ES1688, ES1788, ES1887 and ES1888 is described in * a (preliminary ??) datasheet on ES1887. It's aim is to identify ES1887, but * during detection the text claims that "this chip may be ..." when a step * fails. This scheme is used to distinct between the above chips. * It appears however that some PnP chips like ES1868 are recognized as ES1788 * by the ES1887 detection scheme. These PnP chips can be detected in another * way however: ES1868, ES1869 and ES1878 can be recognized (full proof I think) * by repeatedly reading mixer register 0x40. This is done by ess_identify in * sb_common.c. * This results in the following detection steps: * - distinct between ES688 and ES1688+ (as always done in this driver) *   if ES688 we're ready * - try to detect ES1868, ES1869 or ES1878 *   if successful we're ready * - try to detect ES1888, ES1887 or ES1788 *   if successful we're ready * - Dunno. Must be 1688. Will do in general * * About RECLEV support: * * The existing ES1688 support didn't take care of the ES1688+ recording * levels very well. Whenever a device was selected (recmask) for recording * it's recording level was loud, and it couldn't be changed. The fact that * internal register 0xb4 could take care of RECLEV, didn't work meaning until * it's value was restored every time the chip was reset; this reset the * value of 0xb4 too. I guess that's what 4front also had (have?) trouble with. * * About ES1887 support: * * The ES1887 has separate registers to control the recording levels, for all * inputs. The ES1887 specific software makes these levels the same as their * corresponding playback levels, unless recmask says they aren't recorded. In * the latter case the recording volumes are 0. * Now recording levels of inputs can be controlled, by changing the playback * levels. Futhermore several devices can be recorded together (which is not * possible with the ES1688. * Besides the separate recording level control for each input, the common * recordig level can also be controlled by RECLEV as described above. * * Not only ES1887 have this recording mixer. I know the following from the * documentation: * ES688	no * ES1688	no * ES1868	no * ES1869	yes * ES1878	no * ES1879	yes * ES1888	no/yes	Contradicting documentation; most recent: yes * ES1946	yes		This is a PCI chip; not handled by this driver */#include <linux/delay.h>#include "sound_config.h"#include "sb_mixer.h"#include "sb.h"#include "sb_ess.h"#define ESSTYPE_LIKE20	-1		/* Mimic 2.0 behaviour					*/#define ESSTYPE_DETECT	0		/* Mimic 2.0 behaviour					*/#define SUBMDL_ES1788	0x10	/* Subtype ES1788 for specific handling */#define SUBMDL_ES1868	0x11	/* Subtype ES1868 for specific handling */#define SUBMDL_ES1869	0x12	/* Subtype ES1869 for specific handling */#define SUBMDL_ES1878	0x13	/* Subtype ES1878 for specific handling */#define SUBMDL_ES1879	0x16    /* ES1879 was initially forgotten */#define SUBMDL_ES1887	0x14	/* Subtype ES1887 for specific handling */#define SUBMDL_ES1888	0x15	/* Subtype ES1888 for specific handling */#define SB_CAP_ES18XX_RATE 0x100#define ES1688_CLOCK1 795444 /* 128 - div */#define ES1688_CLOCK2 397722 /* 256 - div */#define ES18XX_CLOCK1 793800 /* 128 - div */#define ES18XX_CLOCK2 768000 /* 256 - div */#ifdef FKS_LOGGINGstatic void ess_show_mixerregs (sb_devc *devc);#endifstatic int ess_read (sb_devc * devc, unsigned char reg);static int ess_write (sb_devc * devc, unsigned char reg, unsigned char data);static void ess_chgmixer	(sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val);/**************************************************************************** *																			* *									ESS audio								* *																			* ****************************************************************************/struct ess_command {short cmd; short data;};/* * Commands for initializing Audio 1 for input (record) */static struct ess_command ess_i08m[] =		/* input 8 bit mono */	{ {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };static struct ess_command ess_i16m[] =		/* input 16 bit mono */	{ {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };static struct ess_command ess_i08s[] =		/* input 8 bit stereo */	{ {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };static struct ess_command ess_i16s[] =		/* input 16 bit stereo */	{ {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };static struct ess_command *ess_inp_cmds[] =	{ ess_i08m, ess_i16m, ess_i08s, ess_i16s };/* * Commands for initializing Audio 1 for output (playback) */static struct ess_command ess_o08m[] =		/* output 8 bit mono */	{ {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} };static struct ess_command ess_o16m[] =		/* output 16 bit mono */	{ {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} };static struct ess_command ess_o08s[] =		/* output 8 bit stereo */	{ {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} };static struct ess_command ess_o16s[] =		/* output 16 bit stereo */	{ {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} };static struct ess_command *ess_out_cmds[] =	{ ess_o08m, ess_o16m, ess_o08s, ess_o16s };static void ess_exec_commands	(sb_devc *devc, struct ess_command *cmdtab[]){	struct ess_command *cmd;	cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ];	while (cmd->cmd != -1) {		ess_write (devc, cmd->cmd, cmd->data);		cmd++;	}}static void ess_change	(sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val){	int value;	value = ess_read (devc, reg);	value = (value & ~mask) | (val & mask);	ess_write (devc, reg, value);}static void ess_set_output_parms	(int dev, unsigned long buf, int nr_bytes, int intrflag){	sb_devc *devc = audio_devs[dev]->devc;	if (devc->duplex) {		devc->trg_buf_16 = buf;		devc->trg_bytes_16 = nr_bytes;		devc->trg_intrflag_16 = intrflag;		devc->irq_mode_16 = IMODE_OUTPUT;	} else {		devc->trg_buf = buf;		devc->trg_bytes = nr_bytes;		devc->trg_intrflag = intrflag;		devc->irq_mode = IMODE_OUTPUT;	}}static void ess_set_input_parms	(int dev, unsigned long buf, int count, int intrflag){	sb_devc *devc = audio_devs[dev]->devc;	devc->trg_buf = buf;	devc->trg_bytes = count;	devc->trg_intrflag = intrflag;	devc->irq_mode = IMODE_INPUT;}static int ess_calc_div (int clock, int revert, int *speedp, int *diffp){	int divider;	int speed, diff;	int retval;	speed   = *speedp;	divider = (clock + speed / 2) / speed;	retval  = revert - divider;	if (retval > revert - 1) {		retval  = revert - 1;		divider = revert - retval;	}	/* This line is suggested. Must be wrong I think	*speedp = (clock + divider / 2) / divider;	So I chose the next one */	*speedp	= clock / divider;	diff	= speed - *speedp;	if (diff < 0) diff =-diff;	*diffp  = diff;	return retval;}static int ess_calc_best_speed	(int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp){	int speed1 = *speedp, speed2 = *speedp;	int div1, div2;	int diff1, diff2;	int retval;	div1 = ess_calc_div (clock1, rev1, &speed1, &diff1);	div2 = ess_calc_div (clock2, rev2, &speed2, &diff2);	if (diff1 < diff2) {		*divp   = div1;		*speedp = speed1;		retval  = 1;	} else {		*divp   = div2;		*speedp = speed2;		retval  = 2;	}	return retval;}/* * Depending on the audiochannel ESS devices can * have different clock settings. These are made consistent for duplex * however. * callers of ess_speed only do an audionum suggestion, which means * input suggests 1, output suggests 2. This suggestion is only true * however when doing duplex. */static void ess_common_speed (sb_devc *devc, int *speedp, int *divp){	int diff = 0, div;	if (devc->duplex) {		/*		 * The 0x80 is important for the first audio channel		 */		div = 0x80 | ess_calc_div (795500, 128, speedp, &diff);	} else if(devc->caps & SB_CAP_ES18XX_RATE) {		ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, 						&div, speedp);	} else {		if (*speedp > 22000) {			div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff);		} else {			div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff);		}	}	*divp = div;}static void ess_speed (sb_devc *devc, int audionum){	int speed;	int div, div2;	ess_common_speed (devc, &(devc->speed), &div);#ifdef FKS_REG_LOGGINGprintk (KERN_INFO "FKS: ess_speed (%d) b speed = %d, div=%x\n", audionum, devc->speed, div);#endif	/* Set filter roll-off to 90% of speed/2 */	speed = (devc->speed * 9) / 20;	div2 = 256 - 7160000 / (speed * 82);	if (!devc->duplex) audionum = 1;	if (audionum == 1) {		/* Change behaviour of register A1 *		sb_chg_mixer(devc, 0x71, 0x20, 0x20)		* For ES1869 only??? */		ess_write (devc, 0xa1, div);		ess_write (devc, 0xa2, div2);	} else {		ess_setmixer (devc, 0x70, div);		/*		 * FKS: fascinating: 0x72 doesn't seem to work.		 */		ess_write (devc, 0xa2, div2);		ess_setmixer (devc, 0x72, div2);	}}static int ess_audio_prepare_for_input(int dev, int bsize, int bcount){	sb_devc *devc = audio_devs[dev]->devc;	ess_speed(devc, 1);	sb_dsp_command(devc, DSP_CMD_SPKOFF);	ess_write (devc, 0xb8, 0x0e);	/* Auto init DMA mode */	ess_change (devc, 0xa8, 0x03, 3 - devc->channels);	/* Mono/stereo */	ess_write (devc, 0xb9, 2);	/* Demand mode (4 bytes/DMA request) */	ess_exec_commands (devc, ess_inp_cmds);	ess_change (devc, 0xb1, 0xf0, 0x50);	ess_change (devc, 0xb2, 0xf0, 0x50);	devc->trigger_bits = 0;	return 0;}static int ess_audio_prepare_for_output_audio1 (int dev, int bsize, int bcount){	sb_devc *devc = audio_devs[dev]->devc;	sb_dsp_reset(devc);	ess_speed(devc, 1);	ess_write (devc, 0xb8, 4);	/* Auto init DMA mode */	ess_change (devc, 0xa8, 0x03, 3 - devc->channels);	/* Mono/stereo */	ess_write (devc, 0xb9, 2);	/* Demand mode (4 bytes/request) */

⌨️ 快捷键说明

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