summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2012-01-25 20:46:10 +0000
committermav <mav@FreeBSD.org>2012-01-25 20:46:10 +0000
commit30761935c6caad4e8f25453ffd5804be83563d02 (patch)
tree50223e7ec4f1c609359930286e8c90f08229c358
parente59865bdd01bbff3136a728d65b9ac431721698f (diff)
downloadFreeBSD-src-30761935c6caad4e8f25453ffd5804be83563d02.zip
FreeBSD-src-30761935c6caad4e8f25453ffd5804be83563d02.tar.gz
Rewrite jack presence detection and implement automatic recording source
selection in snd_hda(4) driver. Now driver tracks jack presence detection status for every CODEC pin. For playback associations, when configured, that information, same as before, can be used to automatically redirect audio to headphones. Also same as before, these events are used to track digital display connection status and fetch ELD. Now in addition to that driver uses that information to automatically switch recording source of the mixer to the connected input. When there are devices with no jack detection and with one both connected, last ones will have the precedence. As result, on most laptops after boot internal microphone should be automatically selected. But if external one (for example, headset) connected, it will be selected automatically. When external mic disconnected, internal one will be selected again. Automatic recording source selection is enabled by default now to make recording work out of the box without touching mixer. But it can be disabled or limited only to attach time using hint.pcm.X.rec.autosrc loader tunables or dev.pcm.X.rec.autosrc sysctls. MFC after: 2 months Sponsored by: iXsystems, Inc.
-rw-r--r--share/man/man4/snd_hda.424
-rw-r--r--sys/dev/sound/pci/hda/hdaa.c346
-rw-r--r--sys/dev/sound/pci/hda/hdaa.h2
3 files changed, 225 insertions, 147 deletions
diff --git a/share/man/man4/snd_hda.4 b/share/man/man4/snd_hda.4
index 270a9f5..bcdd95a 100644
--- a/share/man/man4/snd_hda.4
+++ b/share/man/man4/snd_hda.4
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 11, 2012
+.Dd January 25, 2012
.Dt SND_HDA 4
.Os
.Sh NAME
@@ -182,6 +182,18 @@ May be specified as a 32-bit hexadecimal value with a leading
or as a set of space-separated
.Dq Ar option Ns = Ns Ar value
pairs.
+.It Va hint.pcm.%d.rec.autosrc
+Controls automatic recording source feature:
+.Bl -tag -compact
+.It 0
+disabled,
+.It 1
+once on attach,
+.It 2
+enabled.
+.El
+When enabled, driver will automatically set recording source of the mixer to
+connected input using jack presence detection statuses.
.El
.Pp
Pin configuration is the UAA driver's main source of information about codec
@@ -357,6 +369,16 @@ Original pin configuration written by BIOS.
Setting this to a non-zero value makes driver to destroy existing pcm devices
and process new pins configuration set via
.Va dev.hdaa.%d.nid%d_config.
+.It Va dev.pcm.%d.play.32bit , dev.pcm.%d.rec.32bit
+HDA controller uses 32bit representation for all samples of more then 16 bits.
+These variables allow to specify how many bits of these 32 should be
+used by CODEC.
+Depending on codec capabilities, possible values are 20, 24 and 32 bit.
+The default value is 24.
+.It Va dev.pcm.%d.rec.autosrc
+Run-time equivalent of the
+.Va hint.pcm.%d.rec.autosrc
+tunable.
.El
.Sh EXAMPLES
Taking HP Compaq DX2300 with Realtek ALC888 HDA codec for example.
diff --git a/sys/dev/sound/pci/hda/hdaa.c b/sys/dev/sound/pci/hda/hdaa.c
index aee0740..7777629 100644
--- a/sys/dev/sound/pci/hda/hdaa.c
+++ b/sys/dev/sound/pci/hda/hdaa.c
@@ -239,44 +239,30 @@ hdaa_audio_ctl_amp_get(struct hdaa_devinfo *devinfo, nid_t nid, int dir,
}
/*
- * Jack detection (Speaker/HP redirection) event handler.
+ * Headphones redirection change handler.
*/
static void
-hdaa_hp_switch_handler(struct hdaa_widget *w)
+hdaa_hpredir_handler(struct hdaa_widget *w)
{
struct hdaa_devinfo *devinfo = w->devinfo;
- struct hdaa_audio_as *as;
+ struct hdaa_audio_as *as = &devinfo->as[w->bindas];
struct hdaa_widget *w1;
struct hdaa_audio_ctl *ctl;
- uint32_t val, res;
- int j;
-
- if (w->enable == 0 || w->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
- return;
+ uint32_t val;
+ int j, connected = w->wclass.pin.connected;
- res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
- HDA_BOOTVERBOSE(
- device_printf(devinfo->dev,
- "Pin sense: nid=%d sence=0x%08x", w->nid, res);
- );
- res = (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) != 0;
- if (devinfo->quirks & HDAA_QUIRK_SENSEINV)
- res ^= 1;
HDA_BOOTVERBOSE(
- printf(" (%sconnected)\n", res == 0 ? "dis" : "");
+ device_printf((as->pdevinfo && as->pdevinfo->dev) ?
+ as->pdevinfo->dev : devinfo->dev,
+ "Redirect output to: %s\n",
+ connected ? "headphones": "main");
);
-
- as = &devinfo->as[w->bindas];
- if (as->hpredir < 0 || as->pins[15] != w->nid)
- return;
-
/* (Un)Mute headphone pin. */
ctl = hdaa_audio_ctl_amp_get(devinfo,
w->nid, HDAA_CTL_IN, -1, 1);
if (ctl != NULL && ctl->mute) {
/* If pin has muter - use it. */
- val = (res != 0) ? 0 : 1;
+ val = connected ? 0 : 1;
if (val != ctl->forcemute) {
ctl->forcemute = val;
hdaa_audio_ctl_amp_set(ctl,
@@ -285,7 +271,7 @@ hdaa_hp_switch_handler(struct hdaa_widget *w)
}
} else {
/* If there is no muter - disable pin output. */
- if (res != 0)
+ if (connected)
val = w->wclass.pin.ctrl |
HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
else
@@ -306,7 +292,7 @@ hdaa_hp_switch_handler(struct hdaa_widget *w)
as->pins[j], HDAA_CTL_IN, -1, 1);
if (ctl != NULL && ctl->mute) {
/* If pin has muter - use it. */
- val = (res != 0) ? 1 : 0;
+ val = connected ? 1 : 0;
if (val == ctl->forcemute)
continue;
ctl->forcemute = val;
@@ -317,9 +303,8 @@ hdaa_hp_switch_handler(struct hdaa_widget *w)
}
/* If there is no muter - disable pin output. */
w1 = hdaa_widget_get(devinfo, as->pins[j]);
- if (w1 != NULL && w1->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
- if (res != 0)
+ if (w1 != NULL) {
+ if (connected)
val = w1->wclass.pin.ctrl &
~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
else
@@ -336,110 +321,142 @@ hdaa_hp_switch_handler(struct hdaa_widget *w)
}
/*
- * Callback for poll based jack detection.
+ * Recording source change handler.
*/
static void
-hdaa_jack_poll_callback(void *arg)
+hdaa_autorecsrc_handler(struct hdaa_audio_as *as, struct hdaa_widget *w)
{
- struct hdaa_devinfo *devinfo = arg;
- struct hdaa_widget *w;
- int i;
+ struct hdaa_pcm_devinfo *pdevinfo = as->pdevinfo;
+ struct hdaa_devinfo *devinfo;
+ struct hdaa_widget *w1;
+ int i, mask, fullmask, prio, bestprio;
+ char buf[128];
- hdaa_lock(devinfo);
- if (devinfo->poll_ival == 0) {
- hdaa_unlock(devinfo);
+ if (!as->mixed || pdevinfo == NULL || pdevinfo->mixer == NULL)
return;
- }
- for (i = 0; i < devinfo->ascnt; i++) {
- if (devinfo->as[i].hpredir < 0)
+ /* Don't touch anything if we asked not to. */
+ if (pdevinfo->autorecsrc == 0 ||
+ (pdevinfo->autorecsrc == 1 && w != NULL))
+ return;
+ /* Don't touch anything if "mix" or "speaker" selected. */
+ if (pdevinfo->recsrc & (SOUND_MASK_IMIX | SOUND_MASK_SPEAKER))
+ return;
+ /* Don't touch anything if several selected. */
+ if (ffs(pdevinfo->recsrc) != fls(pdevinfo->recsrc))
+ return;
+ devinfo = pdevinfo->devinfo;
+ mask = fullmask = 0;
+ bestprio = 0;
+ for (i = 0; i < 16; i++) {
+ if (as->pins[i] <= 0)
continue;
- w = hdaa_widget_get(devinfo, devinfo->as[i].pins[15]);
- if (w == NULL || w->enable == 0 || w->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ w1 = hdaa_widget_get(devinfo, as->pins[i]);
+ if (w1 == NULL || w1->enable == 0)
+ continue;
+ if (w1->wclass.pin.connected == 0)
continue;
- hdaa_hp_switch_handler(w);
+ prio = (w1->wclass.pin.connected == 1) ? 2 : 1;
+ if (prio < bestprio)
+ continue;
+ if (prio > bestprio) {
+ mask = 0;
+ bestprio = prio;
+ }
+ mask |= (1 << w1->ossdev);
+ fullmask |= (1 << w1->ossdev);
}
- callout_reset(&devinfo->poll_jack, devinfo->poll_ival,
- hdaa_jack_poll_callback, devinfo);
+ if (mask == 0)
+ return;
+ /* Prefer newly connected input. */
+ if (w != NULL && (mask & (1 << w->ossdev)))
+ mask = (1 << w->ossdev);
+ /* Prefer previously selected input */
+ if (mask & pdevinfo->recsrc)
+ mask &= pdevinfo->recsrc;
+ /* Prefer mic. */
+ if (mask & SOUND_MASK_MIC)
+ mask = SOUND_MASK_MIC;
+ /* Prefer monitor (2nd mic). */
+ if (mask & SOUND_MASK_MONITOR)
+ mask = SOUND_MASK_MONITOR;
+ /* Just take first one. */
+ mask = (1 << (ffs(mask) - 1));
+ HDA_BOOTVERBOSE(
+ hdaa_audio_ctl_ossmixer_mask2allname(mask, buf, sizeof(buf));
+ device_printf(pdevinfo->dev,
+ "Automatically set rec source to: %s\n", buf);
+ );
hdaa_unlock(devinfo);
+ mix_setrecsrc(pdevinfo->mixer, mask);
+ hdaa_lock(devinfo);
}
/*
- * Jack detection initializer.
+ * Jack presence detection event handler.
*/
static void
-hdaa_hp_switch_init(struct hdaa_devinfo *devinfo)
+hdaa_presence_handler(struct hdaa_widget *w)
{
- struct hdaa_audio_as *as = devinfo->as;
- struct hdaa_widget *w;
- int i, poll = 0;
+ struct hdaa_devinfo *devinfo = w->devinfo;
+ struct hdaa_audio_as *as;
+ uint32_t res;
+ int connected;
- for (i = 0; i < devinfo->ascnt; i++) {
- if (as[i].hpredir < 0)
- continue;
+ if (w->enable == 0 || w->type !=
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ return;
- w = hdaa_widget_get(devinfo, as[i].pins[15]);
- if (w == NULL || w->enable == 0 || w->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
- continue;
- if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
- (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
- device_printf(devinfo->dev,
- "No jack detection support at pin %d\n",
- as[i].pins[15]);
- continue;
- }
- if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap) &&
- w->unsol < 0) {
- w->unsol = HDAC_UNSOL_ALLOC(
- device_get_parent(devinfo->dev), devinfo->dev,
- w->nid);
- hda_command(devinfo->dev,
- HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid,
- HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
- w->unsol));
- }
- if (w->unsol < 0)
- poll = 1;
- HDA_BOOTVERBOSE(
- device_printf(devinfo->dev,
- "Headphones redirection "
- "for as=%d nid=%d using %s.\n",
- i, w->nid,
- (poll != 0) ? "polling" : "unsolicited responses");
- );
- hdaa_hp_switch_handler(w);
- }
- if (poll) {
- callout_reset(&devinfo->poll_jack, 1,
- hdaa_jack_poll_callback, devinfo);
- }
+ if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+ (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0)
+ return;
+
+ res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
+ connected = (res & HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT) != 0;
+ if (devinfo->quirks & HDAA_QUIRK_SENSEINV)
+ connected = !connected;
+ if (connected == w->wclass.pin.connected)
+ return;
+ w->wclass.pin.connected = connected;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->dev,
+ "Pin sense: nid=%d sence=0x%08x (%sconnected)\n",
+ w->nid, res, !w->wclass.pin.connected ? "dis" : "");
+ );
+
+ as = &devinfo->as[w->bindas];
+ if (as->hpredir >= 0 && as->pins[15] == w->nid)
+ hdaa_hpredir_handler(w);
+ if (as->dir == HDAA_CTL_IN)
+ hdaa_autorecsrc_handler(as, w);
}
+/*
+ * Callback for poll based presence detection.
+ */
static void
-hdaa_hp_switch_deinit(struct hdaa_devinfo *devinfo)
+hdaa_jack_poll_callback(void *arg)
{
- struct hdaa_audio_as *as = devinfo->as;
- struct hdaa_widget *w;
- int i;
+ struct hdaa_devinfo *devinfo = arg;
+ struct hdaa_widget *w;
+ int i;
+ hdaa_lock(devinfo);
+ if (devinfo->poll_ival == 0) {
+ hdaa_unlock(devinfo);
+ return;
+ }
for (i = 0; i < devinfo->ascnt; i++) {
- w = hdaa_widget_get(devinfo, as[i].pins[15]);
+ if (devinfo->as[i].hpredir < 0)
+ continue;
+ w = hdaa_widget_get(devinfo, devinfo->as[i].pins[15]);
if (w == NULL || w->enable == 0 || w->type !=
HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
continue;
- if (HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) ||
- HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
- continue;
- if (w->unsol < 0)
- continue;
- hda_command(devinfo->dev,
- HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid, 0));
- HDAC_UNSOL_FREE(
- device_get_parent(devinfo->dev), devinfo->dev,
- w->unsol);
- w->unsol = -1;
+ hdaa_presence_handler(w);
}
+ callout_reset(&devinfo->poll_jack, devinfo->poll_ival,
+ hdaa_jack_poll_callback, devinfo);
+ hdaa_unlock(devinfo);
}
static void
@@ -534,13 +551,18 @@ hdaa_eld_handler(struct hdaa_widget *w)
HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
return;
+ if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+ (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0)
+ return;
+
+ res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
+ if ((w->eld != 0) == ((res & HDA_CMD_GET_PIN_SENSE_ELD_VALID) != 0))
+ return;
if (w->eld != NULL) {
w->eld_len = 0;
free(w->eld, M_HDAA);
w->eld = NULL;
}
-
- res = hda_command(devinfo->dev, HDA_CMD_GET_PIN_SENSE(0, w->nid));
HDA_BOOTVERBOSE(
device_printf(devinfo->dev,
"Pin sense: nid=%d sence=0x%08x "
@@ -575,49 +597,73 @@ hdaa_eld_handler(struct hdaa_widget *w)
);
}
-
+/*
+ * Pin sense initializer.
+ */
static void
-hdaa_eld_init(struct hdaa_devinfo *devinfo)
+hdaa_sense_init(struct hdaa_devinfo *devinfo)
{
- struct hdaa_widget *w;
- int i;
+ struct hdaa_audio_as *as;
+ struct hdaa_widget *w;
+ int i, poll = 0;
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdaa_widget_get(devinfo, i);
- if (w == NULL || w->type !=
+ if (w == NULL || w->enable == 0 || w->type !=
HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
continue;
- if (!HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) &&
- !HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
- continue;
if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap) &&
w->unsol < 0) {
w->unsol = HDAC_UNSOL_ALLOC(
- device_get_parent(devinfo->dev), devinfo->dev,
- w->nid);
+ device_get_parent(devinfo->dev), devinfo->dev, w->nid);
hda_command(devinfo->dev,
HDA_CMD_SET_UNSOLICITED_RESPONSE(0, w->nid,
- HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
- w->unsol));
+ HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE | w->unsol));
}
+ as = &devinfo->as[w->bindas];
+ if (as->hpredir >= 0 && as->pins[15] == w->nid) {
+ if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+ (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
+ device_printf(devinfo->dev,
+ "No presence detection support at nid %d\n",
+ as[i].pins[15]);
+ } else {
+ if (w->unsol < 0)
+ poll = 1;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->dev,
+ "Headphones redirection for "
+ "association %d nid=%d using %s.\n",
+ w->bindas, w->nid,
+ (poll != 0) ? "polling" :
+ "unsolicited responses");
+ );
+ };
+ }
+ hdaa_presence_handler(w);
+ if (!HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) &&
+ !HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
+ continue;
hdaa_eld_handler(w);
}
+ if (poll) {
+ callout_reset(&devinfo->poll_jack, 1,
+ hdaa_jack_poll_callback, devinfo);
+ }
}
static void
-hdaa_eld_deinit(struct hdaa_devinfo *devinfo)
+hdaa_sense_deinit(struct hdaa_devinfo *devinfo)
{
struct hdaa_widget *w;
int i;
+ callout_stop(&devinfo->poll_jack);
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdaa_widget_get(devinfo, i);
- if (w == NULL || w->type !=
+ if (w == NULL || w->enable == 0 || w->type !=
HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
continue;
- if (!HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap) &&
- !HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
- continue;
if (w->unsol < 0)
continue;
hda_command(devinfo->dev,
@@ -1191,6 +1237,10 @@ hdaa_widget_postprocess(struct hdaa_widget *w)
}
strlcat(w->name, HDA_CONNS[conn], sizeof(w->name));
strlcat(w->name, ")", sizeof(w->name));
+
+ if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
+ (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0)
+ w->wclass.pin.connected = 2;
}
}
@@ -5778,13 +5828,9 @@ hdaa_configure(device_t dev)
);
hdaa_patch_direct(devinfo);
HDA_BOOTHVERBOSE(
- device_printf(dev, "ELD init...\n");
+ device_printf(dev, "Pin sense init...\n");
);
- hdaa_eld_init(devinfo);
- HDA_BOOTHVERBOSE(
- device_printf(dev, "HP switch init...\n");
- );
- hdaa_hp_switch_init(devinfo);
+ hdaa_sense_init(devinfo);
HDA_BOOTHVERBOSE(
device_printf(dev, "Creating PCM devices...\n");
);
@@ -5849,13 +5895,9 @@ hdaa_unconfigure(device_t dev)
int i, j;
HDA_BOOTHVERBOSE(
- device_printf(dev, "HP switch deinit...\n");
+ device_printf(dev, "Pin sense deinit...\n");
);
- hdaa_hp_switch_deinit(devinfo);
- HDA_BOOTHVERBOSE(
- device_printf(dev, "ELD deinit...\n");
- );
- hdaa_eld_deinit(devinfo);
+ hdaa_sense_deinit(devinfo);
free(devinfo->ctl, M_HDAA);
devinfo->ctl = NULL;
devinfo->ctlcnt = 0;
@@ -6085,10 +6127,6 @@ hdaa_suspend(device_t dev)
}
}
HDA_BOOTHVERBOSE(
- device_printf(dev, "HP switch deinit...\n");
- );
- hdaa_hp_switch_deinit(devinfo);
- HDA_BOOTHVERBOSE(
device_printf(dev, "Power down FG"
" nid=%d to the D3 state...\n",
devinfo->nid);
@@ -6129,9 +6167,9 @@ hdaa_resume(device_t dev)
);
hdaa_patch_direct(devinfo);
HDA_BOOTHVERBOSE(
- device_printf(dev, "HP switch init...\n");
+ device_printf(dev, "Pin sense init...\n");
);
- hdaa_hp_switch_init(devinfo);
+ hdaa_sense_init(devinfo);
hdaa_unlock(devinfo);
for (i = 0; i < devinfo->num_devs; i++) {
@@ -6404,7 +6442,7 @@ hdaa_unsol_intr(device_t dev, uint32_t resp)
else
flags = 0x01;
if (flags & 0x01)
- hdaa_hp_switch_handler(w);
+ hdaa_presence_handler(w);
if (flags & 0x02)
hdaa_eld_handler(w);
}
@@ -6614,8 +6652,6 @@ hdaa_pcm_attach(device_t dev)
);
if (mixer_init(dev, &hdaa_audio_ctl_ossmixer_class, pdevinfo) != 0)
device_printf(dev, "Can't register mixer\n");
- else
- hdaa_audio_ctl_set_defaults(pdevinfo);
HDA_BOOTHVERBOSE(
device_printf(dev, "Registering PCM channels...\n");
@@ -6648,6 +6684,24 @@ hdaa_pcm_attach(device_t dev)
"32bit", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
as, sizeof(as), hdaa_sysctl_32bit, "I",
"Resolution of 32bit samples (20/24/32bit)");
+ pdevinfo->autorecsrc = 2;
+ resource_int_value(device_get_name(dev),
+ device_get_unit(dev), "autosrc", &pdevinfo->autorecsrc);
+ SYSCTL_ADD_INT(&d->rec_sysctl_ctx,
+ SYSCTL_CHILDREN(d->rec_sysctl_tree), OID_AUTO,
+ "autosrc", CTLTYPE_INT | CTLFLAG_RW,
+ &pdevinfo->autorecsrc, 0,
+ "Automatic recording source selection");
+ }
+
+ if (pdevinfo->mixer != NULL) {
+ hdaa_audio_ctl_set_defaults(pdevinfo);
+ if (pdevinfo->recas >= 0) {
+ as = &devinfo->as[pdevinfo->recas];
+ hdaa_lock(devinfo);
+ hdaa_autorecsrc_handler(as, NULL);
+ hdaa_unlock(devinfo);
+ }
}
snprintf(status, SND_STATUSLEN, "on %s %s",
diff --git a/sys/dev/sound/pci/hda/hdaa.h b/sys/dev/sound/pci/hda/hdaa.h
index db2017d..06ee87e 100644
--- a/sys/dev/sound/pci/hda/hdaa.h
+++ b/sys/dev/sound/pci/hda/hdaa.h
@@ -125,6 +125,7 @@ struct hdaa_widget {
uint32_t newconf;
uint32_t cap;
uint32_t ctrl;
+ int connected;
} pin;
struct {
uint8_t stripecap;
@@ -180,6 +181,7 @@ struct hdaa_pcm_devinfo {
u_char digital;
uint32_t ossmask; /* Mask of supported OSS devices. */
uint32_t recsrc; /* Mask of supported OSS sources. */
+ int autorecsrc;
};
struct hdaa_devinfo {
OpenPOWER on IntegriCloud