1/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *   * Redistributions of source code must retain the above copyright
8 *     notice, this list of conditions and the following disclaimer.
9 *   * Redistributions in binary form must reproduce the above
10 *     copyright notice, this list of conditions and the following
11 *     disclaimer in the documentation and/or other materials provided
12 *     with the distribution.
13 *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 *     contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/ioctl.h>
31#include <sys/stat.h>
32#include <linux/ioctl.h>
33#include <fcntl.h>
34#include <string.h>
35#include <stdio.h>
36#include <errno.h>
37#include <stdlib.h>
38
39#include "alsa_ucm.h"
40#include "msm8960_use_cases.h"
41
42/* Function prototypes */
43static void print_help_menu(void);
44static void alsaucm_test_cmd_svr(void);
45static int process_cmd(char *cmdStr);
46
47/* Global data */
48snd_use_case_mgr_t *uc_mgr;
49
50/* Defines */
51enum ucm_cmd_id {
52    UCM_OPEN = 0,
53    UCM_SET,
54    UCM_LISTCARDS,
55    UCM_LIST,
56    UCM_GET,
57    UCM_GETI,
58    UCM_RESET,
59    UCM_RELOAD,
60    UCM_HELP,
61    UCM_QUIT,
62    UCM_UNKNOWN
63};
64
65struct cmd {
66    enum ucm_cmd_id code;
67    const char *cmd_str;
68};
69
70static struct cmd cmds[] = {
71    { UCM_OPEN, "open" },
72    { UCM_SET,  "set" },
73    { UCM_LISTCARDS,  "listcards" },
74    { UCM_LIST,  "list" },
75    { UCM_GET,  "get" },
76    { UCM_GETI,  "geti" },
77    { UCM_RESET,  "reset" },
78    { UCM_RELOAD,  "reload" },
79    { UCM_HELP,  "help" },
80    { UCM_QUIT,  "quit" },
81    { UCM_UNKNOWN, NULL }
82};
83
84static void alsaucm_test_cmd_svr(void)
85{
86    int fd;
87    ssize_t read_count;
88    char cmdstr[256] = {'\0'};
89    char ch;
90    char *exit_str = "quit";
91
92    if (mknod("/data/alsaucm_test", S_IFIFO | 0666, 0) == 0) {
93        fd = open("/data/alsaucm_test", O_RDONLY);
94        while (1) {
95            read_count = read(fd, &ch, 1);
96            if (read_count == 0) {
97                sleep(2);
98                continue;
99            } else if (read_count < 0) {
100                fprintf(stderr, "alsaucm_test: error reading cmd\n");
101                break;
102            }
103
104            if (ch != '\n') {
105                strlcat(cmdstr, &ch , (2+strlen(cmdstr)));
106                continue;
107            } else {
108                if (!strncmp(cmdstr, exit_str, strlen(cmdstr))) {
109                    /* free UCM instace */
110                    if (uc_mgr) {
111                        snd_use_case_mgr_close(uc_mgr);
112                        uc_mgr = NULL;
113                    }
114                    break;
115                } else {
116                    process_cmd(cmdstr);
117                    memset(cmdstr, 0, sizeof(cmdstr));
118                }
119            }
120        }
121        printf("alsaucm_test: exit server mode\n");
122        close(fd);
123        remove("/data/alsaucm_test");
124    } else {
125        fprintf(stderr, "alsaucm_test: Failed to create server\n");
126    }
127}
128
129
130static void print_help_menu(void)
131{
132    printf("\nAvailable commands:\n"
133           "  open NAME                  open card NAME\n"
134           "  reset                      reset sound card to default state\n"
135           "  reload                     reload configuration\n"
136           "  listcards                  list available cards\n"
137           "  list IDENTIFIER            list command\n"
138           "  get IDENTIFIER             get string value\n"
139           "  geti IDENTIFIER            get integer value\n"
140           "  set IDENTIFIER VALUE       set string value\n"
141           "  help                     help\n"
142           "  quit                     quit\n");
143}
144
145int main(int argc, char **argv)
146{
147    char *help_str = "help";
148    argc--;
149    argv++;
150
151    if (argc > 0) {
152        if (!strncmp(argv[0], help_str, strlen(argv[0])))
153            print_help_menu();
154    } else
155	    alsaucm_test_cmd_svr();
156    return 0;
157}
158
159static int process_cmd(char *cmdStr)
160{
161    const char **list = NULL , *str = NULL;
162    long lval;
163    int err, i;
164    char *command = NULL;
165    int count = 0;
166    char *identifier = NULL, *value = NULL;
167    struct cmd *cmd = NULL;
168
169    command = strtok_r(cmdStr, " ", &value);
170    identifier = strtok_r(NULL, " ", &value);
171
172    if (command == NULL) {
173        fprintf(stderr, "NULL pointer encountered. Invalid value for command");
174        return -1;
175    }
176
177    for (cmd = cmds; cmd->cmd_str != NULL; cmd++) {
178        if (strncmp(cmd->cmd_str, command, strlen(cmd->cmd_str)) == 0)
179            break;
180    }
181
182    if (cmd->cmd_str == NULL) {
183        fprintf(stderr, "Unknown command '%s'\n", command);
184        return -EINVAL;
185    }
186
187    if ((identifier == NULL) && ((cmd->code != UCM_HELP) &&
188        (cmd->code != UCM_LISTCARDS) && (cmd->code != UCM_RESET) &&
189        (cmd->code != UCM_RELOAD)))
190    {
191        fprintf(stderr, "NULL pointer encountered. Invalid value for identifier");
192        return -1;
193    }
194
195    switch (cmd->code) {
196    case UCM_HELP:
197        print_help_menu();
198        break;
199
200    case UCM_OPEN:
201        if (uc_mgr) {
202            snd_use_case_mgr_close(uc_mgr);
203            uc_mgr = NULL;
204        }
205
206        err = snd_use_case_mgr_open(&uc_mgr, identifier);
207        if (err < 0) {
208            fprintf(stderr, "%s: error failed to open sound card %s: %d\n", cmd->cmd_str, identifier, err);
209            return err;
210        }
211        snd_use_case_mgr_wait_for_parsing(uc_mgr);
212        break;
213
214    case UCM_LISTCARDS:
215        err = snd_use_case_card_list(&list);
216        if (err < 0) {
217            fprintf(stderr, "%s: error failed to get card list: %d\n", cmd->cmd_str, err);
218            return err;
219        }
220        if (err == 0) {
221            printf("list is empty\n");
222            return 0;
223        }
224
225        for (i = 0; i < err; i++)
226            printf("  %i: %s\n", i+1, list[i]);
227        snd_use_case_free_list(list, err);
228        break;
229
230    case UCM_RESET:
231        if (!uc_mgr) {
232            fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
233            return -EINVAL;
234        }
235
236        err = snd_use_case_mgr_reset(uc_mgr);
237        if (err < 0) {
238            fprintf(stderr, "%s: error failed to reset sound card %d\n", cmd->cmd_str, err);
239            return err;
240        }
241        break;
242
243    case UCM_RELOAD:
244        if (!uc_mgr) {
245            fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
246            return -EINVAL;
247        }
248
249        err = snd_use_case_mgr_reload(uc_mgr);
250        if (err < 0) {
251            fprintf(stderr, "%s: error failed to reload manager %d\n", cmd->cmd_str, err);
252            return err;
253        }
254        break;
255
256    case UCM_LIST:
257        if (!uc_mgr) {
258            fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
259            return -EINVAL;
260        }
261
262        err = snd_use_case_get_list(uc_mgr, identifier, &list);
263        if (err < 0) {
264            fprintf(stderr, "%s: error failed to get list %s: %d\n", cmd->cmd_str, identifier, err);
265            return err;
266        }
267        if (err == 0) {
268           printf("list is empty\n");
269           return 0;
270        }
271        for (i = 0; i < err; i++) {
272            printf("  %i: %s\n", i+1, list[i]);
273        }
274        snd_use_case_free_list(list, err);
275        break;
276
277    case UCM_SET:
278        if (!uc_mgr) {
279            fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
280            return -EINVAL;
281        }
282
283        err = snd_use_case_set(uc_mgr, identifier, value);
284        if (err < 0) {
285            fprintf(stderr, "%s: error failed to set %s=%s: %d\n", cmd->cmd_str, identifier, value, err);
286            return err;
287        }
288        break;
289
290    case UCM_GET:
291        if (!uc_mgr) {
292            fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
293            return -EINVAL;
294        }
295
296        err = snd_use_case_get(uc_mgr, identifier, &str);
297        if (err < 0) {
298            fprintf(stderr, "%s: error failed to get %s: %d\n", cmd->cmd_str, identifier, err);
299            return err;
300        }
301        printf("  %s=%s\n", identifier, str);
302        free((void *)str);
303        break;
304
305    case UCM_GETI:
306        if (!uc_mgr) {
307           fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
308           return -EINVAL;
309        }
310
311        err = snd_use_case_geti(uc_mgr, identifier, &lval);
312        if (err < 0) {
313            fprintf(stderr, "%s: error failed to get integer %s: %d\n", cmd->cmd_str, identifier, err);
314            return lval;
315        }
316        printf("  %s=%li\n", identifier, lval);
317        break;
318
319    default:
320        break;
321    }
322    return 0;
323}
324
325