2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * Support for the verb/device/modifier core logic and API,
17 * command line tool and file parser was kindly sponsored by
18 * Texas Instruments Inc.
19 * Support for multiple active modifiers and devices,
20 * transition sequences, multiple client access and user defined use
21 * cases was kindly sponsored by Wolfson Microelectronics PLC.
23 * Copyright (C) 2008-2010 SlimLogic Ltd
24 * Copyright (C) 2010 Wolfson Microelectronics PLC
25 * Copyright (C) 2010 Texas Instruments Inc.
26 * Copyright (C) 2010 Red Hat Inc.
27 * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
28 * Stefan Schmidt <stefan@slimlogic.co.uk>
29 * Justin Xu <justinx@slimlogic.co.uk>
30 * Jaroslav Kysela <perex@perex.cz>
39 #include <alsa/asoundlib.h>
40 #include <alsa/use-case.h>
47 snd_use_case_mgr_t *uc_mgr;
54 unsigned int interactive:1;
55 unsigned int no_open:1;
56 unsigned int do_exit:1;
81 unsigned int opencard:1;
85 static struct cmd cmds[] = {
86 { OM_OPEN, 1, 0, "open" },
87 { OM_RESET, 0, 1, "reset" },
88 { OM_RELOAD, 0, 1, "reload" },
89 { OM_LISTCARDS, 0, 0, "listcards" },
90 { OM_LIST, 1, 1, "list" },
91 { OM_SET, 2, 1, "set" },
92 { OM_GET, 1, 1, "get" },
93 { OM_GETI, 1, 1, "geti" },
94 { OM_HELP, 0, 0, "help" },
95 { OM_QUIT, 0, 0, "quit" },
96 { OM_HELP, 0, 0, "h" },
97 { OM_HELP, 0, 0, "?" },
98 { OM_QUIT, 0, 0, "q" },
99 { OM_UNKNOWN, 0, 0, NULL }
102 static void dump_help(struct context *context)
104 if (context->command)
105 printf("Usage: %s <options> [command]\n", context->command);
107 "\nAvailable options:\n"
108 " -h,--help this help\n"
109 " -c,--card NAME open card NAME\n"
110 " -i,--interactive interactive mode\n"
111 " -b,--batch FILE batch mode (use '-' for the stdin input)\n"
112 " -n,--no-open do not open first card found\n"
113 "\nAvailable commands:\n"
114 " open NAME open card NAME\n"
115 " reset reset sound card to default state\n"
116 " reload reload configuration\n"
117 " listcards list available cards\n"
118 " list IDENTIFIER list command\n"
119 " get IDENTIFIER get string value\n"
120 " geti IDENTIFIER get integer value\n"
121 " set IDENTIFIER VALUE set string value\n"
127 static int parse_line(struct context *context, char *line)
129 char *start, **nargv;
134 while (*line && (*line == ' ' || *line == '\t' ||
138 if (c == '\"' || c == '\'') {
140 while (*line && *line != c)
148 while (*line && *line != ' ' && *line != '\t' &&
156 if (start[0] == '\0' && context->argc == 0)
158 if (context->argc + 1 >= context->arga) {
160 nargv = realloc(context->argv,
161 context->arga * sizeof(char *));
164 context->argv = nargv;
166 context->argv[context->argc++] = start;
171 static int do_one(struct context *context, struct cmd *cmd, char **argv)
173 const char **list, *str;
177 if (cmd->opencard && context->uc_mgr == NULL) {
178 fprintf(stderr, "%s: command '%s' requires an open card\n",
179 context->command, cmd->id);
185 snd_use_case_mgr_close(context->uc_mgr);
186 context->uc_mgr = NULL;
188 context->card = strdup(argv[0]);
189 err = snd_use_case_mgr_open(&context->uc_mgr, context->card);
192 "%s: error failed to open sound card %s: %s\n",
193 context->command, context->card,
199 err = snd_use_case_mgr_reset(context->uc_mgr);
202 "%s: error failed to reset sound card %s: %s\n",
203 context->command, context->card,
209 err = snd_use_case_mgr_reload(context->uc_mgr);
212 "%s: error failed to reload manager %s: %s\n",
213 context->command, context->card,
219 err = snd_use_case_card_list(&list);
222 "%s: error failed to get card list: %s\n",
228 printf(" list is empty\n");
229 for (i = 0; i < err / 2; i++) {
230 printf(" %i: %s\n", i, list[i*2]);
232 printf(" %s\n", list[i*2+1]);
234 snd_use_case_free_list(list, err);
237 err = snd_use_case_get_list(context->uc_mgr,
242 "%s: error failed to get list %s: %s\n",
243 context->command, argv[0],
248 printf(" list is empty\n");
249 for (i = 0; i < err / 2; i++) {
250 printf(" %i: %s\n", i, list[i*2]);
252 printf(" %s\n", list[i*2+1]);
254 snd_use_case_free_list(list, err);
257 err = snd_use_case_set(context->uc_mgr, argv[0], argv[1]);
260 "%s: error failed to set %s=%s: %s\n",
261 context->command, argv[0], argv[1],
267 err = snd_use_case_get(context->uc_mgr, argv[0], &str);
270 "%s: error failed to get %s: %s\n",
271 context->command, argv[0],
275 printf(" %s=%s\n", argv[0], str);
279 err = snd_use_case_geti(context->uc_mgr, argv[0], &lval);
282 "%s: error failed to get integer %s: %s\n",
283 context->command, argv[0],
287 printf(" %s=%li\n", argv[0], lval);
290 context->do_exit = 1;
296 fprintf(stderr, "%s: unimplemented command '%s'\n",
297 context->command, cmd->id);
303 static int do_commands(struct context *context)
305 char *command, **argv;
309 for (i = 0; i < context->argc && !context->do_exit; i++) {
310 command = context->argv[i];
311 for (cmd = cmds; cmd->id != NULL; cmd++) {
312 if (strcmp(cmd->id, command) == 0)
315 if (cmd->id == NULL) {
316 fprintf(stderr, "%s: unknown command '%s'\n",
317 context->command, command);
320 acnt = context->argc - (i + 1);
321 if (acnt < cmd->args) {
322 fprintf(stderr, "%s: expected %i arguments (got %i)\n",
323 context->command, cmd->args, acnt);
326 argv = context->argv + i + 1;
327 err = do_one(context, cmd, argv);
335 static void my_exit(struct context *context, int exitcode)
338 snd_use_case_mgr_close(context->uc_mgr);
339 if (context->arga > 0)
344 free(context->batch);
353 int main(int argc, char *argv[])
355 static const char short_options[] = "hb:c:in";
356 static const struct option long_options[] = {
358 {"version", 0, 0, OPT_VERSION},
360 {"interactive", 0, 0, 'i'},
361 {"batch", 1, 0, 'b'},
362 {"no-open", 0, 0, 'n'},
365 struct context *context;
366 const char *command = argv[0];
368 int c, err, option_index;
372 context = calloc(1, sizeof(*context));
375 context->command = command;
376 while ((c = getopt_long(argc, argv, short_options,
377 long_options, &option_index)) != -1) {
383 printf("%s: version " SND_UTIL_VERSION_STR "\n", command);
388 context->card = strdup(optarg);
391 context->interactive = 1;
392 context->batch = NULL;
395 context->batch = strdup(optarg);
396 context->interactive = 0;
399 context->no_open = 1;
402 fprintf(stderr, "Try '%s --help' for more information.\n", command);
403 my_exit(context, EXIT_FAILURE);
407 if (!context->no_open && context->card == NULL) {
408 err = snd_use_case_card_list(&list);
410 fprintf(stderr, "%s: unable to obtain card list: %s\n", command, snd_strerror(err));
411 my_exit(context, EXIT_FAILURE);
414 printf("No card found\n");
415 my_exit(context, EXIT_SUCCESS);
417 context->card = strdup(list[0]);
418 snd_use_case_free_list(list, err);
422 if (!context->no_open) {
423 err = snd_use_case_mgr_open(&context->uc_mgr,
427 "%s: error failed to open sound card %s: %s\n",
428 command, context->card, snd_strerror(err));
429 my_exit(context, EXIT_FAILURE);
433 /* parse and execute any command line commands */
435 context->argv = argv + optind;
436 context->argc = argc - optind;
437 err = do_commands(context);
439 my_exit(context, EXIT_FAILURE);
442 if (!context->interactive && !context->batch)
443 my_exit(context, EXIT_SUCCESS);
445 if (context->interactive) {
446 printf("%s: Interacive mode - 'q' to quit\n", command);
449 if (strcmp(context->batch, "-") == 0) {
452 in = fopen(context->batch, "r");
454 fprintf(stderr, "%s: error failed to open file '%s': %s\n",
455 command, context->batch, strerror(-errno));
456 my_exit(context, EXIT_FAILURE);
461 /* run the interactive command parser and handler */
462 while (!context->do_exit && !feof(in)) {
463 if (context->interactive)
464 printf("%s>> ", argv[0]);
466 if (fgets(cmd, MAX_BUF, in) == NULL)
468 err = parse_line(context, cmd);
470 fprintf(stderr, "%s: unable to parse line\n",
472 my_exit(context, EXIT_FAILURE);
474 err = do_commands(context);
476 if (context->interactive)
477 printf("^^^ error, try again\n");
479 my_exit(context, EXIT_FAILURE);
486 my_exit(context, EXIT_SUCCESS);