OSDN Git Service

Remove libaudio from LOCAL_SHARED_LIBRARIES.
[android-x86/external-alsa-utils.git] / alsaucm / usecase.c
1 /*
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.
6  *
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.
11  *
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.
15  *
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.
22  * 
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>
31  */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <signal.h>
38 #include <getopt.h>
39 #include <alsa/asoundlib.h>
40 #include <alsa/use-case.h>
41 #include "aconfig.h"
42 #include "version.h"
43
44 #define MAX_BUF 256
45
46 struct context {
47         snd_use_case_mgr_t *uc_mgr;
48         const char *command;
49         char *card;
50         char **argv;
51         int argc;
52         int arga;
53         char *batch;
54         unsigned int interactive:1;
55         unsigned int no_open:1;
56         unsigned int do_exit:1;
57 };
58
59 enum uc_cmd {
60         /* management */
61         OM_UNKNOWN = 0,
62         OM_OPEN,
63         OM_RESET,
64         OM_RELOAD,
65         OM_LISTCARDS,
66         OM_LIST,
67
68         /* set/get */
69         OM_SET,
70         OM_GET,
71         OM_GETI,
72
73         /* misc */
74         OM_HELP,
75         OM_QUIT,
76 };
77
78 struct cmd {
79         int code;
80         int args;
81         unsigned int opencard:1;
82         const char *id;
83 };
84
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 }
100 };
101
102 static void dump_help(struct context *context)
103 {
104         if (context->command)
105                 printf("Usage: %s <options> [command]\n", context->command);
106         printf(
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"
122 "  h,help                     help\n"
123 "  q,quit                     quit\n"
124 );
125 }
126
127 static int parse_line(struct context *context, char *line)
128 {
129         char *start, **nargv;
130         int c;
131
132         context->argc = 0;
133         while (*line) {
134                 while (*line && (*line == ' ' || *line == '\t' ||
135                                                         *line == '\n'))
136                         line++;
137                 c = *line;
138                 if (c == '\"' || c == '\'') {
139                         start = ++line;
140                         while (*line && *line != c)
141                                 line++;
142                         if (*line) {
143                                 *line = '\0';
144                                 line++;
145                         }
146                 } else {
147                         start = line;
148                         while (*line && *line != ' ' && *line != '\t' &&
149                                *line != '\n')
150                                 line++;
151                         if (*line) {
152                                 *line = '\0';
153                                 line++;
154                         }
155                 }
156                 if (start[0] == '\0' && context->argc == 0)
157                         return 0;
158                 if (context->argc + 1 >= context->arga) {
159                         context->arga += 4;
160                         nargv = realloc(context->argv,
161                                         context->arga * sizeof(char *));
162                         if (nargv == NULL)
163                                 return -ENOMEM;
164                         context->argv = nargv;
165                 }
166                 context->argv[context->argc++] = start;
167         }
168         return 0;
169 }
170
171 static int do_one(struct context *context, struct cmd *cmd, char **argv)
172 {
173         const char **list, *str;
174         long lval;
175         int err, i;
176
177         if (cmd->opencard && context->uc_mgr == NULL) {
178                 fprintf(stderr, "%s: command '%s' requires an open card\n",
179                                 context->command, cmd->id);
180                 return 0;
181         }
182         switch (cmd->code) {
183         case OM_OPEN:
184                 if (context->uc_mgr)
185                         snd_use_case_mgr_close(context->uc_mgr);
186                 context->uc_mgr = NULL;
187                 free(context->card);
188                 context->card = strdup(argv[0]);
189                 err = snd_use_case_mgr_open(&context->uc_mgr, context->card);
190                 if (err < 0) {
191                         fprintf(stderr,
192                                 "%s: error failed to open sound card %s: %s\n",
193                                 context->command, context->card,
194                                 snd_strerror(err));
195                         return err;
196                 }
197                 break;
198         case OM_RESET:
199                 err = snd_use_case_mgr_reset(context->uc_mgr);
200                 if (err < 0) {
201                         fprintf(stderr,
202                                 "%s: error failed to reset sound card %s: %s\n",
203                                 context->command, context->card,
204                                 snd_strerror(err));
205                         return err;
206                 }
207                 break;
208         case OM_RELOAD:
209                 err = snd_use_case_mgr_reload(context->uc_mgr);
210                 if (err < 0) {
211                         fprintf(stderr,
212                                 "%s: error failed to reload manager %s: %s\n",
213                                 context->command, context->card,
214                                 snd_strerror(err));
215                         return err;
216                 }
217                 break;
218         case OM_LISTCARDS:
219                 err = snd_use_case_card_list(&list);
220                 if (err < 0) {
221                         fprintf(stderr,
222                                 "%s: error failed to get card list: %s\n",
223                                 context->command,
224                                 snd_strerror(err));
225                         return err;
226                 }
227                 if (err == 0)
228                         printf("  list is empty\n");
229                 for (i = 0; i < err / 2; i++) {
230                         printf("  %i: %s\n", i, list[i*2]);
231                         if (list[i*2+1])
232                                 printf("    %s\n", list[i*2+1]);
233                 }
234                 snd_use_case_free_list(list, err);
235                 break;
236         case OM_LIST:
237                 err = snd_use_case_get_list(context->uc_mgr,
238                                             argv[0],
239                                             &list);
240                 if (err < 0) {
241                         fprintf(stderr,
242                                 "%s: error failed to get list %s: %s\n",
243                                 context->command, argv[0],
244                                 snd_strerror(err));
245                         return err;
246                 }
247                 if (err == 0)
248                         printf("  list is empty\n");
249                 for (i = 0; i < err / 2; i++) {
250                         printf("  %i: %s\n", i, list[i*2]);
251                         if (list[i*2+1])
252                                 printf("    %s\n", list[i*2+1]);
253                 }
254                 snd_use_case_free_list(list, err);
255                 break;
256         case OM_SET:
257                 err = snd_use_case_set(context->uc_mgr, argv[0], argv[1]);
258                 if (err < 0) {
259                         fprintf(stderr,
260                                 "%s: error failed to set %s=%s: %s\n",
261                                 context->command, argv[0], argv[1],
262                                 snd_strerror(err));
263                         return err;
264                 }
265                 break;
266         case OM_GET:
267                 err = snd_use_case_get(context->uc_mgr, argv[0], &str);
268                 if (err < 0) {
269                         fprintf(stderr,
270                                 "%s: error failed to get %s: %s\n",
271                                 context->command, argv[0],
272                                 snd_strerror(err));
273                         return err;
274                 }
275                 printf("  %s=%s\n", argv[0], str);
276                 free((void *)str);
277                 break;
278         case OM_GETI:
279                 err = snd_use_case_geti(context->uc_mgr, argv[0], &lval);
280                 if (err < 0) {
281                         fprintf(stderr,
282                                 "%s: error failed to get integer %s: %s\n",
283                                 context->command, argv[0],
284                                 snd_strerror(err));
285                         return lval;
286                 }
287                 printf("  %s=%li\n", argv[0], lval);
288                 break;
289         case OM_QUIT:
290                 context->do_exit = 1;
291                 break;
292         case OM_HELP:
293                 dump_help(context);
294                 break;
295         default:
296                 fprintf(stderr, "%s: unimplemented command '%s'\n",
297                                 context->command, cmd->id);
298                 return -EINVAL;
299         }
300         return 0;
301 }
302
303 static int do_commands(struct context *context)
304 {
305         char *command, **argv;
306         struct cmd *cmd;
307         int i, acnt, err;
308
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)
313                                 break;
314                 }
315                 if (cmd->id == NULL) {
316                         fprintf(stderr, "%s: unknown command '%s'\n",
317                                                 context->command, command);
318                         return -EINVAL;
319                 }
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);
324                         return -EINVAL;
325                 }
326                 argv = context->argv + i + 1;
327                 err = do_one(context, cmd, argv);
328                 if (err < 0)
329                         return err;
330                 i += cmd->args;
331         }
332         return 0;
333 }
334
335 static void my_exit(struct context *context, int exitcode)
336 {
337         if (context->uc_mgr)
338                 snd_use_case_mgr_close(context->uc_mgr);
339         if (context->arga > 0)
340                 free(context->argv);
341         if (context->card)
342                 free(context->card);
343         if (context->batch)
344                 free(context->batch);
345         free(context);
346         exit(exitcode);
347 }
348
349 enum {
350         OPT_VERSION = 1,
351 };
352
353 int main(int argc, char *argv[])
354 {
355         static const char short_options[] = "hb:c:in";
356         static const struct option long_options[] = {
357                 {"help", 0, 0, 'h'},
358                 {"version", 0, 0, OPT_VERSION},
359                 {"card", 1, 0, 'c'},
360                 {"interactive", 0, 0, 'i'},
361                 {"batch", 1, 0, 'b'},
362                 {"no-open", 0, 0, 'n'},
363                 {0, 0, 0, 0}
364         };
365         struct context *context;
366         const char *command = argv[0];
367         const char **list;
368         int c, err, option_index;
369         char cmd[MAX_BUF];
370         FILE *in;
371
372         context = calloc(1, sizeof(*context));
373         if (context == NULL)
374                 return EXIT_FAILURE;
375         context->command = command;
376         while ((c = getopt_long(argc, argv, short_options,
377                                  long_options, &option_index)) != -1) {
378                 switch (c) {
379                 case 'h':
380                         dump_help(context);
381                         break;
382                 case OPT_VERSION:
383                         printf("%s: version " SND_UTIL_VERSION_STR "\n", command);
384                         break;
385                 case 'c':
386                         if (context->card)
387                                 free(context->card);
388                         context->card = strdup(optarg);
389                         break;
390                 case 'i':
391                         context->interactive = 1;
392                         context->batch = NULL;
393                         break;
394                 case 'b':
395                         context->batch = strdup(optarg);
396                         context->interactive = 0;
397                         break;
398                 case 'n':
399                         context->no_open = 1;
400                         break;
401                 default:
402                         fprintf(stderr, "Try '%s --help' for more information.\n", command);
403                         my_exit(context, EXIT_FAILURE);
404                 }
405         }
406
407         if (!context->no_open && context->card == NULL) {
408                 err = snd_use_case_card_list(&list);
409                 if (err < 0) {
410                         fprintf(stderr, "%s: unable to obtain card list: %s\n", command, snd_strerror(err));
411                         my_exit(context, EXIT_FAILURE);
412                 }
413                 if (err == 0) {
414                         printf("No card found\n");
415                         my_exit(context, EXIT_SUCCESS);
416                 }
417                 context->card = strdup(list[0]);
418                 snd_use_case_free_list(list, err);
419         }
420
421         /* open library */
422         if (!context->no_open) {
423                 err = snd_use_case_mgr_open(&context->uc_mgr,
424                                             context->card);
425                 if (err < 0) {
426                         fprintf(stderr,
427                                 "%s: error failed to open sound card %s: %s\n",
428                                 command, context->card, snd_strerror(err));
429                         my_exit(context, EXIT_FAILURE);
430                 }
431         }
432
433         /* parse and execute any command line commands */
434         if (argc > optind) {
435                 context->argv = argv + optind;
436                 context->argc = argc - optind;
437                 err = do_commands(context);
438                 if (err < 0)
439                         my_exit(context, EXIT_FAILURE);
440         }
441
442         if (!context->interactive && !context->batch)
443                 my_exit(context, EXIT_SUCCESS);
444
445         if (context->interactive) {
446                 printf("%s: Interacive mode - 'q' to quit\n", command);
447                 in = stdin;
448         } else {
449                 if (strcmp(context->batch, "-") == 0) {
450                         in = stdin;
451                 } else {
452                         in = fopen(context->batch, "r");
453                         if (in == NULL) {
454                                 fprintf(stderr, "%s: error failed to open file '%s': %s\n",
455                                         command, context->batch, strerror(-errno));
456                                 my_exit(context, EXIT_FAILURE);
457                         }
458                 }
459         }
460
461         /* run the interactive command parser and handler */
462         while (!context->do_exit && !feof(in)) {
463                 if (context->interactive)
464                         printf("%s>> ", argv[0]);
465                 fflush(stdin);
466                 if (fgets(cmd, MAX_BUF, in) == NULL)
467                         break;
468                 err = parse_line(context, cmd);
469                 if (err < 0) {
470                         fprintf(stderr, "%s: unable to parse line\n",
471                                 command);
472                         my_exit(context, EXIT_FAILURE);
473                 }
474                 err = do_commands(context);
475                 if (err < 0) {
476                         if (context->interactive)
477                                 printf("^^^ error, try again\n");
478                         else
479                                 my_exit(context, EXIT_FAILURE);
480                 }
481         }
482         
483         if (in != stdin)
484                 fclose(in);
485
486         my_exit(context, EXIT_SUCCESS);
487         return EXIT_SUCCESS;
488 }