📄 sb_ess.c
字号:
#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 (June 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. * * 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 (under development) * * 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 */int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */#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 + -