mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-12-22 14:26:31 +01:00
Merge branch 'ucm'
This commit is contained in:
commit
5f71d96a96
5 changed files with 457 additions and 1 deletions
|
@ -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
|
||||
|
|
13
alsaucm/Makefile.am
Normal file
13
alsaucm/Makefile.am
Normal file
|
@ -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
|
7
alsaucm/go.sh
Executable file
7
alsaucm/go.sh
Executable file
|
@ -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 "$@"
|
435
alsaucm/usecase.c
Normal file
435
alsaucm/usecase.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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 \
|
||||
|
|
Loading…
Reference in a new issue