diff options
| author | Cássio Gabriel <cassiogabrielcontato@gmail.com> | 2026-03-28 07:53:35 +0300 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2026-03-28 16:18:37 +0300 |
| commit | 3bd246d1cf609a80cae19e4aefb599256a72b1a6 (patch) | |
| tree | 37b2c7e7197b25e82578551128d7622ded87ce02 | |
| parent | 0da18c2dd1cc2a026416222ed206e2f269edf055 (diff) | |
| download | linux-3bd246d1cf609a80cae19e4aefb599256a72b1a6.tar.xz | |
ALSA: hda/proc: show GPI and GPO state in codec proc output
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>
Link: https://patch.msgid.link/20260328-hda-proc-gpi-gpo-v1-1-fabb36564bee@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | include/sound/hda_verbs.h | 7 | ||||
| -rw-r--r-- | 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); } - |
