summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_proc.c
diff options
context:
space:
mode:
authorAndrew Paprocki <andrew@ishiboo.com>2008-01-18 12:51:11 +0100
committerJaroslav Kysela <perex@perex.cz>2008-01-31 17:30:04 +0100
commit797760ab14db4e82a50c06a9916dd5c6147b415b (patch)
treec60c279c9dbbe81d399a0d6a7648cfacb2bef60d /sound/pci/hda/hda_proc.c
parente0059549345903195d6eb796c22048204c40a785 (diff)
downloadtalos-op-linux-797760ab14db4e82a50c06a9916dd5c6147b415b.tar.gz
talos-op-linux-797760ab14db4e82a50c06a9916dd5c6147b415b.zip
[ALSA] hda_proc - Add a number of new settings to proc codec output
This patch adds additional output to the /proc codec#X info. The following pieces of information are added to the output: - Balanced, L/R swap, trigger, impedance sense pin capabilities - Vref pin capabilities - Current Vref pin widget control setting - Default configuration association, sequence, and misc bit test - EAPD/BTL bits conveying balanced mode, EAPD, and L/R swap - Power state modified to show state name as well as setting vs actual value - GPIO parameter output on Audio Function Group, including enumeration of IO pins which are indicated present (Any I and O pins are not output at this time) - Stripe and L/R swap widget capabilities - All digital converter bits: enable, validity, validity config, preemphasis, copyright, non-audio, professional, generation level, and content category - Converter stream and channel values for in/out widgets - SDI select value for in widgets - Unsolicited response widget capability tag and enabled bit - Delay widget capability value - Processing widget capability benign bit and number of coefficients - Realtek Define Registers: processing coefficient, coefficient index [Also, fixed space/tab issues and make codes a bit more readable -- Takashi] Signed-off-by: Andrew Paprocki <andrew@ishiboo.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/hda_proc.c')
-rw-r--r--sound/pci/hda/hda_proc.c351
1 files changed, 301 insertions, 50 deletions
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 4b8d64498fb1..35a630d1770f 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -202,7 +202,8 @@ static const char *get_jack_color(u32 cfg)
}
static void print_pin_caps(struct snd_info_buffer *buffer,
- struct hda_codec *codec, hda_nid_t nid)
+ struct hda_codec *codec, hda_nid_t nid,
+ int *supports_vref)
{
static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
static char *jack_types[16] = {
@@ -226,7 +227,45 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
snd_iprintf(buffer, " EAPD");
if (caps & AC_PINCAP_PRES_DETECT)
snd_iprintf(buffer, " Detect");
+ if (caps & AC_PINCAP_BALANCE)
+ snd_iprintf(buffer, " Balanced");
+ if (caps & AC_PINCAP_LR_SWAP)
+ snd_iprintf(buffer, " R/L");
+ if (caps & AC_PINCAP_TRIG_REQ)
+ snd_iprintf(buffer, " Trigger");
+ if (caps & AC_PINCAP_IMP_SENSE)
+ snd_iprintf(buffer, " ImpSense");
snd_iprintf(buffer, "\n");
+ if (caps & AC_PINCAP_VREF) {
+ unsigned int vref =
+ (caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+ snd_iprintf(buffer, " Vref caps:");
+ if (vref & AC_PINCAP_VREF_HIZ)
+ snd_iprintf(buffer, " HIZ");
+ if (vref & AC_PINCAP_VREF_50)
+ snd_iprintf(buffer, " 50");
+ if (vref & AC_PINCAP_VREF_GRD)
+ snd_iprintf(buffer, " GRD");
+ if (vref & AC_PINCAP_VREF_80)
+ snd_iprintf(buffer, " 80");
+ if (vref & AC_PINCAP_VREF_100)
+ snd_iprintf(buffer, " 100");
+ snd_iprintf(buffer, "\n");
+ *supports_vref = 1;
+ } else
+ *supports_vref = 0;
+ if (caps & AC_PINCAP_EAPD) {
+ val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_EAPD_BTLENABLE, 0);
+ snd_iprintf(buffer, " EAPD 0x%x:", val);
+ if (val & AC_EAPDBTL_BALANCED)
+ snd_iprintf(buffer, " BALANCED");
+ if (val & AC_EAPDBTL_EAPD)
+ snd_iprintf(buffer, " EAPD");
+ if (val & AC_EAPDBTL_LR_SWAP)
+ snd_iprintf(buffer, " R/L");
+ snd_iprintf(buffer, "\n");
+ }
caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
@@ -236,13 +275,233 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
snd_iprintf(buffer, " Conn = %s, Color = %s\n",
get_jack_connection(caps),
get_jack_color(caps));
- if (caps & AC_PINCAP_EAPD) {
- val = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_EAPD_BTLENABLE, 0);
- snd_iprintf(buffer, " EAPD: 0x%x\n", val);
+ /* Default association and sequence values refer to default grouping
+ * of pin complexes and their sequence within the group. This is used
+ * for priority and resource allocation.
+ */
+ snd_iprintf(buffer, " DefAssociation = 0x%x, Sequence = 0x%x\n",
+ (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT,
+ caps & AC_DEFCFG_SEQUENCE);
+ if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) &
+ AC_DEFCFG_MISC_NO_PRESENCE) {
+ /* Miscellaneous bit indicates external hardware does not
+ * support presence detection even if the pin complex
+ * indicates it is supported.
+ */
+ snd_iprintf(buffer, " Misc = NO_PRESENCE\n");
}
}
+static void print_pin_ctls(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid,
+ int supports_vref)
+{
+ unsigned int pinctls;
+
+ pinctls = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
+ if (pinctls & AC_PINCTL_IN_EN)
+ snd_iprintf(buffer, " IN");
+ if (pinctls & AC_PINCTL_OUT_EN)
+ snd_iprintf(buffer, " OUT");
+ if (pinctls & AC_PINCTL_HP_EN)
+ snd_iprintf(buffer, " HP");
+ if (supports_vref) {
+ int vref = pinctls & AC_PINCTL_VREFEN;
+ switch (vref) {
+ case AC_PINCTL_VREF_HIZ:
+ snd_iprintf(buffer, " VREF_HIZ");
+ break;
+ case AC_PINCTL_VREF_50:
+ snd_iprintf(buffer, " VREF_50");
+ break;
+ case AC_PINCTL_VREF_GRD:
+ snd_iprintf(buffer, " VREF_GRD");
+ break;
+ case AC_PINCTL_VREF_80:
+ snd_iprintf(buffer, " VREF_80");
+ break;
+ case AC_PINCTL_VREF_100:
+ snd_iprintf(buffer, " VREF_100");
+ break;
+ }
+ }
+ snd_iprintf(buffer, "\n");
+}
+
+static void print_vol_knob(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int cap = snd_hda_param_read(codec, nid,
+ AC_PAR_VOL_KNB_CAP);
+ snd_iprintf(buffer, " Volume-Knob: delta=%d, steps=%d, ",
+ (cap >> 7) & 1, cap & 0x7f);
+ cap = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+ snd_iprintf(buffer, "direct=%d, val=%d\n",
+ (cap >> 7) & 1, cap & 0x7f);
+}
+
+static void print_audio_io(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid,
+ unsigned int wid_type)
+{
+ int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+ snd_iprintf(buffer,
+ " Converter: stream=%d, channel=%d\n",
+ (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
+ conv & AC_CONV_CHANNEL);
+
+ if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) {
+ int sdi = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_SDI_SELECT, 0);
+ snd_iprintf(buffer, " SDI-Select: %d\n",
+ sdi & AC_SDI_SELECT);
+ }
+}
+
+static void print_digital_conv(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_DIGI_CONVERT_1, 0);
+ unsigned int digi2 = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_DIGI_CONVERT_2, 0);
+ snd_iprintf(buffer, " Digital:");
+ if (digi1 & AC_DIG1_ENABLE)
+ snd_iprintf(buffer, " Enabled");
+ if (digi1 & AC_DIG1_V)
+ snd_iprintf(buffer, " Validity");
+ if (digi1 & AC_DIG1_VCFG)
+ snd_iprintf(buffer, " ValidityCfg");
+ if (digi1 & AC_DIG1_EMPHASIS)
+ snd_iprintf(buffer, " Preemphasis");
+ if (digi1 & AC_DIG1_COPYRIGHT)
+ snd_iprintf(buffer, " Copyright");
+ if (digi1 & AC_DIG1_NONAUDIO)
+ snd_iprintf(buffer, " Non-Audio");
+ if (digi1 & AC_DIG1_PROFESSIONAL)
+ snd_iprintf(buffer, " Pro");
+ if (digi1 & AC_DIG1_LEVEL)
+ snd_iprintf(buffer, " GenLevel");
+ snd_iprintf(buffer, "\n");
+ snd_iprintf(buffer, " Digital category: 0x%x\n", digi2 & AC_DIG2_CC);
+}
+
+static const char *get_pwr_state(u32 state)
+{
+ static const char *buf[4] = {
+ "D0", "D1", "D2", "D3"
+ };
+ if (state < 4)
+ return buf[state];
+ return "UNKNOWN";
+}
+
+static void print_power_state(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ int pwr = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_POWER_STATE, 0);
+ snd_iprintf(buffer, " Power: setting=%s, actual=%s\n",
+ get_pwr_state(pwr & AC_PWRST_SETTING),
+ get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
+ AC_PWRST_ACTUAL_SHIFT));
+}
+
+static void print_unsol_cap(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ int unsol = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_UNSOLICITED_RESPONSE, 0);
+ snd_iprintf(buffer,
+ " Unsolicited: tag=%02x, enabled=%d\n",
+ unsol & AC_UNSOL_TAG,
+ (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
+}
+
+static void print_proc_caps(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int proc_caps = snd_hda_param_read(codec, nid,
+ AC_PAR_PROC_CAP);
+ snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n",
+ proc_caps & AC_PCAP_BENIGN,
+ (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT);
+}
+
+static void print_conn_list(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid,
+ unsigned int wid_type, hda_nid_t *conn,
+ int conn_len)
+{
+ int c, curr = -1;
+
+ if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
+ curr = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
+ snd_iprintf(buffer, " Connection: %d\n", conn_len);
+ if (conn_len > 0) {
+ snd_iprintf(buffer, " ");
+ for (c = 0; c < conn_len; c++) {
+ snd_iprintf(buffer, " 0x%02x", conn[c]);
+ if (c == curr)
+ snd_iprintf(buffer, "*");
+ }
+ snd_iprintf(buffer, "\n");
+ }
+}
+
+static void print_realtek_coef(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ int coeff = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PROC_COEF, 0);
+ snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
+ coeff = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_COEF_INDEX, 0);
+ snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
+}
+
+static void print_gpio(struct snd_info_buffer *buffer,
+ struct hda_codec *codec, hda_nid_t nid)
+{
+ unsigned int gpio =
+ snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+ unsigned int enable, direction, wake, unsol, sticky, data;
+ int i, max;
+ snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
+ "unsolicited=%d, wake=%d\n",
+ gpio & AC_GPIO_IO_COUNT,
+ (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT,
+ (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT,
+ (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
+ (gpio & AC_GPIO_WAKE) ? 1 : 0);
+ max = gpio & AC_GPIO_IO_COUNT;
+ enable = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_MASK, 0);
+ direction = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_DIRECTION, 0);
+ wake = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_WAKE_MASK, 0);
+ unsol = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0);
+ sticky = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_STICKY_MASK, 0);
+ data = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPIO_DATA, 0);
+ for (i = 0; i < max; ++i)
+ snd_iprintf(buffer,
+ " IO[%d]: enable=%d, dir=%d, wake=%d, "
+ "sticky=%d, data=%d\n", i,
+ (enable & (1<<i)) ? 1 : 0,
+ (direction & (1<<i)) ? 1 : 0,
+ (wake & (1<<i)) ? 1 : 0,
+ (sticky & (1<<i)) ? 1 : 0,
+ (data & (1<<i)) ? 1 : 0);
+ /* FIXME: add GPO and GPI pin information */
+}
static void print_codec_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
@@ -280,15 +539,17 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_hda_power_down(codec);
return;
}
+
+ print_gpio(buffer, codec, codec->afg);
+
for (i = 0; i < nodes; i++, nid++) {
unsigned int wid_caps =
snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP);
unsigned int wid_type =
(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
- int conn_len = 0;
hda_nid_t conn[HDA_MAX_CONNECTIONS];
- unsigned int pinctls;
+ int conn_len = 0;
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
get_wid_type_name(wid_type), wid_caps);
@@ -302,6 +563,10 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_iprintf(buffer, " Amp-In");
if (wid_caps & AC_WCAP_OUT_AMP)
snd_iprintf(buffer, " Amp-Out");
+ if (wid_caps & AC_WCAP_STRIPE)
+ snd_iprintf(buffer, " Stripe");
+ if (wid_caps & AC_WCAP_LR_SWAP)
+ snd_iprintf(buffer, " R/L");
snd_iprintf(buffer, "\n");
/* volume knob is a special widget that always have connection
@@ -330,33 +595,20 @@ static void print_codec_info(struct snd_info_entry *entry,
}
switch (wid_type) {
- case AC_WID_PIN:
- print_pin_caps(buffer, codec, nid);
- pinctls = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL,
- 0);
- snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls);
- if (pinctls & AC_PINCTL_IN_EN)
- snd_iprintf(buffer, " IN");
- if (pinctls & AC_PINCTL_OUT_EN)
- snd_iprintf(buffer, " OUT");
- if (pinctls & AC_PINCTL_HP_EN)
- snd_iprintf(buffer, " HP");
- snd_iprintf(buffer, "\n");
+ case AC_WID_PIN: {
+ int supports_vref;
+ print_pin_caps(buffer, codec, nid, &supports_vref);
+ print_pin_ctls(buffer, codec, nid, supports_vref);
break;
+ }
case AC_WID_VOL_KNB:
- pinctls = snd_hda_param_read(codec, nid,
- AC_PAR_VOL_KNB_CAP);
- snd_iprintf(buffer, " Volume-Knob: delta=%d, "
- "steps=%d, ",
- (pinctls >> 7) & 1, pinctls & 0x7f);
- pinctls = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
- snd_iprintf(buffer, "direct=%d, val=%d\n",
- (pinctls >> 7) & 1, pinctls & 0x7f);
+ print_vol_knob(buffer, codec, nid);
break;
case AC_WID_AUD_OUT:
case AC_WID_AUD_IN:
+ print_audio_io(buffer, codec, nid, wid_type);
+ if (wid_caps & AC_WCAP_DIGITAL)
+ print_digital_conv(buffer, codec, nid);
if (wid_caps & AC_WCAP_FORMAT_OVRD) {
snd_iprintf(buffer, " PCM:\n");
print_pcm_caps(buffer, codec, nid);
@@ -364,28 +616,27 @@ static void print_codec_info(struct snd_info_entry *entry,
break;
}
+ if (wid_caps & AC_WCAP_UNSOL_CAP)
+ print_unsol_cap(buffer, codec, nid);
+
if (wid_caps & AC_WCAP_POWER)
- snd_iprintf(buffer, " Power: 0x%x\n",
- snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_POWER_STATE,
- 0));
-
- if (wid_caps & AC_WCAP_CONN_LIST) {
- int c, curr = -1;
- if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
- curr = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_CONNECT_SEL, 0);
- snd_iprintf(buffer, " Connection: %d\n", conn_len);
- if (conn_len > 0) {
- snd_iprintf(buffer, " ");
- for (c = 0; c < conn_len; c++) {
- snd_iprintf(buffer, " 0x%02x", conn[c]);
- if (c == curr)
- snd_iprintf(buffer, "*");
- }
- snd_iprintf(buffer, "\n");
- }
- }
+ print_power_state(buffer, codec, nid);
+
+ if (wid_caps & AC_WCAP_DELAY)
+ snd_iprintf(buffer, " Delay: %d samples\n",
+ (wid_caps & AC_WCAP_DELAY) >>
+ AC_WCAP_DELAY_SHIFT);
+
+ if (wid_caps & AC_WCAP_CONN_LIST)
+ print_conn_list(buffer, codec, nid, wid_type,
+ conn, conn_len);
+
+ if (wid_caps & AC_WCAP_PROC_WID)
+ print_proc_caps(buffer, codec, nid);
+
+ /* NID 0x20 == Realtek Define Registers */
+ if (codec->vendor_id == 0x10ec && nid == 0x20)
+ print_realtek_coef(buffer, codec, nid);
}
snd_hda_power_down(codec);
}
OpenPOWER on IntegriCloud