Complete rewrite of the snd_hda(4) volume control.

Previous code was relatively dumb. During CODEC probe it was tracing signals
and statically binding amplifier controls to the OSS mixer controls. To set
volume it just set all bound amplifier controls proportionally to mixer
level, not looking on their hierarchy and amplification levels/offsets.

New code is much smarter. It also traces signals during probe, but mostly
to find out possible amplification control rages in dB for each specific
signal. To set volume it retraces each affected signal again and sets
amplifiers controls recursively to reach desired amplification level in dB.
It would be nice to export values in dB to user, but unluckily our OSS mixer
API is too simple for that.

As result of this change:
 - cascaded amplifiers will work together to reach maximal precision.
If some input has 0/+40dB preamplifier with 10dB step and -10/+10dB mixer
with 1dB step after it, new code will use both to provide 0/+40dB control
with 1dB step! We could even get -10/+50dB range there, but that is
intentionally blocked for now.
 - different channels of multichannel associations on non-uniform CODECs
such as VIA VT1708S will have the same volume, not looking that control
ranges are different. It was not good when fronts were 12dB louder.
 - for multiplexed recording, when we can record from only one source at
a time, we can now use recording amplifier controls to set different
volume levels for different inputs if they have no own controls of they
are less precise. If recording source change, amplifiers will be
reconfigured.

To improve out-of-the-box behavior, ignore default volume levels set by
sound(4) and use own, more reasonable: +20dB for mics, -10dB for analog
output volume and 0dB for the rest of controls. sound(4) defaults of 75%
mean absolutely random things for different controls of different CODECs
because of very different control ranges.
Together with further planned automatic recording source selection this
should allow users to get fine playback and recording without touching
mixer first.
Note that existing users should delete /var/db/mixer*-state and reboot
or trigger CODEC reconfiguration to get new default values.

MFC after:	2 months
Sponsored by:	iXsystems, Inc.
This commit is contained in:
Alexander Motin 2012-01-22 10:24:12 +00:00
parent 28083eaa4d
commit 3d741b14a7
2 changed files with 580 additions and 184 deletions

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,10 @@
#define HDAA_AMP_LEFT_MUTED(v) ((v) & (HDAA_AMP_MUTE_LEFT))
#define HDAA_AMP_RIGHT_MUTED(v) (((v) & HDAA_AMP_MUTE_RIGHT) >> 1)
/* Widget in playback receiving signal from recording. */
#define HDAA_ADC_MONITOR (1 << 0)
/* Input mixer widget needs volume control as destination. */
#define HDAA_IMIX_AS_DST (2 << 0)
#define HDAA_CTL_OUT 1
#define HDAA_CTL_IN 2
@ -82,6 +85,13 @@
#define HDA_MAX_CONNS 32
#define HDA_MAX_NAMELEN 32
struct hdaa_audio_as;
struct hdaa_audio_ctl;
struct hdaa_chan;
struct hdaa_devinfo;
struct hdaa_pcm_devinfo;
struct hdaa_widget;
struct hdaa_widget {
nid_t nid;
int type;
@ -129,7 +139,10 @@ struct hdaa_audio_ctl {
int mute, step, size, offset;
int left, right, forcemute;
uint32_t muted;
uint32_t ossmask, possmask;
uint32_t ossmask; /* OSS devices that may affect control. */
int devleft[SOUND_MIXER_NRDEVICES]; /* Left ampl in 1/4dB. */
int devright[SOUND_MIXER_NRDEVICES]; /* Right ampl in 1/4dB. */
int devmute[SOUND_MIXER_NRDEVICES]; /* Mutes per OSS device. */
};
/* Association is a group of pins bound for some special function. */
@ -148,19 +161,25 @@ struct hdaa_audio_as {
int chans[2];
int location; /* Pins location, if all have the same */
int mixed; /* Mixed/multiplexed recording, not multichannel. */
struct hdaa_pcm_devinfo *pdevinfo;
};
struct hdaa_pcm_devinfo {
device_t dev;
struct hdaa_devinfo *devinfo;
struct snd_mixer *mixer;
int index;
int registered;
int playas, recas;
u_char left[SOUND_MIXER_NRDEVICES];
u_char right[SOUND_MIXER_NRDEVICES];
int minamp[SOUND_MIXER_NRDEVICES]; /* Minimal amps in 1/4dB. */
int maxamp[SOUND_MIXER_NRDEVICES]; /* Maximal amps in 1/4dB. */
int chan_size;
int chan_blkcnt;
u_char digital;
uint32_t ossmask; /* Mask of supported OSS devices. */
uint32_t recsrc; /* Mask of supported OSS sources. */
};
struct hdaa_devinfo {
@ -219,6 +238,22 @@ struct hdaa_chan {
uint8_t stripectl; /* stripe to use to all ios. */
};
#define MINQDB(ctl) \
((0 - (ctl)->offset) * ((ctl)->size + 1))
#define MAXQDB(ctl) \
(((ctl)->step - (ctl)->offset) * ((ctl)->size + 1))
#define RANGEQDB(ctl) \
((ctl)->step * ((ctl)->size + 1))
#define VAL2QDB(ctl, val) \
(((ctl)->size + 1) * ((int)(val) - (ctl)->offset))
#define QDB2VAL(ctl, qdb) \
imax(imin((((qdb) + (ctl)->size / 2 * ((qdb) > 0 ? 1 : -1)) / \
((ctl)->size + 1) + (ctl)->offset), (ctl)->step), 0)
#define hdaa_codec_id(devinfo) \
(((uint32_t)hda_get_vendor_id(devinfo->dev) << 16) + \
hda_get_device_id(devinfo->dev))