summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Schmidt <stefan@slimlogic.co.uk>2009-09-30 21:12:17 +0200
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-22 22:04:00 +0100
commita9d91614bb310b5f5c05e193ef7559bc512af72e (patch)
tree06b6364f9c9a726cbca9ea5b4e52815ff77707f0
parentbb865dc10b6dcee9d428d3c5a17ee312e0aaf7e0 (diff)
downloadalsa-utils-a9d91614bb310b5f5c05e193ef7559bc512af72e.tar.gz
alsaucm: Add Use Case Manager utility
alsaucm is a command line tool that can be used to generate and debug UCM configuration files. The alsaucm utility can fully use the UCM functionality to query and configure all the UCM functionality in alsa-lib. This work was sponsored by Slimlogic Ltd, Texas Instruments Inc and Wolfson Microelectronics PLC. CC: Ian Molton <ian@mnementh.co.uk> CC: Graeme Gregory <gg@slimlogic.co.uk> Signed-off-by: Justin Xu <justinx@slimlogic.co.uk> Signed-off-by: Stefan Schmidt <stefan@slimlogic.co.uk> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r--Makefile.am2
-rw-r--r--alsaucm/Makefile.am9
-rw-r--r--alsaucm/usecase.c438
-rw-r--r--configure.in1
4 files changed, 449 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 5296977..d92e204 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
INCLUDES=-I$(top_srcdir)/include
-SUBDIRS = include alsactl utils m4 po
+SUBDIRS = include alsactl alsaucm utils m4 po
if ALSAMIXER
SUBDIRS += alsamixer
endif
diff --git a/alsaucm/Makefile.am b/alsaucm/Makefile.am
new file mode 100644
index 0000000..50e1f5b
--- /dev/null
+++ b/alsaucm/Makefile.am
@@ -0,0 +1,9 @@
+bin_PROGRAMS = \
+ alsaucm
+
+alsaucm_SOURCES = usecase.c
+
+INCLUDES = \
+ -Wall -I$(top_srcdir)/include
+
+alsaucm_LDADD = -lasound
diff --git a/alsaucm/usecase.c b/alsaucm/usecase.c
new file mode 100644
index 0000000..2db26f1
--- /dev/null
+++ b/alsaucm/usecase.c
@@ -0,0 +1,438 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Support for the verb/device/modifier core logic and API,
+ * command line tool and file parser was kindly sponsored by
+ * Texas Instruments Inc.
+ * Support for multiple active modifiers and devices,
+ * transition sequences, multiple client access and user defined use
+ * cases was kindly sponsored by Wolfson Microelectronics PLC.
+ *
+ * Copyright (C) 2008-2010 SlimLogic Ltd
+ * Copyright (C) 2010 Wolfson Microelectronics PLC
+ * Copyright (C) 2010 Texas Instruments Inc.
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Stefan Schmidt <stefan@slimlogic.co.uk>
+ * Justin Xu <justinx@slimlogic.co.uk>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <alsa/asoundlib.h>
+#include <alsa/use-case.h>
+
+#define MAX_BUF 256
+
+enum uc_cmd {
+ /* list verb, devices and modifiers */
+ OM_UNKNOWN = 0,
+ OM_LIST_VERBS,
+ OM_LIST_DEVICES,
+ OM_LIST_MODIFIERS,
+
+ /* enable and disable verb, device and modifier */
+ OM_SET_VERB,
+ OM_GET_VERB,
+ OM_ENABLE_DEVICE,
+ OM_ENABLE_MODIFIER,
+ OM_DISABLE_DEVICE,
+ OM_DISABLE_MODIFIER,
+ OM_SWITCH_DEVICE,
+ OM_SWITCH_MODIFIER,
+
+ /* dump sound card kcontrols */
+ OP_DUMP,
+ OP_HELP,
+ OP_QUIT,
+ OP_RESET,
+};
+
+static void dump_help(char *name)
+{
+ if (name)
+ printf("Usage: \n"
+ " %s <card>"
+ " %s <card> <cmd> [use case] [<cmd> [use case]]\n",
+ name, name);
+
+ printf( " reset - reset sound card to default state\n"
+ " listv - list available use case verbs\n"
+ " getv - get current verb\n"
+ " setv <name> - apply use case verb <name>\n"
+ " setd <name> - enable use case device <name>\n"
+ " setm <name> - enable use case modifier <name>\n"
+ " switchd <old> <new> - disable <old> device enable <new> device\n"
+ " switchm <old> <new> - disable <old> modifier enable <new> modifier\n"
+ " cleard <name> - disable use case device <name>\n"
+ " clearm <name> - disable use case modifier <name>\n"
+ " listd - list available use case devices for current verb\n"
+ " listm - list available use case modifiers for current verb\n"
+ " dump - dump all mixer control values\n"
+ " h - help\n"
+ " q - quit\n");
+}
+
+/* list devices and status for current verb */
+static int list_verb_device_status(snd_use_case_mgr_t *uc_mgr)
+{
+ const char **device_list, *verb;
+ int i, enabled, num;
+
+ verb = snd_use_case_get_verb(uc_mgr);
+ if (verb == NULL)
+ return -ENODEV;
+
+ num = snd_use_case_get_device_list(uc_mgr, verb, &device_list);
+ if (num <= 0) {
+ printf(" no devices.\n");
+ return 0;
+ }
+
+ for (i = 0; i < num; i++) {
+ enabled = snd_use_case_get_device_status(uc_mgr,
+ device_list[i]);
+ if (enabled < 0)
+ printf(" %s: failed to get status %d\n",
+ device_list[i], enabled);
+ else
+ printf(" %s: %s\n", device_list[i],
+ enabled ? "enabled" : "disabled");
+ }
+ return num;
+}
+
+/* list devices and status for current verb */
+static int list_verb_modifiers_status(snd_use_case_mgr_t *uc_mgr)
+{
+ const char **modifier_list, *verb;
+ int i, enabled, num;
+
+ verb = snd_use_case_get_verb(uc_mgr);
+ if (verb == NULL)
+ return -ENODEV;
+
+ num = snd_use_case_get_mod_list(uc_mgr, verb, &modifier_list);
+ if (num <= 0) {
+ printf(" no modifiers\n");
+ return 0;
+ }
+
+ for (i = 0; i < num; i++) {
+ enabled = snd_use_case_get_modifier_status(uc_mgr,
+ modifier_list[i]);
+ if (enabled < 0)
+ printf(" %s: failed to get status %d\n",
+ modifier_list[i], enabled);
+ else
+ printf(" %s: %s\n", modifier_list[i],
+ enabled ? "enabled" : "disabled");
+ }
+ return num;
+}
+
+static int list_verbs(snd_use_case_mgr_t *uc_mgr)
+{
+ const char **verb_list;
+ int num, i;
+
+ /* get list of use case verbs */
+ num = snd_use_case_get_verb_list(uc_mgr, &verb_list);
+ if (num == 0) {
+ printf(" error: no verbs defined for sound card\n");
+ return 0;
+ } else if (num < 0) {
+ printf(" error: can't get verbs for sound card\n");
+ return num;
+ }
+
+ for (i = 0 ; i < num ; i++) {
+ const char *verb = verb_list[i];
+ printf(" %s\n", verb);
+ }
+
+ return 0;
+}
+
+static int parse_cmdline(char *cmd, enum uc_cmd *command)
+{
+ if (!strcmp(cmd, "listv"))
+ *command = OM_LIST_VERBS;
+ else if (!strcmp(cmd, "listd"))
+ *command = OM_LIST_DEVICES;
+ else if (!strcmp(cmd, "listm"))
+ *command = OM_LIST_MODIFIERS;
+ else if (!strcmp(cmd, "setv"))
+ *command = OM_SET_VERB;
+ else if (!strcmp(cmd, "getv"))
+ *command = OM_GET_VERB;
+ else if (!strcmp(cmd, "setd"))
+ *command = OM_ENABLE_DEVICE;
+ else if (!strcmp(cmd, "setm"))
+ *command = OM_ENABLE_MODIFIER;
+ else if (!strcmp(cmd, "cleard"))
+ *command = OM_DISABLE_DEVICE;
+ else if (!strcmp(cmd, "clearm"))
+ *command = OM_DISABLE_MODIFIER;
+ else if (!strcmp(cmd, "switchd"))
+ *command = OM_SWITCH_DEVICE;
+ else if (!strcmp(cmd, "switchm"))
+ *command = OM_SWITCH_MODIFIER;
+ else if (!strcmp(cmd, "q"))
+ *command = OP_QUIT;
+ else if (!strcmp(cmd, "h"))
+ *command = OP_HELP;
+ else if (!strcmp(cmd, "dump"))
+ *command = OP_DUMP;
+ else if (!strcmp(cmd, "reset"))
+ *command = OP_RESET;
+
+ if (*command)
+ return 1;
+ return -1;
+}
+
+static int parse_cmd(char *cmd, enum uc_cmd *command, const char **parameter)
+{
+ char *cmd_c = cmd;
+
+ *parameter = NULL;
+ *command = OM_UNKNOWN;
+
+ /*
+ * fgets() reads '\n' from stdin
+ * it needs to be removed here
+ */
+ cmd_c = strchr(cmd, '\n');
+ if (cmd_c != NULL)
+ *cmd_c = 0;
+
+ cmd_c = cmd;
+
+ /* Truncate spaces */
+ while (*cmd_c == ' ')
+ cmd_c++;
+
+ if (*cmd_c == 0)
+ return 0;
+
+ cmd = cmd_c;
+
+ cmd_c = strchr(cmd, ' ');
+ if (cmd_c != NULL) {
+ *cmd_c = 0;
+ /* Truncate spaces */
+ while (*++cmd_c == ' ');
+ *parameter = cmd_c;
+ }
+
+ return parse_cmdline(cmd, command);
+}
+
+static int get_switch_parameter(const char *parameter, const char **old,
+ const char **new)
+{
+ char *c;
+
+ if (parameter == NULL)
+ return -EINVAL;
+
+ *old = parameter;
+
+ c = strchr(parameter, ' ');
+ if (c != NULL) {
+ *c = 0;
+
+ /* Truncate spaces */
+ while (*++c == ' ');
+
+ if (*c) {
+ *new = c;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int do_exit = 0;
+
+static int handle_command(snd_use_case_mgr_t *uc_mgr, enum uc_cmd command,
+ const char *parameter)
+{
+ int ret;
+ const char *verb;
+ const char *old = NULL, *new = NULL;
+
+ switch (command) {
+ case OM_UNKNOWN:
+ printf(" error: unknown command\n");
+ break;
+ case OM_LIST_VERBS:
+ return list_verbs(uc_mgr);
+ case OM_LIST_DEVICES:
+ return list_verb_device_status(uc_mgr);
+ case OM_LIST_MODIFIERS:
+ return list_verb_modifiers_status(uc_mgr);
+ case OM_SET_VERB:
+ return snd_use_case_set_verb(uc_mgr, parameter);
+ case OM_GET_VERB:
+ verb = snd_use_case_get_verb(uc_mgr);
+ if (verb != NULL)
+ printf(" current verb: %s\n", verb);
+ else
+ printf(" no verb enabled.\n");
+ return 0;
+ case OM_ENABLE_DEVICE:
+ return snd_use_case_enable_device(uc_mgr, parameter);
+ case OM_ENABLE_MODIFIER:
+ return snd_use_case_enable_modifier(uc_mgr, parameter);
+ case OM_DISABLE_DEVICE:
+ return snd_use_case_disable_device(uc_mgr, parameter);
+ case OM_DISABLE_MODIFIER:
+ return snd_use_case_disable_modifier(uc_mgr, parameter);
+ case OM_SWITCH_DEVICE:
+ ret = get_switch_parameter(parameter, &old, &new);
+ if (ret)
+ return ret;
+ else
+ return snd_use_case_switch_device(uc_mgr, old, new);
+ case OM_SWITCH_MODIFIER:
+ ret = get_switch_parameter(parameter, &old, &new);
+ if (ret)
+ return ret;
+ else
+ return snd_use_case_switch_modifier(uc_mgr, old, new);
+ case OP_HELP:
+ dump_help(NULL);
+ break;
+ case OP_QUIT:
+ do_exit = 1;
+ break;
+ case OP_RESET:
+ return snd_use_case_mgr_reset(uc_mgr);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ snd_use_case_mgr_t *uc_mgr;
+ const char *parameter;
+ char cmd[MAX_BUF];
+ enum uc_cmd command;
+ int card_argv = 1, cmd_status, i, err;
+
+ if (argc < 2) {
+ dump_help(argv[0]);
+ exit(1);
+ }
+
+ /* check for dump as we dont need to open UCM */
+ if (argc == 3 && !strcmp(argv[2], "dump")) {
+ snd_use_case_dump(argv[1]);
+ return 0;
+ }
+
+ /* open library */
+ uc_mgr = snd_use_case_mgr_open(argv[card_argv]);
+ if (uc_mgr == NULL) {
+ printf("%s: error failed to open sound card %s\n",
+ argv[0], argv[card_argv]);
+ return 0;
+ }
+
+ /* parse and execute any command line commands */
+ if (argc >= 3) {
+ for (i = 2; i < argc; i++) {
+ if (parse_cmdline(argv[i], &command) == -1) {
+ printf("error: unknown command %s\n", argv[i]);
+ goto out;
+ } else {
+ switch(command) {
+ case OM_SWITCH_DEVICE:
+ case OM_SWITCH_MODIFIER:
+ if (++i >= argc) {
+ printf("error: %s missing argument\n", argv[i-1]);
+ goto out;
+ }
+ if (++i >= argc) {
+ printf("error: %s missing argument\n", argv[i-2]);
+ goto out;
+ }
+ err = handle_command(uc_mgr, command, argv[i -1]);
+ if (err < 0) {
+ printf(" error: command '%s' failed: %d\n",
+ argv[i - 2], err);
+ goto out;
+ }
+ case OM_SET_VERB:
+ case OM_ENABLE_DEVICE:
+ case OM_ENABLE_MODIFIER:
+ case OM_DISABLE_DEVICE:
+ case OM_DISABLE_MODIFIER:
+ if (++i >= argc) {
+ printf("error: %s missing argument\n", argv[i-1]);
+ goto out;
+ }
+ err = handle_command(uc_mgr, command, argv[i]);
+ if (err < 0) {
+ printf(" error: command '%s' failed: %d\n",
+ argv[i - 1], err);
+ goto out;
+ }
+ break;
+ default:
+ err = handle_command(uc_mgr, command, NULL);
+ if (err < 0) {
+ printf(" error: command '%s' failed: %d\n",
+ argv[i], err);
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ printf("Starting %s - 'q' to quit\n", argv[0]);
+ /* run the interactive command parser and handler */
+ while (!do_exit) {
+ printf("%s>> ", argv[0]);
+ fflush(stdin);
+ if (fgets(cmd, MAX_BUF, stdin) == NULL)
+ break;
+ cmd_status = parse_cmd(cmd, &command, &parameter);
+ if (cmd_status == -1) {
+ printf(" error: unknown command %s\n", cmd);
+ continue;
+ } else if (cmd_status == 1) {
+ err = handle_command(uc_mgr, command, parameter);
+ if (err < 0) {
+ printf(" error: command '%s' failed: %d\n",
+ cmd, err);
+ }
+ }
+ }
+
+out:
+ snd_use_case_mgr_close(uc_mgr);
+ return 0;
+}
diff --git a/configure.in b/configure.in
index 8bae007..a6d6d3d 100644
--- a/configure.in
+++ b/configure.in
@@ -270,6 +270,7 @@ AC_OUTPUT(Makefile alsactl/Makefile alsactl/init/Makefile \
m4/Makefile po/Makefile.in \
alsaconf/alsaconf alsaconf/Makefile \
alsaconf/po/Makefile \
+ alsaucm/Makefile \
aplay/Makefile include/Makefile iecset/Makefile utils/Makefile \
utils/alsa-utils.spec seq/Makefile seq/aconnect/Makefile \
seq/aplaymidi/Makefile seq/aseqdump/Makefile seq/aseqnet/Makefile \