diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c index 0699fe8..627e304 100644 --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -644,95 +644,6 @@ static const struct { }; #define HDAC_CODECS_LEN NELEM(hdac_codecs) -enum { - HDAC_HP_SWITCH_CTL, - HDAC_HP_SWITCH_CTRL, - HDAC_HP_SWITCH_DEBUG -}; - -static const struct { - uint32_t model; - uint32_t id; - int type; - int inverted; - int polling; - int execsense; - nid_t hpnid; - nid_t spkrnid[8]; - nid_t eapdnid; -} hdac_hp_switch[] = { - /* Specific OEM models */ - { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 17, { 16, -1 }, 16 }, - /* { HP_XW4300_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 21, { 16, 17, -1 }, -1 } */ - /* { HP_3010_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_DEBUG, - 0, 1, 0, 16, { 15, 18, 19, 20, 21, -1 }, -1 }, */ - { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 6, { 5, -1 }, 5 }, - { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 6, { 5, -1 }, 5 }, - { HP_NX6325_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 6, { 5, -1 }, 5 }, - /* { HP_DC7700_SUBVENDOR, HDA_CODEC_ALC262, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 21, { 22, 27, -1 }, -1 }, */ - { TOSHIBA_U200_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 6, { 5, -1 }, -1 }, - { TOSHIBA_A135_SUBVENDOR, HDA_CODEC_ALC861VD, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 27, { 20, -1 }, -1 }, - { DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, - 0, 0, -1, 13, { 14, -1 }, -1 }, - { DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, - 0, 0, -1, 13, { 14, -1 }, -1 }, - { DELL_OPLX745_SUBVENDOR, HDA_CODEC_AD1983, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 6, { 5, 7, -1 }, -1 }, - { APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 21, { 20, 22, -1 }, -1 }, - { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDAC_HP_SWITCH_CTRL, - 0, 0, -1, 10, { 13, -1 }, -1 }, - { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, - 1, 0, -1, 26, { 27, -1 }, -1 }, - /* { LENOVO_TCA55_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 26, { 27, 28, 29, 30, -1 }, -1 }, */ - { LG_LW20_SUBVENDOR, HDA_CODEC_ALC880, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 27, { 20, -1 }, -1 }, - { ACER_A5050_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 21, -1 }, -1 }, - { ACER_3681WXM_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 21, -1 }, -1 }, - { ACER_A4520_SUBVENDOR, HDA_CODEC_ALC268, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 21, -1 }, -1 }, - { UNIWILL_9080_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 21, -1 }, -1 }, - { MSI_MS1034_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 27, -1 }, -1 }, - { MSI_MS034A_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 27, -1 }, -1 }, - { FS_SI1848_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 21, -1 }, -1 }, - { FL_S7020D_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 16, -1 }, -1 }, - /* - * All models that at least come from the same vendor with - * simmilar codec. - */ - { HP_ALL_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 17, { 16, -1 }, 16 }, - { HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 6, { 5, -1 }, 5 }, - { TOSHIBA_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 6, { 5, -1 }, -1 }, - { DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, - 0, 0, -1, 13, { 14, -1 }, -1 }, -#if 0 - { LENOVO_ALL_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, - 1, 0, -1, 26, { 27, -1 }, -1 }, - { ACER_ALL_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, - 0, 0, -1, 20, { 21, -1 }, -1 }, -#endif -}; -#define HDAC_HP_SWITCH_LEN NELEM(hdac_hp_switch) - static const struct { uint32_t model; uint32_t id; @@ -900,8 +811,8 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) struct hdac_widget *w; struct hdac_audio_ctl *ctl; uint32_t val, id, res; - int i = 0, j, timeout, forcemute; - nid_t cad; + int i = 0, timeout, forcemute; + nid_t cad, hp_nid; if (devinfo == NULL || devinfo->codec == NULL || devinfo->codec->sc == NULL) @@ -910,35 +821,28 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) sc = devinfo->codec->sc; cad = devinfo->codec->cad; id = hdac_codec_id(devinfo); - for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) { - if (HDA_DEV_MATCH(hdac_hp_switch[i].model, - sc->pci_subvendor) && - hdac_hp_switch[i].id == id) - break; - } - - if (i >= HDAC_HP_SWITCH_LEN) - return; forcemute = 0; - if (hdac_hp_switch[i].eapdnid != -1) { - w = hdac_widget_get(devinfo, hdac_hp_switch[i].eapdnid); - if (w != NULL && w->param.eapdbtl != HDAC_INVALID) - forcemute = (w->param.eapdbtl & - HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD) ? 0 : 1; - } - if (hdac_hp_switch[i].execsense != -1) - hdac_command(sc, - HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid, - hdac_hp_switch[i].execsense), cad); + /*For now, only the first headphone jack supports automute. So find + * that jack*/ + hp_nid = devinfo->startnode; + for (; hp_nid < devinfo->endnode; hp_nid++) { + w = hdac_widget_get(devinfo, hp_nid); + if((w != NULL) && + (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) && + (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(w->wclass.pin.config))) { + break; + } + } timeout = 10000; do { res = hdac_command(sc, - HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), + HDA_CMD_GET_PIN_SENSE(cad, hp_nid), cad); - if (hdac_hp_switch[i].execsense == -1 || res != 0x7fffffff) + + if (res != 0x7fffffff) break; DELAY(10); } while (--timeout != 0); @@ -946,136 +850,47 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo) HDA_BOOTVERBOSE( device_printf(sc->dev, "HDA_DEBUG: Pin sense: nid=%d timeout=%d res=0x%08x\n", - hdac_hp_switch[i].hpnid, timeout, res); + hp_nid, timeout, res); ); - - res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res); - res ^= hdac_hp_switch[i].inverted; - - switch (hdac_hp_switch[i].type) { - case HDAC_HP_SWITCH_CTL: - ctl = hdac_audio_ctl_amp_get(devinfo, - hdac_hp_switch[i].hpnid, 0, 1); - if (ctl != NULL) { - val = (res != 0 && forcemute == 0) ? - HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL; - if (val != ctl->muted) { - ctl->muted = val; - hdac_audio_ctl_amp_set(ctl, - HDA_AMP_MUTE_DEFAULT, ctl->left, - ctl->right); - } - } - for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { - ctl = hdac_audio_ctl_amp_get(devinfo, - hdac_hp_switch[i].spkrnid[j], 0, 1); - if (ctl == NULL) - continue; - val = (res != 0 || forcemute == 1) ? - HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE; - if (val == ctl->muted) - continue; + + + ctl = hdac_audio_ctl_amp_get(devinfo, + hp_nid, 0, 1); + if (ctl != NULL) { + val = (res != 0 && forcemute == 0) ? + HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL; + if (val != ctl->muted) { ctl->muted = val; - hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT, - ctl->left, ctl->right); + hdac_audio_ctl_amp_set(ctl, + HDA_AMP_MUTE_DEFAULT, ctl->left, + ctl->right); } - break; - case HDAC_HP_SWITCH_CTRL: - if (res != 0) { - /* HP in */ - w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); - if (w != NULL && w->type == - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { - if (forcemute == 0) - val = w->wclass.pin.ctrl | - HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - else - val = w->wclass.pin.ctrl & - ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - if (val != w->wclass.pin.ctrl) { - w->wclass.pin.ctrl = val; - hdac_command(sc, - HDA_CMD_SET_PIN_WIDGET_CTRL(cad, - w->nid, w->wclass.pin.ctrl), cad); - } - } - for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { - w = hdac_widget_get(devinfo, - hdac_hp_switch[i].spkrnid[j]); - if (w == NULL || w->type != - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) - continue; - val = w->wclass.pin.ctrl & - ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - if (val == w->wclass.pin.ctrl) - continue; - w->wclass.pin.ctrl = val; - hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL( - cad, w->nid, w->wclass.pin.ctrl), cad); - } - } else { - /* HP out */ - w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); - if (w != NULL && w->type == - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { - val = w->wclass.pin.ctrl & - ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - if (val != w->wclass.pin.ctrl) { - w->wclass.pin.ctrl = val; - hdac_command(sc, - HDA_CMD_SET_PIN_WIDGET_CTRL(cad, - w->nid, w->wclass.pin.ctrl), cad); - } - } - for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { - w = hdac_widget_get(devinfo, - hdac_hp_switch[i].spkrnid[j]); - if (w == NULL || w->type != - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) - continue; - if (forcemute == 0) - val = w->wclass.pin.ctrl | - HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - else - val = w->wclass.pin.ctrl & - ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE; - if (val == w->wclass.pin.ctrl) - continue; - w->wclass.pin.ctrl = val; - hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL( - cad, w->nid, w->wclass.pin.ctrl), cad); - } + } + + + for (i = devinfo->startnode; i < devinfo->endnode; i++) { + + w = hdac_widget_get(devinfo, i); + if(w == NULL || w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { + continue; } - break; - case HDAC_HP_SWITCH_DEBUG: - if (hdac_hp_switch[i].execsense != -1) - hdac_command(sc, - HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid, - hdac_hp_switch[i].execsense), cad); - res = hdac_command(sc, - HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad); - device_printf(sc->dev, - "[ 0] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", - hdac_hp_switch[i].hpnid, res); - for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) { - w = hdac_widget_get(devinfo, - hdac_hp_switch[i].spkrnid[j]); - if (w == NULL || w->type != - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) - continue; - if (hdac_hp_switch[i].execsense != -1) - hdac_command(sc, - HDA_CMD_SET_PIN_SENSE(cad, w->nid, - hdac_hp_switch[i].execsense), cad); - res = hdac_command(sc, - HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad); - device_printf(sc->dev, - "[%2d] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n", - j + 1, w->nid, res); + + if(((w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) != + HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER)) { + continue; } - break; - default: - break; + + ctl = hdac_audio_ctl_amp_get(devinfo, + i, 0, 1); + if (ctl == NULL) + continue; + val = (res != 0 || forcemute == 1) ? + HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE; + if (val == ctl->muted) + continue; + ctl->muted = val; + hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT, + ctl->left, ctl->right); } } @@ -3337,27 +3152,6 @@ static kobj_method_t hdac_channel_methods[] = { }; CHANNEL_DECLARE(hdac_channel); -static void -hdac_jack_poll_callback(void *arg) -{ - struct hdac_devinfo *devinfo = arg; - struct hdac_softc *sc; - - if (devinfo == NULL || devinfo->codec == NULL || - devinfo->codec->sc == NULL) - return; - sc = devinfo->codec->sc; - hdac_lock(sc); - if (sc->poll_ival == 0) { - hdac_unlock(sc); - return; - } - hdac_hp_switch_handler(devinfo); - callout_reset(&sc->poll_jack, sc->poll_ival, - hdac_jack_poll_callback, devinfo); - hdac_unlock(sc); -} - static int hdac_audio_ctl_ossmixer_init(struct snd_mixer *m) { @@ -3376,24 +3170,26 @@ hdac_audio_ctl_ossmixer_init(struct snd_mixer *m) id = hdac_codec_id(devinfo); cad = devinfo->codec->cad; - for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) { - if (!(HDA_DEV_MATCH(hdac_hp_switch[i].model, - sc->pci_subvendor) && hdac_hp_switch[i].id == id)) + + for (i = devinfo->startnode; i < devinfo->endnode; i++) { + w = hdac_widget_get(devinfo, i); + if(w == NULL || w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) { continue; - w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid); - if (w == NULL || w->enable == 0 || w->type != - HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) + } + + if(!HDA_PARAM_PIN_CAP_HEADPHONE_CAP(w->wclass.pin.config)) { continue; - if (hdac_hp_switch[i].polling != 0) - callout_reset(&sc->poll_jack, 1, - hdac_jack_poll_callback, devinfo); - else if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) - hdac_command(sc, + } + + if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) { + device_printf(sc->dev, "Enabling unsolicited responses for nid %d.", w->nid); + hdac_command(sc, HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid, HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE | HDAC_UNSOLTAG_EVENT_HP), cad); - else + } else { continue; + } hdac_hp_switch_handler(devinfo); HDA_BOOTVERBOSE( device_printf(sc->dev, @@ -3404,10 +3200,8 @@ hdac_audio_ctl_ossmixer_init(struct snd_mixer *m) "pci_subvendor=0x%08x " "codec=0x%08x [%s]\n", i, w->nid, sc->pci_subvendor, id, - (hdac_hp_switch[i].polling != 0) ? "POLL" : "UNSOL"); ); - break; } for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) { if (!(HDA_DEV_MATCH(hdac_eapd_switch[i].model, @@ -3742,7 +3536,6 @@ hdac_attach(device_t dev) callout_init(&sc->poll_hda); callout_init(&sc->poll_hdac); - callout_init(&sc->poll_jack); TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc); @@ -5790,7 +5583,6 @@ hdac_release_resources(struct hdac_softc *sc) sc->poll_ival = 0; callout_stop(&sc->poll_hda); callout_stop(&sc->poll_hdac); - callout_stop(&sc->poll_jack); hdac_reset(sc); hdac_unlock(sc); @@ -6167,11 +5959,17 @@ hdac_attach2(void *arg) device_printf(sc->dev, "HDA_DEBUG: Enabling controller interrupt...\n"); ); - if (sc->polling == 0) - HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, - HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); + HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) | HDAC_GCTL_UNSOL); + if (sc->polling == 0) { + HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, + HDAC_INTCTL_CIE | HDAC_INTCTL_GIE); + } else { + callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc); + } + + DELAY(1000); diff --git a/sys/dev/sound/pci/hda/hdac_private.h b/sys/dev/sound/pci/hda/hdac_private.h index 6696597..416485e 100644 --- a/sys/dev/sound/pci/hda/hdac_private.h +++ b/sys/dev/sound/pci/hda/hdac_private.h @@ -333,7 +333,6 @@ struct hdac_softc { int poll_ival; struct callout poll_hda; struct callout poll_hdac; - struct callout poll_jack; struct task unsolq_task;