Date: Wed, 25 Jan 2012 20:46:10 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r230551 - in head: share/man/man4 sys/dev/sound/pci/hda Message-ID: <201201252046.q0PKkAEj044757@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Wed Jan 25 20:46:10 2012 New Revision: 230551 URL: http://svn.freebsd.org/changeset/base/230551 Log: 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. Modified: head/share/man/man4/snd_hda.4 head/sys/dev/sound/pci/hda/hdaa.c head/sys/dev/sound/pci/hda/hdaa.h Modified: head/share/man/man4/snd_hda.4 ============================================================================== --- head/share/man/man4/snd_hda.4 Wed Jan 25 20:15:58 2012 (r230550) +++ head/share/man/man4/snd_hda.4 Wed Jan 25 20:46:10 2012 (r230551) @@ -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 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 BI 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. Modified: head/sys/dev/sound/pci/hda/hdaa.c ============================================================================== --- head/sys/dev/sound/pci/hda/hdaa.c Wed Jan 25 20:15:58 2012 (r230550) +++ head/sys/dev/sound/pci/hda/hdaa.c Wed Jan 25 20:46:10 2012 (r230551) @@ -239,44 +239,30 @@ hdaa_audio_ctl_amp_get(struct hdaa_devin } /* - * 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_widge } } 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_widge 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_widge } /* 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_widge } /* - * 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_widg } 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 r 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", Modified: head/sys/dev/sound/pci/hda/hdaa.h ============================================================================== --- head/sys/dev/sound/pci/hda/hdaa.h Wed Jan 25 20:15:58 2012 (r230550) +++ head/sys/dev/sound/pci/hda/hdaa.h Wed Jan 25 20:46:10 2012 (r230551) @@ -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 {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201252046.q0PKkAEj044757>