--- ac97_codec.c Thu Dec 04 15:53:12 2003 +++ linux-2.4.23/drivers/sound/ac97_codec.c Thu Dec 04 16:30:08 2003 @@ -30,6 +30,9 @@ ************************************************************************** * * History + * Dec 04, 2003 Dennis Newbold + * Added logic to use the MICBOOST bit when writing or reading the + * SOUND_MIXER_MIC channel. * May 02, 2003 Liam Girdwood * Removed non existant WM9700 * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 @@ -240,6 +243,26 @@ {-1,0} }; +/* Note that scale for SOUND_MIXER_MIC is set to 46 rather than 32. This is + * to include the lower volume DB values that do not use the AC97_MICBOOST + * bit. There is a small glitch in the scaling in that the last value to use + * the boost bit is 31, which translates to -14.5 dB, and the next lower value, + * which does not use the boost bit is 32, which is converted to 18, which + * translates to -15 dB, a difference of only 0.5 dB. All other gain values + * differ by 1.5 dB. This is considered acceptable because it happens only + * at an extremely low volume, which most users will not be interested in. + * -dln- */ + +/* MIC_NATURAL_SCALE is the no. of different gain settings that will fit in + * the MIC Volume Gain Register. Computed gain values which fall within this + * range operate with the AC97_MICBOOST bit enabled. Computed values outside + * of this range are forced back into this range, but with the AC97_MICBOOST + * bit turned off. This allows access to the very low dB range scale of the + * AC97 codec, which cannot be accessed with the MICBOOST bit enabled. -dln- + */ + +#define MIC_NATURAL_SCALE (32) + /* table to scale scale from OSS mixer value to AC97 mixer register value */ static struct ac97_mixer_hw { unsigned char offset; @@ -251,7 +274,7 @@ [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 32}, [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 16}, [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 32}, - [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 32}, + [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 46}, [SOUND_MIXER_CD] = {AC97_CD_VOL, 32}, [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 64}, [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 16}, @@ -302,7 +325,7 @@ about that given mixer, and should be holding a spinlock for the card */ static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) { - u16 val; + u16 val, t; int ret = 0; int scale; struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; @@ -340,7 +363,10 @@ scale = (1 << codec->bit_resolution); ret = 100 - (((val & 0x1f) * 100) / scale); } else if (oss_channel == SOUND_MIXER_MIC) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); + t = val & (MIC_NATURAL_SCALE - 1); + if (!(val & AC97_MICBOOST)) + t += (mh->scale - MIC_NATURAL_SCALE); + ret = 100 - ((t * 100) / mh->scale-1); /* the low bit is optional in the tone sliders and masking it lets us avoid the 0xf 'bypass'.. */ } else if (oss_channel == SOUND_MIXER_BASS) { @@ -427,7 +453,7 @@ left = ((100 - left) * mh->scale) / 100; if (left >= mh->scale) left = mh->scale-1; - val = left; + val = left; } else if (oss_channel == SOUND_MIXER_PHONEOUT) { scale = (1 << codec->bit_resolution); left = ((100 - left) * scale) / 100; @@ -436,13 +462,17 @@ val = left; } else if (oss_channel == SOUND_MIXER_MIC) { val = codec->codec_read(codec , mh->offset) & ~0x801f; - left = ((100 - left) * mh->scale) / 100; + left = ((100 - left) * mh->scale-1) / 100; if (left >= mh->scale) - left = mh->scale-1; + left = mh->scale-1 + if (left < MIC_NATURAL_SCALE) + left |= AC97_MICBOOST; + else + left -= (mh->scale - MIC_NATURAL_SCALE); val |= left; /* the low bit is optional in the tone sliders and masking it lets us avoid the 0xf 'bypass'.. */ - } + #ifdef DEBUG printk(" 0x%04x", val); #endif