mirror of
https://github.com/alsa-project/alsa-tools.git
synced 2025-10-29 05:40:25 -04:00
Add a small "hdajacksensetest" helper
I previously had a small python script doing the same thing, but it depended on hda-analyzer, which always breaks when something new is added to the codec proc file. I got tired and rewrote it as a small C program instead, which I hope will be a useful addition to alsa-tools. Signed-off-by: David Henningsson <david.henningsson@canonical.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
eb6408a791
commit
7a7d94a031
5 changed files with 182 additions and 1 deletions
12
hdajacksensetest/Makefile.am
Normal file
12
hdajacksensetest/Makefile.am
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
MYNAME = hdajacksensetest
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
bin_PROGRAMS = hdajacksensetest
|
||||
AM_CFLAGS = @GLIB_CFLAGS@ -I "../hdajackretask/" -I "../hda-verb/"
|
||||
hdajacksensetest_SOURCES = hdajacksensetest.c ../hdajackretask/sysfs-pin-configs.c
|
||||
hdajacksensetest_LDADD = @GLIB_LIBS@
|
||||
|
||||
alsa-dist: distdir
|
||||
@rm -rf ../distdir/$(MYNAME)
|
||||
@mkdir -p ../distdir/$(MYNAME)
|
||||
@cp -RLpv $(distdir)/* ../distdir/$(MYNAME)
|
||||
@rm -rf $(distdir)
|
||||
10
hdajacksensetest/configure.ac
Normal file
10
hdajacksensetest/configure.ac
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
AC_INIT(hdajacksensetest, 0.20141006)
|
||||
AM_INIT_AUTOMAKE(subdir-objects)
|
||||
AM_MAINTAINER_MODE([enable])
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AC_HEADER_STDC
|
||||
|
||||
PKG_CHECK_MODULES([GLIB], [glib-2.0])
|
||||
|
||||
AC_OUTPUT(Makefile)
|
||||
13
hdajacksensetest/gitcompile
Executable file
13
hdajacksensetest/gitcompile
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
aclocal $ACLOCAL_FLAGS || exit 1
|
||||
automake --foreign --add-missing || exit 1
|
||||
autoconf || exit 1
|
||||
export CFLAGS='-O2 -Wall -pipe -g'
|
||||
echo "CFLAGS=$CFLAGS"
|
||||
echo "./configure $@"
|
||||
./configure $@ || exit 1
|
||||
unset CFLAGS
|
||||
if [ -z "$GITCOMPILE_NO_MAKE" ]; then
|
||||
make || exit 1
|
||||
fi
|
||||
146
hdajacksensetest/hdajacksensetest.c
Normal file
146
hdajacksensetest/hdajacksensetest.c
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Checks the current pin/jack status of the codec
|
||||
*
|
||||
* Copyright (c) 2014 David Henningsson, Canonical Ltd. <david.henningsson@canonical.com>
|
||||
* (With some minor pieces copy-pasted from hda-verb by Takashi Iwai)
|
||||
*
|
||||
* Licensed under GPL v2 or later.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <glib.h>
|
||||
#include <errno.h>
|
||||
#include "sysfs-pin-configs.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdint.h>
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
#include "hda_hwdep.h"
|
||||
|
||||
gint card_index, codec_index;
|
||||
gboolean try_all_pins, set_pin_sense;
|
||||
|
||||
static GOptionEntry arg_entries[] =
|
||||
{
|
||||
{ "card", 'c', 0, G_OPTION_ARG_INT, &card_index, "card index (as can be seen in /proc/asound/cards)", "X" },
|
||||
{ "codec", 'd', 0, G_OPTION_ARG_INT, &codec_index, "codec device index (as can be seen in /proc/asound/cardX/codecY)", "Y" },
|
||||
{ "allpins", 'a', 0, G_OPTION_ARG_NONE, &try_all_pins, "try all pins, even those who (probably) does not have a physical jack", NULL },
|
||||
{ "setpinsense", 's', 0, G_OPTION_ARG_NONE, &set_pin_sense, "execute 'Set pin sense' before the pin sense is measured", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void parse_command_line(int argc, char **argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GOptionContext *context = g_option_context_new("- check current jack/pin sense");
|
||||
g_option_context_add_main_entries(context, arg_entries, NULL);
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error)) {
|
||||
fprintf(stderr, "Option parsing failed: %s\n", error->message);
|
||||
exit(1);
|
||||
}
|
||||
g_option_context_free(context);
|
||||
}
|
||||
|
||||
|
||||
static gboolean should_check_pin(pin_configs_t *pin)
|
||||
{
|
||||
unsigned long defcfg = actual_pin_config(pin);
|
||||
if (try_all_pins)
|
||||
return TRUE;
|
||||
if (get_port_conn(defcfg) != 0)
|
||||
return FALSE; // Not a jack
|
||||
if (defcfg & (1 << 8)) // Jack has NO_PRESENCE set
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int fd;
|
||||
|
||||
static void codec_open()
|
||||
{
|
||||
char filename[64];
|
||||
int version = 0;
|
||||
|
||||
snprintf(filename, 64, "/dev/snd/hwC%dD%d", card_index, codec_index);
|
||||
fd = open(filename, O_RDWR);
|
||||
if (fd < 0) {
|
||||
if (errno == EACCES)
|
||||
fprintf(stderr, "Permission error (hint: this program usually requires root)\n");
|
||||
else
|
||||
fprintf(stderr, "Ioctl call failed with error %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ioctl(fd, HDA_IOCTL_PVERSION, &version) < 0) {
|
||||
fprintf(stderr, "Ioctl call failed with error %d\n", errno);
|
||||
fprintf(stderr, "Looks like an invalid hwdep device...\n");
|
||||
close(fd);
|
||||
exit(1);
|
||||
}
|
||||
if (version < HDA_HWDEP_VERSION) {
|
||||
fprintf(stderr, "Invalid version number 0x%x\n", version);
|
||||
fprintf(stderr, "Looks like an invalid hwdep device...\n");
|
||||
close(fd);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long codec_rw(int nid, int verb, int param)
|
||||
{
|
||||
struct hda_verb_ioctl val;
|
||||
|
||||
val.verb = HDA_VERB(nid, verb, param);
|
||||
if (ioctl(fd, HDA_IOCTL_VERB_WRITE, &val) < 0) {
|
||||
fprintf(stderr, "Ioctl call failed with error %d\n", errno);
|
||||
close(fd);
|
||||
exit(1);
|
||||
}
|
||||
return val.res;
|
||||
}
|
||||
|
||||
#define AC_VERB_GET_PIN_SENSE 0x0f09
|
||||
#define AC_VERB_SET_PIN_SENSE 0x709
|
||||
|
||||
#define MAX_PINS 32
|
||||
|
||||
pin_configs_t pin_configs[MAX_PINS];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int pin_count, i;
|
||||
|
||||
parse_command_line(argc, argv);
|
||||
pin_count = get_pin_configs_list(pin_configs, MAX_PINS, card_index, codec_index);
|
||||
if (pin_count == 0) {
|
||||
fprintf(stderr, "No pins found for card %d codec %d, did you pick the right one?\n", card_index, codec_index);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
codec_open();
|
||||
|
||||
if (set_pin_sense) {
|
||||
for (i = 0; i < pin_count; i++)
|
||||
if (should_check_pin(&pin_configs[i])) {
|
||||
codec_rw(pin_configs[i].nid, AC_VERB_SET_PIN_SENSE, 0);
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < pin_count; i++)
|
||||
if (should_check_pin(&pin_configs[i])) {
|
||||
gchar *desc = get_config_description(actual_pin_config(&pin_configs[i]));
|
||||
unsigned long present = codec_rw(pin_configs[i].nid, AC_VERB_GET_PIN_SENSE, 0);
|
||||
printf("Pin 0x%.2x (%s): present = %s\n", pin_configs[i].nid, desc, present & 0x80000000 ? "Yes" : "No");
|
||||
g_free(desc);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue