396 lines
11 KiB
C
396 lines
11 KiB
C
/*
|
|
* Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
* * Neither the name of The Linux Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <linux/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef ANDROID
|
|
#include <stdint.h>
|
|
#define strlcat g_strlcat
|
|
#endif
|
|
|
|
#include "alsa_ucm.h"
|
|
#include "msm8960_use_cases.h"
|
|
#if defined(QC_PROP)
|
|
#include "acdb-loader.h"
|
|
#else
|
|
#define acdb_loader_init_ACDB() 0
|
|
#define acdb_loader_deallocate_ACDB() 0
|
|
#endif
|
|
/* Function prototypes */
|
|
static void print_help_menu(void);
|
|
static void alsaucm_test_cmd_svr(void);
|
|
static int process_cmd(char *cmdStr);
|
|
|
|
/* Global data */
|
|
snd_use_case_mgr_t *uc_mgr;
|
|
|
|
/* Defines */
|
|
enum ucm_cmd_id {
|
|
UCM_OPEN = 0,
|
|
UCM_SET,
|
|
UCM_LISTCARDS,
|
|
UCM_LIST,
|
|
UCM_GET,
|
|
UCM_GETI,
|
|
UCM_RESET,
|
|
UCM_RELOAD,
|
|
UCM_HELP,
|
|
UCM_QUIT,
|
|
UCM_UNKNOWN
|
|
};
|
|
|
|
struct cmd {
|
|
enum ucm_cmd_id code;
|
|
const char *cmd_str;
|
|
};
|
|
|
|
static struct cmd cmds[] = {
|
|
{ UCM_OPEN, "open" },
|
|
{ UCM_SET, "set" },
|
|
{ UCM_LISTCARDS, "listcards" },
|
|
{ UCM_LIST, "list" },
|
|
{ UCM_GET, "get" },
|
|
{ UCM_GETI, "geti" },
|
|
{ UCM_RESET, "reset" },
|
|
{ UCM_RELOAD, "reload" },
|
|
{ UCM_HELP, "help" },
|
|
{ UCM_QUIT, "quit" },
|
|
{ UCM_UNKNOWN, NULL }
|
|
};
|
|
|
|
#define CVD_VERSION_MIXER_CTL "CVD Version"
|
|
#define MAX_CVD_VERSION_STRING_SIZE 100
|
|
|
|
static void get_cvd_version(char *cvd_version)
|
|
{
|
|
int ret = 0;
|
|
int count;
|
|
struct mixer_ctl *ctl;
|
|
struct mixer *mixer;
|
|
const char* device = "/dev/snd/controlC0";
|
|
|
|
mixer = mixer_open(device);
|
|
if (!mixer) {
|
|
fprintf(stderr, "fail to open mixer\n");
|
|
|
|
return;
|
|
}
|
|
|
|
ctl = mixer_get_ctl_by_name(mixer, CVD_VERSION_MIXER_CTL);
|
|
if (!ctl) {
|
|
fprintf(stderr, "fail to get mixer ctl\n");
|
|
|
|
goto done;
|
|
}
|
|
mixer_ctl_update(ctl);
|
|
|
|
count = mixer_ctl_get_num_values(ctl);
|
|
|
|
if (count > MAX_CVD_VERSION_STRING_SIZE)
|
|
count = MAX_CVD_VERSION_STRING_SIZE;
|
|
|
|
ret = mixer_ctl_get_array(ctl, cvd_version, count);
|
|
if (ret != 0) {
|
|
fprintf(stderr, "fail to get mixer_ctl_get_array\n");
|
|
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
mixer_close(mixer);
|
|
return;
|
|
}
|
|
|
|
static void alsaucm_test_cmd_svr(void)
|
|
{
|
|
int fd;
|
|
ssize_t read_count;
|
|
char cmdstr[256] = {'\0'};
|
|
char ch;
|
|
char *exit_str = "quit";
|
|
char *cvd_version = NULL;
|
|
|
|
cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
|
|
if (!cvd_version)
|
|
fprintf(stderr, "fail to allocate cvd_version\n");
|
|
else
|
|
get_cvd_version(cvd_version);
|
|
|
|
if ((acdb_loader_init_v2(NULL, cvd_version, 0)) < 0) {
|
|
fprintf(stderr, "Failed to initialize ACDB\n");
|
|
if (cvd_version)
|
|
free(cvd_version);
|
|
return 0;
|
|
}
|
|
if (cvd_version)
|
|
free(cvd_version);
|
|
|
|
if (mknod("/data/alsaucm_test", S_IFIFO | 0666, 0) == 0) {
|
|
fd = open("/data/alsaucm_test", O_RDONLY);
|
|
while (1) {
|
|
read_count = read(fd, &ch, 1);
|
|
if (read_count == 0) {
|
|
sleep(2);
|
|
continue;
|
|
} else if (read_count < 0) {
|
|
fprintf(stderr, "alsaucm_test: error reading cmd\n");
|
|
break;
|
|
}
|
|
|
|
if (ch != '\n') {
|
|
strlcat(cmdstr, &ch , (2+strlen(cmdstr)));
|
|
continue;
|
|
} else {
|
|
if (!strncmp(cmdstr, exit_str, strlen(cmdstr))) {
|
|
/* free UCM instace */
|
|
if (uc_mgr) {
|
|
snd_use_case_mgr_close(uc_mgr);
|
|
uc_mgr = NULL;
|
|
}
|
|
break;
|
|
} else {
|
|
process_cmd(cmdstr);
|
|
memset(cmdstr, 0, sizeof(cmdstr));
|
|
}
|
|
}
|
|
}
|
|
printf("alsaucm_test: exit server mode\n");
|
|
close(fd);
|
|
remove("/data/alsaucm_test");
|
|
} else {
|
|
fprintf(stderr, "alsaucm_test: Failed to create server\n");
|
|
}
|
|
|
|
acdb_loader_deallocate_ACDB();
|
|
}
|
|
|
|
|
|
static void print_help_menu(void)
|
|
{
|
|
printf("\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"
|
|
" help help\n"
|
|
" quit quit\n");
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char *help_str = "help";
|
|
argc--;
|
|
argv++;
|
|
|
|
if (argc > 0) {
|
|
if (!strncmp(argv[0], help_str, strlen(argv[0])))
|
|
print_help_menu();
|
|
} else
|
|
alsaucm_test_cmd_svr();
|
|
return 0;
|
|
}
|
|
|
|
static int process_cmd(char *cmdStr)
|
|
{
|
|
const char **list = NULL , *str = NULL;
|
|
long lval;
|
|
int err, i;
|
|
char *command = NULL;
|
|
int count = 0;
|
|
char *identifier = NULL, *value = NULL;
|
|
struct cmd *cmd = NULL;
|
|
|
|
command = strtok_r(cmdStr, " ", &value);
|
|
identifier = strtok_r(NULL, " ", &value);
|
|
|
|
if (command == NULL) {
|
|
fprintf(stderr, "NULL pointer encountered. Invalid value for command");
|
|
return -1;
|
|
}
|
|
|
|
for (cmd = cmds; cmd->cmd_str != NULL; cmd++) {
|
|
if (strncmp(cmd->cmd_str, command, strlen(cmd->cmd_str)) == 0)
|
|
break;
|
|
}
|
|
|
|
if (cmd->cmd_str == NULL) {
|
|
fprintf(stderr, "Unknown command '%s'\n", command);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((identifier == NULL) && ((cmd->code != UCM_HELP) &&
|
|
(cmd->code != UCM_LISTCARDS) && (cmd->code != UCM_RESET) &&
|
|
(cmd->code != UCM_RELOAD)))
|
|
{
|
|
fprintf(stderr, "NULL pointer encountered. Invalid value for identifier");
|
|
return -1;
|
|
}
|
|
|
|
switch (cmd->code) {
|
|
case UCM_HELP:
|
|
print_help_menu();
|
|
break;
|
|
|
|
case UCM_OPEN:
|
|
if (uc_mgr) {
|
|
snd_use_case_mgr_close(uc_mgr);
|
|
uc_mgr = NULL;
|
|
}
|
|
|
|
err = snd_use_case_mgr_open(&uc_mgr, identifier);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to open sound card %s: %d\n", cmd->cmd_str, identifier, err);
|
|
return err;
|
|
}
|
|
break;
|
|
|
|
case UCM_LISTCARDS:
|
|
err = snd_use_case_card_list(&list);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to get card list: %d\n", cmd->cmd_str, err);
|
|
return err;
|
|
}
|
|
if (err == 0) {
|
|
printf("list is empty\n");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < err; i++)
|
|
printf(" %i: %s\n", i+1, list[i]);
|
|
snd_use_case_free_list(list, err);
|
|
break;
|
|
|
|
case UCM_RESET:
|
|
if (!uc_mgr) {
|
|
fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = snd_use_case_mgr_reset(uc_mgr);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to reset sound card %d\n", cmd->cmd_str, err);
|
|
return err;
|
|
}
|
|
break;
|
|
|
|
case UCM_RELOAD:
|
|
if (!uc_mgr) {
|
|
fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = snd_use_case_mgr_reload(uc_mgr);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to reload manager %d\n", cmd->cmd_str, err);
|
|
return err;
|
|
}
|
|
break;
|
|
|
|
case UCM_LIST:
|
|
if (!uc_mgr) {
|
|
fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = snd_use_case_get_list(uc_mgr, identifier, &list);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to get list %s: %d\n", cmd->cmd_str, identifier, err);
|
|
return err;
|
|
}
|
|
if (err == 0) {
|
|
printf("list is empty\n");
|
|
return 0;
|
|
}
|
|
for (i = 0; i < err; i++) {
|
|
printf(" %i: %s\n", i+1, list[i]);
|
|
}
|
|
snd_use_case_free_list(list, err);
|
|
break;
|
|
|
|
case UCM_SET:
|
|
if (!uc_mgr) {
|
|
fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = snd_use_case_set(uc_mgr, identifier, value);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to set %s=%s: %d\n", cmd->cmd_str, identifier, value, err);
|
|
return err;
|
|
}
|
|
break;
|
|
|
|
case UCM_GET:
|
|
if (!uc_mgr) {
|
|
fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = snd_use_case_get(uc_mgr, identifier, &str);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to get %s: %d\n", cmd->cmd_str, identifier, err);
|
|
return err;
|
|
}
|
|
if (str != NULL)
|
|
printf(" %s=%s\n", identifier, str);
|
|
free((void *)str);
|
|
break;
|
|
|
|
case UCM_GETI:
|
|
if (!uc_mgr) {
|
|
fprintf(stderr, "No card is opened before. %s command can't be executed\n", cmd->cmd_str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = snd_use_case_geti(uc_mgr, identifier, &lval);
|
|
if (err < 0) {
|
|
fprintf(stderr, "%s: error failed to get integer %s: %d\n", cmd->cmd_str, identifier, err);
|
|
return lval;
|
|
}
|
|
printf(" %s=%li\n", identifier, lval);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|