summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2011-01-24 15:00:26 +0100
committerJaroslav Kysela <perex@perex.cz>2011-01-24 15:00:26 +0100
commit5f71d96a969e47722ee2413d8b36fc59ad01aeec (patch)
tree91f96aeecae7deeeab9b3903eda904075f8d9720
parent4429363aceb8c11fc69414ad85bce21e6dadb6c2 (diff)
parentce282e63c7cbc9093658afd8eacbb2b1cbd9e8dc (diff)
Merge branch 'ucm'
-rw-r--r--Makefile.am2
-rw-r--r--alsaucm/Makefile.am13
-rwxr-xr-xalsaucm/go.sh7
-rw-r--r--alsaucm/usecase.c435
-rw-r--r--configure.in1
5 files changed, 457 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 48a4780..21d69ab 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..4eba677
--- /dev/null
+++ b/alsaucm/Makefile.am
@@ -0,0 +1,13 @@
+bin_PROGRAMS = \
+ alsaucm
+
+alsaucm_SOURCES = usecase.c
+
+INCLUDES = \
+ -Wall -I$(top_srcdir)/include
+
+alsaucm_LDADD = -lasound
+
+# local build
+INCLUDES += -I$(top_srcdir)/../alsa-lib/include
+alsaucm_LDADD += -L$(top_srcdir)/../alsa-lib/src/.libs
diff --git a/alsaucm/go.sh b/alsaucm/go.sh
new file mode 100755
index 0000000..2aadd1c
--- /dev/null
+++ b/alsaucm/go.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+#GDB="gdb --args"
+
+ALSA_CONFIG_UCM="$HOME/alsa/alsa-lib/test/ucm" \
+LD_PRELOAD="$HOME/alsa/alsa-lib/src/.libs/libasound.so" \
+$GDB ./alsaucm "$@"
diff --git a/alsaucm/usecase.c b/alsaucm/usecase.c
new file mode 100644
index 0000000..bb894c6
--- /dev/null
+++ b/alsaucm/usecase.c
@@ -0,0 +1,435 @@
+/*
+ * 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.
+ * Copyright (C) 2010 Red Hat Inc.
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Stefan Schmidt <stefan@slimlogic.co.uk>
+ * Justin Xu <justinx@slimlogic.co.uk>
+ * Jaroslav Kysela <perex@perex.cz>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <getopt.h>
+#include <alsa/asoundlib.h>
+#include <alsa/use-case.h>
+#include "aconfig.h"
+#include "version.h"
+
+#define MAX_BUF 256
+
+struct context {
+ snd_use_case_mgr_t *uc_mgr;
+ const char *command;
+ char *card;
+ char **argv;
+ int argc;
+ unsigned int interactive:1;
+ unsigned int no_open:1;
+ unsigned int do_exit:1;
+};
+
+enum uc_cmd {
+ /* management */
+ OM_UNKNOWN = 0,
+ OM_OPEN,
+ OM_RESET,
+ OM_RELOAD,
+ OM_LISTCARDS,
+ OM_LIST,
+
+ /* set/get */
+ OM_SET,
+ OM_GET,
+ OM_GETI,
+
+ /* misc */
+ OM_HELP,
+ OM_QUIT,
+};
+
+struct cmd {
+ int code;
+ int args;
+ unsigned int opencard:1;
+ const char *id;
+};
+
+static struct cmd cmds[] = {
+ { OM_OPEN, 1, 0, "open" },
+ { OM_RESET, 0, 1, "reset" },
+ { OM_RELOAD, 0, 1, "reload" },
+ { OM_LISTCARDS, 0, 0, "listcards" },
+ { OM_LIST, 0, 1, "list" },
+ { OM_SET, 2, 1, "set" },
+ { OM_GET, 1, 1, "get" },
+ { OM_GETI, 1, 1, "geti" },
+ { OM_HELP, 0, 0, "help" },
+ { OM_QUIT, 0, 0, "quit" },
+ { OM_HELP, 0, 0, "h" },
+ { OM_QUIT, 0, 0, "q" },
+ { OM_UNKNOWN, 0, 0, NULL }
+};
+
+static void dump_help(struct context *context)
+{
+ if (context->command)
+ printf("Usage: %s <options> [command]\n", context->command);
+ printf(
+"\nAvailable options:\n"
+" -h,--help this help\n"
+" -c,--card NAME open card NAME\n"
+" -i,--interactive interactive mode\n"
+" -n,--no-open do not open first card found\n"
+"\nAvailable commands:\n"
+" open NAME open card NAME\n"
+" reset reset sound card to default state\n"
+" reload reload configuration\n"
+" listcards list available cards\n"
+" list IDENTIFIER list command\n"
+" get IDENTIFIER get string value\n"
+" geti IDENTIFIER get integer value\n"
+" set IDENTIFIER VALUE set string value\n"
+" h,help help\n"
+" q,quit quit\n"
+);
+}
+
+static int parse_line(struct context *context, char *line)
+{
+ char *start;
+ int c;
+
+ context->argc = 0;
+ while (*line) {
+ while (*line && (*line == ' ' || *line == '\t' ||
+ *line == '\n'))
+ line++;
+ c = *line;
+ if (c == '\"' || c == '\'') {
+ start = ++line;
+ while (*line && *line != c)
+ line++;
+ if (*line) {
+ *line = '\0';
+ line++;
+ }
+ } else {
+ start = line;
+ while (*line && *line != ' ' && *line != '\t' &&
+ *line != '\n')
+ line++;
+ if (*line) {
+ *line = '\0';
+ line++;
+ }
+ }
+ context->argv[context->argc++] = start;
+ }
+ return 0;
+}
+
+static int do_one(struct context *context, struct cmd *cmd, char **argv)
+{
+ const char **list, *str;
+ long lval;
+ int err, i;
+
+ if (cmd->opencard && context->uc_mgr == NULL) {
+ fprintf(stderr, "%s: command '%s' requires an open card\n",
+ context->command, cmd->id);
+ return 0;
+ }
+ switch (cmd->code) {
+ case OM_OPEN:
+ if (context->uc_mgr)
+ snd_use_case_mgr_close(context->uc_mgr);
+ context->uc_mgr = NULL;
+ free(context->card);
+ context->card = strdup(argv[0]);
+ err = snd_use_case_mgr_open(&context->uc_mgr, context->card);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to open sound card %s: %s\n",
+ context->command, context->card,
+ snd_strerror(err));
+ return err;
+ }
+ break;
+ case OM_RESET:
+ err = snd_use_case_mgr_reset(context->uc_mgr);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to reset sound card %s: %s\n",
+ context->command, context->card,
+ snd_strerror(err));
+ return err;
+ }
+ break;
+ case OM_RELOAD:
+ err = snd_use_case_mgr_reload(context->uc_mgr);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to reload manager %s: %s\n",
+ context->command, context->card,
+ snd_strerror(err));
+ return err;
+ }
+ break;
+ case OM_LISTCARDS:
+ err = snd_use_case_card_list(&list);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to get card list: %s\n",
+ context->command,
+ snd_strerror(err));
+ return err;
+ }
+ if (err == 0)
+ printf(" list is empty\n");
+ for (i = 0; i < err / 2; i++) {
+ printf(" %i: %s\n", i, list[i*2]);
+ if (list[i*2+1])
+ printf(" %s\n", list[i*2+1]);
+ }
+ snd_use_case_free_list(list, err);
+ break;
+ case OM_LIST:
+ err = snd_use_case_get_list(context->uc_mgr,
+ argv[0],
+ &list);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to get list %s: %s\n",
+ context->command, argv[0],
+ snd_strerror(err));
+ return err;
+ }
+ if (err == 0)
+ printf(" list is empty\n");
+ for (i = 0; i < err; i++)
+ printf(" %i: %s\n", i, list[i]);
+ snd_use_case_free_list(list, err);
+ break;
+ case OM_SET:
+ err = snd_use_case_set(context->uc_mgr, argv[0], argv[1]);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to set %s=%s: %s\n",
+ context->command, argv[0], argv[1],
+ snd_strerror(err));
+ return err;
+ }
+ break;
+ case OM_GET:
+ err = snd_use_case_get(context->uc_mgr, argv[0], &str);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to get %s: %s\n",
+ context->command, argv[0],
+ snd_strerror(err));
+ return err;
+ }
+ printf(" %s=%s\n", argv[0], str);
+ free((void *)str);
+ break;
+ case OM_GETI:
+ err = snd_use_case_geti(context->uc_mgr, argv[0], &lval);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to get integer %s: %s\n",
+ context->command, argv[0],
+ snd_strerror(err));
+ return lval;
+ }
+ printf(" %s=%li\n", argv[0], lval);
+ break;
+ case OM_QUIT:
+ context->do_exit = 1;
+ break;
+ case OM_HELP:
+ dump_help(context);
+ break;
+ default:
+ fprintf(stderr, "%s: unimplemented command '%s'\n",
+ context->command, cmd->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int do_commands(struct context *context)
+{
+ char *command, **argv;
+ struct cmd *cmd;
+ int i, acnt, err;
+
+ for (i = 0; i < context->argc && !context->do_exit; i++) {
+ command = context->argv[i];
+ for (cmd = cmds; cmd->id != NULL; cmd++) {
+ if (strcmp(cmd->id, command) == 0)
+ break;
+ }
+ if (cmd->id == NULL) {
+ fprintf(stderr, "%s: unknown command '%s'\n",
+ context->command, command);
+ return -EINVAL;
+ }
+ acnt = context->argc - (i + 1);
+ if (acnt < cmd->args) {
+ fprintf(stderr, "%s: expected %i arguments (got %i)\n",
+ context->command, cmd->args, acnt);
+ return -EINVAL;
+ }
+ argv = context->argv + i + 1;
+ err = do_one(context, cmd, argv);
+ if (err < 0)
+ return err;
+ i += cmd->args;
+ }
+ return 0;
+}
+
+static void my_exit(struct context *context, int exitcode)
+{
+ if (context->uc_mgr)
+ snd_use_case_mgr_close(context->uc_mgr);
+ free(context);
+ exit(exitcode);
+}
+
+enum {
+ OPT_VERSION = 1,
+};
+
+int main(int argc, char *argv[])
+{
+ static const char short_options[] = "hc:in";
+ static const struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"version", 0, 0, OPT_VERSION},
+ {"card", 1, 0, 'c'},
+ {"interactive", 0, 0, 'i'},
+ {"no-open", 0, 0, 'n'},
+ {0, 0, 0, 0}
+ };
+ struct context *context;
+ const char *command = argv[0];
+ const char **list;
+ int c, err, option_index;
+ char cmd[MAX_BUF];
+
+ context = calloc(1, sizeof(*context));
+ if (context == NULL)
+ return EXIT_FAILURE;
+ context->command = command;
+ while ((c = getopt_long(argc, argv, short_options,
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case 'h':
+ dump_help(context);
+ break;
+ case OPT_VERSION:
+ printf("%s: version " SND_UTIL_VERSION_STR "\n", command);
+ break;
+ case 'c':
+ if (context->card)
+ free(context->card);
+ context->card = strdup(optarg);
+ break;
+ case 'i':
+ context->interactive = 1;
+ break;
+ case 'n':
+ context->no_open = 1;
+ break;
+ default:
+ fprintf(stderr, "Try '%s --help' for more information.\n", command);
+ my_exit(context, EXIT_FAILURE);
+ }
+ }
+
+ if (!context->no_open && context->card == NULL) {
+ err = snd_use_case_card_list(&list);
+ if (err < 0) {
+ fprintf(stderr, "%s: unable to obtain card list: %s\n", command, snd_strerror(err));
+ my_exit(context, EXIT_FAILURE);
+ }
+ if (err == 0) {
+ printf("No card found\n");
+ my_exit(context, EXIT_SUCCESS);
+ }
+ context->card = strdup(list[0]);
+ snd_use_case_free_list(list, err);
+ }
+
+ /* open library */
+ if (!context->no_open) {
+ err = snd_use_case_mgr_open(&context->uc_mgr,
+ context->card);
+ if (err < 0) {
+ fprintf(stderr,
+ "%s: error failed to open sound card %s: %s\n",
+ command, context->card, snd_strerror(err));
+ my_exit(context, EXIT_FAILURE);
+ }
+ }
+
+ /* parse and execute any command line commands */
+ if (argc > optind) {
+ context->argv = argv + optind;
+ context->argc = argc - optind;
+ err = do_commands(context);
+ if (err < 0)
+ my_exit(context, EXIT_FAILURE);
+ }
+
+ if (!context->interactive)
+ my_exit(context, EXIT_SUCCESS);
+
+ printf("%s: Interacive mode - 'q' to quit\n", command);
+ /* run the interactive command parser and handler */
+ while (!context->do_exit) {
+ printf("%s>> ", argv[0]);
+ fflush(stdin);
+ if (fgets(cmd, MAX_BUF, stdin) == NULL)
+ break;
+ err = parse_line(context, cmd);
+ if (err < 0) {
+ fprintf(stderr, "%s: unable to parse line\n",
+ command);
+ my_exit(context, EXIT_FAILURE);
+ }
+ err = do_commands(context);
+ if (err < 0)
+ my_exit(context, EXIT_FAILURE);
+ }
+
+ my_exit(context, EXIT_SUCCESS);
+ return EXIT_SUCCESS;
+}
diff --git a/configure.in b/configure.in
index 561ca46..f784363 100644
--- a/configure.in
+++ b/configure.in
@@ -304,6 +304,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 \