TinyMix Enhancements
* Add an option to output everything with tabs for easier parsing
(eg: import into a spread-sheet when there are hundreds of
controls.)
* Add an option to print all valid values or ranges for the printed
controls.
* Add an option to hide the prefix when retrieving a single value.
* Return an error when the operation failed.
Bug: 35318602
Test: Run tinymix with all options.
Run tinymix to show enumerations, multi-integer values, and
single integer values, with or without a prefix, and with
all values or not.
Change-Id: I7b47896a39052e9554bb6205247125afd50449df
diff --git a/tinymix.c b/tinymix.c
index d77d3e5..7b39892 100644
--- a/tinymix.c
+++ b/tinymix.c
@@ -32,51 +32,97 @@
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
+#include <getopt.h>
+#include <errno.h>
static void tinymix_list_controls(struct mixer *mixer);
-static void tinymix_detail_control(struct mixer *mixer, const char *control,
- int print_all);
-static void tinymix_set_value(struct mixer *mixer, const char *control,
- char **values, unsigned int num_values);
-static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all);
+static int tinymix_detail_control(struct mixer *mixer, const char *control,
+ int prefix, int print_all);
+static int tinymix_set_value(struct mixer *mixer, const char *control,
+ char **values, unsigned int num_values);
+static void tinymix_print_enum(struct mixer_ctl *ctl, const char *space,
+ int print_all);
+
+static const char *tinymix_short_options = "D:atvh";
+static struct option tinymix_long_options[] = {
+ {"device", required_argument, 0, 'D'},
+ {"all-values", no_argument, 0, 'a'},
+ {"tabs-only", no_argument, 0, 't'},
+ {"value-only", no_argument, 0, 'v'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+};
+
+static int g_tabs_only = 0;
+static int g_all_values = 0;
+static int g_value_only = 0;
+
+static void usage (void) {
+ fprintf(stderr,
+"tinymix [options] [control name/#] [value to set]\n"
+" options:\n"
+" --device|-D <card#> - use the given card # instead of 0.\n"
+" --all-values|-a - show all possible values/ranges for control.\n"
+" --tabs-only|-t - separate all output columns/values with tabs.\n"
+" --value-only|-v - show only the value for the selected control.\n"
+ );
+}
int main(int argc, char **argv)
{
struct mixer *mixer;
int card = 0;
+ int ret = 0;
- if ((argc > 2) && (strcmp(argv[1], "-D") == 0)) {
- argv++;
- if (argv[1]) {
- card = atoi(argv[1]);
- argv++;
- argc -= 2;
- } else {
- argc -= 1;
+ while (1) {
+ int option_index = 0;
+ int option_char = 0;
+
+ option_char = getopt_long(argc, argv, tinymix_short_options,
+ tinymix_long_options, &option_index);
+ if (option_char == -1)
+ break;
+
+ switch (option_char) {
+ case 'D':
+ card = atoi(optarg);
+ break;
+ case 'a':
+ g_all_values = 1;
+ break;
+ case 't':
+ g_tabs_only = 1;
+ break;
+ case 'v':
+ g_value_only = 1;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ default:
+ usage();
+ return EINVAL;
}
}
mixer = mixer_open(card);
if (!mixer) {
fprintf(stderr, "Failed to open mixer\n");
- return EXIT_FAILURE;
+ return ENODEV;
}
-
- if (argc == 1) {
+ if (argc == optind) {
printf("Mixer name: '%s'\n", mixer_get_name(mixer));
tinymix_list_controls(mixer);
- } else if (argc == 2) {
- tinymix_detail_control(mixer, argv[1], 1);
- } else if (argc >= 3) {
- tinymix_set_value(mixer, argv[1], &argv[2], argc - 2);
- } else {
- printf("Usage: tinymix [-D card] [control id] [value to set]\n");
+ } else if (argc == optind + 1) {
+ ret = tinymix_detail_control(mixer, argv[optind], !g_value_only, !g_value_only);
+ } else if (argc >= optind + 2) {
+ ret = tinymix_set_value(mixer, argv[optind], &argv[optind + 1], argc - optind - 1);
}
mixer_close(mixer);
- return 0;
+ return ret;
}
static void tinymix_list_controls(struct mixer *mixer)
@@ -90,38 +136,53 @@
printf("Number of controls: %d\n", num_ctls);
- printf("ctl\ttype\tnum\t%-40s value\n", "name");
+ if (g_tabs_only)
+ printf("ctl\ttype\tnum\tname\tvalue");
+ else
+ printf("ctl\ttype\tnum\t%-40s value\n", "name");
+ if (g_all_values)
+ printf("\trange/values\n");
+ else
+ printf("\n");
for (i = 0; i < num_ctls; i++) {
ctl = mixer_get_ctl(mixer, i);
name = mixer_ctl_get_name(ctl);
type = mixer_ctl_get_type_string(ctl);
num_values = mixer_ctl_get_num_values(ctl);
- printf("%d\t%s\t%d\t%-40s", i, type, num_values, name);
- tinymix_detail_control(mixer, name, 0);
+ if (g_tabs_only)
+ printf("%d\t%s\t%d\t%s\t", i, type, num_values, name);
+ else
+ printf("%d\t%s\t%d\t%-40s ", i, type, num_values, name);
+ tinymix_detail_control(mixer, name, 0, g_all_values);
}
}
-static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all)
+static void tinymix_print_enum(struct mixer_ctl *ctl, const char *space,
+ int print_all)
{
unsigned int num_enums;
unsigned int i;
const char *string;
+ int control_value = mixer_ctl_get_value(ctl, 0);
- num_enums = mixer_ctl_get_num_enums(ctl);
-
- for (i = 0; i < num_enums; i++) {
- string = mixer_ctl_get_enum_string(ctl, i);
- if (print_all)
- printf("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "",
- string);
- else if (mixer_ctl_get_value(ctl, 0) == (int)i)
- printf(" %-s", string);
+ if (print_all) {
+ num_enums = mixer_ctl_get_num_enums(ctl);
+ for (i = 0; i < num_enums; i++) {
+ string = mixer_ctl_get_enum_string(ctl, i);
+ printf("%s%s%s",
+ control_value == (int)i ? ">" : "", string,
+ (i < num_enums - 1) ? space : "");
+ }
+ }
+ else {
+ string = mixer_ctl_get_enum_string(ctl, control_value);
+ printf("%s", string);
}
}
-static void tinymix_detail_control(struct mixer *mixer, const char *control,
- int print_all)
+static int tinymix_detail_control(struct mixer *mixer, const char *control,
+ int prefix, int print_all)
{
struct mixer_ctl *ctl;
enum mixer_ctl_type type;
@@ -132,6 +193,7 @@
char *buf = NULL;
size_t len;
unsigned int tlv_header_size = 0;
+ const char *space = g_tabs_only ? "\t" : " ";
if (isdigit(control[0]))
ctl = mixer_get_ctl(mixer, atoi(control));
@@ -139,8 +201,8 @@
ctl = mixer_get_ctl_by_name(mixer, control);
if (!ctl) {
- fprintf(stderr, "Invalid mixer control\n");
- return;
+ fprintf(stderr, "Invalid mixer control: %s\n", control);
+ return ENOENT;
}
type = mixer_ctl_get_type(ctl);
@@ -153,7 +215,7 @@
buf = calloc(1, num_values + tlv_header_size);
if (buf == NULL) {
fprintf(stderr, "Failed to alloc mem for bytes %d\n", num_values);
- return;
+ return ENOENT;
}
len = num_values;
@@ -161,46 +223,50 @@
if (ret < 0) {
fprintf(stderr, "Failed to mixer_ctl_get_array\n");
free(buf);
- return;
+ return ENOENT;
}
}
- if (print_all)
- printf("%s:", mixer_ctl_get_name(ctl));
+ if (prefix)
+ printf("%s:%s", mixer_ctl_get_name(ctl), space);
for (i = 0; i < num_values; i++) {
switch (type)
{
case MIXER_CTL_TYPE_INT:
- printf(" %d", mixer_ctl_get_value(ctl, i));
+ printf("%d", mixer_ctl_get_value(ctl, i));
break;
case MIXER_CTL_TYPE_BOOL:
- printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
+ printf("%s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
break;
case MIXER_CTL_TYPE_ENUM:
- tinymix_print_enum(ctl, print_all);
+ tinymix_print_enum(ctl, space, print_all);
break;
case MIXER_CTL_TYPE_BYTE:
/* skip printing TLV header if exists */
printf(" %02x", buf[i + tlv_header_size]);
break;
default:
- printf(" unknown");
+ printf("unknown");
break;
- };
+ }
+
+ if (i < num_values - 1)
+ printf("%s", space);
}
if (print_all) {
if (type == MIXER_CTL_TYPE_INT) {
min = mixer_ctl_get_range_min(ctl);
max = mixer_ctl_get_range_max(ctl);
- printf(" (range %d->%d)", min, max);
+ printf("%s(dsrange %d->%d)", space, min, max);
}
}
free(buf);
printf("\n");
+ return 0;
}
static void tinymix_set_byte_ctl(struct mixer_ctl *ctl,
@@ -265,8 +331,8 @@
exit(EXIT_FAILURE);
}
-static void tinymix_set_value(struct mixer *mixer, const char *control,
- char **values, unsigned int num_values)
+static int tinymix_set_value(struct mixer *mixer, const char *control,
+ char **values, unsigned int num_values)
{
struct mixer_ctl *ctl;
enum mixer_ctl_type type;
@@ -279,8 +345,8 @@
ctl = mixer_get_ctl_by_name(mixer, control);
if (!ctl) {
- fprintf(stderr, "Invalid mixer control\n");
- return;
+ fprintf(stderr, "Invalid mixer control: %s\n", control);
+ return ENOENT;
}
type = mixer_ctl_get_type(ctl);
@@ -288,7 +354,7 @@
if (type == MIXER_CTL_TYPE_BYTE) {
tinymix_set_byte_ctl(ctl, values, num_values);
- return;
+ return ENOENT;
}
if (isdigit(values[0][0])) {
@@ -299,7 +365,7 @@
for (i = 0; i < num_ctl_values; i++) {
if (mixer_ctl_set_value(ctl, i, value)) {
fprintf(stderr, "Error: invalid value\n");
- return;
+ return EINVAL;
}
}
} else {
@@ -308,12 +374,12 @@
fprintf(stderr,
"Error: %d values given, but control only takes %d\n",
num_values, num_ctl_values);
- return;
+ return EINVAL;
}
for (i = 0; i < num_values; i++) {
if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) {
fprintf(stderr, "Error: invalid value for index %d\n", i);
- return;
+ return EINVAL;
}
}
}
@@ -321,13 +387,17 @@
if (type == MIXER_CTL_TYPE_ENUM) {
if (num_values != 1) {
fprintf(stderr, "Enclose strings in quotes and try again\n");
- return;
+ return EINVAL;
}
- if (mixer_ctl_set_enum_by_string(ctl, values[0]))
+ if (mixer_ctl_set_enum_by_string(ctl, values[0])) {
fprintf(stderr, "Error: invalid enum value\n");
+ return EINVAL;
+ }
} else {
fprintf(stderr, "Error: only enum types can be set with strings\n");
+ return EINVAL;
}
}
-}
+ return 0;
+}