- Improve tracer, to handle more cases of input-to-output monitoring

loopback.
- Change the meaning of "mix" OSS control. Now it controls loopback level,
according to comments in soundcard.h.
- Allow AD1981HD codecs to use playback mixer. Now driver should be able to
really use it.
- Fix bug in shared muters operation.
This commit is contained in:
Alexander Motin 2010-01-22 09:31:10 +00:00
parent 5f04b82bcc
commit 028b92a574

View File

@ -86,7 +86,7 @@
#include "mixer_if.h"
#define HDA_DRV_TEST_REV "20100112_0140"
#define HDA_DRV_TEST_REV "20100122_0141"
SND_DECLARE_FILE("$FreeBSD$");
@ -3934,8 +3934,8 @@ hdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
rvol = rvol * pdevinfo->right[j] / 100;
}
}
mute = (left == 0) ? HDA_AMP_MUTE_LEFT : 0;
mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT : 0;
mute = (lvol == 0) ? HDA_AMP_MUTE_LEFT : 0;
mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT : 0;
lvol = (lvol * ctl->step + 50) / 100;
rvol = (rvol * ctl->step + 50) / 100;
hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol);
@ -4757,37 +4757,6 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
}
switch (id) {
#if 0
case HDA_CODEC_ALC883:
/*
* nid: 24/25 = External (jack) or Internal (fixed) Mic.
* Clear vref cap for jack connectivity.
*/
w = hdac_widget_get(devinfo, 24);
if (w != NULL && w->enable != 0 && w->type ==
HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
(w->wclass.pin.config &
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
w->wclass.pin.cap &= ~(
HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
w = hdac_widget_get(devinfo, 25);
if (w != NULL && w->enable != 0 && w->type ==
HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
(w->wclass.pin.config &
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
w->wclass.pin.cap &= ~(
HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
/*
* nid: 26 = Line-in, leave it alone.
*/
break;
#endif
case HDA_CODEC_AD1983:
/*
* This codec has several possible usages, but none
@ -4900,10 +4869,19 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
w = hdac_widget_get(devinfo, 31);
if (w != NULL)
w->enable = 0;
/* Disable playback mixer, use direct bypass. */
w = hdac_widget_get(devinfo, 14);
/* Disable direct playback, use mixer. */
w = hdac_widget_get(devinfo, 5);
if (w != NULL)
w->enable = 0;
w->connsenable[0] = 0;
w = hdac_widget_get(devinfo, 6);
if (w != NULL)
w->connsenable[0] = 0;
w = hdac_widget_get(devinfo, 9);
if (w != NULL)
w->connsenable[0] = 0;
w = hdac_widget_get(devinfo, 24);
if (w != NULL)
w->connsenable[0] = 0;
break;
}
}
@ -5279,6 +5257,8 @@ hdac_audio_trace_to_out(struct hdac_devinfo *devinfo, nid_t nid, int depth)
" %*snid %d found output association %d\n",
depth + 1, "", w->nid, w->bindas);
);
if (w->bindas >= 0)
w->pflags |= HDA_ADC_MONITOR;
return (1);
} else {
HDA_BOOTHVERBOSE(
@ -5321,7 +5301,7 @@ hdac_audio_trace_to_out(struct hdac_devinfo *devinfo, nid_t nid, int depth)
}
break;
}
if (res)
if (res && w->bindas == -1)
w->bindas = -2;
HDA_BOOTHVERBOSE(
@ -5368,11 +5348,39 @@ hdac_audio_trace_as_extra(struct hdac_devinfo *devinfo)
" nid %d is input monitor\n",
w->nid);
);
w->pflags |= HDA_ADC_MONITOR;
w->ossdev = SOUND_MIXER_IMIX;
}
}
/* Other inputs monitor */
/* Find input pins supplying signal for output associations.
Hope it will be input monitoring. */
HDA_BOOTVERBOSE(
device_printf(devinfo->codec->sc->dev,
"Tracing other input monitors\n");
);
for (j = devinfo->startnode; j < devinfo->endnode; j++) {
w = hdac_widget_get(devinfo, j);
if (w == NULL || w->enable == 0)
continue;
if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
continue;
if (w->bindas < 0 || as[w->bindas].dir != HDA_CTL_IN)
continue;
HDA_BOOTVERBOSE(
device_printf(devinfo->codec->sc->dev,
" Tracing nid %d to out\n",
j);
);
if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
HDA_BOOTVERBOSE(
device_printf(devinfo->codec->sc->dev,
" nid %d is input monitor\n",
w->nid);
);
}
}
/* Beeper */
HDA_BOOTVERBOSE(
device_printf(devinfo->codec->sc->dev,
@ -5748,6 +5756,7 @@ hdac_audio_disable_notselected(struct hdac_devinfo *devinfo)
static void
hdac_audio_disable_crossas(struct hdac_devinfo *devinfo)
{
struct hdac_audio_as *ases = devinfo->function.audio.as;
struct hdac_widget *w, *cw;
struct hdac_audio_ctl *ctl;
int i, j;
@ -5770,7 +5779,10 @@ hdac_audio_disable_crossas(struct hdac_devinfo *devinfo)
cw = hdac_widget_get(devinfo, w->conns[j]);
if (cw == NULL || w->enable == 0)
continue;
if (cw->bindas == -2)
if (cw->bindas == -2 ||
((w->pflags & HDA_ADC_MONITOR) &&
cw->bindas >= 0 &&
ases[cw->bindas].dir == HDA_CTL_IN))
continue;
if (w->bindas == cw->bindas &&
(w->bindseqmask & cw->bindseqmask) != 0)
@ -5789,8 +5801,12 @@ hdac_audio_disable_crossas(struct hdac_devinfo *devinfo)
while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
if (ctl->enable == 0 || ctl->childwidget == NULL)
continue;
if (ctl->widget->bindas == -2 ||
ctl->childwidget->bindas == -2)
if (ctl->widget->bindas == -2)
continue;
if (ctl->childwidget->bindas == -2 ||
((ctl->widget->pflags & HDA_ADC_MONITOR) &&
ctl->childwidget->bindas >= 0 &&
ases[ctl->childwidget->bindas].dir == HDA_CTL_IN))
continue;
if (ctl->widget->bindas != ctl->childwidget->bindas ||
(ctl->widget->bindseqmask & ctl->childwidget->bindseqmask) == 0) {
@ -5909,7 +5925,7 @@ hdac_audio_ctl_source_amp(struct hdac_devinfo *devinfo, nid_t nid, int index,
* Find controls to control amplification for destination.
*/
static void
hdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid,
hdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid, int index,
int ossdev, int depth, int need)
{
struct hdac_audio_as *as = devinfo->function.audio.as;
@ -5968,6 +5984,8 @@ hdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid,
int tneed = need;
if (w->connsenable[i] == 0)
continue;
if (index >= 0 && i != index)
continue;
ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
HDA_CTL_IN, i, 1);
if (ctl) {
@ -5977,7 +5995,7 @@ hdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid,
ctl->possmask |= (1 << ossdev);
tneed &= ~HDA_CTL_GIVE(ctl);
}
hdac_audio_ctl_dest_amp(devinfo, w->conns[i], ossdev,
hdac_audio_ctl_dest_amp(devinfo, w->conns[i], -1, ossdev,
depth + 1, tneed);
}
}
@ -6184,8 +6202,8 @@ hdac_audio_assign_mixers(struct hdac_devinfo *devinfo)
{
struct hdac_audio_as *as = devinfo->function.audio.as;
struct hdac_audio_ctl *ctl;
struct hdac_widget *w;
int i;
struct hdac_widget *w, *cw;
int i, j;
/* Assign mixers to the tree. */
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
@ -6200,24 +6218,30 @@ hdac_audio_assign_mixers(struct hdac_devinfo *devinfo)
continue;
hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
w->ossdev, 1, 0, 1);
} else if ((w->pflags & HDA_ADC_MONITOR) != 0) {
if (w->ossdev < 0)
continue;
if (hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
w->ossdev, 1, 0, 1)) {
/* If we are unable to control input monitor
as source - try to control it as destination. */
hdac_audio_ctl_dest_amp(devinfo, w->nid,
w->ossdev, 0, 1);
}
} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
hdac_audio_ctl_dest_amp(devinfo, w->nid,
hdac_audio_ctl_dest_amp(devinfo, w->nid, -1,
SOUND_MIXER_RECLEV, 0, 1);
} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
as[w->bindas].dir == HDA_CTL_OUT) {
hdac_audio_ctl_dest_amp(devinfo, w->nid,
hdac_audio_ctl_dest_amp(devinfo, w->nid, -1,
SOUND_MIXER_VOLUME, 0, 1);
}
if (w->pflags & HDA_ADC_MONITOR) {
for (j = 0; j < w->nconns; j++) {
if (!w->connsenable[j])
continue;
cw = hdac_widget_get(devinfo, w->conns[j]);
if (cw == NULL || cw->enable == 0)
continue;
if (cw->bindas == -1)
continue;
if (cw->bindas >= 0 &&
as[cw->bindas].dir != HDA_CTL_IN)
continue;
hdac_audio_ctl_dest_amp(devinfo,
w->nid, j, SOUND_MIXER_IMIX, 0, 1);
}
}
}
/* Treat unrequired as possible. */
i = 0;
@ -7160,7 +7184,7 @@ hdac_dump_mix(struct hdac_pcm_devinfo *pdevinfo)
w = hdac_widget_get(devinfo, i);
if (w == NULL || w->enable == 0)
continue;
if ((w->pflags & HDA_ADC_MONITOR) == 0)
if (w->ossdev != SOUND_MIXER_IMIX)
continue;
if (printed == 0) {
printed = 1;
@ -8126,7 +8150,7 @@ hdac_pcm_attach(device_t dev)
hdac_dump_ctls(pdevinfo, "Line-in Volume", SOUND_MASK_LINE);
hdac_dump_ctls(pdevinfo, "Speaker/Beep Volume", SOUND_MASK_SPEAKER);
hdac_dump_ctls(pdevinfo, "Recording Level", SOUND_MASK_RECLEV);
hdac_dump_ctls(pdevinfo, "Input Mix Level", SOUND_MASK_IMIX);
hdac_dump_ctls(pdevinfo, "Input Monitoring Level", SOUND_MASK_IMIX);
hdac_dump_ctls(pdevinfo, NULL, 0);
device_printf(dev, "\n");
);