]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ALSA: hda/proc: show GPI and GPO state in codec proc output
authorCássio Gabriel <cassiogabrielcontato@gmail.com>
Sat, 28 Mar 2026 04:53:35 +0000 (01:53 -0300)
committerTakashi Iwai <tiwai@suse.de>
Sat, 28 Mar 2026 13:18:37 +0000 (14:18 +0100)
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>
include/sound/hda_verbs.h
sound/hda/common/proc.c

index 006d358acce254480b5b8a28ce245bbcea005e54..127e7016e4fec5746ff9567ae9324b4ea2eed876 100644 (file)
@@ -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
index 3bc33c5617b2cdc7afa5e8e2f9ad0698ee034dff..c83796b13d3de81eb7ffd46e4cf8ee5505ecfd3e 100644 (file)
@@ -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);
 }
-