📄 sb_ess.c
字号:
* * These registers specifically take care of recording levels. To make the * mapping from playback devices to recording devices every recording * devices = playback device + ES_REC_MIXER_RECDIFF */#define ES_REC_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1)#define ES_REC_MIXER_RECDIFF (ES_REC_MIXER_RECBASE - SOUND_MIXER_SYNTH)#define ES_REC_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECPCM (SOUND_MIXER_PCM + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECLINE (SOUND_MIXER_LINE + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECMIC (SOUND_MIXER_MIC + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECCD (SOUND_MIXER_CD + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES_REC_MIXER_RECDIFF)#define ES_REC_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES_REC_MIXER_RECDIFF)static mixer_tab es688_mix = {MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4),MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4),MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4),MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4),MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4),MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4),MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4),MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0)};/* * The ES1688 specifics... hopefully correct... * - 6 bit master volume * I was wrong, ES1888 docs say ES1688 didn't have it. * - RECLEV control * These may apply to ES688 too. I have no idea. */static mixer_tab es1688_mix = {MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4),MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4),MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4),MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4),MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4),MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4),MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4),MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4),MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0)};static mixer_tab es1688later_mix = {MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6),MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4),MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4),MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4),MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4),MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4),MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4),MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4),MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0)};/* * This one is for all ESS chips with a record mixer. * It's not used (yet) however */static mixer_tab es_rec_mix = {MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6),MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4),MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4),MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4),MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4),MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4),MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4),MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4),MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4),MIX_ENT(ES_REC_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECSPEAKER, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4),MIX_ENT(ES_REC_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4),MIX_ENT(ES_REC_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4),MIX_ENT(ES_REC_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)};/* * This one is for ES1887. It's little different from es_rec_mix: it * has 0x7c for PCM playback level. This is because ES1887 uses * Audio 2 for playback. */static mixer_tab es1887_mix = {MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6),MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4),MIX_ENT(SOUND_MIXER_PCM, 0x7c, 7, 4, 0x7c, 3, 4),MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4),MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4),MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4),MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4),MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4),MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4),MIX_ENT(ES_REC_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECSPEAKER, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4),MIX_ENT(ES_REC_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4),MIX_ENT(ES_REC_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4),MIX_ENT(ES_REC_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0),MIX_ENT(ES_REC_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),MIX_ENT(ES_REC_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)};static int ess_has_rec_mixer (int submodel){ switch (submodel) { case SUBMDL_ES1887: return 1; default: return 0; };};#ifdef FKS_LOGGINGstatic int ess_mixer_mon_regs[] = { 0x70, 0x71, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7f , 0xa1, 0xa2, 0xa4, 0xa5, 0xa8, 0xa9 , 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb9 , 0x00};static void ess_show_mixerregs (sb_devc *devc){ int *mp = ess_mixer_mon_regs;return; while (*mp != 0) { printk (KERN_INFO "res (%x)=%x\n", *mp, (int)(ess_getmixer (devc, *mp))); mp++; }}#endifvoid ess_setmixer (sb_devc * devc, unsigned int port, unsigned int value){ unsigned long flags;#ifdef FKS_LOGGINGprintk(KERN_INFO "FKS: write mixer %x: %x\n", port, value);#endif spin_lock_irqsave(&devc->lock, flags); if (port >= 0xa0) { ess_write (devc, port, value); } else { outb(((unsigned char) (port & 0xff)), MIXER_ADDR); udelay(20); outb(((unsigned char) (value & 0xff)), MIXER_DATA); udelay(20); }; spin_unlock_irqrestore(&devc->lock, flags);}unsigned int ess_getmixer (sb_devc * devc, unsigned int port){ unsigned int val; unsigned long flags; spin_lock_irqsave(&devc->lock, flags); if (port >= 0xa0) { val = ess_read (devc, port); } else { outb(((unsigned char) (port & 0xff)), MIXER_ADDR); udelay(20); val = inb(MIXER_DATA); udelay(20); } spin_unlock_irqrestore(&devc->lock, flags); return val;}static void ess_chgmixer (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val){ int value; value = ess_getmixer (devc, reg); value = (value & ~mask) | (val & mask); ess_setmixer (devc, reg, value);}/* * ess_mixer_init must be called from sb_mixer_init */void ess_mixer_init (sb_devc * devc){ devc->mixer_caps = SOUND_CAP_EXCL_INPUT; /* * Take care of ES1887 specifics... */ switch (devc->submodel) { case SUBMDL_ES1887: devc->supported_devices = ES1887_MIXER_DEVICES; devc->supported_rec_devices = ES1887_RECORDING_DEVICES;#ifdef FKS_LOGGINGprintk (KERN_INFO "FKS: ess_mixer_init dup = %d\n", devc->duplex);#endif if (devc->duplex) { devc->iomap = &es1887_mix; } else { devc->iomap = &es_rec_mix; } break; default: if (devc->submodel < 8) { devc->supported_devices = ES688_MIXER_DEVICES; devc->supported_rec_devices = ES688_RECORDING_DEVICES; devc->iomap = &es688_mix; } else { /* * es1688 has 4 bits master vol. * later chips have 6 bits (?) */ devc->supported_devices = ES1688_MIXER_DEVICES; devc->supported_rec_devices = ES1688_RECORDING_DEVICES; if (devc->submodel < 0x10) { devc->iomap = &es1688_mix; } else { devc->iomap = &es1688later_mix; } } }}/* * Changing playback levels at an ESS chip with record mixer means having to * take care of recording levels of recorded inputs (devc->recmask) too! */int ess_mixer_set(sb_devc *devc, int dev, int left, int right){ if (ess_has_rec_mixer (devc->submodel) && (devc->recmask & (1 << dev))) { sb_common_mixer_set (devc, dev + ES_REC_MIXER_RECDIFF, left, right); } return sb_common_mixer_set (devc, dev, left, right);}/* * After a sb_dsp_reset extended register 0xb4 (RECLEV) is reset too. After * sb_dsp_reset RECLEV has to be restored. This is where ess_mixer_reload * helps. */void ess_mixer_reload (sb_devc *devc, int dev){ int left, right, value; value = devc->levels[dev]; left = value & 0x000000ff; right = (value & 0x0000ff00) >> 8; sb_common_mixer_set(devc, dev, left, right);}int es_rec_set_recmask(sb_devc * devc, int mask){ int i, i_mask, cur_mask, diff_mask; int value, left, right;#ifdef FKS_LOGGINGprintk (KERN_INFO "FKS: es_rec_set_recmask mask = %x\n", mask);#endif /* * Changing the recmask on an ESS chip with recording mixer means: * (1) Find the differences * (2) For "turned-on" inputs: make the recording level the playback level * (3) For "turned-off" inputs: make the recording level zero */ cur_mask = devc->recmask; diff_mask = (cur_mask ^ mask); for (i = 0; i < 32; i++) { i_mask = (1 << i); if (diff_mask & i_mask) { /* Difference? (1) */ if (mask & i_mask) { /* Turn it on (2) */ value = devc->levels[i]; left = value & 0x000000ff; right = (value & 0x0000ff00) >> 8; } else { /* Turn it off (3) */ left = 0; left = 0; right = 0; } sb_common_mixer_set(devc, i + ES_REC_MIXER_RECDIFF, left, right); } } return mask;}int ess_set_recmask(sb_devc * devc, int *mask){ /* This applies to ESS chips with record mixers only! */ if (ess_has_rec_mixer (devc->submodel)) { *mask = es_rec_set_recmask (devc, *mask); return 1; /* Applied */ } else { return 0; /* Not applied */ }}/* * ess_mixer_reset must be called from sb_mixer_reset */int ess_mixer_reset (sb_devc * devc){ /* * Separate actions for ESS chips with a record mixer: */ if (ess_has_rec_mixer (devc->submodel)) { switch (devc->submodel) { case SUBMDL_ES1887: /* * Separate actions for ES1887: * Change registers 7a and 1c to make the record mixer the * actual recording source. */ ess_chgmixer(devc, 0x7a, 0x18, 0x08); ess_chgmixer(devc, 0x1c, 0x07, 0x07); break; }; /* * Call set_recmask for proper initialization */ devc->recmask = devc->supported_rec_devices; es_rec_set_recmask(devc, 0); devc->recmask = 0; return 1; /* We took care of recmask. */ } else { return 0; /* We didn't take care; caller do it */ }}/**************************************************************************** * * * ESS midi * * * ****************************************************************************//* * FKS: IRQ may be shared. Hm. And if so? Then What? */int ess_midi_init(sb_devc * devc, struct address_info *hw_config){ unsigned char cfg, tmp; cfg = ess_getmixer (devc, 0x40) & 0x03; if (devc->submodel < 8) { ess_setmixer (devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ return 0; /* ES688 doesn't support MPU401 mode */ } tmp = (hw_config->io_base & 0x0f0) >> 4; if (tmp > 3) { ess_setmixer (devc, 0x40, cfg); return 0; } cfg |= tmp << 3; tmp = 1; /* MPU enabled without interrupts */ /* May be shared: if so the value is -ve */ switch (abs(hw_config->irq)) { case 9: tmp = 0x4; break; case 5: tmp = 0x5; break; case 7: tmp = 0x6; break; case 10: tmp = 0x7; break; default: return 0; } cfg |= tmp << 5; ess_setmixer (devc, 0x40, cfg | 0x03); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -