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 + * Stefan Schmidt + * Justin Xu + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 " + " %s [use case] [ [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 - apply use case verb \n" + " setd - enable use case device \n" + " setm - enable use case modifier \n" + " switchd - disable device enable device\n" + " switchm - disable modifier enable modifier\n" + " cleard - disable use case device \n" + " clearm - disable use case modifier \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, ¶meter); + 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 \