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>master
parent
0da18c2dd1
commit
3bd246d1cf
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue