include/sound/hda_verbs.h | 7 +++- sound/hda/common/proc.c | 100 +++++++++++++++++++++++++++++++--------------- 2 files changed, 74 insertions(+), 33 deletions(-)
print_gpio() prints the GPIO capability header and the bidirectional
GPIO state, but it never reports the separate GPI and GPO pins even
though AC_PAR_GPIO_CAP exposes their counts.
The HD-audio specification defines dedicated GPI and GPO verbs
alongside the GPIO ones, so codecs with input-only or output-only
general-purpose pins currently lose that state from
/proc/asound/card*/codec#* altogether.
Add the missing read verb definitions and extend print_gpio() to dump
the GPI and GPO pins, too, while leaving the existing IO[] output
unchanged.
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
include/sound/hda_verbs.h | 7 +++-
sound/hda/common/proc.c | 100 +++++++++++++++++++++++++++++++---------------
2 files changed, 74 insertions(+), 33 deletions(-)
diff --git a/include/sound/hda_verbs.h b/include/sound/hda_verbs.h
index 006d358acce2..127e7016e4fe 100644
--- a/include/sound/hda_verbs.h
+++ b/include/sound/hda_verbs.h
@@ -56,7 +56,12 @@ enum {
#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d
#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */
#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
-/* f10-f1a: GPIO */
+/* f10-f1a: GPI/GPO/GPIO */
+#define AC_VERB_GET_GPI_DATA 0x0f10
+#define AC_VERB_GET_GPI_WAKE_MASK 0x0f11
+#define AC_VERB_GET_GPI_UNSOLICITED_RSP_MASK 0x0f12
+#define AC_VERB_GET_GPI_STICKY_MASK 0x0f13
+#define AC_VERB_GET_GPO_DATA 0x0f14
#define AC_VERB_GET_GPIO_DATA 0x0f15
#define AC_VERB_GET_GPIO_MASK 0x0f16
#define AC_VERB_GET_GPIO_DIRECTION 0x0f17
diff --git a/sound/hda/common/proc.c b/sound/hda/common/proc.c
index 3bc33c5617b2..c83796b13d3d 100644
--- a/sound/hda/common/proc.c
+++ b/sound/hda/common/proc.c
@@ -640,41 +640,78 @@ static void print_gpio(struct snd_info_buffer *buffer,
{
unsigned int gpio =
param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
- unsigned int enable, direction, wake, unsol, sticky, data;
- int i, max;
+ int i, gpio_max, gpo_max, gpi_max;
+
+ gpio_max = gpio & AC_GPIO_IO_COUNT;
+ gpo_max = (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT;
+ gpi_max = (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT;
+
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_max, gpo_max, gpi_max,
(gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
(gpio & AC_GPIO_WAKE) ? 1 : 0);
- max = gpio & AC_GPIO_IO_COUNT;
- if (!max || max > 8)
- return;
- 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, unsol=%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,
- (unsol & (1<<i)) ? 1 : 0);
- /* FIXME: add GPO and GPI pin information */
+
+ if (gpio_max && gpio_max <= 8) {
+ unsigned int enable, direction, wake, unsol, sticky, data;
+
+ 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 < gpio_max; ++i) {
+ snd_iprintf(buffer,
+ " IO[%d]: enable=%d, dir=%d, wake=%d, ",
+ i, (enable & (1 << i)) ? 1 : 0,
+ (direction & (1 << i)) ? 1 : 0,
+ (wake & (1 << i)) ? 1 : 0);
+ snd_iprintf(buffer,
+ "sticky=%d, data=%d, unsol=%d\n",
+ (sticky & (1 << i)) ? 1 : 0,
+ (data & (1 << i)) ? 1 : 0,
+ (unsol & (1 << i)) ? 1 : 0);
+ }
+ }
+
+ if (gpo_max && gpo_max <= 8) {
+ unsigned int gpo_data;
+
+ gpo_data = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPO_DATA, 0);
+ for (i = 0; i < gpo_max; ++i)
+ snd_iprintf(buffer, " GPO[%d]: data=%d\n", i,
+ (gpo_data & (1 << i)) ? 1 : 0);
+ }
+
+ if (gpi_max && gpi_max <= 8) {
+ unsigned int wake, unsol, sticky, data;
+
+ wake = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPI_WAKE_MASK, 0);
+ unsol = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPI_UNSOLICITED_RSP_MASK,
+ 0);
+ sticky = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPI_STICKY_MASK, 0);
+ data = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_GPI_DATA, 0);
+ for (i = 0; i < gpi_max; ++i)
+ snd_iprintf(buffer, " GPI[%d]: wake=%d, sticky=%d, data=%d, unsol=%d\n",
+ i, (wake & (1 << i)) ? 1 : 0,
+ (sticky & (1 << i)) ? 1 : 0,
+ (data & (1 << i)) ? 1 : 0,
+ (unsol & (1 << i)) ? 1 : 0);
+ }
+
print_nid_array(buffer, codec, nid, &codec->mixers);
print_nid_array(buffer, codec, nid, &codec->nids);
}
@@ -940,4 +977,3 @@ int snd_hda_codec_proc_new(struct hda_codec *codec)
snprintf(name, sizeof(name), "codec#%d", codec->core.addr);
return snd_card_ro_proc_new(codec->card, name, codec, print_codec_info);
}
-
---
base-commit: 0ce5115cb8f38e23044b04644fce7661336c1efc
change-id: 20260328-hda-proc-gpi-gpo-950a518e7ac6
Best regards,
--
Cássio Gabriel <cassiogabrielcontato@gmail.com>
On Sat, 28 Mar 2026 05:53:35 +0100, Cássio Gabriel wrote: > > print_gpio() prints the GPIO capability header and the bidirectional > GPIO state, but it never reports the separate GPI and GPO pins even > though AC_PAR_GPIO_CAP exposes their counts. > > The HD-audio specification defines dedicated GPI and GPO verbs > alongside the GPIO ones, so codecs with input-only or output-only > general-purpose pins currently lose that state from > /proc/asound/card*/codec#* altogether. > > Add the missing read verb definitions and extend print_gpio() to dump > the GPI and GPO pins, too, while leaving the existing IO[] output > unchanged. > > Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Applied to for-next branch now. I noticed that the verbs for setting GPI and GPO are missing. Will submit a patch to complete those. thanks, Takashi
On 3/28/26 10:42, Takashi Iwai wrote: > > I noticed that the verbs for setting GPI and GPO are missing. > Will submit a patch to complete those. > > > thanks, > > Takashi Cool, thank you! -- Cássio
© 2016 - 2026 Red Hat, Inc.