summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sound/pci/hda/hda_reg.h56
-rw-r--r--sys/dev/sound/pci/hda/hdac.c5849
-rw-r--r--sys/dev/sound/pci/hda/hdac_private.h95
3 files changed, 3550 insertions, 2450 deletions
diff --git a/sys/dev/sound/pci/hda/hda_reg.h b/sys/dev/sound/pci/hda/hda_reg.h
index 7965daf..3c5757a 100644
--- a/sys/dev/sound/pci/hda/hda_reg.h
+++ b/sys/dev/sound/pci/hda/hda_reg.h
@@ -180,13 +180,14 @@
HDA_CMD_VERB_SET_CONV_FMT, (payload)))
/* Digital Converter Control */
-#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT 0xf0d
+#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1 0xf0d
+#define HDA_CMD_VERB_GET_DIGITAL_CONV_FMT2 0xf0e
#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1 0x70d
#define HDA_CMD_VERB_SET_DIGITAL_CONV_FMT2 0x70e
#define HDA_CMD_GET_DIGITAL_CONV_FMT(cad, nid) \
(HDA_CMD_12BIT((cad), (nid), \
- HDA_CMD_VERB_GET_DIGITAL_CONV_FMTT, 0x0))
+ HDA_CMD_VERB_GET_DIGITAL_CONV_FMT1, 0x0))
#define HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, nid, payload) \
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_SET_DIGITAL_CONV_FMT1, (payload)))
@@ -1034,7 +1035,7 @@
HDA_PARAM_PIN_CAP_HEADPHONE_CAP_SHIFT)
#define HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(param) \
(((param) & HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK) >> \
- HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_MASK)
+ HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP_SHIFT)
#define HDA_PARAM_PIN_CAP_TRIGGER_REQD(param) \
(((param) & HDA_PARAM_PIN_CAP_TRIGGER_REQD_MASK) >> \
HDA_PARAM_PIN_CAP_TRIGGER_REQD_SHIFT)
@@ -1193,14 +1194,47 @@
HDA_PARAM_VOLUME_KNOB_CAP_NUM_STEPS_SHIFT)
-#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK 0x00000000f
-#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK 0x0000000f0
-#define HDA_CONFIG_DEFAULTCONF_MISC_MASK 0x000000f00
-#define HDA_CONFIG_DEFAULTCONF_COLOR_MASK 0x00000f000
-#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK 0x000f00000
-#define HDA_CONFIG_DEFAULTCONF_DEVICE_MASK 0x000f00000
-#define HDA_CONFIG_DEFAULTCONF_LOCATION_MASK 0x03f000000
-#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK 0x0c0000000
+#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK 0x0000000f
+#define HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT 0
+#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK 0x000000f0
+#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT 4
+#define HDA_CONFIG_DEFAULTCONF_MISC_MASK 0x00000f00
+#define HDA_CONFIG_DEFAULTCONF_MISC_SHIFT 8
+#define HDA_CONFIG_DEFAULTCONF_COLOR_MASK 0x0000f000
+#define HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT 12
+#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK 0x000f0000
+#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT 16
+#define HDA_CONFIG_DEFAULTCONF_DEVICE_MASK 0x00f00000
+#define HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT 20
+#define HDA_CONFIG_DEFAULTCONF_LOCATION_MASK 0x3f000000
+#define HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT 24
+#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK 0xc0000000
+#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT 30
+
+#define HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT)
+#define HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT)
+#define HDA_CONFIG_DEFAULTCONF_MISC(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_MISC_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_MISC_SHIFT)
+#define HDA_CONFIG_DEFAULTCONF_COLOR(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_COLOR_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT)
+#define HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT)
+#define HDA_CONFIG_DEFAULTCONF_DEVICE(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT)
+#define HDA_CONFIG_DEFAULTCONF_LOCATION(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_LOCATION_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT)
+#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf) \
+ (((conf) & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >> \
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT)
#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK (0<<30)
#define HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE (1<<30)
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c
index 06fa544..2f2ca85 100644
--- a/sys/dev/sound/pci/hda/hdac.c
+++ b/sys/dev/sound/pci/hda/hdac.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
* Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
+ * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,6 +62,7 @@
* * Daniel Eischen <deischen@FreeBSD.org> *
* * Maxime Guillaud <bsd-ports@mguillaud.net> *
* * Ariff Abdullah <ariff@FreeBSD.org> *
+ * * Alexander Motin <mav@FreeBSD.org> *
* * *
* * ....and various people from freebsd-multimedia@FreeBSD.org *
* * *
@@ -81,8 +83,8 @@
#include "mixer_if.h"
-#define HDA_DRV_TEST_REV "20080420_0052"
-#define HDA_WIDGET_PARSER_REV 1
+#define HDA_DRV_TEST_REV "20080913_0111"
+#define HDA_WIDGET_PARSER_REV 2
SND_DECLARE_FILE("$FreeBSD$");
@@ -213,6 +215,7 @@ SND_DECLARE_FILE("$FreeBSD$");
#define ACER_A4710_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x012f)
#define ACER_A4715_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0133)
#define ACER_3681WXM_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x0110)
+#define ACER_T6292_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0x011b)
#define ACER_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(ACER, 0xffff)
/* Asus */
@@ -260,6 +263,11 @@ SND_DECLARE_FILE("$FreeBSD$");
#define APPLE_VENDORID 0x106b
#define APPLE_MB3_SUBVENDOR HDA_MODEL_CONSTRUCT(APPLE, 0x00a1)
+/* Sony */
+#define SONY_VENDORID 0x104d
+#define SONY_S5_SUBVENDOR HDA_MODEL_CONSTRUCT(SONY, 0x81cc)
+#define SONY_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(SONY, 0xffff)
+
/*
* Apple Intel MacXXXX seems using Sigmatel codec/vendor id
* instead of their own, which is beyond my comprehension
@@ -308,6 +316,7 @@ SND_DECLARE_FILE("$FreeBSD$");
/* Misc constants.. */
+#define HDA_AMP_VOL_DEFAULT (-1)
#define HDA_AMP_MUTE_DEFAULT (0xffffffff)
#define HDA_AMP_MUTE_NONE (0)
#define HDA_AMP_MUTE_LEFT (1 << 0)
@@ -317,16 +326,10 @@ SND_DECLARE_FILE("$FreeBSD$");
#define HDA_AMP_LEFT_MUTED(v) ((v) & (HDA_AMP_MUTE_LEFT))
#define HDA_AMP_RIGHT_MUTED(v) (((v) & HDA_AMP_MUTE_RIGHT) >> 1)
-#define HDA_DAC_PATH (1 << 0)
-#define HDA_ADC_PATH (1 << 1)
-#define HDA_ADC_RECSEL (1 << 2)
-
-#define HDA_DAC_LOCKED (1 << 3)
-#define HDA_ADC_LOCKED (1 << 4)
+#define HDA_ADC_MONITOR (1 << 0)
-#define HDA_CTL_OUT (1 << 0)
-#define HDA_CTL_IN (1 << 1)
-#define HDA_CTL_BOTH (HDA_CTL_IN | HDA_CTL_OUT)
+#define HDA_CTL_OUT 1
+#define HDA_CTL_IN 2
#define HDA_GPIO_MAX 8
/* 0 - 7 = GPIO , 8 = Flush */
@@ -346,6 +349,7 @@ SND_DECLARE_FILE("$FreeBSD$");
#define HDA_QUIRK_FORCESTEREO (1 << 11)
#define HDA_QUIRK_EAPDINV (1 << 12)
#define HDA_QUIRK_DMAPOS (1 << 13)
+#define HDA_QUIRK_SENSEINV (1 << 14)
/* 26 - 31 = vrefs */
#define HDA_QUIRK_IVREF50 (1 << 26)
@@ -361,9 +365,6 @@ SND_DECLARE_FILE("$FreeBSD$");
HDA_QUIRK_OVREF100)
#define HDA_QUIRK_VREF (HDA_QUIRK_IVREF | HDA_QUIRK_OVREF)
-#define SOUND_MASK_SKIP (1 << 30)
-#define SOUND_MASK_DISABLE (1 << 31)
-
#if __FreeBSD_version < 600000
#define taskqueue_drain(...)
#endif
@@ -386,6 +387,7 @@ static const struct {
{ "forcestereo", HDA_QUIRK_FORCESTEREO },
{ "eapdinv", HDA_QUIRK_EAPDINV },
{ "dmapos", HDA_QUIRK_DMAPOS },
+ { "senseinv", HDA_QUIRK_SENSEINV },
{ "ivref50", HDA_QUIRK_IVREF50 },
{ "ivref80", HDA_QUIRK_IVREF80 },
{ "ivref100", HDA_QUIRK_IVREF100 },
@@ -413,14 +415,18 @@ static const struct {
#define HDA_PARSE_MAXDEPTH 10
#define HDAC_UNSOLTAG_EVENT_HP 0x00
-#define HDAC_UNSOLTAG_EVENT_TEST 0x01
MALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller");
-enum {
- HDA_PARSE_MIXER,
- HDA_PARSE_DIRECT
-};
+const char *HDA_COLORS[16] = {"Unknown", "Black", "Grey", "Blue", "Green", "Red",
+ "Orange", "Yellow", "Purple", "Pink", "Res.A", "Res.B", "Res.C", "Res.D",
+ "White", "Other"};
+
+const char *HDA_DEVS[16] = {"Line-out", "Speaker", "Headphones", "CD",
+ "SPDIF-out", "Digital-out", "Modem-line", "Modem-handset", "Line-in",
+ "AUX", "Mic", "Telephony", "SPDIF-in", "Digital-in", "Res.E", "Other"};
+
+const char *HDA_CONNS[4] = {"Jack", "None", "Fixed", "Both"};
/* Default */
static uint32_t hdac_fmt[] = {
@@ -535,6 +541,7 @@ static const struct {
#define HDA_CODEC_ALC883 HDA_CODEC_CONSTRUCT(REALTEK, 0x0883)
#define HDA_CODEC_ALC885 HDA_CODEC_CONSTRUCT(REALTEK, 0x0885)
#define HDA_CODEC_ALC888 HDA_CODEC_CONSTRUCT(REALTEK, 0x0888)
+#define HDA_CODEC_ALC889 HDA_CODEC_CONSTRUCT(REALTEK, 0x0889)
#define HDA_CODEC_ALCXXXX HDA_CODEC_CONSTRUCT(REALTEK, 0xffff)
/* Analog Devices */
@@ -554,16 +561,31 @@ static const struct {
/* Sigmatel */
#define SIGMATEL_VENDORID 0x8384
+#define HDA_CODEC_STAC9230X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7612)
+#define HDA_CODEC_STAC9230D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7613)
+#define HDA_CODEC_STAC9229X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7614)
+#define HDA_CODEC_STAC9229D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7615)
+#define HDA_CODEC_STAC9228X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7616)
+#define HDA_CODEC_STAC9228D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7617)
+#define HDA_CODEC_STAC9227X HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618)
+#define HDA_CODEC_STAC9227D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7619)
+#define HDA_CODEC_STAC9271D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627)
+#define HDA_CODEC_STAC9872AK HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7662)
#define HDA_CODEC_STAC9221 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680)
+#define HDA_CODEC_STAC922XD HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
#define HDA_CODEC_STAC9221D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683)
#define HDA_CODEC_STAC9220 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690)
-#define HDA_CODEC_STAC922XD HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
-#define HDA_CODEC_STAC9227 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618)
-#define HDA_CODEC_STAC9271D HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627)
#define HDA_CODEC_STAC9205 HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a0)
-#define HDA_CODEC_STAC9872AK HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7662)
#define HDA_CODEC_STACXXXX HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff)
+/* Silicon Image */
+#define SII_VENDORID 0x1095
+#define HDA_CODEC_SIIXXXX HDA_CODEC_CONSTRUCT(SII, 0xffff)
+
+/* Lucent/Agere */
+#define AGERE_VENDORID 0x11c1
+#define HDA_CODEC_AGEREXXXX HDA_CODEC_CONSTRUCT(AGERE, 0xffff)
+
/*
* Conexant
*
@@ -594,6 +616,11 @@ static const struct {
#define HDA_CODEC_VT1709_7 HDA_CODEC_CONSTRUCT(VIA, 0xe717)
#define HDA_CODEC_VTXXXX HDA_CODEC_CONSTRUCT(VIA, 0xffff)
+/* ATI */
+#define HDA_CODEC_ATIXXXX HDA_CODEC_CONSTRUCT(ATI, 0xffff)
+
+/* NVIDIA */
+#define HDA_CODEC_NVIDIAXXXX HDA_CODEC_CONSTRUCT(NVIDIA, 0xffff)
/* Codecs */
static const struct {
@@ -611,6 +638,7 @@ static const struct {
{ HDA_CODEC_ALC883, "Realtek ALC883" },
{ HDA_CODEC_ALC885, "Realtek ALC885" },
{ HDA_CODEC_ALC888, "Realtek ALC888" },
+ { HDA_CODEC_ALC889, "Realtek ALC889" },
{ HDA_CODEC_AD1981HD, "Analog Devices AD1981HD" },
{ HDA_CODEC_AD1983, "Analog Devices AD1983" },
{ HDA_CODEC_AD1984, "Analog Devices AD1984" },
@@ -622,7 +650,14 @@ static const struct {
{ HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" },
{ HDA_CODEC_STAC9220, "Sigmatel STAC9220" },
{ HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" },
- { HDA_CODEC_STAC9227, "Sigmatel STAC9227" },
+ { HDA_CODEC_STAC9230X, "Sigmatel STAC9230X" },
+ { HDA_CODEC_STAC9230D, "Sigmatel STAC9230D" },
+ { HDA_CODEC_STAC9229X, "Sigmatel STAC9229X" },
+ { HDA_CODEC_STAC9229D, "Sigmatel STAC9229D" },
+ { HDA_CODEC_STAC9228X, "Sigmatel STAC9228X" },
+ { HDA_CODEC_STAC9228D, "Sigmatel STAC9228D" },
+ { HDA_CODEC_STAC9227X, "Sigmatel STAC9227X" },
+ { HDA_CODEC_STAC9227D, "Sigmatel STAC9227D" },
{ HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" },
{ HDA_CODEC_STAC9205, "Sigmatel STAC9205" },
{ HDA_CODEC_STAC9872AK,"Sigmatel STAC9872AK" },
@@ -645,131 +680,21 @@ static const struct {
{ HDA_CODEC_ADXXXX, "Analog Devices (Unknown)" },
{ HDA_CODEC_CMIXXXX, "CMedia (Unknown)" },
{ HDA_CODEC_STACXXXX, "Sigmatel (Unknown)" },
+ { HDA_CODEC_SIIXXXX, "Silicon Image (Unknown)" },
+ { HDA_CODEC_AGEREXXXX, "Lucent/Agere Systems (Unknown)" },
{ HDA_CODEC_CXXXXX, "Conexant (Unknown)" },
{ HDA_CODEC_VTXXXX, "VIA (Unknown)" },
+ { HDA_CODEC_ATIXXXX, "ATI (Unknown)" },
+ { HDA_CODEC_NVIDIAXXXX,"NVidia (Unknown)" },
};
#define HDAC_CODECS_LEN (sizeof(hdac_codecs) / sizeof(hdac_codecs[0]))
-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 },
- { DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205, HDAC_HP_SWITCH_CTRL,
- 0, 0, -1, 10, { 13, -1 }, -1 },
- { DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205, HDAC_HP_SWITCH_CTRL,
- 0, 0, -1, 10, { 13, -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_3KN200_SUBVENDOR, HDA_CODEC_ALC861VD, HDAC_HP_SWITCH_CTL,
- 0, 0, -1, 27, { 20, -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 },
- { ACER_A4710_SUBVENDOR, HDA_CODEC_ALC268, HDAC_HP_SWITCH_CTL,
- 0, 0, -1, 20, { 21, -1 }, -1 },
- { ACER_A4715_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 },
- { FL_U1010_SUBVENDOR, HDA_CODEC_ALC262, HDAC_HP_SWITCH_CTL,
- 0, 0, -1, 20, { 21, -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 \
- (sizeof(hdac_hp_switch) / sizeof(hdac_hp_switch[0]))
-
-static const struct {
- uint32_t model;
- uint32_t id;
- nid_t eapdnid;
- int hp_switch;
-} hdac_eapd_switch[] = {
- { HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, 16, 1 },
- { HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
- { HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
-};
-#define HDAC_EAPD_SWITCH_LEN \
- (sizeof(hdac_eapd_switch) / sizeof(hdac_eapd_switch[0]))
/****************************************************************************
* Function prototypes
****************************************************************************/
static void hdac_intr_handler(void *);
-static int hdac_reset(struct hdac_softc *);
+static int hdac_reset(struct hdac_softc *, int);
static int hdac_get_capabilities(struct hdac_softc *);
static void hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
static int hdac_dma_alloc(struct hdac_softc *,
@@ -783,10 +708,10 @@ static void hdac_corb_init(struct hdac_softc *);
static void hdac_rirb_init(struct hdac_softc *);
static void hdac_corb_start(struct hdac_softc *);
static void hdac_rirb_start(struct hdac_softc *);
-static void hdac_scan_codecs(struct hdac_softc *, int);
-static int hdac_probe_codec(struct hdac_codec *);
-static struct hdac_devinfo *hdac_probe_function(struct hdac_codec *, nid_t);
-static void hdac_add_child(struct hdac_softc *, struct hdac_devinfo *);
+static void hdac_scan_codecs(struct hdac_softc *);
+static void hdac_probe_codec(struct hdac_codec *);
+static void hdac_probe_function(struct hdac_codec *, nid_t);
+static int hdac_pcmchannel_setup(struct hdac_chan *);
static void hdac_attach2(void *);
@@ -798,34 +723,37 @@ static void hdac_command_send_internal(struct hdac_softc *,
static int hdac_probe(device_t);
static int hdac_attach(device_t);
static int hdac_detach(device_t);
+static int hdac_suspend(device_t);
+static int hdac_resume(device_t);
static void hdac_widget_connection_select(struct hdac_widget *, uint8_t);
static void hdac_audio_ctl_amp_set(struct hdac_audio_ctl *,
uint32_t, int, int);
static struct hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *,
- nid_t, int, int);
+ nid_t, int, int, int);
static void hdac_audio_ctl_amp_set_internal(struct hdac_softc *,
nid_t, nid_t, int, int, int, int, int, int);
-static int hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *);
static struct hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t);
static int hdac_rirb_flush(struct hdac_softc *sc);
static int hdac_unsolq_flush(struct hdac_softc *sc);
+static void hdac_dump_pin_config(struct hdac_widget *w, uint32_t conf);
+
#define hdac_command(a1, a2, a3) \
hdac_command_sendone_internal(a1, a2, a3)
-#define hdac_codec_id(d) \
- ((uint32_t)((d == NULL) ? 0x00000000 : \
- ((((uint32_t)(d)->vendor_id & 0x0000ffff) << 16) | \
- ((uint32_t)(d)->device_id & 0x0000ffff))))
+#define hdac_codec_id(c) \
+ ((uint32_t)((c == NULL) ? 0x00000000 : \
+ ((((uint32_t)(c)->vendor_id & 0x0000ffff) << 16) | \
+ ((uint32_t)(c)->device_id & 0x0000ffff))))
static char *
-hdac_codec_name(struct hdac_devinfo *devinfo)
+hdac_codec_name(struct hdac_codec *codec)
{
uint32_t id;
int i;
- id = hdac_codec_id(devinfo);
+ id = hdac_codec_id(codec);
for (i = 0; i < HDAC_CODECS_LEN; i++) {
if (HDA_DEV_MATCH(hdac_codecs[i].id, id))
@@ -836,20 +764,6 @@ hdac_codec_name(struct hdac_devinfo *devinfo)
}
static char *
-hdac_audio_ctl_ossmixer_mask2name(uint32_t devmask)
-{
- static char *ossname[] = SOUND_DEVICE_NAMES;
- static char *unknown = "???";
- int i;
-
- for (i = SOUND_MIXER_NRDEVICES - 1; i >= 0; i--) {
- if (devmask & (1 << i))
- return (ossname[i]);
- }
- return (unknown);
-}
-
-static void
hdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
{
static char *ossname[] = SOUND_DEVICE_NAMES;
@@ -864,6 +778,7 @@ hdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
first = 0;
}
}
+ return (buf);
}
static struct hdac_audio_ctl *
@@ -879,48 +794,46 @@ hdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index)
}
static struct hdac_audio_ctl *
-hdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid,
+hdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid, int dir,
int index, int cnt)
{
- struct hdac_audio_ctl *ctl, *retctl = NULL;
- int i, at, atindex, found = 0;
+ struct hdac_audio_ctl *ctl;
+ int i, found = 0;
if (devinfo == NULL || devinfo->function.audio.ctl == NULL)
return (NULL);
- at = cnt;
- if (at == 0)
- at = 1;
- else if (at < 0)
- at = -1;
- atindex = index;
- if (atindex < 0)
- atindex = -1;
-
i = 0;
while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL)
+ if (ctl->enable == 0)
continue;
- if (!(ctl->widget->nid == nid && (atindex == -1 ||
- ctl->index == atindex)))
+ if (ctl->widget->nid != nid)
+ continue;
+ if (dir && ctl->ndir != dir)
+ continue;
+ if (index >= 0 && ctl->ndir == HDA_CTL_IN &&
+ ctl->dir == ctl->ndir && ctl->index != index)
continue;
found++;
- if (found == cnt)
+ if (found == cnt || cnt <= 0)
return (ctl);
- retctl = ctl;
}
- return ((at == -1) ? retctl : NULL);
+ return (NULL);
}
+/*
+ * Jack detection (Speaker/HP redirection) event handler.
+ */
static void
hdac_hp_switch_handler(struct hdac_devinfo *devinfo)
{
+ struct hdac_audio_as *as;
struct hdac_softc *sc;
struct hdac_widget *w;
struct hdac_audio_ctl *ctl;
- uint32_t val, id, res;
- int i = 0, j, timeout, forcemute;
+ uint32_t val, res;
+ int i, j;
nid_t cad;
if (devinfo == NULL || devinfo->codec == NULL ||
@@ -929,84 +842,47 @@ 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);
+ as = devinfo->function.audio.as;
+ for (i = 0; i < devinfo->function.audio.ascnt; i++) {
+ if (as[i].hpredir < 0)
+ continue;
+
+ w = hdac_widget_get(devinfo, as[i].pins[15]);
+ if (w == NULL || w->enable == 0 || w->type !=
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
- timeout = 10000;
- do {
res = hdac_command(sc,
- HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid),
- cad);
- if (hdac_hp_switch[i].execsense == -1 || res != 0x7fffffff)
- break;
- DELAY(10);
- } while (--timeout != 0);
+ HDA_CMD_GET_PIN_SENSE(cad, as[i].pins[15]), cad);
- 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);
- );
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "Pin sense: nid=%d res=0x%08x\n",
+ as[i].pins[15], res);
+ );
- res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res);
- res ^= hdac_hp_switch[i].inverted;
+ res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res);
+ if (devinfo->function.audio.quirks & HDA_QUIRK_SENSEINV)
+ res ^= 1;
- switch (hdac_hp_switch[i].type) {
- case HDAC_HP_SWITCH_CTL:
+ /* (Un)Mute headphone pin. */
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;
+ as[i].pins[15], HDA_CTL_IN, -1, 1);
+ if (ctl != NULL && ctl->mute) {
+ /* If pin has muter - use it. */
+ val = (res != 0) ? 0 : 1;
+ if (val != ctl->forcemute) {
+ ctl->forcemute = val;
hdac_audio_ctl_amp_set(ctl,
- HDA_AMP_MUTE_DEFAULT, ctl->left,
- ctl->right);
+ HDA_AMP_MUTE_DEFAULT,
+ HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
}
- }
- 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->muted = val;
- 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);
+ } else {
+ /* If there is no muter - disable pin output. */
+ w = hdac_widget_get(devinfo, as[i].pins[15]);
if (w != NULL && w->type ==
HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
- if (forcemute == 0)
+ if (res != 0)
val = w->wclass.pin.ctrl |
HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
else
@@ -1019,27 +895,34 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo)
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)
+ }
+ /* (Un)Mute other pins. */
+ for (j = 0; j < 15; j++) {
+ if (as[i].pins[j] <= 0)
+ continue;
+ ctl = hdac_audio_ctl_amp_get(devinfo,
+ as[i].pins[j], HDA_CTL_IN, -1, 1);
+ if (ctl != NULL && ctl->mute) {
+ /* If pin has muter - use it. */
+ val = (res != 0) ? 1 : 0;
+ if (val == ctl->forcemute)
continue;
- w->wclass.pin.ctrl = val;
- hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL(
- cad, w->nid, w->wclass.pin.ctrl), cad);
+ ctl->forcemute = val;
+ hdac_audio_ctl_amp_set(ctl,
+ HDA_AMP_MUTE_DEFAULT,
+ HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
+ continue;
}
- } else {
- /* HP out */
- w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
+ /* If there is no muter - disable pin output. */
+ w = hdac_widget_get(devinfo, as[i].pins[j]);
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 (res != 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,
@@ -1047,65 +930,98 @@ hdac_hp_switch_handler(struct hdac_devinfo *devinfo)
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);
- }
}
- break;
- case HDAC_HP_SWITCH_DEBUG:
- if (hdac_hp_switch[i].execsense != -1)
+ }
+}
+
+/*
+ * Callback for poll based jack detection.
+ */
+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);
+}
+
+/*
+ * Jack detection initializer.
+ */
+static void
+hdac_hp_switch_init(struct hdac_devinfo *devinfo)
+{
+ struct hdac_softc *sc = devinfo->codec->sc;
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w;
+ uint32_t id;
+ int i, enable = 0, poll = 0;
+ nid_t cad;
+
+ id = hdac_codec_id(devinfo->codec);
+ cad = devinfo->codec->cad;
+ for (i = 0; i < devinfo->function.audio.ascnt; i++) {
+ if (as[i].hpredir < 0)
+ continue;
+
+ w = hdac_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(sc->dev,
+ "No jack detection support at pin %d\n",
+ as[i].pins[15]);
+ continue;
+ }
+ enable = 1;
+ if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
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);
+ HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid,
+ HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
+ HDAC_UNSOLTAG_EVENT_HP), cad);
+ } else
+ poll = 1;
+ HDA_BOOTVERBOSE(
device_printf(sc->dev,
- "[%2d] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n",
- j + 1, w->nid, res);
+ "Enabling headphone/speaker "
+ "audio routing switching:\n");
+ device_printf(sc->dev, "\tas=%d sense nid=%d [%s]\n",
+ i, w->nid, (poll != 0) ? "POLL" : "UNSOL");
+ );
+ }
+ if (enable) {
+ hdac_hp_switch_handler(devinfo);
+ if (poll) {
+ callout_reset(&sc->poll_jack, 1,
+ hdac_jack_poll_callback, devinfo);
}
- break;
- default:
- break;
}
}
+/*
+ * Unsolicited messages handler.
+ */
static void
hdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
{
struct hdac_softc *sc;
struct hdac_devinfo *devinfo = NULL;
- device_t *devlist = NULL;
- int devcount, i;
+ int i;
if (codec == NULL || codec->sc == NULL)
return;
@@ -1113,22 +1029,16 @@ hdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
sc = codec->sc;
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Unsol Tag: 0x%08x\n", tag);
+ device_printf(sc->dev, "Unsol Tag: 0x%08x\n", tag);
);
- device_get_children(sc->dev, &devlist, &devcount);
- for (i = 0; devlist != NULL && i < devcount; i++) {
- devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
- if (devinfo != NULL && devinfo->node_type ==
- HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
- devinfo->codec != NULL &&
- devinfo->codec->cad == codec->cad) {
+ for (i = 0; i < codec->num_fgs; i++) {
+ if (codec->fgs[i].node_type ==
+ HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
+ devinfo = &codec->fgs[i];
break;
- } else
- devinfo = NULL;
+ }
}
- if (devlist != NULL)
- free(devlist, M_TEMP);
if (devinfo == NULL)
return;
@@ -1137,10 +1047,8 @@ hdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
case HDAC_UNSOLTAG_EVENT_HP:
hdac_hp_switch_handler(devinfo);
break;
- case HDAC_UNSOLTAG_EVENT_TEST:
- device_printf(sc->dev, "Unsol Test!\n");
- break;
default:
+ device_printf(sc->dev, "Unknown unsol tag: 0x%08x!\n", tag);
break;
}
}
@@ -1165,7 +1073,7 @@ hdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch)
#ifdef HDAC_INTR_EXTRA
HDA_BOOTVERBOSE(
if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE))
- device_printf(sc->dev,
+ device_printf(ch->pdevinfo->dev,
"PCMDIR_%s intr triggered beyond stream boundary:"
"%08x\n",
(ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res);
@@ -1201,6 +1109,7 @@ hdac_intr_handler(void *context)
uint8_t rirbsts;
struct hdac_rirb *rirb_base;
uint32_t trigger;
+ int i;
sc = (struct hdac_softc *)context;
@@ -1239,12 +1148,11 @@ hdac_intr_handler(void *context)
}
if (intsts & HDAC_INTSTS_SIS_MASK) {
- if ((intsts & (1 << sc->num_iss)) &&
- hdac_stream_intr(sc, &sc->play) != 0)
- trigger |= HDAC_TRIGGER_PLAY;
- if ((intsts & (1 << 0)) &&
- hdac_stream_intr(sc, &sc->rec) != 0)
- trigger |= HDAC_TRIGGER_REC;
+ for (i = 0; i < sc->num_chans; i++) {
+ if ((intsts & (1 << (sc->chans[i].off >> 5))) &&
+ hdac_stream_intr(sc, &sc->chans[i]) != 0)
+ trigger |= (1 << i);
+ }
/* XXX to be removed */
#ifdef HDAC_INTR_EXTRA
HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts &
@@ -1254,21 +1162,21 @@ hdac_intr_handler(void *context)
hdac_unlock(sc);
- if (trigger & HDAC_TRIGGER_PLAY)
- chn_intr(sc->play.c);
- if (trigger & HDAC_TRIGGER_REC)
- chn_intr(sc->rec.c);
+ for (i = 0; i < sc->num_chans; i++) {
+ if (trigger & (1 << i))
+ chn_intr(sc->chans[i].c);
+ }
if (trigger & HDAC_TRIGGER_UNSOL)
taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task);
}
/****************************************************************************
- * int hdac_reset(hdac_softc *)
+ * int hdac_reset(hdac_softc *, int)
*
* Reset the hdac to a quiescent and known state.
****************************************************************************/
static int
-hdac_reset(struct hdac_softc *sc)
+hdac_reset(struct hdac_softc *sc, int wakeup)
{
uint32_t gctl;
int count, i;
@@ -1312,6 +1220,11 @@ hdac_reset(struct hdac_softc *sc)
device_printf(sc->dev, "Unable to put hdac in reset\n");
return (ENXIO);
}
+
+ /* If wakeup is not requested - leave the controller in reset state. */
+ if (!wakeup)
+ return (0);
+
DELAY(100);
gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
@@ -1394,6 +1307,13 @@ hdac_get_capabilities(struct hdac_softc *sc)
return (ENXIO);
}
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, " CORB size: %d\n", sc->corb_size);
+ device_printf(sc->dev, " RIRB size: %d\n", sc->rirb_size);
+ device_printf(sc->dev, " Streams: ISS=%d OSS=%d BSS=%d\n",
+ sc->num_iss, sc->num_oss, sc->num_bss);
+ );
+
return (0);
}
@@ -1602,8 +1522,8 @@ hdac_irq_alloc(struct hdac_softc *sc)
__func__);
goto hdac_irq_alloc_fail;
}
- result = snd_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE,
- hdac_intr_handler, sc, &irq->irq_handle);
+ result = bus_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE | INTR_TYPE_AV,
+ NULL, hdac_intr_handler, sc, &irq->irq_handle);
if (result != 0) {
device_printf(sc->dev,
"%s: Unable to setup interrupt handler (%x)\n",
@@ -1732,18 +1652,16 @@ hdac_rirb_init(struct hdac_softc *sc)
sc->rirb_rp = 0;
HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
- if (sc->polling == 0) {
- /* Setup the interrupt threshold */
- HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
+ /* Setup the interrupt threshold */
+ HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
- /* Enable Overrun and response received reporting */
+ /* Enable Overrun and response received reporting */
#if 0
- HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
- HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
+ HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
+ HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
#else
- HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
+ HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
#endif
- }
#if 0
/*
@@ -1794,19 +1712,14 @@ hdac_rirb_start(struct hdac_softc *sc)
* Scan the bus for available codecs, starting with num.
****************************************************************************/
static void
-hdac_scan_codecs(struct hdac_softc *sc, int num)
+hdac_scan_codecs(struct hdac_softc *sc)
{
struct hdac_codec *codec;
int i;
uint16_t statests;
- if (num < 0)
- num = 0;
- if (num >= HDAC_CODEC_MAX)
- num = HDAC_CODEC_MAX - 1;
-
statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
- for (i = num; i < HDAC_CODEC_MAX; i++) {
+ for (i = 0; i < HDAC_CODEC_MAX; i++) {
if (HDAC_STATESTS_SDIWAKE(statests, i)) {
/* We have found a codec. */
codec = (struct hdac_codec *)malloc(sizeof(*codec),
@@ -1822,8 +1735,7 @@ hdac_scan_codecs(struct hdac_softc *sc, int num)
codec->sc = sc;
codec->cad = i;
sc->codecs[i] = codec;
- if (hdac_probe_codec(codec) != 0)
- break;
+ hdac_probe_codec(codec);
}
}
/* All codecs have been probed, now try to attach drivers to them */
@@ -1835,11 +1747,10 @@ hdac_scan_codecs(struct hdac_softc *sc, int num)
*
* Probe a the given codec_id for available function groups.
****************************************************************************/
-static int
+static void
hdac_probe_codec(struct hdac_codec *codec)
{
struct hdac_softc *sc = codec->sc;
- struct hdac_devinfo *devinfo;
uint32_t vendorid, revisionid, subnode;
int startnode;
int endnode;
@@ -1847,7 +1758,7 @@ hdac_probe_codec(struct hdac_codec *codec)
nid_t cad = codec->cad;
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Probing codec: %d\n", cad);
+ device_printf(sc->dev, "Probing codec %d...\n", cad);
);
vendorid = hdac_command(sc,
HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID),
@@ -1855,6 +1766,33 @@ hdac_probe_codec(struct hdac_codec *codec)
revisionid = hdac_command(sc,
HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID),
cad);
+ codec->vendor_id = HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
+ codec->device_id = HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
+ codec->revision_id = HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
+ codec->stepping_id = HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
+
+ if (vendorid == HDAC_INVALID && revisionid == HDAC_INVALID) {
+ device_printf(sc->dev, "Codec #%d is not responding!"
+ " Probing aborted.\n", cad);
+ return;
+ }
+
+ device_printf(sc->dev, "<HDA Codec #%d: %s>\n",
+ cad, hdac_codec_name(codec));
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "<HDA Codec ID: 0x%08x>\n",
+ hdac_codec_id(codec));
+ device_printf(sc->dev, " Vendor: 0x%04x\n",
+ codec->vendor_id);
+ device_printf(sc->dev, " Device: 0x%04x\n",
+ codec->device_id);
+ device_printf(sc->dev, " Revision: 0x%02x\n",
+ codec->revision_id);
+ device_printf(sc->dev, " Stepping: 0x%02x\n",
+ codec->stepping_id);
+ device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
+ sc->pci_subvendor);
+ );
subnode = hdac_command(sc,
HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT),
cad);
@@ -1862,75 +1800,73 @@ hdac_probe_codec(struct hdac_codec *codec)
endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: \tstartnode=%d endnode=%d\n",
+ device_printf(sc->dev, "\tstartnode=%d endnode=%d\n",
startnode, endnode);
);
- for (i = startnode; i < endnode; i++) {
- devinfo = hdac_probe_function(codec, i);
- if (devinfo != NULL) {
- /* XXX Ignore other FG. */
- devinfo->vendor_id =
- HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
- devinfo->device_id =
- HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
- devinfo->revision_id =
- HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
- devinfo->stepping_id =
- HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: \tFound AFG nid=%d "
- "[startnode=%d endnode=%d]\n",
- devinfo->nid, startnode, endnode);
- );
- return (1);
- }
+
+ codec->fgs = (struct hdac_devinfo *)malloc(sizeof(struct hdac_devinfo) *
+ (endnode - startnode), M_HDAC, M_NOWAIT | M_ZERO);
+ if (codec->fgs == NULL) {
+ device_printf(sc->dev, "%s: Unable to allocate functiom groups\n",
+ __func__);
+ return;
}
- HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: \tAFG not found\n");
- );
- return (0);
+ for (i = startnode; i < endnode; i++)
+ hdac_probe_function(codec, i);
+ return;
}
-static struct hdac_devinfo *
+/*
+ * Probe codec function and add it to the list.
+ */
+static void
hdac_probe_function(struct hdac_codec *codec, nid_t nid)
{
struct hdac_softc *sc = codec->sc;
- struct hdac_devinfo *devinfo;
+ struct hdac_devinfo *devinfo = &codec->fgs[codec->num_fgs];
uint32_t fctgrptype;
+ uint32_t res;
nid_t cad = codec->cad;
fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc,
HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad));
- /* XXX For now, ignore other FG. */
- if (fctgrptype != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
- return (NULL);
-
- devinfo = (struct hdac_devinfo *)malloc(sizeof(*devinfo), M_HDAC,
- M_NOWAIT | M_ZERO);
- if (devinfo == NULL) {
- device_printf(sc->dev, "%s: Unable to allocate ivar\n",
- __func__);
- return (NULL);
- }
-
devinfo->nid = nid;
devinfo->node_type = fctgrptype;
devinfo->codec = codec;
- hdac_add_child(sc, devinfo);
+ res = hdac_command(sc,
+ HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
- return (devinfo);
-}
+ devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
+ devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
+ devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
-static void
-hdac_add_child(struct hdac_softc *sc, struct hdac_devinfo *devinfo)
-{
- devinfo->dev = device_add_child(sc->dev, NULL, -1);
- device_set_ivars(devinfo->dev, (void *)devinfo);
- /* XXX - Print more information when booting verbose??? */
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "\tFound %s FG nid=%d startnode=%d endnode=%d total=%d\n",
+ (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) ? "audio":
+ (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM) ? "modem":
+ "unknown", nid, devinfo->startnode, devinfo->endnode,
+ devinfo->nodecnt);
+ );
+
+ if (devinfo->nodecnt > 0)
+ devinfo->widget = (struct hdac_widget *)malloc(
+ sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
+ M_NOWAIT | M_ZERO);
+ else
+ devinfo->widget = NULL;
+
+ if (devinfo->widget == NULL) {
+ device_printf(sc->dev, "unable to allocate widgets!\n");
+ devinfo->endnode = devinfo->startnode;
+ devinfo->nodecnt = 0;
+ return;
+ }
+
+ codec->num_fgs++;
}
static void
@@ -1983,9 +1919,9 @@ hdac_widget_connection_parse(struct hdac_widget *w)
cnid >= w->devinfo->endnode) {
HDA_BOOTVERBOSE(
device_printf(sc->dev,
- "%s: GHOST: nid=%d j=%d "
+ "GHOST: nid=%d j=%d "
"entnum=%d index=%d res=0x%08x\n",
- __func__, nid, j, entnum, i, res);
+ nid, j, entnum, i, res);
);
}
if (CONN_RANGE(res, entnum, j) == 0)
@@ -2003,11 +1939,12 @@ hdac_widget_connection_parse(struct hdac_widget *w)
while (addcnid <= cnid) {
if (w->nconns > max) {
device_printf(sc->dev,
- "%s: nid=%d: Adding %d: "
+ "Adding %d (nid=%d): "
"Max connection reached! max=%d\n",
- __func__, nid, addcnid, max + 1);
+ addcnid, nid, max + 1);
goto getconns_out;
}
+ w->connsenable[w->nconns] = 1;
w->conns[w->nconns++] = addcnid++;
}
prevcnid = cnid;
@@ -2015,33 +1952,112 @@ hdac_widget_connection_parse(struct hdac_widget *w)
}
getconns_out:
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: %s: nid=%d entries=%d found=%d\n",
- __func__, nid, ents, w->nconns);
- );
return;
}
static uint32_t
+hdac_widget_pin_patch(uint32_t config, const char *str)
+{
+ char buf[256];
+ char *key, *value, *rest, *bad;
+ int ival, i;
+
+ strlcpy(buf, str, sizeof(buf));
+ rest = buf;
+ while ((key = strsep(&rest, "=")) != NULL) {
+ value = strsep(&rest, " \t");
+ if (value == NULL)
+ break;
+ ival = strtol(value, &bad, 10);
+ if (strcmp(key, "seq") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK);
+ } else if (strcmp(key, "as") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK);
+ } else if (strcmp(key, "misc") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_MISC_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_MISC_MASK);
+ } else if (strcmp(key, "color") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_COLOR_MASK;
+ if (bad[0] == 0) {
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_COLOR_MASK);
+ };
+ for (i = 0; i < 16; i++) {
+ if (strcasecmp(HDA_COLORS[i], value) == 0) {
+ config |= (i << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT);
+ break;
+ }
+ }
+ } else if (strcmp(key, "ctype") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK);
+ } else if (strcmp(key, "device") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ if (bad[0] == 0) {
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_DEVICE_MASK);
+ continue;
+ };
+ for (i = 0; i < 16; i++) {
+ if (strcasecmp(HDA_DEVS[i], value) == 0) {
+ config |= (i << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT);
+ break;
+ }
+ }
+ } else if (strcmp(key, "loc") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_LOCATION_MASK;
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_LOCATION_MASK);
+ } else if (strcmp(key, "conn") == 0) {
+ config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
+ if (bad[0] == 0) {
+ config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) &
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
+ continue;
+ };
+ for (i = 0; i < 4; i++) {
+ if (strcasecmp(HDA_CONNS[i], value) == 0) {
+ config |= (i << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT);
+ break;
+ }
+ }
+ }
+ }
+ return (config);
+}
+
+static uint32_t
hdac_widget_pin_getconfig(struct hdac_widget *w)
{
struct hdac_softc *sc;
uint32_t config, orig, id;
nid_t cad, nid;
+ char buf[32];
+ const char *res = NULL, *patch = NULL;
sc = w->devinfo->codec->sc;
cad = w->devinfo->codec->cad;
nid = w->nid;
- id = hdac_codec_id(w->devinfo);
+ id = hdac_codec_id(w->devinfo->codec);
config = hdac_command(sc,
HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid),
cad);
orig = config;
- /*
- * XXX REWRITE!!!! Don't argue!
+ HDA_BOOTVERBOSE(
+ hdac_dump_pin_config(w, orig);
+ );
+
+ /* XXX: Old patches require complete review.
+ * Now they may create more problem then solve due to
+ * incorrect associations.
*/
if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) {
switch (nid) {
@@ -2063,14 +2079,6 @@ hdac_widget_pin_getconfig(struct hdac_widget *w)
* Super broken BIOS
*/
switch (nid) {
- case 20:
- break;
- case 21:
- break;
- case 22:
- break;
- case 23:
- break;
case 24: /* MIC1 */
config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
@@ -2091,12 +2099,6 @@ hdac_widget_pin_getconfig(struct hdac_widget *w)
config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
break;
- case 30:
- break;
- case 31:
- break;
- default:
- break;
}
} else if (id == HDA_CODEC_ALC883 &&
(sc->pci_subvendor == MSI_MS034A_SUBVENDOR ||
@@ -2114,8 +2116,6 @@ hdac_widget_pin_getconfig(struct hdac_widget *w)
config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
break;
- default:
- break;
}
} else if (id == HDA_CODEC_CXVENICE && sc->pci_subvendor ==
HP_V3000_SUBVENDOR) {
@@ -2136,8 +2136,6 @@ hdac_widget_pin_getconfig(struct hdac_widget *w)
config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
break;
- default:
- break;
}
} else if (id == HDA_CODEC_CXWAIKIKI && sc->pci_subvendor ==
HP_DV5000_SUBVENDOR) {
@@ -2147,8 +2145,6 @@ hdac_widget_pin_getconfig(struct hdac_widget *w)
config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
break;
- default:
- break;
}
} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
ASUS_W6F_SUBVENDOR) {
@@ -2175,8 +2171,6 @@ hdac_widget_pin_getconfig(struct hdac_widget *w)
config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
break;
- default:
- break;
}
} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
UNIWILL_9075_SUBVENDOR) {
@@ -2187,42 +2181,66 @@ hdac_widget_pin_getconfig(struct hdac_widget *w)
config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
break;
- default:
- break;
}
- } else if (id == HDA_CODEC_AD1986A &&
+ }
+
+ /* New patches */
+ if (id == HDA_CODEC_AD1986A &&
(sc->pci_subvendor == ASUS_M2NPVMX_SUBVENDOR ||
sc->pci_subvendor == ASUS_A8NVMCSM_SUBVENDOR)) {
switch (nid) {
- case 28: /* LINE */
- config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
- config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
+ case 28: /* 5.1 out => 2.0 out + 2 inputs */
+ patch = "device=Line-in as=8 seq=1";
break;
- case 29: /* MIC */
- config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
- config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
+ case 29:
+ patch = "device=Mic as=8 seq=2";
break;
- default:
+ case 31: /* Lot of inputs configured with as=15 and unusable */
+ patch = "as=8 seq=3";
+ break;
+ case 32:
+ patch = "as=8 seq=4";
+ break;
+ case 34:
+ patch = "as=8 seq=5";
+ break;
+ case 36:
+ patch = "as=8 seq=6";
+ break;
+ }
+ } else if (id == HDA_CODEC_ALC260 &&
+ HDA_DEV_MATCH(SONY_S5_SUBVENDOR, sc->pci_subvendor)) {
+ switch (nid) {
+ case 16:
+ patch = "seq=15 device=Headphones";
break;
}
} else if (id == HDA_CODEC_ALC268 &&
HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor)) {
switch (nid) {
case 28:
- config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
- HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
- config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
- HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
- break;
- default:
+ patch = "device=CD conn=fixed";
break;
}
}
+ if (patch != NULL)
+ config = hdac_widget_pin_patch(config, patch);
+
+ snprintf(buf, sizeof(buf), "cad%u.nid%u.config", cad, nid);
+ if (resource_string_value(device_get_name(sc->dev),
+ device_get_unit(sc->dev), buf, &res) == 0) {
+ if (strncmp(res, "0x", 2) == 0) {
+ config = strtol(res + 2, NULL, 16);
+ } else {
+ config = hdac_widget_pin_patch(config, res);
+ }
+ }
+
HDA_BOOTVERBOSE(
if (config != orig)
device_printf(sc->dev,
- "HDA_DEBUG: Pin config nid=%u 0x%08x -> 0x%08x\n",
+ "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
nid, orig, config);
);
@@ -2239,7 +2257,7 @@ hdac_widget_pin_getcaps(struct hdac_widget *w)
sc = w->devinfo->codec->sc;
cad = w->devinfo->codec->cad;
nid = w->nid;
- id = hdac_codec_id(w->devinfo);
+ id = hdac_codec_id(w->devinfo->codec);
caps = hdac_command(sc,
HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad);
@@ -2248,7 +2266,7 @@ hdac_widget_pin_getcaps(struct hdac_widget *w)
HDA_BOOTVERBOSE(
if (caps != orig)
device_printf(sc->dev,
- "HDA_DEBUG: Pin caps nid=%u 0x%08x -> 0x%08x\n",
+ "Patching pin caps nid=%u 0x%08x -> 0x%08x\n",
nid, orig, caps);
);
@@ -2260,7 +2278,7 @@ hdac_widget_pin_parse(struct hdac_widget *w)
{
struct hdac_softc *sc = w->devinfo->codec->sc;
uint32_t config, pincap;
- char *devstr, *connstr;
+ const char *devstr, *connstr;
nid_t cad = w->devinfo->codec->cad;
nid_t nid = w->nid;
@@ -2271,18 +2289,8 @@ hdac_widget_pin_parse(struct hdac_widget *w)
w->wclass.pin.cap = pincap;
w->wclass.pin.ctrl = hdac_command(sc,
- HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad) &
- ~(HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
- HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
- HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
+ HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad);
- if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
- w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
- if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
- w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
- if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
- w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) {
w->param.eapdbtl = hdac_command(sc,
HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad);
@@ -2291,74 +2299,11 @@ hdac_widget_pin_parse(struct hdac_widget *w)
} else
w->param.eapdbtl = HDAC_INVALID;
- switch (config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
- case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
- devstr = "line out";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
- devstr = "speaker";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
- devstr = "headphones out";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
- devstr = "CD";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
- devstr = "SPDIF out";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
- devstr = "digital (other) out";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE:
- devstr = "modem, line side";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET:
- devstr = "modem, handset side";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
- devstr = "line in";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
- devstr = "AUX";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
- devstr = "Mic in";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY:
- devstr = "telephony";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
- devstr = "SPDIF in";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
- devstr = "digital (other) in";
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER:
- devstr = "other";
- break;
- default:
- devstr = "unknown";
- break;
- }
+ devstr = HDA_DEVS[(config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >>
+ HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT];
- switch (config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) {
- case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK:
- connstr = "jack";
- break;
- case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE:
- connstr = "none";
- break;
- case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED:
- connstr = "fixed";
- break;
- case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH:
- connstr = "jack / fixed";
- break;
- default:
- connstr = "unknown";
- break;
- }
+ connstr = HDA_CONNS[(config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >>
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT];
strlcat(w->name, ": ", sizeof(w->name));
strlcat(w->name, devstr, sizeof(w->name));
@@ -2367,6 +2312,64 @@ hdac_widget_pin_parse(struct hdac_widget *w)
strlcat(w->name, ")", sizeof(w->name));
}
+static uint32_t
+hdac_widget_getcaps(struct hdac_widget *w, int *waspin)
+{
+ struct hdac_softc *sc;
+ uint32_t caps, orig, id;
+ nid_t cad, nid, beeper = -1;
+
+ sc = w->devinfo->codec->sc;
+ cad = w->devinfo->codec->cad;
+ nid = w->nid;
+ id = hdac_codec_id(w->devinfo->codec);
+
+ caps = hdac_command(sc,
+ HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
+ cad);
+ orig = caps;
+
+ /* On some codecs beeper is an input pin, but it is not recordable
+ alone. Also most of BIOSes does not declare beeper pin.
+ Change beeper pin node type to beeper to help parser. */
+ *waspin = 0;
+ switch (id) {
+ case HDA_CODEC_AD1988:
+ case HDA_CODEC_AD1988B:
+ beeper = 26;
+ break;
+ case HDA_CODEC_ALC260:
+ beeper = 23;
+ break;
+ case HDA_CODEC_ALC262:
+ case HDA_CODEC_ALC268:
+ case HDA_CODEC_ALC880:
+ case HDA_CODEC_ALC882:
+ case HDA_CODEC_ALC883:
+ case HDA_CODEC_ALC885:
+ case HDA_CODEC_ALC888:
+ case HDA_CODEC_ALC889:
+ beeper = 29;
+ break;
+ }
+ if (nid == beeper) {
+ caps &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
+ caps |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
+ *waspin = 1;
+ }
+
+ HDA_BOOTVERBOSE(
+ if (caps != orig) {
+ device_printf(sc->dev,
+ "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
+ nid, orig, caps);
+ }
+ );
+
+ return (caps);
+}
+
static void
hdac_widget_parse(struct hdac_widget *w)
{
@@ -2376,9 +2379,8 @@ hdac_widget_parse(struct hdac_widget *w)
nid_t cad = w->devinfo->codec->cad;
nid_t nid = w->nid;
- wcap = hdac_command(sc,
- HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
- cad);
+ wcap = hdac_widget_getcaps(w, &w->waspin);
+
w->param.widget_cap = wcap;
w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap);
@@ -2417,13 +2419,6 @@ hdac_widget_parse(struct hdac_widget *w)
strlcpy(w->name, typestr, sizeof(w->name));
- if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(wcap)) {
- hdac_command(sc,
- HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0),
- cad);
- DELAY(1000);
- }
-
hdac_widget_connection_parse(w);
if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) {
@@ -2515,38 +2510,42 @@ hda_poll_channel(struct hdac_chan *ch)
return (1);
}
-#define hda_chan_active(sc) (((sc)->play.flags | (sc)->rec.flags) & \
- HDAC_CHN_RUNNING)
-
static void
hda_poll_callback(void *arg)
{
struct hdac_softc *sc = arg;
uint32_t trigger;
+ int i, active = 0;
if (sc == NULL)
return;
hdac_lock(sc);
- if (sc->polling == 0 || hda_chan_active(sc) == 0) {
+ if (sc->polling == 0) {
hdac_unlock(sc);
return;
}
trigger = 0;
- trigger |= (hda_poll_channel(&sc->play) != 0) ? HDAC_TRIGGER_PLAY : 0;
- trigger |= (hda_poll_channel(&sc->rec)) != 0 ? HDAC_TRIGGER_REC : 0;
+ for (i = 0; i < sc->num_chans; i++) {
+ if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
+ continue;
+ active = 1;
+ if (hda_poll_channel(&sc->chans[i]))
+ trigger |= (1 << i);
+ }
/* XXX */
- callout_reset(&sc->poll_hda, 1/*sc->poll_ticks*/,
- hda_poll_callback, sc);
+ if (active)
+ callout_reset(&sc->poll_hda, sc->poll_ticks,
+ hda_poll_callback, sc);
hdac_unlock(sc);
- if (trigger & HDAC_TRIGGER_PLAY)
- chn_intr(sc->play.c);
- if (trigger & HDAC_TRIGGER_REC)
- chn_intr(sc->rec.c);
+ for (i = 0; i < sc->num_chans; i++) {
+ if (trigger & (1 << i))
+ chn_intr(sc->chans[i].c);
+ }
}
static int
@@ -2635,6 +2634,45 @@ hdac_poll_callback(void *arg)
}
static void
+hdac_poll_reinit(struct hdac_softc *sc)
+{
+ int i, pollticks, min = 1000000;
+ struct hdac_chan *ch;
+
+ for (i = 0; i < sc->num_chans; i++) {
+ if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
+ continue;
+ ch = &sc->chans[i];
+ pollticks = ((uint64_t)hz * ch->blksz) /
+ ((uint64_t)sndbuf_getbps(ch->b) *
+ sndbuf_getspd(ch->b));
+ pollticks >>= 1;
+ if (pollticks > hz)
+ pollticks = hz;
+ if (pollticks < 1) {
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "%s: pollticks=%d < 1 !\n",
+ __func__, pollticks);
+ );
+ pollticks = 1;
+ }
+ if (min > pollticks)
+ min = pollticks;
+ }
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "%s: pollticks %d -> %d\n",
+ __func__, sc->poll_ticks, min);
+ );
+ sc->poll_ticks = min;
+ if (min == 1000000)
+ callout_stop(&sc->poll_hda);
+ else
+ callout_reset(&sc->poll_hda, 1, hda_poll_callback, sc);
+}
+
+static void
hdac_stream_stop(struct hdac_chan *ch)
{
struct hdac_softc *sc = ch->devinfo->codec->sc;
@@ -2647,48 +2685,12 @@ hdac_stream_stop(struct hdac_chan *ch)
ch->flags &= ~HDAC_CHN_RUNNING;
- if (sc->polling != 0) {
- int pollticks;
+ if (sc->polling != 0)
+ hdac_poll_reinit(sc);
- if (hda_chan_active(sc) == 0) {
- callout_stop(&sc->poll_hda);
- sc->poll_ticks = 1;
- } else {
- if (sc->play.flags & HDAC_CHN_RUNNING)
- ch = &sc->play;
- else
- ch = &sc->rec;
- pollticks = ((uint64_t)hz * ch->blksz) /
- ((uint64_t)sndbuf_getbps(ch->b) *
- sndbuf_getspd(ch->b));
- pollticks >>= 2;
- if (pollticks > hz)
- pollticks = hz;
- if (pollticks < 1) {
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "%s: pollticks=%d < 1 !\n",
- __func__, pollticks);
- );
- pollticks = 1;
- }
- if (pollticks > sc->poll_ticks) {
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "%s: pollticks %d -> %d\n",
- __func__, sc->poll_ticks,
- pollticks);
- );
- sc->poll_ticks = pollticks;
- callout_reset(&sc->poll_hda, 1,
- hda_poll_callback, sc);
- }
- }
- } else {
- ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
- ctl &= ~(1 << (ch->off >> 5));
- HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
- }
+ ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
+ ctl &= ~(1 << (ch->off >> 5));
+ HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
}
static void
@@ -2697,52 +2699,19 @@ hdac_stream_start(struct hdac_chan *ch)
struct hdac_softc *sc = ch->devinfo->codec->sc;
uint32_t ctl;
- if (sc->polling != 0) {
- int pollticks;
+ ch->flags |= HDAC_CHN_RUNNING;
- pollticks = ((uint64_t)hz * ch->blksz) /
- ((uint64_t)sndbuf_getbps(ch->b) * sndbuf_getspd(ch->b));
- pollticks >>= 2;
- if (pollticks > hz)
- pollticks = hz;
- if (pollticks < 1) {
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "%s: pollticks=%d < 1 !\n",
- __func__, pollticks);
- );
- pollticks = 1;
- }
- if (hda_chan_active(sc) == 0 || pollticks < sc->poll_ticks) {
- HDA_BOOTVERBOSE(
- if (hda_chan_active(sc) == 0) {
- device_printf(sc->dev,
- "%s: pollticks=%d\n",
- __func__, pollticks);
- } else {
- device_printf(sc->dev,
- "%s: pollticks %d -> %d\n",
- __func__, sc->poll_ticks,
- pollticks);
- }
- );
- sc->poll_ticks = pollticks;
- callout_reset(&sc->poll_hda, 1, hda_poll_callback,
- sc);
- }
- ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
- ctl |= HDAC_SDCTL_RUN;
- } else {
- ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
- ctl |= 1 << (ch->off >> 5);
- HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
- ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
- ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
- HDAC_SDCTL_RUN;
- }
- HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
+ if (sc->polling != 0)
+ hdac_poll_reinit(sc);
- ch->flags |= HDAC_CHN_RUNNING;
+ ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
+ ctl |= 1 << (ch->off >> 5);
+ HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
+
+ ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
+ ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
+ HDAC_SDCTL_RUN;
+ HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
}
static void
@@ -2802,19 +2771,14 @@ hdac_bdl_setup(struct hdac_chan *ch)
addr = (uint64_t)sndbuf_getbufaddr(ch->b);
bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr;
- if (sc->polling != 0) {
- blksz = ch->blksz * ch->blkcnt;
- blkcnt = 1;
- } else {
- blksz = ch->blksz;
- blkcnt = ch->blkcnt;
- }
+ blksz = ch->blksz;
+ blkcnt = ch->blkcnt;
for (i = 0; i < blkcnt; i++, bdle++) {
bdle->addrl = (uint32_t)addr;
bdle->addrh = (uint32_t)(addr >> 32);
bdle->len = blksz;
- bdle->ioc = 1 ^ sc->polling;
+ bdle->ioc = 1;
addr += blksz;
}
@@ -2881,32 +2845,36 @@ hdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute,
nid_t nid, cad;
int lmute, rmute;
- if (ctl == NULL || ctl->widget == NULL ||
- ctl->widget->devinfo == NULL ||
- ctl->widget->devinfo->codec == NULL ||
- ctl->widget->devinfo->codec->sc == NULL)
- return;
-
sc = ctl->widget->devinfo->codec->sc;
cad = ctl->widget->devinfo->codec->cad;
nid = ctl->widget->nid;
- if (mute == HDA_AMP_MUTE_DEFAULT) {
+ /* Save new values if valid. */
+ if (mute != HDA_AMP_MUTE_DEFAULT)
+ ctl->muted = mute;
+ if (left != HDA_AMP_VOL_DEFAULT)
+ ctl->left = left;
+ if (right != HDA_AMP_VOL_DEFAULT)
+ ctl->right = right;
+ /* Prepare effective values */
+ if (ctl->forcemute) {
+ lmute = 1;
+ rmute = 1;
+ left = 0;
+ right = 0;
+ } else {
lmute = HDA_AMP_LEFT_MUTED(ctl->muted);
rmute = HDA_AMP_RIGHT_MUTED(ctl->muted);
- } else {
- lmute = HDA_AMP_LEFT_MUTED(mute);
- rmute = HDA_AMP_RIGHT_MUTED(mute);
+ left = ctl->left;
+ right = ctl->right;
}
-
+ /* Apply effective values */
if (ctl->dir & HDA_CTL_OUT)
hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
lmute, rmute, left, right, 0);
if (ctl->dir & HDA_CTL_IN)
- hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
+ hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
lmute, rmute, left, right, 1);
- ctl->left = left;
- ctl->right = right;
}
static void
@@ -3074,20 +3042,26 @@ static void *
hdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
struct pcm_channel *c, int dir)
{
- struct hdac_devinfo *devinfo = data;
+ struct hdac_pcm_devinfo *pdevinfo = data;
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_softc *sc = devinfo->codec->sc;
struct hdac_chan *ch;
+ int i, ord = 0, chid;
hdac_lock(sc);
+
+ chid = (dir == PCMDIR_PLAY)?pdevinfo->play:pdevinfo->rec;
+ ch = &sc->chans[chid];
+ for (i = 0; i < sc->num_chans && i < chid; i++) {
+ if (ch->dir == sc->chans[i].dir)
+ ord++;
+ }
if (dir == PCMDIR_PLAY) {
- ch = &sc->play;
- ch->off = (sc->num_iss + devinfo->function.audio.playcnt) << 5;
- devinfo->function.audio.playcnt++;
+ ch->off = (sc->num_iss + ord) << 5;
} else {
- ch = &sc->rec;
- ch->off = devinfo->function.audio.reccnt << 5;
- devinfo->function.audio.reccnt++;
+ ch->off = ord << 5;
}
+
if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) {
ch->caps.minspeed = ch->caps.maxspeed = 48000;
ch->pcmrates[0] = 48000;
@@ -3102,9 +3076,8 @@ hdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
ch->dir = dir;
ch->b = b;
ch->c = c;
- ch->devinfo = devinfo;
- ch->blksz = sc->chan_size / sc->chan_blkcnt;
- ch->blkcnt = sc->chan_blkcnt;
+ ch->blksz = pdevinfo->chan_size / pdevinfo->chan_blkcnt;
+ ch->blkcnt = pdevinfo->chan_blkcnt;
hdac_unlock(sc);
if (hdac_bdl_alloc(ch) != 0) {
@@ -3114,7 +3087,7 @@ hdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
if (sndbuf_alloc(ch->b, sc->chan_dmat,
(sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0,
- sc->chan_size) != 0)
+ pdevinfo->chan_size) != 0)
return (NULL);
return (ch);
@@ -3163,11 +3136,18 @@ static void
hdac_stream_setup(struct hdac_chan *ch)
{
struct hdac_softc *sc = ch->devinfo->codec->sc;
+ struct hdac_audio_as *as = &ch->devinfo->function.audio.as[ch->as];
struct hdac_widget *w;
- int i, chn, totalchn;
+ int i, chn, totalchn, c;
nid_t cad = ch->devinfo->codec->cad;
- uint16_t fmt;
+ uint16_t fmt, dfmt;
+ HDA_BOOTVERBOSE(
+ device_printf(ch->pdevinfo->dev,
+ "PCMDIR_%s: Stream setup fmt=%08x speed=%d\n",
+ (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
+ ch->fmt, ch->spd);
+ );
fmt = 0;
if (ch->fmt & AFMT_S16_LE)
fmt |= ch->bit16 << 4;
@@ -3185,37 +3165,53 @@ hdac_stream_setup(struct hdac_chan *ch)
}
}
- if (ch->fmt & AFMT_STEREO) {
+ if (ch->fmt & (AFMT_STEREO | AFMT_AC3)) {
fmt |= 1;
totalchn = 2;
} else
totalchn = 1;
HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt);
+
+ dfmt = HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN;
+ if (ch->fmt & AFMT_AC3)
+ dfmt |= HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO;
chn = 0;
for (i = 0; ch->io[i] != -1; i++) {
w = hdac_widget_get(ch->devinfo, ch->io[i]);
if (w == NULL)
continue;
+
+ if (as->hpredir >= 0 && i == as->pincnt)
+ chn = 0;
HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: PCMDIR_%s: Stream setup nid=%d "
- "fmt=0x%08x\n",
+ device_printf(ch->pdevinfo->dev,
+ "PCMDIR_%s: Stream setup nid=%d: "
+ "fmt=0x%04x, dfmt=0x%04x\n",
(ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
- ch->io[i], fmt);
+ ch->io[i], fmt, dfmt);
);
hdac_command(sc,
HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad);
- if (ch->dir == PCMDIR_REC)
+ if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
hdac_command(sc,
- HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
- (chn < totalchn) ? ((ch->sid << 4) | chn) : 0),
+ HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], dfmt),
cad);
- else
- hdac_command(sc,
- HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
- ch->sid << 4), cad);
+ }
+ /* If HP redirection is enabled, but failed to use same
+ DAC make last DAC one to duplicate first one. */
+ if (as->hpredir >= 0 && i == as->pincnt) {
+ c = (ch->sid << 4);
+ } else if (chn >= totalchn) {
+ /* This is until OSS will support multichannel.
+ Should be: c = 0; to disable unused DAC */
+ c = (ch->sid << 4);
+ }else {
+ c = (ch->sid << 4) | chn;
+ }
+ hdac_command(sc,
+ HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], c), cad);
chn +=
HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap) ?
2 : 1;
@@ -3265,9 +3261,8 @@ static int
hdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz)
{
struct hdac_chan *ch = data;
- struct hdac_softc *sc = ch->devinfo->codec->sc;
- hdac_channel_setfragments(obj, data, blksz, sc->chan_blkcnt);
+ hdac_channel_setfragments(obj, data, blksz, ch->pdevinfo->chan_blkcnt);
return (ch->blksz);
}
@@ -3276,12 +3271,21 @@ static void
hdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch)
{
struct hdac_devinfo *devinfo = ch->devinfo;
+ struct hdac_widget *w;
nid_t cad = devinfo->codec->cad;
int i;
hdac_stream_stop(ch);
for (i = 0; ch->io[i] != -1; i++) {
+ w = hdac_widget_get(ch->devinfo, ch->io[i]);
+ if (w == NULL)
+ continue;
+ if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
+ hdac_command(sc,
+ HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], 0),
+ cad);
+ }
hdac_command(sc,
HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
0), cad);
@@ -3371,191 +3375,124 @@ 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)
{
- struct hdac_devinfo *devinfo = mix_getdevinfo(m);
+ struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_softc *sc = devinfo->codec->sc;
struct hdac_widget *w, *cw;
struct hdac_audio_ctl *ctl;
uint32_t mask, recmask, id;
int i, j, softpcmvol;
- nid_t cad;
hdac_lock(sc);
+ /* Make sure that in case of soft volume it won't stay muted. */
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+ pdevinfo->left[i] = 100;
+ pdevinfo->right[i] = 100;
+ }
+
mask = 0;
recmask = 0;
+ id = hdac_codec_id(devinfo->codec);
- 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))
- 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)
- 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,
- HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid,
- HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
- HDAC_UNSOLTAG_EVENT_HP), cad);
- else
- continue;
- hdac_hp_switch_handler(devinfo);
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: Enabling headphone/speaker "
- "audio routing switching:\n");
- device_printf(sc->dev,
- "HDA_DEBUG: \tindex=%d nid=%d "
- "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,
- sc->pci_subvendor) &&
- hdac_eapd_switch[i].id == id))
- continue;
- w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
- if (w == NULL || w->enable == 0)
- break;
- if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
- w->param.eapdbtl == HDAC_INVALID)
- break;
- mask |= SOUND_MASK_OGAIN;
- break;
- }
-
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
- continue;
- mask |= w->ctlflags;
- if (!(w->pflags & HDA_ADC_RECSEL))
- continue;
- for (j = 0; j < w->nconns; j++) {
- cw = hdac_widget_get(devinfo, w->conns[j]);
- if (cw == NULL || cw->enable == 0)
+ /* Declate EAPD as ogain control. */
+ if (pdevinfo->play >= 0) {
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
+ w->param.eapdbtl == HDAC_INVALID ||
+ w->bindas != sc->chans[pdevinfo->play].as)
continue;
- recmask |= cw->ctlflags;
+ mask |= SOUND_MASK_OGAIN;
+ break;
}
}
- if (!(mask & SOUND_MASK_PCM)) {
- softpcmvol = 1;
- mask |= SOUND_MASK_PCM;
- } else
- softpcmvol = (devinfo->function.audio.quirks &
- HDA_QUIRK_SOFTPCMVOL) ? 1 : 0;
-
+ /* Declare volume controls assigned to this association. */
i = 0;
ctl = NULL;
while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->widget == NULL || ctl->enable == 0)
- continue;
- if (!(ctl->ossmask & SOUND_MASK_PCM))
+ if (ctl->enable == 0)
continue;
- if (ctl->step > 0)
- break;
- }
-
- if (softpcmvol == 1 || ctl == NULL) {
- pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: %s Soft PCM volume\n",
- (softpcmvol == 1) ?
- "Forcing" : "Enabling");
- );
- i = 0;
- /*
- * XXX Temporary quirk for STAC9220, until the parser
- * become smarter.
- */
- if (id == HDA_CODEC_STAC9220) {
- mask |= SOUND_MASK_VOLUME;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
- NULL) {
- if (ctl->widget == NULL || ctl->enable == 0)
+ if ((pdevinfo->play >= 0 &&
+ ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
+ (pdevinfo->rec >= 0 &&
+ ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
+ (ctl->widget->bindas == -2 && pdevinfo->index == 0))
+ mask |= ctl->ossmask;
+ }
+
+ /* Declare record sources available to this association. */
+ if (pdevinfo->rec >= 0) {
+ struct hdac_chan *ch = &sc->chans[pdevinfo->rec];
+ for (i = 0; ch->io[i] != -1; i++) {
+ w = hdac_widget_get(devinfo, ch->io[i]);
+ if (w == NULL || w->enable == 0)
+ continue;
+ for (j = 0; j < w->nconns; j++) {
+ if (w->connsenable[j] == 0)
continue;
- if (ctl->widget->nid == 11 && ctl->index == 0) {
- ctl->ossmask = SOUND_MASK_VOLUME;
- ctl->ossval = 100 | (100 << 8);
- } else
- ctl->ossmask &= ~SOUND_MASK_VOLUME;
- }
- } else if (id == HDA_CODEC_STAC9221) {
- mask |= SOUND_MASK_VOLUME;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
- NULL) {
- if (ctl->widget == NULL)
+ cw = hdac_widget_get(devinfo, w->conns[j]);
+ if (cw == NULL || cw->enable == 0)
continue;
- if (ctl->widget->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT &&
- ctl->index == 0 && (ctl->widget->nid == 2 ||
- ctl->widget->enable != 0)) {
- ctl->enable = 1;
- ctl->ossmask = SOUND_MASK_VOLUME;
- ctl->ossval = 100 | (100 << 8);
- } else if (ctl->enable == 0)
+ if (cw->bindas != sc->chans[pdevinfo->rec].as &&
+ cw->bindas != -2)
continue;
- else
- ctl->ossmask &= ~SOUND_MASK_VOLUME;
+ recmask |= cw->ossmask;
}
+ }
+ }
+
+ /* Declare soft PCM and master volume if needed. */
+ if (pdevinfo->play >= 0) {
+ ctl = NULL;
+ if ((mask & SOUND_MASK_PCM) == 0 ||
+ (devinfo->function.audio.quirks & HDA_QUIRK_SOFTPCMVOL)) {
+ softpcmvol = 1;
+ mask |= SOUND_MASK_PCM;
} else {
- mix_setparentchild(m, SOUND_MIXER_VOLUME,
- SOUND_MASK_PCM);
- if (!(mask & SOUND_MASK_VOLUME))
- mix_setrealdev(m, SOUND_MIXER_VOLUME,
- SOUND_MIXER_NONE);
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
- NULL) {
- if (ctl->widget == NULL || ctl->enable == 0)
+ softpcmvol = 0;
+ i = 0;
+ while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
+ if (ctl->enable == 0)
+ continue;
+ if (ctl->widget->bindas != sc->chans[pdevinfo->play].as &&
+ (ctl->widget->bindas != -2 || pdevinfo->index != 0))
continue;
- if (!HDA_FLAG_MATCH(ctl->ossmask,
- SOUND_MASK_VOLUME | SOUND_MASK_PCM))
+ if (!(ctl->ossmask & SOUND_MASK_PCM))
continue;
- if (!(ctl->mute == 1 && ctl->step == 0))
- ctl->enable = 0;
+ if (ctl->step > 0)
+ break;
}
}
+
+ if (softpcmvol == 1 || ctl == NULL) {
+ pcm_setflags(pdevinfo->dev, pcm_getflags(pdevinfo->dev) | SD_F_SOFTPCMVOL);
+ HDA_BOOTVERBOSE(
+ device_printf(pdevinfo->dev,
+ "%s Soft PCM volume\n",
+ (softpcmvol == 1) ? "Forcing" : "Enabling");
+ );
+ }
+
+ if ((mask & SOUND_MASK_VOLUME) == 0) {
+ mask |= SOUND_MASK_VOLUME;
+ mix_setparentchild(m, SOUND_MIXER_VOLUME,
+ SOUND_MASK_PCM);
+ mix_setrealdev(m, SOUND_MIXER_VOLUME,
+ SOUND_MIXER_NONE);
+ HDA_BOOTVERBOSE(
+ device_printf(pdevinfo->dev,
+ "Forcing master volume with PCM\n");
+ );
+ }
}
- recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
- SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_IGAIN |
- SOUND_MASK_OGAIN);
recmask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
mask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
@@ -3571,36 +3508,34 @@ static int
hdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
unsigned left, unsigned right)
{
- struct hdac_devinfo *devinfo = mix_getdevinfo(m);
+ struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_softc *sc = devinfo->codec->sc;
struct hdac_widget *w;
struct hdac_audio_ctl *ctl;
- uint32_t id, mute;
- int lvol, rvol, mlvol, mrvol;
- int i = 0;
+ uint32_t mute;
+ int lvol, rvol;
+ int i, j;
hdac_lock(sc);
+ /* Save new values. */
+ pdevinfo->left[dev] = left;
+ pdevinfo->right[dev] = right;
+
+ /* 'ogain' is the special case implemented with EAPD. */
if (dev == SOUND_MIXER_OGAIN) {
uint32_t orig;
- /*if (left != right || !(left == 0 || left == 1)) {
- hdac_unlock(sc);
- return (-1);
- }*/
- id = hdac_codec_id(devinfo);
- for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
- if (HDA_DEV_MATCH(hdac_eapd_switch[i].model,
- sc->pci_subvendor) &&
- hdac_eapd_switch[i].id == id)
- break;
- }
- if (i >= HDAC_EAPD_SWITCH_LEN) {
- hdac_unlock(sc);
- return (-1);
+ w = NULL;
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
+ w->param.eapdbtl == HDAC_INVALID)
+ continue;
+ break;
}
- w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
- if (w == NULL ||
- w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
- w->param.eapdbtl == HDAC_INVALID) {
+ if (i >= devinfo->endnode) {
hdac_unlock(sc);
return (-1);
}
@@ -3612,8 +3547,6 @@ hdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
if (orig != w->param.eapdbtl) {
uint32_t val;
- if (hdac_eapd_switch[i].hp_switch != 0)
- hdac_hp_switch_handler(devinfo);
val = w->param.eapdbtl;
if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV)
val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
@@ -3624,51 +3557,32 @@ hdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
hdac_unlock(sc);
return (left | (left << 8));
}
- if (dev == SOUND_MIXER_VOLUME)
- devinfo->function.audio.mvol = left | (right << 8);
-
- mlvol = devinfo->function.audio.mvol & 0x7f;
- mrvol = (devinfo->function.audio.mvol >> 8) & 0x7f;
- lvol = 0;
- rvol = 0;
+ /* Recalculate all controls related to this OSS device. */
i = 0;
while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->widget == NULL || ctl->enable == 0 ||
+ if (ctl->enable == 0 ||
!(ctl->ossmask & (1 << dev)))
continue;
- switch (dev) {
- case SOUND_MIXER_VOLUME:
- lvol = ((ctl->ossval & 0x7f) * left) / 100;
- lvol = (lvol * ctl->step) / 100;
- rvol = (((ctl->ossval >> 8) & 0x7f) * right) / 100;
- rvol = (rvol * ctl->step) / 100;
- break;
- default:
- if (ctl->ossmask & SOUND_MASK_VOLUME) {
- lvol = (left * mlvol) / 100;
- lvol = (lvol * ctl->step) / 100;
- rvol = (right * mrvol) / 100;
- rvol = (rvol * ctl->step) / 100;
- } else {
- lvol = (left * ctl->step) / 100;
- rvol = (right * ctl->step) / 100;
+ if (!((pdevinfo->play >= 0 &&
+ ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
+ (pdevinfo->rec >= 0 &&
+ ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
+ ctl->widget->bindas == -2))
+ continue;
+
+ lvol = 100;
+ rvol = 100;
+ for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
+ if (ctl->ossmask & (1 << j)) {
+ lvol = lvol * pdevinfo->left[j] / 100;
+ rvol = rvol * pdevinfo->right[j] / 100;
}
- ctl->ossval = left | (right << 8);
- break;
- }
- mute = 0;
- if (ctl->step < 1) {
- mute |= (left == 0) ? HDA_AMP_MUTE_LEFT :
- (ctl->muted & HDA_AMP_MUTE_LEFT);
- mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT :
- (ctl->muted & HDA_AMP_MUTE_RIGHT);
- } else {
- mute |= (lvol == 0) ? HDA_AMP_MUTE_LEFT :
- (ctl->muted & HDA_AMP_MUTE_LEFT);
- mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT :
- (ctl->muted & HDA_AMP_MUTE_RIGHT);
}
+ mute = (left == 0) ? HDA_AMP_MUTE_LEFT : 0;
+ mute |= (right == 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);
}
hdac_unlock(sc);
@@ -3676,54 +3590,108 @@ hdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
return (left | (right << 8));
}
-static int
-hdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
+/*
+ * Commutate specified record source.
+ */
+static uint32_t
+hdac_audio_ctl_recsel_comm(struct hdac_pcm_devinfo *pdevinfo, uint32_t src, nid_t nid, int depth)
{
- struct hdac_devinfo *devinfo = mix_getdevinfo(m);
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_widget *w, *cw;
- struct hdac_softc *sc = devinfo->codec->sc;
- uint32_t ret = src, target;
- int i, j;
+ struct hdac_audio_ctl *ctl;
+ char buf[64];
+ int i, muted;
+ uint32_t res = 0;
- target = 0;
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (src & (1 << i)) {
- target = 1 << i;
+ if (depth > HDA_PARSE_MAXDEPTH)
+ return (0);
+
+ w = hdac_widget_get(devinfo, nid);
+ if (w == NULL || w->enable == 0)
+ return (0);
+
+ for (i = 0; i < w->nconns; i++) {
+ if (w->connsenable[i] == 0)
+ continue;
+ cw = hdac_widget_get(devinfo, w->conns[i]);
+ if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
+ continue;
+ /* Call recursively to trace signal to it's source if needed. */
+ if ((src & cw->ossmask) != 0) {
+ if (cw->ossdev < 0) {
+ res |= hdac_audio_ctl_recsel_comm(pdevinfo, src,
+ w->conns[i], depth + 1);
+ } else {
+ res |= cw->ossmask;
+ }
+ }
+ /* We have two special cases: mixers and others (selectors). */
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) {
+ ctl = hdac_audio_ctl_amp_get(devinfo,
+ w->nid, HDA_CTL_IN, i, 1);
+ if (ctl == NULL)
+ continue;
+ /* If we have input control on this node mute them
+ * according to requested sources. */
+ muted = (src & cw->ossmask) ? 0 : 1;
+ if (muted != ctl->forcemute) {
+ ctl->forcemute = muted;
+ hdac_audio_ctl_amp_set(ctl,
+ HDA_AMP_MUTE_DEFAULT,
+ HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
+ }
+ HDA_BOOTVERBOSE(
+ device_printf(pdevinfo->dev,
+ "Recsel (%s): nid %d source %d %s\n",
+ hdac_audio_ctl_ossmixer_mask2allname(
+ src, buf, sizeof(buf)),
+ nid, i, muted?"mute":"unmute");
+ );
+ } else {
+ if (w->nconns == 1)
+ break;
+ if ((src & cw->ossmask) == 0)
+ continue;
+ /* If we found requested source - select it and exit. */
+ hdac_widget_connection_select(w, i);
+ HDA_BOOTVERBOSE(
+ device_printf(pdevinfo->dev,
+ "Recsel (%s): nid %d source %d select\n",
+ hdac_audio_ctl_ossmixer_mask2allname(
+ src, buf, sizeof(buf)),
+ nid, i);
+ );
break;
}
}
+ return (res);
+}
+
+static uint32_t
+hdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
+{
+ struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
+ struct hdac_widget *w;
+ struct hdac_softc *sc = devinfo->codec->sc;
+ struct hdac_chan *ch;
+ int i;
+ uint32_t ret = 0xffffffff;
hdac_lock(sc);
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
+ /* Commutate requested recsrc for each ADC. */
+ ch = &sc->chans[pdevinfo->rec];
+ for (i = 0; ch->io[i] != -1; i++) {
+ w = hdac_widget_get(devinfo, ch->io[i]);
if (w == NULL || w->enable == 0)
continue;
- if (!(w->pflags & HDA_ADC_RECSEL))
- continue;
- for (j = 0; j < w->nconns; j++) {
- cw = hdac_widget_get(devinfo, w->conns[j]);
- if (cw == NULL || cw->enable == 0)
- continue;
- if ((target == SOUND_MASK_VOLUME &&
- cw->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
- (target != SOUND_MASK_VOLUME &&
- cw->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER))
- continue;
- if (cw->ctlflags & target) {
- if (!(w->pflags & HDA_ADC_LOCKED))
- hdac_widget_connection_select(w, j);
- ret = target;
- j += w->nconns;
- }
- }
+ ret &= hdac_audio_ctl_recsel_comm(pdevinfo, src, ch->io[i], 0);
}
hdac_unlock(sc);
- return (ret);
+ return ((ret == 0xffffffff)? 0 : ret);
}
static kobj_method_t hdac_audio_ctl_ossmixer_methods[] = {
@@ -3762,7 +3730,9 @@ hdac_attach(device_t dev)
uint16_t vendor;
uint8_t v;
- sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
+ device_printf(dev, "<HDA Driver Revision: %s>\n", HDA_DRV_TEST_REV);
+
+ sc = device_get_softc(dev);
sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME);
sc->dev = dev;
sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16;
@@ -3780,7 +3750,7 @@ hdac_attach(device_t dev)
TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc);
- sc->poll_ticks = 1;
+ sc->poll_ticks = 1000000;
sc->poll_ival = HDAC_POLL_INTERVAL;
if (resource_int_value(device_get_name(dev),
device_get_unit(dev), "polling", &i) == 0 && i != 0)
@@ -3788,26 +3758,6 @@ hdac_attach(device_t dev)
else
sc->polling = 0;
- sc->chan_size = pcm_getbuffersize(dev,
- HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX);
-
- if (resource_int_value(device_get_name(dev),
- device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
- i &= HDA_BLK_ALIGN;
- if (i < HDA_BLK_MIN)
- i = HDA_BLK_MIN;
- sc->chan_blkcnt = sc->chan_size / i;
- i = 0;
- while (sc->chan_blkcnt >> i)
- i++;
- sc->chan_blkcnt = 1 << (i - 1);
- if (sc->chan_blkcnt < HDA_BDL_MIN)
- sc->chan_blkcnt = HDA_BDL_MIN;
- else if (sc->chan_blkcnt > HDA_BDL_MAX)
- sc->chan_blkcnt = HDA_BDL_MAX;
- } else
- sc->chan_blkcnt = HDA_BDL_DEFAULT;
-
result = bus_dma_tag_create(NULL, /* parent */
HDAC_DMA_ALIGNMENT, /* alignment */
0, /* boundary */
@@ -3815,9 +3765,9 @@ hdac_attach(device_t dev)
BUS_SPACE_MAXADDR, /* highaddr */
NULL, /* filtfunc */
NULL, /* fistfuncarg */
- sc->chan_size, /* maxsize */
+ HDA_BUFSZ_MAX, /* maxsize */
1, /* nsegments */
- sc->chan_size, /* maxsegsz */
+ HDA_BUFSZ_MAX, /* maxsegsz */
0, /* flags */
NULL, /* lockfunc */
NULL, /* lockfuncarg */
@@ -3935,7 +3885,10 @@ hdac_attach(device_t dev)
goto hdac_attach_fail;
/* Quiesce everything */
- hdac_reset(sc);
+ HDA_BOOTVERBOSE(
+ device_printf(dev, "Reset controller...\n");
+ );
+ hdac_reset(sc, 1);
/* Initialize the CORB and RIRB */
hdac_corb_init(sc);
@@ -3965,7 +3918,8 @@ hdac_attach_fail:
static void
hdac_audio_parse(struct hdac_devinfo *devinfo)
{
- struct hdac_softc *sc = devinfo->codec->sc;
+ struct hdac_codec *codec = devinfo->codec;
+ struct hdac_softc *sc = codec->sc;
struct hdac_widget *w;
uint32_t res;
int i;
@@ -3974,40 +3928,11 @@ hdac_audio_parse(struct hdac_devinfo *devinfo)
cad = devinfo->codec->cad;
nid = devinfo->nid;
- hdac_command(sc,
- HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), cad);
-
- DELAY(100);
-
- res = hdac_command(sc,
- HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
-
- devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
- devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
- devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
-
res = hdac_command(sc,
HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_GPIO_COUNT), cad);
devinfo->function.audio.gpio = res;
HDA_BOOTVERBOSE(
- device_printf(sc->dev, " Vendor: 0x%08x\n",
- devinfo->vendor_id);
- device_printf(sc->dev, " Device: 0x%08x\n",
- devinfo->device_id);
- device_printf(sc->dev, " Revision: 0x%08x\n",
- devinfo->revision_id);
- device_printf(sc->dev, " Stepping: 0x%08x\n",
- devinfo->stepping_id);
- device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
- sc->pci_subvendor);
- device_printf(sc->dev, " Nodes: start=%d "
- "endnode=%d total=%d\n",
- devinfo->startnode, devinfo->endnode, devinfo->nodecnt);
- device_printf(sc->dev, " CORB size: %d\n", sc->corb_size);
- device_printf(sc->dev, " RIRB size: %d\n", sc->rirb_size);
- device_printf(sc->dev, " Streams: ISS=%d OSS=%d BSS=%d\n",
- sc->num_iss, sc->num_oss, sc->num_bss);
device_printf(sc->dev, " GPIO: 0x%08x\n",
devinfo->function.audio.gpio);
device_printf(sc->dev, " NumGPIO=%d NumGPO=%d "
@@ -4039,20 +3964,6 @@ hdac_audio_parse(struct hdac_devinfo *devinfo)
cad);
devinfo->function.audio.inamp_cap = res;
- if (devinfo->nodecnt > 0)
- devinfo->widget = (struct hdac_widget *)malloc(
- sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
- M_NOWAIT | M_ZERO);
- else
- devinfo->widget = NULL;
-
- if (devinfo->widget == NULL) {
- device_printf(sc->dev, "unable to allocate widgets!\n");
- devinfo->endnode = devinfo->startnode;
- devinfo->nodecnt = 0;
- return;
- }
-
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdac_widget_get(devinfo, i);
if (w == NULL)
@@ -4063,7 +3974,8 @@ hdac_audio_parse(struct hdac_devinfo *devinfo)
w->enable = 1;
w->selconn = -1;
w->pflags = 0;
- w->ctlflags = 0;
+ w->ossdev = -1;
+ w->bindas = -1;
w->param.eapdbtl = HDAC_INVALID;
hdac_widget_parse(w);
}
@@ -4141,7 +4053,7 @@ hdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
/*if (offset > step) {
HDA_BOOTVERBOSE(
device_printf(sc->dev,
- "HDA_DEBUG: BUGGY outamp: nid=%d "
+ "BUGGY outamp: nid=%d "
"[offset=%d > step=%d]\n",
w->nid, offset, step);
);
@@ -4155,6 +4067,11 @@ hdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
ctls[cnt].offset = offset;
ctls[cnt].left = offset;
ctls[cnt].right = offset;
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
+ w->waspin)
+ ctls[cnt].ndir = HDA_CTL_IN;
+ else
+ ctls[cnt].ndir = HDA_CTL_OUT;
ctls[cnt++].dir = HDA_CTL_OUT;
}
@@ -4166,7 +4083,7 @@ hdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
/*if (offset > step) {
HDA_BOOTVERBOSE(
device_printf(sc->dev,
- "HDA_DEBUG: BUGGY inamp: nid=%d "
+ "BUGGY inamp: nid=%d "
"[offset=%d > step=%d]\n",
w->nid, offset, step);
);
@@ -4196,6 +4113,7 @@ hdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
ctls[cnt].offset = offset;
ctls[cnt].left = offset;
ctls[cnt].right = offset;
+ ctls[cnt].ndir = HDA_CTL_IN;
ctls[cnt++].dir = HDA_CTL_IN;
}
break;
@@ -4214,6 +4132,11 @@ hdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
ctls[cnt].offset = offset;
ctls[cnt].left = offset;
ctls[cnt].right = offset;
+ if (w->type ==
+ HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ ctls[cnt].ndir = HDA_CTL_OUT;
+ else
+ ctls[cnt].ndir = HDA_CTL_IN;
ctls[cnt++].dir = HDA_CTL_IN;
break;
}
@@ -4223,6 +4146,141 @@ hdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
devinfo->function.audio.ctl = ctls;
}
+static void
+hdac_audio_as_parse(struct hdac_devinfo *devinfo)
+{
+ struct hdac_softc *sc = devinfo->codec->sc;
+ struct hdac_audio_as *as;
+ struct hdac_widget *w;
+ int i, j, cnt, max, type, dir, assoc, seq, first, hpredir;
+
+ /* XXX This is redundant */
+ max = 0;
+ for (j = 0; j < 16; j++) {
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ if (HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config)
+ != j)
+ continue;
+ max++;
+ if (j != 15) /* There could be many 1-pin assocs #15 */
+ break;
+ }
+ }
+
+ devinfo->function.audio.ascnt = max;
+
+ if (max < 1)
+ return;
+
+ as = (struct hdac_audio_as *)malloc(
+ sizeof(*as) * max, M_HDAC, M_ZERO | M_NOWAIT);
+
+ if (as == NULL) {
+ /* Blekh! */
+ device_printf(sc->dev, "unable to allocate assocs!\n");
+ devinfo->function.audio.ascnt = 0;
+ return;
+ }
+
+ for (i = 0; i < max; i++) {
+ as[i].hpredir = -1;
+ as[i].chan = -1;
+ }
+
+ /* Scan associations skipping as=0. */
+ cnt = 0;
+ for (j = 1; j < 16; j++) {
+ first = 16;
+ hpredir = 0;
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ assoc = HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config);
+ seq = HDA_CONFIG_DEFAULTCONF_SEQUENCE(w->wclass.pin.config);
+ if (assoc != j) {
+ continue;
+ }
+ KASSERT(cnt < max,
+ ("%s: Associations owerflow (%d of %d)",
+ __func__, cnt, max));
+ type = w->wclass.pin.config &
+ HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
+ /* Get pin direction. */
+ if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT ||
+ type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
+ type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
+ type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT ||
+ type == HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT)
+ dir = HDA_CTL_OUT;
+ else
+ dir = HDA_CTL_IN;
+ /* If this is a first pin - create new association. */
+ if (as[cnt].pincnt == 0) {
+ as[cnt].enable = 1;
+ as[cnt].index = j;
+ as[cnt].dir = dir;
+ }
+ if (seq < first)
+ first = seq;
+ /* Check association correctness. */
+ if (as[cnt].pins[seq] != 0) {
+ device_printf(sc->dev, "%s: Duplicate pin %d (%d) "
+ "in association %d! Disabling association.\n",
+ __func__, seq, w->nid, j);
+ as[cnt].enable = 0;
+ }
+ if (dir != as[cnt].dir) {
+ device_printf(sc->dev, "%s: Pin %d has wrong "
+ "direction for association %d! Disabling "
+ "association.\n",
+ __func__, w->nid, j);
+ as[cnt].enable = 0;
+ }
+ /* Headphones with seq=15 may mean redirection. */
+ if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT &&
+ seq == 15)
+ hpredir = 1;
+ as[cnt].pins[seq] = w->nid;
+ as[cnt].pincnt++;
+ /* Association 15 is a multiple unassociated pins. */
+ if (j == 15)
+ cnt++;
+ }
+ if (j != 15 && as[cnt].pincnt > 0) {
+ if (hpredir && as[cnt].pincnt > 1)
+ as[cnt].hpredir = first;
+ cnt++;
+ }
+ }
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "%d associations found\n", max);
+ for (i = 0; i < max; i++) {
+ device_printf(sc->dev,
+ "Association %d (%d) %s%s:\n",
+ i, as[i].index, (as[i].dir == HDA_CTL_IN)?"in":"out",
+ as[i].enable?"":" (disabled)");
+ for (j = 0; j < 16; j++) {
+ if (as[i].pins[j] == 0)
+ continue;
+ device_printf(sc->dev,
+ " Pin nid=%d seq=%d\n",
+ as[i].pins[j], j);
+ }
+ }
+ );
+
+ devinfo->function.audio.as = as;
+}
+
static const struct {
uint32_t model;
uint32_t id;
@@ -4260,7 +4318,7 @@ static const struct {
{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
HDA_QUIRK_GPIO1, 0 },
{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
- HDA_QUIRK_EAPDINV, 0 },
+ HDA_QUIRK_EAPDINV | HDA_QUIRK_SENSEINV, 0 },
{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
HDA_QUIRK_EAPDINV, 0 },
{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
@@ -4276,9 +4334,7 @@ static const struct {
{ HDA_MATCH_ALL, HDA_CODEC_AD1988B,
HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
{ HDA_MATCH_ALL, HDA_CODEC_CXVENICE,
- 0, HDA_QUIRK_FORCESTEREO },
- { HDA_MATCH_ALL, HDA_CODEC_STACXXXX,
- HDA_QUIRK_SOFTPCMVOL, 0 }
+ 0, HDA_QUIRK_FORCESTEREO }
};
#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
@@ -4286,11 +4342,10 @@ static void
hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
{
struct hdac_widget *w;
- struct hdac_audio_ctl *ctl;
uint32_t id, subvendor;
int i;
- id = hdac_codec_id(devinfo);
+ id = hdac_codec_id(devinfo->codec);
subvendor = devinfo->codec->sc->pci_subvendor;
/*
@@ -4309,110 +4364,6 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
}
switch (id) {
- case HDA_CODEC_ALC260:
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
- continue;
- if (w->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
- continue;
- if (w->nid != 5)
- w->enable = 0;
- }
- if (subvendor == HP_XW4300_SUBVENDOR) {
- ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
- }
- } else if (subvendor == HP_3010_SUBVENDOR) {
- ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 21, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
- }
- }
- break;
- case HDA_CODEC_ALC262:
- if (subvendor == HP_DC7700S_SUBVENDOR) {
- ctl = hdac_audio_ctl_amp_get(devinfo, 21, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_PHONEOUT;
- ctl->widget->ctlflags |= SOUND_MASK_PHONEOUT;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 22, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
- }
- } else if (subvendor == HP_DC7700_SUBVENDOR) {
- ctl = hdac_audio_ctl_amp_get(devinfo, 22, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 27, 0, 1);
- if (ctl != NULL && ctl->widget != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
- }
- }
- break;
- case HDA_CODEC_ALC268:
- if (HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subvendor)) {
- w = hdac_widget_get(devinfo, 29);
- if (w != NULL) {
- w->enable = 1;
- w->type =
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET;
- w->param.widget_cap &=
- ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
- w->param.widget_cap |=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
- strlcpy(w->name, "beep widget", sizeof(w->name));
- }
- }
- break;
- case HDA_CODEC_ALC861:
- ctl = hdac_audio_ctl_amp_get(devinfo, 21, 2, 1);
- if (ctl != NULL)
- ctl->muted = HDA_AMP_MUTE_ALL;
- break;
- case HDA_CODEC_ALC880:
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
- continue;
- if (w->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
- w->nid != 9 && w->nid != 29) {
- w->enable = 0;
- } else if (w->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET &&
- w->nid == 29) {
- w->type =
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET;
- w->param.widget_cap &=
- ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
- w->param.widget_cap |=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
- strlcpy(w->name, "beep widget", sizeof(w->name));
- }
- }
- break;
case HDA_CODEC_ALC883:
/*
* nid: 24/25 = External (jack) or Internal (fixed) Mic.
@@ -4442,37 +4393,8 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
* nid: 26 = Line-in, leave it alone.
*/
break;
- case HDA_CODEC_AD1981HD:
- w = hdac_widget_get(devinfo, 11);
- if (w != NULL && w->enable != 0 && w->nconns > 3)
- w->selconn = 3;
- if (subvendor == IBM_M52_SUBVENDOR) {
- ctl = hdac_audio_ctl_amp_get(devinfo, 7, 0, 1);
- if (ctl != NULL)
- ctl->ossmask = SOUND_MASK_SPEAKER;
- }
- break;
case HDA_CODEC_AD1986A:
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
- continue;
- if (w->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
- continue;
- if (w->nid != 3)
- w->enable = 0;
- }
- if (subvendor == ASUS_M2NPVMX_SUBVENDOR ||
- subvendor == ASUS_A8NVMCSM_SUBVENDOR) {
- /* nid 28 is mic, nid 29 is line-in */
- w = hdac_widget_get(devinfo, 15);
- if (w != NULL)
- w->selconn = 2;
- w = hdac_widget_get(devinfo, 16);
- if (w != NULL)
- w->selconn = 1;
- } else if (subvendor == ASUS_A8X_SUBVENDOR) {
+ if (subvendor == ASUS_A8X_SUBVENDOR) {
/*
* This is just plain ridiculous.. There
* are several A8 series that share the same
@@ -4488,798 +4410,1482 @@ hdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
~HDA_QUIRK_EAPDINV;
}
break;
- case HDA_CODEC_AD1988:
- case HDA_CODEC_AD1988B:
- /*w = hdac_widget_get(devinfo, 12);
- if (w != NULL) {
- w->selconn = 1;
- w->pflags |= HDA_ADC_LOCKED;
- }
- w = hdac_widget_get(devinfo, 13);
- if (w != NULL) {
- w->selconn = 4;
- w->pflags |= HDA_ADC_LOCKED;
- }
- w = hdac_widget_get(devinfo, 14);
- if (w != NULL) {
- w->selconn = 2;
- w->pflags |= HDA_ADC_LOCKED;
- }*/
- ctl = hdac_audio_ctl_amp_get(devinfo, 57, 0, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_IGAIN;
- ctl->widget->ctlflags |= SOUND_MASK_IGAIN;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 58, 0, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_IGAIN;
- ctl->widget->ctlflags |= SOUND_MASK_IGAIN;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 60, 0, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_IGAIN;
- ctl->widget->ctlflags |= SOUND_MASK_IGAIN;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 32, 0, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME;
- ctl->widget->ctlflags |= SOUND_MASK_MIC;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 32, 4, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME;
- ctl->widget->ctlflags |= SOUND_MASK_MIC;
+ }
+}
+
+/*
+ * Trace path from DAC to pin.
+ */
+static nid_t
+hdac_audio_trace_dac(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
+ int dupseq, int min, int only, int depth)
+{
+ struct hdac_widget *w;
+ int i, im = -1;
+ nid_t m = 0, ret;
+
+ if (depth > HDA_PARSE_MAXDEPTH)
+ return (0);
+ w = hdac_widget_get(devinfo, nid);
+ if (w == NULL || w->enable == 0)
+ return (0);
+ HDA_BOOTVERBOSE(
+ if (!only) {
+ device_printf(devinfo->codec->sc->dev,
+ " %*stracing via nid %d\n",
+ depth + 1, "", w->nid);
}
- ctl = hdac_audio_ctl_amp_get(devinfo, 32, 1, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME;
- ctl->widget->ctlflags |= SOUND_MASK_LINE;
+ );
+ /* Use only unused widgets */
+ if (w->bindas >= 0 && w->bindas != as) {
+ HDA_BOOTVERBOSE(
+ if (!only) {
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d busy by association %d\n",
+ depth + 1, "", w->nid, w->bindas);
+ }
+ );
+ return (0);
+ }
+ if (dupseq < 0) {
+ if (w->bindseqmask != 0) {
+ HDA_BOOTVERBOSE(
+ if (!only) {
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d busy by seqmask %x\n",
+ depth + 1, "", w->nid, w->bindseqmask);
+ }
+ );
+ return (0);
}
- ctl = hdac_audio_ctl_amp_get(devinfo, 32, 7, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_SPEAKER | SOUND_MASK_VOLUME;
- ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
+ } else {
+ /* If this is headphones - allow duplicate first pin. */
+ if (w->bindseqmask != 0 &&
+ (w->bindseqmask & (1 << dupseq)) == 0) {
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d busy by seqmask %x\n",
+ depth + 1, "", w->nid, w->bindseqmask);
+ );
+ return (0);
}
+ }
+
+ switch (w->type) {
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
+ /* Do not traverse input. AD1988 has digital monitor
+ for which we are not ready. */
break;
- case HDA_CODEC_STAC9205:
- if ((subvendor == DELL_V1500_SUBVENDOR) ||
- (subvendor == DELL_D630_SUBVENDOR)) {
- w = hdac_widget_get(devinfo, 29);
- if (w != NULL)
- w->selconn = 1;
- w = hdac_widget_get(devinfo, 30);
- if (w != NULL)
- w->selconn = 1;
- }
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
+ /* If we are tracing HP take only dac of first pin. */
+ if ((only == 0 || only == w->nid) &&
+ (w->nid >= min) && (dupseq < 0 || w->nid ==
+ devinfo->function.audio.as[as].dacs[dupseq]))
+ m = w->nid;
break;
- case HDA_CODEC_STAC9221:
- /*
- * Dell XPS M1210 need all DACs for each output jacks
- */
- if (subvendor == DELL_XPSM1210_SUBVENDOR)
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
+ if (depth > 0)
break;
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
- continue;
- if (w->type !=
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
+ /* Fall */
+ default:
+ /* Find reachable DACs with smallest nid respecting constraints. */
+ for (i = 0; i < w->nconns; i++) {
+ if (w->connsenable[i] == 0)
continue;
- if (w->nid != 2)
- w->enable = 0;
- }
- break;
- case HDA_CODEC_STAC9221D:
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
+ if (w->selconn != -1 && w->selconn != i)
continue;
- if (w->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
- w->nid != 6)
- w->enable = 0;
-
+ if ((ret = hdac_audio_trace_dac(devinfo, as, seq,
+ w->conns[i], dupseq, min, only, depth + 1)) != 0) {
+ if (m == 0 || ret < m) {
+ m = ret;
+ im = i;
+ }
+ if (only || dupseq >= 0)
+ break;
+ }
}
+ if (m && only && ((w->nconns > 1 &&
+ w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
+ w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
+ w->selconn = im;
break;
- case HDA_CODEC_STAC9227:
- w = hdac_widget_get(devinfo, 8);
- if (w != NULL)
- w->enable = 0;
- w = hdac_widget_get(devinfo, 9);
- if (w != NULL)
- w->enable = 0;
- break;
- case HDA_CODEC_CXWAIKIKI:
- if (subvendor == HP_DV5000_SUBVENDOR) {
- w = hdac_widget_get(devinfo, 27);
- if (w != NULL)
- w->enable = 0;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1);
- if (ctl != NULL)
- ctl->ossmask = SOUND_MASK_SKIP;
- ctl = hdac_audio_ctl_amp_get(devinfo, 25, 0, 1);
- if (ctl != NULL && ctl->childwidget != NULL &&
- ctl->childwidget->enable != 0) {
- ctl->ossmask = SOUND_MASK_PCM | SOUND_MASK_VOLUME;
- ctl->childwidget->ctlflags |= SOUND_MASK_PCM;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 25, 1, 1);
- if (ctl != NULL && ctl->childwidget != NULL &&
- ctl->childwidget->enable != 0) {
- ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME;
- ctl->childwidget->ctlflags |= SOUND_MASK_LINE;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 25, 2, 1);
- if (ctl != NULL && ctl->childwidget != NULL &&
- ctl->childwidget->enable != 0) {
- ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME;
- ctl->childwidget->ctlflags |= SOUND_MASK_MIC;
- }
- ctl = hdac_audio_ctl_amp_get(devinfo, 26, 0, 1);
- if (ctl != NULL) {
- ctl->ossmask = SOUND_MASK_SKIP;
- /* XXX mixer \=rec mic broken.. why?!? */
- /* ctl->widget->ctlflags |= SOUND_MASK_MIC; */
+ }
+ if (m && only) {
+ w->bindas = as;
+ w->bindseqmask |= (1 << seq);
+ }
+ HDA_BOOTVERBOSE(
+ if (!only) {
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d returned %d\n",
+ depth + 1, "", w->nid, m);
}
+ );
+ return (m);
+}
+
+/*
+ * Trace path from widget to ADC.
+ */
+static nid_t
+hdac_audio_trace_adc(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
+ int only, int depth)
+{
+ struct hdac_widget *w, *wc;
+ int i, j;
+ nid_t res = 0;
+
+ if (depth > HDA_PARSE_MAXDEPTH)
+ return (0);
+ w = hdac_widget_get(devinfo, nid);
+ if (w == NULL || w->enable == 0)
+ return (0);
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*stracing via nid %d\n",
+ depth + 1, "", w->nid);
+ );
+ /* Use only unused widgets */
+ if (w->bindas >= 0 && w->bindas != as) {
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d busy by association %d\n",
+ depth + 1, "", w->nid, w->bindas);
+ );
+ return (0);
+ }
+
+ switch (w->type) {
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
+ /* If we are tracing HP take only dac of first pin. */
+ if (only == w->nid)
+ res = 1;
break;
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
+ if (depth > 0)
+ break;
+ /* Fall */
default:
+ /* Try to find reachable ADCs with specified nid. */
+ for (j = devinfo->startnode; j < devinfo->endnode; j++) {
+ wc = hdac_widget_get(devinfo, j);
+ if (wc == NULL || wc->enable == 0)
+ continue;
+ for (i = 0; i < wc->nconns; i++) {
+ if (wc->connsenable[i] == 0)
+ continue;
+ if (wc->conns[i] != nid)
+ continue;
+ if (hdac_audio_trace_adc(devinfo, as, seq,
+ j, only, depth + 1) != 0) {
+ res = 1;
+ if (((wc->nconns > 1 &&
+ wc->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
+ wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) &&
+ wc->selconn == -1)
+ wc->selconn = i;
+ }
+ }
+ }
break;
}
+ if (res) {
+ w->bindas = as;
+ w->bindseqmask |= (1 << seq);
+ }
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d returned %d\n",
+ depth + 1, "", w->nid, res);
+ );
+ return (res);
}
-static int
-hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *devinfo)
+/*
+ * Erase trace path of the specified association.
+ */
+static void
+hdac_audio_undo_trace(struct hdac_devinfo *devinfo, int as, int seq)
{
- int *dev = &devinfo->function.audio.ossidx;
-
- while (*dev < SOUND_MIXER_NRDEVICES) {
- switch (*dev) {
- case SOUND_MIXER_VOLUME:
- case SOUND_MIXER_BASS:
- case SOUND_MIXER_TREBLE:
- case SOUND_MIXER_PCM:
- case SOUND_MIXER_SPEAKER:
- case SOUND_MIXER_LINE:
- case SOUND_MIXER_MIC:
- case SOUND_MIXER_CD:
- case SOUND_MIXER_RECLEV:
- case SOUND_MIXER_IGAIN:
- case SOUND_MIXER_OGAIN: /* reserved for EAPD switch */
- (*dev)++;
- break;
- default:
- return (*dev)++;
- break;
+ struct hdac_widget *w;
+ int i;
+
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->bindas == as) {
+ if (seq >= 0) {
+ w->bindseqmask &= ~(1 << seq);
+ if (w->bindseqmask == 0) {
+ w->bindas = -1;
+ w->selconn = -1;
+ }
+ } else {
+ w->bindas = -1;
+ w->bindseqmask = 0;
+ w->selconn = -1;
+ }
}
}
+}
- return (-1);
+/*
+ * Trace association path from DAC to output
+ */
+static int
+hdac_audio_trace_as_out(struct hdac_devinfo *devinfo, int as, int seq)
+{
+ struct hdac_audio_as *ases = devinfo->function.audio.as;
+ int i, hpredir;
+ nid_t min, res;
+
+ /* Find next pin */
+ for (i = seq; ases[as].pins[i] == 0 && i < 16; i++)
+ ;
+ /* Check if there is no any left. If so - we succeded. */
+ if (i == 16)
+ return (1);
+
+ hpredir = (i == 15 && ases[as].fakeredir == 0)?ases[as].hpredir:-1;
+ min = 0;
+ res = 0;
+ do {
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Tracing pin %d with min nid %d",
+ ases[as].pins[i], min);
+ if (hpredir >= 0)
+ printf(" and hpredir %d\n", hpredir);
+ else
+ printf("\n");
+ );
+ /* Trace this pin taking min nid into account. */
+ res = hdac_audio_trace_dac(devinfo, as, i,
+ ases[as].pins[i], hpredir, min, 0, 0);
+ if (res == 0) {
+ /* If we failed - return to previous and redo it. */
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Unable to trace pin %d seq %d with min "
+ "nid %d hpredir %d\n",
+ ases[as].pins[i], i, min, hpredir);
+ );
+ return (0);
+ }
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Pin %d traced to DAC %d%s\n",
+ ases[as].pins[i], res,
+ ases[as].fakeredir?" with fake redirection":"");
+ );
+ /* Trace again to mark the path */
+ hdac_audio_trace_dac(devinfo, as, i,
+ ases[as].pins[i], hpredir, min, res, 0);
+ ases[as].dacs[i] = res;
+ /* We succeded, so call next. */
+ if (hdac_audio_trace_as_out(devinfo, as, i + 1))
+ return (1);
+ /* If next failed, we should retry with next min */
+ hdac_audio_undo_trace(devinfo, as, i);
+ ases[as].dacs[i] = 0;
+ min = res + 1;
+ } while (1);
}
+/*
+ * Trace association path from input to ADC
+ */
static int
-hdac_widget_find_dac_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
+hdac_audio_trace_as_in(struct hdac_devinfo *devinfo, int as)
{
+ struct hdac_audio_as *ases = devinfo->function.audio.as;
struct hdac_widget *w;
- int i, ret = 0;
+ int i, j, k;
- if (depth > HDA_PARSE_MAXDEPTH)
- return (0);
- w = hdac_widget_get(devinfo, nid);
- if (w == NULL || w->enable == 0)
- return (0);
- switch (w->type) {
- case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
- w->pflags |= HDA_DAC_PATH;
- ret = 1;
- break;
- case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
- case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
- for (i = 0; i < w->nconns; i++) {
- if (hdac_widget_find_dac_path(devinfo,
- w->conns[i], depth + 1) != 0) {
- if (w->selconn == -1)
- w->selconn = i;
- ret = 1;
- w->pflags |= HDA_DAC_PATH;
+ 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_AUDIO_INPUT)
+ continue;
+ if (w->bindas >= 0 && w->bindas != as)
+ continue;
+
+ /* Find next pin */
+ for (i = 0; i < 16; i++) {
+ if (ases[as].pins[i] == 0)
+ continue;
+
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Tracing pin %d to ADC %d\n",
+ ases[as].pins[i], j);
+ );
+ /* Trace this pin taking goal into account. */
+ if (hdac_audio_trace_adc(devinfo, as, i,
+ ases[as].pins[i], j, 0) == 0) {
+ /* If we failed - return to previous and redo it. */
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Unable to trace pin %d to ADC %d\n",
+ ases[as].pins[i], j);
+ );
+ hdac_audio_undo_trace(devinfo, as, -1);
+ for (k = 0; k < 16; k++)
+ ases[as].dacs[k] = 0;
+ break;
}
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Traced to ADC %d\n",
+ j);
+ );
+ ases[as].dacs[i] = j;
}
- break;
- default:
- break;
+ if (i == 16)
+ return (1);
}
- return (ret);
+ return (0);
}
-static int
-hdac_widget_find_adc_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
+/*
+ * Trace input monitor path from mixer to output association.
+ */
+static nid_t
+hdac_audio_trace_to_out(struct hdac_devinfo *devinfo, nid_t nid, int depth)
{
- struct hdac_widget *w;
- int i, conndev, ret = 0;
+ struct hdac_audio_as *ases = devinfo->function.audio.as;
+ struct hdac_widget *w, *wc;
+ int i, j;
+ nid_t res = 0;
if (depth > HDA_PARSE_MAXDEPTH)
return (0);
w = hdac_widget_get(devinfo, nid);
if (w == NULL || w->enable == 0)
return (0);
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*stracing via nid %d\n",
+ depth + 1, "", w->nid);
+ );
+ /* Use only unused widgets */
+ if (depth > 0 && w->bindas != -1) {
+ if (w->bindas < 0 || ases[w->bindas].dir == HDA_CTL_OUT) {
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d found output association %d\n",
+ depth + 1, "", w->nid, w->bindas);
+ );
+ return (1);
+ } else {
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d busy by input association %d\n",
+ depth + 1, "", w->nid, w->bindas);
+ );
+ return (0);
+ }
+ }
+
switch (w->type) {
case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
- case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
- case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
- for (i = 0; i < w->nconns; i++) {
- if (hdac_widget_find_adc_path(devinfo, w->conns[i],
- depth + 1) != 0) {
- if (w->selconn == -1)
- w->selconn = i;
- w->pflags |= HDA_ADC_PATH;
- ret = 1;
- }
- }
+ /* Do not traverse input. AD1988 has digital monitor
+ for which we are not ready. */
break;
case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
- conndev = w->wclass.pin.config &
- HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
- if (HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
- (conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_CD ||
- conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN ||
- conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN)) {
- w->pflags |= HDA_ADC_PATH;
- ret = 1;
+ if (depth > 0)
+ break;
+ /* Fall */
+ default:
+ /* Try to find reachable ADCs with specified nid. */
+ for (j = devinfo->startnode; j < devinfo->endnode; j++) {
+ wc = hdac_widget_get(devinfo, j);
+ if (wc == NULL || wc->enable == 0)
+ continue;
+ for (i = 0; i < wc->nconns; i++) {
+ if (wc->connsenable[i] == 0)
+ continue;
+ if (wc->conns[i] != nid)
+ continue;
+ if (hdac_audio_trace_to_out(devinfo,
+ j, depth + 1) != 0) {
+ res = 1;
+ if (wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
+ wc->selconn == -1)
+ wc->selconn = i;
+ }
+ }
}
break;
- /*case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
- if (w->pflags & HDA_DAC_PATH) {
- w->pflags |= HDA_ADC_PATH;
- ret = 1;
+ }
+ if (res)
+ w->bindas = -2;
+
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " %*snid %d returned %d\n",
+ depth + 1, "", w->nid, res);
+ );
+ return (res);
+}
+
+/*
+ * Trace extra associations (beeper, monitor)
+ */
+static void
+hdac_audio_trace_as_extra(struct hdac_devinfo *devinfo)
+{
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w;
+ int j;
+
+ /* Input monitor */
+ /* Find mixer associated with input, but supplying signal
+ for output associations. Hope it will be input monitor. */
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ "Tracing input monitor\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_AUDIO_MIXER)
+ 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);
+ );
+ w->pflags |= HDA_ADC_MONITOR;
+ w->ossdev = SOUND_MIXER_IMIX;
}
- break;*/
- default:
- break;
}
- return (ret);
+
+ /* Beeper */
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ "Tracing beeper\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_BEEP_WIDGET)
+ continue;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Tracing nid %d to out\n",
+ j);
+ );
+ hdac_audio_trace_to_out(devinfo, w->nid, 0);
+ w->bindas = -2;
+ }
}
-static uint32_t
-hdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo,
- nid_t nid, nid_t pnid, int index, int depth)
+/*
+ * Bind assotiations to PCM channels
+ */
+static void
+hdac_audio_bind_as(struct hdac_devinfo *devinfo)
{
- struct hdac_widget *w, *pw;
- struct hdac_audio_ctl *ctl;
- uint32_t fl = 0;
- int i, ossdev, conndev, strategy;
+ struct hdac_softc *sc = devinfo->codec->sc;
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ int j, cnt = 0, free;
+
+ for (j = 0; j < devinfo->function.audio.ascnt; j++) {
+ if (as[j].enable)
+ cnt++;
+ }
+ if (sc->num_chans == 0) {
+ sc->chans = (struct hdac_chan *)malloc(
+ sizeof(struct hdac_chan) * cnt,
+ M_HDAC, M_ZERO | M_NOWAIT);
+ if (sc->chans == NULL) {
+ device_printf(devinfo->codec->sc->dev,
+ "Channels memory allocation failed!\n");
+ return;
+ }
+ } else {
+ sc->chans = (struct hdac_chan *)realloc(sc->chans,
+ sizeof(struct hdac_chan) * cnt,
+ M_HDAC, M_ZERO | M_NOWAIT);
+ if (sc->chans == NULL) {
+ sc->num_chans = 0;
+ device_printf(devinfo->codec->sc->dev,
+ "Channels memory allocation failed!\n");
+ return;
+ }
+ }
+ free = sc->num_chans;
+ sc->num_chans += cnt;
- if (depth > HDA_PARSE_MAXDEPTH)
- return (0);
+ for (j = free; j < free + cnt; j++) {
+ devinfo->codec->sc->chans[j].devinfo = devinfo;
+ devinfo->codec->sc->chans[j].as = -1;
+ }
- w = hdac_widget_get(devinfo, nid);
- if (w == NULL || w->enable == 0)
- return (0);
+ /* Assign associations in order of their numbers, */
+ free = 0;
+ for (j = 0; j < devinfo->function.audio.ascnt; j++) {
+ if (as[j].enable == 0)
+ continue;
+
+ as[j].chan = free;
+ devinfo->codec->sc->chans[free].as = j;
+ if (as[j].dir == HDA_CTL_IN) {
+ devinfo->codec->sc->chans[free].dir = PCMDIR_REC;
+ devinfo->function.audio.reccnt++;
+ } else {
+ devinfo->codec->sc->chans[free].dir = PCMDIR_PLAY;
+ devinfo->function.audio.playcnt++;
+ }
+ hdac_pcmchannel_setup(&devinfo->codec->sc->chans[free]);
+ free++;
+ }
+}
- pw = hdac_widget_get(devinfo, pnid);
- strategy = devinfo->function.audio.parsing_strategy;
+static void
+hdac_audio_disable_nonaudio(struct hdac_devinfo *devinfo)
+{
+ struct hdac_widget *w;
+ int i;
- if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER
- || w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) {
- for (i = 0; i < w->nconns; i++) {
- fl |= hdac_audio_ctl_outamp_build(devinfo, w->conns[i],
- w->nid, i, depth + 1);
+ /* Disable power and volume widgets. */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET ||
+ w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET) {
+ w->enable = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling nid %d due to it's"
+ " non-audio type.\n",
+ w->nid);
+ );
}
- w->ctlflags |= fl;
- return (fl);
- } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT &&
- (w->pflags & HDA_DAC_PATH)) {
+ }
+}
+
+static void
+hdac_audio_disable_useless(struct hdac_devinfo *devinfo)
+{
+ struct hdac_widget *w, *cw;
+ struct hdac_audio_ctl *ctl;
+ int done, found, i, j, k;
+
+ /* Disable useless pins. */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
+ (w->wclass.pin.config &
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
+ HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE) {
+ w->enable = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling pin nid %d due"
+ " to None connectivity.\n",
+ w->nid);
+ );
+ }
+ }
+ do {
+ done = 1;
+ /* Disable and mute controls for disabled widgets. */
i = 0;
while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL)
+ if (ctl->enable == 0)
+ continue;
+ if (ctl->widget->enable == 0 ||
+ (ctl->childwidget != NULL &&
+ ctl->childwidget->enable == 0)) {
+ ctl->forcemute = 1;
+ ctl->muted = HDA_AMP_MUTE_ALL;
+ ctl->left = 0;
+ ctl->right = 0;
+ ctl->enable = 0;
+ if (ctl->ndir == HDA_CTL_IN)
+ ctl->widget->connsenable[ctl->index] = 0;
+ done = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling ctl %d nid %d cnid %d due"
+ " to disabled widget.\n", i,
+ ctl->widget->nid,
+ (ctl->childwidget != NULL)?
+ ctl->childwidget->nid:-1);
+ );
+ }
+ }
+ /* Disable useless widgets. */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
continue;
- /* XXX This should be compressed! */
- if (((ctl->widget->nid == w->nid) ||
- (ctl->widget->nid == pnid && ctl->index == index &&
- (ctl->dir & HDA_CTL_IN)) ||
- (ctl->widget->nid == pnid && pw != NULL &&
- pw->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
- (pw->nconns < 2 || pw->selconn == index ||
- pw->selconn == -1) &&
- (ctl->dir & HDA_CTL_OUT)) ||
- (strategy == HDA_PARSE_DIRECT &&
- ctl->widget->nid == w->nid)) &&
- !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
- /*if (pw != NULL && pw->selconn == -1)
- pw->selconn = index;
- fl |= SOUND_MASK_VOLUME;
- fl |= SOUND_MASK_PCM;
- ctl->ossmask |= SOUND_MASK_VOLUME;
- ctl->ossmask |= SOUND_MASK_PCM;
- ctl->ossdev = SOUND_MIXER_PCM;*/
- if (!(w->ctlflags & SOUND_MASK_PCM) ||
- (pw != NULL &&
- !(pw->ctlflags & SOUND_MASK_PCM))) {
- fl |= SOUND_MASK_VOLUME;
- fl |= SOUND_MASK_PCM;
- ctl->ossmask |= SOUND_MASK_VOLUME;
- ctl->ossmask |= SOUND_MASK_PCM;
- ctl->ossdev = SOUND_MIXER_PCM;
- w->ctlflags |= SOUND_MASK_VOLUME;
- w->ctlflags |= SOUND_MASK_PCM;
- if (pw != NULL) {
- if (pw->selconn == -1)
- pw->selconn = index;
- pw->ctlflags |=
- SOUND_MASK_VOLUME;
- pw->ctlflags |=
- SOUND_MASK_PCM;
+ /* Disable inputs with disabled child widgets. */
+ for (j = 0; j < w->nconns; j++) {
+ if (w->connsenable[j]) {
+ cw = hdac_widget_get(devinfo, w->conns[j]);
+ if (cw == NULL || cw->enable == 0) {
+ w->connsenable[j] = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling nid %d connection %d due"
+ " to disabled child widget.\n",
+ i, j);
+ );
}
}
}
- }
- w->ctlflags |= fl;
- return (fl);
- } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
- HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
- (w->pflags & HDA_ADC_PATH)) {
- conndev = w->wclass.pin.config &
- HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL)
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
+ w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
continue;
- /* XXX This should be compressed! */
- if (((ctl->widget->nid == pnid && ctl->index == index &&
- (ctl->dir & HDA_CTL_IN)) ||
- (ctl->widget->nid == pnid && pw != NULL &&
- pw->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
- (pw->nconns < 2 || pw->selconn == index ||
- pw->selconn == -1) &&
- (ctl->dir & HDA_CTL_OUT)) ||
- (strategy == HDA_PARSE_DIRECT &&
- ctl->widget->nid == w->nid)) &&
- !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
- if (pw != NULL && pw->selconn == -1)
- pw->selconn = index;
- ossdev = 0;
- switch (conndev) {
- case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
- ossdev = SOUND_MIXER_MIC;
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
- ossdev = SOUND_MIXER_LINE;
- break;
- case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
- ossdev = SOUND_MIXER_CD;
- break;
- default:
- ossdev =
- hdac_audio_ctl_ossmixer_getnextdev(
- devinfo);
- if (ossdev < 0)
- ossdev = 0;
+ /* Disable mixers and selectors without inputs. */
+ found = 0;
+ for (j = 0; j < w->nconns; j++) {
+ if (w->connsenable[j]) {
+ found = 1;
break;
}
- if (strategy == HDA_PARSE_MIXER) {
- fl |= SOUND_MASK_VOLUME;
- ctl->ossmask |= SOUND_MASK_VOLUME;
+ }
+ if (found == 0) {
+ w->enable = 0;
+ done = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling nid %d due to all it's"
+ " inputs disabled.\n", w->nid);
+ );
+ }
+ /* Disable nodes without consumers. */
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
+ w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
+ continue;
+ found = 0;
+ for (k = devinfo->startnode; k < devinfo->endnode; k++) {
+ cw = hdac_widget_get(devinfo, k);
+ if (cw == NULL || cw->enable == 0)
+ continue;
+ for (j = 0; j < cw->nconns; j++) {
+ if (cw->connsenable[j] && cw->conns[j] == i) {
+ found = 1;
+ break;
+ }
}
- fl |= 1 << ossdev;
- ctl->ossmask |= 1 << ossdev;
- ctl->ossdev = ossdev;
+ }
+ if (found == 0) {
+ w->enable = 0;
+ done = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling nid %d due to all it's"
+ " consumers disabled.\n", w->nid);
+ );
}
}
- w->ctlflags |= fl;
- return (fl);
- } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL)
- continue;
- /* XXX This should be compressed! */
- if (((ctl->widget->nid == pnid && ctl->index == index &&
- (ctl->dir & HDA_CTL_IN)) ||
- (ctl->widget->nid == pnid && pw != NULL &&
- pw->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
- (pw->nconns < 2 || pw->selconn == index ||
- pw->selconn == -1) &&
- (ctl->dir & HDA_CTL_OUT)) ||
- (strategy == HDA_PARSE_DIRECT &&
- ctl->widget->nid == w->nid)) &&
- !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
- if (pw != NULL && pw->selconn == -1)
- pw->selconn = index;
- fl |= SOUND_MASK_VOLUME;
- fl |= SOUND_MASK_SPEAKER;
- ctl->ossmask |= SOUND_MASK_VOLUME;
- ctl->ossmask |= SOUND_MASK_SPEAKER;
- ctl->ossdev = SOUND_MIXER_SPEAKER;
+ } while (done == 0);
+
+}
+
+static void
+hdac_audio_disable_unas(struct hdac_devinfo *devinfo)
+{
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w, *cw;
+ struct hdac_audio_ctl *ctl;
+ int i, j, k;
+
+ /* Disable unassosiated widgets. */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->bindas == -1) {
+ w->enable = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling unassociated nid %d.\n",
+ w->nid);
+ );
+ }
+ }
+ /* Disable input connections on input pin and
+ * output on output. */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ if (w->bindas < 0)
+ continue;
+ if (as[w->bindas].dir == HDA_CTL_IN) {
+ for (j = 0; j < w->nconns; j++) {
+ if (w->connsenable[j] == 0)
+ continue;
+ w->connsenable[j] = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling connection to input pin "
+ "nid %d conn %d.\n",
+ i, j);
+ );
+ }
+ ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
+ HDA_CTL_IN, -1, 1);
+ if (ctl && ctl->enable) {
+ ctl->forcemute = 1;
+ ctl->muted = HDA_AMP_MUTE_ALL;
+ ctl->left = 0;
+ ctl->right = 0;
+ ctl->enable = 0;
+ }
+ } else {
+ ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
+ HDA_CTL_OUT, -1, 1);
+ if (ctl && ctl->enable) {
+ ctl->forcemute = 1;
+ ctl->muted = HDA_AMP_MUTE_ALL;
+ ctl->left = 0;
+ ctl->right = 0;
+ ctl->enable = 0;
+ }
+ for (k = devinfo->startnode; k < devinfo->endnode; k++) {
+ cw = hdac_widget_get(devinfo, k);
+ if (cw == NULL || cw->enable == 0)
+ continue;
+ for (j = 0; j < cw->nconns; j++) {
+ if (cw->connsenable[j] && cw->conns[j] == i) {
+ cw->connsenable[j] = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling connection from output pin "
+ "nid %d conn %d cnid %d.\n",
+ k, j, i);
+ );
+ if (cw->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
+ cw->nconns > 1)
+ continue;
+ ctl = hdac_audio_ctl_amp_get(devinfo, k,
+ HDA_CTL_IN, j, 1);
+ if (ctl && ctl->enable) {
+ ctl->forcemute = 1;
+ ctl->muted = HDA_AMP_MUTE_ALL;
+ ctl->left = 0;
+ ctl->right = 0;
+ ctl->enable = 0;
+ }
+ }
+ }
}
}
- w->ctlflags |= fl;
- return (fl);
}
- return (0);
}
-static uint32_t
-hdac_audio_ctl_inamp_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
+static void
+hdac_audio_disable_notselected(struct hdac_devinfo *devinfo)
+{
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w;
+ int i, j;
+
+ /* On playback path we can safely disable all unseleted inputs. */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->nconns <= 1)
+ continue;
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
+ continue;
+ if (w->bindas < 0 || as[w->bindas].dir == HDA_CTL_IN)
+ continue;
+ for (j = 0; j < w->nconns; j++) {
+ if (w->connsenable[j] == 0)
+ continue;
+ if (w->selconn < 0 || w->selconn == j)
+ continue;
+ w->connsenable[j] = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling unselected connection "
+ "nid %d conn %d.\n",
+ i, j);
+ );
+ }
+ }
+}
+
+static void
+hdac_audio_disable_crossas(struct hdac_devinfo *devinfo)
{
struct hdac_widget *w, *cw;
struct hdac_audio_ctl *ctl;
- uint32_t fl;
- int i;
-
- if (depth > HDA_PARSE_MAXDEPTH)
- return (0);
+ int i, j;
- w = hdac_widget_get(devinfo, nid);
- if (w == NULL || w->enable == 0)
- return (0);
- /*if (!(w->pflags & HDA_ADC_PATH))
- return (0);
- if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
- w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
- return (0);*/
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL)
+ /* Disable crossassociatement connections. */
+ /* ... using selectors */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->nconns <= 1)
+ continue;
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
continue;
- if (ctl->widget->nid == nid) {
- ctl->ossmask |= SOUND_MASK_RECLEV;
- w->ctlflags |= SOUND_MASK_RECLEV;
- return (SOUND_MASK_RECLEV);
+ if (w->bindas == -2)
+ continue;
+ for (j = 0; j < w->nconns; j++) {
+ if (w->connsenable[j] == 0)
+ continue;
+ cw = hdac_widget_get(devinfo, w->conns[j]);
+ if (cw == NULL || w->enable == 0)
+ continue;
+ if (w->bindas == cw->bindas || cw->bindas == -2)
+ continue;
+ w->connsenable[j] = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling crossassociatement connection "
+ "nid %d conn %d cnid %d.\n",
+ i, j, cw->nid);
+ );
}
}
- for (i = 0; i < w->nconns; i++) {
- cw = hdac_widget_get(devinfo, w->conns[i]);
- if (cw == NULL || cw->enable == 0)
+ /* ... using controls */
+ i = 0;
+ while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
+ if (ctl->enable == 0 || ctl->childwidget == NULL)
continue;
- if (cw->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
+ if (ctl->widget->bindas == -2 ||
+ ctl->childwidget->bindas == -2)
continue;
- fl = hdac_audio_ctl_inamp_build(devinfo, cw->nid, depth + 1);
- if (fl != 0) {
- cw->ctlflags |= fl;
- w->ctlflags |= fl;
- return (fl);
+ if (ctl->widget->bindas != ctl->childwidget->bindas) {
+ ctl->forcemute = 1;
+ ctl->muted = HDA_AMP_MUTE_ALL;
+ ctl->left = 0;
+ ctl->right = 0;
+ ctl->enable = 0;
+ if (ctl->ndir == HDA_CTL_IN)
+ ctl->widget->connsenable[ctl->index] = 0;
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ " Disabling crossassociatement connection "
+ "ctl %d nid %d cnid %d.\n", i,
+ ctl->widget->nid,
+ ctl->childwidget->nid);
+ );
}
}
- return (0);
+
}
+#define HDA_CTL_GIVE(ctl) ((ctl)->step?1:0)
+
+/*
+ * Find controls to control amplification for source.
+ */
static int
-hdac_audio_ctl_recsel_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
+hdac_audio_ctl_source_amp(struct hdac_devinfo *devinfo, nid_t nid, int index,
+ int ossdev, int ctlable, int depth, int need)
{
- struct hdac_widget *w, *cw;
- int i, child = 0;
-
+ struct hdac_widget *w, *wc;
+ struct hdac_audio_ctl *ctl;
+ int i, j, conns = 0, rneed;
+
if (depth > HDA_PARSE_MAXDEPTH)
- return (0);
+ return (need);
w = hdac_widget_get(devinfo, nid);
if (w == NULL || w->enable == 0)
- return (0);
- /*if (!(w->pflags & HDA_ADC_PATH))
- return (0);
- if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
- w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
- return (0);*/
- /* XXX weak! */
- for (i = 0; i < w->nconns; i++) {
- cw = hdac_widget_get(devinfo, w->conns[i]);
- if (cw == NULL)
- continue;
- if (++child > 1) {
- w->pflags |= HDA_ADC_RECSEL;
- return (1);
+ return (need);
+
+ /* Count number of active inputs. */
+ if (depth > 0) {
+ for (j = 0; j < w->nconns; j++) {
+ if (w->connsenable[j])
+ conns++;
}
}
- for (i = 0; i < w->nconns; i++) {
- if (hdac_audio_ctl_recsel_build(devinfo,
- w->conns[i], depth + 1) != 0)
- return (1);
+
+ /* If this is not a first step - use input mixer.
+ Pins have common input ctl so care must be taken. */
+ if (depth > 0 && ctlable && (conns == 1 ||
+ w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)) {
+ ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_IN,
+ index, 1);
+ if (ctl) {
+ if (HDA_CTL_GIVE(ctl) & need)
+ ctl->ossmask |= (1 << ossdev);
+ else
+ ctl->possmask |= (1 << ossdev);
+ need &= ~HDA_CTL_GIVE(ctl);
+ }
}
- return (0);
+
+ /* If widget has own ossdev - not traverse it.
+ It will be traversed on it's own. */
+ if (w->ossdev >= 0 && depth > 0)
+ return (need);
+
+ /* We must not traverse pin */
+ if ((w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
+ w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) &&
+ depth > 0)
+ return (need);
+
+ /* record that this widget exports such signal, */
+ w->ossmask |= (1 << ossdev);
+
+ /* If signals mixed, we can't assign controls farther.
+ * Ignore this on depth zero. Caller must knows why.
+ * Ignore this for static selectors if this input selected.
+ */
+ if (conns > 1)
+ ctlable = 0;
+
+ if (ctlable) {
+ ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_OUT, -1, 1);
+ if (ctl) {
+ if (HDA_CTL_GIVE(ctl) & need)
+ ctl->ossmask |= (1 << ossdev);
+ else
+ ctl->possmask |= (1 << ossdev);
+ need &= ~HDA_CTL_GIVE(ctl);
+ }
+ }
+
+ rneed = 0;
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ wc = hdac_widget_get(devinfo, i);
+ if (wc == NULL || wc->enable == 0)
+ continue;
+ for (j = 0; j < wc->nconns; j++) {
+ if (wc->connsenable[j] && wc->conns[j] == nid) {
+ rneed |= hdac_audio_ctl_source_amp(devinfo,
+ wc->nid, j, ossdev, ctlable, depth + 1, need);
+ }
+ }
+ }
+ rneed &= need;
+
+ return (rneed);
}
-static int
-hdac_audio_build_tree_strategy(struct hdac_devinfo *devinfo)
+/*
+ * Find controls to control amplification for destination.
+ */
+static void
+hdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid,
+ int ossdev, int depth, int need)
{
- struct hdac_widget *w, *cw;
- int i, j, conndev, found_dac = 0;
- int strategy;
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w, *wc;
+ struct hdac_audio_ctl *ctl;
+ int i, j, consumers;
+
+ if (depth > HDA_PARSE_MAXDEPTH)
+ return;
+
+ w = hdac_widget_get(devinfo, nid);
+ if (w == NULL || w->enable == 0)
+ return;
- strategy = devinfo->function.audio.parsing_strategy;
+ if (depth > 0) {
+ /* If this node produce output for several consumers,
+ we can't touch it. */
+ consumers = 0;
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ wc = hdac_widget_get(devinfo, i);
+ if (wc == NULL || wc->enable == 0)
+ continue;
+ for (j = 0; j < wc->nconns; j++) {
+ if (wc->connsenable[j] && wc->conns[j] == nid)
+ consumers++;
+ }
+ }
+ /* The only exception is if real HP redirection is configured
+ and this is a duplication point.
+ XXX: Actually exception is not completely correct.
+ XXX: Duplication point check is not perfect. */
+ if ((consumers == 2 && (w->bindas < 0 ||
+ as[w->bindas].hpredir < 0 || as[w->bindas].fakeredir ||
+ (w->bindseqmask & (1 << 15)) == 0)) ||
+ consumers > 2)
+ return;
+ /* Else use it's output mixer. */
+ ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
+ HDA_CTL_OUT, -1, 1);
+ if (ctl) {
+ if (HDA_CTL_GIVE(ctl) & need)
+ ctl->ossmask |= (1 << ossdev);
+ else
+ ctl->possmask |= (1 << ossdev);
+ need &= ~HDA_CTL_GIVE(ctl);
+ }
+ }
+
+ /* We must not traverse pin */
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
+ depth > 0)
+ return;
+
+ for (i = 0; i < w->nconns; i++) {
+ int tneed = need;
+ if (w->connsenable[i] == 0)
+ continue;
+ ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
+ HDA_CTL_IN, i, 1);
+ if (ctl) {
+ if (HDA_CTL_GIVE(ctl) & tneed)
+ ctl->ossmask |= (1 << ossdev);
+ else
+ ctl->possmask |= (1 << ossdev);
+ tneed &= ~HDA_CTL_GIVE(ctl);
+ }
+ hdac_audio_ctl_dest_amp(devinfo, w->conns[i], ossdev,
+ depth + 1, tneed);
+ }
+}
+
+/*
+ * Assign OSS names to sound sources
+ */
+static void
+hdac_audio_assign_names(struct hdac_devinfo *devinfo)
+{
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w;
+ int i, j;
+ int type = -1, use, used = 0;
+ static const int types[7][13] = {
+ { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
+ SOUND_MIXER_LINE3, -1 }, /* line */
+ { SOUND_MIXER_MONITOR, SOUND_MIXER_MIC, -1 }, /* int mic */
+ { SOUND_MIXER_MIC, SOUND_MIXER_MONITOR, -1 }, /* ext mic */
+ { SOUND_MIXER_CD, -1 }, /* cd */
+ { SOUND_MIXER_SPEAKER, -1 }, /* speaker */
+ { SOUND_MIXER_DIGITAL1, SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3,
+ -1 }, /* digital */
+ { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
+ SOUND_MIXER_LINE3, SOUND_MIXER_PHONEIN, SOUND_MIXER_PHONEOUT,
+ SOUND_MIXER_VIDEO, SOUND_MIXER_RADIO, SOUND_MIXER_DIGITAL1,
+ SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3, SOUND_MIXER_MONITOR,
+ -1 } /* others */
+ };
+
+ /* Surely known names */
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdac_widget_get(devinfo, i);
if (w == NULL || w->enable == 0)
continue;
+ if (w->bindas == -1)
+ continue;
+ use = -1;
+ switch (w->type) {
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
+ if (as[w->bindas].dir == HDA_CTL_OUT)
+ break;
+ type = -1;
+ switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
+ type = 0;
+ break;
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
+ if ((w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK)
+ == HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
+ break;
+ type = 1;
+ break;
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
+ type = 3;
+ break;
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
+ type = 4;
+ break;
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
+ type = 5;
+ break;
+ }
+ if (type == -1)
+ break;
+ j = 0;
+ while (types[type][j] >= 0 &&
+ (used & (1 << types[type][j])) != 0) {
+ j++;
+ }
+ if (types[type][j] >= 0)
+ use = types[type][j];
+ break;
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
+ use = SOUND_MIXER_PCM;
+ break;
+ case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
+ use = SOUND_MIXER_SPEAKER;
+ break;
+ default:
+ break;
+ }
+ if (use >= 0) {
+ w->ossdev = use;
+ used |= (1 << use);
+ }
+ }
+ /* Semi-known names */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->ossdev >= 0)
+ continue;
+ if (w->bindas == -1)
+ continue;
if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
continue;
- if (!HDA_PARAM_PIN_CAP_OUTPUT_CAP(w->wclass.pin.cap))
+ if (as[w->bindas].dir == HDA_CTL_OUT)
+ continue;
+ type = -1;
+ switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
+ type = 0;
+ break;
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
+ type = 2;
+ break;
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
+ case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
+ type = 5;
+ break;
+ }
+ if (type == -1)
+ break;
+ j = 0;
+ while (types[type][j] >= 0 &&
+ (used & (1 << types[type][j])) != 0) {
+ j++;
+ }
+ if (types[type][j] >= 0) {
+ w->ossdev = types[type][j];
+ used |= (1 << types[type][j]);
+ }
+ }
+ /* Others */
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (w->ossdev >= 0)
continue;
- conndev = w->wclass.pin.config &
- HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
- if (!(conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
- conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
- conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT))
+ if (w->bindas == -1)
continue;
- for (j = 0; j < w->nconns; j++) {
- cw = hdac_widget_get(devinfo, w->conns[j]);
- if (cw == NULL || cw->enable == 0)
- continue;
- if (strategy == HDA_PARSE_MIXER && !(cw->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
- cw->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
- continue;
- if (hdac_widget_find_dac_path(devinfo, cw->nid, 0)
- != 0) {
- if (w->selconn == -1)
- w->selconn = j;
- w->pflags |= HDA_DAC_PATH;
- found_dac++;
- }
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ if (as[w->bindas].dir == HDA_CTL_OUT)
+ continue;
+ j = 0;
+ while (types[6][j] >= 0 &&
+ (used & (1 << types[6][j])) != 0) {
+ j++;
+ }
+ if (types[6][j] >= 0) {
+ w->ossdev = types[6][j];
+ used |= (1 << types[6][j]);
}
}
-
- return (found_dac);
}
static void
hdac_audio_build_tree(struct hdac_devinfo *devinfo)
{
- struct hdac_widget *w;
- struct hdac_audio_ctl *ctl;
- int i, j, dacs, strategy;
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ int j, res;
- /* Construct DAC path */
- strategy = HDA_PARSE_MIXER;
- devinfo->function.audio.parsing_strategy = strategy;
HDA_BOOTVERBOSE(
device_printf(devinfo->codec->sc->dev,
- "HDA_DEBUG: HWiP: HDA Widget Parser - Revision %d\n",
+ "HWiP: HDA Widget Parser - Revision %d\n",
HDA_WIDGET_PARSER_REV);
);
- dacs = hdac_audio_build_tree_strategy(devinfo);
- if (dacs == 0) {
+
+ /* Trace all associations in order of their numbers, */
+ for (j = 0; j < devinfo->function.audio.ascnt; j++) {
+ if (as[j].enable == 0)
+ continue;
HDA_BOOTVERBOSE(
device_printf(devinfo->codec->sc->dev,
- "HDA_DEBUG: HWiP: 0 DAC path found! "
- "Retrying parser "
- "using HDA_PARSE_DIRECT strategy.\n");
+ "Tracing association %d (%d)\n", j, as[j].index);
);
- strategy = HDA_PARSE_DIRECT;
- devinfo->function.audio.parsing_strategy = strategy;
- dacs = hdac_audio_build_tree_strategy(devinfo);
+ if (as[j].dir == HDA_CTL_OUT) {
+retry:
+ res = hdac_audio_trace_as_out(devinfo, j, 0);
+ if (res == 0 && as[j].hpredir >= 0 &&
+ as[j].fakeredir == 0) {
+ /* If codec can't do analog HP redirection
+ try to make it using one more DAC. */
+ as[j].fakeredir = 1;
+ goto retry;
+ }
+ } else {
+ res = hdac_audio_trace_as_in(devinfo, j);
+ }
+ if (res) {
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ "Association %d (%d) trace succeded\n",
+ j, as[j].index);
+ );
+ } else {
+ HDA_BOOTVERBOSE(
+ device_printf(devinfo->codec->sc->dev,
+ "Association %d (%d) trace failed\n",
+ j, as[j].index);
+ );
+ as[j].enable = 0;
+ }
}
- HDA_BOOTVERBOSE(
- device_printf(devinfo->codec->sc->dev,
- "HDA_DEBUG: HWiP: Found %d DAC path using HDA_PARSE_%s "
- "strategy.\n",
- dacs, (strategy == HDA_PARSE_MIXER) ? "MIXER" : "DIRECT");
- );
+ /* Trace mixer and beeper pseudo associations. */
+ hdac_audio_trace_as_extra(devinfo);
+}
- /* Construct ADC path */
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
- continue;
- if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
- continue;
- (void)hdac_widget_find_adc_path(devinfo, w->nid, 0);
- }
+static void
+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;
- /* Output mixers */
+ /* Assign mixers to the tree. */
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdac_widget_get(devinfo, i);
if (w == NULL || w->enable == 0)
continue;
- if ((strategy == HDA_PARSE_MIXER &&
- (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
- w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
- && (w->pflags & HDA_DAC_PATH)) ||
- (strategy == HDA_PARSE_DIRECT && (w->pflags &
- (HDA_DAC_PATH | HDA_ADC_PATH)))) {
- w->ctlflags |= hdac_audio_ctl_outamp_build(devinfo,
- w->nid, devinfo->startnode - 1, 0, 0);
- } else if (w->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
- j = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &j)) !=
- NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL)
- continue;
- if (ctl->widget->nid != w->nid)
- continue;
- ctl->ossmask |= SOUND_MASK_VOLUME;
- ctl->ossmask |= SOUND_MASK_SPEAKER;
- ctl->ossdev = SOUND_MIXER_SPEAKER;
- w->ctlflags |= SOUND_MASK_VOLUME;
- w->ctlflags |= SOUND_MASK_SPEAKER;
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
+ w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET ||
+ (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
+ as[w->bindas].dir == HDA_CTL_IN)) {
+ if (w->ossdev < 0)
+ 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,
+ 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,
+ SOUND_MIXER_VOLUME, 0, 1);
}
}
+ /* Treat unrequired as possible. */
+ i = 0;
+ while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
+ if (ctl->ossmask == 0)
+ ctl->ossmask = ctl->possmask;
+ }
+}
- /* Input mixers (rec) */
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0)
+static void
+hdac_audio_prepare_pin_ctrl(struct hdac_devinfo *devinfo)
+{
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w;
+ uint32_t pincap;
+ int i;
+
+ for (i = 0; i < devinfo->nodecnt; i++) {
+ w = &devinfo->widget[i];
+ if (w == NULL)
+ continue;
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
continue;
- if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
- w->pflags & HDA_ADC_PATH))
+
+ pincap = w->wclass.pin.cap;
+
+ /* Disable everything. */
+ w->wclass.pin.ctrl &= ~(
+ HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
+ HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
+ HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
+ HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
+
+ if (w->enable == 0 ||
+ w->bindas < 0 || as[w->bindas].enable == 0) {
+ /* Pin is unused so left it disabled. */
continue;
- hdac_audio_ctl_inamp_build(devinfo, w->nid, 0);
- hdac_audio_ctl_recsel_build(devinfo, w->nid, 0);
+ } else if (as[w->bindas].dir == HDA_CTL_IN) {
+ /* Input pin, configure for input. */
+ if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
+
+ if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) &&
+ HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
+ HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
+ else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) &&
+ HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
+ HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
+ else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) &&
+ HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
+ HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
+ } else {
+ /* Output pin, configure for output. */
+ if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
+
+ if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap) &&
+ (w->wclass.pin.config &
+ HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
+ HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
+
+ if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) &&
+ HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
+ HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
+ else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) &&
+ HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
+ HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
+ else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) &&
+ HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
+ w->wclass.pin.ctrl |=
+ HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
+ HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
+ }
}
}
-#define HDA_COMMIT_CONN (1 << 0)
-#define HDA_COMMIT_CTRL (1 << 1)
-#define HDA_COMMIT_EAPD (1 << 2)
-#define HDA_COMMIT_GPIO (1 << 3)
-#define HDA_COMMIT_MISC (1 << 4)
-#define HDA_COMMIT_ALL (HDA_COMMIT_CONN | HDA_COMMIT_CTRL | \
- HDA_COMMIT_EAPD | HDA_COMMIT_GPIO | HDA_COMMIT_MISC)
-
static void
-hdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl)
+hdac_audio_commit(struct hdac_devinfo *devinfo)
{
struct hdac_softc *sc = devinfo->codec->sc;
struct hdac_widget *w;
nid_t cad;
+ uint32_t gdata, gmask, gdir;
+ int commitgpio, numgpio;
int i;
- if (!(cfl & HDA_COMMIT_ALL))
- return;
-
cad = devinfo->codec->cad;
- if ((cfl & HDA_COMMIT_MISC)) {
- if (sc->pci_subvendor == APPLE_INTEL_MAC)
- hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid,
- 0x7e7, 0), cad);
- }
-
- if (cfl & HDA_COMMIT_GPIO) {
- uint32_t gdata, gmask, gdir;
- int commitgpio, numgpio;
+ if (sc->pci_subvendor == APPLE_INTEL_MAC)
+ hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid,
+ 0x7e7, 0), cad);
- gdata = 0;
- gmask = 0;
- gdir = 0;
- commitgpio = 0;
+ gdata = 0;
+ gmask = 0;
+ gdir = 0;
+ commitgpio = 0;
- numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO(
- devinfo->function.audio.gpio);
+ numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO(
+ devinfo->function.audio.gpio);
- if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH)
- commitgpio = (numgpio > 0) ? 1 : 0;
- else {
- for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) {
- if (!(devinfo->function.audio.quirks &
- (1 << i)))
- continue;
- if (commitgpio == 0) {
- commitgpio = 1;
- HDA_BOOTVERBOSE(
- gdata = hdac_command(sc,
- HDA_CMD_GET_GPIO_DATA(cad,
- devinfo->nid), cad);
- gmask = hdac_command(sc,
- HDA_CMD_GET_GPIO_ENABLE_MASK(cad,
- devinfo->nid), cad);
- gdir = hdac_command(sc,
- HDA_CMD_GET_GPIO_DIRECTION(cad,
- devinfo->nid), cad);
- device_printf(sc->dev,
- "GPIO init: data=0x%08x "
- "mask=0x%08x dir=0x%08x\n",
- gdata, gmask, gdir);
- gdata = 0;
- gmask = 0;
- gdir = 0;
- );
- }
- gdata |= 1 << i;
- gmask |= 1 << i;
- gdir |= 1 << i;
+ if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH)
+ commitgpio = (numgpio > 0) ? 1 : 0;
+ else {
+ for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) {
+ if (!(devinfo->function.audio.quirks &
+ (1 << i)))
+ continue;
+ if (commitgpio == 0) {
+ commitgpio = 1;
+ HDA_BOOTVERBOSE(
+ gdata = hdac_command(sc,
+ HDA_CMD_GET_GPIO_DATA(cad,
+ devinfo->nid), cad);
+ gmask = hdac_command(sc,
+ HDA_CMD_GET_GPIO_ENABLE_MASK(cad,
+ devinfo->nid), cad);
+ gdir = hdac_command(sc,
+ HDA_CMD_GET_GPIO_DIRECTION(cad,
+ devinfo->nid), cad);
+ device_printf(sc->dev,
+ "GPIO init: data=0x%08x "
+ "mask=0x%08x dir=0x%08x\n",
+ gdata, gmask, gdir);
+ gdata = 0;
+ gmask = 0;
+ gdir = 0;
+ );
}
+ gdata |= 1 << i;
+ gmask |= 1 << i;
+ gdir |= 1 << i;
}
+ }
- if (commitgpio != 0) {
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "GPIO commit: data=0x%08x mask=0x%08x "
- "dir=0x%08x\n",
- gdata, gmask, gdir);
- );
- hdac_command(sc,
- HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid,
- gmask), cad);
- hdac_command(sc,
- HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid,
- gdir), cad);
- hdac_command(sc,
- HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid,
- gdata), cad);
- }
+ if (commitgpio != 0) {
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "GPIO commit: data=0x%08x mask=0x%08x "
+ "dir=0x%08x\n",
+ gdata, gmask, gdir);
+ );
+ hdac_command(sc,
+ HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid,
+ gmask), cad);
+ hdac_command(sc,
+ HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid,
+ gdir), cad);
+ hdac_command(sc,
+ HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid,
+ gdata), cad);
}
for (i = 0; i < devinfo->nodecnt; i++) {
w = &devinfo->widget[i];
- if (w == NULL || w->enable == 0)
+ if (w == NULL)
continue;
- if (cfl & HDA_COMMIT_CONN) {
- if (w->selconn == -1)
- w->selconn = 0;
- if (w->nconns > 0)
- hdac_widget_connection_select(w, w->selconn);
- }
- if ((cfl & HDA_COMMIT_CTRL) &&
- w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
- uint32_t pincap;
-
- pincap = w->wclass.pin.cap;
-
- if ((w->pflags & (HDA_DAC_PATH | HDA_ADC_PATH)) ==
- (HDA_DAC_PATH | HDA_ADC_PATH))
- device_printf(sc->dev, "WARNING: node %d "
- "participate both for DAC/ADC!\n", w->nid);
- if (w->pflags & HDA_DAC_PATH) {
- w->wclass.pin.ctrl &=
- ~HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
- if ((w->wclass.pin.config &
- HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) !=
- HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
- w->wclass.pin.ctrl &=
- ~HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
- if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) &&
- HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
- w->wclass.pin.ctrl |=
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
- HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
- else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) &&
- HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
- w->wclass.pin.ctrl |=
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
- HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
- else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) &&
- HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
- w->wclass.pin.ctrl |=
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
- HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
- } else if (w->pflags & HDA_ADC_PATH) {
- w->wclass.pin.ctrl &=
- ~(HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
- HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE);
- if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) &&
- HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
- w->wclass.pin.ctrl |=
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
- HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
- else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) &&
- HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
- w->wclass.pin.ctrl |=
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
- HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
- else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) &&
- HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
- w->wclass.pin.ctrl |=
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
- HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
- } else
- w->wclass.pin.ctrl &= ~(
- HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
- HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
- HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
- HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
+ if (w->selconn == -1)
+ w->selconn = 0;
+ if (w->nconns > 0)
+ hdac_widget_connection_select(w, w->selconn);
+ if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
hdac_command(sc,
HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
w->wclass.pin.ctrl), cad);
}
- if ((cfl & HDA_COMMIT_EAPD) &&
- w->param.eapdbtl != HDAC_INVALID) {
+ if (w->param.eapdbtl != HDAC_INVALID) {
uint32_t val;
val = w->param.eapdbtl;
@@ -5298,64 +5904,54 @@ hdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl)
static void
hdac_audio_ctl_commit(struct hdac_devinfo *devinfo)
{
- struct hdac_softc *sc = devinfo->codec->sc;
struct hdac_audio_ctl *ctl;
- int i;
+ int i, z;
- devinfo->function.audio.mvol = 100 | (100 << 8);
i = 0;
while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL) {
- HDA_BOOTVERBOSE(
- device_printf(sc->dev, "[%2d] Ctl nid=%d",
- i, (ctl->widget != NULL) ?
- ctl->widget->nid : -1);
- if (ctl->childwidget != NULL)
- printf(" childnid=%d",
- ctl->childwidget->nid);
- if (ctl->widget == NULL)
- printf(" NULL WIDGET!");
- printf(" DISABLED\n");
- );
+ if (ctl->enable == 0) {
+ /* Mute disabled controls. */
+ hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_ALL, 0, 0);
continue;
}
- HDA_BOOTVERBOSE(
- if (ctl->ossmask == 0) {
- device_printf(sc->dev, "[%2d] Ctl nid=%d",
- i, ctl->widget->nid);
- if (ctl->childwidget != NULL)
- printf(" childnid=%d",
- ctl->childwidget->nid);
- printf(" Bind to NONE\n");
- }
- );
- if (ctl->step > 0) {
- ctl->ossval = (ctl->left * 100) / ctl->step;
- ctl->ossval |= ((ctl->right * 100) / ctl->step) << 8;
- } else
- ctl->ossval = 0;
- hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT,
- ctl->left, ctl->right);
+ /* Init controls to 0dB amplification. */
+ z = ctl->offset;
+ if (z > ctl->step)
+ z = ctl->step;
+ hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_NONE, z, z);
}
}
-static int
-hdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir)
+static void
+hdac_powerup(struct hdac_devinfo *devinfo)
{
- struct hdac_chan *ch;
- struct hdac_widget *w;
- uint32_t cap, fmtcap, pcmcap, path;
- int i, type, ret, max;
+ struct hdac_softc *sc = devinfo->codec->sc;
+ nid_t cad = devinfo->codec->cad;
+ int i;
- if (dir == PCMDIR_PLAY) {
- type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT;
- ch = &devinfo->codec->sc->play;
- path = HDA_DAC_PATH;
- } else {
- type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT;
- ch = &devinfo->codec->sc->rec;
- path = HDA_ADC_PATH;
+ hdac_command(sc,
+ HDA_CMD_SET_POWER_STATE(cad,
+ devinfo->nid, HDA_CMD_POWER_STATE_D0),
+ cad);
+ DELAY(100);
+
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ hdac_command(sc,
+ HDA_CMD_SET_POWER_STATE(cad,
+ i, HDA_CMD_POWER_STATE_D0),
+ cad);
}
+ DELAY(1000);
+}
+
+static int
+hdac_pcmchannel_setup(struct hdac_chan *ch)
+{
+ struct hdac_devinfo *devinfo = ch->devinfo;
+ struct hdac_audio_as *as = devinfo->function.audio.as;
+ struct hdac_widget *w;
+ uint32_t cap, fmtcap, pcmcap;
+ int i, j, ret, max;
ch->caps = hdac_caps;
ch->caps.fmtlist = ch->fmtlist;
@@ -5369,31 +5965,44 @@ hdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir)
pcmcap = devinfo->function.audio.supp_pcm_size_rate;
max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1;
- for (i = devinfo->startnode; i < devinfo->endnode && ret < max; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL || w->enable == 0 || w->type != type ||
- !(w->pflags & path))
+ for (i = 0; i < 16 && ret < max; i++) {
+ /* Check as is correct */
+ if (ch->as < 0)
+ break;
+ /* Cound only present DACs */
+ if (as[ch->as].dacs[i] <= 0)
+ continue;
+ /* Ignore duplicates */
+ for (j = 0; j < ret; j++) {
+ if (ch->io[j] == as[ch->as].dacs[i])
+ break;
+ }
+ if (j < ret)
continue;
- cap = w->param.widget_cap;
- /*if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(cap))
- continue;*/
- if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(cap))
+
+ w = hdac_widget_get(devinfo, as[ch->as].dacs[i]);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap))
continue;
cap = w->param.supp_stream_formats;
- /*if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) {
- }
- if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) {
+ /*if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) {
}*/
- if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
+ if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap) &&
+ !HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
continue;
+ /* Many codec does not declare AC3 support on SPDIF.
+ I don't beleave that they doesn't support it! */
+ if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
+ cap |= HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK;
if (ret == 0) {
- fmtcap = w->param.supp_stream_formats;
+ fmtcap = cap;
pcmcap = w->param.supp_pcm_size_rate;
} else {
- fmtcap &= w->param.supp_stream_formats;
+ fmtcap &= cap;
pcmcap &= w->param.supp_pcm_size_rate;
}
- ch->io[ret++] = i;
+ ch->io[ret++] = as[ch->as].dacs[i];
}
ch->io[ret] = -1;
@@ -5408,52 +6017,56 @@ hdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir)
* 32bit = 4
*/
if (ret > 0) {
- cap = pcmcap;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
- ch->bit16 = 1;
- else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
- ch->bit16 = 0;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
- ch->bit32 = 4;
- else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
- ch->bit32 = 3;
- else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
- ch->bit32 = 2;
i = 0;
- if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO))
- ch->fmtlist[i++] = AFMT_S16_LE;
- ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO;
- if (ch->bit32 > 0) {
- if (!(devinfo->function.audio.quirks &
- HDA_QUIRK_FORCESTEREO))
- ch->fmtlist[i++] = AFMT_S32_LE;
- ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO;
+ if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(fmtcap)) {
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(pcmcap))
+ ch->bit16 = 1;
+ else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(pcmcap))
+ ch->bit16 = 0;
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(pcmcap))
+ ch->bit32 = 4;
+ else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(pcmcap))
+ ch->bit32 = 3;
+ else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(pcmcap))
+ ch->bit32 = 2;
+ if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO))
+ ch->fmtlist[i++] = AFMT_S16_LE;
+ ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO;
+ if (ch->bit32 > 0) {
+ if (!(devinfo->function.audio.quirks &
+ HDA_QUIRK_FORCESTEREO))
+ ch->fmtlist[i++] = AFMT_S32_LE;
+ ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO;
+ }
+ }
+ if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(fmtcap)) {
+ ch->fmtlist[i++] = AFMT_AC3;
}
ch->fmtlist[i] = 0;
i = 0;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(pcmcap))
ch->pcmrates[i++] = 8000;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(pcmcap))
ch->pcmrates[i++] = 11025;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(pcmcap))
ch->pcmrates[i++] = 16000;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(pcmcap))
ch->pcmrates[i++] = 22050;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(pcmcap))
ch->pcmrates[i++] = 32000;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(pcmcap))
ch->pcmrates[i++] = 44100;
- /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(cap)) */
+ /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(pcmcap)) */
ch->pcmrates[i++] = 48000;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(pcmcap))
ch->pcmrates[i++] = 88200;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(pcmcap))
ch->pcmrates[i++] = 96000;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(pcmcap))
ch->pcmrates[i++] = 176400;
- if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
+ if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(pcmcap))
ch->pcmrates[i++] = 192000;
- /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(cap)) */
+ /* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(pcmcap)) */
ch->pcmrates[i] = 0;
if (i > 0) {
ch->caps.minspeed = ch->pcmrates[0];
@@ -5465,74 +6078,80 @@ hdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir)
}
static void
-hdac_dump_ctls(struct hdac_devinfo *devinfo, const char *banner, uint32_t flag)
+hdac_dump_ctls(struct hdac_pcm_devinfo *pdevinfo, const char *banner, uint32_t flag)
{
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_audio_ctl *ctl;
struct hdac_softc *sc = devinfo->codec->sc;
- int i;
- uint32_t fl = 0;
-
+ char buf[64];
+ int i, j, printed;
if (flag == 0) {
- fl = SOUND_MASK_VOLUME | SOUND_MASK_PCM |
+ flag = ~(SOUND_MASK_VOLUME | SOUND_MASK_PCM |
SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV |
- SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN;
+ SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN |
+ SOUND_MASK_IMIX | SOUND_MASK_MONITOR);
}
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL ||
- ctl->widget->enable == 0 || (ctl->ossmask &
- (SOUND_MASK_SKIP | SOUND_MASK_DISABLE)))
+ for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
+ if ((flag & (1 << j)) == 0)
continue;
- if ((flag == 0 && (ctl->ossmask & ~fl)) ||
- (flag != 0 && (ctl->ossmask & flag))) {
- if (banner != NULL) {
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "%s\n", banner);
- }
- goto hdac_ctl_dump_it_all;
- }
- }
-
- return;
+ i = 0;
+ printed = 0;
+ while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
+ if (ctl->enable == 0 ||
+ ctl->widget->enable == 0)
+ continue;
+ if (!((pdevinfo->play >= 0 &&
+ ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
+ (pdevinfo->rec >= 0 &&
+ ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
+ (ctl->widget->bindas == -2 && pdevinfo->index == 0)))
+ continue;
+ if ((ctl->ossmask & (1 << j)) == 0)
+ continue;
-hdac_ctl_dump_it_all:
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->enable == 0 || ctl->widget == NULL ||
- ctl->widget->enable == 0)
- continue;
- if (!((flag == 0 && (ctl->ossmask & ~fl)) ||
- (flag != 0 && (ctl->ossmask & flag))))
- continue;
- if (flag == 0) {
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "Unknown Ctl (OSS: %s)\n",
- hdac_audio_ctl_ossmixer_mask2name(ctl->ossmask));
+ if (printed == 0) {
+ device_printf(pdevinfo->dev, "\n");
+ if (banner != NULL) {
+ device_printf(pdevinfo->dev, "%s", banner);
+ } else {
+ device_printf(pdevinfo->dev, "Unknown Ctl");
+ }
+ printf(" (OSS: %s)\n",
+ hdac_audio_ctl_ossmixer_mask2allname(1 << j,
+ buf, sizeof(buf)));
+ device_printf(pdevinfo->dev, " |\n");
+ printed = 1;
+ }
+ device_printf(pdevinfo->dev, " +- ctl %2d (nid %3d %s", i,
+ ctl->widget->nid,
+ (ctl->ndir == HDA_CTL_IN)?"in ":"out");
+ if (ctl->ndir == HDA_CTL_IN && ctl->ndir == ctl->dir)
+ printf(" %2d): ", ctl->index);
+ else
+ printf("): ");
+ if (ctl->step > 0) {
+ printf("%+d/%+ddB (%d steps)%s\n",
+ (0 - ctl->offset) * (ctl->size + 1) / 4,
+ (ctl->step - ctl->offset) * (ctl->size + 1) / 4,
+ ctl->step + 1,
+ ctl->mute?" + mute":"");
+ } else
+ printf("%s\n", ctl->mute?"mute":"");
}
- device_printf(sc->dev, " |\n");
- device_printf(sc->dev, " +- nid: %2d index: %2d ",
- ctl->widget->nid, ctl->index);
- if (ctl->childwidget != NULL)
- printf("(nid: %2d) ", ctl->childwidget->nid);
- else
- printf(" ");
- printf("mute: %d step: %3d size: %3d off: %3d dir=0x%x ossmask=0x%08x\n",
- ctl->mute, ctl->step, ctl->size, ctl->offset, ctl->dir,
- ctl->ossmask);
}
}
static void
-hdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap)
+hdac_dump_audio_formats(device_t dev, uint32_t fcap, uint32_t pcmcap)
{
uint32_t cap;
cap = fcap;
if (cap != 0) {
- device_printf(sc->dev, " Stream cap: 0x%08x\n", cap);
- device_printf(sc->dev, " Format:");
+ device_printf(dev, " Stream cap: 0x%08x\n", cap);
+ device_printf(dev, " Format:");
if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
printf(" AC3");
if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap))
@@ -5543,8 +6162,8 @@ hdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap)
}
cap = pcmcap;
if (cap != 0) {
- device_printf(sc->dev, " PCM cap: 0x%08x\n", cap);
- device_printf(sc->dev, " PCM size:");
+ device_printf(dev, " PCM cap: 0x%08x\n", cap);
+ device_printf(dev, " PCM size:");
if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
printf(" 8");
if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
@@ -5556,7 +6175,7 @@ hdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap)
if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
printf(" 32");
printf("\n");
- device_printf(sc->dev, " PCM rate:");
+ device_printf(dev, " PCM rate:");
if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
printf(" 8");
if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
@@ -5634,10 +6253,47 @@ hdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w)
printf(" IN");
if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
printf(" OUT");
+ if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK)
+ printf(" VREFs");
printf("\n");
}
static void
+hdac_dump_pin_config(struct hdac_widget *w, uint32_t conf)
+{
+ struct hdac_softc *sc = w->devinfo->codec->sc;
+
+ device_printf(sc->dev, "nid %d 0x%08x as %2d seq %2d %13s %5s "
+ "jack %2d loc %2d color %7s misc %d%s\n",
+ w->nid, conf,
+ HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf),
+ HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf),
+ HDA_DEVS[HDA_CONFIG_DEFAULTCONF_DEVICE(conf)],
+ HDA_CONNS[HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf)],
+ HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf),
+ HDA_CONFIG_DEFAULTCONF_LOCATION(conf),
+ HDA_COLORS[HDA_CONFIG_DEFAULTCONF_COLOR(conf)],
+ HDA_CONFIG_DEFAULTCONF_MISC(conf),
+ (w->enable == 0)?" [DISABLED]":"");
+}
+
+static void
+hdac_dump_pin_configs(struct hdac_devinfo *devinfo)
+{
+ struct hdac_widget *w;
+ int i;
+
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL)
+ continue;
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ hdac_dump_pin_config(w, w->wclass.pin.config);
+ }
+}
+
+static void
hdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner)
{
device_printf(sc->dev, " %s amp: 0x%08x\n", banner, cap);
@@ -5653,13 +6309,15 @@ static void
hdac_dump_nodes(struct hdac_devinfo *devinfo)
{
struct hdac_softc *sc = devinfo->codec->sc;
+ static char *ossname[] = SOUND_DEVICE_NAMES;
struct hdac_widget *w, *cw;
+ char buf[64];
int i, j;
device_printf(sc->dev, "\n");
device_printf(sc->dev, "Default Parameter\n");
device_printf(sc->dev, "-----------------\n");
- hdac_dump_audio_formats(sc,
+ hdac_dump_audio_formats(sc->dev,
devinfo->function.audio.supp_stream_formats,
devinfo->function.audio.supp_pcm_size_rate);
device_printf(sc->dev, " IN amp: 0x%08x\n",
@@ -5680,13 +6338,18 @@ hdac_dump_nodes(struct hdac_devinfo *devinfo)
device_printf(sc->dev, " name: %s\n", w->name);
device_printf(sc->dev, " widget_cap: 0x%08x\n",
w->param.widget_cap);
- device_printf(sc->dev, " Parse flags: 0x%08x\n",
+ device_printf(sc->dev, " Parse flags: 0x%x\n",
w->pflags);
- device_printf(sc->dev, " Ctl flags: 0x%08x\n",
- w->ctlflags);
+ device_printf(sc->dev, " Association: %d (0x%08x)\n",
+ w->bindas, w->bindseqmask);
+ device_printf(sc->dev, " OSS: %s",
+ hdac_audio_ctl_ossmixer_mask2allname(w->ossmask, buf, sizeof(buf)));
+ if (w->ossdev >= 0)
+ printf(" (%s)", ossname[w->ossdev]);
+ printf("\n");
if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
- hdac_dump_audio_formats(sc,
+ hdac_dump_audio_formats(sc->dev,
w->param.supp_stream_formats,
w->param.supp_pcm_size_rate);
} else if (w->type ==
@@ -5702,10 +6365,12 @@ hdac_dump_nodes(struct hdac_devinfo *devinfo)
w->param.inamp_cap != 0)
hdac_dump_amp(sc, w->param.inamp_cap, " Input");
device_printf(sc->dev, " connections: %d\n", w->nconns);
+ if (w->nconns > 0)
+ device_printf(sc->dev, " |\n");
for (j = 0; j < w->nconns; j++) {
cw = hdac_widget_get(devinfo, w->conns[j]);
- device_printf(sc->dev, " |\n");
- device_printf(sc->dev, " + <- nid=%d [%s]",
+ device_printf(sc->dev, " + %s<- nid=%d [%s]",
+ (w->connsenable[j] == 0)?"[DISABLED] ":"",
w->conns[j], (cw == NULL) ? "GHOST!" : cw->name);
if (cw == NULL)
printf(" [UNKNOWN]");
@@ -5720,142 +6385,171 @@ hdac_dump_nodes(struct hdac_devinfo *devinfo)
}
-static int
-hdac_dump_dac_internal(struct hdac_devinfo *devinfo, nid_t nid, int depth)
+static void
+hdac_dump_dst_nid(struct hdac_pcm_devinfo *pdevinfo, nid_t nid, int depth)
{
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_widget *w, *cw;
- struct hdac_softc *sc = devinfo->codec->sc;
- int i;
+ char buf[64];
+ int i, printed = 0;
if (depth > HDA_PARSE_MAXDEPTH)
- return (0);
+ return;
w = hdac_widget_get(devinfo, nid);
- if (w == NULL || w->enable == 0 || !(w->pflags & HDA_DAC_PATH))
- return (0);
+ if (w == NULL || w->enable == 0)
+ return;
- if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, " nid=%d [%s]\n", w->nid, w->name);
- device_printf(sc->dev, " ^\n");
- device_printf(sc->dev, " |\n");
- device_printf(sc->dev, " +-----<------+\n");
- } else {
- device_printf(sc->dev, " ^\n");
- device_printf(sc->dev, " |\n");
- device_printf(sc->dev, " ");
- printf(" nid=%d [%s]\n", w->nid, w->name);
- }
+ if (depth == 0)
+ device_printf(pdevinfo->dev, "%*s", 4, "");
+ else
+ device_printf(pdevinfo->dev, "%*s + <- ", 4 + (depth - 1) * 7, "");
+ printf("nid=%d [%s]", w->nid, w->name);
- if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) {
- return (1);
- } else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) {
- for (i = 0; i < w->nconns; i++) {
- cw = hdac_widget_get(devinfo, w->conns[i]);
- if (cw == NULL || cw->enable == 0 || cw->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
- continue;
- if (hdac_dump_dac_internal(devinfo, cw->nid,
- depth + 1) != 0)
- return (1);
+ if (depth > 0) {
+ if (w->ossmask == 0) {
+ printf("\n");
+ return;
+ }
+ printf(" [src: %s]",
+ hdac_audio_ctl_ossmixer_mask2allname(
+ w->ossmask, buf, sizeof(buf)));
+ if (w->ossdev >= 0) {
+ printf("\n");
+ return;
}
- } else if ((w->type ==
- HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR ||
- w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) &&
- w->selconn > -1 && w->selconn < w->nconns) {
- if (hdac_dump_dac_internal(devinfo, w->conns[w->selconn],
- depth + 1) != 0)
- return (1);
+ }
+ printf("\n");
+
+ for (i = 0; i < w->nconns; i++) {
+ if (w->connsenable[i] == 0)
+ continue;
+ cw = hdac_widget_get(devinfo, w->conns[i]);
+ if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
+ continue;
+ if (printed == 0) {
+ device_printf(pdevinfo->dev, "%*s |\n", 4 + (depth) * 7, "");
+ printed = 1;
+ }
+ hdac_dump_dst_nid(pdevinfo, w->conns[i], depth + 1);
}
- return (0);
}
static void
-hdac_dump_dac(struct hdac_devinfo *devinfo)
+hdac_dump_dac(struct hdac_pcm_devinfo *pdevinfo)
{
- struct hdac_widget *w;
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_softc *sc = devinfo->codec->sc;
+ struct hdac_widget *w;
int i, printed = 0;
+ if (pdevinfo->play < 0)
+ return;
+
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdac_widget_get(devinfo, i);
if (w == NULL || w->enable == 0)
continue;
- if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
- !(w->pflags & HDA_DAC_PATH))
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+ continue;
+ if (w->bindas != sc->chans[pdevinfo->play].as)
continue;
if (printed == 0) {
printed = 1;
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "Playback path:\n");
+ device_printf(pdevinfo->dev, "\n");
+ device_printf(pdevinfo->dev, "Playback:\n");
}
- hdac_dump_dac_internal(devinfo, w->nid, 0);
+ device_printf(pdevinfo->dev, "\n");
+ hdac_dump_dst_nid(pdevinfo, i, 0);
}
}
static void
-hdac_dump_adc(struct hdac_devinfo *devinfo)
+hdac_dump_adc(struct hdac_pcm_devinfo *pdevinfo)
{
- struct hdac_widget *w, *cw;
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
struct hdac_softc *sc = devinfo->codec->sc;
- int i, j;
+ struct hdac_widget *w;
+ int i;
int printed = 0;
- char ossdevs[256];
+
+ if (pdevinfo->rec < 0)
+ return;
for (i = devinfo->startnode; i < devinfo->endnode; i++) {
w = hdac_widget_get(devinfo, i);
if (w == NULL || w->enable == 0)
continue;
- if (!(w->pflags & HDA_ADC_RECSEL))
+ if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
+ continue;
+ if (w->bindas != sc->chans[pdevinfo->rec].as)
continue;
if (printed == 0) {
printed = 1;
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "Recording sources:\n");
+ device_printf(pdevinfo->dev, "\n");
+ device_printf(pdevinfo->dev, "Record:\n");
}
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, " nid=%d [%s]\n", w->nid, w->name);
- for (j = 0; j < w->nconns; j++) {
- cw = hdac_widget_get(devinfo, w->conns[j]);
- if (cw == NULL || cw->enable == 0)
- continue;
- hdac_audio_ctl_ossmixer_mask2allname(cw->ctlflags,
- ossdevs, sizeof(ossdevs));
- device_printf(sc->dev, " |\n");
- device_printf(sc->dev, " + <- nid=%d [%s]",
- cw->nid, cw->name);
- if (strlen(ossdevs) > 0) {
- printf(" [recsrc: %s]", ossdevs);
- }
- printf("\n");
+ device_printf(pdevinfo->dev, "\n");
+ hdac_dump_dst_nid(pdevinfo, i, 0);
+ }
+}
+
+static void
+hdac_dump_mix(struct hdac_pcm_devinfo *pdevinfo)
+{
+ struct hdac_devinfo *devinfo = pdevinfo->devinfo;
+ struct hdac_widget *w;
+ int i;
+ int printed = 0;
+
+ if (pdevinfo->index != 0)
+ return;
+
+ for (i = devinfo->startnode; i < devinfo->endnode; i++) {
+ w = hdac_widget_get(devinfo, i);
+ if (w == NULL || w->enable == 0)
+ continue;
+ if ((w->pflags & HDA_ADC_MONITOR) == 0)
+ continue;
+ if (printed == 0) {
+ printed = 1;
+ device_printf(pdevinfo->dev, "\n");
+ device_printf(pdevinfo->dev, "Input Mix:\n");
}
+ device_printf(pdevinfo->dev, "\n");
+ hdac_dump_dst_nid(pdevinfo, i, 0);
}
}
static void
-hdac_dump_pcmchannels(struct hdac_softc *sc, int pcnt, int rcnt)
+hdac_dump_pcmchannels(struct hdac_pcm_devinfo *pdevinfo)
{
+ struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
nid_t *nids;
+ int i;
- if (pcnt > 0) {
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, " PCM Playback: %d\n", pcnt);
- hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
- sc->play.supp_pcm_size_rate);
- device_printf(sc->dev, " DAC:");
- for (nids = sc->play.io; *nids != -1; nids++)
+ if (pdevinfo->play >= 0) {
+ i = pdevinfo->play;
+ device_printf(pdevinfo->dev, "\n");
+ device_printf(pdevinfo->dev, "Playback:\n");
+ device_printf(pdevinfo->dev, "\n");
+ hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
+ sc->chans[i].supp_pcm_size_rate);
+ device_printf(pdevinfo->dev, " DAC:");
+ for (nids = sc->chans[i].io; *nids != -1; nids++)
printf(" %d", *nids);
printf("\n");
}
-
- if (rcnt > 0) {
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, " PCM Record: %d\n", rcnt);
- hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
- sc->rec.supp_pcm_size_rate);
- device_printf(sc->dev, " ADC:");
- for (nids = sc->rec.io; *nids != -1; nids++)
+ if (pdevinfo->rec >= 0) {
+ i = pdevinfo->rec;
+ device_printf(pdevinfo->dev, "\n");
+ device_printf(pdevinfo->dev, "Record:\n");
+ device_printf(pdevinfo->dev, "\n");
+ hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
+ sc->chans[i].supp_pcm_size_rate);
+ device_printf(pdevinfo->dev, " ADC:");
+ for (nids = sc->chans[i].io; *nids != -1; nids++)
printf(" %d", *nids);
printf("\n");
}
@@ -5864,9 +6558,7 @@ hdac_dump_pcmchannels(struct hdac_softc *sc, int pcnt, int rcnt)
static void
hdac_release_resources(struct hdac_softc *sc)
{
- struct hdac_devinfo *devinfo = NULL;
- device_t *devlist = NULL;
- int i, devcount;
+ int i, j;
if (sc == NULL)
return;
@@ -5877,7 +6569,7 @@ hdac_release_resources(struct hdac_softc *sc)
callout_stop(&sc->poll_hda);
callout_stop(&sc->poll_hdac);
callout_stop(&sc->poll_jack);
- hdac_reset(sc);
+ hdac_reset(sc, 0);
hdac_unlock(sc);
taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
callout_drain(&sc->poll_hda);
@@ -5886,43 +6578,40 @@ hdac_release_resources(struct hdac_softc *sc)
hdac_irq_free(sc);
- device_get_children(sc->dev, &devlist, &devcount);
- for (i = 0; devlist != NULL && i < devcount; i++) {
- devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
- if (devinfo == NULL)
- continue;
- if (devinfo->widget != NULL)
- free(devinfo->widget, M_HDAC);
- if (devinfo->node_type ==
- HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
- devinfo->function.audio.ctl != NULL)
- free(devinfo->function.audio.ctl, M_HDAC);
- free(devinfo, M_HDAC);
- device_delete_child(sc->dev, devlist[i]);
- }
- if (devlist != NULL)
- free(devlist, M_TEMP);
-
for (i = 0; i < HDAC_CODEC_MAX; i++) {
- if (sc->codecs[i] != NULL)
- free(sc->codecs[i], M_HDAC);
+ if (sc->codecs[i] == NULL)
+ continue;
+ for (j = 0; j < sc->codecs[i]->num_fgs; j++) {
+ free(sc->codecs[i]->fgs[j].widget, M_HDAC);
+ if (sc->codecs[i]->fgs[j].node_type ==
+ HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
+ free(sc->codecs[i]->fgs[j].function.audio.ctl,
+ M_HDAC);
+ free(sc->codecs[i]->fgs[j].function.audio.as,
+ M_HDAC);
+ free(sc->codecs[i]->fgs[j].function.audio.devs,
+ M_HDAC);
+ }
+ }
+ free(sc->codecs[i]->fgs, M_HDAC);
+ free(sc->codecs[i], M_HDAC);
sc->codecs[i] = NULL;
}
hdac_dma_free(sc, &sc->pos_dma);
hdac_dma_free(sc, &sc->rirb_dma);
hdac_dma_free(sc, &sc->corb_dma);
- if (sc->play.blkcnt > 0)
- hdac_dma_free(sc, &sc->play.bdl_dma);
- if (sc->rec.blkcnt > 0)
- hdac_dma_free(sc, &sc->rec.bdl_dma);
+ for (i = 0; i < sc->num_chans; i++) {
+ if (sc->chans[i].blkcnt > 0)
+ hdac_dma_free(sc, &sc->chans[i].bdl_dma);
+ }
+ free(sc->chans, M_HDAC);
if (sc->chan_dmat != NULL) {
bus_dma_tag_destroy(sc->chan_dmat);
sc->chan_dmat = NULL;
}
hdac_mem_free(sc);
snd_mtxfree(sc->lock);
- free(sc, M_DEVBUF);
}
/* This function surely going to make its way into upper level someday. */
@@ -5944,7 +6633,7 @@ hdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off)
if (!(res != NULL && strlen(res) > 0))
return;
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: HDA Config:");
+ device_printf(sc->dev, "HDA Config:");
);
for (;;) {
while (res[i] != '\0' &&
@@ -5990,17 +6679,14 @@ static int
sysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
{
struct hdac_softc *sc;
- struct hdac_devinfo *devinfo;
device_t dev;
uint32_t ctl;
int err, val;
dev = oidp->oid_arg1;
- devinfo = pcm_getdevinfo(dev);
- if (devinfo == NULL || devinfo->codec == NULL ||
- devinfo->codec->sc == NULL)
+ sc = device_get_softc(dev);
+ if (sc == NULL)
return (EINVAL);
- sc = devinfo->codec->sc;
hdac_lock(sc);
val = sc->polling;
hdac_unlock(sc);
@@ -6013,35 +6699,27 @@ sysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
hdac_lock(sc);
if (val != sc->polling) {
- if (hda_chan_active(sc) != 0)
- err = EBUSY;
- else if (val == 0) {
+ if (val == 0) {
+ callout_stop(&sc->poll_hda);
callout_stop(&sc->poll_hdac);
hdac_unlock(sc);
+ callout_drain(&sc->poll_hda);
callout_drain(&sc->poll_hdac);
hdac_lock(sc);
- HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT,
- sc->rirb_size / 2);
- ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
- ctl |= HDAC_RIRBCTL_RINTCTL;
- HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl);
- HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
- HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
sc->polling = 0;
- DELAY(1000);
+ ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
+ ctl |= HDAC_INTCTL_GIE;
+ HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
} else {
- HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 0);
- HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, 0);
- ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
- ctl &= ~HDAC_RIRBCTL_RINTCTL;
- HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl);
+ ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
+ ctl &= ~HDAC_INTCTL_GIE;
+ HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
hdac_unlock(sc);
taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
hdac_lock(sc);
- callout_reset(&sc->poll_hdac, 1, hdac_poll_callback,
- sc);
sc->polling = 1;
- DELAY(1000);
+ hdac_poll_reinit(sc);
+ callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
}
}
hdac_unlock(sc);
@@ -6053,16 +6731,13 @@ static int
sysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS)
{
struct hdac_softc *sc;
- struct hdac_devinfo *devinfo;
device_t dev;
int err, val;
dev = oidp->oid_arg1;
- devinfo = pcm_getdevinfo(dev);
- if (devinfo == NULL || devinfo->codec == NULL ||
- devinfo->codec->sc == NULL)
+ sc = device_get_softc(dev);
+ if (sc == NULL)
return (EINVAL);
- sc = devinfo->codec->sc;
hdac_lock(sc);
val = ((uint64_t)sc->poll_ival * 1000) / hz;
hdac_unlock(sc);
@@ -6088,153 +6763,167 @@ sysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS)
return (err);
}
-#ifdef SND_DEBUG
static int
sysctl_hdac_pindump(SYSCTL_HANDLER_ARGS)
{
struct hdac_softc *sc;
+ struct hdac_codec *codec;
struct hdac_devinfo *devinfo;
struct hdac_widget *w;
device_t dev;
- uint32_t res, pincap, timeout;
+ uint32_t res, pincap, delay;
+ int codec_index, fg_index;
int i, err, val;
nid_t cad;
dev = oidp->oid_arg1;
- devinfo = pcm_getdevinfo(dev);
- if (devinfo == NULL || devinfo->codec == NULL ||
- devinfo->codec->sc == NULL)
+ sc = device_get_softc(dev);
+ if (sc == NULL)
return (EINVAL);
val = 0;
err = sysctl_handle_int(oidp, &val, 0, req);
if (err != 0 || req->newptr == NULL || val == 0)
return (err);
- sc = devinfo->codec->sc;
- cad = devinfo->codec->cad;
+
+ /* XXX: Temporary. For debugging. */
+ if (val == 100) {
+ hdac_suspend(dev);
+ return (0);
+ } else if (val == 101) {
+ hdac_resume(dev);
+ return (0);
+ }
+
hdac_lock(sc);
- device_printf(dev, "HDAC Dump AFG [nid=%d]:\n", devinfo->nid);
- 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)
+ for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
+ codec = sc->codecs[codec_index];
+ if (codec == NULL)
continue;
- pincap = w->wclass.pin.cap;
- if ((HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap) ||
- HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) &&
- HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) {
- timeout = 10000;
- hdac_command(sc,
- HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), cad);
- do {
+ cad = codec->cad;
+ for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
+ devinfo = &codec->fgs[fg_index];
+ if (devinfo->node_type !=
+ HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
+ continue;
+
+ device_printf(dev, "Dumping AFG cad=%d nid=%d pins:\n",
+ codec_index, devinfo->nid);
+ 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;
+ hdac_dump_pin_config(w, w->wclass.pin.config);
+ pincap = w->wclass.pin.cap;
+ device_printf(dev, " Caps: %2s %3s %2s %4s %4s",
+ HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)?"IN":"",
+ HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)?"OUT":"",
+ HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)?"HP":"",
+ HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)?"EAPD":"",
+ HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)?"VREF":"");
+ if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap) ||
+ HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) {
+ if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) {
+ delay = 0;
+ hdac_command(sc,
+ HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), cad);
+ do {
+ res = hdac_command(sc,
+ HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad);
+ if (res != 0x7fffffff && res != 0xffffffff)
+ break;
+ DELAY(10);
+ } while (++delay < 10000);
+ } else {
+ delay = 0;
+ res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad,
+ w->nid), cad);
+ }
+ printf(" Sense: 0x%08x", res);
+ if (delay > 0)
+ printf(" delay %dus", delay * 10);
+ }
+ printf("\n");
+ }
+ device_printf(dev,
+ "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
+ HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
+ HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
+ HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
+ HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
+ HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
+ if (HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) {
+ device_printf(dev, " GPI:");
res = hdac_command(sc,
- HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad);
- if (res != 0x7fffffff)
- break;
- DELAY(10);
- } while (--timeout != 0);
- } else {
- timeout = -1;
- res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad,
- w->nid), cad);
+ HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad);
+ printf(" data=0x%08x", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid),
+ cad);
+ printf(" wake=0x%08x", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
+ cad);
+ printf(" unsol=0x%08x", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad);
+ printf(" sticky=0x%08x\n", res);
+ }
+ if (HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) {
+ device_printf(dev, " GPO:");
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad);
+ printf(" data=0x%08x\n", res);
+ }
+ if (HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) {
+ device_printf(dev, "GPIO:");
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad);
+ printf(" data=0x%08x", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad);
+ printf(" enable=0x%08x", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad);
+ printf(" direction=0x%08x\n", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad);
+ device_printf(dev, " wake=0x%08x", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
+ cad);
+ printf(" unsol=0x%08x", res);
+ res = hdac_command(sc,
+ HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad);
+ printf(" sticky=0x%08x\n", res);
+ }
}
- device_printf(dev,
- "PIN_SENSE: nid=%-3d timeout=%d res=0x%08x [%s]\n",
- w->nid, timeout, res,
- (w->enable == 0) ? "DISABLED" : "ENABLED");
- }
- device_printf(dev,
- "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
- HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
- HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
- HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
- HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
- HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
- if (HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) {
- device_printf(dev, " GPI:");
- res = hdac_command(sc,
- HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad);
- printf(" data=0x%08x", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid),
- cad);
- printf(" wake=0x%08x", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
- cad);
- printf(" unsol=0x%08x", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad);
- printf(" sticky=0x%08x\n", res);
- }
- if (HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) {
- device_printf(dev, " GPO:");
- res = hdac_command(sc,
- HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad);
- printf(" data=0x%08x\n", res);
- }
- if (HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) {
- device_printf(dev, "GPI0:");
- res = hdac_command(sc,
- HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad);
- printf(" data=0x%08x", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad);
- printf(" enable=0x%08x", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad);
- printf(" direction=0x%08x\n", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad);
- device_printf(dev, " wake=0x%08x", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
- cad);
- printf(" unsol=0x%08x", res);
- res = hdac_command(sc,
- HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad);
- printf(" sticky=0x%08x\n", res);
}
hdac_unlock(sc);
return (0);
}
#endif
-#endif
static void
hdac_attach2(void *arg)
{
+ struct hdac_codec *codec;
struct hdac_softc *sc;
- struct hdac_widget *w;
struct hdac_audio_ctl *ctl;
uint32_t quirks_on, quirks_off;
- int pcnt, rcnt, codec_index;
- int i;
- char status[SND_STATUSLEN];
- device_t *devlist = NULL;
- int devcount;
- struct hdac_devinfo *devinfo = NULL;
+ int codec_index, fg_index;
+ int i, pdev, rdev, dmaalloc = 0;
+ struct hdac_devinfo *devinfo;
sc = (struct hdac_softc *)arg;
hdac_config_fetch(sc, &quirks_on, &quirks_off);
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: HDA Config: on=0x%08x off=0x%08x\n",
+ device_printf(sc->dev, "HDA Config: on=0x%08x off=0x%08x\n",
quirks_on, quirks_off);
);
- if (resource_int_value(device_get_name(sc->dev),
- device_get_unit(sc->dev), "codec_index", &codec_index) != 0) {
- switch (sc->pci_subvendor) {
- case GB_G33S2H_SUBVENDOR:
- codec_index = 2;
- break;
- default:
- codec_index = 0;
- break;
- }
- }
-
hdac_lock(sc);
/* Remove ourselves from the config hooks */
@@ -6245,266 +6934,476 @@ hdac_attach2(void *arg)
/* Start the corb and rirb engines */
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Starting CORB Engine...\n");
+ device_printf(sc->dev, "Starting CORB Engine...\n");
);
hdac_corb_start(sc);
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Starting RIRB Engine...\n");
+ device_printf(sc->dev, "Starting RIRB Engine...\n");
);
hdac_rirb_start(sc);
HDA_BOOTVERBOSE(
device_printf(sc->dev,
- "HDA_DEBUG: Enabling controller interrupt...\n");
+ "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);
HDA_BOOTVERBOSE(
device_printf(sc->dev,
- "HDA_DEBUG: Scanning HDA codecs [start index=%d] ...\n",
- codec_index);
+ "Scanning HDA codecs ...\n");
);
- hdac_scan_codecs(sc, codec_index);
+ hdac_scan_codecs(sc);
+
+ for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
+ codec = sc->codecs[codec_index];
+ if (codec == NULL)
+ continue;
+ for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
+ devinfo = &codec->fgs[fg_index];
+ device_printf(sc->dev, "\n");
+ if (devinfo->node_type !=
+ HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "Power down unsupported non-audio FG"
+ " cad=%d nid=%d to the D3 state...\n",
+ codec->cad, devinfo->nid);
+ );
+ hdac_command(sc,
+ HDA_CMD_SET_POWER_STATE(codec->cad,
+ devinfo->nid, HDA_CMD_POWER_STATE_D3),
+ codec->cad);
+ continue;
+ }
- device_get_children(sc->dev, &devlist, &devcount);
- for (i = 0; devlist != NULL && i < devcount; i++) {
- devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
- if (devinfo != NULL && devinfo->node_type ==
- HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
- break;
- } else
- devinfo = NULL;
- }
- if (devlist != NULL)
- free(devlist, M_TEMP);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev,
+ "Power up audio FG cad=%d nid=%d...\n",
+ devinfo->codec->cad, devinfo->nid);
+ );
+ hdac_powerup(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Parsing audio FG...\n");
+ );
+ hdac_audio_parse(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Parsing Ctls...\n");
+ );
+ hdac_audio_ctl_parse(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Parsing vendor patch...\n");
+ );
+ hdac_vendor_patch_parse(devinfo);
+ devinfo->function.audio.quirks |= quirks_on;
+ devinfo->function.audio.quirks &= ~quirks_off;
- if (devinfo == NULL) {
- hdac_unlock(sc);
- device_printf(sc->dev, "Audio Function Group not found!\n");
- hdac_release_resources(sc);
- return;
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Disabling nonaudio...\n");
+ );
+ hdac_audio_disable_nonaudio(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Disabling useless...\n");
+ );
+ hdac_audio_disable_useless(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Patched pins configuration:\n");
+ hdac_dump_pin_configs(devinfo);
+ device_printf(sc->dev, "Parsing pin associations...\n");
+ );
+ hdac_audio_as_parse(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Building AFG tree...\n");
+ );
+ hdac_audio_build_tree(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Disabling unassociated "
+ "widgets...\n");
+ );
+ hdac_audio_disable_unas(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Disabling nonselected "
+ "inputs...\n");
+ );
+ hdac_audio_disable_notselected(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Disabling useless...\n");
+ );
+ hdac_audio_disable_useless(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Disabling "
+ "crossassociatement connections...\n");
+ );
+ hdac_audio_disable_crossas(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Disabling useless...\n");
+ );
+ hdac_audio_disable_useless(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Binding associations to channels...\n");
+ );
+ hdac_audio_bind_as(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Assigning names to signal sources...\n");
+ );
+ hdac_audio_assign_names(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Assigning mixers to the tree...\n");
+ );
+ hdac_audio_assign_mixers(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Preparing pin controls...\n");
+ );
+ hdac_audio_prepare_pin_ctrl(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "AFG commit...\n");
+ );
+ hdac_audio_commit(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Ctls commit...\n");
+ );
+ hdac_audio_ctl_commit(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "HP switch init...\n");
+ );
+ hdac_hp_switch_init(devinfo);
+
+ if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) &&
+ dmaalloc == 0) {
+ if (hdac_dma_alloc(sc, &sc->pos_dma,
+ (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) {
+ HDA_BOOTVERBOSE(
+ device_printf(sc->dev, "Failed to "
+ "allocate DMA pos buffer "
+ "(non-fatal)\n");
+ );
+ } else
+ dmaalloc = 1;
+ }
+
+ i = devinfo->function.audio.playcnt;
+ if (devinfo->function.audio.reccnt > i)
+ i = devinfo->function.audio.reccnt;
+ devinfo->function.audio.devs =
+ (struct hdac_pcm_devinfo *)malloc(
+ sizeof(struct hdac_pcm_devinfo) * i,
+ M_HDAC, M_ZERO | M_NOWAIT);
+ if (devinfo->function.audio.devs == NULL) {
+ device_printf(sc->dev,
+ "Unable to allocate memory for devices\n");
+ continue;
+ }
+ devinfo->function.audio.num_devs = i;
+ for (i = 0; i < devinfo->function.audio.num_devs; i++) {
+ devinfo->function.audio.devs[i].index = i;
+ devinfo->function.audio.devs[i].devinfo = devinfo;
+ devinfo->function.audio.devs[i].play = -1;
+ devinfo->function.audio.devs[i].rec = -1;
+ }
+ pdev = 0;
+ rdev = 0;
+ for (i = 0; i < devinfo->function.audio.ascnt; i++) {
+ if (devinfo->function.audio.as[i].enable == 0)
+ continue;
+ if (devinfo->function.audio.as[i].dir ==
+ HDA_CTL_IN) {
+ devinfo->function.audio.devs[rdev].rec
+ = devinfo->function.audio.as[i].chan;
+ sc->chans[devinfo->function.audio.as[i].chan].pdevinfo =
+ &devinfo->function.audio.devs[rdev];
+ rdev++;
+ } else {
+ devinfo->function.audio.devs[pdev].play
+ = devinfo->function.audio.as[i].chan;
+ sc->chans[devinfo->function.audio.as[i].chan].pdevinfo =
+ &devinfo->function.audio.devs[pdev];
+ pdev++;
+ }
+ }
+ for (i = 0; i < devinfo->function.audio.num_devs; i++) {
+ struct hdac_pcm_devinfo *pdevinfo =
+ &devinfo->function.audio.devs[i];
+ pdevinfo->dev =
+ device_add_child(sc->dev, "pcm", -1);
+ device_set_ivars(pdevinfo->dev,
+ (void *)pdevinfo);
+ }
+
+ HDA_BOOTVERBOSE(
+ if (devinfo->function.audio.quirks != 0) {
+ device_printf(sc->dev, "\n");
+ device_printf(sc->dev, "HDA config/quirks:");
+ for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) {
+ if ((devinfo->function.audio.quirks &
+ hdac_quirks_tab[i].value) ==
+ hdac_quirks_tab[i].value)
+ printf(" %s", hdac_quirks_tab[i].key);
+ }
+ printf("\n");
+ }
+
+ device_printf(sc->dev, "\n");
+ device_printf(sc->dev, "+-------------------+\n");
+ device_printf(sc->dev, "| DUMPING HDA NODES |\n");
+ device_printf(sc->dev, "+-------------------+\n");
+ hdac_dump_nodes(devinfo);
+
+ device_printf(sc->dev, "\n");
+ device_printf(sc->dev, "+------------------------+\n");
+ device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
+ device_printf(sc->dev, "+------------------------+\n");
+ device_printf(sc->dev, "\n");
+ i = 0;
+ while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
+ device_printf(sc->dev, "%3d: nid %3d %s (%s) index %d", i,
+ (ctl->widget != NULL) ? ctl->widget->nid : -1,
+ (ctl->ndir == HDA_CTL_IN)?"in ":"out",
+ (ctl->dir == HDA_CTL_IN)?"in ":"out",
+ ctl->index);
+ if (ctl->childwidget != NULL)
+ printf(" cnid %3d", ctl->childwidget->nid);
+ else
+ printf(" ");
+ printf(" ossmask=0x%08x\n",
+ ctl->ossmask);
+ device_printf(sc->dev,
+ " mute: %d step: %3d size: %3d off: %3d%s\n",
+ ctl->mute, ctl->step, ctl->size, ctl->offset,
+ (ctl->enable == 0) ? " [DISABLED]" :
+ ((ctl->ossmask == 0) ? " [UNUSED]" : ""));
+ }
+ );
+ }
}
+ hdac_unlock(sc);
HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: Parsing AFG nid=%d cad=%d\n",
- devinfo->nid, devinfo->codec->cad);
+ device_printf(sc->dev, "\n");
);
- hdac_audio_parse(devinfo);
+
+ bus_generic_attach(sc->dev);
+
+#ifdef SND_DYNSYSCTL
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
+ "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
+ sysctl_hdac_polling, "I", "Enable polling mode");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
+ "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
+ sizeof(sc->dev), sysctl_hdac_polling_interval, "I",
+ "Controller/Jack Sense polling interval (1-1000 ms)");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
+ "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
+ sysctl_hdac_pindump, "I", "Dump pin states/data");
+#endif
+}
+
+/****************************************************************************
+ * int hdac_suspend(device_t)
+ *
+ * Suspend and power down HDA bus and codecs.
+ ****************************************************************************/
+static int
+hdac_suspend(device_t dev)
+{
+ struct hdac_softc *sc;
+ struct hdac_codec *codec;
+ struct hdac_devinfo *devinfo;
+ int codec_index, fg_index, i;
+
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Parsing Ctls...\n");
+ device_printf(dev, "Suspend...\n");
);
- hdac_audio_ctl_parse(devinfo);
+
+ sc = device_get_softc(dev);
+ hdac_lock(sc);
+
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Parsing vendor patch...\n");
+ device_printf(dev, "Stop streams...\n");
);
- hdac_vendor_patch_parse(devinfo);
- if (quirks_on != 0)
- devinfo->function.audio.quirks |= quirks_on;
- if (quirks_off != 0)
- devinfo->function.audio.quirks &= ~quirks_off;
-
- /* XXX Disable all DIGITAL path. */
- for (i = devinfo->startnode; i < devinfo->endnode; i++) {
- w = hdac_widget_get(devinfo, i);
- if (w == NULL)
- continue;
- if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
- w->enable = 0;
- continue;
+ for (i = 0; i < sc->num_chans; i++) {
+ if (sc->chans[i].flags & HDAC_CHN_RUNNING) {
+ sc->chans[i].flags |= HDAC_CHN_SUSPEND;
+ hdac_channel_stop(sc, &sc->chans[i]);
}
- /* XXX Disable useless pin ? */
- if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
- (w->wclass.pin.config &
- HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
- HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
- w->enable = 0;
}
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->widget == NULL)
- continue;
- if (ctl->ossmask & SOUND_MASK_DISABLE)
- ctl->enable = 0;
- w = ctl->widget;
- if (w->enable == 0 ||
- HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
- ctl->enable = 0;
- w = ctl->childwidget;
- if (w == NULL)
+
+ for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
+ codec = sc->codecs[codec_index];
+ if (codec == NULL)
continue;
- if (w->enable == 0 ||
- HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
- ctl->enable = 0;
+ for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
+ devinfo = &codec->fgs[fg_index];
+ HDA_BOOTVERBOSE(
+ device_printf(dev,
+ "Power down FG"
+ " cad=%d nid=%d to the D3 state...\n",
+ codec->cad, devinfo->nid);
+ );
+ hdac_command(sc,
+ HDA_CMD_SET_POWER_STATE(codec->cad,
+ devinfo->nid, HDA_CMD_POWER_STATE_D3),
+ codec->cad);
+ }
}
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Building AFG tree...\n");
+ device_printf(dev, "Reset controller...\n");
);
- hdac_audio_build_tree(devinfo);
+ callout_stop(&sc->poll_hda);
+ callout_stop(&sc->poll_hdac);
+ callout_stop(&sc->poll_jack);
+ hdac_reset(sc, 0);
+ hdac_unlock(sc);
+ taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
+ callout_drain(&sc->poll_hda);
+ callout_drain(&sc->poll_hdac);
+ callout_drain(&sc->poll_jack);
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- if (ctl->ossmask & (SOUND_MASK_SKIP | SOUND_MASK_DISABLE))
- ctl->ossmask = 0;
- }
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: AFG commit...\n");
+ device_printf(dev, "Suspend done\n");
);
- hdac_audio_commit(devinfo, HDA_COMMIT_ALL);
+
+ return (0);
+}
+
+/****************************************************************************
+ * int hdac_resume(device_t)
+ *
+ * Powerup and restore HDA bus and codecs state.
+ ****************************************************************************/
+static int
+hdac_resume(device_t dev)
+{
+ struct hdac_softc *sc;
+ struct hdac_codec *codec;
+ struct hdac_devinfo *devinfo;
+ int codec_index, fg_index, i;
+
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: Ctls commit...\n");
+ device_printf(dev, "Resume...\n");
);
- hdac_audio_ctl_commit(devinfo);
+ sc = device_get_softc(dev);
+ hdac_lock(sc);
+
+ /* Quiesce everything */
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: PCMDIR_PLAY setup...\n");
+ device_printf(dev, "Reset controller...\n");
);
- pcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_PLAY);
+ hdac_reset(sc, 1);
+
+ /* Initialize the CORB and RIRB */
+ hdac_corb_init(sc);
+ hdac_rirb_init(sc);
+
+ /* Start the corb and rirb engines */
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "HDA_DEBUG: PCMDIR_REC setup...\n");
+ device_printf(dev, "Starting CORB Engine...\n");
);
- rcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_REC);
-
- hdac_unlock(sc);
+ hdac_corb_start(sc);
HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: OSS mixer initialization...\n");
+ device_printf(dev, "Starting RIRB Engine...\n");
);
-
- /*
- * There is no point of return after this. If the driver failed,
- * so be it. Let the detach procedure do all the cleanup.
- */
- if (mixer_init(sc->dev, &hdac_audio_ctl_ossmixer_class, devinfo) != 0)
- device_printf(sc->dev, "Can't register mixer\n");
-
- if (pcnt > 0)
- pcnt = 1;
- if (rcnt > 0)
- rcnt = 1;
+ hdac_rirb_start(sc);
HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "HDA_DEBUG: Registering PCM channels...\n");
+ device_printf(dev,
+ "Enabling controller interrupt...\n");
);
- if (pcm_register(sc->dev, devinfo, pcnt, rcnt) != 0)
- device_printf(sc->dev, "Can't register PCM\n");
-
- sc->registered++;
-
- if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) &&
- hdac_dma_alloc(sc, &sc->pos_dma,
- (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) {
- HDA_BOOTVERBOSE(
- device_printf(sc->dev,
- "Failed to allocate DMA pos buffer (non-fatal)\n");
- );
+ 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);
+
+ for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
+ codec = sc->codecs[codec_index];
+ if (codec == NULL)
+ continue;
+ for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
+ devinfo = &codec->fgs[fg_index];
+ if (devinfo->node_type !=
+ HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
+ HDA_BOOTVERBOSE(
+ device_printf(dev,
+ "Power down unsupported non-audio FG"
+ " cad=%d nid=%d to the D3 state...\n",
+ codec->cad, devinfo->nid);
+ );
+ hdac_command(sc,
+ HDA_CMD_SET_POWER_STATE(codec->cad,
+ devinfo->nid, HDA_CMD_POWER_STATE_D3),
+ codec->cad);
+ continue;
+ }
- for (i = 0; i < pcnt; i++)
- pcm_addchan(sc->dev, PCMDIR_PLAY, &hdac_channel_class, devinfo);
- for (i = 0; i < rcnt; i++)
- pcm_addchan(sc->dev, PCMDIR_REC, &hdac_channel_class, devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(dev,
+ "Power up audio FG cad=%d nid=%d...\n",
+ devinfo->codec->cad, devinfo->nid);
+ );
+ hdac_powerup(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(dev, "AFG commit...\n");
+ );
+ hdac_audio_commit(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(dev, "Ctls commit...\n");
+ );
+ hdac_audio_ctl_commit(devinfo);
+ HDA_BOOTVERBOSE(
+ device_printf(dev, "HP switch init...\n");
+ );
+ hdac_hp_switch_init(devinfo);
-#ifdef SND_DYNSYSCTL
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
- "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
- sysctl_hdac_polling, "I", "Enable polling mode");
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
- "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
- sizeof(sc->dev), sysctl_hdac_polling_interval, "I",
- "Controller/Jack Sense polling interval (1-1000 ms)");
-#ifdef SND_DEBUG
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
- "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
- sysctl_hdac_pindump, "I", "Dump pin states/data");
-#endif
-#endif
+ hdac_unlock(sc);
+ for (i = 0; i < devinfo->function.audio.num_devs; i++) {
+ struct hdac_pcm_devinfo *pdevinfo =
+ &devinfo->function.audio.devs[i];
+ HDA_BOOTVERBOSE(
+ device_printf(pdevinfo->dev,
+ "OSS mixer reinitialization...\n");
+ );
+ if (mixer_reinit(pdevinfo->dev) == -1)
+ device_printf(pdevinfo->dev,
+ "unable to reinitialize the mixer\n");
+ }
+ hdac_lock(sc);
+ }
+ }
- snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s [%s]",
- rman_get_start(sc->mem.mem_res), rman_get_start(sc->irq.irq_res),
- PCM_KLDSTRING(snd_hda), HDA_DRV_TEST_REV);
- pcm_setstatus(sc->dev, status);
- device_printf(sc->dev, "<HDA Codec: %s>\n", hdac_codec_name(devinfo));
HDA_BOOTVERBOSE(
- device_printf(sc->dev, "<HDA Codec ID: 0x%08x>\n",
- hdac_codec_id(devinfo));
+ device_printf(dev, "Start streams...\n");
);
- device_printf(sc->dev, "<HDA Driver Revision: %s>\n",
- HDA_DRV_TEST_REV);
+ for (i = 0; i < sc->num_chans; i++) {
+ if (sc->chans[i].flags & HDAC_CHN_SUSPEND) {
+ sc->chans[i].flags &= ~HDAC_CHN_SUSPEND;
+ hdac_channel_start(sc, &sc->chans[i]);
+ }
+ }
+
+ hdac_unlock(sc);
HDA_BOOTVERBOSE(
- if (devinfo->function.audio.quirks != 0) {
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "HDA config/quirks:");
- for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) {
- if ((devinfo->function.audio.quirks &
- hdac_quirks_tab[i].value) ==
- hdac_quirks_tab[i].value)
- printf(" %s", hdac_quirks_tab[i].key);
- }
- printf("\n");
- }
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "+-------------------+\n");
- device_printf(sc->dev, "| DUMPING HDA NODES |\n");
- device_printf(sc->dev, "+-------------------+\n");
- hdac_dump_nodes(devinfo);
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "+------------------------+\n");
- device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
- device_printf(sc->dev, "+------------------------+\n");
- device_printf(sc->dev, "\n");
- i = 0;
- while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
- device_printf(sc->dev, "%3d: nid=%d", i,
- (ctl->widget != NULL) ? ctl->widget->nid : -1);
- if (ctl->childwidget != NULL)
- printf(" cnid=%d", ctl->childwidget->nid);
- printf(" dir=0x%x index=%d "
- "ossmask=0x%08x ossdev=%d%s\n",
- ctl->dir, ctl->index,
- ctl->ossmask, ctl->ossdev,
- (ctl->enable == 0) ? " [DISABLED]" : "");
- }
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "+-----------------------------------+\n");
- device_printf(sc->dev, "| DUMPING HDA AUDIO/VOLUME CONTROLS |\n");
- device_printf(sc->dev, "+-----------------------------------+\n");
- hdac_dump_ctls(devinfo, "Master Volume (OSS: vol)", SOUND_MASK_VOLUME);
- hdac_dump_ctls(devinfo, "PCM Volume (OSS: pcm)", SOUND_MASK_PCM);
- hdac_dump_ctls(devinfo, "CD Volume (OSS: cd)", SOUND_MASK_CD);
- hdac_dump_ctls(devinfo, "Microphone Volume (OSS: mic)", SOUND_MASK_MIC);
- hdac_dump_ctls(devinfo, "Line-in Volume (OSS: line)", SOUND_MASK_LINE);
- hdac_dump_ctls(devinfo, "Recording Level (OSS: rec)", SOUND_MASK_RECLEV);
- hdac_dump_ctls(devinfo, "Speaker/Beep (OSS: speaker)", SOUND_MASK_SPEAKER);
- hdac_dump_ctls(devinfo, NULL, 0);
- hdac_dump_dac(devinfo);
- hdac_dump_adc(devinfo);
- device_printf(sc->dev, "\n");
- device_printf(sc->dev, "+--------------------------------------+\n");
- device_printf(sc->dev, "| DUMPING PCM Playback/Record Channels |\n");
- device_printf(sc->dev, "+--------------------------------------+\n");
- hdac_dump_pcmchannels(sc, pcnt, rcnt);
+ device_printf(dev, "Resume done\n");
);
- if (sc->polling != 0) {
- hdac_lock(sc);
- callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
- hdac_unlock(sc);
- }
+ return (0);
}
-
/****************************************************************************
* int hdac_detach(device_t)
*
@@ -6513,21 +7412,17 @@ hdac_attach2(void *arg)
static int
hdac_detach(device_t dev)
{
- struct hdac_softc *sc = NULL;
- struct hdac_devinfo *devinfo = NULL;
- int err;
+ struct hdac_softc *sc;
+ device_t *devlist = NULL;
+ int i, devcount;
- devinfo = (struct hdac_devinfo *)pcm_getdevinfo(dev);
- if (devinfo != NULL && devinfo->codec != NULL)
- sc = devinfo->codec->sc;
- if (sc == NULL)
- return (0);
+ sc = device_get_softc(dev);
- if (sc->registered > 0) {
- err = pcm_unregister(dev);
- if (err != 0)
- return (err);
- }
+ device_get_children(dev, &devlist, &devcount);
+ for (i = 0; devlist != NULL && i < devcount; i++)
+ device_delete_child(dev, devlist[i]);
+ if (devlist != NULL)
+ free(devlist, M_TEMP);
hdac_release_resources(sc);
@@ -6539,15 +7434,159 @@ static device_method_t hdac_methods[] = {
DEVMETHOD(device_probe, hdac_probe),
DEVMETHOD(device_attach, hdac_attach),
DEVMETHOD(device_detach, hdac_detach),
+ DEVMETHOD(device_suspend, hdac_suspend),
+ DEVMETHOD(device_resume, hdac_resume),
{ 0, 0 }
};
static driver_t hdac_driver = {
- "pcm",
+ "hdac",
hdac_methods,
- PCM_SOFTC_SIZE,
+ sizeof(struct hdac_softc),
};
-DRIVER_MODULE(snd_hda, pci, hdac_driver, pcm_devclass, 0, 0);
+static devclass_t hdac_devclass;
+
+DRIVER_MODULE(snd_hda, pci, hdac_driver, hdac_devclass, 0, 0);
MODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
MODULE_VERSION(snd_hda, 1);
+
+static int
+hdac_pcm_probe(device_t dev)
+{
+ struct hdac_pcm_devinfo *pdevinfo =
+ (struct hdac_pcm_devinfo *)device_get_ivars(dev);
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "HDA codec #%d %s PCM #%d",
+ pdevinfo->devinfo->codec->cad,
+ hdac_codec_name(pdevinfo->devinfo->codec),
+ pdevinfo->index);
+ device_set_desc_copy(dev, buf);
+ return (0);
+}
+
+static int
+hdac_pcm_attach(device_t dev)
+{
+ struct hdac_pcm_devinfo *pdevinfo =
+ (struct hdac_pcm_devinfo *)device_get_ivars(dev);
+ struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
+ char status[SND_STATUSLEN];
+ int i;
+
+ pdevinfo->chan_size = pcm_getbuffersize(dev,
+ HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX);
+
+ HDA_BOOTVERBOSE(
+ device_printf(dev, "+--------------------------------------+\n");
+ device_printf(dev, "| DUMPING PCM Playback/Record Channels |\n");
+ device_printf(dev, "+--------------------------------------+\n");
+ hdac_dump_pcmchannels(pdevinfo);
+ device_printf(dev, "\n");
+ device_printf(dev, "+--------------------------------+\n");
+ device_printf(dev, "| DUMPING Playback/Record Pathes |\n");
+ device_printf(dev, "+--------------------------------+\n");
+ hdac_dump_dac(pdevinfo);
+ hdac_dump_adc(pdevinfo);
+ hdac_dump_mix(pdevinfo);
+ device_printf(dev, "\n");
+ device_printf(dev, "+-------------------------+\n");
+ device_printf(dev, "| DUMPING Volume Controls |\n");
+ device_printf(dev, "+-------------------------+\n");
+ hdac_dump_ctls(pdevinfo, "Master Volume", SOUND_MASK_VOLUME);
+ hdac_dump_ctls(pdevinfo, "PCM Volume", SOUND_MASK_PCM);
+ hdac_dump_ctls(pdevinfo, "CD Volume", SOUND_MASK_CD);
+ hdac_dump_ctls(pdevinfo, "Microphone Volume", SOUND_MASK_MIC);
+ hdac_dump_ctls(pdevinfo, "Microphone2 Volume", SOUND_MASK_MONITOR);
+ 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, NULL, 0);
+ device_printf(dev, "\n");
+ );
+
+ if (resource_int_value(device_get_name(dev),
+ device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
+ i &= HDA_BLK_ALIGN;
+ if (i < HDA_BLK_MIN)
+ i = HDA_BLK_MIN;
+ pdevinfo->chan_blkcnt = pdevinfo->chan_size / i;
+ i = 0;
+ while (pdevinfo->chan_blkcnt >> i)
+ i++;
+ pdevinfo->chan_blkcnt = 1 << (i - 1);
+ if (pdevinfo->chan_blkcnt < HDA_BDL_MIN)
+ pdevinfo->chan_blkcnt = HDA_BDL_MIN;
+ else if (pdevinfo->chan_blkcnt > HDA_BDL_MAX)
+ pdevinfo->chan_blkcnt = HDA_BDL_MAX;
+ } else
+ pdevinfo->chan_blkcnt = HDA_BDL_DEFAULT;
+
+ /*
+ * We don't register interrupt handler with snd_setup_intr
+ * in pcm device. Mark pcm device as MPSAFE manually.
+ */
+ pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
+
+ HDA_BOOTVERBOSE(
+ device_printf(dev, "OSS mixer initialization...\n");
+ );
+ if (mixer_init(dev, &hdac_audio_ctl_ossmixer_class, pdevinfo) != 0)
+ device_printf(dev, "Can't register mixer\n");
+
+ HDA_BOOTVERBOSE(
+ device_printf(dev, "Registering PCM channels...\n");
+ );
+ if (pcm_register(dev, pdevinfo, (pdevinfo->play >= 0)?1:0,
+ (pdevinfo->rec >= 0)?1:0) != 0)
+ device_printf(dev, "Can't register PCM\n");
+
+ pdevinfo->registered++;
+
+ if (pdevinfo->play >= 0)
+ pcm_addchan(dev, PCMDIR_PLAY, &hdac_channel_class, pdevinfo);
+ if (pdevinfo->rec >= 0)
+ pcm_addchan(dev, PCMDIR_REC, &hdac_channel_class, pdevinfo);
+
+ snprintf(status, SND_STATUSLEN, "at %s cad %d %s [%s]",
+ device_get_nameunit(sc->dev), pdevinfo->devinfo->codec->cad,
+ PCM_KLDSTRING(snd_hda), HDA_DRV_TEST_REV);
+ pcm_setstatus(dev, status);
+
+ return (0);
+}
+
+static int
+hdac_pcm_detach(device_t dev)
+{
+ struct hdac_pcm_devinfo *pdevinfo =
+ (struct hdac_pcm_devinfo *)device_get_ivars(dev);
+ int err;
+
+ if (pdevinfo->registered > 0) {
+ err = pcm_unregister(dev);
+ if (err != 0)
+ return (err);
+ }
+
+ return (0);
+}
+
+static device_method_t hdac_pcm_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, hdac_pcm_probe),
+ DEVMETHOD(device_attach, hdac_pcm_attach),
+ DEVMETHOD(device_detach, hdac_pcm_detach),
+ { 0, 0 }
+};
+
+static driver_t hdac_pcm_driver = {
+ "pcm",
+ hdac_pcm_methods,
+ PCM_SOFTC_SIZE,
+};
+
+DRIVER_MODULE(snd_hda_pcm, hdac, hdac_pcm_driver, pcm_devclass, 0, 0);
+
diff --git a/sys/dev/sound/pci/hda/hdac_private.h b/sys/dev/sound/pci/hda/hdac_private.h
index dd8d3c4..66bbbd8 100644
--- a/sys/dev/sound/pci/hda/hdac_private.h
+++ b/sys/dev/sound/pci/hda/hdac_private.h
@@ -161,18 +161,6 @@ struct hdac_command_list {
typedef int nid_t;
struct hdac_softc;
-/****************************************************************************
- * struct hdac_codec
- *
- ****************************************************************************/
-struct hdac_codec {
- int verbs_sent;
- int responses_received;
- nid_t cad;
- struct hdac_command_list *commands;
- struct hdac_softc *sc;
-};
-
struct hdac_bdle {
volatile uint32_t addrl;
volatile uint32_t addrh;
@@ -183,15 +171,19 @@ struct hdac_bdle {
#define HDA_MAX_CONNS 32
#define HDA_MAX_NAMELEN 32
-struct hdac_devinfo;
-
struct hdac_widget {
nid_t nid;
int type;
int enable;
int nconns, selconn;
- uint32_t pflags, ctlflags;
+ int waspin;
+ uint32_t pflags;
+ int bindas;
+ int bindseqmask;
+ int ossdev;
+ uint32_t ossmask;
nid_t conns[HDA_MAX_CONNS];
+ u_char connsenable[HDA_MAX_CONNS];
char name[HDA_MAX_NAMELEN];
struct hdac_devinfo *devinfo;
struct {
@@ -201,7 +193,6 @@ struct hdac_widget {
uint32_t supp_stream_formats;
uint32_t supp_pcm_size_rate;
uint32_t eapdbtl;
- int outpath;
} param;
union {
struct {
@@ -215,12 +206,36 @@ struct hdac_widget {
struct hdac_audio_ctl {
struct hdac_widget *widget, *childwidget;
int enable;
- int index;
+ int index, dir, ndir;
int mute, step, size, offset;
- int left, right;
+ int left, right, forcemute;
uint32_t muted;
- int ossdev;
- uint32_t dir, ossmask, ossval;
+ uint32_t ossmask, possmask;
+};
+
+/* Association is a group of pins bound for some special function. */
+struct hdac_audio_as {
+ u_char enable;
+ u_char index;
+ u_char dir;
+ u_char pincnt;
+ u_char fakeredir;
+ nid_t hpredir;
+ nid_t pins[16];
+ nid_t dacs[16];
+ int chan;
+};
+
+struct hdac_pcm_devinfo {
+ device_t dev;
+ struct hdac_devinfo *devinfo;
+ int index;
+ int registered;
+ int play, rec;
+ u_char left[SOUND_MIXER_NRDEVICES];
+ u_char right[SOUND_MIXER_NRDEVICES];
+ int chan_size;
+ int chan_blkcnt;
};
/****************************************************************************
@@ -230,11 +245,6 @@ struct hdac_audio_ctl {
* in the ivar of each child of the hdac bus
****************************************************************************/
struct hdac_devinfo {
- device_t dev;
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision_id;
- uint8_t stepping_id;
uint8_t node_type;
nid_t nid;
nid_t startnode, endnode;
@@ -247,14 +257,14 @@ struct hdac_devinfo {
uint32_t inamp_cap;
uint32_t supp_stream_formats;
uint32_t supp_pcm_size_rate;
- int ctlcnt, pcnt, rcnt;
+ int ctlcnt, ascnt;
struct hdac_audio_ctl *ctl;
- uint32_t mvol;
+ struct hdac_audio_as *as;
uint32_t quirks;
uint32_t gpio;
- int ossidx;
int playcnt, reccnt;
- int parsing_strategy;
+ struct hdac_pcm_devinfo *devs;
+ int num_devs;
} audio;
/* XXX undefined: modem, hdmi. */
} function;
@@ -268,6 +278,7 @@ struct hdac_chan {
struct pcm_channel *c;
struct pcmchan_caps caps;
struct hdac_devinfo *devinfo;
+ struct hdac_pcm_devinfo *pdevinfo;
struct hdac_dma bdl_dma;
uint32_t spd, fmt, fmtlist[8], pcmrates[16];
uint32_t supp_stream_formats, supp_pcm_size_rate;
@@ -278,10 +289,29 @@ struct hdac_chan {
int off;
int sid;
int bit16, bit32;
+ int as;
nid_t io[16];
};
/****************************************************************************
+ * struct hdac_codec
+ *
+ ****************************************************************************/
+struct hdac_codec {
+ int verbs_sent;
+ int responses_received;
+ nid_t cad;
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint8_t revision_id;
+ uint8_t stepping_id;
+ struct hdac_command_list *commands;
+ struct hdac_softc *sc;
+ struct hdac_devinfo *fgs;
+ int num_fgs;
+};
+
+/****************************************************************************
* struct hdac_softc
*
* This structure holds the current state of the hdac driver.
@@ -303,6 +333,8 @@ struct hdac_softc {
uint32_t flags;
+ struct hdac_chan *chans;
+ int num_chans;
int num_iss;
int num_oss;
int num_bss;
@@ -319,10 +351,7 @@ struct hdac_softc {
struct hdac_dma pos_dma;
- struct hdac_chan play, rec;
bus_dma_tag_t chan_dmat;
- int chan_size;
- int chan_blkcnt;
/*
* Polling
@@ -345,8 +374,6 @@ struct hdac_softc {
uint32_t unsolq[HDAC_UNSOLQ_MAX];
struct hdac_codec *codecs[HDAC_CODEC_MAX];
-
- int registered;
};
/****************************************************************************
OpenPOWER on IntegriCloud